v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
disasm-arm64.cc
Go to the documentation of this file.
1// Copyright 2013 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#include <assert.h>
6#include <stdarg.h>
7#include <stdio.h>
8#include <string.h>
9
10#include <bitset>
11
12#if V8_TARGET_ARCH_ARM64
13
16#include "src/base/strings.h"
17#include "src/base/vector.h"
22
23namespace v8 {
24namespace internal {
25
27 buffer_size_ = 256;
28 buffer_ = reinterpret_cast<char*>(base::Malloc(buffer_size_));
29 buffer_pos_ = 0;
30 own_buffer_ = true;
31}
32
33DisassemblingDecoder::DisassemblingDecoder(char* text_buffer, int buffer_size) {
34 buffer_size_ = buffer_size;
35 buffer_ = text_buffer;
36 buffer_pos_ = 0;
37 own_buffer_ = false;
38}
39
41 if (own_buffer_) {
43 }
44}
45
47
48void DisassemblingDecoder::VisitAddSubImmediate(Instruction* instr) {
49 bool rd_is_zr = RdIsZROrSP(instr);
50 bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) && (instr->ImmAddSub() == 0)
51 ? true
52 : false;
53 const char* mnemonic = "";
54 const char* form = "'Rds, 'Rns, 'IAddSub";
55 const char* form_cmp = "'Rns, 'IAddSub";
56 const char* form_mov = "'Rds, 'Rns";
57
58 switch (instr->Mask(AddSubImmediateMask)) {
59 case ADD_w_imm:
60 case ADD_x_imm: {
61 mnemonic = "add";
62 if (stack_op) {
63 mnemonic = "mov";
64 form = form_mov;
65 }
66 break;
67 }
68 case ADDS_w_imm:
69 case ADDS_x_imm: {
70 mnemonic = "adds";
71 if (rd_is_zr) {
72 mnemonic = "cmn";
73 form = form_cmp;
74 }
75 break;
76 }
77 case SUB_w_imm:
78 case SUB_x_imm:
79 mnemonic = "sub";
80 break;
81 case SUBS_w_imm:
82 case SUBS_x_imm: {
83 mnemonic = "subs";
84 if (rd_is_zr) {
85 mnemonic = "cmp";
86 form = form_cmp;
87 }
88 break;
89 }
90 default:
92 }
93 Format(instr, mnemonic, form);
94}
95
96void DisassemblingDecoder::VisitAddSubShifted(Instruction* instr) {
97 bool rd_is_zr = RdIsZROrSP(instr);
98 bool rn_is_zr = RnIsZROrSP(instr);
99 const char* mnemonic = "";
100 const char* form = "'Rd, 'Rn, 'Rm'NDP";
101 const char* form_cmp = "'Rn, 'Rm'NDP";
102 const char* form_neg = "'Rd, 'Rm'NDP";
103
104 switch (instr->Mask(AddSubShiftedMask)) {
105 case ADD_w_shift:
106 case ADD_x_shift:
107 mnemonic = "add";
108 break;
109 case ADDS_w_shift:
110 case ADDS_x_shift: {
111 mnemonic = "adds";
112 if (rd_is_zr) {
113 mnemonic = "cmn";
114 form = form_cmp;
115 }
116 break;
117 }
118 case SUB_w_shift:
119 case SUB_x_shift: {
120 mnemonic = "sub";
121 if (rn_is_zr) {
122 mnemonic = "neg";
123 form = form_neg;
124 }
125 break;
126 }
127 case SUBS_w_shift:
128 case SUBS_x_shift: {
129 mnemonic = "subs";
130 if (rd_is_zr) {
131 mnemonic = "cmp";
132 form = form_cmp;
133 } else if (rn_is_zr) {
134 mnemonic = "negs";
135 form = form_neg;
136 }
137 break;
138 }
139 default:
140 UNREACHABLE();
141 }
142 Format(instr, mnemonic, form);
143}
144
145void DisassemblingDecoder::VisitAddSubExtended(Instruction* instr) {
146 bool rd_is_zr = RdIsZROrSP(instr);
147 const char* mnemonic = "";
148 Extend mode = static_cast<Extend>(instr->ExtendMode());
149 const char* form = ((mode == UXTX) || (mode == SXTX)) ? "'Rds, 'Rns, 'Xm'Ext"
150 : "'Rds, 'Rns, 'Wm'Ext";
151 const char* form_cmp =
152 ((mode == UXTX) || (mode == SXTX)) ? "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
153
154 switch (instr->Mask(AddSubExtendedMask)) {
155 case ADD_w_ext:
156 case ADD_x_ext:
157 mnemonic = "add";
158 break;
159 case ADDS_w_ext:
160 case ADDS_x_ext: {
161 mnemonic = "adds";
162 if (rd_is_zr) {
163 mnemonic = "cmn";
164 form = form_cmp;
165 }
166 break;
167 }
168 case SUB_w_ext:
169 case SUB_x_ext:
170 mnemonic = "sub";
171 break;
172 case SUBS_w_ext:
173 case SUBS_x_ext: {
174 mnemonic = "subs";
175 if (rd_is_zr) {
176 mnemonic = "cmp";
177 form = form_cmp;
178 }
179 break;
180 }
181 default:
182 UNREACHABLE();
183 }
184 Format(instr, mnemonic, form);
185}
186
187void DisassemblingDecoder::VisitAddSubWithCarry(Instruction* instr) {
188 bool rn_is_zr = RnIsZROrSP(instr);
189 const char* mnemonic = "";
190 const char* form = "'Rd, 'Rn, 'Rm";
191 const char* form_neg = "'Rd, 'Rm";
192
193 switch (instr->Mask(AddSubWithCarryMask)) {
194 case ADC_w:
195 case ADC_x:
196 mnemonic = "adc";
197 break;
198 case ADCS_w:
199 case ADCS_x:
200 mnemonic = "adcs";
201 break;
202 case SBC_w:
203 case SBC_x: {
204 mnemonic = "sbc";
205 if (rn_is_zr) {
206 mnemonic = "ngc";
207 form = form_neg;
208 }
209 break;
210 }
211 case SBCS_w:
212 case SBCS_x: {
213 mnemonic = "sbcs";
214 if (rn_is_zr) {
215 mnemonic = "ngcs";
216 form = form_neg;
217 }
218 break;
219 }
220 default:
221 UNREACHABLE();
222 }
223 Format(instr, mnemonic, form);
224}
225
226void DisassemblingDecoder::VisitLogicalImmediate(Instruction* instr) {
227 bool rd_is_zr = RdIsZROrSP(instr);
228 bool rn_is_zr = RnIsZROrSP(instr);
229 const char* mnemonic = "";
230 const char* form = "'Rds, 'Rn, 'ITri";
231
232 if (instr->ImmLogical() == 0) {
233 // The immediate encoded in the instruction is not in the expected format.
234 Format(instr, "unallocated", "(LogicalImmediate)");
235 return;
236 }
237
238 switch (instr->Mask(LogicalImmediateMask)) {
239 case AND_w_imm:
240 case AND_x_imm:
241 mnemonic = "and";
242 break;
243 case ORR_w_imm:
244 case ORR_x_imm: {
245 mnemonic = "orr";
246 unsigned reg_size =
247 (instr->SixtyFourBits() == 1) ? kXRegSizeInBits : kWRegSizeInBits;
248 if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
249 mnemonic = "mov";
250 form = "'Rds, 'ITri";
251 }
252 break;
253 }
254 case EOR_w_imm:
255 case EOR_x_imm:
256 mnemonic = "eor";
257 break;
258 case ANDS_w_imm:
259 case ANDS_x_imm: {
260 mnemonic = "ands";
261 if (rd_is_zr) {
262 mnemonic = "tst";
263 form = "'Rn, 'ITri";
264 }
265 break;
266 }
267 default:
268 UNREACHABLE();
269 }
270 Format(instr, mnemonic, form);
271}
272
273bool DisassemblingDecoder::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
274 DCHECK((reg_size == kXRegSizeInBits) ||
275 ((reg_size == kWRegSizeInBits) && (value <= 0xFFFFFFFF)));
276
277 // Test for movz: 16-bits set at positions 0, 16, 32 or 48.
278 if (((value & 0xFFFFFFFFFFFF0000UL) == 0UL) ||
279 ((value & 0xFFFFFFFF0000FFFFUL) == 0UL) ||
280 ((value & 0xFFFF0000FFFFFFFFUL) == 0UL) ||
281 ((value & 0x0000FFFFFFFFFFFFUL) == 0UL)) {
282 return true;
283 }
284
285 // Test for movn: NOT(16-bits set at positions 0, 16, 32 or 48).
286 if ((reg_size == kXRegSizeInBits) &&
287 (((value & 0xFFFFFFFFFFFF0000UL) == 0xFFFFFFFFFFFF0000UL) ||
288 ((value & 0xFFFFFFFF0000FFFFUL) == 0xFFFFFFFF0000FFFFUL) ||
289 ((value & 0xFFFF0000FFFFFFFFUL) == 0xFFFF0000FFFFFFFFUL) ||
290 ((value & 0x0000FFFFFFFFFFFFUL) == 0x0000FFFFFFFFFFFFUL))) {
291 return true;
292 }
293 if ((reg_size == kWRegSizeInBits) && (((value & 0xFFFF0000) == 0xFFFF0000) ||
294 ((value & 0x0000FFFF) == 0x0000FFFF))) {
295 return true;
296 }
297 return false;
298}
299
300void DisassemblingDecoder::VisitLogicalShifted(Instruction* instr) {
301 bool rd_is_zr = RdIsZROrSP(instr);
302 bool rn_is_zr = RnIsZROrSP(instr);
303 const char* mnemonic = "";
304 const char* form = "'Rd, 'Rn, 'Rm'NLo";
305
306 switch (instr->Mask(LogicalShiftedMask)) {
307 case AND_w:
308 case AND_x:
309 mnemonic = "and";
310 break;
311 case BIC_w:
312 case BIC_x:
313 mnemonic = "bic";
314 break;
315 case EOR_w:
316 case EOR_x:
317 mnemonic = "eor";
318 break;
319 case EON_w:
320 case EON_x:
321 mnemonic = "eon";
322 break;
323 case BICS_w:
324 case BICS_x:
325 mnemonic = "bics";
326 break;
327 case ANDS_w:
328 case ANDS_x: {
329 mnemonic = "ands";
330 if (rd_is_zr) {
331 mnemonic = "tst";
332 form = "'Rn, 'Rm'NLo";
333 }
334 break;
335 }
336 case ORR_w:
337 case ORR_x: {
338 mnemonic = "orr";
339 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
340 mnemonic = "mov";
341 form = "'Rd, 'Rm";
342 }
343 break;
344 }
345 case ORN_w:
346 case ORN_x: {
347 mnemonic = "orn";
348 if (rn_is_zr) {
349 mnemonic = "mvn";
350 form = "'Rd, 'Rm'NLo";
351 }
352 break;
353 }
354 default:
355 UNREACHABLE();
356 }
357
358 Format(instr, mnemonic, form);
359}
360
361void DisassemblingDecoder::VisitConditionalCompareRegister(Instruction* instr) {
362 const char* mnemonic = "";
363 const char* form = "'Rn, 'Rm, 'INzcv, 'Cond";
364
365 switch (instr->Mask(ConditionalCompareRegisterMask)) {
366 case CCMN_w:
367 case CCMN_x:
368 mnemonic = "ccmn";
369 break;
370 case CCMP_w:
371 case CCMP_x:
372 mnemonic = "ccmp";
373 break;
374 default:
375 UNREACHABLE();
376 }
377 Format(instr, mnemonic, form);
378}
379
380void DisassemblingDecoder::VisitConditionalCompareImmediate(
381 Instruction* instr) {
382 const char* mnemonic = "";
383 const char* form = "'Rn, 'IP, 'INzcv, 'Cond";
384
385 switch (instr->Mask(ConditionalCompareImmediateMask)) {
386 case CCMN_w_imm:
387 case CCMN_x_imm:
388 mnemonic = "ccmn";
389 break;
390 case CCMP_w_imm:
391 case CCMP_x_imm:
392 mnemonic = "ccmp";
393 break;
394 default:
395 UNREACHABLE();
396 }
397 Format(instr, mnemonic, form);
398}
399
400void DisassemblingDecoder::VisitConditionalSelect(Instruction* instr) {
401 bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
402 bool rn_is_rm = (instr->Rn() == instr->Rm());
403 const char* mnemonic = "";
404 const char* form = "'Rd, 'Rn, 'Rm, 'Cond";
405 const char* form_test = "'Rd, 'CInv";
406 const char* form_update = "'Rd, 'Rn, 'CInv";
407
408 Condition cond = static_cast<Condition>(instr->Condition());
409 bool invertible_cond = (cond != al) && (cond != nv);
410
411 switch (instr->Mask(ConditionalSelectMask)) {
412 case CSEL_w:
413 case CSEL_x:
414 mnemonic = "csel";
415 break;
416 case CSINC_w:
417 case CSINC_x: {
418 mnemonic = "csinc";
419 if (rnm_is_zr && invertible_cond) {
420 mnemonic = "cset";
421 form = form_test;
422 } else if (rn_is_rm && invertible_cond) {
423 mnemonic = "cinc";
424 form = form_update;
425 }
426 break;
427 }
428 case CSINV_w:
429 case CSINV_x: {
430 mnemonic = "csinv";
431 if (rnm_is_zr && invertible_cond) {
432 mnemonic = "csetm";
433 form = form_test;
434 } else if (rn_is_rm && invertible_cond) {
435 mnemonic = "cinv";
436 form = form_update;
437 }
438 break;
439 }
440 case CSNEG_w:
441 case CSNEG_x: {
442 mnemonic = "csneg";
443 if (rn_is_rm && invertible_cond) {
444 mnemonic = "cneg";
445 form = form_update;
446 }
447 break;
448 }
449 default:
450 UNREACHABLE();
451 }
452 Format(instr, mnemonic, form);
453}
454
455void DisassemblingDecoder::VisitBitfield(Instruction* instr) {
456 unsigned s = instr->ImmS();
457 unsigned r = instr->ImmR();
458 unsigned rd_size_minus_1 =
459 ((instr->SixtyFourBits() == 1) ? kXRegSizeInBits : kWRegSizeInBits) - 1;
460 const char* mnemonic = "";
461 const char* form = "";
462 const char* form_shift_right = "'Rd, 'Rn, 'IBr";
463 const char* form_extend = "'Rd, 'Wn";
464 const char* form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
465 const char* form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
466 const char* form_lsl = "'Rd, 'Rn, 'IBZ-r";
467
468 switch (instr->Mask(BitfieldMask)) {
469 case SBFM_w:
470 case SBFM_x: {
471 mnemonic = "sbfx";
472 form = form_bfx;
473 if (r == 0) {
474 form = form_extend;
475 if (s == 7) {
476 mnemonic = "sxtb";
477 } else if (s == 15) {
478 mnemonic = "sxth";
479 } else if ((s == 31) && (instr->SixtyFourBits() == 1)) {
480 mnemonic = "sxtw";
481 } else {
482 form = form_bfx;
483 }
484 } else if (s == rd_size_minus_1) {
485 mnemonic = "asr";
486 form = form_shift_right;
487 } else if (s < r) {
488 mnemonic = "sbfiz";
489 form = form_bfiz;
490 }
491 break;
492 }
493 case UBFM_w:
494 case UBFM_x: {
495 mnemonic = "ubfx";
496 form = form_bfx;
497 if (r == 0) {
498 form = form_extend;
499 if (s == 7) {
500 mnemonic = "uxtb";
501 } else if (s == 15) {
502 mnemonic = "uxth";
503 } else {
504 form = form_bfx;
505 }
506 }
507 if (s == rd_size_minus_1) {
508 mnemonic = "lsr";
509 form = form_shift_right;
510 } else if (r == s + 1) {
511 mnemonic = "lsl";
512 form = form_lsl;
513 } else if (s < r) {
514 mnemonic = "ubfiz";
515 form = form_bfiz;
516 }
517 break;
518 }
519 case BFM_w:
520 case BFM_x: {
521 mnemonic = "bfxil";
522 form = form_bfx;
523 if (s < r) {
524 mnemonic = "bfi";
525 form = form_bfiz;
526 }
527 }
528 }
529 Format(instr, mnemonic, form);
530}
531
532void DisassemblingDecoder::VisitExtract(Instruction* instr) {
533 const char* mnemonic = "";
534 const char* form = "'Rd, 'Rn, 'Rm, 'IExtract";
535
536 switch (instr->Mask(ExtractMask)) {
537 case EXTR_w:
538 case EXTR_x: {
539 if (instr->Rn() == instr->Rm()) {
540 mnemonic = "ror";
541 form = "'Rd, 'Rn, 'IExtract";
542 } else {
543 mnemonic = "extr";
544 }
545 break;
546 }
547 default:
548 UNREACHABLE();
549 }
550 Format(instr, mnemonic, form);
551}
552
553void DisassemblingDecoder::VisitPCRelAddressing(Instruction* instr) {
554 switch (instr->Mask(PCRelAddressingMask)) {
555 case ADR:
556 Format(instr, "adr", "'Xd, 'AddrPCRelByte");
557 break;
558 // ADRP is not implemented.
559 default:
560 Format(instr, "unimplemented", "(PCRelAddressing)");
561 }
562}
563
564void DisassemblingDecoder::VisitConditionalBranch(Instruction* instr) {
565 switch (instr->Mask(ConditionalBranchMask)) {
566 case B_cond:
567 Format(instr, "b.'CBrn", "'TImmCond");
568 break;
569 default:
570 UNREACHABLE();
571 }
572}
573
574void DisassemblingDecoder::VisitUnconditionalBranchToRegister(
575 Instruction* instr) {
576 const char* mnemonic = "unimplemented";
577 const char* form = "'Xn";
578
580 case BR:
581 mnemonic = "br";
582 break;
583 case BLR:
584 mnemonic = "blr";
585 break;
586 case RET: {
587 mnemonic = "ret";
588 if (instr->Rn() == kLinkRegCode) {
589 form = nullptr;
590 }
591 break;
592 }
593 default:
594 form = "(UnconditionalBranchToRegister)";
595 }
596 Format(instr, mnemonic, form);
597}
598
599void DisassemblingDecoder::VisitUnconditionalBranch(Instruction* instr) {
600 const char* mnemonic = "";
601 const char* form = "'TImmUncn";
602
603 switch (instr->Mask(UnconditionalBranchMask)) {
604 case B:
605 mnemonic = "b";
606 break;
607 case BL:
608 mnemonic = "bl";
609 break;
610 default:
611 UNREACHABLE();
612 }
613 Format(instr, mnemonic, form);
614}
615
616void DisassemblingDecoder::VisitDataProcessing1Source(Instruction* instr) {
617 const char* mnemonic = "";
618 const char* form = "'Rd, 'Rn";
619
620 switch (instr->Mask(DataProcessing1SourceMask)) {
621#define FORMAT(A, B) \
622 case A##_w: \
623 case A##_x: \
624 mnemonic = B; \
625 break;
626 FORMAT(RBIT, "rbit");
627 FORMAT(REV16, "rev16");
628 FORMAT(REV, "rev");
629 FORMAT(CLZ, "clz");
630 FORMAT(CLS, "cls");
631#undef FORMAT
632 case REV32_x:
633 mnemonic = "rev32";
634 break;
635 default:
636 UNREACHABLE();
637 }
638 Format(instr, mnemonic, form);
639}
640
641void DisassemblingDecoder::VisitDataProcessing2Source(Instruction* instr) {
642 const char* mnemonic = "unimplemented";
643 const char* form = "'Rd, 'Rn, 'Rm";
644
645 switch (instr->Mask(DataProcessing2SourceMask)) {
646#define FORMAT(A, B) \
647 case A##_w: \
648 case A##_x: \
649 mnemonic = B; \
650 break;
651 FORMAT(UDIV, "udiv");
652 FORMAT(SDIV, "sdiv");
653 FORMAT(LSLV, "lsl");
654 FORMAT(LSRV, "lsr");
655 FORMAT(ASRV, "asr");
656 FORMAT(RORV, "ror");
657#undef FORMAT
658 default:
659 form = "(DataProcessing2Source)";
660 }
661 Format(instr, mnemonic, form);
662}
663
664void DisassemblingDecoder::VisitDataProcessing3Source(Instruction* instr) {
665 bool ra_is_zr = RaIsZROrSP(instr);
666 const char* mnemonic = "";
667 const char* form = "'Xd, 'Wn, 'Wm, 'Xa";
668 const char* form_rrr = "'Rd, 'Rn, 'Rm";
669 const char* form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
670 const char* form_xww = "'Xd, 'Wn, 'Wm";
671 const char* form_xxx = "'Xd, 'Xn, 'Xm";
672
673 switch (instr->Mask(DataProcessing3SourceMask)) {
674 case MADD_w:
675 case MADD_x: {
676 mnemonic = "madd";
677 form = form_rrrr;
678 if (ra_is_zr) {
679 mnemonic = "mul";
680 form = form_rrr;
681 }
682 break;
683 }
684 case MSUB_w:
685 case MSUB_x: {
686 mnemonic = "msub";
687 form = form_rrrr;
688 if (ra_is_zr) {
689 mnemonic = "mneg";
690 form = form_rrr;
691 }
692 break;
693 }
694 case SMADDL_x: {
695 mnemonic = "smaddl";
696 if (ra_is_zr) {
697 mnemonic = "smull";
698 form = form_xww;
699 }
700 break;
701 }
702 case SMSUBL_x: {
703 mnemonic = "smsubl";
704 if (ra_is_zr) {
705 mnemonic = "smnegl";
706 form = form_xww;
707 }
708 break;
709 }
710 case UMADDL_x: {
711 mnemonic = "umaddl";
712 if (ra_is_zr) {
713 mnemonic = "umull";
714 form = form_xww;
715 }
716 break;
717 }
718 case UMSUBL_x: {
719 mnemonic = "umsubl";
720 if (ra_is_zr) {
721 mnemonic = "umnegl";
722 form = form_xww;
723 }
724 break;
725 }
726 case SMULH_x: {
727 mnemonic = "smulh";
728 form = form_xxx;
729 break;
730 }
731 case UMULH_x: {
732 mnemonic = "umulh";
733 form = form_xxx;
734 break;
735 }
736 default:
737 UNREACHABLE();
738 }
739 Format(instr, mnemonic, form);
740}
741
742void DisassemblingDecoder::VisitCompareBranch(Instruction* instr) {
743 const char* mnemonic = "";
744 const char* form = "'Rt, 'TImmCmpa";
745
746 switch (instr->Mask(CompareBranchMask)) {
747 case CBZ_w:
748 case CBZ_x:
749 mnemonic = "cbz";
750 break;
751 case CBNZ_w:
752 case CBNZ_x:
753 mnemonic = "cbnz";
754 break;
755 default:
756 UNREACHABLE();
757 }
758 Format(instr, mnemonic, form);
759}
760
761void DisassemblingDecoder::VisitTestBranch(Instruction* instr) {
762 const char* mnemonic = "";
763 // If the top bit of the immediate is clear, the tested register is
764 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
765 // encoded in bit 31 of the instruction, we can reuse the Rt form, which
766 // uses bit 31 (normally "sf") to choose the register size.
767 const char* form = "'Rt, 'IS, 'TImmTest";
768
769 switch (instr->Mask(TestBranchMask)) {
770 case TBZ:
771 mnemonic = "tbz";
772 break;
773 case TBNZ:
774 mnemonic = "tbnz";
775 break;
776 default:
777 UNREACHABLE();
778 }
779 Format(instr, mnemonic, form);
780}
781
782void DisassemblingDecoder::VisitMoveWideImmediate(Instruction* instr) {
783 const char* mnemonic = "";
784 const char* form = "'Rd, 'IMoveImm";
785
786 // Print the shift separately for movk, to make it clear which half word will
787 // be overwritten. Movn and movz print the computed immediate, which includes
788 // shift calculation.
789 switch (instr->Mask(MoveWideImmediateMask)) {
790 case MOVN_w:
791 case MOVN_x:
792 mnemonic = "movn";
793 break;
794 case MOVZ_w:
795 case MOVZ_x:
796 mnemonic = "movz";
797 break;
798 case MOVK_w:
799 case MOVK_x:
800 mnemonic = "movk";
801 form = "'Rd, 'IMoveLSL";
802 break;
803 default:
804 UNREACHABLE();
805 }
806 Format(instr, mnemonic, form);
807}
808
809#define LOAD_STORE_LIST(V) \
810 V(STRB_w, "strb", "'Wt") \
811 V(STRH_w, "strh", "'Wt") \
812 V(STR_w, "str", "'Wt") \
813 V(STR_x, "str", "'Xt") \
814 V(LDRB_w, "ldrb", "'Wt") \
815 V(LDRH_w, "ldrh", "'Wt") \
816 V(LDR_w, "ldr", "'Wt") \
817 V(LDR_x, "ldr", "'Xt") \
818 V(LDRSB_x, "ldrsb", "'Xt") \
819 V(LDRSH_x, "ldrsh", "'Xt") \
820 V(LDRSW_x, "ldrsw", "'Xt") \
821 V(LDRSB_w, "ldrsb", "'Wt") \
822 V(LDRSH_w, "ldrsh", "'Wt") \
823 V(STR_b, "str", "'Bt") \
824 V(STR_h, "str", "'Ht") \
825 V(STR_s, "str", "'St") \
826 V(STR_d, "str", "'Dt") \
827 V(LDR_b, "ldr", "'Bt") \
828 V(LDR_h, "ldr", "'Ht") \
829 V(LDR_s, "ldr", "'St") \
830 V(LDR_d, "ldr", "'Dt") \
831 V(STR_q, "str", "'Qt") \
832 V(LDR_q, "ldr", "'Qt")
833
834void DisassemblingDecoder::VisitLoadStorePreIndex(Instruction* instr) {
835 const char* mnemonic = "unimplemented";
836 const char* form = "(LoadStorePreIndex)";
837
838 switch (instr->Mask(LoadStorePreIndexMask)) {
839#define LS_PREINDEX(A, B, C) \
840 case A##_pre: \
841 mnemonic = B; \
842 form = C ", ['Xns'ILS]!"; \
843 break;
844 LOAD_STORE_LIST(LS_PREINDEX)
845#undef LS_PREINDEX
846 }
847 Format(instr, mnemonic, form);
848}
849
850void DisassemblingDecoder::VisitLoadStorePostIndex(Instruction* instr) {
851 const char* mnemonic = "unimplemented";
852 const char* form = "(LoadStorePostIndex)";
853
854 switch (instr->Mask(LoadStorePostIndexMask)) {
855#define LS_POSTINDEX(A, B, C) \
856 case A##_post: \
857 mnemonic = B; \
858 form = C ", ['Xns]'ILS"; \
859 break;
860 LOAD_STORE_LIST(LS_POSTINDEX)
861#undef LS_POSTINDEX
862 }
863 Format(instr, mnemonic, form);
864}
865
866void DisassemblingDecoder::VisitLoadStoreUnsignedOffset(Instruction* instr) {
867 const char* mnemonic = "unimplemented";
868 const char* form = "(LoadStoreUnsignedOffset)";
869
870 switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
871#define LS_UNSIGNEDOFFSET(A, B, C) \
872 case A##_unsigned: \
873 mnemonic = B; \
874 form = C ", ['Xns'ILU]"; \
875 break;
876 LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
877#undef LS_UNSIGNEDOFFSET
878 case PRFM_unsigned:
879 mnemonic = "prfm";
880 form = "'PrefOp, ['Xn'ILU]";
881 }
882 Format(instr, mnemonic, form);
883}
884
885void DisassemblingDecoder::VisitLoadStoreRegisterOffset(Instruction* instr) {
886 const char* mnemonic = "unimplemented";
887 const char* form = "(LoadStoreRegisterOffset)";
888
889 switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
890#define LS_REGISTEROFFSET(A, B, C) \
891 case A##_reg: \
892 mnemonic = B; \
893 form = C ", ['Xns, 'Offsetreg]"; \
894 break;
895 LOAD_STORE_LIST(LS_REGISTEROFFSET)
896#undef LS_REGISTEROFFSET
897 case PRFM_reg:
898 mnemonic = "prfm";
899 form = "'PrefOp, ['Xns, 'Offsetreg]";
900 }
901 Format(instr, mnemonic, form);
902}
903
904#undef LOAD_STORE_LIST
905
906#define LOAD_STORE_UNSCALED_LIST(V) \
907 V(STURB_w, "sturb", "'Wt") \
908 V(STURH_w, "sturh", "'Wt") \
909 V(STUR_w, "stur", "'Wt") \
910 V(STUR_x, "stur", "'Xt") \
911 V(LDURB_w, "ldurb", "'Wt") \
912 V(LDURH_w, "ldurh", "'Wt") \
913 V(LDUR_w, "ldur", "'Wt") \
914 V(LDUR_x, "ldur", "'Xt") \
915 V(LDURSB_x, "ldursb", "'Xt") \
916 V(LDURSH_x, "ldursh", "'Xt") \
917 V(LDURSW_x, "ldursw", "'Xt") \
918 V(LDURSB_w, "ldursb", "'Wt") \
919 V(LDURSH_w, "ldursh", "'Wt") \
920 V(STUR_b, "stur", "'Bt") \
921 V(STUR_h, "stur", "'Ht") \
922 V(STUR_s, "stur", "'St") \
923 V(STUR_d, "stur", "'Dt") \
924 V(LDUR_b, "ldur", "'Bt") \
925 V(LDUR_h, "ldur", "'Ht") \
926 V(LDUR_s, "ldur", "'St") \
927 V(LDUR_d, "ldur", "'Dt") \
928 V(STUR_q, "stur", "'Qt") \
929 V(LDUR_q, "ldur", "'Qt")
930
931void DisassemblingDecoder::VisitLoadStoreUnscaledOffset(Instruction* instr) {
932 const char* mnemonic = "unimplemented";
933 const char* form = "(LoadStoreUnscaledOffset)";
934
935 switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
936#define LS_UNSCALEDOFFSET(A, B, C) \
937 case A: \
938 mnemonic = B; \
939 form = C ", ['Xns'ILS]"; \
940 break;
941 LOAD_STORE_UNSCALED_LIST(LS_UNSCALEDOFFSET)
942#undef LS_UNSCALEDOFFSET
943 }
944 Format(instr, mnemonic, form);
945}
946
947#undef LOAD_STORE_UNSCALED_LIST
948
949void DisassemblingDecoder::VisitLoadLiteral(Instruction* instr) {
950 const char* mnemonic = "ldr";
951 const char* form = "(LoadLiteral)";
952
953 switch (instr->Mask(LoadLiteralMask)) {
954 case LDR_w_lit:
955 form = "'Wt, 'ILLiteral 'LValue";
956 break;
957 case LDR_x_lit:
958 form = "'Xt, 'ILLiteral 'LValue";
959 break;
960 case LDR_s_lit:
961 form = "'St, 'ILLiteral 'LValue";
962 break;
963 case LDR_d_lit:
964 form = "'Dt, 'ILLiteral 'LValue";
965 break;
966 default:
967 mnemonic = "unimplemented";
968 }
969 Format(instr, mnemonic, form);
970}
971
972#define LOAD_STORE_PAIR_LIST(V) \
973 V(STP_w, "stp", "'Wt, 'Wt2", "2") \
974 V(LDP_w, "ldp", "'Wt, 'Wt2", "2") \
975 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "2") \
976 V(STP_x, "stp", "'Xt, 'Xt2", "3") \
977 V(LDP_x, "ldp", "'Xt, 'Xt2", "3") \
978 V(STP_s, "stp", "'St, 'St2", "2") \
979 V(LDP_s, "ldp", "'St, 'St2", "2") \
980 V(STP_d, "stp", "'Dt, 'Dt2", "3") \
981 V(LDP_d, "ldp", "'Dt, 'Dt2", "3") \
982 V(LDP_q, "ldp", "'Qt, 'Qt2", "4") \
983 V(STP_q, "stp", "'Qt, 'Qt2", "4")
984
985void DisassemblingDecoder::VisitLoadStorePairPostIndex(Instruction* instr) {
986 const char* mnemonic = "unimplemented";
987 const char* form = "(LoadStorePairPostIndex)";
988
989 switch (instr->Mask(LoadStorePairPostIndexMask)) {
990#define LSP_POSTINDEX(A, B, C, D) \
991 case A##_post: \
992 mnemonic = B; \
993 form = C ", ['Xns]'ILP" D; \
994 break;
995 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
996#undef LSP_POSTINDEX
997 }
998 Format(instr, mnemonic, form);
999}
1000
1001void DisassemblingDecoder::VisitLoadStorePairPreIndex(Instruction* instr) {
1002 const char* mnemonic = "unimplemented";
1003 const char* form = "(LoadStorePairPreIndex)";
1004
1005 switch (instr->Mask(LoadStorePairPreIndexMask)) {
1006#define LSP_PREINDEX(A, B, C, D) \
1007 case A##_pre: \
1008 mnemonic = B; \
1009 form = C ", ['Xns'ILP" D "]!"; \
1010 break;
1011 LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
1012#undef LSP_PREINDEX
1013 }
1014 Format(instr, mnemonic, form);
1015}
1016
1017void DisassemblingDecoder::VisitLoadStorePairOffset(Instruction* instr) {
1018 const char* mnemonic = "unimplemented";
1019 const char* form = "(LoadStorePairOffset)";
1020
1021 switch (instr->Mask(LoadStorePairOffsetMask)) {
1022#define LSP_OFFSET(A, B, C, D) \
1023 case A##_off: \
1024 mnemonic = B; \
1025 form = C ", ['Xns'ILP" D "]"; \
1026 break;
1027 LOAD_STORE_PAIR_LIST(LSP_OFFSET)
1028#undef LSP_OFFSET
1029 }
1030 Format(instr, mnemonic, form);
1031}
1032
1033#undef LOAD_STORE_PAIR_LIST
1034
1035#define LOAD_STORE_ACQUIRE_RELEASE_LIST(V) \
1036 V(STLXR_b, "stlxrb", "'Ws, 'Wt") \
1037 V(STLXR_h, "stlxrh", "'Ws, 'Wt") \
1038 V(STLXR_w, "stlxr", "'Ws, 'Wt") \
1039 V(STLXR_x, "stlxr", "'Ws, 'Xt") \
1040 V(LDAXR_b, "ldaxrb", "'Wt") \
1041 V(LDAXR_h, "ldaxrh", "'Wt") \
1042 V(LDAXR_w, "ldaxr", "'Wt") \
1043 V(LDAXR_x, "ldaxr", "'Xt") \
1044 V(STLR_b, "stlrb", "'Wt") \
1045 V(STLR_h, "stlrh", "'Wt") \
1046 V(STLR_w, "stlr", "'Wt") \
1047 V(STLR_x, "stlr", "'Xt") \
1048 V(LDAR_b, "ldarb", "'Wt") \
1049 V(LDAR_h, "ldarh", "'Wt") \
1050 V(LDAR_w, "ldar", "'Wt") \
1051 V(LDAR_x, "ldar", "'Xt") \
1052 V(CAS_w, "cas", "'Ws, 'Wt") \
1053 V(CAS_x, "cas", "'Xs, 'Xt") \
1054 V(CASA_w, "casa", "'Ws, 'Wt") \
1055 V(CASA_x, "casa", "'Xs, 'Xt") \
1056 V(CASL_w, "casl", "'Ws, 'Wt") \
1057 V(CASL_x, "casl", "'Xs, 'Xt") \
1058 V(CASAL_w, "casal", "'Ws, 'Wt") \
1059 V(CASAL_x, "casal", "'Xs, 'Xt") \
1060 V(CASB, "casb", "'Ws, 'Wt") \
1061 V(CASAB, "casab", "'Ws, 'Wt") \
1062 V(CASLB, "caslb", "'Ws, 'Wt") \
1063 V(CASALB, "casalb", "'Ws, 'Wt") \
1064 V(CASH, "cash", "'Ws, 'Wt") \
1065 V(CASAH, "casah", "'Ws, 'Wt") \
1066 V(CASLH, "caslh", "'Ws, 'Wt") \
1067 V(CASALH, "casalh", "'Ws, 'Wt") \
1068 V(CASP_w, "casp", "'Ws, 'Ws+, 'Wt, 'Wt+") \
1069 V(CASP_x, "casp", "'Xs, 'Xs+, 'Xt, 'Xt+") \
1070 V(CASPA_w, "caspa", "'Ws, 'Ws+, 'Wt, 'Wt+") \
1071 V(CASPA_x, "caspa", "'Xs, 'Xs+, 'Xt, 'Xt+") \
1072 V(CASPL_w, "caspl", "'Ws, 'Ws+, 'Wt, 'Wt+") \
1073 V(CASPL_x, "caspl", "'Xs, 'Xs+, 'Xt, 'Xt+") \
1074 V(CASPAL_w, "caspal", "'Ws, 'Ws+, 'Wt, 'Wt+") \
1075 V(CASPAL_x, "caspal", "'Xs, 'Xs+, 'Xt, 'Xt+")
1076
1077void DisassemblingDecoder::VisitLoadStoreAcquireRelease(Instruction* instr) {
1078 const char* mnemonic = "unimplemented";
1079 const char* form;
1080
1081 switch (instr->Mask(LoadStoreAcquireReleaseMask)) {
1082#define LSAR(A, B, C) \
1083 case A: \
1084 mnemonic = B; \
1085 form = C ", ['Xns]"; \
1086 break;
1087 LOAD_STORE_ACQUIRE_RELEASE_LIST(LSAR)
1088#undef LSAR
1089 default:
1090 form = "(LoadStoreAcquireRelease)";
1091 }
1092
1093 switch (instr->Mask(LoadStoreAcquireReleaseMask)) {
1094 case CASP_w:
1095 case CASP_x:
1096 case CASPA_w:
1097 case CASPA_x:
1098 case CASPL_w:
1099 case CASPL_x:
1100 case CASPAL_w:
1101 case CASPAL_x:
1102 if ((instr->Rs() % 2 == 1) || (instr->Rt() % 2 == 1)) {
1103 mnemonic = "unallocated";
1104 form = "(LoadStoreExclusive)";
1105 }
1106 break;
1107 }
1108
1109 Format(instr, mnemonic, form);
1110}
1111
1112#undef LOAD_STORE_ACQUIRE_RELEASE_LIST
1113
1114#define ATOMIC_MEMORY_SIMPLE_LIST(V) \
1115 V(LDADD, "add") \
1116 V(LDCLR, "clr") \
1117 V(LDEOR, "eor") \
1118 V(LDSET, "set") \
1119 V(LDSMAX, "smax") \
1120 V(LDSMIN, "smin") \
1121 V(LDUMAX, "umax") \
1122 V(LDUMIN, "umin")
1123
1124void DisassemblingDecoder::VisitAtomicMemory(Instruction* instr) {
1125 const int kMaxAtomicOpMnemonicLength = 16;
1126 const char* mnemonic;
1127 const char* form = "'Ws, 'Wt, ['Xns]";
1128
1129 switch (instr->Mask(AtomicMemoryMask)) {
1130#define AMS(A, MN) \
1131 case A##B: \
1132 mnemonic = MN "b"; \
1133 break; \
1134 case A##AB: \
1135 mnemonic = MN "ab"; \
1136 break; \
1137 case A##LB: \
1138 mnemonic = MN "lb"; \
1139 break; \
1140 case A##ALB: \
1141 mnemonic = MN "alb"; \
1142 break; \
1143 case A##H: \
1144 mnemonic = MN "h"; \
1145 break; \
1146 case A##AH: \
1147 mnemonic = MN "ah"; \
1148 break; \
1149 case A##LH: \
1150 mnemonic = MN "lh"; \
1151 break; \
1152 case A##ALH: \
1153 mnemonic = MN "alh"; \
1154 break; \
1155 case A##_w: \
1156 mnemonic = MN; \
1157 break; \
1158 case A##A_w: \
1159 mnemonic = MN "a"; \
1160 break; \
1161 case A##L_w: \
1162 mnemonic = MN "l"; \
1163 break; \
1164 case A##AL_w: \
1165 mnemonic = MN "al"; \
1166 break; \
1167 case A##_x: \
1168 mnemonic = MN; \
1169 form = "'Xs, 'Xt, ['Xns]"; \
1170 break; \
1171 case A##A_x: \
1172 mnemonic = MN "a"; \
1173 form = "'Xs, 'Xt, ['Xns]"; \
1174 break; \
1175 case A##L_x: \
1176 mnemonic = MN "l"; \
1177 form = "'Xs, 'Xt, ['Xns]"; \
1178 break; \
1179 case A##AL_x: \
1180 mnemonic = MN "al"; \
1181 form = "'Xs, 'Xt, ['Xns]"; \
1182 break;
1183 ATOMIC_MEMORY_SIMPLE_LIST(AMS)
1184
1185 // SWP has the same semantics as ldadd etc but without the store aliases.
1186 AMS(SWP, "swp")
1187#undef AMS
1188
1189 default:
1190 mnemonic = "unimplemented";
1191 form = "(AtomicMemory)";
1192 }
1193
1194 const char* prefix = "";
1195 switch (instr->Mask(AtomicMemoryMask)) {
1196#define AMS(A, MN) \
1197 case A##AB: \
1198 case A##ALB: \
1199 case A##AH: \
1200 case A##ALH: \
1201 case A##A_w: \
1202 case A##AL_w: \
1203 case A##A_x: \
1204 case A##AL_x: \
1205 prefix = "ld"; \
1206 break; \
1207 case A##B: \
1208 case A##LB: \
1209 case A##H: \
1210 case A##LH: \
1211 case A##_w: \
1212 case A##L_w: { \
1213 prefix = "ld"; \
1214 unsigned rt = instr->Rt(); \
1215 if (rt == kZeroRegCode) { \
1216 prefix = "st"; \
1217 form = "'Ws, ['Xns]"; \
1218 } \
1219 break; \
1220 } \
1221 case A##_x: \
1222 case A##L_x: { \
1223 prefix = "ld"; \
1224 unsigned rt = instr->Rt(); \
1225 if (rt == kZeroRegCode) { \
1226 prefix = "st"; \
1227 form = "'Xs, ['Xns]"; \
1228 } \
1229 break; \
1230 }
1231 ATOMIC_MEMORY_SIMPLE_LIST(AMS)
1232#undef AMS
1233 }
1234
1235 char buffer[kMaxAtomicOpMnemonicLength];
1236 if (strlen(prefix) > 0) {
1237 snprintf(buffer, kMaxAtomicOpMnemonicLength, "%s%s", prefix, mnemonic);
1238 mnemonic = buffer;
1239 }
1240
1241 Format(instr, mnemonic, form);
1242}
1243
1244void DisassemblingDecoder::VisitFPCompare(Instruction* instr) {
1245 const char* mnemonic = "unimplemented";
1246 const char* form = "'Fn, 'Fm";
1247 const char* form_zero = "'Fn, #0.0";
1248
1249 switch (instr->Mask(FPCompareMask)) {
1250 case FCMP_s_zero:
1251 case FCMP_d_zero:
1252 form = form_zero;
1253 [[fallthrough]];
1254 case FCMP_s:
1255 case FCMP_d:
1256 mnemonic = "fcmp";
1257 break;
1258 default:
1259 form = "(FPCompare)";
1260 }
1261 Format(instr, mnemonic, form);
1262}
1263
1264void DisassemblingDecoder::VisitFPConditionalCompare(Instruction* instr) {
1265 const char* mnemonic = "unimplemented";
1266 const char* form = "'Fn, 'Fm, 'INzcv, 'Cond";
1267
1268 switch (instr->Mask(FPConditionalCompareMask)) {
1269 case FCCMP_s:
1270 case FCCMP_d:
1271 mnemonic = "fccmp";
1272 break;
1273 case FCCMPE_s:
1274 case FCCMPE_d:
1275 mnemonic = "fccmpe";
1276 break;
1277 default:
1278 form = "(FPConditionalCompare)";
1279 }
1280 Format(instr, mnemonic, form);
1281}
1282
1283void DisassemblingDecoder::VisitFPConditionalSelect(Instruction* instr) {
1284 const char* mnemonic = "";
1285 const char* form = "'Fd, 'Fn, 'Fm, 'Cond";
1286
1287 switch (instr->Mask(FPConditionalSelectMask)) {
1288 case FCSEL_s:
1289 case FCSEL_d:
1290 mnemonic = "fcsel";
1291 break;
1292 default:
1293 UNREACHABLE();
1294 }
1295 Format(instr, mnemonic, form);
1296}
1297
1298void DisassemblingDecoder::VisitFPDataProcessing1Source(Instruction* instr) {
1299 const char* mnemonic = "unimplemented";
1300 const char* form = "'Fd, 'Fn";
1301
1302 switch (instr->Mask(FPDataProcessing1SourceMask)) {
1303#define FORMAT(A, B) \
1304 case A##_s: \
1305 case A##_d: \
1306 mnemonic = B; \
1307 break;
1308 FORMAT(FMOV, "fmov");
1309 FORMAT(FABS, "fabs");
1310 FORMAT(FNEG, "fneg");
1311 FORMAT(FSQRT, "fsqrt");
1312 FORMAT(FRINTN, "frintn");
1313 FORMAT(FRINTP, "frintp");
1314 FORMAT(FRINTM, "frintm");
1315 FORMAT(FRINTZ, "frintz");
1316 FORMAT(FRINTA, "frinta");
1317 FORMAT(FRINTX, "frintx");
1318 FORMAT(FRINTI, "frinti");
1319#undef FORMAT
1320 case FCVT_ds:
1321 mnemonic = "fcvt";
1322 form = "'Dd, 'Sn";
1323 break;
1324 case FCVT_sd:
1325 mnemonic = "fcvt";
1326 form = "'Sd, 'Dn";
1327 break;
1328 case FCVT_hs:
1329 mnemonic = "fcvt";
1330 form = "'Hd, 'Sn";
1331 break;
1332 case FCVT_sh:
1333 mnemonic = "fcvt";
1334 form = "'Sd, 'Hn";
1335 break;
1336 case FCVT_dh:
1337 mnemonic = "fcvt";
1338 form = "'Dd, 'Hn";
1339 break;
1340 case FCVT_hd:
1341 mnemonic = "fcvt";
1342 form = "'Hd, 'Dn";
1343 break;
1344 default:
1345 form = "(FPDataProcessing1Source)";
1346 }
1347 Format(instr, mnemonic, form);
1348}
1349
1350void DisassemblingDecoder::VisitFPDataProcessing2Source(Instruction* instr) {
1351 const char* mnemonic = "";
1352 const char* form = "'Fd, 'Fn, 'Fm";
1353
1354 switch (instr->Mask(FPDataProcessing2SourceMask)) {
1355#define FORMAT(A, B) \
1356 case A##_s: \
1357 case A##_d: \
1358 mnemonic = B; \
1359 break;
1360 FORMAT(FMUL, "fmul");
1361 FORMAT(FDIV, "fdiv");
1362 FORMAT(FADD, "fadd");
1363 FORMAT(FSUB, "fsub");
1364 FORMAT(FMAX, "fmax");
1365 FORMAT(FMIN, "fmin");
1366 FORMAT(FMAXNM, "fmaxnm");
1367 FORMAT(FMINNM, "fminnm");
1368 FORMAT(FNMUL, "fnmul");
1369#undef FORMAT
1370 default:
1371 UNREACHABLE();
1372 }
1373 Format(instr, mnemonic, form);
1374}
1375
1376void DisassemblingDecoder::VisitFPDataProcessing3Source(Instruction* instr) {
1377 const char* mnemonic = "";
1378 const char* form = "'Fd, 'Fn, 'Fm, 'Fa";
1379
1380 switch (instr->Mask(FPDataProcessing3SourceMask)) {
1381#define FORMAT(A, B) \
1382 case A##_s: \
1383 case A##_d: \
1384 mnemonic = B; \
1385 break;
1386 FORMAT(FMADD, "fmadd");
1387 FORMAT(FMSUB, "fmsub");
1388 FORMAT(FNMADD, "fnmadd");
1389 FORMAT(FNMSUB, "fnmsub");
1390#undef FORMAT
1391 default:
1392 UNREACHABLE();
1393 }
1394 Format(instr, mnemonic, form);
1395}
1396
1397void DisassemblingDecoder::VisitFPImmediate(Instruction* instr) {
1398 const char* mnemonic = "";
1399 const char* form = "(FPImmediate)";
1400
1401 switch (instr->Mask(FPImmediateMask)) {
1402 case FMOV_s_imm:
1403 mnemonic = "fmov";
1404 form = "'Sd, 'IFPSingle";
1405 break;
1406 case FMOV_d_imm:
1407 mnemonic = "fmov";
1408 form = "'Dd, 'IFPDouble";
1409 break;
1410 default:
1411 UNREACHABLE();
1412 }
1413 Format(instr, mnemonic, form);
1414}
1415
1416void DisassemblingDecoder::VisitFPIntegerConvert(Instruction* instr) {
1417 const char* mnemonic = "unimplemented";
1418 const char* form = "(FPIntegerConvert)";
1419 const char* form_rf = "'Rd, 'Fn";
1420 const char* form_fr = "'Fd, 'Rn";
1421
1422 switch (instr->Mask(FPIntegerConvertMask)) {
1423 case FMOV_ws:
1424 case FMOV_xd:
1425 mnemonic = "fmov";
1426 form = form_rf;
1427 break;
1428 case FMOV_sw:
1429 case FMOV_dx:
1430 mnemonic = "fmov";
1431 form = form_fr;
1432 break;
1433 case FMOV_d1_x:
1434 mnemonic = "fmov";
1435 form = "'Vd.D[1], 'Rn";
1436 break;
1437 case FMOV_x_d1:
1438 mnemonic = "fmov";
1439 form = "'Rd, 'Vn.D[1]";
1440 break;
1441 case FCVTAS_ws:
1442 case FCVTAS_xs:
1443 case FCVTAS_wd:
1444 case FCVTAS_xd:
1445 mnemonic = "fcvtas";
1446 form = form_rf;
1447 break;
1448 case FCVTAU_ws:
1449 case FCVTAU_xs:
1450 case FCVTAU_wd:
1451 case FCVTAU_xd:
1452 mnemonic = "fcvtau";
1453 form = form_rf;
1454 break;
1455 case FCVTMS_ws:
1456 case FCVTMS_xs:
1457 case FCVTMS_wd:
1458 case FCVTMS_xd:
1459 mnemonic = "fcvtms";
1460 form = form_rf;
1461 break;
1462 case FCVTMU_ws:
1463 case FCVTMU_xs:
1464 case FCVTMU_wd:
1465 case FCVTMU_xd:
1466 mnemonic = "fcvtmu";
1467 form = form_rf;
1468 break;
1469 case FCVTNS_ws:
1470 case FCVTNS_xs:
1471 case FCVTNS_wd:
1472 case FCVTNS_xd:
1473 mnemonic = "fcvtns";
1474 form = form_rf;
1475 break;
1476 case FCVTNU_ws:
1477 case FCVTNU_xs:
1478 case FCVTNU_wd:
1479 case FCVTNU_xd:
1480 mnemonic = "fcvtnu";
1481 form = form_rf;
1482 break;
1483 case FCVTZU_xd:
1484 case FCVTZU_ws:
1485 case FCVTZU_wd:
1486 case FCVTZU_xs:
1487 mnemonic = "fcvtzu";
1488 form = form_rf;
1489 break;
1490 case FCVTZS_xd:
1491 case FCVTZS_wd:
1492 case FCVTZS_xs:
1493 case FCVTZS_ws:
1494 mnemonic = "fcvtzs";
1495 form = form_rf;
1496 break;
1497 case FCVTPU_xd:
1498 case FCVTPU_ws:
1499 case FCVTPU_wd:
1500 case FCVTPU_xs:
1501 mnemonic = "fcvtpu";
1502 form = form_rf;
1503 break;
1504 case FCVTPS_xd:
1505 case FCVTPS_wd:
1506 case FCVTPS_xs:
1507 case FCVTPS_ws:
1508 mnemonic = "fcvtps";
1509 form = form_rf;
1510 break;
1511 case SCVTF_sw:
1512 case SCVTF_sx:
1513 case SCVTF_dw:
1514 case SCVTF_dx:
1515 mnemonic = "scvtf";
1516 form = form_fr;
1517 break;
1518 case UCVTF_sw:
1519 case UCVTF_sx:
1520 case UCVTF_dw:
1521 case UCVTF_dx:
1522 mnemonic = "ucvtf";
1523 form = form_fr;
1524 break;
1525 case FJCVTZS:
1526 mnemonic = "fjcvtzs";
1527 form = form_rf;
1528 break;
1529 }
1530 Format(instr, mnemonic, form);
1531}
1532
1533void DisassemblingDecoder::VisitFPFixedPointConvert(Instruction* instr) {
1534 const char* mnemonic = "";
1535 const char* form = "'Rd, 'Fn, 'IFPFBits";
1536 const char* form_fr = "'Fd, 'Rn, 'IFPFBits";
1537
1538 switch (instr->Mask(FPFixedPointConvertMask)) {
1539 case FCVTZS_ws_fixed:
1540 case FCVTZS_xs_fixed:
1541 case FCVTZS_wd_fixed:
1542 case FCVTZS_xd_fixed:
1543 mnemonic = "fcvtzs";
1544 break;
1545 case FCVTZU_ws_fixed:
1546 case FCVTZU_xs_fixed:
1547 case FCVTZU_wd_fixed:
1548 case FCVTZU_xd_fixed:
1549 mnemonic = "fcvtzu";
1550 break;
1551 case SCVTF_sw_fixed:
1552 case SCVTF_sx_fixed:
1553 case SCVTF_dw_fixed:
1554 case SCVTF_dx_fixed:
1555 mnemonic = "scvtf";
1556 form = form_fr;
1557 break;
1558 case UCVTF_sw_fixed:
1559 case UCVTF_sx_fixed:
1560 case UCVTF_dw_fixed:
1561 case UCVTF_dx_fixed:
1562 mnemonic = "ucvtf";
1563 form = form_fr;
1564 break;
1565 }
1566 Format(instr, mnemonic, form);
1567}
1568
1569// clang-format off
1570#define PAUTH_SYSTEM_MNEMONICS(V) \
1571 V(PACIB1716, "pacib1716") \
1572 V(AUTIB1716, "autib1716") \
1573 V(PACIBSP, "pacibsp") \
1574 V(AUTIBSP, "autibsp")
1575// clang-format on
1576
1577void DisassemblingDecoder::VisitSystem(Instruction* instr) {
1578 // Some system instructions hijack their Op and Cp fields to represent a
1579 // range of immediates instead of indicating a different instruction. This
1580 // makes the decoding tricky.
1581 const char* mnemonic = "unimplemented";
1582 const char* form = "(System)";
1583 if (instr->Mask(SystemPAuthFMask) == SystemPAuthFixed) {
1584 switch (instr->Mask(SystemPAuthMask)) {
1585#define PAUTH_CASE(NAME, MN) \
1586 case NAME: \
1587 mnemonic = MN; \
1588 form = nullptr; \
1589 break;
1590
1591 PAUTH_SYSTEM_MNEMONICS(PAUTH_CASE)
1592#undef PAUTH_CASE
1593#undef PAUTH_SYSTEM_MNEMONICS
1594 }
1595 } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1596 switch (instr->Mask(SystemSysRegMask)) {
1597 case MRS: {
1598 mnemonic = "mrs";
1599 switch (instr->ImmSystemRegister()) {
1600 case NZCV:
1601 form = "'Xt, nzcv";
1602 break;
1603 case FPCR:
1604 form = "'Xt, fpcr";
1605 break;
1606 default:
1607 form = "'Xt, (unknown)";
1608 break;
1609 }
1610 break;
1611 }
1612 case MSR: {
1613 mnemonic = "msr";
1614 switch (instr->ImmSystemRegister()) {
1615 case NZCV:
1616 form = "nzcv, 'Xt";
1617 break;
1618 case FPCR:
1619 form = "fpcr, 'Xt";
1620 break;
1621 default:
1622 form = "(unknown), 'Xt";
1623 break;
1624 }
1625 break;
1626 }
1627 }
1628 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1629 DCHECK(instr->Mask(SystemHintMask) == HINT);
1630 form = nullptr;
1631 switch (instr->ImmHint()) {
1632 case NOP:
1633 mnemonic = "nop";
1634 break;
1635 case YIELD:
1636 mnemonic = "yield";
1637 break;
1638 case CSDB:
1639 mnemonic = "csdb";
1640 break;
1641 case BTI:
1642 mnemonic = "bti";
1643 break;
1644 case BTI_c:
1645 mnemonic = "bti c";
1646 break;
1647 case BTI_j:
1648 mnemonic = "bti j";
1649 break;
1650 case BTI_jc:
1651 mnemonic = "bti jc";
1652 break;
1653 default:
1654 // Fall back to 'hint #<imm7>'.
1655 form = "'IH";
1656 mnemonic = "hint";
1657 }
1658 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
1659 switch (instr->Mask(MemBarrierMask)) {
1660 case DMB: {
1661 mnemonic = "dmb";
1662 form = "'M";
1663 break;
1664 }
1665 case DSB: {
1666 mnemonic = "dsb";
1667 form = "'M";
1668 break;
1669 }
1670 case ISB: {
1671 mnemonic = "isb";
1672 form = nullptr;
1673 break;
1674 }
1675 }
1676 }
1677
1678 Format(instr, mnemonic, form);
1679}
1680
1681void DisassemblingDecoder::VisitException(Instruction* instr) {
1682 const char* mnemonic = "unimplemented";
1683 const char* form = "'IDebug";
1684
1685 switch (instr->Mask(ExceptionMask)) {
1686 case HLT:
1687 mnemonic = "hlt";
1688 break;
1689 case BRK:
1690 mnemonic = "brk";
1691 break;
1692 case SVC:
1693 mnemonic = "svc";
1694 break;
1695 case HVC:
1696 mnemonic = "hvc";
1697 break;
1698 case SMC:
1699 mnemonic = "smc";
1700 break;
1701 case DCPS1:
1702 mnemonic = "dcps1";
1703 form = "{'IDebug}";
1704 break;
1705 case DCPS2:
1706 mnemonic = "dcps2";
1707 form = "{'IDebug}";
1708 break;
1709 case DCPS3:
1710 mnemonic = "dcps3";
1711 form = "{'IDebug}";
1712 break;
1713 default:
1714 form = "(Exception)";
1715 }
1716 Format(instr, mnemonic, form);
1717}
1718
1719void DisassemblingDecoder::VisitNEON3Same(Instruction* instr) {
1720 const char* mnemonic = "unimplemented";
1721 const char* form = "'Vd.%s, 'Vn.%s, 'Vm.%s";
1722 NEONFormatDecoder nfd(instr);
1723
1725 switch (instr->Mask(NEON3SameLogicalMask)) {
1726 case NEON_AND:
1727 mnemonic = "and";
1728 break;
1729 case NEON_ORR:
1730 mnemonic = "orr";
1731 if (instr->Rm() == instr->Rn()) {
1732 mnemonic = "mov";
1733 form = "'Vd.%s, 'Vn.%s";
1734 }
1735 break;
1736 case NEON_ORN:
1737 mnemonic = "orn";
1738 break;
1739 case NEON_EOR:
1740 mnemonic = "eor";
1741 break;
1742 case NEON_BIC:
1743 mnemonic = "bic";
1744 break;
1745 case NEON_BIF:
1746 mnemonic = "bif";
1747 break;
1748 case NEON_BIT:
1749 mnemonic = "bit";
1750 break;
1751 case NEON_BSL:
1752 mnemonic = "bsl";
1753 break;
1754 default:
1755 form = "(NEON3Same)";
1756 }
1757 nfd.SetFormatMaps(nfd.LogicalFormatMap());
1758 } else {
1759 static const char* mnemonics[] = {
1760 "shadd", "uhadd", "shadd", "uhadd",
1761 "sqadd", "uqadd", "sqadd", "uqadd",
1762 "srhadd", "urhadd", "srhadd", "urhadd",
1763 nullptr, nullptr, nullptr,
1764 nullptr, // Handled by logical cases above.
1765 "shsub", "uhsub", "shsub", "uhsub",
1766 "sqsub", "uqsub", "sqsub", "uqsub",
1767 "cmgt", "cmhi", "cmgt", "cmhi",
1768 "cmge", "cmhs", "cmge", "cmhs",
1769 "sshl", "ushl", "sshl", "ushl",
1770 "sqshl", "uqshl", "sqshl", "uqshl",
1771 "srshl", "urshl", "srshl", "urshl",
1772 "sqrshl", "uqrshl", "sqrshl", "uqrshl",
1773 "smax", "umax", "smax", "umax",
1774 "smin", "umin", "smin", "umin",
1775 "sabd", "uabd", "sabd", "uabd",
1776 "saba", "uaba", "saba", "uaba",
1777 "add", "sub", "add", "sub",
1778 "cmtst", "cmeq", "cmtst", "cmeq",
1779 "mla", "mls", "mla", "mls",
1780 "mul", "pmul", "mul", "pmul",
1781 "smaxp", "umaxp", "smaxp", "umaxp",
1782 "sminp", "uminp", "sminp", "uminp",
1783 "sqdmulh", "sqrdmulh", "sqdmulh", "sqrdmulh",
1784 "addp", "unallocated", "addp", "unallocated",
1785 "fmaxnm", "fmaxnmp", "fminnm", "fminnmp",
1786 "fmla", "unallocated", "fmls", "unallocated",
1787 "fadd", "faddp", "fsub", "fabd",
1788 "fmulx", "fmul", "unallocated", "unallocated",
1789 "fcmeq", "fcmge", "unallocated", "fcmgt",
1790 "unallocated", "facge", "unallocated", "facgt",
1791 "fmax", "fmaxp", "fmin", "fminp",
1792 "frecps", "fdiv", "frsqrts", "unallocated"};
1793
1794 // Operation is determined by the opcode bits (15-11), the top bit of
1795 // size (23) and the U bit (29).
1796 unsigned index =
1797 (instr->Bits(15, 11) << 2) | (instr->Bit(23) << 1) | instr->Bit(29);
1798 DCHECK_LT(index, arraysize(mnemonics));
1799 mnemonic = mnemonics[index];
1800 // Assert that index is not one of the previously handled logical
1801 // instructions.
1802 DCHECK_NOT_NULL(mnemonic);
1803
1804 if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
1805 nfd.SetFormatMaps(nfd.FPFormatMap());
1806 }
1807 }
1808 Format(instr, mnemonic, nfd.Substitute(form));
1809}
1810
1811void DisassemblingDecoder::VisitNEON3SameHP(Instruction* instr) {
1812 const char* mnemonic = "unimplemented";
1813 const char* form = "'Vd.%s, 'Vn.%s, 'Vm.%s";
1814 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPHPFormatMap());
1815
1816 static const char* mnemonics[] = {
1817 "fmaxnm", "fmaxnmp", "fminnm", "fminnmp", "fmla", "uqadd", "fmls",
1818 "uqadd", "fadd", "faddp", "fsub", "fabd", "fmulx", "fmul",
1819 "fmul", "fmul", "fcmeq", "fcmge", "shsub", "fcmgt", "sqsub",
1820 "facge", "sqsub", "facgt", "fmax", "fmaxp", "fmin", "fminp",
1821 "frecps", "fdiv", "frsqrts", "fdiv"};
1822
1823 // Operation is determined by the opcode bits (13-11), the top bit of
1824 // size (23) and the U bit (29).
1825 unsigned index =
1826 (instr->Bits(13, 11) << 2) | (instr->Bit(23) << 1) | instr->Bit(29);
1827 DCHECK_LT(index, arraysize(mnemonics));
1828 mnemonic = mnemonics[index];
1829
1830 Format(instr, mnemonic, nfd.Substitute(form));
1831}
1832
1833void DisassemblingDecoder::VisitNEON2RegMisc(Instruction* instr) {
1834 const char* mnemonic = "unimplemented";
1835 const char* form = "'Vd.%s, 'Vn.%s";
1836 const char* form_cmp_zero = "'Vd.%s, 'Vn.%s, #0";
1837 const char* form_fcmp_zero = "'Vd.%s, 'Vn.%s, #0.0";
1838 NEONFormatDecoder nfd(instr);
1839
1840 static const NEONFormatMap map_lp_ta = {
1841 {23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}};
1842
1843 static const NEONFormatMap map_cvt_ta = {{22}, {NF_4S, NF_2D}};
1844
1845 static const NEONFormatMap map_cvt_tb = {{22, 30},
1846 {NF_4H, NF_8H, NF_2S, NF_4S}};
1847
1849 // These instructions all use a two bit size field, except NOT and RBIT,
1850 // which use the field to encode the operation.
1851 switch (instr->Mask(NEON2RegMiscMask)) {
1852 case NEON_REV64:
1853 mnemonic = "rev64";
1854 break;
1855 case NEON_REV32:
1856 mnemonic = "rev32";
1857 break;
1858 case NEON_REV16:
1859 mnemonic = "rev16";
1860 break;
1861 case NEON_SADDLP:
1862 mnemonic = "saddlp";
1863 nfd.SetFormatMap(0, &map_lp_ta);
1864 break;
1865 case NEON_UADDLP:
1866 mnemonic = "uaddlp";
1867 nfd.SetFormatMap(0, &map_lp_ta);
1868 break;
1869 case NEON_SUQADD:
1870 mnemonic = "suqadd";
1871 break;
1872 case NEON_USQADD:
1873 mnemonic = "usqadd";
1874 break;
1875 case NEON_CLS:
1876 mnemonic = "cls";
1877 break;
1878 case NEON_CLZ:
1879 mnemonic = "clz";
1880 break;
1881 case NEON_CNT:
1882 mnemonic = "cnt";
1883 break;
1884 case NEON_SADALP:
1885 mnemonic = "sadalp";
1886 nfd.SetFormatMap(0, &map_lp_ta);
1887 break;
1888 case NEON_UADALP:
1889 mnemonic = "uadalp";
1890 nfd.SetFormatMap(0, &map_lp_ta);
1891 break;
1892 case NEON_SQABS:
1893 mnemonic = "sqabs";
1894 break;
1895 case NEON_SQNEG:
1896 mnemonic = "sqneg";
1897 break;
1898 case NEON_CMGT_zero:
1899 mnemonic = "cmgt";
1900 form = form_cmp_zero;
1901 break;
1902 case NEON_CMGE_zero:
1903 mnemonic = "cmge";
1904 form = form_cmp_zero;
1905 break;
1906 case NEON_CMEQ_zero:
1907 mnemonic = "cmeq";
1908 form = form_cmp_zero;
1909 break;
1910 case NEON_CMLE_zero:
1911 mnemonic = "cmle";
1912 form = form_cmp_zero;
1913 break;
1914 case NEON_CMLT_zero:
1915 mnemonic = "cmlt";
1916 form = form_cmp_zero;
1917 break;
1918 case NEON_ABS:
1919 mnemonic = "abs";
1920 break;
1921 case NEON_NEG:
1922 mnemonic = "neg";
1923 break;
1924 case NEON_RBIT_NOT:
1925 switch (instr->FPType()) {
1926 case 0:
1927 mnemonic = "mvn";
1928 break;
1929 case 1:
1930 mnemonic = "rbit";
1931 break;
1932 default:
1933 form = "(NEON2RegMisc)";
1934 }
1935 nfd.SetFormatMaps(nfd.LogicalFormatMap());
1936 break;
1937 }
1938 } else {
1939 // These instructions all use a one bit size field, except XTN, SQXTUN,
1940 // SHLL, SQXTN and UQXTN, which use a two bit size field.
1942 nfd.SetFormatMaps(nfd.FPHPFormatMap());
1943 } else {
1944 nfd.SetFormatMaps(nfd.FPFormatMap());
1945 }
1946 switch (instr->Mask(NEON2RegMiscFPMask ^ NEON2RegMiscHPFixed)) {
1947 case NEON_FABS:
1948 mnemonic = "fabs";
1949 break;
1950 case NEON_FNEG:
1951 mnemonic = "fneg";
1952 break;
1953 case NEON_FCVTN:
1954 mnemonic = instr->Mask(NEON_Q) ? "fcvtn2" : "fcvtn";
1955 nfd.SetFormatMap(0, &map_cvt_tb);
1956 nfd.SetFormatMap(1, &map_cvt_ta);
1957 break;
1958 case NEON_FCVTXN:
1959 mnemonic = instr->Mask(NEON_Q) ? "fcvtxn2" : "fcvtxn";
1960 nfd.SetFormatMap(0, &map_cvt_tb);
1961 nfd.SetFormatMap(1, &map_cvt_ta);
1962 break;
1963 case NEON_FCVTL:
1964 mnemonic = instr->Mask(NEON_Q) ? "fcvtl2" : "fcvtl";
1965 nfd.SetFormatMap(0, &map_cvt_ta);
1966 nfd.SetFormatMap(1, &map_cvt_tb);
1967 break;
1968 case NEON_FRINTN:
1969 mnemonic = "frintn";
1970 break;
1971 case NEON_FRINTA:
1972 mnemonic = "frinta";
1973 break;
1974 case NEON_FRINTP:
1975 mnemonic = "frintp";
1976 break;
1977 case NEON_FRINTM:
1978 mnemonic = "frintm";
1979 break;
1980 case NEON_FRINTX:
1981 mnemonic = "frintx";
1982 break;
1983 case NEON_FRINTZ:
1984 mnemonic = "frintz";
1985 break;
1986 case NEON_FRINTI:
1987 mnemonic = "frinti";
1988 break;
1989 case NEON_FCVTNS:
1990 mnemonic = "fcvtns";
1991 break;
1992 case NEON_FCVTNU:
1993 mnemonic = "fcvtnu";
1994 break;
1995 case NEON_FCVTPS:
1996 mnemonic = "fcvtps";
1997 break;
1998 case NEON_FCVTPU:
1999 mnemonic = "fcvtpu";
2000 break;
2001 case NEON_FCVTMS:
2002 mnemonic = "fcvtms";
2003 break;
2004 case NEON_FCVTMU:
2005 mnemonic = "fcvtmu";
2006 break;
2007 case NEON_FCVTZS:
2008 mnemonic = "fcvtzs";
2009 break;
2010 case NEON_FCVTZU:
2011 mnemonic = "fcvtzu";
2012 break;
2013 case NEON_FCVTAS:
2014 mnemonic = "fcvtas";
2015 break;
2016 case NEON_FCVTAU:
2017 mnemonic = "fcvtau";
2018 break;
2019 case NEON_FSQRT:
2020 mnemonic = "fsqrt";
2021 break;
2022 case NEON_SCVTF:
2023 mnemonic = "scvtf";
2024 break;
2025 case NEON_UCVTF:
2026 mnemonic = "ucvtf";
2027 break;
2028 case NEON_URSQRTE:
2029 mnemonic = "ursqrte";
2030 break;
2031 case NEON_URECPE:
2032 mnemonic = "urecpe";
2033 break;
2034 case NEON_FRSQRTE:
2035 mnemonic = "frsqrte";
2036 break;
2037 case NEON_FRECPE:
2038 mnemonic = "frecpe";
2039 break;
2040 case NEON_FCMGT_zero:
2041 mnemonic = "fcmgt";
2042 form = form_fcmp_zero;
2043 break;
2044 case NEON_FCMGE_zero:
2045 mnemonic = "fcmge";
2046 form = form_fcmp_zero;
2047 break;
2048 case NEON_FCMEQ_zero:
2049 mnemonic = "fcmeq";
2050 form = form_fcmp_zero;
2051 break;
2052 case NEON_FCMLE_zero:
2053 mnemonic = "fcmle";
2054 form = form_fcmp_zero;
2055 break;
2056 case NEON_FCMLT_zero:
2057 mnemonic = "fcmlt";
2058 form = form_fcmp_zero;
2059 break;
2060 default:
2063 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2064 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
2065
2066 switch (instr->Mask(NEON2RegMiscMask)) {
2067 case NEON_XTN:
2068 mnemonic = "xtn";
2069 break;
2070 case NEON_SQXTN:
2071 mnemonic = "sqxtn";
2072 break;
2073 case NEON_UQXTN:
2074 mnemonic = "uqxtn";
2075 break;
2076 case NEON_SQXTUN:
2077 mnemonic = "sqxtun";
2078 break;
2079 case NEON_SHLL:
2080 mnemonic = "shll";
2081 nfd.SetFormatMap(0, nfd.LongIntegerFormatMap());
2082 nfd.SetFormatMap(1, nfd.IntegerFormatMap());
2083 switch (instr->NEONSize()) {
2084 case 0:
2085 form = "'Vd.%s, 'Vn.%s, #8";
2086 break;
2087 case 1:
2088 form = "'Vd.%s, 'Vn.%s, #16";
2089 break;
2090 case 2:
2091 form = "'Vd.%s, 'Vn.%s, #32";
2092 break;
2093 default:
2094 Format(instr, "unallocated", "(NEON2RegMisc)");
2095 return;
2096 }
2097 }
2098 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));
2099 return;
2100 } else {
2101 form = "(NEON2RegMisc)";
2102 }
2103 }
2104 }
2105 Format(instr, mnemonic, nfd.Substitute(form));
2106}
2107
2108void DisassemblingDecoder::VisitNEON3Different(Instruction* instr) {
2109 const char* mnemonic = "unimplemented";
2110 const char* form = "'Vd.%s, 'Vn.%s, 'Vm.%s";
2111
2112 NEONFormatDecoder nfd(instr);
2113 nfd.SetFormatMap(0, nfd.LongIntegerFormatMap());
2114
2115 // Ignore the Q bit. Appending a "2" suffix is handled later.
2116 switch (instr->Mask(NEON3DifferentMask) & ~NEON_Q) {
2117 case NEON_PMULL:
2119 return;
2120 case NEON_SABAL:
2121 mnemonic = "sabal";
2122 break;
2123 case NEON_SABDL:
2124 mnemonic = "sabdl";
2125 break;
2126 case NEON_SADDL:
2127 mnemonic = "saddl";
2128 break;
2129 case NEON_SMLAL:
2130 mnemonic = "smlal";
2131 break;
2132 case NEON_SMLSL:
2133 mnemonic = "smlsl";
2134 break;
2135 case NEON_SMULL:
2136 mnemonic = "smull";
2137 break;
2138 case NEON_SSUBL:
2139 mnemonic = "ssubl";
2140 break;
2141 case NEON_SQDMLAL:
2142 mnemonic = "sqdmlal";
2143 break;
2144 case NEON_SQDMLSL:
2145 mnemonic = "sqdmlsl";
2146 break;
2147 case NEON_SQDMULL:
2148 mnemonic = "sqdmull";
2149 break;
2150 case NEON_UABAL:
2151 mnemonic = "uabal";
2152 break;
2153 case NEON_UABDL:
2154 mnemonic = "uabdl";
2155 break;
2156 case NEON_UADDL:
2157 mnemonic = "uaddl";
2158 break;
2159 case NEON_UMLAL:
2160 mnemonic = "umlal";
2161 break;
2162 case NEON_UMLSL:
2163 mnemonic = "umlsl";
2164 break;
2165 case NEON_UMULL:
2166 mnemonic = "umull";
2167 break;
2168 case NEON_USUBL:
2169 mnemonic = "usubl";
2170 break;
2171 case NEON_SADDW:
2172 mnemonic = "saddw";
2173 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
2174 break;
2175 case NEON_SSUBW:
2176 mnemonic = "ssubw";
2177 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
2178 break;
2179 case NEON_UADDW:
2180 mnemonic = "uaddw";
2181 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
2182 break;
2183 case NEON_USUBW:
2184 mnemonic = "usubw";
2185 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
2186 break;
2187 case NEON_ADDHN:
2188 mnemonic = "addhn";
2189 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
2190 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2191 break;
2192 case NEON_RADDHN:
2193 mnemonic = "raddhn";
2194 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
2195 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2196 break;
2197 case NEON_RSUBHN:
2198 mnemonic = "rsubhn";
2199 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
2200 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2201 break;
2202 case NEON_SUBHN:
2203 mnemonic = "subhn";
2204 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
2205 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2206 break;
2207 default:
2208 form = "(NEON3Different)";
2209 }
2210 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));
2211}
2212
2213void DisassemblingDecoder::VisitNEON3Extension(Instruction* instr) {
2214 const char* form = "'Vd.%s, 'Vn.%s, 'Vm.%s";
2215 const char* mnemonic = "unimplemented";
2216
2217 switch (instr->Mask(NEON3ExtensionMask)) {
2218 case NEON_SDOT:
2219 if (instr->NEONSize() != 2) {
2220 VisitUnallocated(instr);
2221 return;
2222 }
2223
2224 form = instr->Bit(30) == 1 ? "'Vd.4s, 'Vn.16b, 'Vm.16b"
2225 : "'Vd.2s, 'Vn.8b, 'Vm.8b";
2226 mnemonic = "sdot";
2227 break;
2228 default:
2229 form = "(NEON3Extension)";
2230 }
2231
2232 Format(instr, mnemonic, form);
2233}
2234
2235void DisassemblingDecoder::VisitNEONAcrossLanes(Instruction* instr) {
2236 const char* mnemonic = "unimplemented";
2237 const char* form = "%sd, 'Vn.%s";
2238
2239 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap(),
2241
2243 nfd.SetFormatMap(0, nfd.FPScalarFormatMap());
2244 nfd.SetFormatMap(1, nfd.FPFormatMap());
2245 switch (instr->Mask(NEONAcrossLanesFPMask)) {
2246 case NEON_FMAXV:
2247 mnemonic = "fmaxv";
2248 break;
2249 case NEON_FMINV:
2250 mnemonic = "fminv";
2251 break;
2252 case NEON_FMAXNMV:
2253 mnemonic = "fmaxnmv";
2254 break;
2255 case NEON_FMINNMV:
2256 mnemonic = "fminnmv";
2257 break;
2258 default:
2259 form = "(NEONAcrossLanes)";
2260 break;
2261 }
2262 } else if (instr->Mask(NEONAcrossLanesFMask) == NEONAcrossLanesFixed) {
2263 switch (instr->Mask(NEONAcrossLanesMask)) {
2264 case NEON_ADDV:
2265 mnemonic = "addv";
2266 break;
2267 case NEON_SMAXV:
2268 mnemonic = "smaxv";
2269 break;
2270 case NEON_SMINV:
2271 mnemonic = "sminv";
2272 break;
2273 case NEON_UMAXV:
2274 mnemonic = "umaxv";
2275 break;
2276 case NEON_UMINV:
2277 mnemonic = "uminv";
2278 break;
2279 case NEON_SADDLV:
2280 mnemonic = "saddlv";
2281 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
2282 break;
2283 case NEON_UADDLV:
2284 mnemonic = "uaddlv";
2285 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
2286 break;
2287 default:
2288 form = "(NEONAcrossLanes)";
2289 break;
2290 }
2291 }
2292 Format(instr, mnemonic,
2293 nfd.Substitute(form, NEONFormatDecoder::kPlaceholder,
2295}
2296
2297void DisassemblingDecoder::VisitNEONByIndexedElement(Instruction* instr) {
2298 const char* mnemonic = "unimplemented";
2299 bool l_instr = false;
2300 bool fp_instr = false;
2301
2302 const char* form = "'Vd.%s, 'Vn.%s, 'Ve.%s['IVByElemIndex]";
2303
2304 static const NEONFormatMap map_ta = {{23, 22}, {NF_UNDEF, NF_4S, NF_2D}};
2305 NEONFormatDecoder nfd(instr, &map_ta, NEONFormatDecoder::IntegerFormatMap(),
2307
2308 switch (instr->Mask(NEONByIndexedElementMask)) {
2310 mnemonic = "smull";
2311 l_instr = true;
2312 break;
2314 mnemonic = "umull";
2315 l_instr = true;
2316 break;
2318 mnemonic = "smlal";
2319 l_instr = true;
2320 break;
2322 mnemonic = "umlal";
2323 l_instr = true;
2324 break;
2326 mnemonic = "smlsl";
2327 l_instr = true;
2328 break;
2330 mnemonic = "umlsl";
2331 l_instr = true;
2332 break;
2334 mnemonic = "sqdmull";
2335 l_instr = true;
2336 break;
2338 mnemonic = "sqdmlal";
2339 l_instr = true;
2340 break;
2342 mnemonic = "sqdmlsl";
2343 l_instr = true;
2344 break;
2345 case NEON_MUL_byelement:
2346 mnemonic = "mul";
2347 break;
2348 case NEON_MLA_byelement:
2349 mnemonic = "mla";
2350 break;
2351 case NEON_MLS_byelement:
2352 mnemonic = "mls";
2353 break;
2355 mnemonic = "sqdmulh";
2356 break;
2358 mnemonic = "sqrdmulh";
2359 break;
2360 default:
2361 switch (instr->Mask(NEONByIndexedElementFPMask)) {
2363 mnemonic = "fmul";
2364 fp_instr = true;
2365 break;
2367 mnemonic = "fmla";
2368 fp_instr = true;
2369 break;
2371 mnemonic = "fmls";
2372 fp_instr = true;
2373 break;
2375 mnemonic = "fmulx";
2376 fp_instr = true;
2377 break;
2378 }
2379 }
2380
2381 if (l_instr) {
2382 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));
2383 } else if (fp_instr) {
2384 nfd.SetFormatMap(0, nfd.FPFormatMap());
2385 Format(instr, mnemonic, nfd.Substitute(form));
2386 } else {
2387 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2388 Format(instr, mnemonic, nfd.Substitute(form));
2389 }
2390}
2391
2392void DisassemblingDecoder::VisitNEONCopy(Instruction* instr) {
2393 const char* mnemonic = "unimplemented";
2394 const char* form = "(NEONCopy)";
2395
2396 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap(),
2398
2400 mnemonic = "mov";
2401 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
2402 form = "'Vd.%s['IVInsIndex1], 'Vn.%s['IVInsIndex2]";
2403 } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) {
2404 mnemonic = "mov";
2405 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
2406 if (nfd.GetVectorFormat() == kFormatD) {
2407 form = "'Vd.%s['IVInsIndex1], 'Xn";
2408 } else {
2409 form = "'Vd.%s['IVInsIndex1], 'Wn";
2410 }
2411 } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) {
2412 if (instr->Mask(NEON_Q) || ((instr->ImmNEON5() & 7) == 4)) {
2413 mnemonic = "mov";
2414 } else {
2415 mnemonic = "umov";
2416 }
2417 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
2418 if (nfd.GetVectorFormat() == kFormatD) {
2419 form = "'Xd, 'Vn.%s['IVInsIndex1]";
2420 } else {
2421 form = "'Wd, 'Vn.%s['IVInsIndex1]";
2422 }
2423 } else if (instr->Mask(NEONCopySmovMask) == NEON_SMOV) {
2424 mnemonic = "smov";
2425 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
2426 form = "'Rdq, 'Vn.%s['IVInsIndex1]";
2427 } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) {
2428 mnemonic = "dup";
2429 form = "'Vd.%s, 'Vn.%s['IVInsIndex1]";
2430 } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) {
2431 mnemonic = "dup";
2432 if (nfd.GetVectorFormat() == kFormat2D) {
2433 form = "'Vd.%s, 'Xn";
2434 } else {
2435 form = "'Vd.%s, 'Wn";
2436 }
2437 }
2438 Format(instr, mnemonic, nfd.Substitute(form));
2439}
2440
2441void DisassemblingDecoder::VisitNEONExtract(Instruction* instr) {
2442 const char* mnemonic = "unimplemented";
2443 const char* form = "(NEONExtract)";
2444 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
2445 if (instr->Mask(NEONExtractMask) == NEON_EXT) {
2446 mnemonic = "ext";
2447 form = "'Vd.%s, 'Vn.%s, 'Vm.%s, 'IVExtract";
2448 }
2449 Format(instr, mnemonic, nfd.Substitute(form));
2450}
2451
2452void DisassemblingDecoder::VisitNEONLoadStoreMultiStruct(Instruction* instr) {
2453 const char* mnemonic = nullptr;
2454 const char* form = nullptr;
2455 const char* form_1v = "{'Vt.%s}, ['Xns]";
2456 const char* form_2v = "{'Vt.%s, 'Vt2.%s}, ['Xns]";
2457 const char* form_3v = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns]";
2458 const char* form_4v = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s, 'Vt4.%s}, ['Xns]";
2459 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
2460
2461 switch (instr->Mask(NEONLoadStoreMultiStructMask)) {
2462 case NEON_LD1_1v:
2463 mnemonic = "ld1";
2464 form = form_1v;
2465 break;
2466 case NEON_LD1_2v:
2467 mnemonic = "ld1";
2468 form = form_2v;
2469 break;
2470 case NEON_LD1_3v:
2471 mnemonic = "ld1";
2472 form = form_3v;
2473 break;
2474 case NEON_LD1_4v:
2475 mnemonic = "ld1";
2476 form = form_4v;
2477 break;
2478 case NEON_LD2:
2479 mnemonic = "ld2";
2480 form = form_2v;
2481 break;
2482 case NEON_LD3:
2483 mnemonic = "ld3";
2484 form = form_3v;
2485 break;
2486 case NEON_LD4:
2487 mnemonic = "ld4";
2488 form = form_4v;
2489 break;
2490 case NEON_ST1_1v:
2491 mnemonic = "st1";
2492 form = form_1v;
2493 break;
2494 case NEON_ST1_2v:
2495 mnemonic = "st1";
2496 form = form_2v;
2497 break;
2498 case NEON_ST1_3v:
2499 mnemonic = "st1";
2500 form = form_3v;
2501 break;
2502 case NEON_ST1_4v:
2503 mnemonic = "st1";
2504 form = form_4v;
2505 break;
2506 case NEON_ST2:
2507 mnemonic = "st2";
2508 form = form_2v;
2509 break;
2510 case NEON_ST3:
2511 mnemonic = "st3";
2512 form = form_3v;
2513 break;
2514 case NEON_ST4:
2515 mnemonic = "st4";
2516 form = form_4v;
2517 break;
2518 default:
2519 break;
2520 }
2521
2522 // Work out unallocated encodings.
2523 bool allocated = (mnemonic != nullptr);
2524 switch (instr->Mask(NEONLoadStoreMultiStructMask)) {
2525 case NEON_LD2:
2526 case NEON_LD3:
2527 case NEON_LD4:
2528 case NEON_ST2:
2529 case NEON_ST3:
2530 case NEON_ST4:
2531 // LD[2-4] and ST[2-4] cannot use .1d format.
2532 allocated = (instr->NEONQ() != 0) || (instr->NEONLSSize() != 3);
2533 break;
2534 default:
2535 break;
2536 }
2537 if (allocated) {
2538 DCHECK_NOT_NULL(mnemonic);
2539 DCHECK_NOT_NULL(form);
2540 } else {
2541 mnemonic = "unallocated";
2542 form = "(NEONLoadStoreMultiStruct)";
2543 }
2544
2545 Format(instr, mnemonic, nfd.Substitute(form));
2546}
2547
2548void DisassemblingDecoder::VisitNEONLoadStoreMultiStructPostIndex(
2549 Instruction* instr) {
2550 const char* mnemonic = nullptr;
2551 const char* form = nullptr;
2552 const char* form_1v = "{'Vt.%s}, ['Xns], 'Xmr1";
2553 const char* form_2v = "{'Vt.%s, 'Vt2.%s}, ['Xns], 'Xmr2";
2554 const char* form_3v = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns], 'Xmr3";
2555 const char* form_4v = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s, 'Vt4.%s}, ['Xns], 'Xmr4";
2556 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
2557
2559 case NEON_LD1_1v_post:
2560 mnemonic = "ld1";
2561 form = form_1v;
2562 break;
2563 case NEON_LD1_2v_post:
2564 mnemonic = "ld1";
2565 form = form_2v;
2566 break;
2567 case NEON_LD1_3v_post:
2568 mnemonic = "ld1";
2569 form = form_3v;
2570 break;
2571 case NEON_LD1_4v_post:
2572 mnemonic = "ld1";
2573 form = form_4v;
2574 break;
2575 case NEON_LD2_post:
2576 mnemonic = "ld2";
2577 form = form_2v;
2578 break;
2579 case NEON_LD3_post:
2580 mnemonic = "ld3";
2581 form = form_3v;
2582 break;
2583 case NEON_LD4_post:
2584 mnemonic = "ld4";
2585 form = form_4v;
2586 break;
2587 case NEON_ST1_1v_post:
2588 mnemonic = "st1";
2589 form = form_1v;
2590 break;
2591 case NEON_ST1_2v_post:
2592 mnemonic = "st1";
2593 form = form_2v;
2594 break;
2595 case NEON_ST1_3v_post:
2596 mnemonic = "st1";
2597 form = form_3v;
2598 break;
2599 case NEON_ST1_4v_post:
2600 mnemonic = "st1";
2601 form = form_4v;
2602 break;
2603 case NEON_ST2_post:
2604 mnemonic = "st2";
2605 form = form_2v;
2606 break;
2607 case NEON_ST3_post:
2608 mnemonic = "st3";
2609 form = form_3v;
2610 break;
2611 case NEON_ST4_post:
2612 mnemonic = "st4";
2613 form = form_4v;
2614 break;
2615 default:
2616 break;
2617 }
2618
2619 // Work out unallocated encodings.
2620 bool allocated = (mnemonic != nullptr);
2622 case NEON_LD2_post:
2623 case NEON_LD3_post:
2624 case NEON_LD4_post:
2625 case NEON_ST2_post:
2626 case NEON_ST3_post:
2627 case NEON_ST4_post:
2628 // LD[2-4] and ST[2-4] cannot use .1d format.
2629 allocated = (instr->NEONQ() != 0) || (instr->NEONLSSize() != 3);
2630 break;
2631 default:
2632 break;
2633 }
2634 if (allocated) {
2635 DCHECK_NOT_NULL(mnemonic);
2636 DCHECK_NOT_NULL(form);
2637 } else {
2638 mnemonic = "unallocated";
2639 form = "(NEONLoadStoreMultiStructPostIndex)";
2640 }
2641
2642 Format(instr, mnemonic, nfd.Substitute(form));
2643}
2644
2645void DisassemblingDecoder::VisitNEONLoadStoreSingleStruct(Instruction* instr) {
2646 const char* mnemonic = nullptr;
2647 const char* form = nullptr;
2648
2649 const char* form_1b = "{'Vt.b}['IVLSLane0], ['Xns]";
2650 const char* form_1h = "{'Vt.h}['IVLSLane1], ['Xns]";
2651 const char* form_1s = "{'Vt.s}['IVLSLane2], ['Xns]";
2652 const char* form_1d = "{'Vt.d}['IVLSLane3], ['Xns]";
2653 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
2654
2655 switch (instr->Mask(NEONLoadStoreSingleStructMask)) {
2656 case NEON_LD1_b:
2657 mnemonic = "ld1";
2658 form = form_1b;
2659 break;
2660 case NEON_LD1_h:
2661 mnemonic = "ld1";
2662 form = form_1h;
2663 break;
2664 case NEON_LD1_s:
2665 mnemonic = "ld1";
2666 static_assert((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d,
2667 "LSB of size distinguishes S and D registers.");
2668 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d;
2669 break;
2670 case NEON_ST1_b:
2671 mnemonic = "st1";
2672 form = form_1b;
2673 break;
2674 case NEON_ST1_h:
2675 mnemonic = "st1";
2676 form = form_1h;
2677 break;
2678 case NEON_ST1_s:
2679 mnemonic = "st1";
2680 static_assert((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d,
2681 "LSB of size distinguishes S and D registers.");
2682 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d;
2683 break;
2684 case NEON_LD1R:
2685 mnemonic = "ld1r";
2686 form = "{'Vt.%s}, ['Xns]";
2687 break;
2688 case NEON_LD2_b:
2689 case NEON_ST2_b:
2690 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2";
2691 form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns]";
2692 break;
2693 case NEON_LD2_h:
2694 case NEON_ST2_h:
2695 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2";
2696 form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns]";
2697 break;
2698 case NEON_LD2_s:
2699 case NEON_ST2_s:
2700 static_assert((NEON_ST2_s | (1 << NEONLSSize_offset)) == NEON_ST2_d,
2701 "LSB of size distinguishes S and D registers.");
2702 static_assert((NEON_LD2_s | (1 << NEONLSSize_offset)) == NEON_LD2_d,
2703 "LSB of size distinguishes S and D registers.");
2704 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2";
2705 if ((instr->NEONLSSize() & 1) == 0) {
2706 form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns]";
2707 } else {
2708 form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns]";
2709 }
2710 break;
2711 case NEON_LD2R:
2712 mnemonic = "ld2r";
2713 form = "{'Vt.%s, 'Vt2.%s}, ['Xns]";
2714 break;
2715 case NEON_LD3_b:
2716 case NEON_ST3_b:
2717 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3";
2718 form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns]";
2719 break;
2720 case NEON_LD3_h:
2721 case NEON_ST3_h:
2722 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3";
2723 form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns]";
2724 break;
2725 case NEON_LD3_s:
2726 case NEON_ST3_s:
2727 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3";
2728 if ((instr->NEONLSSize() & 1) == 0) {
2729 form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns]";
2730 } else {
2731 form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns]";
2732 }
2733 break;
2734 case NEON_LD3R:
2735 mnemonic = "ld3r";
2736 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns]";
2737 break;
2738 case NEON_LD4_b:
2739 case NEON_ST4_b:
2740 mnemonic = (instr->NEONLoad() == 1) ? "ld4" : "st4";
2741 form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns]";
2742 break;
2743 case NEON_LD4_h:
2744 case NEON_ST4_h:
2745 mnemonic = (instr->NEONLoad() == 1) ? "ld4" : "st4";
2746 form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns]";
2747 break;
2748 case NEON_LD4_s:
2749 case NEON_ST4_s:
2750 static_assert((NEON_LD4_s | (1 << NEONLSSize_offset)) == NEON_LD4_d,
2751 "LSB of size distinguishes S and D registers.");
2752 static_assert((NEON_ST4_s | (1 << NEONLSSize_offset)) == NEON_ST4_d,
2753 "LSB of size distinguishes S and D registers.");
2754 mnemonic = (instr->NEONLoad() == 1) ? "ld4" : "st4";
2755 if ((instr->NEONLSSize() & 1) == 0) {
2756 form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns]";
2757 } else {
2758 form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns]";
2759 }
2760 break;
2761 case NEON_LD4R:
2762 mnemonic = "ld4r";
2763 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s, 'Vt4.%s}, ['Xns]";
2764 break;
2765 default:
2766 break;
2767 }
2768
2769 // Work out unallocated encodings.
2770 bool allocated = (mnemonic != nullptr);
2771 switch (instr->Mask(NEONLoadStoreSingleStructMask)) {
2772 case NEON_LD1_h:
2773 case NEON_LD2_h:
2774 case NEON_LD3_h:
2775 case NEON_LD4_h:
2776 case NEON_ST1_h:
2777 case NEON_ST2_h:
2778 case NEON_ST3_h:
2779 case NEON_ST4_h:
2780 DCHECK(allocated);
2781 allocated = ((instr->NEONLSSize() & 1) == 0);
2782 break;
2783 case NEON_LD1_s:
2784 case NEON_LD2_s:
2785 case NEON_LD3_s:
2786 case NEON_LD4_s:
2787 case NEON_ST1_s:
2788 case NEON_ST2_s:
2789 case NEON_ST3_s:
2790 case NEON_ST4_s:
2791 DCHECK(allocated);
2792 allocated = (instr->NEONLSSize() <= 1) &&
2793 ((instr->NEONLSSize() == 0) || (instr->NEONS() == 0));
2794 break;
2795 case NEON_LD1R:
2796 case NEON_LD2R:
2797 case NEON_LD3R:
2798 case NEON_LD4R:
2799 DCHECK(allocated);
2800 allocated = (instr->NEONS() == 0);
2801 break;
2802 default:
2803 break;
2804 }
2805 if (allocated) {
2806 DCHECK_NOT_NULL(mnemonic);
2807 DCHECK_NOT_NULL(form);
2808 } else {
2809 mnemonic = "unallocated";
2810 form = "(NEONLoadStoreSingleStruct)";
2811 }
2812
2813 Format(instr, mnemonic, nfd.Substitute(form));
2814}
2815
2816void DisassemblingDecoder::VisitNEONLoadStoreSingleStructPostIndex(
2817 Instruction* instr) {
2818 const char* mnemonic = nullptr;
2819 const char* form = nullptr;
2820
2821 const char* form_1b = "{'Vt.b}['IVLSLane0], ['Xns], 'Xmb1";
2822 const char* form_1h = "{'Vt.h}['IVLSLane1], ['Xns], 'Xmb2";
2823 const char* form_1s = "{'Vt.s}['IVLSLane2], ['Xns], 'Xmb4";
2824 const char* form_1d = "{'Vt.d}['IVLSLane3], ['Xns], 'Xmb8";
2825 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
2826
2828 case NEON_LD1_b_post:
2829 mnemonic = "ld1";
2830 form = form_1b;
2831 break;
2832 case NEON_LD1_h_post:
2833 mnemonic = "ld1";
2834 form = form_1h;
2835 break;
2836 case NEON_LD1_s_post:
2837 mnemonic = "ld1";
2838 static_assert((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d,
2839 "LSB of size distinguishes S and D registers.");
2840 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d;
2841 break;
2842 case NEON_ST1_b_post:
2843 mnemonic = "st1";
2844 form = form_1b;
2845 break;
2846 case NEON_ST1_h_post:
2847 mnemonic = "st1";
2848 form = form_1h;
2849 break;
2850 case NEON_ST1_s_post:
2851 mnemonic = "st1";
2852 static_assert((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d,
2853 "LSB of size distinguishes S and D registers.");
2854 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d;
2855 break;
2856 case NEON_LD1R_post:
2857 mnemonic = "ld1r";
2858 form = "{'Vt.%s}, ['Xns], 'Xmz1";
2859 break;
2860 case NEON_LD2_b_post:
2861 case NEON_ST2_b_post:
2862 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2";
2863 form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns], 'Xmb2";
2864 break;
2865 case NEON_ST2_h_post:
2866 case NEON_LD2_h_post:
2867 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2";
2868 form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns], 'Xmb4";
2869 break;
2870 case NEON_LD2_s_post:
2871 case NEON_ST2_s_post:
2872 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2";
2873 if ((instr->NEONLSSize() & 1) == 0)
2874 form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns], 'Xmb8";
2875 else
2876 form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns], 'Xmb16";
2877 break;
2878 case NEON_LD2R_post:
2879 mnemonic = "ld2r";
2880 form = "{'Vt.%s, 'Vt2.%s}, ['Xns], 'Xmz2";
2881 break;
2882 case NEON_LD3_b_post:
2883 case NEON_ST3_b_post:
2884 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3";
2885 form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns], 'Xmb3";
2886 break;
2887 case NEON_LD3_h_post:
2888 case NEON_ST3_h_post:
2889 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3";
2890 form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns], 'Xmb6";
2891 break;
2892 case NEON_LD3_s_post:
2893 case NEON_ST3_s_post:
2894 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3";
2895 if ((instr->NEONLSSize() & 1) == 0)
2896 form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns], 'Xmb12";
2897 else
2898 form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns], 'Xmb24";
2899 break;
2900 case NEON_LD3R_post:
2901 mnemonic = "ld3r";
2902 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns], 'Xmz3";
2903 break;
2904 case NEON_LD4_b_post:
2905 case NEON_ST4_b_post:
2906 mnemonic = (instr->NEONLoad() == 1) ? "ld4" : "st4";
2907 form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns], 'Xmb4";
2908 break;
2909 case NEON_LD4_h_post:
2910 case NEON_ST4_h_post:
2911 mnemonic = (instr->NEONLoad()) == 1 ? "ld4" : "st4";
2912 form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns], 'Xmb8";
2913 break;
2914 case NEON_LD4_s_post:
2915 case NEON_ST4_s_post:
2916 mnemonic = (instr->NEONLoad() == 1) ? "ld4" : "st4";
2917 if ((instr->NEONLSSize() & 1) == 0)
2918 form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns], 'Xmb16";
2919 else
2920 form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns], 'Xmb32";
2921 break;
2922 case NEON_LD4R_post:
2923 mnemonic = "ld4r";
2924 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s, 'Vt4.%s}, ['Xns], 'Xmz4";
2925 break;
2926 default:
2927 break;
2928 }
2929
2930 // Work out unallocated encodings.
2931 bool allocated = (mnemonic != nullptr);
2933 case NEON_LD1_h_post:
2934 case NEON_LD2_h_post:
2935 case NEON_LD3_h_post:
2936 case NEON_LD4_h_post:
2937 case NEON_ST1_h_post:
2938 case NEON_ST2_h_post:
2939 case NEON_ST3_h_post:
2940 case NEON_ST4_h_post:
2941 DCHECK(allocated);
2942 allocated = ((instr->NEONLSSize() & 1) == 0);
2943 break;
2944 case NEON_LD1_s_post:
2945 case NEON_LD2_s_post:
2946 case NEON_LD3_s_post:
2947 case NEON_LD4_s_post:
2948 case NEON_ST1_s_post:
2949 case NEON_ST2_s_post:
2950 case NEON_ST3_s_post:
2951 case NEON_ST4_s_post:
2952 DCHECK(allocated);
2953 allocated = (instr->NEONLSSize() <= 1) &&
2954 ((instr->NEONLSSize() == 0) || (instr->NEONS() == 0));
2955 break;
2956 case NEON_LD1R_post:
2957 case NEON_LD2R_post:
2958 case NEON_LD3R_post:
2959 case NEON_LD4R_post:
2960 DCHECK(allocated);
2961 allocated = (instr->NEONS() == 0);
2962 break;
2963 default:
2964 break;
2965 }
2966 if (allocated) {
2967 DCHECK_NOT_NULL(mnemonic);
2968 DCHECK_NOT_NULL(form);
2969 } else {
2970 mnemonic = "unallocated";
2971 form = "(NEONLoadStoreSingleStructPostIndex)";
2972 }
2973
2974 Format(instr, mnemonic, nfd.Substitute(form));
2975}
2976
2977void DisassemblingDecoder::VisitNEONModifiedImmediate(Instruction* instr) {
2978 const char* mnemonic = "unimplemented";
2979 const char* form = "'Vt.%s, 'IVMIImm8, lsl 'IVMIShiftAmt1";
2980
2981 int cmode = instr->NEONCmode();
2982 int cmode_3 = (cmode >> 3) & 1;
2983 int cmode_2 = (cmode >> 2) & 1;
2984 int cmode_1 = (cmode >> 1) & 1;
2985 int cmode_0 = cmode & 1;
2986 int q = instr->NEONQ();
2987 int op = instr->NEONModImmOp();
2988
2989 static const NEONFormatMap map_b = {{30}, {NF_8B, NF_16B}};
2990 static const NEONFormatMap map_h = {{30}, {NF_4H, NF_8H}};
2991 static const NEONFormatMap map_s = {{30}, {NF_2S, NF_4S}};
2992 NEONFormatDecoder nfd(instr, &map_b);
2993
2994 if (cmode_3 == 0) {
2995 if (cmode_0 == 0) {
2996 mnemonic = (op == 1) ? "mvni" : "movi";
2997 } else { // cmode<0> == '1'.
2998 mnemonic = (op == 1) ? "bic" : "orr";
2999 }
3000 nfd.SetFormatMap(0, &map_s);
3001 } else { // cmode<3> == '1'.
3002 if (cmode_2 == 0) {
3003 if (cmode_0 == 0) {
3004 mnemonic = (op == 1) ? "mvni" : "movi";
3005 } else { // cmode<0> == '1'.
3006 mnemonic = (op == 1) ? "bic" : "orr";
3007 }
3008 nfd.SetFormatMap(0, &map_h);
3009 } else { // cmode<2> == '1'.
3010 if (cmode_1 == 0) {
3011 mnemonic = (op == 1) ? "mvni" : "movi";
3012 form = "'Vt.%s, 'IVMIImm8, msl 'IVMIShiftAmt2";
3013 nfd.SetFormatMap(0, &map_s);
3014 } else { // cmode<1> == '1'.
3015 if (cmode_0 == 0) {
3016 mnemonic = "movi";
3017 if (op == 0) {
3018 form = "'Vt.%s, 'IVMIImm8";
3019 } else {
3020 form = (q == 0) ? "'Dd, 'IVMIImm" : "'Vt.2d, 'IVMIImm";
3021 }
3022 } else { // cmode<0> == '1'
3023 mnemonic = "fmov";
3024 if (op == 0) {
3025 form = "'Vt.%s, 'IVMIImmFPSingle";
3026 nfd.SetFormatMap(0, &map_s);
3027 } else {
3028 if (q == 1) {
3029 form = "'Vt.2d, 'IVMIImmFPDouble";
3030 } else {
3031 mnemonic = "unallocated";
3032 form = "(NEONModifiedImmediate)";
3033 }
3034 }
3035 }
3036 }
3037 }
3038 }
3039 Format(instr, mnemonic, nfd.Substitute(form));
3040}
3041
3042void DisassemblingDecoder::VisitNEONSHA3(Instruction* instr) {
3043 const char* mnemonic = "unimplemented";
3044 const char* form = "'Vd.%s, 'Vn.%s, 'Vm.%s, 'Va.%s";
3045 NEONFormatDecoder nfd(instr);
3046
3047 switch (instr->Mask(NEONSHA3Mask)) {
3048 case NEON_BCAX:
3049 mnemonic = "bcax";
3050 break;
3051 case NEON_EOR3:
3052 mnemonic = "eor3";
3053 break;
3054 default:
3055 form = "(NEONSHA3)";
3056 }
3057 Format(instr, mnemonic, nfd.Substitute(form));
3058}
3059
3060void DisassemblingDecoder::VisitNEONPerm(Instruction* instr) {
3061 const char* mnemonic = "unimplemented";
3062 const char* form = "'Vd.%s, 'Vn.%s, 'Vm.%s";
3063 NEONFormatDecoder nfd(instr);
3064
3065 switch (instr->Mask(NEONPermMask)) {
3066 case NEON_TRN1:
3067 mnemonic = "trn1";
3068 break;
3069 case NEON_TRN2:
3070 mnemonic = "trn2";
3071 break;
3072 case NEON_UZP1:
3073 mnemonic = "uzp1";
3074 break;
3075 case NEON_UZP2:
3076 mnemonic = "uzp2";
3077 break;
3078 case NEON_ZIP1:
3079 mnemonic = "zip1";
3080 break;
3081 case NEON_ZIP2:
3082 mnemonic = "zip2";
3083 break;
3084 default:
3085 form = "(NEONPerm)";
3086 }
3087 Format(instr, mnemonic, nfd.Substitute(form));
3088}
3089
3090void DisassemblingDecoder::VisitNEONScalar2RegMisc(Instruction* instr) {
3091 const char* mnemonic = "unimplemented";
3092 const char* form = "%sd, %sn";
3093 const char* form_0 = "%sd, %sn, #0";
3094 const char* form_fp0 = "%sd, %sn, #0.0";
3095
3096 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
3097
3099 // These instructions all use a two bit size field, except NOT and RBIT,
3100 // which use the field to encode the operation.
3101 switch (instr->Mask(NEONScalar2RegMiscMask)) {
3103 mnemonic = "cmgt";
3104 form = form_0;
3105 break;
3107 mnemonic = "cmge";
3108 form = form_0;
3109 break;
3111 mnemonic = "cmle";
3112 form = form_0;
3113 break;
3115 mnemonic = "cmlt";
3116 form = form_0;
3117 break;
3119 mnemonic = "cmeq";
3120 form = form_0;
3121 break;
3122 case NEON_NEG_scalar:
3123 mnemonic = "neg";
3124 break;
3125 case NEON_SQNEG_scalar:
3126 mnemonic = "sqneg";
3127 break;
3128 case NEON_ABS_scalar:
3129 mnemonic = "abs";
3130 break;
3131 case NEON_SQABS_scalar:
3132 mnemonic = "sqabs";
3133 break;
3134 case NEON_SUQADD_scalar:
3135 mnemonic = "suqadd";
3136 break;
3137 case NEON_USQADD_scalar:
3138 mnemonic = "usqadd";
3139 break;
3140 default:
3141 form = "(NEONScalar2RegMisc)";
3142 }
3143 } else {
3144 // These instructions all use a one bit size field, except SQXTUN, SQXTN
3145 // and UQXTN, which use a two bit size field.
3146 nfd.SetFormatMaps(nfd.FPScalarFormatMap());
3147 switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
3149 mnemonic = "frsqrte";
3150 break;
3151 case NEON_FRECPE_scalar:
3152 mnemonic = "frecpe";
3153 break;
3154 case NEON_SCVTF_scalar:
3155 mnemonic = "scvtf";
3156 break;
3157 case NEON_UCVTF_scalar:
3158 mnemonic = "ucvtf";
3159 break;
3161 mnemonic = "fcmgt";
3162 form = form_fp0;
3163 break;
3165 mnemonic = "fcmge";
3166 form = form_fp0;
3167 break;
3169 mnemonic = "fcmle";
3170 form = form_fp0;
3171 break;
3173 mnemonic = "fcmlt";
3174 form = form_fp0;
3175 break;
3177 mnemonic = "fcmeq";
3178 form = form_fp0;
3179 break;
3180 case NEON_FRECPX_scalar:
3181 mnemonic = "frecpx";
3182 break;
3183 case NEON_FCVTNS_scalar:
3184 mnemonic = "fcvtns";
3185 break;
3186 case NEON_FCVTNU_scalar:
3187 mnemonic = "fcvtnu";
3188 break;
3189 case NEON_FCVTPS_scalar:
3190 mnemonic = "fcvtps";
3191 break;
3192 case NEON_FCVTPU_scalar:
3193 mnemonic = "fcvtpu";
3194 break;
3195 case NEON_FCVTMS_scalar:
3196 mnemonic = "fcvtms";
3197 break;
3198 case NEON_FCVTMU_scalar:
3199 mnemonic = "fcvtmu";
3200 break;
3201 case NEON_FCVTZS_scalar:
3202 mnemonic = "fcvtzs";
3203 break;
3204 case NEON_FCVTZU_scalar:
3205 mnemonic = "fcvtzu";
3206 break;
3207 case NEON_FCVTAS_scalar:
3208 mnemonic = "fcvtas";
3209 break;
3210 case NEON_FCVTAU_scalar:
3211 mnemonic = "fcvtau";
3212 break;
3213 case NEON_FCVTXN_scalar:
3214 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
3215 mnemonic = "fcvtxn";
3216 break;
3217 default:
3218 nfd.SetFormatMap(0, nfd.ScalarFormatMap());
3219 nfd.SetFormatMap(1, nfd.LongScalarFormatMap());
3220 switch (instr->Mask(NEONScalar2RegMiscMask)) {
3221 case NEON_SQXTN_scalar:
3222 mnemonic = "sqxtn";
3223 break;
3224 case NEON_UQXTN_scalar:
3225 mnemonic = "uqxtn";
3226 break;
3227 case NEON_SQXTUN_scalar:
3228 mnemonic = "sqxtun";
3229 break;
3230 default:
3231 form = "(NEONScalar2RegMisc)";
3232 }
3233 }
3234 }
3235 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
3236}
3237
3238void DisassemblingDecoder::VisitNEONScalar3Diff(Instruction* instr) {
3239 const char* mnemonic = "unimplemented";
3240 const char* form = "%sd, %sn, %sm";
3241 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap(),
3243
3244 switch (instr->Mask(NEONScalar3DiffMask)) {
3246 mnemonic = "sqdmlal";
3247 break;
3249 mnemonic = "sqdmlsl";
3250 break;
3252 mnemonic = "sqdmull";
3253 break;
3254 default:
3255 form = "(NEONScalar3Diff)";
3256 }
3257 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
3258}
3259
3260void DisassemblingDecoder::VisitNEONScalar3Same(Instruction* instr) {
3261 const char* mnemonic = "unimplemented";
3262 const char* form = "%sd, %sn, %sm";
3263 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
3264
3266 nfd.SetFormatMaps(nfd.FPScalarFormatMap());
3267 switch (instr->Mask(NEONScalar3SameFPMask)) {
3268 case NEON_FACGE_scalar:
3269 mnemonic = "facge";
3270 break;
3271 case NEON_FACGT_scalar:
3272 mnemonic = "facgt";
3273 break;
3274 case NEON_FCMEQ_scalar:
3275 mnemonic = "fcmeq";
3276 break;
3277 case NEON_FCMGE_scalar:
3278 mnemonic = "fcmge";
3279 break;
3280 case NEON_FCMGT_scalar:
3281 mnemonic = "fcmgt";
3282 break;
3283 case NEON_FMULX_scalar:
3284 mnemonic = "fmulx";
3285 break;
3286 case NEON_FRECPS_scalar:
3287 mnemonic = "frecps";
3288 break;
3290 mnemonic = "frsqrts";
3291 break;
3292 case NEON_FABD_scalar:
3293 mnemonic = "fabd";
3294 break;
3295 default:
3296 form = "(NEONScalar3Same)";
3297 }
3298 } else {
3299 switch (instr->Mask(NEONScalar3SameMask)) {
3300 case NEON_ADD_scalar:
3301 mnemonic = "add";
3302 break;
3303 case NEON_SUB_scalar:
3304 mnemonic = "sub";
3305 break;
3306 case NEON_CMEQ_scalar:
3307 mnemonic = "cmeq";
3308 break;
3309 case NEON_CMGE_scalar:
3310 mnemonic = "cmge";
3311 break;
3312 case NEON_CMGT_scalar:
3313 mnemonic = "cmgt";
3314 break;
3315 case NEON_CMHI_scalar:
3316 mnemonic = "cmhi";
3317 break;
3318 case NEON_CMHS_scalar:
3319 mnemonic = "cmhs";
3320 break;
3321 case NEON_CMTST_scalar:
3322 mnemonic = "cmtst";
3323 break;
3324 case NEON_UQADD_scalar:
3325 mnemonic = "uqadd";
3326 break;
3327 case NEON_SQADD_scalar:
3328 mnemonic = "sqadd";
3329 break;
3330 case NEON_UQSUB_scalar:
3331 mnemonic = "uqsub";
3332 break;
3333 case NEON_SQSUB_scalar:
3334 mnemonic = "sqsub";
3335 break;
3336 case NEON_USHL_scalar:
3337 mnemonic = "ushl";
3338 break;
3339 case NEON_SSHL_scalar:
3340 mnemonic = "sshl";
3341 break;
3342 case NEON_UQSHL_scalar:
3343 mnemonic = "uqshl";
3344 break;
3345 case NEON_SQSHL_scalar:
3346 mnemonic = "sqshl";
3347 break;
3348 case NEON_URSHL_scalar:
3349 mnemonic = "urshl";
3350 break;
3351 case NEON_SRSHL_scalar:
3352 mnemonic = "srshl";
3353 break;
3354 case NEON_UQRSHL_scalar:
3355 mnemonic = "uqrshl";
3356 break;
3357 case NEON_SQRSHL_scalar:
3358 mnemonic = "sqrshl";
3359 break;
3361 mnemonic = "sqdmulh";
3362 break;
3364 mnemonic = "sqrdmulh";
3365 break;
3366 default:
3367 form = "(NEONScalar3Same)";
3368 }
3369 }
3370 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
3371}
3372
3373void DisassemblingDecoder::VisitNEONScalarByIndexedElement(Instruction* instr) {
3374 const char* mnemonic = "unimplemented";
3375 const char* form = "%sd, %sn, 'Ve.%s['IVByElemIndex]";
3376 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
3377 bool long_instr = false;
3378
3379 switch (instr->Mask(NEONScalarByIndexedElementMask)) {
3381 mnemonic = "sqdmull";
3382 long_instr = true;
3383 break;
3385 mnemonic = "sqdmlal";
3386 long_instr = true;
3387 break;
3389 mnemonic = "sqdmlsl";
3390 long_instr = true;
3391 break;
3393 mnemonic = "sqdmulh";
3394 break;
3396 mnemonic = "sqrdmulh";
3397 break;
3398 default:
3399 nfd.SetFormatMap(0, nfd.FPScalarFormatMap());
3400 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
3402 mnemonic = "fmul";
3403 break;
3405 mnemonic = "fmla";
3406 break;
3408 mnemonic = "fmls";
3409 break;
3411 mnemonic = "fmulx";
3412 break;
3413 default:
3414 form = "(NEONScalarByIndexedElement)";
3415 }
3416 }
3417
3418 if (long_instr) {
3419 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
3420 }
3421
3422 Format(instr, mnemonic,
3423 nfd.Substitute(form, nfd.kPlaceholder, nfd.kPlaceholder, nfd.kFormat));
3424}
3425
3426void DisassemblingDecoder::VisitNEONScalarCopy(Instruction* instr) {
3427 const char* mnemonic = "unimplemented";
3428 const char* form = "(NEONScalarCopy)";
3429
3430 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap());
3431
3433 mnemonic = "mov";
3434 form = "%sd, 'Vn.%s['IVInsIndex1]";
3435 }
3436
3437 Format(instr, mnemonic, nfd.Substitute(form, nfd.kPlaceholder, nfd.kFormat));
3438}
3439
3440void DisassemblingDecoder::VisitNEONScalarPairwise(Instruction* instr) {
3441 const char* mnemonic = "unimplemented";
3442 const char* form = "%sd, 'Vn.%s";
3443 NEONFormatMap map = {{22}, {NF_2S, NF_2D}};
3444 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap(), &map);
3445
3446 switch (instr->Mask(NEONScalarPairwiseMask)) {
3447 case NEON_ADDP_scalar:
3448 mnemonic = "addp";
3449 break;
3450 case NEON_FADDP_scalar:
3451 mnemonic = "faddp";
3452 break;
3453 case NEON_FMAXP_scalar:
3454 mnemonic = "fmaxp";
3455 break;
3457 mnemonic = "fmaxnmp";
3458 break;
3459 case NEON_FMINP_scalar:
3460 mnemonic = "fminp";
3461 break;
3463 mnemonic = "fminnmp";
3464 break;
3465 default:
3466 form = "(NEONScalarPairwise)";
3467 }
3468 Format(instr, mnemonic,
3469 nfd.Substitute(form, NEONFormatDecoder::kPlaceholder,
3471}
3472
3473void DisassemblingDecoder::VisitNEONScalarShiftImmediate(Instruction* instr) {
3474 const char* mnemonic = "unimplemented";
3475 const char* form = "%sd, %sn, 'Is1";
3476 const char* form_2 = "%sd, %sn, 'Is2";
3477
3478 static const NEONFormatMap map_shift = {
3479 {22, 21, 20, 19},
3481 NF_D, NF_D, NF_D, NF_D, NF_D}};
3482 static const NEONFormatMap map_shift_narrow = {
3483 {21, 20, 19}, {NF_UNDEF, NF_H, NF_S, NF_S, NF_D, NF_D, NF_D, NF_D}};
3484 NEONFormatDecoder nfd(instr, &map_shift);
3485
3486 if (instr->ImmNEONImmh()) { // immh has to be non-zero.
3487 switch (instr->Mask(NEONScalarShiftImmediateMask)) {
3489 mnemonic = "fcvtzu";
3490 break;
3492 mnemonic = "fcvtzs";
3493 break;
3495 mnemonic = "scvtf";
3496 break;
3498 mnemonic = "ucvtf";
3499 break;
3500 case NEON_SRI_scalar:
3501 mnemonic = "sri";
3502 break;
3503 case NEON_SSHR_scalar:
3504 mnemonic = "sshr";
3505 break;
3506 case NEON_USHR_scalar:
3507 mnemonic = "ushr";
3508 break;
3509 case NEON_SRSHR_scalar:
3510 mnemonic = "srshr";
3511 break;
3512 case NEON_URSHR_scalar:
3513 mnemonic = "urshr";
3514 break;
3515 case NEON_SSRA_scalar:
3516 mnemonic = "ssra";
3517 break;
3518 case NEON_USRA_scalar:
3519 mnemonic = "usra";
3520 break;
3521 case NEON_SRSRA_scalar:
3522 mnemonic = "srsra";
3523 break;
3524 case NEON_URSRA_scalar:
3525 mnemonic = "ursra";
3526 break;
3527 case NEON_SHL_scalar:
3528 mnemonic = "shl";
3529 form = form_2;
3530 break;
3531 case NEON_SLI_scalar:
3532 mnemonic = "sli";
3533 form = form_2;
3534 break;
3535 case NEON_SQSHLU_scalar:
3536 mnemonic = "sqshlu";
3537 form = form_2;
3538 break;
3540 mnemonic = "sqshl";
3541 form = form_2;
3542 break;
3544 mnemonic = "uqshl";
3545 form = form_2;
3546 break;
3547 case NEON_UQSHRN_scalar:
3548 mnemonic = "uqshrn";
3549 nfd.SetFormatMap(1, &map_shift_narrow);
3550 break;
3552 mnemonic = "uqrshrn";
3553 nfd.SetFormatMap(1, &map_shift_narrow);
3554 break;
3555 case NEON_SQSHRN_scalar:
3556 mnemonic = "sqshrn";
3557 nfd.SetFormatMap(1, &map_shift_narrow);
3558 break;
3560 mnemonic = "sqrshrn";
3561 nfd.SetFormatMap(1, &map_shift_narrow);
3562 break;
3564 mnemonic = "sqshrun";
3565 nfd.SetFormatMap(1, &map_shift_narrow);
3566 break;
3568 mnemonic = "sqrshrun";
3569 nfd.SetFormatMap(1, &map_shift_narrow);
3570 break;
3571 default:
3572 form = "(NEONScalarShiftImmediate)";
3573 }
3574 } else {
3575 form = "(NEONScalarShiftImmediate)";
3576 }
3577 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
3578}
3579
3580void DisassemblingDecoder::VisitNEONShiftImmediate(Instruction* instr) {
3581 const char* mnemonic = "unimplemented";
3582 const char* form = "'Vd.%s, 'Vn.%s, 'Is1";
3583 const char* form_shift_2 = "'Vd.%s, 'Vn.%s, 'Is2";
3584 const char* form_xtl = "'Vd.%s, 'Vn.%s";
3585
3586 // 0001->8H, 001x->4S, 01xx->2D, all others undefined.
3587 static const NEONFormatMap map_shift_ta = {
3588 {22, 21, 20, 19},
3590
3591 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H,
3592 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined.
3593 static const NEONFormatMap map_shift_tb = {
3594 {22, 21, 20, 19, 30},
3599
3600 NEONFormatDecoder nfd(instr, &map_shift_tb);
3601
3602 if (instr->ImmNEONImmh()) { // immh has to be non-zero.
3603 switch (instr->Mask(NEONShiftImmediateMask)) {
3604 case NEON_SQSHLU:
3605 mnemonic = "sqshlu";
3606 form = form_shift_2;
3607 break;
3608 case NEON_SQSHL_imm:
3609 mnemonic = "sqshl";
3610 form = form_shift_2;
3611 break;
3612 case NEON_UQSHL_imm:
3613 mnemonic = "uqshl";
3614 form = form_shift_2;
3615 break;
3616 case NEON_SHL:
3617 mnemonic = "shl";
3618 form = form_shift_2;
3619 break;
3620 case NEON_SLI:
3621 mnemonic = "sli";
3622 form = form_shift_2;
3623 break;
3624 case NEON_SCVTF_imm:
3625 mnemonic = "scvtf";
3626 break;
3627 case NEON_UCVTF_imm:
3628 mnemonic = "ucvtf";
3629 break;
3630 case NEON_FCVTZU_imm:
3631 mnemonic = "fcvtzu";
3632 break;
3633 case NEON_FCVTZS_imm:
3634 mnemonic = "fcvtzs";
3635 break;
3636 case NEON_SRI:
3637 mnemonic = "sri";
3638 break;
3639 case NEON_SSHR:
3640 mnemonic = "sshr";
3641 break;
3642 case NEON_USHR:
3643 mnemonic = "ushr";
3644 break;
3645 case NEON_SRSHR:
3646 mnemonic = "srshr";
3647 break;
3648 case NEON_URSHR:
3649 mnemonic = "urshr";
3650 break;
3651 case NEON_SSRA:
3652 mnemonic = "ssra";
3653 break;
3654 case NEON_USRA:
3655 mnemonic = "usra";
3656 break;
3657 case NEON_SRSRA:
3658 mnemonic = "srsra";
3659 break;
3660 case NEON_URSRA:
3661 mnemonic = "ursra";
3662 break;
3663 case NEON_SHRN:
3664 mnemonic = instr->Mask(NEON_Q) ? "shrn2" : "shrn";
3665 nfd.SetFormatMap(1, &map_shift_ta);
3666 break;
3667 case NEON_RSHRN:
3668 mnemonic = instr->Mask(NEON_Q) ? "rshrn2" : "rshrn";
3669 nfd.SetFormatMap(1, &map_shift_ta);
3670 break;
3671 case NEON_UQSHRN:
3672 mnemonic = instr->Mask(NEON_Q) ? "uqshrn2" : "uqshrn";
3673 nfd.SetFormatMap(1, &map_shift_ta);
3674 break;
3675 case NEON_UQRSHRN:
3676 mnemonic = instr->Mask(NEON_Q) ? "uqrshrn2" : "uqrshrn";
3677 nfd.SetFormatMap(1, &map_shift_ta);
3678 break;
3679 case NEON_SQSHRN:
3680 mnemonic = instr->Mask(NEON_Q) ? "sqshrn2" : "sqshrn";
3681 nfd.SetFormatMap(1, &map_shift_ta);
3682 break;
3683 case NEON_SQRSHRN:
3684 mnemonic = instr->Mask(NEON_Q) ? "sqrshrn2" : "sqrshrn";
3685 nfd.SetFormatMap(1, &map_shift_ta);
3686 break;
3687 case NEON_SQSHRUN:
3688 mnemonic = instr->Mask(NEON_Q) ? "sqshrun2" : "sqshrun";
3689 nfd.SetFormatMap(1, &map_shift_ta);
3690 break;
3691 case NEON_SQRSHRUN:
3692 mnemonic = instr->Mask(NEON_Q) ? "sqrshrun2" : "sqrshrun";
3693 nfd.SetFormatMap(1, &map_shift_ta);
3694 break;
3695 case NEON_SSHLL:
3696 nfd.SetFormatMap(0, &map_shift_ta);
3697 if (instr->ImmNEONImmb() == 0 &&
3698 CountSetBits(instr->ImmNEONImmh(), 32) == 1) { // sxtl variant.
3699 form = form_xtl;
3700 mnemonic = instr->Mask(NEON_Q) ? "sxtl2" : "sxtl";
3701 } else { // sshll variant.
3702 form = form_shift_2;
3703 mnemonic = instr->Mask(NEON_Q) ? "sshll2" : "sshll";
3704 }
3705 break;
3706 case NEON_USHLL:
3707 nfd.SetFormatMap(0, &map_shift_ta);
3708 if (instr->ImmNEONImmb() == 0 &&
3709 CountSetBits(instr->ImmNEONImmh(), 32) == 1) { // uxtl variant.
3710 form = form_xtl;
3711 mnemonic = instr->Mask(NEON_Q) ? "uxtl2" : "uxtl";
3712 } else { // ushll variant.
3713 form = form_shift_2;
3714 mnemonic = instr->Mask(NEON_Q) ? "ushll2" : "ushll";
3715 }
3716 break;
3717 default:
3718 form = "(NEONShiftImmediate)";
3719 }
3720 } else {
3721 form = "(NEONShiftImmediate)";
3722 }
3723 Format(instr, mnemonic, nfd.Substitute(form));
3724}
3725
3726void DisassemblingDecoder::VisitNEONTable(Instruction* instr) {
3727 const char* mnemonic = "unimplemented";
3728 const char* form = "(NEONTable)";
3729 const char form_1v[] = "'Vd.%%s, {'Vn.16b}, 'Vm.%%s";
3730 const char form_2v[] = "'Vd.%%s, {'Vn.16b, v%d.16b}, 'Vm.%%s";
3731 const char form_3v[] = "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b}, 'Vm.%%s";
3732 const char form_4v[] =
3733 "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b, v%d.16b}, 'Vm.%%s";
3734 static const NEONFormatMap map_b = {{30}, {NF_8B, NF_16B}};
3735 NEONFormatDecoder nfd(instr, &map_b);
3736
3737 switch (instr->Mask(NEONTableMask)) {
3738 case NEON_TBL_1v:
3739 mnemonic = "tbl";
3740 form = form_1v;
3741 break;
3742 case NEON_TBL_2v:
3743 mnemonic = "tbl";
3744 form = form_2v;
3745 break;
3746 case NEON_TBL_3v:
3747 mnemonic = "tbl";
3748 form = form_3v;
3749 break;
3750 case NEON_TBL_4v:
3751 mnemonic = "tbl";
3752 form = form_4v;
3753 break;
3754 case NEON_TBX_1v:
3755 mnemonic = "tbx";
3756 form = form_1v;
3757 break;
3758 case NEON_TBX_2v:
3759 mnemonic = "tbx";
3760 form = form_2v;
3761 break;
3762 case NEON_TBX_3v:
3763 mnemonic = "tbx";
3764 form = form_3v;
3765 break;
3766 case NEON_TBX_4v:
3767 mnemonic = "tbx";
3768 form = form_4v;
3769 break;
3770 default:
3771 break;
3772 }
3773
3774 char re_form[sizeof(form_4v)];
3775 int reg_num = instr->Rn();
3776 snprintf(re_form, sizeof(re_form), form, (reg_num + 1) % kNumberOfVRegisters,
3777 (reg_num + 2) % kNumberOfVRegisters,
3778 (reg_num + 3) % kNumberOfVRegisters);
3779
3780 Format(instr, mnemonic, nfd.Substitute(re_form));
3781}
3782
3783void DisassemblingDecoder::VisitUnimplemented(Instruction* instr) {
3784 Format(instr, "unimplemented", "(Unimplemented)");
3785}
3786
3787void DisassemblingDecoder::VisitUnallocated(Instruction* instr) {
3788 Format(instr, "unallocated", "(Unallocated)");
3789}
3790
3791void DisassemblingDecoder::ProcessOutput(Instruction* /*instr*/) {
3792 // The base disasm does nothing more than disassembling into a buffer.
3793}
3794
3796 DCHECK(reg.is_valid());
3797 char reg_char;
3798
3799 if (reg.IsRegister()) {
3800 reg_char = reg.Is64Bits() ? 'x' : 'w';
3801 } else {
3802 DCHECK(reg.IsVRegister());
3803 switch (reg.SizeInBits()) {
3804 case kBRegSizeInBits:
3805 reg_char = 'b';
3806 break;
3807 case kHRegSizeInBits:
3808 reg_char = 'h';
3809 break;
3810 case kSRegSizeInBits:
3811 reg_char = 's';
3812 break;
3813 case kDRegSizeInBits:
3814 reg_char = 'd';
3815 break;
3816 default:
3817 DCHECK(reg.Is128Bits());
3818 reg_char = 'q';
3819 }
3820 }
3821
3822 if (reg.IsVRegister() || !(reg.Aliases(sp) || reg.Aliases(xzr))) {
3823 // Filter special registers
3824 if (reg.IsX() && (reg.code() == 27)) {
3825 AppendToOutput("cp");
3826 } else if (reg.IsX() && (reg.code() == 29)) {
3827 AppendToOutput("fp");
3828 } else if (reg.IsX() && (reg.code() == 30)) {
3829 AppendToOutput("lr");
3830 } else {
3831 // A core or scalar/vector register: [wx]0 - 30, [bhsdq]0 - 31.
3832 AppendToOutput("%c%d", reg_char, reg.code());
3833 }
3834 } else if (reg.Aliases(sp)) {
3835 // Disassemble w31/x31 as stack pointer wsp/sp.
3836 AppendToOutput("%s", reg.Is64Bits() ? "sp" : "wsp");
3837 } else {
3838 // Disassemble w31/x31 as zero register wzr/xzr.
3839 AppendToOutput("%czr", reg_char);
3840 }
3841}
3842
3843void DisassemblingDecoder::Format(Instruction* instr, const char* mnemonic,
3844 const char* format) {
3845 // TODO(mcapewel) don't think I can use the instr address here - there needs
3846 // to be a base address too
3847 DCHECK_NOT_NULL(mnemonic);
3848 ResetOutput();
3849 Substitute(instr, mnemonic);
3850 if (format != nullptr) {
3851 buffer_[buffer_pos_++] = ' ';
3852 Substitute(instr, format);
3853 }
3854 buffer_[buffer_pos_] = 0;
3856}
3857
3858void DisassemblingDecoder::Substitute(Instruction* instr, const char* string) {
3859 char chr = *string++;
3860 while (chr != '\0') {
3861 if (chr == '\'') {
3862 string += SubstituteField(instr, string);
3863 } else {
3864 buffer_[buffer_pos_++] = chr;
3865 }
3866 chr = *string++;
3867 }
3868}
3869
3871 const char* format) {
3872 switch (format[0]) {
3873 // NB. The remaining substitution prefix characters are: GJKUZ.
3874 case 'R': // Register. X or W, selected by sf bit.
3875 case 'F': // FP register. S or D, selected by type field.
3876 case 'V': // Vector register, V, vector format.
3877 case 'W':
3878 case 'X':
3879 case 'B':
3880 case 'H':
3881 case 'S':
3882 case 'D':
3883 case 'Q':
3884 return SubstituteRegisterField(instr, format);
3885 case 'I':
3886 return SubstituteImmediateField(instr, format);
3887 case 'L':
3888 return SubstituteLiteralField(instr, format);
3889 case 'N':
3890 return SubstituteShiftField(instr, format);
3891 case 'P':
3892 return SubstitutePrefetchField(instr, format);
3893 case 'C':
3894 return SubstituteConditionField(instr, format);
3895 case 'E':
3896 return SubstituteExtendField(instr, format);
3897 case 'A':
3898 return SubstitutePCRelAddressField(instr, format);
3899 case 'T':
3900 return SubstituteBranchTargetField(instr, format);
3901 case 'O':
3902 return SubstituteLSRegOffsetField(instr, format);
3903 case 'M':
3904 return SubstituteBarrierField(instr, format);
3905 default:
3906 UNREACHABLE();
3907 }
3908}
3909
3911 const char* format) {
3912 char reg_prefix = format[0];
3913 unsigned reg_num = 0;
3914 unsigned field_len = 2;
3915
3916 switch (format[1]) {
3917 case 'd':
3918 reg_num = instr->Rd();
3919 if (format[2] == 'q') {
3920 reg_prefix = instr->NEONQ() ? 'X' : 'W';
3921 field_len = 3;
3922 }
3923 break;
3924 case 'n':
3925 reg_num = instr->Rn();
3926 break;
3927 case 'm':
3928 reg_num = instr->Rm();
3929 switch (format[2]) {
3930 // Handle registers tagged with b (bytes), z (instruction), or
3931 // r (registers), used for address updates in
3932 // NEON load/store instructions.
3933 case 'r':
3934 case 'b':
3935 case 'z': {
3936 field_len = 3;
3937 char* eimm;
3938 int imm = static_cast<int>(strtol(&format[3], &eimm, 10));
3939 field_len += eimm - &format[3];
3940 if (reg_num == 31) {
3941 switch (format[2]) {
3942 case 'z':
3943 imm *= (1 << instr->NEONLSSize());
3944 break;
3945 case 'r':
3946 imm *= (instr->NEONQ() == 0) ? kDRegSize : kQRegSize;
3947 break;
3948 case 'b':
3949 break;
3950 }
3951 AppendToOutput("#%d", imm);
3952 return field_len;
3953 }
3954 break;
3955 }
3956 }
3957 break;
3958 case 'e':
3959 // This is register Rm, but using a 4-bit specifier. Used in NEON
3960 // by-element instructions.
3961 reg_num = (instr->Rm() & 0xF);
3962 break;
3963 case 'a':
3964 reg_num = instr->Ra();
3965 break;
3966 case 't':
3967 reg_num = instr->Rt();
3968 if (format[0] == 'V') {
3969 if ((format[2] >= '2') && (format[2] <= '4')) {
3970 // Handle consecutive vector register specifiers Vt2, Vt3 and Vt4.
3971 reg_num = (reg_num + format[2] - '1') % 32;
3972 field_len = 3;
3973 }
3974 } else {
3975 if (format[2] == '2') {
3976 // Handle register specifier Rt2.
3977 reg_num = instr->Rt2();
3978 field_len = 3;
3979 }
3980 }
3981 break;
3982 case 's':
3983 reg_num = instr->Rs();
3984 break;
3985 default:
3986 UNREACHABLE();
3987 }
3988
3989 // Increase field length for registers tagged as stack.
3990 if (format[2] == 's') {
3991 field_len = 3;
3992 }
3993
3994 // W or X registers tagged with '+' have their number incremented, to support
3995 // instructions such as CASP.
3996 if (format[2] == '+') {
3997 DCHECK((reg_prefix == 'W') || (reg_prefix == 'X'));
3998 reg_num++;
3999 field_len++;
4000 }
4001
4003 unsigned reg_size;
4004
4005 if (reg_prefix == 'R') {
4006 reg_prefix = instr->SixtyFourBits() ? 'X' : 'W';
4007 } else if (reg_prefix == 'F') {
4008 reg_prefix = ((instr->FPType() & 1) == 0) ? 'S' : 'D';
4009 }
4010
4011 switch (reg_prefix) {
4012 case 'W':
4013 reg_type = CPURegister::kRegister;
4014 reg_size = kWRegSizeInBits;
4015 break;
4016 case 'X':
4017 reg_type = CPURegister::kRegister;
4018 reg_size = kXRegSizeInBits;
4019 break;
4020 case 'B':
4021 reg_type = CPURegister::kVRegister;
4022 reg_size = kBRegSizeInBits;
4023 break;
4024 case 'H':
4025 reg_type = CPURegister::kVRegister;
4026 reg_size = kHRegSizeInBits;
4027 break;
4028 case 'S':
4029 reg_type = CPURegister::kVRegister;
4030 reg_size = kSRegSizeInBits;
4031 break;
4032 case 'D':
4033 reg_type = CPURegister::kVRegister;
4034 reg_size = kDRegSizeInBits;
4035 break;
4036 case 'Q':
4037 reg_type = CPURegister::kVRegister;
4038 reg_size = kQRegSizeInBits;
4039 break;
4040 case 'V':
4041 AppendToOutput("v%d", reg_num);
4042 return field_len;
4043 default:
4044 UNREACHABLE();
4045 }
4046
4047 if ((reg_type == CPURegister::kRegister) && (reg_num == kZeroRegCode) &&
4048 (format[2] == 's')) {
4049 reg_num = kSPRegInternalCode;
4050 }
4051
4052 AppendRegisterNameToOutput(CPURegister::Create(reg_num, reg_size, reg_type));
4053
4054 return field_len;
4055}
4056
4058 const char* format) {
4059 DCHECK_EQ(format[0], 'I');
4060
4061 switch (format[1]) {
4062 case 'M': { // IMoveImm or IMoveLSL.
4063 if (format[5] == 'I' || format[5] == 'N') {
4064 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide())
4065 << (16 * instr->ShiftMoveWide());
4066 if (format[5] == 'N') imm = ~imm;
4067 if (!instr->SixtyFourBits()) imm &= UINT64_C(0xFFFFFFFF);
4068 AppendToOutput("#0x%" PRIx64, imm);
4069 } else {
4070 DCHECK_EQ(format[5], 'L');
4071 AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
4072 if (instr->ShiftMoveWide() > 0) {
4073 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
4074 }
4075 }
4076 return 8;
4077 }
4078 case 'L': {
4079 switch (format[2]) {
4080 case 'L': { // ILLiteral - Immediate Load Literal.
4081 AppendToOutput("pc%+" PRId32,
4082 instr->ImmLLiteral() * kLoadLiteralScale);
4083 return 9;
4084 }
4085 case 'S': { // ILS - Immediate Load/Store.
4086 if (instr->ImmLS() != 0) {
4087 AppendToOutput(", #%" PRId32, instr->ImmLS());
4088 }
4089 return 3;
4090 }
4091 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
4092 if (instr->ImmLSPair() != 0) {
4093 // format[3] is the scale value. Convert to a number.
4094 int scale = 1 << (format[3] - '0');
4095 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale);
4096 }
4097 return 4;
4098 }
4099 case 'U': { // ILU - Immediate Load/Store Unsigned.
4100 if (instr->ImmLSUnsigned() != 0) {
4101 int shift = instr->SizeLS();
4102 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned() << shift);
4103 }
4104 return 3;
4105 }
4106 }
4107 }
4108 case 'C': { // ICondB - Immediate Conditional Branch.
4109 int64_t offset = instr->ImmCondBranch() << 2;
4110 char sign = (offset >= 0) ? '+' : '-';
4111 AppendToOutput("#%c0x%" PRIx64, sign, offset);
4112 return 6;
4113 }
4114 case 'A': { // IAddSub.
4115 DCHECK_LE(instr->ShiftAddSub(), 1);
4116 int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
4117 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
4118 return 7;
4119 }
4120 case 'F': { // IFPSingle, IFPDouble or IFPFBits.
4121 if (format[3] == 'F') { // IFPFBits.
4122 AppendToOutput("#%d", 64 - instr->FPScale());
4123 return 8;
4124 } else {
4125 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmFP(),
4126 format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
4127 return 9;
4128 }
4129 }
4130 case 'T': { // ITri - Immediate Triangular Encoded.
4131 AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
4132 return 4;
4133 }
4134 case 'N': { // INzcv.
4135 int nzcv = (instr->Nzcv() << Flags_offset);
4136 AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
4137 ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
4138 ((nzcv & CFlag) == 0) ? 'c' : 'C',
4139 ((nzcv & VFlag) == 0) ? 'v' : 'V');
4140 return 5;
4141 }
4142 case 'P': { // IP - Conditional compare.
4143 AppendToOutput("#%d", instr->ImmCondCmp());
4144 return 2;
4145 }
4146 case 'B': { // Bitfields.
4148 }
4149 case 'E': { // IExtract.
4150 AppendToOutput("#%d", instr->ImmS());
4151 return 8;
4152 }
4153 case 'S': { // IS - Test and branch bit.
4154 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
4155 instr->ImmTestBranchBit40());
4156 return 2;
4157 }
4158 case 's': { // Is - Shift (immediate).
4159 switch (format[2]) {
4160 case '1': { // Is1 - SSHR.
4161 int shift = 16 << HighestSetBitPosition(instr->ImmNEONImmh());
4162 shift -= instr->ImmNEONImmhImmb();
4163 AppendToOutput("#%d", shift);
4164 return 3;
4165 }
4166 case '2': { // Is2 - SLI.
4167 int shift = instr->ImmNEONImmhImmb();
4168 shift -= 8 << HighestSetBitPosition(instr->ImmNEONImmh());
4169 AppendToOutput("#%d", shift);
4170 return 3;
4171 }
4172 default: {
4173 UNIMPLEMENTED();
4174 }
4175 }
4176 }
4177 case 'D': { // IDebug - HLT and BRK instructions.
4178 AppendToOutput("#0x%x", instr->ImmException());
4179 return 6;
4180 }
4181 case 'V': { // Immediate Vector.
4182 switch (format[2]) {
4183 case 'E': { // IVExtract.
4184 AppendToOutput("#%" PRId64, instr->ImmNEONExt());
4185 return 9;
4186 }
4187 case 'B': { // IVByElemIndex.
4188 int vm_index = (instr->NEONH() << 1) | instr->NEONL();
4189 if (instr->NEONSize() == 1) {
4190 vm_index = (vm_index << 1) | instr->NEONM();
4191 }
4192 AppendToOutput("%d", vm_index);
4193 return static_cast<int>(strlen("IVByElemIndex"));
4194 }
4195 case 'I': { // INS element.
4196 if (strncmp(format, "IVInsIndex", strlen("IVInsIndex")) == 0) {
4197 unsigned rd_index, rn_index;
4198 unsigned imm5 = instr->ImmNEON5();
4199 unsigned imm4 = instr->ImmNEON4();
4200 int tz = base::bits::CountTrailingZeros(imm5);
4201 if (tz <= 3) { // Defined for 0 <= tz <= 3 only.
4202 rd_index = imm5 >> (tz + 1);
4203 rn_index = imm4 >> tz;
4204 if (strncmp(format, "IVInsIndex1", strlen("IVInsIndex1")) == 0) {
4205 AppendToOutput("%d", rd_index);
4206 return static_cast<int>(strlen("IVInsIndex1"));
4207 } else if (strncmp(format, "IVInsIndex2",
4208 strlen("IVInsIndex2")) == 0) {
4209 AppendToOutput("%d", rn_index);
4210 return static_cast<int>(strlen("IVInsIndex2"));
4211 }
4212 }
4213 return 0;
4214 }
4215 UNIMPLEMENTED();
4216 }
4217 case 'L': { // IVLSLane[0123] - suffix indicates access size shift.
4218 AppendToOutput("%d", instr->NEONLSIndex(format[8] - '0'));
4219 return 9;
4220 }
4221 case 'M': { // Modified Immediate cases.
4222 if (strncmp(format, "IVMIImmFPSingle", strlen("IVMIImmFPSingle")) ==
4223 0) {
4224 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(),
4225 instr->ImmNEONFP32());
4226 return static_cast<int>(strlen("IVMIImmFPSingle"));
4227 } else if (strncmp(format, "IVMIImmFPDouble",
4228 strlen("IVMIImmFPDouble")) == 0) {
4229 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(),
4230 instr->ImmNEONFP64());
4231 return static_cast<int>(strlen("IVMIImmFPDouble"));
4232 } else if (strncmp(format, "IVMIImm8", strlen("IVMIImm8")) == 0) {
4233 uint64_t imm8 = instr->ImmNEONabcdefgh();
4234 AppendToOutput("#0x%" PRIx64, imm8);
4235 return static_cast<int>(strlen("IVMIImm8"));
4236 } else if (strncmp(format, "IVMIImm", strlen("IVMIImm")) == 0) {
4237 uint64_t imm8 = instr->ImmNEONabcdefgh();
4238 uint64_t imm = 0;
4239 for (int i = 0; i < 8; ++i) {
4240 if (imm8 & (1ULL << i)) {
4241 imm |= (UINT64_C(0xFF) << (8 * i));
4242 }
4243 }
4244 AppendToOutput("#0x%" PRIx64, imm);
4245 return static_cast<int>(strlen("IVMIImm"));
4246 } else if (strncmp(format, "IVMIShiftAmt1",
4247 strlen("IVMIShiftAmt1")) == 0) {
4248 int cmode = instr->NEONCmode();
4249 int shift_amount = 8 * ((cmode >> 1) & 3);
4250 AppendToOutput("#%d", shift_amount);
4251 return static_cast<int>(strlen("IVMIShiftAmt1"));
4252 } else if (strncmp(format, "IVMIShiftAmt2",
4253 strlen("IVMIShiftAmt2")) == 0) {
4254 int cmode = instr->NEONCmode();
4255 int shift_amount = 8 << (cmode & 1);
4256 AppendToOutput("#%d", shift_amount);
4257 return static_cast<int>(strlen("IVMIShiftAmt2"));
4258 } else {
4259 UNIMPLEMENTED();
4260 }
4261 }
4262 default: {
4263 UNIMPLEMENTED();
4264 }
4265 }
4266 }
4267 default: {
4268 printf("%s", format);
4269 UNREACHABLE();
4270 }
4271 }
4272}
4273
4275 const char* format) {
4276 DCHECK((format[0] == 'I') && (format[1] == 'B'));
4277 unsigned r = instr->ImmR();
4278 unsigned s = instr->ImmS();
4279
4280 switch (format[2]) {
4281 case 'r': { // IBr.
4282 AppendToOutput("#%d", r);
4283 return 3;
4284 }
4285 case 's': { // IBs+1 or IBs-r+1.
4286 if (format[3] == '+') {
4287 AppendToOutput("#%d", s + 1);
4288 return 5;
4289 } else {
4290 DCHECK_EQ(format[3], '-');
4291 AppendToOutput("#%d", s - r + 1);
4292 return 7;
4293 }
4294 }
4295 case 'Z': { // IBZ-r.
4296 DCHECK((format[3] == '-') && (format[4] == 'r'));
4297 unsigned reg_size =
4298 (instr->SixtyFourBits() == 1) ? kXRegSizeInBits : kWRegSizeInBits;
4299 AppendToOutput("#%d", reg_size - r);
4300 return 5;
4301 }
4302 default: {
4303 UNREACHABLE();
4304 }
4305 }
4306}
4307
4309 const char* format) {
4310 DCHECK_EQ(strncmp(format, "LValue", 6), 0);
4311 USE(format);
4312
4313 switch (instr->Mask(LoadLiteralMask)) {
4314 case LDR_w_lit:
4315 case LDR_x_lit:
4316 case LDR_s_lit:
4317 case LDR_d_lit:
4318 AppendToOutput("(addr 0x%016" PRIxPTR ")", instr->LiteralAddress());
4319 break;
4320 default:
4321 UNREACHABLE();
4322 }
4323
4324 return 6;
4325}
4326
4328 const char* format) {
4329 DCHECK_EQ(format[0], 'N');
4330 DCHECK_LE(instr->ShiftDP(), 0x3);
4331
4332 switch (format[1]) {
4333 case 'D': { // NDP.
4334 DCHECK(instr->ShiftDP() != ROR);
4335 [[fallthrough]];
4336 }
4337 case 'L': { // NLo.
4338 if (instr->ImmDPShift() != 0) {
4339 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
4340 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()],
4341 instr->ImmDPShift());
4342 }
4343 return 3;
4344 }
4345 default:
4346 UNREACHABLE();
4347 }
4348}
4349
4351 const char* format) {
4352 DCHECK_EQ(format[0], 'C');
4353 const char* condition_code[] = {"eq", "ne", "hs", "lo", "mi", "pl",
4354 "vs", "vc", "hi", "ls", "ge", "lt",
4355 "gt", "le", "al", "nv"};
4356 int cond;
4357 switch (format[1]) {
4358 case 'B':
4359 cond = instr->ConditionBranch();
4360 break;
4361 case 'I': {
4362 cond = NegateCondition(static_cast<Condition>(instr->Condition()));
4363 break;
4364 }
4365 default:
4366 cond = instr->Condition();
4367 }
4368 AppendToOutput("%s", condition_code[cond]);
4369 return 4;
4370}
4371
4373 const char* format) {
4374 USE(format);
4375 DCHECK_EQ(strncmp(format, "AddrPCRel", 9), 0);
4376
4377 int offset = instr->ImmPCRel();
4378
4379 // Only ADR (AddrPCRelByte) is supported.
4380 DCHECK_EQ(strcmp(format, "AddrPCRelByte"), 0);
4381
4382 char sign = '+';
4383 if (offset < 0) {
4384 sign = '-';
4385 }
4386 AppendToOutput("#%c0x%x (addr %p)", sign, Abs(offset),
4387 instr->InstructionAtOffset(offset, Instruction::NO_CHECK));
4388 return 13;
4389}
4390
4392 const char* format) {
4393 DCHECK_EQ(strncmp(format, "TImm", 4), 0);
4394
4395 int64_t offset = 0;
4396 switch (format[5]) {
4397 // TImmUncn - unconditional branch immediate.
4398 case 'n':
4399 offset = instr->ImmUncondBranch();
4400 break;
4401 // TImmCond - conditional branch immediate.
4402 case 'o':
4403 offset = instr->ImmCondBranch();
4404 break;
4405 // TImmCmpa - compare and branch immediate.
4406 case 'm':
4407 offset = instr->ImmCmpBranch();
4408 break;
4409 // TImmTest - test and branch immediate.
4410 case 'e':
4411 offset = instr->ImmTestBranch();
4412 break;
4413 default:
4414 UNREACHABLE();
4415 }
4416 offset *= kInstrSize;
4417 char sign = '+';
4418 if (offset < 0) {
4419 sign = '-';
4420 }
4421 AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset),
4422 instr->InstructionAtOffset(offset), Instruction::NO_CHECK);
4423 return 8;
4424}
4425
4427 const char* format) {
4428 DCHECK_EQ(strncmp(format, "Ext", 3), 0);
4429 DCHECK_LE(instr->ExtendMode(), 7);
4430 USE(format);
4431
4432 const char* extend_mode[] = {"uxtb", "uxth", "uxtw", "uxtx",
4433 "sxtb", "sxth", "sxtw", "sxtx"};
4434
4435 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
4436 // registers becomes lsl.
4437 if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
4438 (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
4439 (instr->ExtendMode() == UXTX))) {
4440 if (instr->ImmExtendShift() > 0) {
4441 AppendToOutput(", lsl #%d", instr->ImmExtendShift());
4442 }
4443 } else {
4444 AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
4445 if (instr->ImmExtendShift() > 0) {
4446 AppendToOutput(" #%d", instr->ImmExtendShift());
4447 }
4448 }
4449 return 3;
4450}
4451
4453 const char* format) {
4454 DCHECK_EQ(strncmp(format, "Offsetreg", 9), 0);
4455 const char* extend_mode[] = {"undefined", "undefined", "uxtw", "lsl",
4456 "undefined", "undefined", "sxtw", "sxtx"};
4457 USE(format);
4458
4459 unsigned shift = instr->ImmShiftLS();
4460 Extend ext = static_cast<Extend>(instr->ExtendMode());
4461 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
4462
4463 unsigned rm = instr->Rm();
4464 if (rm == kZeroRegCode) {
4465 AppendToOutput("%czr", reg_type);
4466 } else {
4467 AppendToOutput("%c%d", reg_type, rm);
4468 }
4469
4470 // Extend mode UXTX is an alias for shift mode LSL here.
4471 if (!((ext == UXTX) && (shift == 0))) {
4472 AppendToOutput(", %s", extend_mode[ext]);
4473 if (shift != 0) {
4474 AppendToOutput(" #%d", instr->SizeLS());
4475 }
4476 }
4477 return 9;
4478}
4479
4481 const char* format) {
4482 DCHECK_EQ(format[0], 'P');
4483 USE(format);
4484
4485 int prefetch_mode = instr->PrefetchMode();
4486
4487 const char* ls = (prefetch_mode & 0x10) ? "st" : "ld";
4488 int level = (prefetch_mode >> 1) + 1;
4489 const char* ks = (prefetch_mode & 1) ? "strm" : "keep";
4490
4491 AppendToOutput("p%sl%d%s", ls, level, ks);
4492 return 6;
4493}
4494
4496 const char* format) {
4497 DCHECK_EQ(format[0], 'M');
4498 USE(format);
4499
4500 static const char* const options[4][4] = {
4501 {"sy (0b0000)", "oshld", "oshst", "osh"},
4502 {"sy (0b0100)", "nshld", "nshst", "nsh"},
4503 {"sy (0b1000)", "ishld", "ishst", "ish"},
4504 {"sy (0b1100)", "ld", "st", "sy"}};
4505 int domain = instr->ImmBarrierDomain();
4506 int type = instr->ImmBarrierType();
4507
4508 AppendToOutput("%s", options[domain][type]);
4509 return 1;
4510}
4511
4513 buffer_pos_ = 0;
4514 buffer_[buffer_pos_] = 0;
4515}
4516
4517void DisassemblingDecoder::AppendToOutput(const char* format, ...) {
4518 va_list args;
4519 va_start(args, format);
4520 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
4521 va_end(args);
4522}
4523
4525 int q = instr->Bit(30);
4526 const char* mnemonic = q ? "pmull2" : "pmull";
4527 const char* form = NULL;
4528 int size = instr->NEONSize();
4529 if (size == 0) {
4530 if (q == 0) {
4531 form = "'Vd.8h, 'Vn.8b, 'Vm.8b";
4532 } else {
4533 form = "'Vd.8h, 'Vn.16b, 'Vm.16b";
4534 }
4535 } else if (size == 3) {
4536 if (q == 0) {
4537 form = "'Vd.1q, 'Vn.1d, 'Vm.1d";
4538 } else {
4539 form = "'Vd.1q, 'Vn.2d, 'Vm.2d";
4540 }
4541 } else {
4542 mnemonic = "undefined";
4543 }
4544 Format(instr, mnemonic, form);
4545}
4546
4547void PrintDisassembler::ProcessOutput(Instruction* instr) {
4548 fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
4549 reinterpret_cast<uint64_t>(instr), instr->InstructionBits(),
4550 GetOutput());
4551}
4552
4553} // namespace internal
4554} // namespace v8
4555
4556namespace disasm {
4557
4558const char* NameConverter::NameOfAddress(uint8_t* addr) const {
4559 v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
4560 return tmp_buffer_.begin();
4561}
4562
4563const char* NameConverter::NameOfConstant(uint8_t* addr) const {
4564 return NameOfAddress(addr);
4565}
4566
4567const char* NameConverter::NameOfCPURegister(int reg) const {
4568 unsigned ureg = reg; // Avoid warnings about signed/unsigned comparisons.
4570 return "noreg";
4571 }
4572 if (ureg == v8::internal::kZeroRegCode) {
4573 return "xzr";
4574 }
4575 v8::base::SNPrintF(tmp_buffer_, "x%u", ureg);
4576 return tmp_buffer_.begin();
4577}
4578
4579const char* NameConverter::NameOfByteCPURegister(int reg) const {
4580 UNREACHABLE(); // ARM64 does not have the concept of a byte register
4581}
4582
4583const char* NameConverter::NameOfXMMRegister(int reg) const {
4584 UNREACHABLE(); // ARM64 does not have any XMM registers
4585}
4586
4587const char* NameConverter::NameInCode(uint8_t* addr) const {
4588 // The default name converter is called for unknown code, so we will not try
4589 // to access any memory.
4590 return "";
4591}
4592
4593//------------------------------------------------------------------------------
4594
4595class BufferDisassembler : public v8::internal::DisassemblingDecoder {
4596 public:
4597 explicit BufferDisassembler(v8::base::Vector<char> out_buffer)
4598 : out_buffer_(out_buffer) {}
4599
4600 ~BufferDisassembler() {}
4601
4602 virtual void ProcessOutput(v8::internal::Instruction* instr) {
4603 v8::base::SNPrintF(out_buffer_, "%08" PRIx32 " %s",
4604 instr->InstructionBits(), GetOutput());
4605 }
4606
4607 private:
4608 v8::base::Vector<char> out_buffer_;
4609};
4610
4612 uint8_t* instr) {
4613 USE(converter_); // avoid unused field warning
4615 BufferDisassembler disasm(buffer);
4616 decoder.AppendVisitor(&disasm);
4617
4618 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(instr));
4620}
4621
4624 reinterpret_cast<v8::internal::Instruction*>(instr));
4625}
4626
4627void Disassembler::Disassemble(FILE* file, uint8_t* start, uint8_t* end,
4628 UnimplementedOpcodeAction) {
4631 decoder.AppendVisitor(&disasm);
4632
4633 for (uint8_t* pc = start; pc < end; pc += v8::internal::kInstrSize) {
4634 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc));
4635 }
4636}
4637
4638} // namespace disasm
4639
4640#endif // V8_TARGET_ARCH_ARM64
interpreter::OperandScale scale
Definition builtins.cc:44
static V8_EXPORT_PRIVATE void Disassemble(FILE *f, uint8_t *begin, uint8_t *end, UnimplementedOpcodeAction unimplemented_action=kAbortOnUnimplementedOpcode)
V8_EXPORT_PRIVATE int InstructionDecode(v8::base::Vector< char > buffer, uint8_t *instruction)
int ConstantPoolSizeAt(uint8_t *instruction)
const NameConverter & converter_
Definition disasm.h:71
virtual const char * NameOfAddress(uint8_t *addr) const
virtual const char * NameOfXMMRegister(int reg) const
virtual const char * NameInCode(uint8_t *addr) const
virtual const char * NameOfConstant(uint8_t *addr) const
v8::base::EmbeddedVector< char, 128 > tmp_buffer_
Definition disasm.h:32
virtual const char * NameOfByteCPURegister(int reg) const
virtual const char * NameOfCPURegister(int reg) const
constexpr T * begin() const
Definition vector.h:96
static int ConstantPoolSizeAt(Instruction *instr)
static constexpr CPURegister Create(int code, int size, RegisterType type)
virtual void Decode(Instruction *instr)
int SubstituteBranchTargetField(Instruction *instr, const char *format)
int SubstituteBitfieldImmediateField(Instruction *instr, const char *format)
void Substitute(Instruction *instr, const char *string)
int SubstituteExtendField(Instruction *instr, const char *format)
int SubstituteLSRegOffsetField(Instruction *instr, const char *format)
int SubstitutePrefetchField(Instruction *instr, const char *format)
int SubstituteShiftField(Instruction *instr, const char *format)
void DisassembleNEONPolynomialMul(Instruction *instr)
void AppendToOutput(const char *string,...)
int SubstituteRegisterField(Instruction *instr, const char *format)
virtual void ProcessOutput(Instruction *instr)
int SubstituteImmediateField(Instruction *instr, const char *format)
void Format(Instruction *instr, const char *mnemonic, const char *format)
int SubstituteLiteralField(Instruction *instr, const char *format)
bool IsMovzMovnImm(unsigned reg_size, uint64_t value)
virtual void AppendRegisterNameToOutput(const CPURegister &reg)
bool RaIsZROrSP(Instruction *instr) const
bool RnIsZROrSP(Instruction *instr) const
int SubstitutePCRelAddressField(Instruction *instr, const char *format)
int SubstituteConditionField(Instruction *instr, const char *format)
int SubstituteField(Instruction *instr, const char *format)
bool RmIsZROrSP(Instruction *instr) const
bool RdIsZROrSP(Instruction *instr) const
int SubstituteBarrierField(Instruction *instr, const char *format)
static const NEONFormatMap * LoadStoreFormatMap()
static const NEONFormatMap * FPScalarFormatMap()
static const NEONFormatMap * TriangularFormatMap()
static const NEONFormatMap * LogicalFormatMap()
static const NEONFormatMap * IntegerFormatMap()
static const NEONFormatMap * LongScalarFormatMap()
static const NEONFormatMap * FPHPFormatMap()
static const NEONFormatMap * ScalarFormatMap()
static const NEONFormatMap * TriangularScalarFormatMap()
virtual void ProcessOutput(Instruction *instr)
int start
int end
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
int32_t offset
Instruction * instr
LiftoffRegister reg
int r
Definition mul-fft.cc:298
constexpr unsigned CountTrailingZeros(T value)
Definition bits.h:144
int SNPrintF(Vector< char > str, const char *format,...)
Definition strings.cc:20
void * Malloc(size_t size)
Definition memory.h:36
void Free(void *memory)
Definition memory.h:63
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_LD3_post
constexpr NEONScalar3SameOp NEONScalar3SameFPFixed
constexpr NEONScalarPairwiseOp NEON_FMINNMP_scalar
constexpr NEON2RegMiscOp NEON_FNEG
constexpr FPFixedPointConvertOp SCVTF_dw_fixed
constexpr NEONTableOp NEON_TBX_4v
constexpr FPDataProcessing1SourceOp FMOV
constexpr LogicalShiftedOp EOR_w
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST4_s_post
constexpr NEONFormatField NEON_Q
constexpr FPDataProcessing1SourceOp FRINTA
constexpr FPConditionalCompareOp FCCMP_d
constexpr LogicalShiftedOp LogicalShiftedMask
constexpr BitfieldOp BFM_x
constexpr NEONShiftImmediateOp NEON_SSRA
constexpr NEONScalar3SameOp NEON_UQADD_scalar
constexpr LogicalShiftedOp ORN_w
constexpr NEONScalar2RegMiscOp NEON_FCVTNS_scalar
constexpr NEONScalar3SameOp NEON_CMGE_scalar
constexpr MiscInstructionsBits74 CLZ
constexpr AddSubShiftedOp AddSubShiftedMask
constexpr FPIntegerConvertOp FCVTNU_xd
constexpr NEONCopyOp NEON_UMOV
constexpr UnconditionalBranchOp BL
constexpr NEONLoadStoreMultiStructOp NEON_LD3
constexpr ConditionalCompareImmediateOp CCMN_w_imm
constexpr NEONLoadStoreSingleStructOp NEON_LD3_h
constexpr NEONAcrossLanesOp NEONAcrossLanesFMask
constexpr FPIntegerConvertOp FCVTZS_wd
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST3_b_post
constexpr NEONScalarPairwiseOp NEON_FMAXP_scalar
constexpr ConditionalCompareRegisterOp CCMN_x
constexpr NEONLoadStoreSingleStructOp NEON_ST1_b
constexpr ConditionalCompareImmediateOp CCMP_w_imm
constexpr FPCompareOp FCMP_d_zero
constexpr NEON2RegMiscOp NEON_FCMLT_zero
constexpr FPConditionalSelectOp FPConditionalSelectMask
V8_EXPORT_PRIVATE int CountSetBits(uint64_t value, int width)
constexpr NEON2RegMiscOp NEON2RegMiscOpcode
constexpr FPIntegerConvertOp FCVTAS_ws
constexpr NEONScalar2RegMiscOp NEON_FRECPE_scalar
constexpr NEONScalar2RegMiscOp NEON_FCVTAU_scalar
constexpr NEONLoadStoreSingleStructOp NEON_LD1_s
constexpr NEON2RegMiscOp NEON2RegMiscMask
constexpr BitfieldOp UBFM_w
constexpr ExceptionOp BRK
constexpr NEONLoadStoreMultiStructOp NEON_ST3
constexpr FPIntegerConvertOp FCVTZU_xd
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD4_s_post
constexpr NEON2RegMiscOp NEON_UADDLP
constexpr DataProcessing3SourceOp MSUB_x
constexpr NEONScalarByIndexedElementOp NEON_SQDMLSL_byelement_scalar
constexpr NEONScalarPairwiseOp NEON_FADDP_scalar
constexpr NEONLoadStoreSingleStructOp NEON_LD2_h
constexpr LogicalShiftedOp ORN_x
constexpr LoadStorePostIndex LoadStorePostIndexMask
constexpr NEONSHA3Op NEON_EOR3
constexpr NEONScalar2RegMiscOp NEON_FCVTMS_scalar
constexpr FPFixedPointConvertOp SCVTF_sx_fixed
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD1_s_post
constexpr DataProcessing3SourceOp SMSUBL_x
constexpr NEON2RegMiscOp NEON_CMGT_zero
constexpr BitfieldOp SBFM_w
constexpr FPIntegerConvertOp UCVTF_sx
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD1_h_post
constexpr NEON3DifferentOp NEON_SABAL
constexpr NEONScalar3SameOp NEON_SSHL_scalar
constexpr NEONScalar3SameOp NEON_UQSUB_scalar
constexpr NEONLoadStoreSingleStructOp NEON_LD2_s
constexpr FPFixedPointConvertOp FCVTZS_xs_fixed
constexpr NEONScalar2RegMiscOp NEON_FCVTNU_scalar
constexpr NEONLoadStoreSingleStructOp NEON_ST3_h
std::make_unsigned< T >::type Abs(T a)
Definition utils.h:93
constexpr LogicalShiftedOp EOR_x
constexpr NEONLoadStoreMultiStructOp NEON_ST1_4v
constexpr NEONShiftImmediateOp NEON_RSHRN
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD3_b_post
constexpr NEON2RegMiscOp NEON_FCVTMU
constexpr NEONShiftImmediateOp NEON_URSHR
constexpr NEONByIndexedElementOp NEONByIndexedElementFPMask
constexpr NEONScalar3SameOp NEON_UQSHL_scalar
constexpr NEON3SameOp NEON3SameLogicalMask
constexpr DataProcessing1SourceOp DataProcessing1SourceMask
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST3_s_post
constexpr DataProcessing2SourceOp ASRV
constexpr NEONScalar2RegMiscOp NEON_SUQADD_scalar
constexpr LoadStoreAcquireReleaseOp CASPA_w
constexpr NEONCopyOp NEONCopyUmovMask
constexpr NEONScalar2RegMiscOp NEON_FCVTPU_scalar
constexpr UnconditionalBranchToRegisterOp BLR
constexpr FPDataProcessing1SourceOp FCVT_hs
constexpr NEON2RegMiscOp NEON_ABS
constexpr ExceptionOp DCPS3
constexpr NEONShiftImmediateOp NEON_FCVTZS_imm
constexpr NEON2RegMiscOp NEON_FCVTAS
constexpr AddSubWithCarryOp ADC_w
constexpr FPFixedPointConvertOp FPFixedPointConvertMask
constexpr NEONLoadStoreSingleStructOp NEON_LD4_b
constexpr NEONScalarShiftImmediateOp NEON_SQRSHRN_scalar
constexpr NEONAcrossLanesOp NEONAcrossLanesFixed
constexpr NEONLoadStoreSingleStructOp NEON_LD1_b
constexpr NEONScalarShiftImmediateOp NEON_SQSHLU_scalar
constexpr FPCompareOp FCMP_d
constexpr NEONScalarByIndexedElementOp NEON_FMUL_byelement_scalar
constexpr NEONScalarPairwiseOp NEON_ADDP_scalar
constexpr NEONShiftImmediateOp NEON_UQSHRN
constexpr NEONLoadStoreSingleStructOp NEONLoadStoreSingleStructMask
constexpr AddSubImmediateOp AddSubImmediateMask
constexpr ConditionalCompareRegisterOp CCMP_x
constexpr LogicalImmediateOp ORR_x_imm
constexpr NEONShiftImmediateOp NEON_SSHR
constexpr FPIntegerConvertOp FCVTMU_ws
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD4_h_post
constexpr NEONScalar3SameOp NEON_SQADD_scalar
constexpr NEONScalar2RegMiscOp NEON_NEG_scalar_opcode
constexpr NEON3SameOp NEON3SameLogicalFixed
constexpr NEON3SameOp NEON_BSL
constexpr FPIntegerConvertOp FCVTZU_xs
constexpr FPIntegerConvertOp FCVTPU_xs
constexpr FPDataProcessing2SourceOp FPDataProcessing2SourceMask
constexpr FPIntegerConvertOp FCVTMU_xs
constexpr SystemHintOp SystemHintFMask
constexpr NEONLoadStoreMultiStructPostIndexOp NEONLoadStoreMultiStructPostIndexMask
constexpr ExceptionOp SMC
constexpr NEONTableOp NEON_TBL_2v
constexpr NEONScalarShiftImmediateOp NEON_FCVTZS_imm_scalar
constexpr FPCompareOp FCMP_s_zero
constexpr FPIntegerConvertOp FCVTPS_wd
constexpr NEONLoadStoreMultiStructOp NEON_LD2
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD3R_post
constexpr NEONAcrossLanesOp NEON_SMINV
constexpr NEONScalarShiftImmediateOp NEON_URSHR_scalar
constexpr LogicalImmediateOp AND_x_imm
constexpr NEONLoadStoreSingleStructPostIndexOp NEONLoadStoreSingleStructPostIndexMask
constexpr AtomicMemoryOp AtomicMemoryMask
constexpr DataProcessing3SourceOp MSUB_w
constexpr NEONScalarShiftImmediateOp NEON_UCVTF_imm_scalar
constexpr NEONLoadStoreSingleStructOp NEON_LD1_h
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_LD4_post
constexpr ConditionalBranchOp ConditionalBranchMask
constexpr NEONShiftImmediateOp NEON_SRSHR
constexpr NEONScalar3SameOp NEON_ADD_scalar
constexpr NEON2RegMiscOp NEON_SADALP
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD3_h_post
constexpr ConditionalSelectOp CSINC_w
constexpr NEON3SameOp NEON_ORN
constexpr FPFixedPointConvertOp UCVTF_dx_fixed
constexpr BitfieldOp SBFM_x
constexpr FPFixedPointConvertOp UCVTF_dw_fixed
constexpr NEONScalarShiftImmediateOp NEON_URSRA_scalar
constexpr ConditionalSelectOp CSEL_x
constexpr TestBranchOp TBZ
constexpr NEON2RegMiscOp NEON_CMLT_zero
constexpr LoadStoreAcquireReleaseOp CASPAL_x
constexpr FPIntegerConvertOp FCVTMS_xd
constexpr NEONScalar2RegMiscOp NEON_ABS_scalar
constexpr NEONLoadStoreMultiStructOp NEON_ST1_3v
constexpr NEONCopyOp NEONCopyInsGeneralMask
constexpr NEONLoadStoreMultiStructOp NEON_LD1_3v
constexpr FPDataProcessing1SourceOp FRINTP
constexpr FPDataProcessing2SourceOp FSUB
constexpr NEON2RegMiscOp NEON_FCVTZS
constexpr ExceptionOp HVC
constexpr AddSubExtendedOp AddSubExtendedMask
constexpr NEONScalar2RegMiscOp NEON_USQADD_scalar
constexpr NEON2RegMiscOp NEON_RBIT_NOT
constexpr FPIntegerConvertOp FCVTNS_xs
constexpr NEONAcrossLanesOp NEON_UMINV
constexpr FPDataProcessing1SourceOp FCVT_dh
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST1_s_post
constexpr NEONTableOp NEON_TBL_1v
constexpr NEON2RegMiscOp NEON_FCVTN
constexpr NEONScalar3SameOp NEON_SQRDMULH_scalar
constexpr NEONLoadStoreSingleStructOp NEON_LD1R
constexpr NEONScalar2RegMiscOp NEON_FRECPX_scalar
constexpr NEON3SameOp NEON3SameLogicalFMask
constexpr NEON3DifferentOp NEON_SSUBW
constexpr LoadStorePairOffsetOp LoadStorePairOffsetMask
constexpr NEONByIndexedElementOp NEON_SQDMLSL_byelement
constexpr LogicalShiftedOp ANDS_x
constexpr ConditionalCompareImmediateOp CCMN_x_imm
constexpr FPDataProcessing1SourceOp FABS
constexpr NEONScalar3SameOp NEON_FRECPS_scalar
constexpr NEONLoadStoreSingleStructOp NEON_LD4_h
constexpr LogicalShiftedOp BICS_w
constexpr FPIntegerConvertOp FCVTMU_wd
constexpr FPFixedPointConvertOp FCVTZU_xd_fixed
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD2_s_post
constexpr int kWRegSizeInBits
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_ST2_post
constexpr DataProcessing3SourceOp DataProcessing3SourceMask
constexpr NEONPermOp NEON_ZIP1
constexpr int kZeroRegCode
constexpr NEON3DifferentOp NEON_SSUBL
constexpr int kNumberOfRegisters
constexpr NEON3DifferentOp NEON_SADDW
constexpr FPIntegerConvertOp FCVTPS_ws
constexpr NEONScalar3SameOp NEON_FACGT_scalar
constexpr FPDataProcessing2SourceOp FNMUL
constexpr NEON2RegMiscOp NEON_FCVTZU
constexpr NEONLoadStoreSingleStructOp NEON_ST2_h
constexpr NEON2RegMiscOp NEON_FCVTMS
constexpr NEON2RegMiscOp NEON_FRINTM
constexpr NEONAcrossLanesOp NEONAcrossLanesMask
constexpr NEONTableOp NEONTableMask
constexpr NEONShiftImmediateOp NEON_URSRA
constexpr ShiftOp LSL
constexpr int B
constexpr NEONLoadStoreSingleStructOp NEON_LD4_d
constexpr NEONShiftImmediateOp NEON_SQSHRUN
constexpr NEONLoadStoreMultiStructOp NEON_ST2
constexpr NEONAcrossLanesOp NEON_UMAXV
constexpr NEONScalar2RegMiscOp NEON_CMEQ_zero_scalar
constexpr NEONScalar2RegMiscOp NEON_UQXTN_scalar
constexpr MemBarrierOp MemBarrierFixed
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST2_b_post
constexpr LogicalImmediateOp EOR_w_imm
constexpr AddSubWithCarryOp AddSubWithCarryMask
constexpr DataProcessing1SourceOp REV32_x
constexpr NEON2RegMiscOp NEON_XTN
constexpr FPConditionalSelectOp FCSEL_d
constexpr NEONByIndexedElementOp NEON_SQDMULH_byelement
constexpr LogicalImmediateOp ORR_w_imm
constexpr LogicalShiftedOp ORR_w
constexpr NEONScalar2RegMiscOp NEON_FCVTZS_scalar
constexpr NEON2RegMiscOp NEON_FCMGE_zero
constexpr AddSubWithCarryOp SBC_x
constexpr BitfieldOp BFM_w
constexpr NEONScalar2RegMiscOp NEON_FRSQRTE_scalar
constexpr NEONScalarShiftImmediateOp NEON_SRSRA_scalar
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD4_b_post
constexpr NEONScalarShiftImmediateOp NEON_SHL_scalar
constexpr NEON2RegMiscOp NEON2RegMiscHPFixed
constexpr FPIntegerConvertOp FCVTPU_wd
constexpr FPFixedPointConvertOp SCVTF_dx_fixed
constexpr NEON2RegMiscOp NEON_URECPE
constexpr LoadStoreAcquireReleaseOp CASP_x
constexpr NEON3DifferentOp NEON_ADDHN
constexpr FPIntegerConvertOp FCVTAU_ws
constexpr FPIntegerConvertOp FCVTMS_ws
constexpr FPDataProcessing3SourceOp FPDataProcessing3SourceMask
constexpr ConditionalCompareRegisterOp CCMN_w
constexpr SystemHintOp HINT
constexpr NEON2RegMiscOp NEON_URSQRTE
constexpr NEON2RegMiscOp NEON_FCVTAU
constexpr FPConditionalCompareOp FCCMP_s
constexpr NEONScalar2RegMiscOp NEON_SQNEG_scalar
constexpr ExtractOp ExtractMask
constexpr FPIntegerConvertOp UCVTF_dx
constexpr DataProcessing2SourceOp DataProcessing2SourceMask
constexpr NEONLoadStoreMultiStructOp NEON_LD1_2v
constexpr DataProcessing2SourceOp RORV
constexpr NEONScalarShiftImmediateOp NEON_SQSHRN_scalar
constexpr FPConditionalCompareOp FPConditionalCompareMask
constexpr NEON3DifferentOp NEON_UABAL
constexpr FPIntegerConvertOp FCVTAS_xd
constexpr NEONScalar2RegMiscOp NEON_UCVTF_scalar
constexpr NEON2RegMiscOp NEON_FCVTL
constexpr FPImmediateOp FPImmediateMask
constexpr NEON2RegMiscOp NEON_FRINTI
constexpr NEON2RegMiscOp NEON_SQNEG
constexpr NEONByIndexedElementOp NEON_SQDMLAL_byelement
constexpr BitfieldOp UBFM_x
constexpr NEONTableOp NEON_TBX_1v
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST4_b_post
constexpr FPDataProcessing1SourceOp FCVT_sh
constexpr NEONScalar3SameOp NEON_FRSQRTS_scalar
constexpr NEONLoadStoreSingleStructOp NEON_LD3_s
constexpr NEON2RegMiscOp NEON_UCVTF
constexpr SystemSysRegOp MRS
constexpr DataProcessing2SourceOp LSLV
constexpr FPIntegerConvertOp FCVTMS_xs
constexpr uint8_t kLoadLiteralScale
constexpr NEON2RegMiscOp NEON_REV16
constexpr NEONScalar3SameOp NEON_URSHL_scalar
constexpr NEON3DifferentOp NEON_SQDMULL
constexpr NEON2RegMiscOp NEON_NEG
constexpr NEONLoadStoreSingleStructOp NEON_ST4_h
constexpr NEON3SameOp NEON_BIF
constexpr LoadStoreUnsignedOffset PRFM_unsigned
constexpr FPDataProcessing2SourceOp FMAX
constexpr FPFixedPointConvertOp FCVTZS_wd_fixed
constexpr NEON2RegMiscOp NEON_REV64
constexpr NEONCopyOp NEON_DUP_GENERAL
constexpr ExceptionOp ExceptionMask
constexpr FPIntegerConvertOp FCVTMS_wd
constexpr FPDataProcessing2SourceOp FMAXNM
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD2_b_post
constexpr NEONShiftImmediateOp NEON_UQSHL_imm
constexpr FPIntegerConvertOp FPIntegerConvertMask
constexpr NEONScalar3SameOp NEON_SQSUB_scalar
constexpr NEON3DifferentOp NEON_UADDL
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_ST1_3v_post
constexpr SystemSysRegOp MSR
constexpr NEONScalar3SameOp NEON_SQRSHL_scalar
constexpr NEONLoadStoreSingleStructOp NEON_ST1_h
constexpr NEONTableOp NEON_TBX_3v
constexpr NEONByIndexedElementOp NEON_UMULL_byelement
constexpr FPDataProcessing1SourceOp FCVT_hd
constexpr NEONScalarShiftImmediateOp NEON_SQSHRUN_scalar
constexpr FPDataProcessing2SourceOp FMINNM
constexpr NEONShiftImmediateOp NEON_SLI
constexpr NEONScalarByIndexedElementOp NEON_SQRDMULH_byelement_scalar
constexpr DataProcessing3SourceOp SMADDL_x
constexpr NEONLoadStoreSingleStructOp NEON_LD4_s
constexpr NEON2RegMiscOp NEON_FRINTA
constexpr NEONSHA3Op NEONSHA3Mask
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_LD1_1v_post
constexpr NEONScalarShiftImmediateOp NEON_SSRA_scalar
constexpr NEONScalar2RegMiscOp NEONScalar2RegMiscMask
constexpr DataProcessing2SourceOp LSRV
int HighestSetBitPosition(uint64_t value)
constexpr CompareBranchOp CBZ_w
constexpr NEONAcrossLanesOp NEON_FMAXV
constexpr FPDataProcessing1SourceOp FRINTM
constexpr MoveWideImmediateOp MOVZ_x
constexpr NEONScalar2RegMiscOp NEON_SQXTN_scalar
constexpr NEON2RegMiscOp NEON_SADDLP
constexpr FPIntegerConvertOp SCVTF_dw
constexpr FPIntegerConvertOp FCVTZS_xs
constexpr NEON3DifferentOp NEON_SADDL
constexpr SystemSysRegOp SystemSysRegFixed
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_ST1_1v_post
constexpr FPIntegerConvertOp FCVTPS_xs
constexpr NEONScalar3DiffOp NEON_SQDMLAL_scalar
constexpr NEONPermOp NEON_TRN1
constexpr NEONByIndexedElementOp NEON_MUL_byelement
constexpr NEONShiftImmediateOp NEON_SQSHLU
constexpr NEONAcrossLanesOp NEON_FMINNMV
constexpr NEONScalar3SameOp NEON_CMTST_scalar
constexpr NEONScalar3SameOp NEON_FACGE_scalar
constexpr NEONShiftImmediateOp NEON_USHLL
constexpr NEONScalar3SameOp NEON_SQSHL_scalar
constexpr NEON2RegMiscOp NEON_XTN_opcode
constexpr NEON2RegMiscOp NEON_REV32
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD1R_post
constexpr LogicalShiftedOp EON_w
constexpr DataProcessing3SourceOp MADD_w
constexpr FPFixedPointConvertOp FCVTZU_ws_fixed
constexpr FPIntegerConvertOp FCVTNU_wd
constexpr NEONScalarShiftImmediateOp NEON_USHR_scalar
constexpr NEON2RegMiscOp NEON_FCMEQ_zero
constexpr DataProcessing3SourceOp UMADDL_x
Disallow flags or implications overriding each other abort_on_contradictory_flags true
Definition flags.cc:368
constexpr NEONScalarShiftImmediateOp NEON_FCVTZU_imm_scalar
constexpr FPDataProcessing2SourceOp FDIV
constexpr NEONShiftImmediateOp NEON_SQRSHRUN
constexpr NEONLoadStoreMultiStructOp NEON_LD4
constexpr DataProcessing1SourceOp RBIT
constexpr FPIntegerConvertOp FCVTPU_ws
constexpr LogicalShiftedOp BIC_x
constexpr NEONScalar3SameOp NEONScalar3SameFPFMask
constexpr FPIntegerConvertOp FCVTMU_xd
constexpr NEONCopyOp NEON_INS_GENERAL
constexpr NEONScalar2RegMiscOp NEON_SQXTUN_scalar
constexpr NEON2RegMiscOp NEON_CNT
constexpr NEONPermOp NEON_ZIP2
constexpr NEONScalar3SameOp NEON_CMHI_scalar
constexpr FPConditionalCompareOp FCCMPE_d
constexpr DataProcessing1SourceOp CLS
constexpr NEONExtractOp NEON_EXT
constexpr NEONPermOp NEON_TRN2
constexpr UnconditionalBranchToRegisterOp BR
constexpr LoadLiteralOp LDR_d_lit
constexpr NEONScalar3SameOp NEON_UQRSHL_scalar
constexpr NEON2RegMiscOp NEON_FRSQRTE
constexpr FPIntegerConvertOp FCVTAS_wd
constexpr FPIntegerConvertOp FCVTNU_ws
constexpr CompareBranchOp CompareBranchMask
constexpr NEONShiftImmediateOp NEON_USRA
constexpr NEONScalar3SameOp NEON_FCMEQ_scalar
constexpr NEON3DifferentOp NEON_UMLSL
constexpr NEONScalar3DiffOp NEON_SQDMLSL_scalar
constexpr NEONAcrossLanesOp NEONAcrossLanesFPFixed
Condition NegateCondition(Condition cond)
constexpr NEON2RegMiscOp NEON_FCVTXN
constexpr FPIntegerConvertOp SCVTF_sx
constexpr ConditionalSelectOp CSINV_x
constexpr NEONPermOp NEONPermMask
constexpr NEONScalarShiftImmediateOp NEON_SSHR_scalar
constexpr NEONCopyOp NEON_SMOV
constexpr SystemHintOp SystemHintFixed
constexpr FPIntegerConvertOp FCVTAS_xs
constexpr NEON2RegMiscOp NEON_SUQADD
constexpr NEONScalarShiftImmediateOp NEON_SQSHL_imm_scalar
constexpr NEONScalarShiftImmediateOp NEON_SLI_scalar
constexpr NEONScalar3DiffOp NEON_SQDMULL_scalar
constexpr NEONCopyOp NEONCopyInsElementMask
constexpr NEONScalarByIndexedElementOp NEON_FMULX_byelement_scalar
constexpr ConditionalCompareRegisterOp ConditionalCompareRegisterMask
constexpr int kBRegSizeInBits
constexpr NEONScalarByIndexedElementOp NEON_SQDMLAL_byelement_scalar
constexpr FPIntegerConvertOp FJCVTZS
constexpr NEONShiftImmediateOp NEON_UCVTF_imm
constexpr NEONScalar3SameOp NEON_FCMGT_scalar
constexpr NEON2RegMiscOp NEON_FRINTZ
constexpr ConditionalSelectOp CSINC_x
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST3_h_post
constexpr FPDataProcessing1SourceOp FRINTZ
constexpr NEONByIndexedElementOp NEON_FMULX_byelement
constexpr NEONExtractOp NEONExtractMask
constexpr NEONScalarPairwiseOp NEON_FMAXNMP_scalar
constexpr CompareBranchOp CBZ_x
constexpr NEON3SameOp NEON_ORR
constexpr NEONScalar3SameOp NEON_FCMGE_scalar
constexpr MoveWideImmediateOp MoveWideImmediateMask
constexpr LogicalImmediateOp ANDS_w_imm
constexpr SystemPAuthOp SystemPAuthFixed
constexpr BitfieldOp BitfieldMask
constexpr NEONLoadStoreSingleStructOp NEON_ST4_b
constexpr FPDataProcessing1SourceOp FRINTI
constexpr DataProcessing1SourceOp REV16
constexpr NEONCopyOp NEON_INS_ELEMENT
constexpr NEONScalarShiftImmediateOp NEON_SCVTF_imm_scalar
constexpr NEONScalar2RegMiscOp NEON_SQABS_scalar
constexpr SystemPAuthOp SystemPAuthMask
constexpr FPIntegerConvertOp FCVTAU_xd
constexpr NEONAcrossLanesOp NEON_SADDLV
constexpr NEON2RegMiscOp NEON_CMLE_zero
constexpr DataProcessing1SourceOp REV
constexpr FPIntegerConvertOp UCVTF_sw
constexpr LoadStoreRegisterOffset LoadStoreRegisterOffsetMask
constexpr FPDataProcessing1SourceOp FRINTX
constexpr NEONLoadStoreSingleStructOp NEON_LD2_d
constexpr NEONScalar2RegMiscOp NEON_FCMGT_zero_scalar
constexpr FPDataProcessing1SourceOp FRINTN
constexpr NEONScalar2RegMiscOp NEON_FCMLT_zero_scalar
constexpr NEON2RegMiscOp NEON_UQXTN_opcode
constexpr LogicalShiftedOp ANDS_w
constexpr NEONShiftImmediateOp NEON_SQRSHRN
constexpr NEONScalarShiftImmediateOp NEONScalarShiftImmediateMask
constexpr NEON3SameOp NEON3SameFPFMask
constexpr NEONLoadStoreSingleStructOp NEON_ST1_d
constexpr LogicalImmediateOp LogicalImmediateMask
constexpr NEON2RegMiscOp NEON_CMEQ_zero
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_ST1_2v_post
constexpr FPIntegerConvertOp FCVTNS_wd
constexpr FPFixedPointConvertOp FCVTZS_ws_fixed
constexpr MoveWideImmediateOp MOVK_w
constexpr NEON2RegMiscOp NEON_CLS
constexpr NEONAcrossLanesOp NEON_UADDLV
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST1_h_post
constexpr LoadLiteralOp LoadLiteralMask
constexpr NEONScalar2RegMiscOp NEON_FCMLE_zero_scalar
constexpr FPDataProcessing2SourceOp FADD
constexpr NEONLoadStoreSingleStructOp NEON_LD3R
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_LD2_post
constexpr MemBarrierOp MemBarrierFMask
constexpr LoadStoreAcquireReleaseOp CASP_w
constexpr int kQRegSize
constexpr FPIntegerConvertOp FCVTPS_xd
constexpr NEONAcrossLanesOp NEONAcrossLanesFPFMask
constexpr MemBarrierOp DSB
constexpr FPIntegerConvertOp FMOV_d1_x
constexpr NEONScalar2RegMiscOp NEON_CMGT_zero_scalar
constexpr FPIntegerConvertOp FCVTNS_xd
constexpr NEON3SameOp NEON_AND
constexpr NEONSHA3Op NEON_BCAX
constexpr NEONScalar2RegMiscOp NEON_CMGE_zero_scalar
constexpr LoadStoreAcquireReleaseOp CASPL_x
constexpr NEONByIndexedElementOp NEON_SMLAL_byelement
constexpr NEONAcrossLanesOp NEON_SMAXV
constexpr ExtractOp EXTR_x
constexpr NEON3ExtensionOp NEON_SDOT
constexpr NEONScalar2RegMiscOp NEON_CMLE_zero_scalar
constexpr NEON3DifferentOp NEON_UABDL
constexpr LoadLiteralOp LDR_w_lit
constexpr PCRelAddressingOp PCRelAddressingMask
constexpr DataProcessing3SourceOp MADD_x
constexpr FPIntegerConvertOp FMOV_x_d1
constexpr SystemSysRegOp SystemSysRegMask
constexpr NEONScalarShiftImmediateOp NEON_SQRSHRUN_scalar
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_ST1_4v_post
constexpr NEONPermOp NEON_UZP1
constexpr NEONLoadStoreSingleStructOp NEON_LD1_d
constexpr NEONShiftImmediateOp NEON_SRSRA
constexpr ConditionalCompareRegisterOp CCMP_w
constexpr FPConditionalCompareOp FCCMPE_s
constexpr LoadStoreAcquireReleaseOp CASPA_x
constexpr NEONAcrossLanesOp NEON_ADDV
constexpr FPIntegerConvertOp FCVTAU_wd
constexpr NEONByIndexedElementOp NEON_FMLA_byelement
constexpr UnconditionalBranchOp UnconditionalBranchMask
constexpr FPConditionalSelectOp FCSEL_s
constexpr int kLinkRegCode
constexpr NEONByIndexedElementOp NEON_SMLSL_byelement
constexpr NEONScalar3SameOp NEON_USHL_scalar
constexpr NEONShiftImmediateOp NEON_SSHLL
constexpr NEONScalarPairwiseOp NEON_FMINP_scalar
constexpr ConditionalBranchOp B_cond
constexpr NEONShiftImmediateOp NEON_SQSHRN
constexpr DataProcessing3SourceOp SMULH_x
constexpr NEONScalarShiftImmediateOp NEON_USRA_scalar
constexpr FPIntegerConvertOp FMOV_dx
constexpr ExtractOp EXTR_w
constexpr NEONScalarShiftImmediateOp NEON_UQSHRN_scalar
constexpr DataProcessing3SourceOp UMULH_x
constexpr LogicalImmediateOp AND_w_imm
constexpr NEONScalar2RegMiscOp NEON_CMLT_zero_scalar
constexpr NEONLoadStoreSingleStructOp NEON_ST2_s
constexpr NEONScalar2RegMiscOp NEON_FCMGE_zero_scalar
constexpr NEONShiftImmediateOp NEON_SRI
constexpr NEONLoadStoreSingleStructOp NEON_ST4_d
constexpr NEONByIndexedElementOp NEON_FMLS_byelement
constexpr NEON3DifferentOp NEON_UMULL
constexpr MemBarrierOp DMB
constexpr NEON3DifferentOp NEON_SQDMLAL
constexpr NEONLoadStoreSingleStructOp NEON_ST1_s
constexpr NEON2RegMiscOp NEON_SQABS
constexpr NEON3DifferentOp NEON_USUBW
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD3_s_post
constexpr NEON2RegMiscOp NEON_UADALP
constexpr NEON3DifferentOp NEON_UADDW
constexpr ConditionalSelectOp CSEL_w
constexpr NEONScalarShiftImmediateOp NEON_SRI_scalar
constexpr NEONShiftImmediateOp NEON_SHRN
constexpr UnconditionalBranchToRegisterOp UnconditionalBranchToRegisterMask
constexpr NEONScalar2RegMiscOp NEON_FCVTXN_scalar
constexpr NEON3SameOp NEON_BIC
constexpr TestBranchOp TBNZ
constexpr NEONScalar3SameOp NEON_SQDMULH_scalar
constexpr ConditionalCompareImmediateOp CCMP_x_imm
constexpr ConditionalSelectOp ConditionalSelectMask
constexpr FPDataProcessing1SourceOp FNEG
constexpr FPCompareOp FCMP_s
constexpr NEONByIndexedElementOp NEONByIndexedElementMask
constexpr ShiftOp ROR
constexpr NEON3DifferentOp NEON_RSUBHN
constexpr NEONAcrossLanesOp NEON_FMAXNMV
constexpr SystemPAuthOp SystemPAuthFMask
constexpr LoadStoreAcquireReleaseOp CASPL_w
constexpr NEONLoadStoreMultiStructOp NEON_LD1_4v
constexpr NEONScalarByIndexedElementOp NEONScalarByIndexedElementFPMask
constexpr TestBranchOp TestBranchMask
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_ST3_post
constexpr FPIntegerConvertOp FCVTZS_xd
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST1_b_post
constexpr FPDataProcessing2SourceOp FMIN
constexpr NEON2RegMiscOp NEON_FABS
constexpr NEON2RegMiscOp NEON_FCVTPS
constexpr LoadStoreUnscaledOffsetOp LoadStoreUnscaledOffsetMask
constexpr AddSubWithCarryOp ADCS_w
constexpr NEON3SameOp NEON3SameFPFixed
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_ST4_post
constexpr ExceptionOp HLT
constexpr NEONScalarShiftImmediateOp NEON_UQSHL_imm_scalar
constexpr MoveWideImmediateOp MOVN_x
constexpr NEON3DifferentOp NEON_UMLAL
constexpr CompareBranchOp CBNZ_w
constexpr NEON2RegMiscOp NEON_SQXTUN
constexpr MemBarrierOp MemBarrierMask
constexpr NEONLoadStoreSingleStructOp NEON_ST3_s
constexpr NEONByIndexedElementOp NEON_SQRDMULH_byelement
constexpr int kXRegSizeInBits
constexpr NEONScalar2RegMiscOp NEON_FCVTAS_scalar
constexpr NEON2RegMiscOp NEON_FCMGT_zero
constexpr NEONShiftImmediateOp NEON_SQSHL_imm
constexpr DataProcessing2SourceOp SDIV
constexpr NEONScalar3SameOp NEON_SRSHL_scalar
constexpr NEONByIndexedElementOp NEON_UMLAL_byelement
constexpr int kNumberOfVRegisters
constexpr NEONTableOp NEON_TBL_3v
constexpr FPDataProcessing1SourceOp FCVT_sd
constexpr NEON3SameOp NEON_BIT
constexpr LogicalShiftedOp BICS_x
constexpr NEONScalarCopyOp NEON_DUP_ELEMENT_scalar
constexpr NEON2RegMiscOp NEON_SHLL
constexpr FPIntegerConvertOp FCVTZS_ws
constexpr NEON3DifferentOp NEON_SABDL
constexpr NEONScalar2RegMiscOp NEON_FCVTMU_scalar
constexpr NEON2RegMiscOp NEON2RegMiscFPMask
constexpr NEONLoadStoreMultiStructOp NEON_ST4
constexpr NEON2RegMiscOp NEON_FCMLE_zero
constexpr NEON3DifferentOp NEON_PMULL
constexpr uint8_t kInstrSize
constexpr int kSPRegInternalCode
constexpr int kSRegSizeInBits
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD4R_post
constexpr NEON2RegMiscOp NEON_CMGE_zero
constexpr SystemSysRegOp SystemSysRegFMask
constexpr NEONAcrossLanesOp NEON_FMINV
constexpr NEONLoadStoreSingleStructOp NEON_ST2_d
constexpr FPIntegerConvertOp SCVTF_dx
constexpr FPFixedPointConvertOp SCVTF_sw_fixed
constexpr LoadLiteralOp LDR_s_lit
constexpr NEON3DifferentOp NEON_SUBHN
constexpr NEONShiftImmediateOp NEON_UQRSHRN
constexpr MoveWideImmediateOp MOVK_x
constexpr NEONScalar3SameOp NEONScalar3SameMask
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD1_b_post
constexpr LoadStorePreIndex LoadStorePreIndexMask
constexpr NEONShiftImmediateOp NEON_FCVTZU_imm
constexpr NEONByIndexedElementOp NEON_FMUL_byelement
constexpr FPDataProcessing1SourceOp FPDataProcessing1SourceMask
constexpr NEON2RegMiscOp NEON_FRINTP
constexpr AddSubWithCarryOp SBC_w
constexpr NEONScalar3SameOp NEON_FABD_scalar
constexpr AddSubWithCarryOp SBCS_x
constexpr NEONByIndexedElementOp NEON_SQDMULL_byelement
constexpr NEONLoadStoreMultiStructOp NEON_ST1_2v
constexpr FPIntegerConvertOp FMOV_ws
constexpr NEONLoadStoreSingleStructOp NEON_ST3_b
constexpr LogicalShiftedOp AND_x
constexpr LogicalImmediateOp ANDS_x_imm
constexpr NEONLoadStoreSingleStructOp NEON_ST2_b
constexpr int kDRegSize
constexpr FPFixedPointConvertOp FCVTZS_xd_fixed
constexpr AddSubWithCarryOp SBCS_w
constexpr MoveWideImmediateOp MOVN_w
constexpr int kQRegSizeInBits
constexpr NEONScalarCopyOp NEONScalarCopyMask
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD2R_post
constexpr FPIntegerConvertOp FCVTNU_xs
constexpr FPCompareOp FPCompareMask
constexpr NEON3DifferentOp NEON_SQDMLSL
constexpr NEONScalar3SameOp NEON_CMEQ_scalar
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST2_s_post
constexpr NEON3DifferentOp NEON_SMLSL
constexpr LoadLiteralOp LDR_x_lit
constexpr NEONLoadStoreSingleStructOp NEON_ST4_s
constexpr NEONScalar3SameOp NEON_SUB_scalar
constexpr NEON2RegMiscOp NEON_NEG_opcode
constexpr NEON3DifferentOp NEON_RADDHN
constexpr ExceptionOp SVC
constexpr NEONShiftImmediateOp NEON_SCVTF_imm
constexpr NEON2RegMiscOp NEON_UQXTN
constexpr LoadStoreAcquireReleaseOp LoadStoreAcquireReleaseMask
constexpr NEONByIndexedElementOp NEON_MLA_byelement
constexpr NEONTableOp NEON_TBL_4v
constexpr NEONTableOp NEON_TBX_2v
constexpr LogicalImmediateOp EOR_x_imm
constexpr NEONShiftImmediateOp NEONShiftImmediateMask
constexpr NEONLoadStoreMultiStructOp NEONLoadStoreMultiStructMask
constexpr LogicalShiftedOp AND_w
constexpr LoadStoreRegisterOffset PRFM_reg
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_LD1_2v_post
constexpr ConditionalSelectOp CSNEG_x
constexpr UnconditionalBranchToRegisterOp RET
constexpr NEONScalarByIndexedElementOp NEON_FMLA_byelement_scalar
constexpr NEONScalarByIndexedElementOp NEON_SQDMULL_byelement_scalar
constexpr FPDataProcessing2SourceOp FMUL
constexpr NEON2RegMiscOp NEON_FRECPE
constexpr CompareBranchOp CBNZ_x
constexpr FPIntegerConvertOp UCVTF_dw
constexpr NEONCopyOp NEONCopyDupElementMask
constexpr NEONScalar2RegMiscOp NEON_NEG_scalar
constexpr NEONScalar3SameOp NEON_CMHS_scalar
constexpr NEON2RegMiscOp NEON_USQADD
constexpr NEONShiftImmediateOp NEON_SHL
constexpr FPImmediateOp FMOV_s_imm
constexpr NEONScalarShiftImmediateOp NEON_UQRSHRN_scalar
constexpr FPIntegerConvertOp FCVTZU_ws
constexpr NEONScalar3SameOp NEON_FMULX_scalar
constexpr NEONByIndexedElementOp NEON_MLS_byelement
constexpr NEONScalar2RegMiscOp NEON_FCMEQ_zero_scalar
constexpr NEONAcrossLanesOp NEONAcrossLanesFPMask
constexpr ConditionalSelectOp CSINV_w
constexpr NEONCopyOp NEON_DUP_ELEMENT
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_LD1_4v_post
constexpr NEONScalar2RegMiscOp NEON_FCVTZU_scalar
constexpr NEONCopyOp NEONCopySmovMask
constexpr MoveWideImmediateOp MOVZ_w
constexpr NEONLoadStoreSingleStructOp NEON_LD4R
constexpr ExceptionOp DCPS1
constexpr DataProcessing3SourceOp UMSUBL_x
constexpr NEON2RegMiscOp NEON_FRINTN
constexpr NEON3DifferentOp NEON3DifferentMask
constexpr NEON2RegMiscOp NEON_SCVTF
constexpr NEONPermOp NEON_UZP2
constexpr NEONScalarByIndexedElementOp NEON_SQDMULH_byelement_scalar
constexpr LoadStorePairPostIndexOp LoadStorePairPostIndexMask
constexpr SystemHintOp SystemHintMask
constexpr FPFixedPointConvertOp FCVTZU_xs_fixed
constexpr NEONShiftImmediateOp NEON_USHR
constexpr NEONLoadStoreMultiStructOp NEON_LD1_1v
constexpr FPDataProcessing1SourceOp FSQRT
constexpr NEONScalarShiftImmediateOp NEON_SRSHR_scalar
constexpr FPIntegerConvertOp SCVTF_sw
constexpr NEONScalarByIndexedElementOp NEON_FMLS_byelement_scalar
constexpr FPFixedPointConvertOp UCVTF_sx_fixed
constexpr NEONLoadStoreSingleStructOp NEON_LD3_b
constexpr NEON3DifferentOp NEON_USUBL
constexpr NEONCopyOp NEONCopyDupGeneralMask
constexpr FPFixedPointConvertOp FCVTZU_wd_fixed
constexpr FPFixedPointConvertOp UCVTF_sw_fixed
constexpr NEONScalarPairwiseOp NEONScalarPairwiseMask
constexpr NEON2RegMiscOp NEON_FSQRT
constexpr NEONScalar2RegMiscOp NEON_FCVTPS_scalar
constexpr LogicalShiftedOp ORR_x
constexpr DataProcessing2SourceOp UDIV
constexpr ConditionalCompareImmediateOp ConditionalCompareImmediateMask
constexpr NEONScalar3SameOp NEONScalar3SameFPMask
constexpr NEON3DifferentOp NEON_SMULL
constexpr NEONScalar3DiffOp NEONScalar3DiffMask
constexpr LogicalShiftedOp EON_x
constexpr FPIntegerConvertOp FCVTPU_xd
constexpr ConditionalSelectOp CSNEG_w
constexpr NEONByIndexedElementOp NEON_UMLSL_byelement
constexpr LoadStoreAcquireReleaseOp CASPAL_w
constexpr LoadStoreUnsignedOffset LoadStoreUnsignedOffsetMask
constexpr FPIntegerConvertOp FMOV_sw
constexpr FPImmediateOp FMOV_d_imm
constexpr NEONScalar2RegMiscOp NEONScalar2RegMiscFPMask
constexpr FPIntegerConvertOp FMOV_xd
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST4_h_post
constexpr ExceptionOp DCPS2
constexpr NEONScalar2RegMiscOp NEON_SCVTF_scalar
constexpr int kHRegSizeInBits
constexpr MemBarrierOp ISB
constexpr FPDataProcessing1SourceOp FCVT_ds
constexpr NEON3SameOp NEON_EOR
constexpr LoadStorePairPreIndexOp LoadStorePairPreIndexMask
constexpr NEONScalarByIndexedElementOp NEONScalarByIndexedElementMask
constexpr NEONLoadStoreMultiStructOp NEON_ST1_1v
constexpr NEONLoadStoreSingleStructOp NEON_LD2R
constexpr PCRelAddressingOp ADR
constexpr FPIntegerConvertOp FCVTNS_ws
constexpr NEON2RegMiscOp NEON_FRINTX
constexpr NEON2RegMiscOp NEON_FCVTNS
constexpr NEONLoadStoreSingleStructOp NEON_LD2_b
constexpr NEONLoadStoreMultiStructPostIndexOp NEON_LD1_3v_post
constexpr LogicalShiftedOp BIC_w
constexpr NEON3ExtensionOp NEON3ExtensionMask
constexpr NEON3DifferentOp NEON_SMLAL
constexpr FPIntegerConvertOp FCVTAU_xs
constexpr AddSubWithCarryOp ADCS_x
constexpr FPIntegerConvertOp FCVTZU_wd
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_ST2_h_post
constexpr NEON2RegMiscOp NEON_SQXTN
constexpr NEONLoadStoreSingleStructPostIndexOp NEON_LD2_h_post
constexpr NEON2RegMiscOp NEON_FCVTPU
constexpr AddSubWithCarryOp ADC_x
constexpr int kDRegSizeInBits
constexpr NEON2RegMiscOp NEON_CLZ
constexpr NEON2RegMiscOp NEON_FCVTNU
constexpr NEONByIndexedElementOp NEON_SMULL_byelement
constexpr NEONScalar3SameOp NEON_CMGT_scalar
#define UNREACHABLE()
Definition logging.h:67
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
#define arraysize(array)
Definition macros.h:67