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>
BitVec in Init.Prelude
Nat in Init.Prelude
List in Init.Prelude
List.Vector in Mathlib.Data.Vector.Defs
Set in Mathlib.Data.Set.Defs
NFA in Mathlib.Computability.NFA
DecidableEq in Init.Prelude
Fintype in Mathlib.Data.Fintype.Defs
Repr in Init.Data.Repr
NFA.accept in Mathlib.Computability.NFA
NFA.start in Mathlib.Computability.NFA
NFA.step in Mathlib.Computability.NFA
Unit in Init.Prelude
cmp in Mathlib.Data.Ordering.Basic
BitVec.ofNat in Init.Prelude
NFA.stepSet in Mathlib.Computability.NFA
BitVec.cons in Init.Data.BitVec.Basic
Language in Mathlib.Computability.Language
List.Vector.ofFn in Mathlib.Data.Vector.Defs
List.Vector.replicate in Mathlib.Data.Vector.Defs
Bool in Init.Prelude
Fin in Init.Prelude
BitVec.iunfoldr in Init.Data.BitVec.Folds
List.finRange in Init.Data.List.FinRange
List.reverseRecOn in Mathlib.Data.List.Induction
FinEnum in Mathlib.Data.FinEnum
BitVec.ofFin in Init.Prelude
BitVec.ule in Init.Data.BitVec.Basic
BitVec.ult in Init.Data.BitVec.Basic
BitVec.sle in Init.Data.BitVec.Basic
BitVec.slt in Init.Data.BitVec.Basic

structure BitVecs (n : Nat) where
  w : Nat
  bvs : List.Vector (BitVec w) n

inductive RelationOrdering
| lt | le | gt | ge
deriving Repr, Fintype

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

inductive Relation
| eq
| signed (ord : RelationOrdering)
| unsigned (ord : RelationOrdering)
deriving Repr

def evalRelation (rel : Relation) {w} (bv1 bv2 : BitVec w) : Prop :=
  match rel with
  | .eq => bv1 = bv2
  | .signed .lt => bv1.slt bv2
  | .signed .le => bv1.sle  bv2
  | .signed .gt => bv2.slt bv1
  | .signed .ge => bv2.sle bv1
  | .unsigned .lt => bv1.ult bv2
  | .unsigned .le => bv1.ule bv2
  | .unsigned .gt => bv2.ult bv1
  | .unsigned .ge => bv2.ule bv1

def bv2 : BitVec 4 := BitVec.ofNat 4 1

def bv1 : BitVec 4 := BitVec.ofNat 4 5

def accepts (M : NFA' n) : Set (BitVecs n) := dec '' M.accepts'

def accepts' (M : NFA' n) : Set (BitVecs' n) := M.M.accepts

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

def BitVec.ofFn {w : Nat} (f : Fin w → Bool) : BitVec w :=
  BitVec.iunfoldr (fun i _ => ((), f i)) () |>.2

def BitStream : Type := Nat → Bool

def enc (bvs : BitVecs n) : BitVecs' n :=
  (List.finRange bvs.w).map (fun i =>
    BitVec.ofFn (fun (k : Fin n) => (bvs.bvs.get k)[i]))

instance instFinEnumBV : FinEnum (BitVec w) where
  card := 2^w
  equiv := {
    toFun := fun x => x.toFin
    invFun := fun x => BitVec.ofFin x
    left_inv := by admit /- proof elided -/

def scalar_i32_shl_and_signbit_eq_X_is_constant1_after := [llvm|
{
^0(%arg5 : i32):
  %0 = llvm.mlir.constant(12345 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.shl %0, %arg5 : i32
  %3 = llvm.icmp "sgt" %2, %1 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

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

def Valuation.equivHVector {Γ : List Ty} : Valuation ⟨Γ⟩ ≃ HVector toType Γ where
  toFun V   := HVector.ofFn _ _ <| fun i => V ⟨i, by admit /- proof elided -/
  ⟩
  invFun    := Valuation.ofHVector
  left_inv V := by admit /- proof elided -/

abbrev Term.Ctx.Env
  (tctx : Term.Ctx wcard tcard)
  (wenv : WidthExpr.Env wcard) :=
  (v : Fin tcard) → BitVec ((tctx v).toNat wenv)

def a_or_b_const_before := [llvm|
{
^0(%arg10 : i32, %arg11 : i32, %arg12 : i32):
  %0 = llvm.icmp "eq" %arg10, %arg12 : i32
  %1 = llvm.icmp "ne" %arg11, %arg12 : i32
  %2 = llvm.and %0, %1 : i1
  %3 = llvm.icmp "ne" %arg10, %arg12 : i32
  %4 = llvm.icmp "eq" %arg11, %arg12 : i32
  %5 = llvm.and %3, %4 : i1
  %6 = llvm.or %2, %5 : i1
  "llvm.return"(%6) : (i1) -> ()
}
]

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

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

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

@[combinator_parenthesizer MLIR.EDSL.balancedBrackets]
def MLIR.EDSL.balancedBracketsParenthesizer : Parenthesizer := pure ()

def and_logic_and_logic_or_3_before := [llvm|
{
^0(%arg132 : i1, %arg133 : i1, %arg134 : i1):
  %0 = llvm.mlir.constant(false) : i1
  %1 = llvm.mlir.constant(true) : i1
  %2 = llvm.and %arg133, %arg132 : i1
  %3 = "llvm.select"(%arg132, %arg134, %0) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %4 = "llvm.select"(%2, %1, %3) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%4) : (i1) -> ()
}
]

def or_and3_before := [llvm|
{
^0(%arg104 : i1, %arg105 : i1, %arg106 : i32, %arg107 : i32):
  %0 = llvm.icmp "eq" %arg106, %arg107 : i32
  %1 = llvm.or %arg104, %0 : i1
  %2 = "llvm.select"(%1, %arg104, %arg105) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%2) : (i1) -> ()
}
]

def and_or1_wrong_operand_after := [llvm|
{
^0(%arg176 : i1, %arg177 : i1, %arg178 : i1, %arg179 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.xor %arg176, %0 : i1
  %2 = llvm.or %arg178, %1 : i1
  %3 = "llvm.select"(%2, %arg179, %arg177) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%3) : (i1) -> ()
}
]

def slli_i32_test : LLVMPeepholeRewriteRefine 32 [Ty.llvm (.bitvec 32)] where
  lhs := slli_llvm_i32
  rhs := slli_riscv_i32

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

def or_eq_with_one_bit_diff_constants1_logical_before := [llvm|
{
^0(%arg365 : i32):
  %0 = llvm.mlir.constant(50 : i32) : i32
  %1 = llvm.mlir.constant(51 : i32) : i32
  %2 = llvm.mlir.constant(true) : i1
  %3 = llvm.icmp "eq" %arg365, %0 : i32
  %4 = llvm.icmp "eq" %arg365, %1 : i32
  %5 = "llvm.select"(%3, %2, %4) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%5) : (i1) -> ()
}
]

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

def t10_almost_highest_bit_after := [llvm|
{
^0(%arg22 : i32, %arg23 : i64, %arg24 : i32):
  %0 = llvm.mlir.constant(64 : i32) : i32
  %1 = llvm.mlir.constant(-2 : i32) : i32
  %2 = llvm.mlir.constant(0 : i32) : i32
  %3 = llvm.sub %0, %arg24 : i32
  %4 = llvm.shl %arg22, %3 : i32
  %5 = llvm.add %arg24, %1 : i32
  %6 = llvm.zext nneg %5 : i32 to i64
  %7 = llvm.lshr %arg23, %6 : i64
  %8 = llvm.trunc %7 : i64 to i32
  %9 = llvm.and %4, %8 : i32
  %10 = llvm.icmp "ne" %9, %2 : i32
  "llvm.return"(%10) : (i1) -> ()
}
]

def or_and_xor_not_constant_commute1_after := [llvm|
{
^0(%arg166 : i9, %arg167 : i9):
  %0 = llvm.mlir.constant(42 : i9) : i9
  %1 = llvm.and %arg166, %0 : i9
  %2 = llvm.xor %1, %arg167 : i9
  "llvm.return"(%2) : (i9) -> ()
}
]

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

def lshr_and_after := [llvm|
{
^0(%arg73 : i8, %arg74 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.mlir.constant(6 : i8) : i8
  %2 = llvm.srem %arg73, %0 : i8
  %3 = llvm.shl %2, %1 : i8
  %4 = llvm.and %arg74, %3 : i8
  "llvm.return"(%4) : (i8) -> ()
}
]

def DCFork := [DC_com| {
  ^entry(%0 : !ValueStream_8):
    %unpack12 = "DC.unpack" (%0) : (!ValueStream_8) -> (!ValueTokenStream_8)
    %unpack1 = "DC.fstVal" (%unpack12) : (!ValueTokenStream_8) -> (!ValueStream_8)
    %unpack2 = "DC.sndVal" (%unpack12) : (!ValueTokenStream_8) -> (!TokenStream)
    %fork12 = "DC.fork" (%unpack2) : (!TokenStream) -> (!TokenStream2)
    %fork1 = "DC.fst" (%fork12) : (!TokenStream2) -> (!TokenStream)
    %fork2 = "DC.snd" (%fork12) : (!TokenStream2) -> (!TokenStream)
    %pack1 = "DC.pack" (%unpack1, %fork1) : (!ValueStream_8, !TokenStream) -> (!ValueStream_8)
    %pack2 = "DC.pack" (%unpack1, %fork2) : (!ValueStream_8, !TokenStream) -> (!ValueStream_8)
    %pack12 = "DC.pair" (%pack1, %pack2) : (!ValueStream_8, !ValueStream_8) -> (!ValueStream2_8)
    "return" (%pack12) : (!ValueStream2_8) -> ()
  }]

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

def bool_add_lshr_after := [llvm|
{
^0(%arg14 : i1, %arg15 : i1):
  %0 = llvm.and %arg14, %arg15 : i1
  %1 = llvm.zext %0 : i1 to i2
  "llvm.return"(%1) : (i2) -> ()
}
]

def test14_before := [llvm|
{
^0(%arg5 : i32):
  %0 = llvm.mlir.constant(4 : i32) : i32
  %1 = llvm.udiv %0, %arg5 : i32
  %2 = llvm.icmp "ult" %1, %0 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

@[simp_denote]
def sltu_llvm_i64 := [LV| {
    ^entry (%a: i64, %b: i64):
    %0 = llvm.icmp.ult %a, %b : i64
    %1 = llvm.zext %0 : i1 to i64
    llvm.return %1 : i64
  }]

def eq_3210_before := [llvm|
{
^0(%arg126 : i32, %arg127 : i32):
  %0 = llvm.mlir.constant(8 : i32) : i32
  %1 = llvm.mlir.constant(16 : i32) : i32
  %2 = llvm.mlir.constant(24 : i32) : i32
  %3 = llvm.trunc %arg126 : i32 to i8
  %4 = llvm.lshr %arg126, %0 : i32
  %5 = llvm.trunc %4 : i32 to i8
  %6 = llvm.lshr %arg126, %1 : i32
  %7 = llvm.trunc %6 : i32 to i8
  %8 = llvm.lshr %arg126, %2 : i32
  %9 = llvm.trunc %8 : i32 to i8
  %10 = llvm.trunc %arg127 : i32 to i8
  %11 = llvm.lshr %arg127, %0 : i32
  %12 = llvm.trunc %11 : i32 to i8
  %13 = llvm.lshr %arg127, %1 : i32
  %14 = llvm.trunc %13 : i32 to i8
  %15 = llvm.lshr %arg127, %2 : i32
  %16 = llvm.trunc %15 : i32 to i8
  %17 = llvm.icmp "eq" %3, %10 : i8
  %18 = llvm.icmp "eq" %5, %12 : i8
  %19 = llvm.icmp "eq" %7, %14 : i8
  %20 = llvm.icmp "eq" %9, %16 : i8
  %21 = llvm.and %17, %18 : i1
  %22 = llvm.and %19, %21 : i1
  %23 = llvm.and %20, %22 : i1
  "llvm.return"(%23) : (i1) -> ()
}
]

def sub_ashr_or_i32_nuw_nsw_before := [llvm|
{
^0(%arg30 : i32, %arg31 : i32):
  %0 = llvm.mlir.constant(31 : i32) : i32
  %1 = llvm.sub %arg31, %arg30 overflow<nsw,nuw> : i32
  %2 = llvm.ashr %1, %0 : i32
  %3 = llvm.or %2, %arg30 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def land_lor_right1_after := [llvm|
{
^0(%arg46 : i1, %arg47 : i1):
  "llvm.return"(%arg46) : (i1) -> ()
}
]

def is_ascii_alphabetic_inverted_after := [llvm|
{
^0(%arg247 : i32):
  %0 = llvm.mlir.constant(-33 : i32) : i32
  %1 = llvm.mlir.constant(-91 : i32) : i32
  %2 = llvm.mlir.constant(-26 : i32) : i32
  %3 = llvm.and %arg247, %0 : i32
  %4 = llvm.add %3, %1 : i32
  %5 = llvm.icmp "ult" %4, %2 : i32
  "llvm.return"(%5) : (i1) -> ()
}
]

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

def lshr_or_or_no_const_before := [llvm|
{
^0(%arg142 : i8, %arg143 : i8, %arg144 : i8, %arg145 : i8):
  %0 = llvm.lshr %arg142, %arg144 : i8
  %1 = llvm.lshr %arg143, %arg144 : i8
  %2 = llvm.or %1, %arg145 : i8
  %3 = llvm.or %0, %2 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def bools_logical_commute1_after := [llvm|
{
^0(%arg96 : i1, %arg97 : i1, %arg98 : i1):
  %0 = "llvm.select"(%arg98, %arg97, %arg96) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def test_logical_before := [llvm|
{
^0(%arg0 : i32):
  %0 = llvm.mlir.constant(13 : i32) : i32
  %1 = llvm.mlir.constant(15 : i32) : i32
  %2 = llvm.mlir.constant(false) : i1
  %3 = llvm.icmp "ugt" %arg0, %0 : i32
  %4 = llvm.icmp "eq" %arg0, %1 : i32
  %5 = "llvm.select"(%3, %4, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%5) : (i1) -> ()
}
]

def src_is_mask_and_before := [llvm|
{
^0(%arg122 : i8, %arg123 : i8, %arg124 : i8):
  %0 = llvm.mlir.constant(123 : i8) : i8
  %1 = llvm.mlir.constant(7 : i8) : i8
  %2 = llvm.mlir.constant(-1 : i8) : i8
  %3 = llvm.xor %arg122, %0 : i8
  %4 = llvm.ashr %1, %arg123 : i8
  %5 = llvm.lshr %2, %arg124 : i8
  %6 = llvm.and %4, %5 : i8
  %7 = llvm.and %3, %6 : i8
  %8 = llvm.icmp "eq" %3, %7 : i8
  "llvm.return"(%8) : (i1) -> ()
}
]

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

def llvm_sext_lower_riscv_i16_to_32 : LLVMPeepholeRewriteRefine 32 [Ty.llvm (.bitvec 16)] :=
  {lhs:= sext_llvm_i16_to_32, rhs:= sext_riscv_i16_to_32}

def sdiv_x_by_const_cmp_x_before := [llvm|
{
^0(%arg15 : i32):
  %0 = llvm.mlir.constant(13 : i32) : i32
  %1 = llvm.sdiv %arg15, %0 : i32
  %2 = llvm.icmp "eq" %1, %arg15 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

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

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

Valuation.map in Mathlib.RingTheory.Valuation.Basic

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

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

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

def masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_3_logical_after := [llvm|
{
^0(%arg21 : i32):
  %0 = llvm.mlir.constant(15 : i32) : i32
  %1 = llvm.mlir.constant(8 : i32) : i32
  %2 = llvm.and %arg21, %0 : i32
  %3 = llvm.icmp "ne" %2, %1 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

def select_ashr_icmp_bad_before := [llvm|
{
^0(%arg45 : i32, %arg46 : i32, %arg47 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.icmp "eq" %arg45, %0 : i32
  %2 = llvm.ashr %arg47, %arg45 : i32
  %3 = "llvm.select"(%1, %2, %arg46) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%3) : (i32) -> ()
}
]

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

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 timeElapsedMs (x : Unit → α) : IO (α × Int) := do
    let tStart ← IO.monoMsNow
    let b := x ()
    let tEnd ← IO.monoMsNow
    return (b, tEnd - tStart)

EmptyCollection in Init.Core
</all_available_defs>

<all_available_lemmas>
NFA.eval_append_singleton in Mathlib.Computability.NFA
NFA.eval_nil in Mathlib.Computability.NFA
BitVec.toNat_eq in Init.Data.BitVec.Lemmas
le_iff_lt_or_eq in Mathlib.Order.Defs.PartialOrder
Nat.le_antisymm in Init.Prelude
BitVec.toInt_inj in Init.Data.BitVec.Lemmas

@[ext]
theorem ext {x y : BitStream} (h : ∀ i, x i = y i) : x = y

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

theorem e_1652 :
    7 * ((a &&& c) ||| (b &&&  ~~~c)) - 1 * (c ^^^  ~~~(a &&& (b &&& c))) + 2 * ((a &&& b) |||  ~~~(b ||| c)) + 2 * (c ^^^ ( ~~~a ||| (b &&& c))) + 1 * (b ^^^  ~~~( ~~~a ||| (b &&& c))) - 2 *  ~~~(b &&& c) + 3 * ((a &&&  ~~~b) ||| (a ^^^ (b ^^^ c))) - 7 *  ~~~(a &&& (b ^^^ c)) + 5 * (c ^^^ (a ||| (b ||| c))) + 11 * (b &&& (a |||  ~~~c)) + 11 * ((b &&& c) ||| ( ~~~a &&& (b ||| c))) - 5 * (b ^^^ (a &&& (b ^^^ c))) + 3 * (b ^^^ (a ||| (b ^^^ c))) + 5 * (c ||| (a ^^^ b)) - 6 * (a ^^^ (b ^^^ c)) + 8 *  ~~~(a ||| (b ||| c)) - 22 *  ~~~(a ||| ( ~~~b ||| c)) - 3 *  ~~~( ~~~a ||| (b ||| c)) - 20 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 7 * ( ~~~a &&& ( ~~~b &&& c)) - 8 * ( ~~~a &&& (b &&& c)) - 12 * (a &&& ( ~~~b &&& c)) - 19 * (a &&& (b &&& c)) = 2 * (c ^^^  ~~~(a &&& ( ~~~b ||| c)))

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

theorem and_or1_wrong_operand_proof : and_or1_wrong_operand_before ⊑ and_or1_wrong_operand_after

theorem ashrsgt_02_12_exact_proof : ashrsgt_02_12_exact_before ⊑ ashrsgt_02_12_exact_after

theorem urem_i32_c_proof : urem_i32_c_before ⊑ urem_i32_c_after

theorem e_328 :
     - 1 *  ~~~x - 2 * (x ||| y) - 6 *  ~~~y + 7 * (x ^^^ y) - 3 *  ~~~(x ^^^ y) + 10 *  ~~~(x ||| y) + 1 * (x &&&  ~~~y) + 5 * (x &&& y) = 4 *  ~~~(x |||  ~~~y)

theorem PR30273_three_bools_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 1),
  x_2 = 1#1 →
    x_1 = 1#1 →
      ¬(True ∧ (zeroExtend 32 x).saddOverflow 1#32 = true) →
        x = 1#1 →
          ¬(True ∧ (zeroExtend 32 x + 1#32).saddOverflow 1#32 = true) →
            True ∧ (2#32).saddOverflow (zeroExtend 32 x_2) = true ∨
                True ∧ (2#32).uaddOverflow (zeroExtend 32 x_2) = true →
              False

theorem f_var1_proof : f_var1_before ⊑ f_var1_after

theorem main5f_like_thm (e e_1 e_2 : IntW 32) :
  select (LLVM.or (icmp IntPred.ne (LLVM.and e_2 e_1) e_2) (icmp IntPred.ne (LLVM.and e_2 e) e_2))
      (const? 32 0) (const? 32 1) ⊑
    zext 32 (icmp IntPred.eq (LLVM.and e_2 (LLVM.and e_1 e)) e_2)

theorem ashr_shl_constants_proof : ashr_shl_constants_before ⊑ ashr_shl_constants_after

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

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

theorem width5 (w : Nat) (a b : BitVec w) : (a + b = a - a) → a = - b

theorem e_1327 :
    1 * (z |||  ~~~t) + 5 * (z ^^^ t) - 1 *  ~~~(z &&&  ~~~t) - 2 * z - 5 *  ~~~z + 3 *  ~~~(z &&&  ~~~z) - 15 *  ~~~(z |||  ~~~t) - 9 * (z &&&  ~~~t) - 12 * (z &&& t) =  - 2 *  ~~~(z &&& t) - 11 * t

theorem pr51551_proof : pr51551_before ⊑ pr51551_after

theorem trunc_equality_nsw_zext_proof : trunc_equality_nsw_zext_before ⊑ trunc_equality_nsw_zext_after

theorem select_of_symmetric_selects_thm.extracted_1._6 : ∀ (x x_1 : BitVec 32) (x_2 x_3 : BitVec 1),
  x_3 = 1#1 → ¬x_2 = 1#1 → ¬x_2 ^^^ x_3 = 1#1 → x = x_1

theorem e_1523 :
    2 * (b ^^^  ~~~( ~~~a &&& (b &&& c))) + 1 * (b ^^^  ~~~( ~~~a &&& ( ~~~b &&& c))) + 2 * (b |||  ~~~(a |||  ~~~c)) - 1 * ((a &&& c) ||| (b &&&  ~~~c)) - 3 *  ~~~(a ||| (b ||| c)) - 1 *  ~~~(a ||| ( ~~~b ||| c)) - 3 *  ~~~( ~~~a ||| (b ||| c)) - 1 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 4 * ( ~~~a &&& (b &&& c)) - 2 * (a &&& ( ~~~b &&& c)) - 1 * (a &&& (b &&& c)) = 4 * ( ~~~a &&& ( ~~~b &&& c))

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

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

theorem test_lshr__exact_is_unsafe_proof : test_lshr__exact_is_unsafe_before ⊑ test_lshr__exact_is_unsafe_after

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 not_sub_thm (e : IntW 32) :
  LLVM.xor (sub (const? 32 123) e) (const? 32 (-1)) ⊑ add e (const? 32 (-124))

theorem lshr_neg_slt_zero_thm (e : IntW 8) :
  icmp IntPred.slt (lshr (const? 8 (-17)) e) (const? 8 0) ⊑ icmp IntPred.eq e (const? 8 0)

theorem mul_constant_eq_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 * 5#32 == x * 5#32) = ofBool (x_1 == x)

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

theorem main12_thm (e : IntW 32) :
  select (LLVM.or (icmp IntPred.slt (trunc 16 e) (const? 16 0)) (icmp IntPred.slt (trunc 8 e) (const? 8 0)))
      (const? 32 2) (const? 32 1) ⊑
    select (icmp IntPred.eq (LLVM.and e (const? 32 32896)) (const? 32 0)) (const? 32 1) (const? 32 2)

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

@[simp]
theorem EnvFin.getLsbD_getLsb {w : Nat} (env : EnvFin (w + 1) n) (bit : Nat) : (env.getLsb i).getLsbD bit =
    if bit = 0 then (env i)[0] else false

theorem sge_swap_and_max_logical_proof : sge_swap_and_max_logical_before ⊑ sge_swap_and_max_logical_after

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

theorem e_1562 :
     - 1 * (b ||| (a ^^^ c)) + 4 *  ~~~( ~~~a ||| (b &&& c)) - 2 * ((a |||  ~~~b) &&&  ~~~(a ^^^ (b ^^^ c))) - 11 * (b ^^^ ( ~~~a ||| (b ||| c))) - 5 *  ~~~( ~~~a ||| ( ~~~b &&& c)) - 6 * ( ~~~b ||| (a ^^^ c)) - 7 * ((a &&& b) ^^^ (b |||  ~~~c)) + 7 *  ~~~(b ^^^ c) + 22 *  ~~~(a ||| (b ||| c)) + 8 *  ~~~( ~~~a ||| (b ||| c)) + 13 *  ~~~( ~~~a ||| ( ~~~b ||| c)) + 21 * ( ~~~a &&& ( ~~~b &&& c)) + 10 * ( ~~~a &&& (b &&& c)) + 18 * (a &&& ( ~~~b &&& c)) + 2 * (a &&& (b &&& c)) = 3 * ( ~~~a ||| (b ||| c)) - 11 *  ~~~(a ||| ( ~~~b ||| c))

theorem n1_thm.extracted_1._2 : ∀ (x x_1 : BitVec 8),
  ¬x_1 ≥ ↑8 →
    ¬(True ∧ 1#8 <<< x_1 >>> x_1 ≠ 1#8 ∨ x_1 ≥ ↑8) →
      ofBool ((1#8 <<< x_1 ^^^ -1#8) &&& x == x) = ofBool (x &&& 1#8 <<< x_1 == 0#8)

theorem t0_proof : t0_before ⊑ t0_after

theorem add_or_sub_comb_i8_commuted2_nsw_thm.extracted_1._2 : ∀ (x : BitVec 8),
  ¬(True ∧ (x * x).saddOverflow (0#8 - x * x ||| x * x) = true) →
    ¬(True ∧ (x * x).saddOverflow (-1#8) = true) → x * x + (0#8 - x * x ||| x * x) = x * x + -1#8 &&& x * x

theorem eq_smax2_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (x <ₛ x_1) = 1#1 → ofBool (x == x) = ofBool (x_1 ≤ₛ x)

theorem const_sub_const_sub_thm (e : IntW 32) : sub (const? 32 2) (sub (const? 32 8) e) ⊑ add e (const? 32 (-6))

theorem n2_badmask_proof : n2_badmask_before ⊑ n2_badmask_after

theorem test_invert_demorgan_or2_proof : test_invert_demorgan_or2_before ⊑ test_invert_demorgan_or2_after

theorem e_1142 :
     - 1 *  ~~~(z &&&  ~~~z) + 1 * t - 11 * (z ^^^ t) - 2 *  ~~~(z ^^^ t) + 8 *  ~~~(z ||| t) + 16 *  ~~~(z |||  ~~~t) + 17 * (z &&&  ~~~t) + 2 * (z &&& t) = 5 *  ~~~(z &&& t)

theorem negative_not_less_than_logical_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (-1#32 <ₛ x) = 1#1 → ofBool (x + 256#32 <ᵤ 256#32) = 0#1

theorem neg_mask2_lshr_thm (e : IntW 8) :
  sub (const? 8 0) (LLVM.and (lshr e (const? 8 3)) (const? 8 2)) ⊑
    sub (const? 8 0) (LLVM.and (lshr e (const? 8 3)) (const? 8 2)) { «nsw» := true, «nuw» := false }

theorem udiv_mul_shl_nuw_thm.extracted_1._2 : ∀ (x x_1 x_2 : BitVec 5),
  ¬(True ∧ x_2.umulOverflow x_1 = true ∨ True ∧ x_2 <<< x >>> x ≠ x_2 ∨ x ≥ ↑5 ∨ x_2 <<< x = 0) →
    ¬x ≥ ↑5 → x_2 * x_1 / x_2 <<< x = x_1 >>> x

theorem test9_thm.extracted_1._2 : ∀ (x : BitVec 77),
  ¬(True ∧ (x &&& 562949953421310#77 &&& 1#77 != 0) = true) →
    (x &&& 562949953421310#77) + 1#77 = x &&& 562949953421310#77 ||

theorem or_xor_tree_0000_thm (e e_1 e_2 : IntW 32) :
  LLVM.or (LLVM.xor (mul e_2 (const? 32 42)) (mul e_1 (const? 32 42)))
      (LLVM.xor (LLVM.xor (mul e_1 (const? 32 42)) (mul e (const? 32 42))) (mul e_2 (const? 32 42))) ⊑
    LLVM.or (LLVM.xor (mul e_2 (const? 32 42)) (mul e_1 (const? 32 42))) (mul e (const? 32 42))

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

theorem or_xor_commute4_thm (e e_1 : IntW 32) :
  LLVM.xor (LLVM.udiv (const? 32 42) e_1) (LLVM.or (LLVM.udiv (const? 32 42) e) (LLVM.udiv (const? 32 42) e_1)) ⊑
    LLVM.and (LLVM.udiv (const? 32 42) e) (LLVM.xor (LLVM.udiv (const? 32 42) e_1) (const? 32 (-1)))

theorem src_is_mask_xor_fail_notmask_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ofBool ((x_1 ^^^ 123#8) &&& (x ^^^ x + -1#8 ^^^ -1#8) != x_1 ^^^ 123#8) =
    ofBool (x ^^^ 0#8 - x ||| x_1 ^^^ BitVec.ofInt 8 (-124) != -1#8)

theorem sel_false_val_is_a_masked_lshr_of_true_val1_thm.extracted_1._3 : ∀ (x : BitVec 64) (x_1 : BitVec 32),
  ¬ofBool (x_1 &&& 60#32 == 0#32) = 1#1 →
    ¬(2#32 ≥ ↑32 ∨ zeroExtend 64 ((x_1 &&& 60#32) >>> 2#32) ≥ ↑64) →
      2#32 ≥ ↑32 ∨ True ∧ (x_1 >>> 2#32 &&& 15#32).msb = true ∨ zeroExtend 64 (x_1 >>> 2#32 &&& 15#32) ≥ ↑64 → False

theorem test14_proof : test14_before ⊑ test14_after

theorem test_lshr_exact__exact_is_safe_thm.extracted_1._1 : ∀ (x : BitVec 64) (x_1 : BitVec 32),
  ofBool (x_1 &&& 60#32 == 0#32) = 1#1 →
    2#32 ≥ ↑32 ∨ True ∧ (x_1 >>> 2#32 &&& 15#32).msb = true ∨ zeroExtend 64 (x_1 >>> 2#32 &&& 15#32) ≥ ↑64 → False

@[simp_llvm_option]
theorem LLVM.IntW.value_isRefinedBy_iff (a : BitVec w) (b? : PoisonOr (BitVec w)) :
    value a ⊑ b? ↔ b? = value a

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

theorem ashr_mul_proof : ashr_mul_before ⊑ ashr_mul_after

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

theorem trunc_ashr_proof : trunc_ashr_before ⊑ trunc_ashr_after

theorem bools_multi_uses1_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 1),
  x_2 = 1#1 → ((x_2 ^^^ 1#1) &&& x_1 ||| x_2 &&& x) ^^^ (x_2 ^^^ 1#1) &&& x_1 = x ^^^ x_1 &&& (x_2 ^^^ 1#1)

theorem p_commutative4_proof : p_commutative4_before ⊑ p_commutative4_after

theorem ule_or_min_commute_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ofBool (x_1 == 0#8) ||

theorem lshrugt_01_02_proof : lshrugt_01_02_before ⊑ lshrugt_01_02_after

theorem intMin_eq_one {w : Nat} (hw : w ≤ 1): BitVec.intMin w = 1

theorem e_1729 :
    2 * ((a ||| b) &&&  ~~~(b ^^^ c)) - 1 * (b ^^^ (a &&&  ~~~c)) + 7 *  ~~~(b &&& c) - 1 * ((a &&& b) ^^^ (b |||  ~~~c)) - 1 *  ~~~(a &&&  ~~~b) - 1 * ( ~~~(a |||  ~~~b) ||| (a ^^^ (b ^^^ c))) + 3 * ((a &&& c) ^^^ (a ^^^ ( ~~~b &&& c))) + 3 * (b &&&  ~~~(a &&&  ~~~c)) + 1 * (b &&&  ~~~(a ^^^ c)) - 6 * ( ~~~(a &&&  ~~~b) &&&  ~~~(a ^^^ (b ^^^ c))) - 2 *  ~~~(a |||  ~~~c) - 1 *  ~~~( ~~~a &&& ( ~~~b &&& c)) + 1 * ( ~~~a &&& ( ~~~b ||| c)) + 11 * (a &&& b) + 7 *  ~~~(a ||| b) - 2 * (a ^^^ (b ^^^ c)) + 7 * (a ||| (b &&& c)) - 3 *  ~~~( ~~~a &&& (b &&& c)) + 3 * (c ^^^ ( ~~~a ||| ( ~~~b ||| c))) + 4 * (a ||| b) + 11 * ((a &&&  ~~~b) |||  ~~~(b ^^^ c)) - 5 * (b ^^^  ~~~(a ||| ( ~~~b &&& c))) + 1 *  ~~~(a &&& ( ~~~b ||| c)) - 13 *  ~~~(a ||| (b ||| c)) - 13 *  ~~~(a ||| ( ~~~b ||| c)) - 32 *  ~~~( ~~~a ||| (b ||| c)) - 17 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 14 * ( ~~~a &&& ( ~~~b &&& c)) - 16 * ( ~~~a &&& (b &&& c)) - 32 * (a &&& ( ~~~b &&& c)) - 25 * (a &&& (b &&& c)) =  - 4 * (b ^^^ (a ||| c))

theorem alive_AndOrXor_2658  (w : Nat)   : alive_AndOrXor_2658_src w  ⊑ alive_AndOrXor_2658_tgt w

theorem test_sub_nuw__nuw_is_safe_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 2147483647#32 == 1073741824#32) = 1#1 →
    True ∧ (BitVec.ofInt 32 (-2147483648)).usubOverflow (x &&& 2147483647#32) = true → False

theorem BitVec.even_mul_eq_shiftLeft_mul_of_eq_mul_two
    (w : Nat) (x : BitVec w) (n e : Nat) (he : e = n * 2) :
    (BitVec.ofNat w e) * x = (BitVec.ofNat w n) * (x <<< (1 : Nat))

theorem test2_proof : test2_before ⊑ test2_after

theorem lsb_mask_sign_sext_commuted_thm (e : IntW 32) :
  ashr (LLVM.and (LLVM.xor e (const? 32 (-1))) (add e (const? 32 (-1)))) (const? 32 31) ⊑
    sext 32 (icmp IntPred.eq e (const? 32 0))

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

theorem lshr_32_add_not_known_32_leading_zeroes_proof : lshr_32_add_not_known_32_leading_zeroes_before ⊑ lshr_32_add_not_known_32_leading_zeroes_after

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

theorem icmp_eq_and_pow2_lshr_pow2_case2_proof : icmp_eq_and_pow2_lshr_pow2_case2_before ⊑ icmp_eq_and_pow2_lshr_pow2_case2_after

theorem add_select_sext_thm.extracted_1._2 : ∀ (x : BitVec 1), ¬x = 1#1 → 1#64 + signExtend 64 x = 1#64

theorem ashr_ult_exact_near_pow2_cmpval_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬(True ∧ x >>> 1#8 <<< 1#8 ≠ x ∨ 1#8 ≥ ↑8) → ofBool (x.sshiftRight' 1#8 <ᵤ 5#8) = ofBool (x <ᵤ 9#8)

theorem ult_rem_nz_nsw_proof : ult_rem_nz_nsw_before ⊑ ult_rem_nz_nsw_after

theorem masked_icmps_mask_notallzeros_bmask_mixed_swapped_1b_logical_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬ofBool (x &&& 3#32 == 1#32) = 1#1 → 0#1 = ofBool (x &&& 3#32 == 1#32) &&& ofBool (x &&& 14#32 != 0#32)

theorem must_drop_poison_proof : must_drop_poison_before ⊑ must_drop_poison_after

theorem andn_or_cmp_4_logical_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 == x) = 1#1 → ofBool (x_1 != x) = 1#1 → True → False

theorem n2_thm (e e_1 : IntW 8) (e_2 : IntW 1) :
  LLVM.and (LLVM.xor e_2 (const? 1 1)) (icmp IntPred.eq e_1 e) ⊑
    LLVM.and (icmp IntPred.eq e_1 e) (LLVM.xor e_2 (const? 1 1))

theorem and_two_ranges_to_mask_and_range_not_pow2_diff_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ofBool (25#8 <ᵤ x + BitVec.ofInt 8 (-97)) &&& ofBool (25#8 <ᵤ x + BitVec.ofInt 8 (-64)) =
    ofBool (x + BitVec.ofInt 8 (-123) <ᵤ BitVec.ofInt 8 (-26)) &&&
      ofBool (x + BitVec.ofInt 8 (-90) <ᵤ BitVec.ofInt 8 (-26))

theorem trunc_lshr_big_mask_proof : trunc_lshr_big_mask_before ⊑ trunc_lshr_big_mask_after

theorem p13_commutativity0_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 <ᵤ 65536#32) = 1#1 → ofBool (65535#32 <ᵤ x_1) = 1#1 → 65535#32 = x

theorem p0_thm (e e_1 : IntW 8) :
  icmp IntPred.ugt (shl (const? 8 1) e_1) e ⊑ icmp IntPred.eq (lshr e e_1) (const? 8 0)

theorem fold_sext_to_and_wrong2_proof : fold_sext_to_and_wrong2_before ⊑ fold_sext_to_and_wrong2_after

@[simp] theorem getElem?_map (Γ : Ctxt Ty) (f : Ty → Ty') (i : Nat) :
    (Γ.map f)[i]? = Γ[i]?.map f

theorem test15a_proof : test15a_before ⊑ test15a_after

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

theorem icmp_ne_sext_ne_otherwise_i128_thm.extracted_1._1 : ∀ (x : BitVec 128),
  ofBool (signExtend 128 (ofBool (x != 2#128)) != x) = ofBool (x != -1#128)
</all_available_lemmas>

<local_ctx>
import Batteries.Data.Fin.Basic

import Batteries.Data.Fin.Lemmas

import Blase.SingleWidth.Defs

import Blase.AutoStructs.Constructions

import Blase.AutoStructs.Defs

import Blase.AutoStructs.FiniteStateMachine

import Mathlib.Tactic.Ring

import Mathlib.Data.Nat.Size -- TODO: remove and get rid of shiftLeft_eq_mul_pow use

import Mathlib.Data.BitVec

import Mathlib.Tactic.FinCases

open Fin.NatCast

open Mathlib

def NFA.sa (_ : NFA α σ) := σ → Language α

structure NFA.correct (M : NFA α σ) (ζ : M.sa) (L : Language α) where
  cond1 : ∀ w, (w ∈ L ↔ ∃ q ∈ M.accept, w ∈ ζ q)
  cond2 : ∀ w q, q ∈ M.eval w ↔ w ∈ ζ q

abbrev BVRel := ∀ ⦃w⦄, BitVec w → BitVec w → Prop

abbrev BVNRel n := ∀ ⦃w⦄, List.Vector (BitVec w) n → Prop

def NFA'.sa (M : NFA' n) := M.σ → BVNRel n

def NFA'.sa2 (M : NFA' 2) := M.σ → BVRel

def langRel (R : BVNRel n) : Set (BitVecs n) :=
  { bvs | R bvs.bvs }

def langRel2 (R : BVRel) : Set (BitVecs 2) :=
  { bvs | R (bvs.bvs.get 0) (bvs.bvs.get 1) }

structure NFA'.correct (M : NFA' n) (ζ : M.sa) (L : BVNRel n) where
  cond1 : ∀ ⦃w⦄ (bvn : List.Vector (BitVec w) n), (L bvn ↔ ∃ q ∈ M.M.accept, ζ q bvn)
  cond2 q : q ∈ M.M.start ↔ ζ q (List.Vector.replicate n .nil)
  cond3 q a {w} (bvn : List.Vector (BitVec w) n) : q ∈ M.M.stepSet { q | ζ q bvn } a ↔
              ζ q (List.Vector.ofFn fun k => BitVec.cons (a.getLsbD k) (bvn.get k))

structure NFA'.correct2 (M : NFA' 2) (ζ : M.sa2) (L : BVRel) where
  cond1 : ∀ (bv1 bv2 : BitVec w), (L bv1 bv2 ↔ ∃ q ∈ M.M.accept, ζ q bv1 bv2)
  cond2 q : q ∈ M.M.start ↔ ζ q .nil .nil
  cond3 q a w (bv1 bv2 : BitVec w) : q ∈ M.M.stepSet { q | ζ q bv1 bv2 } a ↔
              ζ q (BitVec.cons (a.getLsbD 0) bv1) (BitVec.cons (a.getLsbD 1) bv2)

section fsm

variable {arity : Type} [FinEnum arity]

open BitStream in

end fsm

section nfas_relations

def NFA.autEq : NFA (BitVec 2) Unit :=
  { start := ⊤, accept := ⊤, step _ a := { _s' | if a = 0 ∨ a = 3 then true else false }}

def NFA'.autEq : NFA' 2 :=
  ⟨Unit, NFA.autEq⟩

def NFA'.eqRel : BVRel := fun _ x y => x = y

inductive NFA.unsignedCmpState : Type where
| eq | gt | lt
deriving Fintype, DecidableEq

def NFA.unsignedCmpStep (q : NFA.unsignedCmpState) (a : BitVec 2) : List NFA.unsignedCmpState :=
  match q, a with
  | .eq, 0 => [ .eq ] | .eq, 3 => [ .eq ] | .eq, 1 => [ .gt ] | .eq, 2 => [ .lt ]
  | .gt, 0 => [ .gt ] | .gt, 1 => [ .gt ] | .gt, 3 => [ .gt ] | .gt, 2 => [ .lt ]
  | .lt, 0 => [ .lt ] | .lt, 1 => [ .gt ] | .lt, 2 => [ .lt ] | .lt, 3 => [ .lt ]

def NFA.autUnsignedCmp (cmp: RelationOrdering) : NFA (BitVec 2) unsignedCmpState where
  step s a := { s' | s' ∈ unsignedCmpStep s a }
  start := {s | s = .eq }
  accept := { s | s ∈ match cmp with | .lt => [unsignedCmpState.lt] | .le => [.lt, .eq] | .gt => [.gt] | .ge => [.gt, .eq] }

def NFA'.autUnsignedCmp (cmp: RelationOrdering) : NFA' 2 :=
  ⟨_, NFA.autUnsignedCmp cmp⟩

def RelationOrdering.urel (cmp : RelationOrdering) : BVRel :=
  match cmp with
  | .lt => fun _ bv1 bv2 => bv1.ult bv2
  | .le => fun _ bv1 bv2 => bv1.ule bv2
  | .gt => fun _ bv1 bv2 => bv2.ult bv1
  | .ge => fun _ bv1 bv2 => bv2.ule bv1

def NFA'.autUnsignedCmpSA (q : NFA.unsignedCmpState) : BVRel :=
  match q with
  | .eq => fun _ bv1 bv2 => bv1 = bv2
  | .lt => fun _ bv1 bv2 => bv1.ult bv2
  | .gt => fun _ bv1 bv2 => bv2.ult bv1

inductive NFA.signedCmpState : Type where
| eq | gt | lt | ltfin | gtfin
deriving DecidableEq, Fintype

def NFA.signedCmpStep (q : NFA.signedCmpState) (a : BitVec 2) : List NFA.signedCmpState :=
  match q, a with
  | .eq, 0 => [ .eq ] | .eq, 3 => [.eq] | .eq, 1 => [.gt, .ltfin] | .eq, 2 => [ .lt, .gtfin ]
  | .gt, 0 => [ .gt, .gtfin ] | .gt, 1 => [ .gt, .ltfin ] | .gt, 3 => [ .gt, .gtfin ] | .gt, 2 => [ .lt, .gtfin ]
  | .lt, 0 => [ .lt, .ltfin ] | .lt, 1 => [ .gt, .ltfin ] | .lt, 2 => [ .lt, .gtfin ] | .lt, 3 => [ .lt, .ltfin ]
  | .gtfin, _ => ∅
  | .ltfin, _ => ∅

def NFA.autSignedCmp (cmp: RelationOrdering) : NFA (BitVec 2) signedCmpState where
  step s a := { s' | s' ∈ signedCmpStep s a }
  start := { s | s = signedCmpState.eq }
  accept := { s | s ∈ match cmp with | .lt => [NFA.signedCmpState.ltfin] | .le => [.ltfin, .eq] | .gt => [.gtfin] | .ge => [.gtfin, .eq] }

def NFA'.autSignedCmp (cmp: RelationOrdering) : NFA' 2 :=
  ⟨_, NFA.autSignedCmp cmp⟩

def RelationOrdering.srel (cmp : RelationOrdering) : BVRel :=
  match cmp with
  | .lt => fun _ bv1 bv2 => bv1.slt bv2
  | .le => fun _ bv1 bv2 => bv1.sle bv2
  | .gt => fun _ bv1 bv2 => bv2.slt bv1
  | .ge => fun _ bv1 bv2 => bv2.sle bv1

def NFA'.autSignedCmpSA (q : NFA.signedCmpState) : BVRel :=
  match q with
  | .eq => fun _ bv1 bv2 => bv1 = bv2
  | .lt => fun _ bv1 bv2 => bv1.ult bv2
  | .gt => fun _ bv1 bv2 => bv2.ult bv1
  | .ltfin => fun _ bv1 bv2 => bv1.slt bv2
  | .gtfin => fun _ bv1 bv2 => bv2.slt bv1

end nfas_relations

def Relation.absAutOfRelation (rel : Relation) : NFA' 2 :=
  match rel with
  | .eq => NFA'.autEq
  | .unsigned cmp => NFA'.autUnsignedCmp cmp
  | .signed cmp => NFA'.autSignedCmp cmp
</local_ctx>

<target_theorem>
@[simp]
lemma autOfRelation_accepts (r : Relation) :
    r.absAutOfRelation.accepts = r.language :=
</target_theorem>

