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
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
DecidableEq in Init.Prelude
FinEnum in Mathlib.Data.FinEnum
Hashable in Init.Prelude
Empty in Init.Prelude
Empty.elim in Init.Core
Sum in Init.Core
Sum.elim in Init.Data.Sum.Basic
ZMod in Mathlib.Data.ZMod.Defs

syntax "llvm.and"     : MLIR.Pretty.uniform_op

syntax "llvm.ashr"    : MLIR.Pretty.exact_op

syntax "llvm.add"     : MLIR.Pretty.overflow_op

syntax "llvm.return"  : MLIR.Pretty.uniform_op

syntax "return" : MLIR.Pretty.uniform_op

macro_rules
  
  | `(mlir_op| $v:mlir_op_operand = mod_arith.constant $x:neg_num : $t) =>
    `(mlir_op| $v:mlir_op_operand = "mod_arith.constant" () {value = $x:neg_num} : () -> ($t))

| `(mlir_op| $v:mlir_op_operand = mod_arith.constant ${ $x:term } : $t) => do
      let ctor := mkIdent ``MLIR.AST.AttrValue.int
      let x ← `($ctor $x [mlir_type| i64])
      `(mlir_op| $v:mlir_op_operand = "mod_arith.constant" () {value = $$($x)} : () -> ($t))

macro_rules
  | `(mlir_op| $resName:mlir_op_operand = $name:InstCombine.cmp_op_name $x, $y $[: $t]?) => do
    let some opName := extractOpName name.raw
      | Macro.throwUnsupported
    let t ← t.getDM `(mlir_type| _)
    `(mlir_op| $resName:mlir_op_operand = $opName ($x, $y) : ($t, $t) -> (i1) )

macro_rules
  | `(mlir_op| $resName:mlir_op_operand = $name:InstCombine.int_cast_op $x : $t to $t') => do
    let some opName := extractOpName name.raw
      | Macro.throwUnsupported
    `(mlir_op| $resName:mlir_op_operand = $opName ($x) : ($t) -> $t')

macro_rules
  | `(mlir_op| $res:mlir_op_operand = llvm.mlir.constant( $x $[: $inner_type]?)
      $[: $outer_type]? ) => do
       
      let outer_type ← outer_type.getDM `(mlir_type| _)
      let inner_type := inner_type.getD outer_type
      `(mlir_op| $res:mlir_op_operand = "llvm.mlir.constant"()
          {value = $x:neg_num : $inner_type} : () -> ($outer_type) )
  | `(mlir_op| $res:mlir_op_operand = llvm.mlir.constant( ${ $x:term }) $[: $t]?) => do
      let t ← t.getDM `(mlir_type| _)
      let x ← `(MLIR.AST.AttrValue.int $x [mlir_type| $t])
      `(mlir_op| $res:mlir_op_operand = "llvm.mlir.constant"() {value = $$($x) } : () -> ($t) )

macro_rules
  | `(mlir_op| $res:mlir_op_operand = llvm.mlir.constant (true) $[: $t]?) =>
      `(mlir_op| $res:mlir_op_operand = llvm.mlir.constant (1 : i1) : i1)
  | `(mlir_op| $res:mlir_op_operand = llvm.mlir.constant (false) $[: $t]?) =>
      `(mlir_op| $res:mlir_op_operand = llvm.mlir.constant (0 : i1) : i1)
  | `(mlir_op| $res:mlir_op_operand = llvm.mlir.constant $x $[: $t]?) =>
      `(mlir_op| $res:mlir_op_operand = llvm.mlir.constant($x $[: $t]?) $[: $t]?)
  | `(mlir_op| $res:mlir_op_operand = llvm.mlir.constant ${ $x:term } $[: $t]?) =>
      `(mlir_op| $res:mlir_op_operand = llvm.mlir.constant($$($x) $[: $t]?) $[: $t]?)

macro_rules
  | `(mlir_op| $res:mlir_op_operand = llvm.icmp $p $x, $y $[: $t]?) => do
    let t ← t.getDM `(mlir_type| _)
    match p.getString with
      | "eq" => `(mlir_op| $res:mlir_op_operand = "llvm.icmp.eq" ($x, $y) : ($t, $t) -> (i1))
      | "ne" => `(mlir_op| $res:mlir_op_operand = "llvm.icmp.ne" ($x, $y) : ($t, $t) -> (i1))
      | "slt" => `(mlir_op| $res:mlir_op_operand = "llvm.icmp.slt" ($x, $y) : ($t, $t) -> (i1))
      | "sle" => `(mlir_op| $res:mlir_op_operand = "llvm.icmp.sle" ($x, $y) : ($t, $t) -> (i1))
      | "sgt" => `(mlir_op| $res:mlir_op_operand = "llvm.icmp.sgt" ($x, $y) : ($t, $t) -> (i1))
      | "sge" => `(mlir_op| $res:mlir_op_operand = "llvm.icmp.sge" ($x, $y) : ($t, $t) -> (i1))
      | "ult" => `(mlir_op| $res:mlir_op_operand = "llvm.icmp.ult" ($x, $y) : ($t, $t) -> (i1))
      | "ule" => `(mlir_op| $res:mlir_op_operand = "llvm.icmp.ule" ($x, $y) : ($t, $t) -> (i1))
      | "ugt" => `(mlir_op| $res:mlir_op_operand = "llvm.icmp.ugt" ($x, $y) : ($t, $t) -> (i1))
      | "uge" => `(mlir_op| $res:mlir_op_operand = "llvm.icmp.uge" ($x, $y) : ($t, $t) -> (i1))
      | _ => Macro.throwErrorAt p s!"unexpected predicate {p.getString}"

macro_rules
  | `(mlir_op| $res:mlir_op_operand = llvm.select $c, $x, $y $[: $t]?) => do
    let t ← t.getDM `(mlir_type| _)
    `(mlir_op| $res:mlir_op_operand = "llvm.select" ($c, $x, $y) : (i1, $t, $t) -> ($t))

macro_rules
  | `(mlir_op| $v:mlir_op_operand = arith.const $x:neg_num : $t) =>
      `(mlir_op| $v:mlir_op_operand = "arith.const" () {value = $x:neg_num } : () -> ($t))
  | `(mlir_op| $v:mlir_op_operand = arith.const ${ $x:term } : $t) => do
      let ctor := mkIdent ``MLIR.AST.AttrValue.int
      let x ← `($ctor $x [mlir_type| i64])
      
      
      
      
      `(mlir_op| $v:mlir_op_operand = "arith.const" () {value = $$($x) } : () -> ($t))

macro_rules
  | `(mlir_op| $v:mlir_op_operand = poly.const $x:neg_num : $t) =>
      `(mlir_op| $v:mlir_op_operand = "poly.const" () {value = $x:neg_num } : () -> ($t))
  | `(mlir_op| $v:mlir_op_operand = poly.const ${ $x:term } : $t) => do
      let ctor := mkIdent ``MLIR.AST.AttrValue.int
      let x ← `($ctor $x [mlir_type| i64])
      
      
      
      
      `(mlir_op| $v:mlir_op_operand = "poly.const" () {value = $$($x) } : () -> ($t))

macro_rules
  | `(mlir_op| $v:mlir_op_operand = poly.monomial $xs,* : ($ts,*) -> $t) =>
      `(mlir_op| $v:mlir_op_operand = "poly.monomial" ($xs,*) : ($ts,*) -> $t)

def BitStream : Type := Nat → Bool

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 carryWith (p : FSM arity) (carryState : p.α → Bool) (x : arity → BitStream) (n : Nat) : p.α → Bool := fun a =>
  (p.changeInitCarry carryState).carry x n a

def changeInitCarry (p : FSM arity) (c : p.α → Bool) : FSM arity :=
  { p with initCarry := c }

def zero : FSM (Fin 0) :=
  { α := Empty,
    initCarry := Empty.elim,
    nextStateCirc := Empty.elim,
    outputCirc := Circuit.fals
  }

def carry (x : arity → BitStream) : ℕ → p.State
  | 0 => p.initCarry
  | n+1 => (p.nextBit (carry x n) (fun i => x i n)).1

abbrev State : Type := p.α → Bool

def nextBit : p.State → (arity → Bool) → p.State × Bool :=
  fun carry inputBits =>
    let input := Sum.elim carry inputBits
    let newState : p.State  := fun (a : p.α) => (p.nextStateCirc a).eval input
    let outBit : Bool       := (p.outputCirc).eval input
    (newState, outBit)

def rhs := [poly q, n, hq | {
^bb0(%a : !R):
  return %a : !R

}]

inductive AttrValue where
  | symbol: String -> AttrValue 
  | str : String -> AttrValue
  | int : Int -> MLIRType φ -> AttrValue
  | nat: Nat -> AttrValue
  | bool : Bool -> AttrValue
  | float : Float -> MLIRType φ -> AttrValue
  | type : MLIRType φ -> AttrValue
  | affine: AffineMap -> AttrValue
  | permutation: List Nat -> AttrValue 
  | list: List AttrValue -> AttrValue
  | nestedsymbol: AttrValue -> AttrValue -> AttrValue
  | alias: String -> AttrValue
  | dict: AttrDict -> AttrValue
  | opaque_: (dialect: String) -> (value: String) -> AttrValue
  | opaqueElements: (dialect: String) -> (value: String) -> (type: MLIRType φ) -> AttrValue
  | unit: AttrValue

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

def bb0 : Region 0 := [mlir_region|
{
  ^bb0(%arg0: i32):
    %0 = llvm.mlir.constant(8) : i32
    %1 = llvm.mlir.constant(31) : i32
    %2 = llvm.ashr %arg0, %1 : i32
    %3 = llvm.and %2, %0 : i32
    %4 = llvm.add %3, %2 : i32
    llvm.return %4 : i32
  }]

structure Region where
  (name: String)
  (args: List <| TypedSSAVal φ)
  (ops: List Op)

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

def p2_scalar_shifted_urem_by_const_after := [llvm|
{
^0(%arg16 : i32, %arg17 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(3 : i32) : i32
  %2 = llvm.mlir.constant(0 : i32) : i32
  %3 = llvm.and %arg16, %0 : i32
  %4 = llvm.shl %3, %arg17 overflow<nuw> : i32
  %5 = llvm.urem %4, %1 : i32
  %6 = llvm.icmp "eq" %5, %2 : i32
  "llvm.return"(%6) : (i1) -> ()
}
]

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

def and_or3_before := [llvm|
{
^0(%arg168 : i1, %arg169 : i1, %arg170 : i32, %arg171 : i32):
  %0 = llvm.icmp "eq" %arg170, %arg171 : i32
  %1 = llvm.and %arg169, %0 : i1
  %2 = "llvm.select"(%1, %arg168, %arg169) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%2) : (i1) -> ()
}
]

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

def scalar_i32_shl_and_signbit_slt_before := [llvm|
{
^0(%arg2 : i32, %arg3 : i32):
  %0 = llvm.mlir.constant(-2147483648 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.shl %arg2, %arg3 : i32
  %3 = llvm.and %2, %0 : i32
  %4 = llvm.icmp "slt" %3, %1 : i32
  "llvm.return"(%4) : (i1) -> ()
}
]

def test24_before := [llvm|
{
^0(%arg53 : i32):
  %0 = llvm.mlir.constant(-2147483648 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.urem %arg53, %0 : i32
  %3 = llvm.icmp "ne" %2, %1 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

def shl_sub_lshr_reverse_nsw_on_op1_after := [llvm|
{
^0(%arg130 : i32, %arg131 : i32, %arg132 : i32):
  %0 = llvm.lshr exact %arg132, %arg131 : i32
  %1 = llvm.sub %0, %arg130 overflow<nuw> : i32
  "llvm.return"(%1) : (i32) -> ()
}
]

def EnvFin.getAll1 (n : Nat) : { envs : List (EnvFin 1 n) // ∀ (envFin : EnvFin 1 n), envFin ∈ envs } :=
  match hn : n with
  | 0 => ⟨[fun i => i.elim0], by admit /- proof elided -/
  ⟩
  | n' + 1 =>
     let ⟨envs, henvs⟩ := EnvFin.getAll1 n'
     let out := envs.flatMap (fun env => [env.cons (BitVec.ofBool false), env.cons (BitVec.ofBool true)])
     ⟨out, by admit /- proof elided -/
     ⟩

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

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

def xor_ugt_2_before := [llvm|
{
^0(%arg13 : i8, %arg14 : i8, %arg15 : i8):
  %0 = llvm.mlir.constant(63 : i8) : i8
  %1 = llvm.mlir.constant(64 : i8) : i8
  %2 = llvm.add %arg13, %arg15 : i8
  %3 = llvm.and %arg14, %0 : i8
  %4 = llvm.or %3, %1 : i8
  %5 = llvm.xor %2, %4 : i8
  %6 = llvm.icmp "ugt" %2, %5 : i8
  "llvm.return"(%6) : (i1) -> ()
}
]

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

def alive_AndOrXor_2284_tgt :=
[sllvm| {
^bb0(%A : i64, %B : i64):
  %v1 = llvm.mlir.constant -1 : i64
  %v2 = llvm.xor %B, %v1 : i64
  %v3 = llvm.or %A, %B : i64
  %v4 = llvm.mlir.constant -1 : i64
  %v5 = llvm.xor %v3, %v4 : i64
  %v6 = llvm.or %A, %v2 : i64
  llvm.return %v6 : i64
}]

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

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

def negative_with_uniform_bad_mask_logical_before := [llvm|
{
^0(%arg12 : i32):
  %0 = llvm.mlir.constant(-16777152 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.mlir.constant(128 : i32) : i32
  %3 = llvm.mlir.constant(256 : i32) : i32
  %4 = llvm.mlir.constant(false) : i1
  %5 = llvm.and %arg12, %0 : i32
  %6 = llvm.icmp "eq" %5, %1 : i32
  %7 = llvm.add %arg12, %2 : i32
  %8 = llvm.icmp "ult" %7, %3 : i32
  %9 = "llvm.select"(%6, %8, %4) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%9) : (i1) -> ()
}
]

def zext_sext_add_icmp_slt_0_after := [llvm|
{
^0(%arg74 : i1, %arg75 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.xor %arg74, %0 : i1
  %2 = llvm.and %arg75, %1 : i1
  "llvm.return"(%2) : (i1) -> ()
}
]

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

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

def constLLVM17 : Com LLVMPlusRiscV ⟨[]⟩ .pure (.llvm (.bitvec 64)) := [LV| {
  ^entry ():
    %1 = llvm.mlir.constant (17) : i64
    llvm.return %1 : i64
  }]

private def tyi32NoGap : MLIRTy := [mlir_type| i32]

def icmp_slt_0_or_icmp_add_1_sge_100_i32_fail_before := [llvm|
{
^0(%arg38 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(100 : i32) : i32
  %2 = llvm.mlir.constant(31 : i32) : i32
  %3 = llvm.add %arg38, %0 : i32
  %4 = llvm.icmp "sge" %3, %1 : i32
  %5 = llvm.zext %4 : i1 to i32
  %6 = llvm.lshr %arg38, %2 : i32
  %7 = llvm.or %6, %5 : i32
  "llvm.return"(%7) : (i32) -> ()
}
]

def a_or_b_const2_after := [llvm|
{
^0(%arg6 : i32, %arg7 : i32, %arg8 : i32, %arg9 : i32):
  %0 = llvm.icmp "eq" %arg6, %arg8 : i32
  %1 = llvm.icmp "eq" %arg7, %arg9 : i32
  %2 = llvm.xor %0, %1 : i1
  "llvm.return"(%2) : (i1) -> ()
}
]

def size (α : Type u) : Circuit α → Nat
| tru | fals | var .. => 1
| and l r | or l r | xor l r => 1 + l.size  + r.size

def scalar_i16_lshr_and_signbit_eq_before := [llvm|
{
^0(%arg33 : i16, %arg34 : i16):
  %0 = llvm.mlir.constant(-32768 : i16) : i16
  %1 = llvm.mlir.constant(0 : i16) : i16
  %2 = llvm.lshr %arg33, %arg34 : i16
  %3 = llvm.and %2, %0 : i16
  %4 = llvm.icmp "eq" %3, %1 : i16
  "llvm.return"(%4) : (i1) -> ()
}
]

def positive_biggerlshr_shlnuwnsw_lshrexact_after := [llvm|
{
^0(%arg25 : i8):
  %0 = llvm.mlir.constant(3 : i8) : i8
  %1 = llvm.lshr exact %arg25, %0 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

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

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

def genLogicalExprToExpr
  [HydrableInstances genPred]
  [H : HydrableGenPredToExpr parsedExpr genPred]
  (parsedExpr : ParsedLogicalExpr parsedExpr genPred) (logicalExpr : BoolExpr genPred) : MetaM Expr :=
  match logicalExpr with
  | .literal pred => H.genPredToExpr parsedExpr pred
  | .const b =>
      match b with
      | true => return (mkConst ``Bool.true)
      | _ => return (mkConst ``Bool.false)
  | .not boolExpr =>
    return mkApp (.const ``Bool.not []) (← genLogicalExprToExpr parsedExpr boolExpr)
  | .gate gate lhs rhs => do
      let lhs ← genLogicalExprToExpr parsedExpr lhs
      let rhs ← genLogicalExprToExpr parsedExpr rhs
      match gate with
      | .or => return mkApp2 (.const ``Bool.or []) lhs rhs
      | .xor => return mkApp2 (.const ``Bool.xor []) lhs rhs
      | .and => return mkApp2 (.const ``Bool.and []) lhs rhs
      | .beq =>
          mkAppM ``BEq.beq #[lhs, rhs]
  | _ => throwError m! "Unsupported operation {logicalExpr}"

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

def sltu_i32_test : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64), Ty.llvm (.bitvec 64)] where
  lhs := sltu_llvm_i64
  rhs := sltu_riscv_i64

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

def lshr_or_after := [llvm|
{
^0(%arg69 : i8, %arg70 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.mlir.constant(4 : i8) : i8
  %2 = llvm.mlir.constant(-16 : i8) : i8
  %3 = llvm.srem %arg69, %0 : i8
  %4 = llvm.shl %3, %1 : i8
  %5 = llvm.and %arg70, %2 : i8
  %6 = llvm.or %5, %4 : i8
  "llvm.return"(%6) : (i8) -> ()
}
]

def eq_21_after := [llvm|
{
^0(%arg124 : i32, %arg125 : i32):
  %0 = llvm.mlir.constant(8 : i32) : i32
  %1 = llvm.lshr %arg124, %0 : i32
  %2 = llvm.trunc %1 : i32 to i16
  %3 = llvm.lshr %arg125, %0 : i32
  %4 = llvm.trunc %3 : i32 to i16
  %5 = llvm.icmp "eq" %2, %4 : i16
  "llvm.return"(%5) : (i1) -> ()
}
]

def neg_or_ashr_i32_after := [llvm|
{
^0(%arg32 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.icmp "ne" %arg32, %0 : i32
  %2 = llvm.sext %1 : i1 to i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def lsb_mask_sign_zext_before := [llvm|
{
^0(%arg11 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.mlir.constant(31 : i32) : i32
  %2 = llvm.add %arg11, %0 : i32
  %3 = llvm.xor %arg11, %0 : i32
  %4 = llvm.and %2, %3 : i32
  %5 = llvm.lshr %4, %1 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

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

@[simp_denote]
def sext_riscv_i1_to_32 := [LV| {
  ^entry (%arg: i1):
    %0 = "builtin.unrealized_conversion_cast"(%arg) : (i1) -> (!i64)
    %1 = slli %0, 63 : !i64
    %2 = srai %1, 63 : !i64
    %res = "builtin.unrealized_conversion_cast"(%2) : (!i64) -> (i32)
    llvm.return %res : i32
  }]

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

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

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

def both_after := [llvm|
{
^0(%arg17 : i8, %arg18 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.shl %0, %arg17 overflow<nsw> : i8
  %2 = llvm.shl %0, %arg18 overflow<nsw> : i8
  %3 = llvm.icmp "ugt" %1, %2 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

def VariadicValueStream (w : Nat) := CIRCTStream.Stream (List (BitVec w))

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

def ashr_lshr_shift_amt_mismatch_before := [llvm|
{
^0(%arg72 : i32, %arg73 : i32, %arg74 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.icmp "sge" %arg72, %0 : i32
  %2 = llvm.lshr %arg72, %arg73 : i32
  %3 = llvm.ashr %arg72, %arg74 : i32
  %4 = "llvm.select"(%1, %2, %3) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%4) : (i32) -> ()
}
]

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

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

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

def llvm_sext_lower_riscv_i16_to_64 : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 16)] :=
  {lhs:= sext_llvm_i16_to_64, rhs:= sext_riscv_i16_to_64}

def ashr_x_by_const_cmp_sge_x_before := [llvm|
{
^0(%arg6 : i32):
  %0 = llvm.mlir.constant(5 : i32) : i32
  %1 = llvm.ashr %arg6, %0 : i32
  %2 = llvm.icmp "sge" %1, %arg6 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

def xor_or_xor_common_op_commute1_before := [llvm|
{
^0(%arg80 : i32, %arg81 : i32, %arg82 : i32):
  %0 = llvm.xor %arg80, %arg82 : i32
  %1 = llvm.or %arg80, %arg81 : i32
  %2 = llvm.xor %0, %1 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def lshr_and_or_disjoint_before := [llvm|
{
^0(%arg43 : i8, %arg44 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.mlir.constant(2 : i8) : i8
  %2 = llvm.mlir.constant(13 : i8) : i8
  %3 = llvm.srem %arg43, %0 : i8
  %4 = llvm.lshr %arg44, %1 : i8
  %5 = llvm.and %4, %2 : i8
  %6 = llvm.or disjoint %3, %5 : i8
  %7 = llvm.shl %6, %1 : i8
  "llvm.return"(%7) : (i8) -> ()
}
]

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

def or_xor_common_op_commute7_after := [llvm|
{
^0(%arg114 : i8, %arg115 : i8, %arg116 : i8):
  %0 = llvm.or %arg115, %arg114 : i8
  %1 = llvm.or %0, %arg116 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

def constLLVM10 : Com LLVMPlusRiscV ⟨[]⟩ .pure (.llvm (.bitvec 64)) := [LV| {
  ^entry ():
    %1 = llvm.mlir.constant (10) : i64
    llvm.return %1 : i64
  }]

LE in Init.Prelude

Prod.fst in Init.Prelude

IO in Init.System.IO
</all_available_defs>

<all_available_lemmas>
...

theorem carryWith_congrEnv {p : FSM arity}
    {carryState : p.α → Bool} {x y : arity → BitStream} {n : Nat}
    (h : ∀ a i, i < n → x a i = y a i) :
    p.carryWith carryState x n = p.carryWith carryState y n

theorem carry_congrEnv {p : FSM arity}
    {x y : arity → BitStream} {n : Nat} (h : ∀ a i, i < n → x a i = y a i) :
    p.carry x n = p.carry y n

theorem t0_proof : t0_before ⊑ t0_after

theorem xor_sext_sext_thm.extracted_1._1 : ∀ (x : BitVec 4) (x_1 : BitVec 8),
  signExtend 16 x_1 ^^^ signExtend 16 x = signExtend 16 (x_1 ^^^ signExtend 8 x)

theorem negate_sdiv_thm (e e_1 : IntW 8) :
  sub e_1 (LLVM.sdiv e (const? 8 42)) ⊑ add (LLVM.sdiv e (const? 8 (-42))) e_1

theorem test_shl_nuw_nsw__nsw_is_safe_proof : test_shl_nuw_nsw__nsw_is_safe_before ⊑ test_shl_nuw_nsw__nsw_is_safe_after

theorem ashrsgt_01_08_exact_thm (e : IntW 4) :
  icmp IntPred.sgt (ashr e (const? 4 1) { «exact» := true }) (const? 4 (-8)) ⊑ const? 1 1

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

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

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

theorem udiv_i32_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8), ¬zeroExtend 32 x = 0 → x = 0 → False

theorem t15_proof : t15_before ⊑ t15_after

theorem masked_icmps_mask_notallzeros_bmask_mixed_1_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 12#32 != 0#32) &&& ofBool (x &&& 7#32 == 1#32) = ofBool (x &&& 15#32 == 9#32)

theorem a_true_implies_b_true2_comm_thm.extracted_1._2 : ∀ (x : BitVec 1) (x_1 : BitVec 8),
  ofBool (10#8 <ᵤ x_1) = 1#1 → ¬ofBool (20#8 <ᵤ x_1) = 1#1 → x &&& ofBool (20#8 <ᵤ x_1) = 0#1

theorem nonexact_ashr_ne_noexactlog_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬x ≥ ↑8 → ofBool ((BitVec.ofInt 8 (-90)).sshiftRight' x != BitVec.ofInt 8 (-30)) = 1#1

theorem test_mul_nuw__all_are_safe_thm (e : IntW 32) :
  select (icmp IntPred.eq (LLVM.and e (const? 32 255)) (const? 32 17)) (const? 32 153)
      (mul (LLVM.and e (const? 32 255)) (const? 32 9) { «nsw» := false, «nuw» := true }) ⊑
    mul (LLVM.and e (const? 32 255)) (const? 32 9) { «nsw» := true, «nuw» := true }

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

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

theorem logical_and_bitwise_and_icmps_comm3_thm (e e_1 e_2 : IntW 8) :
  select (icmp IntPred.ne (LLVM.and e_2 (shl (const? 8 1) e_1)) (const? 8 0))
      (LLVM.and (icmp IntPred.ne (LLVM.and e_2 (const? 8 1)) (const? 8 0)) (icmp IntPred.eq e (const? 8 42)))
      (const? 1 0) ⊑
    select (icmp IntPred.ne (LLVM.and e_2 (shl (const? 8 1) e_1 { «nsw» := false, «nuw» := true })) (const? 8 0))
      (LLVM.and (icmp IntPred.ne (LLVM.and e_2 (const? 8 1)) (const? 8 0)) (icmp IntPred.eq e (const? 8 42)))
      (const? 1 0)

theorem test2_proof : test2_before ⊑ test2_after

theorem shl_trunc_smaller_ashr_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬(10#32 ≥ ↑32 ∨ 13#24 ≥ ↑24) →
    ¬3#24 ≥ ↑24 → truncate 24 (x.sshiftRight' 10#32) <<< 13#24 = truncate 24 x <<< 3#24 &&& BitVec.ofInt 24 (-8192)

theorem e_1763 :
     - 11 * ((a &&& b) |||  ~~~(a ^^^ (b ^^^ c))) - 3 * ( ~~~b &&& (a ^^^ c)) - 6 *  ~~~(b ||| c) - 6 * ((a |||  ~~~b) &&& (b ^^^ c)) - 1 * ((a &&& b) ||| (b ^^^ c)) + 7 * (b ^^^  ~~~(a &&& (b ||| c))) - 6 *  ~~~(a &&& (b ||| c)) + 3 * (a ||| ( ~~~b &&& c)) + 3 *  ~~~(a |||  ~~~c) - 7 *  ~~~(b &&& c) + 11 * ((a ^^^ b) ||| (a ^^^ c)) - 2 *  ~~~( ~~~a ||| (b ^^^ c)) + 1 * (c ^^^ ( ~~~a ||| (b &&& c))) + 7 * (a &&&  ~~~b) - 7 * (c ^^^  ~~~(a &&&  ~~~b)) + 7 * (a ^^^ c) + 1 * (b |||  ~~~c) - 3 * ( ~~~(a |||  ~~~b) |||  ~~~(a ^^^ (b ^^^ c))) + 1 * ((a &&&  ~~~b) |||  ~~~(a ^^^ (b ^^^ c))) + 3 * (b ||| (a &&&  ~~~c)) + 2 * ( ~~~a ||| ( ~~~b ||| c)) + 1 * ( ~~~(a ||| b) ||| (a ^^^ (b ^^^ c))) - 2 * (c ^^^  ~~~( ~~~a ||| ( ~~~b &&& c))) - 3 * (a ||| (b ||| c)) + 5 * (b ^^^ (a ||| ( ~~~b ||| c))) - 2 * (b &&& (a ^^^ c)) + 2 * (b ^^^ (a ||| ( ~~~b &&& c))) + 3 * (c ^^^ (a |||  ~~~b)) + 14 *  ~~~(a ||| (b ||| c)) - 4 *  ~~~(a ||| ( ~~~b ||| c)) - 29 *  ~~~( ~~~a ||| (b ||| c)) + 1 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 11 * ( ~~~a &&& (b &&& c)) + 3 * (a &&& ( ~~~b &&& c)) - 5 * (a &&& (b &&& c)) = 13 * ( ~~~a &&& ( ~~~b &&& c)) - 5 *  ~~~( ~~~a &&& ( ~~~b &&& c))

theorem positive_biggershl_shlnsw_ashrexact_thm (e : IntW 8) :
  shl (ashr e (const? 8 3) { «exact» := true }) (const? 8 6) { «nsw» := true, «nuw» := false } ⊑
    shl e (const? 8 3) { «nsw» := true, «nuw» := false }

theorem src_proof : src_before ⊑ src_after

theorem test11_proof : test11_before ⊑ test11_after

theorem not_sub_thm (e : IntW 32) :
  LLVM.xor (sub (const? 32 123) e) (const? 32 (-1)) ⊑ add e (const? 32 (-124))

theorem f_t15_t01_t09_proof : f_t15_t01_t09_before ⊑ f_t15_t01_t09_after

theorem lt_unsigned_to_small_negative_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ofBool (zeroExtend 32 x <ₛ BitVec.ofInt 32 (-17)) = 0#1

@[simp] theorem sup_impure_eq : max e impure  = impure

theorem slt_zero_eq_i1_proof : slt_zero_eq_i1_before ⊑ slt_zero_eq_i1_after

theorem lshr_32_add_known_32_leading_zeroes_proof : lshr_32_add_known_32_leading_zeroes_before ⊑ lshr_32_add_known_32_leading_zeroes_after

theorem shrink_select_thm.extracted_1._1 : ∀ (x : BitVec 1), ¬x = 1#1 → truncate 8 42#32 = 42#8

lemma RawCNFA.autMsbSet_wf : autMsbSet.WF

theorem test_cast_select_proof : test_cast_select_before ⊑ test_cast_select_after

theorem e_2318 :
    7 * (e &&&  ~~~(d &&&  ~~~f)) - 2 * ((d &&& f) |||  ~~~(e ||| f)) + 2 * ((e &&& f) ||| ( ~~~d &&& (e ||| f))) - 5 * (d &&&  ~~~e) + 2 * ( ~~~(d |||  ~~~e) |||  ~~~(e ^^^ f)) + 2 * (d ^^^ e) - 11 *  ~~~(d ^^^ ( ~~~e ||| f)) - 6 * (f ^^^  ~~~(d ||| (e &&& f))) - 2 *  ~~~(d &&& f) - 11 * ((d |||  ~~~e) &&& (e ^^^ f)) - 2 * (d ||| e) - 3 * ( ~~~(d ^^^ e) &&&  ~~~(d ^^^ f)) + 2 * ((d |||  ~~~e) &&&  ~~~(d ^^^ (e ^^^ f))) + 1 * (f ^^^ ( ~~~d ||| (e ||| f))) + 11 * (f ^^^  ~~~( ~~~d &&& (e &&& f))) - 1 * (e ^^^ (d ||| (e ||| f))) + 1 * ( ~~~(d |||  ~~~e) ||| (d ^^^ (e ^^^ f))) - 7 * (f ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) + 1 * (f ^^^ ( ~~~d ||| ( ~~~e ||| f))) + 2 * (e ^^^  ~~~(d |||  ~~~f)) - 1 * (d ||| (e ^^^ f)) - 2 * (e ||| (d &&&  ~~~f)) - 3 * (f ^^^  ~~~(d ||| ( ~~~e &&& f))) - 1 * (f ||| (d ^^^ e)) + 1 * ((d ||| e) &&&  ~~~(e ^^^ f)) - 11 * (e ^^^ (d ||| ( ~~~e &&& f))) - 5 * (f ^^^ ( ~~~d &&& ( ~~~e ||| f))) + 5 * (e ^^^  ~~~( ~~~d &&& (e ^^^ f))) + 2 * (e ^^^ ( ~~~d ||| (e &&& f))) + 1 * ( ~~~(d &&& e) &&& (e ^^^ f)) - 1 * ( ~~~(d &&&  ~~~e) &&& (e ^^^ f)) + 1 * ((e &&&  ~~~f) ^^^ (d ||| (e ^^^ f))) + 7 * ( ~~~(d |||  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) - 1 * (f ^^^ ( ~~~d &&& (e ||| f))) - 2 * (e ^^^ ( ~~~d ||| ( ~~~e &&& f))) + 1 * ( ~~~(d ^^^ e) |||  ~~~(d ^^^ f)) + 4 *  ~~~(d &&& e) + 5 * (e ^^^ ( ~~~d ||| (e ||| f))) + 2 *  ~~~(e &&&  ~~~f) + 3 * (e ^^^ (d ||| f)) - 11 * ((d &&& e) ||| (d ^^^ (e ^^^ f))) + 2 * ( ~~~d ||| ( ~~~e ||| f)) - 2 * ((d &&& e) ^^^ (d ^^^ ( ~~~e ||| f))) + 4 * ( ~~~f ||| (d ^^^ e)) - 2 *  ~~~(d ^^^ e) - 7 * ((d &&& f) ^^^  ~~~(d ^^^ (e &&& f))) - 6 * (f ^^^  ~~~(d &&& (e ||| f))) + 7 * (f ^^^  ~~~(d &&& e)) + 3 * (e ^^^  ~~~(d ||| f)) + 5 *  ~~~(d ||| (e &&& f)) + 1 * ((d &&& f) ^^^  ~~~(e &&&  ~~~f)) - 7 *  ~~~( ~~~d &&& (e &&& f)) + 1 *  ~~~(d ^^^ (e ^^^ f)) + 1 *  ~~~(d &&& ( ~~~e ||| f)) - 1 *  ~~~(d ^^^ (e &&& f)) - 1 * (d ^^^ f) - 19 *  ~~~(d ||| (e ||| f)) + 11 *  ~~~(d ||| ( ~~~e ||| f)) + 23 *  ~~~( ~~~d ||| (e ||| f)) + 25 *  ~~~( ~~~d ||| ( ~~~e ||| f)) + 49 * ( ~~~d &&& ( ~~~e &&& f)) - 17 * ( ~~~d &&& (e &&& f)) + 42 * (d &&& ( ~~~e &&& f)) + 48 * (d &&& (e &&& f)) = 11 * (e ^^^ ( ~~~d &&& (e ||| f)))

theorem or_xor_tree_1110_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 32),
  x_2 * 42#32 ^^^ (x_1 * 42#32 ^^^ x * 42#32) ||

theorem not_and_and_or_no_or_proof : not_and_and_or_no_or_before ⊑ not_and_and_or_no_or_after

theorem sge_or_not_max_logical_proof : sge_or_not_max_logical_before ⊑ sge_or_not_max_logical_after

theorem f_var1_commutative_and_proof : f_var1_commutative_and_before ⊑ f_var1_commutative_and_after

theorem shl_lshr_pow2_not_const_case2_thm (e : IntW 16) :
  LLVM.xor (LLVM.and (lshr (shl (const? 16 16) e) (const? 16 3)) (const? 16 8)) (const? 16 8) ⊑
    select (icmp IntPred.eq e (const? 16 2)) (const? 16 0) (const? 16 8)

theorem smear_sign_and_widen_thm.extracted_1._2 : ∀ (x : BitVec 8),
  ¬24#32 ≥ ↑32 → ¬7#8 ≥ ↑8 → signExtend 32 x >>> 24#32 = zeroExtend 32 (x.sshiftRight' 7#8)

theorem shl_add_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8), ¬(2#8 ≥ ↑8 ∨ 2#8 ≥ ↑8) → 2#8 ≥ ↑8 → False

theorem lor_land_right1_thm (e e_1 : IntW 1) : select e_1 (select e_1 (const? 1 1) e) (const? 1 0) ⊑ e_1

theorem and_sext_multiuse_thm.extracted_1._1 : ∀ (x x_1 x_2 x_3 : BitVec 32),
  ofBool (x_2 <ₛ x_3) = 1#1 →
    (signExtend 32 (ofBool (x_2 <ₛ x_3)) &&& x_1) + (signExtend 32 (ofBool (x_2 <ₛ x_3)) &&& x) = x_1 + x

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

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

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

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

theorem neg_nsw_sgt_0_proof : neg_nsw_sgt_0_before ⊑ neg_nsw_sgt_0_after

theorem src_srem_shl_demand_max_signbit_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬((2#32 == 0 || 32 != 1 && x == intMin 32 && 2#32 == -1) = true ∨ 30#32 ≥ ↑32) →
    ¬(2#32 == 0 || 32 != 1 && x == intMin 32 && 2#32 == -1) = true →
      x.srem 2#32 <<< 30#32 &&& BitVec.ofInt 32 (-2147483648) = x.srem 2#32 &&& BitVec.ofInt 32 (-2147483648)

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

theorem bitwise_or_logical_or_icmps_comm1_proof : bitwise_or_logical_or_icmps_comm1_before ⊑ bitwise_or_logical_or_icmps_comm1_after

theorem invert_both_cmp_operands_sub_proof : invert_both_cmp_operands_sub_before ⊑ invert_both_cmp_operands_sub_after

theorem icmp_eq_zext_eq_non_boolean_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (zeroExtend 32 (ofBool (x == 2#32)) == x) = ofBool (x == 0#32)

theorem test_lshr__exact_is_unsafe_proof : test_lshr__exact_is_unsafe_before ⊑ test_lshr__exact_is_unsafe_after

theorem n15_wrong_comparison_predicate_and_constant_thm.extracted_1._3 : ∀ (x : BitVec 8),
  ¬ofBool (x &&& 15#8 <ᵤ 2#8) = 1#1 →
    ¬ofBool (x &&& 14#8 == 0#8) = 1#1 → x + 16#8 &&& BitVec.ofInt 8 (-16) = (x &&& BitVec.ofInt 8 (-16)) + 16#8

theorem or_nosignbit_shl_thm (e : IntW 32) :
  shl (LLVM.or e (const? 32 2147418112)) (const? 32 8) ⊑ LLVM.or (shl e (const? 32 8)) (const? 32 (-16777216))

theorem and_congr (e1 : a ≈ʷ b) (e2 : c ≈ʷ d) : (a &&& c) ≈ʷ (b &&& d)

theorem xor_or_proof : xor_or_before ⊑ xor_or_after

theorem uadd_sat_flipped_wrong_bounds7_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x ≤ᵤ BitVec.ofInt 32 (-12)) = 1#1 → ¬ofBool (x <ᵤ BitVec.ofInt 32 (-11)) = 1#1 → x + 9#32 = -1#32

theorem positive_with_icmp_logical_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x <ᵤ 512#32) = 1#1 → ofBool (x + 128#32 <ᵤ 256#32) = ofBool (x <ᵤ 128#32)

theorem udiv_shl_pair3_proof : udiv_shl_pair3_before ⊑ udiv_shl_pair3_after

theorem and_not_or_commute4_proof : and_not_or_commute4_before ⊑ and_not_or_commute4_after

theorem exact_lshr_eq_opposite_msb_thm (e : IntW 8) :
  icmp IntPred.eq (lshr (const? 8 (-128)) e { «exact» := true }) (const? 8 1) ⊑
    icmp IntPred.eq e (const? 8 7)

theorem test_shl_nuw_nsw__nuw_is_safe_thm.extracted_1._4 : ∀ (x : BitVec 64) (x_1 : BitVec 32),
  ¬ofBool (x_1 &&& 1073741822#32 == 0#32) = 1#1 →
    ¬(True ∧ ((x_1 &&& 1073741822#32) <<< 2#32).sshiftRight' 2#32 ≠ x_1 &&& 1073741822#32 ∨
          True ∧ (x_1 &&& 1073741822#32) <<< 2#32 >>> 2#32 ≠ x_1 &&& 1073741822#32 ∨
            2#32 ≥ ↑32 ∨ zeroExtend 64 ((x_1 &&& 1073741822#32) <<< 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) →
        x.sshiftRight' (zeroExtend 64 ((x_1 &&& 1073741822#32) <<< 2#32)) =
          x.sshiftRight' (zeroExtend 64 (x_1 <<< 2#32 &&& BitVec.ofInt 32 (-8)))

theorem p_constmask_commutative_proof : p_constmask_commutative_before ⊑ p_constmask_commutative_after

theorem mul_constant_eq_proof : mul_constant_eq_before ⊑ mul_constant_eq_after

theorem test9_proof : test9_before ⊑ test9_after

theorem e_1099 :
    11 *  ~~~z - 6 *  ~~~(z ^^^ t) - 5 * z + 1 *  ~~~(z &&&  ~~~z) + 7 * t + 4 * (z ^^^ t) - 6 *  ~~~(z ||| t) + 3 * (z &&& t) = 23 *  ~~~(z |||  ~~~t)

theorem appendInl_toCons {v : Var Γ t} :
    v.toCons (t':=t').appendInl (Δ := Δ) = v.appendInl.toCons

theorem or_xor_tree_1011_proof : or_xor_tree_1011_before ⊑ or_xor_tree_1011_after

theorem t0_ult_slt_65536_thm (e e_1 e_2 : IntW 32) :
  select (icmp IntPred.ult e_2 (const? 32 65536)) e_2
      (select (icmp IntPred.slt e_2 (const? 32 65536)) e_1 e) ⊑
    select (icmp IntPred.sgt e_2 (const? 32 65535)) e
      (select (icmp IntPred.slt e_2 (const? 32 0)) e_1 e_2)

theorem e_1019 :
     - 2 *  ~~~(z ^^^ t) - 2 * (z ||| t) - 11 * z - 7 * (z ^^^ t) + 7 *  ~~~(z ||| t) + 9 *  ~~~(z |||  ~~~t) + 25 * (z &&&  ~~~t) = 5 * (z |||  ~~~t) - 20 * (z &&& t)

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 t9_lshr_proof : t9_lshr_before ⊑ t9_lshr_after

theorem ashrsgt_03_14_thm (e : IntW 4) : icmp IntPred.sgt (ashr e (const? 4 3)) (const? 4 (-2)) ⊑ const? 1 1

theorem test_with_neg_even_proof : test_with_neg_even_before ⊑ test_with_neg_even_after

theorem test11_proof : test11_before ⊑ test11_after

theorem masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_2_logical_thm (e : IntW 32) :
  select (icmp IntPred.ne (LLVM.and e (const? 32 7)) (const? 32 0)) (const? 1 1)
      (icmp IntPred.eq (LLVM.and e (const? 32 3)) (const? 32 0)) ⊑
    const? 1 1

@[simp] theorem Lets.denote_nil {Γ : Ctxt d.Ty} :
    (Lets.nil : Lets d Γ eff Γ).denote = (return ·)

theorem t0_shl_proof : t0_shl_before ⊑ t0_shl_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

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)

namespace KInductionCircuits

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

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

def envBitstream_set (x : arity → BitStream) (n : Nat) (v : arity → Bool) :
    arity → BitStream :=
  fun a j => if j = n then v a else x a j
</local_ctx>

<target_theorem>
theorem FSM.carryWith_congrEnv_envBitstream_set_of_le (fsm : FSM arity)
    (s0 : fsm.α → Bool) (env : arity → BitStream) (n : Nat) (v : arity → Bool)
    (k : Nat) (hk : k ≤ n) :
  fsm.carryWith s0 (envBitstream_set env n v) k =
  fsm.carryWith s0 env k :=
</target_theorem>

