Message ID | ZyyVZ4EOWJbs7XyH@tucnak |
---|---|
State | New |
Headers | show |
Series | inline-asm, i386, v2: Add "redzone" clobber support | expand |
On Thu, Nov 7, 2024 at 11:24 AM Jakub Jelinek <jakub@redhat.com> wrote: > > On Thu, Nov 07, 2024 at 09:12:34AM +0100, Uros Bizjak wrote: > > On Thu, Nov 7, 2024 at 9:00 AM Jakub Jelinek <jakub@redhat.com> wrote: > > > > > > On Thu, Nov 07, 2024 at 08:47:34AM +0100, Uros Bizjak wrote: > > > > Maybe we should always recognize "redzone", even for targets without > > > > it. This is the way we recognize "cc" even for targets without CC reg > > > > (e.g. alpha). This would simplify the definition and processing - if > > > > the hook returns NULL_RTX (the default), then it (obviously) won't be > > > > added to the clobber list. > > > > > > Dunno, am open to that, but thought it would be just weird if one says > > > "redzone" on targets which don't have such a concept. > > > > Let's look at the situation with x86_32 and x86_64. The "redzone" for > > the former is just an afterthought, so we can safely say that it > > doesn't support it. So, the code that targets both targets (e.g. linux > > kernel) would (in a pedantic way) have to redefine many shared asm > > defines, one to have clobber and one without it. We don't want that, > > we want one definition and "let's compiler sort it out". > > > > For targets without clobber concept, well - don't add it to the > > clobber list if it is always ineffective. One *can* add "cc" to all > > alpha asms, but well.. ;) > > Ok, here is a variant of the patch which just ignores "redzone" clobber if > it doesn't make sense. > > 2024-11-07 Jakub Jelinek <jakub@redhat.com> > > gcc/ > * target.def (redzone_clobber): New target hook. > * varasm.cc (decode_reg_name_and_count): Return -5 for > "redzone". > * cfgexpand.cc (expand_asm_stmt): Handle redzone clobber. > * config/i386/i386.h (struct machine_function): Add > asm_redzone_clobber_seen member. > * config/i386/i386.cc (ix86_compute_frame_layout): Don't > use red zone if cfun->machine->asm_redzone_clobber_seen. > (ix86_redzone_clobber): New function. > (TARGET_REDZONE_CLOBBER): Redefine. > * doc/extend.texi (Clobbers and Scratch Registers): Document > the "redzone" clobber. > * doc/tm.texi.in: Add @hook TARGET_REDZONE_CLOBBER. > * doc/tm.texi: Regenerate. > gcc/testsuite/ > * gcc.dg/asm-redzone-1.c: New test. > * gcc.target/i386/asm-redzone-1.c: New test. OK for the x86 part, LGTM for other parts. Thanks, Uros. > > --- gcc/target.def.jj 2024-11-06 18:53:10.836843793 +0100 > +++ gcc/target.def 2024-11-07 10:57:58.697898800 +0100 > @@ -3376,6 +3376,16 @@ to be used.", > bool, (machine_mode mode), > NULL) > > +DEFHOOK > +(redzone_clobber, > + "Define this to return some RTL for the @code{redzone} @code{asm} clobber\n\ > +if target has a red zone and wants to support the @code{redzone} clobber\n\ > +or return NULL if the clobber should be ignored.\n\ > +\n\ > +The default is to ignore the @code{redzone} clobber.", > + rtx, (), > + NULL) > + > /* Support for named address spaces. */ > #undef HOOK_PREFIX > #define HOOK_PREFIX "TARGET_ADDR_SPACE_" > --- gcc/varasm.cc.jj 2024-11-06 18:53:10.838843765 +0100 > +++ gcc/varasm.cc 2024-11-07 10:55:46.858763724 +0100 > @@ -965,9 +965,11 @@ set_user_assembler_name (tree decl, cons > > /* Decode an `asm' spec for a declaration as a register name. > Return the register number, or -1 if nothing specified, > - or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized, > + or -2 if the ASMSPEC is not `cc' or `memory' or `redzone' and is not > + recognized, > or -3 if ASMSPEC is `cc' and is not recognized, > - or -4 if ASMSPEC is `memory' and is not recognized. > + or -4 if ASMSPEC is `memory' and is not recognized, > + or -5 if ASMSPEC is `redzone' and is not recognized. > Accept an exact spelling or a decimal number. > Prefixes such as % are optional. */ > > @@ -1034,6 +1036,9 @@ decode_reg_name_and_count (const char *a > } > #endif /* ADDITIONAL_REGISTER_NAMES */ > > + if (!strcmp (asmspec, "redzone")) > + return -5; > + > if (!strcmp (asmspec, "memory")) > return -4; > > --- gcc/cfgexpand.cc.jj 2024-11-06 18:53:10.803844259 +0100 > +++ gcc/cfgexpand.cc 2024-11-07 11:00:16.212953571 +0100 > @@ -3205,6 +3205,12 @@ expand_asm_stmt (gasm *stmt) > rtx x = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)); > clobber_rvec.safe_push (x); > } > + else if (j == -5) > + { > + if (targetm.redzone_clobber) > + if (rtx x = targetm.redzone_clobber ()) > + clobber_rvec.safe_push (x); > + } > else > { > /* Otherwise we should have -1 == empty string > --- gcc/config/i386/i386.h.jj 2024-11-06 18:53:10.807844203 +0100 > +++ gcc/config/i386/i386.h 2024-11-07 10:55:46.904763076 +0100 > @@ -2881,6 +2881,9 @@ struct GTY(()) machine_function { > /* True if red zone is used. */ > BOOL_BITFIELD red_zone_used : 1; > > + /* True if inline asm with redzone clobber has been seen. */ > + BOOL_BITFIELD asm_redzone_clobber_seen : 1; > + > /* The largest alignment, in bytes, of stack slot actually used. */ > unsigned int max_used_stack_alignment; > > --- gcc/config/i386/i386.cc.jj 2024-11-06 18:53:10.807844203 +0100 > +++ gcc/config/i386/i386.cc 2024-11-07 10:55:46.947762468 +0100 > @@ -7171,6 +7171,7 @@ ix86_compute_frame_layout (void) > if (ix86_using_red_zone () > && crtl->sp_is_unchanging > && crtl->is_leaf > + && !cfun->machine->asm_redzone_clobber_seen > && !ix86_pc_thunk_call_expanded > && !ix86_current_function_calls_tls_descriptor) > { > @@ -26268,6 +26269,22 @@ ix86_mode_can_transfer_bits (machine_mod > return true; > } > > +/* Implement TARGET_REDZONE_CLOBBER. */ > +static rtx > +ix86_redzone_clobber () > +{ > + cfun->machine->asm_redzone_clobber_seen = true; > + if (ix86_using_red_zone ()) > + { > + rtx base = plus_constant (Pmode, stack_pointer_rtx, > + GEN_INT (-RED_ZONE_SIZE)); > + rtx mem = gen_rtx_MEM (BLKmode, base); > + set_mem_size (mem, RED_ZONE_SIZE); > + return mem; > + } > + return NULL_RTX; > +} > + > /* Target-specific selftests. */ > > #if CHECKING_P > @@ -27121,6 +27138,9 @@ ix86_libgcc_floating_mode_supported_p > #undef TARGET_MODE_CAN_TRANSFER_BITS > #define TARGET_MODE_CAN_TRANSFER_BITS ix86_mode_can_transfer_bits > > +#undef TARGET_REDZONE_CLOBBER > +#define TARGET_REDZONE_CLOBBER ix86_redzone_clobber > + > static bool > ix86_libc_has_fast_function (int fcode ATTRIBUTE_UNUSED) > { > --- gcc/doc/extend.texi.jj 2024-11-06 18:53:10.826843934 +0100 > +++ gcc/doc/extend.texi 2024-11-07 10:57:07.550622297 +0100 > @@ -11827,7 +11827,7 @@ asm volatile ("movc3 %0, %1, %2" > : "r0", "r1", "r2", "r3", "r4", "r5", "memory"); > @end example > > -Also, there are two special clobber arguments: > +Also, there are three special clobber arguments: > > @table @code > @item "cc" > @@ -11855,6 +11855,18 @@ Note that this clobber does not prevent > speculative reads past the @code{asm} statement. To prevent that, you need > processor-specific fence instructions. > > +@item "redzone" > +The @code{"redzone"} clobber tells the compiler that the assembly code > +may write to the stack red zone, area below the stack pointer which on > +some architectures in some calling conventions is guaranteed not to be > +changed by signal handlers, interrupts or exceptions and so the compiler > +can store there temporaries in leaf functions. On targets which have > +no concept of the stack red zone, the clobber is ignored. > +It should be used e.g.@: in case the assembly code uses call instructions > +or pushes something to the stack without taking the red zone into account > +by subtracting red zone size from the stack pointer first and restoring > +it afterwards. > + > @end table > > Flushing registers to memory has performance implications and may be > --- gcc/doc/tm.texi.in.jj 2024-11-06 18:53:10.833843835 +0100 > +++ gcc/doc/tm.texi.in 2024-11-07 10:55:46.998761746 +0100 > @@ -3464,6 +3464,8 @@ stack. > > @hook TARGET_MODE_CAN_TRANSFER_BITS > > +@hook TARGET_REDZONE_CLOBBER > + > @hook TARGET_TRANSLATE_MODE_ATTRIBUTE > > @hook TARGET_SCALAR_MODE_SUPPORTED_P > --- gcc/doc/tm.texi.jj 2024-11-06 18:53:10.831843863 +0100 > +++ gcc/doc/tm.texi 2024-11-07 10:55:47.008761605 +0100 > @@ -4563,6 +4563,14 @@ The default is to assume modes with the > to be used. > @end deftypefn > > +@deftypefn {Target Hook} rtx TARGET_REDZONE_CLOBBER () > +Define this to return some RTL for the @code{redzone} @code{asm} clobber > +if target has a red zone and wants to support the @code{redzone} clobber > +or return NULL if the clobber should be ignored. > + > +The default is to ignore the @code{redzone} clobber. > +@end deftypefn > + > @deftypefn {Target Hook} machine_mode TARGET_TRANSLATE_MODE_ATTRIBUTE (machine_mode @var{mode}) > Define this hook if during mode attribute processing, the port should > translate machine_mode @var{mode} to another mode. For example, rs6000's > --- gcc/testsuite/gcc.dg/asm-redzone-1.c.jj 2024-11-07 11:07:52.873493855 +0100 > +++ gcc/testsuite/gcc.dg/asm-redzone-1.c 2024-11-07 11:07:45.697595356 +0100 > @@ -0,0 +1,8 @@ > +/* { dg-do compile } */ > +/* { dg-options "" } */ > + > +void > +foo (void) > +{ > + asm ("" : : : "cc", "memory", "redzone"); > +} > --- gcc/testsuite/gcc.target/i386/asm-redzone-1.c.jj 2024-11-07 10:55:47.018761463 +0100 > +++ gcc/testsuite/gcc.target/i386/asm-redzone-1.c 2024-11-07 10:55:47.018761463 +0100 > @@ -0,0 +1,38 @@ > +/* { dg-do run { target lp64 } } */ > +/* { dg-options "-O2" } */ > + > +__attribute__((noipa)) int > +foo (void) > +{ > + int a = 1; > + int b = 2; > + int c = 3; > + int d = 4; > + int e = 5; > + int f = 6; > + int g = 7; > + int h = 8; > + int i = 9; > + int j = 10; > + int k = 11; > + int l = 12; > + int m = 13; > + int n = 14; > + asm volatile ("" : "+g" (a), "+g" (b), "+g" (c), "+g" (d), "+g" (e)); > + asm volatile ("" : "+g" (f), "+g" (g), "+g" (h), "+g" (i), "+g" (j)); > + asm volatile ("" : "+g" (k), "+g" (l), "+g" (m), "+g" (n)); > + asm volatile ("{pushq %%rax; pushq %%rax; popq %%rax; popq %%rax" > + "|push rax;push rax;pop rax;pop rax}" > + : : : "ax", "si", "di", "r10", "r11", "redzone"); > + asm volatile ("" : "+g" (a), "+g" (b), "+g" (c), "+g" (d), "+g" (e)); > + asm volatile ("" : "+g" (f), "+g" (g), "+g" (h), "+g" (i), "+g" (j)); > + asm volatile ("" : "+g" (k), "+g" (l), "+g" (m), "+g" (n)); > + return a + b + c + d + e + f + g + h + i + j + k + l + m + n; > +} > + > +int > +main () > +{ > + if (foo () != 105) > + __builtin_abort (); > +} > > > Jakub >
--- gcc/target.def.jj 2024-11-06 18:53:10.836843793 +0100 +++ gcc/target.def 2024-11-07 10:57:58.697898800 +0100 @@ -3376,6 +3376,16 @@ to be used.", bool, (machine_mode mode), NULL) +DEFHOOK +(redzone_clobber, + "Define this to return some RTL for the @code{redzone} @code{asm} clobber\n\ +if target has a red zone and wants to support the @code{redzone} clobber\n\ +or return NULL if the clobber should be ignored.\n\ +\n\ +The default is to ignore the @code{redzone} clobber.", + rtx, (), + NULL) + /* Support for named address spaces. */ #undef HOOK_PREFIX #define HOOK_PREFIX "TARGET_ADDR_SPACE_" --- gcc/varasm.cc.jj 2024-11-06 18:53:10.838843765 +0100 +++ gcc/varasm.cc 2024-11-07 10:55:46.858763724 +0100 @@ -965,9 +965,11 @@ set_user_assembler_name (tree decl, cons /* Decode an `asm' spec for a declaration as a register name. Return the register number, or -1 if nothing specified, - or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized, + or -2 if the ASMSPEC is not `cc' or `memory' or `redzone' and is not + recognized, or -3 if ASMSPEC is `cc' and is not recognized, - or -4 if ASMSPEC is `memory' and is not recognized. + or -4 if ASMSPEC is `memory' and is not recognized, + or -5 if ASMSPEC is `redzone' and is not recognized. Accept an exact spelling or a decimal number. Prefixes such as % are optional. */ @@ -1034,6 +1036,9 @@ decode_reg_name_and_count (const char *a } #endif /* ADDITIONAL_REGISTER_NAMES */ + if (!strcmp (asmspec, "redzone")) + return -5; + if (!strcmp (asmspec, "memory")) return -4; --- gcc/cfgexpand.cc.jj 2024-11-06 18:53:10.803844259 +0100 +++ gcc/cfgexpand.cc 2024-11-07 11:00:16.212953571 +0100 @@ -3205,6 +3205,12 @@ expand_asm_stmt (gasm *stmt) rtx x = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)); clobber_rvec.safe_push (x); } + else if (j == -5) + { + if (targetm.redzone_clobber) + if (rtx x = targetm.redzone_clobber ()) + clobber_rvec.safe_push (x); + } else { /* Otherwise we should have -1 == empty string --- gcc/config/i386/i386.h.jj 2024-11-06 18:53:10.807844203 +0100 +++ gcc/config/i386/i386.h 2024-11-07 10:55:46.904763076 +0100 @@ -2881,6 +2881,9 @@ struct GTY(()) machine_function { /* True if red zone is used. */ BOOL_BITFIELD red_zone_used : 1; + /* True if inline asm with redzone clobber has been seen. */ + BOOL_BITFIELD asm_redzone_clobber_seen : 1; + /* The largest alignment, in bytes, of stack slot actually used. */ unsigned int max_used_stack_alignment; --- gcc/config/i386/i386.cc.jj 2024-11-06 18:53:10.807844203 +0100 +++ gcc/config/i386/i386.cc 2024-11-07 10:55:46.947762468 +0100 @@ -7171,6 +7171,7 @@ ix86_compute_frame_layout (void) if (ix86_using_red_zone () && crtl->sp_is_unchanging && crtl->is_leaf + && !cfun->machine->asm_redzone_clobber_seen && !ix86_pc_thunk_call_expanded && !ix86_current_function_calls_tls_descriptor) { @@ -26268,6 +26269,22 @@ ix86_mode_can_transfer_bits (machine_mod return true; } +/* Implement TARGET_REDZONE_CLOBBER. */ +static rtx +ix86_redzone_clobber () +{ + cfun->machine->asm_redzone_clobber_seen = true; + if (ix86_using_red_zone ()) + { + rtx base = plus_constant (Pmode, stack_pointer_rtx, + GEN_INT (-RED_ZONE_SIZE)); + rtx mem = gen_rtx_MEM (BLKmode, base); + set_mem_size (mem, RED_ZONE_SIZE); + return mem; + } + return NULL_RTX; +} + /* Target-specific selftests. */ #if CHECKING_P @@ -27121,6 +27138,9 @@ ix86_libgcc_floating_mode_supported_p #undef TARGET_MODE_CAN_TRANSFER_BITS #define TARGET_MODE_CAN_TRANSFER_BITS ix86_mode_can_transfer_bits +#undef TARGET_REDZONE_CLOBBER +#define TARGET_REDZONE_CLOBBER ix86_redzone_clobber + static bool ix86_libc_has_fast_function (int fcode ATTRIBUTE_UNUSED) { --- gcc/doc/extend.texi.jj 2024-11-06 18:53:10.826843934 +0100 +++ gcc/doc/extend.texi 2024-11-07 10:57:07.550622297 +0100 @@ -11827,7 +11827,7 @@ asm volatile ("movc3 %0, %1, %2" : "r0", "r1", "r2", "r3", "r4", "r5", "memory"); @end example -Also, there are two special clobber arguments: +Also, there are three special clobber arguments: @table @code @item "cc" @@ -11855,6 +11855,18 @@ Note that this clobber does not prevent speculative reads past the @code{asm} statement. To prevent that, you need processor-specific fence instructions. +@item "redzone" +The @code{"redzone"} clobber tells the compiler that the assembly code +may write to the stack red zone, area below the stack pointer which on +some architectures in some calling conventions is guaranteed not to be +changed by signal handlers, interrupts or exceptions and so the compiler +can store there temporaries in leaf functions. On targets which have +no concept of the stack red zone, the clobber is ignored. +It should be used e.g.@: in case the assembly code uses call instructions +or pushes something to the stack without taking the red zone into account +by subtracting red zone size from the stack pointer first and restoring +it afterwards. + @end table Flushing registers to memory has performance implications and may be --- gcc/doc/tm.texi.in.jj 2024-11-06 18:53:10.833843835 +0100 +++ gcc/doc/tm.texi.in 2024-11-07 10:55:46.998761746 +0100 @@ -3464,6 +3464,8 @@ stack. @hook TARGET_MODE_CAN_TRANSFER_BITS +@hook TARGET_REDZONE_CLOBBER + @hook TARGET_TRANSLATE_MODE_ATTRIBUTE @hook TARGET_SCALAR_MODE_SUPPORTED_P --- gcc/doc/tm.texi.jj 2024-11-06 18:53:10.831843863 +0100 +++ gcc/doc/tm.texi 2024-11-07 10:55:47.008761605 +0100 @@ -4563,6 +4563,14 @@ The default is to assume modes with the to be used. @end deftypefn +@deftypefn {Target Hook} rtx TARGET_REDZONE_CLOBBER () +Define this to return some RTL for the @code{redzone} @code{asm} clobber +if target has a red zone and wants to support the @code{redzone} clobber +or return NULL if the clobber should be ignored. + +The default is to ignore the @code{redzone} clobber. +@end deftypefn + @deftypefn {Target Hook} machine_mode TARGET_TRANSLATE_MODE_ATTRIBUTE (machine_mode @var{mode}) Define this hook if during mode attribute processing, the port should translate machine_mode @var{mode} to another mode. For example, rs6000's --- gcc/testsuite/gcc.dg/asm-redzone-1.c.jj 2024-11-07 11:07:52.873493855 +0100 +++ gcc/testsuite/gcc.dg/asm-redzone-1.c 2024-11-07 11:07:45.697595356 +0100 @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ + +void +foo (void) +{ + asm ("" : : : "cc", "memory", "redzone"); +} --- gcc/testsuite/gcc.target/i386/asm-redzone-1.c.jj 2024-11-07 10:55:47.018761463 +0100 +++ gcc/testsuite/gcc.target/i386/asm-redzone-1.c 2024-11-07 10:55:47.018761463 +0100 @@ -0,0 +1,38 @@ +/* { dg-do run { target lp64 } } */ +/* { dg-options "-O2" } */ + +__attribute__((noipa)) int +foo (void) +{ + int a = 1; + int b = 2; + int c = 3; + int d = 4; + int e = 5; + int f = 6; + int g = 7; + int h = 8; + int i = 9; + int j = 10; + int k = 11; + int l = 12; + int m = 13; + int n = 14; + asm volatile ("" : "+g" (a), "+g" (b), "+g" (c), "+g" (d), "+g" (e)); + asm volatile ("" : "+g" (f), "+g" (g), "+g" (h), "+g" (i), "+g" (j)); + asm volatile ("" : "+g" (k), "+g" (l), "+g" (m), "+g" (n)); + asm volatile ("{pushq %%rax; pushq %%rax; popq %%rax; popq %%rax" + "|push rax;push rax;pop rax;pop rax}" + : : : "ax", "si", "di", "r10", "r11", "redzone"); + asm volatile ("" : "+g" (a), "+g" (b), "+g" (c), "+g" (d), "+g" (e)); + asm volatile ("" : "+g" (f), "+g" (g), "+g" (h), "+g" (i), "+g" (j)); + asm volatile ("" : "+g" (k), "+g" (l), "+g" (m), "+g" (n)); + return a + b + c + d + e + f + g + h + i + j + k + l + m + n; +} + +int +main () +{ + if (foo () != 105) + __builtin_abort (); +}