SSA: Sync with latest changes

Now that the shared SSA library supports uncertain/pseudo reads, we can simplify
the Ruby implementation.
This commit is contained in:
Tom Hvitved
2021-02-02 10:02:29 +01:00
parent 2770b4fef8
commit 16c4faef6a
5 changed files with 569 additions and 559 deletions

View File

@@ -48,13 +48,7 @@ module Ssa {
* end
* ```
*/
final VariableReadAccessCfgNode getARead() {
exists(LocalVariable v, BasicBlock bb, int i |
SsaImplCommon::ssaDefReachesRead(v, this, bb, i) and
SsaImpl::variableReadActual(bb, i, v) and
result = bb.getNode(i)
)
}
final VariableReadAccessCfgNode getARead() { result = SsaImpl::getARead(this) }
/**
* Gets a first control-flow node that reads the value of this SSA definition.
@@ -143,6 +137,15 @@ module Ssa {
SsaImpl::adjacentReadPair(this, read1, read2)
}
/**
* Gets an SSA definition whose value can flow to this one in one step. This
* includes inputs to phi nodes and the prior definitions of uncertain writes.
*/
private Definition getAPhiInputOrPriorDefinition() {
result = this.(PhiNode).getAnInput() or
result = this.(CapturedCallDefinition).getPriorDefinition()
}
/**
* Gets a definition that ultimately defines this SSA definition and is
* not itself a phi node.
@@ -168,8 +171,9 @@ module Ssa {
* end
* ```
*/
final override Definition getAnUltimateDefinition() {
result = SsaImplCommon::Definition.super.getAnUltimateDefinition()
final Definition getAnUltimateDefinition() {
result = this.getAPhiInputOrPriorDefinition*() and
not result instanceof PhiNode
}
override string toString() { result = this.getControlFlowNode().toString() }
@@ -284,9 +288,11 @@ module Ssa {
)
}
final override Definition getPriorDefinition() {
result = SsaImplCommon::UncertainWriteDefinition.super.getPriorDefinition()
}
/**
* Gets the immediately preceding definition. Since this update is uncertain,
* the value from the preceding definition might still be valid.
*/
final Definition getPriorDefinition() { result = SsaImpl::uncertainWriteDefinitionInput(this) }
override string toString() { result = this.getControlFlowNode().toString() }
}
@@ -330,7 +336,12 @@ module Ssa {
* end
* ```
*/
final override Definition getAnInput() { result = SsaImplCommon::PhiNode.super.getAnInput() }
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
/** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */
predicate hasInputFromBlock(Definition inp, BasicBlock bb) {
inp = SsaImpl::phiHasInputFromBlock(this, bb)
}
private string getSplitString() {
result = this.getBasicBlock().getFirstNode().(CfgNodes::AstCfgNode).getSplitsString()

View File

@@ -102,23 +102,22 @@ private predicate hasCapturedWrite(Variable v, CfgScope scope) {
}
/** Holds if `v` is read at index `i` in basic block `bb`. */
predicate variableReadActual(BasicBlock bb, int i, LocalVariable v) {
private predicate variableReadActual(BasicBlock bb, int i, LocalVariable v) {
exists(VariableReadAccess read |
read.getVariable() = v and
read = bb.getNode(i).getNode()
)
}
/**
* Holds if a pseudo read of `v` is inserted at index `i` in basic block `bb`.
*
* Pseudo reads are used to make otherwise dead assignments live, as they will
* otherwise not get an SSA definition.
*/
predicate variableReadPseudo(BasicBlock bb, int i, LocalVariable v) {
capturedCallRead(bb, i, v)
predicate variableRead(BasicBlock bb, int i, LocalVariable v, boolean certain) {
variableReadActual(bb, i, v) and
certain = true
or
capturedExitRead(bb, i, v)
capturedCallRead(bb, i, v) and
certain = false
or
capturedExitRead(bb, i, v) and
certain = false
}
pragma[noinline]
@@ -131,49 +130,6 @@ private predicate hasVariableReadWithCapturedWrite(BasicBlock bb, LocalVariable
)
}
private predicate adjacentDefReaches(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
adjacentDefRead(def, bb1, i1, bb2, i2)
or
exists(BasicBlock bb3, int i3 |
adjacentDefReaches(def, bb1, i1, bb3, i3) and
variableReadPseudo(bb3, i3, _) and
adjacentDefRead(def, bb3, i3, bb2, i2)
)
}
pragma[noinline]
private predicate adjacentDefActualRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefReaches(def, bb1, i1, bb2, i2) and
variableReadActual(bb2, i2, _)
}
private predicate adjacentDefPseudoRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefReaches(def, bb1, i1, bb2, i2) and
variableReadPseudo(bb2, i2, _)
}
private predicate reachesLastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
lastRefRedef(def, bb, i, next)
or
exists(BasicBlock bb0, int i0 |
reachesLastRefRedef(def, bb0, i0, next) and
adjacentDefPseudoRead(def, bb, i, bb0, i0)
)
}
private predicate reachesLastRef(Definition def, BasicBlock bb, int i) {
lastRef(def, bb, i)
or
exists(BasicBlock bb0, int i0 |
reachesLastRef(def, bb0, i0) and
adjacentDefPseudoRead(def, bb, i, bb0, i0)
)
}
cached
private module Cached {
/**
@@ -211,6 +167,20 @@ private module Cached {
)
}
cached
VariableReadAccessCfgNode getARead(Definition def) {
exists(LocalVariable v, BasicBlock bb, int i |
ssaDefReachesRead(v, def, bb, i) and
variableReadActual(bb, i, v) and
result = bb.getNode(i)
)
}
cached
Definition phiHasInputFromBlock(PhiNode phi, BasicBlock bb) {
phiHasInputFromBlock(phi, result, bb)
}
/**
* Holds if the value defined at SSA definition `def` can reach a read at `read`,
* without passing through any other non-pseudo read.
@@ -219,7 +189,7 @@ private module Cached {
predicate firstRead(Definition def, VariableReadAccessCfgNode read) {
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
def.definesAt(_, bb1, i1) and
adjacentDefActualRead(def, bb1, i1, bb2, i2) and
adjacentDefNoUncertainReads(def, bb1, i1, bb2, i2) and
read = bb2.getNode(i2)
)
}
@@ -236,7 +206,7 @@ private module Cached {
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
read1 = bb1.getNode(i1) and
variableReadActual(bb1, i1, _) and
adjacentDefActualRead(def, bb1, i1, bb2, i2) and
adjacentDefNoUncertainReads(def, bb1, i1, bb2, i2) and
read2 = bb2.getNode(i2)
)
}
@@ -249,7 +219,7 @@ private module Cached {
cached
predicate lastRead(Definition def, VariableReadAccessCfgNode read) {
exists(BasicBlock bb, int i |
reachesLastRef(def, bb, i) and
lastRefNoUncertainReads(def, bb, i) and
variableReadActual(bb, i, _) and
read = bb.getNode(i)
)
@@ -264,8 +234,12 @@ private module Cached {
*/
cached
predicate lastRefBeforeRedef(Definition def, BasicBlock bb, int i, Definition next) {
reachesLastRefRedef(def, bb, i, next) and
not variableReadPseudo(bb, i, def.getSourceVariable())
lastRefRedefNoUncertainReads(def, bb, i, next)
}
cached
Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) {
uncertainWriteDefinitionInput(def, result)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -31,8 +31,4 @@ predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain)
certain = false
}
predicate variableRead(BasicBlock bb, int i, SourceVariable v) {
SsaImpl::variableReadActual(bb, i, v)
or
SsaImpl::variableReadPseudo(bb, i, v)
}
predicate variableRead = SsaImpl::variableRead/4;