#include <set>
using namespace llvm;
-namespace {
- Statistic<> NumMarked ("globalopt", "Number of globals marked constant");
- Statistic<> NumSRA ("globalopt", "Number of aggregate globals broken "
- "into scalars");
- Statistic<> NumHeapSRA ("globalopt", "Number of heap objects SRA'd");
- Statistic<> NumSubstitute("globalopt",
- "Number of globals with initializers stored into them");
- Statistic<> NumDeleted ("globalopt", "Number of globals deleted");
- Statistic<> NumFnDeleted("globalopt", "Number of functions deleted");
- Statistic<> NumGlobUses ("globalopt", "Number of global uses devirtualized");
- Statistic<> NumLocalized("globalopt", "Number of globals localized");
- Statistic<> NumShrunkToBool("globalopt",
- "Number of global vars shrunk to booleans");
- Statistic<> NumFastCallFns("globalopt",
- "Number of functions converted to fastcc");
- Statistic<> NumCtorsEvaluated("globalopt","Number of static ctors evaluated");
+STATISTIC(NumMarked , "Number of globals marked constant");
+STATISTIC(NumSRA , "Number of aggregate globals broken into scalars");
+STATISTIC(NumHeapSRA , "Number of heap objects SRA'd");
+STATISTIC(NumSubstitute,"Number of globals with initializers stored into them");
+STATISTIC(NumDeleted , "Number of globals deleted");
+STATISTIC(NumFnDeleted , "Number of functions deleted");
+STATISTIC(NumGlobUses , "Number of global uses devirtualized");
+STATISTIC(NumLocalized , "Number of globals localized");
+STATISTIC(NumShrunkToBool , "Number of global vars shrunk to booleans");
+STATISTIC(NumFastCallFns , "Number of functions converted to fastcc");
+STATISTIC(NumCtorsEvaluated, "Number of static ctors evaluated");
+namespace {
struct GlobalOpt : public ModulePass {
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<TargetData>();
if (AnalyzeGlobal(I, GS, PHIUsers)) return true;
GS.isNotSuitableForSRA = true;
GS.HasPHIUser = true;
- } else if (isa<SetCondInst>(I)) {
+ } else if (isa<CmpInst>(I)) {
GS.isNotSuitableForSRA = true;
} else if (isa<MemCpyInst>(I) || isa<MemMoveInst>(I)) {
if (I->getOperand(1) == V)
if (Init)
SubInit = ConstantFoldLoadThroughGEPConstantExpr(Init, CE);
Changed |= CleanupConstantGlobalUsers(CE, SubInit);
- } else if (CE->getOpcode() == Instruction::Cast &&
+ } else if (CE->getOpcode() == Instruction::BitCast &&
isa<PointerType>(CE->getType())) {
// Pointer cast, delete any stores and memsets to the global.
Changed |= CleanupConstantGlobalUsers(CE, 0);
NewGlobals.reserve(STy->getNumElements());
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
Constant *In = getAggregateConstantElement(Init,
- ConstantInt::get(Type::UIntTy, i));
+ ConstantInt::get(Type::Int32Ty, i));
assert(In && "Couldn't get element of initializer?");
GlobalVariable *NGV = new GlobalVariable(STy->getElementType(i), false,
GlobalVariable::InternalLinkage,
NewGlobals.reserve(NumElements);
for (unsigned i = 0, e = NumElements; i != e; ++i) {
Constant *In = getAggregateConstantElement(Init,
- ConstantInt::get(Type::UIntTy, i));
+ ConstantInt::get(Type::Int32Ty, i));
assert(In && "Couldn't get element of initializer?");
GlobalVariable *NGV = new GlobalVariable(STy->getElementType(), false,
DOUT << "PERFORMING GLOBAL SRA ON: " << *GV;
- Constant *NullInt = Constant::getNullValue(Type::IntTy);
+ Constant *NullInt = Constant::getNullValue(Type::Int32Ty);
// Loop over all of the uses of the global, replacing the constantexpr geps,
// with smaller constantexpr geps or direct references.
// Will trap.
} else if (StoreInst *SI = dyn_cast<StoreInst>(*UI)) {
if (SI->getOperand(0) == V) {
- //llvm_cerr << "NONTRAPPING USE: " << **UI;
+ //cerr << "NONTRAPPING USE: " << **UI;
return false; // Storing the value.
}
} else if (CallInst *CI = dyn_cast<CallInst>(*UI)) {
if (CI->getOperand(0) != V) {
- //llvm_cerr << "NONTRAPPING USE: " << **UI;
+ //cerr << "NONTRAPPING USE: " << **UI;
return false; // Not calling the ptr
}
} else if (InvokeInst *II = dyn_cast<InvokeInst>(*UI)) {
if (II->getOperand(0) != V) {
- //llvm_cerr << "NONTRAPPING USE: " << **UI;
+ //cerr << "NONTRAPPING USE: " << **UI;
return false; // Not calling the ptr
}
} else if (CastInst *CI = dyn_cast<CastInst>(*UI)) {
if (!AllUsesOfValueWillTrapIfNull(CI)) return false;
} else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(*UI)) {
if (!AllUsesOfValueWillTrapIfNull(GEPI)) return false;
- } else if (isa<SetCondInst>(*UI) &&
+ } else if (isa<ICmpInst>(*UI) &&
isa<ConstantPointerNull>(UI->getOperand(1))) {
// Ignore setcc X, null
} else {
- //llvm_cerr << "NONTRAPPING USE: " << **UI;
+ //cerr << "NONTRAPPING USE: " << **UI;
return false;
}
return true;
// Ignore stores to the global.
} else {
// We don't know or understand this user, bail out.
- //llvm_cerr << "UNKNOWN USER OF GLOBAL!: " << **UI;
+ //cerr << "UNKNOWN USER OF GLOBAL!: " << **UI;
return false;
}
}
} else if (CastInst *CI = dyn_cast<CastInst>(I)) {
Changed |= OptimizeAwayTrappingUsesOfValue(CI,
- ConstantExpr::getCast(NewV, CI->getType()));
+ ConstantExpr::getCast(CI->getOpcode(),
+ NewV, CI->getType()));
if (CI->use_empty()) {
Changed = true;
CI->eraseFromParent();
/// variable, and transforms the program as if it always contained the result of
/// the specified malloc. Because it is always the result of the specified
/// malloc, there is no reason to actually DO the malloc. Instead, turn the
-/// malloc into a global, and any laods of GV as uses of the new global.
+/// malloc into a global, and any loads of GV as uses of the new global.
static GlobalVariable *OptimizeGlobalAddressOfMalloc(GlobalVariable *GV,
MallocInst *MI) {
DOUT << "PROMOTING MALLOC GLOBAL: " << *GV << " MALLOC = " << *MI;
Type *NewTy = ArrayType::get(MI->getAllocatedType(),
NElements->getZExtValue());
MallocInst *NewMI =
- new MallocInst(NewTy, Constant::getNullValue(Type::UIntTy),
+ new MallocInst(NewTy, Constant::getNullValue(Type::Int32Ty),
MI->getAlignment(), MI->getName(), MI);
std::vector<Value*> Indices;
- Indices.push_back(Constant::getNullValue(Type::IntTy));
+ Indices.push_back(Constant::getNullValue(Type::Int32Ty));
Indices.push_back(Indices[0]);
Value *NewGEP = new GetElementPtrInst(NewMI, Indices,
NewMI->getName()+".el0", MI);
Constant *RepValue = NewGV;
if (NewGV->getType() != GV->getType()->getElementType())
- RepValue = ConstantExpr::getCast(RepValue, GV->getType()->getElementType());
+ RepValue = ConstantExpr::getBitCast(RepValue,
+ GV->getType()->getElementType());
// If there is a comparison against null, we will insert a global bool to
// keep track of whether the global was initialized yet or not.
GlobalVariable *InitBool =
- new GlobalVariable(Type::BoolTy, false, GlobalValue::InternalLinkage,
- ConstantBool::getFalse(), GV->getName()+".init");
+ new GlobalVariable(Type::Int1Ty, false, GlobalValue::InternalLinkage,
+ ConstantInt::getFalse(), GV->getName()+".init");
bool InitBoolUsed = false;
// Loop over all uses of GV, processing them in turn.
if (LoadInst *LI = dyn_cast<LoadInst>(GV->use_back())) {
while (!LI->use_empty()) {
Use &LoadUse = LI->use_begin().getUse();
- if (!isa<SetCondInst>(LoadUse.getUser()))
+ if (!isa<ICmpInst>(LoadUse.getUser()))
LoadUse = RepValue;
else {
- // Replace the setcc X, 0 with a use of the bool value.
- SetCondInst *SCI = cast<SetCondInst>(LoadUse.getUser());
- Value *LV = new LoadInst(InitBool, InitBool->getName()+".val", SCI);
+ ICmpInst *CI = cast<ICmpInst>(LoadUse.getUser());
+ // Replace the cmp X, 0 with a use of the bool value.
+ Value *LV = new LoadInst(InitBool, InitBool->getName()+".val", CI);
InitBoolUsed = true;
- switch (SCI->getOpcode()) {
- default: assert(0 && "Unknown opcode!");
- case Instruction::SetLT:
- LV = ConstantBool::getFalse(); // X < null -> always false
+ switch (CI->getPredicate()) {
+ default: assert(0 && "Unknown ICmp Predicate!");
+ case ICmpInst::ICMP_ULT:
+ case ICmpInst::ICMP_SLT:
+ LV = ConstantInt::getFalse(); // X < null -> always false
break;
- case Instruction::SetEQ:
- case Instruction::SetLE:
- LV = BinaryOperator::createNot(LV, "notinit", SCI);
+ case ICmpInst::ICMP_ULE:
+ case ICmpInst::ICMP_SLE:
+ case ICmpInst::ICMP_EQ:
+ LV = BinaryOperator::createNot(LV, "notinit", CI);
break;
- case Instruction::SetNE:
- case Instruction::SetGE:
- case Instruction::SetGT:
+ case ICmpInst::ICMP_NE:
+ case ICmpInst::ICMP_UGE:
+ case ICmpInst::ICMP_SGE:
+ case ICmpInst::ICMP_UGT:
+ case ICmpInst::ICMP_SGT:
break; // no change.
}
- SCI->replaceAllUsesWith(LV);
- SCI->eraseFromParent();
+ CI->replaceAllUsesWith(LV);
+ CI->eraseFromParent();
}
}
LI->eraseFromParent();
} else {
StoreInst *SI = cast<StoreInst>(GV->use_back());
// The global is initialized when the store to it occurs.
- new StoreInst(ConstantBool::getTrue(), InitBool, SI);
+ new StoreInst(ConstantInt::getTrue(), InitBool, SI);
SI->eraseFromParent();
}
static bool ValueIsOnlyUsedLocallyOrStoredToOneGlobal(Instruction *V,
GlobalVariable *GV) {
for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI)
- if (isa<LoadInst>(*UI) || isa<SetCondInst>(*UI)) {
+ if (isa<LoadInst>(*UI) || isa<CmpInst>(*UI)) {
// Fine, ignore.
} else if (StoreInst *SI = dyn_cast<StoreInst>(*UI)) {
if (SI->getOperand(0) == V && SI->getOperand(1) != GV)
for (Value::use_iterator UI = LI->use_begin(), E = LI->use_end(); UI != E;
++UI) {
// Comparison against null is ok.
- if (SetCondInst *SCI = dyn_cast<SetCondInst>(*UI)) {
- if (!isa<ConstantPointerNull>(SCI->getOperand(1)))
+ if (ICmpInst *ICI = dyn_cast<ICmpInst>(*UI)) {
+ if (!isa<ConstantPointerNull>(ICI->getOperand(1)))
return false;
continue;
}
Instruction *User = Ptr->use_back();
// If this is a comparison against null, handle it.
- if (SetCondInst *SCI = dyn_cast<SetCondInst>(User)) {
+ if (ICmpInst *SCI = dyn_cast<ICmpInst>(User)) {
assert(isa<ConstantPointerNull>(SCI->getOperand(1)));
// If we have a setcc of the loaded pointer, we can use a setcc of any
// field.
NPtr = InsertedLoadsForPtr.back();
}
- Value *New = new SetCondInst(SCI->getOpcode(), NPtr,
- Constant::getNullValue(NPtr->getType()),
- SCI->getName(), SCI);
+ Value *New = new ICmpInst(SCI->getPredicate(), NPtr,
+ Constant::getNullValue(NPtr->getType()),
+ SCI->getName(), SCI);
SCI->replaceAllUsesWith(New);
SCI->eraseFromParent();
continue;
// Otherwise, this should be: 'getelementptr Ptr, Idx, uint FieldNo ...'
GetElementPtrInst *GEPI = cast<GetElementPtrInst>(User);
assert(GEPI->getNumOperands() >= 3 && isa<ConstantInt>(GEPI->getOperand(2))
- && GEPI->getOperand(2)->getType()->isUnsigned()
&& "Unexpected GEPI!");
// Load the pointer for this field.
// }
Value *RunningOr = 0;
for (unsigned i = 0, e = FieldMallocs.size(); i != e; ++i) {
- Value *Cond = new SetCondInst(Instruction::SetEQ, FieldMallocs[i],
+ Value *Cond = new ICmpInst(ICmpInst::ICMP_EQ, FieldMallocs[i],
Constant::getNullValue(FieldMallocs[i]->getType()),
"isnull", MI);
if (!RunningOr)
// pointer, because some may be null while others are not.
for (unsigned i = 0, e = FieldGlobals.size(); i != e; ++i) {
Value *GVVal = new LoadInst(FieldGlobals[i], "tmp", NullPtrBlock);
- Value *Cmp = new SetCondInst(Instruction::SetNE, GVVal,
- Constant::getNullValue(GVVal->getType()),
- "tmp", NullPtrBlock);
+ Value *Cmp = new ICmpInst(ICmpInst::ICMP_NE, GVVal,
+ Constant::getNullValue(GVVal->getType()),
+ "tmp", NullPtrBlock);
BasicBlock *FreeBlock = new BasicBlock("free_it", OrigBB->getParent());
BasicBlock *NextBlock = new BasicBlock("next", OrigBB->getParent());
new BranchInst(FreeBlock, NextBlock, Cmp, NullPtrBlock);
// loads, and all uses of those loads are simple. Rewrite them to use loads
// of the per-field globals instead.
while (!GV->use_empty()) {
- LoadInst *LI = cast<LoadInst>(GV->use_back());
- RewriteUsesOfLoadForHeapSRoA(LI, FieldGlobals);
- LI->eraseFromParent();
+ if (LoadInst *LI = dyn_cast<LoadInst>(GV->use_back())) {
+ RewriteUsesOfLoadForHeapSRoA(LI, FieldGlobals);
+ LI->eraseFromParent();
+ } else {
+ // Must be a store of null.
+ StoreInst *SI = cast<StoreInst>(GV->use_back());
+ assert(isa<Constant>(SI->getOperand(0)) &&
+ cast<Constant>(SI->getOperand(0))->isNullValue() &&
+ "Unexpected heap-sra user!");
+
+ // Insert a store of null into each global.
+ for (unsigned i = 0, e = FieldGlobals.size(); i != e; ++i) {
+ Constant *Null =
+ Constant::getNullValue(FieldGlobals[i]->getType()->getElementType());
+ new StoreInst(Null, FieldGlobals[i], SI);
+ }
+ // Erase the original store.
+ SI->eraseFromParent();
+ }
}
// The old global is now dead, remove it.
GV->getInitializer()->isNullValue()) {
if (Constant *SOVC = dyn_cast<Constant>(StoredOnceVal)) {
if (GV->getInitializer()->getType() != SOVC->getType())
- SOVC = ConstantExpr::getCast(SOVC, GV->getInitializer()->getType());
+ SOVC = ConstantExpr::getBitCast(SOVC, GV->getInitializer()->getType());
// Optimize away any trapping uses of the loaded value.
if (OptimizeAwayTrappingUsesOfLoads(GV, SOVC))
/// values ever stored into GV are its initializer and OtherVal.
static void ShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) {
// Create the new global, initializing it to false.
- GlobalVariable *NewGV = new GlobalVariable(Type::BoolTy, false,
- GlobalValue::InternalLinkage, ConstantBool::getFalse(),
+ GlobalVariable *NewGV = new GlobalVariable(Type::Int1Ty, false,
+ GlobalValue::InternalLinkage, ConstantInt::getFalse(),
GV->getName()+".b");
GV->getParent()->getGlobalList().insert(GV, NewGV);
Constant *InitVal = GV->getInitializer();
- assert(InitVal->getType() != Type::BoolTy && "No reason to shrink to bool!");
+ assert(InitVal->getType() != Type::Int1Ty && "No reason to shrink to bool!");
// If initialized to zero and storing one into the global, we can use a cast
// instead of a select to synthesize the desired value.
// Only do this if we weren't storing a loaded value.
Value *StoreVal;
if (StoringOther || SI->getOperand(0) == InitVal)
- StoreVal = ConstantBool::get(StoringOther);
+ StoreVal = ConstantInt::get(Type::Int1Ty, StoringOther);
else {
// Otherwise, we are storing a previously loaded copy. To do this,
// change the copy from copying the original value to just copying the
LoadInst *NLI = new LoadInst(NewGV, Name+".b", LI);
Value *NSI;
if (IsOneZero)
- NSI = new CastInst(NLI, LI->getType(), Name, LI);
+ NSI = new ZExtInst(NLI, LI->getType(), Name, LI);
else
NSI = new SelectInst(NLI, OtherVal, InitVal, Name, LI);
LI->replaceAllUsesWith(NSI);
if (!AnalyzeGlobal(GV, GS, PHIUsers)) {
#if 0
- llvm_cerr << "Global: " << *GV;
- llvm_cerr << " isLoaded = " << GS.isLoaded << "\n";
- llvm_cerr << " StoredType = ";
+ cerr << "Global: " << *GV;
+ cerr << " isLoaded = " << GS.isLoaded << "\n";
+ cerr << " StoredType = ";
switch (GS.StoredType) {
- case GlobalStatus::NotStored: llvm_cerr << "NEVER STORED\n"; break;
- case GlobalStatus::isInitializerStored: llvm_cerr << "INIT STORED\n"; break;
- case GlobalStatus::isStoredOnce: llvm_cerr << "STORED ONCE\n"; break;
- case GlobalStatus::isStored: llvm_cerr << "stored\n"; break;
+ case GlobalStatus::NotStored: cerr << "NEVER STORED\n"; break;
+ case GlobalStatus::isInitializerStored: cerr << "INIT STORED\n"; break;
+ case GlobalStatus::isStoredOnce: cerr << "STORED ONCE\n"; break;
+ case GlobalStatus::isStored: cerr << "stored\n"; break;
}
if (GS.StoredType == GlobalStatus::isStoredOnce && GS.StoredOnceValue)
- llvm_cerr << " StoredOnceValue = " << *GS.StoredOnceValue << "\n";
+ cerr << " StoredOnceValue = " << *GS.StoredOnceValue << "\n";
if (GS.AccessingFunction && !GS.HasMultipleAccessingFunctions)
- llvm_cerr << " AccessingFunction = " << GS.AccessingFunction->getName()
+ cerr << " AccessingFunction = " << GS.AccessingFunction->getName()
<< "\n";
- llvm_cerr << " HasMultipleAccessingFunctions = "
+ cerr << " HasMultipleAccessingFunctions = "
<< GS.HasMultipleAccessingFunctions << "\n";
- llvm_cerr << " HasNonInstructionUser = " << GS.HasNonInstructionUser<<"\n";
- llvm_cerr << " isNotSuitableForSRA = " << GS.isNotSuitableForSRA << "\n";
- llvm_cerr << "\n";
+ cerr << " HasNonInstructionUser = " << GS.HasNonInstructionUser<<"\n";
+ cerr << " isNotSuitableForSRA = " << GS.isNotSuitableForSRA << "\n";
+ cerr << "\n";
#endif
// If this is a first class global and has only one accessing function
// Otherwise, if the global was not a boolean, we can shrink it to be a
// boolean.
if (Constant *SOVConstant = dyn_cast<Constant>(GS.StoredOnceValue))
- if (GV->getType()->getElementType() != Type::BoolTy &&
+ if (GV->getType()->getElementType() != Type::Int1Ty &&
!GV->getType()->getElementType()->isFloatingPoint() &&
+ !isa<PackedType>(GV->getType()->getElementType()) &&
!GS.HasPHIUser) {
DOUT << " *** SHRINKING TO BOOL: " << *GV;
ShrinkGlobalToBoolean(GV, SOVConstant);
if (!ATy) return 0;
const StructType *STy = dyn_cast<StructType>(ATy->getElementType());
if (!STy || STy->getNumElements() != 2 ||
- STy->getElementType(0) != Type::IntTy) return 0;
+ STy->getElementType(0) != Type::Int32Ty) return 0;
const PointerType *PFTy = dyn_cast<PointerType>(STy->getElementType(1));
if (!PFTy) return 0;
const FunctionType *FTy = dyn_cast<FunctionType>(PFTy->getElementType());
const std::vector<Function*> &Ctors) {
// If we made a change, reassemble the initializer list.
std::vector<Constant*> CSVals;
- CSVals.push_back(ConstantInt::get(Type::IntTy, 65535));
+ CSVals.push_back(ConstantInt::get(Type::Int32Ty, 65535));
CSVals.push_back(0);
// Create the new init list.
std::vector<const Type*>(), false);
const PointerType *PFTy = PointerType::get(FTy);
CSVals[1] = Constant::getNullValue(PFTy);
- CSVals[0] = ConstantInt::get(Type::IntTy, 2147483647);
+ CSVals[0] = ConstantInt::get(Type::Int32Ty, 2147483647);
}
CAList.push_back(ConstantStruct::get(CSVals));
}
if (!GCL->use_empty()) {
Constant *V = NGV;
if (V->getType() != GCL->getType())
- V = ConstantExpr::getCast(V, GCL->getType());
+ V = ConstantExpr::getBitCast(V, GCL->getType());
GCL->replaceAllUsesWith(V);
}
GCL->eraseFromParent();
InstResult = ConstantExpr::get(SI->getOpcode(),
getVal(Values, SI->getOperand(0)),
getVal(Values, SI->getOperand(1)));
+ } else if (CmpInst *CI = dyn_cast<CmpInst>(CurInst)) {
+ InstResult = ConstantExpr::getCompare(CI->getPredicate(),
+ getVal(Values, CI->getOperand(0)),
+ getVal(Values, CI->getOperand(1)));
} else if (CastInst *CI = dyn_cast<CastInst>(CurInst)) {
- InstResult = ConstantExpr::getCast(getVal(Values, CI->getOperand(0)),
+ InstResult = ConstantExpr::getCast(CI->getOpcode(),
+ getVal(Values, CI->getOperand(0)),
CI->getType());
} else if (SelectInst *SI = dyn_cast<SelectInst>(CurInst)) {
InstResult = ConstantExpr::getSelect(getVal(Values, SI->getOperand(0)),
if (BI->isUnconditional()) {
NewBB = BI->getSuccessor(0);
} else {
- ConstantBool *Cond =
- dyn_cast<ConstantBool>(getVal(Values, BI->getCondition()));
+ ConstantInt *Cond =
+ dyn_cast<ConstantInt>(getVal(Values, BI->getCondition()));
if (!Cond) return false; // Cannot determine.
- NewBB = BI->getSuccessor(!Cond->getValue());
+
+ NewBB = BI->getSuccessor(!Cond->getZExtValue());
}
} else if (SwitchInst *SI = dyn_cast<SwitchInst>(CurInst)) {
ConstantInt *Val =