aboutsummaryrefslogtreecommitdiffstats
path: root/tools/bugpoint/Miscompilation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/bugpoint/Miscompilation.cpp')
-rw-r--r--tools/bugpoint/Miscompilation.cpp141
1 files changed, 141 insertions, 0 deletions
diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp
new file mode 100644
index 0000000..3cccffe
--- /dev/null
+++ b/tools/bugpoint/Miscompilation.cpp
@@ -0,0 +1,141 @@
+//===- Miscompilation.cpp - Debug program miscompilations -----------------===//
+//
+// This file implements program miscompilation debugging support.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BugDriver.h"
+#include "SystemUtils.h"
+#include "llvm/Pass.h"
+#include "llvm/Module.h"
+#include "Support/CommandLine.h"
+
+// Anonymous namespace to define command line options for miscompilation
+// debugging.
+//
+namespace {
+ // Output - The user can specify a file containing the expected output of the
+ // program. If this filename is set, it is used as the reference diff source,
+ // otherwise the raw input run through an interpreter is used as the reference
+ // source.
+ //
+ cl::opt<std::string>
+ Output("output", cl::desc("Specify a reference program output "
+ "(for miscompilation detection)"));
+}
+
+/// debugMiscompilation - This method is used when the passes selected are not
+/// crashing, but the generated output is semantically different from the
+/// input.
+///
+bool BugDriver::debugMiscompilation() {
+ std::cout << "*** Debugging miscompilation!\n";
+
+ // Set up the execution environment, selecting a method to run LLVM bytecode.
+ if (initializeExecutionEnvironment()) return true;
+
+ // Run the raw input to see where we are coming from. If a reference output
+ // was specified, make sure that the raw output matches it. If not, it's a
+ // problem in the front-end or whatever produced the input code.
+ //
+ bool CreatedOutput = false;
+ if (Output.empty()) {
+ std::cout << "Generating reference output from raw program...";
+ Output = executeProgram("bugpoint.reference.out");
+ CreatedOutput = true;
+ std::cout << " done!\n";
+ } else if (diffProgram(Output)) {
+ std::cout << "\n*** Input program does not match reference diff!\n"
+ << " Must be problem with input source!\n";
+ return false; // Problem found
+ }
+
+ // Figure out which transformation is the first to miscompile the input
+ // program. We do a binary search here in case there are a large number of
+ // passes involved.
+ //
+ unsigned LastGood = 0, LastBad = PassesToRun.size();
+ while (LastGood != LastBad) {
+ unsigned Mid = (LastBad+LastGood+1) / 2;
+ std::vector<const PassInfo*> P(PassesToRun.begin(),
+ PassesToRun.begin()+Mid);
+ std::cout << "Checking to see if the first " << Mid << " passes are ok: ";
+
+ std::string BytecodeResult;
+ if (runPasses(P, BytecodeResult, false, true)) {
+ std::cerr << ToolName << ": Error running this sequence of passes"
+ << " on the input program!\n";
+ exit(1);
+ }
+
+ // Check to see if the finished program matches the reference output...
+ if (diffProgram(Output, BytecodeResult)) {
+ std::cout << "nope.\n";
+ LastBad = Mid-1; // Miscompilation detected!
+ } else {
+ std::cout << "yup.\n";
+ LastGood = Mid; // No miscompilation!
+ }
+
+ // We are now done with the optimized output... so remove it.
+ removeFile(BytecodeResult);
+ }
+
+ // Make sure something was miscompiled...
+ if (LastBad >= PassesToRun.size()) {
+ std::cerr << "*** Optimized program matches reference output! No problem "
+ << "detected...\nbugpoint can't help you with your problem!\n";
+ return false;
+ }
+
+ // Calculate which pass it is that miscompiles...
+ const PassInfo *ThePass = PassesToRun[LastBad];
+
+ std::cout << "\n*** Found miscompiling pass '-" << ThePass->getPassArgument()
+ << "': " << ThePass->getPassName() << "\n";
+
+ if (LastGood != 0) {
+ std::vector<const PassInfo*> P(PassesToRun.begin(),
+ PassesToRun.begin()+LastGood);
+ std::string Filename;
+ std::cout << "Running good passes to get input for pass:";
+ if (runPasses(P, Filename, false, true)) {
+ std::cerr << "ERROR: Running the first " << LastGood
+ << " passes crashed!\n";
+ return true;
+ }
+ std::cout << " done!\n";
+
+ // Assuming everything was successful, we now have a valid bytecode file in
+ // OutputName. Use it for "Program" Instead.
+ delete Program;
+ Program = ParseInputFile(Filename);
+
+ // Delete the file now.
+ removeFile(Filename);
+ }
+
+ bool Result = debugPassMiscompilation(ThePass, Output);
+
+ if (CreatedOutput) removeFile(Output);
+ return Result;
+}
+
+/// debugPassMiscompilation - This method is called when the specified pass
+/// miscompiles Program as input. It tries to reduce the testcase to something
+/// that smaller that still miscompiles the program. ReferenceOutput contains
+/// the filename of the file containing the output we are to match.
+///
+bool BugDriver::debugPassMiscompilation(const PassInfo *Pass,
+ const std::string &ReferenceOutput) {
+ EmitProgressBytecode(Pass, "passinput");
+
+ // Loop over all of the functions in the program, attempting to find one that
+ // is being miscompiled. We do this by extracting the function into a module,
+ // running the "bad" optimization on that module, then linking it back into
+ // the program. If the program fails the diff, the function got misoptimized.
+ //
+
+
+ return false;
+}