55import csharp
66import SsaImplCommon
77
8- /** A classification of variable reads. */
9- newtype TReadKind =
10- /** An actual read. */
11- ActualRead ( ) or
12- /**
13- * A pseudo read for a `ref` or `out` variable at the end of the variable's enclosing
14- * callable. A pseudo read is inserted to make assignments to `out`/`ref` variables
15- * live, for example line 1 in
16- *
17- * ```csharp
18- * void M(out int i) {
19- * i = 0;
20- * }
21- * ```
22- */
23- OutRefExitRead ( ) or
24- /**
25- * A pseudo read for a captured variable at the end of the capturing
26- * callable. A write to a captured variable needs to be live for the same reasons
27- * as a write to a `ref` or `out` variable (see above).
28- */
29- CapturedVarExitRead ( ) or
30- /**
31- * A pseudo read for a captured variable via a call.
32- */
33- CapturedVarCallRead ( ) or
34- /**
35- * A pseudo read for a `ref` variable, just prior to an update of the referenced value.
36- * A pseudo read is inserted to make assignments to the `ref` variable live, for example
37- * line 2 in
38- *
39- * ```csharp
40- * void M() {
41- * ref int i = ref GetRef();
42- * i = 0;
43- * }
44- * ```
45- *
46- * The pseudo read is inserted at the CFG node `i` on the left-hand side of the
47- * assignment on line 3.
48- */
49- RefReadBeforeWrite ( )
50-
51- /** A classification of variable reads. */
52- class ReadKind extends TReadKind {
53- string toString ( ) {
54- this = ActualRead ( ) and
55- result = "ActualRead"
56- or
57- this = OutRefExitRead ( ) and
58- result = "OutRefExitRead"
59- or
60- this = CapturedVarExitRead ( ) and
61- result = "CapturedVarExitRead"
62- or
63- this = CapturedVarCallRead ( ) and
64- result = "CapturedVarCallRead"
65- or
66- this = RefReadBeforeWrite ( ) and
67- result = "RefReadBeforeWrite"
68- }
69-
70- /** Holds if this kind represents a pseudo read. */
71- predicate isPseudo ( ) { this != ActualRead ( ) }
8+ /**
9+ * Holds if the `i`th node of basic block `bb` reads source variable `v`.
10+ */
11+ predicate variableReadActual ( ControlFlow:: BasicBlock bb , int i , Ssa:: SourceVariable v ) {
12+ v .getAnAccess ( ) .( AssignableRead ) = bb .getNode ( i ) .getElement ( )
7213}
7314
7415private module SourceVariableImpl {
@@ -183,23 +124,17 @@ private module SourceVariableImpl {
183124 }
184125
185126 /**
186- * Holds if the `i`th node of basic block `bb` reads source variable `v`.
187- * The read is of kind `rk`.
127+ * Holds if a pseudo read for `ref` or `out` variable `v` happens at index `i`
128+ * in basic block `bb`. A pseudo read is inserted to make assignments to
129+ * `out`/`ref` variables live, for example line 1 in
188130 *
189- * This excludes implicit reads via calls.
131+ * ```csharp
132+ * void M(out int i) {
133+ * i = 0;
134+ * }
135+ * ```
190136 */
191- predicate variableReadDirect ( ControlFlow:: BasicBlock bb , int i , Ssa:: SourceVariable v , ReadKind rk ) {
192- v .getAnAccess ( ) .( AssignableRead ) = bb .getNode ( i ) .getElement ( ) and
193- rk = ActualRead ( )
194- or
195- outRefExitRead ( bb , i , v ) and
196- rk = OutRefExitRead ( )
197- or
198- refReadBeforeWrite ( bb , i , v ) and
199- rk = RefReadBeforeWrite ( )
200- }
201-
202- private predicate outRefExitRead ( ControlFlow:: BasicBlock bb , int i , LocalScopeSourceVariable v ) {
137+ predicate outRefExitRead ( ControlFlow:: BasicBlock bb , int i , LocalScopeSourceVariable v ) {
203138 exists ( ControlFlow:: Nodes:: AnnotatedExitNode exit |
204139 exit .isNormal ( ) and
205140 exists ( LocalScopeVariable lsv |
@@ -215,7 +150,23 @@ private module SourceVariableImpl {
215150 )
216151 }
217152
218- private predicate refReadBeforeWrite ( ControlFlow:: BasicBlock bb , int i , LocalScopeSourceVariable v ) {
153+ /**
154+ * Holds if a pseudo read for `ref` variable `v` happens at index `i` in basic
155+ * block `bb`, just prior to an update of the referenced value. A pseudo read
156+ * is inserted to make assignments to the `ref` variable live, for example
157+ * line 2 in
158+ *
159+ * ```csharp
160+ * void M() {
161+ * ref int i = ref GetRef();
162+ * i = 0;
163+ * }
164+ * ```
165+ *
166+ * The pseudo read is inserted at the CFG node `i` on the left-hand side of the
167+ * assignment on line 3.
168+ */
169+ predicate refReadBeforeWrite ( ControlFlow:: BasicBlock bb , int i , LocalScopeSourceVariable v ) {
219170 exists ( AssignableDefinitions:: AssignmentDefinition def , LocalVariable lv |
220171 def .getTarget ( ) = lv and
221172 lv .isRef ( ) and
@@ -812,10 +763,13 @@ private module CapturedVariableLivenessImpl {
812763 */
813764 private predicate capturerReads ( Callable c , LocalScopeVariable v ) {
814765 exists ( LocalScopeSourceVariable sv |
815- variableReadDirect ( _, _, sv , _) and
816766 c = sv .getEnclosingCallable ( ) and
817767 v = sv .getAssignable ( ) and
818768 v .getCallable ( ) != c
769+ |
770+ variableReadActual ( _, _, sv )
771+ or
772+ refReadBeforeWrite ( _, _, sv )
819773 )
820774 }
821775
@@ -985,20 +939,25 @@ private module CapturedVariableLivenessImpl {
985939
986940private import CapturedVariableLivenessImpl
987941
942+ private predicate variableReadPseudo ( ControlFlow:: BasicBlock bb , int i , Ssa:: SourceVariable v ) {
943+ outRefExitRead ( bb , i , v )
944+ or
945+ refReadBeforeWrite ( bb , i , v )
946+ or
947+ capturedReadOut ( bb , i , v , _, _, _)
948+ or
949+ capturedReadIn ( bb , i , v , _, _, _)
950+ }
951+
988952/**
989953 * Holds if the `i`th of basic block `bb` reads source variable `v`.
990- * The read is of kind `rk`.
991954 *
992955 * This includes implicit reads via calls.
993956 */
994- predicate variableRead ( ControlFlow:: BasicBlock bb , int i , Ssa:: SourceVariable v , ReadKind rk ) {
995- variableReadDirect ( bb , i , v , rk )
957+ predicate variableRead ( ControlFlow:: BasicBlock bb , int i , Ssa:: SourceVariable v ) {
958+ variableReadActual ( bb , i , v )
996959 or
997- capturedReadOut ( bb , i , v , _, _, _) and
998- rk = CapturedVarExitRead ( )
999- or
1000- capturedReadIn ( bb , i , v , _, _, _) and
1001- rk = CapturedVarCallRead ( )
960+ variableReadPseudo ( bb , i , v )
1002961}
1003962
1004963cached
@@ -1119,7 +1078,7 @@ private module Cached {
11191078 capturedReadIn ( _, _, v , edef .getSourceVariable ( ) , c , additionalCalls ) and
11201079 def = def0 .getAnUltimateDefinition ( ) and
11211080 ssaDefReachesRead ( _, def0 , bb , i ) and
1122- variableRead ( bb , i , v , CapturedVarCallRead ( ) ) and
1081+ capturedReadIn ( bb , i , v , _ , _ , _ ) and
11231082 c = bb .getNode ( i )
11241083 )
11251084 }
@@ -1130,7 +1089,6 @@ private module Cached {
11301089 ) {
11311090 exists ( Ssa:: Definition def0 , ControlFlow:: BasicBlock bb , int i |
11321091 def = def0 .getAnUltimateDefinition ( ) and
1133- lastRef ( def0 , bb , i ) and
11341092 capturedReadOut ( bb , i , def0 .getSourceVariable ( ) , cdef .getSourceVariable ( ) , cdef .getCall ( ) ,
11351093 additionalCalls )
11361094 )
@@ -1151,7 +1109,7 @@ private module Cached {
11511109 or
11521110 exists ( ControlFlow:: BasicBlock bb3 , int i3 |
11531111 adjacentDefReaches ( def , bb1 , i1 , bb3 , i3 ) and
1154- variableRead ( bb3 , i3 , _, any ( ReadKind rk | rk . isPseudo ( ) ) ) and
1112+ variableReadPseudo ( bb3 , i3 , _) and
11551113 adjacentDefRead ( def , bb3 , i3 , bb2 , i2 )
11561114 )
11571115 }
@@ -1161,7 +1119,7 @@ private module Cached {
11611119 Definition def , ControlFlow:: BasicBlock bb1 , int i1 , ControlFlow:: BasicBlock bb2 , int i2
11621120 ) {
11631121 adjacentDefReaches ( def , bb1 , i1 , bb2 , i2 ) and
1164- variableRead ( bb2 , i2 , _, ActualRead ( ) )
1122+ variableReadActual ( bb2 , i2 , _)
11651123 }
11661124
11671125 /**
@@ -1186,7 +1144,7 @@ private module Cached {
11861144 predicate adjacentReadPairSameVar ( Definition def , ControlFlow:: Node cfn1 , ControlFlow:: Node cfn2 ) {
11871145 exists ( ControlFlow:: BasicBlock bb1 , int i1 , ControlFlow:: BasicBlock bb2 , int i2 |
11881146 cfn1 = bb1 .getNode ( i1 ) and
1189- variableRead ( bb1 , i1 , _, ActualRead ( ) ) and
1147+ variableReadActual ( bb1 , i1 , _) and
11901148 adjacentDefActualRead ( def , bb1 , i1 , bb2 , i2 ) and
11911149 cfn2 = bb2 .getNode ( i2 )
11921150 )
@@ -1196,15 +1154,31 @@ private module Cached {
11961154 Definition def , ControlFlow:: BasicBlock bb1 , int i1 , ControlFlow:: BasicBlock bb2 , int i2
11971155 ) {
11981156 adjacentDefReaches ( def , bb1 , i1 , bb2 , i2 ) and
1199- variableRead ( bb2 , i2 , _, any ( ReadKind rk | rk .isPseudo ( ) ) )
1157+ variableReadPseudo ( bb2 , i2 , _)
1158+ }
1159+
1160+ private predicate reachesLastRefRedef (
1161+ Definition def , ControlFlow:: BasicBlock bb , int i , Definition next
1162+ ) {
1163+ lastRefRedef ( def , bb , i , next )
1164+ or
1165+ exists ( ControlFlow:: BasicBlock bb0 , int i0 |
1166+ reachesLastRefRedef ( def , bb0 , i0 , next ) and
1167+ adjacentDefPseudoRead ( def , bb , i , bb0 , i0 )
1168+ )
1169+ }
1170+
1171+ cached
1172+ predicate lastRefBeforeRedef ( Definition def , ControlFlow:: BasicBlock bb , int i , Definition next ) {
1173+ reachesLastRefRedef ( def , bb , i , next ) and
1174+ not variableReadPseudo ( bb , i , def .getSourceVariable ( ) )
12001175 }
12011176
12021177 private predicate reachesLastRef ( Definition def , ControlFlow:: BasicBlock bb , int i ) {
12031178 lastRef ( def , bb , i )
12041179 or
12051180 exists ( ControlFlow:: BasicBlock bb0 , int i0 |
12061181 reachesLastRef ( def , bb0 , i0 ) and
1207- variableRead ( bb0 , i0 , _, any ( ReadKind rk | rk .isPseudo ( ) ) ) and
12081182 adjacentDefPseudoRead ( def , bb , i , bb0 , i0 )
12091183 )
12101184 }
@@ -1213,19 +1187,20 @@ private module Cached {
12131187 predicate lastReadSameVar ( Definition def , ControlFlow:: Node cfn ) {
12141188 exists ( ControlFlow:: BasicBlock bb , int i |
12151189 reachesLastRef ( def , bb , i ) and
1216- variableRead ( bb , i , _, ActualRead ( ) ) and
1190+ variableReadActual ( bb , i , _) and
12171191 cfn = bb .getNode ( i )
12181192 )
12191193 }
12201194
12211195 cached
12221196 predicate isLiveOutRefParameterDefinition ( Ssa:: Definition def , Parameter p ) {
12231197 p .isOutOrRef ( ) and
1224- exists ( Ssa:: Definition def0 , ControlFlow:: BasicBlock bb , int i |
1198+ exists ( Ssa:: SourceVariable v , Ssa:: Definition def0 , ControlFlow:: BasicBlock bb , int i |
1199+ v = def .getSourceVariable ( ) and
1200+ p = v .getAssignable ( ) and
12251201 def = def0 .getAnUltimateDefinition ( ) and
1226- reachesLastRef ( def0 , bb , i ) and
1227- variableRead ( bb , i , def0 .getSourceVariable ( ) , OutRefExitRead ( ) ) and
1228- p = def0 .getSourceVariable ( ) .getAssignable ( )
1202+ ssaDefReachesRead ( _, def0 , bb , i ) and
1203+ outRefExitRead ( bb , i , v )
12291204 )
12301205 }
12311206}
0 commit comments