mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-22 20:20:03 +00:00
Factor this code out into a few methods.
Implement the start of global ctor optimization. It is currently smart enough to remove the global ctor for cases like this: struct foo { foo() {} } x; ... saving a bit of startup time for the program. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@23433 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
09eec56af0
commit
b1ab458047
@ -45,6 +45,7 @@ namespace {
|
||||
"Number of global vars shrunk to booleans");
|
||||
Statistic<> NumFastCallFns("globalopt",
|
||||
"Number of functions converted to fastcc");
|
||||
Statistic<> NumEmptyCtor ("globalopt", "Number of empty ctors removed");
|
||||
|
||||
struct GlobalOpt : public ModulePass {
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
@ -54,6 +55,10 @@ namespace {
|
||||
bool runOnModule(Module &M);
|
||||
|
||||
private:
|
||||
GlobalVariable *FindGlobalCtors(Module &M);
|
||||
bool OptimizeFunctions(Module &M);
|
||||
bool OptimizeGlobalVars(Module &M);
|
||||
bool OptimizeGlobalCtorsList(GlobalVariable *&GCL);
|
||||
bool ProcessInternalGlobal(GlobalVariable *GV, Module::global_iterator &GVI);
|
||||
};
|
||||
|
||||
@ -1077,47 +1082,199 @@ static void ChangeCalleesToFastCall(Function *F) {
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobalOpt::runOnModule(Module &M) {
|
||||
bool GlobalOpt::OptimizeFunctions(Module &M) {
|
||||
bool Changed = false;
|
||||
|
||||
// As a prepass, delete functions that are trivially dead.
|
||||
bool LocalChange = true;
|
||||
while (LocalChange) {
|
||||
LocalChange = false;
|
||||
for (Module::iterator FI = M.begin(), E = M.end(); FI != E; ) {
|
||||
Function *F = FI++;
|
||||
F->removeDeadConstantUsers();
|
||||
if (F->use_empty() && (F->hasInternalLinkage() ||
|
||||
F->hasLinkOnceLinkage())) {
|
||||
M.getFunctionList().erase(F);
|
||||
LocalChange = true;
|
||||
++NumFnDeleted;
|
||||
} else if (F->hasInternalLinkage() &&
|
||||
F->getCallingConv() == CallingConv::C && !F->isVarArg() &&
|
||||
OnlyCalledDirectly(F)) {
|
||||
// If this function has C calling conventions, is not a varargs
|
||||
// function, and is only called directly, promote it to use the Fast
|
||||
// calling convention.
|
||||
F->setCallingConv(CallingConv::Fast);
|
||||
ChangeCalleesToFastCall(F);
|
||||
++NumFastCallFns;
|
||||
LocalChange = true;
|
||||
}
|
||||
// Optimize functions.
|
||||
for (Module::iterator FI = M.begin(), E = M.end(); FI != E; ) {
|
||||
Function *F = FI++;
|
||||
F->removeDeadConstantUsers();
|
||||
if (F->use_empty() && (F->hasInternalLinkage() ||
|
||||
F->hasLinkOnceLinkage())) {
|
||||
M.getFunctionList().erase(F);
|
||||
Changed = true;
|
||||
++NumFnDeleted;
|
||||
} else if (F->hasInternalLinkage() &&
|
||||
F->getCallingConv() == CallingConv::C && !F->isVarArg() &&
|
||||
OnlyCalledDirectly(F)) {
|
||||
// If this function has C calling conventions, is not a varargs
|
||||
// function, and is only called directly, promote it to use the Fast
|
||||
// calling convention.
|
||||
F->setCallingConv(CallingConv::Fast);
|
||||
ChangeCalleesToFastCall(F);
|
||||
++NumFastCallFns;
|
||||
Changed = true;
|
||||
}
|
||||
Changed |= LocalChange;
|
||||
}
|
||||
|
||||
LocalChange = true;
|
||||
while (LocalChange) {
|
||||
LocalChange = false;
|
||||
for (Module::global_iterator GVI = M.global_begin(), E = M.global_end();
|
||||
GVI != E; ) {
|
||||
GlobalVariable *GV = GVI++;
|
||||
if (!GV->isConstant() && GV->hasInternalLinkage() &&
|
||||
GV->hasInitializer())
|
||||
LocalChange |= ProcessInternalGlobal(GV, GVI);
|
||||
}
|
||||
Changed |= LocalChange;
|
||||
}
|
||||
return Changed;
|
||||
}
|
||||
|
||||
bool GlobalOpt::OptimizeGlobalVars(Module &M) {
|
||||
bool Changed = false;
|
||||
for (Module::global_iterator GVI = M.global_begin(), E = M.global_end();
|
||||
GVI != E; ) {
|
||||
GlobalVariable *GV = GVI++;
|
||||
if (!GV->isConstant() && GV->hasInternalLinkage() &&
|
||||
GV->hasInitializer())
|
||||
Changed |= ProcessInternalGlobal(GV, GVI);
|
||||
}
|
||||
return Changed;
|
||||
}
|
||||
|
||||
/// FindGlobalCtors - Find the llvm.globalctors list, verifying that all
|
||||
/// initializers have an init priority of 65535.
|
||||
GlobalVariable *GlobalOpt::FindGlobalCtors(Module &M) {
|
||||
for (Module::giterator I = M.global_begin(), E = M.global_end(); I != E; ++I)
|
||||
if (I->getName() == "llvm.global_ctors") {
|
||||
// Found it, verify it's an array of { int, void()* }.
|
||||
const ArrayType *ATy =dyn_cast<ArrayType>(I->getType()->getElementType());
|
||||
if (!ATy) return 0;
|
||||
const StructType *STy = dyn_cast<StructType>(ATy->getElementType());
|
||||
if (!STy || STy->getNumElements() != 2 ||
|
||||
STy->getElementType(0) != Type::IntTy) return 0;
|
||||
const PointerType *PFTy = dyn_cast<PointerType>(STy->getElementType(1));
|
||||
if (!PFTy) return 0;
|
||||
const FunctionType *FTy = dyn_cast<FunctionType>(PFTy->getElementType());
|
||||
if (!FTy || FTy->getReturnType() != Type::VoidTy || FTy->isVarArg() ||
|
||||
FTy->getNumParams() != 0)
|
||||
return 0;
|
||||
|
||||
// Verify that the initializer is simple enough for us to handle.
|
||||
if (!I->hasInitializer()) return 0;
|
||||
ConstantArray *CA = dyn_cast<ConstantArray>(I->getInitializer());
|
||||
if (!CA) return 0;
|
||||
for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i)
|
||||
if (ConstantStruct *CS = dyn_cast<ConstantStruct>(CA->getOperand(i))) {
|
||||
// Init priority must be standard.
|
||||
ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
|
||||
if (!CI || CI->getRawValue() != 65535)
|
||||
return 0;
|
||||
|
||||
// Must have a function or null ptr.
|
||||
if (!isa<Function>(CS->getOperand(1)) &&
|
||||
!isa<ConstantPointerNull>(CS->getOperand(1)))
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return I;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::vector<Function*> ParseGlobalCtors(GlobalVariable *GV) {
|
||||
ConstantArray *CA = cast<ConstantArray>(GV->getInitializer());
|
||||
std::vector<Function*> Result;
|
||||
Result.reserve(CA->getNumOperands());
|
||||
for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
|
||||
ConstantStruct *CS = cast<ConstantStruct>(CA->getOperand(i));
|
||||
Result.push_back(dyn_cast<Function>(CS->getOperand(1)));
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// OptimizeGlobalCtorsList - Simplify and evaluation global ctors if possible.
|
||||
/// Return true if anything changed.
|
||||
bool GlobalOpt::OptimizeGlobalCtorsList(GlobalVariable *&GCL) {
|
||||
std::vector<Function*> Ctors = ParseGlobalCtors(GCL);
|
||||
bool MadeChange = false;
|
||||
if (Ctors.empty()) return false;
|
||||
|
||||
// Loop over global ctors, optimizing them when we can.
|
||||
for (unsigned i = 0; i != Ctors.size(); ++i) {
|
||||
Function *F = Ctors[i];
|
||||
// Found a null terminator in the middle of the list, prune off the rest of
|
||||
// the list.
|
||||
if (F == 0 && i != Ctors.size()-1) {
|
||||
Ctors.resize(i+1);
|
||||
MadeChange = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the function is empty, just remove it from the ctor list.
|
||||
if (!F->empty() && isa<ReturnInst>(F->begin()->getTerminator()) &&
|
||||
&F->begin()->front() == F->begin()->getTerminator()) {
|
||||
Ctors.erase(Ctors.begin()+i);
|
||||
MadeChange = true;
|
||||
--i;
|
||||
++NumEmptyCtor;
|
||||
}
|
||||
}
|
||||
|
||||
if (!MadeChange) return false;
|
||||
|
||||
std::vector<Constant*> CSVals;
|
||||
CSVals.push_back(ConstantSInt::get(Type::IntTy, 65535));
|
||||
CSVals.push_back(0);
|
||||
|
||||
// Create the new init list.
|
||||
std::vector<Constant*> CAList;
|
||||
for (unsigned i = 0, e = Ctors.size(); i != e; ++i) {
|
||||
if (Ctors[i])
|
||||
CSVals[1] = Ctors[i];
|
||||
else {
|
||||
const Type *FTy = FunctionType::get(Type::VoidTy,
|
||||
std::vector<const Type*>(), false);
|
||||
const PointerType *PFTy = PointerType::get(FTy);
|
||||
CSVals[1] = Constant::getNullValue(PFTy);
|
||||
}
|
||||
CAList.push_back(ConstantStruct::get(CSVals));
|
||||
}
|
||||
|
||||
// Create the array initializer.
|
||||
const Type *StructTy =
|
||||
cast<ArrayType>(GCL->getType()->getElementType())->getElementType();
|
||||
Constant *CA = ConstantArray::get(ArrayType::get(StructTy, CAList.size()),
|
||||
CAList);
|
||||
|
||||
// Create the new global and insert it next to the existing list.
|
||||
GlobalVariable *NGV = new GlobalVariable(CA->getType(), GCL->isConstant(),
|
||||
GCL->getLinkage(), CA,
|
||||
GCL->getName());
|
||||
GCL->setName("");
|
||||
GCL->getParent()->getGlobalList().insert(GCL, NGV);
|
||||
|
||||
// Nuke the old list, replacing any uses with the new one.
|
||||
if (!GCL->use_empty()) {
|
||||
Constant *V = NGV;
|
||||
if (V->getType() != GCL->getType())
|
||||
V = ConstantExpr::getCast(V, GCL->getType());
|
||||
GCL->replaceAllUsesWith(V);
|
||||
}
|
||||
GCL->eraseFromParent();
|
||||
|
||||
if (Ctors.size())
|
||||
GCL = NGV;
|
||||
else
|
||||
GCL = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GlobalOpt::runOnModule(Module &M) {
|
||||
bool Changed = false;
|
||||
|
||||
// Try to find the llvm.globalctors list.
|
||||
GlobalVariable *GlobalCtors = FindGlobalCtors(M);
|
||||
|
||||
bool LocalChange = true;
|
||||
while (LocalChange) {
|
||||
LocalChange = false;
|
||||
|
||||
// Delete functions that are trivially dead, ccc -> fastcc
|
||||
LocalChange |= OptimizeFunctions(M);
|
||||
|
||||
// Optimize global_ctors list.
|
||||
if (GlobalCtors)
|
||||
LocalChange |= OptimizeGlobalCtorsList(GlobalCtors);
|
||||
|
||||
// Optimize non-address-taken globals.
|
||||
LocalChange |= OptimizeGlobalVars(M);
|
||||
Changed |= LocalChange;
|
||||
}
|
||||
|
||||
// TODO: Move all global ctors functions to the end of the module for code
|
||||
// layout.
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user