From 2e0e03c6a089da39039ec3f464f7cee5df86646b Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Thu, 19 Nov 2020 18:53:28 -0500 Subject: [PATCH] OpaquePtr: Require byval on x86_intrcc parameter 0 Currently the backend special cases x86_intrcc and treats the first parameter as byval. Make the IR require byval for this parameter to remove this special case, and avoid the dependence on the pointee element type. Fixes bug 46672. I'm not sure the IR is enforcing all the calling convention constraints. clang seems to ignore the attribute for empty parameter lists, but the IR tolerates it. --- .../SelectionDAG/SelectionDAGBuilder.cpp | 8 ------- llvm/lib/IR/AutoUpgrade.cpp | 7 ++++++ llvm/lib/IR/Verifier.cpp | 5 +++++ llvm/test/Assembler/x86_intrcc.ll | 13 +++++++++++ .../test/Bitcode/Inputs/x86_intrcc_upgrade.bc | Bin 0 -> 1364 bytes llvm/test/Bitcode/compatibility-6.0.ll | 2 +- llvm/test/Bitcode/compatibility.ll | 8 +++---- llvm/test/Bitcode/x86_intr-upgrade.test | 11 +++++++++ llvm/test/CodeGen/X86/x86-32-intrcc.ll | 14 ++++++------ llvm/test/CodeGen/X86/x86-64-intrcc-nosse.ll | 2 +- llvm/test/CodeGen/X86/x86-64-intrcc.ll | 14 ++++++------ llvm/test/CodeGen/X86/x86-interrupt_cc.ll | 2 +- llvm/test/CodeGen/X86/x86-interrupt_cld.ll | 2 +- .../CodeGen/X86/x86-interrupt_vzeroupper.ll | 2 +- .../X86/x86-no_caller_saved_registers.ll | 4 ++-- llvm/test/Verifier/x86_intr.ll | 21 ++++++++++++++++++ 16 files changed, 82 insertions(+), 33 deletions(-) create mode 100644 llvm/test/Assembler/x86_intrcc.ll create mode 100644 llvm/test/Bitcode/Inputs/x86_intrcc_upgrade.bc create mode 100644 llvm/test/Bitcode/x86_intr-upgrade.test create mode 100644 llvm/test/Verifier/x86_intr.ll diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 170f3f2c4e1395..b9a53f34eb883d 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -9846,14 +9846,6 @@ void SelectionDAGISel::LowerArguments(const Function &F) { } Type *ArgMemTy = nullptr; - if (F.getCallingConv() == CallingConv::X86_INTR) { - // IA Interrupt passes frame (1st parameter) by value in the stack. - if (ArgNo == 0) { - Flags.setByVal(); - // FIXME: Dependence on pointee element type. See bug 46672. - ArgMemTy = Arg.getType()->getPointerElementType(); - } - } if (Flags.isByVal() || Flags.isInAlloca() || Flags.isPreallocated() || Flags.isByRef()) { if (!ArgMemTy) diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp index 6d92f8cffee581..fe7b7eb8966ae2 100644 --- a/llvm/lib/IR/AutoUpgrade.cpp +++ b/llvm/lib/IR/AutoUpgrade.cpp @@ -4315,6 +4315,13 @@ void llvm::UpgradeFunctionAttributes(Function &F) { StrictFPUpgradeVisitor SFPV; SFPV.visit(F); } + + if (F.getCallingConv() == CallingConv::X86_INTR && + !F.arg_empty() && !F.hasParamAttribute(0, Attribute::ByVal)) { + Type *ByValTy = cast(F.getArg(0)->getType())->getElementType(); + Attribute NewAttr = Attribute::getWithByValType(F.getContext(), ByValTy); + F.addParamAttr(0, NewAttr); + } } static bool isOldLoopArgument(Metadata *MD) { diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index e3a2828be41aa8..ac44a95d7da538 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -2327,6 +2327,11 @@ void Verifier::visitFunction(const Function &F) { default: case CallingConv::C: break; + case CallingConv::X86_INTR: { + Assert(F.arg_empty() || Attrs.hasParamAttribute(0, Attribute::ByVal), + "Calling convention parameter requires byval", &F); + break; + } case CallingConv::AMDGPU_KERNEL: case CallingConv::SPIR_KERNEL: Assert(F.getReturnType()->isVoidTy(), diff --git a/llvm/test/Assembler/x86_intrcc.ll b/llvm/test/Assembler/x86_intrcc.ll new file mode 100644 index 00000000000000..b75fbb52b09056 --- /dev/null +++ b/llvm/test/Assembler/x86_intrcc.ll @@ -0,0 +1,13 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s +; RUN: verify-uselistorder %s + +; Make sure no arguments is accepted +; CHECK: define x86_intrcc void @no_args() { +define x86_intrcc void @no_args() { + ret void +} + +; CHECK: define x86_intrcc void @byval_arg(i32* byval(i32) %0) { +define x86_intrcc void @byval_arg(i32* byval(i32)) { + ret void +} diff --git a/llvm/test/Bitcode/Inputs/x86_intrcc_upgrade.bc b/llvm/test/Bitcode/Inputs/x86_intrcc_upgrade.bc new file mode 100644 index 0000000000000000000000000000000000000000..f6fb962d01bcc580aefdd65bb1fb3222a3ed6cfc GIT binary patch literal 1364 zcmZ`(Z)g)|7=M#XbFt0tZW>%N@4{WH5R0_ewAG|ZhRtc$u@0m2LkmipKTX?F<28+K zTE|FC^x~Eeu>=-|A6ixhev7Oh{2*J>>s(fD;=~QNm6Fg{-KY}O4Pi3&Uh3F{?ckp0 zeV^xfpZE9tp7(v7Tz;)n2S6PFz^i30HX!qbp-$oN(Lxl z%ue{Dv8GGiMb%qs!fc&YB(!_#GzO#UBX5*AtaQ#cI1_|fXVK{2t~WcAz5FuMbZEPf zBD!al{-Wlpj^=uj^fwB#Gof!bHK*I&&z-nLFBf6ni!=ZP)aFLbHrjt)wWDz%0mXV^ zKCRo{mrOMz5`9ER6W9Yjv?|%Ty-MPHQW3h)aX7;=rsL47eahI zJc33Bg|J=-&k2T`@8XXD{@8_8(%AYzyi8-8unO8ltrm<+-NxGtxf(OBmdHw(`c+{J z=#N@*T-W8eO>*siQOKY$6+t7}qkT`)xXgg@J>!ape85m^1?mHZQ3lLVRge1k`M5X33S3kA6vU%JXG~})8#}R1V4HdDo(p@zHWhAn8!P44?v|-F z2%y(s%f%gw@m&eglH#nAXunpl7DZU2UFuyN*Psy9I3%!NF#LQ2+Z@Cnmef@mzsKVD zX#95<79_BB7K76#CG{^Qtm49+v0V8lhT51XtBM+OPtTnnMGI_JPHer)bxB-TlIwz1 z-{Rho4%(+8!VHgwOz4Ds=C0@gFhJct_mUF-sB%g>513$RKc!@8Dff zLyb!Ig}Ci9Y%t=Oi`!wd)1rL6JTw5Z-l2*q|8G1FV^lE4j1i3qkWuRSy;0>S^6LV? zN%-EhLcJZy@N%BuX}2ddJP|w{bbF^KJ!5V@9Fi^U%a)07=!`G?BG~O8@{PUhmsk9U zd23nC(PnO8TiD^zFzvJY_Xmdd2M+ix9f3}7n}_xKy+fU>dC2Q)_gUEX&I4w1!0(M% Z_Pa-e;gHYgKEn@(JpQ4Uu`#)ZzW~EY#LoZ# literal 0 HcmV?d00001 diff --git a/llvm/test/Bitcode/compatibility-6.0.ll b/llvm/test/Bitcode/compatibility-6.0.ll index 6018e9b2a8ca94..980dd92563c7ed 100644 --- a/llvm/test/Bitcode/compatibility-6.0.ll +++ b/llvm/test/Bitcode/compatibility-6.0.ll @@ -436,7 +436,7 @@ declare cc82 void @f.cc82() ; CHECK: declare hhvm_ccc void @f.cc82() declare hhvm_ccc void @f.hhvm_ccc() ; CHECK: declare hhvm_ccc void @f.hhvm_ccc() -declare cc83 void @f.cc83() +declare cc83 void @f.cc83(i8* byval(i8)) ; CHECK: declare x86_intrcc void @f.cc83() declare x86_intrcc void @f.x86_intrcc() ; CHECK: declare x86_intrcc void @f.x86_intrcc() diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll index 993d5715721e92..c5bc2608a9f532 100644 --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -450,10 +450,10 @@ declare cc82 void @f.cc82() ; CHECK: declare hhvm_ccc void @f.cc82() declare hhvm_ccc void @f.hhvm_ccc() ; CHECK: declare hhvm_ccc void @f.hhvm_ccc() -declare cc83 void @f.cc83() -; CHECK: declare x86_intrcc void @f.cc83() -declare x86_intrcc void @f.x86_intrcc() -; CHECK: declare x86_intrcc void @f.x86_intrcc() +declare cc83 void @f.cc83(i8* byval(i8)) +; CHECK: declare x86_intrcc void @f.cc83(i8* byval(i8)) +declare x86_intrcc void @f.x86_intrcc(i8* byval(i8)) +; CHECK: declare x86_intrcc void @f.x86_intrcc(i8* byval(i8)) declare cc84 void @f.cc84() ; CHECK: declare avr_intrcc void @f.cc84() declare avr_intrcc void @f.avr_intrcc() diff --git a/llvm/test/Bitcode/x86_intr-upgrade.test b/llvm/test/Bitcode/x86_intr-upgrade.test new file mode 100644 index 00000000000000..30940be7d4396c --- /dev/null +++ b/llvm/test/Bitcode/x86_intr-upgrade.test @@ -0,0 +1,11 @@ +RUN: llvm-dis %p/Inputs/x86_intrcc_upgrade.bc -o - | FileCheck %s + +Make sure we upgrade x86_intrcc to a byval with explicit type + +CHECK: define x86_intrcc void @no_args() { +CHECK: define x86_intrcc void @non_byval_ptr_arg0(i32* byval(i32) %0) +CHECK: define x86_intrcc void @non_byval_ptr_struct(%struct* byval(%struct) %0) + +CHECK: declare x86_intrcc void @no_args_decl() +CHECK: declare x86_intrcc void @non_byval_ptr_arg0_decl(i32* byval(i32)) +CHECK: declare x86_intrcc void @non_byval_ptr_struct_decl(%struct* byval(%struct)) diff --git a/llvm/test/CodeGen/X86/x86-32-intrcc.ll b/llvm/test/CodeGen/X86/x86-32-intrcc.ll index be325e2f0edcfa..2a574216e64ffd 100644 --- a/llvm/test/CodeGen/X86/x86-32-intrcc.ll +++ b/llvm/test/CodeGen/X86/x86-32-intrcc.ll @@ -9,7 +9,7 @@ ; Spills eax, putting original esp at +4. ; No stack adjustment if declared with no error code -define x86_intrcc void @test_isr_no_ecode(%struct.interrupt_frame* %frame) { +define x86_intrcc void @test_isr_no_ecode(%struct.interrupt_frame* byval(%struct.interrupt_frame) %frame) { ; CHECK-LABEL: test_isr_no_ecode: ; CHECK: pushl %eax ; CHECK: movl 12(%esp), %eax @@ -29,7 +29,7 @@ define x86_intrcc void @test_isr_no_ecode(%struct.interrupt_frame* %frame) { ; Spills eax and ecx, putting original esp at +8. Stack is adjusted up another 4 bytes ; before return, popping the error code. -define x86_intrcc void @test_isr_ecode(%struct.interrupt_frame* %frame, i32 %ecode) { +define x86_intrcc void @test_isr_ecode(%struct.interrupt_frame* byval(%struct.interrupt_frame) %frame, i32 %ecode) { ; CHECK-LABEL: test_isr_ecode ; CHECK: pushl %ecx ; CHECK: pushl %eax @@ -56,7 +56,7 @@ define x86_intrcc void @test_isr_ecode(%struct.interrupt_frame* %frame, i32 %eco } ; All clobbered registers must be saved -define x86_intrcc void @test_isr_clobbers(%struct.interrupt_frame* %frame, i32 %ecode) { +define x86_intrcc void @test_isr_clobbers(%struct.interrupt_frame* byval(%struct.interrupt_frame) %frame, i32 %ecode) { call void asm sideeffect "", "~{eax},~{ebx},~{ebp}"() ; CHECK-LABEL: test_isr_clobbers ; CHECK: pushl %ebp @@ -82,7 +82,7 @@ define x86_intrcc void @test_isr_clobbers(%struct.interrupt_frame* %frame, i32 % @f80 = common global x86_fp80 0xK00000000000000000000, align 4 ; Test that the presence of x87 does not crash the FP stackifier -define x86_intrcc void @test_isr_x87(%struct.interrupt_frame* %frame) { +define x86_intrcc void @test_isr_x87(%struct.interrupt_frame* byval(%struct.interrupt_frame) %frame) { ; CHECK-LABEL: test_isr_x87 ; CHECK-DAG: fldt f80 ; CHECK-DAG: fld1 @@ -98,7 +98,7 @@ entry: ; Use a frame pointer to check the offsets. No return address, arguments start ; at EBP+4. -define dso_local x86_intrcc void @test_fp_1(%struct.interrupt_frame* %p) #0 { +define dso_local x86_intrcc void @test_fp_1(%struct.interrupt_frame* byval(%struct.interrupt_frame) %p) #0 { ; CHECK-LABEL: test_fp_1: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: pushl %ebp @@ -119,7 +119,7 @@ entry: } ; The error code is between EBP and the interrupt_frame. -define dso_local x86_intrcc void @test_fp_2(%struct.interrupt_frame* %p, i32 %err) #0 { +define dso_local x86_intrcc void @test_fp_2(%struct.interrupt_frame* byval(%struct.interrupt_frame) %p, i32 %err) #0 { ; CHECK-LABEL: test_fp_2: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: pushl %ebp @@ -143,7 +143,7 @@ entry: } ; Test argument copy elision when copied to a local alloca. -define x86_intrcc void @test_copy_elide(%struct.interrupt_frame* %frame, i32 %err) #0 { +define x86_intrcc void @test_copy_elide(%struct.interrupt_frame* byval(%struct.interrupt_frame) %frame, i32 %err) #0 { ; CHECK-LABEL: test_copy_elide: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: pushl %ebp diff --git a/llvm/test/CodeGen/X86/x86-64-intrcc-nosse.ll b/llvm/test/CodeGen/X86/x86-64-intrcc-nosse.ll index 7b39ab64db8a28..187c3963f2fb12 100644 --- a/llvm/test/CodeGen/X86/x86-64-intrcc-nosse.ll +++ b/llvm/test/CodeGen/X86/x86-64-intrcc-nosse.ll @@ -6,7 +6,7 @@ @llvm.used = appending global [1 x i8*] [i8* bitcast (void (%struct.interrupt_frame*, i64)* @test_isr_sse_clobbers to i8*)], section "llvm.metadata" ; Clobbered SSE must not be saved when the target doesn't support SSE -define x86_intrcc void @test_isr_sse_clobbers(%struct.interrupt_frame* %frame, i64 %ecode) { +define x86_intrcc void @test_isr_sse_clobbers(%struct.interrupt_frame* byval(%struct.interrupt_frame) %frame, i64 %ecode) { ; CHECK-LABEL: test_isr_sse_clobbers: ; CHECK: # %bb.0: ; CHECK-NEXT: pushq %rax diff --git a/llvm/test/CodeGen/X86/x86-64-intrcc.ll b/llvm/test/CodeGen/X86/x86-64-intrcc.ll index 548f7100b028ff..c371d67588a3bb 100644 --- a/llvm/test/CodeGen/X86/x86-64-intrcc.ll +++ b/llvm/test/CodeGen/X86/x86-64-intrcc.ll @@ -8,7 +8,7 @@ ; Spills rax, putting original esp at +8. ; No stack adjustment if declared with no error code -define x86_intrcc void @test_isr_no_ecode(%struct.interrupt_frame* %frame) { +define x86_intrcc void @test_isr_no_ecode(%struct.interrupt_frame* byval(%struct.interrupt_frame) %frame) { ; CHECK-LABEL: test_isr_no_ecode: ; CHECK: pushq %rax ; CHECK: movq 24(%rsp), %rax @@ -28,7 +28,7 @@ define x86_intrcc void @test_isr_no_ecode(%struct.interrupt_frame* %frame) { ; Spills rax and rcx, putting original rsp at +16. Stack is adjusted up another 8 bytes ; before return, popping the error code. -define x86_intrcc void @test_isr_ecode(%struct.interrupt_frame* %frame, i64 %ecode) { +define x86_intrcc void @test_isr_ecode(%struct.interrupt_frame* byval(%struct.interrupt_frame) %frame, i64 %ecode) { ; CHECK-LABEL: test_isr_ecode ; CHECK: pushq %rax ; CHECK: pushq %rax @@ -57,7 +57,7 @@ define x86_intrcc void @test_isr_ecode(%struct.interrupt_frame* %frame, i64 %eco } ; All clobbered registers must be saved -define x86_intrcc void @test_isr_clobbers(%struct.interrupt_frame* %frame, i64 %ecode) { +define x86_intrcc void @test_isr_clobbers(%struct.interrupt_frame* byval(%struct.interrupt_frame) %frame, i64 %ecode) { call void asm sideeffect "", "~{rax},~{rbx},~{rbp},~{r11},~{xmm0}"() ; CHECK-LABEL: test_isr_clobbers @@ -93,7 +93,7 @@ define x86_intrcc void @test_isr_clobbers(%struct.interrupt_frame* %frame, i64 % @f80 = common global x86_fp80 0xK00000000000000000000, align 4 ; Test that the presence of x87 does not crash the FP stackifier -define x86_intrcc void @test_isr_x87(%struct.interrupt_frame* %frame) { +define x86_intrcc void @test_isr_x87(%struct.interrupt_frame* byval(%struct.interrupt_frame) %frame) { ; CHECK-LABEL: test_isr_x87 ; CHECK-DAG: fldt f80 ; CHECK-DAG: fld1 @@ -109,7 +109,7 @@ entry: ; Use a frame pointer to check the offsets. No return address, arguments start ; at RBP+4. -define dso_local x86_intrcc void @test_fp_1(%struct.interrupt_frame* %p) #0 { +define dso_local x86_intrcc void @test_fp_1(%struct.interrupt_frame* byval(%struct.interrupt_frame) %p) #0 { ; CHECK-LABEL: test_fp_1: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: pushq %rbp @@ -130,7 +130,7 @@ entry: } ; The error code is between RBP and the interrupt_frame. -define dso_local x86_intrcc void @test_fp_2(%struct.interrupt_frame* %p, i64 %err) #0 { +define dso_local x86_intrcc void @test_fp_2(%struct.interrupt_frame* byval(%struct.interrupt_frame) %p, i64 %err) #0 { ; CHECK-LABEL: test_fp_2: ; CHECK: # %bb.0: # %entry ; This RAX push is just to align the stack. @@ -159,7 +159,7 @@ entry: } ; Test argument copy elision when copied to a local alloca. -define x86_intrcc void @test_copy_elide(%struct.interrupt_frame* %frame, i64 %err) #0 { +define x86_intrcc void @test_copy_elide(%struct.interrupt_frame* byval(%struct.interrupt_frame) %frame, i64 %err) #0 { ; CHECK-LABEL: test_copy_elide: ; CHECK: # %bb.0: # %entry ; This RAX push is just to align the stack. diff --git a/llvm/test/CodeGen/X86/x86-interrupt_cc.ll b/llvm/test/CodeGen/X86/x86-interrupt_cc.ll index 6de8191ca7c755..04566956662732 100644 --- a/llvm/test/CodeGen/X86/x86-interrupt_cc.ll +++ b/llvm/test/CodeGen/X86/x86-interrupt_cc.ll @@ -6,7 +6,7 @@ ; Make sure we spill the high numbered zmm registers and K registers with the right encoding. -define x86_intrcc void @foo(i8* %frame) { +define x86_intrcc void @foo(i8* byval(i8) %frame) { ; CHECK64-KNL-LABEL: foo: ; CHECK64-KNL: ## %bb.0: ; CHECK64-KNL-NEXT: pushq %rax ## encoding: [0x50] diff --git a/llvm/test/CodeGen/X86/x86-interrupt_cld.ll b/llvm/test/CodeGen/X86/x86-interrupt_cld.ll index bbb109eb633ee6..f11d7a456fc1ab 100644 --- a/llvm/test/CodeGen/X86/x86-interrupt_cld.ll +++ b/llvm/test/CodeGen/X86/x86-interrupt_cld.ll @@ -8,7 +8,7 @@ ; CHECK: cld ; CHECK: call -define x86_intrcc void @foo(i8* %frame) { +define x86_intrcc void @foo(i8* byval(i8) %frame) { call void @bar() ret void } diff --git a/llvm/test/CodeGen/X86/x86-interrupt_vzeroupper.ll b/llvm/test/CodeGen/X86/x86-interrupt_vzeroupper.ll index b735ae82bd526d..6dce3e141b8c75 100644 --- a/llvm/test/CodeGen/X86/x86-interrupt_vzeroupper.ll +++ b/llvm/test/CodeGen/X86/x86-interrupt_vzeroupper.ll @@ -10,7 +10,7 @@ ; CHECK-NOT: vzeroupper ; CHECK: iret -define x86_intrcc void @foo(i8* %frame) { +define x86_intrcc void @foo(i8* byval(i8) %frame) { call void @bar() ret void } diff --git a/llvm/test/CodeGen/X86/x86-no_caller_saved_registers.ll b/llvm/test/CodeGen/X86/x86-no_caller_saved_registers.ll index 4e5403d1847f24..7fb82d15b85ef4 100644 --- a/llvm/test/CodeGen/X86/x86-no_caller_saved_registers.ll +++ b/llvm/test/CodeGen/X86/x86-no_caller_saved_registers.ll @@ -7,7 +7,7 @@ ;; In functions with 'no_caller_saved_registers' attribute, all registers should ;; be preserved except for registers used for passing/returning arguments. ;; The test checks that function "bar" preserves xmm0 register. -;; It also checks that caller function "foo" does not store registers for callee +;; It also checks that caller function "foo" does not store registers for callee ;; "bar". For example, there is no store/load/access to xmm registers. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -20,7 +20,7 @@ define i32 @bar(i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4, i32 %a5, i32 %a6, i ret i32 1 } -define x86_intrcc void @foo(i8* nocapture readnone %c) { +define x86_intrcc void @foo(i8* byval(i8) nocapture readnone %c) { ; CHECK-LABEL: foo ; CHECK-NOT: xmm entry: diff --git a/llvm/test/Verifier/x86_intr.ll b/llvm/test/Verifier/x86_intr.ll new file mode 100644 index 00000000000000..c992fafd1e8ed7 --- /dev/null +++ b/llvm/test/Verifier/x86_intr.ll @@ -0,0 +1,21 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +; CHECK: Calling convention parameter requires byval +; CHECK-NEXT: void (i32)* @non_ptr_arg0 +define x86_intrcc void @non_ptr_arg0(i32) { + ret void +} + +; CHECK: Calling convention parameter requires byval +; CHECK-NEXT: void (i32*)* @non_byval_ptr_arg0 +define x86_intrcc void @non_byval_ptr_arg0(i32*) { + ret void +} + +; CHECK: Calling convention parameter requires byval +; CHECK-NEXT: void (i32)* @non_ptr_arg0_decl +declare x86_intrcc void @non_ptr_arg0_decl(i32) + +; CHECK: Calling convention parameter requires byval +; CHECK-NEXT: void (i32*)* @non_byval_ptr_arg0_decl +declare x86_intrcc void @non_byval_ptr_arg0_decl(i32*)