mirror of
https://github.com/RPCSX/llvm.git
synced 2025-01-22 04:05:05 +00:00
[IndVars] Have getInsertPointForUses preserve LCSSA
Summary: Also add a stricter post-condition for IndVarSimplify. Fixes PR25578. Test case by Michael Zolotukhin. Reviewers: hfinkel, atrick, mzolotukhin Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D15059 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@254977 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
51d40aea3b
commit
ca40161d4a
@ -402,6 +402,9 @@ public:
|
||||
/// isLCSSAForm - Return true if the Loop is in LCSSA form
|
||||
bool isLCSSAForm(DominatorTree &DT) const;
|
||||
|
||||
/// \brief Return true if this Loop and all inner subloops are in LCSSA form.
|
||||
bool isRecursivelyLCSSAForm(DominatorTree &DT) const;
|
||||
|
||||
/// isLoopSimplifyForm - Return true if the Loop is in the form that
|
||||
/// the LoopSimplify form transforms loops to, which is sometimes called
|
||||
/// normal form.
|
||||
|
@ -200,6 +200,15 @@ bool Loop::isLCSSAForm(DominatorTree &DT) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Loop::isRecursivelyLCSSAForm(DominatorTree &DT) const {
|
||||
if (!isLCSSAForm(DT))
|
||||
return false;
|
||||
|
||||
return std::all_of(begin(), end(), [&](const Loop *L) {
|
||||
return L->isRecursivelyLCSSAForm(DT);
|
||||
});
|
||||
}
|
||||
|
||||
/// isLoopSimplifyForm - Return true if the Loop is in the form that
|
||||
/// the LoopSimplify form transforms loops to, which is sometimes called
|
||||
/// normal form.
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
#include "llvm/Transforms/Utils/LoopUtils.h"
|
||||
#include "llvm/Transforms/Utils/SimplifyIndVar.h"
|
||||
using namespace llvm;
|
||||
|
||||
@ -215,7 +216,7 @@ bool IndVarSimplify::isValidRewrite(Value *FromVal, Value *ToVal) {
|
||||
/// loop. For PHI nodes, there may be multiple uses, so compute the nearest
|
||||
/// common dominator for the incoming blocks.
|
||||
static Instruction *getInsertPointForUses(Instruction *User, Value *Def,
|
||||
DominatorTree *DT) {
|
||||
DominatorTree *DT, LoopInfo *LI) {
|
||||
PHINode *PHI = dyn_cast<PHINode>(User);
|
||||
if (!PHI)
|
||||
return User;
|
||||
@ -234,10 +235,21 @@ static Instruction *getInsertPointForUses(Instruction *User, Value *Def,
|
||||
InsertPt = InsertBB->getTerminator();
|
||||
}
|
||||
assert(InsertPt && "Missing phi operand");
|
||||
assert((!isa<Instruction>(Def) ||
|
||||
DT->dominates(cast<Instruction>(Def), InsertPt)) &&
|
||||
"def does not dominate all uses");
|
||||
return InsertPt;
|
||||
|
||||
auto *DefI = dyn_cast<Instruction>(Def);
|
||||
if (!DefI)
|
||||
return InsertPt;
|
||||
|
||||
assert(DT->dominates(DefI, InsertPt) && "def does not dominate all uses");
|
||||
|
||||
auto *L = LI->getLoopFor(DefI->getParent());
|
||||
assert(!L || L->contains(LI->getLoopFor(InsertPt->getParent())));
|
||||
|
||||
for (auto *DTN = (*DT)[InsertPt->getParent()]; DTN; DTN = DTN->getIDom())
|
||||
if (LI->getLoopFor(DTN->getBlock()) == L)
|
||||
return DTN->getBlock()->getTerminator();
|
||||
|
||||
llvm_unreachable("DefI dominates InsertPt!");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -528,8 +540,8 @@ Value *IndVarSimplify::expandSCEVIfNeeded(SCEVExpander &Rewriter, const SCEV *S,
|
||||
/// able to brute-force evaluate arbitrary instructions as long as they have
|
||||
/// constant operands at the beginning of the loop.
|
||||
void IndVarSimplify::rewriteLoopExitValues(Loop *L, SCEVExpander &Rewriter) {
|
||||
// Verify the input to the pass in already in LCSSA form.
|
||||
assert(L->isLCSSAForm(*DT));
|
||||
// Check a pre-condition.
|
||||
assert(L->isRecursivelyLCSSAForm(*DT) && "Indvars did not preserve LCSSA!");
|
||||
|
||||
SmallVector<BasicBlock*, 8> ExitBlocks;
|
||||
L->getUniqueExitBlocks(ExitBlocks);
|
||||
@ -1167,10 +1179,11 @@ const SCEVAddRecExpr *WidenIV::getWideRecurrence(Instruction *NarrowUse) {
|
||||
|
||||
/// This IV user cannot be widen. Replace this use of the original narrow IV
|
||||
/// with a truncation of the new wide IV to isolate and eliminate the narrow IV.
|
||||
static void truncateIVUse(NarrowIVDefUse DU, DominatorTree *DT) {
|
||||
static void truncateIVUse(NarrowIVDefUse DU, DominatorTree *DT, LoopInfo *LI) {
|
||||
DEBUG(dbgs() << "INDVARS: Truncate IV " << *DU.WideDef
|
||||
<< " for user " << *DU.NarrowUse << "\n");
|
||||
IRBuilder<> Builder(getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT));
|
||||
IRBuilder<> Builder(
|
||||
getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT, LI));
|
||||
Value *Trunc = Builder.CreateTrunc(DU.WideDef, DU.NarrowDef->getType());
|
||||
DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, Trunc);
|
||||
}
|
||||
@ -1207,7 +1220,8 @@ bool WidenIV::widenLoopCompare(NarrowIVDefUse DU) {
|
||||
assert (CastWidth <= IVWidth && "Unexpected width while widening compare.");
|
||||
|
||||
// Widen the compare instruction.
|
||||
IRBuilder<> Builder(getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT));
|
||||
IRBuilder<> Builder(
|
||||
getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT, LI));
|
||||
DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, DU.WideDef);
|
||||
|
||||
// Widen the other operand of the compare, if necessary.
|
||||
@ -1229,7 +1243,7 @@ Instruction *WidenIV::widenIVUse(NarrowIVDefUse DU, SCEVExpander &Rewriter) {
|
||||
// After SimplifyCFG most loop exit targets have a single predecessor.
|
||||
// Otherwise fall back to a truncate within the loop.
|
||||
if (UsePhi->getNumOperands() != 1)
|
||||
truncateIVUse(DU, DT);
|
||||
truncateIVUse(DU, DT, LI);
|
||||
else {
|
||||
PHINode *WidePhi =
|
||||
PHINode::Create(DU.WideDef->getType(), 1, UsePhi->getName() + ".wide",
|
||||
@ -1297,7 +1311,7 @@ Instruction *WidenIV::widenIVUse(NarrowIVDefUse DU, SCEVExpander &Rewriter) {
|
||||
// This user does not evaluate to a recurence after widening, so don't
|
||||
// follow it. Instead insert a Trunc to kill off the original use,
|
||||
// eventually isolating the original narrow IV so it can be removed.
|
||||
truncateIVUse(DU, DT);
|
||||
truncateIVUse(DU, DT, LI);
|
||||
return nullptr;
|
||||
}
|
||||
// Assume block terminators cannot evaluate to a recurrence. We can't to
|
||||
@ -2165,9 +2179,9 @@ bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
|
||||
|
||||
// Clean up dead instructions.
|
||||
Changed |= DeleteDeadPHIs(L->getHeader(), TLI);
|
||||
|
||||
// Check a post-condition.
|
||||
assert(L->isLCSSAForm(*DT) &&
|
||||
"Indvars did not leave the loop in lcssa form!");
|
||||
assert(L->isRecursivelyLCSSAForm(*DT) && "Indvars did not preserve LCSSA!");
|
||||
|
||||
// Verify that LFTR, and any other change have not interfered with SCEV's
|
||||
// ability to compute trip count.
|
||||
|
45
test/Transforms/IndVarSimplify/pr25578.ll
Normal file
45
test/Transforms/IndVarSimplify/pr25578.ll
Normal file
@ -0,0 +1,45 @@
|
||||
; RUN: opt < %s -indvars -S | FileCheck %s
|
||||
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
||||
; CHECK-LABEL: @foo
|
||||
define void @foo() {
|
||||
entry:
|
||||
br label %L1_header
|
||||
|
||||
L1_header:
|
||||
br label %L2_header
|
||||
|
||||
; CHECK: L2_header:
|
||||
; CHECK: %[[INDVAR:.*]] = phi i64
|
||||
; CHECK: %[[TRUNC:.*]] = trunc i64 %[[INDVAR]] to i32
|
||||
L2_header:
|
||||
%i = phi i32 [ 0, %L1_header ], [ %i_next, %L2_latch ]
|
||||
%i_prom = sext i32 %i to i64
|
||||
br label %L3_header
|
||||
|
||||
L3_header:
|
||||
br i1 undef, label %L3_latch, label %L2_exiting_1
|
||||
|
||||
L3_latch:
|
||||
br i1 undef, label %L3_header, label %L2_exiting_2
|
||||
|
||||
L2_exiting_1:
|
||||
br i1 undef, label %L2_latch, label %L1_latch
|
||||
|
||||
L2_exiting_2:
|
||||
br i1 undef, label %L2_latch, label %L1_latch
|
||||
|
||||
L2_latch:
|
||||
%i_next = add nsw i32 %i, 1
|
||||
br label %L2_header
|
||||
|
||||
L1_latch:
|
||||
; CHECK: L1_latch:
|
||||
; CHECK: %i_lcssa = phi i32 [ %[[TRUNC]], %L2_exiting_1 ], [ %[[TRUNC]], %L2_exiting_2 ]
|
||||
|
||||
%i_lcssa = phi i32 [ %i, %L2_exiting_1 ], [ %i, %L2_exiting_2 ]
|
||||
br i1 undef, label %exit, label %L1_header
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user