@@ -760,16 +760,16 @@ module Ssa {
760760
761761 private cached module Cached {
762762 /**
763- * Holds if `read ` is a last read of the non-trivial SSA definition `def`.
764- * That is, `read ` can reach the end of the enclosing callable, or another
763+ * Holds if `cfn ` is a last read of the non-trivial SSA definition `def`.
764+ * That is, `cfn ` can reach the end of the enclosing callable, or another
765765 * SSA definition for the underlying source variable, without passing through
766766 * another read.
767767 */
768768 cached
769- predicate lastRead ( TrackedDefinition def , AssignableRead read ) {
769+ predicate lastRead ( TrackedDefinition def , ControlFlow :: Node cfn ) {
770770 exists ( TrackedVar v , BasicBlock bb , int i , int rnk |
771- read = def .getARead ( ) and
772- variableRead ( bb , i , v , read . getAControlFlowNode ( ) , _) and
771+ exists ( def .getAReadAtNode ( cfn ) ) and
772+ variableRead ( bb , i , v , cfn , _) and
773773 rnk = ssaRefRank ( bb , i , v , SsaRead ( ) ) |
774774 // Next reference to `v` inside `bb` is a write
775775 rnk + 1 = ssaRefRank ( bb , _, v , SsaDef ( ) )
@@ -854,27 +854,29 @@ module Ssa {
854854 }
855855
856856 /**
857- * Holds if the value defined at non-trivial SSA definition `def` can reach `read`
858- * without passing through any other read.
857+ * Holds if the value defined at non-trivial SSA definition `def` can reach a
858+ * read at `cfn`, without passing through any other read.
859859 */
860860 cached
861- predicate firstReadSameVar ( TrackedDefinition def , AssignableRead read ) {
861+ predicate firstReadSameVar ( TrackedDefinition def , ControlFlow :: Node cfn ) {
862862 exists ( TrackedVar v , BasicBlock b1 , int i1 , BasicBlock b2 , int i2 |
863863 adjacentVarRefs ( v , b1 , i1 , b2 , i2 ) and
864864 definesAt ( def , b1 , i1 , v ) and
865- variableRead ( b2 , i2 , v , read . getAControlFlowNode ( ) , _)
865+ variableRead ( b2 , i2 , v , cfn , _)
866866 )
867867 }
868868
869869 /**
870- * INTERNAL: Use `AssignableRead.getANextRead()` instead.
870+ * Holds if the read at `cfn2` is a read of the same SSA definition as the
871+ * read at `cfn1`, and `cfn2` can be reached from `cfn1` without passing
872+ * through another read.
871873 */
872874 cached
873- predicate adjacentReadPairSameVar ( AssignableRead read1 , AssignableRead read2 ) {
875+ predicate adjacentReadPairSameVar ( ControlFlow :: Node cfn1 , ControlFlow :: Node cfn2 ) {
874876 exists ( TrackedVar v , BasicBlock bb1 , int i1 , BasicBlock bb2 , int i2 |
875877 adjacentVarRefs ( v , bb1 , i1 , bb2 , i2 ) and
876- variableRead ( bb1 , i1 , v , read1 . getAControlFlowNode ( ) , _) and
877- variableRead ( bb2 , i2 , v , read2 . getAControlFlowNode ( ) , _)
878+ variableRead ( bb1 , i1 , v , cfn1 , _) and
879+ variableRead ( bb2 , i2 , v , cfn2 , _)
878880 )
879881 }
880882 }
@@ -2074,8 +2076,45 @@ module Ssa {
20742076 * Subsequent reads can be found by following the steps defined by
20752077 * `AssignableRead.getANextRead()`.
20762078 */
2077- AssignableRead getAFirstRead ( ) {
2078- firstReadSameVar ( this , result )
2079+ AssignableRead getAFirstRead ( ) { result = this .getAFirstReadAtNode ( _) }
2080+
2081+ /**
2082+ * Gets a read of the source variable underlying this SSA definition at
2083+ * control flow node `cfn` that can be reached from this SSA definition
2084+ * without passing through any other SSA definition or read. Example:
2085+ *
2086+ * ```
2087+ * int Field;
2088+ *
2089+ * void SetField(int i) {
2090+ * this.Field = i;
2091+ * Use(this.Field);
2092+ * if (i > 0)
2093+ * this.Field = i - 1;
2094+ * else if (i < 0)
2095+ * SetField(1);
2096+ * Use(this.Field);
2097+ * Use(this.Field);
2098+ * }
2099+ * ```
2100+ *
2101+ * - The read of `i` on line 4 can be reached from the explicit SSA
2102+ * definition (wrapping an implicit entry definition) on line 3.
2103+ * - The reads of `i` on lines 6 and 7 are not the first reads of any SSA
2104+ * definition.
2105+ * - The read of `this.Field` on line 5 can be reached from the explicit SSA
2106+ * definition on line 4.
2107+ * - The read of `this.Field` on line 10 can be reached from the phi node
2108+ * between lines 9 and 10.
2109+ * - The read of `this.Field` on line 11 is not the first read of any SSA
2110+ * definition.
2111+ *
2112+ * Subsequent reads can be found by following the steps defined by
2113+ * `AssignableRead.getANextRead()`.
2114+ */
2115+ AssignableRead getAFirstReadAtNode ( ControlFlow:: Node cfn ) {
2116+ firstReadSameVar ( this , cfn ) and
2117+ result .getAControlFlowNode ( ) = cfn
20792118 }
20802119
20812120 /**
@@ -2106,8 +2145,39 @@ module Ssa {
21062145 * - The read of `this.Field` on line 11 is a last read of the phi node
21072146 * between lines 9 and 10.
21082147 */
2109- AssignableRead getALastRead ( ) {
2110- lastRead ( this , result )
2148+ AssignableRead getALastRead ( ) { result = this .getALastReadAtNode ( _) }
2149+
2150+ /**
2151+ * Gets a last read of the source variable underlying this SSA definition at
2152+ * control flow node `cfn`. That is, a read that can reach the end of the
2153+ * enclosing callable, or another SSA definition for the source variable,
2154+ * without passing through any other read. Example:
2155+ *
2156+ * ```
2157+ * int Field;
2158+ *
2159+ * void SetField(int i) {
2160+ * this.Field = i;
2161+ * Use(this.Field);
2162+ * if (i > 0)
2163+ * this.Field = i - 1;
2164+ * else if (i < 0)
2165+ * SetField(1);
2166+ * Use(this.Field);
2167+ * Use(this.Field);
2168+ * }
2169+ * ```
2170+ *
2171+ * - The reads of `i` on lines 7 and 8 are the last reads for the implicit
2172+ * parameter definition on line 3.
2173+ * - The read of `this.Field` on line 5 is a last read of the definition on
2174+ * line 4.
2175+ * - The read of `this.Field` on line 11 is a last read of the phi node
2176+ * between lines 9 and 10.
2177+ */
2178+ AssignableRead getALastReadAtNode ( ControlFlow:: Node cfn ) {
2179+ lastRead ( this , cfn ) and
2180+ result .getAControlFlowNode ( ) = cfn
21112181 }
21122182
21132183 /**
0 commit comments