]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===- CrashDebugger.cpp - Debug compilation crashes ----------------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This file defines the bugpoint internals that narrow down compilation crashes | |
11 | // | |
12 | //===----------------------------------------------------------------------===// | |
13 | ||
14 | #include "BugDriver.h" | |
223e47cc | 15 | #include "ListReducer.h" |
970d7e83 | 16 | #include "ToolRunner.h" |
223e47cc | 17 | #include "llvm/ADT/SmallPtrSet.h" |
1a4d82fc | 18 | #include "llvm/IR/CFG.h" |
970d7e83 LB |
19 | #include "llvm/IR/Constants.h" |
20 | #include "llvm/IR/DerivedTypes.h" | |
21 | #include "llvm/IR/Instructions.h" | |
22 | #include "llvm/IR/Module.h" | |
23 | #include "llvm/IR/ValueSymbolTable.h" | |
1a4d82fc | 24 | #include "llvm/IR/Verifier.h" |
970d7e83 LB |
25 | #include "llvm/Pass.h" |
26 | #include "llvm/PassManager.h" | |
970d7e83 LB |
27 | #include "llvm/Support/CommandLine.h" |
28 | #include "llvm/Support/FileUtilities.h" | |
223e47cc LB |
29 | #include "llvm/Transforms/Scalar.h" |
30 | #include "llvm/Transforms/Utils/Cloning.h" | |
223e47cc LB |
31 | #include <set> |
32 | using namespace llvm; | |
33 | ||
34 | namespace { | |
35 | cl::opt<bool> | |
36 | KeepMain("keep-main", | |
37 | cl::desc("Force function reduction to keep main"), | |
38 | cl::init(false)); | |
39 | cl::opt<bool> | |
40 | NoGlobalRM ("disable-global-remove", | |
41 | cl::desc("Do not remove global variables"), | |
42 | cl::init(false)); | |
43 | } | |
44 | ||
45 | namespace llvm { | |
46 | class ReducePassList : public ListReducer<std::string> { | |
47 | BugDriver &BD; | |
48 | public: | |
49 | ReducePassList(BugDriver &bd) : BD(bd) {} | |
50 | ||
51 | // doTest - Return true iff running the "removed" passes succeeds, and | |
52 | // running the "Kept" passes fail when run on the output of the "removed" | |
53 | // passes. If we return true, we update the current module of bugpoint. | |
54 | // | |
1a4d82fc JJ |
55 | TestResult doTest(std::vector<std::string> &Removed, |
56 | std::vector<std::string> &Kept, | |
57 | std::string &Error) override; | |
223e47cc LB |
58 | }; |
59 | } | |
60 | ||
61 | ReducePassList::TestResult | |
62 | ReducePassList::doTest(std::vector<std::string> &Prefix, | |
63 | std::vector<std::string> &Suffix, | |
64 | std::string &Error) { | |
1a4d82fc JJ |
65 | std::string PrefixOutput; |
66 | Module *OrigProgram = nullptr; | |
223e47cc LB |
67 | if (!Prefix.empty()) { |
68 | outs() << "Checking to see if these passes crash: " | |
69 | << getPassesString(Prefix) << ": "; | |
1a4d82fc | 70 | if (BD.runPasses(BD.getProgram(), Prefix, PrefixOutput)) |
223e47cc LB |
71 | return KeepPrefix; |
72 | ||
223e47cc LB |
73 | OrigProgram = BD.Program; |
74 | ||
1a4d82fc JJ |
75 | BD.Program = parseInputFile(PrefixOutput, BD.getContext()).release(); |
76 | if (BD.Program == nullptr) { | |
223e47cc | 77 | errs() << BD.getToolName() << ": Error reading bitcode file '" |
1a4d82fc | 78 | << PrefixOutput << "'!\n"; |
223e47cc LB |
79 | exit(1); |
80 | } | |
1a4d82fc | 81 | sys::fs::remove(PrefixOutput); |
223e47cc LB |
82 | } |
83 | ||
84 | outs() << "Checking to see if these passes crash: " | |
85 | << getPassesString(Suffix) << ": "; | |
86 | ||
87 | if (BD.runPasses(BD.getProgram(), Suffix)) { | |
88 | delete OrigProgram; // The suffix crashes alone... | |
89 | return KeepSuffix; | |
90 | } | |
91 | ||
92 | // Nothing failed, restore state... | |
93 | if (OrigProgram) { | |
94 | delete BD.Program; | |
95 | BD.Program = OrigProgram; | |
96 | } | |
97 | return NoFailure; | |
98 | } | |
99 | ||
100 | namespace { | |
101 | /// ReduceCrashingGlobalVariables - This works by removing the global | |
102 | /// variable's initializer and seeing if the program still crashes. If it | |
103 | /// does, then we keep that program and try again. | |
104 | /// | |
105 | class ReduceCrashingGlobalVariables : public ListReducer<GlobalVariable*> { | |
106 | BugDriver &BD; | |
107 | bool (*TestFn)(const BugDriver &, Module *); | |
108 | public: | |
109 | ReduceCrashingGlobalVariables(BugDriver &bd, | |
110 | bool (*testFn)(const BugDriver &, Module *)) | |
111 | : BD(bd), TestFn(testFn) {} | |
112 | ||
1a4d82fc JJ |
113 | TestResult doTest(std::vector<GlobalVariable*> &Prefix, |
114 | std::vector<GlobalVariable*> &Kept, | |
115 | std::string &Error) override { | |
223e47cc LB |
116 | if (!Kept.empty() && TestGlobalVariables(Kept)) |
117 | return KeepSuffix; | |
118 | if (!Prefix.empty() && TestGlobalVariables(Prefix)) | |
119 | return KeepPrefix; | |
120 | return NoFailure; | |
121 | } | |
122 | ||
123 | bool TestGlobalVariables(std::vector<GlobalVariable*> &GVs); | |
124 | }; | |
125 | } | |
126 | ||
127 | bool | |
128 | ReduceCrashingGlobalVariables::TestGlobalVariables( | |
129 | std::vector<GlobalVariable*> &GVs) { | |
130 | // Clone the program to try hacking it apart... | |
131 | ValueToValueMapTy VMap; | |
132 | Module *M = CloneModule(BD.getProgram(), VMap); | |
133 | ||
134 | // Convert list to set for fast lookup... | |
135 | std::set<GlobalVariable*> GVSet; | |
136 | ||
137 | for (unsigned i = 0, e = GVs.size(); i != e; ++i) { | |
138 | GlobalVariable* CMGV = cast<GlobalVariable>(VMap[GVs[i]]); | |
139 | assert(CMGV && "Global Variable not in module?!"); | |
140 | GVSet.insert(CMGV); | |
141 | } | |
142 | ||
143 | outs() << "Checking for crash with only these global variables: "; | |
144 | PrintGlobalVariableList(GVs); | |
145 | outs() << ": "; | |
146 | ||
147 | // Loop over and delete any global variables which we aren't supposed to be | |
148 | // playing with... | |
149 | for (Module::global_iterator I = M->global_begin(), E = M->global_end(); | |
150 | I != E; ++I) | |
151 | if (I->hasInitializer() && !GVSet.count(I)) { | |
1a4d82fc | 152 | I->setInitializer(nullptr); |
223e47cc LB |
153 | I->setLinkage(GlobalValue::ExternalLinkage); |
154 | } | |
155 | ||
156 | // Try running the hacked up program... | |
157 | if (TestFn(BD, M)) { | |
158 | BD.setNewProgram(M); // It crashed, keep the trimmed version... | |
159 | ||
160 | // Make sure to use global variable pointers that point into the now-current | |
161 | // module. | |
162 | GVs.assign(GVSet.begin(), GVSet.end()); | |
163 | return true; | |
164 | } | |
165 | ||
166 | delete M; | |
167 | return false; | |
168 | } | |
169 | ||
170 | namespace { | |
171 | /// ReduceCrashingFunctions reducer - This works by removing functions and | |
172 | /// seeing if the program still crashes. If it does, then keep the newer, | |
173 | /// smaller program. | |
174 | /// | |
175 | class ReduceCrashingFunctions : public ListReducer<Function*> { | |
176 | BugDriver &BD; | |
177 | bool (*TestFn)(const BugDriver &, Module *); | |
178 | public: | |
179 | ReduceCrashingFunctions(BugDriver &bd, | |
180 | bool (*testFn)(const BugDriver &, Module *)) | |
181 | : BD(bd), TestFn(testFn) {} | |
182 | ||
1a4d82fc JJ |
183 | TestResult doTest(std::vector<Function*> &Prefix, |
184 | std::vector<Function*> &Kept, | |
185 | std::string &Error) override { | |
223e47cc LB |
186 | if (!Kept.empty() && TestFuncs(Kept)) |
187 | return KeepSuffix; | |
188 | if (!Prefix.empty() && TestFuncs(Prefix)) | |
189 | return KeepPrefix; | |
190 | return NoFailure; | |
191 | } | |
192 | ||
193 | bool TestFuncs(std::vector<Function*> &Prefix); | |
194 | }; | |
195 | } | |
196 | ||
197 | bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) { | |
1a4d82fc JJ |
198 | // If main isn't present, claim there is no problem. |
199 | if (KeepMain && std::find(Funcs.begin(), Funcs.end(), | |
200 | BD.getProgram()->getFunction("main")) == | |
201 | Funcs.end()) | |
223e47cc LB |
202 | return false; |
203 | ||
204 | // Clone the program to try hacking it apart... | |
205 | ValueToValueMapTy VMap; | |
206 | Module *M = CloneModule(BD.getProgram(), VMap); | |
207 | ||
208 | // Convert list to set for fast lookup... | |
209 | std::set<Function*> Functions; | |
210 | for (unsigned i = 0, e = Funcs.size(); i != e; ++i) { | |
211 | Function *CMF = cast<Function>(VMap[Funcs[i]]); | |
212 | assert(CMF && "Function not in module?!"); | |
213 | assert(CMF->getFunctionType() == Funcs[i]->getFunctionType() && "wrong ty"); | |
214 | assert(CMF->getName() == Funcs[i]->getName() && "wrong name"); | |
215 | Functions.insert(CMF); | |
216 | } | |
217 | ||
218 | outs() << "Checking for crash with only these functions: "; | |
219 | PrintFunctionList(Funcs); | |
220 | outs() << ": "; | |
221 | ||
222 | // Loop over and delete any functions which we aren't supposed to be playing | |
223 | // with... | |
224 | for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) | |
225 | if (!I->isDeclaration() && !Functions.count(I)) | |
226 | DeleteFunctionBody(I); | |
227 | ||
228 | // Try running the hacked up program... | |
229 | if (TestFn(BD, M)) { | |
230 | BD.setNewProgram(M); // It crashed, keep the trimmed version... | |
231 | ||
232 | // Make sure to use function pointers that point into the now-current | |
233 | // module. | |
234 | Funcs.assign(Functions.begin(), Functions.end()); | |
235 | return true; | |
236 | } | |
237 | delete M; | |
238 | return false; | |
239 | } | |
240 | ||
241 | ||
242 | namespace { | |
243 | /// ReduceCrashingBlocks reducer - This works by setting the terminators of | |
244 | /// all terminators except the specified basic blocks to a 'ret' instruction, | |
245 | /// then running the simplify-cfg pass. This has the effect of chopping up | |
246 | /// the CFG really fast which can reduce large functions quickly. | |
247 | /// | |
248 | class ReduceCrashingBlocks : public ListReducer<const BasicBlock*> { | |
249 | BugDriver &BD; | |
250 | bool (*TestFn)(const BugDriver &, Module *); | |
251 | public: | |
252 | ReduceCrashingBlocks(BugDriver &bd, | |
253 | bool (*testFn)(const BugDriver &, Module *)) | |
254 | : BD(bd), TestFn(testFn) {} | |
255 | ||
1a4d82fc JJ |
256 | TestResult doTest(std::vector<const BasicBlock*> &Prefix, |
257 | std::vector<const BasicBlock*> &Kept, | |
258 | std::string &Error) override { | |
223e47cc LB |
259 | if (!Kept.empty() && TestBlocks(Kept)) |
260 | return KeepSuffix; | |
261 | if (!Prefix.empty() && TestBlocks(Prefix)) | |
262 | return KeepPrefix; | |
263 | return NoFailure; | |
264 | } | |
265 | ||
266 | bool TestBlocks(std::vector<const BasicBlock*> &Prefix); | |
267 | }; | |
268 | } | |
269 | ||
270 | bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { | |
271 | // Clone the program to try hacking it apart... | |
272 | ValueToValueMapTy VMap; | |
273 | Module *M = CloneModule(BD.getProgram(), VMap); | |
274 | ||
275 | // Convert list to set for fast lookup... | |
276 | SmallPtrSet<BasicBlock*, 8> Blocks; | |
277 | for (unsigned i = 0, e = BBs.size(); i != e; ++i) | |
278 | Blocks.insert(cast<BasicBlock>(VMap[BBs[i]])); | |
279 | ||
280 | outs() << "Checking for crash with only these blocks:"; | |
281 | unsigned NumPrint = Blocks.size(); | |
282 | if (NumPrint > 10) NumPrint = 10; | |
283 | for (unsigned i = 0, e = NumPrint; i != e; ++i) | |
284 | outs() << " " << BBs[i]->getName(); | |
285 | if (NumPrint < Blocks.size()) | |
286 | outs() << "... <" << Blocks.size() << " total>"; | |
287 | outs() << ": "; | |
288 | ||
289 | // Loop over and delete any hack up any blocks that are not listed... | |
290 | for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) | |
291 | for (Function::iterator BB = I->begin(), E = I->end(); BB != E; ++BB) | |
292 | if (!Blocks.count(BB) && BB->getTerminator()->getNumSuccessors()) { | |
293 | // Loop over all of the successors of this block, deleting any PHI nodes | |
294 | // that might include it. | |
295 | for (succ_iterator SI = succ_begin(BB), E = succ_end(BB); SI != E; ++SI) | |
296 | (*SI)->removePredecessor(BB); | |
297 | ||
298 | TerminatorInst *BBTerm = BB->getTerminator(); | |
299 | ||
300 | if (!BB->getTerminator()->getType()->isVoidTy()) | |
301 | BBTerm->replaceAllUsesWith(Constant::getNullValue(BBTerm->getType())); | |
302 | ||
303 | // Replace the old terminator instruction. | |
304 | BB->getInstList().pop_back(); | |
305 | new UnreachableInst(BB->getContext(), BB); | |
306 | } | |
307 | ||
308 | // The CFG Simplifier pass may delete one of the basic blocks we are | |
309 | // interested in. If it does we need to take the block out of the list. Make | |
310 | // a "persistent mapping" by turning basic blocks into <function, name> pairs. | |
311 | // This won't work well if blocks are unnamed, but that is just the risk we | |
312 | // have to take. | |
313 | std::vector<std::pair<std::string, std::string> > BlockInfo; | |
314 | ||
1a4d82fc JJ |
315 | for (BasicBlock *BB : Blocks) |
316 | BlockInfo.push_back(std::make_pair(BB->getParent()->getName(), | |
317 | BB->getName())); | |
223e47cc LB |
318 | |
319 | // Now run the CFG simplify pass on the function... | |
320 | std::vector<std::string> Passes; | |
321 | Passes.push_back("simplifycfg"); | |
322 | Passes.push_back("verify"); | |
1a4d82fc | 323 | std::unique_ptr<Module> New = BD.runPassesOn(M, Passes); |
223e47cc LB |
324 | delete M; |
325 | if (!New) { | |
326 | errs() << "simplifycfg failed!\n"; | |
327 | exit(1); | |
328 | } | |
1a4d82fc | 329 | M = New.release(); |
223e47cc LB |
330 | |
331 | // Try running on the hacked up program... | |
332 | if (TestFn(BD, M)) { | |
333 | BD.setNewProgram(M); // It crashed, keep the trimmed version... | |
334 | ||
335 | // Make sure to use basic block pointers that point into the now-current | |
336 | // module, and that they don't include any deleted blocks. | |
337 | BBs.clear(); | |
338 | const ValueSymbolTable &GST = M->getValueSymbolTable(); | |
339 | for (unsigned i = 0, e = BlockInfo.size(); i != e; ++i) { | |
340 | Function *F = cast<Function>(GST.lookup(BlockInfo[i].first)); | |
341 | ValueSymbolTable &ST = F->getValueSymbolTable(); | |
342 | Value* V = ST.lookup(BlockInfo[i].second); | |
343 | if (V && V->getType() == Type::getLabelTy(V->getContext())) | |
344 | BBs.push_back(cast<BasicBlock>(V)); | |
345 | } | |
346 | return true; | |
347 | } | |
348 | delete M; // It didn't crash, try something else. | |
349 | return false; | |
350 | } | |
351 | ||
352 | namespace { | |
353 | /// ReduceCrashingInstructions reducer - This works by removing the specified | |
354 | /// non-terminator instructions and replacing them with undef. | |
355 | /// | |
356 | class ReduceCrashingInstructions : public ListReducer<const Instruction*> { | |
357 | BugDriver &BD; | |
358 | bool (*TestFn)(const BugDriver &, Module *); | |
359 | public: | |
360 | ReduceCrashingInstructions(BugDriver &bd, | |
361 | bool (*testFn)(const BugDriver &, Module *)) | |
362 | : BD(bd), TestFn(testFn) {} | |
363 | ||
1a4d82fc JJ |
364 | TestResult doTest(std::vector<const Instruction*> &Prefix, |
365 | std::vector<const Instruction*> &Kept, | |
366 | std::string &Error) override { | |
223e47cc LB |
367 | if (!Kept.empty() && TestInsts(Kept)) |
368 | return KeepSuffix; | |
369 | if (!Prefix.empty() && TestInsts(Prefix)) | |
370 | return KeepPrefix; | |
371 | return NoFailure; | |
372 | } | |
373 | ||
374 | bool TestInsts(std::vector<const Instruction*> &Prefix); | |
375 | }; | |
376 | } | |
377 | ||
378 | bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*> | |
379 | &Insts) { | |
380 | // Clone the program to try hacking it apart... | |
381 | ValueToValueMapTy VMap; | |
382 | Module *M = CloneModule(BD.getProgram(), VMap); | |
383 | ||
384 | // Convert list to set for fast lookup... | |
385 | SmallPtrSet<Instruction*, 64> Instructions; | |
386 | for (unsigned i = 0, e = Insts.size(); i != e; ++i) { | |
387 | assert(!isa<TerminatorInst>(Insts[i])); | |
388 | Instructions.insert(cast<Instruction>(VMap[Insts[i]])); | |
389 | } | |
390 | ||
391 | outs() << "Checking for crash with only " << Instructions.size(); | |
392 | if (Instructions.size() == 1) | |
393 | outs() << " instruction: "; | |
394 | else | |
395 | outs() << " instructions: "; | |
396 | ||
397 | for (Module::iterator MI = M->begin(), ME = M->end(); MI != ME; ++MI) | |
398 | for (Function::iterator FI = MI->begin(), FE = MI->end(); FI != FE; ++FI) | |
399 | for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E;) { | |
400 | Instruction *Inst = I++; | |
401 | if (!Instructions.count(Inst) && !isa<TerminatorInst>(Inst) && | |
402 | !isa<LandingPadInst>(Inst)) { | |
403 | if (!Inst->getType()->isVoidTy()) | |
404 | Inst->replaceAllUsesWith(UndefValue::get(Inst->getType())); | |
405 | Inst->eraseFromParent(); | |
406 | } | |
407 | } | |
408 | ||
409 | // Verify that this is still valid. | |
410 | PassManager Passes; | |
411 | Passes.add(createVerifierPass()); | |
1a4d82fc | 412 | Passes.add(createDebugInfoVerifierPass()); |
223e47cc LB |
413 | Passes.run(*M); |
414 | ||
415 | // Try running on the hacked up program... | |
416 | if (TestFn(BD, M)) { | |
417 | BD.setNewProgram(M); // It crashed, keep the trimmed version... | |
418 | ||
419 | // Make sure to use instruction pointers that point into the now-current | |
420 | // module, and that they don't include any deleted blocks. | |
421 | Insts.clear(); | |
1a4d82fc JJ |
422 | for (Instruction *Inst : Instructions) |
423 | Insts.push_back(Inst); | |
223e47cc LB |
424 | return true; |
425 | } | |
426 | delete M; // It didn't crash, try something else. | |
427 | return false; | |
428 | } | |
429 | ||
430 | /// DebugACrash - Given a predicate that determines whether a component crashes | |
431 | /// on a program, try to destructively reduce the program while still keeping | |
432 | /// the predicate true. | |
433 | static bool DebugACrash(BugDriver &BD, | |
434 | bool (*TestFn)(const BugDriver &, Module *), | |
435 | std::string &Error) { | |
436 | // See if we can get away with nuking some of the global variable initializers | |
437 | // in the program... | |
438 | if (!NoGlobalRM && | |
439 | BD.getProgram()->global_begin() != BD.getProgram()->global_end()) { | |
440 | // Now try to reduce the number of global variable initializers in the | |
441 | // module to something small. | |
442 | Module *M = CloneModule(BD.getProgram()); | |
443 | bool DeletedInit = false; | |
444 | ||
445 | for (Module::global_iterator I = M->global_begin(), E = M->global_end(); | |
446 | I != E; ++I) | |
447 | if (I->hasInitializer()) { | |
1a4d82fc | 448 | I->setInitializer(nullptr); |
223e47cc LB |
449 | I->setLinkage(GlobalValue::ExternalLinkage); |
450 | DeletedInit = true; | |
451 | } | |
452 | ||
453 | if (!DeletedInit) { | |
454 | delete M; // No change made... | |
455 | } else { | |
456 | // See if the program still causes a crash... | |
457 | outs() << "\nChecking to see if we can delete global inits: "; | |
458 | ||
459 | if (TestFn(BD, M)) { // Still crashes? | |
460 | BD.setNewProgram(M); | |
461 | outs() << "\n*** Able to remove all global initializers!\n"; | |
462 | } else { // No longer crashes? | |
463 | outs() << " - Removing all global inits hides problem!\n"; | |
464 | delete M; | |
465 | ||
466 | std::vector<GlobalVariable*> GVs; | |
467 | ||
468 | for (Module::global_iterator I = BD.getProgram()->global_begin(), | |
469 | E = BD.getProgram()->global_end(); I != E; ++I) | |
470 | if (I->hasInitializer()) | |
471 | GVs.push_back(I); | |
472 | ||
473 | if (GVs.size() > 1 && !BugpointIsInterrupted) { | |
474 | outs() << "\n*** Attempting to reduce the number of global " | |
475 | << "variables in the testcase\n"; | |
476 | ||
477 | unsigned OldSize = GVs.size(); | |
478 | ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs, Error); | |
479 | if (!Error.empty()) | |
480 | return true; | |
481 | ||
482 | if (GVs.size() < OldSize) | |
483 | BD.EmitProgressBitcode(BD.getProgram(), "reduced-global-variables"); | |
484 | } | |
485 | } | |
486 | } | |
487 | } | |
488 | ||
489 | // Now try to reduce the number of functions in the module to something small. | |
490 | std::vector<Function*> Functions; | |
491 | for (Module::iterator I = BD.getProgram()->begin(), | |
492 | E = BD.getProgram()->end(); I != E; ++I) | |
493 | if (!I->isDeclaration()) | |
494 | Functions.push_back(I); | |
495 | ||
496 | if (Functions.size() > 1 && !BugpointIsInterrupted) { | |
497 | outs() << "\n*** Attempting to reduce the number of functions " | |
498 | "in the testcase\n"; | |
499 | ||
500 | unsigned OldSize = Functions.size(); | |
501 | ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error); | |
502 | ||
503 | if (Functions.size() < OldSize) | |
504 | BD.EmitProgressBitcode(BD.getProgram(), "reduced-function"); | |
505 | } | |
506 | ||
507 | // Attempt to delete entire basic blocks at a time to speed up | |
508 | // convergence... this actually works by setting the terminator of the blocks | |
509 | // to a return instruction then running simplifycfg, which can potentially | |
510 | // shrinks the code dramatically quickly | |
511 | // | |
512 | if (!DisableSimplifyCFG && !BugpointIsInterrupted) { | |
513 | std::vector<const BasicBlock*> Blocks; | |
514 | for (Module::const_iterator I = BD.getProgram()->begin(), | |
515 | E = BD.getProgram()->end(); I != E; ++I) | |
516 | for (Function::const_iterator FI = I->begin(), E = I->end(); FI !=E; ++FI) | |
517 | Blocks.push_back(FI); | |
518 | unsigned OldSize = Blocks.size(); | |
519 | ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error); | |
520 | if (Blocks.size() < OldSize) | |
521 | BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks"); | |
522 | } | |
523 | ||
524 | // Attempt to delete instructions using bisection. This should help out nasty | |
525 | // cases with large basic blocks where the problem is at one end. | |
526 | if (!BugpointIsInterrupted) { | |
527 | std::vector<const Instruction*> Insts; | |
528 | for (Module::const_iterator MI = BD.getProgram()->begin(), | |
529 | ME = BD.getProgram()->end(); MI != ME; ++MI) | |
530 | for (Function::const_iterator FI = MI->begin(), FE = MI->end(); FI != FE; | |
531 | ++FI) | |
532 | for (BasicBlock::const_iterator I = FI->begin(), E = FI->end(); | |
533 | I != E; ++I) | |
534 | if (!isa<TerminatorInst>(I)) | |
535 | Insts.push_back(I); | |
536 | ||
537 | ReduceCrashingInstructions(BD, TestFn).reduceList(Insts, Error); | |
538 | } | |
539 | ||
540 | // FIXME: This should use the list reducer to converge faster by deleting | |
541 | // larger chunks of instructions at a time! | |
542 | unsigned Simplification = 2; | |
543 | do { | |
544 | if (BugpointIsInterrupted) break; | |
545 | --Simplification; | |
546 | outs() << "\n*** Attempting to reduce testcase by deleting instruc" | |
547 | << "tions: Simplification Level #" << Simplification << '\n'; | |
548 | ||
549 | // Now that we have deleted the functions that are unnecessary for the | |
550 | // program, try to remove instructions that are not necessary to cause the | |
551 | // crash. To do this, we loop through all of the instructions in the | |
552 | // remaining functions, deleting them (replacing any values produced with | |
553 | // nulls), and then running ADCE and SimplifyCFG. If the transformed input | |
554 | // still triggers failure, keep deleting until we cannot trigger failure | |
555 | // anymore. | |
556 | // | |
557 | unsigned InstructionsToSkipBeforeDeleting = 0; | |
558 | TryAgain: | |
559 | ||
560 | // Loop over all of the (non-terminator) instructions remaining in the | |
561 | // function, attempting to delete them. | |
562 | unsigned CurInstructionNum = 0; | |
563 | for (Module::const_iterator FI = BD.getProgram()->begin(), | |
564 | E = BD.getProgram()->end(); FI != E; ++FI) | |
565 | if (!FI->isDeclaration()) | |
566 | for (Function::const_iterator BI = FI->begin(), E = FI->end(); BI != E; | |
567 | ++BI) | |
568 | for (BasicBlock::const_iterator I = BI->begin(), E = --BI->end(); | |
569 | I != E; ++I, ++CurInstructionNum) { | |
570 | if (InstructionsToSkipBeforeDeleting) { | |
571 | --InstructionsToSkipBeforeDeleting; | |
572 | } else { | |
573 | if (BugpointIsInterrupted) goto ExitLoops; | |
574 | ||
575 | if (isa<LandingPadInst>(I)) | |
576 | continue; | |
577 | ||
578 | outs() << "Checking instruction: " << *I; | |
1a4d82fc JJ |
579 | std::unique_ptr<Module> M = |
580 | BD.deleteInstructionFromProgram(I, Simplification); | |
223e47cc LB |
581 | |
582 | // Find out if the pass still crashes on this pass... | |
1a4d82fc | 583 | if (TestFn(BD, M.get())) { |
223e47cc LB |
584 | // Yup, it does, we delete the old module, and continue trying |
585 | // to reduce the testcase... | |
1a4d82fc | 586 | BD.setNewProgram(M.release()); |
223e47cc LB |
587 | InstructionsToSkipBeforeDeleting = CurInstructionNum; |
588 | goto TryAgain; // I wish I had a multi-level break here! | |
589 | } | |
223e47cc LB |
590 | } |
591 | } | |
592 | ||
593 | if (InstructionsToSkipBeforeDeleting) { | |
594 | InstructionsToSkipBeforeDeleting = 0; | |
595 | goto TryAgain; | |
596 | } | |
597 | ||
598 | } while (Simplification); | |
599 | ExitLoops: | |
600 | ||
601 | // Try to clean up the testcase by running funcresolve and globaldce... | |
602 | if (!BugpointIsInterrupted) { | |
603 | outs() << "\n*** Attempting to perform final cleanups: "; | |
604 | Module *M = CloneModule(BD.getProgram()); | |
1a4d82fc | 605 | M = BD.performFinalCleanups(M, true).release(); |
223e47cc LB |
606 | |
607 | // Find out if the pass still crashes on the cleaned up program... | |
608 | if (TestFn(BD, M)) { | |
609 | BD.setNewProgram(M); // Yup, it does, keep the reduced version... | |
610 | } else { | |
611 | delete M; | |
612 | } | |
613 | } | |
614 | ||
615 | BD.EmitProgressBitcode(BD.getProgram(), "reduced-simplified"); | |
616 | ||
617 | return false; | |
618 | } | |
619 | ||
620 | static bool TestForOptimizerCrash(const BugDriver &BD, Module *M) { | |
621 | return BD.runPasses(M); | |
622 | } | |
623 | ||
624 | /// debugOptimizerCrash - This method is called when some pass crashes on input. | |
625 | /// It attempts to prune down the testcase to something reasonable, and figure | |
626 | /// out exactly which pass is crashing. | |
627 | /// | |
628 | bool BugDriver::debugOptimizerCrash(const std::string &ID) { | |
629 | outs() << "\n*** Debugging optimizer crash!\n"; | |
630 | ||
631 | std::string Error; | |
632 | // Reduce the list of passes which causes the optimizer to crash... | |
633 | if (!BugpointIsInterrupted) | |
634 | ReducePassList(*this).reduceList(PassesToRun, Error); | |
635 | assert(Error.empty()); | |
636 | ||
637 | outs() << "\n*** Found crashing pass" | |
638 | << (PassesToRun.size() == 1 ? ": " : "es: ") | |
639 | << getPassesString(PassesToRun) << '\n'; | |
640 | ||
641 | EmitProgressBitcode(Program, ID); | |
642 | ||
643 | bool Success = DebugACrash(*this, TestForOptimizerCrash, Error); | |
644 | assert(Error.empty()); | |
645 | return Success; | |
646 | } | |
647 | ||
648 | static bool TestForCodeGenCrash(const BugDriver &BD, Module *M) { | |
649 | std::string Error; | |
650 | BD.compileProgram(M, &Error); | |
651 | if (!Error.empty()) { | |
652 | errs() << "<crash>\n"; | |
653 | return true; // Tool is still crashing. | |
654 | } | |
655 | errs() << '\n'; | |
656 | return false; | |
657 | } | |
658 | ||
659 | /// debugCodeGeneratorCrash - This method is called when the code generator | |
660 | /// crashes on an input. It attempts to reduce the input as much as possible | |
661 | /// while still causing the code generator to crash. | |
662 | bool BugDriver::debugCodeGeneratorCrash(std::string &Error) { | |
663 | errs() << "*** Debugging code generator crash!\n"; | |
664 | ||
665 | return DebugACrash(*this, TestForCodeGenCrash, Error); | |
666 | } |