/// TestMergedProgram - Given two modules, link them together and run the /// program, checking to see if the program matches the diff. If the diff /// matches, return false, otherwise return true. If the DeleteInputs argument /// is set to true then this function deletes both input modules before it /// returns. /// static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, bool DeleteInputs, std::string &Error) { // Link the two portions of the program back to together. std::string ErrorMsg; if (!DeleteInputs) { M1 = CloneModule(M1); M2 = CloneModule(M2); } if (Linker::LinkModules(M1, M2, &ErrorMsg)) { errs() << BD.getToolName() << ": Error linking modules together:" << ErrorMsg << '\n'; exit(1); } delete M2; // We are done with this module. OwningPtr<Module> OldProgram(BD.swapProgramIn(M1)); // Execute the program. If it does not match the expected output, we must // return true. bool Broken = BD.diffProgram("", "", false, &Error); if (!Error.empty()) { // Delete the linked module & restore the original delete BD.swapProgramIn(OldProgram.take()); } return Broken; }
/// TestOptimizer - This is the predicate function used to check to see if the /// "Test" portion of the program is misoptimized. If so, return true. In any /// case, both module arguments are deleted. /// static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe, std::string &Error) { // Run the optimization passes on ToOptimize, producing a transformed version // of the functions being tested. outs() << " Optimizing functions being tested: "; Module *Optimized = BD.runPassesOn(Test, BD.getPassesToRun(), /*AutoDebugCrashes*/true); outs() << "done.\n"; delete Test; outs() << " Checking to see if the merged program executes correctly: "; bool Broken; Module *New = TestMergedProgram(BD, Optimized, Safe, true, Error, Broken); if (New) { outs() << (Broken ? " nope.\n" : " yup.\n"); // Delete the original and set the new program. delete BD.swapProgramIn(New); } return Broken; }
/// This is the predicate function used to check to see if the "Test" portion of /// the program is misoptimized. If so, return true. In any case, both module /// arguments are deleted. /// static bool TestOptimizer(BugDriver &BD, std::unique_ptr<Module> Test, std::unique_ptr<Module> Safe, std::string &Error) { // Run the optimization passes on ToOptimize, producing a transformed version // of the functions being tested. outs() << " Optimizing functions being tested: "; std::unique_ptr<Module> Optimized = BD.runPassesOn(Test.get(), BD.getPassesToRun(), /*AutoDebugCrashes*/ true); outs() << "done.\n"; outs() << " Checking to see if the merged program executes correctly: "; bool Broken; std::unique_ptr<Module> New = testMergedProgram( BD, std::move(Optimized), std::move(Safe), Error, Broken); if (New) { outs() << (Broken ? " nope.\n" : " yup.\n"); // Delete the original and set the new program. delete BD.swapProgramIn(New.release()); } return Broken; }
/// 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; ValueToValueMapTy VMap; Module *ToNotOptimize = CloneModule(BD.getProgram(), VMap); Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, MiscompiledFunctions, VMap); Module *ToOptimizeLoopExtracted = BD.extractLoop(ToOptimize).release(); 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; Module *New = TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, false, Error, Failure); if (!New) return false; // Delete the original and set the new program. Module *Old = BD.swapProgramIn(New); for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]); delete Old; 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; 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, VMap); Module *TNOBackup = CloneModule(ToNotOptimize, VMap); for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]); Failure = TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize, Error); if (!Error.empty()) return false; ToOptimizeLoopExtracted = TOLEBackup; ToNotOptimize = TNOBackup; 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. std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions; for (Function *F : MiscompiledFunctions) { MisCompFunctions.emplace_back(F->getName(), F->getFunctionType()); } if (Linker::linkModules(*ToNotOptimize, *ToOptimizeLoopExtracted, diagnosticHandler)) exit(1); MiscompiledFunctions.clear(); for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { Function *NewF = ToNotOptimize->getFunction(MisCompFunctions[i].first); assert(NewF && "Function not found??"); MiscompiledFunctions.push_back(NewF); } delete ToOptimizeLoopExtracted; BD.setNewProgram(ToNotOptimize); return MadeChange; } outs() << "*** Loop extraction successful!\n"; std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions; for (Module::iterator I = ToOptimizeLoopExtracted->begin(), E = ToOptimizeLoopExtracted->end(); I != E; ++I) if (!I->isDeclaration()) MisCompFunctions.emplace_back(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. if (Linker::linkModules(*ToNotOptimize, *ToOptimizeLoopExtracted, diagnosticHandler)) 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??"); MiscompiledFunctions.push_back(NewF); } BD.setNewProgram(ToNotOptimize); MadeChange = true; } }