Skip to content

Commit 0c6253e

Browse files
authored
Merge pull request #61824 from meg-gupta/simplifycfgossapr1
Update some parts of SimplifyCFG for OSSA
2 parents 3bac57d + 62901c2 commit 0c6253e

33 files changed

+1924
-1725
lines changed

include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -273,18 +273,8 @@ class BasicBlockCloner : public SILCloner<BasicBlockCloner> {
273273
bi->eraseFromParent();
274274
}
275275

276-
/// Create phis and maintain OSSA invariants.
277-
///
278-
/// Note: This must be called after calling cloneBlock or cloneBranchTarget,
279-
/// before using any OSSA utilities.
280-
///
281-
/// The client may perform arbitrary branch fixups and dead block removal
282-
/// after cloning and before calling this.
283-
///
284-
/// WARNING: If client converts terminator results to phis (e.g. replaces a
285-
/// switch_enum with a branch), then it must call this before performing that
286-
/// transformation, or fix the OSSA representation of that value itself.
287-
void updateOSSAAfterCloning();
276+
/// Helper function to perform SSA updates
277+
void updateSSAAfterCloning();
288278

289279
/// Get the newly cloned block corresponding to `origBB`.
290280
SILBasicBlock *getNewBB() {
@@ -294,13 +284,6 @@ class BasicBlockCloner : public SILCloner<BasicBlockCloner> {
294284
bool wasCloned() { return isBlockCloned(origBB); }
295285

296286
protected:
297-
/// Helper function to perform SSA updates used by updateOSSAAfterCloning.
298-
void updateSSAAfterCloning(SmallVectorImpl<SILPhiArgument *> &newPhis);
299-
300-
/// Given a terminator result, either from the original or the cloned block,
301-
/// update OSSA for any phis created for the result during edge splitting.
302-
void updateOSSATerminatorResult(SILPhiArgument *termResult);
303-
304287
// MARK: CRTP overrides.
305288

306289
/// Override getMappedValue to allow values defined outside the block to be

lib/SIL/IR/SILArgument.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ bool SILPhiArgument::getIncomingPhiOperands(
175175
return false;
176176

177177
const auto *parentBlock = getParent();
178-
assert(!parentBlock->pred_empty());
179178

180179
unsigned argIndex = getIndex();
181180
for (auto *predBlock : getParent()->getPredecessorBlocks()) {

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,9 @@ bool swift::onlyAffectsRefCount(SILInstruction *user) {
279279
switch (user->getKind()) {
280280
default:
281281
return false;
282-
case SILInstructionKind::AutoreleaseValueInst:
282+
case SILInstructionKind::CopyValueInst:
283283
case SILInstructionKind::DestroyValueInst:
284+
case SILInstructionKind::AutoreleaseValueInst:
284285
case SILInstructionKind::ReleaseValueInst:
285286
case SILInstructionKind::RetainValueInst:
286287
case SILInstructionKind::StrongReleaseInst:

lib/SIL/Verifier/SILOwnershipVerifier.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,10 @@ bool SILValueOwnershipChecker::isSubobjectProjectionWithLifetimeEndingUses(
620620
bool SILValueOwnershipChecker::
621621
hasGuaranteedForwardingIncomingPhiOperandsOnZeroOrAllPaths(
622622
SILPhiArgument *phi) const {
623+
// For a phi in a trivially dead block, return true.
624+
if (phi->getParentBlock()->pred_empty()) {
625+
return true;
626+
}
623627
bool foundGuaranteedForwardingPhiOperand = false;
624628
bool foundNonGuaranteedForwardingPhiOperand = false;
625629
phi->visitTransitiveIncomingPhiOperands([&](auto *, auto *operand) -> bool {

lib/SILOptimizer/Mandatory/DiagnoseInvalidEscapingCaptures.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,25 @@ static bool checkNoEscapePartialApplyUse(Operand *oper, FollowUse followUses) {
5555
isa<CopyBlockWithoutEscapingInst>(user))
5656
return false;
5757

58+
// Look through copies, borrows, and conversions.
59+
// getSingleValueCopyOrCast handles all result producing instructions for
60+
// which onlyAffectsRefCount returns true.
61+
if (SingleValueInstruction *copy = getSingleValueCopyOrCast(user)) {
62+
// Only follow the copied operand. Other operands are incidental,
63+
// as in the second operand of mark_dependence.
64+
if (oper->getOperandNumber() == 0)
65+
followUses(copy);
66+
67+
return false;
68+
}
69+
5870
// Ignore uses that are totally uninteresting. partial_apply [stack] is
5971
// terminated by a dealloc_stack instruction.
6072
if (isIncidentalUse(user) || onlyAffectsRefCount(user) ||
61-
isa<DeallocStackInst>(user))
73+
isa<DeallocStackInst>(user)) {
74+
assert(user->getNumResults() == 0);
6275
return false;
76+
}
6377

6478
// Before checking conversions in general below (getSingleValueCopyOrCast),
6579
// check for convert_function to [without_actually_escaping]. Assume such
@@ -69,16 +83,6 @@ static bool checkNoEscapePartialApplyUse(Operand *oper, FollowUse followUses) {
6983
return false;
7084
}
7185

72-
// Look through copies, borrows, and conversions.
73-
if (SingleValueInstruction *copy = getSingleValueCopyOrCast(user)) {
74-
// Only follow the copied operand. Other operands are incidental,
75-
// as in the second operand of mark_dependence.
76-
if (oper->getOperandNumber() == 0)
77-
followUses(copy);
78-
79-
return false;
80-
}
81-
8286
// Look through `differentiable_function`.
8387
if (auto *DFI = dyn_cast<DifferentiableFunctionInst>(user)) {
8488
followUses(DFI);

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ void DCE::markLive() {
292292
});
293293
};
294294
// If we have a begin_borrow of a @guaranteed operand, disable DCE'ing
295-
// of parent borrow scopes. Dead reborrows needs complex handling, whuch
295+
// of parent borrow scopes. Dead reborrows needs complex handling, which
296296
// is why it is disabled for now.
297297
if (borrowInst->getOperand()->getOwnershipKind() ==
298298
OwnershipKind::Guaranteed) {

lib/SILOptimizer/Transforms/SimplifyCFG.cpp

Lines changed: 48 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ bool SimplifyCFG::threadEdge(const ThreadInfo &ti) {
245245
dyn_cast<BranchInst>(ThreadedSuccessorBlock->getTerminator())) {
246246
simplifyBranchBlock(branchInst);
247247
}
248-
Cloner.updateOSSAAfterCloning();
248+
Cloner.updateSSAAfterCloning();
249249
return true;
250250
}
251251

@@ -924,6 +924,11 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) {
924924
if (destTerminator->isFunctionExiting())
925925
return false;
926926

927+
// There is no benefit duplicating such a destination.
928+
if (DestBB->getSinglePredecessorBlock() != nullptr) {
929+
return false;
930+
}
931+
927932
// Jump threading only makes sense if there is an argument on the branch
928933
// (which is reacted on in the DestBB), or if this goes through a memory
929934
// location (switch_enum_addr is the only address-instruction which we
@@ -942,6 +947,7 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) {
942947
for (unsigned i : indices(BI->getArgs())) {
943948
SILValue Arg = BI->getArg(i);
944949

950+
// TODO: Verify if we need to jump thread to remove releases in OSSA.
945951
// If the value being substituted on is release there is a chance we could
946952
// remove the release after jump threading.
947953
if (!Arg->getType().isTrivial(*SrcBB->getParent()) &&
@@ -1030,7 +1036,7 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) {
10301036
// Duplicate the destination block into this one, rewriting uses of the BBArgs
10311037
// to use the branch arguments as we go.
10321038
Cloner.cloneBranchTarget(BI);
1033-
Cloner.updateOSSAAfterCloning();
1039+
Cloner.updateSSAAfterCloning();
10341040

10351041
// Once all the instructions are copied, we can nuke BI itself. We also add
10361042
// the threaded and edge block to the worklist now that they (likely) can be
@@ -1278,13 +1284,13 @@ bool SimplifyCFG::simplifyBranchBlock(BranchInst *BI) {
12781284
//
12791285
SILBasicBlock *remainingBlock = nullptr, *deletedBlock = nullptr;
12801286
if (BB != Fn.getEntryBlock() && hasLessInstructions(BB, DestBB)) {
1287+
DestBB->spliceAtBegin(BB);
1288+
DestBB->dropAllArguments();
1289+
DestBB->moveArgumentList(BB);
12811290
while (!BB->pred_empty()) {
12821291
SILBasicBlock *pred = *BB->pred_begin();
12831292
replaceBranchTarget(pred->getTerminator(), BB, DestBB, true);
12841293
}
1285-
DestBB->spliceAtBegin(BB);
1286-
DestBB->dropAllArguments();
1287-
DestBB->moveArgumentList(BB);
12881294
remainingBlock = DestBB;
12891295
deletedBlock = BB;
12901296
} else {
@@ -1715,10 +1721,6 @@ static bool isOnlyUnreachable(SILBasicBlock *BB) {
17151721
/// switch_enum where all but one block consists of just an
17161722
/// "unreachable" with an unchecked_enum_data and branch.
17171723
bool SimplifyCFG::simplifySwitchEnumUnreachableBlocks(SwitchEnumInst *SEI) {
1718-
if (!EnableOSSARewriteTerminator && Fn.hasOwnership()) {
1719-
if (!SEI->getOperand()->getType().isTrivial(Fn))
1720-
return false;
1721-
}
17221724
auto Count = SEI->getNumCases();
17231725

17241726
SILBasicBlock *Dest = nullptr;
@@ -1851,7 +1853,9 @@ static bool containsOnlyObjMethodCallOnOptional(SILValue optionalValue,
18511853

18521854
// The branch should forward one of the objc_method call.
18531855
if (auto *br = dyn_cast<BranchInst>(inst)) {
1854-
if (br->getNumArgs() == 0 || br->getNumArgs() > 1)
1856+
if (br->getNumArgs() == 0)
1857+
continue;
1858+
if (br->getNumArgs() > 1)
18551859
return false;
18561860
auto branchArg = br->getArg(0);
18571861
if (std::find(objCApplies.begin(), objCApplies.end(), branchArg) ==
@@ -1899,6 +1903,9 @@ static bool onlyForwardsNone(SILBasicBlock *noneBB, SILBasicBlock *someBB,
18991903
continue;
19001904
}
19011905
if (auto *noneBranch = dyn_cast<BranchInst>(inst)) {
1906+
if (noneBranch->getNumArgs() == 0) {
1907+
continue;
1908+
}
19021909
if (noneBranch->getNumArgs() != 1 ||
19031910
(noneBranch->getArg(0) != SEI->getOperand() &&
19041911
noneBranch->getArg(0) != optionalNone))
@@ -2010,12 +2017,6 @@ static bool hasSameUltimateSuccessor(SILBasicBlock *noneBB, SILBasicBlock *someB
20102017
/// %4 = enum #Optional.none
20112018
/// br mergeBB(%4)
20122019
bool SimplifyCFG::simplifySwitchEnumOnObjcClassOptional(SwitchEnumInst *SEI) {
2013-
// TODO: OSSA; handle non-trivial enum case cleanup
2014-
// (simplify_switch_enum_objc.sil).
2015-
if (!EnableOSSARewriteTerminator && Fn.hasOwnership()) {
2016-
return false;
2017-
}
2018-
20192020
auto optional = SEI->getOperand();
20202021
auto optionalPayloadType = optional->getType().getOptionalObjectType();
20212022
if (!optionalPayloadType ||
@@ -2052,10 +2053,20 @@ bool SimplifyCFG::simplifySwitchEnumOnObjcClassOptional(SwitchEnumInst *SEI) {
20522053
optionalPayloadType);
20532054
optionalPayload->replaceAllUsesWith(payloadCast);
20542055
auto *switchBB = SEI->getParent();
2055-
if (someBB->getNumArguments())
2056-
Builder.createBranch(SEI->getLoc(), someBB, SILValue(payloadCast));
2057-
else
2056+
2057+
if (!someBB->args_empty()) {
2058+
assert(someBB->getNumArguments() == 1);
2059+
auto *someBBArg = someBB->getArgument(0);
2060+
if (!someBBArg->use_empty()) {
2061+
assert(optionalPayload != someBBArg);
2062+
someBBArg->replaceAllUsesWith(payloadCast);
2063+
}
2064+
someBB->eraseArgument(0);
2065+
Builder.createBranch(SEI->getLoc(), someBB);
2066+
} else {
2067+
assert(!Fn.hasOwnership());
20582068
Builder.createBranch(SEI->getLoc(), someBB);
2069+
}
20592070

20602071
SEI->eraseFromParent();
20612072
addToWorklist(switchBB);
@@ -2076,12 +2087,6 @@ bool SimplifyCFG::simplifySwitchEnumBlock(SwitchEnumInst *SEI) {
20762087
auto *LiveBlock = SEI->getCaseDestination(EnumCase.get());
20772088
auto *ThisBB = SEI->getParent();
20782089

2079-
if (!EnableOSSARewriteTerminator && Fn.hasOwnership()) {
2080-
// TODO: OSSA; cleanup terminator results.
2081-
if (!SEI->getOperand()->getType().isTrivial(Fn))
2082-
return false;
2083-
}
2084-
20852090
bool DroppedLiveBlock = false;
20862091
// Copy the successors into a vector, dropping one entry for the liveblock.
20872092
SmallVector<SILBasicBlock*, 4> Dests;
@@ -2096,29 +2101,27 @@ bool SimplifyCFG::simplifySwitchEnumBlock(SwitchEnumInst *SEI) {
20962101
LLVM_DEBUG(llvm::dbgs() << "fold switch " << *SEI);
20972102

20982103
auto *EI = dyn_cast<EnumInst>(SEI->getOperand());
2104+
auto loc = SEI->getLoc();
20992105
SILBuilderWithScope Builder(SEI);
21002106
if (!LiveBlock->args_empty()) {
21012107
SILValue PayLoad;
21022108
if (SEI->hasDefault() && LiveBlock == SEI->getDefaultBB()) {
21032109
assert(Fn.hasOwnership() && "Only OSSA default case has an argument");
21042110
PayLoad = SEI->getOperand();
21052111
} else {
2106-
if (EI) {
2107-
PayLoad = EI->getOperand();
2108-
} else {
2109-
PayLoad = Builder.createUncheckedEnumData(SEI->getLoc(),
2110-
SEI->getOperand(),
2111-
EnumCase.get());
2112-
}
2112+
PayLoad = Builder.createUncheckedEnumData(loc, SEI->getOperand(),
2113+
EnumCase.get());
21132114
}
2114-
Builder.createBranch(SEI->getLoc(), LiveBlock, PayLoad);
2115+
Builder.createBranch(loc, LiveBlock, PayLoad);
21152116
} else {
2116-
Builder.createBranch(SEI->getLoc(), LiveBlock);
2117+
Builder.createBranch(loc, LiveBlock);
21172118
}
2119+
21182120
SEI->eraseFromParent();
2119-
// TODO: also remove this EnumInst in OSSA default case when the only
2120-
// remaining uses are destroys, and incidental uses.
2121-
if (EI && EI->use_empty()) EI->eraseFromParent();
2121+
if (EI && isInstructionTriviallyDead(EI)) {
2122+
EI->replaceAllUsesOfAllResultsWithUndef();
2123+
EI->eraseFromParent();
2124+
}
21222125

21232126
addToWorklist(ThisBB);
21242127

@@ -2547,15 +2550,6 @@ bool SimplifyCFG::simplifyTermWithIdenticalDestBlocks(SILBasicBlock *BB) {
25472550
return false;
25482551
}
25492552
TermInst *Term = BB->getTerminator();
2550-
// TODO: OSSA; cleanup nontrivial terminator operands (if this ever actually
2551-
// happens)
2552-
if (!EnableOSSARewriteTerminator && Fn.hasOwnership()) {
2553-
if (llvm::any_of(Term->getOperandValues(), [this](SILValue op) {
2554-
return !op->getType().isTrivial(Fn);
2555-
})) {
2556-
return false;
2557-
}
2558-
}
25592553
LLVM_DEBUG(llvm::dbgs() << "replace term with identical dests: " << *Term);
25602554
SILBuilderWithScope(Term).createBranch(Term->getLoc(), commonDest.destBB,
25612555
commonDest.newSourceBranchArgs);
@@ -2877,7 +2871,7 @@ bool SimplifyCFG::tailDuplicateObjCMethodCallSuccessorBlocks() {
28772871
continue;
28782872

28792873
Cloner.cloneBranchTarget(Branch);
2880-
Cloner.updateOSSAAfterCloning();
2874+
Cloner.updateSSAAfterCloning();
28812875

28822876
Changed = true;
28832877
// Simplify the cloned block and continue tail duplicating through its new
@@ -3832,16 +3826,21 @@ bool SimplifyCFG::simplifyArgument(SILBasicBlock *BB, unsigned i) {
38323826
// the uses in this block, and then rewrite the branch operands.
38333827
LLVM_DEBUG(llvm::dbgs() << "unwrap argument:" << *A);
38343828
A->replaceAllUsesWith(SILUndef::get(A->getType(), *BB->getParent()));
3835-
auto *NewArg =
3836-
BB->replacePhiArgument(i, proj->getType(), OwnershipKind::Owned);
3829+
auto *NewArg = BB->replacePhiArgument(i, proj->getType(),
3830+
BB->getArgument(i)->getOwnershipKind());
38373831
proj->replaceAllUsesWith(NewArg);
38383832

38393833
// Rewrite the branch operand for each incoming branch.
38403834
for (auto *Pred : BB->getPredecessorBlocks()) {
38413835
if (auto *Branch = cast<BranchInst>(Pred->getTerminator())) {
3836+
auto *BranchOpValue = cast<SingleValueInstruction>(Branch->getOperand(i));
38423837
auto V = getInsertedValue(cast<SingleValueInstruction>(Branch->getArg(i)),
38433838
proj);
38443839
Branch->setOperand(i, V);
3840+
if (isInstructionTriviallyDead(BranchOpValue)) {
3841+
BranchOpValue->replaceAllUsesWithUndef();
3842+
BranchOpValue->eraseFromParent();
3843+
}
38453844
addToWorklist(Pred);
38463845
}
38473846
}
@@ -3887,15 +3886,6 @@ bool SimplifyCFG::simplifyArgs(SILBasicBlock *BB) {
38873886
if (BB->pred_empty())
38883887
return false;
38893888

3890-
if (!EnableOSSARewriteTerminator && Fn.hasOwnership()) {
3891-
// TODO: OSSA phi support
3892-
if (llvm::any_of(BB->getArguments(), [this](SILArgument *arg) {
3893-
return !arg->getType().isTrivial(Fn);
3894-
})) {
3895-
return false;
3896-
}
3897-
}
3898-
38993889
// Ignore blocks that are successors of terminators with mandatory args.
39003890
for (SILBasicBlock *pred : BB->getPredecessorBlocks()) {
39013891
if (hasMandatoryArgument(pred->getTerminator()))

0 commit comments

Comments
 (0)