@@ -298,9 +298,139 @@ private module SsaImpl {
298298 )
299299 }
300300 }
301+
302+ private module AdjacentUsesImpl {
303+ /**
304+ * Holds if `rankix` is the rank the index `i` at which there is an SSA definition or explicit use of
305+ * `v` in the basic block `b`.
306+ */
307+ private predicate defUseRank ( BaseSsaSourceVariable v , BasicBlock b , int rankix , int i ) {
308+ i = rank [ rankix ] ( int j | any ( TrackedSsaDef def ) .definesAt ( v , b , j ) or variableUse ( v , _, b , j ) )
309+ }
310+
311+ /** Gets the maximum rank index for the given variable and basic block. */
312+ private int lastRank ( BaseSsaSourceVariable v , BasicBlock b ) {
313+ result = max ( int rankix | defUseRank ( v , b , rankix , _) )
314+ }
315+
316+ /** Holds if `v` is defined or used in `b`. */
317+ private predicate varOccursInBlock ( BaseSsaSourceVariable v , BasicBlock b ) {
318+ defUseRank ( v , b , _, _)
319+ }
320+
321+ /** Holds if `v` occurs in `b` or one of `b`'s transitive successors. */
322+ private predicate blockPrecedesVar ( BaseSsaSourceVariable v , BasicBlock b ) {
323+ varOccursInBlock ( v , b .getABBSuccessor * ( ) )
324+ }
325+
326+ /**
327+ * Holds if `b2` is a transitive successor of `b1` and `v` occurs in `b1` and
328+ * in `b2` or one of its transitive successors but not in any block on the path
329+ * between `b1` and `b2`.
330+ */
331+ private predicate varBlockReaches ( BaseSsaSourceVariable v , BasicBlock b1 , BasicBlock b2 ) {
332+ varOccursInBlock ( v , b1 ) and b2 = b1 .getABBSuccessor ( )
333+ or
334+ exists ( BasicBlock mid |
335+ varBlockReaches ( v , b1 , mid ) and
336+ b2 = mid .getABBSuccessor ( ) and
337+ not varOccursInBlock ( v , mid ) and
338+ blockPrecedesVar ( v , b2 )
339+ )
340+ }
341+
342+ /**
343+ * Holds if `b2` is a transitive successor of `b1` and `v` occurs in `b1` and
344+ * `b2` but not in any block on the path between `b1` and `b2`.
345+ */
346+ private predicate varBlockStep ( BaseSsaSourceVariable v , BasicBlock b1 , BasicBlock b2 ) {
347+ varBlockReaches ( v , b1 , b2 ) and
348+ varOccursInBlock ( v , b2 )
349+ }
350+
351+ /**
352+ * Holds if `v` occurs at index `i1` in `b1` and at index `i2` in `b2` and
353+ * there is a path between them without any occurrence of `v`.
354+ */
355+ predicate adjacentVarRefs ( BaseSsaSourceVariable v , BasicBlock b1 , int i1 , BasicBlock b2 , int i2 ) {
356+ exists ( int rankix |
357+ b1 = b2 and
358+ defUseRank ( v , b1 , rankix , i1 ) and
359+ defUseRank ( v , b2 , rankix + 1 , i2 )
360+ )
361+ or
362+ defUseRank ( v , b1 , lastRank ( v , b1 ) , i1 ) and
363+ varBlockStep ( v , b1 , b2 ) and
364+ defUseRank ( v , b2 , 1 , i2 )
365+ }
366+ }
367+ private import AdjacentUsesImpl
368+
369+ /**
370+ * Holds if the value defined at `def` can reach `use` without passing through
371+ * any other uses, but possibly through phi nodes.
372+ */
373+ cached
374+ predicate firstUse ( TrackedSsaDef def , RValue use ) {
375+ exists ( BaseSsaSourceVariable v , BasicBlock b1 , int i1 , BasicBlock b2 , int i2 |
376+ adjacentVarRefs ( v , b1 , i1 , b2 , i2 ) and
377+ def .definesAt ( v , b1 , i1 ) and
378+ variableUse ( v , use , b2 , i2 )
379+ )
380+ or
381+ exists (
382+ BaseSsaSourceVariable v , TrackedSsaDef redef , BasicBlock b1 , int i1 , BasicBlock b2 , int i2
383+ |
384+ redef instanceof BaseSsaPhiNode
385+ |
386+ adjacentVarRefs ( v , b1 , i1 , b2 , i2 ) and
387+ def .definesAt ( v , b1 , i1 ) and
388+ redef .definesAt ( v , b2 , i2 ) and
389+ firstUse ( redef , use )
390+ )
391+ }
392+
393+ cached
394+ module SsaPublic {
395+ /**
396+ * Holds if `use1` and `use2` form an adjacent use-use-pair of the same SSA
397+ * variable, that is, the value read in `use1` can reach `use2` without passing
398+ * through any other use or any SSA definition of the variable.
399+ */
400+ cached
401+ predicate baseSsaAdjacentUseUseSameVar ( RValue use1 , RValue use2 ) {
402+ exists ( BaseSsaSourceVariable v , BasicBlock b1 , int i1 , BasicBlock b2 , int i2 |
403+ adjacentVarRefs ( v , b1 , i1 , b2 , i2 ) and
404+ variableUse ( v , use1 , b1 , i1 ) and
405+ variableUse ( v , use2 , b2 , i2 )
406+ )
407+ }
408+
409+ /**
410+ * Holds if `use1` and `use2` form an adjacent use-use-pair of the same
411+ * `SsaSourceVariable`, that is, the value read in `use1` can reach `use2`
412+ * without passing through any other use or any SSA definition of the variable
413+ * except for phi nodes.
414+ */
415+ cached
416+ predicate baseSsaAdjacentUseUse ( RValue use1 , RValue use2 ) {
417+ baseSsaAdjacentUseUseSameVar ( use1 , use2 )
418+ or
419+ exists (
420+ BaseSsaSourceVariable v , TrackedSsaDef def , BasicBlock b1 , int i1 , BasicBlock b2 , int i2
421+ |
422+ adjacentVarRefs ( v , b1 , i1 , b2 , i2 ) and
423+ variableUse ( v , use1 , b1 , i1 ) and
424+ def .definesAt ( v , b2 , i2 ) and
425+ firstUse ( def , use2 ) and
426+ def instanceof BaseSsaPhiNode
427+ )
428+ }
429+ }
301430}
302431private import SsaImpl
303432private import SsaDefReaches
433+ import SsaPublic
304434
305435private newtype TBaseSsaVariable =
306436 TSsaPhiNode ( BaseSsaSourceVariable v , BasicBlock b ) { phiNode ( v , b ) } or
@@ -354,6 +484,16 @@ class BaseSsaVariable extends TBaseSsaVariable {
354484 /** Gets an access of this SSA variable. */
355485 RValue getAUse ( ) { ssaDefReachesUse ( _, this , result ) }
356486
487+ /**
488+ * Gets an access of the SSA source variable underlying this SSA variable
489+ * that can be reached from this SSA variable without passing through any
490+ * other uses, but potentially through phi nodes.
491+ *
492+ * Subsequent uses can be found by following the steps defined by
493+ * `baseSsaAdjacentUseUse`.
494+ */
495+ RValue getAFirstUse ( ) { firstUse ( this , result ) }
496+
357497 /** Holds if this SSA variable is live at the end of `b`. */
358498 predicate isLiveAtEndOfBlock ( BasicBlock b ) { ssaDefReachesEndOfBlock ( _, this , b ) }
359499
0 commit comments