aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2011-04-26 01:21:15 +0000
committerChris Lattner <sabre@nondot.org>2011-04-26 01:21:15 +0000
commit1f821512fc1441480b3355305e0da5267073fe1c (patch)
tree6bba91bc3f9b51387c675e6663d88edee1ddbf48
parent0c99861836741911300587c579d4f9d3fe1d2a39 (diff)
downloadexternal_llvm-1f821512fc1441480b3355305e0da5267073fe1c.zip
external_llvm-1f821512fc1441480b3355305e0da5267073fe1c.tar.gz
external_llvm-1f821512fc1441480b3355305e0da5267073fe1c.tar.bz2
Enhance MemDep: When alias analysis returns a partial alias result,
return it as a clobber. This allows GVN to do smart things. Enhance GVN to be smart about the case when a small load is clobbered by a larger overlapping load. In this case, forward the value. This allows us to compile stuff like this: int test(void *P) { int tmp = *(unsigned int*)P; return tmp+*((unsigned char*)P+1); } into: _test: ## @test movl (%rdi), %ecx movzbl %ch, %eax addl %ecx, %eax ret which has one load. We already handled the case where the smaller load was from a must-aliased base pointer. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@130180 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Analysis/MemoryDependenceAnalysis.h5
-rw-r--r--lib/Analysis/MemoryDependenceAnalysis.cpp20
-rw-r--r--lib/Transforms/Scalar/GVN.cpp102
-rw-r--r--test/Transforms/GVN/rle.ll27
4 files changed, 125 insertions, 29 deletions
diff --git a/include/llvm/Analysis/MemoryDependenceAnalysis.h b/include/llvm/Analysis/MemoryDependenceAnalysis.h
index 4d5dd19..f2e3353 100644
--- a/include/llvm/Analysis/MemoryDependenceAnalysis.h
+++ b/include/llvm/Analysis/MemoryDependenceAnalysis.h
@@ -48,6 +48,11 @@ namespace llvm {
/// this occurs when we see a may-aliased store to the memory location we
/// care about.
///
+ /// There are several cases that may be interesting here:
+ /// 1. Loads are clobbered by may-alias stores.
+ /// 2. Loads are considered clobbered by partially-aliased loads. The
+ /// client may choose to analyze deeper into these cases.
+ ///
/// A dependence query on the first instruction of the entry block will
/// return a clobber(self) result.
Clobber,
diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp
index 35043bdd..c8c4b4c 100644
--- a/lib/Analysis/MemoryDependenceAnalysis.cpp
+++ b/lib/Analysis/MemoryDependenceAnalysis.cpp
@@ -291,16 +291,26 @@ getPointerDependencyFrom(const AliasAnalysis::Location &MemLoc, bool isLoad,
if (R == AliasAnalysis::NoAlias)
continue;
- // May-alias loads don't depend on each other without a dependence.
- if (isLoad && R != AliasAnalysis::MustAlias)
+ if (isLoad) {
+ // Must aliased loads are defs of each other.
+ if (R == AliasAnalysis::MustAlias)
+ return MemDepResult::getDef(Inst);
+
+ // If we have a partial alias, then return this as a clobber for the
+ // client to handle.
+ if (R == AliasAnalysis::PartialAlias)
+ return MemDepResult::getClobber(Inst);
+
+ // Random may-alias loads don't depend on each other without a
+ // dependence.
continue;
+ }
// Stores don't alias loads from read-only memory.
- if (!isLoad && AA->pointsToConstantMemory(LoadLoc))
+ if (AA->pointsToConstantMemory(LoadLoc))
continue;
- // Stores depend on may and must aliased loads, loads depend on must-alias
- // loads.
+ // Stores depend on may/must aliased loads.
return MemDepResult::getDef(Inst);
}
diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp
index 45fd665..15db9ad 100644
--- a/lib/Transforms/Scalar/GVN.cpp
+++ b/lib/Transforms/Scalar/GVN.cpp
@@ -636,10 +636,9 @@ static Value *CoerceAvailableValueToLoadType(Value *StoredVal,
// If the store and reload are the same size, we can always reuse it.
if (StoreSize == LoadSize) {
- if (StoredValTy->isPointerTy() && LoadedTy->isPointerTy()) {
- // Pointer to Pointer -> use bitcast.
+ // Pointer to Pointer -> use bitcast.
+ if (StoredValTy->isPointerTy() && LoadedTy->isPointerTy())
return new BitCastInst(StoredVal, LoadedTy, "", InsertPt);
- }
// Convert source pointers to integers, which can be bitcast.
if (StoredValTy->isPointerTy()) {
@@ -796,6 +795,22 @@ static int AnalyzeLoadFromClobberingStore(const Type *LoadTy, Value *LoadPtr,
StorePtr, StoreSize, TD);
}
+/// AnalyzeLoadFromClobberingLoad - This function is called when we have a
+/// memdep query of a load that ends up being clobbered by another load. See if
+/// the other load can feed into the second load.
+static int AnalyzeLoadFromClobberingLoad(const Type *LoadTy, Value *LoadPtr,
+ LoadInst *DepLI, const TargetData &TD){
+ // Cannot handle reading from store of first-class aggregate yet.
+ if (DepLI->getType()->isStructTy() || DepLI->getType()->isArrayTy())
+ return -1;
+
+ Value *DepPtr = DepLI->getPointerOperand();
+ uint64_t DepSize = TD.getTypeSizeInBits(DepLI->getType());
+ return AnalyzeLoadFromClobberingWrite(LoadTy, LoadPtr, DepPtr, DepSize, TD);
+}
+
+
+
static int AnalyzeLoadFromClobberingMemInst(const Type *LoadTy, Value *LoadPtr,
MemIntrinsic *MI,
const TargetData &TD) {
@@ -1129,6 +1144,26 @@ bool GVN::processNonLocalLoad(LoadInst *LI,
}
}
}
+
+ // Check to see if we have something like this:
+ // load i32* P
+ // load i8* (P+1)
+ // if we have this, replace the later with an extraction from the former.
+ if (LoadInst *DepLI = dyn_cast<LoadInst>(DepInfo.getInst())) {
+ // If this is a clobber and L is the first instruction in its block, then
+ // we have the first instruction in the entry block.
+ if (DepLI != LI && Address && TD) {
+ int Offset = AnalyzeLoadFromClobberingLoad(LI->getType(),
+ LI->getPointerOperand(),
+ DepLI, *TD);
+
+ if (Offset != -1) {
+ ValuesPerBlock.push_back(AvailableValueInBlock::get(DepBB, DepLI,
+ Offset));
+ continue;
+ }
+ }
+ }
// If the clobbering value is a memset/memcpy/memmove, see if we can
// forward a value on from it.
@@ -1454,8 +1489,9 @@ bool GVN::processLoad(LoadInst *L, SmallVectorImpl<Instruction*> &toErase) {
// ... to a pointer that has been loaded from before...
MemDepResult Dep = MD->getDependency(L);
- // If the value isn't available, don't do anything!
- if (Dep.isClobber()) {
+ // If we have a clobber and target data is around, see if this is a clobber
+ // that we can fix up through code synthesis.
+ if (Dep.isClobber() && TD) {
// Check to see if we have something like this:
// store i32 123, i32* %P
// %A = bitcast i32* %P to i8*
@@ -1467,26 +1503,40 @@ bool GVN::processLoad(LoadInst *L, SmallVectorImpl<Instruction*> &toErase) {
// completely covers this load. This sort of thing can happen in bitfield
// access code.
Value *AvailVal = 0;
- if (StoreInst *DepSI = dyn_cast<StoreInst>(Dep.getInst()))
- if (TD) {
- int Offset = AnalyzeLoadFromClobberingStore(L->getType(),
- L->getPointerOperand(),
- DepSI, *TD);
- if (Offset != -1)
- AvailVal = GetStoreValueForLoad(DepSI->getValueOperand(), Offset,
- L->getType(), L, *TD);
- }
+ if (StoreInst *DepSI = dyn_cast<StoreInst>(Dep.getInst())) {
+ int Offset = AnalyzeLoadFromClobberingStore(L->getType(),
+ L->getPointerOperand(),
+ DepSI, *TD);
+ if (Offset != -1)
+ AvailVal = GetStoreValueForLoad(DepSI->getValueOperand(), Offset,
+ L->getType(), L, *TD);
+ }
+
+ // Check to see if we have something like this:
+ // load i32* P
+ // load i8* (P+1)
+ // if we have this, replace the later with an extraction from the former.
+ if (LoadInst *DepLI = dyn_cast<LoadInst>(Dep.getInst())) {
+ // If this is a clobber and L is the first instruction in its block, then
+ // we have the first instruction in the entry block.
+ if (DepLI == L)
+ return false;
+
+ int Offset = AnalyzeLoadFromClobberingLoad(L->getType(),
+ L->getPointerOperand(),
+ DepLI, *TD);
+ if (Offset != -1)
+ AvailVal = GetStoreValueForLoad(DepLI, Offset, L->getType(), L, *TD);
+ }
// If the clobbering value is a memset/memcpy/memmove, see if we can forward
// a value on from it.
if (MemIntrinsic *DepMI = dyn_cast<MemIntrinsic>(Dep.getInst())) {
- if (TD) {
- int Offset = AnalyzeLoadFromClobberingMemInst(L->getType(),
- L->getPointerOperand(),
- DepMI, *TD);
- if (Offset != -1)
- AvailVal = GetMemInstValueForLoad(DepMI, Offset, L->getType(), L,*TD);
- }
+ int Offset = AnalyzeLoadFromClobberingMemInst(L->getType(),
+ L->getPointerOperand(),
+ DepMI, *TD);
+ if (Offset != -1)
+ AvailVal = GetMemInstValueForLoad(DepMI, Offset, L->getType(), L, *TD);
}
if (AvailVal) {
@@ -1502,9 +1552,12 @@ bool GVN::processLoad(LoadInst *L, SmallVectorImpl<Instruction*> &toErase) {
++NumGVNLoad;
return true;
}
-
+ }
+
+ // If the value isn't available, don't do anything!
+ if (Dep.isClobber()) {
DEBUG(
- // fast print dep, using operator<< on instruction would be too slow
+ // fast print dep, using operator<< on instruction is too slow.
dbgs() << "GVN: load ";
WriteAsOperand(dbgs(), L);
Instruction *I = Dep.getInst();
@@ -1556,7 +1609,8 @@ bool GVN::processLoad(LoadInst *L, SmallVectorImpl<Instruction*> &toErase) {
// (depending on its type).
if (DepLI->getType() != L->getType()) {
if (TD) {
- AvailableVal = CoerceAvailableValueToLoadType(DepLI, L->getType(), L,*TD);
+ AvailableVal = CoerceAvailableValueToLoadType(DepLI, L->getType(),
+ L, *TD);
if (AvailableVal == 0)
return false;
diff --git a/test/Transforms/GVN/rle.ll b/test/Transforms/GVN/rle.ll
index 2e43321..42363d8 100644
--- a/test/Transforms/GVN/rle.ll
+++ b/test/Transforms/GVN/rle.ll
@@ -544,3 +544,30 @@ entry:
; CHECK: ret i32 0
}
+
+;;===----------------------------------------------------------------------===;;
+;; Load -> Load forwarding in partial alias case.
+;;===----------------------------------------------------------------------===;;
+
+define i32 @load_load_partial_alias(i8* %P) nounwind ssp {
+entry:
+ %0 = bitcast i8* %P to i32*
+ %tmp2 = load i32* %0
+ %add.ptr = getelementptr inbounds i8* %P, i64 1
+ %tmp5 = load i8* %add.ptr
+ %conv = zext i8 %tmp5 to i32
+ %add = add nsw i32 %tmp2, %conv
+ ret i32 %add
+
+; CHECK: @load_load_partial_alias
+; CHECK: load i32*
+; CHECK-NOT: load
+; CHECK: lshr i32 {{.*}}, 8
+; CHECK-NOT: load
+; CHECK: trunc i32 {{.*}} to i8
+; CHECK-NOT: load
+; CHECK: ret i32
+}
+
+
+