From b7c941bad9b77d1456c2f5d01fca58dd641a5c01 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 18 Jun 2012 16:04:04 +0000 Subject: [PATCH] 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 llvm-svn: 158660 --- llvm/docs/LangRef.html | 44 ++++++++++++++++++++++++++++++ llvm/include/llvm/LLVMContext.h | 3 ++- llvm/lib/VMCore/LLVMContext.cpp | 5 ++++ llvm/lib/VMCore/Verifier.cpp | 33 +++++++++++++++++++++++ llvm/test/Verifier/alloc-1.ll | 48 +++++++++++++++++++++++++++++++++ llvm/test/Verifier/alloc-2.ll | 19 +++++++++++++ 6 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Verifier/alloc-1.ll create mode 100644 llvm/test/Verifier/alloc-2.ll diff --git a/llvm/docs/LangRef.html b/llvm/docs/LangRef.html index 9cb7e6392abf..2b81279b6e5b 100644 --- a/llvm/docs/LangRef.html +++ b/llvm/docs/LangRef.html @@ -105,6 +105,7 @@
  • 'tbaa' Metadata
  • 'fpmath' Metadata
  • 'range' Metadata
  • +
  • 'alloc' Metadata
  • @@ -3077,6 +3078,49 @@ call void @llvm.dbg.value(metadata !24, i64 0, metadata !25) + + +

    + 'alloc' Metadata +

    + +
    + +

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

    + +
    + +

    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.

    +

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

    + +
    + + +

    Examples:

    +
    +
    +  ; 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}
    +
    +
    +
    + diff --git a/llvm/include/llvm/LLVMContext.h b/llvm/include/llvm/LLVMContext.h index a8306a9e7617..d15f3e0850fe 100644 --- a/llvm/include/llvm/LLVMContext.h +++ b/llvm/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/llvm/lib/VMCore/LLVMContext.cpp b/llvm/lib/VMCore/LLVMContext.cpp index f07f0b393926..a140543a51e5 100644 --- a/llvm/lib/VMCore/LLVMContext.cpp +++ b/llvm/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/llvm/lib/VMCore/Verifier.cpp b/llvm/lib/VMCore/Verifier.cpp index 477b81dc67f5..2ca4854d9ac0 100644 --- a/llvm/lib/VMCore/Verifier.cpp +++ b/llvm/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(MD->getOperand(0)); + Function *OffsetFn = MD->getNumOperands() >= 2 ? + dyn_cast_or_null(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(I), "Ranges are only for loads!", &I); diff --git a/llvm/test/Verifier/alloc-1.ll b/llvm/test/Verifier/alloc-1.ll new file mode 100644 index 000000000000..60917a03be11 --- /dev/null +++ b/llvm/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/llvm/test/Verifier/alloc-2.ll b/llvm/test/Verifier/alloc-2.ll new file mode 100644 index 000000000000..10496d141a4e --- /dev/null +++ b/llvm/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}