Merge pull request #12356 from MathiasVP/use-phi-reads

C++: Include "phi reads" in `DataFlow::Node`
This commit is contained in:
Mathias Vorreiter Pedersen
2023-03-03 11:14:08 +00:00
committed by GitHub
5 changed files with 84 additions and 29 deletions

View File

@@ -43,7 +43,7 @@ class Node0Impl extends TIRDataFlowNode0 {
/** /**
* Gets the type of this node. * Gets the type of this node.
* *
* If `asInstruction().isGLValue()` holds, then the type of this node * If `isGLValue()` holds, then the type of this node
* should be thought of as "pointer to `getType()`". * should be thought of as "pointer to `getType()`".
*/ */
DataFlowType getType() { none() } // overridden in subclasses DataFlowType getType() { none() } // overridden in subclasses

View File

@@ -498,7 +498,14 @@ class SsaPhiNode extends Node, TSsaPhiNode {
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() } override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
override DataFlowType getType() { result = this.getAnInput().getType().getUnspecifiedType() } override DataFlowType getType() {
exists(Ssa::SourceVariable sv |
this.getPhiNode().definesAt(sv, _, _, _) and
result = sv.getType()
)
}
override predicate isGLValue() { phi.getSourceVariable().isGLValue() }
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() } final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }

View File

@@ -48,6 +48,16 @@ private module SourceVariables {
* indirections) of this source variable. * indirections) of this source variable.
*/ */
abstract BaseSourceVariable getBaseVariable(); abstract BaseSourceVariable getBaseVariable();
/** Holds if this variable is a glvalue. */
predicate isGLValue() { none() }
/**
* Gets the type of this source variable. If `isGLValue()` holds, then
* the type of this source variable should be thought of as "pointer
* to `getType()`".
*/
abstract DataFlowType getType();
} }
class SourceIRVariable extends SourceVariable, TSourceIRVariable { class SourceIRVariable extends SourceVariable, TSourceIRVariable {
@@ -66,6 +76,12 @@ private module SourceVariables {
ind > 0 and ind > 0 and
result = this.getIRVariable().toString() + " indirection" result = this.getIRVariable().toString() + " indirection"
} }
override predicate isGLValue() { ind = 0 }
override DataFlowType getType() {
if ind = 0 then result = var.getType() else result = getTypeImpl(var.getType(), ind - 1)
}
} }
class CallVariable extends SourceVariable, TCallVariable { class CallVariable extends SourceVariable, TCallVariable {
@@ -84,6 +100,8 @@ private module SourceVariables {
ind > 0 and ind > 0 and
result = "Call indirection" result = "Call indirection"
} }
override DataFlowType getType() { result = getTypeImpl(call.getResultType(), ind) }
} }
} }
@@ -530,15 +548,15 @@ predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
exists(IRBlock bb1, int i1, SourceVariable v | exists(IRBlock bb1, int i1, SourceVariable v |
defOrUse1.asDefOrUse().hasIndexInBlock(bb1, i1, v) defOrUse1.asDefOrUse().hasIndexInBlock(bb1, i1, v)
| |
exists(IRBlock bb2, int i2, Definition def | exists(IRBlock bb2, int i2, DefinitionExt def |
adjacentDefRead(pragma[only_bind_into](def), pragma[only_bind_into](bb1), adjacentDefReadExt(pragma[only_bind_into](def), pragma[only_bind_into](bb1),
pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
def.getSourceVariable() = v and def.getSourceVariable() = v and
use.asDefOrUse().(UseImpl).hasIndexInBlock(bb2, i2, v) use.asDefOrUse().(UseImpl).hasIndexInBlock(bb2, i2, v)
) )
or or
exists(PhiNode phi | exists(PhiNode phi |
lastRefRedef(_, bb1, i1, phi) and lastRefRedefExt(_, bb1, i1, phi) and
use.asPhi() = phi and use.asPhi() = phi and
phi.getSourceVariable() = pragma[only_bind_into](v) phi.getSourceVariable() = pragma[only_bind_into](v)
) )
@@ -550,11 +568,18 @@ predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
* flows to `useOrPhi`. * flows to `useOrPhi`.
*/ */
private predicate globalDefToUse(GlobalDef globalDef, UseOrPhi useOrPhi) { private predicate globalDefToUse(GlobalDef globalDef, UseOrPhi useOrPhi) {
exists(IRBlock bb1, int i1, IRBlock bb2, int i2, SourceVariable v | exists(IRBlock bb1, int i1, SourceVariable v | globalDef.hasIndexInBlock(bb1, i1, v) |
globalDef.hasIndexInBlock(bb1, i1, v) and exists(IRBlock bb2, int i2 |
adjacentDefRead(_, pragma[only_bind_into](bb1), pragma[only_bind_into](i1), adjacentDefReadExt(_, pragma[only_bind_into](bb1), pragma[only_bind_into](i1),
pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
useOrPhi.asDefOrUse().hasIndexInBlock(bb2, i2, v) useOrPhi.asDefOrUse().hasIndexInBlock(bb2, i2, v)
)
or
exists(PhiNode phi |
lastRefRedefExt(_, bb1, i1, phi) and
useOrPhi.asPhi() = phi and
phi.getSourceVariable() = pragma[only_bind_into](v)
)
) )
} }
@@ -666,17 +691,17 @@ private predicate ssaFlowImpl(SsaDefOrUse defOrUse, Node nodeFrom, Node nodeTo,
* Holds if `def` is the corresponding definition of * Holds if `def` is the corresponding definition of
* the SSA library's `definition`. * the SSA library's `definition`.
*/ */
private Definition ssaDefinition(Def def) { private DefinitionExt ssaDefinition(Def def) {
exists(IRBlock block, int i, SourceVariable sv | exists(IRBlock block, int i, SourceVariable sv |
def.hasIndexInBlock(block, i, sv) and def.hasIndexInBlock(block, i, sv) and
result.definesAt(sv, block, i) result.definesAt(sv, block, i, _)
) )
} }
/** Gets a node that represents the prior definition of `node`. */ /** Gets a node that represents the prior definition of `node`. */
private Node getAPriorDefinition(SsaDefOrUse defOrUse) { private Node getAPriorDefinition(SsaDefOrUse defOrUse) {
exists(IRBlock bb, int i, SourceVariable sv, Definition def, DefOrUse defOrUse0 | exists(IRBlock bb, int i, SourceVariable sv, DefinitionExt def, DefOrUse defOrUse0 |
SsaCached::lastRefRedef(pragma[only_bind_into](def), pragma[only_bind_into](bb), lastRefRedefExt(pragma[only_bind_into](def), pragma[only_bind_into](bb),
pragma[only_bind_into](i), ssaDefinition(defOrUse)) and pragma[only_bind_into](i), ssaDefinition(defOrUse)) and
def.getSourceVariable() = sv and def.getSourceVariable() = sv and
defOrUse0.hasIndexInBlock(bb, i, sv) and defOrUse0.hasIndexInBlock(bb, i, sv) and
@@ -702,7 +727,7 @@ pragma[nomagic]
private predicate fromPhiNodeToUse(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use) { private predicate fromPhiNodeToUse(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use) {
exists(IRBlock bb2, int i2 | exists(IRBlock bb2, int i2 |
use.asDefOrUse().hasIndexInBlock(bb2, i2, sv) and use.asDefOrUse().hasIndexInBlock(bb2, i2, sv) and
adjacentDefRead(pragma[only_bind_into](phi), pragma[only_bind_into](bb1), adjacentDefReadExt(pragma[only_bind_into](phi), pragma[only_bind_into](bb1),
pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2))
) )
} }
@@ -711,13 +736,13 @@ private predicate fromPhiNodeToUse(PhiNode phi, SourceVariable sv, IRBlock bb1,
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) { predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use | exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use |
phi = nodeFrom.getPhiNode() and phi = nodeFrom.getPhiNode() and
phi.definesAt(sv, bb1, i1) and phi.definesAt(sv, bb1, i1, _) and
useToNode(use, nodeTo) useToNode(use, nodeTo)
| |
fromPhiNodeToUse(phi, sv, bb1, i1, use) fromPhiNodeToUse(phi, sv, bb1, i1, use)
or or
exists(PhiNode phiTo | exists(PhiNode phiTo |
lastRefRedef(phi, _, _, phiTo) and lastRefRedefExt(phi, _, _, phiTo) and
nodeTo.(SsaPhiNode).getPhiNode() = phiTo nodeTo.(SsaPhiNode).getPhiNode() = phiTo
) )
) )
@@ -796,8 +821,8 @@ module SsaCached {
* path between them without any read of `def`. * path between them without any read of `def`.
*/ */
cached cached
predicate adjacentDefRead(Definition def, IRBlock bb1, int i1, IRBlock bb2, int i2) { predicate adjacentDefReadExt(DefinitionExt def, IRBlock bb1, int i1, IRBlock bb2, int i2) {
SsaImpl::adjacentDefRead(def, bb1, i1, bb2, i2) SsaImpl::adjacentDefReadExt(def, _, bb1, i1, bb2, i2)
} }
/** /**
@@ -806,8 +831,8 @@ module SsaCached {
* without passing through another read or write. * without passing through another read or write.
*/ */
cached cached
predicate lastRefRedef(Definition def, IRBlock bb, int i, Definition next) { predicate lastRefRedefExt(DefinitionExt def, IRBlock bb, int i, DefinitionExt next) {
SsaImpl::lastRefRedef(def, bb, i, next) SsaImpl::lastRefRedefExt(def, _, bb, i, next)
} }
} }
@@ -818,8 +843,8 @@ private newtype TSsaDefOrUse =
or or
// Like in the pruning stage, we only include definition that's live after the // Like in the pruning stage, we only include definition that's live after the
// write as the final definitions computed by SSA. // write as the final definitions computed by SSA.
exists(Definition def, SourceVariable sv, IRBlock bb, int i | exists(DefinitionExt def, SourceVariable sv, IRBlock bb, int i |
def.definesAt(sv, bb, i) and def.definesAt(sv, bb, i, _) and
defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv) defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv)
) )
} or } or
@@ -967,9 +992,14 @@ class Def extends DefOrUse {
private module SsaImpl = SsaImplCommon::Make<SsaInput>; private module SsaImpl = SsaImplCommon::Make<SsaInput>;
class PhiNode = SsaImpl::PhiNode; class PhiNode extends SsaImpl::DefinitionExt {
PhiNode() {
this instanceof SsaImpl::PhiNode or
this instanceof SsaImpl::PhiReadNode
}
}
class Definition = SsaImpl::Definition; class DefinitionExt = SsaImpl::DefinitionExt;
class UncertainWriteDefinition = SsaImpl::UncertainWriteDefinition; class UncertainWriteDefinition = SsaImpl::UncertainWriteDefinition;

View File

@@ -225,8 +225,8 @@ private newtype TSsaDefOrUse =
or or
// If `defOrUse` is a definition we only include it if the // If `defOrUse` is a definition we only include it if the
// SSA library concludes that it's live after the write. // SSA library concludes that it's live after the write.
exists(Definition def, SourceVariable sv, IRBlock bb, int i | exists(DefinitionExt def, SourceVariable sv, IRBlock bb, int i |
def.definesAt(sv, bb, i) and def.definesAt(sv, bb, i, _) and
defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv) defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv)
) )
} or } or
@@ -301,6 +301,11 @@ class Def extends DefOrUse {
private module SsaImpl = SsaImplCommon::Make<SsaInput>; private module SsaImpl = SsaImplCommon::Make<SsaInput>;
class PhiNode = SsaImpl::PhiNode; class PhiNode extends SsaImpl::DefinitionExt {
PhiNode() {
this instanceof SsaImpl::PhiNode or
this instanceof SsaImpl::PhiReadNode
}
}
class Definition = SsaImpl::Definition; class DefinitionExt = SsaImpl::DefinitionExt;

View File

@@ -615,3 +615,16 @@ void test_flow_through_void_double_pointer(int *p) // $ ast-def=p
void* q = (void*)&p; void* q = (void*)&p;
sink(**(int**)q); // $ ir MISSING: ast sink(**(int**)q); // $ ir MISSING: ast
} }
void use(int *);
void test_def_via_phi_read(bool b)
{
static int buffer[10]; // This is missing an initialisation in IR dataflow
if (b)
{
use(buffer);
}
intPointerSource(buffer);
sink(buffer); // $ ast,ir
}