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>
Nat in Init.Prelude
Bool in Init.Prelude
Polynomial.X in Mathlib.Algebra.Polynomial.Basic
ZMod in Mathlib.Data.ZMod.Defs
Inhabited in Init.Prelude
Lean.ToExpr in Lean.ToExpr
Repr in Init.Data.Repr
BitVec in Init.Prelude
BitVec.zero in Init.Data.BitVec.Basic
Fin in Init.Prelude
NFA in Mathlib.Computability.NFA
Fin.last in Init.Data.Fin.Basic
NFA.accept in Mathlib.Computability.NFA
NFA.start in Mathlib.Computability.NFA
NFA.step in Mathlib.Computability.NFA
Fin.mk in Init.Prelude
FinEnum in Mathlib.Data.FinEnum
BitVec.ofFin in Init.Prelude
Set in Mathlib.Data.Set.Defs
SetRel in Mathlib.Data.Rel
BEq in Init.Prelude
DecidableEq in Init.Prelude
Hashable in Init.Prelude
Std.HashMap in Std.Data.HashMap.Basic
Std.HashSet in Std.Data.HashSet.Basic
Finset in Mathlib.Data.Finset.Defs
Finset.range in Mathlib.Data.Finset.Range
LawfulBEq in Init.Core

abbrev State := Nat

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

def RawCNFA.empty : RawCNFA A := {
  stateMax := 0
  initials := ∅
  finals := ∅
  trans := ∅
}

instance RawCNFA.statesFinset (m : RawCNFA A) : Fintype m.states := (Finset.range m.stateMax).fintypeCoeSort

inductive WidthPredicate
| eq
| neq
| lt
| le
| gt
| ge
deriving Repr, Inhabited, Lean.ToExpr

instance instFinEnumBV : FinEnum (BitVec w) where
  card := 2^w
  equiv := {
    toFun := fun x => x.toFin
    invFun := fun x => BitVec.ofFin x
    left_inv := by admit /- proof elided -/

def CNFA.Sim (m : CNFA n) (M : NFA' n) :=
  m.m.Sim M.M

def RawCNFA.Sim (m : RawCNFA A) (A : NFA A S) := ∃ R, RawCNFA.Simul m A R ⊤ ∅

structure RawCNFA.Simul (m : RawCNFA A) (M : NFA A Q) (R : SetRel State Q) (D : Set Q) (T : Set (Q × A × Q)) where
  accept {s q} : s ~[R] q → (s ∈ m.finals ↔ q ∈ M.accept)
  initial₁ {s} : s ∈ m.initials → ∃ q ∈ M.start, s ~[R] q
  initial₂ {q} : q ∈ M.start → ∃ s ∈ m.initials, s ~[R] q
  trans_match₁ {s s' a q} : s ~[R] q → s' ∈ m.tr s a → ∃ q', q' ∈ M.step q a ∧ s' ~[R] q'
  trans_match₂ {s a q q'} : s ~[R] q → q' ∈ M.step q a → q ∈ D → (q, a, q') ∉ T → ∃ s', s' ∈ m.tr s a ∧ s' ~[R] q'

structure RawCNFA.SimulFun (m : RawCNFA A) (M : NFA A Q) (f : m.states ≃ Q)  where
  accept {q} : ((f.invFun q).val ∈ m.finals ↔ q ∈ M.accept)
  initial {q} : q ∈ M.start ↔ (f.invFun q).val ∈ m.initials
  trans_match {a q q'} : q' ∈ M.step q a ↔ (f.invFun q').val ∈ m.tr (f.invFun q) a

@[inline]
def RawCNFA.tr (m : RawCNFA A) s a := m.trans.getD (s, a) ∅

abbrev R := (ZMod q)[X] ⧸ (Ideal.span {f q n})

structure CNFA (n : Nat) where
  m : RawCNFA (BitVec n)
  wf : m.WF

structure NFA' (n : Nat) where
  σ : Type
  M : NFA (BitVec n) σ

abbrev zero   : BitStream := fun _ => false

def BitStream : Type := Nat → Bool

def RawCNFA.states (m : RawCNFA A) : Finset State := Finset.range m.stateMax

structure RawCNFA.WF (m : RawCNFA A) where
  initials_lt : ∀ {s}, s ∈ m.initials → s ∈ m.states
  finals_lt : ∀ {s}, s ∈ m.finals → s ∈ m.states
  trans_src_lt : ∀ s_a ∈ m.trans, s_a.1 ∈ m.states
  trans_tgt_lt : s' ∈ m.tr s a → s' ∈ m.states

def RawCNFA.addTrans (m : RawCNFA A) (a : A) (s s' : State) : RawCNFA A :=
  let ns := m.trans.getD (s, a) ∅
  let ns := ns.insert s'
  { m with trans :=  m.trans.insert (s, a) ns }

def RawCNFA.newState (m : RawCNFA A) : State × RawCNFA A :=
  let old := m.stateMax
  let m := { m with stateMax := old + 1 }
  (old, m)

def RawCNFA.addInitial (m : RawCNFA A) (s : State) : RawCNFA A :=
  { m with initials := m.initials.insert s }

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

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) -> ()
}
]

Int.sub in Init.Data.Int.Basic

def llvm_const_lower_riscv_li_22 : LLVMPeepholeRewriteRefine 64 [] :=
  {lhs := constLLVM_22, rhs:= liRiscv_22,
   correct := by admit /- proof elided -/

def ashr_uge_noexact_before := [llvm|
{
^0(%arg160 : i8):
  %0 = llvm.mlir.constant(3 : i8) : i8
  %1 = llvm.mlir.constant(10 : i8) : i8
  %2 = llvm.ashr %arg160, %0 : i8
  %3 = llvm.icmp "uge" %2, %1 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

@[simp_llvm]
def sub? {w : Nat} (x y : BitVec w) : IntW w :=
  .value <| x - y

def icmp_slt_0_and_icmp_ne_neg2_i32_fail_before := [llvm|
{
^0(%arg44 : i32):
  %0 = llvm.mlir.constant(-2 : i32) : i32
  %1 = llvm.mlir.constant(31 : i32) : i32
  %2 = llvm.icmp "ne" %arg44, %0 : i32
  %3 = llvm.zext %2 : i1 to i32
  %4 = llvm.lshr %arg44, %1 : i32
  %5 = llvm.and %4, %3 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def and_add_bool_to_select_after := [llvm|
{
^0(%arg5 : i1, %arg6 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = "llvm.select"(%arg5, %0, %arg6) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%1) : (i32) -> ()
}
]

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

def test_or_eq_a_b_after := [llvm|
{
^0(%arg36 : i1, %arg37 : i8, %arg38 : i8):
  %0 = "llvm.select"(%arg36, %arg37, %arg38) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  "llvm.return"(%0) : (i8) -> ()
}
]

def t7_ashr_before := [llvm|
{
^0(%arg29 : i32, %arg30 : i32):
  %0 = llvm.mlir.constant(32 : i32) : i32
  %1 = llvm.mlir.constant(-2 : i32) : i32
  %2 = llvm.sub %0, %arg30 : i32
  %3 = llvm.ashr exact %arg29, %2 : i32
  %4 = llvm.add %arg30, %1 : i32
  %5 = llvm.ashr %3, %4 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def main7f_after := [llvm|
{
^0(%arg44 : i32, %arg45 : i32, %arg46 : i32, %arg47 : i32, %arg48 : i32):
  %0 = llvm.and %arg45, %arg47 : i32
  %1 = llvm.and %arg46, %arg48 : i32
  %2 = llvm.or %0, %1 : i32
  %3 = llvm.and %arg44, %2 : i32
  %4 = llvm.icmp "ne" %3, %2 : i32
  %5 = llvm.zext %4 : i1 to i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def uaddo_commute4_before := [llvm|
{
^0(%arg22 : i32, %arg23 : i32, %arg24 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg23, %0 : i32
  %2 = llvm.add %arg23, %arg22 : i32
  %3 = llvm.icmp "ult" %1, %arg22 : i32
  %4 = "llvm.select"(%3, %arg24, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%4) : (i32) -> ()
}
]

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

def ugt_rem_zero_nsw_after := [llvm|
{
^0(%arg166 : i8):
  %0 = llvm.mlir.constant(3 : i8) : i8
  %1 = llvm.icmp "ugt" %arg166, %0 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

instance : One Term := ⟨one⟩

@[simp_denote]
def and_riscv_i64 :=
  [LV| {
    ^entry (%arg0: i64, %arg1: i64):
    %a = "builtin.unrealized_conversion_cast" (%arg0) : (i64) -> (!i64)
    %b = "builtin.unrealized_conversion_cast" (%arg1) : (i64) -> (!i64)
    %0 = and %a, %b : !i64
    %1 = "builtin.unrealized_conversion_cast" (%0) : (!i64) -> (i64)
    llvm.return %1 : i64
  }]

def inf : EffectKind → EffectKind → EffectKind
  | .impure, .impure => .impure
  | _, _ => .pure

noncomputable def R.toTensor {q n} (a : R q n) : List Int :=
  List.range a.repLength |>.map fun i =>
        a.coeff i |>.toInt

def test9_after := [llvm|
{
^0(%arg198 : i32, %arg199 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg199, %0 : i32
  %2 = llvm.or %arg198, %1 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def lshr_pow2_slt_before := [llvm|
{
^0(%arg58 : i8):
  %0 = llvm.mlir.constant(-128 : i8) : i8
  %1 = llvm.mlir.constant(3 : i8) : i8
  %2 = llvm.lshr %0, %arg58 : i8
  %3 = llvm.icmp "slt" %2, %1 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

def select_sub_icmp_after := [llvm|
{
^0(%arg214 : i32, %arg215 : i32, %arg216 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.icmp "eq" %arg214, %0 : i32
  %2 = "llvm.select"(%1, %arg216, %arg215) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def zext_nneg_sext_sle_op0_narrow_before := [llvm|
{
^0(%arg50 : i8, %arg51 : i16):
  %0 = llvm.zext nneg %arg50 : i8 to i32
  %1 = llvm.sext %arg51 : i16 to i32
  %2 = llvm.icmp "sle" %0, %1 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

def negate_select_of_op_vs_negated_op_nsw_after := [llvm|
{
^0(%arg21 : i8, %arg22 : i8, %arg23 : i1):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.sub %0, %arg21 : i8
  %2 = "llvm.select"(%arg23, %arg21, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  %3 = llvm.add %2, %arg22 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def ule_umax2_after := [llvm|
{
^0(%arg50 : i32, %arg51 : i32):
  %0 = llvm.icmp "ule" %arg51, %arg50 : i32
  "llvm.return"(%0) : (i1) -> ()
}
]

CommRing in Mathlib.Algebra.Ring.Defs

def getIdentityAndAbsorptionConstraints
    (_pred : FpPredicate)
    (_symVars : Std.HashSet Nat) : List GenFpLogicalExpr :=
 []

def f_after := [llvm|
{
^0(%arg0 : i32):
  %0 = llvm.mlir.constant(false) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def shl_nsw_add_nuw_before := [llvm|
{
^0(%arg64 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.add %arg64, %0 overflow<nuw> : i32
  %3 = llvm.shl %1, %2 overflow<nsw> : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def mul_add_to_mul_9_before := [llvm|
{
^0(%arg23 : i16):
  %0 = llvm.mlir.constant(16384 : i16) : i16
  %1 = llvm.mul %arg23, %0 overflow<nsw> : i16
  %2 = llvm.mul %arg23, %0 overflow<nsw> : i16
  %3 = llvm.add %1, %2 overflow<nsw> : i16
  "llvm.return"(%3) : (i16) -> ()
}
]

@[reducible]
instance : DialectDenote ExOp ExTy where
  denote
    | .add, .cons (a : Nat) (.cons b .nil), _ => a + b
    | .runK (k : Nat), (.cons (v : Nat) .nil), (.cons rgn _nil) =>
      k.iterate (fun val => rgn (fun _ty _var => val)) v

def eq_10_before := [llvm|
{
^0(%arg130 : i32, %arg131 : i32):
  %0 = llvm.mlir.constant(8 : i32) : i32
  %1 = llvm.trunc %arg130 : i32 to i8
  %2 = llvm.lshr %arg130, %0 : i32
  %3 = llvm.trunc %2 : i32 to i8
  %4 = llvm.trunc %arg131 : i32 to i8
  %5 = llvm.lshr %arg131, %0 : i32
  %6 = llvm.trunc %5 : i32 to i8
  %7 = llvm.icmp "eq" %1, %4 : i8
  %8 = llvm.icmp "eq" %3, %6 : i8
  %9 = llvm.and %7, %8 : i1
  "llvm.return"(%9) : (i1) -> ()
}
]

structure Item where
 name : String
 tac : Syntax

def  shift_mul:=
  [llvm(64)| {
  ^bb0(%X : _, %Y : _):
    %c1 = llvm.mlir.constant(1)
    %poty = llvm.shl %c1, %Y
    %r = llvm.mul %poty, %X
    llvm.return %r
  }]

def test_with_even_before := [llvm|
{
^0(%arg313 : i32):
  %0 = llvm.mlir.constant(4 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.shl %0, %arg313 : i32
  %3 = llvm.and %2, %1 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

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

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

def test11_after := [llvm|
{
^0(%arg89 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  "llvm.return"(%0) : (i32) -> ()
}
]

def generalizeMap (g : MVarId) (e : Expr) : MetaM (FVarId × MVarId) :=  do
  let (fvars, g) ← g.generalize #[{ expr := e : GeneralizeArg}]
  
  if h : fvars.size = 1 then
    return (fvars[0], g)
  throwError"expected a single free variable from generalizing map {e}, found multiple..."

def or_not_and_commute6_after := [llvm|
{
^0(%arg519 : i32, %arg520 : i32, %arg521 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg520, %arg521 : i32
  %2 = llvm.xor %arg519, %0 : i32
  %3 = llvm.and %1, %2 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def ashr_mul_times_3_div_2_exact_2_after := [llvm|
{
^0(%arg17 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.ashr exact %arg17, %0 : i32
  %2 = llvm.add %arg17, %1 overflow<nsw> : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def sub_sext_mask1_trunc_lshr_after := [llvm|
{
^0(%arg16 : i64):
  %0 = llvm.mlir.constant(48) : i64
  %1 = llvm.mlir.constant(63) : i64
  %2 = llvm.mlir.constant(10 : i8) : i8
  %3 = llvm.shl %arg16, %0 : i64
  %4 = llvm.ashr %3, %1 : i64
  %5 = llvm.trunc %4 overflow<nsw> : i64 to i8
  %6 = llvm.add %5, %2 overflow<nsw> : i8
  %7 = llvm.zext %6 : i8 to i32
  "llvm.return"(%7) : (i32) -> ()
}
]

def masked_icmps_mask_notallzeros_bmask_mixed_swapped_7b_logical_after := [llvm|
{
^0(%arg31 : i32):
  %0 = llvm.mlir.constant(false) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

instance : Lean.ToExpr TestDialect.Op :=

def autWidth_equiv : (CNFA.autWidth wp n).m.states ≃ (NFA'.autWidth wp n).σ where
  toFun := fun ⟨s, hs⟩ =>
    Fin.mk s (by admit /- proof elided -/
    )
  invFun q := ⟨q.val, by admit /- proof elided -/
  ⟩
  left_inv := by admit /- proof elided -/

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

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

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

def icmp {w : Nat} (c : IntPred) (x y : IntW w) : IntW 1 := do
  let x' ← x
  let y' ← y
  icmp? c x' y'

def land_lor_right1_after := [llvm|
{
^0(%arg46 : i1, %arg47 : i1):
  "llvm.return"(%arg46) : (i1) -> ()
}
]

def p13_commutativity0_after := [llvm|
{
^0(%arg28 : i32, %arg29 : i32):
  %0 = llvm.mlir.constant(65535 : i32) : i32
  %1 = llvm.icmp "ugt" %arg28, %0 : i32
  %2 = "llvm.select"(%1, %arg29, %0) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def ofList {Γ : Ctxt _} ty : (l : List ((ty : Comb.Ty) × Γ.Var ty)) → (h : l.all (·.1 = ty)) → HVector (Γ.Var) (List.replicate l.length ty)
| [], h => .nil
| ⟨ty', var⟩::rest, h =>
  have hty : ty' = ty := by admit /- proof elided -/

def srai_test: LLVMPeepholeRewriteRefine 16 [Ty.llvm (.bitvec 16)] where
  lhs := srai_llvm
  rhs := srai_riscv

def both_sides_fold_slt_after := [llvm|
{
^0(%arg39 : i32, %arg40 : i1):
  %0 = llvm.mlir.constant(false) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def icmp_ne_and_pow2_shl1_after := [llvm|
{
^0(%arg67 : i32):
  %0 = llvm.mlir.constant(4 : i32) : i32
  %1 = llvm.icmp "eq" %arg67, %0 : i32
  %2 = llvm.zext %1 : i1 to i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def addhshlhsdivhscalar2_after := [llvm|
{
^0(%arg17 : i32):
  %0 = llvm.mlir.constant(1073741824 : i32) : i32
  %1 = llvm.srem %arg17, %0 : i32
  "llvm.return"(%1) : (i32) -> ()
}
]

def test_zext4_after := [llvm|
{
^0(%arg35 : i1, %arg36 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.xor %arg36, %0 : i1
  %2 = "llvm.select"(%1, %0, %arg35) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %3 = llvm.zext %2 : i1 to i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def irc_constants_C1Minus2MinusC2_0_0 : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64)] where
  lhs := [LV| {
    ^entry (%a: i64):
      %c1 = llvm.mlir.constant (0) : i64
      %c2 = llvm.mlir.constant (0) : i64
      %0 = llvm.sub %c1, %a : i64
      %1 = llvm.sub %0, %c2 : i64
      llvm.return %1 : i64
  }]
  rhs := [LV| {
    ^entry (%a: i64):
      %c1 = llvm.mlir.constant (0) : i64
      %c2 = llvm.mlir.constant (0) : i64
      %0 = llvm.sub %c1, %c2 : i64
      %1 = llvm.sub %0, %a : i64
      llvm.return %1 : i64
  }]

declare_config_elab elabGenConfig GenConfig

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

def ult_swap_and_not_max_after := [llvm|
{
^0(%arg102 : i8, %arg103 : i8):
  %0 = llvm.icmp "ugt" %arg103, %arg102 : i8
  "llvm.return"(%0) : (i1) -> ()
}
]

def srai_i32_test : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64)] where
  lhs := srai_llvm_i64
  rhs := srai_riscv_i64

def Env.ofEnvFin (envFin : EnvFin w n) : Env w := (List.finRange n).map envFin

def test7_after := [llvm|
{
^0(%arg44 : i8):
  %0 = llvm.mlir.constant(-1 : i29) : i29
  "llvm.return"(%0) : (i29) -> ()
}
]

instance instReprTy : Repr (Dialect.Ty d) where reprPrec t _ := printTy t

def unmasked_shlop_insufficient_mask_shift_amount_before := [llvm|
{
^0(%arg14 : i16, %arg15 : i16, %arg16 : i16):
  %0 = llvm.mlir.constant(15 : i16) : i16
  %1 = llvm.mlir.constant(255 : i16) : i16
  %2 = llvm.mlir.constant(8 : i16) : i16
  %3 = llvm.and %arg16, %0 : i16
  %4 = llvm.and %arg14, %1 : i16
  %5 = llvm.sub %2, %3 : i16
  %6 = llvm.shl %arg15, %5 : i16
  %7 = llvm.lshr %4, %3 : i16
  %8 = llvm.or %6, %7 : i16
  %9 = llvm.trunc %8 : i16 to i8
  "llvm.return"(%9) : (i8) -> ()
}
]

def sgt_negative_multip_rem_zero_after := [llvm|
{
^0(%arg169 : i8):
  %0 = llvm.mlir.constant(-3 : i8) : i8
  %1 = llvm.icmp "slt" %arg169, %0 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

def select_icmp_eq_pow2_before := [llvm|
{
^0(%arg13 : i8):
  %0 = llvm.mlir.constant(4 : i8) : i8
  %1 = llvm.mlir.constant(0 : i8) : i8
  %2 = llvm.and %arg13, %0 : i8
  %3 = llvm.icmp "eq" %2, %1 : i8
  %4 = llvm.xor %arg13, %0 : i8
  %5 = "llvm.select"(%3, %arg13, %4) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  "llvm.return"(%5) : (i8) -> ()
}
]

def positive_biggerlshr_before := [llvm|
{
^0(%arg60 : i8):
  %0 = llvm.mlir.constant(6 : i8) : i8
  %1 = llvm.mlir.constant(3 : i8) : i8
  %2 = llvm.lshr %arg60, %0 : i8
  %3 = llvm.shl %2, %1 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

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

def n2_before := [llvm|
{
^0(%arg0 : i8, %arg1 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.mlir.constant(1 : i8) : i8
  %2 = llvm.shl %0, %arg1 : i8
  %3 = llvm.xor %2, %1 : i8
  %4 = llvm.and %3, %arg0 : i8
  %5 = llvm.icmp "ne" %4, %arg0 : i8
  "llvm.return"(%5) : (i1) -> ()
}
]

noncomputable def nonesUntilSome (x : Stream α) (not_stuck : x ≠ stuck α) : Nat :=
  prop.choose
where
  prop : ∃ i, (x.drop i).head.isSome ∧ ∀ j < i, x.get j = none := by admit /- proof elided -/

def or_not_and_commute3_after := [llvm|
{
^0(%arg528 : i32, %arg529 : i32, %arg530 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg529, %arg530 : i32
  %2 = llvm.xor %arg528, %0 : i32
  %3 = llvm.and %1, %2 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def Vector.ofArray {α : Type u} (a : Array α) : List.Vector α a.size :=
 Vector.ofList a.toList

def rev8_mul_and_lshr_after := [llvm|
{
^0(%arg29 : i8):
  %0 = llvm.mlir.constant(2050) : i64
  %1 = llvm.mlir.constant(139536) : i64
  %2 = llvm.mlir.constant(32800) : i64
  %3 = llvm.mlir.constant(558144) : i64
  %4 = llvm.mlir.constant(65793) : i64
  %5 = llvm.mlir.constant(16) : i64
  %6 = llvm.zext %arg29 : i8 to i64
  %7 = llvm.mul %6, %0 overflow<nsw,nuw> : i64
  %8 = llvm.and %7, %1 : i64
  %9 = llvm.mul %6, %2 overflow<nsw,nuw> : i64
  %10 = llvm.and %9, %3 : i64
  %11 = llvm.or disjoint %8, %10 : i64
  %12 = llvm.mul %11, %4 overflow<nsw,nuw> : i64
  %13 = llvm.lshr %12, %5 : i64
  %14 = llvm.trunc %13 : i64 to i8
  "llvm.return"(%14) : (i8) -> ()
}
]

instance [DecidableEq Ty] {Γ : Ctxt Ty} {t : Ty} : Fintype (Γ.Var t) where
  elems := {
      val := .ofList <|
                List.range Γ.length
                |>.filterMap fun i =>
                    if h : Γ[i]? = some t then
                      some ⟨i, h⟩
                    else
                      none
      nodup := by admit /- proof elided -/

def scalar_i8_lshr_and_negC_eq_not_negatedPowerOf2_after := [llvm|
{
^0(%arg0 : i8, %arg1 : i8):
  %0 = llvm.mlir.constant(-3 : i8) : i8
  %1 = llvm.mlir.constant(0 : i8) : i8
  %2 = llvm.shl %0, %arg1 : i8
  %3 = llvm.and %arg0, %2 : i8
  %4 = llvm.icmp "eq" %3, %1 : i8
  "llvm.return"(%4) : (i1) -> ()
}
]

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

def par_after := [llvm|
{
^0(%arg81 : i32, %arg82 : i32, %arg83 : i32, %arg84 : i32):
  %0 = llvm.icmp "slt" %arg81, %arg82 : i32
  %1 = "llvm.select"(%0, %arg83, %arg84) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%1) : (i32) -> ()
}
]

RV64.binv in RISCV.Instructions
</all_available_defs>

<all_available_lemmas>
BitVec.zero_eq in Init.Data.BitVec.Basic
Finset.mem_range in Mathlib.Data.Finset.Range
Function.iterate_add in Mathlib.Logic.Function.Iterate
eq_of_forall_lt_iff in Mathlib.Order.Basic
gt_iff_lt in Init.Core
Fin.add_def in Init.Data.Fin.Lemmas
Fin.val_one in Init.Data.Fin.Lemmas
Nat.mod_eq_of_lt in Init.Data.Nat.Div.Basic
eq_iff_eq_of_cmp_eq_cmp in Mathlib.Order.Compare

@[grind ., simp, aesop 50% unsafe]
lemma wf_addTrans [LawfulBEq A] (m : RawCNFA A) (hwf : m.WF) s a s' (hin : s ∈ m.states) (hin' : s' ∈ m.states) :
    (m.addTrans a s s').WF

@[grind =, simp]
lemma RawCNFA.same_stateMax (m : RawCNFA A) x y (z : Std.HashMap (State × A) (Std.HashSet State)) :
    (RawCNFA.mk m.stateMax x y z).states = m.states

@[grind =, simp, aesop 50% unsafe]
lemma newState_eq (m : RawCNFA A) :
    m.newState.1 = m.stateMax

@[grind =, simp]
lemma addInitial_stateMax {m : RawCNFA A} : (m.addInitial s).stateMax = m.stateMax

@[grind =, simp]
lemma addTrans_stateMax {m : RawCNFA A} : (m.addTrans a s s').stateMax = m.stateMax

lemma simulFun_sim {m : CNFA n} f :
    m.m.SimulFun M.M f → m.Sim M

lemma simulFun_sim_raw [LawfulBEq A] {m : RawCNFA A} (hwf : m.WF) f :
    m.SimulFun M f → m.Sim M

@[simp]
lemma RawCNFA.Simul.initial {m : RawCNFA A} {M : NFA A Q} (hsim : m.Simul M R ⊤ ∅) :
    R.set_eq m.initials.toSet M.start

theorem pr33078_1_thm.extracted_1._2 : ∀ (x : BitVec 8),
  ¬8#16 ≥ ↑16 → ¬7#8 ≥ ↑8 → truncate 8 (signExtend 16 x >>> 8#16) = x.sshiftRight' 7#8

theorem and_xor_or4_proof : and_xor_or4_before ⊑ and_xor_or4_after

theorem e_1600 :
    7 * ( ~~~(a &&&  ~~~b) &&& (a ^^^ (b ^^^ c))) + 4 * ((a &&& b) ^^^ (a ^^^ ( ~~~b ||| c))) - 1 * ((a &&& c) ^^^  ~~~(a ^^^ ( ~~~b &&& c))) - 1 * ( ~~~(a &&& b) &&& (b ^^^ c)) + 7 * (b ^^^  ~~~( ~~~a &&& ( ~~~b &&& c))) - 1 * ( ~~~a &&& (b ^^^ c)) - 3 * (a ||| (b &&& c)) + 1 * ((a |||  ~~~b) &&&  ~~~(b ^^^ c)) - 3 * (b ||| (a ^^^ c)) - 5 *  ~~~( ~~~a &&& (b &&& c)) + 7 *  ~~~(a &&&  ~~~c) + 4 * (b ^^^  ~~~(a ||| ( ~~~b &&& c))) - 17 *  ~~~(a ||| (b ||| c)) - 3 *  ~~~(a ||| ( ~~~b ||| c)) + 3 *  ~~~( ~~~a ||| (b ||| c)) - 11 * ( ~~~a &&& (b &&& c)) - 12 * (a &&& ( ~~~b &&& c)) - 11 * (a &&& (b &&& c)) = 15 * ( ~~~a &&& ( ~~~b &&& c)) - 7 * (c ^^^ (a &&& b))

theorem n3_constmask_samemask_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  x_1 &&& 65280#32 ||

theorem shl_or_thm.extracted_1._2 : ∀ (x x_1 : BitVec 16),
  ¬((42#16 == 0 || 16 != 1 && x_1 == intMin 16 && 42#16 == -1) = true ∨ 5#16 ≥ ↑16 ∨ 7#16 ≥ ↑16) →
    ¬(12#16 ≥ ↑16 ∨
          (42#16 == 0 || 16 != 1 && x_1 == intMin 16 && 42#16 == -1) = true ∨
            True ∧ (x_1.srem 42#16 <<< 7#16).sshiftRight' 7#16 ≠ x_1.srem 42#16 ∨ 7#16 ≥ ↑16) →
      (x_1.srem 42#16 ||| x <<< 5#16) <<< 7#16 = x <<< 12#16 ||

theorem test7_proof : test7_before ⊑ test7_after

theorem ugt_swap_and_min_commute_logical_proof : ugt_swap_and_min_commute_logical_before ⊑ ugt_swap_and_min_commute_logical_after

theorem lshr_pow2_sgt_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬x ≥ ↑8 → True ∧ BitVec.ofInt 8 (-128) >>> x <<< x ≠ BitVec.ofInt 8 (-128) ∨ x ≥ ↑8 → False

theorem urem_i32_c_proof : urem_i32_c_before ⊑ urem_i32_c_after

theorem tryFactorization_add_nuw_mul_nuw_mul_nuw_var_proof : tryFactorization_add_nuw_mul_nuw_mul_nuw_var_before ⊑ tryFactorization_add_nuw_mul_nuw_mul_nuw_var_after

theorem e_367 :
     - 1 * (x |||  ~~~y) + 3 *  ~~~y - 3 *  ~~~x - 6 *  ~~~(x ^^^ y) + 2 *  ~~~(x ||| y) - 2 *  ~~~(x |||  ~~~y) - 7 * (x &&&  ~~~y) + 7 * (x &&& y) =  - 5 *  ~~~(x &&& y)

theorem n2_thm.extracted_1._2 : ∀ (x : BitVec 1), ¬x = 1#1 → ¬x ^^^ 1#1 = 1#1 → False

theorem shl_xor_lshr_thm (e e_1 e_2 : IntW 32) :
  lshr (LLVM.xor (shl e_2 e_1 { «nsw» := false, «nuw» := true }) e) e_1 ⊑ LLVM.xor (lshr e e_1) e_2

theorem ashrsgt_03_00_exact_proof : ashrsgt_03_00_exact_before ⊑ ashrsgt_03_00_exact_after

theorem e_290 :
    5 *  ~~~(x ^^^ y) + 2 * x + 2 *  ~~~(x &&&  ~~~y) + 11 *  ~~~(x &&& y) - 18 *  ~~~(x ||| y) - 13 *  ~~~(x |||  ~~~y) - 13 * (x &&&  ~~~y) = 9 * (x &&& y)

theorem wrongimm_proof : wrongimm_before ⊑ wrongimm_after

theorem and_ne_with_one_bit_diff_constants2_proof : and_ne_with_one_bit_diff_constants2_before ⊑ and_ne_with_one_bit_diff_constants2_after

theorem logical_and_bitwise_and_icmps_comm2_proof : logical_and_bitwise_and_icmps_comm2_before ⊑ logical_and_bitwise_and_icmps_comm2_after

theorem src_srem_shl_demand_eliminate_signbit_proof : src_srem_shl_demand_eliminate_signbit_before ⊑ src_srem_shl_demand_eliminate_signbit_after

theorem zext_nneg_i1_thm.extracted_1._1 : ∀ (x : BitVec 1), ¬(True ∧ x.msb = true) → zeroExtend 32 x = 0#32

theorem ashrslt_01_09_exact_thm (e : IntW 4) :
  icmp IntPred.slt (ashr e (const? 4 1) { «exact» := true }) (const? 4 (-7)) ⊑ const? 1 0

theorem masked_icmps_bmask_notmixed_and_thm (e : IntW 32) :
  LLVM.and (icmp IntPred.ne (LLVM.and e (const? 32 15)) (const? 32 3))
      (icmp IntPred.ne (LLVM.and e (const? 32 255)) (const? 32 243)) ⊑
    icmp IntPred.ne (LLVM.and e (const? 32 15)) (const? 32 3)

theorem ule_umax4_proof : ule_umax4_before ⊑ ule_umax4_after

theorem test47_proof : test47_before ⊑ test47_after

theorem andn_or_cmp_4_logical_proof : andn_or_cmp_4_logical_before ⊑ andn_or_cmp_4_logical_after

theorem or_eq_notY_eq_0_thm (e e_1 : IntW 8) :
  icmp IntPred.eq (LLVM.or e_1 (LLVM.xor e (const? 8 (-1)))) (LLVM.xor e (const? 8 (-1))) ⊑
    icmp IntPred.eq (LLVM.and e_1 e) (const? 8 0)

@[simp] theorem Com.size_castPureToEff {com : Com d Γ .pure ty} :
    (com.castPureToEff eff).size = com.size

theorem test8_logical_thm (e : IntW 32) :
  select (icmp IntPred.ne e (const? 32 0)) (icmp IntPred.ult e (const? 32 14)) (const? 1 0) ⊑
    icmp IntPred.ult (add e (const? 32 (-1))) (const? 32 13)

theorem e_2303 :
    11 * ((d &&& f) ^^^  ~~~(d ^^^ ( ~~~e &&& f))) - 2 *  ~~~(d ||| e) + 1 *  ~~~( ~~~d &&& ( ~~~e ||| f)) - 1 * (f ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) + 4 * ((d |||  ~~~e) &&& (d ^^^ (e ^^^ f))) + 7 *  ~~~( ~~~d &&& (e ||| f)) - 7 *  ~~~e + 4 * ( ~~~d &&& (e ||| f)) + 11 * ( ~~~(d &&& e) &&& (e ^^^ f)) - 2 * (e ^^^  ~~~( ~~~d ||| (e ^^^ f))) - 6 *  ~~~(d |||  ~~~f) - 5 * (e ^^^ (d &&& (e ||| f))) - 1 *  ~~~(d &&&  ~~~e) + 1 * ( ~~~e &&& (d ^^^ f)) - 3 * ((d &&&  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) - 3 * (e ^^^ ( ~~~d ||| ( ~~~e &&& f))) + 2 *  ~~~(d ||| ( ~~~e &&& f)) + 7 * (e ^^^ ( ~~~d ||| (e ^^^ f))) + 5 *  ~~~(d ^^^ e) + 5 * (f ^^^  ~~~(d ||| (e &&& f))) - 7 * (f ^^^  ~~~(d &&& (e &&& f))) + 3 * (f |||  ~~~(d |||  ~~~e)) - 11 * (f ^^^ ( ~~~d ||| (e &&& f))) + 5 * ( ~~~f &&&  ~~~(d ^^^ e)) + 3 * (f |||  ~~~(d ^^^ e)) + 2 * (e ^^^  ~~~(d &&& ( ~~~e &&& f))) + 7 * ((d &&& e) ^^^ (d ^^^ ( ~~~e ||| f))) - 1 * (d ^^^ ( ~~~e ||| f)) + 4 *  ~~~(d ^^^ (e ||| f)) - 5 * (d &&& e) + 11 * (d ^^^ (e ^^^ f)) - 6 * (e ^^^ (d &&&  ~~~f)) + 2 * (f ^^^  ~~~( ~~~d ||| (e &&& f))) + 1 *  ~~~(d &&& (e &&& f)) - 1 * (f ^^^ (d ||| ( ~~~e &&& f))) + 1 * (d ||| ( ~~~e &&& f)) - 3 *  ~~~(d &&& (e ||| f)) + 1 * ((d &&& e) ||| (d ^^^ (e ^^^ f))) - 5 * (f ^^^ ( ~~~d &&& ( ~~~e ||| f))) + 1 * (d &&& (e ||| f)) + 2 * ((d &&& e) |||  ~~~(e ||| f)) + 5 * ((d &&& f) ^^^ (d ^^^ ( ~~~e &&& f))) + 3 * ( ~~~(d &&& e) &&&  ~~~(d ^^^ (e ^^^ f))) + 1 * (f ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) - 5 * ( ~~~d ||| ( ~~~e &&& f)) - 2 * (f ^^^ ( ~~~d ||| (e ||| f))) + 3 * ( ~~~f |||  ~~~(d ^^^ e)) - 2 * ( ~~~d ||| (e ^^^ f)) + 7 * ((d ^^^ e) |||  ~~~(d ^^^ f)) + 1 * (f ^^^  ~~~(d &&& e)) - 2 * ((e &&&  ~~~f) ^^^ (d ||| (e ^^^ f))) - 1 *  ~~~(d ||| (e ^^^ f)) - 7 * (e &&&  ~~~(d &&&  ~~~f)) + 4 * (d ||| f) + 2 * ((d &&& e) ^^^  ~~~(d ^^^ (e &&& f))) - 25 *  ~~~(d ||| (e ||| f)) - 12 *  ~~~(d ||| ( ~~~e ||| f)) - 11 *  ~~~( ~~~d ||| (e ||| f)) - 9 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 34 * ( ~~~d &&& ( ~~~e &&& f)) - 8 * ( ~~~d &&& (e &&& f)) - 20 * (d &&& ( ~~~e &&& f)) - 43 * (d &&& (e &&& f)) = 11 * (d ^^^ ( ~~~e &&& f))

theorem sext_multiuse_proof : sext_multiuse_before ⊑ sext_multiuse_after

theorem samesign_inverted_commute1_proof : samesign_inverted_commute1_before ⊑ samesign_inverted_commute1_after

theorem PR39793_bswap_u32_as_u16_trunc_proof : PR39793_bswap_u32_as_u16_trunc_before ⊑ PR39793_bswap_u32_as_u16_trunc_after

theorem e_301 :
     - 3 * y + 1 * (x ||| y) + 1 * (x |||  ~~~y) - 1 *  ~~~(x ||| y) - 9 *  ~~~(x |||  ~~~y) - 13 * (x &&&  ~~~y) + 1 * (x &&& y) =  - 11 * (x ^^^ y)

theorem ugt_and_not_min_commute_proof : ugt_and_not_min_commute_before ⊑ ugt_and_not_min_commute_after

theorem n13_overshift_proof : n13_overshift_before ⊑ n13_overshift_after

theorem n9_wrong_x0_thm.extracted_1._2 : ∀ (x x_1 : BitVec 8),
  ¬ofBool (x_1 &&& 15#8 == 0#8) = 1#1 → x_1 + 16#8 &&& BitVec.ofInt 8 (-16) = (x_1 &&& BitVec.ofInt 8 (-16)) + 16#8

theorem nonexact_lshr_eq_exactdiv_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬x ≥ ↑8 → ofBool (80#8 >>> x == 5#8) = ofBool (x == 4#8)

theorem width_1_char_2 (x : BitVec w) (hw : w = 1) : x + x = 0#w

theorem eq_smin3_proof : eq_smin3_before ⊑ eq_smin3_after

theorem icmp_eq_zext_eq_non_boolean_thm (e : IntW 32) :
  icmp IntPred.eq (zext 32 (icmp IntPred.eq e (const? 32 2))) e ⊑
    icmp IntPred.eq e (const? 32 0)

theorem lshrult_03_04_exact_proof : lshrult_03_04_exact_before ⊑ lshrult_03_04_exact_after

theorem ashrslt_01_01_proof : ashrslt_01_01_before ⊑ ashrslt_01_01_after

@[simp, grind=] lemma val_start_appendInl (r : DeleteRange Γ) :
    (r.appendInl (ts := ts)).start.val = r.start.val + ts.length

theorem test_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32), ofBool (x_1 <ₛ x) ||

@[simp]
theorem Term.toBV_bnot {wenv : WidthExpr.Env wcard}
    {tctx : Term.Ctx wcard tcard}
    (benv : Term.BoolEnv bcard)
    (tenv : tctx.Env wenv) (a : Term bcard ncard icard pcard tctx (.bv w)) :
  Term.toBV benv nenv ienv penv tenv (.bnot a) = ~~~ (a.toBV benv nenv ienv penv tenv)

theorem e_2305 :
    4 * (e ^^^ (d ||| f)) - 6 * (d ||| (e ||| f)) - 11 * (e ^^^  ~~~(d ||| ( ~~~e &&& f))) + 11 * (d ||| ( ~~~e ||| f)) + 11 * (f ^^^ (d &&& e)) + 1 *  ~~~(d ^^^ (e ^^^ f)) - 1 * (e ^^^ (d &&&  ~~~f)) + 5 *  ~~~(d &&&  ~~~e) + 2 * (d &&&  ~~~f) + 1 * ((d &&& f) ^^^ (d ^^^ (e &&& f))) - 11 * ((d ||| e) &&& (d ^^^ (e ^^^ f))) + 4 * (f ^^^  ~~~(d |||  ~~~e)) - 6 * ( ~~~(d |||  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) + 4 * ((d ||| e) &&&  ~~~(e ^^^ f)) - 1 * ((e &&&  ~~~f) |||  ~~~( ~~~d ||| ( ~~~e &&& f))) + 2 * (f ^^^ (d &&&  ~~~e)) + 4 *  ~~~(e |||  ~~~f) + 1 * (e ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) - 7 * (f &&& (d ||| e)) - 1 * (f ^^^ ( ~~~d ||| ( ~~~e &&& f))) - 2 * ((d |||  ~~~e) &&& (e ^^^ f)) - 1 * (e ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) + 1 * (d ^^^ ( ~~~e ||| f)) - 7 * ((d ^^^ e) &&& (d ^^^ f)) + 2 *  ~~~(e &&& f) + 1 *  ~~~e + 7 * (e ^^^  ~~~( ~~~d ||| (e &&& f))) - 1 *  ~~~( ~~~d ||| ( ~~~e &&& f)) - 1 * ( ~~~f ||| (d ^^^ e)) - 6 * (f ^^^  ~~~(d &&& (e &&& f))) + 3 * (d ^^^ f) + 5 * (e ^^^  ~~~(d &&& f)) + 1 * (e ^^^ (d ||| ( ~~~e &&& f))) + 7 *  ~~~(d &&&  ~~~d) - 2 * ((e &&&  ~~~f) ^^^ ( ~~~d ||| (e ^^^ f))) + 4 * e + 7 * (e ^^^  ~~~( ~~~d &&& (e ^^^ f))) - 1 * (e ^^^ (d ||| (e ^^^ f))) - 7 * ((d &&& e) ^^^ (e ||| f)) - 2 * (f ||| (d ^^^ e)) - 7 * (d ||| (e &&& f)) - 2 * (e &&& f) + 1 * (e ||| (d ^^^ f)) - 2 * (d &&&  ~~~e) - 3 * (f &&&  ~~~(d &&&  ~~~e)) - 1 * (f ^^^ ( ~~~d ||| ( ~~~e ||| f))) + 2 * (e ^^^ ( ~~~d &&& (e ^^^ f))) - 7 * (f ||| (d &&&  ~~~e)) - 2 * f + 1 * ((e &&&  ~~~f) |||  ~~~(d ||| ( ~~~e &&& f))) - 2 * (f ^^^ ( ~~~d &&& (e ||| f))) - 11 * ( ~~~f &&&  ~~~(d ^^^ e)) - 11 * (f ^^^ (d &&& (e ||| f))) + 3 * (f ^^^  ~~~(d ||| ( ~~~e &&& f))) - 1 * (e ^^^  ~~~(d &&& ( ~~~e &&& f))) - 3 * ((d ^^^ e) &&&  ~~~(d ^^^ f)) - 1 * ( ~~~d ||| (e &&& f)) - 4 *  ~~~(d ||| (e ||| f)) + 3 *  ~~~(d ||| ( ~~~e ||| f)) + 11 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 22 * ( ~~~d &&& ( ~~~e &&& f)) + 12 * ( ~~~d &&& (e &&& f)) - 6 * (d &&& ( ~~~e &&& f)) =  - 15 * (d &&& (e &&& f)) + 3 *  ~~~( ~~~d ||| (e ||| f))

theorem icmp_sgt11_proof : icmp_sgt11_before ⊑ icmp_sgt11_after

theorem test3_proof : test3_before ⊑ test3_after

@[simp]
lemma reduce_spec (M : NFA α σ) : M.reduce.accepts = M.accepts

theorem xor_sext_sext_proof : xor_sext_sext_before ⊑ xor_sext_sext_after

theorem test13_proof : test13_before ⊑ test13_after

theorem e_1587 :
     - 5 * ( ~~~(a ^^^ b) &&&  ~~~(a ^^^ c)) - 3 * ( ~~~c ||| (a ^^^ b)) + 3 * ((a ||| b) &&&  ~~~(a ^^^ (b ^^^ c))) - 2 * (b ^^^ ( ~~~a &&& (b ^^^ c))) + 11 * ( ~~~(a |||  ~~~b) ||| (b ^^^ c)) + 11 * (b ^^^  ~~~( ~~~a &&& ( ~~~b &&& c))) - 1 * ( ~~~a ||| ( ~~~b ||| c)) + 1 * (b &&&  ~~~(a ^^^ c)) - 2 * (a ||| (b &&& c)) + 7 * (c ||| (a &&& b)) - 8 *  ~~~(a ||| ( ~~~b ||| c)) - 5 *  ~~~( ~~~a ||| (b ||| c)) - 9 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 15 * ( ~~~a &&& ( ~~~b &&& c)) - 13 * ( ~~~a &&& (b &&& c)) - 26 * (a &&& ( ~~~b &&& c)) + 2 * (a &&& (b &&& c)) = 5 * ( ~~~c &&&  ~~~(a ^^^ b)) - 3 *  ~~~(a ||| (b ||| c))

theorem substitute_constant_or_ne_uge_commute_thm (e e_1 : IntW 8) :
  LLVM.or (icmp IntPred.uge e_1 e) (icmp IntPred.ne e_1 (const? 8 42)) ⊑
    LLVM.or (icmp IntPred.ne e_1 (const? 8 42)) (icmp IntPred.ult e (const? 8 43))

lemma nfaOfTerm_bv_language (t : Term) :
    nfaOfTerm t |>.bv_recognizes t.language

theorem lshrult_03_05_exact_proof : lshrult_03_05_exact_before ⊑ lshrult_03_05_exact_after

theorem select1_thm.extracted_1._5 : ∀ (x x_1 x_2 : BitVec 32) (x_3 : BitVec 1),
  ¬x_3 = 1#1 → zeroExtend 32 (truncate 8 x_1 + truncate 8 x) = x_1 + x &&& 255#32

theorem sdiv_exact_eq_9_no_of_proof : sdiv_exact_eq_9_no_of_before ⊑ sdiv_exact_eq_9_no_of_after

theorem lshr_16_add_zext_basic_multiuse_proof : lshr_16_add_zext_basic_multiuse_before ⊑ lshr_16_add_zext_basic_multiuse_after

@[simp]
theorem Array.take_ge_size {a : Array α} {n} (h : n ≥ a.size) : a.take n = a

theorem masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_6_proof : masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_6_before ⊑ masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_6_after

theorem test_invert_demorgan_logical_and_thm.extracted_1._5 : ∀ (x x_1 : BitVec 64),
  ¬ofBool (x_1 == 27#64) = 1#1 →
    ofBool (x_1 != 27#64) = 1#1 → (ofBool (x_1 == 0#64) ||| 0#1) ^^^ 1#1 = ofBool (x_1 != 0#64) &&& 1#1

theorem e_861 :
     - 11 *  ~~~(z &&&  ~~~z) + 1 *  ~~~t - 2 *  ~~~(z ^^^ t) + 13 *  ~~~(z |||  ~~~t) + 10 * (z &&&  ~~~t) + 13 * (z &&& t) = 2 *  ~~~z - 14 *  ~~~(z ||| t)

theorem positive_biggershl_shlnuw_lshrexact_proof : positive_biggershl_shlnuw_lshrexact_before ⊑ positive_biggershl_shlnuw_lshrexact_after

theorem icmp_slt_0_and_icmp_sge_neg2_i64_proof : icmp_slt_0_and_icmp_sge_neg2_i64_before ⊑ icmp_slt_0_and_icmp_sge_neg2_i64_after

theorem lshrugt_02_01_thm (e : IntW 4) :
  icmp IntPred.ugt (lshr e (const? 4 2)) (const? 4 1) ⊑ icmp IntPred.slt e (const? 4 0)

theorem sge_to_ugt_proof : sge_to_ugt_before ⊑ sge_to_ugt_after

theorem fold_add_udiv_urem_commuted_thm (e : IntW 32) :
  add (urem e (const? 32 10)) (shl (LLVM.udiv e (const? 32 10)) (const? 32 4)) ⊑
    add (mul (LLVM.udiv e (const? 32 10)) (const? 32 6) { «nsw» := false, «nuw» := true }) e

theorem negate_xor_thm.extracted_1._1 : ∀ (x : BitVec 4), 0#4 - (x ^^^ 5#4) = (x ^^^ BitVec.ofInt 4 (-6)) + 1#4

theorem factorize4_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32), ¬1#32 ≥ ↑32 → x_1 <<< 1#32 * x - x * x_1 = x_1 * x

theorem uadd_sat_flipped_wrong_bounds7_thm (e : IntW 32) :
  select (icmp IntPred.ule e (const? 32 (-12))) (add e (const? 32 9)) (const? 32 (-1)) ⊑
    select (icmp IntPred.ult e (const? 32 (-11))) (add e (const? 32 9)) (const? 32 (-1))

theorem trunc_equality_nuw_zext_thm (e : IntW 8) (e_1 : IntW 32) :
  icmp IntPred.ne (trunc 16 e_1 { «nsw» := false, «nuw» := true }) (zext 16 e) ⊑
    icmp IntPred.ne e_1 (zext 32 e)

theorem sge_swap_or_not_max_proof : sge_swap_or_not_max_before ⊑ sge_swap_or_not_max_after

theorem zext_sext_add_icmp_slt_1_thm.extracted_1._1 : ∀ (x x_1 : BitVec 1),
  ofBool (zeroExtend 8 x_1 + signExtend 8 x <ₛ 1#8) = x ||

theorem e_744 :
    1 * (x ^^^ y) - 11 *  ~~~(x &&&  ~~~x) + 11 * x + 3 *  ~~~(x &&& y) - 3 *  ~~~(x &&&  ~~~y) - 1 *  ~~~y + 1 * y + 14 *  ~~~(x ||| y) + 15 *  ~~~(x |||  ~~~y) - 3 * (x &&&  ~~~y) - 2 * (x &&& y) =  - 4 *  ~~~(x ^^^ y) + 6 *  ~~~x

theorem reduce_xor_common_op_commute1_thm (e e_1 e_2 : IntW 4) :
  LLVM.or (LLVM.xor (LLVM.xor e_2 e_1) e) e_1 ⊑ LLVM.or (LLVM.xor e_2 e) e_1

theorem prove_exact_with_high_mask_limit_proof : prove_exact_with_high_mask_limit_before ⊑ prove_exact_with_high_mask_limit_after

theorem BitVec.eq_iff_sub_zero (x y : BitVec w) : x = y ↔ x - y = 0

theorem bitvec_AddSub_1309 :
  [llvm(w)| {
    ^bb0(%X : _, %Y : _):
      %v1 = llvm.and %X, %Y
      %v2 = llvm.or %X, %Y
      %v3 = llvm.add %v1, %v2
      llvm.return %v3
  }] ⊑ [llvm(w)| {
    ^bb0(%X : _, %Y : _):
      %v3 = llvm.add %X, %Y
      llvm.return %v3
  }]
</all_available_lemmas>

<local_ctx>
import Batteries.Data.Fin.Basic

import Batteries.Data.Fin.Lemmas

import Blase.SingleWidth.Defs

import Blase.AutoStructs.Constructions

import Blase.AutoStructs.Defs

import Blase.AutoStructs.FiniteStateMachine

import Mathlib.Tactic.Ring

import Mathlib.Data.Nat.Size -- TODO: remove and get rid of shiftLeft_eq_mul_pow use

import Mathlib.Data.BitVec

import Mathlib.Tactic.FinCases

open Fin.NatCast

open Mathlib

section fsm

variable {arity : Type} [FinEnum arity]

open BitStream in

end fsm

section nfas_relations

def WidthPredicate.final? (wp : WidthPredicate) (n : Nat) (s : State) : Bool :=
  decide (wp.sat s n)

def RawCNFA.autWidth (wp : WidthPredicate) (n : Nat) : RawCNFA (BitVec 0) :=
  let m := (n+2).iterate f empty
  let m := m.addInitial 0
  m.addTrans (BitVec.zero 0) (n + 1) (n + 1)
where
  f m :=
    let (s, m) := m.newState
    let m := if wp.final? n s then m.addFinal s else m
    if s > 0 then m.addTrans (BitVec.zero 0) (s-1) s else m

def CNFA.autWidth (wp : WidthPredicate) (n : Nat) : CNFA 0 :=
  ⟨RawCNFA.autWidth wp n, RawCNFA.autWidth_wf⟩

def NFA.autWidth (wp : WidthPredicate) (n : Nat) : NFA (BitVec 0) (Fin (n+2)) where
  start := { 0 }
  accept := { s | wp.final? n s }
  step s₁ _ := { s₂ | if s₁ = Fin.last (n+1) then s₁ = s₂ else s₂ = s₁ + 1 }

def NFA'.autWidth (wp : WidthPredicate) (n : Nat) : NFA' 0 := ⟨_, NFA.autWidth wp n⟩

def autWidth_equiv : (CNFA.autWidth wp n).m.states ≃ (NFA'.autWidth wp n).σ where
  toFun := fun ⟨s, hs⟩ =>
    Fin.mk s (by admit /- proof elided -/
    )
  invFun q := ⟨q.val, by admit /- proof elided -/
  ⟩
  left_inv := by admit /- proof elided -/
</local_ctx>

<target_theorem>
lemma CNFA.autWidth_spec : autWidth wp n |>.Sim (NFA'.autWidth wp n) :=
</target_theorem>

