Skip to content

Commit 43ea9bf

Browse files
committed
[ownership] Refactor linear lifetime checker so that it doesnt require a value (only a beginBlock).
NFCI. The checker internally doesn't actually use the value for anything except for diagnostics and getting the value's parent block. So what this commit does is change the value to be optional state that is used in the diagnostics if it is available and otherwise uses its own ptr to the beginBlock. This will allow me to make two different constructors, one that takes a value (and sets the beginBlock ptr to its own parent block) and one that just takes a block. In certain cases, basing it off of the value can lead to counter-intuitive bugs (esp if code is using Builder.emit*ValueOperation() to create retain/release in non-ossa code). The reason why I am doing this is I want to introduce a higher level API on top of this for a common pattern in ossa (and code written for both modes): lifetime extending a value from a use point to a later program point by using a copy. I will explain this in more detail in a forthcoming commit.
1 parent 6562fa4 commit 43ea9bf

File tree

1 file changed

+84
-28
lines changed

1 file changed

+84
-28
lines changed

lib/SIL/LinearLifetimeChecker.cpp

Lines changed: 84 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,14 @@ namespace {
4242
using BrPropUserAndBlockPair = std::pair<BranchPropagatedUser, SILBasicBlock *>;
4343

4444
struct State {
45-
/// The value that we are checking.
46-
SILValue value;
45+
/// If we are checking for a specific value, this is that value. This is only
46+
/// used for diagnostic purposes. The algorithm if this is set works on the
47+
/// parent block of the value.
48+
Optional<SILValue> value;
49+
50+
/// The block where the live range begins. If the field value is not None,
51+
/// then this is value->getParentBlock();
52+
SILBasicBlock *beginBlock;
4753

4854
/// The result error object that use to signal either that no errors were
4955
/// found or if errors are found the specific type of error that was found.
@@ -75,8 +81,15 @@ struct State {
7581
State(SILValue value, SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
7682
ErrorBehaviorKind errorBehavior,
7783
SmallVectorImpl<SILBasicBlock *> *leakingBlocks)
78-
: value(value), error(errorBehavior), visitedBlocks(visitedBlocks),
79-
leakingBlocks(leakingBlocks) {}
84+
: value(value), beginBlock(value->getParentBlock()), error(errorBehavior),
85+
visitedBlocks(visitedBlocks), leakingBlocks(leakingBlocks) {}
86+
87+
State(SILBasicBlock *beginBlock,
88+
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
89+
ErrorBehaviorKind errorBehavior,
90+
SmallVectorImpl<SILBasicBlock *> *leakingBlocks)
91+
: value(), beginBlock(beginBlock), error(errorBehavior),
92+
visitedBlocks(visitedBlocks), leakingBlocks(leakingBlocks) {}
8093

8194
void initializeAllNonConsumingUses(
8295
ArrayRef<BranchPropagatedUser> nonConsumingUsers);
@@ -183,7 +196,7 @@ void State::initializeAllConsumingUses(
183196
// If this user is in the same block as the value, do not visit
184197
// predecessors. We must be extra tolerant here since we allow for
185198
// unreachable code.
186-
if (userBlock == value->getParentBlock())
199+
if (userBlock == beginBlock)
187200
continue;
188201

189202
// Then for each predecessor of this block...
@@ -203,10 +216,15 @@ void State::initializeConsumingUse(BranchPropagatedUser consumingUser,
203216
return;
204217

205218
error.handleOverConsume([&] {
206-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
207-
<< "Found over consume?!\n"
208-
<< "Value: " << *value << "User: " << *consumingUser
209-
<< "Block: bb" << userBlock->getDebugID() << "\n\n";
219+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName() << "'\n"
220+
<< "Found over consume?!\n";
221+
if (auto v = value) {
222+
llvm::errs() << "Value: " << *value;
223+
} else {
224+
llvm::errs() << "Value: N/A\n";
225+
}
226+
llvm::errs() << "User: " << *consumingUser << "Block: bb"
227+
<< userBlock->getDebugID() << "\n\n";
210228
});
211229
}
212230

@@ -228,10 +246,16 @@ void State::checkForSameBlockUseAfterFree(BranchPropagatedUser consumingUser,
228246
// the cond branch user is in a previous block. So just bail early.
229247
if (consumingUser.isCondBranchUser()) {
230248
error.handleUseAfterFree([&]() {
231-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
249+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName()
250+
<< "'\n"
232251
<< "Found use after free?!\n"
233-
<< "Value: " << *value
234-
<< "Consuming User: " << *consumingUser
252+
<< "Value: ";
253+
if (auto v = value) {
254+
llvm::errs() << *v;
255+
} else {
256+
llvm::errs() << "N/A. \n";
257+
}
258+
llvm::errs() << "Consuming User: " << *consumingUser
235259
<< "Non Consuming User: " << *iter->second << "Block: bb"
236260
<< userBlock->getDebugID() << "\n\n";
237261
});
@@ -255,10 +279,16 @@ void State::checkForSameBlockUseAfterFree(BranchPropagatedUser consumingUser,
255279
return nonConsumingUser == &i;
256280
}) != userBlock->end()) {
257281
error.handleUseAfterFree([&] {
258-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
282+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName()
283+
<< "'\n"
259284
<< "Found use after free?!\n"
260-
<< "Value: " << *value
261-
<< "Consuming User: " << *consumingUser
285+
<< "Value: ";
286+
if (auto v = value) {
287+
llvm::errs() << *v;
288+
} else {
289+
llvm::errs() << "N/A. \n";
290+
}
291+
llvm::errs() << "Consuming User: " << *consumingUser
262292
<< "Non Consuming User: " << *iter->second << "Block: bb"
263293
<< userBlock->getDebugID() << "\n\n";
264294
});
@@ -287,10 +317,17 @@ void State::checkPredsForDoubleConsume(BranchPropagatedUser consumingUser,
287317
}
288318

289319
error.handleOverConsume([&] {
290-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
320+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName() << "'\n"
291321
<< "Found over consume?!\n"
292-
<< "Value: " << *value << "User: " << *consumingUser
293-
<< "Block: bb" << userBlock->getDebugID() << "\n\n";
322+
<< "Value: ";
323+
if (auto v = value) {
324+
llvm::errs() << *v;
325+
} else {
326+
llvm::errs() << "N/A. \n";
327+
}
328+
329+
llvm::errs() << "User: " << *consumingUser << "Block: bb"
330+
<< userBlock->getDebugID() << "\n\n";
294331
});
295332
}
296333

@@ -310,10 +347,16 @@ void State::checkPredsForDoubleConsume(SILBasicBlock *userBlock) {
310347
}
311348

312349
error.handleOverConsume([&] {
313-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
350+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName() << "'\n"
314351
<< "Found over consume?!\n"
315-
<< "Value: " << *value << "Block: bb"
316-
<< userBlock->getDebugID() << "\n\n";
352+
<< "Value: ";
353+
if (auto v = value) {
354+
llvm::errs() << *v;
355+
} else {
356+
llvm::errs() << "N/A. \n";
357+
}
358+
359+
llvm::errs() << "Block: bb" << userBlock->getDebugID() << "\n\n";
317360
});
318361
}
319362

@@ -370,7 +413,7 @@ void State::performDataflow(DeadEndBlocks &deBlocks) {
370413
// further to do since we do not want to visit the predecessors of our
371414
// dominating block. On the other hand, we do want to add its successors to
372415
// the successorBlocksThatMustBeVisited set.
373-
if (block == value->getParentBlock())
416+
if (block == beginBlock)
374417
continue;
375418

376419
// Then for each predecessor of this block:
@@ -405,11 +448,16 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
405448

406449
// If we are supposed to error on leaks, do so now.
407450
error.handleLeak([&] {
408-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
451+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName()
452+
<< "'\n"
409453
<< "Error! Found a leak due to a consuming post-dominance "
410-
"failure!\n"
411-
<< " Value: " << *value
412-
<< " Post Dominating Failure Blocks:\n";
454+
"failure!\n";
455+
if (auto v = value) {
456+
llvm::errs() << "Value: " << *value;
457+
} else {
458+
llvm::errs() << "Value: N/A\n";
459+
}
460+
llvm::errs() << " Post Dominating Failure Blocks:\n";
413461
for (auto *succBlock : successorBlocksThatMustBeVisited) {
414462
llvm::errs() << " bb" << succBlock->getDebugID();
415463
}
@@ -434,10 +482,18 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
434482
}
435483

436484
error.handleUseAfterFree([&] {
437-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
485+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName()
486+
<< "'\n"
438487
<< "Found use after free due to unvisited non lifetime "
439488
"ending uses?!\n"
440-
<< "Value: " << *value << " Remaining Users:\n";
489+
<< "Value: ";
490+
if (auto v = value) {
491+
llvm::errs() << *v;
492+
} else {
493+
llvm::errs() << "N/A. \n";
494+
}
495+
496+
llvm::errs() << " Remaining Users:\n";
441497
for (auto &pair : blocksWithNonConsumingUses) {
442498
llvm::errs() << "User:" << *pair.second << "Block: bb"
443499
<< pair.first->getDebugID() << "\n";

0 commit comments

Comments
 (0)