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 @@ -3277,10 +3277,32 @@ "Return type cannot be x86_amx for indirect call!"); } - if (Function *F = Call.getCalledFunction()) - if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) + if (Function *F = Call.getCalledFunction()) { + if (Intrinsic::ID ID = F->getIntrinsicID()) visitIntrinsicCall(ID, Call); + // Verify that arguments have matching attributes as the callee's + // parameters. + for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) { + if (F->hasParamAttribute(i, Attribute::InAlloca)) { + Assert(Attrs.getParamAttributes(i).hasAttribute(Attribute::InAlloca), + "argument to inalloca parameter requires inalloca attribute", + Call); + } + if (F->hasParamAttribute(i, Attribute::ByVal)) { + Assert(Attrs.getParamAttributes(i).hasAttribute(Attribute::ByVal), + "argument to byval parameter requires byval attribute", Call); + } + if (F->hasParamAttribute(i, Attribute::Preallocated)) { + Assert( + Attrs.getParamAttributes(i).hasAttribute(Attribute::Preallocated), + "argument to preallocated parameter requires preallocated " + "attribute", + Call); + } + } + } + // Verify that a callsite has at most one "deopt", at most one "funclet", at // most one "gc-transition", at most one "cfguardtarget", // and at most one "preallocated" operand bundle. diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-call-sret.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-call-sret.ll --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-call-sret.ll +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-call-sret.ll @@ -73,7 +73,7 @@ %in.gep1 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %in.val, i32 0, i32 1 store i8 3, i8 addrspace(5)* %in.gep0 store i32 8, i32 addrspace(5)* %in.gep1 - call void @external_void_func_sret_struct_i8_i32_byval_struct_i8_i32({ i8, i32 } addrspace(5)* %out.val, { i8, i32 } addrspace(5)* %in.val) + call void @external_void_func_sret_struct_i8_i32_byval_struct_i8_i32({ i8, i32 } addrspace(5)* %out.val, { i8, i32 } addrspace(5)* byval({i8, i32}) %in.val) %out.gep0 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %out.val, i32 0, i32 0 %out.gep1 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %out.val, i32 0, i32 1 %out.val0 = load i8, i8 addrspace(5)* %out.gep0 diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-call.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-call.ll --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-call.ll +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-call.ll @@ -3991,7 +3991,7 @@ ; CHECK: ADJCALLSTACKDOWN 0, 36, implicit-def $scc ; CHECK: [[COPY21:%[0-9]+]]:ccr_sgpr_64 = COPY [[COPY10]] ; CHECK: S_SETPC_B64_return [[COPY21]] - call void @void_func_byval_a3i32_byval_i8_align32([3 x i32] addrspace(5)* byval([3 x i32]) %incoming0, i8 addrspace(5)* align 32 %incoming1, i32 999) + call void @void_func_byval_a3i32_byval_i8_align32([3 x i32] addrspace(5)* byval([3 x i32]) %incoming0, i8 addrspace(5)* byval(i8) align 32 %incoming1, i32 999) ret void } diff --git a/llvm/test/CodeGen/AMDGPU/callee-special-input-vgprs-packed.ll b/llvm/test/CodeGen/AMDGPU/callee-special-input-vgprs-packed.ll --- a/llvm/test/CodeGen/AMDGPU/callee-special-input-vgprs-packed.ll +++ b/llvm/test/CodeGen/AMDGPU/callee-special-input-vgprs-packed.ll @@ -517,7 +517,7 @@ i32 210, i32 220, i32 230, i32 240, i32 250, i32 260, i32 270, i32 280, i32 290, i32 300, i32 310, i32 320, - i32 addrspace(5)* %alloca) + i32 addrspace(5)* byval(i32) %alloca) ret void } @@ -541,7 +541,7 @@ i32 210, i32 220, i32 230, i32 240, i32 250, i32 260, i32 270, i32 280, i32 290, i32 300, i32 310, i32 320, - i32 addrspace(5)* %alloca) + i32 addrspace(5)* byval(i32) %alloca) ret void } diff --git a/llvm/test/CodeGen/AMDGPU/callee-special-input-vgprs.ll b/llvm/test/CodeGen/AMDGPU/callee-special-input-vgprs.ll --- a/llvm/test/CodeGen/AMDGPU/callee-special-input-vgprs.ll +++ b/llvm/test/CodeGen/AMDGPU/callee-special-input-vgprs.ll @@ -649,7 +649,7 @@ i32 210, i32 220, i32 230, i32 240, i32 250, i32 260, i32 270, i32 280, i32 290, i32 300, i32 310, i32 320, - i32 addrspace(5)* %alloca) + i32 addrspace(5)* byval(i32) %alloca) ret void } @@ -686,7 +686,7 @@ i32 210, i32 220, i32 230, i32 240, i32 250, i32 260, i32 270, i32 280, i32 290, i32 300, i32 310, i32 320, - i32 addrspace(5)* %alloca) + i32 addrspace(5)* byval(i32) %alloca) ret void } diff --git a/llvm/test/CodeGen/AMDGPU/gfx-callable-argument-types.ll b/llvm/test/CodeGen/AMDGPU/gfx-callable-argument-types.ll --- a/llvm/test/CodeGen/AMDGPU/gfx-callable-argument-types.ll +++ b/llvm/test/CodeGen/AMDGPU/gfx-callable-argument-types.ll @@ -3081,7 +3081,7 @@ %gep1 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %val, i32 0, i32 1 store i8 3, i8 addrspace(5)* %gep0 store i32 8, i32 addrspace(5)* %gep1 - call amdgpu_gfx void @external_void_func_byval_struct_i8_i32({ i8, i32 } addrspace(5)* %val) + call amdgpu_gfx void @external_void_func_byval_struct_i8_i32({ i8, i32 } addrspace(5)* byval({ i8, i32 }) %val) ret void } @@ -3173,7 +3173,7 @@ %in.gep1 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %in.val, i32 0, i32 1 store i8 3, i8 addrspace(5)* %in.gep0 store i32 8, i32 addrspace(5)* %in.gep1 - call amdgpu_gfx void @external_void_func_sret_struct_i8_i32_byval_struct_i8_i32({ i8, i32 } addrspace(5)* %out.val, { i8, i32 } addrspace(5)* %in.val) + call amdgpu_gfx void @external_void_func_sret_struct_i8_i32_byval_struct_i8_i32({ i8, i32 } addrspace(5)* %out.val, { i8, i32 } addrspace(5)* byval({ i8, i32 }) %in.val) %out.gep0 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %out.val, i32 0, i32 0 %out.gep1 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %out.val, i32 0, i32 1 %out.val0 = load i8, i8 addrspace(5)* %out.gep0 diff --git a/llvm/test/CodeGen/WebAssembly/byval.ll b/llvm/test/CodeGen/WebAssembly/byval.ll --- a/llvm/test/CodeGen/WebAssembly/byval.ll +++ b/llvm/test/CodeGen/WebAssembly/byval.ll @@ -101,7 +101,7 @@ define void @byval_empty_callee(%EmptyStruct* byval(%EmptyStruct) %ptr) { ; CHECK: .functype byval_empty_callee (i32) -> () ; CHECK: call ext_func_empty, $0 - call void @ext_func_empty(%EmptyStruct* %ptr) + call void @ext_func_empty(%EmptyStruct* byval(%EmptyStruct) %ptr) ret void } diff --git a/llvm/test/CodeGen/X86/movtopush.ll b/llvm/test/CodeGen/X86/movtopush.ll --- a/llvm/test/CodeGen/X86/movtopush.ll +++ b/llvm/test/CodeGen/X86/movtopush.ll @@ -307,9 +307,9 @@ define void @test12() optsize { entry: %s = alloca %struct.s, align 4 - call void @struct(%struct.s* %s, i32 2, i32 3, i32 4) + call void @struct(%struct.s* byval(%struct.s) %s, i32 2, i32 3, i32 4) call void @good(i32 5, i32 6, i32 7, i32 8) - call void @struct(%struct.s* %s, i32 10, i32 11, i32 12) + call void @struct(%struct.s* byval(%struct.s) %s, i32 10, i32 11, i32 12) ret void } @@ -340,7 +340,7 @@ entry: %s = alloca %struct.s, align 4 call void @good(i32 1, i32 2, i32 3, i32 4) - call void @struct(%struct.s* %s, i32 6, i32 7, i32 8) + call void @struct(%struct.s* byval(%struct.s) %s, i32 6, i32 7, i32 8) call void @good(i32 9, i32 10, i32 11, i32 12) ret void } diff --git a/llvm/test/Transforms/ArgumentPromotion/dbg.ll b/llvm/test/Transforms/ArgumentPromotion/dbg.ll --- a/llvm/test/Transforms/ArgumentPromotion/dbg.ll +++ b/llvm/test/Transforms/ArgumentPromotion/dbg.ll @@ -46,7 +46,7 @@ ; call void @test(i32** %Y), !dbg !1 - call void @test_byval(%struct.pair* %P), !dbg !6 + call void @test_byval(%struct.pair* byval(%struct.pair) %P), !dbg !6 ret void } diff --git a/llvm/test/Transforms/ArgumentPromotion/fp80.ll b/llvm/test/Transforms/ArgumentPromotion/fp80.ll --- a/llvm/test/Transforms/ArgumentPromotion/fp80.ll +++ b/llvm/test/Transforms/ArgumentPromotion/fp80.ll @@ -20,15 +20,15 @@ ; CHECK-NEXT: [[DOT0:%.*]] = getelementptr [[UNION_U:%.*]], %union.u* bitcast (%struct.s* @b to %union.u*), i32 0, i32 0 ; CHECK-NEXT: [[DOT0_VAL:%.*]] = load x86_fp80, x86_fp80* [[DOT0]] ; CHECK-NEXT: [[TMP1:%.*]] = tail call x86_fp80 @UseLongDoubleSafely(x86_fp80 [[DOT0_VAL]]) -; CHECK-NEXT: [[TMP2:%.*]] = call i64 @AccessPaddingOfStruct(%struct.Foo* @a) -; CHECK-NEXT: [[TMP3:%.*]] = call i64 @CaptureAStruct(%struct.Foo* @a) +; CHECK-NEXT: [[TMP2:%.*]] = call i64 @AccessPaddingOfStruct(%struct.Foo* byval(%struct.Foo) @a) +; CHECK-NEXT: [[TMP3:%.*]] = call i64 @CaptureAStruct(%struct.Foo* byval(%struct.Foo) @a) ; CHECK-NEXT: ret void ; entry: tail call i8 @UseLongDoubleUnsafely(%union.u* byval(%union.u) align 16 bitcast (%struct.s* @b to %union.u*)) tail call x86_fp80 @UseLongDoubleSafely(%union.u* byval(%union.u) align 16 bitcast (%struct.s* @b to %union.u*)) - call i64 @AccessPaddingOfStruct(%struct.Foo* @a) - call i64 @CaptureAStruct(%struct.Foo* @a) + call i64 @AccessPaddingOfStruct(%struct.Foo* byval(%struct.Foo) @a) + call i64 @CaptureAStruct(%struct.Foo* byval(%struct.Foo) @a) ret void } diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll @@ -46,7 +46,7 @@ ; call void @test(i32** %Y), !dbg !1 - call void @test_byval(%struct.pair* %P), !dbg !6 + call void @test_byval(%struct.pair* byval(%struct.pair) %P), !dbg !6 ret void } diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll @@ -25,7 +25,7 @@ ; IS________OPM-LABEL: define {{[^@]+}}@run ; IS________OPM-SAME: () #[[ATTR0:[0-9]+]] { ; IS________OPM-NEXT: entry: -; IS________OPM-NEXT: [[TMP0:%.*]] = call i64 @CaptureAStruct(%struct.Foo* nocapture nofree noundef nonnull readonly align 8 dereferenceable(16) @a) #[[ATTR0]] +; IS________OPM-NEXT: [[TMP0:%.*]] = call i64 @CaptureAStruct(%struct.Foo* nocapture nofree noundef nonnull readonly byval([[STRUCT_FOO:%.*]]) align 8 dereferenceable(16) @a) #[[ATTR0]] ; IS________OPM-NEXT: unreachable ; ; IS__TUNIT_NPM: Function Attrs: nofree noreturn nosync nounwind readnone @@ -52,8 +52,8 @@ entry: tail call i8 @UseLongDoubleUnsafely(%union.u* byval(%union.u) align 16 bitcast (%struct.s* @b to %union.u*)) tail call x86_fp80 @UseLongDoubleSafely(%union.u* byval(%union.u) align 16 bitcast (%struct.s* @b to %union.u*)) - call i64 @AccessPaddingOfStruct(%struct.Foo* @a) - call i64 @CaptureAStruct(%struct.Foo* @a) + call i64 @AccessPaddingOfStruct(%struct.Foo* byval(%struct.Foo) @a) + call i64 @CaptureAStruct(%struct.Foo* byval(%struct.Foo) @a) ret void } diff --git a/llvm/test/Transforms/Attributor/readattrs.ll b/llvm/test/Transforms/Attributor/readattrs.ll --- a/llvm/test/Transforms/Attributor/readattrs.ll +++ b/llvm/test/Transforms/Attributor/readattrs.ll @@ -384,22 +384,22 @@ define void @testbyval(i8* %read_only) { ; IS__TUNIT____-LABEL: define {{[^@]+}}@testbyval ; IS__TUNIT____-SAME: (i8* nocapture readonly [[READ_ONLY:%.*]]) { -; IS__TUNIT____-NEXT: call void @byval_not_readonly_1(i8* nocapture readonly [[READ_ONLY]]) #[[ATTR2]] -; IS__TUNIT____-NEXT: call void @byval_not_readnone_1(i8* noalias nocapture readnone [[READ_ONLY]]) +; IS__TUNIT____-NEXT: call void @byval_not_readonly_1(i8* nocapture readonly byval(i8) [[READ_ONLY]]) #[[ATTR2]] +; IS__TUNIT____-NEXT: call void @byval_not_readnone_1(i8* noalias nocapture readnone byval(i8) [[READ_ONLY]]) ; IS__TUNIT____-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: readonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@testbyval ; IS__CGSCC____-SAME: (i8* nocapture noundef nonnull readonly dereferenceable(1) [[READ_ONLY:%.*]]) #[[ATTR2]] { -; IS__CGSCC____-NEXT: call void @byval_not_readonly_1(i8* noalias nocapture noundef nonnull readonly dereferenceable(1) [[READ_ONLY]]) #[[ATTR2]] -; IS__CGSCC____-NEXT: call void @byval_not_readnone_1(i8* noalias nocapture noundef nonnull readnone dereferenceable(1) [[READ_ONLY]]) +; IS__CGSCC____-NEXT: call void @byval_not_readonly_1(i8* noalias nocapture noundef nonnull readonly byval(i8) dereferenceable(1) [[READ_ONLY]]) #[[ATTR2]] +; IS__CGSCC____-NEXT: call void @byval_not_readnone_1(i8* noalias nocapture noundef nonnull readnone byval(i8) dereferenceable(1) [[READ_ONLY]]) ; IS__CGSCC____-NEXT: ret void ; - call void @byval_not_readonly_1(i8* %read_only) - call void @byval_not_readonly_2(i8* %read_only) - call void @byval_not_readnone_1(i8* %read_only) - call void @byval_not_readnone_2(i8* %read_only) - call void @byval_no_fnarg(i8* %read_only) + call void @byval_not_readonly_1(i8* byval(i8) %read_only) + call void @byval_not_readonly_2(i8* byval(i8) %read_only) + call void @byval_not_readnone_1(i8* byval(i8) %read_only) + call void @byval_not_readnone_2(i8* byval(i8) %read_only) + call void @byval_no_fnarg(i8* byval(i8) %read_only) ret void } ;} diff --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll --- a/llvm/test/Transforms/Attributor/value-simplify.ll +++ b/llvm/test/Transforms/Attributor/value-simplify.ll @@ -349,22 +349,22 @@ ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@complicated_args_inalloca ; IS__TUNIT____-SAME: (i32* nofree readnone returned "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR1]] { -; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree writeonly "no-capture-maybe-returned" [[ARG]]) #[[ATTR1]] +; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree writeonly inalloca(i32) "no-capture-maybe-returned" [[ARG]]) #[[ATTR1]] ; IS__TUNIT____-NEXT: ret i32* [[CALL]] ; ; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@complicated_args_inalloca ; IS__CGSCC_OPM-SAME: (i32* nofree noundef nonnull readnone returned dereferenceable(4) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR1]] { -; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree noundef nonnull writeonly dereferenceable(4) "no-capture-maybe-returned" [[ARG]]) #[[ATTR5:[0-9]+]] +; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree noundef nonnull writeonly inalloca(i32) dereferenceable(4) "no-capture-maybe-returned" [[ARG]]) #[[ATTR5:[0-9]+]] ; IS__CGSCC_OPM-NEXT: ret i32* [[CALL]] ; ; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@complicated_args_inalloca ; IS__CGSCC_NPM-SAME: (i32* nofree noundef nonnull readnone returned dereferenceable(4) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR1]] { -; IS__CGSCC_NPM-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree noundef nonnull writeonly dereferenceable(4) "no-capture-maybe-returned" [[ARG]]) #[[ATTR4:[0-9]+]] +; IS__CGSCC_NPM-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree noundef nonnull writeonly inalloca(i32) dereferenceable(4) "no-capture-maybe-returned" [[ARG]]) #[[ATTR4:[0-9]+]] ; IS__CGSCC_NPM-NEXT: ret i32* [[CALL]] ; - %call = call i32* @test_inalloca(i32* %arg) + %call = call i32* @test_inalloca(i32* inalloca(i32) %arg) ret i32* %call } @@ -531,7 +531,7 @@ ; IS__CGSCC_NPM-SAME: () #[[ATTR3:[0-9]+]] { ; IS__CGSCC_NPM-NEXT: ret void ; - call void @test_byval(%struct.X* @S) + call void @test_byval(%struct.X* byval(%struct.X) @S) ret void } @@ -573,7 +573,7 @@ ; IS__CGSCC_NPM-NEXT: [[C:%.*]] = call i8* @test_byval2() #[[ATTR7:[0-9]+]] ; IS__CGSCC_NPM-NEXT: ret i8* [[C]] ; - %c = call i8* @test_byval2(%struct.X* @S) + %c = call i8* @test_byval2(%struct.X* byval(%struct.X) @S) ret i8* %c } diff --git a/llvm/test/Transforms/TailCallElim/basic.ll b/llvm/test/Transforms/TailCallElim/basic.ll --- a/llvm/test/Transforms/TailCallElim/basic.ll +++ b/llvm/test/Transforms/TailCallElim/basic.ll @@ -214,11 +214,11 @@ define void @test13() { ; CHECK-LABEL: @test13 ; CHECK: tail call void @bar(%struct.foo* byval(%struct.foo) %f) -; CHECK: tail call void @bar(%struct.foo* null) +; CHECK: tail call void @bar(%struct.foo* byval(%struct.foo) null) entry: %f = alloca %struct.foo call void @bar(%struct.foo* byval(%struct.foo) %f) - call void @bar(%struct.foo* null) + call void @bar(%struct.foo* byval(%struct.foo) null) ret void } diff --git a/llvm/test/Verifier/indirect-attrs.ll b/llvm/test/Verifier/indirect-attrs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/indirect-attrs.ll @@ -0,0 +1,32 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +declare void @inalloca(i32* inalloca(i32) %p) + +; CHECK: argument to inalloca parameter requires inalloca attribute +define void @inalloca_not_on_parameter() { + %a = alloca inalloca i32 + call void @inalloca(i32* %a) + ret void +} + +declare void @byval(i32* byval(i32) %p) + +; CHECK: argument to byval parameter requires byval attribute +define void @byval_not_on_parameter() { + %a = alloca i32 + call void @byval(i32* %a) + ret void +} + +declare token @llvm.call.preallocated.setup(i32) +declare i8* @llvm.call.preallocated.arg(token, i32) +declare void @preallocated(i32* preallocated(i32)) + +; CHECK: argument to preallocated parameter requires preallocated attribute +define void @preallocated_not_on_parameter() { + %cs = call token @llvm.call.preallocated.setup(i32 1) + %x = call i8* @llvm.call.preallocated.arg(token %cs, i32 0) preallocated(i32) + %y = bitcast i8* %x to i32* + call void @preallocated(i32* %y) ["preallocated"(token %cs)] + ret void +}