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>
Polynomial.X in Mathlib.Algebra.Polynomial.Basic
ZMod in Mathlib.Data.ZMod.Defs
Nat in Init.Prelude
Ideal in Mathlib.RingTheory.Ideal.Defs
Ideal.Quotient.mk in Mathlib.RingTheory.Ideal.Quotient.Defs
Ideal.span in Mathlib.RingTheory.Ideal.Span
Polynomial in Mathlib.Algebra.Polynomial.Basic
Polynomial.monomial in Mathlib.Algebra.Polynomial.Basic
Int in Init.Data.Int.Basic
List in Init.Prelude
Function.surjInv in Mathlib.Logic.Function.Basic
Polynomial.coeff in Mathlib.Algebra.Polynomial.Basic
Int.cast in Init.Data.Int.Basic
List.toFinsupp in Mathlib.Data.List.ToFinsupp
Polynomial.ofFinsupp in Mathlib.Algebra.Polynomial.Basic
List.length in Init.Prelude
Polynomial.degree in Mathlib.Algebra.Polynomial.Degree.Definitions
WithBot in Mathlib.Order.TypeTags
List.reverseRecOn in Mathlib.Data.List.Induction
List.zipIdx in Init.Data.List.Basic
Polynomial.Monic in Mathlib.Algebra.Polynomial.Degree.Definitions
List.getD in Init.Data.List.BasicAux
Fin in Init.Prelude
OfNat in Init.Prelude
OfNat.ofNat in Init.Prelude
List.map in Init.Prelude
DecidableEq in Init.Prelude
Polynomial.toFinsupp in Mathlib.Algebra.Polynomial.Basic
Semiring in Mathlib.Algebra.Ring.Defs
Finset in Mathlib.Data.Finset.Defs
Nat.cast in Init.Data.Cast

...

checkTimeout

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

def 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 t0_after := [llvm|
{
^0(%arg206 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.add %arg206, %0 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

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

abbrev EnumerativeSearchCache :=  Std.HashMap BVExprWrapper BVExpr.PackedBitVec

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

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

def 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 different_size_zext_zext_sgt_after := [llvm|
{
^0(%arg16 : i7, %arg17 : i4):
  %0 = llvm.zext %arg17 : i4 to i7
  %1 = llvm.icmp "ugt" %arg16, %0 : i7
  "llvm.return"(%1) : (i1) -> ()
}
]

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

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

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

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

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

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

def testi64i32_ne_before := [llvm|
{
^0(%arg7 : i64):
  %0 = llvm.mlir.constant(32) : i64
  %1 = llvm.mlir.constant(31 : i32) : i32
  %2 = llvm.lshr %arg7, %0 : i64
  %3 = llvm.trunc %2 : i64 to i32
  %4 = llvm.trunc %arg7 : i64 to i32
  %5 = llvm.ashr %4, %1 : i32
  %6 = llvm.icmp "ne" %5, %3 : i32
  "llvm.return"(%6) : (i1) -> ()
}
]

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

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

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

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

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

def or_basic_before := [llvm|
{
^0(%arg15 : i16):
  %0 = llvm.mlir.constant(127 : i8) : i8
  %1 = llvm.mlir.constant(-256 : i16) : i16
  %2 = llvm.mlir.constant(17664 : i16) : i16
  %3 = llvm.trunc %arg15 : i16 to i8
  %4 = llvm.icmp "ne" %3, %0 : i8
  %5 = llvm.and %arg15, %1 : i16
  %6 = llvm.icmp "ne" %5, %2 : i16
  %7 = llvm.or %4, %6 : i1
  "llvm.return"(%7) : (i1) -> ()
}
]

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

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

def ugt_swap_and_not_min_logical_before := [llvm|
{
^0(%arg68 : i8, %arg69 : i8):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.mlir.constant(false) : i1
  %2 = llvm.icmp "ult" %arg69, %arg68 : i8
  %3 = llvm.icmp "ne" %arg68, %0 : i8
  %4 = "llvm.select"(%2, %3, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%4) : (i1) -> ()
}
]

IO.FS.Handle in Init.System.IO

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

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

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

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

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

def 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 ashr_eq_msb_low_second_zero_before := [llvm|
{
^0(%arg175 : i8):
  %0 = llvm.mlir.constant(127 : i8) : i8
  %1 = llvm.mlir.constant(0 : i8) : i8
  %2 = llvm.ashr %0, %arg175 : i8
  %3 = llvm.icmp "eq" %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) -> ()
}
]

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

@[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 ashrslt_03_04_exact_before := [llvm|
{
^0(%arg17 : i4):
  %0 = llvm.mlir.constant(3 : i4) : i4
  %1 = llvm.mlir.constant(4 : i4) : i4
  %2 = llvm.ashr exact %arg17, %0 : i4
  %3 = llvm.icmp "slt" %2, %1 : i4
  "llvm.return"(%3) : (i1) -> ()
}
]

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

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

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

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

def udiv_pow2_128 : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64)] where
  lhs := [LV| {
    ^entry (%x: i64):
      %c = llvm.mlir.constant (128) : i64
      %0 = llvm.udiv %x, %c : i64
      llvm.return %0 : i64
  }]
  rhs := [LV| {
    ^entry (%x: i64):
      %c = llvm.mlir.constant (7) : i64
      %0 = llvm.lshr %x, %c : i64
      llvm.return %0 : i64
  }]

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

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

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

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

def and_slt_to_mask_before := [llvm|
{
^0(%arg5 : i8):
  %0 = llvm.mlir.constant(-124 : i8) : i8
  %1 = llvm.mlir.constant(2 : i8) : i8
  %2 = llvm.mlir.constant(0 : i8) : i8
  %3 = llvm.icmp "slt" %arg5, %0 : i8
  %4 = llvm.and %arg5, %1 : i8
  %5 = llvm.icmp "eq" %4, %2 : i8
  %6 = llvm.and %3, %5 : i1
  "llvm.return"(%6) : (i1) -> ()
}
]

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

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

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 llvm_const_lower_riscv_li_7 : LLVMPeepholeRewriteRefine 64 [] :=
  {lhs := constLLVM_7, rhs:= liRiscv_7,
   correct := by admit /- proof elided -/

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

def xor_signbit_shl_after := [llvm|
{
^0(%arg19 : i32):
  %0 = llvm.mlir.constant(8 : i32) : i32
  %1 = llvm.mlir.constant(-16777216 : i32) : i32
  %2 = llvm.shl %arg19, %0 : i32
  %3 = llvm.xor %2, %1 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

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

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

def positive_biggershl_ashrexact_after := [llvm|
{
^0(%arg39 : i8):
  %0 = llvm.mlir.constant(3 : i8) : i8
  %1 = llvm.shl %arg39, %0 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

def add_nsw_poison_constant_fold_after := [llvm|
{
^0(%arg2 : i1, %arg3 : i8):
  %0 = llvm.mlir.constant(64 : i8) : i8
  %1 = llvm.mlir.constant(-127 : i8) : i8
  %2 = llvm.add %arg3, %0 overflow<nsw> : i8
  %3 = "llvm.select"(%arg2, %2, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  "llvm.return"(%3) : (i8) -> ()
}
]

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

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

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

<all_available_lemmas>
List.length_map in Init.Data.List.Lemmas
List.map_append in Init.Data.List.Lemmas
List.map_cons in Init.Data.List.Basic
List.map_nil in Init.Data.List.Basic
List.toFinsupp_concat_eq_toFinsupp_add_single in Mathlib.Data.List.ToFinsupp
Polynomial.ofFinsupp_add in Mathlib.Algebra.Polynomial.Basic
Polynomial.ofFinsupp_single in Mathlib.Algebra.Polynomial.Basic
List.foldl_append in Init.Data.List.Lemmas
List.foldl_cons in Init.Data.List.Basic
List.foldl_nil in Init.Data.List.Basic
List.zipIdx_append in Init.Data.List.Nat.Range
List.zipIdx_cons in Init.Data.List.Basic
List.zipIdx_nil in Init.Data.List.Basic
map_add in Mathlib.Algebra.Group.Hom.Defs
zero_add in Mathlib.Algebra.Group.Defs
Nat.one_le_two_pow in Init.Data.Nat.Lemmas
Nat.sub_add_cancel in Init.Data.Nat.Basic
Polynomial.monic_X_pow_add in Mathlib.Algebra.Polynomial.Monic
Function.surjInv_eq in Mathlib.Logic.Function.Basic
Ideal.mem_span_singleton in Mathlib.RingTheory.Ideal.Span
Polynomial.modByMonic_eq_of_dvd_sub in Mathlib.Algebra.Polynomial.Div
Polynomial.modByMonic_eq_self_iff in Mathlib.Algebra.Polynomial.Div
List.getD_map in Mathlib.Data.List.GetD
List.toFinsupp_apply in Mathlib.Data.List.ToFinsupp
Polynomial.coeff_ofFinsupp in Mathlib.Algebra.Polynomial.Basic
Fin.pos' in Init.Data.Fin.Lemmas
Nat.cast_ofNat in Mathlib.Data.Nat.Cast.Defs
Nat.cast_pow in Mathlib.Data.Nat.Cast.Basic
Polynomial.degree_X_pow in Mathlib.Algebra.Polynomial.Degree.Definitions
Polynomial.degree_add_eq_left_of_degree_lt in Mathlib.Algebra.Polynomial.Degree.Operations
Polynomial.degree_one in Mathlib.Algebra.Polynomial.Degree.Definitions
Finset.max_le in Mathlib.Data.Finset.Max
Finset.mem_filter in Mathlib.Data.Finset.Filter
Finset.mem_insert in Mathlib.Data.Finset.Insert
Finset.mem_range in Mathlib.Data.Finset.Range
Finset.range_add_one in Mathlib.Data.Finset.Range
List.length_cons in Init.Data.List.Basic
Nat.cast_add in Mathlib.Data.Nat.Cast.Defs
Nat.cast_one in Mathlib.Data.Nat.Cast.Defs
Nat.le_add_one_iff in Init.Data.Nat.Lemmas
Nat.le_of_lt in Init.Data.Nat.Basic
Polynomial.support_ofFinsupp in Mathlib.Algebra.Polynomial.Basic
WithBot.coe_le_coe in Mathlib.Order.WithBot
Nat.lt_of_le_of_lt in Init.Prelude
WithBot.coe_strictMono in Mathlib.Order.WithBot
WithBot.lt_def in Mathlib.Order.WithBot

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

theorem ashrslt_02_03_proof : ashrslt_02_03_before ⊑ ashrslt_02_03_after

lemma CNFA.bv_recognizes_functional {m : CNFA n} :
    m.bv_recognizes L₁ → m.bv_recognizes L₂ → L₁ = L₂

theorem or_trunc_lshr_small_mask_proof : or_trunc_lshr_small_mask_before ⊑ or_trunc_lshr_small_mask_after

theorem zext_masked_bit_zero_to_smaller_bitwidth_proof : zext_masked_bit_zero_to_smaller_bitwidth_before ⊑ zext_masked_bit_zero_to_smaller_bitwidth_after

theorem rev8_mul_and_lshr_thm (e : IntW 8) :
  trunc 8
      (lshr
        (mul
          (LLVM.or (LLVM.and (mul (zext 64 e) (const? 64 2050) { «nsw» := true, «nuw» := true }) (const? 64 139536))
            (LLVM.and (mul (zext 64 e) (const? 64 32800) { «nsw» := true, «nuw» := true }) (const? 64 558144)))
          (const? 64 65793) { «nsw» := true, «nuw» := true })
        (const? 64 16)) ⊑
    trunc 8
      (lshr
        (mul
          (LLVM.or (LLVM.and (mul (zext 64 e) (const? 64 2050) { «nsw» := true, «nuw» := true }) (const? 64 139536))
            (LLVM.and (mul (zext 64 e) (const? 64 32800) { «nsw» := true, «nuw» := true }) (const? 64 558144))
            { «disjoint» := true })
          (const? 64 65793) { «nsw» := true, «nuw» := true })
        (const? 64 16))

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

theorem t0_thm.extracted_1._27 : ∀ (x x_1 x_2 x_3 : BitVec 8) (x_4 : BitVec 1),
  x_4 ^^^ 1#1 = 1#1 → ¬x_4 = 1#1 → True → 0#1 = 1#1 → x_1 = x

theorem slt_and_max_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8), ofBool (x_1 <ₛ x) &&& ofBool (x_1 == 127#8) = 0#1

theorem e_1323 :
     - 11 * (z ^^^ t) - 1 * (z |||  ~~~t) - 5 *  ~~~(z &&&  ~~~t) + 2 * (z ||| t) - 11 *  ~~~(z &&& t) + 24 *  ~~~(z ||| t) + 25 *  ~~~(z |||  ~~~t) + 20 * (z &&&  ~~~t) + 10 * (z &&& t) = 7 *  ~~~(z ^^^ t) - 1 * z

theorem lshr_xor_or_good_mask_thm (e e_1 : IntW 8) :
  LLVM.or (lshr e_1 (const? 8 4)) (LLVM.xor (lshr e (const? 8 4)) (const? 8 48)) ⊑
    LLVM.or (lshr (LLVM.or e e_1) (const? 8 4)) (const? 8 48) { «disjoint» := true }

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

theorem logic_or_logic_and_6_thm.extracted_1._3 : ∀ (x x_1 x_2 : BitVec 1), x_2 = 1#1 → ¬x = 1#1 → True → x_2 = 1#1

theorem p_commutative4_proof : p_commutative4_before ⊑ p_commutative4_after

theorem shl_or_with_or_disjoint_instead_of_add_thm.extracted_1._2 : ∀ (x : BitVec 8),
  ¬(x ≥ ↑8 ∨ True ∧ (x &&& 1#8 != 0) = true ∨ x ||| 1#8 ≥ ↑8) →
    ¬x ≥ ↑8 → 16#8 <<< x ||

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

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

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

theorem PR42691_3_proof : PR42691_3_before ⊑ PR42691_3_after

@[aesop 50% unsafe]
theorem Std.HashMap.get?_none_not_mem [BEq K] [LawfulBEq K] [Hashable K] [LawfulHashable K] {m : Std.HashMap K V} {k : K} : m.get? k = none → k ∉ m

theorem alive_820   : alive_820_src ⊑ alive_820_tgt

theorem main5f_like_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 32),
  ofBool (x_2 &&& x_1 != x_2) ||

theorem test5_proof : test5_before ⊑ test5_after

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

@[simp]
theorem EnvFin.eq_elim0 (envFin : EnvFin w 0) : envFin = fun i => i.elim0

theorem n8_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 1#32 == 1#32) = 1#1 → ¬2#32 ≥ ↑32 → ofBool (x &&& 1#32 == 0#32) = 1#1 → x >>> 2#32 &&& 1#32 = 1#32

theorem test_shift_and_cmp_changed1_thm (e e_1 : IntW 8) :
  icmp IntPred.slt
      (ashr (shl (LLVM.or (LLVM.and e_1 (const? 8 8)) (LLVM.and e (const? 8 6))) (const? 8 5)) (const? 8 5))
      (const? 8 1) ⊑
    icmp IntPred.slt (LLVM.and (shl e (const? 8 5)) (const? 8 (-64))) (const? 8 32)

theorem add_signbit_shl_thm (e : IntW 32) :
  shl (add e (const? 32 (-65536))) (const? 32 8) ⊑ add (shl e (const? 32 8)) (const? 32 (-16777216))

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 e_243 :
    2 *  ~~~(x &&&  ~~~y) + 1 *  ~~~(x &&&  ~~~x) - 1 *  ~~~x - 2 *  ~~~(x ||| y) + 3 *  ~~~(x |||  ~~~y) + 4 * (x &&&  ~~~y) + 2 * (x &&& y) = 5 * (x ||| y)

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 add_shl_same_amount_partial_nsw1_proof : add_shl_same_amount_partial_nsw1_before ⊑ add_shl_same_amount_partial_nsw1_after

theorem uge_or_not_max_commute_proof : uge_or_not_max_commute_before ⊑ uge_or_not_max_commute_after

theorem e_1439 :
    2 *  ~~~t + 1 *  ~~~(z &&& t) + 1 * (z |||  ~~~t) + 7 *  ~~~(z ^^^ t) - 1 *  ~~~(z &&&  ~~~z) + 3 * (z ^^^ t) - 2 * z - 3 *  ~~~(z |||  ~~~t) - 4 * (z &&&  ~~~t) - 5 * (z &&& t) = 10 *  ~~~(z ||| t)

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

theorem uge_or_not_max_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8), ofBool (x ≤ᵤ x_1) ||

theorem e_1109 :
    1 *  ~~~(z &&&  ~~~z) - 6 *  ~~~z + 4 * (z ||| t) + 11 * (z |||  ~~~t) + 11 * z - 6 *  ~~~(z ||| t) + 1 *  ~~~(z |||  ~~~t) - 27 * (z &&& t) = 27 * (z &&&  ~~~t)

theorem lshrult_02_12_proof : lshrult_02_12_before ⊑ lshrult_02_12_after

theorem select_icmp_ne_0_and_32_or_4096_thm (e e_1 : IntW 32) :
  select (icmp IntPred.ne (const? 32 0) (LLVM.and e_1 (const? 32 32))) e (LLVM.or e (const? 32 4096)) ⊑
    LLVM.or e (LLVM.xor (LLVM.and (shl e_1 (const? 32 7)) (const? 32 4096)) (const? 32 4096))

theorem test1_proof : test1_before ⊑ test1_after

theorem sub_ashr_or_i32_commute_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬(True ∧ x.ssubOverflow x_1 = true ∨ 31#32 ≥ ↑32) →
    ¬ofBool (x <ₛ x_1) = 1#1 → x_1 ||

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

theorem negate_sdiv_thm.extracted_1._2 : ∀ (x x_1 : BitVec 8),
  ¬(42#8 == 0 || 8 != 1 && x == intMin 8 && 42#8 == -1) = true →
    ¬(BitVec.ofInt 8 (-42) == 0 || 8 != 1 && x == intMin 8 && BitVec.ofInt 8 (-42) == -1) = true →
      x_1 - x.sdiv 42#8 = x.sdiv (BitVec.ofInt 8 (-42)) + x_1

theorem or_and_or_pat7_proof : or_and_or_pat7_before ⊑ or_and_or_pat7_after

theorem cv2_thm (e e_1 : IntW 8) :
  icmp IntPred.ule (LLVM.and (lshr (const? 8 (-1)) e_1) e) e ⊑ const? 1 1

theorem ashrsgt_02_04_exact_thm (e : IntW 4) :
  icmp IntPred.sgt (ashr e (const? 4 2) { «exact» := true }) (const? 4 4) ⊑ const? 1 0

theorem e_225 :
     - 3 * (x ||| y) - 1 *  ~~~y + 3 * (x |||  ~~~y) + 5 *  ~~~(x &&&  ~~~y) - 10 *  ~~~(x ||| y) + 3 * (x &&&  ~~~y) - 10 * (x &&& y) =  - 5 *  ~~~(x ^^^ y) + 2 *  ~~~(x &&& y)

theorem uge_swap_or_max_logical_proof : uge_swap_or_max_logical_before ⊑ uge_swap_or_max_logical_after

theorem ashrslt_01_05_proof : ashrslt_01_05_before ⊑ ashrslt_01_05_after

theorem test_sdiv_canonicalize_op0_thm (e e_1 : IntW 32) :
  LLVM.sdiv (sub (const? 32 0) e_1 { «nsw» := true, «nuw» := false }) e ⊑
    sub (const? 32 0) (LLVM.sdiv e_1 e) { «nsw» := true, «nuw» := false }

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

theorem test2_thm.extracted_1._1 : ∀ (x x_1 : BitVec 1), x_1 &&& x &&& x_1 = x_1 &&& x

protected theorem carry_eq_carry (x y : BitStream) (c : Bool)
    (x' y' : BitVec w)
    (hx : ∀ i, x'.getLsbD i = x i)
    (hy : ∀ i,  y'.getLsbD i = y i) :
    carry c x y n = (BitVec.carry (n + 1) x' y' c)

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

theorem demorgan_nor_use2c_proof : demorgan_nor_use2c_before ⊑ demorgan_nor_use2c_after

theorem main3_logical_thm.extracted_1._4 : ∀ (x : BitVec 32),
  ¬ofBool (x &&& 7#32 == 0#32) = 1#1 → ¬0#1 = 1#1 → 1#32 = zeroExtend 32 (ofBool (x &&& 55#32 != 0#32))

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

theorem e_2448 :
     - 2 *  ~~~(d ^^^ e) - 1 * (f ^^^  ~~~(d &&& (e &&& f))) + 11 * (f ^^^  ~~~( ~~~d &&& (e &&& f))) - 7 * (d ^^^ f) + 2 * ( ~~~(d |||  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) + 1 *  ~~~(d ||| ( ~~~e &&& f)) - 11 * ( ~~~(d ^^^ e) &&&  ~~~(d ^^^ f)) - 5 * (e ^^^  ~~~( ~~~d ||| (e ^^^ f))) + 2 * (e &&& (d ^^^ f)) + 5 *  ~~~(d ^^^ ( ~~~e &&& f)) + 2 *  ~~~(d &&& (e ||| f)) + 1 * ((d ||| e) &&& (d ^^^ (e ^^^ f))) + 5 * ((d |||  ~~~e) &&&  ~~~(d ^^^ (e ^^^ f))) - 1 * (f ^^^  ~~~(d &&& (e ||| f))) - 2 * (e &&& f) - 2 * ((d ^^^ e) &&& (d ^^^ f)) + 1 * ((e &&&  ~~~f) |||  ~~~( ~~~d ||| ( ~~~e &&& f))) - 1 *  ~~~(d ^^^ f) - 6 * (f ^^^  ~~~(d ||| e)) - 1 * (d &&&  ~~~e) - 2 *  ~~~(d &&& ( ~~~e &&& f)) - 1 * (f ^^^ ( ~~~d &&& ( ~~~e ||| f))) + 2 * ( ~~~e |||  ~~~(d ^^^ f)) + 7 * ( ~~~(d ^^^ e) ||| (d ^^^ f)) + 11 * (e ^^^  ~~~( ~~~d ||| ( ~~~e &&& f))) + 1 * ((e &&&  ~~~f) ^^^ ( ~~~d ||| (e ^^^ f))) - 11 *  ~~~(d ^^^ (e ^^^ f)) - 6 * ( ~~~f &&& (d ^^^ e)) + 5 * (f ^^^  ~~~( ~~~d ||| ( ~~~e &&& f))) - 6 * (d ||| ( ~~~e &&& f)) + 7 * (e ^^^ (d ||| ( ~~~e ||| f))) - 2 * ((d &&&  ~~~e) ||| (d ^^^ (e ^^^ f))) - 6 * ((d ^^^ e) ||| (d ^^^ f)) + 4 * ( ~~~(d &&& e) &&&  ~~~(d ^^^ (e ^^^ f))) + 3 * (e ^^^  ~~~(d ||| f)) - 3 * ( ~~~(d |||  ~~~e) |||  ~~~(e ^^^ f)) - 7 * (f ^^^ (d &&& ( ~~~e ||| f))) + 4 * (d |||  ~~~f) - 3 * ((d ||| e) &&&  ~~~(e ^^^ f)) - 1 * (f ^^^ ( ~~~d ||| ( ~~~e &&& f))) + 11 * ((d &&& e) ||| (d ^^^ (e ^^^ f))) - 7 * (f &&&  ~~~(d ^^^ e)) - 1 * ((d &&& f) ^^^ (e ||| f)) + 1 * (f ^^^  ~~~(d &&& e)) + 1 * ( ~~~d ||| (e &&& f)) - 2 *  ~~~( ~~~d &&& (e ||| f)) - 1 * ((d &&& e) ^^^ (e |||  ~~~f)) + 7 * ( ~~~d &&& (e ||| f)) + 1 * (f ^^^ ( ~~~d ||| ( ~~~e ||| f))) - 1 * (e |||  ~~~(d ^^^ f)) - 1 * ((d |||  ~~~e) &&& (e ^^^ f)) + 3 *  ~~~(d &&&  ~~~d) - 3 *  ~~~( ~~~d ||| (e &&& f)) - 2 * ((d &&&  ~~~e) |||  ~~~(e ^^^ f)) + 1 * (f ^^^  ~~~(d &&&  ~~~e)) + 3 * (e |||  ~~~(d ||| f)) - 5 * ((e &&&  ~~~f) ^^^ (d ||| (e ^^^ f))) + 2 * ( ~~~(d &&& e) &&&  ~~~(e ^^^ f)) + 2 * (f |||  ~~~(d ^^^ e)) - 3 * (d ||| (e &&& f)) + 11 * ((d &&& f) ^^^ (d ^^^ (e &&& f))) + 11 * (e ^^^ (d &&& f)) + 4 * (f ^^^  ~~~(d ||| (e &&& f))) + 7 *  ~~~( ~~~d &&& ( ~~~e ||| f)) - 1 * ((d &&& e) |||  ~~~(d ^^^ (e ^^^ f))) - 3 * ((e &&& f) ||| (d &&& (e ||| f))) + 1 * ((d ^^^ e) &&&  ~~~(d ^^^ f)) + 2 * (e ^^^  ~~~(d &&& (e ^^^ f))) + 1 * ((e &&& f) ||| ( ~~~d &&& (e ||| f))) - 27 *  ~~~(d ||| (e ||| f)) - 68 *  ~~~(d ||| ( ~~~e ||| f)) - 21 *  ~~~( ~~~d ||| (e ||| f)) - 37 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 6 * ( ~~~d &&& ( ~~~e &&& f)) - 33 * ( ~~~d &&& (e &&& f)) - 8 * (d &&& ( ~~~e &&& f)) + 3 * (d &&& (e &&& f)) =  - 1 * (e ^^^ ( ~~~d &&& (e ||| f)))

theorem main4b_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬ofBool (x &&& 7#32 == 7#32) &&& ofBool (x &&& 16#32 != 0#32) = 1#1 →
    1#32 = zeroExtend 32 (ofBool (x &&& 23#32 != 23#32))

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

theorem select_add_icmp_bad_proof : select_add_icmp_bad_before ⊑ select_add_icmp_bad_after

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

theorem bitwise_and_logical_and_masked_icmp_allones_poison1_thm.extracted_1._4 : ∀ (x : BitVec 1) (x_1 x_2 : BitVec 32),
  ofBool (x_2 &&& x_1 == x_1) = 1#1 →
    ¬ofBool (x_2 &&& (x_1 ||| 7#32) == x_1 ||| 7#32) = 1#1 → x &&& ofBool (x_2 &&& 7#32 == 7#32) = 0#1

theorem sub_ashr_and_i64_thm.extracted_1._2 : ∀ (x x_1 : BitVec 64),
  ¬(True ∧ x_1.ssubOverflow x = true ∨ 63#64 ≥ ↑64) →
    ¬ofBool (x_1 <ₛ x) = 1#1 → (x_1 - x).sshiftRight' 63#64 &&& x = 0#64

theorem srem_common_dividend_defined_cond_proof : srem_common_dividend_defined_cond_before ⊑ srem_common_dividend_defined_cond_after

theorem shift_no_xor_multiuse_xor_thm.extracted_1._4 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (x_1 &&& 1#32 == 0#32) = 1#1 →
    ¬1#32 ≥ ↑32 → (x ^^^ 2#32) * (x ^^^ 2#32) = (x ^^^ x_1 <<< 1#32 &&& 2#32) * (x ^^^ 2#32)

theorem test6_thm (e : IntW 32) :
  icmp IntPred.ugt (LLVM.udiv (const? 32 5) e) (const? 32 0) ⊑ icmp IntPred.ult e (const? 32 6)

theorem ule_swap_or_min_logical_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ofBool (x ≤ᵤ x_1) = 1#1 → 1#1 = ofBool (x ≤ᵤ x_1)

theorem test1_proof : test1_before ⊑ test1_after

theorem e_1078 :
     - 2 *  ~~~z + 1 *  ~~~(z &&&  ~~~z) - 3 * z - 1 *  ~~~(z &&&  ~~~t) + 7 * (z ||| t) + 2 *  ~~~(z ||| t) + 6 *  ~~~(z |||  ~~~t) - 5 * (z &&&  ~~~t) =  - 7 * (z &&& t) + 11 * t

theorem trunc_sel_equal_zext_thm.extracted_1._2 : ∀ (x : BitVec 32) (x_1 : BitVec 1),
  x_1 = 1#1 → zeroExtend 32 (truncate 16 x) = x &&& 65535#32

theorem test4_proof : test4_before ⊑ test4_after

theorem f_thm (e : IntW 32) :
  select (icmp IntPred.slt e (const? 32 0)) (const? 1 1) (icmp IntPred.sgt e (ashr (const? 32 7) e)) ⊑
    select (icmp IntPred.slt e (const? 32 0)) (const? 1 1)
      (icmp IntPred.sgt e (lshr (const? 32 7) e))

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 and_orn_xor_thm (e e_1 : IntW 4) :
  LLVM.and (LLVM.or (LLVM.xor e_1 (const? 4 (-1))) e) (LLVM.xor e_1 e) ⊑
    LLVM.and e (LLVM.xor e_1 (const? 4 (-1)))

theorem test_add_nuw__all_are_safe_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 1073741823#32 == 3#32) = 1#1 →
    True ∧ (x &&& 1073741823#32).saddOverflow 1#32 = true ∨ True ∧ (x &&& 1073741823#32).uaddOverflow 1#32 = true →
      False

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 factorize3_proof : factorize3_before ⊑ factorize3_after

theorem lshrult_03_09_proof : lshrult_03_09_before ⊑ lshrult_03_09_after

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

@[simp, defeq] theorem entries_eqvVar : (eqvVarLeft mapOut).val.entries = mapOut.val.entries

@[simp]
theorem not_bne' {a b : Bool} : (!bne a b) = (a == b)

theorem masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_1_proof : masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_1_before ⊑ masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_1_after

theorem zext_sext_add_icmp_eq_1_thm.extracted_1._1 : ∀ (x x_1 : BitVec 1),
  ofBool (zeroExtend 8 x_1 + signExtend 8 x == 1#8) = x_1 &&& (x ^^^ 1#1)

theorem urem_illegal_type_proof : urem_illegal_type_before ⊑ urem_illegal_type_after

theorem or_xor_tree_1001_proof : or_xor_tree_1001_before ⊑ or_xor_tree_1001_after

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

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

theorem 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 e_678 :
    1 * x + 1 * y - 1 * (x |||  ~~~y) - 1 * (x ||| y) - 7 *  ~~~(x ^^^ y) - 7 *  ~~~x + 22 *  ~~~(x ||| y) + 8 *  ~~~(x |||  ~~~y) + 7 * (x &&&  ~~~y) + 8 * (x &&& y) = 6 *  ~~~y + 1 *  ~~~(x &&&  ~~~y)
</all_available_lemmas>

<local_ctx>
import Mathlib.RingTheory.Polynomial.Quotient

import Mathlib.RingTheory.Ideal.Defs

import Mathlib.RingTheory.Ideal.Basic

import Mathlib.Data.ZMod.Defs

import Mathlib.Data.ZMod.Basic

import Mathlib.Algebra.MonoidAlgebra.Basic

import Mathlib.Algebra.Polynomial.RingDivision

import Mathlib.Data.Finset.Sort

import Mathlib.Data.List.ToFinsupp

import Mathlib.Data.List.Basic

import Mathlib.Tactic.Cases

import LeanMLIR.Framework

open Polynomial -- for R[X] notation

section CommRing

variable (q t : Nat) [Fact (q > 1)] (n : Nat)

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

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

abbrev R.fromPoly {q n : Nat} : (ZMod q)[X] →+* R q n := Ideal.Quotient.mk (Ideal.span {f q n})

end CommRing

section Representative

variable (q t n : Nat)

private noncomputable def R.representative' :
    R q n → (ZMod q)[X] := Function.surjInv (R.surjective_fromPoly q n)

noncomputable def R.representative :
    R q n → (ZMod q)[X] := fun x => R.representative' q n x %ₘ (f q n)

variable [Fact (q > 1)]

end Representative

section Coeff

noncomputable def R.coeff {q n} (a : R q n) (i : Nat) : ZMod q :=
  Polynomial.coeff a.representative i

noncomputable def R.monomial {q n : Nat} (c : ZMod q) (i : Nat): R q n :=
  R.fromPoly (Polynomial.monomial i c)

noncomputable def R.fromTensor {q n} (coeffs : List Int) : R q n :=
  coeffs.zipIdx.foldl (init := 0) fun res (c, i) =>
    res + R.monomial ↑c i

end Coeff

section FinnSupp

variable {q n : Nat}

noncomputable def R.fromTensorFinsupp (q : Nat) (coeffs : List Int) : (ZMod q)[X] :=
  Polynomial.ofFinsupp (List.toFinsupp (coeffs.map Int.cast))

end FinnSupp

section Tensor

variable {q n : Nat} [Fact (q > 1)]
</local_ctx>

<target_theorem>
theorem R.coeff_fromTensor (tensor : List Int)
    (htensorlen : tensor.length < 2^n) :
    (R.fromTensor (q := q) (n := n) tensor).coeff i = (tensor.getD i 0) :=
</target_theorem>

