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
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)
{
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
#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)
{
/* 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;
: "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"
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
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
@hook TARGET_MODE_CAN_TRANSFER_BITS
+@hook TARGET_REDZONE_CLOBBER
+
@hook TARGET_TRANSLATE_MODE_ATTRIBUTE
@hook TARGET_SCALAR_MODE_SUPPORTED_P
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_"
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void
+foo (void)
+{
+ asm ("" : : : "cc", "memory", "redzone");
+}
--- /dev/null
+/* { 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 ();
+}
\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. */
}
#endif /* ADDITIONAL_REGISTER_NAMES */
+ if (!strcmp (asmspec, "redzone"))
+ return -5;
+
if (!strcmp (asmspec, "memory"))
return -4;