This commit adds a new feature called find-bugs. The find-bugs option can be invoked...
authorPatrick Jenkins <pjenkins@apple.com>
Tue, 15 Aug 2006 16:40:49 +0000 (16:40 +0000)
committerPatrick Jenkins <pjenkins@apple.com>
Tue, 15 Aug 2006 16:40:49 +0000 (16:40 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@29703 91177308-0d34-0410-b5e6-96231b3b80d8

tools/bugpoint/BugDriver.cpp
tools/bugpoint/BugDriver.h
tools/bugpoint/CrashDebugger.cpp
tools/bugpoint/ExecutionDriver.cpp
tools/bugpoint/bugpoint.cpp

index f8beb2a64c2ed7d25e946193688c3d081148d4fd..9d82e8b3ccbbd706acef275e7906b2feb4c747fc 100644 (file)
@@ -62,10 +62,11 @@ std::string llvm::getPassesString(const std::vector<const PassInfo*> &Passes) {
   return Result;
 }
 
-BugDriver::BugDriver(const char *toolname, bool as_child, unsigned timeout)
+BugDriver::BugDriver(const char *toolname, bool as_child, bool find_bugs,
+                     unsigned timeout)
   : ToolName(toolname), ReferenceOutputFile(OutputFile),
     Program(0), Interpreter(0), cbe(0), gcc(0), run_as_child(as_child),
-    Timeout(timeout) {}
+    run_find_bugs(find_bugs), Timeout(timeout) {}
 
 
 /// ParseInputFile - Given a bytecode or assembly input filename, parse and
@@ -140,6 +141,12 @@ bool BugDriver::run() {
     // Execute the passes
     return runPassesAsChild(PassesToRun);
   }
+  
+  if (run_find_bugs) {
+    // Rearrange the passes and apply them to the program. Repeat this process
+    // until the user kills the program or we find a bug.
+    return runManyPasses(PassesToRun);
+  }
 
   // If we're not running as a child, the first thing that we must do is 
   // determine what the problem is. Does the optimization series crash the 
@@ -175,20 +182,10 @@ bool BugDriver::run() {
   bool CreatedOutput = false;
   if (ReferenceOutputFile.empty()) {
     std::cout << "Generating reference output from raw program: ";
-    try {
-      ReferenceOutputFile = executeProgramWithCBE("bugpoint.reference.out");
-      CreatedOutput = true;
-      std::cout << "Reference output is: " << ReferenceOutputFile << '\n';
-    } catch (ToolExecutionError &TEE) {
-      std::cerr << TEE.what();
-      if (Interpreter != cbe) {
-        std::cerr << "*** There is a bug running the C backend.  Either debug"
-                  << " it (use the -run-cbe bugpoint option), or fix the error"
-                  << " some other way.\n";
-        return 1;
-      }
-      return debugCodeGeneratorCrash();
+    if(!createReferenceFile(Program)){
+       return debugCodeGeneratorCrash();
     }
+    CreatedOutput = true;
   }
 
   // Make sure the reference output file gets deleted on exit from this
@@ -197,7 +194,8 @@ bool BugDriver::run() {
   FileRemover RemoverInstance(ROF, CreatedOutput);
 
   // Diff the output of the raw program against the reference output.  If it
-  // matches, then we have a miscompilation bug.
+  // matches, then we assume there is a miscompilation bug and try to 
+  // diagnose it.
   std::cout << "*** Checking the code generator...\n";
   try {
     if (!diffProgram()) {
index ec687b3c7bc0efb343927e1ae27a02fa95e5c7a7..ced7df81bafbdac16e2d4e3baa0a93a50e5b8997 100644 (file)
@@ -48,6 +48,7 @@ class BugDriver {
   CBE *cbe;
   GCC *gcc;
   bool run_as_child;
+  bool run_find_bugs;
   unsigned Timeout;
 
   // FIXME: sort out public/private distinctions...
@@ -55,7 +56,8 @@ class BugDriver {
   friend class ReduceMisCodegenFunctions;
 
 public:
-  BugDriver(const char *toolname, bool as_child, unsigned timeout);
+  BugDriver(const char *toolname, bool as_child, bool find_bugs,
+            unsigned timeout);
 
   const std::string &getToolName() const { return ToolName; }
 
@@ -82,7 +84,7 @@ public:
   /// crashes on input.  It attempts to prune down the testcase to something
   /// reasonable, and figure out exactly which pass is crashing.
   ///
-  bool debugOptimizerCrash();
+  bool debugOptimizerCrash(const std::string &ID = "passes");
 
   /// debugCodeGeneratorCrash - This method is called when the code generator
   /// crashes on an input.  It attempts to reduce the input as much as possible
@@ -175,6 +177,13 @@ public:
   ///
   std::string executeProgramWithCBE(std::string OutputFile = "");
 
+  /// createReferenceFile - calls compileProgram and then records the output
+  /// into ReferenceOutputFile. Returns true if reference file created, false 
+  /// otherwise. Note: initializeExecutionEnvironment should be called BEFORE
+  /// this function.
+  ///
+  bool createReferenceFile(Module *M, const std::string &Filename  = "bugpoint.reference.out");
+
   /// diffProgram - This method executes the specified module and diffs the
   /// output against the file specified by ReferenceOutputFile.  If the output
   /// is different, true is returned.  If there is a problem with the code
@@ -183,6 +192,7 @@ public:
   bool diffProgram(const std::string &BytecodeFile = "",
                    const std::string &SharedObj = "",
                    bool RemoveBytecode = false);
+                   
   /// EmitProgressBytecode - This function is used to output the current Program
   /// to a file named "bugpoint-ID.bc".
   ///
@@ -235,6 +245,15 @@ public:
   bool runPasses(const std::vector<const PassInfo*> &PassesToRun,
                  std::string &OutputFilename, bool DeleteOutput = false,
                  bool Quiet = false) const;
+                 
+  /// runManyPasses - Take the specified pass list and create different 
+  /// combinations of passes to compile the program with. Compile the program with
+  /// each set and mark test to see if it compiled correctly. If the passes 
+  /// compiled correctly output nothing and rearrange the passes into a new order.
+  /// If the passes did not compile correctly, output the command required to 
+  /// recreate the failure. This returns true if a compiler error is found.
+  ///
+  bool runManyPasses(const std::vector<const PassInfo*> &AllPasses);
 
   /// writeProgramToFile - This writes the current "Program" to the named
   /// bytecode file.  If an error occurs, true is returned.
index 2e2ab20fa04dff191d1a9d5d8931bf0973c4ae73..63926464e23d272d5faf1b391de0d2441c7411c9 100644 (file)
@@ -423,7 +423,7 @@ static bool TestForOptimizerCrash(BugDriver &BD, Module *M) {
 /// It attempts to prune down the testcase to something reasonable, and figure
 /// out exactly which pass is crashing.
 ///
-bool BugDriver::debugOptimizerCrash() {
+bool BugDriver::debugOptimizerCrash(const std::string &ID) {
   std::cout << "\n*** Debugging optimizer crash!\n";
 
   // Reduce the list of passes which causes the optimizer to crash...
@@ -435,7 +435,7 @@ bool BugDriver::debugOptimizerCrash() {
             << (PassesToRun.size() == 1 ? ": " : "es: ")
             << getPassesString(PassesToRun) << '\n';
 
-  EmitProgressBytecode("passinput");
+  EmitProgressBytecode(ID);
 
   return DebugACrash(*this, TestForOptimizerCrash);
 }
index 453833eb8dff9a12b27537aa49857f28e60be809..93eef5dbc565b278ad2dadd63a58841d78daf936 100644 (file)
@@ -297,10 +297,36 @@ std::string BugDriver::compileSharedObject(const std::string &BytecodeFile) {
   return "./" + SharedObjectFile;
 }
 
+/// createReferenceFile - calls compileProgram and then records the output
+/// into ReferenceOutputFile. Returns true if reference file created, false 
+/// otherwise. Note: initializeExecutionEnvironment should be called BEFORE
+/// this function.
+///
+bool BugDriver::createReferenceFile(Module *M, const std::string &Filename){
+  try {
+    compileProgram(Program);
+  } catch (ToolExecutionError &TEE) {
+    return false;
+  }
+  try {
+    ReferenceOutputFile = executeProgramWithCBE(Filename);
+    std::cout << "Reference output is: " << ReferenceOutputFile << "\n\n";
+  } catch (ToolExecutionError &TEE) {
+    std::cerr << TEE.what();
+    if (Interpreter != cbe) {
+      std::cerr << "*** There is a bug running the C backend.  Either debug"
+                << " it (use the -run-cbe bugpoint option), or fix the error"
+                << " some other way.\n";
+    }
+    return false;
+  }
+  return true;
+}
 
-/// diffProgram - This method executes the specified module and diffs the output
-/// against the file specified by ReferenceOutputFile.  If the output is
-/// different, true is returned.
+/// diffProgram - This method executes the specified module and diffs the
+/// output against the file specified by ReferenceOutputFile.  If the output
+/// is different, true is returned.  If there is a problem with the code
+/// generator (e.g., llc crashes), this will throw an exception.
 ///
 bool BugDriver::diffProgram(const std::string &BytecodeFile,
                             const std::string &SharedObject,
index cc05fea65086e936ed306d640aa28496a021ba5e..353e117369a1b9994d75bcc6161a3f3a6e6a18fc 100644 (file)
@@ -29,8 +29,12 @@ using namespace llvm;
 // from a parent process. It is not intended to be used by users so the 
 // option is hidden.
 static cl::opt<bool> 
-  AsChild("as-child", cl::desc("Run bugpoint as child process"), 
-          cl::ReallyHidden);
+AsChild("as-child", cl::desc("Run bugpoint as child process"), 
+        cl::ReallyHidden);
+          
+static cl::opt<bool> 
+FindBugs("find-bugs", cl::desc("Run many different optimization sequences"
+                               "on program to find bugs"), cl::init(false));
 
 static cl::list<std::string>
 InputFilenames(cl::Positional, cl::OneOrMore,
@@ -62,7 +66,7 @@ int main(int argc, char **argv) {
   sys::PrintStackTraceOnErrorSignal();
   sys::SetInterruptFunction(BugpointInterruptFunction);
   
-  BugDriver D(argv[0],AsChild,TimeoutValue);
+  BugDriver D(argv[0],AsChild,FindBugs,TimeoutValue);
   if (D.addSources(InputFilenames)) return 1;
   D.addPasses(PassList.begin(), PassList.end());