@@ -21,7 +21,8 @@ private module Cached {
2121 TOperandNode ( Operand op ) or
2222 TVariableNode ( Variable var ) or
2323 TStoreNodeInstr ( Instruction i ) { Ssa:: explicitWrite ( _, _, i ) } or
24- TStoreNodeOperand ( ArgumentOperand op ) { Ssa:: explicitWrite ( _, _, op .getDef ( ) ) }
24+ TStoreNodeOperand ( ArgumentOperand op ) { Ssa:: explicitWrite ( _, _, op .getDef ( ) ) } or
25+ TReadNode ( Instruction i ) { needsPostReadNode ( i ) }
2526
2627 cached
2728 predicate localFlowStepCached ( Node nodeFrom , Node nodeTo ) {
@@ -291,6 +292,61 @@ private class StoreNodeOperand extends StoreNode, TStoreNodeOperand {
291292 override StoreNode getAPredecessor ( ) { operand .getDef ( ) = result .getInstruction ( ) }
292293}
293294
295+ /**
296+ * INTERNAL: do not use.
297+ *
298+ * A `ReadNode` is a node that has been (or is about to be) the
299+ * source or target of a `readStep`.
300+ */
301+ class ReadNode extends Node , TReadNode {
302+ Instruction i ;
303+
304+ ReadNode ( ) { this = TReadNode ( i ) }
305+
306+ /** Gets the underlying instruction. */
307+ Instruction getInstruction ( ) { result = i }
308+
309+ override Declaration getEnclosingCallable ( ) { result = this .getFunction ( ) }
310+
311+ override Function getFunction ( ) { result = this .getInstruction ( ) .getEnclosingFunction ( ) }
312+
313+ override IRType getType ( ) { result = this .getInstruction ( ) .getResultIRType ( ) }
314+
315+ override Location getLocation ( ) { result = this .getInstruction ( ) .getLocation ( ) }
316+
317+ override string toString ( ) {
318+ result = instructionNode ( this .getInstruction ( ) ) .toString ( ) + " [read]"
319+ }
320+
321+ /** Gets a load instruction that uses the address computed by this read node. */
322+ final Instruction getALoadInstruction ( ) {
323+ Ssa:: addressFlowTC ( this .getInstruction ( ) , Ssa:: getSourceAddress ( result ) )
324+ }
325+
326+ /**
327+ * Gets a read node with an underlying instruction that is used by this
328+ * underlying instruction to compute an address of a load instruction.
329+ */
330+ final ReadNode getAPredecessor ( ) {
331+ Ssa:: addressFlow ( result .getInstruction ( ) , this .getInstruction ( ) )
332+ }
333+
334+ /** The inverse of `ReadNode.getAPredecessor`. */
335+ final ReadNode getASuccessor ( ) { result .getAPredecessor ( ) = this }
336+
337+ /** Holds if this read node computes a value that will not be used for any future read nodes. */
338+ final predicate isTerminal ( ) {
339+ not exists ( this .getASuccessor ( ) ) and
340+ not readStep ( this , _, _)
341+ }
342+
343+ /** Holds if this read node computes a value that has not yet been used for any read operations. */
344+ final predicate isInitial ( ) {
345+ not exists ( this .getAPredecessor ( ) ) and
346+ not readStep ( _, _, this )
347+ }
348+ }
349+
294350/**
295351 * An expression, viewed as a node in a data flow graph.
296352 */
@@ -731,6 +787,13 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
731787 StoreNodeFlow:: flowThrough ( nodeFrom , nodeTo )
732788 or
733789 StoreNodeFlow:: flowOutOf ( nodeFrom , nodeTo )
790+ or
791+ // Flow into, through, and out of read nodes
792+ ReadNodeFlow:: flowInto ( nodeFrom , nodeTo )
793+ or
794+ ReadNodeFlow:: flowThrough ( nodeFrom , nodeTo )
795+ or
796+ ReadNodeFlow:: flowOutOf ( nodeFrom , nodeTo )
734797}
735798
736799pragma [ noinline]
@@ -742,12 +805,65 @@ private predicate getFieldSizeOfClass(Class c, Type type, int size) {
742805 )
743806}
744807
745- private predicate isSingleFieldClass ( Type type , Operand op ) {
746- exists ( int size , Class c |
747- c = op .getType ( ) .getUnderlyingType ( ) and
748- c .getSize ( ) = size and
749- getFieldSizeOfClass ( c , type , size )
750- )
808+ private module ReadNodeFlow {
809+ /** Holds if the read node `nodeTo` should receive flow from `nodeFrom`. */
810+ predicate flowInto ( Node nodeFrom , ReadNode nodeTo ) {
811+ nodeTo .isInitial ( ) and
812+ (
813+ // If we entered through an address operand.
814+ nodeFrom .asOperand ( ) .getDef ( ) = nodeTo .getInstruction ( )
815+ or
816+ // If we entered flow through a memory-producing instruction.
817+ // This can happen if we have flow to an `InitializeParameterIndirection` through
818+ // a `ReadSideEffectInstruction`.
819+ exists ( Instruction load , Instruction def |
820+ def = nodeFrom .asInstruction ( ) and
821+ def = Ssa:: getSourceValueOperand ( load ) .getAnyDef ( ) and
822+ not def = any ( StoreNode store ) .getStoreInstruction ( ) and
823+ pragma [ only_bind_into ] ( nodeTo ) .getALoadInstruction ( ) = load
824+ )
825+ )
826+ }
827+
828+ /** Holds if the read node `nodeTo` should receive flow from the read node `nodeFrom`. */
829+ predicate flowThrough ( ReadNode nodeFrom , ReadNode nodeTo ) {
830+ not readStep ( nodeFrom , _, _) and
831+ nodeFrom .getASuccessor ( ) = nodeTo
832+ }
833+
834+ /**
835+ * Holds if flow should leave the read node `nFrom` and enter the node `nodeTo`.
836+ * This happens either because there is use-use flow from one of the variables used in
837+ * the read operation, or because we have traversed all the field dereferences in the
838+ * read operation.
839+ */
840+ predicate flowOutOf ( ReadNode nFrom , Node nodeTo ) {
841+ // Use-use flow to another use of the same variable instruction
842+ Ssa:: ssaFlow ( nFrom , nodeTo )
843+ or
844+ not exists ( nFrom .getAPredecessor ( ) ) and
845+ exists ( Node store |
846+ Ssa:: explicitWrite ( _, store .asInstruction ( ) , nFrom .getInstruction ( ) ) and
847+ Ssa:: ssaFlow ( store , nodeTo )
848+ )
849+ or
850+ // Flow out of read nodes and into memory instructions if we cannot move any further through
851+ // read nodes.
852+ nFrom .isTerminal ( ) and
853+ (
854+ exists ( Instruction load |
855+ load = nodeTo .asInstruction ( ) and
856+ Ssa:: getSourceAddress ( load ) = nFrom .getInstruction ( )
857+ )
858+ or
859+ exists ( CallInstruction call , int i |
860+ call .getArgument ( i ) = nodeTo .asInstruction ( ) and
861+ call .getArgument ( i ) = nFrom .getInstruction ( )
862+ )
863+ )
864+ }
865+ }
866+
751867private module StoreNodeFlow {
752868 /** Holds if the store node `nodeTo` should receive flow from `nodeFrom`. */
753869 predicate flowInto ( Node nodeFrom , StoreNode nodeTo ) {
0 commit comments