llvm.org GIT mirror llvm / 7b862ec
bugpoint Enhancement. Summary: This patch adds two flags to `bugpoint`: "-replace-funcs-with-null" and "-disable-pass-list-reduction". When "-replace-funcs-with-null" is specified, bugpoint will, instead of simply deleting function bodies, replace all uses of functions and then will delete functions completely from the test module, correctly handling aliasing and @llvm.used && @llvm.compiler.used. This part was conceived while trying to debug the PNaCl IR simplification passes, which don't allow undefined functions (ie no declarations). With "-disable-pass-list-reduction", bugpoint won't try to reduce the set of passes causing the "crash". This is needed in cases where one is trying to debug an issue inside the PNaCl IR simplification passes which is causing an PNaCl ABI verification error, for example. Reviewers: jfb Reviewed By: jfb Subscribers: jfb, llvm-commits Differential Revision: http://reviews.llvm.org/D8555 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235362 91177308-0d34-0410-b5e6-96231b3b80d8 JF Bastien 4 years ago
3 changed file(s) with 123 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
0 ; Test that bugpoint can reduce the set of functions by replacing them with null.
1 ;
2 ; RUN: bugpoint -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t -replace-funcs-with-null -bugpoint-crash-decl-funcs -silence-passes -safe-run-llc
3 ; REQUIRES: loadable_module
4
5 @foo2 = alias i32 ()* @foo
6
7 define i32 @foo() { ret i32 1 }
8
9 define i32 @test() {
10 call i32 @test()
11 ret i32 %1
12 }
13
14 define i32 @bar() { ret i32 2 }
15
16 @llvm.used = appending global [1 x i8*] [i8* bitcast (i32 ()* @foo to i8*)], section "llvm.metadata"
3939 NoGlobalRM ("disable-global-remove",
4040 cl::desc("Do not remove global variables"),
4141 cl::init(false));
42
43 cl::opt
44 ReplaceFuncsWithNull("replace-funcs-with-null",
45 cl::desc("When stubbing functions, replace all uses will null"),
46 cl::init(false));
47 cl::opt
48 DontReducePassList("disable-pass-list-reduction",
49 cl::desc("Skip pass list reduction steps"),
50 cl::init(false));
4251 }
4352
4453 namespace llvm {
193202 };
194203 }
195204
205 static void RemoveFunctionReferences(Module *M, const char* Name) {
206 auto *UsedVar = M->getGlobalVariable(Name, true);
207 if (!UsedVar || !UsedVar->hasInitializer()) return;
208 if (isa(UsedVar->getInitializer())) {
209 assert(UsedVar->use_empty());
210 UsedVar->eraseFromParent();
211 return;
212 }
213 auto *OldUsedVal = cast(UsedVar->getInitializer());
214 std::vector Used;
215 for(Value *V : OldUsedVal->operand_values()) {
216 Constant *Op = cast(V->stripPointerCasts());
217 if(!Op->isNullValue()) {
218 Used.push_back(cast(V));
219 }
220 }
221 auto *NewValElemTy = OldUsedVal->getType()->getElementType();
222 auto *NewValTy = ArrayType::get(NewValElemTy, Used.size());
223 auto *NewUsedVal = ConstantArray::get(NewValTy, Used);
224 UsedVar->mutateType(NewUsedVal->getType()->getPointerTo());
225 UsedVar->setInitializer(NewUsedVal);
226 }
227
196228 bool ReduceCrashingFunctions::TestFuncs(std::vector &Funcs) {
197229 // If main isn't present, claim there is no problem.
198230 if (KeepMain && std::find(Funcs.begin(), Funcs.end(),
217249 outs() << "Checking for crash with only these functions: ";
218250 PrintFunctionList(Funcs);
219251 outs() << ": ";
220
221 // Loop over and delete any functions which we aren't supposed to be playing
222 // with...
223 for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
224 if (!I->isDeclaration() && !Functions.count(I))
225 DeleteFunctionBody(I);
226
252 if (!ReplaceFuncsWithNull) {
253 // Loop over and delete any functions which we aren't supposed to be playing
254 // with...
255 for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
256 if (!I->isDeclaration() && !Functions.count(I))
257 DeleteFunctionBody(I);
258 } else {
259 std::vector ToRemove;
260 // First, remove aliases to functions we're about to purge.
261 for (GlobalAlias &Alias : M->aliases()) {
262 Constant *Root = Alias.getAliasee()->stripPointerCasts();
263 Function *F = dyn_cast(Root);
264 if (F) {
265 if (Functions.count(F))
266 // We're keeping this function.
267 continue;
268 } else if (Root->isNullValue()) {
269 // This referenced a globalalias that we've already replaced,
270 // so we still need to replace this alias.
271 } else if (!F) {
272 // Not a function, therefore not something we mess with.
273 continue;
274 }
275
276 PointerType *Ty = cast(Alias.getType());
277 Constant *Replacement = ConstantPointerNull::get(Ty);
278 Alias.replaceAllUsesWith(Replacement);
279 ToRemove.push_back(&Alias);
280 }
281
282 for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) {
283 if (!I->isDeclaration() && !Functions.count(I)) {
284 PointerType *Ty = cast(I->getType());
285 Constant *Replacement = ConstantPointerNull::get(Ty);
286 I->replaceAllUsesWith(Replacement);
287 ToRemove.push_back(I);
288 }
289 }
290
291 for (auto *F : ToRemove) {
292 F->eraseFromParent();
293 }
294
295 // Finally, remove any null members from any global intrinsic.
296 RemoveFunctionReferences(M, "llvm.used");
297 RemoveFunctionReferences(M, "llvm.compiler.used");
298 }
227299 // Try running the hacked up program...
228300 if (TestFn(BD, M)) {
229301 BD.setNewProgram(M); // It crashed, keep the trimmed version...
295367 (*SI)->removePredecessor(BB);
296368
297369 TerminatorInst *BBTerm = BB->getTerminator();
298
370
299371 if (!BB->getTerminator()->getType()->isVoidTy())
300372 BBTerm->replaceAllUsesWith(Constant::getNullValue(BBTerm->getType()));
301373
628700
629701 std::string Error;
630702 // Reduce the list of passes which causes the optimizer to crash...
631 if (!BugpointIsInterrupted)
703 if (!BugpointIsInterrupted && !DontReducePassList)
632704 ReducePassList(*this).reduceList(PassesToRun, Error);
633705 assert(Error.empty());
634706
6767 }
6868 };
6969 }
70
70
7171 char DeleteCalls::ID = 0;
7272 static RegisterPass
7373 Y("bugpoint-deletecalls",
7474 "BugPoint Test Pass - Intentionally 'misoptimize' CallInsts");
75
76 namespace {
77 /// CrashOnDeclFunc - This pass is used to test bugpoint. It intentionally
78 /// crash if the module has an undefined function (ie a function that is
79 /// defined in an external module).
80 class CrashOnDeclFunc : public ModulePass {
81 public:
82 static char ID; // Pass ID, replacement for typeid
83 CrashOnDeclFunc() : ModulePass(ID) {}
84 private:
85 bool runOnModule(Module &M) override {
86 for (auto &F : M.functions()) {
87 if (F.isDeclaration())
88 abort();
89 }
90 return false;
91 }
92 };
93 }
94
95 char CrashOnDeclFunc::ID = 0;
96 static RegisterPass
97 Z("bugpoint-crash-decl-funcs",
98 "BugPoint Test Pass - Intentionally crash on declared functions");