You are an expert Lean4 and formal verification agent proving a Lean4 theorem. Your output **must** strictly adhere to the specified format.

### Input Information
You will receive the following components, relevant to the target theorem:
* <all_available_defs>: Definitions available from imported modules (either from the current Lean repository or from Mathlib)
* <all_available_lemmas>: Lemmas/theorems available that may assist the proof.
* <local_ctx>...</local_ctx>: The local file context (imports, namespaces, definitions, comments, etc.) from the top of the file up to—but not including—the target theorem or any previously defined local lemmas/theorems.
* <target_theorem>...</target_theorem>: The target theorem statement, ending with `:=`.

**Notes**
1. Definitions include their full bodies, but for definitions whose bodies contain proofs, the proof parts are replaced by `admit` (i.e., admit /- proof elided -/), while the rest of the definition is kept unchanged; lemmas include only their statements.
2. You may freely reference any definition or lemma contained in these tags without redefining them.
3. The tags for available definitions and lemmas (all_available_defs, all_available_lemmas) may be omitted if empty.

### Output Format & Requirements
Your output MUST contain a complete, syntactically correct Lean 4 proof for the target theorem.

**Strict Output Structure:**
<reasoning> 
...
</reasoning> 

<lean4_invented_lemmas>
-- each lemma is a full Lean 4 declaration with a complete proof
...
</lean4_invented_lemmas>

<lean4_proof>
-- Lean 4 proof body of the target theorem
...
</lean4_proof>

**Requirements:**
1. <reasoning> and <lean4_invented_lemmas> are OPTIONAL. Include them only if they aid proof construction.
2. <lean4_proof> MUST contain only the proof body (tactics/terms), starting by "by", NOT the theorem declaration.
3. <lean4_invented_lemmas> (if present) MUST contain syntactically correct lemma declarations that type checks AND complete proof bodies. Defining a lemma using `axiom` is NOT allowed.
4. <reasoning> contains high-level proof planning.
5. If you create a lemma under <lean4_invented_lemmas> whose name is namespaced (e.g., X.Y.Z), you MUST always refer to it using its fully qualified name. Do NOT rely on shortened names. For example, write rw [X.Y.Z], not rw [Z] for invented lemmas.
6. All Lean 4 code MUST be syntactically correct. No `sorry`, `admit`, or non-Lean text. Comments allowed using `--` or `/- ... -/`.
7. Follow the tags and structure EXACTLY. No extra text before, between, or after the sections.
8. Do NOT wrap invented lemmas in a `mutual` block unless they have genuine mutual recursion. Declare each lemma independently.

### Examples are provided here (example input are under "User Prompt", and example assistant response are under "Agent Response"):
Example 1 ------------------- 
User Prompt:
<all_available_defs>
structure BitVec (w : Nat) where
  /-- Construct a `BitVec w` from a number less than `2^w`.
  O(1), because we use `Fin` as the internal representation of a bitvector. -/
  ofFin ::

  /-- Interpret a bitvector as a number less than `2^w`.
  O(1), because we use `Fin` as the internal representation of a bitvector. -/
  toFin : Fin (hPow 2 w)
</all_available_defs>

<all_available_lemmas>
theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) : (l₁ ++ l₂)[i] = l₁[i]
theorem getElem_eq_testBit_toNat (x : BitVec w) (i : Nat) (h : i < w) :
  x[i] = x.toNat.testBit i := rfl
@[simp, grind =] theorem toNat_cons (b : Bool) (x : BitVec w) :
    (cons b x).toNat = (b.toNat <<< w) ||| x.toNat
@[simp, grind =] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false
theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i
</all_available_lemmas>

<local_ctx>
import Mathlib.Computability.NFA
import Mathlib.Data.FinEnum
import Mathlib.Data.Rel
import Mathlib.Data.Vector.Basic
import Blase.AutoStructs.ForLean

open Set
open Mathlib
open SetRel

-- this is better because card is defeq to n
instance (α : Type) : Inter (Language α) := ⟨Set.inter⟩
instance (α : Type) : Union (Language α) := ⟨Set.union⟩

/--
The set of `n`-tuples of bit vectors of an arbitrary width.
-/
structure BitVecs (n : Nat) where
  w : Nat
  bvs : List.Vector (BitVec w) n

def BitVecs.cast (bvs : BitVecs n) (h : n = n') : BitVecs n' :=
  { w := bvs.w, bvs := h ▸ bvs.bvs }

abbrev BitVecs.empty : BitVecs n := ⟨0, List.Vector.replicate n .nil⟩
abbrev BitVecs.singleton {w : Nat} (bv : BitVec w) : BitVecs 1 := ⟨w, bv ::ᵥ .nil⟩
abbrev BitVecs.pair {w : Nat} (bv1 bv2 : BitVec w) : BitVecs 2 := ⟨w, bv1 ::ᵥ bv2 ::ᵥ .nil⟩

/--
The set of `n`-tuples of bit vectors of an arbitrary width, encoded as a list of
bit vectors of width `n`. The width of the encoded bit vectors is the length of
the list.
-/
abbrev BitVecs' (n : Nat) := List (BitVec n)

@[simps]
def dec (bvs' : BitVecs' n) : BitVecs n where
  w := bvs'.length
  bvs := List.Vector.ofFn fun k => BitVec.ofFn fun i => bvs'[i].getLsbD k

@[simp]
</local_ctx>

<target_theorem>
lemma dec_snoc n (bvs' : BitVecs' n) (a : BitVec n) :
  dec (bvs' ++ [a]) =
    { w := bvs'.length + 1
      bvs := List.Vector.ofFn fun k =>
        BitVec.cons (a.getLsbD k) ((dec bvs').bvs.get k) } :=
</target_theorem>

Agent Response:
<reasoning> 
The goal is to understand what `dec` does after appending one more bitvector `a` to `bvs'`. By definition, `dec` builds a width `= length` and a vector of bitvectors whose `i`-th bit at position `k` is `bvs'[i].getLsbD k`. So for `bvs' ++ [a]`, we expect the width to increase by 1 and each resulting bitvector to be `BitVec.cons` of the new bit coming from `a`.

First, I use `ext` twice: once on the record to focus on the `bvs` field, and once on the resulting bitvector. This reduces everything to a pointwise statement:
for fixed `k` and `i` with `i < bvs'.length + 1`,
the bit `(bvs' ++ [a])[i].getLsbD k` should match the bit at index `i` of `BitVec.cons (a.getLsbD k) ((dec bvs').bvs.get k)`.

At this point I need a clean description of indexing into `BitVec.cons`: if we have `x : BitVec n`, then `(cons b x)[i]` should give `b` at the new “last” index `n` and `x[i]` otherwise. That motivates an auxiliary lemma `getElem_cons` expressing exactly this behavior, proved via the `testBit`/`toNat` characterization and a case split on `i < n`, `i = n`, `i > n`.

Using `getElem_cons`, the RHS becomes an `if` on whether `i = bvs'.length`. So I split into cases:
- If `i = bvs'.length`, then `(bvs' ++ [a])[i]` is the appended `a`, so both sides reduce to `a.getLsbD k`.
- If `i ≠ bvs'.length`, the bound `i < bvs'.length + 1` forces `i < bvs'.length`. Then `(bvs' ++ [a])[i] = bvs'[i]` by `List.getElem_append_left`, and the RHS takes the “else” branch and likewise gives the bit from `bvs'[i]`. In both subcases, `simp` (plus the definition of `dec`) finishes.

So the whole proof is: `ext` to bit level, unfold `dec` with `simp_all`, rewrite with `getElem_cons`, split on the boundary index `i = length bvs'`, and in the “< length” branch use `List.getElem_append_left` and bounds to line up both sides.
</reasoning> 

<lean4_invented_lemmas>
@[grind =]
theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
    (cons b x)[i] = if h : i = n then b else x[i] := by
  simp only [BitVec.getElem_eq_testBit_toNat, BitVec.toNat_cons, Nat.testBit_or]
  rw [Nat.testBit_shiftLeft]
  rcases Nat.lt_trichotomy i n with i_lt_n | i_eq_n | n_lt_i
  · have p1 : ¬(n ≤ i) := by omega
    have p2 : i ≠ n := by omega
    simp [p1, p2]
  · simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_true, Nat.sub_self, Nat.testBit_zero,
    Bool.true_and, BitVec.testBit_toNat, BitVec.getLsbD_of_ge, Bool.or_false]
    cases b <;> trivial
  · have p1 : i ≠ n := by omega
    have p2 : i - n ≠ 0 := by omega
    simp [p1, p2, Nat.testBit_bool_toNat]
</lean4_invented_lemmas>

<lean4_proof>
by
  ext k i hi <;> simp_all
  rw [getElem_cons]
  split
  next heq => simp_all
  next h =>
    have hlt : i < List.length bvs' := by simp at hi; omega
    rw [List.getElem_append_left hlt]
    simp
</lean4_proof>

### Your task:
<all_available_defs>
Bool in Init.Prelude
Nat in Init.Prelude
BitVec in Init.Prelude
BitVec.adcb in Init.Data.BitVec.Bitblast
Prod in Init.Prelude
Add in Init.Prelude
Add.add in Init.Prelude
BitVec.carry in Init.Data.BitVec.Bitblast
BitVec.getLsbD in Init.Data.BitVec.Basic
HAdd in Init.Prelude
HAdd.hAdd in Init.Prelude
Int.succ in Mathlib.Data.Int.Init

...

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

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

@[simp_llvm_option]
def udiv {w : Nat} (x y : IntW w) (flag : ExactFlag := {exact := false}) : IntW w := do
  let x' ← x
  let y' ← y
  if flag.exact ∧ x'.umod y' ≠ 0 then
    .poison
  else
    udiv? x' y'

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

def test_invert_demorgan_or2_before := [llvm|
{
^0(%arg15 : i64, %arg16 : i64, %arg17 : i64):
  %0 = llvm.mlir.constant(23) : i64
  %1 = llvm.mlir.constant(59) : i64
  %2 = llvm.mlir.constant(true) : i1
  %3 = llvm.icmp "ugt" %arg15, %0 : i64
  %4 = llvm.icmp "ugt" %arg16, %1 : i64
  %5 = llvm.or %3, %4 : i1
  %6 = llvm.icmp "ugt" %arg17, %1 : i64
  %7 = llvm.or %5, %6 : i1
  %8 = llvm.xor %7, %2 : i1
  "llvm.return"(%8) : (i1) -> ()
}
]

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

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

def andn_or_cmp_1_logical_after := [llvm|
{
^0(%arg173 : i37, %arg174 : i37, %arg175 : i37):
  %0 = llvm.mlir.constant(42 : i37) : i37
  %1 = llvm.mlir.constant(false) : i1
  %2 = llvm.icmp "sle" %arg173, %arg174 : i37
  %3 = llvm.icmp "ugt" %arg175, %0 : i37
  %4 = "llvm.select"(%2, %3, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%4) : (i1) -> ()
}
]

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

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

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

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

match_expr hExpr with
    | Eq w lhsExpr rhsExpr =>

def sub_to_add_5 : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64)] where
  lhs := [LV| {
    ^entry (%x: i64):
      %c = llvm.mlir.constant 5 : i64
      %1 = llvm.sub %x, %c : i64
      llvm.return %1 : i64
  }]
  rhs := [LV| {
    ^entry (%x: i64):
      %c = llvm.mlir.constant -5 : i64
      %1 = llvm.add %x, %c : i64
      llvm.return %1 : i64
  }]

def function : Parser :=
  leading_parser argumentList >> arrow >> termParser

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

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

def State.cseCom {α}
  {lets : Lets d Γstart .pure Γ}
  (s : State d lets)
  (com: Com d Γ .pure α) :
  { com' : Com d Γ .pure α
    // ∀ (V : Ctxt.Valuation Γstart), com.denote (lets.denote V) = com'.denote (lets.denote V) } :=
  match com with
  | .rets vs =>
      let ⟨vs', hvs'⟩ := s.vars2vars vs
      ⟨.rets vs', by admit /- proof elided -/
        ⟩
  | .var e body =>
      let ⟨⟨e', he'⟩, v'?⟩ := s.cseExpr e
      match v'? with
      | .none =>  
        let s' := s.consNewExpr2Cache (e := e')
         
        let ⟨body', hbody'⟩ := s'.cseCom body
        ⟨.var e' body',  by admit /- proof elided -/
            ⟩
      | .some ⟨v', hv'⟩ =>
        let s' := s.consOldExpr2Cache (enew := e') (eold := e) (henew := by admit /- proof elided -/
        )
          (vold := v') (hv := by admit /- proof elided -/
          )
          
        let ⟨body', hbody'⟩ := s'.cseCom body
        
        ⟨.var e body' 
        , by admit /- proof elided -/
        ⟩

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

HAdd.hAdd in Init.Prelude

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

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

def mul_of_bools_before := [llvm|
{
^0(%arg91 : i32, %arg92 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(2 : i32) : i32
  %2 = llvm.and %arg91, %0 : i32
  %3 = llvm.and %arg92, %0 : i32
  %4 = llvm.mul %2, %3 : i32
  %5 = llvm.icmp "ult" %4, %1 : i32
  "llvm.return"(%5) : (i1) -> ()
}
]

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

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

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

let mut bitwidth := negativeExamples[0]!.values[0]!.w

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

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

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

structure State where
   
  mapping : DiscrTree Expr
  invMapping : Std.HashMap Expr Expr
  deriving Inhabited

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

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

def no_masks_with_logical_or2_after := [llvm|
{
^0(%arg7 : i32, %arg8 : i32, %arg9 : i32):
  %0 = llvm.mlir.constant(63 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.mlir.constant(true) : i1
  %3 = llvm.icmp "ne" %arg8, %0 : i32
  %4 = llvm.and %arg7, %arg9 : i32
  %5 = llvm.icmp "ne" %4, %1 : i32
  %6 = "llvm.select"(%5, %2, %3) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%6) : (i1) -> ()
}
]

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

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

for (const, val) in positiveExamples[0]!.toArray do
        let bvExprVar := GenBVExpr.var const
        let powerOf2Expr :=  GenBVExpr.bin bvExprVar BVBinOp.and (GenBVExpr.bin bvExprVar BVBinOp.add (minusOne val.w))
        let powerOfTwoResults := positiveExamples.map (λ pos => evalBVExpr pos powerOf2Expr)

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

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

def test12_before := [llvm|
{
^0(%arg46 : i32, %arg47 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(-1431655766 : i32) : i32
  %2 = llvm.mlir.constant(1431655765 : i32) : i32
  %3 = llvm.add %arg47, %0 overflow<nsw> : i32
  %4 = llvm.or %arg46, %1 : i32
  %5 = llvm.xor %4, %2 : i32
  %6 = llvm.add %3, %5 overflow<nsw> : i32
  "llvm.return"(%6) : (i32) -> ()
}
]

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

def udiv_i32_multiuse_before := [llvm|
{
^0(%arg25 : i8, %arg26 : i8):
  %0 = llvm.zext %arg25 : i8 to i32
  %1 = llvm.zext %arg26 : i8 to i32
  %2 = llvm.udiv %0, %1 : i32
  %3 = llvm.add %0, %1 : i32
  %4 = llvm.mul %2, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def test_shl_nuw__nuw_is_safe_after := [llvm|
{
^0(%arg80 : i32, %arg81 : i64):
  %0 = llvm.mlir.constant(2 : i32) : i32
  %1 = llvm.mlir.constant(-8 : i32) : i32
  %2 = llvm.shl %arg80, %0 : i32
  %3 = llvm.and %2, %1 : i32
  %4 = llvm.zext nneg %3 : i32 to i64
  %5 = llvm.ashr %arg81, %4 : i64
  "llvm.return"(%5) : (i64) -> ()
}
]

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

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

def subMax (a : BitVec v) (b : BitVec w) : BitVec (max v w + 1) :=
   a.signExtend _ - b.signExtend _

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

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

def and_xor_commute1_after := [llvm|
{
^0(%arg155 : i32, %arg156 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.udiv %0, %arg155 : i32
  %3 = llvm.udiv %0, %arg156 : i32
  %4 = llvm.xor %2, %1 : i32
  %5 = llvm.and %3, %4 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def icmp_sge_riscv_eq_icmp_sge_llvm_32 : LLVMPeepholeRewriteRefine 1 [Ty.llvm (.bitvec 32), Ty.llvm (.bitvec 32)] :=
  {lhs:= icmp_sge_llvm_32, rhs:= icmp_sge_riscv_32}

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

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

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

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

def test_invalid_simplify_other_after := [llvm|
{
^0(%arg204 : i8, %arg205 : i8):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.mlir.constant(-1 : i8) : i8
  %2 = llvm.icmp "eq" %arg204, %0 : i8
  %3 = llvm.add %arg205, %1 : i8
  %4 = "llvm.select"(%2, %0, %3) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  "llvm.return"(%4) : (i8) -> ()
}
]

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

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

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

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

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

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

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

checkTimeout

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

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

IO.FS.Handle in Init.System.IO

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

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

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

def fold_add_udiv_urem_or_disjoint_after := [llvm|
{
^0(%arg5 : i32):
  %0 = llvm.mlir.constant(10 : i32) : i32
  %1 = llvm.mlir.constant(6 : i32) : i32
  %2 = llvm.udiv %arg5, %0 : i32
  %3 = llvm.mul %2, %1 overflow<nuw> : i32
  %4 = llvm.add %3, %arg5 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

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

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

|
</all_available_defs>

<all_available_lemmas>
Nat.add_mod in Init.Data.Nat.Lemmas
Nat.mod_two_eq_zero_or_one in Init.Data.Nat.Lemmas
BitVec.add_eq in Init.Data.BitVec.Basic
BitVec.carry_succ in Init.Data.BitVec.Bitblast
BitVec.getElem_add in Init.Data.BitVec.Bitblast
Nat.add_eq in Init.Data.Nat.Basic

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

theorem test15a_thm.extracted_1._2 : ∀ (x : BitVec 1),
  ¬x = 1#1 → ¬zeroExtend 53 1#8 ≥ ↑53 → 64#53 <<< zeroExtend 53 1#8 = 128#53

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

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

theorem alive_Select_699 : forall (w : Nat) (A B : Bitvec 1)
, TSSA.eval
  (Op := Op) (e := e)
  (i := TSSAIndex.STMT (UserType.base (BaseType.bitvec 1)))
  [dsl_bb|
  ^bb
  %v0 := unit: ;
  %v1 := op:const (A) %v0;
  %v2 := op:const (B) %v0;
  %v3 := pair:%v1 %v2;
  %v4 := op:icmp uge  w %v3;
  %v5 := triple:%v4 %v1 %v2;
  %v6 := op:select 1 %v5;
  %v7 := pair:%v6 %v2;
  %v8 := op:icmp uge  w %v7;
  %v9 := triple:%v8 %v6 %v2;
  %v10 := op:select 1 %v9
  dsl_ret %v10
  ]  ⊑
  TSSA.eval
  (Op := Op) (e := e)
  (i := TSSAIndex.STMT (UserType.base (BaseType.bitvec 1)))
  [dsl_bb|
  ^bb
  %v0 := unit: ;
  %v1 := op:const (A) %v0;
  %v2 := op:const (B) %v0;
  %v3 := pair:%v1 %v2;
  %v4 := op:icmp uge  1 %v3;
  %v5 := triple:%v4 %v1 %v2;
  %v6 := op:select 1 %v5;
  %v7 := pair:%v6 %v2;
  %v8 := op:icmp uge  1 %v7;
  %v9 := triple:%v4 %v1 %v2;
  %v10 := op:select 1 %v9
  dsl_ret %v10
  ]

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

theorem e_2305 :
    4 * (e ^^^ (d ||| f)) - 6 * (d ||| (e ||| f)) - 11 * (e ^^^  ~~~(d ||| ( ~~~e &&& f))) + 11 * (d ||| ( ~~~e ||| f)) + 11 * (f ^^^ (d &&& e)) + 1 *  ~~~(d ^^^ (e ^^^ f)) - 1 * (e ^^^ (d &&&  ~~~f)) + 5 *  ~~~(d &&&  ~~~e) + 2 * (d &&&  ~~~f) + 1 * ((d &&& f) ^^^ (d ^^^ (e &&& f))) - 11 * ((d ||| e) &&& (d ^^^ (e ^^^ f))) + 4 * (f ^^^  ~~~(d |||  ~~~e)) - 6 * ( ~~~(d |||  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) + 4 * ((d ||| e) &&&  ~~~(e ^^^ f)) - 1 * ((e &&&  ~~~f) |||  ~~~( ~~~d ||| ( ~~~e &&& f))) + 2 * (f ^^^ (d &&&  ~~~e)) + 4 *  ~~~(e |||  ~~~f) + 1 * (e ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) - 7 * (f &&& (d ||| e)) - 1 * (f ^^^ ( ~~~d ||| ( ~~~e &&& f))) - 2 * ((d |||  ~~~e) &&& (e ^^^ f)) - 1 * (e ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) + 1 * (d ^^^ ( ~~~e ||| f)) - 7 * ((d ^^^ e) &&& (d ^^^ f)) + 2 *  ~~~(e &&& f) + 1 *  ~~~e + 7 * (e ^^^  ~~~( ~~~d ||| (e &&& f))) - 1 *  ~~~( ~~~d ||| ( ~~~e &&& f)) - 1 * ( ~~~f ||| (d ^^^ e)) - 6 * (f ^^^  ~~~(d &&& (e &&& f))) + 3 * (d ^^^ f) + 5 * (e ^^^  ~~~(d &&& f)) + 1 * (e ^^^ (d ||| ( ~~~e &&& f))) + 7 *  ~~~(d &&&  ~~~d) - 2 * ((e &&&  ~~~f) ^^^ ( ~~~d ||| (e ^^^ f))) + 4 * e + 7 * (e ^^^  ~~~( ~~~d &&& (e ^^^ f))) - 1 * (e ^^^ (d ||| (e ^^^ f))) - 7 * ((d &&& e) ^^^ (e ||| f)) - 2 * (f ||| (d ^^^ e)) - 7 * (d ||| (e &&& f)) - 2 * (e &&& f) + 1 * (e ||| (d ^^^ f)) - 2 * (d &&&  ~~~e) - 3 * (f &&&  ~~~(d &&&  ~~~e)) - 1 * (f ^^^ ( ~~~d ||| ( ~~~e ||| f))) + 2 * (e ^^^ ( ~~~d &&& (e ^^^ f))) - 7 * (f ||| (d &&&  ~~~e)) - 2 * f + 1 * ((e &&&  ~~~f) |||  ~~~(d ||| ( ~~~e &&& f))) - 2 * (f ^^^ ( ~~~d &&& (e ||| f))) - 11 * ( ~~~f &&&  ~~~(d ^^^ e)) - 11 * (f ^^^ (d &&& (e ||| f))) + 3 * (f ^^^  ~~~(d ||| ( ~~~e &&& f))) - 1 * (e ^^^  ~~~(d &&& ( ~~~e &&& f))) - 3 * ((d ^^^ e) &&&  ~~~(d ^^^ f)) - 1 * ( ~~~d ||| (e &&& f)) - 4 *  ~~~(d ||| (e ||| f)) + 3 *  ~~~(d ||| ( ~~~e ||| f)) + 11 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 22 * ( ~~~d &&& ( ~~~e &&& f)) + 12 * ( ~~~d &&& (e &&& f)) - 6 * (d &&& ( ~~~e &&& f)) =  - 15 * (d &&& (e &&& f)) + 3 *  ~~~( ~~~d ||| (e ||| f))

theorem foo_proof : foo_before ⊑ foo_after

theorem bitwise_or_logical_or_icmps_comm1_thm.extracted_1._2 : ∀ (x x_1 x_2 : BitVec 8),
  ¬x_1 ≥ ↑8 →
    ¬ofBool (x == 42#8) = 1#1 →
      True ∧ 1#8 <<< x_1 >>> x_1 ≠ 1#8 ∨ x_1 ≥ ↑8 ∨ True ∧ 1#8 <<< x_1 >>> x_1 ≠ 1#8 ∨ x_1 ≥ ↑8 → False

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

theorem exact_ashr_ne_exactdiv_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬(True ∧ BitVec.ofInt 8 (-80) >>> x <<< x ≠ BitVec.ofInt 8 (-80) ∨ x ≥ ↑8) →
    ofBool ((BitVec.ofInt 8 (-80)).sshiftRight' x != BitVec.ofInt 8 (-5)) = ofBool (x != 4#8)

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

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

theorem bitwise_and_logical_and_masked_icmp_allones_thm.extracted_1._4 : ∀ (x : BitVec 1) (x_1 : BitVec 32),
  ofBool (x_1 &&& 8#32 == 8#32) = 1#1 →
    ¬ofBool (x_1 &&& 15#32 == 15#32) = 1#1 → x &&& ofBool (x_1 &&& 7#32 == 7#32) = 0#1

theorem add_const_const_sub_nsw_proof : add_const_const_sub_nsw_before ⊑ add_const_const_sub_nsw_after

theorem t0_thm.extracted_1._8 : ∀ (x x_1 x_2 x_3 : BitVec 32),
  ¬ofBool (x_3 == x_2) = 1#1 → ¬ofBool (x_3 != x_2) = 1#1 → 0#1 ^^^ 1#1 = ofBool (x_1 != x)

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

theorem test_lshr__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 test_ashr__exact_is_unsafe_proof : test_ashr__exact_is_unsafe_before ⊑ test_ashr__exact_is_unsafe_after

theorem sge_or_max_commute_proof : sge_or_max_commute_before ⊑ sge_or_max_commute_after

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

theorem test4_thm (e : IntW 37) : LLVM.xor e (LLVM.xor (const? 37 (-1)) e) ⊑ const? 37 (-1)

theorem e_1516 :
    5 * ( ~~~(a &&&  ~~~b) &&&  ~~~(a ^^^ (b ^^^ c))) - 1 *  ~~~c + 7 * (b ^^^ (a |||  ~~~c)) + 4 * ((a ^^^ b) |||  ~~~(a ^^^ c)) - 2 *  ~~~( ~~~a ||| (b &&& c)) - 15 *  ~~~(a ||| (b ||| c)) - 3 *  ~~~(a ||| ( ~~~b ||| c)) - 8 *  ~~~( ~~~a ||| (b ||| c)) - 16 * ( ~~~a &&& (b &&& c)) - 4 * (a &&& (b &&& c)) = 9 * (a &&& ( ~~~b &&& c)) + 2 *  ~~~( ~~~a ||| ( ~~~b ||| c))

theorem trunc_shl_15_i16_i64_proof : trunc_shl_15_i16_i64_before ⊑ trunc_shl_15_i16_i64_after

theorem sge_swap_and_max_commute_proof : sge_swap_and_max_commute_before ⊑ sge_swap_and_max_commute_after

@[bv_automata_nnf] theorem imp_self_eq (p : Prop) : (p → p) = True

theorem bv_276_2 :
    ∀ (e e_1 : LLVM.IntW 5), LLVM.mul (LLVM.udiv e_1 e) (LLVM.sub (LLVM.const? 5 0) e) ⊑ LLVM.sub (LLVM.urem e_1 e) e_1

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

theorem ashr_ult_2_proof : ashr_ult_2_before ⊑ ashr_ult_2_after

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

theorem e_302 :
     - 1 * x - 7 * (x |||  ~~~y) - 1 *  ~~~(x &&&  ~~~x) - 7 * (x ||| y) + 10 *  ~~~(x |||  ~~~y) + 16 * (x &&&  ~~~y) + 18 * (x &&& y) =  - 10 *  ~~~(x ||| y) + 2 *  ~~~(x &&&  ~~~y)

theorem udiv_shl_mul_nuw_thm (e e_1 e_2 : IntW 5) :
  LLVM.udiv (shl e_2 e_1 { «nsw» := false, «nuw» := true }) (mul e_2 e { «nsw» := false, «nuw» := true }) ⊑
    LLVM.udiv (shl (const? 5 1) e_1 { «nsw» := false, «nuw» := true }) e

theorem select_icmp_eq_and_1_0_lshr_tv_thm.extracted_1._4 : ∀ (x x_1 : BitVec 8),
  ¬ofBool (x_1 &&& 1#8 != 0#8) = 1#1 → ¬(1#8 ≥ ↑8 ∨ x_1 <<< 1#8 &&& 2#8 ≥ ↑8) → x = x >>> (x_1 <<< 1#8 &&& 2#8)

theorem differentconsts_thm (e : IntW 32) :
  select (icmp IntPred.ult (add e (const? 32 16)) (const? 32 144)) (trunc 16 e)
      (select (icmp IntPred.slt e (const? 32 128)) (const? 16 256) (const? 16 (-1))) ⊑
    select (icmp IntPred.sgt e (const? 32 127)) (const? 16 (-1))
      (select (icmp IntPred.slt e (const? 32 (-16))) (const? 16 256) (trunc 16 e))

theorem sgt_negative_multip_rem_zero_thm (e : IntW 8) :
  icmp IntPred.sgt (mul e (const? 8 (-7)) { «nsw» := true, «nuw» := false }) (const? 8 21) ⊑
    icmp IntPred.slt e (const? 8 (-3))

theorem shl_add_and_fail_mismatch_shift_proof : shl_add_and_fail_mismatch_shift_before ⊑ shl_add_and_fail_mismatch_shift_after

theorem lshr_mul_times_3_div_2_exact_proof : lshr_mul_times_3_div_2_exact_before ⊑ lshr_mul_times_3_div_2_exact_after

theorem select_icmp_eq_and_4096_0_or_4096_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (x_1 &&& 4096#32 == 0#32) = 1#1 → x ||

theorem e_1107 :
    11 * (z ^^^ t) + 11 *  ~~~z - 1 * (z |||  ~~~t) - 3 *  ~~~(z ^^^ t) - 12 *  ~~~(z ||| t) - 20 *  ~~~(z |||  ~~~t) - 15 * (z &&&  ~~~t) + 11 * (z &&& t) =  - 5 *  ~~~(z &&& t) + 7 * t

theorem t4_const_after_fold_lshr_shl_ne_thm (e e_1 e_2 : IntW 32) :
  icmp IntPred.ne (LLVM.and (shl e_2 (sub (const? 32 32) e_1)) (lshr e (add e_1 (const? 32 (-1))))) (const? 32 0) ⊑
    icmp IntPred.ne (LLVM.and (lshr e (const? 32 31)) e_2) (const? 32 0)

theorem udiv_shl_mul_nuw_exact_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 5),
  ¬(True ∧ x_2 <<< x_1 >>> x_1 ≠ x_2 ∨
        x_1 ≥ ↑5 ∨ True ∧ x_2.umulOverflow x = true ∨ True ∧ (x_2 <<< x_1).umod (x_2 * x) ≠ 0 ∨ x_2 * x = 0) →
    True ∧ 1#5 <<< x_1 >>> x_1 ≠ 1#5 ∨ x_1 ≥ ↑5 ∨ True ∧ (1#5 <<< x_1).umod x ≠ 0 ∨ x = 0 → False

theorem e_24 :
    7 *  ~~~(x ^^^ y) - 3 * (x ||| y) - 11 * (x ^^^ y) - 7 *  ~~~(x ||| y) + 14 * (x &&&  ~~~y) =  - 14 *  ~~~(x |||  ~~~y) + 4 * (x &&& y)

@[simp]
theorem denote_splitProgramAt [LawfulMonad d.m] {pos : ℕ} {prog : Com d Γ eff t}
    {res : _} (hres : res ∈ splitProgramAt pos prog) :
    res.denote = prog.denote

theorem add_shl_same_amount_partial_nsw1_proof : add_shl_same_amount_partial_nsw1_before ⊑ add_shl_same_amount_partial_nsw1_after

theorem bv_InstCombineShift__440 :
    ∀ (e e_1 e_2 e_3 : LLVM.IntW w),
      LLVM.shl (LLVM.xor e (LLVM.and (LLVM.lshr e_1 e_2) e_3)) e_2 ⊑
        LLVM.xor (LLVM.and e_1 (LLVM.shl e_3 e_2)) (LLVM.shl e e_2)

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

theorem not_not_true_thm.extracted_1._1 : ∀ (x : BitVec 1), ¬x ^^^ 1#1 = 1#1 → ¬x = 1#1 → False

theorem not_mul_of_bool_thm.extracted_1._1 : ∀ (x : BitVec 8) (x_1 : BitVec 32),
  True ∧ (x_1 &&& 3#32).smulOverflow (zeroExtend 32 x) = true ∨
      True ∧ (x_1 &&& 3#32).umulOverflow (zeroExtend 32 x) = true →
    False

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

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

theorem and_xor_commute4_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ¬(x_1 = 0 ∨ x = 0 ∨ x_1 = 0) → x_1 = 0 ∨ x = 0 → False

theorem ashr_ult_2_thm (e : IntW 4) :
  icmp IntPred.ult (ashr e (const? 4 1)) (const? 4 2) ⊑ icmp IntPred.ult e (const? 4 4)

theorem e_437 :
     - 1 * (x ^^^ y) + 1 *  ~~~(x ^^^ y) + 4 *  ~~~x - 6 * (x ||| y) - 1 * (x |||  ~~~y) - 4 *  ~~~(x ||| y) + 8 * (x &&&  ~~~y) + 6 * (x &&& y) =  - 3 *  ~~~(x |||  ~~~y)

theorem test10_proof : test10_before ⊑ test10_after

theorem e_254 :
     - 7 * y - 6 *  ~~~(x &&&  ~~~y) - 7 * (x ^^^ y) - 1 *  ~~~(x ^^^ y) + 12 *  ~~~(x ||| y) + 25 *  ~~~(x |||  ~~~y) + 12 * (x &&&  ~~~y) =  - 19 * (x &&& y) + 5 *  ~~~(x &&&  ~~~x)

theorem p0_thm (e e_1 : IntW 8) :
  icmp IntPred.ult (LLVM.xor (shl (const? 8 (-1)) e_1) (const? 8 (-1))) e ⊑
    icmp IntPred.ne (lshr e e_1) (const? 8 0)

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

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

theorem select_replace_one_use_proof : select_replace_one_use_before ⊑ select_replace_one_use_after

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

theorem eq_umin2_thm (e e_1 : IntW 32) :
  icmp IntPred.eq (select (icmp IntPred.ult e_1 e) e_1 e) e ⊑ icmp IntPred.ule e e_1

theorem and_consts_logical_proof : and_consts_logical_before ⊑ and_consts_logical_after

theorem t0_thm.extracted_1._4 : ∀ (x x_1 x_2 : BitVec 32),
  ¬ofBool (x_2 == x_1) = 1#1 → ¬ofBool (x_2 != x_1) = 1#1 → False

theorem ashrslt_01_14_proof : ashrslt_01_14_before ⊑ ashrslt_01_14_after

theorem lshr_C1_add_A_C2_i32_proof : lshr_C1_add_A_C2_i32_before ⊑ lshr_C1_add_A_C2_i32_after

theorem xor_ashr_not_fail_invalid_xor_constant_thm (e e_1 e_2 : IntW 8) :
  LLVM.xor (ashr e_2 e_1) (LLVM.xor (ashr e e_1) (const? 8 (-2))) ⊑
    LLVM.xor (ashr (LLVM.xor e e_2) e_1) (const? 8 (-2))

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

theorem test11_thm (e : IntW 737) :
  icmp IntPred.ne (LLVM.and e (const? 737 (-2147483648))) (const? 737 0) ⊑
    icmp IntPred.ugt e (const? 737 2147483647)

theorem alive_AndOrXor_2113___A__B__A___A__B : alive_AndOrXor_2113___A__B__A___A__B_src ⊑ alive_AndOrXor_2113___A__B__A___A__B_tgt

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

theorem eq_iff_EqualUpTo (x y : BitStream) :
  x = y ↔ (∀ w, EqualUpTo w x y)

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

theorem sdiv400_yes_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬(2#32 ≥ ↑32 ∨ (100#32 == 0 || 32 != 1 && x >>> 2#32 == intMin 32 && 100#32 == -1) = true) →
    ¬400#32 = 0 → (x >>> 2#32).sdiv 100#32 = x / 400#32

theorem a_false_implies_b_false2_comm_proof : a_false_implies_b_false2_comm_before ⊑ a_false_implies_b_false2_comm_after

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

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

theorem lshrult_03_09_proof : lshrult_03_09_before ⊑ lshrult_03_09_after

theorem le_proof : le_before ⊑ le_after

theorem test33b_proof : test33b_before ⊑ test33b_after

theorem bools_logical_commute0_thm.extracted_1._13 : ∀ (x x_1 x_2 : BitVec 1),
  x_2 ^^^ 1#1 = 1#1 → x_2 = 1#1 → x_1 = 1#1 → 1#1 = x

theorem or_simplify_ult_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ofBool (x_1 &&& BitVec.ofInt 8 (-5) <ᵤ x ||| 36#8 ||| x_1 &&& BitVec.ofInt 8 (-5)) =
    ofBool (x_1 &&& BitVec.ofInt 8 (-5) <ᵤ x ||| x_1 ||| 36#8)

theorem icmp_eq_zext_ne_zero_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (zeroExtend 32 (ofBool (x != 0#32)) == x) = ofBool (x <ᵤ 2#32)

theorem test_nuw_nsw_and_unsigned_pred_proof : test_nuw_nsw_and_unsigned_pred_before ⊑ test_nuw_nsw_and_unsigned_pred_after

theorem urem_i32_multiuse_thm (e e_1 : IntW 8) :
  mul (urem (zext 32 e_1) (zext 32 e)) (add (zext 32 e_1) (zext 32 e)) ⊑
    mul (urem (zext 32 e_1) (zext 32 e)) (add (zext 32 e_1) (zext 32 e) { «nsw» := true, «nuw» := true })
      { «nsw» := true, «nuw» := true }

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

@[simp]
theorem eval_map (fsm : FSM arity) (f : arity → arity')
    (env' : arity' → BitStream):
    (fsm.map f).eval env' = fsm.eval (env' ∘ f)

theorem select_icmp_sgt_allones_smin_flipped_proof : select_icmp_sgt_allones_smin_flipped_before ⊑ select_icmp_sgt_allones_smin_flipped_after

theorem select_icmp_and_2147483648_eq_0_xor_2147483648_proof : select_icmp_and_2147483648_eq_0_xor_2147483648_before ⊑ select_icmp_and_2147483648_eq_0_xor_2147483648_after

theorem logic_and_logic_or_5_proof : logic_and_logic_or_5_before ⊑ logic_and_logic_or_5_after

theorem test10_proof : test10_before ⊑ test10_after

theorem shl_nsw_slt_1_proof : shl_nsw_slt_1_before ⊑ shl_nsw_slt_1_after

theorem and_or2_commuted_proof : and_or2_commuted_before ⊑ and_or2_commuted_after

theorem lshr_and_thm.extracted_1._1 : ∀ (x : BitVec 8), ¬(x ≥ ↑8 ∨ x + 1#8 ≥ ↑8) → x ≥ ↑8 → False

theorem test14_proof : test14_before ⊑ test14_after

theorem test4_proof : test4_before ⊑ test4_after
</all_available_lemmas>

<local_ctx>
import Mathlib.Tactic.NormNum

import Mathlib.Logic.Function.Iterate

section UpStream

namespace Int

end Int

end UpStream

def BitStream : Type := Nat → Bool

namespace BitStream

section Basic

section Lemmas

end Lemmas

end Basic

section OfNat

end OfNat

section ToBitVec

abbrev ofBitVecSext {w} (x : BitVec w) : BitStream :=
  fun i => if i < w then x.getLsbD i else x.msb

section Lemmas

end Lemmas

end ToBitVec

section BitwiseOps

section Lemmas

variable {w : Nat}

variable (x y : BitStream) (i : Nat)

variable (x y : BitVec (w+1))

end Lemmas

end BitwiseOps

section Scan

end Scan

section FindIndex

section Arith

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

def add (x y : BitStream) : BitStream :=
  fun n => (addAux x y n).1

abbrev zero   : BitStream := fun _ => false

section Lemmas

variable {w : Nat} {x y : BitVec w} {a b a' b' : BitStream}

local infix:20 " ≈ʷ " => EqualUpTo w
</local_ctx>

<target_theorem>
theorem ofBitVec_add : ofBitVecSext (x + y) ≈ʷ (ofBitVecSext x) + (ofBitVecSext y) :=
</target_theorem>

