[llvm] 7b68411 - [IR] Adds Function::splice() member functions
Vasileios Porpodas via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 14 10:47:19 PST 2022
Author: Vasileios Porpodas
Date: 2022-12-14T10:45:47-08:00
New Revision: 7b684119abc7d94bad47ec0b97b35598fac412d3
URL: https://github.com/llvm/llvm-project/commit/7b684119abc7d94bad47ec0b97b35598fac412d3
DIFF: https://github.com/llvm/llvm-project/commit/7b684119abc7d94bad47ec0b97b35598fac412d3.diff
LOG: [IR] Adds Function::splice() member functions
This is part of a series of patches that aim at making Function::getBasicBlockList() private.
Differential Revision: https://reviews.llvm.org/D139982
Added:
Modified:
llvm/include/llvm/IR/Function.h
llvm/lib/IR/Function.cpp
llvm/unittests/IR/FunctionTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
index a46462bb5ec45..ce0fb45a65d2d 100644
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -693,6 +693,28 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
return BasicBlocks.insert(Position, BB);
}
+ /// Transfer all blocks from \p FromF to this function at \p ToIt.
+ void splice(Function::iterator ToIt, Function *FromF) {
+ splice(ToIt, FromF, FromF->begin(), FromF->end());
+ }
+
+ /// Transfer one BasicBlock from \p FromF at \p FromIt to this function
+ /// at \p ToIt.
+ void splice(Function::iterator ToIt, Function *FromF,
+ Function::iterator FromIt) {
+ auto FromItNext = std::next(FromIt);
+ // Single-element splice is a noop if destination == source.
+ if (ToIt == FromIt || ToIt == FromItNext)
+ return;
+ splice(ToIt, FromF, FromIt, FromItNext);
+ }
+
+ /// Transfer a range of basic blocks that belong to \p FromF from \p
+ /// FromBeginIt to \p FromEndIt, to this function at \p ToIt.
+ void splice(Function::iterator ToIt, Function *FromF,
+ Function::iterator FromBeginIt,
+ Function::iterator FromEndIt);
+
/// Get the underlying elements of the Function... the basic block list is
/// empty for external functions.
///
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 10bbdcfa0d818..949eb05cd6f0f 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -368,6 +368,18 @@ void Function::eraseFromParent() {
getParent()->getFunctionList().erase(getIterator());
}
+void Function::splice(Function::iterator ToIt, Function *FromF,
+ Function::iterator FromBeginIt,
+ Function::iterator FromEndIt) {
+#ifdef EXPENSIVE_CHECKS
+ // Check that FromBeginIt is before FromEndIt.
+ auto FromFEnd = FromF->end();
+ for (auto It = FromBeginIt; It != FromEndIt; ++It)
+ assert(It != FromBBEnd && "FromBeginIt not before FromEndIt!");
+#endif // EXPENSIVE_CHECKS
+ BasicBlocks.splice(ToIt, FromF->BasicBlocks, FromBeginIt, FromEndIt);
+}
+
//===----------------------------------------------------------------------===//
// Function Implementation
//===----------------------------------------------------------------------===//
diff --git a/llvm/unittests/IR/FunctionTest.cpp b/llvm/unittests/IR/FunctionTest.cpp
index 2336ea3ec1a52..79f46a924065d 100644
--- a/llvm/unittests/IR/FunctionTest.cpp
+++ b/llvm/unittests/IR/FunctionTest.cpp
@@ -239,4 +239,211 @@ define void @bar() {
EXPECT_EQ(It, FooBB0->getIterator());
}
+TEST(FunctionTest, SpliceOneBB) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ define void @from() {
+ from_bb1:
+ br label %from_bb2
+ from_bb2:
+ br label %from_bb3
+ from_bb3:
+ ret void
+ }
+ define void @to() {
+ to_bb1:
+ br label %to_bb2
+ to_bb2:
+ br label %to_bb3
+ to_bb3:
+ ret void
+ }
+)");
+ Function *FromF = M->getFunction("from");
+ BasicBlock *FromBB1 = getBBWithName(FromF, "from_bb1");
+ BasicBlock *FromBB2 = getBBWithName(FromF, "from_bb2");
+ BasicBlock *FromBB3 = getBBWithName(FromF, "from_bb3");
+
+ Function *ToF = M->getFunction("to");
+ BasicBlock *ToBB1 = getBBWithName(ToF, "to_bb1");
+ BasicBlock *ToBB2 = getBBWithName(ToF, "to_bb2");
+ BasicBlock *ToBB3 = getBBWithName(ToF, "to_bb3");
+
+ // Move from_bb2 before to_bb1.
+ ToF->splice(ToBB1->getIterator(), FromF, FromBB2->getIterator());
+ EXPECT_EQ(FromF->size(), 2u);
+ EXPECT_EQ(ToF->size(), 4u);
+
+ auto It = FromF->begin();
+ EXPECT_EQ(&*It++, FromBB1);
+ EXPECT_EQ(&*It++, FromBB3);
+
+ It = ToF->begin();
+ EXPECT_EQ(&*It++, FromBB2);
+ EXPECT_EQ(&*It++, ToBB1);
+ EXPECT_EQ(&*It++, ToBB2);
+ EXPECT_EQ(&*It++, ToBB3);
+
+ // Cleanup to avoid "Uses remain when a value is destroyed!".
+ FromF->splice(FromBB3->getIterator(), ToF, FromBB2->getIterator());
+}
+
+TEST(FunctionTest, SpliceOneBBWhenFromIsSameAsTo) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ define void @fromto() {
+ bb1:
+ br label %bb2
+ bb2:
+ ret void
+ }
+)");
+ Function *F = M->getFunction("fromto");
+ BasicBlock *BB1 = getBBWithName(F, "bb1");
+ BasicBlock *BB2 = getBBWithName(F, "bb2");
+
+ // According to ilist's splice() a single-element splice where dst == src
+ // should be a noop.
+ F->splice(BB1->getIterator(), F, BB1->getIterator());
+
+ auto It = F->begin();
+ EXPECT_EQ(&*It++, BB1);
+ EXPECT_EQ(&*It++, BB2);
+ EXPECT_EQ(F->size(), 2u);
+}
+
+TEST(FunctionTest, SpliceLastBB) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ define void @from() {
+ from_bb1:
+ br label %from_bb2
+ from_bb2:
+ br label %from_bb3
+ from_bb3:
+ ret void
+ }
+ define void @to() {
+ to_bb1:
+ br label %to_bb2
+ to_bb2:
+ br label %to_bb3
+ to_bb3:
+ ret void
+ }
+)");
+
+ Function *FromF = M->getFunction("from");
+ BasicBlock *FromBB1 = getBBWithName(FromF, "from_bb1");
+ BasicBlock *FromBB2 = getBBWithName(FromF, "from_bb2");
+ BasicBlock *FromBB3 = getBBWithName(FromF, "from_bb3");
+
+ Function *ToF = M->getFunction("to");
+ BasicBlock *ToBB1 = getBBWithName(ToF, "to_bb1");
+ BasicBlock *ToBB2 = getBBWithName(ToF, "to_bb2");
+ BasicBlock *ToBB3 = getBBWithName(ToF, "to_bb3");
+
+ // Move from_bb2 before to_bb1.
+ auto ToMove = FromBB2->getIterator();
+ ToF->splice(ToBB1->getIterator(), FromF, ToMove, std::next(ToMove));
+
+ EXPECT_EQ(FromF->size(), 2u);
+ auto It = FromF->begin();
+ EXPECT_EQ(&*It++, FromBB1);
+ EXPECT_EQ(&*It++, FromBB3);
+
+ EXPECT_EQ(ToF->size(), 4u);
+ It = ToF->begin();
+ EXPECT_EQ(&*It++, FromBB2);
+ EXPECT_EQ(&*It++, ToBB1);
+ EXPECT_EQ(&*It++, ToBB2);
+ EXPECT_EQ(&*It++, ToBB3);
+
+ // Cleanup to avoid "Uses remain when a value is destroyed!".
+ FromF->splice(FromBB3->getIterator(), ToF, ToMove);
+}
+
+TEST(FunctionTest, SpliceBBRange) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ define void @from() {
+ from_bb1:
+ br label %from_bb2
+ from_bb2:
+ br label %from_bb3
+ from_bb3:
+ ret void
+ }
+ define void @to() {
+ to_bb1:
+ br label %to_bb2
+ to_bb2:
+ br label %to_bb3
+ to_bb3:
+ ret void
+ }
+)");
+
+ Function *FromF = M->getFunction("from");
+ BasicBlock *FromBB1 = getBBWithName(FromF, "from_bb1");
+ BasicBlock *FromBB2 = getBBWithName(FromF, "from_bb2");
+ BasicBlock *FromBB3 = getBBWithName(FromF, "from_bb3");
+
+ Function *ToF = M->getFunction("to");
+ BasicBlock *ToBB1 = getBBWithName(ToF, "to_bb1");
+ BasicBlock *ToBB2 = getBBWithName(ToF, "to_bb2");
+ BasicBlock *ToBB3 = getBBWithName(ToF, "to_bb3");
+
+ // Move all BBs from @from to @to.
+ ToF->splice(ToBB2->getIterator(), FromF, FromF->begin(), FromF->end());
+
+ EXPECT_EQ(FromF->size(), 0u);
+
+ EXPECT_EQ(ToF->size(), 6u);
+ auto It = ToF->begin();
+ EXPECT_EQ(&*It++, ToBB1);
+ EXPECT_EQ(&*It++, FromBB1);
+ EXPECT_EQ(&*It++, FromBB2);
+ EXPECT_EQ(&*It++, FromBB3);
+ EXPECT_EQ(&*It++, ToBB2);
+ EXPECT_EQ(&*It++, ToBB3);
+}
+
+#ifdef EXPENSIVE_CHECKS
+TEST(FunctionTest, SpliceEndBeforeBegin) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ define void @from() {
+ from_bb1:
+ br label %from_bb2
+ from_bb2:
+ br label %from_bb3
+ from_bb3:
+ ret void
+ }
+ define void @to() {
+ to_bb1:
+ br label %to_bb2
+ to_bb2:
+ br label %to_bb3
+ to_bb3:
+ ret void
+ }
+)");
+
+ Function *FromF = M->getFunction("from");
+ BasicBlock *FromBB1 = getBBWithName(FromF, "from_bb1");
+ BasicBlock *FromBB2 = getBBWithName(FromF, "from_bb2");
+ BasicBlock *FromBB3 = getBBWithName(FromF, "from_bb3");
+
+ Function *ToF = M->getFunction("to");
+ BasicBlock *ToBB1 = getBBWithName(ToF, "to_bb1");
+ BasicBlock *ToBB2 = getBBWithName(ToF, "to_bb2");
+ BasicBlock *ToBB3 = getBBWithName(ToF, "to_bb3");
+
+ EXPECT_DEATH(ToF->splice(ToBB2->getIterator(), FromF, FromBB2->getIterator(),
+ FromBB1->getIterator()),
+ "FromBeginIt not before FromEndIt!");
+}
+#endif //EXPENSIVE_CHECKS
} // end namespace
More information about the llvm-commits
mailing list