Skip to content

Commit be793d2

Browse files
committed
Remove last bit of retain release code motion in SILCodeMotion. All these code are
replaced by retain release code motion. This code has been disabled for sometime now. This should bring the retain release code motion into a close. The retain release code motion pipeline looks like this. There could be some minor cleanups after this though. 1. We perform a global data flow for retain release code motion in RRCM (RetainReleaseCodeMotion) 2. We perform a local form of retain release code motion in SILCodeMotion. This is more for cases which can not be handled in RRCM. e.g. sinking into a switch is more efficiently done in a local form, the retain is not needed on the None block. Release on SILArgument needs to be split to incoming values, this can not be done in RRCM and other cases. 3. We do not perform code motion in ASO, only elimination which are very important. Some modifications to test cases, they look different, but functionally the same. RRCM has this canonicalization effect, i.e. it uses the rc root, instead of the SSA value the retain/release is currently using. As a result some test cases need to be modified. I also removed some test cases that do not make sense anymore and lot of duplicate test cases between earlycodemotion.sil and latecodemotion.sil. These tests cases only have retains and should be used to test early code motion.
1 parent ecb4140 commit be793d2

File tree

8 files changed

+95
-721
lines changed

8 files changed

+95
-721
lines changed

include/swift/SILOptimizer/Utils/CFG.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ SILBasicBlock *splitBasicBlockAndBranch(SILBuilder &B,
115115
SILInstruction *SplitBeforeInst,
116116
DominanceInfo *DT, SILLoopInfo *LI);
117117

118+
/// \brief Return true if the function has a critical edge, false otherwise.
119+
bool hasCriticalEdges(SILFunction &F, bool OnlyNonCondBr);
120+
118121
/// \brief Split all critical edges in the function updating the dominator tree
119122
/// and loop information (if they are not set to null). If \p OnlyNonCondBr is
120123
/// true this will not split cond_br edges (Only edges which can't carry

lib/SILOptimizer/Transforms/RetainReleaseCodeMotion.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ STATISTIC(NumRetainsSunk, "Number of retains sunk");
9494
STATISTIC(NumReleasesHoisted, "Number of releases hoisted");
9595

9696
llvm::cl::opt<bool> DisableRRCodeMotion("disable-rr-cm", llvm::cl::init(false));
97+
llvm::cl::opt<bool> DisableIfWithCriticalEdge("disable-with-critical-edge", llvm::cl::init(false));
9798

9899
//===----------------------------------------------------------------------===//
99100
// Utility
@@ -1005,6 +1006,11 @@ class RRCodeMotion : public SILFunctionTransform {
10051006
if (!F->shouldOptimize())
10061007
return;
10071008

1009+
// Return if there is critical edge and we are disabling critical edge
1010+
// splitting.
1011+
if (DisableIfWithCriticalEdge && hasCriticalEdges(*F, false))
1012+
return;
1013+
10081014
DEBUG(llvm::dbgs() << "*** RRCM on function: " << F->getName() << " ***\n");
10091015
// Split all critical edges.
10101016
//

lib/SILOptimizer/Transforms/SILCodeMotion.cpp

Lines changed: 23 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -852,10 +852,11 @@ static bool tryToSinkRefCountAcrossSelectEnum(CondBranchInst *CondBr,
852852
return true;
853853
}
854854

855-
static bool tryToSinkRefCountInst(SILBasicBlock::iterator T,
856-
SILBasicBlock::iterator I,
857-
bool CanSinkToSuccessors, AliasAnalysis *AA,
858-
RCIdentityFunctionInfo *RCIA) {
855+
static bool tryTosinkIncrementsIntoSwitchRegions(SILBasicBlock::iterator T,
856+
SILBasicBlock::iterator I,
857+
bool CanSinkToSuccessors,
858+
AliasAnalysis *AA,
859+
RCIdentityFunctionInfo *RCIA) {
859860
// The following methods should only be attempted if we can sink to our
860861
// successor.
861862
if (CanSinkToSuccessors) {
@@ -874,168 +875,15 @@ static bool tryToSinkRefCountInst(SILBasicBlock::iterator T,
874875
return true;
875876
}
876877

877-
if (!isa<StrongRetainInst>(I) && !isa<RetainValueInst>(I))
878-
return false;
879-
880-
SILValue Ptr = I->getOperand(0);
881-
if (auto B = valueHasARCDecrementOrCheckInInstructionRange(Ptr, std::next(I),
882-
T, AA)) {
883-
DEBUG(llvm::dbgs() << " Moving " << *I);
884-
I->moveBefore(&**B);
885-
return true;
886-
}
887-
888-
// Ok, we have a ref count instruction that *could* be sunk. If we have a
889-
// terminator that we cannot sink through or the cfg will not let us sink
890-
// into our predecessors, just move the increment before the terminator.
891-
if (!CanSinkToSuccessors ||
892-
(!isa<CheckedCastBranchInst>(T) && !isa<CondBranchInst>(T))) {
893-
DEBUG(llvm::dbgs() << " Moving " << *I);
894-
I->moveBefore(&*T);
895-
return true;
896-
}
897-
898-
// Ok, it is legal for us to sink this increment to our successors. Create a
899-
// copy of this instruction in each one of our successors unless they are
900-
// ignorable trap blocks.
901-
DEBUG(llvm::dbgs() << " Sinking " << *I);
902-
SILBuilderWithScope Builder(T, &*I);
903-
for (auto &Succ : T->getParent()->getSuccessors()) {
904-
SILBasicBlock *SuccBB = Succ.getBB();
905-
906-
if (isARCInertTrapBB(SuccBB))
907-
continue;
908-
909-
Builder.setInsertionPoint(&*SuccBB->begin());
910-
if (isa<StrongRetainInst>(I)) {
911-
Builder.createStrongRetain(I->getLoc(), Ptr, Atomicity::Atomic);
912-
} else {
913-
assert(isa<RetainValueInst>(I) && "This can only be retain_value");
914-
Builder.createRetainValue(I->getLoc(), Ptr, Atomicity::Atomic);
915-
}
916-
}
917-
918-
// Then erase this instruction.
919-
I->eraseFromParent();
920-
NumSunk++;
921-
return true;
922-
}
923-
924-
static bool isRetainAvailableInSomeButNotAllPredecessors(
925-
SILValue Ptr, SILBasicBlock *BB, AliasAnalysis *AA,
926-
RCIdentityFunctionInfo *RCIA,
927-
llvm::SmallDenseMap<SILBasicBlock *, Optional<SILInstruction *>, 4>
928-
&CheckUpToInstruction) {
929-
bool AvailInSome = false;
930-
bool NotAvailInSome = false;
931-
932-
Ptr = RCIA->getRCIdentityRoot(Ptr);
933-
934-
// Check whether a retain on the pointer is available in the predecessors.
935-
for (auto *Pred : BB->getPreds()) {
936-
937-
// Find the first retain of the pointer.
938-
auto Retain = std::find_if(
939-
Pred->rbegin(), Pred->rend(), [=](const SILInstruction &I) -> bool {
940-
if (!isa<StrongRetainInst>(I) && !isa<RetainValueInst>(I))
941-
return false;
942-
943-
return Ptr == RCIA->getRCIdentityRoot(I.getOperand(0));
944-
});
945-
946-
// Check that there is no decrement or check from the increment to the end
947-
// of the basic block. After we have hoisted the first release this release
948-
// would prevent further hoisting. Instead we check that no decrement or
949-
// check occurs up to this hoisted release.
950-
auto End = CheckUpToInstruction[Pred];
951-
auto EndIt = SILBasicBlock::iterator(End ? *End : Pred->getTerminator());
952-
if (Retain == Pred->rend() || valueHasARCDecrementOrCheckInInstructionRange(
953-
Ptr, Retain->getIterator(), EndIt, AA)) {
954-
NotAvailInSome = true;
955-
continue;
956-
}
957-
958-
// Alright, the retain is 'available' for merging with a release from a
959-
// successor block.
960-
AvailInSome = true;
961-
}
962-
963-
return AvailInSome && NotAvailInSome;
878+
// At this point, this is a retain on a regular SSA value, leave it to retain
879+
// release code motion to sink.
880+
return false;
964881
}
965882

966-
static bool hoistDecrementsToPredecessors(SILBasicBlock *BB, AliasAnalysis *AA,
967-
RCIdentityFunctionInfo *RCIA) {
968-
if (BB->getSinglePredecessor())
969-
return false;
970-
971-
// Make sure we can move potential decrements to the predecessors and collect
972-
// retains we could match.
973-
for (auto *Pred : BB->getPreds())
974-
if (!Pred->getSingleSuccessor())
975-
return false;
976-
977-
bool HoistedDecrement = false;
978-
979-
// When we hoist a release to the predecessor block this release would block
980-
// hoisting further releases because it looks like a ARC decrement in the
981-
// predecessor block. Instead once we hoisted a release we scan only to this
982-
// release when looking for ARC decrements or checks.
983-
llvm::SmallDenseMap<SILBasicBlock *, Optional<SILInstruction *>, 4>
984-
CheckUpToInstruction;
985-
986-
for (auto It = BB->begin(); It != BB->end();) {
987-
auto *Inst = &*It;
988-
++It;
989-
990-
if (!isa<StrongReleaseInst>(Inst) && !isa<ReleaseValueInst>(Inst))
991-
continue;
992-
993-
SILValue Ptr = Inst->getOperand(0);
994-
995-
// The pointer must be defined outside of this basic block.
996-
if (Ptr->getParentBB() == BB)
997-
continue;
998-
999-
// No arc use to the beginning of this block.
1000-
if (valueHasARCUsesInInstructionRange(Ptr, BB->begin(), Inst->getIterator(),
1001-
AA))
1002-
continue;
1003-
1004-
if (!isRetainAvailableInSomeButNotAllPredecessors(Ptr, BB, AA, RCIA,
1005-
CheckUpToInstruction))
1006-
continue;
1007-
1008-
// Hoist decrement to predecessors.
1009-
DEBUG(llvm::dbgs() << " Hoisting " << *Inst);
1010-
SILBuilderWithScope Builder(Inst);
1011-
for (auto *PredBB : BB->getPreds()) {
1012-
Builder.setInsertionPoint(PredBB->getTerminator());
1013-
SILInstruction *Release;
1014-
if (isa<StrongReleaseInst>(Inst)) {
1015-
Release =
1016-
Builder.createStrongRelease(Inst->getLoc(), Ptr, Atomicity::Atomic);
1017-
} else {
1018-
assert(isa<ReleaseValueInst>(Inst) && "This can only be retain_value");
1019-
Release =
1020-
Builder.createReleaseValue(Inst->getLoc(), Ptr, Atomicity::Atomic);
1021-
}
1022-
// Update the last instruction to consider when looking for ARC uses or
1023-
// decrements in predecessor blocks.
1024-
if (!CheckUpToInstruction[PredBB])
1025-
CheckUpToInstruction[PredBB] = Release;
1026-
}
1027-
1028-
Inst->eraseFromParent();
1029-
HoistedDecrement = true;
1030-
}
1031-
1032-
return HoistedDecrement;
1033-
}
1034883
/// Try sink a retain as far as possible. This is either to successor BBs,
1035884
/// or as far down the current BB as possible
1036-
static bool sinkRefCountIncrement(SILBasicBlock *BB, AliasAnalysis *AA,
1037-
RCIdentityFunctionInfo *RCIA) {
1038-
885+
static bool sinkIncrementsIntoSwitchRegions(SILBasicBlock *BB, AliasAnalysis *AA,
886+
RCIdentityFunctionInfo *RCIA) {
1039887
// Make sure that each one of our successors only has one predecessor,
1040888
// us.
1041889
// If that condition is not true, we can still sink to the end of this BB,
@@ -1067,13 +915,16 @@ static bool sinkRefCountIncrement(SILBasicBlock *BB, AliasAnalysis *AA,
1067915
// terminator, sink the ref count inst into either our successors.
1068916
// 2. If there are such decrements, move the retain right before that
1069917
// decrement.
1070-
Changed |= tryToSinkRefCountInst(S->getIterator(), Inst->getIterator(),
1071-
CanSinkToSuccessor, AA, RCIA);
918+
Changed |= tryTosinkIncrementsIntoSwitchRegions(S->getIterator(),
919+
Inst->getIterator(),
920+
CanSinkToSuccessor,
921+
AA, RCIA);
1072922
}
1073923

1074924
// Handle the first instruction in the BB.
1075925
Changed |=
1076-
tryToSinkRefCountInst(S->getIterator(), SI, CanSinkToSuccessor, AA, RCIA);
926+
tryTosinkIncrementsIntoSwitchRegions(S->getIterator(), SI,
927+
CanSinkToSuccessor, AA, RCIA);
1077928
return Changed;
1078929
}
1079930

@@ -1747,12 +1598,17 @@ static bool processFunction(SILFunction *F, AliasAnalysis *AA,
17471598
DEBUG(llvm::dbgs() << " Attempting to move releases into "
17481599
"predecessors!\n");
17491600

1750-
if (HoistReleases)
1601+
// Perform a relatively local forms of retain sinking and release hoisting
1602+
// regarding switch regions and SILargument. This are not handled by retain
1603+
// release code motion.
1604+
if (HoistReleases) {
17511605
Changed |= State.hoistDecrementsIntoSwitchRegions(AA);
1606+
}
17521607

1608+
// Sink switch related retains.
1609+
Changed |= sinkIncrementsIntoSwitchRegions(State.getBB(), AA, RCIA);
17531610
Changed |= State.sinkIncrementsOutOfSwitchRegions(AA, RCIA);
17541611

1755-
17561612
// Then attempt to sink code from predecessors. This can include retains
17571613
// which is why we always attempt to move releases up the CFG before sinking
17581614
// code from predecessors. We will never sink the hoisted releases from
@@ -1768,15 +1624,6 @@ static bool processFunction(SILFunction *F, AliasAnalysis *AA,
17681624
// Then perform the dataflow.
17691625
DEBUG(llvm::dbgs() << " Performing the dataflow!\n");
17701626
Changed |= State.process();
1771-
1772-
// Finally we try to sink retain instructions from this BB to the next BB.
1773-
if (!DisableSILRRCodeMotion)
1774-
Changed |= sinkRefCountIncrement(State.getBB(), AA, RCIA);
1775-
1776-
// And hoist decrements to predecessors. This is beneficial if we can then
1777-
// match them up with an increment in some of the predecessors.
1778-
if (!DisableSILRRCodeMotion && HoistReleases)
1779-
Changed |= hoistDecrementsToPredecessors(State.getBB(), AA, RCIA);
17801627
}
17811628

17821629
return Changed;

lib/SILOptimizer/Utils/CFG.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,23 @@ SILBasicBlock *swift::splitCriticalEdge(TermInst *T, unsigned EdgeIdx,
687687
return splitEdge(T, EdgeIdx, DT, LI);
688688
}
689689

690+
bool swift::hasCriticalEdges(SILFunction &F, bool OnlyNonCondBr) {
691+
for (SILBasicBlock &BB : F) {
692+
// Only consider critical edges for terminators that don't support block
693+
// arguments.
694+
if (OnlyNonCondBr && isa<CondBranchInst>(BB.getTerminator()))
695+
continue;
696+
697+
if (isa<BranchInst>(BB.getTerminator()))
698+
continue;
699+
700+
for (unsigned Idx = 0, e = BB.getSuccessors().size(); Idx != e; ++Idx)
701+
if (isCriticalEdge(BB.getTerminator(), Idx))
702+
return true;
703+
}
704+
return false;
705+
}
706+
690707
/// Split all critical edges in the function updating the dominator tree and
691708
/// loop information (if they are not set to null).
692709
bool swift::splitAllCriticalEdges(SILFunction &F, bool OnlyNonCondBr,

test/SILOptimizer/devirt_covariant_return.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ class EEE : CCC {
276276

277277
// Check that c.foo() is devirtualized, because the optimizer can handle the casting the return type
278278
// correctly, i.e. it can cast (BBB, BBB) into (AAA, AAA)
279-
// CHECK-LABEL: sil hidden @_TTSf4g_n___TF23devirt_covariant_return37testDevirtOfMethodReturningTupleTypesFTCS_3CCC1bCS_2BB_TCS_2AAS2__
279+
// CHECK-LABEL: sil hidden @_TTSf4g_g___TF23devirt_covariant_return37testDevirtOfMethodReturningTupleTypesFTCS_3CCC1bCS_2BB_TCS_2AAS2__
280280
// CHECK: checked_cast_br [exact] %{{.*}} : $CCC to $CCC
281281
// CHECK: checked_cast_br [exact] %{{.*}} : $CCC to $DDD
282282
// CHECK: checked_cast_br [exact] %{{.*}} : $CCC to $EEE

0 commit comments

Comments
 (0)