From 930551bb624e397594d2d59e1f82bfc86caebd22 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 13 May 2026 08:27:50 +0800
Subject: [PATCH] x86: Honor preserve_none ABI for x86-64 MS calls
In 64-bit mode, preserve_none attribute uses a different calling
convention. Ignore MS ABI with preserve_none attribute to always
use the preserve_none calling convention with preserve_none
attribute.
gcc/
PR target/125297
* config/i386/i386.cc (ix86_function_arg_regno_p): Use
x86_64_preserve_none_int_parameter_registers for
TYPE_PRESERVE_NONE.
(ix86_function_type_abi): In 64-bit mode, ignore ms_abi
attribute with preserve_none attribute.
(x86_64_cumulative_ms_abi_p): New function.
(init_cumulative_args): Call x86_64_cumulative_ms_abi_p to
decide if MS_ABI is used.
(ix86_function_arg_advance): Likewise.
(ix86_function_arg): Likewise.
gcc/testsuite/
PR target/125297
* gcc.target/i386/preserve-none-31a.c: New test.
* gcc.target/i386/preserve-none-31b.c: Likewise.
* gcc.target/i386/preserve-none-32a.c: Likewise.
* gcc.target/i386/preserve-none-32b.c: Likewise.
* gcc.target/i386/preserve-none-33a.c: Likewise.
* gcc.target/i386/preserve-none-33b.c: Likewise.
* gcc.target/i386/preserve-none-34a.c: Likewise.
* gcc.target/i386/preserve-none-34b.c: Likewise.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
gcc/config/i386/i386.cc | 38 +++++++++++++------
.../gcc.target/i386/preserve-none-31a.c | 36 ++++++++++++++++++
.../gcc.target/i386/preserve-none-31b.c | 25 ++++++++++++
.../gcc.target/i386/preserve-none-32a.c | 29 ++++++++++++++
.../gcc.target/i386/preserve-none-32b.c | 18 +++++++++
.../gcc.target/i386/preserve-none-33a.c | 36 ++++++++++++++++++
.../gcc.target/i386/preserve-none-33b.c | 25 ++++++++++++
.../gcc.target/i386/preserve-none-34a.c | 29 ++++++++++++++
.../gcc.target/i386/preserve-none-34b.c | 18 +++++++++
9 files changed, 243 insertions(+), 11 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-31a.c
create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-31b.c
create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-32a.c
create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-32b.c
create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-33a.c
create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-33b.c
create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-34a.c
create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-34b.c
@@ -1591,16 +1591,19 @@ ix86_function_arg_regno_p (int regno)
if (call_abi == SYSV_ABI && regno == AX_REG)
return true;
+ int regparm_max = X86_64_REGPARM_MAX;
if (cfun
&& cfun->machine->call_saved_registers == TYPE_PRESERVE_NONE)
parm_regs = x86_64_preserve_none_int_parameter_registers;
else if (call_abi == MS_ABI)
- parm_regs = x86_64_ms_abi_int_parameter_registers;
+ {
+ parm_regs = x86_64_ms_abi_int_parameter_registers;
+ regparm_max = X86_64_MS_REGPARM_MAX;
+ }
else
parm_regs = x86_64_int_parameter_registers;
- for (i = 0; i < (call_abi == MS_ABI
- ? X86_64_MS_REGPARM_MAX : X86_64_REGPARM_MAX); i++)
+ for (i = 0; i < regparm_max; i++)
if (regno == parm_regs[i])
return true;
return false;
@@ -1665,7 +1668,11 @@ ix86_function_type_abi (const_tree fntype)
warned = 1;
}
- abi = MS_ABI;
+ /* NB: preserve_none attribute overrides ms_abi in 64-bit mode. */
+ if (!TARGET_64BIT
+ || !lookup_attribute ("preserve_none",
+ TYPE_ATTRIBUTES (fntype)))
+ abi = MS_ABI;
}
else if (abi == MS_ABI
&& lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (fntype)))
@@ -1856,6 +1863,17 @@ ix86_init_pic_reg (void)
commit_one_edge_insertion (entry_edge);
}
+/* Return true if x86-64 CUM is MS_ABI. */
+
+static bool
+x86_64_cumulative_ms_abi_p (CUMULATIVE_ARGS *cum)
+{
+ if (!cum)
+ return ix86_abi == MS_ABI;
+
+ return !cum->preserve_none_abi && cum->call_abi == MS_ABI;
+}
+
/* Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0. */
@@ -1910,9 +1928,9 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */
cum->nregs = ix86_regparm;
if (TARGET_64BIT)
{
- cum->nregs = (cum->call_abi == SYSV_ABI
- ? X86_64_REGPARM_MAX
- : X86_64_MS_REGPARM_MAX);
+ cum->nregs = (x86_64_cumulative_ms_abi_p (cum)
+ ? X86_64_MS_REGPARM_MAX
+ : X86_64_REGPARM_MAX);
}
if (TARGET_SSE)
{
@@ -3262,9 +3280,7 @@ ix86_function_arg_advance (cumulative_args_t cum_v,
if (TARGET_64BIT)
{
- enum calling_abi call_abi = cum ? cum->call_abi : ix86_abi;
-
- if (call_abi == MS_ABI)
+ if (x86_64_cumulative_ms_abi_p (cum))
nregs = function_arg_advance_ms_64 (cum, bytes, words);
else
nregs = function_arg_advance_64 (cum, mode, arg.type, words,
@@ -3593,7 +3609,7 @@ ix86_function_arg (cumulative_args_t cum_v, const function_arg_info &arg)
if (TARGET_64BIT)
{
- if (cum->call_abi == MS_ABI)
+ if (x86_64_cumulative_ms_abi_p (cum))
reg = function_arg_ms_64 (cum, mode, arg.mode, arg.named,
arg.type, bytes);
else
new file mode 100644
@@ -0,0 +1,36 @@
+/* { dg-do compile { target { lp64 } } } */
+/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args -fomit-frame-pointer -mtune=generic -mabi=ms" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */
+
+/*
+**entry:
+**.LFB[0-9]+:
+** .cfi_startproc
+** subq \$72, %rsp
+**...
+** movl %ecx, %r12d
+** movl %edx, %r13d
+** movl %r9d, %r15d
+** movl 120\(%rsp\), %esi
+** movl 112\(%rsp\), %edi
+** movl %r8d, %r14d
+** xorl %eax, %eax
+** movl \$-559038737, 48\(%rsp\)
+** call continuation
+** addq \$72, %rsp
+**...
+** ret
+** .cfi_endproc
+**...
+*/
+
+extern void continuation (int, int, int, int, int, int, ...)
+ __attribute__ ((preserve_none));
+
+__attribute__ ((no_callee_saved_registers))
+void
+entry (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6)
+{
+ continuation (arg1, arg2, arg3, arg4, arg5, arg6, 0xdeadbeef);
+}
new file mode 100644
@@ -0,0 +1,25 @@
+/* { dg-do compile { target { llp64 } } } */
+/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args -fomit-frame-pointer -mtune=generic -mabi=ms" } */
+/* Keep labels and directives ('.seh_endprologue'). */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */
+
+/*
+**entry:
+** subq \$72, %rsp
+** .seh_stackalloc 72
+** .seh_endprologue
+** xorl %eax, %eax
+** movl 120\(%rsp\), %esi
+** movl 112\(%rsp\), %edi
+** movl %ecx, %r12d
+** movl %edx, %r13d
+** movl %r9d, %r15d
+** movl %r8d, %r14d
+** movl \$-559038737, 48\(%rsp\)
+** call continuation
+** nop
+** addq \$72, %rsp
+** ret
+*/
+
+#include "preserve-none-31a.c"
new file mode 100644
@@ -0,0 +1,29 @@
+/* { dg-do compile { target { lp64 } } } */
+/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args -fomit-frame-pointer -mtune=generic -mabi=ms" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */
+
+/*
+**entry:
+**.LFB[0-9]+:
+** .cfi_startproc
+** movl 56\(%rsp\), %esi
+** movl 48\(%rsp\), %edi
+** movl %edx, %r12d
+** movl %r9d, %r14d
+** movl 40\(%rsp\), %r15d
+** movl %r8d, %r13d
+** jmp continuation
+** .cfi_endproc
+**...
+*/
+
+extern void continuation (double, int, int, int, int, int, int)
+ __attribute__ ((preserve_none));
+
+__attribute__ ((no_callee_saved_registers))
+void
+entry (double fp, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6)
+{
+ continuation (fp, arg1, arg2, arg3, arg4, arg5, arg6);
+}
new file mode 100644
@@ -0,0 +1,18 @@
+/* { dg-do compile { target { llp64 } } } */
+/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args -fomit-frame-pointer -mtune=generic -mabi=ms" } */
+/* Keep labels and directives ('.seh_endprologue'). */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */
+
+/*
+**entry:
+** .seh_endprologue
+** movl 56\(%rsp\), %esi
+** movl 48\(%rsp\), %edi
+** movl 40\(%rsp\), %r15d
+** movl %edx, %r12d
+** movl %r9d, %r14d
+** movl %r8d, %r13d
+** jmp continuation
+*/
+
+#include "preserve-none-32a.c"
new file mode 100644
@@ -0,0 +1,36 @@
+/* { dg-do compile { target { lp64 } } } */
+/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args -fomit-frame-pointer -mtune=generic -mabi=sysv" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */
+
+/*
+**entry:
+**.LFB[0-9]+:
+** .cfi_startproc
+** subq \$24, %rsp
+**...
+** movl %edi, %r12d
+** movl %esi, %r13d
+** movl %edx, %r14d
+** movl \$-559038737, \(%rsp\)
+** movl %ecx, %r15d
+** movl %r9d, %esi
+** movl %r8d, %edi
+** xorl %eax, %eax
+** call continuation
+** addq \$24, %rsp
+**...
+** ret
+** .cfi_endproc
+**...
+*/
+
+extern void continuation (int, int, int, int, int, int, ...)
+ __attribute__ ((preserve_none, ms_abi));
+
+__attribute__ ((no_callee_saved_registers))
+void
+entry (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6)
+{
+ continuation (arg1, arg2, arg3, arg4, arg5, arg6, 0xdeadbeef);
+}
new file mode 100644
@@ -0,0 +1,25 @@
+/* { dg-do compile { target { llp64 } } } */
+/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args -fomit-frame-pointer -mtune=generic -mabi=ms" } */
+/* Keep labels and directives ('.seh_endprologue'). */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */
+
+/*
+**entry:
+** subq \$72, %rsp
+** .seh_stackalloc 72
+** .seh_endprologue
+** xorl %eax, %eax
+** movl 120\(%rsp\), %esi
+** movl 112\(%rsp\), %edi
+** movl %ecx, %r12d
+** movl %edx, %r13d
+** movl %r9d, %r15d
+** movl %r8d, %r14d
+** movl \$-559038737, 48\(%rsp\)
+** call continuation
+** nop
+** addq \$72, %rsp
+** ret
+*/
+
+#include "preserve-none-33a.c"
new file mode 100644
@@ -0,0 +1,29 @@
+/* { dg-do compile { target { lp64 } } } */
+/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer -mtune=generic -mabi=sysv" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */
+
+/*
+**entry:
+**.LFB[0-9]+:
+** .cfi_startproc
+** movl %edi, %r12d
+** movl %esi, %r13d
+** movl %edx, %r14d
+** movl %ecx, %r15d
+** movl %r9d, %esi
+** movl %r8d, %edi
+** jmp continuation
+** .cfi_endproc
+**...
+*/
+
+extern void continuation (double, int, int, int, int, int, int)
+ __attribute__ ((preserve_none, ms_abi));
+
+__attribute__ ((no_callee_saved_registers))
+void
+entry (double fp, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6)
+{
+ continuation (fp, arg1, arg2, arg3, arg4, arg5, arg6);
+}
new file mode 100644
@@ -0,0 +1,18 @@
+/* { dg-do compile { target { llp64 } } } */
+/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args -fomit-frame-pointer -mtune=generic -mabi=ms" } */
+/* Keep labels and directives ('.seh_endprologue'). */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */
+
+/*
+**entry:
+** .seh_endprologue
+** movl 56\(%rsp\), %esi
+** movl 48\(%rsp\), %edi
+** movl 40\(%rsp\), %r15d
+** movl %edx, %r12d
+** movl %r9d, %r14d
+** movl %r8d, %r13d
+** jmp continuation
+*/
+
+#include "preserve-none-34a.c"
--
2.55.0