1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

Ensure SplitEdge to return the new block between the two given blocks

This PR implements the function splitBasicBlockBefore to address an
issue
that occurred during SplitEdge(BB, Succ, ...), inside splitBlockBefore.
The issue occurs in SplitEdge when the Succ has a single predecessor
and the edge between the BB and Succ is not critical. This produces
the result ‘BB->Succ->New’. The new function splitBasicBlockBefore
was added to splitBlockBefore to handle the issue and now produces
the correct result ‘BB->New->Succ’.

Below is an example of splitting the block bb1 at its first instruction.

/// Original IR
bb0:
	br bb1
bb1:
        %0 = mul i32 1, 2
	br bb2
bb2:
/// IR after splitEdge(bb0, bb1) using splitBasicBlock
bb0:
	br bb1
bb1:
	br bb1.split
bb1.split:
        %0 = mul i32 1, 2
	br bb2
bb2:
/// IR after splitEdge(bb0, bb1) using splitBasicBlockBefore
bb0:
	br bb1.split
bb1.split
	br bb1
bb1:
        %0 = mul i32 1, 2
	br bb2
bb2:

Differential Revision: https://reviews.llvm.org/D92200
This commit is contained in:
Whitney Tsang 2020-12-18 17:35:46 +00:00
parent 7b36fe3c9b
commit 0ac56aa46f
7 changed files with 385 additions and 28 deletions

View File

@ -398,22 +398,49 @@ public:
/// Split the basic block into two basic blocks at the specified instruction.
///
/// Note that all instructions BEFORE the specified iterator stay as part of
/// the original basic block, an unconditional branch is added to the original
/// BB, and the rest of the instructions in the BB are moved to the new BB,
/// including the old terminator. The newly formed BasicBlock is returned.
/// This function invalidates the specified iterator.
/// If \p Before is true, splitBasicBlockBefore handles the
/// block splitting. Otherwise, execution proceeds as described below.
///
/// Note that all instructions BEFORE the specified iterator
/// stay as part of the original basic block, an unconditional branch is added
/// to the original BB, and the rest of the instructions in the BB are moved
/// to the new BB, including the old terminator. The newly formed basic block
/// is returned. This function invalidates the specified iterator.
///
/// Note that this only works on well formed basic blocks (must have a
/// terminator), and 'I' must not be the end of instruction list (which would
/// cause a degenerate basic block to be formed, having a terminator inside of
/// the basic block).
/// terminator), and \p 'I' must not be the end of instruction list (which
/// would cause a degenerate basic block to be formed, having a terminator
/// inside of the basic block).
///
/// Also note that this doesn't preserve any passes. To split blocks while
/// keeping loop information consistent, use the SplitBlock utility function.
BasicBlock *splitBasicBlock(iterator I, const Twine &BBName = "");
BasicBlock *splitBasicBlock(Instruction *I, const Twine &BBName = "") {
return splitBasicBlock(I->getIterator(), BBName);
BasicBlock *splitBasicBlock(iterator I, const Twine &BBName = "",
bool Before = false);
BasicBlock *splitBasicBlock(Instruction *I, const Twine &BBName = "",
bool Before = false) {
return splitBasicBlock(I->getIterator(), BBName, Before);
}
/// Split the basic block into two basic blocks at the specified instruction
/// and insert the new basic blocks as the predecessor of the current block.
///
/// This function ensures all instructions AFTER and including the specified
/// iterator \p I are part of the original basic block. All Instructions
/// BEFORE the iterator \p I are moved to the new BB and an unconditional
/// branch is added to the new BB. The new basic block is returned.
///
/// Note that this only works on well formed basic blocks (must have a
/// terminator), and \p 'I' must not be the end of instruction list (which
/// would cause a degenerate basic block to be formed, having a terminator
/// inside of the basic block). \p 'I' cannot be a iterator for a PHINode
/// with multiple incoming blocks.
///
/// Also note that this doesn't preserve any passes. To split blocks while
/// keeping loop information consistent, use the SplitBlockBefore utility
/// function.
BasicBlock *splitBasicBlockBefore(iterator I, const Twine &BBName = "");
BasicBlock *splitBasicBlockBefore(Instruction *I, const Twine &BBName = "") {
return splitBasicBlockBefore(I->getIterator(), BBName);
}
/// Returns true if there are any uses of this basic block other than

View File

@ -244,19 +244,33 @@ unsigned SplitAllCriticalEdges(Function &F,
const CriticalEdgeSplittingOptions &Options =
CriticalEdgeSplittingOptions());
/// Split the edge connecting specified block.
/// Split the edge connecting the specified blocks, and return the newly created
/// basic block between \p From and \p To.
BasicBlock *SplitEdge(BasicBlock *From, BasicBlock *To,
DominatorTree *DT = nullptr, LoopInfo *LI = nullptr,
MemorySSAUpdater *MSSAU = nullptr);
/// Split the specified block at the specified instruction - everything before
/// SplitPt stays in Old and everything starting with SplitPt moves to a new
/// block. The two blocks are joined by an unconditional branch and the loop
/// info is updated.
/// Split the specified block at the specified instruction.
///
/// If \p Before is true, splitBlockBefore handles the block
/// splitting. Otherwise, execution proceeds as described below.
///
/// Everything before \p SplitPt stays in \p Old and everything starting with \p
/// SplitPt moves to a new block. The two blocks are joined by an unconditional
/// branch. The new block with name \p BBName is returned.
BasicBlock *SplitBlock(BasicBlock *Old, Instruction *SplitPt,
DominatorTree *DT = nullptr, LoopInfo *LI = nullptr,
MemorySSAUpdater *MSSAU = nullptr,
const Twine &BBName = "");
const Twine &BBName = "", bool Before = false);
/// Split the specified block at the specified instruction \p SplitPt.
/// All instructions before \p SplitPt are moved to a new block and all
/// instructions after \p SplitPt stay in the old block. The new block and the
/// old block are joined by inserting an unconditional branch to the end of the
/// new block. The new block with name \p BBName is returned.
BasicBlock *splitBlockBefore(BasicBlock *Old, Instruction *SplitPt,
DominatorTree *DT, LoopInfo *LI,
MemorySSAUpdater *MSSAU, const Twine &BBName = "");
/// This method introduces at least one new basic block into the function and
/// moves some of the predecessors of BB to be predecessors of the new block.

View File

@ -372,7 +372,11 @@ bool BasicBlock::isLegalToHoistInto() const {
return !Term->isExceptionalTerminator();
}
BasicBlock *BasicBlock::splitBasicBlock(iterator I, const Twine &BBName) {
BasicBlock *BasicBlock::splitBasicBlock(iterator I, const Twine &BBName,
bool Before) {
if (Before)
return splitBasicBlockBefore(I, BBName);
assert(getTerminator() && "Can't use splitBasicBlock on degenerate BB!");
assert(I != InstList.end() &&
"Trying to get me to create degenerate basic block!");
@ -399,6 +403,40 @@ BasicBlock *BasicBlock::splitBasicBlock(iterator I, const Twine &BBName) {
return New;
}
BasicBlock *BasicBlock::splitBasicBlockBefore(iterator I, const Twine &BBName) {
assert(getTerminator() &&
"Can't use splitBasicBlockBefore on degenerate BB!");
assert(I != InstList.end() &&
"Trying to get me to create degenerate basic block!");
assert((!isa<PHINode>(*I) || getSinglePredecessor()) &&
"cannot split on multi incoming phis");
BasicBlock *New = BasicBlock::Create(getContext(), BBName, getParent(), this);
// Save DebugLoc of split point before invalidating iterator.
DebugLoc Loc = I->getDebugLoc();
// Move all of the specified instructions from the original basic block into
// the new basic block.
New->getInstList().splice(New->end(), this->getInstList(), begin(), I);
// Loop through all of the predecessors of the 'this' block (which will be the
// predecessors of the New block), replace the specified successor 'this'
// block to point at the New block and update any PHI nodes in 'this' block.
// If there were PHI nodes in 'this' block, the PHI nodes are updated
// to reflect that the incoming branches will be from the New block and not
// from predecessors of the 'this' block.
for (BasicBlock *Pred : predecessors(this)) {
Instruction *TI = Pred->getTerminator();
TI->replaceSuccessorWith(this, New);
this->replacePhiUsesWith(Pred, New);
}
// Add a branch instruction from "New" to "this" Block.
BranchInst *BI = BranchInst::Create(this, New);
BI->setDebugLoc(Loc);
return New;
}
void BasicBlock::replacePhiUsesWith(BasicBlock *Old, BasicBlock *New) {
// N.B. This might not be a complete BasicBlock, so don't assume
// that it ends with a non-phi instruction.

View File

@ -510,7 +510,7 @@ BasicBlock *llvm::SplitEdge(BasicBlock *BB, BasicBlock *Succ, DominatorTree *DT,
// block.
assert(SP == BB && "CFG broken");
SP = nullptr;
return SplitBlock(Succ, &Succ->front(), DT, LI, MSSAU);
return SplitBlock(Succ, &Succ->front(), DT, LI, MSSAU, "", /*Before=*/true);
}
// Otherwise, if BB has a single successor, split it at the bottom of the
@ -537,7 +537,10 @@ llvm::SplitAllCriticalEdges(Function &F,
BasicBlock *llvm::SplitBlock(BasicBlock *Old, Instruction *SplitPt,
DominatorTree *DT, LoopInfo *LI,
MemorySSAUpdater *MSSAU, const Twine &BBName) {
MemorySSAUpdater *MSSAU, const Twine &BBName,
bool Before) {
if (Before)
return splitBlockBefore(Old, SplitPt, DT, LI, MSSAU, BBName);
BasicBlock::iterator SplitIt = SplitPt->getIterator();
while (isa<PHINode>(SplitIt) || SplitIt->isEHPad())
++SplitIt;
@ -569,6 +572,51 @@ BasicBlock *llvm::SplitBlock(BasicBlock *Old, Instruction *SplitPt,
return New;
}
BasicBlock *llvm::splitBlockBefore(BasicBlock *Old, Instruction *SplitPt,
DominatorTree *DT, LoopInfo *LI,
MemorySSAUpdater *MSSAU,
const Twine &BBName) {
BasicBlock::iterator SplitIt = SplitPt->getIterator();
while (isa<PHINode>(SplitIt) || SplitIt->isEHPad())
++SplitIt;
std::string Name = BBName.str();
BasicBlock *New = Old->splitBasicBlock(
SplitIt, Name.empty() ? Old->getName() + ".split" : Name,
/* Before=*/true);
// The new block lives in whichever loop the old one did. This preserves
// LCSSA as well, because we force the split point to be after any PHI nodes.
if (LI)
if (Loop *L = LI->getLoopFor(Old))
L->addBasicBlockToLoop(New, *LI);
if (DT) {
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
SmallVector<DominatorTree::UpdateType, 8> DTUpdates;
// New dominates Old. The predecessor nodes of the Old node dominate
// New node.
DTUpdates.push_back({DominatorTree::Insert, New, Old});
for (BasicBlock *Pred : predecessors(New))
if (DT->getNode(Pred)) {
DTUpdates.push_back({DominatorTree::Insert, Pred, New});
DTUpdates.push_back({DominatorTree::Delete, Pred, Old});
}
DTU.applyUpdates(DTUpdates);
DTU.flush();
// Move MemoryAccesses still tracked in Old, but part of New now.
// Update accesses in successor blocks accordingly.
if (MSSAU) {
MSSAU->applyUpdates(DTUpdates, *DT);
if (VerifyMemorySSA)
MSSAU->getMemorySSA()->verifyMemorySSA();
}
}
return New;
}
/// Update DominatorTree, LoopInfo, and LCCSA analysis information.
static void UpdateAnalysisInformation(BasicBlock *OldBB, BasicBlock *NewBB,
ArrayRef<BasicBlock *> Preds,

View File

@ -100,7 +100,7 @@ define amdgpu_kernel void @test_bitcast_use_workitem_id_x() #0 {
; OPT-LABEL: @test_invoke(
; OPT: %1 = bitcast float 2.000000e+00 to i32
; OPT: %val = invoke i32 @ident_i32(i32 %1)
; OPT-NEXT: to label %continue unwind label %broken
; OPT-NEXT: to label %continue.split unwind label %broken
; OPT-LABEL: continue.split:
; OPT: bitcast i32 %val to float
@_ZTIi = external global i8*

View File

@ -36,7 +36,7 @@
; CHECK: loop_begin.us1: ; preds = %loop_begin.backedge.us5, %.split.split.us
; CHECK-NEXT: %var_val.us2 = load i32, i32* %var
; CHECK-NEXT: switch i32 2, label %default.us-lcssa.us-lcssa.us [
; CHECK-NEXT: i32 1, label %inc.us4
; CHECK-NEXT: i32 1, label %inc.split.us
; CHECK-NEXT: i32 2, label %dec.us3
; CHECK-NEXT: ]
@ -50,15 +50,15 @@
; CHECK: loop_begin: ; preds = %loop_begin.backedge, %.split.split
; CHECK-NEXT: %var_val = load i32, i32* %var
; CHECK-NEXT: switch i32 %c, label %default.us-lcssa.us-lcssa [
; CHECK-NEXT: i32 1, label %inc
; CHECK-NEXT: i32 2, label %dec
; CHECK-NEXT: i32 1, label %inc.split
; CHECK-NEXT: i32 2, label %dec.split
; CHECK-NEXT: ]
; CHECK: inc: ; preds = %loop_begin
; CHECK-NEXT: br i1 true, label %us-unreachable.us-lcssa, label %inc.split
; CHECK: inc.split: ; preds = %loop_begin
; CHECK-NEXT: br i1 true, label %us-unreachable.us-lcssa, label %inc
; CHECK: dec: ; preds = %loop_begin
; CHECK-NEXT: br i1 true, label %us-unreachable6, label %dec.split
; CHECK: dec.split: ; preds = %loop_begin
; CHECK-NEXT: br i1 true, label %us-unreachable6, label %dec
define i32 @test(i32* %var) {
%mem = alloca i32

View File

@ -7,10 +7,15 @@
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Dominators.h"
@ -28,6 +33,13 @@ static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
return Mod;
}
static BasicBlock *getBasicBlockByName(Function &F, StringRef Name) {
for (BasicBlock &BB : F)
if (BB.getName() == Name)
return &BB;
llvm_unreachable("Expected to find basic block!");
}
TEST(BasicBlockUtils, EliminateUnreachableBlocks) {
LLVMContext C;
@ -58,6 +70,224 @@ TEST(BasicBlockUtils, EliminateUnreachableBlocks) {
EXPECT_TRUE(DT.verify());
}
TEST(BasicBlockUtils, SplitEdge_ex1) {
LLVMContext C;
std::unique_ptr<Module> M =
parseIR(C, "define void @foo(i1 %cond0) {\n"
"entry:\n"
" br i1 %cond0, label %bb0, label %bb1\n"
"bb0:\n"
" %0 = mul i32 1, 2\n"
" br label %bb1\n"
"bb1:\n"
" br label %bb2\n"
"bb2:\n"
" ret void\n"
"}\n"
"\n");
Function *F = M->getFunction("foo");
DominatorTree DT(*F);
BasicBlock *SrcBlock;
BasicBlock *DestBlock;
BasicBlock *NewBB;
SrcBlock = getBasicBlockByName(*F, "entry");
DestBlock = getBasicBlockByName(*F, "bb0");
NewBB = SplitEdge(SrcBlock, DestBlock, &DT, nullptr, nullptr);
EXPECT_TRUE(DT.verify());
EXPECT_EQ(NewBB->getSinglePredecessor(), SrcBlock);
EXPECT_EQ(NewBB->getSingleSuccessor(), DestBlock);
EXPECT_EQ(NewBB->getParent(), F);
bool BBFlag = false;
for (BasicBlock &BB : *F) {
if (BB.getName() == NewBB->getName()) {
BBFlag = true;
}
}
EXPECT_TRUE(BBFlag);
}
TEST(BasicBlockUtils, SplitEdge_ex2) {
LLVMContext C;
std::unique_ptr<Module> M = parseIR(C, "define void @foo() {\n"
"bb0:\n"
" br label %bb2\n"
"bb1:\n"
" br label %bb2\n"
"bb2:\n"
" ret void\n"
"}\n"
"\n");
Function *F = M->getFunction("foo");
DominatorTree DT(*F);
BasicBlock *SrcBlock;
BasicBlock *DestBlock;
BasicBlock *NewBB;
SrcBlock = getBasicBlockByName(*F, "bb0");
DestBlock = getBasicBlockByName(*F, "bb2");
NewBB = SplitEdge(SrcBlock, DestBlock, &DT, nullptr, nullptr);
EXPECT_TRUE(DT.verify());
EXPECT_EQ(NewBB->getSinglePredecessor(), SrcBlock);
EXPECT_EQ(NewBB->getSingleSuccessor(), DestBlock);
EXPECT_EQ(NewBB->getParent(), F);
bool BBFlag = false;
for (BasicBlock &BB : *F) {
if (BB.getName() == NewBB->getName()) {
BBFlag = true;
}
}
EXPECT_TRUE(BBFlag);
}
TEST(BasicBlockUtils, SplitEdge_ex3) {
LLVMContext C;
std::unique_ptr<Module> M =
parseIR(C, "define i32 @foo(i32 %n) {\n"
"entry:\n"
" br label %header\n"
"header:\n"
" %sum.02 = phi i32 [ 0, %entry ], [ %sum.1, %bb3 ]\n"
" %0 = phi i32 [ 0, %entry ], [ %4, %bb3 ] \n"
" %1 = icmp slt i32 %0, %n \n"
" br i1 %1, label %bb0, label %bb1\n"
"bb0:\n"
" %2 = add nsw i32 %sum.02, 2\n"
" br label %bb2\n"
"bb1:\n"
" %3 = add nsw i32 %sum.02, 1\n"
" br label %bb2\n"
"bb2:\n"
" %sum.1 = phi i32 [ %2, %bb0 ], [ %3, %bb1 ]\n"
" br label %bb3\n"
"bb3:\n"
" %4 = add nsw i32 %0, 1 \n"
" %5 = icmp slt i32 %4, 100\n"
" br i1 %5, label %header, label %bb4\n"
"bb4:\n"
" %sum.0.lcssa = phi i32 [ %sum.1, %bb3 ]\n"
" ret i32 %sum.0.lcssa\n"
"}\n"
"\n");
Function *F = M->getFunction("foo");
DominatorTree DT(*F);
LoopInfo LI(DT);
DataLayout DL("e-i64:64-f80:128-n8:16:32:64-S128");
TargetLibraryInfoImpl TLII;
TargetLibraryInfo TLI(TLII);
AssumptionCache AC(*F);
AAResults AA(TLI);
BasicAAResult BAA(DL, *F, TLI, AC, &DT);
AA.addAAResult(BAA);
MemorySSA MSSA(*F, &AA, &DT);
MemorySSAUpdater Updater(&MSSA);
BasicBlock *SrcBlock;
BasicBlock *DestBlock;
BasicBlock *NewBB;
SrcBlock = getBasicBlockByName(*F, "header");
DestBlock = getBasicBlockByName(*F, "bb0");
NewBB = SplitEdge(SrcBlock, DestBlock, &DT, &LI, &Updater);
Updater.getMemorySSA()->verifyMemorySSA();
EXPECT_TRUE(DT.verify());
EXPECT_NE(LI.getLoopFor(SrcBlock), nullptr);
EXPECT_NE(LI.getLoopFor(DestBlock), nullptr);
EXPECT_NE(LI.getLoopFor(NewBB), nullptr);
EXPECT_EQ(NewBB->getSinglePredecessor(), SrcBlock);
EXPECT_EQ(NewBB->getSingleSuccessor(), DestBlock);
EXPECT_EQ(NewBB->getParent(), F);
bool BBFlag = false;
for (BasicBlock &BB : *F) {
if (BB.getName() == NewBB->getName()) {
BBFlag = true;
}
}
EXPECT_TRUE(BBFlag);
}
TEST(BasicBlockUtils, splitBasicBlockBefore_ex1) {
LLVMContext C;
std::unique_ptr<Module> M = parseIR(C, "define void @foo() {\n"
"bb0:\n"
" %0 = mul i32 1, 2\n"
" br label %bb2\n"
"bb1:\n"
" br label %bb3\n"
"bb2:\n"
" %1 = phi i32 [ %0, %bb0 ]\n"
" br label %bb3\n"
"bb3:\n"
" ret void\n"
"}\n"
"\n");
Function *F = M->getFunction("foo");
DominatorTree DT(*F);
BasicBlock *DestBlock;
BasicBlock *NewBB;
DestBlock = getBasicBlockByName(*F, "bb2");
NewBB = DestBlock->splitBasicBlockBefore(DestBlock->front().getIterator(),
"test");
PHINode *PN = dyn_cast<PHINode>(&(DestBlock->front()));
EXPECT_EQ(PN->getIncomingBlock(0), NewBB);
EXPECT_EQ(NewBB->getName(), "test");
EXPECT_EQ(NewBB->getSingleSuccessor(), DestBlock);
EXPECT_EQ(DestBlock->getSinglePredecessor(), NewBB);
}
#ifndef NDEBUG
TEST(BasicBlockUtils, splitBasicBlockBefore_ex2) {
LLVMContext C;
std::unique_ptr<Module> M =
parseIR(C, "define void @foo() {\n"
"bb0:\n"
" %0 = mul i32 1, 2\n"
" br label %bb2\n"
"bb1:\n"
" br label %bb2\n"
"bb2:\n"
" %1 = phi i32 [ %0, %bb0 ], [ 1, %bb1 ]\n"
" br label %bb3\n"
"bb3:\n"
" ret void\n"
"}\n"
"\n");
Function *F = M->getFunction("foo");
DominatorTree DT(*F);
BasicBlock *DestBlock;
DestBlock = getBasicBlockByName(*F, "bb2");
ASSERT_DEATH(
{
DestBlock->splitBasicBlockBefore(DestBlock->front().getIterator(),
"test");
},
"cannot split on multi incoming phis");
}
#endif
TEST(BasicBlockUtils, NoUnreachableBlocksToEliminate) {
LLVMContext C;