Home | History | Annotate | Line # | Download | only in riscv
      1 /* This file is part of GCC.
      2 
      3 GCC is free software; you can redistribute it and/or modify
      4 it under the terms of the GNU General Public License as published by
      5 the Free Software Foundation; either version 3, or (at your option)
      6 any later version.
      7 
      8 GCC is distributed in the hope that it will be useful,
      9 but WITHOUT ANY WARRANTY; without even the implied warranty of
     10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11 GNU General Public License for more details.
     12 
     13 You should have received a copy of the GNU General Public License
     14 along with GCC; see the file COPYING3.  If not see
     15 <http://www.gnu.org/licenses/>.  */
     16 
     17 #define IN_TARGET_CODE 1
     18 
     19 #define INCLUDE_STRING
     20 #define INCLUDE_MAP
     21 #define INCLUDE_VECTOR
     22 #include "config.h"
     23 #include "system.h"
     24 #include "coretypes.h"
     25 #include "tm.h"
     26 #include "rtl.h"
     27 #include "tree.h"
     28 #include "stringpool.h"
     29 #include "function.h"
     30 #include "memmodel.h"
     31 #include "emit-rtl.h"
     32 #include "tm_p.h"
     33 #include "expr.h"
     34 #include "selftest.h"
     35 #include "selftest-rtl.h"
     36 #include "insn-attr.h"
     37 #include "target.h"
     38 #include "optabs.h"
     39 
     40 #if CHECKING_P
     41 using namespace selftest;
     42 class riscv_selftest_arch_abi_setter
     43 {
     44 private:
     45   std::string m_arch_backup;
     46   enum riscv_abi_type m_abi_backup;
     47 
     48 public:
     49   riscv_selftest_arch_abi_setter (const char *arch, enum riscv_abi_type abi)
     50     : m_arch_backup (riscv_arch_str ()), m_abi_backup (riscv_abi)
     51   {
     52     riscv_parse_arch_string (arch, &global_options, UNKNOWN_LOCATION);
     53     riscv_abi = abi;
     54     riscv_reinit ();
     55   }
     56   ~riscv_selftest_arch_abi_setter ()
     57   {
     58     riscv_parse_arch_string (m_arch_backup.c_str (), &global_options,
     59 			     UNKNOWN_LOCATION);
     60     riscv_abi = m_abi_backup;
     61     riscv_reinit ();
     62   }
     63 };
     64 
     65 static poly_int64
     66 eval_value (rtx x, std::map<unsigned, rtx> &regno_to_rtx)
     67 {
     68   if (!REG_P (x))
     69     {
     70       debug (x);
     71       gcc_unreachable ();
     72     }
     73 
     74   rtx expr = NULL_RTX;
     75   unsigned regno = REGNO (x);
     76   expr = regno_to_rtx[regno];
     77 
     78   poly_int64 op1_val = 0;
     79   poly_int64 op2_val = 0;
     80   if (UNARY_P (expr))
     81     {
     82       op1_val = eval_value (XEXP (expr, 0), regno_to_rtx);
     83     }
     84   if (BINARY_P (expr))
     85     {
     86       op1_val = eval_value (XEXP (expr, 0), regno_to_rtx);
     87       op2_val = eval_value (XEXP (expr, 1), regno_to_rtx);
     88     }
     89 
     90   switch (GET_CODE (expr))
     91     {
     92     case CONST_POLY_INT:
     93       return rtx_to_poly_int64 (expr);
     94     case CONST_INT:
     95       return INTVAL (expr);
     96 
     97     case MULT:
     98       if (op1_val.is_constant ())
     99 	return op1_val.to_constant () * op2_val;
    100       else if (op2_val.is_constant ())
    101 	return op1_val * op2_val.to_constant ();
    102       else
    103 	gcc_unreachable ();
    104     case PLUS:
    105       return op1_val + op2_val;
    106     default:
    107       gcc_unreachable ();
    108     }
    109 }
    110 
    111 /* Calculate the value of x register in the sequence.  */
    112 static poly_int64
    113 calculate_x_in_sequence (rtx reg)
    114 {
    115   std::map<unsigned, rtx> regno_to_rtx;
    116   rtx_insn *insn;
    117   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
    118     {
    119       rtx pat = PATTERN (insn);
    120       rtx dest = SET_DEST (pat);
    121 
    122       if (GET_CODE (pat) == CLOBBER)
    123 	continue;
    124 
    125       if (SUBREG_P (dest))
    126 	continue;
    127 
    128       gcc_assert (REG_P (dest));
    129       rtx note = find_reg_equal_equiv_note (insn);
    130       unsigned regno = REGNO (dest);
    131       if (note)
    132 	regno_to_rtx[regno] = XEXP (note, 0);
    133       else
    134 	regno_to_rtx[regno] = SET_SRC (pat);
    135     }
    136 
    137   return eval_value (reg, regno_to_rtx);
    138 }
    139 
    140 typedef enum
    141 {
    142   POLY_TEST_DIMODE,
    143   POLY_TEST_PMODE
    144 } poly_test_mode_t;
    145 
    146 static void
    147 simple_poly_selftest (const char *arch, enum riscv_abi_type abi,
    148 		      const std::vector<machine_mode> &modes)
    149 {
    150   riscv_selftest_arch_abi_setter rv (arch, abi);
    151   rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl"));
    152   set_new_first_and_last_insn (NULL, NULL);
    153 
    154   for (machine_mode mode : modes)
    155     emit_move_insn (gen_reg_rtx (mode),
    156 		    gen_int_mode (BYTES_PER_RISCV_VECTOR, mode));
    157 }
    158 
    159 static void
    160 run_poly_int_selftest (const char *arch, enum riscv_abi_type abi,
    161 		       poly_test_mode_t test_mode,
    162 		       const std::vector<poly_int64> &worklist)
    163 {
    164   riscv_selftest_arch_abi_setter rv (arch, abi);
    165   rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl"));
    166   set_new_first_and_last_insn (NULL, NULL);
    167   machine_mode mode = VOIDmode;
    168 
    169   switch (test_mode)
    170     {
    171     case POLY_TEST_DIMODE:
    172       mode = DImode;
    173       break;
    174     case POLY_TEST_PMODE:
    175       mode = Pmode;
    176       break;
    177     default:
    178       gcc_unreachable ();
    179     }
    180 
    181   for (const poly_int64 &poly_val : worklist)
    182     {
    183       start_sequence ();
    184       rtx dest = gen_reg_rtx (mode);
    185       emit_move_insn (dest, gen_int_mode (poly_val, mode));
    186       ASSERT_TRUE (known_eq (calculate_x_in_sequence (dest), poly_val));
    187       end_sequence ();
    188     }
    189 }
    190 
    191 static void
    192 run_poly_int_selftests (void)
    193 {
    194   std::vector<poly_int64> worklist
    195     = {BYTES_PER_RISCV_VECTOR,	    BYTES_PER_RISCV_VECTOR * 8,
    196        BYTES_PER_RISCV_VECTOR * 32, -BYTES_PER_RISCV_VECTOR * 8,
    197        -BYTES_PER_RISCV_VECTOR * 32, BYTES_PER_RISCV_VECTOR * 7,
    198        BYTES_PER_RISCV_VECTOR * 31, -BYTES_PER_RISCV_VECTOR * 7,
    199        -BYTES_PER_RISCV_VECTOR * 31, BYTES_PER_RISCV_VECTOR * 9,
    200        BYTES_PER_RISCV_VECTOR * 33, -BYTES_PER_RISCV_VECTOR * 9,
    201        -BYTES_PER_RISCV_VECTOR * 33, poly_int64 (207, 0),
    202        poly_int64 (-207, 0),	    poly_int64 (0, 207),
    203        poly_int64 (0, -207),	    poly_int64 (5555, 0),
    204        poly_int64 (0, 5555),	    poly_int64 (4096, 4096),
    205        poly_int64 (17, 4088),	    poly_int64 (3889, 4104),
    206        poly_int64 (-4096, -4096),   poly_int64 (219, -4088),
    207        poly_int64 (-4309, -4104),   poly_int64 (-7337, 88),
    208        poly_int64 (9317, -88),	    poly_int64 (4, 4),
    209        poly_int64 (17, 4),	    poly_int64 (-7337, 4),
    210        poly_int64 (-4, -4),	    poly_int64 (-389, -4),
    211        poly_int64 (4789, -4),	    poly_int64 (-5977, 1508),
    212        poly_int64 (219, -1508),	    poly_int64 (2, 2),
    213        poly_int64 (33, 2),	    poly_int64 (-7337, 2),
    214        poly_int64 (-2, -2),	    poly_int64 (-389, -2),
    215        poly_int64 (4789, -2),	    poly_int64 (-3567, 954),
    216        poly_int64 (945, -954),	    poly_int64 (1, 1),
    217        poly_int64 (977, 1),	    poly_int64 (-339, 1),
    218        poly_int64 (-1, -1),	    poly_int64 (-12, -1),
    219        poly_int64 (44, -1),	    poly_int64 (9567, 77),
    220        poly_int64 (3467, -77)};
    221 
    222   simple_poly_selftest ("rv64imafdv", ABI_LP64D,
    223 			{QImode, HImode, SImode, DImode});
    224   simple_poly_selftest ("rv32imafdv", ABI_ILP32D, {QImode, HImode, SImode});
    225 
    226   run_poly_int_selftest ("rv64imafdv", ABI_LP64D, POLY_TEST_PMODE, worklist);
    227   run_poly_int_selftest ("rv64imafd_zve32x1p0", ABI_LP64D, POLY_TEST_PMODE,
    228 			 worklist);
    229   run_poly_int_selftest ("rv32imafdv", ABI_ILP32, POLY_TEST_PMODE, worklist);
    230   run_poly_int_selftest ("rv32imafdv", ABI_ILP32, POLY_TEST_DIMODE, worklist);
    231   run_poly_int_selftest ("rv32imafd_zve32x1p0", ABI_ILP32D, POLY_TEST_PMODE,
    232 			 worklist);
    233   run_poly_int_selftest ("rv32imafd_zve32x1p0", ABI_ILP32D, POLY_TEST_DIMODE,
    234 			 worklist);
    235   simple_poly_selftest ("rv64imafdv_zvl256b", ABI_LP64D,
    236 			{QImode, HImode, SImode, DImode});
    237   simple_poly_selftest ("rv64imafdv_zvl512b", ABI_LP64D,
    238 			{QImode, HImode, SImode, DImode});
    239   simple_poly_selftest ("rv64imafdv_zvl1024b", ABI_LP64D,
    240 			{QImode, HImode, SImode, DImode});
    241   simple_poly_selftest ("rv64imafdv_zvl2048b", ABI_LP64D,
    242 			{QImode, HImode, SImode, DImode});
    243   simple_poly_selftest ("rv64imafdv_zvl4096b", ABI_LP64D,
    244 			{QImode, HImode, SImode, DImode});
    245 }
    246 
    247 static void
    248 run_const_vector_selftests (void)
    249 {
    250   /* We dont't need to do the redundant tests in different march && mabi.
    251      Just pick up the march && mabi which fully support all RVV modes.  */
    252   riscv_selftest_arch_abi_setter rv ("rv64imafdcv", ABI_LP64D);
    253   rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl"));
    254   set_new_first_and_last_insn (NULL, NULL);
    255 
    256   machine_mode mode;
    257   std::vector<HOST_WIDE_INT> worklist = {-111, -17, -16, 7, 15, 16, 111};
    258 
    259   FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT)
    260     {
    261       if (riscv_v_ext_vector_mode_p (mode))
    262 	{
    263 	  for (const HOST_WIDE_INT &val : worklist)
    264 	    {
    265 	      start_sequence ();
    266 	      rtx dest = gen_reg_rtx (mode);
    267 	      rtx dup = gen_const_vec_duplicate (mode, GEN_INT (val));
    268 	      emit_move_insn (dest, dup);
    269 	      rtx_insn *insn = get_last_insn ();
    270 	      rtx src = SET_SRC (PATTERN (insn));
    271 	      /* 1. Should be vmv.v.i for in rang of -16 ~ 15.
    272 		 2. Should be vmv.v.x for exceed -16 ~ 15.  */
    273 	      if (IN_RANGE (val, -16, 15))
    274 		ASSERT_TRUE (
    275 		  rtx_equal_p (XEXP (SET_SRC (PATTERN (insn)), 1), dup));
    276 	      else
    277 		ASSERT_TRUE (GET_CODE (src) == VEC_DUPLICATE);
    278 	      end_sequence ();
    279 	    }
    280 	}
    281     }
    282 
    283   FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_FLOAT)
    284     {
    285       if (riscv_v_ext_vector_mode_p (mode))
    286 	{
    287 	  scalar_mode inner_mode = GET_MODE_INNER (mode);
    288 	  REAL_VALUE_TYPE f = REAL_VALUE_ATOF ("0.2928932", inner_mode);
    289 	  rtx ele = const_double_from_real_value (f, inner_mode);
    290 
    291 	  start_sequence ();
    292 	  rtx dest = gen_reg_rtx (mode);
    293 	  rtx dup = gen_const_vec_duplicate (mode, ele);
    294 	  emit_move_insn (dest, dup);
    295 	  rtx_insn *insn = get_last_insn ();
    296 	  rtx src = SET_SRC (PATTERN (insn));
    297 	  /* Should always be vfmv.v.f.  */
    298 	  ASSERT_TRUE (GET_CODE (src) == VEC_DUPLICATE);
    299 	  end_sequence ();
    300 	}
    301     }
    302 
    303   FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_BOOL)
    304     {
    305       /* Test vmset.m.  */
    306       if (riscv_v_ext_vector_mode_p (mode))
    307 	{
    308 	  start_sequence ();
    309 	  rtx dest = gen_reg_rtx (mode);
    310 	  emit_move_insn (dest, CONSTM1_RTX (mode));
    311 	  rtx_insn *insn = get_last_insn ();
    312 	  rtx src = XEXP (SET_SRC (PATTERN (insn)), 1);
    313 	  ASSERT_TRUE (rtx_equal_p (src, CONSTM1_RTX (mode)));
    314 	  end_sequence ();
    315 	}
    316     }
    317 }
    318 
    319 static void
    320 run_broadcast_selftests (void)
    321 {
    322   /* We dont't need to do the redundant tests in different march && mabi.
    323      Just pick up the march && mabi which fully support all RVV modes.  */
    324   riscv_selftest_arch_abi_setter rv ("rv64imafdcv", ABI_LP64D);
    325   rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl"));
    326   set_new_first_and_last_insn (NULL, NULL);
    327 
    328   machine_mode mode;
    329 
    330 #define BROADCAST_TEST(MODE_CLASS)                                             \
    331   FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT)                               \
    332     {                                                                          \
    333       if (riscv_v_ext_vector_mode_p (mode))                                    \
    334 	{                                                                      \
    335 	  rtx_insn *insn;                                                      \
    336 	  rtx src;                                                             \
    337 	  scalar_mode inner_mode = GET_MODE_INNER (mode);                      \
    338 	  /* Test vlse.v with zero stride.  */                                 \
    339 	  start_sequence ();                                                   \
    340 	  rtx addr = gen_reg_rtx (Pmode);                                      \
    341 	  rtx mem = gen_rtx_MEM (inner_mode, addr);                            \
    342 	  expand_vector_broadcast (mode, mem);                                 \
    343 	  insn = get_last_insn ();                                             \
    344 	  src = SET_SRC (PATTERN (insn));                                      \
    345 	  ASSERT_TRUE (MEM_P (XEXP (src, 0)));                                 \
    346 	  ASSERT_TRUE (                                                        \
    347 	    rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0))));   \
    348 	  end_sequence ();                                                     \
    349 	  /* Test vmv.v.x or vfmv.v.f.  */                                     \
    350 	  start_sequence ();                                                   \
    351 	  rtx reg = gen_reg_rtx (inner_mode);                                  \
    352 	  expand_vector_broadcast (mode, reg);                                 \
    353 	  insn = get_last_insn ();                                             \
    354 	  src = SET_SRC (PATTERN (insn));                                      \
    355 	  ASSERT_TRUE (REG_P (XEXP (src, 0)));                                 \
    356 	  ASSERT_TRUE (                                                        \
    357 	    rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0))));   \
    358 	  end_sequence ();                                                     \
    359 	}                                                                      \
    360     }
    361 
    362   BROADCAST_TEST (MODE_VECTOR_INT)
    363   BROADCAST_TEST (MODE_VECTOR_FLOAT)
    364 }
    365 
    366 namespace selftest {
    367 /* Run all target-specific selftests.  */
    368 void
    369 riscv_run_selftests (void)
    370 {
    371   if (!BYTES_PER_RISCV_VECTOR.is_constant ())
    372     /* We can know POLY value = [4, 4] when BYTES_PER_RISCV_VECTOR
    373        is !is_constant () since we can use csrr vlenb and scalar shift
    374        instruction to compute such POLY value and store it into a scalar
    375        register.  Wheras, we can't know [4, 4] on it is specified as
    376        FIXED-VLMAX since BYTES_PER_RISCV_VECTOR = 16 for -march=rv64gcv
    377        and csrr vlenb is 16 which is totally unrelated to any
    378        compile-time unknown POLY value.
    379 
    380        Since we never need to compute a compile-time unknown POLY value
    381        when -mrvv-vector-bits=zvl, disable poly
    382        selftests in such situation.  */
    383     run_poly_int_selftests ();
    384   run_const_vector_selftests ();
    385   run_broadcast_selftests ();
    386 }
    387 } // namespace selftest
    388 #endif /* #if CHECKING_P */
    389