3cccffe10c11d9d95db70184c5444772c43972d2
[oota-llvm.git] / tools / bugpoint / Miscompilation.cpp
1 //===- Miscompilation.cpp - Debug program miscompilations -----------------===//
2 //
3 // This file implements program miscompilation debugging support.
4 //
5 //===----------------------------------------------------------------------===//
6
7 #include "BugDriver.h"
8 #include "SystemUtils.h"
9 #include "llvm/Pass.h"
10 #include "llvm/Module.h"
11 #include "Support/CommandLine.h"
12
13 // Anonymous namespace to define command line options for miscompilation
14 // debugging.
15 //
16 namespace {
17   // Output - The user can specify a file containing the expected output of the
18   // program.  If this filename is set, it is used as the reference diff source,
19   // otherwise the raw input run through an interpreter is used as the reference
20   // source.
21   //
22   cl::opt<std::string> 
23   Output("output", cl::desc("Specify a reference program output "
24                             "(for miscompilation detection)"));
25 }
26
27 /// debugMiscompilation - This method is used when the passes selected are not
28 /// crashing, but the generated output is semantically different from the
29 /// input.
30 ///
31 bool BugDriver::debugMiscompilation() {
32   std::cout << "*** Debugging miscompilation!\n";
33
34   // Set up the execution environment, selecting a method to run LLVM bytecode.
35   if (initializeExecutionEnvironment()) return true;
36
37   // Run the raw input to see where we are coming from.  If a reference output
38   // was specified, make sure that the raw output matches it.  If not, it's a
39   // problem in the front-end or whatever produced the input code.
40   //
41   bool CreatedOutput = false;
42   if (Output.empty()) {
43     std::cout << "Generating reference output from raw program...";
44     Output = executeProgram("bugpoint.reference.out");
45     CreatedOutput = true;
46     std::cout << " done!\n";
47   } else if (diffProgram(Output)) {
48     std::cout << "\n*** Input program does not match reference diff!\n"
49               << "    Must be problem with input source!\n";
50     return false;  // Problem found
51   }
52
53   // Figure out which transformation is the first to miscompile the input
54   // program.  We do a binary search here in case there are a large number of
55   // passes involved.
56   //
57   unsigned LastGood = 0, LastBad = PassesToRun.size();
58   while (LastGood != LastBad) {
59     unsigned Mid = (LastBad+LastGood+1) / 2;
60     std::vector<const PassInfo*> P(PassesToRun.begin(),
61                                    PassesToRun.begin()+Mid);
62     std::cout << "Checking to see if the first " << Mid << " passes are ok: ";
63
64     std::string BytecodeResult;
65     if (runPasses(P, BytecodeResult, false, true)) {
66       std::cerr << ToolName << ": Error running this sequence of passes"
67                 << " on the input program!\n";
68       exit(1);
69     }
70
71     // Check to see if the finished program matches the reference output...
72     if (diffProgram(Output, BytecodeResult)) {
73       std::cout << "nope.\n";
74       LastBad = Mid-1;    // Miscompilation detected!
75     } else {
76       std::cout << "yup.\n";
77       LastGood = Mid;     // No miscompilation!
78     }
79
80     // We are now done with the optimized output... so remove it.
81     removeFile(BytecodeResult);
82   }
83
84   // Make sure something was miscompiled...
85   if (LastBad >= PassesToRun.size()) {
86     std::cerr << "*** Optimized program matches reference output!  No problem "
87               << "detected...\nbugpoint can't help you with your problem!\n";
88     return false;
89   }
90
91   // Calculate which pass it is that miscompiles...
92   const PassInfo *ThePass = PassesToRun[LastBad];
93   
94   std::cout << "\n*** Found miscompiling pass '-" << ThePass->getPassArgument()
95             << "': " << ThePass->getPassName() << "\n";
96   
97   if (LastGood != 0) {
98     std::vector<const PassInfo*> P(PassesToRun.begin(), 
99                                    PassesToRun.begin()+LastGood);
100     std::string Filename;
101     std::cout << "Running good passes to get input for pass:";
102     if (runPasses(P, Filename, false, true)) {
103       std::cerr << "ERROR: Running the first " << LastGood
104                 << " passes crashed!\n";
105       return true;
106     }
107     std::cout << " done!\n";
108     
109     // Assuming everything was successful, we now have a valid bytecode file in
110     // OutputName.  Use it for "Program" Instead.
111     delete Program;
112     Program = ParseInputFile(Filename);
113     
114     // Delete the file now.
115     removeFile(Filename);
116   }
117
118   bool Result = debugPassMiscompilation(ThePass, Output);
119
120   if (CreatedOutput) removeFile(Output);
121   return Result;
122 }
123
124 /// debugPassMiscompilation - This method is called when the specified pass
125 /// miscompiles Program as input.  It tries to reduce the testcase to something
126 /// that smaller that still miscompiles the program.  ReferenceOutput contains
127 /// the filename of the file containing the output we are to match.
128 ///
129 bool BugDriver::debugPassMiscompilation(const PassInfo *Pass,
130                                         const std::string &ReferenceOutput) {
131   EmitProgressBytecode(Pass, "passinput");
132
133   // Loop over all of the functions in the program, attempting to find one that
134   // is being miscompiled.  We do this by extracting the function into a module,
135   // running the "bad" optimization on that module, then linking it back into
136   // the program.  If the program fails the diff, the function got misoptimized.
137   //
138
139
140   return false;
141 }