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
This commit is contained in:
Nuno Lopes 2012-06-18 16:04:04 +00:00
parent 96ef284da4
commit fa7494306b
6 changed files with 151 additions and 1 deletions

View File

@ -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>

View 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.

View 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; }

View 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);

48
test/Verifier/alloc-1.ll Normal file
View File

@ -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}

19
test/Verifier/alloc-2.ll Normal file
View File

@ -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}