mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[TempRValueOpt] Fold new destroy_addrs into loads.
To avoid introducing new copies--which is illegal for move-only values-- don't rewrite `load [take]`s and `copy_addr [take]`s as `load [copy]`s and `copy_addr`s respectively and introduce new `destroy_addr`s after them. Instead, get the effect of folding such a newly created `destroy_addr` into the preceding rewritten `load [copy]` or `copy_addr`. Get that effect by neither modifying the `copy_addr [take]` or `load [take]` nor adding a subsequent `destroy_addr`. An example for each kind (`load [take]` and `copy_addr [take]`): ``` // Input 1 (`load [take]`) copy_addr [take] %src to [init] %tmp %val = load [take] %src // Old Output 1 %val = load [copy] %src destroy_addr %src // New Output 2 %val = load [take] %src ``` ``` // Input 2 (`copy_addr [take]`) copy_addr [take] %src to [init] %tmp copy_addr [take] %src to [init] %dst // Old Output 2 copy_addr %src to [init] %dst destroy_addr %src // New Output 2 copy_addr [take] %src to [init] %dst ``` rdar://107839979
This commit is contained in:
@@ -535,9 +535,10 @@ void TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
|
||||
SILValue copySrc = copyInst->getSrc();
|
||||
assert(tempObj != copySrc && "can't initialize temporary with itself");
|
||||
|
||||
// If the source of the copyInst is taken, we must insert a compensating
|
||||
// destroy_addr. This must be done at the right spot: after the last use
|
||||
// tempObj, but before any (potential) re-initialization of the source.
|
||||
// If the source of the copyInst is taken, it must be deinitialized (via
|
||||
// destroy_addr, load [take], copy_addr [take]). This must be done at the
|
||||
// right spot: after the last use tempObj, but before any (potential)
|
||||
// re-initialization of the source.
|
||||
bool needFinalDeinit = copyInst->isTakeOfSrc();
|
||||
|
||||
// Scan all uses of the temporary storage (tempObj) to verify they all refer
|
||||
@@ -601,7 +602,29 @@ void TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
|
||||
|
||||
LLVM_DEBUG(llvm::dbgs() << " Success: replace temp" << *tempObj);
|
||||
|
||||
if (needFinalDeinit) {
|
||||
// If copyInst's source must be deinitialized, whether that must be done via
|
||||
// a newly created destroy_addr.
|
||||
//
|
||||
// If lastLoadInst is a load or a copy_addr, then the deinitialization can be
|
||||
// done in that instruction.
|
||||
//
|
||||
// This is necessary for correctness: otherwise, copies of move-only values
|
||||
// would be introduced.
|
||||
bool needToInsertDestroy = [&]() {
|
||||
if (!needFinalDeinit)
|
||||
return false;
|
||||
if (lastLoadInst == copyInst)
|
||||
return true;
|
||||
if (auto *cai = dyn_cast<CopyAddrInst>(lastLoadInst)) {
|
||||
return cai->getSrc() != tempObj || !cai->isTakeOfSrc();
|
||||
}
|
||||
if (auto *li = dyn_cast<LoadInst>(lastLoadInst)) {
|
||||
return li->getOperand() != tempObj ||
|
||||
li->getOwnershipQualifier() != LoadOwnershipQualifier::Take;
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
if (needToInsertDestroy) {
|
||||
// Compensate the [take] of the original copyInst.
|
||||
SILBuilderWithScope::insertAfter(lastLoadInst, [&] (SILBuilder &builder) {
|
||||
builder.createDestroyAddr(builder.getInsertionPoint()->getLoc(), copySrc);
|
||||
@@ -630,16 +653,19 @@ void TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
|
||||
auto *cai = cast<CopyAddrInst>(user);
|
||||
if (cai != copyInst) {
|
||||
assert(cai->getSrc() == tempObj);
|
||||
if (cai->isTakeOfSrc())
|
||||
if (cai->isTakeOfSrc() && (!needFinalDeinit || lastLoadInst != cai)) {
|
||||
cai->setIsTakeOfSrc(IsNotTake);
|
||||
}
|
||||
}
|
||||
use->set(copySrc);
|
||||
break;
|
||||
}
|
||||
case SILInstructionKind::LoadInst: {
|
||||
auto *li = cast<LoadInst>(user);
|
||||
if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take)
|
||||
if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take &&
|
||||
(!needFinalDeinit || li != lastLoadInst)) {
|
||||
li->setOwnershipQualifier(LoadOwnershipQualifier::Copy);
|
||||
}
|
||||
use->set(copySrc);
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user