Skip to content

Commit 39f74bb

Browse files
authored
Merge pull request #40002 from meg-gupta/newfixoutliner
Fix OSSA Outliner for scoped guaranteed values
2 parents 3c606c3 + 2b0e101 commit 39f74bb

File tree

6 files changed

+298
-24
lines changed

6 files changed

+298
-24
lines changed

include/swift/SIL/BasicBlockUtils.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,11 @@ class DeadEndBlocks {
9191
/// the set of reachable blocks.
9292
void updateForReachableBlock(SILBasicBlock *reachableBB);
9393

94+
/// Add new blocks to the set of reachable blocks.
95+
void updateForNewBlock(SILBasicBlock *newBB);
96+
9497
const SILFunction *getFunction() const { return f; }
95-
98+
9699
/// Performs a simple check if \p block (or its single successor) ends in an
97100
/// "unreachable".
98101
///

include/swift/SILOptimizer/Utils/OwnershipOptUtils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ void extendLocalBorrow(BeginBorrowInst *beginBorrow,
7373
/// newly created phis do not yet have a borrow scope.
7474
bool createBorrowScopeForPhiOperands(SILPhiArgument *newPhi);
7575

76+
SILValue
77+
makeGuaranteedValueAvailable(SILValue value, SILInstruction *user,
78+
DeadEndBlocks &deBlocks,
79+
InstModCallbacks callbacks = InstModCallbacks());
80+
7681
//===----------------------------------------------------------------------===//
7782
// GuaranteedOwnershipExtension
7883
//===----------------------------------------------------------------------===//

lib/SIL/Utils/BasicBlockUtils.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,16 @@ void DeadEndBlocks::updateForReachableBlock(SILBasicBlock *reachableBB) {
404404
propagateNewlyReachableBlocks(numReachable);
405405
}
406406

407+
void DeadEndBlocks::updateForNewBlock(SILBasicBlock *newBB) {
408+
if (!didComputeValue)
409+
return;
410+
411+
assert(reachableBlocks.count(newBB) == 0);
412+
unsigned numReachable = reachableBlocks.size();
413+
reachableBlocks.insert(newBB);
414+
propagateNewlyReachableBlocks(numReachable);
415+
}
416+
407417
bool DeadEndBlocks::triviallyEndsInUnreachable(SILBasicBlock *block) {
408418
// Handle the case where a single "unreachable" block (e.g. containing a call
409419
// to fatalError()), is jumped to from multiple source blocks.

lib/SILOptimizer/Transforms/Outliner.cpp

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,19 @@
1919
#include "swift/Demangling/Demangler.h"
2020
#include "swift/Demangling/ManglingMacros.h"
2121
#include "swift/SIL/ApplySite.h"
22+
#include "swift/SIL/BasicBlockDatastructures.h"
23+
#include "swift/SIL/BasicBlockUtils.h"
2224
#include "swift/SIL/DebugUtils.h"
2325
#include "swift/SIL/DynamicCasts.h"
2426
#include "swift/SIL/SILArgument.h"
2527
#include "swift/SIL/SILBuilder.h"
2628
#include "swift/SIL/SILFunction.h"
2729
#include "swift/SIL/SILInstruction.h"
2830
#include "swift/SIL/SILModule.h"
29-
#include "swift/SIL/BasicBlockDatastructures.h"
31+
#include "swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
3032
#include "swift/SILOptimizer/PassManager/Passes.h"
3133
#include "swift/SILOptimizer/PassManager/Transforms.h"
34+
#include "swift/SILOptimizer/Utils/OwnershipOptUtils.h"
3235
#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h"
3336
#include "llvm/ADT/BitVector.h"
3437
#include "llvm/Support/CommandLine.h"
@@ -118,9 +121,14 @@ namespace {
118121
class OutlinePattern {
119122
protected:
120123
SILOptFunctionBuilder &FuncBuilder;
124+
InstModCallbacks callbacks;
125+
DeadEndBlocks *deBlocks;
121126

122127
public:
123-
OutlinePattern(SILOptFunctionBuilder &FuncBuilder) : FuncBuilder(FuncBuilder) {}
128+
OutlinePattern(SILOptFunctionBuilder &FuncBuilder,
129+
InstModCallbacks callbacks,
130+
DeadEndBlocks *deBlocks)
131+
: FuncBuilder(FuncBuilder), callbacks(callbacks), deBlocks(deBlocks) {}
124132

125133
/// Match the instruction sequence.
126134
virtual bool matchInstSequence(SILBasicBlock::iterator I) = 0;
@@ -233,7 +241,10 @@ class BridgedProperty : public OutlinePattern {
233241
std::pair<SILFunction *, SILBasicBlock::iterator>
234242
outline(SILModule &M) override;
235243

236-
BridgedProperty(SILOptFunctionBuilder &FuncBuilder) : OutlinePattern(FuncBuilder) {
244+
BridgedProperty(SILOptFunctionBuilder &FuncBuilder,
245+
InstModCallbacks callbacks,
246+
DeadEndBlocks *deBlocks)
247+
: OutlinePattern(FuncBuilder, callbacks, deBlocks) {
237248
clearState();
238249
}
239250

@@ -352,7 +363,9 @@ BridgedProperty::outline(SILModule &M) {
352363
auto *OutlinedEntryBB = StartBB->split(SILBasicBlock::iterator(FirstInst));
353364
auto *OldMergeBB = switchInfo.Br->getDestBB();
354365
auto *NewTailBB = OldMergeBB->split(OldMergeBB->begin());
355-
366+
if (deBlocks) {
367+
deBlocks->updateForNewBlock(NewTailBB);
368+
}
356369
// Call the outlined function.
357370
{
358371
SILBuilder Builder(StartBB);
@@ -900,8 +913,11 @@ namespace {
900913
//
901914
// bb3(%32 : $Optional<String>):
902915
class BridgedReturn {
916+
DeadEndBlocks *deBlocks;
903917
SwitchInfo switchInfo;
904918
public:
919+
BridgedReturn(DeadEndBlocks *deBlocks) : deBlocks(deBlocks) {}
920+
905921
bool match(ApplyInst *BridgedCall) {
906922
switchInfo = SwitchInfo();
907923
auto *SwitchBB = BridgedCall->getParent();
@@ -941,7 +957,10 @@ void BridgedReturn::outline(SILFunction *Fun, ApplyInst *NewOutlinedCall) {
941957
auto *OutlinedEntryBB = StartBB->split(SILBasicBlock::iterator(switchInfo.SwitchEnum));
942958
auto *OldMergeBB = switchInfo.Br->getDestBB();
943959
auto *NewTailBB = OldMergeBB->split(OldMergeBB->begin());
944-
auto Loc = switchInfo.SwitchEnum->getLoc();
960+
if (deBlocks) {
961+
deBlocks->updateForNewBlock(NewTailBB);
962+
}
963+
auto Loc = switchInfo.SwitchEnum->getLoc();
945964

946965
{
947966
SILBuilder Builder(StartBB);
@@ -992,8 +1011,10 @@ class ObjCMethodCall : public OutlinePattern {
9921011
std::pair<SILFunction *, SILBasicBlock::iterator>
9931012
outline(SILModule &M) override;
9941013

995-
ObjCMethodCall(SILOptFunctionBuilder &FuncBuilder)
996-
: OutlinePattern(FuncBuilder) {}
1014+
ObjCMethodCall(SILOptFunctionBuilder &FuncBuilder,
1015+
InstModCallbacks callbacks,
1016+
DeadEndBlocks *deBlocks)
1017+
: OutlinePattern(FuncBuilder, callbacks, deBlocks), BridgedReturn(deBlocks) {}
9971018
~ObjCMethodCall();
9981019

9991020
private:
@@ -1043,7 +1064,12 @@ ObjCMethodCall::outline(SILModule &M) {
10431064
for (auto Arg : BridgedCall->getArguments()) {
10441065
if (BridgedArgIdx < BridgedArguments.size() &&
10451066
BridgedArguments[BridgedArgIdx].Idx == OrigSigIdx) {
1046-
Args.push_back(BridgedArguments[BridgedArgIdx].bridgedValue());
1067+
auto bridgedArgValue = BridgedArguments[BridgedArgIdx].bridgedValue();
1068+
if (bridgedArgValue.getOwnershipKind() == OwnershipKind::Guaranteed) {
1069+
bridgedArgValue = makeGuaranteedValueAvailable(
1070+
bridgedArgValue, BridgedCall, *deBlocks);
1071+
}
1072+
Args.push_back(bridgedArgValue);
10471073
++BridgedArgIdx;
10481074
} else {
10491075
// Otherwise, use the original type convention.
@@ -1263,9 +1289,11 @@ class OutlinePatterns {
12631289
return nullptr;
12641290
}
12651291

1266-
OutlinePatterns(SILOptFunctionBuilder &FuncBuilder)
1267-
: BridgedPropertyPattern(FuncBuilder),
1268-
ObjCMethodCallPattern(FuncBuilder) {}
1292+
OutlinePatterns(SILOptFunctionBuilder &FuncBuilder,
1293+
InstModCallbacks callbacks,
1294+
DeadEndBlocks *deBlocks)
1295+
: BridgedPropertyPattern(FuncBuilder, callbacks, deBlocks),
1296+
ObjCMethodCallPattern(FuncBuilder, callbacks, deBlocks) {}
12691297
~OutlinePatterns() {}
12701298

12711299
OutlinePatterns(const OutlinePatterns&) = delete;
@@ -1277,9 +1305,11 @@ class OutlinePatterns {
12771305
/// Perform outlining on the function and return any newly created outlined
12781306
/// functions.
12791307
bool tryOutline(SILOptFunctionBuilder &FuncBuilder, SILFunction *Fun,
1280-
SmallVectorImpl<SILFunction *> &FunctionsAdded) {
1308+
SmallVectorImpl<SILFunction *> &FunctionsAdded,
1309+
InstModCallbacks callbacks = InstModCallbacks(),
1310+
DeadEndBlocks *deBlocks = nullptr) {
12811311
BasicBlockWorklist Worklist(Fun->getEntryBlock());
1282-
OutlinePatterns patterns(FuncBuilder);
1312+
OutlinePatterns patterns(FuncBuilder, callbacks, deBlocks);
12831313
bool changed = false;
12841314

12851315
// Traverse the function.
@@ -1329,9 +1359,21 @@ class Outliner : public SILFunctionTransform {
13291359
Fun->dump();
13301360
}
13311361

1362+
DeadEndBlocksAnalysis *deBlocksAnalysis =
1363+
PM->getAnalysis<DeadEndBlocksAnalysis>();
1364+
DeadEndBlocks *deBlocks = deBlocksAnalysis->get(Fun);
1365+
InstModCallbacks callbacks;
1366+
13321367
SILOptFunctionBuilder FuncBuilder(*this);
13331368
SmallVector<SILFunction *, 16> FunctionsAdded;
1334-
bool Changed = tryOutline(FuncBuilder, Fun, FunctionsAdded);
1369+
bool Changed = false;
1370+
1371+
if (Fun->hasOwnership()) {
1372+
Changed =
1373+
tryOutline(FuncBuilder, Fun, FunctionsAdded, callbacks, deBlocks);
1374+
} else {
1375+
Changed = tryOutline(FuncBuilder, Fun, FunctionsAdded);
1376+
}
13351377

13361378
if (!FunctionsAdded.empty()) {
13371379
// Notify the pass manager of any new functions we outlined.

lib/SILOptimizer/Utils/OwnershipOptUtils.cpp

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,12 @@ struct OwnershipLifetimeExtender {
643643
SILBasicBlock::iterator borrowPoint,
644644
RangeTy guaranteedUsePoints);
645645

646+
template <typename RangeTy>
647+
BeginBorrowInst *
648+
borrowCopyOverGuaranteedUsers(SILValue newValue,
649+
SILBasicBlock::iterator borrowPoint,
650+
RangeTy guaranteedUsers);
651+
646652
/// Borrow \p newValue over the lifetime of \p guaranteedValue. Return the
647653
/// new guaranteed value.
648654
SILValue borrowOverValue(SILValue newValue, SILValue guaranteedValue);
@@ -654,6 +660,10 @@ struct OwnershipLifetimeExtender {
654660
/// the BorrowedValue that begins the scope.
655661
SILValue borrowOverSingleUse(SILValue newValue,
656662
Operand *singleGuaranteedUse);
663+
664+
SILValue
665+
borrowOverSingleNonLifetimeEndingUser(SILValue newValue,
666+
SILInstruction *nonLifetimeEndingUser);
657667
};
658668

659669
} // end anonymous namespace
@@ -780,9 +790,9 @@ OwnershipLifetimeExtender::borrowCopyOverScope(SILValue newValue,
780790
///
781791
/// Precondition: None of \p guaranteedUses are lifetime ending.
782792
template <typename RangeTy>
783-
BeginBorrowInst *OwnershipLifetimeExtender::borrowCopyOverGuaranteedUses(
793+
BeginBorrowInst *OwnershipLifetimeExtender::borrowCopyOverGuaranteedUsers(
784794
SILValue newValue, SILBasicBlock::iterator borrowPoint,
785-
RangeTy guaranteedUsePoints) {
795+
RangeTy guaranteedUsers) {
786796

787797
auto loc = RegularLocation::getAutoGeneratedLocation(borrowPoint->getLoc());
788798

@@ -794,12 +804,11 @@ BeginBorrowInst *OwnershipLifetimeExtender::borrowCopyOverGuaranteedUses(
794804

795805
// Create end_borrows at the end of the borrow's lifetime.
796806
{
797-
// We don't expect an empty guaranteedUsePoints. If it happens, then the
807+
// We don't expect an empty guaranteedUsers. If it happens, then the
798808
// newly created copy will never be destroyed.
799-
assert(!guaranteedUsePoints.empty());
809+
assert(!guaranteedUsers.empty());
800810

801-
auto opRange = makeUserRange(guaranteedUsePoints);
802-
ValueLifetimeAnalysis lifetimeAnalysis(borrow, opRange);
811+
ValueLifetimeAnalysis lifetimeAnalysis(borrow, guaranteedUsers);
803812
ValueLifetimeBoundary borrowBoundary;
804813
lifetimeAnalysis.computeLifetimeBoundary(borrowBoundary);
805814

@@ -834,6 +843,14 @@ BeginBorrowInst *OwnershipLifetimeExtender::borrowCopyOverGuaranteedUses(
834843
return borrow;
835844
}
836845

846+
template <typename RangeTy>
847+
BeginBorrowInst *OwnershipLifetimeExtender::borrowCopyOverGuaranteedUses(
848+
SILValue newValue, SILBasicBlock::iterator borrowPoint,
849+
RangeTy guaranteedUsePoints) {
850+
return borrowCopyOverGuaranteedUsers(newValue, borrowPoint,
851+
makeUserRange(guaranteedUsePoints));
852+
}
853+
837854
// Return the borrow position when replacing guaranteedValue with newValue.
838855
//
839856
// Precondition: newValue's block dominates and reaches guaranteedValue's block.
@@ -944,6 +961,27 @@ OwnershipLifetimeExtender::borrowOverSingleUse(SILValue newValue,
944961
return newBeginBorrow;
945962
}
946963

964+
SILValue OwnershipLifetimeExtender::borrowOverSingleNonLifetimeEndingUser(
965+
SILValue newValue, SILInstruction *nonLifetimeEndingUser) {
966+
// Avoid borrowing guaranteed function arguments.
967+
if (isa<SILFunctionArgument>(newValue) &&
968+
newValue.getOwnershipKind() == OwnershipKind::Guaranteed) {
969+
return newValue;
970+
}
971+
auto borrowPt = newValue->getNextInstruction()->getIterator();
972+
return borrowCopyOverGuaranteedUsers(
973+
newValue, borrowPt, ArrayRef<SILInstruction *>(nonLifetimeEndingUser));
974+
}
975+
976+
SILValue swift::makeGuaranteedValueAvailable(SILValue value,
977+
SILInstruction *user,
978+
DeadEndBlocks &deBlocks,
979+
InstModCallbacks callbacks) {
980+
OwnershipFixupContext ctx{callbacks, deBlocks};
981+
OwnershipLifetimeExtender extender{ctx};
982+
return extender.borrowOverSingleNonLifetimeEndingUser(value, user);
983+
}
984+
947985
//===----------------------------------------------------------------------===//
948986
// OwnershipRAUWUtility - RAUW + fix ownership
949987
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)