@@ -59,7 +59,9 @@ ChangeResult Liveness::meet(const AbstractSparseLattice &other) {
59
59
// / (1.a) is an operand of an op with memory effects OR
60
60
// / (1.b) is a non-forwarded branch operand and its branch op could take the
61
61
// / control to a block that has an op with memory effects OR
62
- // / (1.c) is a non-forwarded call operand.
62
+ // / (1.c) is a non-forwarded branch operand and its branch op could result
63
+ // / in different live result OR
64
+ // / (1.d) is a non-forwarded call operand.
63
65
// /
64
66
// / A value `A` is said to be "used to compute" value `B` iff `B` cannot be
65
67
// / computed in the absence of `A`. Thus, in this implementation, we say that
@@ -106,51 +108,88 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) {
106
108
// the forwarded branch operands or the non-branch operands. Thus they need
107
109
// to be handled separately. This is where we handle them.
108
110
109
- // This marks values of type (1.b) liveness as "live". A non-forwarded
111
+ // This marks values of type (1.b/1.c ) liveness as "live". A non-forwarded
110
112
// branch operand will be live if a block where its op could take the control
111
- // has an op with memory effects.
113
+ // has an op with memory effects or could result in different results .
112
114
// Populating such blocks in `blocks`.
115
+ bool mayLive = false ;
113
116
SmallVector<Block *, 4 > blocks;
114
117
if (isa<RegionBranchOpInterface>(op)) {
115
- // When the op is a `RegionBranchOpInterface`, like an `scf.for` or an
116
- // `scf.index_switch` op, its branch operand controls the flow into this
117
- // op's regions.
118
- for (Region ®ion : op->getRegions ()) {
119
- for (Block &block : region)
120
- blocks.push_back (&block);
118
+ if (op->getNumResults () != 0 ) {
119
+ // This mark value of type 1.c liveness as may live, because the region
120
+ // branch operation has a return value, and the non-forwarded operand can
121
+ // determine the region to jump to, it can thereby control the result of
122
+ // the region branch operation.
123
+ // Therefore, if the result value is live, we conservatively consider the
124
+ // non-forwarded operand of the region branch operation with result may
125
+ // live and record all result.
126
+ for (Value result : op->getResults ()) {
127
+ if (getLatticeElement (result)->isLive ) {
128
+ mayLive = true ;
129
+ break ;
130
+ }
131
+ }
132
+ } else {
133
+ // When the op is a `RegionBranchOpInterface`, like an `scf.for` or an
134
+ // `scf.index_switch` op, its branch operand controls the flow into this
135
+ // op's regions.
136
+ for (Region ®ion : op->getRegions ()) {
137
+ for (Block &block : region)
138
+ blocks.push_back (&block);
139
+ }
121
140
}
122
141
} else if (isa<BranchOpInterface>(op)) {
123
- // When the op is a `BranchOpInterface`, like a `cf.cond_br` or a
124
- // `cf.switch` op, its branch operand controls the flow into this op's
125
- // successors.
126
- blocks = op->getSuccessors ();
142
+ // We cannot track all successor blocks of the branch operation(More
143
+ // specifically, it's the successor's successor). Additionally, different
144
+ // blocks might also lead to the different block argument described in 1.c.
145
+ // Therefore, we conservatively consider the non-forwarded operand of the
146
+ // branch operation may live.
147
+ mayLive = true ;
127
148
} else {
128
- // When the op is a `RegionBranchTerminatorOpInterface`, like an
129
- // `scf.condition` op or return-like, like an `scf.yield` op, its branch
130
- // operand controls the flow into this op's parent's (which is a
131
- // `RegionBranchOpInterface`'s) regions.
132
149
Operation *parentOp = op->getParentOp ();
133
150
assert (isa<RegionBranchOpInterface>(parentOp) &&
134
151
" expected parent op to implement `RegionBranchOpInterface`" );
135
- for (Region ®ion : parentOp->getRegions ()) {
136
- for (Block &block : region)
137
- blocks.push_back (&block);
152
+ if (parentOp->getNumResults () != 0 ) {
153
+ // This mark value of type 1.c liveness as may live, because the region
154
+ // branch operation has a return value, and the non-forwarded operand can
155
+ // determine the region to jump to, it can thereby control the result of
156
+ // the region branch operation.
157
+ // Therefore, if the result value is live, we conservatively consider the
158
+ // non-forwarded operand of the region branch operation with result may
159
+ // live and record all result.
160
+ for (Value result : parentOp->getResults ()) {
161
+ if (getLatticeElement (result)->isLive ) {
162
+ mayLive = true ;
163
+ break ;
164
+ }
165
+ }
166
+ } else {
167
+ // When the op is a `RegionBranchTerminatorOpInterface`, like an
168
+ // `scf.condition` op or return-like, like an `scf.yield` op, its branch
169
+ // operand controls the flow into this op's parent's (which is a
170
+ // `RegionBranchOpInterface`'s) regions.
171
+ for (Region ®ion : parentOp->getRegions ()) {
172
+ for (Block &block : region)
173
+ blocks.push_back (&block);
174
+ }
138
175
}
139
176
}
140
- bool foundMemoryEffectingOp = false ;
141
177
for (Block *block : blocks) {
142
- if (foundMemoryEffectingOp )
178
+ if (mayLive )
143
179
break ;
144
180
for (Operation &nestedOp : *block) {
145
181
if (!isMemoryEffectFree (&nestedOp)) {
146
- Liveness *operandLiveness = getLatticeElement (operand.get ());
147
- propagateIfChanged (operandLiveness, operandLiveness->markLive ());
148
- foundMemoryEffectingOp = true ;
182
+ mayLive = true ;
149
183
break ;
150
184
}
151
185
}
152
186
}
153
187
188
+ if (mayLive) {
189
+ Liveness *operandLiveness = getLatticeElement (operand.get ());
190
+ propagateIfChanged (operandLiveness, operandLiveness->markLive ());
191
+ }
192
+
154
193
// Now that we have checked for memory-effecting ops in the blocks of concern,
155
194
// we will simply visit the op with this non-forwarded operand to potentially
156
195
// mark it "live" due to type (1.a/3) liveness.
@@ -191,8 +230,12 @@ void LivenessAnalysis::visitCallOperand(OpOperand &operand) {
191
230
}
192
231
193
232
void LivenessAnalysis::setToExitState (Liveness *lattice) {
233
+ if (lattice->isLive ) {
234
+ return ;
235
+ }
194
236
// This marks values of type (2) liveness as "live".
195
237
(void )lattice->markLive ();
238
+ propagateIfChanged (lattice, ChangeResult::Change);
196
239
}
197
240
198
241
// ===----------------------------------------------------------------------===//
0 commit comments