From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) by sourceware.org (Postfix) with ESMTPS id 5A7B73857B8D for ; Fri, 23 Sep 2022 15:34:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 5A7B73857B8D Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ed1-x52d.google.com with SMTP id z2so766990edi.1 for ; Fri, 23 Sep 2022 08:34:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date; bh=eE0hIRqNU4OpSNZASFRLYXLGDAyErmgr/4dMklo+Bec=; b=PV0XBEu3LZfDer1N3WiSpqYy3M1XeBwmsVmok1CU4TIS0EFykOAq7RUThrqzTqDx/1 GFPYZ4mhdMo0scYjJ5mb0cfHZ1sVvoUcoAWdrUQQd2qbWhaiOMJbAIpJQKuYNb76Pblu SJvj09MvqgzAoYWNGnqV7CsymoVRf0CZ2TI8Ml/m1VP7/CNkPDnO8zGWBK1ChFOo6GZp bEsScUXYrC2F3YlopLSRWg0OXfGeLI1tBCUlPfRC9OpTjPVLZd9BwXsn72oxxDl+InBY N3UsgtQhneKjWI68PcQ/dhhkDz1wYFJzTXT4bLiEpaX9llmERm0CdkSS4R4o4Vatmebx TfDg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date; bh=eE0hIRqNU4OpSNZASFRLYXLGDAyErmgr/4dMklo+Bec=; b=thFwVYHq9wwajKejLYNprNnZ8zU1VvHBj+Z+/O8AJCKTxSSlQF3e2RVIqyg830HCIA 0L6+A0br/nSIgKxwBeClj//PijTYTSTW4udLQ3sLgoNNX2fx7ws91qqkklKfZzxfhdgR /3tNUgutzrznHkvtyCwGPop77Hmp/1WS3C0VDdxaJCUJqkzi6yW5nn8KDYi946YypPcS eHwKlJVp+Fw5aFsf8gvUK6zNsauT2pL1w0BYJp/5XIm3Fsz0RF7V6Z72OzVOGa63wJn8 XWh8s23qUmvLyYOUOMeiSG68qx4HsMfbi5GZVo00MGHuCU+SzOU9n/60nAA/+ffJzVws IjgA== X-Gm-Message-State: ACrzQf3QNrdr1Y8mE5AsYDdNuClHZ2ccPSa1+d8+EeG0wIdISk1G6lp4 KjPpMhABBNcj4e+rRMSQ/ZUZRkqm7jhASKcHsV8= X-Google-Smtp-Source: AMsMyM7u5c+iZpg8Lz6OL2S/ZklYsSZwAm1VOHxKl9cDOLbLarYeMbCGLBPEyEnVcMp8frI4TV813IZJ6AlaluYBg9Y= X-Received: by 2002:aa7:ca56:0:b0:453:ceea:99d4 with SMTP id j22-20020aa7ca56000000b00453ceea99d4mr9173945edt.54.1663947292463; Fri, 23 Sep 2022 08:34:52 -0700 (PDT) MIME-Version: 1.0 References: <20220915082853.109235-1-juzhe.zhong@rivai.ai> In-Reply-To: <20220915082853.109235-1-juzhe.zhong@rivai.ai> From: Kito Cheng Date: Fri, 23 Sep 2022 23:34:40 +0800 Message-ID: Subject: Re: [PATCH] RISC-V: Support poly move manipulation and selftests. To: juzhe.zhong@rivai.ai Cc: GCC Patches Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-8.2 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,GIT_PATCH_0,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_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: Committed. thanks! On Thu, Sep 15, 2022 at 4:29 PM wrote: > > 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 >