mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-21 18:29:46 +00:00
Add simplifyLoopLatch to LoopRotate pass.
This folds a simple loop tail into a loop latch. It covers the common (in fortran) case of postincrement loops. It's a "free" way to expose this type of loop to downstream loop optimizations that bail out on non-canonical loops (getLoopLatch is a heavily used check). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@150439 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c3a825b76c
commit
f6629ab847
@ -19,6 +19,7 @@
|
||||
#include "llvm/Analysis/LoopPass.h"
|
||||
#include "llvm/Analysis/InstructionSimplify.h"
|
||||
#include "llvm/Analysis/ScalarEvolution.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/SSAUpdater.h"
|
||||
@ -52,6 +53,7 @@ namespace {
|
||||
}
|
||||
|
||||
bool runOnLoop(Loop *L, LPPassManager &LPM);
|
||||
void simplifyLoopLatch(Loop *L);
|
||||
bool rotateLoop(Loop *L);
|
||||
|
||||
private:
|
||||
@ -73,6 +75,11 @@ Pass *llvm::createLoopRotatePass() { return new LoopRotate(); }
|
||||
bool LoopRotate::runOnLoop(Loop *L, LPPassManager &LPM) {
|
||||
LI = &getAnalysis<LoopInfo>();
|
||||
|
||||
// Simplify the loop latch before attempting to rotate the header
|
||||
// upward. Rotation may not be needed if the loop tail can be folded into the
|
||||
// loop exit.
|
||||
simplifyLoopLatch(L);
|
||||
|
||||
// One loop can be rotated multiple times.
|
||||
bool MadeChange = false;
|
||||
while (rotateLoop(L))
|
||||
@ -146,6 +153,102 @@ static void RewriteUsesOfClonedInstructions(BasicBlock *OrigHeader,
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine whether the instructions in this range my be safely and cheaply
|
||||
/// speculated. This is not an important enough situation to develop complex
|
||||
/// heuristics. We handle a single arithmetic instruction along with any type
|
||||
/// conversions.
|
||||
static bool shouldSpeculateInstrs(BasicBlock::iterator Begin,
|
||||
BasicBlock::iterator End) {
|
||||
bool seenIncrement = false;
|
||||
for (BasicBlock::iterator I = Begin; I != End; ++I) {
|
||||
|
||||
if (!isSafeToSpeculativelyExecute(I))
|
||||
return false;
|
||||
|
||||
if (isa<DbgInfoIntrinsic>(I))
|
||||
continue;
|
||||
|
||||
switch (I->getOpcode()) {
|
||||
default:
|
||||
return false;
|
||||
case Instruction::GetElementPtr:
|
||||
// GEPs are cheap if all indices are constant.
|
||||
if (!cast<GEPOperator>(I)->hasAllConstantIndices())
|
||||
return false;
|
||||
// fall-thru to increment case
|
||||
case Instruction::Add:
|
||||
case Instruction::Sub:
|
||||
case Instruction::And:
|
||||
case Instruction::Or:
|
||||
case Instruction::Xor:
|
||||
case Instruction::Shl:
|
||||
case Instruction::LShr:
|
||||
case Instruction::AShr:
|
||||
if (seenIncrement)
|
||||
return false;
|
||||
seenIncrement = true;
|
||||
break;
|
||||
case Instruction::Trunc:
|
||||
case Instruction::ZExt:
|
||||
case Instruction::SExt:
|
||||
// ignore type conversions
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Fold the loop tail into the loop exit by speculating the loop tail
|
||||
/// instructions. Typically, this is a single post-increment. In the case of a
|
||||
/// simple 2-block loop, hoisting the increment can be much better than
|
||||
/// duplicating the entire loop header. In the cast of loops with early exits,
|
||||
/// rotation will not work anyway, but simplifyLoopLatch will put the loop in
|
||||
/// canonical form so downstream passes can handle it.
|
||||
///
|
||||
/// I don't believe this invalidates SCEV.
|
||||
void LoopRotate::simplifyLoopLatch(Loop *L) {
|
||||
BasicBlock *Latch = L->getLoopLatch();
|
||||
if (!Latch || Latch->hasAddressTaken())
|
||||
return;
|
||||
|
||||
BranchInst *Jmp = dyn_cast<BranchInst>(Latch->getTerminator());
|
||||
if (!Jmp || !Jmp->isUnconditional())
|
||||
return;
|
||||
|
||||
BasicBlock *LastExit = Latch->getSinglePredecessor();
|
||||
if (!LastExit || !L->isLoopExiting(LastExit))
|
||||
return;
|
||||
|
||||
BranchInst *BI = dyn_cast<BranchInst>(LastExit->getTerminator());
|
||||
if (!BI)
|
||||
return;
|
||||
|
||||
if (!shouldSpeculateInstrs(Latch->begin(), Jmp))
|
||||
return;
|
||||
|
||||
DEBUG(dbgs() << "Folding loop latch " << Latch->getName() << " into "
|
||||
<< LastExit->getName() << "\n");
|
||||
|
||||
// Hoist the instructions from Latch into LastExit.
|
||||
LastExit->getInstList().splice(BI, Latch->getInstList(), Latch->begin(), Jmp);
|
||||
|
||||
unsigned FallThruPath = BI->getSuccessor(0) == Latch ? 0 : 1;
|
||||
BasicBlock *Header = Jmp->getSuccessor(0);
|
||||
assert(Header == L->getHeader() && "expected a backward branch");
|
||||
|
||||
// Remove Latch from the CFG so that LastExit becomes the new Latch.
|
||||
BI->setSuccessor(FallThruPath, Header);
|
||||
Latch->replaceSuccessorsPhiUsesWith(LastExit);
|
||||
Jmp->eraseFromParent();
|
||||
|
||||
// Nuke the Latch block.
|
||||
assert(Latch->empty() && "unable to evacuate Latch");
|
||||
LI->removeBlock(Latch);
|
||||
if (DominatorTree *DT = getAnalysisIfAvailable<DominatorTree>())
|
||||
DT->eraseNode(Latch);
|
||||
Latch->eraseFromParent();
|
||||
}
|
||||
|
||||
/// Rotate loop LP. Return true if the loop is rotated.
|
||||
bool LoopRotate::rotateLoop(Loop *L) {
|
||||
// If the loop has only one block then there is not much to rotate.
|
||||
|
39
test/Transforms/LoopRotate/simplifylatch.ll
Normal file
39
test/Transforms/LoopRotate/simplifylatch.ll
Normal file
@ -0,0 +1,39 @@
|
||||
; RUN: opt -S < %s -loop-rotate -verify-dom-info -verify-loop-info | FileCheck %s
|
||||
; PR2624 unroll multiple exits
|
||||
|
||||
@mode_table = global [4 x i32] zeroinitializer ; <[4 x i32]*> [#uses=1]
|
||||
|
||||
; CHECK: @f
|
||||
; CHECK-NOT: bb4
|
||||
define i8 @f() {
|
||||
entry:
|
||||
tail call i32 @fegetround( ) ; <i32>:0 [#uses=1]
|
||||
br label %bb
|
||||
|
||||
bb: ; preds = %bb4, %entry
|
||||
%mode.0 = phi i8 [ 0, %entry ], [ %indvar.next, %bb4 ] ; <i8> [#uses=4]
|
||||
zext i8 %mode.0 to i32 ; <i32>:1 [#uses=1]
|
||||
getelementptr [4 x i32]* @mode_table, i32 0, i32 %1 ; <i32*>:2 [#uses=1]
|
||||
load i32* %2, align 4 ; <i32>:3 [#uses=1]
|
||||
icmp eq i32 %3, %0 ; <i1>:4 [#uses=1]
|
||||
br i1 %4, label %bb1, label %bb2
|
||||
|
||||
bb1: ; preds = %bb
|
||||
ret i8 %mode.0
|
||||
|
||||
bb2: ; preds = %bb
|
||||
icmp eq i8 %mode.0, 1 ; <i1>:5 [#uses=1]
|
||||
br i1 %5, label %bb5, label %bb4
|
||||
|
||||
bb4: ; preds = %bb2
|
||||
%indvar.next = add i8 %mode.0, 1 ; <i8> [#uses=1]
|
||||
br label %bb
|
||||
|
||||
bb5: ; preds = %bb2
|
||||
tail call void @raise_exception( ) noreturn
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare i32 @fegetround()
|
||||
|
||||
declare void @raise_exception() noreturn
|
Loading…
Reference in New Issue
Block a user