Newer
Older
Owen Anderson
committed
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
deletedLoad = true;
NumGVNLoad++;
}
// Whether we removed it or not, we can't
// go any further
break;
} else if (!last) {
// If we don't depend on a store, and we haven't
// been loaded before, bail.
break;
} else if (dep == last) {
// Remove it!
MD.removeInstruction(L);
L->replaceAllUsesWith(last);
toErase.push_back(L);
deletedLoad = true;
NumGVNLoad++;
break;
} else {
dep = MD.getDependency(L, dep);
Owen Anderson
committed
}
}
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
if (dep != MemoryDependenceAnalysis::None &&
dep != MemoryDependenceAnalysis::NonLocal &&
isa<AllocationInst>(dep)) {
// Check that this load is actually from the
// allocation we found
Value* v = L->getOperand(0);
while (true) {
if (BitCastInst *BC = dyn_cast<BitCastInst>(v))
v = BC->getOperand(0);
else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(v))
v = GEP->getOperand(0);
else
break;
}
if (v == dep) {
// If this load depends directly on an allocation, there isn't
// anything stored there; therefore, we can optimize this load
// to undef.
MD.removeInstruction(L);
L->replaceAllUsesWith(UndefValue::get(L->getType()));
toErase.push_back(L);
deletedLoad = true;
NumGVNLoad++;
}
}
Owen Anderson
committed
if (!deletedLoad)
last = L;
return deletedLoad;
}
Owen Anderson
committed
/// valueHasOnlyOneUse - Returns true if a value has only one use after the
/// cutoff that is in the current same block and is the same as the use
/// parameter.
bool GVN::valueHasOnlyOneUseAfter(Value* val, MemCpyInst* use,
Instruction* cutoff) {
DominatorTree& DT = getAnalysis<DominatorTree>();
SmallVector<User*, 8> useList(val->use_begin(), val->use_end());
Owen Anderson
committed
while (!useList.empty()) {
User* UI = useList.back();
Owen Anderson
committed
Owen Anderson
committed
if (isa<GetElementPtrInst>(UI) || isa<BitCastInst>(UI)) {
useList.pop_back();
for (User::use_iterator I = UI->use_begin(), E = UI->use_end();
I != E; ++I)
useList.push_back(*I);
Owen Anderson
committed
} else if (UI == use) {
Owen Anderson
committed
useList.pop_back();
Owen Anderson
committed
} else if (Instruction* inst = dyn_cast<Instruction>(UI)) {
if (inst->getParent() == use->getParent() &&
(inst == cutoff || !DT.dominates(cutoff, inst))) {
useList.pop_back();
} else
return false;
} else
Owen Anderson
committed
return false;
}
return true;
}
Owen Anderson
committed
/// performReturnSlotOptzn - takes a memcpy and a call that it depends on,
/// and checks for the possibility of a return slot optimization by having
/// the call write its result directly into the callees return parameter
/// rather than using memcpy
bool GVN::performReturnSlotOptzn(MemCpyInst* cpy, CallInst* C,
SmallVector<Instruction*, 4>& toErase) {
Owen Anderson
committed
// Deliberately get the source and destination with bitcasts stripped away,
// because we'll need to do type comparisons based on the underlying type.
Owen Anderson
committed
Value* cpyDest = cpy->getDest();
Owen Anderson
committed
Value* cpySrc = cpy->getSource();
CallSite CS = CallSite::get(C);
Owen Anderson
committed
Owen Anderson
committed
// Since this is a return slot optimization, we need to make sure that
// the value being copied is, in fact, in a return slot. We also need to
// check that the return slot parameter is marked noalias, so that we can
// be sure that changing it will not cause unexpected behavior changes due
Owen Anderson
committed
// to it being accessed through a global or another parameter.
if (CS.arg_size() == 0 ||
cpySrc != CS.getArgument(0) ||
!CS.paramHasAttr(1, ParamAttr::NoAlias | ParamAttr::StructRet))
Owen Anderson
committed
return false;
Owen Anderson
committed
// Since we're changing the parameter to the callsite, we need to make sure
// that what would be the new parameter dominates the callsite.
DominatorTree& DT = getAnalysis<DominatorTree>();
if (Instruction* cpyDestInst = dyn_cast<Instruction>(cpyDest))
if (!DT.dominates(cpyDestInst, C))
return false;
Owen Anderson
committed
// Check that something sneaky is not happening involving casting
// return slot types around.
if (CS.getArgument(0)->getType() != cpyDest->getType())
Owen Anderson
committed
return false;
Owen Anderson
committed
// sret --> pointer
const PointerType* PT = cast<PointerType>(cpyDest->getType());
Owen Anderson
committed
Owen Anderson
committed
// We can only perform the transformation if the size of the memcpy
// is constant and equal to the size of the structure.
Owen Anderson
committed
ConstantInt* cpyLength = dyn_cast<ConstantInt>(cpy->getLength());
if (!cpyLength)
Owen Anderson
committed
return false;
Owen Anderson
committed
TargetData& TD = getAnalysis<TargetData>();
Owen Anderson
committed
if (TD.getTypeStoreSize(PT->getElementType()) != cpyLength->getZExtValue())
return false;
Owen Anderson
committed
// For safety, we must ensure that the output parameter of the call only has
// a single use, the memcpy. Otherwise this can introduce an invalid
// transformation.
if (!valueHasOnlyOneUseAfter(CS.getArgument(0), cpy, C))
return false;
Owen Anderson
committed
// We only perform the transformation if it will be profitable.
Owen Anderson
committed
if (!valueHasOnlyOneUseAfter(cpyDest, cpy, C))
Owen Anderson
committed
return false;
// In addition to knowing that the call does not access the return slot
// in some unexpected manner, which we derive from the noalias attribute,
// we also need to know that it does not sneakily modify the destination
// slot in the caller. We don't have parameter attributes to go by
// for this one, so we just rely on AA to figure it out for us.
AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
if (AA.getModRefInfo(C, cpy->getRawDest(), cpyLength->getZExtValue()) !=
AliasAnalysis::NoModRef)
return false;
// If all the checks have passed, then we're alright to do the transformation.
Owen Anderson
committed
CS.setArgument(0, cpyDest);
Owen Anderson
committed
Owen Anderson
committed
// Drop any cached information about the call, because we may have changed
// its dependence information by changing its parameter.
Owen Anderson
committed
MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
MD.dropInstruction(C);
// Remove the memcpy
Owen Anderson
committed
MD.removeInstruction(cpy);
Owen Anderson
committed
toErase.push_back(cpy);
return true;
}
/// processMemCpy - perform simplication of memcpy's. If we have memcpy A which
/// copies X to Y, and memcpy B which copies Y to Z, then we can rewrite B to be
/// a memcpy from X to Z (or potentially a memmove, depending on circumstances).
/// This allows later passes to remove the first memcpy altogether.
Owen Anderson
committed
bool GVN::processMemCpy(MemCpyInst* M, MemCpyInst* MDep,
SmallVector<Instruction*, 4>& toErase) {
// We can only transforms memcpy's where the dest of one is the source of the
// other
if (M->getSource() != MDep->getDest())
return false;
// Second, the length of the memcpy's must be the same, or the preceeding one
// must be larger than the following one.
ConstantInt* C1 = dyn_cast<ConstantInt>(MDep->getLength());
ConstantInt* C2 = dyn_cast<ConstantInt>(M->getLength());
if (!C1 || !C2)
return false;
uint64_t DepSize = C1->getValue().getZExtValue();
uint64_t CpySize = C2->getValue().getZExtValue();
if (DepSize < CpySize)
return false;
// Finally, we have to make sure that the dest of the second does not
// alias the source of the first
AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
if (AA.alias(M->getRawDest(), CpySize, MDep->getRawSource(), DepSize) !=
AliasAnalysis::NoAlias)
return false;
else if (AA.alias(M->getRawDest(), CpySize, M->getRawSource(), CpySize) !=
AliasAnalysis::NoAlias)
return false;
else if (AA.alias(MDep->getRawDest(), DepSize, MDep->getRawSource(), DepSize)
!= AliasAnalysis::NoAlias)
return false;
// If all checks passed, then we can transform these memcpy's
Owen Anderson
committed
Function* MemCpyFun = Intrinsic::getDeclaration(
M->getParent()->getParent()->getParent(),
Owen Anderson
committed
M->getIntrinsicID());
std::vector<Value*> args;
args.push_back(M->getRawDest());
args.push_back(MDep->getRawSource());
args.push_back(M->getLength());
args.push_back(M->getAlignment());
Owen Anderson
committed
CallInst* C = new CallInst(MemCpyFun, args.begin(), args.end(), "", M);
Owen Anderson
committed
MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
if (MD.getDependency(C) == MDep) {
MD.dropInstruction(M);
toErase.push_back(M);
return true;
} else {
MD.removeInstruction(C);
toErase.push_back(C);
return false;
}
}
Owen Anderson
committed
/// processInstruction - When calculating availability, handle an instruction
Owen Anderson
committed
/// by inserting it into the appropriate sets
bool GVN::processInstruction(Instruction* I,
ValueNumberedSet& currAvail,
DenseMap<Value*, LoadInst*>& lastSeenLoad,
SmallVector<Instruction*, 4>& toErase) {
if (LoadInst* L = dyn_cast<LoadInst>(I)) {
return processLoad(L, lastSeenLoad, toErase);
} else if (MemCpyInst* M = dyn_cast<MemCpyInst>(I)) {
Owen Anderson
committed
MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
// The are two possible optimizations we can do for memcpy:
// a) memcpy-memcpy xform which exposes redundance for DSE
// b) call-memcpy xform for sret return slot optimization
Instruction* dep = MD.getDependency(M);
if (dep == MemoryDependenceAnalysis::None ||
dep == MemoryDependenceAnalysis::NonLocal)
return false;
if (MemCpyInst *MemCpy = dyn_cast<MemCpyInst>(dep))
return processMemCpy(M, MemCpy, toErase);
if (CallInst* C = dyn_cast<CallInst>(dep))
return performReturnSlotOptzn(M, C, toErase);
return false;
Owen Anderson
committed
}
unsigned num = VN.lookup_or_add(I);
Owen Anderson
committed
if (PHINode* p = dyn_cast<PHINode>(I)) {
Value* constVal = CollapsePhi(p);
Owen Anderson
committed
if (constVal) {
for (PhiMapType::iterator PI = phiMap.begin(), PE = phiMap.end();
PI != PE; ++PI)
if (PI->second.count(p))
PI->second.erase(p);
Owen Anderson
committed
p->replaceAllUsesWith(constVal);
toErase.push_back(p);
Owen Anderson
committed
}
// Perform value-number based elimination
Owen Anderson
committed
} else if (currAvail.test(num)) {
Owen Anderson
committed
Value* repl = find_leader(currAvail, num);
Owen Anderson
committed
if (CallInst* CI = dyn_cast<CallInst>(I)) {
AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
if (!AA.doesNotAccessMemory(CI)) {
Owen Anderson
committed
MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
if (cast<Instruction>(repl)->getParent() != CI->getParent() ||
MD.getDependency(CI) != MD.getDependency(cast<CallInst>(repl))) {
Owen Anderson
committed
// There must be an intervening may-alias store, so nothing from
// this point on will be able to be replaced with the preceding call
currAvail.erase(repl);
currAvail.insert(I);
return false;
}
}
}
Owen Anderson
committed
// Remove it!
MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
MD.removeInstruction(I);
Owen Anderson
committed
I->replaceAllUsesWith(repl);
toErase.push_back(I);
return true;
} else if (!I->isTerminator()) {
currAvail.set(num);
currAvail.insert(I);
}
return false;
}
// GVN::runOnFunction - This is the main transformation entry point for a
// function.
//
VN.setAliasAnalysis(&getAnalysis<AliasAnalysis>());
bool changed = false;
bool shouldContinue = true;
while (shouldContinue) {
shouldContinue = iterateOnFunction(F);
changed |= shouldContinue;
}
return changed;
}
// GVN::iterateOnFunction - Executes one iteration of GVN
bool GVN::iterateOnFunction(Function &F) {
Owen Anderson
committed
// Clean out global sets from any previous functions
VN.clear();
availableOut.clear();
Owen Anderson
committed
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
bool changed_function = false;
DominatorTree &DT = getAnalysis<DominatorTree>();
SmallVector<Instruction*, 4> toErase;
// Top-down walk of the dominator tree
for (df_iterator<DomTreeNode*> DI = df_begin(DT.getRootNode()),
E = df_end(DT.getRootNode()); DI != E; ++DI) {
// Get the set to update for this block
ValueNumberedSet& currAvail = availableOut[DI->getBlock()];
DenseMap<Value*, LoadInst*> lastSeenLoad;
BasicBlock* BB = DI->getBlock();
// A block inherits AVAIL_OUT from its dominator
if (DI->getIDom() != 0)
currAvail = availableOut[DI->getIDom()->getBlock()];
for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();
changed_function |= processInstruction(BI, currAvail,
lastSeenLoad, toErase);
NumGVNInstr += toErase.size();
// Avoid iterator invalidation
++BI;
Owen Anderson
committed
for (SmallVector<Instruction*, 4>::iterator I = toErase.begin(),
E = toErase.end(); I != E; ++I) {
(*I)->eraseFromParent();
}
Owen Anderson
committed
Owen Anderson
committed
}
}
return changed_function;
}