Hoist release on SILArgument to predecessors.

so that they can be potentially paired retains on some paths.

I did not measure real performance difference on my machine

rdar://19011844
This commit is contained in:
Xin Tong
2016-06-01 12:02:47 -07:00
parent 06d8455cdf
commit a3c1c1649e
2 changed files with 78 additions and 0 deletions

View File

@@ -34,6 +34,7 @@
STATISTIC(NumSunk, "Number of instructions sunk");
STATISTIC(NumRefCountOpsSimplified, "Number of enum ref count ops simplified");
STATISTIC(NumHoisted, "Number of instructions hoisted");
STATISTIC(NumSILArgumentReleaseHoisted, "Number of silargument release instructions hoisted");
llvm::cl::opt<bool> DisableSILRRCodeMotion("disable-sil-cm-rr-cm", llvm::cl::init(true));
@@ -45,6 +46,10 @@ namespace {
// Utility
//===----------------------------------------------------------------------===//
static bool isReleaseInstruction(SILInstruction *I) {
return isa<StrongReleaseInst>(I) || isa<ReleaseValueInst>(I);
}
static void createRefCountOpForPayload(SILBuilder &Builder, SILInstruction *I,
EnumElementDecl *EnumDecl,
SILValue DefOfEnum = SILValue()) {
@@ -106,6 +111,47 @@ static void createRefCountOpForPayload(SILBuilder &Builder, SILInstruction *I,
// Generic Sinking Code
//===----------------------------------------------------------------------===//
/// \brief Hoist release on a SILArgument to its predecessors.
static bool hoistSILArgumentReleaseInst(SILBasicBlock *BB) {
// There is no block to hoist releases to.
if (BB->pred_empty())
return false;
// Only try to hoist the first instruction. RRCM should have hoisted the release
// to the beginning of the block if it can.
auto Head = &*BB->begin();
// Make sure it is a release instruction.
if (!isReleaseInstruction(&*Head))
return false;
// Make sure it is a release on a SILArgument of the current basic block..
SILArgument *SA = dyn_cast<SILArgument>(Head->getOperand(0));
if (!SA || SA->getParent() != BB)
return false;
// Make sure the release will not be blocked by the terminator instructions
// Make sure the terminator does not block, nor is a branch with multiple targets.
for (auto P : BB->getPreds()) {
if (!isa<BranchInst>(P->getTerminator()))
return false;
}
// Make sure we can get all the incoming values.
llvm::SmallVector<SILValue , 4> PredValues;
if (!SA->getIncomingValues(PredValues))
return false;
// Ok, we can get all the incoming values and create releases for them.
unsigned indices = 0;
for (auto P : BB->getPreds()) {
createDecrementBefore(PredValues[indices++], P->getTerminator());
}
// Erase the old instruction.
Head->eraseFromParent();
++NumSILArgumentReleaseHoisted;
return true;
}
static const int SinkSearchWindow = 6;
/// \brief Returns True if we can sink this instruction to another basic block.
@@ -1716,6 +1762,8 @@ static bool processFunction(SILFunction *F, AliasAnalysis *AA,
Changed |= sinkCodeFromPredecessors(State.getBB());
Changed |= sinkArgumentsFromPredecessors(State.getBB());
Changed |= sinkLiteralsFromPredecessors(State.getBB());
// Try to hoist release of a SILArgument to predecessors.
Changed |= hoistSILArgumentReleaseInst(State.getBB());
// Then perform the dataflow.
DEBUG(llvm::dbgs() << " Performing the dataflow!\n");