Skip to content

Commit bf5851f

Browse files
committed
C#: Reduce caching in SsaImplCommon.qll
1 parent 1a507ff commit bf5851f

File tree

3 files changed

+67
-56
lines changed

3 files changed

+67
-56
lines changed

csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,16 @@ module Ssa {
176176
exists(ControlFlow::BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i))
177177
}
178178

179+
/**
180+
* Holds is this SSA definition is live at the end of basic block `bb`.
181+
* That is, this definition reaches the end of basic block `bb`, at which
182+
* point it is still live, without crossing another SSA definition of the
183+
* same source variable.
184+
*/
185+
final predicate isLiveAtEndOfBlock(ControlFlow::BasicBlock bb) {
186+
SsaImpl::isLiveAtEndOfBlock(this, bb)
187+
}
188+
179189
/**
180190
* Gets a read of the source variable underlying this SSA definition that
181191
* can be reached from this SSA definition without passing through any
@@ -233,12 +243,7 @@ module Ssa {
233243
* node between lines 9 and 10.
234244
*/
235245
final AssignableRead getAReadAtNode(ControlFlow::Node cfn) {
236-
exists(SourceVariable v, ControlFlow::BasicBlock bb, int i |
237-
SsaImpl::ssaDefReachesRead(v, this, bb, i) and
238-
SsaImpl::variableReadActual(bb, i, v) and
239-
cfn = bb.getNode(i) and
240-
result.getAControlFlowNode() = cfn
241-
)
246+
result = SsaImpl::getAReadAtNode(this, cfn)
242247
}
243248

244249
/**

csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import SsaImplCommon
88
/**
99
* Holds if the `i`th node of basic block `bb` reads source variable `v`.
1010
*/
11-
predicate variableReadActual(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v) {
11+
private predicate variableReadActual(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v) {
1212
v.getAnAccess().(AssignableRead) = bb.getNode(i).getElement()
1313
}
1414

@@ -1102,6 +1102,11 @@ private module Cached {
11021102
)
11031103
}
11041104

1105+
cached
1106+
predicate isLiveAtEndOfBlock(Definition def, ControlFlow::BasicBlock bb) {
1107+
ssaDefReachesEndOfBlock(bb, def, _)
1108+
}
1109+
11051110
private predicate adjacentDefReaches(
11061111
Definition def, ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2
11071112
) {
@@ -1122,6 +1127,16 @@ private module Cached {
11221127
variableReadActual(bb2, i2, _)
11231128
}
11241129

1130+
cached
1131+
AssignableRead getAReadAtNode(Definition def, ControlFlow::Node cfn) {
1132+
exists(Ssa::SourceVariable v, ControlFlow::BasicBlock bb, int i |
1133+
ssaDefReachesRead(v, def, bb, i) and
1134+
variableReadActual(bb, i, v) and
1135+
cfn = bb.getNode(i) and
1136+
result.getAControlFlowNode() = cfn
1137+
)
1138+
}
1139+
11251140
/**
11261141
* Holds if the value defined at SSA definition `def` can reach a read at `cfn`,
11271142
* without passing through any other read.

csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll

Lines changed: 40 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -174,15 +174,34 @@ private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) {
174174
}
175175

176176
cached
177-
newtype TDefinition =
178-
TWriteDef(SourceVariable v, BasicBlock bb, int i) {
179-
variableWrite(bb, i, v, _) and
180-
liveAfterWrite(bb, i, v)
181-
} or
182-
TPhiNode(SourceVariable v, BasicBlock bb) {
183-
inDefDominanceFrontier(bb, v) and
184-
liveAtEntry(bb, v)
177+
private module Cached {
178+
cached
179+
newtype TDefinition =
180+
TWriteDef(SourceVariable v, BasicBlock bb, int i) {
181+
variableWrite(bb, i, v, _) and
182+
liveAfterWrite(bb, i, v)
183+
} or
184+
TPhiNode(SourceVariable v, BasicBlock bb) {
185+
inDefDominanceFrontier(bb, v) and
186+
liveAtEntry(bb, v)
187+
}
188+
189+
cached
190+
predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) {
191+
lastRefRedef(inp, _, _, def)
192+
}
193+
194+
cached
195+
predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) {
196+
exists(SourceVariable v, BasicBlock bbDef |
197+
phi.definesAt(v, bbDef, _) and
198+
getABasicBlockPredecessor(bbDef) = bb and
199+
ssaDefReachesEndOfBlock(bb, inp, v)
200+
)
185201
}
202+
}
203+
204+
import Cached
186205

187206
private module SsaDefReaches {
188207
newtype TSsaRefKind =
@@ -369,11 +388,12 @@ private predicate ssaDefReachesEndOfBlockRec(BasicBlock bb, Definition def, Sour
369388
}
370389

371390
/**
391+
* NB: If this predicate is exposed, it should be cached.
392+
*
372393
* Holds if the SSA definition of `v` at `def` reaches the end of basic
373394
* block `bb`, at which point it is still live, without crossing another
374395
* SSA definition of `v`.
375396
*/
376-
cached
377397
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
378398
exists(int last | last = maxSsaRefRank(bb, v) |
379399
ssaDefReachesRank(bb, def, last, v) and
@@ -386,11 +406,12 @@ predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable
386406
}
387407

388408
/**
409+
* NB: If this predicate is exposed, it should be cached.
410+
*
389411
* Holds if the SSA definition of `v` at `def` reaches a read at index `i` in
390412
* basic block `bb`, without crossing another SSA definition of `v`. The read
391413
* is of kind `rk`.
392414
*/
393-
cached
394415
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
395416
ssaDefReachesReadWithinBlock(v, def, bb, i)
396417
or
@@ -400,26 +421,12 @@ predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int
400421
}
401422

402423
/**
403-
* Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition
404-
* `redef` without crossing another SSA definition of `v`.
405-
*/
406-
cached
407-
predicate ssaDefReachesUncertainDef(SourceVariable v, Definition def, UncertainWriteDefinition redef) {
408-
ssaDefReachesUncertainDefWithinBlock(v, def, redef)
409-
or
410-
exists(BasicBlock bb |
411-
redef.definesAt(v, bb, _) and
412-
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
413-
not ssaDefReachesUncertainDefWithinBlock(v, _, redef)
414-
)
415-
}
416-
417-
/**
424+
* NB: If this predicate is exposed, it should be cached.
425+
*
418426
* Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read
419427
* or a write), `def` is read at index `i2` in basic block `bb2`, and there is a
420428
* path between them without any read of `def`.
421429
*/
422-
cached
423430
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
424431
exists(int rnk |
425432
rnk = ssaDefRank(def, _, bb1, i1, _) and
@@ -433,11 +440,12 @@ predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2
433440
}
434441

435442
/**
443+
* NB: If this predicate is exposed, it should be cached.
444+
*
436445
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
437446
* `def`. The reference is last because it can reach another write `next`,
438447
* without passing through another read or write.
439448
*/
440-
cached
441449
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
442450
exists(int rnk, SourceVariable v, int j | rnk = ssaDefRank(def, v, bb, i, _) |
443451
// Next reference to `v` inside `bb` is a write
@@ -455,14 +463,15 @@ predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
455463
}
456464

457465
/**
466+
* NB: If this predicate is exposed, it should be cached.
467+
*
458468
* Holds if the node at index `i` in `bb` is a last reference to SSA
459469
* definition `def`.
460470
*
461471
* That is, the node can reach the end of the enclosing callable, or another
462472
* SSA definition for the underlying source variable, without passing through
463473
* another read.
464474
*/
465-
cached
466475
predicate lastRef(Definition def, BasicBlock bb, int i) {
467476
lastRefRedef(def, bb, i, _)
468477
or
@@ -483,14 +492,6 @@ class Definition extends TDefinition {
483492
/** Gets the source variable underlying this SSA definition. */
484493
SourceVariable getSourceVariable() { this.definesAt(result, _, _) }
485494

486-
/**
487-
* Holds is this SSA definition is live at the end of basic block `bb`.
488-
* That is, this definition reaches the end of basic block `bb`, at which
489-
* point it is still live, without crossing another SSA definition of the
490-
* same source variable.
491-
*/
492-
final predicate isLiveAtEndOfBlock(BasicBlock bb) { ssaDefReachesEndOfBlock(bb, this, _) }
493-
494495
/**
495496
* Holds if this SSA definition defines `v` at index `i` in basic block `bb`.
496497
* Phi nodes are considered to be at index `-1`, while normal variable writes
@@ -541,20 +542,10 @@ class WriteDefinition extends Definition, TWriteDef {
541542
/** A phi node. */
542543
class PhiNode extends Definition, TPhiNode {
543544
/** Gets an input of this phi node. */
544-
Definition getAnInput() {
545-
exists(BasicBlock bb, BasicBlock pred, SourceVariable v |
546-
this.definesAt(v, bb, _) and
547-
getABasicBlockPredecessor(bb) = pred and
548-
ssaDefReachesEndOfBlock(pred, result, v)
549-
)
550-
}
545+
Definition getAnInput() { this.hasInputFromBlock(result, _) }
551546

552547
/** Holds if `inp` is an input to the phi node along the edge originating in `bb`. */
553-
predicate hasInputFromBlock(Definition inp, BasicBlock bb) {
554-
inp = this.getAnInput() and
555-
getABasicBlockPredecessor(this.getBasicBlock()) = bb and
556-
ssaDefReachesEndOfBlock(bb, inp, _)
557-
}
548+
predicate hasInputFromBlock(Definition inp, BasicBlock bb) { phiHasInputFromBlock(this, inp, bb) }
558549

559550
override string toString() { result = "Phi" }
560551
}
@@ -575,5 +566,5 @@ class UncertainWriteDefinition extends WriteDefinition {
575566
* Gets the immediately preceding definition. Since this update is uncertain,
576567
* the value from the preceding definition might still be valid.
577568
*/
578-
Definition getPriorDefinition() { ssaDefReachesUncertainDef(_, result, this) }
569+
Definition getPriorDefinition() { uncertainWriteDefinitionInput(this, result) }
579570
}

0 commit comments

Comments
 (0)