static void ReduceGlobalInitializers(BugDriver &BD, bool (*TestFn)(const BugDriver &, Module *), std::string &Error) { if (BD.getProgram()->global_begin() != BD.getProgram()->global_end()) { // Now try to reduce the number of global variable initializers in the // module to something small. Module *M = CloneModule(BD.getProgram()).release(); bool DeletedInit = false; for (Module::global_iterator I = M->global_begin(), E = M->global_end(); I != E; ++I) if (I->hasInitializer()) { DeleteGlobalInitializer(&*I); I->setLinkage(GlobalValue::ExternalLinkage); I->setComdat(nullptr); DeletedInit = true; } if (!DeletedInit) { delete M; // No change made... } else { // See if the program still causes a crash... outs() << "\nChecking to see if we can delete global inits: "; if (TestFn(BD, M)) { // Still crashes? BD.setNewProgram(M); outs() << "\n*** Able to remove all global initializers!\n"; } else { // No longer crashes? outs() << " - Removing all global inits hides problem!\n"; delete M; std::vector<GlobalVariable*> GVs; for (Module::global_iterator I = BD.getProgram()->global_begin(), E = BD.getProgram()->global_end(); I != E; ++I) if (I->hasInitializer()) GVs.push_back(&*I); if (GVs.size() > 1 && !BugpointIsInterrupted) { outs() << "\n*** Attempting to reduce the number of global " << "variables in the testcase\n"; unsigned OldSize = GVs.size(); ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs, Error); assert(!Error.empty()); if (GVs.size() < OldSize) BD.EmitProgressBitcode(BD.getProgram(), "reduced-global-variables"); } } } } }
/// DebugACrash - Given a predicate that determines whether a component crashes /// on a program, try to destructively reduce the program while still keeping /// the predicate true. static bool DebugACrash(BugDriver &BD, bool (*TestFn)(const BugDriver &, Module *), std::string &Error) { // See if we can get away with nuking some of the global variable initializers // in the program... if (!NoGlobalRM && BD.getProgram()->global_begin() != BD.getProgram()->global_end()) { // Now try to reduce the number of global variable initializers in the // module to something small. Module *M = CloneModule(BD.getProgram()); bool DeletedInit = false; for (Module::global_iterator I = M->global_begin(), E = M->global_end(); I != E; ++I) if (I->hasInitializer()) { I->setInitializer(nullptr); I->setLinkage(GlobalValue::ExternalLinkage); DeletedInit = true; } if (!DeletedInit) { delete M; // No change made... } else { // See if the program still causes a crash... outs() << "\nChecking to see if we can delete global inits: "; if (TestFn(BD, M)) { // Still crashes? BD.setNewProgram(M); outs() << "\n*** Able to remove all global initializers!\n"; } else { // No longer crashes? outs() << " - Removing all global inits hides problem!\n"; delete M; std::vector<GlobalVariable*> GVs; for (Module::global_iterator I = BD.getProgram()->global_begin(), E = BD.getProgram()->global_end(); I != E; ++I) if (I->hasInitializer()) GVs.push_back(&*I); if (GVs.size() > 1 && !BugpointIsInterrupted) { outs() << "\n*** Attempting to reduce the number of global " << "variables in the testcase\n"; unsigned OldSize = GVs.size(); ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs, Error); if (!Error.empty()) return true; if (GVs.size() < OldSize) BD.EmitProgressBitcode(BD.getProgram(), "reduced-global-variables"); } } } } // Now try to reduce the number of functions in the module to something small. std::vector<Function*> Functions; for (Function &F : *BD.getProgram()) if (!F.isDeclaration()) Functions.push_back(&F); if (Functions.size() > 1 && !BugpointIsInterrupted) { outs() << "\n*** Attempting to reduce the number of functions " "in the testcase\n"; unsigned OldSize = Functions.size(); ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error); if (Functions.size() < OldSize) BD.EmitProgressBitcode(BD.getProgram(), "reduced-function"); } // Attempt to delete entire basic blocks at a time to speed up // convergence... this actually works by setting the terminator of the blocks // to a return instruction then running simplifycfg, which can potentially // shrinks the code dramatically quickly // if (!DisableSimplifyCFG && !BugpointIsInterrupted) { std::vector<const BasicBlock*> Blocks; for (Function &F : *BD.getProgram()) for (BasicBlock &BB : F) Blocks.push_back(&BB); unsigned OldSize = Blocks.size(); ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error); if (Blocks.size() < OldSize) BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks"); } // Attempt to delete instructions using bisection. This should help out nasty // cases with large basic blocks where the problem is at one end. if (!BugpointIsInterrupted) { std::vector<const Instruction*> Insts; for (const Function &F : *BD.getProgram()) for (const BasicBlock &BB : F) for (const Instruction &I : BB) if (!isa<TerminatorInst>(&I)) Insts.push_back(&I); ReduceCrashingInstructions(BD, TestFn).reduceList(Insts, Error); } // FIXME: This should use the list reducer to converge faster by deleting // larger chunks of instructions at a time! unsigned Simplification = 2; do { if (BugpointIsInterrupted) break; --Simplification; outs() << "\n*** Attempting to reduce testcase by deleting instruc" << "tions: Simplification Level #" << Simplification << '\n'; // Now that we have deleted the functions that are unnecessary for the // program, try to remove instructions that are not necessary to cause the // crash. To do this, we loop through all of the instructions in the // remaining functions, deleting them (replacing any values produced with // nulls), and then running ADCE and SimplifyCFG. If the transformed input // still triggers failure, keep deleting until we cannot trigger failure // anymore. // unsigned InstructionsToSkipBeforeDeleting = 0; TryAgain: // Loop over all of the (non-terminator) instructions remaining in the // function, attempting to delete them. unsigned CurInstructionNum = 0; for (Module::const_iterator FI = BD.getProgram()->begin(), E = BD.getProgram()->end(); FI != E; ++FI) if (!FI->isDeclaration()) for (Function::const_iterator BI = FI->begin(), E = FI->end(); BI != E; ++BI) for (BasicBlock::const_iterator I = BI->begin(), E = --BI->end(); I != E; ++I, ++CurInstructionNum) { if (InstructionsToSkipBeforeDeleting) { --InstructionsToSkipBeforeDeleting; } else { if (BugpointIsInterrupted) goto ExitLoops; if (isa<LandingPadInst>(I)) continue; outs() << "Checking instruction: " << *I; std::unique_ptr<Module> M = BD.deleteInstructionFromProgram(&*I, Simplification); // Find out if the pass still crashes on this pass... if (TestFn(BD, M.get())) { // Yup, it does, we delete the old module, and continue trying // to reduce the testcase... BD.setNewProgram(M.release()); InstructionsToSkipBeforeDeleting = CurInstructionNum; goto TryAgain; // I wish I had a multi-level break here! } } } if (InstructionsToSkipBeforeDeleting) { InstructionsToSkipBeforeDeleting = 0; goto TryAgain; } } while (Simplification); ExitLoops: // Try to clean up the testcase by running funcresolve and globaldce... if (!BugpointIsInterrupted) { outs() << "\n*** Attempting to perform final cleanups: "; Module *M = CloneModule(BD.getProgram()); M = BD.performFinalCleanups(M, true).release(); // Find out if the pass still crashes on the cleaned up program... if (TestFn(BD, M)) { BD.setNewProgram(M); // Yup, it does, keep the reduced version... } else { delete M; } } BD.EmitProgressBitcode(BD.getProgram(), "reduced-simplified"); return false; }
static Error ReduceInsts(BugDriver &BD, bool (*TestFn)(const BugDriver &, Module *)) { // Attempt to delete instructions using bisection. This should help out nasty // cases with large basic blocks where the problem is at one end. if (!BugpointIsInterrupted) { std::vector<const Instruction *> Insts; for (const Function &F : *BD.getProgram()) for (const BasicBlock &BB : F) for (const Instruction &I : BB) if (!isa<TerminatorInst>(&I)) Insts.push_back(&I); Expected<bool> Result = ReduceCrashingInstructions(BD, TestFn).reduceList(Insts); if (Error E = Result.takeError()) return E; } unsigned Simplification = 2; do { if (BugpointIsInterrupted) // TODO: Should we distinguish this with an "interrupted error"? return Error::success(); --Simplification; outs() << "\n*** Attempting to reduce testcase by deleting instruc" << "tions: Simplification Level #" << Simplification << '\n'; // Now that we have deleted the functions that are unnecessary for the // program, try to remove instructions that are not necessary to cause the // crash. To do this, we loop through all of the instructions in the // remaining functions, deleting them (replacing any values produced with // nulls), and then running ADCE and SimplifyCFG. If the transformed input // still triggers failure, keep deleting until we cannot trigger failure // anymore. // unsigned InstructionsToSkipBeforeDeleting = 0; TryAgain: // Loop over all of the (non-terminator) instructions remaining in the // function, attempting to delete them. unsigned CurInstructionNum = 0; for (Module::const_iterator FI = BD.getProgram()->begin(), E = BD.getProgram()->end(); FI != E; ++FI) if (!FI->isDeclaration()) for (Function::const_iterator BI = FI->begin(), E = FI->end(); BI != E; ++BI) for (BasicBlock::const_iterator I = BI->begin(), E = --BI->end(); I != E; ++I, ++CurInstructionNum) { if (InstructionsToSkipBeforeDeleting) { --InstructionsToSkipBeforeDeleting; } else { if (BugpointIsInterrupted) // TODO: Should this be some kind of interrupted error? return Error::success(); if (I->isEHPad() || I->getType()->isTokenTy()) continue; outs() << "Checking instruction: " << *I; std::unique_ptr<Module> M = BD.deleteInstructionFromProgram(&*I, Simplification); // Find out if the pass still crashes on this pass... if (TestFn(BD, M.get())) { // Yup, it does, we delete the old module, and continue trying // to reduce the testcase... BD.setNewProgram(M.release()); InstructionsToSkipBeforeDeleting = CurInstructionNum; goto TryAgain; // I wish I had a multi-level break here! } } } if (InstructionsToSkipBeforeDeleting) { InstructionsToSkipBeforeDeleting = 0; goto TryAgain; } } while (Simplification); BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions"); return Error::success(); }
/// DebugACrash - Given a predicate that determines whether a component crashes /// on a program, try to destructively reduce the program while still keeping /// the predicate true. static Error DebugACrash(BugDriver &BD, bool (*TestFn)(const BugDriver &, Module *)) { // See if we can get away with nuking some of the global variable initializers // in the program... if (!NoGlobalRM) if (Error E = ReduceGlobalInitializers(BD, TestFn)) return E; // Now try to reduce the number of functions in the module to something small. std::vector<Function *> Functions; for (Function &F : *BD.getProgram()) if (!F.isDeclaration()) Functions.push_back(&F); if (Functions.size() > 1 && !BugpointIsInterrupted) { outs() << "\n*** Attempting to reduce the number of functions " "in the testcase\n"; unsigned OldSize = Functions.size(); Expected<bool> Result = ReduceCrashingFunctions(BD, TestFn).reduceList(Functions); if (Error E = Result.takeError()) return E; if (Functions.size() < OldSize) BD.EmitProgressBitcode(BD.getProgram(), "reduced-function"); } // Attempt to change conditional branches into unconditional branches to // eliminate blocks. if (!DisableSimplifyCFG && !BugpointIsInterrupted) { std::vector<const BasicBlock *> Blocks; for (Function &F : *BD.getProgram()) for (BasicBlock &BB : F) Blocks.push_back(&BB); unsigned OldSize = Blocks.size(); Expected<bool> Result = ReduceCrashingConditionals(BD, TestFn, true).reduceList(Blocks); if (Error E = Result.takeError()) return E; Result = ReduceCrashingConditionals(BD, TestFn, false).reduceList(Blocks); if (Error E = Result.takeError()) return E; if (Blocks.size() < OldSize) BD.EmitProgressBitcode(BD.getProgram(), "reduced-conditionals"); } // Attempt to delete entire basic blocks at a time to speed up // convergence... this actually works by setting the terminator of the blocks // to a return instruction then running simplifycfg, which can potentially // shrinks the code dramatically quickly // if (!DisableSimplifyCFG && !BugpointIsInterrupted) { std::vector<const BasicBlock *> Blocks; for (Function &F : *BD.getProgram()) for (BasicBlock &BB : F) Blocks.push_back(&BB); unsigned OldSize = Blocks.size(); Expected<bool> Result = ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks); if (Error E = Result.takeError()) return E; if (Blocks.size() < OldSize) BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks"); } if (!DisableSimplifyCFG & !BugpointIsInterrupted) { std::vector<const BasicBlock *> Blocks; for (Function &F : *BD.getProgram()) for (BasicBlock &BB : F) Blocks.push_back(&BB); unsigned OldSize = Blocks.size(); Expected<bool> Result = ReduceSimplifyCFG(BD, TestFn).reduceList(Blocks); if (Error E = Result.takeError()) return E; if (Blocks.size() < OldSize) BD.EmitProgressBitcode(BD.getProgram(), "reduced-simplifycfg"); } // Attempt to delete instructions using bisection. This should help out nasty // cases with large basic blocks where the problem is at one end. if (!BugpointIsInterrupted) if (Error E = ReduceInsts(BD, TestFn)) return E; // Attempt to strip debug info metadata. auto stripMetadata = [&](std::function<bool(Module &)> strip) { std::unique_ptr<Module> M = CloneModule(BD.getProgram()); strip(*M); if (TestFn(BD, M.get())) BD.setNewProgram(M.release()); }; if (!NoStripDebugInfo && !BugpointIsInterrupted) { outs() << "\n*** Attempting to strip the debug info: "; stripMetadata(StripDebugInfo); } if (!NoStripDebugTypeInfo && !BugpointIsInterrupted) { outs() << "\n*** Attempting to strip the debug type info: "; stripMetadata(stripNonLineTableDebugInfo); } if (!NoNamedMDRM) { if (!BugpointIsInterrupted) { // Try to reduce the amount of global metadata (particularly debug info), // by dropping global named metadata that anchors them outs() << "\n*** Attempting to remove named metadata: "; std::vector<std::string> NamedMDNames; for (auto &NamedMD : BD.getProgram()->named_metadata()) NamedMDNames.push_back(NamedMD.getName().str()); Expected<bool> Result = ReduceCrashingNamedMD(BD, TestFn).reduceList(NamedMDNames); if (Error E = Result.takeError()) return E; } if (!BugpointIsInterrupted) { // Now that we quickly dropped all the named metadata that doesn't // contribute to the crash, bisect the operands of the remaining ones std::vector<const MDNode *> NamedMDOps; for (auto &NamedMD : BD.getProgram()->named_metadata()) for (auto op : NamedMD.operands()) NamedMDOps.push_back(op); Expected<bool> Result = ReduceCrashingNamedMDOps(BD, TestFn).reduceList(NamedMDOps); if (Error E = Result.takeError()) return E; } BD.EmitProgressBitcode(BD.getProgram(), "reduced-named-md"); } // Try to clean up the testcase by running funcresolve and globaldce... if (!BugpointIsInterrupted) { outs() << "\n*** Attempting to perform final cleanups: "; Module *M = CloneModule(BD.getProgram()).release(); M = BD.performFinalCleanups(M, true).release(); // Find out if the pass still crashes on the cleaned up program... if (TestFn(BD, M)) { BD.setNewProgram(M); // Yup, it does, keep the reduced version... } else { delete M; } } BD.EmitProgressBitcode(BD.getProgram(), "reduced-simplified"); return Error::success(); }
/// DebugAMiscompilation - This is a generic driver to narrow down /// miscompilations, either in an optimization or a code generator. /// static std::vector<Function*> DebugAMiscompilation(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *, Module *, std::string &), std::string &Error) { // Okay, now that we have reduced the list of passes which are causing the // failure, see if we can pin down which functions are being // miscompiled... first build a list of all of the non-external functions in // the program. std::vector<Function*> MiscompiledFunctions; Module *Prog = BD.getProgram(); for (Module::iterator I = Prog->begin(), E = Prog->end(); I != E; ++I) if (!I->isDeclaration()) MiscompiledFunctions.push_back(I); // Do the reduction... if (!BugpointIsInterrupted) ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions, Error); if (!Error.empty()) return MiscompiledFunctions; outs() << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") << " being miscompiled: "; PrintFunctionList(MiscompiledFunctions); outs() << '\n'; // See if we can rip any loops out of the miscompiled functions and still // trigger the problem. if (!BugpointIsInterrupted && !DisableLoopExtraction) { bool Ret = ExtractLoops(BD, TestFn, MiscompiledFunctions, Error); if (!Error.empty()) return MiscompiledFunctions; if (Ret) { // Okay, we extracted some loops and the problem still appears. See if // we can eliminate some of the created functions from being candidates. DisambiguateGlobalSymbols(BD.getProgram()); // Do the reduction... if (!BugpointIsInterrupted) ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions, Error); if (!Error.empty()) return MiscompiledFunctions; outs() << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") << " being miscompiled: "; PrintFunctionList(MiscompiledFunctions); outs() << '\n'; } } if (!BugpointIsInterrupted && !DisableBlockExtraction) { bool Ret = ExtractBlocks(BD, TestFn, MiscompiledFunctions, Error); if (!Error.empty()) return MiscompiledFunctions; if (Ret) { // Okay, we extracted some blocks and the problem still appears. See if // we can eliminate some of the created functions from being candidates. DisambiguateGlobalSymbols(BD.getProgram()); // Do the reduction... ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions, Error); if (!Error.empty()) return MiscompiledFunctions; outs() << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") << " being miscompiled: "; PrintFunctionList(MiscompiledFunctions); outs() << '\n'; } } return MiscompiledFunctions; }
/// ExtractBlocks - Given a reduced list of functions that still expose the bug, /// extract as many basic blocks from the region as possible without obscuring /// the bug. /// static bool ExtractBlocks(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *, Module *, std::string &), std::vector<Function*> &MiscompiledFunctions, std::string &Error) { if (BugpointIsInterrupted) return false; std::vector<BasicBlock*> Blocks; for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) for (Function::iterator I = MiscompiledFunctions[i]->begin(), E = MiscompiledFunctions[i]->end(); I != E; ++I) Blocks.push_back(I); // Use the list reducer to identify blocks that can be extracted without // obscuring the bug. The Blocks list will end up containing blocks that must // be retained from the original program. unsigned OldSize = Blocks.size(); // Check to see if all blocks are extractible first. bool Ret = ReduceMiscompiledBlocks(BD, TestFn, MiscompiledFunctions) .TestFuncs(std::vector<BasicBlock*>(), Error); if (!Error.empty()) return false; if (Ret) { Blocks.clear(); } else { ReduceMiscompiledBlocks(BD, TestFn, MiscompiledFunctions).reduceList(Blocks, Error); if (!Error.empty()) return false; if (Blocks.size() == OldSize) return false; } DenseMap<const Value*, Value*> ValueMap; Module *ProgClone = CloneModule(BD.getProgram(), ValueMap); Module *ToExtract = SplitFunctionsOutOfModule(ProgClone, MiscompiledFunctions, ValueMap); Module *Extracted = BD.ExtractMappedBlocksFromModule(Blocks, ToExtract); if (Extracted == 0) { // Weird, extraction should have worked. errs() << "Nondeterministic problem extracting blocks??\n"; delete ProgClone; delete ToExtract; return false; } // Otherwise, block extraction succeeded. Link the two program fragments back // together. delete ToExtract; std::vector<std::pair<std::string, const FunctionType*> > MisCompFunctions; for (Module::iterator I = Extracted->begin(), E = Extracted->end(); I != E; ++I) if (!I->isDeclaration()) MisCompFunctions.push_back(std::make_pair(I->getName(), I->getFunctionType())); std::string ErrorMsg; if (Linker::LinkModules(ProgClone, Extracted, &ErrorMsg)) { errs() << BD.getToolName() << ": Error linking modules together:" << ErrorMsg << '\n'; exit(1); } delete Extracted; // Set the new program and delete the old one. BD.setNewProgram(ProgClone); // Update the list of miscompiled functions. MiscompiledFunctions.clear(); for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first); assert(NewF && "Function not found??"); assert(NewF->getFunctionType() == MisCompFunctions[i].second && "Function has wrong type??"); MiscompiledFunctions.push_back(NewF); } return true; }
/// ExtractLoops - Given a reduced list of functions that still exposed the bug, /// check to see if we can extract the loops in the region without obscuring the /// bug. If so, it reduces the amount of code identified. /// static bool ExtractLoops(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *, Module *, std::string &), std::vector<Function*> &MiscompiledFunctions, std::string &Error) { bool MadeChange = false; while (1) { if (BugpointIsInterrupted) return MadeChange; DenseMap<const Value*, Value*> ValueMap; Module *ToNotOptimize = CloneModule(BD.getProgram(), ValueMap); Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, MiscompiledFunctions, ValueMap); Module *ToOptimizeLoopExtracted = BD.ExtractLoop(ToOptimize); if (!ToOptimizeLoopExtracted) { // If the loop extractor crashed or if there were no extractible loops, // then this chapter of our odyssey is over with. delete ToNotOptimize; delete ToOptimize; return MadeChange; } errs() << "Extracted a loop from the breaking portion of the program.\n"; // Bugpoint is intentionally not very trusting of LLVM transformations. In // particular, we're not going to assume that the loop extractor works, so // we're going to test the newly loop extracted program to make sure nothing // has broken. If something broke, then we'll inform the user and stop // extraction. AbstractInterpreter *AI = BD.switchToSafeInterpreter(); bool Failure = TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, false, Error); if (!Error.empty()) return false; if (Failure) { BD.switchToInterpreter(AI); // Merged program doesn't work anymore! errs() << " *** ERROR: Loop extraction broke the program. :(" << " Please report a bug!\n"; errs() << " Continuing on with un-loop-extracted version.\n"; BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-tno.bc", ToNotOptimize); BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to.bc", ToOptimize); BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to-le.bc", ToOptimizeLoopExtracted); errs() << "Please submit the " << OutputPrefix << "-loop-extract-fail-*.bc files.\n"; delete ToOptimize; delete ToNotOptimize; delete ToOptimizeLoopExtracted; return MadeChange; } delete ToOptimize; BD.switchToInterpreter(AI); outs() << " Testing after loop extraction:\n"; // Clone modules, the tester function will free them. Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted); Module *TNOBackup = CloneModule(ToNotOptimize); Failure = TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize, Error); if (!Error.empty()) return false; if (!Failure) { outs() << "*** Loop extraction masked the problem. Undoing.\n"; // If the program is not still broken, then loop extraction did something // that masked the error. Stop loop extraction now. delete TOLEBackup; delete TNOBackup; return MadeChange; } ToOptimizeLoopExtracted = TOLEBackup; ToNotOptimize = TNOBackup; outs() << "*** Loop extraction successful!\n"; std::vector<std::pair<std::string, const FunctionType*> > MisCompFunctions; for (Module::iterator I = ToOptimizeLoopExtracted->begin(), E = ToOptimizeLoopExtracted->end(); I != E; ++I) if (!I->isDeclaration()) MisCompFunctions.push_back(std::make_pair(I->getName(), I->getFunctionType())); // Okay, great! Now we know that we extracted a loop and that loop // extraction both didn't break the program, and didn't mask the problem. // Replace the current program with the loop extracted version, and try to // extract another loop. std::string ErrorMsg; if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted, &ErrorMsg)){ errs() << BD.getToolName() << ": Error linking modules together:" << ErrorMsg << '\n'; exit(1); } delete ToOptimizeLoopExtracted; // All of the Function*'s in the MiscompiledFunctions list are in the old // module. Update this list to include all of the functions in the // optimized and loop extracted module. MiscompiledFunctions.clear(); for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { Function *NewF = ToNotOptimize->getFunction(MisCompFunctions[i].first); assert(NewF && "Function not found??"); assert(NewF->getFunctionType() == MisCompFunctions[i].second && "found wrong function type?"); MiscompiledFunctions.push_back(NewF); } BD.setNewProgram(ToNotOptimize); MadeChange = true; } }
/// TestCodeGenerator - This is the predicate function used to check to see if /// the "Test" portion of the program is miscompiled by the code generator under /// test. If so, return true. In any case, both module arguments are deleted. /// static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, std::string &Error) { CleanupAndPrepareModules(BD, Test, Safe); SmallString<128> TestModuleBC; int TestModuleFD; std::error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc", TestModuleFD, TestModuleBC); if (EC) { errs() << BD.getToolName() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } if (BD.writeProgramToFile(TestModuleBC.str(), TestModuleFD, Test)) { errs() << "Error writing bitcode to `" << TestModuleBC.str() << "'\nExiting."; exit(1); } delete Test; FileRemover TestModuleBCRemover(TestModuleBC.str(), !SaveTemps); // Make the shared library SmallString<128> SafeModuleBC; int SafeModuleFD; EC = sys::fs::createTemporaryFile("bugpoint.safe", "bc", SafeModuleFD, SafeModuleBC); if (EC) { errs() << BD.getToolName() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } if (BD.writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, Safe)) { errs() << "Error writing bitcode to `" << SafeModuleBC << "'\nExiting."; exit(1); } FileRemover SafeModuleBCRemover(SafeModuleBC.str(), !SaveTemps); std::string SharedObject = BD.compileSharedObject(SafeModuleBC.str(), Error); if (!Error.empty()) return false; delete Safe; FileRemover SharedObjectRemover(SharedObject, !SaveTemps); // Run the code generator on the `Test' code, loading the shared library. // The function returns whether or not the new output differs from reference. bool Result = BD.diffProgram(BD.getProgram(), TestModuleBC.str(), SharedObject, false, &Error); if (!Error.empty()) return false; if (Result) errs() << ": still failing!\n"; else errs() << ": didn't fail.\n"; return Result; }
/// DebugAMiscompilation - This is a generic driver to narrow down /// miscompilations, either in an optimization or a code generator. /// static std::vector<Function*> DebugAMiscompilation(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *, Module *)) { // Okay, now that we have reduced the list of passes which are causing the // failure, see if we can pin down which functions are being // miscompiled... first build a list of all of the non-external functions in // the program. std::vector<Function*> MiscompiledFunctions; Module *Prog = BD.getProgram(); for (Module::iterator I = Prog->begin(), E = Prog->end(); I != E; ++I) if (!I->isDeclaration()) MiscompiledFunctions.push_back(I); // Do the reduction... if (!BugpointIsInterrupted) ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); outs() << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") << " being miscompiled: "; PrintFunctionList(MiscompiledFunctions); outs() << '\n'; // See if we can rip any loops out of the miscompiled functions and still // trigger the problem. if (!BugpointIsInterrupted && !DisableLoopExtraction && ExtractLoops(BD, TestFn, MiscompiledFunctions)) { // Okay, we extracted some loops and the problem still appears. See if we // can eliminate some of the created functions from being candidates. // Loop extraction can introduce functions with the same name (foo_code). // Make sure to disambiguate the symbols so that when the program is split // apart that we can link it back together again. DisambiguateGlobalSymbols(BD.getProgram()); // Do the reduction... if (!BugpointIsInterrupted) ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); outs() << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") << " being miscompiled: "; PrintFunctionList(MiscompiledFunctions); outs() << '\n'; } if (!BugpointIsInterrupted && !DisableBlockExtraction && ExtractBlocks(BD, TestFn, MiscompiledFunctions)) { // Okay, we extracted some blocks and the problem still appears. See if we // can eliminate some of the created functions from being candidates. // Block extraction can introduce functions with the same name (foo_code). // Make sure to disambiguate the symbols so that when the program is split // apart that we can link it back together again. DisambiguateGlobalSymbols(BD.getProgram()); // Do the reduction... ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); outs() << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") << " being miscompiled: "; PrintFunctionList(MiscompiledFunctions); outs() << '\n'; } return MiscompiledFunctions; }