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