Ejemplo n.º 1
0
/// 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;
}
Ejemplo n.º 2
0
/// 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;
}
Ejemplo n.º 3
0
/// 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;
}
Ejemplo n.º 4
0
/// 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;
    }
}