aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Analysis/MemoryDependenceAnalysis.h7
-rw-r--r--include/llvm/IR/LLVMContext.h3
-rw-r--r--lib/Analysis/MemoryDependenceAnalysis.cpp18
-rw-r--r--lib/IR/LLVMContext.cpp5
-rw-r--r--test/Analysis/BasicAA/invariant_load.ll29
5 files changed, 55 insertions, 7 deletions
diff --git a/include/llvm/Analysis/MemoryDependenceAnalysis.h b/include/llvm/Analysis/MemoryDependenceAnalysis.h
index b87f886c00..47afd1b77b 100644
--- a/include/llvm/Analysis/MemoryDependenceAnalysis.h
+++ b/include/llvm/Analysis/MemoryDependenceAnalysis.h
@@ -391,14 +391,17 @@ namespace llvm {
/// getPointerDependencyFrom - Return the instruction on which a memory
/// location depends. If isLoad is true, this routine ignores may-aliases
/// with read-only operations. If isLoad is false, this routine ignores
- /// may-aliases with reads from read-only locations.
+ /// may-aliases with reads from read-only locations. If possible, pass
+ /// the query instruction as well; this function may take advantage of
+ /// the metadata annotated to the query instruction to refine the result.
///
/// Note that this is an uncached query, and thus may be inefficient.
///
MemDepResult getPointerDependencyFrom(const AliasAnalysis::Location &Loc,
bool isLoad,
BasicBlock::iterator ScanIt,
- BasicBlock *BB);
+ BasicBlock *BB,
+ Instruction *QueryInst = 0);
/// getLoadLoadClobberFullWidthSize - This is a little bit of analysis that
diff --git a/include/llvm/IR/LLVMContext.h b/include/llvm/IR/LLVMContext.h
index b3c558bbcd..ae81e5b1c3 100644
--- a/include/llvm/IR/LLVMContext.h
+++ b/include/llvm/IR/LLVMContext.h
@@ -46,7 +46,8 @@ public:
MD_prof = 2, // "prof"
MD_fpmath = 3, // "fpmath"
MD_range = 4, // "range"
- MD_tbaa_struct = 5 // "tbaa.struct"
+ MD_tbaa_struct = 5, // "tbaa.struct"
+ MD_invariant_load = 6 // "invariant.load"
};
/// getMDKindID - Return a unique non-zero ID for the specified metadata kind.
diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp
index 38bf5dde39..1faa04623e 100644
--- a/lib/Analysis/MemoryDependenceAnalysis.cpp
+++ b/lib/Analysis/MemoryDependenceAnalysis.cpp
@@ -351,15 +351,23 @@ getLoadLoadClobberFullWidthSize(const Value *MemLocBase, int64_t MemLocOffs,
/// getPointerDependencyFrom - Return the instruction on which a memory
/// location depends. If isLoad is true, this routine ignores may-aliases with
/// read-only operations. If isLoad is false, this routine ignores may-aliases
-/// with reads from read-only locations.
+/// with reads from read-only locations. If possible, pass the query
+/// instruction as well; this function may take advantage of the metadata
+/// annotated to the query instruction to refine the result.
MemDepResult MemoryDependenceAnalysis::
getPointerDependencyFrom(const AliasAnalysis::Location &MemLoc, bool isLoad,
- BasicBlock::iterator ScanIt, BasicBlock *BB) {
+ BasicBlock::iterator ScanIt, BasicBlock *BB,
+ Instruction *QueryInst) {
const Value *MemLocBase = 0;
int64_t MemLocOffset = 0;
-
unsigned Limit = BlockScanLimit;
+ bool isInvariantLoad = false;
+ if (isLoad && QueryInst) {
+ LoadInst *LI = dyn_cast<LoadInst>(QueryInst);
+ if (LI && LI->getMetadata(LLVMContext::MD_invariant_load) != 0)
+ isInvariantLoad = true;
+ }
// Walk backwards through the basic block, looking for dependencies.
while (ScanIt != BB->begin()) {
@@ -474,6 +482,8 @@ getPointerDependencyFrom(const AliasAnalysis::Location &MemLoc, bool isLoad,
continue;
if (R == AliasAnalysis::MustAlias)
return MemDepResult::getDef(Inst);
+ if (isInvariantLoad)
+ continue;
return MemDepResult::getClobber(Inst);
}
@@ -571,7 +581,7 @@ MemDepResult MemoryDependenceAnalysis::getDependency(Instruction *QueryInst) {
isLoad |= II->getIntrinsicID() == Intrinsic::lifetime_start;
LocalCache = getPointerDependencyFrom(MemLoc, isLoad, ScanPos,
- QueryParent);
+ QueryParent, QueryInst);
} else if (isa<CallInst>(QueryInst) || isa<InvokeInst>(QueryInst)) {
CallSite QueryCS(QueryInst);
bool isReadOnly = AA->onlyReadsMemory(QueryCS);
diff --git a/lib/IR/LLVMContext.cpp b/lib/IR/LLVMContext.cpp
index b73cd03ddd..883bb9878f 100644
--- a/lib/IR/LLVMContext.cpp
+++ b/lib/IR/LLVMContext.cpp
@@ -58,6 +58,11 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) {
unsigned TBAAStructID = getMDKindID("tbaa.struct");
assert(TBAAStructID == MD_tbaa_struct && "tbaa.struct kind id drifted");
(void)TBAAStructID;
+
+ // Create the 'invariant.load' metadata kind.
+ unsigned InvariantLdId = getMDKindID("invariant.load");
+ assert(InvariantLdId == MD_invariant_load && "invariant.load kind id drifted");
+ (void)InvariantLdId;
}
LLVMContext::~LLVMContext() { delete pImpl; }
diff --git a/test/Analysis/BasicAA/invariant_load.ll b/test/Analysis/BasicAA/invariant_load.ll
new file mode 100644
index 0000000000..cd6ddb92d2
--- /dev/null
+++ b/test/Analysis/BasicAA/invariant_load.ll
@@ -0,0 +1,29 @@
+; RUN: opt < %s -basicaa -gvn -S | FileCheck %s
+
+; The input *.ll is obtained by manually annotating "invariant.load" to the
+; two loads. With "invariant.load" metadata, the second load is redundant.
+;
+; int foo(int *p, char *q) {
+; *q = (char)*p;
+; return *p + 1;
+; }
+
+define i32 @foo(i32* nocapture %p, i8* nocapture %q) {
+entry:
+ %0 = load i32* %p, align 4, !tbaa !0, !invariant.load !3
+ %conv = trunc i32 %0 to i8
+ store i8 %conv, i8* %q, align 1, !tbaa !1
+ %1 = load i32* %p, align 4, !tbaa !0, !invariant.load !3
+ %add = add nsw i32 %1, 1
+ ret i32 %add
+
+; CHECK: foo
+; CHECK: %0 = load i32* %p
+; CHECK: store i8 %conv, i8* %q,
+; CHECK: %add = add nsw i32 %0, 1
+}
+
+!0 = metadata !{metadata !"int", metadata !1}
+!1 = metadata !{metadata !"omnipotent char", metadata !2}
+!2 = metadata !{metadata !"Simple C/C++ TBAA"}
+!3 = metadata !{}