1193323Sed//===-- FindBugs.cpp - Run Many Different Optimizations -------------------===//
2193323Sed//
3193323Sed//                     The LLVM Compiler Infrastructure
4193323Sed//
5193323Sed// This file is distributed under the University of Illinois Open Source
6193323Sed// License. See LICENSE.TXT for details.
7193323Sed//
8193323Sed//===----------------------------------------------------------------------===//
9193323Sed//
10193323Sed// This file defines an interface that allows bugpoint to choose different
11193323Sed// combinations of optimizations to run on the selected input. Bugpoint will
12193323Sed// run these optimizations and record the success/failure of each. This way
13193323Sed// we can hopefully spot bugs in the optimizations.
14193323Sed//
15193323Sed//===----------------------------------------------------------------------===//
16193323Sed
17193323Sed#include "BugDriver.h"
18193323Sed#include "ToolRunner.h"
19193323Sed#include "llvm/Pass.h"
20263508Sdim#include "llvm/Support/FileSystem.h"
21198090Srdivacky#include "llvm/Support/raw_ostream.h"
22193323Sed#include <algorithm>
23193323Sed#include <ctime>
24193323Sedusing namespace llvm;
25193323Sed
26193323Sed/// runManyPasses - Take the specified pass list and create different
27193323Sed/// combinations of passes to compile the program with. Compile the program with
28193323Sed/// each set and mark test to see if it compiled correctly. If the passes
29193323Sed/// compiled correctly output nothing and rearrange the passes into a new order.
30193323Sed/// If the passes did not compile correctly, output the command required to
31193323Sed/// recreate the failure. This returns true if a compiler error is found.
32193323Sed///
33212793Sdimbool BugDriver::runManyPasses(const std::vector<std::string> &AllPasses,
34207618Srdivacky                              std::string &ErrMsg) {
35193323Sed  setPassesToRun(AllPasses);
36198090Srdivacky  outs() << "Starting bug finding procedure...\n\n";
37193323Sed
38193323Sed  // Creating a reference output if necessary
39193323Sed  if (initializeExecutionEnvironment()) return false;
40193323Sed
41198090Srdivacky  outs() << "\n";
42193323Sed  if (ReferenceOutputFile.empty()) {
43198090Srdivacky    outs() << "Generating reference output from raw program: \n";
44193323Sed    if (!createReferenceFile(Program))
45193323Sed      return false;
46193323Sed  }
47193323Sed
48193323Sed  srand(time(NULL));
49193323Sed
50193323Sed  unsigned num = 1;
51193323Sed  while(1) {
52193323Sed    //
53193323Sed    // Step 1: Randomize the order of the optimizer passes.
54193323Sed    //
55193323Sed    std::random_shuffle(PassesToRun.begin(), PassesToRun.end());
56193323Sed
57193323Sed    //
58193323Sed    // Step 2: Run optimizer passes on the program and check for success.
59193323Sed    //
60198090Srdivacky    outs() << "Running selected passes on program to test for crash: ";
61193323Sed    for(int i = 0, e = PassesToRun.size(); i != e; i++) {
62212793Sdim      outs() << "-" << PassesToRun[i] << " ";
63193323Sed    }
64193323Sed
65193323Sed    std::string Filename;
66212793Sdim    if(runPasses(Program, PassesToRun, Filename, false)) {
67198090Srdivacky      outs() << "\n";
68198090Srdivacky      outs() << "Optimizer passes caused failure!\n\n";
69193323Sed      debugOptimizerCrash();
70193323Sed      return true;
71193323Sed    } else {
72198090Srdivacky      outs() << "Combination " << num << " optimized successfully!\n";
73193323Sed    }
74193323Sed
75193323Sed    //
76193323Sed    // Step 3: Compile the optimized code.
77193323Sed    //
78198090Srdivacky    outs() << "Running the code generator to test for a crash: ";
79207618Srdivacky    std::string Error;
80207618Srdivacky    compileProgram(Program, &Error);
81207618Srdivacky    if (!Error.empty()) {
82198090Srdivacky      outs() << "\n*** compileProgram threw an exception: ";
83207618Srdivacky      outs() << Error;
84207618Srdivacky      return debugCodeGeneratorCrash(ErrMsg);
85193323Sed    }
86207618Srdivacky    outs() << '\n';
87193323Sed
88193323Sed    //
89193323Sed    // Step 4: Run the program and compare its output to the reference
90193323Sed    // output (created above).
91193323Sed    //
92198090Srdivacky    outs() << "*** Checking if passes caused miscompliation:\n";
93212793Sdim    bool Diff = diffProgram(Program, Filename, "", false, &Error);
94207618Srdivacky    if (Error.empty() && Diff) {
95207618Srdivacky      outs() << "\n*** diffProgram returned true!\n";
96207618Srdivacky      debugMiscompilation(&Error);
97207618Srdivacky      if (Error.empty())
98193323Sed        return true;
99207618Srdivacky    }
100207618Srdivacky    if (!Error.empty()) {
101207618Srdivacky      errs() << Error;
102207618Srdivacky      debugCodeGeneratorCrash(ErrMsg);
103193323Sed      return true;
104193323Sed    }
105207618Srdivacky    outs() << "\n*** diff'd output matches!\n";
106193323Sed
107263508Sdim    sys::fs::remove(Filename);
108193323Sed
109198090Srdivacky    outs() << "\n\n";
110193323Sed    num++;
111193323Sed  } //end while
112193323Sed
113193323Sed  // Unreachable.
114193323Sed}
115