summaryrefslogtreecommitdiffstats
path: root/lib/Transforms/Scalar/GVN.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms/Scalar/GVN.cpp')
-rw-r--r--lib/Transforms/Scalar/GVN.cpp257
1 files changed, 152 insertions, 105 deletions
diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp
index a126382..afa152d 100644
--- a/lib/Transforms/Scalar/GVN.cpp
+++ b/lib/Transforms/Scalar/GVN.cpp
@@ -937,6 +937,115 @@ SpeculationFailure:
return false;
}
+
+/// CoerceAvailableValueToLoadType - If we saw a store of a value to memory, and
+/// then a load from a must-aliased pointer of a different type, try to coerce
+/// the stored value. LoadedTy is the type of the load we want to replace and
+/// InsertPt is the place to insert new instructions.
+///
+/// If we can't do it, return null.
+static Value *CoerceAvailableValueToLoadType(Value *StoredVal,
+ const Type *LoadedTy,
+ Instruction *InsertPt,
+ const TargetData &TD) {
+ const Type *StoredValTy = StoredVal->getType();
+
+ uint64_t StoreSize = TD.getTypeSizeInBits(StoredValTy);
+ uint64_t LoadSize = TD.getTypeSizeInBits(LoadedTy);
+
+ // If the store and reload are the same size, we can always reuse it.
+ if (StoreSize == LoadSize) {
+ if (isa<PointerType>(StoredValTy) && isa<PointerType>(LoadedTy)) {
+ // Pointer to Pointer -> use bitcast.
+ return new BitCastInst(StoredVal, LoadedTy, "", InsertPt);
+ }
+
+ // Convert source pointers to integers, which can be bitcast.
+ if (isa<PointerType>(StoredValTy)) {
+ StoredValTy = TD.getIntPtrType(StoredValTy->getContext());
+ StoredVal = new PtrToIntInst(StoredVal, StoredValTy, "", InsertPt);
+ }
+
+ const Type *TypeToCastTo = LoadedTy;
+ if (isa<PointerType>(TypeToCastTo))
+ TypeToCastTo = TD.getIntPtrType(StoredValTy->getContext());
+
+ if (StoredValTy != TypeToCastTo)
+ StoredVal = new BitCastInst(StoredVal, TypeToCastTo, "", InsertPt);
+
+ // Cast to pointer if the load needs a pointer type.
+ if (isa<PointerType>(LoadedTy))
+ StoredVal = new IntToPtrInst(StoredVal, LoadedTy, "", InsertPt);
+
+ return StoredVal;
+ }
+
+ // If the loaded value is smaller than the available value, then we can
+ // extract out a piece from it. If the available value is too small, then we
+ // can't do anything.
+ if (StoreSize < LoadSize)
+ return 0;
+
+ // Convert source pointers to integers, which can be manipulated.
+ if (isa<PointerType>(StoredValTy)) {
+ StoredValTy = TD.getIntPtrType(StoredValTy->getContext());
+ StoredVal = new PtrToIntInst(StoredVal, StoredValTy, "", InsertPt);
+ }
+
+ // Convert vectors and fp to integer, which can be manipulated.
+ if (!isa<IntegerType>(StoredValTy)) {
+ StoredValTy = IntegerType::get(StoredValTy->getContext(), StoreSize);
+ StoredVal = new BitCastInst(StoredVal, StoredValTy, "", InsertPt);
+ }
+
+ // If this is a big-endian system, we need to shift the value down to the low
+ // bits so that a truncate will work.
+ if (TD.isBigEndian()) {
+ Constant *Val = ConstantInt::get(StoredVal->getType(), StoreSize-LoadSize);
+ StoredVal = BinaryOperator::CreateLShr(StoredVal, Val, "tmp", InsertPt);
+ }
+
+ // Truncate the integer to the right size now.
+ const Type *NewIntTy = IntegerType::get(StoredValTy->getContext(), LoadSize);
+ StoredVal = new TruncInst(StoredVal, NewIntTy, "trunc", InsertPt);
+
+ if (LoadedTy == NewIntTy)
+ return StoredVal;
+
+ // If the result is a pointer, inttoptr.
+ if (isa<PointerType>(LoadedTy))
+ return new IntToPtrInst(StoredVal, LoadedTy, "inttoptr", InsertPt);
+
+ // Otherwise, bitcast.
+ return new BitCastInst(StoredVal, LoadedTy, "bitcast", InsertPt);
+}
+
+static void
+GetAvailableBlockValues(DenseMap<BasicBlock*, Value*> &BlockReplValues,
+ SmallVector<std::pair<BasicBlock*,
+ Value*>, 16> &ValuesPerBlock,
+ const Type *LoadTy,
+ const TargetData *TD) {
+
+ for (unsigned i = 0, e = ValuesPerBlock.size(); i != e; ++i) {
+ BasicBlock *BB = ValuesPerBlock[i].first;
+ Value *AvailableVal = ValuesPerBlock[i].second;
+
+ Value *&BlockEntry = BlockReplValues[BB];
+ if (BlockEntry) continue;
+
+ if (AvailableVal->getType() != LoadTy) {
+ assert(TD && "Need target data to handle type mismatch case");
+ AvailableVal = CoerceAvailableValueToLoadType(AvailableVal, LoadTy,
+ BB->getTerminator(), *TD);
+ DEBUG(errs() << "GVN COERCED NONLOCAL VAL:\n"
+ << *ValuesPerBlock[i].second << '\n'
+ << *AvailableVal << '\n' << "\n\n\n");
+ }
+ BlockEntry = AvailableVal;
+ }
+}
+
/// processNonLocalLoad - Attempt to eliminate a load whose dependencies are
/// non-local by performing PHI construction.
bool GVN::processNonLocalLoad(LoadInst *LI,
@@ -972,6 +1081,8 @@ bool GVN::processNonLocalLoad(LoadInst *LI,
SmallVector<std::pair<BasicBlock*, Value*>, 16> ValuesPerBlock;
SmallVector<BasicBlock*, 16> UnavailableBlocks;
+ const TargetData *TD = 0;
+
for (unsigned i = 0, e = Deps.size(); i != e; ++i) {
BasicBlock *DepBB = Deps[i].first;
MemDepResult DepInfo = Deps[i].second;
@@ -992,24 +1103,41 @@ bool GVN::processNonLocalLoad(LoadInst *LI,
if (StoreInst* S = dyn_cast<StoreInst>(DepInst)) {
// Reject loads and stores that are to the same address but are of
- // different types.
- // NOTE: 403.gcc does have this case (e.g. in readonly_fields_p) because
- // of bitfield access, it would be interesting to optimize for it at some
- // point.
+ // different types if we have to.
if (S->getOperand(0)->getType() != LI->getType()) {
- UnavailableBlocks.push_back(DepBB);
- continue;
+ if (TD == 0)
+ TD = getAnalysisIfAvailable<TargetData>();
+
+ // If the stored value is larger or equal to the loaded value, we can
+ // reuse it.
+ if (TD == 0 ||
+ TD->getTypeSizeInBits(S->getOperand(0)->getType()) <
+ TD->getTypeSizeInBits(LI->getType())) {
+ UnavailableBlocks.push_back(DepBB);
+ continue;
+ }
}
ValuesPerBlock.push_back(std::make_pair(DepBB, S->getOperand(0)));
} else if (LoadInst* LD = dyn_cast<LoadInst>(DepInst)) {
+ // If the types mismatch and we can't handle it, reject reuse of the load.
if (LD->getType() != LI->getType()) {
- UnavailableBlocks.push_back(DepBB);
- continue;
+ if (TD == 0)
+ TD = getAnalysisIfAvailable<TargetData>();
+
+ // If the stored value is larger or equal to the loaded value, we can
+ // reuse it.
+ if (TD == 0 ||
+ TD->getTypeSizeInBits(LD->getType()) <
+ TD->getTypeSizeInBits(LI->getType())) {
+ UnavailableBlocks.push_back(DepBB);
+ continue;
+ }
}
ValuesPerBlock.push_back(std::make_pair(DepBB, LD));
} else {
+ // FIXME: Handle memset/memcpy.
UnavailableBlocks.push_back(DepBB);
continue;
}
@@ -1043,16 +1171,18 @@ bool GVN::processNonLocalLoad(LoadInst *LI,
DEBUG(errs() << "GVN REMOVING NONLOCAL LOAD: " << *LI << '\n');
+ // Convert the block information to a map, and insert coersions as needed.
DenseMap<BasicBlock*, Value*> BlockReplValues;
- BlockReplValues.insert(ValuesPerBlock.begin(), ValuesPerBlock.end());
+ GetAvailableBlockValues(BlockReplValues, ValuesPerBlock, LI->getType(), TD);
+
// Perform PHI construction.
- Value* v = GetValueForBlock(LI->getParent(), LI, BlockReplValues, true);
- LI->replaceAllUsesWith(v);
+ Value *V = GetValueForBlock(LI->getParent(), LI, BlockReplValues, true);
+ LI->replaceAllUsesWith(V);
- if (isa<PHINode>(v))
- v->takeName(LI);
- if (isa<PointerType>(v->getType()))
- MD->invalidateCachedPointerInfo(v);
+ if (isa<PHINode>(V))
+ V->takeName(LI);
+ if (isa<PointerType>(V->getType()))
+ MD->invalidateCachedPointerInfo(V);
toErase.push_back(LI);
NumGVNLoad++;
return true;
@@ -1196,104 +1326,21 @@ bool GVN::processNonLocalLoad(LoadInst *LI,
ValuesPerBlock.push_back(std::make_pair((*I)->getParent(), *I));
DenseMap<BasicBlock*, Value*> BlockReplValues;
- BlockReplValues.insert(ValuesPerBlock.begin(), ValuesPerBlock.end());
+ GetAvailableBlockValues(BlockReplValues, ValuesPerBlock, LI->getType(), TD);
BlockReplValues[UnavailablePred] = NewLoad;
// Perform PHI construction.
- Value* v = GetValueForBlock(LI->getParent(), LI, BlockReplValues, true);
- LI->replaceAllUsesWith(v);
- if (isa<PHINode>(v))
- v->takeName(LI);
- if (isa<PointerType>(v->getType()))
- MD->invalidateCachedPointerInfo(v);
+ Value *V = GetValueForBlock(LI->getParent(), LI, BlockReplValues, true);
+ LI->replaceAllUsesWith(V);
+ if (isa<PHINode>(V))
+ V->takeName(LI);
+ if (isa<PointerType>(V->getType()))
+ MD->invalidateCachedPointerInfo(V);
toErase.push_back(LI);
NumPRELoad++;
return true;
}
-/// CoerceAvailableValueToLoadType - If we saw a store of a value to memory, and
-/// then a load from a must-aliased pointer of a different type, try to coerce
-/// the stored value. LoadedTy is the type of the load we want to replace and
-/// InsertPt is the place to insert new instructions.
-///
-/// If we can't do it, return null.
-static Value *CoerceAvailableValueToLoadType(Value *StoredVal,
- const Type *LoadedTy,
- Instruction *InsertPt,
- const TargetData &TD) {
- const Type *StoredValTy = StoredVal->getType();
-
- uint64_t StoreSize = TD.getTypeSizeInBits(StoredValTy);
- uint64_t LoadSize = TD.getTypeSizeInBits(LoadedTy);
-
- // If the store and reload are the same size, we can always reuse it.
- if (StoreSize == LoadSize) {
- if (isa<PointerType>(StoredValTy) && isa<PointerType>(LoadedTy)) {
- // Pointer to Pointer -> use bitcast.
- return new BitCastInst(StoredVal, LoadedTy, "", InsertPt);
- }
-
- // Convert source pointers to integers, which can be bitcast.
- if (isa<PointerType>(StoredValTy)) {
- StoredValTy = TD.getIntPtrType(StoredValTy->getContext());
- StoredVal = new PtrToIntInst(StoredVal, StoredValTy, "", InsertPt);
- }
-
- const Type *TypeToCastTo = LoadedTy;
- if (isa<PointerType>(TypeToCastTo))
- TypeToCastTo = TD.getIntPtrType(StoredValTy->getContext());
-
- if (StoredValTy != TypeToCastTo)
- StoredVal = new BitCastInst(StoredVal, TypeToCastTo, "", InsertPt);
-
- // Cast to pointer if the load needs a pointer type.
- if (isa<PointerType>(LoadedTy))
- StoredVal = new IntToPtrInst(StoredVal, LoadedTy, "", InsertPt);
-
- return StoredVal;
- }
-
- // If the loaded value is smaller than the available value, then we can
- // extract out a piece from it. If the available value is too small, then we
- // can't do anything.
- if (StoreSize < LoadSize)
- return 0;
-
- // Convert source pointers to integers, which can be manipulated.
- if (isa<PointerType>(StoredValTy)) {
- StoredValTy = TD.getIntPtrType(StoredValTy->getContext());
- StoredVal = new PtrToIntInst(StoredVal, StoredValTy, "", InsertPt);
- }
-
- // Convert vectors and fp to integer, which can be manipulated.
- if (!isa<IntegerType>(StoredValTy)) {
- StoredValTy = IntegerType::get(StoredValTy->getContext(), StoreSize);
- StoredVal = new BitCastInst(StoredVal, StoredValTy, "", InsertPt);
- }
-
- // If this is a big-endian system, we need to shift the value down to the low
- // bits so that a truncate will work.
- if (TD.isBigEndian()) {
- Constant *Val = ConstantInt::get(StoredVal->getType(), StoreSize-LoadSize);
- StoredVal = BinaryOperator::CreateLShr(StoredVal, Val, "tmp", InsertPt);
- }
-
- // Truncate the integer to the right size now.
- const Type *NewIntTy = IntegerType::get(StoredValTy->getContext(), LoadSize);
- StoredVal = new TruncInst(StoredVal, NewIntTy, "trunc", InsertPt);
-
- if (LoadedTy == NewIntTy)
- return StoredVal;
-
- // If the result is a pointer, inttoptr.
- if (isa<PointerType>(LoadedTy))
- return new IntToPtrInst(StoredVal, LoadedTy, "inttoptr", InsertPt);
-
- // Otherwise, bitcast.
- return new BitCastInst(StoredVal, LoadedTy, "bitcast", InsertPt);
-}
-
-
/// processLoad - Attempt to eliminate a load, first by eliminating it
/// locally, and then attempting non-local elimination if that fails.
bool GVN::processLoad(LoadInst *L, SmallVectorImpl<Instruction*> &toErase) {