@@ -375,6 +375,33 @@ cached
375375class IRGuardCondition extends Instruction {
376376 Instruction branch ;
377377
378+ /*
379+ * An `IRGuardCondition` supports reasoning about four different kinds of
380+ * relations:
381+ * 1. A unary equality relation of the form `e == k`
382+ * 2. A binary equality relation of the form `e1 == e2 + k`
383+ * 3. A unary inequality relation of the form `e < k`
384+ * 4. A binary inequality relation of the form `e1 < e2 + k`
385+ *
386+ * where `k` is a constant.
387+ *
388+ * Furthermore, the unary relations (i.e., case 1 and case 3) are also
389+ * inferred from `switch` statement guards: equality relations are inferred
390+ * from the unique `case` statement, if any, and inequality relations are
391+ * inferred from the [case range](https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html)
392+ * gcc extension.
393+ *
394+ * The implementation of all four follows the same structure: Each relation
395+ * has a cached user-facing predicate that. For example,
396+ * `GuardCondition::comparesEq` calls `compares_eq`. This predicate has
397+ * several cases that recursively decompose the relation to bring it to a
398+ * canonical form (i.e., a relation of the form `e1 == e2 + k`). The base
399+ * case for this relation (i.e., `simple_comparison_eq`) handles
400+ * `CompareEQInstruction`s and `CompareNEInstruction`, and recursive
401+ * predicates (e.g., `complex_eq`) rewrites larger expressions such as
402+ * `e1 + k1 == e2 + k2` into canonical the form `e1 == e2 + (k2 - k1)`.
403+ */
404+
378405 cached
379406 IRGuardCondition ( ) { branch = getBranchForCondition ( this ) }
380407
@@ -735,6 +762,8 @@ private predicate compares_eq(
735762 exists ( AbstractValue dual | value = dual .getDualValue ( ) |
736763 compares_eq ( test .( LogicalNotInstruction ) .getUnary ( ) , left , right , k , areEqual , dual )
737764 )
765+ or
766+ compares_eq ( test .( BuiltinExpectCallInstruction ) .getCondition ( ) , left , right , k , areEqual , value )
738767}
739768
740769/**
@@ -776,7 +805,9 @@ private predicate unary_compares_eq(
776805 Instruction test , Operand op , int k , boolean areEqual , boolean inNonZeroCase , AbstractValue value
777806) {
778807 /* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
779- exists ( AbstractValue v | unary_simple_comparison_eq ( test , op , k , inNonZeroCase , v ) |
808+ exists ( AbstractValue v |
809+ unary_simple_comparison_eq ( test , k , inNonZeroCase , v ) and op .getDef ( ) = test
810+ |
780811 areEqual = true and value = v
781812 or
782813 areEqual = false and value = v .getDualValue ( )
@@ -802,6 +833,9 @@ private predicate unary_compares_eq(
802833 int_value ( const ) = k1 and
803834 k = k1 + k2
804835 )
836+ or
837+ unary_compares_eq ( test .( BuiltinExpectCallInstruction ) .getCondition ( ) , op , k , areEqual ,
838+ inNonZeroCase , value )
805839}
806840
807841/** Rearrange various simple comparisons into `left == right + k` form. */
@@ -821,45 +855,55 @@ private predicate simple_comparison_eq(
821855 value .( BooleanValue ) .getValue ( ) = false
822856}
823857
824- /**
825- * Holds if `test` is an instruction that is part of test that eventually is
826- * used in a conditional branch.
827- */
828- private predicate relevantUnaryComparison ( Instruction test ) {
829- not test instanceof CompareInstruction and
830- exists ( IRType type , ConditionalBranchInstruction branch |
831- type instanceof IRAddressType or type instanceof IRIntegerType
832- |
833- type = test .getResultIRType ( ) and
834- branch .getCondition ( ) = test
835- )
836- or
837- exists ( LogicalNotInstruction logicalNot |
838- relevantUnaryComparison ( logicalNot ) and
839- test = logicalNot .getUnary ( )
840- )
841- }
842-
843858/**
844859 * Rearrange various simple comparisons into `op == k` form.
845860 */
846861private predicate unary_simple_comparison_eq (
847- Instruction test , Operand op , int k , boolean inNonZeroCase , AbstractValue value
862+ Instruction test , int k , boolean inNonZeroCase , AbstractValue value
848863) {
849864 exists ( SwitchInstruction switch , CaseEdge case |
850865 test = switch .getExpression ( ) and
851- op .getDef ( ) = test and
852866 case = value .( MatchValue ) .getCase ( ) and
853867 exists ( switch .getSuccessor ( case ) ) and
854868 case .getValue ( ) .toInt ( ) = k and
855869 inNonZeroCase = false
856870 )
857871 or
858- // There's no implicit CompareInstruction in files compiled as C since C
859- // doesn't have implicit boolean conversions. So instead we check whether
860- // there's a branch on a value of pointer or integer type.
861- relevantUnaryComparison ( test ) and
862- op .getDef ( ) = test and
872+ // Any instruction with an integral type could potentially be part of a
873+ // check for nullness when used in a guard. So we include all integral
874+ // typed instructions here. However, since some of these instructions are
875+ // already included as guards in other cases, we exclude those here.
876+ // These are instructions that compute a binary equality or inequality
877+ // relation. For example, the following:
878+ // ```cpp
879+ // if(a == b + 42) { ... }
880+ // ```
881+ // generates the following IR:
882+ // ```
883+ // r1(glval<int>) = VariableAddress[a] :
884+ // r2(int) = Load[a] : &:r1, m1
885+ // r3(glval<int>) = VariableAddress[b] :
886+ // r4(int) = Load[b] : &:r3, m2
887+ // r5(int) = Constant[42] :
888+ // r6(int) = Add : r4, r5
889+ // r7(bool) = CompareEQ : r2, r6
890+ // v1(void) = ConditionalBranch : r7
891+ // ```
892+ // and since `r7` is an integral typed instruction this predicate could
893+ // include a case for when `r7` evaluates to true (in which case we would
894+ // infer that `r6` was non-zero, and a case for when `r7` evaluates to false
895+ // (in which case we would infer that `r6` was zero).
896+ // However, since `a == b + 42` is already supported when reasoning about
897+ // binary equalities we exclude those cases here.
898+ not test .isGLValue ( ) and
899+ not simple_comparison_eq ( test , _, _, _, _) and
900+ not simple_comparison_lt ( test , _, _, _) and
901+ not test = any ( SwitchInstruction switch ) .getExpression ( ) and
902+ (
903+ test .getResultIRType ( ) instanceof IRAddressType or
904+ test .getResultIRType ( ) instanceof IRIntegerType or
905+ test .getResultIRType ( ) instanceof IRBooleanType
906+ ) and
863907 (
864908 k = 1 and
865909 value .( BooleanValue ) .getValue ( ) = true and
@@ -871,12 +915,68 @@ private predicate unary_simple_comparison_eq(
871915 )
872916}
873917
918+ /** A call to the builtin operation `__builtin_expect`. */
919+ private class BuiltinExpectCallInstruction extends CallInstruction {
920+ BuiltinExpectCallInstruction ( ) { this .getStaticCallTarget ( ) .hasName ( "__builtin_expect" ) }
921+
922+ /** Gets the condition of this call. */
923+ Instruction getCondition ( ) {
924+ // The first parameter of `__builtin_expect` has type `long`. So we skip
925+ // the conversion when inferring guards.
926+ result = this .getArgument ( 0 ) .( ConvertInstruction ) .getUnary ( )
927+ }
928+ }
929+
930+ /**
931+ * Holds if `left == right + k` is `areEqual` if `cmp` evaluates to `value`,
932+ * and `cmp` is an instruction that compares the value of
933+ * `__builtin_expect(left == right + k, _)` to `0`.
934+ */
935+ private predicate builtin_expect_eq (
936+ CompareInstruction cmp , Operand left , Operand right , int k , boolean areEqual , AbstractValue value
937+ ) {
938+ exists ( BuiltinExpectCallInstruction call , Instruction const , AbstractValue innerValue |
939+ int_value ( const ) = 0 and
940+ cmp .hasOperands ( call .getAUse ( ) , const .getAUse ( ) ) and
941+ compares_eq ( call .getCondition ( ) , left , right , k , areEqual , innerValue )
942+ |
943+ cmp instanceof CompareNEInstruction and
944+ value = innerValue
945+ or
946+ cmp instanceof CompareEQInstruction and
947+ value .getDualValue ( ) = innerValue
948+ )
949+ }
950+
874951private predicate complex_eq (
875952 CompareInstruction cmp , Operand left , Operand right , int k , boolean areEqual , AbstractValue value
876953) {
877954 sub_eq ( cmp , left , right , k , areEqual , value )
878955 or
879956 add_eq ( cmp , left , right , k , areEqual , value )
957+ or
958+ builtin_expect_eq ( cmp , left , right , k , areEqual , value )
959+ }
960+
961+ /**
962+ * Holds if `op == k` is `areEqual` if `cmp` evaluates to `value`, and `cmp` is
963+ * an instruction that compares the value of `__builtin_expect(op == k, _)` to `0`.
964+ */
965+ private predicate unary_builtin_expect_eq (
966+ CompareInstruction cmp , Operand op , int k , boolean areEqual , boolean inNonZeroCase ,
967+ AbstractValue value
968+ ) {
969+ exists ( BuiltinExpectCallInstruction call , Instruction const , AbstractValue innerValue |
970+ int_value ( const ) = 0 and
971+ cmp .hasOperands ( call .getAUse ( ) , const .getAUse ( ) ) and
972+ unary_compares_eq ( call .getCondition ( ) , op , k , areEqual , inNonZeroCase , innerValue )
973+ |
974+ cmp instanceof CompareNEInstruction and
975+ value = innerValue
976+ or
977+ cmp instanceof CompareEQInstruction and
978+ value .getDualValue ( ) = innerValue
979+ )
880980}
881981
882982private predicate unary_complex_eq (
@@ -885,6 +985,8 @@ private predicate unary_complex_eq(
885985 unary_sub_eq ( test , op , k , areEqual , inNonZeroCase , value )
886986 or
887987 unary_add_eq ( test , op , k , areEqual , inNonZeroCase , value )
988+ or
989+ unary_builtin_expect_eq ( test , op , k , areEqual , inNonZeroCase , value )
888990}
889991
890992/*
@@ -913,7 +1015,8 @@ private predicate compares_lt(
9131015
9141016/** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */
9151017private predicate compares_lt ( Instruction test , Operand op , int k , boolean isLt , AbstractValue value ) {
916- simple_comparison_lt ( test , op , k , isLt , value )
1018+ unary_simple_comparison_lt ( test , k , isLt , value ) and
1019+ op .getDef ( ) = test
9171020 or
9181021 complex_lt ( test , op , k , isLt , value )
9191022 or
@@ -960,12 +1063,11 @@ private predicate simple_comparison_lt(CompareInstruction cmp, Operand left, Ope
9601063}
9611064
9621065/** Rearrange various simple comparisons into `op < k` form. */
963- private predicate simple_comparison_lt (
964- Instruction test , Operand op , int k , boolean isLt , AbstractValue value
1066+ private predicate unary_simple_comparison_lt (
1067+ Instruction test , int k , boolean isLt , AbstractValue value
9651068) {
9661069 exists ( SwitchInstruction switch , CaseEdge case |
9671070 test = switch .getExpression ( ) and
968- op .getDef ( ) = test and
9691071 case = value .( MatchValue ) .getCase ( ) and
9701072 exists ( switch .getSuccessor ( case ) ) and
9711073 case .getMaxValue ( ) > case .getMinValue ( )
0 commit comments