Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add SMT-LIB overflow on addition for bitvectors (uadd_overflow,sadd_overflow, uadd_overflow_eq,sadd_overflow_eq) and support theorems #6628

Open
wants to merge 58 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
8e26dee
feat; add overflow defs
luisacicolini Jan 13, 2025
8c64c87
chore: add smtlib names in docstrings
luisacicolini Jan 13, 2025
8c3448f
chore: fix docstrings
luisacicolini Jan 14, 2025
c8ed74e
chore: fix definition case
luisacicolini Jan 14, 2025
7026bd1
chore: only add
luisacicolini Jan 22, 2025
7d0c873
chore: uadd, sadd
luisacicolini Jan 22, 2025
686141a
chore: add theorems
luisacicolini Jan 22, 2025
b005e45
chore: remove not-overflow
luisacicolini Jan 22, 2025
3f33283
chore: formatting
luisacicolini Jan 22, 2025
95e3c01
chore: formatting
luisacicolini Jan 22, 2025
65be585
choire: move to normalize
luisacicolini Jan 22, 2025
58de782
chore: formatting
luisacicolini Jan 22, 2025
7f4f484
chore: formatting
luisacicolini Jan 22, 2025
befd15a
chore: formatting
luisacicolini Jan 22, 2025
cd84f3a
chore: move overflow theorems back
luisacicolini Jan 22, 2025
77bb974
chore: move all theorems
luisacicolini Jan 22, 2025
a8470b4
chore: add attribute to normalize
luisacicolini Jan 22, 2025
4c582c2
chore: move int theorem
luisacicolini Jan 22, 2025
a315c89
chore: merge master
luisacicolini Jan 22, 2025
1e3e07b
chore: update housing of theorems
luisacicolini Jan 22, 2025
ab1d3d5
chore: formatting
luisacicolini Jan 22, 2025
ffe861e
chore: everyone found their spot but everything is broken
luisacicolini Jan 22, 2025
7af6bb8
chore: more fixing in places
luisacicolini Jan 22, 2025
4115b36
chore: le_toInt works
luisacicolini Jan 22, 2025
04f49e4
chore: fix toInt_lt
luisacicolini Jan 22, 2025
ddceb18
chore: replace rcases
luisacicolini Jan 22, 2025
bd24dbd
chore: uncomment proofs
luisacicolini Jan 23, 2025
df55e51
chore: parentheses format
luisacicolini Jan 23, 2025
cf259c0
feat: add tests
luisacicolini Jan 23, 2025
b7deb99
make it compile
tobiasgrosser Jan 24, 2025
e963a5b
Further cleanup
tobiasgrosser Jan 24, 2025
c275d43
make it compile again
tobiasgrosser Jan 24, 2025
3b71364
clean a bit
tobiasgrosser Jan 24, 2025
8be4e02
simplify further
tobiasgrosser Jan 24, 2025
f5d228c
WIP
tobiasgrosser Jan 24, 2025
9f24743
chore: simplify uadd_overflow
luisacicolini Jan 24, 2025
4bb440b
feat: example with bv_decide proof
luisacicolini Jan 24, 2025
214c613
chore: undo unrelated change
luisacicolini Jan 24, 2025
d45bfc9
chore: correct tests for bv_norm
luisacicolini Jan 24, 2025
bcf668e
chore: update theorem name
luisacicolini Jan 24, 2025
b7bf543
chore: simplify toInt_lt
luisacicolini Jan 24, 2025
1243ed7
chore: simpler le_toInt proof
luisacicolini Jan 24, 2025
978ace8
chore: simpler toInt_lt proof too
luisacicolini Jan 24, 2025
81c9071
chore: golf toInd_add_toInt_lt_two_pow
luisacicolini Jan 24, 2025
4266a24
chore: golf neg_two_pow_le_toInd_add_toInt
luisacicolini Jan 24, 2025
f72ad61
chore: golf toInd_add_toInt_lt_two_pow and neg_two_pow_le_toInd_add_t…
luisacicolini Jan 24, 2025
8c76c62
chore: erstore previous version and remove commas
luisacicolini Jan 24, 2025
fc22884
chore: fix bool coercion
luisacicolini Jan 27, 2025
4537011
chore: parentheses and brackets
luisacicolini Jan 27, 2025
e1fbe8b
chore: golf proof
luisacicolini Jan 28, 2025
e97dfed
chore: rename and move toNat_mod_cancel_of_lt
luisacicolini Jan 28, 2025
6ddf150
chore: indentation
luisacicolini Jan 30, 2025
aaf2b46
chore: typo
luisacicolini Jan 30, 2025
204633f
chore: docstring
luisacicolini Jan 30, 2025
bdff0b7
chore: docstring
luisacicolini Jan 30, 2025
62b551c
chore: docstring
luisacicolini Jan 30, 2025
ce311f8
chore: fix typo and fix build
luisacicolini Jan 30, 2025
2697dc0
chore: fix boolean ops
luisacicolini Jan 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/Init/Data/BitVec/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,21 @@ def ofBoolListLE : (bs : List Bool) → BitVec bs.length
| [] => 0#0
| b :: bs => concat (ofBoolListLE bs) b

/-! ## Overflow -/

/-- Overflow predicate for unsigned addition modulo 2^w.
luisacicolini marked this conversation as resolved.
Show resolved Hide resolved

SMT-Lib name: `bvuaddo`.
-/
def uaddOverflow {w : Nat} (x y : BitVec w) : Bool := x.toNat + y.toNat ≥ 2 ^ w

/-- Overflow predicate for signed addition on w-bit 2's complement.
luisacicolini marked this conversation as resolved.
Show resolved Hide resolved

SMT-Lib name: `bvsaddo`.
-/
def saddOverflow {w : Nat} (x y : BitVec w) : Bool :=
(x.toInt + y.toInt ≥ 2 ^ (w - 1)) || (x.toInt + y.toInt < - 2 ^ (w - 1))

/- ### reverse -/

/-- Reverse the bits in a bitvector. -/
Expand Down
34 changes: 34 additions & 0 deletions src/Init/Data/BitVec/Bitblast.lean
Original file line number Diff line number Diff line change
Expand Up @@ -1230,4 +1230,38 @@ theorem shiftRight_eq_ushiftRightRec (x : BitVec w₁) (y : BitVec w₂) :
· simp [of_length_zero]
· simp [ushiftRightRec_eq]

/-! ### Overflow definitions -/


@[simp] theorem toNat_mod_lt_eq {x : BitVec n} (h : n < m): x.toNat % (2 ^ m) = x.toNat :=
Nat.mod_eq_of_lt (by
have := (@Nat.pow_lt_pow_iff_right 2 n m (by omega)).mpr (by omega)
omega
)
luisacicolini marked this conversation as resolved.
Show resolved Hide resolved

theorem uaddOverflow_eq {w : Nat} (x y : BitVec w) :
uaddOverflow x y = (x.setWidth (w + 1) + y.setWidth (w + 1)).msb := by
simp [uaddOverflow, msb_add, msb_setWidth, carry]
luisacicolini marked this conversation as resolved.
Show resolved Hide resolved

theorem saddOverflow_eq {w : Nat} (x y : BitVec w) :
saddOverflow x y ↔ (x.msb = y.msb ∧ ¬(x + y).msb = x.msb) := by
luisacicolini marked this conversation as resolved.
Show resolved Hide resolved
simp only [saddOverflow]
rcases w with _|w
· revert x y; decide
· have := le_toInt x; have := toInt_lt x
have := le_toInt y; have := toInt_lt y
have := toInd_add_toInt_lt_two_pow x y
have := neg_two_pow_le_toInd_add_toInt x y
have bmod_neg_iff {m : Nat} {x : Int} (h2 : -m ≤ x) (h1 : x < m) :
(x.bmod m) < 0 ↔ (-(m / 2) ≤ x ∧ x < 0) ∨ ((m + 1) / 2 ≤ x) := by
simp only [Int.bmod_def]
by_cases xpos : 0 ≤ x
· rw [Int.emod_eq_of_lt xpos (by omega)]; omega
· rw [Int.add_emod_self.symm, Int.emod_eq_of_lt (by omega) (by omega)]; omega
simp only [ge_iff_le, Bool.or_eq_true, decide_eq_true_eq, BitVec.msb_eq_toInt,
decide_eq_decide, BitVec.toInt_add]
rw_mod_cast [bmod_neg_iff (by assumption) (by assumption),
← @Nat.two_pow_pred_add_two_pow_pred (w + 1) (by omega)] at *
omega

end BitVec
34 changes: 34 additions & 0 deletions src/Init/Data/BitVec/Lemmas.lean
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,40 @@ theorem eq_zero_or_eq_one (a : BitVec 1) : a = 0#1 ∨ a = 1#1 := by
theorem toInt_zero {w : Nat} : (0#w).toInt = 0 := by
simp [BitVec.toInt, show 0 < 2^w by exact Nat.two_pow_pos w]

theorem toInt_lt {w : Nat} (x : BitVec w) : x.toInt < 2 ^ (w - 1) := by
simp only [BitVec.toInt]
rcases w with _|w'
· omega
· rw [← Nat.two_pow_pred_add_two_pow_pred (by omega), ← Nat.two_mul, Nat.add_sub_cancel]
simp only [Nat.zero_lt_succ, Nat.mul_lt_mul_left, Int.natCast_mul, Int.Nat.cast_ofNat_Int]
norm_cast; omega

theorem le_toInt {w : Nat} (x : BitVec w) : -2 ^ (w - 1) ≤ x.toInt := by
simp only [BitVec.toInt]
rcases w with _|w'
· omega
· rw [← Nat.two_pow_pred_add_two_pow_pred (by omega), ← Nat.two_mul, Nat.add_sub_cancel]
simp only [Nat.zero_lt_succ, Nat.mul_lt_mul_left, Int.natCast_mul, Int.Nat.cast_ofNat_Int]
norm_cast; omega

theorem toInd_add_toInt_lt_two_pow (x y : BitVec w) :
x.toInt + y.toInt < 2 ^ w := by
rcases w with _|w'
· simp [BitVec.eq_nil x, BitVec.eq_nil y]
· have hx := toInt_lt x
have hy := toInt_lt y
rw [Nat.add_sub_cancel] at hx hy
omega

theorem neg_two_pow_le_toInd_add_toInt (x y : BitVec w) :
- 2 ^ w ≤ x.toInt + y.toInt := by
rcases w with _|w'
· simp [BitVec.eq_nil x, BitVec.eq_nil y]
· have hx := le_toInt x
have hy := le_toInt y
rw [Nat.add_sub_cancel] at hx hy
omega

/-! ### slt -/

/--
Expand Down
3 changes: 3 additions & 0 deletions src/Std/Tactic/BVDecide/Normalize/BitVec.lean
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,9 @@ attribute [bv_normalize] BitVec.umod_zero
attribute [bv_normalize] BitVec.umod_one
attribute [bv_normalize] BitVec.umod_eq_and

attribute [bv_normalize] BitVec.saddOverflow_eq
attribute [bv_normalize] BitVec.uaddOverflow_eq
luisacicolini marked this conversation as resolved.
Show resolved Hide resolved

luisacicolini marked this conversation as resolved.
Show resolved Hide resolved
/-- `x / (BitVec.ofNat n)` where `n = 2^k` is the same as shifting `x` right by `k`. -/
theorem BitVec.udiv_ofNat_eq_of_lt (w : Nat) (x : BitVec w) (n : Nat) (k : Nat) (hk : 2 ^ k = n) (hlt : k < w) :
x / (BitVec.ofNat w n) = x >>> k := by
Expand Down
7 changes: 7 additions & 0 deletions tests/lean/run/bv_decide_rewriter.lean
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ example {x : BitVec 16} : x / (BitVec.twoPow 16 2) = x >>> 2 := by bv_normalize
example {x : BitVec 16} : x / (BitVec.ofNat 16 8) = x >>> 3 := by bv_normalize
example {x y : Bool} (h1 : x && y) : x || y := by bv_normalize
example (a b c: Bool) : (if a then b else c) = (if !a then c else b) := by bv_normalize
example (x y : BitVec 16) : BitVec.uaddOverflow x y = (x.setWidth (17) + y.setWidth (17)).msb := by bv_normalize
example (x y : BitVec 16) : BitVec.saddOverflow x y = (x.msb = y.msb ∧ ¬(x + y).msb = x.msb) := by bv_normalize
example (x y : BitVec w) : BitVec.uaddOverflow x y = (x.setWidth (w + 1) + y.setWidth (w + 1)).msb := by bv_normalize
example (x y : BitVec w) : BitVec.saddOverflow x y = (x.msb = y.msb ∧ ¬(x + y).msb = x.msb) := by bv_normalize


section

Expand All @@ -96,6 +101,8 @@ example (x y : BitVec 256) : x * y = y * x := by
example {x y z : BitVec 64} : ~~~(x &&& (y * z)) = (~~~x ||| ~~~(z * y)) := by
bv_decide (config := { acNf := true })

example {x : BitVec 16} : (x = BitVec.allOnes 16) → (BitVec.uaddOverflow x x) := by bv_decide

end

def foo (x : Bool) : Prop := x = true
Expand Down
Loading