diff --git a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h index 979f3b3eb72ff..e677cbf2d8968 100644 --- a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h +++ b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h @@ -21,6 +21,7 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Dominators.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Printable.h" #include namespace llvm { @@ -611,6 +612,10 @@ LLVM_ABI void InvertBranch(BranchInst *PBI, IRBuilderBase &Builder); // br/brcond/unreachable/ret LLVM_ABI bool hasOnlySimpleTerminator(const Function &F); +/// Print BasicBlock \p BB as an operand or print "" if \p BB is a +/// nullptr. +LLVM_ABI Printable printBasicBlock(const BasicBlock *BB); + } // end namespace llvm #endif // LLVM_TRANSFORMS_UTILS_BASICBLOCKUTILS_H diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp index c8255742c41ba..75bf80e11adea 100644 --- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp +++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp @@ -1775,3 +1775,13 @@ bool llvm::hasOnlySimpleTerminator(const Function &F) { } return true; } + +Printable llvm::printBasicBlock(const BasicBlock *BB) { + return Printable([BB](raw_ostream &OS) { + if (!BB) { + OS << ""; + return; + } + BB->printAsOperand(OS); + }); +} diff --git a/llvm/unittests/Transforms/Utils/BasicBlockUtilsTest.cpp b/llvm/unittests/Transforms/Utils/BasicBlockUtilsTest.cpp index 40a8c1d8d3da1..87eece5496526 100644 --- a/llvm/unittests/Transforms/Utils/BasicBlockUtilsTest.cpp +++ b/llvm/unittests/Transforms/Utils/BasicBlockUtilsTest.cpp @@ -716,3 +716,32 @@ attributes #0 = { presplitcoroutine } EXPECT_FALSE(llvm::isPresplitCoroSuspendExitEdge( *ExitN.getSinglePredecessor(), ExitN)); } + +TEST(BasicBlockUtils, BasicBlockPrintable) { + std::string S; + std::string SCheck; + llvm::raw_string_ostream OS{S}; + llvm::raw_string_ostream OSCheck{SCheck}; + + LLVMContext C; + std::unique_ptr M = parseIR(C, R"IR( +define void @foo() { + br label %bb0 +bb0: + br label %.exit +.exit: + ret void +} +)IR"); + + Function *F = M->getFunction("foo"); + for (const BasicBlock &BB : *F) { + OS << printBasicBlock(&BB); + BB.printAsOperand(OSCheck); + EXPECT_EQ(OS.str(), OSCheck.str()); + S.clear(); + SCheck.clear(); + } + OS << printBasicBlock(nullptr); + EXPECT_EQ(OS.str(), ""); +}