@@ -375,6 +375,33 @@ cached
375
375
class IRGuardCondition extends Instruction {
376
376
Instruction branch ;
377
377
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
+
378
405
cached
379
406
IRGuardCondition ( ) { branch = getBranchForCondition ( this ) }
380
407
@@ -735,6 +762,8 @@ private predicate compares_eq(
735
762
exists ( AbstractValue dual | value = dual .getDualValue ( ) |
736
763
compares_eq ( test .( LogicalNotInstruction ) .getUnary ( ) , left , right , k , areEqual , dual )
737
764
)
765
+ or
766
+ compares_eq ( test .( BuiltinExpectCallInstruction ) .getCondition ( ) , left , right , k , areEqual , value )
738
767
}
739
768
740
769
/**
@@ -776,7 +805,9 @@ private predicate unary_compares_eq(
776
805
Instruction test , Operand op , int k , boolean areEqual , boolean inNonZeroCase , AbstractValue value
777
806
) {
778
807
/* 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
+ |
780
811
areEqual = true and value = v
781
812
or
782
813
areEqual = false and value = v .getDualValue ( )
@@ -802,6 +833,9 @@ private predicate unary_compares_eq(
802
833
int_value ( const ) = k1 and
803
834
k = k1 + k2
804
835
)
836
+ or
837
+ unary_compares_eq ( test .( BuiltinExpectCallInstruction ) .getCondition ( ) , op , k , areEqual ,
838
+ inNonZeroCase , value )
805
839
}
806
840
807
841
/** Rearrange various simple comparisons into `left == right + k` form. */
@@ -821,45 +855,55 @@ private predicate simple_comparison_eq(
821
855
value .( BooleanValue ) .getValue ( ) = false
822
856
}
823
857
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
-
843
858
/**
844
859
* Rearrange various simple comparisons into `op == k` form.
845
860
*/
846
861
private 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
848
863
) {
849
864
exists ( SwitchInstruction switch , CaseEdge case |
850
865
test = switch .getExpression ( ) and
851
- op .getDef ( ) = test and
852
866
case = value .( MatchValue ) .getCase ( ) and
853
867
exists ( switch .getSuccessor ( case ) ) and
854
868
case .getValue ( ) .toInt ( ) = k and
855
869
inNonZeroCase = false
856
870
)
857
871
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
863
907
(
864
908
k = 1 and
865
909
value .( BooleanValue ) .getValue ( ) = true and
@@ -871,12 +915,68 @@ private predicate unary_simple_comparison_eq(
871
915
)
872
916
}
873
917
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
+
874
951
private predicate complex_eq (
875
952
CompareInstruction cmp , Operand left , Operand right , int k , boolean areEqual , AbstractValue value
876
953
) {
877
954
sub_eq ( cmp , left , right , k , areEqual , value )
878
955
or
879
956
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
+ )
880
980
}
881
981
882
982
private predicate unary_complex_eq (
@@ -885,6 +985,8 @@ private predicate unary_complex_eq(
885
985
unary_sub_eq ( test , op , k , areEqual , inNonZeroCase , value )
886
986
or
887
987
unary_add_eq ( test , op , k , areEqual , inNonZeroCase , value )
988
+ or
989
+ unary_builtin_expect_eq ( test , op , k , areEqual , inNonZeroCase , value )
888
990
}
889
991
890
992
/*
@@ -913,7 +1015,8 @@ private predicate compares_lt(
913
1015
914
1016
/** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */
915
1017
private 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
917
1020
or
918
1021
complex_lt ( test , op , k , isLt , value )
919
1022
or
@@ -960,12 +1063,11 @@ private predicate simple_comparison_lt(CompareInstruction cmp, Operand left, Ope
960
1063
}
961
1064
962
1065
/** 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
965
1068
) {
966
1069
exists ( SwitchInstruction switch , CaseEdge case |
967
1070
test = switch .getExpression ( ) and
968
- op .getDef ( ) = test and
969
1071
case = value .( MatchValue ) .getCase ( ) and
970
1072
exists ( switch .getSuccessor ( case ) ) and
971
1073
case .getMaxValue ( ) > case .getMinValue ( )
0 commit comments