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>
Array in Init.Prelude
Array.emptyWithCapacity in Init.Prelude
Nat in Init.Prelude
BEq in Init.Prelude
DecidableEq in Init.Prelude
FinEnum in Mathlib.Data.FinEnum
Hashable in Init.Prelude
Repr in Init.Data.Repr
Std.HashMap in Std.Data.HashMap.Basic
Std.HashSet in Std.Data.HashSet.Basic
BitVec in Init.Prelude
Prod in Init.Prelude
Prod.mk in Init.Prelude
Bool in Init.Prelude
Classical.propDecidable in Init.Classical
Decidable in Init.Prelude
NFA in Mathlib.Computability.NFA
Set in Mathlib.Data.Set.Defs
SetRel in Mathlib.Data.Rel
List in Init.Prelude
Subtype in Init.Prelude
LawfulBEq in Init.Core
Function.Injective2 in Mathlib.Logic.Function.Basic
List.Nodup in Init.Data.List.Basic
FinEnum.toList in Mathlib.Data.FinEnum

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

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

abbrev State := Nat

def product (final? : Prop → Prop → Prop) (M N : NFA' n) : NFA' n where
  σ := _
  M := M.M.product final? N.M

structure NFA' (n : Nat) where
  σ : Type
  M : NFA (BitVec n) σ

def nfa : NFA A S where
  start := { sa | sa ∈ inits }
  accept := { sa | final sa }
  step sa a := { sa' | (a, sa') ∈ f sa }

def Std.HashSet.toSet [BEq α] [Hashable α] (m : HashSet α) : Set α := { x | x ∈ m }

axiom hashMap_missing : ∀ {P : Prop}, P

Id in Init.Control.Id

def src_is_mask_select_after := [llvm|
{
^0(%arg110 : i8, %arg111 : i8, %arg112 : i1):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.mlir.constant(15 : i8) : i8
  %2 = llvm.mlir.constant(123 : i8) : i8
  %3 = llvm.add %arg111, %0 : i8
  %4 = llvm.xor %arg111, %3 : i8
  %5 = "llvm.select"(%arg112, %4, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  %6 = llvm.xor %arg110, %2 : i8
  %7 = llvm.icmp "ugt" %6, %5 : i8
  "llvm.return"(%7) : (i1) -> ()
}
]

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

def logic_or_logic_and_8_before := [llvm|
{
^0(%arg66 : i1, %arg67 : i1, %arg68 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.mlir.constant(false) : i1
  %2 = "llvm.select"(%arg66, %0, %arg67) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %3 = "llvm.select"(%arg68, %0, %arg66) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %4 = "llvm.select"(%3, %2, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%4) : (i1) -> ()
}
]

def ashr_ugt_12_after := [llvm|
{
^0(%arg102 : i4):
  %0 = llvm.mlir.constant(-7 : i4) : i4
  %1 = llvm.icmp "ugt" %arg102, %0 : i4
  "llvm.return"(%1) : (i1) -> ()
}
]

@[match_pattern] def ashr (w : Width φ)
  (ExactFlag : ExactFlag := {exact := false} ) : MOp φ
    := .binary w (.ashr ExactFlag )

def test2_after := [llvm|
{
^0(%arg4 : i16, %arg5 : i16):
  %0 = llvm.add %arg4, %arg5 : i16
  "llvm.return"(%0) : (i16) -> ()
}
]

def select_zext_different_condition_before := [llvm|
{
^0(%arg15 : i1, %arg16 : i1):
  %0 = llvm.mlir.constant(64) : i64
  %1 = llvm.mlir.constant(1) : i64
  %2 = "llvm.select"(%arg15, %0, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i64, i64) -> i64
  %3 = llvm.zext %arg16 : i1 to i64
  %4 = llvm.add %2, %3 : i64
  "llvm.return"(%4) : (i64) -> ()
}
]

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

def liRiscv36 := [LV| {
  ^entry ():
    %0 = "li"() {imm = 36 : !i64} : (!i64) -> (!i64)
    %1 = "builtin.unrealized_conversion_cast"(%0) : (!i64) -> (i64)
    llvm.return %1 : i64
  }]

def llvm_shl_lower_riscv_nsw_nuw_64: LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64), Ty.llvm (.bitvec 64)] where
  lhs := shl_llvm_nsw_nuw_64
  rhs := shl_riscv_64

def fold_sext_to_and_wrong9_before := [llvm|
{
^0(%arg1 : i8):
  %0 = llvm.mlir.constant(128 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.sext %arg1 : i8 to i32
  %3 = llvm.and %2, %0 : i32
  %4 = llvm.icmp "ne" %3, %1 : i32
  "llvm.return"(%4) : (i1) -> ()
}
]

def not_and_and_or_not_or_or_commute1_before := [llvm|
{
^0(%arg238 : i32, %arg239 : i32, %arg240 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.or %arg238, %arg239 : i32
  %2 = llvm.or %1, %arg240 : i32
  %3 = llvm.xor %2, %0 : i32
  %4 = llvm.xor %arg238, %0 : i32
  %5 = llvm.and %4, %arg239 : i32
  %6 = llvm.and %5, %arg240 : i32
  %7 = llvm.or %6, %3 : i32
  "llvm.return"(%7) : (i32) -> ()
}
]

@[inline]
def CNFA.proj (m: CNFA n2) (f : Fin n1 → Fin n2) : CNFA n1 :=
  ⟨m.m.proj f, m.m.proj_wf m.wf⟩

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

def runPreprocessing (g : MVarId) : MetaM (Option MVarId) := do
  let some ext ← (getSimpExtension? `bv_automata_preprocess)
    | throwError m!"'bv_automata_preprocess' simp attribute not found!"
  let theorems ← ext.getTheorems
  let some ext ← (Simp.getSimprocExtension? `bv_automata_preprocess)
    | throwError m!" 'bv_automata_preprocess' simp attribute not found!"
  let simprocs ← ext.getSimprocs
  let config : Simp.Config := { }
  let config := { config with failIfUnchanged := false }
  let ctx ← Simp.mkContext (config := config)
    (simpTheorems := #[theorems])
    (congrTheorems := ← Meta.getSimpCongrTheorems)
  match ← simpGoal g ctx (simprocs := #[simprocs]) with
  | (none, _) => return none
  | (some (_newHyps, g'), _) => pure g'

def and_or_not_not_commute7_after := [llvm|
{
^0(%arg354 : i32, %arg355 : i32, %arg356 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.or %arg356, %arg355 : i32
  %2 = llvm.and %1, %arg354 : i32
  %3 = llvm.xor %2, %0 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def or_not_and_commute3_after := [llvm|
{
^0(%arg528 : i32, %arg529 : i32, %arg530 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg529, %arg530 : i32
  %2 = llvm.xor %arg528, %0 : i32
  %3 = llvm.and %1, %2 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def test7_before := [llvm|
{
^0(%arg202 : i32, %arg203 : i32):
  %0 = llvm.mlir.constant(7 : i32) : i32
  %1 = llvm.mlir.constant(128 : i32) : i32
  %2 = llvm.and %arg202, %0 : i32
  %3 = llvm.and %arg203, %1 : i32
  %4 = llvm.xor %2, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def main7g_logical_after := [llvm|
{
^0(%arg29 : i32, %arg30 : i32, %arg31 : i32, %arg32 : i32, %arg33 : i32):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.and %arg30, %arg32 : i32
  %2 = llvm.and %arg31, %arg33 : i32
  %3 = llvm.and %1, %arg29 : i32
  %4 = llvm.icmp "ne" %1, %3 : i32
  %5 = llvm.and %2, %arg29 : i32
  %6 = llvm.icmp "ne" %2, %5 : i32
  %7 = "llvm.select"(%4, %0, %6) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %8 = llvm.zext %7 : i1 to i32
  "llvm.return"(%8) : (i32) -> ()
}
]

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

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

def PR42691_8_logical_before := [llvm|
{
^0(%arg328 : i32):
  %0 = llvm.mlir.constant(14 : i32) : i32
  %1 = llvm.mlir.constant(-2147483648 : i32) : i32
  %2 = llvm.mlir.constant(false) : i1
  %3 = llvm.icmp "slt" %arg328, %0 : i32
  %4 = llvm.icmp "ne" %arg328, %1 : i32
  %5 = "llvm.select"(%3, %4, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%5) : (i1) -> ()
}
]

def worklistRun'_spec :
    (worklistRun' A S final inits hinits f |>.Sim $ nfa inits final f) :=

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

def positive_biggershl_shlnsw_ashrexact_after := [llvm|
{
^0(%arg34 : i8):
  %0 = llvm.mlir.constant(3 : i8) : i8
  %1 = llvm.shl %arg34, %0 overflow<nsw> : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

instance : Inhabited (
  {lets : Lets d Γstart .pure Γ} →
  State d lets →
  (com: Com d Γ .pure α) →
  { com' : Com d Γ .pure α // ∀ (V: Ctxt.Valuation Γ), com.denote V = com'.denote V }) where
  default := fun _s com => ⟨com, by admit /- proof elided -/
  ⟩

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

def uaddo_commute4_before := [llvm|
{
^0(%arg22 : i32, %arg23 : i32, %arg24 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg23, %0 : i32
  %2 = llvm.add %arg23, %arg22 : i32
  %3 = llvm.icmp "ult" %1, %arg22 : i32
  %4 = "llvm.select"(%3, %arg24, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%4) : (i32) -> ()
}
]

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

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

inductive BasicBlock
  | mk (label : BlockLabel) (args : List VarName) (body : Body)

def binop_same_val_and : RISCVPeepholeRewrite [Ty.riscv (.bv)] where
  lhs := [LV| {
    ^entry (%x: !riscv.reg):
      %0 = and %x, %x : !riscv.reg
      ret %0 : !riscv.reg
  }]
  rhs := [LV| {
    ^entry (%x: !riscv.reg):
      ret %x : !riscv.reg
  }]

def zext_ult_zext_before := [llvm|
{
^0(%arg159 : i1, %arg160 : i8):
  %0 = llvm.mul %arg160, %arg160 : i8
  %1 = llvm.zext %arg159 : i1 to i16
  %2 = llvm.zext %0 : i8 to i16
  %3 = llvm.icmp "ult" %2, %1 : i16
  "llvm.return"(%3) : (i1) -> ()
}
]

Lean.levelZero in Lean.Level

def masked_or_allones_after := [llvm|
{
^0(%arg127 : i32):
  %0 = llvm.mlir.constant(7 : i32) : i32
  %1 = llvm.and %arg127, %0 : i32
  %2 = llvm.icmp "eq" %1, %0 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

def negNumToTerm : TSyntax ``neg_num → MacroM Term
  | `(neg_num| $x:num) => `($x:num)
  | `(neg_num| -$x:num) => `(-$x:num)
  | _ => Macro.throwUnsupported

def t7_twoshifts2_after := [llvm|
{
^0(%arg28 : i32, %arg29 : i32, %arg30 : i32, %arg31 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.shl %0, %arg29 overflow<nuw> : i32
  %3 = llvm.shl %arg30, %arg31 : i32
  %4 = llvm.and %3, %2 : i32
  %5 = llvm.icmp "eq" %4, %1 : i32
  "llvm.return"(%5) : (i1) -> ()
}
]

def or_xor_and_commuted2_before := [llvm|
{
^0(%arg48 : i32, %arg49 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.mul %arg49, %arg49 : i32
  %2 = llvm.mul %arg48, %arg48 : i32
  %3 = llvm.xor %1, %0 : i32
  %4 = llvm.xor %2, %3 : i32
  %5 = llvm.or %4, %1 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

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

def test_mul_nuw__all_are_safe_before := [llvm|
{
^0(%arg14 : i32):
  %0 = llvm.mlir.constant(255 : i32) : i32
  %1 = llvm.mlir.constant(17 : i32) : i32
  %2 = llvm.mlir.constant(9 : i32) : i32
  %3 = llvm.mlir.constant(153 : i32) : i32
  %4 = llvm.and %arg14, %0 : i32
  %5 = llvm.icmp "eq" %4, %1 : i32
  %6 = llvm.mul %4, %2 overflow<nuw> : i32
  %7 = "llvm.select"(%5, %3, %6) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%7) : (i32) -> ()
}
]

def ashrslt_02_01_exact_after := [llvm|
{
^0(%arg36 : i4):
  %0 = llvm.mlir.constant(4 : i4) : i4
  %1 = llvm.icmp "slt" %arg36, %0 : i4
  "llvm.return"(%1) : (i1) -> ()
}
]

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

instance : LawfulGetElem (Ctxt Ty) Nat Ty (fun as i => i < as.length) where
  getElem?_def Γ i _ := by admit /- proof elided -/

def in_constant_varx_6_invmask_before := [llvm|
{
^0(%arg39 : i4, %arg40 : i4):
  %0 = llvm.mlir.constant(-1 : i4) : i4
  %1 = llvm.mlir.constant(6 : i4) : i4
  %2 = llvm.xor %arg40, %0 : i4
  %3 = llvm.xor %arg39, %1 : i4
  %4 = llvm.and %3, %2 : i4
  %5 = llvm.xor %4, %1 : i4
  "llvm.return"(%5) : (i4) -> ()
}
]

def trunc_equality_nsw_zext_after := [llvm|
{
^0(%arg16 : i32, %arg17 : i8):
  %0 = llvm.zext %arg17 : i8 to i32
  %1 = llvm.icmp "ne" %arg16, %0 : i32
  "llvm.return"(%1) : (i1) -> ()
}
]

def llvm_mul_lower_riscv_nsw_flag_32 : LLVMPeepholeRewriteRefine 32 [Ty.llvm (.bitvec 32), Ty.llvm (.bitvec 32)] where
  lhs := mul_llvm_nsw_32
  rhs := mul_riscv_32

def select_icmp_eq_0_and_1_xor_1_after := [llvm|
{
^0(%arg213 : i64, %arg214 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.trunc %arg213 : i64 to i32
  %2 = llvm.and %1, %0 : i32
  %3 = llvm.xor %arg214, %2 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def andcond.100.inv.inner.cond.in.outer.cond_before := [llvm|
{
^0(%arg55 : i1, %arg56 : i1, %arg57 : i8, %arg58 : i8, %arg59 : i8):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.mlir.constant(false) : i1
  %2 = llvm.xor %arg55, %0 : i1
  %3 = "llvm.select"(%2, %arg56, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %4 = "llvm.select"(%arg55, %arg57, %arg58) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  %5 = "llvm.select"(%3, %arg59, %4) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  "llvm.return"(%5) : (i8) -> ()
}
]

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

def liRiscv_22 := [LV| {
  ^entry ():
    %0 = "li"() {imm = -22 : !i64} : (!i64) -> (!i64)
    %1 = "builtin.unrealized_conversion_cast"(%0) : (!i64) -> (i64)
    llvm.return %1 : i64
  }]

def foo : Nat := 42

def n0_before := [llvm|
{
^0(%arg9 : i8, %arg10 : i8):
  %0 = llvm.mlir.constant(1 : i8) : i8
  %1 = llvm.mlir.constant(-1 : i8) : i8
  %2 = llvm.shl %0, %arg10 : i8
  %3 = llvm.xor %2, %1 : i8
  %4 = llvm.icmp "ult" %3, %arg9 : i8
  "llvm.return"(%4) : (i1) -> ()
}
]

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

instance : DialectParse TestDialect 0 where
  mkTy
    | .undefined "int" => return .int
    | .undefined "int2" => return .int2
    | _ => throw .unsupportedType
  isValidReturn _ stx := return (stx.name == "return")
  mkExpr Γ opStx := do
    let op : TestDialect.Op ← match opStx.name with
      | "noop"     => pure .noop
      | "unpair"   => pure .unPair
      | "pair"     => pure .mkPair
      | opName => throw <| .unsupportedOp opName
    opStx.mkExprOf Γ op

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

def Expr.HasPureOp (e : Expr d Γ eff ty) : Prop :=
  DialectSignature.effectKind e.op = .pure

def basic_before := [llvm|
{
^0(%arg25 : i8, %arg26 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.xor %arg25, %0 : i8
  %2 = llvm.add %1, %arg26 : i8
  %3 = llvm.xor %2, %0 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

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

def sextbool_add_before := [llvm|
{
^0(%arg12 : i1, %arg13 : i32):
  %0 = llvm.sext %arg12 : i1 to i32
  %1 = llvm.add %0, %arg13 : i32
  "llvm.return"(%1) : (i32) -> ()
}
]

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

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

def t2_after := [llvm|
{
^0(%arg202 : i8, %arg203 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.shl %0, %arg203 : i8
  %2 = llvm.add %1, %arg202 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

List.length in Init.Prelude
</all_available_defs>

<all_available_lemmas>
Array.mem_push in Init.Data.Array.Lemmas
Array.mem_toList_iff in Init.Data.Array.Lemmas
Array.toList_push in Init.Data.Array.Bootstrap
Function.Injective2.eq_iff in Mathlib.Logic.Function.Basic
List.Nodup.append in Mathlib.Data.List.Nodup
List.append_assoc in Init.Data.List.Basic
List.disjoint_singleton in Batteries.Data.List.Lemmas
List.mem_append in Init.Data.List.Lemmas
List.mem_singleton in Init.Data.List.Lemmas
Set.mem_empty_iff_false in Mathlib.Data.Set.Basic
Set.mem_insert_iff in Mathlib.Data.Set.Insert
Set.union_singleton in Mathlib.Data.Set.Insert
and_false in Init.SimpLemmas
iff_and_self in Init.SimpLemmas
ne_eq in Init.SimpLemmas
or_false in Init.SimpLemmas
true_and in Init.SimpLemmas
ne_or_eq in Mathlib.Logic.Basic
Array.emptyWithCapacity_eq in Init.Data.Array.Basic
and_self in Init.SimpLemmas
implies_true in Init.SimpLemmas
Array.mem_def in Init.Data.Array.Basic
Array.not_mem_empty in Init.Data.Array.Lemmas
FinEnum.nodup_toList in Mathlib.Data.FinEnum
List.Nodup.notMem in Mathlib.Data.List.Nodup
List.dedup_eq_self in Mathlib.Data.List.Dedup
List.foldl_nil in Init.Data.List.Basic
List.mem_cons in Init.Data.List.Lemmas
List.nodup_cons in Init.Data.List.Pairwise
List.not_mem_nil in Init.Data.List.Lemmas
false_and in Init.SimpLemmas
false_or in Init.SimpLemmas
Set.mem_setOf_eq in Mathlib.Data.Set.Operations

theorem Std.HashSet.fold_induction [BEq α] [LawfulBEq α] [Hashable α]
  {f : β → α → β} {m : HashSet α} {motive : β → Set α → Prop} :
    motive b ∅ →
    (∀ b x s, x ∉ s → motive b s → motive (f b x) (s ∪ {x})) →
    motive (m.fold f b) m.toSet

theorem Std.HashSet.toSet_toList[BEq α] [LawfulBEq α] [Hashable α] (m : HashSet α) : m.toSet = { x | x ∈ m.toList }

@[simp]
lemma Std.HashSet.mem_toSet [BEq α] [Hashable α] (m : HashSet α) : x ∈ m.toSet ↔ x ∈ m

@[simp]
theorem Std.HashSet.mem_attachWith_mem [BEq α] [Hashable α] [LawfulBEq α] (m : HashSet α) {P H} (x : α) h :
    ⟨x, h⟩ ∈ m.attachWith P H ↔ x ∈ m

theorem logic_or_logic_and_7_thm.extracted_1._7 : ∀ (x x_1 x_2 : BitVec 1),
  ¬x_2 = 1#1 → ¬x = 1#1 → ¬x_1 = 1#1 → 0#1 = 1#1 → 0#1 = 1#1

theorem sge_and_max_thm (e e_1 : IntW 8) :
  LLVM.and (icmp IntPred.sge e_1 e) (icmp IntPred.eq e_1 (const? 8 127)) ⊑
    icmp IntPred.eq e_1 (const? 8 127)

theorem AvoidCollision_setWidth_xor {x y : BitVec w} :
    (x ^^^ y).setWidth k = x.setWidth k ^^^ y.setWidth k

@[simp]
lemma dec_spec (bvs' : BitVecs' n) (k : Fin n) (i : Fin bvs'.length) :
    ((dec bvs').bvs.get k).getLsbD i = bvs'[i].getLsbD k

theorem masked_icmps_mask_notallzeros_bmask_mixed_7b_logical_thm (e : IntW 32) :
  select (icmp IntPred.ne (LLVM.and e (const? 32 6)) (const? 32 0))
      (icmp IntPred.eq (LLVM.and e (const? 32 15)) (const? 32 8)) (const? 1 0) ⊑
    const? 1 0

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

theorem xor_and_logic_or1_thm.extracted_1._2 : ∀ (x x_1 x_2 : BitVec 1),
  x_2 = 1#1 → x_2 &&& x_1 ^^^ 1#1 = x_1 ^^^ 1#1

theorem sub_ule_sext_proof : sub_ule_sext_before ⊑ sub_ule_sext_after

theorem lshrult_02_07_exact_thm.extracted_1._1 : ∀ (x : BitVec 4),
  ¬(True ∧ x >>> 2#4 <<< 2#4 ≠ x ∨ 2#4 ≥ ↑4) → ofBool (x >>> 2#4 <ᵤ 7#4) = 1#1

theorem sdiv_common_dividend_defined_cond_thm.extracted_1._1 : ∀ (x x_1 : BitVec 5) (x_2 : BitVec 1),
  ¬(x_2 = 1#1 ∨ (x == 0 || 5 != 1 && x_1 == intMin 5 && x == -1) = true) → x_2 = 1#1 → False

theorem both_sides_fold_slt_thm (e : IntW 32) (e_1 : IntW 1) :
  icmp IntPred.slt (select e_1 (const? 32 9) e) (select e_1 (const? 32 1) e) ⊑ const? 1 0

theorem select_or_disjoint_or_proof : select_or_disjoint_or_before ⊑ select_or_disjoint_or_after

theorem not_or_or_and_not_and_and_commute4_proof : not_or_or_and_not_and_and_commute4_before ⊑ not_or_or_and_not_and_and_commute4_after

theorem negative_with_uniform_bad_mask_logical_proof : negative_with_uniform_bad_mask_logical_before ⊑ negative_with_uniform_bad_mask_logical_after

theorem select_bittest_to_shl_negative_test_proof : select_bittest_to_shl_negative_test_before ⊑ select_bittest_to_shl_negative_test_after

theorem demorganize_constant2_proof : demorganize_constant2_before ⊑ demorganize_constant2_after

theorem ashr_x_by_const_cmp_sge_x_thm (e : IntW 32) :
  icmp IntPred.sge (ashr e (const? 32 5)) e ⊑ icmp IntPred.slt e (const? 32 1)

theorem p0_thm (e : IntW 8) :
  icmp IntPred.sge (LLVM.and e (const? 8 3)) e ⊑ icmp IntPred.slt e (const? 8 4)

theorem ashrsgt_03_00_exact_proof : ashrsgt_03_00_exact_before ⊑ ashrsgt_03_00_exact_after

@[simp] lemma eval_and (x : Bool → BitStream) : and.eval x = (x true) &&& (x false)

theorem test35_with_trunc_proof : test35_with_trunc_before ⊑ test35_with_trunc_after

theorem bad_add1_proof : bad_add1_before ⊑ bad_add1_after

theorem add_const_const_sub_nuw_thm (e : IntW 8) :
  sub (const? 8 (-127)) (add e (const? 8 1)) { «nsw» := false, «nuw» := true } ⊑ sub (const? 8 (-128)) e

theorem e_2252 :
    2 * ( ~~~e ||| (d ^^^ f)) + 2 * ( ~~~(d |||  ~~~e) |||  ~~~(e ^^^ f)) + 3 * (e ^^^  ~~~(d &&& f)) - 1 * (e |||  ~~~(d ||| f)) + 1 * ((e &&&  ~~~f) ^^^ ( ~~~d ||| (e ^^^ f))) - 6 *  ~~~e + 5 * (f ^^^  ~~~( ~~~d ||| (e &&& f))) - 6 * ((d &&& f) ^^^  ~~~(d ^^^ ( ~~~e &&& f))) - 6 * (d ^^^ ( ~~~e ||| f)) + 7 * (e |||  ~~~(d ^^^ f)) - 5 * (f &&& (d ||| e)) - 3 * (e ^^^  ~~~( ~~~d ||| (e &&& f))) + 5 *  ~~~(d &&& (e ||| f)) + 7 * ( ~~~e &&& (d ^^^ f)) + 2 * ( ~~~(d &&&  ~~~e) &&& (e ^^^ f)) + 11 * (e ^^^  ~~~(d &&&  ~~~f)) + 4 *  ~~~(e &&& f) + 7 * ( ~~~(d ^^^ e) &&& (d ^^^ f)) - 2 * (e ^^^ (d &&& (e ^^^ f))) + 1 *  ~~~( ~~~d &&& ( ~~~e &&& f)) + 2 * ((d ^^^ e) &&& (d ^^^ f)) - 1 * (e ^^^  ~~~(d ||| ( ~~~e &&& f))) + 2 * ( ~~~d ||| (e ^^^ f)) + 2 * (f ^^^  ~~~(d &&& ( ~~~e ||| f))) + 11 * ( ~~~(d ||| e) |||  ~~~(d ^^^ (e ^^^ f))) + 1 * (f ^^^ (d &&& ( ~~~e ||| f))) - 3 * (f ||| (d &&&  ~~~e)) - 1 * ( ~~~(d &&& e) &&& (d ^^^ (e ^^^ f))) + 2 * ( ~~~d ||| (e ||| f)) + 7 * (d &&& f) + 3 * (e &&& (d ||| f)) - 2 * (e ^^^ (d ||| (e ^^^ f))) + 4 * (f ^^^  ~~~(d &&&  ~~~e)) - 1 *  ~~~(e ||| f) + 11 * (f ^^^ (d &&&  ~~~e)) - 3 *  ~~~(d |||  ~~~f) + 1 * (d &&& (e ||| f)) + 1 * ((d &&& e) |||  ~~~(e ^^^ f)) + 2 * (f &&&  ~~~(d &&&  ~~~e)) - 5 *  ~~~(d &&& ( ~~~e ||| f)) + 11 * (e ^^^ ( ~~~d ||| ( ~~~e &&& f))) + 2 * ( ~~~f &&& (d ^^^ e)) - 7 * (e ^^^  ~~~( ~~~d &&& (e ||| f))) - 11 * (e ^^^  ~~~(d ||| f)) - 1 *  ~~~( ~~~d ||| (e &&& f)) + 7 * (e ^^^ (d |||  ~~~f)) + 1 * (f ^^^  ~~~(d &&& ( ~~~e &&& f))) + 3 * ( ~~~(d ^^^ e) &&&  ~~~(d ^^^ f)) - 2 *  ~~~(d ||| e) - 34 *  ~~~(d ||| (e ||| f)) - 11 *  ~~~(d ||| ( ~~~e ||| f)) - 30 *  ~~~( ~~~d ||| (e ||| f)) - 54 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 61 * ( ~~~d &&& ( ~~~e &&& f)) - 13 * ( ~~~d &&& (e &&& f)) - 47 * (d &&& ( ~~~e &&& f)) - 29 * (d &&& (e &&& f)) =  - 2 * ( ~~~(d |||  ~~~e) ||| (e ^^^ f))

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

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

theorem xor_1_thm (e e_1 e_2 : IntW 8) (e_3 : IntW 1) :
  LLVM.xor (LLVM.xor (select e_3 (LLVM.xor e_2 (const? 8 (-1))) (LLVM.xor e_1 (const? 8 123))) e) (const? 8 (-1)) ⊑
    LLVM.xor (select e_3 e_2 (LLVM.xor e_1 (const? 8 (-124)))) e

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

theorem xor_nosignbit_select_ashr_proof : xor_nosignbit_select_ashr_before ⊑ xor_nosignbit_select_ashr_after

theorem main13_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (truncate 16 x <ₛ 0#16) &&& ofBool (truncate 8 x <ₛ 0#8) = 1#1 →
    ¬ofBool (x &&& 32896#32 == 32896#32) = 1#1 → 2#32 = 1#32

theorem p0_proof : p0_before ⊑ p0_after

theorem e_75 :
    1 *  ~~~(x &&&  ~~~y) + 1 * x - 12 *  ~~~(x ||| y) - 1 *  ~~~(x |||  ~~~y) - 2 * (x &&& y) =  - 11 *  ~~~y + 12 * (x &&&  ~~~y)

theorem icmp_ne_zext_eq_zero_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (zeroExtend 32 (ofBool (x == 0#32)) != x) = 1#1

theorem or_not_and_and_not_and_xor_commute4_proof : or_not_and_and_not_and_xor_commute4_before ⊑ or_not_and_and_not_and_xor_commute4_after

theorem test15e_thm.extracted_1._1 : ∀ (x : BitVec 32), ofBool (x &&& 128#32 != 0#32) = 1#1 → 1#32 ≥ ↑32 → False

theorem ashr_ult_8_proof : ashr_ult_8_before ⊑ ashr_ult_8_after

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

theorem main7e_logical_proof : main7e_logical_before ⊑ main7e_logical_after

theorem different_size_sext_sext_sle_proof : different_size_sext_sext_sle_before ⊑ different_size_sext_sext_sle_after

theorem test_sub__none_are_safe_proof : test_sub__none_are_safe_before ⊑ test_sub__none_are_safe_after

theorem ashr_ult_2_proof : ashr_ult_2_before ⊑ ashr_ult_2_after

theorem c_0_1_0_proof : c_0_1_0_before ⊑ c_0_1_0_after

theorem and_or3_thm.extracted_1._5 : ∀ (x : BitVec 1) (x_1 x_2 : BitVec 32) (x_3 : BitVec 1),
  x_3 &&& ofBool (x_2 == x_1) = 1#1 → ¬x_3 = 1#1 → x = 0#1

theorem lshrult_01_08_proof : lshrult_01_08_before ⊑ lshrult_01_08_after

theorem select_or_disjoint_or_thm.extracted_1._1 : ∀ (x : BitVec 32) (x_1 : BitVec 1),
  x_1 = 1#1 →
    ¬(4#32 ≥ ↑32 ∨ True ∧ (0#32 &&& x <<< 4#32 != 0) = true) →
      4#32 ≥ ↑32 ∨
          True ∧ (0#32 &&& x <<< 4#32 != 0) = true ∨
            True ∧ (0#32 ||| x <<< 4#32).saddOverflow 4#32 = true ∨
              True ∧ (0#32 ||| x <<< 4#32).uaddOverflow 4#32 = true →
        False

theorem sgt_smin3_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (x_1 + 3#32 <ₛ x) = 1#1 → ofBool (x_1 + 3#32 <ₛ x) = 0#1

theorem t7_ashr_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬(True ∧ x_1 >>> (32#32 - x) <<< (32#32 - x) ≠ x_1 ∨ 32#32 - x ≥ ↑32 ∨ x + BitVec.ofInt 32 (-2) ≥ ↑32) →
    ¬30#32 ≥ ↑32 → (x_1.sshiftRight' (32#32 - x)).sshiftRight' (x + BitVec.ofInt 32 (-2)) = x_1.sshiftRight' 30#32

theorem unsigned_sign_bit_extract_with_trunc_proof : unsigned_sign_bit_extract_with_trunc_before ⊑ unsigned_sign_bit_extract_with_trunc_after

theorem t0_shl_thm.extracted_1._2 : ∀ (x : BitVec 8) (x_1 : BitVec 32),
  ¬signExtend 32 x ≥ ↑32 →
    ¬(True ∧ x.msb = true ∨ zeroExtend 32 x ≥ ↑32) → x_1 <<< signExtend 32 x = x_1 <<< zeroExtend 32 x

theorem ne_umax1_proof : ne_umax1_before ⊑ ne_umax1_after

theorem thisdoesnotloop_proof : thisdoesnotloop_before ⊑ thisdoesnotloop_after

theorem trunc_lshr_sext_exact_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬(True ∧ signExtend 32 x >>> 6#32 <<< 6#32 ≠ signExtend 32 x ∨ 6#32 ≥ ↑32) →
    True ∧ x >>> 6#8 <<< 6#8 ≠ x ∨ 6#8 ≥ ↑8 → False

theorem trunc_unsigned_nsw_zext_thm.extracted_1._1 : ∀ (x : BitVec 8) (x_1 : BitVec 32),
  ¬(True ∧ signExtend 32 (truncate 16 x_1) ≠ x_1) →
    ofBool (truncate 16 x_1 <ᵤ zeroExtend 16 x) = ofBool (x_1 <ᵤ zeroExtend 32 x)

omit [Fintype S] in
lemma processOneElem_spec {st : worklist.St A S} (s : State) (sa : S) (k : ℕ) :
    ∀ a sa', (f sa)[k]? = some (a, sa') →
    processOneElem_mot inits final f s sa k st →
    processOneElem_mot inits final f s sa (k+1) (processOneElem A S final s st (a, sa'))

theorem scalar_i32_udiv_and_negC_eq_X_is_constant3_proof : scalar_i32_udiv_and_negC_eq_X_is_constant3_before ⊑ scalar_i32_udiv_and_negC_eq_X_is_constant3_after

@[simp]
lemma CNFA.SignedCmp_states cmp : s ∈ (autSignedCmp cmp).m.states ↔  s < 5

@[simp] theorem val_toArgResult (mapOut : MatchVarResult lets v (.var matchLets matchExpr) w.appendInl mapIn) :
    mapOut.toArgResult.val = mapOut.val

theorem lshrult_02_13_exact_thm.extracted_1._1 : ∀ (x : BitVec 4),
  ¬(True ∧ x >>> 2#4 <<< 2#4 ≠ x ∨ 2#4 ≥ ↑4) → ofBool (x >>> 2#4 <ᵤ BitVec.ofInt 4 (-3)) = 1#1

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

theorem and_xor_or8_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 64),
  ¬(x_2 = 0 ∨ x_1 = 0 ∨ x_2 = 0 ∨ x = 0) → x_2 = 0 ∨ x_1 = 0 → False

theorem logical_or_not_thm.extracted_1._3 : ∀ (x x_1 : BitVec 1), ¬x_1 = 1#1 → ¬x_1 ^^^ 1#1 = 1#1 → 1#1 = x

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

theorem test3_logical_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬(True ∧ x_1.ssubOverflow x = true) →
    ¬ofBool (x_1 - x == 0#32) = 1#1 → ofBool (x_1 == x) = 1#1 → ofBool (x_1 - x == 31#32) = 1#1

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

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

theorem n15_wrong_comparison_predicate_and_constant_proof : n15_wrong_comparison_predicate_and_constant_before ⊑ n15_wrong_comparison_predicate_and_constant_after

theorem e_1041 :
     - 5 *  ~~~z - 11 *  ~~~(z ^^^ t) + 1 * (z ||| t) - 2 * (z |||  ~~~t) + 6 *  ~~~(z |||  ~~~t) + 3 * (z &&&  ~~~t) + 14 * (z &&& t) =  - 20 *  ~~~(z ||| t) + 2 *  ~~~(z &&&  ~~~z)

theorem e_108 :
     - 2 * x + 2 *  ~~~(x ^^^ y) - 11 *  ~~~x + 9 *  ~~~(x ||| y) + 22 *  ~~~(x |||  ~~~y) + 13 * (x &&&  ~~~y) =  - 11 * (x &&& y) + 11 * (x ||| y)

theorem and_xor_or1_proof : and_xor_or1_before ⊑ and_xor_or1_after

theorem shl_sub_lshr_reverse_nsw_on_op1_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 32),
  ¬(True ∧ (x_1 <<< x).sshiftRight' x ≠ x_1 ∨
        True ∧ x_1 <<< x >>> x ≠ x_1 ∨
          x ≥ ↑32 ∨
            True ∧ x_2.usubOverflow (x_1 <<< x) = true ∨
              True ∧ (x_2 - x_1 <<< x) >>> x <<< x ≠ x_2 - x_1 <<< x ∨ x ≥ ↑32) →
    True ∧ x_2 >>> x <<< x ≠ x_2 ∨ x ≥ ↑32 ∨ True ∧ (x_2 >>> x).usubOverflow x_1 = true → False

theorem e_1278 :
    2 *  ~~~z + 4 * z + 7 * (z ^^^ t) + 2 *  ~~~(z ^^^ t) + 1 * t - 6 * (z ||| t) - 5 *  ~~~(z ||| t) - 6 * (z &&&  ~~~t) - 1 * (z &&& t) = 4 *  ~~~(z |||  ~~~t) - 1 *  ~~~t

theorem lshrult_03_14_proof : lshrult_03_14_before ⊑ lshrult_03_14_after

theorem test_sext_zext_thm (e : IntW 16) : sext 64 (zext 32 e) ⊑ zext 64 e

theorem sle_and_min_commute_logical_thm.extracted_1._2 : ∀ (x x_1 : BitVec 8),
  ofBool (x_1 == BitVec.ofInt 8 (-128)) = 1#1 → ofBool (x_1 ≤ₛ x) = ofBool (x_1 == BitVec.ofInt 8 (-128))

theorem PR44545_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 == 0#32) = 1#1 →
    ¬(True ∧ (truncate 16 0#32).saddOverflow (-1#16) = true) → truncate 16 0#32 + -1#16 = -1#16

theorem e_2396 :
     - 2 * (e ^^^ (d ||| f)) - 6 * (f ^^^  ~~~( ~~~d &&& (e &&& f))) - 3 * (f ^^^  ~~~(d &&& (e &&& f))) - 5 * (e &&& (d ||| f)) - 7 * (e ^^^ ( ~~~d ||| ( ~~~e &&& f))) + 7 *  ~~~( ~~~d &&& ( ~~~e ||| f)) + 11 *  ~~~(d ^^^ (e &&& f)) - 1 * (e ^^^ (d ||| (e ||| f))) + 7 * f - 11 * ( ~~~(d ^^^ e) &&& (d ^^^ f)) + 11 * (e ||| (d &&&  ~~~f)) - 11 * ( ~~~e |||  ~~~(d ^^^ f)) + 1 * ((d &&& f) ^^^ (d ^^^ ( ~~~e &&& f))) + 1 * (f ^^^  ~~~( ~~~d ||| (e &&& f))) - 2 * (f ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) - 1 * (e ^^^  ~~~(d &&& f)) - 3 * (f ^^^  ~~~(d &&& ( ~~~e &&& f))) + 2 * (d ^^^ (e ^^^ f)) - 1 *  ~~~(e ^^^ f) + 11 * ((d &&& f) ^^^  ~~~(e &&&  ~~~f)) + 1 * ( ~~~(d ||| e) ||| (e ^^^ f)) + 3 *  ~~~(d |||  ~~~f) - 6 * (d ||| ( ~~~e &&& f)) + 11 * ( ~~~d ||| ( ~~~e ||| f)) + 5 * (f ^^^ ( ~~~d ||| (e &&& f))) - 11 * ((d &&& e) ||| (d ^^^ (e ^^^ f))) + 2 * ((d &&& f) ^^^ (d ^^^ (e &&& f))) - 1 * ( ~~~(d ||| e) |||  ~~~(e ^^^ f)) - 1 * (f ||| (d &&& e)) + 1 * d + 5 * (f ^^^  ~~~(d ||| (e &&& f))) - 11 * (f ^^^  ~~~(d &&& ( ~~~e ||| f))) - 5 * ((d &&&  ~~~e) ||| (e ^^^ f)) - 2 * (f |||  ~~~(d ||| e)) + 1 * (f &&& (d ^^^ e)) + 3 * ( ~~~(d &&& e) &&&  ~~~(d ^^^ (e ^^^ f))) - 5 * (e ||| f) + 11 * (d ||| (e ^^^ f)) + 2 * (f ^^^ ( ~~~d &&& ( ~~~e ||| f))) - 5 * (e ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) - 7 * (f ^^^ ( ~~~d &&& (e ||| f))) + 4 *  ~~~( ~~~d &&& (e ||| f)) - 1 * (e ^^^  ~~~(d &&&  ~~~f)) + 1 *  ~~~(d &&& e) + 4 * (e ^^^ ( ~~~d &&& (e ^^^ f))) - 2 *  ~~~( ~~~d ||| (e ^^^ f)) - 2 * ( ~~~d &&& (e ^^^ f)) - 1 *  ~~~(e ||| f) + 2 * (e &&& (d ^^^ f)) + 3 * (f ^^^  ~~~(d |||  ~~~e)) + 4 *  ~~~(d ||| f) + 2 * (f ||| (d ^^^ e)) - 6 * ((d ||| e) &&& (d ^^^ (e ^^^ f))) - 1 *  ~~~(d ^^^ f) - 6 * (f ^^^  ~~~(d &&& e)) - 2 * (f ^^^  ~~~( ~~~d ||| ( ~~~e &&& f))) - 1 * (e ^^^ ( ~~~d ||| (e &&& f))) - 5 * ( ~~~(d |||  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) - 2 * ((d &&& e) ^^^ (d ^^^ (e &&& f))) - 1 * ( ~~~(d &&&  ~~~e) &&& (e ^^^ f)) - 2 * ((d ||| e) &&&  ~~~(e ^^^ f)) + 1 * ((d &&& e) |||  ~~~(e |||  ~~~f)) + 7 * ((d &&& f) ^^^ (e ||| f)) + 4 *  ~~~(d ||| (e ||| f)) + 7 *  ~~~(d ||| ( ~~~e ||| f)) + 14 *  ~~~( ~~~d ||| (e ||| f)) + 34 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 4 * ( ~~~d &&& ( ~~~e &&& f)) - 31 * ( ~~~d &&& (e &&& f)) + 11 * (d &&& ( ~~~e &&& f)) + 7 * (d &&& (e &&& f)) = 1 * (e |||  ~~~(d ||| f))

theorem p0_ult_65536_proof : p0_ult_65536_before ⊑ p0_ult_65536_after

theorem exact_lshr_eq_both_equal_proof : exact_lshr_eq_both_equal_before ⊑ exact_lshr_eq_both_equal_after

theorem xor_or_xor_thm.extracted_1._1 : ∀ (x : BitVec 8),
  (x ^^^ 33#8 ||| 7#8) ^^^ 12#8 = x &&& BitVec.ofInt 8 (-8) ^^^ 43#8

theorem ashr_slt_exact_near_pow2_cmpval_proof : ashr_slt_exact_near_pow2_cmpval_before ⊑ ashr_slt_exact_near_pow2_cmpval_after

theorem ashr_xor_proof : ashr_xor_before ⊑ ashr_xor_after

theorem eq_21_logical_proof : eq_21_logical_before ⊑ eq_21_logical_after

theorem or_nosignbit_select_ashr_proof : or_nosignbit_select_ashr_before ⊑ or_nosignbit_select_ashr_after

theorem shl_bad_sub2_i32_proof : shl_bad_sub2_i32_before ⊑ shl_bad_sub2_i32_after

theorem t4_ugt_slt_65536_proof : t4_ugt_slt_65536_before ⊑ t4_ugt_slt_65536_after

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

theorem urem_c_i32_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬zeroExtend 32 x = 0 → x = 0 ∨ True ∧ (10#8 % x).msb = true → False

theorem src_srem_shl_demand_max_mask_hit_demand_proof : src_srem_shl_demand_max_mask_hit_demand_before ⊑ src_srem_shl_demand_max_mask_hit_demand_after

theorem bv_AndOrXor_1683_1 :
    ∀ (e e_1 : LLVM.IntW w),
      LLVM.or (LLVM.icmp LLVM.IntPred.ugt e e_1) (LLVM.icmp LLVM.IntPred.eq e e_1) ⊑ LLVM.icmp LLVM.IntPred.uge e e_1

theorem lshr_lshr_thm (e : IntW 232) : lshr (lshr e (const? 232 231)) (const? 232 1) ⊑ const? 232 0

theorem test_add_nuw__nuw_is_safe_proof : test_add_nuw__nuw_is_safe_before ⊑ test_add_nuw__nuw_is_safe_after

theorem trunc_sandwich_big_sum_shift1_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬(21#32 ≥ ↑32 ∨ 11#12 ≥ ↑12) → truncate 12 (x >>> 21#32) >>> 11#12 = 0#12

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
</all_available_lemmas>

<local_ctx>
import Mathlib.Data.Fintype.Prod

import Blase.AutoStructs.Worklist

import Mathlib.Tactic.ApplyFun

open SetRel

section sink

variable {A : Type} [BEq A] [Hashable A] [DecidableEq A] [FinEnum A]

end sink

section generic_prod

variable {α} [BEq α] [Hashable α] [LawfulBEq α]

variable {β} [BEq β] [Hashable β] [LawfulBEq β]

variable {S₁ : Finset α} {S₂ : Finset β}

variable {γ} (f : S₁ → S₂ → γ) (hinj : Function.Injective2 f)

variable {m₁ : Std.HashSet α} (hm₁ : ∀ s₁ ∈ m₁, s₁ ∈ S₁)

variable {m₂ : Std.HashSet β} (hm₂ : ∀ s₂ ∈ m₂, s₂ ∈ S₂)

@[inline]
def product.prodArray' (a : Array γ) :=
  m₁.attachWith _ hm₁ |>.fold (init := a) fun is s1 =>
    m₂.attachWith _ hm₂ |>.fold (init := is) fun is s2 =>
      is.push (f s1 s2)

@[inline]
def product.prodArray := prodArray' f hm₁ hm₂ (Array.emptyWithCapacity <| m₁.size * m₂.size)

end generic_prod

section product

variable {A : Type} [BEq A] [LawfulBEq A] [Hashable A] [DecidableEq A] [FinEnum A]

def product.inits (m₁ m₂ : CNFA n) :=
  product.prodArray Prod.mk @m₁.wf.initials_lt @m₂.wf.initials_lt

def product (final? : Bool → Bool → Bool) (m₁ m₂ : CNFA n) : CNFA n :=
  worklistRun (m₁.m.states × m₂.m.states) final (product.inits m₁ m₂)
    (by admit /- proof elided -/
    ) f
where final (ss : m₁.m.states × m₂.m.states) := final? (ss.1 ∈ m₁.m.finals) (ss.2 ∈ m₂.m.finals)
      f (ss : m₁.m.states × m₂.m.states) :=
        let (s1, s2) := ss
        (FinEnum.toList (α := BitVec n)).foldl (init := Array.empty) fun as a =>
          product.prodArray' (λ s₁ s₂ ↦ (a, (s₁, s₂)))
            (fun s' => m₁.wf.trans_tgt_lt (s := s1) (a := a)) (fun s' => m₂.wf.trans_tgt_lt (s := s2) (a := a)) as

noncomputable def to_prop (f : Bool → Bool → Bool) (p1 p2 : Prop) : Prop :=
  f (@Decidable.decide p1 (Classical.propDecidable _)) (@Decidable.decide p2 (Classical.propDecidable _))
</local_ctx>

<target_theorem>
lemma product.sim {m1 m2 : CNFA n}:
    m1.Sim M1 → m2.Sim M2 →
    (nfa (product.inits m1 m2) (final final? m1 m2) (f m1 m2)).Bisim (M1.M.product (to_prop final?) M2.M) :=
</target_theorem>

