X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fbugpoint%2FExtractFunction.cpp;h=fe0ab69dc162d8f1ebfb287eb1ca1f3dadc6fc52;hb=ac6ac4cb6c567726b5ea8c823906a4ab6c8c089a;hp=73b65ca94f70c5cbe2c3466d01710afb22387725;hpb=db125cfaf57cc83e7dd7453de2d509bc8efd0e5e;p=oota-llvm.git diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index 73b65ca94f7..fe0ab69dc16 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -13,28 +13,29 @@ //===----------------------------------------------------------------------===// #include "BugDriver.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/LLVMContext.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/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "llvm/Pass.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Assembly/Writer.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/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileUtilities.h" -#include "llvm/Support/ToolOutputFile.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 using namespace llvm; +#define DEBUG_TYPE "bugpoint" + namespace llvm { bool DisableSimplifyCFG = false; extern cl::opt OutputPrefix; @@ -47,17 +48,45 @@ namespace { cl::opt NoSCFG("disable-simplifycfg", cl::location(DisableSimplifyCFG), cl::desc("Do not use the -simplifycfg pass to reduce testcases")); -} -/// deleteInstructionFromProgram - This method clones the current Program and -/// deletes the specified instruction from the cloned module. It then runs a -/// series of cleanup passes (ADCE and SimplifyCFG) to eliminate any code which -/// depends on the value. The modified module is then returned. -/// -Module *BugDriver::deleteInstructionFromProgram(const Instruction *I, - unsigned Simplification) { + 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 Todo; + std::set Done; + Todo.push_back(I); + + while (!Todo.empty()) { + Constant* V = Todo.back(); + Todo.pop_back(); + Done.insert(V); + + if (BlockAddress *BA = dyn_cast(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(*i); + if (C && !isa(C) && !Done.count(C)) + Todo.push_back(C); + } + } + return nullptr; + } +} // end anonymous namespace + +std::unique_ptr +BugDriver::deleteInstructionFromProgram(const Instruction *I, + unsigned Simplification) { // FIXME, use vmap? - Module *Clone = CloneModule(Program); + Module *Clone = CloneModule(Program).release(); const BasicBlock *PBB = I->getParent(); const Function *PF = PBB->getParent(); @@ -71,7 +100,7 @@ Module *BugDriver::deleteInstructionFromProgram(const Instruction *I, BasicBlock::iterator RI = RBI->begin(); // Get iterator to corresponding inst std::advance(RI, std::distance(PBB->begin(), BasicBlock::const_iterator(I))); - Instruction *TheInst = RI; // Got the corresponding instruction! + Instruction *TheInst = &*RI; // Got the corresponding instruction! // If this instruction produces a value, replace any users with null values if (!TheInst->getType()->isVoidTy()) @@ -90,7 +119,7 @@ Module *BugDriver::deleteInstructionFromProgram(const Instruction *I, Passes.push_back("simplifycfg"); // Delete dead control flow Passes.push_back("verify"); - Module *New = runPassesOn(Clone, Passes); + std::unique_ptr New = runPassesOn(Clone, Passes); delete Clone; if (!New) { errs() << "Instruction removal failed. Sorry. :( Please report a bug!\n"; @@ -99,11 +128,8 @@ Module *BugDriver::deleteInstructionFromProgram(const Instruction *I, return New; } -/// performFinalCleanups - This method clones the current Program and performs -/// a series of cleanups intended to get rid of extra cruft on the module -/// before handing it to the user. -/// -Module *BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) { +std::unique_ptr +BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) { // Make all functions external, so GlobalDCE doesn't delete them... for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) I->setLinkage(GlobalValue::ExternalLinkage); @@ -116,29 +142,25 @@ Module *BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) { else CleanupPasses.push_back("deadargelim"); - Module *New = runPassesOn(M, CleanupPasses); - if (New == 0) { + std::unique_ptr New = runPassesOn(M, CleanupPasses); + if (!New) { errs() << "Final cleanups failed. Sorry. :( Please report a bug!\n"; - return M; + return nullptr; } delete M; return New; } - -/// ExtractLoop - Given a module, extract up to one loop from it into a new -/// 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::unique_ptr BugDriver::extractLoop(Module *M) { std::vector LoopExtractPasses; LoopExtractPasses.push_back("loop-extract-single"); - Module *NewM = runPassesOn(M, LoopExtractPasses); - if (NewM == 0) { + std::unique_ptr NewM = runPassesOn(M, LoopExtractPasses); + if (!NewM) { outs() << "*** Loop extraction failed: "; EmitProgressBitcode(M, "loopextraction", true); outs() << "*** Sorry. :( Please report a bug!\n"; - return 0; + return nullptr; } // Check to see if we created any new functions. If not, no loops were @@ -146,8 +168,7 @@ Module *BugDriver::ExtractLoop(Module *M) { // to avoid taking forever. 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(); @@ -158,11 +179,43 @@ Module *BugDriver::ExtractLoop(Module *M) { return NewM; } +static void eliminateAliases(GlobalValue *GV) { + // First, check whether a GlobalAlias references this definition. + // GlobalAlias MAY NOT reference declarations. + for (;;) { + // 1. Find aliases + SmallVector aliases; + Module *M = GV->getParent(); + for (Module::alias_iterator I=M->alias_begin(), E=M->alias_end(); I!=E; ++I) + if (I->getAliasee()->stripPointerCasts() == GV) + aliases.push_back(&*I); + if (aliases.empty()) + break; + // 2. Resolve aliases + for (unsigned i=0, e=aliases.size(); ireplaceAllUsesWith(aliases[i]->getAliasee()); + aliases[i]->eraseFromParent(); + } + // 3. Repeat until no more aliases found; there might + // be an alias to an alias... + } +} + +// +// DeleteGlobalInitializer - "Remove" the global variable by deleting its initializer, +// making it external. +// +void llvm::DeleteGlobalInitializer(GlobalVariable *GV) { + eliminateAliases(GV); + GV->setInitializer(nullptr); +} // DeleteFunctionBody - "Remove" the function by deleting all of its basic // blocks, making it external. // void llvm::DeleteFunctionBody(Function *F) { + eliminateAliases(F); + // delete the body of the function... F->deleteBody(); assert(F->isDeclaration() && "This didn't make the function external!"); @@ -174,9 +227,9 @@ static Constant *GetTorInit(std::vector > &TorList) { assert(!TorList.empty() && "Don't create empty tor list!"); std::vector ArrayElts; Type *Int32Ty = Type::getInt32Ty(TorList[0].first->getContext()); - + StructType *STy = - StructType::get(Int32Ty, TorList[0].first->getType(), NULL); + StructType::get(Int32Ty, TorList[0].first->getType(), nullptr); for (unsigned i = 0, e = TorList.size(); i != e; ++i) { Constant *Elts[] = { ConstantInt::get(Int32Ty, TorList[i].second), @@ -250,13 +303,8 @@ static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2, } } - -/// 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 &F, +std::unique_ptr +llvm::SplitFunctionsOutOfModule(Module *M, const std::vector &F, ValueToValueMapTy &VMap) { // Make sure functions & globals are all external so that linkage // between the two modules will work. @@ -270,19 +318,14 @@ llvm::SplitFunctionsOutOfModule(Module *M, } ValueToValueMapTy NewVMap; - Module *New = CloneModule(M, NewVMap); - - // Make sure global initializers exist only in the safe module (CBE->.so) - for (Module::global_iterator I = New->global_begin(), E = New->global_end(); - I != E; ++I) - I->setInitializer(0); // Delete the initializer to make it external + std::unique_ptr New = CloneModule(M, NewVMap); // Remove the Test functions from the Safe module std::set TestFunctions; for (unsigned i = 0, e = F.size(); i != e; ++i) { Function *TNOF = cast(VMap[F[i]]); DEBUG(errs() << "Removing function "); - DEBUG(WriteAsOperand(errs(), TNOF, false)); + DEBUG(TNOF->printAsOperand(errs(), false)); DEBUG(errs() << "\n"); TestFunctions.insert(cast(NewVMap[TNOF])); DeleteFunctionBody(TNOF); // Function is now external in this module! @@ -290,16 +333,35 @@ llvm::SplitFunctionsOutOfModule(Module *M, // 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); - + for (Function &I : *New) + if (!TestFunctions.count(&I)) + DeleteFunctionBody(&I); + + // Try to split the global initializers evenly + for (GlobalVariable &I : M->globals()) { + GlobalVariable *GV = cast(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); + } + DeleteGlobalInitializer(&I); // Delete the initializer to make it external + } else { + // If we keep it in the safe module, then delete it in the test module + DeleteGlobalInitializer(GV); + } + } // 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, NewVMap); - SplitStaticCtorDtor("llvm.global_dtors", M, New, NewVMap); - + SplitStaticCtorDtor("llvm.global_ctors", M, New.get(), NewVMap); + SplitStaticCtorDtor("llvm.global_dtors", M, New.get(), NewVMap); + return New; } @@ -307,62 +369,51 @@ llvm::SplitFunctionsOutOfModule(Module *M, // Basic Block Extraction Code //===----------------------------------------------------------------------===// -/// 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. -/// If this operation fails for some reason (ie the implementation is buggy), -/// this function should return null, otherwise it returns a new Module. -Module *BugDriver::ExtractMappedBlocksFromModule(const - std::vector &BBs, - Module *M) { - sys::Path uniqueFilename(OutputPrefix + "-extractblocks"); - std::string ErrMsg; - if (uniqueFilename.createTemporaryFileOnDisk(true, &ErrMsg)) { +std::unique_ptr +BugDriver::extractMappedBlocksFromModule(const std::vector &BBs, + Module *M) { + SmallString<128> Filename; + int FD; + std::error_code EC = sys::fs::createUniqueFile( + OutputPrefix + "-extractblocks%%%%%%%", FD, Filename); + if (EC) { outs() << "*** Basic Block extraction failed!\n"; - errs() << "Error creating temporary file: " << ErrMsg << "\n"; + errs() << "Error creating temporary file: " << EC.message() << "\n"; EmitProgressBitcode(M, "basicblockextractfail", true); - return 0; + return nullptr; } - sys::RemoveFileOnSignal(uniqueFilename); + sys::RemoveFileOnSignal(Filename); - std::string ErrorInfo; - tool_output_file BlocksToNotExtractFile(uniqueFilename.c_str(), ErrorInfo); - if (!ErrorInfo.empty()) { - outs() << "*** Basic Block extraction failed!\n"; - errs() << "Error writing list of blocks to not extract: " << ErrorInfo - << "\n"; - EmitProgressBitcode(M, "basicblockextractfail", true); - return 0; - } + tool_output_file BlocksToNotExtractFile(Filename.c_str(), FD); for (std::vector::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()->getNameStr() << " " + 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: " << ErrorInfo - << "\n"; + errs() << "Error writing list of blocks to not extract\n"; EmitProgressBitcode(M, "basicblockextractfail", true); BlocksToNotExtractFile.os().clear_error(); - return 0; + return nullptr; } BlocksToNotExtractFile.keep(); - std::string uniqueFN = "--extract-blocks-file=" + uniqueFilename.str(); + std::string uniqueFN = "--extract-blocks-file="; + uniqueFN += Filename.str(); const char *ExtraArg = uniqueFN.c_str(); std::vector PI; PI.push_back("extract-blocks"); - Module *Ret = runPassesOn(M, PI, false, 1, &ExtraArg); + std::unique_ptr Ret = runPassesOn(M, PI, false, 1, &ExtraArg); - uniqueFilename.eraseFromDisk(); // Free disk space + sys::fs::remove(Filename.c_str()); - if (Ret == 0) { + if (!Ret) { outs() << "*** Basic Block extraction failed, please report a bug!\n"; EmitProgressBitcode(M, "basicblockextractfail", true); }