[llvm] 75a3d9d - [IR][NFC] Adds BasicBlock::splice().
Vasileios Porpodas via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 1 13:54:45 PST 2022
Author: Vasileios Porpodas
Date: 2022-12-01T13:52:57-08:00
New Revision: 75a3d9d1b30d148e0cade62c45be7accb5661dc4
URL: https://github.com/llvm/llvm-project/commit/75a3d9d1b30d148e0cade62c45be7accb5661dc4
DIFF: https://github.com/llvm/llvm-project/commit/75a3d9d1b30d148e0cade62c45be7accb5661dc4.diff
LOG: [IR][NFC] Adds BasicBlock::splice().
Currently the only way to do this is to work with the instruction list directly.
This is part of a series of cleanup patches towards making BasicBlock::getInstList() private.
Differential Revision: https://reviews.llvm.org/D138977
Added:
Modified:
llvm/include/llvm/IR/BasicBlock.h
llvm/lib/IR/BasicBlock.cpp
llvm/unittests/IR/BasicBlockTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h
index ff0ea61771c3c..379dd4f8922cc 100644
--- a/llvm/include/llvm/IR/BasicBlock.h
+++ b/llvm/include/llvm/IR/BasicBlock.h
@@ -453,6 +453,28 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
return splitBasicBlockBefore(I->getIterator(), BBName);
}
+ /// Transfer all instructions from \p FromBB to this basic block at \p ToIt.
+ void splice(BasicBlock::iterator ToIt, BasicBlock *FromBB) {
+ splice(ToIt, FromBB, FromBB->begin(), FromBB->end());
+ }
+
+ /// Transfer one instruction from \p FromBB at \p FromIt to this basic block
+ /// at \p ToIt.
+ void splice(BasicBlock::iterator ToIt, BasicBlock *FromBB,
+ BasicBlock::iterator FromIt) {
+ auto FromItNext = std::next(FromIt);
+ // Single-element splice is a noop if destination == source.
+ if (ToIt == FromIt || ToIt == FromItNext)
+ return;
+ splice(ToIt, FromBB, FromIt, FromItNext);
+ }
+
+ /// Transfer a range of instructions that belong to \p FromBB from \p
+ /// FromBeginIt to \p FromEndIt, to this basic block at \p ToIt.
+ void splice(BasicBlock::iterator ToIt, BasicBlock *FromBB,
+ BasicBlock::iterator FromBeginIt,
+ BasicBlock::iterator FromEndIt);
+
/// Returns true if there are any uses of this basic block other than
/// direct branches, switches, etc. to it.
bool hasAddressTaken() const {
diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp
index 160492ae7fb16..fcd6ff08c319b 100644
--- a/llvm/lib/IR/BasicBlock.cpp
+++ b/llvm/lib/IR/BasicBlock.cpp
@@ -468,6 +468,18 @@ BasicBlock *BasicBlock::splitBasicBlockBefore(iterator I, const Twine &BBName) {
return New;
}
+void BasicBlock::splice(BasicBlock::iterator ToIt, BasicBlock *FromBB,
+ BasicBlock::iterator FromBeginIt,
+ BasicBlock::iterator FromEndIt) {
+#ifdef EXPENSIVE_CHECKS
+ // Check that FromBeginIt is befor FromEndIt.
+ auto FromBBEnd = FromBB->end();
+ for (auto It = FromBeginIt; It != FromEndIt; ++It)
+ assert(It != FromBBEnd && "FromBeginIt not before FromEndIt!");
+#endif // EXPENSIVE_CHECKS
+ getInstList().splice(ToIt, FromBB->getInstList(), FromBeginIt, FromEndIt);
+}
+
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.
diff --git a/llvm/unittests/IR/BasicBlockTest.cpp b/llvm/unittests/IR/BasicBlockTest.cpp
index b364b981b4030..c0cf5db4e6993 100644
--- a/llvm/unittests/IR/BasicBlockTest.cpp
+++ b/llvm/unittests/IR/BasicBlockTest.cpp
@@ -260,5 +260,252 @@ TEST_F(InstrOrderInvalidationTest, EraseNoInvalidation) {
EXPECT_EQ(std::next(I1->getIterator()), I3->getIterator());
}
+static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
+ SMDiagnostic Err;
+ std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
+ if (!Mod)
+ Err.print(__FILE__, errs());
+ return Mod;
+}
+
+TEST(BasicBlockTest, SpliceFromBB) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ define void @f(i32 %a) {
+ from:
+ %fromInstr1 = add i32 %a, %a
+ %fromInstr2 = sub i32 %a, %a
+ br label %to
+
+ to:
+ %toInstr1 = mul i32 %a, %a
+ %toInstr2 = sdiv i32 %a, %a
+ ret void
+ }
+)");
+ Function *F = &*M->begin();
+ auto BBIt = F->begin();
+ BasicBlock *FromBB = &*BBIt++;
+ BasicBlock *ToBB = &*BBIt++;
+
+ auto FromBBIt = FromBB->begin();
+ Instruction *FromI1 = &*FromBBIt++;
+ Instruction *FromI2 = &*FromBBIt++;
+ Instruction *FromBr = &*FromBBIt++;
+
+ auto ToBBIt = ToBB->begin();
+ Instruction *ToI1 = &*ToBBIt++;
+ Instruction *ToI2 = &*ToBBIt++;
+ Instruction *ToRet = &*ToBBIt++;
+ ToBB->splice(ToI1->getIterator(), FromBB);
+
+ EXPECT_TRUE(FromBB->empty());
+
+ auto It = ToBB->begin();
+ EXPECT_EQ(&*It++, FromI1);
+ EXPECT_EQ(&*It++, FromI2);
+ EXPECT_EQ(&*It++, FromBr);
+ EXPECT_EQ(&*It++, ToI1);
+ EXPECT_EQ(&*It++, ToI2);
+ EXPECT_EQ(&*It++, ToRet);
+}
+
+TEST(BasicBlockTest, SpliceOneInstr) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ define void @f(i32 %a) {
+ from:
+ %fromInstr1 = add i32 %a, %a
+ %fromInstr2 = sub i32 %a, %a
+ br label %to
+
+ to:
+ %toInstr1 = mul i32 %a, %a
+ %toInstr2 = sdiv i32 %a, %a
+ ret void
+ }
+)");
+ Function *F = &*M->begin();
+ auto BBIt = F->begin();
+ BasicBlock *FromBB = &*BBIt++;
+ BasicBlock *ToBB = &*BBIt++;
+
+ auto FromBBIt = FromBB->begin();
+ Instruction *FromI1 = &*FromBBIt++;
+ Instruction *FromI2 = &*FromBBIt++;
+ Instruction *FromBr = &*FromBBIt++;
+
+ auto ToBBIt = ToBB->begin();
+ Instruction *ToI1 = &*ToBBIt++;
+ Instruction *ToI2 = &*ToBBIt++;
+ Instruction *ToRet = &*ToBBIt++;
+ ToBB->splice(ToI1->getIterator(), FromBB, FromI2->getIterator());
+
+ EXPECT_EQ(FromBB->size(), 2u);
+ EXPECT_EQ(ToBB->size(), 4u);
+
+ auto It = FromBB->begin();
+ EXPECT_EQ(&*It++, FromI1);
+ EXPECT_EQ(&*It++, FromBr);
+
+ It = ToBB->begin();
+ EXPECT_EQ(&*It++, FromI2);
+ EXPECT_EQ(&*It++, ToI1);
+ EXPECT_EQ(&*It++, ToI2);
+ EXPECT_EQ(&*It++, ToRet);
+}
+
+TEST(BasicBlockTest, SpliceOneInstrWhenFromIsSameAsTo) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ define void @f(i32 %a) {
+ bb:
+ %instr1 = add i32 %a, %a
+ %instr2 = sub i32 %a, %a
+ ret void
+ }
+)");
+ Function *F = &*M->begin();
+ auto BBIt = F->begin();
+ BasicBlock *BB = &*BBIt++;
+
+ auto It = BB->begin();
+ Instruction *Instr1 = &*It++;
+ Instruction *Instr2 = &*It++;
+ Instruction *Ret = &*It++;
+
+ // According to ilist's splice() a single-element splice where dst == src
+ // should be a noop.
+ BB->splice(Instr1->getIterator(), BB, Instr1->getIterator());
+
+ It = BB->begin();
+ EXPECT_EQ(&*It++, Instr1);
+ EXPECT_EQ(&*It++, Instr2);
+ EXPECT_EQ(&*It++, Ret);
+ EXPECT_EQ(BB->size(), 3u);
+}
+
+TEST(BasicBlockTest, SpliceLastInstr) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ define void @f(i32 %a) {
+ from:
+ %fromInstr1 = add i32 %a, %a
+ %fromInstr2 = sub i32 %a, %a
+ br label %to
+
+ to:
+ %toInstr1 = mul i32 %a, %a
+ %toInstr2 = sdiv i32 %a, %a
+ ret void
+ }
+)");
+ Function *F = &*M->begin();
+ auto BBIt = F->begin();
+ BasicBlock *FromBB = &*BBIt++;
+ BasicBlock *ToBB = &*BBIt++;
+
+ auto FromBBIt = FromBB->begin();
+ Instruction *FromI1 = &*FromBBIt++;
+ Instruction *FromI2 = &*FromBBIt++;
+ Instruction *FromBr = &*FromBBIt++;
+
+ auto ToBBIt = ToBB->begin();
+ Instruction *ToI1 = &*ToBBIt++;
+ Instruction *ToI2 = &*ToBBIt++;
+ Instruction *ToRet = &*ToBBIt++;
+ ToBB->splice(ToI1->getIterator(), FromBB, FromI2->getIterator(),
+ FromBr->getIterator());
+
+ EXPECT_EQ(FromBB->size(), 2u);
+ auto It = FromBB->begin();
+ EXPECT_EQ(&*It++, FromI1);
+ EXPECT_EQ(&*It++, FromBr);
+
+ EXPECT_EQ(ToBB->size(), 4u);
+ It = ToBB->begin();
+ EXPECT_EQ(&*It++, FromI2);
+ EXPECT_EQ(&*It++, ToI1);
+ EXPECT_EQ(&*It++, ToI2);
+ EXPECT_EQ(&*It++, ToRet);
+}
+
+TEST(BasicBlockTest, SpliceInstrRange) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ define void @f(i32 %a) {
+ from:
+ %fromInstr1 = add i32 %a, %a
+ %fromInstr2 = sub i32 %a, %a
+ br label %to
+
+ to:
+ %toInstr1 = mul i32 %a, %a
+ %toInstr2 = sdiv i32 %a, %a
+ ret void
+ }
+)");
+ Function *F = &*M->begin();
+ auto BBIt = F->begin();
+ BasicBlock *FromBB = &*BBIt++;
+ BasicBlock *ToBB = &*BBIt++;
+
+ auto FromBBIt = FromBB->begin();
+ Instruction *FromI1 = &*FromBBIt++;
+ Instruction *FromI2 = &*FromBBIt++;
+ Instruction *FromBr = &*FromBBIt++;
+
+ auto ToBBIt = ToBB->begin();
+ Instruction *ToI1 = &*ToBBIt++;
+ Instruction *ToI2 = &*ToBBIt++;
+ Instruction *ToRet = &*ToBBIt++;
+ ToBB->splice(ToI2->getIterator(), FromBB, FromBB->begin(), FromBB->end());
+
+ EXPECT_EQ(FromBB->size(), 0u);
+
+ EXPECT_EQ(ToBB->size(), 6u);
+ auto It = ToBB->begin();
+ EXPECT_EQ(&*It++, ToI1);
+ EXPECT_EQ(&*It++, FromI1);
+ EXPECT_EQ(&*It++, FromI2);
+ EXPECT_EQ(&*It++, FromBr);
+ EXPECT_EQ(&*It++, ToI2);
+ EXPECT_EQ(&*It++, ToRet);
+}
+
+#ifdef EXPENSIVE_CHECKS
+TEST(BasicBlockTest, SpliceEndBeforeBegin) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ define void @f(i32 %a) {
+ from:
+ %fromInstr1 = add i32 %a, %a
+ %fromInstr2 = sub i32 %a, %a
+ br label %to
+
+ to:
+ %toInstr1 = mul i32 %a, %a
+ %toInstr2 = sdiv i32 %a, %a
+ ret void
+ }
+)");
+ Function *F = &*M->begin();
+ auto BBIt = F->begin();
+ BasicBlock *FromBB = &*BBIt++;
+ BasicBlock *ToBB = &*BBIt++;
+
+ auto FromBBIt = FromBB->begin();
+ Instruction *FromI1 = &*FromBBIt++;
+ Instruction *FromI2 = &*FromBBIt++;
+
+ auto ToBBIt = ToBB->begin();
+ Instruction *ToI2 = &*ToBBIt++;
+
+ EXPECT_DEATH(ToBB->splice(ToI2->getIterator(), FromBB, FromI2->getIterator(),
+ FromI1->getIterator()),
+ "FromBeginIt not before FromEndIt!");
+}
+#endif //EXPENSIVE_CHECKS
+
} // End anonymous namespace.
} // End llvm namespace.
More information about the llvm-commits
mailing list