blob: 500af49a167ec087dfb26e18215d925dd26a694c [file] [log] [blame]
Chris Lattner4a106452002-12-23 23:50:16 +00001//===- 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//
16namespace {
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///
31bool 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;
Chris Lattnereea21dd2003-04-23 20:41:18 +000046 std::cout << " done! Reference output is: bugpoint.reference.out.\n";
Chris Lattner4a106452002-12-23 23:50:16 +000047 } 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///
129bool 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}