@@ -289,6 +289,10 @@ signature module LangSig<Semantic Sem, DeltaSig D> {
289289 predicate ignoreExprBound ( Sem:: Expr e ) ;
290290
291291 default predicate javaCompatibility ( ) { none ( ) }
292+
293+ default predicate includeConstantBounds ( ) { any ( ) }
294+
295+ default predicate includeRelativeBounds ( ) { any ( ) }
292296}
293297
294298signature module BoundSig< LocationSig Location, Semantic Sem, DeltaSig D> {
@@ -678,60 +682,65 @@ module RangeStage<
678682 * - `upper = false` : `e2 >= e1 + delta`
679683 */
680684 private predicate boundFlowStep ( Sem:: Expr e2 , Sem:: Expr e1 , D:: Delta delta , boolean upper ) {
681- valueFlowStep ( e2 , e1 , delta ) and
682- ( upper = true or upper = false )
683- or
684- e2 . ( SafeCastExpr ) . getOperand ( ) = e1 and
685- delta = D :: fromInt ( 0 ) and
686- ( upper = true or upper = false )
687- or
688- javaCompatibility ( ) and
689- exists ( Sem :: Expr x , Sem :: SubExpr sub |
690- e2 = sub and
691- sub . getLeftOperand ( ) = e1 and
692- sub . getRightOperand ( ) = x
693- |
694- // `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
695- not x instanceof Sem :: ConstantIntegerExpr and
696- if strictlyPositiveIntegralExpr ( x )
697- then upper = true and delta = D :: fromInt ( - 1 )
698- else
699- if semPositive ( x )
700- then upper = true and delta = D:: fromInt ( 0 )
685+ // Constants have easy, base-case bounds, so let's not infer any recursive bounds.
686+ not e2 instanceof Sem :: ConstantIntegerExpr and
687+ (
688+ valueFlowStep ( e2 , e1 , delta ) and
689+ upper = [ true , false ]
690+ or
691+ e2 . ( SafeCastExpr ) . getOperand ( ) = e1 and
692+ delta = D :: fromInt ( 0 ) and
693+ upper = [ true , false ]
694+ or
695+ javaCompatibility ( ) and
696+ exists ( Sem :: Expr x , Sem :: SubExpr sub |
697+ e2 = sub and
698+ sub . getLeftOperand ( ) = e1 and
699+ sub . getRightOperand ( ) = x
700+ |
701+ // `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
702+ not x instanceof Sem :: ConstantIntegerExpr and
703+ if strictlyPositiveIntegralExpr ( x )
704+ then upper = true and delta = D:: fromInt ( - 1 )
701705 else
702- if strictlyNegativeIntegralExpr ( x )
703- then upper = false and delta = D:: fromInt ( 1 )
706+ if semPositive ( x )
707+ then upper = true and delta = D:: fromInt ( 0 )
704708 else
705- if semNegative ( x )
706- then upper = false and delta = D:: fromInt ( 0 )
707- else none ( )
709+ if strictlyNegativeIntegralExpr ( x )
710+ then upper = false and delta = D:: fromInt ( 1 )
711+ else
712+ if semNegative ( x )
713+ then upper = false and delta = D:: fromInt ( 0 )
714+ else none ( )
715+ )
716+ or
717+ e2 .( Sem:: RemExpr ) .getRightOperand ( ) = e1 and
718+ semPositive ( e1 ) and
719+ delta = D:: fromInt ( - 1 ) and
720+ upper = true
721+ or
722+ e2 .( Sem:: RemExpr ) .getLeftOperand ( ) = e1 and
723+ semPositive ( e1 ) and
724+ delta = D:: fromInt ( 0 ) and
725+ upper = true
726+ or
727+ e2 .( Sem:: BitAndExpr ) .getAnOperand ( ) = e1 and
728+ semPositive ( e1 ) and
729+ delta = D:: fromInt ( 0 ) and
730+ upper = true
731+ or
732+ e2 .( Sem:: BitOrExpr ) .getAnOperand ( ) = e1 and
733+ semPositive ( e2 ) and
734+ delta = D:: fromInt ( 0 ) and
735+ upper = false
736+ or
737+ additionalBoundFlowStep ( e2 , e1 , delta , upper )
708738 )
709- or
710- e2 .( Sem:: RemExpr ) .getRightOperand ( ) = e1 and
711- semPositive ( e1 ) and
712- delta = D:: fromInt ( - 1 ) and
713- upper = true
714- or
715- e2 .( Sem:: RemExpr ) .getLeftOperand ( ) = e1 and
716- semPositive ( e1 ) and
717- delta = D:: fromInt ( 0 ) and
718- upper = true
719- or
720- e2 .( Sem:: BitAndExpr ) .getAnOperand ( ) = e1 and
721- semPositive ( e1 ) and
722- delta = D:: fromInt ( 0 ) and
723- upper = true
724- or
725- e2 .( Sem:: BitOrExpr ) .getAnOperand ( ) = e1 and
726- semPositive ( e2 ) and
727- delta = D:: fromInt ( 0 ) and
728- upper = false
729- or
730- additionalBoundFlowStep ( e2 , e1 , delta , upper )
731739 }
732740
733741 /** Holds if `e2 = e1 * factor` and `factor > 0`. */
734742 private predicate boundFlowStepMul ( Sem:: Expr e2 , Sem:: Expr e1 , D:: Delta factor ) {
743+ not e2 instanceof Sem:: ConstantIntegerExpr and
735744 exists ( Sem:: ConstantIntegerExpr c , int k | k = c .getIntValue ( ) and k > 0 |
736745 e2 .( Sem:: MulExpr ) .hasOperands ( e1 , c ) and factor = D:: fromInt ( k )
737746 or
@@ -751,6 +760,7 @@ module RangeStage<
751760 * therefore only valid for non-negative numbers.
752761 */
753762 private predicate boundFlowStepDiv ( Sem:: Expr e2 , Sem:: Expr e1 , D:: Delta factor ) {
763+ not e2 instanceof Sem:: ConstantIntegerExpr and
754764 Sem:: getExprType ( e2 ) instanceof Sem:: IntegerType and
755765 exists ( Sem:: ConstantIntegerExpr c , D:: Delta k |
756766 k = D:: fromInt ( c .getIntValue ( ) ) and D:: toFloat ( k ) > 0
@@ -983,16 +993,31 @@ module RangeStage<
983993 )
984994 }
985995
996+ private predicate includeBound ( SemBound b ) {
997+ // always include phi bounds
998+ b .( SemSsaBound ) .getVariable ( ) instanceof Sem:: SsaPhiNode
999+ or
1000+ if b instanceof SemZeroBound then includeConstantBounds ( ) else includeRelativeBounds ( )
1001+ }
1002+
9861003 /**
987- * Holds if `e` has an upper (for `upper = true`) or lower
988- * (for `upper = false`) bound of `b` .
1004+ * Holds if `e` has an intrinsic upper (for `upper = true`) or lower
1005+ * (for `upper = false`) bound of `b + delta` as a base case for range analysis .
9891006 */
990- private predicate baseBound ( Sem:: Expr e , D:: Delta b , boolean upper ) {
991- hasConstantBound ( e , b , upper )
992- or
993- upper = false and
994- b = D:: fromInt ( 0 ) and
995- semPositive ( e .( Sem:: BitAndExpr ) .getAnOperand ( ) )
1007+ private predicate baseBound ( Sem:: Expr e , SemBound b , D:: Delta delta , boolean upper ) {
1008+ includeBound ( b ) and
1009+ (
1010+ e = b .getExpr ( delta ) and
1011+ upper = [ true , false ]
1012+ or
1013+ hasConstantBound ( e , delta , upper ) and
1014+ b instanceof SemZeroBound
1015+ or
1016+ upper = false and
1017+ delta = D:: fromInt ( 0 ) and
1018+ semPositive ( e .( Sem:: BitAndExpr ) .getAnOperand ( ) ) and
1019+ b instanceof SemZeroBound
1020+ )
9961021 }
9971022
9981023 /**
@@ -1107,6 +1132,84 @@ module RangeStage<
11071132 bindingset [ x, y]
11081133 private float truncatingDiv ( float x , float y ) { result = ( x - ( x % y ) ) / y }
11091134
1135+ /**
1136+ * Holds if `e1 + delta` is a valid bound for `e2`.
1137+ * - `upper = true` : `e2 <= e1 + delta`
1138+ * - `upper = false` : `e2 >= e1 + delta`
1139+ *
1140+ * This is restricted to simple forward-flowing steps and disregards phi-nodes.
1141+ */
1142+ private predicate preBoundStep ( Sem:: Expr e2 , Sem:: Expr e1 , D:: Delta delta , boolean upper ) {
1143+ boundFlowStep ( e2 , e1 , delta , upper )
1144+ or
1145+ exists ( Sem:: SsaVariable v , SsaReadPositionBlock bb |
1146+ boundFlowStepSsa ( v , bb , e1 , delta , upper , _) and
1147+ bb .getAnSsaRead ( v ) = e2
1148+ )
1149+ }
1150+
1151+ /**
1152+ * Holds if simple forward-flowing steps from `e` can reach an expression that
1153+ * has multiple incoming bound-flow edges, that is, it has multiple ways to
1154+ * get a valid bound.
1155+ */
1156+ private predicate reachesBoundMergepoint ( Sem:: Expr e , boolean upper ) {
1157+ 2 <= strictcount ( Sem:: Expr mid | preBoundStep ( e , mid , _, upper ) )
1158+ or
1159+ exists ( Sem:: SsaPhiNode v , SsaReadPositionBlock bb |
1160+ boundFlowStepSsa ( v , bb , _, _, upper , _) and
1161+ bb .getAnSsaRead ( v ) = e
1162+ )
1163+ or
1164+ exists ( Sem:: Expr e2 |
1165+ preBoundStep ( e2 , e , _, upper ) and
1166+ reachesBoundMergepoint ( e2 , upper )
1167+ )
1168+ }
1169+
1170+ pragma [ nomagic]
1171+ private predicate relevantPreBoundStep ( Sem:: Expr e2 , Sem:: Expr e1 , D:: Delta delta , boolean upper ) {
1172+ preBoundStep ( e2 , e1 , delta , upper ) and
1173+ reachesBoundMergepoint ( e2 , upper )
1174+ }
1175+
1176+ /**
1177+ * Holds if `b + delta` is a valid bound for `e` that can be found using only
1178+ * simple forward-flowing steps and disregarding phi-nodes.
1179+ * - `upper = true` : `e <= b + delta`
1180+ * - `upper = false` : `e >= b + delta`
1181+ *
1182+ * This predicate is used as a fast approximation for `bounded` to avoid
1183+ * excessive computation in certain cases. In particular, this applies to
1184+ * loop-unrolled code like
1185+ * ```
1186+ * if (..) x+=1; else x+=100;
1187+ * x &= 7;
1188+ * if (..) x+=1; else x+=100;
1189+ * x &= 7;
1190+ * if (..) x+=1; else x+=100;
1191+ * x &= 7;
1192+ * ...
1193+ * ```
1194+ */
1195+ private predicate preBounded ( Sem:: Expr e , SemBound b , D:: Delta delta , boolean upper ) {
1196+ baseBound ( e , b , delta , upper )
1197+ or
1198+ exists ( Sem:: Expr mid , D:: Delta d1 , D:: Delta d2 |
1199+ relevantPreBoundStep ( e , mid , d1 , upper ) and
1200+ preBounded ( mid , b , d2 , upper ) and
1201+ delta = D:: fromFloat ( D:: toFloat ( d1 ) + D:: toFloat ( d2 ) )
1202+ )
1203+ }
1204+
1205+ private predicate bestPreBound ( Sem:: Expr e , SemBound b , D:: Delta delta , boolean upper ) {
1206+ delta = min ( D:: Delta d | preBounded ( e , b , d , upper ) | d order by D:: toFloat ( d ) ) and
1207+ upper = true
1208+ or
1209+ delta = max ( D:: Delta d | preBounded ( e , b , d , upper ) | d order by D:: toFloat ( d ) ) and
1210+ upper = false
1211+ }
1212+
11101213 /**
11111214 * Holds if `b + delta` is a valid bound for `e`.
11121215 * - `upper = true` : `e <= b + delta`
@@ -1117,15 +1220,14 @@ module RangeStage<
11171220 D:: Delta origdelta , SemReason reason
11181221 ) {
11191222 not ignoreExprBound ( e ) and
1120- (
1121- e = b .getExpr ( delta ) and
1122- ( upper = true or upper = false ) and
1123- fromBackEdge = false and
1124- origdelta = delta and
1125- reason = TSemNoReason ( )
1223+ // ignore poor bounds
1224+ not exists ( D:: Delta d | bestPreBound ( e , b , d , upper ) |
1225+ D:: toFloat ( delta ) > D:: toFloat ( d ) and upper = true
11261226 or
1127- baseBound ( e , delta , upper ) and
1128- b instanceof SemZeroBound and
1227+ D:: toFloat ( delta ) < D:: toFloat ( d ) and upper = false
1228+ ) and
1229+ (
1230+ baseBound ( e , b , delta , upper ) and
11291231 fromBackEdge = false and
11301232 origdelta = delta and
11311233 reason = TSemNoReason ( )
@@ -1137,8 +1239,6 @@ module RangeStage<
11371239 or
11381240 exists ( Sem:: Expr mid , D:: Delta d1 , D:: Delta d2 |
11391241 boundFlowStep ( e , mid , d1 , upper ) and
1140- // Constants have easy, base-case bounds, so let's not infer any recursive bounds.
1141- not e instanceof Sem:: ConstantIntegerExpr and
11421242 bounded ( mid , b , d2 , upper , fromBackEdge , origdelta , reason ) and
11431243 // upper = true: e <= mid + d1 <= b + d1 + d2 = b + delta
11441244 // upper = false: e >= mid + d1 >= b + d1 + d2 = b + delta
@@ -1152,15 +1252,13 @@ module RangeStage<
11521252 or
11531253 exists ( Sem:: Expr mid , D:: Delta factor , D:: Delta d |
11541254 boundFlowStepMul ( e , mid , factor ) and
1155- not e instanceof Sem:: ConstantIntegerExpr and
11561255 bounded ( mid , b , d , upper , fromBackEdge , origdelta , reason ) and
11571256 b instanceof SemZeroBound and
11581257 delta = D:: fromFloat ( D:: toFloat ( d ) * D:: toFloat ( factor ) )
11591258 )
11601259 or
11611260 exists ( Sem:: Expr mid , D:: Delta factor , D:: Delta d |
11621261 boundFlowStepDiv ( e , mid , factor ) and
1163- not e instanceof Sem:: ConstantIntegerExpr and
11641262 bounded ( mid , b , d , upper , fromBackEdge , origdelta , reason ) and
11651263 b instanceof SemZeroBound and
11661264 D:: toFloat ( d ) >= 0 and
0 commit comments