@@ -924,6 +924,49 @@ private predicate simple_comparison_eq(
924924 value .( BooleanValue ) .getValue ( ) = false
925925}
926926
927+ private predicate isRelevantUnaryComparisonOperand ( Operand op ) {
928+ exists ( CompareInstruction eq , Instruction instr |
929+ eq .hasOperands ( op , instr .getAUse ( ) ) and
930+ exists ( int_value ( instr ) )
931+ |
932+ eq instanceof CompareEQInstruction
933+ or
934+ eq instanceof CompareNEInstruction
935+ )
936+ or
937+ // C doesn't have int-to-bool conversions, so `if(x)` will just generate:
938+ // r2_1(glval<int>) = VariableAddress[x]
939+ // r2_2(int) = Load[x] : &:r2_1, m1_6
940+ // v2_3(void) = ConditionalBranch : r2_2
941+ exists ( ConditionalBranchInstruction branch | branch .getConditionOperand ( ) = op )
942+ or
943+ // If `!x` is a relevant unary comparison then so is `x`.
944+ exists ( LogicalNotInstruction logicalNot |
945+ isRelevantUnaryComparisonOperand ( unique( | | logicalNot .getAUse ( ) ) ) and
946+ logicalNot .getUnaryOperand ( ) = op
947+ )
948+ or
949+ // If `y` is a relevant unary comparison and `y = x` then so is `x`.
950+ not op .isDefinitionInexact ( ) and
951+ exists ( CopyInstruction copy |
952+ isRelevantUnaryComparisonOperand ( unique( | | copy .getAUse ( ) ) ) and
953+ op = copy .getSourceValueOperand ( )
954+ )
955+ or
956+ // If phi(x1, x2) is a relevant unary comparison then so is `x1` and `x2`.
957+ not op .isDefinitionInexact ( ) and
958+ exists ( PhiInstruction phi |
959+ isRelevantUnaryComparisonOperand ( unique( | | phi .getAUse ( ) ) ) and
960+ op = phi .getAnInputOperand ( )
961+ )
962+ or
963+ // If `__builtin_expect(x)` is a relevant unary comparison then so is `x`.
964+ exists ( BuiltinExpectCallInstruction call |
965+ isRelevantUnaryComparisonOperand ( unique( | | call .getAUse ( ) ) ) and
966+ op = call .getConditionOperand ( )
967+ )
968+ }
969+
927970/** Rearrange various simple comparisons into `op == k` form. */
928971private predicate unary_simple_comparison_eq (
929972 ValueNumber test , Operand op , int k , boolean inNonZeroCase , AbstractValue value
@@ -937,41 +980,8 @@ private predicate unary_simple_comparison_eq(
937980 inNonZeroCase = false
938981 )
939982 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
983+ isRelevantUnaryComparisonOperand ( op ) and
984+ op .getDef ( ) = test .getAnInstruction ( ) and
975985 (
976986 k = 1 and
977987 value .( BooleanValue ) .getValue ( ) = true and
@@ -988,10 +998,12 @@ private class BuiltinExpectCallInstruction extends CallInstruction {
988998 BuiltinExpectCallInstruction ( ) { this .getStaticCallTarget ( ) .hasName ( "__builtin_expect" ) }
989999
9901000 /** Gets the condition of this call. */
991- Instruction getCondition ( ) {
1001+ Instruction getCondition ( ) { result = this .getConditionOperand ( ) .getDef ( ) }
1002+
1003+ Operand getConditionOperand ( ) {
9921004 // The first parameter of `__builtin_expect` has type `long`. So we skip
9931005 // the conversion when inferring guards.
994- result = this .getArgument ( 0 ) .( ConvertInstruction ) .getUnary ( )
1006+ result = this .getArgument ( 0 ) .( ConvertInstruction ) .getUnaryOperand ( )
9951007 }
9961008}
9971009
0 commit comments