//
// The LLVM Compiler Infrastructure
//
-// This file was developed by the LLVM research group and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Module.h"
+#include "llvm/ParameterAttributes.h"
#include "llvm/Pass.h"
-#include "llvm/Support/Debug.h"
+#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Target/TargetData.h"
-#include "llvm/Transforms/Utils/Local.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/GetElementPtrTypeIterator.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include <algorithm>
#include <set>
using namespace llvm;
+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");
+STATISTIC(NumNestRemoved , "Number of nest attributes removed");
+
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");
-
- struct GlobalOpt : public ModulePass {
+ struct VISIBILITY_HIDDEN GlobalOpt : public ModulePass {
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<TargetData>();
}
+ static char ID; // Pass identification, replacement for typeid
+ GlobalOpt() : ModulePass((intptr_t)&ID) {}
bool runOnModule(Module &M);
bool ProcessInternalGlobal(GlobalVariable *GV,Module::global_iterator &GVI);
};
+ char GlobalOpt::ID = 0;
RegisterPass<GlobalOpt> X("globalopt", "Global Variable Optimizer");
}
/// GlobalStatus - As we analyze each global, keep track of some information
/// about it. If we find out that the address of the global is taken, none of
/// this info will be accurate.
-struct GlobalStatus {
+struct VISIBILITY_HIDDEN GlobalStatus {
/// isLoaded - True if the global is ever loaded. If the global isn't ever
/// loaded it can be deleted.
bool isLoaded;
/// HasPHIUser - Set to true if this global has a user that is a PHI node.
bool HasPHIUser;
- /// isNotSuitableForSRA - Keep track of whether any SRA preventing users of
- /// the global exist. Such users include GEP instruction with variable
- /// indexes, and non-gep/load/store users like constant expr casts.
- bool isNotSuitableForSRA;
-
GlobalStatus() : isLoaded(false), StoredType(NotStored), StoredOnceValue(0),
AccessingFunction(0), HasMultipleAccessingFunctions(false),
- HasNonInstructionUser(false), HasPHIUser(false),
- isNotSuitableForSRA(false) {}
+ HasNonInstructionUser(false), HasPHIUser(false) {}
};
GS.HasNonInstructionUser = true;
if (AnalyzeGlobal(CE, GS, PHIUsers)) return true;
- if (CE->getOpcode() != Instruction::GetElementPtr)
- GS.isNotSuitableForSRA = true;
- else if (!GS.isNotSuitableForSRA) {
- // Check to see if this ConstantExpr GEP is SRA'able. In particular, we
- // don't like < 3 operand CE's, and we don't like non-constant integer
- // indices.
- if (CE->getNumOperands() < 3 || !CE->getOperand(1)->isNullValue())
- GS.isNotSuitableForSRA = true;
- else {
- for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i)
- if (!isa<ConstantInt>(CE->getOperand(i))) {
- GS.isNotSuitableForSRA = true;
- break;
- }
- }
- }
} else if (Instruction *I = dyn_cast<Instruction>(*UI)) {
if (!GS.HasMultipleAccessingFunctions) {
else if (GS.AccessingFunction != F)
GS.HasMultipleAccessingFunctions = true;
}
- if (isa<LoadInst>(I)) {
+ if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
GS.isLoaded = true;
+ if (LI->isVolatile()) return true; // Don't hack on volatile loads.
} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
// Don't allow a store OF the address, only stores TO the address.
if (SI->getOperand(0) == V) return true;
+ if (SI->isVolatile()) return true; // Don't hack on volatile stores.
+
// If this is a direct store to the global (i.e., the global is a scalar
// value, not an aggregate), keep more specific information about
// stores.
- if (GS.StoredType != GlobalStatus::isStored)
+ if (GS.StoredType != GlobalStatus::isStored) {
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(SI->getOperand(1))){
Value *StoredVal = SI->getOperand(0);
if (StoredVal == GV->getInitializer()) {
} else {
GS.StoredType = GlobalStatus::isStored;
}
+ }
} else if (isa<GetElementPtrInst>(I)) {
if (AnalyzeGlobal(I, GS, PHIUsers)) return true;
-
- // If the first two indices are constants, this can be SRA'd.
- if (isa<GlobalVariable>(I->getOperand(0))) {
- if (I->getNumOperands() < 3 || !isa<Constant>(I->getOperand(1)) ||
- !cast<Constant>(I->getOperand(1))->isNullValue() ||
- !isa<ConstantInt>(I->getOperand(2)))
- GS.isNotSuitableForSRA = true;
- } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(I->getOperand(0))){
- if (CE->getOpcode() != Instruction::GetElementPtr ||
- CE->getNumOperands() < 3 || I->getNumOperands() < 2 ||
- !isa<Constant>(I->getOperand(0)) ||
- !cast<Constant>(I->getOperand(0))->isNullValue())
- GS.isNotSuitableForSRA = true;
- } else {
- GS.isNotSuitableForSRA = true;
- }
} else if (isa<SelectInst>(I)) {
if (AnalyzeGlobal(I, GS, PHIUsers)) return true;
- GS.isNotSuitableForSRA = true;
} else if (PHINode *PN = dyn_cast<PHINode>(I)) {
// PHI nodes we can check just like select or GEP instructions, but we
// have to be careful about infinite recursion.
if (PHIUsers.insert(PN).second) // Not already visited.
if (AnalyzeGlobal(I, GS, PHIUsers)) return true;
- GS.isNotSuitableForSRA = true;
GS.HasPHIUser = true;
- } else if (isa<SetCondInst>(I)) {
- GS.isNotSuitableForSRA = true;
+ } else if (isa<CmpInst>(I)) {
} else if (isa<MemCpyInst>(I) || isa<MemMoveInst>(I)) {
if (I->getOperand(1) == V)
GS.StoredType = GlobalStatus::isStored;
if (I->getOperand(2) == V)
GS.isLoaded = true;
- GS.isNotSuitableForSRA = true;
} else if (isa<MemSetInst>(I)) {
assert(I->getOperand(1) == V && "Memset only takes one pointer!");
GS.StoredType = GlobalStatus::isStored;
- GS.isNotSuitableForSRA = true;
} else {
return true; // Any other non-load instruction might take address!
}
if (IdxV < CS->getNumOperands()) return CS->getOperand(IdxV);
} else if (ConstantArray *CA = dyn_cast<ConstantArray>(Agg)) {
if (IdxV < CA->getNumOperands()) return CA->getOperand(IdxV);
- } else if (ConstantPacked *CP = dyn_cast<ConstantPacked>(Agg)) {
+ } else if (ConstantVector *CP = dyn_cast<ConstantVector>(Agg)) {
if (IdxV < CP->getNumOperands()) return CP->getOperand(IdxV);
} else if (isa<ConstantAggregateZero>(Agg)) {
if (const StructType *STy = dyn_cast<StructType>(Agg->getType())) {
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);
Changed = true;
}
} else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) {
+ // Do not transform "gepinst (gep constexpr (GV))" here, because forming
+ // "gepconstexpr (gep constexpr (GV))" will cause the two gep's to fold
+ // and will invalidate our notion of what Init is.
Constant *SubInit = 0;
- ConstantExpr *CE =
- dyn_cast_or_null<ConstantExpr>(ConstantFoldInstruction(GEP));
- if (Init && CE && CE->getOpcode() == Instruction::GetElementPtr)
- SubInit = ConstantFoldLoadThroughGEPConstantExpr(Init, CE);
+ if (!isa<ConstantExpr>(GEP->getOperand(0))) {
+ ConstantExpr *CE =
+ dyn_cast_or_null<ConstantExpr>(ConstantFoldInstruction(GEP));
+ if (Init && CE && CE->getOpcode() == Instruction::GetElementPtr)
+ SubInit = ConstantFoldLoadThroughGEPConstantExpr(Init, CE);
+ }
Changed |= CleanupConstantGlobalUsers(GEP, SubInit);
if (GEP->use_empty()) {
return Changed;
}
+/// isSafeSROAElementUse - Return true if the specified instruction is a safe
+/// user of a derived expression from a global that we want to SROA.
+static bool isSafeSROAElementUse(Value *V) {
+ // We might have a dead and dangling constant hanging off of here.
+ if (Constant *C = dyn_cast<Constant>(V))
+ return ConstantIsDead(C);
+
+ Instruction *I = dyn_cast<Instruction>(V);
+ if (!I) return false;
+
+ // Loads are ok.
+ if (isa<LoadInst>(I)) return true;
+
+ // Stores *to* the pointer are ok.
+ if (StoreInst *SI = dyn_cast<StoreInst>(I))
+ return SI->getOperand(0) != V;
+
+ // Otherwise, it must be a GEP.
+ GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I);
+ if (GEPI == 0) return false;
+
+ if (GEPI->getNumOperands() < 3 || !isa<Constant>(GEPI->getOperand(1)) ||
+ !cast<Constant>(GEPI->getOperand(1))->isNullValue())
+ return false;
+
+ for (Value::use_iterator I = GEPI->use_begin(), E = GEPI->use_end();
+ I != E; ++I)
+ if (!isSafeSROAElementUse(*I))
+ return false;
+ return true;
+}
+
+
+/// IsUserOfGlobalSafeForSRA - U is a direct user of the specified global value.
+/// Look at it and its uses and decide whether it is safe to SROA this global.
+///
+static bool IsUserOfGlobalSafeForSRA(User *U, GlobalValue *GV) {
+ // The user of the global must be a GEP Inst or a ConstantExpr GEP.
+ if (!isa<GetElementPtrInst>(U) &&
+ (!isa<ConstantExpr>(U) ||
+ cast<ConstantExpr>(U)->getOpcode() != Instruction::GetElementPtr))
+ return false;
+
+ // Check to see if this ConstantExpr GEP is SRA'able. In particular, we
+ // don't like < 3 operand CE's, and we don't like non-constant integer
+ // indices. This enforces that all uses are 'gep GV, 0, C, ...' for some
+ // value of C.
+ if (U->getNumOperands() < 3 || !isa<Constant>(U->getOperand(1)) ||
+ !cast<Constant>(U->getOperand(1))->isNullValue() ||
+ !isa<ConstantInt>(U->getOperand(2)))
+ return false;
+
+ gep_type_iterator GEPI = gep_type_begin(U), E = gep_type_end(U);
+ ++GEPI; // Skip over the pointer index.
+
+ // If this is a use of an array allocation, do a bit more checking for sanity.
+ if (const ArrayType *AT = dyn_cast<ArrayType>(*GEPI)) {
+ uint64_t NumElements = AT->getNumElements();
+ ConstantInt *Idx = cast<ConstantInt>(U->getOperand(2));
+
+ // Check to make sure that index falls within the array. If not,
+ // something funny is going on, so we won't do the optimization.
+ //
+ if (Idx->getZExtValue() >= NumElements)
+ return false;
+
+ // We cannot scalar repl this level of the array unless any array
+ // sub-indices are in-range constants. In particular, consider:
+ // A[0][i]. We cannot know that the user isn't doing invalid things like
+ // allowing i to index an out-of-range subscript that accesses A[1].
+ //
+ // Scalar replacing *just* the outer index of the array is probably not
+ // going to be a win anyway, so just give up.
+ for (++GEPI; // Skip array index.
+ GEPI != E && (isa<ArrayType>(*GEPI) || isa<VectorType>(*GEPI));
+ ++GEPI) {
+ uint64_t NumElements;
+ if (const ArrayType *SubArrayTy = dyn_cast<ArrayType>(*GEPI))
+ NumElements = SubArrayTy->getNumElements();
+ else
+ NumElements = cast<VectorType>(*GEPI)->getNumElements();
+
+ ConstantInt *IdxVal = dyn_cast<ConstantInt>(GEPI.getOperand());
+ if (!IdxVal || IdxVal->getZExtValue() >= NumElements)
+ return false;
+ }
+ }
+
+ for (Value::use_iterator I = U->use_begin(), E = U->use_end(); I != E; ++I)
+ if (!isSafeSROAElementUse(*I))
+ return false;
+ return true;
+}
+
+/// GlobalUsersSafeToSRA - Look at all uses of the global and decide whether it
+/// is safe for us to perform this transformation.
+///
+static bool GlobalUsersSafeToSRA(GlobalValue *GV) {
+ for (Value::use_iterator UI = GV->use_begin(), E = GV->use_end();
+ UI != E; ++UI) {
+ if (!IsUserOfGlobalSafeForSRA(*UI, GV))
+ return false;
+ }
+ return true;
+}
+
+
/// SRAGlobal - Perform scalar replacement of aggregates on the specified global
/// variable. This opens the door for other optimizations by exposing the
/// behavior of the program in a more fine-grained way. We have determined that
/// this transformation is safe already. We return the first global variable we
/// insert so that the caller can reprocess it.
static GlobalVariable *SRAGlobal(GlobalVariable *GV) {
+ // Make sure this global only has simple uses that we can SRA.
+ if (!GlobalUsersSafeToSRA(GV))
+ return 0;
+
assert(GV->hasInternalLinkage() && !GV->isConstant());
Constant *Init = GV->getInitializer();
const Type *Ty = Init->getType();
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,
- In, GV->getName()+"."+utostr(i));
+ In, GV->getName()+"."+utostr(i),
+ (Module *)NULL,
+ GV->isThreadLocal());
Globals.insert(GV, NGV);
NewGlobals.push_back(NGV);
}
unsigned NumElements = 0;
if (const ArrayType *ATy = dyn_cast<ArrayType>(STy))
NumElements = ATy->getNumElements();
- else if (const PackedType *PTy = dyn_cast<PackedType>(STy))
+ else if (const VectorType *PTy = dyn_cast<VectorType>(STy))
NumElements = PTy->getNumElements();
else
assert(0 && "Unknown aggregate sequential type!");
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,
GlobalVariable::InternalLinkage,
- In, GV->getName()+"."+utostr(i));
+ In, GV->getName()+"."+utostr(i),
+ (Module *)NULL,
+ GV->isThreadLocal());
Globals.insert(GV, NGV);
NewGlobals.push_back(NGV);
}
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.
Value *NewPtr = NewGlobals[Val];
// Form a shorter GEP if needed.
- if (GEP->getNumOperands() > 3)
+ if (GEP->getNumOperands() > 3) {
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(GEP)) {
- std::vector<Constant*> Idxs;
+ SmallVector<Constant*, 8> Idxs;
Idxs.push_back(NullInt);
for (unsigned i = 3, e = CE->getNumOperands(); i != e; ++i)
Idxs.push_back(CE->getOperand(i));
- NewPtr = ConstantExpr::getGetElementPtr(cast<Constant>(NewPtr), Idxs);
+ NewPtr = ConstantExpr::getGetElementPtr(cast<Constant>(NewPtr),
+ &Idxs[0], Idxs.size());
} else {
GetElementPtrInst *GEPI = cast<GetElementPtrInst>(GEP);
- std::vector<Value*> Idxs;
+ SmallVector<Value*, 8> Idxs;
Idxs.push_back(NullInt);
for (unsigned i = 3, e = GEPI->getNumOperands(); i != e; ++i)
Idxs.push_back(GEPI->getOperand(i));
- NewPtr = new GetElementPtrInst(NewPtr, Idxs,
+ NewPtr = new GetElementPtrInst(NewPtr, Idxs.begin(), Idxs.end(),
GEPI->getName()+"."+utostr(Val), GEPI);
}
+ }
GEP->replaceAllUsesWith(NewPtr);
if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(GEP))
}
/// AllUsesOfValueWillTrapIfNull - Return true if all users of the specified
-/// value will trap if the value is dynamically null.
-static bool AllUsesOfValueWillTrapIfNull(Value *V) {
+/// value will trap if the value is dynamically null. PHIs keeps track of any
+/// phi nodes we've seen to avoid reprocessing them.
+static bool AllUsesOfValueWillTrapIfNull(Value *V,
+ SmallPtrSet<PHINode*, 8> &PHIs) {
for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++UI)
if (isa<LoadInst>(*UI)) {
// 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 (BitCastInst *CI = dyn_cast<BitCastInst>(*UI)) {
+ if (!AllUsesOfValueWillTrapIfNull(CI, PHIs)) return false;
} else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(*UI)) {
- if (!AllUsesOfValueWillTrapIfNull(GEPI)) return false;
- } else if (isa<SetCondInst>(*UI) &&
+ if (!AllUsesOfValueWillTrapIfNull(GEPI, PHIs)) return false;
+ } else if (PHINode *PN = dyn_cast<PHINode>(*UI)) {
+ // If we've already seen this phi node, ignore it, it has already been
+ // checked.
+ if (PHIs.insert(PN))
+ return AllUsesOfValueWillTrapIfNull(PN, PHIs);
+ } 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;
static bool AllUsesOfLoadedValueWillTrapIfNull(GlobalVariable *GV) {
for (Value::use_iterator UI = GV->use_begin(), E = GV->use_end(); UI!=E; ++UI)
if (LoadInst *LI = dyn_cast<LoadInst>(*UI)) {
- if (!AllUsesOfValueWillTrapIfNull(LI))
+ SmallPtrSet<PHINode*, 8> PHIs;
+ if (!AllUsesOfValueWillTrapIfNull(LI, PHIs))
return false;
} else if (isa<StoreInst>(*UI)) {
// 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();
}
} else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
// Should handle GEP here.
- std::vector<Constant*> Indices;
- Indices.reserve(GEPI->getNumOperands()-1);
+ SmallVector<Constant*, 8> Idxs;
+ Idxs.reserve(GEPI->getNumOperands()-1);
for (unsigned i = 1, e = GEPI->getNumOperands(); i != e; ++i)
if (Constant *C = dyn_cast<Constant>(GEPI->getOperand(i)))
- Indices.push_back(C);
+ Idxs.push_back(C);
else
break;
- if (Indices.size() == GEPI->getNumOperands()-1)
+ if (Idxs.size() == GEPI->getNumOperands()-1)
Changed |= OptimizeAwayTrappingUsesOfValue(GEPI,
- ConstantExpr::getGetElementPtr(NewV, Indices));
+ ConstantExpr::getGetElementPtr(NewV, &Idxs[0],
+ Idxs.size()));
if (GEPI->use_empty()) {
Changed = true;
GEPI->eraseFromParent();
Loads.push_back(LI);
Changed |= OptimizeAwayTrappingUsesOfValue(LI, LV);
} else {
- assert(isa<StoreInst>(*GUI) && "Only expect load and stores!");
+ // If we get here we could have stores, selects, or phi nodes whose values
+ // are loaded.
+ assert((isa<StoreInst>(*GUI) || isa<PHINode>(*GUI) ||
+ isa<SelectInst>(*GUI) || isa<ConstantExpr>(*GUI)) &&
+ "Only expect load and stores!");
}
if (Changed) {
/// 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(Indices[0]);
- Value *NewGEP = new GetElementPtrInst(NewMI, Indices,
+ Value* Indices[2];
+ Indices[0] = Indices[1] = Constant::getNullValue(Type::Int32Ty);
+ Value *NewGEP = new GetElementPtrInst(NewMI, Indices, Indices + 2,
NewMI->getName()+".el0", MI);
MI->replaceAllUsesWith(NewGEP);
MI->eraseFromParent();
Constant *Init = UndefValue::get(MI->getAllocatedType());
GlobalVariable *NewGV = new GlobalVariable(MI->getAllocatedType(), false,
GlobalValue::InternalLinkage, Init,
- GV->getName()+".body");
+ GV->getName()+".body",
+ (Module *)NULL,
+ GV->isThreadLocal());
GV->getParent()->getGlobalList().insert(GV, NewGV);
// Anything that used the malloc now uses the global directly.
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",
+ (Module *)NULL, GV->isThreadLocal());
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();
}
/// like dereferencing the pointer, but not storing through the address, unless
/// it is to the specified global.
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)) {
+ GlobalVariable *GV,
+ SmallPtrSet<PHINode*, 8> &PHIs) {
+ for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++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)
return false; // Storing the pointer itself... bad.
// Otherwise, storing through it, or storing into GV... fine.
- } else if (isa<GetElementPtrInst>(*UI) || isa<SelectInst>(*UI)) {
- if (!ValueIsOnlyUsedLocallyOrStoredToOneGlobal(cast<Instruction>(*UI),GV))
+ } else if (isa<GetElementPtrInst>(*UI)) {
+ if (!ValueIsOnlyUsedLocallyOrStoredToOneGlobal(cast<Instruction>(*UI),
+ GV, PHIs))
return false;
+ } else if (PHINode *PN = dyn_cast<PHINode>(*UI)) {
+ // PHIs are ok if all uses are ok. Don't infinitely recurse through PHI
+ // cycles.
+ if (PHIs.insert(PN))
+ if (!ValueIsOnlyUsedLocallyOrStoredToOneGlobal(PN, GV, PHIs))
+ return false;
} else {
return false;
}
static void ReplaceUsesOfMallocWithGlobal(Instruction *Alloc,
GlobalVariable *GV) {
while (!Alloc->use_empty()) {
- Instruction *U = Alloc->use_back();
+ Instruction *U = cast<Instruction>(*Alloc->use_begin());
+ Instruction *InsertPt = U;
if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
// If this is the store of the allocation into the global, remove it.
if (SI->getOperand(1) == GV) {
SI->eraseFromParent();
continue;
}
+ } else if (PHINode *PN = dyn_cast<PHINode>(U)) {
+ // Insert the load in the corresponding predecessor, not right before the
+ // PHI.
+ unsigned PredNo = Alloc->use_begin().getOperandNo()/2;
+ InsertPt = PN->getIncomingBlock(PredNo)->getTerminator();
}
// Insert a load from the global, and use it instead of the malloc.
- Value *NL = new LoadInst(GV, GV->getName()+".val", U);
+ Value *NL = new LoadInst(GV, GV->getName()+".val", InsertPt);
U->replaceUsesOfWith(Alloc, NL);
}
}
/// GlobalLoadUsesSimpleEnoughForHeapSRA - If all users of values loaded from
/// GV are simple enough to perform HeapSRA, return true.
-static bool GlobalLoadUsesSimpleEnoughForHeapSRA(GlobalVariable *GV) {
+static bool GlobalLoadUsesSimpleEnoughForHeapSRA(GlobalVariable *GV,
+ MallocInst *MI) {
for (Value::use_iterator UI = GV->use_begin(), E = GV->use_end(); UI != E;
++UI)
if (LoadInst *LI = dyn_cast<LoadInst>(*UI)) {
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;
}
// getelementptr is also ok, but only a simple form.
- GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(*UI);
- if (!GEPI) return false;
+ if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(*UI)) {
+ // Must index into the array and into the struct.
+ if (GEPI->getNumOperands() < 3)
+ return false;
+
+ // Otherwise the GEP is ok.
+ continue;
+ }
- // Must index into the array and into the struct.
- if (GEPI->getNumOperands() < 3)
- return false;
+ if (PHINode *PN = dyn_cast<PHINode>(*UI)) {
+ // We have a phi of a load from the global. We can only handle this
+ // if the other PHI'd values are actually the same. In this case,
+ // the rewriter will just drop the phi entirely.
+ for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
+ Value *IV = PN->getIncomingValue(i);
+ if (IV == LI) continue; // Trivial the same.
+
+ // If the phi'd value is from the malloc that initializes the value,
+ // we can xform it.
+ if (IV == MI) continue;
+
+ // Otherwise, we don't know what it is.
+ return false;
+ }
+ return true;
+ }
- // Otherwise the GEP is ok.
- continue;
+ // Otherwise we don't know what this is, not ok.
+ return false;
}
}
return true;
}
-/// RewriteUsesOfLoadForHeapSRoA - We are performing Heap SRoA on a global. Ptr
-/// is a value loaded from the global. Eliminate all uses of Ptr, making them
-/// use FieldGlobals instead. All uses of loaded values satisfy
-/// GlobalLoadUsesSimpleEnoughForHeapSRA.
-static void RewriteUsesOfLoadForHeapSRoA(LoadInst *Ptr,
- const std::vector<GlobalVariable*> &FieldGlobals) {
- std::vector<Value *> InsertedLoadsForPtr;
- //InsertedLoadsForPtr.resize(FieldGlobals.size());
- while (!Ptr->use_empty()) {
- Instruction *User = Ptr->use_back();
-
- // If this is a comparison against null, handle it.
- if (SetCondInst *SCI = dyn_cast<SetCondInst>(User)) {
- assert(isa<ConstantPointerNull>(SCI->getOperand(1)));
- // If we have a setcc of the loaded pointer, we can use a setcc of any
- // field.
- Value *NPtr;
- if (InsertedLoadsForPtr.empty()) {
- NPtr = new LoadInst(FieldGlobals[0], Ptr->getName()+".f0", Ptr);
- InsertedLoadsForPtr.push_back(Ptr);
- } else {
- NPtr = InsertedLoadsForPtr.back();
- }
-
- Value *New = new SetCondInst(SCI->getOpcode(), NPtr,
- Constant::getNullValue(NPtr->getType()),
- SCI->getName(), SCI);
- SCI->replaceAllUsesWith(New);
- SCI->eraseFromParent();
- continue;
+/// GetHeapSROALoad - Return the load for the specified field of the HeapSROA'd
+/// value, lazily creating it on demand.
+static Value *GetHeapSROALoad(Instruction *Load, unsigned FieldNo,
+ const std::vector<GlobalVariable*> &FieldGlobals,
+ std::vector<Value *> &InsertedLoadsForPtr) {
+ if (InsertedLoadsForPtr.size() <= FieldNo)
+ InsertedLoadsForPtr.resize(FieldNo+1);
+ if (InsertedLoadsForPtr[FieldNo] == 0)
+ InsertedLoadsForPtr[FieldNo] = new LoadInst(FieldGlobals[FieldNo],
+ Load->getName()+".f" +
+ utostr(FieldNo), Load);
+ return InsertedLoadsForPtr[FieldNo];
+}
+
+/// RewriteHeapSROALoadUser - Given a load instruction and a value derived from
+/// the load, rewrite the derived value to use the HeapSRoA'd load.
+static void RewriteHeapSROALoadUser(LoadInst *Load, Instruction *LoadUser,
+ const std::vector<GlobalVariable*> &FieldGlobals,
+ std::vector<Value *> &InsertedLoadsForPtr) {
+ // If this is a comparison against null, handle it.
+ if (ICmpInst *SCI = dyn_cast<ICmpInst>(LoadUser)) {
+ assert(isa<ConstantPointerNull>(SCI->getOperand(1)));
+ // If we have a setcc of the loaded pointer, we can use a setcc of any
+ // field.
+ Value *NPtr;
+ if (InsertedLoadsForPtr.empty()) {
+ NPtr = GetHeapSROALoad(Load, 0, FieldGlobals, InsertedLoadsForPtr);
+ } else {
+ NPtr = InsertedLoadsForPtr.back();
}
- // Otherwise, this should be: 'getelementptr Ptr, Idx, uint FieldNo ...'
- GetElementPtrInst *GEPI = cast<GetElementPtrInst>(User);
+ Value *New = new ICmpInst(SCI->getPredicate(), NPtr,
+ Constant::getNullValue(NPtr->getType()),
+ SCI->getName(), SCI);
+ SCI->replaceAllUsesWith(New);
+ SCI->eraseFromParent();
+ return;
+ }
+
+ // Handle 'getelementptr Ptr, Idx, uint FieldNo ...'
+ if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(LoadUser)) {
assert(GEPI->getNumOperands() >= 3 && isa<ConstantInt>(GEPI->getOperand(2))
- && GEPI->getOperand(2)->getType()->isUnsigned()
&& "Unexpected GEPI!");
-
+
// Load the pointer for this field.
unsigned FieldNo = cast<ConstantInt>(GEPI->getOperand(2))->getZExtValue();
- if (InsertedLoadsForPtr.size() <= FieldNo)
- InsertedLoadsForPtr.resize(FieldNo+1);
- if (InsertedLoadsForPtr[FieldNo] == 0)
- InsertedLoadsForPtr[FieldNo] = new LoadInst(FieldGlobals[FieldNo],
- Ptr->getName()+".f" +
- utostr(FieldNo), Ptr);
- Value *NewPtr = InsertedLoadsForPtr[FieldNo];
-
+ Value *NewPtr = GetHeapSROALoad(Load, FieldNo,
+ FieldGlobals, InsertedLoadsForPtr);
+
// Create the new GEP idx vector.
- std::vector<Value*> GEPIdx;
+ SmallVector<Value*, 8> GEPIdx;
GEPIdx.push_back(GEPI->getOperand(1));
- GEPIdx.insert(GEPIdx.end(), GEPI->op_begin()+3, GEPI->op_end());
-
- Value *NGEPI = new GetElementPtrInst(NewPtr, GEPIdx, GEPI->getName(), GEPI);
+ GEPIdx.append(GEPI->op_begin()+3, GEPI->op_end());
+
+ Value *NGEPI = new GetElementPtrInst(NewPtr, GEPIdx.begin(), GEPIdx.end(),
+ GEPI->getName(), GEPI);
GEPI->replaceAllUsesWith(NGEPI);
GEPI->eraseFromParent();
+ return;
+ }
+
+ // Handle PHI nodes. PHI nodes must be merging in the same values, plus
+ // potentially the original malloc. Insert phi nodes for each field, then
+ // process uses of the PHI.
+ PHINode *PN = cast<PHINode>(LoadUser);
+ std::vector<Value *> PHIsForField;
+ PHIsForField.resize(FieldGlobals.size());
+ for (unsigned i = 0, e = FieldGlobals.size(); i != e; ++i) {
+ Value *LoadV = GetHeapSROALoad(Load, i, FieldGlobals, InsertedLoadsForPtr);
+
+ PHINode *FieldPN = new PHINode(LoadV->getType(),
+ PN->getName()+"."+utostr(i), PN);
+ // Fill in the predecessor values.
+ for (unsigned pred = 0, e = PN->getNumIncomingValues(); pred != e; ++pred) {
+ // Each predecessor either uses the load or the original malloc.
+ Value *InVal = PN->getIncomingValue(pred);
+ BasicBlock *BB = PN->getIncomingBlock(pred);
+ Value *NewVal;
+ if (isa<MallocInst>(InVal)) {
+ // Insert a reload from the global in the predecessor.
+ NewVal = GetHeapSROALoad(BB->getTerminator(), i, FieldGlobals,
+ PHIsForField);
+ } else {
+ NewVal = InsertedLoadsForPtr[i];
+ }
+ FieldPN->addIncoming(NewVal, BB);
+ }
+ PHIsForField[i] = FieldPN;
}
+
+ // Since PHIsForField specifies a phi for every input value, the lazy inserter
+ // will never insert a load.
+ while (!PN->use_empty())
+ RewriteHeapSROALoadUser(Load, PN->use_back(), FieldGlobals, PHIsForField);
+ PN->eraseFromParent();
+}
+
+/// RewriteUsesOfLoadForHeapSRoA - We are performing Heap SRoA on a global. Ptr
+/// is a value loaded from the global. Eliminate all uses of Ptr, making them
+/// use FieldGlobals instead. All uses of loaded values satisfy
+/// GlobalLoadUsesSimpleEnoughForHeapSRA.
+static void RewriteUsesOfLoadForHeapSRoA(LoadInst *Load,
+ const std::vector<GlobalVariable*> &FieldGlobals) {
+ std::vector<Value *> InsertedLoadsForPtr;
+ //InsertedLoadsForPtr.resize(FieldGlobals.size());
+ while (!Load->use_empty())
+ RewriteHeapSROALoadUser(Load, Load->use_back(),
+ FieldGlobals, InsertedLoadsForPtr);
}
/// PerformHeapAllocSRoA - MI is an allocation of an array of structures. Break
for (unsigned FieldNo = 0, e = STy->getNumElements(); FieldNo != e;++FieldNo){
const Type *FieldTy = STy->getElementType(FieldNo);
- const Type *PFieldTy = PointerType::get(FieldTy);
+ const Type *PFieldTy = PointerType::getUnqual(FieldTy);
GlobalVariable *NGV =
new GlobalVariable(PFieldTy, false, GlobalValue::InternalLinkage,
Constant::getNullValue(PFieldTy),
- GV->getName() + ".f" + utostr(FieldNo), GV);
+ GV->getName() + ".f" + utostr(FieldNo), GV,
+ GV->isThreadLocal());
FieldGlobals.push_back(NGV);
MallocInst *NMI = new MallocInst(FieldTy, MI->getArraySize(),
// }
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))
// malloc to be stored into the specified global, loaded setcc'd, and
// GEP'd. These are all things we could transform to using the global
// for.
- if (!ValueIsOnlyUsedLocallyOrStoredToOneGlobal(MI, GV))
- return false;
+ {
+ SmallPtrSet<PHINode*, 8> PHIs;
+ if (!ValueIsOnlyUsedLocallyOrStoredToOneGlobal(MI, GV, PHIs))
+ return false;
+ }
// If we have a global that is only initialized with a fixed size malloc,
// (2048 bytes currently), as we don't want to introduce a 16M global or
// something.
if (NElements->getZExtValue()*
- TD.getTypeSize(MI->getAllocatedType()) < 2048) {
+ TD.getABITypeSize(MI->getAllocatedType()) < 2048) {
GVI = OptimizeGlobalAddressOfMalloc(GV, MI);
return true;
}
// This the structure has an unreasonable number of fields, leave it
// alone.
if (AllocTy->getNumElements() <= 16 && AllocTy->getNumElements() > 0 &&
- GlobalLoadUsesSimpleEnoughForHeapSRA(GV)) {
+ GlobalLoadUsesSimpleEnoughForHeapSRA(GV, MI)) {
GVI = PerformHeapAllocSRoA(GV, MI);
return true;
}
return false;
}
-/// ShrinkGlobalToBoolean - At this point, we have learned that the only two
-/// values ever stored into GV are its initializer and OtherVal.
-static void ShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) {
+/// TryToShrinkGlobalToBoolean - At this point, we have learned that the only
+/// two values ever stored into GV are its initializer and OtherVal. See if we
+/// can shrink the global into a boolean and select between the two values
+/// whenever it is used. This exposes the values to other scalar optimizations.
+static bool TryToShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) {
+ const Type *GVElType = GV->getType()->getElementType();
+
+ // If GVElType is already i1, it is already shrunk. If the type of the GV is
+ // an FP value or vector, don't do this optimization because a select between
+ // them is very expensive and unlikely to lead to later simplification.
+ if (GVElType == Type::Int1Ty || GVElType->isFloatingPoint() ||
+ isa<VectorType>(GVElType))
+ return false;
+
+ // Walk the use list of the global seeing if all the uses are load or store.
+ // If there is anything else, bail out.
+ for (Value::use_iterator I = GV->use_begin(), E = GV->use_end(); I != E; ++I)
+ if (!isa<LoadInst>(I) && !isa<StoreInst>(I))
+ return false;
+
+ DOUT << " *** SHRINKING TO BOOL: " << *GV;
+
// Create the new global, initializing it to false.
- GlobalVariable *NewGV = new GlobalVariable(Type::BoolTy, false,
- GlobalValue::InternalLinkage, ConstantBool::getFalse(),
- GV->getName()+".b");
+ GlobalVariable *NewGV = new GlobalVariable(Type::Int1Ty, false,
+ GlobalValue::InternalLinkage, ConstantInt::getFalse(),
+ GV->getName()+".b",
+ (Module *)NULL,
+ GV->isThreadLocal());
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.
bool IsOneZero = false;
if (ConstantInt *CI = dyn_cast<ConstantInt>(OtherVal))
- IsOneZero = InitVal->isNullValue() && CI->equalsInt(1);
+ IsOneZero = InitVal->isNullValue() && CI->isOne();
while (!GV->use_empty()) {
Instruction *UI = cast<Instruction>(GV->use_back());
// 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
}
}
new StoreInst(StoreVal, NewGV, SI);
- } else if (!UI->use_empty()) {
+ } else {
// Change the load into a load of bool then a select.
LoadInst *LI = cast<LoadInst>(UI);
-
- std::string Name = LI->getName(); LI->setName("");
- LoadInst *NLI = new LoadInst(NewGV, Name+".b", LI);
+ LoadInst *NLI = new LoadInst(NewGV, LI->getName()+".b", LI);
Value *NSI;
if (IsOneZero)
- NSI = new CastInst(NLI, LI->getType(), Name, LI);
+ NSI = new ZExtInst(NLI, LI->getType(), "", LI);
else
- NSI = new SelectInst(NLI, OtherVal, InitVal, Name, LI);
+ NSI = new SelectInst(NLI, OtherVal, InitVal, "", LI);
+ NSI->takeName(LI);
LI->replaceAllUsesWith(NSI);
}
UI->eraseFromParent();
}
GV->eraseFromParent();
+ return true;
}
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 << "\n";
#endif
// If this is a first class global and has only one accessing function
++NumMarked;
return true;
- } else if (!GS.isNotSuitableForSRA &&
- !GV->getInitializer()->getType()->isFirstClassType()) {
+ } else if (!GV->getInitializer()->getType()->isFirstClassType()) {
if (GlobalVariable *FirstNewGV = SRAGlobal(GV)) {
GVI = FirstNewGV; // Don't skip the newly produced globals!
return true;
// 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 &&
- !GV->getType()->getElementType()->isFloatingPoint() &&
- !GS.HasPHIUser) {
- DOUT << " *** SHRINKING TO BOOL: " << *GV;
- ShrinkGlobalToBoolean(GV, SOVConstant);
+ if (TryToShrinkGlobalToBoolean(GV, SOVConstant)) {
++NumShrunkToBool;
return true;
}
/// function, changing them to FastCC.
static void ChangeCalleesToFastCall(Function *F) {
for (Value::use_iterator UI = F->use_begin(), E = F->use_end(); UI != E;++UI){
- Instruction *User = cast<Instruction>(*UI);
- if (CallInst *CI = dyn_cast<CallInst>(User))
- CI->setCallingConv(CallingConv::Fast);
- else
- cast<InvokeInst>(User)->setCallingConv(CallingConv::Fast);
+ CallSite User(cast<Instruction>(*UI));
+ User.setCallingConv(CallingConv::Fast);
+ }
+}
+
+static const ParamAttrsList *StripNest(const ParamAttrsList *Attrs) {
+ if (!Attrs)
+ return NULL;
+
+ for (unsigned i = 0, e = Attrs->size(); i != e; ++i) {
+ if ((Attrs->getParamAttrsAtIndex(i) & ParamAttr::Nest) == 0)
+ continue;
+
+ Attrs = ParamAttrsList::excludeAttrs(Attrs, Attrs->getParamIndex(i),
+ ParamAttr::Nest);
+ // There can be only one.
+ break;
+ }
+
+ return Attrs;
+}
+
+static void RemoveNestAttribute(Function *F) {
+ F->setParamAttrs(StripNest(F->getParamAttrs()));
+ for (Value::use_iterator UI = F->use_begin(), E = F->use_end(); UI != E;++UI){
+ CallSite User(cast<Instruction>(*UI));
+ User.setParamAttrs(StripNest(User.getParamAttrs()));
}
}
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;
+ } else if (F->hasInternalLinkage()) {
+ if (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;
+ }
+
+ if (F->getParamAttrs() &&
+ F->getParamAttrs()->hasAttrSomewhere(ParamAttr::Nest) &&
+ OnlyCalledDirectly(F)) {
+ // The function is not used by a trampoline intrinsic, so it is safe
+ // to remove the 'nest' attribute.
+ RemoveNestAttribute(F);
+ ++NumNestRemoved;
+ Changed = true;
+ }
}
}
return Changed;
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.
} else {
const Type *FTy = FunctionType::get(Type::VoidTy,
std::vector<const Type*>(), false);
- const PointerType *PFTy = PointerType::get(FTy);
+ const PointerType *PFTy = PointerType::getUnqual(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));
}
// 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->getLinkage(), CA, "",
+ (Module *)NULL,
+ GCL->isThreadLocal());
GCL->getParent()->getGlobalList().insert(GCL, NGV);
+ NGV->takeName(GCL);
// 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());
+ V = ConstantExpr::getBitCast(V, GCL->getType());
GCL->replaceAllUsesWith(V);
}
GCL->eraseFromParent();
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) {
if (!GV->hasExternalLinkage() && !GV->hasInternalLinkage())
return false; // do not allow weak/linkonce/dllimport/dllexport linkage.
- return !GV->isExternal(); // reject external globals.
+ return !GV->isDeclaration(); // reject external globals.
}
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C))
// Handle a constantexpr gep.
Elts[Idx] = EvaluateStoreInto(Elts[Idx], Val, Addr, OpNo+1);
// Return the modified struct.
- return ConstantStruct::get(Elts);
+ return ConstantStruct::get(&Elts[0], Elts.size(), STy->isPacked());
} else {
ConstantInt *CI = cast<ConstantInt>(Addr->getOperand(OpNo));
const ArrayType *ATy = cast<ArrayType>(Init->getType());
InstResult = ConstantExpr::get(BO->getOpcode(),
getVal(Values, BO->getOperand(0)),
getVal(Values, BO->getOperand(1)));
- } else if (ShiftInst *SI = dyn_cast<ShiftInst>(CurInst)) {
- 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)),
getVal(Values, SI->getOperand(2)));
} else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(CurInst)) {
Constant *P = getVal(Values, GEP->getOperand(0));
- std::vector<Constant*> GEPOps;
+ SmallVector<Constant*, 8> GEPOps;
for (unsigned i = 1, e = GEP->getNumOperands(); i != e; ++i)
GEPOps.push_back(getVal(Values, GEP->getOperand(i)));
- InstResult = ConstantExpr::getGetElementPtr(P, GEPOps);
+ InstResult = ConstantExpr::getGetElementPtr(P, &GEPOps[0], GEPOps.size());
} else if (LoadInst *LI = dyn_cast<LoadInst>(CurInst)) {
if (LI->isVolatile()) return false; // no volatile accesses.
InstResult = ComputeLoadResult(getVal(Values, LI->getOperand(0)),
for (unsigned i = 1, e = CI->getNumOperands(); i != e; ++i)
Formals.push_back(getVal(Values, CI->getOperand(i)));
- if (Callee->isExternal()) {
+ if (Callee->isDeclaration()) {
// If this is a function we can constant fold, do it.
- if (Constant *C = ConstantFoldCall(Callee, Formals)) {
+ if (Constant *C = ConstantFoldCall(Callee, &Formals[0],
+ Formals.size())) {
InstResult = C;
} else {
return false;
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 =