@@ -45,6 +45,7 @@ private newtype TIRDataFlowNode =
45
45
or
46
46
Ssa:: isModifiableByCall ( operand , indirectionIndex )
47
47
} or
48
+ TSsaPhiInputNode ( Ssa:: PhiNode phi , IRBlock input ) { phi .hasInputFromBlock ( _, _, _, _, input ) } or
48
49
TSsaPhiNode ( Ssa:: PhiNode phi ) or
49
50
TSsaIteratorNode ( IteratorFlow:: IteratorFlowNode n ) or
50
51
TRawIndirectOperand0 ( Node0Impl node , int indirectionIndex ) {
@@ -165,6 +166,12 @@ class Node extends TIRDataFlowNode {
165
166
/** Gets the operands corresponding to this node, if any. */
166
167
Operand asOperand ( ) { result = this .( OperandNode ) .getOperand ( ) }
167
168
169
+ /**
170
+ * Gets the operand that is indirectly tracked by this node behind `index`
171
+ * number of indirections.
172
+ */
173
+ Operand asIndirectOperand ( int index ) { hasOperandAndIndex ( this , result , index ) }
174
+
168
175
/**
169
176
* Holds if this node is at index `i` in basic block `block`.
170
177
*
@@ -177,6 +184,9 @@ class Node extends TIRDataFlowNode {
177
184
or
178
185
this .( SsaPhiNode ) .getPhiNode ( ) .getBasicBlock ( ) = block and i = - 1
179
186
or
187
+ this .( SsaPhiInputNode ) .getBlock ( ) = block and
188
+ i = block .getInstructionCount ( )
189
+ or
180
190
this .( RawIndirectOperand ) .getOperand ( ) .getUse ( ) = block .getInstruction ( i )
181
191
or
182
192
this .( RawIndirectInstruction ) .getInstruction ( ) = block .getInstruction ( i )
@@ -629,7 +639,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
629
639
630
640
final override Location getLocationImpl ( ) { result = phi .getBasicBlock ( ) .getLocation ( ) }
631
641
632
- override string toStringImpl ( ) { result = "Phi" }
642
+ override string toStringImpl ( ) { result = phi . toString ( ) }
633
643
634
644
/**
635
645
* Gets a node that is used as input to this phi node.
@@ -638,7 +648,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
638
648
*/
639
649
cached
640
650
final Node getAnInput ( boolean fromBackEdge ) {
641
- localFlowStep ( result , this ) and
651
+ result . ( SsaPhiInputNode ) . getPhiNode ( ) = phi and
642
652
exists ( IRBlock bPhi , IRBlock bResult |
643
653
bPhi = phi .getBasicBlock ( ) and bResult = result .getBasicBlock ( )
644
654
|
@@ -661,6 +671,58 @@ class SsaPhiNode extends Node, TSsaPhiNode {
661
671
predicate isPhiRead ( ) { phi .isPhiRead ( ) }
662
672
}
663
673
674
+ /**
675
+ * INTERNAL: Do not use.
676
+ *
677
+ * A node that is used as an input to a phi node.
678
+ *
679
+ * This class exists to allow more powerful barrier guards. Consider this
680
+ * example:
681
+ *
682
+ * ```cpp
683
+ * int x = source();
684
+ * if(!safe(x)) {
685
+ * x = clear();
686
+ * }
687
+ * // phi node for x here
688
+ * sink(x);
689
+ * ```
690
+ *
691
+ * At the phi node for `x` it is neither the case that `x` is dominated by
692
+ * `safe(x)`, or is the case that the phi is dominated by a clearing of `x`.
693
+ *
694
+ * By inserting a "phi input" node as the last entry in the basic block that
695
+ * defines the inputs to the phi we can conclude that each of those inputs are
696
+ * safe to pass to `sink`.
697
+ */
698
+ class SsaPhiInputNode extends Node , TSsaPhiInputNode {
699
+ Ssa:: PhiNode phi ;
700
+ IRBlock block ;
701
+
702
+ SsaPhiInputNode ( ) { this = TSsaPhiInputNode ( phi , block ) }
703
+
704
+ /** Gets the phi node associated with this node. */
705
+ Ssa:: PhiNode getPhiNode ( ) { result = phi }
706
+
707
+ /** Gets the basic block in which this input originates. */
708
+ IRBlock getBlock ( ) { result = block }
709
+
710
+ override Declaration getEnclosingCallable ( ) { result = this .getFunction ( ) }
711
+
712
+ override Declaration getFunction ( ) { result = phi .getBasicBlock ( ) .getEnclosingFunction ( ) }
713
+
714
+ override DataFlowType getType ( ) { result = this .getSourceVariable ( ) .getType ( ) }
715
+
716
+ override predicate isGLValue ( ) { phi .getSourceVariable ( ) .isGLValue ( ) }
717
+
718
+ final override Location getLocationImpl ( ) { result = block .getLastInstruction ( ) .getLocation ( ) }
719
+
720
+ override string toStringImpl ( ) { result = "Phi input" }
721
+
722
+ /** Gets the source variable underlying this phi node. */
723
+ Ssa:: SourceVariable getSourceVariable ( ) { result = phi .getSourceVariable ( ) }
724
+ }
725
+
664
726
/**
665
727
* INTERNAL: do not use.
666
728
*
@@ -2183,6 +2245,9 @@ private module Cached {
2183
2245
// Def-use/Use-use flow
2184
2246
Ssa:: ssaFlow ( nodeFrom , nodeTo )
2185
2247
or
2248
+ // Phi input -> Phi
2249
+ nodeFrom .( SsaPhiInputNode ) .getPhiNode ( ) = nodeTo .( SsaPhiNode ) .getPhiNode ( )
2250
+ or
2186
2251
IteratorFlow:: localFlowStep ( nodeFrom , nodeTo )
2187
2252
or
2188
2253
// Operand -> Instruction flow
@@ -2621,6 +2686,22 @@ class ContentSet instanceof Content {
2621
2686
}
2622
2687
}
2623
2688
2689
+ pragma [ nomagic]
2690
+ private predicate guardControlsPhiInput (
2691
+ IRGuardCondition g , boolean branch , Ssa:: Definition def , IRBlock input , Ssa:: PhiNode phi
2692
+ ) {
2693
+ phi .hasInputFromBlock ( def , _, _, _, input ) and
2694
+ (
2695
+ g .controls ( input , branch )
2696
+ or
2697
+ exists ( EdgeKind kind |
2698
+ g .getBlock ( ) = input and
2699
+ kind = getConditionalEdge ( branch ) and
2700
+ input .getSuccessor ( kind ) = phi .getBasicBlock ( )
2701
+ )
2702
+ )
2703
+ }
2704
+
2624
2705
/**
2625
2706
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
2626
2707
*
@@ -2669,13 +2750,21 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
2669
2750
*
2670
2751
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
2671
2752
*/
2672
- ExprNode getABarrierNode ( ) {
2753
+ Node getABarrierNode ( ) {
2673
2754
exists ( IRGuardCondition g , Expr e , ValueNumber value , boolean edge |
2674
2755
e = value .getAnInstruction ( ) .getConvertedResultExpression ( ) and
2675
- result .getConvertedExpr ( ) = e and
2756
+ result .asConvertedExpr ( ) = e and
2676
2757
guardChecks ( g , value .getAnInstruction ( ) .getConvertedResultExpression ( ) , edge ) and
2677
2758
g .controls ( result .getBasicBlock ( ) , edge )
2678
2759
)
2760
+ or
2761
+ exists (
2762
+ IRGuardCondition g , boolean branch , Ssa:: DefinitionExt def , IRBlock input , Ssa:: PhiNode phi
2763
+ |
2764
+ guardChecks ( g , def .getARead ( ) .asOperand ( ) .getDef ( ) .getConvertedResultExpression ( ) , branch ) and
2765
+ guardControlsPhiInput ( g , branch , def , input , phi ) and
2766
+ result = TSsaPhiInputNode ( phi , input )
2767
+ )
2679
2768
}
2680
2769
2681
2770
/**
@@ -2711,7 +2800,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
2711
2800
*
2712
2801
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
2713
2802
*/
2714
- IndirectExprNode getAnIndirectBarrierNode ( ) { result = getAnIndirectBarrierNode ( _) }
2803
+ Node getAnIndirectBarrierNode ( ) { result = getAnIndirectBarrierNode ( _) }
2715
2804
2716
2805
/**
2717
2806
* Gets an indirect expression node with indirection index `indirectionIndex` that is
@@ -2747,13 +2836,23 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
2747
2836
*
2748
2837
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
2749
2838
*/
2750
- IndirectExprNode getAnIndirectBarrierNode ( int indirectionIndex ) {
2839
+ Node getAnIndirectBarrierNode ( int indirectionIndex ) {
2751
2840
exists ( IRGuardCondition g , Expr e , ValueNumber value , boolean edge |
2752
2841
e = value .getAnInstruction ( ) .getConvertedResultExpression ( ) and
2753
- result .getConvertedExpr ( indirectionIndex ) = e and
2842
+ result .asIndirectConvertedExpr ( indirectionIndex ) = e and
2754
2843
guardChecks ( g , value .getAnInstruction ( ) .getConvertedResultExpression ( ) , edge ) and
2755
2844
g .controls ( result .getBasicBlock ( ) , edge )
2756
2845
)
2846
+ or
2847
+ exists (
2848
+ IRGuardCondition g , boolean branch , Ssa:: DefinitionExt def , IRBlock input , Ssa:: PhiNode phi
2849
+ |
2850
+ guardChecks ( g ,
2851
+ def .getARead ( ) .asIndirectOperand ( indirectionIndex ) .getDef ( ) .getConvertedResultExpression ( ) ,
2852
+ branch ) and
2853
+ guardControlsPhiInput ( g , branch , def , input , phi ) and
2854
+ result = TSsaPhiInputNode ( phi , input )
2855
+ )
2757
2856
}
2758
2857
}
2759
2858
@@ -2762,6 +2861,14 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
2762
2861
*/
2763
2862
signature predicate instructionGuardChecksSig ( IRGuardCondition g , Instruction instr , boolean branch ) ;
2764
2863
2864
+ private EdgeKind getConditionalEdge ( boolean branch ) {
2865
+ branch = true and
2866
+ result instanceof TrueEdge
2867
+ or
2868
+ branch = false and
2869
+ result instanceof FalseEdge
2870
+ }
2871
+
2765
2872
/**
2766
2873
* Provides a set of barrier nodes for a guard that validates an instruction.
2767
2874
*
@@ -2770,12 +2877,20 @@ signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction in
2770
2877
*/
2771
2878
module InstructionBarrierGuard< instructionGuardChecksSig / 3 instructionGuardChecks> {
2772
2879
/** Gets a node that is safely guarded by the given guard check. */
2773
- ExprNode getABarrierNode ( ) {
2880
+ Node getABarrierNode ( ) {
2774
2881
exists ( IRGuardCondition g , ValueNumber value , boolean edge , Operand use |
2775
2882
instructionGuardChecks ( g , value .getAnInstruction ( ) , edge ) and
2776
2883
use = value .getAnInstruction ( ) .getAUse ( ) and
2777
2884
result .asOperand ( ) = use and
2778
- g .controls ( use .getDef ( ) .getBlock ( ) , edge )
2885
+ g .controls ( result .getBasicBlock ( ) , edge )
2886
+ )
2887
+ or
2888
+ exists (
2889
+ IRGuardCondition g , boolean branch , Ssa:: DefinitionExt def , IRBlock input , Ssa:: PhiNode phi
2890
+ |
2891
+ instructionGuardChecks ( g , def .getARead ( ) .asOperand ( ) .getDef ( ) , branch ) and
2892
+ guardControlsPhiInput ( g , branch , def , input , phi ) and
2893
+ result = TSsaPhiInputNode ( phi , input )
2779
2894
)
2780
2895
}
2781
2896
}
0 commit comments