]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
inline-asm, i386: Add "redzone" clobber support
authorJakub Jelinek <jakub@redhat.com>
Thu, 28 Nov 2024 10:42:11 +0000 (11:42 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 28 Nov 2024 10:42:11 +0000 (11:42 +0100)
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  <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.

gcc/cfgexpand.cc
gcc/config/i386/i386.cc
gcc/config/i386/i386.h
gcc/doc/extend.texi
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/target.def
gcc/testsuite/gcc.dg/asm-redzone-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/asm-redzone-1.c [new file with mode: 0644]
gcc/varasm.cc

index 2a984758bc7b7e4c1300044921a8acebfff4ac56..58d68ec1caa543ea518393f727b8cf35172d8ac7 100644 (file)
@@ -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
index fda2112e4d60080e6f3dbeb9796d986e54860d3c..0beeb514cf9538dec831678cea1f7e1ea7a26bfa 100644 (file)
@@ -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)
 {
index 65227e7fd4132d31478ffae04194e7e2489304a2..85c54c35c5c9ed2160c70a8a3f83da70b3c77cd6 100644 (file)
@@ -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;
 
index df34cd1da309bf9a29dd7c5226cb899e01093407..2fc513efdb585d823a15d7b745477fc71ecf5237 100644 (file)
@@ -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
index 31b8c29dd4460a0f25054dcb95e3b473cf5f8a32..05f85f83858f34a6b2f6a19f05edc6bb66415d72 100644 (file)
@@ -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
index 88139757191eb0e769a712df45d031be07b67dea..22d453ca9549c6a8459cdb0e8bbb455350434104 100644 (file)
@@ -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
index 269787023e45f48984d20f6052e14740dee5adee..cda3d4f4b8ff4209885410ec324320d97a07d6d0 100644 (file)
@@ -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 (file)
index 0000000..eea7d3a
--- /dev/null
@@ -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 (file)
index 0000000..2a0514b
--- /dev/null
@@ -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 ();
+}
index dd67dd441c0f5ee103eb7de47c8d0a4da88bfc57..be11123180cdf31eb3263ab4505568434ff1f21c 100644 (file)
@@ -968,9 +968,11 @@ set_user_assembler_name (tree decl, const char *name)
 \f
 /* 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;