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> ®no_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