@@ -923,6 +923,55 @@ private predicate simple_comparison_eq(
923923 value .( BooleanValue ) .getValue ( ) = false
924924}
925925
926+ /**
927+ * Holds if `op` is an operand that is eventually used in a unary comparison
928+ * with a constant.
929+ */
930+ private predicate isRelevantUnaryComparisonOperand ( Operand op ) {
931+ // Base case: `op` is an operand of a `CompareEQInstruction` or `CompareNEInstruction`,
932+ // and the other operand is a constant.
933+ exists ( CompareInstruction eq , Instruction instr |
934+ eq .hasOperands ( op , instr .getAUse ( ) ) and
935+ exists ( int_value ( instr ) )
936+ |
937+ eq instanceof CompareEQInstruction
938+ or
939+ eq instanceof CompareNEInstruction
940+ )
941+ or
942+ // C doesn't have int-to-bool conversions, so `if(x)` will just generate:
943+ // r2_1(glval<int>) = VariableAddress[x]
944+ // r2_2(int) = Load[x] : &:r2_1, m1_6
945+ // v2_3(void) = ConditionalBranch : r2_2
946+ exists ( ConditionalBranchInstruction branch | branch .getConditionOperand ( ) = op )
947+ or
948+ // If `!x` is a relevant unary comparison then so is `x`.
949+ exists ( LogicalNotInstruction logicalNot |
950+ isRelevantUnaryComparisonOperand ( unique( | | logicalNot .getAUse ( ) ) ) and
951+ logicalNot .getUnaryOperand ( ) = op
952+ )
953+ or
954+ // If `y` is a relevant unary comparison and `y = x` then so is `x`.
955+ not op .isDefinitionInexact ( ) and
956+ exists ( CopyInstruction copy |
957+ isRelevantUnaryComparisonOperand ( unique( | | copy .getAUse ( ) ) ) and
958+ op = copy .getSourceValueOperand ( )
959+ )
960+ or
961+ // If phi(x1, x2) is a relevant unary comparison then so is `x1` and `x2`.
962+ not op .isDefinitionInexact ( ) and
963+ exists ( PhiInstruction phi |
964+ isRelevantUnaryComparisonOperand ( unique( | | phi .getAUse ( ) ) ) and
965+ op = phi .getAnInputOperand ( )
966+ )
967+ or
968+ // If `__builtin_expect(x)` is a relevant unary comparison then so is `x`.
969+ exists ( BuiltinExpectCallInstruction call |
970+ isRelevantUnaryComparisonOperand ( unique( | | call .getAUse ( ) ) ) and
971+ op = call .getConditionOperand ( )
972+ )
973+ }
974+
926975/** Rearrange various simple comparisons into `op == k` form. */
927976private predicate unary_simple_comparison_eq (
928977 ValueNumber test , Operand op , int k , boolean inNonZeroCase , AbstractValue value
@@ -936,41 +985,8 @@ private predicate unary_simple_comparison_eq(
936985 inNonZeroCase = false
937986 )
938987 or
939- // Any instruction with an integral type could potentially be part of a
940- // check for nullness when used in a guard. So we include all integral
941- // typed instructions here. However, since some of these instructions are
942- // already included as guards in other cases, we exclude those here.
943- // These are instructions that compute a binary equality or inequality
944- // relation. For example, the following:
945- // ```cpp
946- // if(a == b + 42) { ... }
947- // ```
948- // generates the following IR:
949- // ```
950- // r1(glval<int>) = VariableAddress[a] :
951- // r2(int) = Load[a] : &:r1, m1
952- // r3(glval<int>) = VariableAddress[b] :
953- // r4(int) = Load[b] : &:r3, m2
954- // r5(int) = Constant[42] :
955- // r6(int) = Add : r4, r5
956- // r7(bool) = CompareEQ : r2, r6
957- // v1(void) = ConditionalBranch : r7
958- // ```
959- // and since `r7` is an integral typed instruction this predicate could
960- // include a case for when `r7` evaluates to true (in which case we would
961- // infer that `r6` was non-zero, and a case for when `r7` evaluates to false
962- // (in which case we would infer that `r6` was zero).
963- // However, since `a == b + 42` is already supported when reasoning about
964- // binary equalities we exclude those cases here.
965- not test .isGLValue ( ) and
966- not simple_comparison_eq ( test , _, _, _, _) and
967- not simple_comparison_lt ( test , _, _, _) and
968- op = test .getExpressionOperand ( ) and
969- (
970- test .getResultIRType ( ) instanceof IRAddressType or
971- test .getResultIRType ( ) instanceof IRIntegerType or
972- test .getResultIRType ( ) instanceof IRBooleanType
973- ) and
988+ isRelevantUnaryComparisonOperand ( op ) and
989+ op .getDef ( ) = test .getAnInstruction ( ) and
974990 (
975991 k = 1 and
976992 value .( BooleanValue ) .getValue ( ) = true and
@@ -987,10 +1003,12 @@ private class BuiltinExpectCallInstruction extends CallInstruction {
9871003 BuiltinExpectCallInstruction ( ) { this .getStaticCallTarget ( ) .hasName ( "__builtin_expect" ) }
9881004
9891005 /** Gets the condition of this call. */
990- Instruction getCondition ( ) {
1006+ Instruction getCondition ( ) { result = this .getConditionOperand ( ) .getDef ( ) }
1007+
1008+ Operand getConditionOperand ( ) {
9911009 // The first parameter of `__builtin_expect` has type `long`. So we skip
9921010 // the conversion when inferring guards.
993- result = this .getArgument ( 0 ) .( ConvertInstruction ) .getUnary ( )
1011+ result = this .getArgument ( 0 ) .( ConvertInstruction ) .getUnaryOperand ( )
9941012 }
9951013}
9961014
0 commit comments