[bugpoint] Fix "Alias must point to a definition" problems

GlobalAliases may reference function definitions, but not function declarations.

bugpoint would sometimes create invalid IR by deleting a function's body (thus
mutating a function definition into a declaration) without first 'fixing' any
GlobalAliases that reference that function definition.

This change iteratively prevents that issue. Before deleting a function's body,
it scans the module for GlobalAliases which reference that function. When
found, it eliminates them using replaceAllUsesWith.

Fixes PR20788.

Patch by Nick Johnson!

llvm-svn: 254171
This commit is contained in:
Hal Finkel 2015-11-26 19:23:49 +00:00
parent 8934577171
commit 28ad2b47dd
3 changed files with 41 additions and 4 deletions

View File

@ -321,6 +321,11 @@ void PrintFunctionList(const std::vector<Function*> &Funcs);
///
void PrintGlobalVariableList(const std::vector<GlobalVariable*> &GVs);
// DeleteGlobalInitializer - "Remove" the global variable by deleting its
// initializer, making it external.
//
void DeleteGlobalInitializer(GlobalVariable *GV);
// DeleteFunctionBody - "Remove" the function by deleting all of it's basic
// blocks, making it external.
//

View File

@ -162,7 +162,7 @@ ReduceCrashingGlobalVariables::TestGlobalVariables(
// playing with...
for (GlobalVariable &I : M->globals())
if (I.hasInitializer() && !GVSet.count(&I)) {
I.setInitializer(nullptr);
DeleteGlobalInitializer(&I);
I.setLinkage(GlobalValue::ExternalLinkage);
}
@ -664,7 +664,7 @@ static bool DebugACrash(BugDriver &BD,
for (Module::global_iterator I = M->global_begin(), E = M->global_end();
I != E; ++I)
if (I->hasInitializer()) {
I->setInitializer(nullptr);
DeleteGlobalInitializer(&*I);
I->setLinkage(GlobalValue::ExternalLinkage);
DeletedInit = true;
}

View File

@ -179,11 +179,43 @@ std::unique_ptr<Module> BugDriver::extractLoop(Module *M) {
return NewM;
}
static void eliminateAliases(GlobalValue *GV) {
// First, check whether a GlobalAlias references this definition.
// GlobalAlias MAY NOT reference declarations.
for (;;) {
// 1. Find aliases
SmallVector<GlobalAlias*,1> aliases;
Module *M = GV->getParent();
for (Module::alias_iterator I=M->alias_begin(), E=M->alias_end(); I!=E; ++I)
if (I->getAliasee()->stripPointerCasts() == GV)
aliases.push_back(&*I);
if (aliases.empty())
break;
// 2. Resolve aliases
for (unsigned i=0, e=aliases.size(); i<e; ++i) {
aliases[i]->replaceAllUsesWith(aliases[i]->getAliasee());
aliases[i]->eraseFromParent();
}
// 3. Repeat until no more aliases found; there might
// be an alias to an alias...
}
}
//
// DeleteGlobalInitializer - "Remove" the global variable by deleting its initializer,
// making it external.
//
void llvm::DeleteGlobalInitializer(GlobalVariable *GV) {
eliminateAliases(GV);
GV->setInitializer(nullptr);
}
// DeleteFunctionBody - "Remove" the function by deleting all of its basic
// blocks, making it external.
//
void llvm::DeleteFunctionBody(Function *F) {
eliminateAliases(F);
// delete the body of the function...
F->deleteBody();
assert(F->isDeclaration() && "This didn't make the function external!");
@ -323,10 +355,10 @@ llvm::SplitFunctionsOutOfModule(Module *M,
<< "' and from test function '" << TestFn->getName() << "'.\n";
exit(1);
}
I.setInitializer(nullptr); // Delete the initializer to make it external
DeleteGlobalInitializer(&I); // Delete the initializer to make it external
} else {
// If we keep it in the safe module, then delete it in the test module
GV->setInitializer(nullptr);
DeleteGlobalInitializer(GV);
}
}