lean4-htt/tests/lean/run/bv_will_overflow.lean
Kim Morrison 6b62fed82e
feat: proposed change to BitVec API (#5200)
This renames `BitVec.getLsb` to `getLsbD` (`D` for "default" value, i.e.
false), and introduces `getLsb?` and `getLsb'` (which we can rename to
`getLsb` after a deprecation cycle).

(Similarly for `getMsb`.)

Also adds a `GetElem` class so we can use `x[i]` and `x[i]?` notation. 

Later, we will turn
```
theorem getLsbD_eq_getElem?_getD (x : BitVec w) (i : Nat) (h : i < w) :
    x.getLsbD i = x[i]?.getD false
```
on as a `@[simp]` lemma.

This PR doesn't attempt to demonstrate the benefits, but I think both
arguments are going to get easier, and this will bring the BitVec API
closer in line to List/Array, etc.

---------

Co-authored-by: Markus Himmel <markus@lean-fro.org>
2024-08-30 02:00:57 +00:00

120 lines
3.7 KiB
Text

import Std.Tactic.BVDecide
/-
This file is based on: https://grack.com/blog/2022/12/20/deriving-a-bit-twiddling-hack/
-/
open BitVec
namespace DerivingBitTwiddlingHack
/-
bool will_add_overflow_64bit(int32_t a, int32_t b) {
// a and b are promoted to 64-bit signed integers
int64_t result = (int64_t)a + b;
if (result < INT32_MIN || result > INT32_MAX) {
return true;
}
return false;
}
-/
def will_add_overflow_64bit (a b : BitVec 32) : Bool :=
let a := a.signExtend 64
let b := b.signExtend 64
let result := a + b
-- copied from libc
let INT32_MAX := 0x7fffffff#32
let INT32_MIN := (-0x7fffffff#32 - 1#32)
BitVec.slt result (INT32_MIN.signExtend 64) || BitVec.slt (INT32_MAX.signExtend 64) result
/-
bool will_add_overflow_expression(int32_t a_, int32_t b_) {
uint32_t a = (uint32_t)a_, b = (uint32_t)b_;
uint32_t c = (uint32_t)a + (uint32_t)b;
#define NEG(x) (((uint32_t)(x) & 0x80000000) == 0x80000000)
return ((!NEG(a) && !NEG(b) && NEG(c))
|| (NEG(a) && NEG(b) && !NEG(c)));
#undef NEG
}
-/
def will_add_overflow_expression (a b : BitVec 32) : Bool :=
let c := a + b
let NEG (x : BitVec 32) : Bool :=
(x &&& 0x80000000#32) == 0x80000000#32
(!NEG a && !NEG b && NEG c) || (NEG a && NEG b && !NEG c)
example (a b : BitVec 32) : will_add_overflow_64bit a b = will_add_overflow_expression a b := by
dsimp [will_add_overflow_64bit, will_add_overflow_expression]
intros; bv_decide
/-
bool will_add_overflow_bitwise_2(int32_t a_, int32_t b_) {
uint32_t a = (uint32_t)a_, b = (uint32_t)b_;
uint32_t c = (uint32_t)a + (uint32_t)b;
#define NEG(x) (((uint32_t)(x) & 0x80000000) == 0x80000000)
return NEG((~a & ~b & c) | (a & b & ~c));
#undef NEG
}
-/
def will_add_overflow_bitwise_2 (a b : BitVec 32) : Bool :=
let c := a + b
let NEG (x : BitVec 32) : Bool :=
((x &&& 0x80000000#32) == 0x80000000#32)
NEG ((~~~a &&& ~~~b &&& c) ||| (a &&& b &&& ~~~c))
example (a b : BitVec 32) : will_add_overflow_expression a b = will_add_overflow_bitwise_2 a b := by
dsimp [will_add_overflow_expression, will_add_overflow_bitwise_2]
intros; bv_decide
/-
bool will_add_overflow_bitwise_3(int32_t a_, int32_t b_) {
uint32_t a = (uint32_t)a_, b = (uint32_t)b_;
uint32_t c = (uint32_t)a + (uint32_t)b;
return ((~a & ~b & c) | (a & b & ~c)) >> 31;
}
-/
def will_add_overflow_bitwise_3 (a b : BitVec 32) : Bool :=
let c := a + b
getLsbD (((~~~a &&& ~~~b &&& c) ||| (a &&& b &&& ~~~c)) >>> 31) 0
example (a b : BitVec 32) : will_add_overflow_bitwise_2 a b = will_add_overflow_bitwise_3 a b := by
dsimp [will_add_overflow_bitwise_2, will_add_overflow_bitwise_3]
intros; bv_decide
/-
bool will_add_overflow_optimized_a(int32_t a_, int32_t b_) {
uint32_t a = (uint32_t)a_, b = (uint32_t)b_;
uint32_t c = (uint32_t)a + (uint32_t)b;
return (~(a ^ b) & (c ^ a)) >> 31;
}
-/
def will_add_overflow_optimized_a (a b : BitVec 32) : Bool :=
let c := a + b
getLsbD ((~~~(a ^^^ b) &&& (c ^^^ a)) >>> 31) 0
example (a b : BitVec 32) :
will_add_overflow_bitwise_3 a b = will_add_overflow_optimized_a a b := by
dsimp [will_add_overflow_bitwise_3, will_add_overflow_optimized_a]
intros; bv_decide
/-
bool will_add_overflow_optimized_b(int32_t a_, int32_t b_) {
uint32_t a = (uint32_t)a_, b = (uint32_t)b_;
uint32_t c = (uint32_t)a + (uint32_t)b;
return ((c ^ a) & (c ^ b)) >> 31;
}
-/
def will_add_overflow_optimized_b (a b : BitVec 32) : Bool :=
let c := a + b
getLsbD (((c ^^^ a) &&& (c ^^^ b)) >>> 31) 0
example (a b : BitVec 32) :
will_add_overflow_optimized_a a b = will_add_overflow_optimized_b a b := by
dsimp [will_add_overflow_optimized_a, will_add_overflow_optimized_b]
intros; bv_decide
end DerivingBitTwiddlingHack