diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1683,8 +1683,10 @@ SmallPtrSet Visited; if (!PTy->getElementType()->isSized(&Visited)) { Assert(!Attrs.hasAttribute(Attribute::ByVal) && - !Attrs.hasAttribute(Attribute::InAlloca), - "Attributes 'byval' and 'inalloca' do not support unsized types!", + !Attrs.hasAttribute(Attribute::InAlloca) && + !Attrs.hasAttribute(Attribute::Preallocated), + "Attributes 'byval', 'inalloca', and 'preallocated' do not " + "support unsized types!", V); } if (!isa(PTy->getElementType())) @@ -2959,6 +2961,22 @@ } } + // For each argument with the preallocated attribute, make sure it matches the + // callee's parameter's attribute + for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) { + if (Call.paramHasAttr(i, Attribute::Preallocated)) { + Assert(Callee && Callee->hasParamAttribute(i, Attribute::Preallocated), + "preallocated argument should match callee's parameter attribute"); + auto CallAttrs = Call.getAttributes().getParamAttributes(i); + auto CalleeAttrs = Callee->getAttributes().getParamAttributes(i); + + Assert( + CallAttrs.getPreallocatedType() == CalleeAttrs.getPreallocatedType(), + "preallocated type must match between argument and callee parameter", + Call.getArgOperand(i), Call); + } + } + if (FTy->isVarArg()) { // FIXME? is 'nest' even legal here? bool SawNest = false; diff --git a/llvm/test/Verifier/call_setup_invalid.ll b/llvm/test/Verifier/call_setup_invalid.ll --- a/llvm/test/Verifier/call_setup_invalid.ll +++ b/llvm/test/Verifier/call_setup_invalid.ll @@ -7,7 +7,8 @@ declare token @llvm.what() declare void @foo0() -declare void @foo1(i32*) +declare void @foo1(i32* preallocated(i32)) +declare void @bar1(i32*) declare i32 @blackbox() ; CHECK: "callsetup" argument must be a token from llvm.call.setup @@ -65,10 +66,20 @@ } ; CHECK: Attribute 'preallocated' type does not match parameter -define void @call_setup_allocated_type_mismatch() { +define void @call_setup_preallocated_type_mismatch() { %cs = call token @llvm.call.setup(i32 1) %x = call i8* @llvm.call.alloc(token %cs, i32 0) %y = bitcast i8* %x to i32* call void @foo1(i32* preallocated(i8) %y) ["callsetup"(token %cs)] ret void } + +; CHECK: preallocated type must match between argument and callee parameter +; @bar1's parameter does not have the preallocated attribute +define void @call_setup_preallocated_signature() { + %cs = call token @llvm.call.setup(i32 1) + %x = call i8* @llvm.call.alloc(token %cs, i32 0) + %y = bitcast i8* %x to i32* + call void @bar1(i32* preallocated(i32) %y) ["callsetup"(token %cs)] + ret void +} diff --git a/llvm/test/Verifier/call_setup_valid.ll b/llvm/test/Verifier/call_setup_valid.ll --- a/llvm/test/Verifier/call_setup_valid.ll +++ b/llvm/test/Verifier/call_setup_valid.ll @@ -3,7 +3,7 @@ declare token @llvm.call.setup(i32) declare i8* @llvm.call.alloc(token, i32) -declare void @f1(i32*) +declare void @f1(i32* preallocated(i32)) define void @callsetup() { %cs = call token @llvm.call.setup(i32 1)