X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fbugpoint%2FExtractFunction.cpp;h=5119c801a024f368d8f1842c268b5808ae0e41cb;hb=91ef460285021b5bf43b3850f0f8958a09b8939c;hp=9cb922a55d4a2b98ddfe80b3ed8c7703ff25a54e;hpb=47ae4a1cee5eec5767a11403c0fac7c91ec45461;p=oota-llvm.git diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index 9cb922a55d4..5119c801a02 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -1,36 +1,44 @@ //===- ExtractFunction.cpp - Extract a function from Program --------------===// +// +// The LLVM Compiler Infrastructure // -// This file implements a method that extracts a function from program, cleans -// it up, and returns it as a new module. +// 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 implements several methods that are used to extract functions, +// loops, or portions of a module from the rest of the module. // //===----------------------------------------------------------------------===// #include "BugDriver.h" +#include "llvm/Constant.h" #include "llvm/Module.h" #include "llvm/PassManager.h" +#include "llvm/Pass.h" +#include "llvm/Type.h" +#include "llvm/Analysis/Verifier.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Type.h" -#include "llvm/Constant.h" +#include "llvm/Target/TargetData.h" #include "Support/CommandLine.h" +#include "Support/Debug.h" +#include "Support/FileUtilities.h" +using namespace llvm; -bool DisableSimplifyCFG = false; +namespace llvm { + bool DisableSimplifyCFG = false; +} // End llvm namespace namespace { cl::opt - NoADCE("disable-adce", - cl::desc("Do not use the -adce pass to reduce testcases")); - cl::opt NoDCE ("disable-dce", cl::desc("Do not use the -dce pass to reduce testcases")); cl::opt NoSCFG("disable-simplifycfg", cl::location(DisableSimplifyCFG), cl::desc("Do not use the -simplifycfg pass to reduce testcases")); - cl::opt - NoFinalCleanup("disable-final-cleanup", - cl::desc("Disable the final cleanup phase of narrowing")); } /// deleteInstructionFromProgram - This method clones the current Program and @@ -38,35 +46,38 @@ namespace { /// 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(Instruction *I, +Module *BugDriver::deleteInstructionFromProgram(const Instruction *I, unsigned Simplification) const { Module *Result = CloneModule(Program); - BasicBlock *PBB = I->getParent(); - Function *PF = PBB->getParent(); + const BasicBlock *PBB = I->getParent(); + const Function *PF = PBB->getParent(); Module::iterator RFI = Result->begin(); // Get iterator to corresponding fn - std::advance(RFI, std::distance(Program->begin(), Module::iterator(PF))); + std::advance(RFI, std::distance(PF->getParent()->begin(), + Module::const_iterator(PF))); Function::iterator RBI = RFI->begin(); // Get iterator to corresponding BB - std::advance(RBI, std::distance(PF->begin(), Function::iterator(PBB))); + std::advance(RBI, std::distance(PF->begin(), Function::const_iterator(PBB))); BasicBlock::iterator RI = RBI->begin(); // Get iterator to corresponding inst - std::advance(RI, std::distance(PBB->begin(), BasicBlock::iterator(I))); - I = RI; // Got the corresponding instruction! + std::advance(RI, std::distance(PBB->begin(), BasicBlock::const_iterator(I))); + Instruction *TheInst = RI; // Got the corresponding instruction! // If this instruction produces a value, replace any users with null values - if (I->getType() != Type::VoidTy) - I->replaceAllUsesWith(Constant::getNullValue(I->getType())); + if (TheInst->getType() != Type::VoidTy) + TheInst->replaceAllUsesWith(Constant::getNullValue(TheInst->getType())); // Remove the instruction from the program. - I->getParent()->getInstList().erase(I); + TheInst->getParent()->getInstList().erase(TheInst); // Spiff up the output a little bit. PassManager Passes; - if (Simplification > 2 && !NoADCE) - Passes.add(createAggressiveDCEPass()); // Remove dead code... - //Passes.add(createInstructionCombiningPass()); + // Make sure that the appropriate target data is always used... + Passes.add(new TargetData("bugpoint", Result)); + + /// FIXME: If this used runPasses() like the methods below, we could get rid + /// of the -disable-* options! if (Simplification > 1 && !NoDCE) Passes.add(createDeadCodeEliminationPass()); if (Simplification && !DisableSimplifyCFG) @@ -77,30 +88,117 @@ Module *BugDriver::deleteInstructionFromProgram(Instruction *I, return Result; } +static const PassInfo *getPI(Pass *P) { + const PassInfo *PI = P->getPassInfo(); + delete P; + return PI; +} + /// 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 *InM) const { - Module *M = InM ? InM : CloneModule(Program); - - // Allow disabling these passes if they crash bugpoint. - // - // FIXME: This should eventually run these passes in a pass list to prevent - // them from being able to crash bugpoint at all! - // - if (NoFinalCleanup) return M; - +Module *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); - PassManager CleanupPasses; - CleanupPasses.add(createFunctionResolvingPass()); - CleanupPasses.add(createGlobalDCEPass()); - CleanupPasses.add(createDeadTypeEliminationPass()); - CleanupPasses.add(createDeadArgEliminationPass(InM == 0)); - CleanupPasses.add(createVerifierPass()); - CleanupPasses.run(*M); - return M; + std::vector CleanupPasses; + CleanupPasses.push_back(getPI(createFunctionResolvingPass())); + CleanupPasses.push_back(getPI(createGlobalDCEPass())); + CleanupPasses.push_back(getPI(createDeadTypeEliminationPass())); + + if (MayModifySemantics) + CleanupPasses.push_back(getPI(createDeadArgHackingPass())); + else + CleanupPasses.push_back(getPI(createDeadArgEliminationPass())); + + Module *New = runPassesOn(M, CleanupPasses); + if (New == 0) { + std::cerr << "Final cleanups failed. Sorry. :( Please report a bug!\n"; + } + 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::vector LoopExtractPasses; + LoopExtractPasses.push_back(getPI(createSingleLoopExtractorPass())); + + 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; + } + + // Check to see if we created any new functions. If not, no loops were + // extracted and we should return null. + if (M->size() == NewM->size()) { + delete NewM; + return 0; + } + + return NewM; +} + + +// DeleteFunctionBody - "Remove" the function by deleting all of its basic +// blocks, making it external. +// +void llvm::DeleteFunctionBody(Function *F) { + // delete the body of the function... + F->deleteBody(); + assert(F->isExternal() && "This didn't make the function external!"); +} + +/// 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. +/// +/// FIXME: this could be made DRAMATICALLY more efficient for large programs if +/// we just MOVED functions from one module to the other, instead of cloning the +/// whole module, then proceeding to delete an entire module's worth of stuff. +/// +Module *llvm::SplitFunctionsOutOfModule(Module *M, + const std::vector &F) { + // 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::giterator I = M->gbegin(), E = M->gend(); I != E; ++I) + I->setLinkage(GlobalValue::ExternalLinkage); + + Module *New = CloneModule(M); + + // Make sure global initializers exist only in the safe module (CBE->.so) + for (Module::giterator I = New->gbegin(), E = New->gend(); I != E; ++I) + I->setInitializer(0); // Delete the initializer to make it external + + // Remove the Test functions from the Safe module + for (unsigned i = 0, e = F.size(); i != e; ++i) { + Function *TNOF = M->getFunction(F[i]->getName(), F[i]->getFunctionType()); + DEBUG(std::cerr << "Removing function " << F[i]->getName() << "\n"); + assert(TNOF && "Function doesn't exist in module!"); + DeleteFunctionBody(TNOF); // Function is now external in this module! + } + + // Remove the Safe functions from the Test module + for (Module::iterator I = New->begin(), E = New->end(); I != E; ++I) { + bool funcFound = false; + for (std::vector::const_iterator FI = F.begin(), Fe = F.end(); + FI != Fe; ++FI) + if (I->getName() == (*FI)->getName()) funcFound = true; + + if (!funcFound) + DeleteFunctionBody(I); + } + return New; }