@@ -174,15 +174,34 @@ private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) {
174174}
175175
176176cached
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
187206private 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
377397predicate 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
394415predicate 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
423430predicate 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
441449predicate 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
466475predicate 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. */
542543class 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