add the 'alloc' metadata node to represent the size of offset of buffers pointed...
authorNuno Lopes <nunoplopes@sapo.pt>
Mon, 18 Jun 2012 16:04:04 +0000 (16:04 +0000)
committerNuno Lopes <nunoplopes@sapo.pt>
Mon, 18 Jun 2012 16:04:04 +0000 (16:04 +0000)
This metadata can be attached to any instruction returning a pointer

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@158660 91177308-0d34-0410-b5e6-96231b3b80d8

docs/LangRef.html
include/llvm/LLVMContext.h
lib/VMCore/LLVMContext.cpp
lib/VMCore/Verifier.cpp
test/Verifier/alloc-1.ll [new file with mode: 0644]
test/Verifier/alloc-2.ll [new file with mode: 0644]

index 9cb7e6392abf1e9ec84238d98a0a28d4ac249bfd..2b81279b6e5b50a2b42c93c25c45d6c1664428d9 100644 (file)
           <li><a href="#tbaa">'<tt>tbaa</tt>' Metadata</a></li>
           <li><a href="#fpmath">'<tt>fpmath</tt>' Metadata</a></li>
           <li><a href="#range">'<tt>range</tt>' Metadata</a></li>
+          <li><a href="#alloc">'<tt>alloc</tt>' Metadata</a></li>
         </ol>
       </li>
     </ol>
@@ -3077,6 +3078,49 @@ call void @llvm.dbg.value(metadata !24, i64 0, metadata !25)
 </pre>
 </div>
 </div>
+
+<!-- _______________________________________________________________________ -->
+<h4>
+  <a name="alloc">'<tt>alloc</tt>' Metadata</a>
+</h4>
+<div>
+
+<p><tt>alloc</tt> metadata may be attached to any instruction returning a
+   pointer. It can be used to express the size and offset relative to the
+   beginning of the buffer pointed by.</p>
+
+<blockquote>
+
+<p>The first parameter is a function that returns the size of the buffer, and
+   the second (optional) parameter is a function that returns the offset from
+   the beginning of the buffer. If the second parameter is not present or null,
+   the offset is assumed to be null. Both functions must be either readonly or
+   readnone.</p>
+<p><tt>alloc</tt> metadata can have additional parameters, which are passed to
+   the size and offset functions when they are evaluated. Therefore the size and
+   offset functions must have the same signature.</p>
+
+</blockquote>
+
+
+<p>Examples:</p>
+<div class="doc_code">
+<pre>
+  ; size of buffer allocated by this call is my_malloc_size(%s), and offset=0
+  %a = call my_malloc(%s), !alloc !{i32 (i32)* @my_malloc_size, null, i32 %s}
+
+  ; size of the buffer pointed by *ptr is size(%x), and offset=offset(%x)
+  %b = load i8** %foo, !alloc !{i32 (i32)* @size, i32 (i32)* @offset, i32 %x}
+
+  ; size of buffer allocated by this call is foo_size(), and offset=0
+  %a = call alloc_foo(%s), !alloc !0
+...
+!0 = metadata {i32 ()* @foo_size}
+</pre>
+</div>
+</div>
+
 </div>
 
 </div>
index a8306a9e7617cf848b032647d1655ed6b333ab47..d15f3e0850fe3c6db1a399a322bfbb3f88bff1f4 100644 (file)
@@ -43,7 +43,8 @@ public:
     MD_tbaa = 1, // "tbaa"
     MD_prof = 2,  // "prof"
     MD_fpmath = 3,  // "fpmath"
-    MD_range = 4 // "range"
+    MD_range = 4, // "range"
+    MD_alloc = 5 // "alloc"
   };
   
   /// getMDKindID - Return a unique non-zero ID for the specified metadata kind.
index f07f0b3939262db465d801c7ce484a55c40c7ca3..a140543a51e5901b8ad8157a4af941b2d362067d 100644 (file)
@@ -53,6 +53,11 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) {
   unsigned RangeID = getMDKindID("range");
   assert(RangeID == MD_range && "range kind id drifted");
   (void)RangeID;
+
+  // Create the 'alloc' metadata kind.
+  unsigned AllocID = getMDKindID("alloc");
+  assert(AllocID == MD_alloc && "alloc kind id drifted");
+  (void)AllocID;
 }
 LLVMContext::~LLVMContext() { delete pImpl; }
 
index 477b81dc67f5e002216caa39f2a28229c885833e..2ca4854d9ac07b3111370d42a5b4d3be08be6fb9 100644 (file)
@@ -1672,6 +1672,39 @@ void Verifier::visitInstruction(Instruction &I) {
     }
   }
 
+  if (MDNode *MD = I.getMetadata(LLVMContext::MD_alloc)) {
+    Assert1(I.getType()->isPointerTy(), "alloc requires a pointer result", &I);
+    Assert1(MD->getNumOperands() >= 1, "alloc takes at least one operand", &I);
+    Function *SizeFn = dyn_cast<Function>(MD->getOperand(0));
+    Function *OffsetFn = MD->getNumOperands() >= 2 ?
+                         dyn_cast_or_null<Function>(MD->getOperand(1)) : 0;
+    Assert1(SizeFn, "first parameter of alloc must be a function", &I);
+    Assert1(MD->getNumOperands() == 1 || !MD->getOperand(1) || OffsetFn,
+            "second parameter of alloc must be either a function or null", &I);
+    Assert1(SizeFn->onlyReadsMemory(),
+            "size function must be readonly/readnone", &I);
+    Assert1(!OffsetFn || OffsetFn->onlyReadsMemory(),
+            "offset function must be readonly/readnone", &I);
+    Assert1(SizeFn->getReturnType()->isIntegerTy(),
+            "size function must return an integer", &I);
+    Assert1(!OffsetFn || OffsetFn->getReturnType()->isIntegerTy(),
+            "offset function must return an integer", &I);
+
+    FunctionType *SizeFnTy = SizeFn->getFunctionType();
+    FunctionType *OffsetFnTy = OffsetFn ? OffsetFn->getFunctionType() : 0;
+    Assert1(SizeFnTy->getNumParams() == MD->getNumOperands()-2,
+            "size function number of parameters mismatch", &I);
+    Assert1(!OffsetFnTy || OffsetFnTy->getNumParams() == MD->getNumOperands()-2,
+            "offset function number of parameters mismatch", &I);
+    for (unsigned i = 0, e = SizeFnTy->getNumParams(); i != e; ++i) {
+      Assert1(SizeFnTy->getParamType(i) == MD->getOperand(i+2)->getType(),
+              "size function parameter type mismatch", &I);
+      if (OffsetFnTy)
+        Assert1(OffsetFnTy->getParamType(i) == MD->getOperand(i+2)->getType(),
+                "offset function parameter type mismatch", &I);
+    }
+  }
+
   MDNode *MD = I.getMetadata(LLVMContext::MD_range);
   Assert1(!MD || isa<LoadInst>(I), "Ranges are only for loads!", &I);
 
diff --git a/test/Verifier/alloc-1.ll b/test/Verifier/alloc-1.ll
new file mode 100644 (file)
index 0000000..60917a0
--- /dev/null
@@ -0,0 +1,48 @@
+; RUN: not llvm-as < %s -o /dev/null |& FileCheck %s
+
+declare i32 @size() readonly
+declare i32 @sizeR()
+declare i32 @size1(i32) readnone
+declare i32 @size1i8(i8) readnone
+declare i32* @sizeptr() readnone
+
+define void @f1(i8** %x, i32* %y) {
+entry:
+  %0 = load i8** %x, !alloc !0
+  %1 = load i8** %x, !alloc !1
+  %2 = load i8** %x, !alloc !2
+  %3 = load i8** %x, !alloc !3
+  %4 = load i8** %x, !alloc !4
+  %5 = load i8** %x, !alloc !5
+  %6 = load i8** %x, !alloc !6
+  %7 = load i8** %x, !alloc !7
+  %8 = load i8** %x, !alloc !8
+  %9 = load i32* %y, !alloc !9
+  %10 = load i8** %x, !alloc !10
+  %11 = load i8** %x, !alloc !11
+  ret void
+}
+; CHECK: alloc takes at least one operand
+!0 = metadata !{}
+; CHECK: first parameter of alloc must be a function
+!1 = metadata !{i32 0}
+; CHECK: second parameter of alloc must be either a function or null
+!2 = metadata !{i32 ()* @size, i32 0}
+; CHECK: size function number of parameters mismatch
+!3 = metadata !{i32 ()* @size, null, i32 0}
+; CHECK: offset function number of parameters mismatch
+!4 = metadata !{i32 (i32)* @size1, i32 ()* @size, i32 1}
+; CHECK: size function must be readonly/readnone
+!5 = metadata !{i32 ()* @sizeR, i32 ()* @size}
+; CHECK: offset function must be readonly/readnone
+!6 = metadata !{i32 ()* @size, i32 ()* @sizeR}
+; CHECK: size function parameter type mismatch
+!7 = metadata !{i32 (i32)* @size1, i32 (i8)* @size1i8, i8 5}
+; CHECK: offset function parameter type mismatch
+!8 = metadata !{i32 (i8)* @size1i8, i32 (i32)* @size1, i8 5}
+; CHECK: alloc requires a pointer result
+!9 = metadata !{i32 ()* @size, null}
+; CHECK: size function must return an integer
+!10 = metadata !{i32* ()* @sizeptr, null}
+; CHECK: offset function must return an integer
+!11 = metadata !{i32 ()* @size, i32* ()* @sizeptr}
diff --git a/test/Verifier/alloc-2.ll b/test/Verifier/alloc-2.ll
new file mode 100644 (file)
index 0000000..10496d1
--- /dev/null
@@ -0,0 +1,19 @@
+; RUN: llvm-as < %s -o /dev/null
+
+declare i32 @size() readonly
+declare i32 @size1(i32) readnone
+declare i32 @size1i8(i8) readnone
+
+define void @ok(i8** %x, i32 %y) {
+entry:
+  %0 = load i8** %x, !alloc !0
+  %1 = load i8** %x, !alloc !1
+  %2 = load i8** %x, !alloc !2
+  %3 = load i8** %x, !alloc !3
+  %4 = load i8** %x, !alloc !{i32 (i32)* @size1, i32 (i32)* @size1, i32 %y}
+  ret void
+}
+!0 = metadata !{i32 ()* @size, i32 ()* @size}
+!1 = metadata !{i32 ()* @size, null}
+!2 = metadata !{i32 (i32)* @size1, i32 (i32)* @size1, i32 0}
+!3 = metadata !{i32 (i8)* @size1i8, i32 (i8)* @size1i8, i8 0}