This normalized a bitvec using ofFin
to ofNat
.
msb #
cast #
toInt/ofInt #
slt #
setWidth, zeroExtend and truncate #
extractLsb #
allOnes #
or #
and #
xor #
not #
Negating x
and then extracting [start..start+len) is the same as extracting and then negating,
as long as the range [start..start+len) is in bounds.
See that if the index is out-of-bounds, then extractLsb
will return false
,
which makes the operation not commute.
Negating x
and then extracting [lo:hi] is the same as extracting and then negating.
For the extraction to be well-behaved,
we need the range [lo:hi] to be a valid closed interval inside the bitvector:
lo ≤ hi
for the interval to be a well-formed closed interval.hi < w
, for the interval to be contained inside the bitvector.
cast #
shiftLeft #
shiftLeft reductions from BitVec to Nat #
ushiftRight #
Unsigned shift right by at least one bit makes the interpretations of the bitvector as an Int
or Nat
agree,
because it makes the value of the bitvector less than or equal to 2^(w-1)
.
In the case when n = 0
, then the shift right value equals the integer interpretation.
sshiftRight #
If the msb is true
, the arithmetic shift right equals negating,
then logical shifting right, then negating again.
The double negation preserves the lower bits that have been shifted,
and the outer negation ensures that the high bits are '1'.
The msb after arithmetic shifting right equals the original msb.
sshiftRight reductions from BitVec to Nat #
signExtend #
The sign extension is a bitwise not, followed by a zero extend, followed by another bitwise not
when msb = true
. The double bitwise not ensures that the high bits are '1',
and the lower bits are preserved.
Sign extending to a width smaller than the starting width is a truncation.
Sign extending to the same bitwidth is a no op.
Sign extending to a larger bitwidth depends on the msb.
If the msb is false, then the result equals the original value.
If the msb is true, then we add a value of (2^v - 2^w)
, which arises from the sign extension.
append #
rev #
cons #
concat #
shiftConcat #
add #
sub/neg #
add self #
fill #
mul #
le and lt #
udiv #
umod #
smtUDiv #
sdiv #
smtSDiv #
srem #
smod #
Equation theorem for smod
in terms of umod
.
ofBoolList #
Rotate Left #
rotateLeft
is invariant under mod
by the bitwidth.
rotateLeft
equals the bit fiddling definition of rotateLeftAux
when the rotation amount is
smaller than the bitwidth.
Accessing bits in x.rotateLeft r
the range [0, r)
is equal to
accessing bits x
in the range [w - r, w)
.
Proof by example: Let x := <6 5 4 3 2 1 0> : BitVec 7. x.rotateLeft 2 = (<6 5 | 4 3 2 1 0>).rotateLeft 2 = <3 2 1 0 | 6 5>
(x.rotateLeft 2).getLsbD ⟨i, i < 2⟩ = <3 2 1 0 | 6 5>.getLsbD ⟨i, i < 2⟩ = <6 5>[i] = <6 5 | 4 3 2 1 0>[i + len(<4 3 2 1 0>)] = <6 5 | 4 3 2 1 0>[i + 7 - 2]
Accessing bits in x.rotateLeft r
the range [r, w)
is equal to
accessing bits x
in the range [0, w - r)
.
Proof by example: Let x := <6 5 4 3 2 1 0> : BitVec 7. x.rotateLeft 2 = (<6 5 | 4 3 2 1 0>).rotateLeft 2 = <3 2 1 0 | 6 5>
(x.rotateLeft 2).getLsbD ⟨i, i ≥ 2⟩ = <3 2 1 0 | 6 5>.getLsbD ⟨i, i ≥ 2⟩ = <3 2 1 0>[i - 2] = <6 5 | 3 2 1 0>[i - 2]
Intuitively, grab the full width (7), then move the marker |
by r
to the right (-2)
Then, access the bit at i
from the right (+i)
.
Rotate Right #
Accessing bits in x.rotateRight r
the range [0, w-r)
is equal to
accessing bits x
in the range [r, w)
.
Proof by example: Let x := <6 5 4 3 2 1 0> : BitVec 7. x.rotateRight 2 = (<6 5 4 3 2 | 1 0>).rotateRight 2 = <1 0 | 6 5 4 3 2>
(x.rotateLeft 2).getLsbD ⟨i, i ≤ 7 - 2⟩ = <1 0 | 6 5 4 3 2>.getLsbD ⟨i, i ≤ 7 - 2⟩ = <6 5 4 3 2>.getLsbD i = <6 5 4 3 2 | 1 0>[i + 2]
Accessing bits in x.rotateRight r
the range [w-r, w)
is equal to
accessing bits x
in the range [0, r)
.
Proof by example: Let x := <6 5 4 3 2 1 0> : BitVec 7. x.rotateRight 2 = (<6 5 4 3 2 | 1 0>).rotateRight 2 = <1 0 | 6 5 4 3 2>
(x.rotateLeft 2).getLsbD ⟨i, i ≥ 7 - 2⟩ = <1 0 | 6 5 4 3 2>.getLsbD ⟨i, i ≤ 7 - 2⟩ = <1 0>.getLsbD (i - len(<6 5 4 3 2>) = <6 5 4 3 2 | 1 0> (i - len<6 4 4 3 2>)
rotateRight
equals the bit fiddling definition of rotateRightAux
when the rotation amount is
smaller than the bitwidth.
rotateRight is invariant under mod
by the bitwidth.
When the (i+1)
th bit of x
is true,
keeping the lower (i + 1)
bits of x
equalsk eeping the lower i
bits
and then performing bitwise-or with twoPow i = (1 << i)
,
intMin #
The bitvector of width w
that has the smallest value when interpreted as an integer.
Equations
- BitVec.intMin w = BitVec.twoPow w (w - 1)
Instances For
intMax #
The bitvector of width w
that has the largest value when interpreted as an integer.
Equations
- BitVec.intMax w = BitVec.twoPow w (w - 1) - 1
Instances For
Non-overflow theorems #
neg #
abs #
The absolute value of x : BitVec w
, interpreted as an integer, is a case split:
- When
x = intMin w
, thenx.abs = intMin w
- Otherwise,
x.abs.toInt
equals the absolute value (x.toInt.natAbs
).
This is a simpler version of BitVec.toInt_abs_eq_ite
, which hides a case split on x.msb
.
Reverse #
Decidable quantifiers #
Equations
- BitVec.instDecidableForallBitVecSucc P = decidable_of_iff' (∀ (x : Bool) (v : BitVec n), P (BitVec.cons x v)) ⋯
Equations
- BitVec.instDecidableExistsBitVecSucc P = decidable_of_iff (¬∀ (v : BitVec (n + 1)), ¬P v) ⋯
For small numerals this isn't necessary (as typeclass search can use the above two instances),
but for large numerals this provides a shortcut.
Note, however, that for large numerals the decision procedure may be very slow,
and you should use bv_decide
if possible.
Equations
For small numerals this isn't necessary (as typeclass search can use the above two instances), but for large numerals this provides a shortcut. Note, however, that for large numerals the decision procedure may be very slow.