summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2009-12-06 05:29:56 +0000
committerChris Lattner <sabre@nondot.org>2009-12-06 05:29:56 +0000
commit778cb92235aa8db2f105873058404a3898322b70 (patch)
treebf3c9f89d744ad4ca86b4041f94c8c697d32f3e0
parent93236ba32775264aced69dcd6b3048367fa6b9ca (diff)
downloadbcm5719-llvm-778cb92235aa8db2f105873058404a3898322b70.tar.gz
bcm5719-llvm-778cb92235aa8db2f105873058404a3898322b70.zip
constant fold loads from memcpy's from global constants. This is important
because clang lowers nontrivial automatic struct/array inits to memcpy from a global array. llvm-svn: 90698
-rw-r--r--llvm/lib/Transforms/Scalar/GVN.cpp52
-rw-r--r--llvm/test/Transforms/GVN/rle.ll16
2 files changed, 62 insertions, 6 deletions
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 7454f62b388..b703a76ba90 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -31,8 +31,9 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/ConstantFolding.h"
+#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Support/CFG.h"
@@ -1094,11 +1095,39 @@ static int AnalyzeLoadFromClobberingMemInst(LoadInst *L, MemIntrinsic *MI,
ConstantInt *SizeCst = dyn_cast<ConstantInt>(MI->getLength());
if (SizeCst == 0) return -1;
uint64_t MemSizeInBits = SizeCst->getZExtValue()*8;
-
+
+ // If this is memset, we just need to see if the offset is valid in the size
+ // of the memset..
if (MI->getIntrinsicID() == Intrinsic::memset)
return AnalyzeLoadFromClobberingWrite(L, MI->getDest(), MemSizeInBits, TD);
- // Unhandled memcpy/memmove.
+ // If we have a memcpy/memmove, the only case we can handle is if this is a
+ // copy from constant memory. In that case, we can read directly from the
+ // constant memory.
+ MemTransferInst *MTI = cast<MemTransferInst>(MI);
+
+ Constant *Src = dyn_cast<Constant>(MTI->getSource());
+ if (Src == 0) return -1;
+
+ GlobalVariable *GV = dyn_cast<GlobalVariable>(Src->getUnderlyingObject());
+ if (GV == 0 || !GV->isConstant()) return -1;
+
+ // See if the access is within the bounds of the transfer.
+ int Offset =
+ AnalyzeLoadFromClobberingWrite(L, MI->getDest(), MemSizeInBits, TD);
+ if (Offset == -1)
+ return Offset;
+
+ // Otherwise, see if we can constant fold a load from the constant with the
+ // offset applied as appropriate.
+ Src = ConstantExpr::getBitCast(Src,
+ llvm::Type::getInt8PtrTy(Src->getContext()));
+ Constant *OffsetCst =
+ ConstantInt::get(Type::getInt64Ty(Src->getContext()), (unsigned)Offset);
+ Src = ConstantExpr::getGetElementPtr(Src, &OffsetCst, 1);
+ Src = ConstantExpr::getBitCast(Src, PointerType::getUnqual(L->getType()));
+ if (ConstantFoldLoadFromConstPtr(Src, &TD))
+ return Offset;
return -1;
}
@@ -1182,9 +1211,20 @@ static Value *GetMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset,
return CoerceAvailableValueToLoadType(Val, LoadTy, InsertPt, TD);
}
-
- // ABORT;
- return 0;
+
+ // Otherwise, this is a memcpy/memmove from a constant global.
+ MemTransferInst *MTI = cast<MemTransferInst>(SrcInst);
+ Constant *Src = cast<Constant>(MTI->getSource());
+
+ // Otherwise, see if we can constant fold a load from the constant with the
+ // offset applied as appropriate.
+ Src = ConstantExpr::getBitCast(Src,
+ llvm::Type::getInt8PtrTy(Src->getContext()));
+ Constant *OffsetCst =
+ ConstantInt::get(Type::getInt64Ty(Src->getContext()), (unsigned)Offset);
+ Src = ConstantExpr::getGetElementPtr(Src, &OffsetCst, 1);
+ Src = ConstantExpr::getBitCast(Src, PointerType::getUnqual(LoadTy));
+ return ConstantFoldLoadFromConstPtr(Src, &TD);
}
diff --git a/llvm/test/Transforms/GVN/rle.ll b/llvm/test/Transforms/GVN/rle.ll
index af025570b3c..e667eece85d 100644
--- a/llvm/test/Transforms/GVN/rle.ll
+++ b/llvm/test/Transforms/GVN/rle.ll
@@ -187,8 +187,24 @@ Cont:
; CHECK: ret i16 %A
}
+@GCst = constant {i32, float, i32 } { i32 42, float 14., i32 97 }
+
+; memset -> float forwarding.
+define float @memcpy_to_float_local(float* %A) nounwind ssp {
+entry:
+ %conv = bitcast float* %A to i8* ; <i8*> [#uses=1]
+ tail call void @llvm.memcpy.i64(i8* %conv, i8* bitcast ({i32, float, i32 }* @GCst to i8*), i64 12, i32 1)
+ %arrayidx = getelementptr inbounds float* %A, i64 1 ; <float*> [#uses=1]
+ %tmp2 = load float* %arrayidx ; <float> [#uses=1]
+ ret float %tmp2
+; CHECK: @memcpy_to_float_local
+; CHECK-NOT: load
+; CHECK: ret float 1.400000e+01
+}
+
declare void @llvm.memset.i64(i8* nocapture, i8, i64, i32) nounwind
+declare void @llvm.memcpy.i64(i8* nocapture, i8* nocapture, i64, i32) nounwind
OpenPOWER on IntegriCloud