@@ -762,6 +762,8 @@ private predicate compares_eq(
762762 exists ( AbstractValue dual | value = dual .getDualValue ( ) |
763763 compares_eq ( test .( LogicalNotInstruction ) .getUnary ( ) , left , right , k , areEqual , dual )
764764 )
765+ or
766+ compares_eq ( test .( BuiltinExpectCallInstruction ) .getCondition ( ) , left , right , k , areEqual , value )
765767}
766768
767769/**
@@ -831,6 +833,9 @@ private predicate unary_compares_eq(
831833 int_value ( const ) = k1 and
832834 k = k1 + k2
833835 )
836+ or
837+ unary_compares_eq ( test .( BuiltinExpectCallInstruction ) .getCondition ( ) , op , k , areEqual ,
838+ inNonZeroCase , value )
834839}
835840
836841/** Rearrange various simple comparisons into `left == right + k` form. */
@@ -910,12 +915,68 @@ private predicate unary_simple_comparison_eq(
910915 )
911916}
912917
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+
913951private predicate complex_eq (
914952 CompareInstruction cmp , Operand left , Operand right , int k , boolean areEqual , AbstractValue value
915953) {
916954 sub_eq ( cmp , left , right , k , areEqual , value )
917955 or
918956 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+ )
919980}
920981
921982private predicate unary_complex_eq (
@@ -924,6 +985,8 @@ private predicate unary_complex_eq(
924985 unary_sub_eq ( test , op , k , areEqual , inNonZeroCase , value )
925986 or
926987 unary_add_eq ( test , op , k , areEqual , inNonZeroCase , value )
988+ or
989+ unary_builtin_expect_eq ( test , op , k , areEqual , inNonZeroCase , value )
927990}
928991
929992/*
0 commit comments