mirror of
https://github.com/RPCS3/llvm.git
synced 2026-07-19 23:23:38 -04:00
[LICM] sink through non-trivially replicable PHI
Summary: The current LICM allows sinking an instruction only when it is exposed to exit blocks through a trivially replacable PHI of which all incoming values are the same instruction. This change enhance LICM to sink a sinkable instruction through non-trivially replacable PHIs by spliting predecessors of loop exits. Reviewers: hfinkel, majnemer, davidxl, bmakam, mcrosier, danielcdh, efriedma, jtony Reviewed By: efriedma Subscribers: nemanjai, dberlin, llvm-commits Differential Revision: https://reviews.llvm.org/D37163 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317335 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
+144
-60
@@ -62,6 +62,7 @@
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/Scalar/LoopPassManager.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
#include "llvm/Transforms/Utils/LoopUtils.h"
|
||||
#include "llvm/Transforms/Utils/SSAUpdater.h"
|
||||
@@ -93,9 +94,8 @@ static bool isNotUsedInLoop(const Instruction &I, const Loop *CurLoop,
|
||||
static bool hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,
|
||||
const LoopSafetyInfo *SafetyInfo,
|
||||
OptimizationRemarkEmitter *ORE);
|
||||
static bool sink(Instruction &I, const LoopInfo *LI, const DominatorTree *DT,
|
||||
const Loop *CurLoop, AliasSetTracker *CurAST,
|
||||
const LoopSafetyInfo *SafetyInfo,
|
||||
static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT,
|
||||
const Loop *CurLoop, const LoopSafetyInfo *SafetyInfo,
|
||||
OptimizationRemarkEmitter *ORE);
|
||||
static bool isSafeToExecuteUnconditionally(Instruction &Inst,
|
||||
const DominatorTree *DT,
|
||||
@@ -394,8 +394,12 @@ bool llvm::sinkRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI,
|
||||
//
|
||||
if (isNotUsedInLoop(I, CurLoop, SafetyInfo) &&
|
||||
canSinkOrHoistInst(I, AA, DT, CurLoop, CurAST, SafetyInfo, ORE)) {
|
||||
++II;
|
||||
Changed |= sink(I, LI, DT, CurLoop, CurAST, SafetyInfo, ORE);
|
||||
if (sink(I, LI, DT, CurLoop, SafetyInfo, ORE)) {
|
||||
++II;
|
||||
CurAST->deleteValue(&I);
|
||||
I.eraseFromParent();
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -717,26 +721,6 @@ static bool isNotUsedInLoop(const Instruction &I, const Loop *CurLoop,
|
||||
if (!BlockColors.empty() &&
|
||||
BlockColors.find(const_cast<BasicBlock *>(BB))->second.size() != 1)
|
||||
return false;
|
||||
|
||||
// A PHI node where all of the incoming values are this instruction are
|
||||
// special -- they can just be RAUW'ed with the instruction and thus
|
||||
// don't require a use in the predecessor. This is a particular important
|
||||
// special case because it is the pattern found in LCSSA form.
|
||||
if (isTriviallyReplacablePHI(*PN, I)) {
|
||||
if (CurLoop->contains(PN))
|
||||
return false;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, PHI node uses occur in predecessor blocks if the incoming
|
||||
// values. Check for such a use being inside the loop.
|
||||
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
|
||||
if (PN->getIncomingValue(i) == &I)
|
||||
if (CurLoop->contains(PN->getIncomingBlock(i)))
|
||||
return false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CurLoop->contains(UI))
|
||||
@@ -806,14 +790,96 @@ CloneInstructionInExitBlock(Instruction &I, BasicBlock &ExitBlock, PHINode &PN,
|
||||
return New;
|
||||
}
|
||||
|
||||
static Instruction *sinkThroughTriviallyReplacablePHI(
|
||||
PHINode *TPN, Instruction *I, LoopInfo *LI,
|
||||
SmallDenseMap<BasicBlock *, Instruction *, 32> &SunkCopies,
|
||||
const LoopSafetyInfo *SafetyInfo, const Loop *CurLoop) {
|
||||
assert(isTriviallyReplacablePHI(*TPN, *I) &&
|
||||
"Expect only trivially replacalbe PHI");
|
||||
BasicBlock *ExitBlock = TPN->getParent();
|
||||
Instruction *New;
|
||||
auto It = SunkCopies.find(ExitBlock);
|
||||
if (It != SunkCopies.end())
|
||||
New = It->second;
|
||||
else
|
||||
New = SunkCopies[ExitBlock] =
|
||||
CloneInstructionInExitBlock(*I, *ExitBlock, *TPN, LI, SafetyInfo);
|
||||
return New;
|
||||
}
|
||||
|
||||
static bool canSplitPredecessors(PHINode *PN) {
|
||||
BasicBlock *BB = PN->getParent();
|
||||
if (!BB->canSplitPredecessors())
|
||||
return false;
|
||||
for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) {
|
||||
BasicBlock *BBPred = *PI;
|
||||
if (isa<IndirectBrInst>(BBPred->getTerminator()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void splitPredecessorsOfLoopExit(PHINode *PN, DominatorTree *DT,
|
||||
LoopInfo *LI, const Loop *CurLoop) {
|
||||
#ifndef NDEBUG
|
||||
SmallVector<BasicBlock *, 32> ExitBlocks;
|
||||
CurLoop->getUniqueExitBlocks(ExitBlocks);
|
||||
SmallPtrSet<BasicBlock *, 32> ExitBlockSet(ExitBlocks.begin(),
|
||||
ExitBlocks.end());
|
||||
#endif
|
||||
BasicBlock *ExitBB = PN->getParent();
|
||||
assert(ExitBlockSet.count(ExitBB) && "Expect the PHI is in an exit block.");
|
||||
|
||||
// Split predecessors of the loop exit to make instructions in the loop are
|
||||
// exposed to exit blocks through trivially replacable PHIs while keeping the
|
||||
// loop in the canonical form where each predecessor of each exit block should
|
||||
// be contained within the loop. For example, this will convert the loop below
|
||||
// from
|
||||
//
|
||||
// LB1:
|
||||
// %v1 =
|
||||
// br %LE, %LB2
|
||||
// LB2:
|
||||
// %v2 =
|
||||
// br %LE, %LB1
|
||||
// LE:
|
||||
// %p = phi [%v1, %LB1], [%v2, %LB2] <-- non-trivially replacable
|
||||
//
|
||||
// to
|
||||
//
|
||||
// LB1:
|
||||
// %v1 =
|
||||
// br %LE.split, %LB2
|
||||
// LB2:
|
||||
// %v2 =
|
||||
// br %LE.split2, %LB1
|
||||
// LE.split:
|
||||
// %p1 = phi [%v1, %LB1] <-- trivially replacable
|
||||
// br %LE
|
||||
// LE.split2:
|
||||
// %p2 = phi [%v2, %LB2] <-- trivially replacable
|
||||
// br %LE
|
||||
// LE:
|
||||
// %p = phi [%p1, %LE.split], [%p2, %LE.split2]
|
||||
//
|
||||
SmallSetVector<BasicBlock *, 8> PredBBs(pred_begin(ExitBB), pred_end(ExitBB));
|
||||
while (!PredBBs.empty()) {
|
||||
BasicBlock *PredBB = *PredBBs.begin();
|
||||
assert(CurLoop->contains(PredBB) &&
|
||||
"Expect all predecessors are in the loop");
|
||||
if (PN->getBasicBlockIndex(PredBB) >= 0)
|
||||
SplitBlockPredecessors(ExitBB, PredBB, ".split.loop.exit", DT, LI, true);
|
||||
PredBBs.remove(PredBB);
|
||||
}
|
||||
}
|
||||
|
||||
/// When an instruction is found to only be used outside of the loop, this
|
||||
/// function moves it to the exit blocks and patches up SSA form as needed.
|
||||
/// This method is guaranteed to remove the original instruction from its
|
||||
/// position, and may either delete it or move it to outside of the loop.
|
||||
///
|
||||
static bool sink(Instruction &I, const LoopInfo *LI, const DominatorTree *DT,
|
||||
const Loop *CurLoop, AliasSetTracker *CurAST,
|
||||
const LoopSafetyInfo *SafetyInfo,
|
||||
static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT,
|
||||
const Loop *CurLoop, const LoopSafetyInfo *SafetyInfo,
|
||||
OptimizationRemarkEmitter *ORE) {
|
||||
DEBUG(dbgs() << "LICM sinking instruction: " << I << "\n");
|
||||
ORE->emit([&]() {
|
||||
@@ -828,6 +894,51 @@ static bool sink(Instruction &I, const LoopInfo *LI, const DominatorTree *DT,
|
||||
++NumSunk;
|
||||
Changed = true;
|
||||
|
||||
// Iterate over users to be ready for actual sinking. Replace users via
|
||||
// unrechable blocks with undef and make all user PHIs trivially replcable.
|
||||
SmallPtrSet<Instruction *, 8> VisitedUsers;
|
||||
for (Value::user_iterator UI = I.user_begin(), UE = I.user_end(); UI != UE;) {
|
||||
auto *User = cast<Instruction>(*UI);
|
||||
Use &U = UI.getUse();
|
||||
++UI;
|
||||
|
||||
if (VisitedUsers.count(User))
|
||||
continue;
|
||||
|
||||
if (!DT->isReachableFromEntry(User->getParent())) {
|
||||
User->replaceUsesOfWith(&I, UndefValue::get(I.getType()));
|
||||
continue;
|
||||
}
|
||||
|
||||
// The user must be a PHI node.
|
||||
PHINode *PN = cast<PHINode>(User);
|
||||
|
||||
// Surprisingly, instructions can be used outside of loops without any
|
||||
// exits. This can only happen in PHI nodes if the incoming block is
|
||||
// unreachable.
|
||||
BasicBlock *BB = PN->getIncomingBlock(U);
|
||||
if (!DT->isReachableFromEntry(BB)) {
|
||||
U = UndefValue::get(I.getType());
|
||||
continue;
|
||||
}
|
||||
|
||||
VisitedUsers.insert(PN);
|
||||
if (isTriviallyReplacablePHI(*PN, I))
|
||||
continue;
|
||||
|
||||
if (!canSplitPredecessors(PN))
|
||||
return false;
|
||||
|
||||
// Split predecessors of the PHI so that we can make users trivially
|
||||
// replacable.
|
||||
splitPredecessorsOfLoopExit(PN, DT, LI, CurLoop);
|
||||
|
||||
// Should rebuild the iterators, as they may be invalidated by
|
||||
// splitPredecessorsOfLoopExit().
|
||||
UI = I.user_begin();
|
||||
UE = I.user_end();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
SmallVector<BasicBlock *, 32> ExitBlocks;
|
||||
CurLoop->getUniqueExitBlocks(ExitBlocks);
|
||||
@@ -843,42 +954,15 @@ static bool sink(Instruction &I, const LoopInfo *LI, const DominatorTree *DT,
|
||||
// the instruction.
|
||||
while (!I.use_empty()) {
|
||||
Value::user_iterator UI = I.user_begin();
|
||||
auto *User = cast<Instruction>(*UI);
|
||||
if (!DT->isReachableFromEntry(User->getParent())) {
|
||||
User->replaceUsesOfWith(&I, UndefValue::get(I.getType()));
|
||||
continue;
|
||||
}
|
||||
// The user must be a PHI node.
|
||||
PHINode *PN = cast<PHINode>(User);
|
||||
|
||||
// Surprisingly, instructions can be used outside of loops without any
|
||||
// exits. This can only happen in PHI nodes if the incoming block is
|
||||
// unreachable.
|
||||
Use &U = UI.getUse();
|
||||
BasicBlock *BB = PN->getIncomingBlock(U);
|
||||
if (!DT->isReachableFromEntry(BB)) {
|
||||
U = UndefValue::get(I.getType());
|
||||
continue;
|
||||
}
|
||||
|
||||
BasicBlock *ExitBlock = PN->getParent();
|
||||
assert(ExitBlockSet.count(ExitBlock) &&
|
||||
PHINode *PN = cast<PHINode>(*UI);
|
||||
assert(ExitBlockSet.count(PN->getParent()) &&
|
||||
"The LCSSA PHI is not in an exit block!");
|
||||
|
||||
Instruction *New;
|
||||
auto It = SunkCopies.find(ExitBlock);
|
||||
if (It != SunkCopies.end())
|
||||
New = It->second;
|
||||
else
|
||||
New = SunkCopies[ExitBlock] =
|
||||
CloneInstructionInExitBlock(I, *ExitBlock, *PN, LI, SafetyInfo);
|
||||
|
||||
// The PHI must be trivially replacable.
|
||||
Instruction *New = sinkThroughTriviallyReplacablePHI(PN, &I, LI, SunkCopies,
|
||||
SafetyInfo, CurLoop);
|
||||
PN->replaceAllUsesWith(New);
|
||||
PN->eraseFromParent();
|
||||
}
|
||||
|
||||
CurAST->deleteValue(&I);
|
||||
I.eraseFromParent();
|
||||
return Changed;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; RUN: llc -verify-machineinstrs -mcpu=pwr7 < %s | FileCheck %s
|
||||
; RUN: llc -verify-machineinstrs -mcpu=pwr7 -ppc-gen-isel=false < %s | FileCheck --check-prefix=CHECK-NO-ISEL %s
|
||||
; RUN: llc -verify-machineinstrs -mcpu=pwr7 -ppc-gep-opt=0 < %s | FileCheck %s
|
||||
; RUN: llc -verify-machineinstrs -mcpu=pwr7 -ppc-gen-isel=false -ppc-gep-opt=0 < %s | FileCheck --check-prefix=CHECK-NO-ISEL %s
|
||||
target datalayout = "E-m:e-i64:64-n32:64"
|
||||
target triple = "powerpc64-unknown-linux-gnu"
|
||||
|
||||
@@ -38,10 +38,10 @@ while.end418: ; preds = %wait_on_buffer.exit
|
||||
; CHECK: stdcx.
|
||||
; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, [[REG]]
|
||||
; CHECK-NO-ISEL: bc 12, 20, [[TRUE:.LBB[0-9]+]]
|
||||
; CHECK-NO-ISEL: ori 4, 7, 0
|
||||
; CHECK-NO-ISEL: ori 7, 8, 0
|
||||
; CHECK-NO-ISEL-NEXT: b [[SUCCESSOR:.LBB[0-9]+]]
|
||||
; CHECK-NO-ISEL: [[TRUE]]
|
||||
; CHECK-NO-ISEL-NEXT: addi 4, 3, 0
|
||||
; CHECK-NO-ISEL: addi 7, 3, 0
|
||||
|
||||
if.then420: ; preds = %while.end418
|
||||
unreachable
|
||||
|
||||
@@ -392,6 +392,288 @@ lab60:
|
||||
indirectbr i8* undef, [label %lab21, label %lab19]
|
||||
}
|
||||
|
||||
declare void @f(i32*)
|
||||
; Check if LICM can sink a sinkable instruction the exit blocks through
|
||||
; a non-trivially replacable PHI node.
|
||||
;
|
||||
; CHECK-LABEL: @test14
|
||||
; CHECK-LABEL: Loop:
|
||||
; CHECK-NOT: mul
|
||||
; CHECK-NOT: sub
|
||||
;
|
||||
; CHECK-LABEL: Out12.split.loop.exit:
|
||||
; CHECK: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop ]
|
||||
; CHECK: %[[MUL:.*]] = mul i32 %N, %[[LCSSAPHI]]
|
||||
; CHECK: br label %Out12
|
||||
;
|
||||
; CHECK-LABEL: Out12.split.loop.exit1:
|
||||
; CHECK: %[[LCSSAPHI2:.*]] = phi i32 [ %N_addr.0.pn, %Loop ]
|
||||
; CHECK: %[[MUL2:.*]] = mul i32 %N, %[[LCSSAPHI2]]
|
||||
; CHECK: %[[SUB:.*]] = sub i32 %[[MUL2]], %N
|
||||
; CHECK: br label %Out12
|
||||
;
|
||||
; CHECK-LABEL: Out12:
|
||||
; CHECK: phi i32 [ %[[MUL]], %Out12.split.loop.exit ], [ %[[SUB]], %Out12.split.loop.exit1 ]
|
||||
define i32 @test14(i32 %N, i32 %N2, i1 %C) {
|
||||
Entry:
|
||||
br label %Loop
|
||||
Loop:
|
||||
%N_addr.0.pn = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ]
|
||||
%sink.mul = mul i32 %N, %N_addr.0.pn
|
||||
%sink.sub = sub i32 %sink.mul, %N
|
||||
%dec = add i32 %N_addr.0.pn, -1
|
||||
br i1 %C, label %ContLoop, label %Out12
|
||||
ContLoop:
|
||||
%tmp.1 = icmp ne i32 %N_addr.0.pn, 1
|
||||
br i1 %tmp.1, label %Loop, label %Out12
|
||||
Out12:
|
||||
%tmp = phi i32 [%sink.mul, %ContLoop], [%sink.sub, %Loop]
|
||||
ret i32 %tmp
|
||||
}
|
||||
|
||||
; In this test, splitting predecessors is not really required because the
|
||||
; operations of sinkable instructions (sub and mul) are same. In this case, we
|
||||
; can sink the same sinkable operations and modify the PHI to pass the operands
|
||||
; to the shared operations. As of now, we split predecessors of non-trivially
|
||||
; replicalbe PHIs by default in LICM because all incoming edges of a
|
||||
; non-trivially replacable PHI in LCSSA is critical.
|
||||
;
|
||||
; CHECK-LABEL: @test15
|
||||
; CHECK-LABEL: Loop:
|
||||
; CHECK-NOT: mul
|
||||
; CHECK-NOT: sub
|
||||
;
|
||||
; CHECK-LABEL: Out12.split.loop.exit:
|
||||
; CHECK: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop ]
|
||||
; CHECK: %[[MUL:.*]] = mul i32 %N, %[[LCSSAPHI]]
|
||||
; CHECK: %[[SUB:.*]] = sub i32 %[[MUL]], %N2
|
||||
; CHECK: br label %Out12
|
||||
;
|
||||
; CHECK-LABEL: Out12.split.loop.exit1:
|
||||
; CHECK: %[[LCSSAPHI2:.*]] = phi i32 [ %N_addr.0.pn, %Loop ]
|
||||
; CHECK: %[[MUL2:.*]] = mul i32 %N, %[[LCSSAPHI2]]
|
||||
; CHECK: %[[SUB2:.*]] = sub i32 %[[MUL2]], %N
|
||||
; CHECK: br label %Out12
|
||||
;
|
||||
; CHECK-LABEL: Out12:
|
||||
; CHECK: phi i32 [ %[[SUB]], %Out12.split.loop.exit ], [ %[[SUB2]], %Out12.split.loop.exit1 ]
|
||||
define i32 @test15(i32 %N, i32 %N2, i1 %C) {
|
||||
Entry:
|
||||
br label %Loop
|
||||
Loop:
|
||||
%N_addr.0.pn = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ]
|
||||
%sink.mul = mul i32 %N, %N_addr.0.pn
|
||||
%sink.sub = sub i32 %sink.mul, %N
|
||||
%sink.sub2 = sub i32 %sink.mul, %N2
|
||||
%dec = add i32 %N_addr.0.pn, -1
|
||||
br i1 %C, label %ContLoop, label %Out12
|
||||
ContLoop:
|
||||
%tmp.1 = icmp ne i32 %N_addr.0.pn, 1
|
||||
br i1 %tmp.1, label %Loop, label %Out12
|
||||
Out12:
|
||||
%tmp = phi i32 [%sink.sub2, %ContLoop], [%sink.sub, %Loop]
|
||||
ret i32 %tmp
|
||||
}
|
||||
|
||||
; Sink through a non-trivially replacable PHI node which use the same sinkable
|
||||
; instruction multiple times.
|
||||
;
|
||||
; CHECK-LABEL: @test16
|
||||
; CHECK-LABEL: Loop:
|
||||
; CHECK-NOT: mul
|
||||
;
|
||||
; CHECK-LABEL: Out.split.loop.exit:
|
||||
; CHECK: %[[PHI:.*]] = phi i32 [ %l2, %ContLoop ]
|
||||
; CHECK: br label %Out
|
||||
;
|
||||
; CHECK-LABEL: Out.split.loop.exit1:
|
||||
; CHECK: %[[SINKABLE:.*]] = mul i32 %l2.lcssa, %t.le
|
||||
; CHECK: br label %Out
|
||||
;
|
||||
; CHECK-LABEL: Out:
|
||||
; CHECK: %idx = phi i32 [ %[[PHI]], %Out.split.loop.exit ], [ %[[SINKABLE]], %Out.split.loop.exit1 ]
|
||||
define i32 @test16(i1 %c, i8** %P, i32* %P2, i64 %V) {
|
||||
entry:
|
||||
br label %loop.ph
|
||||
loop.ph:
|
||||
br label %Loop
|
||||
Loop:
|
||||
%iv = phi i64 [ 0, %loop.ph ], [ %next, %ContLoop ]
|
||||
%l2 = call i32 @getv()
|
||||
%t = trunc i64 %iv to i32
|
||||
%sinkable = mul i32 %l2, %t
|
||||
switch i32 %l2, label %ContLoop [
|
||||
i32 32, label %Out
|
||||
i32 46, label %Out
|
||||
i32 95, label %Out
|
||||
]
|
||||
ContLoop:
|
||||
%next = add nuw i64 %iv, 1
|
||||
%c1 = call i1 @getc()
|
||||
br i1 %c1, label %Loop, label %Out
|
||||
Out:
|
||||
%idx = phi i32 [ %l2, %ContLoop ], [ %sinkable, %Loop ], [ %sinkable, %Loop ], [ %sinkable, %Loop ]
|
||||
ret i32 %idx
|
||||
}
|
||||
|
||||
; Sink a sinkable instruction through multiple non-trivially replacable PHIs in
|
||||
; differect exit blocks.
|
||||
;
|
||||
; CHECK-LABEL: @test17
|
||||
; CHECK-LABEL: Loop:
|
||||
; CHECK-NOT: mul
|
||||
;
|
||||
; CHECK-LABEL:OutA.split.loop.exit{{.*}}:
|
||||
; CHECK: %[[OP1:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop1 ]
|
||||
; CHECK: %[[SINKABLE:.*]] = mul i32 %N, %[[OP1]]
|
||||
; CHECK: br label %OutA
|
||||
;
|
||||
; CHECK-LABEL:OutA:
|
||||
; CHECK: phi i32{{.*}}[ %[[SINKABLE]], %OutA.split.loop.exit{{.*}} ]
|
||||
;
|
||||
; CHECK-LABEL:OutB.split.loop.exit{{.*}}:
|
||||
; CHECK: %[[OP2:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop2 ]
|
||||
; CHECK: %[[SINKABLE2:.*]] = mul i32 %N, %[[OP2]]
|
||||
; CHECK: br label %OutB
|
||||
;
|
||||
; CHECK-LABEL:OutB:
|
||||
; CHECK: phi i32 {{.*}}[ %[[SINKABLE2]], %OutB.split.loop.exit{{.*}} ]
|
||||
define i32 @test17(i32 %N, i32 %N2) {
|
||||
Entry:
|
||||
br label %Loop
|
||||
Loop:
|
||||
%N_addr.0.pn = phi i32 [ %dec, %ContLoop3 ], [ %N, %Entry ]
|
||||
%sink.mul = mul i32 %N, %N_addr.0.pn
|
||||
%c0 = call i1 @getc()
|
||||
br i1 %c0 , label %ContLoop1, label %OutA
|
||||
ContLoop1:
|
||||
%c1 = call i1 @getc()
|
||||
br i1 %c1, label %ContLoop2, label %OutA
|
||||
|
||||
ContLoop2:
|
||||
%c2 = call i1 @getc()
|
||||
br i1 %c2, label %ContLoop3, label %OutB
|
||||
ContLoop3:
|
||||
%c3 = call i1 @getc()
|
||||
%dec = add i32 %N_addr.0.pn, -1
|
||||
br i1 %c3, label %Loop, label %OutB
|
||||
OutA:
|
||||
%tmp1 = phi i32 [%sink.mul, %ContLoop1], [%N2, %Loop]
|
||||
br label %Out12
|
||||
OutB:
|
||||
%tmp2 = phi i32 [%sink.mul, %ContLoop2], [%dec, %ContLoop3]
|
||||
br label %Out12
|
||||
Out12:
|
||||
%tmp = phi i32 [%tmp1, %OutA], [%tmp2, %OutB]
|
||||
ret i32 %tmp
|
||||
}
|
||||
|
||||
|
||||
; Sink a sinkable instruction through both trivially and non-trivially replacable PHIs.
|
||||
;
|
||||
; CHECK-LABEL: @test18
|
||||
; CHECK-LABEL: Loop:
|
||||
; CHECK-NOT: mul
|
||||
; CHECK-NOT: sub
|
||||
;
|
||||
; CHECK-LABEL:Out12.split.loop.exit:
|
||||
; CHECK: %[[OP:.*]] = phi i32 [ %iv, %ContLoop ]
|
||||
; CHECK: %[[DEC:.*]] = phi i32 [ %dec, %ContLoop ]
|
||||
; CHECK: %[[SINKMUL:.*]] = mul i32 %N, %[[OP]]
|
||||
; CHECK: %[[SINKSUB:.*]] = sub i32 %[[SINKMUL]], %N2
|
||||
; CHECK: br label %Out12
|
||||
;
|
||||
; CHECK-LABEL:Out12.split.loop.exit1:
|
||||
; CHECK: %[[OP2:.*]] = phi i32 [ %iv, %Loop ]
|
||||
; CHECK: %[[SINKMUL2:.*]] = mul i32 %N, %[[OP2]]
|
||||
; CHECK: %[[SINKSUB2:.*]] = sub i32 %[[SINKMUL2]], %N2
|
||||
; CHECK: br label %Out12
|
||||
;
|
||||
; CHECK-LABEL:Out12:
|
||||
; CHECK: %tmp1 = phi i32 [ %[[SINKSUB]], %Out12.split.loop.exit ], [ %[[SINKSUB2]], %Out12.split.loop.exit1 ]
|
||||
; CHECK: %tmp2 = phi i32 [ %[[DEC]], %Out12.split.loop.exit ], [ %[[SINKSUB2]], %Out12.split.loop.exit1 ]
|
||||
; CHECK: %add = add i32 %tmp1, %tmp2
|
||||
define i32 @test18(i32 %N, i32 %N2) {
|
||||
Entry:
|
||||
br label %Loop
|
||||
Loop:
|
||||
%iv = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ]
|
||||
%sink.mul = mul i32 %N, %iv
|
||||
%sink.sub = sub i32 %sink.mul, %N2
|
||||
%c0 = call i1 @getc()
|
||||
br i1 %c0, label %ContLoop, label %Out12
|
||||
ContLoop:
|
||||
%dec = add i32 %iv, -1
|
||||
%c1 = call i1 @getc()
|
||||
br i1 %c1, label %Loop, label %Out12
|
||||
Out12:
|
||||
%tmp1 = phi i32 [%sink.sub, %ContLoop], [%sink.sub, %Loop]
|
||||
%tmp2 = phi i32 [%dec, %ContLoop], [%sink.sub, %Loop]
|
||||
%add = add i32 %tmp1, %tmp2
|
||||
ret i32 %add
|
||||
}
|
||||
|
||||
; Do not sink an instruction through a non-trivially replacable PHI, to avoid
|
||||
; assert while splitting predecessors, if the terminator of predecessor is an
|
||||
; indirectbr.
|
||||
; CHECK-LABEL: @test19
|
||||
; CHECK-LABEL: L0:
|
||||
; CHECK: %sinkable = mul
|
||||
; CHECK: %sinkable2 = add
|
||||
|
||||
define i32 @test19(i1 %cond, i1 %cond2, i8* %address, i32 %v1) nounwind {
|
||||
entry:
|
||||
br label %L0
|
||||
L0:
|
||||
%indirect.goto.dest = select i1 %cond, i8* blockaddress(@test19, %exit), i8* %address
|
||||
%v2 = call i32 @getv()
|
||||
%sinkable = mul i32 %v1, %v2
|
||||
%sinkable2 = add i32 %v1, %v2
|
||||
indirectbr i8* %indirect.goto.dest, [label %L1, label %exit]
|
||||
|
||||
L1:
|
||||
%indirect.goto.dest2 = select i1 %cond2, i8* blockaddress(@test19, %exit), i8* %address
|
||||
indirectbr i8* %indirect.goto.dest2, [label %L0, label %exit]
|
||||
|
||||
exit:
|
||||
%r = phi i32 [%sinkable, %L0], [%sinkable2, %L1]
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
|
||||
; Do not sink through a non-trivially replacable PHI if splitting predecessors
|
||||
; not allowed in SplitBlockPredecessors().
|
||||
;
|
||||
; CHECK-LABEL: @test20
|
||||
; CHECK-LABEL: while.cond
|
||||
; CHECK: %sinkable = mul
|
||||
; CHECK: %sinkable2 = add
|
||||
define void @test20(i32* %s, i1 %b, i32 %v1, i32 %v2) personality i32 (...)* @__CxxFrameHandler3 {
|
||||
entry:
|
||||
br label %while.cond
|
||||
while.cond:
|
||||
%v = call i32 @getv()
|
||||
%sinkable = mul i32 %v, %v2
|
||||
%sinkable2 = add i32 %v, %v2
|
||||
br i1 %b, label %try.cont, label %while.body
|
||||
while.body:
|
||||
invoke void @may_throw()
|
||||
to label %while.body2 unwind label %catch.dispatch
|
||||
while.body2:
|
||||
invoke void @may_throw2()
|
||||
to label %while.cond unwind label %catch.dispatch
|
||||
catch.dispatch:
|
||||
%.lcssa1 = phi i32 [ %sinkable, %while.body ], [ %sinkable2, %while.body2 ]
|
||||
%cp = cleanuppad within none []
|
||||
store i32 %.lcssa1, i32* %s
|
||||
cleanupret from %cp unwind to caller
|
||||
try.cont:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @may_throw()
|
||||
declare void @may_throw2()
|
||||
declare i32 @__CxxFrameHandler3(...)
|
||||
declare i32 @getv()
|
||||
declare i1 @getc()
|
||||
declare void @f(i32*)
|
||||
declare void @g()
|
||||
|
||||
Reference in New Issue
Block a user