Skip to content

Commit e06e1be

Browse files
committed
Merge pull request #2950 from trentxintong/SCM
Remove last bit of retain release code motion in SILCodeMotion.
2 parents ee5ec6b + be793d2 commit e06e1be

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)