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
|
//===- BugDriver.h - Top-Level BugPoint class -------------------*- C++ -*-===//
//
// This class contains all of the shared state and information that is used by
// the BugPoint tool to track down errors in optimizations. This class is the
// main driver class that invokes all sub-functionality.
//
//===----------------------------------------------------------------------===//
#ifndef BUGDRIVER_H
#define BUGDRIVER_H
#include <vector>
#include <string>
class PassInfo;
class Module;
class Function;
class AbstractInterpreter;
class Instruction;
class DebugCrashes;
class ReduceMiscompilingPasses;
class ReduceMiscompilingFunctions;
class ReduceCrashingFunctions;
class ReduceCrashingBlocks;
class CBE;
class GCC;
class BugDriver {
const std::string ToolName; // Name of bugpoint
std::string ReferenceOutputFile; // Name of `good' output file
Module *Program; // The raw program, linked together
std::vector<const PassInfo*> PassesToRun;
AbstractInterpreter *Interpreter; // How to run the program
CBE *cbe;
GCC *gcc;
// FIXME: sort out public/private distinctions...
friend class DebugCrashes;
friend class ReduceMiscompilingPasses;
friend class ReduceMiscompilingFunctions;
friend class ReduceMisCodegenFunctions;
friend class ReduceCrashingFunctions;
friend class ReduceCrashingBlocks;
public:
BugDriver(const char *toolname);
const std::string &getToolName() const { return ToolName; }
// Set up methods... these methods are used to copy information about the
// command line arguments into instance variables of BugDriver.
//
bool addSources(const std::vector<std::string> &FileNames);
template<class It>
void addPasses(It I, It E) { PassesToRun.insert(PassesToRun.end(), I, E); }
/// run - The top level method that is invoked after all of the instance
/// variables are set up from command line arguments.
///
bool run();
/// 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 debugCrash();
/// debugMiscompilation - This method is used when the passes selected are not
/// crashing, but the generated output is semantically different from the
/// input.
bool debugMiscompilation();
/// debugPassMiscompilation - This method is called when the specified pass
/// miscompiles Program as input. It tries to reduce the testcase to
/// something that smaller that still miscompiles the program.
/// ReferenceOutput contains the filename of the file containing the output we
/// are to match.
///
bool debugPassMiscompilation(const PassInfo *ThePass,
const std::string &ReferenceOutput);
/// compileSharedObject - This method creates a SharedObject from a given
/// BytecodeFile for debugging a code generator.
int compileSharedObject(const std::string &BytecodeFile,
std::string &SharedObject);
/// debugCodeGenerator - This method narrows down a module to a function or
/// set of functions, using the CBE as a ``safe'' code generator for other
/// functions that are not under consideration.
bool debugCodeGenerator();
/// isExecutingJIT - Returns true if bugpoint is currently testing the JIT
///
bool isExecutingJIT();
private:
/// ParseInputFile - Given a bytecode or assembly input filename, parse and
/// return it, or return null if not possible.
///
Module *ParseInputFile(const std::string &InputFilename) const;
/// writeProgramToFile - This writes the current "Program" to the named
/// bytecode file. If an error occurs, true is returned.
///
bool writeProgramToFile(const std::string &Filename, Module *M = 0) const;
/// EmitProgressBytecode - This function is used to output the current Program
/// to a file named "bugpoing-ID.bc".
///
void EmitProgressBytecode(const std::string &ID, bool NoFlyer = false);
/// runPasses - Run the specified passes on Program, outputting a bytecode
/// file and writting the filename into OutputFile if successful. If the
/// optimizations fail for some reason (optimizer crashes), return true,
/// otherwise return false. If DeleteOutput is set to true, the bytecode is
/// deleted on success, and the filename string is undefined. This prints to
/// cout a single line message indicating whether compilation was successful
/// or failed, unless Quiet is set.
///
bool runPasses(const std::vector<const PassInfo*> &PassesToRun,
std::string &OutputFilename, bool DeleteOutput = false,
bool Quiet = false) const;
/// runPasses - Just like the method above, but this just returns true or
/// false indicating whether or not the optimizer crashed on the specified
/// input (true = crashed).
///
bool runPasses(const std::vector<const PassInfo*> &PassesToRun,
bool DeleteOutput = true) const {
std::string Filename;
return runPasses(PassesToRun, Filename, DeleteOutput);
}
/// PrintFunctionList - prints out list of problematic functions
///
static void PrintFunctionList(const std::vector<Function*> &Funcs);
/// deleteInstructionFromProgram - This method clones the current Program and
/// deletes the specified instruction from the cloned module. It then runs a
/// series of cleanup passes (ADCE and SimplifyCFG) to eliminate any code
/// which depends on the value. The modified module is then returned.
///
Module *deleteInstructionFromProgram(Instruction *I, unsigned Simp) const;
/// performFinalCleanups - This method clones the current Program and performs
/// a series of cleanups intended to get rid of extra cruft on the module
/// before handing it to the user...
///
Module *performFinalCleanups() const;
/// initializeExecutionEnvironment - This method is used to set up the
/// environment for executing LLVM programs.
///
bool initializeExecutionEnvironment();
/// executeProgram - This method runs "Program", capturing the output of the
/// program to a file, returning the filename of the file. A recommended
/// filename may be optionally specified.
///
std::string executeProgram(std::string RequestedOutputFilename = "",
std::string Bytecode = "",
std::string SharedObject = "",
AbstractInterpreter *AI = 0);
/// executeProgramWithCBE - Used to create reference output with the C
/// backend, if reference output is not provided.
std::string executeProgramWithCBE(std::string RequestedOutputFilename = "",
std::string Bytecode = "",
std::string SharedObject = "");
/// 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.
///
bool diffProgram(const std::string &BytecodeFile = "",
const std::string &SharedObject = "",
bool RemoveBytecode = false);
};
/// getPassesString - Turn a list of passes into a string which indicates the
/// command line options that must be passed to add the passes.
///
std::string getPassesString(const std::vector<const PassInfo*> &Passes);
// DeleteFunctionBody - "Remove" the function by deleting all of it's basic
// blocks, making it external.
//
void DeleteFunctionBody(Function *F);
#endif
|