https://gcc.gnu.org/g:37c98fdeac7ae2f9649d49e0cfa2631c84a329da
commit r15-5748-g37c98fdeac7ae2f9649d49e0cfa2631c84a329da Author: Jakub Jelinek <ja...@redhat.com> Date: Thu Nov 28 11:42:11 2024 +0100 inline-asm, i386: Add "redzone" clobber support The following patch adds a "redzone" clobber (recognized everywhere, even on on targets which don't do anything with it), with which one can mark the rare case where inline asm pushes something on the stack or uses call instruction without taking red zone into account (i.e. addq $-128, %rsp; and addq $128, %rsp around that). 2024-11-28 Jakub Jelinek <ja...@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. Diff: --- gcc/cfgexpand.cc | 6 +++++ gcc/config/i386/i386.cc | 20 ++++++++++++++ gcc/config/i386/i386.h | 3 +++ gcc/doc/extend.texi | 14 +++++++++- gcc/doc/tm.texi | 8 ++++++ gcc/doc/tm.texi.in | 2 ++ gcc/target.def | 10 +++++++ gcc/testsuite/gcc.dg/asm-redzone-1.c | 8 ++++++ gcc/testsuite/gcc.target/i386/asm-redzone-1.c | 38 +++++++++++++++++++++++++++ gcc/varasm.cc | 9 +++++-- 10 files changed, 115 insertions(+), 3 deletions(-) diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc index 2a984758bc7b..58d68ec1caa5 100644 --- a/gcc/cfgexpand.cc +++ b/gcc/cfgexpand.cc @@ -3209,6 +3209,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 diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index fda2112e4d60..0beeb514cf95 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -7170,6 +7170,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) { @@ -26419,6 +26420,22 @@ ix86_mode_can_transfer_bits (machine_mode mode) 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 @@ -27272,6 +27289,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) { diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 65227e7fd413..85c54c35c5c9 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2895,6 +2895,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; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index df34cd1da309..2fc513efdb58 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -11800,7 +11800,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" @@ -11828,6 +11828,18 @@ Note that this clobber does not prevent the @emph{processor} from doing 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 diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 31b8c29dd446..05f85f83858f 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -4563,6 +4563,14 @@ The default is to assume modes with the same precision as size are fine 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 diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 88139757191e..22d453ca9549 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -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 diff --git a/gcc/target.def b/gcc/target.def index 269787023e45..cda3d4f4b8ff 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -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_" diff --git a/gcc/testsuite/gcc.dg/asm-redzone-1.c b/gcc/testsuite/gcc.dg/asm-redzone-1.c new file mode 100644 index 000000000000..eea7d3a79621 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asm-redzone-1.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ + +void +foo (void) +{ + asm ("" : : : "cc", "memory", "redzone"); +} diff --git a/gcc/testsuite/gcc.target/i386/asm-redzone-1.c b/gcc/testsuite/gcc.target/i386/asm-redzone-1.c new file mode 100644 index 000000000000..2a0514bf7f4f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/asm-redzone-1.c @@ -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 (); +} diff --git a/gcc/varasm.cc b/gcc/varasm.cc index dd67dd441c0f..be11123180cd 100644 --- a/gcc/varasm.cc +++ b/gcc/varasm.cc @@ -968,9 +968,11 @@ set_user_assembler_name (tree decl, const char *name) /* 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. */ @@ -1037,6 +1039,9 @@ decode_reg_name_and_count (const char *asmspec, int *pnregs) } #endif /* ADDITIONAL_REGISTER_NAMES */ + if (!strcmp (asmspec, "redzone")) + return -5; + if (!strcmp (asmspec, "memory")) return -4;