v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
simulator-riscv.cc
Go to the documentation of this file.
1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Copyright(c) 2010 - 2017,
6// The Regents of the University of California(Regents).All Rights Reserved.
7//
8// Redistribution and use in source and binary forms,
9// with or without modification,
10// are permitted provided that the following
11// conditions are met : 1. Redistributions of source code must retain the
12// above copyright notice, this list of conditions and the following
13// disclaimer.2. Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer in
15// the
16// documentation and /
17// or
18// other materials provided with the distribution.3. Neither the name of
19// the Regents nor the names of its contributors may be used to endorse
20// or
21// promote products derived from
22// this software without specific prior written permission.
23//
24// IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
25// INDIRECT, SPECIAL,
26// INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
27// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
28// EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29//
30// REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES,
31// INCLUDING, BUT NOT LIMITED TO,
32// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
33// PARTICULAR PURPOSE.THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
34// IF ANY,
35// PROVIDED HEREUNDER IS PROVIDED
36// "AS IS".REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
37// SUPPORT, UPDATES, ENHANCEMENTS,
38// OR MODIFICATIONS.
39
40// The original source code covered by the above license above has been
41// modified significantly by the v8 project authors.
42
44
45// Only build the simulator if not compiling for real RISCV hardware.
46#if defined(USE_SIMULATOR)
47
48#include <limits.h>
49#include <math.h>
50#include <stdarg.h>
51#include <stdlib.h>
52
53#include "src/base/bits.h"
55#include "src/base/vector.h"
60#include "src/heap/base/stack.h"
63#include "src/utils/ostreams.h"
64#include "src/utils/utils.h"
65
66#if V8_ENABLE_WEBASSEMBLY
68#endif // V8_ENABLE_WEBASSEMBLY
69
70#if V8_TARGET_ARCH_RISCV64
71#define REGIx_FORMAT PRIx64
72#define REGId_FORMAT PRId64
73#elif V8_TARGET_ARCH_RISCV32
74#define REGIx_FORMAT PRIx32
75#define REGId_FORMAT PRId32
76#endif
77
78// The following code about RVV was based from:
79// https://github.com/riscv/riscv-isa-sim
80// Copyright (c) 2010-2017, The Regents of the University of California
81// (Regents). All Rights Reserved.
82
83// Redistribution and use in source and binary forms, with or without
84// modification, are permitted provided that the following conditions are met:
85// 1. Redistributions of source code must retain the above copyright
86// notice, this list of conditions and the following disclaimer.
87// 2. Redistributions in binary form must reproduce the above copyright
88// notice, this list of conditions and the following disclaimer in the
89// documentation and/or other materials provided with the distribution.
90// 3. Neither the name of the Regents nor the
91// names of its contributors may be used to endorse or promote products
92// derived from this software without specific prior written permission.
93
94// IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
95// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
96// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
97// REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
98
99// REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED
100// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
101// PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
102// HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
103// MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
104#ifdef CAN_USE_RVV_INSTRUCTIONS
105static inline bool is_aligned(const unsigned val, const unsigned pos) {
106 return pos ? (val & (pos - 1)) == 0 : true;
107}
108
109static inline bool is_overlapped(const int astart, int asize, const int bstart,
110 int bsize) {
111 asize = asize == 0 ? 1 : asize;
112 bsize = bsize == 0 ? 1 : bsize;
113
114 const int aend = astart + asize;
115 const int bend = bstart + bsize;
116
117 return std::max(aend, bend) - std::min(astart, bstart) < asize + bsize;
118}
119static inline bool is_overlapped_widen(const int astart, int asize,
120 const int bstart, int bsize) {
121 asize = asize == 0 ? 1 : asize;
122 bsize = bsize == 0 ? 1 : bsize;
123
124 const int aend = astart + asize;
125 const int bend = bstart + bsize;
126
127 if (astart < bstart && is_overlapped(astart, asize, bstart, bsize) &&
128 !is_overlapped(astart, asize, bstart + bsize, bsize)) {
129 return false;
130 } else {
131 return std::max(aend, bend) - std::min(astart, bstart) < asize + bsize;
132 }
133}
134
135#ifdef DEBUG
136#define require_align(val, pos) \
137 if (!is_aligned(val, pos)) { \
138 std::cout << val << " " << pos << std::endl; \
139 } \
140 CHECK_EQ(is_aligned(val, pos), true)
141#else
142#define require_align(val, pos) CHECK_EQ(is_aligned(val, pos), true)
143#endif
144
145// RVV
146// The following code about RVV was based from:
147// https://github.com/riscv/riscv-isa-sim
148// Copyright (c) 2010-2017, The Regents of the University of California
149// (Regents). All Rights Reserved.
150
151// Redistribution and use in source and binary forms, with or without
152// modification, are permitted provided that the following conditions are met:
153// 1. Redistributions of source code must retain the above copyright
154// notice, this list of conditions and the following disclaimer.
155// 2. Redistributions in binary form must reproduce the above copyright
156// notice, this list of conditions and the following disclaimer in the
157// documentation and/or other materials provided with the distribution.
158// 3. Neither the name of the Regents nor the
159// names of its contributors may be used to endorse or promote products
160// derived from this software without specific prior written permission.
161
162// IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
163// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
164// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
165// REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
166
167// REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED
168// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
169// PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
170// HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
171// MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
172template <uint64_t N>
173struct type_usew_t;
174template <>
175struct type_usew_t<8> {
176 using type = uint8_t;
177};
178
179template <>
180struct type_usew_t<16> {
181 using type = uint16_t;
182};
183
184template <>
185struct type_usew_t<32> {
186 using type = uint32_t;
187};
188
189template <>
190struct type_usew_t<64> {
191 using type = uint64_t;
192};
193
194template <>
195struct type_usew_t<128> {
196 using type = __uint128_t;
197};
198template <uint64_t N>
199struct type_sew_t;
200
201template <>
202struct type_sew_t<8> {
203 using type = int8_t;
204};
205
206template <>
207struct type_sew_t<16> {
208 using type = int16_t;
209};
210
211template <>
212struct type_sew_t<32> {
213 using type = int32_t;
214};
215
216template <>
217struct type_sew_t<64> {
218 using type = int64_t;
219};
220
221template <>
222struct type_sew_t<128> {
223 using type = __int128_t;
224};
225
226#define VV_PARAMS(x) \
227 type_sew_t<x>::type& vd = \
228 Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
229 type_sew_t<x>::type vs1 = Rvvelt<type_sew_t<x>::type>(rvv_vs1_reg(), i); \
230 type_sew_t<x>::type vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i);
231
232#define VV_UPARAMS(x) \
233 type_usew_t<x>::type& vd = \
234 Rvvelt<type_usew_t<x>::type>(rvv_vd_reg(), i, true); \
235 type_usew_t<x>::type vs1 = Rvvelt<type_usew_t<x>::type>(rvv_vs1_reg(), i); \
236 type_usew_t<x>::type vs2 = Rvvelt<type_usew_t<x>::type>(rvv_vs2_reg(), i);
237
238#define VX_PARAMS(x) \
239 type_sew_t<x>::type& vd = \
240 Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
241 type_sew_t<x>::type rs1 = (type_sew_t<x>::type)(get_register(rs1_reg())); \
242 type_sew_t<x>::type vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i);
243
244#define VX_UPARAMS(x) \
245 type_usew_t<x>::type& vd = \
246 Rvvelt<type_usew_t<x>::type>(rvv_vd_reg(), i, true); \
247 type_usew_t<x>::type rs1 = (type_usew_t<x>::type)(get_register(rs1_reg())); \
248 type_usew_t<x>::type vs2 = Rvvelt<type_usew_t<x>::type>(rvv_vs2_reg(), i);
249
250#define VI_PARAMS(x) \
251 type_sew_t<x>::type& vd = \
252 Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
253 type_sew_t<x>::type simm5 = (type_sew_t<x>::type)(instr_.RvvSimm5()); \
254 type_sew_t<x>::type vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i);
255
256#define VI_UPARAMS(x) \
257 type_usew_t<x>::type& vd = \
258 Rvvelt<type_usew_t<x>::type>(rvv_vd_reg(), i, true); \
259 type_usew_t<x>::type uimm5 = (type_usew_t<x>::type)(instr_.RvvUimm5()); \
260 type_usew_t<x>::type vs2 = Rvvelt<type_usew_t<x>::type>(rvv_vs2_reg(), i);
261
262#define VN_PARAMS(x) \
263 constexpr int half_x = x >> 1; \
264 type_sew_t<half_x>::type& vd = \
265 Rvvelt<type_sew_t<half_x>::type>(rvv_vd_reg(), i, true); \
266 type_sew_t<x>::type uimm5 = (type_sew_t<x>::type)(instr_.RvvUimm5()); \
267 type_sew_t<x>::type vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i);
268
269#define VN_UPARAMS(x) \
270 constexpr int half_x = x >> 1; \
271 type_usew_t<half_x>::type& vd = \
272 Rvvelt<type_usew_t<half_x>::type>(rvv_vd_reg(), i, true); \
273 type_usew_t<x>::type uimm5 = (type_usew_t<x>::type)(instr_.RvvUimm5()); \
274 type_sew_t<x>::type vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i);
275
276#define VXI_PARAMS(x) \
277 type_sew_t<x>::type& vd = \
278 Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
279 type_sew_t<x>::type vs1 = Rvvelt<type_sew_t<x>::type>(rvv_vs1_reg(), i); \
280 type_sew_t<x>::type vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i); \
281 type_sew_t<x>::type rs1 = (type_sew_t<x>::type)(get_register(rs1_reg())); \
282 type_sew_t<x>::type simm5 = (type_sew_t<x>::type)(instr_.RvvSimm5());
283
284#define VI_XI_SLIDEDOWN_PARAMS(x, off) \
285 auto& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
286 auto vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i + off);
287
288#define VI_XI_SLIDEUP_PARAMS(x, offset) \
289 auto& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
290 auto vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i - offset);
291
292#define VX_SLIDE1DOWN_PARAMS(x, off) \
293 auto& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
294 if ((i + off) == rvv_vlmax()) { \
295 type_sew_t<x>::type src = (type_sew_t<x>::type)(get_register(rs1_reg())); \
296 vd = src; \
297 } else { \
298 auto src = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i + off); \
299 vd = src; \
300 }
301
302#define VX_SLIDE1UP_PARAMS(x, offset) \
303 auto& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
304 if (i == 0 && rvv_vstart() == 0) { \
305 type_sew_t<x>::type src = (type_sew_t<x>::type)(get_register(rs1_reg())); \
306 vd = src; \
307 } else { \
308 auto src = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i - offset); \
309 vd = src; \
310 }
311
312#define VF_SLIDE1DOWN_PARAMS(x, offset) \
313 auto& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
314 if ((i + offset) == rvv_vlmax()) { \
315 auto src = base::bit_cast<type_sew_t<x>::type>( \
316 get_fpu_register_Float##x(rs1_reg()).get_bits()); \
317 vd = src; \
318 } else { \
319 auto src = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i + offset); \
320 vd = src; \
321 }
322
323#define VF_SLIDE1UP_PARAMS(x, offset) \
324 auto& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
325 if (i == rvv_vstart() && i == 0) { \
326 auto src = base::bit_cast<type_sew_t<x>::type>( \
327 get_fpu_register_Float##x(rs1_reg()).get_bits()); \
328 vd = src; \
329 } else { \
330 auto src = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i - offset); \
331 vd = src; \
332 }
333
334/* Vector Integer Extension */
335#define VI_VIE_PARAMS(x, scale) \
336 if ((x / scale) < 8) UNREACHABLE(); \
337 auto& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
338 auto vs2 = Rvvelt<type_sew_t<x / scale>::type>(rvv_vs2_reg(), i);
339
340#define VI_VIE_UPARAMS(x, scale) \
341 if ((x / scale) < 8) UNREACHABLE(); \
342 auto& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \
343 auto vs2 = Rvvelt<type_usew_t<x / scale>::type>(rvv_vs2_reg(), i);
344
345#define require_noover(astart, asize, bstart, bsize) \
346 CHECK_EQ(!is_overlapped(astart, asize, bstart, bsize), true)
347#define require_noover_widen(astart, asize, bstart, bsize) \
348 CHECK_EQ(!is_overlapped_widen(astart, asize, bstart, bsize), true)
349
350#define RVV_VI_GENERAL_LOOP_BASE \
351 for (uint64_t i = rvv_vstart(); i < rvv_vl(); i++) {
352#define RVV_VI_LOOP_END \
353 set_rvv_vstart(0); \
354 }
355
356#define RVV_VI_MASK_VARS \
357 const uint8_t midx = i / 64; \
358 const uint8_t mpos = i % 64;
359
360#define RVV_VI_LOOP_MASK_SKIP(BODY) \
361 RVV_VI_MASK_VARS \
362 if (instr_.RvvVM() == 0) { \
363 bool skip = ((Rvvelt<uint64_t>(0, midx) >> mpos) & 0x1) == 0; \
364 if (skip) { \
365 continue; \
366 } \
367 }
368
369#define RVV_VI_VV_LOOP(BODY) \
370 RVV_VI_GENERAL_LOOP_BASE \
371 RVV_VI_LOOP_MASK_SKIP() \
372 if (rvv_vsew() == E8) { \
373 VV_PARAMS(8); \
374 BODY \
375 } else if (rvv_vsew() == E16) { \
376 VV_PARAMS(16); \
377 BODY \
378 } else if (rvv_vsew() == E32) { \
379 VV_PARAMS(32); \
380 BODY \
381 } else if (rvv_vsew() == E64) { \
382 VV_PARAMS(64); \
383 BODY \
384 } else { \
385 UNREACHABLE(); \
386 } \
387 RVV_VI_LOOP_END \
388 rvv_trace_vd();
389
390#define RVV_VI_VV_ULOOP(BODY) \
391 RVV_VI_GENERAL_LOOP_BASE \
392 RVV_VI_LOOP_MASK_SKIP() \
393 if (rvv_vsew() == E8) { \
394 VV_UPARAMS(8); \
395 BODY \
396 } else if (rvv_vsew() == E16) { \
397 VV_UPARAMS(16); \
398 BODY \
399 } else if (rvv_vsew() == E32) { \
400 VV_UPARAMS(32); \
401 BODY \
402 } else if (rvv_vsew() == E64) { \
403 VV_UPARAMS(64); \
404 BODY \
405 } else { \
406 UNREACHABLE(); \
407 } \
408 RVV_VI_LOOP_END \
409 rvv_trace_vd();
410
411#define RVV_VI_VX_LOOP(BODY) \
412 RVV_VI_GENERAL_LOOP_BASE \
413 RVV_VI_LOOP_MASK_SKIP() \
414 if (rvv_vsew() == E8) { \
415 VX_PARAMS(8); \
416 BODY \
417 } else if (rvv_vsew() == E16) { \
418 VX_PARAMS(16); \
419 BODY \
420 } else if (rvv_vsew() == E32) { \
421 VX_PARAMS(32); \
422 BODY \
423 } else if (rvv_vsew() == E64) { \
424 VX_PARAMS(64); \
425 BODY \
426 } else { \
427 UNREACHABLE(); \
428 } \
429 RVV_VI_LOOP_END \
430 rvv_trace_vd();
431
432#define RVV_VI_VX_ULOOP(BODY) \
433 RVV_VI_GENERAL_LOOP_BASE \
434 RVV_VI_LOOP_MASK_SKIP() \
435 if (rvv_vsew() == E8) { \
436 VX_UPARAMS(8); \
437 BODY \
438 } else if (rvv_vsew() == E16) { \
439 VX_UPARAMS(16); \
440 BODY \
441 } else if (rvv_vsew() == E32) { \
442 VX_UPARAMS(32); \
443 BODY \
444 } else if (rvv_vsew() == E64) { \
445 VX_UPARAMS(64); \
446 BODY \
447 } else { \
448 UNREACHABLE(); \
449 } \
450 RVV_VI_LOOP_END \
451 rvv_trace_vd();
452
453#define RVV_VI_VI_LOOP(BODY) \
454 RVV_VI_GENERAL_LOOP_BASE \
455 RVV_VI_LOOP_MASK_SKIP() \
456 if (rvv_vsew() == E8) { \
457 VI_PARAMS(8); \
458 BODY \
459 } else if (rvv_vsew() == E16) { \
460 VI_PARAMS(16); \
461 BODY \
462 } else if (rvv_vsew() == E32) { \
463 VI_PARAMS(32); \
464 BODY \
465 } else if (rvv_vsew() == E64) { \
466 VI_PARAMS(64); \
467 BODY \
468 } else { \
469 UNREACHABLE(); \
470 } \
471 RVV_VI_LOOP_END \
472 rvv_trace_vd();
473
474#define RVV_VI_VI_ULOOP(BODY) \
475 RVV_VI_GENERAL_LOOP_BASE \
476 RVV_VI_LOOP_MASK_SKIP() \
477 if (rvv_vsew() == E8) { \
478 VI_UPARAMS(8); \
479 BODY \
480 } else if (rvv_vsew() == E16) { \
481 VI_UPARAMS(16); \
482 BODY \
483 } else if (rvv_vsew() == E32) { \
484 VI_UPARAMS(32); \
485 BODY \
486 } else if (rvv_vsew() == E64) { \
487 VI_UPARAMS(64); \
488 BODY \
489 } else { \
490 UNREACHABLE(); \
491 } \
492 RVV_VI_LOOP_END \
493 rvv_trace_vd();
494
495// widen operation loop
496
497#define VI_WIDE_CHECK_COMMON \
498 CHECK_LE(rvv_vflmul(), 4); \
499 CHECK_LE(rvv_vsew() * 2, kRvvELEN); \
500 require_align(rvv_vd_reg(), rvv_vflmul() * 2); \
501 require_vm;
502
503#define VI_NARROW_CHECK_COMMON \
504 CHECK_LE(rvv_vflmul(), 4); \
505 CHECK_LE(rvv_vsew() * 2, kRvvELEN); \
506 require_align(rvv_vs2_reg(), rvv_vflmul() * 2); \
507 require_align(rvv_vd_reg(), rvv_vflmul()); \
508 require_vm;
509
510#define RVV_VI_CHECK_SLIDE(is_over) \
511 require_align(rvv_vs2_reg(), rvv_vflmul()); \
512 require_align(rvv_vd_reg(), rvv_vflmul()); \
513 require_vm; \
514 if (is_over) require(rvv_vd_reg() != rvv_vs2_reg());
515
516#define RVV_VI_CHECK_DDS(is_rs) \
517 VI_WIDE_CHECK_COMMON; \
518 require_align(rvv_vs2_reg(), rvv_vflmul() * 2); \
519 if (is_rs) { \
520 require_align(rvv_vs1_reg(), rvv_vflmul()); \
521 if (rvv_vflmul() < 1) { \
522 require_noover(rvv_vd_reg(), rvv_vflmul() * 2, rvv_vs1_reg(), \
523 rvv_vflmul()); \
524 } else { \
525 require_noover_widen(rvv_vd_reg(), rvv_vflmul() * 2, rvv_vs1_reg(), \
526 rvv_vflmul()); \
527 } \
528 }
529
530#define RVV_VI_CHECK_DSS(is_vs1) \
531 VI_WIDE_CHECK_COMMON; \
532 require_align(rvv_vs2_reg(), rvv_vflmul()); \
533 if (rvv_vflmul() < 1) { \
534 require_noover(rvv_vd_reg(), rvv_vflmul() * 2, rvv_vs2_reg(), \
535 rvv_vflmul()); \
536 } else { \
537 require_noover_widen(rvv_vd_reg(), rvv_vflmul() * 2, rvv_vs2_reg(), \
538 rvv_vflmul()); \
539 } \
540 if (is_vs1) { \
541 require_align(rvv_vs1_reg(), rvv_vflmul()); \
542 if (rvv_vflmul() < 1) { \
543 require_noover(rvv_vd_reg(), rvv_vflmul() * 2, rvv_vs1_reg(), \
544 rvv_vflmul()); \
545 } else { \
546 require_noover_widen(rvv_vd_reg(), rvv_vflmul() * 2, rvv_vs1_reg(), \
547 rvv_vflmul()); \
548 } \
549 }
550
551#define RVV_VI_CHECK_SDS(is_vs1) \
552 VI_NARROW_CHECK_COMMON; \
553 if (rvv_vd_reg() != rvv_vs2_reg()) \
554 require_noover(rvv_vd_reg(), rvv_vflmul(), rvv_vs2_reg(), \
555 rvv_vflmul() * 2); \
556 if (is_vs1) require_align(rvv_vs1_reg(), rvv_vflmul());
557
558#define RVV_VI_VV_LOOP_WIDEN(BODY) \
559 RVV_VI_GENERAL_LOOP_BASE \
560 RVV_VI_LOOP_MASK_SKIP() \
561 if (rvv_vsew() == E8) { \
562 VV_PARAMS(8); \
563 BODY; \
564 } else if (rvv_vsew() == E16) { \
565 VV_PARAMS(16); \
566 BODY; \
567 } else if (rvv_vsew() == E32) { \
568 VV_PARAMS(32); \
569 BODY; \
570 } \
571 RVV_VI_LOOP_END \
572 rvv_trace_vd();
573
574#define RVV_VI_VX_LOOP_WIDEN(BODY) \
575 RVV_VI_GENERAL_LOOP_BASE \
576 if (rvv_vsew() == E8) { \
577 VX_PARAMS(8); \
578 BODY; \
579 } else if (rvv_vsew() == E16) { \
580 VX_PARAMS(16); \
581 BODY; \
582 } else if (rvv_vsew() == E32) { \
583 VX_PARAMS(32); \
584 BODY; \
585 } \
586 RVV_VI_LOOP_END \
587 rvv_trace_vd();
588
589#define VI_WIDE_OP_AND_ASSIGN(var0, var1, var2, op0, op1, sign) \
590 switch (rvv_vsew()) { \
591 case E8: { \
592 Rvvelt<uint16_t>(rvv_vd_reg(), i, true) = \
593 op1((sign##16_t)(sign##8_t)var0 op0(sign##16_t)(sign##8_t) var1) + \
594 var2; \
595 } break; \
596 case E16: { \
597 Rvvelt<uint32_t>(rvv_vd_reg(), i, true) = \
598 op1((sign##32_t)(sign##16_t)var0 op0(sign##32_t)(sign##16_t) var1) + \
599 var2; \
600 } break; \
601 default: { \
602 Rvvelt<uint64_t>(rvv_vd_reg(), i, true) = \
603 op1((sign##64_t)(sign##32_t)var0 op0(sign##64_t)(sign##32_t) var1) + \
604 var2; \
605 } break; \
606 }
607
608#define VI_WIDE_WVX_OP(var0, op0, sign) \
609 switch (rvv_vsew()) { \
610 case E8: { \
611 sign##16_t & vd_w = Rvvelt<sign##16_t>(rvv_vd_reg(), i, true); \
612 sign##16_t vs2_w = Rvvelt<sign##16_t>(rvv_vs2_reg(), i); \
613 vd_w = vs2_w op0(sign##16_t)(sign##8_t) var0; \
614 } break; \
615 case E16: { \
616 sign##32_t & vd_w = Rvvelt<sign##32_t>(rvv_vd_reg(), i, true); \
617 sign##32_t vs2_w = Rvvelt<sign##32_t>(rvv_vs2_reg(), i); \
618 vd_w = vs2_w op0(sign##32_t)(sign##16_t) var0; \
619 } break; \
620 default: { \
621 sign##64_t & vd_w = Rvvelt<sign##64_t>(rvv_vd_reg(), i, true); \
622 sign##64_t vs2_w = Rvvelt<sign##64_t>(rvv_vs2_reg(), i); \
623 vd_w = vs2_w op0(sign##64_t)(sign##32_t) var0; \
624 } break; \
625 }
626
627#define RVV_VI_VVXI_MERGE_LOOP(BODY) \
628 RVV_VI_GENERAL_LOOP_BASE \
629 if (rvv_vsew() == E8) { \
630 VXI_PARAMS(8); \
631 BODY; \
632 } else if (rvv_vsew() == E16) { \
633 VXI_PARAMS(16); \
634 BODY; \
635 } else if (rvv_vsew() == E32) { \
636 VXI_PARAMS(32); \
637 BODY; \
638 } else if (rvv_vsew() == E64) { \
639 VXI_PARAMS(64); \
640 BODY; \
641 } \
642 RVV_VI_LOOP_END \
643 rvv_trace_vd();
644
645#define VV_WITH_CARRY_PARAMS(x) \
646 type_sew_t<x>::type vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i); \
647 type_sew_t<x>::type vs1 = Rvvelt<type_sew_t<x>::type>(rvv_vs1_reg(), i); \
648 type_sew_t<x>::type& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true);
649
650#define XI_WITH_CARRY_PARAMS(x) \
651 type_sew_t<x>::type vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i); \
652 type_sew_t<x>::type rs1 = (type_sew_t<x>::type)(get_register(rs1_reg())); \
653 type_sew_t<x>::type simm5 = (type_sew_t<x>::type)instr_.RvvSimm5(); \
654 type_sew_t<x>::type& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true);
655
656// carry/borrow bit loop
657#define RVV_VI_VV_LOOP_WITH_CARRY(BODY) \
658 CHECK_NE(rvv_vd_reg(), 0); \
659 RVV_VI_GENERAL_LOOP_BASE \
660 RVV_VI_MASK_VARS \
661 if (rvv_vsew() == E8) { \
662 VV_WITH_CARRY_PARAMS(8) \
663 BODY; \
664 } else if (rvv_vsew() == E16) { \
665 VV_WITH_CARRY_PARAMS(16) \
666 BODY; \
667 } else if (rvv_vsew() == E32) { \
668 VV_WITH_CARRY_PARAMS(32) \
669 BODY; \
670 } else if (rvv_vsew() == E64) { \
671 VV_WITH_CARRY_PARAMS(64) \
672 BODY; \
673 } \
674 RVV_VI_LOOP_END
675
676#define RVV_VI_XI_LOOP_WITH_CARRY(BODY) \
677 CHECK_NE(rvv_vd_reg(), 0); \
678 RVV_VI_GENERAL_LOOP_BASE \
679 RVV_VI_MASK_VARS \
680 if (rvv_vsew() == E8) { \
681 XI_WITH_CARRY_PARAMS(8) \
682 BODY; \
683 } else if (rvv_vsew() == E16) { \
684 XI_WITH_CARRY_PARAMS(16) \
685 BODY; \
686 } else if (rvv_vsew() == E32) { \
687 XI_WITH_CARRY_PARAMS(32) \
688 BODY; \
689 } else if (rvv_vsew() == E64) { \
690 XI_WITH_CARRY_PARAMS(64) \
691 BODY; \
692 } \
693 RVV_VI_LOOP_END
694
695#define VV_CMP_PARAMS(x) \
696 type_sew_t<x>::type vs1 = Rvvelt<type_sew_t<x>::type>(rvv_vs1_reg(), i); \
697 type_sew_t<x>::type vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i);
698
699#define VX_CMP_PARAMS(x) \
700 type_sew_t<x>::type rs1 = (type_sew_t<x>::type)(get_register(rs1_reg())); \
701 type_sew_t<x>::type vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i);
702
703#define VI_CMP_PARAMS(x) \
704 type_sew_t<x>::type simm5 = (type_sew_t<x>::type)instr_.RvvSimm5(); \
705 type_sew_t<x>::type vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i);
706
707#define VV_UCMP_PARAMS(x) \
708 type_usew_t<x>::type vs1 = Rvvelt<type_usew_t<x>::type>(rvv_vs1_reg(), i); \
709 type_usew_t<x>::type vs2 = Rvvelt<type_usew_t<x>::type>(rvv_vs2_reg(), i);
710
711#define VX_UCMP_PARAMS(x) \
712 type_usew_t<x>::type rs1 = \
713 (type_sew_t<x>::type)(get_register(rvv_vs1_reg())); \
714 type_usew_t<x>::type vs2 = Rvvelt<type_usew_t<x>::type>(rvv_vs2_reg(), i);
715
716#define VI_UCMP_PARAMS(x) \
717 type_usew_t<x>::type uimm5 = (type_usew_t<x>::type)instr_.RvvUimm5(); \
718 type_usew_t<x>::type vs2 = Rvvelt<type_usew_t<x>::type>(rvv_vs2_reg(), i);
719
720#define float32_t float
721#define float64_t double
722
723#define RVV_VI_LOOP_CMP_BASE \
724 CHECK(rvv_vsew() >= E8 && rvv_vsew() <= E64); \
725 for (reg_t i = rvv_vstart(); i < rvv_vl(); ++i) { \
726 RVV_VI_LOOP_MASK_SKIP(); \
727 uint64_t mmask = uint64_t(1) << mpos; \
728 uint64_t& vdi = Rvvelt<uint64_t>(rvv_vd_reg(), midx, true); \
729 uint64_t res = 0;
730
731#define RVV_VI_LOOP_CMP_END \
732 vdi = (vdi & ~mmask) | (((res) << mpos) & mmask); \
733 } \
734 rvv_trace_vd(); \
735 set_rvv_vstart(0);
736
737// comparision result to masking register
738#define RVV_VI_VV_LOOP_CMP(BODY) \
739 RVV_VI_LOOP_CMP_BASE \
740 if (rvv_vsew() == E8) { \
741 VV_CMP_PARAMS(8); \
742 BODY; \
743 } else if (rvv_vsew() == E16) { \
744 VV_CMP_PARAMS(16); \
745 BODY; \
746 } else if (rvv_vsew() == E32) { \
747 VV_CMP_PARAMS(32); \
748 BODY; \
749 } else if (rvv_vsew() == E64) { \
750 VV_CMP_PARAMS(64); \
751 BODY; \
752 } \
753 RVV_VI_LOOP_CMP_END
754
755#define RVV_VI_VX_LOOP_CMP(BODY) \
756 RVV_VI_LOOP_CMP_BASE \
757 if (rvv_vsew() == E8) { \
758 VX_CMP_PARAMS(8); \
759 BODY; \
760 } else if (rvv_vsew() == E16) { \
761 VX_CMP_PARAMS(16); \
762 BODY; \
763 } else if (rvv_vsew() == E32) { \
764 VX_CMP_PARAMS(32); \
765 BODY; \
766 } else if (rvv_vsew() == E64) { \
767 VX_CMP_PARAMS(64); \
768 BODY; \
769 } \
770 RVV_VI_LOOP_CMP_END
771
772#define RVV_VI_VI_LOOP_CMP(BODY) \
773 RVV_VI_LOOP_CMP_BASE \
774 if (rvv_vsew() == E8) { \
775 VI_CMP_PARAMS(8); \
776 BODY; \
777 } else if (rvv_vsew() == E16) { \
778 VI_CMP_PARAMS(16); \
779 BODY; \
780 } else if (rvv_vsew() == E32) { \
781 VI_CMP_PARAMS(32); \
782 BODY; \
783 } else if (rvv_vsew() == E64) { \
784 VI_CMP_PARAMS(64); \
785 BODY; \
786 } \
787 RVV_VI_LOOP_CMP_END
788
789#define RVV_VI_VV_ULOOP_CMP(BODY) \
790 RVV_VI_LOOP_CMP_BASE \
791 if (rvv_vsew() == E8) { \
792 VV_UCMP_PARAMS(8); \
793 BODY; \
794 } else if (rvv_vsew() == E16) { \
795 VV_UCMP_PARAMS(16); \
796 BODY; \
797 } else if (rvv_vsew() == E32) { \
798 VV_UCMP_PARAMS(32); \
799 BODY; \
800 } else if (rvv_vsew() == E64) { \
801 VV_UCMP_PARAMS(64); \
802 BODY; \
803 } \
804 RVV_VI_LOOP_CMP_END
805
806#define RVV_VI_VX_ULOOP_CMP(BODY) \
807 RVV_VI_LOOP_CMP_BASE \
808 if (rvv_vsew() == E8) { \
809 VX_UCMP_PARAMS(8); \
810 BODY; \
811 } else if (rvv_vsew() == E16) { \
812 VX_UCMP_PARAMS(16); \
813 BODY; \
814 } else if (rvv_vsew() == E32) { \
815 VX_UCMP_PARAMS(32); \
816 BODY; \
817 } else if (rvv_vsew() == E64) { \
818 VX_UCMP_PARAMS(64); \
819 BODY; \
820 } \
821 RVV_VI_LOOP_CMP_END
822
823#define RVV_VI_VI_ULOOP_CMP(BODY) \
824 RVV_VI_LOOP_CMP_BASE \
825 if (rvv_vsew() == E8) { \
826 VI_UCMP_PARAMS(8); \
827 BODY; \
828 } else if (rvv_vsew() == E16) { \
829 VI_UCMP_PARAMS(16); \
830 BODY; \
831 } else if (rvv_vsew() == E32) { \
832 VI_UCMP_PARAMS(32); \
833 BODY; \
834 } else if (rvv_vsew() == E64) { \
835 VI_UCMP_PARAMS(64); \
836 BODY; \
837 } \
838 RVV_VI_LOOP_CMP_END
839
840#define RVV_VI_VF_MERGE_LOOP_BASE \
841 for (uint64_t i = rvv_vstart(); i < rvv_vl(); i++) {
842#define RVV_VI_VF_MERGE_LOOP_END \
843 set_rvv_vstart(0); \
844 }
845
846#define RVV_VI_VF_MERGE_LOOP(BODY16, BODY32, BODY64) \
847 RVV_VI_VF_MERGE_LOOP_BASE \
848 switch (rvv_vsew()) { \
849 case E16: { \
850 UNIMPLEMENTED(); \
851 } \
852 case E32: { \
853 int32_t& vd = Rvvelt<int32_t>(rvv_vd_reg(), i, true); \
854 int32_t fs1 = base::bit_cast<int32_t>( \
855 get_fpu_register_Float32(rs1_reg()).get_bits()); \
856 int32_t vs2 = Rvvelt<int32_t>(rvv_vs2_reg(), i); \
857 BODY32; \
858 break; \
859 } \
860 case E64: { \
861 int64_t& vd = Rvvelt<int64_t>(rvv_vd_reg(), i, true); \
862 int64_t fs1 = base::bit_cast<int64_t>( \
863 get_fpu_register_Float64(rs1_reg()).get_bits()); \
864 int64_t vs2 = Rvvelt<int64_t>(rvv_vs2_reg(), i); \
865 BODY64; \
866 break; \
867 } \
868 default: \
869 UNREACHABLE(); \
870 break; \
871 } \
872 RVV_VI_VF_MERGE_LOOP_END \
873 rvv_trace_vd();
874
875#define RVV_VI_VFP_LOOP_BASE \
876 for (uint64_t i = rvv_vstart(); i < rvv_vl(); ++i) { \
877 RVV_VI_LOOP_MASK_SKIP();
878
879#define RVV_VI_VFP_LOOP_END \
880 } \
881 set_rvv_vstart(0);
882
883#define RVV_VI_VFP_VF_LOOP(BODY16, BODY32, BODY64) \
884 RVV_VI_VFP_LOOP_BASE \
885 switch (rvv_vsew()) { \
886 case E16: { \
887 UNIMPLEMENTED(); \
888 } \
889 case E32: { \
890 float& vd = Rvvelt<float>(rvv_vd_reg(), i, true); \
891 float fs1 = get_fpu_register_float(rs1_reg()); \
892 float vs2 = Rvvelt<float>(rvv_vs2_reg(), i); \
893 BODY32; \
894 break; \
895 } \
896 case E64: { \
897 double& vd = Rvvelt<double>(rvv_vd_reg(), i, true); \
898 double fs1 = get_fpu_register_double(rs1_reg()); \
899 double vs2 = Rvvelt<double>(rvv_vs2_reg(), i); \
900 BODY64; \
901 break; \
902 } \
903 default: \
904 UNREACHABLE(); \
905 break; \
906 } \
907 RVV_VI_VFP_LOOP_END \
908 rvv_trace_vd();
909
910#define RVV_VI_VFP_VV_LOOP(BODY16, BODY32, BODY64) \
911 RVV_VI_VFP_LOOP_BASE \
912 switch (rvv_vsew()) { \
913 case E16: { \
914 UNIMPLEMENTED(); \
915 break; \
916 } \
917 case E32: { \
918 float& vd = Rvvelt<float>(rvv_vd_reg(), i, true); \
919 float vs1 = Rvvelt<float>(rvv_vs1_reg(), i); \
920 float vs2 = Rvvelt<float>(rvv_vs2_reg(), i); \
921 BODY32; \
922 break; \
923 } \
924 case E64: { \
925 double& vd = Rvvelt<double>(rvv_vd_reg(), i, true); \
926 double vs1 = Rvvelt<double>(rvv_vs1_reg(), i); \
927 double vs2 = Rvvelt<double>(rvv_vs2_reg(), i); \
928 BODY64; \
929 break; \
930 } \
931 default: \
932 require(0); \
933 break; \
934 } \
935 RVV_VI_VFP_LOOP_END \
936 rvv_trace_vd();
937
938#define RVV_VFSGNJ_VV_VF_LOOP(BODY16, BODY32, BODY64) \
939 RVV_VI_VFP_LOOP_BASE \
940 switch (rvv_vsew()) { \
941 case E16: { \
942 UNIMPLEMENTED(); \
943 break; \
944 } \
945 case E32: { \
946 uint32_t& vd = Rvvelt<uint32_t>(rvv_vd_reg(), i, true); \
947 uint32_t vs1 = Rvvelt<uint32_t>(rvv_vs1_reg(), i); \
948 uint32_t vs2 = Rvvelt<uint32_t>(rvv_vs2_reg(), i); \
949 Float32 fs1 = get_fpu_register_Float32(rs1_reg()); \
950 BODY32; \
951 break; \
952 } \
953 case E64: { \
954 uint64_t& vd = Rvvelt<uint64_t>(rvv_vd_reg(), i, true); \
955 uint64_t vs1 = Rvvelt<uint64_t>(rvv_vs1_reg(), i); \
956 uint64_t vs2 = Rvvelt<uint64_t>(rvv_vs2_reg(), i); \
957 Float64 fs1 = get_fpu_register_Float64(rs1_reg()); \
958 BODY64; \
959 break; \
960 } \
961 default: \
962 require(0); \
963 break; \
964 } \
965 RVV_VI_VFP_LOOP_END \
966 rvv_trace_vd();
967
968#define RVV_VI_VFP_VF_LOOP_WIDEN(BODY32, vs2_is_widen) \
969 RVV_VI_VFP_LOOP_BASE \
970 switch (rvv_vsew()) { \
971 case E16: \
972 case E64: { \
973 UNIMPLEMENTED(); \
974 break; \
975 } \
976 case E32: { \
977 double& vd = Rvvelt<double>(rvv_vd_reg(), i, true); \
978 double fs1 = static_cast<double>(get_fpu_register_float(rs1_reg())); \
979 double vs2 = vs2_is_widen \
980 ? Rvvelt<double>(rvv_vs2_reg(), i) \
981 : static_cast<double>(Rvvelt<float>(rvv_vs2_reg(), i)); \
982 double vs3 = Rvvelt<double>(rvv_vd_reg(), i); \
983 BODY32; \
984 break; \
985 } \
986 default: \
987 UNREACHABLE(); \
988 break; \
989 } \
990 RVV_VI_VFP_LOOP_END \
991 rvv_trace_vd();
992
993#define RVV_VI_VFP_VV_LOOP_WIDEN(BODY32, vs2_is_widen) \
994 RVV_VI_VFP_LOOP_BASE \
995 switch (rvv_vsew()) { \
996 case E16: \
997 case E64: { \
998 UNIMPLEMENTED(); \
999 break; \
1000 } \
1001 case E32: { \
1002 double& vd = Rvvelt<double>(rvv_vd_reg(), i, true); \
1003 double vs2 = vs2_is_widen \
1004 ? static_cast<double>(Rvvelt<double>(rvv_vs2_reg(), i)) \
1005 : static_cast<double>(Rvvelt<float>(rvv_vs2_reg(), i)); \
1006 double vs1 = static_cast<double>(Rvvelt<float>(rvv_vs1_reg(), i)); \
1007 double vs3 = Rvvelt<double>(rvv_vd_reg(), i); \
1008 BODY32; \
1009 break; \
1010 } \
1011 default: \
1012 require(0); \
1013 break; \
1014 } \
1015 RVV_VI_VFP_LOOP_END \
1016 rvv_trace_vd();
1017
1018#define RVV_VI_VFP_VV_ARITH_CHECK_COMPUTE(type, check_fn, op) \
1019 auto fn = [this](type frs1, type frs2) { \
1020 if (check_fn(frs1, frs2)) { \
1021 this->set_fflags(kInvalidOperation); \
1022 return std::numeric_limits<type>::quiet_NaN(); \
1023 } else { \
1024 return frs2 op frs1; \
1025 } \
1026 }; \
1027 auto alu_out = fn(vs1, vs2); \
1028 \
1029 if (std::isnan(alu_out) || std::isnan(vs1) || std::isnan(vs2)) { \
1030 \
1031 if (isSnan(alu_out) || isSnan(vs1) || isSnan(vs2)) \
1032 set_fflags(kInvalidOperation); \
1033 alu_out = std::numeric_limits<type>::quiet_NaN(); \
1034 } \
1035 vd = alu_out;
1036
1037#define RVV_VI_VFP_VF_ARITH_CHECK_COMPUTE(type, check_fn, op) \
1038 auto fn = [this](type frs1, type frs2) { \
1039 if (check_fn(frs1, frs2)) { \
1040 this->set_fflags(kInvalidOperation); \
1041 return std::numeric_limits<type>::quiet_NaN(); \
1042 } else { \
1043 return frs2 op frs1; \
1044 } \
1045 }; \
1046 auto alu_out = fn(fs1, vs2); \
1047 \
1048 if (std::isnan(alu_out) || std::isnan(fs1) || std::isnan(vs2)) { \
1049 \
1050 if (isSnan(alu_out) || isSnan(fs1) || isSnan(vs2)) \
1051 set_fflags(kInvalidOperation); \
1052 alu_out = std::numeric_limits<type>::quiet_NaN(); \
1053 } \
1054 vd = alu_out;
1055
1056#define RVV_VI_VFP_FMA(type, _f1, _f2, _a) \
1057 auto fn = [](type f1, type f2, type a) { return std::fma(f1, f2, a); }; \
1058 vd = CanonicalizeFPUOpFMA<type>(fn, _f1, _f2, _a);
1059
1060#define RVV_VI_VFP_FMA_VV_LOOP(BODY32, BODY64) \
1061 RVV_VI_VFP_LOOP_BASE \
1062 switch (rvv_vsew()) { \
1063 case E16: { \
1064 UNIMPLEMENTED(); \
1065 } \
1066 case E32: { \
1067 float& vd = Rvvelt<float>(rvv_vd_reg(), i, true); \
1068 float vs1 = Rvvelt<float>(rvv_vs1_reg(), i); \
1069 float vs2 = Rvvelt<float>(rvv_vs2_reg(), i); \
1070 BODY32; \
1071 break; \
1072 } \
1073 case E64: { \
1074 double& vd = Rvvelt<double>(rvv_vd_reg(), i, true); \
1075 double vs1 = Rvvelt<double>(rvv_vs1_reg(), i); \
1076 double vs2 = Rvvelt<double>(rvv_vs2_reg(), i); \
1077 BODY64; \
1078 break; \
1079 } \
1080 default: \
1081 require(0); \
1082 break; \
1083 } \
1084 RVV_VI_VFP_LOOP_END \
1085 rvv_trace_vd();
1086
1087#define RVV_VI_VFP_FMA_VF_LOOP(BODY32, BODY64) \
1088 RVV_VI_VFP_LOOP_BASE \
1089 switch (rvv_vsew()) { \
1090 case E16: { \
1091 UNIMPLEMENTED(); \
1092 } \
1093 case E32: { \
1094 float& vd = Rvvelt<float>(rvv_vd_reg(), i, true); \
1095 float fs1 = get_fpu_register_float(rs1_reg()); \
1096 float vs2 = Rvvelt<float>(rvv_vs2_reg(), i); \
1097 BODY32; \
1098 break; \
1099 } \
1100 case E64: { \
1101 double& vd = Rvvelt<double>(rvv_vd_reg(), i, true); \
1102 float fs1 = get_fpu_register_float(rs1_reg()); \
1103 double vs2 = Rvvelt<double>(rvv_vs2_reg(), i); \
1104 BODY64; \
1105 break; \
1106 } \
1107 default: \
1108 require(0); \
1109 break; \
1110 } \
1111 RVV_VI_VFP_LOOP_END \
1112 rvv_trace_vd();
1113
1114#define RVV_VI_VFP_LOOP_CMP_BASE \
1115 for (reg_t i = rvv_vstart(); i < rvv_vl(); ++i) { \
1116 RVV_VI_LOOP_MASK_SKIP(); \
1117 uint64_t mmask = uint64_t(1) << mpos; \
1118 uint64_t& vdi = Rvvelt<uint64_t>(rvv_vd_reg(), midx, true); \
1119 uint64_t res = 0;
1120
1121#define RVV_VI_VFP_LOOP_CMP_END \
1122 switch (rvv_vsew()) { \
1123 case E16: \
1124 case E32: \
1125 case E64: { \
1126 vdi = (vdi & ~mmask) | (((res) << mpos) & mmask); \
1127 break; \
1128 } \
1129 default: \
1130 UNREACHABLE(); \
1131 break; \
1132 } \
1133 } \
1134 set_rvv_vstart(0); \
1135 rvv_trace_vd();
1136
1137#define RVV_VI_VFP_LOOP_CMP(BODY16, BODY32, BODY64, is_vs1) \
1138 RVV_VI_VFP_LOOP_CMP_BASE \
1139 switch (rvv_vsew()) { \
1140 case E16: { \
1141 UNIMPLEMENTED(); \
1142 } \
1143 case E32: { \
1144 float vs2 = Rvvelt<float>(rvv_vs2_reg(), i); \
1145 float vs1 = Rvvelt<float>(rvv_vs1_reg(), i); \
1146 BODY32; \
1147 break; \
1148 } \
1149 case E64: { \
1150 double vs2 = Rvvelt<double>(rvv_vs2_reg(), i); \
1151 double vs1 = Rvvelt<double>(rvv_vs1_reg(), i); \
1152 BODY64; \
1153 break; \
1154 } \
1155 default: \
1156 UNREACHABLE(); \
1157 break; \
1158 } \
1159 RVV_VI_VFP_LOOP_CMP_END
1160
1161// reduction loop - signed
1162#define RVV_VI_LOOP_REDUCTION_BASE(x) \
1163 auto& vd_0_des = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), 0, true); \
1164 auto vd_0_res = Rvvelt<type_sew_t<x>::type>(rvv_vs1_reg(), 0); \
1165 for (uint64_t i = rvv_vstart(); i < rvv_vl(); ++i) { \
1166 RVV_VI_LOOP_MASK_SKIP(); \
1167 auto vs2 = Rvvelt<type_sew_t<x>::type>(rvv_vs2_reg(), i);
1168
1169#define RVV_VI_LOOP_REDUCTION_END(x) \
1170 } \
1171 if (rvv_vl() > 0) { \
1172 vd_0_des = vd_0_res; \
1173 } \
1174 set_rvv_vstart(0);
1175
1176#define REDUCTION_LOOP(x, BODY) \
1177 RVV_VI_LOOP_REDUCTION_BASE(x) \
1178 BODY; \
1179 RVV_VI_LOOP_REDUCTION_END(x)
1180
1181#define RVV_VI_VV_LOOP_REDUCTION(BODY) \
1182 if (rvv_vsew() == E8) { \
1183 REDUCTION_LOOP(8, BODY) \
1184 } else if (rvv_vsew() == E16) { \
1185 REDUCTION_LOOP(16, BODY) \
1186 } else if (rvv_vsew() == E32) { \
1187 REDUCTION_LOOP(32, BODY) \
1188 } else if (rvv_vsew() == E64) { \
1189 REDUCTION_LOOP(64, BODY) \
1190 } \
1191 rvv_trace_vd();
1192
1193#define VI_VFP_LOOP_REDUCTION_BASE(width) \
1194 float##width##_t vd_0 = Rvvelt<float##width##_t>(rvv_vd_reg(), 0); \
1195 float##width##_t vs1_0 = Rvvelt<float##width##_t>(rvv_vs1_reg(), 0); \
1196 vd_0 = vs1_0; \
1197 /*bool is_active = false;*/ \
1198 for (reg_t i = rvv_vstart(); i < rvv_vl(); ++i) { \
1199 RVV_VI_LOOP_MASK_SKIP(); \
1200 float##width##_t vs2 = Rvvelt<float##width##_t>(rvv_vs2_reg(), i); \
1201 /*is_active = true;*/
1202
1203#define VI_VFP_LOOP_REDUCTION_END(x) \
1204 } \
1205 set_rvv_vstart(0); \
1206 if (rvv_vl() > 0) { \
1207 Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), 0, true) = vd_0; \
1208 }
1209
1210#define RVV_VI_VFP_VV_LOOP_REDUCTION(BODY16, BODY32, BODY64) \
1211 if (rvv_vsew() == E16) { \
1212 UNIMPLEMENTED(); \
1213 } else if (rvv_vsew() == E32) { \
1214 VI_VFP_LOOP_REDUCTION_BASE(32) \
1215 BODY32; \
1216 VI_VFP_LOOP_REDUCTION_END(32) \
1217 } else if (rvv_vsew() == E64) { \
1218 VI_VFP_LOOP_REDUCTION_BASE(64) \
1219 BODY64; \
1220 VI_VFP_LOOP_REDUCTION_END(64) \
1221 } \
1222 rvv_trace_vd();
1223
1224// reduction loop - unsgied
1225#define RVV_VI_ULOOP_REDUCTION_BASE(x) \
1226 auto& vd_0_des = Rvvelt<type_usew_t<x>::type>(rvv_vd_reg(), 0, true); \
1227 auto vd_0_res = Rvvelt<type_usew_t<x>::type>(rvv_vs1_reg(), 0); \
1228 for (reg_t i = rvv_vstart(); i < rvv_vl(); ++i) { \
1229 RVV_VI_LOOP_MASK_SKIP(); \
1230 auto vs2 = Rvvelt<type_usew_t<x>::type>(rvv_vs2_reg(), i);
1231
1232#define REDUCTION_ULOOP(x, BODY) \
1233 RVV_VI_ULOOP_REDUCTION_BASE(x) \
1234 BODY; \
1235 RVV_VI_LOOP_REDUCTION_END(x)
1236
1237#define RVV_VI_VV_ULOOP_REDUCTION(BODY) \
1238 if (rvv_vsew() == E8) { \
1239 REDUCTION_ULOOP(8, BODY) \
1240 } else if (rvv_vsew() == E16) { \
1241 REDUCTION_ULOOP(16, BODY) \
1242 } else if (rvv_vsew() == E32) { \
1243 REDUCTION_ULOOP(32, BODY) \
1244 } else if (rvv_vsew() == E64) { \
1245 REDUCTION_ULOOP(64, BODY) \
1246 } \
1247 rvv_trace_vd();
1248
1249#define VI_STRIP(inx) reg_t vreg_inx = inx;
1250
1251#define VI_ELEMENT_SKIP(inx) \
1252 if (inx >= vl) { \
1253 continue; \
1254 } else if (inx < rvv_vstart()) { \
1255 continue; \
1256 } else { \
1257 RVV_VI_LOOP_MASK_SKIP(); \
1258 }
1259
1260#define require_vm \
1261 do { \
1262 if (instr_.RvvVM() == 0) CHECK_NE(rvv_vd_reg(), 0); \
1263 } while (0);
1264
1265#define VI_CHECK_STORE(elt_width, is_mask_ldst) \
1266 reg_t veew = is_mask_ldst ? 1 : sizeof(elt_width##_t) * 8;
1267// float vemul = is_mask_ldst ? 1 : ((float)veew / rvv_vsew() * Rvvvflmul);
1268// reg_t emul = vemul < 1 ? 1 : vemul;
1269// require(vemul >= 0.125 && vemul <= 8);
1270// require_align(rvv_rd(), vemul);
1271// require((nf * emul) <= (NVPR / 4) && (rvv_rd() + nf * emul) <= NVPR);
1272
1273#define VI_CHECK_LOAD(elt_width, is_mask_ldst) \
1274 VI_CHECK_STORE(elt_width, is_mask_ldst); \
1275 require_vm;
1276
1277/*vd + fn * emul*/
1278#define RVV_VI_LD(stride, offset, elt_width, is_mask_ldst) \
1279 const reg_t nf = rvv_nf() + 1; \
1280 const reg_t vl = is_mask_ldst ? ((rvv_vl() + 7) / 8) : rvv_vl(); \
1281 const int64_t baseAddr = rs1(); \
1282 for (reg_t i = 0; i < vl; ++i) { \
1283 VI_ELEMENT_SKIP(i); \
1284 VI_STRIP(i); \
1285 set_rvv_vstart(i); \
1286 for (reg_t fn = 0; fn < nf; ++fn) { \
1287 auto addr = baseAddr + (stride) + (offset) * sizeof(elt_width##_t); \
1288 if (!ProbeMemory(addr, sizeof(elt_width##_t))) { \
1289 set_rvv_vstart(0); \
1290 return true; \
1291 } \
1292 auto val = ReadMem<elt_width##_t>(addr, instr_.instr()); \
1293 type_sew_t<sizeof(elt_width##_t) * 8>::type& vd = \
1294 Rvvelt<type_sew_t<sizeof(elt_width##_t) * 8>::type>(rvv_vd_reg(), \
1295 vreg_inx, true); \
1296 vd = val; \
1297 } \
1298 } \
1299 set_rvv_vstart(0); \
1300 if (v8_flags.trace_sim) { \
1301 __int128_t value = Vregister_[rvv_vd_reg()]; \
1302 SNPrintF(trace_buf_, \
1303 "%016" PRIx64 "%016" PRIx64 " (%" PRId64 ") vlen:%" PRId64 \
1304 " <-- [addr: %" REGIx_FORMAT "]", \
1305 *(reinterpret_cast<int64_t*>(&value) + 1), \
1306 *reinterpret_cast<int64_t*>(&value), icount_, rvv_vlen(), \
1307 (sreg_t)(get_register(rs1_reg()))); \
1308 }
1309
1310#define RVV_VI_ST(stride, offset, elt_width, is_mask_ldst) \
1311 const reg_t nf = rvv_nf() + 1; \
1312 const reg_t vl = is_mask_ldst ? ((rvv_vl() + 7) / 8) : rvv_vl(); \
1313 const int64_t baseAddr = rs1(); \
1314 for (reg_t i = 0; i < vl; ++i) { \
1315 VI_STRIP(i) \
1316 VI_ELEMENT_SKIP(i); \
1317 set_rvv_vstart(i); \
1318 for (reg_t fn = 0; fn < nf; ++fn) { \
1319 auto addr = baseAddr + (stride) + (offset) * sizeof(elt_width##_t); \
1320 if (!ProbeMemory(addr, sizeof(elt_width##_t))) { \
1321 set_rvv_vstart(0); \
1322 return true; \
1323 } \
1324 elt_width##_t vs1 = Rvvelt<type_sew_t<sizeof(elt_width##_t) * 8>::type>( \
1325 rvv_vs3_reg(), vreg_inx); \
1326 WriteMem(addr, vs1, instr_.instr()); \
1327 } \
1328 } \
1329 set_rvv_vstart(0); \
1330 if (v8_flags.trace_sim) { \
1331 __int128_t value = Vregister_[rvv_vd_reg()]; \
1332 SNPrintF(trace_buf_, \
1333 "%016" PRIx64 "%016" PRIx64 " (%" PRId64 ") vlen:%" PRId64 \
1334 " --> [addr: %" REGIx_FORMAT "]", \
1335 *(reinterpret_cast<int64_t*>(&value) + 1), \
1336 *reinterpret_cast<int64_t*>(&value), icount_, rvv_vlen(), \
1337 (sreg_t)(get_register(rs1_reg()))); \
1338 }
1339
1340#define VI_VFP_LOOP_SCALE_BASE \
1341 /*require(STATE.frm < 0x5);*/ \
1342 for (reg_t i = rvv_vstart(); i < rvv_vl(); ++i) { \
1343 RVV_VI_LOOP_MASK_SKIP();
1344
1345#define RVV_VI_VFP_CVT_SCALE(BODY8, BODY16, BODY32, CHECK8, CHECK16, CHECK32, \
1346 is_widen, eew_check) \
1347 if (is_widen) { \
1348 RVV_VI_CHECK_DSS(false); \
1349 } else { \
1350 RVV_VI_CHECK_SDS(false); \
1351 } \
1352 CHECK(eew_check); \
1353 switch (rvv_vsew()) { \
1354 case E8: { \
1355 CHECK8 \
1356 VI_VFP_LOOP_SCALE_BASE \
1357 BODY8 /*set_fp_exceptions*/; \
1358 RVV_VI_VFP_LOOP_END \
1359 } break; \
1360 case E16: { \
1361 CHECK16 \
1362 VI_VFP_LOOP_SCALE_BASE \
1363 BODY16 /*set_fp_exceptions*/; \
1364 RVV_VI_VFP_LOOP_END \
1365 } break; \
1366 case E32: { \
1367 CHECK32 \
1368 VI_VFP_LOOP_SCALE_BASE \
1369 BODY32 /*set_fp_exceptions*/; \
1370 RVV_VI_VFP_LOOP_END \
1371 } break; \
1372 default: \
1373 require(0); \
1374 break; \
1375 } \
1376 rvv_trace_vd();
1377
1378// calculate the value of r used in rounding
1379static inline uint8_t get_round(int vxrm, uint64_t v, uint8_t shift) {
1380 uint8_t d = v8::internal::unsigned_bitextract_64(shift, shift, v);
1381 uint8_t d1;
1382 uint64_t D1, D2;
1383
1384 if (shift == 0 || shift > 64) {
1385 return 0;
1386 }
1387
1388 d1 = v8::internal::unsigned_bitextract_64(shift - 1, shift - 1, v);
1389 D1 = v8::internal::unsigned_bitextract_64(shift - 1, 0, v);
1390 if (vxrm == 0) { /* round-to-nearest-up (add +0.5 LSB) */
1391 return d1;
1392 } else if (vxrm == 1) { /* round-to-nearest-even */
1393 if (shift > 1) {
1394 D2 = v8::internal::unsigned_bitextract_64(shift - 2, 0, v);
1395 return d1 & ((D2 != 0) | d);
1396 } else {
1397 return d1 & d;
1398 }
1399 } else if (vxrm == 3) { /* round-to-odd (OR bits into LSB, aka "jam") */
1400 return !d & (D1 != 0);
1401 }
1402 return 0; /* round-down (truncate) */
1403}
1404
1405template <typename Src, typename Dst>
1406inline Dst signed_saturation(Src v, uint n) {
1407 Dst smax = (Dst)(INTPTR_MAX >> (sizeof(intptr_t) * 8 - n));
1408 Dst smin = (Dst)(INTPTR_MIN >> (sizeof(intptr_t) * 8 - n));
1409 return (v > smax) ? smax : ((v < smin) ? smin : (Dst)v);
1410}
1411
1412template <typename Src, typename Dst>
1413inline Dst unsigned_saturation(Src v, uint n) {
1414 Dst umax = (Dst)(UINTPTR_MAX >> (sizeof(uintptr_t) * 8 - n));
1415 return (v > umax) ? umax : ((v < 0) ? 0 : (Dst)v);
1416}
1417
1418#define RVV_VN_CLIPU_VI_LOOP() \
1419 RVV_VI_GENERAL_LOOP_BASE \
1420 RVV_VI_LOOP_MASK_SKIP() \
1421 if (rvv_vsew() == E8) { \
1422 VN_UPARAMS(16); \
1423 vd = unsigned_saturation<uint16_t, uint8_t>( \
1424 (static_cast<uint16_t>(vs2) >> uimm5) + \
1425 get_round(static_cast<int>(rvv_vxrm()), vs2, uimm5), \
1426 8); \
1427 } else if (rvv_vsew() == E16) { \
1428 VN_UPARAMS(32); \
1429 vd = unsigned_saturation<uint32_t, uint16_t>( \
1430 (static_cast<uint32_t>(vs2) >> uimm5) + \
1431 get_round(static_cast<int>(rvv_vxrm()), vs2, uimm5), \
1432 16); \
1433 } else if (rvv_vsew() == E32) { \
1434 VN_UPARAMS(64); \
1435 vd = unsigned_saturation<uint64_t, uint32_t>( \
1436 (static_cast<uint64_t>(vs2) >> uimm5) + \
1437 get_round(static_cast<int>(rvv_vxrm()), vs2, uimm5), \
1438 32); \
1439 } else if (rvv_vsew() == E64) { \
1440 UNREACHABLE(); \
1441 } else { \
1442 UNREACHABLE(); \
1443 } \
1444 RVV_VI_LOOP_END \
1445 rvv_trace_vd();
1446
1447#define RVV_VN_CLIP_VI_LOOP() \
1448 RVV_VI_GENERAL_LOOP_BASE \
1449 RVV_VI_LOOP_MASK_SKIP() \
1450 if (rvv_vsew() == E8) { \
1451 VN_PARAMS(16); \
1452 vd = signed_saturation<int16_t, int8_t>( \
1453 (vs2 >> uimm5) + get_round(static_cast<int>(rvv_vxrm()), vs2, uimm5), \
1454 8); \
1455 } else if (rvv_vsew() == E16) { \
1456 VN_PARAMS(32); \
1457 vd = signed_saturation<int32_t, int16_t>( \
1458 (vs2 >> uimm5) + get_round(static_cast<int>(rvv_vxrm()), vs2, uimm5), \
1459 16); \
1460 } else if (rvv_vsew() == E32) { \
1461 VN_PARAMS(64); \
1462 vd = signed_saturation<int64_t, int32_t>( \
1463 (vs2 >> uimm5) + get_round(static_cast<int>(rvv_vxrm()), vs2, uimm5), \
1464 32); \
1465 } else if (rvv_vsew() == E64) { \
1466 UNREACHABLE(); \
1467 } else { \
1468 UNREACHABLE(); \
1469 } \
1470 RVV_VI_LOOP_END \
1471 rvv_trace_vd();
1472
1473#define CHECK_EXT(div) \
1474 CHECK_NE(rvv_vd_reg(), rvv_vs2_reg()); \
1475 reg_t from = rvv_vsew() / div; \
1476 CHECK(from >= E8 && from <= E64); \
1477 CHECK_GE((float)rvv_vflmul() / div, 0.125); \
1478 CHECK_LE((float)rvv_vflmul() / div, 8); \
1479 require_align(rvv_vd_reg(), rvv_vflmul()); \
1480 require_align(rvv_vs2_reg(), rvv_vflmul() / div); \
1481 if ((rvv_vflmul() / div) < 1) { \
1482 require_noover(rvv_vd_reg(), rvv_vflmul(), rvv_vs2_reg(), \
1483 rvv_vflmul() / div); \
1484 } else { \
1485 require_noover_widen(rvv_vd_reg(), rvv_vflmul(), rvv_vs2_reg(), \
1486 rvv_vflmul() / div); \
1487 }
1488
1489#define RVV_VI_VIE_8_LOOP(signed) \
1490 CHECK_EXT(8) \
1491 RVV_VI_GENERAL_LOOP_BASE \
1492 RVV_VI_LOOP_MASK_SKIP() \
1493 if (rvv_vsew() == E64) { \
1494 if (signed) { \
1495 VI_VIE_PARAMS(64, 8); \
1496 vd = static_cast<int64_t>(vs2); \
1497 } else { \
1498 VI_VIE_UPARAMS(64, 8); \
1499 vd = static_cast<uint64_t>(vs2); \
1500 } \
1501 } else { \
1502 UNREACHABLE(); \
1503 } \
1504 RVV_VI_LOOP_END \
1505 rvv_trace_vd();
1506
1507#define RVV_VI_VIE_4_LOOP(signed) \
1508 CHECK_EXT(4) \
1509 RVV_VI_GENERAL_LOOP_BASE \
1510 RVV_VI_LOOP_MASK_SKIP() \
1511 if (rvv_vsew() == E32) { \
1512 if (signed) { \
1513 VI_VIE_PARAMS(32, 4); \
1514 vd = static_cast<int32_t>(vs2); \
1515 } else { \
1516 VI_VIE_UPARAMS(32, 4); \
1517 vd = static_cast<uint32_t>(vs2); \
1518 } \
1519 } else if (rvv_vsew() == E64) { \
1520 if (signed) { \
1521 VI_VIE_PARAMS(64, 4); \
1522 vd = static_cast<int64_t>(vs2); \
1523 } else { \
1524 VI_VIE_UPARAMS(64, 4); \
1525 vd = static_cast<uint64_t>(vs2); \
1526 } \
1527 } else { \
1528 UNREACHABLE(); \
1529 } \
1530 RVV_VI_LOOP_END \
1531 rvv_trace_vd();
1532
1533#define RVV_VI_VIE_2_LOOP(signed) \
1534 CHECK_EXT(2) \
1535 RVV_VI_GENERAL_LOOP_BASE \
1536 RVV_VI_LOOP_MASK_SKIP() \
1537 if (rvv_vsew() == E16) { \
1538 if (signed) { \
1539 VI_VIE_PARAMS(16, 2); \
1540 vd = static_cast<int16_t>(vs2); \
1541 } else { \
1542 VI_VIE_UPARAMS(16, 2); \
1543 vd = static_cast<uint16_t>(vs2); \
1544 } \
1545 } else if (rvv_vsew() == E32) { \
1546 if (signed) { \
1547 VI_VIE_PARAMS(32, 2); \
1548 vd = static_cast<int32_t>(vs2); \
1549 } else { \
1550 VI_VIE_UPARAMS(32, 2); \
1551 vd = static_cast<uint32_t>(vs2); \
1552 } \
1553 } else if (rvv_vsew() == E64) { \
1554 if (signed) { \
1555 VI_VIE_PARAMS(64, 2); \
1556 vd = static_cast<int64_t>(vs2); \
1557 } else { \
1558 VI_VIE_UPARAMS(64, 2); \
1559 vd = static_cast<uint64_t>(vs2); \
1560 } \
1561 } else { \
1562 UNREACHABLE(); \
1563 } \
1564 RVV_VI_LOOP_END \
1565 rvv_trace_vd();
1566#endif
1567
1568namespace v8 {
1569namespace internal {
1570
1571DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,
1572 Simulator::GlobalMonitor::Get)
1573
1574// Util functions.
1575inline bool HaveSameSign(int64_t a, int64_t b) { return ((a ^ b) >= 0); }
1576
1577uint32_t get_fcsr_condition_bit(uint32_t cc) {
1578 if (cc == 0) {
1579 return 23;
1580 } else {
1581 return 24 + cc;
1582 }
1583}
1584
1585// Generated by Assembler::break_()/stop(), ebreak code is passed as immediate
1586// field of a subsequent LUI instruction; otherwise returns -1
1587static inline int32_t get_ebreak_code(Instruction* instr) {
1589 uint8_t* cur = reinterpret_cast<uint8_t*>(instr);
1590 Instruction* next_instr = reinterpret_cast<Instruction*>(cur + kInstrSize);
1591 if (next_instr->BaseOpcodeFieldRaw() == LUI)
1592 return (next_instr->Imm20UValue());
1593 else
1594 return -1;
1595}
1596
1597// This macro provides a platform independent use of sscanf. The reason for
1598// SScanF not being implemented in a platform independent was through
1599// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
1600// Library does not provide vsscanf.
1601#define SScanF sscanf
1602
1603// The RiscvDebugger class is used by the simulator while debugging simulated
1604// code.
1605class RiscvDebugger {
1606 public:
1607 explicit RiscvDebugger(Simulator* sim) : sim_(sim) {}
1608
1609 void Debug();
1610 // Print all registers with a nice formatting.
1611 void PrintRegs(char name_prefix, int start_index, int end_index);
1612 void PrintAllRegs();
1613 void PrintAllRegsIncludingFPU();
1614
1615 static const Instr kNopInstr = 0x0;
1616
1617 private:
1618 Simulator* sim_;
1619
1620 sreg_t GetRegisterValue(int regnum);
1621 int64_t GetFPURegisterValue(int regnum);
1622 float GetFPURegisterValueFloat(int regnum);
1623 double GetFPURegisterValueDouble(int regnum);
1624#ifdef CAN_USE_RVV_INSTRUCTIONS
1625 __int128_t GetVRegisterValue(int regnum);
1626#endif
1627 bool GetValue(const char* desc, sreg_t* value);
1628};
1629
1630#define UNSUPPORTED() \
1631 v8::base::EmbeddedVector<char, 256> buffer; \
1632 disasm::NameConverter converter; \
1633 disasm::Disassembler dasm(converter); \
1634 dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(&instr_)); \
1635 printf("Sim: Unsupported inst. Func:%s Line:%d PC:0x%" REGIx_FORMAT, \
1636 __FUNCTION__, __LINE__, get_pc()); \
1637 PrintF(" %-44s\n", buffer.begin()); \
1638 base::OS::Abort();
1639
1640sreg_t RiscvDebugger::GetRegisterValue(int regnum) {
1641 if (regnum == kNumSimuRegisters) {
1642 return sim_->get_pc();
1643 } else {
1644 return sim_->get_register(regnum);
1645 }
1646}
1647
1648int64_t RiscvDebugger::GetFPURegisterValue(int regnum) {
1649 if (regnum == kNumFPURegisters) {
1650 return sim_->get_pc();
1651 } else {
1652 return sim_->get_fpu_register(regnum);
1653 }
1654}
1655
1656float RiscvDebugger::GetFPURegisterValueFloat(int regnum) {
1657 if (regnum == kNumFPURegisters) {
1658 return sim_->get_pc();
1659 } else {
1660 return sim_->get_fpu_register_float(regnum);
1661 }
1662}
1663
1664double RiscvDebugger::GetFPURegisterValueDouble(int regnum) {
1665 if (regnum == kNumFPURegisters) {
1666 return sim_->get_pc();
1667 } else {
1668 return sim_->get_fpu_register_double(regnum);
1669 }
1670}
1671
1672#ifdef CAN_USE_RVV_INSTRUCTIONS
1673__int128_t RiscvDebugger::GetVRegisterValue(int regnum) {
1674 if (regnum == kNumVRegisters) {
1675 return sim_->get_pc();
1676 } else {
1677 return sim_->get_vregister(regnum);
1678 }
1679}
1680#endif
1681
1682bool RiscvDebugger::GetValue(const char* desc, sreg_t* value) {
1683 int regnum = Registers::Number(desc);
1684 int fpuregnum = FPURegisters::Number(desc);
1685
1686 if (regnum != kInvalidRegister) {
1687 *value = GetRegisterValue(regnum);
1688 return true;
1689 } else if (fpuregnum != kInvalidFPURegister) {
1690 *value = GetFPURegisterValue(fpuregnum);
1691 return true;
1692 } else if (strncmp(desc, "0x", 2) == 0) {
1693#if V8_TARGET_ARCH_RISCV64
1694 return SScanF(desc + 2, "%" SCNx64, reinterpret_cast<reg_t*>(value)) == 1;
1695#elif V8_TARGET_ARCH_RISCV32
1696 return SScanF(desc + 2, "%" SCNx32, reinterpret_cast<reg_t*>(value)) == 1;
1697#endif
1698 } else {
1699#if V8_TARGET_ARCH_RISCV64
1700 return SScanF(desc, "%" SCNu64, reinterpret_cast<reg_t*>(value)) == 1;
1701#elif V8_TARGET_ARCH_RISCV32
1702 return SScanF(desc, "%" SCNu32, reinterpret_cast<reg_t*>(value)) == 1;
1703#endif
1704 }
1705}
1706
1707#define REG_INFO(name) \
1708 name, GetRegisterValue(Registers::Number(name)), \
1709 GetRegisterValue(Registers::Number(name))
1710
1711void RiscvDebugger::PrintRegs(char name_prefix, int start_index,
1712 int end_index) {
1713 base::EmbeddedVector<char, 10> name1, name2;
1714 DCHECK(name_prefix == 'a' || name_prefix == 't' || name_prefix == 's');
1715 DCHECK(start_index >= 0 && end_index <= 99);
1716 int num_registers = (end_index - start_index) + 1;
1717 for (int i = 0; i < num_registers / 2; i++) {
1718 SNPrintF(name1, "%c%d", name_prefix, start_index + 2 * i);
1719 SNPrintF(name2, "%c%d", name_prefix, start_index + 2 * i + 1);
1720 PrintF("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT
1721 " \t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT " \n",
1722 REG_INFO(name1.begin()), REG_INFO(name2.begin()));
1723 }
1724 if (num_registers % 2 == 1) {
1725 SNPrintF(name1, "%c%d", name_prefix, end_index);
1726 PrintF("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT " \n",
1727 REG_INFO(name1.begin()));
1728 }
1729}
1730
1731void RiscvDebugger::PrintAllRegs() {
1732 PrintF("\n");
1733 // ra, sp, gp
1734 PrintF("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT
1735 "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT
1736 "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT "\n",
1737 REG_INFO("ra"), REG_INFO("sp"), REG_INFO("gp"));
1738
1739 // tp, fp, pc
1740 PrintF("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT
1741 "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT
1742 "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT "\n",
1743 REG_INFO("tp"), REG_INFO("fp"), REG_INFO("pc"));
1744
1745 // print register a0, .., a7
1746 PrintRegs('a', 0, 7);
1747 // print registers s1, ..., s11
1748 PrintRegs('s', 1, 11);
1749 // print registers t0, ..., t6
1750 PrintRegs('t', 0, 6);
1751}
1752
1753#undef REG_INFO
1754
1755void RiscvDebugger::PrintAllRegsIncludingFPU() {
1756#define FPU_REG_INFO(n) \
1757 FPURegisters::Name(n), GetFPURegisterValue(n), GetFPURegisterValueDouble(n)
1758
1759 PrintAllRegs();
1760
1761 PrintF("\n\n");
1762 // f0, f1, f2, ... f31.
1764 for (int i = 0; i < kNumFPURegisters; i += 2)
1765 PrintF("%3s: 0x%016" PRIx64 " %16.4e \t%3s: 0x%016" PRIx64 " %16.4e\n",
1766 FPU_REG_INFO(i), FPU_REG_INFO(i + 1));
1767#undef FPU_REG_INFO
1768}
1769
1770void RiscvDebugger::Debug() {
1771 intptr_t last_pc = -1;
1772 bool done = false;
1773
1774#define COMMAND_SIZE 63
1775#define ARG_SIZE 255
1776
1777#define STR(a) #a
1778#define XSTR(a) STR(a)
1779
1780 char cmd[COMMAND_SIZE + 1];
1781 char arg1[ARG_SIZE + 1];
1782 char arg2[ARG_SIZE + 1];
1783 char* argv[3] = {cmd, arg1, arg2};
1784
1785 // Make sure to have a proper terminating character if reaching the limit.
1786 cmd[COMMAND_SIZE] = 0;
1787 arg1[ARG_SIZE] = 0;
1788 arg2[ARG_SIZE] = 0;
1789
1790 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
1791 if (last_pc != sim_->get_pc()) {
1792 disasm::NameConverter converter;
1793 disasm::Disassembler dasm(converter);
1794 // Use a reasonably large buffer.
1796 const char* name = sim_->builtins_.Lookup((Address)sim_->get_pc());
1797 if (name != nullptr) {
1798 PrintF("Call builtin: %s\n", name);
1799 }
1800 dasm.InstructionDecode(buffer,
1801 reinterpret_cast<uint8_t*>(sim_->get_pc()));
1802 PrintF(" 0x%016" REGIx_FORMAT " %s\n", sim_->get_pc(), buffer.begin());
1803 last_pc = sim_->get_pc();
1804 }
1805 char* line = ReadLine("sim> ");
1806 if (line == nullptr) {
1807 break;
1808 } else {
1809 char* last_input = sim_->last_debugger_input();
1810 if (strcmp(line, "\n") == 0 && last_input != nullptr) {
1811 line = last_input;
1812 } else {
1813 // Ownership is transferred to sim_;
1814 sim_->set_last_debugger_input(line);
1815 }
1816 // Use sscanf to parse the individual parts of the command line. At the
1817 // moment no command expects more than two parameters.
1818 int argc = SScanF(
1819 line,
1820 "%" XSTR(COMMAND_SIZE) "s "
1821 "%" XSTR(ARG_SIZE) "s "
1822 "%" XSTR(ARG_SIZE) "s",
1823 cmd, arg1, arg2);
1824 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
1825 Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
1826 if (!(instr->IsTrap()) ||
1828 sim_->icount_++;
1829 sim_->InstructionDecode(
1830 reinterpret_cast<Instruction*>(sim_->get_pc()));
1831 } else {
1832 // Allow si to jump over generated breakpoints.
1833 PrintF("/!\\ Jumping over generated breakpoint.\n");
1834 sim_->set_pc(sim_->get_pc() + kInstrSize);
1835 }
1836 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
1837 // Execute the one instruction we broke at with breakpoints disabled.
1838 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
1839 // Leave the debugger shell.
1840 done = true;
1841 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
1842 if (argc == 2) {
1843 sreg_t value;
1844 int64_t fvalue;
1845 double dvalue;
1846 if (strcmp(arg1, "all") == 0) {
1847 PrintAllRegs();
1848 } else if (strcmp(arg1, "allf") == 0) {
1849 PrintAllRegsIncludingFPU();
1850 } else {
1851 int regnum = Registers::Number(arg1);
1852 int fpuregnum = FPURegisters::Number(arg1);
1853#ifdef CAN_USE_RVV_INSTRUCTIONS
1854 int vregnum = VRegisters::Number(arg1);
1855#endif
1856 if (regnum != kInvalidRegister) {
1857 value = GetRegisterValue(regnum);
1858 PrintF("%s: 0x%08" REGIx_FORMAT " %" REGId_FORMAT " \n", arg1,
1859 value, value);
1860 } else if (fpuregnum != kInvalidFPURegister) {
1861 fvalue = GetFPURegisterValue(fpuregnum);
1862 dvalue = GetFPURegisterValueDouble(fpuregnum);
1863 PrintF("%3s: 0x%016" PRIx64 " %16.4e\n",
1864 FPURegisters::Name(fpuregnum), fvalue, dvalue);
1865#ifdef CAN_USE_RVV_INSTRUCTIONS
1866 } else if (vregnum != kInvalidVRegister) {
1867 __int128_t v = GetVRegisterValue(vregnum);
1868 PrintF("\t%s:0x%016" PRIx64 "%016" PRIx64 "\n",
1869 VRegisters::Name(vregnum), (uint64_t)(v >> 64),
1870 (uint64_t)v);
1871#endif
1872 } else {
1873 PrintF("%s unrecognized\n", arg1);
1874 }
1875 }
1876 } else {
1877 if (argc == 3) {
1878 if (strcmp(arg2, "single") == 0) {
1879 int64_t value;
1880 float fvalue;
1881 int fpuregnum = FPURegisters::Number(arg1);
1882
1883 if (fpuregnum != kInvalidFPURegister) {
1884 value = GetFPURegisterValue(fpuregnum);
1885 value &= 0xFFFFFFFFUL;
1886 fvalue = GetFPURegisterValueFloat(fpuregnum);
1887 PrintF("%s: 0x%08" PRIx64 " %11.4e\n", arg1, value, fvalue);
1888 } else {
1889 PrintF("%s unrecognized\n", arg1);
1890 }
1891 } else {
1892 PrintF("print <fpu register> single\n");
1893 }
1894 } else {
1895 PrintF("print <register> or print <fpu register> single\n");
1896 }
1897 }
1898 } else if ((strcmp(cmd, "po") == 0) ||
1899 (strcmp(cmd, "printobject") == 0)) {
1900 if (argc == 2) {
1901 sreg_t value;
1902 StdoutStream os;
1903 if (GetValue(arg1, &value)) {
1904 Tagged<Object> obj(value);
1905 os << arg1 << ": \n";
1906#ifdef DEBUG
1907 Print(obj, os);
1908 os << "\n";
1909#else
1910 os << Brief(obj) << "\n";
1911#endif
1912 } else {
1913 os << arg1 << " unrecognized\n";
1914 }
1915 } else {
1916 PrintF("printobject <value>\n");
1917 }
1918 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
1919 sreg_t* cur = nullptr;
1920 sreg_t* end = nullptr;
1921 int next_arg = 1;
1922
1923 if (strcmp(cmd, "stack") == 0) {
1924 cur = reinterpret_cast<sreg_t*>(sim_->get_register(Simulator::sp));
1925 } else { // Command "mem".
1926 if (argc < 2) {
1927 PrintF("Need to specify <address> to mem command\n");
1928 continue;
1929 }
1930 sreg_t value;
1931 if (!GetValue(arg1, &value)) {
1932 PrintF("%s unrecognized\n", arg1);
1933 continue;
1934 }
1935 cur = reinterpret_cast<sreg_t*>(value);
1936 next_arg++;
1937 }
1938
1939 sreg_t words;
1940 if (argc == next_arg) {
1941 words = 10;
1942 } else {
1943 if (!GetValue(argv[next_arg], &words)) {
1944 words = 10;
1945 }
1946 }
1947 end = cur + words;
1948
1949 while (cur < end) {
1950 PrintF(" 0x%012" PRIxPTR " : 0x%016" REGIx_FORMAT
1951 " %14" REGId_FORMAT " ",
1952 reinterpret_cast<intptr_t>(cur), *cur, *cur);
1953 // Tagged<Object> obj(*cur);
1954 // Heap* current_heap = sim_->isolate_->heap();
1955 // if (IsSmi(obj) ||
1956 // IsValidHeapObject(current_heap, Cast<HeapObject>(obj))) {
1957 // PrintF(" (");
1958 // if (IsSmi(obj)) {
1959 // PrintF("smi %d", Smi::ToInt(obj));
1960 // }
1961 // PrintF(")");
1962 // }
1963 PrintF("\n");
1964 cur++;
1965 }
1966 } else if (strcmp(cmd, "memhex") == 0) {
1967 sreg_t* cur = nullptr;
1968 sreg_t* end = nullptr;
1969 int next_arg = 1;
1970 if (argc < 2) {
1971 PrintF("Need to specify <address> to memhex command\n");
1972 continue;
1973 }
1974 sreg_t value;
1975 if (!GetValue(arg1, &value)) {
1976 PrintF("%s unrecognized\n", arg1);
1977 continue;
1978 }
1979 cur = reinterpret_cast<sreg_t*>(value);
1980 next_arg++;
1981
1982 sreg_t words;
1983 if (argc == next_arg) {
1984 words = 10;
1985 } else {
1986 if (!GetValue(argv[next_arg], &words)) {
1987 words = 10;
1988 }
1989 }
1990 end = cur + words;
1991
1992 while (cur < end) {
1993 PrintF(" 0x%012" PRIxPTR " : 0x%016" REGIx_FORMAT
1994 " %14" REGId_FORMAT " ",
1995 reinterpret_cast<intptr_t>(cur), *cur, *cur);
1996 PrintF("\n");
1997 cur++;
1998 }
1999 } else if ((strcmp(cmd, "watch") == 0)) {
2000 if (argc < 2) {
2001 PrintF("Need to specify <address> to mem command\n");
2002 continue;
2003 }
2004 sreg_t value;
2005 if (!GetValue(arg1, &value)) {
2006 PrintF("%s unrecognized\n", arg1);
2007 continue;
2008 }
2009 sim_->watch_address_ = reinterpret_cast<sreg_t*>(value);
2010 sim_->watch_value_ = *(sim_->watch_address_);
2011 } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) ||
2012 (strcmp(cmd, "di") == 0)) {
2013 disasm::NameConverter converter;
2014 disasm::Disassembler dasm(converter);
2015 // Use a reasonably large buffer.
2017
2018 uint8_t* cur = nullptr;
2019 uint8_t* end = nullptr;
2020
2021 if (argc == 1) {
2022 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
2023 end = cur + (10 * kInstrSize);
2024 } else if (argc == 2) {
2025 int regnum = Registers::Number(arg1);
2026 if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
2027 // The argument is an address or a register name.
2028 sreg_t value;
2029 if (GetValue(arg1, &value)) {
2030 cur = reinterpret_cast<uint8_t*>(value);
2031 // Disassemble 10 instructions at <arg1>.
2032 end = cur + (10 * kInstrSize);
2033 }
2034 } else {
2035 // The argument is the number of instructions.
2036 sreg_t value;
2037 if (GetValue(arg1, &value)) {
2038 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
2039 // Disassemble <arg1> instructions.
2040 end = cur + (value * kInstrSize);
2041 }
2042 }
2043 } else {
2044 sreg_t value1;
2045 sreg_t value2;
2046 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
2047 cur = reinterpret_cast<uint8_t*>(value1);
2048 end = cur + (value2 * kInstrSize);
2049 }
2050 }
2051
2052 while (cur < end) {
2053 dasm.InstructionDecode(buffer, cur);
2054 PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
2055 buffer.begin());
2056 cur += kInstrSize;
2057 }
2058 } else if (strcmp(cmd, "gdb") == 0) {
2059 PrintF("relinquishing control to gdb\n");
2061 PrintF("regaining control from gdb\n");
2062 } else if (strcmp(cmd, "trace") == 0) {
2063 PrintF("enable trace sim\n");
2064 v8_flags.trace_sim = true;
2065 } else if (strcmp(cmd, "break") == 0 || strcmp(cmd, "b") == 0 ||
2066 strcmp(cmd, "tbreak") == 0) {
2067 bool is_tbreak = strcmp(cmd, "tbreak") == 0;
2068 if (argc == 2) {
2069 sreg_t value;
2070 if (GetValue(arg1, &value)) {
2071 sim_->SetBreakpoint(reinterpret_cast<Instruction*>(value),
2072 is_tbreak);
2073 } else {
2074 PrintF("%s unrecognized\n", arg1);
2075 }
2076 } else {
2077 sim_->ListBreakpoints();
2078 PrintF("Use `break <address>` to set or disable a breakpoint\n");
2079 PrintF(
2080 "Use `tbreak <address>` to set or disable a temporary "
2081 "breakpoint\n");
2082 }
2083 } else if (strcmp(cmd, "flags") == 0) {
2084 PrintF("No flags on RISC-V !\n");
2085 } else if (strcmp(cmd, "stop") == 0) {
2086 sreg_t value;
2087 if (argc == 3) {
2088 // Print information about all/the specified breakpoint(s).
2089 if (strcmp(arg1, "info") == 0) {
2090 if (strcmp(arg2, "all") == 0) {
2091 PrintF("Stop information:\n");
2092 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
2093 i++) {
2094 sim_->PrintStopInfo(i);
2095 }
2096 } else if (GetValue(arg2, &value)) {
2097 sim_->PrintStopInfo(value);
2098 } else {
2099 PrintF("Unrecognized argument.\n");
2100 }
2101 } else if (strcmp(arg1, "enable") == 0) {
2102 // Enable all/the specified breakpoint(s).
2103 if (strcmp(arg2, "all") == 0) {
2104 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
2105 i++) {
2106 sim_->EnableStop(i);
2107 }
2108 } else if (GetValue(arg2, &value)) {
2109 sim_->EnableStop(value);
2110 } else {
2111 PrintF("Unrecognized argument.\n");
2112 }
2113 } else if (strcmp(arg1, "disable") == 0) {
2114 // Disable all/the specified breakpoint(s).
2115 if (strcmp(arg2, "all") == 0) {
2116 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
2117 i++) {
2118 sim_->DisableStop(i);
2119 }
2120 } else if (GetValue(arg2, &value)) {
2121 sim_->DisableStop(value);
2122 } else {
2123 PrintF("Unrecognized argument.\n");
2124 }
2125 }
2126 } else {
2127 PrintF("Wrong usage. Use help command for more information.\n");
2128 }
2129 } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
2130 // Print registers and disassemble.
2131 PrintAllRegs();
2132 PrintF("\n");
2133
2134 disasm::NameConverter converter;
2135 disasm::Disassembler dasm(converter);
2136 // Use a reasonably large buffer.
2138
2139 uint8_t* cur = nullptr;
2140 uint8_t* end = nullptr;
2141
2142 if (argc == 1) {
2143 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
2144 end = cur + (10 * kInstrSize);
2145 } else if (argc == 2) {
2146 sreg_t value;
2147 if (GetValue(arg1, &value)) {
2148 cur = reinterpret_cast<uint8_t*>(value);
2149 // no length parameter passed, assume 10 instructions
2150 end = cur + (10 * kInstrSize);
2151 }
2152 } else {
2153 sreg_t value1;
2154 sreg_t value2;
2155 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
2156 cur = reinterpret_cast<uint8_t*>(value1);
2157 end = cur + (value2 * kInstrSize);
2158 }
2159 }
2160
2161 while (cur < end) {
2162 dasm.InstructionDecode(buffer, cur);
2163 PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
2164 buffer.begin());
2165 cur += kInstrSize;
2166 }
2167 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
2168 PrintF("cont (alias 'c')\n");
2169 PrintF(" Continue execution\n");
2170 PrintF("stepi (alias 'si')\n");
2171 PrintF(" Step one instruction\n");
2172 PrintF("print (alias 'p')\n");
2173 PrintF(" print <register>\n");
2174 PrintF(" Print register content\n");
2175 PrintF(" Use register name 'all' to print all GPRs\n");
2176 PrintF(" Use register name 'allf' to print all GPRs and FPRs\n");
2177 PrintF("printobject (alias 'po')\n");
2178 PrintF(" printobject <register>\n");
2179 PrintF(" Print an object from a register\n");
2180 PrintF("stack\n");
2181 PrintF(" stack [<words>]\n");
2182 PrintF(" Dump stack content, default dump 10 words)\n");
2183 PrintF("mem\n");
2184 PrintF(" mem <address> [<words>]\n");
2185 PrintF(" Dump memory content, default dump 10 words)\n");
2186 PrintF("watch\n");
2187 PrintF(" watch <address> \n");
2188 PrintF(" watch memory content.)\n");
2189 PrintF("flags\n");
2190 PrintF(" print flags\n");
2191 PrintF("disasm (alias 'di')\n");
2192 PrintF(" disasm [<instructions>]\n");
2193 PrintF(" disasm [<address/register>] (e.g., disasm pc) \n");
2194 PrintF(" disasm [[<address/register>] <instructions>]\n");
2195 PrintF(" Disassemble code, default is 10 instructions\n");
2196 PrintF(" from pc\n");
2197 PrintF("gdb \n");
2198 PrintF(" Return to gdb if the simulator was started with gdb\n");
2199 PrintF("break (alias 'b')\n");
2200 PrintF(" break : list all breakpoints\n");
2201 PrintF(" break <address> : set / enable / disable a breakpoint.\n");
2202 PrintF("tbreak\n");
2203 PrintF(" tbreak : list all breakpoints\n");
2204 PrintF(
2205 " tbreak <address> : set / enable / disable a temporary "
2206 "breakpoint.\n");
2207 PrintF(" Set a breakpoint enabled only for one stop. \n");
2208 PrintF("stop feature:\n");
2209 PrintF(" Description:\n");
2210 PrintF(" Stops are debug instructions inserted by\n");
2211 PrintF(" the Assembler::stop() function.\n");
2212 PrintF(" When hitting a stop, the Simulator will\n");
2213 PrintF(" stop and give control to the Debugger.\n");
2214 PrintF(" All stop codes are watched:\n");
2215 PrintF(" - They can be enabled / disabled: the Simulator\n");
2216 PrintF(" will / won't stop when hitting them.\n");
2217 PrintF(" - The Simulator keeps track of how many times they \n");
2218 PrintF(" are met. (See the info command.) Going over a\n");
2219 PrintF(" disabled stop still increases its counter. \n");
2220 PrintF(" Commands:\n");
2221 PrintF(" stop info all/<code> : print infos about number <code>\n");
2222 PrintF(" or all stop(s).\n");
2223 PrintF(" stop enable/disable all/<code> : enables / disables\n");
2224 PrintF(" all or number <code> stop(s)\n");
2225 } else {
2226 PrintF("Unknown command: %s\n", cmd);
2227 }
2228 }
2229 }
2230
2231#undef COMMAND_SIZE
2232#undef ARG_SIZE
2233
2234#undef STR
2235#undef XSTR
2236}
2237
2238void Simulator::SetBreakpoint(Instruction* location, bool is_tbreak) {
2239 for (unsigned i = 0; i < breakpoints_.size(); i++) {
2240 if (breakpoints_.at(i).location == location) {
2241 if (breakpoints_.at(i).is_tbreak != is_tbreak) {
2242 PrintF("Change breakpoint at %p to %s breakpoint\n",
2243 reinterpret_cast<void*>(location),
2244 is_tbreak ? "temporary" : "regular");
2245 breakpoints_.at(i).is_tbreak = is_tbreak;
2246 return;
2247 }
2248 PrintF("Existing breakpoint at %p was %s\n",
2249 reinterpret_cast<void*>(location),
2250 breakpoints_.at(i).enabled ? "disabled" : "enabled");
2251 breakpoints_.at(i).enabled = !breakpoints_.at(i).enabled;
2252 return;
2253 }
2254 }
2255 Breakpoint new_breakpoint = {location, true, is_tbreak};
2256 breakpoints_.push_back(new_breakpoint);
2257 PrintF("Set a %sbreakpoint at %p\n", is_tbreak ? "temporary " : "",
2258 reinterpret_cast<void*>(location));
2259}
2260
2261void Simulator::ListBreakpoints() {
2262 PrintF("Breakpoints:\n");
2263 for (unsigned i = 0; i < breakpoints_.size(); i++) {
2264 PrintF("%p : %s %s\n",
2265 reinterpret_cast<void*>(breakpoints_.at(i).location),
2266 breakpoints_.at(i).enabled ? "enabled" : "disabled",
2267 breakpoints_.at(i).is_tbreak ? ": temporary" : "");
2268 }
2269}
2270
2271void Simulator::CheckBreakpoints() {
2272 bool hit_a_breakpoint = false;
2273 bool is_tbreak = false;
2274 Instruction* pc_ = reinterpret_cast<Instruction*>(get_pc());
2275 for (unsigned i = 0; i < breakpoints_.size(); i++) {
2276 if ((breakpoints_.at(i).location == pc_) && breakpoints_.at(i).enabled) {
2277 hit_a_breakpoint = true;
2278 if (breakpoints_.at(i).is_tbreak) {
2279 // Disable a temporary breakpoint.
2280 is_tbreak = true;
2281 breakpoints_.at(i).enabled = false;
2282 }
2283 break;
2284 }
2285 }
2286 if (hit_a_breakpoint) {
2287 PrintF("Hit %sa breakpoint at %p.\n", is_tbreak ? "and disabled " : "",
2288 reinterpret_cast<void*>(pc_));
2289 RiscvDebugger dbg(this);
2290 dbg.Debug();
2291 }
2292}
2293
2294bool Simulator::ICacheMatch(void* one, void* two) {
2295 DCHECK_EQ(reinterpret_cast<intptr_t>(one) & CachePage::kPageMask, 0);
2296 DCHECK_EQ(reinterpret_cast<intptr_t>(two) & CachePage::kPageMask, 0);
2297 return one == two;
2298}
2299
2300static uint32_t ICacheHash(void* key) {
2301 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
2302}
2303
2304static bool AllOnOnePage(uintptr_t start, size_t size) {
2305 intptr_t start_page = (start & ~CachePage::kPageMask);
2306 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
2307 return start_page == end_page;
2308}
2309
2310void Simulator::set_last_debugger_input(char* input) {
2311 DeleteArray(last_debugger_input_);
2312 last_debugger_input_ = input;
2313}
2314
2315void Simulator::SetRedirectInstruction(Instruction* instruction) {
2316 instruction->SetInstructionBits(rtCallRedirInstr);
2317}
2318
2319void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache,
2320 void* start_addr, size_t size) {
2321 int64_t start = reinterpret_cast<int64_t>(start_addr);
2322 int64_t intra_line = (start & CachePage::kLineMask);
2323 start -= intra_line;
2324 size += intra_line;
2325 size = ((size - 1) | CachePage::kLineMask) + 1;
2326 int offset = (start & CachePage::kPageMask);
2327 while (!AllOnOnePage(start, size - 1)) {
2328 int bytes_to_flush = CachePage::kPageSize - offset;
2329 FlushOnePage(i_cache, start, bytes_to_flush);
2330 start += bytes_to_flush;
2331 size -= bytes_to_flush;
2332 DCHECK_EQ((int64_t)0, start & CachePage::kPageMask);
2333 offset = 0;
2334 }
2335 if (size != 0) {
2336 FlushOnePage(i_cache, start, size);
2337 }
2338}
2339
2340CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache,
2341 void* page) {
2342 base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page));
2343 if (entry->value == nullptr) {
2344 CachePage* new_page = new CachePage();
2345 entry->value = new_page;
2346 }
2347 return reinterpret_cast<CachePage*>(entry->value);
2348}
2349
2350// Flush from start up to and not including start + size.
2351void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
2352 intptr_t start, size_t size) {
2353 DCHECK_LE(size, CachePage::kPageSize);
2354 DCHECK(AllOnOnePage(start, size - 1));
2355 DCHECK_EQ(start & CachePage::kLineMask, 0);
2356 DCHECK_EQ(size & CachePage::kLineMask, 0);
2357 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
2358 int offset = (start & CachePage::kPageMask);
2359 CachePage* cache_page = GetCachePage(i_cache, page);
2360 char* valid_bytemap = cache_page->ValidityByte(offset);
2361 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
2362}
2363
2364void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache,
2365 Instruction* instr) {
2366 sreg_t address = reinterpret_cast<sreg_t>(instr);
2367 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
2368 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
2369 int offset = (address & CachePage::kPageMask);
2370 CachePage* cache_page = GetCachePage(i_cache, page);
2371 char* cache_valid_byte = cache_page->ValidityByte(offset);
2372 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
2373 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
2374 if (cache_hit) {
2375 // Check that the data in memory matches the contents of the I-cache.
2376 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
2377 cache_page->CachedData(offset), kInstrSize));
2378 } else {
2379 // Cache miss. Load memory into the cache.
2380 memcpy(cached_line, line, CachePage::kLineLength);
2381 *cache_valid_byte = CachePage::LINE_VALID;
2382 }
2383}
2384
2385Simulator::Simulator(Isolate* isolate) : isolate_(isolate), builtins_(isolate) {
2386 // Set up simulator support first. Some of this information is needed to
2387 // setup the architecture state.
2388 // Allocate and setup the simulator stack.
2389 size_t stack_size = AllocatedStackSize();
2390
2391 stack_ = reinterpret_cast<uintptr_t>(new uint8_t[stack_size]());
2392 stack_limit_ = stack_ + kStackProtectionSize;
2393
2394 pc_modified_ = false;
2395 icount_ = 0;
2396 break_count_ = 0;
2397 // Reset debug helpers.
2398 breakpoints_.clear();
2399 // TODO(riscv): 'next' command
2400 // break_on_next_ = false;
2401
2402 // Set up architecture state.
2403 // All registers are initialized to zero to start with.
2404 for (int i = 0; i < kNumSimuRegisters; i++) {
2405 registers_[i] = 0;
2406 }
2407
2408 for (int i = 0; i < kNumFPURegisters; i++) {
2409 FPUregisters_[i] = 0;
2410 }
2411
2412 FCSR_ = 0;
2413
2414 // The sp is initialized to point to the bottom (high address) of the
2415 // allocated stack area. To be safe in potential stack underflows we leave
2416 // some buffer below.
2417 registers_[sp] = StackBase();
2418 // The ra and pc are initialized to a known bad value that will cause an
2419 // access violation if the simulator ever tries to execute it.
2420 registers_[pc] = bad_ra;
2421 registers_[ra] = bad_ra;
2422
2423 last_debugger_input_ = nullptr;
2424#ifdef CAN_USE_RVV_INSTRUCTIONS
2425 for (int i = 0; i < kNumVRegisters; ++i) {
2426 Vregister_[i] = 0;
2427 }
2428 vxrm_ = 0;
2429 vstart_ = 0;
2430 vxsat_ = 0;
2431 vxrm_ = 0;
2432 vcsr_ = 0;
2433 vtype_ = 0;
2434 vl_ = 0;
2435 vlenb_ = 0;
2436#endif
2437}
2438
2439Simulator::~Simulator() {
2440 GlobalMonitor::Get()->RemoveLinkedAddress(&global_monitor_thread_);
2441 delete[] reinterpret_cast<uint8_t*>(stack_);
2442}
2443
2444// Get the active Simulator for the current thread.
2445Simulator* Simulator::current(Isolate* isolate) {
2447 isolate->FindOrAllocatePerThreadDataForThisThread();
2448 DCHECK_NOT_NULL(isolate_data);
2449
2450 Simulator* sim = isolate_data->simulator();
2451 if (sim == nullptr) {
2452 // TODO(146): delete the simulator object when a thread/isolate goes away.
2453 sim = new Simulator(isolate);
2454 isolate_data->set_simulator(sim);
2455 }
2456 return sim;
2457}
2458
2459// Sets the register in the architecture state. It will also deal with
2460// updating Simulator internal state for special registers such as PC.
2461void Simulator::set_register(int reg, sreg_t value) {
2462 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
2463 if (reg == pc) {
2464 pc_modified_ = true;
2465 }
2466
2467 // Zero register always holds 0.
2468 registers_[reg] = (reg == 0) ? 0 : value;
2469}
2470
2471void Simulator::set_fpu_register(int fpureg, int64_t value) {
2472 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2473 FPUregisters_[fpureg] = value;
2474}
2475
2476void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
2477 // Set ONLY lower 32-bits, leaving upper bits untouched.
2478 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2479 int32_t* pword;
2480 if (kArchEndian == kLittle) {
2481 pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
2482 } else {
2483 pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]) + 1;
2484 }
2485 *pword = value;
2486}
2487
2488void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
2489 // Set ONLY upper 32-bits, leaving lower bits untouched.
2490 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2491 int32_t* phiword;
2492 if (kArchEndian == kLittle) {
2493 phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
2494 } else {
2495 phiword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
2496 }
2497 *phiword = value;
2498}
2499
2500void Simulator::set_fpu_register_float(int fpureg, float value) {
2501 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2502 FPUregisters_[fpureg] = box_float(value);
2503}
2504
2505void Simulator::set_fpu_register_float(int fpureg, Float32 value) {
2506 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2507 Float64 t = Float64::FromBits(box_float(value.get_bits()));
2508 memcpy(&FPUregisters_[fpureg], &t, 8);
2509}
2510
2511void Simulator::set_fpu_register_double(int fpureg, double value) {
2512 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2513 FPUregisters_[fpureg] = base::bit_cast<int64_t>(value);
2514}
2515
2516void Simulator::set_fpu_register_double(int fpureg, Float64 value) {
2517 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2518 memcpy(&FPUregisters_[fpureg], &value, 8);
2519}
2520// Get the register from the architecture state. This function does handle
2521// the special case of accessing the PC register.
2522sreg_t Simulator::get_register(int reg) const {
2523 DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
2524 if (reg == 0)
2525 return 0;
2526 else
2527 return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
2528}
2529
2530double Simulator::get_double_from_register_pair(int reg) {
2531 // TODO(plind): bad ABI stuff, refactor or remove.
2532 DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
2533
2534 double dm_val = 0.0;
2535 // Read the bits from the unsigned integer register_[] array
2536 // into the double precision floating point value and return it.
2537 char buffer[sizeof(registers_[0])];
2538 memcpy(buffer, &registers_[reg], sizeof(registers_[0]));
2539 memcpy(&dm_val, buffer, sizeof(registers_[0]));
2540 return (dm_val);
2541}
2542
2543int64_t Simulator::get_fpu_register(int fpureg) const {
2544 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2545 return FPUregisters_[fpureg];
2546}
2547
2548int32_t Simulator::get_fpu_register_word(int fpureg) const {
2549 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2550 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xFFFFFFFF);
2551}
2552
2553int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
2554 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2555 return static_cast<int32_t>(FPUregisters_[fpureg] & 0xFFFFFFFF);
2556}
2557
2558int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
2559 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2560 return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xFFFFFFFF);
2561}
2562
2563float Simulator::get_fpu_register_float(int fpureg) const {
2564 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2565 if (!is_boxed_float(FPUregisters_[fpureg])) {
2566 return std::numeric_limits<float>::quiet_NaN();
2567 }
2568 return Float32::FromBits(FPUregisters_[fpureg] & 0xFFFF'FFFF).get_scalar();
2569}
2570
2571// Fix NaN boxing error according to
2572// https://github.com/riscv/riscv-isa-manual/blob/main/src/d-st-ext.adoc#nan-boxing-of-narrower-values"
2573Float32 Simulator::get_fpu_register_Float32(int fpureg,
2574 bool check_nanbox) const {
2575 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2576 if (check_nanbox && !is_boxed_float(FPUregisters_[fpureg])) {
2577 std::cout << std::hex << FPUregisters_[fpureg] << std::endl;
2578 return Float32::FromBits(0x7fc00000);
2579 }
2580 return Float32::FromBits(FPUregisters_[fpureg] & 0xFFFF'FFFF);
2581}
2582
2583double Simulator::get_fpu_register_double(int fpureg) const {
2584 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2585 return base::bit_cast<double>(FPUregisters_[fpureg]);
2586}
2587
2588Float64 Simulator::get_fpu_register_Float64(int fpureg) const {
2589 DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
2590 return Float64::FromBits(FPUregisters_[fpureg]);
2591}
2592
2593#ifdef CAN_USE_RVV_INSTRUCTIONS
2594__int128_t Simulator::get_vregister(int vreg) const {
2595 DCHECK((vreg >= 0) && (vreg < kNumVRegisters));
2596 return Vregister_[vreg];
2597}
2598#endif
2599
2600// Runtime FP routines take up to two double arguments and zero
2601// or one integer arguments. All are constructed here,
2602// from fa0, fa1, and a0.
2603void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
2604 *x = get_fpu_register_double(fa0);
2605 *y = get_fpu_register_double(fa1);
2606 *z = static_cast<int32_t>(get_register(a0));
2607}
2608
2609// The return value is in fa0.
2610void Simulator::SetFpResult(const double& result) {
2611 set_fpu_register_double(fa0, result);
2612}
2613
2614// helper functions to read/write/set/clear CRC values/bits
2615uint32_t Simulator::read_csr_value(uint32_t csr) {
2616 switch (csr) {
2617 case csr_fflags: // Floating-Point Accrued Exceptions (RW)
2618 return (FCSR_ & kFcsrFlagsMask);
2619 case csr_frm: // Floating-Point Dynamic Rounding Mode (RW)
2620 return (FCSR_ & kFcsrFrmMask) >> kFcsrFrmShift;
2621 case csr_fcsr: // Floating-Point Control and Status Register (RW)
2622 return (FCSR_ & kFcsrMask);
2623 default:
2624 UNIMPLEMENTED();
2625 }
2626}
2627
2628uint32_t Simulator::get_dynamic_rounding_mode() {
2629 return read_csr_value(csr_frm);
2630}
2631
2632void Simulator::write_csr_value(uint32_t csr, reg_t val) {
2633 uint32_t value = (uint32_t)val;
2634 switch (csr) {
2635 case csr_fflags: // Floating-Point Accrued Exceptions (RW)
2636 DCHECK(value <= ((1 << kFcsrFlagsBits) - 1));
2637 FCSR_ = (FCSR_ & (~kFcsrFlagsMask)) | value;
2638 break;
2639 case csr_frm: // Floating-Point Dynamic Rounding Mode (RW)
2640 DCHECK(value <= ((1 << kFcsrFrmBits) - 1));
2641 FCSR_ = (FCSR_ & (~kFcsrFrmMask)) | (value << kFcsrFrmShift);
2642 break;
2643 case csr_fcsr: // Floating-Point Control and Status Register (RW)
2644 DCHECK(value <= ((1 << kFcsrBits) - 1));
2645 FCSR_ = (FCSR_ & (~kFcsrMask)) | value;
2646 break;
2647 default:
2648 UNIMPLEMENTED();
2649 }
2650}
2651
2652void Simulator::set_csr_bits(uint32_t csr, reg_t val) {
2653 uint32_t value = (uint32_t)val;
2654 switch (csr) {
2655 case csr_fflags: // Floating-Point Accrued Exceptions (RW)
2656 DCHECK(value <= ((1 << kFcsrFlagsBits) - 1));
2657 FCSR_ = FCSR_ | value;
2658 break;
2659 case csr_frm: // Floating-Point Dynamic Rounding Mode (RW)
2660 DCHECK(value <= ((1 << kFcsrFrmBits) - 1));
2661 FCSR_ = FCSR_ | (value << kFcsrFrmShift);
2662 break;
2663 case csr_fcsr: // Floating-Point Control and Status Register (RW)
2664 DCHECK(value <= ((1 << kFcsrBits) - 1));
2665 FCSR_ = FCSR_ | value;
2666 break;
2667 default:
2668 UNIMPLEMENTED();
2669 }
2670}
2671
2672void Simulator::clear_csr_bits(uint32_t csr, reg_t val) {
2673 uint32_t value = (uint32_t)val;
2674 switch (csr) {
2675 case csr_fflags: // Floating-Point Accrued Exceptions (RW)
2676 DCHECK(value <= ((1 << kFcsrFlagsBits) - 1));
2677 FCSR_ = FCSR_ & (~value);
2678 break;
2679 case csr_frm: // Floating-Point Dynamic Rounding Mode (RW)
2680 DCHECK(value <= ((1 << kFcsrFrmBits) - 1));
2681 FCSR_ = FCSR_ & (~(value << kFcsrFrmShift));
2682 break;
2683 case csr_fcsr: // Floating-Point Control and Status Register (RW)
2684 DCHECK(value <= ((1 << kFcsrBits) - 1));
2685 FCSR_ = FCSR_ & (~value);
2686 break;
2687 default:
2688 UNIMPLEMENTED();
2689 }
2690}
2691
2692bool Simulator::test_fflags_bits(uint32_t mask) {
2693 return (FCSR_ & kFcsrFlagsMask & mask) != 0;
2694}
2695
2696template <typename T>
2697T Simulator::FMaxMinHelper(T a, T b, MaxMinKind kind) {
2698 // set invalid bit for signaling nan
2699 if ((a == std::numeric_limits<T>::signaling_NaN()) ||
2700 (b == std::numeric_limits<T>::signaling_NaN())) {
2701 set_csr_bits(csr_fflags, kInvalidOperation);
2702 }
2703
2704 T result = 0;
2705 if (std::isnan(a) && std::isnan(b)) {
2706 result = std::numeric_limits<float>::quiet_NaN();
2707 } else if (std::isnan(a)) {
2708 result = b;
2709 } else if (std::isnan(b)) {
2710 result = a;
2711 } else if (b == a) { // Handle -0.0 == 0.0 case.
2712 if (kind == MaxMinKind::kMax) {
2713 result = std::signbit(b) ? a : b;
2714 } else {
2715 result = std::signbit(b) ? b : a;
2716 }
2717 } else {
2718 result = (kind == MaxMinKind::kMax) ? fmax(a, b) : fmin(a, b);
2719 }
2720
2721 return result;
2722}
2723
2724// Raw access to the PC register.
2725void Simulator::set_pc(sreg_t value) {
2726 pc_modified_ = true;
2727 registers_[pc] = value;
2728 DCHECK(has_bad_pc() || ((value % kInstrSize) == 0) ||
2729 ((value % kShortInstrSize) == 0));
2730}
2731
2732bool Simulator::has_bad_pc() const {
2733 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
2734}
2735
2736// Raw access to the PC register without the special adjustment when reading.
2737sreg_t Simulator::get_pc() const { return registers_[pc]; }
2738
2739// The RISC-V spec leaves it open to the implementation on how to handle
2740// unaligned reads and writes. For now, we simply disallow unaligned reads but
2741// at some point, we may want to implement some other behavior.
2742
2743// TODO(plind): refactor this messy debug code when we do unaligned access.
2744void Simulator::DieOrDebug() {
2745 if (v8_flags.riscv_trap_to_simulator_debugger) {
2746 RiscvDebugger dbg(this);
2747 dbg.Debug();
2748 } else {
2749 base::OS::Abort();
2750 }
2751}
2752
2753#if V8_TARGET_ARCH_RISCV64
2754void Simulator::TraceRegWr(int64_t value, TraceType t) {
2755 if (v8_flags.trace_sim) {
2756 union {
2757 int64_t fmt_int64;
2758 int32_t fmt_int32[2];
2759 float fmt_float[2];
2760 double fmt_double;
2761 } v;
2762 v.fmt_int64 = value;
2763
2764 switch (t) {
2765 case WORD:
2766 SNPrintF(trace_buf_,
2767 "%016" REGIx_FORMAT " (%" PRId64 ") int32:%" PRId32
2768 " uint32:%" PRIu32,
2769 v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0]);
2770 break;
2771 case DWORD:
2772 SNPrintF(trace_buf_,
2773 "%016" REGIx_FORMAT " (%" PRId64 ") int64:%" REGId_FORMAT
2774 " uint64:%" PRIu64,
2775 value, icount_, value, value);
2776 break;
2777 case FLOAT:
2778 SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") flt:%e",
2779 v.fmt_int64, icount_, v.fmt_float[0]);
2780 break;
2781 case DOUBLE:
2782 SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") dbl:%e",
2783 v.fmt_int64, icount_, v.fmt_double);
2784 break;
2785 default:
2786 UNREACHABLE();
2787 }
2788 }
2789}
2790
2791#elif V8_TARGET_ARCH_RISCV32
2792template <typename T>
2793void Simulator::TraceRegWr(T value, TraceType t) {
2794 if (v8_flags.trace_sim) {
2795 union {
2796 int32_t fmt_int32;
2797 float fmt_float;
2798 double fmt_double;
2799 } v;
2800 if (t != DOUBLE) {
2801 v.fmt_int32 = value;
2802 } else {
2803 DCHECK_EQ(sizeof(T), 8);
2804 v.fmt_double = value;
2805 }
2806 switch (t) {
2807 case WORD:
2808 SNPrintF(trace_buf_,
2809 "%016" REGIx_FORMAT " (%" PRId64 ") int32:%" REGId_FORMAT
2810 " uint32:%" PRIu32,
2811 v.fmt_int32, icount_, v.fmt_int32, v.fmt_int32);
2812 break;
2813 case FLOAT:
2814 SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") flt:%e",
2815 v.fmt_int32, icount_, v.fmt_float);
2816 break;
2817 case DOUBLE:
2818 SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRId64 ") dbl:%e",
2819 static_cast<int64_t>(v.fmt_double), icount_, v.fmt_double);
2820 break;
2821 default:
2822 UNREACHABLE();
2823 }
2824 }
2825}
2826#endif
2827
2828// TODO(plind): consider making icount_ printing a flag option.
2829template <typename T>
2830void Simulator::TraceMemRd(sreg_t addr, T value, sreg_t reg_value) {
2831 if (v8_flags.trace_sim) {
2832 if (std::is_integral<T>::value) {
2833 switch (sizeof(T)) {
2834 case 1:
2835 SNPrintF(trace_buf_,
2836 "%016" REGIx_FORMAT " (%" PRId64 ") int8:%" PRId8
2837 " uint8:%" PRIu8 " <-- [addr: %" REGIx_FORMAT "]",
2838 reg_value, icount_, static_cast<int8_t>(value),
2839 static_cast<uint8_t>(value), addr);
2840 break;
2841 case 2:
2842 SNPrintF(trace_buf_,
2843 "%016" REGIx_FORMAT " (%" PRId64 ") int16:%" PRId16
2844 " uint16:%" PRIu16 " <-- [addr: %" REGIx_FORMAT "]",
2845 reg_value, icount_, static_cast<int16_t>(value),
2846 static_cast<uint16_t>(value), addr);
2847 break;
2848 case 4:
2849 SNPrintF(trace_buf_,
2850 "%016" REGIx_FORMAT " (%" PRId64 ") int32:%" PRId32
2851 " uint32:%" PRIu32 " <-- [addr: %" REGIx_FORMAT "]",
2852 reg_value, icount_, static_cast<int32_t>(value),
2853 static_cast<uint32_t>(value), addr);
2854 break;
2855 case 8:
2856 SNPrintF(trace_buf_,
2857 "%016" REGIx_FORMAT " (%" PRId64 ") int64:%" PRId64
2858 " uint64:%" PRIu64 " <-- [addr: %" REGIx_FORMAT "]",
2859 reg_value, icount_, static_cast<int64_t>(value),
2860 static_cast<uint64_t>(value), addr);
2861 break;
2862 default:
2863 UNREACHABLE();
2864 }
2865 } else if (std::is_same<float, T>::value) {
2866 SNPrintF(trace_buf_,
2867 "%016" REGIx_FORMAT " (%" PRId64
2868 ") flt:%e <-- [addr: %" REGIx_FORMAT "]",
2869 reg_value, icount_, static_cast<float>(value), addr);
2870 } else if (std::is_same<double, T>::value) {
2871 SNPrintF(trace_buf_,
2872 "%016" REGIx_FORMAT " (%" PRId64
2873 ") dbl:%e <-- [addr: %" REGIx_FORMAT "]",
2874 reg_value, icount_, static_cast<double>(value), addr);
2875 } else {
2876 UNREACHABLE();
2877 }
2878 }
2879}
2880
2881void Simulator::TraceMemRdFloat(sreg_t addr, Float32 value, int64_t reg_value) {
2882 if (v8_flags.trace_sim) {
2883 SNPrintF(trace_buf_,
2884 "%016" PRIx64 " (%" PRId64
2885 ") flt:%e <-- [addr: %" REGIx_FORMAT "]",
2886 reg_value, icount_, static_cast<float>(value.get_scalar()), addr);
2887 }
2888}
2889
2890void Simulator::TraceMemRdDouble(sreg_t addr, double value, int64_t reg_value) {
2891 if (v8_flags.trace_sim) {
2892 SNPrintF(trace_buf_,
2893 "%016" PRIx64 " (%" PRId64
2894 ") dbl:%e <-- [addr: %" REGIx_FORMAT "]",
2895 reg_value, icount_, static_cast<double>(value), addr);
2896 }
2897}
2898
2899void Simulator::TraceMemRdDouble(sreg_t addr, Float64 value,
2900 int64_t reg_value) {
2901 if (v8_flags.trace_sim) {
2902 SNPrintF(trace_buf_,
2903 "%016" PRIx64 " (%" PRId64
2904 ") dbl:%e <-- [addr: %" REGIx_FORMAT "]",
2905 reg_value, icount_, static_cast<double>(value.get_scalar()), addr);
2906 }
2907}
2908
2909template <typename T>
2910void Simulator::TraceMemWr(sreg_t addr, T value) {
2911 if (v8_flags.trace_sim) {
2912 switch (sizeof(T)) {
2913 case 1:
2914 SNPrintF(trace_buf_,
2915 " (%" PRIu64 ") int8:%" PRId8
2916 " uint8:%" PRIu8 " --> [addr: %" REGIx_FORMAT "]",
2917 icount_, static_cast<int8_t>(value),
2918 static_cast<uint8_t>(value), addr);
2919 break;
2920 case 2:
2921 SNPrintF(trace_buf_,
2922 " (%" PRIu64 ") int16:%" PRId16
2923 " uint16:%" PRIu16 " --> [addr: %" REGIx_FORMAT "]",
2924 icount_, static_cast<int16_t>(value),
2925 static_cast<uint16_t>(value), addr);
2926 break;
2927 case 4:
2928 if (std::is_integral<T>::value) {
2929 SNPrintF(trace_buf_,
2930 " (%" PRIu64 ") int32:%" PRId32
2931 " uint32:%" PRIu32 " --> [addr: %" REGIx_FORMAT "]",
2932 icount_, static_cast<int32_t>(value),
2933 static_cast<uint32_t>(value), addr);
2934 } else {
2935 SNPrintF(trace_buf_,
2936 " (%" PRIu64
2937 ") flt:%e bit:%x --> [addr: %" REGIx_FORMAT "]",
2938 icount_, static_cast<float>(value),
2939 base::bit_cast<int32_t, float>(value), addr);
2940 }
2941 break;
2942 case 8:
2943 if (std::is_integral<T>::value) {
2944 SNPrintF(trace_buf_,
2945 " (%" PRIu64 ") int64:%" PRId64
2946 " uint64:%" PRIu64 " --> [addr: %" REGIx_FORMAT "]",
2947 icount_, static_cast<int64_t>(value),
2948 static_cast<uint64_t>(value), addr);
2949 } else {
2950 SNPrintF(trace_buf_,
2951 " (%" PRIu64 ") dbl:%e bit:%" PRIx64
2952 " --> [addr: %" REGIx_FORMAT "]",
2953 icount_, static_cast<double>(value),
2954 base::bit_cast<int64_t, double>(value), addr);
2955 }
2956 break;
2957 default:
2958 UNREACHABLE();
2959 }
2960 }
2961}
2962
2963void Simulator::TraceMemWrDouble(sreg_t addr, double value) {
2964 if (v8_flags.trace_sim) {
2965 SNPrintF(trace_buf_,
2966 " (%" PRIu64 ") dbl:%e bit:%" PRIx64
2967 "--> [addr: %" REGIx_FORMAT "]",
2968 icount_, value, base::bit_cast<int64_t, double>(value), addr);
2969 }
2970}
2971// RISCV Memory Read/Write functions
2972
2973bool Simulator::ProbeMemory(uintptr_t address, uintptr_t access_size) {
2974#if V8_ENABLE_WEBASSEMBLY && V8_TRAP_HANDLER_SUPPORTED
2975 uintptr_t last_accessed_byte = address + access_size - 1;
2976 uintptr_t current_pc = registers_[pc];
2977 uintptr_t landing_pad =
2978 trap_handler::ProbeMemory(last_accessed_byte, current_pc);
2979 if (!landing_pad) return true;
2980 set_pc(landing_pad);
2981 set_register(kWasmTrapHandlerFaultAddressRegister.code(), current_pc);
2982 return false;
2983#else
2984 return true;
2985#endif
2986}
2987
2988// TODO(RISCV): check whether the specific board supports unaligned load/store
2989// (determined by EEI). For now, we assume the board does not support unaligned
2990// load/store (e.g., trapping)
2991template <typename T>
2992T Simulator::ReadMem(sreg_t addr, Instruction* instr) {
2993 if (addr >= 0 && addr < 0x400) {
2994 // This has to be a nullptr-dereference, drop into debugger.
2995 PrintF("Memory read from bad address: 0x%08" REGIx_FORMAT
2996 " , pc=0x%08" PRIxPTR " \n",
2997 addr, reinterpret_cast<intptr_t>(instr));
2998 DieOrDebug();
2999 }
3000#if !defined(V8_COMPRESS_POINTERS) && defined(RISCV_HAS_NO_UNALIGNED)
3001 // check for natural alignment
3002 if (!v8_flags.riscv_c_extension && ((addr & (sizeof(T) - 1)) != 0)) {
3003 PrintF("Unaligned read at 0x%08" REGIx_FORMAT " , pc=0x%08" V8PRIxPTR "\n",
3004 addr, reinterpret_cast<intptr_t>(instr));
3005 DieOrDebug();
3006 }
3007#endif
3008 T* ptr = reinterpret_cast<T*>(addr);
3009 T value = *ptr;
3010 return value;
3011}
3012
3013template <typename T>
3014void Simulator::WriteMem(sreg_t addr, T value, Instruction* instr) {
3015 if (addr >= 0 && addr < 0x400) {
3016 // This has to be a nullptr-dereference, drop into debugger.
3017 PrintF("Memory write to bad address: 0x%08" REGIx_FORMAT
3018 " , pc=0x%08" PRIxPTR " \n",
3019 addr, reinterpret_cast<intptr_t>(instr));
3020 DieOrDebug();
3021 }
3022#if !defined(V8_COMPRESS_POINTERS) && defined(RISCV_HAS_NO_UNALIGNED)
3023 // check for natural alignment
3024 if (!v8_flags.riscv_c_extension && ((addr & (sizeof(T) - 1)) != 0)) {
3025 PrintF("Unaligned write at 0x%08" REGIx_FORMAT " , pc=0x%08" V8PRIxPTR "\n",
3026 addr, reinterpret_cast<intptr_t>(instr));
3027 DieOrDebug();
3028 }
3029#endif
3030 T* ptr = reinterpret_cast<T*>(addr);
3031 if (!std::is_same<double, T>::value) {
3032 TraceMemWr(addr, value);
3033 } else {
3034 TraceMemWrDouble(addr, value);
3035 }
3036 *ptr = value;
3037}
3038
3039template <>
3040void Simulator::WriteMem(sreg_t addr, Float32 value, Instruction* instr) {
3041 if (addr >= 0 && addr < 0x400) {
3042 // This has to be a nullptr-dereference, drop into debugger.
3043 PrintF("Memory write to bad address: 0x%08" REGIx_FORMAT
3044 " , pc=0x%08" PRIxPTR " \n",
3045 addr, reinterpret_cast<intptr_t>(instr));
3046 DieOrDebug();
3047 }
3048#if !defined(V8_COMPRESS_POINTERS) && defined(RISCV_HAS_NO_UNALIGNED)
3049 // check for natural alignment
3050 if (!v8_flags.riscv_c_extension && ((addr & (sizeof(T) - 1)) != 0)) {
3051 PrintF("Unaligned write at 0x%08" REGIx_FORMAT " , pc=0x%08" V8PRIxPTR "\n",
3052 addr, reinterpret_cast<intptr_t>(instr));
3053 DieOrDebug();
3054 }
3055#endif
3056 float* ptr = reinterpret_cast<float*>(addr);
3057 TraceMemWr(addr, value.get_scalar());
3058 memcpy(ptr, &value, 4);
3059}
3060
3061template <>
3062void Simulator::WriteMem(sreg_t addr, Float64 value, Instruction* instr) {
3063 if (addr >= 0 && addr < 0x400) {
3064 // This has to be a nullptr-dereference, drop into debugger.
3065 PrintF("Memory write to bad address: 0x%08" REGIx_FORMAT
3066 " , pc=0x%08" PRIxPTR " \n",
3067 addr, reinterpret_cast<intptr_t>(instr));
3068 DieOrDebug();
3069 }
3070#if !defined(V8_COMPRESS_POINTERS) && defined(RISCV_HAS_NO_UNALIGNED)
3071 // check for natural alignment
3072 if (!v8_flags.riscv_c_extension && ((addr & (sizeof(T) - 1)) != 0)) {
3073 PrintF("Unaligned write at 0x%08" REGIx_FORMAT " , pc=0x%08" V8PRIxPTR "\n",
3074 addr, reinterpret_cast<intptr_t>(instr));
3075 DieOrDebug();
3076 }
3077#endif
3078 double* ptr = reinterpret_cast<double*>(addr);
3079 TraceMemWrDouble(addr, value.get_scalar());
3080 memcpy(ptr, &value, 8);
3081}
3082
3083// Returns the limit of the stack area to enable checking for stack overflows.
3084uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
3085 // The simulator uses a separate JS stack. If we have exhausted the C stack,
3086 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
3087 if (GetCurrentStackPosition() < c_limit) {
3088 return reinterpret_cast<uintptr_t>(get_sp());
3089 }
3090
3091 // Otherwise the limit is the JS stack. Leave a safety margin to prevent
3092 // overrunning the stack when pushing values.
3093 return stack_limit_ + kAdditionalStackMargin;
3094}
3095
3096uintptr_t Simulator::StackBase() const { return stack_ + UsableStackSize(); }
3097
3098base::Vector<uint8_t> Simulator::GetCentralStackView() const {
3099 // We do not add an additional safety margin as above in
3100 // Simulator::StackLimit, as users of this method are expected to add their
3101 // own margin.
3102 return base::VectorOf(
3103 reinterpret_cast<uint8_t*>(stack_ + kStackProtectionSize),
3104 UsableStackSize());
3105}
3106
3107// We touch the stack, which may or may not have been initialized properly. Msan
3108// reports here are not interesting.
3109DISABLE_MSAN void Simulator::IterateRegistersAndStack(
3110 ::heap::base::StackVisitor* visitor) {
3111 for (int i = 0; i < kNumSimuRegisters; ++i) {
3112 visitor->VisitPointer(reinterpret_cast<const void*>(get_register(i)));
3113 }
3114 for (const void* const* current =
3115 reinterpret_cast<const void* const*>(get_sp());
3117 const void* address = *current;
3118 if (address == nullptr) {
3119 continue;
3120 }
3121 visitor->VisitPointer(address);
3122 }
3123}
3124
3125// Unsupported instructions use Format to print an error and stop execution.
3126void Simulator::Format(Instruction* instr, const char* format) {
3127 PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR " : %s\n",
3128 reinterpret_cast<intptr_t>(instr), format);
3130}
3131
3132// Calls into the V8 runtime are based on this very simple interface.
3133// Note: To be able to return two values from some calls the code in
3134// runtime.cc uses the ObjectPair which is essentially two 32-bit values
3135// stuffed into a 64-bit value. With the code below we assume that all runtime
3136// calls return 64 bits of result. If they don't, the a1 result register
3137// contains a bogus value, which is fine because it is caller-saved.
3138#if V8_TARGET_ARCH_RISCV64
3139using SimulatorRuntimeCall = ObjectPair (*)(
3140#elif V8_TARGET_ARCH_RISCV32
3141using SimulatorRuntimeCall = int64_t (*)(
3142#endif
3143 sreg_t arg0, sreg_t arg1, sreg_t arg2, sreg_t arg3, sreg_t arg4,
3144 sreg_t arg5, sreg_t arg6, sreg_t arg7, sreg_t arg8, sreg_t arg9,
3145 sreg_t arg10, sreg_t arg11, sreg_t arg12, sreg_t arg13, sreg_t arg14,
3146 sreg_t arg15, sreg_t arg16, sreg_t arg17, sreg_t arg18, sreg_t arg19);
3147
3148// These prototypes handle the four types of FP calls.
3149using SimulatorRuntimeCompareCall = int64_t (*)(double darg0, double darg1);
3150using SimulatorRuntimeFPFPCall = double (*)(double darg0, double darg1);
3151using SimulatorRuntimeFPCall = double (*)(double darg0);
3152using SimulatorRuntimeFPIntCall = double (*)(double darg0, int32_t arg0);
3153using SimulatorRuntimeIntFPCall = int32_t (*)(double darg0);
3154
3155// This signature supports direct call in to API function native callback
3156// (refer to InvocationCallback in v8.h).
3157using SimulatorRuntimeDirectApiCall = void (*)(sreg_t arg0);
3158
3159// This signature supports direct call to accessor getter callback.
3160using SimulatorRuntimeDirectGetterCall = void (*)(sreg_t arg0, sreg_t arg1);
3161
3162// Define four args for future flexibility; at the time of this writing only
3163// one is ever used.
3164using SimulatorRuntimeFPTaggedCall = double (*)(int64_t arg0, int64_t arg1,
3165 int64_t arg2, int64_t arg3);
3166
3167#ifdef V8_TARGET_ARCH_RISCV64
3168using MixedRuntimeCall_0 = AnyCType (*)();
3169#define BRACKETS(ident, N) ident[N]
3170#define REP_0(expr, FMT)
3171#define REP_1(expr, FMT) FMT(expr, 0)
3172#define REP_2(expr, FMT) REP_1(expr, FMT), FMT(expr, 1)
3173#define REP_3(expr, FMT) REP_2(expr, FMT), FMT(expr, 2)
3174#define REP_4(expr, FMT) REP_3(expr, FMT), FMT(expr, 3)
3175#define REP_5(expr, FMT) REP_4(expr, FMT), FMT(expr, 4)
3176#define REP_6(expr, FMT) REP_5(expr, FMT), FMT(expr, 5)
3177#define REP_7(expr, FMT) REP_6(expr, FMT), FMT(expr, 6)
3178#define REP_8(expr, FMT) REP_7(expr, FMT), FMT(expr, 7)
3179#define REP_9(expr, FMT) REP_8(expr, FMT), FMT(expr, 8)
3180#define REP_10(expr, FMT) REP_9(expr, FMT), FMT(expr, 9)
3181#define REP_11(expr, FMT) REP_10(expr, FMT), FMT(expr, 10)
3182#define REP_12(expr, FMT) REP_11(expr, FMT), FMT(expr, 11)
3183#define REP_13(expr, FMT) REP_12(expr, FMT), FMT(expr, 12)
3184#define REP_14(expr, FMT) REP_13(expr, FMT), FMT(expr, 13)
3185#define REP_15(expr, FMT) REP_14(expr, FMT), FMT(expr, 14)
3186#define REP_16(expr, FMT) REP_15(expr, FMT), FMT(expr, 15)
3187#define REP_17(expr, FMT) REP_16(expr, FMT), FMT(expr, 16)
3188#define REP_18(expr, FMT) REP_17(expr, FMT), FMT(expr, 17)
3189#define REP_19(expr, FMT) REP_18(expr, FMT), FMT(expr, 18)
3190#define REP_20(expr, FMT) REP_19(expr, FMT), FMT(expr, 19)
3191#define GEN_MAX_PARAM_COUNT(V) \
3192 V(0) \
3193 V(1) \
3194 V(2) \
3195 V(3) \
3196 V(4) \
3197 V(5) \
3198 V(6) \
3199 V(7) \
3200 V(8) \
3201 V(9) \
3202 V(10) \
3203 V(11) \
3204 V(12) \
3205 V(13) \
3206 V(14) \
3207 V(15) \
3208 V(16) \
3209 V(17) \
3210 V(18) \
3211 V(19) \
3212 V(20)
3213#define MIXED_RUNTIME_CALL(N) \
3214 using MixedRuntimeCall_##N = AnyCType (*)(REP_##N(AnyCType arg, CONCAT));
3215GEN_MAX_PARAM_COUNT(MIXED_RUNTIME_CALL)
3216#undef MIXED_RUNTIME_CALL
3217#define CALL_ARGS(N) REP_##N(args, BRACKETS)
3218#define CALL_TARGET_VARARG(N) \
3219 if (signature.ParameterCount() == N) { /* NOLINT */ \
3220 MixedRuntimeCall_##N target = \
3221 reinterpret_cast<MixedRuntimeCall_##N>(target_address); \
3222 result = target(CALL_ARGS(N)); \
3223 } else /* NOLINT */
3224#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
3225#define RETURN_REGISTER a0
3226#define FP_PARAM_REGISTERS fa0, fa1, fa2, fa3, fa4, fa5, fa6, fa7
3227#define FP_RETURN_REGISTER fa0
3228void Simulator::CallAnyCTypeFunction(Address target_address,
3229 const EncodedCSignature& signature) {
3230 const int64_t* stack_pointer = reinterpret_cast<int64_t*>(get_register(sp));
3231 const double* double_stack_pointer =
3232 reinterpret_cast<double*>(get_register(sp));
3233 const Register kParamRegisters[] = {PARAM_REGISTERS};
3234 const FPURegister kFPParamRegisters[] = {FP_PARAM_REGISTERS};
3235 CHECK_LE(signature.ParameterCount(), kMaxCParameters);
3236 static_assert(sizeof(AnyCType) == 8, "AnyCType is assumed to be 64-bit.");
3237 AnyCType args[kMaxCParameters];
3238 int num_gp_params = 0, num_fp_params = 0, num_stack_params = 0;
3239 for (int i = 0; i < signature.ParameterCount(); ++i) {
3240 if (signature.IsFloat(i)) {
3241 if (num_fp_params < 8) {
3242 args[i].double_value =
3243 get_fpu_register_double(kFPParamRegisters[num_fp_params++]);
3244 } else {
3245 args[i].double_value = double_stack_pointer[num_stack_params++];
3246 }
3247 } else {
3248 if (num_gp_params < 8) {
3249 args[i].int64_value = get_register(kParamRegisters[num_gp_params++]);
3250 } else {
3251 args[i].int64_value = stack_pointer[num_stack_params++];
3252 }
3253 }
3254 }
3255 AnyCType result;
3256 GEN_MAX_PARAM_COUNT(CALL_TARGET_VARARG)
3257 /* else */ {
3258 UNREACHABLE();
3259 }
3260 static_assert(20 == kMaxCParameters,
3261 "If you've changed kMaxCParameters, please change the "
3262 "GEN_MAX_PARAM_COUNT macro.");
3263 if (v8_flags.trace_sim) {
3264 printf("CallAnyCTypeFunction end result \n");
3265 }
3266#undef CALL_TARGET_VARARG
3267#undef CALL_ARGS
3268#undef GEN_MAX_PARAM_COUNT
3269 if (signature.IsReturnFloat()) {
3270 if (signature.IsReturnFloat64()) {
3271 set_fpu_register_double(FP_RETURN_REGISTER, result.double_value);
3272 } else {
3273 set_fpu_register_float(FP_RETURN_REGISTER, result.float_value);
3274 }
3275 } else {
3276 set_register(RETURN_REGISTER, result.int64_value);
3277 }
3278}
3279#undef PARAM_REGISTERS
3280#undef RETURN_REGISTER
3281#undef FP_PARAM_REGISTERS
3282#undef FP_RETURN_REGISTER
3283#endif // V8_TARGET_ARCH_RISCV64
3284
3285// Software interrupt instructions are used by the simulator to call into the
3286// C-based V8 runtime. They are also used for debugging with simulator.
3287void Simulator::SoftwareInterrupt() {
3288 // There are two instructions that could get us here, the ebreak or ecall
3289 // instructions are "SYSTEM" class opcode distinuished by Imm12Value field w/
3290 // the rest of instruction fields being zero
3291 int32_t func = instr_.Imm12Value();
3292 // We first check if we met a call_rt_redirected.
3293 if (instr_.InstructionBits() == rtCallRedirInstr) { // ECALL
3294 Redirection* redirection = Redirection::FromInstruction(instr_.instr());
3295
3296 // This is dodgy but it works because the C entry stubs are never moved.
3297 int64_t saved_ra = get_register(ra);
3298 intptr_t external =
3299 reinterpret_cast<intptr_t>(redirection->external_function());
3300#ifdef V8_TARGET_ARCH_RISCV64
3301 Address func_addr =
3302 reinterpret_cast<Address>(redirection->external_function());
3303 SimulatorData* simulator_data = isolate_->simulator_data();
3304 DCHECK_NOT_NULL(simulator_data);
3305 const EncodedCSignature& signature =
3306 simulator_data->GetSignatureForTarget(func_addr);
3307 if (signature.IsValid()) {
3308 CHECK_EQ(redirection->type(), ExternalReference::FAST_C_CALL);
3309 CallAnyCTypeFunction(external, signature);
3310 set_register(ra, saved_ra);
3311 set_pc(get_register(ra));
3312 return;
3313 }
3314#endif
3315
3316 sreg_t* stack_pointer = reinterpret_cast<sreg_t*>(get_register(sp));
3317
3318 const sreg_t arg0 = get_register(a0);
3319 const sreg_t arg1 = get_register(a1);
3320 const sreg_t arg2 = get_register(a2);
3321 const sreg_t arg3 = get_register(a3);
3322 const sreg_t arg4 = get_register(a4);
3323 const sreg_t arg5 = get_register(a5);
3324 const sreg_t arg6 = get_register(a6);
3325 const sreg_t arg7 = get_register(a7);
3326 const sreg_t arg8 = stack_pointer[0];
3327 const sreg_t arg9 = stack_pointer[1];
3328 const sreg_t arg10 = stack_pointer[2];
3329 const sreg_t arg11 = stack_pointer[3];
3330 const sreg_t arg12 = stack_pointer[4];
3331 const sreg_t arg13 = stack_pointer[5];
3332 const sreg_t arg14 = stack_pointer[6];
3333 const sreg_t arg15 = stack_pointer[7];
3334 const sreg_t arg16 = stack_pointer[8];
3335 const sreg_t arg17 = stack_pointer[9];
3336 const sreg_t arg18 = stack_pointer[10];
3337 const sreg_t arg19 = stack_pointer[11];
3338 static_assert(kMaxCParameters == 20);
3339
3340 bool fp_call =
3341 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
3342 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
3343 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
3344 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL) ||
3345 (redirection->type() == ExternalReference::BUILTIN_INT_FP_CALL);
3346
3347 sreg_t pc = get_pc();
3348
3349 if (fp_call) {
3350 double dval0, dval1; // one or two double parameters
3351 int32_t ival; // zero or one integer parameters
3352 int64_t iresult = 0; // integer return value
3353 double dresult = 0; // double return value
3354 GetFpArgs(&dval0, &dval1, &ival);
3355 SimulatorRuntimeCall generic_target =
3356 reinterpret_cast<SimulatorRuntimeCall>(external);
3357 if (v8_flags.trace_sim) {
3358 switch (redirection->type()) {
3359 case ExternalReference::BUILTIN_FP_FP_CALL:
3360 case ExternalReference::BUILTIN_COMPARE_CALL:
3361 PrintF("Call to host function %s at %p with args %f, %f",
3362 ExternalReferenceTable::NameOfIsolateIndependentAddress(
3363 pc, IsolateGroup::current()->external_ref_table()),
3364 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
3365 dval0, dval1);
3366 break;
3367 case ExternalReference::BUILTIN_FP_CALL:
3368 PrintF("Call to host function %s at %p with arg %f",
3369 ExternalReferenceTable::NameOfIsolateIndependentAddress(
3370 pc, IsolateGroup::current()->external_ref_table()),
3371 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
3372 dval0);
3373 break;
3374 case ExternalReference::BUILTIN_FP_INT_CALL:
3375 PrintF("Call to host function %s at %p with args %f, %d",
3376 ExternalReferenceTable::NameOfIsolateIndependentAddress(
3377 pc, IsolateGroup::current()->external_ref_table()),
3378 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
3379 dval0, ival);
3380 break;
3381 case ExternalReference::BUILTIN_INT_FP_CALL:
3382 PrintF("Call to host function %s at %p with args %f",
3383 ExternalReferenceTable::NameOfIsolateIndependentAddress(
3384 pc, IsolateGroup::current()->external_ref_table()),
3385 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
3386 dval0);
3387 break;
3388 default:
3389 UNREACHABLE();
3390 }
3391 }
3392 switch (redirection->type()) {
3393 case ExternalReference::BUILTIN_COMPARE_CALL: {
3394 SimulatorRuntimeCompareCall target =
3395 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
3396 iresult = target(dval0, dval1);
3397 set_register(a0, static_cast<sreg_t>(iresult));
3398 // set_register(a1, static_cast<int64_t>(iresult >> 32));
3399 break;
3400 }
3401 case ExternalReference::BUILTIN_FP_FP_CALL: {
3402 SimulatorRuntimeFPFPCall target =
3403 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
3404 dresult = target(dval0, dval1);
3405 SetFpResult(dresult);
3406 break;
3407 }
3408 case ExternalReference::BUILTIN_FP_CALL: {
3409 SimulatorRuntimeFPCall target =
3410 reinterpret_cast<SimulatorRuntimeFPCall>(external);
3411 dresult = target(dval0);
3412 SetFpResult(dresult);
3413 break;
3414 }
3415 case ExternalReference::BUILTIN_FP_INT_CALL: {
3416 SimulatorRuntimeFPIntCall target =
3417 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
3418 dresult = target(dval0, ival);
3419 SetFpResult(dresult);
3420 break;
3421 }
3422 case ExternalReference::BUILTIN_INT_FP_CALL: {
3423 SimulatorRuntimeIntFPCall target =
3424 reinterpret_cast<SimulatorRuntimeIntFPCall>(external);
3425 iresult = target(dval0);
3426 set_register(a0, static_cast<int64_t>(iresult));
3427 break;
3428 }
3429 default:
3430 UNREACHABLE();
3431 }
3432 if (v8_flags.trace_sim) {
3433 switch (redirection->type()) {
3434 case ExternalReference::BUILTIN_COMPARE_CALL:
3435 case ExternalReference::BUILTIN_INT_FP_CALL:
3436 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
3437 break;
3438 case ExternalReference::BUILTIN_FP_FP_CALL:
3439 case ExternalReference::BUILTIN_FP_CALL:
3440 case ExternalReference::BUILTIN_FP_INT_CALL:
3441 PrintF("Returned %f\n", dresult);
3442 break;
3443 default:
3444 UNREACHABLE();
3445 }
3446 }
3447 } else if (redirection->type() ==
3448 ExternalReference::BUILTIN_FP_POINTER_CALL) {
3449 if (v8_flags.trace_sim) {
3450 PrintF("Call to host function at %p args %08" REGIx_FORMAT " \n",
3451 reinterpret_cast<void*>(external), arg0);
3452 }
3453 SimulatorRuntimeFPTaggedCall target =
3454 reinterpret_cast<SimulatorRuntimeFPTaggedCall>(external);
3455 double dresult = target(arg0, arg1, arg2, arg3);
3456 SetFpResult(dresult);
3457 if (v8_flags.trace_sim) {
3458 PrintF("Returned %f\n", dresult);
3459 }
3460 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
3461 // See callers of MacroAssembler::CallApiFunctionAndReturn for
3462 // explanation of register usage.
3463 // void f(v8::FunctionCallbackInfo&)
3464 if (v8_flags.trace_sim) {
3465 PrintF("Call to host function %s at %p args %08" REGIx_FORMAT " \n",
3466 ExternalReferenceTable::NameOfIsolateIndependentAddress(
3467 pc, IsolateGroup::current()->external_ref_table()),
3468 reinterpret_cast<void*>(external), arg0);
3469 }
3470 SimulatorRuntimeDirectApiCall target =
3471 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
3472 target(arg0);
3473 } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
3474 // See callers of MacroAssembler::CallApiFunctionAndReturn for
3475 // explanation of register usage.
3476 // void f(v8::Local<String> property, v8::PropertyCallbackInfo& info)
3477 if (v8_flags.trace_sim) {
3478 PrintF("Call to host function at %p args %08" REGIx_FORMAT
3479 " %08" REGIx_FORMAT " \n",
3480 reinterpret_cast<void*>(external), arg0, arg1);
3481 }
3482 SimulatorRuntimeDirectGetterCall target =
3483 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
3484 target(arg0, arg1);
3485 } else {
3486#ifdef V8_TARGET_ARCH_RISCV64
3487 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
3488 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
3489#else // V8_TARGET_ARCH_RISCV32
3490 // FAST_C_CALL is temporarily handled here as well, because we lack
3491 // proper support for direct C calls with FP params in the simulator.
3492 // The generic BUILTIN_CALL path assumes all parameters are passed in
3493 // the GP registers, thus supporting calling the slow callback without
3494 // crashing. The reason for that is that in the mjsunit tests we check
3495 // the `fast_c_api.supports_fp_params` (which is false on non-simulator
3496 // builds for arm/arm64), thus we expect that the slow path will be
3497 // called. And since the slow path passes the arguments as a `const
3498 // FunctionCallbackInfo<Value>&` (which is a GP argument), the call is
3499 // made correctly.
3500 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
3501 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR ||
3502 redirection->type() == ExternalReference::FAST_C_CALL);
3503#endif // V8_TARGET_ARCH_RISCV64
3504 SimulatorRuntimeCall target =
3505 reinterpret_cast<SimulatorRuntimeCall>(external);
3506 if (v8_flags.trace_sim) {
3507 PrintF(
3508 "Call to host function %s at %p "
3509 "args %08" REGIx_FORMAT " , %08" REGIx_FORMAT " , %08" REGIx_FORMAT
3510 " , %08" REGIx_FORMAT " , %08" REGIx_FORMAT " , %08" REGIx_FORMAT
3511 " , %08" REGIx_FORMAT " , %08" REGIx_FORMAT " , %08" REGIx_FORMAT
3512 " , %08" REGIx_FORMAT " , %016" REGIx_FORMAT " , %016" REGIx_FORMAT
3513 " , %016" REGIx_FORMAT " , %016" REGIx_FORMAT " , %016" REGIx_FORMAT
3514 " , %016" REGIx_FORMAT " , %016" REGIx_FORMAT " , %016" REGIx_FORMAT
3515 " , %016" REGIx_FORMAT " , %016" REGIx_FORMAT " \n",
3516 ExternalReferenceTable::NameOfIsolateIndependentAddress(
3517 pc, IsolateGroup::current()->external_ref_table()),
3518 reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2,
3519 arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12,
3520 arg13, arg14, arg15, arg16, arg17, arg18, arg19);
3521 }
3522#if V8_TARGET_ARCH_RISCV64
3523 ObjectPair result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
3524 arg8, arg9, arg10, arg11, arg12, arg13, arg14,
3525 arg15, arg16, arg17, arg18, arg19);
3526 set_register(a0, (sreg_t)(result.x));
3527 set_register(a1, (sreg_t)(result.y));
3528
3529#elif V8_TARGET_ARCH_RISCV32
3530 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
3531 arg8, arg9, arg10, arg11, arg12, arg13, arg14,
3532 arg15, arg16, arg17, arg18, arg19);
3533 set_register(a0, (sreg_t)result);
3534 set_register(a1, (sreg_t)(result >> 32));
3535#endif
3536 }
3537 if (v8_flags.trace_sim) {
3538 PrintF("Returned %08" REGIx_FORMAT " : %08" REGIx_FORMAT " \n",
3539 get_register(a1), get_register(a0));
3540 }
3541 set_register(ra, saved_ra);
3542 set_pc(get_register(ra));
3543
3544 } else if (func == 1) { // EBREAK
3545 int32_t code = get_ebreak_code(instr_.instr());
3546 set_pc(get_pc() + kInstrSize * 2);
3547 if (code != -1 && static_cast<uint32_t>(code) <= kMaxStopCode) {
3548 if (IsWatchpoint(code)) {
3549 PrintWatchpoint(code);
3550 } else if (IsTracepoint(code)) {
3551 if (!v8_flags.debug_sim) {
3552 PrintF("Add --debug-sim when tracepoint instruction is used.\n");
3553 abort();
3554 }
3555 Builtin builtin = LookUp((Address)get_pc());
3556 printf("%d %d %d %d\n", code, code & LOG_TRACE, code & LOG_REGS,
3557 code & kDebuggerTracingDirectivesMask);
3558 if (builtin != Builtin::kNoBuiltinId) {
3559 printf("Builitin: %s\n", builtins_.name(builtin));
3560 }
3561 switch (code & kDebuggerTracingDirectivesMask) {
3562 case TRACE_ENABLE:
3563 if (code & LOG_TRACE) {
3564 v8_flags.trace_sim = true;
3565 }
3566 if (code & LOG_REGS) {
3567 RiscvDebugger dbg(this);
3568 dbg.PrintAllRegs();
3569 }
3570 break;
3571 case TRACE_DISABLE:
3572 if (code & LOG_TRACE) {
3573 v8_flags.trace_sim = false;
3574 }
3575 break;
3576 default:
3577 UNREACHABLE();
3578 }
3579 } else {
3580 IncreaseStopCounter(code);
3581 HandleStop(code);
3582 }
3583 } else if (IsSwitchStackLimit(code)) {
3584 if (v8_flags.trace_sim) {
3585 PrintF("Switching stack limit\n");
3586 }
3587 DoSwitchStackLimit(instr_.instr());
3588 } else {
3589 // All remaining break_ codes, and all traps are handled here.
3590 RiscvDebugger dbg(this);
3591 dbg.Debug();
3592 }
3593 } else {
3594 UNREACHABLE();
3595 }
3596}
3597
3598// Stop helper functions.
3599bool Simulator::IsWatchpoint(reg_t code) {
3600 return (code <= kMaxWatchpointCode);
3601}
3602
3603bool Simulator::IsTracepoint(reg_t code) {
3604 return (code <= kMaxTracepointCode && code > kMaxWatchpointCode);
3605}
3606
3607bool Simulator::IsSwitchStackLimit(reg_t code) {
3608 return code == kExceptionIsSwitchStackLimit;
3609}
3610
3611void Simulator::PrintWatchpoint(reg_t code) {
3612 RiscvDebugger dbg(this);
3613 ++break_count_;
3614 PrintF("\n---- watchpoint %" REGId_FORMAT
3615 " marker: %3d (instr count: %8" PRId64
3616 " ) ----------"
3617 "----------------------------------",
3618 code, break_count_, icount_);
3619 dbg.PrintAllRegs(); // Print registers and continue running.
3620}
3621
3622void Simulator::HandleStop(reg_t code) {
3623 // Stop if it is enabled, otherwise go on jumping over the stop
3624 // and the message address.
3625 if (IsEnabledStop(code)) {
3626 PrintF("Simulator hit stop (%" REGId_FORMAT ")\n", code);
3627 DieOrDebug();
3628 }
3629}
3630
3631bool Simulator::IsStopInstruction(Instruction* instr) {
3632 if (instr->InstructionBits() != kBreakInstr) return false;
3633 int32_t code = get_ebreak_code(instr);
3634 return code != -1 && static_cast<uint32_t>(code) > kMaxWatchpointCode &&
3635 static_cast<uint32_t>(code) <= kMaxStopCode;
3636}
3637
3638bool Simulator::IsEnabledStop(reg_t code) {
3639 DCHECK_LE(code, kMaxStopCode);
3640 DCHECK_GT(code, kMaxWatchpointCode);
3641 return !(watched_stops_[code].count & kStopDisabledBit);
3642}
3643
3644void Simulator::EnableStop(reg_t code) {
3645 if (!IsEnabledStop(code)) {
3646 watched_stops_[code].count &= ~kStopDisabledBit;
3647 }
3648}
3649
3650void Simulator::DisableStop(reg_t code) {
3651 if (IsEnabledStop(code)) {
3652 watched_stops_[code].count |= kStopDisabledBit;
3653 }
3654}
3655
3656void Simulator::IncreaseStopCounter(reg_t code) {
3657 DCHECK_LE(code, kMaxStopCode);
3658 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7FFFFFFF) {
3659 PrintF("Stop counter for code %" REGId_FORMAT
3660 " has overflowed.\n"
3661 "Enabling this code and reseting the counter to 0.\n",
3662 code);
3663 watched_stops_[code].count = 0;
3664 EnableStop(code);
3665 } else {
3666 watched_stops_[code].count++;
3667 }
3668}
3669
3670// Print a stop status.
3671void Simulator::PrintStopInfo(reg_t code) {
3672 if (code <= kMaxWatchpointCode) {
3673 PrintF("That is a watchpoint, not a stop.\n");
3674 return;
3675 } else if (code > kMaxStopCode) {
3676 PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
3677 return;
3678 }
3679 const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
3680 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
3681 // Don't print the state of unused breakpoints.
3682 if (count != 0) {
3683 if (watched_stops_[code].desc) {
3684 PrintF("stop %" REGId_FORMAT " - 0x%" REGIx_FORMAT
3685 " : \t%s, \tcounter = %i, \t%s\n",
3686 code, code, state, count, watched_stops_[code].desc);
3687 } else {
3688 PrintF("stop %" REGId_FORMAT " - 0x%" REGIx_FORMAT
3689 " : \t%s, \tcounter = %i\n",
3690 code, code, state, count);
3691 }
3692 }
3693}
3694
3695void Simulator::SignalException(Exception e) {
3696 FATAL("Error: Exception %i raised.", static_cast<int>(e));
3697}
3698
3699// RISCV Instruction Decode Routine
3700void Simulator::DecodeRVRType() {
3701 switch (instr_.InstructionBits() & kRTypeMask) {
3702 case RO_ADD: {
3703 set_rd(sext_xlen(rs1() + rs2()));
3704 break;
3705 }
3706 case RO_SUB: {
3707 set_rd(sext_xlen(rs1() - rs2()));
3708 break;
3709 }
3710 case RO_SLL: {
3711 set_rd(sext_xlen(rs1() << (rs2() & (xlen - 1))));
3712 break;
3713 }
3714 case RO_SLT: {
3715 set_rd(sreg_t(rs1()) < sreg_t(rs2()));
3716 break;
3717 }
3718 case RO_SLTU: {
3719 set_rd(reg_t(rs1()) < reg_t(rs2()));
3720 break;
3721 }
3722 case RO_XOR: {
3723 set_rd(rs1() ^ rs2());
3724 break;
3725 }
3726 case RO_SRL: {
3727 set_rd(sext_xlen(zext_xlen(rs1()) >> (rs2() & (xlen - 1))));
3728 break;
3729 }
3730 case RO_SRA: {
3731 set_rd(sext_xlen(sext_xlen(rs1()) >> (rs2() & (xlen - 1))));
3732 break;
3733 }
3734 case RO_OR: {
3735 set_rd(rs1() | rs2());
3736 break;
3737 }
3738 case RO_AND: {
3739 set_rd(rs1() & rs2());
3740 break;
3741 }
3742 case RO_ANDN:
3743 set_rd(rs1() & ~rs2());
3744 break;
3745 case RO_ORN:
3746 set_rd(rs1() | (~rs2()));
3747 break;
3748 case RO_XNOR:
3749 set_rd((~rs1()) ^ (~rs2()));
3750 break;
3751#ifdef V8_TARGET_ARCH_RISCV64
3752 case RO_ADDW: {
3753 set_rd(sext32(rs1() + rs2()));
3754 break;
3755 }
3756 case RO_ADDUW:
3757 set_rd(zext32(rs1()) + rs2());
3758 break;
3759 case RO_SUBW: {
3760 set_rd(sext32(rs1() - rs2()));
3761 break;
3762 }
3763 case RO_SLLW: {
3764 set_rd(sext32(rs1() << (rs2() & 0x1F)));
3765 break;
3766 }
3767 case RO_SRLW: {
3768 set_rd(sext32(uint32_t(rs1()) >> (rs2() & 0x1F)));
3769 break;
3770 }
3771 case RO_SRAW: {
3772 set_rd(sext32(int32_t(rs1()) >> (rs2() & 0x1F)));
3773 break;
3774 }
3775 case RO_SH1ADDUW: {
3776 set_rd(rs2() + (zext32(rs1()) << 1));
3777 break;
3778 }
3779 case RO_SH2ADDUW: {
3780 set_rd(rs2() + (zext32(rs1()) << 2));
3781 break;
3782 }
3783 case RO_SH3ADDUW: {
3784 set_rd(rs2() + (zext32(rs1()) << 3));
3785 break;
3786 }
3787 case RO_ROLW: {
3788 reg_t extz_rs1 = zext32(rs1());
3789 sreg_t shamt = rs2() & 31;
3790 set_rd(sext32((extz_rs1 << shamt) | (extz_rs1 >> (32 - shamt))));
3791 break;
3792 }
3793 case RO_RORW: {
3794 reg_t extz_rs1 = zext32(rs1());
3795 sreg_t shamt = rs2() & 31;
3796 set_rd(sext32((extz_rs1 >> shamt) | (extz_rs1 << (32 - shamt))));
3797 break;
3798 }
3799#endif /* V8_TARGET_ARCH_RISCV64 */
3800 // TODO(riscv): Add RISCV M extension macro
3801 case RO_MUL: {
3802 set_rd(rs1() * rs2());
3803 break;
3804 }
3805 case RO_MULH: {
3806 set_rd(mulh(rs1(), rs2()));
3807 break;
3808 }
3809 case RO_MULHSU: {
3810 set_rd(mulhsu(rs1(), rs2()));
3811 break;
3812 }
3813 case RO_MULHU: {
3814 set_rd(mulhu(rs1(), rs2()));
3815 break;
3816 }
3817 case RO_DIV: {
3818 sreg_t lhs = sext_xlen(rs1());
3819 sreg_t rhs = sext_xlen(rs2());
3820 if (rhs == 0) {
3821 set_rd(-1);
3822 } else if (lhs == INTPTR_MIN && rhs == -1) {
3823 set_rd(lhs);
3824 } else {
3825 set_rd(sext_xlen(lhs / rhs));
3826 }
3827 break;
3828 }
3829 case RO_DIVU: {
3830 reg_t lhs = zext_xlen(rs1());
3831 reg_t rhs = zext_xlen(rs2());
3832 if (rhs == 0) {
3833 set_rd(UINTPTR_MAX);
3834 } else {
3835 set_rd(zext_xlen(lhs / rhs));
3836 }
3837 break;
3838 }
3839 case RO_REM: {
3840 sreg_t lhs = sext_xlen(rs1());
3841 sreg_t rhs = sext_xlen(rs2());
3842 if (rhs == 0) {
3843 set_rd(lhs);
3844 } else if (lhs == INTPTR_MIN && rhs == -1) {
3845 set_rd(0);
3846 } else {
3847 set_rd(sext_xlen(lhs % rhs));
3848 }
3849 break;
3850 }
3851 case RO_REMU: {
3852 reg_t lhs = zext_xlen(rs1());
3853 reg_t rhs = zext_xlen(rs2());
3854 if (rhs == 0) {
3855 set_rd(lhs);
3856 } else {
3857 set_rd(zext_xlen(lhs % rhs));
3858 }
3859 break;
3860 }
3861#ifdef V8_TARGET_ARCH_RISCV64
3862 case RO_MULW: {
3863 set_rd(sext32(sext32(rs1()) * sext32(rs2())));
3864 break;
3865 }
3866 case RO_DIVW: {
3867 sreg_t lhs = sext32(rs1());
3868 sreg_t rhs = sext32(rs2());
3869 if (rhs == 0) {
3870 set_rd(-1);
3871 } else if (lhs == INT32_MIN && rhs == -1) {
3872 set_rd(lhs);
3873 } else {
3874 set_rd(sext32(lhs / rhs));
3875 }
3876 break;
3877 }
3878 case RO_DIVUW: {
3879 reg_t lhs = zext32(rs1());
3880 reg_t rhs = zext32(rs2());
3881 if (rhs == 0) {
3882 set_rd(UINT32_MAX);
3883 } else {
3884 set_rd(zext32(lhs / rhs));
3885 }
3886 break;
3887 }
3888 case RO_REMW: {
3889 sreg_t lhs = sext32(rs1());
3890 sreg_t rhs = sext32(rs2());
3891 if (rhs == 0) {
3892 set_rd(lhs);
3893 } else if (lhs == INT32_MIN && rhs == -1) {
3894 set_rd(0);
3895 } else {
3896 set_rd(sext32(lhs % rhs));
3897 }
3898 break;
3899 }
3900 case RO_REMUW: {
3901 reg_t lhs = zext32(rs1());
3902 reg_t rhs = zext32(rs2());
3903 if (rhs == 0) {
3904 set_rd(zext32(lhs));
3905 } else {
3906 set_rd(zext32(lhs % rhs));
3907 }
3908 break;
3909 }
3910#endif /*V8_TARGET_ARCH_RISCV64*/
3911 case RO_SH1ADD:
3912 set_rd(rs2() + (rs1() << 1));
3913 break;
3914 case RO_SH2ADD:
3915 set_rd(rs2() + (rs1() << 2));
3916 break;
3917 case RO_SH3ADD:
3918 set_rd(rs2() + (rs1() << 3));
3919 break;
3920 case RO_MAX:
3921 set_rd(rs1() < rs2() ? rs2() : rs1());
3922 break;
3923 case RO_MAXU:
3924 set_rd(reg_t(rs1()) < reg_t(rs2()) ? rs2() : rs1());
3925 break;
3926 case RO_MIN:
3927 set_rd(rs1() < rs2() ? rs1() : rs2());
3928 break;
3929 case RO_MINU:
3930 set_rd(reg_t(rs1()) < reg_t(rs2()) ? rs1() : rs2());
3931 break;
3932 case RO_ZEXTH:
3933 set_rd(zext_xlen(uint16_t(rs1())));
3934 break;
3935 case RO_ROL: {
3936 sreg_t shamt = rs2() & (xlen - 1);
3937 set_rd((reg_t(rs1()) << shamt) | (reg_t(rs1()) >> (xlen - shamt)));
3938 break;
3939 }
3940 case RO_ROR: {
3941 sreg_t shamt = rs2() & (xlen - 1);
3942 set_rd((reg_t(rs1()) >> shamt) | (reg_t(rs1()) << (xlen - shamt)));
3943 break;
3944 }
3945 case RO_BCLR: {
3946 sreg_t index = rs2() & (xlen - 1);
3947 set_rd(rs1() & ~(1l << index));
3948 break;
3949 }
3950 case RO_BEXT: {
3951 sreg_t index = rs2() & (xlen - 1);
3952 set_rd((rs1() >> index) & 1);
3953 break;
3954 }
3955 case RO_BINV: {
3956 sreg_t index = rs2() & (xlen - 1);
3957 set_rd(rs1() ^ (1 << index));
3958 break;
3959 }
3960 case RO_BSET: {
3961 sreg_t index = rs2() & (xlen - 1);
3962 set_rd(rs1() | (1 << index));
3963 break;
3964 }
3965 case RO_CZERO_EQZ: {
3966 sreg_t condition = rs2();
3967 set_rd(condition == 0 ? 0 : rs1());
3968 break;
3969 }
3970 case RO_CZERO_NEZ: {
3971 sreg_t condition = rs2();
3972 set_rd(condition != 0 ? 0 : rs1());
3973 break;
3974 }
3975 default: {
3976 switch (instr_.BaseOpcode()) {
3977 case AMO:
3978 DecodeRVRAType();
3979 break;
3980 case OP_FP:
3981 DecodeRVRFPType();
3982 break;
3983 default:
3984 UNSUPPORTED();
3985 }
3986 }
3987 }
3988}
3989
3990float Simulator::RoundF2FHelper(float input_val, int rmode) {
3991 if (rmode == DYN) rmode = get_dynamic_rounding_mode();
3992
3993 float rounded = 0;
3994 switch (rmode) {
3995 case RNE: { // Round to Nearest, tiest to Even
3996 rounded = floorf(input_val);
3997 float error = input_val - rounded;
3998
3999 // Take care of correctly handling the range [-0.5, -0.0], which must
4000 // yield -0.0.
4001 if ((-0.5 <= input_val) && (input_val < 0.0)) {
4002 rounded = -0.0;
4003
4004 // If the error is greater than 0.5, or is equal to 0.5 and the integer
4005 // result is odd, round up.
4006 } else if ((error > 0.5) ||
4007 ((error == 0.5) && (std::fmod(rounded, 2) != 0))) {
4008 rounded++;
4009 }
4010 break;
4011 }
4012 case RTZ: // Round towards Zero
4013 rounded = std::truncf(input_val);
4014 break;
4015 case RDN: // Round Down (towards -infinity)
4016 rounded = floorf(input_val);
4017 break;
4018 case RUP: // Round Up (towards +infinity)
4019 rounded = ceilf(input_val);
4020 break;
4021 case RMM: // Round to Nearest, tiest to Max Magnitude
4022 rounded = std::roundf(input_val);
4023 break;
4024 default:
4025 UNREACHABLE();
4026 }
4027
4028 return rounded;
4029}
4030
4031double Simulator::RoundF2FHelper(double input_val, int rmode) {
4032 if (rmode == DYN) rmode = get_dynamic_rounding_mode();
4033
4034 double rounded = 0;
4035 switch (rmode) {
4036 case RNE: { // Round to Nearest, tiest to Even
4037 rounded = std::floor(input_val);
4038 double error = input_val - rounded;
4039
4040 // Take care of correctly handling the range [-0.5, -0.0], which must
4041 // yield -0.0.
4042 if ((-0.5 <= input_val) && (input_val < 0.0)) {
4043 rounded = -0.0;
4044
4045 // If the error is greater than 0.5, or is equal to 0.5 and the integer
4046 // result is odd, round up.
4047 } else if ((error > 0.5) ||
4048 ((error == 0.5) && (std::fmod(rounded, 2) != 0))) {
4049 rounded++;
4050 }
4051 break;
4052 }
4053 case RTZ: // Round towards Zero
4054 rounded = std::trunc(input_val);
4055 break;
4056 case RDN: // Round Down (towards -infinity)
4057 rounded = std::floor(input_val);
4058 break;
4059 case RUP: // Round Up (towards +infinity)
4060 rounded = std::ceil(input_val);
4061 break;
4062 case RMM: // Round to Nearest, tiest to Max Magnitude
4063 rounded = std::round(input_val);
4064 break;
4065 default:
4066 UNREACHABLE();
4067 }
4068 return rounded;
4069}
4070
4071// convert rounded floating-point to integer types, handle input values that
4072// are out-of-range, underflow, or NaN, and set appropriate fflags
4073template <typename I_TYPE, typename F_TYPE>
4074I_TYPE Simulator::RoundF2IHelper(F_TYPE original, int rmode) {
4075 DCHECK(std::is_integral<I_TYPE>::value);
4076
4077 DCHECK((std::is_same<F_TYPE, float>::value ||
4078 std::is_same<F_TYPE, double>::value));
4079
4080 I_TYPE max_i = std::numeric_limits<I_TYPE>::max();
4081 I_TYPE min_i = std::numeric_limits<I_TYPE>::min();
4082
4083 if (!std::isfinite(original)) {
4084 set_fflags(kInvalidOperation);
4085 if (std::isnan(original) ||
4086 original == std::numeric_limits<F_TYPE>::infinity()) {
4087 return max_i;
4088 } else {
4089 DCHECK(original == -std::numeric_limits<F_TYPE>::infinity());
4090 return min_i;
4091 }
4092 }
4093
4094 F_TYPE rounded = RoundF2FHelper(original, rmode);
4095 if (original != rounded) set_fflags(kInexact);
4096
4097 if (!std::isfinite(rounded)) {
4098 set_fflags(kInvalidOperation);
4099 if (std::isnan(rounded) ||
4100 rounded == std::numeric_limits<F_TYPE>::infinity()) {
4101 return max_i;
4102 } else {
4103 DCHECK(rounded == -std::numeric_limits<F_TYPE>::infinity());
4104 return min_i;
4105 }
4106 }
4107
4108 // Since integer max values are either all 1s (for unsigned) or all 1s
4109 // except for sign-bit (for signed), they cannot be represented precisely in
4110 // floating point, in order to precisely tell whether the rounded floating
4111 // point is within the max range, we compare against (max_i+1) which would
4112 // have a single 1 w/ many trailing zeros
4113 float max_i_plus_1 =
4114 std::is_same<uint64_t, I_TYPE>::value
4115 ? 0x1p64f // uint64_t::max + 1 cannot be represented in integers,
4116 // so use its float representation directly
4117 : static_cast<float>(static_cast<uint64_t>(max_i) + 1);
4118 if (rounded >= max_i_plus_1) {
4119 set_fflags(kFPUOverflow | kInvalidOperation);
4120 return max_i;
4121 }
4122
4123 // Since min_i (either 0 for unsigned, or for signed) is represented
4124 // precisely in floating-point, comparing rounded directly against min_i
4125 if (rounded <= min_i) {
4126 if (rounded < min_i) set_fflags(kFPUOverflow | kInvalidOperation);
4127 return min_i;
4128 }
4129
4130 F_TYPE underflow_fval =
4131 std::is_same<F_TYPE, float>::value ? FLT_MIN : DBL_MIN;
4132 if (rounded < underflow_fval && rounded > -underflow_fval && rounded != 0) {
4133 set_fflags(kUnderflow);
4134 }
4135
4136 return static_cast<I_TYPE>(rounded);
4137}
4138
4139template <typename T>
4140static int64_t FclassHelper(T value) {
4141 switch (std::fpclassify(value)) {
4142 case FP_INFINITE:
4143 return (std::signbit(value) ? kNegativeInfinity : kPositiveInfinity);
4144 case FP_NAN:
4145 return (isSnan(value) ? kSignalingNaN : kQuietNaN);
4146 case FP_NORMAL:
4147 return (std::signbit(value) ? kNegativeNormalNumber
4148 : kPositiveNormalNumber);
4149 case FP_SUBNORMAL:
4150 return (std::signbit(value) ? kNegativeSubnormalNumber
4151 : kPositiveSubnormalNumber);
4152 case FP_ZERO:
4153 return (std::signbit(value) ? kNegativeZero : kPositiveZero);
4154 default:
4155 UNREACHABLE();
4156 }
4157}
4158
4159template <typename T>
4160bool Simulator::CompareFHelper(T input1, T input2, FPUCondition cc) {
4161 DCHECK(std::is_floating_point<T>::value);
4162 bool result = false;
4163 switch (cc) {
4164 case LT:
4165 case LE:
4166 // FLT, FLE are signaling compares
4167 if (std::isnan(input1) || std::isnan(input2)) {
4168 set_fflags(kInvalidOperation);
4169 result = false;
4170 } else {
4171 result = (cc == LT) ? (input1 < input2) : (input1 <= input2);
4172 }
4173 break;
4174
4175 case EQ:
4176 if (std::numeric_limits<T>::signaling_NaN() == input1 ||
4177 std::numeric_limits<T>::signaling_NaN() == input2) {
4178 set_fflags(kInvalidOperation);
4179 }
4180 if (std::isnan(input1) || std::isnan(input2)) {
4181 result = false;
4182 } else {
4183 result = (input1 == input2);
4184 }
4185 break;
4186 case NE:
4187 if (std::numeric_limits<T>::signaling_NaN() == input1 ||
4188 std::numeric_limits<T>::signaling_NaN() == input2) {
4189 set_fflags(kInvalidOperation);
4190 }
4191 if (std::isnan(input1) || std::isnan(input2)) {
4192 result = true;
4193 } else {
4194 result = (input1 != input2);
4195 }
4196 break;
4197 default:
4198 UNREACHABLE();
4199 }
4200 return result;
4201}
4202
4203template <typename T>
4204static inline bool is_invalid_fmul(T src1, T src2) {
4205 return (isinf(src1) && src2 == static_cast<T>(0.0)) ||
4206 (src1 == static_cast<T>(0.0) && isinf(src2));
4207}
4208
4209template <typename T>
4210static inline bool is_invalid_fadd(T src1, T src2) {
4211 return (isinf(src1) && isinf(src2) &&
4212 std::signbit(src1) != std::signbit(src2));
4213}
4214
4215template <typename T>
4216static inline bool is_invalid_fsub(T src1, T src2) {
4217 return (isinf(src1) && isinf(src2) &&
4218 std::signbit(src1) == std::signbit(src2));
4219}
4220
4221template <typename T>
4222static inline bool is_invalid_fdiv(T src1, T src2) {
4223 return ((src1 == 0 && src2 == 0) || (isinf(src1) && isinf(src2)));
4224}
4225
4226template <typename T>
4227static inline bool is_invalid_fsqrt(T src1) {
4228 return (src1 < 0);
4229}
4230
4231void Simulator::DecodeRVRAType() {
4232 // TODO(riscv): Add macro for RISCV A extension
4233 // Special handling for A extension instructions because it uses func5
4234 // For all A extension instruction, V8 simulator is pure sequential. No
4235 // Memory address lock or other synchronizaiton behaviors.
4236 switch (instr_.InstructionBits() & kRATypeMask) {
4237 case RO_LR_W: {
4238 sreg_t addr = rs1();
4239 if (!ProbeMemory(addr, sizeof(int32_t))) return;
4240 {
4241 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4242 if ((addr & 0x3) != 0) {
4243 DieOrDebug();
4244 }
4245 auto val = ReadMem<int32_t>(addr, instr_.instr());
4246 set_rd(sext32(val), false);
4247 TraceMemRd(addr, val, get_register(rd_reg()));
4248 local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word);
4249 GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr,
4250 &global_monitor_thread_);
4251 }
4252 break;
4253 }
4254 case RO_SC_W: {
4255 sreg_t addr = rs1();
4256 if (!ProbeMemory(addr, sizeof(int32_t))) return;
4257 if ((addr & 0x3) != 0) {
4258 DieOrDebug();
4259 }
4260 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4261 if (local_monitor_.NotifyStoreConditional(addr, TransactionSize::Word) &&
4262 GlobalMonitor::Get()->NotifyStoreConditional_Locked(
4263 addr, &global_monitor_thread_)) {
4264 local_monitor_.NotifyStore();
4265 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
4266 WriteMem<int32_t>(rs1(), (int32_t)rs2(), instr_.instr());
4267 set_rd(0, false);
4268 } else {
4269 set_rd(1, false);
4270 }
4271 break;
4272 }
4273 case RO_AMOSWAP_W: {
4274 if ((rs1() & 0x3) != 0) {
4275 DieOrDebug();
4276 }
4277 set_rd(sext32(amo<uint32_t>(
4278 rs1(), [&](uint32_t lhs) { return (uint32_t)rs2(); }, instr_.instr(),
4279 WORD)));
4280 break;
4281 }
4282 case RO_AMOADD_W: {
4283 if ((rs1() & 0x3) != 0) {
4284 DieOrDebug();
4285 }
4286 set_rd(sext32(amo<uint32_t>(
4287 rs1(), [&](uint32_t lhs) { return lhs + (uint32_t)rs2(); },
4288 instr_.instr(), WORD)));
4289 break;
4290 }
4291 case RO_AMOXOR_W: {
4292 if ((rs1() & 0x3) != 0) {
4293 DieOrDebug();
4294 }
4295 set_rd(sext32(amo<uint32_t>(
4296 rs1(), [&](uint32_t lhs) { return lhs ^ (uint32_t)rs2(); },
4297 instr_.instr(), WORD)));
4298 break;
4299 }
4300 case RO_AMOAND_W: {
4301 if ((rs1() & 0x3) != 0) {
4302 DieOrDebug();
4303 }
4304 set_rd(sext32(amo<uint32_t>(
4305 rs1(), [&](uint32_t lhs) { return lhs & (uint32_t)rs2(); },
4306 instr_.instr(), WORD)));
4307 break;
4308 }
4309 case RO_AMOOR_W: {
4310 if ((rs1() & 0x3) != 0) {
4311 DieOrDebug();
4312 }
4313 set_rd(sext32(amo<uint32_t>(
4314 rs1(), [&](uint32_t lhs) { return lhs | (uint32_t)rs2(); },
4315 instr_.instr(), WORD)));
4316 break;
4317 }
4318 case RO_AMOMIN_W: {
4319 if ((rs1() & 0x3) != 0) {
4320 DieOrDebug();
4321 }
4322 set_rd(sext32(amo<int32_t>(
4323 rs1(), [&](int32_t lhs) { return std::min(lhs, (int32_t)rs2()); },
4324 instr_.instr(), WORD)));
4325 break;
4326 }
4327 case RO_AMOMAX_W: {
4328 if ((rs1() & 0x3) != 0) {
4329 DieOrDebug();
4330 }
4331 set_rd(sext32(amo<int32_t>(
4332 rs1(), [&](int32_t lhs) { return std::max(lhs, (int32_t)rs2()); },
4333 instr_.instr(), WORD)));
4334 break;
4335 }
4336 case RO_AMOMINU_W: {
4337 if ((rs1() & 0x3) != 0) {
4338 DieOrDebug();
4339 }
4340 set_rd(sext32(amo<uint32_t>(
4341 rs1(), [&](uint32_t lhs) { return std::min(lhs, (uint32_t)rs2()); },
4342 instr_.instr(), WORD)));
4343 break;
4344 }
4345 case RO_AMOMAXU_W: {
4346 if ((rs1() & 0x3) != 0) {
4347 DieOrDebug();
4348 }
4349 set_rd(sext32(amo<uint32_t>(
4350 rs1(), [&](uint32_t lhs) { return std::max(lhs, (uint32_t)rs2()); },
4351 instr_.instr(), WORD)));
4352 break;
4353 }
4354#ifdef V8_TARGET_ARCH_RISCV64
4355 case RO_LR_D: {
4356 int64_t addr = rs1();
4357 if (!ProbeMemory(addr, sizeof(int64_t))) return;
4358 {
4359 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4360 auto val = ReadMem<int64_t>(addr, instr_.instr());
4361 set_rd(val, false);
4362 TraceMemRd(addr, val, get_register(rd_reg()));
4363 local_monitor_.NotifyLoadLinked(addr, TransactionSize::DoubleWord);
4364 GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr,
4365 &global_monitor_thread_);
4366 break;
4367 }
4368 }
4369 case RO_SC_D: {
4370 int64_t addr = rs1();
4371 if (!ProbeMemory(addr, sizeof(int64_t))) return;
4372 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4373 if (local_monitor_.NotifyStoreConditional(addr,
4374 TransactionSize::DoubleWord) &&
4375 (GlobalMonitor::Get()->NotifyStoreConditional_Locked(
4376 addr, &global_monitor_thread_))) {
4377 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
4378 WriteMem<int64_t>(rs1(), rs2(), instr_.instr());
4379 set_rd(0, false);
4380 } else {
4381 set_rd(1, false);
4382 }
4383 break;
4384 }
4385 case RO_AMOSWAP_D: {
4386 set_rd(amo<int64_t>(
4387 rs1(), [&](int64_t lhs) { return rs2(); }, instr_.instr(), DWORD));
4388 break;
4389 }
4390 case RO_AMOADD_D: {
4391 set_rd(amo<int64_t>(
4392 rs1(), [&](int64_t lhs) { return lhs + rs2(); }, instr_.instr(),
4393 DWORD));
4394 break;
4395 }
4396 case RO_AMOXOR_D: {
4397 set_rd(amo<int64_t>(
4398 rs1(), [&](int64_t lhs) { return lhs ^ rs2(); }, instr_.instr(),
4399 DWORD));
4400 break;
4401 }
4402 case RO_AMOAND_D: {
4403 set_rd(amo<int64_t>(
4404 rs1(), [&](int64_t lhs) { return lhs & rs2(); }, instr_.instr(),
4405 DWORD));
4406 break;
4407 }
4408 case RO_AMOOR_D: {
4409 set_rd(amo<int64_t>(
4410 rs1(), [&](int64_t lhs) { return lhs | rs2(); }, instr_.instr(),
4411 DWORD));
4412 break;
4413 }
4414 case RO_AMOMIN_D: {
4415 set_rd(amo<int64_t>(
4416 rs1(), [&](int64_t lhs) { return std::min(lhs, rs2()); },
4417 instr_.instr(), DWORD));
4418 break;
4419 }
4420 case RO_AMOMAX_D: {
4421 set_rd(amo<int64_t>(
4422 rs1(), [&](int64_t lhs) { return std::max(lhs, rs2()); },
4423 instr_.instr(), DWORD));
4424 break;
4425 }
4426 case RO_AMOMINU_D: {
4427 set_rd(amo<uint64_t>(
4428 rs1(), [&](uint64_t lhs) { return std::min(lhs, (uint64_t)rs2()); },
4429 instr_.instr(), DWORD));
4430 break;
4431 }
4432 case RO_AMOMAXU_D: {
4433 set_rd(amo<uint64_t>(
4434 rs1(), [&](uint64_t lhs) { return std::max(lhs, (uint64_t)rs2()); },
4435 instr_.instr(), DWORD));
4436 break;
4437 }
4438#endif /*V8_TARGET_ARCH_RISCV64*/
4439 // TODO(riscv): End Add macro for RISCV A extension
4440 default: {
4441 UNSUPPORTED();
4442 }
4443 }
4444}
4445
4446void Simulator::DecodeRVRFPType() {
4447 // OP_FP instructions (F/D) uses func7 first. Some further uses func3 and
4448 // rs2()
4449
4450 // kRATypeMask is only for func7
4451 switch (instr_.InstructionBits() & kRFPTypeMask) {
4452 // TODO(riscv): Add macro for RISCV F extension
4453 case RO_FADD_S: {
4454 // TODO(riscv): use rm value (round mode)
4455 auto fn = [this](float frs1, float frs2) {
4456 if (is_invalid_fadd(frs1, frs2)) {
4457 this->set_fflags(kInvalidOperation);
4458 return std::numeric_limits<float>::quiet_NaN();
4459 } else {
4460 return frs1 + frs2;
4461 }
4462 };
4463 set_frd(CanonicalizeFPUOp2<float>(fn));
4464 break;
4465 }
4466 case RO_FSUB_S: {
4467 // TODO(riscv): use rm value (round mode)
4468 auto fn = [this](float frs1, float frs2) {
4469 if (is_invalid_fsub(frs1, frs2)) {
4470 this->set_fflags(kInvalidOperation);
4471 return std::numeric_limits<float>::quiet_NaN();
4472 } else {
4473 return frs1 - frs2;
4474 }
4475 };
4476 set_frd(CanonicalizeFPUOp2<float>(fn));
4477 break;
4478 }
4479 case RO_FMUL_S: {
4480 // TODO(riscv): use rm value (round mode)
4481 auto fn = [this](float frs1, float frs2) {
4482 if (is_invalid_fmul(frs1, frs2)) {
4483 this->set_fflags(kInvalidOperation);
4484 return std::numeric_limits<float>::quiet_NaN();
4485 } else {
4486 return frs1 * frs2;
4487 }
4488 };
4489 set_frd(CanonicalizeFPUOp2<float>(fn));
4490 break;
4491 }
4492 case RO_FDIV_S: {
4493 // TODO(riscv): use rm value (round mode)
4494 auto fn = [this](float frs1, float frs2) {
4495 if (is_invalid_fdiv(frs1, frs2)) {
4496 this->set_fflags(kInvalidOperation);
4497 return std::numeric_limits<float>::quiet_NaN();
4498 } else if (frs2 == 0.0f) {
4499 this->set_fflags(kDivideByZero);
4500 return (std::signbit(frs1) == std::signbit(frs2)
4501 ? std::numeric_limits<float>::infinity()
4502 : -std::numeric_limits<float>::infinity());
4503 } else {
4504 return frs1 / frs2;
4505 }
4506 };
4507 set_frd(CanonicalizeFPUOp2<float>(fn));
4508 break;
4509 }
4510 case RO_FSQRT_S: {
4511 if (instr_.Rs2Value() == 0b00000) {
4512 // TODO(riscv): use rm value (round mode)
4513 auto fn = [this](float frs) {
4514 if (is_invalid_fsqrt(frs)) {
4515 this->set_fflags(kInvalidOperation);
4516 return std::numeric_limits<float>::quiet_NaN();
4517 } else {
4518 return std::sqrt(frs);
4519 }
4520 };
4521 set_frd(CanonicalizeFPUOp1<float>(fn));
4522 } else {
4523 UNSUPPORTED();
4524 }
4525 break;
4526 }
4527 case RO_FSGNJ_S: { // RO_FSGNJN_S RO_FSQNJX_S
4528 switch (instr_.Funct3Value()) {
4529 case 0b000: { // RO_FSGNJ_S
4530 set_frd(fsgnj32(frs1_boxed(), frs2_boxed(), false, false));
4531 break;
4532 }
4533 case 0b001: { // RO_FSGNJN_S
4534 set_frd(fsgnj32(frs1_boxed(), frs2_boxed(), true, false));
4535 break;
4536 }
4537 case 0b010: { // RO_FSQNJX_S
4538 set_frd(fsgnj32(frs1_boxed(), frs2_boxed(), false, true));
4539 break;
4540 }
4541 default: {
4542 UNSUPPORTED();
4543 }
4544 }
4545 break;
4546 }
4547 case RO_FMIN_S: { // RO_FMAX_S
4548 switch (instr_.Funct3Value()) {
4549 case 0b000: { // RO_FMIN_S
4550 set_frd(FMaxMinHelper(frs1(), frs2(), MaxMinKind::kMin));
4551 break;
4552 }
4553 case 0b001: { // RO_FMAX_S
4554 set_frd(FMaxMinHelper(frs1(), frs2(), MaxMinKind::kMax));
4555 break;
4556 }
4557 default: {
4558 UNSUPPORTED();
4559 }
4560 }
4561 break;
4562 }
4563 case RO_FCVT_W_S: { // RO_FCVT_WU_S , 64F RO_FCVT_L_S RO_FCVT_LU_S
4564 float original_val = frs1();
4565 switch (instr_.Rs2Value()) {
4566 case 0b00000: { // RO_FCVT_W_S
4567 set_rd(RoundF2IHelper<int32_t>(original_val, instr_.RoundMode()));
4568 break;
4569 }
4570 case 0b00001: { // RO_FCVT_WU_S
4571 set_rd(sext32(
4572 RoundF2IHelper<uint32_t>(original_val, instr_.RoundMode())));
4573 break;
4574 }
4575#ifdef V8_TARGET_ARCH_RISCV64
4576 case 0b00010: { // RO_FCVT_L_S
4577 set_rd(RoundF2IHelper<int64_t>(original_val, instr_.RoundMode()));
4578 break;
4579 }
4580 case 0b00011: { // RO_FCVT_LU_S
4581 set_rd(RoundF2IHelper<uint64_t>(original_val, instr_.RoundMode()));
4582 break;
4583 }
4584#endif /* V8_TARGET_ARCH_RISCV64 */
4585 default: {
4586 UNSUPPORTED();
4587 }
4588 }
4589 break;
4590 }
4591 case RO_FMV: { // RO_FCLASS_S
4592 switch (instr_.Funct3Value()) {
4593 case 0b000: {
4594 if (instr_.Rs2Value() == 0b00000) {
4595 // RO_FMV_X_W
4596 set_rd(sext32(get_fpu_register_word(rs1_reg())));
4597 } else {
4598 UNSUPPORTED();
4599 }
4600 break;
4601 }
4602 case 0b001: { // RO_FCLASS_S
4603 set_rd(FclassHelper(frs1()));
4604 break;
4605 }
4606 default: {
4607 UNSUPPORTED();
4608 }
4609 }
4610 break;
4611 }
4612 case RO_FLE_S: { // RO_FEQ_S RO_FLT_S RO_FLE_S
4613 switch (instr_.Funct3Value()) {
4614 case 0b010: { // RO_FEQ_S
4615 set_rd(CompareFHelper(frs1(), frs2(), EQ));
4616 break;
4617 }
4618 case 0b001: { // RO_FLT_S
4619 set_rd(CompareFHelper(frs1(), frs2(), LT));
4620 break;
4621 }
4622 case 0b000: { // RO_FLE_S
4623 set_rd(CompareFHelper(frs1(), frs2(), LE));
4624 break;
4625 }
4626 default: {
4627 UNSUPPORTED();
4628 }
4629 }
4630 break;
4631 }
4632 case RO_FCVT_S_W: { // RO_FCVT_S_WU , 64F RO_FCVT_S_L RO_FCVT_S_LU
4633 switch (instr_.Rs2Value()) {
4634 case 0b00000: { // RO_FCVT_S_W
4635 set_frd(static_cast<float>((int32_t)rs1()));
4636 break;
4637 }
4638 case 0b00001: { // RO_FCVT_S_WU
4639 set_frd(static_cast<float>((uint32_t)rs1()));
4640 break;
4641 }
4642#ifdef V8_TARGET_ARCH_RISCV64
4643 case 0b00010: { // RO_FCVT_S_L
4644 set_frd(static_cast<float>((int64_t)rs1()));
4645 break;
4646 }
4647 case 0b00011: { // RO_FCVT_S_LU
4648 set_frd(static_cast<float>((uint64_t)rs1()));
4649 break;
4650 }
4651#endif /* V8_TARGET_ARCH_RISCV64 */
4652 default: {
4653 UNSUPPORTED();
4654 }
4655 }
4656 break;
4657 }
4658 case RO_FMV_W_X: {
4659 if (instr_.Funct3Value() == 0b000) {
4660 // since FMV preserves source bit-pattern, no need to canonize
4661 Float32 result = Float32::FromBits((uint32_t)rs1());
4662 set_frd(result);
4663 } else {
4664 UNSUPPORTED();
4665 }
4666 break;
4667 }
4668 // TODO(riscv): Add macro for RISCV D extension
4669 case RO_FADD_D: {
4670 // TODO(riscv): use rm value (round mode)
4671 auto fn = [this](double drs1, double drs2) {
4672 if (is_invalid_fadd(drs1, drs2)) {
4673 this->set_fflags(kInvalidOperation);
4674 return std::numeric_limits<double>::quiet_NaN();
4675 } else {
4676 return drs1 + drs2;
4677 }
4678 };
4679 set_drd(CanonicalizeFPUOp2<double>(fn));
4680 break;
4681 }
4682 case RO_FSUB_D: {
4683 // TODO(riscv): use rm value (round mode)
4684 auto fn = [this](double drs1, double drs2) {
4685 if (is_invalid_fsub(drs1, drs2)) {
4686 this->set_fflags(kInvalidOperation);
4687 return std::numeric_limits<double>::quiet_NaN();
4688 } else {
4689 return drs1 - drs2;
4690 }
4691 };
4692 set_drd(CanonicalizeFPUOp2<double>(fn));
4693 break;
4694 }
4695 case RO_FMUL_D: {
4696 // TODO(riscv): use rm value (round mode)
4697 auto fn = [this](double drs1, double drs2) {
4698 if (is_invalid_fmul(drs1, drs2)) {
4699 this->set_fflags(kInvalidOperation);
4700 return std::numeric_limits<double>::quiet_NaN();
4701 } else {
4702 return drs1 * drs2;
4703 }
4704 };
4705 set_drd(CanonicalizeFPUOp2<double>(fn));
4706 break;
4707 }
4708 case RO_FDIV_D: {
4709 // TODO(riscv): use rm value (round mode)
4710 auto fn = [this](double drs1, double drs2) {
4711 if (is_invalid_fdiv(drs1, drs2)) {
4712 this->set_fflags(kInvalidOperation);
4713 return std::numeric_limits<double>::quiet_NaN();
4714 } else if (drs2 == 0.0) {
4715 this->set_fflags(kDivideByZero);
4716 return (std::signbit(drs1) == std::signbit(drs2)
4717 ? std::numeric_limits<double>::infinity()
4718 : -std::numeric_limits<double>::infinity());
4719 } else {
4720 return drs1 / drs2;
4721 }
4722 };
4723 set_drd(CanonicalizeFPUOp2<double>(fn));
4724 break;
4725 }
4726 case RO_FSQRT_D: {
4727 if (instr_.Rs2Value() == 0b00000) {
4728 // TODO(riscv): use rm value (round mode)
4729 auto fn = [this](double drs) {
4730 if (is_invalid_fsqrt(drs)) {
4731 this->set_fflags(kInvalidOperation);
4732 return std::numeric_limits<double>::quiet_NaN();
4733 } else {
4734 return std::sqrt(drs);
4735 }
4736 };
4737 set_drd(CanonicalizeFPUOp1<double>(fn));
4738 } else {
4739 UNSUPPORTED();
4740 }
4741 break;
4742 }
4743 case RO_FSGNJ_D: { // RO_FSGNJN_D RO_FSQNJX_D
4744 switch (instr_.Funct3Value()) {
4745 case 0b000: { // RO_FSGNJ_D
4746 set_drd(fsgnj64(drs1_boxed(), drs2_boxed(), false, false));
4747 break;
4748 }
4749 case 0b001: { // RO_FSGNJN_D
4750 set_drd(fsgnj64(drs1_boxed(), drs2_boxed(), true, false));
4751 break;
4752 }
4753 case 0b010: { // RO_FSQNJX_D
4754 set_drd(fsgnj64(drs1_boxed(), drs2_boxed(), false, true));
4755 break;
4756 }
4757 default: {
4758 UNSUPPORTED();
4759 }
4760 }
4761 break;
4762 }
4763 case RO_FMIN_D: { // RO_FMAX_D
4764 switch (instr_.Funct3Value()) {
4765 case 0b000: { // RO_FMIN_D
4766 set_drd(FMaxMinHelper(drs1(), drs2(), MaxMinKind::kMin));
4767 break;
4768 }
4769 case 0b001: { // RO_FMAX_D
4770 set_drd(FMaxMinHelper(drs1(), drs2(), MaxMinKind::kMax));
4771 break;
4772 }
4773 default: {
4774 UNSUPPORTED();
4775 }
4776 }
4777 break;
4778 }
4779 case (RO_FCVT_S_D & kRFPTypeMask): {
4780 if (instr_.Rs2Value() == 0b00001) {
4781 auto fn = [](double drs) { return static_cast<float>(drs); };
4782 set_frd(CanonicalizeDoubleToFloatOperation(fn));
4783 } else {
4784 UNSUPPORTED();
4785 }
4786 break;
4787 }
4788 case RO_FCVT_D_S: {
4789 if (instr_.Rs2Value() == 0b00000) {
4790 auto fn = [](float frs) { return static_cast<double>(frs); };
4791 set_drd(CanonicalizeFloatToDoubleOperation(fn));
4792 } else {
4793 UNSUPPORTED();
4794 }
4795 break;
4796 }
4797 case RO_FLE_D: { // RO_FEQ_D RO_FLT_D RO_FLE_D
4798 switch (instr_.Funct3Value()) {
4799 case 0b010: { // RO_FEQ_S
4800 set_rd(CompareFHelper(drs1(), drs2(), EQ));
4801 break;
4802 }
4803 case 0b001: { // RO_FLT_D
4804 set_rd(CompareFHelper(drs1(), drs2(), LT));
4805 break;
4806 }
4807 case 0b000: { // RO_FLE_D
4808 set_rd(CompareFHelper(drs1(), drs2(), LE));
4809 break;
4810 }
4811 default: {
4812 UNSUPPORTED();
4813 }
4814 }
4815 break;
4816 }
4817 case (RO_FCLASS_D & kRFPTypeMask): { // RO_FCLASS_D , 64D RO_FMV_X_D
4818 if (instr_.Rs2Value() != 0b00000) {
4819 UNSUPPORTED();
4820 }
4821 switch (instr_.Funct3Value()) {
4822 case 0b001: { // RO_FCLASS_D
4823 set_rd(FclassHelper(drs1()));
4824 break;
4825 }
4826#ifdef V8_TARGET_ARCH_RISCV64
4827 case 0b000: { // RO_FMV_X_D
4828 set_rd(base::bit_cast<int64_t>(drs1()));
4829 break;
4830 }
4831#endif /* V8_TARGET_ARCH_RISCV64 */
4832 default: {
4833 UNSUPPORTED();
4834 }
4835 }
4836 break;
4837 }
4838 case RO_FCVT_W_D: { // RO_FCVT_WU_D , 64F RO_FCVT_L_D RO_FCVT_LU_D
4839 double original_val = drs1();
4840 switch (instr_.Rs2Value()) {
4841 case 0b00000: { // RO_FCVT_W_D
4842 set_rd(RoundF2IHelper<int32_t>(original_val, instr_.RoundMode()));
4843 break;
4844 }
4845 case 0b00001: { // RO_FCVT_WU_D
4846 set_rd(sext32(
4847 RoundF2IHelper<uint32_t>(original_val, instr_.RoundMode())));
4848 break;
4849 }
4850#ifdef V8_TARGET_ARCH_RISCV64
4851 case 0b00010: { // RO_FCVT_L_D
4852 set_rd(RoundF2IHelper<int64_t>(original_val, instr_.RoundMode()));
4853 break;
4854 }
4855 case 0b00011: { // RO_FCVT_LU_D
4856 set_rd(RoundF2IHelper<uint64_t>(original_val, instr_.RoundMode()));
4857 break;
4858 }
4859#endif /* V8_TARGET_ARCH_RISCV64 */
4860 default: {
4861 UNSUPPORTED();
4862 }
4863 }
4864 break;
4865 }
4866 case RO_FCVT_D_W: { // RO_FCVT_D_WU , 64F RO_FCVT_D_L RO_FCVT_D_LU
4867 switch (instr_.Rs2Value()) {
4868 case 0b00000: { // RO_FCVT_D_W
4869 set_drd((int32_t)rs1());
4870 break;
4871 }
4872 case 0b00001: { // RO_FCVT_D_WU
4873 set_drd((uint32_t)rs1());
4874 break;
4875 }
4876#ifdef V8_TARGET_ARCH_RISCV64
4877 case 0b00010: { // RO_FCVT_D_L
4878 set_drd((int64_t)rs1());
4879 break;
4880 }
4881 case 0b00011: { // RO_FCVT_D_LU
4882 set_drd((uint64_t)rs1());
4883 break;
4884 }
4885#endif /* V8_TARGET_ARCH_RISCV64 */
4886 default: {
4887 UNSUPPORTED();
4888 }
4889 }
4890 break;
4891 }
4892#ifdef V8_TARGET_ARCH_RISCV64
4893 case RO_FMV_D_X: {
4894 if (instr_.Funct3Value() == 0b000 && instr_.Rs2Value() == 0b00000) {
4895 // Since FMV preserves source bit-pattern, no need to canonize
4896 set_drd(base::bit_cast<double>(rs1()));
4897 } else {
4898 UNSUPPORTED();
4899 }
4900 break;
4901 }
4902#endif /* V8_TARGET_ARCH_RISCV64 */
4903 default: {
4904 UNSUPPORTED();
4905 }
4906 }
4907}
4908
4909void Simulator::DecodeRVR4Type() {
4910 switch (instr_.InstructionBits() & kR4TypeMask) {
4911 // TODO(riscv): use F Extension macro block
4912 case RO_FMADD_S: {
4913 // TODO(riscv): use rm value (round mode)
4914 auto fn = [this](float frs1, float frs2, float frs3) {
4915 if (is_invalid_fmul(frs1, frs2) || is_invalid_fadd(frs1 * frs2, frs3)) {
4916 this->set_fflags(kInvalidOperation);
4917 return std::numeric_limits<float>::quiet_NaN();
4918 } else {
4919 return std::fma(frs1, frs2, frs3);
4920 }
4921 };
4922 set_frd(CanonicalizeFPUOp3<float>(fn));
4923 break;
4924 }
4925 case RO_FMSUB_S: {
4926 // TODO(riscv): use rm value (round mode)
4927 auto fn = [this](float frs1, float frs2, float frs3) {
4928 if (is_invalid_fmul(frs1, frs2) || is_invalid_fsub(frs1 * frs2, frs3)) {
4929 this->set_fflags(kInvalidOperation);
4930 return std::numeric_limits<float>::quiet_NaN();
4931 } else {
4932 return std::fma(frs1, frs2, -frs3);
4933 }
4934 };
4935 set_frd(CanonicalizeFPUOp3<float>(fn));
4936 break;
4937 }
4938 case RO_FNMSUB_S: {
4939 // TODO(riscv): use rm value (round mode)
4940 auto fn = [this](float frs1, float frs2, float frs3) {
4941 if (is_invalid_fmul(frs1, frs2) || is_invalid_fsub(frs3, frs1 * frs2)) {
4942 this->set_fflags(kInvalidOperation);
4943 return std::numeric_limits<float>::quiet_NaN();
4944 } else {
4945 return -std::fma(frs1, frs2, -frs3);
4946 }
4947 };
4948 set_frd(CanonicalizeFPUOp3<float>(fn));
4949 break;
4950 }
4951 case RO_FNMADD_S: {
4952 // TODO(riscv): use rm value (round mode)
4953 auto fn = [this](float frs1, float frs2, float frs3) {
4954 if (is_invalid_fmul(frs1, frs2) || is_invalid_fadd(frs1 * frs2, frs3)) {
4955 this->set_fflags(kInvalidOperation);
4956 return std::numeric_limits<float>::quiet_NaN();
4957 } else {
4958 return -std::fma(frs1, frs2, frs3);
4959 }
4960 };
4961 set_frd(CanonicalizeFPUOp3<float>(fn));
4962 break;
4963 }
4964 // TODO(riscv): use F Extension macro block
4965 case RO_FMADD_D: {
4966 // TODO(riscv): use rm value (round mode)
4967 auto fn = [this](double drs1, double drs2, double drs3) {
4968 if (is_invalid_fmul(drs1, drs2) || is_invalid_fadd(drs1 * drs2, drs3)) {
4969 this->set_fflags(kInvalidOperation);
4970 return std::numeric_limits<double>::quiet_NaN();
4971 } else {
4972 return std::fma(drs1, drs2, drs3);
4973 }
4974 };
4975 set_drd(CanonicalizeFPUOp3<double>(fn));
4976 break;
4977 }
4978 case RO_FMSUB_D: {
4979 // TODO(riscv): use rm value (round mode)
4980 auto fn = [this](double drs1, double drs2, double drs3) {
4981 if (is_invalid_fmul(drs1, drs2) || is_invalid_fsub(drs1 * drs2, drs3)) {
4982 this->set_fflags(kInvalidOperation);
4983 return std::numeric_limits<double>::quiet_NaN();
4984 } else {
4985 return std::fma(drs1, drs2, -drs3);
4986 }
4987 };
4988 set_drd(CanonicalizeFPUOp3<double>(fn));
4989 break;
4990 }
4991 case RO_FNMSUB_D: {
4992 // TODO(riscv): use rm value (round mode)
4993 auto fn = [this](double drs1, double drs2, double drs3) {
4994 if (is_invalid_fmul(drs1, drs2) || is_invalid_fsub(drs3, drs1 * drs2)) {
4995 this->set_fflags(kInvalidOperation);
4996 return std::numeric_limits<double>::quiet_NaN();
4997 } else {
4998 return -std::fma(drs1, drs2, -drs3);
4999 }
5000 };
5001 set_drd(CanonicalizeFPUOp3<double>(fn));
5002 break;
5003 }
5004 case RO_FNMADD_D: {
5005 // TODO(riscv): use rm value (round mode)
5006 auto fn = [this](double drs1, double drs2, double drs3) {
5007 if (is_invalid_fmul(drs1, drs2) || is_invalid_fadd(drs1 * drs2, drs3)) {
5008 this->set_fflags(kInvalidOperation);
5009 return std::numeric_limits<double>::quiet_NaN();
5010 } else {
5011 return -std::fma(drs1, drs2, drs3);
5012 }
5013 };
5014 set_drd(CanonicalizeFPUOp3<double>(fn));
5015 break;
5016 }
5017 default:
5018 UNSUPPORTED();
5019 }
5020}
5021
5022#ifdef CAN_USE_RVV_INSTRUCTIONS
5023bool Simulator::DecodeRvvVL() {
5024 uint32_t instr_temp =
5025 instr_.InstructionBits() & (kRvvMopMask | kRvvNfMask | kBaseOpcodeMask);
5026 if (RO_V_VL == instr_temp) {
5027 if (!(instr_.InstructionBits() & (kRvvRs2Mask))) {
5028 switch (instr_.vl_vs_width()) {
5029 case 8: {
5030 RVV_VI_LD(0, (i * nf + fn), int8, false);
5031 break;
5032 }
5033 case 16: {
5034 RVV_VI_LD(0, (i * nf + fn), int16, false);
5035 break;
5036 }
5037 case 32: {
5038 RVV_VI_LD(0, (i * nf + fn), int32, false);
5039 break;
5040 }
5041 case 64: {
5042 RVV_VI_LD(0, (i * nf + fn), int64, false);
5043 break;
5044 }
5045 default:
5047 break;
5048 }
5049 return true;
5050 } else {
5052 return true;
5053 }
5054 } else if (RO_V_VLS == instr_temp) {
5056 return true;
5057 } else if (RO_V_VLX == instr_temp) {
5059 return true;
5060 } else if (RO_V_VLSEG2 == instr_temp || RO_V_VLSEG3 == instr_temp ||
5061 RO_V_VLSEG4 == instr_temp || RO_V_VLSEG5 == instr_temp ||
5062 RO_V_VLSEG6 == instr_temp || RO_V_VLSEG7 == instr_temp ||
5063 RO_V_VLSEG8 == instr_temp) {
5064 if (!(instr_.InstructionBits() & (kRvvRs2Mask))) {
5066 return true;
5067 } else {
5069 return true;
5070 }
5071 } else if (RO_V_VLSSEG2 == instr_temp || RO_V_VLSSEG3 == instr_temp ||
5072 RO_V_VLSSEG4 == instr_temp || RO_V_VLSSEG5 == instr_temp ||
5073 RO_V_VLSSEG6 == instr_temp || RO_V_VLSSEG7 == instr_temp ||
5074 RO_V_VLSSEG8 == instr_temp) {
5076 return true;
5077 } else if (RO_V_VLXSEG2 == instr_temp || RO_V_VLXSEG3 == instr_temp ||
5078 RO_V_VLXSEG4 == instr_temp || RO_V_VLXSEG5 == instr_temp ||
5079 RO_V_VLXSEG6 == instr_temp || RO_V_VLXSEG7 == instr_temp ||
5080 RO_V_VLXSEG8 == instr_temp) {
5082 return true;
5083 } else {
5084 return false;
5085 }
5086}
5087
5088bool Simulator::DecodeRvvVS() {
5089 uint32_t instr_temp =
5090 instr_.InstructionBits() & (kRvvMopMask | kRvvNfMask | kBaseOpcodeMask);
5091 if (RO_V_VS == instr_temp) {
5092 if (!(instr_.InstructionBits() & (kRvvRs2Mask))) {
5093 switch (instr_.vl_vs_width()) {
5094 case 8: {
5095 RVV_VI_ST(0, (i * nf + fn), uint8, false);
5096 break;
5097 }
5098 case 16: {
5099 RVV_VI_ST(0, (i * nf + fn), uint16, false);
5100 break;
5101 }
5102 case 32: {
5103 RVV_VI_ST(0, (i * nf + fn), uint32, false);
5104 break;
5105 }
5106 case 64: {
5107 RVV_VI_ST(0, (i * nf + fn), uint64, false);
5108 break;
5109 }
5110 default:
5112 break;
5113 }
5114 } else {
5116 }
5117 return true;
5118 } else if (RO_V_VSS == instr_temp) {
5120 return true;
5121 } else if (RO_V_VSX == instr_temp) {
5123 return true;
5124 } else if (RO_V_VSU == instr_temp) {
5126 return true;
5127 } else if (RO_V_VSSEG2 == instr_temp || RO_V_VSSEG3 == instr_temp ||
5128 RO_V_VSSEG4 == instr_temp || RO_V_VSSEG5 == instr_temp ||
5129 RO_V_VSSEG6 == instr_temp || RO_V_VSSEG7 == instr_temp ||
5130 RO_V_VSSEG8 == instr_temp) {
5132 return true;
5133 } else if (RO_V_VSSSEG2 == instr_temp || RO_V_VSSSEG3 == instr_temp ||
5134 RO_V_VSSSEG4 == instr_temp || RO_V_VSSSEG5 == instr_temp ||
5135 RO_V_VSSSEG6 == instr_temp || RO_V_VSSSEG7 == instr_temp ||
5136 RO_V_VSSSEG8 == instr_temp) {
5138 return true;
5139 } else if (RO_V_VSXSEG2 == instr_temp || RO_V_VSXSEG3 == instr_temp ||
5140 RO_V_VSXSEG4 == instr_temp || RO_V_VSXSEG5 == instr_temp ||
5141 RO_V_VSXSEG6 == instr_temp || RO_V_VSXSEG7 == instr_temp ||
5142 RO_V_VSXSEG8 == instr_temp) {
5144 return true;
5145 } else {
5146 return false;
5147 }
5148}
5149#endif
5150
5151Builtin Simulator::LookUp(Address pc) {
5152 for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
5153 ++builtin) {
5154 if (builtins_.code(builtin)->contains(isolate_, pc)) return builtin;
5155 }
5156 return Builtin::kNoBuiltinId;
5157}
5158
5159void Simulator::DecodeRVIType() {
5160 switch (instr_.InstructionBits() & kITypeMask) {
5161 case RO_JALR: {
5162 set_rd(get_pc() + kInstrSize);
5163 // Note: No need to shift 2 for JALR's imm12, but set lowest bit to 0.
5164 sreg_t next_pc = (rs1() + imm12()) & ~sreg_t(1);
5165 set_pc(next_pc);
5166 if (v8_flags.trace_sim) {
5167 Builtin builtin = LookUp((Address)get_pc());
5168 if (builtin != Builtin::kNoBuiltinId) {
5169 auto code = builtins_.code(builtin);
5170 if ((rs1_reg() != ra || imm12() != 0)) {
5171 if ((Address)get_pc() == code->instruction_start()) {
5172 sreg_t arg0 = get_register(a0);
5173 sreg_t arg1 = get_register(a1);
5174 sreg_t arg2 = get_register(a2);
5175 sreg_t arg3 = get_register(a3);
5176 sreg_t arg4 = get_register(a4);
5177 sreg_t arg5 = get_register(a5);
5178 sreg_t arg6 = get_register(a6);
5179 sreg_t arg7 = get_register(a7);
5180 sreg_t* stack_pointer =
5181 reinterpret_cast<sreg_t*>(get_register(sp));
5182 sreg_t arg8 = stack_pointer[0];
5183 sreg_t arg9 = stack_pointer[1];
5184 PrintF(
5185 "Call to Builtin at %s "
5186 "a0 %08" REGIx_FORMAT " ,a1 %08" REGIx_FORMAT
5187 " ,a2 %08" REGIx_FORMAT " ,a3 %08" REGIx_FORMAT
5188 " ,a4 %08" REGIx_FORMAT " ,a5 %08" REGIx_FORMAT
5189 " ,a6 %08" REGIx_FORMAT " ,a7 %08" REGIx_FORMAT
5190 " ,0(sp) %08" REGIx_FORMAT " ,8(sp) %08" REGIx_FORMAT
5191 " ,sp %08" REGIx_FORMAT ",fp %08" REGIx_FORMAT " \n",
5192 builtins_.name(builtin), arg0, arg1, arg2, arg3, arg4, arg5,
5193 arg6, arg7, arg8, arg9, get_register(sp), get_register(fp));
5194 }
5195 } else if (rd_reg() == zero_reg) {
5196 PrintF("Return to Builtin at %s \n", builtins_.name(builtin));
5197 }
5198 }
5199 }
5200 break;
5201 }
5202 case RO_LB: {
5203 sreg_t addr = rs1() + imm12();
5204 if (!ProbeMemory(addr, sizeof(int8_t))) return;
5205 int8_t val = ReadMem<int8_t>(addr, instr_.instr());
5206 set_rd(sext_xlen(val), false);
5207 TraceMemRd(addr, val, get_register(rd_reg()));
5208 break;
5209 }
5210 case RO_LH: {
5211 sreg_t addr = rs1() + imm12();
5212 if (!ProbeMemory(addr, sizeof(int16_t))) return;
5213 int16_t val = ReadMem<int16_t>(addr, instr_.instr());
5214 set_rd(sext_xlen(val), false);
5215 TraceMemRd(addr, val, get_register(rd_reg()));
5216 break;
5217 }
5218 case RO_LW: {
5219 sreg_t addr = rs1() + imm12();
5220 if (!ProbeMemory(addr, sizeof(int32_t))) return;
5221 int32_t val = ReadMem<int32_t>(addr, instr_.instr());
5222 set_rd(sext_xlen(val), false);
5223 TraceMemRd(addr, val, get_register(rd_reg()));
5224 break;
5225 }
5226 case RO_LBU: {
5227 sreg_t addr = rs1() + imm12();
5228 if (!ProbeMemory(addr, sizeof(int8_t))) return;
5229 uint8_t val = ReadMem<uint8_t>(addr, instr_.instr());
5230 set_rd(zext_xlen(val), false);
5231 TraceMemRd(addr, val, get_register(rd_reg()));
5232 break;
5233 }
5234 case RO_LHU: {
5235 sreg_t addr = rs1() + imm12();
5236 if (!ProbeMemory(addr, sizeof(int16_t))) return;
5237 uint16_t val = ReadMem<uint16_t>(addr, instr_.instr());
5238 set_rd(zext_xlen(val), false);
5239 TraceMemRd(addr, val, get_register(rd_reg()));
5240 break;
5241 }
5242#ifdef V8_TARGET_ARCH_RISCV64
5243 case RO_LWU: {
5244 int64_t addr = rs1() + imm12();
5245 if (!ProbeMemory(addr, sizeof(int32_t))) return;
5246 uint32_t val = ReadMem<uint32_t>(addr, instr_.instr());
5247 set_rd(zext_xlen(val), false);
5248 TraceMemRd(addr, val, get_register(rd_reg()));
5249 break;
5250 }
5251 case RO_LD: {
5252 int64_t addr = rs1() + imm12();
5253 if (!ProbeMemory(addr, sizeof(int64_t))) return;
5254 int64_t val = ReadMem<int64_t>(addr, instr_.instr());
5255 set_rd(sext_xlen(val), false);
5256 TraceMemRd(addr, val, get_register(rd_reg()));
5257 break;
5258 }
5259#endif /*V8_TARGET_ARCH_RISCV64*/
5260 case RO_ADDI: {
5261 set_rd(sext_xlen(rs1() + imm12()));
5262 break;
5263 }
5264 case RO_SLTI: {
5265 set_rd(sreg_t(rs1()) < sreg_t(imm12()));
5266 break;
5267 }
5268 case RO_SLTIU: {
5269 set_rd(reg_t(rs1()) < reg_t(imm12()));
5270 break;
5271 }
5272 case RO_XORI: {
5273 set_rd(imm12() ^ rs1());
5274 break;
5275 }
5276 case RO_ORI: {
5277 set_rd(imm12() | rs1());
5278 break;
5279 }
5280 case RO_ANDI: {
5281 set_rd(imm12() & rs1());
5282 break;
5283 }
5284 case OP_SHL: {
5285 switch (instr_.Funct6FieldRaw() | OP_SHL) {
5286 case RO_SLLI:
5287 require(shamt6() < xlen);
5288 set_rd(sext_xlen(rs1() << shamt6()));
5289 break;
5290 case RO_BCLRI: {
5291 require(shamt6() < xlen);
5292 sreg_t index = shamt6() & (xlen - 1);
5293 set_rd(rs1() & ~(1l << index));
5294 break;
5295 }
5296 case RO_BINVI: {
5297 require(shamt6() < xlen);
5298 sreg_t index = shamt6() & (xlen - 1);
5299 set_rd(rs1() ^ (1l << index));
5300 break;
5301 }
5302 case RO_BSETI: {
5303 require(shamt6() < xlen);
5304 sreg_t index = shamt6() & (xlen - 1);
5305 set_rd(rs1() | (1l << index));
5306 break;
5307 }
5308 case OP_COUNT:
5309 switch (instr_.Shamt()) {
5310 case 0: { // clz
5311 sreg_t x = rs1();
5312 int highest_setbit = -1;
5313 for (auto i = xlen - 1; i >= 0; i--) {
5314 if ((x & (1l << i))) {
5315 highest_setbit = i;
5316 break;
5317 }
5318 }
5319 set_rd(xlen - 1 - highest_setbit);
5320 break;
5321 }
5322 case 1: { // ctz
5323 sreg_t x = rs1();
5324 int lowest_setbit = xlen;
5325 for (auto i = 0; i < xlen; i++) {
5326 if ((x & (1l << i))) {
5327 lowest_setbit = i;
5328 break;
5329 }
5330 }
5331 set_rd(lowest_setbit);
5332 break;
5333 }
5334 case 2: { // cpop
5335 int i = 0;
5336 sreg_t n = rs1();
5337 while (n) {
5338 n &= (n - 1);
5339 i++;
5340 }
5341 set_rd(i);
5342 break;
5343 }
5344 case 4:
5345 set_rd(int8_t(rs1()));
5346 break;
5347 case 5:
5348 set_rd(int16_t(rs1()));
5349 break;
5350 default:
5352 }
5353 break;
5354 default:
5356 }
5357 break;
5358 }
5359 case OP_SHR: { // RO_SRAI
5360 switch (instr_.Funct6FieldRaw() | OP_SHR) {
5361 case RO_SRLI:
5362 require(shamt6() < xlen);
5363 set_rd(sext_xlen(zext_xlen(rs1()) >> shamt6()));
5364 break;
5365 case RO_SRAI:
5366 require(shamt6() < xlen);
5367 set_rd(sext_xlen(sext_xlen(rs1()) >> shamt6()));
5368 break;
5369 case RO_BEXTI: {
5370 require(shamt6() < xlen);
5371 sreg_t index = shamt6() & (xlen - 1);
5372 set_rd((rs1() >> index) & 1);
5373 break;
5374 }
5375 case RO_ORCB&(kFunct6Mask | OP_SHR): {
5376 reg_t rs1_val = rs1();
5377 reg_t result = 0;
5378 reg_t mask = 0xFF;
5379 reg_t step = 8;
5380 for (reg_t i = 0; i < xlen; i += step) {
5381 if ((rs1_val & mask) != 0) {
5382 result |= mask;
5383 }
5384 mask <<= step;
5385 }
5386 set_rd(result);
5387 break;
5388 }
5389 case RO_RORI: {
5390#ifdef V8_TARGET_ARCH_RISCV64
5391 int16_t shamt = shamt6();
5392#else
5393 int16_t shamt = shamt5();
5394#endif
5395 set_rd((reg_t(rs1()) >> shamt) | (reg_t(rs1()) << (xlen - shamt)));
5396 break;
5397 }
5398 case RO_REV8: {
5399 if (imm12() == RO_REV8_IMM12) {
5400 reg_t input = rs1();
5401 reg_t output = 0;
5402 reg_t j = xlen - 1;
5403 for (int i = 0; i < xlen; i += 8) {
5404 output |= ((input >> (j - 7)) & 0xff) << i;
5405 j -= 8;
5406 }
5407 set_rd(output);
5408 break;
5409 }
5411 }
5412 default:
5414 }
5415 break;
5416 }
5417#ifdef V8_TARGET_ARCH_RISCV64
5418 case RO_ADDIW: {
5419 set_rd(sext32(rs1() + imm12()));
5420 break;
5421 }
5422 case OP_SHLW:
5423 switch (instr_.Funct7FieldRaw() | OP_SHLW) {
5424 case RO_SLLIW:
5425 set_rd(sext32(rs1() << shamt5()));
5426 break;
5427 case RO_SLLIUW:
5428 set_rd(zext32(rs1()) << shamt6());
5429 break;
5430 case OP_COUNTW: {
5431 switch (instr_.Shamt()) {
5432 case 0: { // clzw
5433 sreg_t x = rs1();
5434 int highest_setbit = -1;
5435 for (auto i = 31; i >= 0; i--) {
5436 if ((x & (1l << i))) {
5437 highest_setbit = i;
5438 break;
5439 }
5440 }
5441 set_rd(31 - highest_setbit);
5442 break;
5443 }
5444 case 1: { // ctzw
5445 sreg_t x = rs1();
5446 int lowest_setbit = 32;
5447 for (auto i = 0; i < 32; i++) {
5448 if ((x & (1l << i))) {
5449 lowest_setbit = i;
5450 break;
5451 }
5452 }
5453 set_rd(lowest_setbit);
5454 break;
5455 }
5456 case 2: { // cpopw
5457 int i = 0;
5458 int32_t n = static_cast<int32_t>(rs1());
5459 while (n) {
5460 n &= (n - 1);
5461 i++;
5462 }
5463 set_rd(i);
5464 break;
5465 }
5466 default:
5468 }
5469 break;
5470 }
5471 default:
5473 }
5474 break;
5475 case OP_SHRW: { // RO_SRAI
5476 switch (instr_.Funct7FieldRaw() | OP_SHRW) {
5477 case RO_SRLIW:
5478 set_rd(sext32(uint32_t(rs1()) >> shamt5()));
5479 break;
5480 case RO_SRAIW:
5481 set_rd(sext32(int32_t(rs1()) >> shamt5()));
5482 break;
5483 case RO_RORIW: {
5484 reg_t extz_rs1 = zext32(rs1());
5485 int16_t shamt = shamt5();
5486 set_rd(sext32((extz_rs1 >> shamt) | (extz_rs1 << (32 - shamt))));
5487 break;
5488 }
5489 default:
5491 }
5492 break;
5493 }
5494#endif /*V8_TARGET_ARCH_RISCV64*/
5495 case RO_FENCE: {
5496 // DO nothing in sumulator
5497 break;
5498 }
5499 case RO_ECALL: { // RO_EBREAK
5500 if (instr_.Imm12Value() == 0) { // ECALL
5501 SoftwareInterrupt();
5502 } else if (instr_.Imm12Value() == 1) { // EBREAK
5503 SoftwareInterrupt();
5504 } else {
5505 UNSUPPORTED();
5506 }
5507 break;
5508 }
5509 // TODO(riscv): use Zifencei Standard Extension macro block
5510 case RO_FENCE_I: {
5511 // spike: flush icache.
5512 break;
5513 }
5514 // TODO(riscv): use Zicsr Standard Extension macro block
5515 case RO_CSRRW: {
5516 if (rd_reg() != zero_reg) {
5517 set_rd(zext_xlen(read_csr_value(csr_reg())));
5518 }
5519 write_csr_value(csr_reg(), rs1());
5520 break;
5521 }
5522 case RO_CSRRS: {
5523 set_rd(zext_xlen(read_csr_value(csr_reg())));
5524 if (rs1_reg() != zero_reg) {
5525 set_csr_bits(csr_reg(), rs1());
5526 }
5527 break;
5528 }
5529 case RO_CSRRC: {
5530 set_rd(zext_xlen(read_csr_value(csr_reg())));
5531 if (rs1_reg() != zero_reg) {
5532 clear_csr_bits(csr_reg(), rs1());
5533 }
5534 break;
5535 }
5536 case RO_CSRRWI: {
5537 if (rd_reg() != zero_reg) {
5538 set_rd(zext_xlen(read_csr_value(csr_reg())));
5539 }
5540 write_csr_value(csr_reg(), imm5CSR());
5541 break;
5542 }
5543 case RO_CSRRSI: {
5544 set_rd(zext_xlen(read_csr_value(csr_reg())));
5545 if (imm5CSR() != 0) {
5546 set_csr_bits(csr_reg(), imm5CSR());
5547 }
5548 break;
5549 }
5550 case RO_CSRRCI: {
5551 set_rd(zext_xlen(read_csr_value(csr_reg())));
5552 if (imm5CSR() != 0) {
5553 clear_csr_bits(csr_reg(), imm5CSR());
5554 }
5555 break;
5556 }
5557 // TODO(riscv): use F Extension macro block
5558 case RO_FLW: {
5559 sreg_t addr = rs1() + imm12();
5560 if (!ProbeMemory(addr, sizeof(float))) return;
5561 uint32_t val = ReadMem<uint32_t>(addr, instr_.instr());
5562 set_frd(Float32::FromBits(val), false);
5563 TraceMemRdFloat(addr, Float32::FromBits(val),
5564 get_fpu_register(frd_reg()));
5565 break;
5566 }
5567 // TODO(riscv): use D Extension macro block
5568 case RO_FLD: {
5569 sreg_t addr = rs1() + imm12();
5570 if (!ProbeMemory(addr, sizeof(double))) return;
5571 uint64_t val = ReadMem<uint64_t>(addr, instr_.instr());
5572 set_drd(Float64::FromBits(val), false);
5573 TraceMemRdDouble(addr, Float64::FromBits(val),
5574 get_fpu_register(frd_reg()));
5575 break;
5576 }
5577 default: {
5578#ifdef CAN_USE_RVV_INSTRUCTIONS
5579 if (!DecodeRvvVL()) {
5580 UNSUPPORTED();
5581 }
5582 break;
5583#else
5584 UNSUPPORTED();
5585#endif
5586 }
5587 }
5588}
5589
5590void Simulator::DecodeRVSType() {
5591 switch (instr_.InstructionBits() & kSTypeMask) {
5592 case RO_SB:
5593 if (!ProbeMemory(rs1() + s_imm12(), sizeof(int8_t))) return;
5594 WriteMem<uint8_t>(rs1() + s_imm12(), (uint8_t)rs2(), instr_.instr());
5595 break;
5596 case RO_SH:
5597 if (!ProbeMemory(rs1() + s_imm12(), sizeof(int16_t))) return;
5598 WriteMem<uint16_t>(rs1() + s_imm12(), (uint16_t)rs2(), instr_.instr());
5599 break;
5600 case RO_SW:
5601 if (!ProbeMemory(rs1() + s_imm12(), sizeof(int32_t))) return;
5602 WriteMem<uint32_t>(rs1() + s_imm12(), (uint32_t)rs2(), instr_.instr());
5603 break;
5604#ifdef V8_TARGET_ARCH_RISCV64
5605 case RO_SD:
5606 if (!ProbeMemory(rs1() + s_imm12(), sizeof(int64_t))) return;
5607 WriteMem<uint64_t>(rs1() + s_imm12(), (uint64_t)rs2(), instr_.instr());
5608 break;
5609#endif /*V8_TARGET_ARCH_RISCV64*/
5610 // TODO(riscv): use F Extension macro block
5611 case RO_FSW: {
5612 if (!ProbeMemory(rs1() + s_imm12(), sizeof(float))) return;
5613 WriteMem<Float32>(rs1() + s_imm12(),
5614 get_fpu_register_Float32(rs2_reg(), false),
5615 instr_.instr());
5616 break;
5617 }
5618 // TODO(riscv): use D Extension macro block
5619 case RO_FSD: {
5620 if (!ProbeMemory(rs1() + s_imm12(), sizeof(double))) return;
5621 WriteMem<Float64>(rs1() + s_imm12(), get_fpu_register_Float64(rs2_reg()),
5622 instr_.instr());
5623 break;
5624 }
5625 default:
5626#ifdef CAN_USE_RVV_INSTRUCTIONS
5627 if (!DecodeRvvVS()) {
5628 UNSUPPORTED();
5629 }
5630 break;
5631#else
5632 UNSUPPORTED();
5633#endif
5634 }
5635}
5636
5637void Simulator::DecodeRVBType() {
5638 switch (instr_.InstructionBits() & kBTypeMask) {
5639 case RO_BEQ:
5640 if (rs1() == rs2()) {
5641 int64_t next_pc = get_pc() + boffset();
5642 set_pc(next_pc);
5643 }
5644 break;
5645 case RO_BNE:
5646 if (rs1() != rs2()) {
5647 int64_t next_pc = get_pc() + boffset();
5648 set_pc(next_pc);
5649 }
5650 break;
5651 case RO_BLT:
5652 if (rs1() < rs2()) {
5653 int64_t next_pc = get_pc() + boffset();
5654 set_pc(next_pc);
5655 }
5656 break;
5657 case RO_BGE:
5658 if (rs1() >= rs2()) {
5659 int64_t next_pc = get_pc() + boffset();
5660 set_pc(next_pc);
5661 }
5662 break;
5663 case RO_BLTU:
5664 if ((reg_t)rs1() < (reg_t)rs2()) {
5665 int64_t next_pc = get_pc() + boffset();
5666 set_pc(next_pc);
5667 }
5668 break;
5669 case RO_BGEU:
5670 if ((reg_t)rs1() >= (reg_t)rs2()) {
5671 int64_t next_pc = get_pc() + boffset();
5672 set_pc(next_pc);
5673 }
5674 break;
5675 default:
5676 UNSUPPORTED();
5677 }
5678}
5679void Simulator::DecodeRVUType() {
5680 // U Type doesn't have additoinal mask
5681 switch (instr_.BaseOpcodeFieldRaw()) {
5682 case LUI:
5683 set_rd(u_imm20());
5684 break;
5685 case AUIPC:
5686 set_rd(sext_xlen(u_imm20() + get_pc()));
5687 break;
5688 default:
5689 UNSUPPORTED();
5690 }
5691}
5692void Simulator::DecodeRVJType() {
5693 // J Type doesn't have additional mask
5694 switch (instr_.BaseOpcodeValue()) {
5695 case JAL: {
5696 set_rd(get_pc() + kInstrSize);
5697 int64_t next_pc = get_pc() + imm20J();
5698 set_pc(next_pc);
5699 break;
5700 }
5701 default:
5702 UNSUPPORTED();
5703 }
5704}
5705void Simulator::DecodeCRType() {
5706 switch (instr_.RvcFunct4Value()) {
5707 case 0b1000:
5708 if (instr_.RvcRs1Value() != 0 && instr_.RvcRs2Value() == 0) { // c.jr
5709 set_pc(rvc_rs1());
5710 } else if (instr_.RvcRdValue() != 0 &&
5711 instr_.RvcRs2Value() != 0) { // c.mv
5712 set_rvc_rd(sext_xlen(rvc_rs2()));
5713 } else {
5715 }
5716 break;
5717 case 0b1001:
5718 if (instr_.RvcRs1Value() == 0 && instr_.RvcRs2Value() == 0) { // c.ebreak
5719 DieOrDebug();
5720 } else if (instr_.RvcRdValue() != 0 &&
5721 instr_.RvcRs2Value() == 0) { // c.jalr
5722 set_register(ra, get_pc() + kShortInstrSize);
5723 set_pc(rvc_rs1());
5724 } else if (instr_.RvcRdValue() != 0 &&
5725 instr_.RvcRs2Value() != 0) { // c.add
5726 set_rvc_rd(sext_xlen(rvc_rs1() + rvc_rs2()));
5727 } else {
5728 UNSUPPORTED();
5729 }
5730 break;
5731 default:
5732 UNSUPPORTED();
5733 }
5734}
5735
5736void Simulator::DecodeCAType() {
5737 switch (instr_.InstructionBits() & kCATypeMask) {
5738 case RO_C_SUB:
5739 set_rvc_rs1s(sext_xlen(rvc_rs1s() - rvc_rs2s()));
5740 break;
5741 case RO_C_XOR:
5742 set_rvc_rs1s(rvc_rs1s() ^ rvc_rs2s());
5743 break;
5744 case RO_C_OR:
5745 set_rvc_rs1s(rvc_rs1s() | rvc_rs2s());
5746 break;
5747 case RO_C_AND:
5748 set_rvc_rs1s(rvc_rs1s() & rvc_rs2s());
5749 break;
5750#if V8_TARGET_ARCH_RISCV64
5751 case RO_C_SUBW:
5752 set_rvc_rs1s(sext32(rvc_rs1s() - rvc_rs2s()));
5753 break;
5754 case RO_C_ADDW:
5755 set_rvc_rs1s(sext32(rvc_rs1s() + rvc_rs2s()));
5756 break;
5757#endif
5758 default:
5759 UNSUPPORTED();
5760 }
5761}
5762
5763void Simulator::DecodeCIType() {
5764 switch (instr_.RvcOpcode()) {
5765 case RO_C_NOP_ADDI:
5766 if (instr_.RvcRdValue() == 0) // c.nop
5767 break;
5768 else // c.addi
5769 set_rvc_rd(sext_xlen(rvc_rs1() + rvc_imm6()));
5770 break;
5771#if V8_TARGET_ARCH_RISCV64
5772 case RO_C_ADDIW:
5773 set_rvc_rd(sext32(rvc_rs1() + rvc_imm6()));
5774 break;
5775#endif
5776 case RO_C_LI:
5777 set_rvc_rd(sext_xlen(rvc_imm6()));
5778 break;
5779 case RO_C_LUI_ADD:
5780 if (instr_.RvcRdValue() == 2) {
5781 // c.addi16sp
5782 int64_t value = get_register(sp) + rvc_imm6_addi16sp();
5783 set_register(sp, value);
5784 } else if (instr_.RvcRdValue() != 0 && instr_.RvcRdValue() != 2) {
5785 // c.lui
5786 set_rvc_rd(rvc_u_imm6());
5787 } else {
5788 UNSUPPORTED();
5789 }
5790 break;
5791 case RO_C_SLLI:
5792 set_rvc_rd(sext_xlen(rvc_rs1() << rvc_shamt6()));
5793 break;
5794 case RO_C_FLDSP: {
5795 sreg_t addr = get_register(sp) + rvc_imm6_ldsp();
5796 uint64_t val = ReadMem<uint64_t>(addr, instr_.instr());
5797 set_rvc_drd(Float64::FromBits(val), false);
5798 TraceMemRdDouble(addr, Float64::FromBits(val),
5799 get_fpu_register(rvc_frd_reg()));
5800 break;
5801 }
5802#if V8_TARGET_ARCH_RISCV64
5803 case RO_C_LWSP: {
5804 sreg_t addr = get_register(sp) + rvc_imm6_lwsp();
5805 int64_t val = ReadMem<int32_t>(addr, instr_.instr());
5806 set_rvc_rd(sext_xlen(val), false);
5807 TraceMemRd(addr, val, get_register(rvc_rd_reg()));
5808 break;
5809 }
5810 case RO_C_LDSP: {
5811 sreg_t addr = get_register(sp) + rvc_imm6_ldsp();
5812 int64_t val = ReadMem<int64_t>(addr, instr_.instr());
5813 set_rvc_rd(sext_xlen(val), false);
5814 TraceMemRd(addr, val, get_register(rvc_rd_reg()));
5815 break;
5816 }
5817#elif V8_TARGET_ARCH_RISCV32
5818 case RO_C_FLWSP: {
5819 sreg_t addr = get_register(sp) + rvc_imm6_ldsp();
5820 uint32_t val = ReadMem<uint32_t>(addr, instr_.instr());
5821 set_rvc_frd(Float32::FromBits(val), false);
5822 TraceMemRdFloat(addr, Float32::FromBits(val),
5823 get_fpu_register(rvc_frd_reg()));
5824 break;
5825 }
5826 case RO_C_LWSP: {
5827 sreg_t addr = get_register(sp) + rvc_imm6_lwsp();
5828 int32_t val = ReadMem<int32_t>(addr, instr_.instr());
5829 set_rvc_rd(sext_xlen(val), false);
5830 TraceMemRd(addr, val, get_register(rvc_rd_reg()));
5831 break;
5832 }
5833#endif
5834 default:
5835 UNSUPPORTED();
5836 }
5837}
5838
5839void Simulator::DecodeCIWType() {
5840 switch (instr_.RvcOpcode()) {
5841 case RO_C_ADDI4SPN: {
5842 set_rvc_rs2s(get_register(sp) + rvc_imm8_addi4spn());
5843 break;
5844 default:
5845 UNSUPPORTED();
5846 }
5847 }
5848}
5849
5850void Simulator::DecodeCSSType() {
5851 switch (instr_.RvcOpcode()) {
5852 case RO_C_FSDSP: {
5853 sreg_t addr = get_register(sp) + rvc_imm6_sdsp();
5854 WriteMem<Float64>(addr, get_fpu_register_Float64(rvc_rs2_reg()),
5855 instr_.instr());
5856 break;
5857 }
5858#if V8_TARGET_ARCH_RISCV32
5859 case RO_C_FSWSP: {
5860 sreg_t addr = get_register(sp) + rvc_imm6_sdsp();
5861 WriteMem<Float32>(addr, get_fpu_register_Float32(rvc_rs2_reg(), false),
5862 instr_.instr());
5863 break;
5864 }
5865#endif
5866 case RO_C_SWSP: {
5867 sreg_t addr = get_register(sp) + rvc_imm6_swsp();
5868 WriteMem<int32_t>(addr, (int32_t)rvc_rs2(), instr_.instr());
5869 break;
5870 }
5871#if V8_TARGET_ARCH_RISCV64
5872 case RO_C_SDSP: {
5873 sreg_t addr = get_register(sp) + rvc_imm6_sdsp();
5874 WriteMem<int64_t>(addr, (int64_t)rvc_rs2(), instr_.instr());
5875 break;
5876 }
5877#endif
5878 default:
5879 UNSUPPORTED();
5880 }
5881}
5882
5883void Simulator::DecodeCLType() {
5884 switch (instr_.RvcOpcode()) {
5885 case RO_C_LW: {
5886 sreg_t addr = rvc_rs1s() + rvc_imm5_w();
5887 int64_t val = ReadMem<int32_t>(addr, instr_.instr());
5888 set_rvc_rs2s(sext_xlen(val), false);
5889 TraceMemRd(addr, val, get_register(rvc_rs2s_reg()));
5890 break;
5891 }
5892 case RO_C_FLD: {
5893 sreg_t addr = rvc_rs1s() + rvc_imm5_d();
5894 uint64_t val = ReadMem<uint64_t>(addr, instr_.instr());
5895 set_rvc_drs2s(Float64::FromBits(val), false);
5896 break;
5897 }
5898#if V8_TARGET_ARCH_RISCV64
5899 case RO_C_LD: {
5900 sreg_t addr = rvc_rs1s() + rvc_imm5_d();
5901 int64_t val = ReadMem<int64_t>(addr, instr_.instr());
5902 set_rvc_rs2s(sext_xlen(val), false);
5903 TraceMemRd(addr, val, get_register(rvc_rs2s_reg()));
5904 break;
5905 }
5906#elif V8_TARGET_ARCH_RISCV32
5907 case RO_C_FLW: {
5908 sreg_t addr = rvc_rs1s() + rvc_imm5_d();
5909 uint32_t val = ReadMem<uint32_t>(addr, instr_.instr());
5910 set_rvc_frs2s(Float32::FromBits(val), false);
5911 break;
5912 }
5913#endif
5914 default:
5915 UNSUPPORTED();
5916 }
5917}
5918
5919void Simulator::DecodeCSType() {
5920 switch (instr_.RvcOpcode()) {
5921 case RO_C_SW: {
5922 sreg_t addr = rvc_rs1s() + rvc_imm5_w();
5923 WriteMem<int32_t>(addr, (int32_t)rvc_rs2s(), instr_.instr());
5924 break;
5925 }
5926#if V8_TARGET_ARCH_RISCV64
5927 case RO_C_SD: {
5928 sreg_t addr = rvc_rs1s() + rvc_imm5_d();
5929 WriteMem<int64_t>(addr, (int64_t)rvc_rs2s(), instr_.instr());
5930 break;
5931 }
5932#endif
5933 case RO_C_FSD: {
5934 sreg_t addr = rvc_rs1s() + rvc_imm5_d();
5935 WriteMem<double>(addr, static_cast<double>(rvc_drs2s()), instr_.instr());
5936 break;
5937 }
5938 default:
5939 UNSUPPORTED();
5940 }
5941}
5942
5943void Simulator::DecodeCJType() {
5944 switch (instr_.RvcOpcode()) {
5945 case RO_C_J: {
5946 set_pc(get_pc() + instr_.RvcImm11CJValue());
5947 break;
5948 }
5949 default:
5950 UNSUPPORTED();
5951 }
5952}
5953
5954void Simulator::DecodeCBType() {
5955 switch (instr_.RvcOpcode()) {
5956 case RO_C_BNEZ:
5957 if (rvc_rs1() != 0) {
5958 sreg_t next_pc = get_pc() + rvc_imm8_b();
5959 set_pc(next_pc);
5960 }
5961 break;
5962 case RO_C_BEQZ:
5963 if (rvc_rs1() == 0) {
5964 sreg_t next_pc = get_pc() + rvc_imm8_b();
5965 set_pc(next_pc);
5966 }
5967 break;
5968 case RO_C_MISC_ALU:
5969 if (instr_.RvcFunct2BValue() == 0b00) { // c.srli
5970 set_rvc_rs1s(sext_xlen(sext_xlen(rvc_rs1s()) >> rvc_shamt6()));
5971 } else if (instr_.RvcFunct2BValue() == 0b01) { // c.srai
5972 require(rvc_shamt6() < xlen);
5973 set_rvc_rs1s(sext_xlen(sext_xlen(rvc_rs1s()) >> rvc_shamt6()));
5974 } else if (instr_.RvcFunct2BValue() == 0b10) { // c.andi
5975 set_rvc_rs1s(rvc_imm6() & rvc_rs1s());
5976 } else {
5977 UNSUPPORTED();
5978 }
5979 break;
5980 default:
5981 UNSUPPORTED();
5982 }
5983}
5984
5992// ref: https://locklessinc.com/articles/sat_arithmetic/
5993template <typename T, typename UT>
5994static inline T sat_add(T x, T y, bool& sat) {
5995 UT ux = x;
5996 UT uy = y;
5997 UT res = ux + uy;
5998 sat = false;
5999 int sh = sizeof(T) * 8 - 1;
6000
6001 /* Calculate overflowed result. (Don't change the sign bit of ux) */
6002 ux = (ux >> sh) + (((UT)0x1 << sh) - 1);
6003
6004 /* Force compiler to use cmovns instruction */
6005 if ((T)((ux ^ uy) | ~(uy ^ res)) >= 0) {
6006 res = ux;
6007 sat = true;
6008 }
6009
6010 return res;
6011}
6012
6013template <typename T, typename UT>
6014static inline T sat_sub(T x, T y, bool& sat) {
6015 UT ux = x;
6016 UT uy = y;
6017 UT res = ux - uy;
6018 sat = false;
6019 int sh = sizeof(T) * 8 - 1;
6020
6021 /* Calculate overflowed result. (Don't change the sign bit of ux) */
6022 ux = (ux >> sh) + (((UT)0x1 << sh) - 1);
6023
6024 /* Force compiler to use cmovns instruction */
6025 if ((T)((ux ^ uy) & (ux ^ res)) < 0) {
6026 res = ux;
6027 sat = true;
6028 }
6029
6030 return res;
6031}
6032
6033template <typename T>
6034T sat_addu(T x, T y, bool& sat) {
6035 T res = x + y;
6036 sat = false;
6037
6038 sat = res < x;
6039 res |= -(res < x);
6040
6041 return res;
6042}
6043
6044template <typename T>
6045T sat_subu(T x, T y, bool& sat) {
6046 T res = x - y;
6047 sat = false;
6048
6049 sat = !(res <= x);
6050 res &= -(res <= x);
6051
6052 return res;
6053}
6054
6055#ifdef CAN_USE_RVV_INSTRUCTIONS
6056void Simulator::DecodeRvvIVV() {
6057 DCHECK_EQ(instr_.InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_IVV);
6058 switch (instr_.InstructionBits() & kVTypeMask) {
6059 case RO_V_VADD_VV: {
6060 RVV_VI_VV_LOOP({ vd = vs1 + vs2; });
6061 break;
6062 }
6063 case RO_V_VSADD_VV: {
6064 RVV_VI_GENERAL_LOOP_BASE
6065 bool sat = false;
6066 switch (rvv_vsew()) {
6067 case E8: {
6068 VV_PARAMS(8);
6069 vd = sat_add<int8_t, uint8_t>(vs2, vs1, sat);
6070 break;
6071 }
6072 case E16: {
6073 VV_PARAMS(16);
6074 vd = sat_add<int16_t, uint16_t>(vs2, vs1, sat);
6075 break;
6076 }
6077 case E32: {
6078 VV_PARAMS(32);
6079 vd = sat_add<int32_t, uint32_t>(vs2, vs1, sat);
6080 break;
6081 }
6082 default: {
6083 VV_PARAMS(64);
6084 vd = sat_add<int64_t, uint64_t>(vs2, vs1, sat);
6085 break;
6086 }
6087 }
6088 set_rvv_vxsat(sat);
6089 RVV_VI_LOOP_END
6090 break;
6091 }
6092 case RO_V_VSADDU_VV:
6093 RVV_VI_VV_ULOOP({
6094 vd = vs2 + vs1;
6095 vd |= -(vd < vs2);
6096 })
6097 break;
6098 case RO_V_VSUB_VV: {
6099 RVV_VI_VV_LOOP({ vd = vs2 - vs1; })
6100 break;
6101 }
6102 case RO_V_VSSUB_VV: {
6103 RVV_VI_GENERAL_LOOP_BASE
6104 bool sat = false;
6105 switch (rvv_vsew()) {
6106 case E8: {
6107 VV_PARAMS(8);
6108 vd = sat_sub<int8_t, uint8_t>(vs2, vs1, sat);
6109 break;
6110 }
6111 case E16: {
6112 VV_PARAMS(16);
6113 vd = sat_sub<int16_t, uint16_t>(vs2, vs1, sat);
6114 break;
6115 }
6116 case E32: {
6117 VV_PARAMS(32);
6118 vd = sat_sub<int32_t, uint32_t>(vs2, vs1, sat);
6119 break;
6120 }
6121 default: {
6122 VV_PARAMS(64);
6123 vd = sat_sub<int64_t, uint64_t>(vs2, vs1, sat);
6124 break;
6125 }
6126 }
6127 set_rvv_vxsat(sat);
6128 RVV_VI_LOOP_END
6129 break;
6130 }
6131 case RO_V_VSSUBU_VV: {
6132 RVV_VI_GENERAL_LOOP_BASE
6133 bool sat = false;
6134 switch (rvv_vsew()) {
6135 case E8: {
6136 VV_UPARAMS(8);
6137 vd = sat_subu<uint8_t>(vs2, vs1, sat);
6138 break;
6139 }
6140 case E16: {
6141 VV_UPARAMS(16);
6142 vd = sat_subu<uint16_t>(vs2, vs1, sat);
6143 break;
6144 }
6145 case E32: {
6146 VV_UPARAMS(32);
6147 vd = sat_subu<uint32_t>(vs2, vs1, sat);
6148 break;
6149 }
6150 default: {
6151 VV_UPARAMS(64);
6152 vd = sat_subu<uint64_t>(vs2, vs1, sat);
6153 break;
6154 }
6155 }
6156 set_rvv_vxsat(sat);
6157 RVV_VI_LOOP_END
6158 break;
6159 }
6160 case RO_V_VAND_VV: {
6161 RVV_VI_VV_LOOP({ vd = vs1 & vs2; })
6162 break;
6163 }
6164 case RO_V_VOR_VV: {
6165 RVV_VI_VV_LOOP({ vd = vs1 | vs2; })
6166 break;
6167 }
6168 case RO_V_VXOR_VV: {
6169 RVV_VI_VV_LOOP({ vd = vs1 ^ vs2; })
6170 break;
6171 }
6172 case RO_V_VMAXU_VV: {
6173 RVV_VI_VV_ULOOP({
6174 if (vs1 <= vs2) {
6175 vd = vs2;
6176 } else {
6177 vd = vs1;
6178 }
6179 })
6180 break;
6181 }
6182 case RO_V_VMAX_VV: {
6183 RVV_VI_VV_LOOP({
6184 if (vs1 <= vs2) {
6185 vd = vs2;
6186 } else {
6187 vd = vs1;
6188 }
6189 })
6190 break;
6191 }
6192 case RO_V_VMINU_VV: {
6193 RVV_VI_VV_ULOOP({
6194 if (vs1 <= vs2) {
6195 vd = vs1;
6196 } else {
6197 vd = vs2;
6198 }
6199 })
6200 break;
6201 }
6202 case RO_V_VMIN_VV: {
6203 RVV_VI_VV_LOOP({
6204 if (vs1 <= vs2) {
6205 vd = vs1;
6206 } else {
6207 vd = vs2;
6208 }
6209 })
6210 break;
6211 }
6212 case RO_V_VMV_VV: {
6213 if (instr_.RvvVM()) {
6214 RVV_VI_VVXI_MERGE_LOOP({
6215 vd = vs1;
6216 USE(simm5);
6217 USE(vs2);
6218 USE(rs1);
6219 });
6220 } else {
6221 RVV_VI_VVXI_MERGE_LOOP({
6222 bool use_first = (Rvvelt<uint64_t>(0, (i / 64)) >> (i % 64)) & 0x1;
6223 vd = use_first ? vs1 : vs2;
6224 USE(simm5);
6225 USE(rs1);
6226 });
6227 }
6228 break;
6229 }
6230 case RO_V_VMSEQ_VV: {
6231 RVV_VI_VV_LOOP_CMP({ res = vs1 == vs2; })
6232 break;
6233 }
6234 case RO_V_VMSNE_VV: {
6235 RVV_VI_VV_LOOP_CMP({ res = vs1 != vs2; })
6236 break;
6237 }
6238 case RO_V_VMSLTU_VV: {
6239 RVV_VI_VV_ULOOP_CMP({ res = vs2 < vs1; })
6240 break;
6241 }
6242 case RO_V_VMSLT_VV: {
6243 RVV_VI_VV_LOOP_CMP({ res = vs2 < vs1; })
6244 break;
6245 }
6246 case RO_V_VMSLE_VV: {
6247 RVV_VI_VV_LOOP_CMP({ res = vs2 <= vs1; })
6248 break;
6249 }
6250 case RO_V_VMSLEU_VV: {
6251 RVV_VI_VV_ULOOP_CMP({ res = vs2 <= vs1; })
6252 break;
6253 }
6254 case RO_V_VADC_VV:
6255 if (instr_.RvvVM()) {
6256 RVV_VI_VV_LOOP_WITH_CARRY({
6257 auto& v0 = Rvvelt<uint64_t>(0, midx);
6258 vd = vs1 + vs2 + (v0 >> mpos) & 0x1;
6259 })
6260 } else {
6261 UNREACHABLE();
6262 }
6263 break;
6264 case RO_V_VSLL_VV: {
6265 RVV_VI_VV_LOOP({ vd = vs2 << (vs1 & (rvv_sew() - 1)); })
6266 break;
6267 }
6268 case RO_V_VSRL_VV:
6269 RVV_VI_VV_ULOOP({ vd = vs2 >> (vs1 & (rvv_sew() - 1)); })
6270 break;
6271 case RO_V_VSRA_VV:
6272 RVV_VI_VV_LOOP({ vd = vs2 >> (vs1 & (rvv_sew() - 1)); })
6273 break;
6274 case RO_V_VSMUL_VV: {
6275 RVV_VI_GENERAL_LOOP_BASE
6276 RVV_VI_LOOP_MASK_SKIP()
6277 if (rvv_vsew() == E8) {
6278 VV_PARAMS(8);
6279 int16_t result = (int16_t)vs1 * (int16_t)vs2;
6280 uint8_t round = get_round(static_cast<int>(rvv_vxrm()), result, 7);
6281 result = (result >> 7) + round;
6282 vd = signed_saturation<int16_t, int8_t>(result, 8);
6283 } else if (rvv_vsew() == E16) {
6284 VV_PARAMS(16);
6285 int32_t result = (int32_t)vs1 * (int32_t)vs2;
6286 uint8_t round = get_round(static_cast<int>(rvv_vxrm()), result, 15);
6287 result = (result >> 15) + round;
6288 vd = signed_saturation<int32_t, int16_t>(result, 16);
6289 } else if (rvv_vsew() == E32) {
6290 VV_PARAMS(32);
6291 int64_t result = (int64_t)vs1 * (int64_t)vs2;
6292 uint8_t round = get_round(static_cast<int>(rvv_vxrm()), result, 31);
6293 result = (result >> 31) + round;
6294 vd = signed_saturation<int64_t, int32_t>(result, 32);
6295 } else if (rvv_vsew() == E64) {
6296 VV_PARAMS(64);
6297 __int128_t result = (__int128_t)vs1 * (__int128_t)vs2;
6298 uint8_t round = get_round(static_cast<int>(rvv_vxrm()), result, 63);
6299 result = (result >> 63) + round;
6300 vd = signed_saturation<__int128_t, int64_t>(result, 64);
6301 } else {
6302 UNREACHABLE();
6303 }
6304 RVV_VI_LOOP_END
6305 rvv_trace_vd();
6306 break;
6307 }
6308 case RO_V_VRGATHER_VV: {
6309 RVV_VI_GENERAL_LOOP_BASE
6310 CHECK_NE(rvv_vs1_reg(), rvv_vd_reg());
6311 CHECK_NE(rvv_vs2_reg(), rvv_vd_reg());
6312 switch (rvv_vsew()) {
6313 case E8: {
6314 auto vs1 = Rvvelt<uint8_t>(rvv_vs1_reg(), i);
6315 // if (i > 255) continue;
6316 Rvvelt<uint8_t>(rvv_vd_reg(), i, true) =
6317 vs1 >= rvv_vlmax() ? 0 : Rvvelt<uint8_t>(rvv_vs2_reg(), vs1);
6318 break;
6319 }
6320 case E16: {
6321 auto vs1 = Rvvelt<uint16_t>(rvv_vs1_reg(), i);
6322 Rvvelt<uint16_t>(rvv_vd_reg(), i, true) =
6323 vs1 >= rvv_vlmax() ? 0 : Rvvelt<uint16_t>(rvv_vs2_reg(), vs1);
6324 break;
6325 }
6326 case E32: {
6327 auto vs1 = Rvvelt<uint32_t>(rvv_vs1_reg(), i);
6328 Rvvelt<uint32_t>(rvv_vd_reg(), i, true) =
6329 vs1 >= rvv_vlmax() ? 0 : Rvvelt<uint32_t>(rvv_vs2_reg(), vs1);
6330 break;
6331 }
6332 default: {
6333 auto vs1 = Rvvelt<uint64_t>(rvv_vs1_reg(), i);
6334 Rvvelt<uint64_t>(rvv_vd_reg(), i, true) =
6335 vs1 >= rvv_vlmax() ? 0 : Rvvelt<uint64_t>(rvv_vs2_reg(), vs1);
6336 break;
6337 }
6338 }
6339 RVV_VI_LOOP_END;
6340 rvv_trace_vd();
6341 break;
6342 }
6343 default:
6344 // v8::base::EmbeddedVector<char, 256> buffer;
6345 // SNPrintF(trace_buf_, " ");
6346 // disasm::NameConverter converter;
6347 // disasm::Disassembler dasm(converter);
6348 // // Use a reasonably large buffer.
6349 // dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(&instr_));
6350
6351 // PrintF("EXECUTING 0x%08" PRIxPTR " %-44s\n",
6352 // reinterpret_cast<intptr_t>(&instr_), buffer.begin());
6354 break;
6355 }
6356 set_rvv_vstart(0);
6357}
6358
6359void Simulator::DecodeRvvIVI() {
6360 DCHECK_EQ(instr_.InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_IVI);
6361 switch (instr_.InstructionBits() & kVTypeMask) {
6362 case RO_V_VADD_VI: {
6363 RVV_VI_VI_LOOP({ vd = simm5 + vs2; })
6364 break;
6365 }
6366 case RO_V_VSADD_VI: {
6367 RVV_VI_GENERAL_LOOP_BASE
6368 bool sat = false;
6369 switch (rvv_vsew()) {
6370 case E8: {
6371 VI_PARAMS(8);
6372 vd = sat_add<int8_t, uint8_t>(vs2, simm5, sat);
6373 break;
6374 }
6375 case E16: {
6376 VI_PARAMS(16);
6377 vd = sat_add<int16_t, uint16_t>(vs2, simm5, sat);
6378 break;
6379 }
6380 case E32: {
6381 VI_PARAMS(32);
6382 vd = sat_add<int32_t, uint32_t>(vs2, simm5, sat);
6383 break;
6384 }
6385 default: {
6386 VI_PARAMS(64);
6387 vd = sat_add<int64_t, uint64_t>(vs2, simm5, sat);
6388 break;
6389 }
6390 }
6391 set_rvv_vxsat(sat);
6392 RVV_VI_LOOP_END
6393 break;
6394 }
6395 case RO_V_VSADDU_VI: {
6396 RVV_VI_VI_ULOOP({
6397 vd = vs2 + uimm5;
6398 vd |= -(vd < vs2);
6399 })
6400 break;
6401 }
6402 case RO_V_VRSUB_VI: {
6403 RVV_VI_VI_LOOP({ vd = simm5 - vs2; })
6404 break;
6405 }
6406 case RO_V_VAND_VI: {
6407 RVV_VI_VI_LOOP({ vd = simm5 & vs2; })
6408 break;
6409 }
6410 case RO_V_VOR_VI: {
6411 RVV_VI_VI_LOOP({ vd = simm5 | vs2; })
6412 break;
6413 }
6414 case RO_V_VXOR_VI: {
6415 RVV_VI_VI_LOOP({ vd = simm5 ^ vs2; })
6416 break;
6417 }
6418 case RO_V_VMV_VI:
6419 if (instr_.RvvVM()) {
6420 RVV_VI_VVXI_MERGE_LOOP({
6421 vd = simm5;
6422 USE(vs1);
6423 USE(vs2);
6424 USE(rs1);
6425 });
6426 } else {
6427 RVV_VI_VVXI_MERGE_LOOP({
6428 bool use_first = (Rvvelt<uint64_t>(0, (i / 64)) >> (i % 64)) & 0x1;
6429 vd = use_first ? simm5 : vs2;
6430 USE(vs1);
6431 USE(rs1);
6432 });
6433 }
6434 break;
6435 case RO_V_VMSEQ_VI:
6436 RVV_VI_VI_LOOP_CMP({ res = simm5 == vs2; })
6437 break;
6438 case RO_V_VMSNE_VI:
6439 RVV_VI_VI_LOOP_CMP({ res = simm5 != vs2; })
6440 break;
6441 case RO_V_VMSLEU_VI:
6442 RVV_VI_VI_ULOOP_CMP({ res = vs2 <= uimm5; })
6443 break;
6444 case RO_V_VMSLE_VI:
6445 RVV_VI_VI_LOOP_CMP({ res = vs2 <= simm5; })
6446 break;
6447 case RO_V_VMSGT_VI:
6448 RVV_VI_VI_LOOP_CMP({ res = vs2 > simm5; })
6449 break;
6450 case RO_V_VSLIDEDOWN_VI: {
6451 RVV_VI_CHECK_SLIDE(false);
6452 const uint8_t sh = instr_.RvvUimm5();
6453 RVV_VI_GENERAL_LOOP_BASE
6454
6455 reg_t offset = 0;
6456 bool is_valid = (i + sh) < rvv_vlmax();
6457
6458 if (is_valid) {
6459 offset = sh;
6460 }
6461
6462 switch (rvv_vsew()) {
6463 case E8: {
6464 VI_XI_SLIDEDOWN_PARAMS(8, offset);
6465 vd = is_valid ? vs2 : 0;
6466 } break;
6467 case E16: {
6468 VI_XI_SLIDEDOWN_PARAMS(16, offset);
6469 vd = is_valid ? vs2 : 0;
6470 } break;
6471 case E32: {
6472 VI_XI_SLIDEDOWN_PARAMS(32, offset);
6473 vd = is_valid ? vs2 : 0;
6474 } break;
6475 default: {
6476 VI_XI_SLIDEDOWN_PARAMS(64, offset);
6477 vd = is_valid ? vs2 : 0;
6478 } break;
6479 }
6480 RVV_VI_LOOP_END
6481 rvv_trace_vd();
6482 } break;
6483 case RO_V_VSLIDEUP_VI: {
6484 RVV_VI_CHECK_SLIDE(true);
6485
6486 const uint8_t offset = instr_.RvvUimm5();
6487 RVV_VI_GENERAL_LOOP_BASE
6488 if (rvv_vstart() < offset && i < offset) continue;
6489
6490 switch (rvv_vsew()) {
6491 case E8: {
6492 VI_XI_SLIDEUP_PARAMS(8, offset);
6493 vd = vs2;
6494 } break;
6495 case E16: {
6496 VI_XI_SLIDEUP_PARAMS(16, offset);
6497 vd = vs2;
6498 } break;
6499 case E32: {
6500 VI_XI_SLIDEUP_PARAMS(32, offset);
6501 vd = vs2;
6502 } break;
6503 default: {
6504 VI_XI_SLIDEUP_PARAMS(64, offset);
6505 vd = vs2;
6506 } break;
6507 }
6508 RVV_VI_LOOP_END
6509 rvv_trace_vd();
6510 } break;
6511 case RO_V_VSRL_VI:
6512 RVV_VI_VI_ULOOP({ vd = vs2 >> (uimm5 & (rvv_sew() - 1)); })
6513 break;
6514 case RO_V_VSRA_VI:
6515 RVV_VI_VI_LOOP({ vd = vs2 >> (simm5 & (rvv_sew() - 1) & 0x1f); })
6516 break;
6517 case RO_V_VSLL_VI:
6518 RVV_VI_VI_ULOOP({ vd = vs2 << (uimm5 & (rvv_sew() - 1)); })
6519 break;
6520 case RO_V_VADC_VI:
6521 if (instr_.RvvVM()) {
6522 RVV_VI_XI_LOOP_WITH_CARRY({
6523 auto& v0 = Rvvelt<uint64_t>(0, midx);
6524 vd = simm5 + vs2 + (v0 >> mpos) & 0x1;
6525 USE(rs1);
6526 })
6527 } else {
6528 UNREACHABLE();
6529 }
6530 break;
6531 case RO_V_VNCLIP_WI:
6532 RVV_VN_CLIP_VI_LOOP()
6533 break;
6534 case RO_V_VNCLIPU_WI:
6535 RVV_VN_CLIPU_VI_LOOP()
6536 break;
6537 default:
6539 break;
6540 }
6541}
6542
6543void Simulator::DecodeRvvIVX() {
6544 DCHECK_EQ(instr_.InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_IVX);
6545 switch (instr_.InstructionBits() & kVTypeMask) {
6546 case RO_V_VADD_VX: {
6547 RVV_VI_VX_LOOP({ vd = rs1 + vs2; })
6548 break;
6549 }
6550 case RO_V_VSADD_VX: {
6551 RVV_VI_GENERAL_LOOP_BASE
6552 bool sat = false;
6553 switch (rvv_vsew()) {
6554 case E8: {
6555 VX_PARAMS(8);
6556 vd = sat_add<int8_t, uint8_t>(vs2, rs1, sat);
6557 break;
6558 }
6559 case E16: {
6560 VX_PARAMS(16);
6561 vd = sat_add<int16_t, uint16_t>(vs2, rs1, sat);
6562 break;
6563 }
6564 case E32: {
6565 VX_PARAMS(32);
6566 vd = sat_add<int32_t, uint32_t>(vs2, rs1, sat);
6567 break;
6568 }
6569 default: {
6570 VX_PARAMS(64);
6571 vd = sat_add<int64_t, uint64_t>(vs2, rs1, sat);
6572 break;
6573 }
6574 }
6575 set_rvv_vxsat(sat);
6576 RVV_VI_LOOP_END
6577 break;
6578 }
6579 case RO_V_VSADDU_VX: {
6580 RVV_VI_VX_ULOOP({
6581 vd = vs2 + rs1;
6582 vd |= -(vd < vs2);
6583 })
6584 break;
6585 }
6586 case RO_V_VSUB_VX: {
6587 RVV_VI_VX_LOOP({ vd = vs2 - rs1; })
6588 break;
6589 }
6590 case RO_V_VSSUB_VX: {
6591 RVV_VI_GENERAL_LOOP_BASE
6592 bool sat = false;
6593 switch (rvv_vsew()) {
6594 case E8: {
6595 VX_PARAMS(8);
6596 vd = sat_sub<int8_t, uint8_t>(vs2, rs1, sat);
6597 break;
6598 }
6599 case E16: {
6600 VX_PARAMS(16);
6601 vd = sat_sub<int16_t, uint16_t>(vs2, rs1, sat);
6602 break;
6603 }
6604 case E32: {
6605 VX_PARAMS(32);
6606 vd = sat_sub<int32_t, uint32_t>(vs2, rs1, sat);
6607 break;
6608 }
6609 default: {
6610 VX_PARAMS(64);
6611 vd = sat_sub<int64_t, uint64_t>(vs2, rs1, sat);
6612 break;
6613 }
6614 }
6615 set_rvv_vxsat(sat);
6616 RVV_VI_LOOP_END
6617 break;
6618 }
6619 case RO_V_VRSUB_VX: {
6620 RVV_VI_VX_LOOP({ vd = rs1 - vs2; })
6621 break;
6622 }
6623 case RO_V_VAND_VX: {
6624 RVV_VI_VX_LOOP({ vd = rs1 & vs2; })
6625 break;
6626 }
6627 case RO_V_VOR_VX: {
6628 RVV_VI_VX_LOOP({ vd = rs1 | vs2; })
6629 break;
6630 }
6631 case RO_V_VXOR_VX: {
6632 RVV_VI_VX_LOOP({ vd = rs1 ^ vs2; })
6633 break;
6634 }
6635 case RO_V_VMAX_VX: {
6636 RVV_VI_VX_LOOP({
6637 if (rs1 <= vs2) {
6638 vd = vs2;
6639 } else {
6640 vd = rs1;
6641 }
6642 })
6643 break;
6644 }
6645 case RO_V_VMAXU_VX: {
6646 RVV_VI_VX_ULOOP({
6647 if (rs1 <= vs2) {
6648 vd = vs2;
6649 } else {
6650 vd = rs1;
6651 }
6652 })
6653 break;
6654 }
6655 case RO_V_VMINU_VX: {
6656 RVV_VI_VX_ULOOP({
6657 if (rs1 <= vs2) {
6658 vd = rs1;
6659 } else {
6660 vd = vs2;
6661 }
6662 })
6663 break;
6664 }
6665 case RO_V_VMIN_VX: {
6666 RVV_VI_VX_LOOP({
6667 if (rs1 <= vs2) {
6668 vd = rs1;
6669 } else {
6670 vd = vs2;
6671 }
6672 })
6673 break;
6674 }
6675 case RO_V_VMV_VX:
6676 if (instr_.RvvVM()) {
6677 RVV_VI_VVXI_MERGE_LOOP({
6678 vd = rs1;
6679 USE(vs1);
6680 USE(vs2);
6681 USE(simm5);
6682 });
6683 } else {
6684 RVV_VI_VVXI_MERGE_LOOP({
6685 bool use_first = (Rvvelt<uint64_t>(0, (i / 64)) >> (i % 64)) & 0x1;
6686 vd = use_first ? rs1 : vs2;
6687 USE(vs1);
6688 USE(simm5);
6689 });
6690 }
6691 break;
6692 case RO_V_VMSEQ_VX:
6693 RVV_VI_VX_LOOP_CMP({ res = vs2 == rs1; })
6694 break;
6695 case RO_V_VMSNE_VX:
6696 RVV_VI_VX_LOOP_CMP({ res = vs2 != rs1; })
6697 break;
6698 case RO_V_VMSLT_VX:
6699 RVV_VI_VX_LOOP_CMP({ res = vs2 < rs1; })
6700 break;
6701 case RO_V_VMSLTU_VX:
6702 RVV_VI_VX_ULOOP_CMP({ res = vs2 < rs1; })
6703 break;
6704 case RO_V_VMSLE_VX:
6705 RVV_VI_VX_LOOP_CMP({ res = vs2 <= rs1; })
6706 break;
6707 case RO_V_VMSLEU_VX:
6708 RVV_VI_VX_ULOOP_CMP({ res = vs2 <= rs1; })
6709 break;
6710 case RO_V_VMSGT_VX:
6711 RVV_VI_VX_LOOP_CMP({ res = vs2 > rs1; })
6712 break;
6713 case RO_V_VMSGTU_VX:
6714 RVV_VI_VX_ULOOP_CMP({ res = vs2 > rs1; })
6715 break;
6716 case RO_V_VSLIDEDOWN_VX: {
6717 RVV_VI_CHECK_SLIDE(false);
6718
6719 const sreg_t sh = get_register(rs1_reg());
6720 RVV_VI_GENERAL_LOOP_BASE
6721
6722 reg_t offset = 0;
6723 bool is_valid = (i + sh) < rvv_vlmax();
6724
6725 if (is_valid) {
6726 offset = sh;
6727 }
6728
6729 switch (rvv_vsew()) {
6730 case E8: {
6731 VI_XI_SLIDEDOWN_PARAMS(8, offset);
6732 vd = is_valid ? vs2 : 0;
6733 } break;
6734 case E16: {
6735 VI_XI_SLIDEDOWN_PARAMS(16, offset);
6736 vd = is_valid ? vs2 : 0;
6737 } break;
6738 case E32: {
6739 VI_XI_SLIDEDOWN_PARAMS(32, offset);
6740 vd = is_valid ? vs2 : 0;
6741 } break;
6742 default: {
6743 VI_XI_SLIDEDOWN_PARAMS(64, offset);
6744 vd = is_valid ? vs2 : 0;
6745 } break;
6746 }
6747 RVV_VI_LOOP_END
6748 rvv_trace_vd();
6749 } break;
6750 case RO_V_VSLIDEUP_VX: {
6751 RVV_VI_CHECK_SLIDE(true);
6752
6753 const reg_t offset = get_register(rs1_reg());
6754 RVV_VI_GENERAL_LOOP_BASE
6755 if (rvv_vstart() < offset && i < offset) continue;
6756
6757 switch (rvv_vsew()) {
6758 case E8: {
6759 VI_XI_SLIDEUP_PARAMS(8, offset);
6760 vd = vs2;
6761 } break;
6762 case E16: {
6763 VI_XI_SLIDEUP_PARAMS(16, offset);
6764 vd = vs2;
6765 } break;
6766 case E32: {
6767 VI_XI_SLIDEUP_PARAMS(32, offset);
6768 vd = vs2;
6769 } break;
6770 default: {
6771 VI_XI_SLIDEUP_PARAMS(64, offset);
6772 vd = vs2;
6773 } break;
6774 }
6775 RVV_VI_LOOP_END
6776 rvv_trace_vd();
6777 } break;
6778 case RO_V_VADC_VX:
6779 if (instr_.RvvVM()) {
6780 RVV_VI_XI_LOOP_WITH_CARRY({
6781 auto& v0 = Rvvelt<uint64_t>(0, midx);
6782 vd = rs1 + vs2 + (v0 >> mpos) & 0x1;
6783 USE(simm5);
6784 })
6785 } else {
6786 UNREACHABLE();
6787 }
6788 break;
6789 case RO_V_VSLL_VX: {
6790 RVV_VI_VX_LOOP({ vd = vs2 << (rs1 & (rvv_sew() - 1)); })
6791 break;
6792 }
6793 case RO_V_VSRL_VX: {
6794 RVV_VI_VX_ULOOP({ vd = (vs2 >> (rs1 & (rvv_sew() - 1))); })
6795 break;
6796 }
6797 case RO_V_VSRA_VX: {
6798 RVV_VI_VX_LOOP({ vd = ((vs2) >> (rs1 & (rvv_sew() - 1))); })
6799 break;
6800 }
6801 default:
6803 break;
6804 }
6805}
6806
6807void Simulator::DecodeRvvMVV() {
6808 DCHECK_EQ(instr_.InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_MVV);
6809 switch (instr_.InstructionBits() & kVTypeMask) {
6810 case RO_V_VMUNARY0: {
6811 if (instr_.Vs1Value() == VID_V) {
6812 CHECK(rvv_vsew() >= E8 && rvv_vsew() <= E64);
6813 uint8_t rd_num = rvv_vd_reg();
6814 require_align(rd_num, rvv_vflmul());
6815 require_vm;
6816 for (uint8_t i = rvv_vstart(); i < rvv_vl(); ++i) {
6817 RVV_VI_LOOP_MASK_SKIP();
6818 switch (rvv_vsew()) {
6819 case E8:
6820 Rvvelt<uint8_t>(rd_num, i, true) = i;
6821 break;
6822 case E16:
6823 Rvvelt<uint16_t>(rd_num, i, true) = i;
6824 break;
6825 case E32:
6826 Rvvelt<uint32_t>(rd_num, i, true) = i;
6827 break;
6828 default:
6829 Rvvelt<uint64_t>(rd_num, i, true) = i;
6830 break;
6831 }
6832 }
6833 set_rvv_vstart(0);
6834 } else {
6836 }
6837 break;
6838 }
6839 case RO_V_VMUL_VV: {
6840 RVV_VI_VV_LOOP({ vd = vs2 * vs1; })
6841 break;
6842 }
6843 case RO_V_VWMUL_VV: {
6844 RVV_VI_CHECK_DSS(true);
6845 RVV_VI_VV_LOOP_WIDEN({
6846 VI_WIDE_OP_AND_ASSIGN(vs2, vs1, 0, *, +, int);
6847 USE(vd);
6848 })
6849 break;
6850 }
6851 case RO_V_VWMULU_VV: {
6852 RVV_VI_CHECK_DSS(true);
6853 RVV_VI_VV_LOOP_WIDEN({
6854 VI_WIDE_OP_AND_ASSIGN(vs2, vs1, 0, *, +, uint);
6855 USE(vd);
6856 })
6857 break;
6858 }
6859 case RO_V_VMULHU_VV: {
6860 RVV_VI_VV_LOOP({ vd = ((__uint128_t)vs2 * vs1) >> rvv_sew(); })
6861 break;
6862 }
6863 case RO_V_VMULH_VV: {
6864 RVV_VI_VV_LOOP({ vd = ((__int128_t)vs2 * vs1) >> rvv_sew(); })
6865 break;
6866 }
6867 case RO_V_VDIV_VV: {
6868 RVV_VI_VV_LOOP({ vd = vs2 / vs1; })
6869 break;
6870 }
6871 case RO_V_VDIVU_VV: {
6872 RVV_VI_VV_LOOP({ vd = vs2 / vs1; })
6873 break;
6874 }
6875 case RO_V_VWXUNARY0: {
6876 if (rvv_vs1_reg() == 0) {
6877 // vmv.x.s
6878 switch (rvv_vsew()) {
6879 case E8:
6880 set_rd(Rvvelt<type_sew_t<8>::type>(rvv_vs2_reg(), 0));
6881 break;
6882 case E16:
6883 set_rd(Rvvelt<type_sew_t<16>::type>(rvv_vs2_reg(), 0));
6884 break;
6885 case E32:
6886 set_rd(Rvvelt<type_sew_t<32>::type>(rvv_vs2_reg(), 0));
6887 break;
6888 case E64:
6889 set_rd(Rvvelt<type_sew_t<64>::type>(rvv_vs2_reg(), 0));
6890 break;
6891 default:
6892 UNREACHABLE();
6893 }
6894 set_rvv_vstart(0);
6895 rvv_trace_vd();
6896 } else if (rvv_vs1_reg() == 0b10000) {
6897 // vpopc
6898 reg_t cnt = 0;
6899 RVV_VI_GENERAL_LOOP_BASE
6900 RVV_VI_LOOP_MASK_SKIP()
6901 const uint8_t idx = i / 64;
6902 const uint8_t pos = i % 64;
6903 bool mask = (Rvvelt<uint64_t>(rvv_vs2_reg(), idx) >> pos) & 0x1;
6904 if (mask) cnt++;
6905 RVV_VI_LOOP_END
6906 set_register(rd_reg(), cnt);
6907 rvv_trace_vd();
6908 } else if (rvv_vs1_reg() == 0b10001) {
6909 // vfirst
6910 sreg_t index = -1;
6911 RVV_VI_GENERAL_LOOP_BASE
6912 RVV_VI_LOOP_MASK_SKIP()
6913 const uint8_t idx = i / 64;
6914 const uint8_t pos = i % 64;
6915 bool mask = (Rvvelt<uint64_t>(rvv_vs2_reg(), idx) >> pos) & 0x1;
6916 if (mask) {
6917 index = i;
6918 break;
6919 }
6920 RVV_VI_LOOP_END
6921 set_register(rd_reg(), index);
6922 rvv_trace_vd();
6923 } else {
6925 disasm::NameConverter converter;
6926 disasm::Disassembler dasm(converter);
6927 dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(&instr_));
6928 PrintF("EXECUTING 0x%08" PRIxPTR " %-44s\n",
6929 reinterpret_cast<intptr_t>(&instr_), buffer.begin());
6931 }
6932 } break;
6933 case RO_V_VREDMAXU:
6934 RVV_VI_VV_ULOOP_REDUCTION(
6935 { vd_0_res = (vd_0_res >= vs2) ? vd_0_res : vs2; })
6936 break;
6937 case RO_V_VREDMAX:
6938 RVV_VI_VV_LOOP_REDUCTION(
6939 { vd_0_res = (vd_0_res >= vs2) ? vd_0_res : vs2; })
6940 break;
6941 case RO_V_VREDMINU:
6942 RVV_VI_VV_ULOOP_REDUCTION(
6943 { vd_0_res = (vd_0_res <= vs2) ? vd_0_res : vs2; })
6944 break;
6945 case RO_V_VREDMIN:
6946 RVV_VI_VV_LOOP_REDUCTION(
6947 { vd_0_res = (vd_0_res <= vs2) ? vd_0_res : vs2; })
6948 break;
6949 case RO_V_VXUNARY0:
6950 if (rvv_vs1_reg() == 0b00010) {
6951 RVV_VI_VIE_8_LOOP(false);
6952 } else if (rvv_vs1_reg() == 0b00011) {
6953 RVV_VI_VIE_8_LOOP(true);
6954 } else if (rvv_vs1_reg() == 0b00100) {
6955 RVV_VI_VIE_4_LOOP(false);
6956 } else if (rvv_vs1_reg() == 0b00101) {
6957 RVV_VI_VIE_4_LOOP(true);
6958 } else if (rvv_vs1_reg() == 0b00110) {
6959 RVV_VI_VIE_2_LOOP(false);
6960 } else if (rvv_vs1_reg() == 0b00111) {
6961 RVV_VI_VIE_2_LOOP(true);
6962 } else {
6964 }
6965 break;
6966 case RO_V_VWADDU_VV:
6967 RVV_VI_CHECK_DSS(true);
6968 RVV_VI_VV_LOOP_WIDEN({
6969 VI_WIDE_OP_AND_ASSIGN(vs2, vs1, 0, +, +, uint);
6970 USE(vd);
6971 })
6972 break;
6973 case RO_V_VWADD_VV:
6974 RVV_VI_CHECK_DSS(true);
6975 RVV_VI_VV_LOOP_WIDEN({
6976 VI_WIDE_OP_AND_ASSIGN(vs2, vs1, 0, +, +, int);
6977 USE(vd);
6978 })
6979 break;
6980 case RO_V_VCOMPRESS_VV: {
6981 CHECK_EQ(rvv_vstart(), 0);
6982 require_align(rvv_vd_reg(), rvv_vflmul());
6983 require_align(rvv_vs2_reg(), rvv_vflmul());
6984 require(rvv_vd_reg() != rvv_vs2_reg());
6985 require_noover(rvv_vd_reg(), rvv_vflmul(), rvv_vs1_reg(), 1);
6986
6987 reg_t pos = 0;
6988
6989 RVV_VI_GENERAL_LOOP_BASE
6990 const uint64_t midx = i / 64;
6991 const uint64_t mpos = i % 64;
6992
6993 bool do_mask = (Rvvelt<uint64_t>(rvv_vs1_reg(), midx) >> mpos) & 0x1;
6994 if (do_mask) {
6995 switch (rvv_vsew()) {
6996 case E8:
6997 Rvvelt<uint8_t>(rvv_vd_reg(), pos, true) =
6998 Rvvelt<uint8_t>(rvv_vs2_reg(), i);
6999 break;
7000 case E16:
7001 Rvvelt<uint16_t>(rvv_vd_reg(), pos, true) =
7002 Rvvelt<uint16_t>(rvv_vs2_reg(), i);
7003 break;
7004 case E32:
7005 Rvvelt<uint32_t>(rvv_vd_reg(), pos, true) =
7006 Rvvelt<uint32_t>(rvv_vs2_reg(), i);
7007 break;
7008 default:
7009 Rvvelt<uint64_t>(rvv_vd_reg(), pos, true) =
7010 Rvvelt<uint64_t>(rvv_vs2_reg(), i);
7011 break;
7012 }
7013
7014 ++pos;
7015 }
7016 RVV_VI_LOOP_END;
7017 rvv_trace_vd();
7018 } break;
7019 default:
7021 disasm::NameConverter converter;
7022 disasm::Disassembler dasm(converter);
7023 dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(&instr_));
7024 PrintF("EXECUTING 0x%08" PRIxPTR " %-44s\n",
7025 reinterpret_cast<intptr_t>(&instr_), buffer.begin());
7027 break;
7028 }
7029}
7030
7031void Simulator::DecodeRvvMVX() {
7032 DCHECK_EQ(instr_.InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_MVX);
7033 switch (instr_.InstructionBits() & kVTypeMask) {
7034 case RO_V_VRXUNARY0:
7035 // vmv.s.x
7036 if (instr_.Vs2Value() == 0x0) {
7037 if (rvv_vl() > 0 && rvv_vstart() < rvv_vl()) {
7038 switch (rvv_vsew()) {
7039 case E8:
7040 Rvvelt<uint8_t>(rvv_vd_reg(), 0, true) =
7041 (uint8_t)get_register(rs1_reg());
7042 break;
7043 case E16:
7044 Rvvelt<uint16_t>(rvv_vd_reg(), 0, true) =
7045 (uint16_t)get_register(rs1_reg());
7046 break;
7047 case E32:
7048 Rvvelt<uint32_t>(rvv_vd_reg(), 0, true) =
7049 (uint32_t)get_register(rs1_reg());
7050 break;
7051 case E64:
7052 Rvvelt<uint64_t>(rvv_vd_reg(), 0, true) =
7053 (uint64_t)get_register(rs1_reg());
7054 break;
7055 default:
7056 UNREACHABLE();
7057 }
7058 }
7059 set_rvv_vstart(0);
7060 rvv_trace_vd();
7061 } else {
7063 }
7064 break;
7065 case RO_V_VDIV_VX: {
7066 RVV_VI_VX_LOOP({ vd = vs2 / rs1; })
7067 break;
7068 }
7069 case RO_V_VDIVU_VX: {
7070 RVV_VI_VX_ULOOP({ vd = vs2 / rs1; })
7071 break;
7072 }
7073 case RO_V_VMUL_VX: {
7074 RVV_VI_VX_LOOP({ vd = vs2 * rs1; })
7075 break;
7076 }
7077 case RO_V_VWADDUW_VX: {
7078 RVV_VI_CHECK_DDS(false);
7079 RVV_VI_VX_LOOP_WIDEN({
7080 VI_WIDE_WVX_OP(rs1, +, uint);
7081 USE(vd);
7082 USE(vs2);
7083 })
7084 break;
7085 }
7086 case RO_V_VSLIDE1DOWN_VX: {
7087 RVV_VI_CHECK_SLIDE(false);
7088 RVV_VI_GENERAL_LOOP_BASE
7089 switch (rvv_vsew()) {
7090 case E8: {
7091 VX_SLIDE1DOWN_PARAMS(8, 1);
7092 } break;
7093 case E16: {
7094 VX_SLIDE1DOWN_PARAMS(16, 1);
7095 } break;
7096 case E32: {
7097 VX_SLIDE1DOWN_PARAMS(32, 1);
7098 } break;
7099 default: {
7100 VX_SLIDE1DOWN_PARAMS(64, 1);
7101 } break;
7102 }
7103 RVV_VI_LOOP_END
7104 rvv_trace_vd();
7105 } break;
7106 case RO_V_VSLIDE1UP_VX: {
7107 RVV_VI_CHECK_SLIDE(true);
7108 RVV_VI_GENERAL_LOOP_BASE
7109 if (i < rvv_vstart()) continue;
7110 switch (rvv_vsew()) {
7111 case E8: {
7112 VX_SLIDE1UP_PARAMS(8, 1);
7113 } break;
7114 case E16: {
7115 VX_SLIDE1UP_PARAMS(16, 1);
7116 } break;
7117 case E32: {
7118 VX_SLIDE1UP_PARAMS(32, 1);
7119 } break;
7120 default: {
7121 VX_SLIDE1UP_PARAMS(64, 1);
7122 } break;
7123 }
7124 RVV_VI_LOOP_END
7125 rvv_trace_vd();
7126 } break;
7127 default:
7129 disasm::NameConverter converter;
7130 disasm::Disassembler dasm(converter);
7131 dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(&instr_));
7132 PrintF("EXECUTING 0x%08" PRIxPTR " %-44s\n",
7133 reinterpret_cast<intptr_t>(&instr_), buffer.begin());
7135 break;
7136 }
7137}
7138
7139void Simulator::DecodeRvvFVV() {
7140 DCHECK_EQ(instr_.InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_FVV);
7141 switch (instr_.InstructionBits() & kVTypeMask) {
7142 case RO_V_VFDIV_VV: {
7143 RVV_VI_VFP_VV_LOOP(
7144 { UNIMPLEMENTED(); },
7145 {
7146 // TODO(riscv): use rm value (round mode)
7147 auto fn = [this](float vs1, float vs2) {
7148 if (is_invalid_fdiv(vs1, vs2)) {
7149 this->set_fflags(kInvalidOperation);
7150 return std::numeric_limits<float>::quiet_NaN();
7151 } else if (vs1 == 0.0f) {
7152 this->set_fflags(kDivideByZero);
7153 return (std::signbit(vs1) == std::signbit(vs2)
7154 ? std::numeric_limits<float>::infinity()
7155 : -std::numeric_limits<float>::infinity());
7156 } else {
7157 return vs2 / vs1;
7158 }
7159 };
7160 auto alu_out = fn(vs1, vs2);
7161 // if any input or result is NaN, the result is quiet_NaN
7162 if (std::isnan(alu_out) || std::isnan(vs1) || std::isnan(vs2)) {
7163 // signaling_nan sets kInvalidOperation bit
7164 if (isSnan(alu_out) || isSnan(vs1) || isSnan(vs2))
7165 set_fflags(kInvalidOperation);
7166 alu_out = std::numeric_limits<float>::quiet_NaN();
7167 }
7168 vd = alu_out;
7169 },
7170 {
7171 // TODO(riscv): use rm value (round mode)
7172 auto fn = [this](double vs1, double vs2) {
7173 if (is_invalid_fdiv(vs1, vs2)) {
7174 this->set_fflags(kInvalidOperation);
7175 return std::numeric_limits<double>::quiet_NaN();
7176 } else if (vs1 == 0.0f) {
7177 this->set_fflags(kDivideByZero);
7178 return (std::signbit(vs1) == std::signbit(vs2)
7179 ? std::numeric_limits<double>::infinity()
7180 : -std::numeric_limits<double>::infinity());
7181 } else {
7182 return vs2 / vs1;
7183 }
7184 };
7185 auto alu_out = fn(vs1, vs2);
7186 // if any input or result is NaN, the result is quiet_NaN
7187 if (std::isnan(alu_out) || std::isnan(vs1) || std::isnan(vs2)) {
7188 // signaling_nan sets kInvalidOperation bit
7189 if (isSnan(alu_out) || isSnan(vs1) || isSnan(vs2))
7190 set_fflags(kInvalidOperation);
7191 alu_out = std::numeric_limits<double>::quiet_NaN();
7192 }
7193 vd = alu_out;
7194 })
7195 break;
7196 }
7197 case RO_V_VFMUL_VV: {
7198 RVV_VI_VFP_VV_LOOP(
7199 { UNIMPLEMENTED(); },
7200 {
7201 // TODO(riscv): use rm value (round mode)
7202 auto fn = [this](double drs1, double drs2) {
7203 if (is_invalid_fmul(drs1, drs2)) {
7204 this->set_fflags(kInvalidOperation);
7205 return std::numeric_limits<double>::quiet_NaN();
7206 } else {
7207 return drs1 * drs2;
7208 }
7209 };
7210 auto alu_out = fn(vs1, vs2);
7211 // if any input or result is NaN, the result is quiet_NaN
7212 if (std::isnan(alu_out) || std::isnan(vs1) || std::isnan(vs2)) {
7213 // signaling_nan sets kInvalidOperation bit
7214 if (isSnan(alu_out) || isSnan(vs1) || isSnan(vs2))
7215 set_fflags(kInvalidOperation);
7216 alu_out = std::numeric_limits<float>::quiet_NaN();
7217 }
7218 vd = alu_out;
7219 },
7220 {
7221 // TODO(riscv): use rm value (round mode)
7222 auto fn = [this](double drs1, double drs2) {
7223 if (is_invalid_fmul(drs1, drs2)) {
7224 this->set_fflags(kInvalidOperation);
7225 return std::numeric_limits<double>::quiet_NaN();
7226 } else {
7227 return drs1 * drs2;
7228 }
7229 };
7230 auto alu_out = fn(vs1, vs2);
7231 // if any input or result is NaN, the result is quiet_NaN
7232 if (std::isnan(alu_out) || std::isnan(vs1) || std::isnan(vs2)) {
7233 // signaling_nan sets kInvalidOperation bit
7234 if (isSnan(alu_out) || isSnan(vs1) || isSnan(vs2))
7235 set_fflags(kInvalidOperation);
7236 alu_out = std::numeric_limits<double>::quiet_NaN();
7237 }
7238 vd = alu_out;
7239 })
7240 break;
7241 }
7242 case RO_V_VFUNARY0:
7243 switch (instr_.Vs1Value()) {
7244 case VFCVT_X_F_V:
7245 RVV_VI_VFP_VF_LOOP(
7246 { UNIMPLEMENTED(); },
7247 {
7248 Rvvelt<int32_t>(rvv_vd_reg(), i) =
7249 RoundF2IHelper<int32_t>(vs2, read_csr_value(csr_frm));
7250 USE(vd);
7251 USE(fs1);
7252 },
7253 {
7254 Rvvelt<int64_t>(rvv_vd_reg(), i) =
7255 RoundF2IHelper<int64_t>(vs2, read_csr_value(csr_frm));
7256 USE(vd);
7257 USE(fs1);
7258 })
7259 break;
7260 case VFCVT_XU_F_V:
7261 RVV_VI_VFP_VF_LOOP(
7262 { UNIMPLEMENTED(); },
7263 {
7264 Rvvelt<uint32_t>(rvv_vd_reg(), i) =
7265 RoundF2IHelper<uint32_t>(vs2, read_csr_value(csr_frm));
7266 USE(vd);
7267 USE(fs1);
7268 },
7269 {
7270 Rvvelt<uint64_t>(rvv_vd_reg(), i) =
7271 RoundF2IHelper<uint64_t>(vs2, read_csr_value(csr_frm));
7272 USE(vd);
7273 USE(fs1);
7274 })
7275 break;
7276 case VFCVT_F_XU_V:
7277 RVV_VI_VFP_VF_LOOP({ UNIMPLEMENTED(); },
7278 {
7279 auto vs2_i = Rvvelt<uint32_t>(rvv_vs2_reg(), i);
7280 vd = static_cast<float>(vs2_i);
7281 USE(vs2);
7282 USE(fs1);
7283 },
7284 {
7285 auto vs2_i = Rvvelt<uint64_t>(rvv_vs2_reg(), i);
7286 vd = static_cast<double>(vs2_i);
7287 USE(vs2);
7288 USE(fs1);
7289 })
7290 break;
7291 case VFCVT_F_X_V:
7292 RVV_VI_VFP_VF_LOOP({ UNIMPLEMENTED(); },
7293 {
7294 auto vs2_i = Rvvelt<int32_t>(rvv_vs2_reg(), i);
7295 vd = static_cast<float>(vs2_i);
7296 USE(vs2);
7297 USE(fs1);
7298 },
7299 {
7300 auto vs2_i = Rvvelt<int64_t>(rvv_vs2_reg(), i);
7301 vd = static_cast<double>(vs2_i);
7302 USE(vs2);
7303 USE(fs1);
7304 })
7305 break;
7306 case VFNCVT_F_F_W:
7307 RVV_VI_VFP_CVT_SCALE(
7308 { UNREACHABLE(); }, { UNREACHABLE(); },
7309 {
7310 auto vs2 = Rvvelt<double>(rvv_vs2_reg(), i);
7311 Rvvelt<float>(rvv_vd_reg(), i, true) =
7312 CanonicalizeDoubleToFloatOperation(
7313 [](double drs) { return static_cast<float>(drs); },
7314 vs2);
7315 },
7316 { ; }, { ; }, { ; }, false, (rvv_vsew() >= E16))
7317 break;
7318 case VFNCVT_X_F_W:
7319 RVV_VI_VFP_CVT_SCALE(
7320 { UNREACHABLE(); }, { UNREACHABLE(); },
7321 {
7322 auto vs2 = Rvvelt<double>(rvv_vs2_reg(), i);
7323 int32_t& vd = Rvvelt<int32_t>(rvv_vd_reg(), i, true);
7324 vd = RoundF2IHelper<int32_t>(vs2, read_csr_value(csr_frm));
7325 },
7326 { ; }, { ; }, { ; }, false, (rvv_vsew() <= E32))
7327 break;
7328 case VFNCVT_XU_F_W:
7329 RVV_VI_VFP_CVT_SCALE(
7330 { UNREACHABLE(); }, { UNREACHABLE(); },
7331 {
7332 auto vs2 = Rvvelt<double>(rvv_vs2_reg(), i);
7333 uint32_t& vd = Rvvelt<uint32_t>(rvv_vd_reg(), i, true);
7334 vd = RoundF2IHelper<uint32_t>(vs2, read_csr_value(csr_frm));
7335 },
7336 { ; }, { ; }, { ; }, false, (rvv_vsew() <= E32))
7337 break;
7338 case VFWCVT_F_X_V:
7339 RVV_VI_VFP_CVT_SCALE({ UNREACHABLE(); },
7340 {
7341 auto vs2 = Rvvelt<int16_t>(rvv_vs2_reg(), i);
7342 Rvvelt<float32_t>(rvv_vd_reg(), i, true) =
7343 static_cast<float>(vs2);
7344 },
7345 {
7346 auto vs2 = Rvvelt<int32_t>(rvv_vs2_reg(), i);
7347 Rvvelt<double>(rvv_vd_reg(), i, true) =
7348 static_cast<double>(vs2);
7349 },
7350 { ; }, { ; }, { ; }, true, (rvv_vsew() >= E8))
7351 break;
7352 case VFWCVT_F_XU_V:
7353 RVV_VI_VFP_CVT_SCALE({ UNREACHABLE(); },
7354 {
7355 auto vs2 = Rvvelt<uint16_t>(rvv_vs2_reg(), i);
7356 Rvvelt<float32_t>(rvv_vd_reg(), i, true) =
7357 static_cast<float>(vs2);
7358 },
7359 {
7360 auto vs2 = Rvvelt<uint32_t>(rvv_vs2_reg(), i);
7361 Rvvelt<double>(rvv_vd_reg(), i, true) =
7362 static_cast<double>(vs2);
7363 },
7364 { ; }, { ; }, { ; }, true, (rvv_vsew() >= E8))
7365 break;
7366 case VFWCVT_XU_F_V:
7367 RVV_VI_VFP_CVT_SCALE({ UNREACHABLE(); }, { UNREACHABLE(); },
7368 {
7369 auto vs2 = Rvvelt<float32_t>(rvv_vs2_reg(), i);
7370 Rvvelt<uint64_t>(rvv_vd_reg(), i, true) =
7371 static_cast<uint64_t>(vs2);
7372 },
7373 { ; }, { ; }, { ; }, true, (rvv_vsew() >= E16))
7374 break;
7375 case VFWCVT_X_F_V:
7376 RVV_VI_VFP_CVT_SCALE({ UNREACHABLE(); }, { UNREACHABLE(); },
7377 {
7378 auto vs2 = Rvvelt<float32_t>(rvv_vs2_reg(), i);
7379 Rvvelt<int64_t>(rvv_vd_reg(), i, true) =
7380 static_cast<int64_t>(vs2);
7381 },
7382 { ; }, { ; }, { ; }, true, (rvv_vsew() >= E16))
7383 break;
7384 case VFWCVT_F_F_V:
7385 RVV_VI_VFP_CVT_SCALE({ UNREACHABLE(); }, { UNREACHABLE(); },
7386 {
7387 auto vs2 = Rvvelt<float32_t>(rvv_vs2_reg(), i);
7388 Rvvelt<double>(rvv_vd_reg(), i, true) =
7389 static_cast<double>(vs2);
7390 },
7391 { ; }, { ; }, { ; }, true, (rvv_vsew() >= E16))
7392 break;
7393 default:
7395 }
7396 break;
7397 case RO_V_VFUNARY1:
7398 switch (instr_.Vs1Value()) {
7399 case VFCLASS_V:
7400 RVV_VI_VFP_VF_LOOP(
7401 { UNIMPLEMENTED(); },
7402 {
7403 int32_t& vd_i = Rvvelt<int32_t>(rvv_vd_reg(), i, true);
7404 vd_i = int32_t(FclassHelper(vs2));
7405 USE(fs1);
7406 USE(vd);
7407 },
7408 {
7409 int64_t& vd_i = Rvvelt<int64_t>(rvv_vd_reg(), i, true);
7410 vd_i = FclassHelper(vs2);
7411 USE(fs1);
7412 USE(vd);
7413 })
7414 break;
7415 case VFSQRT_V:
7416 RVV_VI_VFP_VF_LOOP({ UNIMPLEMENTED(); },
7417 {
7418 vd = std::sqrt(vs2);
7419 USE(fs1);
7420 },
7421 {
7422 vd = std::sqrt(vs2);
7423 USE(fs1);
7424 })
7425 break;
7426 case VFRSQRT7_V:
7427 RVV_VI_VFP_VF_LOOP(
7428 {},
7429 {
7430 vd = base::RecipSqrt(vs2);
7431 USE(fs1);
7432 },
7433 {
7434 vd = base::RecipSqrt(vs2);
7435 USE(fs1);
7436 })
7437 break;
7438 case VFREC7_V:
7439 RVV_VI_VFP_VF_LOOP(
7440 {},
7441 {
7442 vd = base::Recip(vs2);
7443 USE(fs1);
7444 },
7445 {
7446 vd = base::Recip(vs2);
7447 USE(fs1);
7448 })
7449 break;
7450 default:
7451 break;
7452 }
7453 break;
7454 case RO_V_VMFEQ_VV: {
7455 RVV_VI_VFP_LOOP_CMP({ UNIMPLEMENTED(); },
7456 { res = CompareFHelper(vs2, vs1, EQ); },
7457 { res = CompareFHelper(vs2, vs1, EQ); }, true)
7458 } break;
7459 case RO_V_VMFNE_VV: {
7460 RVV_VI_VFP_LOOP_CMP({ UNIMPLEMENTED(); },
7461 { res = CompareFHelper(vs2, vs1, NE); },
7462 { res = CompareFHelper(vs2, vs1, NE); }, true)
7463 } break;
7464 case RO_V_VMFLT_VV: {
7465 RVV_VI_VFP_LOOP_CMP({ UNIMPLEMENTED(); },
7466 { res = CompareFHelper(vs2, vs1, LT); },
7467 { res = CompareFHelper(vs2, vs1, LT); }, true)
7468 } break;
7469 case RO_V_VMFLE_VV: {
7470 RVV_VI_VFP_LOOP_CMP({ UNIMPLEMENTED(); },
7471 { res = CompareFHelper(vs2, vs1, LE); },
7472 { res = CompareFHelper(vs2, vs1, LE); }, true)
7473 } break;
7474 case RO_V_VFMAX_VV: {
7475 RVV_VI_VFP_VV_LOOP({ UNIMPLEMENTED(); },
7476 { vd = FMaxMinHelper(vs2, vs1, MaxMinKind::kMax); },
7477 { vd = FMaxMinHelper(vs2, vs1, MaxMinKind::kMax); })
7478 break;
7479 }
7480 case RO_V_VFREDMAX_VV: {
7481 RVV_VI_VFP_VV_LOOP_REDUCTION(
7482 { UNIMPLEMENTED(); },
7483 { vd_0 = FMaxMinHelper(vd_0, vs2, MaxMinKind::kMax); },
7484 { vd_0 = FMaxMinHelper(vd_0, vs2, MaxMinKind::kMax); })
7485 break;
7486 }
7487 case RO_V_VFMIN_VV: {
7488 RVV_VI_VFP_VV_LOOP({ UNIMPLEMENTED(); },
7489 { vd = FMaxMinHelper(vs2, vs1, MaxMinKind::kMin); },
7490 { vd = FMaxMinHelper(vs2, vs1, MaxMinKind::kMin); })
7491 break;
7492 }
7493 case RO_V_VFSGNJ_VV:
7494 RVV_VFSGNJ_VV_VF_LOOP({ UNIMPLEMENTED(); },
7495 {
7496 vd = fsgnj32(Float32::FromBits(vs2),
7497 Float32::FromBits(vs1), false, false)
7498 .get_bits();
7499 USE(fs1);
7500 },
7501 {
7502 vd = fsgnj64(Float64::FromBits(vs2),
7503 Float64::FromBits(vs1), false, false)
7504 .get_bits();
7505 USE(fs1);
7506 })
7507 break;
7508 case RO_V_VFSGNJN_VV:
7509 RVV_VFSGNJ_VV_VF_LOOP({ UNIMPLEMENTED(); },
7510 {
7511 vd = fsgnj32(Float32::FromBits(vs2),
7512 Float32::FromBits(vs1), true, false)
7513 .get_bits();
7514 USE(fs1);
7515 },
7516 {
7517 vd = fsgnj64(Float64::FromBits(vs2),
7518 Float64::FromBits(vs1), true, false)
7519 .get_bits();
7520 USE(fs1);
7521 })
7522 break;
7523 case RO_V_VFSGNJX_VV:
7524 RVV_VFSGNJ_VV_VF_LOOP({ UNIMPLEMENTED(); },
7525 {
7526 vd = fsgnj32(Float32::FromBits(vs2),
7527 Float32::FromBits(vs1), false, true)
7528 .get_bits();
7529 USE(fs1);
7530 },
7531 {
7532 vd = fsgnj64(Float64::FromBits(vs2),
7533 Float64::FromBits(vs1), false, true)
7534 .get_bits();
7535 USE(fs1);
7536 })
7537 break;
7538 case RO_V_VFADD_VV:
7539 RVV_VI_VFP_VV_LOOP(
7540 { UNIMPLEMENTED(); },
7541 {
7542 auto fn = [this](float frs1, float frs2) {
7543 if (is_invalid_fadd(frs1, frs2)) {
7544 this->set_fflags(kInvalidOperation);
7545 return std::numeric_limits<float>::quiet_NaN();
7546 } else {
7547 return frs1 + frs2;
7548 }
7549 };
7550 auto alu_out = fn(vs1, vs2);
7551 // if any input or result is NaN, the result is quiet_NaN
7552 if (std::isnan(alu_out) || std::isnan(vs1) || std::isnan(vs2)) {
7553 // signaling_nan sets kInvalidOperation bit
7554 if (isSnan(alu_out) || isSnan(vs1) || isSnan(vs2))
7555 set_fflags(kInvalidOperation);
7556 alu_out = std::numeric_limits<float>::quiet_NaN();
7557 }
7558 vd = alu_out;
7559 },
7560 {
7561 auto fn = [this](double frs1, double frs2) {
7562 if (is_invalid_fadd(frs1, frs2)) {
7563 this->set_fflags(kInvalidOperation);
7564 return std::numeric_limits<double>::quiet_NaN();
7565 } else {
7566 return frs1 + frs2;
7567 }
7568 };
7569 auto alu_out = fn(vs1, vs2);
7570 // if any input or result is NaN, the result is quiet_NaN
7571 if (std::isnan(alu_out) || std::isnan(vs1) || std::isnan(vs2)) {
7572 // signaling_nan sets kInvalidOperation bit
7573 if (isSnan(alu_out) || isSnan(vs1) || isSnan(vs2))
7574 set_fflags(kInvalidOperation);
7575 alu_out = std::numeric_limits<double>::quiet_NaN();
7576 }
7577 vd = alu_out;
7578 })
7579 break;
7580 case RO_V_VFSUB_VV:
7581 RVV_VI_VFP_VV_LOOP(
7582 { UNIMPLEMENTED(); },
7583 {
7584 auto fn = [this](float frs1, float frs2) {
7585 if (is_invalid_fsub(frs1, frs2)) {
7586 this->set_fflags(kInvalidOperation);
7587 return std::numeric_limits<float>::quiet_NaN();
7588 } else {
7589 return frs2 - frs1;
7590 }
7591 };
7592 auto alu_out = fn(vs1, vs2);
7593 // if any input or result is NaN, the result is quiet_NaN
7594 if (std::isnan(alu_out) || std::isnan(vs1) || std::isnan(vs2)) {
7595 // signaling_nan sets kInvalidOperation bit
7596 if (isSnan(alu_out) || isSnan(vs1) || isSnan(vs2))
7597 set_fflags(kInvalidOperation);
7598 alu_out = std::numeric_limits<float>::quiet_NaN();
7599 }
7600
7601 vd = alu_out;
7602 },
7603 {
7604 auto fn = [this](double frs1, double frs2) {
7605 if (is_invalid_fsub(frs1, frs2)) {
7606 this->set_fflags(kInvalidOperation);
7607 return std::numeric_limits<double>::quiet_NaN();
7608 } else {
7609 return frs2 - frs1;
7610 }
7611 };
7612 auto alu_out = fn(vs1, vs2);
7613 // if any input or result is NaN, the result is quiet_NaN
7614 if (std::isnan(alu_out) || std::isnan(vs1) || std::isnan(vs2)) {
7615 // signaling_nan sets kInvalidOperation bit
7616 if (isSnan(alu_out) || isSnan(vs1) || isSnan(vs2))
7617 set_fflags(kInvalidOperation);
7618 alu_out = std::numeric_limits<double>::quiet_NaN();
7619 }
7620 vd = alu_out;
7621 })
7622 break;
7623 case RO_V_VFWADD_VV:
7624 RVV_VI_CHECK_DSS(true);
7625 RVV_VI_VFP_VV_LOOP_WIDEN(
7626 {
7627 RVV_VI_VFP_VV_ARITH_CHECK_COMPUTE(double, is_invalid_fadd, +);
7628 USE(vs3);
7629 },
7630 false)
7631 break;
7632 case RO_V_VFWSUB_VV:
7633 RVV_VI_CHECK_DSS(true);
7634 RVV_VI_VFP_VV_LOOP_WIDEN(
7635 {
7636 RVV_VI_VFP_VV_ARITH_CHECK_COMPUTE(double, is_invalid_fsub, -);
7637 USE(vs3);
7638 },
7639 false)
7640 break;
7641 case RO_V_VFWADD_W_VV:
7642 RVV_VI_CHECK_DSS(true);
7643 RVV_VI_VFP_VV_LOOP_WIDEN(
7644 {
7645 RVV_VI_VFP_VV_ARITH_CHECK_COMPUTE(double, is_invalid_fadd, +);
7646 USE(vs3);
7647 },
7648 true)
7649 break;
7650 case RO_V_VFWSUB_W_VV:
7651 RVV_VI_CHECK_DSS(true);
7652 RVV_VI_VFP_VV_LOOP_WIDEN(
7653 {
7654 RVV_VI_VFP_VV_ARITH_CHECK_COMPUTE(double, is_invalid_fsub, -);
7655 USE(vs3);
7656 },
7657 true)
7658 break;
7659 case RO_V_VFWMUL_VV:
7660 RVV_VI_CHECK_DSS(true);
7661 RVV_VI_VFP_VV_LOOP_WIDEN(
7662 {
7663 RVV_VI_VFP_VV_ARITH_CHECK_COMPUTE(double, is_invalid_fmul, *);
7664 USE(vs3);
7665 },
7666 false)
7667 break;
7668 case RO_V_VFWREDUSUM_VS:
7669 case RO_V_VFWREDOSUM_VS:
7670 RVV_VI_CHECK_DSS(true);
7671 switch (rvv_vsew()) {
7672 case E16:
7673 case E64: {
7674 UNIMPLEMENTED();
7675 }
7676 case E32: {
7677 double& vd = Rvvelt<double>(rvv_vd_reg(), 0, true);
7678 double vs1 = Rvvelt<double>(rvv_vs1_reg(), 0);
7679 double alu_out = vs1;
7680 for (uint64_t i = rvv_vstart(); i < rvv_vl(); ++i) {
7681 double vs2 = static_cast<double>(Rvvelt<float>(rvv_vs2_reg(), i));
7682 if (is_invalid_fadd(alu_out, vs2)) {
7683 set_fflags(kInvalidOperation);
7684 alu_out = std::numeric_limits<float>::quiet_NaN();
7685 break;
7686 }
7687 alu_out = alu_out + vs2;
7688 if (std::isnan(alu_out) || std::isnan(vs2)) {
7689 // signaling_nan sets kInvalidOperation bit
7690 if (isSnan(alu_out) || isSnan(vs2)) set_fflags(kInvalidOperation);
7691 alu_out = std::numeric_limits<float>::quiet_NaN();
7692 break;
7693 }
7694 }
7695 vd = alu_out;
7696 break;
7697 }
7698 default:
7699 require(false);
7700 break;
7701 }
7702 rvv_trace_vd();
7703 break;
7704 case RO_V_VFMADD_VV:
7705 RVV_VI_VFP_FMA_VV_LOOP({RVV_VI_VFP_FMA(float, vd, vs1, vs2)},
7706 {RVV_VI_VFP_FMA(double, vd, vs1, vs2)})
7707 break;
7708 case RO_V_VFNMADD_VV:
7709 RVV_VI_VFP_FMA_VV_LOOP({RVV_VI_VFP_FMA(float, -vd, vs1, -vs2)},
7710 {RVV_VI_VFP_FMA(double, -vd, vs1, -vs2)})
7711 break;
7712 case RO_V_VFMSUB_VV:
7713 RVV_VI_VFP_FMA_VV_LOOP({RVV_VI_VFP_FMA(float, vd, vs1, -vs2)},
7714 {RVV_VI_VFP_FMA(double, vd, vs1, -vs2)})
7715 break;
7716 case RO_V_VFNMSUB_VV:
7717 RVV_VI_VFP_FMA_VV_LOOP({RVV_VI_VFP_FMA(float, -vd, vs1, +vs2)},
7718 {RVV_VI_VFP_FMA(double, -vd, vs1, +vs2)})
7719 break;
7720 case RO_V_VFMACC_VV:
7721 RVV_VI_VFP_FMA_VV_LOOP({RVV_VI_VFP_FMA(float, vs2, vs1, vd)},
7722 {RVV_VI_VFP_FMA(double, vs2, vs1, vd)})
7723 break;
7724 case RO_V_VFNMACC_VV:
7725 RVV_VI_VFP_FMA_VV_LOOP({RVV_VI_VFP_FMA(float, -vs2, vs1, -vd)},
7726 {RVV_VI_VFP_FMA(double, -vs2, vs1, -vd)})
7727 break;
7728 case RO_V_VFMSAC_VV:
7729 RVV_VI_VFP_FMA_VV_LOOP({RVV_VI_VFP_FMA(float, vs2, vs1, -vd)},
7730 {RVV_VI_VFP_FMA(double, vs2, vs1, -vd)})
7731 break;
7732 case RO_V_VFNMSAC_VV:
7733 RVV_VI_VFP_FMA_VV_LOOP({RVV_VI_VFP_FMA(float, -vs2, vs1, +vd)},
7734 {RVV_VI_VFP_FMA(double, -vs2, vs1, +vd)})
7735 break;
7736 case RO_V_VFWMACC_VV:
7737 RVV_VI_CHECK_DSS(true);
7738 RVV_VI_VFP_VV_LOOP_WIDEN({RVV_VI_VFP_FMA(double, vs2, vs1, vs3)}, false)
7739 break;
7740 case RO_V_VFWNMACC_VV:
7741 RVV_VI_CHECK_DSS(true);
7742 RVV_VI_VFP_VV_LOOP_WIDEN({RVV_VI_VFP_FMA(double, -vs2, vs1, -vs3)}, false)
7743 break;
7744 case RO_V_VFWMSAC_VV:
7745 RVV_VI_CHECK_DSS(true);
7746 RVV_VI_VFP_VV_LOOP_WIDEN({RVV_VI_VFP_FMA(double, vs2, vs1, -vs3)}, false)
7747 break;
7748 case RO_V_VFWNMSAC_VV:
7749 RVV_VI_CHECK_DSS(true);
7750 RVV_VI_VFP_VV_LOOP_WIDEN({RVV_VI_VFP_FMA(double, -vs2, vs1, +vs3)}, false)
7751 break;
7752 case RO_V_VFMV_FS:
7753 switch (rvv_vsew()) {
7754 case E16: {
7755 UNIMPLEMENTED();
7756 }
7757 case E32: {
7758 uint32_t fs2 = Rvvelt<uint32_t>(rvv_vs2_reg(), 0);
7759 set_frd(Float32::FromBits(fs2));
7760 break;
7761 }
7762 case E64: {
7763 uint64_t fs2 = Rvvelt<uint64_t>(rvv_vs2_reg(), 0);
7764 set_drd(Float64::FromBits(fs2));
7765 break;
7766 }
7767 default:
7768 require(0);
7769 break;
7770 }
7771 break;
7772 default:
7774 }
7775}
7776
7777void Simulator::DecodeRvvFVF() {
7778 DCHECK_EQ(instr_.InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_FVF);
7779 switch (instr_.InstructionBits() & kVTypeMask) {
7780 case RO_V_VFSGNJ_VF:
7781 RVV_VFSGNJ_VV_VF_LOOP(
7782 {},
7783 {
7784 vd = fsgnj32(Float32::FromBits(vs2), fs1, false, false).get_bits();
7785 USE(vs1);
7786 },
7787 {
7788 vd = fsgnj64(Float64::FromBits(vs2), fs1, false, false).get_bits();
7789 USE(vs1);
7790 })
7791 break;
7792 case RO_V_VFSGNJN_VF:
7793 RVV_VFSGNJ_VV_VF_LOOP(
7794 {},
7795 {
7796 vd = fsgnj32(Float32::FromBits(vs2), fs1, true, false).get_bits();
7797 USE(vs1);
7798 },
7799 {
7800 vd = fsgnj64(Float64::FromBits(vs2), fs1, true, false).get_bits();
7801 USE(vs1);
7802 })
7803 break;
7804 case RO_V_VFSGNJX_VF:
7805 RVV_VFSGNJ_VV_VF_LOOP(
7806 {},
7807 {
7808 vd = fsgnj32(Float32::FromBits(vs2), fs1, false, true).get_bits();
7809 USE(vs1);
7810 },
7811 {
7812 vd = fsgnj64(Float64::FromBits(vs2), fs1, false, true).get_bits();
7813 USE(vs1);
7814 })
7815 break;
7816 case RO_V_VFMV_VF:
7817 if (instr_.RvvVM()) {
7818 RVV_VI_VF_MERGE_LOOP(
7819 {},
7820 {
7821 vd = fs1;
7822 USE(vs2);
7823 },
7824 {
7825 vd = fs1;
7826 USE(vs2);
7827 });
7828 } else {
7829 RVV_VI_VF_MERGE_LOOP(
7830 {},
7831 {
7832 bool use_first =
7833 (Rvvelt<uint64_t>(0, (i / 64)) >> (i % 64)) & 0x1;
7834 vd = use_first ? fs1 : vs2;
7835 },
7836 {
7837 bool use_first =
7838 (Rvvelt<uint64_t>(0, (i / 64)) >> (i % 64)) & 0x1;
7839 vd = use_first ? fs1 : vs2;
7840 });
7841 }
7842 break;
7843 case RO_V_VFADD_VF:
7844 RVV_VI_VFP_VF_LOOP(
7845 { UNIMPLEMENTED(); },
7846 {
7847 auto fn = [this](float frs1, float frs2) {
7848 if (is_invalid_fadd(frs1, frs2)) {
7849 this->set_fflags(kInvalidOperation);
7850 return std::numeric_limits<float>::quiet_NaN();
7851 } else {
7852 return frs1 + frs2;
7853 }
7854 };
7855 auto alu_out = fn(fs1, vs2);
7856 // if any input or result is NaN, the result is quiet_NaN
7857 if (std::isnan(alu_out) || std::isnan(fs1) || std::isnan(vs2)) {
7858 // signaling_nan sets kInvalidOperation bit
7859 if (isSnan(alu_out) || isSnan(fs1) || isSnan(vs2))
7860 set_fflags(kInvalidOperation);
7861 alu_out = std::numeric_limits<float>::quiet_NaN();
7862 }
7863 vd = alu_out;
7864 },
7865 {
7866 auto fn = [this](double frs1, double frs2) {
7867 if (is_invalid_fadd(frs1, frs2)) {
7868 this->set_fflags(kInvalidOperation);
7869 return std::numeric_limits<double>::quiet_NaN();
7870 } else {
7871 return frs1 + frs2;
7872 }
7873 };
7874 auto alu_out = fn(fs1, vs2);
7875 // if any input or result is NaN, the result is quiet_NaN
7876 if (std::isnan(alu_out) || std::isnan(fs1) || std::isnan(vs2)) {
7877 // signaling_nan sets kInvalidOperation bit
7878 if (isSnan(alu_out) || isSnan(fs1) || isSnan(vs2))
7879 set_fflags(kInvalidOperation);
7880 alu_out = std::numeric_limits<double>::quiet_NaN();
7881 }
7882 vd = alu_out;
7883 })
7884 break;
7885 case RO_V_VFWADD_VF:
7886 RVV_VI_CHECK_DSS(true);
7887 RVV_VI_VFP_VF_LOOP_WIDEN(
7888 {
7889 RVV_VI_VFP_VF_ARITH_CHECK_COMPUTE(double, is_invalid_fadd, +);
7890 USE(vs3);
7891 },
7892 false)
7893 break;
7894 case RO_V_VFWSUB_VF:
7895 RVV_VI_CHECK_DSS(true);
7896 RVV_VI_VFP_VF_LOOP_WIDEN(
7897 {
7898 RVV_VI_VFP_VF_ARITH_CHECK_COMPUTE(double, is_invalid_fsub, -);
7899 USE(vs3);
7900 },
7901 false)
7902 break;
7903 case RO_V_VFWADD_W_VF:
7904 RVV_VI_CHECK_DSS(true);
7905 RVV_VI_VFP_VF_LOOP_WIDEN(
7906 {
7907 RVV_VI_VFP_VF_ARITH_CHECK_COMPUTE(double, is_invalid_fadd, +);
7908 USE(vs3);
7909 },
7910 true)
7911 break;
7912 case RO_V_VFWSUB_W_VF:
7913 RVV_VI_CHECK_DSS(true);
7914 RVV_VI_VFP_VF_LOOP_WIDEN(
7915 {
7916 RVV_VI_VFP_VF_ARITH_CHECK_COMPUTE(double, is_invalid_fsub, -);
7917 USE(vs3);
7918 },
7919 true)
7920 break;
7921 case RO_V_VFWMUL_VF:
7922 RVV_VI_CHECK_DSS(true);
7923 RVV_VI_VFP_VF_LOOP_WIDEN(
7924 {
7925 RVV_VI_VFP_VF_ARITH_CHECK_COMPUTE(double, is_invalid_fmul, *);
7926 USE(vs3);
7927 },
7928 false)
7929 break;
7930 case RO_V_VFMADD_VF:
7931 RVV_VI_VFP_FMA_VF_LOOP({RVV_VI_VFP_FMA(float, vd, fs1, vs2)},
7932 {RVV_VI_VFP_FMA(double, vd, fs1, vs2)})
7933 break;
7934 case RO_V_VFNMADD_VF:
7935 RVV_VI_VFP_FMA_VF_LOOP({RVV_VI_VFP_FMA(float, -vd, fs1, -vs2)},
7936 {RVV_VI_VFP_FMA(double, -vd, fs1, -vs2)})
7937 break;
7938 case RO_V_VFMSUB_VF:
7939 RVV_VI_VFP_FMA_VF_LOOP({RVV_VI_VFP_FMA(float, vd, fs1, -vs2)},
7940 {RVV_VI_VFP_FMA(double, vd, fs1, -vs2)})
7941 break;
7942 case RO_V_VFNMSUB_VF:
7943 RVV_VI_VFP_FMA_VF_LOOP({RVV_VI_VFP_FMA(float, -vd, fs1, vs2)},
7944 {RVV_VI_VFP_FMA(double, -vd, fs1, vs2)})
7945 break;
7946 case RO_V_VFMACC_VF:
7947 RVV_VI_VFP_FMA_VF_LOOP({RVV_VI_VFP_FMA(float, vs2, fs1, vd)},
7948 {RVV_VI_VFP_FMA(double, vs2, fs1, vd)})
7949 break;
7950 case RO_V_VFNMACC_VF:
7951 RVV_VI_VFP_FMA_VF_LOOP({RVV_VI_VFP_FMA(float, -vs2, fs1, -vd)},
7952 {RVV_VI_VFP_FMA(double, -vs2, fs1, -vd)})
7953 break;
7954 case RO_V_VFMSAC_VF:
7955 RVV_VI_VFP_FMA_VF_LOOP({RVV_VI_VFP_FMA(float, vs2, fs1, -vd)},
7956 {RVV_VI_VFP_FMA(double, vs2, fs1, -vd)})
7957 break;
7958 case RO_V_VFNMSAC_VF:
7959 RVV_VI_VFP_FMA_VF_LOOP({RVV_VI_VFP_FMA(float, -vs2, fs1, vd)},
7960 {RVV_VI_VFP_FMA(double, -vs2, fs1, vd)})
7961 break;
7962 case RO_V_VFWMACC_VF:
7963 RVV_VI_CHECK_DSS(true);
7964 RVV_VI_VFP_VF_LOOP_WIDEN({RVV_VI_VFP_FMA(double, vs2, fs1, vs3)}, false)
7965 break;
7966 case RO_V_VFWNMACC_VF:
7967 RVV_VI_CHECK_DSS(true);
7968 RVV_VI_VFP_VF_LOOP_WIDEN({RVV_VI_VFP_FMA(double, -vs2, fs1, -vs3)}, false)
7969 break;
7970 case RO_V_VFWMSAC_VF:
7971 RVV_VI_CHECK_DSS(true);
7972 RVV_VI_VFP_VF_LOOP_WIDEN({RVV_VI_VFP_FMA(double, vs2, fs1, -vs3)}, false)
7973 break;
7974 case RO_V_VFWNMSAC_VF:
7975 RVV_VI_CHECK_DSS(true);
7976 RVV_VI_VFP_VF_LOOP_WIDEN({RVV_VI_VFP_FMA(double, -vs2, fs1, vs3)}, false)
7977 break;
7978 case RO_V_VFMV_SF: {
7979 if (instr_.Vs2Value() == 0x0) {
7980 if (rvv_vl() > 0 && rvv_vstart() < rvv_vl()) {
7981 switch (rvv_vsew()) {
7982 case E8:
7983 UNREACHABLE();
7984 case E16:
7985 UNREACHABLE();
7986 case E32:
7987 Rvvelt<uint32_t>(rvv_vd_reg(), 0, true) =
7988 (uint32_t)(get_fpu_register_Float32(rs1_reg()).get_bits());
7989 break;
7990 case E64:
7991 Rvvelt<uint64_t>(rvv_vd_reg(), 0, true) =
7992 (uint64_t)(get_fpu_register_Float64(rs1_reg()).get_bits());
7993 break;
7994 default:
7995 UNREACHABLE();
7996 }
7997 }
7998 set_rvv_vstart(0);
7999 rvv_trace_vd();
8000 } else {
8002 }
8003 } break;
8004 case RO_V_VFSLIDE1DOWN_VF: {
8005 RVV_VI_CHECK_SLIDE(false);
8006 RVV_VI_GENERAL_LOOP_BASE
8007 switch (rvv_vsew()) {
8008 case E8: {
8009 UNSUPPORTED();
8010 }
8011 case E16: {
8012 UNSUPPORTED();
8013 }
8014 case E32: {
8015 VF_SLIDE1DOWN_PARAMS(32, 1);
8016 } break;
8017 default: {
8018 VF_SLIDE1DOWN_PARAMS(64, 1);
8019 } break;
8020 }
8021 RVV_VI_LOOP_END
8022 rvv_trace_vd();
8023 } break;
8024 case RO_V_VFSLIDE1UP_VF: {
8025 RVV_VI_CHECK_SLIDE(true);
8026 RVV_VI_GENERAL_LOOP_BASE
8027 if (i < rvv_vstart()) continue;
8028 switch (rvv_vsew()) {
8029 case E8: {
8030 UNSUPPORTED();
8031 }
8032 case E16: {
8033 UNSUPPORTED();
8034 }
8035 case E32: {
8036 VF_SLIDE1UP_PARAMS(32, 1);
8037 } break;
8038 default: {
8039 VF_SLIDE1UP_PARAMS(64, 1);
8040 } break;
8041 }
8042 RVV_VI_LOOP_END
8043 rvv_trace_vd();
8044 } break;
8045 default:
8047 }
8048}
8049void Simulator::DecodeVType() {
8050 switch (instr_.InstructionBits() & (kFunct3Mask | kBaseOpcodeMask)) {
8051 case OP_IVV:
8052 DecodeRvvIVV();
8053 return;
8054 case OP_FVV:
8055 DecodeRvvFVV();
8056 return;
8057 case OP_MVV:
8058 DecodeRvvMVV();
8059 return;
8060 case OP_IVI:
8061 DecodeRvvIVI();
8062 return;
8063 case OP_IVX:
8064 DecodeRvvIVX();
8065 return;
8066 case OP_FVF:
8067 DecodeRvvFVF();
8068 return;
8069 case OP_MVX:
8070 DecodeRvvMVX();
8071 return;
8072 }
8073 switch (instr_.InstructionBits() &
8074 (kBaseOpcodeMask | kFunct3Mask | 0x80000000)) {
8075 case RO_V_VSETVLI: {
8076 uint64_t avl;
8077 set_rvv_vtype(rvv_zimm());
8078 CHECK_GE(rvv_vsew(), E8);
8079 CHECK_LE(rvv_vsew(), E64);
8080 if (rs1_reg() != zero_reg) {
8081 avl = rs1();
8082 } else if (rd_reg() != zero_reg) {
8083 avl = ~0;
8084 } else {
8085 avl = rvv_vl();
8086 }
8087 avl = avl <= rvv_vlmax() ? avl : rvv_vlmax();
8088 set_rvv_vl(avl);
8089 set_rd(rvv_vl());
8090 set_rvv_vstart(0);
8091 rvv_trace_status();
8092 break;
8093 }
8094 case RO_V_VSETVL: {
8095 if (!(instr_.InstructionBits() & 0x40000000)) {
8096 uint64_t avl;
8097 set_rvv_vtype(rs2());
8098 CHECK_GE(rvv_sew(), E8);
8099 CHECK_LE(rvv_sew(), E64);
8100 if (rs1_reg() != zero_reg) {
8101 avl = rs1();
8102 } else if (rd_reg() != zero_reg) {
8103 avl = ~0;
8104 } else {
8105 avl = rvv_vl();
8106 }
8107 avl = avl <= rvv_vlmax() ? avl
8108 : avl < (rvv_vlmax() * 2) ? avl / 2
8109 : rvv_vlmax();
8110 set_rvv_vl(avl);
8111 set_rd(rvv_vl());
8112 rvv_trace_status();
8113 } else {
8114 DCHECK_EQ(instr_.InstructionBits() &
8115 (kBaseOpcodeMask | kFunct3Mask | 0xC0000000),
8116 RO_V_VSETIVLI);
8117 uint64_t avl;
8118 set_rvv_vtype(rvv_zimm());
8119 avl = instr_.Rvvuimm();
8120 avl = avl <= rvv_vlmax() ? avl
8121 : avl < (rvv_vlmax() * 2) ? avl / 2
8122 : rvv_vlmax();
8123 set_rvv_vl(avl);
8124 set_rd(rvv_vl());
8125 rvv_trace_status();
8126 break;
8127 }
8128 break;
8129 }
8130 default:
8131 FATAL("Error: Unsupport on FILE:%s:%d.", __FILE__, __LINE__);
8132 }
8133}
8134#endif
8135
8136// Executes the current instruction.
8137void Simulator::InstructionDecode(Instruction* instr) {
8138 if (v8_flags.check_icache) {
8139 CheckICache(i_cache(), instr);
8140 }
8141 pc_modified_ = false;
8142
8144
8145 if (v8_flags.trace_sim || v8_flags.debug_sim) {
8146 SNPrintF(trace_buf_, " ");
8147 disasm::NameConverter converter;
8148 disasm::Disassembler dasm(converter);
8149 // Use a reasonably large buffer.
8150 dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(instr));
8151
8152 // PrintF("EXECUTING 0x%08" PRIxPTR " %-44s\n",
8153 // reinterpret_cast<intptr_t>(instr), buffer.begin());
8154 }
8155 instr_ = instr;
8156 switch (instr_.InstructionType()) {
8157 case Instruction::kRType:
8158 DecodeRVRType();
8159 break;
8160 case Instruction::kR4Type:
8161 DecodeRVR4Type();
8162 break;
8163 case Instruction::kIType:
8164 DecodeRVIType();
8165 break;
8166 case Instruction::kSType:
8167 DecodeRVSType();
8168 break;
8169 case Instruction::kBType:
8170 DecodeRVBType();
8171 break;
8172 case Instruction::kUType:
8173 DecodeRVUType();
8174 break;
8175 case Instruction::kJType:
8176 DecodeRVJType();
8177 break;
8178 case Instruction::kCRType:
8179 DecodeCRType();
8180 break;
8181 case Instruction::kCAType:
8182 DecodeCAType();
8183 break;
8184 case Instruction::kCJType:
8185 DecodeCJType();
8186 break;
8187 case Instruction::kCBType:
8188 DecodeCBType();
8189 break;
8190 case Instruction::kCIType:
8191 DecodeCIType();
8192 break;
8193 case Instruction::kCIWType:
8194 DecodeCIWType();
8195 break;
8196 case Instruction::kCSSType:
8197 DecodeCSSType();
8198 break;
8199 case Instruction::kCLType:
8200 DecodeCLType();
8201 break;
8202 case Instruction::kCSType:
8203 DecodeCSType();
8204 break;
8205#ifdef CAN_USE_RVV_INSTRUCTIONS
8206 case Instruction::kVType:
8207 DecodeVType();
8208 break;
8209#endif
8210 default:
8211 if (1) {
8212 std::cout << "Unrecognized instruction [@pc=0x" << std::hex
8213 << registers_[pc] << "]: 0x" << instr->InstructionBits()
8214 << std::endl;
8215 }
8216 UNSUPPORTED();
8217 }
8218
8219 if (v8_flags.trace_sim) {
8220 PrintF(" 0x%012" PRIxPTR " %-44s\t%s\n",
8221 reinterpret_cast<intptr_t>(instr), buffer.begin(),
8222 trace_buf_.begin());
8223 }
8224
8225 if (!pc_modified_) {
8226 set_register(pc,
8227 reinterpret_cast<sreg_t>(instr) + instr->InstructionSize());
8228 }
8229
8230 if (watch_address_ != nullptr) {
8231 PrintF(" 0x%012" PRIxPTR " : 0x%016" REGIx_FORMAT " %14" REGId_FORMAT
8232 " ",
8233 reinterpret_cast<intptr_t>(watch_address_), *watch_address_,
8234 *watch_address_);
8235 // Object obj(*watch_address_);
8236 // Heap* current_heap = isolate_->heap();
8237 // if (obj.IsSmi() || IsValidHeapObject(current_heap,
8238 // Cast<HeapObject>(obj))) {
8239 // PrintF(" (");
8240 // if (obj.IsSmi()) {
8241 // PrintF("smi %d", Smi::ToInt(obj));
8242 // } else {
8243 // ShortPrint(obj);
8244 // }
8245 // PrintF(")");
8246 // }
8247 PrintF("\n");
8248 if (watch_value_ != *watch_address_) {
8249 RiscvDebugger dbg(this);
8250 dbg.Debug();
8251 watch_value_ = *watch_address_;
8252 }
8253 }
8254}
8255
8256void Simulator::Execute() {
8257 // Get the PC to simulate. Cannot use the accessor here as we need the
8258 // raw PC value and not the one used as input to arithmetic instructions.
8259 sreg_t program_counter = get_pc();
8260 while (program_counter != end_sim_pc) {
8261 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
8262 icount_++;
8263 if (icount_ == static_cast<sreg_t>(v8_flags.stop_sim_at)) {
8264 RiscvDebugger dbg(this);
8265 dbg.Debug();
8266 } else {
8267 InstructionDecode(instr);
8268 }
8269 CheckBreakpoints();
8270 program_counter = get_pc();
8271 }
8272}
8273
8274void Simulator::CallInternal(Address entry) {
8275 // Adjust JS-based stack limit to C-based stack limit.
8276 isolate_->stack_guard()->AdjustStackLimitForSimulator();
8277
8278 // Prepare to execute the code at entry.
8279 set_register(pc, static_cast<sreg_t>(entry));
8280 // Put down marker for end of simulation. The simulator will stop simulation
8281 // when the PC reaches this value. By saving the "end simulation" value into
8282 // the LR the simulation stops when returning to this call point.
8283 set_register(ra, end_sim_pc);
8284
8285 // Remember the values of callee-saved registers.
8286 sreg_t s0_val = get_register(s0);
8287 sreg_t s1_val = get_register(s1);
8288 sreg_t s2_val = get_register(s2);
8289 sreg_t s3_val = get_register(s3);
8290 sreg_t s4_val = get_register(s4);
8291 sreg_t s5_val = get_register(s5);
8292 sreg_t s6_val = get_register(s6);
8293 sreg_t s7_val = get_register(s7);
8294 sreg_t s8_val = get_register(s8);
8295 sreg_t s9_val = get_register(s9);
8296 sreg_t s10_val = get_register(s10);
8297 sreg_t s11_val = get_register(s11);
8298 sreg_t gp_val = get_register(gp);
8299 sreg_t sp_val = get_register(sp);
8300
8301 // Set up the callee-saved registers with a known value. To be able to check
8302 // that they are preserved properly across JS execution. If this value is
8303 // small int, it should be SMI.
8304 sreg_t callee_saved_value = icount_ != 0 ? icount_ & ~kSmiTagMask : -1;
8305 set_register(s0, callee_saved_value);
8306 set_register(s1, callee_saved_value);
8307 set_register(s2, callee_saved_value);
8308 set_register(s3, callee_saved_value);
8309 set_register(s4, callee_saved_value);
8310 set_register(s5, callee_saved_value);
8311 set_register(s6, callee_saved_value);
8312 set_register(s7, callee_saved_value);
8313 set_register(s8, callee_saved_value);
8314 set_register(s9, callee_saved_value);
8315 set_register(s10, callee_saved_value);
8316 set_register(s11, callee_saved_value);
8317 set_register(gp, callee_saved_value);
8318
8319 // Start the simulation.
8320 Execute();
8321
8322 // Check that the callee-saved registers have been preserved.
8323 CHECK_EQ(callee_saved_value, get_register(s0));
8324 CHECK_EQ(callee_saved_value, get_register(s1));
8325 CHECK_EQ(callee_saved_value, get_register(s2));
8326 CHECK_EQ(callee_saved_value, get_register(s3));
8327 CHECK_EQ(callee_saved_value, get_register(s4));
8328 CHECK_EQ(callee_saved_value, get_register(s5));
8329 CHECK_EQ(callee_saved_value, get_register(s6));
8330 CHECK_EQ(callee_saved_value, get_register(s7));
8331 CHECK_EQ(callee_saved_value, get_register(s8));
8332 CHECK_EQ(callee_saved_value, get_register(s9));
8333 CHECK_EQ(callee_saved_value, get_register(s10));
8334 CHECK_EQ(callee_saved_value, get_register(s11));
8335 CHECK_EQ(callee_saved_value, get_register(gp));
8336
8337 // Restore callee-saved registers with the original value.
8338 set_register(s0, s0_val);
8339 set_register(s1, s1_val);
8340 set_register(s2, s2_val);
8341 set_register(s3, s3_val);
8342 set_register(s4, s4_val);
8343 set_register(s5, s5_val);
8344 set_register(s6, s6_val);
8345 set_register(s7, s7_val);
8346 set_register(s8, s8_val);
8347 set_register(s9, s9_val);
8348 set_register(s10, s10_val);
8349 set_register(s11, s11_val);
8350 set_register(gp, gp_val);
8351 set_register(sp, sp_val);
8352}
8353
8354#ifdef V8_TARGET_ARCH_RISCV64
8355void Simulator::CallImpl(Address entry, CallArgument* args) {
8356 int index_gp = 0;
8357 int index_fp = 0;
8358 std::vector<int64_t> stack_args(0);
8359 for (int i = 0; !args[i].IsEnd(); i++) {
8360 CallArgument arg = args[i];
8361 if (arg.IsGP() && (index_gp < 8)) {
8362 set_register(index_gp + kRegCode_a0, arg.bits());
8363 index_gp++;
8364 } else if (arg.IsFP() && (index_fp < 8)) {
8365 set_fpu_register(index_fp + kDoubleCode_fa0, arg.bits());
8366 index_fp++;
8367 } else {
8368 DCHECK(arg.IsFP() || arg.IsGP());
8369 stack_args.push_back(arg.bits());
8370 }
8371 }
8372 if (v8_flags.trace_sim) {
8373 std::cout << "CallImpl: reg_arg_count = " << index_fp + index_gp << std::hex
8374 << " entry-pc (JSEntry) = 0x" << entry
8375 << " a0 (Isolate-root) = 0x" << get_register(a0)
8376 << " a1 (orig_func/new_target) = 0x" << get_register(a1)
8377 << " a2 (func/target) = 0x" << get_register(a2)
8378 << " a3 (receiver) = 0x" << get_register(a3) << " a4 (argc) = 0x"
8379 << get_register(a4) << " a5 (argv) = 0x" << get_register(a5)
8380 << std::endl;
8381 }
8382 // Remaining arguments passed on stack.
8383 int64_t original_stack = get_register(sp);
8384 // Compute position of stack on entry to generated code.
8385 int64_t stack_args_size =
8386 stack_args.size() * sizeof(stack_args[0]) + kCArgsSlotsSize;
8387 int64_t entry_stack = original_stack - stack_args_size;
8388 if (base::OS::ActivationFrameAlignment() != 0) {
8389 entry_stack &= -base::OS::ActivationFrameAlignment();
8390 }
8391 // Store remaining arguments on stack, from low to high memory.
8392 char* stack_argument = reinterpret_cast<char*>(entry_stack);
8393 memcpy(stack_argument + kCArgSlotCount, stack_args.data(),
8394 stack_args.size() * sizeof(int64_t));
8395 set_register(sp, entry_stack);
8396 CallInternal(entry);
8397 // Pop stack passed arguments.
8398 CHECK_EQ(entry_stack, get_register(sp));
8399 set_register(sp, original_stack);
8400}
8401#else
8402intptr_t Simulator::CallImpl(Address entry, int argument_count,
8403 const intptr_t* arguments) {
8404 constexpr int kRegisterPassedArguments = 8;
8405 // Set up arguments.
8406 // RISC-V 64G ISA has a0-a7 for passing arguments
8407 int reg_arg_count = std::min(kRegisterPassedArguments, argument_count);
8408 if (reg_arg_count > 0) set_register(a0, arguments[0]);
8409 if (reg_arg_count > 1) set_register(a1, arguments[1]);
8410 if (reg_arg_count > 2) set_register(a2, arguments[2]);
8411 if (reg_arg_count > 3) set_register(a3, arguments[3]);
8412 if (reg_arg_count > 4) set_register(a4, arguments[4]);
8413 if (reg_arg_count > 5) set_register(a5, arguments[5]);
8414 if (reg_arg_count > 6) set_register(a6, arguments[6]);
8415 if (reg_arg_count > 7) set_register(a7, arguments[7]);
8416 if (v8_flags.trace_sim) {
8417 std::cout << "CallImpl: reg_arg_count = " << reg_arg_count << std::hex
8418 << " entry-pc (JSEntry) = 0x" << entry
8419 << " a0 (Isolate-root) = 0x" << get_register(a0)
8420 << " a1 (orig_func/new_target) = 0x" << get_register(a1)
8421 << " a2 (func/target) = 0x" << get_register(a2)
8422 << " a3 (receiver) = 0x" << get_register(a3) << " a4 (argc) = 0x"
8423 << get_register(a4) << " a5 (argv) = 0x" << get_register(a5)
8424 << std::endl;
8425 }
8426 // Remaining arguments passed on stack.
8427 sreg_t original_stack = get_register(sp);
8428 // Compute position of stack on entry to generated code.
8429 int stack_args_count = argument_count - reg_arg_count;
8430 int stack_args_size = stack_args_count * sizeof(*arguments) + kCArgsSlotsSize;
8431 sreg_t entry_stack = original_stack - stack_args_size;
8432 if (base::OS::ActivationFrameAlignment() != 0) {
8433 entry_stack &= -base::OS::ActivationFrameAlignment();
8434 }
8435 // Store remaining arguments on stack, from low to high memory.
8436 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
8437 memcpy(stack_argument + kCArgSlotCount, arguments + reg_arg_count,
8438 stack_args_count * sizeof(*arguments));
8439 set_register(sp, entry_stack);
8440 CallInternal(entry);
8441 // Pop stack passed arguments.
8442 CHECK_EQ(entry_stack, get_register(sp));
8443 set_register(sp, original_stack);
8444 // return get_register(a0);
8445 // RISCV uses a0 to return result
8446 return get_register(a0);
8447}
8448#endif // V8_TARGET_ARCH_RISCV64
8449
8450double Simulator::CallFP(Address entry, double d0, double d1) {
8451 set_fpu_register_double(fa0, d0);
8452 set_fpu_register_double(fa1, d1);
8453 CallInternal(entry);
8454 return get_fpu_register_double(fa0);
8455}
8456
8457uintptr_t Simulator::PushAddress(uintptr_t address) {
8458 int64_t new_sp = get_register(sp) - sizeof(uintptr_t);
8459 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
8460 *stack_slot = address;
8461 set_register(sp, new_sp);
8462 return new_sp;
8463}
8464
8465uintptr_t Simulator::PopAddress() {
8466 int64_t current_sp = get_register(sp);
8467 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
8468 uintptr_t address = *stack_slot;
8469 set_register(sp, current_sp + sizeof(uintptr_t));
8470 return address;
8471}
8472
8473Simulator::LocalMonitor::LocalMonitor()
8474 : access_state_(MonitorAccess::Open),
8475 tagged_addr_(0),
8476 size_(TransactionSize::None) {}
8477
8478void Simulator::LocalMonitor::Clear() {
8479 access_state_ = MonitorAccess::Open;
8480 tagged_addr_ = 0;
8481 size_ = TransactionSize::None;
8482}
8483
8484void Simulator::LocalMonitor::NotifyLoad() {
8485 if (access_state_ == MonitorAccess::RMW) {
8486 // A non linked load could clear the local monitor. As a result, it's
8487 // most strict to unconditionally clear the local monitor on load.
8488 Clear();
8489 }
8490}
8491
8492void Simulator::LocalMonitor::NotifyLoadLinked(uintptr_t addr,
8493 TransactionSize size) {
8494 access_state_ = MonitorAccess::RMW;
8495 tagged_addr_ = addr;
8496 size_ = size;
8497}
8498
8499void Simulator::LocalMonitor::NotifyStore() {
8500 if (access_state_ == MonitorAccess::RMW) {
8501 // A non exclusive store could clear the local monitor. As a result, it's
8502 // most strict to unconditionally clear the local monitor on store.
8503 Clear();
8504 }
8505}
8506
8507bool Simulator::LocalMonitor::NotifyStoreConditional(uintptr_t addr,
8508 TransactionSize size) {
8509 if (access_state_ == MonitorAccess::RMW) {
8510 if (addr == tagged_addr_ && size_ == size) {
8511 Clear();
8512 return true;
8513 } else {
8514 return false;
8515 }
8516 } else {
8517 DCHECK(access_state_ == MonitorAccess::Open);
8518 return false;
8519 }
8520}
8521
8522Simulator::GlobalMonitor::LinkedAddress::LinkedAddress()
8523 : access_state_(MonitorAccess::Open),
8524 tagged_addr_(0),
8525 next_(nullptr),
8526 prev_(nullptr),
8527 failure_counter_(0) {}
8528
8529void Simulator::GlobalMonitor::LinkedAddress::Clear_Locked() {
8530 access_state_ = MonitorAccess::Open;
8531 tagged_addr_ = 0;
8532}
8533
8534void Simulator::GlobalMonitor::LinkedAddress::NotifyLoadLinked_Locked(
8535 uintptr_t addr) {
8536 access_state_ = MonitorAccess::RMW;
8537 tagged_addr_ = addr;
8538}
8539
8540void Simulator::GlobalMonitor::LinkedAddress::NotifyStore_Locked() {
8541 if (access_state_ == MonitorAccess::RMW) {
8542 // A non exclusive store could clear the global monitor. As a result, it's
8543 // most strict to unconditionally clear global monitors on store.
8544 Clear_Locked();
8545 }
8546}
8547
8548bool Simulator::GlobalMonitor::LinkedAddress::NotifyStoreConditional_Locked(
8549 uintptr_t addr, bool is_requesting_thread) {
8550 if (access_state_ == MonitorAccess::RMW) {
8551 if (is_requesting_thread) {
8552 if (addr == tagged_addr_) {
8553 Clear_Locked();
8554 // Introduce occasional sc/scd failures. This is to simulate the
8555 // behavior of hardware, which can randomly fail due to background
8556 // cache evictions.
8557 if (failure_counter_++ >= kMaxFailureCounter) {
8558 failure_counter_ = 0;
8559 return false;
8560 } else {
8561 return true;
8562 }
8563 }
8564 } else if ((addr & kExclusiveTaggedAddrMask) ==
8565 (tagged_addr_ & kExclusiveTaggedAddrMask)) {
8566 // Check the masked addresses when responding to a successful lock by
8567 // another thread so the implementation is more conservative (i.e. the
8568 // granularity of locking is as large as possible.)
8569 Clear_Locked();
8570 return false;
8571 }
8572 }
8573 return false;
8574}
8575
8576void Simulator::GlobalMonitor::NotifyLoadLinked_Locked(
8577 uintptr_t addr, LinkedAddress* linked_address) {
8578 linked_address->NotifyLoadLinked_Locked(addr);
8579 PrependProcessor_Locked(linked_address);
8580}
8581
8582void Simulator::GlobalMonitor::NotifyStore_Locked(
8583 LinkedAddress* linked_address) {
8584 // Notify each thread of the store operation.
8585 for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
8586 iter->NotifyStore_Locked();
8587 }
8588}
8589
8590bool Simulator::GlobalMonitor::NotifyStoreConditional_Locked(
8591 uintptr_t addr, LinkedAddress* linked_address) {
8592 DCHECK(IsProcessorInLinkedList_Locked(linked_address));
8593 if (linked_address->NotifyStoreConditional_Locked(addr, true)) {
8594 // Notify the other processors that this StoreConditional succeeded.
8595 for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
8596 if (iter != linked_address) {
8597 iter->NotifyStoreConditional_Locked(addr, false);
8598 }
8599 }
8600 return true;
8601 } else {
8602 return false;
8603 }
8604}
8605
8606bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked(
8607 LinkedAddress* linked_address) const {
8608 return head_ == linked_address || linked_address->next_ ||
8609 linked_address->prev_;
8610}
8611
8612void Simulator::GlobalMonitor::PrependProcessor_Locked(
8613 LinkedAddress* linked_address) {
8614 if (IsProcessorInLinkedList_Locked(linked_address)) {
8615 return;
8616 }
8617
8618 if (head_) {
8619 head_->prev_ = linked_address;
8620 }
8621 linked_address->prev_ = nullptr;
8622 linked_address->next_ = head_;
8623 head_ = linked_address;
8624}
8625
8626void Simulator::GlobalMonitor::RemoveLinkedAddress(
8627 LinkedAddress* linked_address) {
8628 base::MutexGuard lock_guard(&mutex);
8629 if (!IsProcessorInLinkedList_Locked(linked_address)) {
8630 return;
8631 }
8632
8633 if (linked_address->prev_) {
8634 linked_address->prev_->next_ = linked_address->next_;
8635 } else {
8636 head_ = linked_address->next_;
8637 }
8638 if (linked_address->next_) {
8639 linked_address->next_->prev_ = linked_address->prev_;
8640 }
8641 linked_address->prev_ = nullptr;
8642 linked_address->next_ = nullptr;
8643}
8644
8645#undef SScanF
8646#undef BRACKETS
8647
8648void Simulator::DoSwitchStackLimit(Instruction* instr) {
8649 const int64_t stack_limit = get_register(kSimulatorBreakArgument.code());
8650 // stack_limit represents js limit and adjusted by extra runaway gap.
8651 // Also, stack switching code reads js_limit generated by
8652 // {Simulator::StackLimit} and then resets it back here.
8653 // So without adjusting back incoming value by safety gap
8654 // {stack_limit_} will be shortened by kAdditionalStackMargin yielding
8655 // positive feedback loop.
8656 stack_limit_ = static_cast<uintptr_t>(stack_limit - kAdditionalStackMargin);
8657}
8658
8659} // namespace internal
8660} // namespace v8
8661
8662#endif // USE_SIMULATOR
Isolate * isolate_
#define UNSUPPORTED_RISCV()
#define UNIMPLEMENTED_RISCV()
#define T
#define one
Builtins::Kind kind
Definition builtins.cc:40
SourcePosition pos
virtual void VisitPointer(const void *address)=0
static void DebugBreak()
constexpr T * begin() const
Definition vector.h:96
static const char * Name(int reg)
static int Number(const char *name)
constexpr int8_t code() const
static int Number(const char *name)
static const char * Name(int reg)
static int Number(const char *name)
Handle< Code > code
const int size_
Definition assembler.cc:132
#define FUNCTION_ADDR(f)
Definition globals.h:712
@ kLittle
int start
int end
LineAndColumn current
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
int32_t offset
#define XSTR(s)
TNode< Object > target
std::optional< TNode< JSArray > > a
Instruction * instr
ZoneVector< RpoNumber > & result
#define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName,...)
Builtin builtin
LiftoffRegister reg
EmitFn fn
int y
int x
uint32_t const mask
#define xlen
base::Mutex mutex
#define DISABLE_MSAN
Definition msan.h:40
int int32_t
Definition unicode.cc:40
unsigned short uint16_t
Definition unicode.cc:39
signed short int16_t
Definition unicode.cc:38
int SNPrintF(Vector< char > str, const char *format,...)
Definition strings.cc:20
uintptr_t Address
Definition memory.h:13
CustomMatcherTemplateHashMapImpl< DefaultAllocationPolicy > CustomMatcherHashMap
Definition hashmap.h:480
FloatWithBits< 32 > Float32
Definition index.h:233
FloatWithBits< 64 > Float64
Definition index.h:234
void DeleteArray(T *array)
Definition allocation.h:63
constexpr Opcode RO_FLE_S
constexpr Opcode OP_MVV
constexpr Opcode RO_V_VFWADD_VV
constexpr Opcode RO_V_VFSLIDE1DOWN_VF
constexpr Opcode RO_V_VMSGT_VI
constexpr Opcode RO_FMADD_S
constexpr Opcode RO_C_AND
constexpr Opcode RO_V_VFWSUB_VF
constexpr Opcode RO_CZERO_EQZ
constexpr Opcode RO_MULH
constexpr Opcode RO_FCVT_S_W
constexpr Opcode RO_V_VSLIDEUP_VX
constexpr Opcode RO_V_VADD_VI
constexpr Opcode RO_C_SUB
constexpr Opcode RO_V_VFNMADD_VF
constexpr Opcode RO_BGE
constexpr Opcode RO_V_VFNMADD_VV
constexpr Opcode RO_XORI
constexpr Opcode RO_MIN
constexpr Opcode RO_V_VFADD_VF
constexpr Opcode RO_FSGNJ_D
constexpr Opcode RO_V_VMULH_VV
constexpr Opcode RO_MULHU
constexpr Opcode RO_V_VMIN_VX
constexpr Opcode RO_C_MISC_ALU
constexpr Opcode RO_FLW
constexpr Opcode RO_SRA
constexpr Opcode RO_V_VFMADD_VV
constexpr Opcode RO_V_VMULHU_VV
constexpr Opcode RO_V_VFWNMSAC_VV
constexpr Opcode RO_V_VFSGNJN_VF
constexpr Opcode RO_C_OR
constexpr Opcode RO_V_VMSLEU_VI
constexpr Opcode RO_SLTIU
constexpr Opcode RO_REM
constexpr Opcode RO_REMU
constexpr Opcode RO_V_VFWMSAC_VF
constexpr Opcode RO_V_VFNMACC_VF
const uint32_t kRvvNfMask
constexpr Opcode RO_V_VFNMSUB_VV
constexpr Opcode RO_FCVT_D_W
constexpr Opcode RO_DIVU
constexpr Opcode RO_BINV
constexpr Opcode RO_V_VSRL_VI
const uint32_t kExceptionIsSwitchStackLimit
constexpr Opcode RO_V_VMSLTU_VX
constexpr Opcode RO_V_VMUL_VX
constexpr Opcode RO_V_VMINU_VV
constexpr Opcode RO_V_VSLL_VX
constexpr Opcode RO_BCLRI
constexpr Opcode RO_LBU
constexpr Opcode VFRSQRT7_V
constexpr Opcode VFWCVT_F_X_V
constexpr Opcode RO_V_VFWADD_W_VF
constexpr Opcode RO_V_VREDMIN
constexpr Opcode RO_C_NOP_ADDI
constexpr Opcode RO_V_VSSUB_VX
constexpr Opcode RO_V_VSLIDE1UP_VX
constexpr Opcode RO_V_VFWMUL_VV
void PrintF(const char *format,...)
Definition utils.cc:39
char * ReadLine(const char *prompt)
Definition utils.cc:69
const Instr rtCallRedirInstr
constexpr Opcode RO_REV8
constexpr Opcode RO_V_VMSEQ_VX
constexpr Opcode RO_V_VSLL_VI
constexpr Opcode RO_SRAI
constexpr Opcode OP_IVX
constexpr uint32_t kMaxStopCode
const uint32_t kMaxWatchpointCode
constexpr Opcode RO_V_VMSLT_VX
constexpr Opcode RO_FCVT_W_D
constexpr Opcode RO_SRLI
constexpr Opcode RO_V_VSLIDEDOWN_VX
constexpr Opcode VFNCVT_XU_F_W
constexpr Opcode RO_V_VDIVU_VX
constexpr Opcode RO_V_VFSUB_VV
const uint32_t kRvvMopMask
constexpr Opcode RO_V_VMFNE_VV
constexpr Opcode RO_SC_W
constexpr Opcode RO_V_VFUNARY1
constexpr Opcode RO_V_VFMACC_VF
constexpr Opcode RO_V_VMSEQ_VV
constexpr Opcode RO_V_VXOR_VV
constexpr Opcode RO_V_VMSGT_VX
constexpr Opcode RO_V_VADD_VV
constexpr Opcode RO_FLD
constexpr Opcode OP_MVX
constexpr Opcode RO_C_LWSP
constexpr Opcode RO_V_VFMV_FS
constexpr Opcode RO_V_VMV_VV
constexpr Opcode RO_JALR
constexpr Opcode RO_AMOMAX_W
constexpr Opcode RO_SUB
constexpr Opcode RO_C_ADDI4SPN
constexpr Opcode RO_V_VFWSUB_VV
constexpr Opcode RO_V_VFWMACC_VV
constexpr Opcode RO_V_VFMV_SF
constexpr Opcode RO_V_VMFLT_VV
constexpr Opcode RO_V_VDIVU_VV
constexpr Opcode RO_V_VMSLEU_VX
constexpr Opcode RO_V_VFWMACC_VF
constexpr Opcode RO_V_VFMSAC_VV
constexpr Opcode RO_C_FLD
constexpr Opcode RO_V_VMSEQ_VI
constexpr Opcode RO_V_VMSLEU_VV
constexpr Opcode RO_LHU
constexpr Opcode RO_V_VMUL_VV
constexpr Opcode RO_V_VMV_VI
constexpr Opcode RO_CZERO_NEZ
constexpr Opcode RO_V_VSLIDEUP_VI
constexpr Opcode RO_SB
constexpr Opcode RO_V_VFREDMAX_VV
constexpr Opcode RO_V_VFWSUB_W_VV
constexpr Opcode VFNCVT_X_F_W
constexpr Opcode RO_XOR
constexpr Opcode RO_C_XOR
constexpr Opcode VFCVT_X_F_V
constexpr Opcode RO_V_VFMAX_VV
constexpr Opcode RO_BSET
constexpr Opcode RO_V_VFWREDOSUM_VS
constexpr Opcode RO_BLTU
constexpr Opcode RO_V_VWMUL_VV
constexpr Opcode VFSQRT_V
const int kNumFPURegisters
constexpr Opcode RO_C_LI
constexpr Opcode RO_BEQ
constexpr Opcode RO_SH
constexpr Opcode RO_V_VXOR_VX
constexpr Register kSimulatorBreakArgument
constexpr Opcode RO_V_VFWNMACC_VF
const int kInvalidFPURegister
constexpr Opcode RO_V_VFNMSAC_VV
constexpr Opcode RO_C_LW
constexpr Opcode RO_V_VFSGNJN_VV
void Print(Tagged< Object > obj)
Definition objects.h:774
constexpr Opcode RO_V_VMFEQ_VV
constexpr Opcode RO_LH
constexpr Opcode RO_MAX
constexpr Opcode VFCLASS_V
constexpr Opcode RO_FCVT_W_S
constexpr Opcode RO_CSRRWI
constexpr Opcode RO_V_VSADDU_VI
constexpr Opcode RO_AMOOR_W
constexpr Opcode RO_C_SW
const int kNumSimuRegisters
constexpr Opcode VFWCVT_F_F_V
constexpr Opcode RO_V_VFMSUB_VF
constexpr Opcode RO_V_VSADDU_VX
constexpr Opcode RO_V_VFWMUL_VF
constexpr Opcode RO_ECALL
constexpr Opcode RO_V_VSLIDE1DOWN_VX
constexpr Opcode JAL
constexpr Opcode OP_IVI
constexpr Opcode RO_V_VWXUNARY0
constexpr Opcode RO_SLTI
constexpr Opcode RO_V_VNCLIP_WI
constexpr Opcode RO_CSRRS
const int kInvalidRegister
constexpr Opcode RO_V_VSLIDEDOWN_VI
const int kInvalidVRegister
constexpr Opcode RO_DIV
constexpr Opcode RO_BEXTI
constexpr Opcode RO_V_VDIV_VV
constexpr Opcode RO_MUL
constexpr Opcode RO_FMIN_S
constexpr Opcode RO_V_VMSLE_VV
constexpr Opcode RO_V_VMAX_VV
constexpr Opcode RO_V_VMFLE_VV
constexpr Opcode RO_ROL
uintptr_t GetCurrentStackPosition()
Definition utils.cc:222
constexpr Opcode RO_V_VSETVL
constexpr Opcode RO_V_VSADD_VX
constexpr Opcode RO_V_VFWSUB_W_VF
constexpr Opcode RO_FCVT_D_S
constexpr Opcode RO_FSQRT_D
constexpr Opcode RO_V_VSRL_VX
constexpr Opcode RO_V_VADD_VX
constexpr Opcode RO_BEXT
constexpr Opcode RO_V_VMIN_VV
constexpr Opcode RO_SH2ADD
constexpr Opcode RO_AMOADD_W
constexpr Opcode RO_XNOR
constexpr Opcode RO_FSUB_S
constexpr Opcode RO_BGEU
constexpr Opcode RO_V_VSUB_VX
constexpr Opcode RO_V_VXOR_VI
constexpr Opcode OP_SHL
constexpr Opcode LUI
constexpr Opcode RO_V_VFSGNJX_VF
constexpr Opcode RO_C_FSDSP
constexpr Opcode RO_C_BEQZ
constexpr Opcode RO_FNMADD_D
constexpr Opcode RO_CSRRCI
constexpr Opcode RO_V_VMSLE_VX
constexpr Opcode RO_SLLI
constexpr Opcode RO_FADD_D
constexpr Opcode RO_FSGNJ_S
constexpr Opcode RO_V_VRSUB_VX
constexpr Opcode RO_V_VMV_VX
constexpr Opcode RO_V_VMINU_VX
constexpr Opcode RO_ORI
const uint32_t kFunct6Mask
constexpr Opcode RO_BLT
constexpr Opcode RO_LW
constexpr Opcode RO_C_SWSP
constexpr Opcode RO_V_VFUNARY0
constexpr Opcode RO_SLTU
constexpr Opcode RO_V_VFNMSUB_VF
constexpr Opcode RO_V_VFMSAC_VF
constexpr Opcode RO_FMADD_D
constexpr Opcode RO_V_VFWNMACC_VV
constexpr Opcode RO_V_VMAXU_VX
constexpr Opcode RO_V_VFMSUB_VV
constexpr Opcode RO_ANDN
constexpr Opcode VFCVT_F_X_V
constexpr Opcode RO_V_VOR_VV
constexpr Opcode RO_V_VSRA_VI
constexpr Opcode RO_C_BNEZ
const int kCArgsSlotsSize
constexpr Opcode RO_V_VFSLIDE1UP_VF
constexpr Opcode RO_V_VREDMAXU
constexpr Opcode RO_V_VSUB_VV
constexpr Opcode RO_SH3ADD
constexpr Opcode RO_V_VWADD_VV
constexpr Opcode RO_V_VADC_VV
constexpr Opcode RO_V_VCOMPRESS_VV
constexpr Opcode RO_V_VFSGNJX_VV
constexpr Opcode RO_V_VMSNE_VX
constexpr Opcode RO_ADDI
constexpr Register kWasmTrapHandlerFaultAddressRegister
constexpr Opcode RO_FADD_S
constexpr Opcode RO_V_VSMUL_VV
constexpr Opcode RO_MULHSU
constexpr Opcode RO_AMOMINU_W
constexpr Opcode RO_V_VMAXU_VV
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr Opcode RO_AMOMAXU_W
constexpr Opcode RO_ORN
constexpr Opcode RO_CSRRC
constexpr Opcode RO_AMOAND_W
constexpr Opcode RO_V_VMUNARY0
constexpr Opcode RO_V_VMSNE_VI
constexpr Opcode RO_SLL
constexpr Opcode RO_SRL
constexpr Opcode RO_V_VAND_VV
constexpr Opcode RO_V_VMSLE_VI
constexpr Opcode RO_BNE
constexpr Opcode VFWCVT_X_F_V
constexpr Opcode RO_OR
constexpr Opcode RO_MAXU
constexpr Opcode RO_V_VFWADD_W_VV
constexpr Opcode RO_V_VXUNARY0
constexpr Opcode RO_BCLR
constexpr Opcode RO_ROR
constexpr Opcode RO_V_VWADDUW_VX
constexpr Opcode RO_V_VFMADD_VF
constexpr Opcode RO_V_VADC_VI
constexpr Opcode RO_CSRRSI
constexpr Opcode RO_V_VMSLT_VV
constexpr Opcode RO_V_VSETVLI
constexpr Opcode RO_C_J
constexpr Opcode RO_FMSUB_D
constexpr Opcode VFNCVT_F_F_W
constexpr Opcode RO_FSW
uint64_t ObjectPair
constexpr Opcode RO_FSUB_D
constexpr Opcode RO_V_VSRA_VV
constexpr Opcode RO_FENCE_I
constexpr Opcode RO_AND
constexpr Opcode RO_V_VRSUB_VI
constexpr Opcode RO_V_VFSGNJ_VF
constexpr Opcode VFWCVT_F_XU_V
return value
Definition map-inl.h:893
constexpr Opcode RO_V_VREDMINU
constexpr Opcode VFCVT_F_XU_V
constexpr Opcode RO_AMOMIN_W
constexpr Opcode RO_ORCB
constexpr Opcode RO_FMV
constexpr Opcode RO_FMUL_D
constexpr Opcode RO_V_VFMUL_VV
constexpr Opcode RO_V_VMSLTU_VV
constexpr Opcode RO_FMV_W_X
constexpr Opcode RO_FNMSUB_D
constexpr Opcode RO_V_VSADD_VV
uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x)
Definition utils.h:559
const Instr kBreakInstr
constexpr Opcode RO_V_VDIV_VX
constexpr Opcode RO_V_VFSGNJ_VV
constexpr uint8_t kInstrSize
constexpr Opcode RO_V_VOR_VX
constexpr Opcode RO_V_VFMACC_VV
constexpr Opcode RO_V_VREDMAX
constexpr Opcode RO_V_VWADDU_VV
constexpr Opcode RO_FMUL_S
constexpr Opcode RO_V_VRGATHER_VV
constexpr Opcode RO_BSETI
constexpr Opcode RO_C_FSD
constexpr Opcode RO_V_VSLL_VV
constexpr Opcode RO_LB
constexpr Opcode RO_FDIV_D
constexpr Opcode RO_V_VMAX_VX
constexpr Opcode RO_V_VFWMSAC_VV
constexpr Opcode VFCVT_XU_F_V
constexpr Opcode RO_ANDI
constexpr Opcode RO_FLE_D
constexpr Opcode RO_V_VMSGTU_VX
constexpr Opcode RO_C_FLDSP
constexpr Opcode VFREC7_V
constexpr Opcode RO_AMOSWAP_W
constexpr Opcode RO_V_VRXUNARY0
constexpr Opcode RO_V_VSADDU_VV
constexpr Opcode RO_V_VAND_VI
constexpr Opcode RO_LR_W
constexpr Opcode OP_IVV
constexpr Opcode RO_FMIN_D
constexpr Opcode OP_FVV
constexpr Opcode RO_V_VSRA_VX
constexpr Opcode RO_V_VADC_VX
constexpr Opcode RO_SH1ADD
constexpr Opcode RO_V_VSSUB_VV
constexpr Opcode RO_V_VFMIN_VV
constexpr Opcode RO_CSRRW
constexpr Opcode RO_FSD
constexpr Opcode RO_V_VSRL_VV
constexpr Opcode RO_V_VFWNMSAC_VF
constexpr Opcode RO_FENCE
constexpr Opcode RO_V_VFMV_VF
constexpr Opcode RO_C_LUI_ADD
constexpr Opcode RO_FNMSUB_S
constexpr Opcode RO_FSQRT_S
constexpr Opcode RO_V_VFNMSAC_VF
constexpr Opcode OP_FVF
constexpr Opcode RO_ADD
const uint32_t kBaseOpcodeMask
constexpr Opcode RO_V_VFADD_VV
constexpr Opcode RO_V_VOR_VI
constexpr Opcode RO_V_VSADD_VI
constexpr Opcode RO_C_SLLI
constexpr Opcode RO_V_VFWREDUSUM_VS
constexpr Opcode RO_V_VMSNE_VV
constexpr Opcode RO_FNMADD_S
constexpr Opcode RO_V_VAND_VX
constexpr Opcode RO_V_VFDIV_VV
constexpr Opcode VFWCVT_XU_F_V
constexpr Opcode RO_MINU
constexpr Opcode RO_FDIV_S
constexpr Opcode RO_AMOXOR_W
constexpr Opcode RO_V_VSSUBU_VV
constexpr Opcode RO_V_VFWADD_VF
constexpr Opcode OP_SHR
constexpr Opcode RO_V_VWMULU_VV
constexpr Opcode OP_COUNT
constexpr Opcode RO_SW
constexpr Opcode RO_FMSUB_S
constexpr Opcode RO_BINVI
constexpr Opcode RO_SLT
constexpr Opcode RO_V_VFNMACC_VV
@ None
Definition v8-object.h:141
base::SmallVector< RegisterT, kStaticCapacity > registers_
const uintptr_t stack_limit_
Node * prev_
#define UNREACHABLE()
Definition logging.h:67
#define FATAL(...)
Definition logging.h:47
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK_GE(lhs, rhs)
#define CHECK(condition)
Definition logging.h:124
#define CHECK_LE(lhs, rhs)
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define CHECK_NE(lhs, rhs)
#define CHECK_EQ(lhs, rhs)
#define UNIMPLEMENTED()
Definition logging.h:66
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define USE(...)
Definition macros.h:293
#define V8PRIxPTR
Definition macros.h:331
std::unique_ptr< ValueMirror > value
unsigned long DWORD