[llvm] f6c7bae - [Win/x64] Update preserve_most to treat XMM registers like C (#73866)

via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 4 11:53:41 PST 2023


Author: Seth Brenith
Date: 2023-12-04T11:53:36-08:00
New Revision: f6c7baea098aac03687f5041fc860ca95f070e4e

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

LOG: [Win/x64] Update preserve_most to treat XMM registers like C (#73866)

As [scottmcm
described](https://discourse.llvm.org/t/conv-c-and-conv-preservemost-mix-badly-on-windows-x64/73054),
the `preserve_most` calling convention, as currently implemented, is a
bad fit for Windows on x64. The intent of `preserve_most` is "to make
the code in the caller as unintrusive as possible", but `preserve_most`
causes the caller to spill and restore ten SIMD registers. It would be
preferable to make `preserve_most` treat the XMM registers however the C
calling convention does on the target operating system.

This is a breaking change, but the documentation indicates that
`preserve_most` is still experimental, so I believe that ABI
compatibility is not yet a requirement.

Added: 
    llvm/test/CodeGen/X86/preserve_mostcc64_win.ll

Modified: 
    llvm/docs/LangRef.rst
    llvm/lib/Target/X86/X86CallingConv.td
    llvm/lib/Target/X86/X86RegisterInfo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index af064d7ac2195..4bd19a332d8d8 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -365,8 +365,9 @@ added in the future:
 
     - On X86-64 the callee preserves all general purpose registers, except for
       R11 and return registers, if any. R11 can be used as a scratch register.
-      Floating-point registers (XMMs/YMMs) are not preserved and need to be
-      saved by the caller.
+      The treatment of floating-point registers (XMMs/YMMs) matches the OS's C
+      calling convention: on most platforms, they are not preserved and need to
+      be saved by the caller, but on Windows, xmm6-xmm15 are preserved.
 
     - On AArch64 the callee preserve all general purpose registers, except X0-X8
       and X16-X18.

diff  --git a/llvm/lib/Target/X86/X86CallingConv.td b/llvm/lib/Target/X86/X86CallingConv.td
index 27e4fe0cb7a02..16014d6a2f602 100644
--- a/llvm/lib/Target/X86/X86CallingConv.td
+++ b/llvm/lib/Target/X86/X86CallingConv.td
@@ -1151,6 +1151,9 @@ def CSR_64_CXX_TLS_Darwin_ViaCopy : CalleeSavedRegs<(sub CSR_64_TLS_Darwin, RBP)
 def CSR_64_RT_MostRegs : CalleeSavedRegs<(add CSR_64, RAX, RCX, RDX, RSI, RDI,
                                               R8, R9, R10)>;
 
+def CSR_Win64_RT_MostRegs : CalleeSavedRegs<(add CSR_64_RT_MostRegs,
+                                                 (sequence "XMM%u", 6, 15))>;
+
 // All registers - except r11 and return registers.
 def CSR_64_RT_AllRegs     : CalleeSavedRegs<(add CSR_64_RT_MostRegs,
                                                  (sequence "XMM%u", 0, 15))>;

diff  --git a/llvm/lib/Target/X86/X86RegisterInfo.cpp b/llvm/lib/Target/X86/X86RegisterInfo.cpp
index 379a9d448a963..5c32519dab371 100644
--- a/llvm/lib/Target/X86/X86RegisterInfo.cpp
+++ b/llvm/lib/Target/X86/X86RegisterInfo.cpp
@@ -310,7 +310,8 @@ X86RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
       return CSR_64_AllRegs_AVX_SaveList;
     return CSR_64_AllRegs_SaveList;
   case CallingConv::PreserveMost:
-    return CSR_64_RT_MostRegs_SaveList;
+    return IsWin64 ? CSR_Win64_RT_MostRegs_SaveList
+                   : CSR_64_RT_MostRegs_SaveList;
   case CallingConv::PreserveAll:
     if (HasAVX)
       return CSR_64_RT_AllRegs_AVX_SaveList;
@@ -431,7 +432,7 @@ X86RegisterInfo::getCallPreservedMask(const MachineFunction &MF,
       return CSR_64_AllRegs_AVX_RegMask;
     return CSR_64_AllRegs_RegMask;
   case CallingConv::PreserveMost:
-    return CSR_64_RT_MostRegs_RegMask;
+    return IsWin64 ? CSR_Win64_RT_MostRegs_RegMask : CSR_64_RT_MostRegs_RegMask;
   case CallingConv::PreserveAll:
     if (HasAVX)
       return CSR_64_RT_AllRegs_AVX_RegMask;

diff  --git a/llvm/test/CodeGen/X86/preserve_mostcc64_win.ll b/llvm/test/CodeGen/X86/preserve_mostcc64_win.ll
new file mode 100644
index 0000000000000..7042a2e77da1b
--- /dev/null
+++ b/llvm/test/CodeGen/X86/preserve_mostcc64_win.ll
@@ -0,0 +1,91 @@
+; RUN: sed -e "s/RETTYPE/void/;s/RETVAL//" %s | llc -mtriple=x86_64-win32 -mcpu=corei7 | FileCheck --check-prefixes=ALL,VOID %s
+; RUN: sed -e "s/RETTYPE/i32/;s/RETVAL/undef/" %s | llc -mtriple=x86_64-win32 -mcpu=corei7 | FileCheck --check-prefixes=ALL,INT %s
+; RUN: sed -e "s/RETTYPE/\{i64\,i64\}/;s/RETVAL/undef/" %s | llc -mtriple=x86_64-win32 -mcpu=corei7 | FileCheck --check-prefixes=ALL,INT128 %s
+
+; Every GPR should be saved, except r11 and return registers.
+; XMM registers 6-15 should also be saved.
+define preserve_mostcc RETTYPE @preserve_mostcc1(i64, i64, double, double) nounwind {
+entry:
+;ALL-LABEL:   preserve_mostcc1
+;ALL:         pushq %r10
+;ALL-NEXT:    pushq %r9
+;ALL-NEXT:    pushq %r8
+;ALL-NEXT:    pushq %rdi
+;ALL-NEXT:    pushq %rsi
+;VOID-NEXT:   pushq %rdx
+;INT-NEXT:    pushq %rdx
+;INT128-NOT:  pushq %rdx
+;ALL-NEXT:    pushq %rcx
+;VOID-NEXT:   pushq %rax
+;INT-NOT:     pushq %rax
+;INT128-NOT:  pushq %rax
+;ALL-NEXT:    pushq %rbp
+;ALL-NEXT:    pushq %r15
+;ALL-NEXT:    pushq %r14
+;ALL-NEXT:    pushq %r13
+;ALL-NEXT:    pushq %r12
+;ALL-NEXT:    pushq %rbx
+;ALL:         movaps %xmm15
+;ALL-NEXT:    movaps %xmm14
+;ALL-NEXT:    movaps %xmm13
+;ALL-NEXT:    movaps %xmm12
+;ALL-NEXT:    movaps %xmm11
+;ALL-NEXT:    movaps %xmm10
+;ALL-NEXT:    movaps %xmm9
+;ALL-NEXT:    movaps %xmm8
+;ALL-NEXT:    movaps %xmm7
+;ALL-NEXT:    movaps %xmm6
+;ALL-NOT:     movaps %xmm5
+;ALL-NOT:     movaps %xmm4
+;ALL-NOT:     movaps %xmm3
+;ALL-NOT:     movaps %xmm2
+;ALL-NOT:     movaps %xmm1
+;ALL-NOT:     movaps %xmm0
+;ALL-NOT:     movaps {{.*}} %xmm0
+;ALL-NOT:     movaps {{.*}} %xmm1
+;ALL-NOT:     movaps {{.*}} %xmm2
+;ALL-NOT:     movaps {{.*}} %xmm3
+;ALL-NOT:     movaps {{.*}} %xmm4
+;ALL-NOT:     movaps {{.*}} %xmm5
+;ALL:         movaps {{.*}} %xmm6
+;ALL-NEXT:    movaps {{.*}} %xmm7
+;ALL-NEXT:    movaps {{.*}} %xmm8
+;ALL-NEXT:    movaps {{.*}} %xmm9
+;ALL-NEXT:    movaps {{.*}} %xmm10
+;ALL-NEXT:    movaps {{.*}} %xmm11
+;ALL-NEXT:    movaps {{.*}} %xmm12
+;ALL-NEXT:    movaps {{.*}} %xmm13
+;ALL-NEXT:    movaps {{.*}} %xmm14
+;ALL-NEXT:    movaps {{.*}} %xmm15
+;ALL:         popq    %rbx
+;ALL-NEXT:    popq    %r12
+;ALL-NEXT:    popq    %r13
+;ALL-NEXT:    popq    %r14
+;ALL-NEXT:    popq    %r15
+;ALL-NEXT:    popq    %rbp
+;VOID-NEXT:   popq    %rax
+;INT-NOT:     popq    %rax
+;INT128-NOT:  popq    %rax
+;ALL-NEXT:    popq    %rcx
+;VOID-NEXT:   popq    %rdx
+;INT-NEXT:    popq    %rdx
+;INT128-NOT:  popq    %rdx
+;ALL-NEXT:    popq    %rsi
+;ALL-NEXT:    popq    %rdi
+;ALL-NEXT:    popq    %r8
+;ALL-NEXT:    popq    %r9
+;ALL-NEXT:    popq    %r10
+  call void asm sideeffect "", "~{rax},~{rbx},~{rcx},~{rdx},~{rsi},~{rdi},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{rbp},~{xmm0},~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15}"()
+  ret RETTYPE RETVAL
+}
+
+; Make sure XMMs are not saved before the call
+declare preserve_mostcc RETTYPE @foo(i64, i64, double, double)
+define void @preserve_mostcc2() nounwind {
+entry:
+;ALL-LABEL: preserve_mostcc2
+;ALL-NOT:   movaps
+;ALL-NOT:   {{.*xmm[0-1,4-9].*}}
+  call preserve_mostcc RETTYPE @foo(i64 1, i64 2, double 3.0, double 4.0)
+  ret void
+}


        


More information about the llvm-commits mailing list