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>
Bool in Init.Prelude
Nat in Init.Prelude
BitVec in Init.Prelude
BitVec.adcb in Init.Data.BitVec.Bitblast
Prod in Init.Prelude
Fin in Init.Prelude
BitVec.iunfoldr in Init.Data.BitVec.Folds
FinEnum in Mathlib.Data.FinEnum
FinEnum.card in Mathlib.Data.FinEnum
Polynomial.X in Mathlib.Algebra.Polynomial.Basic
ZMod in Mathlib.Data.ZMod.Defs
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
Array in Init.Prelude
List.map in Init.Prelude
Array.foldl in Init.Data.Array.Basic
Std.HashMap.emptyWithCapacity in Std.Data.HashMap.Basic
Array.size in Init.Prelude
List in Init.Prelude
Vector in Init.Data.Vector.Basic
String in Init.Prelude
Unit in Init.Prelude
Field in Mathlib.Algebra.Field.Defs
FinEnum.equiv in Mathlib.Data.FinEnum
NFA in Mathlib.Computability.NFA
NFA.accept in Mathlib.Computability.NFA
NFA.start in Mathlib.Computability.NFA
NFA.step in Mathlib.Computability.NFA
FinEnum.toList in Mathlib.Data.FinEnum
BitVec.ofNat in Init.Prelude
BitVec.cons in Init.Data.BitVec.Basic
BitVec.cast in Init.Data.BitVec.Basic
Function.Injective in Init.Data.Function
Function.LeftInverse in Init.Data.Function

def carry (initCarry : Bool) (x y : BitStream) : BitStream :=
  fun n => (addAux' initCarry x y n).2

def BitStream : Type := Nat → Bool

def addAux' (carryIn : Bool) (x y : BitStream) (i : Nat) :  Bool × Bool :=
  let carryIn : Bool := match i with
    | 0 => carryIn
    | i + 1 => (addAux' carryIn x y i).2
  Prod.swap (BitVec.adcb (x i) (y i) carryIn)

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

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

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

def worklistRun' (final : S → Bool) (inits : Array S) (hinits : inits.toList.Nodup) (f : S → Array (A × S)) : RawCNFA A :=
  let st0 := worklist.initState _ _ inits hinits final
  go st0
where go (st0 : worklist.St A S) : RawCNFA A :=
  if hemp : st0.worklist.isEmpty then st0.m else
  let sa? := st0.worklist.back?
  match heq : sa? with
  | some sa =>
    let wl := st0.worklist.pop
    let st1 := { st0 with worklist := wl,
                          worklist_nodup := by admit /- proof elided -/

structure worklist.St where
  m : RawCNFA A
  map : Std.HashMap S State := ∅
  worklist : Array S := ∅
  worklist_nodup : worklist.toList.Nodup
  worklist_incl : ∀ sa ∈ worklist, sa ∈ map

def worklist.initState (inits : Array S) (hinits : inits.toList.Nodup) (final? : S → Bool) : worklist.St A S :=
  let m := RawCNFA.empty (A := A)
  let mapm := inits.foldl (init := (Std.HashMap.emptyWithCapacity, m)) fun (map, m) sa =>
    let (s, m) := m.newState
    let m := m.addInitial s
    let m := if final? sa then m.addFinal s else m
    (map.insert sa s, m)
  let map := mapm.1
  let m := mapm.2
  let worklist_incl : ∀ sa ∈ inits, sa ∈ map :=

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

abbrev State := Nat

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

def processOneElem (final : S → Bool) (s : State) (st : worklist.St A S) : A × S → worklist.St A S :=
  fun (a', sa') =>
    let (s', st') := st.addOrCreateState _ _ (final sa') sa'
    let m := st'.m.addTrans a' s s'
    { st' with m }

def worklist.St.addOrCreateState (st : worklist.St A S) (final? : Bool) (sa : S) : State × worklist.St A S :=
  match heq : st.map[sa]? with
  | some s => (s, st)
  | none =>
    let (s, m) := st.m.newState
    let m := if final? then m.addFinal s else m
    let map := st.map.insert sa s
    let worklist := st.worklist.push sa
    have worklist_nodup : worklist.toList.Nodup := by admit /- proof elided -/

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

structure FSM (arity : Type) : Type 1 where
   
  ( α  : Type )
  [ i : FinEnum α ]
  [ h : Hashable α ]
  [ dec_eq : DecidableEq α ]
   
  ( initCarry : α → Bool )
   
  outputCirc : Circuit (α ⊕ arity)
  nextStateCirc : α → Circuit (α ⊕ arity)

inductive Circuit (α : Type u) : Type u
  | tru : Circuit α
  | fals : Circuit α
   
  | var : (positive: Bool) → α → Circuit α
  | and : Circuit α → Circuit α → Circuit α
  | or : Circuit α → Circuit α → Circuit α
  | xor : Circuit α → Circuit α → Circuit α
deriving Repr, DecidableEq

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

def bv2 : BitVec 4 := BitVec.ofNat 4 1

def bv1 : BitVec 4 := BitVec.ofNat 4 5

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

def test53_after := [llvm|
{
^0(%arg131 : i32):
  %0 = llvm.mlir.constant(7224 : i16) : i16
  %1 = llvm.mlir.constant(-32574 : i16) : i16
  %2 = llvm.trunc %arg131 : i32 to i16
  %3 = llvm.and %2, %0 : i16
  %4 = llvm.or disjoint %3, %1 : i16
  %5 = llvm.zext %4 : i16 to i64
  "llvm.return"(%5) : (i64) -> ()
}
]

def GLobalISelPostLegalizerCombiner :
    List (Σ Γ, Σ ty, PeepholeRewrite LLVMPlusRiscV Γ ty) :=
  (List.map (fun ⟨_,y⟩ => mkRewrite (LLVMToRiscvPeepholeRewriteRefine.toPeepholeUNSOUND y))
  redundant_binop_in_equality)
  ++
  (List.map (fun ⟨_,y⟩ => mkRewrite (LLVMToRiscvPeepholeRewriteRefine.toPeepholeUNSOUND y))
  PostLegalizerCombiner_LLVMIR_64)
  ++
  (List.map (fun ⟨_,y⟩ => mkRewrite (LLVMToRiscvPeepholeRewriteRefine.toPeepholeUNSOUND y))
  PostLegalizerCombiner_LLVMIR_32)
  ++
  (List.map (fun ⟨_,y⟩ => mkRewrite (LLVMToRiscvPeepholeRewriteRefine.toPeepholeUNSOUND y))
  canonicalize_icmp)
  ++
  List.map (fun ⟨_,y⟩ => mkRewrite (RISCVPeepholeRewriteToRiscvPeephole y))
  PostLegalizerCombiner_RISCV

def test25_before := [llvm|
{
^0(%arg2 : i37, %arg3 : i37):
  %0 = llvm.mlir.constant(17 : i37) : i37
  %1 = llvm.lshr %arg3, %0 : i37
  %2 = llvm.lshr %arg2, %0 : i37
  %3 = llvm.add %2, %1 : i37
  %4 = llvm.shl %3, %0 : i37
  "llvm.return"(%4) : (i37) -> ()
}
]

def add_positive_low_bound_reject_test: LLVMPeepholeRewriteRefine 32 [Ty.llvm (.bitvec 32)] where
  lhs := add_positive_low_bound_reject_llvm
  rhs := add_positive_low_bound_reject_riscv

Polynomial.coeff in Mathlib.Algebra.Polynomial.Basic

def wide_source_matching_signbits_before := [llvm|
{
^0(%arg5 : i32):
  %0 = llvm.mlir.constant(7 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.and %arg5, %0 : i32
  %3 = llvm.shl %1, %2 overflow<nsw> : i32
  %4 = llvm.trunc %3 : i32 to i8
  %5 = llvm.sext %4 : i8 to i24
  "llvm.return"(%5) : (i24) -> ()
}
]

def alive_AddSub_1152_src   :=
[llvm()| {
^bb0(%y : i1, %x : i1):
  %v1 = llvm.add %x, %y : i1
  llvm.return %v1 : i1
}]

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 test2_before := [llvm|
{
^0(%arg208 : i1):
  %0 = llvm.xor %arg208, %arg208 : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def xor_and_logic_or1_after := [llvm|
{
^0(%arg30 : i1, %arg31 : i1, %arg32 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.xor %arg31, %0 : i1
  %2 = "llvm.select"(%arg30, %1, %arg32) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%2) : (i1) -> ()
}
]

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

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

abbrev ReaderM  (d : Dialect) := ReaderT NameMapping (ExceptM d)

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

def test_nuw_dropped_before := [llvm|
{
^0(%arg7 : i32):
  %0 = llvm.mlir.constant(1073741823 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.mlir.constant(2 : i32) : i32
  %3 = llvm.and %arg7, %0 : i32
  %4 = llvm.icmp "eq" %3, %1 : i32
  %5 = llvm.shl %arg7, %2 overflow<nuw> : i32
  %6 = "llvm.select"(%4, %1, %5) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%6) : (i32) -> ()
}
]

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

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

def bitwise_and_bitwise_and_icmps_comm3_after := [llvm|
{
^0(%arg235 : i8, %arg236 : i8, %arg237 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.mlir.constant(1 : i8) : i8
  %2 = llvm.icmp "eq" %arg236, %0 : i8
  %3 = llvm.shl %1, %arg237 overflow<nuw> : i8
  %4 = llvm.or %3, %1 : i8
  %5 = llvm.and %arg235, %4 : i8
  %6 = llvm.icmp "eq" %5, %4 : i8
  %7 = llvm.and %6, %2 : i1
  "llvm.return"(%7) : (i1) -> ()
}
]

def add_mask_ashr28_non_pow2_i32_before := [llvm|
{
^0(%arg1 : i32):
  %0 = llvm.mlir.constant(28 : i32) : i32
  %1 = llvm.mlir.constant(9 : i32) : i32
  %2 = llvm.ashr %arg1, %0 : i32
  %3 = llvm.and %2, %1 : i32
  %4 = llvm.add %3, %2 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def test1_before := [llvm|
{
^0(%arg3 : i16):
  %0 = llvm.mlir.constant(8 : i32) : i32
  %1 = llvm.mlir.constant(5 : i32) : i32
  %2 = llvm.zext %arg3 : i16 to i32
  %3 = llvm.lshr %2, %0 : i32
  %4 = llvm.mul %2, %1 : i32
  %5 = llvm.or %3, %4 : i32
  %6 = llvm.trunc %5 : i32 to i16
  "llvm.return"(%6) : (i16) -> ()
}
]

def lshr_ne_msb_low_last_zero_before := [llvm|
{
^0(%arg174 : i8):
  %0 = llvm.mlir.constant(127 : i8) : i8
  %1 = llvm.mlir.constant(0 : i8) : i8
  %2 = llvm.lshr %0, %arg174 : i8
  %3 = llvm.icmp "ne" %2, %1 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

def test1_before := [llvm|
{
^0(%arg3 : i57, %arg4 : i57, %arg5 : i57):
  %0 = llvm.lshr %arg3, %arg5 : i57
  %1 = llvm.lshr %arg4, %arg5 : i57
  %2 = llvm.or %0, %1 : i57
  "llvm.return"(%2) : (i57) -> ()
}
]

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

def not_or_or_and_not_and_and_commute1_and_after := [llvm|
{
^0(%arg205 : i32, %arg206 : i32, %arg207 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg205, %0 : i32
  %2 = llvm.xor %arg207, %arg206 : i32
  %3 = llvm.or %2, %1 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def t0_before := [llvm|
{
^0(%arg206 : i8):
  %0 = llvm.mlir.constant(-42 : i8) : i8
  %1 = llvm.sub %arg206, %0 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

def test11_before := [llvm|
{
^0(%arg197 : i8):
  %0 = llvm.mlir.constant(12 : i8) : i8
  %1 = llvm.mlir.constant(4 : i8) : i8
  %2 = llvm.or %arg197, %0 : i8
  %3 = llvm.xor %2, %1 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

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

def test47_after := [llvm|
{
^0(%arg197 : i32, %arg198 : i32):
  %0 = llvm.and %arg198, %arg197 : i32
  "llvm.return"(%0) : (i32) -> ()
}
]

def accepts' (M : NFA' n) : Set (BitVecs' n) := M.M.accepts

def urem_i8_after := [llvm|
{
^0(%arg33 : i8, %arg34 : i8):
  %0 = llvm.urem %arg33, %arg34 : i8
  "llvm.return"(%0) : (i8) -> ()
}
]

def match_unsigned_after := [llvm|
{
^0(%arg18 : i64):
  %0 = llvm.mlir.constant(19136) : i64
  %1 = llvm.urem %arg18, %0 : i64
  "llvm.return"(%1) : (i64) -> ()
}
]

def icmp_eq_select_after := [llvm|
{
^0(%arg3 : i1, %arg4 : i32, %arg5 : i32):
  %0 = llvm.icmp "eq" %arg4, %arg5 : i32
  "llvm.return"(%0) : (i1) -> ()
}
]

def add_2_before := [llvm|
{
^0(%arg121 : i8, %arg122 : i1, %arg123 : i8, %arg124 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.mlir.constant(123 : i8) : i8
  %2 = llvm.xor %arg123, %0 : i8
  %3 = llvm.xor %arg124, %1 : i8
  %4 = "llvm.select"(%arg122, %2, %3) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  %5 = llvm.add %arg121, %4 : i8
  %6 = llvm.xor %5, %0 : i8
  "llvm.return"(%6) : (i8) -> ()
}
]

def udiv_exact_eq_1_before := [llvm|
{
^0(%arg10 : i8, %arg11 : i8):
  %0 = llvm.mlir.constant(1 : i8) : i8
  %1 = llvm.udiv exact %arg10, %arg11 : i8
  %2 = llvm.icmp "ne" %1, %0 : i8
  "llvm.return"(%2) : (i1) -> ()
}
]

structure NonNegFlag where
  nneg : Bool := false
  deriving Repr, DecidableEq, Lean.ToExpr

def and_and_logic_or_1_before := [llvm|
{
^0(%arg102 : i1, %arg103 : i1, %arg104 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.and %arg102, %arg103 : i1
  %2 = llvm.and %arg102, %arg104 : i1
  %3 = "llvm.select"(%1, %0, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%3) : (i1) -> ()
}
]

|

def demorgan_nand_before := [llvm|
{
^0(%arg38 : i8, %arg39 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.xor %arg38, %0 : i8
  %2 = llvm.and %1, %arg39 : i8
  %3 = llvm.xor %2, %0 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def sub_from_constant_of_add_with_constant_after := [llvm|
{
^0(%arg169 : i8):
  %0 = llvm.mlir.constant(-31 : i8) : i8
  %1 = llvm.sub %0, %arg169 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

def test14a_after := [llvm|
{
^0(%arg25 : i79):
  %0 = llvm.mlir.constant(77 : i79) : i79
  %1 = llvm.and %arg25, %0 : i79
  "llvm.return"(%1) : (i79) -> ()
}
]

def lshr_xor_after := [llvm|
{
^0(%arg21 : i8):
  %0 = llvm.mlir.constant(17 : i8) : i8
  %1 = llvm.lshr %0, %arg21 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

inductive WidthAbstractionKind
 
| generalizeGeq (cutoff : Nat)
 
| always
 
| never
deriving DecidableEq, Repr

def samesign_inverted_commute3_before := [llvm|
{
^0(%arg97 : i32, %arg98 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.and %arg97, %arg98 : i32
  %3 = llvm.icmp "sgt" %2, %0 : i32
  %4 = llvm.or %arg98, %arg97 : i32
  %5 = llvm.icmp "slt" %4, %1 : i32
  %6 = llvm.and %5, %3 : i1
  "llvm.return"(%6) : (i1) -> ()
}
]

def icmp_select_var_pred_uge_after := [llvm|
{
^0(%arg65 : i8, %arg66 : i8, %arg67 : i8):
  %0 = llvm.mlir.constant(2 : i8) : i8
  %1 = llvm.mlir.constant(0 : i8) : i8
  %2 = llvm.mlir.constant(false) : i1
  %3 = llvm.add %arg67, %0 overflow<nuw> : i8
  %4 = llvm.icmp "ne" %arg65, %1 : i8
  %5 = llvm.icmp "uge" %arg66, %3 : i8
  %6 = "llvm.select"(%4, %5, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%6) : (i1) -> ()
}
]

def xor_nosignbit_select_lshr_after := [llvm|
{
^0(%arg20 : i32, %arg21 : i1):
  %0 = llvm.mlir.constant(8 : i32) : i32
  %1 = llvm.mlir.constant(8388352 : i32) : i32
  %2 = llvm.lshr %arg20, %0 : i32
  %3 = llvm.xor %2, %1 : i32
  %4 = "llvm.select"(%arg21, %3, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%4) : (i32) -> ()
}
]

let φ : Nat := mvars.getElems.size
  let ⟨_, _, _, mcom⟩ ← SSA.elabIntoComObj reg (MetaLLVM φ)

AndOp in Init.Prelude
</all_available_defs>

<all_available_lemmas>
List.nodup_singleton in Mathlib.Data.List.Nodup
BitVec.eq_of_getLsbD_eq in Init.Data.BitVec.Bootstrap
BitVec.getLsbD_append in Init.Data.BitVec.Lemmas
BitVec.ofBool_eq_iff_eq in Init.Data.BitVec.Lemmas
Function.LeftInverse.injective in Init.Data.Function
BitVec.cons_msb_setWidth in Init.Data.BitVec.Bootstrap
BitVec.setWidth_cons in Init.Data.BitVec.Lemmas
List.foldl_cons in Init.Data.List.Basic
and_self in Init.SimpLemmas
and_true in Init.SimpLemmas
or_true in Init.SimpLemmas

@[ext]
theorem ext {x y : BitStream} (h : ∀ i, x i = y i) : x = y

theorem e_2412 :
     - 1 * ( ~~~(d ||| e) ||| (d ^^^ (e ^^^ f))) - 1 * ((d ^^^ e) &&& (d ^^^ f)) + 11 * (f ^^^ (d ||| ( ~~~e &&& f))) - 3 *  ~~~(d ^^^ (e &&& f)) - 2 * (e ^^^  ~~~( ~~~d ||| (e ^^^ f))) + 3 * (f ^^^ ( ~~~d ||| (e &&& f))) + 1 * (e |||  ~~~(d ||| f)) + 1 * (f ^^^  ~~~(d |||  ~~~e)) - 1 *  ~~~(d ^^^ (e ||| f)) + 4 * (f ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) + 2 * (d ||| ( ~~~e &&& f)) + 5 * ((e &&& f) ||| ( ~~~d &&& (e ||| f))) - 1 * (f ^^^  ~~~(d ||| ( ~~~e &&& f))) - 1 * (e ^^^ (d ||| ( ~~~e ||| f))) + 1 * (f ^^^  ~~~(d ||| e)) + 7 * (f ^^^  ~~~(d &&& ( ~~~e &&& f))) + 3 * (f &&&  ~~~(d &&&  ~~~e)) - 1 * (d &&& f) + 2 *  ~~~(d &&& ( ~~~e &&& f)) - 1 *  ~~~(d &&& ( ~~~e ||| f)) - 2 * (e ^^^  ~~~(d &&&  ~~~f)) + 2 * (f |||  ~~~(d ||| e)) - 6 * (d ^^^ ( ~~~e &&& f)) - 11 * (f ^^^ (d ||| (e ||| f))) + 2 * (e ^^^  ~~~(d &&& (e ||| f))) + 3 *  ~~~(d &&& (e &&& f)) + 1 *  ~~~(d |||  ~~~e) + 1 * (d ||| e) + 1 * ( ~~~(d ^^^ e) &&& (d ^^^ f)) - 2 * ( ~~~(d &&& e) &&& (e ^^^ f)) + 7 *  ~~~(e &&& f) + 3 * (d |||  ~~~f) - 1 * ( ~~~(d &&&  ~~~e) &&&  ~~~(e ^^^ f)) + 11 * (e &&&  ~~~f) - 5 * ( ~~~(d &&& e) &&& (d ^^^ (e ^^^ f))) + 11 * ( ~~~(d &&& e) &&&  ~~~(d ^^^ (e ^^^ f))) + 11 * (e |||  ~~~(d |||  ~~~f)) - 7 * (e ^^^ (d ||| (e ||| f))) + 1 *  ~~~(d &&& f) - 7 * (e &&& (d ||| f)) - 1 * (f ^^^ (d ||| e)) - 1 * (e &&&  ~~~(d &&&  ~~~f)) + 1 * (e ^^^  ~~~( ~~~d &&& (e ||| f))) - 11 *  ~~~( ~~~d &&& (e ||| f)) - 5 * (e ^^^ (d &&& (e ||| f))) - 5 * ( ~~~d ||| (e ||| f)) + 2 * ((d &&& e) ^^^  ~~~(d ^^^ (e &&& f))) + 1 * (e ^^^ ( ~~~d &&& (e ^^^ f))) + 2 * ((d ||| e) &&& (d ^^^ (e ^^^ f))) - 2 * (f |||  ~~~(d |||  ~~~e)) - 1 * (e &&&  ~~~(d ^^^ f)) + 1 * (f ^^^ (d |||  ~~~e)) + 2 * ((d &&& f) |||  ~~~(e ||| f)) - 5 * ( ~~~(d ||| e) |||  ~~~(d ^^^ (e ^^^ f))) + 2 * ( ~~~(d &&&  ~~~e) &&& (e ^^^ f)) + 2 * (e &&& (d ^^^ f)) - 11 * (e ^^^ ( ~~~d ||| (e &&& f))) + 3 * (d &&& ( ~~~e ||| f)) - 7 * (d ||| (e &&& f)) - 6 * (f ^^^ ( ~~~d &&& ( ~~~e ||| f))) - 6 *  ~~~( ~~~d &&& ( ~~~e &&& f)) - 6 *  ~~~(e &&&  ~~~f) - 2 * (d &&& (e ||| f)) + 5 * ((d &&& f) ^^^ (d ^^^ ( ~~~e &&& f))) + 4 * (e ^^^  ~~~(d ||| ( ~~~e &&& f))) - 7 *  ~~~(d ||| (e ||| f)) - 20 *  ~~~(d ||| ( ~~~e ||| f)) - 3 *  ~~~( ~~~d ||| (e ||| f)) - 13 *  ~~~( ~~~d ||| ( ~~~e ||| f)) + 5 * ( ~~~d &&& ( ~~~e &&& f)) - 16 * ( ~~~d &&& (e &&& f)) + 18 * (d &&& ( ~~~e &&& f)) + 15 * (d &&& (e &&& f)) =  - 4 *  ~~~(e ||| f) - 7 * ((d &&& e) |||  ~~~(e ^^^ f))

theorem sle_swap_or_min_commute_proof : sle_swap_or_min_commute_before ⊑ sle_swap_or_min_commute_after

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

theorem trunc_shl_shl_var_thm.extracted_1._2 : ∀ (x x_1 : BitVec 64),
  ¬(x ≥ ↑64 ∨ 2#64 ≥ ↑64) →
    ¬(x ≥ ↑64 ∨ 2#32 ≥ ↑32) → truncate 32 (x_1 <<< x <<< 2#64) = truncate 32 (x_1 <<< x) <<< 2#32

theorem zext_add_scalar_thm.extracted_1._2 : ∀ (x : BitVec 1), ¬x = 1#1 → zeroExtend 32 x + 42#32 = 42#32

theorem icmp_eq_sext_eq_zero_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (signExtend 32 (ofBool (x == 0#32)) == x) = 0#1

theorem t0_proof : t0_before ⊑ t0_after

theorem test_sext_zext_proof : test_sext_zext_before ⊑ test_sext_zext_after

theorem xor_sge_thm (e e_1 : IntW 8) :
  icmp IntPred.sge (mul e_1 e_1) (LLVM.xor (LLVM.or e (const? 8 (-128))) (mul e_1 e_1)) ⊑
    icmp IntPred.slt (LLVM.xor (LLVM.or e (const? 8 (-128))) (mul e_1 e_1)) (mul e_1 e_1)

theorem xor_of_icmps_to_ne_thm (e : IntW 64) :
  LLVM.xor (icmp IntPred.sgt e (const? 64 4)) (icmp IntPred.slt e (const? 64 6)) ⊑
    icmp IntPred.ne e (const? 64 5)

theorem t7_thm.extracted_1._2 : ∀ (x : BitVec 8) (x_1 : BitVec 1) (x_2 : BitVec 8), x_1 = 1#1 → x_2 - 0#8 = 0#8 + x_2

theorem e_1232 :
    7 *  ~~~(z ^^^ t) - 3 * (z |||  ~~~t) - 6 * (z ||| t) - 2 *  ~~~(z &&&  ~~~z) - 11 *  ~~~z + 7 * t + 9 *  ~~~(z ||| t) + 12 *  ~~~(z |||  ~~~t) + 13 * (z &&&  ~~~t) = 1 * (z &&& t) + 2 * z

theorem shl_trunc_bigger_shl_thm.extracted_1._1 : ∀ (x : BitVec 32), ¬(4#32 ≥ ↑32 ∨ 2#8 ≥ ↑8) → 6#8 ≥ ↑8 → False

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

theorem xor_andn_commute4_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬(x_1 = 0 ∨ x = 0 ∨ x_1 = 0) →
    ¬(x_1 = 0 ∨ x = 0) → 42#32 / x_1 ^^^ 42#32 / x &&& (42#32 / x_1 ^^^ -1#32) = 42#32 / x_1 ||

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

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

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 masked_icmps_mask_notallzeros_bmask_mixed_negated_4_logical_proof : masked_icmps_mask_notallzeros_bmask_mixed_negated_4_logical_before ⊑ masked_icmps_mask_notallzeros_bmask_mixed_negated_4_logical_after

theorem add_smin_simplify_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬(True ∧ x.saddOverflow (BitVec.ofInt 32 (-3)) = true) →
    ¬ofBool (x + BitVec.ofInt 32 (-3) <ₛ 2147483644#32) = 1#1 → 2147483644#32 = x + BitVec.ofInt 32 (-3)

theorem or_xor_tree_0111_proof : or_xor_tree_0111_before ⊑ or_xor_tree_0111_after

theorem src_srem_shl_demand_max_mask_hit_demand_thm (e : IntW 32) :
  LLVM.and (shl (LLVM.srem e (const? 32 4)) (const? 32 1)) (const? 32 (-4)) ⊑
    LLVM.and (shl (LLVM.srem e (const? 32 4)) (const? 32 1) { «nsw» := true, «nuw» := false }) (const? 32 (-4))

theorem test_proof : test_before ⊑ test_after

theorem negative_not_power_of_two_logical_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬ofBool (-1#32 <ₛ x) = 1#1 → 0#1 = ofBool (x == 0#32)

theorem e_2434 :
    1 * (d ||| f) - 2 *  ~~~(d ||| f) - 7 * (f &&&  ~~~(d &&&  ~~~e)) + 5 * (f ^^^  ~~~( ~~~d &&& (e &&& f))) + 1 * ((d &&& e) ^^^  ~~~(d ^^^ ( ~~~e ||| f))) - 7 * ( ~~~(d ^^^ e) &&& (d ^^^ f)) + 7 * (f ^^^  ~~~(d ||| (e &&& f))) - 7 * ( ~~~(d &&&  ~~~e) &&& (e ^^^ f)) - 2 * (e ^^^  ~~~( ~~~d ||| (e &&& f))) - 11 *  ~~~(d &&&  ~~~e) - 3 * (d &&&  ~~~e) + 1 * (e ^^^  ~~~(d &&& ( ~~~e ||| f))) - 5 * (e ^^^  ~~~(d ||| (e &&& f))) + 1 * ((e &&& f) ^^^  ~~~( ~~~d &&& (e ^^^ f))) + 2 * (f &&&  ~~~(d ^^^ e)) - 1 * ((e &&&  ~~~f) ^^^ (d ||| (e ^^^ f))) + 4 *  ~~~(d ^^^ (e &&& f)) - 3 * (e ^^^ (d ||| f)) + 11 * (d |||  ~~~e) + 1 * ((d &&& e) ^^^  ~~~(d ^^^ (e &&& f))) - 7 * ( ~~~(d &&& e) &&& (d ^^^ (e ^^^ f))) - 1 * ( ~~~(d ||| e) ||| (d ^^^ (e ^^^ f))) - 2 * (f ^^^  ~~~(d &&& (e &&& f))) - 5 * (e ^^^ (d ||| ( ~~~e ||| f))) + 3 * (d ||| ( ~~~e &&& f)) + 4 *  ~~~( ~~~d &&& (e ^^^ f)) + 5 * (f ^^^  ~~~(d &&& (e ||| f))) - 6 *  ~~~(d ^^^ (e ^^^ f)) + 11 * (d &&& ( ~~~e ||| f)) + 1 * ( ~~~(d |||  ~~~e) ||| (d ^^^ (e ^^^ f))) + 7 * ((d &&& e) |||  ~~~(e ^^^ f)) + 3 * (e &&& f) - 2 * ((d ||| e) &&&  ~~~(d ^^^ (e ^^^ f))) + 1 * ((d &&& f) |||  ~~~(e ||| f)) - 11 *  ~~~(d ^^^ ( ~~~e ||| f)) - 3 * (d ^^^ e) + 7 * (f ^^^  ~~~(d &&& e)) + 5 *  ~~~( ~~~d ||| ( ~~~e &&& f)) - 1 * (e ^^^  ~~~( ~~~d ||| (e ^^^ f))) + 2 *  ~~~( ~~~d &&& ( ~~~e &&& f)) - 1 * (f ^^^ ( ~~~d ||| (e ||| f))) + 2 * (d &&& (e ^^^ f)) - 1 * ( ~~~(d ^^^ e) |||  ~~~(d ^^^ f)) - 5 * ( ~~~f &&&  ~~~(d ^^^ e)) - 7 * (f ^^^  ~~~(d |||  ~~~e)) - 1 * (e ^^^  ~~~(d &&& (e ^^^ f))) + 11 * ((d |||  ~~~e) &&&  ~~~(d ^^^ (e ^^^ f))) + 4 * (e ^^^  ~~~(d |||  ~~~f)) + 3 * (d ||| ( ~~~e ||| f)) + 1 * ( ~~~(d ||| e) ||| (e ^^^ f)) + 11 *  ~~~(e |||  ~~~f) + 7 * (e ^^^  ~~~(d &&& ( ~~~e &&& f))) + 2 *  ~~~(d &&&  ~~~d) - 2 * (e ^^^  ~~~(d ||| f)) - 1 * e + 2 *  ~~~(d &&& f) - 5 * ( ~~~(d &&& e) &&& (e ^^^ f)) - 6 * ((e &&& f) ||| (d &&& (e ||| f))) + 1 *  ~~~(e &&& f) + 2 * (e &&&  ~~~(d &&& f)) - 2 * (e ^^^ (d ||| ( ~~~e &&& f))) - 11 * (e |||  ~~~f) + 5 *  ~~~(d &&& (e ^^^ f)) - 1 * d + 1 * (f ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) + 7 * ((d &&& f) ||| (e &&&  ~~~f)) + 1 * ((d &&& f) ^^^ (d ^^^ ( ~~~e &&& f))) + 1 * (d ||| (e &&& f)) - 29 *  ~~~(d ||| (e ||| f)) + 25 *  ~~~(d ||| ( ~~~e ||| f)) - 33 *  ~~~( ~~~d ||| (e ||| f)) - 8 *  ~~~( ~~~d ||| ( ~~~e ||| f)) + 15 * ( ~~~d &&& ( ~~~e &&& f)) + 13 * ( ~~~d &&& (e &&& f)) - 23 * (d &&& ( ~~~e &&& f)) - 27 * (d &&& (e &&& f)) = 1 * (d ^^^ ( ~~~e &&& f)) + 6 * (e ^^^ ( ~~~d ||| (e ||| f)))

theorem tryFactorization_xor_ashr_ashr_thm (e : IntW 32) :
  LLVM.xor (ashr (const? 32 (-3)) e) (ashr (const? 32 (-5)) e) ⊑ lshr (const? 32 6) e

theorem or_eq_with_one_bit_diff_constants1_logical_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬ofBool (x == 50#32) = 1#1 → ofBool (x == 51#32) = ofBool (x &&& BitVec.ofInt 32 (-2) == 50#32)

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

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

theorem foo1_and_commuted_thm.extracted_1._2 : ∀ (x x_1 x_2 : BitVec 32),
  ¬(x_1 ≥ ↑32 ∨ x ≥ ↑32) →
    ¬(True ∧ 1#32 <<< x_1 >>> x_1 ≠ 1#32 ∨
          x_1 ≥ ↑32 ∨
            True ∧ 1#32 <<< x >>> x ≠ 1#32 ∨
              x ≥ ↑32 ∨ True ∧ 1#32 <<< x_1 >>> x_1 ≠ 1#32 ∨ x_1 ≥ ↑32 ∨ True ∧ 1#32 <<< x >>> x ≠ 1#32 ∨ x ≥ ↑32) →
      ofBool (x_2 * x_2 &&& 1#32 <<< x_1 == 0#32) ||

theorem ashr_mul_thm.extracted_1._2 : ∀ (x x_1 : BitVec 8),
  ¬8#20 ≥ ↑20 →
    ¬(True ∧ (signExtend 16 x_1).smulOverflow (signExtend 16 x) = true ∨ 8#16 ≥ ↑16) →
      truncate 16 ((signExtend 20 x_1 * signExtend 20 x).sshiftRight' 8#20) =
        (signExtend 16 x_1 * signExtend 16 x).sshiftRight' 8#16

theorem lshrult_02_04_exact_proof : lshrult_02_04_exact_before ⊑ lshrult_02_04_exact_after

theorem test_srem_canonicalize_op0_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ¬(True ∧ (0#32).ssubOverflow x_1 = true ∨ (x == 0 || 32 != 1 && 0#32 - x_1 == intMin 32 && x == -1) = true) →
    (x == 0 || 32 != 1 && x_1 == intMin 32 && x == -1) = true ∨ True ∧ (0#32).ssubOverflow (x_1.srem x) = true →
      False

theorem signExtend_eq (x : BitVec w) : x.signExtend w = x  := sorry

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

theorem or_signbit_select_lshr_thm.extracted_1._1 : ∀ (x : BitVec 32) (x_1 : BitVec 1),
  x_1 = 1#1 → ¬8#32 ≥ ↑32 → (x ||| BitVec.ofInt 32 (-65536)) >>> 8#32 = x >>> 8#32 ||

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

@[simp]
theorem BitVec.intCast_eq_ofInt : ((i : Int) : BitVec w) = BitVec.ofInt w i

theorem positive_samevar_shlnsw_thm.extracted_1._2 : ∀ (x x_1 : BitVec 8),
  ¬(x ≥ ↑8 ∨ True ∧ (x_1.sshiftRight' x <<< x).sshiftRight' x ≠ x_1.sshiftRight' x ∨ x ≥ ↑8) →
    ¬(True ∧ ((-1#8) <<< x).sshiftRight' x ≠ -1#8 ∨ x ≥ ↑8) → x_1.sshiftRight' x <<< x = (-1#8) <<< x &&& x_1

theorem test23_proof : test23_before ⊑ test23_after

theorem and_not_or_proof : and_not_or_before ⊑ and_not_or_after

theorem e_1808 :
    5 *  ~~~(a ^^^ b) + 3 * (b ^^^  ~~~(a &&& ( ~~~b ||| c))) - 2 * ((a ^^^ b) ||| (a ^^^ c)) + 5 * ((a ||| b) &&& (b ^^^ c)) - 1 * (a ||| c) + 1 * (c |||  ~~~(a ||| b)) - 7 * (a ||| (b ^^^ c)) - 2 * (a &&&  ~~~b) - 1 * ((a &&& c) ^^^ (a ^^^ ( ~~~b &&& c))) - 7 * ( ~~~(a &&&  ~~~b) &&&  ~~~(a ^^^ (b ^^^ c))) + 1 *  ~~~(a &&&  ~~~a) - 11 * ((a &&& b) |||  ~~~(b ||| c)) - 2 * (b ||| (a &&&  ~~~c)) + 7 * (c ^^^ (a ||| (b &&& c))) - 2 *  ~~~(a ^^^ (b ^^^ c)) - 1 * (c ^^^ (a ||| ( ~~~b ||| c))) - 2 * (b ^^^ (a ||| c)) + 5 * ( ~~~c &&&  ~~~(a ^^^ b)) - 3 * (b ^^^  ~~~( ~~~a ||| (b ^^^ c))) - 1 * ((a &&&  ~~~b) |||  ~~~(a ^^^ (b ^^^ c))) + 1 * ((a ||| b) &&&  ~~~(b ^^^ c)) - 2 * (b ^^^ ( ~~~a ||| (b &&& c))) + 2 * (a |||  ~~~b) - 1 * (c ^^^  ~~~(a &&& ( ~~~b &&& c))) + 1 * (b ^^^ (a &&& (b ||| c))) - 3 * (c ^^^  ~~~(a &&& (b ||| c))) - 1 * ( ~~~(a ^^^ b) ||| (a ^^^ c)) - 7 * ((a ^^^ b) &&&  ~~~(a ^^^ c)) + 1 *  ~~~( ~~~a &&& (b ^^^ c)) - 3 * (c ||| (a &&& b)) + 1 * (b ^^^ (a &&&  ~~~c)) - 2 * ((a &&& c) |||  ~~~(b ||| c)) - 2 * (b ^^^ ( ~~~a &&& (b ^^^ c))) - 5 * (b ^^^ (a ||| (b ^^^ c))) + 13 *  ~~~(a ||| (b ||| c)) + 19 *  ~~~(a ||| ( ~~~b ||| c)) + 32 *  ~~~( ~~~a ||| (b ||| c)) + 21 *  ~~~( ~~~a ||| ( ~~~b ||| c)) + 23 * ( ~~~a &&& (b &&& c)) + 28 * (a &&& ( ~~~b &&& c)) + 17 * (a &&& (b &&& c)) =  - 7 * ( ~~~a &&& ( ~~~b &&& c))

theorem shl_add_log_may_cause_poison_pr62175_with_nuw_proof : shl_add_log_may_cause_poison_pr62175_with_nuw_before ⊑ shl_add_log_may_cause_poison_pr62175_with_nuw_after

theorem test_shl_nuw_nsw__none_are_safe_thm.extracted_1._3 : ∀ (x : BitVec 64) (x_1 : BitVec 32),
  ¬ofBool (x_1 &&& BitVec.ofInt 32 (-2) == 0#32) = 1#1 →
    ¬(True ∧ ((x_1 &&& BitVec.ofInt 32 (-2)) <<< 2#32).sshiftRight' 2#32 ≠ x_1 &&& BitVec.ofInt 32 (-2) ∨
          True ∧ (x_1 &&& BitVec.ofInt 32 (-2)) <<< 2#32 >>> 2#32 ≠ x_1 &&& BitVec.ofInt 32 (-2) ∨
            2#32 ≥ ↑32 ∨ zeroExtend 64 ((x_1 &&& BitVec.ofInt 32 (-2)) <<< 2#32) ≥ ↑64) →
      2#32 ≥ ↑32 ∨
          True ∧ (x_1 <<< 2#32 &&& BitVec.ofInt 32 (-8)).msb = true ∨
            zeroExtend 64 (x_1 <<< 2#32 &&& BitVec.ofInt 32 (-8)) ≥ ↑64 →
        False

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

theorem uge_or_max_commute_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ofBool (x_1 == -1#8) ||

theorem and_logic_and_logic_or_3_thm.extracted_1._5 : ∀ (x x_1 x_2 : BitVec 1),
  ¬x_2 &&& x_1 = 1#1 → x_1 = 1#1 → x_2 = 1#1 → x = 1#1

theorem e_2194 :
     - 3 * ((d &&& e) ^^^ (d ^^^ ( ~~~e ||| f))) + 11 * (f ^^^ (d ||| (e &&& f))) + 3 * (d &&& ( ~~~e ||| f)) + 2 * (d ^^^ (e &&& f)) - 11 *  ~~~(d |||  ~~~e) - 2 * ((d &&& e) ||| (e ^^^ f)) - 5 * (e ^^^ (d &&& (e ||| f))) - 1 * ( ~~~e ||| (d ^^^ f)) + 2 * (e &&&  ~~~(d &&& f)) - 7 * (f ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) + 5 * (d ||| e) - 2 * d + 2 * (e ^^^ ( ~~~d ||| ( ~~~e &&& f))) + 2 * (e ^^^ (d ||| ( ~~~e ||| f))) + 3 * e - 1 * (e |||  ~~~(d |||  ~~~f)) + 1 * (e ||| (d &&&  ~~~f)) - 7 * (e ^^^  ~~~(d &&&  ~~~f)) - 11 * (f ^^^ (d ||| e)) - 7 * ( ~~~d &&& ( ~~~e ||| f)) + 1 * (e ^^^ (d &&& ( ~~~e ||| f))) - 5 * (e ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) - 3 * (f ^^^ (d &&& e)) - 2 * (f &&& (d ^^^ e)) + 11 * (e ^^^ (d &&& f)) - 1 * f - 6 * (e ^^^ (d ||| (e &&& f))) + 1 * (e ^^^  ~~~(d &&& ( ~~~e ||| f))) + 4 *  ~~~(d &&&  ~~~e) + 1 * ( ~~~(d &&& e) &&& (e ^^^ f)) - 6 * ((d &&& e) ^^^ (e |||  ~~~f)) + 2 * (e |||  ~~~(d ||| f)) + 1 * ((d &&& f) ^^^  ~~~(d ^^^ ( ~~~e &&& f))) + 7 * ((e &&&  ~~~f) ^^^ ( ~~~d ||| (e ^^^ f))) + 1 *  ~~~(d ^^^ (e ||| f)) + 1 *  ~~~(e ^^^ f) + 3 * (e ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) - 11 * (e &&&  ~~~(d ^^^ f)) - 6 * (f ^^^ ( ~~~d ||| ( ~~~e ||| f))) + 1 * (d ^^^ ( ~~~e ||| f)) + 1 * ( ~~~(d &&&  ~~~e) &&&  ~~~(e ^^^ f)) - 11 * ( ~~~(d ^^^ e) &&& (d ^^^ f)) + 1 * (f ^^^  ~~~(d ||| (e &&& f))) + 13 *  ~~~(d ||| (e ||| f)) + 34 *  ~~~(d ||| ( ~~~e ||| f)) + 20 *  ~~~( ~~~d ||| (e ||| f)) - 1 *  ~~~( ~~~d ||| ( ~~~e ||| f)) + 30 * ( ~~~d &&& ( ~~~e &&& f)) + 3 * ( ~~~d &&& (e &&& f)) + 2 * (d &&& ( ~~~e &&& f)) - 1 * (d &&& (e &&& f)) = 2 *  ~~~(d ^^^ ( ~~~e &&& f)) + 5 * ((e &&&  ~~~f) ^^^ (d ||| (e ^^^ f)))

theorem no_shift_xor_multiuse_cmp_thm (e e_1 e_2 e_3 : IntW 32) :
  mul (select (icmp IntPred.ne (const? 32 0) (LLVM.and e_3 (const? 32 4096))) e_2 (LLVM.or e_2 (const? 32 4096)))
      (select (icmp IntPred.ne (const? 32 0) (LLVM.and e_3 (const? 32 4096))) e_1 e) ⊑
    mul (LLVM.or e_2 (LLVM.xor (LLVM.and e_3 (const? 32 4096)) (const? 32 4096)))
      (select (icmp IntPred.eq (LLVM.and e_3 (const? 32 4096)) (const? 32 0)) e e_1)

theorem lor_land_right2_proof : lor_land_right2_before ⊑ lor_land_right2_after

theorem main14_logical_thm (e : IntW 32) :
  select
      (select (icmp IntPred.sge (trunc 16 e) (const? 16 0)) (icmp IntPred.sge (trunc 8 e) (const? 8 0))
        (const? 1 0))
      (const? 32 2) (const? 32 1) ⊑
    select (icmp IntPred.eq (LLVM.and e (const? 32 32896)) (const? 32 0)) (const? 32 2) (const? 32 1)

theorem e_661 :
     - 1 *  ~~~y + 5 *  ~~~(x &&& y) + 11 * x + 1 *  ~~~(x &&&  ~~~x) - 5 * y - 2 *  ~~~x + 1 * (x ||| y) - 1 *  ~~~(x ||| y) - 17 * (x &&&  ~~~y) - 6 * (x &&& y) = 2 *  ~~~(x ^^^ y)

@[simp]
theorem Factor.denote_width_zero  (f : Factor) (env : Env 0) : f.denote env = 0

theorem lshrugt_02_14_exact_proof : lshrugt_02_14_exact_before ⊑ lshrugt_02_14_exact_after

theorem sext_sub_proof : sext_sub_before ⊑ sext_sub_after
</all_available_lemmas>

<local_ctx>
import Batteries.Data.Fin.Basic

import Batteries.Data.Fin.Lemmas

import Blase.SingleWidth.Defs

import Blase.AutoStructs.Constructions

import Blase.AutoStructs.Defs

import Blase.AutoStructs.FiniteStateMachine

import Mathlib.Tactic.Ring

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

import Mathlib.Data.BitVec

import Mathlib.Tactic.FinCases

open Fin.NatCast

open Mathlib

section fsm

abbrev Alphabet (arity: Type) [FinEnum arity] := BitVec (FinEnum.card arity + 1)

variable {arity : Type} [FinEnum arity]

def finFunToBitVec [fe : FinEnum carry] (c : carry → Bool) : BitVec (FinEnum.card carry) :=
  BitVec.ofFn fun i => c (fe.equiv.invFun i)

def bitVecToFinFun [FinEnum ar] (bv : BitVec $ FinEnum.card ar) : ar → Bool :=
  fun c => bv[FinEnum.equiv.toFun c]

def NFA.ofFSM (p : FSM arity) : NFA (Alphabet arity) (p.α → Bool) where
  start := { q | q = p.initCarry }
  accept := ⊤
  step s a := {s' |
    let (s'', b) := p.nextBit s (bitVecToFinFun (a.truncate $ FinEnum.card arity))
    s' = s'' ∧ a.msb = b }

open BitStream in

def CNFA.ofFSM (p : FSM arity) : CNFA (FinEnum.card arity + 1) :=
  worklistRun (BitVec (FinEnum.card p.α))
    (fun _ => true)
    #[finFunToBitVec p.initCarry]
    (by admit /- proof elided -/
    )
    f
  where
</local_ctx>

<target_theorem>
@[simp]
lemma CNFA.ofFSM.f_spec {p : FSM arity} {s s' : BitVec (FinEnum.card p.α)} :
    (a, s') ∈ f p s ↔ bitVecToFinFun s' ∈ (NFA.ofFSM p).step (bitVecToFinFun s) a :=
</target_theorem>

