Skip to content

Commit 521b971

Browse files
committed
Base SSA classes on shared SSA library
1 parent 5bc4ccf commit 521b971

File tree

2 files changed

+37
-141
lines changed

2 files changed

+37
-141
lines changed

go/ql/lib/semmle/go/dataflow/SSA.qll

+26-55
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ private predicate unresolvedIdentifier(Ident id, string name) {
6161
/**
6262
* An SSA variable.
6363
*/
64-
class SsaVariable extends TSsaDefinition {
64+
class SsaVariable instanceof SsaDefinition {
6565
/** Gets the source variable corresponding to this SSA variable. */
6666
SsaSourceVariable getSourceVariable() { result = this.(SsaDefinition).getSourceVariable() }
6767

@@ -107,27 +107,26 @@ class SsaVariable extends TSsaDefinition {
107107
/**
108108
* An SSA definition.
109109
*/
110-
class SsaDefinition extends TSsaDefinition {
110+
class SsaDefinition instanceof ZZZDefinition {
111+
/**
112+
* Holds if this SSA definition defines `v` at index `i` in basic block `bb`.
113+
* Phi nodes are considered to be at index `-1`, while normal variable writes
114+
* are at the index of the control flow node they wrap.
115+
*/
116+
predicate definesAt(SsaSourceVariable v, BasicBlock bb, int i) {
117+
this.(ZZZDefinition).definesAt(v, bb, i)
118+
}
119+
111120
/** Gets the SSA variable defined by this definition. */
112121
SsaVariable getVariable() { result = this }
113122

114123
/** Gets the source variable defined by this definition. */
115-
abstract SsaSourceVariable getSourceVariable();
124+
SsaSourceVariable getSourceVariable() { this.definesAt(result, _, _) }
116125

117126
/**
118127
* Gets the basic block to which this definition belongs.
119128
*/
120-
abstract ReachableBasicBlock getBasicBlock();
121-
122-
/**
123-
* INTERNAL: Use `getBasicBlock()` and `getSourceVariable()` instead.
124-
*
125-
* Holds if this is a definition of source variable `v` at index `idx` in basic block `bb`.
126-
*
127-
* Phi nodes are considered to be at index `-1`, all other definitions at the index of
128-
* the control flow node they correspond to.
129-
*/
130-
abstract predicate definesAt(SsaSourceVariable v, ReachableBasicBlock bb, int idx);
129+
ReachableBasicBlock getBasicBlock() { this.definesAt(_, result, _) }
131130

132131
/**
133132
* INTERNAL: Use `toString()` instead.
@@ -146,12 +145,12 @@ class SsaDefinition extends TSsaDefinition {
146145
/** Gets the innermost function or file to which this SSA definition belongs. */
147146
ControlFlow::Root getRoot() { result = this.getBasicBlock().getRoot() }
148147

148+
/** Gets the location of this SSA definition. */
149+
Location getLocation() { result = this.(ZZZDefinition).getLocation() }
150+
149151
/** Gets a textual representation of this element. */
150152
string toString() { result = this.prettyPrintDef() }
151153

152-
/** Gets the source location for this element. */
153-
abstract Location getLocation();
154-
155154
/**
156155
* DEPRECATED: Use `getLocation()` instead.
157156
*
@@ -178,32 +177,24 @@ class SsaDefinition extends TSsaDefinition {
178177
/**
179178
* An SSA definition that corresponds to an explicit assignment or other variable definition.
180179
*/
181-
class SsaExplicitDefinition extends SsaDefinition, TExplicitDef {
180+
class SsaExplicitDefinition extends SsaDefinition {
181+
SsaExplicitDefinition() { not this instanceof SsaImplicitDefinition }
182+
182183
/** Gets the instruction where the definition happens. */
183184
IR::Instruction getInstruction() {
184-
exists(BasicBlock bb, int i | this = TExplicitDef(bb, i, _) | result = bb.getNode(i))
185+
exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i))
185186
}
186187

187188
/** Gets the right-hand side of the definition. */
188189
IR::Instruction getRhs() { this.getInstruction().writes(_, result) }
189190

190-
override predicate definesAt(SsaSourceVariable v, ReachableBasicBlock bb, int i) {
191-
this = TExplicitDef(bb, i, v)
192-
}
193-
194-
override ReachableBasicBlock getBasicBlock() { this.definesAt(_, result, _) }
195-
196-
override SsaSourceVariable getSourceVariable() { this.definesAt(result, _, _) }
197-
198191
override string prettyPrintRef() {
199192
exists(Location loc | loc = this.getLocation() |
200193
result = "def@" + loc.getStartLine() + ":" + loc.getStartColumn()
201194
)
202195
}
203196

204197
override string prettyPrintDef() { result = "definition of " + this.getSourceVariable() }
205-
206-
override Location getLocation() { result = this.getInstruction().getLocation() }
207198
}
208199

209200
/** Provides a helper predicate for working with explicit SSA definitions. */
@@ -230,8 +221,6 @@ abstract class SsaImplicitDefinition extends SsaDefinition {
230221
result = this.getKind() + "@" + loc.getStartLine() + ":" + loc.getStartColumn()
231222
)
232223
}
233-
234-
override Location getLocation() { result = this.getBasicBlock().getLocation() }
235224
}
236225

237226
/**
@@ -241,24 +230,16 @@ abstract class SsaImplicitDefinition extends SsaDefinition {
241230
* Capturing definitions appear at the beginning of such functions, as well as
242231
* at any function call that may affect the value of the variable.
243232
*/
244-
class SsaVariableCapture extends SsaImplicitDefinition, TCapture {
245-
override predicate definesAt(SsaSourceVariable v, ReachableBasicBlock bb, int i) {
246-
this = TCapture(bb, i, v)
233+
class SsaVariableCapture extends SsaImplicitDefinition {
234+
SsaVariableCapture() {
235+
exists(BasicBlock bb, int i, SsaSourceVariable v | this.definesAt(v, bb, i) |
236+
mayCapture(bb, i, v)
237+
)
247238
}
248239

249-
override ReachableBasicBlock getBasicBlock() { this.definesAt(_, result, _) }
250-
251-
override SsaSourceVariable getSourceVariable() { this.definesAt(result, _, _) }
252-
253240
override string getKind() { result = "capture" }
254241

255242
override string prettyPrintDef() { result = "capture variable " + this.getSourceVariable() }
256-
257-
override Location getLocation() {
258-
exists(ReachableBasicBlock bb, int i | this.definesAt(_, bb, i) |
259-
result = bb.getNode(i).getLocation()
260-
)
261-
}
262243
}
263244

264245
/**
@@ -283,26 +264,16 @@ abstract class SsaPseudoDefinition extends SsaImplicitDefinition {
283264
* in the flow graph where otherwise two or more definitions for the variable
284265
* would be visible.
285266
*/
286-
class SsaPhiNode extends SsaPseudoDefinition, TPhi {
267+
class SsaPhiNode extends SsaPseudoDefinition instanceof ZZZPhiNode {
287268
override SsaVariable getAnInput() {
288269
result = getDefReachingEndOf(this.getBasicBlock().getAPredecessor(), this.getSourceVariable())
289270
}
290271

291-
override predicate definesAt(SsaSourceVariable v, ReachableBasicBlock bb, int i) {
292-
bb = this.getBasicBlock() and v = this.getSourceVariable() and i = -1
293-
}
294-
295-
override ReachableBasicBlock getBasicBlock() { this = TPhi(result, _) }
296-
297-
override SsaSourceVariable getSourceVariable() { this = TPhi(_, result) }
298-
299272
override string getKind() { result = "phi" }
300273

301274
override string prettyPrintDef() {
302275
result = this.getSourceVariable() + " = phi(" + this.ppInputs() + ")"
303276
}
304-
305-
override Location getLocation() { result = this.getBasicBlock().getLocation() }
306277
}
307278

308279
/**

go/ql/lib/semmle/go/dataflow/SsaImpl.qll

+11-86
Original file line numberDiff line numberDiff line change
@@ -21,61 +21,6 @@ private module Internal {
2121
bb.getNode(i).(IR::Instruction).reads(v)
2222
}
2323

24-
/**
25-
* A data type representing SSA definitions.
26-
*
27-
* We distinguish three kinds of SSA definitions:
28-
*
29-
* 1. Variable definitions, including declarations, assignments and increments/decrements.
30-
* 2. Pseudo-definitions for captured variables at the beginning of the capturing function
31-
* as well as after calls.
32-
* 3. Phi nodes.
33-
*
34-
* SSA definitions are only introduced where necessary. In particular,
35-
* unreachable code has no SSA definitions associated with it, and neither
36-
* have dead assignments (that is, assignments whose value is never read).
37-
*/
38-
cached
39-
newtype TSsaDefinition =
40-
/**
41-
* An SSA definition that corresponds to an explicit assignment or other variable definition.
42-
*/
43-
TExplicitDef(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
44-
defAt(bb, i, v) and
45-
(liveAfterDef(bb, i, v) or v.isCaptured())
46-
} or
47-
/**
48-
* An SSA definition representing the capturing of an SSA-convertible variable
49-
* in the closure of a nested function.
50-
*
51-
* Capturing definitions appear at the beginning of such functions, as well as
52-
* at any function call that may affect the value of the variable.
53-
*/
54-
TCapture(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
55-
mayCapture(bb, i, v) and
56-
liveAfterDef(bb, i, v)
57-
} or
58-
/**
59-
* An SSA phi node, that is, a pseudo-definition for a variable at a point
60-
* in the flow graph where otherwise two or more definitions for the variable
61-
* would be visible.
62-
*/
63-
TPhi(ReachableJoinBlock bb, SsaSourceVariable v) {
64-
liveAtEntry(bb, v) and
65-
inDefDominanceFrontier(bb, v)
66-
}
67-
68-
/**
69-
* Holds if `bb` is in the dominance frontier of a block containing a definition of `v`.
70-
*/
71-
pragma[noinline]
72-
private predicate inDefDominanceFrontier(ReachableJoinBlock bb, SsaSourceVariable v) {
73-
exists(ReachableBasicBlock defbb, SsaDefinition def |
74-
def.definesAt(v, defbb, _) and
75-
bb.inDominanceFrontierOf(defbb)
76-
)
77-
}
78-
7924
/**
8025
* Holds if `v` is a captured variable which is declared in `declFun` and read in `useFun`.
8126
*/
@@ -104,7 +49,8 @@ private module Internal {
10449
* modeling updates to captured variable `v`. Whether the definition is actually
10550
* introduced depends on whether `v` is live at this point in the program.
10651
*/
107-
private predicate mayCapture(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
52+
cached
53+
predicate mayCapture(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
10854
exists(FuncDef capturingContainer, FuncDef declContainer |
10955
// capture initial value of variable declared in enclosing scope
11056
readsCapturedVar(capturingContainer, v, declContainer) and
@@ -143,31 +89,6 @@ private module Internal {
14389
ref(bb, i, v, tp)
14490
}
14591

146-
/**
147-
* Gets the maximum rank among all references to `v` in basic block `bb`.
148-
*/
149-
private int maxRefRank(ReachableBasicBlock bb, SsaSourceVariable v) {
150-
result = max(refRank(bb, _, v, _))
151-
}
152-
153-
/**
154-
* Holds if variable `v` is live after the `i`th node of basic block `bb`, where
155-
* `i` is the index of a node that may assign or capture `v`.
156-
*
157-
* For the purposes of this predicate, function calls are considered as writes of captured variables.
158-
*/
159-
private predicate liveAfterDef(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
160-
exists(int r | r = refRank(bb, i, v, WriteRef()) |
161-
// the next reference to `v` inside `bb` is a read
162-
r + 1 = refRank(bb, _, v, ReadRef())
163-
or
164-
// this is the last reference to `v` inside `bb`, but `v` is live at entry
165-
// to a successor basic block of `bb`
166-
r = maxRefRank(bb, v) and
167-
liveAtSuccEntry(bb, v)
168-
)
169-
}
170-
17192
/**
17293
* Holds if variable `v` is live at the beginning of basic block `bb`.
17394
*
@@ -486,6 +407,8 @@ private module Internal {
486407
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
487408
defAt(bb, i, v) and
488409
certain = true
410+
or
411+
mayCapture(bb, i, v) and certain = true
489412
}
490413

491414
/**
@@ -496,19 +419,21 @@ private module Internal {
496419
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
497420
useAt(bb, i, v) and certain = true
498421
or
499-
mayCapture(bb, i, v) and certain = false
422+
mayCapture(bb, i, v) and certain = true
500423
}
501424
}
502425

503426
import SsaImplCommon::Make<Location, SsaInput> as Impl
504427

505-
final class SsaInputDefinition = Impl::Definition;
428+
final class ZZZDefinition = Impl::Definition;
506429

507-
final class SsaInputWriteDefinition = Impl::WriteDefinition;
430+
final class ZZZWriteDefinition = Impl::WriteDefinition;
508431

509-
final class SsaInputUncertainWriteDefinition = Impl::UncertainWriteDefinition;
432+
final class ZZZUncertainWriteDefinition = Impl::UncertainWriteDefinition;
510433

511-
final class SsaInputPhiNode = Impl::PhiNode;
434+
final class ZZZPhiNode = Impl::PhiNode;
512435
}
513436

514437
import Internal
438+
439+
predicate captures = Internal::mayCapture/3;

0 commit comments

Comments
 (0)