[gcc r10-9033] PR target/97682 - Fix to reuse t1 register between call address and epilogue.

Kito Cheng kito@gcc.gnu.org
Tue Nov 17 03:53:14 GMT 2020


https://gcc.gnu.org/g:4ba2f918583089172ac899c8eecaddef0d47cd85

commit r10-9033-g4ba2f918583089172ac899c8eecaddef0d47cd85
Author: Monk Chiang <monk.chiang@sifive.com>
Date:   Fri Nov 13 19:35:11 2020 -0800

    PR target/97682 - Fix to reuse t1 register between call address and epilogue.
    
      - When expanding the call pattern, choose t1 register be a jump register.
        Epilogue also uses a t1 register to adjust Stack point. The call pattern
        and epilogue will initial t1 twice, if both are generated in the same
        function. The call pattern will emit 'la t1,symbol' and 'jalr t1'instructions.
        Epilogue also emits 'li t1,4096' and 'addi sp,sp,t1' instructions.
        But li and addi instructions will be placed between la and jalr instructions.
        The la instruction will be removed by some optimizations,
        because t1 register define twice, the first define instruction look
        likes duplicate.
    
      - To resolve this issue, Prologue and Epilogue use the t0 register
        be a temporary register, the call pattern use the t1 register be
        a temporary register.
    
    gcc/
    2020-11-13  Monk Chiang  <monk.chiang@sifive.com>
    
            PR target/97682
            * config/riscv/riscv.h (RISCV_PROLOGUE_TEMP_REGNUM): Change register
            to t0.
            (RISCV_CALL_ADDRESS_TEMP_REGNUM): New Marco, define t1 register.
            (RISCV_CALL_ADDRESS_TEMP): Use it for call instructions.
            * config/riscv/riscv.c (riscv_legitimize_call_address): Use
            RISCV_CALL_ADDRESS_TEMP.
            (riscv_compute_frame_info): Change temporary register to t0 form t1.
            (riscv_trampoline_init): Adjust comment.
    
    gcc/testsuite/
    2020-11-13  Monk Chiang  <monk.chiang@sifive.com>
    
            PR target/97682
            * g++.target/riscv/pr97682.C: New test.
            * gcc.target/riscv/interrupt-3.c: Check register for t0.
            * gcc.target/riscv/interrupt-4.c: Likewise.
    
    (cherry picked from commit 207de83922bda8707aa33d6a2185e691116377e7)

Diff:
---
 gcc/config/riscv/riscv.c                     |  23 ++--
 gcc/config/riscv/riscv.h                     |   6 +-
 gcc/testsuite/g++.target/riscv/pr97682.C     | 160 +++++++++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/interrupt-3.c |   4 +-
 gcc/testsuite/gcc.target/riscv/interrupt-4.c |   4 +-
 5 files changed, 181 insertions(+), 16 deletions(-)

diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index 86785d0f351..2d0bfa3c3ff 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -3028,7 +3028,7 @@ riscv_legitimize_call_address (rtx addr)
 {
   if (!call_insn_operand (addr, VOIDmode))
     {
-      rtx reg = RISCV_PROLOGUE_TEMP (Pmode);
+      rtx reg = RISCV_CALL_ADDRESS_TEMP (Pmode);
       riscv_emit_move (reg, addr);
       return reg;
     }
@@ -3625,18 +3625,18 @@ riscv_compute_frame_info (void)
 {
   struct riscv_frame_info *frame;
   HOST_WIDE_INT offset;
-  bool interrupt_save_t1 = false;
+  bool interrupt_save_prologue_temp = false;
   unsigned int regno, i, num_x_saved = 0, num_f_saved = 0;
 
   frame = &cfun->machine->frame;
 
   /* In an interrupt function, if we have a large frame, then we need to
-     save/restore t1.  We check for this before clearing the frame struct.  */
+     save/restore t0.  We check for this before clearing the frame struct.  */
   if (cfun->machine->interrupt_handler_p)
     {
       HOST_WIDE_INT step1 = riscv_first_stack_step (frame);
       if (! SMALL_OPERAND (frame->total_size - step1))
-	interrupt_save_t1 = true;
+	interrupt_save_prologue_temp = true;
     }
 
   memset (frame, 0, sizeof (*frame));
@@ -3646,7 +3646,8 @@ riscv_compute_frame_info (void)
       /* Find out which GPRs we need to save.  */
       for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
 	if (riscv_save_reg_p (regno)
-	    || (interrupt_save_t1 && (regno == T1_REGNUM)))
+	    || (interrupt_save_prologue_temp
+		&& (regno == RISCV_PROLOGUE_TEMP_REGNUM)))
 	  frame->mask |= 1 << (regno - GP_REG_FIRST), num_x_saved++;
 
       /* If this function calls eh_return, we must also save and restore the
@@ -4770,9 +4771,9 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
 
       rtx target_function = force_reg (Pmode, XEXP (DECL_RTL (fndecl), 0));
       /* lui     t2, hi(chain)
-	 lui     t1, hi(func)
+	 lui     t0, hi(func)
 	 addi    t2, t2, lo(chain)
-	 jr      r1, lo(func)
+	 jr      t0, lo(func)
       */
       unsigned HOST_WIDE_INT lui_hi_chain_code, lui_hi_func_code;
       unsigned HOST_WIDE_INT lo_chain_code, lo_func_code;
@@ -4797,7 +4798,7 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
       mem = adjust_address (m_tramp, SImode, 0);
       riscv_emit_move (mem, lui_hi_chain);
 
-      /* Gen lui t1, hi(func).  */
+      /* Gen lui t0, hi(func).  */
       rtx hi_func = riscv_force_binary (SImode, PLUS, target_function,
 					fixup_value);
       hi_func = riscv_force_binary (SImode, AND, hi_func,
@@ -4824,7 +4825,7 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
       mem = adjust_address (m_tramp, SImode, 2 * GET_MODE_SIZE (SImode));
       riscv_emit_move (mem, addi_lo_chain);
 
-      /* Gen jr r1, lo(func).  */
+      /* Gen jr t0, lo(func).  */
       rtx lo_func = riscv_force_binary (SImode, AND, target_function,
 					imm12_mask);
       lo_func = riscv_force_binary (SImode, ASHIFT, lo_func, GEN_INT (20));
@@ -4843,9 +4844,9 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
       target_function_offset = static_chain_offset + GET_MODE_SIZE (ptr_mode);
 
       /* auipc   t2, 0
-	 l[wd]   t1, target_function_offset(t2)
+	 l[wd]   t0, target_function_offset(t2)
 	 l[wd]   t2, static_chain_offset(t2)
-	 jr      t1
+	 jr      t0
       */
       trampoline[0] = OPCODE_AUIPC | (STATIC_CHAIN_REGNUM << SHIFT_RD);
       trampoline[1] = (Pmode == DImode ? OPCODE_LD : OPCODE_LW)
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 567c23380fe..765d6cf9689 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -322,9 +322,13 @@ along with GCC; see the file COPYING3.  If not see
    The epilogue temporary mustn't conflict with the return registers,
    the frame pointer, the EH stack adjustment, or the EH data registers. */
 
-#define RISCV_PROLOGUE_TEMP_REGNUM (GP_TEMP_FIRST + 1)
+#define RISCV_PROLOGUE_TEMP_REGNUM (GP_TEMP_FIRST)
 #define RISCV_PROLOGUE_TEMP(MODE) gen_rtx_REG (MODE, RISCV_PROLOGUE_TEMP_REGNUM)
 
+#define RISCV_CALL_ADDRESS_TEMP_REGNUM (GP_TEMP_FIRST + 1)
+#define RISCV_CALL_ADDRESS_TEMP(MODE) \
+  gen_rtx_REG (MODE, RISCV_CALL_ADDRESS_TEMP_REGNUM)
+
 #define MCOUNT_NAME "_mcount"
 
 #define NO_PROFILE_COUNTERS 1
diff --git a/gcc/testsuite/g++.target/riscv/pr97682.C b/gcc/testsuite/g++.target/riscv/pr97682.C
new file mode 100644
index 00000000000..03c7a447de5
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/pr97682.C
@@ -0,0 +1,160 @@
+/* PR target/97682 */
+/* { dg-do compile } */
+/* { dg-options "-fPIC -O2 -march=rv64g -mabi=lp64" } */
+
+template <typename ab, int ac> struct g { ab b[ac]; };
+long i, m;
+
+namespace std
+{
+  template <typename c> struct t
+  {
+    int a;
+    c h;
+  };
+
+  struct ad
+  {
+    enum { j };
+  };
+
+  template <typename k> k l(k);
+  struct al {};
+  template <typename k> k aa(k);
+
+  struct v
+  {
+    template <typename n, typename q> static q o(n, n, q);
+  };
+
+  template <int, typename n, typename q> void p(n z, n ao, q ap)
+  {
+    v::o(z, ao, ap);
+  }
+
+  template <int ae, typename n, typename q> void r(n z, n ao, q ap)
+  {
+    p<ae>(z, ao, ap);
+  }
+
+  template <int ae, typename n, typename q> void af(n z, n ao, q)
+  {
+    r<ae>(aa(z), aa(ao), 0);
+  }
+
+  template <typename n, typename q> void ag(n z, n ao, q ap)
+  {
+    af<ad::j>(l(z), l(ao), ap);
+  }
+
+  template <typename> class allocator;
+  template <typename ah, typename ai, typename aj> void ak(ah, ai, aj);
+
+  template <typename s> class aq
+  {
+    template <typename am> struct ar { using f = am *; };
+  public:
+    using an = typename ar<s>::f;
+  };
+
+  template <typename s> class as
+  {
+  public:
+    using an = typename aq<s>::an;
+    an operator->();
+  };
+
+  struct ay
+  {
+    int at();
+  };
+
+  template <typename s, typename = allocator<s>> class vector : ay
+  {
+  public:
+    long au();
+    long x;
+    void av() { _M_default_append(x); }
+    void _M_default_append(unsigned long);
+    void aw();
+    long ax(int);
+  };
+
+  template <typename s, typename y>
+  void vector<s, y>::_M_default_append(unsigned long z)
+  {
+    long az = au();
+    int w = at(), bc = at();
+    i = ax(w);
+    m = ax(w);
+    if (i || m)
+      aw();
+    ak(az, z, bc);
+  }
+}
+
+namespace llvm
+{
+  template <int bd> class bh
+  {
+    enum { bf = bd } * bg[bf];
+  };
+
+  template <class> class bi;
+
+  class bm
+  {
+    using bj = bi<int>;
+    std::as<bj> bk;
+    void bl();
+  };
+
+  template <class> struct bn;
+
+  class br
+  {
+    bh<8> bo;
+  };
+
+  class ca
+  {
+    int *d;
+    int e;
+  };
+
+  template <class bp> class bv : std::al, br
+  {
+    g<std::t<ca>, 8> b;
+  };
+
+  template <class ab> bv<ab> bt(ab);
+
+  class BlockFrequencyInfoImplBase
+  {
+  public:
+    struct FrequencyData;
+    std::vector<FrequencyData> bu;
+  };
+
+  template <class> struct cb { using bw = int; };
+  template <class bx> class bi : BlockFrequencyInfoImplBase
+  {
+    using bw = typename cb<bx>::bw;
+  public:
+    void bl();
+  };
+
+  template <class bx> void bi<bx>::bl()
+  {
+    const bw *by;
+    bv<const int *> bz;
+    ag(bz, bt(by), 0);
+    bu.av();
+  }
+
+  template <> struct bn<const int *> { using u = ca; };
+  void bm::bl() { bk->bl(); }
+}
+
+/* The t1 register is to initial symbol reference for call instruction.  */
+/* { dg-final { scan-assembler "la\tt1,.*FrequencyData.*_M_default_append.*" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-3.c b/gcc/testsuite/gcc.target/riscv/interrupt-3.c
index bc9e0c14f05..3d1d44df45e 100644
--- a/gcc/testsuite/gcc.target/riscv/interrupt-3.c
+++ b/gcc/testsuite/gcc.target/riscv/interrupt-3.c
@@ -1,4 +1,4 @@
-/* Verify t1 is saved before use.  */
+/* Verify t0 is saved before use.  */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fomit-frame-pointer" } */
 void __attribute__ ((interrupt))
@@ -6,4 +6,4 @@ foo (void)
 {
   char array[4096];
 }
-/* { dg-final { scan-assembler "s\[wd\]\tt1" } } */
+/* { dg-final { scan-assembler "s\[wd\]\tt0" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-4.c b/gcc/testsuite/gcc.target/riscv/interrupt-4.c
index b6fdd19095c..658aa176e77 100644
--- a/gcc/testsuite/gcc.target/riscv/interrupt-4.c
+++ b/gcc/testsuite/gcc.target/riscv/interrupt-4.c
@@ -1,4 +1,4 @@
-/* Verify t1 is saved before use.  */
+/* Verify t0 is saved before use.  */
 /* { dg-do compile } */
 /* { dg-options "-O0 -fomit-frame-pointer" } */
 void __attribute__ ((interrupt))
@@ -15,4 +15,4 @@ foo2 (void)
   COUNTER++;
 #endif
 }
-/* { dg-final { scan-assembler "s\[wd\]\tt1" } } */
+/* { dg-final { scan-assembler "s\[wd\]\tt0" } } */


More information about the Gcc-cvs mailing list