43 changes: 43 additions & 0 deletions llvm/test/Transforms/BlockExtractor/extract-blocks.ll
Original file line number Diff line number Diff line change
@@ -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
}

9 changes: 9 additions & 0 deletions llvm/test/Transforms/BlockExtractor/invalid-block.ll
Original file line number Diff line number Diff line change
@@ -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
}

9 changes: 9 additions & 0 deletions llvm/test/Transforms/BlockExtractor/invalid-function.ll
Original file line number Diff line number Diff line change
@@ -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
}

29 changes: 29 additions & 0 deletions llvm/test/tools/llvm-extract/extract-block.ll
Original file line number Diff line number Diff line change
@@ -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
}

28 changes: 28 additions & 0 deletions llvm/test/tools/llvm-extract/extract-invalid-block.ll
Original file line number Diff line number Diff line change
@@ -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
}

29 changes: 29 additions & 0 deletions llvm/test/tools/llvm-extract/extract-multiple-blocks.ll
Original file line number Diff line number Diff line change
@@ -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
}

12 changes: 9 additions & 3 deletions llvm/tools/bugpoint/ExtractFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
40 changes: 40 additions & 0 deletions llvm/tools/llvm-extract/llvm-extract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down Expand Up @@ -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: ");

Expand Down Expand Up @@ -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;
Expand Down