[Hexagon] Find speculative loop preheader in hardware loop generation

Before adding a new preheader block, check if there is a candidate block
where the loop setup could be placed speculatively. This will be off by
default.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@276919 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Krzysztof Parzyszek 2016-07-27 21:20:54 +00:00
parent 3e611f85b8
commit ca740c1356
2 changed files with 101 additions and 10 deletions

View File

@ -60,6 +60,13 @@ static cl::opt<bool> HWCreatePreheader("hexagon-hwloop-preheader",
cl::Hidden, cl::init(true),
cl::desc("Add a preheader to a hardware loop if one doesn't exist"));
// Turn it off by default. If a preheader block is not created here, the
// software pipeliner may be unable to find a block suitable to serve as
// a preheader. In that case SWP will not run.
static cl::opt<bool> SpecPreheader("hwloop-spec-preheader", cl::init(false),
cl::Hidden, cl::ZeroOrMore, cl::desc("Allow speculation of preheader "
"instructions"));
STATISTIC(NumHWLoops, "Number of loops converted to hardware loops");
namespace llvm {
@ -270,6 +277,10 @@ namespace {
/// cannot be adjusted to reflect the post-bump value.
bool fixupInductionVariable(MachineLoop *L);
/// \brief Find the block that either is the loop preheader, or could
/// speculatively be used as the preheader.
MachineBasicBlock *findLoopPreheader(MachineLoop *L) const;
/// \brief Given a loop, if it does not have a preheader, create one.
/// Return the block that is the preheader.
MachineBasicBlock *createPreheaderForLoop(MachineLoop *L);
@ -385,7 +396,7 @@ bool HexagonHardwareLoops::findInductionRegister(MachineLoop *L,
MachineInstr *&IVOp
) const {
MachineBasicBlock *Header = L->getHeader();
MachineBasicBlock *Preheader = L->getLoopPreheader();
MachineBasicBlock *Preheader = findLoopPreheader(L);
MachineBasicBlock *Latch = L->getLoopLatch();
MachineBasicBlock *ExitingBlock = getExitingBlock(L);
if (!Header || !Preheader || !Latch || !ExitingBlock)
@ -566,7 +577,7 @@ CountValue *HexagonHardwareLoops::getLoopTripCount(MachineLoop *L,
if (!FoundIV)
return nullptr;
MachineBasicBlock *Preheader = L->getLoopPreheader();
MachineBasicBlock *Preheader = findLoopPreheader(L);
MachineOperand *InitialValue = nullptr;
MachineInstr *IV_Phi = MRI->getVRegDef(IVReg);
@ -787,7 +798,7 @@ CountValue *HexagonHardwareLoops::computeCount(MachineLoop *Loop,
if (!isPowerOf2_64(std::abs(IVBump)))
return nullptr;
MachineBasicBlock *PH = Loop->getLoopPreheader();
MachineBasicBlock *PH = findLoopPreheader(Loop);
assert (PH && "Should have a preheader by now");
MachineBasicBlock::iterator InsertPos = PH->getFirstTerminator();
DebugLoc DL;
@ -1153,7 +1164,7 @@ bool HexagonHardwareLoops::convertToHardwareLoop(MachineLoop *L,
// Ensure the loop has a preheader: the loop instruction will be
// placed there.
MachineBasicBlock *Preheader = L->getLoopPreheader();
MachineBasicBlock *Preheader = findLoopPreheader(L);
if (!Preheader) {
Preheader = createPreheaderForLoop(L);
if (!Preheader)
@ -1807,12 +1818,45 @@ bool HexagonHardwareLoops::fixupInductionVariable(MachineLoop *L) {
return false;
}
/// \brief Create a preheader for a given loop.
/// Find a preaheader of the given loop.
MachineBasicBlock *HexagonHardwareLoops::findLoopPreheader(MachineLoop *L)
const {
if (MachineBasicBlock *PB = L->getLoopPreheader())
return PB;
if (!SpecPreheader)
return nullptr;
MachineBasicBlock *HB = L->getHeader(), *LB = L->getLoopLatch();
if (HB->pred_size() != 2 || HB->hasAddressTaken())
return nullptr;
// Find the predecessor of the header that is not the latch block.
MachineBasicBlock *Preheader = nullptr;
for (MachineBasicBlock *P : HB->predecessors()) {
if (P == LB)
continue;
// Sanity.
if (Preheader)
return nullptr;
Preheader = P;
}
// Check if the preheader candidate is a successor of any other loop
// headers. We want to avoid having two loop setups in the same block.
for (MachineBasicBlock *S : Preheader->successors()) {
if (S == HB)
continue;
MachineLoop *T = MLI->getLoopFor(S);
if (T && T->getHeader() == S)
return nullptr;
}
return Preheader;
}
/// createPreheaderForLoop - Create a preheader for a given loop.
MachineBasicBlock *HexagonHardwareLoops::createPreheaderForLoop(
MachineLoop *L) {
if (MachineBasicBlock *TmpPH = L->getLoopPreheader())
if (MachineBasicBlock *TmpPH = findLoopPreheader(L))
return TmpPH;
if (!HWCreatePreheader)
return nullptr;
@ -1958,9 +2002,12 @@ MachineBasicBlock *HexagonHardwareLoops::createPreheaderForLoop(
// Update the dominator information with the new preheader.
if (MDT) {
MachineDomTreeNode *HDom = MDT->getNode(Header);
MDT->addNewBlock(NewPH, HDom->getIDom()->getBlock());
MDT->changeImmediateDominator(Header, NewPH);
if (MachineDomTreeNode *HN = MDT->getNode(Header)) {
if (MachineDomTreeNode *DHN = HN->getIDom()) {
MDT->addNewBlock(NewPH, DHN->getBlock());
MDT->changeImmediateDominator(Header, NewPH);
}
}
}
return NewPH;

View File

@ -0,0 +1,44 @@
; RUN: llc -march=hexagon -disable-machine-licm -hwloop-spec-preheader=1 < %s | FileCheck %s
; CHECK: loop0
target triple = "hexagon"
define i32 @foo(i32 %x, i32 %n, i32* nocapture %A, i32* nocapture %B) #0 {
entry:
%cmp = icmp sgt i32 %x, 0
br i1 %cmp, label %for.cond.preheader, label %return
for.cond.preheader: ; preds = %entry
%cmp16 = icmp sgt i32 %n, 0
br i1 %cmp16, label %for.body.preheader, label %return
for.body.preheader: ; preds = %for.cond.preheader
br label %for.body
for.body: ; preds = %for.body.preheader, %for.body
%arrayidx.phi = phi i32* [ %arrayidx.inc, %for.body ], [ %B, %for.body.preheader ]
%arrayidx2.phi = phi i32* [ %arrayidx2.inc, %for.body ], [ %A, %for.body.preheader ]
%i.07 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ]
%0 = load i32, i32* %arrayidx.phi, align 4, !tbaa !0
%1 = load i32, i32* %arrayidx2.phi, align 4, !tbaa !0
%add = add nsw i32 %1, %0
store i32 %add, i32* %arrayidx2.phi, align 4, !tbaa !0
%inc = add nsw i32 %i.07, 1
%exitcond = icmp eq i32 %inc, %n
%arrayidx.inc = getelementptr i32, i32* %arrayidx.phi, i32 1
%arrayidx2.inc = getelementptr i32, i32* %arrayidx2.phi, i32 1
br i1 %exitcond, label %return.loopexit, label %for.body
return.loopexit: ; preds = %for.body
br label %return
return: ; preds = %return.loopexit, %for.cond.preheader, %entry
%retval.0 = phi i32 [ 2, %entry ], [ 0, %for.cond.preheader ], [ 0, %return.loopexit ]
ret i32 %retval.0
}
!0 = !{!"int", !1}
!1 = !{!"omnipotent char", !2}
!2 = !{!"Simple C/C++ TBAA"}
attributes #0 = { nounwind "target-cpu"="hexagonv60" "target-features"="-hvx,-hvx-double" }