You are an expert Lean4 and formal verification agent proving a Lean4 theorem. Your output **must** strictly adhere to the specified format.

### Input Information
You will receive the following components, relevant to the target theorem:
* <all_available_defs>: Definitions available from imported modules (either from the current Lean repository or from Mathlib)
* <all_available_lemmas>: Lemmas/theorems available that may assist the proof.
* <local_ctx>...</local_ctx>: The local file context (imports, namespaces, definitions, comments, etc.) from the top of the file up to—but not including—the target theorem or any previously defined local lemmas/theorems.
* <target_theorem>...</target_theorem>: The target theorem statement, ending with `:=`.

**Notes**
1. Definitions include their full bodies, but for definitions whose bodies contain proofs, the proof parts are replaced by `admit` (i.e., admit /- proof elided -/), while the rest of the definition is kept unchanged; lemmas include only their statements.
2. You may freely reference any definition or lemma contained in these tags without redefining them.
3. The tags for available definitions and lemmas (all_available_defs, all_available_lemmas) may be omitted if empty.

### Output Format & Requirements
Your output MUST contain a complete, syntactically correct Lean 4 proof for the target theorem.

**Strict Output Structure:**
<reasoning> 
...
</reasoning> 

<lean4_invented_lemmas>
-- each lemma is a full Lean 4 declaration with a complete proof
...
</lean4_invented_lemmas>

<lean4_proof>
-- Lean 4 proof body of the target theorem
...
</lean4_proof>

**Requirements:**
1. <reasoning> and <lean4_invented_lemmas> are OPTIONAL. Include them only if they aid proof construction.
2. <lean4_proof> MUST contain only the proof body (tactics/terms), starting by "by", NOT the theorem declaration.
3. <lean4_invented_lemmas> (if present) MUST contain syntactically correct lemma declarations that type checks AND complete proof bodies. Defining a lemma using `axiom` is NOT allowed.
4. <reasoning> contains high-level proof planning.
5. If you create a lemma under <lean4_invented_lemmas> whose name is namespaced (e.g., X.Y.Z), you MUST always refer to it using its fully qualified name. Do NOT rely on shortened names. For example, write rw [X.Y.Z], not rw [Z] for invented lemmas.
6. All Lean 4 code MUST be syntactically correct. No `sorry`, `admit`, or non-Lean text. Comments allowed using `--` or `/- ... -/`.
7. Follow the tags and structure EXACTLY. No extra text before, between, or after the sections.
8. Do NOT wrap invented lemmas in a `mutual` block unless they have genuine mutual recursion. Declare each lemma independently.

### Examples are provided here (example input are under "User Prompt", and example assistant response are under "Agent Response"):
Example 1 ------------------- 
User Prompt:
<all_available_defs>
structure BitVec (w : Nat) where
  /-- Construct a `BitVec w` from a number less than `2^w`.
  O(1), because we use `Fin` as the internal representation of a bitvector. -/
  ofFin ::

  /-- Interpret a bitvector as a number less than `2^w`.
  O(1), because we use `Fin` as the internal representation of a bitvector. -/
  toFin : Fin (hPow 2 w)
</all_available_defs>

<all_available_lemmas>
theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) : (l₁ ++ l₂)[i] = l₁[i]
theorem getElem_eq_testBit_toNat (x : BitVec w) (i : Nat) (h : i < w) :
  x[i] = x.toNat.testBit i := rfl
@[simp, grind =] theorem toNat_cons (b : Bool) (x : BitVec w) :
    (cons b x).toNat = (b.toNat <<< w) ||| x.toNat
@[simp, grind =] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false
theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i
</all_available_lemmas>

<local_ctx>
import Mathlib.Computability.NFA
import Mathlib.Data.FinEnum
import Mathlib.Data.Rel
import Mathlib.Data.Vector.Basic
import Blase.AutoStructs.ForLean

open Set
open Mathlib
open SetRel

-- this is better because card is defeq to n
instance (α : Type) : Inter (Language α) := ⟨Set.inter⟩
instance (α : Type) : Union (Language α) := ⟨Set.union⟩

/--
The set of `n`-tuples of bit vectors of an arbitrary width.
-/
structure BitVecs (n : Nat) where
  w : Nat
  bvs : List.Vector (BitVec w) n

def BitVecs.cast (bvs : BitVecs n) (h : n = n') : BitVecs n' :=
  { w := bvs.w, bvs := h ▸ bvs.bvs }

abbrev BitVecs.empty : BitVecs n := ⟨0, List.Vector.replicate n .nil⟩
abbrev BitVecs.singleton {w : Nat} (bv : BitVec w) : BitVecs 1 := ⟨w, bv ::ᵥ .nil⟩
abbrev BitVecs.pair {w : Nat} (bv1 bv2 : BitVec w) : BitVecs 2 := ⟨w, bv1 ::ᵥ bv2 ::ᵥ .nil⟩

/--
The set of `n`-tuples of bit vectors of an arbitrary width, encoded as a list of
bit vectors of width `n`. The width of the encoded bit vectors is the length of
the list.
-/
abbrev BitVecs' (n : Nat) := List (BitVec n)

@[simps]
def dec (bvs' : BitVecs' n) : BitVecs n where
  w := bvs'.length
  bvs := List.Vector.ofFn fun k => BitVec.ofFn fun i => bvs'[i].getLsbD k

@[simp]
</local_ctx>

<target_theorem>
lemma dec_snoc n (bvs' : BitVecs' n) (a : BitVec n) :
  dec (bvs' ++ [a]) =
    { w := bvs'.length + 1
      bvs := List.Vector.ofFn fun k =>
        BitVec.cons (a.getLsbD k) ((dec bvs').bvs.get k) } :=
</target_theorem>

Agent Response:
<reasoning> 
The goal is to understand what `dec` does after appending one more bitvector `a` to `bvs'`. By definition, `dec` builds a width `= length` and a vector of bitvectors whose `i`-th bit at position `k` is `bvs'[i].getLsbD k`. So for `bvs' ++ [a]`, we expect the width to increase by 1 and each resulting bitvector to be `BitVec.cons` of the new bit coming from `a`.

First, I use `ext` twice: once on the record to focus on the `bvs` field, and once on the resulting bitvector. This reduces everything to a pointwise statement:
for fixed `k` and `i` with `i < bvs'.length + 1`,
the bit `(bvs' ++ [a])[i].getLsbD k` should match the bit at index `i` of `BitVec.cons (a.getLsbD k) ((dec bvs').bvs.get k)`.

At this point I need a clean description of indexing into `BitVec.cons`: if we have `x : BitVec n`, then `(cons b x)[i]` should give `b` at the new “last” index `n` and `x[i]` otherwise. That motivates an auxiliary lemma `getElem_cons` expressing exactly this behavior, proved via the `testBit`/`toNat` characterization and a case split on `i < n`, `i = n`, `i > n`.

Using `getElem_cons`, the RHS becomes an `if` on whether `i = bvs'.length`. So I split into cases:
- If `i = bvs'.length`, then `(bvs' ++ [a])[i]` is the appended `a`, so both sides reduce to `a.getLsbD k`.
- If `i ≠ bvs'.length`, the bound `i < bvs'.length + 1` forces `i < bvs'.length`. Then `(bvs' ++ [a])[i] = bvs'[i]` by `List.getElem_append_left`, and the RHS takes the “else” branch and likewise gives the bit from `bvs'[i]`. In both subcases, `simp` (plus the definition of `dec`) finishes.

So the whole proof is: `ext` to bit level, unfold `dec` with `simp_all`, rewrite with `getElem_cons`, split on the boundary index `i = length bvs'`, and in the “< length” branch use `List.getElem_append_left` and bounds to line up both sides.
</reasoning> 

<lean4_invented_lemmas>
@[grind =]
theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
    (cons b x)[i] = if h : i = n then b else x[i] := by
  simp only [BitVec.getElem_eq_testBit_toNat, BitVec.toNat_cons, Nat.testBit_or]
  rw [Nat.testBit_shiftLeft]
  rcases Nat.lt_trichotomy i n with i_lt_n | i_eq_n | n_lt_i
  · have p1 : ¬(n ≤ i) := by omega
    have p2 : i ≠ n := by omega
    simp [p1, p2]
  · simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_true, Nat.sub_self, Nat.testBit_zero,
    Bool.true_and, BitVec.testBit_toNat, BitVec.getLsbD_of_ge, Bool.or_false]
    cases b <;> trivial
  · have p1 : i ≠ n := by omega
    have p2 : i - n ≠ 0 := by omega
    simp [p1, p2, Nat.testBit_bool_toNat]
</lean4_invented_lemmas>

<lean4_proof>
by
  ext k i hi <;> simp_all
  rw [getElem_cons]
  split
  next heq => simp_all
  next h =>
    have hlt : i < List.length bvs' := by simp at hi; omega
    rw [List.getElem_append_left hlt]
    simp
</lean4_proof>

### Your task:
<all_available_defs>
DecidableEq in Init.Prelude
Lean.ToExpr in Lean.ToExpr
List in Init.Prelude
Repr in Init.Data.Repr
Nat in Init.Prelude
AList in Mathlib.Data.List.AList
Option in Init.Prelude
StateT in Init.Control.State
Unit in Init.Prelude
String in Init.Prelude
BEq in Init.Prelude
ite in Init.Prelude
Vector in Init.Data.Vector.Basic
Bool in Init.Prelude
Int in Init.Data.Int.Basic
bool in Init.Control.Basic
Computation in Mathlib.Data.Seq.Computation
AList.insert in Mathlib.Data.List.AList
Valuation.map in Mathlib.RingTheory.Valuation.Basic
Exists in Init.Core
Id in Init.Control.Id
List.map in Init.Prelude
Polynomial.X in Mathlib.Algebra.Polynomial.Basic
ZMod in Mathlib.Data.ZMod.Defs
Sigma in Init.Core
Sigma.mk in Init.Core
liftM in Init.Prelude
Iff in Init.Core
IsEmpty in Mathlib.Logic.IsEmpty
id in Init.Prelude
PUnit in Init.Prelude
Pure in Init.Prelude
HEq in Init.Prelude

syntax "neg" : MLIR.Pretty.uniform_op

macro_rules
  | `(mlir_op| $res:mlir_op_operand = const ($x)
      $[: $outer_type]? ) => do
      let outer_type ← outer_type.getDM `(mlir_type| _)
      `(mlir_op| $res:mlir_op_operand = "const"()
          {val = $x:num : $outer_type} : ($outer_type) -> ($outer_type) )

macro_rules
  | `(mlir_op| $res:mlir_op_operand = li ($x)
     $[: $outer_type]?  ) => do
      let outer_type ← outer_type.getDM `(mlir_type| _ )
      `(mlir_op| $res:mlir_op_operand = "li"()
          {imm = $x:num : $outer_type } : ($outer_type) -> ($outer_type))

macro_rules
| `(mlir_op| $res:mlir_op_operand = $op1:MLIR.Pretty.RV.opWithImmediate $reg1 , $x : $t)  => do
    let some opName := MLIR.EDSL.Pretty.extractOpName op1.raw
      | Macro.throwUnsupported
    `(mlir_op| $res:mlir_op_operand = $opName ($reg1) {imm = $x:num : $t} : ($t) -> ($t) )

macro_rules
| `(mlir_op| $res:mlir_op_operand = $op1:MLIR.Pretty.RV.opWithShamt $reg1 , $x  : $t )  => do
    let some opName := MLIR.EDSL.Pretty.extractOpName op1.raw
      | Macro.throwUnsupported
    `(mlir_op| $res:mlir_op_operand = $opName ($reg1) {shamt = $x:num : $t}  : ($t) -> ($t) )

abbrev Mapping (Γ Δ : Ctxt Ty) : Type :=
  @AList (Σ t, Var Γ t) (fun x => Var Δ x.1)

structure Ctxt (Ty : Type) : Type where
  ofList :: toList : List Ty
  
  deriving Repr, Lean.ToExpr, DecidableEq

def Var (Γ : Ctxt Ty) (t : Ty) : Type :=
  { i : Nat // Γ[i]? = some t }

inductive Lets (Γ_in : Ctxt d.Ty) (eff : EffectKind) :
    (Γ_out : Ctxt d.Ty) → Type where
  | nil : Lets Γ_in eff Γ_in
  | var (body : Lets Γ_in eff Γ_out) (e : Expr d Γ_out eff t) : Lets Γ_in eff e.outContext

protected instance Expr.decidableEq [DecidableEq d.Op] [DecidableEq d.Ty] :
    {Γ : Ctxt d.Ty} → {ty : List d.Ty} → DecidableEq (Expr d Γ eff ty)
  | Γ, _, .mk op₁ rfl eff_le₁ arg₁ regArgs₁, .mk op₂ eq eff_le₂ arg₂ regArgs₂ =>
    if ho : op₁ = op₂ then by
      subst ho
      letI := HVector.decidableEq arg₁ arg₂
      letI := HVector.decidableEqReg regArgs₁ regArgs₂
      exact decidable_of_iff (arg₁ = arg₂ ∧ regArgs₁ = regArgs₂) (by admit /- proof elided -/
      )
    else isFalse (by admit /- proof elided -/
    )

def Var (Γ : Context Ty) (ty : Ty) : Type := { v : VarName // Γ.hasType v ty }

def Valuation.nil : Ctxt.Valuation (∅ : Ctxt Ty) := fun _ v => v.emptyElim

inductive EffectKind
| pure 
| impure 
deriving Repr, DecidableEq, Lean.ToExpr

def Valuation.cons {Γ : Ctxt Ty} {t : Ty} (x : toType t) (V : Γ.Valuation) :
    (Γ.cons t).Valuation :=

protected instance HVector.decidableEqReg [DecidableEq d.Op] [DecidableEq d.Ty] :
    ∀ {l : RegionSignature d.Ty}, DecidableEq (HVector (fun t => Com d t.1 .impure t.2) l)
  | _, .nil, .nil => isTrue rfl
  | _, .cons x₁ v₁, .cons x₂ v₂ =>
    letI := HVector.decidableEqReg v₁ v₂
    letI := Com.decidableEq x₁ x₂
    decidable_of_iff (x₁ = x₂ ∧ v₁ = v₂) (by admit /- proof elided -/
    )

@[elab_as_elim]
def appendCases
    {motive : (Γ ++ Δ).Var t → Sort u}
    (left : (v : Var Γ t) → motive (appendInl v))
    (right : (v : Var Δ t) → motive (appendInr v)) :
    (v : (Γ ++ Δ).Var t) → motive v
  | ⟨idx, h⟩ =>
    if hv : idx < Γ.length then
      left ⟨idx, by admit /- proof elided -/
      ⟩
    else
      let v' : Var _ _ := ⟨idx - Γ.length, by admit /- proof elided -/
      ⟩
      have eq : v'.appendInr = ⟨idx, h⟩ := by admit /- proof elided -/

@[match_pattern]
def last (Γ : Ctxt Ty) (t : Ty) : Ctxt.Var (Ctxt.cons t Γ) t :=
  ⟨0, by admit /- proof elided -/
  ⟩

def appendInl (v : Γ.Var t) : (Γ ++ Δ).Var t :=
  ⟨v.val, by admit /- proof elided -/
  ⟩

class TyDenote (β : Type) : Type 1 where
  toType : β → Type

def map (f : ∀ (a : α), A a → B a) :
    ∀ {l : List α}, HVector A l → HVector B l
  | [],   .nil        => .nil
  | t::_, .cons a as  => .cons (f t a) (map f as)

def map (f : Ty₁ → Ty₂) : Ctxt Ty₁ → Ctxt Ty₂ :=
  ofList ∘ (List.map f) ∘ toList

@[match_pattern]
def cons (hd : Ty) : Ctxt Ty → Ctxt Ty
| ⟨tl⟩ => ⟨hd :: tl⟩

noncomputable def f : (ZMod q)[X] := X^(2^n) + 1

def sig          := Signature.sig ∘ s.signature

structure Signature (Ty : Type) where
  mkEffectful ::
  sig         : List Ty
  regSig      : RegionSignature Ty
  returnTypes : List Ty
  effectKind  : EffectKind := .pure

class DialectSignature (d : Dialect) where
  signature : d.Op → Signature d.Ty

def effectKind   := Signature.effectKind ∘ s.signature

def returnTypes  := Signature.returnTypes ∘ s.signature

def Expr.ty : Expr d Γ eff [t] → d.Ty := fun _ => t

def Expr.op {Γ : Ctxt d.Ty} {eff : EffectKind} {ty} (e : Expr d Γ eff ty) : d.Op :=
  Expr.casesOn e (fun op _ _ _ _ => op)

class DialectDenote (d : Dialect) [TyDenote d.Ty] [DialectSignature d] where
  denote : (op : d.Op) → HVector toType (DialectSignature.sig op) →
    (HVector (fun t : Ctxt d.Ty × List d.Ty =>
      t.1.Valuation
      → EffectKind.impure.toMonad d.m (HVector toType t.2))
            (DialectSignature.regSig op)) →
    ((DialectSignature.effectKind op).toMonad d.m
      (HVector toType <| DialectSignature.returnTypes op))

def Lets.denote [DialectSignature d] [DialectDenote d] {Γ₂}
    (lets : Lets d Γ₁ eff Γ₂) (V : Valuation Γ₁) : (eff.toMonad d.m <| Valuation Γ₂) :=
  match lets with
  | .nil          => return V
  | .var lets' e  => lets'.denote V >>= e.denote

def regSig       := Signature.regSig ∘ s.signature

abbrev RegionSignature Ty := List (Ctxt Ty × List Ty)

inductive Ty (q : Nat) (n : Nat)
  | index : Ty q n
  | integer : Ty q n
  | tensor : Ty q n
  | polynomialLike : Ty q n
  deriving DecidableEq, Repr

structure Dialect where
  (Op : Type)
  (Ty : Type)
  (m : Type → Type := Id)

inductive Op (q : Nat) (n : Nat)
  | add : Op q n
  | sub : Op q n
  | mul : Op q n
  | mul_constant : Op q n
    
    
  | leading_term : Op q n
  | monomial : Op q n
  | monomial_mul : Op q n
  | from_tensor : Op q n
  | to_tensor : Op q n
  | const (c : R q n) : Op q n
  | const_int (c : Int) : Op q n
  | const_idx (i : Nat) : Op q n

@[simp]
instance Valuation.instAppendHVector (Γ : Ctxt Ty) (ts : List Ty) :
    HAppend (HVector toType ts) (Valuation Γ) (Valuation <| ⟨ts⟩ ++ Γ) where
  hAppend vals V :=
    (Valuation.ofHVector vals) ++ V

def HVector.denote :
    {l : RegionSignature d.Ty} → (T : HVector (fun t => Com d t.1 .impure t.2) l) →
    HVector (fun t => t.1.Valuation → EffectKind.impure.toMonad d.m (HVector toType t.2)) l
  | _, .nil => HVector.nil
  | _, .cons v vs => HVector.cons (v.denote) (HVector.denote vs)

@[simp] abbrev FlatCom.denote [DialectDenote d]
    (flatCom : FlatCom d Γ eff Γ_out ts)
    (V : Γ.Valuation) : eff.toMonad d.m (HVector toType ts) :=
  flatCom.lets.denote V >>= (return flatCom.rets.map ·)

structure FlatCom (d : Dialect) [DialectSignature d]  (Γ_in : Ctxt d.Ty) (eff : EffectKind)
    (Γ_out : Ctxt d.Ty) (ts : List d.Ty) where
  lets : Lets d Γ_in eff Γ_out
  rets : HVector Γ_out.Var ts

def RegionSignature.map (f : Ty → Ty') : RegionSignature Ty → RegionSignature Ty' :=
  List.map fun ⟨Γ, ty⟩ => (Γ.map f, ty.map f)

def Signature.map (f : Ty → Ty') : Signature Ty → Signature Ty' :=
  fun sig => {
    sig         := sig.sig.map f
    regSig      := sig.regSig.map f
    returnTypes := sig.returnTypes.map f
  }

inductive Com : Ctxt d.Ty → EffectKind → List d.Ty → Type where
  | rets {Γ} {tys} {eff : EffectKind} (vs : HVector Γ.Var tys) : Com Γ eff tys
  | var (e : Expr Γ eff ty) (body : Com (ty ++ Γ) eff β) : Com Γ eff β

def Expr.denote {ty} (e : Expr d Γ eff ty) (V : Valuation Γ) :
    eff.toMonad d.m (e.outContext.Valuation) :=
  match e with
  | ⟨op, ty_eq, heff, args, regArgs⟩ => do
      let argsDenote := args.map V
      let val ← EffectKind.liftEffect heff <| DialectDenote.denote op argsDenote regArgs.denote
      return (val ++ V).cast (by admit /- proof elided -/
      )

def Com.outContext {Γ} : Com d Γ eff ts → Ctxt d.Ty :=
  Com.rec' (motive := fun _ => Ctxt d.Ty)
    (@fun Γ _ => Γ) 
    (fun _ _ r => r)

def Com.rec' {Γ} (com : Com d Γ eff t) : motive com :=
   
  Com.rec
    (motive_1 := fun _ _ _ _ => PUnit)
    (motive_2 := fun _ eff' t' c =>
      (h₁ : eff = eff') → (h₂ : t = t') → motive (h₁ ▸ h₂ ▸ c))
    (motive_3 := fun _ _ => PUnit)
    (fun _ _ _ _ _ _ => ⟨⟩) 
    (fun v h₁ h₂ => 
      cast (by admit /- proof elided -/
      ) <| rets (h₂ ▸ v))
    (fun e' body' _ r' h₁ h₂ => 
      let e := h₁ ▸ e'
      let body : Com _ _ eff t := cast (by admit /- proof elided -/
      ) body'
      let r : motive body := cast (by admit /- proof elided -/
      ) (r' h₁ h₂)
      cast (by admit /- proof elided -/
      ) <| var e body r)
    ⟨⟩
    (fun _ _ _ _ => ⟨⟩)
    com
    rfl
    rfl

def Valuation.cast {Γ Δ : Ctxt Ty} (h : Γ = Δ) (V : Valuation Γ) : Valuation Δ :=
  fun _ v => V <| v.castCtxt h.symm

abbrev Expr.outContext (_ : Expr d Γ eff ts) : Ctxt d.Ty :=
  ts ++ Γ

def liftEffect [Pure m] {e1 e2 : EffectKind} {α : Type}
    (hle : e1 ≤ e2) (v1 : e1.toMonad m α) : e2.toMonad m α :=
  match e1, e2, hle with
    | .pure, .pure, _ | .impure, .impure, _ => v1
    | .pure, .impure, _ => Pure.pure v1

def toMonad (e : EffectKind) (m : Type → Type) : Type → Type :=
  match e with
  | pure => Id
  | impure => m

def Com.denote : Com d Γ eff ty → (Γv : Valuation Γ) →
    eff.toMonad d.m (HVector toType ty)
  | .rets vs, Γv     => pure (vs.map Γv)
  | .var e body, V => e.denote V >>= body.denote

def Com.ty : Com d Γ eff [t] → d.Ty := fun _ => t

def Expr.args {Γ ts} (e : Expr d Γ eff ts) :
    HVector (Var Γ) (DialectSignature.sig e.op) :=
  Expr.casesOn e (fun _ _ _ args _ => args)

def Expr.regArgs {Γ ts} (e : Expr d Γ eff ts) :
    Regions d (DialectSignature.regSig e.op) :=
  Expr.casesOn e (fun _ _ _ _ regArgs => regArgs)

abbrev Regions (regSig : RegionSignature d.Ty) : Type :=
  HVector (fun t => Com d t.1 .impure t.2) regSig

def Expr.denoteOp (e : Expr d Γ eff ty) (V : Γ.Valuation) :
    eff.toMonad d.m (HVector toType ty) :=
  EffectKind.liftEffect e.eff_le <| cast (by admit /- proof elided -/
  ) <|
    DialectDenote.denote e.op (e.args.map V) e.regArgs.denote

infixr:50 "::ₕ" => HVector.cons

notation "⟦" x "⟧" => TyDenote.toType x

infixr:67 "::ᵥ" => Valuation.cons

Std.Tactic.BVDecide.BVExpr.PackedBitVec in Std.Tactic.BVDecide.Bitblast.BVExpr.Basic

def fold_add_udiv_urem_to_mul_after := [llvm|
{
^0(%arg8 : i32):
  %0 = llvm.mlir.constant(3 : i32) : i32
  %1 = llvm.mul %arg8, %0 : i32
  "llvm.return"(%1) : (i32) -> ()
}
]

def or_and_not_constant_commute0_after := [llvm|
{
^0(%arg112 : i32, %arg113 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.and %arg112, %0 : i32
  %2 = llvm.or %1, %arg113 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def not_and_and_or_not_or_or_commute1_and_before := [llvm|
{
^0(%arg244 : i32, %arg245 : i32, %arg246 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.or %arg245, %arg244 : i32
  %2 = llvm.or %1, %arg246 : i32
  %3 = llvm.xor %2, %0 : i32
  %4 = llvm.xor %arg244, %0 : i32
  %5 = llvm.and %4, %arg246 : i32
  %6 = llvm.and %5, %arg245 : i32
  %7 = llvm.or %6, %3 : i32
  "llvm.return"(%7) : (i32) -> ()
}
]

instance [Monad d.m] [inst : LawfulMonad d.m] : LawfulMonad (Scf d).m := inst

def scalar_i32_lshr_and_negC_slt_before := [llvm|
{
^0(%arg4 : i32, %arg5 : i32):
  %0 = llvm.mlir.constant(-8 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.lshr %arg4, %arg5 : i32
  %3 = llvm.and %2, %0 : i32
  %4 = llvm.icmp "slt" %3, %1 : i32
  "llvm.return"(%4) : (i1) -> ()
}
]

def branch {r} {Γ : Ctxt _} (a : Var Γ (.stream r)) (c : Var Γ (.stream (.bitvec 1))) : Expr (Handshake) Γ .pure (.stream2 r) :=
  Expr.mk
    (op := .branch r)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .cons a <| .cons c <| .nil)
    (regArgs := .nil)

@[simp_denote]
def icmp_eq_riscv_32_pseudo := [LV| {
  ^entry (%lhs: i32, %rhs: i32):
    %lhsr = "builtin.unrealized_conversion_cast"(%lhs) : (i32) -> (!riscv.reg)
    %rhsr = "builtin.unrealized_conversion_cast"(%rhs) : (i32) -> (!riscv.reg)
    %0 = xor    %lhsr, %rhsr : !riscv.reg
    %1 = seqz    %0 : !riscv.reg
    %2 = "builtin.unrealized_conversion_cast"(%1) : (!riscv.reg) -> (i1)
    llvm.return %2 : i1
  }]

def Expr.KInductionCircuits.mkIsLawful_mkN (fsm : Expr) (n : Expr) : MetaM Expr :=
  mkAppM ``ReflectVerif.BvDecide.KInductionCircuits.IsLawful_mkN #[fsm, n]

def ashrsgt_03_15_exact_after := [llvm|
{
^0(%arg54 : i4):
  %0 = llvm.mlir.constant(-1 : i4) : i4
  %1 = llvm.icmp "sgt" %arg54, %0 : i4
  "llvm.return"(%1) : (i1) -> ()
}
]

let some x ← getElem xs i
      | return .continue

def ashrsgt_02_02_exact_after := [llvm|
{
^0(%arg83 : i4):
  %0 = llvm.mlir.constant(false) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def ashr_ugt_8_before := [llvm|
{
^0(%arg106 : i4):
  %0 = llvm.mlir.constant(1 : i4) : i4
  %1 = llvm.mlir.constant(-8 : i4) : i4
  %2 = llvm.ashr %arg106, %0 : i4
  %3 = llvm.icmp "ugt" %2, %1 : i4
  "llvm.return"(%3) : (i1) -> ()
}
]

def test_slt_before := [llvm|
{
^0(%arg4 : i32, %arg5 : i16):
  %0 = llvm.trunc %arg4 overflow<nsw> : i32 to i8
  %1 = llvm.trunc %arg5 overflow<nsw> : i16 to i8
  %2 = llvm.icmp "slt" %0, %1 : i8
  "llvm.return"(%2) : (i1) -> ()
}
]

def lshrult_02_02_exact_before := [llvm|
{
^0(%arg131 : i4):
  %0 = llvm.mlir.constant(2 : i4) : i4
  %1 = llvm.lshr exact %arg131, %0 : i4
  %2 = llvm.icmp "ult" %1, %0 : i4
  "llvm.return"(%2) : (i1) -> ()
}
]

def envBitstream_set (x : arity → BitStream) (n : Nat) (v : arity → Bool) :
    arity → BitStream :=
  fun a j => if j = n then v a else x a j

def trunc_equality_nsw_zext_after := [llvm|
{
^0(%arg16 : i32, %arg17 : i8):
  %0 = llvm.zext %arg17 : i8 to i32
  %1 = llvm.icmp "ne" %arg16, %0 : i32
  "llvm.return"(%1) : (i1) -> ()
}
]

def ashrslt_03_01_after := [llvm|
{
^0(%arg236 : i4):
  %0 = llvm.mlir.constant(true) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def binop_same_val : List (Σ Γ, RISCVPeepholeRewrite  Γ) :=
    [⟨_, binop_same_val_and⟩,
    ⟨_, binop_same_val_or⟩]

def bools2_logical_commute0_before := [llvm|
{
^0(%arg64 : i1, %arg65 : i1, %arg66 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.mlir.constant(false) : i1
  %2 = llvm.xor %arg66, %0 : i1
  %3 = "llvm.select"(%arg66, %arg64, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %4 = "llvm.select"(%2, %arg65, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %5 = "llvm.select"(%3, %0, %4) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%5) : (i1) -> ()
}
]

def PR42691_3_logical_after := [llvm|
{
^0(%arg338 : i32):
  %0 = llvm.mlir.constant(-2147483647 : i32) : i32
  %1 = llvm.icmp "ult" %arg338, %0 : i32
  "llvm.return"(%1) : (i1) -> ()
}
]

def Predicate.eval (p : Predicate) (vars : List BitStream) : BitStream :=
  match p with
  | .width .eq n => BitStream.falseIffEq n
  | .width .neq n => BitStream.falseIffNeq n
  | .width .lt n => BitStream.falseIffLt n
  | .width .le n => BitStream.falseIffLe n
  | .width .gt n => BitStream.falseIffGt n
  | .width .ge n => BitStream.falseIffGe n
  | lor p q => Predicate.evalLor (p.eval vars) (q.eval vars)
  | land p q => Predicate.evalLand (p.eval vars) (q.eval vars)
  | binary .eq t₁ t₂ => Predicate.evalEq (t₁.eval vars) (t₂.eval vars)
   
  | binary .neq t1 t2 => Predicate.evalNeq (t1.eval vars) (t2.eval vars)
  | binary .ult t₁ t₂ => Predicate.evalUlt (t₁.eval vars) (t₂.eval vars)
  | binary .ule t₁ t₂ =>
     Predicate.evalLor
       (Predicate.evalEq (t₁.eval vars) (t₂.eval vars))
       (Predicate.evalUlt (t₁.eval vars) (t₂.eval vars))
  | binary .slt t₁ t₂ => Predicate.evalSlt (t₁.eval vars) (t₂.eval vars)
  | binary .sle t₁ t₂ => Predicate.evalLor
       (Predicate.evalEq (t₁.eval vars) (t₂.eval vars))
       (Predicate.evalSlt (t₁.eval vars) (t₂.eval vars))

def liRiscv_15 := [LV| {
  ^entry ():
    %0 = "li"() {imm = -15 : !i64} : (!i64) -> (!i64)
    %1 = "builtin.unrealized_conversion_cast"(%0) : (!i64) -> (i64)
    llvm.return %1 : i64
  }]

def test4c_after := [llvm|
{
^0(%arg7 : i64):
  %0 = llvm.mlir.constant(1) : i64
  %1 = llvm.icmp "slt" %arg7, %0 : i64
  "llvm.return"(%1) : (i1) -> ()
}
]

def sub_mask1_lshr_before := [llvm|
{
^0(%arg21 : i8):
  %0 = llvm.mlir.constant(1 : i8) : i8
  %1 = llvm.mlir.constant(10 : i8) : i8
  %2 = llvm.lshr %arg21, %0 : i8
  %3 = llvm.and %2, %0 : i8
  %4 = llvm.sub %1, %3 : i8
  "llvm.return"(%4) : (i8) -> ()
}
]

def land_lor_right1_before := [llvm|
{
^0(%arg46 : i1, %arg47 : i1):
  %0 = llvm.mlir.constant(false) : i1
  %1 = llvm.mlir.constant(true) : i1
  %2 = "llvm.select"(%arg46, %arg47, %0) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %3 = "llvm.select"(%arg46, %1, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%3) : (i1) -> ()
}
]

def test_add_nuw_nsw__none_are_safe_before := [llvm|
{
^0(%arg35 : i32):
  %0 = llvm.mlir.constant(3 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.mlir.constant(4 : i32) : i32
  %3 = llvm.icmp "eq" %arg35, %0 : i32
  %4 = llvm.add %arg35, %1 overflow<nsw,nuw> : i32
  %5 = "llvm.select"(%3, %2, %4) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def test9_after := [llvm|
{
^0(%arg111 : i32, %arg112 : i32):
  %0 = llvm.or %arg111, %arg112 : i32
  "llvm.return"(%0) : (i32) -> ()
}
]

def negate_add_with_single_negatible_operand_depth2_after := [llvm|
{
^0(%arg21 : i8, %arg22 : i8):
  %0 = llvm.mlir.constant(-21 : i8) : i8
  %1 = llvm.sub %0, %arg21 : i8
  %2 = llvm.mul %1, %arg22 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def hoist_logic_op_with_same_opcode_hands_64 : List (Σ Γ, LLVMPeepholeRewriteRefine 64 Γ) :=
  [⟨_, AndSextSext⟩,
  ⟨_, OrSextSext⟩,
  ⟨_, XorSextSext⟩,
  ⟨_, AndZextZext⟩,
  ⟨_, OrZextZext⟩,
  ⟨_, XorZextZext⟩,
  ⟨_, AndShlShl⟩,
  ⟨_, OrShlShl⟩,
  ⟨_, XorShlShl⟩,
  ⟨_, AndLshrLshr⟩,
  ⟨_, OrLshrLshr⟩,
  ⟨_, XorLshrLshr⟩,
  ⟨_, AndAshrAshr⟩,
  ⟨_, OrAshrAshr⟩,
  ⟨_, XorAshrAshr⟩,
  ⟨_, AndAndAnd⟩,
  ⟨_, OrAndAnd⟩,
  ⟨_, XorAndAnd⟩]

def lshrult_02_09_before := [llvm|
{
^0(%arg342 : i4):
  %0 = llvm.mlir.constant(2 : i4) : i4
  %1 = llvm.mlir.constant(-7 : i4) : i4
  %2 = llvm.lshr %arg342, %0 : i4
  %3 = llvm.icmp "ult" %2, %1 : i4
  "llvm.return"(%3) : (i1) -> ()
}
]

def uge_or_not_max_logical_after := [llvm|
{
^0(%arg302 : i8, %arg303 : i8):
  %0 = llvm.mlir.constant(true) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def ashrsgt_02_06_exact_after := [llvm|
{
^0(%arg79 : i4):
  %0 = llvm.mlir.constant(false) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def ashr_ult_8_after := [llvm|
{
^0(%arg88 : i4):
  %0 = llvm.mlir.constant(-1 : i4) : i4
  %1 = llvm.icmp "sgt" %arg88, %0 : i4
  "llvm.return"(%1) : (i1) -> ()
}
]

def t1_after := [llvm|
{
^0(%arg17 : i16):
  %0 = llvm.mlir.constant(15 : i16) : i16
  %1 = llvm.mlir.constant(-1 : i16) : i16
  %2 = llvm.sub %0, %arg17 : i16
  %3 = llvm.lshr %1, %2 : i16
  "llvm.return"(%3) : (i16) -> ()
}
]

def or_or_and_pat5_before := [llvm|
{
^0(%arg58 : i8, %arg59 : i8, %arg60 : i8, %arg61 : i8):
  %0 = llvm.and %arg58, %arg59 : i8
  %1 = llvm.and %arg58, %arg61 : i8
  %2 = llvm.or %1, %arg60 : i8
  %3 = llvm.or %2, %0 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def intro_example_rhs := [LV| {
  ^entry (%arg: i64, %amount: i64):
    llvm.return %arg : i64
  }]

instance : DecidableNFA' (NFA'.autMsbSet) where

def BMinusAPlusA : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64), Ty.llvm (.bitvec 64)] where
  lhs := [LV| {
    ^entry (%a: i64, %b: i64):
      %0 = llvm.sub %b, %a : i64
      %1 = llvm.add %0, %a : i64
      llvm.return %1 : i64
  }]
  rhs := [LV| {
    ^entry (%a: i64, %b: i64):
      llvm.return %b : i64
  }]

def worklistRun (final : S → Bool) (inits : Array S)
    (hinits : inits.toList.Nodup) (f : S → Array (BitVec n × S)) : CNFA n :=
  ⟨worklistRun' _ S final inits hinits f, worklistRun'_wf (BitVec n) S⟩

def neg_after := [llvm|
{
^0(%arg10 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.mlir.constant(0 : i8) : i8
  %2 = llvm.udiv %arg10, %0 : i8
  %3 = llvm.sub %1, %arg10 : i8
  %4 = llvm.xor %2, %3 : i8
  "llvm.return"(%4) : (i8) -> ()
}
]

def substBvEqualitiesTac : TacticM Unit := do
  liftMetaTactic1 substBvEqualities

deriving Repr, Inhabited, Lean.ToExpr

def shl_lshr_demand4_after := [llvm|
{
^0(%arg17 : i8):
  %0 = llvm.mlir.constant(44 : i8) : i8
  %1 = llvm.mlir.constant(3 : i8) : i8
  %2 = llvm.mlir.constant(-32 : i8) : i8
  %3 = llvm.shl %0, %arg17 : i8
  %4 = llvm.lshr %3, %1 : i8
  %5 = llvm.or disjoint %4, %2 : i8
  "llvm.return"(%5) : (i8) -> ()
}
]

def and_not_or_commute9_after := [llvm|
{
^0(%arg454 : i32, %arg455 : i32, %arg456 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.sdiv %0, %arg454 : i32
  %3 = llvm.sdiv %0, %arg455 : i32
  %4 = llvm.sdiv %0, %arg456 : i32
  %5 = llvm.xor %3, %4 : i32
  %6 = llvm.and %5, %2 : i32
  %7 = llvm.xor %6, %1 : i32
  "llvm.return"(%7) : (i32) -> ()
}
]

def max_sub_uge_c32_before := [llvm|
{
^0(%arg2 : i32):
  %0 = llvm.mlir.constant(2 : i32) : i32
  %1 = llvm.mlir.constant(-2 : i32) : i32
  %2 = llvm.mlir.constant(0 : i32) : i32
  %3 = llvm.icmp "uge" %0, %arg2 : i32
  %4 = llvm.add %arg2, %1 : i32
  %5 = "llvm.select"(%3, %4, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def positive_samevar_shlnuwnsw_before := [llvm|
{
^0(%arg47 : i8, %arg48 : i8):
  %0 = llvm.ashr %arg47, %arg48 : i8
  %1 = llvm.shl %0, %arg48 overflow<nsw,nuw> : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

def lshrugt_02_07_exact_before := [llvm|
{
^0(%arg198 : i4):
  %0 = llvm.mlir.constant(2 : i4) : i4
  %1 = llvm.mlir.constant(7 : i4) : i4
  %2 = llvm.lshr exact %arg198, %0 : i4
  %3 = llvm.icmp "ugt" %2, %1 : i4
  "llvm.return"(%3) : (i1) -> ()
}
]

@[simp_denote]
def rem_llvm_16 := [LV| {
  ^entry (%x: i16, %y: i16):
    %1 = llvm.srem %x, %y : i16
    llvm.return %1 : i16
  }]

RV64.sub in RISCV.Instructions

def masked_icmps_mask_notallzeros_bmask_mixed_7b_logical_before := [llvm|
{
^0(%arg75 : i32):
  %0 = llvm.mlir.constant(6 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.mlir.constant(15 : i32) : i32
  %3 = llvm.mlir.constant(8 : i32) : i32
  %4 = llvm.mlir.constant(false) : i1
  %5 = llvm.and %arg75, %0 : i32
  %6 = llvm.icmp "ne" %5, %1 : i32
  %7 = llvm.and %arg75, %2 : i32
  %8 = llvm.icmp "eq" %7, %3 : i32
  %9 = "llvm.select"(%6, %8, %4) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%9) : (i1) -> ()
}
]

CoeDep in Init.Coe

mkFreshExprMVar expr

|
</all_available_defs>

<all_available_lemmas>
Bool.false_eq_true in Init.Data.Bool
IsEmpty.exists_iff in Mathlib.Logic.IsEmpty
Option.isSome_none in Init.Data.Option.Basic
iff_false in Init.SimpLemmas
Option.get_some in Init.Data.Option.Basic
Option.isSome_iff_exists in Init.Data.Option.Lemmas
forall_exists_index in Init.PropLemmas
Exists.choose_spec in Init.Classical

@[simp] theorem map_cons : (Γ.cons a).map f = (Γ.map f).cons (f a)

theorem eq.ty_eq {v : Γ.Var t} {w : Γ.Var u} (h : v.eq w) : t = u

@[simp]
theorem Expr.op_mk {Γ : Ctxt d.Ty} {ty} {eff : EffectKind} (op : d.Op)
    (ty_eq : ty = DialectSignature.returnTypes op)
    (eff_le : DialectSignature.effectKind op ≤ eff)
    (args : HVector (Var Γ) (DialectSignature.sig op))
    (regArgs) :
    (Expr.mk op ty_eq eff_le args regArgs).op = op

@[simp]
theorem Expr.regArgs_mk {Γ : Ctxt d.Ty} {ty eff op}
    (ty_eq : ty = DialectSignature.returnTypes op)
    (eff_le : DialectSignature.effectKind op ≤ eff)
    (args : HVector (Var Γ) (DialectSignature.sig op)) (regArgs) :
    (Expr.mk op ty_eq eff_le args regArgs).regArgs = regArgs

@[simp] theorem appendCases_appendInl (v : Γ.Var t) :
    appendCases (motive := motive) left right v.appendInl = (left v)

@[simp]
theorem Expr.args_mk {Γ : Ctxt d.Ty} {ty eff op}
    (ty_eq : ty = DialectSignature.returnTypes op)
    (eff_le : DialectSignature.effectKind op ≤ eff)
    (args : HVector (Var Γ) (DialectSignature.sig op)) (regArgs) :
    (Expr.mk op ty_eq eff_le args regArgs).args = args

theorem Id.bind_eq' (x : Id α) (f : α → id β) : x >>= f = f x

@[simp] theorem Expr.denoteOp_eq_denoteOp_of {e₁ : Expr d Γ eff ty} {e₂ : Expr d Δ eff ty}
    {Γv : Valuation Γ} {Δv : Valuation Δ}
    (op_eq : e₁.op = e₂.op)
    (h_args : HVector.map Γv (op_eq ▸ e₁.args)
              = HVector.map Δv e₂.args)
    (h_regArgs : HEq e₁.regArgs.denote e₂.regArgs.denote) :
    e₁.denoteOp Γv = e₂.denoteOp Δv

theorem Id.pure_eq' (a : α) : (pure a : Id α) = a

theorem and_or2_wrong_operand_thm.extracted_1._2 : ∀ (x x_1 x_2 : BitVec 1),
  ¬(x_2 ^^^ 1#1) &&& x_1 = 1#1 → x_1 &&& (x_2 ^^^ 1#1) = 1#1 → False

theorem max_sub_ult_c1_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x <ᵤ 1#32) = 1#1 → x + -1#32 = signExtend 32 (ofBool (x == 0#32))

theorem ashrsgt_02_04_exact_thm.extracted_1._1 : ∀ (x : BitVec 4),
  ¬(True ∧ x >>> 2#4 <<< 2#4 ≠ x ∨ 2#4 ≥ ↑4) → ofBool (4#4 <ₛ x.sshiftRight' 2#4) = 0#1

theorem ule_or_not_min_commute_proof : ule_or_not_min_commute_before ⊑ ule_or_not_min_commute_after

theorem ashrslt_03_15_exact_proof : ashrslt_03_15_exact_before ⊑ ashrslt_03_15_exact_after

theorem or_logic_or_logic_and_2_thm.extracted_1._3 : ∀ (x x_1 x_2 : BitVec 1),
  x_2 ||

lemma RawCNFA.autSignedCmp_wf {cmp} : autSignedCmp cmp |>.WF

theorem PR28476_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  zeroExtend 32 (ofBool (x_1 != 0#32) &&& ofBool (x != 0#32)) ^^^ 1#32 =
    zeroExtend 32 (ofBool (x_1 == 0#32) ||| ofBool (x == 0#32))

theorem main8_logical_thm.extracted_1._4 : ∀ (x : BitVec 32),
  ¬ofBool (x &&& 64#32 != 0#32) = 1#1 →
    ¬ofBool (x &&& 192#32 == 0#32) = 1#1 → ¬ofBool (truncate 8 x <ₛ 0#8) = 1#1 → 1#32 = 2#32

theorem lsb_mask_sign_zext_proof : lsb_mask_sign_zext_before ⊑ lsb_mask_sign_zext_after

theorem bools_multi_uses1_logical_thm.extracted_1._18 : ∀ (x x_1 x_2 : BitVec 1),
  ¬x_2 ^^^ 1#1 = 1#1 → ¬x_2 = 1#1 → ¬0#1 = 1#1 → 0#1 ^^^ 0#1 = x_1 ^^^ 0#1

theorem sub_select_sext_op_swapped_non_const_args_thm.extracted_1._2 : ∀ (x : BitVec 6) (x_1 : BitVec 1),
  ¬x_1 = 1#1 → signExtend 6 x_1 - x = 0#6 - x

@[simp] theorem Com.rec'_var (e : Expr d Γ eff u) (body : Com d _ _ t) :
    (Com.var e body).rec' (motive:=motive) rets var
    = var e body (body.rec' (motive:=motive) rets var)

theorem ult_umin1_proof : ult_umin1_before ⊑ ult_umin1_after

theorem xor_lshr_thm.extracted_1._2 : ∀ (x x_1 x_2 x_3 : BitVec 8),
  ¬(x_2 ≥ ↑8 ∨ x_2 ≥ ↑8) → ¬x_2 ≥ ↑8 → x_3 >>> x_2 ^^^ x_1 ^^^ x >>> x_2 = (x_3 ^^^ x) >>> x_2 ^^^ x_1

theorem alive_AndOrXor_2118___A__B__A___A__B  (w : Nat)   : alive_AndOrXor_2118___A__B__A___A__B_src w  ⊑ alive_AndOrXor_2118___A__B__A___A__B_tgt w

theorem main7e_logical_thm.extracted_1._2 : ∀ (x x_1 x_2 : BitVec 32),
  ¬ofBool (x_2 &&& x_1 &&& x == x_2 &&& x_1) = 1#1 →
    ofBool (x_2 &&& x_1 &&& x != x_2 &&& x_1) = 1#1 → ¬0#1 = 1#1 → 1#32 = zeroExtend 32 1#1

theorem or_not_and_and_not_and_xor_proof : or_not_and_and_not_and_xor_before ⊑ or_not_and_and_not_and_xor_after

theorem ashrsgt_02_06_proof : ashrsgt_02_06_before ⊑ ashrsgt_02_06_after

theorem one_side_fold_eq_thm.extracted_1._4 : ∀ (x x_1 : BitVec 32) (x_2 : BitVec 1),
  ¬x_2 = 1#1 → ¬x_2 ^^^ 1#1 = 1#1 → False

theorem scalar_i8_lshr_and_negC_eq_not_negatedPowerOf2_proof : scalar_i8_lshr_and_negC_eq_not_negatedPowerOf2_before ⊑ scalar_i8_lshr_and_negC_eq_not_negatedPowerOf2_after

@[simp]
theorem unifyVars_eq_some_iff :
    unifyVars w v mapIn = some ((), mapOut)
    ↔ ( mapIn.lookup ⟨t, w⟩ = none ∧ mapIn.insert ⟨t, w⟩ v = mapOut
        ∨ mapIn.lookup ⟨t, w⟩ = v ∧ mapIn = mapOut
      )

theorem sge_swap_or_not_max_logical_thm (e e_1 : IntW 8) :
  select (icmp IntPred.sle e_1 e) (const? 1 1) (icmp IntPred.ne e (const? 8 127)) ⊑ const? 1 1

theorem udiv_exact_ne_0_proof : udiv_exact_ne_0_before ⊑ udiv_exact_ne_0_after

theorem bools2_logical_commute3_and1_thm.extracted_1._2 : ∀ (x x_1 : BitVec 1), x_1 &&& x = 1#1 → ¬x = 1#1 → False

theorem shl_sub_no_commute_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ¬(3#8 ≥ ↑8 ∨ 2#8 ≥ ↑8) → 2#8 ≥ ↑8 ∨ 5#8 ≥ ↑8 → False

omit [Fintype S] [DecidableEq S] in
lemma processOneElem_trans_preserve (st : worklist.St A S) (final : S → Bool) (a b : A) (sa : S) (s s1 s2 : State) :
    s2 ∈ st.m.tr s1 b →
    s2 ∈ (processOneElem A S final s st (a, sa)).m.tr s1 b

theorem mul_eleven' (x : BitVec w) : 11 * x =
  (x + x + x + x + x +
   x + x + x + x + x +
   x)

theorem ashrsgt_01_15_exact_thm (e : IntW 4) :
  icmp IntPred.sgt (ashr e (const? 4 1) { «exact» := true }) (const? 4 (-1)) ⊑
    icmp IntPred.sgt e (const? 4 (-1))

theorem orn_and_cmp_1_logical_thm.extracted_1._1 : ∀ (x : BitVec 1) (x_1 x_2 : BitVec 37),
  ¬ofBool (x_2 ≤ₛ x_1) = 1#1 → x = 1#1 → ofBool (x_1 <ₛ x_2) = x

theorem rem_euclid_wrong_sign_test_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬(8#32 == 0 || 32 != 1 && x == intMin 32 && 8#32 == -1) = true →
    ofBool (0#32 <ₛ x.srem 8#32) = 1#1 →
      (8#32 == 0 || 32 != 1 && x == intMin 32 && 8#32 == -1) = true ∨ True ∧ (x.srem 8#32).saddOverflow 8#32 = true →
        False

theorem pr89516_thm (e e_1 : IntW 8) :
  select (icmp IntPred.slt e_1 (const? 8 0))
      (add (LLVM.srem (const? 8 1) (shl (const? 8 1) e { «nsw» := false, «nuw» := true }))
        (shl (const? 8 1) e { «nsw» := false, «nuw» := true }) { «nsw» := false, «nuw» := true })
      (LLVM.srem (const? 8 1) (shl (const? 8 1) e { «nsw» := false, «nuw» := true })) ⊑
    add (LLVM.srem (const? 8 1) (shl (const? 8 1) e { «nsw» := false, «nuw» := true }))
      (select (icmp IntPred.slt e_1 (const? 8 0)) (shl (const? 8 1) e { «nsw» := false, «nuw» := true })
        (const? 8 0))
      { «nsw» := false, «nuw» := true }

theorem icmp_eq_x_invertable_y2_todo_thm.extracted_1._3 : ∀ (x x_1 : BitVec 8) (x_2 : BitVec 1),
  ¬x_2 = 1#1 → ofBool (x_1 ^^^ -1#8 == x ||| x_1 ^^^ -1#8) = ofBool (x &&& x_1 == 0#8)

theorem ashr_ult_11_thm (e : IntW 4) :
  icmp IntPred.ult (ashr e (const? 4 1)) (const? 4 (-5)) ⊑ icmp IntPred.sgt e (const? 4 (-1))

theorem icmp_equality_test_commute_icmp2_proof : icmp_equality_test_commute_icmp2_before ⊑ icmp_equality_test_commute_icmp2_after

theorem test3_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬(True ∧ x_1.ssubOverflow x = true ∨ True ∧ x_1.ssubOverflow x = true) →
    ¬(True ∧ x_1.ssubOverflow x = true) →
      ofBool (x_1 - x == 0#32) ||

theorem alive_AndOrXor_2587__BAA___B__A : alive_AndOrXor_2587__BAA___B__A_src ⊑ alive_AndOrXor_2587__BAA___B__A_tgt

@[simp] theorem getValue_value [Inhabited α] : (value a).getValue = a

theorem e_1085 :
    4 * t + 1 *  ~~~t - 7 *  ~~~(z ^^^ t) + 5 *  ~~~z + 4 * z + 1 *  ~~~(z ||| t) - 9 *  ~~~(z |||  ~~~t) - 1 * (z &&& t) = 5 * (z &&&  ~~~t)

theorem e_2383 :
     - 2 * ((d &&& e) ||| (e ^^^ f)) + 2 * ((d &&& e) ^^^ (e ||| f)) - 1 * (f ^^^  ~~~(d ||| ( ~~~e &&& f))) - 5 * ( ~~~e &&&  ~~~(d ^^^ f)) + 4 * (d ||| ( ~~~e &&& f)) + 4 * ( ~~~(d ||| e) |||  ~~~(e ^^^ f)) + 2 * ((d &&& e) ^^^  ~~~(d ^^^ (e &&& f))) - 1 * ( ~~~(d ||| e) ||| (e ^^^ f)) - 5 * (e &&& (d |||  ~~~f)) - 6 * ( ~~~d &&& ( ~~~e ||| f)) - 6 * (f ^^^ ( ~~~d &&& (e ||| f))) - 11 * ( ~~~f &&&  ~~~(d ^^^ e)) + 3 * ((d &&& e) |||  ~~~(d ^^^ (e ^^^ f))) + 1 * ( ~~~d ||| ( ~~~e &&& f)) + 5 * ( ~~~(d ^^^ e) ||| (d ^^^ f)) + 1 * ((d &&& e) ^^^  ~~~(d ^^^ ( ~~~e ||| f))) - 7 * ( ~~~d ||| ( ~~~e ||| f)) - 11 *  ~~~(d ||| (e ^^^ f)) + 2 * (f ^^^  ~~~(d &&& (e ||| f))) + 2 * (e ^^^ (d &&& ( ~~~e ||| f))) + 3 * ((e &&&  ~~~f) ^^^ (d ||| (e ^^^ f))) - 5 *  ~~~( ~~~d ||| (e &&& f)) + 1 * ((d ||| e) &&& (e ^^^ f)) - 7 *  ~~~(d ^^^ (e &&& f)) + 1 * (d |||  ~~~f) - 7 * (e ^^^  ~~~(d &&& (e ||| f))) - 2 * (f ^^^ ( ~~~d ||| ( ~~~e &&& f))) - 2 * ((d ^^^ e) &&&  ~~~(d ^^^ f)) - 1 * (e &&&  ~~~(d &&& f)) + 5 * (e &&&  ~~~(d &&&  ~~~f)) + 1 * (f ^^^ (d ||| (e &&& f))) + 1 *  ~~~(d &&& e) + 3 * (f ^^^  ~~~(d ||| e)) - 11 * ( ~~~f &&& (d ^^^ e)) - 1 * (e ^^^ (d ||| ( ~~~e &&& f))) + 4 *  ~~~(e |||  ~~~f) + 7 * (f ||| (d &&&  ~~~e)) - 7 * ((d &&& f) ^^^ (d ^^^ (e &&& f))) - 2 * ( ~~~f |||  ~~~(d ^^^ e)) - 2 *  ~~~(d ||| (e &&& f)) + 5 *  ~~~d - 1 * (d ||| (e ||| f)) + 1 * (d ||| (e &&& f)) - 5 * ((d &&& e) |||  ~~~(e ^^^ f)) + 1 * (e |||  ~~~(d ^^^ f)) + 7 * ((d &&& f) ^^^ (e ||| f)) - 1 * (e &&& (d ^^^ f)) - 6 * (f ^^^ (d ||| e)) + 1 *  ~~~(d |||  ~~~e) - 11 * ( ~~~(d ^^^ e) &&&  ~~~(d ^^^ f)) + 4 * (e ^^^ (d &&& f)) + 2 * (d &&&  ~~~e) - 1 * (f ^^^  ~~~(d &&&  ~~~e)) + 7 * (f ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) + 7 * (d &&& (e ^^^ f)) + 11 * (d ^^^ f) + 2 * ( ~~~d &&& (e ||| f)) + 2 * (e ^^^ ( ~~~d ||| (e ^^^ f))) + 1 * (f &&& (d ^^^ e)) - 6 * (e ^^^ ( ~~~d &&& (e ||| f))) + 4 * (d ||| ( ~~~e ||| f)) - 1 * (e &&&  ~~~f) + 4 * ((e &&& f) ||| ( ~~~d &&& (e ||| f))) + 38 *  ~~~(d ||| (e ||| f)) + 10 *  ~~~(d ||| ( ~~~e ||| f)) - 4 *  ~~~( ~~~d ||| (e ||| f)) - 27 * ( ~~~d &&& ( ~~~e &&& f)) - 39 * ( ~~~d &&& (e &&& f)) - 30 * (d &&& ( ~~~e &&& f)) + 15 * (d &&& (e &&& f)) =  - 5 * (f &&& (d ||| e))

theorem ashrslt_01_04_exact_proof : ashrslt_01_04_exact_before ⊑ ashrslt_01_04_exact_after

theorem not_or_or_and_no_and_commute1_or_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 32),
  (x_2 ||| x_1 ||| x ^^^ -1#32) &&& (x_1 &&& x ^^^ -1#32) = x_2 &&& (x_1 ^^^ -1#32) ||

theorem e_1218 :
    1 * t - 2 * (z |||  ~~~t) + 11 *  ~~~z + 1 *  ~~~(z &&&  ~~~t) - 1 *  ~~~t - 2 * z - 9 *  ~~~(z ||| t) - 17 *  ~~~(z |||  ~~~t) + 1 * (z &&&  ~~~t) =  - 2 * (z &&& t) - 4 * (z ^^^ t)

theorem or_not_xor_common_op_commute0_thm (e e_1 e_2 : IntW 4) :
  LLVM.or (LLVM.or (LLVM.xor e_2 (const? 4 (-1))) e_1) (LLVM.xor e_2 e) ⊑
    LLVM.or e_1 (LLVM.xor (LLVM.and e_2 e) (const? 4 (-1)))

theorem same_source_matching_signbits_proof : same_source_matching_signbits_before ⊑ same_source_matching_signbits_after

theorem sel_false_val_is_a_masked_ashr_of_true_val1_thm.extracted_1._4 : ∀ (x : BitVec 64) (x_1 : BitVec 32),
  ¬ofBool (x_1 &&& BitVec.ofInt 32 (-2147483588) == 0#32) = 1#1 →
    ¬(2#32 ≥ ↑32 ∨ zeroExtend 64 ((x_1 &&& BitVec.ofInt 32 (-2147483588)).sshiftRight' 2#32) ≥ ↑64) →
      ¬(2#32 ≥ ↑32 ∨
            True ∧ (x_1.sshiftRight' 2#32 &&& BitVec.ofInt 32 (-536870897)).msb = true ∨
              zeroExtend 64 (x_1.sshiftRight' 2#32 &&& BitVec.ofInt 32 (-536870897)) ≥ ↑64) →
        x.sshiftRight' (zeroExtend 64 ((x_1 &&& BitVec.ofInt 32 (-2147483588)).sshiftRight' 2#32)) =
          x.sshiftRight' (zeroExtend 64 (x_1.sshiftRight' 2#32 &&& BitVec.ofInt 32 (-536870897)))

theorem ashr_lshr_exact_lshr_only_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ofBool (-1#32 <ₛ x_1) = 1#1 → ¬(True ∧ x_1 >>> x <<< x ≠ x_1 ∨ x ≥ ↑32) → x ≥ ↑32 → False

theorem and_xor_or5_proof : and_xor_or5_before ⊑ and_xor_or5_after

theorem and_or_not_not_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 32),
  (x_2 &&& x_1 ^^^ -1#32 ||| x) &&& (x &&& x_2 ^^^ -1#32) = (x_1 ||| x) &&& x_2 ^^^ -1#32

theorem alive_AndOrXor_2627  (w : Nat)   : alive_AndOrXor_2627_src w  ⊑ alive_AndOrXor_2627_tgt w

theorem test4_proof : test4_before ⊑ test4_after

theorem exact_lshr_ne_both_equal_thm (e : IntW 8) :
  icmp IntPred.ne (lshr (const? 8 126) e { «exact» := true }) (const? 8 126) ⊑
    icmp IntPred.ne e (const? 8 0)

theorem sub_shl_same_amount_partial_nsw2_thm (e e_1 e_2 : IntW 6) :
  sub (shl e_2 e_1) (shl e e_1 { «nsw» := true, «nuw» := false }) { «nsw» := true, «nuw» := false } ⊑
    shl (sub e_2 e) e_1

theorem PR75692_1_thm (e : IntW 32) :
  LLVM.or (LLVM.xor e (const? 32 4)) (LLVM.xor e (const? 32 (-5))) ⊑ const? 32 (-1)

theorem testi16i8_com_thm (e : IntW 16) :
  icmp IntPred.eq (trunc 8 (lshr e (const? 16 8))) (ashr (trunc 8 e) (const? 8 7)) ⊑
    icmp IntPred.ult (add e (const? 16 128)) (const? 16 256)

theorem sge_or_max_logical_thm (e e_1 : IntW 8) :
  select (icmp IntPred.sge e_1 e) (const? 1 1) (icmp IntPred.eq e_1 (const? 8 127)) ⊑
    icmp IntPred.sge e_1 e

@[simp]
lemma Set.mem_cast (A : W → Type) (P : A w → Prop) (h : w = w') (x : A w') :
  x ∈ h ▸ setOf P ↔
  P (h ▸ x)

theorem test_zext2_thm.extracted_1._2 : ∀ (x x_1 : BitVec 1), x_1 = 1#1 → 1#32 = zeroExtend 32 1#1

theorem positive_with_aggressive_icmp_logical_proof : positive_with_aggressive_icmp_logical_before ⊑ positive_with_aggressive_icmp_logical_after

theorem sub_zext_trunc_lshr_thm.extracted_1._1 : ∀ (x : BitVec 64),
  ¬15#64 ≥ ↑64 →
    16#32 ≥ ↑32 ∨ 31#32 ≥ ↑32 ∨ True ∧ ((truncate 32 x <<< 16#32).sshiftRight' 31#32).saddOverflow 10#32 = true →
      False

theorem src_fv_eq_proof : src_fv_eq_before ⊑ src_fv_eq_after

theorem shift_trunc_signbit_test_proof : shift_trunc_signbit_test_before ⊑ shift_trunc_signbit_test_after

theorem test29_proof : test29_before ⊑ test29_after
</all_available_lemmas>

<local_ctx>
import LeanMLIR.Framework

import LeanMLIR.Transforms.Rewrite.Mapping

open Ctxt (Var VarSet Valuation Hom)

variable {d} [DialectSignature d] [DecidableEq d.Ty]

variable {Γ : Ctxt d.Ty} {ty : d.Ty}

abbrev MatchVarM (Δ Γ : Ctxt d.Ty) := (StateT (Mapping Δ Γ) Option)

abbrev MatchVar (Δ Γ : Ctxt d.Ty)  := MatchVarM Δ Γ Unit

def MatchVarM.unifyVars {Δ Γ : Ctxt d.Ty} (v : Δ.Var t) (w : Γ.Var t) : MatchVar Δ Γ :=
  fun ma =>
    match ma.lookup ⟨_, v⟩ with
    | some v =>
      if v = w then
        some ((), ma)
      else
        none
    | none =>
      some ((), AList.insert ⟨_, v⟩ w ma)

open MatchVarM

variable [DecidableEq d.Op]

def matchArg [DecidableEq d.Op]
    (lets : Lets d Γ_in eff Γ_out) (matchLets : Lets d Δ_in .pure Δ_out) :
    {l : List d.Ty} → HVector (Var Γ_out) l → HVector (Var Δ_out) l →
    MatchVar Δ_in Γ_out
  | _, .nil, .nil => return
  | t::l, .cons vₗ vsₗ, .cons vᵣ vsᵣ => do
      matchVar (t := t) lets vₗ matchLets vᵣ
      matchArg lets matchLets vsₗ vsᵣ
  termination_by l => (sizeOf matchLets, l.length + 1)

def matchVar {Γ_in Γ_out Δ_in Δ_out : Ctxt d.Ty} {t : d.Ty} [DecidableEq d.Op]
    (lets : Lets d Γ_in eff Γ_out) (v : Var Γ_out t) :
    (matchLets : Lets d Δ_in .pure Δ_out) →
    (w : Var Δ_out t) →
    MatchVar Δ_in Γ_out
   
  | @Lets.var _ _ _ _ Δ_out ts matchLets matchExpr, w => by admit /- proof elided -/
      | right w =>
        exact matchVar lets v matchLets w
      | left w => exact do
        let ⟨ts', w', ie⟩ ← lets.getPureExpr v
        if hs : ∃ h : ie.op = matchExpr.op, ie.regArgs = (h ▸ matchExpr.regArgs) then
          have hts : Ctxt.ofList ts' = ts := by admit /- proof elided -/

end

section MatchVar

variable [DecidableEq d.Op] {Γ_in Γ_out Δ_in Δ_out t te}
          {lets : Lets d Γ_in eff Γ_out} {v : Var Γ_out t}
          {matchLets : Lets d Δ_in .pure Δ_out}
          {matchExpr : Expr d Δ_out .pure te}

variable (lets v matchLets w) (mapIn : Mapping _ _) in

def MatchVarResult := { mapOut : Mapping _ _ //
  ∃ (mapIn' mapOut' : Mapping _ _),
    mapIn.entries ⊆ mapIn'.entries
    ∧ mapOut'.entries ⊆ mapOut.entries
    ∧ matchVar lets v matchLets w mapIn' = some ((), mapOut') }

variable (lets matchLets) {tys} (vs ws : HVector _ tys) (mapIn : Mapping _ _) in

def MatchArgResult := { mapOut : Mapping _ _ //
  ∃ (mapIn' mapOut' : Mapping _ _),
    mapIn.entries ⊆ mapIn'.entries
    ∧ mapOut'.entries ⊆ mapOut.entries
    ∧ matchArg lets matchLets vs ws mapIn' = some ((), mapOut') }

namespace MatchVarResult

variable [TyDenote d.Ty] [∀ (t : d.Ty), Inhabited ⟦t⟧] in

section Left

variable {w : Δ_out.Var t}

def eqvVarLeft  :
    MatchVarResult lets v (.var matchLets matchExpr) w.appendInr ma
    ≃ MatchVarResult lets v matchLets w ma where
  toFun := fun ⟨x, h⟩ => ⟨x, by admit /- proof elided -/
  ⟩
  invFun := fun ⟨x, h⟩ => ⟨x, by admit /- proof elided -/
  ⟩

variable {mapIn} (mapOut : MatchVarResult lets v (.var matchLets matchExpr) w.appendInr mapIn)

end Left

variable {w : Var ⟨te⟩ _} {mapIn}

noncomputable def toArgResult
    (mapOut : MatchVarResult lets v (.var matchLets matchExpr) w.appendInl mapIn) :
    let args := mapOut.getPureExpr_eq_some.choose
    MatchArgResult lets matchLets args matchExpr.args mapIn :=
  ⟨mapOut.1, by admit /- proof elided -/
  ⟩

end MatchVarResult

end MatchVar

section SubsetEntries

open MatchVar

section UnifyVars

variable {Δ Γ : Ctxt d.Ty} {t} (w : Δ.Var t) (v : Γ.Var t)

end UnifyVars

variable [DecidableEq d.Op]

end SubsetEntries

namespace MatchArgResult

variable [DecidableEq d.Op] {Γ_in Γ_out Δ_in Δ_out te}
          {lets : Lets d Γ_in eff Γ_out}
          {matchLets : Lets d Δ_in .pure Δ_out}
          {matchExpr : Expr d Δ_out .pure te}
          {u us}
          {v : Γ_out.Var u} {vs : HVector Γ_out.Var us}
          {w : Δ_out.Var u} {ws : HVector Δ_out.Var us}
          {mapIn : Mapping _ _}
          (mapOut : MatchArgResult lets matchLets (v ::ₕ vs) (w ::ₕ ws) mapIn)

end MatchArgResult

section DenoteLemmas

variable [TyDenote d.Ty] [DecidableEq d.Op]

variable [∀ (t : d.Ty), Inhabited ⟦t⟧]

variable [Monad d.m] [LawfulMonad d.m] [DialectDenote d]

section DenoteIntoSubtype

end DenoteIntoSubtype

variable {Γ_in Γ_out Δ_in Δ_out : Ctxt d.Ty}
    {lets : Lets d Γ_in eff Γ_out}
    {matchLets : Lets d Δ_in .pure Δ_out}
</local_ctx>

<target_theorem>
theorem denote_matchVar
    {v w : Var _ t}
    (mapOut : MatchVarResult lets v matchLets w mapIn)
    (V : lets.ValidDenotation) :
    (matchLets.denote (mapOut.val.mapValuation V.val) w)
    = V.val v :=
</target_theorem>

