From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpbguseast1.qq.com (smtpbguseast1.qq.com [54.204.34.129]) by sourceware.org (Postfix) with ESMTPS id AC73A385802A for ; Thu, 15 Sep 2022 08:29:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org AC73A385802A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=rivai.ai Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=rivai.ai X-QQ-mid: bizesmtp85t1663230538t2lgr4fp Received: from server1.localdomain ( [42.247.22.65]) by bizesmtp.qq.com (ESMTP) with id ; Thu, 15 Sep 2022 16:28:56 +0800 (CST) X-QQ-SSF: 01400000002000D0J000B00A0000000 X-QQ-FEAT: k8Irs33ik7vVDJTkJZUANjXNTxF3lH5hiKHjEkbPL7D1fNMyVSd1WcmLzZQNC NB2KekExezDhjfVXveZEWp27quvQi3pDrj1A0jGNTVRQs8xcgr4lw7n43PKGdHrbnUop1L1 0JL1oh7kLqqnH4ls4gnHxABP0Mb6RvnImDKT/KOgJZRin50ErUAhaoxGmtv+zU2opLWQ5k8 0NnVbF6NnkaO0gxU5ZGUPG4olr2RSmZ6i9waM+cdkKJ01dlgeCP5Flk7GtF40Esk0Xgao0y 1IAdl2M/c9CYujbY2737FHjyPEyh4KISGYVuhywxdM+53PJnIQvpLs3QFrtTgu0MzQm57NF mGGmSUL0KaiMSDcHT2iORmkKMN9HV61GEhXX5fDJhryhSjZXMA84MYRXO7Gigi4HFiwdFe9 CtIOdmLlu6I= X-QQ-GoodBg: 2 From: juzhe.zhong@rivai.ai To: gcc-patches@gcc.gnu.org Cc: kito.cheng@gmail.com, palmer@dabbelt.com, zhongjuzhe Subject: [PATCH] RISC-V: Support poly move manipulation and selftests. Date: Thu, 15 Sep 2022 16:28:53 +0800 Message-Id: <20220915082853.109235-1-juzhe.zhong@rivai.ai> X-Mailer: git-send-email 2.36.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:rivai.ai:qybglogicsvr:qybglogicsvr7 X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00,GIT_PATCH_0,KAM_DMARC_STATUS,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_HELO_PASS,TXREP 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: From: zhongjuzhe gcc/ChangeLog: * common/config/riscv/riscv-common.cc: Change "static void" to "void". * config.gcc: Add riscv-selftests.o * config/riscv/predicates.md: Allow const_poly_int. * config/riscv/riscv-protos.h (riscv_reinit): New function. (riscv_parse_arch_string): change as exten function. (riscv_run_selftests): New function. * config/riscv/riscv.cc (riscv_cannot_force_const_mem): Don't allow poly into const pool. (riscv_report_v_required): New function. (riscv_expand_op): New function. (riscv_expand_mult_with_const_int): New function. (riscv_legitimize_poly_move): Ditto. (riscv_legitimize_move): New function. (riscv_hard_regno_mode_ok): Add VL/VTYPE register allocation and fix vector RA. (riscv_convert_vector_bits): Fix riscv_vector_chunks configuration for -marh no 'v'. (riscv_reinit): New function. (TARGET_RUN_TARGET_SELFTESTS): New target hook support. * config/riscv/t-riscv: Add riscv-selftests.o. * config/riscv/riscv-selftests.cc: New file. gcc/testsuite/ChangeLog: * selftests/riscv/empty-func.rtl: New test. --- gcc/common/config/riscv/riscv-common.cc | 2 +- gcc/config.gcc | 2 +- gcc/config/riscv/predicates.md | 3 + gcc/config/riscv/riscv-protos.h | 9 + gcc/config/riscv/riscv-selftests.cc | 239 +++++++++++++++ gcc/config/riscv/riscv.cc | 298 ++++++++++++++++++- gcc/config/riscv/t-riscv | 4 + gcc/testsuite/selftests/riscv/empty-func.rtl | 8 + 8 files changed, 558 insertions(+), 7 deletions(-) create mode 100644 gcc/config/riscv/riscv-selftests.cc create mode 100644 gcc/testsuite/selftests/riscv/empty-func.rtl diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index 77219162eeb..c39ed2e2696 100644 --- a/gcc/common/config/riscv/riscv-common.cc +++ b/gcc/common/config/riscv/riscv-common.cc @@ -1224,7 +1224,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = /* Parse a RISC-V ISA string into an option mask. Must clear or set all arch dependent mask bits, in case more than one -march string is passed. */ -static void +void riscv_parse_arch_string (const char *isa, struct gcc_options *opts, location_t loc) diff --git a/gcc/config.gcc b/gcc/config.gcc index f4e757bd853..27ffce3fb50 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -515,7 +515,7 @@ pru-*-*) ;; riscv*) cpu_type=riscv - extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o" + extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o" d_target_objs="riscv-d.o" ;; rs6000*-*-*) diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index 862e72b0983..5e149b3a95f 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -146,6 +146,9 @@ case CONST_INT: return !splittable_const_int_operand (op, mode); + case CONST_POLY_INT: + return known_eq (rtx_to_poly_int64 (op), BYTES_PER_RISCV_VECTOR); + case CONST: case SYMBOL_REF: case LABEL_REF: diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 649c5c977e1..f9a2baa46c7 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -74,6 +74,7 @@ extern bool riscv_expand_block_move (rtx, rtx, rtx); extern bool riscv_store_data_bypass_p (rtx_insn *, rtx_insn *); extern rtx riscv_gen_gpr_save_insn (struct riscv_frame_info *); extern bool riscv_gpr_save_operation_p (rtx); +extern void riscv_reinit (void); /* Routines implemented in riscv-c.cc. */ void riscv_cpu_cpp_builtins (cpp_reader *); @@ -86,6 +87,7 @@ extern void riscv_init_builtins (void); /* Routines implemented in riscv-common.cc. */ extern std::string riscv_arch_str (bool version_p = true); +extern void riscv_parse_arch_string (const char *, struct gcc_options *, location_t); extern bool riscv_hard_regno_rename_ok (unsigned, unsigned); @@ -105,4 +107,11 @@ struct riscv_cpu_info { extern const riscv_cpu_info *riscv_find_cpu (const char *); +/* Routines implemented in riscv-selftests.cc. */ +#if CHECKING_P +namespace selftest { +extern void riscv_run_selftests (void); +} // namespace selftest +#endif + #endif /* ! GCC_RISCV_PROTOS_H */ diff --git a/gcc/config/riscv/riscv-selftests.cc b/gcc/config/riscv/riscv-selftests.cc new file mode 100644 index 00000000000..167cd47c880 --- /dev/null +++ b/gcc/config/riscv/riscv-selftests.cc @@ -0,0 +1,239 @@ +/* This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#define IN_TARGET_CODE 1 + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "tree.h" +#include "stringpool.h" +#include "function.h" +#include "memmodel.h" +#include "emit-rtl.h" +#include "tm_p.h" +#include "expr.h" +#include "selftest.h" +#include "selftest-rtl.h" +#include +#include + +#if CHECKING_P +using namespace selftest; +class riscv_selftest_arch_abi_setter +{ +private: + std::string m_arch_backup; + enum riscv_abi_type m_abi_backup; + +public: + riscv_selftest_arch_abi_setter (const char *arch, enum riscv_abi_type abi) + : m_arch_backup (riscv_arch_str ()), m_abi_backup (riscv_abi) + { + riscv_parse_arch_string (arch, &global_options, UNKNOWN_LOCATION); + riscv_abi = abi; + riscv_reinit (); + } + ~riscv_selftest_arch_abi_setter () + { + riscv_parse_arch_string (m_arch_backup.c_str (), &global_options, + UNKNOWN_LOCATION); + riscv_abi = m_abi_backup; + riscv_reinit (); + } +}; + +static poly_int64 +eval_value (rtx x, std::map ®no_to_rtx) +{ + if (!REG_P (x)) + { + debug (x); + gcc_unreachable (); + } + + rtx expr = NULL_RTX; + unsigned regno = REGNO (x); + expr = regno_to_rtx[regno]; + + poly_int64 op1_val, op2_val; + if (UNARY_P (expr)) + { + op1_val = eval_value (XEXP (expr, 0), regno_to_rtx); + } + if (BINARY_P (expr)) + { + op1_val = eval_value (XEXP (expr, 0), regno_to_rtx); + op2_val = eval_value (XEXP (expr, 1), regno_to_rtx); + } + + switch (GET_CODE (expr)) + { + case CONST_POLY_INT: + return rtx_to_poly_int64 (expr); + case CONST_INT: + return INTVAL (expr); + + case MULT: + if (op1_val.is_constant ()) + return op1_val.to_constant () * op2_val; + else if (op2_val.is_constant ()) + return op1_val * op2_val.to_constant (); + else + gcc_unreachable (); + case PLUS: + return op1_val + op2_val; + default: + gcc_unreachable (); + } +} + +/* Calculate the value of x register in the sequence. */ +static poly_int64 +calculate_x_in_sequence (rtx reg) +{ + std::map regno_to_rtx; + rtx_insn *insn; + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + rtx pat = PATTERN (insn); + rtx dest = SET_DEST (pat); + + if (GET_CODE (pat) == CLOBBER) + continue; + + if (SUBREG_P (dest)) + continue; + + gcc_assert (REG_P (dest)); + rtx note = find_reg_equal_equiv_note (insn); + unsigned regno = REGNO (dest); + if (note) + regno_to_rtx[regno] = XEXP (note, 0); + else + regno_to_rtx[regno] = SET_SRC (pat); + } + + return eval_value (reg, regno_to_rtx); +} + +typedef enum +{ + POLY_TEST_DIMODE, + POLY_TEST_PMODE +} poly_test_mode_t; + +static void +simple_poly_selftest (const char *arch, enum riscv_abi_type abi, + const std::vector &modes) +{ + riscv_selftest_arch_abi_setter rv (arch, abi); + rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl")); + set_new_first_and_last_insn (NULL, NULL); + + for (machine_mode mode : modes) + emit_move_insn (gen_reg_rtx (mode), + gen_int_mode (BYTES_PER_RISCV_VECTOR, mode)); +} + +static void +run_poly_int_selftest (const char *arch, enum riscv_abi_type abi, + poly_test_mode_t test_mode, + const std::vector &worklist) +{ + riscv_selftest_arch_abi_setter rv (arch, abi); + rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl")); + set_new_first_and_last_insn (NULL, NULL); + machine_mode mode = VOIDmode; + + switch (test_mode) + { + case POLY_TEST_DIMODE: + mode = DImode; + break; + case POLY_TEST_PMODE: + mode = Pmode; + break; + default: + gcc_unreachable (); + } + + for (const poly_int64 &poly_val : worklist) + { + start_sequence (); + rtx dest = gen_reg_rtx (mode); + emit_move_insn (dest, gen_int_mode (poly_val, mode)); + ASSERT_TRUE (known_eq (calculate_x_in_sequence (dest), poly_val)); + end_sequence (); + } +} + +static void +run_poly_int_selftests (void) +{ + std::vector worklist + = {BYTES_PER_RISCV_VECTOR, BYTES_PER_RISCV_VECTOR * 8, + BYTES_PER_RISCV_VECTOR * 32, -BYTES_PER_RISCV_VECTOR * 8, + -BYTES_PER_RISCV_VECTOR * 32, BYTES_PER_RISCV_VECTOR * 7, + BYTES_PER_RISCV_VECTOR * 31, -BYTES_PER_RISCV_VECTOR * 7, + -BYTES_PER_RISCV_VECTOR * 31, BYTES_PER_RISCV_VECTOR * 9, + BYTES_PER_RISCV_VECTOR * 33, -BYTES_PER_RISCV_VECTOR * 9, + -BYTES_PER_RISCV_VECTOR * 33, poly_int64 (207, 0), + poly_int64 (-207, 0), poly_int64 (0, 207), + poly_int64 (0, -207), poly_int64 (5555, 0), + poly_int64 (0, 5555), poly_int64 (4096, 4096), + poly_int64 (17, 4088), poly_int64 (3889, 4104), + poly_int64 (-4096, -4096), poly_int64 (219, -4088), + poly_int64 (-4309, -4104), poly_int64 (-7337, 88), + poly_int64 (9317, -88), poly_int64 (4, 4), + poly_int64 (17, 4), poly_int64 (-7337, 4), + poly_int64 (-4, -4), poly_int64 (-389, -4), + poly_int64 (4789, -4), poly_int64 (-5977, 1508), + poly_int64 (219, -1508), poly_int64 (2, 2), + poly_int64 (33, 2), poly_int64 (-7337, 2), + poly_int64 (-2, -2), poly_int64 (-389, -2), + poly_int64 (4789, -2), poly_int64 (-3567, 954), + poly_int64 (945, -954), poly_int64 (1, 1), + poly_int64 (977, 1), poly_int64 (-339, 1), + poly_int64 (-1, -1), poly_int64 (-12, -1), + poly_int64 (44, -1), poly_int64 (9567, 77), + poly_int64 (3467, -77)}; + + simple_poly_selftest ("rv64imafdv", ABI_LP64D, + {QImode, HImode, SImode, DImode}); + simple_poly_selftest ("rv32imafdv", ABI_ILP32D, {QImode, HImode, SImode}); + + run_poly_int_selftest ("rv64imafdv", ABI_LP64D, POLY_TEST_PMODE, worklist); + run_poly_int_selftest ("rv64imafd_zve32x1p0", ABI_LP64D, POLY_TEST_PMODE, + worklist); + run_poly_int_selftest ("rv32imafdv", ABI_ILP32, POLY_TEST_PMODE, worklist); + run_poly_int_selftest ("rv32imafdv", ABI_ILP32, POLY_TEST_DIMODE, worklist); + run_poly_int_selftest ("rv32imafd_zve32x1p0", ABI_ILP32D, POLY_TEST_PMODE, + worklist); + run_poly_int_selftest ("rv32imafd_zve32x1p0", ABI_ILP32D, POLY_TEST_DIMODE, + worklist); +} +namespace selftest { +/* Run all target-specific selftests. */ +void +riscv_run_selftests (void) +{ + run_poly_int_selftests (); +} +} // namespace selftest +#endif /* #if CHECKING_P */ diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 675d92c0961..4d5d88798ea 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -57,6 +57,8 @@ along with GCC; see the file COPYING3. If not see #include "predict.h" #include "tree-pass.h" #include "opts.h" +#include "tm-constrs.h" +#include "rtl-iter.h" /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */ #define UNSPEC_ADDRESS_P(X) \ @@ -778,6 +780,12 @@ riscv_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x) enum riscv_symbol_type type; rtx base, offset; + /* There's no way to calculate VL-based values using relocations. */ + subrtx_iterator::array_type array; + FOR_EACH_SUBRTX (iter, array, x, ALL) + if (GET_CODE (*iter) == CONST_POLY_INT) + return true; + /* There is no assembler syntax for expressing an address-sized high part. */ if (GET_CODE (x) == HIGH) @@ -1684,12 +1692,268 @@ riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src) riscv_emit_move (dest, src); } +/* Report when we try to do something that requires vector when vector is + disabled. This is an error of last resort and isn't very high-quality. It + usually involves attempts to measure the vector length in some way. */ + +static void +riscv_report_v_required (void) +{ + static bool reported_p = false; + + /* Avoid reporting a slew of messages for a single oversight. */ + if (reported_p) + return; + + error ("this operation requires the RVV ISA extension"); + inform (input_location, "you can enable RVV using the command-line" + " option %<-march%>, or by using the %" + " attribute or pragma"); + reported_p = true; +} + +/* Helper function to operation for rtx_code CODE. */ +static void +riscv_expand_op (enum rtx_code code, machine_mode mode, rtx op0, rtx op1, + rtx op2) +{ + if (can_create_pseudo_p ()) + { + rtx result; + if (GET_RTX_CLASS (code) == RTX_UNARY) + result = expand_simple_unop (mode, code, op1, NULL_RTX, false); + else + result = expand_simple_binop (mode, code, op1, op2, NULL_RTX, false, + OPTAB_DIRECT); + riscv_emit_move (op0, result); + } + else + { + rtx pat; + /* The following implementation is for prologue and epilogue. + Because prologue and epilogue can not use pseudo register. + We can't using expand_simple_binop or expand_simple_unop. */ + if (GET_RTX_CLASS (code) == RTX_UNARY) + pat = gen_rtx_fmt_e (code, mode, op1); + else + pat = gen_rtx_fmt_ee (code, mode, op1, op2); + emit_insn (gen_rtx_SET (op0, pat)); + } +} + +/* Expand mult operation with constant integer, multiplicand also used as a + * temporary register. */ + +static void +riscv_expand_mult_with_const_int (machine_mode mode, rtx dest, rtx multiplicand, + int multiplier) +{ + if (multiplier == 0) + { + riscv_emit_move (dest, GEN_INT (0)); + return; + } + + bool neg_p = multiplier < 0; + int multiplier_abs = abs (multiplier); + + if (multiplier_abs == 1) + { + if (neg_p) + riscv_expand_op (NEG, mode, dest, multiplicand, NULL_RTX); + else + riscv_emit_move (dest, multiplicand); + } + else + { + if (pow2p_hwi (multiplier_abs)) + { + /* + multiplicand = [BYTES_PER_RISCV_VECTOR]. + 1. const_poly_int:P [BYTES_PER_RISCV_VECTOR * 8]. + Sequence: + csrr a5, vlenb + slli a5, a5, 3 + 2. const_poly_int:P [-BYTES_PER_RISCV_VECTOR * 8]. + Sequence: + csrr a5, vlenb + slli a5, a5, 3 + neg a5, a5 + */ + riscv_expand_op (ASHIFT, mode, dest, multiplicand, + gen_int_mode (exact_log2 (multiplier_abs), QImode)); + if (neg_p) + riscv_expand_op (NEG, mode, dest, dest, NULL_RTX); + } + else if (pow2p_hwi (multiplier_abs + 1)) + { + /* + multiplicand = [BYTES_PER_RISCV_VECTOR]. + 1. const_poly_int:P [BYTES_PER_RISCV_VECTOR * 7]. + Sequence: + csrr a5, vlenb + slli a4, a5, 3 + sub a5, a4, a5 + 2. const_poly_int:P [-BYTES_PER_RISCV_VECTOR * 7]. + Sequence: + csrr a5, vlenb + slli a4, a5, 3 + sub a5, a4, a5 + neg a5, a5 => sub a5, a5, a4 + */ + riscv_expand_op (ASHIFT, mode, dest, multiplicand, + gen_int_mode (exact_log2 (multiplier_abs + 1), + QImode)); + if (neg_p) + riscv_expand_op (MINUS, mode, dest, multiplicand, dest); + else + riscv_expand_op (MINUS, mode, dest, dest, multiplicand); + } + else if (pow2p_hwi (multiplier - 1)) + { + /* + multiplicand = [BYTES_PER_RISCV_VECTOR]. + 1. const_poly_int:P [BYTES_PER_RISCV_VECTOR * 9]. + Sequence: + csrr a5, vlenb + slli a4, a5, 3 + add a5, a4, a5 + 2. const_poly_int:P [-BYTES_PER_RISCV_VECTOR * 9]. + Sequence: + csrr a5, vlenb + slli a4, a5, 3 + add a5, a4, a5 + neg a5, a5 + */ + riscv_expand_op (ASHIFT, mode, dest, multiplicand, + gen_int_mode (exact_log2 (multiplier_abs - 1), + QImode)); + riscv_expand_op (PLUS, mode, dest, dest, multiplicand); + if (neg_p) + riscv_expand_op (NEG, mode, dest, dest, NULL_RTX); + } + else + { + /* We use multiplication for remaining cases. */ + gcc_assert ( + TARGET_MUL + && "M-extension must be enabled to calculate the poly_int " + "size/offset."); + riscv_emit_move (dest, gen_int_mode (multiplier, mode)); + riscv_expand_op (MULT, mode, dest, dest, multiplicand); + } + } +} + +/* Analyze src and emit const_poly_int mov sequence. */ + +static void +riscv_legitimize_poly_move (machine_mode mode, rtx dest, rtx tmp, rtx src) +{ + poly_int64 value = rtx_to_poly_int64 (src); + int offset = value.coeffs[0]; + int factor = value.coeffs[1]; + int vlenb = BYTES_PER_RISCV_VECTOR.coeffs[1]; + int div_factor = 0; + /* Calculate (const_poly_int:MODE [m, n]) using scalar instructions. + For any (const_poly_int:MODE [m, n]), the calculation formula is as + follows. + constant = m - n. + When minimum VLEN = 32, poly of VLENB = (4, 4). + base = vlenb(4, 4) or vlenb/2(2, 2) or vlenb/4(1, 1). + When minimum VLEN > 32, poly of VLENB = (8, 8). + base = vlenb(8, 8) or vlenb/2(4, 4) or vlenb/4(2, 2) or vlenb/8(1, 1). + magn = (n, n) / base. + (m, n) = base * magn + constant. + This calculation doesn't need div operation. */ + + emit_move_insn (tmp, gen_int_mode (BYTES_PER_RISCV_VECTOR, mode)); + + if (BYTES_PER_RISCV_VECTOR.is_constant ()) + { + gcc_assert (value.is_constant ()); + riscv_emit_move (dest, GEN_INT (value.to_constant ())); + return; + } + else if ((factor % vlenb) == 0) + div_factor = 1; + else if ((factor % (vlenb / 2)) == 0) + div_factor = 2; + else if ((factor % (vlenb / 4)) == 0) + div_factor = 4; + else if ((factor % (vlenb / 8)) == 0) + div_factor = 8; + else + gcc_unreachable (); + + if (div_factor != 1) + riscv_expand_op (LSHIFTRT, mode, tmp, tmp, + gen_int_mode (exact_log2 (div_factor), QImode)); + + riscv_expand_mult_with_const_int (mode, dest, tmp, + factor / (vlenb / div_factor)); + HOST_WIDE_INT constant = offset - factor; + + if (constant == 0) + return; + else if (SMALL_OPERAND (constant)) + riscv_expand_op (PLUS, mode, dest, dest, gen_int_mode (constant, mode)); + else + { + /* Handle the constant value is not a 12-bit value. */ + rtx high; + + /* Leave OFFSET as a 16-bit offset and put the excess in HIGH. + The addition inside the macro CONST_HIGH_PART may cause an + overflow, so we need to force a sign-extension check. */ + high = gen_int_mode (CONST_HIGH_PART (constant), mode); + constant = CONST_LOW_PART (constant); + riscv_emit_move (tmp, high); + riscv_expand_op (PLUS, mode, dest, tmp, dest); + riscv_expand_op (PLUS, mode, dest, dest, gen_int_mode (constant, mode)); + } +} + /* If (set DEST SRC) is not a valid move instruction, emit an equivalent sequence that is valid. */ bool riscv_legitimize_move (machine_mode mode, rtx dest, rtx src) { + if (CONST_POLY_INT_P (src)) + { + poly_int64 value = rtx_to_poly_int64 (src); + if (!value.is_constant () && !TARGET_VECTOR) + { + riscv_report_v_required (); + return false; + } + + if (satisfies_constraint_vp (src)) + return false; + + if (GET_MODE_SIZE (mode).to_constant () < GET_MODE_SIZE (Pmode)) + { + /* In RV32 system, handle (const_poly_int:QI [m, n]) + (const_poly_int:HI [m, n]). + In RV64 system, handle (const_poly_int:QI [m, n]) + (const_poly_int:HI [m, n]) + (const_poly_int:SI [m, n]). */ + rtx tmp = gen_reg_rtx (Pmode); + riscv_legitimize_poly_move (Pmode, gen_lowpart (Pmode, dest), tmp, + src); + } + else + { + /* In RV32 system, handle (const_poly_int:SI [m, n]) + (const_poly_int:DI [m, n]). + In RV64 system, handle (const_poly_int:DI [m, n]). + FIXME: Maybe we could gen SImode in RV32 and then sign-extend to DImode, + the offset should not exceed 4GiB in general. */ + rtx tmp = gen_reg_rtx (mode); + riscv_legitimize_poly_move (mode, dest, tmp, src); + } + return true; + } /* Expand (set (reg:QI target) (mem:QI (address))) to @@ -5033,6 +5297,9 @@ riscv_hard_regno_mode_ok (unsigned int regno, machine_mode mode) if (!riscv_v_ext_vector_mode_p (mode)) return false; + if (!V_REG_P (regno + nregs - 1)) + return false; + /* 3.3.2. LMUL = 2,4,8, register numbers should be multiple of 2,4,8. but for mask vector register, register numbers can be any number. */ int lmul = 1; @@ -5041,6 +5308,8 @@ riscv_hard_regno_mode_ok (unsigned int regno, machine_mode mode) if (lmul != 1) return ((regno % lmul) == 0); } + else if (regno == VL_REGNUM || regno == VTYPE_REGNUM) + return true; else return false; @@ -5231,10 +5500,6 @@ riscv_init_machine_status (void) static poly_uint16 riscv_convert_vector_bits (void) { - /* The runtime invariant is only meaningful when TARGET_VECTOR is enabled. */ - if (!TARGET_VECTOR) - return 0; - if (TARGET_MIN_VLEN > 32) { /* When targetting minimum VLEN > 32, we should use 64-bit chunk size. @@ -5255,7 +5520,13 @@ riscv_convert_vector_bits (void) riscv_bytes_per_vector_chunk = 4; } - return poly_uint16 (1, 1); + /* Set riscv_vector_chunks as poly (1, 1) run-time constant if TARGET_VECTOR + is enabled. Set riscv_vector_chunks as 1 compile-time constant if + TARGET_VECTOR is disabled. riscv_vector_chunks is used in "riscv-modes.def" + to set RVV mode size. The RVV machine modes size are run-time constant if + TARGET_VECTOR is enabled. The RVV machine modes size remains default + compile-time constant if TARGET_VECTOR is disabled. */ + return TARGET_VECTOR ? poly_uint16 (1, 1) : 1; } /* Implement TARGET_OPTION_OVERRIDE. */ @@ -6002,6 +6273,23 @@ riscv_init_libfuncs (void) set_optab_libfunc (unord_optab, HFmode, NULL); } +#if CHECKING_P +void +riscv_reinit (void) +{ + riscv_option_override (); + init_adjust_machine_modes (); + init_derived_machine_modes (); + reinit_regs (); + init_optabs (); +} +#endif + +#if CHECKING_P +#undef TARGET_RUN_TARGET_SELFTESTS +#define TARGET_RUN_TARGET_SELFTESTS selftest::riscv_run_selftests +#endif /* #if CHECKING_P */ + /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv index 19736b3a38f..2b82e5f2399 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -23,6 +23,10 @@ riscv-shorten-memrefs.o: $(srcdir)/config/riscv/riscv-shorten-memrefs.cc $(COMPILE) $< $(POSTCOMPILE) +riscv-selftests.o: $(srcdir)/config/riscv/riscv-selftests.cc + $(COMPILE) $< + $(POSTCOMPILE) + PASSES_EXTRA += $(srcdir)/config/riscv/riscv-passes.def $(common_out_file): $(srcdir)/config/riscv/riscv-cores.def \ diff --git a/gcc/testsuite/selftests/riscv/empty-func.rtl b/gcc/testsuite/selftests/riscv/empty-func.rtl new file mode 100644 index 00000000000..f25586cb19a --- /dev/null +++ b/gcc/testsuite/selftests/riscv/empty-func.rtl @@ -0,0 +1,8 @@ +(function "func" + (insn-chain + (block 2 + (edge-from entry (flags "FALLTHRU")) + (edge-to exit (flags "FALLTHRU")) + ) ;; block 2 + ) ;; insn-chain +) ;; function \ No newline at end of file -- 2.36.1