aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 9cb7e63..2b81279 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 a8306a9..d15f3e0 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 f07f0b3..a140543 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 477b81d..2ca4854 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 0000000..60917a0
--- /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 0000000..10496d1
--- /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}