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 00000000000000..f6fb962d01bcc5 Binary files /dev/null and b/llvm/test/Bitcode/Inputs/x86_intrcc_upgrade.bc differ 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*)