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 @@ -3272,15 +3272,37 @@ // Verify that indirect calls don't return tokens. if (!Call.getCalledFunction()) { Assert(!FTy->getReturnType()->isTokenTy(), - "Return type cannot be token for indirect call!"); + "Return type cannot be token for indirect call!", Call); Assert(!FTy->getReturnType()->isX86_AMXTy(), - "Return type cannot be x86_amx for indirect call!"); + "Return type cannot be x86_amx for indirect call!", 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/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 +}