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
Finset in Mathlib.Data.Finset.Defs
Finset.range in Mathlib.Data.Finset.Range
FinEnum in Mathlib.Data.FinEnum
FinEnum.toList in Mathlib.Data.FinEnum
BEq in Init.Prelude
DecidableEq in Init.Prelude
Hashable in Init.Prelude
Repr in Init.Data.Repr
Std.HashMap in Std.Data.HashMap.Basic
Std.HashSet in Std.Data.HashSet.Basic
LawfulBEq in Init.Core
List in Init.Prelude
LawfulHashable in Init.Data.LawfulHashable
Inhabited in Init.Prelude

...

def not_and_and_not_after := [llvm|
{
^0(%arg567 : i32, %arg568 : i32, %arg569 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.sdiv %0, %arg567 : i32
  %3 = llvm.or %arg568, %arg569 : i32
  %4 = llvm.xor %3, %1 : i32
  %5 = llvm.and %2, %4 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def src_srem_shl_demand_min_signbit_before := [llvm|
{
^0(%arg23 : i32):
  %0 = llvm.mlir.constant(1073741823 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.mlir.constant(-2147483648 : i32) : i32
  %3 = llvm.srem %arg23, %0 : i32
  %4 = llvm.shl %3, %1 : i32
  %5 = llvm.and %4, %2 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def masked_or_allzeroes_notoptimised_logical_after := [llvm|
{
^0(%arg116 : i32):
  %0 = llvm.mlir.constant(15 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.mlir.constant(39 : i32) : i32
  %3 = llvm.and %arg116, %0 : i32
  %4 = llvm.icmp "eq" %3, %1 : i32
  %5 = llvm.and %arg116, %2 : i32
  %6 = llvm.icmp "eq" %5, %1 : i32
  %7 = llvm.or %4, %6 : i1
  "llvm.return"(%7) : (i1) -> ()
}
]

@[simp_denote]
def trunc_llvm_64_to_32_nuw := [LV| {
  ^entry (%lhs: i64):
    %0 = llvm.trunc %lhs overflow<nuw> : i64 to i32
    llvm.return %0 : i32
  }]

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

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

def or_ugt_after := [llvm|
{
^0(%arg58 : i8, %arg59 : i8):
  %0 = llvm.or %arg58, %arg59 : i8
  %1 = llvm.icmp "ne" %0, %arg58 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

def different_size_zext_zext_eq_before := [llvm|
{
^0(%arg22 : i4, %arg23 : i7):
  %0 = llvm.zext %arg22 : i4 to i25
  %1 = llvm.zext %arg23 : i7 to i25
  %2 = llvm.icmp "eq" %0, %1 : i25
  "llvm.return"(%2) : (i1) -> ()
}
]

def test_mul_nuw_nsw__nsw_is_safe_before := [llvm|
{
^0(%arg7 : i32):
  %0 = llvm.mlir.constant(-83886080 : i32) : i32
  %1 = llvm.mlir.constant(-83886079 : i32) : i32
  %2 = llvm.mlir.constant(9 : i32) : i32
  %3 = llvm.mlir.constant(-754974711 : i32) : i32
  %4 = llvm.or %arg7, %0 : i32
  %5 = llvm.icmp "eq" %4, %1 : i32
  %6 = llvm.mul %4, %2 overflow<nsw,nuw> : i32
  %7 = "llvm.select"(%5, %3, %6) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%7) : (i32) -> ()
}
]

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

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

@[simp_denote]
def add_hi_and_lo_negone_llvm_i64 := [LV| {
    ^entry (%arg: i64):
    %1 = llvm.mlir.constant (-1) : i64
    %0 = llvm.add %arg, %1 overflow<nsw> : i64
    llvm.return %0 : i64
  }]

def select_icmp_eq_and_4096_0_xor_4096_after := [llvm|
{
^0(%arg221 : i32, %arg222 : i32):
  %0 = llvm.mlir.constant(4096 : i32) : i32
  %1 = llvm.and %arg221, %0 : i32
  %2 = llvm.xor %arg222, %1 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def isCloseBracket(c: Char):Option Bracket :=
match c with
| ')' => some .Round
| ']' => some .Square
| '{' => some .Curly
| '<' => some .Angle
| _ => none

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

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

def t2_before := [llvm|
{
^0(%arg220 : i8, %arg221 : i8):
  %0 = llvm.mlir.constant(-42 : i8) : i8
  %1 = llvm.shl %0, %arg221 : i8
  %2 = llvm.sub %arg220, %1 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

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

def add {Γ : Ctxt _} (e₁ e₂ : Var Γ .nat) : Expr Γ .nat :=
  Expr.mk
    (op := .add)
    (ty_eq := rfl)
    (eff_le := EffectKind.pure_le _)
    (args := .cons e₁ <| .cons e₂ .nil)
    (regArgs := .nil)

def icmp_ne_and_pow2_lshr_pow2_before := [llvm|
{
^0(%arg41 : i32):
  %0 = llvm.mlir.constant(8 : i32) : i32
  %1 = llvm.mlir.constant(4 : i32) : i32
  %2 = llvm.mlir.constant(0 : i32) : i32
  %3 = llvm.lshr %0, %arg41 : i32
  %4 = llvm.and %3, %1 : i32
  %5 = llvm.icmp "eq" %4, %2 : i32
  %6 = llvm.zext %5 : i1 to i32
  "llvm.return"(%6) : (i32) -> ()
}
]

def ashr_and_after := [llvm|
{
^0(%arg17 : i8):
  %0 = llvm.mlir.constant(-64 : i8) : i8
  %1 = llvm.ashr %0, %arg17 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

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 lshrult_02_09_after := [llvm|
{
^0(%arg342 : i4):
  %0 = llvm.mlir.constant(true) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

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

checkTimeout

IO.FS.Handle in Init.System.IO

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

DecidableRel in Init.Prelude

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

def a_or_b_after := [llvm|
{
^0(%arg15 : i32, %arg16 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.icmp "eq" %arg15, %0 : i32
  %2 = llvm.icmp "eq" %arg16, %0 : i32
  %3 = llvm.xor %1, %2 : i1
  "llvm.return"(%3) : (i1) -> ()
}
]

def sge_swap_and_max_commute_after := [llvm|
{
^0(%arg242 : i8, %arg243 : i8):
  %0 = llvm.mlir.constant(127 : i8) : i8
  %1 = llvm.icmp "eq" %arg242, %0 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

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

def test_nuw_nsw_and_signed_pred_before := [llvm|
{
^0(%arg54 : i64):
  %0 = llvm.mlir.constant(10) : i64
  %1 = llvm.mlir.constant(3) : i64
  %2 = llvm.sub %0, %arg54 overflow<nsw,nuw> : i64
  %3 = llvm.icmp "slt" %2, %1 : i64
  "llvm.return"(%3) : (i1) -> ()
}
]

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

def urem_c_i32_before := [llvm|
{
^0(%arg5 : i8):
  %0 = llvm.mlir.constant(10 : i32) : i32
  %1 = llvm.zext %arg5 : i8 to i32
  %2 = llvm.urem %0, %1 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

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

def ult_to_slt_before := [llvm|
{
^0(%arg32 : i8, %arg33 : i8):
  %0 = llvm.mlir.constant(-128 : i8) : i8
  %1 = llvm.xor %arg32, %0 : i8
  %2 = llvm.xor %arg33, %0 : i8
  %3 = llvm.icmp "ult" %1, %2 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

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

def one_side_fold_eq_before := [llvm|
{
^0(%arg25 : i32, %arg26 : i32, %arg27 : i32, %arg28 : i1):
  %0 = "llvm.select"(%arg28, %arg25, %arg27) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %1 = "llvm.select"(%arg28, %arg26, %arg27) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %2 = llvm.icmp "eq" %1, %0 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

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

def or_xor_tree_1100_after := [llvm|
{
^0(%arg9 : i32, %arg10 : i32, %arg11 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mul %arg9, %0 : i32
  %2 = llvm.mul %arg10, %0 : i32
  %3 = llvm.mul %arg11, %0 : i32
  %4 = llvm.xor %1, %2 : i32
  %5 = llvm.or %4, %3 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

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

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 urem? {w : Nat} (x y : BitVec w) : IntW w :=
  if y = 0 then
    .poison
  else
    .value <| x % y

def or_eq_with_one_bit_diff_constants1_logical_before := [llvm|
{
^0(%arg365 : i32):
  %0 = llvm.mlir.constant(50 : i32) : i32
  %1 = llvm.mlir.constant(51 : i32) : i32
  %2 = llvm.mlir.constant(true) : i1
  %3 = llvm.icmp "eq" %arg365, %0 : i32
  %4 = llvm.icmp "eq" %arg365, %1 : i32
  %5 = "llvm.select"(%3, %2, %4) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%5) : (i1) -> ()
}
]

def cMerge (x y : TokenStream) : ValueStream (BitVec 1) × TokenStream :=
  Stream.corec₂ (β := TokenStream × TokenStream) (x, y) fun ⟨x, y⟩ =>
    match x 0, y 0 with
    | some x', some _ => (some 1, some x', (x.tail, y))
    | some x', none => (some 1, some x', (x.tail, y.tail))
    | none, some y' => (some 0, some y', (x.tail, y.tail))
    | none, none => (none, none, (x.tail, y.tail))

def signbit_splat_mask_after := [llvm|
{
^0(%arg117 : i8, %arg118 : i16):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.mlir.constant(0 : i16) : i16
  %2 = llvm.icmp "slt" %arg117, %0 : i8
  %3 = "llvm.select"(%2, %arg118, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i16, i16) -> i16
  "llvm.return"(%3) : (i16) -> ()
}
]

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

def trunc_before := [llvm|
{
^0(%arg15 : i32, %arg16 : i32, %arg17 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.icmp "ult" %arg15, %arg16 : i32
  %2 = "llvm.select"(%1, %0, %arg17) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %3 = llvm.trunc %2 : i32 to i16
  "llvm.return"(%3) : (i16) -> ()
}
]

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

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

structure Item where
 name : String
 tac : Syntax

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

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 shl_nsw_add_before := [llvm|
{
^0(%arg22 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.shl %0, %arg22 overflow<nsw> : i32
  %3 = llvm.add %2, %1 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def oppositesign_after := [llvm|
{
^0(%arg32 : i16, %arg33 : i16):
  %0 = llvm.mlir.constant(-32768 : i16) : i16
  %1 = llvm.mlir.constant(32767 : i16) : i16
  %2 = llvm.or %arg32, %0 : i16
  %3 = llvm.and %arg33, %1 : i16
  %4 = llvm.add %2, %3 overflow<nsw> : i16
  "llvm.return"(%4) : (i16) -> ()
}
]

def pr4917_3_before := [llvm|
{
^0(%arg25 : i32, %arg26 : i32):
  %0 = llvm.mlir.constant(4294967295) : i64
  %1 = llvm.mlir.constant(111) : i64
  %2 = llvm.zext %arg25 : i32 to i64
  %3 = llvm.zext %arg26 : i32 to i64
  %4 = llvm.mul %2, %3 : i64
  %5 = llvm.icmp "ugt" %4, %0 : i64
  %6 = "llvm.select"(%5, %4, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i64, i64) -> i64
  "llvm.return"(%6) : (i64) -> ()
}
]

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

def test1_before := [llvm|
{
^0(%arg1 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(1431655765 : i32) : i32
  %2 = llvm.mlir.constant(-1 : i32) : i32
  %3 = llvm.ashr %arg1, %0 : i32
  %4 = llvm.and %3, %1 : i32
  %5 = llvm.xor %4, %2 : i32
  %6 = llvm.add %5, %0 overflow<nsw> : i32
  %7 = llvm.add %arg1, %6 overflow<nsw> : i32
  "llvm.return"(%7) : (i32) -> ()
}
]

def udiv_common_divisor_before := [llvm|
{
^0(%arg65 : i1, %arg66 : i5, %arg67 : i5, %arg68 : i5):
  %0 = llvm.udiv %arg67, %arg66 : i5
  %1 = llvm.udiv %arg68, %arg66 : i5
  %2 = "llvm.select"(%arg65, %1, %0) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i5, i5) -> i5
  "llvm.return"(%2) : (i5) -> ()
}
]

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

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 n10_wrong_pred2_after := [llvm|
{
^0(%arg10 : i8, %arg11 : i8):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.icmp "eq" %arg10, %0 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

def xor_common_op_commute0_before := [llvm|
{
^0(%arg208 : i8, %arg209 : i8):
  %0 = llvm.xor %arg208, %arg209 : i8
  %1 = llvm.or %0, %arg208 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

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

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

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

structure Tensor2d' (α : Type) where
  dim₀ : Index
  dim₁ : Index
  mat : Matrix (Fin dim₀) (Fin dim₁) α

@[simp_llvm]
def not? {w : Nat} (x : BitVec w) : IntW w := do
  .value (~~~x)

pure validCandidates

|
</all_available_defs>

<all_available_lemmas>
Std.HashSet.mem_insert in Std.Data.HashSet.Lemmas
and_true in Init.SimpLemmas
beq_iff_eq in Init.Core
true_and in Init.SimpLemmas
Std.HashMap.getD_eq_getD_getElem? in Std.Data.HashMap.Lemmas
Finset.range_add in Mathlib.Algebra.Group.Nat.Range
FinEnum.mem_toList in Mathlib.Data.FinEnum

@[aesop 50% unsafe]
theorem Std.HashMap.mem_of_getElem? [BEq K] [LawfulBEq K] [Hashable K] [LawfulHashable K] {m : Std.HashMap K V} {k : K} :
    m[k]? = some v → k ∈ m

theorem Std.HashMap.mem_iff_getElem? [BEq K] [LawfulBEq K] [Hashable K] [LawfulHashable K] [Inhabited V] {m : Std.HashMap K V} {k : K} :
     k ∈ m ↔ ∃ v, m[k]? = some v

theorem test9_thm (e : IntW 32) :
  LLVM.and (icmp IntPred.ne (LLVM.and e (const? 32 1073741824)) (const? 32 0))
      (icmp IntPred.sgt e (const? 32 (-1))) ⊑
    icmp IntPred.eq (LLVM.and e (const? 32 (-1073741824))) (const? 32 1073741824)

theorem ashrslt_02_03_proof : ashrslt_02_03_before ⊑ ashrslt_02_03_after

theorem n14_trunc_of_lshr_proof : n14_trunc_of_lshr_before ⊑ n14_trunc_of_lshr_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 main6_logical_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 7#32 == 3#32) = 1#1 →
    ofBool (x &&& 48#32 == 16#32) = 1#1 → 0#32 = zeroExtend 32 (ofBool (x &&& 55#32 != 19#32))

theorem masked_icmps_mask_notallzeros_bmask_mixed_3_logical_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 15#32 != 0#32) = 1#1 → ofBool (x &&& 7#32 == 0#32) = ofBool (x &&& 15#32 == 8#32)

theorem a_false_implies_b_false2_comm_thm.extracted_1._5 : ∀ (x x_1 : BitVec 1) (x_2 : BitVec 8),
  ofBool (20#8 <ᵤ x_2) = 1#1 → ofBool (10#8 <ᵤ x_2) = 1#1 → x_1 ||

theorem urem_i8_thm (e e_1 : IntW 8) : trunc 8 (urem (zext 32 e_1) (zext 32 e)) ⊑ urem e_1 e

theorem test_sub_nuw_nsw__nuw_is_safe_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ofBool (x &&& 2147483647#32 == 1073741824#32) = 1#1 →
    ¬(True ∧ (BitVec.ofInt 32 (-2147483648)).usubOverflow (x &&& 2147483647#32) = true) →
      1073741824#32 = BitVec.ofInt 32 (-2147483648) - (x &&& 2147483647#32)

theorem shl_C1_add_A_C2_i32_thm (e : IntW 16) :
  shl (const? 32 6) (add (zext 32 e) (const? 32 5)) ⊑ shl (const? 32 192) (zext 32 e { «nneg» := true })

theorem test16_thm.extracted_1._1 : ∀ (x : BitVec 16), 12#16 ≥ ↑16 ∨ 15#16 ≥ ↑16 → False

theorem alive_820   : alive_820_src ⊑ alive_820_tgt

theorem sle_or_min_logical_thm (e e_1 : IntW 8) :
  select (icmp IntPred.sle e_1 e) (const? 1 1) (icmp IntPred.eq e_1 (const? 8 (-128))) ⊑
    icmp IntPred.sle e_1 e

theorem main7d_logical_thm.extracted_1._9 : ∀ (x x_1 x_2 x_3 x_4 : BitVec 32),
  ofBool (x_4 &&& (x_3 &&& x_2) == x_3 &&& x_2) = 1#1 →
    ofBool (x_4 &&& (x_3 &&& x_2) != x_3 &&& x_2) = 1#1 →
      ofBool (x_4 &&& (x_1 &&& x) == x_1 &&& x) = 1#1 → 0#32 = zeroExtend 32 1#1

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 sext_zext_ult_known_nonneg_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ¬6#8 ≥ ↑8 → ofBool (signExtend 32 x_1 <ᵤ zeroExtend 32 (x >>> 6#8)) = ofBool (x_1 <ᵤ x >>> 6#8)

@[simp]
lemma swapLastTwo_eq1' : swapLastTwo (n := n) (Fin.last (n + 1)) = n

theorem and_to_xor3_thm (e e_1 : IntW 32) :
  LLVM.and (LLVM.or e_1 e) (LLVM.xor (LLVM.and e e_1) (const? 32 (-1))) ⊑ LLVM.xor e_1 e

theorem neg_eq_not_add_one (x : BitVec w) :
    -x = ~~~ x + 1#w

theorem ne_shift_in_zeros_proof : ne_shift_in_zeros_before ⊑ ne_shift_in_zeros_after

theorem select_icmp_ne_0_and_32_and_not_4096_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (0#32 != x_1 &&& 32#32) = 1#1 → ¬ofBool (x_1 &&& 32#32 == 0#32) = 1#1 → x &&& BitVec.ofInt 32 (-4097) = x

theorem icmp_ne_sext_eq_otherwise_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (signExtend 32 (ofBool (x == 2#32)) != x) = ofBool (x != 0#32)

theorem eval_congrEnv {p : FSM arity}
    {x y : arity → BitStream} {n : Nat} (h : ∀ a i, i ≤ n → x a i = y a i) :
    p.eval x n = p.eval y n

theorem lshr_lshr_pow2_const_negative_overflow_proof : lshr_lshr_pow2_const_negative_overflow_before ⊑ lshr_lshr_pow2_const_negative_overflow_after

theorem mul_splat_fold_too_narrow_proof : mul_splat_fold_too_narrow_before ⊑ mul_splat_fold_too_narrow_after

theorem test5_proof : test5_before ⊑ test5_after

@[simp, simp_sllvm]
theorem bind_eq (x : EffectM α) (f : α → EffectM β) (s) :
    (x >>= f) s = x s >>= (fun (x, s) => f x s)

theorem ashr_ult_9_proof : ashr_ult_9_before ⊑ ashr_ult_9_after

theorem e_739 :
    5 * (x ^^^ y) + 7 *  ~~~(x ^^^ y) + 2 * x + 1 * y - 5 *  ~~~y - 2 *  ~~~(x &&& y) + 7 * (x ||| y) - 7 *  ~~~x + 2 *  ~~~(x ||| y) - 4 *  ~~~(x |||  ~~~y) - 22 * (x &&& y) =  - 5 * (x |||  ~~~y) + 12 * (x &&&  ~~~y)

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

theorem scalar_i32_lshr_and_signbit_eq_proof : scalar_i32_lshr_and_signbit_eq_before ⊑ scalar_i32_lshr_and_signbit_eq_after

theorem test_sub_nuw__nsw_is_safe_thm (e : IntW 32) :
  select (icmp IntPred.eq (LLVM.or e (const? 32 (-2147483648))) (const? 32 (-2147483647))) (const? 32 (-1))
      (sub (const? 32 (-2147483648)) (LLVM.or e (const? 32 (-2147483648))) { «nsw» := false, «nuw» := true }) ⊑
    sub (const? 32 (-2147483648)) (LLVM.or e (const? 32 (-2147483648))) { «nsw» := true, «nuw» := false }

theorem sgt_smax4_thm (e e_1 : IntW 32) :
  icmp IntPred.slt (add e_1 (const? 32 3))
      (select (icmp IntPred.sgt e (add e_1 (const? 32 3))) e (add e_1 (const? 32 3))) ⊑
    icmp IntPred.sgt e (add e_1 (const? 32 3))

theorem foo1_and_signbit_lshr_without_shifting_signbit_both_sides_proof : foo1_and_signbit_lshr_without_shifting_signbit_both_sides_before ⊑ foo1_and_signbit_lshr_without_shifting_signbit_both_sides_after

@[simp] theorem isPoison_value : isPoison (value a) = false

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 relabelNat_unsat_iff' {aig : AIG α} {hidx1} {hidx2} :
    (aig.relabelNat).UnsatAt idx invert hidx1 ↔ aig.UnsatAt idx invert hidx2

theorem add_smax_simplify2_proof : add_smax_simplify2_before ⊑ add_smax_simplify2_after

theorem map_map {A B C : α → Type*} {l : List α} (t : HVector A l)
    (f : ∀ a, A a → B a) (g : ∀ a, B a → C a) :
    (t.map f).map g = t.map (fun a v => g a (f a v))

theorem ult_1_impliesF_eq_1_thm.extracted_1._5 : ∀ (x x_1 : BitVec 8),
  ¬ofBool (x_1 <ᵤ 1#8) = 1#1 → ofBool (x_1 != 0#8) = 1#1 → ofBool (x_1 == x) = ofBool (x == x_1)

theorem icmp_eq_sext_eq_zero_proof : icmp_eq_sext_eq_zero_before ⊑ icmp_eq_sext_eq_zero_after

theorem test_shl_nsw__nsw_is_safe_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ofBool (x ||| BitVec.ofInt 32 (-83886080) == BitVec.ofInt 32 (-83886079)) = 1#1 →
    ¬(True ∧ ((x ||| BitVec.ofInt 32 (-83886080)) <<< 2#32).sshiftRight' 2#32 ≠ x ||| BitVec.ofInt 32 (-83886080) ∨
          2#32 ≥ ↑32) →
      ¬(True ∧ ((x ||| BitVec.ofInt 32 (-83886080)) <<< 2#32).sshiftRight' 2#32 ≠ x ||| BitVec.ofInt 32 (-83886080) ∨
            2#32 ≥ ↑32 ∨
              True ∧
                  ((x ||| BitVec.ofInt 32 (-83886080)) <<< 2#32).sshiftRight' 2#32 ≠ x ||| BitVec.ofInt 32 (-83886080) ∨
                2#32 ≥ ↑32) →
        BitVec.ofInt 32 (-335544316) * (x ||| BitVec.ofInt 32 (-83886080)) *
            (x ||| BitVec.ofInt 32 (-83886080)) <<< 2#32 =
          (x ||| BitVec.ofInt 32 (-83886080)) <<< 2#32 * (x ||| BitVec.ofInt 32 (-83886080)) *
            (x ||| BitVec.ofInt 32 (-83886080)) <<< 2#32

theorem icmp_eq_and_pow2_shl1_proof : icmp_eq_and_pow2_shl1_before ⊑ icmp_eq_and_pow2_shl1_after

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

theorem select_zext_different_condition_thm.extracted_1._1 : ∀ (x x_1 : BitVec 1),
  x_1 = 1#1 →
    True ∧ (64#64).saddOverflow (zeroExtend 64 x) = true ∨ True ∧ (64#64).uaddOverflow (zeroExtend 64 x) = true →
      False

theorem lor_bor_left2_thm (e e_1 : IntW 1) : LLVM.or (select e_1 (const? 1 1) e) e ⊑ select e_1 (const? 1 1) e

theorem and_sel_op0_thm (e : IntW 1) : LLVM.and (select e (const? 32 25) (const? 32 0)) (const? 32 1) ⊑ zext 32 e

theorem or_nosignbit_shl_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬8#32 ≥ ↑32 → (x ||| 2147418112#32) <<< 8#32 = x <<< 8#32 ||

theorem ne_smax4_proof : ne_smax4_before ⊑ ne_smax4_after

theorem n3_constmask_samemask_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  True ∧ (x_1 &&& 65280#32).saddOverflow (x &&& 65280#32) = true ∨
      True ∧ (x_1 &&& 65280#32).uaddOverflow (x &&& 65280#32) = true →
    False

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

theorem shl1_trunc_sgt0_thm (e : IntW 9) :
  icmp IntPred.sgt (trunc 6 (shl (const? 9 1) e)) (const? 6 0) ⊑
    icmp IntPred.sgt (trunc 6 (shl (const? 9 1) e { «nsw» := false, «nuw» := true })) (const? 6 0)

theorem ashr_ult_2_proof : ashr_ult_2_before ⊑ ashr_ult_2_after

theorem ne_nuw_rem_nz_thm (e : IntW 8) :
  icmp IntPred.ne (mul e (const? 8 5) { «nsw» := false, «nuw» := true }) (const? 8 (-30)) ⊑ const? 1 1

theorem or_eq_and_not_add :
    x ||

theorem sle_smax1_proof : sle_smax1_before ⊑ sle_smax1_after

theorem not_match_inconsistent_signs_thm (e : IntW 64) :
  add (urem e (const? 64 299)) (mul (urem (LLVM.sdiv e (const? 64 299)) (const? 64 64)) (const? 64 299)) ⊑
    add (urem e (const? 64 299))
      (mul (LLVM.and (LLVM.sdiv e (const? 64 299)) (const? 64 63)) (const? 64 299) { «nsw» := true, «nuw» := true })
      { «nsw» := true, «nuw» := true }

theorem masked_icmps_mask_notallzeros_bmask_mixed_negated_6_logical_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 12#32 == 0#32) = 1#1 → 1#1 = ofBool (x &&& 15#32 != 8#32)

theorem shl_nsw_nuw_add_nsw_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬(True ∧ (1#32 <<< x).sshiftRight' x ≠ 1#32 ∨
        True ∧ 1#32 <<< x >>> x ≠ 1#32 ∨ x ≥ ↑32 ∨ True ∧ (1#32 <<< x).saddOverflow (-1#32) = true) →
    True ∧ ((-1#32) <<< x).sshiftRight' x ≠ -1#32 ∨ x ≥ ↑32 → False

theorem mul_mask_pow2_eq4_thm (e : IntW 8) :
  icmp IntPred.eq (LLVM.and (mul e (const? 8 44)) (const? 8 4)) (const? 8 4) ⊑
    icmp IntPred.ne (LLVM.and e (const? 8 1)) (const? 8 0)

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

theorem ashrslt_02_15_thm (e : IntW 4) :
  icmp IntPred.slt (ashr e (const? 4 2)) (const? 4 (-1)) ⊑ icmp IntPred.slt e (const? 4 (-4))

theorem select_1_proof : select_1_before ⊑ select_1_after

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

theorem or_to_nxor1_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  x_1 &&& x ||

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 t0_thm.extracted_1._2 : ∀ (x : BitVec 8),
  ¬(True ∧ x.smod (BitVec.ofInt 8 (-32)) ≠ 0 ∨
        (BitVec.ofInt 8 (-32) == 0 || 8 != 1 && x == intMin 8 && BitVec.ofInt 8 (-32) == -1) = true) →
    ¬(True ∧ x >>> 5#8 <<< 5#8 ≠ x ∨ 5#8 ≥ ↑8 ∨ True ∧ (0#8).ssubOverflow (x.sshiftRight' 5#8) = true) →
      x.sdiv (BitVec.ofInt 8 (-32)) = 0#8 - x.sshiftRight' 5#8

theorem lshrult_02_02_thm.extracted_1._1 : ∀ (x : BitVec 4),
  ¬2#4 ≥ ↑4 → ofBool (x >>> 2#4 <ᵤ 2#4) = ofBool (-1#4 <ₛ x)

theorem p0_proof : p0_before ⊑ p0_after

theorem t0_ult_slt_128_thm.extracted_1._6 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 + 16#32 <ᵤ 144#32) = 1#1 → ofBool (127#32 <ₛ x_1) = 1#1 → x_1 = x

theorem t0_proof : t0_before ⊑ t0_after

theorem sub_dec_thm (e e_1 : IntW 8) : sub (add e_1 (const? 8 (-1))) e ⊑ add e_1 (LLVM.xor e (const? 8 (-1)))

theorem t1_sshr_proof : t1_sshr_before ⊑ t1_sshr_after

theorem p_constmask2_thm (e e_1 : IntW 32) :
  add (LLVM.and e_1 (const? 32 61440)) (LLVM.and e (const? 32 (-65281))) ⊑
    LLVM.or (LLVM.and e_1 (const? 32 61440)) (LLVM.and e (const? 32 (-65281))) { «disjoint» := true }

theorem test19_proof : test19_before ⊑ test19_after

@[bv_automata_nnf] theorem not_eq_eq {α : Sort u} (a b : α) : (¬ (a = b)) = (a ≠ b)

theorem e_1950 :
    11 * (b ^^^  ~~~( ~~~a &&& (b ^^^ c))) + 1 *  ~~~( ~~~a ||| (b ^^^ c)) - 3 *  ~~~( ~~~a ||| ( ~~~b &&& c)) + 1 * (b &&& (a ^^^ c)) - 7 * ( ~~~(a &&& b) &&&  ~~~(a ^^^ (b ^^^ c))) - 5 * ( ~~~c &&&  ~~~(a ^^^ b)) + 1 * (c ^^^ (a &&& (b ||| c))) + 1 * ( ~~~(a ||| b) ||| (b ^^^ c)) - 1 * (b ^^^  ~~~(a &&& (b &&& c))) - 2 *  ~~~(a &&& ( ~~~b ||| c)) + 3 * ( ~~~a &&& (b ^^^ c)) - 1 * ((a &&& b) ^^^ (b ||| c)) - 1 * (b ^^^  ~~~(a ||| c)) - 5 * ( ~~~(a &&&  ~~~b) &&& (b ^^^ c)) + 5 * ((a &&& c) ^^^  ~~~(a ^^^ ( ~~~b &&& c))) - 1 * ((a |||  ~~~b) &&& (a ^^^ (b ^^^ c))) + 2 * (b ^^^  ~~~(a &&& c)) - 11 *  ~~~( ~~~a ||| (b &&& c)) - 3 * (c ^^^ ( ~~~a ||| (b &&& c))) - 5 *  ~~~(b ^^^ c) + 11 * (c ^^^ ( ~~~a &&& ( ~~~b ||| c))) - 1 * (b ^^^  ~~~(a &&& ( ~~~b ||| c))) - 1 * (b &&&  ~~~c) - 1 * ( ~~~b &&&  ~~~(a ^^^ c)) + 1 * (c &&& (a |||  ~~~b)) + 2 * (b ^^^ ( ~~~a &&& (b ^^^ c))) - 7 * (a &&& (b ||| c)) - 2 * (b ^^^ (a &&& ( ~~~b ||| c))) + 1 * (c ^^^ (a ||| b)) + 5 * ((a |||  ~~~b) &&& (b ^^^ c)) - 1 * ((a &&& b) |||  ~~~(b ||| c)) + 2 *  ~~~(a &&& (b &&& c)) + 7 * (c ^^^  ~~~( ~~~a ||| (b &&& c))) - 2 *  ~~~( ~~~a &&& (b ||| c)) - 1 * (b &&& c) + 2 * ((a &&&  ~~~b) |||  ~~~(a ^^^ (b ^^^ c))) + 2 * (b |||  ~~~(a ||| c)) + 4 * (c ^^^  ~~~( ~~~a &&& (b &&& c))) + 3 * (b &&&  ~~~(a &&&  ~~~c)) + 1 * ((a ||| b) &&& (a ^^^ (b ^^^ c))) - 3 * ( ~~~(a ^^^ b) |||  ~~~(a ^^^ c)) + 7 * (b ^^^ (a ||| (b ^^^ c))) + 1 * ((a &&& c) ^^^ (a ^^^ (b &&& c))) - 3 *  ~~~c + 5 * ( ~~~c ||| (a ^^^ b)) - 7 * c - 5 *  ~~~(a &&& (b ||| c)) - 8 *  ~~~(a ||| (b ||| c)) - 13 *  ~~~(a ||| ( ~~~b ||| c)) - 8 *  ~~~( ~~~a ||| (b ||| c)) + 9 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 6 * ( ~~~a &&& ( ~~~b &&& c)) - 12 * ( ~~~a &&& (b &&& c)) - 1 * (a &&& (b &&& c)) =  - 3 * ( ~~~(a &&&  ~~~b) &&&  ~~~(a ^^^ (b ^^^ c))) + 2 * ((a ||| b) &&&  ~~~(b ^^^ c))

theorem lshr_eq_msb_low_last_zero_proof : lshr_eq_msb_low_last_zero_before ⊑ lshr_eq_msb_low_last_zero_after

theorem select_icmp_eq_and_32_0_xor_8_proof : select_icmp_eq_and_32_0_xor_8_before ⊑ select_icmp_eq_and_32_0_xor_8_after

theorem icmp_slt_0_or_icmp_sgt_0_i64_proof : icmp_slt_0_or_icmp_sgt_0_i64_before ⊑ icmp_slt_0_or_icmp_sgt_0_i64_after

theorem test56_proof : test56_before ⊑ test56_after

theorem or_or_and_pat3_proof : or_or_and_pat3_before ⊑ or_or_and_pat3_after

theorem e_2304 :
     - 1 * (f ^^^ ( ~~~d ||| ( ~~~e ||| f))) - 7 * (f ^^^ (d &&& (e ||| f))) + 1 * ((d &&& e) ^^^ (e ||| f)) - 2 * (f &&& (d |||  ~~~e)) + 2 * ((d |||  ~~~e) &&&  ~~~(e ^^^ f)) - 2 * ( ~~~(d &&& e) &&& (e ^^^ f)) - 5 * (d ||| (e ^^^ f)) - 1 * ( ~~~(d &&&  ~~~e) &&& (d ^^^ (e ^^^ f))) + 7 * (e ^^^  ~~~(d ||| (e &&& f))) - 2 * (e ^^^ (d &&& ( ~~~e ||| f))) - 1 * (f ^^^ (d ||| ( ~~~e &&& f))) + 11 * (e &&&  ~~~f) + 3 * (e &&&  ~~~(d &&& f)) - 2 * (e ||| (d &&&  ~~~f)) - 1 *  ~~~(d &&&  ~~~f) - 2 *  ~~~( ~~~d &&& ( ~~~e &&& f)) - 2 * ( ~~~d ||| (e ||| f)) - 11 * (f ^^^ (d &&&  ~~~e)) - 1 * (e |||  ~~~(d |||  ~~~f)) + 4 * (e ^^^  ~~~(d ||| (e ^^^ f))) + 2 * (e ^^^  ~~~(d ||| ( ~~~e &&& f))) - 3 *  ~~~(d ||| (e ^^^ f)) + 11 * ( ~~~(d &&& e) &&& (d ^^^ (e ^^^ f))) - 11 * (f ^^^  ~~~(d &&&  ~~~e)) + 5 * ((d |||  ~~~e) &&& (e ^^^ f)) - 6 * (f ^^^  ~~~(d ||| (e &&& f))) + 2 * ((d &&& f) ^^^ (d ^^^ ( ~~~e &&& f))) - 7 * (e ^^^  ~~~( ~~~d ||| (e &&& f))) + 1 * (e ^^^ ( ~~~d ||| (e ||| f))) + 3 *  ~~~( ~~~d ||| (e ^^^ f)) + 3 * ( ~~~d &&& (e ^^^ f)) - 5 * ( ~~~(d ||| e) ||| (d ^^^ (e ^^^ f))) + 2 * ((d &&&  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) - 3 * (f ^^^  ~~~(d &&& (e &&& f))) + 2 * ((d |||  ~~~e) &&& (d ^^^ (e ^^^ f))) + 5 * (f ^^^ (d ||| (e ||| f))) + 11 *  ~~~(d |||  ~~~e) - 5 * (d &&& e) - 3 *  ~~~(d ||| (e &&& f)) - 3 * ((d &&& e) |||  ~~~(e ||| f)) + 7 * ( ~~~e |||  ~~~(d ^^^ f)) - 1 * (f ^^^  ~~~( ~~~d ||| ( ~~~e &&& f))) - 1 * ((d &&& e) |||  ~~~(d ^^^ (e ^^^ f))) - 1 * ( ~~~(d ||| e) |||  ~~~(e ^^^ f)) - 11 * ( ~~~(d |||  ~~~e) |||  ~~~(e ^^^ f)) - 6 * (d ^^^ ( ~~~e ||| f)) + 1 * ( ~~~(d &&&  ~~~e) &&&  ~~~(d ^^^ (e ^^^ f))) + 1 * (e ^^^  ~~~(d &&& (e ||| f))) - 2 * ( ~~~(d &&& e) &&&  ~~~(e ^^^ f)) + 3 *  ~~~(d ^^^ ( ~~~e ||| f)) - 1 * (e ^^^ f) - 1 * (d &&& ( ~~~e ||| f)) - 1 * (e |||  ~~~(d ||| f)) - 6 * (d &&& (e ||| f)) + 2 * (e ||| (d ^^^ f)) + 26 *  ~~~(d ||| (e ||| f)) - 5 *  ~~~(d ||| ( ~~~e ||| f)) + 20 *  ~~~( ~~~d ||| (e ||| f)) + 15 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 2 * ( ~~~d &&& ( ~~~e &&& f)) + 41 * ( ~~~d &&& (e &&& f)) + 18 * (d &&& ( ~~~e &&& f)) + 35 * (d &&& (e &&& f)) = 2 * (e ^^^  ~~~(d &&& f)) - 11 * (f ^^^  ~~~(d ||| ( ~~~e &&& f)))

theorem lshrugt_02_15_exact_thm (e : IntW 4) :
  icmp IntPred.ugt (lshr e (const? 4 2) { «exact» := true }) (const? 4 (-1)) ⊑ const? 1 0

theorem test19_thm (e : IntW 10) :
  sext 10 (ashr (shl (trunc 3 e) (const? 3 2)) (const? 3 2)) ⊑
    sext 10 (sub (const? 3 0) (LLVM.and (trunc 3 e) (const? 3 1)) { «nsw» := true, «nuw» := false })

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

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 t2_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬(True ∧ (0#8).ssubOverflow x = true) → ofBool (0#8 - x <ₛ x) = ofBool (0#8 <ₛ x)

theorem e_352 :
     - 2 *  ~~~(x &&&  ~~~x) + 3 *  ~~~(x &&&  ~~~y) - 1 *  ~~~(x &&& y) - 1 *  ~~~x + 5 * (x ||| y) - 4 *  ~~~(x |||  ~~~y) - 2 * (x &&&  ~~~y) - 6 * (x &&& y) =  - 1 *  ~~~(x ||| y)

theorem cmpne_xor_cst3_proof : cmpne_xor_cst3_before ⊑ cmpne_xor_cst3_after

theorem test1_proof : test1_before ⊑ test1_after

theorem test4_proof : test4_before ⊑ test4_after

theorem e_312 :
     - 1 * (x |||  ~~~y) - 11 * (x ||| y) + 11 *  ~~~(x &&& y) - 6 * y + 1 * x - 12 *  ~~~(x ||| y) + 15 * (x &&& y) =  - 4 *  ~~~(x |||  ~~~y) - 2 *  ~~~(x &&&  ~~~y)
</all_available_lemmas>

<local_ctx>
import Mathlib.Algebra.Group.Nat.Range

import Blase.AutoStructs.BundledNfa

import Blase.FinEnum

open SetRel

abbrev State := Nat

structure RawCNFA (A : Type 0) [BEq A] [Hashable A] [DecidableEq A] [FinEnum A] where
  stateMax : State
  initials : Std.HashSet State
  finals : Std.HashSet State
  trans : Std.HashMap (State × A) (Std.HashSet State)
deriving Repr

section sim

variable {A : Type} [BEq A] [Hashable A] [DecidableEq A] [FinEnum A]

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

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

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

end sim

section basics

variable {A : Type} [BEq A] [Hashable A] [DecidableEq A] [FinEnum A]

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

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.addInitial (m : RawCNFA A) (s : State) : RawCNFA A :=
  { m with initials := m.initials.insert s }

def RawCNFA.createSink (m : RawCNFA A) : State × RawCNFA A :=
  let (s, m) := m.newState
  let m := m.addInitial s
  let m := FinEnum.toList (α := A).foldl (init := m) fun m a =>
    m.addTrans a s s
  (s, m)

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
</local_ctx>

<target_theorem>
@[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) :=
</target_theorem>

