[PATCH] Alias analysis take advantage of "invariant.load" metadata
Shuxin Yang
shuxin.llvm at gmail.com
Tue Mar 5 14:50:27 PST 2013
Hi,
This defect is tracked by rdar://11311484.
The original motivating example is an ObjectiveC snippet.
Unfortunately, I know nothing
about ObjectiveC. So, I use following C snippet to illustrate the
motivation. The loads
are manually annotated with "invariant.load" metadata. (Compile the
snippet to get *.ll and
then then manually annotated the loads with "invariant.load" metadata)
With such annotation, GVN should be able to CSE away the redundant load.
------------------------
int foo(int *p, char *q) {
*q = (char)*p;
return *p + 1;
}
-------------------
The change is made to class MemoryDependenceAnalysis.
We rely on the "invariant.load" metadata only when the analyzer fails to
figure out if a load and
a store are definitely alias not definitely not alias,
I wish AliasAnalysis::alias() could take advantage of this
metadata. However the interface of class
AliasAnalysis is defined in a way such that we are not able to tell the
if the memory access in question
is load or store; it seem the compiler is not supposed to blindly say
'no-alias' for pair of loads because,
as far as I can tell, load-redundancy-elimination is triggered only
when some optimizers see
some may-alias or must-alias loads.
getMetadata("metadataname") seems to be pretty slow. In order to
speed it up, I add predefined id for
"invariant.load".
Thank you for code review!
Shuxin
-------------- next part --------------
Index: test/Analysis/BasicAA/invariant_load.ll
===================================================================
--- test/Analysis/BasicAA/invariant_load.ll (revision 0)
+++ test/Analysis/BasicAA/invariant_load.ll (revision 0)
@@ -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 !{}
Index: include/llvm/Analysis/MemoryDependenceAnalysis.h
===================================================================
--- include/llvm/Analysis/MemoryDependenceAnalysis.h (revision 176510)
+++ include/llvm/Analysis/MemoryDependenceAnalysis.h (working copy)
@@ -391,14 +391,17 @@
/// 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
Index: include/llvm/IR/LLVMContext.h
===================================================================
--- include/llvm/IR/LLVMContext.h (revision 176510)
+++ include/llvm/IR/LLVMContext.h (working copy)
@@ -46,7 +46,8 @@
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.
Index: lib/Analysis/MemoryDependenceAnalysis.cpp
===================================================================
--- lib/Analysis/MemoryDependenceAnalysis.cpp (revision 176510)
+++ lib/Analysis/MemoryDependenceAnalysis.cpp (working copy)
@@ -351,15 +351,23 @@
/// 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 @@
continue;
if (R == AliasAnalysis::MustAlias)
return MemDepResult::getDef(Inst);
+ if (isInvariantLoad)
+ continue;
return MemDepResult::getClobber(Inst);
}
@@ -571,7 +581,7 @@
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);
Index: lib/IR/LLVMContext.cpp
===================================================================
--- lib/IR/LLVMContext.cpp (revision 176510)
+++ lib/IR/LLVMContext.cpp (working copy)
@@ -58,6 +58,11 @@
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; }
More information about the llvm-commits
mailing list