summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolkan Keles <vkeles@apple.com>2018-01-23 21:51:34 +0000
committerVolkan Keles <vkeles@apple.com>2018-01-23 21:51:34 +0000
commitdc40be75f8537e036b593f454765940e69ef7025 (patch)
tree0e01c174c0301c8793ac3db35f3de778124e452a
parentbf3c39877ee3c0b593c3de21e67d55fa7d804621 (diff)
downloadbcm5719-llvm-dc40be75f8537e036b593f454765940e69ef7025.tar.gz
bcm5719-llvm-dc40be75f8537e036b593f454765940e69ef7025.zip
[llvm-extract] Support extracting basic blocks
Summary: Currently, there is no way to extract a basic block from a function easily. This patch extends llvm-extract to extract the specified basic block(s). Reviewers: loladiro, rafael, bogner Reviewed By: bogner Subscribers: hintonda, mgorny, qcolombet, llvm-commits Differential Revision: https://reviews.llvm.org/D41638 llvm-svn: 323266
-rw-r--r--llvm/include/llvm/InitializePasses.h2
-rw-r--r--llvm/include/llvm/Transforms/IPO.h7
-rw-r--r--llvm/lib/Transforms/IPO/BlockExtractor.cpp174
-rw-r--r--llvm/lib/Transforms/IPO/CMakeLists.txt1
-rw-r--r--llvm/lib/Transforms/IPO/IPO.cpp2
-rw-r--r--llvm/lib/Transforms/IPO/LoopExtractor.cpp152
-rw-r--r--llvm/test/Transforms/BlockExtractor/extract-blocks.ll43
-rw-r--r--llvm/test/Transforms/BlockExtractor/invalid-block.ll9
-rw-r--r--llvm/test/Transforms/BlockExtractor/invalid-function.ll9
-rw-r--r--llvm/test/tools/llvm-extract/extract-block.ll29
-rw-r--r--llvm/test/tools/llvm-extract/extract-invalid-block.ll28
-rw-r--r--llvm/test/tools/llvm-extract/extract-multiple-blocks.ll29
-rw-r--r--llvm/tools/bugpoint/ExtractFunction.cpp12
-rw-r--r--llvm/tools/llvm-extract/llvm-extract.cpp40
14 files changed, 378 insertions, 159 deletions
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index cfa169e7106..e8f152feff7 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -73,7 +73,7 @@ void initializeAtomicExpandPass(PassRegistry&);
void initializeBDCELegacyPassPass(PassRegistry&);
void initializeBarrierNoopPass(PassRegistry&);
void initializeBasicAAWrapperPassPass(PassRegistry&);
-void initializeBlockExtractorPassPass(PassRegistry&);
+void initializeBlockExtractorPass(PassRegistry &);
void initializeBlockFrequencyInfoWrapperPassPass(PassRegistry&);
void initializeBoundsCheckingLegacyPassPass(PassRegistry&);
void initializeBranchFolderPassPass(PassRegistry&);
diff --git a/llvm/include/llvm/Transforms/IPO.h b/llvm/include/llvm/Transforms/IPO.h
index ce20a726b78..433621bacba 100644
--- a/llvm/include/llvm/Transforms/IPO.h
+++ b/llvm/include/llvm/Transforms/IPO.h
@@ -179,10 +179,13 @@ Pass *createLoopExtractorPass();
///
Pass *createSingleLoopExtractorPass();
-/// createBlockExtractorPass - This pass extracts all blocks (except those
-/// specified in the argument list) from the functions in the module.
+/// createBlockExtractorPass - This pass extracts all the specified blocks
+/// from the functions in the module.
///
ModulePass *createBlockExtractorPass();
+ModulePass *
+createBlockExtractorPass(const SmallVectorImpl<BasicBlock *> &BlocksToExtract,
+ bool EraseFunctions);
/// createStripDeadPrototypesPass - This pass removes any function declarations
/// (prototypes) that are not used.
diff --git a/llvm/lib/Transforms/IPO/BlockExtractor.cpp b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
new file mode 100644
index 00000000000..9b15f185745
--- /dev/null
+++ b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
@@ -0,0 +1,174 @@
+//===- BlockExtractor.cpp - Extracts blocks into their own functions ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass extracts the specified basic blocks from the module into their
+// own functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/CodeExtractor.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "block-extractor"
+
+STATISTIC(NumExtracted, "Number of basic blocks extracted");
+
+static cl::opt<std::string> BlockExtractorFile(
+ "extract-blocks-file", cl::value_desc("filename"),
+ cl::desc("A file containing list of basic blocks to extract"), cl::Hidden);
+
+cl::opt<bool> BlockExtractorEraseFuncs("extract-blocks-erase-funcs",
+ cl::desc("Erase the existing functions"),
+ cl::Hidden);
+
+namespace {
+class BlockExtractor : public ModulePass {
+ SmallVector<BasicBlock *, 16> Blocks;
+ bool EraseFunctions;
+ SmallVector<std::pair<std::string, std::string>, 32> BlocksByName;
+
+public:
+ static char ID;
+ BlockExtractor(const SmallVectorImpl<BasicBlock *> &BlocksToExtract,
+ bool EraseFunctions)
+ : ModulePass(ID), Blocks(BlocksToExtract.begin(), BlocksToExtract.end()),
+ EraseFunctions(EraseFunctions) {
+ if (!BlockExtractorFile.empty())
+ loadFile();
+ }
+ BlockExtractor() : BlockExtractor(SmallVector<BasicBlock *, 0>(), false) {}
+ bool runOnModule(Module &M) override;
+
+private:
+ void loadFile();
+ void splitLandingPadPreds(Function &F);
+};
+} // end anonymous namespace
+
+char BlockExtractor::ID = 0;
+INITIALIZE_PASS(BlockExtractor, "extract-blocks",
+ "Extract basic blocks from module", false, false)
+
+ModulePass *llvm::createBlockExtractorPass() { return new BlockExtractor(); }
+ModulePass *llvm::createBlockExtractorPass(
+ const SmallVectorImpl<BasicBlock *> &BlocksToExtract, bool EraseFunctions) {
+ return new BlockExtractor(BlocksToExtract, EraseFunctions);
+}
+
+/// Gets all of the blocks specified in the input file.
+void BlockExtractor::loadFile() {
+ auto ErrOrBuf = MemoryBuffer::getFile(BlockExtractorFile);
+ if (std::error_code EC = ErrOrBuf.getError())
+ report_fatal_error("BlockExtractor couldn't load the file.");
+ // Read the file.
+ auto &Buf = *ErrOrBuf;
+ SmallVector<StringRef, 16> Lines;
+ Buf->getBuffer().split(Lines, '\n', /*MaxSplit=*/-1,
+ /*KeepEmpty=*/false);
+ for (const auto &Line : Lines) {
+ auto FBPair = Line.split(' ');
+ BlocksByName.push_back({FBPair.first, FBPair.second});
+ }
+}
+
+/// Extracts the landing pads to make sure all of them have only one
+/// predecessor.
+void BlockExtractor::splitLandingPadPreds(Function &F) {
+ for (BasicBlock &BB : F) {
+ for (Instruction &I : BB) {
+ if (!isa<InvokeInst>(&I))
+ continue;
+ InvokeInst *II = cast<InvokeInst>(&I);
+ BasicBlock *Parent = II->getParent();
+ BasicBlock *LPad = II->getUnwindDest();
+
+ // Look through the landing pad's predecessors. If one of them ends in an
+ // 'invoke', then we want to split the landing pad.
+ bool Split = false;
+ for (auto PredBB : predecessors(LPad)) {
+ if (PredBB->isLandingPad() && PredBB != Parent &&
+ isa<InvokeInst>(Parent->getTerminator())) {
+ Split = true;
+ break;
+ }
+ }
+
+ if (!Split)
+ continue;
+
+ SmallVector<BasicBlock *, 2> NewBBs;
+ SplitLandingPadPredecessors(LPad, Parent, ".1", ".2", NewBBs);
+ }
+ }
+}
+
+bool BlockExtractor::runOnModule(Module &M) {
+
+ bool Changed = false;
+
+ // Get all the functions.
+ SmallVector<Function *, 4> Functions;
+ for (Function &F : M) {
+ splitLandingPadPreds(F);
+ Functions.push_back(&F);
+ }
+
+ // Get all the blocks specified in the input file.
+ for (const auto &BInfo : BlocksByName) {
+ Function *F = M.getFunction(BInfo.first);
+ if (!F)
+ report_fatal_error("Invalid function name specified in the input file");
+ auto Res = llvm::find_if(*F, [&](const BasicBlock &BB) {
+ return BB.getName().equals(BInfo.second);
+ });
+ if (Res == F->end())
+ report_fatal_error("Invalid block name specified in the input file");
+ Blocks.push_back(&*Res);
+ }
+
+ // Extract basic blocks.
+ for (BasicBlock *BB : Blocks) {
+ // Check if the module contains BB.
+ if (BB->getParent()->getParent() != &M)
+ report_fatal_error("Invalid basic block");
+ DEBUG(dbgs() << "BlockExtractor: Extracting " << BB->getParent()->getName()
+ << ":" << BB->getName() << "\n");
+ SmallVector<BasicBlock *, 2> BlocksToExtractVec;
+ BlocksToExtractVec.push_back(BB);
+ if (const InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator()))
+ BlocksToExtractVec.push_back(II->getUnwindDest());
+ CodeExtractor(BlocksToExtractVec).extractCodeRegion();
+ ++NumExtracted;
+ Changed = true;
+ }
+
+ // Erase the functions.
+ if (EraseFunctions || BlockExtractorEraseFuncs) {
+ for (Function *F : Functions) {
+ DEBUG(dbgs() << "BlockExtractor: Deleting " << F->getName() << "\n");
+ F->eraseFromParent();
+ }
+ // Set linkage as ExternalLinkage to avoid erasing unreachable functions.
+ for (Function &F : M)
+ F.setLinkage(GlobalValue::ExternalLinkage);
+ Changed = true;
+ }
+
+ return Changed;
+}
diff --git a/llvm/lib/Transforms/IPO/CMakeLists.txt b/llvm/lib/Transforms/IPO/CMakeLists.txt
index 28d38471069..e1a002aff40 100644
--- a/llvm/lib/Transforms/IPO/CMakeLists.txt
+++ b/llvm/lib/Transforms/IPO/CMakeLists.txt
@@ -2,6 +2,7 @@ add_llvm_library(LLVMipo
AlwaysInliner.cpp
ArgumentPromotion.cpp
BarrierNoopPass.cpp
+ BlockExtractor.cpp
CalledValuePropagation.cpp
ConstantMerge.cpp
CrossDSOCFI.cpp
diff --git a/llvm/lib/Transforms/IPO/IPO.cpp b/llvm/lib/Transforms/IPO/IPO.cpp
index d5d35ee89e0..4a31cbcb092 100644
--- a/llvm/lib/Transforms/IPO/IPO.cpp
+++ b/llvm/lib/Transforms/IPO/IPO.cpp
@@ -40,7 +40,7 @@ void llvm::initializeIPO(PassRegistry &Registry) {
initializeInferFunctionAttrsLegacyPassPass(Registry);
initializeInternalizeLegacyPassPass(Registry);
initializeLoopExtractorPass(Registry);
- initializeBlockExtractorPassPass(Registry);
+ initializeBlockExtractorPass(Registry);
initializeSingleLoopExtractorPass(Registry);
initializeLowerTypeTestsPass(Registry);
initializeMergeFunctionsPass(Registry);
diff --git a/llvm/lib/Transforms/IPO/LoopExtractor.cpp b/llvm/lib/Transforms/IPO/LoopExtractor.cpp
index 36b6bdba2cd..6964235df06 100644
--- a/llvm/lib/Transforms/IPO/LoopExtractor.cpp
+++ b/llvm/lib/Transforms/IPO/LoopExtractor.cpp
@@ -158,155 +158,3 @@ bool LoopExtractor::runOnLoop(Loop *L, LPPassManager &LPM) {
Pass *llvm::createSingleLoopExtractorPass() {
return new SingleLoopExtractor();
}
-
-
-// BlockFile - A file which contains a list of blocks that should not be
-// extracted.
-static cl::opt<std::string>
-BlockFile("extract-blocks-file", cl::value_desc("filename"),
- cl::desc("A file containing list of basic blocks to not extract"),
- cl::Hidden);
-
-namespace {
- /// BlockExtractorPass - This pass is used by bugpoint to extract all blocks
- /// from the module into their own functions except for those specified by the
- /// BlocksToNotExtract list.
- class BlockExtractorPass : public ModulePass {
- void LoadFile(const char *Filename);
- void SplitLandingPadPreds(Function *F);
-
- std::vector<BasicBlock*> BlocksToNotExtract;
- std::vector<std::pair<std::string, std::string> > BlocksToNotExtractByName;
- public:
- static char ID; // Pass identification, replacement for typeid
- BlockExtractorPass() : ModulePass(ID) {
- if (!BlockFile.empty())
- LoadFile(BlockFile.c_str());
- }
-
- bool runOnModule(Module &M) override;
- };
-}
-
-char BlockExtractorPass::ID = 0;
-INITIALIZE_PASS(BlockExtractorPass, "extract-blocks",
- "Extract Basic Blocks From Module (for bugpoint use)",
- false, false)
-
-// createBlockExtractorPass - This pass extracts all blocks (except those
-// specified in the argument list) from the functions in the module.
-//
-ModulePass *llvm::createBlockExtractorPass() {
- return new BlockExtractorPass();
-}
-
-void BlockExtractorPass::LoadFile(const char *Filename) {
- // Load the BlockFile...
- std::ifstream In(Filename);
- if (!In.good()) {
- errs() << "WARNING: BlockExtractor couldn't load file '" << Filename
- << "'!\n";
- return;
- }
- while (In) {
- std::string FunctionName, BlockName;
- In >> FunctionName;
- In >> BlockName;
- if (!BlockName.empty())
- BlocksToNotExtractByName.push_back(
- std::make_pair(FunctionName, BlockName));
- }
-}
-
-/// SplitLandingPadPreds - The landing pad needs to be extracted with the invoke
-/// instruction. The critical edge breaker will refuse to break critical edges
-/// to a landing pad. So do them here. After this method runs, all landing pads
-/// should have only one predecessor.
-void BlockExtractorPass::SplitLandingPadPreds(Function *F) {
- for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
- InvokeInst *II = dyn_cast<InvokeInst>(I);
- if (!II) continue;
- BasicBlock *Parent = II->getParent();
- BasicBlock *LPad = II->getUnwindDest();
-
- // Look through the landing pad's predecessors. If one of them ends in an
- // 'invoke', then we want to split the landing pad.
- bool Split = false;
- for (pred_iterator
- PI = pred_begin(LPad), PE = pred_end(LPad); PI != PE; ++PI) {
- BasicBlock *BB = *PI;
- if (BB->isLandingPad() && BB != Parent &&
- isa<InvokeInst>(Parent->getTerminator())) {
- Split = true;
- break;
- }
- }
-
- if (!Split) continue;
-
- SmallVector<BasicBlock*, 2> NewBBs;
- SplitLandingPadPredecessors(LPad, Parent, ".1", ".2", NewBBs);
- }
-}
-
-bool BlockExtractorPass::runOnModule(Module &M) {
- if (skipModule(M))
- return false;
-
- std::set<BasicBlock*> TranslatedBlocksToNotExtract;
- for (unsigned i = 0, e = BlocksToNotExtract.size(); i != e; ++i) {
- BasicBlock *BB = BlocksToNotExtract[i];
- Function *F = BB->getParent();
-
- // Map the corresponding function in this module.
- Function *MF = M.getFunction(F->getName());
- assert(MF->getFunctionType() == F->getFunctionType() && "Wrong function?");
-
- // Figure out which index the basic block is in its function.
- Function::iterator BBI = MF->begin();
- std::advance(BBI, std::distance(F->begin(), Function::iterator(BB)));
- TranslatedBlocksToNotExtract.insert(&*BBI);
- }
-
- while (!BlocksToNotExtractByName.empty()) {
- // There's no way to find BBs by name without looking at every BB inside
- // every Function. Fortunately, this is always empty except when used by
- // bugpoint in which case correctness is more important than performance.
-
- std::string &FuncName = BlocksToNotExtractByName.back().first;
- std::string &BlockName = BlocksToNotExtractByName.back().second;
-
- for (Function &F : M) {
- if (F.getName() != FuncName) continue;
-
- for (BasicBlock &BB : F) {
- if (BB.getName() != BlockName) continue;
-
- TranslatedBlocksToNotExtract.insert(&BB);
- }
- }
-
- BlocksToNotExtractByName.pop_back();
- }
-
- // Now that we know which blocks to not extract, figure out which ones we WANT
- // to extract.
- std::vector<BasicBlock*> BlocksToExtract;
- for (Function &F : M) {
- SplitLandingPadPreds(&F);
- for (BasicBlock &BB : F)
- if (!TranslatedBlocksToNotExtract.count(&BB))
- BlocksToExtract.push_back(&BB);
- }
-
- for (BasicBlock *BlockToExtract : BlocksToExtract) {
- SmallVector<BasicBlock*, 2> BlocksToExtractVec;
- BlocksToExtractVec.push_back(BlockToExtract);
- if (const InvokeInst *II =
- dyn_cast<InvokeInst>(BlockToExtract->getTerminator()))
- BlocksToExtractVec.push_back(II->getUnwindDest());
- CodeExtractor(BlocksToExtractVec).extractCodeRegion();
- }
-
- return !BlocksToExtract.empty();
-}
diff --git a/llvm/test/Transforms/BlockExtractor/extract-blocks.ll b/llvm/test/Transforms/BlockExtractor/extract-blocks.ll
new file mode 100644
index 00000000000..daf9a0923ce
--- /dev/null
+++ b/llvm/test/Transforms/BlockExtractor/extract-blocks.ll
@@ -0,0 +1,43 @@
+; RUN: echo 'foo bb9' > %t
+; RUN: echo 'foo bb20' >> %t
+; RUN: opt -S -extract-blocks -extract-blocks-file=%t %s | FileCheck %s --check-prefix=CHECK-NO-ERASE
+; RUN: opt -S -extract-blocks -extract-blocks-file=%t -extract-blocks-erase-funcs %s | FileCheck %s --check-prefix=CHECK-ERASE
+
+; CHECK-NO-ERASE: @foo(
+; CHECK-NO-ERASE: @foo_bb9(
+; CHECK-NO-ERASE: @foo_bb20(
+; CHECK-ERASE-NOT: @foo(
+; CHECK-ERASE: @foo_bb9(
+; CHECK-ERASE: @foo_bb20(
+define i32 @foo(i32 %arg, i32 %arg1) {
+bb:
+ %tmp5 = icmp sgt i32 %arg, 0
+ %tmp8 = icmp sgt i32 %arg1, 0
+ %or.cond = and i1 %tmp5, %tmp8
+ br i1 %or.cond, label %bb9, label %bb14
+
+bb9: ; preds = %bb
+ %tmp12 = shl i32 %arg1, 2
+ %tmp13 = add nsw i32 %tmp12, %arg
+ br label %bb30
+
+bb14: ; preds = %bb
+ %0 = and i32 %arg1, %arg
+ %1 = icmp slt i32 %0, 0
+ br i1 %1, label %bb20, label %bb26
+
+bb20: ; preds = %bb14
+ %tmp22 = mul nsw i32 %arg, 3
+ %tmp24 = sdiv i32 %arg1, 6
+ %tmp25 = add nsw i32 %tmp24, %tmp22
+ br label %bb30
+
+bb26: ; preds = %bb14
+ %tmp29 = sub nsw i32 %arg, %arg1
+ br label %bb30
+
+bb30: ; preds = %bb26, %bb20, %bb9
+ %tmp.0 = phi i32 [ %tmp13, %bb9 ], [ %tmp25, %bb20 ], [ %tmp29, %bb26 ]
+ ret i32 %tmp.0
+}
+
diff --git a/llvm/test/Transforms/BlockExtractor/invalid-block.ll b/llvm/test/Transforms/BlockExtractor/invalid-block.ll
new file mode 100644
index 00000000000..f444764e991
--- /dev/null
+++ b/llvm/test/Transforms/BlockExtractor/invalid-block.ll
@@ -0,0 +1,9 @@
+; RUN: echo 'bar invalidbb' > %t
+; RUN: not opt -S -extract-blocks -extract-blocks-file=%t %s 2>&1 | FileCheck %s
+
+; CHECK: Invalid block
+define void @bar() {
+bb:
+ ret void
+}
+
diff --git a/llvm/test/Transforms/BlockExtractor/invalid-function.ll b/llvm/test/Transforms/BlockExtractor/invalid-function.ll
new file mode 100644
index 00000000000..4044815893e
--- /dev/null
+++ b/llvm/test/Transforms/BlockExtractor/invalid-function.ll
@@ -0,0 +1,9 @@
+; RUN: echo 'foo bb' > %t
+; RUN: not opt -S -extract-blocks -extract-blocks-file=%t %s 2>&1 | FileCheck %s
+
+; CHECK: Invalid function
+define void @bar() {
+bb:
+ ret void
+}
+
diff --git a/llvm/test/tools/llvm-extract/extract-block.ll b/llvm/test/tools/llvm-extract/extract-block.ll
new file mode 100644
index 00000000000..761ed3268aa
--- /dev/null
+++ b/llvm/test/tools/llvm-extract/extract-block.ll
@@ -0,0 +1,29 @@
+; RUN: llvm-extract -S -bb foo:bb4 %s | FileCheck %s
+
+; CHECK: @foo_bb4
+; CHECK: %tmp5
+define i32 @foo(i32 %arg) {
+bb:
+ %tmp = alloca i32, align 4
+ %tmp1 = alloca i32, align 4
+ store i32 %arg, i32* %tmp1, align 4
+ %tmp2 = load i32, i32* %tmp1, align 4
+ %tmp3 = icmp sgt i32 %tmp2, 0
+ br i1 %tmp3, label %bb4, label %bb7
+
+bb4: ; preds = %bb
+ %tmp5 = load i32, i32* %tmp1, align 4
+ %tmp6 = add nsw i32 %tmp5, 1
+ store i32 %tmp6, i32* %tmp1, align 4
+ store i32 %tmp6, i32* %tmp, align 4
+ br label %bb8
+
+bb7: ; preds = %bb
+ store i32 0, i32* %tmp, align 4
+ br label %bb8
+
+bb8: ; preds = %bb7, %bb4
+ %tmp9 = load i32, i32* %tmp, align 4
+ ret i32 %tmp9
+}
+
diff --git a/llvm/test/tools/llvm-extract/extract-invalid-block.ll b/llvm/test/tools/llvm-extract/extract-invalid-block.ll
new file mode 100644
index 00000000000..04b40ca2b84
--- /dev/null
+++ b/llvm/test/tools/llvm-extract/extract-invalid-block.ll
@@ -0,0 +1,28 @@
+; RUN: not llvm-extract -S -bb foo:invalidbb %s 2>&1 | FileCheck %s
+
+; CHECK: function foo doesn't contain a basic block named 'invalidbb'!
+define i32 @foo(i32 %arg) {
+bb:
+ %tmp = alloca i32, align 4
+ %tmp1 = alloca i32, align 4
+ store i32 %arg, i32* %tmp1, align 4
+ %tmp2 = load i32, i32* %tmp1, align 4
+ %tmp3 = icmp sgt i32 %tmp2, 0
+ br i1 %tmp3, label %bb4, label %bb7
+
+bb4: ; preds = %bb
+ %tmp5 = load i32, i32* %tmp1, align 4
+ %tmp6 = add nsw i32 %tmp5, 1
+ store i32 %tmp6, i32* %tmp1, align 4
+ store i32 %tmp6, i32* %tmp, align 4
+ br label %bb8
+
+bb7: ; preds = %bb
+ store i32 0, i32* %tmp, align 4
+ br label %bb8
+
+bb8: ; preds = %bb7, %bb4
+ %tmp9 = load i32, i32* %tmp, align 4
+ ret i32 %tmp9
+}
+
diff --git a/llvm/test/tools/llvm-extract/extract-multiple-blocks.ll b/llvm/test/tools/llvm-extract/extract-multiple-blocks.ll
new file mode 100644
index 00000000000..a7f270bdcd6
--- /dev/null
+++ b/llvm/test/tools/llvm-extract/extract-multiple-blocks.ll
@@ -0,0 +1,29 @@
+; RUN: llvm-extract -S -bb foo:bb4 -bb foo:bb7 %s | FileCheck %s
+
+; CHECK: @foo_bb4
+; CHECK: @foo_bb7
+define i32 @foo(i32 %arg) {
+bb:
+ %tmp = alloca i32, align 4
+ %tmp1 = alloca i32, align 4
+ store i32 %arg, i32* %tmp1, align 4
+ %tmp2 = load i32, i32* %tmp1, align 4
+ %tmp3 = icmp sgt i32 %tmp2, 0
+ br i1 %tmp3, label %bb4, label %bb7
+
+bb4: ; preds = %bb
+ %tmp5 = load i32, i32* %tmp1, align 4
+ %tmp6 = add nsw i32 %tmp5, 1
+ store i32 %tmp6, i32* %tmp1, align 4
+ store i32 %tmp6, i32* %tmp, align 4
+ br label %bb8
+
+bb7: ; preds = %bb
+ store i32 0, i32* %tmp, align 4
+ br label %bb8
+
+bb8: ; preds = %bb7, %bb4
+ %tmp9 = load i32, i32* %tmp, align 4
+ ret i32 %tmp9
+}
+
diff --git a/llvm/tools/bugpoint/ExtractFunction.cpp b/llvm/tools/bugpoint/ExtractFunction.cpp
index 431dcedfe20..d5a2a0b211b 100644
--- a/llvm/tools/bugpoint/ExtractFunction.cpp
+++ b/llvm/tools/bugpoint/ExtractFunction.cpp
@@ -383,10 +383,16 @@ BugDriver::extractMappedBlocksFromModule(const std::vector<BasicBlock *> &BBs,
}
DiscardTemp Discard{*Temp};
+ // Extract all of the blocks except the ones in BBs.
+ SmallVector<BasicBlock *, 32> BlocksToExtract;
+ for (Function &F : *M)
+ for (BasicBlock &BB : F)
+ // Check if this block is going to be extracted.
+ if (std::find(BBs.begin(), BBs.end(), &BB) == BBs.end())
+ BlocksToExtract.push_back(&BB);
+
raw_fd_ostream OS(Temp->FD, /*shouldClose*/ false);
- for (std::vector<BasicBlock *>::const_iterator I = BBs.begin(), E = BBs.end();
- I != E; ++I) {
- BasicBlock *BB = *I;
+ for (BasicBlock *BB : BBs) {
// If the BB doesn't have a name, give it one so we have something to key
// off of.
if (!BB->hasName())
diff --git a/llvm/tools/llvm-extract/llvm-extract.cpp b/llvm/tools/llvm-extract/llvm-extract.cpp
index c39ffa58fbf..7cd270a76ba 100644
--- a/llvm/tools/llvm-extract/llvm-extract.cpp
+++ b/llvm/tools/llvm-extract/llvm-extract.cpp
@@ -67,6 +67,12 @@ ExtractRegExpFuncs("rfunc", cl::desc("Specify function(s) to extract using a "
"regular expression"),
cl::ZeroOrMore, cl::value_desc("rfunction"));
+// ExtractBlocks - The blocks to extract from the module.
+static cl::list<std::string>
+ ExtractBlocks("bb",
+ cl::desc("Specify <function, basic block> pairs to extract"),
+ cl::ZeroOrMore, cl::value_desc("function:bb"));
+
// ExtractAlias - The alias to extract from the module.
static cl::list<std::string>
ExtractAliases("alias", cl::desc("Specify alias to extract"),
@@ -228,6 +234,32 @@ int main(int argc, char **argv) {
}
}
+ // Figure out which BasicBlocks we should extract.
+ SmallVector<BasicBlock *, 4> BBs;
+ for (StringRef StrPair : ExtractBlocks) {
+ auto BBInfo = StrPair.split(':');
+ // Get the function.
+ Function *F = M->getFunction(BBInfo.first);
+ if (!F) {
+ errs() << argv[0] << ": program doesn't contain a function named '"
+ << BBInfo.first << "'!\n";
+ return 1;
+ }
+ // Do not materialize this function.
+ GVs.insert(F);
+ // Get the basic block.
+ auto Res = llvm::find_if(*F, [&](const BasicBlock &BB) {
+ return BB.getName().equals(BBInfo.second);
+ });
+ if (Res == F->end()) {
+ errs() << argv[0] << ": function " << F->getName()
+ << " doesn't contain a basic block named '" << BBInfo.second
+ << "'!\n";
+ return 1;
+ }
+ BBs.push_back(&*Res);
+ }
+
// Use *argv instead of argv[0] to work around a wrong GCC warning.
ExitOnError ExitOnErr(std::string(*argv) + ": error reading input: ");
@@ -286,6 +318,14 @@ int main(int argc, char **argv) {
ExitOnErr(M->materializeAll());
}
+ // Extract the specified basic blocks from the module and erase the existing
+ // functions.
+ if (!ExtractBlocks.empty()) {
+ legacy::PassManager PM;
+ PM.add(createBlockExtractorPass(BBs, true));
+ PM.run(*M);
+ }
+
// In addition to deleting all other functions, we also want to spiff it
// up a little bit. Do this now.
legacy::PassManager Passes;
OpenPOWER on IntegriCloud