[ownership] Eliminate the need for mark_uninitialized fixup.

This commit eliminates the need for mark uninitialized fixup by updating the
compiler so that we now emit:

```
%0 = alloc_box
%1 = mark_uninitialized %0
%2 = project_box %1
...
destroy_value %1
```

Instead of:

```
%0 = alloc_box
%1 = project_box %0
%2 = mark_uninitialized %1
...
destroy_value %0
```

Now that the first type of code is generated, I can change project_box to only
take guaranteed arguments. This will ensure that the OSSA ARC optimizer can
eliminate copies of boxes without needing to understand the usage of the
project_box.
This commit is contained in:
Michael Gottesman
2019-12-19 10:15:40 -08:00
parent c4c78517e2
commit 28ffcf9a7a
12 changed files with 176 additions and 282 deletions

View File

@@ -477,10 +477,14 @@ namespace {
void processUninitializedRelease(SILInstruction *Release,
bool consumed,
SILBasicBlock::iterator InsertPt);
void processUninitializedReleaseOfBox(AllocBoxInst *ABI,
/// Process a mark_uninitialized of an alloc_box that is uninitialized and
/// needs a dealloc_box.
void processUninitializedReleaseOfBox(MarkUninitializedInst *MUI,
SILInstruction *Release,
bool consumed,
SILBasicBlock::iterator InsertPt);
void deleteDeadRelease(unsigned ReleaseID);
void processNonTrivialRelease(unsigned ReleaseID);
@@ -791,6 +795,7 @@ void LifetimeChecker::doIt() {
// thereof) is not initialized on some path, the bad things happen. Process
// releases to adjust for this.
if (!TheMemory.hasTrivialType()) {
// NOTE: This array may increase in size!
for (unsigned i = 0, e = Destroys.size(); i != e; ++i)
processNonTrivialRelease(i);
}
@@ -1941,12 +1946,13 @@ void LifetimeChecker::updateInstructionForInitState(DIMemoryUse &Use) {
}
void LifetimeChecker::processUninitializedReleaseOfBox(
AllocBoxInst *ABI, SILInstruction *Release, bool consumed,
MarkUninitializedInst *MUI, SILInstruction *Release, bool consumed,
SILBasicBlock::iterator InsertPt) {
assert(ABI == Release->getOperand(0));
assert(isa<AllocBoxInst>(MUI->getOperand()));
assert(MUI == Release->getOperand(0));
SILBuilderWithScope B(Release);
B.setInsertionPoint(InsertPt);
Destroys.push_back(B.createDeallocBox(Release->getLoc(), ABI));
Destroys.push_back(B.createDeallocBox(Release->getLoc(), MUI));
}
void LifetimeChecker::processUninitializedRelease(SILInstruction *Release,
@@ -1956,8 +1962,10 @@ void LifetimeChecker::processUninitializedRelease(SILInstruction *Release,
// dealloc_partial_ref to free the memory. If this is a derived class, we
// may have to do a load of the 'self' box to get the class reference.
if (!TheMemory.isClassInitSelf()) {
if (auto *ABI = dyn_cast<AllocBoxInst>(Release->getOperand(0))) {
return processUninitializedReleaseOfBox(ABI, Release, consumed, InsertPt);
if (auto *MUI = dyn_cast<MarkUninitializedInst>(Release->getOperand(0))) {
if (isa<AllocBoxInst>(MUI->getOperand())) {
return processUninitializedReleaseOfBox(MUI, Release, consumed, InsertPt);
}
}
return;
}
@@ -1972,9 +1980,14 @@ void LifetimeChecker::processUninitializedRelease(SILInstruction *Release,
// If we see an alloc_box as the pointer, then we're deallocating a 'box' for
// self. Make sure that the box gets deallocated (not released) since the
// pointer it contains will be manually cleaned up.
auto *ABI = dyn_cast<AllocBoxInst>(Release->getOperand(0));
if (ABI)
Pointer = getOrCreateProjectBox(ABI, 0);
auto *MUI = dyn_cast<MarkUninitializedInst>(Release->getOperand(0));
if (MUI && isa<AllocBoxInst>(MUI->getOperand())) {
Pointer = MUI->getSingleUserOfType<ProjectBoxInst>();
assert(Pointer);
} else {
MUI = nullptr;
}
if (!consumed) {
if (Pointer->getType().isAddress())
@@ -1999,8 +2012,8 @@ void LifetimeChecker::processUninitializedRelease(SILInstruction *Release,
}
// dealloc_box the self box if necessary.
if (ABI) {
auto DB = B.createDeallocBox(Loc, ABI);
if (MUI) {
auto DB = B.createDeallocBox(Loc, MUI);
Destroys.push_back(DB);
}
}