//
// The LLVM Compiler Infrastructure
//
-// This file was developed by the LLVM research group and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
-#include "llvm/Constants.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Module.h"
-#include "llvm/PassManager.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
#include "llvm/Pass.h"
-#include "llvm/SymbolTable.h"
-#include "llvm/Analysis/Verifier.h"
-#include "llvm/Transforms/IPO.h"
-#include "llvm/Transforms/Scalar.h"
-#include "llvm/Transforms/Utils/Cloning.h"
-#include "llvm/Transforms/Utils/FunctionUtils.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm/Transforms/Utils/CodeExtractor.h"
#include <set>
-#include <iostream>
using namespace llvm;
+#define DEBUG_TYPE "bugpoint"
+
namespace llvm {
bool DisableSimplifyCFG = false;
+ extern cl::opt<std::string> OutputPrefix;
} // End llvm namespace
namespace {
cl::opt<bool, true>
NoSCFG("disable-simplifycfg", cl::location(DisableSimplifyCFG),
cl::desc("Do not use the -simplifycfg pass to reduce testcases"));
-}
+
+ Function* globalInitUsesExternalBA(GlobalVariable* GV) {
+ if (!GV->hasInitializer())
+ return nullptr;
+
+ Constant *I = GV->getInitializer();
+
+ // walk the values used by the initializer
+ // (and recurse into things like ConstantExpr)
+ std::vector<Constant*> Todo;
+ std::set<Constant*> Done;
+ Todo.push_back(I);
+
+ while (!Todo.empty()) {
+ Constant* V = Todo.back();
+ Todo.pop_back();
+ Done.insert(V);
+
+ if (BlockAddress *BA = dyn_cast<BlockAddress>(V)) {
+ Function *F = BA->getFunction();
+ if (F->isDeclaration())
+ return F;
+ }
+
+ for (User::op_iterator i = V->op_begin(), e = V->op_end(); i != e; ++i) {
+ Constant *C = dyn_cast<Constant>(*i);
+ if (C && !isa<GlobalValue>(C) && !Done.count(C))
+ Todo.push_back(C);
+ }
+ }
+ return nullptr;
+ }
+} // end anonymous namespace
/// deleteInstructionFromProgram - This method clones the current Program and
/// deletes the specified instruction from the cloned module. It then runs a
/// depends on the value. The modified module is then returned.
///
Module *BugDriver::deleteInstructionFromProgram(const Instruction *I,
- unsigned Simplification) const {
- Module *Result = CloneModule(Program);
+ unsigned Simplification) {
+ // FIXME, use vmap?
+ Module *Clone = CloneModule(Program);
const BasicBlock *PBB = I->getParent();
const Function *PF = PBB->getParent();
- Module::iterator RFI = Result->begin(); // Get iterator to corresponding fn
+ Module::iterator RFI = Clone->begin(); // Get iterator to corresponding fn
std::advance(RFI, std::distance(PF->getParent()->begin(),
Module::const_iterator(PF)));
Instruction *TheInst = RI; // Got the corresponding instruction!
// If this instruction produces a value, replace any users with null values
- if (TheInst->getType() != Type::VoidTy)
+ if (!TheInst->getType()->isVoidTy())
TheInst->replaceAllUsesWith(Constant::getNullValue(TheInst->getType()));
// Remove the instruction from the program.
TheInst->getParent()->getInstList().erase(TheInst);
-
- //writeProgramToFile("current.bc", Result);
-
// Spiff up the output a little bit.
- PassManager Passes;
- // Make sure that the appropriate target data is always used...
- Passes.add(new TargetData(Result));
+ std::vector<std::string> Passes;
- /// FIXME: If this used runPasses() like the methods below, we could get rid
- /// of the -disable-* options!
+ /// Can we get rid of the -disable-* options?
if (Simplification > 1 && !NoDCE)
- Passes.add(createDeadCodeEliminationPass());
+ Passes.push_back("dce");
if (Simplification && !DisableSimplifyCFG)
- Passes.add(createCFGSimplificationPass()); // Delete dead control flow
-
- Passes.add(createVerifierPass());
- Passes.run(*Result);
- return Result;
-}
-
-static const PassInfo *getPI(Pass *P) {
- const PassInfo *PI = P->getPassInfo();
- delete P;
- return PI;
+ Passes.push_back("simplifycfg"); // Delete dead control flow
+
+ Passes.push_back("verify");
+ Module *New = runPassesOn(Clone, Passes);
+ delete Clone;
+ if (!New) {
+ errs() << "Instruction removal failed. Sorry. :( Please report a bug!\n";
+ exit(1);
+ }
+ return New;
}
/// performFinalCleanups - This method clones the current Program and performs
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
I->setLinkage(GlobalValue::ExternalLinkage);
- std::vector<const PassInfo*> CleanupPasses;
- CleanupPasses.push_back(getPI(createFunctionResolvingPass()));
- CleanupPasses.push_back(getPI(createGlobalDCEPass()));
- CleanupPasses.push_back(getPI(createDeadTypeEliminationPass()));
+ std::vector<std::string> CleanupPasses;
+ CleanupPasses.push_back("globaldce");
if (MayModifySemantics)
- CleanupPasses.push_back(getPI(createDeadArgHackingPass()));
+ CleanupPasses.push_back("deadarghaX0r");
else
- CleanupPasses.push_back(getPI(createDeadArgEliminationPass()));
+ CleanupPasses.push_back("deadargelim");
Module *New = runPassesOn(M, CleanupPasses);
- if (New == 0) {
- std::cerr << "Final cleanups failed. Sorry. :( Please report a bug!\n";
+ if (!New) {
+ errs() << "Final cleanups failed. Sorry. :( Please report a bug!\n";
return M;
}
delete M;
/// function. This returns null if there are no extractable loops in the
/// program or if the loop extractor crashes.
Module *BugDriver::ExtractLoop(Module *M) {
- std::vector<const PassInfo*> LoopExtractPasses;
- LoopExtractPasses.push_back(getPI(createSingleLoopExtractorPass()));
+ std::vector<std::string> LoopExtractPasses;
+ LoopExtractPasses.push_back("loop-extract-single");
Module *NewM = runPassesOn(M, LoopExtractPasses);
- if (NewM == 0) {
- Module *Old = swapProgramIn(M);
- std::cout << "*** Loop extraction failed: ";
- EmitProgressBytecode("loopextraction", true);
- std::cout << "*** Sorry. :( Please report a bug!\n";
- swapProgramIn(Old);
- return 0;
+ if (!NewM) {
+ outs() << "*** Loop extraction failed: ";
+ EmitProgressBitcode(M, "loopextraction", true);
+ outs() << "*** Sorry. :( Please report a bug!\n";
+ return nullptr;
}
// Check to see if we created any new functions. If not, no loops were
static unsigned NumExtracted = 32;
if (M->size() == NewM->size() || --NumExtracted == 0) {
delete NewM;
- return 0;
+ return nullptr;
} else {
assert(M->size() < NewM->size() && "Loop extract removed functions?");
Module::iterator MI = NewM->begin();
void llvm::DeleteFunctionBody(Function *F) {
// delete the body of the function...
F->deleteBody();
- assert(F->isExternal() && "This didn't make the function external!");
+ assert(F->isDeclaration() && "This didn't make the function external!");
}
/// GetTorInit - Given a list of entries for static ctors/dtors, return them
static Constant *GetTorInit(std::vector<std::pair<Function*, int> > &TorList) {
assert(!TorList.empty() && "Don't create empty tor list!");
std::vector<Constant*> ArrayElts;
+ Type *Int32Ty = Type::getInt32Ty(TorList[0].first->getContext());
+
+ StructType *STy =
+ StructType::get(Int32Ty, TorList[0].first->getType(), NULL);
for (unsigned i = 0, e = TorList.size(); i != e; ++i) {
- std::vector<Constant*> Elts;
- Elts.push_back(ConstantSInt::get(Type::IntTy, TorList[i].second));
- Elts.push_back(TorList[i].first);
- ArrayElts.push_back(ConstantStruct::get(Elts));
+ Constant *Elts[] = {
+ ConstantInt::get(Int32Ty, TorList[i].second),
+ TorList[i].first
+ };
+ ArrayElts.push_back(ConstantStruct::get(STy, Elts));
}
return ConstantArray::get(ArrayType::get(ArrayElts[0]->getType(),
ArrayElts.size()),
/// M1 has all of the global variables. If M2 contains any functions that are
/// static ctors/dtors, we need to add an llvm.global_[cd]tors global to M2, and
/// prune appropriate entries out of M1s list.
-static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2){
+static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2,
+ ValueToValueMapTy &VMap) {
GlobalVariable *GV = M1->getNamedGlobal(GlobalName);
- if (!GV || GV->isExternal() || GV->hasInternalLinkage() ||
+ if (!GV || GV->isDeclaration() || GV->hasLocalLinkage() ||
!GV->use_empty()) return;
std::vector<std::pair<Function*, int> > M1Tors, M2Tors;
if (CS->getOperand(1)->isNullValue())
break; // Found a null terminator, stop here.
- ConstantSInt *CI = dyn_cast<ConstantSInt>(CS->getOperand(0));
- int Priority = CI ? CI->getValue() : 0;
+ ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
+ int Priority = CI ? CI->getSExtValue() : 0;
Constant *FP = CS->getOperand(1);
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
- if (CE->getOpcode() == Instruction::Cast)
+ if (CE->isCast())
FP = CE->getOperand(0);
if (Function *F = dyn_cast<Function>(FP)) {
- if (!F->isExternal())
+ if (!F->isDeclaration())
M1Tors.push_back(std::make_pair(F, Priority));
else {
// Map to M2's version of the function.
- F = M2->getFunction(F->getName(), F->getFunctionType());
+ F = cast<Function>(VMap[F]);
M2Tors.push_back(std::make_pair(F, Priority));
}
}
GV->eraseFromParent();
if (!M1Tors.empty()) {
Constant *M1Init = GetTorInit(M1Tors);
- new GlobalVariable(M1Init->getType(), false, GlobalValue::AppendingLinkage,
- M1Init, GlobalName, M1);
+ new GlobalVariable(*M1, M1Init->getType(), false,
+ GlobalValue::AppendingLinkage,
+ M1Init, GlobalName);
}
GV = M2->getNamedGlobal(GlobalName);
GV->eraseFromParent();
if (!M2Tors.empty()) {
Constant *M2Init = GetTorInit(M2Tors);
- new GlobalVariable(M2Init->getType(), false, GlobalValue::AppendingLinkage,
- M2Init, GlobalName, M2);
- }
-}
-
-/// RewriteUsesInNewModule - Given a constant 'OrigVal' and a module 'OrigMod',
-/// find all uses of the constant. If they are not in the specified module,
-/// replace them with uses of another constant 'NewVal'.
-static void RewriteUsesInNewModule(Constant *OrigVal, Constant *NewVal,
- Module *OrigMod) {
- assert(OrigVal->getType() == NewVal->getType() &&
- "Can't replace something with a different type");
- for (Value::use_iterator UI = OrigVal->use_begin(), E = OrigVal->use_end();
- UI != E; ) {
- Value::use_iterator TmpUI = UI++;
- User *U = *TmpUI;
- if (Instruction *Inst = dyn_cast<Instruction>(U)) {
- if (Inst->getParent()->getParent()->getParent() != OrigMod)
- TmpUI.getUse() = NewVal;
- } else if (GlobalVariable *GV = dyn_cast<GlobalVariable>(U)) {
- if (GV->getParent() != OrigMod)
- TmpUI.getUse() = NewVal;
- } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) {
- // If nothing uses this, don't bother making a copy.
- if (CE->use_empty()) continue;
- Constant *NewCE = CE->getWithOperandReplaced(TmpUI.getOperandNo(),
- NewVal);
- RewriteUsesInNewModule(CE, NewCE, OrigMod);
- } else if (ConstantStruct *CS = dyn_cast<ConstantStruct>(U)) {
- // If nothing uses this, don't bother making a copy.
- if (CS->use_empty()) continue;
- unsigned OpNo = TmpUI.getOperandNo();
- std::vector<Constant*> Ops;
- for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i)
- Ops.push_back(i == OpNo ? NewVal : CS->getOperand(i));
- Constant *NewStruct = ConstantStruct::get(Ops);
- RewriteUsesInNewModule(CS, NewStruct, OrigMod);
- } else if (ConstantPacked *CP = dyn_cast<ConstantPacked>(U)) {
- // If nothing uses this, don't bother making a copy.
- if (CP->use_empty()) continue;
- unsigned OpNo = TmpUI.getOperandNo();
- std::vector<Constant*> Ops;
- for (unsigned i = 0, e = CP->getNumOperands(); i != e; ++i)
- Ops.push_back(i == OpNo ? NewVal : CP->getOperand(i));
- Constant *NewPacked = ConstantPacked::get(Ops);
- RewriteUsesInNewModule(CP, NewPacked, OrigMod);
- } else if (ConstantArray *CA = dyn_cast<ConstantArray>(U)) {
- // If nothing uses this, don't bother making a copy.
- if (CA->use_empty()) continue;
- unsigned OpNo = TmpUI.getOperandNo();
- std::vector<Constant*> Ops;
- for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
- Ops.push_back(i == OpNo ? NewVal : CA->getOperand(i));
- }
- Constant *NewArray = ConstantArray::get(CA->getType(), Ops);
- RewriteUsesInNewModule(CA, NewArray, OrigMod);
- } else {
- assert(0 && "Unexpected user");
- }
+ new GlobalVariable(*M2, M2Init->getType(), false,
+ GlobalValue::AppendingLinkage,
+ M2Init, GlobalName);
}
}
/// SplitFunctionsOutOfModule - Given a module and a list of functions in the
/// module, split the functions OUT of the specified module, and place them in
/// the new module.
-Module *llvm::SplitFunctionsOutOfModule(Module *M,
- const std::vector<Function*> &F) {
+Module *
+llvm::SplitFunctionsOutOfModule(Module *M,
+ const std::vector<Function*> &F,
+ ValueToValueMapTy &VMap) {
// Make sure functions & globals are all external so that linkage
// between the two modules will work.
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
I->setLinkage(GlobalValue::ExternalLinkage);
for (Module::global_iterator I = M->global_begin(), E = M->global_end();
- I != E; ++I)
+ I != E; ++I) {
+ if (I->hasName() && I->getName()[0] == '\01')
+ I->setName(I->getName().substr(1));
I->setLinkage(GlobalValue::ExternalLinkage);
+ }
- // First off, we need to create the new module...
- Module *New = new Module(M->getModuleIdentifier());
- New->setEndianness(M->getEndianness());
- New->setPointerSize(M->getPointerSize());
- New->setTargetTriple(M->getTargetTriple());
- New->setModuleInlineAsm(M->getModuleInlineAsm());
-
- // Copy all of the dependent libraries over.
- for (Module::lib_iterator I = M->lib_begin(), E = M->lib_end(); I != E; ++I)
- New->addLibrary(*I);
+ ValueToValueMapTy NewVMap;
+ Module *New = CloneModule(M, NewVMap);
- // build a set of the functions to search later...
- std::set<std::pair<std::string, const PointerType*> > TestFunctions;
+ // Remove the Test functions from the Safe module
+ std::set<Function *> TestFunctions;
for (unsigned i = 0, e = F.size(); i != e; ++i) {
- TestFunctions.insert(std::make_pair(F[i]->getName(), F[i]->getType()));
+ Function *TNOF = cast<Function>(VMap[F[i]]);
+ DEBUG(errs() << "Removing function ");
+ DEBUG(TNOF->printAsOperand(errs(), false));
+ DEBUG(errs() << "\n");
+ TestFunctions.insert(cast<Function>(NewVMap[TNOF]));
+ DeleteFunctionBody(TNOF); // Function is now external in this module!
}
- std::map<GlobalValue*, GlobalValue*> GlobalToPrototypeMap;
- std::vector<GlobalValue*> OrigGlobals;
-
- // Adding specified functions to new module...
- for (Module::iterator I = M->begin(), E = M->end(); I != E;) {
- OrigGlobals.push_back(I);
- if (TestFunctions.count(std::make_pair(I->getName(), I->getType()))) {
- Module::iterator tempI = I;
- I++;
- Function *Func = new Function(tempI->getFunctionType(),
- GlobalValue::ExternalLinkage);
- M->getFunctionList().insert(tempI, Func);
- New->getFunctionList().splice(New->end(),
- M->getFunctionList(),
- tempI);
- Func->setName(tempI->getName());
- Func->setCallingConv(tempI->getCallingConv());
- GlobalToPrototypeMap[tempI] = Func;
- } else {
- Function *Func = new Function(I->getFunctionType(),
- GlobalValue::ExternalLinkage,
- I->getName(),
- New);
- Func->setCallingConv(I->getCallingConv());
- GlobalToPrototypeMap[I] = Func;
- I++;
- }
- }
+
+ // Remove the Safe functions from the Test module
+ for (Module::iterator I = New->begin(), E = New->end(); I != E; ++I)
+ if (!TestFunctions.count(I))
+ DeleteFunctionBody(I);
+
- // Copy over global variable list.
+ // Try to split the global initializers evenly
for (Module::global_iterator I = M->global_begin(), E = M->global_end();
I != E; ++I) {
- OrigGlobals.push_back(I);
- GlobalVariable *G = new GlobalVariable(I->getType()->getElementType(),
- I->isConstant(),
- GlobalValue::ExternalLinkage,
- 0, I->getName(), New);
- GlobalToPrototypeMap[I] = G;
- }
-
- // Copy all of the type symbol table entries over.
- const SymbolTable &SymTab = M->getSymbolTable();
- SymbolTable::type_const_iterator TypeI = SymTab.type_begin();
- SymbolTable::type_const_iterator TypeE = SymTab.type_end();
- for (; TypeI != TypeE; ++TypeI)
- New->addTypeName(TypeI->first, TypeI->second);
-
- // Loop over globals, rewriting uses in the module the prototype is in to use
- // the prototype.
- for (unsigned i = 0, e = OrigGlobals.size(); i != e; ++i) {
- assert(OrigGlobals[i]->getName() ==
- GlobalToPrototypeMap[OrigGlobals[i]]->getName() &&
- "Something got renamed?");
- RewriteUsesInNewModule(OrigGlobals[i], GlobalToPrototypeMap[OrigGlobals[i]],
- OrigGlobals[i]->getParent());
+ GlobalVariable *GV = cast<GlobalVariable>(NewVMap[I]);
+ if (Function *TestFn = globalInitUsesExternalBA(I)) {
+ if (Function *SafeFn = globalInitUsesExternalBA(GV)) {
+ errs() << "*** Error: when reducing functions, encountered "
+ "the global '";
+ GV->printAsOperand(errs(), false);
+ errs() << "' with an initializer that references blockaddresses "
+ "from safe function '" << SafeFn->getName()
+ << "' and from test function '" << TestFn->getName() << "'.\n";
+ exit(1);
+ }
+ I->setInitializer(nullptr); // Delete the initializer to make it external
+ } else {
+ // If we keep it in the safe module, then delete it in the test module
+ GV->setInitializer(nullptr);
+ }
}
// Make sure that there is a global ctor/dtor array in both halves of the
// module if they both have static ctor/dtor functions.
- SplitStaticCtorDtor("llvm.global_ctors", M, New);
- SplitStaticCtorDtor("llvm.global_dtors", M, New);
+ SplitStaticCtorDtor("llvm.global_ctors", M, New, NewVMap);
+ SplitStaticCtorDtor("llvm.global_dtors", M, New, NewVMap);
return New;
}
// Basic Block Extraction Code
//===----------------------------------------------------------------------===//
-namespace {
- std::vector<BasicBlock*> BlocksToNotExtract;
-
- /// 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 {
- bool runOnModule(Module &M);
- };
- RegisterPass<BlockExtractorPass>
- XX("extract-bbs", "Extract Basic Blocks From Module (for bugpoint use)");
-}
-
-bool BlockExtractorPass::runOnModule(Module &M) {
- 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(), F->getFunctionType());
-
- // 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);
- }
-
- // Now that we know which blocks to not extract, figure out which ones we WANT
- // to extract.
- std::vector<BasicBlock*> BlocksToExtract;
- for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F)
- for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
- if (!TranslatedBlocksToNotExtract.count(BB))
- BlocksToExtract.push_back(BB);
-
- for (unsigned i = 0, e = BlocksToExtract.size(); i != e; ++i)
- ExtractBasicBlock(BlocksToExtract[i]);
-
- return !BlocksToExtract.empty();
-}
-
/// ExtractMappedBlocksFromModule - Extract all but the specified basic blocks
/// into their own functions. The only detail is that M is actually a module
/// cloned from the one the BBs are in, so some mapping needs to be performed.
Module *BugDriver::ExtractMappedBlocksFromModule(const
std::vector<BasicBlock*> &BBs,
Module *M) {
- // Set the global list so that pass will be able to access it.
- BlocksToNotExtract = BBs;
-
- std::vector<const PassInfo*> PI;
- PI.push_back(getPI(new BlockExtractorPass()));
- Module *Ret = runPassesOn(M, PI);
- BlocksToNotExtract.clear();
- if (Ret == 0) {
- std::cout << "*** Basic Block extraction failed, please report a bug!\n";
- M = swapProgramIn(M);
- EmitProgressBytecode("basicblockextractfail", true);
- swapProgramIn(M);
+ SmallString<128> Filename;
+ int FD;
+ error_code EC = sys::fs::createUniqueFile(
+ OutputPrefix + "-extractblocks%%%%%%%", FD, Filename);
+ if (EC) {
+ outs() << "*** Basic Block extraction failed!\n";
+ errs() << "Error creating temporary file: " << EC.message() << "\n";
+ EmitProgressBitcode(M, "basicblockextractfail", true);
+ return nullptr;
+ }
+ sys::RemoveFileOnSignal(Filename);
+
+ tool_output_file BlocksToNotExtractFile(Filename.c_str(), FD);
+ for (std::vector<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end();
+ I != E; ++I) {
+ BasicBlock *BB = *I;
+ // If the BB doesn't have a name, give it one so we have something to key
+ // off of.
+ if (!BB->hasName()) BB->setName("tmpbb");
+ BlocksToNotExtractFile.os() << BB->getParent()->getName() << " "
+ << BB->getName() << "\n";
+ }
+ BlocksToNotExtractFile.os().close();
+ if (BlocksToNotExtractFile.os().has_error()) {
+ errs() << "Error writing list of blocks to not extract\n";
+ EmitProgressBitcode(M, "basicblockextractfail", true);
+ BlocksToNotExtractFile.os().clear_error();
+ return nullptr;
+ }
+ BlocksToNotExtractFile.keep();
+
+ std::string uniqueFN = "--extract-blocks-file=";
+ uniqueFN += Filename.str();
+ const char *ExtraArg = uniqueFN.c_str();
+
+ std::vector<std::string> PI;
+ PI.push_back("extract-blocks");
+ Module *Ret = runPassesOn(M, PI, false, 1, &ExtraArg);
+
+ sys::fs::remove(Filename.c_str());
+
+ if (!Ret) {
+ outs() << "*** Basic Block extraction failed, please report a bug!\n";
+ EmitProgressBitcode(M, "basicblockextractfail", true);
}
return Ret;
}