New files for miscompilation detection


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@5120 91177308-0d34-0410-b5e6-96231b3b80d8
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;
+}