173a6bdd9SChris Lattner //===- CrashDebugger.cpp - Debug compilation crashes ----------------------===//
273a6bdd9SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609344dcfSJohn Criswell //
709344dcfSJohn Criswell //===----------------------------------------------------------------------===//
809344dcfSJohn Criswell //
973a6bdd9SChris Lattner // This file defines the bugpoint internals that narrow down compilation crashes
1073a6bdd9SChris Lattner //
1173a6bdd9SChris Lattner //===----------------------------------------------------------------------===//
1273a6bdd9SChris Lattner
1373a6bdd9SChris Lattner #include "BugDriver.h"
141d080f24SChris Lattner #include "ListReducer.h"
154d88a1c2SChandler Carruth #include "ToolRunner.h"
164d88a1c2SChandler Carruth #include "llvm/ADT/SmallPtrSet.h"
1734ca831dSKeno Fischer #include "llvm/ADT/StringSet.h"
188d0a0811SJustin Bogner #include "llvm/Analysis/TargetTransformInfo.h"
191305dc33SChandler Carruth #include "llvm/IR/CFG.h"
209fb823bbSChandler Carruth #include "llvm/IR/Constants.h"
21e5428043SMichael Ilseman #include "llvm/IR/DebugInfo.h"
229fb823bbSChandler Carruth #include "llvm/IR/DerivedTypes.h"
2329e8b8ceSFlorian Hahn #include "llvm/IR/InstIterator.h"
249fb823bbSChandler Carruth #include "llvm/IR/Instructions.h"
2530d69c2eSChandler Carruth #include "llvm/IR/LegacyPassManager.h"
269fb823bbSChandler Carruth #include "llvm/IR/Module.h"
279fb823bbSChandler Carruth #include "llvm/IR/ValueSymbolTable.h"
285ad5f15cSChandler Carruth #include "llvm/IR/Verifier.h"
290c2305b1SMisha Brukman #include "llvm/Pass.h"
304d88a1c2SChandler Carruth #include "llvm/Support/CommandLine.h"
314d88a1c2SChandler Carruth #include "llvm/Support/FileUtilities.h"
32f32939bbSChris Lattner #include "llvm/Transforms/Scalar.h"
33271ca401SDaniel Berlin #include "llvm/Transforms/Utils/BasicBlockUtils.h"
341d080f24SChris Lattner #include "llvm/Transforms/Utils/Cloning.h"
3529e8b8ceSFlorian Hahn #include "llvm/Transforms/Utils/Local.h"
361d080f24SChris Lattner #include <set>
372f1aa118SChris Lattner using namespace llvm;
3873a6bdd9SChris Lattner
39ef9aa129SAndrew Lenharth namespace {
408d0a0811SJustin Bogner cl::opt<bool> KeepMain("keep-main",
41ef9aa129SAndrew Lenharth cl::desc("Force function reduction to keep main"),
42ef9aa129SAndrew Lenharth cl::init(false));
438d0a0811SJustin Bogner cl::opt<bool> NoGlobalRM("disable-global-remove",
445bd3f7b4STorok Edwin cl::desc("Do not remove global variables"),
455bd3f7b4STorok Edwin cl::init(false));
46f87e20ddSJF Bastien
476f06eda0SMatt Arsenault cl::opt<bool> NoAttributeRM("disable-attribute-remove",
486f06eda0SMatt Arsenault cl::desc("Do not remove function attributes"),
496f06eda0SMatt Arsenault cl::init(false));
506f06eda0SMatt Arsenault
518d0a0811SJustin Bogner cl::opt<bool> ReplaceFuncsWithNull(
528d0a0811SJustin Bogner "replace-funcs-with-null",
53f87e20ddSJF Bastien cl::desc("When stubbing functions, replace all uses will null"),
54f87e20ddSJF Bastien cl::init(false));
558d0a0811SJustin Bogner cl::opt<bool> DontReducePassList("disable-pass-list-reduction",
56f87e20ddSJF Bastien cl::desc("Skip pass list reduction steps"),
57f87e20ddSJF Bastien cl::init(false));
5834ca831dSKeno Fischer
5934ca831dSKeno Fischer cl::opt<bool> NoNamedMDRM("disable-namedmd-remove",
6034ca831dSKeno Fischer cl::desc("Do not remove global named metadata"),
6134ca831dSKeno Fischer cl::init(false));
62e5428043SMichael Ilseman cl::opt<bool> NoStripDebugInfo("disable-strip-debuginfo",
63e5428043SMichael Ilseman cl::desc("Do not strip debug info metadata"),
64e5428043SMichael Ilseman cl::init(false));
65e5428043SMichael Ilseman cl::opt<bool> NoStripDebugTypeInfo("disable-strip-debug-types",
66e5428043SMichael Ilseman cl::desc("Do not strip debug type info metadata"),
67e5428043SMichael Ilseman cl::init(false));
688f7d0199SSebastian Pop cl::opt<bool> VerboseErrors("verbose-errors",
698f7d0199SSebastian Pop cl::desc("Print the output of crashing program"),
708f7d0199SSebastian Pop cl::init(false));
71ef9aa129SAndrew Lenharth }
72ef9aa129SAndrew Lenharth
73960707c3SBrian Gaeke namespace llvm {
7433e81a82SRafael Espindola class ReducePassList : public ListReducer<std::string> {
7516a41310SChris Lattner BugDriver &BD;
768d0a0811SJustin Bogner
7716a41310SChris Lattner public:
ReducePassList(BugDriver & bd)78327019b4SChris Lattner ReducePassList(BugDriver &bd) : BD(bd) {}
7916a41310SChris Lattner
801c039155SJustin Bogner // Return true iff running the "removed" passes succeeds, and running the
811c039155SJustin Bogner // "Kept" passes fail when run on the output of the "removed" passes. If we
821c039155SJustin Bogner // return true, we update the current module of bugpoint.
831c039155SJustin Bogner Expected<TestResult> doTest(std::vector<std::string> &Removed,
841c039155SJustin Bogner std::vector<std::string> &Kept) override;
8516a41310SChris Lattner };
862f1aa118SChris Lattner }
871d080f24SChris Lattner
881c039155SJustin Bogner Expected<ReducePassList::TestResult>
doTest(std::vector<std::string> & Prefix,std::vector<std::string> & Suffix)8933e81a82SRafael Espindola ReducePassList::doTest(std::vector<std::string> &Prefix,
901c039155SJustin Bogner std::vector<std::string> &Suffix) {
91bb876654SRafael Espindola std::string PrefixOutput;
922c8bcab6SRafael Espindola std::unique_ptr<Module> OrigProgram;
931d080f24SChris Lattner if (!Prefix.empty()) {
94ee05152cSDan Gohman outs() << "Checking to see if these passes crash: "
951d080f24SChris Lattner << getPassesString(Prefix) << ": ";
96bb876654SRafael Espindola if (BD.runPasses(BD.getProgram(), Prefix, PrefixOutput))
971d080f24SChris Lattner return KeepPrefix;
981d080f24SChris Lattner
99f6074ed9SRafael Espindola OrigProgram = std::move(BD.Program);
100a9656314SChris Lattner
101f6074ed9SRafael Espindola BD.Program = parseInputFile(PrefixOutput, BD.getContext());
102e6cb63e4SCraig Topper if (BD.Program == nullptr) {
103d8db3760SDan Gohman errs() << BD.getToolName() << ": Error reading bitcode file '"
104bb876654SRafael Espindola << PrefixOutput << "'!\n";
1051d080f24SChris Lattner exit(1);
1061d080f24SChris Lattner }
107bb876654SRafael Espindola sys::fs::remove(PrefixOutput);
108a9656314SChris Lattner }
109a9656314SChris Lattner
1108d0a0811SJustin Bogner outs() << "Checking to see if these passes crash: " << getPassesString(Suffix)
1118d0a0811SJustin Bogner << ": ";
1121d080f24SChris Lattner
1132c8bcab6SRafael Espindola if (BD.runPasses(BD.getProgram(), Suffix))
1142c8bcab6SRafael Espindola return KeepSuffix; // The suffix crashes alone...
1151d080f24SChris Lattner
1161d080f24SChris Lattner // Nothing failed, restore state...
117f6074ed9SRafael Espindola if (OrigProgram)
118f6074ed9SRafael Espindola BD.Program = std::move(OrigProgram);
1191d080f24SChris Lattner return NoFailure;
1201d080f24SChris Lattner }
1211d080f24SChris Lattner
12208d829daSVedant Kumar using BugTester = bool (*)(const BugDriver &, Module *);
12308d829daSVedant Kumar
1243f83343cSBill Wendling namespace {
12566e85e6cSVedant Kumar /// ReduceCrashingGlobalInitializers - This works by removing global variable
12666e85e6cSVedant Kumar /// initializers and seeing if the program still crashes. If it does, then we
12766e85e6cSVedant Kumar /// keep that program and try again.
12866e85e6cSVedant Kumar class ReduceCrashingGlobalInitializers : public ListReducer<GlobalVariable *> {
1293f83343cSBill Wendling BugDriver &BD;
13008d829daSVedant Kumar BugTester TestFn;
1318d0a0811SJustin Bogner
1323f83343cSBill Wendling public:
ReduceCrashingGlobalInitializers(BugDriver & bd,BugTester testFn)13366e85e6cSVedant Kumar ReduceCrashingGlobalInitializers(BugDriver &bd, BugTester testFn)
1343f83343cSBill Wendling : BD(bd), TestFn(testFn) {}
1353f83343cSBill Wendling
doTest(std::vector<GlobalVariable * > & Prefix,std::vector<GlobalVariable * > & Kept)1361c039155SJustin Bogner Expected<TestResult> doTest(std::vector<GlobalVariable *> &Prefix,
1371c039155SJustin Bogner std::vector<GlobalVariable *> &Kept) override {
1383f83343cSBill Wendling if (!Kept.empty() && TestGlobalVariables(Kept))
1393f83343cSBill Wendling return KeepSuffix;
1403f83343cSBill Wendling if (!Prefix.empty() && TestGlobalVariables(Prefix))
1413f83343cSBill Wendling return KeepPrefix;
1423f83343cSBill Wendling return NoFailure;
1433f83343cSBill Wendling }
1443f83343cSBill Wendling
1453f83343cSBill Wendling bool TestGlobalVariables(std::vector<GlobalVariable *> &GVs);
1463f83343cSBill Wendling };
1473f83343cSBill Wendling }
1483f83343cSBill Wendling
TestGlobalVariables(std::vector<GlobalVariable * > & GVs)14966e85e6cSVedant Kumar bool ReduceCrashingGlobalInitializers::TestGlobalVariables(
1503f83343cSBill Wendling std::vector<GlobalVariable *> &GVs) {
1513f83343cSBill Wendling // Clone the program to try hacking it apart...
152229e38f0SRafael Espindola ValueToValueMapTy VMap;
153f6074ed9SRafael Espindola std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap);
1543f83343cSBill Wendling
1553f83343cSBill Wendling // Convert list to set for fast lookup...
1563f83343cSBill Wendling std::set<GlobalVariable *> GVSet;
1573f83343cSBill Wendling
1583f83343cSBill Wendling for (unsigned i = 0, e = GVs.size(); i != e; ++i) {
1590dc3c2d3SDevang Patel GlobalVariable *CMGV = cast<GlobalVariable>(VMap[GVs[i]]);
1603f83343cSBill Wendling assert(CMGV && "Global Variable not in module?!");
1613f83343cSBill Wendling GVSet.insert(CMGV);
1623f83343cSBill Wendling }
1633f83343cSBill Wendling
164ee05152cSDan Gohman outs() << "Checking for crash with only these global variables: ";
1653f83343cSBill Wendling PrintGlobalVariableList(GVs);
166ee05152cSDan Gohman outs() << ": ";
1673f83343cSBill Wendling
1683f83343cSBill Wendling // Loop over and delete any global variables which we aren't supposed to be
1693f83343cSBill Wendling // playing with...
170306d16e0SDuncan P. N. Exon Smith for (GlobalVariable &I : M->globals())
171306d16e0SDuncan P. N. Exon Smith if (I.hasInitializer() && !GVSet.count(&I)) {
17228ad2b47SHal Finkel DeleteGlobalInitializer(&I);
173306d16e0SDuncan P. N. Exon Smith I.setLinkage(GlobalValue::ExternalLinkage);
1742a445cf7SJustin Lebar I.setComdat(nullptr);
1753f83343cSBill Wendling }
1763f83343cSBill Wendling
1773f83343cSBill Wendling // Try running the hacked up program...
17866e85e6cSVedant Kumar if (TestFn(BD, M.get())) {
179f6074ed9SRafael Espindola BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version...
1803f83343cSBill Wendling
1813f83343cSBill Wendling // Make sure to use global variable pointers that point into the now-current
1823f83343cSBill Wendling // module.
1833f83343cSBill Wendling GVs.assign(GVSet.begin(), GVSet.end());
1843f83343cSBill Wendling return true;
1853f83343cSBill Wendling }
1863f83343cSBill Wendling
1873f83343cSBill Wendling return false;
1883f83343cSBill Wendling }
1893f83343cSBill Wendling
190a379b181SDavid Blaikie namespace {
1913f83343cSBill Wendling /// ReduceCrashingFunctions reducer - This works by removing functions and
1923f83343cSBill Wendling /// seeing if the program still crashes. If it does, then keep the newer,
1933f83343cSBill Wendling /// smaller program.
1943f83343cSBill Wendling ///
195fd72bed3SChris Lattner class ReduceCrashingFunctions : public ListReducer<Function *> {
1961d080f24SChris Lattner BugDriver &BD;
19708d829daSVedant Kumar BugTester TestFn;
1988d0a0811SJustin Bogner
1991d080f24SChris Lattner public:
ReduceCrashingFunctions(BugDriver & bd,BugTester testFn)20008d829daSVedant Kumar ReduceCrashingFunctions(BugDriver &bd, BugTester testFn)
2018bda4c49SChris Lattner : BD(bd), TestFn(testFn) {}
2021d080f24SChris Lattner
doTest(std::vector<Function * > & Prefix,std::vector<Function * > & Kept)2031c039155SJustin Bogner Expected<TestResult> doTest(std::vector<Function *> &Prefix,
2041c039155SJustin Bogner std::vector<Function *> &Kept) override {
205689398feSMisha Brukman if (!Kept.empty() && TestFuncs(Kept))
2061d080f24SChris Lattner return KeepSuffix;
2071d080f24SChris Lattner if (!Prefix.empty() && TestFuncs(Prefix))
2081d080f24SChris Lattner return KeepPrefix;
2091d080f24SChris Lattner return NoFailure;
2101d080f24SChris Lattner }
2111d080f24SChris Lattner
212fd72bed3SChris Lattner bool TestFuncs(std::vector<Function *> &Prefix);
2131d080f24SChris Lattner };
2142f1aa118SChris Lattner }
2151d080f24SChris Lattner
RemoveFunctionReferences(Module * M,const char * Name)216f87e20ddSJF Bastien static void RemoveFunctionReferences(Module *M, const char *Name) {
217f87e20ddSJF Bastien auto *UsedVar = M->getGlobalVariable(Name, true);
2188d0a0811SJustin Bogner if (!UsedVar || !UsedVar->hasInitializer())
2198d0a0811SJustin Bogner return;
220f87e20ddSJF Bastien if (isa<ConstantAggregateZero>(UsedVar->getInitializer())) {
221f87e20ddSJF Bastien assert(UsedVar->use_empty());
222f87e20ddSJF Bastien UsedVar->eraseFromParent();
223f87e20ddSJF Bastien return;
224f87e20ddSJF Bastien }
225f87e20ddSJF Bastien auto *OldUsedVal = cast<ConstantArray>(UsedVar->getInitializer());
226f87e20ddSJF Bastien std::vector<Constant *> Used;
227f87e20ddSJF Bastien for (Value *V : OldUsedVal->operand_values()) {
228f87e20ddSJF Bastien Constant *Op = cast<Constant>(V->stripPointerCasts());
229f87e20ddSJF Bastien if (!Op->isNullValue()) {
230f87e20ddSJF Bastien Used.push_back(cast<Constant>(V));
231f87e20ddSJF Bastien }
232f87e20ddSJF Bastien }
233f87e20ddSJF Bastien auto *NewValElemTy = OldUsedVal->getType()->getElementType();
234f87e20ddSJF Bastien auto *NewValTy = ArrayType::get(NewValElemTy, Used.size());
235f87e20ddSJF Bastien auto *NewUsedVal = ConstantArray::get(NewValTy, Used);
236f87e20ddSJF Bastien UsedVar->mutateType(NewUsedVal->getType()->getPointerTo());
237f87e20ddSJF Bastien UsedVar->setInitializer(NewUsedVal);
238f87e20ddSJF Bastien }
239f87e20ddSJF Bastien
TestFuncs(std::vector<Function * > & Funcs)240fd72bed3SChris Lattner bool ReduceCrashingFunctions::TestFuncs(std::vector<Function *> &Funcs) {
2416e0520e9SDmitri Gribenko // If main isn't present, claim there is no problem.
242f6074ed9SRafael Espindola if (KeepMain && !is_contained(Funcs, BD.getProgram().getFunction("main")))
243ef9aa129SAndrew Lenharth return false;
244ef9aa129SAndrew Lenharth
2458b2bd4edSMisha Brukman // Clone the program to try hacking it apart...
246229e38f0SRafael Espindola ValueToValueMapTy VMap;
247f6074ed9SRafael Espindola std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap);
2481d080f24SChris Lattner
2491d080f24SChris Lattner // Convert list to set for fast lookup...
2501d080f24SChris Lattner std::set<Function *> Functions;
2511d080f24SChris Lattner for (unsigned i = 0, e = Funcs.size(); i != e; ++i) {
2520dc3c2d3SDevang Patel Function *CMF = cast<Function>(VMap[Funcs[i]]);
2531d080f24SChris Lattner assert(CMF && "Function not in module?!");
2543aaaa0b2SReid Spencer assert(CMF->getFunctionType() == Funcs[i]->getFunctionType() && "wrong ty");
255bcad718fSDan Gohman assert(CMF->getName() == Funcs[i]->getName() && "wrong name");
2561d080f24SChris Lattner Functions.insert(CMF);
2571d080f24SChris Lattner }
2581d080f24SChris Lattner
259ee05152cSDan Gohman outs() << "Checking for crash with only these functions: ";
260fd72bed3SChris Lattner PrintFunctionList(Funcs);
261ee05152cSDan Gohman outs() << ": ";
262f87e20ddSJF Bastien if (!ReplaceFuncsWithNull) {
2631d080f24SChris Lattner // Loop over and delete any functions which we aren't supposed to be playing
2641d080f24SChris Lattner // with...
265306d16e0SDuncan P. N. Exon Smith for (Function &I : *M)
266306d16e0SDuncan P. N. Exon Smith if (!I.isDeclaration() && !Functions.count(&I))
267306d16e0SDuncan P. N. Exon Smith DeleteFunctionBody(&I);
268f87e20ddSJF Bastien } else {
269f87e20ddSJF Bastien std::vector<GlobalValue *> ToRemove;
270f87e20ddSJF Bastien // First, remove aliases to functions we're about to purge.
271f87e20ddSJF Bastien for (GlobalAlias &Alias : M->aliases()) {
27240ec1c0fSItay Bookstein GlobalObject *Root = Alias.getAliaseeObject();
273*46f0e2ceSSimon Pilgrim auto *F = dyn_cast<Function>(Root);
274f87e20ddSJF Bastien if (F) {
275f87e20ddSJF Bastien if (Functions.count(F))
276f87e20ddSJF Bastien // We're keeping this function.
277f87e20ddSJF Bastien continue;
278f87e20ddSJF Bastien } else if (Root->isNullValue()) {
279f87e20ddSJF Bastien // This referenced a globalalias that we've already replaced,
280f87e20ddSJF Bastien // so we still need to replace this alias.
281*46f0e2ceSSimon Pilgrim } else {
282f87e20ddSJF Bastien // Not a function, therefore not something we mess with.
283f87e20ddSJF Bastien continue;
284f87e20ddSJF Bastien }
2851d080f24SChris Lattner
286f87e20ddSJF Bastien PointerType *Ty = cast<PointerType>(Alias.getType());
287f87e20ddSJF Bastien Constant *Replacement = ConstantPointerNull::get(Ty);
288f87e20ddSJF Bastien Alias.replaceAllUsesWith(Replacement);
289f87e20ddSJF Bastien ToRemove.push_back(&Alias);
290f87e20ddSJF Bastien }
291f87e20ddSJF Bastien
292306d16e0SDuncan P. N. Exon Smith for (Function &I : *M) {
293306d16e0SDuncan P. N. Exon Smith if (!I.isDeclaration() && !Functions.count(&I)) {
294306d16e0SDuncan P. N. Exon Smith PointerType *Ty = cast<PointerType>(I.getType());
295f87e20ddSJF Bastien Constant *Replacement = ConstantPointerNull::get(Ty);
296306d16e0SDuncan P. N. Exon Smith I.replaceAllUsesWith(Replacement);
297306d16e0SDuncan P. N. Exon Smith ToRemove.push_back(&I);
298f87e20ddSJF Bastien }
299f87e20ddSJF Bastien }
300f87e20ddSJF Bastien
301f87e20ddSJF Bastien for (auto *F : ToRemove) {
302f87e20ddSJF Bastien F->eraseFromParent();
303f87e20ddSJF Bastien }
304f87e20ddSJF Bastien
305f87e20ddSJF Bastien // Finally, remove any null members from any global intrinsic.
30615647b77SRafael Espindola RemoveFunctionReferences(M.get(), "llvm.used");
30715647b77SRafael Espindola RemoveFunctionReferences(M.get(), "llvm.compiler.used");
308f87e20ddSJF Bastien }
3091d080f24SChris Lattner // Try running the hacked up program...
31015647b77SRafael Espindola if (TestFn(BD, M.get())) {
311f6074ed9SRafael Espindola BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version...
3121d080f24SChris Lattner
3131d080f24SChris Lattner // Make sure to use function pointers that point into the now-current
3141d080f24SChris Lattner // module.
3151d080f24SChris Lattner Funcs.assign(Functions.begin(), Functions.end());
3161d080f24SChris Lattner return true;
3171d080f24SChris Lattner }
3181d080f24SChris Lattner return false;
3191d080f24SChris Lattner }
3201d080f24SChris Lattner
3211942f98dSChris Lattner namespace {
322274981ebSBrian Gesiak /// ReduceCrashingFunctionAttributes reducer - This works by removing
323274981ebSBrian Gesiak /// attributes on a particular function and seeing if the program still crashes.
324274981ebSBrian Gesiak /// If it does, then keep the newer, smaller program.
325274981ebSBrian Gesiak ///
326274981ebSBrian Gesiak class ReduceCrashingFunctionAttributes : public ListReducer<Attribute> {
327274981ebSBrian Gesiak BugDriver &BD;
328274981ebSBrian Gesiak std::string FnName;
329274981ebSBrian Gesiak BugTester TestFn;
330274981ebSBrian Gesiak
331274981ebSBrian Gesiak public:
ReduceCrashingFunctionAttributes(BugDriver & bd,const std::string & FnName,BugTester testFn)332274981ebSBrian Gesiak ReduceCrashingFunctionAttributes(BugDriver &bd, const std::string &FnName,
333274981ebSBrian Gesiak BugTester testFn)
334274981ebSBrian Gesiak : BD(bd), FnName(FnName), TestFn(testFn) {}
335274981ebSBrian Gesiak
doTest(std::vector<Attribute> & Prefix,std::vector<Attribute> & Kept)336274981ebSBrian Gesiak Expected<TestResult> doTest(std::vector<Attribute> &Prefix,
337274981ebSBrian Gesiak std::vector<Attribute> &Kept) override {
338274981ebSBrian Gesiak if (!Kept.empty() && TestFuncAttrs(Kept))
339274981ebSBrian Gesiak return KeepSuffix;
340274981ebSBrian Gesiak if (!Prefix.empty() && TestFuncAttrs(Prefix))
341274981ebSBrian Gesiak return KeepPrefix;
342274981ebSBrian Gesiak return NoFailure;
343274981ebSBrian Gesiak }
344274981ebSBrian Gesiak
345274981ebSBrian Gesiak bool TestFuncAttrs(std::vector<Attribute> &Attrs);
346274981ebSBrian Gesiak };
347274981ebSBrian Gesiak }
348274981ebSBrian Gesiak
TestFuncAttrs(std::vector<Attribute> & Attrs)349274981ebSBrian Gesiak bool ReduceCrashingFunctionAttributes::TestFuncAttrs(
350274981ebSBrian Gesiak std::vector<Attribute> &Attrs) {
351274981ebSBrian Gesiak // Clone the program to try hacking it apart...
352274981ebSBrian Gesiak std::unique_ptr<Module> M = CloneModule(BD.getProgram());
353274981ebSBrian Gesiak Function *F = M->getFunction(FnName);
354274981ebSBrian Gesiak
355274981ebSBrian Gesiak // Build up an AttributeList from the attributes we've been given by the
356274981ebSBrian Gesiak // reducer.
357d2cc6c2dSSerge Guelton AttrBuilder AB(M->getContext());
358274981ebSBrian Gesiak for (auto A : Attrs)
359274981ebSBrian Gesiak AB.addAttribute(A);
360274981ebSBrian Gesiak AttributeList NewAttrs;
361de0ae9e8SArthur Eubanks NewAttrs = NewAttrs.addFnAttributes(BD.getContext(), AB);
362274981ebSBrian Gesiak
363274981ebSBrian Gesiak // Set this new list of attributes on the function.
364274981ebSBrian Gesiak F->setAttributes(NewAttrs);
365274981ebSBrian Gesiak
366055aeb52SDavid Greene // If the attribute list includes "optnone" we need to make sure it also
367055aeb52SDavid Greene // includes "noinline" otherwise we will get a verifier failure.
368055aeb52SDavid Greene if (F->hasFnAttribute(Attribute::OptimizeNone))
369055aeb52SDavid Greene F->addFnAttr(Attribute::NoInline);
370055aeb52SDavid Greene
371274981ebSBrian Gesiak // Try running on the hacked up program...
372274981ebSBrian Gesiak if (TestFn(BD, M.get())) {
373274981ebSBrian Gesiak BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version...
374274981ebSBrian Gesiak
375274981ebSBrian Gesiak // Pass along the set of attributes that caused the crash.
376274981ebSBrian Gesiak Attrs.clear();
37780ea2bb5SArthur Eubanks for (Attribute A : NewAttrs.getFnAttrs()) {
378274981ebSBrian Gesiak Attrs.push_back(A);
379274981ebSBrian Gesiak }
380274981ebSBrian Gesiak return true;
381274981ebSBrian Gesiak }
382274981ebSBrian Gesiak return false;
383274981ebSBrian Gesiak }
384274981ebSBrian Gesiak
385274981ebSBrian Gesiak namespace {
38660606266SDaniel Berlin /// Simplify the CFG without completely destroying it.
38760606266SDaniel Berlin /// This is not well defined, but basically comes down to "try to eliminate
38860606266SDaniel Berlin /// unreachable blocks and constant fold terminators without deciding that
38960606266SDaniel Berlin /// certain undefined behavior cuts off the program at the legs".
simpleSimplifyCfg(Function & F,SmallVectorImpl<BasicBlock * > & BBs)39060606266SDaniel Berlin void simpleSimplifyCfg(Function &F, SmallVectorImpl<BasicBlock *> &BBs) {
39160606266SDaniel Berlin if (F.empty())
39260606266SDaniel Berlin return;
39360606266SDaniel Berlin
39460606266SDaniel Berlin for (auto *BB : BBs) {
39560606266SDaniel Berlin ConstantFoldTerminator(BB);
39660606266SDaniel Berlin MergeBlockIntoPredecessor(BB);
39760606266SDaniel Berlin }
39860606266SDaniel Berlin
39960606266SDaniel Berlin // Remove unreachable blocks
40060606266SDaniel Berlin // removeUnreachableBlocks can't be used here, it will turn various
40160606266SDaniel Berlin // undefined behavior into unreachables, but bugpoint was the thing that
40260606266SDaniel Berlin // generated the undefined behavior, and we don't want it to kill the entire
40360606266SDaniel Berlin // program.
40460606266SDaniel Berlin SmallPtrSet<BasicBlock *, 16> Visited;
40560606266SDaniel Berlin for (auto *BB : depth_first(&F.getEntryBlock()))
40660606266SDaniel Berlin Visited.insert(BB);
40760606266SDaniel Berlin
40860606266SDaniel Berlin SmallVector<BasicBlock *, 16> Unreachable;
40960606266SDaniel Berlin for (auto &BB : F)
41060606266SDaniel Berlin if (!Visited.count(&BB))
41160606266SDaniel Berlin Unreachable.push_back(&BB);
41260606266SDaniel Berlin
41360606266SDaniel Berlin // The dead BB's may be in a dead cycle or otherwise have references to each
41460606266SDaniel Berlin // other. Because of this, we have to drop all references first, then delete
41560606266SDaniel Berlin // them all at once.
41660606266SDaniel Berlin for (auto *BB : Unreachable) {
41760606266SDaniel Berlin for (BasicBlock *Successor : successors(&*BB))
41860606266SDaniel Berlin if (Visited.count(Successor))
41960606266SDaniel Berlin Successor->removePredecessor(&*BB);
42060606266SDaniel Berlin BB->dropAllReferences();
42160606266SDaniel Berlin }
42260606266SDaniel Berlin for (auto *BB : Unreachable)
42360606266SDaniel Berlin BB->eraseFromParent();
42460606266SDaniel Berlin }
4252f1aa118SChris Lattner /// ReduceCrashingBlocks reducer - This works by setting the terminators of
4262f1aa118SChris Lattner /// all terminators except the specified basic blocks to a 'ret' instruction,
427472462c4SBjorn Pettersson /// then running the simplifycfg pass. This has the effect of chopping up
4282f1aa118SChris Lattner /// the CFG really fast which can reduce large functions quickly.
429f32939bbSChris Lattner ///
4308bda4c49SChris Lattner class ReduceCrashingBlocks : public ListReducer<const BasicBlock *> {
431f32939bbSChris Lattner BugDriver &BD;
43208d829daSVedant Kumar BugTester TestFn;
4338d0a0811SJustin Bogner
434f32939bbSChris Lattner public:
ReduceCrashingBlocks(BugDriver & BD,BugTester testFn)43508d829daSVedant Kumar ReduceCrashingBlocks(BugDriver &BD, BugTester testFn)
43660606266SDaniel Berlin : BD(BD), TestFn(testFn) {}
437f32939bbSChris Lattner
doTest(std::vector<const BasicBlock * > & Prefix,std::vector<const BasicBlock * > & Kept)4381c039155SJustin Bogner Expected<TestResult> doTest(std::vector<const BasicBlock *> &Prefix,
4391c039155SJustin Bogner std::vector<const BasicBlock *> &Kept) override {
440fe69bc50SJohn Criswell if (!Kept.empty() && TestBlocks(Kept))
441f32939bbSChris Lattner return KeepSuffix;
442f32939bbSChris Lattner if (!Prefix.empty() && TestBlocks(Prefix))
443f32939bbSChris Lattner return KeepPrefix;
444f32939bbSChris Lattner return NoFailure;
445f32939bbSChris Lattner }
446f32939bbSChris Lattner
4478bda4c49SChris Lattner bool TestBlocks(std::vector<const BasicBlock *> &Prefix);
448f32939bbSChris Lattner };
4492f1aa118SChris Lattner }
450f32939bbSChris Lattner
TestBlocks(std::vector<const BasicBlock * > & BBs)4518bda4c49SChris Lattner bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock *> &BBs) {
4528b2bd4edSMisha Brukman // Clone the program to try hacking it apart...
453229e38f0SRafael Espindola ValueToValueMapTy VMap;
454f6074ed9SRafael Espindola std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap);
455f32939bbSChris Lattner
456f32939bbSChris Lattner // Convert list to set for fast lookup...
457b294e31eSNick Lewycky SmallPtrSet<BasicBlock *, 8> Blocks;
458b294e31eSNick Lewycky for (unsigned i = 0, e = BBs.size(); i != e; ++i)
4590dc3c2d3SDevang Patel Blocks.insert(cast<BasicBlock>(VMap[BBs[i]]));
460f32939bbSChris Lattner
461ee05152cSDan Gohman outs() << "Checking for crash with only these blocks:";
4624f50ebdaSChris Lattner unsigned NumPrint = Blocks.size();
4638d0a0811SJustin Bogner if (NumPrint > 10)
4648d0a0811SJustin Bogner NumPrint = 10;
4654f50ebdaSChris Lattner for (unsigned i = 0, e = NumPrint; i != e; ++i)
466ee05152cSDan Gohman outs() << " " << BBs[i]->getName();
4674f50ebdaSChris Lattner if (NumPrint < Blocks.size())
468ee05152cSDan Gohman outs() << "... <" << Blocks.size() << " total>";
469ee05152cSDan Gohman outs() << ": ";
470f32939bbSChris Lattner
471f32939bbSChris Lattner // Loop over and delete any hack up any blocks that are not listed...
472e84e7675SVedant Kumar for (Function &F : M->functions()) {
473e84e7675SVedant Kumar for (BasicBlock &BB : F) {
474e84e7675SVedant Kumar if (!Blocks.count(&BB) && BB.getTerminator()->getNumSuccessors()) {
475f32939bbSChris Lattner // Loop over all of the successors of this block, deleting any PHI nodes
476f32939bbSChris Lattner // that might include it.
477e84e7675SVedant Kumar for (BasicBlock *Succ : successors(&BB))
478e84e7675SVedant Kumar Succ->removePredecessor(&BB);
479f32939bbSChris Lattner
480e303c87eSChandler Carruth Instruction *BBTerm = BB.getTerminator();
48129e641cdSPhilip Reames if (BBTerm->isEHPad() || BBTerm->getType()->isTokenTy())
482189d7da1SDavid Majnemer continue;
48329e641cdSPhilip Reames if (!BBTerm->getType()->isVoidTy())
4845a1acd99SOwen Anderson BBTerm->replaceAllUsesWith(Constant::getNullValue(BBTerm->getType()));
4857855a5cbSChris Lattner
4867855a5cbSChris Lattner // Replace the old terminator instruction.
487e84e7675SVedant Kumar BB.getInstList().pop_back();
488e84e7675SVedant Kumar new UnreachableInst(BB.getContext(), &BB);
489e84e7675SVedant Kumar }
490e84e7675SVedant Kumar }
491f32939bbSChris Lattner }
492f32939bbSChris Lattner
493f32939bbSChris Lattner // The CFG Simplifier pass may delete one of the basic blocks we are
494f32939bbSChris Lattner // interested in. If it does we need to take the block out of the list. Make
495f32939bbSChris Lattner // a "persistent mapping" by turning basic blocks into <function, name> pairs.
496f32939bbSChris Lattner // This won't work well if blocks are unnamed, but that is just the risk we
497e84e7675SVedant Kumar // have to take. FIXME: Can we just name the blocks?
498d1e241a4SRafael Espindola std::vector<std::pair<std::string, std::string>> BlockInfo;
499f32939bbSChris Lattner
5004627679cSCraig Topper for (BasicBlock *BB : Blocks)
501cd87e207SBenjamin Kramer BlockInfo.emplace_back(std::string(BB->getParent()->getName()),
50249ad3f61SBenjamin Kramer std::string(BB->getName()));
503f32939bbSChris Lattner
50460606266SDaniel Berlin SmallVector<BasicBlock *, 16> ToProcess;
50560606266SDaniel Berlin for (auto &F : *M) {
50660606266SDaniel Berlin for (auto &BB : F)
50760606266SDaniel Berlin if (!Blocks.count(&BB))
50860606266SDaniel Berlin ToProcess.push_back(&BB);
50960606266SDaniel Berlin simpleSimplifyCfg(F, ToProcess);
51060606266SDaniel Berlin ToProcess.clear();
51160606266SDaniel Berlin }
51260606266SDaniel Berlin // Verify we didn't break anything
513d1e241a4SRafael Espindola std::vector<std::string> Passes;
514d1e241a4SRafael Espindola Passes.push_back("verify");
515e84e7675SVedant Kumar std::unique_ptr<Module> New = BD.runPassesOn(M.get(), Passes);
516d1e241a4SRafael Espindola if (!New) {
51760606266SDaniel Berlin errs() << "verify failed!\n";
518d1e241a4SRafael Espindola exit(1);
519d1e241a4SRafael Espindola }
520e84e7675SVedant Kumar M = std::move(New);
521f32939bbSChris Lattner
522f32939bbSChris Lattner // Try running on the hacked up program...
523e84e7675SVedant Kumar if (TestFn(BD, M.get())) {
524f6074ed9SRafael Espindola BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version...
525f32939bbSChris Lattner
526f32939bbSChris Lattner // Make sure to use basic block pointers that point into the now-current
527f32939bbSChris Lattner // module, and that they don't include any deleted blocks.
528f32939bbSChris Lattner BBs.clear();
529f6074ed9SRafael Espindola const ValueSymbolTable &GST = BD.getProgram().getValueSymbolTable();
530e84e7675SVedant Kumar for (const auto &BI : BlockInfo) {
531e84e7675SVedant Kumar Function *F = cast<Function>(GST.lookup(BI.first));
532e84e7675SVedant Kumar Value *V = F->getValueSymbolTable()->lookup(BI.second);
53355f1c09eSOwen Anderson if (V && V->getType() == Type::getLabelTy(V->getContext()))
5343aaaa0b2SReid Spencer BBs.push_back(cast<BasicBlock>(V));
535f32939bbSChris Lattner }
536f32939bbSChris Lattner return true;
537f32939bbSChris Lattner }
538e84e7675SVedant Kumar // It didn't crash, try something else.
539f32939bbSChris Lattner return false;
540f32939bbSChris Lattner }
541f32939bbSChris Lattner
5426e090c91SNick Lewycky namespace {
543271ca401SDaniel Berlin /// ReduceCrashingConditionals reducer - This works by changing
544271ca401SDaniel Berlin /// conditional branches to unconditional ones, then simplifying the CFG
545271ca401SDaniel Berlin /// This has the effect of chopping up the CFG really fast which can reduce
546271ca401SDaniel Berlin /// large functions quickly.
547271ca401SDaniel Berlin ///
548271ca401SDaniel Berlin class ReduceCrashingConditionals : public ListReducer<const BasicBlock *> {
549271ca401SDaniel Berlin BugDriver &BD;
55008d829daSVedant Kumar BugTester TestFn;
551271ca401SDaniel Berlin bool Direction;
552271ca401SDaniel Berlin
553271ca401SDaniel Berlin public:
ReduceCrashingConditionals(BugDriver & bd,BugTester testFn,bool Direction)55408d829daSVedant Kumar ReduceCrashingConditionals(BugDriver &bd, BugTester testFn, bool Direction)
555271ca401SDaniel Berlin : BD(bd), TestFn(testFn), Direction(Direction) {}
556271ca401SDaniel Berlin
doTest(std::vector<const BasicBlock * > & Prefix,std::vector<const BasicBlock * > & Kept)5571c039155SJustin Bogner Expected<TestResult> doTest(std::vector<const BasicBlock *> &Prefix,
5581c039155SJustin Bogner std::vector<const BasicBlock *> &Kept) override {
559271ca401SDaniel Berlin if (!Kept.empty() && TestBlocks(Kept))
560271ca401SDaniel Berlin return KeepSuffix;
561271ca401SDaniel Berlin if (!Prefix.empty() && TestBlocks(Prefix))
562271ca401SDaniel Berlin return KeepPrefix;
563271ca401SDaniel Berlin return NoFailure;
564271ca401SDaniel Berlin }
565271ca401SDaniel Berlin
566271ca401SDaniel Berlin bool TestBlocks(std::vector<const BasicBlock *> &Prefix);
567271ca401SDaniel Berlin };
568271ca401SDaniel Berlin }
569271ca401SDaniel Berlin
TestBlocks(std::vector<const BasicBlock * > & BBs)570271ca401SDaniel Berlin bool ReduceCrashingConditionals::TestBlocks(
571271ca401SDaniel Berlin std::vector<const BasicBlock *> &BBs) {
572271ca401SDaniel Berlin // Clone the program to try hacking it apart...
573271ca401SDaniel Berlin ValueToValueMapTy VMap;
574f6074ed9SRafael Espindola std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap);
575271ca401SDaniel Berlin
576271ca401SDaniel Berlin // Convert list to set for fast lookup...
577271ca401SDaniel Berlin SmallPtrSet<const BasicBlock *, 8> Blocks;
578271ca401SDaniel Berlin for (const auto *BB : BBs)
579271ca401SDaniel Berlin Blocks.insert(cast<BasicBlock>(VMap[BB]));
580271ca401SDaniel Berlin
581271ca401SDaniel Berlin outs() << "Checking for crash with changing conditionals to always jump to "
582271ca401SDaniel Berlin << (Direction ? "true" : "false") << ":";
583271ca401SDaniel Berlin unsigned NumPrint = Blocks.size();
584271ca401SDaniel Berlin if (NumPrint > 10)
585271ca401SDaniel Berlin NumPrint = 10;
586271ca401SDaniel Berlin for (unsigned i = 0, e = NumPrint; i != e; ++i)
587271ca401SDaniel Berlin outs() << " " << BBs[i]->getName();
588271ca401SDaniel Berlin if (NumPrint < Blocks.size())
589271ca401SDaniel Berlin outs() << "... <" << Blocks.size() << " total>";
590271ca401SDaniel Berlin outs() << ": ";
591271ca401SDaniel Berlin
592271ca401SDaniel Berlin // Loop over and delete any hack up any blocks that are not listed...
593271ca401SDaniel Berlin for (auto &F : *M)
594271ca401SDaniel Berlin for (auto &BB : F)
595271ca401SDaniel Berlin if (!Blocks.count(&BB)) {
596271ca401SDaniel Berlin auto *BR = dyn_cast<BranchInst>(BB.getTerminator());
597271ca401SDaniel Berlin if (!BR || !BR->isConditional())
598271ca401SDaniel Berlin continue;
599271ca401SDaniel Berlin if (Direction)
600271ca401SDaniel Berlin BR->setCondition(ConstantInt::getTrue(BR->getContext()));
601271ca401SDaniel Berlin else
602271ca401SDaniel Berlin BR->setCondition(ConstantInt::getFalse(BR->getContext()));
603271ca401SDaniel Berlin }
604271ca401SDaniel Berlin
605271ca401SDaniel Berlin // The following may destroy some blocks, so we save them first
606271ca401SDaniel Berlin std::vector<std::pair<std::string, std::string>> BlockInfo;
607271ca401SDaniel Berlin
608271ca401SDaniel Berlin for (const BasicBlock *BB : Blocks)
60942a25e7fSBenjamin Kramer BlockInfo.emplace_back(std::string(BB->getParent()->getName()),
61049ad3f61SBenjamin Kramer std::string(BB->getName()));
611271ca401SDaniel Berlin
612271ca401SDaniel Berlin SmallVector<BasicBlock *, 16> ToProcess;
613271ca401SDaniel Berlin for (auto &F : *M) {
614271ca401SDaniel Berlin for (auto &BB : F)
615271ca401SDaniel Berlin if (!Blocks.count(&BB))
616271ca401SDaniel Berlin ToProcess.push_back(&BB);
617271ca401SDaniel Berlin simpleSimplifyCfg(F, ToProcess);
618271ca401SDaniel Berlin ToProcess.clear();
619271ca401SDaniel Berlin }
620271ca401SDaniel Berlin // Verify we didn't break anything
621271ca401SDaniel Berlin std::vector<std::string> Passes;
622271ca401SDaniel Berlin Passes.push_back("verify");
623e84e7675SVedant Kumar std::unique_ptr<Module> New = BD.runPassesOn(M.get(), Passes);
624271ca401SDaniel Berlin if (!New) {
625271ca401SDaniel Berlin errs() << "verify failed!\n";
626271ca401SDaniel Berlin exit(1);
627271ca401SDaniel Berlin }
628e84e7675SVedant Kumar M = std::move(New);
629271ca401SDaniel Berlin
630271ca401SDaniel Berlin // Try running on the hacked up program...
631e84e7675SVedant Kumar if (TestFn(BD, M.get())) {
632f6074ed9SRafael Espindola BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version...
633271ca401SDaniel Berlin
634271ca401SDaniel Berlin // Make sure to use basic block pointers that point into the now-current
635271ca401SDaniel Berlin // module, and that they don't include any deleted blocks.
636271ca401SDaniel Berlin BBs.clear();
637f6074ed9SRafael Espindola const ValueSymbolTable &GST = BD.getProgram().getValueSymbolTable();
638271ca401SDaniel Berlin for (auto &BI : BlockInfo) {
639271ca401SDaniel Berlin auto *F = cast<Function>(GST.lookup(BI.first));
640a53d49e1SMehdi Amini Value *V = F->getValueSymbolTable()->lookup(BI.second);
641271ca401SDaniel Berlin if (V && V->getType() == Type::getLabelTy(V->getContext()))
642271ca401SDaniel Berlin BBs.push_back(cast<BasicBlock>(V));
643271ca401SDaniel Berlin }
644271ca401SDaniel Berlin return true;
645271ca401SDaniel Berlin }
646e84e7675SVedant Kumar // It didn't crash, try something else.
647271ca401SDaniel Berlin return false;
648271ca401SDaniel Berlin }
649271ca401SDaniel Berlin
650271ca401SDaniel Berlin namespace {
65160606266SDaniel Berlin /// SimplifyCFG reducer - This works by calling SimplifyCFG on each basic block
65260606266SDaniel Berlin /// in the program.
65360606266SDaniel Berlin
65460606266SDaniel Berlin class ReduceSimplifyCFG : public ListReducer<const BasicBlock *> {
65560606266SDaniel Berlin BugDriver &BD;
65608d829daSVedant Kumar BugTester TestFn;
65760606266SDaniel Berlin TargetTransformInfo TTI;
65860606266SDaniel Berlin
65960606266SDaniel Berlin public:
ReduceSimplifyCFG(BugDriver & bd,BugTester testFn)66008d829daSVedant Kumar ReduceSimplifyCFG(BugDriver &bd, BugTester testFn)
661f6074ed9SRafael Espindola : BD(bd), TestFn(testFn), TTI(bd.getProgram().getDataLayout()) {}
66260606266SDaniel Berlin
doTest(std::vector<const BasicBlock * > & Prefix,std::vector<const BasicBlock * > & Kept)6631c039155SJustin Bogner Expected<TestResult> doTest(std::vector<const BasicBlock *> &Prefix,
6641c039155SJustin Bogner std::vector<const BasicBlock *> &Kept) override {
66560606266SDaniel Berlin if (!Kept.empty() && TestBlocks(Kept))
66660606266SDaniel Berlin return KeepSuffix;
66760606266SDaniel Berlin if (!Prefix.empty() && TestBlocks(Prefix))
66860606266SDaniel Berlin return KeepPrefix;
66960606266SDaniel Berlin return NoFailure;
67060606266SDaniel Berlin }
67160606266SDaniel Berlin
67260606266SDaniel Berlin bool TestBlocks(std::vector<const BasicBlock *> &Prefix);
67360606266SDaniel Berlin };
67460606266SDaniel Berlin }
67560606266SDaniel Berlin
TestBlocks(std::vector<const BasicBlock * > & BBs)6768d0a0811SJustin Bogner bool ReduceSimplifyCFG::TestBlocks(std::vector<const BasicBlock *> &BBs) {
67760606266SDaniel Berlin // Clone the program to try hacking it apart...
67860606266SDaniel Berlin ValueToValueMapTy VMap;
679f6074ed9SRafael Espindola std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap);
68060606266SDaniel Berlin
68160606266SDaniel Berlin // Convert list to set for fast lookup...
68260606266SDaniel Berlin SmallPtrSet<const BasicBlock *, 8> Blocks;
68360606266SDaniel Berlin for (const auto *BB : BBs)
68460606266SDaniel Berlin Blocks.insert(cast<BasicBlock>(VMap[BB]));
68560606266SDaniel Berlin
68660606266SDaniel Berlin outs() << "Checking for crash with CFG simplifying:";
68760606266SDaniel Berlin unsigned NumPrint = Blocks.size();
68860606266SDaniel Berlin if (NumPrint > 10)
68960606266SDaniel Berlin NumPrint = 10;
69060606266SDaniel Berlin for (unsigned i = 0, e = NumPrint; i != e; ++i)
69160606266SDaniel Berlin outs() << " " << BBs[i]->getName();
69260606266SDaniel Berlin if (NumPrint < Blocks.size())
69360606266SDaniel Berlin outs() << "... <" << Blocks.size() << " total>";
69460606266SDaniel Berlin outs() << ": ";
69560606266SDaniel Berlin
69660606266SDaniel Berlin // The following may destroy some blocks, so we save them first
69760606266SDaniel Berlin std::vector<std::pair<std::string, std::string>> BlockInfo;
69860606266SDaniel Berlin
69960606266SDaniel Berlin for (const BasicBlock *BB : Blocks)
70042a25e7fSBenjamin Kramer BlockInfo.emplace_back(std::string(BB->getParent()->getName()),
70149ad3f61SBenjamin Kramer std::string(BB->getName()));
70260606266SDaniel Berlin
70360606266SDaniel Berlin // Loop over and delete any hack up any blocks that are not listed...
70460606266SDaniel Berlin for (auto &F : *M)
70560606266SDaniel Berlin // Loop over all of the basic blocks and remove them if they are unneeded.
70660606266SDaniel Berlin for (Function::iterator BBIt = F.begin(); BBIt != F.end();) {
70760606266SDaniel Berlin if (!Blocks.count(&*BBIt)) {
70860606266SDaniel Berlin ++BBIt;
70960606266SDaniel Berlin continue;
71060606266SDaniel Berlin }
7114c33d521SSanjay Patel simplifyCFG(&*BBIt++, TTI);
71260606266SDaniel Berlin }
71360606266SDaniel Berlin // Verify we didn't break anything
71460606266SDaniel Berlin std::vector<std::string> Passes;
71560606266SDaniel Berlin Passes.push_back("verify");
716e84e7675SVedant Kumar std::unique_ptr<Module> New = BD.runPassesOn(M.get(), Passes);
71760606266SDaniel Berlin if (!New) {
71860606266SDaniel Berlin errs() << "verify failed!\n";
71960606266SDaniel Berlin exit(1);
72060606266SDaniel Berlin }
721e84e7675SVedant Kumar M = std::move(New);
72260606266SDaniel Berlin
72360606266SDaniel Berlin // Try running on the hacked up program...
724e84e7675SVedant Kumar if (TestFn(BD, M.get())) {
725f6074ed9SRafael Espindola BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version...
72660606266SDaniel Berlin
72760606266SDaniel Berlin // Make sure to use basic block pointers that point into the now-current
72860606266SDaniel Berlin // module, and that they don't include any deleted blocks.
72960606266SDaniel Berlin BBs.clear();
730f6074ed9SRafael Espindola const ValueSymbolTable &GST = BD.getProgram().getValueSymbolTable();
73160606266SDaniel Berlin for (auto &BI : BlockInfo) {
73260606266SDaniel Berlin auto *F = cast<Function>(GST.lookup(BI.first));
733a53d49e1SMehdi Amini Value *V = F->getValueSymbolTable()->lookup(BI.second);
73460606266SDaniel Berlin if (V && V->getType() == Type::getLabelTy(V->getContext()))
73560606266SDaniel Berlin BBs.push_back(cast<BasicBlock>(V));
73660606266SDaniel Berlin }
73760606266SDaniel Berlin return true;
73860606266SDaniel Berlin }
739e84e7675SVedant Kumar // It didn't crash, try something else.
74060606266SDaniel Berlin return false;
74160606266SDaniel Berlin }
74260606266SDaniel Berlin
74360606266SDaniel Berlin namespace {
7446e090c91SNick Lewycky /// ReduceCrashingInstructions reducer - This works by removing the specified
7456e090c91SNick Lewycky /// non-terminator instructions and replacing them with undef.
7466e090c91SNick Lewycky ///
7476e090c91SNick Lewycky class ReduceCrashingInstructions : public ListReducer<const Instruction *> {
7486e090c91SNick Lewycky BugDriver &BD;
74908d829daSVedant Kumar BugTester TestFn;
7508d0a0811SJustin Bogner
7516e090c91SNick Lewycky public:
ReduceCrashingInstructions(BugDriver & bd,BugTester testFn)75208d829daSVedant Kumar ReduceCrashingInstructions(BugDriver &bd, BugTester testFn)
7536e090c91SNick Lewycky : BD(bd), TestFn(testFn) {}
7546e090c91SNick Lewycky
doTest(std::vector<const Instruction * > & Prefix,std::vector<const Instruction * > & Kept)7551c039155SJustin Bogner Expected<TestResult> doTest(std::vector<const Instruction *> &Prefix,
7561c039155SJustin Bogner std::vector<const Instruction *> &Kept) override {
7576e090c91SNick Lewycky if (!Kept.empty() && TestInsts(Kept))
7586e090c91SNick Lewycky return KeepSuffix;
7596e090c91SNick Lewycky if (!Prefix.empty() && TestInsts(Prefix))
7606e090c91SNick Lewycky return KeepPrefix;
7616e090c91SNick Lewycky return NoFailure;
7626e090c91SNick Lewycky }
7636e090c91SNick Lewycky
7646e090c91SNick Lewycky bool TestInsts(std::vector<const Instruction *> &Prefix);
7656e090c91SNick Lewycky };
7666e090c91SNick Lewycky }
7676e090c91SNick Lewycky
TestInsts(std::vector<const Instruction * > & Insts)7688d0a0811SJustin Bogner bool ReduceCrashingInstructions::TestInsts(
7698d0a0811SJustin Bogner std::vector<const Instruction *> &Insts) {
7706e090c91SNick Lewycky // Clone the program to try hacking it apart...
771229e38f0SRafael Espindola ValueToValueMapTy VMap;
772f6074ed9SRafael Espindola std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap);
7736e090c91SNick Lewycky
7746e090c91SNick Lewycky // Convert list to set for fast lookup...
775b30f2f51SMatthias Braun SmallPtrSet<Instruction *, 32> Instructions;
7766e090c91SNick Lewycky for (unsigned i = 0, e = Insts.size(); i != e; ++i) {
7779ae926b9SChandler Carruth assert(!Insts[i]->isTerminator());
7780dc3c2d3SDevang Patel Instructions.insert(cast<Instruction>(VMap[Insts[i]]));
7796e090c91SNick Lewycky }
7806e090c91SNick Lewycky
781ee05152cSDan Gohman outs() << "Checking for crash with only " << Instructions.size();
7826e090c91SNick Lewycky if (Instructions.size() == 1)
783ee05152cSDan Gohman outs() << " instruction: ";
7846e090c91SNick Lewycky else
785ee05152cSDan Gohman outs() << " instructions: ";
7866e090c91SNick Lewycky
7876e090c91SNick Lewycky for (Module::iterator MI = M->begin(), ME = M->end(); MI != ME; ++MI)
7886e090c91SNick Lewycky for (Function::iterator FI = MI->begin(), FE = MI->end(); FI != FE; ++FI)
78987e53a0aSKazu Hirata for (Instruction &Inst : llvm::make_early_inc_range(*FI)) {
79087e53a0aSKazu Hirata if (!Instructions.count(&Inst) && !Inst.isTerminator() &&
79187e53a0aSKazu Hirata !Inst.isEHPad() && !Inst.getType()->isTokenTy() &&
79287e53a0aSKazu Hirata !Inst.isSwiftError()) {
79387e53a0aSKazu Hirata if (!Inst.getType()->isVoidTy())
79487e53a0aSKazu Hirata Inst.replaceAllUsesWith(UndefValue::get(Inst.getType()));
79587e53a0aSKazu Hirata Inst.eraseFromParent();
7966e090c91SNick Lewycky }
7976e090c91SNick Lewycky }
7986e090c91SNick Lewycky
7996e090c91SNick Lewycky // Verify that this is still valid.
80030d69c2eSChandler Carruth legacy::PassManager Passes;
801919bdf1dSAdrian Prantl Passes.add(createVerifierPass(/*FatalErrors=*/false));
8026e090c91SNick Lewycky Passes.run(*M);
8036e090c91SNick Lewycky
8046e090c91SNick Lewycky // Try running on the hacked up program...
80519d8655cSRafael Espindola if (TestFn(BD, M.get())) {
806f6074ed9SRafael Espindola BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version...
8076e090c91SNick Lewycky
8086e090c91SNick Lewycky // Make sure to use instruction pointers that point into the now-current
8096e090c91SNick Lewycky // module, and that they don't include any deleted blocks.
8106e090c91SNick Lewycky Insts.clear();
8114627679cSCraig Topper for (Instruction *Inst : Instructions)
8124627679cSCraig Topper Insts.push_back(Inst);
8136e090c91SNick Lewycky return true;
8146e090c91SNick Lewycky }
81519d8655cSRafael Espindola // It didn't crash, try something else.
8166e090c91SNick Lewycky return false;
8176e090c91SNick Lewycky }
8186e090c91SNick Lewycky
81934ca831dSKeno Fischer namespace {
82029e8b8ceSFlorian Hahn /// ReduceCrashingMetadata reducer - This works by removing all metadata from
82129e8b8ceSFlorian Hahn /// the specified instructions.
82229e8b8ceSFlorian Hahn ///
82329e8b8ceSFlorian Hahn class ReduceCrashingMetadata : public ListReducer<Instruction *> {
82429e8b8ceSFlorian Hahn BugDriver &BD;
82529e8b8ceSFlorian Hahn BugTester TestFn;
82629e8b8ceSFlorian Hahn
82729e8b8ceSFlorian Hahn public:
ReduceCrashingMetadata(BugDriver & bd,BugTester testFn)82829e8b8ceSFlorian Hahn ReduceCrashingMetadata(BugDriver &bd, BugTester testFn)
82929e8b8ceSFlorian Hahn : BD(bd), TestFn(testFn) {}
83029e8b8ceSFlorian Hahn
doTest(std::vector<Instruction * > & Prefix,std::vector<Instruction * > & Kept)83129e8b8ceSFlorian Hahn Expected<TestResult> doTest(std::vector<Instruction *> &Prefix,
83229e8b8ceSFlorian Hahn std::vector<Instruction *> &Kept) override {
83329e8b8ceSFlorian Hahn if (!Kept.empty() && TestInsts(Kept))
83429e8b8ceSFlorian Hahn return KeepSuffix;
83529e8b8ceSFlorian Hahn if (!Prefix.empty() && TestInsts(Prefix))
83629e8b8ceSFlorian Hahn return KeepPrefix;
83729e8b8ceSFlorian Hahn return NoFailure;
83829e8b8ceSFlorian Hahn }
83929e8b8ceSFlorian Hahn
84029e8b8ceSFlorian Hahn bool TestInsts(std::vector<Instruction *> &Prefix);
84129e8b8ceSFlorian Hahn };
84229e8b8ceSFlorian Hahn } // namespace
84329e8b8ceSFlorian Hahn
TestInsts(std::vector<Instruction * > & Insts)84429e8b8ceSFlorian Hahn bool ReduceCrashingMetadata::TestInsts(std::vector<Instruction *> &Insts) {
84529e8b8ceSFlorian Hahn // Clone the program to try hacking it apart...
84629e8b8ceSFlorian Hahn ValueToValueMapTy VMap;
84729e8b8ceSFlorian Hahn std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap);
84829e8b8ceSFlorian Hahn
84929e8b8ceSFlorian Hahn // Convert list to set for fast lookup...
85029e8b8ceSFlorian Hahn SmallPtrSet<Instruction *, 32> Instructions;
85129e8b8ceSFlorian Hahn for (Instruction *I : Insts)
85229e8b8ceSFlorian Hahn Instructions.insert(cast<Instruction>(VMap[I]));
85329e8b8ceSFlorian Hahn
85429e8b8ceSFlorian Hahn outs() << "Checking for crash with metadata retained from "
85529e8b8ceSFlorian Hahn << Instructions.size();
85629e8b8ceSFlorian Hahn if (Instructions.size() == 1)
85729e8b8ceSFlorian Hahn outs() << " instruction: ";
85829e8b8ceSFlorian Hahn else
85929e8b8ceSFlorian Hahn outs() << " instructions: ";
86029e8b8ceSFlorian Hahn
86129e8b8ceSFlorian Hahn // Try to drop instruction metadata from all instructions, except the ones
86229e8b8ceSFlorian Hahn // selected in Instructions.
86329e8b8ceSFlorian Hahn for (Function &F : *M)
86429e8b8ceSFlorian Hahn for (Instruction &Inst : instructions(F)) {
8653badd17bSBenjamin Kramer if (!Instructions.count(&Inst)) {
86629e8b8ceSFlorian Hahn Inst.dropUnknownNonDebugMetadata();
86729e8b8ceSFlorian Hahn Inst.setDebugLoc({});
86829e8b8ceSFlorian Hahn }
86929e8b8ceSFlorian Hahn }
87029e8b8ceSFlorian Hahn
87129e8b8ceSFlorian Hahn // Verify that this is still valid.
87229e8b8ceSFlorian Hahn legacy::PassManager Passes;
87329e8b8ceSFlorian Hahn Passes.add(createVerifierPass(/*FatalErrors=*/false));
87429e8b8ceSFlorian Hahn Passes.run(*M);
87529e8b8ceSFlorian Hahn
87629e8b8ceSFlorian Hahn // Try running on the hacked up program...
87729e8b8ceSFlorian Hahn if (TestFn(BD, M.get())) {
87829e8b8ceSFlorian Hahn BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version...
87929e8b8ceSFlorian Hahn
88029e8b8ceSFlorian Hahn // Make sure to use instruction pointers that point into the now-current
88129e8b8ceSFlorian Hahn // module, and that they don't include any deleted blocks.
88229e8b8ceSFlorian Hahn Insts.clear();
88329e8b8ceSFlorian Hahn for (Instruction *I : Instructions)
88429e8b8ceSFlorian Hahn Insts.push_back(I);
88529e8b8ceSFlorian Hahn return true;
88629e8b8ceSFlorian Hahn }
88729e8b8ceSFlorian Hahn // It didn't crash, try something else.
88829e8b8ceSFlorian Hahn return false;
88929e8b8ceSFlorian Hahn }
89029e8b8ceSFlorian Hahn
89129e8b8ceSFlorian Hahn namespace {
89234ca831dSKeno Fischer // Reduce the list of Named Metadata nodes. We keep this as a list of
89334ca831dSKeno Fischer // names to avoid having to convert back and forth every time.
89434ca831dSKeno Fischer class ReduceCrashingNamedMD : public ListReducer<std::string> {
89534ca831dSKeno Fischer BugDriver &BD;
89608d829daSVedant Kumar BugTester TestFn;
89734ca831dSKeno Fischer
89834ca831dSKeno Fischer public:
ReduceCrashingNamedMD(BugDriver & bd,BugTester testFn)89908d829daSVedant Kumar ReduceCrashingNamedMD(BugDriver &bd, BugTester testFn)
90034ca831dSKeno Fischer : BD(bd), TestFn(testFn) {}
90134ca831dSKeno Fischer
doTest(std::vector<std::string> & Prefix,std::vector<std::string> & Kept)9021c039155SJustin Bogner Expected<TestResult> doTest(std::vector<std::string> &Prefix,
9031c039155SJustin Bogner std::vector<std::string> &Kept) override {
90434ca831dSKeno Fischer if (!Kept.empty() && TestNamedMDs(Kept))
90534ca831dSKeno Fischer return KeepSuffix;
90634ca831dSKeno Fischer if (!Prefix.empty() && TestNamedMDs(Prefix))
90734ca831dSKeno Fischer return KeepPrefix;
90834ca831dSKeno Fischer return NoFailure;
90934ca831dSKeno Fischer }
91034ca831dSKeno Fischer
91134ca831dSKeno Fischer bool TestNamedMDs(std::vector<std::string> &NamedMDs);
91234ca831dSKeno Fischer };
91334ca831dSKeno Fischer }
91434ca831dSKeno Fischer
TestNamedMDs(std::vector<std::string> & NamedMDs)91534ca831dSKeno Fischer bool ReduceCrashingNamedMD::TestNamedMDs(std::vector<std::string> &NamedMDs) {
91634ca831dSKeno Fischer
91734ca831dSKeno Fischer ValueToValueMapTy VMap;
918f6074ed9SRafael Espindola std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap);
91934ca831dSKeno Fischer
92034ca831dSKeno Fischer outs() << "Checking for crash with only these named metadata nodes:";
92134ca831dSKeno Fischer unsigned NumPrint = std::min<size_t>(NamedMDs.size(), 10);
92234ca831dSKeno Fischer for (unsigned i = 0, e = NumPrint; i != e; ++i)
92334ca831dSKeno Fischer outs() << " " << NamedMDs[i];
92434ca831dSKeno Fischer if (NumPrint < NamedMDs.size())
92534ca831dSKeno Fischer outs() << "... <" << NamedMDs.size() << " total>";
92634ca831dSKeno Fischer outs() << ": ";
92734ca831dSKeno Fischer
92834ca831dSKeno Fischer // Make a StringMap for faster lookup
92934ca831dSKeno Fischer StringSet<> Names;
93034ca831dSKeno Fischer for (const std::string &Name : NamedMDs)
93134ca831dSKeno Fischer Names.insert(Name);
93234ca831dSKeno Fischer
93334ca831dSKeno Fischer // First collect all the metadata to delete in a vector, then
93434ca831dSKeno Fischer // delete them all at once to avoid invalidating the iterator
93534ca831dSKeno Fischer std::vector<NamedMDNode *> ToDelete;
93634ca831dSKeno Fischer ToDelete.reserve(M->named_metadata_size() - Names.size());
93734ca831dSKeno Fischer for (auto &NamedMD : M->named_metadata())
938faebbb05SAdrian Prantl // Always keep a nonempty llvm.dbg.cu because the Verifier would complain.
939faebbb05SAdrian Prantl if (!Names.count(NamedMD.getName()) &&
940faebbb05SAdrian Prantl (!(NamedMD.getName() == "llvm.dbg.cu" && NamedMD.getNumOperands() > 0)))
94134ca831dSKeno Fischer ToDelete.push_back(&NamedMD);
94234ca831dSKeno Fischer
94334ca831dSKeno Fischer for (auto *NamedMD : ToDelete)
94434ca831dSKeno Fischer NamedMD->eraseFromParent();
94534ca831dSKeno Fischer
94634ca831dSKeno Fischer // Verify that this is still valid.
94734ca831dSKeno Fischer legacy::PassManager Passes;
948919bdf1dSAdrian Prantl Passes.add(createVerifierPass(/*FatalErrors=*/false));
94934ca831dSKeno Fischer Passes.run(*M);
95034ca831dSKeno Fischer
95134ca831dSKeno Fischer // Try running on the hacked up program...
9522911841fSRafael Espindola if (TestFn(BD, M.get())) {
953f6074ed9SRafael Espindola BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version...
95434ca831dSKeno Fischer return true;
95534ca831dSKeno Fischer }
95634ca831dSKeno Fischer return false;
95734ca831dSKeno Fischer }
95834ca831dSKeno Fischer
95934ca831dSKeno Fischer namespace {
96034ca831dSKeno Fischer // Reduce the list of operands to named metadata nodes
96134ca831dSKeno Fischer class ReduceCrashingNamedMDOps : public ListReducer<const MDNode *> {
96234ca831dSKeno Fischer BugDriver &BD;
96308d829daSVedant Kumar BugTester TestFn;
96434ca831dSKeno Fischer
96534ca831dSKeno Fischer public:
ReduceCrashingNamedMDOps(BugDriver & bd,BugTester testFn)96608d829daSVedant Kumar ReduceCrashingNamedMDOps(BugDriver &bd, BugTester testFn)
96734ca831dSKeno Fischer : BD(bd), TestFn(testFn) {}
96834ca831dSKeno Fischer
doTest(std::vector<const MDNode * > & Prefix,std::vector<const MDNode * > & Kept)9691c039155SJustin Bogner Expected<TestResult> doTest(std::vector<const MDNode *> &Prefix,
9701c039155SJustin Bogner std::vector<const MDNode *> &Kept) override {
97134ca831dSKeno Fischer if (!Kept.empty() && TestNamedMDOps(Kept))
97234ca831dSKeno Fischer return KeepSuffix;
97334ca831dSKeno Fischer if (!Prefix.empty() && TestNamedMDOps(Prefix))
97434ca831dSKeno Fischer return KeepPrefix;
97534ca831dSKeno Fischer return NoFailure;
97634ca831dSKeno Fischer }
97734ca831dSKeno Fischer
97834ca831dSKeno Fischer bool TestNamedMDOps(std::vector<const MDNode *> &NamedMDOps);
97934ca831dSKeno Fischer };
98034ca831dSKeno Fischer }
98134ca831dSKeno Fischer
TestNamedMDOps(std::vector<const MDNode * > & NamedMDOps)98234ca831dSKeno Fischer bool ReduceCrashingNamedMDOps::TestNamedMDOps(
98334ca831dSKeno Fischer std::vector<const MDNode *> &NamedMDOps) {
98434ca831dSKeno Fischer // Convert list to set for fast lookup...
985b30f2f51SMatthias Braun SmallPtrSet<const MDNode *, 32> OldMDNodeOps;
98634ca831dSKeno Fischer for (unsigned i = 0, e = NamedMDOps.size(); i != e; ++i) {
98734ca831dSKeno Fischer OldMDNodeOps.insert(NamedMDOps[i]);
98834ca831dSKeno Fischer }
98934ca831dSKeno Fischer
99034ca831dSKeno Fischer outs() << "Checking for crash with only " << OldMDNodeOps.size();
99134ca831dSKeno Fischer if (OldMDNodeOps.size() == 1)
99234ca831dSKeno Fischer outs() << " named metadata operand: ";
99334ca831dSKeno Fischer else
99434ca831dSKeno Fischer outs() << " named metadata operands: ";
99534ca831dSKeno Fischer
99634ca831dSKeno Fischer ValueToValueMapTy VMap;
997f6074ed9SRafael Espindola std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap);
99834ca831dSKeno Fischer
99934ca831dSKeno Fischer // This is a little wasteful. In the future it might be good if we could have
100034ca831dSKeno Fischer // these dropped during cloning.
1001f6074ed9SRafael Espindola for (auto &NamedMD : BD.getProgram().named_metadata()) {
100234ca831dSKeno Fischer // Drop the old one and create a new one
100334ca831dSKeno Fischer M->eraseNamedMetadata(M->getNamedMetadata(NamedMD.getName()));
100434ca831dSKeno Fischer NamedMDNode *NewNamedMDNode =
100534ca831dSKeno Fischer M->getOrInsertNamedMetadata(NamedMD.getName());
100634ca831dSKeno Fischer for (MDNode *op : NamedMD.operands())
100734ca831dSKeno Fischer if (OldMDNodeOps.count(op))
100834ca831dSKeno Fischer NewNamedMDNode->addOperand(cast<MDNode>(MapMetadata(op, VMap)));
100934ca831dSKeno Fischer }
101034ca831dSKeno Fischer
101134ca831dSKeno Fischer // Verify that this is still valid.
101234ca831dSKeno Fischer legacy::PassManager Passes;
1013919bdf1dSAdrian Prantl Passes.add(createVerifierPass(/*FatalErrors=*/false));
101434ca831dSKeno Fischer Passes.run(*M);
101534ca831dSKeno Fischer
101634ca831dSKeno Fischer // Try running on the hacked up program...
101702a3fb15SRafael Espindola if (TestFn(BD, M.get())) {
101834ca831dSKeno Fischer // Make sure to use instruction pointers that point into the now-current
101934ca831dSKeno Fischer // module, and that they don't include any deleted blocks.
102034ca831dSKeno Fischer NamedMDOps.clear();
102134ca831dSKeno Fischer for (const MDNode *Node : OldMDNodeOps)
1022da4a56d1SDuncan P. N. Exon Smith NamedMDOps.push_back(cast<MDNode>(*VMap.getMappedMD(Node)));
102334ca831dSKeno Fischer
1024f6074ed9SRafael Espindola BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version...
102534ca831dSKeno Fischer return true;
102634ca831dSKeno Fischer }
102702a3fb15SRafael Espindola // It didn't crash, try something else.
102834ca831dSKeno Fischer return false;
102934ca831dSKeno Fischer }
103034ca831dSKeno Fischer
103166e85e6cSVedant Kumar /// Attempt to eliminate as many global initializers as possible.
ReduceGlobalInitializers(BugDriver & BD,BugTester TestFn)103208d829daSVedant Kumar static Error ReduceGlobalInitializers(BugDriver &BD, BugTester TestFn) {
1033f6074ed9SRafael Espindola Module &OrigM = BD.getProgram();
1034f6074ed9SRafael Espindola if (OrigM.global_empty())
103566e85e6cSVedant Kumar return Error::success();
103666e85e6cSVedant Kumar
10373f83343cSBill Wendling // Now try to reduce the number of global variable initializers in the
10383f83343cSBill Wendling // module to something small.
1039f6074ed9SRafael Espindola std::unique_ptr<Module> M = CloneModule(OrigM);
104074a4a2a8SBill Wendling bool DeletedInit = false;
104174a4a2a8SBill Wendling
104266e85e6cSVedant Kumar for (GlobalVariable &GV : M->globals()) {
104366e85e6cSVedant Kumar if (GV.hasInitializer()) {
104466e85e6cSVedant Kumar DeleteGlobalInitializer(&GV);
104566e85e6cSVedant Kumar GV.setLinkage(GlobalValue::ExternalLinkage);
104666e85e6cSVedant Kumar GV.setComdat(nullptr);
104774a4a2a8SBill Wendling DeletedInit = true;
104874a4a2a8SBill Wendling }
104966e85e6cSVedant Kumar }
105074a4a2a8SBill Wendling
105166e85e6cSVedant Kumar if (!DeletedInit)
105266e85e6cSVedant Kumar return Error::success();
105366e85e6cSVedant Kumar
105474a4a2a8SBill Wendling // See if the program still causes a crash...
1055ee05152cSDan Gohman outs() << "\nChecking to see if we can delete global inits: ";
105674a4a2a8SBill Wendling
105766e85e6cSVedant Kumar if (TestFn(BD, M.get())) { // Still crashes?
1058f6074ed9SRafael Espindola BD.setNewProgram(std::move(M));
1059ee05152cSDan Gohman outs() << "\n*** Able to remove all global initializers!\n";
106066e85e6cSVedant Kumar return Error::success();
106166e85e6cSVedant Kumar }
106266e85e6cSVedant Kumar
106366e85e6cSVedant Kumar // No longer crashes.
1064ee05152cSDan Gohman outs() << " - Removing all global inits hides problem!\n";
106574a4a2a8SBill Wendling
10663f83343cSBill Wendling std::vector<GlobalVariable *> GVs;
1067f6074ed9SRafael Espindola for (GlobalVariable &GV : OrigM.globals())
106866e85e6cSVedant Kumar if (GV.hasInitializer())
106966e85e6cSVedant Kumar GVs.push_back(&GV);
10703f83343cSBill Wendling
10713f83343cSBill Wendling if (GVs.size() > 1 && !BugpointIsInterrupted) {
107266e85e6cSVedant Kumar outs() << "\n*** Attempting to reduce the number of global initializers "
107366e85e6cSVedant Kumar << "in the testcase\n";
10743f83343cSBill Wendling
10753f83343cSBill Wendling unsigned OldSize = GVs.size();
10761c039155SJustin Bogner Expected<bool> Result =
107766e85e6cSVedant Kumar ReduceCrashingGlobalInitializers(BD, TestFn).reduceList(GVs);
10781c039155SJustin Bogner if (Error E = Result.takeError())
10791c039155SJustin Bogner return E;
10803f83343cSBill Wendling
10813f83343cSBill Wendling if (GVs.size() < OldSize)
1082594994a3SRafael Espindola BD.EmitProgressBitcode(BD.getProgram(), "reduced-global-variables");
108365e5f653SChris Lattner }
10841c039155SJustin Bogner return Error::success();
10851c232f9bSPhilip Reames }
10861c232f9bSPhilip Reames
ReduceInsts(BugDriver & BD,BugTester TestFn)108708d829daSVedant Kumar static Error ReduceInsts(BugDriver &BD, BugTester TestFn) {
10881c232f9bSPhilip Reames // Attempt to delete instructions using bisection. This should help out nasty
10891c232f9bSPhilip Reames // cases with large basic blocks where the problem is at one end.
10901c232f9bSPhilip Reames if (!BugpointIsInterrupted) {
10911c232f9bSPhilip Reames std::vector<const Instruction *> Insts;
1092f6074ed9SRafael Espindola for (const Function &F : BD.getProgram())
10931c232f9bSPhilip Reames for (const BasicBlock &BB : F)
10941c232f9bSPhilip Reames for (const Instruction &I : BB)
10959ae926b9SChandler Carruth if (!I.isTerminator())
10961c232f9bSPhilip Reames Insts.push_back(&I);
10971c232f9bSPhilip Reames
10981c039155SJustin Bogner Expected<bool> Result =
10991c039155SJustin Bogner ReduceCrashingInstructions(BD, TestFn).reduceList(Insts);
11001c039155SJustin Bogner if (Error E = Result.takeError())
11011c039155SJustin Bogner return E;
11021c232f9bSPhilip Reames }
11031c232f9bSPhilip Reames
11041c232f9bSPhilip Reames unsigned Simplification = 2;
11051c232f9bSPhilip Reames do {
11061c232f9bSPhilip Reames if (BugpointIsInterrupted)
11071c039155SJustin Bogner // TODO: Should we distinguish this with an "interrupted error"?
11081c039155SJustin Bogner return Error::success();
11091c232f9bSPhilip Reames --Simplification;
11101c232f9bSPhilip Reames outs() << "\n*** Attempting to reduce testcase by deleting instruc"
11111c232f9bSPhilip Reames << "tions: Simplification Level #" << Simplification << '\n';
11121c232f9bSPhilip Reames
11131c232f9bSPhilip Reames // Now that we have deleted the functions that are unnecessary for the
11141c232f9bSPhilip Reames // program, try to remove instructions that are not necessary to cause the
11151c232f9bSPhilip Reames // crash. To do this, we loop through all of the instructions in the
11161c232f9bSPhilip Reames // remaining functions, deleting them (replacing any values produced with
11171c232f9bSPhilip Reames // nulls), and then running ADCE and SimplifyCFG. If the transformed input
11181c232f9bSPhilip Reames // still triggers failure, keep deleting until we cannot trigger failure
11191c232f9bSPhilip Reames // anymore.
11201c232f9bSPhilip Reames //
11211c232f9bSPhilip Reames unsigned InstructionsToSkipBeforeDeleting = 0;
11221c232f9bSPhilip Reames TryAgain:
11231c232f9bSPhilip Reames
11241c232f9bSPhilip Reames // Loop over all of the (non-terminator) instructions remaining in the
11251c232f9bSPhilip Reames // function, attempting to delete them.
11261c232f9bSPhilip Reames unsigned CurInstructionNum = 0;
1127f6074ed9SRafael Espindola for (Module::const_iterator FI = BD.getProgram().begin(),
1128f6074ed9SRafael Espindola E = BD.getProgram().end();
11298d0a0811SJustin Bogner FI != E; ++FI)
11301c232f9bSPhilip Reames if (!FI->isDeclaration())
11311c232f9bSPhilip Reames for (Function::const_iterator BI = FI->begin(), E = FI->end(); BI != E;
11321c232f9bSPhilip Reames ++BI)
11331c232f9bSPhilip Reames for (BasicBlock::const_iterator I = BI->begin(), E = --BI->end();
11341c232f9bSPhilip Reames I != E; ++I, ++CurInstructionNum) {
11351c232f9bSPhilip Reames if (InstructionsToSkipBeforeDeleting) {
11361c232f9bSPhilip Reames --InstructionsToSkipBeforeDeleting;
11371c232f9bSPhilip Reames } else {
11381c232f9bSPhilip Reames if (BugpointIsInterrupted)
11391c039155SJustin Bogner // TODO: Should this be some kind of interrupted error?
11401c039155SJustin Bogner return Error::success();
11411c232f9bSPhilip Reames
1142a8f5a829SArnold Schwaighofer if (I->isEHPad() || I->getType()->isTokenTy() ||
1143a8f5a829SArnold Schwaighofer I->isSwiftError())
11441c232f9bSPhilip Reames continue;
11451c232f9bSPhilip Reames
11461c232f9bSPhilip Reames outs() << "Checking instruction: " << *I;
11471c232f9bSPhilip Reames std::unique_ptr<Module> M =
11481c232f9bSPhilip Reames BD.deleteInstructionFromProgram(&*I, Simplification);
11491c232f9bSPhilip Reames
11501c232f9bSPhilip Reames // Find out if the pass still crashes on this pass...
11511c232f9bSPhilip Reames if (TestFn(BD, M.get())) {
11521c232f9bSPhilip Reames // Yup, it does, we delete the old module, and continue trying
11531c232f9bSPhilip Reames // to reduce the testcase...
1154f6074ed9SRafael Espindola BD.setNewProgram(std::move(M));
11551c232f9bSPhilip Reames InstructionsToSkipBeforeDeleting = CurInstructionNum;
11561c232f9bSPhilip Reames goto TryAgain; // I wish I had a multi-level break here!
11571c232f9bSPhilip Reames }
11581c232f9bSPhilip Reames }
11591c232f9bSPhilip Reames }
11601c232f9bSPhilip Reames
11611c232f9bSPhilip Reames if (InstructionsToSkipBeforeDeleting) {
11621c232f9bSPhilip Reames InstructionsToSkipBeforeDeleting = 0;
11631c232f9bSPhilip Reames goto TryAgain;
11641c232f9bSPhilip Reames }
11651c232f9bSPhilip Reames
11661c232f9bSPhilip Reames } while (Simplification);
116729e8b8ceSFlorian Hahn
116829e8b8ceSFlorian Hahn // Attempt to drop metadata from instructions that does not contribute to the
116929e8b8ceSFlorian Hahn // crash.
117029e8b8ceSFlorian Hahn if (!BugpointIsInterrupted) {
117129e8b8ceSFlorian Hahn std::vector<Instruction *> Insts;
117229e8b8ceSFlorian Hahn for (Function &F : BD.getProgram())
117329e8b8ceSFlorian Hahn for (Instruction &I : instructions(F))
117429e8b8ceSFlorian Hahn Insts.push_back(&I);
117529e8b8ceSFlorian Hahn
117629e8b8ceSFlorian Hahn Expected<bool> Result =
117729e8b8ceSFlorian Hahn ReduceCrashingMetadata(BD, TestFn).reduceList(Insts);
117829e8b8ceSFlorian Hahn if (Error E = Result.takeError())
117929e8b8ceSFlorian Hahn return E;
118029e8b8ceSFlorian Hahn }
118129e8b8ceSFlorian Hahn
11821c232f9bSPhilip Reames BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions");
11831c039155SJustin Bogner return Error::success();
11841c232f9bSPhilip Reames }
11851c232f9bSPhilip Reames
11861c232f9bSPhilip Reames /// DebugACrash - Given a predicate that determines whether a component crashes
11871c232f9bSPhilip Reames /// on a program, try to destructively reduce the program while still keeping
11881c232f9bSPhilip Reames /// the predicate true.
DebugACrash(BugDriver & BD,BugTester TestFn)118908d829daSVedant Kumar static Error DebugACrash(BugDriver &BD, BugTester TestFn) {
11901c232f9bSPhilip Reames // See if we can get away with nuking some of the global variable initializers
11911c232f9bSPhilip Reames // in the program...
11921c232f9bSPhilip Reames if (!NoGlobalRM)
11931c039155SJustin Bogner if (Error E = ReduceGlobalInitializers(BD, TestFn))
11941c039155SJustin Bogner return E;
119573a6bdd9SChris Lattner
11961d080f24SChris Lattner // Now try to reduce the number of functions in the module to something small.
1197fd72bed3SChris Lattner std::vector<Function *> Functions;
1198f6074ed9SRafael Espindola for (Function &F : BD.getProgram())
1199306d16e0SDuncan P. N. Exon Smith if (!F.isDeclaration())
1200306d16e0SDuncan P. N. Exon Smith Functions.push_back(&F);
120173a6bdd9SChris Lattner
1202beb01faeSChris Lattner if (Functions.size() > 1 && !BugpointIsInterrupted) {
1203ee05152cSDan Gohman outs() << "\n*** Attempting to reduce the number of functions "
12041d080f24SChris Lattner "in the testcase\n";
120573a6bdd9SChris Lattner
12068bda4c49SChris Lattner unsigned OldSize = Functions.size();
12071c039155SJustin Bogner Expected<bool> Result =
12081c039155SJustin Bogner ReduceCrashingFunctions(BD, TestFn).reduceList(Functions);
12091c039155SJustin Bogner if (Error E = Result.takeError())
12101c039155SJustin Bogner return E;
121173a6bdd9SChris Lattner
1212beb01faeSChris Lattner if (Functions.size() < OldSize)
1213594994a3SRafael Espindola BD.EmitProgressBitcode(BD.getProgram(), "reduced-function");
1214514c02ebSChris Lattner }
1215514c02ebSChris Lattner
12166f06eda0SMatt Arsenault if (!NoAttributeRM) {
1217274981ebSBrian Gesiak // For each remaining function, try to reduce that function's attributes.
1218274981ebSBrian Gesiak std::vector<std::string> FunctionNames;
1219274981ebSBrian Gesiak for (Function &F : BD.getProgram())
1220adcd0268SBenjamin Kramer FunctionNames.push_back(std::string(F.getName()));
1221274981ebSBrian Gesiak
1222274981ebSBrian Gesiak if (!FunctionNames.empty() && !BugpointIsInterrupted) {
12236f06eda0SMatt Arsenault outs() << "\n*** Attempting to reduce the number of function attributes"
12246f06eda0SMatt Arsenault " in the testcase\n";
1225274981ebSBrian Gesiak
1226274981ebSBrian Gesiak unsigned OldSize = 0;
1227274981ebSBrian Gesiak unsigned NewSize = 0;
1228274981ebSBrian Gesiak for (std::string &Name : FunctionNames) {
1229274981ebSBrian Gesiak Function *Fn = BD.getProgram().getFunction(Name);
123096551c9cSCraig Topper assert(Fn && "Could not find function?");
1231274981ebSBrian Gesiak
1232274981ebSBrian Gesiak std::vector<Attribute> Attrs;
123380ea2bb5SArthur Eubanks for (Attribute A : Fn->getAttributes().getFnAttrs())
1234274981ebSBrian Gesiak Attrs.push_back(A);
1235274981ebSBrian Gesiak
1236274981ebSBrian Gesiak OldSize += Attrs.size();
1237274981ebSBrian Gesiak Expected<bool> Result =
1238274981ebSBrian Gesiak ReduceCrashingFunctionAttributes(BD, Name, TestFn).reduceList(Attrs);
1239274981ebSBrian Gesiak if (Error E = Result.takeError())
1240274981ebSBrian Gesiak return E;
1241274981ebSBrian Gesiak
1242274981ebSBrian Gesiak NewSize += Attrs.size();
1243274981ebSBrian Gesiak }
1244274981ebSBrian Gesiak
1245274981ebSBrian Gesiak if (OldSize < NewSize)
1246274981ebSBrian Gesiak BD.EmitProgressBitcode(BD.getProgram(), "reduced-function-attributes");
1247274981ebSBrian Gesiak }
12486f06eda0SMatt Arsenault }
1249274981ebSBrian Gesiak
1250271ca401SDaniel Berlin // Attempt to change conditional branches into unconditional branches to
1251271ca401SDaniel Berlin // eliminate blocks.
1252271ca401SDaniel Berlin if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
1253271ca401SDaniel Berlin std::vector<const BasicBlock *> Blocks;
1254f6074ed9SRafael Espindola for (Function &F : BD.getProgram())
1255271ca401SDaniel Berlin for (BasicBlock &BB : F)
1256271ca401SDaniel Berlin Blocks.push_back(&BB);
1257271ca401SDaniel Berlin unsigned OldSize = Blocks.size();
12581c039155SJustin Bogner Expected<bool> Result =
12591c039155SJustin Bogner ReduceCrashingConditionals(BD, TestFn, true).reduceList(Blocks);
12601c039155SJustin Bogner if (Error E = Result.takeError())
12611c039155SJustin Bogner return E;
12621c039155SJustin Bogner Result = ReduceCrashingConditionals(BD, TestFn, false).reduceList(Blocks);
12631c039155SJustin Bogner if (Error E = Result.takeError())
12641c039155SJustin Bogner return E;
1265271ca401SDaniel Berlin if (Blocks.size() < OldSize)
1266271ca401SDaniel Berlin BD.EmitProgressBitcode(BD.getProgram(), "reduced-conditionals");
1267271ca401SDaniel Berlin }
1268271ca401SDaniel Berlin
1269f32939bbSChris Lattner // Attempt to delete entire basic blocks at a time to speed up
1270f32939bbSChris Lattner // convergence... this actually works by setting the terminator of the blocks
1271f32939bbSChris Lattner // to a return instruction then running simplifycfg, which can potentially
1272f32939bbSChris Lattner // shrinks the code dramatically quickly
1273f32939bbSChris Lattner //
1274beb01faeSChris Lattner if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
12758bda4c49SChris Lattner std::vector<const BasicBlock *> Blocks;
1276f6074ed9SRafael Espindola for (Function &F : BD.getProgram())
1277306d16e0SDuncan P. N. Exon Smith for (BasicBlock &BB : F)
1278306d16e0SDuncan P. N. Exon Smith Blocks.push_back(&BB);
12796ee6f739STorok Edwin unsigned OldSize = Blocks.size();
12801c039155SJustin Bogner Expected<bool> Result = ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks);
12811c039155SJustin Bogner if (Error E = Result.takeError())
12821c039155SJustin Bogner return E;
12836ee6f739STorok Edwin if (Blocks.size() < OldSize)
1284594994a3SRafael Espindola BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks");
1285d1e2aaefSChris Lattner }
12860eb5ce94SChris Lattner
12870c559f6dSSimon Pilgrim if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
128860606266SDaniel Berlin std::vector<const BasicBlock *> Blocks;
1289f6074ed9SRafael Espindola for (Function &F : BD.getProgram())
129060606266SDaniel Berlin for (BasicBlock &BB : F)
129160606266SDaniel Berlin Blocks.push_back(&BB);
129260606266SDaniel Berlin unsigned OldSize = Blocks.size();
12931c039155SJustin Bogner Expected<bool> Result = ReduceSimplifyCFG(BD, TestFn).reduceList(Blocks);
12941c039155SJustin Bogner if (Error E = Result.takeError())
12951c039155SJustin Bogner return E;
129660606266SDaniel Berlin if (Blocks.size() < OldSize)
129760606266SDaniel Berlin BD.EmitProgressBitcode(BD.getProgram(), "reduced-simplifycfg");
129860606266SDaniel Berlin }
129960606266SDaniel Berlin
13006e090c91SNick Lewycky // Attempt to delete instructions using bisection. This should help out nasty
13016e090c91SNick Lewycky // cases with large basic blocks where the problem is at one end.
13021c232f9bSPhilip Reames if (!BugpointIsInterrupted)
13031c039155SJustin Bogner if (Error E = ReduceInsts(BD, TestFn))
13041c039155SJustin Bogner return E;
130534ca831dSKeno Fischer
1306e5428043SMichael Ilseman // Attempt to strip debug info metadata.
1307e5428043SMichael Ilseman auto stripMetadata = [&](std::function<bool(Module &)> strip) {
1308f6074ed9SRafael Espindola std::unique_ptr<Module> M = CloneModule(BD.getProgram());
1309e5428043SMichael Ilseman strip(*M);
1310e5428043SMichael Ilseman if (TestFn(BD, M.get()))
1311f6074ed9SRafael Espindola BD.setNewProgram(std::move(M));
1312e5428043SMichael Ilseman };
1313e5428043SMichael Ilseman if (!NoStripDebugInfo && !BugpointIsInterrupted) {
1314e5428043SMichael Ilseman outs() << "\n*** Attempting to strip the debug info: ";
1315e5428043SMichael Ilseman stripMetadata(StripDebugInfo);
1316e5428043SMichael Ilseman }
1317e5428043SMichael Ilseman if (!NoStripDebugTypeInfo && !BugpointIsInterrupted) {
1318e5428043SMichael Ilseman outs() << "\n*** Attempting to strip the debug type info: ";
1319e5428043SMichael Ilseman stripMetadata(stripNonLineTableDebugInfo);
1320e5428043SMichael Ilseman }
1321e5428043SMichael Ilseman
1322ac285cc9SPhilip Reames if (!NoNamedMDRM) {
132334ca831dSKeno Fischer if (!BugpointIsInterrupted) {
132434ca831dSKeno Fischer // Try to reduce the amount of global metadata (particularly debug info),
132534ca831dSKeno Fischer // by dropping global named metadata that anchors them
132634ca831dSKeno Fischer outs() << "\n*** Attempting to remove named metadata: ";
132734ca831dSKeno Fischer std::vector<std::string> NamedMDNames;
1328f6074ed9SRafael Espindola for (auto &NamedMD : BD.getProgram().named_metadata())
132934ca831dSKeno Fischer NamedMDNames.push_back(NamedMD.getName().str());
13301c039155SJustin Bogner Expected<bool> Result =
13311c039155SJustin Bogner ReduceCrashingNamedMD(BD, TestFn).reduceList(NamedMDNames);
13321c039155SJustin Bogner if (Error E = Result.takeError())
13331c039155SJustin Bogner return E;
133434ca831dSKeno Fischer }
133534ca831dSKeno Fischer
133634ca831dSKeno Fischer if (!BugpointIsInterrupted) {
133734ca831dSKeno Fischer // Now that we quickly dropped all the named metadata that doesn't
133834ca831dSKeno Fischer // contribute to the crash, bisect the operands of the remaining ones
133934ca831dSKeno Fischer std::vector<const MDNode *> NamedMDOps;
1340f6074ed9SRafael Espindola for (auto &NamedMD : BD.getProgram().named_metadata())
1341256df863SKeno Fischer for (auto op : NamedMD.operands())
1342256df863SKeno Fischer NamedMDOps.push_back(op);
13431c039155SJustin Bogner Expected<bool> Result =
13441c039155SJustin Bogner ReduceCrashingNamedMDOps(BD, TestFn).reduceList(NamedMDOps);
13451c039155SJustin Bogner if (Error E = Result.takeError())
13461c039155SJustin Bogner return E;
134734ca831dSKeno Fischer }
1348ac285cc9SPhilip Reames BD.EmitProgressBitcode(BD.getProgram(), "reduced-named-md");
134934ca831dSKeno Fischer }
135034ca831dSKeno Fischer
1351514c02ebSChris Lattner // Try to clean up the testcase by running funcresolve and globaldce...
1352beb01faeSChris Lattner if (!BugpointIsInterrupted) {
1353ee05152cSDan Gohman outs() << "\n*** Attempting to perform final cleanups: ";
1354f6074ed9SRafael Espindola std::unique_ptr<Module> M = CloneModule(BD.getProgram());
1355b71251caSRafael Espindola M = BD.performFinalCleanups(std::move(M), true);
1356514c02ebSChris Lattner
1357514c02ebSChris Lattner // Find out if the pass still crashes on the cleaned up program...
1358e84e7675SVedant Kumar if (M && TestFn(BD, M.get()))
1359f6074ed9SRafael Espindola BD.setNewProgram(
1360f6074ed9SRafael Espindola std::move(M)); // Yup, it does, keep the reduced version...
1361beb01faeSChris Lattner }
1362514c02ebSChris Lattner
1363594994a3SRafael Espindola BD.EmitProgressBitcode(BD.getProgram(), "reduced-simplified");
1364514c02ebSChris Lattner
13651c039155SJustin Bogner return Error::success();
136673a6bdd9SChris Lattner }
1367960707c3SBrian Gaeke
TestForOptimizerCrash(const BugDriver & BD,Module * M)1368d1c7ef4aSRafael Espindola static bool TestForOptimizerCrash(const BugDriver &BD, Module *M) {
1369f6074ed9SRafael Espindola return BD.runPasses(*M, BD.getPassesToRun());
13708bda4c49SChris Lattner }
1371ead1dff0SChris Lattner
13728bda4c49SChris Lattner /// debugOptimizerCrash - This method is called when some pass crashes on input.
13738bda4c49SChris Lattner /// It attempts to prune down the testcase to something reasonable, and figure
13748bda4c49SChris Lattner /// out exactly which pass is crashing.
13758bda4c49SChris Lattner ///
debugOptimizerCrash(const std::string & ID)13761c039155SJustin Bogner Error BugDriver::debugOptimizerCrash(const std::string &ID) {
1377ee05152cSDan Gohman outs() << "\n*** Debugging optimizer crash!\n";
13788bda4c49SChris Lattner
13798bda4c49SChris Lattner // Reduce the list of passes which causes the optimizer to crash...
13801c039155SJustin Bogner if (!BugpointIsInterrupted && !DontReducePassList) {
13811c039155SJustin Bogner Expected<bool> Result = ReducePassList(*this).reduceList(PassesToRun);
13821c039155SJustin Bogner if (Error E = Result.takeError())
13831c039155SJustin Bogner return E;
13841c039155SJustin Bogner }
13858bda4c49SChris Lattner
1386ee05152cSDan Gohman outs() << "\n*** Found crashing pass"
13878bda4c49SChris Lattner << (PassesToRun.size() == 1 ? ": " : "es: ")
13886aa3c83fSMisha Brukman << getPassesString(PassesToRun) << '\n';
13898bda4c49SChris Lattner
1390f6074ed9SRafael Espindola EmitProgressBitcode(*Program, ID);
13918bda4c49SChris Lattner
139243a46f1cSFlorian Hahn auto Res = DebugACrash(*this, TestForOptimizerCrash);
139343a46f1cSFlorian Hahn if (Res || DontReducePassList)
139443a46f1cSFlorian Hahn return Res;
139543a46f1cSFlorian Hahn // Try to reduce the pass list again. This covers additional cases
139643a46f1cSFlorian Hahn // we failed to reduce earlier, because of more complex pass dependencies
139743a46f1cSFlorian Hahn // triggering the crash.
139843a46f1cSFlorian Hahn auto SecondRes = ReducePassList(*this).reduceList(PassesToRun);
139943a46f1cSFlorian Hahn if (Error E = SecondRes.takeError())
140043a46f1cSFlorian Hahn return E;
140143a46f1cSFlorian Hahn outs() << "\n*** Found crashing pass"
140243a46f1cSFlorian Hahn << (PassesToRun.size() == 1 ? ": " : "es: ")
140343a46f1cSFlorian Hahn << getPassesString(PassesToRun) << '\n';
140443a46f1cSFlorian Hahn
140543a46f1cSFlorian Hahn EmitProgressBitcode(getProgram(), "reduced-simplified");
140643a46f1cSFlorian Hahn return Res;
14078bda4c49SChris Lattner }
14088bda4c49SChris Lattner
TestForCodeGenCrash(const BugDriver & BD,Module * M)1409d1c7ef4aSRafael Espindola static bool TestForCodeGenCrash(const BugDriver &BD, Module *M) {
1410f6074ed9SRafael Espindola if (Error E = BD.compileProgram(*M)) {
14118f7d0199SSebastian Pop if (VerboseErrors)
14121c039155SJustin Bogner errs() << toString(std::move(E)) << "\n";
14131c039155SJustin Bogner else {
14141c039155SJustin Bogner consumeError(std::move(E));
1415d8db3760SDan Gohman errs() << "<crash>\n";
14161c039155SJustin Bogner }
14178bda4c49SChris Lattner return true; // Tool is still crashing.
14188bda4c49SChris Lattner }
14196ba630b0SNick Lewycky errs() << '\n';
14206ba630b0SNick Lewycky return false;
14218bda4c49SChris Lattner }
1422ead1dff0SChris Lattner
1423ead1dff0SChris Lattner /// debugCodeGeneratorCrash - This method is called when the code generator
1424ead1dff0SChris Lattner /// crashes on an input. It attempts to reduce the input as much as possible
1425ead1dff0SChris Lattner /// while still causing the code generator to crash.
debugCodeGeneratorCrash()14261c039155SJustin Bogner Error BugDriver::debugCodeGeneratorCrash() {
1427d8db3760SDan Gohman errs() << "*** Debugging code generator crash!\n";
1428ead1dff0SChris Lattner
14291c039155SJustin Bogner return DebugACrash(*this, TestForCodeGenCrash);
1430ead1dff0SChris Lattner }
1431