From: oltolm <[email protected]>
On x86-32 fastcall, by-value aggregate arguments are stack-passed and
must not consume the ECX/EDX register cursor in function_arg_advance_32.
Advancing the cursor for BLKmode/DImode/aggregate arguments could shift
later eligible scalar arguments out of fastcall registers and onto the stack.
gcc/ChangeLog:
PR target/41013
* config/i386/i386.cc (function_arg_advance_32): Do not
consume fastcall register slots for BLKmode/DImode/aggregate
arguments.
gcc/testsuite/ChangeLog:
PR target/41013
* gcc.target/i386/fastcall-1.c: Restrict to mingw targets and
force -m32.
* gcc.target/i386/fastcall-arg-kinds-1.c: New test.
* gcc.target/i386/thiscall-arg-kinds-1.c: New test.
Signed-off-by: oltolm <[email protected]>
---
I don't have commit rights for the git repository.
gcc/config/i386/i386.cc | 12 ++++
gcc/testsuite/gcc.target/i386/fastcall-1.c | 4 +-
.../gcc.target/i386/fastcall-arg-kinds-1.c | 70 +++++++++++++++++++
.../gcc.target/i386/thiscall-arg-kinds-1.c | 42 +++++++++++
4 files changed, 126 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/i386/fastcall-arg-kinds-1.c
create mode 100644 gcc/testsuite/gcc.target/i386/thiscall-arg-kinds-1.c
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index e66958db7a..1b019f9e1c 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -3101,6 +3101,18 @@ function_arg_advance_32 (CUMULATIVE_ARGS *cum,
machine_mode mode,
case E_HImode:
case E_QImode:
pass_in_reg:
+ /* For fastcall, only register-eligible scalar arguments consume
+ the ECX/EDX slots. Non-eligible arguments are passed on stack
+ and must not advance the fastcall register cursor. */
+ if (cum->fastcall
+ && (mode == BLKmode
+ || mode == DImode
+ || (type && AGGREGATE_TYPE_P (type))))
+ {
+ cum->words += words;
+ break;
+ }
+
cum->words += words;
cum->nregs -= words;
cum->regno += words;
diff --git a/gcc/testsuite/gcc.target/i386/fastcall-1.c
b/gcc/testsuite/gcc.target/i386/fastcall-1.c
index 9d70123916..ce08695563 100644
--- a/gcc/testsuite/gcc.target/i386/fastcall-1.c
+++ b/gcc/testsuite/gcc.target/i386/fastcall-1.c
@@ -1,5 +1,5 @@
-/* { dg-do compile { target i?86-*-mingw32* i?86-*-cygwin* } } */
-/* { dg-options "-std=gnu89" } */
+/* { dg-do compile { target *-*-mingw32* i?86-*-cygwin* } } */
+/* { dg-options "-m32 -std=gnu89" } */
void
__attribute__ ((fastcall))
diff --git a/gcc/testsuite/gcc.target/i386/fastcall-arg-kinds-1.c
b/gcc/testsuite/gcc.target/i386/fastcall-arg-kinds-1.c
new file mode 100644
index 0000000000..fadad43359
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/fastcall-arg-kinds-1.c
@@ -0,0 +1,70 @@
+/* { dg-do compile { target *-*-mingw32* } } */
+/* { dg-options "-m32 -O0" } */
+
+enum e { E0 = 0, E1 = 1 };
+union u { int x; };
+struct s { int x; };
+
+int __attribute__((fastcall, noinline))
+fp (int *p, int a1)
+{
+ return *p + a1;
+}
+
+int __attribute__((fastcall, noinline))
+fe (enum e v, int a1)
+{
+ return (int) v + a1;
+}
+
+int __attribute__((fastcall, noinline))
+fu (union u v, int a1)
+{
+ return v.x + a1;
+}
+
+int __attribute__((fastcall, noinline))
+fs (struct s v, int a1)
+{
+ return v.x + a1;
+}
+
+int __attribute__((fastcall, noinline))
+f2 (struct s v, int a1, int a2)
+{
+ return v.x + a1 + a2;
+}
+
+int
+main (void)
+{
+ int a = 7;
+ union u uv = { 11 };
+ struct s sv = { 13 };
+
+ return (fp (&a, 1)
+ + fe (E1, 2)
+ + fu (uv, 3)
+ + fs (sv, 4)
+ + f2 (sv, 5, 6));
+}
+
+/* Pointer and enum arguments are register-eligible in fastcall. */
+/* { dg-final { scan-assembler {call[ \t]+@fp@8} } } */
+/* { dg-final { scan-assembler {call[ \t]+@fe@8} } } */
+/* { dg-final { scan-assembler {movl\t\$1, %edx} } } */
+/* { dg-final { scan-assembler {movl\t\$2, %edx} } } */
+/* { dg-final { scan-assembler {movl\t\$1, %ecx} } } */
+
+/* Small aggregates remain stack-passed, and the integer argument stays in
ECX. */
+/* { dg-final { scan-assembler {call[ \t]+@fu@8} } } */
+/* { dg-final { scan-assembler {call[ \t]+@fs@8} } } */
+/* { dg-final { scan-assembler-times {movl\t%eax, \(%esp\)} 3 } } */
+/* { dg-final { scan-assembler {movl\t\$3, %ecx} } } */
+/* { dg-final { scan-assembler {movl\t\$4, %ecx} } } */
+
+/* Aggregate arg must not consume fastcall register slots; both ints stay
+ register-passed in ECX/EDX. */
+/* { dg-final { scan-assembler {call[ \t]+@f2@12} } } */
+/* { dg-final { scan-assembler {movl\t\$5, %ecx} } } */
+/* { dg-final { scan-assembler {movl\t\$6, %edx} } } */
diff --git a/gcc/testsuite/gcc.target/i386/thiscall-arg-kinds-1.c
b/gcc/testsuite/gcc.target/i386/thiscall-arg-kinds-1.c
new file mode 100644
index 0000000000..2b5450aae3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/thiscall-arg-kinds-1.c
@@ -0,0 +1,42 @@
+/* { dg-do compile { target *-*-mingw32* } } */
+/* { dg-options "-m32 -O0" } */
+
+struct s { int x; };
+
+int __attribute__((thiscall, noinline))
+fp (int *p, int a1)
+{
+ return *p + a1;
+}
+
+int __attribute__((thiscall, noinline))
+fs (struct s v, int a1)
+{
+ return v.x + a1;
+}
+
+int __attribute__((thiscall, noinline))
+f2 (int a0, int a1)
+{
+ return a0 + a1;
+}
+
+int
+main (void)
+{
+ int a = 7;
+ struct s sv = { 11 };
+
+ return fp (&a, 1) + fs (sv, 2) + f2 (3, 4);
+}
+
+/* Pointer arguments remain register-eligible in thiscall. */
+/* { dg-final { scan-assembler {movl\t\$1, \(%esp\)} } } */
+
+/* Small aggregates remain stack-passed, and the later integer stays in ECX.
*/
+/* { dg-final { scan-assembler-times {movl\t%eax, \(%esp\)} 1 } } */
+/* { dg-final { scan-assembler {movl\t\$2, %ecx} } } */
+
+/* Control case: only the first scalar gets the ECX slot. */
+/* { dg-final { scan-assembler {movl\t\$3, %ecx} } } */
+/* { dg-final { scan-assembler {movl\t\$4, \(%esp\)} } } */
--
2.54.0.windows.1