DRAP register is used to restore stack pointer in epilogue for stack realignment. In no-callee-saved and preserve_none functions, although DRAP register isn't preserved, it must be unchanged between prologue and epilogue so that stack pointer can be restored. In no-callee-saved and preserve_none functions, mark BX_REG as fixed and use it for DRAP register.
NB: r12-r15 aren't made available as the local general purpose registers since it causes: FAIL: gcc.target/i386/preserve-none-1.c scan-assembler-not movq FAIL: gcc.target/i386/preserve-none-30a.c check-function-bodies entry FAIL: gcc.target/i386/preserve-none-30b.c check-function-bodies entry which have the same cause as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124798 gcc/ PR target/120870 * config/i386/i386.cc (X86_NO_CALLEE_DRAP_REG): New. (ix86_conditional_register_usage): Mark X86_NO_CALLEE_DRAP_REG as fixed. (find_drap_reg): Return X86_PRESERVE_NONE_DRAP_REG for no-callee-saved and preserve_none functions gcc/testsuite/ PR target/120870 * gcc.target/i386/pr120870-1.c: New test. * gcc.target/i386/pr120870-2.c: Likewise. H.J.
From f7bc8a980a9b08d5659f8e6204fefb6166f30685 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" <[email protected]> Date: Sun, 10 May 2026 18:36:26 +0800 Subject: [PATCH] x86: Use BX_REG for DRAP register in preserve_none function DRAP register is used to restore stack pointer in epilogue for stack realignment. In no-callee-saved and preserve_none functions, although DRAP register isn't preserved, it must be unchanged between prologue and epilogue so that stack pointer can be restored. In no-callee-saved and preserve_none functions, mark BX_REG as fixed and use it for DRAP register. NB: r12-r15 aren't made available as the local general purpose registers since it causes: FAIL: gcc.target/i386/preserve-none-1.c scan-assembler-not movq FAIL: gcc.target/i386/preserve-none-30a.c check-function-bodies entry FAIL: gcc.target/i386/preserve-none-30b.c check-function-bodies entry which have the same cause as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124798 gcc/ PR target/120870 * config/i386/i386.cc (X86_NO_CALLEE_DRAP_REG): New. (ix86_conditional_register_usage): Mark X86_NO_CALLEE_DRAP_REG as fixed. (find_drap_reg): Return X86_PRESERVE_NONE_DRAP_REG for no-callee-saved and preserve_none functions gcc/testsuite/ PR target/120870 * gcc.target/i386/pr120870-1.c: New test. * gcc.target/i386/pr120870-2.c: Likewise. Signed-off-by: H.J. Lu <[email protected]> --- gcc/config/i386/i386.cc | 71 +++++++++++++++++++--- gcc/testsuite/gcc.target/i386/pr120870-1.c | 35 +++++++++++ gcc/testsuite/gcc.target/i386/pr120870-2.c | 6 ++ 3 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr120870-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120870-2.c diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 9aecd51119f..9541496afb1 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -496,6 +496,14 @@ ix86_profile_before_prologue (void) return flag_fentry != 0; } +/* In no-callee-saved and preserve_none functions, reserve BX_REG for + DRAP register. + + FIXME: Why is BX_REG the only working DRAP register in preserve_none + functions? Is is because only BX_REG is 0 in CALL_USED_REGISTERS + which has some permanent impacts on register allocator. */ +#define X86_NO_CALLEE_DRAP_REG BX_REG + /* Update register usage after having seen the compiler flags. */ static void @@ -503,16 +511,54 @@ ix86_conditional_register_usage (void) { int i, c_mask; - /* If there are no caller-saved registers, preserve all registers. - except fixed_regs and registers used for function return value - since aggregate_value_p checks call_used_regs[regno] on return - value. */ - if (cfun - && (cfun->machine->call_saved_registers - == TYPE_NO_CALLER_SAVED_REGISTERS)) - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (!fixed_regs[i] && !ix86_function_value_regno_p (i)) - call_used_regs[i] = 0; + if (cfun) + switch (cfun->machine->call_saved_registers) + { + case TYPE_DEFAULT_CALL_SAVED_REGISTERS: + break; + + case TYPE_NO_CALLER_SAVED_REGISTERS: + /* If there are no caller-saved registers, preserve all + registers. except fixed_regs and registers used for + function return value since aggregate_value_p checks + call_used_regs[regno] on return value. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (!fixed_regs[i] && !ix86_function_value_regno_p (i)) + call_used_regs[i] = 0; + break; + + case TYPE_NO_CALLEE_SAVED_REGISTERS: + case TYPE_PRESERVE_NONE: + /* DRAP register is used to restore stack pointer in epilogue + for stack realignment. Although DRAP register isn't + preserved, it must be unchanged between prologue and + epilogue so that stack pointer can be restored. In + no-callee-saved and preserve_none function, mark BX_REG + as fixed and use it for DRAP register. */ + fixed_regs[X86_NO_CALLEE_DRAP_REG] = 1; + + /* Disabled to avoid + +FAIL: gcc.target/i386/preserve-none-1.c scan-assembler-not movq +FAIL: gcc.target/i386/preserve-none-30a.c check-function-bodies entry +FAIL: gcc.target/i386/preserve-none-30b.c check-function-bodies entry + + which have the same cause as + + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124798 + + */ + if (0 && TARGET_64BIT) + { + /* Make R12_REG, R13_REG, R14_REG, R15_REG available as + the local general purpose registers. */ + call_used_regs[R12_REG] = 1; + call_used_regs[R13_REG] = 1; + call_used_regs[R14_REG] = 1; + call_used_regs[R15_REG] = 1; + } + break; + } /* For 32-bit targets, disable the REX registers. */ if (! TARGET_64BIT) @@ -7940,6 +7986,11 @@ pro_epilogue_adjust_stack (rtx dest, rtx src, rtx offset, static unsigned int find_drap_reg (void) { + if (cfun->machine->call_saved_registers == TYPE_PRESERVE_NONE + || (cfun->machine->call_saved_registers + == TYPE_NO_CALLEE_SAVED_REGISTERS)) + return X86_NO_CALLEE_DRAP_REG; + tree decl = cfun->decl; /* Always use callee-saved register if there are no caller-saved diff --git a/gcc/testsuite/gcc.target/i386/pr120870-1.c b/gcc/testsuite/gcc.target/i386/pr120870-1.c new file mode 100644 index 00000000000..31d38391133 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120870-1.c @@ -0,0 +1,35 @@ +/* { dg-do run } */ +/* { dg-options "-O0 -march=x86-64-v3" } */ + +void +ext (long a, long b, long c, long d, long e, long f, long g) +{ +} + +__attribute__ ((preserve_none)) void +tail (long a, long b) +{ +} + +__attribute__ ((preserve_none)) void +caller (long a, long b, long c, long d, long e, long f, long g) +{ + __attribute__ ((aligned (32))) long x[4]; // for stack alignment + ext (a, b, c, d, e, f, g); + __attribute__ ((musttail)) return tail (a + b, b + c); +} + +__attribute__ ((noipa)) +static void +do_test () +{ + caller (1, 2, 3, 4, 5, 6, 7); +} + +int +main (void) +{ + if (__builtin_cpu_supports ("x86-64-v3")) + do_test (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120870-2.c b/gcc/testsuite/gcc.target/i386/pr120870-2.c new file mode 100644 index 00000000000..7e68718d81a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120870-2.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-O0 -march=x86-64-v3" } */ + +#define preserve_none no_callee_saved_registers + +#include "pr120870-1.c" -- 2.54.0
