From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from out30-98.freemail.mail.aliyun.com (out30-98.freemail.mail.aliyun.com [115.124.30.98]) by sourceware.org (Postfix) with ESMTPS id F04A83858D28 for ; Fri, 17 Nov 2023 07:33:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F04A83858D28 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linux.alibaba.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org F04A83858D28 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=115.124.30.98 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700206426; cv=none; b=N5MFakCJVxquuT/6sJ8no1fVFq5mp7W4GiKidZMud1vnsUiLofqvowBvHJv6dV4Kf2rDVysv2/PRTG7fD+5QHR8XLkZl0k+6qdE4h3gMzYJoAaCEYH5SYoAtcmh8MF+/MZNVJWnGTcNG4Ogge9U8yWNg7i2asg/gnkekIZUxR64= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700206426; c=relaxed/simple; bh=ruzNqsEeNtRWkpXfYQ98ck1KWrnJ0OI2JBmeCC26WWA=; h=From:To:Subject:Date:Message-Id:MIME-Version; b=LBx8WGNUEe2oaKLrBlXpBMH4JpidiQTk4fx6AMPZv2fdticviTELGZImYg8lYnxvpyHpspz30bDKzo1Q6UptEO0z+WcgcAUBCp7Shkz9a36mZCrgfmHkd0LjD7Wj9jLyXkaN6y9LFVR6JPtPxkI6CZA9qdM6jHAX7kxarmPUTsw= ARC-Authentication-Results: i=1; server2.sourceware.org X-Alimail-AntiSpam:AC=PASS;BC=-1|-1;BR=01201311R171e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=ay29a033018045176;MF=jinma@linux.alibaba.com;NM=1;PH=DS;RN=5;SR=0;TI=SMTPD_---0VwYzwir_1700206415; Received: from localhost.localdomain(mailfrom:jinma@linux.alibaba.com fp:SMTPD_---0VwYzwir_1700206415) by smtp.aliyun-inc.com; Fri, 17 Nov 2023 15:33:37 +0800 From: Jin Ma To: gcc-patches@gcc.gnu.org Cc: kito.cheng@gmail.com, christoph.muellner@vrull.eu, jinma.contrib@gmail.com, Jin Ma Subject: [PATCH v2] RISC-V: T-HEAD: Add support for the XTheadInt ISA extension Date: Fri, 17 Nov 2023 15:33:25 +0800 Message-Id: <20231117073325.1959-1-jinma@linux.alibaba.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20231107030415.1105-1-jinma@linux.alibaba.com> References: <20231107030415.1105-1-jinma@linux.alibaba.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-20.4 required=5.0 tests=BAYES_00,ENV_AND_HDR_SPF_MATCH,GIT_PATCH_0,KAM_DMARC_STATUS,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP,T_SCC_BODY_TEXT_LINE,UNPARSEABLE_RELAY,USER_IN_DEF_SPF_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: The XTheadInt ISA extension provides acceleration interruption instructions as defined in T-Head-specific: * 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 (TH_INT_INTERRUPT): New macro. (riscv_expand_prologue): Add the processing of XTheadInt. (riscv_expand_epilogue): Likewise. * config/riscv/riscv.md: New unspec. * config/riscv/thead.cc (BITSET_P): New macro. * 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. --- 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(-) create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadint-push-pop.c diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 196b53f10f3..91d1e99f672 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -633,6 +633,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 c2bd1c2ed29..6ff6f4789a4 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -94,15 +94,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. */ @@ -6737,6 +6744,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); @@ -6805,6 +6813,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) { @@ -7033,6 +7063,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. */ @@ -7195,12 +7226,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. */ @@ -7263,7 +7314,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 6205d7533f4..4c04a5d4c22 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -629,6 +629,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 8f28e8e56ab..4023cacf7c0 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -126,6 +126,10 @@ (define_c_enum "unspecv" [ ;; 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 a485fb1fba6..b444a0b478f 100644 --- a/gcc/config/riscv/thead.cc +++ b/gcc/config/riscv/thead.cc @@ -945,3 +945,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 2babfafb23c..4d6e16c0edc 100644 --- a/gcc/config/riscv/thead.md +++ b/gcc/config/riscv/thead.md @@ -210,6 +210,73 @@ (define_insn "th_fmv_x_hw" (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" 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 } } } } */ base-commit: 37183018134049a70482a59b8f12180946ab8fa4 -- 2.17.1