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>
DecidableEq in Init.Prelude
Lean.ToExpr in Lean.ToExpr
List in Init.Prelude
Repr in Init.Data.Repr
PUnit in Init.Prelude
Nat in Init.Prelude
Id in Init.Control.Id
Pure in Init.Prelude
decidable_of_iff in Init.PropLemmas
String in Init.Prelude
Valuation.mk in Mathlib.RingTheory.Valuation.Basic
List.map in Init.Prelude
Monad in Init.Prelude
Lean.Parser.Term.matchAlts in Lean.Parser.Term
bool in Init.Control.Basic
Inhabited in Init.Prelude
BitVec in Init.Prelude
Set in Mathlib.Data.Set.Defs
RV64.sub in RISCV.Instructions
RV64.sltiu in RISCV.Instructions
RV64.slt in RISCV.Instructions
RV64.andi in RISCV.Instructions
RV64.sltu in RISCV.Instructions
RV64.adduw in RISCV.Instructions
RV64.addiw in RISCV.Instructions
RV64.xori in RISCV.Instructions
RV64.addi in RISCV.Instructions
RV64.subw in RISCV.Instructions
RV64.add in RISCV.Instructions
RV64.addw in RISCV.Instructions
RV64.andn in RISCV.Instructions
RV64.auipc in RISCV.Instructions
RV64.bclr in RISCV.Instructions
RV64.bclri in RISCV.Instructions
RV64.bext in RISCV.Instructions
RV64.bexti in RISCV.Instructions
RV64.binv in RISCV.Instructions
RV64.binvi in RISCV.Instructions
RV64.bset in RISCV.Instructions
RV64.bseti in RISCV.Instructions
RV64.clz in RISCV.Instructions
RV64.clzw in RISCV.Instructions
RV64.ctz in RISCV.Instructions
RV64.ctzw in RISCV.Instructions
RV64.div in RISCV.Instructions
RV64.divu in RISCV.Instructions
RV64.divuw in RISCV.Instructions
RV64.divw in RISCV.Instructions
RV64.lui in RISCV.Instructions
RV64.max in RISCV.Instructions
RV64.maxu in RISCV.Instructions
RV64.min in RISCV.Instructions
RV64.minu in RISCV.Instructions
RV64.mul in RISCV.Instructions
RV64.mulh in RISCV.Instructions
RV64.mulhsu in RISCV.Instructions
RV64.mulhu in RISCV.Instructions
RV64.mulw in RISCV.Instructions
RV64.ori in RISCV.Instructions
RV64.orn in RISCV.Instructions
RV64.pack in RISCV.Instructions
RV64.packh in RISCV.Instructions
RV64.packw in RISCV.Instructions
RV64.rem in RISCV.Instructions
RV64.remu in RISCV.Instructions
RV64.remuw in RISCV.Instructions
RV64.remw in RISCV.Instructions
RV64.rol in RISCV.Instructions
RV64.rolw in RISCV.Instructions
RV64.ror in RISCV.Instructions
RV64.rori in RISCV.Instructions
RV64.roriw in RISCV.Instructions
RV64.rorw in RISCV.Instructions
RV64.sextb in RISCV.Instructions
RV64.sexth in RISCV.Instructions
RV64.sh1add in RISCV.Instructions
RV64.sh1adduw in RISCV.Instructions
RV64.sh2add in RISCV.Instructions
RV64.sh2adduw in RISCV.Instructions
RV64.sh3add in RISCV.Instructions
RV64.sh3adduw in RISCV.Instructions
RV64.sll in RISCV.Instructions
RV64.slli in RISCV.Instructions
RV64.slliuw in RISCV.Instructions
RV64.slliw in RISCV.Instructions
RV64.sllw in RISCV.Instructions
RV64.slti in RISCV.Instructions
RV64.sra in RISCV.Instructions
RV64.srai in RISCV.Instructions
RV64.sraiw in RISCV.Instructions
RV64.sraw in RISCV.Instructions
RV64.srl in RISCV.Instructions
RV64.srli in RISCV.Instructions
RV64.srliw in RISCV.Instructions
RV64.srlw in RISCV.Instructions
RV64.xnor in RISCV.Instructions
RV64.xor in RISCV.Instructions
RV64.zexth in RISCV.Instructions
Polynomial.X in Mathlib.Algebra.Polynomial.Basic
ZMod in Mathlib.Data.ZMod.Defs
Ideal in Mathlib.RingTheory.Ideal.Defs
Ideal.Quotient.mk in Mathlib.RingTheory.Ideal.Quotient.Defs
Ideal.span in Mathlib.RingTheory.Ideal.Span
Polynomial in Mathlib.Algebra.Polynomial.Basic
Polynomial.monomial in Mathlib.Algebra.Polynomial.Basic
Int in Init.Data.Int.Basic
Function.surjInv in Mathlib.Logic.Function.Basic
Polynomial.coeff in Mathlib.Algebra.Polynomial.Basic
Polynomial.degree in Mathlib.Algebra.Polynomial.Degree.Definitions
List.range in Init.Data.List.Basic
Polynomial.map in Mathlib.Algebra.Polynomial.Eval.Defs
List.replicate in Init.Data.List.Basic
Option in Init.Prelude
BitVec.signExtend in Init.Data.BitVec.Basic
Fin in Init.Prelude
cast in Init.Prelude
cond in Init.Prelude
Stream' in Mathlib.Data.Stream.Defs

structure Ctxt (Ty : Type) : Type where
  ofList :: toList : List Ty
  
  deriving Repr, Lean.ToExpr, DecidableEq

inductive EffectKind
| pure 
| impure 
deriving Repr, DecidableEq, Lean.ToExpr

def Valuation.cast {Γ Δ : Ctxt Ty} (h : Γ = Δ) (V : Valuation Γ) : Valuation Δ :=
  fun _ v => V <| v.castCtxt h.symm

@[simp]
instance Valuation.instAppendHVector (Γ : Ctxt Ty) (ts : List Ty) :
    HAppend (HVector toType ts) (Valuation Γ) (Valuation <| ⟨ts⟩ ++ Γ) where
  hAppend vals V :=
    (Valuation.ofHVector vals) ++ V

class TyDenote (β : Type) : Type 1 where
  toType : β → Type

def Var (Γ : Ctxt Ty) (t : Ty) : Type :=
  { i : Nat // Γ[i]? = some t }

def liftEffect [Pure m] {e1 e2 : EffectKind} {α : Type}
    (hle : e1 ≤ e2) (v1 : e1.toMonad m α) : e2.toMonad m α :=
  match e1, e2, hle with
    | .pure, .pure, _ | .impure, .impure, _ => v1
    | .pure, .impure, _ => Pure.pure v1

def toMonad (e : EffectKind) (m : Type → Type) : Type → Type :=
  match e with
  | pure => Id
  | impure => m

inductive Ty (q : Nat) (n : Nat)
  | index : Ty q n
  | integer : Ty q n
  | tensor : Ty q n
  | polynomialLike : Ty q n
  deriving DecidableEq, Repr

def Valuation.nil : Ctxt.Valuation (∅ : Ctxt Ty) := fun _ v => v.emptyElim

def Valuation.cons {Γ : Ctxt Ty} {t : Ty} (x : toType t) (V : Γ.Valuation) :
    (Γ.cons t).Valuation :=

structure Dialect where
  (Op : Type)
  (Ty : Type)
  (m : Type → Type := Id)

inductive Op (q : Nat) (n : Nat)
  | add : Op q n
  | sub : Op q n
  | mul : Op q n
  | mul_constant : Op q n
    
    
  | leading_term : Op q n
  | monomial : Op q n
  | monomial_mul : Op q n
  | from_tensor : Op q n
  | to_tensor : Op q n
  | const (c : R q n) : Op q n
  | const_int (c : Int) : Op q n
  | const_idx (i : Nat) : Op q n

def map (f : Ty₁ → Ty₂) : Ctxt Ty₁ → Ctxt Ty₂ :=
  ofList ∘ (List.map f) ∘ toList

@[simp_denote]
    instance : DialectDenote $dialect where
      denote := fun op => match op with $matchAlts:matchAlts
  )

noncomputable instance (q : ℕ) [Fact (q > 1)] : DialectDenote (ModArith q) where
denote
  | .add, arg, _ =>
      
      (fun args : R q × R q => args.1 + args.2) arg.toPair
  | .sub, arg, _ =>
      
      (fun args : R q × R q => args.1 - args.2) arg.toPair
  | .mul, arg, _ =>
      
      (fun args : R q × R q => args.1 * args.2) arg.toPair
  | .const _ c, _, _ =>
      
      c

@[reducible]
instance : DialectDenote Ex where
  denote
    | .cst n, _, _ => n ::ₕ .nil
    | .add, .cons (a : Nat) (.cons b .nil), _ => a + b ::ₕ .nil
    | .beq, .cons (a : Nat) (.cons b .nil), _ => (a == b) ::ₕ .nil

inductive ExOp :  Type
  | add : ExOp
  | beq : ExOp
  | cst : ℕ → ExOp
  deriving DecidableEq

def add {Γ : Ctxt _} (e₁ e₂ : Ctxt.Var Γ .nat) : Expr Ex Γ .pure [.nat] :=
  Expr.mk
    (op := .add)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .cons e₁ <| .cons e₂ .nil)
    (regArgs := .nil)

abbrev Ex : Dialect where
  Op := ExOp
  Ty := ExTy

inductive ExTy
  | nat
  | bool
  deriving DecidableEq

def cst {Γ : Ctxt _} (n : ℕ) : Expr Ex Γ .pure [.nat]  :=
  Expr.mk
    (op := .cst n)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .nil)
    (regArgs := .nil)

@[match_pattern]
def cons (hd : Ty) : Ctxt Ty → Ctxt Ty
| ⟨tl⟩ => ⟨hd :: tl⟩

@[simp, reducible]
instance : DialectDenote RV64 where
  denote o args _ := [o.denote args]ₕ

@[simp, simp_denote]
abbrev Op.denote : (o : RV64.Op) → HVector toType o.sig → ⟦o.outTy⟧
  | .li imm, _  => imm
  | .addiw imm, regs => RV64.addiw imm (regs.getN 0)
  | .lui imm, regs  => RV64.lui imm
  | .auipc imm, regs => RV64.auipc imm (regs.getN 0)
  | .slliw shamt, regs => RV64.slliw shamt (regs.getN 0)
  | .srliw shamt, regs => RV64.srliw shamt (regs.getN 0)
  | .sraiw shamt, regs => RV64.sraiw shamt (regs.getN 0)
  | .slli shamt, regs => RV64.slli shamt (regs.getN 0)
  | .srli shamt, regs => RV64.srli shamt (regs.getN 0)
  | .srai shamt, regs => RV64.srai shamt (regs.getN 0)
  | .addw, regs => RV64.addw (regs.getN 1) (regs.getN 0)
  | .subw, regs => RV64.subw (regs.getN 1) (regs.getN 0)
  | .sllw, regs => RV64.sllw (regs.getN 1) (regs.getN 0)
  | .srlw, regs => RV64.srlw (regs.getN 1) (regs.getN 0)
  | .sraw, regs => RV64.sraw (regs.getN 1) (regs.getN 0)
  | .add, regs => RV64.add (regs.getN 1) (regs.getN 0)
  | .slt, regs => RV64.slt (regs.getN 1) (regs.getN 0)
  | .sltu, regs => RV64.sltu (regs.getN 1) (regs.getN 0)
  | .and, regs => RV64.and (regs.getN 1) (regs.getN 0)
  | .or, regs => RV64.or (regs.getN 1) (regs.getN 0)
  | .xor, regs => RV64.xor (regs.getN 1) (regs.getN 0)
  | .sll, regs => RV64.sll (regs.getN 1) (regs.getN 0)
  | .srl, regs => RV64.srl (regs.getN 1) (regs.getN 0)
  | .sub, regs => RV64.sub (regs.getN 1) (regs.getN 0)
  | .sra, regs => RV64.sra (regs.getN 1) (regs.getN 0)
  | .remw, regs => RV64.remw (regs.getN 1) (regs.getN 0)
  | .remuw, regs => RV64.remuw (regs.getN 1) (regs.getN 0)
  | .rem, regs => RV64.rem (regs.getN 1) (regs.getN 0)
  | .remu, regs => RV64.remu (regs.getN 1) (regs.getN 0)
  | .mulhu,regs => RV64.mulhu (regs.getN 1) (regs.getN 0)
  | .mul ,regs => RV64.mul (regs.getN 1) (regs.getN 0)
  | .mulhsu ,regs => RV64.mulhsu (regs.getN 1) (regs.getN 0)
  | .mulh,regs => RV64.mulh (regs.getN 1) (regs.getN 0)
  | .mulw,  regs => RV64.mulw (regs.getN 1) (regs.getN 0)
  | .div, regs => RV64.div (regs.getN 1) (regs.getN 0)
  | .divu, regs => RV64.divu (regs.getN 1) (regs.getN 0)
  | .divw, regs => RV64.divw (regs.getN 1) (regs.getN 0)
  | .divuw, regs => RV64.divuw (regs.getN 1) (regs.getN 0)
  | .addi imm, reg => RV64.addi imm (reg.getN 0)
  | .slti imm, reg => RV64.slti imm (reg.getN 0)
  | .sltiu imm, reg => RV64.sltiu imm (reg.getN 0)
  | .andi imm, reg => RV64.andi imm (reg.getN 0)
  | .ori imm, reg => RV64.ori imm (reg.getN 0)
  | .xori imm, reg => RV64.xori imm (reg.getN 0)
  | .bclr, regs => RV64.bclr (regs.getN 1) (regs.getN 0)
  | .bext, regs => RV64.bext (regs.getN 1) (regs.getN 0)
  | .binv, regs => RV64.binv (regs.getN 1) (regs.getN 0)
  | .bset, regs => RV64.bset (regs.getN 1) (regs.getN 0)
  | .bclri shamt , reg => RV64.bclri shamt (reg.getN 0)
  | .bexti shamt, reg => RV64.bexti shamt (reg.getN 0)
  | .binvi shamt, reg => RV64.binvi shamt (reg.getN 0)
  | .bseti shamt, reg => RV64.bseti shamt (reg.getN 0)
  | .adduw, regs => RV64.adduw (regs.getN 1) (regs.getN 0)
  | .sh1adduw , regs => RV64.sh1adduw (regs.getN 1) (regs.getN 0)
  | .sh2adduw, regs => RV64.sh2adduw (regs.getN 1) (regs.getN 0)
  | .sh3adduw, regs => RV64.sh3adduw (regs.getN 1) (regs.getN 0)
  | .sh1add, regs => RV64.sh1add (regs.getN 1) (regs.getN 0)
  | .sh2add, regs => RV64.sh2add (regs.getN 1) (regs.getN 0)
  | .sh3add, regs => RV64.sh3add (regs.getN 1) (regs.getN 0)
  | .slliuw shamt, regs => RV64.slliuw shamt (regs.getN 0)
  | .andn, regs => RV64.andn (regs.getN 1) (regs.getN 0)
  | .orn, regs => RV64.orn (regs.getN 1) (regs.getN 0)
  | .xnor, regs => RV64.xnor (regs.getN 1) (regs.getN 0)
  | .clz, regs => RV64.clz (regs.getN 1)
  | .clzw, regs => RV64.clzw (regs.getN 1)
  | .ctz, regs => RV64.ctz (regs.getN 1)
  | .ctzw, regs => RV64.ctzw (regs.getN 1)
  | .max, regs => RV64.max (regs.getN 1) (regs.getN 0)
  | .maxu, regs => RV64.maxu (regs.getN 1) (regs.getN 0)
  | .min, regs => RV64.min (regs.getN 1) (regs.getN 0)
  | .minu, regs => RV64.minu (regs.getN 1) (regs.getN 0)
  | .sextb, reg => RV64.sextb (reg.getN 0)
  | .sexth, reg => RV64.sexth (reg.getN 0)
  | .zexth, reg => RV64.zexth (reg.getN 0)
  | .rol, regs => RV64.rol (regs.getN 1) (regs.getN 0)
  | .rolw, regs => RV64.rolw (regs.getN 1) (regs.getN 0)
  | .ror, regs => RV64.ror (regs.getN 1) (regs.getN 0)
  | .rori shamt, regs => RV64.rori shamt (regs.getN 0)
  | .roriw shamt, regs => RV64.roriw shamt (regs.getN 0)
  | .rorw, regs => RV64.rorw (regs.getN 1) (regs.getN 0)
  | .pack, regs => RV64.pack (regs.getN 1) (regs.getN 0)
  | .packh, regs => RV64.packh (regs.getN 1) (regs.getN 0)
  | .packw, regs => RV64.packw (regs.getN 1) (regs.getN 0)
  
  | .mv, regs  => RV64.mv_pseudo (regs.getN 0)
  | .not, regs => RV64.not_pseudo (regs.getN 0)
  | .neg, regs => RV64.neg_pseudo (regs.getN 0)
  | .negw, regs => RV64.negw_pseudo (regs.getN 0)
  | .sextw, regs => RV64.sextw_pseudo (regs.getN 0)
  | .zextb, regs => RV64.zextb_pseudo (regs.getN 0)
  | .zextw, regs => RV64.zextw_pseudo (regs.getN 0)
  | .seqz, regs => RV64.seqz_pseudo (regs.getN 0)
  | .snez, regs => RV64.snez_pseudo (regs.getN 0)
  | .sltz, regs => RV64.sltz_pseudo (regs.getN 0)
  | .sgtz, regs => RV64.sgtz_pseudo (regs.getN 0)

inductive Op
   
  | li : (val : BitVec 64) → Op
  | lui (imm : BitVec 20)
  | auipc (imm : BitVec 20)
  | addi (imm : BitVec 12)
  | andi (imm : BitVec 12)
  | ori (imm : BitVec 12)
  | xori (imm : BitVec 12)
  | addiw (imm : BitVec 12)
  | add
  | slli (shamt : BitVec 6)
  | sub
  | and
  | or
  | xor
  | sll
  | srl
  | sra
  | addw
  | subw
  | sllw
  | srlw
  | sraw
  | slti (imm : BitVec 12)
  | sltiu (imm : BitVec 12)
  | srli (shamt : BitVec 6)
  | srai (shamt : BitVec 6)
  | slliw (shamt : BitVec 5)
  | srliw (shamt : BitVec 5)
  | sraiw (shamt : BitVec 5)
  | slt
  | sltu
   
  | mul
  | mulw
  | mulh
  | mulhu
  | mulhsu
  | divw
  | divuw
  | div
  | divu
  | remw
  | rem
  | remuw
  | remu
   
   
  | adduw
  | sh1adduw
  | sh2adduw
  | sh3adduw
  | sh1add
  | sh2add
  | sh3add
  | slliuw (shamt : BitVec 6)
   
  | andn
  | orn
  | xnor
  | clz
  | clzw
  | ctz
  | ctzw
  | max
  | maxu
  | min
  | minu
  | sextb
  | sexth
  | zexth
  | rol
  | rolw
  | ror
  | rori (_shamt : BitVec 6)
  | roriw (_shamt : BitVec 5)
  | rorw
   
  | bclr
  | bclri (shamt : BitVec 6)
  | bext
  | bexti (shamt : BitVec 6)
  | binv
  | binvi (shamt : BitVec 6)
  | bset
  | bseti (shamt : BitVec 6)
   
  | pack
  | packh
  | packw
   
  | mv
  | not
  | neg
  | negw
  | sextw
  | zextb
  | zextw
  | seqz
  | snez
  | sltz
  | sgtz
  deriving DecidableEq, Repr, Lean.ToExpr

@[simp]
abbrev RV64 : Dialect where
  Op := Op
  Ty := Ty

inductive Ty
  | bv : Ty
  deriving DecidableEq, Repr, Inhabited, Lean.ToExpr

@[simp_riscv]
def neg_pseudo (rs1_val : BitVec 64) : BitVec 64 :=
  RV64.sub rs1_val 0

@[simp_riscv]
def seqz_pseudo (rs1_val : BitVec 64) : BitVec 64 :=
  RV64.sltiu 1 rs1_val

@[simp_riscv]
def sgtz_pseudo (rs1_val : BitVec 64) : BitVec 64 :=
  RV64.slt rs1_val 0

@[simp_riscv]
def zextb_pseudo (rs1_val : BitVec 64) : BitVec 64 :=
  RV64.andi 255 rs1_val

@[simp_riscv]
def snez_pseudo (rs1_val : BitVec 64) : BitVec 64 :=
  RV64.sltu rs1_val 0

@[simp_riscv]
def sltz_pseudo (rs1_val : BitVec 64) : BitVec 64 :=
  RV64.slt 0 rs1_val

@[simp_riscv]
def zextw_pseudo (rs1_val : BitVec 64) : BitVec 64 :=
  RV64.adduw 0 rs1_val

@[simp_riscv]
def sextw_pseudo (rs1_val : BitVec 64) : BitVec 64 :=
  RV64.addiw 0 rs1_val

@[simp_riscv]
def not_pseudo (rs1_val : BitVec 64) : BitVec 64 :=
  RV64.xori (-1) rs1_val

@[simp_riscv]
def mv_pseudo (rs1_val : BitVec 64) : BitVec 64 :=
  RV64.addi 0 rs1_val

@[simp_riscv]
def negw_pseudo (rs1_val : BitVec 64) : BitVec 64 :=
  RV64.subw rs1_val 0

@[simp]
noncomputable instance : DialectDenote (FHE q n) where
    denote
    | Op.add, arg, _ => [(fun args : R q n × R q n => args.1 + args.2) arg.toPair]ₕ
    | Op.sub, arg, _ => [(fun args : R q n × R q n => args.1 - args.2) arg.toPair]ₕ
    | Op.mul, arg, _ => [(fun args : R q n × R q n => args.1 * args.2) arg.toPair]ₕ
    | Op.mul_constant, arg, _ => [(fun args : R q n × Int => args.1 * ↑(args.2)) arg.toPair]ₕ
    | Op.leading_term, arg, _ => [R.leadingTerm arg.toSingle]ₕ
    | Op.monomial, arg, _ => [(fun args => R.monomial ↑(args.1) args.2) arg.toPair]ₕ
    | Op.monomial_mul, arg, _ => [(fun args : R q n × Nat => args.1 * R.monomial 1 args.2) arg.toPair]ₕ
    | Op.from_tensor, arg, _ => [R.fromTensor arg.toSingle]ₕ
    | Op.to_tensor, arg, _ => [R.toTensor' arg.toSingle]ₕ
    | Op.const c, _arg, _
    | Op.const_int c, _, _
    | Op.const_idx c, _, _ => [c]ₕ

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

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

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

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

noncomputable def R.leadingTerm {q n} (a : R q n) : R q n :=
  let deg? := Polynomial.degree a.representative
  match deg? with
    | .none => 0
    | .some deg =>  R.monomial (a.coeff deg) deg

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

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

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

noncomputable def R.toTensor' {q n} (a : R q n) : List Int :=
  let t := a.toTensor
  t ++ List.replicate (2^n - t.length + 1) 0

noncomputable def R.toTensor {q n} (a : R q n) : List Int :=
  List.range a.repLength |>.map fun i =>
        a.coeff i |>.toInt

noncomputable def R.repLength {q n} (a : R q n) : Nat := match
  Polynomial.degree a.representative with
    | none => 0
    | some d => d + 1

instance : DialectDenote LLVM := ⟨
  fun o args _ => [Op.denote o args]ₕ
⟩

@[reducible]
instance : DialectDenote SimpleReg where
  denote
    | .const n, _, _ => BitVec.ofInt 32 n ::ₕ .nil
    | .add, [(a : BitVec 32), (b : BitVec 32)]ₕ , _ => a + b ::ₕ .nil
    | .iterate k, [(x : BitVec 32)]ₕ, [(f : _ → _)]ₕ =>
      let f := fun y => (f y).getN 0
      let f' (v :  BitVec 32) : BitVec 32 := f (Ctxt.Valuation.nil.cons v)
      let y := k.iterate f' x
      [y]ₕ

inductive Op :  Type
  | add : Op
  | const : (val : ℤ) → Op
  | iterate (k : ℕ) : Op
  deriving DecidableEq

@[simp_denote]
def add {Γ : Ctxt _} (e₁ e₂ : Var Γ int) : Expr SimpleReg Γ .pure [int] :=
  Expr.mk
    (op := .add)
    (eff_le := by admit /- proof elided -/
    )
    (ty_eq := rfl)
    (args := .cons e₁ <| .cons e₂ .nil)
    (regArgs := .nil)

abbrev SimpleReg.int : SimpleReg.Ty := .int

abbrev SimpleReg : Dialect where
  Op := Op
  Ty := Ty

@[simp_denote]
def iterate {Γ : Ctxt _} (k : Nat) (input : Var Γ int) (body : Com SimpleReg ⟨[int]⟩ .impure [int]) :
    Expr SimpleReg Γ .pure [int] :=
  Expr.mk
    (op := Op.iterate k)
    (eff_le := by admit /- proof elided -/
    )
    (ty_eq := rfl)
    (args := .cons input .nil)
    (regArgs := HVector.cons body HVector.nil)

inductive Ty
  | int
  deriving DecidableEq

instance [SIG : DialectSignature d] [DENOTE : DialectDenote d] {Γ : Ctxt d.Ty} {t}
    (com : Com d Γ .pure t) : Inhabited (DCEType com) where
  default :=
    ⟨Γ, Hom.id, com, by admit /- proof elided -/
    ⟩

@[simp] abbrev Hom.id {Γ : Ctxt Ty} : Γ.Hom Γ :=
  fun _ v => v

@[reducible]
instance : DialectDenote Ex where
  denote
    | .cst n, _, _ => n ::ₕ .nil
    | .add, (a : Nat) ::ₕ b ::ₕ .nil, _ => a + b    ::ₕ .nil
    | .beq, (a : Nat) ::ₕ b ::ₕ .nil, _ => (a == b) ::ₕ .nil

def cst {Γ : Ctxt _} (n : ℕ) : Expr Ex Γ .pure [.nat] :=
  Expr.mk
    (op := .cst n)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .nil)
    (regArgs := .nil)

inductive ExTy
  | nat
  | bool
  deriving DecidableEq, Repr

@[simp, reducible]
instance : DialectDenote (LLVMPlusRiscV) where
  denote
  | .llvm llvmOp, args, .nil => do
      let xs ← DialectDenote.denote llvmOp (llvmArgsFromHybrid args) .nil
      return xs.map' Ty.llvm (fun t x => x)
  | .riscv (riscvOp), args, .nil => do
      let xs ← DialectDenote.denote riscvOp (riscvArgsFromHybrid args) .nil
      return xs.map' Ty.riscv (fun t x => x)
  | .castRiscv _ , elemToCast, _ =>
    let toCast : BitVec 64 :=
      elemToCast.getN 0 (by admit /- proof elided -/
      )
    [castriscvToLLVM toCast]ₕ
  | .castLLVM _,
    (elemToCast : HVector TyDenote.toType [Ty.llvm (.bitvec _)]), _ =>
    let toCast : PoisonOr (BitVec _) :=
      elemToCast.getN 0 (by admit /- proof elided -/
      )
    [castLLVMToriscv toCast]ₕ

inductive Op where
  | llvm : LLVM.Op -> Op
  | riscv : RISCV64.RV64.Op -> Op
  | castRiscv : Nat → Op
  | castLLVM : Nat → Op
  deriving DecidableEq, Repr, Lean.ToExpr

@[simp_riscv]
def castLLVMToriscv (toCast : PoisonOr (BitVec w)) : BitVec 64 :=
  BitVec.signExtend 64 (toCast.toOption.getD 0#w)

structure PoisonOr (α : Type) where
  ofOption :: toOption : Option α
  deriving DecidableEq

@[simp_riscv]
def castriscvToLLVM (toCast : BitVec 64) : PoisonOr (BitVec w) :=
  .value (BitVec.signExtend w toCast)

@[simp_denote]
def llvmArgsFromHybrid : {tys : List LLVM.Ty} →
  HVector TyDenote.toType (tys.map LLVMRiscV.Ty.llvm) → HVector TyDenote.toType tys
  | [], .nil => .nil
  | _ :: _, .cons x xs => .cons x (llvmArgsFromHybrid xs)

inductive Ty where
  | llvm : LLVM.Ty -> Ty
  | riscv : RISCV64.RV64.Ty -> Ty
  deriving DecidableEq, Repr, Lean.ToExpr

@[simp_denote]
def riscvArgsFromHybrid : {tys : List RISCV64.RV64.Ty} →
  HVector TyDenote.toType (tys.map LLVMRiscV.Ty.riscv) → HVector TyDenote.toType tys
  | [], .nil => .nil
  | _ :: _, .cons x xs => .cons x (riscvArgsFromHybrid xs)

@[reducible]
instance : DialectDenote ExOp ExTy where
  denote
    | .cst n, _, _ => n
    | .add, .cons (a : Nat) (.cons b .nil), _ => a + b
    | .beq, .cons (a : Nat) (.cons b .nil), _ => a == b

inductive ExOp :  Type
  | add : ExOp
  | beq : ExOp
  | cst : ℕ → ExOp
  deriving DecidableEq, Repr

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

inductive ExTy
  | nat
  deriving DecidableEq, Repr

abbrev Expr (Γ) (ty) := _root_.Expr ExOp Γ .pure ty

def cst {Γ : Ctxt _} (n : ℕ) : Expr Γ .nat  :=
  Expr.mk
    (op := .cst n)
    (ty_eq := rfl)
    (eff_le := EffectKind.le_refl _)
    (args := .nil)
    (regArgs := .nil)

@[reducible]
instance : DialectDenote ExOp ExTy where
  denote
    | .add, .cons (a : Nat) (.cons b .nil), _ => a + b
    | .runK (k : Nat), (.cons (v : Nat) .nil), (.cons rgn _nil) =>
      k.iterate (fun val => rgn (fun _ty _var => val)) v

inductive ExOp :  Type
  | add : ExOp
  | runK : ℕ → ExOp
  deriving DecidableEq, Repr

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

@[reducible]
instance [Monad d.m] : DialectDenote (Scf d) where
  denote
    | .coe o', args', regArgs' =>
        let denote' := DialectDenote.denote o'
        by
         exact denote' args' regArgs'
    | .if t t', (.cons (cond ) (.cons v .nil)),
         (.cons (f : Ctxt.Valuation ⟨[t]⟩ → d.m (HVector toType [t'])) (.cons (g : _ → _) .nil)) =>
         let body := if B.denote_eq ▸ cond then f else g
      body (Ctxt.Valuation.nil.cons v)
    | .run _t, (.cons v .nil), (.cons (f : _ → _) .nil) =>
        f (Ctxt.Valuation.nil.cons v)
    | .for ty, (.cons istart (.cons istep (.cons niter (.cons vstart .nil)))),
        (.cons (f : _  → _) .nil) => do
        let istart : ℤ := Z.denote_eq ▸ istart
        let istep : ℤ := Z.denote_eq ▸ istep
        let niter : ℕ := N.denote_eq ▸ niter
        let f' : LoopBody (d.m ⟦ty⟧) := fun i v => do
          let v ← v
          let i := Z.denote_eq.symm ▸ i
          let xs ← f (Valuation.ofPair i v)
          return xs.get (0 : Fin 1)
        let to_iterate := f'.counterDecorator (α := d.m ⟦ty⟧) (δ := istep)
        let loop_fn := niter.iterate (op := to_iterate)
        let x ← (loop_fn (istart, pure vstart)).2
        return [x]ₕ

| .iterate k, (.cons (x) .nil), (.cons (f : _ → _) .nil) => do
      let x : ℤ := Z.denote_eq ▸ x
      let coe : ℤ = toType Z.ty := Z.denote_eq.symm
      let f' (v : d.m ℤ) : d.m ℤ := do
        let v ← v
        let xs ← f (Ctxt.Valuation.nil.cons (cast coe v))
        let x := xs.getN 0
        return coe ▸ x
      let y ← (k.iterate f' (pure x))
      return [cast Z.denote_eq.symm y]ₕ

def counterDecorator (δ : Int) (f : LoopBody α) : Int × α → Int × α :=
  fun (i, v) => (i + δ, f i v)

inductive Scf.Op (Op' Ty' : Type) (m') [TyDenote Ty'] [DialectSignature ⟨Op', Ty', m'⟩]
    [DialectDenote ⟨Op', Ty', m'⟩] : Type _
  | coe (o : Op')
  | iterate (k : ℕ) 
  | run (inputty : Ty')  
  | if (inputty retty' : Ty')  
  | for (ty : Ty')
  deriving DecidableEq, Repr

class HasTy (d : Dialect) (DenotedTy : Type) [TyDenote d.Ty] [DialectSignature d] where
    ty : d.Ty
    denote_eq : toType ty = DenotedTy := by admit /- proof elided -/

abbrev LoopBody (t : Type) : Type := Int → t → t

@[simp_denote] def iterate {Γ : Ctxt _} (k : Nat) (input : Var Γ Arith.Ty.int)
    (body : Com ScfArith ⟨[.int]⟩ .impure .int) : Expr ScfArith Γ .impure .int :=
  Expr.mk
    (op := .iterate k)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .cons input .nil)
    (regArgs := HVector.cons body HVector.nil)

abbrev ScfArith := Scf Arith

def Scf (d : Dialect) [TyDenote d.Ty] [DialectSignature d] [DialectDenote d] : Dialect where
  Op := Scf.Op d.Op d.Ty d.m
  Ty := d.Ty
  m  := d.m

inductive Op
  | add : Op  
  | add_nat : Op  
  | axpy : Op  
  | neg : Op  
  | const : (val : ℤ) → Op
  | const_nat : (val : ℕ) → Op

@[simp_denote]
def run {Γ : Ctxt _} {t : Arith.Ty} (v : Var Γ t) (body : Com ScfArith ⟨[t]⟩ .impure t) :
    Expr ScfArith Γ .impure t :=
  Expr.mk
    (op := .run t)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .cons v .nil)
    (regArgs := HVector.cons body <| HVector.nil)

inductive Ty
| int
| bool
| nat
 deriving DecidableEq, Repr

@[simp_denote] def neg {Γ : Ctxt _} (a : Var Γ .int) : Expr ScfArith Γ .pure .int :=
  Expr.mk
    (op := .coe <| .neg)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .cons a <| .nil)
    (regArgs := .nil)

@[simp_denote] def axpy {Γ : Ctxt _} (a : Var Γ .int) (x : Var Γ .nat) (b: Var Γ .int) :
    Expr ScfArith Γ .pure .int :=
  Expr.mk
    (op := .coe <| .axpy)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .cons a <| .cons x <| .cons b .nil)
    (regArgs := .nil)

@[simp_denote] def add_nat (e₁ e₂ : Var Γ .nat) : Expr ScfArith Γ .pure .nat :=
  Expr.mk
    (op := .coe <| .add_nat)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .cons e₁ <| .cons e₂ .nil)
    (regArgs := .nil)

inductive Ty
  | int
   
  | int2
  deriving DecidableEq, Lean.ToExpr

inductive Op
  | noop
  | mkPair
  | unPair
  deriving Lean.ToExpr

abbrev Arith : Dialect := {Op, Ty}

def Valuation.ofPair  {t₁ t₂ : Ty} (v₁: ⟦t₁⟧) (v₂ : ⟦t₂⟧) :
    Valuation (Ctxt.ofList [t₁, t₂]) :=
  Valuation.ofHVector (.cons v₁ <| .cons v₂ <| .nil )

@[reducible]
instance : DialectDenote Arith where
  denote
    | .const n, _, _ => [n]ₕ
    | .const_nat n, _, _ => [n]ₕ
    | .neg, .cons (a : ℤ ) .nil, _ => [-a]ₕ
    | .axpy, .cons (a : ℤ) (.cons (x : ℕ) (.cons (b : ℤ) .nil)), _ => [a * (x : ℤ) + b]ₕ
    | .add, .cons (a : ℤ) (.cons (b : ℤ) .nil), _ => [a + b]ₕ
    | .add_nat, .cons (a : ℕ) (.cons (b : ℕ) .nil), _ => [a + b]ₕ

@[simp_denote] def add {Γ : Ctxt _} (e₁ e₂ : Var Γ .int) : Expr ScfArith Γ .pure .int :=
  Expr.mk
    (op := .coe <| .add)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .cons e₁ <| .cons e₂ .nil)
    (regArgs := .nil)

instance : DialectSignature $dialect where
        signature := fun op => match op with $matchAlts:matchAlts
    )

@[simp, reducible]
def Op.signature : Op q n → Signature (Ty q n) :=
  fun o => {sig := Op.sig o, returnTypes := [Op.outTy o], regSig := []}

@[simp, reducible]
def Op.sig : Op q n → List (Ty q n)
| Op.add => [Ty.polynomialLike, Ty.polynomialLike]
| Op.sub => [Ty.polynomialLike, Ty.polynomialLike]
| Op.mul => [Ty.polynomialLike, Ty.polynomialLike]
| Op.mul_constant => [Ty.polynomialLike, Ty.integer]
| Op.leading_term => [Ty.polynomialLike]
| Op.monomial => [Ty.integer, Ty.index]
| Op.monomial_mul => [Ty.polynomialLike, Ty.index]
| Op.from_tensor => [Ty.tensor]
| Op.to_tensor => [Ty.polynomialLike]
| Op.const _ => []
| Op.const_int _ => []
| Op.const_idx _ => []

@[simp, reducible]
def Op.outTy : Op q n → Ty q n
| Op.add | Op.sub | Op.mul | Op.mul_constant | Op.leading_term | Op.monomial
| Op.monomial_mul | Op.from_tensor | Op.const _  => Ty.polynomialLike
| Op.to_tensor => Ty.tensor
| Op.const_int _ => Ty.integer
| Op.const_idx _ => Ty.index

@[reducible, simp]
def Op.regSig : Op → RegionSignature Ty
  | .map2d => [([Ty.int], [.int])]
  | _ => []

instance : DialectSignature Ex where
  signature
    | .add    => ⟨[.nat, .nat], [], [.nat], .pure⟩
    | .beq    => ⟨[.nat, .nat], [], [.bool], .pure⟩
    | .cst _  => ⟨[], [], [.nat], .pure⟩

@[reducible]
instance : DialectSignature Tensor2D where
  signature op := { sig := op.sig, regSig := op.regSig, returnTypes := [op.outTy] }

instance : DialectSignature Tensor1D where
  signature op := { sig := op.sig, regSig := op.regSig, returnTypes := [op.outTy], effectKind := .pure }

instance : DialectSignature RV64 where
  signature o := {sig := Op.sig o, returnTypes := [Op.outTy o], regSig := []}

@[simp, reducible]
def Op.sig : Op → List Ty
  | .li _ => []
  | .mulh  => [Ty.bv, Ty.bv]
  | .mulhu  => [Ty.bv, Ty.bv]
  | .mulhsu  => [Ty.bv, Ty.bv]
  | .divu =>  [Ty.bv, Ty.bv]
  | .remuw  => [Ty.bv, Ty.bv]
  | .remu  =>  [Ty.bv, Ty.bv]
  | .addiw (_imm : BitVec 12) => [Ty.bv]
  | .lui (_imm : BitVec 20) => [Ty.bv]
  | .auipc (_imm : BitVec 20)  => [Ty.bv]
  | .slliw (_shamt : BitVec 5)  => [Ty.bv]
  | .srliw (_shamt : BitVec 5) => [Ty.bv]
  | .sraiw (_shamt : BitVec 5) => [Ty.bv]
  | .slli (_shamt : BitVec 6) => [Ty.bv]
  | .srli (_shamt : BitVec 6) => [Ty.bv]
  | .srai (_shamt : BitVec 6) => [Ty.bv]
  | .addw => [Ty.bv, Ty.bv]
  | .subw => [Ty.bv, Ty.bv]
  | .sllw => [Ty.bv, Ty.bv]
  | .srlw => [Ty.bv, Ty.bv]
  | .sraw => [Ty.bv, Ty.bv]
  | .add => [Ty.bv, Ty.bv]
  | .slt => [Ty.bv, Ty.bv]
  | .sltu => [Ty.bv, Ty.bv]
  | .and => [Ty.bv, Ty.bv]
  | .or => [Ty.bv, Ty.bv]
  | .xor => [Ty.bv, Ty.bv]
  | .sll => [Ty.bv, Ty.bv]
  | .srl => [Ty.bv, Ty.bv]
  | .sub => [Ty.bv, Ty.bv]
  | .sra => [Ty.bv, Ty.bv]
  | .remw  => [Ty.bv, Ty.bv]
  | .rem  =>  [Ty.bv, Ty.bv]
  | .mul => [Ty.bv, Ty.bv]
  | .mulw => [Ty.bv, Ty.bv]
  | .div  =>  [Ty.bv, Ty.bv]
  | .divw  =>  [Ty.bv, Ty.bv]
  | .divuw  =>  [Ty.bv, Ty.bv]
  | .addi (_imm : BitVec 12) => [Ty.bv]
  | .slti (_imm : BitVec 12) => [Ty.bv]
  | .sltiu (_imm : BitVec 12) => [Ty.bv]
  | .andi (_imm : BitVec 12) => [Ty.bv]
  | .ori (_imm : BitVec 12) => [Ty.bv]
  | .xori (_imm : BitVec 12) => [Ty.bv]
  | .bclr => [Ty.bv, Ty.bv]
  | .bext => [Ty.bv, Ty.bv]
  | .binv => [Ty.bv, Ty.bv]
  | .bset  => [Ty.bv, Ty.bv]
  | .bclri (_shamt : BitVec 6) => [Ty.bv]
  | .bexti (_shamt : BitVec 6) => [Ty.bv]
  | .binvi (_shamt : BitVec 6) => [Ty.bv]
  | .bseti (_shamt : BitVec 6) => [Ty.bv]
  | .adduw => [Ty.bv, Ty.bv]
  | .sh1adduw => [Ty.bv, Ty.bv]
  | .sh2adduw => [Ty.bv, Ty.bv]
  | .sh3adduw => [Ty.bv, Ty.bv]
  | .sh1add => [Ty.bv, Ty.bv]
  | .sh2add => [Ty.bv, Ty.bv]
  | .sh3add => [Ty.bv, Ty.bv]
  | .slliuw (_shamt : BitVec 6) => [Ty.bv]
  | .andn => [Ty.bv, Ty.bv]
  | .orn => [Ty.bv, Ty.bv]
  | .xnor => [Ty.bv, Ty.bv]
  | .clz
  | .clzw
  | .ctz
  | .ctzw
  | .max => [Ty.bv, Ty.bv]
  | .maxu => [Ty.bv, Ty.bv]
  | .min  => [Ty.bv, Ty.bv]
  | .minu  => [Ty.bv, Ty.bv]
  | .sextb => [Ty.bv]
  | .sexth => [Ty.bv]
  | .zexth => [Ty.bv]
  | .rol => [Ty.bv, Ty.bv]
  | .rolw => [Ty.bv, Ty.bv]
  | .ror => [Ty.bv, Ty.bv]
  | .rori (_shamt : BitVec 6) =>[Ty.bv]
  | .roriw (_shamt : BitVec 5) =>[Ty.bv]
  | .rorw => [Ty.bv, Ty.bv]
  | .pack => [Ty.bv, Ty.bv]
  | .packh => [Ty.bv, Ty.bv]
  | .packw => [Ty.bv, Ty.bv]
  | .mv => [Ty.bv]
  | .not => [Ty.bv]
  | .neg => [Ty.bv]
  | .negw => [Ty.bv]
  | .sextw => [Ty.bv]
  | .zextb => [Ty.bv]
  | .zextw => [Ty.bv]
  | .seqz => [Ty.bv]
  | .snez => [Ty.bv]
  | .sltz => [Ty.bv]
  | .sgtz => [Ty.bv]

instance : DialectSignature (FHE q n) := ⟨Op.signature⟩

instance : DialectSignature LLVM where
  signature op := ⟨op.sig, [], [op.outTy], .pure⟩

instance : DialectSignature HSxComb where
  signature := fun op =>
    match op with
    | .comb o => liftSig (signature o) 
    
    
    | .hs o => MLIR2Handshake.instDialectSignatureHandshake.signature o

inductive Op : Type _
  | comb (o : MLIR2Comb.Comb.Op)
  | hs (o : MLIR2Handshake.Handshake.Op)
  deriving Inhabited, DecidableEq, Repr, Lean.ToExpr

def liftSig (sig : Signature MLIR2Comb.Ty) : Signature MLIR2Handshake.Ty :=
  Signature.mk (sig.sig.map liftTy) [] (liftTy sig.outTy)

def liftTy : MLIR2Comb.Ty → MLIR2Handshake.Ty
| .bitvec w => .stream (.bitvec w)

inductive Ty
| stream (ty2 : Ty2) : Ty 
| stream2 (ty2 : Ty2) : Ty 
| stream2token (ty2 : Ty2) : Ty 
deriving Inhabited, DecidableEq, Repr, Lean.ToExpr

inductive Ty
| bitvec (w : Nat) : Ty 
deriving DecidableEq, Repr, ToExpr

inductive Ty2
  | bitvec (w : Nat) : Ty2
deriving Inhabited, DecidableEq, Repr, Lean.ToExpr

def map {α β : Type} (s : Stream α) (f : α → β) : Stream β :=
  fun i => (s i).map f

def Stream (β : Type) := Stream' (Option β)

instance : DialectSignature DCxComb where
  signature := fun op =>
    match op with
    | .comb o => liftSig (signature o) 
    
    
    | .dc o => MLIR2DC.instDialectSignatureDC.signature o

inductive Op : Type _
  | comb (o : MLIR2Comb.Comb.Op)
  | dc (o : MLIR2DC.DC.Op)
  deriving Inhabited, DecidableEq, Repr, Lean.ToExpr

def liftSig (sig : Signature MLIR2Comb.Ty) : Signature MLIR2DC.Ty :=
  Signature.mk (sig.sig.map liftTy) [] (liftTy sig.outTy)

def liftTy : MLIR2Comb.Ty → MLIR2DC.Ty
| .bitvec w => .valuestream w

inductive Ty
| tokenstream : Ty
| tokenstream2 : Ty
| valuestream (w : Nat) : Ty 
| valuestream2 (w : Nat) : Ty 
| valuetokenstream (w : Nat) : Ty 
| variadicvaluetokenstream (w : Nat) : Ty 
deriving Inhabited, DecidableEq, Repr, Lean.ToExpr

@[simp]
instance LLVMPlusRiscVSignature : DialectSignature LLVMPlusRiscV where
  signature
  | .llvm llvmOp => .llvm <$> DialectSignature.signature llvmOp
  | .riscv riscvOp => .riscv <$> DialectSignature.signature riscvOp
  | .castRiscv w =>
      {sig := [Ty.riscv .bv], returnTypes := [Ty.llvm (.bitvec w)], regSig := []}
  | .castLLVM w =>
      {sig := [Ty.llvm (.bitvec w)], returnTypes := [Ty.riscv .bv], regSig := []}

instance : DialectSignature ExOp ExTy where
  signature
    | .add    => ⟨[.nat, .nat], [], .nat, .pure⟩
    | .beq    => ⟨[.nat, .nat], [], .bool, .pure⟩
    | .cst _  => ⟨[], [], .nat, .pure⟩

instance : DialectSignature ExOp ExTy where
  signature
  | .add    => ⟨[.nat, .nat], [], .nat, .pure⟩
  | .runK _ => ⟨[.nat], [([.nat], .nat)], .nat, .pure⟩

@[reducible]
instance [TyDenote d.Ty] [DialectSignature d] [DialectDenote d]
    [B : HasBool d] [N : HasNat d] [I : HasInt d] : DialectSignature (Scf d) where
   signature
   | .coe o => signature (d:=d) o
    | .if t t' => ⟨[B.ty, t], [(⟨[t]⟩, [t']), (⟨[t]⟩, [t'])], [t'], .impure⟩
      
      
      
      
      
    | .for t => ⟨[ I.ty,  I.ty,  N.ty, t], [(⟨[I.ty, t]⟩, [t])], [t], .impure⟩
    | .run t => ⟨[t], [(⟨[t]⟩, [t])], [t], .impure⟩
    | .iterate _k => ⟨[I.ty], [(⟨[I.ty]⟩, [I.ty])], [I.ty], .impure⟩

@[reducible]
instance : DialectSignature Arith where
  signature
    | .axpy => ⟨[.int, .nat, .int], [], [.int], .pure⟩
    | .neg => ⟨[.int], [], [.int], .pure⟩
    | .const _ => ⟨[], [], [.int], .pure⟩
    | .const_nat _ => ⟨[], [], [.nat], .pure⟩
    | .add   => ⟨[.int, .int], [], [.int], .pure⟩
    | .add_nat   => ⟨[.nat, .nat], [], [.nat], .pure⟩

infixr:50 "::ₕ" => HVector.cons

notation "⟦" x "⟧" => TyDenote.toType x

infixr:67 "::ᵥ" => Valuation.cons

def positive_biggershl_shlnuwnsw_before := [llvm|
{
^0(%arg44 : i8):
  %0 = llvm.mlir.constant(3 : i8) : i8
  %1 = llvm.mlir.constant(6 : i8) : i8
  %2 = llvm.ashr %arg44, %0 : i8
  %3 = llvm.shl %2, %1 overflow<nsw,nuw> : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def carry (initCarry : Bool) (x y : BitStream) : BitStream :=
  fun n => (addAux' initCarry x y n).2

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

def t3_after := [llvm|
{
^0(%arg23 : i8, %arg24 : i2):
  %0 = llvm.sext %arg24 : i2 to i8
  %1 = llvm.add %arg23, %0 : i8
  %2 = llvm.xor %1, %0 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def sext_sext_add_mismatched_types_after := [llvm|
{
^0(%arg39 : i16, %arg40 : i32):
  %0 = llvm.mlir.constant(7 : i16) : i16
  %1 = llvm.mlir.constant(9 : i32) : i32
  %2 = llvm.ashr %arg39, %0 : i16
  %3 = llvm.ashr %arg40, %1 : i32
  %4 = llvm.sext %2 : i16 to i64
  %5 = llvm.sext %3 : i32 to i64
  %6 = llvm.add %4, %5 overflow<nsw> : i64
  "llvm.return"(%6) : (i64) -> ()
}
]

def narrow_zext_xor_after := [llvm|
{
^0(%arg46 : i16, %arg47 : i32):
  %0 = llvm.trunc %arg47 : i32 to i16
  %1 = llvm.xor %arg46, %0 : i16
  "llvm.return"(%1) : (i16) -> ()
}
]

def three_inst_stmt (e : LLVM.IntW w) :
    (LLVM.not (LLVM.not (LLVM.not e)))
      ⊑ (LLVM.not (LLVM.not (LLVM.not e))) :=

def test10b_after := [llvm|
{
^0(%arg105 : i32, %arg106 : i32):
  %0 = llvm.or %arg105, %arg106 : i32
  "llvm.return"(%0) : (i32) -> ()
}
]

instance : HydrableReduceWidth ParsedFpExpr FpPredicate FpExpr where
  shrink := shrink

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

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

def icmp_lshr_and_overshift_after := [llvm|
{
^0(%arg3 : i8):
  %0 = llvm.mlir.constant(31 : i8) : i8
  %1 = llvm.icmp "ugt" %arg3, %0 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

def decrAux (x : BitStream) : Nat → Bool × Bool
  | 0 => (!(x 0), !(x 0))
  | (n+1) =>
    let borrow := (decrAux x n).2
    let a := x (n + 1)
    (xor a borrow, !a && borrow)

List.reverseRecOn in Mathlib.Data.List.Induction

def shl_mask_wrong_shl_const_after := [llvm|
{
^0(%arg5 : i32):
  %0 = llvm.mlir.constant(255 : i32) : i32
  %1 = llvm.mlir.constant(7 : i32) : i32
  %2 = llvm.and %arg5, %0 : i32
  %3 = llvm.shl %2, %1 overflow<nsw,nuw> : i32
  %4 = llvm.or %2, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def test11_after := [llvm|
{
^0(%arg48 : i32, %arg49 : i32):
  %0 = llvm.mlir.constant(1431655765 : i32) : i32
  %1 = llvm.and %arg48, %0 : i32
  %2 = llvm.sub %arg49, %1 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def add_positive_high_bound_accept_test: LLVMPeepholeRewriteRefine 32 [Ty.llvm (.bitvec 32)] where
  lhs := add_positive_high_bound_accept_llvm
  rhs := add_positive_high_bound_accept_riscv

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

def llvm_const_lower_riscv_li_34 : LLVMPeepholeRewriteRefine 64 [] :=
  {lhs := constLLVM_34, rhs:= liRiscv_34,
   correct := by admit /- proof elided -/

def test1_before := [llvm|
{
^0(%arg232 : i32, %arg233 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.or %arg232, %arg233 : i32
  %2 = llvm.xor %1, %0 : i32
  %3 = llvm.or %arg232, %2 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

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

def not_or_or_not_before := [llvm|
{
^0(%arg552 : i32, %arg553 : i32, %arg554 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.sdiv %0, %arg552 : i32
  %3 = llvm.xor %arg553, %1 : i32
  %4 = llvm.xor %arg554, %1 : i32
  %5 = llvm.or %2, %3 : i32
  %6 = llvm.or %5, %4 : i32
  "llvm.return"(%6) : (i32) -> ()
}
]

@[simp]
def ofNat_eq_concrete (x : Nat) :
    (OfNat.ofNat x) = (ConcreteOrMVar.concrete x : ConcreteOrMVar Nat φ) := rfl

@[simp_denote]
def andi_llvm_i64 := [LV| {
    ^entry (%a: i64):
    %0 = llvm.mlir.constant (6) : i64
    %1 = llvm.and %a, %0 : i64
    llvm.return %1 : i64
  }]

def RawCNFA.addManyTrans (m : RawCNFA A) (a : List A) (s s' : State) : RawCNFA A :=
  a.foldl (init := m) fun m a => m.addTrans a s s'

Lean.Import in Lean.Setup

def not_shl_after := [llvm|
{
^0(%arg86 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.mlir.constant(7 : i8) : i8
  %2 = llvm.xor %arg86, %0 : i8
  %3 = llvm.shl %2, %1 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def test_mul_one_lhs_LHS := [mod_arith q, hq| {
  ^bb0(%x : !R):
    %one = mod_arith.constant 1 : !R
    %mul = mod_arith.mul %one, %x : !R
    return %mul : !R
}]

def foo_after := [llvm|
{
^0(%arg0 : i8, %arg1 : i8):
  %0 = llvm.mlir.constant(7 : i8) : i8
  %1 = llvm.mlir.constant(84 : i8) : i8
  %2 = llvm.mlir.constant(-118 : i8) : i8
  %3 = llvm.mlir.constant(33 : i8) : i8
  %4 = llvm.mlir.constant(40 : i8) : i8
  %5 = llvm.mlir.constant(2 : i8) : i8
  %6 = llvm.mlir.constant(32 : i8) : i8
  %7 = llvm.shl %arg0, %0 : i8
  %8 = llvm.and %arg1, %1 : i8
  %9 = llvm.and %arg1, %2 : i8
  %10 = llvm.and %arg1, %3 : i8
  %11 = llvm.sub %4, %8 overflow<nsw> : i8
  %12 = llvm.and %11, %1 : i8
  %13 = llvm.or disjoint %10, %12 : i8
  %14 = llvm.xor %7, %9 : i8
  %15 = llvm.or disjoint %13, %14 : i8
  %16 = llvm.lshr %14, %5 : i8
  %17 = llvm.and %16, %6 : i8
  %18 = llvm.xor %17, %15 : i8
  "llvm.return"(%18) : (i8) -> ()
}
]

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 test_with_neg_even_before := [llvm|
{
^0(%arg311 : i32):
  %0 = llvm.mlir.constant(-4 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.shl %0, %arg311 : i32
  %3 = llvm.and %2, %1 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def Tensor2D : Dialect where
  Op := Op
  Ty := Ty

def ule_swap_or_not_min_before := [llvm|
{
^0(%arg264 : i8, %arg265 : i8):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.icmp "uge" %arg265, %arg264 : i8
  %2 = llvm.icmp "ne" %arg264, %0 : i8
  %3 = llvm.or %1, %2 : i1
  "llvm.return"(%3) : (i1) -> ()
}
]

def RawCNFA.transBV (m : RawCNFA A) (s : m.states) (a : A) : BitVec m.stateMax :=
  let ts := m.trans.getD (s, a) ∅
  BitVec.ofFn (fun n => n ∈ ts)

instance : DialectParse SLLVM 0 where
  isValidReturn Γ opStx := return opStx.name == "llvm.return"

  mkExpr (Γ : Ctxt SLLVM.Ty) (opStx : MLIR.AST.Op 0) := do
  let args ← opStx.parseArgs Γ

   
  let binW := do
  
    let args ← args.assumeArity 2
    getIntWidth args[0]

   
  let unW := do
    let args ← args.assumeArity 1
    getIntWidth args[0]

  let getOutputWidth := getOutputWidth opStx

  let mkExprOf := opStx.mkExprOf (args? := args) Γ
  match opStx.name with
    
    | "ptr.add" => mkExprOf <| .ptradd
    | "ptr.load" => mkExprOf <| .load (← getOutputWidth)
    | "ptr.store" => do
        let args ← args.assumeArity 2
        mkExprOf <| .store (← getIntWidth args[1])
    | "ptr.alloca" =>
        let t ← opStx.getTypeAttr "elem_type"
        let .int _ w := t
          | throw <| .generic s!"Expected value of attribute `elem_type` to be an integer type"
        mkExprOf <| .alloca w.toConcrete
    
    | "llvm.select" =>
        let args ← args.assumeArity 3
        let w ← getIntWidth args[1]
        mkExprOf <| Op.select w
    
    | "llvm.and"      => mkExprOf <| Op.and (← binW)
    | "llvm.or"       => mkExprOf <| Op.or (← binW) ⟨opStx.hasAttr "isDisjoint"⟩
    | "llvm.xor"      => mkExprOf <| Op.xor (← binW)
    | "llvm.urem"     => mkExprOf <| Op.urem (← binW)
    | "llvm.srem"     => mkExprOf <| Op.srem (← binW)
    | "llvm.lshr"     => mkExprOf <| Op.lshr (← binW) ⟨opStx.hasAttr "isExact"⟩
    | "llvm.ashr"     => mkExprOf <| Op.ashr (← binW) ⟨opStx.hasAttr "isExact"⟩
    | "llvm.sdiv"     => mkExprOf <| Op.sdiv (← binW) ⟨opStx.hasAttr "isExact"⟩
    | "llvm.udiv"     => mkExprOf <| Op.udiv (← binW) ⟨opStx.hasAttr "isExact"⟩
    | "llvm.shl"      => mkExprOf <| Op.shl (← binW) (← parseOverflowFlags opStx)
    | "llvm.add"      => mkExprOf <| Op.add (← binW) (← parseOverflowFlags opStx)
    | "llvm.mul"      => mkExprOf <| Op.mul (← binW) (← parseOverflowFlags opStx)
    | "llvm.sub"      => mkExprOf <| Op.sub (← binW) (← parseOverflowFlags opStx)
    | "llvm.icmp.eq"  => mkExprOf <| Op.icmp .eq (← binW)
    | "llvm.icmp.ne"  => mkExprOf <| Op.icmp .ne (← binW)
    | "llvm.icmp.ugt" => mkExprOf <| Op.icmp .ugt (← binW)
    | "llvm.icmp.uge" => mkExprOf <| Op.icmp .uge (← binW)
    | "llvm.icmp.ult" => mkExprOf <| Op.icmp .ult (← binW)
    | "llvm.icmp.ule" => mkExprOf <| Op.icmp .ule (← binW)
    | "llvm.icmp.sgt" => mkExprOf <| Op.icmp .sgt (← binW)
    | "llvm.icmp.sge" => mkExprOf <| Op.icmp .sge (← binW)
    | "llvm.icmp.slt" => mkExprOf <| Op.icmp .slt (← binW)
    | "llvm.icmp.sle" => mkExprOf <| Op.icmp .sle (← binW)
    
    | "llvm.not"    => mkExprOf <| Op.not (← unW)
    | "llvm.neg"    => mkExprOf <| Op.neg (← unW)
    | "llvm.copy"   => mkExprOf <| Op.copy (← unW)
    | "llvm.freeze" => mkExprOf <| Op.freeze (← unW)
    | "llvm.zext"   => mkExprOf <| Op.zext (← unW) (← getOutputWidth) ⟨ opStx.hasAttr "nonNeg" ⟩
    | "llvm.sext"   => mkExprOf <| Op.sext (← unW) (← getOutputWidth)
    | "llvm.trunc"  => mkExprOf <| Op.trunc (← unW) (← getOutputWidth) (← parseOverflowFlags opStx)
    
    | "llvm.mlir.constant" => do
      let ⟨val, ty⟩ ← opStx.getIntAttr "value"
      let opTy ← mkTy ty
      let Ty.bitvec w := opTy
        | throw <| .generic s!"Expected a `bitvec _`, but found: {opTy}"
      mkExprOf <| Op.const w val
    
    | opName => throw <| .unsupportedOp opName

def ult_rem_zero_nsw_before := [llvm|
{
^0(%arg173 : i8):
  %0 = llvm.mlir.constant(7 : i8) : i8
  %1 = llvm.mlir.constant(21 : i8) : i8
  %2 = llvm.mul %arg173, %0 overflow<nsw,nuw> : i8
  %3 = llvm.icmp "ult" %2, %1 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

def negate_select_of_op_vs_negated_op_nsw_before := [llvm|
{
^0(%arg21 : i8, %arg22 : i8, %arg23 : i1):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.sub %0, %arg21 overflow<nsw> : i8
  %2 = "llvm.select"(%arg23, %1, %arg21) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  %3 = llvm.sub %arg22, %2 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def fold_zext_xor_sandwich_before := [llvm|
{
^0(%arg188 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.mlir.constant(2 : i32) : i32
  %2 = llvm.xor %arg188, %0 : i1
  %3 = llvm.zext %2 : i1 to i32
  %4 = llvm.xor %3, %1 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

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 test4_before := [llvm|
{
^0(%arg50 : i32):
  %0 = llvm.icmp "sgt" %arg50, %arg50 : i32
  "llvm.return"(%0) : (i1) -> ()
}
]

def prove_exact_with_high_mask_limit_after := [llvm|
{
^0(%arg6 : i8, %arg7 : i8):
  %0 = llvm.mlir.constant(3 : i8) : i8
  %1 = llvm.ashr %arg6, %0 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

def logical_and_bitwise_and_icmps_comm2_before := [llvm|
{
^0(%arg214 : i8, %arg215 : i8, %arg216 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.mlir.constant(1 : i8) : i8
  %2 = llvm.mlir.constant(0 : i8) : i8
  %3 = llvm.mlir.constant(false) : i1
  %4 = llvm.icmp "eq" %arg215, %0 : i8
  %5 = llvm.and %arg214, %1 : i8
  %6 = llvm.shl %1, %arg216 : i8
  %7 = llvm.and %arg214, %6 : i8
  %8 = llvm.icmp "ne" %5, %2 : i8
  %9 = llvm.icmp "ne" %7, %2 : i8
  %10 = llvm.and %8, %4 : i1
  %11 = "llvm.select"(%10, %9, %3) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%11) : (i1) -> ()
}
]

def test1_before := [llvm|
{
^0(%arg2 : i177):
  %0 = llvm.mlir.constant(1 : i177) : i177
  %1 = llvm.mlir.constant(155 : i177) : i177
  %2 = llvm.shl %0, %1 : i177
  %3 = llvm.mul %arg2, %2 : i177
  "llvm.return"(%3) : (i177) -> ()
}
]

def llvm_or_lower_riscv_disjoint_64 : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64), Ty.llvm (.bitvec 64)] where
  lhs := or_llvm_disjoint_64
  rhs := or_riscv_64

def and1_shl1_is_cmp_eq_0_multiuse_before := [llvm|
{
^0(%arg14 : i8):
  %0 = llvm.mlir.constant(1 : i8) : i8
  %1 = llvm.shl %0, %arg14 : i8
  %2 = llvm.and %1, %0 : i8
  %3 = llvm.add %1, %2 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

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

def ParsedArgs.ofList {Γ : Ctxt d.Ty} : List (Σ t, Γ.Var t) → ParsedArgs Γ :=
  (⟨·, by admit /- proof elided -/
  ⟩)

def shift_no_xor_multiuse_cmp_before := [llvm|
{
^0(%arg120 : i32, %arg121 : i32, %arg122 : i32, %arg123 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.mlir.constant(2 : i32) : i32
  %3 = llvm.and %arg120, %0 : i32
  %4 = llvm.icmp "eq" %3, %1 : i32
  %5 = llvm.or %arg121, %2 : i32
  %6 = "llvm.select"(%4, %arg121, %5) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %7 = "llvm.select"(%4, %arg122, %arg123) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %8 = llvm.mul %6, %7 : i32
  "llvm.return"(%8) : (i32) -> ()
}
]

def Predicate.Env.empty : Predicate.Env 0 :=
  fun v => v.elim0

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

def is_ascii_alphabetic_before := [llvm|
{
^0(%arg248 : i32):
  %0 = llvm.mlir.constant(-65 : i32) : i32
  %1 = llvm.mlir.constant(26 : i32) : i32
  %2 = llvm.mlir.constant(-97 : i32) : i32
  %3 = llvm.mlir.constant(true) : i1
  %4 = llvm.add %arg248, %0 overflow<nsw> : i32
  %5 = llvm.icmp "ult" %4, %1 : i32
  %6 = llvm.add %arg248, %2 overflow<nsw> : i32
  %7 = llvm.icmp "ult" %6, %1 : i32
  %8 = "llvm.select"(%5, %3, %7) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%8) : (i1) -> ()
}
]

def test_shl_nsw__all_are_safe_before := [llvm|
{
^0(%arg86 : i32, %arg87 : i64):
  %0 = llvm.mlir.constant(15 : i32) : i32
  %1 = llvm.mlir.constant(2 : i32) : i32
  %2 = llvm.mlir.constant(0 : i32) : i32
  %3 = llvm.and %arg86, %0 : i32
  %4 = llvm.shl %3, %1 overflow<nsw> : i32
  %5 = llvm.zext %4 : i32 to i64
  %6 = llvm.icmp "eq" %3, %2 : i32
  %7 = llvm.ashr %arg87, %5 : i64
  %8 = "llvm.select"(%6, %arg87, %7) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i64, i64) -> i64
  "llvm.return"(%8) : (i64) -> ()
}
]

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

def f_var0_before := [llvm|
{
^0(%arg52 : i32, %arg53 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.and %arg52, %arg53 : i32
  %3 = llvm.icmp "eq" %2, %0 : i32
  %4 = llvm.lshr %arg52, %1 : i32
  %5 = llvm.and %4, %1 : i32
  %6 = "llvm.select"(%3, %5, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%6) : (i32) -> ()
}
]

def t9_lshr_before := [llvm|
{
^0(%arg2 : i32, %arg3 : i16):
  %0 = llvm.mlir.constant(32 : i16) : i16
  %1 = llvm.mlir.constant(-2 : i16) : i16
  %2 = llvm.sub %0, %arg3 : i16
  %3 = llvm.zext %2 : i16 to i32
  %4 = llvm.lshr %arg2, %3 : i32
  %5 = llvm.trunc %4 : i32 to i16
  %6 = llvm.add %arg3, %1 : i16
  %7 = llvm.lshr %5, %6 : i16
  "llvm.return"(%7) : (i16) -> ()
}
]

def n3_after := [llvm|
{
^0(%arg1 : i8, %arg2 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.shl %0, %arg2 overflow<nsw> : i8
  %2 = llvm.xor %1, %0 : i8
  %3 = llvm.icmp "uge" %arg1, %2 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

def not_ashr_const_before := [llvm|
{
^0(%arg138 : i8):
  %0 = llvm.mlir.constant(-42 : i8) : i8
  %1 = llvm.mlir.constant(-1 : i8) : i8
  %2 = llvm.ashr %0, %arg138 : i8
  %3 = llvm.xor %2, %1 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def shift_trunc_wrong_cmp_after := [llvm|
{
^0(%arg0 : i32):
  %0 = llvm.mlir.constant(24 : i32) : i32
  %1 = llvm.mlir.constant(1 : i8) : i8
  %2 = llvm.lshr %arg0, %0 : i32
  %3 = llvm.trunc %2 overflow<nuw> : i32 to i8
  %4 = llvm.icmp "slt" %3, %1 : i8
  "llvm.return"(%4) : (i1) -> ()
}
]

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

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

def shl_sub_i32_after := [llvm|
{
^0(%arg18 : i32):
  %0 = llvm.mlir.constant(-2147483648 : i32) : i32
  %1 = llvm.lshr exact %0, %arg18 : i32
  "llvm.return"(%1) : (i32) -> ()
}
]

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

def goo_before := [llvm|
{
^0(%arg105 : i32, %arg106 : i32, %arg107 : i32, %arg108 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.icmp "slt" %arg105, %arg106 : i32
  %3 = "llvm.select"(%2, %0, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %4 = llvm.and %3, %arg107 : i32
  %5 = llvm.xor %3, %0 : i32
  %6 = llvm.and %5, %arg108 : i32
  %7 = llvm.or %4, %6 : i32
  "llvm.return"(%7) : (i32) -> ()
}
]

def test_or_eq_a_b_after := [llvm|
{
^0(%arg36 : i1, %arg37 : i8, %arg38 : i8):
  %0 = "llvm.select"(%arg36, %arg37, %arg38) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  "llvm.return"(%0) : (i8) -> ()
}
]

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

def test_sext3_before := [llvm|
{
^0(%arg45 : i1, %arg46 : i1):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.sext %arg45 : i1 to i32
  %2 = "llvm.select"(%arg46, %0, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%2) : (i32) -> ()
}
]

Function.RightInverse in Init.Data.Function

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

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

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

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

def lshr_lshr_before := [llvm|
{
^0(%arg47 : i232):
  %0 = llvm.mlir.constant(231 : i232) : i232
  %1 = llvm.mlir.constant(1 : i232) : i232
  %2 = llvm.lshr %arg47, %0 : i232
  %3 = llvm.lshr %2, %1 : i232
  "llvm.return"(%3) : (i232) -> ()
}
]

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

def n3_before := [llvm|
{
^0(%arg1 : i8, %arg2 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.shl %0, %arg2 : i8
  %2 = llvm.xor %1, %0 : i8
  %3 = llvm.icmp "ule" %2, %arg1 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

def t2_before := [llvm|
{
^0(%arg8 : i64):
  %0 = llvm.mlir.constant(63) : i64
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.ashr %arg8, %0 : i64
  %3 = llvm.trunc %2 : i64 to i32
  %4 = llvm.sub %1, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

reprStr in Init.Data.Repr

def select_or_icmp_bad_after := [llvm|
{
^0(%arg149 : i32, %arg150 : i32, %arg151 : i32):
  %0 = llvm.mlir.constant(3 : i32) : i32
  %1 = llvm.icmp "eq" %arg149, %0 : i32
  %2 = llvm.or %arg151, %0 : i32
  %3 = "llvm.select"(%1, %2, %arg150) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%3) : (i32) -> ()
}
]

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

def t0_basic_before := [llvm|
{
^0(%arg24 : i8, %arg25 : i8):
  %0 = llvm.sub %arg24, %arg25 : i8
  %1 = llvm.icmp "ugt" %0, %arg24 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

def icmp_x_slt_0_xor_icmp_y_sgt_neg1_i32_after := [llvm|
{
^0(%arg55 : i32, %arg56 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg56, %arg55 : i32
  %2 = llvm.icmp "sgt" %1, %0 : i32
  %3 = llvm.zext %2 : i1 to i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def precondSynthesisUpdateCache (previousLevelCache synthesisComponents: Std.HashMap (FpExpr w)  PreconditionSynthesisCacheValue)
      (positiveExamples negativeExamples: List (Std.HashMap Nat FpExprWrapper)) (specialConstants : Std.HashMap (FpExpr w) FpExprWrapper)
      (ops : List (FpExpr w → FpExpr w → FpExpr w)) : GeneralizerStateM ParsedFpExpr FpPredicate (Std.HashMap (FpExpr w) PreconditionSynthesisCacheValue) := do
  return {}

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

def test_const_shr_exact_and_1_ne_0_before := [llvm|
{
^0(%arg6 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.mlir.constant(0 : i32) : i32
  %3 = llvm.lshr exact %0, %arg6 : i32
  %4 = llvm.and %3, %1 : i32
  %5 = llvm.icmp "ne" %4, %2 : i32
  "llvm.return"(%5) : (i1) -> ()
}
]

structure NonNegFlag where
  nneg : Bool := false
  deriving Repr, DecidableEq, Lean.ToExpr

def r : Com (.ofList [.nat, .nat]) .nat :=
  .var (add ⟨1, by admit /- proof elided -/
  ⟩ ⟨0, by admit /- proof elided -/
  ⟩) (.ret ⟨0, by admit /- proof elided -/
  ⟩)

def sub_ashr_and_i32_nuw_nsw_after := [llvm|
{
^0(%arg23 : i32, %arg24 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.icmp "slt" %arg24, %arg23 : i32
  %2 = "llvm.select"(%1, %arg23, %0) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%2) : (i32) -> ()
}
]

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

def xor_or_xor_common_op_commute7_before := [llvm|
{
^0(%arg62 : i32, %arg63 : i32, %arg64 : i32):
  %0 = llvm.xor %arg62, %arg64 : i32
  %1 = llvm.or %arg63, %arg62 : i32
  %2 = llvm.xor %1, %0 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

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

def t4_commutative_after := [llvm|
{
^0(%arg34 : i8, %arg35 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.xor %arg35, %0 : i8
  %2 = llvm.icmp "ule" %arg34, %1 : i8
  "llvm.return"(%2) : (i1) -> ()
}
]

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

def exactly_one_set_signbit_signed_before := [llvm|
{
^0(%arg26 : i8, %arg27 : i8):
  %0 = llvm.mlir.constant(7 : i8) : i8
  %1 = llvm.mlir.constant(-1 : i8) : i8
  %2 = llvm.ashr %arg26, %0 : i8
  %3 = llvm.icmp "sgt" %arg27, %1 : i8
  %4 = llvm.sext %3 : i1 to i8
  %5 = llvm.icmp "eq" %2, %4 : i8
  "llvm.return"(%5) : (i1) -> ()
}
]

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

def match_signed_after := [llvm|
{
^0(%arg15 : i64):
  %0 = llvm.mlir.constant(172224) : i64
  %1 = llvm.srem %arg15, %0 : i64
  "llvm.return"(%1) : (i64) -> ()
}
]

def xor_common_op_commute2_after := [llvm|
{
^0(%arg204 : i8, %arg205 : i8):
  %0 = llvm.mlir.constant(5 : i8) : i8
  %1 = llvm.xor %arg204, %0 : i8
  %2 = llvm.or %1, %arg205 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def and_and_logic_or_2_before := [llvm|
{
^0(%arg99 : i1, %arg100 : i1, %arg101 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.and %arg100, %arg99 : i1
  %2 = llvm.and %arg99, %arg101 : i1
  %3 = "llvm.select"(%2, %0, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%3) : (i1) -> ()
}
]

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

def test6_after := [llvm|
{
^0(%arg3 : i16):
  %0 = llvm.sext %arg3 : i16 to i32
  "llvm.return"(%0) : (i32) -> ()
}
]

@[simp_denote]
def add_b31_llvm_i64 := [LV| {
    ^entry (%x: i64):
    %0 = llvm.mlir.constant (2147483648) : i64
    %1 = llvm.add %x, %0 : i64
    llvm.return %1 : i64
  }]

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

def test2_after := [llvm|
{
^0(%arg0 : i52, %arg1 : i52):
  %0 = llvm.icmp "ugt" %arg0, %arg1 : i52
  "llvm.return"(%0) : (i1) -> ()
}
]

def test4_after := [llvm|
{
^0(%arg3 : i737):
  %0 = llvm.mlir.constant(-1 : i737) : i737
  "llvm.return"(%0) : (i737) -> ()
}
]

def ult_swap_and_not_max_after := [llvm|
{
^0(%arg102 : i8, %arg103 : i8):
  %0 = llvm.icmp "ugt" %arg103, %arg102 : i8
  "llvm.return"(%0) : (i1) -> ()
}
]

def test15_commuted_after := [llvm|
{
^0(%arg170 : i32, %arg171 : i32):
  %0 = llvm.xor %arg170, %arg171 : i32
  "llvm.return"(%0) : (i32) -> ()
}
]

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

@[simp_llvm_option]
def not {w : Nat} (x : IntW w) : IntW w := do
  let x' ← x
  not? x'

def mul128_low_before := [llvm|
{
^0(%arg18 : i128, %arg19 : i128):
  %0 = llvm.mlir.constant(18446744073709551615 : i128) : i128
  %1 = llvm.mlir.constant(64 : i128) : i128
  %2 = llvm.and %arg18, %0 : i128
  %3 = llvm.lshr %arg18, %1 : i128
  %4 = llvm.and %arg19, %0 : i128
  %5 = llvm.lshr %arg19, %1 : i128
  %6 = llvm.mul %5, %2 : i128
  %7 = llvm.mul %4, %3 : i128
  %8 = llvm.mul %4, %2 : i128
  %9 = llvm.add %6, %7 : i128
  %10 = llvm.shl %9, %1 : i128
  %11 = llvm.add %10, %8 : i128
  "llvm.return"(%11) : (i128) -> ()
}
]

def test65_after := [llvm|
{
^0(%arg43 : i64):
  %0 = llvm.mlir.constant(16) : i64
  %1 = llvm.mlir.constant(0) : i64
  %2 = llvm.mlir.constant(42 : i32) : i32
  %3 = llvm.mlir.constant(40 : i32) : i32
  %4 = llvm.and %arg43, %0 : i64
  %5 = llvm.icmp "eq" %4, %1 : i64
  %6 = "llvm.select"(%5, %2, %3) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%6) : (i32) -> ()
}
]

def and_min_7_8_before := [llvm|
{
^0(%arg1 : i8):
  %0 = llvm.mlir.constant(-8 : i8) : i8
  %1 = llvm.icmp "ult" %arg1, %0 : i8
  %2 = "llvm.select"(%1, %arg1, %0) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  %3 = llvm.and %2, %0 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def lshr_pow2_slt_before := [llvm|
{
^0(%arg58 : i8):
  %0 = llvm.mlir.constant(-128 : i8) : i8
  %1 = llvm.mlir.constant(3 : i8) : i8
  %2 = llvm.lshr %0, %arg58 : i8
  %3 = llvm.icmp "slt" %2, %1 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

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

def positive_biggerLshr_before := [llvm|
{
^0(%arg33 : i32):
  %0 = llvm.mlir.constant(5 : i32) : i32
  %1 = llvm.mlir.constant(10 : i32) : i32
  %2 = llvm.shl %arg33, %0 : i32
  %3 = llvm.lshr %2, %1 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def and_xor_or8_after := [llvm|
{
^0(%arg652 : i64, %arg653 : i64, %arg654 : i64):
  %0 = llvm.mlir.constant(42) : i64
  %1 = llvm.udiv %0, %arg653 : i64
  %2 = llvm.udiv %0, %arg654 : i64
  %3 = llvm.or %1, %2 : i64
  "llvm.return"(%3) : (i64) -> ()
}
]

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

def llvm_zext_lower_riscv_1_to_32 : LLVMPeepholeRewriteRefine 32 [Ty.llvm (.bitvec 1)] :=
  {lhs:= zext_llvm_1_to_32, rhs:= zext_riscv_1_to_32}

def or_not_and_wrong_c_before := [llvm|
{
^0(%arg488 : i32, %arg489 : i32, %arg490 : i32, %arg491 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.or %arg488, %arg489 : i32
  %2 = llvm.xor %1, %0 : i32
  %3 = llvm.and %2, %arg490 : i32
  %4 = llvm.or %arg488, %arg491 : i32
  %5 = llvm.xor %4, %0 : i32
  %6 = llvm.and %5, %arg489 : i32
  %7 = llvm.or %3, %6 : i32
  "llvm.return"(%7) : (i32) -> ()
}
]

def test1_trunc_before := [llvm|
{
^0(%arg53 : i32):
  %0 = llvm.mlir.constant(24 : i32) : i32
  %1 = llvm.mlir.constant(8 : i32) : i32
  %2 = llvm.mlir.constant(65280 : i32) : i32
  %3 = llvm.lshr %arg53, %0 : i32
  %4 = llvm.lshr %arg53, %1 : i32
  %5 = llvm.and %4, %2 : i32
  %6 = llvm.or %3, %5 : i32
  %7 = llvm.trunc %6 : i32 to i16
  "llvm.return"(%7) : (i16) -> ()
}
]

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

def icmp_ult_x_y_2_before := [llvm|
{
^0(%arg40 : i8, %arg41 : i8):
  %0 = llvm.mul %arg40, %arg40 : i8
  %1 = llvm.and %0, %arg41 : i8
  %2 = llvm.icmp "ugt" %0, %1 : i8
  "llvm.return"(%2) : (i1) -> ()
}
]

def nonexact_ashr_ne_exactdiv_before := [llvm|
{
^0(%arg145 : i8):
  %0 = llvm.mlir.constant(-80 : i8) : i8
  %1 = llvm.mlir.constant(-5 : i8) : i8
  %2 = llvm.ashr %0, %arg145 : i8
  %3 = llvm.icmp "ne" %2, %1 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

def not_mul_of_bool_commute_after := [llvm|
{
^0(%arg87 : i32, %arg88 : i32):
  %0 = llvm.mlir.constant(30 : i32) : i32
  %1 = llvm.mlir.constant(255 : i32) : i32
  %2 = llvm.lshr %arg87, %0 : i32
  %3 = llvm.and %arg88, %1 : i32
  %4 = llvm.mul %3, %2 overflow<nsw,nuw> : i32
  %5 = llvm.icmp "ugt" %4, %1 : i32
  "llvm.return"(%5) : (i1) -> ()
}
]

def test4_before := [llvm|
{
^0(%arg25 : i32):
  %0 = llvm.mlir.constant(64 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.udiv %0, %arg25 : i32
  %3 = llvm.icmp "ne" %2, %1 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

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

inductive Op : Type
| add (n : Nat) : Op
| const : (val : ℤ) → Op
deriving DecidableEq, Repr

def test_or2_after := [llvm|
{
^0(%arg32 : i32, %arg33 : i32):
  %0 = llvm.mlir.constant(2147483647 : i32) : i32
  %1 = llvm.and %arg33, %0 : i32
  %2 = llvm.icmp "ugt" %arg32, %1 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

def CNFA.proj_spec (m : CNFA n2) (f : Fin n1 → Fin n2) {M : NFA' n2} :
    m.Sim M → (m.proj f |>.Sim (M.proj f)) :=

def test5_before := [llvm|
{
^0(%arg45 : i32, %arg46 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg45, %0 : i32
  %2 = llvm.xor %arg46, %0 : i32
  %3 = llvm.or %1, %2 : i32
  %4 = llvm.xor %3, %0 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

@[simp_denote]
def sext_llvm_i1_to_32 := [LV| {
  ^entry (%arg: i1):
    %0 = llvm.sext %arg: i1 to i32
    llvm.return %0: i32
  }]

def t0_after := [llvm|
{
^0(%arg42 : i32, %arg43 : i32, %arg44 : i32, %arg45 : i32):
  %0 = llvm.icmp "ne" %arg42, %arg43 : i32
  %1 = llvm.icmp "ne" %arg44, %arg45 : i32
  %2 = llvm.and %1, %0 : i1
  "llvm.return"(%2) : (i1) -> ()
}
]

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

def t12_shift_of_const0_before := [llvm|
{
^0(%arg12 : i32, %arg13 : i32, %arg14 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.shl %0, %arg13 : i32
  %3 = llvm.and %2, %arg14 : i32
  %4 = llvm.icmp "eq" %3, %1 : i32
  "llvm.return"(%4) : (i1) -> ()
}
]

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

def prove_exact_with_high_mask_before := [llvm|
{
^0(%arg8 : i8, %arg9 : i8):
  %0 = llvm.mlir.constant(-8 : i8) : i8
  %1 = llvm.mlir.constant(4 : i8) : i8
  %2 = llvm.and %arg8, %0 : i8
  %3 = llvm.sdiv %2, %1 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def test7_before := [llvm|
{
^0(%arg115 : i32, %arg116 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.or %arg115, %arg116 : i32
  %2 = llvm.xor %arg115, %0 : i32
  %3 = llvm.xor %1, %2 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def or_shl_before := [llvm|
{
^0(%arg640 : i8, %arg641 : i8, %arg642 : i8, %arg643 : i8):
  %0 = llvm.shl %arg640, %arg643 : i8
  %1 = llvm.shl %arg641, %arg643 : i8
  %2 = llvm.or %0, %arg642 : i8
  %3 = llvm.or %2, %1 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

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

def t3_before := [llvm|
{
^0(%arg23 : i8, %arg24 : i2):
  %0 = llvm.sext %arg24 : i2 to i8
  %1 = llvm.add %0, %arg23 : i8
  %2 = llvm.xor %1, %0 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def select_constants_and_icmp_ne0_common_bit_after := [llvm|
{
^0(%arg18 : i1, %arg19 : i1):
  %0 = llvm.mlir.constant(true) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def main3_after := [llvm|
{
^0(%arg155 : i32):
  %0 = llvm.mlir.constant(55 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.and %arg155, %0 : i32
  %3 = llvm.icmp "ne" %2, %1 : i32
  %4 = llvm.zext %3 : i1 to i32
  "llvm.return"(%4) : (i32) -> ()
}
]

bne in Init.Core

def xor_lshr_before := [llvm|
{
^0(%arg624 : i8, %arg625 : i8, %arg626 : i8, %arg627 : i8):
  %0 = llvm.lshr %arg624, %arg627 : i8
  %1 = llvm.lshr %arg625, %arg627 : i8
  %2 = llvm.xor %0, %arg626 : i8
  %3 = llvm.xor %2, %1 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def ashr_mul_times_5_div_4_after := [llvm|
{
^0(%arg16 : i32):
  %0 = llvm.mlir.constant(2 : i32) : i32
  %1 = llvm.lshr %arg16, %0 : i32
  %2 = llvm.add %arg16, %1 overflow<nsw,nuw> : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def sltiu_signext_test: LLVMPeepholeRewriteRefine 16 [Ty.llvm (.bitvec 16)] where
  lhs := sltiu_signext_llvm
  rhs := sltiu_signext_riscv

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

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

def llvm_xor_lower_riscv_32: LLVMPeepholeRewriteRefine 32 [Ty.llvm (.bitvec 32), Ty.llvm (.bitvec 32)] :=
  {lhs := llvm_xor_32, rhs := xor_riscv_32}

Lean.Parser.Term.matchAlts in Lean.Parser.Term

def mul? {w : Nat} (x y : BitVec w) : IntW w :=
  .value <| x * y

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

def add_of_mul_before := [llvm|
{
^0(%arg4 : i8, %arg5 : i8, %arg6 : i8):
  %0 = llvm.mul %arg4, %arg5 overflow<nsw> : i8
  %1 = llvm.mul %arg4, %arg6 overflow<nsw> : i8
  %2 = llvm.add %0, %1 overflow<nsw> : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def zext_nneg_sext_ule_op0_wide_before := [llvm|
{
^0(%arg46 : i9, %arg47 : i8):
  %0 = llvm.zext nneg %arg46 : i9 to i32
  %1 = llvm.sext %arg47 : i8 to i32
  %2 = llvm.icmp "ule" %0, %1 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

@[simp_denote]
def add_lo_negone_riscv_i64 :=
  [LV| {
    ^entry (%arg0: i64):
    %a = "builtin.unrealized_conversion_cast" (%arg0) : (i64) -> (!riscv.reg)
    %0 = li (0) : !riscv.reg
    %1= li (1) : !riscv.reg
    %2 = sub %0, %1 : !riscv.reg  
    %3 = slli %2, 32 : !riscv.reg
    %4 = add %3, %2 : !riscv.reg
    %5 = add %a, %4 : !riscv.reg
    %6 = "builtin.unrealized_conversion_cast" (%5) : (!riscv.reg) -> (i64)
    llvm.return %6 : i64
  }]

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

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

def add_constant_equal_with_the_top_bit_of_demandedbits_pass_after := [llvm|
{
^0(%arg9 : i32):
  %0 = llvm.mlir.constant(24 : i32) : i32
  %1 = llvm.mlir.constant(16 : i32) : i32
  %2 = llvm.and %arg9, %0 : i32
  %3 = llvm.xor %2, %1 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

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

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

def test15_before := [llvm|
{
^0(%arg40 : i32, %arg41 : i32):
  %0 = llvm.mlir.constant(-1431655767 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.and %arg40, %0 : i32
  %3 = llvm.xor %2, %0 : i32
  %4 = llvm.add %arg41, %1 : i32
  %5 = llvm.add %4, %3 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

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

def icmp {w : Nat} (c : IntPred) (x y : IntW w) : IntW 1 := do
  let x' ← x
  let y' ← y
  icmp? c x' y'

Lean.Parser.mkAtomicInfo in Lean.Parser.Basic

def add_shl_sext_test : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 32)] where
  lhs := add_shl_sext_llvm
  rhs := add_shl_sext_riscv

def sgt_positive_multip_rem_nz_after := [llvm|
{
^0(%arg168 : i8):
  %0 = llvm.mlir.constant(4 : i8) : i8
  %1 = llvm.icmp "sgt" %arg168, %0 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

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

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

def test_sub_nuw_nsw__nsw_is_safe_after := [llvm|
{
^0(%arg23 : i32):
  %0 = llvm.mlir.constant(-2147483648 : i32) : i32
  %1 = llvm.or %arg23, %0 : i32
  %2 = llvm.sub %0, %1 overflow<nsw> : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

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 shl_add_nuw_after := [llvm|
{
^0(%arg16 : i8, %arg17 : i8):
  %0 = llvm.mlir.constant(63 : i8) : i8
  %1 = llvm.mlir.constant(2 : i8) : i8
  %2 = llvm.and %arg16, %0 : i8
  %3 = llvm.and %arg17, %1 : i8
  %4 = llvm.shl %2, %3 overflow<nuw> : i8
  "llvm.return"(%4) : (i8) -> ()
}
]

inductive GenBVExpr : Nat → Type where
   
  | var (idx : Nat) : GenBVExpr w
   
  | const (val : BitVec w) : GenBVExpr w
   
  | extract (start len : Nat) (expr : GenBVExpr w) : GenBVExpr len
   
  | bin (lhs : GenBVExpr w) (op : BVBinOp) (rhs : GenBVExpr w) : GenBVExpr w
   
  | un (op : BVUnOp) (operand : GenBVExpr w) : GenBVExpr w
   
  | append (lhs : GenBVExpr l) (rhs : GenBVExpr r) (h : w = l + r) : GenBVExpr w
   
  | replicate (n : Nat) (expr : GenBVExpr w) (h : w' = w * n) : GenBVExpr w'
   
  | shiftLeft (lhs : GenBVExpr m) (rhs : GenBVExpr n) : GenBVExpr m
   
  | shiftRight (lhs : GenBVExpr m) (rhs : GenBVExpr n) : GenBVExpr m
   
  | arithShiftRight (lhs : GenBVExpr m) (rhs : GenBVExpr n) : GenBVExpr m
  | signExtend (v : Nat) (expr : GenBVExpr w) : GenBVExpr v
  | zeroExtend (v : Nat) (expr : GenBVExpr w) : GenBVExpr v
  | truncate (v : Nat) (expr : GenBVExpr w) : GenBVExpr v
with

def llvm_const_lower_riscv_li_11 : LLVMPeepholeRewriteRefine 64 [] :=
  {lhs := constLLVM_11, rhs:= liRiscv_11,
   correct := by admit /- proof elided -/

def sdiv_exact_eq_9_no_of_before := [llvm|
{
^0(%arg8 : i8, %arg9 : i8):
  %0 = llvm.mlir.constant(7 : i8) : i8
  %1 = llvm.mlir.constant(9 : i8) : i8
  %2 = llvm.and %arg9, %0 : i8
  %3 = llvm.sdiv exact %arg8, %2 : i8
  %4 = llvm.icmp "eq" %3, %1 : i8
  "llvm.return"(%4) : (i1) -> ()
}
]

structure TermFSM (wcard tcard bcard ncard icard pcard : Nat) (t : Nondep.Term) where
  toFsmZext : FSM (StateSpace wcard tcard bcard ncard icard pcard)
  width : NatFSM wcard tcard bcard ncard icard pcard t.width

def sext_xor_sub_2_before := [llvm|
{
^0(%arg24 : i64, %arg25 : i1):
  %0 = llvm.sext %arg25 : i1 to i64
  %1 = llvm.xor %arg24, %0 : i64
  %2 = llvm.sub %0, %1 : i64
  "llvm.return"(%2) : (i64) -> ()
}
]

def map {α β : Type u} (f : α → β) {n : Nat} : LengthIndexedList α n → LengthIndexedList β n
  | nil => nil
  | cons x xs => cons (f x) (map f xs)

def positive_biggerLshr_lshrexact_after := [llvm|
{
^0(%arg32 : i32):
  %0 = llvm.mlir.constant(5 : i32) : i32
  %1 = llvm.mlir.constant(4194303 : i32) : i32
  %2 = llvm.lshr exact %arg32, %0 : i32
  %3 = llvm.and %2, %1 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

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

instance {n} : ShiftRight (BitVec n) := ⟨fun x y => x >>> y.toNat⟩

def test_or4_after := [llvm|
{
^0(%arg24 : i32, %arg25 : i32):
  %0 = llvm.mlir.constant(2147483647 : i32) : i32
  %1 = llvm.and %arg25, %0 : i32
  %2 = llvm.icmp "ugt" %arg24, %1 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

def test8_before := [llvm|
{
^0(%arg15 : i27):
  %0 = llvm.mlir.constant(9 : i27) : i27
  %1 = llvm.mul %0, %arg15 : i27
  %2 = llvm.sub %1, %arg15 : i27
  "llvm.return"(%2) : (i27) -> ()
}
]

def test14_after := [llvm|
{
^0(%arg0 : i32, %arg1 : i32):
  %0 = llvm.mlir.constant(8 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.mlir.constant(128 : i32) : i32
  %3 = llvm.shl %arg0, %0 : i32
  %4 = llvm.sub %1, %arg1 : i32
  %5 = llvm.and %4, %2 : i32
  %6 = llvm.mul %5, %3 : i32
  "llvm.return"(%6) : (i32) -> ()
}
]

def sub_3_after := [llvm|
{
^0(%arg105 : i128, %arg106 : i1, %arg107 : i128, %arg108 : i128):
  %0 = llvm.mlir.constant(-124 : i128) : i128
  %1 = llvm.mlir.constant(-2 : i128) : i128
  %2 = llvm.xor %arg108, %0 : i128
  %3 = "llvm.select"(%arg106, %arg107, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i128, i128) -> i128
  %4 = llvm.add %3, %arg105 : i128
  %5 = llvm.sub %1, %4 : i128
  "llvm.return"(%5) : (i128) -> ()
}
]

def sext_before := [llvm|
{
^0(%arg9 : i1):
  %0 = llvm.mlir.constant(-1 : i41) : i41
  %1 = llvm.mlir.constant(0 : i41) : i41
  %2 = "llvm.select"(%arg9, %0, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i41, i41) -> i41
  "llvm.return"(%2) : (i41) -> ()
}
]

def zext_mul_before := [llvm|
{
^0(%arg13 : i8):
  %0 = llvm.mlir.constant(3 : i16) : i16
  %1 = llvm.zext %arg13 : i8 to i16
  %2 = llvm.mul %1, %0 : i16
  %3 = llvm.and %2, %1 : i16
  "llvm.return"(%3) : (i16) -> ()
}
]

def bar_before := [llvm|
{
^0(%arg109 : i32, %arg110 : i32, %arg111 : i32, %arg112 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.icmp "slt" %arg109, %arg110 : i32
  %2 = llvm.sext %1 : i1 to i32
  %3 = llvm.and %arg111, %2 : i32
  %4 = llvm.xor %2, %0 : i32
  %5 = llvm.and %arg112, %4 : i32
  %6 = llvm.or %5, %3 : i32
  "llvm.return"(%6) : (i32) -> ()
}
]

def only_one_masked_after := [llvm|
{
^0(%arg0 : i64):
  %0 = llvm.mlir.constant(-9223372036854775808) : i64
  %1 = llvm.icmp "eq" %arg0, %0 : i64
  "llvm.return"(%1) : (i1) -> ()
}
]

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

def test_ne_11_and_15_add_10_before := [llvm|
{
^0(%arg0 : i8):
  %0 = llvm.mlir.constant(10 : i8) : i8
  %1 = llvm.mlir.constant(15 : i8) : i8
  %2 = llvm.mlir.constant(11 : i8) : i8
  %3 = llvm.add %arg0, %0 : i8
  %4 = llvm.and %3, %1 : i8
  %5 = llvm.icmp "ne" %4, %2 : i8
  "llvm.return"(%5) : (i1) -> ()
}
]

Lean.Meta.mkAppOptM in Lean.Meta.AppBuilder

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

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

def test9_before := [llvm|
{
^0(%arg87 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.and %arg87, %0 : i32
  %2 = llvm.trunc %1 : i32 to i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def and_sequence_10_rhs (w : Nat)  :=
[llvm( w )| {
^bb0(%C1 : _, %Z : _):
  %v1 = llvm.and %Z,  %C1
  llvm.return %v1
}]

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

@[simp_denote]
def icmp_ule_llvm_32 : Com LLVMPlusRiscV ⟨[.llvm (.bitvec 32), .llvm (.bitvec 32)]⟩
  .pure (.llvm (.bitvec 1)) := [LV| {
  ^entry (%lhs: i32, %rhs: i32):
    %1 = llvm.icmp.ule %lhs, %rhs : i32
    llvm.return %1 : i1
  }]

def two_ne_stmt (b a : LLVM.IntW w) :
    (LLVM.icmp LLVM.IntPred.ne b a)
      ⊑ (LLVM.icmp LLVM.IntPred.ne b a) :=

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

def a_before := [llvm|
{
^0(%arg48 : i1, %arg49 : i1):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.zext %arg48 : i1 to i32
  %3 = llvm.zext %arg49 : i1 to i32
  %4 = llvm.sub %0, %3 : i32
  %5 = llvm.add %2, %1 : i32
  %6 = llvm.add %5, %4 : i32
  "llvm.return"(%6) : (i32) -> ()
}
]

def test2_after := [llvm|
{
^0(%arg12 : i15):
  "llvm.return"(%arg12) : (i15) -> ()
}
]

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

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

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

def test2_after := [llvm|
{
^0(%arg0 : i167):
  %0 = llvm.mlir.constant(9 : i167) : i167
  %1 = llvm.mlir.constant(8 : i167) : i167
  %2 = llvm.lshr %arg0, %0 : i167
  %3 = llvm.shl %arg0, %1 : i167
  %4 = llvm.or %2, %3 : i167
  "llvm.return"(%4) : (i167) -> ()
}
]

def udiv_illegal_type_before := [llvm|
{
^0(%arg23 : i9, %arg24 : i9):
  %0 = llvm.zext %arg23 : i9 to i32
  %1 = llvm.zext %arg24 : i9 to i32
  %2 = llvm.udiv %0, %1 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def Expr.mkPredicateFSMDep (_wcard _tcard _bcard _pcard : Nat) (_tctx : Expr) (p : Expr) : SolverM Expr := do
  let out ← mkAppM (``MultiWidth.mkPredicateFSMDep) #[p]
  debugCheck out
  return out

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

def test1_before := [llvm|
{
^0(%arg3 : i33):
  %0 = llvm.mlir.constant(4096 : i33) : i33
  %1 = llvm.urem %arg3, %0 : i33
  "llvm.return"(%1) : (i33) -> ()
}
]

def test15b_after := [llvm|
{
^0(%arg26 : i32):
  %0 = llvm.mlir.constant(32 : i32) : i32
  %1 = llvm.and %arg26, %0 : i32
  %2 = llvm.xor %1, %0 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def matchMulO: List (Σ Γ, LLVMPeepholeRewriteRefine 64 Γ) :=
  [⟨_, mulo_by_2_unsigned_signed⟩,
  ⟨_, mulo_by_2_unsigned⟩,
  ⟨_, mulo_by_2_signed⟩]

Lean.Expr.numeral? in Mathlib.Lean.Expr.Basic

def demorganize_constant2_before := [llvm|
{
^0(%arg18 : i32):
  %0 = llvm.mlir.constant(15 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.or %arg18, %0 : i32
  %3 = llvm.xor %2, %1 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

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

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

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

def n2_badmask_after := [llvm|
{
^0(%arg4 : i32, %arg5 : i32, %arg6 : i32, %arg7 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.and %arg6, %arg4 : i32
  %2 = llvm.xor %arg7, %0 : i32
  %3 = llvm.and %arg5, %2 : i32
  %4 = llvm.or %1, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)

OneHom in Mathlib.Algebra.Group.Hom.Defs

def add_nsw_mul_nsw_before := [llvm|
{
^0(%arg33 : i16):
  %0 = llvm.add %arg33, %arg33 overflow<nsw> : i16
  %1 = llvm.add %0, %arg33 overflow<nsw> : i16
  "llvm.return"(%1) : (i16) -> ()
}
]

def land_land_left1_before := [llvm|
{
^0(%arg102 : i1, %arg103 : i1):
  %0 = llvm.mlir.constant(false) : i1
  %1 = "llvm.select"(%arg102, %arg103, %0) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %2 = "llvm.select"(%1, %arg102, %0) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%2) : (i1) -> ()
}
]

def SelectionDAG_combines : List (Σ Γ, LLVMPeepholeRewriteRefine 64 Γ) :=
  visitADD ++ visitAND ++ visitSUB ++ visitMUL ++ visitSDIV ++ visitOR
  ++ visitXOR ++ visitSRA ++ visitSELECT

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

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

def a_or_b_const_after := [llvm|
{
^0(%arg10 : i32, %arg11 : i32, %arg12 : i32):
  %0 = llvm.icmp "eq" %arg10, %arg12 : i32
  %1 = llvm.icmp "eq" %arg11, %arg12 : i32
  %2 = llvm.xor %0, %1 : i1
  "llvm.return"(%2) : (i1) -> ()
}
]

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

def shl_mask_after := [llvm|
{
^0(%arg6 : i32):
  %0 = llvm.mlir.constant(255 : i32) : i32
  %1 = llvm.mlir.constant(8 : i32) : i32
  %2 = llvm.and %arg6, %0 : i32
  %3 = llvm.shl %2, %1 overflow<nsw,nuw> : i32
  %4 = llvm.or disjoint %2, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

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

def sle_swap_or_min_after := [llvm|
{
^0(%arg150 : i8, %arg151 : i8):
  %0 = llvm.icmp "sge" %arg151, %arg150 : i8
  "llvm.return"(%0) : (i1) -> ()
}
]

def filterCandidatePredicates  (bvLogicalExpr: BoolExpr GenBVPred) (preconditionCandidates visited: Std.HashSet (BoolExpr GenBVPred))
                                                    : GeneralizerStateM ParsedBVExpr GenBVPred (List (BoolExpr GenBVPred)) :=
  withTraceNode `Generalize (fun _ => return "Filtered out invalid expression sketches") do
    let state ← get
    let widthId := state.widthId
    let bitwidth := state.processingWidth

    let mut res : List (BoolExpr GenBVPred) := []
    
    
    
    
    let widthConstraint : BoolExpr GenBVPred :=
      BoolExpr.literal (GenBVPred.bin (GenBVExpr.var widthId) BVBinPred.eq (GenBVExpr.const (BitVec.ofNat bitwidth bitwidth)))

    let mut numInvocations := 0
    let mut currentCandidates := preconditionCandidates.filter (λ cand => !visited.contains cand)
    logInfo m! "Originally processing {currentCandidates.size} candidates"

    
    while !currentCandidates.isEmpty do
      let expressionsConstraints : BoolExpr GenBVPred := bigOr (currentCandidates.toList)
      let bvLogicalExpr := bvLogicalExpr
      let expr := BoolExpr.gate Gate.and (BoolExpr.gate .and expressionsConstraints widthConstraint) (BoolExpr.not bvLogicalExpr)

      let mut newCandidates : Std.HashSet (BoolExpr GenBVPred) := Std.HashSet.emptyWithCapacity
      numInvocations := numInvocations + 1
      match (← solve expr) with
      | none => break
      | some assignment =>
          newCandidates ← withTraceNode `Generalize (fun _ => return "Evaluated expressions for filtering") do
            let mut res : Std.HashSet (BoolExpr GenBVPred) := Std.HashSet.emptyWithCapacity
            for candidate in currentCandidates do
              let widthSubstitutedCandidate := subsituteGenLogicalExpr candidate (bvExprToSubstitutionValue (Std.HashMap.ofList [(widthId, wrap (GenBVExpr.const (BitVec.ofNat bitwidth bitwidth)))]))
              if !(evalBoolExpr widthSubstitutedCandidate (fun v => v.eval assignment)) then
                res := res.insert candidate
            pure res

      currentCandidates := newCandidates

    logInfo m! "Invoked the solver {numInvocations} times for {preconditionCandidates.size} potential candidates."
    res := currentCandidates.toList
    pure res

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

def zext_masked_bit_nonzero_to_smaller_bitwidth_before := [llvm|
{
^0(%arg43 : i32, %arg44 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.shl %0, %arg44 : i32
  %3 = llvm.and %2, %arg43 : i32
  %4 = llvm.icmp "ne" %3, %1 : i32
  %5 = llvm.zext %4 : i1 to i16
  "llvm.return"(%5) : (i16) -> ()
}
]

def alive_AndOrXor_2647_tgt  (w : Nat)  :=
[llvm( w )| {
^bb0(%a : _, %b : _):
  %v1 = llvm.and %a, %b
  %v2 = llvm.xor %a, %b
  %v3 = llvm.or %a, %b
  llvm.return %v3
}]

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

def test_mul_nuw_nsw__nsw_is_safe_after := [llvm|
{
^0(%arg7 : i32):
  %0 = llvm.mlir.constant(-83886080 : i32) : i32
  %1 = llvm.mlir.constant(9 : i32) : i32
  %2 = llvm.or %arg7, %0 : i32
  %3 = llvm.mul %2, %1 overflow<nsw> : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def trunc_lshr_sext_exact_before := [llvm|
{
^0(%arg45 : i8):
  %0 = llvm.mlir.constant(6 : i32) : i32
  %1 = llvm.sext %arg45 : i8 to i32
  %2 = llvm.lshr exact %1, %0 : i32
  %3 = llvm.trunc %2 : i32 to i8
  "llvm.return"(%3) : (i8) -> ()
}
]

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

def test_mul_nuw_nsw__nsw_is_safe_before := [llvm|
{
^0(%arg7 : i32):
  %0 = llvm.mlir.constant(-83886080 : i32) : i32
  %1 = llvm.mlir.constant(-83886079 : i32) : i32
  %2 = llvm.mlir.constant(9 : i32) : i32
  %3 = llvm.mlir.constant(-754974711 : i32) : i32
  %4 = llvm.or %arg7, %0 : i32
  %5 = llvm.icmp "eq" %4, %1 : i32
  %6 = llvm.mul %4, %2 overflow<nsw,nuw> : i32
  %7 = "llvm.select"(%5, %3, %6) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%7) : (i32) -> ()
}
]

def test31_before := [llvm|
{
^0(%arg164 : i64):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mlir.constant(10 : i32) : i32
  %2 = llvm.trunc %arg164 : i64 to i32
  %3 = llvm.and %2, %0 : i32
  %4 = llvm.icmp "eq" %3, %1 : i32
  "llvm.return"(%4) : (i1) -> ()
}
]

BitVec.truncate in Init.Data.BitVec.Basic

@[simps]
def complete (M : NFA α σ) : NFA α (σ ⊕ Unit) where
  start := { x | match x with | .inl x => x ∈ M.start | .inr () => True }
  accept := { x | match x with | .inl x => x ∈ M.accept | .inr () => False }
  step x a := { y |
    match x with
    | .inl x => match y with | .inl y => y ∈ M.step x a | .inr () => False
    | .inr () => y = .inr () }

def trunc_equality_nsw_sext_after := [llvm|
{
^0(%arg14 : i32, %arg15 : i8):
  %0 = llvm.sext %arg15 : i8 to i32
  %1 = llvm.icmp "ne" %arg14, %0 : i32
  "llvm.return"(%1) : (i1) -> ()
}
]

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

def IndexInvariant (f : LoopBody t) : Prop :=
  ∀ (i j : Int) (v : t), f i v = f j v

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

def and_umax_muchless_before := [llvm|
{
^0(%arg18 : i32):
  %0 = llvm.mlir.constant(12 : i32) : i32
  %1 = llvm.mlir.constant(-32 : i32) : i32
  %2 = llvm.icmp "ugt" %0, %arg18 : i32
  %3 = "llvm.select"(%2, %0, %arg18) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %4 = llvm.and %3, %1 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

instance {α β : Type} [Fintype α] [Fintype β] (b : Bool) :
    Fintype (cond b α β) :=

def masked_bit_clear_commute_after := [llvm|
{
^0(%arg77 : i32, %arg78 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.mlir.constant(1 : i32) : i32
  %3 = llvm.srem %0, %arg77 : i32
  %4 = llvm.xor %3, %1 : i32
  %5 = llvm.lshr %4, %arg78 : i32
  %6 = llvm.and %5, %2 : i32
  "llvm.return"(%6) : (i32) -> ()
}
]

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

def ashr_xor_before := [llvm|
{
^0(%arg20 : i8):
  %0 = llvm.mlir.constant(-128 : i8) : i8
  %1 = llvm.mlir.constant(1 : i8) : i8
  %2 = llvm.mlir.constant(-64 : i8) : i8
  %3 = llvm.ashr %0, %arg20 : i8
  %4 = llvm.add %arg20, %1 : i8
  %5 = llvm.ashr %2, %4 : i8
  %6 = llvm.xor %3, %5 : i8
  "llvm.return"(%6) : (i8) -> ()
}
]

def samesign_different_sign_bittest2_before := [llvm|
{
^0(%arg127 : i32, %arg128 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.and %arg127, %arg128 : i32
  %2 = llvm.icmp "slt" %1, %0 : i32
  %3 = llvm.or %arg127, %arg128 : i32
  %4 = llvm.icmp "sge" %3, %0 : i32
  %5 = llvm.or %2, %4 : i1
  "llvm.return"(%5) : (i1) -> ()
}
]

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

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

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

def or_or_and_pat5_after := [llvm|
{
^0(%arg58 : i8, %arg59 : i8, %arg60 : i8, %arg61 : i8):
  %0 = llvm.or %arg61, %arg59 : i8
  %1 = llvm.and %arg58, %0 : i8
  %2 = llvm.or %1, %arg60 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def collectBVAtom (state : CollectState)
  (e : Expr) : SolverM (MultiWidth.Nondep.Term × CollectState) := do
  let t ← inferType e
  let_expr BitVec w := t
    | throwError m!"expected type 'BitVec w', found: {indentD t} (expression: {indentD e})"
  let (wexpr, state) ← collectWidthExpr state w
  let (bvix, bvToIx) := state.bvToIx.findOrInsertVal (e, wexpr)
  return (.var bvix wexpr, { state with bvToIx })

def mul_unkV_evenC_ne_after := [llvm|
{
^0(%arg12 : i64):
  %0 = llvm.mlir.constant(4611686018427387903) : i64
  %1 = llvm.mlir.constant(0) : i64
  %2 = llvm.and %arg12, %0 : i64
  %3 = llvm.icmp "ne" %2, %1 : i64
  "llvm.return"(%3) : (i1) -> ()
}
]

def ashr_and_or_disjoint_after := [llvm|
{
^0(%arg41 : i8, %arg42 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.mlir.constant(2 : i8) : i8
  %2 = llvm.mlir.constant(52 : i8) : i8
  %3 = llvm.srem %arg41, %0 : i8
  %4 = llvm.shl %3, %1 : i8
  %5 = llvm.and %arg42, %2 : i8
  %6 = llvm.or disjoint %5, %4 : i8
  "llvm.return"(%6) : (i8) -> ()
}
]

def t0_before := [llvm|
{
^0(%arg18 : i8):
  %0 = llvm.mlir.constant(1 : i8) : i8
  %1 = llvm.mlir.constant(-1 : i8) : i8
  %2 = llvm.shl %0, %arg18 : i8
  %3 = llvm.add %2, %1 : i8
  %4 = llvm.or %3, %2 : i8
  "llvm.return"(%4) : (i8) -> ()
}
]

def test4_after := [llvm|
{
^0(%arg97 : i32, %arg98 : i1):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.mlir.constant(7 : i32) : i32
  %2 = "llvm.select"(%arg98, %0, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %3 = llvm.and %arg97, %2 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def demorgan_or_apint1_after := [llvm|
{
^0(%arg62 : i43, %arg63 : i43):
  %0 = llvm.mlir.constant(-1 : i43) : i43
  %1 = llvm.and %arg62, %arg63 : i43
  %2 = llvm.xor %1, %0 : i43
  "llvm.return"(%2) : (i43) -> ()
}
]

def test_imply_not2_after := [llvm|
{
^0(%arg3 : i32, %arg4 : i1):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.mlir.constant(true) : i1
  %2 = llvm.icmp "ne" %arg3, %0 : i32
  %3 = "llvm.select"(%2, %1, %arg4) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%3) : (i1) -> ()
}
]

def sgt_smax1_before := [llvm|
{
^0(%arg39 : i32, %arg40 : i32):
  %0 = llvm.icmp "sgt" %arg39, %arg40 : i32
  %1 = "llvm.select"(%0, %arg39, %arg40) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %2 = llvm.icmp "sgt" %1, %arg39 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

def llvm_sext_lower_riscv_i1_to_64 : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 1)] :=
  {lhs:= sext_llvm_i1_to_64, rhs:= sext_riscv_i1_to_64}

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

def no_shift_no_xor_multiuse_cmp_xor_after := [llvm|
{
^0(%arg56 : i32, %arg57 : i32, %arg58 : i32, %arg59 : i32):
  %0 = llvm.mlir.constant(4096 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.and %arg56, %0 : i32
  %3 = llvm.icmp "eq" %2, %1 : i32
  %4 = llvm.xor %arg57, %0 : i32
  %5 = llvm.xor %arg57, %2 : i32
  %6 = "llvm.select"(%3, %arg58, %arg59) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %7 = llvm.mul %5, %6 : i32
  %8 = llvm.mul %7, %4 : i32
  "llvm.return"(%8) : (i32) -> ()
}
]

def modulo2_before := [llvm|
{
^0(%arg10 : i32):
  %0 = llvm.mlir.constant(2 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.srem %arg10, %0 : i32
  %3 = llvm.icmp "slt" %2, %1 : i32
  %4 = "llvm.select"(%3, %0, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %5 = llvm.add %4, %2 overflow<nsw> : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

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

def uge_swap_or_max_commute_after := [llvm|
{
^0(%arg162 : i8, %arg163 : i8):
  %0 = llvm.icmp "ule" %arg163, %arg162 : i8
  "llvm.return"(%0) : (i1) -> ()
}
]

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

def elabDefSignatureFor (dialect : Term) (alts : TSyntax ``matchAltsSig) : CommandElabM Unit := do
  let msg := (return m!"{exceptEmoji ·} Defining operation signature for {dialect} dialect")
  withTraceNode `LeanMLIR.Elab msg (collapsed := false) <| do
    let alts := getMatchAlts alts
    let alts ← do
      alts.mapM fun view => do
        trace[LeanMLIR.Elab] m!"Parsing match alternative with\n\
          \tpatterns: {view.patterns}\n\
          \tsignature: {view.rhs}"
        let rhs ← parseSignature view.rhs
        return { view with rhs }

    |

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

def sub_ashr_or_i64_before := [llvm|
{
^0(%arg33 : i64, %arg34 : i64):
  %0 = llvm.mlir.constant(63) : i64
  %1 = llvm.sub %arg34, %arg33 overflow<nsw> : i64
  %2 = llvm.ashr %1, %0 : i64
  %3 = llvm.or %2, %arg33 : i64
  "llvm.return"(%3) : (i64) -> ()
}
]

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

def SolverM.run (m : SolverM α) (ctx : Context) : TermElabM α :=
  ReaderT.run m ctx

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

def test86_after := [llvm|
{
^0(%arg59 : i16):
  %0 = llvm.mlir.constant(4 : i16) : i16
  %1 = llvm.ashr %arg59, %0 : i16
  "llvm.return"(%1) : (i16) -> ()
}
]

def test16_after := [llvm|
{
^0(%arg42 : i8, %arg43 : i8):
  %0 = llvm.mlir.constant(33 : i8) : i8
  %1 = llvm.xor %arg43, %arg42 : i8
  %2 = llvm.xor %arg42, %arg43 : i8
  %3 = llvm.xor %2, %0 : i8
  %4 = llvm.and %3, %1 : i8
  %5 = llvm.mul %4, %3 : i8
  "llvm.return"(%5) : (i8) -> ()
}
]

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

def test18_before := [llvm|
{
^0(%arg194 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.mlir.constant(123 : i32) : i32
  %2 = llvm.xor %arg194, %0 : i32
  %3 = llvm.sub %1, %2 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def n12_before := [llvm|
{
^0(%arg0 : i8, %arg1 : i8):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.sub %0, %arg0 overflow<nsw> : i8
  %2 = llvm.icmp "sgt" %1, %arg1 : i8
  "llvm.return"(%2) : (i1) -> ()
}
]

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

def llvm_const_lower_riscv_li0 : LLVMPeepholeRewriteRefine 64 [] :=
  {lhs := constLLVM0, rhs:= liRiscv0,
   correct := by admit /- proof elided -/

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

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

def test25_after := [llvm|
{
^0(%arg271 : i32):
  %0 = llvm.mlir.constant(-50 : i32) : i32
  %1 = llvm.mlir.constant(50 : i32) : i32
  %2 = llvm.add %arg271, %0 : i32
  %3 = llvm.icmp "ult" %2, %1 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

def trunc_shl_ashr_var_before := [llvm|
{
^0(%arg16 : i64, %arg17 : i64):
  %0 = llvm.mlir.constant(2) : i64
  %1 = llvm.ashr %arg16, %arg17 : i64
  %2 = llvm.shl %1, %0 : i64
  %3 = llvm.trunc %2 : i64 to i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def p_constmask2_before := [llvm|
{
^0(%arg41 : i32, %arg42 : i32):
  %0 = llvm.mlir.constant(61440 : i32) : i32
  %1 = llvm.mlir.constant(-65281 : i32) : i32
  %2 = llvm.and %arg41, %0 : i32
  %3 = llvm.and %arg42, %1 : i32
  %4 = llvm.add %2, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def or_and_not_not_commute4_before := [llvm|
{
^0(%arg413 : i32, %arg414 : i32, %arg415 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.or %arg413, %arg414 : i32
  %2 = llvm.xor %1, %0 : i32
  %3 = llvm.or %arg413, %arg415 : i32
  %4 = llvm.xor %3, %0 : i32
  %5 = llvm.and %4, %arg414 : i32
  %6 = llvm.or %5, %2 : i32
  "llvm.return"(%6) : (i32) -> ()
}
]

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

def add_smax_simplify2_after := [llvm|
{
^0(%arg24 : i8):
  %0 = llvm.mlir.constant(127 : i8) : i8
  %1 = llvm.add %arg24, %0 overflow<nsw> : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

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

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

def main15_logical_before := [llvm|
{
^0(%arg13 : i32):
  %0 = llvm.mlir.constant(0 : i16) : i16
  %1 = llvm.mlir.constant(0 : i8) : i8
  %2 = llvm.mlir.constant(true) : i1
  %3 = llvm.mlir.constant(2 : i32) : i32
  %4 = llvm.mlir.constant(1 : i32) : i32
  %5 = llvm.trunc %arg13 : i32 to i16
  %6 = llvm.icmp "sge" %5, %0 : i16
  %7 = llvm.trunc %arg13 : i32 to i8
  %8 = llvm.icmp "sge" %7, %1 : i8
  %9 = "llvm.select"(%6, %2, %8) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %10 = "llvm.select"(%9, %3, %4) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%10) : (i32) -> ()
}
]

def sub_from_variable_of_sub_from_constant_after := [llvm|
{
^0(%arg167 : i8, %arg168 : i8):
  %0 = llvm.mlir.constant(-42 : i8) : i8
  %1 = llvm.add %arg167, %0 : i8
  %2 = llvm.add %1, %arg168 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def uge_umin2_before := [llvm|
{
^0(%arg50 : i32, %arg51 : i32):
  %0 = llvm.icmp "ult" %arg51, %arg50 : i32
  %1 = "llvm.select"(%0, %arg51, %arg50) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %2 = llvm.icmp "uge" %1, %arg50 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

def udiv_shl_mul_nuw_swap_after := [llvm|
{
^0(%arg145 : i5, %arg146 : i5, %arg147 : i5):
  %0 = llvm.mlir.constant(1 : i5) : i5
  %1 = llvm.shl %0, %arg147 overflow<nuw> : i5
  %2 = llvm.udiv %1, %arg146 : i5
  "llvm.return"(%2) : (i5) -> ()
}
]

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

def icmp_ne_mul_nsw_nonequal_before := [llvm|
{
^0(%arg28 : i8, %arg29 : i8):
  %0 = llvm.mlir.constant(1 : i8) : i8
  %1 = llvm.add %arg28, %0 : i8
  %2 = llvm.mul %arg28, %arg29 overflow<nsw> : i8
  %3 = llvm.mul %1, %arg29 overflow<nsw> : i8
  %4 = llvm.icmp "ne" %2, %3 : i8
  "llvm.return"(%4) : (i1) -> ()
}
]

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

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

def BuilderM.isOk {α : Type} (x : BuilderM d α) : Bool :=
  match x.run [] with
  | Except.ok _ => true
  | Except.error _ => false

def test5_before := [llvm|
{
^0(%arg224 : i32, %arg225 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg224, %arg225 : i32
  %2 = llvm.xor %arg224, %0 : i32
  %3 = llvm.or %1, %2 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def eval_sext_multi_use_in_one_inst_before := [llvm|
{
^0(%arg6 : i32):
  %0 = llvm.mlir.constant(14 : i16) : i16
  %1 = llvm.mlir.constant(-32768 : i16) : i16
  %2 = llvm.trunc %arg6 : i32 to i16
  %3 = llvm.and %2, %0 : i16
  %4 = llvm.mul %3, %3 overflow<nsw,nuw> : i16
  %5 = llvm.or %4, %1 : i16
  %6 = llvm.sext %5 : i16 to i32
  "llvm.return"(%6) : (i32) -> ()
}
]

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

def test8_before := [llvm|
{
^0(%arg94 : i32, %arg95 : i32):
  %0 = llvm.mlir.constant(32 : i128) : i128
  %1 = llvm.zext %arg94 : i32 to i128
  %2 = llvm.zext %arg95 : i32 to i128
  %3 = llvm.shl %2, %0 : i128
  %4 = llvm.or %3, %1 : i128
  %5 = llvm.trunc %4 : i128 to i64
  "llvm.return"(%5) : (i64) -> ()
}
]

def lshr_shl_pow2_const_xor_after := [llvm|
{
^0(%arg59 : i16):
  %0 = llvm.mlir.constant(7 : i16) : i16
  %1 = llvm.mlir.constant(0 : i16) : i16
  %2 = llvm.mlir.constant(8 : i16) : i16
  %3 = llvm.icmp "eq" %arg59, %0 : i16
  %4 = "llvm.select"(%3, %1, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i16, i16) -> i16
  "llvm.return"(%4) : (i16) -> ()
}
]

def ashrslt_03_07_exact_before := [llvm|
{
^0(%arg14 : i4):
  %0 = llvm.mlir.constant(3 : i4) : i4
  %1 = llvm.mlir.constant(7 : i4) : i4
  %2 = llvm.ashr exact %arg14, %0 : i4
  %3 = llvm.icmp "slt" %2, %1 : i4
  "llvm.return"(%3) : (i1) -> ()
}
]

def p_after := [llvm|
{
^0(%arg60 : i32, %arg61 : i32, %arg62 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.and %arg60, %arg62 : i32
  %2 = llvm.xor %arg62, %0 : i32
  %3 = llvm.and %arg61, %2 : i32
  %4 = llvm.or disjoint %1, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

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

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

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

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

def demorgan_nand_apint1_before := [llvm|
{
^0(%arg36 : i7, %arg37 : i7):
  %0 = llvm.mlir.constant(-1 : i7) : i7
  %1 = llvm.xor %arg36, %0 : i7
  %2 = llvm.and %1, %arg37 : i7
  %3 = llvm.xor %2, %0 : i7
  "llvm.return"(%3) : (i7) -> ()
}
]

def in_constant_varx_mone_invmask_after := [llvm|
{
^0(%arg41 : i4, %arg42 : i4):
  %0 = llvm.or %arg41, %arg42 : i4
  "llvm.return"(%0) : (i4) -> ()
}
]

def alive_AddSub_1152_tgt  :=
[llvm()| {
^bb0(%y : i1, %x : i1):
  %v1 = llvm.xor %x, %y : i1
  llvm.return %v1 : i1
}]

def dec_sub_before := [llvm|
{
^0(%arg16 : i8, %arg17 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.sub %arg16, %arg17 : i8
  %2 = llvm.add %1, %0 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

instance {n} : ShiftLeft (BitVec n) := ⟨fun x y => x <<< y.toNat⟩

def sub_from_constant_of_sub_from_constant_after := [llvm|
{
^0(%arg170 : i8):
  %0 = llvm.mlir.constant(-31 : i8) : i8
  %1 = llvm.add %arg170, %0 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

def sub_to_xor_before := [llvm|
{
^0(%arg15 : i32, %arg16 : i32):
  %0 = llvm.or %arg15, %arg16 : i32
  %1 = llvm.and %arg15, %arg16 : i32
  %2 = llvm.sub %0, %1 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def shrink_and_after := [llvm|
{
^0(%arg9 : i64):
  %0 = llvm.mlir.constant(42) : i64
  %1 = llvm.and %arg9, %0 : i64
  %2 = llvm.trunc %1 overflow<nsw,nuw> : i64 to i31
  "llvm.return"(%2) : (i31) -> ()
}
]

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

def canonicalize_icmp_uge_3 : LLVMPeepholeRewriteRefine 1 [Ty.llvm (.bitvec 64)] where
  lhs := [LV| {
    ^entry (%x: i64):
      %c = llvm.mlir.constant 3 : i64
      %1 = llvm.icmp.uge %c, %x : i64
      llvm.return %1 : i1
  }]
  rhs := [LV| {
    ^entry (%x: i64):
      %c = llvm.mlir.constant 3 : i64
      %1 = llvm.icmp.ule %x, %c : i64
      llvm.return %1 : i1
  }]

def test15_before := [llvm|
{
^0(%arg44 : i8, %arg45 : i8):
  %0 = llvm.mlir.constant(33 : i8) : i8
  %1 = llvm.xor %arg45, %arg44 : i8
  %2 = llvm.xor %arg44, %0 : i8
  %3 = llvm.xor %2, %arg45 : i8
  %4 = llvm.and %1, %3 : i8
  %5 = llvm.mul %4, %3 : i8
  "llvm.return"(%5) : (i8) -> ()
}
]

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

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

def sgt_x_impliesF_eq_smin_todo_before := [llvm|
{
^0(%arg11 : i8, %arg12 : i8, %arg13 : i8):
  %0 = llvm.mlir.constant(-128 : i8) : i8
  %1 = llvm.icmp "sgt" %arg11, %arg13 : i8
  %2 = "llvm.select"(%1, %0, %arg12) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  %3 = llvm.icmp "eq" %2, %arg11 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

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

def and_or_not_not_wrong_b_before := [llvm|
{
^0(%arg328 : i32, %arg329 : i32, %arg330 : i32, %arg331 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.and %arg331, %arg328 : i32
  %2 = llvm.xor %1, %0 : i32
  %3 = llvm.and %arg328, %arg330 : i32
  %4 = llvm.xor %3, %0 : i32
  %5 = llvm.or %4, %arg329 : i32
  %6 = llvm.and %5, %2 : i32
  "llvm.return"(%6) : (i32) -> ()
}
]

def ult_umin2_after := [llvm|
{
^0(%arg34 : i32, %arg35 : i32):
  %0 = llvm.icmp "ult" %arg35, %arg34 : i32
  "llvm.return"(%0) : (i1) -> ()
}
]

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

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

And in Init.Prelude

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

def shl_xor_xor_no_const_after := [llvm|
{
^0(%arg134 : i8, %arg135 : i8, %arg136 : i8, %arg137 : i8):
  %0 = llvm.xor %arg135, %arg134 : i8
  %1 = llvm.shl %0, %arg136 : i8
  %2 = llvm.xor %1, %arg137 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def trunc_equality_nsw_zext_before := [llvm|
{
^0(%arg16 : i32, %arg17 : i8):
  %0 = llvm.trunc %arg16 overflow<nsw> : i32 to i16
  %1 = llvm.zext %arg17 : i8 to i16
  %2 = llvm.icmp "ne" %0, %1 : i16
  "llvm.return"(%2) : (i1) -> ()
}
]

def src_is_mask_xor_before := [llvm|
{
^0(%arg115 : i8, %arg116 : i8):
  %0 = llvm.mlir.constant(123 : i8) : i8
  %1 = llvm.mlir.constant(-1 : i8) : i8
  %2 = llvm.xor %arg115, %0 : i8
  %3 = llvm.add %arg116, %1 : i8
  %4 = llvm.xor %arg116, %3 : i8
  %5 = llvm.and %2, %4 : i8
  %6 = llvm.icmp "ne" %5, %2 : i8
  "llvm.return"(%6) : (i1) -> ()
}
]

def xor_common_op_commute3_after := [llvm|
{
^0(%arg202 : i8, %arg203 : i8):
  %0 = llvm.mlir.constant(5 : i8) : i8
  %1 = llvm.xor %arg202, %0 : i8
  %2 = llvm.mul %arg203, %arg203 : i8
  %3 = llvm.or %1, %2 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

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

def bool_add_ashr_after := [llvm|
{
^0(%arg10 : i1, %arg11 : i1):
  %0 = llvm.mlir.constant(1 : i2) : i2
  %1 = llvm.zext %arg10 : i1 to i2
  %2 = llvm.zext %arg11 : i1 to i2
  %3 = llvm.add %1, %2 overflow<nuw> : i2
  %4 = llvm.ashr %3, %0 : i2
  "llvm.return"(%4) : (i2) -> ()
}
]

def slt_positive_multip_rem_nz_before := [llvm|
{
^0(%arg175 : i8):
  %0 = llvm.mlir.constant(5 : i8) : i8
  %1 = llvm.mlir.constant(21 : i8) : i8
  %2 = llvm.mul %arg175, %0 overflow<nsw> : i8
  %3 = llvm.icmp "slt" %2, %1 : i8
  "llvm.return"(%3) : (i1) -> ()
}
]

def gt_unsigned_to_large_signed_before := [llvm|
{
^0(%arg34 : i8):
  %0 = llvm.mlir.constant(1024 : i32) : i32
  %1 = llvm.zext %arg34 : i8 to i32
  %2 = llvm.icmp "sgt" %1, %0 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

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

def or_trunc_lshr_small_mask_before := [llvm|
{
^0(%arg0 : i8):
  %0 = llvm.mlir.constant(4 : i8) : i8
  %1 = llvm.mlir.constant(-8 : i6) : i6
  %2 = llvm.lshr %arg0, %0 : i8
  %3 = llvm.trunc %2 : i8 to i6
  %4 = llvm.or %3, %1 : i6
  "llvm.return"(%4) : (i6) -> ()
}
]

IO.FS.Stream in Init.System.IO

@[simp_denote]
def add_riscv_i32 :=
  [LV| {
    ^entry (%arg0: i32, %arg1: i32):
    %a = "builtin.unrealized_conversion_cast" (%arg0) : (i32) -> (!i64)
    %b = "builtin.unrealized_conversion_cast" (%arg1) : (i32) -> (!i64)
    %0 = addw %a, %b : !i64
    %1 = "builtin.unrealized_conversion_cast" (%0) : (!i64) -> (i32)
    llvm.return %1 : i32
  }]

def narrow_sext_add_after := [llvm|
{
^0(%arg44 : i16, %arg45 : i32):
  %0 = llvm.trunc %arg45 : i32 to i16
  %1 = llvm.add %arg44, %0 : i16
  "llvm.return"(%1) : (i16) -> ()
}
]

@[simp_denote]
def add_riscv_32 := [LV| {
  ^entry (%lhs: i32, %rhs: i32):
    %lhsr = "builtin.unrealized_conversion_cast" (%lhs) : (i32) -> (!i64)
    %rhsr = "builtin.unrealized_conversion_cast" (%rhs) : (i32) -> (!i64)
    %0 = add %lhsr, %rhsr : !i64
    %1 = "builtin.unrealized_conversion_cast" (%0) : (!i64) -> (i32)
    llvm.return %1 : i32
  }]

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

def test_nsw_dropped_before := [llvm|
{
^0(%arg6 : i32):
  %0 = llvm.mlir.constant(1073741823 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.mlir.constant(2 : i32) : i32
  %3 = llvm.and %arg6, %0 : i32
  %4 = llvm.icmp "eq" %3, %1 : i32
  %5 = llvm.shl %arg6, %2 overflow<nsw> : i32
  %6 = "llvm.select"(%4, %1, %5) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%6) : (i32) -> ()
}
]

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

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

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

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

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

def add_shl_rhs_constant_test : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64),Ty.llvm (.bitvec 64) ] where
  lhs := add_shl_rhs_constant_llvm
  rhs := add_shl_rhs_constant_riscv

def not_add_before := [llvm|
{
^0(%arg124 : i32):
  %0 = llvm.mlir.constant(123 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.add %arg124, %0 : i32
  %3 = llvm.xor %2, %1 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def icmp_power2_and_icmp_shifted_mask_swapped_2147483648_1610612736_before := [llvm|
{
^0(%arg44 : i32):
  %0 = llvm.mlir.constant(-2147483648 : i32) : i32
  %1 = llvm.mlir.constant(1610612736 : i32) : i32
  %2 = llvm.icmp "ult" %arg44, %0 : i32
  %3 = llvm.and %arg44, %1 : i32
  %4 = llvm.icmp "ne" %3, %1 : i32
  %5 = llvm.and %4, %2 : i1
  "llvm.return"(%5) : (i1) -> ()
}
]

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

def sdiv_mul_shl_nsw_before := [llvm|
{
^0(%arg193 : i5, %arg194 : i5, %arg195 : i5):
  %0 = llvm.mul %arg193, %arg194 overflow<nsw> : i5
  %1 = llvm.shl %arg193, %arg195 overflow<nsw> : i5
  %2 = llvm.sdiv %0, %1 : i5
  "llvm.return"(%2) : (i5) -> ()
}
]

def sub_dec_before := [llvm|
{
^0(%arg4 : i8, %arg5 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.add %arg4, %0 : i8
  %2 = llvm.sub %1, %arg5 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def sgt_positive_multip_rem_nz_after := [llvm|
{
^0(%arg168 : i8):
  %0 = llvm.mlir.constant(4 : i8) : i8
  %1 = llvm.icmp "sgt" %arg168, %0 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

def negative_not_next_power_of_two_logical_before := [llvm|
{
^0(%arg4 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.mlir.constant(64 : i32) : i32
  %2 = llvm.mlir.constant(256 : i32) : i32
  %3 = llvm.mlir.constant(false) : i1
  %4 = llvm.icmp "sgt" %arg4, %0 : i32
  %5 = llvm.add %arg4, %1 : i32
  %6 = llvm.icmp "ult" %5, %2 : i32
  %7 = "llvm.select"(%4, %6, %3) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%7) : (i1) -> ()
}
]

def test_sdiv_canonicalize_op0_exact_after := [llvm|
{
^0(%arg13 : i32, %arg14 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.sdiv exact %arg13, %arg14 : i32
  %2 = llvm.sub %0, %1 overflow<nsw> : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def test_ult_xor_before := [llvm|
{
^0(%arg36 : i32, %arg37 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.xor %arg36, %0 : i32
  %2 = llvm.xor %1, %arg37 : i32
  %3 = llvm.icmp "ult" %2, %1 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

def simpHide (e : Expr) : Meta.SimpM Meta.Simp.Step := do
  let ctx ← Simp.getContext
  if let some parent := ctx.parent? then
    if parent.isAppOf ``hide then
      trace[LeanMLIR.Elab] "{Lean.crossEmoji}: parent ({parent}) is an application of `hide`"
      return .continue

  let expr ← Meta.mkAppM ``hide #[e]
  let proof ← Meta.mkAppOptM ``eq_hide #[none, e]
  return .done {
    expr := expr
    proof? := some proof
  }

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

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

def const_sub_add_const_after := [llvm|
{
^0(%arg30 : i32):
  %0 = llvm.mlir.constant(10 : i32) : i32
  %1 = llvm.sub %0, %arg30 : i32
  "llvm.return"(%1) : (i32) -> ()
}
]

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

def Deleted.toHom (h : Deleted Γ r Γ') : Γ'.Hom Γ :=
  fun _ v => Hom.delete r (v.castCtxt h)

def icmp_slt_0_or_icmp_sgt_0_i64_fail3_after := [llvm|
{
^0(%arg69 : i64):
  %0 = llvm.mlir.constant(62) : i64
  %1 = llvm.mlir.constant(63) : i64
  %2 = llvm.ashr %arg69, %0 : i64
  %3 = llvm.lshr %arg69, %1 : i64
  %4 = llvm.or %2, %3 : i64
  "llvm.return"(%4) : (i64) -> ()
}
]

@[simp_denote]
def add_shl_sext_riscv := [LV| {
    ^entry (%a: i32):
    %a0 = "builtin.unrealized_conversion_cast" (%a) : (i32) -> (!i64)
    %0 = addi %a0, 3 : !i64
    %1 = sllw %0, %a0 : !i64
    %2 = "builtin.unrealized_conversion_cast" (%1) : (!i64) -> (i64)
    llvm.return %2 : i64
  }]

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

def t1_exact_after := [llvm|
{
^0(%arg9 : i64):
  %0 = llvm.mlir.constant(63) : i64
  %1 = llvm.ashr exact %arg9, %0 : i64
  %2 = llvm.trunc %1 overflow<nsw> : i64 to i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def and_xor_or7_before := [llvm|
{
^0(%arg655 : i64, %arg656 : i64, %arg657 : i64):
  %0 = llvm.mlir.constant(42) : i64
  %1 = llvm.udiv %0, %arg655 : i64
  %2 = llvm.udiv %0, %arg656 : i64
  %3 = llvm.udiv %0, %arg657 : i64
  %4 = llvm.and %1, %2 : i64
  %5 = llvm.xor %3, %4 : i64
  %6 = llvm.or %2, %5 : i64
  "llvm.return"(%6) : (i64) -> ()
}
]

def select_xor_inv_icmp_before := [llvm|
{
^0(%arg266 : i32, %arg267 : i32, %arg268 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.icmp "eq" %arg266, %0 : i32
  %2 = llvm.xor %arg268, %arg266 : i32
  %3 = "llvm.select"(%1, %2, %arg267) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def test2_before := [llvm|
{
^0(%arg0 : i999, %arg1 : i999):
  %0 = llvm.mlir.constant(65280 : i999) : i999
  %1 = llvm.and %arg0, %0 : i999
  %2 = llvm.and %arg1, %0 : i999
  %3 = llvm.icmp "ne" %1, %2 : i999
  "llvm.return"(%3) : (i1) -> ()
}
]

def sge_swap_or_max_commute_before := [llvm|
{
^0(%arg178 : i8, %arg179 : i8):
  %0 = llvm.mlir.constant(127 : i8) : i8
  %1 = llvm.icmp "sle" %arg179, %arg178 : i8
  %2 = llvm.icmp "eq" %arg178, %0 : i8
  %3 = llvm.or %2, %1 : i1
  "llvm.return"(%3) : (i1) -> ()
}
]

Fin.instGetElemFinVal in Init.GetElem

def masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_0_logical_after := [llvm|
{
^0(%arg29 : i32):
  %0 = llvm.mlir.constant(12 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.mlir.constant(3 : i32) : i32
  %3 = llvm.mlir.constant(1 : i32) : i32
  %4 = llvm.and %arg29, %0 : i32
  %5 = llvm.icmp "eq" %4, %1 : i32
  %6 = llvm.and %arg29, %2 : i32
  %7 = llvm.icmp "ne" %6, %3 : i32
  %8 = llvm.or %7, %5 : i1
  "llvm.return"(%8) : (i1) -> ()
}
]

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

def lshr_add_xor_fail_before := [llvm|
{
^0(%arg90 : i8, %arg91 : i8):
  %0 = llvm.mlir.constant(1 : i8) : i8
  %1 = llvm.mlir.constant(123 : i8) : i8
  %2 = llvm.lshr %arg90, %0 : i8
  %3 = llvm.lshr %arg91, %0 : i8
  %4 = llvm.add %3, %1 : i8
  %5 = llvm.xor %2, %4 : i8
  "llvm.return"(%5) : (i8) -> ()
}
]

@[simp_denote]
def add_multiuse_const_riscv_i64 :=
  [LV| {
    ^entry (%x: i64, %y: i64):
    %0 = "li"() {imm = -1 : !i64} : (!i64) -> (!i64)
    %1 = srli %0, 24 : !i64
    %a0 = "builtin.unrealized_conversion_cast" (%x) : (i64) -> (!i64)
    %2 = sub %a0, %1 : !i64
    %a1 = "builtin.unrealized_conversion_cast" (%y) : (i64) -> (!i64)
    %3 = sub %a1, %1 : !i64
    %4 = xor %2, %3 : !i64
    %5 = "builtin.unrealized_conversion_cast" (%4) : (!i64) -> (i64)
    llvm.return %5 : i64
  }]

inductive Term : Type
| var : Nat → Term
 
| zero : Term
 
| negOne : Term
 
| one : Term
 
| ofNat (n : Nat) : Term
 
| and : Term → Term → Term
 
| or : Term → Term → Term
 
| xor : Term → Term → Term
 
| not : Term → Term
 
| add : Term → Term → Term
 
| sub : Term → Term → Term
 
| neg : Term → Term




 
| shiftL : Term → Nat → Term




deriving Repr, Inhabited, Lean.ToExpr

def test4_before := [llvm|
{
^0(%arg97 : i32, %arg98 : i1):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(8 : i32) : i32
  %2 = "llvm.select"(%arg98, %0, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %3 = llvm.urem %arg97, %2 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def samesign_inverted_commute2_after := [llvm|
{
^0(%arg99 : i32, %arg100 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.xor %arg99, %arg100 : i32
  %2 = llvm.icmp "slt" %1, %0 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

def eq_smax4_after := [llvm|
{
^0(%arg57 : i32, %arg58 : i32):
  %0 = llvm.mlir.constant(3 : i32) : i32
  %1 = llvm.add %arg57, %0 : i32
  %2 = llvm.icmp "sge" %1, %arg58 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

def smear_set_bit_after := [llvm|
{
^0(%arg6 : i32):
  %0 = llvm.mlir.constant(24 : i32) : i32
  %1 = llvm.mlir.constant(31 : i32) : i32
  %2 = llvm.shl %arg6, %0 : i32
  %3 = llvm.ashr %2, %1 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def PR42691_1_logical_after := [llvm|
{
^0(%arg342 : i32):
  %0 = llvm.mlir.constant(2147483646 : i32) : i32
  %1 = llvm.icmp "ugt" %arg342, %0 : i32
  "llvm.return"(%1) : (i1) -> ()
}
]

inductive Term {wcard tcard : Nat} (bcard : Nat) (ncard : Nat) (icard : Nat) (pcard : Nat)
  (tctx : Term.Ctx wcard tcard) : TermKind wcard → Type







 
| ofNat (w : WidthExpr wcard) (n : Nat) : Term bcard ncard icard pcard tctx (.bv w)
 
| var (v : Fin tcard) : Term bcard ncard icard pcard tctx (.bv (tctx v))
 
| add (a : Term bcard ncard icard pcard tctx (.bv w))
  (b : Term bcard ncard icard pcard tctx (.bv w)) : Term bcard ncard icard pcard tctx (.bv w)
 
| shiftl (a : Term bcard ncard icard pcard tctx (.bv w)) (k : Nat) : Term bcard ncard icard pcard tctx (.bv w)
 
| bor (a b : Term bcard ncard icard pcard tctx (.bv w)) : Term bcard ncard icard pcard tctx (.bv w)
 
| band (a b : Term bcard ncard icard pcard tctx (.bv w)) : Term bcard ncard icard pcard tctx (.bv w)
 
| bxor (a b : Term bcard ncard icard pcard tctx (.bv w)) : Term bcard ncard icard pcard tctx (.bv w)
 
| bnot (a : Term bcard ncard icard pcard tctx (.bv w)) : Term bcard ncard icard pcard tctx (.bv w)
 
| zext (a : Term bcard ncard icard pcard tctx (.bv w)) (v : WidthExpr wcard) : Term bcard ncard icard pcard tctx (.bv v)
 
| setWidth (a : Term bcard ncard icard pcard tctx (.bv w)) (v : WidthExpr wcard) : Term bcard ncard icard pcard tctx (.bv v)
 
| sext (a : Term bcard ncard icard pcard tctx (.bv w)) (v : WidthExpr wcard) : Term bcard ncard icard pcard tctx (.bv v)
 
| bvOfBool (b : Term bcard ncard icard pcard tctx .bool) : Term bcard ncard icard pcard tctx (.bv (.const 1))

| boolConst (b : Bool) : Term bcard ncard icard pcard tctx .bool
| boolVar (v : Fin bcard) : Term bcard ncard icard pcard tctx .bool
| binWidthRel (k : WidthBinaryRelationKind) (wa wb : WidthExpr wcard) :
    Term bcard ncard icard pcard tctx .prop
| binRel
    (k : BinaryRelationKind)
    (w : WidthExpr wcard)
    (a : Term bcard ncard icard pcard tctx (.bv w))
    (b : Term bcard ncard icard pcard tctx (.bv w)) :
    Term bcard ncard icard pcard tctx .prop
| and (p1 p2 : Term bcard ncard icard pcard tctx (.prop)) : Term bcard ncard icard pcard tctx (.prop)
| or (p1 p2 : Term bcard ncard icard pcard tctx (.prop)) : Term bcard ncard icard pcard tctx (.prop)
| pvar (v : Fin pcard) : Term bcard ncard icard pcard tctx (.prop) 






| boolBinRel
  (k : BoolBinaryRelationKind)
  (a b : Term bcard ncard icard pcard tctx .bool) :
  Term bcard ncard icard pcard tctx (.prop)

def test4_apint_after := [llvm|
{
^0(%arg42 : i61):
  %0 = llvm.mlir.constant(5 : i61) : i61
  %1 = llvm.and %arg42, %0 : i61
  %2 = llvm.xor %1, %0 : i61
  "llvm.return"(%2) : (i61) -> ()
}
]

def Expr.KInductionCircuits.mkMkSafetyCircuit (circs : Expr) : MetaM Expr :=
  mkAppM ``ReflectVerif.BvDecide.KInductionCircuits.mkSafetyCircuit #[circs]

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

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

Lean.withTraceNode in Lean.Util.Trace

def CollectState.mkEnvExpr
    (empty : SolverM Expr)
    (cons : (env : Expr) → (x : Expr) → SolverM Expr)
    (xs : Array Expr) : SolverM Expr := do
  let mut out ← empty
  for x in xs do
    out ← cons out x
    debugCheck out
  debugCheck out
  return out

def shl_and_xor_after := [llvm|
{
^0(%arg158 : i8, %arg159 : i8):
  %0 = llvm.mlir.constant(10 : i8) : i8
  %1 = llvm.mlir.constant(1 : i8) : i8
  %2 = llvm.and %arg158, %0 : i8
  %3 = llvm.xor %arg159, %2 : i8
  %4 = llvm.shl %3, %1 : i8
  "llvm.return"(%4) : (i8) -> ()
}
]

def supp {Γ : Ctxt _} (a : Var Γ (.stream r)) (b : Var Γ (.stream (.bitvec 1))) : Expr (Handshake) Γ .pure (.stream r)  :=
  Expr.mk
    (op := .supp r)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .cons a <| .cons b <| .nil)
    (regArgs := .nil)

def sext_zext_apint1_before := [llvm|
{
^0(%arg86 : i77):
  %0 = llvm.zext %arg86 : i77 to i533
  %1 = llvm.sext %0 : i533 to i1024
  "llvm.return"(%1) : (i1024) -> ()
}
]

def sub_to_xor_or_commuted_after := [llvm|
{
^0(%arg7 : i32, %arg8 : i32):
  %0 = llvm.xor %arg7, %arg8 : i32
  "llvm.return"(%0) : (i32) -> ()
}
]

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

def trunc_shl_shl_var_before := [llvm|
{
^0(%arg14 : i64, %arg15 : i64):
  %0 = llvm.mlir.constant(2) : i64
  %1 = llvm.shl %arg14, %arg15 : i64
  %2 = llvm.shl %1, %0 : i64
  %3 = llvm.trunc %2 : i64 to i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def ROfZComputable_impl (z : ℤ) : R q n :=
  let zq : ZMod q := z
  let p : (ZMod q)[X] := {
      toFinsupp := Finsupp.mk
        (support := List.toFinset (if zq = 0 then  [] else [0]))
        (toFun := fun i => if i = 0 then z else 0)
        (mem_support_toFun := by admit /- proof elided -/
        )
      : (ZMod q)[X]
  }
  R.fromPoly p

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

}]

def substBvEqualitiesTac : TacticM Unit := do
  liftMetaTactic1 substBvEqualities

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

def or_simplify_uge_after := [llvm|
{
^0(%arg15 : i8, %arg16 : i8, %arg17 : i1):
  %0 = llvm.mlir.constant(false) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

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

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

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

@[simp_denote]
def sub {Γ : Ctxt _} (w : ℕ) (l r : Nat)
    (lp : (Γ[l]? = some (InstCombine.MTy.bitvec (ConcreteOrMVar.concrete w)))
      := by admit /- proof elided -/
      )
    (rp : (Γ[r]? = some (InstCombine.MTy.bitvec (ConcreteOrMVar.concrete w)))
      := by admit /- proof elided -/
      ) :
    Expr InstCombine.LLVM Γ .pure (LLVM.Ty.bitvec w) :=
  Expr.mk
    (op := InstCombine.MOp.sub w)
    (eff_le := by admit /- proof elided -/
    )
    (ty_eq := rfl)
    (args := .cons ⟨l, lp⟩ <| .cons ⟨r, rp⟩ .nil)
    (regArgs := .nil)

def PR42691_9_after := [llvm|
{
^0(%arg327 : i32):
  %0 = llvm.mlir.constant(-14 : i32) : i32
  %1 = llvm.mlir.constant(2147483633 : i32) : i32
  %2 = llvm.add %arg327, %0 : i32
  %3 = llvm.icmp "ult" %2, %1 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

def VarList (Γ : Context Ty) (tys : List Ty) : Type :=
  { vs : List VarName // vs.length = tys.length ∧ ∀ v ∈ vs.zip tys, Γ.hasType v.fst v.snd }

def and_orn_xor_commute8_after := [llvm|
{
^0(%arg66 : i32, %arg67 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.mul %arg66, %arg66 : i32
  %2 = llvm.mul %arg67, %arg67 : i32
  %3 = llvm.xor %1, %0 : i32
  %4 = llvm.and %2, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def xor_ashr_not_after := [llvm|
{
^0(%arg27 : i8, %arg28 : i8, %arg29 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.xor %arg28, %arg27 : i8
  %2 = llvm.ashr %1, %arg29 : i8
  %3 = llvm.xor %2, %0 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

@[simp_denote]
def llvm_sub_32 := [LV| {
  ^entry (%x: i32, %y: i32):
    %1 = llvm.sub %x, %y : i32
    llvm.return %1 : i32
  }]

def not_and_and_or_no_or_commute2_before := [llvm|
{
^0(%arg151 : i32, %arg152 : i32, %arg153 : i32):
  %0 = llvm.mlir.constant(42 : i32) : i32
  %1 = llvm.mlir.constant(-1 : i32) : i32
  %2 = llvm.sdiv %0, %arg152 : i32
  %3 = llvm.or %2, %arg151 : i32
  %4 = llvm.xor %3, %1 : i32
  %5 = llvm.xor %arg151, %1 : i32
  %6 = llvm.and %2, %5 : i32
  %7 = llvm.and %6, %arg153 : i32
  %8 = llvm.or %7, %4 : i32
  "llvm.return"(%8) : (i32) -> ()
}
]

def sub_from_constant_commute_before := [llvm|
{
^0(%arg4 : i5, %arg5 : i5):
  %0 = llvm.mlir.constant(10 : i5) : i5
  %1 = llvm.mul %arg5, %arg5 : i5
  %2 = llvm.sub %0, %arg4 overflow<nsw> : i5
  %3 = llvm.add %1, %2 overflow<nsw> : i5
  "llvm.return"(%3) : (i5) -> ()
}
]

def APlusBMinusCPlusA : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 64), Ty.llvm (.bitvec 64), Ty.llvm (.bitvec 64)] where
  lhs := [LV| {
    ^entry (%a: i64, %b: i64, %c: i64):
      %0 = llvm.add %c, %a : i64
      %1 = llvm.sub %b, %0 : i64
      %2 = llvm.add %a, %1 : i64
      llvm.return %2 : i64
  }]
  rhs := [LV| {
    ^entry (%a: i64, %b: i64, %c: i64):
      %0 = llvm.sub %b, %c : i64
      llvm.return %0 : i64
  }]

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

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

def flip_add_of_shift_neg_before := [llvm|
{
^0(%arg12 : i8, %arg13 : i8, %arg14 : i8):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.sub %0, %arg12 : i8
  %2 = llvm.shl %1, %arg13 overflow<nsw,nuw> : i8
  %3 = llvm.add %2, %arg14 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def test3_before := [llvm|
{
^0(%arg307 : i1):
  %0 = llvm.mlir.constant(false) : i1
  %1 = llvm.and %arg307, %0 : i1
  "llvm.return"(%1) : (i1) -> ()
}
]

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

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

def sub_from_constant_commute_before := [llvm|
{
^0(%arg4 : i5, %arg5 : i5):
  %0 = llvm.mlir.constant(10 : i5) : i5
  %1 = llvm.mul %arg5, %arg5 : i5
  %2 = llvm.sub %0, %arg4 overflow<nsw> : i5
  %3 = llvm.add %1, %2 overflow<nsw> : i5
  "llvm.return"(%3) : (i5) -> ()
}
]

def bitwise_or_bitwise_or_icmps_comm3_after := [llvm|
{
^0(%arg187 : i8, %arg188 : i8, %arg189 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.mlir.constant(1 : i8) : i8
  %2 = llvm.icmp "eq" %arg188, %0 : i8
  %3 = llvm.shl %1, %arg189 overflow<nuw> : i8
  %4 = llvm.or %3, %1 : i8
  %5 = llvm.and %arg187, %4 : i8
  %6 = llvm.icmp "ne" %5, %4 : i8
  %7 = llvm.or %6, %2 : i1
  "llvm.return"(%7) : (i1) -> ()
}
]

def or_and_not_constant_commute2_after := [llvm|
{
^0(%arg108 : i32, %arg109 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.and %arg108, %0 : i32
  %2 = llvm.or %1, %arg109 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def not_not_cmp_after := [llvm|
{
^0(%arg147 : i32, %arg148 : i32):
  %0 = llvm.icmp "sgt" %arg147, %arg148 : i32
  "llvm.return"(%0) : (i1) -> ()
}
]

def eq_basic_before := [llvm|
{
^0(%arg34 : i8, %arg35 : i8):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.icmp "eq" %arg34, %0 : i8
  %2 = llvm.icmp "ugt" %arg34, %arg35 : i8
  %3 = llvm.or %1, %2 : i1
  "llvm.return"(%3) : (i1) -> ()
}
]

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

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

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

def ule_swap_or_not_min_logical_after := [llvm|
{
^0(%arg262 : i8, %arg263 : i8):
  %0 = llvm.mlir.constant(true) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def or_and_not_not_commute7_before := [llvm|
{
^0(%arg404 : i32, %arg405 : i32, %arg406 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.or %arg404, %arg405 : i32
  %2 = llvm.xor %1, %0 : i32
  %3 = llvm.or %arg406, %arg404 : i32
  %4 = llvm.xor %3, %0 : i32
  %5 = llvm.and %4, %arg405 : i32
  %6 = llvm.or %5, %2 : i32
  "llvm.return"(%6) : (i32) -> ()
}
]

def xor_logic_and_logic_or4_before := [llvm|
{
^0(%arg45 : i1, %arg46 : i1, %arg47 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.mlir.constant(false) : i1
  %2 = "llvm.select"(%arg45, %0, %arg47) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %3 = "llvm.select"(%arg46, %arg45, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  %4 = llvm.xor %3, %2 : i1
  "llvm.return"(%4) : (i1) -> ()
}
]

def scalar_i32_shl_ult_const_before := [llvm|
{
^0(%arg15 : i32):
  %0 = llvm.mlir.constant(11 : i32) : i32
  %1 = llvm.mlir.constant(131072 : i32) : i32
  %2 = llvm.shl %arg15, %0 : i32
  %3 = llvm.icmp "ult" %2, %1 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

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

def icmp_eq_mul_nsw_nonequal_commuted_before := [llvm|
{
^0(%arg30 : i8, %arg31 : i8):
  %0 = llvm.mlir.constant(1 : i8) : i8
  %1 = llvm.add %arg30, %0 : i8
  %2 = llvm.mul %arg30, %arg31 overflow<nsw> : i8
  %3 = llvm.mul %arg31, %1 overflow<nsw> : i8
  %4 = llvm.icmp "eq" %2, %3 : i8
  "llvm.return"(%4) : (i1) -> ()
}
]

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

def uge_or_not_max_commute_logical_after := [llvm|
{
^0(%arg298 : i8, %arg299 : i8):
  %0 = llvm.mlir.constant(true) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

def lshr_C1_add_A_C2_i32_before := [llvm|
{
^0(%arg6 : i32):
  %0 = llvm.mlir.constant(65535 : i32) : i32
  %1 = llvm.mlir.constant(5 : i32) : i32
  %2 = llvm.mlir.constant(6 : i32) : i32
  %3 = llvm.and %arg6, %0 : i32
  %4 = llvm.add %3, %1 : i32
  %5 = llvm.shl %2, %4 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def lshr_32_add_zext_basic_multiuse_after := [llvm|
{
^0(%arg23 : i32, %arg24 : i32):
  %0 = llvm.mlir.constant(32) : i64
  %1 = llvm.zext %arg23 : i32 to i64
  %2 = llvm.zext %arg24 : i32 to i64
  %3 = llvm.add %1, %2 overflow<nsw,nuw> : i64
  %4 = llvm.lshr %3, %0 : i64
  %5 = llvm.or %4, %2 : i64
  "llvm.return"(%5) : (i64) -> ()
}
]

def test23_before := [llvm|
{
^0(%arg8 : i44):
  %0 = llvm.mlir.constant(33 : i44) : i44
  %1 = llvm.shl %arg8, %0 : i44
  %2 = llvm.ashr %1, %0 : i44
  %3 = llvm.trunc %2 : i44 to i11
  "llvm.return"(%3) : (i11) -> ()
}
]

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

def match_unsigned_before := [llvm|
{
^0(%arg18 : i64):
  %0 = llvm.mlir.constant(299) : i64
  %1 = llvm.mlir.constant(64) : i64
  %2 = llvm.urem %arg18, %0 : i64
  %3 = llvm.udiv %arg18, %0 : i64
  %4 = llvm.urem %3, %1 : i64
  %5 = llvm.mul %4, %0 : i64
  %6 = llvm.add %2, %5 : i64
  "llvm.return"(%6) : (i64) -> ()
}
]

def shl_and_xor_after := [llvm|
{
^0(%arg158 : i8, %arg159 : i8):
  %0 = llvm.mlir.constant(10 : i8) : i8
  %1 = llvm.mlir.constant(1 : i8) : i8
  %2 = llvm.and %arg158, %0 : i8
  %3 = llvm.xor %arg159, %2 : i8
  %4 = llvm.shl %3, %1 : i8
  "llvm.return"(%4) : (i8) -> ()
}
]

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

def test24_before := [llvm|
{
^0(%arg183 : i32, %arg184 : i32):
  %0 = llvm.xor %arg184, %arg183 : i32
  %1 = llvm.icmp "ne" %0, %arg183 : i32
  "llvm.return"(%1) : (i1) -> ()
}
]

structure ParsedFpExpr where
  width : Nat
  bvExpr: FpExpr width
  symVars: Std.HashMap Nat BVExpr.PackedBitVec
  inputVars : Std.HashMap Nat HydraVariable

def test23_after := [llvm|
{
^0(%arg185 : i32, %arg186 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.icmp "eq" %arg186, %0 : i32
  "llvm.return"(%1) : (i1) -> ()
}
]

inductive Op
| add (w : Nat) (arity : Nat)
| and (w : Nat) (arity : Nat)

| divs (w : Nat)
| divu (w : Nat)
| extract (w : Nat) (n : Nat)
| icmp (p : String) (w : Nat)
| mods (w : Nat)
| modu (w : Nat)
| mul (w : Nat) (arity : Nat)
| mux (w : Nat)
| or (w : Nat) (arity : Nat)
| parity (w : Nat)
| replicate (w : Nat) (n : Nat)
| shl (w : Nat)
| shlPar (w n : Nat)
| shrs (w : Nat)
| shru (w : Nat)
| sub (w : Nat)
| xor (w : Nat) (arity : Nat)
deriving DecidableEq, Repr, ToExpr

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

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

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

def or_not_xor_common_op_commute3_before := [llvm|
{
^0(%arg98 : i8, %arg99 : i8, %arg100 : i8):
  %0 = llvm.mlir.constant(0 : i8) : i8
  %1 = llvm.mlir.constant(-1 : i8) : i8
  %2 = llvm.sub %0, %arg100 : i8
  %3 = llvm.xor %arg98, %1 : i8
  %4 = llvm.xor %arg98, %arg99 : i8
  %5 = llvm.or %2, %3 : i8
  %6 = llvm.or %5, %4 : i8
  "llvm.return"(%6) : (i8) -> ()
}
]

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

@[simp_denote]
def andi_llvm := [LV| {
    ^entry (%a: i16):
    %0 = llvm.mlir.constant (6) : i16
    %1 = llvm.and %a, %0 : i16
    llvm.return %1 :i16
  }]

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

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

def demorgan_nand_after := [llvm|
{
^0(%arg38 : i8, %arg39 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.xor %arg39, %0 : i8
  %2 = llvm.or %arg38, %1 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def neg_not_signbit3_before := [llvm|
{
^0(%arg3 : i8):
  %0 = llvm.mlir.constant(7 : i8) : i8
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.ashr %arg3, %0 : i8
  %3 = llvm.zext %2 : i8 to i32
  %4 = llvm.sub %1, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def test88_before := [llvm|
{
^0(%arg57 : i16):
  %0 = llvm.mlir.constant(18 : i32) : i32
  %1 = llvm.sext %arg57 : i16 to i32
  %2 = llvm.ashr %1, %0 : i32
  %3 = llvm.trunc %2 : i32 to i16
  "llvm.return"(%3) : (i16) -> ()
}
]

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

def n1_before := [llvm|
{
^0(%arg7 : i8, %arg8 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.mlir.constant(1 : i8) : i8
  %2 = llvm.shl %0, %arg8 : i8
  %3 = llvm.xor %2, %1 : i8
  %4 = llvm.icmp "uge" %3, %arg7 : i8
  "llvm.return"(%4) : (i1) -> ()
}
]

def logical_and_icmps1_after := [llvm|
{
^0(%arg36 : i32, %arg37 : i1):
  %0 = llvm.mlir.constant(10086 : i32) : i32
  %1 = llvm.mlir.constant(false) : i1
  %2 = llvm.icmp "ult" %arg36, %0 : i32
  %3 = "llvm.select"(%arg37, %2, %1) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%3) : (i1) -> ()
}
]

def t1_sshr_after := [llvm|
{
^0(%arg28 : i32, %arg29 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.shl %0, %arg29 overflow<nsw> : i32
  %2 = llvm.and %1, %arg28 : i32
  %3 = llvm.ashr exact %2, %arg29 : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def and_or_hoist_mask_after := [llvm|
{
^0(%arg91 : i8, %arg92 : i8):
  %0 = llvm.mlir.constant(6 : i8) : i8
  %1 = llvm.mlir.constant(3 : i8) : i8
  %2 = llvm.lshr %arg91, %0 : i8
  %3 = llvm.and %arg92, %1 : i8
  %4 = llvm.or %2, %3 : i8
  "llvm.return"(%4) : (i8) -> ()
}
]

def not_true_not_before := [llvm|
{
^0(%arg234 : i1, %arg235 : i1):
  %0 = llvm.mlir.constant(true) : i1
  %1 = llvm.xor %arg234, %0 : i1
  %2 = llvm.xor %arg235, %0 : i1
  %3 = "llvm.select"(%1, %0, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%3) : (i1) -> ()
}
]

instance : DialectPrint Ex where
  printOpName
  | .add    => "add"
  | .beq    => "beq"
  | .cst _  => "cst"
  printAttributes
  | .cst v => s!"\{value = {v}}"
  | _ => ""
  printTy
  | .nat => "nat"
  | .bool => "bool"
  dialectName := "ex"
  printReturn _ := "return"
  printFunc _ := "^entry"

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

def xor_nosignbit_select_ashr_after := [llvm|
{
^0(%arg4 : i32, %arg5 : i1):
  %0 = llvm.mlir.constant(8 : i32) : i32
  %1 = llvm.mlir.constant(8388352 : i32) : i32
  %2 = llvm.ashr %arg4, %0 : i32
  %3 = llvm.xor %2, %1 : i32
  %4 = "llvm.select"(%arg5, %3, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def srl_match : List (Σ Γ, Σ ty, PeepholeRewrite LLVMPlusRiscV Γ ty) := [
  
  
  mkRewrite (LLVMToRiscvPeepholeRewriteRefine.toPeepholeUNSOUND llvm_srl_lower_riscv_exact_64),
  mkRewrite (LLVMToRiscvPeepholeRewriteRefine.toPeepholeUNSOUND llvm_srl_lower_riscv_64),
]

def p_after := [llvm|
{
^0(%arg60 : i32, %arg61 : i32, %arg62 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.and %arg60, %arg62 : i32
  %2 = llvm.xor %arg62, %0 : i32
  %3 = llvm.and %arg61, %2 : i32
  %4 = llvm.or disjoint %1, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def merge {Γ : Ctxt _} (a b : Var Γ (.stream r)) : Expr (Handshake) Γ .pure (.stream r)  :=
  Expr.mk
    (op := .merge r)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .cons a <| .cons b <| .nil)
    (regArgs := .nil)

def urem_common_divisor_before := [llvm|
{
^0(%arg61 : i1, %arg62 : i5, %arg63 : i5, %arg64 : i5):
  %0 = llvm.urem %arg63, %arg62 : i5
  %1 = llvm.urem %arg64, %arg62 : i5
  %2 = "llvm.select"(%arg61, %1, %0) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i5, i5) -> i5
  "llvm.return"(%2) : (i5) -> ()
}
]

def and_zext_zext_before := [llvm|
{
^0(%arg58 : i8, %arg59 : i4):
  %0 = llvm.zext %arg58 : i8 to i16
  %1 = llvm.zext %arg59 : i4 to i16
  %2 = llvm.and %0, %1 : i16
  "llvm.return"(%2) : (i16) -> ()
}
]

def and_ne_with_one_bit_diff_constants1_before := [llvm|
{
^0(%arg364 : i32):
  %0 = llvm.mlir.constant(51 : i32) : i32
  %1 = llvm.mlir.constant(50 : i32) : i32
  %2 = llvm.icmp "ne" %arg364, %0 : i32
  %3 = llvm.icmp "ne" %arg364, %1 : i32
  %4 = llvm.and %2, %3 : i1
  "llvm.return"(%4) : (i1) -> ()
}
]

def ripple_no_nsw2_after := [llvm|
{
^0(%arg9 : i16, %arg10 : i16):
  %0 = llvm.mlir.constant(1 : i16) : i16
  %1 = llvm.mlir.constant(32767 : i16) : i16
  %2 = llvm.and %arg10, %0 : i16
  %3 = llvm.and %arg9, %1 : i16
  %4 = llvm.add %2, %3 overflow<nuw> : i16
  "llvm.return"(%4) : (i16) -> ()
}
]

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

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

def mul_add_to_mul_6_before := [llvm|
{
^0(%arg26 : i32, %arg27 : i32):
  %0 = llvm.mlir.constant(5 : i32) : i32
  %1 = llvm.mul %arg26, %arg27 overflow<nsw> : i32
  %2 = llvm.mul %1, %0 overflow<nsw> : i32
  %3 = llvm.add %1, %2 overflow<nsw> : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

def test4_before := [llvm|
{
^0(%arg8 : i49):
  %0 = llvm.mlir.constant(-2 : i49) : i49
  %1 = llvm.mlir.constant(1 : i49) : i49
  %2 = llvm.and %arg8, %0 : i49
  %3 = llvm.add %2, %1 : i49
  "llvm.return"(%3) : (i49) -> ()
}
]

def sub_inc_before := [llvm|
{
^0(%arg10 : i8, %arg11 : i8):
  %0 = llvm.mlir.constant(1 : i8) : i8
  %1 = llvm.add %arg10, %0 : i8
  %2 = llvm.sub %arg11, %1 : i8
  "llvm.return"(%2) : (i8) -> ()
}
]

def not_cond_after := [llvm|
{
^0(%arg24 : i1, %arg25 : i32, %arg26 : i32):
  %0 = "llvm.select"(%arg24, %arg26, %arg25) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%0) : (i32) -> ()
}
]

def sext_zext_apint2_after := [llvm|
{
^0(%arg85 : i11):
  %0 = llvm.zext %arg85 : i11 to i47
  "llvm.return"(%0) : (i47) -> ()
}
]

instance instTransformTy : MLIR.AST.TransformTy DCPlus 0 where
  mkTy := mkTy

def src_before := [llvm|
{
^0(%arg16 : i32, %arg17 : i32):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.and %arg17, %arg16 : i32
  %2 = llvm.or %arg17, %arg16 : i32
  %3 = llvm.xor %2, %0 : i32
  %4 = llvm.add %1, %3 : i32
  "llvm.return"(%4) : (i32) -> ()
}
]

def sub_from_constant_of_sub_from_constant_before := [llvm|
{
^0(%arg170 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.mlir.constant(11 : i8) : i8
  %2 = llvm.sub %0, %arg170 : i8
  %3 = llvm.sub %1, %2 : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

def unCons (d : Diff (Γ₁.cons t) Γ₂) : Diff Γ₁ Γ₂ :=
  ⟨d.val + 1, by admit /- proof elided -/
  ⟩

def trunc_lshr_exact_mask_before := [llvm|
{
^0(%arg9 : i8):
  %0 = llvm.mlir.constant(2 : i8) : i8
  %1 = llvm.mlir.constant(15 : i6) : i6
  %2 = llvm.lshr %arg9, %0 : i8
  %3 = llvm.trunc %2 : i8 to i6
  %4 = llvm.and %3, %1 : i6
  "llvm.return"(%4) : (i6) -> ()
}
]

def sle_swap_or_not_min_after := [llvm|
{
^0(%arg280 : i8, %arg281 : i8):
  %0 = llvm.mlir.constant(true) : i1
  "llvm.return"(%0) : (i1) -> ()
}
]

class DecidableNFA' (M : NFA' α) [Fintype M.σ] [DecidableEq M.σ] [DecidableNFA M.M]

def matchArg [DecidableEq d.Op]
    (lets : Lets d Γ_in eff Γ_out) (matchLets : Lets d Δ_in .pure Δ_out) :
    {l : List d.Ty} → HVector (Var Γ_out) l → HVector (Var Δ_out) l →
    MatchVar Δ_in Γ_out
  | _, .nil, .nil => return
  | t::l, .cons vₗ vsₗ, .cons vᵣ vsᵣ => do
      matchVar (t := t) lets vₗ matchLets vᵣ
      matchArg lets matchLets vsₗ vsᵣ
  termination_by l => (sizeOf matchLets, l.length + 1)

def ult_rem_zero_nsw_after := [llvm|
{
^0(%arg173 : i8):
  %0 = llvm.mlir.constant(3 : i8) : i8
  %1 = llvm.icmp "ult" %arg173, %0 : i8
  "llvm.return"(%1) : (i1) -> ()
}
]

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

def alive_AddSub_1295_src :=
[sllvm| {
^bb0(%a : i64, %b : i64):
  %v1 = llvm.and %a, %b : i64
  %v2 = llvm.xor %a, %b : i64
  %v3 = llvm.add %v1, %v2 : i64
  llvm.return %v3 : i64
}]

def trunc_sandwich_small_shift1_before := [llvm|
{
^0(%arg67 : i32):
  %0 = llvm.mlir.constant(19 : i32) : i32
  %1 = llvm.mlir.constant(1 : i12) : i12
  %2 = llvm.lshr %arg67, %0 : i32
  %3 = llvm.trunc %2 : i32 to i12
  %4 = llvm.lshr %3, %1 : i12
  "llvm.return"(%4) : (i12) -> ()
}
]

def absdiff_before := [llvm|
{
^0(%arg4 : i64, %arg5 : i64):
  %0 = llvm.icmp "ult" %arg4, %arg5 : i64
  %1 = llvm.sext %0 : i1 to i64
  %2 = llvm.sub %arg4, %arg5 : i64
  %3 = llvm.xor %1, %2 : i64
  %4 = llvm.sub %3, %1 : i64
  "llvm.return"(%4) : (i64) -> ()
}
]

def positive_biggerashr_shlnsw_ashrexact_before := [llvm|
{
^0(%arg35 : i8):
  %0 = llvm.mlir.constant(6 : i8) : i8
  %1 = llvm.mlir.constant(3 : i8) : i8
  %2 = llvm.ashr exact %arg35, %0 : i8
  %3 = llvm.shl %2, %1 overflow<nsw> : i8
  "llvm.return"(%3) : (i8) -> ()
}
]

noncomputable def TV_mul_one_rhs : PeepholeRewrite (ModArith q) [.modLike] .modLike :=
{
  lhs := test_mul_one_rhs_LHS,
  rhs := test_mul_one_rhs_RHS,
  correct := by admit /- proof elided -/

def logical_or_bitwise_or_icmps_after := [llvm|
{
^0(%arg172 : i8, %arg173 : i8, %arg174 : i8):
  %0 = llvm.mlir.constant(42 : i8) : i8
  %1 = llvm.mlir.constant(1 : i8) : i8
  %2 = llvm.mlir.constant(0 : i8) : i8
  %3 = llvm.mlir.constant(true) : i1
  %4 = llvm.icmp "eq" %arg173, %0 : i8
  %5 = llvm.and %arg172, %1 : i8
  %6 = llvm.shl %1, %arg174 overflow<nuw> : i8
  %7 = llvm.and %arg172, %6 : i8
  %8 = llvm.icmp "eq" %5, %2 : i8
  %9 = llvm.icmp "eq" %7, %2 : i8
  %10 = llvm.or %4, %8 : i1
  %11 = "llvm.select"(%10, %3, %9) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i1, i1) -> i1
  "llvm.return"(%11) : (i1) -> ()
}
]

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

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

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

@[simp_denote]
def andi_riscv_i32 :=
  [LV| {
    ^entry (%arg: i32):
    %a = "builtin.unrealized_conversion_cast" (%arg) : (i32) -> (!i64)
    %0 = andi %a, 6 : !i64
    %1 = "builtin.unrealized_conversion_cast" (%0) : (!i64) -> (i32)
    llvm.return %1 : i32
  }]

instance : TyDenote Unit where toType := fun _ => Unit

instance {cmp} : DecidableNFA' (NFA'.autSignedCmp cmp) where

def src_is_mask_xor_after := [llvm|
{
^0(%arg115 : i8, %arg116 : i8):
  %0 = llvm.mlir.constant(-1 : i8) : i8
  %1 = llvm.mlir.constant(123 : i8) : i8
  %2 = llvm.add %arg116, %0 : i8
  %3 = llvm.xor %arg116, %2 : i8
  %4 = llvm.xor %arg115, %1 : i8
  %5 = llvm.icmp "ugt" %4, %3 : i8
  "llvm.return"(%5) : (i1) -> ()
}
]

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

def positive_sameconst_shlnuw_after := [llvm|
{
^0(%arg29 : i32):
  "llvm.return"(%arg29) : (i32) -> ()
}
]

def lowmask_add_2_after := [llvm|
{
^0(%arg144 : i8):
  %0 = llvm.mlir.constant(63 : i8) : i8
  %1 = llvm.and %arg144, %0 : i8
  "llvm.return"(%1) : (i8) -> ()
}
]

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

def test44_after := [llvm|
{
^0(%arg144 : i8):
  %0 = llvm.mlir.constant(1234 : i16) : i16
  %1 = llvm.zext %arg144 : i8 to i16
  %2 = llvm.or %1, %0 : i16
  %3 = llvm.zext nneg %2 : i16 to i64
  "llvm.return"(%3) : (i64) -> ()
}
]

def select_icmp_ne_pow2_before := [llvm|
{
^0(%arg10 : i8):
  %0 = llvm.mlir.constant(4 : i8) : i8
  %1 = llvm.mlir.constant(0 : i8) : i8
  %2 = llvm.and %arg10, %0 : i8
  %3 = llvm.icmp "ne" %2, %1 : i8
  %4 = llvm.xor %arg10, %0 : i8
  %5 = "llvm.select"(%3, %4, %arg10) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i8, i8) -> i8
  "llvm.return"(%5) : (i8) -> ()
}
]

def sink {Γ : Ctxt _} (a : Γ.Var (MLIR2DCPlus.Ty.tokenstream)) : Expr (DCPlus) Γ .pure (.tokenstream) :=
  Expr.mk
    (op := .sink)
    (ty_eq := rfl)
    (eff_le := by admit /- proof elided -/
    )
    (args := .cons a <| .nil)
    (regArgs := .nil)

@[simp_denote]
def add_multiuse_const_llvm_i64 := [LV| {
    ^entry (%x: i64, %y: i64):
    %0 = llvm.mlir.constant (-1099511627775) : i64
    %1 = llvm.add %x, %0 : i64
    %2 = llvm.add %y, %0 : i64
    %3 = llvm.xor %1, %2 : i64
    llvm.return %3 : i64
  }]

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

def sge_smin2_before := [llvm|
{
^0(%arg77 : i32, %arg78 : i32):
  %0 = llvm.icmp "slt" %arg78, %arg77 : i32
  %1 = "llvm.select"(%0, %arg78, %arg77) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %2 = llvm.icmp "sge" %1, %arg77 : i32
  "llvm.return"(%2) : (i1) -> ()
}
]

inductive Op
|   add_int
|   const_ix (v: Index)
|   sub_int
|   map1d
|   extract1d
deriving DecidableEq

def cmpeq_xor_cst3_before := [llvm|
{
^0(%arg22 : i32, %arg23 : i32):
  %0 = llvm.mlir.constant(10 : i32) : i32
  %1 = llvm.xor %arg22, %0 : i32
  %2 = llvm.xor %arg23, %0 : i32
  %3 = llvm.icmp "eq" %1, %2 : i32
  "llvm.return"(%3) : (i1) -> ()
}
]

def test_sub_nsw__nsw_is_safe_after := [llvm|
{
^0(%arg21 : i32):
  %0 = llvm.mlir.constant(-2147483648 : i32) : i32
  %1 = llvm.or %arg21, %0 : i32
  %2 = llvm.sub %0, %1 overflow<nsw> : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def p15_commutativity2_before := [llvm|
{
^0(%arg24 : i32, %arg25 : i32):
  %0 = llvm.mlir.constant(65536 : i32) : i32
  %1 = llvm.mlir.constant(42 : i32) : i32
  %2 = llvm.mlir.constant(65535 : i32) : i32
  %3 = llvm.icmp "ult" %arg24, %0 : i32
  %4 = "llvm.select"(%3, %1, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%4) : (i32) -> ()
}
]

@[simp_denote]
def trunc_riscv_32_to_16 := [LV| {
  ^entry (%lhs: i32):
    %lhsr = "builtin.unrealized_conversion_cast"(%lhs) : (i32) -> (!i64)
    %0= "builtin.unrealized_conversion_cast"(%lhsr) : (!i64) -> (i16)
    llvm.return %0 : i16
  }]

def icmp_x_slt_0_and_icmp_y_ne_neg2_i32_fail_before := [llvm|
{
^0(%arg42 : i32, %arg43 : i32):
  %0 = llvm.mlir.constant(-2 : i32) : i32
  %1 = llvm.mlir.constant(31 : i32) : i32
  %2 = llvm.icmp "ne" %arg42, %0 : i32
  %3 = llvm.zext %2 : i1 to i32
  %4 = llvm.lshr %arg43, %1 : i32
  %5 = llvm.and %4, %3 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

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

def test1_before := [llvm|
{
^0(%arg10 : i32, %arg11 : i32):
  %0 = llvm.mlir.constant(7 : i32) : i32
  %1 = llvm.mlir.constant(8 : i32) : i32
  %2 = llvm.and %arg10, %0 : i32
  %3 = llvm.and %arg11, %1 : i32
  %4 = llvm.or %2, %3 : i32
  %5 = llvm.and %4, %0 : i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def narrow_sext_or_after := [llvm|
{
^0(%arg52 : i16, %arg53 : i32):
  %0 = llvm.trunc %arg53 : i32 to i16
  %1 = llvm.or %arg52, %0 : i16
  "llvm.return"(%1) : (i16) -> ()
}
]

@[simp_denote]
def and_llvm_i16:= [LV| {
    ^entry (%a: i16,%b: i16 ):
    %0 = llvm.and %a, %b : i16
    llvm.return %0 :i16
  }]

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

def shl_sub_i64_after := [llvm|
{
^0(%arg15 : i64):
  %0 = llvm.mlir.constant(-9223372036854775808) : i64
  %1 = llvm.lshr exact %0, %arg15 : i64
  "llvm.return"(%1) : (i64) -> ()
}
]

def foo1_or_before := [llvm|
{
^0(%arg154 : i32, %arg155 : i32, %arg156 : i32):
  %0 = llvm.mlir.constant(1 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.shl %0, %arg155 : i32
  %3 = llvm.shl %0, %arg156 : i32
  %4 = llvm.and %2, %arg154 : i32
  %5 = llvm.icmp "ne" %4, %1 : i32
  %6 = llvm.and %3, %arg154 : i32
  %7 = llvm.icmp "ne" %6, %1 : i32
  %8 = llvm.and %5, %7 : i1
  "llvm.return"(%8) : (i1) -> ()
}
]

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

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

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

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

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

def trunc_shl_shl_infloop_before := [llvm|
{
^0(%arg35 : i64):
  %0 = llvm.mlir.constant(1) : i64
  %1 = llvm.mlir.constant(2) : i64
  %2 = llvm.shl %arg35, %0 : i64
  %3 = llvm.shl %2, %1 : i64
  %4 = llvm.trunc %3 : i64 to i32
  "llvm.return"(%4) : (i32) -> ()
}
]

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

def t5_ugt_slt_0_after := [llvm|
{
^0(%arg51 : i32, %arg52 : i32, %arg53 : i32):
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.mlir.constant(65535 : i32) : i32
  %2 = llvm.icmp "slt" %arg51, %0 : i32
  %3 = llvm.icmp "sgt" %arg51, %1 : i32
  %4 = "llvm.select"(%2, %arg52, %arg51) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  %5 = "llvm.select"(%3, %arg53, %4) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%5) : (i32) -> ()
}
]

def p4 : PeepholeRewrite ExOp [.nat, .nat] .nat:=
  { lhs := r3, rhs := m, correct :=
    by admit /- proof elided -/

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

def neg_mask2_lshr_after := [llvm|
{
^0(%arg14 : i8):
  %0 = llvm.mlir.constant(3 : i8) : i8
  %1 = llvm.mlir.constant(2 : i8) : i8
  %2 = llvm.mlir.constant(0 : i8) : i8
  %3 = llvm.lshr %arg14, %0 : i8
  %4 = llvm.and %3, %1 : i8
  %5 = llvm.sub %2, %4 overflow<nsw> : i8
  "llvm.return"(%5) : (i8) -> ()
}
]

@[simp_denote]
def urem_riscv: Com  LLVMPlusRiscV ⟨[.llvm (.bitvec 64), .llvm (.bitvec 64)]⟩
  .pure (.llvm (.bitvec 64)) := [LV| {
  ^entry (%reg1: i64, %reg2: i64):
    %0 = "builtin.unrealized_conversion_cast"(%reg1) : (i64) -> (!i64)
    %1 = "builtin.unrealized_conversion_cast"(%reg2) : (i64) -> (!i64)
    %2 = remu %0, %1 : !i64
    %3 = "builtin.unrealized_conversion_cast"(%2) : (!i64) -> (i64)
    llvm.return %3 : i64
  }]

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 test15g_before := [llvm|
{
^0(%arg21 : i32):
  %0 = llvm.mlir.constant(8 : i32) : i32
  %1 = llvm.mlir.constant(0 : i32) : i32
  %2 = llvm.mlir.constant(-1 : i32) : i32
  %3 = llvm.mlir.constant(-9 : i32) : i32
  %4 = llvm.and %arg21, %0 : i32
  %5 = llvm.icmp "ne" %4, %1 : i32
  %6 = "llvm.select"(%5, %2, %3) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%6) : (i32) -> ()
}
]

inductive Ty
| int
deriving DecidableEq, Repr

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

def and : FSM Bool :=
  { α := Empty,
    initCarry := Empty.elim,
    nextStateCirc := fun a => a.elim,
    outputCirc := Circuit.var true (inr true) &&& Circuit.var true (inr false),
  }

def and_to_xor2_after := [llvm|
{
^0(%arg117 : i32, %arg118 : i32):
  %0 = llvm.xor %arg117, %arg118 : i32
  "llvm.return"(%0) : (i32) -> ()
}
]

def mkReturn (Γ : Ctxt Comb.Ty) (opStx : MLIR.AST.Op 0) :
   MLIR.AST.ReaderM Comb (Σ eff ty, Com Comb Γ eff ty) := do
  if opStx.name ≠ "return" then
    throw <| .generic s!"Tried to build return out of non-return statement {opStx.name}"
  else
    let args ← (← opStx.parseArgs Γ).assumeArity 1
    let ⟨ty, v⟩ := args[0]
    return ⟨.pure, ty, Com.ret v⟩

def shl_sub_lshr_before := [llvm|
{
^0(%arg139 : i32, %arg140 : i32, %arg141 : i32):
  %0 = llvm.shl %arg139, %arg140 overflow<nuw> : i32
  %1 = llvm.sub %0, %arg141 overflow<nsw,nuw> : i32
  %2 = llvm.lshr exact %1, %arg140 : i32
  "llvm.return"(%2) : (i32) -> ()
}
]

def xor_nosignbit_select_lshr_after := [llvm|
{
^0(%arg20 : i32, %arg21 : i1):
  %0 = llvm.mlir.constant(8 : i32) : i32
  %1 = llvm.mlir.constant(8388352 : i32) : i32
  %2 = llvm.lshr %arg20, %0 : i32
  %3 = llvm.xor %2, %1 : i32
  %4 = "llvm.select"(%arg21, %3, %2) <{"fastmathFlags" = #llvm.fastmath<none>}> : (i1, i32, i32) -> i32
  "llvm.return"(%4) : (i32) -> ()
}
]

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

inductive Op
| add

| constIx (v: Nat) | constTensor (t : Tensor2d' Int) | constInt (v : Int)
| sub
| map2d
| fill2d
| extract2d

def test43_after := [llvm|
{
^0(%arg145 : i8):
  %0 = llvm.mlir.constant(-1 : i32) : i32
  %1 = llvm.zext %arg145 : i8 to i32
  %2 = llvm.add %1, %0 overflow<nsw> : i32
  %3 = llvm.sext %2 : i32 to i64
  "llvm.return"(%3) : (i64) -> ()
}
]

def zero_sign_bit2_before := [llvm|
{
^0(%arg29 : i16, %arg30 : i16):
  %0 = llvm.mlir.constant(32767 : i16) : i16
  %1 = llvm.and %arg29, %0 : i16
  %2 = llvm.and %arg30, %0 : i16
  %3 = llvm.add %1, %2 : i16
  "llvm.return"(%3) : (i16) -> ()
}
]

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

def test_sub_nuw_nsw__all_are_safe_after := [llvm|
{
^0(%arg31 : i32):
  %0 = llvm.mlir.constant(255 : i32) : i32
  %1 = llvm.mlir.constant(-254 : i32) : i32
  %2 = llvm.and %arg31, %0 : i32
  %3 = llvm.sub %1, %2 overflow<nsw,nuw> : i32
  "llvm.return"(%3) : (i32) -> ()
}
]

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

def mul9_low_after := [llvm|
{
^0(%arg8 : i9, %arg9 : i9):
  %0 = llvm.mlir.constant(15 : i9) : i9
  %1 = llvm.mlir.constant(4 : i9) : i9
  %2 = llvm.and %arg8, %0 : i9
  %3 = llvm.lshr %arg8, %1 : i9
  %4 = llvm.and %arg9, %0 : i9
  %5 = llvm.lshr %arg9, %1 : i9
  %6 = llvm.mul %5, %2 overflow<nuw> : i9
  %7 = llvm.mul %4, %3 overflow<nuw> : i9
  %8 = llvm.mul %4, %2 overflow<nsw,nuw> : i9
  %9 = llvm.add %6, %7 : i9
  %10 = llvm.shl %9, %1 : i9
  %11 = llvm.add %10, %8 : i9
  "llvm.return"(%11) : (i9) -> ()
}
]

def test5_after := [llvm|
{
^0(%arg19 : i19, %arg20 : i19, %arg21 : i19):
  %0 = llvm.sub %arg21, %arg20 : i19
  %1 = llvm.add %0, %arg19 : i19
  "llvm.return"(%1) : (i19) -> ()
}
]

@[simp_denote]
def sra_llvm_i64 := [LV| {
    ^entry (%a: i64, %b: i64):
    %0 = llvm.ashr %a, %b : i64
    llvm.return %0 : i64
  }]

def select_same_val_self : LLVMPeepholeRewriteRefine 64 [Ty.llvm (.bitvec 1), Ty.llvm (.bitvec 64) ] where
  lhs := [LV| {
    ^entry (%x: i64, %c: i1):
      %0 = llvm.select %c, %x, %x : i64
      llvm.return %0 : i64
  }]
  rhs := [LV| {
    ^entry (%x: i64, %c: i1):
      llvm.return %x : i64
  }]

def Predicate.evalUlt (t₁ t₂ : BitStream) : BitStream := (~~~ (t₁.borrow t₂)).concat true

abbrev MatchVarM (Δ Γ : Ctxt d.Ty) := (StateT (Mapping Δ Γ) Option)

def test4_after := [llvm|
{
^0(%arg8 : i49):
  %0 = llvm.mlir.constant(1 : i49) : i49
  %1 = llvm.or %arg8, %0 : i49
  "llvm.return"(%1) : (i49) -> ()
}
]

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

def lshrult_03_11_before := [llvm|
{
^0(%arg324 : i4):
  %0 = llvm.mlir.constant(3 : i4) : i4
  %1 = llvm.mlir.constant(-5 : i4) : i4
  %2 = llvm.lshr %arg324, %0 : i4
  %3 = llvm.icmp "ult" %2, %1 : i4
  "llvm.return"(%3) : (i1) -> ()
}
]
</all_available_defs>

<all_available_lemmas>
...

@[simp]
theorem pure_liftEffect {eff₁ eff₂ : EffectKind}
    (hle : eff₁ ≤ .pure) [Monad m] (x : eff₁.toMonad m α) :
    (Pure.pure (liftEffect hle x) : eff₂.toMonad m α)
    = liftEffect (by cases hle; constructor) x

@[simp]
theorem eq_of_le_pure {e : EffectKind}
    (he : e ≤ pure) : e = pure

theorem pure_map (f : α → β) (x : pure.toMonad m α) (eff : EffectKind) :
    (Pure.pure (f <$> x : pure.toMonad m _) : eff.toMonad m _) = f <$> (Pure.pure x)

theorem shl_fold_or_disjoint_cnt_proof : shl_fold_or_disjoint_cnt_before ⊑ shl_fold_or_disjoint_cnt_after

theorem test7_proof : test7_before ⊑ test7_after

theorem or_eq_with_one_bit_diff_constants3_logical_proof : or_eq_with_one_bit_diff_constants3_logical_before ⊑ or_eq_with_one_bit_diff_constants3_logical_after

theorem narrow_zext_ashr_keep_trunc_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ¬(True ∧ (signExtend 32 x_1).saddOverflow (signExtend 32 x) = true ∨ 1#32 ≥ ↑32) →
    True ∧ (signExtend 16 x_1).saddOverflow (signExtend 16 x) = true ∨ 1#16 ≥ ↑16 → False

theorem and_and_logic_or_2_thm.extracted_1._4 : ∀ (x x_1 x_2 : BitVec 1),
  x_2 &&& x_1 = 1#1 → ¬x_1 = 1#1 → 1#1 = x_2 &&& x

theorem masked_and_notA_logical_thm (e : IntW 32) :
  select (icmp IntPred.ne (LLVM.and e (const? 32 14)) e) (icmp IntPred.ne (LLVM.and e (const? 32 78)) e)
      (const? 1 0) ⊑
    icmp IntPred.ne (LLVM.and e (const? 32 (-79))) (const? 32 0)

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

@[simp]
theorem Term.toBV_and {wenv : WidthExpr.Env wcard}
    {tctx : Term.Ctx wcard tcard}
    (benv : Term.BoolEnv bcard)
    (tenv : tctx.Env wenv)
    (p1 p2 : Term bcard ncard icard pcard tctx (.prop)) :
  Term.toBV benv nenv ienv penv tenv (.and p1 p2) = (p1.toBV benv nenv ienv penv tenv ∧ p2.toBV benv nenv ienv penv tenv)

theorem test51_thm.extracted_1._3 : ∀ (x : BitVec 64) (x_1 : BitVec 1),
  ¬x_1 = 1#1 → True ∧ (truncate 32 x &&& BitVec.ofInt 32 (-2) &&& zeroExtend 32 (x_1 ^^^ 1#1) != 0) = true → False

theorem corec₂_eq_val (x : Stream α):
  (corec₂ x fun x => Id.run (x 0, x 0, tail x)) = (corec₂ x fun x => Id.run (x 0, x 0, x.tail))

theorem icmp_power2_and_icmp_shifted_mask_2147483648_1610612736_proof : icmp_power2_and_icmp_shifted_mask_2147483648_1610612736_before ⊑ icmp_power2_and_icmp_shifted_mask_2147483648_1610612736_after

theorem ult_swap_and_not_max_commute_proof : ult_swap_and_not_max_commute_before ⊑ ult_swap_and_not_max_commute_after

theorem sub_to_xor_or_commuted_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32), (x_1 ||| x) - (x &&& x_1) = x ^^^ x_1

theorem positive_sameconst_shlnuw_lshrexact_proof : positive_sameconst_shlnuw_lshrexact_before ⊑ positive_sameconst_shlnuw_lshrexact_after

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

theorem e_1968 :
    7 * (c ^^^  ~~~(a &&&  ~~~b)) - 1 *  ~~~(a ^^^ ( ~~~b ||| c)) - 2 * ((a ||| b) &&& (b ^^^ c)) + 4 * (b &&&  ~~~(a &&& c)) - 2 * ( ~~~b &&&  ~~~(a ^^^ c)) + 1 *  ~~~c + 4 * b - 11 *  ~~~(a &&&  ~~~c) - 1 * (c ^^^  ~~~( ~~~a &&& (b ||| c))) - 6 *  ~~~(b |||  ~~~c) + 11 * (a ||| ( ~~~b &&& c)) + 2 * ( ~~~c &&& (a ^^^ b)) - 3 * (c ^^^  ~~~( ~~~a &&& ( ~~~b ||| c))) + 5 * (b ^^^  ~~~( ~~~a ||| (b &&& c))) - 1 * ( ~~~(a ||| b) |||  ~~~(a ^^^ (b ^^^ c))) - 7 * (b &&&  ~~~c) - 6 * ((b &&& c) ^^^  ~~~( ~~~a &&& (b ^^^ c))) + 11 * ((b &&&  ~~~c) ^^^ ( ~~~a ||| (b ^^^ c))) + 7 * (b ^^^  ~~~(a &&& (b &&& c))) - 7 * (a ^^^ c) + 1 * (c &&&  ~~~(a &&& b)) + 1 * ((a &&&  ~~~b) |||  ~~~(a ^^^ (b ^^^ c))) - 5 * (c ||| (a &&& b)) + 3 * (b |||  ~~~(a ^^^ c)) + 3 * (c ^^^  ~~~(a &&& ( ~~~b ||| c))) + 3 * (c |||  ~~~(a ^^^ b)) + 1 * ((a &&& b) ^^^ (b |||  ~~~c)) - 7 *  ~~~( ~~~a &&& ( ~~~b ||| c)) - 11 * (b ||| c) - 7 *  ~~~(a &&& b) + 7 * (b ^^^  ~~~(a &&& ( ~~~b ||| c))) + 2 * ( ~~~(a &&&  ~~~b) &&&  ~~~(b ^^^ c)) - 6 * ( ~~~(a &&& b) &&& (b ^^^ c)) - 7 * (b ^^^  ~~~( ~~~a &&& ( ~~~b ||| c))) + 5 * ( ~~~(a ^^^ b) &&& (a ^^^ c)) + 2 * (a ||| (b ||| c)) - 11 * (b ^^^  ~~~(a ||| (b &&& c))) - 6 * ((a &&& c) ^^^ (a ^^^ (b &&& c))) + 1 * (b ^^^  ~~~( ~~~a &&& (b ^^^ c))) - 2 * (c &&& (a ||| b)) - 1 * ((a &&& b) ^^^  ~~~(a ^^^ ( ~~~b ||| c))) + 1 * ((b &&& c) ||| ( ~~~a &&& (b ||| c))) - 11 * ((b &&& c) ^^^  ~~~(a &&& (b ^^^ c))) + 11 *  ~~~(a ||| c) - 1 * ( ~~~(a &&& b) &&& (a ^^^ (b ^^^ c))) - 1 * ((a &&& b) ^^^  ~~~(a ^^^ (b &&& c))) + 7 * (b ^^^ ( ~~~a &&& (b ^^^ c))) - 6 * ((a ^^^ b) |||  ~~~(a ^^^ c)) + 7 * ( ~~~(a &&& b) &&&  ~~~(b ^^^ c)) - 8 *  ~~~(a ||| (b ||| c)) + 30 *  ~~~(a ||| ( ~~~b ||| c)) + 32 *  ~~~( ~~~a ||| (b ||| c)) + 18 *  ~~~( ~~~a ||| ( ~~~b ||| c)) + 32 * ( ~~~a &&& (b &&& c)) + 26 * (a &&& ( ~~~b &&& c)) + 11 * (a &&& (b &&& c)) = 6 * (c ^^^ (a &&&  ~~~b)) - 33 * ( ~~~a &&& ( ~~~b &&& c))

theorem smear_set_bit_different_dest_type_wider_dst_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬7#8 ≥ ↑8 →
    ¬(24#32 ≥ ↑32 ∨ 31#32 ≥ ↑32) →
      signExtend 64 ((truncate 8 x).sshiftRight' 7#8) = signExtend 64 ((x <<< 24#32).sshiftRight' 31#32)

theorem e_1208 :
    2 *  ~~~(z &&&  ~~~t) - 7 *  ~~~(z &&&  ~~~z) + 2 * z + 7 *  ~~~(z &&& t) + 1 *  ~~~t - 11 * (z ^^^ t) - 3 *  ~~~(z ||| t) + 13 * (z &&&  ~~~t) + 8 * (z &&& t) =  - 14 *  ~~~(z |||  ~~~t) + 5 * (z ||| t)

theorem t1_ult_slt_0_proof : t1_ult_slt_0_before ⊑ t1_ult_slt_0_after

theorem test52_thm (e : IntW 64) :
  zext 32 (LLVM.and (LLVM.or (trunc 16 e) (const? 16 (-32574))) (const? 16 (-25350))) ⊑
    zext 32 (LLVM.or (LLVM.and (trunc 16 e) (const? 16 7224)) (const? 16 (-32574)) { «disjoint» := true })

theorem zext_ult_zext_thm.extracted_1._1 : ∀ (x : BitVec 1) (x_1 : BitVec 8),
  ofBool (zeroExtend 16 (x_1 * x_1) <ᵤ zeroExtend 16 x) = ofBool (x_1 * x_1 == 0#8) &&& x

theorem icmp_power2_and_icmp_shifted_mask_swapped_2147483648_2147483647_proof : icmp_power2_and_icmp_shifted_mask_swapped_2147483648_2147483647_before ⊑ icmp_power2_and_icmp_shifted_mask_swapped_2147483648_2147483647_after

theorem e_301 :
     - 3 * y + 1 * (x ||| y) + 1 * (x |||  ~~~y) - 1 *  ~~~(x ||| y) - 9 *  ~~~(x |||  ~~~y) - 13 * (x &&&  ~~~y) + 1 * (x &&& y) =  - 11 * (x ^^^ y)

theorem Predicate.evalUlt_denote_false_iff {w : Nat} (a b : Term) (vars : List (BitVec w)) :
    evalUlt (a.eval (List.map .ofBitVecSext vars)) (b.eval (List.map .ofBitVecSext vars)) w = false ↔
    (Term.denote w a vars < Term.denote w b vars)

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

theorem land_bor_left1_thm.extracted_1._2 : ∀ (x x_1 : BitVec 1), x_1 = 1#1 → x ||

theorem demorgan_and_apint2_proof : demorgan_and_apint2_before ⊑ demorgan_and_apint2_after

theorem test3_thm.extracted_1._1 : ∀ (x : BitVec 1) (x_1 : BitVec 59),
  x = 1#1 → ¬70368744177664#59 = 0 → x_1 % 70368744177664#59 = x_1 &&& 70368744177663#59

theorem Term.toBV_of_KInductionCircuits'
    {wcard tcard bcard ncard icard pcard : Nat}
    (P : Prop)
    (tctx : Term.Ctx wcard tcard)
    (p : MultiWidth.Term bcard ncard icard pcard tctx .prop)
    (pNondep : Nondep.Term)
    (_hpNondep : pNondep = (.ofDepTerm p))
    (fsm : TermFSM wcard tcard bcard ncard icard pcard pNondep)
    (_hfsm : fsm = mkTermFsmNondep wcard tcard bcard ncard icard pcard pNondep)
    (n : Nat)
    (circs : KInductionCircuits fsm.toFsmZext n)
    (hCircs : circs.IsLawful)
    (sCert : Lean.Elab.Tactic.BVDecide.Frontend.LratCert)
    (hs : Circuit.verifyCircuit (circs.mkSafetyCircuit) sCert = true)
    (indCert : Lean.Elab.Tactic.BVDecide.Frontend.LratCert)
    (hind : Circuit.verifyCircuit (circs.mkIndHypCycleBreaking) indCert = true)
    (wenv : WidthExpr.Env wcard)
    (tenv : tctx.Env wenv)
    (benv : Term.BoolEnv bcard)
    (nenv : Term.NatEnv ncard)
    (ienv : Term.IntEnv icard)
    (penv : Predicate.Env pcard)
    (hp : p.toBV benv nenv ienv penv tenv = P) :
    P

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

theorem or_eq_with_one_bit_diff_constants1_thm (e : IntW 32) :
  LLVM.or (icmp IntPred.eq e (const? 32 50)) (icmp IntPred.eq e (const? 32 51)) ⊑
    icmp IntPred.eq (LLVM.and e (const? 32 (-2))) (const? 32 50)

theorem t1_ult_slt_0_thm.extracted_1._5 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 + 16#32 <ᵤ 144#32) = 1#1 → ofBool (127#32 <ₛ x_1) = 1#1 → x_1 = x

theorem add_incr_left (x : BitVec v) :
    x.zeroExtend (2 + v) = (x.zeroExtend (1 + v)).zeroExtend (2 + v)

theorem test2_proof : test2_before ⊑ test2_after

theorem add_nsw_const_const_sub_nsw_proof : add_nsw_const_const_sub_nsw_before ⊑ add_nsw_const_const_sub_nsw_after

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

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

theorem sgt_smax3_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ofBool (x <ₛ x_1 + 3#32) = 1#1 → ofBool (x_1 + 3#32 <ₛ x_1 + 3#32) = ofBool (x_1 + 3#32 <ₛ x)

theorem ashr_lshr_cst_proof : ashr_lshr_cst_before ⊑ ashr_lshr_cst_after

theorem e_1695 :
    4 * (c ^^^  ~~~(a &&& ( ~~~b &&& c))) + 1 * ( ~~~(a &&& b) &&& (a ^^^ (b ^^^ c))) + 1 * (b |||  ~~~c) - 3 * ((a &&& c) ^^^ (b ||| c)) + 7 * (b ^^^ (a &&& c)) + 7 * (b ^^^ (a &&& (b ^^^ c))) - 1 *  ~~~( ~~~a &&& (b ^^^ c)) + 1 * ((b &&& c) ^^^  ~~~( ~~~a &&& (b ^^^ c))) - 5 * (c ^^^ (a ||| (b &&& c))) + 2 * (a &&&  ~~~b) + 5 * (b ^^^ ( ~~~a &&& (b ^^^ c))) + 4 * (c ^^^ ( ~~~a ||| (b &&& c))) - 5 * a + 7 * ((a &&& b) ^^^ (b ||| c)) - 5 * (c ||| (a ^^^ b)) - 3 * (a ||| c) + 1 * (a ^^^ ( ~~~b &&& c)) + 2 * ( ~~~a ||| ( ~~~b &&& c)) + 4 * (b ^^^ (a &&& ( ~~~b ||| c))) - 2 *  ~~~a - 2 * (a ||| (b &&& c)) - 2 *  ~~~(a ||| (b ||| c)) - 27 *  ~~~(a ||| ( ~~~b ||| c)) + 7 *  ~~~( ~~~a ||| (b ||| c)) - 4 *  ~~~( ~~~a ||| ( ~~~b ||| c)) + 9 * ( ~~~a &&& ( ~~~b &&& c)) - 17 * ( ~~~a &&& (b &&& c)) - 22 * (a &&& ( ~~~b &&& c)) + 9 * (a &&& (b &&& c)) = 7 * (b ^^^  ~~~(a &&& ( ~~~b ||| c)))

theorem positive_trunc_base_thm (e : IntW 32) :
  LLVM.and (icmp IntPred.sgt (trunc 16 e) (const? 16 (-1)))
      (icmp IntPred.ult (add (trunc 16 e) (const? 16 128)) (const? 16 256)) ⊑
    icmp IntPred.eq (LLVM.and e (const? 32 65408)) (const? 32 0)

theorem select_mul_icmp_bad_proof : select_mul_icmp_bad_before ⊑ select_mul_icmp_bad_after

theorem gt_unsigned_to_small_unsigned_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ofBool (17#32 <ᵤ zeroExtend 32 x) = ofBool (17#8 <ᵤ x)

theorem shl_xor_xor_bad_mask_distribute_thm (e e_1 : IntW 8) :
  LLVM.xor (shl e_1 (const? 8 1)) (LLVM.xor (shl e (const? 8 1)) (const? 8 (-68))) ⊑
    LLVM.xor (shl (LLVM.xor e e_1) (const? 8 1)) (const? 8 (-68))

theorem icmp_eq_and_pow2_shl_pow2_proof : icmp_eq_and_pow2_shl_pow2_before ⊑ icmp_eq_and_pow2_shl_pow2_after

theorem ashrsgt_02_06_exact_proof : ashrsgt_02_06_exact_before ⊑ ashrsgt_02_06_exact_after

theorem R.trim_toTensor'_eq_toTensor [hqgt1 : Fact (q > 1)] (a : R q n) :
  trimTensor a.toTensor' = a.toTensor

theorem test16_thm (e : IntW 32) : icmp IntPred.eq (LLVM.and e (const? 32 5)) (const? 32 8) ⊑ const? 1 0

theorem ashr_lshr_shift_amt_mismatch_thm (e e_1 e_2 : IntW 32) :
  select (icmp IntPred.sge e_2 (const? 32 0)) (lshr e_2 e_1) (ashr e_2 e) ⊑
    select (icmp IntPred.slt e_2 (const? 32 0)) (ashr e_2 e) (lshr e_2 e_1)

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

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

theorem ashrsgt_02_04_proof : ashrsgt_02_04_before ⊑ ashrsgt_02_04_after

lemma carry_compose [FinEnum arity] [DecidableEq arity] [Hashable arity]
    (new_arity : Type)
    (q_arity : arity → Type)
    (vars : ∀ (a : arity), q_arity a → new_arity)
    (q : ∀ (a : arity), FSM (q_arity a))
    (x : new_arity → BitStream) : ∀ (n : ℕ),
    (p.compose new_arity q_arity vars q).carry x n =
      let z := p.carry (λ a => (q a).eval (fun i => x (vars _ i))) n
      Sum.elim z (fun a => (q a.1).carry (fun t => x (vars _ t)) n a.2)

theorem lshr_exact_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬(2#8 ≥ ↑8 ∨ 2#8 ≥ ↑8) → (x <<< 2#8 + 4#8) >>> 2#8 = x + 1#8 &&& 63#8

theorem masked_or_allzeroes_proof : masked_or_allzeroes_before ⊑ masked_or_allzeroes_after

theorem scanAnd_eq_decide (s : BitStream) (n : Nat) :
    s.scanAnd n = decide (∀ (i : Nat), i ≤ n → s i = true)

theorem shl_sub_i32_thm (e : IntW 32) :
  shl (const? 32 1) (sub (const? 32 31) e) ⊑ lshr (const? 32 (-2147483648)) e { «exact» := true }

theorem test1_proof : test1_before ⊑ test1_after

theorem Lets.denote_eq_denoteIntoSubtype (lets : Lets d Γ_in eff Γ_out) (Γv : Valuation Γ_in) :
    lets.denote Γv = Subtype.val <$> (lets.denoteIntoSubtype Γv)

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

theorem test_add_nuw__all_are_safe_proof : test_add_nuw__all_are_safe_before ⊑ test_add_nuw__all_are_safe_after

theorem lshrult_03_05_exact_thm (e : IntW 4) :
  icmp IntPred.ult (lshr e (const? 4 3) { «exact» := true }) (const? 4 5) ⊑ const? 1 1

theorem e_2445 :
    2 * (f ^^^  ~~~(d ||| e)) + 2 * (d &&&  ~~~f) + 11 * (f ^^^  ~~~( ~~~d &&& (e &&& f))) - 7 * (d &&& (e ||| f)) - 7 * (e &&&  ~~~f) + 11 *  ~~~e - 7 *  ~~~(d ^^^ (e &&& f)) + 3 * ((e &&&  ~~~f) ^^^ ( ~~~d ||| (e ^^^ f))) - 1 * ( ~~~d ||| (e &&& f)) + 1 *  ~~~(d ||| f) + 4 * ((d ^^^ e) ||| (d ^^^ f)) - 3 * ( ~~~(d ||| e) ||| (d ^^^ (e ^^^ f))) + 3 * ( ~~~d ||| (e ||| f)) + 3 * ((d &&& e) ^^^ (d ^^^ ( ~~~e ||| f))) + 1 * ((d &&& f) |||  ~~~(e ||| f)) - 2 * ((d &&&  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) - 1 * (f ^^^  ~~~(d &&& e)) - 5 * (e ^^^  ~~~(d ||| (e &&& f))) + 1 *  ~~~f - 1 * (e ^^^ (d ||| ( ~~~e &&& f))) + 2 * ((d |||  ~~~e) &&& (d ^^^ (e ^^^ f))) + 2 * ((e &&&  ~~~f) |||  ~~~(d ||| ( ~~~e &&& f))) - 5 * ( ~~~(d ||| e) |||  ~~~(e ^^^ f)) - 3 * (f ||| (d &&& e)) + 11 * ((d &&&  ~~~e) ||| (d ^^^ (e ^^^ f))) - 11 * (e ^^^  ~~~(d ||| f)) - 2 * (f |||  ~~~(d ^^^ e)) - 5 *  ~~~(d &&& (e &&& f)) - 1 * (f &&&  ~~~(d &&& e)) + 11 * e - 6 * (f ||| (d ^^^ e)) + 4 *  ~~~(d |||  ~~~f) + 2 *  ~~~( ~~~d &&& (e &&& f)) - 3 * (e |||  ~~~(d ^^^ f)) + 4 * (f ^^^  ~~~(d ||| ( ~~~e &&& f))) - 1 * ( ~~~f |||  ~~~(d ^^^ e)) + 1 * ( ~~~e &&& (d ^^^ f)) - 3 *  ~~~(e ^^^ f) + 5 * ( ~~~e |||  ~~~(d ^^^ f)) + 2 * (e ^^^ (d ||| f)) - 2 * (e |||  ~~~(d ||| f)) + 5 * (f &&& (d |||  ~~~e)) - 1 *  ~~~( ~~~d ||| (e &&& f)) - 2 * ( ~~~(d &&& e) &&& (d ^^^ (e ^^^ f))) + 7 * (f ^^^ ( ~~~d ||| (e &&& f))) - 3 * (e ^^^  ~~~(d &&&  ~~~f)) + 7 * ((d &&& f) ^^^  ~~~(d ^^^ (e &&& f))) - 2 * ((d &&& f) ||| (e &&&  ~~~f)) + 1 *  ~~~( ~~~d &&& (e ||| f)) - 7 * (d ||| (e &&& f)) - 11 * (d &&& e) - 6 * (e ^^^  ~~~(d |||  ~~~f)) - 6 * ( ~~~(d &&&  ~~~e) &&&  ~~~(d ^^^ (e ^^^ f))) - 11 * ( ~~~(d |||  ~~~e) ||| (d ^^^ (e ^^^ f))) - 5 * ( ~~~e &&&  ~~~(d ^^^ f)) + 1 *  ~~~(d &&& (e ||| f)) + 1 * (e ^^^ ( ~~~d ||| (e ^^^ f))) - 1 * (e ^^^ ( ~~~d ||| (e ||| f))) + 2 * (e ^^^  ~~~(d &&& (e &&& f))) + 2 * (e ^^^  ~~~( ~~~d ||| (e ^^^ f))) + 1 * (d ^^^ (e &&& f)) + 5 * (f ^^^  ~~~(d &&& (e ||| f))) - 1 * (e ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) + 3 * (f ^^^ ( ~~~d &&& (e ||| f))) - 2 * (d |||  ~~~e) - 1 * (d ^^^ e) - 1 * ((d &&&  ~~~e) |||  ~~~(e ^^^ f)) - 2 * (e ^^^ ( ~~~d ||| (e &&& f))) - 6 *  ~~~( ~~~d &&& (e ^^^ f)) + 1 * (e ^^^  ~~~(d &&& ( ~~~e ||| f))) + 4 *  ~~~(d ||| (e ||| f)) - 26 *  ~~~(d ||| ( ~~~e ||| f)) - 6 *  ~~~( ~~~d ||| (e ||| f)) + 54 *  ~~~( ~~~d ||| ( ~~~e ||| f)) + 32 * ( ~~~d &&& (e &&& f)) - 20 * (d &&& ( ~~~e &&& f)) + 41 * (d &&& (e &&& f)) = 5 * ( ~~~d &&& ( ~~~e &&& f)) - 3 * (e &&&  ~~~(d &&&  ~~~f))

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

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

theorem or_simplify_uge_proof : or_simplify_uge_before ⊑ or_simplify_uge_after

theorem e_1718 :
    11 * ( ~~~(a ^^^ b) &&& (a ^^^ c)) + 1 * (a &&& (b ^^^ c)) - 1 * (c ^^^  ~~~(a ||| ( ~~~b &&& c))) - 1 *  ~~~(a ||| (b ^^^ c)) - 11 * (c ^^^ ( ~~~a ||| (b ||| c))) - 1 * (b ^^^  ~~~(a &&& (b ||| c))) - 7 * (c ^^^ ( ~~~a ||| ( ~~~b &&& c))) + 1 * ((b &&&  ~~~c) |||  ~~~(a ||| ( ~~~b &&& c))) - 11 * ((a &&&  ~~~b) |||  ~~~(a ^^^ (b ^^^ c))) + 4 * ((b &&& c) ||| ( ~~~a &&& (b ||| c))) + 1 *  ~~~(a ^^^ (b ^^^ c)) + 4 *  ~~~( ~~~a ||| ( ~~~b &&& c)) - 11 *  ~~~(a ^^^ c) + 5 * (b ^^^ ( ~~~a ||| ( ~~~b &&& c))) + 1 *  ~~~a - 2 *  ~~~(a &&& c) - 1 * (a ||| c) - 3 * (c ^^^ (a &&&  ~~~b)) + 4 * ((a ^^^ b) &&& (a ^^^ c)) - 1 * (c &&& (a |||  ~~~b)) - 2 * (c ^^^  ~~~( ~~~a ||| (b &&& c))) - 7 *  ~~~(b ^^^ c) + 44 *  ~~~(a ||| (b ||| c)) + 26 *  ~~~(a ||| ( ~~~b ||| c)) + 18 *  ~~~( ~~~a ||| (b ||| c)) + 4 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 11 * ( ~~~a &&& ( ~~~b &&& c)) + 16 * ( ~~~a &&& (b &&& c)) + 17 * (a &&& ( ~~~b &&& c)) + 20 * (a &&& (b &&& c)) =  - 1 * (a ||| ( ~~~b &&& c))

theorem shl_add_log_may_cause_poison_pr62175_with_nuw_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ¬(True ∧ 4#8 <<< x >>> x ≠ 4#8 ∨ x ≥ ↑8) → x + 2#8 ≥ ↑8 → False

theorem select_icmp_x_and_8_eq_0_y_xor_8_thm.extracted_1._3 : ∀ (x : BitVec 64) (x_1 : BitVec 32),
  ¬ofBool (x_1 &&& 8#32 == 0#32) = 1#1 → True ∧ (x_1 &&& 8#32).msb = true → False

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

theorem test85_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬(True ∧ x.uaddOverflow (BitVec.ofInt 32 (-16777216)) = true ∨
        True ∧ (x + BitVec.ofInt 32 (-16777216)) >>> 23#32 <<< 23#32 ≠ x + BitVec.ofInt 32 (-16777216) ∨ 23#32 ≥ ↑32) →
    23#32 ≥ ↑32 → False

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

theorem sgt_and_min_commute_logical_proof : sgt_and_min_commute_logical_before ⊑ sgt_and_min_commute_logical_after

theorem and_xor_commute3_proof : and_xor_commute3_before ⊑ and_xor_commute3_after

theorem lshrugt_03_07_proof : lshrugt_03_07_before ⊑ lshrugt_03_07_after

theorem ashr_lshr_no_ashr_thm (e e_1 : IntW 32) :
  select (icmp IntPred.sge e_1 (const? 32 0)) (lshr e_1 e) (LLVM.xor e_1 e) ⊑
    select (icmp IntPred.slt e_1 (const? 32 0)) (LLVM.xor e_1 e) (lshr e_1 e)

theorem sdiv6_proof : sdiv6_before ⊑ sdiv6_after

theorem one_side_fold_eq_thm.extracted_1._2 : ∀ (x : BitVec 32) (x_1 : BitVec 1),
  ¬x_1 = 1#1 → ¬x_1 ^^^ 1#1 = 1#1 → False

theorem ashr_1_proof : ashr_1_before ⊑ ashr_1_after

theorem test25_proof : test25_before ⊑ test25_after

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

theorem sub_select_zext_op_swapped_non_const_args_thm.extracted_1._1 : ∀ (x : BitVec 6) (x_1 : BitVec 1),
  x_1 = 1#1 → zeroExtend 6 x_1 - x = 1#6 - x

theorem andn_or_cmp_2_partial_logical_proof : andn_or_cmp_2_partial_logical_before ⊑ andn_or_cmp_2_partial_logical_after

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

theorem icmp_slt_0_and_icmp_sge_neg1_i64_fail_thm.extracted_1._2 : ∀ (x : BitVec 64),
  ¬62#64 ≥ ↑64 →
    ¬ofBool (BitVec.ofInt 64 (-2) <ₛ x) = 1#1 → x >>> 62#64 &&& zeroExtend 64 (ofBool (-1#64 ≤ₛ x)) = 0#64

theorem ne_smin2_proof : ne_smin2_before ⊑ ne_smin2_after

theorem e_2007 :
    1 * ((d |||  ~~~e) &&& (d ^^^ (e ^^^ f))) - 1 * (f ^^^ ( ~~~d &&& (e ||| f))) + 11 *  ~~~(e ^^^ f) + 1 *  ~~~(e &&& f) + 11 * ((e &&&  ~~~f) ^^^ (d ||| (e ^^^ f))) - 1 * ( ~~~(d ^^^ e) |||  ~~~(d ^^^ f)) - 1 * ( ~~~d &&& ( ~~~e ||| f)) + 1 * (e &&& (d ||| f)) + 5 * (e ^^^ (d &&& (e ||| f))) - 5 * (d ^^^ f) - 2 * (e ||| (d &&&  ~~~f)) + 1 * (e ^^^  ~~~( ~~~d ||| ( ~~~e &&& f))) + 11 * (f &&&  ~~~(d ^^^ e)) + 7 * (d ^^^ e) - 3 *  ~~~(d &&& ( ~~~e &&& f)) - 3 * ((d &&& e) ^^^ (e ||| f)) + 4 *  ~~~(d &&& f) + 1 * (e ^^^ ( ~~~d ||| ( ~~~e ||| f))) - 5 * (d ^^^ ( ~~~e ||| f)) + 1 * ((e &&&  ~~~f) |||  ~~~( ~~~d ||| ( ~~~e &&& f))) + 7 * (f ^^^  ~~~(d ||| e)) + 3 * (f ^^^ ( ~~~d ||| (e ||| f))) - 2 * (e ^^^ (d &&& ( ~~~e ||| f))) - 6 * (d ||| (e ^^^ f)) - 1 * ( ~~~(d ||| e) |||  ~~~(d ^^^ (e ^^^ f))) + 2 * ((e &&&  ~~~f) |||  ~~~(d ||| ( ~~~e &&& f))) - 18 *  ~~~(d ||| (e ||| f)) - 20 *  ~~~( ~~~d ||| (e ||| f)) + 12 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 1 * ( ~~~d &&& ( ~~~e &&& f)) - 13 * ( ~~~d &&& (e &&& f)) - 18 * (d &&& ( ~~~e &&& f)) - 27 * (d &&& (e &&& f)) = 3 * ((e &&& f) ||| ( ~~~d &&& (e ||| f))) + 3 *  ~~~(d ||| ( ~~~e ||| f))

theorem icmp_slt_0_and_icmp_sge_neg1_i64_thm (e : IntW 64) :
  LLVM.and (lshr e (const? 64 63)) (zext 64 (icmp IntPred.sge e (const? 64 (-1)))) ⊑
    zext 64 (icmp IntPred.eq e (const? 64 (-1)))

theorem ne_3210_thm (e e_1 : IntW 32) :
  LLVM.or (icmp IntPred.ne (trunc 8 (lshr e_1 (const? 32 24))) (trunc 8 (lshr e (const? 32 24))))
      (LLVM.or (icmp IntPred.ne (trunc 8 (lshr e_1 (const? 32 16))) (trunc 8 (lshr e (const? 32 16))))
        (LLVM.or (icmp IntPred.ne (trunc 8 e_1) (trunc 8 e))
          (icmp IntPred.ne (trunc 8 (lshr e_1 (const? 32 8))) (trunc 8 (lshr e (const? 32 8)))))) ⊑
    icmp IntPred.ne e_1 e

theorem zext_sext_add_icmp_i128_thm.extracted_1._1 : ∀ (x x_1 : BitVec 1),
  ofBool (9223372036854775808#128 <ₛ zeroExtend 128 x_1 + signExtend 128 x) = 0#1

theorem ashr_lshr_shift_base_mismatch_proof : ashr_lshr_shift_base_mismatch_before ⊑ ashr_lshr_shift_base_mismatch_after

theorem e_1713 :
     - 2 * (b ^^^ (a ||| ( ~~~b &&& c))) + 11 * ((a &&& b) |||  ~~~(b ||| c)) - 7 * ((a &&& b) ^^^  ~~~(a ^^^ (b &&& c))) - 6 *  ~~~(a &&& c) - 2 * (b ^^^  ~~~( ~~~a &&& (b ^^^ c))) + 1 * (a ||| (b ^^^ c)) - 11 * (b ^^^  ~~~(a ||| (b &&& c))) + 3 * (b ^^^ ( ~~~a &&& (b ||| c))) - 6 * ((b &&&  ~~~c) |||  ~~~( ~~~a ||| ( ~~~b &&& c))) + 1 * ((a &&& c) ^^^ (b ||| c)) - 2 * ( ~~~(a &&&  ~~~b) &&& (a ^^^ (b ^^^ c))) - 1 * ((a &&& b) ||| (a ^^^ (b ^^^ c))) + 4 * ( ~~~a &&& ( ~~~b ||| c)) + 3 *  ~~~(a ^^^ ( ~~~b &&& c)) - 2 * ((a &&& c) ^^^  ~~~(a ^^^ (b &&& c))) + 11 * (a &&& ( ~~~b ||| c)) + 1 * (c ||| (a ^^^ b)) - 3 *  ~~~( ~~~a &&& (b &&& c)) - 1 * ((a &&& b) ^^^ (a ^^^ (b &&& c))) + 7 * ( ~~~b &&& (a ^^^ c)) - 3 * (c ^^^  ~~~( ~~~a &&& ( ~~~b ||| c))) - 1 * (c &&& (a ||| b)) - 1 * (b &&& (a ||| c)) + 13 *  ~~~(a ||| (b ||| c)) + 28 *  ~~~(a ||| ( ~~~b ||| c)) - 14 *  ~~~( ~~~a ||| (b ||| c)) + 22 *  ~~~( ~~~a ||| ( ~~~b ||| c)) + 13 * ( ~~~a &&& ( ~~~b &&& c)) + 16 * ( ~~~a &&& (b &&& c)) - 12 * (a &&& ( ~~~b &&& c)) = 8 * (a &&& (b &&& c)) - 7 * ((b &&&  ~~~c) ^^^ (a ||| (b ^^^ c)))

theorem shift_xor_multiuse_cmp_proof : shift_xor_multiuse_cmp_before ⊑ shift_xor_multiuse_cmp_after

theorem test11_thm (e e_1 : IntW 32) :
  add (add e_1 (const? 32 1)) (LLVM.xor (LLVM.or e (const? 32 (-1431655766))) (const? 32 1431655765)) ⊑
    sub e_1 (LLVM.and e (const? 32 1431655765))

theorem shl_add_proof : shl_add_before ⊑ shl_add_after

theorem test_and1_logical_thm (e e_1 : IntW 32) :
  select (icmp IntPred.sge e_1 (const? 32 0)) (icmp IntPred.slt e_1 (LLVM.and e (const? 32 2147483647)))
      (const? 1 0) ⊑
    select (icmp IntPred.sgt e_1 (const? 32 (-1))) (icmp IntPred.slt e_1 (LLVM.and e (const? 32 2147483647)))
      (const? 1 0)

theorem samesign_proof : samesign_before ⊑ samesign_after

theorem ashrslt_01_05_exact_thm (e : IntW 4) :
  icmp IntPred.slt (ashr e (const? 4 1) { «exact» := true }) (const? 4 5) ⊑ const? 1 1

theorem masked_or_allzeroes_notoptimised_logical_proof : masked_or_allzeroes_notoptimised_logical_before ⊑ masked_or_allzeroes_notoptimised_logical_after

theorem n2_thm (e : IntW 8) :
  LLVM.sdiv e (const? 8 (-128)) ⊑ zext 8 (icmp IntPred.eq e (const? 8 (-128)))

theorem icmp_x_slt_0_and_icmp_y_sgt_neg1_i32_fail_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ¬31#32 ≥ ↑32 →
    x_1 >>> 31#32 &&& zeroExtend 32 (ofBool (-1#32 <ₛ x)) =
      zeroExtend 32 (ofBool (x_1 <ₛ 0#32) &&& ofBool (-1#32 <ₛ x))

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

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

theorem scalar_i32_shl_and_negC_eq_X_is_constant1_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬x ≥ ↑32 → ofBool (12345#32 <<< x &&& BitVec.ofInt 32 (-8) == 0#32) = ofBool (12345#32 <<< x <ᵤ 8#32)

theorem select_ashr_thm.extracted_1._4 : ∀ (x x_1 : BitVec 128) (x_2 : BitVec 1),
  ¬x_2 = 1#1 → ¬0#128 ≥ ↑128 → x_1 = x_1.sshiftRight' 0#128

theorem sgt_smin2_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32), ofBool (x_1 <ₛ x) = 1#1 → ofBool (x <ₛ x_1) = 0#1

theorem ashr_sub_nsw_thm.extracted_1._1 : ∀ (x x_1 : BitVec 17),
  ¬(True ∧ x_1.ssubOverflow x = true ∨ 16#17 ≥ ↑17) →
    (x_1 - x).sshiftRight' 16#17 = signExtend 17 (ofBool (x_1 <ₛ x))

@[simp]
lemma determinize_complete (M : NFA α σ) :
    M.toDFA.toNFA.Complete

theorem band_lor_left1_proof : band_lor_left1_before ⊑ band_lor_left1_after

theorem lshrult_01_12_proof : lshrult_01_12_before ⊑ lshrult_01_12_after

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

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

theorem trunc_unsigned_nsw_sext_thm (e : IntW 8) (e_1 : IntW 32) :
  icmp IntPred.ult (trunc 16 e_1 { «nsw» := true, «nuw» := false }) (sext 16 e) ⊑
    icmp IntPred.ult e_1 (sext 32 e)

theorem sub_mask1_trunc_lshr_thm.extracted_1._2 : ∀ (x : BitVec 64),
  ¬15#64 ≥ ↑64 →
    ¬(48#64 ≥ ↑64 ∨
          63#64 ≥ ↑64 ∨
            True ∧ signExtend 64 (truncate 8 ((x <<< 48#64).sshiftRight' 63#64)) ≠ (x <<< 48#64).sshiftRight' 63#64 ∨
              True ∧ (truncate 8 ((x <<< 48#64).sshiftRight' 63#64)).saddOverflow 10#8 = true) →
      10#8 - (truncate 8 (x >>> 15#64) &&& 1#8) = truncate 8 ((x <<< 48#64).sshiftRight' 63#64) + 10#8

theorem logical_and_logical_and_icmps_comm1_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ¬(x ≥ ↑8 ∨ ofBool (x_1 &&& 1#8 <<< x != 0#8) = 1#1) → True ∧ 1#8 <<< x >>> x ≠ 1#8 ∨ x ≥ ↑8 → False

theorem test19_commutative1_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ¬(x ≥ ↑32 ∨ x ≥ ↑32 ∨ x_1 ≥ ↑32 ∨ 1#32 <<< x + (1#32 <<< x &&& 1#32 <<< x_1) = 0) →
    True ∧ 1#32 <<< x >>> x ≠ 1#32 ∨
        x ≥ ↑32 ∨ True ∧ 1#32 <<< x >>> x ≠ 1#32 ∨ x ≥ ↑32 ∨ True ∧ 1#32 <<< x_1 >>> x_1 ≠ 1#32 ∨ x_1 ≥ ↑32 →
      False

theorem compose_first {α: Type u₁} (i : Nat) (a : α)
    (f : α → α × Bool) :
    (f ((Prod.fst ∘ f)^[i] a)).1 = (Prod.fst ∘ f)^[i] (f a).1

theorem select_lshr_icmp_bad_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 == 1#32) = 1#1 → ¬x_1 ≥ ↑32 → ¬1#32 ≥ ↑32 → x >>> x_1 = x >>> 1#32

theorem e_1913 :
    5 * ( ~~~a ||| ( ~~~b ||| c)) - 1 * ( ~~~a &&& ( ~~~b ||| c)) + 1 *  ~~~b - 5 * (b ||| (a &&& c)) + 2 * ((a &&& c) ||| (b &&&  ~~~c)) + 11 *  ~~~a - 1 * (b ^^^ (a |||  ~~~c)) + 5 *  ~~~( ~~~a ||| (b &&& c)) - 1 * (c ||| (a ^^^ b)) + 5 * ( ~~~(a &&&  ~~~b) &&& (b ^^^ c)) - 11 * ( ~~~b &&&  ~~~(a ^^^ c)) - 1 * ((a &&& b) |||  ~~~(b |||  ~~~c)) + 11 * (b |||  ~~~(a ||| c)) - 2 * ( ~~~c &&& (a ^^^ b)) - 5 * ((a &&&  ~~~b) |||  ~~~(a ^^^ (b ^^^ c))) + 1 * (a ^^^ ( ~~~b ||| c)) - 5 * (b ^^^  ~~~(a &&& (b ||| c))) + 3 * ((a &&&  ~~~b) |||  ~~~(b ^^^ c)) - 2 * ((a ^^^ b) |||  ~~~(a ^^^ c)) + 7 * (b ^^^  ~~~(a &&& ( ~~~b &&& c))) + 4 *  ~~~(a |||  ~~~c) + 1 * (c &&& (a |||  ~~~b)) + 7 * (a &&& (b ^^^ c)) - 6 * (b |||  ~~~(a |||  ~~~c)) + 11 * ((a ^^^ b) ||| (a ^^^ c)) + 2 * ((a &&& b) ^^^ (a ^^^ ( ~~~b ||| c))) - 1 *  ~~~(a |||  ~~~b) - 1 * ((a &&&  ~~~b) ||| (a ^^^ (b ^^^ c))) + 2 *  ~~~( ~~~a &&& (b ^^^ c)) + 3 * ( ~~~b &&& (a ^^^ c)) + 2 * (c ^^^  ~~~(a &&& (b &&& c))) - 3 * (b ^^^ ( ~~~a ||| (b ^^^ c))) + 1 *  ~~~(a ^^^ (b ^^^ c)) + 1 * (c &&&  ~~~(a &&& b)) - 2 * (b |||  ~~~(a ^^^ c)) + 7 * (c ^^^ ( ~~~a &&& (b ||| c))) + 11 * ( ~~~c |||  ~~~(a ^^^ b)) + 3 * (a ^^^ ( ~~~b &&& c)) + 1 * b - 3 * ((a &&& b) |||  ~~~(b ||| c)) + 2 * (b ^^^  ~~~( ~~~a ||| (b &&& c))) - 7 * ((a &&& c) ^^^ (a ^^^ (b &&& c))) - 21 *  ~~~(a ||| (b ||| c)) - 48 *  ~~~(a ||| ( ~~~b ||| c)) - 25 *  ~~~( ~~~a ||| (b ||| c)) - 25 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 45 * ( ~~~a &&& ( ~~~b &&& c)) - 24 * ( ~~~a &&& (b &&& c)) - 13 * (a &&& ( ~~~b &&& c)) - 13 * (a &&& (b &&& c)) = 3 * (a |||  ~~~b)

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

theorem fold_eq_lhs_proof : fold_eq_lhs_before ⊑ fold_eq_lhs_after

theorem add_nsw_or_and_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ¬(True ∧ (x_1 ||| x).saddOverflow (x_1 &&& x) = true) → True ∧ x_1.saddOverflow x = true → False

theorem n2_badmask_proof : n2_badmask_before ⊑ n2_badmask_after

lemma Ctxt.getElem?_delete {i : Nat} {vs : DeleteRange Γ} :
    (Γ.delete vs)[i]? = if i < vs.start then Γ[i]? else Γ[i + vs.num]?

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

theorem icmp_eq_or_z_or_pow2orz_fail_bad_pred2_proof : icmp_eq_or_z_or_pow2orz_fail_bad_pred2_before ⊑ icmp_eq_or_z_or_pow2orz_fail_bad_pred2_after

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

theorem main6_logical_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 7#32 == 3#32) = 1#1 →
    ofBool (x &&& 48#32 == 16#32) = 1#1 → 0#32 = zeroExtend 32 (ofBool (x &&& 55#32 != 19#32))

theorem masked_bit_set_nonzero_cmp_proof : masked_bit_set_nonzero_cmp_before ⊑ masked_bit_set_nonzero_cmp_after

theorem decideIfZeroAux_wf {α : Type _} [Fintype α] [DecidableEq α]
    {c c' : Circuit α} (h : ¬c' ≤ c) : card_compl (c' ||| c) < card_compl c

theorem udiv_common_dividend_defined_cond_thm (e e_1 e_2 : IntW 5) (e_3 : IntW 1) :
  select e_3 (LLVM.udiv e_2 e_1) (LLVM.udiv e_2 e) ⊑ LLVM.udiv e_2 (select e_3 e_1 e)

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

theorem test_srem_canonicalize_op0_proof : test_srem_canonicalize_op0_before ⊑ test_srem_canonicalize_op0_after

theorem t1_thm (e : IntW 8) : sext 16 (trunc 3 (lshr e (const? 8 5))) ⊑ sext 16 (ashr e (const? 8 5))

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

theorem trunc_lshr_trunc_outofrange_proof : trunc_lshr_trunc_outofrange_before ⊑ trunc_lshr_trunc_outofrange_after

theorem select_icmp_x_and_8_ne_0_y_xor_8_thm.extracted_1._4 : ∀ (x : BitVec 64) (x_1 : BitVec 32),
  ¬ofBool (x_1 &&& 8#32 == 0#32) = 1#1 →
    ¬(True ∧ (x_1 &&& 8#32 ^^^ 8#32).msb = true) → x = x ^^^ zeroExtend 64 (x_1 &&& 8#32 ^^^ 8#32)

theorem test0_thm (e : IntW 32) :
  icmp IntPred.sgt (LLVM.xor e (const? 32 (-2147483648))) (const? 32 (-1)) ⊑
    icmp IntPred.slt e (const? 32 0)

theorem e_1320 :
     - 2 * (z ^^^ t) - 7 * (z ||| t) - 6 * t + 2 *  ~~~t + 1 *  ~~~(z ^^^ t) + 7 * (z |||  ~~~t) - 5 *  ~~~(z ||| t) + 20 *  ~~~(z |||  ~~~t) + 10 * (z &&& t) = 5 *  ~~~(z &&&  ~~~t)

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

theorem test4_proof : test4_before ⊑ test4_after

theorem ashrslt_01_09_thm (e : IntW 4) : icmp IntPred.slt (ashr e (const? 4 1)) (const? 4 (-7)) ⊑ const? 1 0

theorem positive_samevar_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬(x ≥ ↑32 ∨ x ≥ ↑32) → ¬x ≥ ↑32 → x_1 <<< x >>> x = (-1#32) >>> x &&& x_1

theorem e_771 :
     - 1 * (z |||  ~~~t) - 1 *  ~~~t + 2 * (z ^^^ t) + 1 *  ~~~(z ||| t) + 2 * (z &&& t) =  - 1 *  ~~~(z ^^^ t) + 2 * t

theorem ashrslt_03_06_proof : ashrslt_03_06_before ⊑ ashrslt_03_06_after

theorem shl_xor_thm.extracted_1._2 : ∀ (x : BitVec 8),
  ¬(x ≥ ↑8 ∨ x + 1#8 ≥ ↑8) → ¬x ≥ ↑8 → 16#8 <<< x ^^^ 3#8 <<< (x + 1#8) = 22#8 <<< x

theorem n14_trunc_of_lshr_proof : n14_trunc_of_lshr_before ⊑ n14_trunc_of_lshr_after

theorem udiv_icmp2_proof : udiv_icmp2_before ⊑ udiv_icmp2_after

@[simp, simp_denote, simp_sllvm]
lemma run_pure : StateT.run (pure x : EffectM α) s = .value (x, s)

theorem bv_AddSub_1165 :
    ∀ (e e_1 : LLVM.IntW w),
      LLVM.add (LLVM.sub (LLVM.const? w 0) e) (LLVM.sub (LLVM.const? w 0) e_1) ⊑ LLVM.sub (LLVM.const? w 0) (LLVM.add e e_1)

theorem or_and3_thm.extracted_1._6 : ∀ (x : BitVec 1) (x_1 x_2 : BitVec 32) (x_3 : BitVec 1),
  x_3 ||

theorem sub_select_sext_op_swapped_non_const_args_proof : sub_select_sext_op_swapped_non_const_args_before ⊑ sub_select_sext_op_swapped_non_const_args_after

theorem eq_umax3_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (x <ᵤ x_1 + 3#32) = 1#1 → ofBool (x_1 + 3#32 == x) = ofBool (x ≤ᵤ x_1 + 3#32)

theorem mul_of_pow2_proof : mul_of_pow2_before ⊑ mul_of_pow2_after

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

theorem e_1744 :
     - 2 * (b ^^^ (a ||| (b ^^^ c))) + 1 *  ~~~( ~~~a &&& ( ~~~b &&& c)) - 7 * (a ^^^ (b &&& c)) + 4 * (c ^^^  ~~~(a &&& (b ||| c))) + 4 * ((a &&& b) ^^^ (a ^^^ (b &&& c))) - 5 * (b &&& c) - 7 *  ~~~(a &&&  ~~~c) - 6 * (b ^^^  ~~~( ~~~a ||| (b &&& c))) - 1 * ( ~~~(a ||| b) ||| (a ^^^ (b ^^^ c))) + 2 * (b ^^^ (a &&& ( ~~~b ||| c))) - 2 * (a ||| c) + 2 * (c ^^^ (a ||| (b &&& c))) + 7 *  ~~~(a ||| (b ^^^ c)) - 6 * ((a &&& c) ||| (b &&&  ~~~c)) + 4 * (a &&& (b ^^^ c)) - 7 * ((b &&& c) ^^^  ~~~(a &&& (b ^^^ c))) - 2 * ((a &&& b) ^^^  ~~~(a ^^^ ( ~~~b ||| c))) - 6 * (b ^^^  ~~~(a &&& c)) + 5 *  ~~~(b &&&  ~~~c) + 2 * (c ^^^ (a &&& ( ~~~b ||| c))) + 7 * ( ~~~(a &&&  ~~~b) &&&  ~~~(a ^^^ (b ^^^ c))) + 5 *  ~~~(a ||| (b &&& c)) + 1 * (c ^^^  ~~~( ~~~a ||| ( ~~~b &&& c))) + 1 * (c ^^^ ( ~~~a ||| ( ~~~b &&& c))) + 5 * ((a &&& c) ^^^  ~~~(b &&&  ~~~c)) - 2 * (a ||| (b ||| c)) - 11 *  ~~~(a ||| (b ||| c)) + 21 *  ~~~(a ||| ( ~~~b ||| c)) + 12 *  ~~~( ~~~a ||| (b ||| c)) + 5 *  ~~~( ~~~a ||| ( ~~~b ||| c)) + 10 * ( ~~~a &&& ( ~~~b &&& c)) - 3 * ( ~~~a &&& (b &&& c)) + 13 * (a &&& ( ~~~b &&& c)) + 23 * (a &&& (b &&& c)) = 3 * ( ~~~c |||  ~~~(a ^^^ b))

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

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

theorem select_sub_icmp_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32), ofBool (x_1 == 0#32) = 1#1 → x - x_1 = x

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

theorem ne_umax4_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (x_1 + 3#32 <ᵤ x) = 1#1 → ofBool (x_1 + 3#32 != x_1 + 3#32) = ofBool (x_1 + 3#32 <ᵤ x)

theorem p0_thm.extracted_1._1 : ∀ (x : BitVec 8), ofBool (x &&& 3#8 == x) = ofBool (x <ᵤ 4#8)

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

@[simp] theorem Hom.castDomain_rfl {h : Δ = Δ} {f : Γ.Hom Δ} :
    (f.castCodomain h) = f

theorem multiuse_lshr_lshr_thm.extracted_1._2 : ∀ (x : BitVec 9),
  ¬(2#9 ≥ ↑9 ∨ 2#9 ≥ ↑9 ∨ 3#9 ≥ ↑9) → ¬(2#9 ≥ ↑9 ∨ 5#9 ≥ ↑9) → x >>> 2#9 * x >>> 2#9 >>> 3#9 = x >>> 2#9 * x >>> 5#9

theorem test_proof : test_before ⊑ test_after

theorem and1_lshr1_is_cmp_eq_0_proof : and1_lshr1_is_cmp_eq_0_before ⊑ and1_lshr1_is_cmp_eq_0_after

theorem test1_proof : test1_before ⊑ test1_after

theorem negative_not_power_of_two_logical_thm (e : IntW 32) :
  select (icmp IntPred.sgt e (const? 32 (-1))) (icmp IntPred.ult (add e (const? 32 255)) (const? 32 256))
      (const? 1 0) ⊑
    icmp IntPred.eq e (const? 32 0)

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

theorem src_is_mask_or_thm (e e_1 : IntW 8) :
  icmp IntPred.eq (LLVM.xor e_1 (const? 8 123))
      (LLVM.and (LLVM.and (lshr (const? 8 (-1)) e) (const? 8 7)) (LLVM.xor e_1 (const? 8 123))) ⊑
    icmp IntPred.ule (LLVM.xor e_1 (const? 8 123)) (LLVM.and (lshr (const? 8 (-1)) e) (const? 8 7))

theorem test39_proof : test39_before ⊑ test39_after

theorem icmp_slt_sext_ne_allones_nofold_proof : icmp_slt_sext_ne_allones_nofold_before ⊑ icmp_slt_sext_ne_allones_nofold_after

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 xor_with_or_disjoint_ba_proof : xor_with_or_disjoint_ba_before ⊑ xor_with_or_disjoint_ba_after

theorem bitwise_and_bitwise_and_icmps_comm2_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 8),
  ¬x ≥ ↑8 → True ∧ 1#8 <<< x >>> x ≠ 1#8 ∨ x ≥ ↑8 ∨ True ∧ 1#8 <<< x >>> x ≠ 1#8 ∨ x ≥ ↑8 → False

theorem simplify_and_common_op_commute2_thm (e e_1 e_2 e_3 : IntW 4) :
  LLVM.and (LLVM.xor (LLVM.or (LLVM.or (mul e_3 e_3) (LLVM.or e_2 e_1)) e) (const? 4 (-1))) e_2 ⊑ const? 4 0

theorem add_eq_xor_add_mul_and_nt (x y : BitVec w) :
    x + y = (x ^^^ y) + 2 * (x &&& y)

theorem sextinreg_alt_proof : sextinreg_alt_before ⊑ sextinreg_alt_after

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

theorem e_1712 :
     - 11 *  ~~~( ~~~a &&& (b ^^^ c)) + 5 *  ~~~( ~~~a &&& (b ||| c)) + 3 * ((a &&& b) |||  ~~~(b |||  ~~~c)) + 4 * ( ~~~(a ^^^ b) ||| (a ^^^ c)) + 11 * ((a &&&  ~~~b) ||| (a ^^^ (b ^^^ c))) - 2 * ((a &&& b) |||  ~~~(b ||| c)) + 1 * (b ^^^  ~~~( ~~~a &&& (b ||| c))) + 1 * ((b &&&  ~~~c) |||  ~~~(a ||| ( ~~~b &&& c))) - 1 * (a |||  ~~~b) + 2 * (b &&&  ~~~(a ^^^ c)) + 2 * (b ^^^ (a &&& ( ~~~b ||| c))) - 1 * (b ^^^  ~~~(a &&& (b ^^^ c))) - 2 *  ~~~a + 11 * (b ^^^ (a &&&  ~~~c)) + 3 *  ~~~( ~~~a &&& ( ~~~b &&& c)) + 2 * (a ||| (b &&& c)) - 1 * ((b &&&  ~~~c) |||  ~~~( ~~~a ||| ( ~~~b &&& c))) - 1 *  ~~~(a &&& b) - 1 * ((a &&& c) ^^^ (b ||| c)) + 2 * ((a &&& b) ^^^  ~~~(a ^^^ ( ~~~b ||| c))) - 1 * ( ~~~(a ||| b) ||| (b ^^^ c)) + 1 * (b ^^^  ~~~( ~~~a &&& ( ~~~b &&& c))) + 2 *  ~~~(a ||| (b ||| c)) - 32 *  ~~~(a ||| ( ~~~b ||| c)) - 30 *  ~~~( ~~~a ||| (b ||| c)) - 11 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 16 * ( ~~~a &&& ( ~~~b &&& c)) - 11 * ( ~~~a &&& (b &&& c)) - 18 * (a &&& ( ~~~b &&& c)) - 26 * (a &&& (b &&& c)) =  - 2 *  ~~~(a ^^^ (b ^^^ c)) - 5 * (c ^^^ (a ||| b))

theorem e_1655 :
    1 * ( ~~~(a ||| b) |||  ~~~(a ^^^ (b ^^^ c))) - 2 * (a |||  ~~~c) - 5 * (c &&& (a ^^^ b)) + 1 * (c &&&  ~~~(a &&& b)) + 2 * ((a ||| b) &&& (b ^^^ c)) - 7 * ((b &&& c) ^^^  ~~~( ~~~a &&& (b ^^^ c))) + 3 * (b &&& (a |||  ~~~c)) - 6 * ( ~~~(a &&& b) &&&  ~~~(a ^^^ (b ^^^ c))) + 1 * (b &&& c) - 1 * (b ^^^  ~~~( ~~~a &&& ( ~~~b &&& c))) + 5 * ( ~~~b |||  ~~~(a ^^^ c)) + 5 * (c ^^^  ~~~( ~~~a &&& ( ~~~b &&& c))) + 2 *  ~~~a + 11 * (c ||| (a ^^^ b)) - 2 * ((a &&&  ~~~b) ||| (b ^^^ c)) + 2 * (a &&&  ~~~c) - 1 * ( ~~~(a ^^^ b) &&&  ~~~(a ^^^ c)) - 24 *  ~~~(a ||| ( ~~~b ||| c)) - 11 *  ~~~( ~~~a ||| (b ||| c)) - 2 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 23 * ( ~~~a &&& ( ~~~b &&& c)) - 5 * ( ~~~a &&& (b &&& c)) + 3 * (a &&& ( ~~~b &&& c)) - 17 * (a &&& (b &&& c)) =  - 4 *  ~~~(a ||| (b ||| c))

theorem or_xor_tree_1000_proof : or_xor_tree_1000_before ⊑ or_xor_tree_1000_after

theorem shl_and_lshr_comm_thm.extracted_1._2 : ∀ (x x_1 x_2 : BitVec 32),
  ¬(True ∧ x_1 <<< x >>> x ≠ x_1 ∨ x ≥ ↑32 ∨ x ≥ ↑32) → ¬x ≥ ↑32 → (x_2 &&& x_1 <<< x) >>> x = x_2 >>> x &&& x_1

theorem mul_of_pow2s_thm (e e_1 : IntW 32) :
  LLVM.or (mul (LLVM.and e_1 (const? 32 8)) (LLVM.and e (const? 32 16))) (const? 32 128) ⊑ const? 32 128

theorem test6_proof : test6_before ⊑ test6_after

theorem shl_sub_lshr_reverse_proof : shl_sub_lshr_reverse_before ⊑ shl_sub_lshr_reverse_after

theorem test8_thm (e : IntW 32) : LLVM.srem (shl e (const? 32 4)) (const? 32 8) ⊑ const? 32 0

theorem t3_c0_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8), 42#8 - x_1 - x = 42#8 - (x_1 + x)

theorem sub_from_constant_commute_proof : sub_from_constant_commute_before ⊑ sub_from_constant_commute_after

theorem nonexact_ashr_ne_proof : nonexact_ashr_ne_before ⊑ nonexact_ashr_ne_after

theorem masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_6_thm (e : IntW 32) :
  LLVM.or (icmp IntPred.ne (LLVM.and e (const? 32 15)) (const? 32 8))
      (icmp IntPred.eq (LLVM.and e (const? 32 12)) (const? 32 0)) ⊑
    icmp IntPred.ne (LLVM.and e (const? 32 15)) (const? 32 8)

theorem p_constmask2_thm (e e_1 : IntW 32) :
  LLVM.or (LLVM.and e_1 (const? 32 61440)) (LLVM.and e (const? 32 (-65281))) ⊑
    LLVM.or (LLVM.and e_1 (const? 32 61440)) (LLVM.and e (const? 32 (-65281))) { «disjoint» := true }

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

theorem samesign_commute3_proof : samesign_commute3_before ⊑ samesign_commute3_after

theorem shrink_or_proof : shrink_or_before ⊑ shrink_or_after

theorem tryFactorization_xor_ashr_lshr_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬(x ≥ ↑32 ∨ x ≥ ↑32) →
    ¬x ≥ ↑32 → (BitVec.ofInt 32 (-3)).sshiftRight' x ^^^ 5#32 >>> x = (BitVec.ofInt 32 (-8)).sshiftRight' x

theorem foo1_and_signbit_lshr_without_shifting_signbit_both_sides_thm (e e_1 e_2 : IntW 32) :
  LLVM.or (icmp IntPred.sgt (shl e_2 e_1) (const? 32 (-1))) (icmp IntPred.sgt (shl e_2 e) (const? 32 (-1))) ⊑
    icmp IntPred.sgt (LLVM.and (shl e_2 e_1) (shl e_2 e)) (const? 32 (-1))

theorem sext_multiuse_proof : sext_multiuse_before ⊑ sext_multiuse_after

lemma simul_equiv {m : CNFA n} {M : NFA' n} :
    m.Sim M → m.toNFA'.M.Bisim M.M

theorem masked_icmps_mask_notallzeros_bmask_mixed_swapped_7_proof : masked_icmps_mask_notallzeros_bmask_mixed_swapped_7_before ⊑ masked_icmps_mask_notallzeros_bmask_mixed_swapped_7_after

theorem icmp_slt_0_and_icmp_sge_neg1_i32_proof : icmp_slt_0_and_icmp_sge_neg1_i32_before ⊑ icmp_slt_0_and_icmp_sge_neg1_i32_after

theorem test73_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬ofBool (-1#8 <ₛ truncate 8 x) = 1#1 → ofBool (x &&& 128#32 == 0#32) = 1#1 → 42#32 = 40#32

theorem negative_trunc_not_arg_logical_thm.extracted_1._3 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (-1#8 <ₛ truncate 8 x_1) = 1#1 →
    ofBool (x_1 &&& 128#32 == 0#32) = 1#1 → 0#1 = ofBool (x + 128#32 <ᵤ 256#32)

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

theorem icmp_sgt11_thm (e : IntW 8) :
  icmp IntPred.sgt (shl e (const? 8 7) { «nsw» := true, «nuw» := false }) (const? 8 (-2)) ⊑
    icmp IntPred.sgt e (const? 8 (-1))

theorem t4_thm (e : IntW 1) (e_1 : IntW 8) :
  sub e_1 (select e (const? 8 (-42)) (const? 8 44)) ⊑ add (select e (const? 8 42) (const? 8 (-44))) e_1

theorem test14_thm.extracted_1._1 : ∀ (x : BitVec 32) (x_1 : BitVec 64),
  ¬(x ≥ ↑32 ∨ zeroExtend 64 (1#32 <<< x) = 0) →
    True ∧ 1#32 <<< x >>> x ≠ 1#32 ∨ x ≥ ↑32 ∨ True ∧ (zeroExtend 64 (1#32 <<< x)).saddOverflow (-1#64) = true →
      False

theorem e_1120 :
     - 3 * (z ||| t) + 7 *  ~~~(z &&& t) + 2 *  ~~~(z &&&  ~~~t) + 1 *  ~~~z + 3 * (z ^^^ t) - 10 *  ~~~(z ||| t) - 10 *  ~~~(z |||  ~~~t) - 8 * (z &&&  ~~~t) =  - 1 * z

theorem foo_proof : foo_before ⊑ foo_after

theorem e_1477 :
    7 *  ~~~(z &&&  ~~~z) - 7 *  ~~~z - 6 *  ~~~(z &&&  ~~~t) + 5 *  ~~~(z &&& t) + 2 * (z |||  ~~~t) + 5 * (z ^^^ t) + 2 *  ~~~t - 3 *  ~~~(z ||| t) + 1 *  ~~~(z |||  ~~~t) - 21 * (z &&&  ~~~t) + 2 * (z &&& t) = 5 * t

theorem n3_constmask_samemask_proof : n3_constmask_samemask_before ⊑ n3_constmask_samemask_after

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

theorem ashrslt_02_11_exact_proof : ashrslt_02_11_exact_before ⊑ ashrslt_02_11_exact_after

theorem p_proof : p_before ⊑ p_after

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

theorem same_source_shifted_signbit_thm (e : IntW 32) : sext 32 (trunc 8 (lshr e (const? 32 24))) ⊑ ashr e (const? 32 24)

theorem select_icmp_eq_0_and_1_xor_1_proof : select_icmp_eq_0_and_1_xor_1_before ⊑ select_icmp_eq_0_and_1_xor_1_after

@[simp]
theorem Term.toBV_ofBool {wenv : WidthExpr.Env wcard}
    {tctx : Term.Ctx wcard tcard}
    (benv : Term.BoolEnv bcard)
    (tenv : tctx.Env wenv) (b : Term bcard ncard icard pcard tctx .bool) :
  Term.toBV benv nenv ienv penv tenv (.bvOfBool b) = BitVec.ofBool (b.toBV benv nenv ienv penv tenv)

theorem test14a_proof : test14a_before ⊑ test14a_after

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

theorem shl1_trunc_eq0_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬x ≥ ↑32 → ofBool (truncate 16 (1#32 <<< x) == 0#16) = ofBool (15#32 <ᵤ x)

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

theorem xor_lshr_multiuse_thm (e e_1 e_2 e_3 : IntW 8) :
  LLVM.sdiv (LLVM.xor (lshr e_3 e_2) e_1) (LLVM.xor (LLVM.xor (lshr e_3 e_2) e_1) (lshr e e_2)) ⊑
    LLVM.sdiv (LLVM.xor (lshr e_3 e_2) e_1) (LLVM.xor (lshr (LLVM.xor e_3 e) e_2) e_1)

theorem concat_false_self_EqualUpTo_ofBitVec_toBitVec_shiftConcat (x : BitStream) :
  EqualUpTo (w + 1) (BitStream.concat false x)
    (BitStream.ofBitVecSext ((x.toBitVec (w + 1)).shiftConcat false))

theorem test24_thm.extracted_1._1 : ∀ (x : BitVec 32), ofBool (1#32 <ₛ x) &&& ofBool (x != 2#32) = ofBool (2#32 <ₛ x)

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

theorem test_implied_true_proof : test_implied_true_before ⊑ test_implied_true_after

theorem t5_ugt_slt_0_thm.extracted_1._6 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (65535#32 <ᵤ x_1) = 1#1 → ofBool (65535#32 <ₛ x_1) = 1#1 → x_1 = x

theorem testi64i32_thm.extracted_1._1 : ∀ (x : BitVec 64),
  ¬(31#32 ≥ ↑32 ∨ 32#64 ≥ ↑64) →
    ofBool ((truncate 32 x).sshiftRight' 31#32 == truncate 32 (x >>> 32#64)) =
      ofBool (x + 2147483648#64 <ᵤ 4294967296#64)

theorem andn_or_cmp_2_logical_thm.extracted_1._1 : ∀ (x x_1 : BitVec 16) (x_2 : BitVec 1),
  ¬x_2 = 1#1 → ofBool (x ≤ₛ x_1) = 1#1 → ofBool (x_1 <ₛ x) = 0#1

theorem p_constmask_commutative_thm (e e_1 : IntW 32) :
  LLVM.xor (LLVM.and e_1 (const? 32 (-65281))) (LLVM.and e (const? 32 65280)) ⊑
    LLVM.or (LLVM.and e_1 (const? 32 (-65281))) (LLVM.and e (const? 32 65280)) { «disjoint» := true }

theorem positive_sameconst_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬(5#32 ≥ ↑32 ∨ 5#32 ≥ ↑32) → x <<< 5#32 >>> 5#32 = x &&& 134217727#32

theorem or_comm (x y : BitStream) : x ||

theorem ule_swap_or_min_commute_proof : ule_swap_or_min_commute_before ⊑ ule_swap_or_min_commute_after

theorem test43_thm.extracted_1._1 : ∀ (x : BitVec 8), True ∧ (zeroExtend 32 x).saddOverflow (-1#32) = true → False

theorem eq_optimized_highbits_cmp_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 ^^^ x <ᵤ 33554432#32) &&& ofBool (truncate 25 x == truncate 25 x_1) = ofBool (x_1 == x)

theorem bools_logical_thm.extracted_1._17 : ∀ (x x_1 x_2 : BitVec 1),
  ¬x_2 ^^^ 1#1 = 1#1 → ¬x_2 = 1#1 → 0#1 = 1#1 → 1#1 = x_1

theorem t10_almost_highest_bit_proof : t10_almost_highest_bit_before ⊑ t10_almost_highest_bit_after

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

theorem test1_proof : test1_before ⊑ test1_after

theorem one_side_fold_sgt_proof : one_side_fold_sgt_before ⊑ one_side_fold_sgt_after

theorem negtest_near_pow2_cmpval_would_overflow_into_signbit_proof : negtest_near_pow2_cmpval_would_overflow_into_signbit_before ⊑ negtest_near_pow2_cmpval_would_overflow_into_signbit_after

theorem splat_mul_known_lz_thm (e : IntW 32) :
  icmp IntPred.eq (lshr (mul (zext 128 e) (const? 128 18446744078004518913)) (const? 128 96)) (const? 128 0) ⊑
    const? 1 1

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

@[simp]
theorem Term.toBV_or {wenv : WidthExpr.Env wcard}
    {tctx : Term.Ctx wcard tcard}
    (benv : Term.BoolEnv bcard)
    (tenv : tctx.Env wenv)
    (p1 p2 : Term bcard ncard icard pcard tctx (.prop)) :
  Term.toBV benv nenv ienv penv tenv (.or p1 p2) = (p1.toBV benv nenv ienv penv tenv ∨ p2.toBV benv nenv ienv penv tenv)

theorem simplify_or_common_op_commute2_thm (e e_1 e_2 e_3 : IntW 4) :
  LLVM.or (LLVM.xor (LLVM.and (LLVM.and (mul e_3 e_3) (LLVM.and e_2 e_1)) e) (const? 4 (-1))) e_2 ⊑
    const? 4 (-1)

theorem main8_logical_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 64#32 != 0#32) = 1#1 → ofBool (x &&& 192#32 == 0#32) = 1#1 → True → 2#32 = 1#32

theorem differentconsts_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ofBool (x + 16#32 <ᵤ 144#32) = 1#1 →
    ¬ofBool (127#32 <ₛ x) = 1#1 → ofBool (x <ₛ BitVec.ofInt 32 (-16)) = 1#1 → truncate 16 x = 256#16

theorem main6b_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 7#32 == 3#32) &&& ofBool (x &&& 16#32 != 0#32) = 1#1 →
    0#32 = zeroExtend 32 (ofBool (x &&& 23#32 != 19#32))

theorem unsigned_sign_bit_extract_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬31#32 ≥ ↑32 → ofBool (x >>> 31#32 != 0#32) = ofBool (x <ₛ 0#32)

theorem ashrslt_03_05_exact_proof : ashrslt_03_05_exact_before ⊑ ashrslt_03_05_exact_after

theorem e_1367 :
    1 *  ~~~z + 3 * z - 2 * t - 1 * (z ||| t) - 2 *  ~~~(z &&&  ~~~z) + 1 *  ~~~(z &&&  ~~~t) - 7 * (z |||  ~~~t) + 4 *  ~~~(z ||| t) + 4 * (z &&&  ~~~t) + 8 * (z &&& t) =  - 3 *  ~~~(z &&& t)

lemma BitVec.ule_iff_ult_or_eq {w : ℕ} (bv1 bv2 : BitVec w):
    (bv1.ule bv2) = true ↔ (bv1.ult bv2) = true ∨ bv1 = bv2

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

theorem e_798 :
    3 *  ~~~(z ^^^ t) + 11 *  ~~~(z &&&  ~~~t) - 5 *  ~~~z - 6 *  ~~~(z |||  ~~~t) - 14 * (z &&& t) = 9 *  ~~~(z ||| t)

theorem e_2303 :
    11 * ((d &&& f) ^^^  ~~~(d ^^^ ( ~~~e &&& f))) - 2 *  ~~~(d ||| e) + 1 *  ~~~( ~~~d &&& ( ~~~e ||| f)) - 1 * (f ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) + 4 * ((d |||  ~~~e) &&& (d ^^^ (e ^^^ f))) + 7 *  ~~~( ~~~d &&& (e ||| f)) - 7 *  ~~~e + 4 * ( ~~~d &&& (e ||| f)) + 11 * ( ~~~(d &&& e) &&& (e ^^^ f)) - 2 * (e ^^^  ~~~( ~~~d ||| (e ^^^ f))) - 6 *  ~~~(d |||  ~~~f) - 5 * (e ^^^ (d &&& (e ||| f))) - 1 *  ~~~(d &&&  ~~~e) + 1 * ( ~~~e &&& (d ^^^ f)) - 3 * ((d &&&  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) - 3 * (e ^^^ ( ~~~d ||| ( ~~~e &&& f))) + 2 *  ~~~(d ||| ( ~~~e &&& f)) + 7 * (e ^^^ ( ~~~d ||| (e ^^^ f))) + 5 *  ~~~(d ^^^ e) + 5 * (f ^^^  ~~~(d ||| (e &&& f))) - 7 * (f ^^^  ~~~(d &&& (e &&& f))) + 3 * (f |||  ~~~(d |||  ~~~e)) - 11 * (f ^^^ ( ~~~d ||| (e &&& f))) + 5 * ( ~~~f &&&  ~~~(d ^^^ e)) + 3 * (f |||  ~~~(d ^^^ e)) + 2 * (e ^^^  ~~~(d &&& ( ~~~e &&& f))) + 7 * ((d &&& e) ^^^ (d ^^^ ( ~~~e ||| f))) - 1 * (d ^^^ ( ~~~e ||| f)) + 4 *  ~~~(d ^^^ (e ||| f)) - 5 * (d &&& e) + 11 * (d ^^^ (e ^^^ f)) - 6 * (e ^^^ (d &&&  ~~~f)) + 2 * (f ^^^  ~~~( ~~~d ||| (e &&& f))) + 1 *  ~~~(d &&& (e &&& f)) - 1 * (f ^^^ (d ||| ( ~~~e &&& f))) + 1 * (d ||| ( ~~~e &&& f)) - 3 *  ~~~(d &&& (e ||| f)) + 1 * ((d &&& e) ||| (d ^^^ (e ^^^ f))) - 5 * (f ^^^ ( ~~~d &&& ( ~~~e ||| f))) + 1 * (d &&& (e ||| f)) + 2 * ((d &&& e) |||  ~~~(e ||| f)) + 5 * ((d &&& f) ^^^ (d ^^^ ( ~~~e &&& f))) + 3 * ( ~~~(d &&& e) &&&  ~~~(d ^^^ (e ^^^ f))) + 1 * (f ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) - 5 * ( ~~~d ||| ( ~~~e &&& f)) - 2 * (f ^^^ ( ~~~d ||| (e ||| f))) + 3 * ( ~~~f |||  ~~~(d ^^^ e)) - 2 * ( ~~~d ||| (e ^^^ f)) + 7 * ((d ^^^ e) |||  ~~~(d ^^^ f)) + 1 * (f ^^^  ~~~(d &&& e)) - 2 * ((e &&&  ~~~f) ^^^ (d ||| (e ^^^ f))) - 1 *  ~~~(d ||| (e ^^^ f)) - 7 * (e &&&  ~~~(d &&&  ~~~f)) + 4 * (d ||| f) + 2 * ((d &&& e) ^^^  ~~~(d ^^^ (e &&& f))) - 25 *  ~~~(d ||| (e ||| f)) - 12 *  ~~~(d ||| ( ~~~e ||| f)) - 11 *  ~~~( ~~~d ||| (e ||| f)) - 9 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 34 * ( ~~~d &&& ( ~~~e &&& f)) - 8 * ( ~~~d &&& (e &&& f)) - 20 * (d &&& ( ~~~e &&& f)) - 43 * (d &&& (e &&& f)) = 11 * (d ^^^ ( ~~~e &&& f))

theorem e_832 :
    5 *  ~~~z - 8 *  ~~~(z ||| t) - 7 *  ~~~(z |||  ~~~t) - 2 * (z &&&  ~~~t) - 1 * (z &&& t) =  - 1 *  ~~~(z ^^^ t) - 2 *  ~~~(z &&& t)

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

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

theorem e_8 :
    1 * (x |||  ~~~y) - 1 * (x ||| y) - 2 *  ~~~(x ||| y) - 1 * (x &&& y) =  - 1 *  ~~~(x &&&  ~~~y)

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

theorem no_shift_no_xor_multiuse_xor_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 &&& 4096#32 == 0#32) = 1#1 → x * (x ^^^ 4096#32) = (x ^^^ x_1 &&& 4096#32) * (x ^^^ 4096#32)

theorem e_7 :
    11 *  ~~~(x &&&  ~~~y) - 11 * x + 11 * (x &&&  ~~~y) + 11 * (x &&& y) = 11 *  ~~~(x ||| y) + 11 * y

theorem poo_proof : poo_before ⊑ poo_after

theorem select_ashr_proof : select_ashr_before ⊑ select_ashr_after

theorem main7d_thm.extracted_1._2 : ∀ (x x_1 x_2 x_3 x_4 : BitVec 32),
  ¬ofBool (x_4 &&& (x_3 &&& x_2) == x_3 &&& x_2) &&& ofBool (x_4 &&& (x_1 &&& x) == x_1 &&& x) = 1#1 →
    1#32 = zeroExtend 32 (ofBool (x_4 &&& (x_3 &&& x_2 ||| x_1 &&& x) != x_3 &&& x_2 ||| x_1 &&& x))

theorem icmp_ult_8_proof : icmp_ult_8_before ⊑ icmp_ult_8_after

theorem not_or_or_not_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 32),
  ¬(x_2 == 0 || 32 != 1 && 42#32 == intMin 32 && x_2 == -1) = true →
    (42#32).sdiv x_2 ||

theorem shl_C1_add_A_C2_i32_thm.extracted_1._2 : ∀ (x : BitVec 16),
  ¬zeroExtend 32 x + 5#32 ≥ ↑32 →
    ¬(True ∧ x.msb = true ∨ zeroExtend 32 x ≥ ↑32) → 6#32 <<< (zeroExtend 32 x + 5#32) = 192#32 <<< zeroExtend 32 x

@[simp] lemma liftMaxSuccSucc1_cast {x : Fin n} : liftMaxSuccSucc1 n m x.castSucc = x.castLE (by omega)

theorem masked_icmps_mask_notallzeros_bmask_mixed_swapped_7b_proof : masked_icmps_mask_notallzeros_bmask_mixed_swapped_7b_before ⊑ masked_icmps_mask_notallzeros_bmask_mixed_swapped_7b_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 testi64i32_ne_thm.extracted_1._1 : ∀ (x : BitVec 64),
  ¬(31#32 ≥ ↑32 ∨ 32#64 ≥ ↑64) →
    ofBool ((truncate 32 x).sshiftRight' 31#32 != truncate 32 (x >>> 32#64)) =
      ofBool (x + BitVec.ofInt 64 (-2147483648) <ᵤ BitVec.ofInt 64 (-4294967296))

theorem ugt_umax4_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (x_1 + 3#32 <ᵤ x) = 1#1 → ofBool (x_1 + 3#32 <ᵤ x_1 + 3#32) = ofBool (x_1 + 3#32 <ᵤ x)

theorem xor_icmp_to_icmp_add_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (3#32 <ₛ x) ^^^ ofBool (x <ₛ 6#32) = ofBool (x + BitVec.ofInt 32 (-6) <ᵤ BitVec.ofInt 32 (-2))

theorem invert_signbit_splat_mask_thm (e : IntW 16) (e_1 : IntW 8) :
  LLVM.and (sext 16 (LLVM.xor (ashr e_1 (const? 8 7)) (const? 8 (-1)))) e ⊑
    select (icmp IntPred.sgt e_1 (const? 8 (-1))) e (const? 16 0)

theorem foo_proof : foo_before ⊑ foo_after

theorem ashrsgt_03_05_thm.extracted_1._1 : ∀ (x : BitVec 4), ¬3#4 ≥ ↑4 → ofBool (5#4 <ₛ x.sshiftRight' 3#4) = 0#1

theorem C0zero_thm (e e_1 e_2 : IntW 8) :
  select (icmp IntPred.ult (add e_2 (const? 8 10)) (const? 8 0)) e_2
      (select (icmp IntPred.slt e_2 (const? 8 (-10))) e_1 e) ⊑
    select (icmp IntPred.slt e_2 (const? 8 (-10))) e_1 e

theorem xor_icmp_invalid_range_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ofBool (x == 0#8) ^^^ ofBool (x != 4#8) = ofBool (x &&& BitVec.ofInt 8 (-5) != 0#8)

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

theorem add_nosignbit_select_shl_thm.extracted_1._1 : ∀ (x : BitVec 32) (x_1 : BitVec 1),
  x_1 = 1#1 → ¬8#32 ≥ ↑32 → (x + 2147418112#32) <<< 8#32 = x <<< 8#32 + BitVec.ofInt 32 (-16777216)

theorem t7_ugt_sgt_neg1_thm.extracted_1._12 : ∀ (x x_1 x_2 : BitVec 32),
  ofBool (143#32 <ᵤ x_2 + 16#32) = 1#1 →
    ¬ofBool (BitVec.ofInt 32 (-17) <ₛ x_2) = 1#1 → ofBool (127#32 <ₛ x_2) = 1#1 → x = x_1

theorem trunc_sel_larger_sext_proof : trunc_sel_larger_sext_before ⊑ trunc_sel_larger_sext_after

theorem add_shl_same_amount_proof : add_shl_same_amount_before ⊑ add_shl_same_amount_after

theorem or_eq_with_one_bit_diff_constants1_logical_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬ofBool (x == 50#32) = 1#1 → ofBool (x == 51#32) = ofBool (x &&& BitVec.ofInt 32 (-2) == 50#32)

theorem shl_and_proof : shl_and_before ⊑ shl_and_after

@[simp] lemma Deleted.toHom_append {Γ Γ' : Ctxt Ty} {vs : DeleteRange Γ}
    (DEL : Deleted (⟨us⟩ ++ Γ) vs.appendInl (⟨us⟩ ++ Γ')) :
    DEL.toHom
    = have DEL' : Deleted Γ vs Γ' := by
        rcases Γ'
        simp only [Deleted, Ctxt.delete_append_appendInl] at DEL ⊢
        injection DEL
        simp_all [Ctxt.delete]
      DEL'.toHom.append := by
  have DEL' : Deleted Γ vs Γ' := by
    rcases Γ'
    simp only [Deleted, Ctxt.delete_append_appendInl] at DEL ⊢
    injection DEL
    simp_all [Ctxt.delete]
  subst DEL'
  funext t v
  apply Subtype.ext
  simp only [toHom, Hom.delete, Var.val_castCtxt, DeleteRange.val_start_appendInl,
    DeleteRange.val_num_appendInl, Hom.append, Var.castCtxt_rfl]
  cases v using Var.appendCases with

theorem test20_proof : test20_before ⊑ test20_after

theorem e_944 :
    5 *  ~~~(z &&&  ~~~z) - 3 * (z ||| t) + 2 * t + 2 * z - 4 * (z &&&  ~~~t) - 6 * (z &&& t) = 5 *  ~~~(z ||| t) + 4 *  ~~~(z |||  ~~~t)

theorem bools_logical_commute0_and2_thm (e e_1 e_2 : IntW 1) :
  select (select (LLVM.xor e_2 (const? 1 1)) e_1 (const? 1 0)) (const? 1 1) (LLVM.and e_2 e) ⊑ select e_2 e e_1

theorem invert_both_cmp_operands_add_proof : invert_both_cmp_operands_add_before ⊑ invert_both_cmp_operands_add_after

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

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

theorem test10_thm (e : IntW 19) :
  shl (lshr e (const? 19 18)) (const? 19 18) ⊑ LLVM.and e (const? 19 (-262144))

theorem AvoidCollision_setWidth_append_append_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} {b'' : BitVec w''} {b''' : BitVec w'''} :
    (b ++ b' ++ b'' ++ b''').setWidth w'''' = (b.setWidth w'''' <<< (w' + w'' + w''')) ||

theorem and_orn_cmp_3_logical_proof : and_orn_cmp_3_logical_before ⊑ and_orn_cmp_3_logical_after

theorem ashr_ugt_5_proof : ashr_ugt_5_before ⊑ ashr_ugt_5_after

theorem sub_ashr_or_i8_proof : sub_ashr_or_i8_before ⊑ sub_ashr_or_i8_after

theorem sdiv_icmp3_proof : sdiv_icmp3_before ⊑ sdiv_icmp3_after

theorem zext_sext_add_icmp_ne_1_thm.extracted_1._1 : ∀ (x x_1 : BitVec 1),
  ofBool (zeroExtend 8 x_1 + signExtend 8 x != 1#8) = x ||

theorem ashrsgt_02_14_proof : ashrsgt_02_14_before ⊑ ashrsgt_02_14_after

theorem shl_and_add_thm (e e_1 : IntW 8) :
  add (shl e_1 (const? 8 1)) (LLVM.and (shl e (const? 8 1)) (const? 8 119)) ⊑
    shl (add e_1 (LLVM.and e (const? 8 59))) (const? 8 1)

theorem ugt_umax2_proof : ugt_umax2_before ⊑ ugt_umax2_after

theorem test5_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬8#32 ≥ ↑32 → ((x ^^^ 1234#32) >>> 8#32 ^^^ 1#32) + (x ^^^ 1234#32) = (x >>> 8#32 ^^^ 5#32) + (x ^^^ 1234#32)

theorem ule_or_min_proof : ule_or_min_before ⊑ ule_or_min_after

theorem or_and3_commuted_thm.extracted_1._8 : ∀ (x x_1 : BitVec 1) (x_2 x_3 : BitVec 32),
  ¬ofBool (x_3 == x_2) ||

@[simp] lemma BitVec.lk00 : (0#2 : BitVec 2)[0] = false

theorem fromTensor_toTensor [hqgt1 : Fact (q > 1)] (a : R q n)
    (adeg : (R.representative q n a).natDegree + 1 < 2^n) :
  R.fromTensor a.toTensor = a

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

theorem negate_select_of_op_vs_negated_op_nsw_thm.extracted_1._1 : ∀ (x : BitVec 8) (x_1 : BitVec 1) (x_2 : BitVec 8),
  x_1 = 1#1 → ¬(True ∧ (0#8).ssubOverflow x = true) → x_2 - (0#8 - x) = x + x_2

theorem test6_proof : test6_before ⊑ test6_after

theorem e_2062 :
    11 * (f ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) - 2 * (e ^^^  ~~~( ~~~d ||| ( ~~~e &&& f))) - 7 * (e ^^^ (d &&&  ~~~f)) - 5 * ((d &&& e) |||  ~~~(e |||  ~~~f)) + 3 * ( ~~~(d ^^^ e) |||  ~~~(d ^^^ f)) + 2 * (d ||| e) - 1 * (f ||| (d ^^^ e)) + 1 * ( ~~~e &&& (d ^^^ f)) + 1 * (e ^^^  ~~~(d &&& (e ^^^ f))) - 1 * (f ^^^  ~~~(d ||| ( ~~~e &&& f))) + 1 * ((d ||| e) &&& (e ^^^ f)) - 6 *  ~~~(d ||| (e ^^^ f)) - 3 * ((e &&& f) ^^^  ~~~(d &&& (e ^^^ f))) + 2 *  ~~~(d ^^^ ( ~~~e ||| f)) - 11 * ((d &&& e) ^^^  ~~~(d ^^^ (e &&& f))) - 2 *  ~~~(d ^^^ e) - 1 * ((d &&& e) ||| (e ^^^ f)) - 2 * (e |||  ~~~f) - 6 *  ~~~(d ^^^ (e ||| f)) + 2 * (e ^^^  ~~~(d ||| ( ~~~e &&& f))) + 2 * ( ~~~(d |||  ~~~e) ||| (d ^^^ (e ^^^ f))) - 6 * (f &&& (d ||| e)) - 2 * (d ^^^ ( ~~~e ||| f)) + 5 * (e ^^^  ~~~(d &&& (e ||| f))) - 5 * ( ~~~d &&& (e ^^^ f)) - 11 * (e &&&  ~~~f) + 5 * (f |||  ~~~(d ^^^ e)) - 11 * (d ||| (e ||| f)) + 5 *  ~~~(d ^^^ (e &&& f)) + 3 *  ~~~( ~~~d &&& ( ~~~e &&& f)) - 4 *  ~~~(d ||| (e ||| f)) + 26 *  ~~~(d ||| ( ~~~e ||| f)) - 1 *  ~~~( ~~~d ||| (e ||| f)) + 16 *  ~~~( ~~~d ||| ( ~~~e ||| f)) + 7 * ( ~~~d &&& ( ~~~e &&& f)) + 25 * ( ~~~d &&& (e &&& f)) + 13 * (d &&& ( ~~~e &&& f)) + 11 * (d &&& (e &&& f)) =  - 2 * (e ^^^ ( ~~~d ||| ( ~~~e &&& f)))

theorem PR2844_logical_thm.extracted_1._4 : ∀ (x : BitVec 32),
  ¬ofBool (x == 0#32) = 1#1 →
    ¬ofBool (x <ₛ BitVec.ofInt 32 (-638208501)) = 1#1 →
      1#32 = zeroExtend 32 (ofBool (x != 0#32) &&& ofBool (BitVec.ofInt 32 (-638208502) <ₛ x))

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 t4_ugt_slt_128_thm.extracted_1._5 : ∀ (x x_1 : BitVec 32),
  ¬ofBool (143#32 <ᵤ x_1 + 16#32) = 1#1 →
    ¬ofBool (127#32 <ₛ x_1) = 1#1 → ofBool (x_1 <ₛ BitVec.ofInt 32 (-16)) = 1#1 → x_1 = x

theorem test6_proof : test6_before ⊑ test6_after

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

theorem slt_and_shl_one_thm (e e_1 : IntW 8) :
  icmp IntPred.slt (LLVM.and e_1 (shl (const? 8 1) e)) (shl (const? 8 1) e) ⊑
    icmp IntPred.slt (LLVM.and e_1 (shl (const? 8 1) e { «nsw» := false, «nuw» := true }))
      (shl (const? 8 1) e { «nsw» := false, «nuw» := true })

theorem ult_to_slt_proof : ult_to_slt_before ⊑ ult_to_slt_after

theorem select_icmp_and_8_eq_0_xor_8_thm (e : IntW 32) :
  select (icmp IntPred.eq (LLVM.and e (const? 32 8)) (const? 32 0)) (LLVM.xor e (const? 32 8)) e ⊑
    LLVM.or e (const? 32 8)

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

theorem absdiff2_thm.extracted_1._1 : ∀ (x x_1 : BitVec 64),
  ofBool (x_1 <ᵤ x) = 1#1 →
    (x_1 - x ^^^ signExtend 64 (ofBool (x_1 <ᵤ x))) - signExtend 64 (ofBool (x_1 <ᵤ x)) = 0#64 - (x_1 - x)

theorem mul_of_sdiv_thm.extracted_1._2 : ∀ (x : BitVec 8),
  ¬(True ∧ x.smod 12#8 ≠ 0 ∨ (12#8 == 0 || 8 != 1 && x == intMin 8 && 12#8 == -1) = true) →
    ¬(True ∧ x >>> 1#8 <<< 1#8 ≠ x ∨ 1#8 ≥ ↑8 ∨ True ∧ (0#8).ssubOverflow (x.sshiftRight' 1#8) = true) →
      x.sdiv 12#8 * BitVec.ofInt 8 (-6) = 0#8 - x.sshiftRight' 1#8

theorem not_lshr_thm.extracted_1._1 : ∀ (x : BitVec 8), ¬5#8 ≥ ↑8 → x >>> 5#8 ^^^ 7#8 = (x ^^^ -1#8) >>> 5#8

theorem sgt_x_impliesF_eq_smin_todo_proof : sgt_x_impliesF_eq_smin_todo_before ⊑ sgt_x_impliesF_eq_smin_todo_after

theorem shl_add_nuw_and_nsw_proof : shl_add_nuw_and_nsw_before ⊑ shl_add_nuw_and_nsw_after

theorem e_926 :
    3 * z - 2 * t + 4 * (z ^^^ t) - 5 *  ~~~(z ||| t) - 12 * (z &&&  ~~~t) - 6 * (z &&& t) = 7 *  ~~~(z |||  ~~~t) - 5 *  ~~~(z &&&  ~~~z)

theorem test8_thm (e : IntW 32) :
  icmp IntPred.ugt (LLVM.udiv (const? 32 4) e) (const? 32 3) ⊑ icmp IntPred.ult e (const? 32 2)

theorem PR39793_bswap_u32_as_u16_trunc_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬(8#32 ≥ ↑32 ∨ 8#32 ≥ ↑32) →
    ¬8#32 ≥ ↑32 → truncate 8 (x >>> 8#32 &&& 255#32 ||| x <<< 8#32 &&& 65280#32) = truncate 8 (x >>> 8#32)

theorem sge_swap_or_not_max_commute_proof : sge_swap_or_not_max_commute_before ⊑ sge_swap_or_not_max_commute_after

theorem test4a_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬(31#32 ≥ ↑32 ∨ 31#32 ≥ ↑32) → ofBool (x.sshiftRight' 31#32 ||| (0#32 - x) >>> 31#32 <ₛ 1#32) = ofBool (x <ₛ 1#32)

theorem negate_ashr_thm (e e_1 : IntW 8) : sub e_1 (ashr e (const? 8 7)) ⊑ add (lshr e (const? 8 7)) e_1

theorem alive_AddSub_1560  (w : Nat)   : alive_AddSub_1560_src w  ⊑ alive_AddSub_1560_tgt w

theorem main2_logical_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 1#32 == 0#32) = 1#1 → True → 0#32 = zeroExtend 32 (ofBool (x &&& 3#32 == 3#32))

theorem sext_xor_sub_2_thm.extracted_1._2 : ∀ (x : BitVec 64) (x_1 : BitVec 1),
  ¬x_1 = 1#1 → signExtend 64 x_1 - (x ^^^ signExtend 64 x_1) = 0#64 - x

theorem sext_multiuse_thm.extracted_1._1 : ∀ (x : BitVec 4),
  ¬(True ∧ (zeroExtend 7 (x ^^^ BitVec.ofInt 4 (-8))).saddOverflow (BitVec.ofInt 7 (-8)) = true ∨
        (zeroExtend 7 (x ^^^ BitVec.ofInt 4 (-8)) + BitVec.ofInt 7 (-8) == 0 ||
              7 != 1 && zeroExtend 7 (x ^^^ BitVec.ofInt 4 (-8)) == intMin 7 &&
                zeroExtend 7 (x ^^^ BitVec.ofInt 4 (-8)) + BitVec.ofInt 7 (-8) == -1) =
            true ∨
          (x ^^^ BitVec.ofInt 4 (-8) == 0 ||
              4 != 1 &&
                  truncate 4
                      ((zeroExtend 7 (x ^^^ BitVec.ofInt 4 (-8))).sdiv
                        (zeroExtend 7 (x ^^^ BitVec.ofInt 4 (-8)) + BitVec.ofInt 7 (-8))) ==
                    intMin 4 &&
                x ^^^ BitVec.ofInt 4 (-8) == -1) =
            true) →
    (signExtend 7 x == 0 || 7 != 1 && zeroExtend 7 (x ^^^ BitVec.ofInt 4 (-8)) == intMin 7 && signExtend 7 x == -1) =
          true ∨
        (x ^^^ BitVec.ofInt 4 (-8) == 0 ||
            4 != 1 && truncate 4 ((zeroExtend 7 (x ^^^ BitVec.ofInt 4 (-8))).sdiv (signExtend 7 x)) == intMin 4 &&
              x ^^^ BitVec.ofInt 4 (-8) == -1) =
          true →
      False

theorem test3_apint_proof : test3_apint_before ⊑ test3_apint_after

theorem icmp_slt_0_xor_icmp_sge_neg2_i32_fail_proof : icmp_slt_0_xor_icmp_sge_neg2_i32_fail_before ⊑ icmp_slt_0_xor_icmp_sge_neg2_i32_fail_after

theorem sub_select_not_zext_thm.extracted_1._1 : ∀ (x : BitVec 1),
  ¬x = 1#1 → 64#64 - zeroExtend 64 (x ^^^ 1#1) = 63#64

theorem in_constant_6_vary_invmask_proof : in_constant_6_vary_invmask_before ⊑ in_constant_6_vary_invmask_after

theorem lt_signed_to_small_unsigned_proof : lt_signed_to_small_unsigned_before ⊑ lt_signed_to_small_unsigned_after

theorem or_test2_proof : or_test2_before ⊑ or_test2_after

theorem bools2_logical_commute3_and1_thm.extracted_1._4 : ∀ (x x_1 x_2 : BitVec 1),
  x_2 &&& x_1 = 1#1 → ¬x_1 = 1#1 → 1#1 = x

theorem zext_proof : zext_before ⊑ zext_after

theorem multiuse1_thm (e : IntW 32) :
  LLVM.or
      (LLVM.or (lshr (LLVM.and e (const? 32 2)) (const? 32 1) { «exact» := true })
        (lshr (LLVM.and e (const? 32 4)) (const? 32 1) { «exact» := true }))
      (LLVM.or (shl (LLVM.and e (const? 32 2)) (const? 32 6) { «nsw» := true, «nuw» := true })
        (shl (LLVM.and e (const? 32 4)) (const? 32 6) { «nsw» := true, «nuw» := true })) ⊑
    LLVM.or
      (LLVM.or (LLVM.and (lshr e (const? 32 1)) (const? 32 1)) (LLVM.and (lshr e (const? 32 1)) (const? 32 2))
        { «disjoint» := true })
      (LLVM.and (shl e (const? 32 6)) (const? 32 384)) { «disjoint» := true }

theorem icmp_slt_0_and_icmp_sge_neg1_i64_thm.extracted_1._1 : ∀ (x : BitVec 64),
  ¬63#64 ≥ ↑64 → x >>> 63#64 &&& zeroExtend 64 (ofBool (-1#64 ≤ₛ x)) = zeroExtend 64 (ofBool (x == -1#64))

theorem ashrslt_01_08_thm.extracted_1._1 : ∀ (x : BitVec 4),
  ¬1#4 ≥ ↑4 → ofBool (x.sshiftRight' 1#4 <ₛ BitVec.ofInt 4 (-8)) = 0#1

theorem test2_proof : test2_before ⊑ test2_after

theorem shl_lshr_demand6_proof : shl_lshr_demand6_before ⊑ shl_lshr_demand6_after

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

theorem ashr_not_thm (e : IntW 8) :
  ashr (LLVM.xor e (const? 8 (-1))) (const? 8 5) ⊑ LLVM.xor (ashr e (const? 8 5)) (const? 8 (-1))

theorem lshr_add_xor_fail_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ¬(1#8 ≥ ↑8 ∨ 1#8 ≥ ↑8) → 1#8 ≥ ↑8 ∨ 1#8 ≥ ↑8 ∨ True ∧ (x >>> 1#8).uaddOverflow 123#8 = true → False

theorem test_sub_nuw_nsw__nuw_is_safe_proof : test_sub_nuw_nsw__nuw_is_safe_before ⊑ test_sub_nuw_nsw__nuw_is_safe_after

theorem e_938 :
    11 *  ~~~(z &&& t) + 4 *  ~~~(z &&&  ~~~t) + 3 * (z ||| t) - 26 *  ~~~(z ||| t) - 25 * (z &&&  ~~~t) - 7 * (z &&& t) = 18 *  ~~~(z |||  ~~~t) - 11 *  ~~~t

theorem icmp_select_implied_cond_swapped_select_thm (e e_1 : IntW 8) :
  icmp IntPred.eq (select (icmp IntPred.eq e_1 (const? 8 0)) e (const? 8 0)) e_1 ⊑
    select (icmp IntPred.eq e_1 (const? 8 0)) (icmp IntPred.eq e (const? 8 0)) (const? 1 0)

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

theorem trunc_shl_33_i32_i64_thm.extracted_1._1 : ∀ (x : BitVec 64), ¬33#64 ≥ ↑64 → truncate 32 (x <<< 33#64) = 0#32

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

theorem shl1_trunc_sgt0_proof : shl1_trunc_sgt0_before ⊑ shl1_trunc_sgt0_after

theorem slt_x_impliesT_ne_smin_todo_proof : slt_x_impliesT_ne_smin_todo_before ⊑ slt_x_impliesT_ne_smin_todo_after

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

theorem test_logical_or_eq_a_b_proof : test_logical_or_eq_a_b_before ⊑ test_logical_or_eq_a_b_after

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

theorem e_660 :
    5 *  ~~~(x &&& y) + 2 *  ~~~(x &&&  ~~~y) + 1 *  ~~~(x ^^^ y) + 1 * (x ||| y) + 1 * (x ^^^ y) - 11 * x - 2 *  ~~~(x ||| y) - 9 *  ~~~(x |||  ~~~y) + 10 * (x &&&  ~~~y) + 7 * (x &&& y) = 6 *  ~~~y

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

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

theorem test5_proof : test5_before ⊑ test5_after

theorem add_select_not_sext_thm (e : IntW 1) :
  add (select e (const? 64 64) (const? 64 1)) (sext 64 (LLVM.xor e (const? 1 1))) ⊑
    select e (const? 64 64) (const? 64 0)

theorem p1_ugt_proof : p1_ugt_before ⊑ p1_ugt_after

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

theorem e_2067 :
     - 1 * ( ~~~(d &&&  ~~~e) &&& (d ^^^ (e ^^^ f))) - 11 * (e &&& (d |||  ~~~f)) - 11 * (f ^^^ (d &&& (e ||| f))) + 2 * ((d &&& e) ^^^ (d ^^^ ( ~~~e ||| f))) - 1 * ((d |||  ~~~e) &&&  ~~~(e ^^^ f)) - 1 * (d |||  ~~~e) - 1 * (f ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) + 2 * (e ^^^ ( ~~~d ||| ( ~~~e &&& f))) + 1 * (e ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) - 6 * ( ~~~(d &&&  ~~~e) &&& (e ^^^ f)) - 1 * ( ~~~(d &&&  ~~~e) &&&  ~~~(e ^^^ f)) - 3 * (e ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) + 1 * ((d &&& f) ^^^  ~~~(d ^^^ (e &&& f))) + 1 * ( ~~~(d ^^^ e) ||| (d ^^^ f)) - 6 * (f ^^^ ( ~~~d ||| ( ~~~e ||| f))) - 7 * ( ~~~d ||| ( ~~~e ||| f)) + 2 * (e ^^^  ~~~(d ||| f)) - 5 * (d |||  ~~~f) - 2 * (e |||  ~~~(d ||| f)) - 2 * (f ^^^  ~~~(d &&& (e ||| f))) + 1 * (e |||  ~~~(d |||  ~~~f)) + 3 * ( ~~~d &&& (e ^^^ f)) + 1 * ( ~~~(d &&& e) &&& (e ^^^ f)) - 1 * (e ^^^ (d ||| ( ~~~e &&& f))) + 1 * (e ||| (d ^^^ f)) + 11 * ( ~~~e ||| (d ^^^ f)) + 11 * (e ^^^  ~~~( ~~~d &&& (e &&& f))) - 1 * (f ^^^  ~~~(d |||  ~~~e)) + 2 * (f &&& (d |||  ~~~e)) + 1 * (d ^^^ f) - 1 * ((d &&& e) |||  ~~~(e |||  ~~~f)) - 4 *  ~~~(d ||| (e ||| f)) + 33 *  ~~~(d ||| ( ~~~e ||| f)) - 2 *  ~~~( ~~~d ||| (e ||| f)) + 16 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 10 * ( ~~~d &&& ( ~~~e &&& f)) - 9 * ( ~~~d &&& (e &&& f)) - 11 * (d &&& ( ~~~e &&& f)) + 19 * (d &&& (e &&& f)) =  - 3 *  ~~~( ~~~d &&& (e &&& f))

theorem and_logic_and_logic_or_8_proof : and_logic_and_logic_or_8_before ⊑ and_logic_and_logic_or_8_after

theorem nomask_rhs_logical_thm (e : IntW 32) :
  select (icmp IntPred.eq (LLVM.and e (const? 32 1)) (const? 32 0)) (const? 1 1)
      (icmp IntPred.eq e (const? 32 0)) ⊑
    icmp IntPred.eq (LLVM.and e (const? 32 1)) (const? 32 0)

theorem logical_and_bitwise_and_icmps_comm1_proof : logical_and_bitwise_and_icmps_comm1_before ⊑ logical_and_bitwise_and_icmps_comm1_after

theorem substitute_constant_or_ne_swap_sle_logical_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ¬ofBool (x_1 != 42#8) = 1#1 → ofBool (x ≤ₛ x_1) = ofBool (x <ₛ 43#8)

theorem test_ashr_exact__exact_is_unsafe_thm (e : IntW 64) (e_1 : IntW 32) :
  select (icmp IntPred.eq (LLVM.and e_1 (const? 32 (-2147483585))) (const? 32 0)) e
      (ashr e (zext 64 (ashr (LLVM.and e_1 (const? 32 (-2147483585))) (const? 32 2) { «exact» := true }))) ⊑
    ashr e (zext 64 (LLVM.and (ashr e_1 (const? 32 2)) (const? 32 (-536870897))) { «nneg» := true })

theorem positive_sameconst_proof : positive_sameconst_before ⊑ positive_sameconst_after

theorem t20_thm.extracted_1._1 : ∀ (x : BitVec 16) (x_1 : BitVec 8),
  ¬x ≥ ↑16 → x_1 - truncate 8 (BitVec.ofInt 16 (-42) <<< x) = x_1 + truncate 8 (42#16 <<< x)

theorem udiv_i32_proof : udiv_i32_before ⊑ udiv_i32_after

theorem e_1508 :
     - 1 * (b |||  ~~~(a |||  ~~~c)) - 5 * ( ~~~(a &&& b) &&&  ~~~(b ^^^ c)) + 7 * (b &&&  ~~~(a ^^^ c)) - 1 * (c ^^^ ( ~~~a ||| (b ||| c))) + 6 *  ~~~(a ||| (b ||| c)) - 5 *  ~~~(a ||| ( ~~~b ||| c)) + 5 *  ~~~( ~~~a ||| (b ||| c)) + 6 * ( ~~~a &&& (b &&& c)) - 6 * (a &&& (b &&& c)) =  - 2 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 1 * ( ~~~a &&& ( ~~~b &&& c))

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

theorem ne_smin1_proof : ne_smin1_before ⊑ ne_smin1_after

theorem t0_ult_slt_128_thm.extracted_1._12 : ∀ (x x_1 x_2 : BitVec 32),
  ¬ofBool (x_2 + 16#32 <ᵤ 144#32) = 1#1 → ofBool (x_2 <ₛ 128#32) = 1#1 → ofBool (127#32 <ₛ x_2) = 1#1 → x_1 = x

theorem test_shl_nsw__all_are_safe_thm.extracted_1._4 : ∀ (x : BitVec 64) (x_1 : BitVec 32),
  ¬ofBool (x_1 &&& 15#32 == 0#32) = 1#1 →
    ¬(True ∧ ((x_1 &&& 15#32) <<< 2#32).sshiftRight' 2#32 ≠ x_1 &&& 15#32 ∨
          2#32 ≥ ↑32 ∨ zeroExtend 64 ((x_1 &&& 15#32) <<< 2#32) ≥ ↑64) →
      ¬(2#32 ≥ ↑32 ∨ True ∧ (x_1 <<< 2#32 &&& 60#32).msb = true ∨ zeroExtend 64 (x_1 <<< 2#32 &&& 60#32) ≥ ↑64) →
        x.sshiftRight' (zeroExtend 64 ((x_1 &&& 15#32) <<< 2#32)) =
          x.sshiftRight' (zeroExtend 64 (x_1 <<< 2#32 &&& 60#32))

theorem testi64i32_ne_thm.extracted_1._1 : ∀ (x : BitVec 64),
  ¬(31#32 ≥ ↑32 ∨ 32#64 ≥ ↑64) →
    ofBool ((truncate 32 x).sshiftRight' 31#32 != truncate 32 (x >>> 32#64)) =
      ofBool (x + BitVec.ofInt 64 (-2147483648) <ᵤ BitVec.ofInt 64 (-4294967296))

theorem cond_eq_or_const_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ¬ofBool (x_1 != 10#8) = 1#1 → ofBool (x_1 <ᵤ x) = ofBool (10#8 <ᵤ x)

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

theorem lshrugt_01_09_exact_proof : lshrugt_01_09_exact_before ⊑ lshrugt_01_09_exact_after

theorem test5_proof : test5_before ⊑ test5_after

theorem add_mask_ashr28_i32_thm (e : IntW 32) :
  add (LLVM.and (ashr e (const? 32 28)) (const? 32 8)) (ashr e (const? 32 28)) ⊑
    LLVM.and (lshr e (const? 32 28)) (const? 32 7)

theorem e_2033 :
    1 *  ~~~(d &&& f) - 1 * (e ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) + 5 * (e ^^^ ( ~~~d ||| (e ||| f))) - 5 * (e ^^^  ~~~(d &&& (e ^^^ f))) + 2 * (f ^^^  ~~~(d &&& e)) - 3 * (e &&& (d ^^^ f)) + 2 * (e &&&  ~~~f) - 2 * ( ~~~d ||| (e &&& f)) + 11 * (d ^^^ f) + 2 * (e ^^^  ~~~( ~~~d ||| (e &&& f))) + 11 * (e ||| (d &&& f)) - 11 * ((e &&& f) ||| ( ~~~d &&& (e ||| f))) + 2 * (f ^^^  ~~~( ~~~d &&& (e &&& f))) - 3 * (d |||  ~~~e) - 2 * ((d &&& f) ^^^ (e ||| f)) + 1 * ((d |||  ~~~e) &&&  ~~~(e ^^^ f)) + 1 * (d &&&  ~~~f) + 5 * (d ||| (e &&& f)) - 5 * (e ^^^  ~~~(d ||| f)) + 4 * ( ~~~(d |||  ~~~e) |||  ~~~(e ^^^ f)) + 1 * ((d &&& e) |||  ~~~(e ||| f)) + 1 * ((e &&& f) ^^^  ~~~(d &&& (e ^^^ f))) + 1 *  ~~~(d &&& ( ~~~e ||| f)) - 6 * (d ^^^ (e ^^^ f)) - 1 * (f ^^^  ~~~(d ||| ( ~~~e &&& f))) - 1 * (e ^^^  ~~~(d &&& ( ~~~e ||| f))) - 1 * (e &&& f) + 4 * ((e &&&  ~~~f) |||  ~~~(d ||| ( ~~~e &&& f))) - 4 *  ~~~(d ||| (e ||| f)) - 16 *  ~~~( ~~~d ||| (e ||| f)) - 21 *  ~~~( ~~~d ||| ( ~~~e ||| f)) + 12 * ( ~~~d &&& ( ~~~e &&& f)) - 17 * ( ~~~d &&& (e &&& f)) - 18 * (d &&& ( ~~~e &&& f)) + 4 * (d &&& (e &&& f)) = 8 *  ~~~(d ||| ( ~~~e ||| f))

theorem positive_with_aggressive_icmp_logical_proof : positive_with_aggressive_icmp_logical_before ⊑ positive_with_aggressive_icmp_logical_after

theorem mul_of_udiv_fail_bad_remainder_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬(True ∧ x.umod 11#8 ≠ 0 ∨ 11#8 = 0) →
    True ∧ x.umod 11#8 ≠ 0 ∨ 11#8 = 0 ∨ True ∧ (x / 11#8).umulOverflow 6#8 = true → False

theorem icmp_slt_0_and_icmp_sge_neg1_i64_fail_thm.extracted_1._1 : ∀ (x : BitVec 64),
  ¬62#64 ≥ ↑64 →
    ofBool (BitVec.ofInt 64 (-2) <ₛ x) = 1#1 →
      x >>> 62#64 &&& zeroExtend 64 (ofBool (-1#64 ≤ₛ x)) = x >>> 62#64 &&& 1#64

theorem shl_trunc_bigger_lshr_thm (e : IntW 32) :
  shl (trunc 8 (lshr e (const? 32 5))) (const? 8 3) ⊑ LLVM.and (trunc 8 (lshr e (const? 32 2))) (const? 8 (-8))

theorem PR42691_7_proof : PR42691_7_before ⊑ PR42691_7_after

theorem sgt_smax3_thm (e e_1 : IntW 32) :
  icmp IntPred.slt (add e_1 (const? 32 3))
      (select (icmp IntPred.sgt (add e_1 (const? 32 3)) e) (add e_1 (const? 32 3)) e) ⊑
    icmp IntPred.sgt e (add e_1 (const? 32 3))

theorem ult_umin3_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 + 3#32 <ᵤ x) = 1#1 → ofBool (x_1 + 3#32 <ᵤ x_1 + 3#32) = ofBool (x <ᵤ x_1 + 3#32)

theorem select_add_icmp_bad_thm.extracted_1._2 : ∀ (x x_1 x_2 : BitVec 32),
  ofBool (x_2 == 1#32) = 1#1 → x_2 + x_1 = x_1 + 1#32

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

theorem e_640 :
     - 7 * y + 1 *  ~~~y + 4 *  ~~~(x &&& y) - 7 *  ~~~x - 11 * (x ^^^ y) - 1 * (x ||| y) - 1 *  ~~~(x ||| y) + 22 *  ~~~(x |||  ~~~y) + 7 * (x &&&  ~~~y) + 5 * (x &&& y) =  - 3 *  ~~~(x ^^^ y)

theorem t6_ugt_sgt_128_thm (e e_1 e_2 : IntW 32) :
  select (icmp IntPred.ugt (add e_2 (const? 32 16)) (const? 32 143))
      (select (icmp IntPred.sgt e_2 (const? 32 127)) e_1 e) e_2 ⊑
    select (icmp IntPred.sgt e_2 (const? 32 127)) e_1
      (select (icmp IntPred.slt e_2 (const? 32 (-16))) e e_2)

theorem icmp_select_var_select_thm.extracted_1._1 : ∀ (x : BitVec 8) (x_1 : BitVec 1),
  x_1 = 1#1 → ofBool (x == 0#8) = 1#1 ∧ x_1 = 1#1 → ofBool (x == 0#8) = 1#1 → True → ofBool (x == x) = 1#1

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

theorem e_950 :
     - 1 * (z |||  ~~~t) - 3 *  ~~~(z &&&  ~~~z) - 6 * (z ||| t) + 9 *  ~~~(z |||  ~~~t) + 10 * (z &&&  ~~~t) + 6 * (z &&& t) =  - 4 *  ~~~(z ^^^ t)

theorem set_shl_mask_proof : set_shl_mask_before ⊑ set_shl_mask_after

theorem p_constmask_thm (e e_1 : IntW 32) :
  LLVM.or (LLVM.and e_1 (const? 32 65280)) (LLVM.and e (const? 32 (-65281))) ⊑
    LLVM.or (LLVM.and e_1 (const? 32 65280)) (LLVM.and e (const? 32 (-65281))) { «disjoint» := true }

theorem trunc_ashr_proof : trunc_ashr_before ⊑ trunc_ashr_after

theorem t4_thm.extracted_1._2 : ∀ (x : BitVec 1) (x_1 : BitVec 8), ¬x = 1#1 → x_1 - 44#8 = BitVec.ofInt 8 (-44) + x_1

theorem lshr_not_nneg2_thm.extracted_1._2 : ∀ (x : BitVec 8),
  ¬1#8 ≥ ↑8 →
    ¬(1#8 ≥ ↑8 ∨ True ∧ (x >>> 1#8 &&& BitVec.ofInt 8 (-128) != 0) = true) →
      (x ^^^ -1#8) >>> 1#8 ^^^ -1#8 = x >>> 1#8 ||

theorem mul_add_to_mul_7_thm.extracted_1._2 : ∀ (x : BitVec 16),
  ¬(True ∧ x.smulOverflow 32767#16 = true ∨ True ∧ x.saddOverflow (x * 32767#16) = true) →
    ¬15#16 ≥ ↑16 → x + x * 32767#16 = x <<< 15#16

theorem trunc_equality_both_thm (e e_1 : IntW 16) :
  icmp IntPred.eq (trunc 8 e_1 { «nsw» := true, «nuw» := true }) (trunc 8 e { «nsw» := true, «nuw» := true }) ⊑
    icmp IntPred.eq e_1 e

theorem xor_i8_to_i64_shl_save_and_ne_thm.extracted_1._4 : ∀ (x : BitVec 64) (x_1 : BitVec 8),
  ¬ofBool (x_1 &&& 1#8 != 0#8) = 1#1 → ¬63#64 ≥ ↑64 → x = x ^^^ zeroExtend 64 x_1 <<< 63#64

theorem e_1925 :
    7 * (c ^^^  ~~~(a &&&  ~~~b)) + 1 * (b ^^^ ( ~~~a ||| ( ~~~b ||| c))) + 3 * ((b &&& c) ||| (a &&& (b ||| c))) + 1 * ( ~~~b ||| (a ^^^ c)) - 1 *  ~~~(a ^^^ ( ~~~b ||| c)) - 3 * (c |||  ~~~(a |||  ~~~b)) + 1 * ( ~~~a ||| ( ~~~b &&& c)) - 7 *  ~~~( ~~~a &&& ( ~~~b ||| c)) - 6 *  ~~~( ~~~a ||| ( ~~~b &&& c)) + 4 * ((a |||  ~~~b) &&&  ~~~(a ^^^ (b ^^^ c))) + 1 * (c ^^^ ( ~~~a ||| (b ||| c))) + 11 * ( ~~~c |||  ~~~(a ^^^ b)) - 1 * (c ||| (a &&& b)) + 11 * (b ^^^  ~~~(a &&& (b ^^^ c))) - 7 * (a ||| (b ||| c)) + 4 * (b ^^^ ( ~~~a &&& ( ~~~b ||| c))) + 11 * (b &&& c) + 1 * (a &&& ( ~~~b ||| c)) + 5 * (c ^^^  ~~~(a ||| ( ~~~b &&& c))) + 2 * ((a &&& c) ^^^ (b ||| c)) + 7 *  ~~~(a &&& b) + 2 * ( ~~~(a &&& b) &&&  ~~~(a ^^^ (b ^^^ c))) + 7 * ((a &&& c) |||  ~~~(b ||| c)) - 5 * ( ~~~a ||| ( ~~~b ||| c)) + 3 * (b ^^^  ~~~(a &&& (b ||| c))) + 7 * b - 6 * ((a &&& c) ^^^  ~~~(a ^^^ ( ~~~b &&& c))) - 6 * ((a &&&  ~~~b) ||| (b ^^^ c)) - 1 * ( ~~~a &&& (b ^^^ c)) + 3 * ((a &&& c) ^^^  ~~~(a ^^^ (b &&& c))) + 2 * (b ^^^  ~~~(a &&& (b &&& c))) + 3 *  ~~~c + 1 * ( ~~~c &&&  ~~~(a ^^^ b)) - 3 * ( ~~~a &&& ( ~~~b ||| c)) + 1 * (c ^^^  ~~~( ~~~a &&& ( ~~~b &&& c))) - 7 * ((b &&&  ~~~c) |||  ~~~(a ||| ( ~~~b &&& c))) + 1 * (a ||| (b &&& c)) - 11 * (c ^^^  ~~~( ~~~a ||| ( ~~~b &&& c))) + 7 * (c ^^^ (a &&& b)) - 3 * (c ^^^ (a &&& ( ~~~b ||| c))) - 2 * ( ~~~(a ||| b) |||  ~~~(b ^^^ c)) + 2 * ( ~~~(a ||| b) ||| (a ^^^ (b ^^^ c))) - 11 * (c ^^^ ( ~~~a ||| ( ~~~b ||| c))) - 6 * (a &&& (b ^^^ c)) - 43 *  ~~~(a ||| (b ||| c)) + 5 *  ~~~(a ||| ( ~~~b ||| c)) + 8 *  ~~~( ~~~a ||| (b ||| c)) - 17 *  ~~~( ~~~a ||| ( ~~~b ||| c)) - 19 * ( ~~~a &&& ( ~~~b &&& c)) + 6 * ( ~~~a &&& (b &&& c)) - 14 * (a &&& (b &&& c)) = 5 * (c ^^^ ( ~~~a &&& (b ||| c)))

theorem test1_thm (e e_1 : IntW 32) :
  icmp IntPred.ne (LLVM.and e_1 (const? 32 65280)) (LLVM.and e (const? 32 65280)) ⊑
    icmp IntPred.ne (LLVM.and (LLVM.xor e_1 e) (const? 32 65280)) (const? 32 0)

theorem icmp_slt_0_and_icmp_sge_neg2_i64_thm.extracted_1._1 : ∀ (x : BitVec 64),
  ¬63#64 ≥ ↑64 →
    x >>> 63#64 &&& zeroExtend 64 (ofBool (BitVec.ofInt 64 (-2) ≤ₛ x)) =
      zeroExtend 64 (ofBool (BitVec.ofInt 64 (-3) <ᵤ x))

theorem or_and2_commuted_thm.extracted_1._5 : ∀ (x x_1 x_2 : BitVec 1),
  x_2 ||

@[simp]
lemma Set.mem_cast (A : W → Type) (P : A w → Prop) (h : w = w') (x : A w') :
  x ∈ h ▸ setOf P ↔
  P (h ▸ x)

theorem evalWith_succ_eq_evalWith_delta' (p : FSM arity) (carryState : p.α → Bool)
      (x : arity → BitStream) :
  p.evalWith carryState x (n + 1) =
  p.evalWith (p.delta' carryState (fun s => x s 0)) (fun s i => x s (i + 1)) n

theorem test55_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬(True ∧ (truncate 16 x &&& 7224#16 &&& BitVec.ofInt 16 (-32574) != 0) = true) →
    signExtend 64 ((truncate 16 x ||| BitVec.ofInt 16 (-32574)) &&& BitVec.ofInt 16 (-25350)) =
      signExtend 64 (truncate 16 x &&& 7224#16 ||| BitVec.ofInt 16 (-32574))

theorem or_disjoint_with_xor_proof : or_disjoint_with_xor_before ⊑ or_disjoint_with_xor_after

theorem ashrsgt_03_11_exact_thm.extracted_1._1 : ∀ (x : BitVec 4),
  ¬(True ∧ x >>> 3#4 <<< 3#4 ≠ x ∨ 3#4 ≥ ↑4) → ofBool (BitVec.ofInt 4 (-5) <ₛ x.sshiftRight' 3#4) = 1#1

theorem masked_icmps_bmask_notmixed_and_expected_false_proof : masked_icmps_bmask_notmixed_and_expected_false_before ⊑ masked_icmps_bmask_notmixed_and_expected_false_after

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

theorem icmp_slt_sext_ne_zero_nofold_proof : icmp_slt_sext_ne_zero_nofold_before ⊑ icmp_slt_sext_ne_zero_nofold_after

theorem t8_lshr_exact_flag_preservation_thm (e e_1 : IntW 32) :
  lshr (lshr e_1 (sub (const? 32 32) e) { «exact» := true }) (add e (const? 32 (-2))) { «exact» := true } ⊑
    lshr e_1 (const? 32 30) { «exact» := true }

theorem ashr_sgt_noexact_thm (e : IntW 8) :
  icmp IntPred.sgt (ashr e (const? 8 3)) (const? 8 10) ⊑ icmp IntPred.sgt e (const? 8 87)

theorem and_and_logic_or_1_thm.extracted_1._1 : ∀ (x x_1 : BitVec 1), x_1 &&& x = 1#1 → x = 1#1 → 1#1 = x_1 &&& 1#1

theorem test15b_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 32#32 == 0#32) = 1#1 → 32#32 = x &&& 32#32 ^^^ 32#32

theorem t0_commutative_proof : t0_commutative_before ⊑ t0_commutative_after

theorem ugt_rem_zero_nsw_proof : ugt_rem_zero_nsw_before ⊑ ugt_rem_zero_nsw_after

theorem shr_umax_proof : shr_umax_before ⊑ shr_umax_after

theorem both_proof : both_before ⊑ both_after

theorem n9_proof : n9_before ⊑ n9_after

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

theorem prove_exact_with_high_mask_proof : prove_exact_with_high_mask_before ⊑ prove_exact_with_high_mask_after

theorem negate_select_of_op_vs_negated_op_nsw_xyyx_thm.extracted_1._2 : ∀ (x x_1 : BitVec 8) (x_2 : BitVec 1)
  (x_3 : BitVec 8), ¬x_2 = 1#1 → ¬(True ∧ x.ssubOverflow x_1 = true) → x_3 - (x - x_1) = x_1 - x + x_3

@[bv_multi_width_normalize] theorem ofBool_xor_ofBool (x y : Bool) :
  (BitVec.ofBool x ^^^ BitVec.ofBool y) = BitVec.ofBool (x ^^ y)

theorem positive_biggerShl_thm (e : IntW 32) :
  lshr (shl e (const? 32 10)) (const? 32 5) ⊑ LLVM.and (shl e (const? 32 5)) (const? 32 134217696)

theorem mul_of_bools_thm (e e_1 : IntW 32) :
  icmp IntPred.ult (mul (LLVM.and e_1 (const? 32 1)) (LLVM.and e (const? 32 1))) (const? 32 2) ⊑
    const? 1 1

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

theorem test9_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x &&& 1073741824#32 != 0#32) &&& ofBool (-1#32 <ₛ x) =
    ofBool (x &&& BitVec.ofInt 32 (-1073741824) == 1073741824#32)

theorem test2_thm (e : IntW 1) : LLVM.xor e e ⊑ const? 1 0

theorem test1_thm.extracted_1._1 : ∀ (x x_1 : BitVec 33),
  ofBool (x_1 &&& 65280#33 != x &&& 65280#33) = ofBool ((x_1 ^^^ x) &&& 65280#33 != 0#33)

theorem test_ult_xor_proof : test_ult_xor_before ⊑ test_ult_xor_after

theorem e_12 :
     - 3 *  ~~~(x &&&  ~~~x) + 1 *  ~~~x + 2 * (x &&&  ~~~y) + 4 * (x &&& y) =  - 2 *  ~~~(x &&& y) + 1 * x

theorem masked_or_allzeroes_notoptimised_logical_proof : masked_or_allzeroes_notoptimised_logical_before ⊑ masked_or_allzeroes_notoptimised_logical_after

theorem mul_select_zext_thm.extracted_1._1 : ∀ (x : BitVec 1), ¬x = 1#1 → 1#64 * zeroExtend 64 x = 0#64

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

theorem and_logic_and_logic_or_7_proof : and_logic_and_logic_or_7_before ⊑ and_logic_and_logic_or_7_after

theorem e_617 :
     - 5 *  ~~~(x &&& y) - 5 * y - 1 *  ~~~y + 2 *  ~~~(x &&&  ~~~x) - 2 * (x ^^^ y) - 5 * x + 2 *  ~~~(x ||| y) + 9 *  ~~~(x |||  ~~~y) + 8 * (x &&&  ~~~y) + 5 * (x &&& y) =  - 1 * (x ||| y) - 2 * (x |||  ~~~y)

theorem add_shl_same_amount_constants_proof : add_shl_same_amount_constants_before ⊑ add_shl_same_amount_constants_after

theorem ashr_sle_exact_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬(True ∧ x >>> 3#8 <<< 3#8 ≠ x ∨ 3#8 ≥ ↑8) → ofBool (x.sshiftRight' 3#8 ≤ₛ 10#8) = ofBool (x <ₛ 88#8)

theorem t2_ult_sgt_65536_proof : t2_ult_sgt_65536_before ⊑ t2_ult_sgt_65536_after

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

theorem t3_no_extrause_proof : t3_no_extrause_before ⊑ t3_no_extrause_after

theorem ugt_and_min_thm (e e_1 : IntW 8) :
  LLVM.and (icmp IntPred.ugt e_1 e) (icmp IntPred.eq e_1 (const? 8 0)) ⊑ const? 1 0

theorem e_2334 :
    1 *  ~~~(d ||| (e &&& f)) + 2 * ((d &&& f) ^^^  ~~~(e &&&  ~~~f)) - 6 * ( ~~~(d |||  ~~~e) ||| (e ^^^ f)) - 1 * (f &&& (d ||| e)) - 7 *  ~~~(d ^^^ f) + 11 * (f &&&  ~~~(d &&&  ~~~e)) - 5 * (f ^^^ (d |||  ~~~e)) + 11 * ((e &&& f) ||| (d &&& (e ||| f))) - 1 * (f ||| (d ^^^ e)) - 2 * ( ~~~(d ||| e) |||  ~~~(d ^^^ (e ^^^ f))) - 2 *  ~~~( ~~~d ||| (e ^^^ f)) - 2 * ((d &&& e) ^^^  ~~~(d ^^^ (e &&& f))) + 1 * ( ~~~(d &&& e) &&& (d ^^^ (e ^^^ f))) + 11 * (e ^^^ ( ~~~d ||| (e ^^^ f))) - 3 * (f ^^^  ~~~(d |||  ~~~e)) - 3 * (e ^^^  ~~~( ~~~d &&& (e ^^^ f))) - 2 * (d &&& e) - 1 * (f |||  ~~~(d ||| e)) - 11 * (f ^^^  ~~~( ~~~d &&& ( ~~~e ||| f))) + 2 * (f |||  ~~~(d ^^^ e)) + 11 * (d &&& (e ^^^ f)) + 2 * (e ^^^ (d ||| (e &&& f))) - 3 * (d ||| f) - 5 * (d &&& (e ||| f)) + 2 * ((d &&& e) ||| (e ^^^ f)) - 1 * (e ^^^ f) + 7 * (e ^^^ ( ~~~d &&& ( ~~~e ||| f))) - 1 *  ~~~(d &&& (e ||| f)) + 11 *  ~~~(d &&& ( ~~~e &&& f)) + 7 * (e ^^^ ( ~~~d ||| (e ||| f))) + 2 * ((d &&&  ~~~e) |||  ~~~(e ^^^ f)) + 5 * ((d &&& f) |||  ~~~(e ||| f)) + 1 *  ~~~(e ^^^ f) + 4 * ( ~~~(d &&&  ~~~e) &&& (e ^^^ f)) - 6 * ( ~~~d ||| ( ~~~e ||| f)) + 4 * (d ^^^ ( ~~~e ||| f)) + 5 * (e ||| (d &&& f)) + 1 * ( ~~~e &&&  ~~~(d ^^^ f)) + 1 * ( ~~~(d &&& e) &&& (e ^^^ f)) + 1 * (f ^^^ (d ||| ( ~~~e ||| f))) - 1 * (f ^^^ (d ||| ( ~~~e &&& f))) - 11 * ((e &&&  ~~~f) |||  ~~~( ~~~d ||| ( ~~~e &&& f))) + 1 * (e ||| (d ^^^ f)) + 4 * (e ^^^ ( ~~~d ||| (e &&& f))) - 2 * (f ^^^  ~~~( ~~~d &&& (e &&& f))) - 5 * (f ^^^  ~~~( ~~~d ||| ( ~~~e &&& f))) - 1 * (e ^^^  ~~~( ~~~d &&& (e &&& f))) - 1 * ((e &&& f) ||| ( ~~~d &&& (e ||| f))) + 2 * (f ||| (d &&& e)) - 1 *  ~~~(d ||| e) + 3 * ((d &&& e) |||  ~~~(e |||  ~~~f)) + 5 * (e ^^^ (d ||| ( ~~~e &&& f))) + 1 * (e ^^^  ~~~(d &&&  ~~~f)) - 1 * (f ^^^  ~~~( ~~~d ||| (e &&& f))) + 5 * ((e &&& f) ^^^  ~~~(d &&& (e ^^^ f))) - 3 * ( ~~~(d &&& e) &&&  ~~~(d ^^^ (e ^^^ f))) - 6 *  ~~~(d &&& ( ~~~e ||| f)) + 1 *  ~~~(d ^^^ (e ||| f)) - 26 *  ~~~(d ||| (e ||| f)) + 16 *  ~~~(d ||| ( ~~~e ||| f)) + 17 *  ~~~( ~~~d ||| (e ||| f)) - 7 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 32 * ( ~~~d &&& ( ~~~e &&& f)) - 23 * (d &&& ( ~~~e &&& f)) - 31 * (d &&& (e &&& f)) = 1 *  ~~~(e |||  ~~~f)

theorem e_1412 :
     - 11 *  ~~~(z ^^^ t) - 6 * (z ||| t) - 2 *  ~~~z + 1 *  ~~~(z &&& t) + 11 * t + 3 * (z |||  ~~~t) - 3 * z + 9 *  ~~~(z ||| t) - 4 *  ~~~(z |||  ~~~t) + 6 * (z &&& t) =  - 5 * (z &&&  ~~~t)

theorem PR60818_sgt_proof : PR60818_sgt_before ⊑ PR60818_sgt_after

theorem slt_x_impliesT_ne_smin_todo_thm (e e_1 e_2 : IntW 8) :
  icmp IntPred.ne e_2 (select (icmp IntPred.slt e_2 e_1) (const? 8 127) e) ⊑
    select (icmp IntPred.slt e_2 e_1) (const? 1 1) (icmp IntPred.ne e e_2)

theorem demorgan_nor_use2ac_thm.extracted_1._2 : ∀ (x x_1 : BitVec 8),
  ¬(((x_1 ^^^ -1#8 ||| x) * 23#8 == 0 ||
            8 != 1 && (x_1 ^^^ -1#8 ||| x) ^^^ -1#8 == intMin 8 && (x_1 ^^^ -1#8 ||| x) * 23#8 == -1) =
          true ∨
        ((x_1 ^^^ -1#8) * 17#8 == 0 ||
            8 != 1 && ((x_1 ^^^ -1#8 ||| x) ^^^ -1#8).sdiv ((x_1 ^^^ -1#8 ||| x) * 23#8) == intMin 8 &&
              (x_1 ^^^ -1#8) * 17#8 == -1) =
          true) →
    ¬(((x ||| x_1 ^^^ -1#8) * 23#8 == 0 ||
              8 != 1 && (x ||| x_1 ^^^ -1#8) ^^^ -1#8 == intMin 8 && (x ||| x_1 ^^^ -1#8) * 23#8 == -1) =
            true ∨
          ((x_1 ^^^ -1#8) * 17#8 == 0 ||
              8 != 1 && ((x ||| x_1 ^^^ -1#8) ^^^ -1#8).sdiv ((x ||| x_1 ^^^ -1#8) * 23#8) == intMin 8 &&
                (x_1 ^^^ -1#8) * 17#8 == -1) =
            true) →
      (((x_1 ^^^ -1#8 ||| x) ^^^ -1#8).sdiv ((x_1 ^^^ -1#8 ||| x) * 23#8)).sdiv ((x_1 ^^^ -1#8) * 17#8) =
        (((x ||| x_1 ^^^ -1#8) ^^^ -1#8).sdiv ((x ||| x_1 ^^^ -1#8) * 23#8)).sdiv ((x_1 ^^^ -1#8) * 17#8)

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

private theorem falseUptoExcluding_eq_false_iff (n : Nat) (i : Nat) {env : Fin 0 → BitStream} :
    ((falseUptoExcluding n).eval env i = false) ↔ i < n

theorem or_xor_or_proof : or_xor_or_before ⊑ or_xor_or_after

theorem zext_shl_proof : zext_shl_before ⊑ zext_shl_after

theorem e_278 :
     - 1 *  ~~~(x &&&  ~~~x) - 2 * x + 5 *  ~~~(x &&&  ~~~y) + 5 * (x ||| y) - 4 *  ~~~(x ||| y) - 20 *  ~~~(x |||  ~~~y) - 13 * (x &&&  ~~~y) =  - 11 * (x ^^^ y) + 7 * (x &&& y)

theorem test_sub_nuw_nsw__nsw_is_safe_thm (e : IntW 32) :
  select (icmp IntPred.eq (LLVM.or e (const? 32 (-2147483648))) (const? 32 (-2147483647))) (const? 32 (-1))
      (sub (const? 32 (-2147483648)) (LLVM.or e (const? 32 (-2147483648))) { «nsw» := true, «nuw» := true }) ⊑
    sub (const? 32 (-2147483648)) (LLVM.or e (const? 32 (-2147483648))) { «nsw» := true, «nuw» := false }

theorem PR42691_8_logical_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x <ₛ 14#32) = 1#1 →
    ofBool (x != BitVec.ofInt 32 (-2147483648)) = ofBool (x + 2147483647#32 <ᵤ BitVec.ofInt 32 (-2147483635))

theorem main5c_like_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 &&& 7#32 != 7#32) ||

theorem eq_rem_zero_nonuw_proof : eq_rem_zero_nonuw_before ⊑ eq_rem_zero_nonuw_after

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

theorem or_eq_with_one_bit_diff_constants1_logical_proof : or_eq_with_one_bit_diff_constants1_logical_before ⊑ or_eq_with_one_bit_diff_constants1_logical_after

theorem logical_or_cond_reuse_proof : logical_or_cond_reuse_before ⊑ logical_or_cond_reuse_after

@[bv_multi_width_normalize]
theorem BitVec.lt_ult {x y : BitVec w} : (x < y) = (x.ult y)

theorem denote_rewritePeephole_go (pr : PeepholeRewrite d Γ t)
    (pos : ℕ) (target : Com d Γ₂ eff t₂) :
    (rewritePeephole_go fuel pr pos target).denote = target.denote

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

theorem ashrslt_03_09_exact_thm.extracted_1._1 : ∀ (x : BitVec 4),
  ¬(True ∧ x >>> 3#4 <<< 3#4 ≠ x ∨ 3#4 ≥ ↑4) → ofBool (x.sshiftRight' 3#4 <ₛ BitVec.ofInt 4 (-7)) = 0#1

theorem fold_sext_to_and_wrong10_proof : fold_sext_to_and_wrong10_before ⊑ fold_sext_to_and_wrong10_after

theorem mul_sel_op0_proof : mul_sel_op0_before ⊑ mul_sel_op0_after

theorem lshr_C1_add_A_C2_i32_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬(x &&& 65535#32) + 5#32 ≥ ↑32 →
    ¬x &&& 65535#32 ≥ ↑32 → 6#32 <<< ((x &&& 65535#32) + 5#32) = 192#32 <<< (x &&& 65535#32)

theorem n2_proof : n2_before ⊑ n2_after

theorem srem_eq_zero_of_smod {w : Nat} {x y : BitVec w} :
  x.smod y = 0#_ → x.srem y = 0#_

theorem alive_AndOrXor_2486  (w : Nat)   : alive_AndOrXor_2486_src w  ⊑ alive_AndOrXor_2486_tgt w

theorem demorgan_nor_use2a_proof : demorgan_nor_use2a_before ⊑ demorgan_nor_use2a_after

theorem not_shl_proof : not_shl_before ⊑ not_shl_after

theorem shl_add_lshr_comm_thm.extracted_1._1 : ∀ (x x_1 x_2 : BitVec 32),
  ¬(True ∧ x_1 <<< x >>> x ≠ x_1 ∨ x ≥ ↑32 ∨ True ∧ (x_2 * x_2).uaddOverflow (x_1 <<< x) = true ∨ x ≥ ↑32) →
    x ≥ ↑32 ∨ True ∧ ((x_2 * x_2) >>> x).uaddOverflow x_1 = true → False

theorem test1_trunc_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬(24#32 ≥ ↑32 ∨ 8#32 ≥ ↑32) →
    24#32 ≥ ↑32 ∨
        8#32 ≥ ↑32 ∨
          True ∧ (x >>> 24#32 &&& (x >>> 8#32 &&& 65280#32) != 0) = true ∨
            True ∧
              zeroExtend 32 (truncate 16 (x >>> 24#32 ||| x >>> 8#32 &&& 65280#32)) ≠
                x >>> 24#32 ||

theorem rem_euclid_wrong_operands_select_proof : rem_euclid_wrong_operands_select_before ⊑ rem_euclid_wrong_operands_select_after

theorem pv_proof : pv_before ⊑ pv_after

theorem t4_ugt_slt_128_thm.extracted_1._7 : ∀ (x x_1 : BitVec 32),
  ofBool (143#32 <ᵤ x_1 + 16#32) = 1#1 →
    ¬ofBool (x_1 <ₛ 128#32) = 1#1 →
      ¬ofBool (127#32 <ₛ x_1) = 1#1 → ¬ofBool (x_1 <ₛ BitVec.ofInt 32 (-16)) = 1#1 → x = x_1

theorem lshr_exact_ne_0_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ¬(True ∧ x_1 >>> x <<< x ≠ x_1 ∨ x ≥ ↑32) → ofBool (x_1 >>> x != 0#32) = ofBool (x_1 != 0#32)

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

theorem icmp_and_ashr_multiuse_proof : icmp_and_ashr_multiuse_before ⊑ icmp_and_ashr_multiuse_after

theorem no_shift_xor_multiuse_cmp_xor_proof : no_shift_xor_multiuse_cmp_xor_before ⊑ no_shift_xor_multiuse_cmp_xor_after

theorem urem_i1_is_zero_proof : urem_i1_is_zero_before ⊑ urem_i1_is_zero_after

theorem eq_commuted_proof : eq_commuted_before ⊑ eq_commuted_after

theorem xor_sext_to_sel_thm (e : IntW 32) (e_1 : IntW 1) : LLVM.xor (sext 32 e_1) e ⊑ LLVM.xor e (sext 32 e_1)

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

theorem mul_of_bool_thm.extracted_1._1 : ∀ (x : BitVec 8) (x_1 : BitVec 32),
  ofBool (255#32 <ᵤ (x_1 &&& 1#32) * zeroExtend 32 x) = 0#1

theorem ashrslt_01_13_proof : ashrslt_01_13_before ⊑ ashrslt_01_13_after

theorem test3_thm (e : IntW 8) :
  icmp IntPred.sge e (const? 8 (-127)) ⊑ icmp IntPred.ne e (const? 8 (-128))

theorem ashrslt_03_06_exact_thm.extracted_1._1 : ∀ (x : BitVec 4),
  ¬(True ∧ x >>> 3#4 <<< 3#4 ≠ x ∨ 3#4 ≥ ↑4) → ofBool (x.sshiftRight' 3#4 <ₛ 6#4) = 1#1

theorem xor_nosignbit_ashr_proof : xor_nosignbit_ashr_before ⊑ xor_nosignbit_ashr_after

theorem test_add__nsw_is_safe_thm.extracted_1._3 : ∀ (x : BitVec 32),
  ¬ofBool (x ||| BitVec.ofInt 32 (-2147483648) == -1#32) = 1#1 →
    True ∧ (x ||| BitVec.ofInt 32 (-2147483648)).saddOverflow 1#32 = true → False

theorem icmp_eq_and_pow2_shl_pow2_negative2_proof : icmp_eq_and_pow2_shl_pow2_negative2_before ⊑ icmp_eq_and_pow2_shl_pow2_negative2_after

theorem lshr_shl_demand4_proof : lshr_shl_demand4_before ⊑ lshr_shl_demand4_after

theorem ripple_nsw5_proof : ripple_nsw5_before ⊑ ripple_nsw5_after

include hinj in
lemma product.prodArray_spec_full :
    (product.prodArray f hm₁ hm₂).toList.Nodup ∧
    ∀ s₁ s₂, f s₁ s₂ ∈ product.prodArray f hm₁ hm₂ ↔ (s₁.val ∈ m₁ ∧ s₂.val ∈ m₂)

theorem e_533 :
     - 1 * (x ||| y) + 7 * (x ^^^ y) + 11 *  ~~~x + 1 *  ~~~y + 3 *  ~~~(x &&& y) - 10 *  ~~~(x ||| y) - 20 *  ~~~(x |||  ~~~y) - 5 * (x &&&  ~~~y) + 6 * (x &&& y) = 5 * (x |||  ~~~y)

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

@[simp] theorem hasType_push {Γ : Context Ty} :
    (Γ.push v ty).hasType v ty

theorem AvoidCollision_signExtend_eq_setWidth_of_lt (x : BitVec w) {v : Nat} (hv : v ≤ w) :
  x.signExtend v = x.setWidth v

theorem ashr_xor_proof : ashr_xor_before ⊑ ashr_xor_after

theorem bools_logical_commute0_and1_and2_proof : bools_logical_commute0_and1_and2_before ⊑ bools_logical_commute0_and1_and2_after

theorem e_2411 :
    3 * (e ^^^  ~~~( ~~~d ||| (e &&& f))) - 3 * (e &&& (d |||  ~~~f)) - 6 * (f &&&  ~~~(d &&& e)) + 11 * (f ^^^ (d ||| (e &&& f))) - 1 * (e ^^^ (d &&& (e ||| f))) + 4 *  ~~~e - 3 * (f ^^^  ~~~(d ||| (e &&& f))) - 1 * (e ^^^  ~~~( ~~~d ||| (e ^^^ f))) + 5 * ( ~~~d ||| (e &&& f)) - 5 *  ~~~(d ||| ( ~~~e &&& f)) + 7 * (f ^^^  ~~~(d &&& (e &&& f))) - 1 * (e ^^^  ~~~( ~~~d &&& (e &&& f))) - 2 *  ~~~(d |||  ~~~f) + 11 * (e ||| f) - 1 * (d |||  ~~~f) + 2 * ((e &&& f) ^^^  ~~~(d &&& (e ^^^ f))) + 2 * (d &&& f) - 7 * ((d ||| e) &&&  ~~~(d ^^^ (e ^^^ f))) - 1 * ( ~~~f &&&  ~~~(d ^^^ e)) - 1 * (f ^^^  ~~~( ~~~d &&& (e &&& f))) + 7 *  ~~~(d ||| (e ^^^ f)) - 6 * ( ~~~e |||  ~~~(d ^^^ f)) - 1 * (e ^^^ (d |||  ~~~f)) - 5 * d - 11 * (e ^^^ (d ||| (e &&& f))) - 1 * (f ^^^  ~~~( ~~~d ||| (e &&& f))) - 2 *  ~~~(e |||  ~~~f) + 11 * (f ^^^  ~~~(d ||| ( ~~~e &&& f))) + 2 * f - 5 * (f ^^^  ~~~( ~~~d ||| ( ~~~e &&& f))) + 1 * ((d &&& e) |||  ~~~(d ^^^ (e ^^^ f))) - 2 * ((d ^^^ e) &&&  ~~~(d ^^^ f)) + 4 * (e ^^^  ~~~(d &&& (e &&& f))) + 4 *  ~~~( ~~~d &&& ( ~~~e &&& f)) - 2 * ((d &&& e) ^^^  ~~~(d ^^^ ( ~~~e ||| f))) - 7 *  ~~~(d &&& (e ^^^ f)) + 1 * ( ~~~e &&&  ~~~(d ^^^ f)) + 3 *  ~~~(d ^^^ (e ^^^ f)) + 2 * (e |||  ~~~(d |||  ~~~f)) + 1 * (e ^^^  ~~~(d &&& (e ||| f))) - 11 * (e ^^^ ( ~~~d ||| (e ||| f))) + 3 *  ~~~( ~~~d &&& (e ^^^ f)) - 6 * (e ^^^ f) + 2 * ((e &&& f) ||| ( ~~~d &&& (e ||| f))) - 6 * (e ^^^ (d &&& (e ^^^ f))) - 2 * ((e &&&  ~~~f) |||  ~~~( ~~~d ||| ( ~~~e &&& f))) - 7 * (e ^^^  ~~~(d &&& (e ^^^ f))) + 2 *  ~~~(e ||| f) + 1 * (d ^^^ ( ~~~e ||| f)) - 7 * (e ^^^ ( ~~~d ||| ( ~~~e ||| f))) - 5 * (f ^^^ ( ~~~d &&& ( ~~~e ||| f))) - 11 * (d &&& ( ~~~e ||| f)) + 5 * (f |||  ~~~(d ||| e)) - 5 * (e &&&  ~~~(d &&& f)) + 7 * ((d &&& f) ||| (e &&&  ~~~f)) + 1 * ( ~~~(d |||  ~~~e) ||| (e ^^^ f)) + 2 * (f ^^^ (d &&& (e ||| f))) - 2 * ((d &&& f) ^^^  ~~~(e &&&  ~~~f)) + 7 * (d ^^^ e) + 3 * (e ||| (d ^^^ f)) + 1 *  ~~~(d &&&  ~~~f) - 3 * (e &&&  ~~~(d ^^^ f)) - 5 * (f ^^^  ~~~(d ||| e)) + 1 * (f ^^^ ( ~~~d ||| (e &&& f))) - 11 * ( ~~~d &&& (e ||| f)) + 1 *  ~~~(d ||| (e ||| f)) + 10 *  ~~~(d ||| ( ~~~e ||| f)) + 20 *  ~~~( ~~~d ||| (e ||| f)) - 2 *  ~~~( ~~~d ||| ( ~~~e ||| f)) + 6 * ( ~~~d &&& ( ~~~e &&& f)) + 8 * ( ~~~d &&& (e &&& f)) + 33 * (d &&& ( ~~~e &&& f)) - 16 * (d &&& (e &&& f)) = 1 * ((e &&&  ~~~f) |||  ~~~(d ||| ( ~~~e &&& f)))

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

theorem sdiv_x_by_const_cmp_x_proof : sdiv_x_by_const_cmp_x_before ⊑ sdiv_x_by_const_cmp_x_after

theorem ashr_mul_sign_bits_proof : ashr_mul_sign_bits_before ⊑ ashr_mul_sign_bits_after

theorem udiv_illegal_type_thm.extracted_1._2 : ∀ (x x_1 : BitVec 9),
  ¬zeroExtend 32 x = 0 → ¬x = 0 → zeroExtend 32 x_1 / zeroExtend 32 x = zeroExtend 32 (x_1 / x)

theorem ashr_lshr_cst2_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬ofBool (-1#32 <ₛ x) = 1#1 → ¬(True ∧ x >>> 8#32 <<< 8#32 ≠ x ∨ 8#32 ≥ ↑32) → 8#32 ≥ ↑32 → False

theorem sdiv_icmp3_thm (e : IntW 64) :
  icmp IntPred.eq (LLVM.sdiv e (const? 64 5) { «exact» := true }) (const? 64 (-1)) ⊑
    icmp IntPred.eq e (const? 64 (-5))

theorem zext_mul_thm.extracted_1._1 : ∀ (x : BitVec 8),
  zeroExtend 16 x * 3#16 &&& zeroExtend 16 x = zeroExtend 16 (x * 3#8 &&& x)

theorem e_2359 :
     - 2 * (e ^^^ ( ~~~d ||| (e ^^^ f))) + 3 * (f ^^^ (d &&& ( ~~~e ||| f))) + 5 * ( ~~~(d ^^^ e) ||| (d ^^^ f)) + 11 * (e ^^^ ( ~~~d ||| ( ~~~e ||| f))) - 1 *  ~~~(d &&& ( ~~~e &&& f)) + 3 * (e ^^^  ~~~(d &&& f)) - 1 *  ~~~(d &&& ( ~~~e ||| f)) - 1 * ( ~~~(d ||| e) |||  ~~~(d ^^^ (e ^^^ f))) - 11 * (e &&&  ~~~f) - 5 * ( ~~~(d &&&  ~~~e) &&&  ~~~(e ^^^ f)) + 1 * (d ^^^ (e ||| f)) + 4 * (f ^^^  ~~~(d &&& ( ~~~e &&& f))) - 11 * ( ~~~e ||| (d ^^^ f)) + 1 * (f ^^^ (d ||| (e ||| f))) + 2 *  ~~~(d ||| e) + 1 * (e ^^^ ( ~~~d &&& (e ^^^ f))) + 1 * ( ~~~(d ^^^ e) &&&  ~~~(d ^^^ f)) - 2 * (e ^^^ ( ~~~d &&& (e ||| f))) - 6 * ((d |||  ~~~e) &&&  ~~~(d ^^^ (e ^^^ f))) + 1 *  ~~~(d &&& (e ||| f)) + 1 * (f ^^^ ( ~~~d ||| (e &&& f))) - 6 * (f &&& (d ^^^ e)) - 5 * (e ||| (d &&&  ~~~f)) - 11 *  ~~~(d ^^^ (e ||| f)) - 6 * (e ^^^ ( ~~~d &&& ( ~~~e ||| f))) - 1 * ((e &&& f) ||| (d &&& (e ||| f))) + 4 * ((e &&&  ~~~f) ^^^ (d ||| (e ^^^ f))) - 5 *  ~~~(d &&& e) + 3 * (e ^^^  ~~~(d |||  ~~~f)) - 1 * (d ^^^ ( ~~~e ||| f)) + 2 * ( ~~~(d &&&  ~~~e) &&& (e ^^^ f)) - 3 * (f ^^^  ~~~(d &&& ( ~~~e ||| f))) + 2 * ((d &&& f) |||  ~~~(e ||| f)) - 7 * (e &&&  ~~~(d ^^^ f)) - 11 * ((d &&& e) |||  ~~~(e |||  ~~~f)) + 3 * (e ^^^ (d ||| (e ||| f))) - 1 * ((d &&& e) ^^^ (d ^^^ (e &&& f))) + 4 * (e ^^^ ( ~~~d ||| ( ~~~e &&& f))) - 7 * (f ^^^ (d ||| ( ~~~e &&& f))) - 7 * (f ^^^  ~~~( ~~~d &&& (e ||| f))) + 1 * ( ~~~d &&& ( ~~~e ||| f)) - 1 * (f ^^^ (d ||| e)) + 5 * (e ^^^  ~~~(d ||| f)) + 1 *  ~~~(e ^^^ f) - 1 * ( ~~~f &&& (d ^^^ e)) + 3 * (d ||| (e ||| f)) + 5 * (f ^^^ (d |||  ~~~e)) - 7 * ((d &&& e) ^^^  ~~~(d ^^^ (e &&& f))) - 7 * (f ||| (d &&& e)) + 7 * (d ||| ( ~~~e ||| f)) - 3 * ((d &&& f) ^^^ (d ^^^ (e &&& f))) + 1 * ((d &&& f) ^^^ (e ||| f)) - 6 * (f ||| (d ^^^ e)) + 1 * ((d &&& e) ^^^ (e |||  ~~~f)) + 2 * f - 5 *  ~~~( ~~~d &&& (e ^^^ f)) + 2 * (f ^^^ (d ||| ( ~~~e ||| f))) - 1 * (e &&&  ~~~(d &&& f)) + 1 * ( ~~~d ||| ( ~~~e ||| f)) - 11 * ((d ^^^ e) &&& (d ^^^ f)) + 15 *  ~~~(d ||| (e ||| f)) + 36 *  ~~~(d ||| ( ~~~e ||| f)) + 7 *  ~~~( ~~~d ||| (e ||| f)) + 56 *  ~~~( ~~~d ||| ( ~~~e ||| f)) + 11 * ( ~~~d &&& ( ~~~e &&& f)) + 48 * ( ~~~d &&& (e &&& f)) + 35 * (d &&& ( ~~~e &&& f)) + 34 * (d &&& (e &&& f)) = 1 * (d ^^^ (e &&& f))

theorem xor_or_xor_common_op_commute1_proof : xor_or_xor_common_op_commute1_before ⊑ xor_or_xor_common_op_commute1_after

theorem uadd_sat_canon_nuw_proof : uadd_sat_canon_nuw_before ⊑ uadd_sat_canon_nuw_after

theorem substitute_constant_and_eq_eq_commute_logical_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ofBool (x_1 == x) = 1#1 → ofBool (x_1 == 42#8) = ofBool (x_1 == 42#8) &&& ofBool (x == 42#8)

theorem main5c_like_proof : main5c_like_before ⊑ main5c_like_after

theorem lshr_sub_nsw_thm (e e_1 : IntW 32) :
  lshr (sub e_1 e { «nsw» := true, «nuw» := false }) (const? 32 31) ⊑ zext 32 (icmp IntPred.slt e_1 e)

theorem not_xor_to_or_not4_proof : not_xor_to_or_not4_before ⊑ not_xor_to_or_not4_after

theorem t3_singlebit_proof : t3_singlebit_before ⊑ t3_singlebit_after

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

theorem shl_nsw_add_nuw_proof : shl_nsw_add_nuw_before ⊑ shl_nsw_add_nuw_after

theorem masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_7b_logical_proof : masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_7b_logical_before ⊑ masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_7b_logical_after

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

theorem icmp_slt_0_or_icmp_sgt_0_i64_fail3_proof : icmp_slt_0_or_icmp_sgt_0_i64_fail3_before ⊑ icmp_slt_0_or_icmp_sgt_0_i64_fail3_after

theorem e_358 :
    1 * (x |||  ~~~y) - 3 *  ~~~(x &&& y) - 7 *  ~~~(x ^^^ y) - 2 * y - 7 * x + 9 *  ~~~(x ||| y) + 9 * (x &&&  ~~~y) + 15 * (x &&& y) =  - 5 *  ~~~(x |||  ~~~y)

theorem test_proof : test_before ⊑ test_after

@[simp]
theorem eval_fsmUlt_eq_evalFin_Predicate_ult (t₁ t₂ : Term) :
   (fsmUlt (termEvalEqFSM t₁).toFSM (termEvalEqFSM t₂).toFSM).eval = (Predicate.binary .ult t₁ t₂).evalFin

theorem select_icmp_eq_and_4096_0_xor_4096_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 &&& 4096#32 == 0#32) = 1#1 → x = x ^^^ x_1 &&& 4096#32

theorem test13_proof : test13_before ⊑ test13_after

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

lemma union_eq (M N : NFA' n) : M.union N = NFA'.product Or M.complete N.complete

theorem icmp_select_const_proof : icmp_select_const_before ⊑ icmp_select_const_after

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

theorem slt_and_max_proof : slt_and_max_before ⊑ slt_and_max_after

theorem not_and_and_or_not_or_or_commute4_proof : not_and_and_or_not_or_or_commute4_before ⊑ not_and_and_or_not_or_or_commute4_after

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

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

theorem sgt_positive_multip_rem_nz_proof : sgt_positive_multip_rem_nz_before ⊑ sgt_positive_multip_rem_nz_after

theorem test_invert_demorgan_or3_proof : test_invert_demorgan_or3_before ⊑ test_invert_demorgan_or3_after

theorem or_and3_thm.extracted_1._7 : ∀ (x : BitVec 1) (x_1 x_2 : BitVec 32) (x_3 : BitVec 1),
  ¬x_3 ||

@[simp] theorem le_refl (e : EffectKind) : e ≤ e

@[grind =, simp, aesop 50% unsafe]
lemma states_empty :
    RawCNFA.empty (A := A).states = ∅

theorem t5_thm.extracted_1._7 : ∀ (x x_1 : BitVec 1) (x_2 : BitVec 32),
  x_1 = 1#1 → ¬x = 1#1 → ¬64#32 = 0 → ¬6#32 ≥ ↑32 → x_2 / 64#32 = x_2 >>> 6#32

theorem logical_or_bitwise_or_icmps_comm2_proof : logical_or_bitwise_or_icmps_comm2_before ⊑ logical_or_bitwise_or_icmps_comm2_after

theorem test16_proof : test16_before ⊑ test16_after

theorem n0_proof : n0_before ⊑ n0_after

theorem bools_logical_commute1_thm.extracted_1._2 : ∀ (x x_1 : BitVec 1),
  x_1 = 1#1 → x = 1#1 → x ^^^ 1#1 = 1#1 → False

theorem test_ule_xor_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32),
  ofBool (x_1 ^^^ -1#32 ^^^ x ≤ᵤ x_1 ^^^ -1#32) = ofBool (x_1 ≤ᵤ x ^^^ x_1)

theorem not_and_and_or_not_or_or_commute1_or_proof : not_and_and_or_not_or_or_commute1_or_before ⊑ not_and_and_or_not_or_or_commute1_or_after

theorem sub_mask1_trunc_lshr_thm (e : IntW 64) :
  sub (const? 8 10) (LLVM.and (trunc 8 (lshr e (const? 64 15))) (const? 8 1)) ⊑
    add (trunc 8 (ashr (shl e (const? 64 48)) (const? 64 63)) { «nsw» := true, «nuw» := false }) (const? 8 10)
      { «nsw» := true, «nuw» := false }

theorem e_1591 :
    1 * ((a ^^^ b) &&&  ~~~(a ^^^ c)) - 7 *  ~~~(a ||| c) - 6 * (c ^^^ ( ~~~a ||| (b ||| c))) - 3 * (c ^^^  ~~~(a &&& ( ~~~b &&& c))) - 11 * (b ^^^  ~~~(a &&& ( ~~~b &&& c))) - 1 * (b ||| (a &&&  ~~~c)) - 1 * ( ~~~(a &&&  ~~~b) &&&  ~~~(b ^^^ c)) - 6 * ( ~~~a ||| ( ~~~b ||| c)) - 5 * (c ^^^  ~~~( ~~~a ||| ( ~~~b &&& c))) + 4 * (c ^^^  ~~~( ~~~a &&& ( ~~~b &&& c))) + 30 *  ~~~(a ||| (b ||| c)) + 23 *  ~~~(a ||| ( ~~~b ||| c)) + 22 *  ~~~( ~~~a ||| (b ||| c)) + 11 *  ~~~( ~~~a ||| ( ~~~b ||| c)) + 18 * ( ~~~a &&& ( ~~~b &&& c)) + 18 * ( ~~~a &&& (b &&& c)) + 13 * (a &&& ( ~~~b &&& c)) + 13 * (a &&& (b &&& c)) = 5 * (b &&&  ~~~(a &&&  ~~~c))

theorem e_980 :
    4 *  ~~~z + 11 *  ~~~(z &&&  ~~~t) + 5 *  ~~~(z ^^^ t) - 21 *  ~~~(z ||| t) - 16 *  ~~~(z |||  ~~~t) - 1 * (z &&&  ~~~t) - 17 * (z &&& t) =  - 1 *  ~~~(z &&&  ~~~z)

theorem ashr_sgt_exact_proof : ashr_sgt_exact_before ⊑ ashr_sgt_exact_after

theorem or_xor_xor_normal_variant2_thm (e e_1 : IntW 8) :
  LLVM.or (LLVM.xor (LLVM.and e_1 e) e) (LLVM.xor e_1 (LLVM.and e_1 e)) ⊑ LLVM.xor e_1 e

theorem thisdoesnotloop_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x <ₛ BitVec.ofInt 32 (-128)) = 1#1 → truncate 8 128#32 = BitVec.ofInt 8 (-128)

theorem ule_swap_and_min_commute_logical_thm.extracted_1._2 : ∀ (x x_1 : BitVec 8),
  ofBool (x_1 == 0#8) = 1#1 → ofBool (x_1 ≤ᵤ x) = ofBool (x_1 == 0#8)

theorem e_1474 :
     - 11 *  ~~~(z &&&  ~~~t) + 4 *  ~~~z + 11 * (z ^^^ t) + 5 *  ~~~t + 4 * t + 7 * z + 2 *  ~~~(z &&& t) - 1 *  ~~~(z ^^^ t) + 1 *  ~~~(z ||| t) - 9 *  ~~~(z |||  ~~~t) - 24 * (z &&&  ~~~t) = 1 * (z ||| t) - 2 * (z &&& t)

theorem not_not_true_proof : not_not_true_before ⊑ not_not_true_after

theorem t9_thm (e e_1 : IntW 8) : sub (const? 8 0) (sub e_1 e) ⊑ sub e e_1

theorem negate_xor_thm (e : IntW 4) :
  sub (const? 4 0) (LLVM.xor e (const? 4 5)) ⊑ add (LLVM.xor e (const? 4 (-6))) (const? 4 1)

theorem udiv400_thm.extracted_1._2 : ∀ (x : BitVec 32),
  ¬(2#32 ≥ ↑32 ∨ 100#32 = 0) → ¬400#32 = 0 → x >>> 2#32 / 100#32 = x / 400#32

theorem shl_nsw_add_nuw_proof : shl_nsw_add_nuw_before ⊑ shl_nsw_add_nuw_after

theorem test23_proof : test23_before ⊑ test23_after

theorem test13_thm.extracted_1._2 : ∀ (x x_1 : BitVec 32),
  ¬zeroExtend 128 x &&& 31#128 ≥ ↑128 →
    ¬(True ∧ (x &&& 31#32).msb = true ∨ zeroExtend 64 (x &&& 31#32) ≥ ↑64) →
      truncate 64 ((signExtend 128 x_1).sshiftRight' (zeroExtend 128 x &&& 31#128)) =
        (signExtend 64 x_1).sshiftRight' (zeroExtend 64 (x &&& 31#32))

theorem t2_ult_sgt_128_proof : t2_ult_sgt_128_before ⊑ t2_ult_sgt_128_after

theorem t3_ult_sgt_neg1_proof : t3_ult_sgt_neg1_before ⊑ t3_ult_sgt_neg1_after

theorem t4_ugt_slt_65536_proof : t4_ugt_slt_65536_before ⊑ t4_ugt_slt_65536_after

theorem fold_sext_to_and_wrong9_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ofBool (signExtend 32 x &&& 128#32 != 1#32) = 1#1

theorem test36_thm (e : IntW 32) :
  LLVM.and (add (zext 64 e) (const? 64 7)) (const? 64 240) ⊑
    zext 64 (LLVM.and (add e (const? 32 7)) (const? 32 240)) { «nneg» := true }

theorem icmp_sle9_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬(True ∧ (x <<< 7#8).sshiftRight' 7#8 ≠ x ∨ 7#8 ≥ ↑8) →
    ofBool (x <<< 7#8 ≤ₛ BitVec.ofInt 8 (-128)) = ofBool (x != 0#8)

theorem test_zext3_thm.extracted_1._2 : ∀ (x : BitVec 1), x = 1#1 → ¬x ^^^ 1#1 = 1#1 → 0#32 = zeroExtend 32 0#1

theorem lshr_32_add_zext_trunc_thm (e e_1 : IntW 32) :
  add (trunc 32 (add (zext 64 e_1) (zext 64 e))) (trunc 32 (lshr (add (zext 64 e_1) (zext 64 e)) (const? 64 32))) ⊑
    add (add e_1 e) (zext 32 (icmp IntPred.ult (add e_1 e) e_1))

theorem test3_thm (e : IntW 1) : LLVM.and e (const? 1 0) ⊑ const? 1 0

theorem shl_xor_xor_no_const_proof : shl_xor_xor_no_const_before ⊑ shl_xor_xor_no_const_after

theorem test14_proof : test14_before ⊑ test14_after

theorem and_logic_and_logic_or_8_thm.extracted_1._8 : ∀ (x x_1 x_2 : BitVec 1),
  ¬x_2 = 1#1 → ¬0#1 = 1#1 → x &&& x_1 = x_1 &&& x

theorem ashr_mul_thm.extracted_1._2 : ∀ (x x_1 : BitVec 8),
  ¬8#20 ≥ ↑20 →
    ¬(True ∧ (signExtend 16 x_1).smulOverflow (signExtend 16 x) = true ∨ 8#16 ≥ ↑16) →
      truncate 16 ((signExtend 20 x_1 * signExtend 20 x).sshiftRight' 8#20) =
        (signExtend 16 x_1 * signExtend 16 x).sshiftRight' 8#16

theorem or_xor_xor_normal_variant3_proof : or_xor_xor_normal_variant3_before ⊑ or_xor_xor_normal_variant3_after

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

theorem lshrugt_03_00_thm (e : IntW 4) :
  icmp IntPred.ugt (lshr e (const? 4 3)) (const? 4 0) ⊑ icmp IntPred.slt e (const? 4 0)

theorem sgt_and_not_min_commute_proof : sgt_and_not_min_commute_before ⊑ sgt_and_not_min_commute_after

theorem ugt_swap_and_min_logical_thm.extracted_1._1 : ∀ (x x_1 : BitVec 8),
  ofBool (x_1 <ᵤ x) = 1#1 → ofBool (x == 0#8) = 0#1

theorem sext_multi_uses_thm.extracted_1._2 : ∀ (x : BitVec 64) (x_1 : BitVec 1) (x_2 : BitVec 64),
  ¬x_1 = 1#1 → x_2 * signExtend 64 x_1 + ((x ^^^ signExtend 64 x_1) - signExtend 64 x_1) = x

theorem mul_unkV_evenC_ne_proof : mul_unkV_evenC_ne_before ⊑ mul_unkV_evenC_ne_after

theorem test2_logical_thm.extracted_1._4 : ∀ (x x_1 : BitVec 1), ¬x_1 = 1#1 → 0#1 = 1#1 → x_1 = 0#1

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

theorem slt_thm (e : IntW 64) :
  icmp IntPred.slt (ashr (trunc 32 e) (const? 32 31)) (trunc 32 (lshr e (const? 64 32))) ⊑
    icmp IntPred.slt (ashr (trunc 32 e) (const? 32 31))
      (trunc 32 (lshr e (const? 64 32)) { «nsw» := false, «nuw» := true })

theorem sdiv400_yes_proof : sdiv400_yes_before ⊑ sdiv400_yes_after

theorem mul_of_udiv_thm (e : IntW 8) :
  mul (LLVM.udiv e (const? 8 12) { «exact» := true }) (const? 8 6) ⊑ lshr e (const? 8 1) { «exact» := true }

theorem lshrult_03_10_thm (e : IntW 4) : icmp IntPred.ult (lshr e (const? 4 3)) (const? 4 (-6)) ⊑ const? 1 1

theorem test6_thm (e : IntW 64) :
  trunc 32 (lshr (zext 128 e) (const? 128 32)) ⊑
    trunc 32 (lshr e (const? 64 32)) { «nsw» := false, «nuw» := true }

theorem test11_thm (e : IntW 32) :
  icmp IntPred.ult (LLVM.udiv (const? 32 4) e) (const? 32 1) ⊑ icmp IntPred.ugt e (const? 32 4)

theorem ashr_proof : ashr_before ⊑ ashr_after

@[simp]
lemma swapLastTwo_eq1' : swapLastTwo (n := n) (Fin.last (n + 1)) = n

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 masked_icmps_mask_notallzeros_bmask_mixed_4_logical_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ¬ofBool (x &&& 255#32 != 0#32) = 1#1 → 0#1 = ofBool (x &&& 15#32 == 8#32)

theorem test_add_nuw__nsw_is_safe_thm.extracted_1._1 : ∀ (x : BitVec 32),
  ofBool (x ||| BitVec.ofInt 32 (-2147483648) == -1#32) = 1#1 →
    True ∧ (x ||| BitVec.ofInt 32 (-2147483648)).saddOverflow 1#32 = true → False

theorem and_not_or_commute3_proof : and_not_or_commute3_before ⊑ and_not_or_commute3_after

theorem e_2178 :
    2 * (f &&&  ~~~(d ^^^ e)) - 6 * ( ~~~f &&&  ~~~(d ^^^ e)) + 7 * ((d &&& e) |||  ~~~(e ^^^ f)) - 3 * (f ^^^ (d &&& ( ~~~e ||| f))) + 2 * ( ~~~d &&& (e ||| f)) + 2 * ((d |||  ~~~e) &&&  ~~~(e ^^^ f)) - 5 * ( ~~~d &&& ( ~~~e ||| f)) - 1 * (d ^^^ (e ^^^ f)) - 2 * ((d &&&  ~~~e) |||  ~~~(e ^^^ f)) + 4 *  ~~~(d ||| f) + 2 * ( ~~~(d ||| e) ||| (e ^^^ f)) + 1 * e + 1 * (e ^^^  ~~~(d |||  ~~~f)) + 2 * ((d ^^^ e) &&& (d ^^^ f)) + 4 * (d ||| ( ~~~e ||| f)) - 7 * (e ^^^  ~~~( ~~~d &&& ( ~~~e &&& f))) - 5 * (d |||  ~~~f) + 1 * ( ~~~(d ||| e) |||  ~~~(e ^^^ f)) - 1 * ( ~~~(d &&&  ~~~e) &&& (d ^^^ (e ^^^ f))) - 1 * ((d &&& e) ^^^  ~~~(d ^^^ (e &&& f))) - 2 * (f ^^^ (d &&&  ~~~e)) - 1 * ( ~~~e |||  ~~~(d ^^^ f)) + 7 * ( ~~~(d ||| e) ||| (d ^^^ (e ^^^ f))) - 11 * ((d ||| e) &&& (e ^^^ f)) + 2 * (e ^^^ (d ||| (e ^^^ f))) - 2 * (f &&& (d |||  ~~~e)) + 1 * (e ^^^ (d ||| f)) + 4 * (d ||| f) - 1 * (d &&& ( ~~~e ||| f)) - 1 * (f ^^^  ~~~( ~~~d &&& (e ||| f))) - 3 * ((d &&& e) ||| (d ^^^ (e ^^^ f))) + 2 * (d ^^^ f) + 5 * ( ~~~(d ^^^ e) &&& (d ^^^ f)) - 11 * (e &&&  ~~~f) - 2 * (f ^^^ ( ~~~d &&& ( ~~~e ||| f))) - 1 * (e &&& f) - 1 *  ~~~(d ^^^ ( ~~~e ||| f)) - 6 * ((d &&&  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) - 6 * (f ^^^  ~~~(d ||| (e &&& f))) - 3 * ( ~~~(d ^^^ e) |||  ~~~(d ^^^ f)) + 5 * (f ^^^ (d ||| ( ~~~e &&& f))) + 7 * (d ^^^ ( ~~~e ||| f)) + 11 *  ~~~(d ||| (e ||| f)) + 23 *  ~~~(d ||| ( ~~~e ||| f)) - 7 *  ~~~( ~~~d ||| (e ||| f)) + 7 *  ~~~( ~~~d ||| ( ~~~e ||| f)) - 16 * ( ~~~d &&& ( ~~~e &&& f)) - 11 * ( ~~~d &&& (e &&& f)) + 35 * (d &&& ( ~~~e &&& f)) + 2 * (d &&& (e &&& f)) =  - 3 * (f ^^^ (d ||| (e ||| f))) + 1 * ((d |||  ~~~e) &&& (e ^^^ f))

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

theorem ne_umin2_thm (e e_1 : IntW 32) :
  icmp IntPred.ne (select (icmp IntPred.ult e_1 e) e_1 e) e ⊑ icmp IntPred.ugt e e_1

theorem reassoc_x2_add_nuw_proof : reassoc_x2_add_nuw_before ⊑ reassoc_x2_add_nuw_after

theorem t1_thm (e : IntW 8) :
  select (icmp IntPred.eq (LLVM.and e (const? 8 31)) (const? 8 0)) e
      (LLVM.and (add e (const? 8 32)) (const? 8 (-32))) ⊑
    LLVM.and (add e (const? 8 31)) (const? 8 (-32))

@[simp] theorem Lets.denote_var_appendInl_pure (lets : Lets d Γ_in .pure Γ_out)
    (e : Expr d Γ_out .pure tys) (V_in : Valuation Γ_in) (v : Var _ u) :
    Lets.denote (var lets e) V_in v.appendInl
    = let xs : HVector .. := e.denoteOp (lets.denote V_in)
      xs[v]

theorem shift_xor_multiuse_and_proof : shift_xor_multiuse_and_before ⊑ shift_xor_multiuse_and_after

theorem check_axioms_cadical (w : Nat) (a b : BitVec w) : a + b = b + a

@[simp] theorem inf_pure_eq      : min e pure = pure

theorem or_and_not_not_commute6_proof : or_and_not_not_commute6_before ⊑ or_and_not_not_commute6_after

theorem ashrslt_02_12_exact_proof : ashrslt_02_12_exact_before ⊑ ashrslt_02_12_exact_after

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

theorem bools_multi_uses2_logical_thm.extracted_1._29 : ∀ (x x_1 x_2 : BitVec 1),
  ¬x_2 ^^^ 1#1 = 1#1 → x_2 = 1#1 → 0#1 = 1#1 → x = 1#1 → ¬True → 0#1 + x = 0#1 ^^^ x

theorem e_2165 :
    7 * (e ^^^  ~~~(d &&& (e &&& f))) - 2 *  ~~~(d ^^^ (e ||| f)) - 1 * (d ^^^ f) - 7 * (d ||| (e &&& f)) + 5 * (e ^^^  ~~~( ~~~d &&& (e ||| f))) + 11 *  ~~~(d ||| ( ~~~e &&& f)) - 7 *  ~~~d + 4 * (e ^^^  ~~~(d &&& f)) + 1 * ((d |||  ~~~e) &&&  ~~~(d ^^^ (e ^^^ f))) + 3 * ( ~~~d &&& (e ^^^ f)) + 1 * ( ~~~(d &&&  ~~~e) &&&  ~~~(d ^^^ (e ^^^ f))) - 11 * ( ~~~(d ||| e) ||| (d ^^^ (e ^^^ f))) - 1 * (f ^^^ (d ||| ( ~~~e ||| f))) - 2 * ((d &&& e) |||  ~~~(e |||  ~~~f)) - 2 * ((d ^^^ e) |||  ~~~(d ^^^ f)) - 3 * (f ^^^  ~~~(d ||| e)) + 4 *  ~~~(d |||  ~~~f) - 3 * (f ^^^  ~~~( ~~~d &&& (e ||| f))) - 1 *  ~~~f - 2 *  ~~~(d &&&  ~~~e) + 5 * (f ^^^ ( ~~~d ||| ( ~~~e ||| f))) - 2 * (e ^^^ ( ~~~d ||| (e &&& f))) - 5 * ( ~~~(d |||  ~~~e) |||  ~~~(d ^^^ (e ^^^ f))) - 2 * (e ^^^ (d |||  ~~~f)) - 7 * (e ^^^ (d &&& (e ^^^ f))) - 2 * (e ^^^  ~~~(d &&& (e ||| f))) + 5 * (e ^^^ (d ||| (e ^^^ f))) + 1 *  ~~~(d ^^^ e) + 5 *  ~~~(d &&& ( ~~~e ||| f)) + 7 * (d &&& ( ~~~e ||| f)) + 2 * (f ^^^ ( ~~~d &&& (e ||| f))) - 1 * (d &&& (e ||| f)) + 2 * (e &&& f) + 7 * (e ^^^  ~~~(d &&&  ~~~f)) - 6 * (f ^^^ (d &&&  ~~~e)) + 1 * (e ^^^ (d ||| ( ~~~e ||| f))) - 11 * (e ^^^ ( ~~~d ||| ( ~~~e ||| f))) + 3 * ((e &&&  ~~~f) |||  ~~~(d ||| ( ~~~e &&& f))) + 3 * ( ~~~e ||| (d ^^^ f)) - 3 * (f |||  ~~~(d ^^^ e)) - 3 *  ~~~(d ||| f) + 5 *  ~~~(d ||| (e ||| f)) + 2 *  ~~~(d ||| ( ~~~e ||| f)) + 10 *  ~~~( ~~~d ||| (e ||| f)) + 21 *  ~~~( ~~~d ||| ( ~~~e ||| f)) + 9 * ( ~~~d &&& ( ~~~e &&& f)) + 9 * ( ~~~d &&& (e &&& f)) + 7 * (d &&& ( ~~~e &&& f)) + 24 * (d &&& (e &&& f)) =  - 1 * (e ^^^ ( ~~~d &&& ( ~~~e ||| f)))

theorem or_trunc_lshr_thm.extracted_1._1 : ∀ (x : BitVec 8),
  ¬1#8 ≥ ↑8 → 1#6 ≥ ↑6 ∨ True ∧ (truncate 6 x >>> 1#6 &&& BitVec.ofInt 6 (-32) != 0) = true → False

theorem test87_proof : test87_before ⊑ test87_after

theorem lshrugt_03_01_thm.extracted_1._1 : ∀ (x : BitVec 4), ¬3#4 ≥ ↑4 → ofBool (1#4 <ᵤ x >>> 3#4) = 0#1

theorem test3_proof : test3_before ⊑ test3_after

theorem p_commutative4_thm (e e_1 e_2 : IntW 32) :
  add (LLVM.and (LLVM.xor e_2 (const? 32 (-1))) e_1) (LLVM.and e_2 e) ⊑
    LLVM.or (LLVM.and e_1 (LLVM.xor e_2 (const? 32 (-1)))) (LLVM.and e_2 e) { «disjoint» := true }

theorem select_of_symmetric_selects_thm.extracted_1._1 : ∀ (x : BitVec 32) (x_1 x_2 : BitVec 1),
  x_2 = 1#1 → x_1 = 1#1 → x_1 ^^^ x_2 = 1#1 → False

theorem cmpeq_xor_cst1_proof : cmpeq_xor_cst1_before ⊑ cmpeq_xor_cst1_after

theorem trunc_thm.extracted_1._1 : ∀ (x x_1 : BitVec 32), ofBool (x_1 <ᵤ x) = 1#1 → truncate 16 42#32 = 42#16

theorem ashrsgt_02_05_proof : ashrsgt_02_05_before ⊑ ashrsgt_02_05_after

theorem e_619 :
     - 7 *  ~~~(x ^^^ y) + 7 * (x |||  ~~~y) - 11 *  ~~~(x &&&  ~~~x) + 2 * (x ^^^ y) - 2 * x - 2 *  ~~~y + 11 *  ~~~(x &&& y) + 4 *  ~~~(x ||| y) - 5 * (x &&&  ~~~y) + 12 * (x &&& y) =  - 1 *  ~~~(x &&&  ~~~y) + 3 *  ~~~x

theorem e_1257 :
     - 11 * (z ||| t) - 1 *  ~~~t - 3 *  ~~~(z &&&  ~~~z) + 11 * (z ^^^ t) + 5 * t - 2 *  ~~~(z &&& t) + 5 *  ~~~(z ||| t) + 13 * (z &&&  ~~~t) + 15 * (z &&& t) =  - 1 *  ~~~(z ^^^ t) + 7 * z

theorem ashr_ugt_0_proof : ashr_ugt_0_before ⊑ ashr_ugt_0_after

theorem t3_proof : t3_before ⊑ t3_after

theorem lshrugt_02_02_proof : lshrugt_02_02_before ⊑ lshrugt_02_02_after

theorem or_xor_xor_normal_binops_proof : or_xor_xor_normal_binops_before ⊑ or_xor_xor_normal_binops_after

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

theorem src_fv_eq_thm.extracted_1._1 : ∀ (x : BitVec 8) (x_1 : BitVec 1),
  ¬x_1 = 1#1 → ofBool (0#8 ||| x == 0#8) = ofBool (x == 0#8) &&& (x_1 ^^^ 1#1)

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

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

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

theorem ashrsgt_02_05_exact_proof : ashrsgt_02_05_exact_before ⊑ ashrsgt_02_05_exact_after

theorem masked_icmps_mask_notallzeros_bmask_mixed_swapped_3b_logical_proof : masked_icmps_mask_notallzeros_bmask_mixed_swapped_3b_logical_before ⊑ masked_icmps_mask_notallzeros_bmask_mixed_swapped_3b_logical_after

theorem bv_AndOrXor_2243__B__C__A__B___B__A__C :
    ∀ (e e_1 e_2 : LLVM.IntW w), LLVM.or (LLVM.and (LLVM.or e_2 e_1) e) e_2 ⊑ LLVM.or e_2 (LLVM.and e e_1)

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

theorem negate_add_with_single_negatible_operand_depth2_thm (e e_1 : IntW 8) :
  sub (const? 8 0) (mul (add e_1 (const? 8 21)) e) ⊑ mul (sub (const? 8 (-21)) e_1) e

lemma RawCNFA.autMsbSet_wf : autMsbSet.WF

theorem xor_icmp_true_signed_thm.extracted_1._1 : ∀ (x : BitVec 32), ofBool (5#32 <ₛ x) ^^^ ofBool (x <ₛ 6#32) = 1#1

theorem e_1959 :
     - 3 * ( ~~~(a &&&  ~~~b) &&&  ~~~(a ^^^ (b ^^^ c))) + 2 *  ~~~(a &&& (b ^^^ c)) + 1 * (a ^^^ (b ||| c)) - 3 * (b ^^^  ~~~(a ||| c)) + 5 * (b ^^^  ~~~(a &&&  ~~~c)) + 2 * (b &&&  ~~~c) - 5 *  ~~~(a ^^^ ( ~~~b ||| c)) - 3 * ( ~~~(a &&&  ~~~b) &&& (a ^^^ (b ^^^ c))) - 7 * ( ~~~c |||  ~~~(a ^^^ b)) + 3 *  ~~~( ~~~a &&& ( ~~~b ||| c)) - 1 *  ~~~(a &&& ( ~~~b &&& c)) - 7 * b - 7 * (b ^^^ (a ||| ( ~~~b &&& c))) + 2 * ((a &&& b) ^^^ (b |||  ~~~c)) - 2 * ((a &&& b) ^^^ (a ^^^ (b &&& c))) - 5 * (b ^^^ (a &&&  ~~~c)) - 1 * (b ^^^  ~~~(a &&& ( ~~~b &&& c))) + 1 * ( ~~~b &&&  ~~~(a ^^^ c)) - 6 * ((a |||  ~~~b) &&& (a ^^^ (b ^^^ c))) + 3 *  ~~~(a ^^^ c) + 5 * ( ~~~(a ||| b) ||| (a ^^^ (b ^^^ c))) - 2 * (b ^^^  ~~~( ~~~a ||| ( ~~~b &&& c))) + 5 * (b ^^^  ~~~( ~~~a &&& (b ^^^ c))) - 1 * ( ~~~(a ^^^ b) &&& (a ^^^ c)) + 2 * (b ^^^ (a ||| (b ^^^ c))) - 3 * (a ^^^ b) - 2 * (b |||  ~~~c) - 1 * ((a |||  ~~~b) &&& (b ^^^ c)) - 2 * (c &&&  ~~~(a &&& b)) + 1 * (b ^^^  ~~~(a &&& c)) + 1 * ( ~~~(a ^^^ b) |||  ~~~(a ^^^ c)) + 3 * (b ^^^  ~~~( ~~~a &&& ( ~~~b ||| c))) - 2 *  ~~~(b ^^^ c) - 1 * ((a &&& b) ||| (a ^^^ (b ^^^ c))) - 1 * (a ^^^ c) + 1 * (a ||| ( ~~~b ||| c)) - 1 * (c ^^^ (a &&& b)) + 5 * ((b &&&  ~~~c) ^^^ ( ~~~a ||| (b ^^^ c))) - 11 * (b &&& c) - 6 * (c ^^^ (a &&& (b ||| c))) + 11 * (c ^^^  ~~~(a &&& ( ~~~b &&& c))) + 5 * (a ^^^ (b ^^^ c)) - 7 * (c ^^^  ~~~( ~~~a &&& ( ~~~b &&& c))) - 5 * (b ^^^  ~~~(a &&& (b ^^^ c))) + 1 * ((a ^^^ b) |||  ~~~(a ^^^ c)) + 2 *  ~~~(a &&& c) - 11 * ((a &&& c) |||  ~~~(b ||| c)) - 3 * ((a &&&  ~~~b) |||  ~~~(a ^^^ (b ^^^ c))) + 7 *  ~~~(a ||| ( ~~~b ||| c)) + 35 *  ~~~( ~~~a ||| (b ||| c)) + 32 *  ~~~( ~~~a ||| ( ~~~b ||| c)) + 28 * ( ~~~a &&& ( ~~~b &&& c)) + 42 * ( ~~~a &&& (b &&& c)) + 2 * (a &&& ( ~~~b &&& c)) + 50 * (a &&& (b &&& c)) = 2 * ((a &&& c) ^^^ (a ^^^ ( ~~~b &&& c))) + 6 * (a ||| ( ~~~b &&& c))

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

theorem icmp_sle_x_negy_proof : icmp_sle_x_negy_before ⊑ icmp_sle_x_negy_after

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

theorem lshrult_01_05_thm (e : IntW 4) :
  icmp IntPred.ult (lshr e (const? 4 1)) (const? 4 5) ⊑ icmp IntPred.ult e (const? 4 (-6))

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

theorem one_side_fold_sgt_thm.extracted_1._3 : ∀ (x x_1 : BitVec 32) (x_2 : BitVec 1),
  x_2 = 1#1 → x_2 ^^^ 1#1 = 1#1 → False

theorem e_977 :
     - 1 * (z ^^^ t) - 2 * t + 3 * z + 1 *  ~~~(z &&&  ~~~z) - 1 *  ~~~(z ||| t) + 2 *  ~~~(z |||  ~~~t) - 3 * (z &&&  ~~~t) = 2 * (z &&& t)
</all_available_lemmas>

<local_ctx>
import LeanMLIR.ErasedContext

import LeanMLIR.HVector

import LeanMLIR.EffectKind

import LeanMLIR.Framework.Dialect

import Mathlib.Data.Finset.Union

open Ctxt (Var VarSet Valuation Hom)

open TyDenote (toType)

abbrev RegionSignature Ty := List (Ctxt Ty × List Ty)

structure Signature (Ty : Type) where
  mkEffectful ::
  sig         : List Ty
  regSig      : RegionSignature Ty
  returnTypes : List Ty
  effectKind  : EffectKind := .pure

abbrev Signature.mk (sig : List Ty) (regSig : RegionSignature Ty) (returnTypes : List Ty) : Signature Ty :=
 { sig, regSig, returnTypes }

class DialectSignature (d : Dialect) where
  signature : d.Op → Signature d.Ty

namespace DialectSignature

variable {d} [s : DialectSignature d]

def sig          := Signature.sig ∘ s.signature

def regSig       := Signature.regSig ∘ s.signature

def returnTypes  := Signature.returnTypes ∘ s.signature

def effectKind   := Signature.effectKind ∘ s.signature

end DialectSignature

class DialectDenote (d : Dialect) [TyDenote d.Ty] [DialectSignature d] where
  denote : (op : d.Op) → HVector toType (DialectSignature.sig op) →
    (HVector (fun t : Ctxt d.Ty × List d.Ty =>
      t.1.Valuation
      → EffectKind.impure.toMonad d.m (HVector toType t.2))
            (DialectSignature.regSig op)) →
    ((DialectSignature.effectKind op).toMonad d.m
      (HVector toType <| DialectSignature.returnTypes op))

section DataStructures

variable (d : Dialect) [DialectSignature d]

inductive Expr : (Γ : Ctxt d.Ty) → (eff : EffectKind) → (ty : List d.Ty) → Type where
  | mk {Γ} {ty} (op : d.Op)
    (ty_eq : ty = DialectSignature.returnTypes op)
    (eff_le : DialectSignature.effectKind op ≤ eff)
    (args : HVector (Var Γ) <| DialectSignature.sig op)
     
    (regArgs : HVector (fun t : Ctxt d.Ty × List d.Ty => Com t.1 .impure t.2)
      (DialectSignature.regSig op)) : Expr Γ eff ty

inductive Com : Ctxt d.Ty → EffectKind → List d.Ty → Type where
  | rets {Γ} {tys} {eff : EffectKind} (vs : HVector Γ.Var tys) : Com Γ eff tys
  | var (e : Expr Γ eff ty) (body : Com (ty ++ Γ) eff β) : Com Γ eff β

end

abbrev Expr.outContext (_ : Expr d Γ eff ts) : Ctxt d.Ty :=
  ts ++ Γ

abbrev Regions (regSig : RegionSignature d.Ty) : Type :=
  HVector (fun t => Com d t.1 .impure t.2) regSig

inductive Lets (Γ_in : Ctxt d.Ty) (eff : EffectKind) :
    (Γ_out : Ctxt d.Ty) → Type where
  | nil : Lets Γ_in eff Γ_in
  | var (body : Lets Γ_in eff Γ_out) (e : Expr d Γ_out eff t) : Lets Γ_in eff e.outContext

variable {d} [DialectSignature d]

protected instance HVector.decidableEqReg [DecidableEq d.Op] [DecidableEq d.Ty] :
    ∀ {l : RegionSignature d.Ty}, DecidableEq (HVector (fun t => Com d t.1 .impure t.2) l)
  | _, .nil, .nil => isTrue rfl
  | _, .cons x₁ v₁, .cons x₂ v₂ =>
    letI := HVector.decidableEqReg v₁ v₂
    letI := Com.decidableEq x₁ x₂
    decidable_of_iff (x₁ = x₂ ∧ v₁ = v₂) (by admit /- proof elided -/
    )

protected instance Expr.decidableEq [DecidableEq d.Op] [DecidableEq d.Ty] :
    {Γ : Ctxt d.Ty} → {ty : List d.Ty} → DecidableEq (Expr d Γ eff ty)
  | Γ, _, .mk op₁ rfl eff_le₁ arg₁ regArgs₁, .mk op₂ eq eff_le₂ arg₂ regArgs₂ =>
    if ho : op₁ = op₂ then by
      subst ho
      letI := HVector.decidableEq arg₁ arg₂
      letI := HVector.decidableEqReg regArgs₁ regArgs₂
      exact decidable_of_iff (arg₁ = arg₂ ∧ regArgs₁ = regArgs₂) (by admit /- proof elided -/
      )
    else isFalse (by admit /- proof elided -/
    )

protected instance Com.decidableEq [DecidableEq d.Op] [DecidableEq d.Ty]
    {Γ : Ctxt d.Ty} {eff : EffectKind} {tys : List d.Ty} : DecidableEq (Com d Γ eff tys)
  | .rets v₁, .rets v₂ => decidable_of_iff (v₁ = v₂) (by admit /- proof elided -/
  )
  | .var (ty := ty₁) e₁ body₁, .var (ty := ty₂) e₂ body₂ =>
    if hα : ty₁ = ty₂
    then by
      subst hα
      letI := Expr.decidableEq e₁ e₂
      letI := Com.decidableEq body₁ body₂
      exact decidable_of_iff (e₁ = e₂ ∧ body₁ = body₂) (by admit /- proof elided -/
      )
    else isFalse (by admit /- proof elided -/
    )
  | .rets _, .var _ _ => isFalse (fun h => Com.noConfusion h)
  | .var _ _, .rets _ => isFalse (fun h => Com.noConfusion h)

end -- decEq

end DataStructures

variable {d : Dialect} [DialectSignature d]

section Rec

variable {eff t} {motive : ∀ {Γ}, Com d Γ eff t → Sort u}
          (rets : ∀ {Γ : Ctxt _} , (v : HVector Γ.Var t) → motive (Com.rets v))
          (var : ∀ {Γ} {u},
            (e : Expr d Γ eff u) → (body : Com d e.outContext eff t) →
              motive body → motive (Com.var e body))

def Com.rec' {Γ} (com : Com d Γ eff t) : motive com :=
   
  Com.rec
    (motive_1 := fun _ _ _ _ => PUnit)
    (motive_2 := fun _ eff' t' c =>
      (h₁ : eff = eff') → (h₂ : t = t') → motive (h₁ ▸ h₂ ▸ c))
    (motive_3 := fun _ _ => PUnit)
    (fun _ _ _ _ _ _ => ⟨⟩) 
    (fun v h₁ h₂ => 
      cast (by admit /- proof elided -/
      ) <| rets (h₂ ▸ v))
    (fun e' body' _ r' h₁ h₂ => 
      let e := h₁ ▸ e'
      let body : Com _ _ eff t := cast (by admit /- proof elided -/
      ) body'
      let r : motive body := cast (by admit /- proof elided -/
      ) (r' h₁ h₂)
      cast (by admit /- proof elided -/
      ) <| var e body r)
    ⟨⟩
    (fun _ _ _ _ => ⟨⟩)
    com
    rfl
    rfl

variable {rets} {var} {Γ : Ctxt _}

end Rec

def Expr.op {Γ : Ctxt d.Ty} {eff : EffectKind} {ty} (e : Expr d Γ eff ty) : d.Op :=
  Expr.casesOn e (fun op _ _ _ _ => op)

def Expr.args {Γ ts} (e : Expr d Γ eff ts) :
    HVector (Var Γ) (DialectSignature.sig e.op) :=
  Expr.casesOn e (fun _ _ _ args _ => args)

def Expr.regArgs {Γ ts} (e : Expr d Γ eff ts) :
    Regions d (DialectSignature.regSig e.op) :=
  Expr.casesOn e (fun _ _ _ _ regArgs => regArgs)

section Lemmas

namespace Com

end Com

end Lemmas

def Com.outContext {Γ} : Com d Γ eff ts → Ctxt d.Ty :=
  Com.rec' (motive := fun _ => Ctxt d.Ty)
    (@fun Γ _ => Γ) 
    (fun _ _ r => r) 

section Lemmas

end Lemmas

variable [TyDenote d.Ty] [DialectDenote d] [DecidableEq d.Ty] [Monad d.m] [LawfulMonad d.m]

def HVector.denote :
    {l : RegionSignature d.Ty} → (T : HVector (fun t => Com d t.1 .impure t.2) l) →
    HVector (fun t => t.1.Valuation → EffectKind.impure.toMonad d.m (HVector toType t.2)) l
  | _, .nil => HVector.nil
  | _, .cons v vs => HVector.cons (v.denote) (HVector.denote vs)

def Expr.denote {ty} (e : Expr d Γ eff ty) (V : Valuation Γ) :
    eff.toMonad d.m (e.outContext.Valuation) :=
  match e with
  | ⟨op, ty_eq, heff, args, regArgs⟩ => do
      let argsDenote := args.map V
      let val ← EffectKind.liftEffect heff <| DialectDenote.denote op argsDenote regArgs.denote
      return (val ++ V).cast (by admit /- proof elided -/
      )

def Com.denote : Com d Γ eff ty → (Γv : Valuation Γ) →
    eff.toMonad d.m (HVector toType ty)
  | .rets vs, Γv     => pure (vs.map Γv)
  | .var e body, V => e.denote V >>= body.denote

end

def Lets.denote [DialectSignature d] [DialectDenote d] {Γ₂}
    (lets : Lets d Γ₁ eff Γ₂) (V : Valuation Γ₁) : (eff.toMonad d.m <| Valuation Γ₂) :=
  match lets with
  | .nil          => return V
  | .var lets' e  => lets'.denote V >>= e.denote

section Unfoldings

open EffectKind (liftEffect)

def Expr.denoteOp (e : Expr d Γ eff ty) (V : Γ.Valuation) :
    eff.toMonad d.m (HVector toType ty) :=
  EffectKind.liftEffect e.eff_le <| cast (by admit /- proof elided -/
  ) <|
    DialectDenote.denote e.op (e.args.map V) e.regArgs.denote

end Unfoldings

section Lemmas

end Lemmas

section Lemmas

variable {Γ Γ' : Ctxt d.Ty} {t} (f : Γ.Hom Γ') (e : Expr d Γ eff t) (V : Γ'.Valuation)

end Lemmas

structure FlatCom (d : Dialect) [DialectSignature d]  (Γ_in : Ctxt d.Ty) (eff : EffectKind)
    (Γ_out : Ctxt d.Ty) (ts : List d.Ty) where
  lets : Lets d Γ_in eff Γ_out
  rets : HVector Γ_out.Var ts

@[simp] abbrev FlatCom.denote [DialectDenote d]
    (flatCom : FlatCom d Γ eff Γ_out ts)
    (V : Γ.Valuation) : eff.toMonad d.m (HVector toType ts) :=
  flatCom.lets.denote V >>= (return flatCom.rets.map ·)

def Expr.changeEffect {eff₁ eff₂ : EffectKind} (h : eff₁ ≤ eff₂) :
    Expr d Γ eff₁ t → Expr d Γ eff₂ t
  | Expr.mk op ty_eq eff_le args regArgs =>
    have heff : DialectSignature.effectKind op ≤ eff₂ := by admit /- proof elided -/

def Expr.castPureToEff (eff : EffectKind) : Expr d Γ .pure t → Expr d Γ eff t :=
  changeEffect (EffectKind.pure_le eff)

section Lemmas
</local_ctx>

<target_theorem>
@[simp] theorem Expr.denote_castPureToEff {e : Expr d Γ .pure t} :
    denote (e.castPureToEff eff) = fun V => pure (e.denote V) :=
</target_theorem>

