diff --git a/include/llvm/Analysis/MemoryDependenceAnalysis.h b/include/llvm/Analysis/MemoryDependenceAnalysis.h index b87f886c006..47afd1b77b0 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 b3c558bbcd1..ae81e5b1c3b 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 38bf5dde39f..1faa04623ef 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(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(QueryInst) || isa(QueryInst)) { CallSite QueryCS(QueryInst); bool isReadOnly = AA->onlyReadsMemory(QueryCS); diff --git a/lib/IR/LLVMContext.cpp b/lib/IR/LLVMContext.cpp index b73cd03ddd6..883bb9878fa 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 00000000000..cd6ddb92d21 --- /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 !{}