Skip to content

Commit

Permalink
RISC-V: T-HEAD: Add support for the XTheadInt ISA extension
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
majin2020 authored and cmuellner committed Jan 10, 2024
1 parent 7cbe41d commit 52e809d
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 4 deletions.
3 changes: 3 additions & 0 deletions gcc/config/riscv/riscv-protos.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
61 changes: 57 additions & 4 deletions gcc/config/riscv/riscv.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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. */

Expand Down Expand Up @@ -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 ());
Expand Down
3 changes: 3 additions & 0 deletions gcc/config/riscv/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions gcc/config/riscv/riscv.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@
;; XTheadFmv unspec
UNSPEC_XTHEADFMV
UNSPEC_XTHEADFMV_HW

;; XTheadInt unspec
UNSPECV_XTHEADINT_PUSH
UNSPECV_XTHEADINT_POP
])

(define_constants
Expand Down
77 changes: 77 additions & 0 deletions gcc/config/riscv/thead.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
67 changes: 67 additions & 0 deletions gcc/config/riscv/thead.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>"
Expand Down
36 changes: 36 additions & 0 deletions gcc/testsuite/gcc.target/riscv/xtheadint-push-pop.c
Original file line number Diff line number Diff line change
@@ -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 } } } } */

0 comments on commit 52e809d

Please sign in to comment.