Index: test/BugPoint/func-attrs.ll =================================================================== --- /dev/null +++ test/BugPoint/func-attrs.ll @@ -0,0 +1,12 @@ +; RUN: bugpoint -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t -bugpoint-crashfuncattr -silence-passes +; RUN: llvm-dis %t-reduced-simplified.bc -o - | FileCheck %s +; REQUIRES: loadable_module + +; CHECK: f() #0 +define void @f() #0 { + ret void +} + +; CHECK: "bugpoint-crash" +; CHECK-NOT: inline +attributes #0 = { noinline "bugpoint-crash" "no-frame-pointer-elim-non-leaf" } Index: tools/bugpoint-passes/TestPasses.cpp =================================================================== --- tools/bugpoint-passes/TestPasses.cpp +++ tools/bugpoint-passes/TestPasses.cpp @@ -123,3 +123,28 @@ static RegisterPass A("bugpoint-crash-too-many-cus", "BugPoint Test Pass - Intentionally crash on too many CUs"); + +namespace { +class CrashOnFunctionAttribute : public FunctionPass { +public: + static char ID; // Pass ID, replacement for typeid + CrashOnFunctionAttribute() : FunctionPass(ID) {} + +private: + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + bool runOnFunction(Function &F) override { + AttributeSet A = F.getAttributes().getFnAttributes(); + if (A.hasAttribute("bugpoint-crash")) + abort(); + return false; + } +}; +} // namespace + +char CrashOnFunctionAttribute::ID = 0; +static RegisterPass + B("bugpoint-crashfuncattr", "BugPoint Test Pass - Intentionally crash on " + "function attribute 'bugpoint-crash'"); Index: tools/bugpoint/CrashDebugger.cpp =================================================================== --- tools/bugpoint/CrashDebugger.cpp +++ tools/bugpoint/CrashDebugger.cpp @@ -315,6 +315,66 @@ } namespace { +/// ReduceCrashingFunctionAttributes reducer - This works by removing +/// attributes on a particular function and seeing if the program still crashes. +/// If it does, then keep the newer, smaller program. +/// +class ReduceCrashingFunctionAttributes : public ListReducer { + BugDriver &BD; + std::string FnName; + BugTester TestFn; + +public: + ReduceCrashingFunctionAttributes(BugDriver &bd, const std::string &FnName, + BugTester testFn) + : BD(bd), FnName(FnName), TestFn(testFn) {} + + Expected doTest(std::vector &Prefix, + std::vector &Kept) override { + if (!Kept.empty() && TestFuncAttrs(Kept)) + return KeepSuffix; + if (!Prefix.empty() && TestFuncAttrs(Prefix)) + return KeepPrefix; + return NoFailure; + } + + bool TestFuncAttrs(std::vector &Attrs); +}; +} + +bool ReduceCrashingFunctionAttributes::TestFuncAttrs( + std::vector &Attrs) { + // Clone the program to try hacking it apart... + std::unique_ptr M = CloneModule(BD.getProgram()); + Function *F = M->getFunction(FnName); + + // Build up an AttributeList from the attributes we've been given by the + // reducer. + AttrBuilder AB; + for (auto A : Attrs) + AB.addAttribute(A); + AttributeList NewAttrs; + NewAttrs = + NewAttrs.addAttributes(BD.getContext(), AttributeList::FunctionIndex, AB); + + // Set this new list of attributes on the function. + F->setAttributes(NewAttrs); + + // Try running on the hacked up program... + if (TestFn(BD, M.get())) { + BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version... + + // Pass along the set of attributes that caused the crash. + Attrs.clear(); + for (Attribute A : NewAttrs.getFnAttributes()) { + Attrs.push_back(A); + } + return true; + } + return false; +} + +namespace { /// Simplify the CFG without completely destroying it. /// This is not well defined, but basically comes down to "try to eliminate /// unreachable blocks and constant fold terminators without deciding that @@ -1056,6 +1116,34 @@ BD.EmitProgressBitcode(BD.getProgram(), "reduced-function"); } + // For each remaining function, try to reduce that function's attributes. + std::vector FunctionNames; + for (Function &F : BD.getProgram()) + FunctionNames.push_back(F.getName()); + + if (!FunctionNames.empty() && !BugpointIsInterrupted) { + outs() << "\n*** Attempting to reduce the number of function attributes in " + "the testcase\n"; + + for (std::string &Name : FunctionNames) { + Function *Fn = BD.getProgram().getFunction(Name); + assert(Fn && "Could not find funcion?"); + + std::vector Attrs; + for (Attribute A : Fn->getAttributes().getFnAttributes()) + Attrs.push_back(A); + + unsigned OldSize = Attrs.size(); + Expected Result = + ReduceCrashingFunctionAttributes(BD, Name, TestFn).reduceList(Attrs); + if (Error E = Result.takeError()) + return E; + + if (Attrs.size() < OldSize) + BD.EmitProgressBitcode(BD.getProgram(), "reduced-function-attributes"); + } + } + // Attempt to change conditional branches into unconditional branches to // eliminate blocks. if (!DisableSimplifyCFG && !BugpointIsInterrupted) {