Re: [PATCH] i386: preserve fastcall reg slots across aggregate args [PR41013]
Oleg Tolmatcev <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CACcXsZguTk4V-trv9CjePTn0PErhKoJxLUSaKnUCAcEWpxCEfA@mail.gmail.com> |
сб, 27 июн. 2026 г. в 18:07, Oleg Tolmatcev <[email protected]>: > > 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 > I am dropping this patch. i386 is obsolete, so fixing this bug is not worth it. Oleg