Skip to content

Commit 286db27

Browse files
committed
Go: Only compute most recent side effect for relevant nodes
1 parent c64223a commit 286db27

1 file changed

Lines changed: 94 additions & 64 deletions

File tree

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

Lines changed: 94 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -132,62 +132,75 @@ private predicate sideEffectCfg(ControlFlow::Node src, ControlFlow::Node dst) {
132132
private predicate iDomEffect(ControlFlow::Node dominator, ControlFlow::Node node) =
133133
idominance(entryNode/1, sideEffectCfg/2)(_, dominator, node)
134134

135-
/**
136-
* Gets the most recent side effect. To be more precise, `result` is a
137-
* dominator of `node` and no side-effects can occur between `result` and
138-
* `node`.
139-
*
140-
* `sideEffectCFG` has an edge from the function entry to every node with a
141-
* side-effect. This means that every node with a side-effect has the
142-
* function entry as its immediate dominator. So if node `x` dominates node
143-
* `y` then there can be no side effects between `x` and `y` unless `x` is
144-
* the function entry. So the optimal choice for `result` has the function
145-
* entry as its immediate dominator.
146-
*
147-
* Example:
148-
*
149-
* ```
150-
* 000: int f(int a, int b, int *p) {
151-
* 001: int r = 0;
152-
* 002: if (a) {
153-
* 003: if (b) {
154-
* 004: sideEffect1();
155-
* 005: }
156-
* 006: } else {
157-
* 007: sideEffect2();
158-
* 008: }
159-
* 009: if (a) {
160-
* 010: r++; // Not a side-effect, because r is an SSA variable.
161-
* 011: }
162-
* 012: if (b) {
163-
* 013: r++; // Not a side-effect, because r is an SSA variable.
164-
* 014: }
165-
* 015: return *p;
166-
* 016: }
167-
* ```
168-
*
169-
* Suppose we want to find the most recent side-effect for the dereference
170-
* of `p` on line 015. The `sideEffectCFG` has an edge from the function
171-
* entry (line 000) to the side effects at lines 004 and 007. Therefore,
172-
* the immediate dominator tree looks like this:
173-
*
174-
* 000 - 001 - 002 - 003
175-
* - 004
176-
* - 007
177-
* - 009 - 010
178-
* - 012 - 013
179-
* - 015
180-
*
181-
* The immediate dominator path to line 015 is 000 - 009 - 012 - 015.
182-
* Therefore, the most recent side effect for line 015 is line 009.
183-
*/
184-
cached
185-
private ControlFlow::Node mostRecentSideEffect(ControlFlow::Node node) {
186-
exists(ControlFlow::Node entry |
187-
entryNode(entry) and
188-
iDomEffect(entry, result) and
189-
iDomEffect*(result, node)
190-
)
135+
private signature predicate relevantNodeSig(ControlFlow::Node n);
136+
137+
private module MostRecentSideEffect<relevantNodeSig/1 relevantNode> {
138+
private predicate iDomEntry(ControlFlow::Node node) {
139+
exists(ControlFlow::Node entry |
140+
entryNode(entry) and
141+
iDomEffect(entry, node)
142+
)
143+
}
144+
145+
private predicate iDomEffectPlus(ControlFlow::Node n1, ControlFlow::Node n2) =
146+
doublyBoundedFastTC(iDomEffect/2, iDomEntry/1, relevantNode/1)(n1, n2)
147+
148+
/**
149+
* Gets the most recent side effect. To be more precise, `result` is a
150+
* dominator of `node` and no side-effects can occur between `result` and
151+
* `node`.
152+
*
153+
* `sideEffectCFG` has an edge from the function entry to every node with a
154+
* side-effect. This means that every node with a side-effect has the
155+
* function entry as its immediate dominator. So if node `x` dominates node
156+
* `y` then there can be no side effects between `x` and `y` unless `x` is
157+
* the function entry. So the optimal choice for `result` has the function
158+
* entry as its immediate dominator.
159+
*
160+
* Example:
161+
*
162+
* ```
163+
* 000: int f(int a, int b, int *p) {
164+
* 001: int r = 0;
165+
* 002: if (a) {
166+
* 003: if (b) {
167+
* 004: sideEffect1();
168+
* 005: }
169+
* 006: } else {
170+
* 007: sideEffect2();
171+
* 008: }
172+
* 009: if (a) {
173+
* 010: r++; // Not a side-effect, because r is an SSA variable.
174+
* 011: }
175+
* 012: if (b) {
176+
* 013: r++; // Not a side-effect, because r is an SSA variable.
177+
* 014: }
178+
* 015: return *p;
179+
* 016: }
180+
* ```
181+
*
182+
* Suppose we want to find the most recent side-effect for the dereference
183+
* of `p` on line 015. The `sideEffectCFG` has an edge from the function
184+
* entry (line 000) to the side effects at lines 004 and 007. Therefore,
185+
* the immediate dominator tree looks like this:
186+
*
187+
* 000 - 001 - 002 - 003
188+
* - 004
189+
* - 007
190+
* - 009 - 010
191+
* - 012 - 013
192+
* - 015
193+
*
194+
* The immediate dominator path to line 015 is 000 - 009 - 012 - 015.
195+
* Therefore, the most recent side effect for line 015 is line 009.
196+
*/
197+
ControlFlow::Node mostRecentSideEffect(ControlFlow::Node node) {
198+
iDomEntry(node) and
199+
result = node and
200+
relevantNode(node)
201+
or
202+
iDomEffectPlus(result, node)
203+
}
191204
}
192205

193206
/** Used to represent the "global value number" of an expression. */
@@ -369,10 +382,12 @@ private predicate mkMethodAccess(DataFlow::Node access, GVN qualifier, Method m)
369382
)
370383
}
371384

385+
private predicate isReadInstruction(ControlFlow::Node node) { node instanceof IR::ReadInstruction }
386+
372387
private predicate analyzableFieldRead(Read fread, DataFlow::Node base, Field f) {
373388
exists(IR::ReadInstruction r | r = fread.asInstruction() |
374389
r.readsField(base.asInstruction(), f) and
375-
strictcount(mostRecentSideEffect(r)) = 1 and
390+
strictcount(MostRecentSideEffect<isReadInstruction/1>::mostRecentSideEffect(r)) = 1 and
376391
not r.isConst()
377392
)
378393
}
@@ -383,7 +398,8 @@ private predicate mkFieldRead(
383398
exists(DataFlow::Node base |
384399
analyzableFieldRead(fread, base, v) and
385400
qualifier = globalValueNumber(base) and
386-
dominator = mostRecentSideEffect(fread.asInstruction())
401+
dominator =
402+
MostRecentSideEffect<isReadInstruction/1>::mostRecentSideEffect(fread.asInstruction())
387403
)
388404
}
389405

@@ -418,20 +434,23 @@ private predicate incompleteSsa(ValueEntity v) {
418434
)
419435
}
420436

437+
private predicate instructionReads(ControlFlow::Node node) { node.(IR::Instruction).reads(_) }
438+
421439
/**
422440
* Holds if `access` is an access to a variable `target` for which SSA information is incomplete.
423441
*/
424442
private predicate analyzableOtherVariable(DataFlow::Node access, ValueEntity target) {
425443
access.asInstruction().reads(target) and
426444
incompleteSsa(target) and
427-
strictcount(mostRecentSideEffect(access.asInstruction())) = 1 and
445+
strictcount(MostRecentSideEffect<instructionReads/1>::mostRecentSideEffect(access.asInstruction())) =
446+
1 and
428447
not access.isConst() and
429448
not target instanceof Function
430449
}
431450

432451
private predicate mkOtherVariable(DataFlow::Node access, ValueEntity x, ControlFlow::Node dominator) {
433452
analyzableOtherVariable(access, x) and
434-
dominator = mostRecentSideEffect(access.asInstruction())
453+
dominator = MostRecentSideEffect<instructionReads/1>::mostRecentSideEffect(access.asInstruction())
435454
}
436455

437456
private predicate analyzableBinaryOp(
@@ -463,8 +482,12 @@ private predicate mkUnaryOp(DataFlow::UnaryOperationNode op, GVN child, string o
463482
opname = op.getOperator()
464483
}
465484

485+
private predicate isElementRead(ControlFlow::Node node) {
486+
node instanceof IR::ElementReadInstruction
487+
}
488+
466489
private predicate analyzableIndexExpr(DataFlow::ElementReadNode ae) {
467-
strictcount(mostRecentSideEffect(ae.asInstruction())) = 1 and
490+
strictcount(MostRecentSideEffect<isElementRead/1>::mostRecentSideEffect(ae.asInstruction())) = 1 and
468491
not ae.isConst()
469492
}
470493

@@ -474,18 +497,25 @@ private predicate mkIndex(
474497
analyzableIndexExpr(ae) and
475498
base = globalValueNumber(ae.getBase()) and
476499
offset = globalValueNumber(ae.getIndex()) and
477-
dominator = mostRecentSideEffect(ae.asInstruction())
500+
dominator = MostRecentSideEffect<isElementRead/1>::mostRecentSideEffect(ae.asInstruction())
501+
}
502+
503+
private predicate isPointerDereference(ControlFlow::Node node) {
504+
node instanceof IR::EvalImplicitDerefInstruction
478505
}
479506

480507
private predicate analyzablePointerDereferenceExpr(DataFlow::PointerDereferenceNode deref) {
481-
strictcount(mostRecentSideEffect(deref.asInstruction())) = 1 and
508+
strictcount(MostRecentSideEffect<isPointerDereference/1>::mostRecentSideEffect(deref
509+
.asInstruction())
510+
) = 1 and
482511
not deref.isConst()
483512
}
484513

485514
private predicate mkDeref(DataFlow::PointerDereferenceNode deref, GVN p, ControlFlow::Node dominator) {
486515
analyzablePointerDereferenceExpr(deref) and
487516
p = globalValueNumber(deref.getOperand()) and
488-
dominator = mostRecentSideEffect(deref.asInstruction())
517+
dominator =
518+
MostRecentSideEffect<isPointerDereference/1>::mostRecentSideEffect(deref.asInstruction())
489519
}
490520

491521
private predicate ssaInit(SsaExplicitDefinition ssa, DataFlow::Node rhs) {

0 commit comments

Comments
 (0)