@@ -194,7 +194,7 @@ private module SsaComputeImpl {
194194 defUseRank ( v , b , rankix , i )
195195 }
196196
197- /** A `VarAccess` `use` of `v` in `b` at index `i`. */
197+ /** A variable access `use` of `v` in `b` at index `i`. */
198198 cached
199199 predicate variableUse ( SsaSourceVariable v , ControlFlowNode use , BasicBlock b , int i ) {
200200 ( v .getAUse ( ) = use or v .hasRefinement ( use , _) ) and
@@ -348,11 +348,147 @@ private module SsaComputeImpl {
348348 )
349349 }
350350 }
351+
352+ cached
353+ module AdjacentUsesImpl {
354+ /**
355+ * Holds if `rankix` is the rank the index `i` at which there is an SSA definition or explicit use of
356+ * `v` in the basic block `b`.
357+ */
358+ cached
359+ predicate defSourceUseRank ( SsaSourceVariable v , BasicBlock b , int rankix , int i ) {
360+ i = rank [ rankix ] ( int j | variableDefine ( v , _, b , j ) or variableSourceUse ( v , _, b , j ) )
361+ }
362+
363+ /** A variable access `use` of `v` in `b` at index `i`. */
364+ cached
365+ predicate variableSourceUse ( SsaSourceVariable v , ControlFlowNode use , BasicBlock b , int i ) {
366+ v .getASourceUse ( ) = use and
367+ exists ( int j |
368+ b .getNode ( j ) = use and
369+ i = 2 * j
370+ )
371+ }
372+
373+ /** Gets the maximum rank index for the given variable and basic block. */
374+ private int lastSourceUseRank ( SsaSourceVariable v , BasicBlock b ) {
375+ result = max ( int rankix | defSourceUseRank ( v , b , rankix , _) )
376+ }
377+
378+ /** Holds if `v` is defined or used in `b`. */
379+ private predicate varOccursInBlock ( SsaSourceVariable v , BasicBlock b ) {
380+ defSourceUseRank ( v , b , _, _)
381+ }
382+
383+ /** Holds if `v` occurs in `b` or one of `b`'s transitive successors. */
384+ private predicate blockPrecedesVar ( SsaSourceVariable v , BasicBlock b ) {
385+ varOccursInBlock ( v , b .getASuccessor * ( ) )
386+ }
387+
388+ /**
389+ * Holds if `b2` is a transitive successor of `b1` and `v` occurs in `b1` and
390+ * in `b2` or one of its transitive successors but not in any block on the path
391+ * between `b1` and `b2`.
392+ */
393+ private predicate varBlockReaches ( SsaSourceVariable v , BasicBlock b1 , BasicBlock b2 ) {
394+ varOccursInBlock ( v , b1 ) and
395+ b2 = b1 .getASuccessor ( ) and
396+ blockPrecedesVar ( v , b2 )
397+ or
398+ exists ( BasicBlock mid |
399+ varBlockReaches ( v , b1 , mid ) and
400+ b2 = mid .getASuccessor ( ) and
401+ not varOccursInBlock ( v , mid ) and
402+ blockPrecedesVar ( v , b2 )
403+ )
404+ }
405+
406+ /**
407+ * Holds if `b2` is a transitive successor of `b1` and `v` occurs in `b1` and
408+ * `b2` but not in any block on the path between `b1` and `b2`.
409+ */
410+ private predicate varBlockStep ( SsaSourceVariable v , BasicBlock b1 , BasicBlock b2 ) {
411+ varBlockReaches ( v , b1 , b2 ) and
412+ varOccursInBlock ( v , b2 )
413+ }
414+
415+ /**
416+ * Holds if `v` occurs at index `i1` in `b1` and at index `i2` in `b2` and
417+ * there is a path between them without any occurrence of `v`.
418+ */
419+ cached
420+ predicate adjacentVarRefs ( SsaSourceVariable v , BasicBlock b1 , int i1 , BasicBlock b2 , int i2 ) {
421+ exists ( int rankix |
422+ b1 = b2 and
423+ defSourceUseRank ( v , b1 , rankix , i1 ) and
424+ defSourceUseRank ( v , b2 , rankix + 1 , i2 )
425+ )
426+ or
427+ defSourceUseRank ( v , b1 , lastSourceUseRank ( v , b1 ) , i1 ) and
428+ varBlockStep ( v , b1 , b2 ) and
429+ defSourceUseRank ( v , b2 , 1 , i2 )
430+ }
431+
432+ /**
433+ * Holds if `use1` and `use2` form an adjacent use-use-pair of the same SSA
434+ * variable, that is, the value read in `use1` can reach `use2` without passing
435+ * through any other use or any SSA definition of the variable.
436+ */
437+ cached
438+ predicate adjacentUseUseSameVar ( ControlFlowNode use1 , ControlFlowNode use2 ) {
439+ exists ( SsaSourceVariable v , BasicBlock b1 , int i1 , BasicBlock b2 , int i2 |
440+ adjacentVarRefs ( v , b1 , i1 , b2 , i2 ) and
441+ variableSourceUse ( v , use1 , b1 , i1 ) and
442+ variableSourceUse ( v , use2 , b2 , i2 )
443+ )
444+ }
445+
446+ /**
447+ * Holds if the value defined at `def` can reach `use` without passing through
448+ * any other uses, but possibly through phi nodes and uncertain implicit updates.
449+ */
450+ cached
451+ predicate firstUse ( EssaDefinition def , ControlFlowNode use ) {
452+ exists ( SsaSourceVariable v , BasicBlock b1 , int i1 , BasicBlock b2 , int i2 |
453+ adjacentVarRefs ( v , b1 , i1 , b2 , i2 ) and
454+ definesAt ( def , v , b1 , i1 ) and
455+ variableSourceUse ( v , use , b2 , i2 )
456+ )
457+ or
458+ exists (
459+ SsaSourceVariable v , EssaDefinition redef , BasicBlock b1 , int i1 , BasicBlock b2 , int i2
460+ |
461+ redef instanceof PhiFunction
462+ |
463+ adjacentVarRefs ( v , b1 , i1 , b2 , i2 ) and
464+ definesAt ( def , v , b1 , i1 ) and
465+ definesAt ( redef , v , b2 , i2 ) and
466+ firstUse ( redef , use )
467+ )
468+ }
469+
470+ /**
471+ * Holds if `def` defines `v` at the specified position.
472+ * Phi nodes are placed at index -1.
473+ */
474+ cached
475+ predicate definesAt ( EssaDefinition def , SsaSourceVariable v , BasicBlock b , int i ) {
476+ exists ( ControlFlowNode defNode |
477+ def .( EssaNodeDefinition ) .definedBy ( v , defNode ) and
478+ variableDefine ( v , defNode , b , i )
479+ )
480+ or
481+ v = def .( PhiFunction ) .getSourceVariable ( ) and
482+ b = def .( PhiFunction ) .getBasicBlock ( ) and
483+ i = - 1
484+ }
485+ }
351486}
352487
353488import SsaComputeImpl:: SsaDefinitionsImpl as SsaDefinitions
354489import SsaComputeImpl:: EssaDefinitionsImpl as EssaDefinitions
355490import SsaComputeImpl:: LivenessImpl as Liveness
491+ import SsaComputeImpl:: AdjacentUsesImpl as AdjacentUses
356492
357493/* This is exported primarily for testing */
358494/*
0 commit comments