[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

llvm-svn: 349601
This commit is contained in:
Brian Gesiak 2018-12-19 03:42:19 +00:00
parent 329ea467f2
commit dd4a470df3
4 changed files with 139 additions and 0 deletions

View File

@ -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" }

View File

@ -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" }

View File

@ -123,3 +123,28 @@ char CrashOnTooManyCUs::ID = 0;
static RegisterPass<CrashOnTooManyCUs>
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<CrashOnFunctionAttribute>
B("bugpoint-crashfuncattr", "BugPoint Test Pass - Intentionally crash on "
"function attribute 'bugpoint-crash'");

View File

@ -314,6 +314,66 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function *> &Funcs) {
return false;
}
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<Attribute> {
BugDriver &BD;
std::string FnName;
BugTester TestFn;
public:
ReduceCrashingFunctionAttributes(BugDriver &bd, const std::string &FnName,
BugTester testFn)
: BD(bd), FnName(FnName), TestFn(testFn) {}
Expected<TestResult> doTest(std::vector<Attribute> &Prefix,
std::vector<Attribute> &Kept) override {
if (!Kept.empty() && TestFuncAttrs(Kept))
return KeepSuffix;
if (!Prefix.empty() && TestFuncAttrs(Prefix))
return KeepPrefix;
return NoFailure;
}
bool TestFuncAttrs(std::vector<Attribute> &Attrs);
};
}
bool ReduceCrashingFunctionAttributes::TestFuncAttrs(
std::vector<Attribute> &Attrs) {
// Clone the program to try hacking it apart...
std::unique_ptr<Module> 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
@ -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<std::string> 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<Attribute> Attrs;
for (Attribute A : Fn->getAttributes().getFnAttributes())
Attrs.push_back(A);
OldSize += Attrs.size();
Expected<bool> 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) {