@@ -289,6 +289,10 @@ signature module LangSig<Semantic Sem, DeltaSig D> {
289
289
predicate ignoreExprBound ( Sem:: Expr e ) ;
290
290
291
291
default predicate javaCompatibility ( ) { none ( ) }
292
+
293
+ default predicate includeConstantBounds ( ) { any ( ) }
294
+
295
+ default predicate includeRelativeBounds ( ) { any ( ) }
292
296
}
293
297
294
298
signature module BoundSig< LocationSig Location, Semantic Sem, DeltaSig D> {
@@ -678,60 +682,65 @@ module RangeStage<
678
682
* - `upper = false` : `e2 >= e1 + delta`
679
683
*/
680
684
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 )
701
705
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 )
704
708
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 )
708
738
)
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 )
731
739
}
732
740
733
741
/** Holds if `e2 = e1 * factor` and `factor > 0`. */
734
742
private predicate boundFlowStepMul ( Sem:: Expr e2 , Sem:: Expr e1 , D:: Delta factor ) {
743
+ not e2 instanceof Sem:: ConstantIntegerExpr and
735
744
exists ( Sem:: ConstantIntegerExpr c , int k | k = c .getIntValue ( ) and k > 0 |
736
745
e2 .( Sem:: MulExpr ) .hasOperands ( e1 , c ) and factor = D:: fromInt ( k )
737
746
or
@@ -751,6 +760,7 @@ module RangeStage<
751
760
* therefore only valid for non-negative numbers.
752
761
*/
753
762
private predicate boundFlowStepDiv ( Sem:: Expr e2 , Sem:: Expr e1 , D:: Delta factor ) {
763
+ not e2 instanceof Sem:: ConstantIntegerExpr and
754
764
Sem:: getExprType ( e2 ) instanceof Sem:: IntegerType and
755
765
exists ( Sem:: ConstantIntegerExpr c , D:: Delta k |
756
766
k = D:: fromInt ( c .getIntValue ( ) ) and D:: toFloat ( k ) > 0
@@ -983,16 +993,31 @@ module RangeStage<
983
993
)
984
994
}
985
995
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
+
986
1003
/**
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 .
989
1006
*/
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
+ )
996
1021
}
997
1022
998
1023
/**
@@ -1107,6 +1132,84 @@ module RangeStage<
1107
1132
bindingset [ x, y]
1108
1133
private float truncatingDiv ( float x , float y ) { result = ( x - ( x % y ) ) / y }
1109
1134
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
+
1110
1213
/**
1111
1214
* Holds if `b + delta` is a valid bound for `e`.
1112
1215
* - `upper = true` : `e <= b + delta`
@@ -1117,15 +1220,14 @@ module RangeStage<
1117
1220
D:: Delta origdelta , SemReason reason
1118
1221
) {
1119
1222
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
1126
1226
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
1129
1231
fromBackEdge = false and
1130
1232
origdelta = delta and
1131
1233
reason = TSemNoReason ( )
@@ -1137,8 +1239,6 @@ module RangeStage<
1137
1239
or
1138
1240
exists ( Sem:: Expr mid , D:: Delta d1 , D:: Delta d2 |
1139
1241
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
1142
1242
bounded ( mid , b , d2 , upper , fromBackEdge , origdelta , reason ) and
1143
1243
// upper = true: e <= mid + d1 <= b + d1 + d2 = b + delta
1144
1244
// upper = false: e >= mid + d1 >= b + d1 + d2 = b + delta
@@ -1152,15 +1252,13 @@ module RangeStage<
1152
1252
or
1153
1253
exists ( Sem:: Expr mid , D:: Delta factor , D:: Delta d |
1154
1254
boundFlowStepMul ( e , mid , factor ) and
1155
- not e instanceof Sem:: ConstantIntegerExpr and
1156
1255
bounded ( mid , b , d , upper , fromBackEdge , origdelta , reason ) and
1157
1256
b instanceof SemZeroBound and
1158
1257
delta = D:: fromFloat ( D:: toFloat ( d ) * D:: toFloat ( factor ) )
1159
1258
)
1160
1259
or
1161
1260
exists ( Sem:: Expr mid , D:: Delta factor , D:: Delta d |
1162
1261
boundFlowStepDiv ( e , mid , factor ) and
1163
- not e instanceof Sem:: ConstantIntegerExpr and
1164
1262
bounded ( mid , b , d , upper , fromBackEdge , origdelta , reason ) and
1165
1263
b instanceof SemZeroBound and
1166
1264
D:: toFloat ( d ) >= 0 and
0 commit comments