@@ -496,11 +496,20 @@ private predicate isRecursiveDef(RangeSsaDefinition def, StackVariable v) {
496496}
497497
498498private predicate isExplosiveVar ( StackVariable v ) {
499+ // exists(RangeSsaDefinition def, StackVariable v |
500+ // nrOfBoundsDef(def, v)
501+ // )
502+ // or
499503 none ( ) and
500504 64 < count ( RangeSsaDefinition def | def .getAVariable ( ) = v and def .isPhiNode ( _) )
501505}
502506
503- // private predicate isWidenedVariable
507+ /**
508+ * Holds if `e` is an expression for which a very large number of bounds might
509+ * be generated during the range analysis.
510+ */
511+ private predicate isExplosiveExpr ( Expr e ) { nrOfBounds ( e ) > 1000000 }
512+
504513/**
505514 * Holds if the bounds of `e` depend on a recursive definition, meaning that
506515 * `e` is likely to have many candidate bounds during the main recursion.
@@ -512,7 +521,7 @@ private predicate isRecursiveExpr(Expr e) {
512521}
513522
514523/** Provides an estimated measure on the number of bounds for an expression. */
515- private int nrOfBounds ( Expr e ) {
524+ private float nrOfBounds ( Expr e ) {
516525 isRecursiveExpr ( e ) and result = 13 // FIXME: Let's not hardcode this
517526 or
518527 not isRecursiveExpr ( e ) and
@@ -550,8 +559,6 @@ private int nrOfBounds(Expr e) {
550559 exists ( AssignMulByConstantExpr mulExpr |
551560 e = mulExpr and
552561 result = nrOfBounds ( mulExpr .getLValue ( ) )
553- // xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and
554- // result = xLow * mulExpr.getConstant()
555562 )
556563 or
557564 // Handles the `--` and `++` operators
@@ -573,7 +580,7 @@ private int nrOfBounds(Expr e) {
573580 or
574581 exists ( RangeSsaDefinition def , StackVariable v |
575582 e = def .getAUse ( v ) and
576- result = defNrOfBounds ( def , v ) and
583+ result = nrOfBoundsDef ( def , v ) and
577584 not exists ( getValue ( e ) .toFloat ( ) )
578585 )
579586 or
@@ -593,6 +600,12 @@ private int nrOfBounds(Expr e) {
593600 e instanceof AssignSubExpr or
594601 e instanceof UnsignedAssignMulExpr
595602 )
603+ or
604+ exists ( RShiftExpr rsExpr |
605+ e = rsExpr and
606+ exists ( getValue ( rsExpr .getRightOperand ( ) .getFullyConverted ( ) ) .toInt ( ) ) and
607+ result = nrOfBounds ( rsExpr .getLeftOperand ( ) )
608+ )
596609 )
597610 or
598611 not analyzableExpr ( e ) and exists ( exprMinVal ( e ) ) and result = 1
@@ -608,87 +621,113 @@ int teststst(RangeSsaDefinition def, StackVariable v, VariableAccess access) {
608621 )
609622}
610623
624+ private predicate hasLinearBoundFromGuard2 (
625+ ComparisonOperation guard , VariableAccess v , float p , float q , RelationStrictness strictness ,
626+ boolean branch // Which control-flow branch is this bound valid on?
627+ ) {
628+ exists ( Expr lhs , Expr rhs , RelationDirection dir , RelationStrictness st |
629+ linearAccess ( lhs , v , p , q ) and
630+ relOpWithSwapAndNegate ( guard , lhs , rhs , dir , st , branch )
631+ |
632+ strictness = st
633+ or
634+ strictness = Nonstrict ( ) and
635+ exprTypeBounds ( rhs , _, _)
636+ )
637+ or
638+ exists ( Expr lhs , Expr rhs |
639+ linearAccess ( lhs , v , p , q ) and
640+ eqOpWithSwapAndNegate ( guard , lhs , rhs , true , branch ) and
641+ strictness = Nonstrict ( )
642+ )
643+ }
644+
645+ /**
646+ * Holds if `lowerBoundFromGuard(guard, v, _, branch)` holds, but without
647+ * relying on range analysis (which would cause non-monotonic recursion
648+ * elsewhere).
649+ */
650+ predicate hasLowerBoundFromGuard ( Expr guard , VariableAccess v , boolean branch ) {
651+ hasLinearBoundFromGuard2 ( guard , v , _, _, _, branch )
652+ or
653+ // lowerBoundFromGuard(guard, v, _, branch)
654+ exists ( float p , float q , Expr e |
655+ linearAccess ( e , v , p , q ) and
656+ eqZeroWithNegate ( guard , e , true , branch ) // and
657+ // boundValue = (0.0 - q) / p and
658+ // isLowerBound = [false, true] and
659+ // strictness = Nonstrict()
660+ )
661+ }
662+
663+ predicate missing ( Expr guard , VariableAccess access , boolean branch ) {
664+ lowerBoundFromGuard ( guard , access , _, branch ) and
665+ not hasLowerBoundFromGuard ( guard , access , branch )
666+ }
667+
668+ predicate tooMuch ( Expr guard , VariableAccess access , boolean branch ) {
669+ not lowerBoundFromGuard ( guard , access , _, branch ) and
670+ hasLowerBoundFromGuard ( guard , access , branch )
671+ }
672+
611673predicate isGuardPhiWithBound (
612674 RangeSsaDefinition def , StackVariable v , VariableAccess access , Expr guard , boolean branch
613675) {
614676 def .isGuardPhi ( v , access , guard , branch ) and
615- lowerBoundFromGuard ( guard , access , _ , branch )
677+ hasLowerBoundFromGuard ( guard , access , branch )
616678}
617679
618- language [ monotonicAggregates]
619- int defNrOfBoundsPhiGuard ( RangeSsaDefinition def , StackVariable v ) {
620- v = Debug:: getRelevantLocatable ( ) and
621- (
622- // NOTE: A phi node can be both a guard phi node and a normal phi node. In
623- // that case we only treat it as a normal phi node.
624- // TODO: Should we change this in `getPhiLowerBounds`?
625- // not exists(VariableAccess access, Expr guard, boolean branch |
626- // def.isGuardPhi(v, access, guard, branch) and
627- // lowerBoundFromGuard(guard, access, _, branch)
628- // ) and
629- not isGuardPhiWithBound ( def , v , _, _, _) and
630- def .isPhiNode ( v ) and
631- result = 0
632- or
633- // NOTE: The differenct `access`es are the same variable and the lower
634- // bounds are the same. The guard may filter some away. Hence adding these
635- // guards make no sense (the impl will take the union but after dedup taking
636- // `max` is a better representation).
637- result =
638- max ( VariableAccess access |
639- // def.isGuardPhi(v, access, guard, branch) and
640- // lowerBoundFromGuard(guard, access, _, branch)
641- isGuardPhiWithBound ( def , v , access , _, _)
642- |
643- nrOfBounds ( access )
644- )
645- )
680+ predicate debugThing ( RangeSsaDefinition def , StackVariable v , VariableAccess access ) {
681+ def .isGuardPhi ( v , access , _, _) and
682+ not isGuardPhiWithBound ( def , v , access , _, _)
646683}
647684
648685language [ monotonicAggregates]
649- int defNrOfBoundsPhiNormal ( RangeSsaDefinition def , StackVariable v ) {
650- v = Debug:: getRelevantLocatable ( ) and
651- (
652- def .isGuardPhi ( v , _, _, _) and
653- not exists ( def .getAPhiInput ( v ) ) and
654- result = 0
655- or
656- result =
657- strictsum ( RangeSsaDefinition inputDef |
658- inputDef = def .getAPhiInput ( v )
659- |
660- defNrOfBounds ( inputDef , v )
661- )
662- )
686+ float defNrOfBoundsPhiGuard ( RangeSsaDefinition def , StackVariable v ) {
687+ def .isPhiNode ( v ) and
688+ not isGuardPhiWithBound ( def , v , _, _, _) and
689+ result = 0
690+ or
691+ // NOTE: The differenct `access`es are the same variable and the lower
692+ // bounds are the same. The guard may filter some away. Hence adding these
693+ // guards make no sense (the impl will take the union but after dedup taking
694+ // `max` is a better representation).
695+ result =
696+ max ( VariableAccess access | isGuardPhiWithBound ( def , v , access , _, _) | nrOfBounds ( access ) )
663697}
664698
665- int nrOfBoundsNEPhi ( RangeSsaDefinition def , StackVariable v ) {
666- v = Debug:: getRelevantLocatable ( ) and
667- (
668- exists ( VariableAccess access | isNEPhi ( v , def , access , _) and result = nrOfBounds ( access ) )
669- or
670- not isNEPhi ( v , def , _, _) and result = 0
671- )
699+ language [ monotonicAggregates]
700+ float defNrOfBoundsPhiNormal ( RangeSsaDefinition def , StackVariable v ) {
701+ def .isPhiNode ( v ) and
702+ not exists ( def .getAPhiInput ( v ) ) and
703+ result = 0
704+ or
705+ result =
706+ strictsum ( RangeSsaDefinition inputDef |
707+ inputDef = def .getAPhiInput ( v )
708+ |
709+ nrOfBoundsDef ( inputDef , v )
710+ )
672711}
673712
674- predicate gimmeBug ( RangeSsaDefinition def , StackVariable v ) {
675- nrOfBoundsNEPhi ( def , v ) > 0 and
676- exists ( defNrOfBoundsPhiNormal ( def , v ) ) and
677- exists ( defNrOfBoundsPhiGuard ( def , v ) )
713+ float nrOfBoundsNEPhi ( RangeSsaDefinition def , StackVariable v ) {
714+ exists ( VariableAccess access | isNEPhi ( v , def , access , _) and result = nrOfBounds ( access ) )
715+ or
716+ def .isPhiNode ( v ) and
717+ not isNEPhi ( v , def , _, _) and
718+ result = 0
678719}
679720
680- int nrOfBoundsPhi ( RangeSsaDefinition def , StackVariable v ) {
681- exists ( int nePhi , int unsupportedGuardPhi |
721+ float nrOfBoundsPhi ( RangeSsaDefinition def , StackVariable v ) {
722+ // NOTE: A phi node can be both a guard phi node and a normal phi node. In
723+ // that case we only treat it as a normal phi node.
724+ // TODO: Should we change this in `getPhiLowerBounds`?
725+ exists ( int unsupportedGuardPhi |
682726 result =
683727 // Guard phi nodes
684728 defNrOfBoundsPhiGuard ( def , v ) +
685729 // Normal phi nodes
686- defNrOfBoundsPhiNormal ( def , v ) + nePhi + unsupportedGuardPhi and
687- // (exists(VariableAccess access | isNEPhi(v, def, access, _) and nePhi = nrOfBounds(access))
688- // or
689- // not isNEPhi(v, def, _, _) and nePhi = 0.0)
690- nePhi = nrOfBoundsNEPhi ( def , v ) and
691- // unsupportedGuardPhi = 0 and
730+ defNrOfBoundsPhiNormal ( def , v ) + nrOfBoundsNEPhi ( def , v ) + unsupportedGuardPhi and
692731 (
693732 exists ( VariableAccess access |
694733 isUnsupportedGuardPhi ( v , def , access ) and
@@ -702,7 +741,7 @@ int nrOfBoundsPhi(RangeSsaDefinition def, StackVariable v) {
702741}
703742
704743language [ monotonicAggregates]
705- int defNrOfBounds ( RangeSsaDefinition def , StackVariable v ) {
744+ float nrOfBoundsDef ( RangeSsaDefinition def , StackVariable v ) {
706745 v = Debug:: getRelevantLocatable ( ) and
707746 (
708747 // Definitions with a defining value
@@ -1777,27 +1816,23 @@ private predicate exprTypeBounds(Expr expr, float boundValue, boolean isLowerBou
17771816private predicate isNEPhi (
17781817 Variable v , RangeSsaDefinition phi , VariableAccess access , float neConstant
17791818) {
1780- v = Debug:: getRelevantLocatable ( ) and
1781- (
1782- exists (
1783- ComparisonOperation cmp , boolean branch , Expr linearExpr , Expr rExpr , float p , float q ,
1784- float r
1785- |
1786- phi .isGuardPhi ( v , access , cmp , branch ) and
1787- eqOpWithSwapAndNegate ( cmp , linearExpr , rExpr , false , branch ) and
1788- v .getUnspecifiedType ( ) instanceof IntegralOrEnumType and // Float `!=` is too imprecise
1789- r = getValue ( rExpr ) .toFloat ( ) and
1790- linearAccess ( linearExpr , access , p , q ) and
1791- neConstant = ( r - q ) / p
1792- )
1793- or
1794- exists ( Expr op , boolean branch , Expr linearExpr , float p , float q |
1795- phi .isGuardPhi ( v , access , op , branch ) and
1796- eqZeroWithNegate ( op , linearExpr , false , branch ) and
1797- v .getUnspecifiedType ( ) instanceof IntegralOrEnumType and // Float `!` is too imprecise
1798- linearAccess ( linearExpr , access , p , q ) and
1799- neConstant = ( 0.0 - q ) / p
1800- )
1819+ exists (
1820+ ComparisonOperation cmp , boolean branch , Expr linearExpr , Expr rExpr , float p , float q , float r
1821+ |
1822+ phi .isGuardPhi ( v , access , cmp , branch ) and
1823+ eqOpWithSwapAndNegate ( cmp , linearExpr , rExpr , false , branch ) and
1824+ v .getUnspecifiedType ( ) instanceof IntegralOrEnumType and // Float `!=` is too imprecise
1825+ r = getValue ( rExpr ) .toFloat ( ) and
1826+ linearAccess ( linearExpr , access , p , q ) and
1827+ neConstant = ( r - q ) / p
1828+ )
1829+ or
1830+ exists ( Expr op , boolean branch , Expr linearExpr , float p , float q |
1831+ phi .isGuardPhi ( v , access , op , branch ) and
1832+ eqZeroWithNegate ( op , linearExpr , false , branch ) and
1833+ v .getUnspecifiedType ( ) instanceof IntegralOrEnumType and // Float `!` is too imprecise
1834+ linearAccess ( linearExpr , access , p , q ) and
1835+ neConstant = ( 0.0 - q ) / p
18011836 )
18021837}
18031838
@@ -2117,7 +2152,7 @@ private module Debug {
21172152 Locatable getRelevantLocatable ( ) {
21182153 exists ( string filepath , int startline |
21192154 result .getLocation ( ) .hasLocationInfo ( filepath , startline , _, _, _) and
2120- // filepath.matches("%/Cmprs_RiceLayersMem.C") and
2155+ // filepath.matches("%/Cmprs_RiceLayersMem.C") // and
21212156 // startline = [1452 .. 1480]
21222157 filepath .matches ( "%/test.c" ) // and
21232158 // startline = [845 .. 867]
@@ -2174,16 +2209,6 @@ private module Debug {
21742209 )
21752210 }
21762211
2177- int debugDefNrOfBounds ( RangeSsaDefinition def , StackVariable v ) {
2178- v = getRelevantLocatable ( ) and
2179- defNrOfBounds ( def , v ) = result
2180- }
2181-
2182- int debugDefNrOfBoundsPhiNormal ( RangeSsaDefinition def , StackVariable v ) {
2183- v = getRelevantLocatable ( ) and
2184- defNrOfBoundsPhiNormal ( def , v ) = result
2185- }
2186-
21872212 int nonFunctionalNrOfBounds ( Expr e ) {
21882213 // e = getRelevantLocatable() and
21892214 strictcount ( nrOfBounds ( e ) ) > 1 and
0 commit comments