Skip to content

Commit e769747

Browse files
author
brianhuffman
authored
Merge pull request #29 from GaloisInc/fix-bvdomain
Fix bugs in abstract bitvector domain operations `sdiv` and `srem`.
2 parents fccc96b + 14881f5 commit e769747

File tree

2 files changed

+37
-31
lines changed

2 files changed

+37
-31
lines changed

what4/doc/bvdomain.cry

+13-11
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,15 @@ sbounds a = (lo - delta, hi - delta)
7474
delta = reverse 1
7575
(lo, hi) = ubounds (interval (a.lo + delta) a.sz)
7676

77-
/** Least and greatest nonzero values in a domain, according to the
78-
unsigned ordering. */
77+
/** Nonzero signed values in a domain with the least and greatest
78+
reciprocals. Note that this coincides with the greatest and least
79+
nonzero values using the unsigned ordering. */
7980
rbounds : {n} (fin n, n >= 1) => BVDom n -> ([n], [n])
8081
rbounds a =
81-
if a.lo == 0 then (1, a_hi) else
82-
if a_hi == 0 then (a.lo, ~0) else
83-
if a_hi < a.lo then (1, ~0) else
84-
(a.lo, a_hi)
82+
if a.lo == 0 then (a_hi, 1) else
83+
if a_hi == 0 then (-1, a.lo) else
84+
if a_hi < a.lo then (-1, 1) else
85+
(a_hi, a.lo)
8586
where a_hi = a.lo + a.sz
8687

8788
overlap : {n} (fin n) => BVDom n -> BVDom n -> Bit
@@ -203,14 +204,15 @@ urem a b =
203204
(ql, rl) = (al / bh', al % bh')
204205
(qh, rh) = (ah / bl', ah % bl')
205206

206-
// The first argument is a signed interval, but the second argument is
207-
// an unsigned interval: The arguments should satisfy 'al <=$ ah'
208-
// (signed) and 'bl <= bh' (unsigned).
207+
// The first argument is an ordinary signed interval, but the second
208+
// argument is a reciprocal interval: The arguments should satisfy 'al
209+
// <=$ ah' (signed) and '1/bl <= 1/bh' (signed), or equivalently, 'bh
210+
// <= bl' (unsigned).
209211
sdivRange : {n} (fin n, n >= 1) => ([n], [n]) -> ([n], [n]) -> ([1+n], [1+n])
210212
sdivRange (al, ah) (bl, bh) = (ql, qh)
211213
where
212-
(ql1, qh1) = shrinkRange (al, ah) bl
213-
(ql2, qh2) = shrinkRange (al, ah) bh
214+
(ql1, qh1) = shrinkRange (al, ah) bh
215+
(ql2, qh2) = shrinkRange (al, ah) bl
214216
ql = smin ql1 ql2
215217
qh = smax qh1 qh2
216218

what4/src/What4/Utils/BVDomain.hs

+24-20
Original file line numberDiff line numberDiff line change
@@ -469,29 +469,33 @@ urem a b
469469
(ql, rl) = al `divMod` max 1 bh -- assume that division by 0 does not happen
470470
(qh, rh) = ah `divMod` max 1 bl -- assume that division by 0 does not happen
471471

472-
-- | Least and greatest nonzero values in a domain, according to the
473-
-- unsigned ordering.
474-
rbounds :: BVDomain w -> (Integer, Integer)
475-
rbounds a =
472+
-- | Pairs of nonzero integers @(lo, hi)@ such that @1\/lo <= 1\/hi@.
473+
-- This pair represents the set of all nonzero integers @x@ such that
474+
-- @1\/lo <= 1\/x <= 1\/hi@.
475+
data ReciprocalRange = ReciprocalRange Integer Integer
476+
477+
-- | Nonzero signed values in a domain with the least and greatest
478+
-- reciprocals.
479+
rbounds :: (1 <= w) => NatRepr w -> BVDomain w -> ReciprocalRange
480+
rbounds w a =
476481
case a of
477-
BVDAny mask -> (1, mask)
482+
BVDAny _ -> ReciprocalRange (-1) 1
478483
BVDInterval mask al aw
479-
| ah > mask + 1 -> (1, mask)
480-
| otherwise -> (max 1 al, min mask aw)
481-
where ah = al + aw
484+
| ah > mask + 1 -> ReciprocalRange (-1) 1
485+
| otherwise -> ReciprocalRange (signed (min mask ah)) (signed (max 1 al))
486+
where
487+
ah = al + aw
488+
signed x = if x < halfRange w then x else x - (mask + 1)
482489

483490
-- | Interval arithmetic for integer division (rounding towards 0).
484-
-- The argument ranges @(al, ah)@ and @(bl, bh)@ should satisfy @al <=
485-
-- ah@ and @1\/bl >= 1\/bh@. That is, if @bl@ and @bh@ have the same
486-
-- sign, then we require @bl <= bh@, but if they have opposite signs
487-
-- then we require @bl > bh@. Given @a@ and @b@ with @al <= a <= ah@
488-
-- and @1\/bl >= 1\/b >= 1/bh@, @sdivRange (al, ah) (bl, bh)@ returns
489-
-- @(ql, qh)@ such that @ql <= a `quot` b <= qh@.
490-
sdivRange :: (Integer, Integer) -> (Integer, Integer) -> (Integer, Integer)
491-
sdivRange (al, ah) (bl, bh) = (ql, qh)
491+
-- Given @a@ and @b@ with @al <= a <= ah@ and @1\/bl <= 1\/b <= 1/bh@,
492+
-- @sdivRange (al, ah) (ReciprocalRange bl bh)@ returns @(ql, qh)@
493+
-- such that @ql <= a `quot` b <= qh@.
494+
sdivRange :: (Integer, Integer) -> ReciprocalRange -> (Integer, Integer)
495+
sdivRange (al, ah) (ReciprocalRange bl bh) = (ql, qh)
492496
where
493-
(ql1, qh1) = scaleDownRange (al, ah) bl
494-
(ql2, qh2) = scaleDownRange (al, ah) bh
497+
(ql1, qh1) = scaleDownRange (al, ah) bh
498+
(ql2, qh2) = scaleDownRange (al, ah) bl
495499
ql = min ql1 ql2
496500
qh = max qh1 qh2
497501

@@ -507,7 +511,7 @@ sdiv :: (1 <= w) => NatRepr w -> BVDomain w -> BVDomain w -> BVDomain w
507511
sdiv w a b = interval mask ql (qh - ql)
508512
where
509513
mask = bvdMask a
510-
(ql, qh) = sdivRange (sbounds w a) (sbounds w b)
514+
(ql, qh) = sdivRange (sbounds w a) (rbounds w b)
511515

512516
srem :: (1 <= w) => NatRepr w -> BVDomain w -> BVDomain w -> BVDomain w
513517
srem w a b =
@@ -524,7 +528,7 @@ srem w a b =
524528
mask = bvdMask a
525529
(al, ah) = sbounds w a
526530
(bl, bh) = sbounds w b
527-
(ql, qh) = sdivRange (al, ah) (rbounds b)
531+
(ql, qh) = sdivRange (al, ah) (rbounds w b)
528532
rl = if al < 0 then min (bl+1) (-bh+1) else 0
529533
rh = if ah > 0 then max (-bl-1) (bh-1) else 0
530534
aw = ah - al

0 commit comments

Comments
 (0)