@@ -11,6 +11,7 @@ known equivalent values.
11
11
{-# LANGUAGE FlexibleContexts #-}
12
12
{-# LANGUAGE KindSignatures #-}
13
13
{-# LANGUAGE MultiParamTypeClasses #-}
14
+ {-# LANGUAGE MultiWayIf #-}
14
15
{-# LANGUAGE OverloadedStrings #-}
15
16
{-# LANGUAGE PolyKinds #-}
16
17
{-# LANGUAGE RankNTypes #-}
@@ -400,7 +401,7 @@ exprRangePred info e = do
400
401
lowerBound = truncUnsigned $ rangeLowerBound r
401
402
upperBound = truncUnsigned $ rangeUpperBound r
402
403
in
403
- SomeRangePred (mkRangeBound w lowerBound upperBound)
404
+ SomeRangePred (mkRangeBound w lowerBound upperBound)
404
405
_ -> NoRangePred
405
406
406
407
-- | This returns a natural number with a computed upper bound for the
@@ -674,89 +675,159 @@ addRangePred cns v p =
674
675
_ ->
675
676
Right $ branchAssignRangePred n p
676
677
678
+ -- | @addLowerBoundPred cns w l x@ adds a @l <= x@ constraint over the `w`-bit-truncated values.
679
+ -- Fails when the bound excludes all possible values (lower bound greater than the maximum `w`-bit
680
+ -- value).
681
+ -- Note: The arguments are ordered so that it reads more naturally, as the difference of type
682
+ -- between `l` and `x` prevents mistakes.
683
+ addLowerBoundPred ::
684
+ RegisterInfo (ArchReg arch ) =>
685
+ BlockIntraStackConstraints arch ids -> NatRepr n -> Integer -> Value arch ids (BVType n ) ->
686
+ Either String (BranchConstraints arch ids )
687
+ addLowerBoundPred cns w l x
688
+ | l > maxUnsigned w = Left " Lower bound excludes all possible values"
689
+ | otherwise = addRangePred cns (intraStackValueExpr cns x) $! mkLowerBound w (fromInteger l)
690
+
691
+ -- | @addUpperBoundPred cns w x u@ adds a @x <= u@ constraint over the `w`-bit-truncated values.
692
+ -- Fails when the bound excludes all possible values (`u` < 0).
693
+ addUpperBoundPred ::
694
+ RegisterInfo (ArchReg arch ) =>
695
+ BlockIntraStackConstraints arch ids -> NatRepr n -> Value arch ids (BVType n ) -> Integer ->
696
+ Either String (BranchConstraints arch ids )
697
+ addUpperBoundPred cns w x u
698
+ | u < 0 = Left " Upper bound excludes all possible values"
699
+ | otherwise = addRangePred cns (intraStackValueExpr cns x) $! mkUpperBound w (fromInteger u)
700
+
701
+ clamp :: NatRepr w -> Integer -> Integer
702
+ clamp w x
703
+ | x < 0 = 0
704
+ | x > maxUnsigned w = maxUnsigned w
705
+ | otherwise = x
706
+
707
+ -- | @addWithinRangePred cns w l x u@ adds a @l <= x <= u@ constraint over the `w`-bit-truncated values.
708
+ -- Fails when the bound excludes all possible values.
709
+ -- Note: The arguments are ordered so that it reads more naturally.
710
+ addWithinRangePred ::
711
+ RegisterInfo (ArchReg arch ) =>
712
+ BlockIntraStackConstraints arch ids -> NatRepr n -> Integer -> Value arch ids (BVType n ) -> Integer ->
713
+ Either String (BranchConstraints arch ids )
714
+ addWithinRangePred cns w l x u
715
+ -- Note: we could avoid this duplication by instead producing a conjunction of `addLowerBoundPred`
716
+ -- and `addUpperBoundPred`, but this produces a single range instead.
717
+ | l > maxUnsigned w = Left " Lower bound excludes all possible values"
718
+ | u < 0 = Left " Upper bound excludes all possible values"
719
+ | clamp w u < clamp w l = Left " Empty range excludes all possible values"
720
+ | otherwise =
721
+ addRangePred cns (intraStackValueExpr cns x) $! mkRangeBound w (fromInteger l) (fromInteger u)
722
+
723
+ -- | @addExcludeRangePred cns w x l u@ adds a @(x < l) or (u < x)@ constraint over the
724
+ -- `w`-bit-truncated values. Fails when the bound excludes all possible values.
725
+ addExcludeRangePred ::
726
+ RegisterInfo (ArchReg arch ) =>
727
+ BlockIntraStackConstraints arch ids -> NatRepr n -> Value arch ids (BVType n ) -> Integer -> Integer ->
728
+ Either String (BranchConstraints arch ids )
729
+ addExcludeRangePred cns w x l u = do
730
+ let lowerBoundTooLow = l <= 0 -- (l - 1) would be negative
731
+ let upperBoundTooHigh = u >= maxUnsigned w -- (u + 1) would overflow
732
+ if
733
+ | lowerBoundTooLow && upperBoundTooHigh -> Left " Excluded range excludes all possible values"
734
+ | lowerBoundTooLow -> addLowerBoundPred cns w (u + 1 ) x
735
+ | upperBoundTooHigh -> addUpperBoundPred cns w x (l - 1 )
736
+ | otherwise ->
737
+ -- compiles it to @(x <= l - 1) or (u + 1 <= x)@
738
+ disjoinBranchConstraints
739
+ <$> addUpperBoundPred cns w x (l - 1 )
740
+ <*> addLowerBoundPred cns w (u + 1 ) x
741
+
742
+ -- | @assertEqPred cns x w c isTrue@ asserts equality @x = BVValue c w@ is either true or false,
743
+ -- based on `isTrue`.
744
+ assertEqPred ::
745
+ RegisterInfo (ArchReg arch ) =>
746
+ -- | Constraints that let us evaluate `x`
747
+ BlockIntraStackConstraints arch ids ->
748
+ -- | Bitwidth the comparison should apply to
749
+ NatRepr w ->
750
+ -- | Value to be constrained
751
+ Value arch ids (BVType w ) ->
752
+ -- | Numeric constant x should be equal/different to
753
+ Integer ->
754
+ -- | `True` if we should assert equality, `False` if we should assert non-equality
755
+ Bool ->
756
+ Either String (BranchConstraints arch ids )
757
+ assertEqPred cns w x c isTrue
758
+ | isTrue =
759
+ -- x == c becomes c <= x <= c
760
+ addWithinRangePred cns w c x c
761
+ | otherwise =
762
+ -- !(x == c) is handled via !(c <= x <= c) and becomes (x <= c - 1) or (c + 1 <= x)
763
+ addExcludeRangePred cns w x c c
764
+
677
765
-- | Assert a predicate is true/false and update bounds.
678
766
--
679
767
-- If it returns a new upper bounds, then that may be used.
680
768
-- Otherwise, it detects an inconsistency and returns a message
681
769
-- explaing why.
682
- assertPred :: ( OrdF (ArchReg arch )
683
- , HasRepr (ArchReg arch ) TypeRepr
684
- , MemWidth (ArchAddrWidth arch )
685
- , ShowF (ArchReg arch )
686
- )
770
+ assertPred :: RegisterInfo (ArchReg arch )
687
771
=> IntraJumpBounds arch ids
688
772
-> Value arch ids BoolType -- ^ Value representing predicate
689
773
-> Bool -- ^ Controls whether predicate is true or false
690
774
-> Either String (BranchConstraints arch ids )
691
775
assertPred bnds (AssignedValue a) isTrue = do
692
776
let cns = intraStackConstraints bnds
693
777
case assignRhs a of
694
- EvalApp (Eq x (BVValue w c)) -> do
695
- addRangePred cns (intraStackValueExpr cns x)
696
- (mkRangeBound w (fromInteger c) (fromInteger c))
697
- EvalApp (Eq (BVValue w c) x) -> do
698
- addRangePred cns (intraStackValueExpr cns x)
699
- (mkRangeBound w (fromInteger c) (fromInteger c))
700
- -- Given x < c), assert x <= c-1
701
- EvalApp (BVUnsignedLt x (BVValue _ c)) -> do
702
- if isTrue then do
703
- when (c == 0 ) $ Left " x < 0 must be false."
704
- addRangePred cns (intraStackValueExpr cns x) $!
705
- mkUpperBound (typeWidth x) (fromInteger (c- 1 ))
706
- else do
707
- addRangePred cns (intraStackValueExpr cns x) $!
708
- mkLowerBound (typeWidth x) (fromInteger c)
709
- -- Given not (c < y), assert y <= c
710
- EvalApp (BVUnsignedLt (BVValue w c) y) -> do
711
- p <-
712
- if isTrue then do
713
- when (c >= maxUnsigned w) $ Left " x <= max_unsigned must be true"
714
- pure $! mkLowerBound w (fromInteger (c+ 1 ))
715
- else do
716
- pure $! mkUpperBound w (fromInteger c)
717
- addRangePred cns (intraStackValueExpr cns y) p
718
- -- Given x <= c, assert x <= c
719
- EvalApp (BVUnsignedLe x (BVValue w c)) -> do
720
- p <-
721
- if isTrue then
722
- pure $! mkUpperBound w (fromInteger c)
723
- else do
724
- when (c >= maxUnsigned w) $ Left " x <= max_unsigned must be true"
725
- pure $! mkLowerBound w (fromInteger (c+ 1 ))
726
- addRangePred cns (intraStackValueExpr cns x) p
727
- -- Given not (c <= y), assert y <= (c-1)
728
- EvalApp (BVUnsignedLe (BVValue _ c) y)
729
- | isTrue -> do
730
- addRangePred cns (intraStackValueExpr cns y)
731
- (mkLowerBound (typeWidth y) (fromInteger c))
732
- | otherwise -> do
733
- when (c == 0 ) $ Left " 0 <= x cannot be false"
734
- addRangePred cns
735
- (intraStackValueExpr cns y)
736
- (mkUpperBound (typeWidth y) (fromInteger (c- 1 )))
737
- EvalApp (AndApp l r) ->
738
- if isTrue then
778
+ EvalApp (Eq x (BVValue w c)) -> assertEqPred cns w x c isTrue
779
+ EvalApp (Eq (BVValue w c) x) -> assertEqPred cns w x c isTrue
780
+ EvalApp (BVUnsignedLt x (BVValue w c))
781
+ | isTrue ->
782
+ -- x < c becomes x <= c - 1
783
+ addUpperBoundPred cns w x (c - 1 )
784
+ | otherwise ->
785
+ -- !(x < c) becomes c <= x
786
+ addLowerBoundPred cns w c x
787
+ EvalApp (BVUnsignedLt (BVValue w c) y)
788
+ | isTrue ->
789
+ -- c < y becomes c + 1 <= y
790
+ addLowerBoundPred cns w (c + 1 ) y
791
+ | otherwise ->
792
+ -- !(c < y) becomes y <= c
793
+ addUpperBoundPred cns w y c
794
+ EvalApp (BVUnsignedLe x (BVValue w c))
795
+ | isTrue ->
796
+ -- x <= c
797
+ addUpperBoundPred cns w x c
798
+ | otherwise ->
799
+ -- !(x <= c) becomes c + 1 <= x
800
+ addLowerBoundPred cns w (c + 1 ) x
801
+ EvalApp (BVUnsignedLe (BVValue w c) y)
802
+ | isTrue ->
803
+ -- c <= y
804
+ addLowerBoundPred cns w c y
805
+ | otherwise ->
806
+ -- !(c <= y) becomes y <= c - 1
807
+ addUpperBoundPred cns w y (c - 1 )
808
+ EvalApp (AndApp l r)
809
+ | isTrue ->
810
+ -- l && r
739
811
conjoinBranchConstraints
740
812
<$> assertPred bnds l True
741
813
<*> assertPred bnds r True
742
- else
814
+ | otherwise ->
815
+ -- !(l && r) becomes !l || !r
743
816
disjoinBranchConstraints
744
817
<$> assertPred bnds l False
745
818
<*> assertPred bnds r False
746
- -- Given not (x || y), assert not x, then assert not y
747
- EvalApp (OrApp l r) ->
748
- if isTrue then
749
- -- Assert l | r
819
+ EvalApp (OrApp l r)
820
+ | isTrue ->
821
+ -- l || r
750
822
disjoinBranchConstraints
751
823
<$> assertPred bnds l True
752
824
<*> assertPred bnds r True
753
- else
754
- -- Assert not l && not r
825
+ | otherwise ->
826
+ -- !(l || r) becomes ! l && ! r
755
827
conjoinBranchConstraints
756
828
<$> assertPred bnds l False
757
829
<*> assertPred bnds r False
758
- EvalApp (NotApp p) ->
759
- assertPred bnds p (not isTrue)
830
+ EvalApp (NotApp p) -> assertPred bnds p (not isTrue)
760
831
_ -> Right emptyBranchConstraints
761
832
assertPred _ _ _ =
762
833
Right emptyBranchConstraints
0 commit comments