Files
swift-mirror/lib/SILPasses/SILCodeMotion.cpp
Pete Cooper 8322876162 Sink retains down in the current BB if they cannot be sunk to a successor.
We currently only sink retains to successor BBs.

However, if a retain can't be moved to a successor, we may still want to move it as late in the current BB as
possible.  For example, we want retains after called to _swift_isUniquelyReferenced and not before it.

Here are performance numbers for -O.  Note that i'm about to commit improvements to enum_is_tag which fixes the
regressions here.

Ackermann``````,``````````1413.00```,`````````````````1566.00```,``````````153.00``,`````````````````-9.8%
ArrayLiteral```,``````````834.00````,`````````````````859.00````,``````````25.00```,`````````````````-2.9%
Ary````````````,``````````1110.00```,`````````````````1121.00```,``````````11.00```,`````````````````-1.0%
Ary2```````````,``````````1092.00```,`````````````````1105.00```,``````````13.00```,`````````````````-1.2%
Ary3```````````,``````````1164.00```,`````````````````1193.00```,``````````29.00```,`````````````````-2.4%
DeltaBlue``````,``````````2195.00```,`````````````````2204.00```,``````````9.00````,`````````````````-0.4%
Dictionary`````,``````````502.00````,`````````````````512.00````,``````````10.00```,`````````````````-2.0%
Dictionary2````,``````````884.00````,`````````````````895.00````,``````````11.00```,`````````````````-1.2%
Dictionary3````,``````````859.00````,`````````````````870.00````,``````````11.00```,`````````````````-1.3%
EditDistance```,``````````1344.00```,`````````````````1344.00```,``````````0.00````,`````````````````0.0%
Fibonacci``````,``````````1382.00```,`````````````````1309.00```,``````````73.00```,`````````````````5.6%
ForLoops```````,``````````1318.00```,`````````````````1324.00```,``````````6.00````,`````````````````-0.5%
Forest`````````,``````````757.00````,`````````````````775.00````,``````````18.00```,`````````````````-2.3%
GlobalClass````,``````````1617.00```,`````````````````1620.00```,``````````3.00````,`````````````````-0.2%
Hash```````````,``````````660.00````,`````````````````718.00````,``````````58.00```,`````````````````-8.1%
HeapSort```````,``````````1256.00```,`````````````````1292.00```,``````````36.00```,`````````````````-2.8%
Histogram``````,``````````313.00````,`````````````````296.00````,``````````17.00```,`````````````````5.7%
InsertionSort``,``````````1223.00```,`````````````````1351.00```,``````````128.00``,`````````````````-9.5%
Life```````````,``````````69.00`````,`````````````````70.00`````,``````````1.00````,`````````````````-1.4%
LinkedList`````,``````````1516.00```,`````````````````1529.00```,``````````13.00```,`````````````````-0.9%
MatMul`````````,``````````224.00````,`````````````````239.00````,``````````15.00```,`````````````````-6.3%
Memset`````````,``````````43.00`````,`````````````````43.00`````,``````````0.00````,`````````````````0.0%
MonteCarloE````,``````````905.00````,`````````````````900.00````,``````````5.00````,`````````````````0.6%
MonteCarloPi```,``````````643.00````,`````````````````654.00````,``````````11.00```,`````````````````-1.7%
NBody``````````,``````````42.00`````,`````````````````41.00`````,``````````1.00````,`````````````````2.4%
NestedLoop`````,``````````931.00````,`````````````````876.00````,``````````55.00```,`````````````````6.3%
NopDeinit``````,``````````1119.00```,`````````````````1117.00```,``````````2.00````,`````````````````0.2%
Phonebook``````,``````````1424.00```,`````````````````1395.00```,``````````29.00```,`````````````````2.1%
PrimeNum```````,``````````214.00````,`````````````````219.00````,``````````5.00````,`````````````````-2.3%
Prims``````````,``````````1182.00```,`````````````````1198.00```,``````````16.00```,`````````````````-1.3%
QuickSort``````,``````````1196.00```,`````````````````1166.00```,``````````30.00```,`````````````````2.6%
R17315246``````,``````````798.00````,`````````````````798.00````,``````````0.00````,`````````````````0.0%
RC4````````````,``````````25.00`````,`````````````````25.00`````,``````````0.00````,`````````````````0.0%
RIPEMD`````````,``````````724.00````,`````````````````746.00````,``````````22.00```,`````````````````-2.9%
Random`````````,``````````960.00````,`````````````````963.00````,``````````3.00````,`````````````````-0.3%
Rectangles`````,``````````836.00````,`````````````````849.00````,``````````13.00```,`````````````````-1.5%
Richards```````,``````````220.00````,`````````````````225.00````,``````````5.00````,`````````````````-2.2%
SelectionSort``,``````````931.00````,`````````````````932.00````,``````````1.00````,`````````````````-0.1%
SmallPT````````,``````````1014.00```,`````````````````1039.00```,``````````25.00```,`````````````````-2.4%
StdlibSort`````,``````````1617.00```,`````````````````1602.00```,``````````15.00```,`````````````````0.9%
StrCat`````````,``````````1061.00```,`````````````````1121.00```,``````````60.00```,`````````````````-5.4%
StrSplitter````,``````````1607.00```,`````````````````1533.00```,``````````74.00```,`````````````````4.8%
StrToInt```````,``````````616.00````,`````````````````612.00````,``````````4.00````,`````````````````0.7%
StringBuilder``,``````````701.00````,`````````````````682.00````,``````````19.00```,`````````````````2.8%
StringWalk`````,``````````1165.00```,`````````````````1182.00```,``````````17.00```,`````````````````-1.4%
Totals`````````,``````````42392.00``,`````````````````42778.00``,``````````386.00``,`````````````````-0.9%
TwoSum`````````,``````````581.00````,`````````````````564.00````,``````````17.00```,`````````````````3.0%
Walsh``````````,``````````105.00````,`````````````````104.00````,``````````1.00````,`````````````````1.0%

Swift SVN r21133
2014-08-11 17:48:37 +00:00

658 lines
22 KiB
C++

//===- SILCodeMotion.cpp - Code Motion Optimizations ----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "codemotion"
#include "swift/SILPasses/Passes.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILType.h"
#include "swift/SIL/SILValue.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SIL/Projection.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILPasses/Transforms.h"
#include "swift/SILAnalysis/AliasAnalysis.h"
#include "swift/SILAnalysis/ARCAnalysis.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/RecyclingAllocator.h"
STATISTIC(NumSunk, "Number of instructions sunk");
using namespace swift;
using namespace swift::arc;
static const int SinkSearchWindow = 6;
/// \brief Returns True if we can sink this instruction to another basic block.
static bool canSinkInstruction(SILInstruction *Inst) {
return Inst->use_empty() && !isa<TermInst>(Inst);
}
/// \brief Returns true if this instruction is a skip barrier, which means that
/// we can't sink other instructions past it.
static bool isSinkBarrier(SILInstruction *Inst) {
// We know that some calls do not have side effects.
if (const ApplyInst *AI = dyn_cast<ApplyInst>(Inst))
if (BuiltinFunctionRefInst *FR =
dyn_cast<BuiltinFunctionRefInst>(AI->getCallee()))
return !isSideEffectFree(FR);
if (isa<TermInst>(Inst))
return false;
if (Inst->mayHaveSideEffects())
return true;
return false;
}
/// \brief Search for an instruction that is identical to \p Iden by scanning
/// \p BB starting at the end of the block, stopping on sink barriers.
SILInstruction *findIdenticalInBlock(SILBasicBlock *BB, SILInstruction *Iden) {
int SkipBudget = SinkSearchWindow;
SILBasicBlock::iterator InstToSink = BB->getTerminator();
while (SkipBudget) {
// If we found a sinkable instruction that is identical to our goal
// then return it.
if (canSinkInstruction(InstToSink) && Iden->isIdenticalTo(InstToSink)) {
DEBUG(llvm::dbgs() << "Found an identical instruction.");
return InstToSink;
}
// If this instruction is a skip-barrier end the scan.
if (isSinkBarrier(InstToSink))
return nullptr;
// If this is the first instruction in the block then we are done.
if (InstToSink == BB->begin())
return nullptr;
SkipBudget--;
InstToSink = std::prev(InstToSink);
DEBUG(llvm::dbgs() << "Continuing scan. Next inst: " << *InstToSink);
}
return nullptr;
}
/// The 2 instructions given are not identical, but are passed as arguments
/// to a common successor. It may be cheaper to pass one of their operands
/// to the successor instead of the whole instruction.
/// Return ~0U if no such operand could be found, otherwise return the index
/// of a suitable operand.
static unsigned cheaperToPassOperandsAsArguments(SILInstruction *First,
SILInstruction *Second) {
// TODO: Add more cases than Struct
StructInst *FirstStruct = dyn_cast<StructInst>(First);
StructInst *SecondStruct = dyn_cast<StructInst>(Second);
if (!FirstStruct || !SecondStruct)
return ~0U;
assert(First->getNumOperands() == Second->getNumOperands() &&
First->getNumTypes() == Second->getNumTypes() &&
"Types should be identical");
unsigned DifferentOperandIndex = ~0U;
// Check operands.
for (unsigned i = 0, e = First->getNumOperands(); i != e; ++i) {
if (First->getOperand(i) != Second->getOperand(i)) {
// Only track one different operand for now
if (DifferentOperandIndex != ~0U)
return ~0U;
DifferentOperandIndex = i;
}
}
if (DifferentOperandIndex == ~0U)
return ~0U;
// Found a different operand, now check to see if its type is something
// cheap enough to sink.
// TODO: Sink more than just integers.
const auto &ArgTy = First->getOperand(DifferentOperandIndex).getType();
if (!ArgTy.is<BuiltinIntegerType>())
return ~0U;
return DifferentOperandIndex;
}
// Try to sink values from the Nth argument \p ArgNum.
static bool sinkArgument(SILBasicBlock *BB, unsigned ArgNum) {
assert(ArgNum < BB->getNumBBArg() && "Invalid argument");
// Find the first predecessor, the first terminator and the Nth argument.
SILBasicBlock *FirstPred = *BB->pred_begin();
TermInst *FirstTerm = FirstPred->getTerminator();
auto FirstPredArg = FirstTerm->getOperand(ArgNum);
SILInstruction *FSI = dyn_cast<SILInstruction>(FirstPredArg);
// The list of identical instructions.
SmallVector<SILValue, 8> Clones;
Clones.push_back(FirstPredArg);
// We only move instructions with a single use.
if (!FSI || !FSI->hasOneUse())
return false;
// Don't move instructions that are sensitive to their location.
if (FSI->mayHaveSideEffects())
return false;
// If the instructions are different, but only in terms of a cheap operand
// then we can still sink it, and create new arguments for this operand.
unsigned DifferentOperandIndex = ~0U;
// Check if the Nth argument in all predecessors is identical.
for (auto P : BB->getPreds()) {
if (P == FirstPred)
continue;
// Only handle branch or conditional branch instructions.
TermInst *TI = P->getTerminator();
if (!isa<BranchInst>(TI) && !isa<CondBranchInst>(TI))
return false;
// Find the Nth argument passed to BB.
SILValue Arg = TI->getOperand(ArgNum);
SILInstruction *SI = dyn_cast<SILInstruction>(Arg);
if (!SI || !SI->hasOneUse())
return false;
if (SI->isIdenticalTo(FSI)) {
Clones.push_back(SI);
continue;
}
// If the instructions are close enough, then we should sink them anyway.
// For example, we should sink 'struct S(%0)' if %0 is small, eg, an integer
unsigned DifferentOp = cheaperToPassOperandsAsArguments(FSI, SI);
// Couldn't find a suitable operand, so bail.
if (DifferentOp == ~0U)
return false;
// Make sure we found the same operand as prior iterations.
if (DifferentOperandIndex == ~0U)
DifferentOperandIndex = DifferentOp;
else if (DifferentOp != DifferentOperandIndex)
return false;
Clones.push_back(SI);
}
if (!FSI)
return false;
SILValue Undef = SILUndef::get(FirstPredArg.getType(), BB->getModule());
if (DifferentOperandIndex != ~0U) {
// Sink one of the instructions to BB
FSI->moveBefore(BB->begin());
// The instruction we are lowering has an argument which is different
// for each predecessor. We need to sink the instruction, then add
// arguments for each predecessor.
SILValue(BB->getBBArg(ArgNum)).replaceAllUsesWith(FSI);
const auto &ArgType = FSI->getOperand(DifferentOperandIndex).getType();
BB->replaceBBArg(ArgNum, ArgType);
// Update all branch instructions in the predecessors to pass the new
// argument to this BB.
auto CloneIt = Clones.begin();
for (auto P : BB->getPreds()) {
// Only handle branch or conditional branch instructions.
TermInst *TI = P->getTerminator();
assert((isa<BranchInst>(TI) || isa<CondBranchInst>(TI)) &&
"Branch instruction required");
SILInstruction *CloneInst = dyn_cast<SILInstruction>(*CloneIt);
TI->setOperand(ArgNum, CloneInst->getOperand(DifferentOperandIndex));
// Now delete the clone as we only needed it operand.
if (CloneInst != FSI)
recursivelyDeleteTriviallyDeadInstructions(CloneInst);
++CloneIt;
}
assert(CloneIt == Clones.end() && "Clone/pred mismatch");
// The sunk instruction should now read from the argument of the BB it
// was moved to.
FSI->setOperand(DifferentOperandIndex, BB->getBBArg(ArgNum));
return true;
}
// Sink one of the copies of the instruction.
FirstPredArg.replaceAllUsesWith(Undef);
FSI->moveBefore(BB->begin());
SILValue(BB->getBBArg(ArgNum)).replaceAllUsesWith(FirstPredArg);
// The argument is no longer in use. Replace all incoming inputs with undef
// and try to delete the instruction.
for (auto S : Clones)
if (S.getDef() != FSI) {
S.replaceAllUsesWith(Undef);
auto DeadArgInst = cast<SILInstruction>(S.getDef());
recursivelyDeleteTriviallyDeadInstructions(DeadArgInst);
}
return true;
}
/// Try to sink identical arguments coming from multiple predecessors.
static bool sinkArgumentsFromPredecessors(SILBasicBlock *BB) {
if (BB->pred_empty() || BB->getSinglePredecessor())
return false;
// This block must be the only successor of all the predecessors.
for (auto P : BB->getPreds())
if (P->getSingleSuccessor() != BB)
return false;
// Try to sink values from each of the arguments to the basic block.
bool Changed = false;
for (int i = 0, e = BB->getNumBBArg(); i < e; ++i)
Changed |= sinkArgument(BB, i);
return Changed;
}
static bool sinkCodeFromPredecessors(SILBasicBlock *BB) {
bool Changed = false;
if (BB->pred_empty())
return Changed;
// This block must be the only successor of all the predecessors.
for (auto P : BB->getPreds())
if (P->getSingleSuccessor() != BB)
return Changed;
SILBasicBlock *FirstPred = *BB->pred_begin();
// The first Pred must have at least one non-terminator.
if (FirstPred->getTerminator() == FirstPred->begin())
return Changed;
DEBUG(llvm::dbgs() << " Sinking values from predecessors.\n");
unsigned SkipBudget = SinkSearchWindow;
// Start scanning backwards from the terminator.
SILBasicBlock::iterator InstToSink = FirstPred->getTerminator();
while (SkipBudget) {
DEBUG(llvm::dbgs() << "Processing: " << *InstToSink);
// Save the duplicated instructions in case we need to remove them.
SmallVector<SILInstruction *, 4> Dups;
if (canSinkInstruction(InstToSink)) {
// For all preds:
for (auto P : BB->getPreds()) {
if (P == FirstPred)
continue;
// Search the duplicated instruction in the predecessor.
if (SILInstruction *DupInst = findIdenticalInBlock(P, InstToSink)) {
Dups.push_back(DupInst);
} else {
DEBUG(llvm::dbgs() << "Instruction mismatch.\n");
Dups.clear();
break;
}
}
// If we found duplicated instructions, sink one of the copies and delete
// the rest.
if (Dups.size()) {
DEBUG(llvm::dbgs() << "Moving: " << *InstToSink);
InstToSink->moveBefore(BB->begin());
Changed = true;
for (auto I : Dups) {
I->replaceAllUsesWith(InstToSink);
I->eraseFromParent();
NumSunk++;
}
// Restart the scan.
InstToSink = FirstPred->getTerminator();
DEBUG(llvm::dbgs() << "Restarting scan. Next inst: " << *InstToSink);
continue;
}
}
// If this instruction was a barrier then we can't sink anything else.
if (isSinkBarrier(InstToSink)) {
DEBUG(llvm::dbgs() << "Aborting on barrier: " << *InstToSink);
return Changed;
}
// This is the first instruction, we are done.
if (InstToSink == FirstPred->begin()) {
DEBUG(llvm::dbgs() << "Reached the first instruction.");
return Changed;
}
SkipBudget--;
InstToSink = std::prev(InstToSink);
DEBUG(llvm::dbgs() << "Continuing scan. Next inst: " << *InstToSink);
}
return Changed;
}
static void createRefCountOpForPayload(SILBuilder &Builder, SILInstruction *I,
EnumElementDecl *EnumDecl) {
// If we do not have any argument, there is nothing to do... bail...
if (!EnumDecl->hasArgumentType())
return;
// Otherwise, create a UEDI for our payload.
SILModule &Mod = I->getModule();
SILType ArgType =
I->getOperand(0).getType().getEnumElementType(EnumDecl, Mod);
auto *UEDI = Builder.createUncheckedEnumData(I->getLoc(), I->getOperand(0),
EnumDecl, ArgType);
if (isa<RetainValueInst>(I)) {
Builder.createRetainValue(I->getLoc(), UEDI);
return;
}
Builder.createReleaseValue(I->getLoc(), UEDI);
}
/// Sink retain_value, release_value before switch_enum to be retain_value,
/// release_value on the payload of the switch_enum in the destination BBs. We
/// only do this if the destination BBs have only the switch enum as its
/// predecessor.
static bool tryToSinkRefCountAcrossSwitch(SwitchEnumInst *S, SILInstruction *I,
AliasAnalysis *AA) {
// If this instruction is not a retain_value, there is nothing left for us to
// do... bail...
if (!isa<RetainValueInst>(I))
return false;
SILValue Ptr = I->getOperand(0);
// If the retain value's argument is not the switch's argument, we can't do
// anything with our simplistic analysis... bail...
if (Ptr != S->getOperand())
return false;
// If S has a default case bail since the default case could represent
// multiple cases.
//
// TODO: I am currently just disabling this behavior so we can get this out
// for Seed 5. After Seed 5, we should be able to recognize if a switch_enum
// handles all cases except for 1 and has a default case. We might be able to
// stick code into SILBuilder that has this behavior.
if (S->hasDefault())
return false;
// Next go over all instructions after I in the basic block. If none of them
// can decrement our ptr value, we can move the retain over the ref count
// inst. If any of them do potentially decrement the ref count of Ptr, we can
// not move it.
SILBasicBlock::iterator II = I;
if (valueHasARCDecrementsInInstructionRange(Ptr, std::next(II),
SILBasicBlock::iterator(S),
AA))
return false;
SILBuilder Builder(S);
// Ok, we have a ref count instruction, sink it!
for (unsigned i = 0, e = S->getNumCases(); i != e; ++i) {
auto Case = S->getCase(i);
EnumElementDecl *Enum = Case.first;
SILBasicBlock *Succ = Case.second;
Builder.setInsertionPoint(&*Succ->begin());
createRefCountOpForPayload(Builder, I, Enum);
}
I->eraseFromParent();
NumSunk++;
return true;
}
/// Sink retain_value, release_value before enum_is_tag to be retain_value,
/// release_value on the payload of the switch_enum in the destination BBs. We
/// only do this if the destination BBs have only the switch enum as its
/// predecessor.
static bool tryToSinkRefCountAcrossEnumIsTag(CondBranchInst *CondBr,
SILInstruction *I,
AliasAnalysis *AA) {
// If this instruction is not a retain_value, there is nothing left for us to
// do... bail...
if (!isa<RetainValueInst>(I))
return false;
SILValue Ptr = I->getOperand(0);
// Make sure the condition comes from an enum_is_tag
auto *EITI = dyn_cast<EnumIsTagInst>(CondBr->getCondition());
if (!EITI)
return false;
// If the retain value's argument is not the cond_br's argument, we can't do
// anything with our simplistic analysis... bail...
if (Ptr != EITI->getOperand())
return false;
// Next go over all instructions after I in the basic block. If none of them
// can decrement our ptr value, we can move the retain over the ref count
// inst. If any of them do potentially decrement the ref count of Ptr, we can
// not move it.
SILBasicBlock::iterator II = I;
if (valueHasARCDecrementsInInstructionRange(Ptr, std::next(II),
SILBasicBlock::iterator(CondBr),
AA))
return false;
// Work out which enum element is the true branch, and which is false.
// If the enum only has 2 values and its tag isn't the true branch, then we
// know the true branch must be the other tag.
EnumElementDecl *Elts[2] = {EITI->getElement(), nullptr};
EnumDecl *E = EITI->getOperand().getType().getEnumOrBoundGenericEnum();
if (!E)
return false;
// Look for a single other element on this enum.
EnumElementDecl *OtherElt = nullptr;
for (EnumElementDecl *Elt : E->getAllElements()) {
// Skip the case where we find the enum_is_tag element
if (Elt == EITI->getElement())
continue;
// If we find another element, then we must have more than 2, so bail.
if (OtherElt)
return false;
OtherElt = Elt;
}
// Only a single enum element? How would this even get here? We should
// handle it in SILCombine.
if (!OtherElt)
return false;
Elts[1] = OtherElt;
SILBuilder Builder(EITI);
// Ok, we have a ref count instruction, sink it!
for (unsigned i = 0; i != 2; ++i) {
EnumElementDecl *Enum = Elts[i];
SILBasicBlock *Succ = i == 0 ? CondBr->getTrueBB() : CondBr->getFalseBB();
Builder.setInsertionPoint(&*Succ->begin());
createRefCountOpForPayload(Builder, I, Enum);
}
I->eraseFromParent();
NumSunk++;
return true;
}
static bool tryToSinkRefCountInst(SILInstruction *T, SILInstruction *I,
AliasAnalysis *AA) {
if (auto *S = dyn_cast<SwitchEnumInst>(T))
return tryToSinkRefCountAcrossSwitch(S, I, AA);
if (auto *CondBr = dyn_cast<CondBranchInst>(T))
if (tryToSinkRefCountAcrossEnumIsTag(CondBr, I, AA))
return true;
// We currently handle checked_cast_br and cond_br.
if (!isa<CheckedCastBranchInst>(T) && !isa<CondBranchInst>(T))
return false;
if (!isa<StrongRetainInst>(I) && !isa<RetainValueInst>(I))
return false;
SILValue Ptr = I->getOperand(0);
SILBasicBlock::iterator II = I;
++II;
for (; &*II != T; ++II) {
if (canDecrementRefCount(&*II, Ptr, AA))
return false;
}
SILBuilder Builder(T);
// Ok, we have a ref count instruction, sink it!
for (auto &Succ : T->getParent()->getSuccs()) {
SILBasicBlock *SuccBB = Succ.getBB();
Builder.setInsertionPoint(&*SuccBB->begin());
if (isa<StrongRetainInst>(I))
Builder.createStrongRetain(I->getLoc(), Ptr);
else
// I should be RetainValueInst.
Builder.createRetainValue(I->getLoc(), Ptr);
}
I->eraseFromParent();
NumSunk++;
return true;
}
/// \brief - Tries to move the given retain instruction down as far as possible
/// in the current BB. It will move it as far as 'Pos' if possible, or to the
/// first release it sees.
static bool tryToMoveRefCountInstDownInBB(SILBasicBlock::iterator Pos,
SILInstruction *I,
AliasAnalysis *AA) {
if (!isa<StrongRetainInst>(I) && !isa<RetainValueInst>(I))
return false;
SILValue Ptr = I->getOperand(0);
SILBasicBlock::iterator II = I;
++II;
for (; II != Pos; ++II) {
// If we find a release, then this is the farthest down we can move the
// instruction.
if (canDecrementRefCount(&*II, Ptr, AA))
break;
}
// If we didn't find anywhere to move it then give up.
Pos = II;
--II;
if (I == II)
return false;
// Ok, we have a ref count instruction, move it further down the BB.
I->moveBefore(Pos);
NumSunk++;
return true;
}
/// Try sink a retain as far as possible. This is either to sucessor BBs,
/// or as far down the current BB as possible
static bool sinkRetain(SILBasicBlock *BB, AliasAnalysis *AA) {
// Make sure that each one of our successors only has one predecessor,
// us.
// If that condition is not true, we can still sink to the end of this BB,
// but not to successors.
bool CanSinkToSuccessor = true;
for (auto &Succ : BB->getSuccs()) {
SILBasicBlock *SuccBB = Succ.getBB();
if (!SuccBB || !SuccBB->getSinglePredecessor()) {
CanSinkToSuccessor = false;
break;
}
}
SILInstruction *S = BB->getTerminator();
SILBasicBlock::iterator SI = S, SE = BB->begin();
if (SI == SE)
return false;
bool Changed = false;
// Walk from the terminator up the BB. Try move retains either to the next
// BB, or the end of this BB. Note that ordering is maintained of retains
// within this BB.
SILBasicBlock::iterator InsertPos = SI;
SI = std::prev(SI);
while (SI != SE) {
SILInstruction *Inst = &*SI;
SI = std::prev(SI);
// Try sink to successor
if (CanSinkToSuccessor && tryToSinkRefCountInst(S, Inst, AA)) {
Changed = true;
continue;
}
// Try move further down the current BB.
if (tryToMoveRefCountInstDownInBB(InsertPos, Inst, AA)) {
InsertPos = std::prev(InsertPos);
Changed = true;
continue;
}
}
if (CanSinkToSuccessor && tryToSinkRefCountInst(S, &*SI, AA))
return true;
if (tryToMoveRefCountInstDownInBB(InsertPos, &*SI, AA))
return true;
return Changed;
}
namespace {
class SILCodeMotion : public SILFunctionTransform {
/// The entry point to the transformation.
void run() {
SILFunction &F = *getFunction();
AliasAnalysis *AA = getAnalysis<AliasAnalysis>();
DEBUG(llvm::dbgs() << "***** CodeMotion on function: " << F.getName() <<
" *****\n");
// Sink duplicated code from predecessors.
bool Changed = false;
for (auto &BB : F) {
Changed |= sinkCodeFromPredecessors(&BB);
Changed |= sinkArgumentsFromPredecessors(&BB);
Changed |= sinkRetain(&BB, AA);
}
if (Changed)
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
}
StringRef getName() override { return "SIL Code Motion"; }
};
} // end anonymous namespace
SILTransform *swift::createCodeMotion() {
return new SILCodeMotion();
}