aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNuno Lopes <nunoplopes@sapo.pt>2012-06-18 16:04:04 +0000
committerNuno Lopes <nunoplopes@sapo.pt>2012-06-18 16:04:04 +0000
commitfa7494306bc6fbe16cc82a67b93e762241b26777 (patch)
treebc87b64fbaa757a52d4a23c4558dcfd002d3085c
parent96ef284da415cccd60cf5066929a4683dec5dd79 (diff)
add the 'alloc' metadata node to represent the size of offset of buffers pointed to by pointers.
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
-rw-r--r--docs/LangRef.html44
-rw-r--r--include/llvm/LLVMContext.h3
-rw-r--r--lib/VMCore/LLVMContext.cpp5
-rw-r--r--lib/VMCore/Verifier.cpp33
-rw-r--r--test/Verifier/alloc-1.ll48
-rw-r--r--test/Verifier/alloc-2.ll19
6 files changed, 151 insertions, 1 deletions
diff --git a/docs/LangRef.html b/docs/LangRef.html
index 9cb7e6392a..2b81279b6e 100644
--- a/docs/LangRef.html
+++ b/docs/LangRef.html
@@ -105,6 +105,7 @@
<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>
diff --git a/include/llvm/LLVMContext.h b/include/llvm/LLVMContext.h
index a8306a9e76..d15f3e0850 100644
--- a/include/llvm/LLVMContext.h
+++ b/include/llvm/LLVMContext.h
@@ -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.
diff --git a/lib/VMCore/LLVMContext.cpp b/lib/VMCore/LLVMContext.cpp
index f07f0b3939..a140543a51 100644
--- a/lib/VMCore/LLVMContext.cpp
+++ b/lib/VMCore/LLVMContext.cpp
@@ -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; }
diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp
index 477b81dc67..2ca4854d9a 100644
--- a/lib/VMCore/Verifier.cpp
+++ b/lib/VMCore/Verifier.cpp
@@ -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
index 0000000000..60917a03be
--- /dev/null
+++ b/test/Verifier/alloc-1.ll
@@ -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
index 0000000000..10496d141a
--- /dev/null
+++ b/test/Verifier/alloc-2.ll
@@ -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}