From 79550f6c951ba7cd70ddacd28b42d6e56116ce80 Mon Sep 17 00:00:00 2001 From: Brian Gesiak Date: Wed, 19 Dec 2018 03:42:19 +0000 Subject: [PATCH] [bugpoint][PR29027] Reduce function attributes Summary: In addition to reducing the functions in an LLVM module, bugpoint now reduces the function attributes associated with each of the remaining functions. To test this, add a -bugpoint-crashfuncattr test pass, which crashes if a function in the module has a "bugpoint-crash" attribute. A test case demonstrates that the IR is reduced to just that one attribute. Reviewers: MatzeB, silvas, davide, reames Reviewed By: reames Subscribers: reames, llvm-commits Differential Revision: https://reviews.llvm.org/D55216 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@349601 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/BugPoint/func-attrs-keyval.ll | 11 +++++ test/BugPoint/func-attrs.ll | 11 +++++ tools/bugpoint-passes/TestPasses.cpp | 25 ++++++++++ tools/bugpoint/CrashDebugger.cpp | 92 ++++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 test/BugPoint/func-attrs-keyval.ll create mode 100644 test/BugPoint/func-attrs.ll diff --git a/test/BugPoint/func-attrs-keyval.ll b/test/BugPoint/func-attrs-keyval.ll new file mode 100644 index 00000000000..830d0964cde --- /dev/null +++ b/test/BugPoint/func-attrs-keyval.ll @@ -0,0 +1,11 @@ +; 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() #[[ATTRS:[0-9]+]] +define void @f() #0 { + ret void +} + +; CHECK: attributes #[[ATTRS]] = { "bugpoint-crash"="sure" } +attributes #0 = { "bugpoint-crash"="sure" noreturn "no-frame-pointer-elim-non-leaf" } diff --git a/test/BugPoint/func-attrs.ll b/test/BugPoint/func-attrs.ll new file mode 100644 index 00000000000..3941e73c217 --- /dev/null +++ b/test/BugPoint/func-attrs.ll @@ -0,0 +1,11 @@ +; 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() #[[ATTRS:[0-9]+]] +define void @f() #0 { + ret void +} + +; CHECK: attributes #[[ATTRS]] = { "bugpoint-crash" } +attributes #0 = { noinline "bugpoint-crash" "no-frame-pointer-elim-non-leaf" } diff --git a/tools/bugpoint-passes/TestPasses.cpp b/tools/bugpoint-passes/TestPasses.cpp index 22ded6261a1..6b1463685b2 100644 --- a/tools/bugpoint-passes/TestPasses.cpp +++ b/tools/bugpoint-passes/TestPasses.cpp @@ -123,3 +123,28 @@ char CrashOnTooManyCUs::ID = 0; 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'"); diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index a50ff4c255b..ef6a214fde2 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -315,6 +315,66 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector &Funcs) { } 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,38 @@ static Error DebugACrash(BugDriver &BD, BugTester TestFn) { 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"; + + unsigned OldSize = 0; + unsigned NewSize = 0; + 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); + + OldSize += Attrs.size(); + Expected Result = + ReduceCrashingFunctionAttributes(BD, Name, TestFn).reduceList(Attrs); + if (Error E = Result.takeError()) + return E; + + NewSize += Attrs.size(); + } + + if (OldSize < NewSize) + BD.EmitProgressBitcode(BD.getProgram(), "reduced-function-attributes"); + } + // Attempt to change conditional branches into unconditional branches to // eliminate blocks. if (!DisableSimplifyCFG && !BugpointIsInterrupted) { -- 2.11.0