]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Fix .cfi_offset directive when push/pop in zcmp
authorLino Hsing-Yu Peng <linopeng@andestech.com>
Thu, 20 Feb 2025 09:09:22 +0000 (17:09 +0800)
committerKito Cheng <kito.cheng@sifive.com>
Mon, 24 Feb 2025 08:04:32 +0000 (16:04 +0800)
The incorrect cfi directive info breaks stack unwind in try/catch/cxa.

Before patch:
  cm.push {ra, s0-s2}, -16
  .cfi_offset 1, -12
  .cfi_offset 8, -8
  .cfi_offset 18, -4

After patch:
  cm.push {ra, s0-s2}, -16
  .cfi_offset 1, -16
  .cfi_offset 8, -12
  .cfi_offset 9, -8
  .cfi_offset 18, -4

gcc/ChangeLog:

* config/riscv/riscv.cc: Set multi push regs bits.

gcc/testsuite/ChangeLog:
* gcc.target/riscv/zcmp_push_gpr.c: New test.

gcc/config/riscv/riscv.cc
gcc/testsuite/gcc.target/riscv/zcmp_push_gpr.c [new file with mode: 0644]

index 9bf7713139f67f03642816272105eb3901628f54..89aa25d5da92b73028cadfb990007b1414905766 100644 (file)
@@ -728,6 +728,12 @@ static const unsigned gpr_save_reg_order[] = {
   S10_REGNUM, S11_REGNUM
 };
 
+/* Order for the (ra, s0-sx) of zcmp_save.  */
+static const unsigned zcmp_save_reg_order[]
+  = {RETURN_ADDR_REGNUM, S0_REGNUM,  S1_REGNUM,         S2_REGNUM,     S3_REGNUM,
+     S4_REGNUM,                 S5_REGNUM,  S6_REGNUM,  S7_REGNUM,     S8_REGNUM,
+     S9_REGNUM,                 S10_REGNUM, S11_REGNUM, INVALID_REGNUM};
+
 /* A table describing all the processors GCC knows about.  */
 static const struct riscv_tune_info riscv_tune_info_table[] = {
 #define RISCV_TUNE(TUNE_NAME, PIPELINE_MODEL, TUNE_INFO)       \
@@ -8364,8 +8370,11 @@ riscv_adjust_multi_push_cfi_prologue (int saved_size)
   int offset;
   int saved_cnt = 0;
 
-  if (mask & S10_MASK)
-    mask |= S11_MASK;
+  unsigned int num_multi_push = riscv_multi_push_regs_count (mask);
+  for (unsigned int i = 0; i < num_multi_push; i++) {
+    gcc_assert(zcmp_save_reg_order[i] != INVALID_REGNUM);
+    mask |= 1 << (zcmp_save_reg_order[i] - GP_REG_FIRST);
+  }
 
   for (int regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
     if (BITSET_P (mask & MULTI_PUSH_GPR_MASK, regno - GP_REG_FIRST))
diff --git a/gcc/testsuite/gcc.target/riscv/zcmp_push_gpr.c b/gcc/testsuite/gcc.target/riscv/zcmp_push_gpr.c
new file mode 100644 (file)
index 0000000..acebafa
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafd_zicsr_zifencei_zca_zcmp -mabi=ilp32d -Os -g" } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
+
+int
+zcmp_push ()
+{
+  __asm__ __volatile__("" ::: "ra", "s0", "s2");
+  return 0;
+}
+
+/* { dg-final { scan-assembler ".cfi_offset 1, -16\n\t.cfi_offset 8, -12\n\t.cfi_offset 9, -8\n\t.cfi_offset 18, -4\n\t.cfi_def_cfa_offset 16" } } */