findDeadCallerSavedReg needs to pay attention to calling convention
authorAndy Ayers <andya@microsoft.com>
Mon, 23 Nov 2015 22:17:44 +0000 (22:17 +0000)
committerAndy Ayers <andya@microsoft.com>
Mon, 23 Nov 2015 22:17:44 +0000 (22:17 +0000)
Caller saved regs differ between SysV and Win64. Use the tail call available set to scavenge from.

Refactor register info to create new helper to get at tail call GPRs. Added a new test case for windows. Fixed up a number of X64 tests since now RCX is preferred over RDX on SysV.

Differential Revision: http://reviews.llvm.org/D14878

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@253927 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
lib/Target/X86/X86FrameLowering.cpp
lib/Target/X86/X86RegisterInfo.cpp
lib/Target/X86/X86RegisterInfo.h
lib/Target/X86/X86RegisterInfo.td
test/CodeGen/X86/emutls-pie.ll
test/CodeGen/X86/emutls.ll
test/CodeGen/X86/half.ll
test/CodeGen/X86/statepoint-allocas.ll
test/CodeGen/X86/statepoint-call-lowering.ll
test/CodeGen/X86/statepoint-gctransition-call-lowering.ll
test/CodeGen/X86/vector-sext.ll
test/CodeGen/X86/win64_sibcall.ll [new file with mode: 0644]

index 4fbe3613d1e5f0599c7d7cb4909001277af0905f..c7f71478f3880fa1bcd167058e0dd1e273facc94 100644 (file)
@@ -146,21 +146,14 @@ static unsigned getLEArOpcode(unsigned IsLP64) {
 /// to this register without worry about clobbering it.
 static unsigned findDeadCallerSavedReg(MachineBasicBlock &MBB,
                                        MachineBasicBlock::iterator &MBBI,
-                                       const TargetRegisterInfo *TRI,
+                                       const X86RegisterInfo *TRI,
                                        bool Is64Bit) {
   const MachineFunction *MF = MBB.getParent();
   const Function *F = MF->getFunction();
   if (!F || MF->getMMI().callsEHReturn())
     return 0;
 
-  static const uint16_t CallerSavedRegs32Bit[] = {
-    X86::EAX, X86::EDX, X86::ECX, 0
-  };
-
-  static const uint16_t CallerSavedRegs64Bit[] = {
-    X86::RAX, X86::RDX, X86::RCX, X86::RSI, X86::RDI,
-    X86::R8,  X86::R9,  X86::R10, X86::R11, 0
-  };
+  const TargetRegisterClass &AvailableRegs = *TRI->getGPRsForTailCall(*MF);
 
   unsigned Opc = MBBI->getOpcode();
   switch (Opc) {
@@ -189,10 +182,9 @@ static unsigned findDeadCallerSavedReg(MachineBasicBlock &MBB,
         Uses.insert(*AI);
     }
 
-    const uint16_t *CS = Is64Bit ? CallerSavedRegs64Bit : CallerSavedRegs32Bit;
-    for (; *CS; ++CS)
-      if (!Uses.count(*CS))
-        return *CS;
+    for (auto CS : AvailableRegs)
+      if (!Uses.count(CS) && CS != X86::RIP)
+        return CS;
   }
   }
 
index 8b4bbac70076c5af0fffd1c09c031889b489a7ae..39de5004143e934142f44367b6ed34e2956f9449 100644 (file)
@@ -177,19 +177,24 @@ X86RegisterInfo::getPointerRegClass(const MachineFunction &MF,
       return &X86::GR64_NOREX_NOSPRegClass;
     return &X86::GR32_NOREX_NOSPRegClass;
   case 4: // Available for tailcall (not callee-saved GPRs).
-    const Function *F = MF.getFunction();
-    if (IsWin64 || (F && F->getCallingConv() == CallingConv::X86_64_Win64))
-      return &X86::GR64_TCW64RegClass;
-    else if (Is64Bit)
-      return &X86::GR64_TCRegClass;
-
-    bool hasHipeCC = (F ? F->getCallingConv() == CallingConv::HiPE : false);
-    if (hasHipeCC)
-      return &X86::GR32RegClass;
-    return &X86::GR32_TCRegClass;
+    return getGPRsForTailCall(MF);
   }
 }
 
+const TargetRegisterClass *
+X86RegisterInfo::getGPRsForTailCall(const MachineFunction &MF) const {
+  const Function *F = MF.getFunction();
+  if (IsWin64 || (F && F->getCallingConv() == CallingConv::X86_64_Win64))
+    return &X86::GR64_TCW64RegClass;
+  else if (Is64Bit)
+    return &X86::GR64_TCRegClass;
+
+  bool hasHipeCC = (F ? F->getCallingConv() == CallingConv::HiPE : false);
+  if (hasHipeCC)
+    return &X86::GR32RegClass;
+  return &X86::GR32_TCRegClass;
+}
+
 const TargetRegisterClass *
 X86RegisterInfo::getCrossCopyRegClass(const TargetRegisterClass *RC) const {
   if (RC == &X86::CCRRegClass) {
index 1b1a1ccfc1a37a6abc0037d03a91b86732eb0d25..c3a2845c36227420292589e4159e9f1e56add253 100644 (file)
@@ -87,6 +87,11 @@ public:
   const TargetRegisterClass *
   getCrossCopyRegClass(const TargetRegisterClass *RC) const override;
 
+  /// getGPRsForTailCall - Returns a register class with registers that can be
+  /// used in forming tail calls.
+  const TargetRegisterClass *
+  getGPRsForTailCall(const MachineFunction &MF) const;
+
   unsigned getRegPressureLimit(const TargetRegisterClass *RC,
                                MachineFunction &MF) const override;
 
index 6c74dcbff5b28422057e5097eefdf630c5406d2e..12f38c7946a85c5d7b3aa9c3a1828a04a032c35b 100644 (file)
@@ -375,7 +375,7 @@ def GR32_TC   : RegisterClass<"X86", [i32], 32, (add EAX, ECX, EDX)>;
 def GR64_TC   : RegisterClass<"X86", [i64], 64, (add RAX, RCX, RDX, RSI, RDI,
                                                      R8, R9, R11, RIP)>;
 def GR64_TCW64 : RegisterClass<"X86", [i64], 64, (add RAX, RCX, RDX,
-                                                      R8, R9, R11)>;
+                                                      R8, R9, R10, R11)>;
 
 // GR8_NOREX - GR8 registers which do not require a REX prefix.
 def GR8_NOREX : RegisterClass<"X86", [i8], 8,
index 4970b14838c86038df493d3475b0485afc492863..45e5c38c0d8a17737347fe6fbda6aaef9ad6f9ac 100644 (file)
@@ -24,7 +24,7 @@ define i32 @my_get_xyz() {
 ; X64:      movq my_emutls_v_xyz@GOTPCREL(%rip), %rdi
 ; X64-NEXT: callq my_emutls_get_address@PLT
 ; X64-NEXT: movl (%rax), %eax
-; X64-NEXT: popq %rdx
+; X64-NEXT: popq %rcx
 ; X64-NEXT: retq
 
 entry:
@@ -50,7 +50,7 @@ define i32 @f1() {
 ; X64:      movq __emutls_v.i@GOTPCREL(%rip), %rdi
 ; X64-NEXT: callq __emutls_get_address@PLT
 ; X64-NEXT: movl (%rax), %eax
-; X64-NEXT: popq %rdx
+; X64-NEXT: popq %rcx
 ; X64-NEXT: retq
 
 entry:
index bb2f1e2aa82fb1a9fd519817a78be05486d7ffa6..9266fe962df27e8b92c37f1aebd26526d3ad46c8 100644 (file)
@@ -21,7 +21,7 @@ define i32 @my_get_xyz() {
 ; X64:         movl $my_emutls_v_xyz, %edi
 ; X64-NEXT:    callq my_emutls_get_address
 ; X64-NEXT:    movl (%rax), %eax
-; X64-NEXT:    popq %rdx
+; X64-NEXT:    popq %rcx
 ; X64-NEXT:    retq
 
 entry:
@@ -50,7 +50,7 @@ define i32 @f1() {
 ; X64:         movl $__emutls_v.i1, %edi
 ; X64-NEXT:    callq __emutls_get_address
 ; X64-NEXT:    movl (%rax), %eax
-; X64-NEXT:    popq %rdx
+; X64-NEXT:    popq %rcx
 ; X64-NEXT:    retq
 
 entry:
@@ -67,7 +67,7 @@ define i32* @f2() {
 ; X64-LABEL: f2:
 ; X64:         movl $__emutls_v.i1, %edi
 ; X64-NEXT:    callq __emutls_get_address
-; X64-NEXT:    popq %rdx
+; X64-NEXT:    popq %rcx
 ; X64-NEXT:    retq
 
 entry:
index 8a726370f19abc1e55b62a0244a0e4bd030993a7..3b2518e28f587fe916325cac75cebf4c8eeb5f38 100644 (file)
@@ -77,7 +77,7 @@ define i64 @test_fptosi_i64(half* %p) #0 {
 ; CHECK-LIBCALL-NEXT: movzwl (%rdi), %edi
 ; CHECK-LIBCALL-NEXT: callq __gnu_h2f_ieee
 ; CHECK-LIBCALL-NEXT: cvttss2si %xmm0, %rax
-; CHECK-LIBCALL-NEXT: popq %rdx
+; CHECK-LIBCALL-NEXT: popq %rcx
 ; CHECK-LIBCALL-NEXT: retq
 
 ; CHECK-F16C-NEXT: movswl (%rdi), [[REG0:%[a-z0-9]+]]
@@ -127,7 +127,7 @@ define i64 @test_fptoui_i64(half* %p) #0 {
 ; CHECK-LIBCALL-NEXT: cvttss2si %xmm0, [[REG5:%[a-z0-9]+]]
 ; CHECK-LIBCALL-NEXT: ucomiss [[REG1]], %xmm0
 ; CHECK-LIBCALL-NEXT: cmovaeq [[REG4]], [[REG5]]
-; CHECK-LIBCALL-NEXT: popq %rdx
+; CHECK-LIBCALL-NEXT: popq %rcx
 ; CHECK-LIBCALL-NEXT: retq
 
 ; CHECK-F16C-NEXT: movswl (%rdi), [[REG0:%[a-z0-9]+]]
index 4af33e1f54782dc3e0ca142838c99a0aa4337d02..61c972f1743b0d739755bf4ed5ab392767dad248 100644 (file)
@@ -16,7 +16,7 @@ define i32 addrspace(1)* @test(i32 addrspace(1)* %ptr) gc "statepoint-example" {
 ; CHECK: movq   %rdi, (%rsp)
 ; CHECK: callq return_i1
 ; CHECK: movq   (%rsp), %rax
-; CHECK: popq   %rdx
+; CHECK: popq   %rcx
 ; CHECK: retq
 entry:
   %alloca = alloca i32 addrspace(1)*, align 8
@@ -33,7 +33,7 @@ define i32 addrspace(1)* @test2(i32 addrspace(1)* %ptr) gc "statepoint-example"
 ; CHECK: movq   %rdi, (%rsp)
 ; CHECK: callq return_i1
 ; CHECK: xorl   %eax, %eax
-; CHECK: popq   %rdx
+; CHECK: popq   %rcx
 ; CHECK: retq
 entry:
   %alloca = alloca i32 addrspace(1)*, align 8
index 14e7da721ca056dc5a1dfa2bf5a1a95b73923a10..df386b551d820721af37c6328cb4192ee55e3d99 100644 (file)
@@ -20,7 +20,7 @@ define i1 @test_i1_return() gc "statepoint-example" {
 ; state arguments to the statepoint
 ; CHECK: pushq %rax
 ; CHECK: callq return_i1
-; CHECK: popq %rdx
+; CHECK: popq %rcx
 ; CHECK: retq
 entry:
   %safepoint_token = tail call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0)
@@ -32,7 +32,7 @@ define i32 @test_i32_return() gc "statepoint-example" {
 ; CHECK-LABEL: test_i32_return
 ; CHECK: pushq %rax
 ; CHECK: callq return_i32
-; CHECK: popq %rdx
+; CHECK: popq %rcx
 ; CHECK: retq
 entry:
   %safepoint_token = tail call i32 (i64, i32, i32 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i32f(i64 0, i32 0, i32 ()* @return_i32, i32 0, i32 0, i32 0, i32 0)
@@ -44,7 +44,7 @@ define i32* @test_i32ptr_return() gc "statepoint-example" {
 ; CHECK-LABEL: test_i32ptr_return
 ; CHECK: pushq %rax
 ; CHECK: callq return_i32ptr
-; CHECK: popq %rdx
+; CHECK: popq %rcx
 ; CHECK: retq
 entry:
   %safepoint_token = tail call i32 (i64, i32, i32* ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_p0i32f(i64 0, i32 0, i32* ()* @return_i32ptr, i32 0, i32 0, i32 0, i32 0)
@@ -82,7 +82,7 @@ define i1 @test_relocate(i32 addrspace(1)* %a) gc "statepoint-example" {
 ; CHECK: pushq %rax
 ; CHECK: callq return_i1
 ; CHECK-NEXT: .Ltmp11:
-; CHECK-NEXT: popq %rdx
+; CHECK-NEXT: popq %rcx
 ; CHECK-NEXT: retq
 entry:
   %safepoint_token = tail call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %a)
@@ -107,7 +107,7 @@ define i1 @test_i1_return_patchable() gc "statepoint-example" {
 ; A patchable variant of test_i1_return
 ; CHECK: pushq %rax
 ; CHECK: nopl
-; CHECK: popq %rdx
+; CHECK: popq %rcx
 ; CHECK: retq
 entry:
   %safepoint_token = tail call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 3, i1 ()*null, i32 0, i32 0, i32 0, i32 0)
index 61b8ded2c4720212768771292f86b43950cf118b..c0bb8ce40c2e4a3e1187c8dc59ce26f061184ecd 100644 (file)
@@ -18,7 +18,7 @@ define i1 @test_i1_return() gc "statepoint-example" {
 ; state arguments to the statepoint
 ; CHECK: pushq %rax
 ; CHECK: callq return_i1
-; CHECK: popq %rdx
+; CHECK: popq %rcx
 ; CHECK: retq
 entry:
   %safepoint_token = tail call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 1, i32 0, i32 0)
@@ -30,7 +30,7 @@ define i32 @test_i32_return() gc "statepoint-example" {
 ; CHECK-LABEL: test_i32_return
 ; CHECK: pushq %rax
 ; CHECK: callq return_i32
-; CHECK: popq %rdx
+; CHECK: popq %rcx
 ; CHECK: retq
 entry:
   %safepoint_token = tail call i32 (i64, i32, i32 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i32f(i64 0, i32 0, i32 ()* @return_i32, i32 0, i32 1, i32 0, i32 0)
@@ -42,7 +42,7 @@ define i32* @test_i32ptr_return() gc "statepoint-example" {
 ; CHECK-LABEL: test_i32ptr_return
 ; CHECK: pushq %rax
 ; CHECK: callq return_i32ptr
-; CHECK: popq %rdx
+; CHECK: popq %rcx
 ; CHECK: retq
 entry:
   %safepoint_token = tail call i32 (i64, i32, i32* ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_p0i32f(i64 0, i32 0, i32* ()* @return_i32ptr, i32 0, i32 1, i32 0, i32 0)
@@ -68,7 +68,7 @@ define i1 @test_relocate(i32 addrspace(1)* %a) gc "statepoint-example" {
 ; CHECK: pushq %rax
 ; CHECK: callq return_i1
 ; CHECK-NEXT: .Ltmp9:
-; CHECK-NEXT: popq %rdx
+; CHECK-NEXT: popq %rcx
 ; CHECK-NEXT: retq
 entry:
   %safepoint_token = tail call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 1, i32 0, i32 0, i32 addrspace(1)* %a)
@@ -92,7 +92,7 @@ define i32 @test_transition_args() gc "statepoint-example" {
 ; CHECK-LABEL: test_transition_args
 ; CHECK: pushq %rax
 ; CHECK: callq return_i32
-; CHECK: popq %rdx
+; CHECK: popq %rcx
 ; CHECK: retq
 entry:
   %val = alloca i32
@@ -105,7 +105,7 @@ define i32 @test_transition_args_2() gc "statepoint-example" {
 ; CHECK-LABEL: test_transition_args_2
 ; CHECK: pushq %rax
 ; CHECK: callq return_i32
-; CHECK: popq %rdx
+; CHECK: popq %rcx
 ; CHECK: retq
 entry:
   %val = alloca i32
index 4f1cfdfd4b0425efdbd6705af96623daefa747f0..bcf8a2ab164225ccb1b7478da8ff9810ead7d60d 100644 (file)
@@ -3696,7 +3696,7 @@ define i32 @sext_2i8_to_i32(<16 x i8> %A) nounwind uwtable readnone ssp {
 ; X32-SSE41-NEXT:    .cfi_def_cfa_offset 8
 ; X32-SSE41-NEXT:    pmovsxbw %xmm0, %xmm0
 ; X32-SSE41-NEXT:    movd %xmm0, %eax
-; X32-SSE41-NEXT:    popl %edx
+; X32-SSE41-NEXT:    popl %ecx
 ; X32-SSE41-NEXT:    retl
 entry:
   %Shuf = shufflevector <16 x i8> %A, <16 x i8> undef, <2 x i32> <i32 0, i32 1>
diff --git a/test/CodeGen/X86/win64_sibcall.ll b/test/CodeGen/X86/win64_sibcall.ll
new file mode 100644 (file)
index 0000000..4001f63
--- /dev/null
@@ -0,0 +1,38 @@
+; RUN: llc < %s -mtriple=x86_64-pc-win32-coreclr | FileCheck %s -check-prefix=WIN_X64
+; RUN: llc < %s -mtriple=x86_64-pc-linux         | FileCheck %s -check-prefix=LINUX
+
+%Object = type <{ [0 x i64*]* }>
+
+define void @C1(%Object addrspace(1)* %param0) gc "coreclr" {
+entry:
+
+; WIN_X64: # BB#0:
+; WIN_X64:     pushq   %rax
+; LINUX:   # BB#0:                                 # %entry
+; LINUX:       movq    $0, -8(%rsp)
+
+  %this = alloca %Object addrspace(1)*
+  store %Object addrspace(1)* null, %Object addrspace(1)** %this
+  store %Object addrspace(1)* %param0, %Object addrspace(1)** %this
+  br label %0
+
+; <label>:0                                       ; preds = %entry
+  %1 = load %Object addrspace(1)*, %Object addrspace(1)** %this, align 8
+
+; WIN_X64:     xorl    %r8d, %r8d
+; WIN_X64:     popq    %rax
+; WIN_X64:     rex64 jmp       C2              # TAILCALL
+; LINUX:       xorl    %edx, %edx
+; LINUX:       jmp     C2                      # TAILCALL
+
+  tail call void @C2(%Object addrspace(1)* %1, i32 0, %Object addrspace(1)* null)
+  ret void
+}
+
+declare void @C2(%Object addrspace(1)*, i32, %Object addrspace(1)*)
+
+; Function Attrs: nounwind
+declare void @llvm.localescape(...) #0
+
+attributes #0 = { nounwind }
+