@@ -328,6 +328,126 @@ module Make<LocationSig Location, InputSig<Location> Input> {
328328
329329 private class TDefinition = TWriteDef or TPhiNode ;
330330
331+ private module SsaDefReachesNew {
332+ newtype TSsaRefKind =
333+ SsaActualRead ( ) or
334+ SsaPhiRead ( ) or
335+ SsaDef ( )
336+
337+ class SsaRead = SsaActualRead or SsaPhiRead ;
338+
339+ class SsaDefExt = SsaDef or SsaPhiRead ;
340+
341+ SsaDefExt ssaDefExt ( ) { any ( ) }
342+
343+ /**
344+ * A classification of SSA variable references into reads and definitions.
345+ */
346+ class SsaRefKind extends TSsaRefKind {
347+ string toString ( ) {
348+ this = SsaActualRead ( ) and
349+ result = "SsaActualRead"
350+ or
351+ this = SsaPhiRead ( ) and
352+ result = "SsaPhiRead"
353+ or
354+ this = SsaDef ( ) and
355+ result = "SsaDef"
356+ }
357+
358+ int getOrder ( ) {
359+ this instanceof SsaRead and
360+ result = 0
361+ or
362+ this = SsaDef ( ) and
363+ result = 1
364+ }
365+ }
366+
367+ /**
368+ * Holds if the `i`th node of basic block `bb` is a reference to `v`,
369+ * either a read (when `k` is `SsaActualRead()`), an SSA definition (when `k`
370+ * is `SsaDef()`), or a phi-read (when `k` is `SsaPhiRead()`).
371+ *
372+ * Unlike `Liveness::ref`, this includes `phi` (read) nodes.
373+ */
374+ pragma [ nomagic]
375+ predicate ssaRef ( BasicBlock bb , int i , SourceVariable v , SsaRefKind k ) {
376+ variableRead ( bb , i , v , _) and
377+ k = SsaActualRead ( )
378+ or
379+ any ( Definition def ) .definesAt ( v , bb , i ) and
380+ k = SsaDef ( )
381+ or
382+ synthPhiRead ( bb , v ) and i = - 1 and k = SsaPhiRead ( )
383+ }
384+
385+ private newtype OrderedSsaRefIndex =
386+ MkOrderedSsaRefIndex ( int i , SsaRefKind k ) { ssaRef ( _, i , _, k ) }
387+
388+ private OrderedSsaRefIndex ssaRefOrd (
389+ BasicBlock bb , int i , SourceVariable v , SsaRefKind k , int ord
390+ ) {
391+ ssaRef ( bb , i , v , k ) and
392+ result = MkOrderedSsaRefIndex ( i , k ) and
393+ ord = k .getOrder ( )
394+ }
395+
396+ /**
397+ * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic
398+ * block `bb`, which has the given reference kind `k`.
399+ *
400+ * For example, if `bb` is a basic block with a phi node for `v` (considered
401+ * to be at index -1), reads `v` at node 2, and defines it at node 5, we have:
402+ *
403+ * ```ql
404+ * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node
405+ * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2
406+ * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5
407+ * ```
408+ *
409+ * Reads are considered before writes when they happen at the same index.
410+ */
411+ int ssaRefRank ( BasicBlock bb , int i , SourceVariable v , SsaRefKind k ) {
412+ ssaRefOrd ( bb , i , v , k , _) =
413+ rank [ result ] ( int j , int ord , OrderedSsaRefIndex res |
414+ res = ssaRefOrd ( bb , j , v , _, ord )
415+ |
416+ res order by j , ord
417+ )
418+ }
419+
420+ int maxSsaRefRank ( BasicBlock bb , SourceVariable v ) {
421+ result = ssaRefRank ( bb , _, v , _) and
422+ not result + 1 = ssaRefRank ( bb , _, v , _)
423+ }
424+
425+ /**
426+ * Holds if the SSA definition `def` reaches rank index `rnk` in its own
427+ * basic block `bb`.
428+ */
429+ predicate ssaDefReachesRank ( BasicBlock bb , DefinitionExt def , int rnk , SourceVariable v ) {
430+ exists ( int i |
431+ rnk = ssaRefRank ( bb , i , v , ssaDefExt ( ) ) and
432+ def .definesAt ( v , bb , i , _)
433+ )
434+ or
435+ ssaDefReachesRank ( bb , def , rnk - 1 , v ) and
436+ rnk = ssaRefRank ( bb , _, v , SsaActualRead ( ) )
437+ }
438+
439+ /**
440+ * Holds if the SSA definition of `v` at `def` reaches index `i` in the same
441+ * basic block `bb`, without crossing another SSA definition of `v`.
442+ */
443+ predicate ssaDefReachesReadWithinBlock ( SourceVariable v , DefinitionExt def , BasicBlock bb , int i ) {
444+ exists ( int rnk |
445+ ssaDefReachesRank ( bb , def , rnk , v ) and
446+ rnk = ssaRefRank ( bb , i , v , SsaActualRead ( ) )
447+ )
448+ }
449+ }
450+
331451 private module SsaDefReaches {
332452 newtype TSsaRefKind =
333453 SsaActualRead ( ) or
0 commit comments