Skip to content

Commit

Permalink
feat: Add BitVector overflow predicates from SMT-LIB.
Browse files Browse the repository at this point in the history
This PR adds the definitions for overflow predicates,
which allows one to detect when a bitvector expression
has potentially overflowed.

We define unsigned overflow to have happened when `BitVec.toNat . BitVec.ofNat w != id`,
and similarly for signed overflow.

We will introduce circuits that compute these conditions for `bv_decide` to
bitblast these predicates with.
  • Loading branch information
bollu committed Jan 6, 2025
1 parent 78ddee9 commit caa4016
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 0 deletions.
80 changes: 80 additions & 0 deletions src/Init/Data/BitVec/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,86 @@ def twoPow (w : Nat) (i : Nat) : BitVec w := 1#w <<< i

end bitwise


section overflow

/--
`UnsignedOverflow w x` denotes that the natural number `x`
will overflow when represented as a bitvector of width `w`.
-/
def UnsignedOverflow (w : Nat) (x : Nat) : Prop := (BitVec.ofNat w x).toNat ≠ x

instance : Decidable (UnsignedOverflow w x) :=
by rw [UnsignedOverflow]; infer_instance

/--
`SignedOverflow w x` denotes that the integer `x`
will overflow when represented as a bitvector of width `w`.
-/
def SignedOverflow (w : Nat) (x : Int) : Prop :=
(BitVec.ofInt w x).toInt ≠ x

instance : Decidable (SignedOverflow w x) :=
by rw [SignedOverflow]; infer_instance

/--
Predicate indicating if signed addition produces an overflow.
SMT-LIB: bvnego
-/
def negOverflow (x : BitVec w) : Bool :=
SignedOverflow w (-(x.signExtend (w + 1))).toInt

/--
Predicate indicating if unsigned addition produces an overflow.
SMT-LIB: bvuaddo
-/
def uaddOverflow (x y : BitVec w) : Bool :=
UnsignedOverflow w (x.zeroExtend (w + 1) + y.zeroExtend (w + 1)).toNat

/--
Predicate indicating if unsigned addition produces an overflow.
SMT-LIB: bvusubo
-/
def usubOverflow (x y : BitVec w) : Bool :=
UnsignedOverflow w (x.zeroExtend (w + 1) - y.zeroExtend (w + 1)).toNat

/--
Predicate indicating if unsigned multiplication produces an overflow.
SMT-LIB: bvumulo
-/
def umulOverflow (x y : BitVec w) : Bool :=
UnsignedOverflow w (x.zeroExtend (w * 2) * y.zeroExtend (w * 2)).toNat

/--
Predicate indicating if signed addition produces an overflow.
SMT-LIB: bvsaddo
-/
def saddOverflow (x y : BitVec w) : Bool :=
SignedOverflow w (x.signExtend (w + 1) + y.signExtend (w + 1)).toInt

/--
Predicate indicating if signed addition produces an overflow.
SMT-LIB: bvssubo
-/
def ssubOverflow (x y : BitVec w) : Bool :=
SignedOverflow w (x.signExtend (w + 1) - y.signExtend (w + 1)).toInt

/--
Predicate indicating if signed addition produces an overflow.
SMT-LIB: bvsmulo
-/
def smulOverflow (x y : BitVec w) : Bool :=
SignedOverflow w (x.signExtend (w * 2) * y.signExtend (w * 2)).toInt

/--
Predicate indicating if signed addition produces an overflow.
SMT-LIB: bvsdivo
-/
def sdivOverflow (x y : BitVec w) : Bool :=
SignedOverflow w ((x.signExtend (w + 1)).sdiv (y.signExtend (w + 1))).toInt

end overflow

/-- Compute a hash of a bitvector, combining 64-bit words using `mixHash`. -/
def hash (bv : BitVec n) : UInt64 :=
if n ≤ 64 then
Expand Down
5 changes: 5 additions & 0 deletions src/Init/Data/BitVec/Lemmas.lean
Original file line number Diff line number Diff line change
Expand Up @@ -3566,6 +3566,11 @@ instance instDecidableExistsBitVec :
| 0, _, _ => inferInstance
| _ + 1, _, _ => inferInstance


/-! ### Overflow Theorems -/

-- theorem udiv_overflow (x y : BitVec w) : ¬ NatOverflows w (x.toNat / y.toNat) := by sorry

/-! ### Deprecations -/

set_option linter.missingDocs false
Expand Down

0 comments on commit caa4016

Please sign in to comment.