public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] RISC-V: Support poly move manipulation and selftests.
@ 2022-09-15  8:28 juzhe.zhong
  2022-09-23 15:34 ` Kito Cheng
  0 siblings, 1 reply; 2+ messages in thread
From: juzhe.zhong @ 2022-09-15  8:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: kito.cheng, palmer, zhongjuzhe

From: zhongjuzhe <juzhe.zhong@rivai.ai>

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
+<http://www.gnu.org/licenses/>.  */
+
+#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 <map>
+#include <vector>
+
+#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<unsigned, rtx> &regno_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<unsigned, rtx> 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<machine_mode> &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<poly_int64> &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<poly_int64> 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 %<target%>"
+			  " 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


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] RISC-V: Support poly move manipulation and selftests.
  2022-09-15  8:28 [PATCH] RISC-V: Support poly move manipulation and selftests juzhe.zhong
@ 2022-09-23 15:34 ` Kito Cheng
  0 siblings, 0 replies; 2+ messages in thread
From: Kito Cheng @ 2022-09-23 15:34 UTC (permalink / raw)
  To: juzhe.zhong; +Cc: GCC Patches

Committed. thanks!

On Thu, Sep 15, 2022 at 4:29 PM <juzhe.zhong@rivai.ai> wrote:
>
> From: zhongjuzhe <juzhe.zhong@rivai.ai>
>
> 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
> +<http://www.gnu.org/licenses/>.  */
> +
> +#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 <map>
> +#include <vector>
> +
> +#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<unsigned, rtx> &regno_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<unsigned, rtx> 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<machine_mode> &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<poly_int64> &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<poly_int64> 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 %<target%>"
> +                         " 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
>

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-09-23 15:34 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-15  8:28 [PATCH] RISC-V: Support poly move manipulation and selftests juzhe.zhong
2022-09-23 15:34 ` Kito Cheng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).