[gcc r14-7116] RISC-V: T-HEAD: Add support for the XTheadInt ISA extension

Christoph Mテシllner cmuellner@gcc.gnu.org
Wed Jan 10 17:55:38 GMT 2024


https://gcc.gnu.org/g:52e809d5cf345ce01fc81be716a57f5b6d5b4545

commit r14-7116-g52e809d5cf345ce01fc81be716a57f5b6d5b4545
Author: Jin Ma <jinma@linux.alibaba.com>
Date:   Fri Nov 17 15:33:25 2023 +0800

    RISC-V: T-HEAD: Add support for the XTheadInt ISA extension
    
    The XTheadInt ISA extension provides the following instructions
    to accelerate interrupt processing:
    * th.ipush
    * th.ipop
    
    Ref:
    https://github.com/T-head-Semi/thead-extension-spec/releases/download/2.3.0/xthead-2023-11-10-2.3.0.pdf
    
    gcc/ChangeLog:
    
            * config/riscv/riscv-protos.h (th_int_get_mask): New prototype.
            (th_int_get_save_adjustment): Likewise.
            (th_int_adjust_cfi_prologue): Likewise.
            * config/riscv/riscv.cc (BITSET_P): Moved away from here.
            (TH_INT_INTERRUPT): New macro.
            (riscv_expand_prologue): Add the processing of XTheadInt.
            (riscv_expand_epilogue): Likewise.
            * config/riscv/riscv.h (BITSET_P): Moved to here.
            * config/riscv/riscv.md: New unspec.
            * config/riscv/thead.cc (th_int_get_mask): New function.
            (th_int_get_save_adjustment): Likewise.
            (th_int_adjust_cfi_prologue): Likewise.
            * config/riscv/thead.md (th_int_push): New pattern.
            (th_int_pop): new pattern.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/xtheadint-push-pop.c: New test.

Diff:
---
 gcc/config/riscv/riscv-protos.h                    |  3 +
 gcc/config/riscv/riscv.cc                          | 61 +++++++++++++++--
 gcc/config/riscv/riscv.h                           |  3 +
 gcc/config/riscv/riscv.md                          |  4 ++
 gcc/config/riscv/thead.cc                          | 77 ++++++++++++++++++++++
 gcc/config/riscv/thead.md                          | 67 +++++++++++++++++++
 .../gcc.target/riscv/xtheadint-push-pop.c          | 36 ++++++++++
 7 files changed, 247 insertions(+), 4 deletions(-)

diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index fc0097acde3..e8c54c5be50 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -726,6 +726,9 @@ extern void th_mempair_prepare_save_restore_operands (rtx[4], bool,
 						      int, HOST_WIDE_INT,
 						      int, HOST_WIDE_INT);
 extern void th_mempair_save_restore_regs (rtx[4], bool, machine_mode);
+extern unsigned int th_int_get_mask (unsigned int);
+extern unsigned int th_int_get_save_adjustment (void);
+extern rtx th_int_adjust_cfi_prologue (unsigned int);
 #ifdef RTX_CODE
 extern const char*
 th_mempair_output_move (rtx[4], bool, machine_mode, RTX_CODE);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 2620e3e7b79..122892b5155 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -95,15 +95,22 @@ along with GCC; see the file COPYING3.  If not see
 #define UNSPEC_ADDRESS_TYPE(X) \
   ((enum riscv_symbol_type) (XINT (X, 1) - UNSPEC_ADDRESS_FIRST))
 
-/* True if bit BIT is set in VALUE.  */
-#define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
-
 /* Extract the backup dynamic frm rtl.  */
 #define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
 
 /* True the mode switching has static frm, or false.  */
 #define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
 
+/* True if we can use the instructions in the XTheadInt extension
+   to handle interrupts, or false.  */
+#define TH_INT_INTERRUPT(c)						\
+  (TARGET_XTHEADINT							\
+   /* The XTheadInt extension only supports rv32.  */			\
+   && !TARGET_64BIT							\
+   && (c)->machine->interrupt_handler_p					\
+   /* The XTheadInt instructions can only be executed in M-mode.  */	\
+   && (c)->machine->interrupt_mode == MACHINE_MODE)
+
 /* Information about a function's frame layout.  */
 struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -7101,6 +7108,7 @@ riscv_expand_prologue (void)
   unsigned fmask = frame->fmask;
   int spimm, multi_push_additional, stack_adj;
   rtx insn, dwarf = NULL_RTX;
+  unsigned th_int_mask = 0;
 
   if (flag_stack_usage_info)
     current_function_static_stack_size = constant_lower_bound (remaining_size);
@@ -7169,6 +7177,28 @@ riscv_expand_prologue (void)
       REG_NOTES (insn) = dwarf;
     }
 
+  th_int_mask = th_int_get_mask (frame->mask);
+  if (th_int_mask && TH_INT_INTERRUPT (cfun))
+    {
+      frame->mask &= ~th_int_mask;
+
+      /* RISCV_PROLOGUE_TEMP may be used to handle some CSR for
+	 interrupts, such as fcsr.  */
+      if ((TARGET_HARD_FLOAT  && frame->fmask)
+	  || (TARGET_ZFINX && frame->mask))
+	frame->mask |= (1 << RISCV_PROLOGUE_TEMP_REGNUM);
+
+      unsigned save_adjustment = th_int_get_save_adjustment ();
+      frame->gp_sp_offset -= save_adjustment;
+      remaining_size -= save_adjustment;
+
+      insn = emit_insn (gen_th_int_push ());
+
+      rtx dwarf = th_int_adjust_cfi_prologue (th_int_mask);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      REG_NOTES (insn) = dwarf;
+    }
+
   /* Save the GP, FP registers.  */
   if ((frame->mask | frame->fmask) != 0)
     {
@@ -7397,6 +7427,7 @@ riscv_expand_epilogue (int style)
     = use_multi_pop ? frame->multi_push_adj_base + frame->multi_push_adj_addi
 		    : 0;
   rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
+  unsigned th_int_mask = 0;
   rtx insn;
 
   /* We need to add memory barrier to prevent read from deallocated stack.  */
@@ -7559,12 +7590,32 @@ riscv_expand_epilogue (int style)
   else if (use_restore_libcall)
     frame->mask = 0; /* Temporarily fib that we need not restore GPRs.  */
 
+  th_int_mask = th_int_get_mask (frame->mask);
+  if (th_int_mask && TH_INT_INTERRUPT (cfun))
+    {
+      frame->mask &= ~th_int_mask;
+
+      /* RISCV_PROLOGUE_TEMP may be used to handle some CSR for
+	 interrupts, such as fcsr.  */
+      if ((TARGET_HARD_FLOAT  && frame->fmask)
+	  || (TARGET_ZFINX && frame->mask))
+	frame->mask |= (1 << RISCV_PROLOGUE_TEMP_REGNUM);
+    }
+
   /* Restore the registers.  */
   riscv_for_each_saved_v_reg (step2, riscv_restore_reg, false);
   riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size
 			      - multipop_size,
 			    riscv_restore_reg, true, style == EXCEPTION_RETURN);
 
+  if (th_int_mask && TH_INT_INTERRUPT (cfun))
+    {
+      frame->mask = mask; /* Undo the above fib.  */
+      unsigned save_adjustment = th_int_get_save_adjustment ();
+      gcc_assert (step2.to_constant () >= save_adjustment);
+      step2 -= save_adjustment;
+    }
+
   if (use_restore_libcall)
     frame->mask = mask; /* Undo the above fib.  */
 
@@ -7627,7 +7678,9 @@ riscv_expand_epilogue (int style)
 
       gcc_assert (mode != UNKNOWN_MODE);
 
-      if (mode == MACHINE_MODE)
+      if (th_int_mask && TH_INT_INTERRUPT (cfun))
+	emit_jump_insn (gen_th_int_pop ());
+      else if (mode == MACHINE_MODE)
 	emit_jump_insn (gen_riscv_mret ());
       else if (mode == SUPERVISOR_MODE)
 	emit_jump_insn (gen_riscv_sret ());
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index b13ccc5aba9..15d554e8170 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -634,6 +634,9 @@ enum reg_class
   (!SMALL_OPERAND (VALUE)						\
    && SMALL_OPERAND (VALUE & ~(HOST_WIDE_INT_1U << floor_log2 (VALUE))))
 
+/* True if bit BIT is set in VALUE.  */
+#define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
+
 /* Stack layout; function entry, exit and calling.  */
 
 #define STACK_GROWS_DOWNWARD 1
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 84212430dc0..95753c75cfc 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -130,6 +130,10 @@
   ;; XTheadFmv unspec
   UNSPEC_XTHEADFMV
   UNSPEC_XTHEADFMV_HW
+
+  ;; XTheadInt unspec
+  UNSPECV_XTHEADINT_PUSH
+  UNSPECV_XTHEADINT_POP
 ])
 
 (define_constants
diff --git a/gcc/config/riscv/thead.cc b/gcc/config/riscv/thead.cc
index a75351d66e4..0b7e4d8f030 100644
--- a/gcc/config/riscv/thead.cc
+++ b/gcc/config/riscv/thead.cc
@@ -912,3 +912,80 @@ th_print_operand_address (FILE *file, machine_mode mode, rtx x)
 
   gcc_unreachable ();
 }
+
+/* Number array of registers X1, X5-X7, X10-X17, X28-X31, to be
+   operated on by instruction th.ipush/th.ipop in XTheadInt.  */
+
+int th_int_regs[] ={
+  RETURN_ADDR_REGNUM,
+  T0_REGNUM, T1_REGNUM, T2_REGNUM,
+  A0_REGNUM, A1_REGNUM, A2_REGNUM, A3_REGNUM,
+  A4_REGNUM, A5_REGNUM, A6_REGNUM, A7_REGNUM,
+  T3_REGNUM, T4_REGNUM, T5_REGNUM, T6_REGNUM,
+};
+
+/* If MASK contains registers X1, X5-X7, X10-X17, X28-X31, then
+   return the mask composed of these registers, otherwise return
+   zero.  */
+
+unsigned int
+th_int_get_mask (unsigned int mask)
+{
+  unsigned int xtheadint_mask = 0;
+
+  if (!TARGET_XTHEADINT || TARGET_64BIT)
+    return 0;
+
+  for (unsigned int i = 0; i < ARRAY_SIZE (th_int_regs); i++)
+    {
+      if (!BITSET_P (mask, th_int_regs[i]))
+	return 0;
+
+      xtheadint_mask |= (1 << th_int_regs[i]);
+    }
+
+  return xtheadint_mask; /* Usually 0xf003fce2.  */
+}
+
+/* Returns the occupied frame needed to save registers X1, X5-X7,
+   X10-X17, X28-X31.  */
+
+unsigned int
+th_int_get_save_adjustment (void)
+{
+  gcc_assert (TARGET_XTHEADINT && !TARGET_64BIT);
+  return ARRAY_SIZE (th_int_regs) * UNITS_PER_WORD;
+}
+
+rtx
+th_int_adjust_cfi_prologue (unsigned int mask)
+{
+  gcc_assert (TARGET_XTHEADINT && !TARGET_64BIT);
+
+  rtx dwarf = NULL_RTX;
+  rtx adjust_sp_rtx, reg, mem, insn;
+  int saved_size = ARRAY_SIZE (th_int_regs) * UNITS_PER_WORD;
+  int offset = saved_size;
+
+  for (int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
+    if (BITSET_P (mask, regno - GP_REG_FIRST))
+      {
+	offset -= UNITS_PER_WORD;
+	reg = gen_rtx_REG (SImode, regno);
+	mem = gen_frame_mem (SImode, plus_constant (Pmode,
+						    stack_pointer_rtx,
+						    offset));
+
+	insn = gen_rtx_SET (mem, reg);
+	dwarf = alloc_reg_note (REG_CFA_OFFSET, insn, dwarf);
+      }
+
+  /* Debug info for adjust sp.  */
+  adjust_sp_rtx =
+    gen_rtx_SET (stack_pointer_rtx,
+		 gen_rtx_PLUS (GET_MODE (stack_pointer_rtx),
+			       stack_pointer_rtx, GEN_INT (-saved_size)));
+  dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, adjust_sp_rtx, dwarf);
+
+  return dwarf;
+}
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
index 903d3f794b9..e370774d518 100644
--- a/gcc/config/riscv/thead.md
+++ b/gcc/config/riscv/thead.md
@@ -210,6 +210,73 @@
    (set_attr "type" "fmove")
    (set_attr "mode" "DF")])
 
+;; XTheadInt
+
+(define_constants
+  [(T0_REGNUM	5)
+   (T1_REGNUM	6)
+   (T2_REGNUM	7)
+   (A0_REGNUM	10)
+   (A1_REGNUM	11)
+   (A2_REGNUM	12)
+   (A3_REGNUM	13)
+   (A4_REGNUM	14)
+   (A5_REGNUM	15)
+   (A6_REGNUM	16)
+   (A7_REGNUM	17)
+   (T3_REGNUM	28)
+   (T4_REGNUM	29)
+   (T5_REGNUM	30)
+   (T6_REGNUM	31)
+])
+
+(define_insn "th_int_push"
+  [(unspec_volatile [(const_int 0)] UNSPECV_XTHEADINT_PUSH)
+   (use (reg:SI RETURN_ADDR_REGNUM))
+   (use (reg:SI T0_REGNUM))
+   (use (reg:SI T1_REGNUM))
+   (use (reg:SI T2_REGNUM))
+   (use (reg:SI A0_REGNUM))
+   (use (reg:SI A1_REGNUM))
+   (use (reg:SI A2_REGNUM))
+   (use (reg:SI A3_REGNUM))
+   (use (reg:SI A4_REGNUM))
+   (use (reg:SI A5_REGNUM))
+   (use (reg:SI A6_REGNUM))
+   (use (reg:SI A7_REGNUM))
+   (use (reg:SI T3_REGNUM))
+   (use (reg:SI T4_REGNUM))
+   (use (reg:SI T5_REGNUM))
+   (use (reg:SI T6_REGNUM))]
+  "TARGET_XTHEADINT && !TARGET_64BIT"
+  "th.ipush"
+  [(set_attr "type"	"store")
+   (set_attr "mode"	"SI")])
+
+(define_insn "th_int_pop"
+  [(unspec_volatile [(const_int 0)] UNSPECV_XTHEADINT_POP)
+   (clobber (reg:SI RETURN_ADDR_REGNUM))
+   (clobber (reg:SI T0_REGNUM))
+   (clobber (reg:SI T1_REGNUM))
+   (clobber (reg:SI T2_REGNUM))
+   (clobber (reg:SI A0_REGNUM))
+   (clobber (reg:SI A1_REGNUM))
+   (clobber (reg:SI A2_REGNUM))
+   (clobber (reg:SI A3_REGNUM))
+   (clobber (reg:SI A4_REGNUM))
+   (clobber (reg:SI A5_REGNUM))
+   (clobber (reg:SI A6_REGNUM))
+   (clobber (reg:SI A7_REGNUM))
+   (clobber (reg:SI T3_REGNUM))
+   (clobber (reg:SI T4_REGNUM))
+   (clobber (reg:SI T5_REGNUM))
+   (clobber (reg:SI T6_REGNUM))
+   (return)]
+  "TARGET_XTHEADINT && !TARGET_64BIT"
+  "th.ipop"
+  [(set_attr "type"	"ret")
+   (set_attr "mode"	"SI")])
+
 ;; XTheadMac
 
 (define_insn "*th_mula<mode>"
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadint-push-pop.c b/gcc/testsuite/gcc.target/riscv/xtheadint-push-pop.c
new file mode 100644
index 00000000000..dc5609c8f76
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadint-push-pop.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadint -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadint -mabi=lp64d" { target { rv64 } } } */
+
+extern void f (void);
+
+__attribute__ ((interrupt))
+void func_default (void)
+{
+  f ();
+}
+
+__attribute__ ((interrupt ("machine")))
+void func_machine (void)
+{
+  f ();
+}
+
+/* { dg-final { scan-assembler-times {\mth\.ipush\M} 2 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times {\mth\.ipop\M} 2 { target { rv32 } } } } */
+
+
+__attribute__ ((interrupt ("user")))
+void func_usr (void)
+{
+  f ();
+}
+
+__attribute__ ((interrupt ("supervisor")))
+void func_supervisor (void)
+{
+  f ();
+}
+
+/* { dg-final { scan-assembler-not {\mth\.ipush\M} { target { rv64 } } } } */
+/* { dg-final { scan-assembler-not {\mth\.ipop\M} { target { rv64 } } } } */


More information about the Gcc-cvs mailing list