On Thu, Jul 24, 2025 at 5:35 PM Artemiy Granat <a.gra...@ispras.ru> wrote: > > The regparm attribute does not affect code generation on x86-64 target. > Despite this, regparm was accepted silently, unlike other calling > convention attributes handled in the ix86_handle_cconv_attribute > function. > > Due to lack of diagnostics, Linux kernel attempted to specify regparm(0) > on vmread_error_trampoline declaration, which is supposed to be invoked > with all arguments on stack: > https://lore.kernel.org/all/20220928232015.745948-1-sea...@google.com/
This looks somehow familiar ;) > To produce a warning for regparm in 64-bit mode, simply move the block > that produces diagnostics above the block that handles the regparm > attribute. I agree we should warn for ignored regparm attribute. > gcc/ChangeLog: > > * config/i386/i386-options.cc (ix86_handle_cconv_attribute): > Move 64-bit mode check before regparm handling. > > gcc/testsuite/ChangeLog: > > * g++.dg/abi/regparm1.C: Use regparm attribute only if not in > 64-bit mode. > * gcc.target/i386/20020224-1.c: Likewise. > * gcc.target/i386/pr103785.c: Likewise. > * gcc.target/i386/pr36533.c: Likewise. > * gcc.target/i386/pr59099.c: Likewise. > * gcc.target/i386/sibcall-8.c: Likewise. > * gcc.target/i386/sw-1.c: Likewise. > * gcc.target/i386/pr15184-2.c: Fix invalid comment. > * gcc.target/i386/attributes-ignore.c: New test. Please enable testcases that explicitly test regparm attribute only for ix86 targets using ia32 target selector. They are irrelevant for x86_64 anyway. Uros. > --- > gcc/config/i386/i386-options.cc | 24 +++++++++---------- > gcc/testsuite/g++.dg/abi/regparm1.C | 9 ++++++- > gcc/testsuite/gcc.target/i386/20020224-1.c | 10 ++++++-- > .../gcc.target/i386/attributes-ignore.c | 8 +++++++ > gcc/testsuite/gcc.target/i386/pr103785.c | 5 +++- > gcc/testsuite/gcc.target/i386/pr15184-2.c | 2 +- > gcc/testsuite/gcc.target/i386/pr36533.c | 24 +++++++++++++++---- > gcc/testsuite/gcc.target/i386/pr59099.c | 9 ++++++- > gcc/testsuite/gcc.target/i386/sibcall-8.c | 14 +++++++---- > gcc/testsuite/gcc.target/i386/sw-1.c | 5 +++- > 10 files changed, 83 insertions(+), 27 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/i386/attributes-ignore.c > > diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc > index d244b225afe..f07e8bc5303 100644 > --- a/gcc/config/i386/i386-options.cc > +++ b/gcc/config/i386/i386-options.cc > @@ -3613,6 +3613,18 @@ ix86_handle_cconv_attribute (tree *node, tree name, > tree args, int, > return NULL_TREE; > } > > + if (TARGET_64BIT) > + { > + /* Do not warn when emulating the MS ABI. */ > + if ((TREE_CODE (*node) != FUNCTION_TYPE > + && TREE_CODE (*node) != METHOD_TYPE) > + || ix86_function_type_abi (*node) != MS_ABI) > + warning (OPT_Wattributes, "%qE attribute ignored", > + name); > + *no_add_attrs = true; > + return NULL_TREE; > + } > + > /* Can combine regparm with all attributes but fastcall, and thiscall. */ > if (is_attribute_p ("regparm", name)) > { > @@ -3646,18 +3658,6 @@ ix86_handle_cconv_attribute (tree *node, tree name, > tree args, int, > return NULL_TREE; > } > > - if (TARGET_64BIT) > - { > - /* Do not warn when emulating the MS ABI. */ > - if ((TREE_CODE (*node) != FUNCTION_TYPE > - && TREE_CODE (*node) != METHOD_TYPE) > - || ix86_function_type_abi (*node) != MS_ABI) > - warning (OPT_Wattributes, "%qE attribute ignored", > - name); > - *no_add_attrs = true; > - return NULL_TREE; > - } > - > /* Can combine fastcall with stdcall (redundant) and sseregparm. */ > if (is_attribute_p ("fastcall", name)) > { > diff --git a/gcc/testsuite/g++.dg/abi/regparm1.C > b/gcc/testsuite/g++.dg/abi/regparm1.C > index c4710464acc..52ba8d8d9cf 100644 > --- a/gcc/testsuite/g++.dg/abi/regparm1.C > +++ b/gcc/testsuite/g++.dg/abi/regparm1.C > @@ -11,7 +11,10 @@ int fail; > > struct Base > { > - __attribute((regparm(3))) void > +#ifndef __x86_64__ > + __attribute((regparm(3))) > +#endif > + void > set(int *addr1, int *addr2) > { > if (this != save_this) > @@ -34,7 +37,11 @@ struct Base > > int main() > { > +#ifndef __x86_64__ > void (__attribute((regparm(3))) Base::* pfm)(int *, int *) = &Base::set; > +#else > + void (Base::* pfm)(int *, int *) = &Base::set; > +#endif > __typeof (&Base::set) pfm2 = &Base::set; > decltype (&Base::set) pfm3 = &Base::set; > auto pfm4 = &Base::set; > diff --git a/gcc/testsuite/gcc.target/i386/20020224-1.c > b/gcc/testsuite/gcc.target/i386/20020224-1.c > index 2905719fa62..0a21857fc0b 100644 > --- a/gcc/testsuite/gcc.target/i386/20020224-1.c > +++ b/gcc/testsuite/gcc.target/i386/20020224-1.c > @@ -15,13 +15,19 @@ typedef struct { > > A a; > > -A __attribute__ ((regparm (2))) > +A > +#ifndef __x86_64__ > +__attribute__ ((regparm (2))) > +#endif > foo (int x) > { > return a; > } > > -int __attribute__ ((regparm (2))) > +int > +#ifndef __x86_64__ > +__attribute__ ((regparm (2))) > +#endif > bar (int x) > { > int r = foo(0).a2; > diff --git a/gcc/testsuite/gcc.target/i386/attributes-ignore.c > b/gcc/testsuite/gcc.target/i386/attributes-ignore.c > new file mode 100644 > index 00000000000..93a3770842c > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/attributes-ignore.c > @@ -0,0 +1,8 @@ > +/* { dg-do compile { target { ! ia32 } } } */ > + > +void foo1(int i, int j) __attribute__((regparm(0))); /* { dg-warning > "ignored" } */ > +void foo2(int i, int j) __attribute__((stdcall)); /* { dg-warning "ignored" > } */ > +void foo3(int i, int j) __attribute__((fastcall)); /* { dg-warning "ignored" > } */ > +void foo4(int i, int j) __attribute__((cdecl)); /* { dg-warning "ignored" } > */ > +void foo5(int i, int j) __attribute__((thiscall)); /* { dg-warning "ignored" > } */ > +void foo6(int i, int j) __attribute__((sseregparm)); /* { dg-warning > "ignored" } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr103785.c > b/gcc/testsuite/gcc.target/i386/pr103785.c > index 5503b965256..49d6c56f8d2 100644 > --- a/gcc/testsuite/gcc.target/i386/pr103785.c > +++ b/gcc/testsuite/gcc.target/i386/pr103785.c > @@ -11,7 +11,10 @@ struct wrapper_t > > struct wrapper_t **table; > > -__attribute__ ((weak, regparm (2))) > +#ifndef __x86_64__ > +__attribute__ ((regparm (2))) > +#endif > +__attribute__ ((weak)) > void > update (long k, long e) > { > diff --git a/gcc/testsuite/gcc.target/i386/pr15184-2.c > b/gcc/testsuite/gcc.target/i386/pr15184-2.c > index cb8201f9731..dd50c42b90d 100644 > --- a/gcc/testsuite/gcc.target/i386/pr15184-2.c > +++ b/gcc/testsuite/gcc.target/i386/pr15184-2.c > @@ -1,4 +1,4 @@ > -/* PR 15184 second two tests > +/* PR 15184 second two tests */ > /* { dg-do compile { target ia32 } } */ > /* { dg-options "-O2 -march=pentiumpro" } */ > /* { dg-additional-options "-fno-PIE" { target ia32 } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr36533.c > b/gcc/testsuite/gcc.target/i386/pr36533.c > index 8d71ece199d..8699d262a59 100644 > --- a/gcc/testsuite/gcc.target/i386/pr36533.c > +++ b/gcc/testsuite/gcc.target/i386/pr36533.c > @@ -55,14 +55,22 @@ typedef struct > S1 *s18; > } S7; > > -__attribute__((regparm (3), noinline)) int > +#ifndef __x86_64__ > +__attribute__((regparm (3))) > +#endif > +__attribute__((noinline)) > +int > fn1 (const char *x, void *y, S1 *z) > { > asm volatile ("" : : : "memory"); > return *x + (y != 0); > } > > -__attribute__((regparm (3), noinline)) int > +#ifndef __x86_64__ > +__attribute__((regparm (3))) > +#endif > +__attribute__((noinline)) > +int > fn2 (const char *x, int y, S2 *z) > { > asm volatile ("" : : : "memory"); > @@ -84,7 +92,11 @@ fn3 (S3 *p) > return (S3 *) ((char *) p + fn4 (p->s9)); > } > > -__attribute__((regparm (3), noinline)) int > +#ifndef __x86_64__ > +__attribute__((regparm (3))) > +#endif > +__attribute__((noinline)) > +int > fn5 (void) > { > asm volatile ("" : : : "memory"); > @@ -116,7 +128,11 @@ fn6 (S3 *w, int x, S2 *y, S4 *z) > return a; > } > > -__attribute__((regparm (3), noinline)) unsigned int > +#ifndef __x86_64__ > +__attribute__((regparm (3))) > +#endif > +__attribute__((noinline)) > +unsigned int > test (void *u, S6 *v, S1 **w, S7 *x, S2 *y, S1 *z) > { > unsigned b = v->s17->s16; > diff --git a/gcc/testsuite/gcc.target/i386/pr59099.c > b/gcc/testsuite/gcc.target/i386/pr59099.c > index cf4a8da7db1..21dfbc2defa 100644 > --- a/gcc/testsuite/gcc.target/i386/pr59099.c > +++ b/gcc/testsuite/gcc.target/i386/pr59099.c > @@ -13,10 +13,17 @@ struct s > }; > > > -void* f (struct s *, struct s *) __attribute__ ((noinline, regparm(1))); > +void* f (struct s *, struct s *) > +#ifndef __x86_64__ > +__attribute__ ((regparm(1))) > +#endif > +__attribute__ ((noinline)) > +; > > void* > +#ifndef __x86_64__ > __attribute__ ((regparm(1))) > +#endif > f (struct s *p, struct s *p2) > { > void *gp, *gp1; > diff --git a/gcc/testsuite/gcc.target/i386/sibcall-8.c > b/gcc/testsuite/gcc.target/i386/sibcall-8.c > index 3ab3809036d..29ebfe59284 100644 > --- a/gcc/testsuite/gcc.target/i386/sibcall-8.c > +++ b/gcc/testsuite/gcc.target/i386/sibcall-8.c > @@ -1,23 +1,29 @@ > /* { dg-do run } */ > /* { dg-options "-O2" } */ > > +#ifndef __x86_64__ > +#define REGPARM __attribute__((regparm(1))) > +#else > +#define REGPARM > +#endif > + > extern void abort (void); > > -static int __attribute__((regparm(1))) > +static int REGPARM > bar(void *arg) > { > return arg != bar; > } > > -static int __attribute__((noinline,noclone,regparm(1))) > -foo(int (__attribute__((regparm(1))) **bar)(void*)) > +static int __attribute__((noinline,noclone)) REGPARM > +foo(int (REGPARM **bar)(void*)) > { > return (*bar)(*bar); > } > > int main() > { > - int (__attribute__((regparm(1))) *p)(void*) = bar; > + int (REGPARM *p)(void*) = bar; > if (foo(&p)) > abort(); > return 0; > diff --git a/gcc/testsuite/gcc.target/i386/sw-1.c > b/gcc/testsuite/gcc.target/i386/sw-1.c > index 14db3cee206..025f0e15d51 100644 > --- a/gcc/testsuite/gcc.target/i386/sw-1.c > +++ b/gcc/testsuite/gcc.target/i386/sw-1.c > @@ -7,7 +7,10 @@ > > int c; > int x[2000]; > -__attribute__((regparm(1))) void foo (int a, int b) > +#ifndef __x86_64__ > +__attribute__((regparm(1))) > +#endif > +void foo (int a, int b) > { > int t[200]; > if (a == 0 || c == 0) > -- > 2.50.1 >