diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -4127,9 +4127,13 @@ if (Subtarget.isPICStyleGOT()) { // ELF / PIC requires GOT in the EBX register before function calls via PLT - // GOT pointer. + // GOT pointer (except regcall). if (!isTailCall) { - RegsToPass.push_back(std::make_pair( + // Indirect call with RegCall calling convertion may use up all the + // general registers, so it is not suitable to bind EBX reister for + // GOT address, just let register allocator handle it. + if (CallConv != CallingConv::X86_RegCall) + RegsToPass.push_back(std::make_pair( Register(X86::EBX), DAG.getNode(X86ISD::GlobalBaseReg, SDLoc(), getPointerTy(DAG.getDataLayout())))); } else { diff --git a/llvm/test/CodeGen/X86/tailregccpic.ll b/llvm/test/CodeGen/X86/tailregccpic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/tailregccpic.ll @@ -0,0 +1,26 @@ +; RUN: llc < %s -mtriple=i386-pc-unknown-linux-gnu -relocation-model=pic | FileCheck %s + +@a0 = global i32 0, align 4 + +define x86_regcallcc void @tail_call_regcall(i32 %a) nounwind { + tail call x86_regcallcc void @__regcall3__func(i32 %a) nounwind + ret void +} + +define internal x86_regcallcc void @__regcall3__func(i32 %i1) { +entry: + store i32 %i1, i32* @a0, align 4 + ret void +} + +;CHECK-LABLE: tail_call_regcall: +;CHECK: # %bb.0: +;CHECK-NEXT: jmp __regcall3__func # TAILCALL +;CHECK-NEXT: .Lfunc_end0: + +;CHECK-LABLE: __regcall3__func: +;CHECK: addl $_GLOBAL_OFFSET_TABLE_+({{.*}}), %ecx +;CHECK-NEXT: movl a0@GOT(%ecx), %ecx +;CHECK-NEXT: movl %eax, (%ecx) +;CHECK-NEXT: retl +;CHECK-NEXT: .Lfunc_end1: diff --git a/llvm/test/CodeGen/X86/x86-regcall-got.ll b/llvm/test/CodeGen/X86/x86-regcall-got.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/x86-regcall-got.ll @@ -0,0 +1,37 @@ +; RUN: llc -O0 -mtriple=i386-unknown-linux-gnu -relocation-model=pic < %s | FileCheck %s + +; Unbind the ebx with GOT address in regcall calling convention, or the following +; case will failed in register allocation by no register can be used. + +;#define REGCALL __attribute__((regcall)) +;int REGCALL func (int i1, int i2, int i3, int i4, int i5); +;int (REGCALL *fptr) (int, int, int, int, int) = func; +;int test() { +; return fptr(1,2,3,4,5); +;} + +@fptr = global i32 (i32, i32, i32, i32, i32)* @__regcall3__func, align 4 + +declare x86_regcallcc i32 @__regcall3__func(i32 inreg, i32 inreg, i32 inreg, i32 inreg, i32 inreg) + +; Function Attrs: noinline nounwind optnone +define i32 @test() { +; CHECK-LABEL: test: +; CHECK: .L0$pb: +; CHECK-NEXT: popl %eax +; CHECK: .Ltmp0: +; CHECK-NEXT: addl $_GLOBAL_OFFSET_TABLE_+(.Ltmp0-.L0$pb), %eax +; CHECK-NEXT: movl fptr@GOT(%eax), %eax +; CHECK-NEXT: movl (%eax), %ebx +; CHECK-NEXT: movl $1, %eax +; CHECK-NEXT: movl $2, %ecx +; CHECK-NEXT: movl $3, %edx +; CHECK-NEXT: movl $4, %edi +; CHECK-NEXT: movl $5, %esi +; CHECK-NEXT: calll *%ebx + +entry: + %0 = load i32 (i32, i32, i32, i32, i32)*, i32 (i32, i32, i32, i32, i32)** @fptr, align 4 + %call = call x86_regcallcc i32 %0(i32 inreg 1, i32 inreg 2, i32 inreg 3, i32 inreg 4, i32 inreg 5) + ret i32 %call +}