@@ -44,9 +44,15 @@ struct State {
44
44
// / parent block of the value.
45
45
Optional<SILValue> value;
46
46
47
- // / The block where the live range begins. If the field value is not None,
48
- // / then this is value->getParentBlock();
49
- SILBasicBlock *beginBlock;
47
+ // / The insertion point where the live range begins. If the field value is not
48
+ // / None, then:
49
+ //
50
+ // 1. If this value is defined by an instruction, it will be
51
+ // value->getDefiningInstruction().
52
+ //
53
+ // 2. If this is an argument, this is the first instruction in the argument's
54
+ // defining block.
55
+ SILInstruction *beginInst;
50
56
51
57
// / The result error object that use to signal either that no errors were
52
58
// / found or if errors are found the specific type of error that was found.
@@ -84,8 +90,8 @@ struct State {
84
90
LinearLifetimeChecker::ErrorBehaviorKind errorBehavior,
85
91
Optional<function_ref<void (SILBasicBlock *)>> leakingBlockCallback,
86
92
ArrayRef<Operand *> consumingUses, ArrayRef<Operand *> nonConsumingUses)
87
- : value(value), beginBlock (value->getParentBlock ()), error(errorBehavior ),
88
- visitedBlocks(visitedBlocks),
93
+ : value(value), beginInst (value->getDefiningInsertionPoint () ),
94
+ error(errorBehavior), visitedBlocks(visitedBlocks),
89
95
leakingBlockCallback(leakingBlockCallback),
90
96
consumingUses(consumingUses), nonConsumingUses(nonConsumingUses) {}
91
97
@@ -94,11 +100,13 @@ struct State {
94
100
LinearLifetimeChecker::ErrorBehaviorKind errorBehavior,
95
101
Optional<function_ref<void (SILBasicBlock *)>> leakingBlockCallback,
96
102
ArrayRef<Operand *> consumingUses, ArrayRef<Operand *> nonConsumingUses)
97
- : value(), beginBlock( beginBlock), error(errorBehavior),
103
+ : value(), beginInst(&* beginBlock-> begin () ), error(errorBehavior),
98
104
visitedBlocks(visitedBlocks),
99
105
leakingBlockCallback(leakingBlockCallback),
100
106
consumingUses(consumingUses), nonConsumingUses(nonConsumingUses) {}
101
107
108
+ SILBasicBlock *getBeginBlock () const { return beginInst->getParent (); }
109
+
102
110
void initializeAllNonConsumingUses (ArrayRef<Operand *> nonConsumingUsers);
103
111
void initializeAllConsumingUses (
104
112
ArrayRef<Operand *> consumingUsers,
@@ -159,6 +167,30 @@ void State::initializeAllNonConsumingUses(
159
167
ArrayRef<Operand *> nonConsumingUsers) {
160
168
for (Operand *use : nonConsumingUsers) {
161
169
auto *userBlock = use->getUser ()->getParent ();
170
+
171
+ // First check if this non consuming user is in our definition block. If so,
172
+ // validate that it is strictly after our defining instruction. If so, just
173
+ // emit an error now and exit.
174
+ if (userBlock == getBeginBlock ()) {
175
+ if (std::find_if (beginInst->getIterator (), userBlock->end (),
176
+ [&use](const SILInstruction &inst) -> bool {
177
+ return use->getUser () == &inst;
178
+ }) == userBlock->end ()) {
179
+ error.handleUseAfterFree ([&] {
180
+ llvm::errs () << " Function: '"
181
+ << getBeginBlock ()->getParent ()->getName () << " '\n "
182
+ << " Found use before def?!\n "
183
+ << " Value: " ;
184
+ if (auto v = value) {
185
+ llvm::errs () << *v;
186
+ } else {
187
+ llvm::errs () << " N/A. \n " ;
188
+ }
189
+ });
190
+ return ;
191
+ }
192
+ }
193
+
162
194
// First try to associate User with User->getParent().
163
195
auto result =
164
196
blocksWithNonConsumingUses.insert (std::make_pair (userBlock, use));
@@ -213,7 +245,7 @@ void State::initializeAllConsumingUses(
213
245
// If this user is in the same block as the value, do not visit
214
246
// predecessors. We must be extra tolerant here since we allow for
215
247
// unreachable code.
216
- if (userBlock == beginBlock )
248
+ if (userBlock == getBeginBlock () )
217
249
continue ;
218
250
219
251
// Then for each predecessor of this block...
@@ -233,7 +265,8 @@ void State::initializeConsumingUse(Operand *consumingUse,
233
265
return ;
234
266
235
267
error.handleOverConsume ([&] {
236
- llvm::errs () << " Function: '" << beginBlock->getParent ()->getName () << " '\n "
268
+ llvm::errs () << " Function: '" << getBeginBlock ()->getParent ()->getName ()
269
+ << " '\n "
237
270
<< " Found over consume?!\n " ;
238
271
if (auto v = value) {
239
272
llvm::errs () << " Value: " << *v;
@@ -266,7 +299,7 @@ void State::checkForSameBlockUseAfterFree(Operand *consumingUse,
266
299
return nonConsumingUse->getUser () == &i;
267
300
}) != userBlock->end ()) {
268
301
error.handleUseAfterFree ([&] {
269
- llvm::errs () << " Function: '" << beginBlock ->getParent ()->getName ()
302
+ llvm::errs () << " Function: '" << getBeginBlock () ->getParent ()->getName ()
270
303
<< " '\n "
271
304
<< " Found use after free?!\n "
272
305
<< " Value: " ;
@@ -304,7 +337,8 @@ void State::checkPredsForDoubleConsume(Operand *consumingUse,
304
337
}
305
338
306
339
error.handleOverConsume ([&] {
307
- llvm::errs () << " Function: '" << beginBlock->getParent ()->getName () << " '\n "
340
+ llvm::errs () << " Function: '" << getBeginBlock ()->getParent ()->getName ()
341
+ << " '\n "
308
342
<< " Found over consume?!\n "
309
343
<< " Value: " ;
310
344
if (auto v = value) {
@@ -335,7 +369,8 @@ void State::checkPredsForDoubleConsume(SILBasicBlock *userBlock) {
335
369
}
336
370
337
371
error.handleOverConsume ([&] {
338
- llvm::errs () << " Function: '" << beginBlock->getParent ()->getName () << " '\n "
372
+ llvm::errs () << " Function: '" << getBeginBlock ()->getParent ()->getName ()
373
+ << " '\n "
339
374
<< " Found over consume?!\n "
340
375
<< " Value: " ;
341
376
if (auto v = value) {
@@ -402,7 +437,7 @@ void State::performDataflow(DeadEndBlocks &deBlocks) {
402
437
// further to do since we do not want to visit the predecessors of our
403
438
// dominating block. On the other hand, we do want to add its successors to
404
439
// the successorBlocksThatMustBeVisited set.
405
- if (block == beginBlock )
440
+ if (block == getBeginBlock () )
406
441
continue ;
407
442
408
443
// Then for each predecessor of this block:
@@ -438,7 +473,7 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
438
473
439
474
// If we are supposed to error on leaks, do so now.
440
475
error.handleLeak ([&] {
441
- llvm::errs () << " Function: '" << beginBlock ->getParent ()->getName ()
476
+ llvm::errs () << " Function: '" << getBeginBlock () ->getParent ()->getName ()
442
477
<< " '\n "
443
478
<< " Error! Found a leak due to a consuming post-dominance "
444
479
" failure!\n " ;
@@ -472,7 +507,7 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
472
507
}
473
508
474
509
error.handleUseAfterFree ([&] {
475
- llvm::errs () << " Function: '" << beginBlock ->getParent ()->getName ()
510
+ llvm::errs () << " Function: '" << getBeginBlock () ->getParent ()->getName ()
476
511
<< " '\n "
477
512
<< " Found use after free due to unvisited non lifetime "
478
513
" ending uses?!\n "
0 commit comments