[llvm-branch-commits] [llvm] f2e2924 - [X86] Unbind the ebx with GOT address in regcall calling convention

Xiang1 Zhang via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Dec 3 18:06:22 PST 2020


Author: Xiang1 Zhang
Date: 2020-12-04T10:00:13+08:00
New Revision: f2e292446334de01403cddb9132ae06cc4475175

URL: https://github.com/llvm/llvm-project/commit/f2e292446334de01403cddb9132ae06cc4475175
DIFF: https://github.com/llvm/llvm-project/commit/f2e292446334de01403cddb9132ae06cc4475175.diff

LOG: [X86] Unbind the ebx with GOT address in regcall calling convention

No register can be allocated for indirect call when it use regcall calling
convention and passed 5/5+ args.
For example:
call vreg (ag1, ag2, ag3, ag4, ag5, ...) --> 5 regs (EAX, ECX, EDX, ESI, EDI)
used for pass args, 1 reg (EBX )used for hold GOT point, so no regs can be
allocated to vreg.

The Intel386 architecture provides 8 general purpose 32-bit registers. RA
mostly use 6 of them (EAX, EBX, ECX, EDX, ESI, EDI). 5 of this regs can be
used to pass function arguments (EAX, ECX, EDX, ESI, EDI).
EBX used to hold the GOT pointer when making function calls via the PLT.
ESP and EBP usually be "reserved" in register allocation.

Reviewed By: LuoYuanke

Differential Revision: https://reviews.llvm.org/D91020

Added: 
    llvm/test/CodeGen/X86/tailregccpic.ll
    llvm/test/CodeGen/X86/x86-regcall-got.ll

Modified: 
    llvm/lib/Target/X86/X86ISelLowering.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index caf9e690f5b8..0b6b5614db6f 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -4127,9 +4127,13 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
 
   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
index 000000000000..5f960c17da15
--- /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
+
+ at 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 at 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
index 000000000000..320b21d6359b
--- /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);
+;}
+
+ at 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 at 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
+}


        


More information about the llvm-branch-commits mailing list