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
Vector in Init.Data.Vector.Basic
Fin in Init.Prelude
String in Init.Prelude
Unit in Init.Prelude
List in Init.Prelude
Field in Mathlib.Algebra.Field.Defs
Bool in Init.Prelude
DecidableEq in Init.Prelude
FinEnum in Mathlib.Data.FinEnum
Hashable in Init.Prelude
input in Leanwuzla.Basic
Fintype in Mathlib.Data.Fintype.Defs
FinEnum.toList in Mathlib.Data.FinEnum
List.range in Init.Data.List.Basic
Bool.xor in Init.Data.Bool
Vector.mapM in Init.Data.Vector.Basic
Subtype in Init.Prelude

def Vars.inputN (inp : ι) (k : Nat) {n : Nat} (hkn : k < n := by admit /- proof elided -/
) : Vars σ ι n :=
  .inputs (Inputs.mk ⟨k, by admit /- proof elided -/
  ⟩ inp)

inductive Vars (σ : Type) (ι : Type) (n : Nat)
| state (s : Inputs σ (n + 1))
| inputs (is : Inputs ι n)
| outputs (os : Fin n) 
deriving DecidableEq, Hashable

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 }

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

def Vars.stateN (s : σ) (i : Nat) {n : Nat} (hin : i ≤ n := by admit /- proof elided -/
) : Vars σ ι n :=
  .state (Inputs.mk ⟨i, by admit /- proof elided -/
  ⟩ s)

structure Inputs (ι : Type) (n : Nat) : Type  where
  ix : Fin n
  input : ι
deriving DecidableEq, Hashable

def Vars.state0 (s : σ) {n : Nat} : Vars σ ι n :=
  .state (Inputs.mk ⟨0, by admit /- proof elided -/
  ⟩ s)

def bigOr {α : Type _}
    (cs : List (Circuit α)) : Circuit α :=
  match cs with
  | [] => Circuit.fals
  | c :: cs =>
    c ||| (Circuit.bigOr cs)

def bigAnd {α : Type _}
    (cs : List (Circuit α)) : Circuit α :=
  match cs with
  | [] => Circuit.tru
  | c :: cs =>
    c &&& (Circuit.bigAnd cs)

@[simp]
def eval : Circuit α → (α → Bool) → Bool
  | tru, _ => true
  | fals, _ => false
  | var b x, f => if b then f x else !(f x)
  | and c₁ c₂, f => (eval c₁ f) && (eval c₂ f)
  | or c₁ c₂, f => (eval c₁ f) || (eval c₂ f)
  | xor c₁ c₂, f => Bool.xor (eval c₁ f) (eval c₂ f)

def map : ∀ (_c : Circuit α) (_f : α → β), Circuit β
  | tru, _ => tru
  | fals, _ => fals
  | var b x, f => var b (f x)
  | and c₁ c₂, f => (map c₁ f) &&& (map c₂ f)
  | or c₁ c₂, f => (map c₁ f) ||| (map c₂ f)
  | xor c₁ c₂, f => (map c₁ f) ^^^ (map c₂ f)

def Vars.castLe {n m : Nat} (v : Vars σ ι n) (hnm : n ≤ m) : Vars σ ι m :=
  match v with
  | .state ss => .state (ss.castLe (by admit /- proof elided -/
  ))
  | .inputs is => .inputs (is.castLe hnm)
  | .outputs os =>
    .outputs (os.castLE (by admit /- proof elided -/
    ))

def castLe (i : Inputs ι n) (hn : n ≤ m) : Inputs ι m where
  ix := ⟨i.ix, by admit /- proof elided -/
  ⟩
  input := i.input

def trunc_lshr_before := [llvm|
{
^0(%arg10 : i8):
  %0 = llvm.mlir.constant(2 : i8) : i8
  %1 = llvm.mlir.constant(14 : i6) : i6
  %2 = llvm.lshr %arg10, %0 : i8
  %3 = llvm.trunc %2 : i8 to i6
  %4 = llvm.and %3, %1 : i6
  "llvm.return"(%4) : (i6) -> ()
}
]

def emptyElim {α : Sort _} {t : Ty} : Ctxt.Var ∅ t → α :=
  fun ⟨_, h⟩ => by admit /- proof elided -/

def ashr_32_add_zext_basic_before := [llvm|
{
^0(%arg9 : i32, %arg10 : i32):
  %0 = llvm.mlir.constant(32) : i64
  %1 = llvm.zext %arg9 : i32 to i64
  %2 = llvm.zext %arg10 : i32 to i64
  %3 = llvm.add %1, %2 : i64
  %4 = llvm.ashr %3, %0 : i64
  "llvm.return"(%4) : (i64) -> ()
}
]

def masked_icmps_mask_notallzeros_bmask_mixed_swapped_1_after := [llvm|
{
^0(%arg50 : i32):
  %0 = llvm.mlir.constant(15 : i32) : i32
  %1 = llvm.mlir.constant(9 : i32) : i32
  %2 = llvm.and %arg50, %0 : i32
  %3 = llvm.icmp "eq" %2, %1 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

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

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

def test_sdiv_canonicalize_op0_exact_before := [llvm|
{
^0(%arg13 : i32, %arg14 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.sub %0, %arg13 overflow<nsw> : i32
  %2 = llvm.sdiv exact %1, %arg14 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

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

def and_orn_cmp_1_logical_after := [llvm|
{
^0(%arg128 : i32, %arg129 : i32, %arg130 : i1):
  %0 = llvm.mlir.constant(false) : i1
  %1 = llvm.icmp "sgt" %arg128, %arg129 : i32
  %2 = "llvm.select"(%1, %arg130, %0) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%2) : (i1) -> ()
}
]

BitVec.sdiv in Init.Data.BitVec.Basic

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 badimm1_before := [llvm|
{
^0(%arg28 : i16):
  %0 = llvm.mlir.constant(9 : i16) : i16
  %1 = llvm.mlir.constant(7 : i8) : i8
  %2 = llvm.mlir.constant(15 : i16) : i16
  %3 = llvm.mlir.constant(127 : i8) : i8
  %4 = llvm.lshr %arg28, %0 : i16
  %5 = llvm.trunc %4 : i16 to i8
  %6 = llvm.trunc %arg28 : i16 to i8
  %7 = llvm.ashr %6, %1 : i8
  %8 = llvm.icmp "eq" %7, %5 : i8
  %9 = llvm.ashr %arg28, %2 : i16
  %10 = llvm.trunc %9 : i16 to i8
  %11 = llvm.xor %10, %3 : i8
  %12 = "llvm.select"(%8, %6, %11) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  "llvm.return"(%12) : (i8) -> ()
}
]

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

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

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

def test28_after := [llvm|
{
^0(%arg45 : i32):
  %0 = llvm.mlir.constant(2147483647 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.and %arg45, %0 : i32
  %3 = llvm.icmp "eq" %2, %1 : i32
  "llvm.return"(%3) : (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 shrink_xor_after := [llvm|
{
^0(%arg13 : i64):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.trunc %arg13 : i64 to i32
  %2 = llvm.xor %1, %0 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def uadd_sat_flipped_wrong_bounds6_after := [llvm|
{
^0(%arg91 : 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" %arg91, %0 : i32
  %4 = llvm.add %arg91, %1 : i32
  %5 = "llvm.select"(%3, %4, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%5) : (i32) -> ()
}
]

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 n2_badmask_after := [llvm|
{
^0(%arg4 : i32, %arg5 : i32, %arg6 : i32, %arg7 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.and %arg6, %arg4 : i32
  %2 = llvm.xor %arg7, %0 : i32
  %3 = llvm.and %arg5, %2 : i32
  %4 = llvm.add %1, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

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

def test11_before := [llvm|
{
^0(%arg69 : i32, %arg70 : i32):
  %0 = llvm.mlir.constant(31 : i128) : i128
  %1 = llvm.zext %arg69 : i32 to i128
  %2 = llvm.zext %arg70 : i32 to i128
  %3 = llvm.and %2, %0 : i128
  %4 = llvm.shl %1, %3 : i128
  %5 = llvm.trunc %4 : i128 to i64
  "llvm.return"(%5) : (i64) -> ()
}
]

def shl_lshr_pow2_const_negative_overflow2_before := [llvm|
{
^0(%arg69 : i16):
  %0 = llvm.mlir.constant(8 : i16) : i16
  %1 = llvm.mlir.constant(6 : i16) : i16
  %2 = llvm.mlir.constant(-32768 : i16) : i16
  %3 = llvm.shl %0, %arg69 : i16
  %4 = llvm.lshr %3, %1 : i16
  %5 = llvm.and %4, %2 : i16
  "llvm.return"(%5) : (i16) -> ()
}
]

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_ugt_after := [llvm|
{
^0(%arg41 : i32, %arg42 : i32):
  %0 = llvm.mlir.constant(false) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def test_and_ne_a_b_commuted_before := [llvm|
{
^0(%arg27 : i1, %arg28 : i8, %arg29 : i8):
  %0 = llvm.icmp "ne" %arg28, %arg29 : i8
  %1 = llvm.and %arg27, %0 : i1
  %2 = "llvm.select"(%1, %arg29, %arg28) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def test_add_sub_const_lhs_LHS := [mod_arith q, hq| {
  ^bb0(%x : !R):
    %c0 = mod_arith.constant 12 : !R
    %c1 = mod_arith.constant 34 : !R
    %sub = mod_arith.sub %c0, %x : !R
    %add = mod_arith.add %sub, %c1 : !R
    return %add : !R
}]

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

def mul_select_sext_after := [llvm|
{
^0(%arg17 : i1):
  %0 = llvm.mlir.constant(-64) : i64
  %1 = llvm.mlir.constant(0) : i64
  %2 = "llvm.select"(%arg17, %0, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i64, i64) -> i64
  "llvm.return"(%2) : (i64) -> ()
}
]

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

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

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

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

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

def test_and2_after := [llvm|
{
^0(%arg48 : i32, %arg49 : i32):
  %0 = llvm.mlir.constant(2147483647 : i32) : i32
  %1 = llvm.and %arg49, %0 : i32
  %2 = llvm.icmp "ule" %arg48, %1 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

def exactly_one_set_signbit_wrong_pred_before := [llvm|
{
^0(%arg28 : i8, %arg29 : i8):
  %0 = llvm.mlir.constant(7 : i8) : i8
  %1 = llvm.mlir.constant(-1 : i8) : i8
  %2 = llvm.lshr %arg28, %0 : i8
  %3 = llvm.icmp "sgt" %arg29, %1 : i8
  %4 = llvm.zext %3 : i1 to i8
  %5 = llvm.icmp "sgt" %2, %4 : i8
  "llvm.return"(%5) : (i1) -> ()
}
]

def sgt_mulzero_after := [llvm|
{
^0(%arg144 : i8):
  %0 = llvm.mlir.constant(false) : i1
  "llvm.return"(%0) : (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 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 alive_AndOrXor_2263_tgt :=
[sllvm| {
^bb0(%B : i64, %op0 : i64):
  %v1 = llvm.xor %op0, %B : i64
  %v2 = llvm.or %op0, %B : i64
  llvm.return %v2 : i64
}]

def PR42691_6_before := [llvm|
{
^0(%arg333 : i32):
  %0 = llvm.mlir.constant(-2147483647 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.icmp "ult" %arg333, %0 : i32
  %3 = llvm.icmp "eq" %arg333, %1 : i32
  %4 = llvm.or %2, %3 : i1
  "llvm.return"(%4) : (i1) -> ()
}
]

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

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

def ashrsgt_02_05_exact_before := [llvm|
{
^0(%arg80 : i4):
  %0 = llvm.mlir.constant(2 : i4) : i4
  %1 = llvm.mlir.constant(5 : i4) : i4
  %2 = llvm.ashr exact %arg80, %0 : i4
  %3 = llvm.icmp "sgt" %2, %1 : i4
  "llvm.return"(%3) : (i1) -> ()
}
]

def or_lshr_after := [llvm|
{
^0(%arg628 : i8, %arg629 : i8, %arg630 : i8, %arg631 : i8):
  %0 = llvm.or %arg628, %arg629 : i8
  %1 = llvm.lshr %0, %arg631 : i8
  %2 = llvm.or %1, %arg630 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def test1_before := [llvm|
{
^0(%arg3 : i33):
  %0 = llvm.mlir.constant(4096 : i33) : i33
  %1 = llvm.urem %arg3, %0 : i33
  "llvm.return"(%1) : (i33) -> ()
}
]

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

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

def shiftLeft (op1 : GenBVExpr w) (op2: GenBVExpr w) : GenBVExpr w :=
  GenBVExpr.shiftLeft op1 op2

def andn_or_cmp_4_logical_before := [llvm|
{
^0(%arg158 : i32, %arg159 : i32, %arg160 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mlir.constant(true) : i1
  %2 = llvm.mlir.constant(false) : i1
  %3 = llvm.icmp "eq" %arg158, %arg159 : i32
  %4 = llvm.icmp "ne" %arg158, %arg159 : i32
  %5 = llvm.icmp "ugt" %arg160, %0 : i32
  %6 = "llvm.select"(%3, %1, %5) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %7 = "llvm.select"(%6, %4, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%7) : (i1) -> ()
}
]

def select_xor_icmp_meta_before := [llvm|
{
^0(%arg287 : i32, %arg288 : i32, %arg289 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.icmp "eq" %arg287, %0 : i32
  %2 = llvm.xor %arg287, %arg289 : i32
  %3 = "llvm.select"(%1, %2, %arg288) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def eq_optimized_highbits_cmp_before := [llvm|
{
^0(%arg26 : i32, %arg27 : i32):
  %0 = llvm.mlir.constant(33554432 : i32) : i32
  %1 = llvm.xor %arg27, %arg26 : i32
  %2 = llvm.icmp "ult" %1, %0 : i32
  %3 = llvm.trunc %arg26 : i32 to i25
  %4 = llvm.trunc %arg27 : i32 to i25
  %5 = llvm.icmp "eq" %3, %4 : i25
  %6 = llvm.and %2, %5 : i1
  "llvm.return"(%6) : (i1) -> ()
}
]

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

<all_available_lemmas>
List.mem_attach in Init.Data.List.Attach
List.mem_map in Init.Data.List.Lemmas
List.mem_range in Init.Data.List.Nat.Range
forall_exists_index in Init.PropLemmas
true_and in Init.SimpLemmas

lemma eval_map {c : Circuit α} {f : α → β} {g : β → Bool} :
    eval (map c f) g = eval c (λ x => g (f x))

@[simp]
theorem eval_bigOr_eq_false_iff
    (cs : List (Circuit α)) (env : α → Bool):
    (Circuit.bigOr cs).eval env = false ↔
    (∀ (c : Circuit α), c ∈ cs → c.eval env = false)

@[simp]
theorem Vars.castLe_inputs_eq_inputs {n i m : Nat} (hi : i < n) (hnm : n ≤ m) :
  (Vars.inputN inp i hi : Vars σ ι n).castLe hnm =
  Vars.inputN inp i (by omega)

@[simp]
theorem Vars.castLe_stateN_eq_stateN  {n i m : Nat} (hi : i ≤ n) (hnm : n ≤ m) :
  (Vars.stateN s i : Vars σ ι n).castLe hnm =
  Vars.stateN s i (hin := by omega)

@[simp]
theorem Vars.castLe_castLe_eq_castLe_self {α : Type _} {p q r : Nat}
  (v : Vars α σ p) (h : p ≤ q) (h' : q ≤ r) :
    (v.castLe h).castLe h' = v.castLe (by omega)

theorem t5_ugt_slt_0_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬ofBool (65535#32 <ᵤ x) = 1#1 → ofBool (65535#32 <ₛ x) = 1#1 ∨ ofBool (x <ₛ 0#32) = 1#1 → False

theorem e_507 :
     - 6 * x - 1 *  ~~~(x ^^^ y) - 2 * (x ^^^ y) + 1 * (x ||| y) - 2 *  ~~~y + 8 *  ~~~(x ||| y) + 5 *  ~~~(x |||  ~~~y) + 9 * (x &&&  ~~~y) + 5 * (x &&& y) = 5 *  ~~~x - 1 * y

theorem shl_trunc_bigger_ashr_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬(12#32 ≥ ↑32 ∨ 3#24 ≥ ↑24) →
    9#32 ≥ ↑32 ∨ True ∧ signExtend 32 (truncate 24 (x.sshiftRight' 9#32)) ≠ x.sshiftRight' 9#32 → False

theorem test3_proof : test3_before ⊑ test3_after

theorem not_or_or_and_not_and_and_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_1 e_2) e) (const? 32 (-1))) ⊑
    LLVM.or (LLVM.xor e e_1) (LLVM.xor e_2 (const? 32 (-1)))

theorem ashrslt_02_02_exact_proof : ashrslt_02_02_exact_before ⊑ ashrslt_02_02_exact_after

theorem ashrsgt_01_10_thm.extracted_1._1 : ∀ (x : BitVec 4),
  ¬1#4 ≥ ↑4 → ofBool (BitVec.ofInt 4 (-6) <ₛ x.sshiftRight' 1#4) = 1#1

theorem AvoidCollision_getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
    (x.setWidth m)[i]? = if i < m then some (x.getLsbD i) else none

theorem samesign_commute2_thm (e e_1 : IntW 32) :
  LLVM.or (icmp IntPred.slt (LLVM.and e_1 e) (const? 32 0))
      (icmp IntPred.sgt (LLVM.or e e_1) (const? 32 (-1))) ⊑
    icmp IntPred.sgt (LLVM.xor e_1 e) (const? 32 (-1))

theorem test_lshr_exact__exact_is_unsafe_thm.extracted_1._2 : ∀ (x : BitVec 64) (x_1 : BitVec 32),
  ofBool (x_1 &&& 63#32 == 0#32) = 1#1 →
    ¬(2#32 ≥ ↑32 ∨ True ∧ (x_1 >>> 2#32 &&& 15#32).msb = true ∨ zeroExtend 64 (x_1 >>> 2#32 &&& 15#32) ≥ ↑64) →
      x = x.sshiftRight' (zeroExtend 64 (x_1 >>> 2#32 &&& 15#32))

theorem uge_swap_or_max_logical_thm (e e_1 : IntW 8) :
  select (icmp IntPred.ule e_1 e) (const? 1 1) (icmp IntPred.eq e (const? 8 (-1))) ⊑
    icmp IntPred.ule e_1 e

@[simp] theorem Com.denoteLets_var (e : Expr d Γ eff t) (body : Com d _ eff u) [LawfulMonad d.m] :
    (Com.var e body).denoteLets =
        fun V => e.denote V >>= body.denoteLets

theorem shl_add_lshr_thm.extracted_1._2 : ∀ (x x_1 x_2 : BitVec 32),
  ¬(True ∧ x_2 <<< x_1 >>> x_1 ≠ x_2 ∨ x_1 ≥ ↑32 ∨ True ∧ (x_2 <<< x_1).uaddOverflow x = true ∨ x_1 ≥ ↑32) →
    ¬(x_1 ≥ ↑32 ∨ True ∧ (x >>> x_1).uaddOverflow x_2 = true) → (x_2 <<< x_1 + x) >>> x_1 = x >>> x_1 + x_2

theorem zext_sext_ugt_known_nonneg_proof : zext_sext_ugt_known_nonneg_before ⊑ zext_sext_ugt_known_nonneg_after

theorem e_106 :
    3 *  ~~~x - 1 * y + 11 * (x ||| y) - 14 *  ~~~(x |||  ~~~y) - 11 * (x &&&  ~~~y) - 11 * (x &&& y) = 4 *  ~~~(x ||| y) - 1 *  ~~~(x &&&  ~~~y)

theorem band_lor_right1_thm (e e_1 : IntW 1) : select e_1 (const? 1 1) (LLVM.and e_1 e) ⊑ e_1

theorem p_commutative2_proof : p_commutative2_before ⊑ p_commutative2_after

theorem ashr_sle_noexact_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬3#8 ≥ ↑8 → ofBool (x.sshiftRight' 3#8 ≤ₛ 10#8) = ofBool (x <ₛ 88#8)

theorem matchVar_nil {lets : Lets d Γ_in eff Γ_out} :
    matchVar lets v (.nil : Lets d Δ .pure Δ) w ma = some ((), ma') →
    ma'.lookup ⟨_, w⟩ = some v

theorem test47_thm.extracted_1._1 : ∀ (x : BitVec 8),
  zeroExtend 64 (signExtend 32 x ||| 42#32) = zeroExtend 64 (signExtend 32 (x ||| 42#8))

theorem shl_nsw_add_negative_invalid_constant3_proof : shl_nsw_add_negative_invalid_constant3_before ⊑ shl_nsw_add_negative_invalid_constant3_after

theorem icmp_select_implied_cond_proof : icmp_select_implied_cond_before ⊑ icmp_select_implied_cond_after

theorem t1_flags_nuw_only_thm (e e_1 e_2 : IntW 8) :
  sub (sub e_2 e_1 { «nsw» := false, «nuw» := true }) e { «nsw» := false, «nuw» := true } ⊑
    sub e_2 (add e_1 e { «nsw» := false, «nuw» := true }) { «nsw» := false, «nuw» := true }

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

theorem sub_undemanded_low_bits_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬4#32 ≥ ↑32 → ((x ||| 15#32) - 1616#32) >>> 4#32 = (x + BitVec.ofInt 32 (-1616)) >>> 4#32

theorem and_ne_with_one_bit_diff_constants1_logical_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬ofBool (x != 51#32) = 1#1 → 0#1 = ofBool (x + BitVec.ofInt 32 (-52) <ᵤ BitVec.ofInt 32 (-2))

theorem or_and1_thm.extracted_1._8 : ∀ (x x_1 x_2 : BitVec 1),
  ¬(x_2 ^^^ 1#1) &&& x_1 = 1#1 → ¬x_2 = 1#1 → ¬x_1 = 1#1 → x_2 = 0#1

theorem in_constant_mone_vary_proof : in_constant_mone_vary_before ⊑ in_constant_mone_vary_after

theorem select_add_icmp_bad_thm (e e_1 e_2 : IntW 32) :
  select (icmp IntPred.eq e_2 (const? 32 1)) (add e_2 e_1) e ⊑
    select (icmp IntPred.eq e_2 (const? 32 1)) (add e_1 (const? 32 1)) e

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

theorem icmp_sle2_proof : icmp_sle2_before ⊑ icmp_sle2_after

theorem test1_proof : test1_before ⊑ test1_after

theorem test_shl_nsw__all_are_safe_thm.extracted_1._4 : ∀ (x : BitVec 64) (x_1 : BitVec 32),
  ¬ofBool (x_1 &&& 15#32 == 0#32) = 1#1 →
    ¬(True ∧ ((x_1 &&& 15#32) <<< 2#32).sshiftRight' 2#32 ≠ x_1 &&& 15#32 ∨
          2#32 ≥ ↑32 ∨ zeroExtend 64 ((x_1 &&& 15#32) <<< 2#32) ≥ ↑64) →
      ¬(2#32 ≥ ↑32 ∨ True ∧ (x_1 <<< 2#32 &&& 60#32).msb = true ∨ zeroExtend 64 (x_1 <<< 2#32 &&& 60#32) ≥ ↑64) →
        x.sshiftRight' (zeroExtend 64 ((x_1 &&& 15#32) <<< 2#32)) =
          x.sshiftRight' (zeroExtend 64 (x_1 <<< 2#32 &&& 60#32))

theorem sgt_smin1_proof : sgt_smin1_before ⊑ sgt_smin1_after

theorem or_xor_tree_0100_proof : or_xor_tree_0100_before ⊑ or_xor_tree_0100_after

theorem sdiv_exact_eq_0_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ¬(True ∧ x_1.smod x ≠ 0 ∨ (x == 0 || 8 != 1 && x_1 == intMin 8 && x == -1) = true) →
    ofBool (x_1.sdiv x == 0#8) = ofBool (x_1 == 0#8)

theorem and_nosignbit_select_shl_proof : and_nosignbit_select_shl_before ⊑ and_nosignbit_select_shl_after

theorem not_or_or_and_not_and_and_commute2_and_proof : not_or_or_and_not_and_and_commute2_and_before ⊑ not_or_or_and_not_and_and_commute2_and_after

theorem positive_biggershl_shlnsw_lshrexact_proof : positive_biggershl_shlnsw_lshrexact_before ⊑ positive_biggershl_shlnsw_lshrexact_after

theorem t1_flags_nuw_second_thm (e e_1 e_2 : IntW 8) :
  sub (sub e_2 e_1) e { «nsw» := false, «nuw» := true } ⊑ sub e_2 (add e_1 e)

theorem test_sub_nsw__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» := true, «nuw» := false }) ⊑
    sub (const? 32 (-2147483648)) (LLVM.or e (const? 32 (-2147483648))) { «nsw» := true, «nuw» := false }

theorem main1_proof : main1_before ⊑ main1_after

theorem pr33078_1_proof : pr33078_1_before ⊑ pr33078_1_after

theorem e_2250 :
    11 * (f ^^^ (d &&& ( ~~~e ||| f))) - 2 * ( ~~~e ||| (d ^^^ f)) - 6 * (e ^^^  ~~~(d &&& ( ~~~e ||| f))) - 3 * (f &&& (d |||  ~~~e)) - 11 * (e ^^^ (d |||  ~~~f)) - 2 * (e |||  ~~~(d ||| f)) + 2 * (f ^^^ (d &&& e)) - 1 * (f ^^^ (d ||| ( ~~~e ||| f))) - 5 * ( ~~~d &&& ( ~~~e ||| f)) - 5 * ( ~~~(d |||  ~~~e) |||  ~~~(e ^^^ f)) - 7 * (d ^^^ ( ~~~e &&& f)) + 1 *  ~~~(e ||| f) + 3 * (e &&&  ~~~(d &&& f)) + 1 *  ~~~(d &&&  ~~~d) - 2 * (d ^^^ f) + 1 * (f ^^^  ~~~( ~~~d ||| ( ~~~e &&& f))) - 7 *  ~~~(d &&& (e &&& f)) + 7 * (e ^^^ (d ||| (e ||| f))) + 1 * (e ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) - 1 *  ~~~(d |||  ~~~f) - 6 * ((e &&&  ~~~f) |||  ~~~(d ||| ( ~~~e &&& f))) - 1 * ((d &&& e) ^^^ (d ^^^ (e &&& f))) - 1 * ((d |||  ~~~e) &&&  ~~~(d ^^^ (e ^^^ f))) + 7 *  ~~~(d &&& e) + 3 * (f &&&  ~~~(d &&& e)) - 5 * (f ^^^ (d ||| ( ~~~e &&& f))) - 2 * (e &&& (d ||| f)) + 1 * ((e &&&  ~~~f) ^^^ ( ~~~d ||| (e ^^^ f))) - 6 * (e |||  ~~~(d ^^^ f)) + 5 * (d &&& (e ^^^ f)) + 3 * (e ^^^ (d ||| ( ~~~e &&& f))) - 1 * (e ^^^  ~~~( ~~~d &&& (e &&& f))) + 5 * (f ^^^ (d |||  ~~~e)) + 1 * ( ~~~(d ||| e) |||  ~~~(e ^^^ f)) + 5 *  ~~~(d &&& (e ||| f)) + 2 * ((d ^^^ e) &&&  ~~~(d ^^^ f)) - 6 * (d ^^^ (e &&& f)) - 1 * ( ~~~e &&& (d ^^^ f)) + 1 * ( ~~~(d |||  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) - 1 *  ~~~(d ^^^ ( ~~~e &&& f)) - 1 * ((d ||| e) &&& (e ^^^ f)) - 3 * (f ^^^  ~~~(d &&& (e &&& f))) - 2 * (e ^^^  ~~~( ~~~d ||| (e &&& f))) - 1 * (f &&& (d ||| e)) - 5 * (f ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) + 1 *  ~~~(d ^^^ e) + 2 *  ~~~(e |||  ~~~f) + 7 * e - 1 *  ~~~(d ||| f) - 3 * (e ^^^ ( ~~~d ||| ( ~~~e ||| f))) + 37 *  ~~~(d ||| (e ||| f)) + 10 *  ~~~(d ||| ( ~~~e ||| f)) + 19 *  ~~~( ~~~d ||| (e ||| f)) + 33 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 2 * ( ~~~d &&& ( ~~~e &&& f)) + 20 * ( ~~~d &&& (e &&& f)) + 10 * (d &&& ( ~~~e &&& f)) =  - 28 * (d &&& (e &&& f))

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

theorem mul16_low_miss_shift_amount_thm.extracted_1._1 : ∀ (x x_1 : BitVec 16),
  ¬(8#16 ≥ ↑16 ∨ 8#16 ≥ ↑16 ∨ 8#16 ≥ ↑16) →
    8#16 ≥ ↑16 ∨
        True ∧ (x_1 >>> 8#16).smulOverflow (x &&& 127#16) = true ∨
          True ∧ (x_1 >>> 8#16).umulOverflow (x &&& 127#16) = true ∨
            8#16 ≥ ↑16 ∨
              True ∧ (x_1 &&& 127#16).smulOverflow (x >>> 8#16) = true ∨
                True ∧ (x_1 &&& 127#16).umulOverflow (x >>> 8#16) = true ∨
                  True ∧ (x_1 >>> 8#16 * (x &&& 127#16)).uaddOverflow ((x_1 &&& 127#16) * x >>> 8#16) = true ∨
                    8#16 ≥ ↑16 ∨
                      True ∧ (x_1 &&& 127#16).smulOverflow (x &&& 127#16) = true ∨
                        True ∧ (x_1 &&& 127#16).umulOverflow (x &&& 127#16) = true →
      False

theorem not_and_and_or_not_or_or_commute1_proof : not_and_and_or_not_or_or_commute1_before ⊑ not_and_and_or_not_or_or_commute1_after

theorem udiv_shl_pair_const_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬(True ∧ x <<< 2#32 >>> 2#32 ≠ x ∨ 2#32 ≥ ↑32 ∨ True ∧ x <<< 1#32 >>> 1#32 ≠ x ∨ 1#32 ≥ ↑32 ∨ x <<< 1#32 = 0) →
    x <<< 2#32 / x <<< 1#32 = 2#32

theorem flip_add_of_shift_neg_thm.extracted_1._2 : ∀ (x x_1 x_2 : BitVec 8),
  ¬(True ∧ ((0#8 - x_2) <<< x_1).sshiftRight' x_1 ≠ 0#8 - x_2 ∨
        True ∧ (0#8 - x_2) <<< x_1 >>> x_1 ≠ 0#8 - x_2 ∨ x_1 ≥ ↑8) →
    ¬x_1 ≥ ↑8 → (0#8 - x_2) <<< x_1 + x = x - x_2 <<< x_1

theorem main11_logical_thm.extracted_1._3 : ∀ (x : BitVec 32),
  ¬ofBool (x &&& 64#32 == 0#32) = 1#1 →
    ofBool (x &&& 192#32 == 192#32) = 1#1 → ofBool (0#8 ≤ₛ truncate 8 x) = 1#1 → 2#32 = 1#32

theorem e_1428 :
     - 11 *  ~~~z - 11 *  ~~~(z ^^^ t) + 5 *  ~~~(z &&& t) + 4 *  ~~~(z &&&  ~~~t) + 2 * z - 2 * (z ||| t) - 1 * (z |||  ~~~t) + 14 *  ~~~(z ||| t) + 6 *  ~~~(z |||  ~~~t) - 4 * (z &&&  ~~~t) = 2 * t - 10 * (z &&& t)

theorem test_invert_demorgan_logical_and_thm (e e_1 : IntW 64) :
  LLVM.xor
      (LLVM.or (icmp IntPred.eq e_1 (const? 64 0))
        (select (icmp IntPred.eq e_1 (const? 64 27)) (icmp IntPred.eq e (const? 64 0)) (const? 1 0)))
      (const? 1 1) ⊑
    LLVM.and (icmp IntPred.ne e_1 (const? 64 0))
      (select (icmp IntPred.ne e_1 (const? 64 27)) (const? 1 1) (icmp IntPred.ne e (const? 64 0)))

theorem positive_samevar_shlnuw_lshrexact_thm (e e_1 : IntW 8) :
  shl (lshr e_1 e { «exact» := true }) e { «nsw» := false, «nuw» := true } ⊑ e_1

theorem sext_sext_ult_proof : sext_sext_ult_before ⊑ sext_sext_ult_after

theorem positive_with_aggressive_icmp_logical_proof : positive_with_aggressive_icmp_logical_before ⊑ positive_with_aggressive_icmp_logical_after

theorem shl_sub_i8_proof : shl_sub_i8_before ⊑ shl_sub_i8_after

theorem bools_logical_commute1_and2_thm.extracted_1._8 : ∀ (x x_1 x_2 : BitVec 1),
  x_2 = 1#1 → x_1 = 1#1 → ¬x_1 ^^^ 1#1 = 1#1 → x_1 &&& x = x

theorem alive_275_2   : alive_275_2_src ⊑ alive_275_2_tgt

theorem ashrsgt_01_08_exact_proof : ashrsgt_01_08_exact_before ⊑ ashrsgt_01_08_exact_after

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

theorem e_922 :
    3 *  ~~~t + 1 * t - 7 *  ~~~(z ||| t) - 5 *  ~~~(z |||  ~~~t) - 3 * (z &&&  ~~~t) - 1 * (z &&& t) =  - 4 *  ~~~z

theorem not_ashr_const_proof : not_ashr_const_before ⊑ not_ashr_const_after

theorem and_ashr_not_commuted_thm.extracted_1._2 : ∀ (x x_1 x_2 : BitVec 8),
  ¬(x_1 ≥ ↑8 ∨ x_1 ≥ ↑8) →
    ¬x_1 ≥ ↑8 → (x_2.sshiftRight' x_1 ^^^ -1#8) &&& x.sshiftRight' x_1 = (x &&& (x_2 ^^^ -1#8)).sshiftRight' x_1

theorem ule_swap_and_min_logical_thm (e e_1 : IntW 8) :
  select (icmp IntPred.uge e_1 e) (icmp IntPred.eq e (const? 8 0)) (const? 1 0) ⊑
    icmp IntPred.eq e (const? 8 0)

@[simp] theorem carry'_zero
    (initCarry : Bool) (x y : BitStream) :
  (carry' initCarry x y 0) = initCarry

theorem masked_and_notA_slightly_optimized_proof : masked_and_notA_slightly_optimized_before ⊑ masked_and_notA_slightly_optimized_after

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

theorem test73_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (-1#8 <ₛ truncate 8 x) = 1#1 → ¬ofBool (x &&& 128#32 == 0#32) = 1#1 → 40#32 = 42#32

theorem test11_thm.extracted_1._1 : ∀ (x : BitVec 23),
  ¬(11#23 ≥ ↑23 ∨ 12#23 ≥ ↑23) → (x * 3#23) >>> 11#23 <<< 12#23 = x * 6#23 &&& BitVec.ofInt 23 (-4096)

theorem sdiv_icmp1_thm.extracted_1._1 : ∀ (x : BitVec 64),
  ¬(True ∧ x.smod 5#64 ≠ 0 ∨ (5#64 == 0 || 64 != 1 && x == intMin 64 && 5#64 == -1) = true) →
    ofBool (x.sdiv 5#64 == 0#64) = ofBool (x == 0#64)

theorem icmp_ne_sext_slt_allones_nofold_proof : icmp_ne_sext_slt_allones_nofold_before ⊑ icmp_ne_sext_slt_allones_nofold_after

theorem c_1_1_0_proof : c_1_1_0_before ⊑ c_1_1_0_after

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

theorem udiv_shl_pair_const_proof : udiv_shl_pair_const_before ⊑ udiv_shl_pair_const_after

theorem sdiv_mul_shl_nsw_exact_commute1_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 5),
  ¬(True ∧ x_2.smulOverflow x_1 = true ∨
        True ∧ (x_1 <<< x).sshiftRight' x ≠ x_1 ∨
          x ≥ ↑5 ∨
            True ∧ (x_2 * x_1).smod (x_1 <<< x) ≠ 0 ∨
              (x_1 <<< x == 0 || 5 != 1 && x_2 * x_1 == intMin 5 && x_1 <<< x == -1) = true) →
    True ∧ 1#5 <<< x >>> x ≠ 1#5 ∨
        x ≥ ↑5 ∨
          True ∧ x_2.smod (1#5 <<< x) ≠ 0 ∨ (1#5 <<< x == 0 || 5 != 1 && x_2 == intMin 5 && 1#5 <<< x == -1) = true →
      False

theorem t0_thm.extracted_1._3 : ∀ (x x_1 : BitVec 8) (x_2 : BitVec 1),
  ¬x_2 ^^^ 1#1 = 1#1 → x_2 = 1#1 → 0#1 = 1#1 → False

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

theorem e_569 :
    3 * x - 11 * y + 3 *  ~~~(x &&&  ~~~y) - 11 *  ~~~(x &&&  ~~~x) + 2 *  ~~~y + 7 * (x ||| y) + 6 *  ~~~(x ||| y) + 12 *  ~~~(x |||  ~~~y) + 9 * (x &&& y) = 1 * (x &&&  ~~~y)

theorem trunc_lshr_sext_thm (e : IntW 8) : trunc 8 (lshr (sext 32 e) (const? 32 6)) ⊑ ashr e (const? 8 6)

theorem e_1493 :
    1 * (z |||  ~~~t) + 1 *  ~~~(z &&&  ~~~t) + 2 * (z ||| t) - 1 * (z ^^^ t) - 5 *  ~~~(z ^^^ t) + 2 * z - 6 *  ~~~t - 1 *  ~~~(z &&& t) + 3 *  ~~~z + 8 *  ~~~(z ||| t) + 4 * (z &&&  ~~~t) = 1 *  ~~~(z &&&  ~~~z) + 3 *  ~~~(z |||  ~~~t)

theorem select_icmp_ne_0_and_32_xor_4096_thm.extracted_1._4 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (0#32 != x_1 &&& 32#32) = 1#1 → ¬7#32 ≥ ↑32 → x ^^^ 4096#32 = x_1 <<< 7#32 &&& 4096#32 ^^^ x ^^^ 4096#32

theorem masked_icmps_mask_notallzeros_bmask_mixed_swapped_4_proof : masked_icmps_mask_notallzeros_bmask_mixed_swapped_4_before ⊑ masked_icmps_mask_notallzeros_bmask_mixed_swapped_4_after

theorem shl_nsw_nuw_add_nuw_proof : shl_nsw_nuw_add_nuw_before ⊑ shl_nsw_nuw_add_nuw_after
</all_available_lemmas>

<local_ctx>
import Mathlib.Data.Bool.Basic

import Mathlib.Data.Fin.Basic

import Mathlib.Data.Finset.Basic

import Mathlib.Data.Finset.Defs

import Mathlib.Data.Multiset.FinsetOps

import Blase.Fast.BitStream

import Blase.Fast.Defs

import Blase.Fast.FiniteStateMachine

import Blase.Fast.Decide

import Blase.SingleWidth.Syntax

import Lean.Meta.ForEachExpr

import Lean.Meta.Tactic.Simp.BuiltinSimprocs.BitVec

import Blase.Fast.ForLean

import Blase.Vars

import Blase.EnvBitstream

import Lean

open Fin.NatCast

namespace ReflectVerif

open Lean Meta Elab Tactic

namespace BvDecide

open Std Sat AIG

def mkCarryAssignCircuitNAux {arity : Type _}
  [DecidableEq arity]
  [Fintype arity]
  [Hashable arity]
  (p : FSM arity) (s : p.α) (n : Nat) : Circuit (Vars p.α arity (n + 1)) :=
    (p.nextStateCirc s).map fun v =>
      match v with
        | .inl t => Vars.stateN t n
        | .inr i => Vars.inputN i n

def mkCarryAssignCircuitN {arity : Type _}
  [DecidableEq arity]
  [Fintype arity]
  [Hashable arity]
  (p : FSM arity) (n : Nat) :
  Circuit (Vars p.α arity (n + 1)) :=
  let carrys := FinEnum.toList p.α |>.map fun s =>
    
    Circuit.xor
      (mkCarryAssignCircuitNAux p s n)
      (Circuit.var true <| Vars.stateN s (n + 1))
  Circuit.bigOr carrys

def mkOutputAssignCircuitNAux {arity : Type _}
  [DecidableEq arity]
  [Fintype arity]
  [Hashable arity]
  (p : FSM arity) (n : Nat) : Circuit (Vars p.α arity (n + 1)) :=
    (p.outputCirc).map fun v =>
      match v with
        | .inl s' => Vars.stateN s' n
        | .inr i => Vars.inputN i n

def mkOutputAssignCircuitN {arity : Type _}
  [DecidableEq arity]
  [Fintype arity]
  [Hashable arity]
  (p : FSM arity) (n : Nat) :
  Circuit (Vars p.α arity (n + 1)) :=
    Circuit.xor
      (mkOutputAssignCircuitNAux p n)
      (Circuit.var true <| Vars.outputs ⟨n, by admit /- proof elided -/
      ⟩)

def mkStateNeqCircuit
  {arity : Type _} {i : Nat}
  [DecidableEq arity] [Fintype arity] [Hashable arity]
  (p : FSM arity) (s t : p.α → Circuit (Vars p.α arity i)) : Circuit (Vars p.α arity i) :=
  Circuit.bigAnd <| FinEnum.toList p.α |>.map fun a => ~~~ (s a) ^^^ (t a)

def mkStateUniqueCircuitN {arity : Type _}
  [DecidableEq arity] [Fintype arity] [Hashable arity]
  (p : FSM arity) (n : Nat) : Circuit (Vars p.α arity n) :=
  let sn : p.α → Circuit (Vars p.α arity n) := fun s =>
    Circuit.var true (Vars.stateN s n)
  let circs := (List.range n).attach |>.map fun ⟨i, hi⟩ =>
    let si : p.α → Circuit (Vars p.α arity n) := fun s =>
      Circuit.var true (Vars.stateN s i (by admit /- proof elided -/
      ))
    (mkStateNeqCircuit p si sn)
  Circuit.bigOr circs

structure KInductionCircuits {arity : Type _}
  [DecidableEq arity] [Fintype arity] [Hashable arity] (fsm : FSM arity) (n : Nat) where
  
  cInitCarryAssignCirc : Circuit (Vars fsm.α arity 0)
  
  cSuccCarryAssignCirc : Circuit (Vars fsm.α arity (n+2))
  
  cOutAssignCirc : Circuit (Vars fsm.α arity (n + 2))
  
  cStatesUniqueCirc : Circuit (Vars fsm.α arity n)

structure KInductionCircuits.IsLawful {arity : Type _}
    [DecidableEq arity] [Fintype arity] [Hashable arity] {fsm : FSM arity} {n : Nat}
  (circs : KInductionCircuits fsm n) where
  hCInitCarryAssignCirc :
    ∀ {env : Vars fsm.α arity 0 → Bool},
      (circs.cInitCarryAssignCirc.eval env = false)
      ↔ (∀ (s : fsm.α), fsm.initCarry s = env (Vars.state0 s))

  hCSuccCarryAssignCirc :
    ∀ {env : Vars fsm.α arity (n + 2) → Bool},
      (circs.cSuccCarryAssignCirc.eval env = false)
      ↔ (∀ (s : fsm.α) (i : Nat) (hi : i < n + 2),
        env (Vars.stateN s (i + 1)) =
          ((mkCarryAssignCircuitNAux fsm s i).map
            (fun v => v.castLe (by admit /- proof elided -/
            ))).eval env)
  hCOutAssignCirc :
    ∀ {env : Vars fsm.α arity (n + 2) → Bool},
      (circs.cOutAssignCirc.eval env = false)
      ↔ (∀ (i : Nat) (hi : i < n + 2),
        (fsm.outputCirc).eval
          (fun x => match x with
            | .inl s => env (Vars.stateN s i)
            | .inr j => env (Vars.inputN j i)) =
        env (Vars.outputs ⟨i, by admit /- proof elided -/
        ⟩))
  hCStatesUniqueCirc :
    ∀ {env : Vars fsm.α arity (n) → Bool},
      (circs.cStatesUniqueCirc.eval env = false)
      ↔ (∀ (i j : Nat) (hij : i < j ∧ j ≤ n),
        ∃ (s : fsm.α), env (Vars.stateN s i) ≠ env (Vars.stateN s j))

namespace KInductionCircuits

variable {arity : Type _}
  {fsm : FSM arity}

def castCircLe {n m : Nat} (c : Circuit (Vars fsm.α arity n)) (hnm : n ≤ m := by admit /- proof elided -/
) :
    Circuit (Vars fsm.α arity m) :=
  c.map (fun v => v.castLe hnm)

variable [DecidableEq arity] [Fintype arity] [Hashable arity]

def mkSucc
    (prev : KInductionCircuits fsm n) :
    KInductionCircuits fsm (n + 1) :=
  let cInitCarryAssignCirc := prev.cInitCarryAssignCirc
  { cInitCarryAssignCirc := cInitCarryAssignCirc
  , cSuccCarryAssignCirc :=
      (mkCarryAssignCircuitN fsm (n + 2)) |||
      (castCircLe prev.cSuccCarryAssignCirc)
  , cOutAssignCirc :=
      (mkOutputAssignCircuitN fsm (n + 2)) |||
      (castCircLe prev.cOutAssignCirc)
  , cStatesUniqueCirc :=
      mkStateUniqueCircuitN fsm (n + 1) |||
      (castCircLe prev.cStatesUniqueCirc)
  }
</local_ctx>

<target_theorem>
theorem IsLawful_mkSucc_of_IsLawful {arity : Type _}
    [DecidableEq arity] [Fintype arity] [Hashable arity]
    {fsm : FSM arity} {n : Nat}
    (prev : KInductionCircuits fsm n)
    (hPrev : prev.IsLawful) :
    (mkSucc prev).IsLawful :=
</target_theorem>

