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>
BitVec in Init.Prelude
Fin in Init.Prelude
NFA in Mathlib.Computability.NFA
NFA.accept in Mathlib.Computability.NFA
NFA.start in Mathlib.Computability.NFA
NFA.step in Mathlib.Computability.NFA
Bool in Init.Prelude
Nat in Init.Prelude
BitVec.iunfoldr in Init.Data.BitVec.Folds
List in Init.Prelude
List.Vector in Mathlib.Data.Vector.Defs
Vector in Init.Data.Vector.Basic
Vector.ofFn in Init.Data.Vector.Basic
List.getLast in Init.Data.List.Basic
List.reverseRecOn in Mathlib.Data.List.Induction
NFA.stepSet in Mathlib.Computability.NFA

def BitVec.ofFn {w : Nat} (f : Fin w → Bool) : BitVec w :=
  BitVec.iunfoldr (fun i _ => ((), f i)) () |>.2

@[simp]
def _root_.Set.proj (f : Fin n → Fin m) (bvs : Set (BitVecs m)) : Set (BitVecs n) :=
  BitVecs.transport f '' bvs

def scalar1_before := [llvm|
{
^0(%arg30 : i4, %arg31 : i4):
  %0 = llvm.mlir.constant(-2 : i4) : i4
  %1 = llvm.xor %arg30, %arg31 : i4
  %2 = llvm.and %1, %0 : i4
  %3 = llvm.xor %2, %arg31 : i4
  "llvm.return"(%3) : (i4) -> ()
}
]

noncomputable def R.leadingTerm {q n} (a : R q n) : R q n :=
  let deg? := Polynomial.degree a.representative
  match deg? with
    | .none => 0
    | .some deg =>  R.monomial (a.coeff deg) deg

def test14_after := [llvm|
{
^0(%arg36 : i1, %arg37 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.xor %arg36, %arg37 : i1
  %2 = llvm.xor %1, %0 : i1
  "llvm.return"(%2) : (i1) -> ()
}
]

let subRes ← deductiveSearch expr constants {bv := constBv - target.bv} (depth-1) constId
              res := res ++ subRes.map (λ resExpr => GenBVExpr.bin newVar BVBinOp.add (negate resExpr))

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

def zext_sext_sgt_known_nonneg_after := [llvm|
{
^0(%arg24 : i8, %arg25 : i8):
  %0 = llvm.mlir.constant(127 : i8) : i8
  %1 = llvm.udiv %0, %arg24 : i8
  %2 = llvm.icmp "sgt" %1, %arg25 : i8
  "llvm.return"(%2) : (i1) -> ()
}
]

def src3_after := [llvm|
{
^0(%arg8 : i32, %arg9 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg9, %arg8 : i32
  %2 = llvm.xor %1, %0 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def xor_i32_test : LLVMPeepholeRewriteRefine 32 [Ty.llvm (.bitvec 32), Ty.llvm (.bitvec 32)] where
  lhs := xor_llvm_i32
  rhs := xor_riscv_i32

if constId == parent then 
                continue

def sle_swap_and_min_logical_after := [llvm|
{
^0(%arg212 : i8, %arg213 : i8):
  %0 = llvm.mlir.constant(-128 : i8) : i8
  %1 = llvm.icmp "eq" %arg212, %0 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

def bad_shl2_sub_i32_before := [llvm|
{
^0(%arg9 : i32):
  %0 = llvm.mlir.constant(31 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.sub %arg9, %0 : i32
  %3 = llvm.shl %1, %2 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def test2_before := [llvm|
{
^0(%arg0 : i999, %arg1 : i999):
  %0 = llvm.mlir.constant(65280 : i999) : i999
  %1 = llvm.and %arg0, %0 : i999
  %2 = llvm.and %arg1, %0 : i999
  %3 = llvm.icmp "ne" %1, %2 : i999
  "llvm.return"(%3) : (i1) -> ()
}
]

def slt_zero_ult_i1_fail2_after := [llvm|
{
^0(%arg6 : i32, %arg7 : i1):
  %0 = llvm.mlir.constant(31 : i32) : i32
  %1 = llvm.zext %arg7 : i1 to i32
  %2 = llvm.ashr %arg6, %0 : i32
  %3 = llvm.icmp "ugt" %2, %1 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

def llvm_add_lower_riscv_nuw_flag_16 : LLVMPeepholeRewriteRefine 16 [Ty.llvm (.bitvec 16), Ty.llvm (.bitvec 16)] where
  lhs:= add_llvm_nuw_flags_16
  rhs:= add_riscv_16

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

def select_t_cond : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64), Ty.llvm (.bitvec 1)] where
  lhs := [LV| {
    ^entry (%c: i1, %t: i64):
      %0 = llvm.sext %c: i1 to i64
      %1 = llvm.select %c, %t, %0 : i64
      llvm.return %1 : i64
  }]
  rhs := [LV| {
    ^entry (%c: i1, %t: i64):
      %0 = llvm.sext %c: i1 to i64
      %1 = llvm.freeze %t : i64
      %2 = llvm.and %0, %1 : i64
      llvm.return %2 : i64
  }]

def test4_before := [llvm|
{
^0(%arg25 : i32):
  %0 = llvm.mlir.constant(64 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.udiv %0, %arg25 : i32
  %3 = llvm.icmp "ne" %2, %1 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

def test7_after := [llvm|
{
^0(%arg81 : i64):
  %0 = llvm.mlir.constant(32) : i64
  %1 = llvm.lshr %arg81, %0 : i64
  %2 = llvm.zext nneg %1 : i64 to i92
  "llvm.return"(%2) : (i92) -> ()
}
]

@[simp_denote]
def add_positive_low_bound_accept_llvm := [LV| {
    ^entry (%a: i32):
    %0 = llvm.mlir.constant (2048) : i32
    %1 = llvm.add %0, %a : i32
    llvm.return %1 :i32
  }]

def test_ne_0_and_15_add_3_before := [llvm|
{
^0(%arg2 : i8):
  %0 = llvm.mlir.constant(3 : i8) : i8
  %1 = llvm.mlir.constant(15 : i8) : i8
  %2 = llvm.mlir.constant(0 : i8) : i8
  %3 = llvm.add %arg2, %0 : i8
  %4 = llvm.and %3, %1 : i8
  %5 = llvm.icmp "ne" %4, %2 : i8
  "llvm.return"(%5) : (i1) -> ()
}
]

def t9_ashr_exact_flag_preservation_after := [llvm|
{
^0(%arg25 : i32, %arg26 : i32):
  %0 = llvm.mlir.constant(30 : i32) : i32
  %1 = llvm.ashr exact %arg25, %0 : i32
  "llvm.return"(%1) : (i32) -> ()
}
]

def mapOpt {α β : Type} (s : Stream α) (f : α → (Option β)) : Stream β :=
  fun i => (s i).bind f

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

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

def urem? {w : Nat} (x y : BitVec w) : IntW w :=
  if y = 0 then
    .poison
  else
    .value <| x % y

def inter (M N : NFA' n) : NFA' n := ⟨_, M.M.inter N.M⟩

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

def eq_umin1_before := [llvm|
{
^0(%arg60 : i32, %arg61 : i32):
  %0 = llvm.icmp "ult" %arg60, %arg61 : i32
  %1 = "llvm.select"(%0, %arg60, %arg61) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %2 = llvm.icmp "eq" %1, %arg60 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

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

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

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

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

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

def atZero (f : LoopBody t) : t → t := fun v => f 0 v

def or_eq_notY_eq_0_after := [llvm|
{
^0(%arg45 : i8, %arg46 : i8):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.and %arg45, %arg46 : i8
  %2 = llvm.icmp "eq" %1, %0 : i8
  "llvm.return"(%2) : (i1) -> ()
}
]

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

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 sgt_or_not_min_logical_before := [llvm|
{
^0(%arg28 : i8, %arg29 : i8):
  %0 = llvm.mlir.constant(-128 : i8) : i8
  %1 = llvm.mlir.constant(true) : i1
  %2 = llvm.icmp "sgt" %arg28, %arg29 : i8
  %3 = llvm.icmp "ne" %arg28, %0 : i8
  %4 = "llvm.select"(%2, %1, %3) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%4) : (i1) -> ()
}
]

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 t2_commutative_before := [llvm|
{
^0(%arg20 : i8, %arg21 : i8):
  %0 = llvm.sub %arg20, %arg21 : i8
  %1 = llvm.icmp "uge" %arg20, %0 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

def test22_logical_after := [llvm|
{
^0(%arg5 : i32, %arg6 : i32):
  %0 = llvm.mlir.constant(true) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def fold_sext_to_and_wrong_after := [llvm|
{
^0(%arg9 : i8):
  %0 = llvm.mlir.constant(false) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

String.intercalate in Init.Data.String.Defs

def irc_constants_C1Minus2MinusC2_neg2_2 : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64)] where
  lhs := [LV| {
    ^entry (%a: i64):
      %c1 = llvm.mlir.constant (-2) : i64
      %c2 = llvm.mlir.constant (2) : 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 (-2) : i64
      %c2 = llvm.mlir.constant (2) : i64
      %0 = llvm.sub %c1, %c2 : i64
      %1 = llvm.sub %0, %a : i64
      llvm.return %1 : i64
  }]

def test_invert_demorgan_logical_or_after := [llvm|
{
^0(%arg11 : i64, %arg12 : i64):
  %0 = llvm.mlir.constant(27) : i64
  %1 = llvm.mlir.constant(0) : i64
  %2 = llvm.mlir.constant(false) : i1
  %3 = llvm.icmp "ne" %arg11, %0 : i64
  %4 = llvm.icmp "ne" %arg12, %1 : i64
  %5 = "llvm.select"(%3, %4, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %6 = llvm.icmp "ne" %arg11, %1 : i64
  %7 = llvm.and %6, %5 : i1
  "llvm.return"(%7) : (i1) -> ()
}
]

def not_or_or_and_no_and_after := [llvm|
{
^0(%arg121 : i32, %arg122 : i32, %arg123 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg121, %0 : i32
  %2 = llvm.xor %arg122, %0 : i32
  %3 = llvm.and %arg123, %2 : i32
  %4 = llvm.or %3, %1 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def eq_smin1_after := [llvm|
{
^0(%arg87 : i32, %arg88 : i32):
  %0 = llvm.icmp "sle" %arg87, %arg88 : i32
  "llvm.return"(%0) : (i1) -> ()
}
]

def trunc_shl_nuw_31_i32_i64_before := [llvm|
{
^0(%arg56 : i64):
  %0 = llvm.mlir.constant(31) : i64
  %1 = llvm.shl %arg56, %0 overflow<nuw> : i64
  %2 = llvm.trunc %1 : i64 to i32
  "llvm.return"(%2) : (i32) -> ()
}
]

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

def shrMax (a : BitVec v) (b : BitVec w) : BitVec (max v w) :=
    a.signExtend (max v w) >>> b.signExtend (max v w)

def test13_before := [llvm|
{
^0(%arg44 : i32, %arg45 : i32):
  %0 = llvm.mlir.constant(-1431655767 : i32) : i32
  %1 = llvm.mlir.constant(1431655766 : i32) : i32
  %2 = llvm.mlir.constant(1 : i32) : i32
  %3 = llvm.or %arg44, %0 : i32
  %4 = llvm.xor %3, %1 : i32
  %5 = llvm.add %arg45, %2 : i32
  %6 = llvm.add %5, %4 : i32
  "llvm.return"(%6) : (i32) -> ()
}
]

def neg (x : BitStream) : BitStream :=
  fun n => (negAux x n).1

def icmp_sle10_before := [llvm|
{
^0(%arg3 : i8):
  %0 = llvm.mlir.constant(7 : i8) : i8
  %1 = llvm.mlir.constant(-127 : i8) : i8
  %2 = llvm.shl %arg3, %0 overflow<nsw> : i8
  %3 = llvm.icmp "sle" %2, %1 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

def fold_add_udiv_urem_without_noundef_after := [llvm|
{
^0(%arg4 : i32):
  %0 = llvm.mlir.constant(10 : i32) : i32
  %1 = llvm.mlir.constant(4 : i32) : i32
  %2 = llvm.udiv %arg4, %0 : i32
  %3 = llvm.shl %2, %1 : i32
  %4 = llvm.urem %arg4, %0 : i32
  %5 = llvm.or disjoint %3, %4 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def or_not_and_commute1_after := [llvm|
{
^0(%arg534 : i32, %arg535 : i32, %arg536 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.sdiv %0, %arg535 : i32
  %3 = llvm.xor %2, %arg536 : i32
  %4 = llvm.xor %arg534, %1 : i32
  %5 = llvm.and %3, %4 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def udiv_shl_mul_nuw_exact_after := [llvm|
{
^0(%arg142 : i5, %arg143 : i5, %arg144 : i5):
  %0 = llvm.mlir.constant(1 : i5) : i5
  %1 = llvm.shl %0, %arg144 overflow<nuw> : i5
  %2 = llvm.udiv exact %1, %arg143 : i5
  "llvm.return"(%2) : (i5) -> ()
}
]

def exact_lshr_ne_both_equal_after := [llvm|
{
^0(%arg165 : i8):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.icmp "ne" %arg165, %0 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

@[simp_denote]
def icmp_ule_llvm_32 : Com LLVMPlusRiscV ⟨[.llvm (.bitvec 32), .llvm (.bitvec 32)]⟩
  .pure (.llvm (.bitvec 1)) := [LV| {
  ^entry (%lhs: i32, %rhs: i32):
    %1 = llvm.icmp.ule %lhs, %rhs : i32
    llvm.return %1 : i1
  }]

def a_false_implies_b_true2_comm_after := [llvm|
{
^0(%arg9 : i8, %arg10 : i1, %arg11 : i1):
  %0 = llvm.mlir.constant(10 : i8) : i8
  %1 = llvm.mlir.constant(true) : i1
  %2 = llvm.icmp "ugt" %arg9, %0 : i8
  %3 = "llvm.select"(%2, %1, %arg10) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%3) : (i1) -> ()
}
]

def and_or3_commuted_before := [llvm|
{
^0(%arg164 : i1, %arg165 : i1, %arg166 : i32, %arg167 : i32):
  %0 = llvm.icmp "eq" %arg166, %arg167 : i32
  %1 = llvm.and %0, %arg165 : i1
  %2 = "llvm.select"(%1, %arg164, %arg165) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%2) : (i1) -> ()
}
]

def BoolBinaryRelationKind.toSmtLib : BoolBinaryRelationKind → SexprPBV.BoolBinaryRelationKind
| .eq => .eq

def irc_constants_C1Minus2MinusC2_1_neg2 : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64)] where
  lhs := [LV| {
    ^entry (%a: i64):
      %c1 = llvm.mlir.constant (1) : i64
      %c2 = llvm.mlir.constant (-2) : 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 (1) : i64
      %c2 = llvm.mlir.constant (-2) : i64
      %0 = llvm.sub %c1, %c2 : i64
      %1 = llvm.sub %0, %a : i64
      llvm.return %1 : i64
  }]

def OrSextSext : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 32), Ty.llvm (.bitvec 32)] where
  lhs := [LV| {
    ^entry (%x: i32, %y: i32):
      %0 = llvm.sext %x : i32 to i64
      %1 = llvm.sext %y : i32 to i64
      %2 = llvm.or %0, %1 : i64
      llvm.return %2 : i64
  }]
  rhs := [LV| {
    ^entry (%x: i32, %y: i32):
      %0 = llvm.or %x, %y : i32
      %1 = llvm.sext %0 : i32 to i64
      llvm.return %1 : i64
  }]

def trunc_shl_zext_64_before := [llvm|
{
^0(%arg0 : i64):
  %0 = llvm.mlir.constant(7 : i8) : i8
  %1 = llvm.trunc %arg0 : i64 to i8
  %2 = llvm.shl %1, %0 : i8
  %3 = llvm.zext %2 : i8 to i64
  "llvm.return"(%3) : (i64) -> ()
}
]

def ex1_lhs : Com [.nat] .nat :=
  Com.var (rgn (k := 0) ⟨0, by admit /- proof elided -/
  ⟩ (
      Com.var (add ⟨0, by admit /- proof elided -/
      ⟩ ⟨0, by admit /- proof elided -/
      ⟩) 
      <| Com.ret ⟨0, by admit /- proof elided -/
      ⟩
  )) <|
  Com.ret ⟨0, by admit /- proof elided -/
  ⟩

def add_hi_and_lo_negone_i64_test : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64)] where
  lhs := add_hi_and_lo_negone_llvm_i64
  rhs := add_hi_and_lo_negone_riscv_i64

def t7_before := [llvm|
{
^0(%arg6 : i8):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.sub %0, %arg6 overflow<nsw> : i8
  %2 = llvm.icmp "ule" %1, %arg6 : i8
  "llvm.return"(%2) : (i1) -> ()
}
]

def ult_swap_or_not_max_logical_before := [llvm|
{
^0(%arg36 : i8, %arg37 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.mlir.constant(true) : i1
  %2 = llvm.icmp "ugt" %arg37, %arg36 : i8
  %3 = llvm.icmp "ne" %arg36, %0 : i8
  %4 = "llvm.select"(%2, %1, %3) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%4) : (i1) -> ()
}
]

def test_sub_nuw__nsw_is_safe_before := [llvm|
{
^0(%arg22 : i32):
  %0 = llvm.mlir.constant(-2147483648 : i32) : i32
  %1 = llvm.mlir.constant(-2147483647 : i32) : i32
  %2 = llvm.mlir.constant(-1 : i32) : i32
  %3 = llvm.or %arg22, %0 : i32
  %4 = llvm.icmp "eq" %3, %1 : i32
  %5 = llvm.sub %0, %3 overflow<nuw> : i32
  %6 = "llvm.select"(%4, %2, %5) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%6) : (i32) -> ()
}
]

IO.FS.Mode in Init.System.IO

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 or_xor_tree_0011_before := [llvm|
{
^0(%arg36 : i32, %arg37 : i32, %arg38 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mul %arg36, %0 : i32
  %2 = llvm.mul %arg37, %0 : i32
  %3 = llvm.mul %arg38, %0 : i32
  %4 = llvm.xor %2, %1 : i32
  %5 = llvm.xor %3, %2 : i32
  %6 = llvm.xor %5, %1 : i32
  %7 = llvm.or %4, %6 : i32
  "llvm.return"(%7) : (i32) -> ()
}
]

def throwUBIf [Pure m] (p : Prop) [Decidable p] : m Unit :=
  if p then HasUB.throwUB else pure ()

def add_shl_moreOneUse_sh3add_no_ZBA_test : LLVMPeepholeRewriteRefine 32 [Ty.llvm (.bitvec 32)] where
  lhs := add_shl_moreOneUse_sh3add
  rhs := add_shl_moreOneUse_sh3add_riscv_no_ZBA

def composeQuinaryAux' (p : FSM (Fin 5)) (q₀ q₁ q₂ q₃ q₄: FSM α) : FSM α :=
  p.compose (α)
    (λ _ => α)
    (λ _ i => i)
    (λ v =>
      v.cases q₀ fun v =>
        v.cases q₁ fun v =>
          v.cases q₂ fun v =>
            v.cases q₃ fun v =>
              v.cases q₄ fun v => v.elim0)

def zero_sign_bit_after := [llvm|
{
^0(%arg31 : i16):
  %0 = llvm.mlir.constant(32767 : i16) : i16
  %1 = llvm.mlir.constant(512 : i16) : i16
  %2 = llvm.and %arg31, %0 : i16
  %3 = llvm.add %2, %1 overflow<nuw> : i16
  "llvm.return"(%3) : (i16) -> ()
}
]

def test_after := [llvm|
{
^0(%arg0 : i26):
  "llvm.return"(%arg0) : (i26) -> ()
}
]

def add_nsw_poison_constant_fold_after := [llvm|
{
^0(%arg2 : i1, %arg3 : i8):
  %0 = llvm.mlir.constant(64 : i8) : i8
  %1 = llvm.mlir.constant(-127 : i8) : i8
  %2 = llvm.add %arg3, %0 overflow<nsw> : i8
  %3 = "llvm.select"(%arg2, %2, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def bools_logical_commute0_after := [llvm|
{
^0(%arg108 : i1, %arg109 : i1, %arg110 : i1):
  %0 = "llvm.select"(%arg110, %arg109, %arg108) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def sltu_i32_test : LLVMPeepholeRewriteRefine 32 [Ty.llvm (.bitvec 32), Ty.llvm (.bitvec 32)] where
  lhs := sltu_llvm_i32
  rhs := sltu_riscv_i32

BitVec.cons in Init.Data.BitVec.Basic

return res
</all_available_defs>

<all_available_lemmas>
List.append_inj_left' in Init.Data.List.Lemmas
List.append_inj_right' in Init.Data.List.Lemmas
List.dropLast_concat_getLast in Init.Data.List.Lemmas
List.map_append in Init.Data.List.Lemmas
List.map_cons in Init.Data.List.Basic
List.map_dropLast in Init.Data.List.Lemmas
List.map_nil in Init.Data.List.Basic
Set.ext in Mathlib.Data.Set.Defs
Set.mem_iUnion in Mathlib.Order.SetNotation
exists_prop in Init.PropLemmas

theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) :\n(l₁ ++ l₂)[i] = l₁[i]

@[simp]
theorem R.fromPoly_representative [Fact (q > 1)]:
    forall a : R q n, (R.fromPoly (n:=n) (R.representative q n a)) = a

theorem bitwise_and_logical_and_icmps_comm3_thm.extracted_1._3 : ∀ (x x_1 x_2 : BitVec 8),
  ¬x_1 ≥ ↑8 →
    ofBool (x_2 &&& 1#8 != 0#8) = 1#1 →
      True ∧ 1#8 <<< x_1 >>> x_1 ≠ 1#8 ∨ x_1 ≥ ↑8 ∨ True ∧ 1#8 <<< x_1 >>> x_1 ≠ 1#8 ∨ x_1 ≥ ↑8 → False

theorem alive_1030 : alive_1030_src ⊑ alive_1030_tgt

theorem n7_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬ofBool (x &&& 2#32 != 0#32) = 1#1 → ¬ofBool (x &&& 2#32 == 0#32) = 1#1 → 1#32 = x &&& 1#32

theorem e_1109 :
    1 *  ~~~(z &&&  ~~~z) - 6 *  ~~~z + 4 * (z ||| t) + 11 * (z |||  ~~~t) + 11 * z - 6 *  ~~~(z ||| t) + 1 *  ~~~(z |||  ~~~t) - 27 * (z &&& t) = 27 * (z &&&  ~~~t)

theorem e_1080 :
     - 6 * (z |||  ~~~t) - 6 *  ~~~t - 6 * t - 1 *  ~~~(z &&&  ~~~z) - 11 * (z ^^^ t) + 18 *  ~~~(z |||  ~~~t) + 24 * (z &&&  ~~~t) + 13 * (z &&& t) =  - 13 *  ~~~(z ||| t)

@[simp, simp_denote]
theorem liftEffect_rfl [Pure m] (hle : eff ≤ eff) :
    liftEffect hle (α := α) (m := m) = id

@[grind ., simp]
lemma RawCNFA.states_lt (m : RawCNFA A) s : s ∈ m.states → s < m.stateMax

theorem trunc_shl_1_i32_i64_thm.extracted_1._2 : ∀ (x : BitVec 64),
  ¬1#64 ≥ ↑64 → ¬1#32 ≥ ↑32 → truncate 32 (x <<< 1#64) = truncate 32 x <<< 1#32

theorem e_2220 :
    11 * (e ^^^  ~~~(d &&& (e ^^^ f))) - 5 * (f ||| (d &&&  ~~~e)) - 1 * (f ^^^  ~~~(d &&& ( ~~~e ||| f))) + 1 * ( ~~~(d ||| e) ||| (d ^^^ (e ^^^ f))) - 6 * ( ~~~(d ^^^ e) &&& (d ^^^ f)) - 1 * ( ~~~(d &&& e) &&&  ~~~(e ^^^ f)) + 11 *  ~~~( ~~~d &&& ( ~~~e &&& f)) - 6 * (d ^^^ ( ~~~e ||| f)) - 3 * ( ~~~(d |||  ~~~e) ||| (d ^^^ (e ^^^ f))) + 5 *  ~~~(d ^^^ e) - 6 * ((e &&& f) ||| (d &&& (e ||| f))) + 11 * (d ||| ( ~~~e &&& f)) - 1 * ((d |||  ~~~e) &&&  ~~~(e ^^^ f)) + 2 * (e ^^^ (d ||| ( ~~~e ||| f))) - 5 * (e |||  ~~~(d ||| f)) - 3 * (f &&& (d |||  ~~~e)) + 1 * ((d &&& e) ^^^ (e ||| f)) - 1 * ((d ^^^ e) ||| (d ^^^ f)) + 1 * (d &&& f) + 3 * d + 2 *  ~~~(d ^^^ (e ^^^ f)) - 1 * (f ^^^ (d &&&  ~~~e)) - 11 * (f ^^^ (d &&& ( ~~~e ||| f))) + 2 *  ~~~(d &&&  ~~~d) + 2 * (f &&&  ~~~(d &&&  ~~~e)) - 11 * (e ^^^ ( ~~~d &&& (e ^^^ f))) + 4 * (e ^^^  ~~~(d ||| (e ^^^ f))) + 1 * (f ^^^  ~~~(d ||| (e &&& f))) + 5 * ((d |||  ~~~e) &&& (d ^^^ (e ^^^ f))) - 11 * ((d &&& e) ^^^ (e |||  ~~~f)) - 2 * ( ~~~(d ^^^ e) |||  ~~~(d ^^^ f)) - 1 * (f &&& (d ||| e)) - 1 * (e &&& (d |||  ~~~f)) - 2 *  ~~~(d ^^^ ( ~~~e ||| f)) + 2 * (e ^^^ (d &&& (e ^^^ f))) - 2 * (e ^^^  ~~~( ~~~d ||| (e &&& f))) + 7 * (e ^^^ ( ~~~d ||| (e &&& f))) + 1 * (f ||| (d ^^^ e)) + 11 * (f ^^^ ( ~~~d ||| ( ~~~e &&& f))) - 3 * ((e &&& f) ^^^  ~~~( ~~~d &&& (e ^^^ f))) + 4 * (d |||  ~~~f) + 2 * (d ^^^ (e ||| f)) - 3 * (f ^^^ ( ~~~d ||| ( ~~~e ||| f))) + 5 * ((d &&& e) ^^^ (d ^^^ ( ~~~e ||| f))) - 2 * (f ^^^ ( ~~~d ||| (e &&& f))) + 7 * (d ^^^ ( ~~~e &&& f)) - 31 *  ~~~(d ||| (e ||| f)) - 10 *  ~~~(d ||| ( ~~~e ||| f)) - 17 *  ~~~( ~~~d ||| (e ||| f)) - 26 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 13 * ( ~~~d &&& ( ~~~e &&& f)) + 34 * ( ~~~d &&& (e &&& f)) - 14 * (d &&& ( ~~~e &&& f)) - 32 * (d &&& (e &&& f)) =  - 1 * (e ^^^ (d &&& ( ~~~e ||| f)))

theorem test2_logical_thm.extracted_1._1 : ∀ (x : BitVec 1), ¬x = 1#1 → 0#1 = 1#1 → x = 0#1

theorem lshr_mul_times_5_div_4_proof : lshr_mul_times_5_div_4_before ⊑ lshr_mul_times_5_div_4_after

theorem and_xor_or2_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 64),
  ¬(x_2 = 0 ∨ x_1 = 0 ∨ x = 0 ∨ x_2 = 0) → x = 0 ∨ x_2 = 0 → False

theorem test7_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬1#32 ≥ ↑32 →
    ¬(1#32 ≥ ↑32 ∨ True ∧ (x >>> 1#32).uaddOverflow 2147483647#32 = true) →
      zeroExtend 64 (x >>> 1#32) + 2147483647#64 = zeroExtend 64 (x >>> 1#32 + 2147483647#32)

theorem sgt_swap_or_not_min_commute_logical_thm (e e_1 : IntW 8) :
  select (icmp IntPred.ne e_1 (const? 8 (-128))) (const? 1 1) (icmp IntPred.slt e e_1) ⊑
    icmp IntPred.ne e_1 (const? 8 (-128))

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

theorem zext_ashr_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬2#16 ≥ ↑16 → 2#8 ≥ ↑8 ∨ True ∧ (x >>> 2#8 &&& x).msb = true → False

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

theorem or_or_and_pat5_proof : or_or_and_pat5_before ⊑ or_or_and_pat5_after

theorem bor_lor_left1_thm.extracted_1._2 : ∀ (x x_1 : BitVec 1), ¬x_1 ||

theorem select_1_proof : select_1_before ⊑ select_1_after

theorem xor_common_op_commute0_thm (e e_1 : IntW 8) : LLVM.or (LLVM.xor e_1 e) e_1 ⊑ LLVM.or e e_1

theorem shift_xor_multiuse_cmp_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 32),
  ofBool (0#32 != x_2 &&& 4096#32) = 1#1 → ofBool (x_2 &&& 4096#32 == 0#32) = 1#1 → False

@[simp]
theorem EnvFin.apply_getLsb_eq (env : EnvFin (w + 1) n) (i : Fin n) : env.getLsb i =
  BitVec.ofBool (env i)[0]

theorem n2_badmask_proof : n2_badmask_before ⊑ n2_badmask_after

theorem demorgan_nor_use2ac_proof : demorgan_nor_use2ac_before ⊑ demorgan_nor_use2ac_after

theorem e_1076 :
     - 6 * t + 2 * (z ||| t) - 6 *  ~~~(z &&&  ~~~t) - 1 *  ~~~(z ||| t) + 10 *  ~~~(z |||  ~~~t) - 9 * (z &&&  ~~~t) + 3 * (z &&& t) =  - 7 * (z |||  ~~~t)

theorem sgt_swap_and_not_min_proof : sgt_swap_and_not_min_before ⊑ sgt_swap_and_not_min_after

theorem badimm2_thm (e : IntW 16) :
  select (icmp IntPred.eq (ashr (trunc 8 e) (const? 8 6)) (trunc 8 (lshr e (const? 16 8)))) (trunc 8 e)
      (LLVM.xor (trunc 8 (ashr e (const? 16 15))) (const? 8 127)) ⊑
    select
      (icmp IntPred.eq (ashr (trunc 8 e) (const? 8 6))
        (trunc 8 (lshr e (const? 16 8)) { «nsw» := false, «nuw» := true }))
      (trunc 8 e) (select (icmp IntPred.sgt e (const? 16 (-1))) (const? 8 127) (const? 8 (-128)))

theorem sub_not_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8), x_1 - x ^^^ -1#8 = x + (x_1 ^^^ -1#8)

theorem sel_false_val_is_a_masked_ashr_of_true_val1_thm.extracted_1._3 : ∀ (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 →
        False

theorem e_925 :
     - 2 *  ~~~(z &&&  ~~~t) + 3 *  ~~~z + 5 *  ~~~(z ||| t) + 5 *  ~~~(z |||  ~~~t) + 6 * (z &&&  ~~~t) + 8 * (z &&& t) = 6 *  ~~~(z &&&  ~~~z)

@[simp]
theorem union_accepts (M : NFA α σ) (N : NFA α ς) :
    (M.union N).accepts = M.accepts ∪ N.accepts

theorem ashrslt_01_08_thm (e : IntW 4) : icmp IntPred.slt (ashr e (const? 4 1)) (const? 4 (-8)) ⊑ const? 1 0

theorem a_false_implies_b_true2_proof : a_false_implies_b_true2_before ⊑ a_false_implies_b_true2_after

theorem in_constant_mone_vary_invmask_thm.extracted_1._1 : ∀ (x x_1 : BitVec 4),
  (-1#4 ^^^ x_1) &&& (x ^^^ -1#4) ^^^ x_1 = x_1 ||

theorem ne_shift_in_zeros_thm (e e_1 : IntW 32) :
  LLVM.or (icmp IntPred.ne (trunc 24 (lshr e_1 (const? 32 16))) (trunc 24 (lshr e (const? 32 16))))
      (icmp IntPred.ne (trunc 8 (lshr e_1 (const? 32 8))) (trunc 8 (lshr e (const? 32 8)))) ⊑
    icmp IntPred.ugt (LLVM.xor e_1 e) (const? 32 255)

theorem test_ashr__exact_is_safe_thm (e : IntW 64) (e_1 : IntW 32) :
  select (icmp IntPred.eq (LLVM.and e_1 (const? 32 (-2147483588))) (const? 32 0)) e
      (ashr e (zext 64 (ashr (LLVM.and e_1 (const? 32 (-2147483588))) (const? 32 2)))) ⊑
    ashr e (zext 64 (LLVM.and (ashr e_1 (const? 32 2)) (const? 32 (-536870897))) { «nneg» := true })

theorem eq_nsw_rem_nz_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬(True ∧ x.smulOverflow 5#8 = true) → ofBool (x * 5#8 == BitVec.ofInt 8 (-11)) = 0#1

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

theorem sextinreg2_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬(24#32 ≥ ↑32 ∨ True ∧ x <<< 24#32 >>> 24#32 <<< 24#32 ≠ x <<< 24#32 ∨ 24#32 ≥ ↑32) →
    (x &&& 255#32 ^^^ 128#32) + BitVec.ofInt 32 (-128) = (x <<< 24#32).sshiftRight' 24#32

theorem test35_with_trunc_thm.extracted_1._2 : ∀ (x : BitVec 64),
  ¬ofBool (0#32 ≤ₛ truncate 32 x) = 1#1 → ofBool (x &&& 2147483648#64 == 0#64) = 1#1 → 100#32 = 60#32

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

theorem test7_thm (e : IntW 32) :
  icmp IntPred.ugt (LLVM.udiv (const? 32 8) e) (const? 32 8) ⊑ const? 1 0

theorem select_exact_lshr_icmp_const_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬ofBool (31#32 <ᵤ x) = 1#1 → 5#32 ≥ ↑32 → False

theorem add_mask_ashr28_non_pow2_i32_thm (e : IntW 32) :
  add (LLVM.and (ashr e (const? 32 28)) (const? 32 9)) (ashr e (const? 32 28)) ⊑
    add (LLVM.and (ashr e (const? 32 28)) (const? 32 9)) (ashr e (const? 32 28))
      { «nsw» := true, «nuw» := false }

theorem ashrslt_01_07_proof : ashrslt_01_07_before ⊑ ashrslt_01_07_after

theorem main4c_logical_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ofBool (x &&& 7#32 != 7#32) = 1#1 → ¬True → 0#32 = zeroExtend 32 (ofBool (x &&& 55#32 == 55#32))

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

theorem bools2_logical_commute1_thm.extracted_1._3 : ∀ (x x_1 : BitVec 1),
  x_1 = 1#1 → ¬x ^^^ 1#1 = 1#1 → x = 1#1 → 1#1 = x_1

theorem n0_thm (e e_1 : IntW 8) :
  icmp IntPred.ult (LLVM.xor (shl (const? 8 1) e_1) (const? 8 (-1))) e ⊑
    icmp IntPred.ugt e (LLVM.xor (shl (const? 8 1) e_1 { «nsw» := false, «nuw» := true }) (const? 8 (-1)))

theorem test2_thm.extracted_1._2 : ∀ (x : BitVec 49),
  ¬(17#49 ≥ ↑49 ∨ 4096#49 <<< 17#49 = 0) → ¬29#49 ≥ ↑49 → x / 4096#49 <<< 17#49 = x >>> 29#49

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

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

theorem e_680 :
     - 11 *  ~~~(x &&& y) - 6 * (x |||  ~~~y) - 5 * (x ||| y) - 7 *  ~~~(x ^^^ y) - 2 * (x ^^^ y) + 1 *  ~~~(x &&&  ~~~y) + 34 *  ~~~(x ||| y) + 31 *  ~~~(x |||  ~~~y) + 24 * (x &&&  ~~~y) + 20 * (x &&& y) = 11 *  ~~~x + 3 * y

theorem not_lshr_bitwidth_mask_proof : not_lshr_bitwidth_mask_before ⊑ not_lshr_bitwidth_mask_after

theorem t6_no_extrause_proof : t6_no_extrause_before ⊑ t6_no_extrause_after

theorem shl_add_nuw_and_nsw_thm (e e_1 : IntW 8) :
  shl (LLVM.and e_1 (const? 8 31)) (LLVM.and e (const? 8 2)) ⊑
    shl (LLVM.and e_1 (const? 8 31)) (LLVM.and e (const? 8 2)) { «nsw» := true, «nuw» := true }

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

theorem src_is_mask_p2_m1_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ¬x_1 ≥ ↑8 →
    ofBool (2#8 <<< x_1 + -1#8 &&& (x ^^^ 123#8) <ᵤ x ^^^ 123#8) = ofBool (2#8 <<< x_1 + -1#8 <ᵤ x ^^^ 123#8)

theorem trunc_shl_33_i32_i64_proof : trunc_shl_33_i32_i64_before ⊑ trunc_shl_33_i32_i64_after

theorem test3_thm.extracted_1._1 : ∀ (x : BitVec 32), ofBool (x <ₛ x) = 0#1

theorem tryFactorization_add_nuw_mul_nuw_int_max_proof : tryFactorization_add_nuw_mul_nuw_int_max_before ⊑ tryFactorization_add_nuw_mul_nuw_int_max_after

theorem ashrslt_02_05_proof : ashrslt_02_05_before ⊑ ashrslt_02_05_after

theorem test_or1_thm (e e_1 : IntW 32) :
  LLVM.or (icmp IntPred.slt e_1 (const? 32 0)) (icmp IntPred.sge e_1 (LLVM.and e (const? 32 2147483647))) ⊑
    icmp IntPred.uge e_1 (LLVM.and e (const? 32 2147483647))

theorem select_shl_icmp_bad_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 == 1#32) = 1#1 → ¬x_1 ≥ ↑32 → 1#32 ≥ ↑32 → False

@[grind =, simp]
lemma createSink_trans [LawfulBEq A] {m : RawCNFA A} (hwf : m.WF) :
    s₂ ∈ m.createSink.2.tr s₁ a ↔
      (s₁ = m.stateMax ∧ s₂ = m.stateMax) ∨
      (s₁ ∈ m.states ∧ s₂ ∈ m.states ∧ s₂ ∈ m.tr s₁ a)

theorem e_1111 :
     - 1 *  ~~~(z ^^^ t) - 2 * (z ||| t) - 5 * (z |||  ~~~t) - 1 *  ~~~(z &&&  ~~~z) - 2 *  ~~~(z &&&  ~~~t) - 2 *  ~~~t + 11 *  ~~~(z ||| t) + 11 * (z &&& t) =  - 10 * (z &&&  ~~~t) - 5 *  ~~~(z |||  ~~~t)

theorem e_65 :
     - 11 * (x ^^^ y) + 5 * x + 4 *  ~~~(x &&& y) + 7 *  ~~~(x |||  ~~~y) - 5 * (x &&& y) = 4 *  ~~~(x ||| y) - 2 * (x &&&  ~~~y)

theorem masked_icmps_mask_notallzeros_bmask_mixed_2_logical_proof : masked_icmps_mask_notallzeros_bmask_mixed_2_logical_before ⊑ masked_icmps_mask_notallzeros_bmask_mixed_2_logical_after

theorem select_zext_or_eq_ult_add_thm (e : IntW 32) :
  select (icmp IntPred.ult (add e (const? 32 (-3))) (const? 32 2)) (const? 32 1)
      (zext 32 (icmp IntPred.eq e (const? 32 5))) ⊑
    zext 32 (icmp IntPred.ult (add e (const? 32 (-3))) (const? 32 3))

theorem masked_or_allzeroes_notoptimised_logical_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬ofBool (x &&& 15#32 == 0#32) = 1#1 →
    ofBool (x &&& 39#32 == 0#32) = ofBool (x &&& 15#32 == 0#32) ||

theorem zext_zext_eq_proof : zext_zext_eq_before ⊑ zext_zext_eq_after

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

theorem foo_thm (e : IntW 32) :
  LLVM.and (sub (const? 32 5) e) (const? 32 2) ⊑ LLVM.and (sub (const? 32 1) e) (const? 32 2)

theorem self_EqualUpTo_ofBitVecSext_toBitVec (x : BitStream) :
  EqualUpTo w x (BitStream.ofBitVecSext (x.toBitVec w))

theorem ashrsgt_02_06_exact_thm (e : IntW 4) :
  icmp IntPred.sgt (ashr e (const? 4 2) { «exact» := true }) (const? 4 6) ⊑ const? 1 0

theorem uge_swap_or_not_max_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8), ofBool (x_1 ≤ᵤ x) ||

@[bv_automata_nnf↓] theorem not_ite {_ : Decidable p} (q r : Prop) : (¬ite p q r) = ite p (¬q) (¬r)

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

theorem test_sub_0_Y_ne_0_thm (e : IntW 8) :
  icmp IntPred.ne (sub (const? 8 0) e) (const? 8 0) ⊑ icmp IntPred.ne e (const? 8 0)

theorem test3_proof : test3_before ⊑ test3_after

theorem select_constants_and_icmp_eq0_zero_fval_proof : select_constants_and_icmp_eq0_zero_fval_before ⊑ select_constants_and_icmp_eq0_zero_fval_after

theorem bools_multi_uses1_logical_thm.extracted_1._4 : ∀ (x x_1 : BitVec 1),
  x_1 ^^^ 1#1 = 1#1 → x_1 = 1#1 → x = 1#1 → False

theorem positive_sameconst_shlnuwnsw_thm (e : IntW 8) :
  shl (ashr e (const? 8 3)) (const? 8 3) { «nsw» := true, «nuw» := true } ⊑ LLVM.and e (const? 8 (-8))

theorem icmp_slt_0_and_icmp_sge_neg2_i64_thm.extracted_1._1 : ∀ (x : BitVec 64),
  ¬63#64 ≥ ↑64 →
    x >>> 63#64 &&& zeroExtend 64 (ofBool (BitVec.ofInt 64 (-2) ≤ₛ x)) =
      zeroExtend 64 (ofBool (BitVec.ofInt 64 (-3) <ᵤ x))

theorem f_var0_thm (e e_1 : IntW 32) :
  select (icmp IntPred.eq (LLVM.and e_1 e) (const? 32 0)) (LLVM.and (lshr e_1 (const? 32 1)) (const? 32 1))
      (const? 32 1) ⊑
    zext 32 (icmp IntPred.ne (LLVM.and e_1 (LLVM.or e (const? 32 2))) (const? 32 0))

theorem and_logic_and_logic_or_7_thm.extracted_1._7 : ∀ (x x_1 x_2 : BitVec 1),
  ¬x_2 = 1#1 → ¬0#1 = 1#1 → x &&& x_2 = 0#1

@[simp]
theorem scanOr_zero (s : BitStream) : scanOr s 0 = s 0

theorem bv_AndOrXor_144 :
    ∀ (e e_1 e_2 : LLVM.IntW w), LLVM.and (LLVM.or e e_1) e_2 ⊑ LLVM.and (LLVM.or e (LLVM.and e_1 e_2)) e_2

theorem bools_multi_uses2_logical_thm.extracted_1._32 : ∀ (x x_1 x_2 : BitVec 1),
  ¬x_2 ^^^ 1#1 = 1#1 → x_2 = 1#1 → ¬0#1 = 1#1 → x = 1#1 → 0#1 + x = 0#1 ^^^ x

theorem ule_swap_or_not_min_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8), ofBool (x ≤ᵤ x_1) ||

theorem select_add_thm.extracted_1._1 : ∀ (x : BitVec 64) (x_1 : BitVec 1), ¬x_1 = 1#1 → x = x + 0#64

theorem addhshlhsdivhscalar0_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬((BitVec.ofInt 8 (-4) == 0 || 8 != 1 && x == intMin 8 && BitVec.ofInt 8 (-4) == -1) = true ∨ 2#8 ≥ ↑8) →
    (4#8 == 0 || 8 != 1 && x == intMin 8 && 4#8 == -1) = true → False

theorem udiv_shl_pair1_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 32),
  ¬(True ∧ x_2 <<< x_1 >>> x_1 ≠ x_2 ∨ x_1 ≥ ↑32 ∨ True ∧ x_2 <<< x >>> x ≠ x_2 ∨ x ≥ ↑32 ∨ x_2 <<< x = 0) →
    True ∧ 1#32 <<< x_1 >>> x_1 ≠ 1#32 ∨ x_1 ≥ ↑32 ∨ x ≥ ↑32 → False

theorem add_smax_simplify2_proof : add_smax_simplify2_before ⊑ add_smax_simplify2_after

theorem positive_samevar_shlnuwnsw_lshrexact_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ¬(True ∧ x_1 >>> x <<< x ≠ x_1 ∨
        x ≥ ↑8 ∨
          True ∧ (x_1 >>> x <<< x).sshiftRight' x ≠ x_1 >>> x ∨ True ∧ x_1 >>> x <<< x >>> x ≠ x_1 >>> x ∨ x ≥ ↑8) →
    x_1 >>> x <<< x = x_1

theorem select_add_proof : select_add_before ⊑ select_add_after
</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

def List.Vector.transport (v : Vector α m) (f : Fin n → Fin m) : Vector α n :=
  Vector.ofFn fun i => v.get (f i)

def BitVec.transport (f : Fin n2 → Fin n1) (bv : BitVec n1) : BitVec n2 :=
  BitVec.ofFn fun i => bv.getLsbD (f i)

structure BitVecs (n : Nat) where
  w : Nat
  bvs : List.Vector (BitVec w) n

abbrev BitVecs' (n : Nat) := List (BitVec n)

def BitVecs.transport (f : Fin n → Fin m) (bvs : BitVecs m) : BitVecs n :=
  { w := bvs.w, bvs := bvs.bvs.transport f }

def BitVecs'.transport (f : Fin n → Fin m) (bvs' : BitVecs' m): BitVecs' n :=
  bvs'.map fun bv => bv.transport f

namespace NFA

structure Deterministic (M : NFA α σ) : Prop where
  start : M.start.Subsingleton
  step : ∀ q a, M.step q a |>.Subsingleton

@[simps]
def proj (M: NFA (BitVec n1) σ) (f : Fin n2 → Fin n1) : NFA (BitVec n2) σ where
  start := M.start
  accept := M.accept
  step q a := { q' | ∃ a', a'.transport f = a ∧ q' ∈ M.step q a' }
</local_ctx>

<target_theorem>
@[simp]
lemma proj_eval (M : NFA (BitVec m) σ) (f : Fin n → Fin m) :
    (M.proj f).eval w =
      ⋃ w' ∈ BitVecs'.transport f ⁻¹' {w}, M.eval w' :=
</target_theorem>

