]>
Commit | Line | Data |
---|---|---|
b4feb49c | 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" | |
fa144175 JZZ |
36 | #include "insn-attr.h" |
37 | #include "target.h" | |
38 | #include "optabs.h" | |
b4feb49c | 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 | } | |
fa144175 JZZ |
236 | |
237 | static void | |
238 | run_const_vector_selftests (void) | |
239 | { | |
240 | /* We dont't need to do the redundant tests in different march && mabi. | |
241 | Just pick up the march && mabi which fully support all RVV modes. */ | |
242 | riscv_selftest_arch_abi_setter rv ("rv64imafdcv", ABI_LP64D); | |
243 | rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl")); | |
244 | set_new_first_and_last_insn (NULL, NULL); | |
245 | ||
246 | machine_mode mode; | |
247 | std::vector<HOST_WIDE_INT> worklist = {-111, -17, -16, 7, 15, 16, 111}; | |
248 | ||
249 | FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT) | |
250 | { | |
251 | if (riscv_v_ext_vector_mode_p (mode)) | |
252 | { | |
253 | for (const HOST_WIDE_INT &val : worklist) | |
254 | { | |
255 | start_sequence (); | |
256 | rtx dest = gen_reg_rtx (mode); | |
257 | rtx dup = gen_const_vec_duplicate (mode, GEN_INT (val)); | |
258 | emit_move_insn (dest, dup); | |
259 | rtx_insn *insn = get_last_insn (); | |
260 | rtx src = XEXP (SET_SRC (PATTERN (insn)), 1); | |
261 | /* 1. Should be vmv.v.i for in rang of -16 ~ 15. | |
262 | 2. Should be vmv.v.x for exceed -16 ~ 15. */ | |
263 | if (IN_RANGE (val, -16, 15)) | |
264 | ASSERT_TRUE (rtx_equal_p (src, dup)); | |
265 | else | |
266 | ASSERT_TRUE ( | |
267 | rtx_equal_p (src, | |
268 | gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0)))); | |
269 | end_sequence (); | |
270 | } | |
271 | } | |
272 | } | |
273 | ||
274 | FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_FLOAT) | |
275 | { | |
276 | if (riscv_v_ext_vector_mode_p (mode)) | |
277 | { | |
278 | scalar_mode inner_mode = GET_MODE_INNER (mode); | |
279 | REAL_VALUE_TYPE f = REAL_VALUE_ATOF ("0.2928932", inner_mode); | |
280 | rtx ele = const_double_from_real_value (f, inner_mode); | |
281 | ||
282 | start_sequence (); | |
283 | rtx dest = gen_reg_rtx (mode); | |
284 | rtx dup = gen_const_vec_duplicate (mode, ele); | |
285 | emit_move_insn (dest, dup); | |
286 | rtx_insn *insn = get_last_insn (); | |
287 | rtx src = XEXP (SET_SRC (PATTERN (insn)), 1); | |
288 | /* Should always be vfmv.v.f. */ | |
289 | ASSERT_TRUE ( | |
290 | rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0)))); | |
291 | end_sequence (); | |
292 | } | |
293 | } | |
294 | ||
295 | FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_BOOL) | |
296 | { | |
297 | /* Test vmset.m. */ | |
298 | if (riscv_v_ext_vector_mode_p (mode)) | |
299 | { | |
300 | start_sequence (); | |
301 | rtx dest = gen_reg_rtx (mode); | |
302 | emit_move_insn (dest, CONSTM1_RTX (mode)); | |
303 | rtx_insn *insn = get_last_insn (); | |
304 | rtx src = XEXP (SET_SRC (PATTERN (insn)), 1); | |
305 | ASSERT_TRUE (rtx_equal_p (src, CONSTM1_RTX (mode))); | |
306 | end_sequence (); | |
307 | } | |
308 | } | |
309 | } | |
310 | ||
311 | static void | |
312 | run_broadcast_selftests (void) | |
313 | { | |
314 | /* We dont't need to do the redundant tests in different march && mabi. | |
315 | Just pick up the march && mabi which fully support all RVV modes. */ | |
316 | riscv_selftest_arch_abi_setter rv ("rv64imafdcv", ABI_LP64D); | |
317 | rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl")); | |
318 | set_new_first_and_last_insn (NULL, NULL); | |
319 | ||
320 | machine_mode mode; | |
321 | ||
322 | #define BROADCAST_TEST(MODE_CLASS) \ | |
323 | FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT) \ | |
324 | { \ | |
325 | if (riscv_v_ext_vector_mode_p (mode)) \ | |
326 | { \ | |
327 | rtx_insn *insn; \ | |
328 | rtx src; \ | |
329 | scalar_mode inner_mode = GET_MODE_INNER (mode); \ | |
330 | /* Test vlse.v with zero stride. */ \ | |
331 | start_sequence (); \ | |
332 | rtx addr = gen_reg_rtx (Pmode); \ | |
333 | rtx mem = gen_rtx_MEM (inner_mode, addr); \ | |
334 | expand_vector_broadcast (mode, mem); \ | |
335 | insn = get_last_insn (); \ | |
336 | src = XEXP (SET_SRC (PATTERN (insn)), 1); \ | |
337 | ASSERT_TRUE (MEM_P (XEXP (src, 0))); \ | |
338 | ASSERT_TRUE ( \ | |
339 | rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0)))); \ | |
340 | end_sequence (); \ | |
341 | /* Test vmv.v.x or vfmv.v.f. */ \ | |
342 | start_sequence (); \ | |
343 | rtx reg = gen_reg_rtx (inner_mode); \ | |
344 | expand_vector_broadcast (mode, reg); \ | |
345 | insn = get_last_insn (); \ | |
346 | src = XEXP (SET_SRC (PATTERN (insn)), 1); \ | |
347 | ASSERT_TRUE (REG_P (XEXP (src, 0))); \ | |
348 | ASSERT_TRUE ( \ | |
349 | rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0)))); \ | |
350 | end_sequence (); \ | |
351 | } \ | |
352 | } | |
353 | ||
354 | BROADCAST_TEST (MODE_VECTOR_INT) | |
355 | BROADCAST_TEST (MODE_VECTOR_FLOAT) | |
356 | } | |
357 | ||
b4feb49c | 358 | namespace selftest { |
359 | /* Run all target-specific selftests. */ | |
360 | void | |
361 | riscv_run_selftests (void) | |
362 | { | |
363 | run_poly_int_selftests (); | |
fa144175 JZZ |
364 | run_const_vector_selftests (); |
365 | run_broadcast_selftests (); | |
b4feb49c | 366 | } |
367 | } // namespace selftest | |
368 | #endif /* #if CHECKING_P */ |