Skip to content

Commit b756a08

Browse files
authored
Merge pull request #22425 from MathiasVP/speed-up-get-an-ultimate-definition
C++: Speed up `Ssa::getAnUltimateDefinition`
2 parents f70e0b5 + 49600c1 commit b756a08

4 files changed

Lines changed: 159 additions & 39 deletions

File tree

cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,28 @@ private module Input2 implements Impl::Private::InputSig2 {
171171
result = e.(ConversionCall).getQualifier().(LambdaExpression).getLambdaFunction()
172172
}
173173

174+
private predicate isRelevantUltimateDefinition(Ssa::DirectExplicitDefinition def, Function f) {
175+
f =
176+
getFunctionFromExpr(def.getAssignedInstruction()
177+
.(StoreInstruction)
178+
.getSourceValue()
179+
.getUnconvertedResultExpression())
180+
}
181+
182+
private module GetAnUltimateDefinitionInput implements Ssa::GetAnUltimateDefinitionSig {
183+
predicate isRelevantUltimateDefinition(Ssa::Definition def) {
184+
isRelevantUltimateDefinition(def, _)
185+
}
186+
}
187+
188+
private predicate hasAnUltimateFunctionAccessDefinition(Ssa::Definition def, Function f) {
189+
exists(Ssa::Definition ultimate |
190+
ultimate =
191+
Ssa::GetAnUltimateDefinition<GetAnUltimateDefinitionInput>::getAnUltimateDefinition(def) and
192+
isRelevantUltimateDefinition(ultimate, f)
193+
)
194+
}
195+
174196
class SourceSinkReportingElement extends Element {
175197
SourceSinkReportingElement() { this instanceof Expr or this instanceof Parameter }
176198

@@ -190,13 +212,7 @@ private module Input2 implements Impl::Private::InputSig2 {
190212
// The expression is an SSA read of an assignment of a callable
191213
exists(Ssa::Definition def |
192214
def.getAUse().getDef().getUnconvertedResultExpression() = this and
193-
result =
194-
getFunctionFromExpr(def.getAnUltimateDefinition()
195-
.(Ssa::DirectExplicitDefinition)
196-
.getAssignedInstruction()
197-
.(StoreInstruction)
198-
.getSourceValue()
199-
.getUnconvertedResultExpression())
215+
hasAnUltimateFunctionAccessDefinition(def, result)
200216
)
201217
}
202218

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1977,13 +1977,23 @@ module IteratorFlow {
19771977
}
19781978

19791979
/**
1980-
* Gets an ultimate definition of `def`.
1981-
*
1982-
* Note: Unlike `def.getAnUltimateDefinition()` this predicate also
1983-
* traverses back through iterator increment and decrement operations.
1980+
* Holds if `write` is an instruction that writes to address `address`
19841981
*/
1985-
private Ssa::Definition getAnUltimateDefinition(Ssa::Definition def) {
1986-
result = def.getAnUltimateDefinition()
1982+
private predicate isIteratorWrite(Instruction write, Operand address) {
1983+
exists(Ssa::DefImpl writeDef, IRBlock bb, int i |
1984+
writeDef.hasIndexInBlock(_, bb, i) and
1985+
bb.getInstruction(i) = write and
1986+
address = writeDef.getAddressOperand()
1987+
)
1988+
}
1989+
1990+
private module GetAnUltimateDefinitionInput implements Ssa::GetAnUltimateDefinitionSig {
1991+
predicate isRelevantUltimateDefinition(Ssa::Definition def) { fwd(_, def) }
1992+
}
1993+
1994+
private Ssa::Definition getAnUltimateDefinitionStep(Ssa::Definition def) {
1995+
result =
1996+
Ssa::GetAnUltimateDefinition<GetAnUltimateDefinitionInput>::getAnUltimateDefinition(def)
19871997
or
19881998
exists(IRBlock bb, int i, IteratorCrementCall crementCall, Ssa::SourceVariable sv |
19891999
crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and
@@ -1993,14 +2003,28 @@ module IteratorFlow {
19932003
)
19942004
}
19952005

1996-
/**
1997-
* Holds if `write` is an instruction that writes to address `address`
1998-
*/
1999-
private predicate isIteratorWrite(Instruction write, Operand address) {
2000-
exists(Ssa::DefImpl writeDef, IRBlock bb, int i |
2001-
writeDef.hasIndexInBlock(_, bb, i) and
2002-
bb.getInstruction(i) = write and
2003-
address = writeDef.getAddressOperand()
2006+
private predicate isSource(GetsIteratorCall beginCall, Ssa::Definition def) {
2007+
exists(StoreInstruction beginStore |
2008+
beginStore = def.getValue().asInstruction() and
2009+
operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)
2010+
)
2011+
}
2012+
2013+
private predicate isSink(Instruction writeToDeref, Ssa::Definition def) {
2014+
exists(IteratorPointerDereferenceCall starCall, Operand address, IRBlock bbStar, int iStar |
2015+
isIteratorWrite(writeToDeref, address) and
2016+
operandForFullyConvertedCall(address, starCall) and
2017+
bbStar.getInstruction(iStar) = starCall and
2018+
Ssa::ssaDefReachesRead(_, def, bbStar, iStar)
2019+
)
2020+
}
2021+
2022+
private predicate fwd(GetsIteratorCall beginCall, Ssa::Definition def) {
2023+
isSource(beginCall, def)
2024+
or
2025+
exists(Ssa::Definition def0 |
2026+
fwd(beginCall, def0) and
2027+
def0 = getAnUltimateDefinitionStep(def)
20042028
)
20052029
}
20062030

@@ -2016,17 +2040,9 @@ module IteratorFlow {
20162040
private predicate isIteratorStoreInstruction(
20172041
GetsIteratorCall beginCall, Instruction writeToDeref
20182042
) {
2019-
exists(
2020-
StoreInstruction beginStore, IRBlock bbStar, int iStar, Ssa::Definition def,
2021-
IteratorPointerDereferenceCall starCall, Ssa::Definition ultimate, Operand address
2022-
|
2023-
isIteratorWrite(writeToDeref, address) and
2024-
operandForFullyConvertedCall(address, starCall) and
2025-
bbStar.getInstruction(iStar) = starCall and
2026-
Ssa::ssaDefReachesRead(_, def, bbStar, iStar) and
2027-
ultimate = getAnUltimateDefinition*(def) and
2028-
beginStore = ultimate.getValue().asInstruction() and
2029-
operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)
2043+
exists(Ssa::Definition def |
2044+
fwd(beginCall, def) and
2045+
isSink(writeToDeref, def)
20302046
)
20312047
}
20322048

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,4 +1018,6 @@ module Ssa {
10181018
class IndirectExplicitDefinition = SsaImpl::IndirectExplicitDefinition;
10191019

10201020
class PhiNode = SsaImpl::PhiNode;
1021+
1022+
import SsaImpl::Public
10211023
}

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,14 +1405,96 @@ private class PhiCycle extends PhiCycleEquivalence::EquivalenceClass {
14051405
}
14061406
}
14071407

1408-
/** An static single assignment (SSA) definition. */
1409-
class Definition extends SsaImpl::Definition {
1410-
private Definition getAPhiInputOrPriorDefinition() {
1411-
result = this.(PhiNode).getAnInput()
1412-
or
1413-
uncertainWriteDefinitionInput(this, result)
1408+
private Definition getAPhiInputOrPriorDefinition(Definition def) {
1409+
result = def.(PhiNode).getAnInput()
1410+
or
1411+
uncertainWriteDefinitionInput(def, result)
1412+
}
1413+
1414+
module Public {
1415+
/**
1416+
* A module signature to define relevant ultimate definitions for an
1417+
* optimized version of `Definition.getAnUltimateDefinition`.
1418+
*/
1419+
signature module GetAnUltimateDefinitionSig {
1420+
/**
1421+
* Holds if `def` is a relevant definition. This defines the set
1422+
* of `Definition`s which may be returned by
1423+
* `GetAnUltimateDefinition::getAnUltimateDefinition`.
1424+
*/
1425+
predicate isRelevantUltimateDefinition(Definition def);
1426+
}
1427+
1428+
/**
1429+
* A module which constructs an optimized version of
1430+
* ```
1431+
* Definition.getAnUltimateDefinition
1432+
* ```
1433+
* by restricting the set of possible ultimate definitions.
1434+
*
1435+
* Use this module by defining a module `M` which implements
1436+
* `GetAnUltimateDefinitionSig` and then call:
1437+
* ```
1438+
* GetAnUltimateDefinition<M>::getAnUltimateDefinition
1439+
* ```
1440+
*/
1441+
module GetAnUltimateDefinition<GetAnUltimateDefinitionSig Sig> {
1442+
private import Sig
1443+
1444+
private predicate relevantUltimateDefinition(Definition def) {
1445+
isRelevantUltimateDefinition(def) and
1446+
not def instanceof PhiNode
1447+
}
1448+
1449+
/**
1450+
* The `getAnUltimateDefinition` predicate uses an optimized step relation
1451+
* which is pruned to only those uncertain steps which lead back to a
1452+
* definition which satisfies `relevantUltimateDefinition`. This predicate
1453+
* computes the subset of `Definition`s which can lead back to definitions
1454+
* which satisfy `relevantUltimateDefinition`.
1455+
*/
1456+
private predicate fwd(Definition def) {
1457+
// Base case: This definition is a relevant definition
1458+
relevantUltimateDefinition(def)
1459+
or
1460+
exists(Definition def0 |
1461+
// Recursive case: `def0` is a relevant definition, and
1462+
// `def` is an uncertain step which takes us back to `def0`.
1463+
fwd(def0) and
1464+
def0 = getAPhiInputOrPriorDefinition(def)
1465+
)
1466+
}
1467+
1468+
/**
1469+
* Holds if `def1 = getAPhiInputOrPriorDefinition(def2)`, and
1470+
* both `def1` and `def2` are part of a sequence of uncertain
1471+
* steps which lead back to a `Definition` which
1472+
* satisfies `relevantUltimateDefinition`.
1473+
*/
1474+
private predicate step(Definition def1, Definition def2) {
1475+
fwd(def1) and
1476+
fwd(def2) and
1477+
def1 = getAPhiInputOrPriorDefinition(def2)
1478+
}
1479+
1480+
/**
1481+
* Gets a definition that ultimately defines this SSA definition and is
1482+
* not itself a phi node.
1483+
*
1484+
* This predicate is restricted to ultimate definitions which
1485+
* satisfy `isRelevantUltimateDefinition`.
1486+
*/
1487+
Definition getAnUltimateDefinition(Definition def) {
1488+
step*(result, def) and
1489+
relevantUltimateDefinition(result)
1490+
}
14141491
}
1492+
}
1493+
1494+
import Public
14151495

1496+
/** A static single assignment (SSA) definition. */
1497+
class Definition extends SsaImpl::Definition {
14161498
/**
14171499
* Holds if this SSA definition is live at the end of basic block `bb`.
14181500
* That is, this definition reaches the end of basic block `bb`, at which
@@ -1424,9 +1506,13 @@ class Definition extends SsaImpl::Definition {
14241506
/**
14251507
* Gets a definition that ultimately defines this SSA definition and is
14261508
* not itself a phi node.
1509+
*
1510+
* Note: A more efficient implementation of this predicate exists. See the
1511+
* `GetAnUltimateDefinition` module for a description of how to access
1512+
* the more efficient implementation.
14271513
*/
14281514
final Definition getAnUltimateDefinition() {
1429-
result = this.getAPhiInputOrPriorDefinition*() and
1515+
result = getAPhiInputOrPriorDefinition*(this) and
14301516
not result instanceof PhiNode
14311517
}
14321518

0 commit comments

Comments
 (0)