[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