Skip to content

Commit e5a6de6

Browse files
authored
Merge pull request swiftlang#34996 from meg-gupta/ossarle
Enable RLE on OSSA
2 parents 62dc8ce + 66ef200 commit e5a6de6

File tree

11 files changed

+3251
-46
lines changed

11 files changed

+3251
-46
lines changed

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#ifndef SWIFT_SILOPTIMIZER_UTILS_INSTOPTUTILS_H
2121
#define SWIFT_SILOPTIMIZER_UTILS_INSTOPTUTILS_H
2222

23+
#include "swift/SIL/BasicBlockUtils.h"
2324
#include "swift/SIL/SILBuilder.h"
2425
#include "swift/SIL/SILInstruction.h"
2526
#include "swift/SILOptimizer/Analysis/ARCAnalysis.h"
@@ -688,6 +689,20 @@ SILBasicBlock::iterator replaceAllUsesAndErase(SingleValueInstruction *svi,
688689
SILBasicBlock::iterator replaceSingleUse(Operand *use, SILValue newValue,
689690
InstModCallbacks &callbacks);
690691

692+
/// Creates a copy of \p value and inserts additional control equivalent copy
693+
/// and destroy at leaking blocks to adjust ownership and make available for use
694+
/// at \p inBlock.
695+
SILValue
696+
makeCopiedValueAvailable(SILValue value, SILBasicBlock *inBlock,
697+
JointPostDominanceSetComputer *jointPostDomComputer);
698+
699+
/// Given a newly created @owned value \p value without any uses, this utility
700+
/// inserts control equivalent copy and destroy at leaking blocks to adjust
701+
/// ownership and make \p value available for use at \p inBlock.
702+
SILValue
703+
makeNewValueAvailable(SILValue value, SILBasicBlock *inBlock,
704+
JointPostDominanceSetComputer *jointPostDomComputer);
705+
691706
} // end namespace swift
692707

693708
#endif

include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,27 @@ class LSValue : public LSBase {
255255
///
256256
/// In the case where we have a single value this can be materialized by
257257
/// applying Path to the Base.
258-
SILValue materialize(SILInstruction *Inst) {
258+
SILValue materialize(SILInstruction *Inst,
259+
JointPostDominanceSetComputer *jointPostDomComputer) {
259260
if (CoveringValue)
260261
return SILValue();
261-
return Path.getValue().createExtract(Base, Inst, true);
262+
auto Val = Base;
263+
auto InsertPt = getInsertAfterPoint(Base).getValue();
264+
SILBuilderWithScope Builder(InsertPt);
265+
if (Inst->getFunction()->hasOwnership() && !Path.getValue().empty()) {
266+
// We have to create a @guaranteed scope with begin_borrow in order to
267+
// create a struct_extract in OSSA
268+
Val = Builder.emitBeginBorrowOperation(InsertPt->getLoc(), Base);
269+
}
270+
auto Res = Path.getValue().createExtract(Val, &*InsertPt, true);
271+
if (Val != Base) {
272+
Res = makeCopiedValueAvailable(Res, Inst->getParentBlock(),
273+
jointPostDomComputer);
274+
Builder.emitEndBorrowOperation(InsertPt->getLoc(), Val);
275+
// Insert a destroy on the Base
276+
SILBuilderWithScope(Inst).emitDestroyValueOperation(Inst->getLoc(), Base);
277+
}
278+
return Res;
262279
}
263280

264281
void print(llvm::raw_ostream &os) override {
@@ -279,9 +296,11 @@ class LSValue : public LSBase {
279296
/// location holds. This may involve extracting and aggregating available
280297
/// values.
281298
static void reduceInner(LSLocation &B, SILModule *M, LSLocationValueMap &Vals,
282-
SILInstruction *InsertPt);
299+
SILInstruction *InsertPt,
300+
JointPostDominanceSetComputer *jointPostDomComputer);
283301
static SILValue reduce(LSLocation &B, SILModule *M, LSLocationValueMap &Vals,
284-
SILInstruction *InsertPt);
302+
SILInstruction *InsertPt,
303+
JointPostDominanceSetComputer *jointPostDomComputer);
285304
};
286305

287306
static inline llvm::hash_code hash_value(const LSValue &V) {

lib/SIL/Utils/BasicBlockUtils.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,13 @@ void JointPostDominanceSetComputer::findJointPostDominatingSet(
463463
for (auto *predBlock : block->getPredecessorBlocks()) {
464464
if (initialBlocks.count(predBlock)) {
465465
reachableInputBlocks.push_back(predBlock);
466+
for (auto *succBlock : predBlock->getSuccessorBlocks()) {
467+
if (visitedBlocks.count(succBlock))
468+
continue;
469+
if (deadEndBlocks.isDeadEnd(succBlock))
470+
continue;
471+
blocksThatLeakIfNeverVisited.insert(succBlock);
472+
}
466473
}
467474
if (visitedBlocks.insert(predBlock).second)
468475
worklist.push_back(predBlock);

lib/SIL/Utils/Projection.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,8 @@ Optional<ProjectionPath> ProjectionPath::getProjectionPath(SILValue Start,
384384
//
385385
// TODO: migrate users to getProjectionPath to the AccessPath utility to
386386
// avoid this hack.
387-
if (!isa<EndCOWMutationInst>(Iter) && !isa<BeginAccessInst>(Iter)) {
387+
if (!isa<EndCOWMutationInst>(Iter) && !isa<BeginAccessInst>(Iter) &&
388+
!isa<BeginBorrowInst>(Iter)) {
388389
Projection AP(Iter);
389390
if (!AP.isValid())
390391
break;

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ void addFunctionPasses(SILPassPipelinePlan &P,
385385
} else {
386386
P.addRedundantLoadElimination();
387387
}
388+
// Optimize copies created during RLE.
389+
P.addSemanticARCOpts();
388390

389391
P.addCOWOpts();
390392
P.addPerformanceConstantPropagation();

lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ static bool isRLEInertInstruction(SILInstruction *Inst) {
155155
case SILInstructionKind::EndAccessInst:
156156
case SILInstructionKind::SetDeallocatingInst:
157157
case SILInstructionKind::DeallocRefInst:
158+
case SILInstructionKind::BeginBorrowInst:
159+
case SILInstructionKind::EndBorrowInst:
158160
return true;
159161
default:
160162
return false;
@@ -481,14 +483,17 @@ class RLEContext {
481483
/// If set, RLE ignores loads from that array type.
482484
NominalTypeDecl *ArrayType;
483485

486+
JointPostDominanceSetComputer &jointPostDomComputer;
487+
484488
#ifndef NDEBUG
485489
SILPrintContext printCtx;
486490
#endif
487491

488492
public:
489493
RLEContext(SILFunction *F, SILPassManager *PM, AliasAnalysis *AA,
490494
TypeExpansionAnalysis *TE, PostOrderFunctionInfo *PO,
491-
EpilogueARCFunctionInfo *EAFI, bool disableArrayLoads);
495+
EpilogueARCFunctionInfo *EAFI, bool disableArrayLoads,
496+
JointPostDominanceSetComputer &computer);
492497

493498
RLEContext(const RLEContext &) = delete;
494499
RLEContext(RLEContext &&) = delete;
@@ -536,6 +541,11 @@ class RLEContext {
536541
/// Return the BlockState for the basic block this basic block belongs to.
537542
BlockState &getBlockState(SILBasicBlock *B) { return BBToLocState[B]; }
538543

544+
/// Return the initialized jointPostDomComputer
545+
JointPostDominanceSetComputer *getJointPostDomSetComputer() {
546+
return &jointPostDomComputer;
547+
}
548+
539549
/// Get the bit representing the LSLocation in the LocationVault.
540550
unsigned getLocationBit(const LSLocation &L);
541551

@@ -679,14 +689,17 @@ SILValue BlockState::reduceValuesAtEndOfBlock(RLEContext &Ctx, LSLocation &L) {
679689
// we do not have a concrete value in the current basic block.
680690
ValueTableMap &OTM = getForwardValOut();
681691
for (unsigned i = 0; i < Locs.size(); ++i) {
682-
Values[Locs[i]] = Ctx.getValue(OTM[Ctx.getLocationBit(Locs[i])]);
692+
auto Val = Ctx.getValue(OTM[Ctx.getLocationBit(Locs[i])]);
693+
auto AvailVal = makeCopiedValueAvailable(Val.getBase(), BB,
694+
Ctx.getJointPostDomSetComputer());
695+
Values[Locs[i]] = LSValue(AvailVal, Val.getPath().getValue());
683696
}
684697

685698
// Second, reduce the available values into a single SILValue we can use to
686699
// forward.
687-
SILValue TheForwardingValue;
688-
TheForwardingValue =
689-
LSValue::reduce(L, &BB->getModule(), Values, BB->getTerminator());
700+
SILValue TheForwardingValue =
701+
LSValue::reduce(L, &BB->getModule(), Values, BB->getTerminator(),
702+
Ctx.getJointPostDomSetComputer());
690703
/// Return the forwarding value.
691704
return TheForwardingValue;
692705
}
@@ -711,7 +724,9 @@ bool BlockState::setupRLE(RLEContext &Ctx, SILInstruction *I, SILValue Mem) {
711724

712725
// Reduce the available values into a single SILValue we can use to forward.
713726
SILModule *Mod = &I->getModule();
714-
SILValue TheForwardingValue = LSValue::reduce(L, Mod, Values, I);
727+
SILValue TheForwardingValue =
728+
LSValue::reduce(L, Mod, Values, I, Ctx.getJointPostDomSetComputer());
729+
715730
if (!TheForwardingValue)
716731
return false;
717732

@@ -849,11 +864,11 @@ void BlockState::processWrite(RLEContext &Ctx, SILInstruction *I, SILValue Mem,
849864
return;
850865
}
851866

867+
auto *Fn = I->getFunction();
852868
// Expand the given location and val into individual fields and process
853869
// them as separate writes.
854870
LSLocationList Locs;
855-
LSLocation::expand(L, &I->getModule(),
856-
TypeExpansionContext(*I->getFunction()), Locs,
871+
LSLocation::expand(L, &I->getModule(), TypeExpansionContext(*Fn), Locs,
857872
Ctx.getTE());
858873

859874
if (isComputeAvailSetMax(Kind)) {
@@ -873,8 +888,8 @@ void BlockState::processWrite(RLEContext &Ctx, SILInstruction *I, SILValue Mem,
873888

874889
// Are we computing available value or performing RLE?
875890
LSValueList Vals;
876-
LSValue::expand(Val, &I->getModule(), TypeExpansionContext(*I->getFunction()),
877-
Vals, Ctx.getTE());
891+
LSValue::expand(Val, &I->getModule(), TypeExpansionContext(*Fn), Vals,
892+
Ctx.getTE());
878893
if (isComputeAvailValue(Kind) || isPerformingRLE(Kind)) {
879894
for (unsigned i = 0; i < Locs.size(); ++i) {
880895
updateForwardSetAndValForWrite(Ctx, Ctx.getLocationBit(Locs[i]),
@@ -903,11 +918,11 @@ void BlockState::processRead(RLEContext &Ctx, SILInstruction *I, SILValue Mem,
903918
if (!L.isValid())
904919
return;
905920

921+
auto *Fn = I->getFunction();
906922
// Expand the given LSLocation and Val into individual fields and process
907923
// them as separate reads.
908924
LSLocationList Locs;
909-
LSLocation::expand(L, &I->getModule(),
910-
TypeExpansionContext(*I->getFunction()), Locs,
925+
LSLocation::expand(L, &I->getModule(), TypeExpansionContext(*Fn), Locs,
911926
Ctx.getTE());
912927

913928
if (isComputeAvailSetMax(Kind)) {
@@ -928,8 +943,8 @@ void BlockState::processRead(RLEContext &Ctx, SILInstruction *I, SILValue Mem,
928943
// Are we computing available values ?.
929944
bool CanForward = true;
930945
LSValueList Vals;
931-
LSValue::expand(Val, &I->getModule(), TypeExpansionContext(*I->getFunction()),
932-
Vals, Ctx.getTE());
946+
LSValue::expand(Val, &I->getModule(), TypeExpansionContext(*Fn), Vals,
947+
Ctx.getTE());
933948
if (isComputeAvailValue(Kind) || isPerformingRLE(Kind)) {
934949
for (unsigned i = 0; i < Locs.size(); ++i) {
935950
if (isTrackingLocation(ForwardSetIn, Ctx.getLocationBit(Locs[i])))
@@ -1194,10 +1209,13 @@ void BlockState::dump(RLEContext &Ctx) {
11941209

11951210
RLEContext::RLEContext(SILFunction *F, SILPassManager *PM, AliasAnalysis *AA,
11961211
TypeExpansionAnalysis *TE, PostOrderFunctionInfo *PO,
1197-
EpilogueARCFunctionInfo *EAFI, bool disableArrayLoads)
1212+
EpilogueARCFunctionInfo *EAFI, bool disableArrayLoads,
1213+
JointPostDominanceSetComputer &computer)
11981214
: Fn(F), PM(PM), AA(AA), TE(TE), PO(PO), EAFI(EAFI),
1199-
ArrayType(disableArrayLoads ?
1200-
F->getModule().getASTContext().getArrayDecl() : nullptr)
1215+
ArrayType(disableArrayLoads
1216+
? F->getModule().getASTContext().getArrayDecl()
1217+
: nullptr),
1218+
jointPostDomComputer(computer)
12011219
#ifndef NDEBUG
12021220
,
12031221
printCtx(llvm::dbgs(), /*Verbose=*/false, /*Sorted=*/true)
@@ -1322,8 +1340,8 @@ SILValue RLEContext::computePredecessorLocationValue(SILBasicBlock *BB,
13221340

13231341
// Reduce the available values into a single SILValue we can use to forward
13241342
SILInstruction *IPt = CurBB->getTerminator();
1325-
Values.push_back(
1326-
{CurBB, LSValue::reduce(L, &BB->getModule(), LSValues, IPt)});
1343+
Values.push_back({CurBB, LSValue::reduce(L, &BB->getModule(), LSValues, IPt,
1344+
&jointPostDomComputer)});
13271345
}
13281346

13291347
// Finally, collect all the values for the SILArgument, materialize it using
@@ -1335,7 +1353,8 @@ SILValue RLEContext::computePredecessorLocationValue(SILBasicBlock *BB,
13351353
Updater.addAvailableValue(V.first, V.second);
13361354
}
13371355

1338-
return Updater.getValueInMiddleOfBlock(BB);
1356+
auto Val = Updater.getValueInMiddleOfBlock(BB);
1357+
return makeNewValueAvailable(Val, BB, &jointPostDomComputer);
13391358
}
13401359

13411360
bool RLEContext::collectLocationValues(SILBasicBlock *BB, LSLocation &L,
@@ -1350,9 +1369,14 @@ bool RLEContext::collectLocationValues(SILBasicBlock *BB, LSLocation &L,
13501369
// Find the locations that this basic block defines and the locations which
13511370
// we do not have a concrete value in the current basic block.
13521371
for (auto &X : Locs) {
1353-
Values[X] = getValue(VM[getLocationBit(X)]);
1354-
if (!Values[X].isCoveringValue())
1372+
auto Val = getValue(VM[getLocationBit(X)]);
1373+
if (!Val.isCoveringValue()) {
1374+
auto AvailValue =
1375+
makeCopiedValueAvailable(Val.getBase(), BB, &jointPostDomComputer);
1376+
Values[X] = LSValue(AvailValue, Val.getPath().getValue());
13551377
continue;
1378+
}
1379+
Values[X] = Val;
13561380
CSLocs.push_back(X);
13571381
}
13581382

@@ -1367,7 +1391,6 @@ bool RLEContext::collectLocationValues(SILBasicBlock *BB, LSLocation &L,
13671391
SILValue V = computePredecessorLocationValue(BB, X);
13681392
if (!V)
13691393
return false;
1370-
13711394
// We've constructed a concrete value for the covering value. Expand and
13721395
// collect the newly created forwardable values.
13731396
LSLocationList Locs;
@@ -1610,9 +1633,15 @@ bool RLEContext::run() {
16101633
continue;
16111634
LLVM_DEBUG(llvm::dbgs() << "Replacing " << SILValue(Iter->first)
16121635
<< "With " << Iter->second);
1636+
auto *origLoad = cast<LoadInst>(Iter->first);
1637+
SILValue newValue = Iter->second;
1638+
if (origLoad->getOwnershipQualifier() == LoadOwnershipQualifier::Take) {
1639+
SILBuilderWithScope(origLoad).createDestroyAddr(origLoad->getLoc(),
1640+
origLoad->getOperand());
1641+
}
16131642
SILChanged = true;
1614-
Iter->first->replaceAllUsesWith(Iter->second);
1615-
InstsToDelete.push_back(Iter->first);
1643+
origLoad->replaceAllUsesWith(newValue);
1644+
InstsToDelete.push_back(origLoad);
16161645
++NumForwardedLoads;
16171646
}
16181647
}
@@ -1650,9 +1679,6 @@ class RedundantLoadElimination : public SILFunctionTransform {
16501679
/// The entry point to the transformation.
16511680
void run() override {
16521681
SILFunction *F = getFunction();
1653-
// FIXME: Handle ownership.
1654-
if (F->hasOwnership())
1655-
return;
16561682

16571683
LLVM_DEBUG(llvm::dbgs() << "*** RLE on function: " << F->getName()
16581684
<< " ***\n");
@@ -1662,7 +1688,9 @@ class RedundantLoadElimination : public SILFunctionTransform {
16621688
auto *PO = PM->getAnalysis<PostOrderAnalysis>()->get(F);
16631689
auto *EAFI = PM->getAnalysis<EpilogueARCAnalysis>()->get(F);
16641690

1665-
RLEContext RLE(F, PM, AA, TE, PO, EAFI, disableArrayLoads);
1691+
DeadEndBlocks deadEndBlocks(F);
1692+
JointPostDominanceSetComputer computer(deadEndBlocks);
1693+
RLEContext RLE(F, PM, AA, TE, PO, EAFI, disableArrayLoads, computer);
16661694
if (RLE.run()) {
16671695
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
16681696
}

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1963,3 +1963,53 @@ SILBasicBlock::iterator swift::replaceSingleUse(Operand *use, SILValue newValue,
19631963

19641964
return nextII;
19651965
}
1966+
1967+
SILValue swift::makeCopiedValueAvailable(
1968+
SILValue value, SILBasicBlock *inBlock,
1969+
JointPostDominanceSetComputer *jointPostDomComputer) {
1970+
if (!value->getFunction()->hasOwnership())
1971+
return value;
1972+
1973+
if (value->getType().isTrivial(*value->getFunction()))
1974+
return value;
1975+
1976+
auto insertPt = getInsertAfterPoint(value).getValue();
1977+
auto *copy =
1978+
SILBuilderWithScope(insertPt).createCopyValue(insertPt->getLoc(), value);
1979+
1980+
return makeNewValueAvailable(copy, inBlock, jointPostDomComputer);
1981+
}
1982+
1983+
SILValue swift::makeNewValueAvailable(
1984+
SILValue value, SILBasicBlock *inBlock,
1985+
JointPostDominanceSetComputer *jointPostDomComputer) {
1986+
if (!value->getFunction()->hasOwnership())
1987+
return value;
1988+
1989+
if (value->getType().isTrivial(*value->getFunction()))
1990+
return value;
1991+
1992+
assert(value->getUses().empty() &&
1993+
value.getOwnershipKind() == OwnershipKind::Owned);
1994+
1995+
// Use \p jointPostDomComputer to:
1996+
// 1. Create a control equivalent copy at \p inBlock if needed
1997+
// 2. Insert destroy_value at leaking blocks
1998+
SILValue controlEqCopy;
1999+
jointPostDomComputer->findJointPostDominatingSet(
2000+
value->getParentBlock(), inBlock,
2001+
[&](SILBasicBlock *loopBlock) {
2002+
assert(loopBlock == inBlock);
2003+
auto front = loopBlock->begin();
2004+
SILBuilderWithScope newBuilder(front);
2005+
controlEqCopy = newBuilder.createCopyValue(front->getLoc(), value);
2006+
},
2007+
[&](SILBasicBlock *postDomBlock) {
2008+
// Insert a destroy_value in the leaking block
2009+
auto front = postDomBlock->begin();
2010+
SILBuilderWithScope newBuilder(front);
2011+
newBuilder.createDestroyValue(front->getLoc(), value);
2012+
});
2013+
2014+
return controlEqCopy ? controlEqCopy : value;
2015+
}

0 commit comments

Comments
 (0)