1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
//===- CrashDebugger.cpp - Debug compilation crashes ----------------------===//
//
// This file defines the bugpoint internals that narrow down compilation crashes
//
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
#include "SystemUtils.h"
#include "llvm/Module.h"
#include "llvm/Bytecode/Writer.h"
#include "llvm/Pass.h"
#include <fstream>
/// debugCrash - This method is called when some pass crashes on input. It
/// attempts to prune down the testcase to something reasonable, and figure
/// out exactly which pass is crashing.
///
bool BugDriver::debugCrash() {
std::cout << "\n*** Debugging optimizer crash!\n";
// Determine which pass causes the optimizer to crash... using binary search
unsigned LastToPass = 0, LastToCrash = PassesToRun.size();
while (LastToPass != LastToCrash) {
unsigned Mid = (LastToCrash+LastToPass+1) / 2;
std::vector<const PassInfo*> P(PassesToRun.begin(),
PassesToRun.begin()+Mid);
std::cout << "Checking to see if the first " << Mid << " passes crash: ";
if (runPasses(P))
LastToCrash = Mid-1;
else
LastToPass = Mid;
}
// Make sure something crashed. :)
if (LastToCrash >= PassesToRun.size()) {
std::cerr << "ERROR: No passes crashed!\n";
return true;
}
// Calculate which pass it is that crashes...
const PassInfo *CrashingPass = PassesToRun[LastToCrash];
std::cout << "\n*** Found crashing pass '-" << CrashingPass->getPassArgument()
<< "': " << CrashingPass->getPassName() << "\n";
// Compile the program with just the passes that don't crash.
if (LastToPass != 0) { // Don't bother doing this if the first pass crashes...
std::vector<const PassInfo*> P(PassesToRun.begin(),
PassesToRun.begin()+LastToPass);
std::string Filename;
std::cout << "Running passes that don't crash to get input for pass: ";
if (runPasses(P, Filename)) {
std::cerr << "ERROR: Running the first " << LastToPass
<< " passes crashed this time!\n";
return true;
}
// 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);
}
return debugPassCrash(CrashingPass);
}
/// CountFunctions - return the number of non-external functions defined in the
/// module.
static unsigned CountFunctions(Module *M) {
unsigned N = 0;
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
if (!I->isExternal())
++N;
return N;
}
/// debugPassCrash - This method is called when the specified pass crashes on
/// Program as input. It tries to reduce the testcase to something that still
/// crashes, but it smaller.
///
bool BugDriver::debugPassCrash(const PassInfo *Pass) {
EmitProgressBytecode(Pass, "passinput");
bool Reduced = false, AnyReduction = false;
if (CountFunctions(Program) > 1) {
// Attempt to reduce the input program down to a single function that still
// crashes. Do this by removing everything except for that one function...
//
std::cout << "\n*** Attempting to reduce the testcase to one function\n";
for (Module::iterator I = Program->begin(), E = Program->end(); I != E; ++I)
if (!I->isExternal()) {
// Extract one function from the module...
Module *M = extractFunctionFromModule(I);
// Make the function the current program...
std::swap(Program, M);
// Find out if the pass still crashes on this pass...
std::cout << "Checking function '" << I->getName() << "': ";
if (runPass(Pass)) {
// Yup, it does, we delete the old module, and continue trying to
// reduce the testcase...
delete M;
Reduced = AnyReduction = true;
break;
}
// This pass didn't crash on this function, try the next one.
delete Program;
Program = M;
}
if (CountFunctions(Program) > 1) {
std::cout << "\n*** Couldn't reduce testcase to one function.\n"
<< " Attempting to remove individual functions.\n";
std::cout << "XXX Individual function removal unimplemented!\n";
}
}
if (Reduced) {
EmitProgressBytecode(Pass, "reduced-function");
Reduced = false;
}
// FIXME: This should attempt to delete entire basic blocks at a time to speed
// up convergence...
unsigned Simplification = 4;
do {
--Simplification;
std::cout << "\n*** Attempting to reduce testcase by deleting instruc"
<< "tions: Simplification Level #" << Simplification << "\n";
// Now that we have deleted the functions that are unneccesary for the
// program, try to remove instructions that are not neccesary to cause the
// crash. To do this, we loop through all of the instructions in the
// remaining functions, deleting them (replacing any values produced with
// nulls), and then running ADCE and SimplifyCFG. If the transformed input
// still triggers failure, keep deleting until we cannot trigger failure
// anymore.
//
TryAgain:
// Loop over all of the (non-terminator) instructions remaining in the
// function, attempting to delete them.
for (Module::iterator FI = Program->begin(), E = Program->end();
FI != E; ++FI)
if (!FI->isExternal()) {
for (Function::iterator BI = FI->begin(), E = FI->end(); BI != E; ++BI)
for (BasicBlock::iterator I = BI->begin(), E = --BI->end();
I != E; ++I) {
Module *M = deleteInstructionFromProgram(I, Simplification);
// Make the function the current program...
std::swap(Program, M);
// Find out if the pass still crashes on this pass...
std::cout << "Checking instruction '" << I->getName() << "': ";
if (runPass(Pass)) {
// Yup, it does, we delete the old module, and continue trying to
// reduce the testcase...
delete M;
Reduced = AnyReduction = true;
goto TryAgain; // I wish I had a multi-level break here!
}
// This pass didn't crash without this instruction, try the next
// one.
delete Program;
Program = M;
}
}
} while (Simplification);
// Try to clean up the testcase by running funcresolve and globaldce...
if (AnyReduction) {
std::cout << "\n*** Attempting to perform final cleanups: ";
Module *M = performFinalCleanups();
std::swap(Program, M);
// Find out if the pass still crashes on the cleaned up program...
if (runPass(Pass)) {
// Yup, it does, keep the reduced version...
delete M;
Reduced = AnyReduction = true;
} else {
delete Program; // Otherwise, restore the original module...
Program = M;
}
}
if (Reduced) {
EmitProgressBytecode(Pass, "reduced-simplified");
Reduced = false;
}
return false;
}
|