hw/dma/xilinx_axidma: remove dead code
[qemu/ar7.git] / disas / libvixl / a64 / disasm-a64.cc
blobf7bc2468bb23d781d5623ee7938363fd65b1c493
1 // Copyright 2013, ARM Limited
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright notice,
8 // this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 // * Neither the name of ARM Limited nor the names of its contributors may be
13 // used to endorse or promote products derived from this software without
14 // specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <cstdlib>
28 #include "a64/disasm-a64.h"
30 namespace vixl {
32 Disassembler::Disassembler() {
33 buffer_size_ = 256;
34 buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
35 buffer_pos_ = 0;
36 own_buffer_ = true;
37 code_address_offset_ = 0;
41 Disassembler::Disassembler(char* text_buffer, int buffer_size) {
42 buffer_size_ = buffer_size;
43 buffer_ = text_buffer;
44 buffer_pos_ = 0;
45 own_buffer_ = false;
46 code_address_offset_ = 0;
50 Disassembler::~Disassembler() {
51 if (own_buffer_) {
52 free(buffer_);
57 char* Disassembler::GetOutput() {
58 return buffer_;
62 void Disassembler::VisitAddSubImmediate(const Instruction* instr) {
63 bool rd_is_zr = RdIsZROrSP(instr);
64 bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
65 (instr->ImmAddSub() == 0) ? true : false;
66 const char *mnemonic = "";
67 const char *form = "'Rds, 'Rns, 'IAddSub";
68 const char *form_cmp = "'Rns, 'IAddSub";
69 const char *form_mov = "'Rds, 'Rns";
71 switch (instr->Mask(AddSubImmediateMask)) {
72 case ADD_w_imm:
73 case ADD_x_imm: {
74 mnemonic = "add";
75 if (stack_op) {
76 mnemonic = "mov";
77 form = form_mov;
79 break;
81 case ADDS_w_imm:
82 case ADDS_x_imm: {
83 mnemonic = "adds";
84 if (rd_is_zr) {
85 mnemonic = "cmn";
86 form = form_cmp;
88 break;
90 case SUB_w_imm:
91 case SUB_x_imm: mnemonic = "sub"; break;
92 case SUBS_w_imm:
93 case SUBS_x_imm: {
94 mnemonic = "subs";
95 if (rd_is_zr) {
96 mnemonic = "cmp";
97 form = form_cmp;
99 break;
101 default: VIXL_UNREACHABLE();
103 Format(instr, mnemonic, form);
107 void Disassembler::VisitAddSubShifted(const Instruction* instr) {
108 bool rd_is_zr = RdIsZROrSP(instr);
109 bool rn_is_zr = RnIsZROrSP(instr);
110 const char *mnemonic = "";
111 const char *form = "'Rd, 'Rn, 'Rm'HDP";
112 const char *form_cmp = "'Rn, 'Rm'HDP";
113 const char *form_neg = "'Rd, 'Rm'HDP";
115 switch (instr->Mask(AddSubShiftedMask)) {
116 case ADD_w_shift:
117 case ADD_x_shift: mnemonic = "add"; break;
118 case ADDS_w_shift:
119 case ADDS_x_shift: {
120 mnemonic = "adds";
121 if (rd_is_zr) {
122 mnemonic = "cmn";
123 form = form_cmp;
125 break;
127 case SUB_w_shift:
128 case SUB_x_shift: {
129 mnemonic = "sub";
130 if (rn_is_zr) {
131 mnemonic = "neg";
132 form = form_neg;
134 break;
136 case SUBS_w_shift:
137 case SUBS_x_shift: {
138 mnemonic = "subs";
139 if (rd_is_zr) {
140 mnemonic = "cmp";
141 form = form_cmp;
142 } else if (rn_is_zr) {
143 mnemonic = "negs";
144 form = form_neg;
146 break;
148 default: VIXL_UNREACHABLE();
150 Format(instr, mnemonic, form);
154 void Disassembler::VisitAddSubExtended(const Instruction* instr) {
155 bool rd_is_zr = RdIsZROrSP(instr);
156 const char *mnemonic = "";
157 Extend mode = static_cast<Extend>(instr->ExtendMode());
158 const char *form = ((mode == UXTX) || (mode == SXTX)) ?
159 "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext";
160 const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ?
161 "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
163 switch (instr->Mask(AddSubExtendedMask)) {
164 case ADD_w_ext:
165 case ADD_x_ext: mnemonic = "add"; break;
166 case ADDS_w_ext:
167 case ADDS_x_ext: {
168 mnemonic = "adds";
169 if (rd_is_zr) {
170 mnemonic = "cmn";
171 form = form_cmp;
173 break;
175 case SUB_w_ext:
176 case SUB_x_ext: mnemonic = "sub"; break;
177 case SUBS_w_ext:
178 case SUBS_x_ext: {
179 mnemonic = "subs";
180 if (rd_is_zr) {
181 mnemonic = "cmp";
182 form = form_cmp;
184 break;
186 default: VIXL_UNREACHABLE();
188 Format(instr, mnemonic, form);
192 void Disassembler::VisitAddSubWithCarry(const Instruction* instr) {
193 bool rn_is_zr = RnIsZROrSP(instr);
194 const char *mnemonic = "";
195 const char *form = "'Rd, 'Rn, 'Rm";
196 const char *form_neg = "'Rd, 'Rm";
198 switch (instr->Mask(AddSubWithCarryMask)) {
199 case ADC_w:
200 case ADC_x: mnemonic = "adc"; break;
201 case ADCS_w:
202 case ADCS_x: mnemonic = "adcs"; break;
203 case SBC_w:
204 case SBC_x: {
205 mnemonic = "sbc";
206 if (rn_is_zr) {
207 mnemonic = "ngc";
208 form = form_neg;
210 break;
212 case SBCS_w:
213 case SBCS_x: {
214 mnemonic = "sbcs";
215 if (rn_is_zr) {
216 mnemonic = "ngcs";
217 form = form_neg;
219 break;
221 default: VIXL_UNREACHABLE();
223 Format(instr, mnemonic, form);
227 void Disassembler::VisitLogicalImmediate(const Instruction* instr) {
228 bool rd_is_zr = RdIsZROrSP(instr);
229 bool rn_is_zr = RnIsZROrSP(instr);
230 const char *mnemonic = "";
231 const char *form = "'Rds, 'Rn, 'ITri";
233 if (instr->ImmLogical() == 0) {
234 // The immediate encoded in the instruction is not in the expected format.
235 Format(instr, "unallocated", "(LogicalImmediate)");
236 return;
239 switch (instr->Mask(LogicalImmediateMask)) {
240 case AND_w_imm:
241 case AND_x_imm: mnemonic = "and"; break;
242 case ORR_w_imm:
243 case ORR_x_imm: {
244 mnemonic = "orr";
245 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize
246 : kWRegSize;
247 if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
248 mnemonic = "mov";
249 form = "'Rds, 'ITri";
251 break;
253 case EOR_w_imm:
254 case EOR_x_imm: mnemonic = "eor"; break;
255 case ANDS_w_imm:
256 case ANDS_x_imm: {
257 mnemonic = "ands";
258 if (rd_is_zr) {
259 mnemonic = "tst";
260 form = "'Rn, 'ITri";
262 break;
264 default: VIXL_UNREACHABLE();
266 Format(instr, mnemonic, form);
270 bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
271 VIXL_ASSERT((reg_size == kXRegSize) ||
272 ((reg_size == kWRegSize) && (value <= 0xffffffff)));
274 // Test for movz: 16 bits set at positions 0, 16, 32 or 48.
275 if (((value & UINT64_C(0xffffffffffff0000)) == 0) ||
276 ((value & UINT64_C(0xffffffff0000ffff)) == 0) ||
277 ((value & UINT64_C(0xffff0000ffffffff)) == 0) ||
278 ((value & UINT64_C(0x0000ffffffffffff)) == 0)) {
279 return true;
282 // Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48).
283 if ((reg_size == kXRegSize) &&
284 (((~value & UINT64_C(0xffffffffffff0000)) == 0) ||
285 ((~value & UINT64_C(0xffffffff0000ffff)) == 0) ||
286 ((~value & UINT64_C(0xffff0000ffffffff)) == 0) ||
287 ((~value & UINT64_C(0x0000ffffffffffff)) == 0))) {
288 return true;
290 if ((reg_size == kWRegSize) &&
291 (((value & 0xffff0000) == 0xffff0000) ||
292 ((value & 0x0000ffff) == 0x0000ffff))) {
293 return true;
295 return false;
299 void Disassembler::VisitLogicalShifted(const Instruction* instr) {
300 bool rd_is_zr = RdIsZROrSP(instr);
301 bool rn_is_zr = RnIsZROrSP(instr);
302 const char *mnemonic = "";
303 const char *form = "'Rd, 'Rn, 'Rm'HLo";
305 switch (instr->Mask(LogicalShiftedMask)) {
306 case AND_w:
307 case AND_x: mnemonic = "and"; break;
308 case BIC_w:
309 case BIC_x: mnemonic = "bic"; break;
310 case EOR_w:
311 case EOR_x: mnemonic = "eor"; break;
312 case EON_w:
313 case EON_x: mnemonic = "eon"; break;
314 case BICS_w:
315 case BICS_x: mnemonic = "bics"; break;
316 case ANDS_w:
317 case ANDS_x: {
318 mnemonic = "ands";
319 if (rd_is_zr) {
320 mnemonic = "tst";
321 form = "'Rn, 'Rm'HLo";
323 break;
325 case ORR_w:
326 case ORR_x: {
327 mnemonic = "orr";
328 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
329 mnemonic = "mov";
330 form = "'Rd, 'Rm";
332 break;
334 case ORN_w:
335 case ORN_x: {
336 mnemonic = "orn";
337 if (rn_is_zr) {
338 mnemonic = "mvn";
339 form = "'Rd, 'Rm'HLo";
341 break;
343 default: VIXL_UNREACHABLE();
346 Format(instr, mnemonic, form);
350 void Disassembler::VisitConditionalCompareRegister(const Instruction* instr) {
351 const char *mnemonic = "";
352 const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
354 switch (instr->Mask(ConditionalCompareRegisterMask)) {
355 case CCMN_w:
356 case CCMN_x: mnemonic = "ccmn"; break;
357 case CCMP_w:
358 case CCMP_x: mnemonic = "ccmp"; break;
359 default: VIXL_UNREACHABLE();
361 Format(instr, mnemonic, form);
365 void Disassembler::VisitConditionalCompareImmediate(const Instruction* instr) {
366 const char *mnemonic = "";
367 const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
369 switch (instr->Mask(ConditionalCompareImmediateMask)) {
370 case CCMN_w_imm:
371 case CCMN_x_imm: mnemonic = "ccmn"; break;
372 case CCMP_w_imm:
373 case CCMP_x_imm: mnemonic = "ccmp"; break;
374 default: VIXL_UNREACHABLE();
376 Format(instr, mnemonic, form);
380 void Disassembler::VisitConditionalSelect(const Instruction* instr) {
381 bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
382 bool rn_is_rm = (instr->Rn() == instr->Rm());
383 const char *mnemonic = "";
384 const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
385 const char *form_test = "'Rd, 'CInv";
386 const char *form_update = "'Rd, 'Rn, 'CInv";
388 Condition cond = static_cast<Condition>(instr->Condition());
389 bool invertible_cond = (cond != al) && (cond != nv);
391 switch (instr->Mask(ConditionalSelectMask)) {
392 case CSEL_w:
393 case CSEL_x: mnemonic = "csel"; break;
394 case CSINC_w:
395 case CSINC_x: {
396 mnemonic = "csinc";
397 if (rnm_is_zr && invertible_cond) {
398 mnemonic = "cset";
399 form = form_test;
400 } else if (rn_is_rm && invertible_cond) {
401 mnemonic = "cinc";
402 form = form_update;
404 break;
406 case CSINV_w:
407 case CSINV_x: {
408 mnemonic = "csinv";
409 if (rnm_is_zr && invertible_cond) {
410 mnemonic = "csetm";
411 form = form_test;
412 } else if (rn_is_rm && invertible_cond) {
413 mnemonic = "cinv";
414 form = form_update;
416 break;
418 case CSNEG_w:
419 case CSNEG_x: {
420 mnemonic = "csneg";
421 if (rn_is_rm && invertible_cond) {
422 mnemonic = "cneg";
423 form = form_update;
425 break;
427 default: VIXL_UNREACHABLE();
429 Format(instr, mnemonic, form);
433 void Disassembler::VisitBitfield(const Instruction* instr) {
434 unsigned s = instr->ImmS();
435 unsigned r = instr->ImmR();
436 unsigned rd_size_minus_1 =
437 ((instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize) - 1;
438 const char *mnemonic = "";
439 const char *form = "";
440 const char *form_shift_right = "'Rd, 'Rn, 'IBr";
441 const char *form_extend = "'Rd, 'Wn";
442 const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
443 const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
444 const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
446 switch (instr->Mask(BitfieldMask)) {
447 case SBFM_w:
448 case SBFM_x: {
449 mnemonic = "sbfx";
450 form = form_bfx;
451 if (r == 0) {
452 form = form_extend;
453 if (s == 7) {
454 mnemonic = "sxtb";
455 } else if (s == 15) {
456 mnemonic = "sxth";
457 } else if ((s == 31) && (instr->SixtyFourBits() == 1)) {
458 mnemonic = "sxtw";
459 } else {
460 form = form_bfx;
462 } else if (s == rd_size_minus_1) {
463 mnemonic = "asr";
464 form = form_shift_right;
465 } else if (s < r) {
466 mnemonic = "sbfiz";
467 form = form_bfiz;
469 break;
471 case UBFM_w:
472 case UBFM_x: {
473 mnemonic = "ubfx";
474 form = form_bfx;
475 if (r == 0) {
476 form = form_extend;
477 if (s == 7) {
478 mnemonic = "uxtb";
479 } else if (s == 15) {
480 mnemonic = "uxth";
481 } else {
482 form = form_bfx;
485 if (s == rd_size_minus_1) {
486 mnemonic = "lsr";
487 form = form_shift_right;
488 } else if (r == s + 1) {
489 mnemonic = "lsl";
490 form = form_lsl;
491 } else if (s < r) {
492 mnemonic = "ubfiz";
493 form = form_bfiz;
495 break;
497 case BFM_w:
498 case BFM_x: {
499 mnemonic = "bfxil";
500 form = form_bfx;
501 if (s < r) {
502 mnemonic = "bfi";
503 form = form_bfiz;
507 Format(instr, mnemonic, form);
511 void Disassembler::VisitExtract(const Instruction* instr) {
512 const char *mnemonic = "";
513 const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
515 switch (instr->Mask(ExtractMask)) {
516 case EXTR_w:
517 case EXTR_x: {
518 if (instr->Rn() == instr->Rm()) {
519 mnemonic = "ror";
520 form = "'Rd, 'Rn, 'IExtract";
521 } else {
522 mnemonic = "extr";
524 break;
526 default: VIXL_UNREACHABLE();
528 Format(instr, mnemonic, form);
532 void Disassembler::VisitPCRelAddressing(const Instruction* instr) {
533 switch (instr->Mask(PCRelAddressingMask)) {
534 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
535 case ADRP: Format(instr, "adrp", "'Xd, 'AddrPCRelPage"); break;
536 default: Format(instr, "unimplemented", "(PCRelAddressing)");
541 void Disassembler::VisitConditionalBranch(const Instruction* instr) {
542 switch (instr->Mask(ConditionalBranchMask)) {
543 case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
544 default: VIXL_UNREACHABLE();
549 void Disassembler::VisitUnconditionalBranchToRegister(
550 const Instruction* instr) {
551 const char *mnemonic = "unimplemented";
552 const char *form = "'Xn";
554 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
555 case BR: mnemonic = "br"; break;
556 case BLR: mnemonic = "blr"; break;
557 case RET: {
558 mnemonic = "ret";
559 if (instr->Rn() == kLinkRegCode) {
560 form = NULL;
562 break;
564 default: form = "(UnconditionalBranchToRegister)";
566 Format(instr, mnemonic, form);
570 void Disassembler::VisitUnconditionalBranch(const Instruction* instr) {
571 const char *mnemonic = "";
572 const char *form = "'BImmUncn";
574 switch (instr->Mask(UnconditionalBranchMask)) {
575 case B: mnemonic = "b"; break;
576 case BL: mnemonic = "bl"; break;
577 default: VIXL_UNREACHABLE();
579 Format(instr, mnemonic, form);
583 void Disassembler::VisitDataProcessing1Source(const Instruction* instr) {
584 const char *mnemonic = "";
585 const char *form = "'Rd, 'Rn";
587 switch (instr->Mask(DataProcessing1SourceMask)) {
588 #define FORMAT(A, B) \
589 case A##_w: \
590 case A##_x: mnemonic = B; break;
591 FORMAT(RBIT, "rbit");
592 FORMAT(REV16, "rev16");
593 FORMAT(REV, "rev");
594 FORMAT(CLZ, "clz");
595 FORMAT(CLS, "cls");
596 #undef FORMAT
597 case REV32_x: mnemonic = "rev32"; break;
598 default: VIXL_UNREACHABLE();
600 Format(instr, mnemonic, form);
604 void Disassembler::VisitDataProcessing2Source(const Instruction* instr) {
605 const char *mnemonic = "unimplemented";
606 const char *form = "'Rd, 'Rn, 'Rm";
608 switch (instr->Mask(DataProcessing2SourceMask)) {
609 #define FORMAT(A, B) \
610 case A##_w: \
611 case A##_x: mnemonic = B; break;
612 FORMAT(UDIV, "udiv");
613 FORMAT(SDIV, "sdiv");
614 FORMAT(LSLV, "lsl");
615 FORMAT(LSRV, "lsr");
616 FORMAT(ASRV, "asr");
617 FORMAT(RORV, "ror");
618 #undef FORMAT
619 default: form = "(DataProcessing2Source)";
621 Format(instr, mnemonic, form);
625 void Disassembler::VisitDataProcessing3Source(const Instruction* instr) {
626 bool ra_is_zr = RaIsZROrSP(instr);
627 const char *mnemonic = "";
628 const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
629 const char *form_rrr = "'Rd, 'Rn, 'Rm";
630 const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
631 const char *form_xww = "'Xd, 'Wn, 'Wm";
632 const char *form_xxx = "'Xd, 'Xn, 'Xm";
634 switch (instr->Mask(DataProcessing3SourceMask)) {
635 case MADD_w:
636 case MADD_x: {
637 mnemonic = "madd";
638 form = form_rrrr;
639 if (ra_is_zr) {
640 mnemonic = "mul";
641 form = form_rrr;
643 break;
645 case MSUB_w:
646 case MSUB_x: {
647 mnemonic = "msub";
648 form = form_rrrr;
649 if (ra_is_zr) {
650 mnemonic = "mneg";
651 form = form_rrr;
653 break;
655 case SMADDL_x: {
656 mnemonic = "smaddl";
657 if (ra_is_zr) {
658 mnemonic = "smull";
659 form = form_xww;
661 break;
663 case SMSUBL_x: {
664 mnemonic = "smsubl";
665 if (ra_is_zr) {
666 mnemonic = "smnegl";
667 form = form_xww;
669 break;
671 case UMADDL_x: {
672 mnemonic = "umaddl";
673 if (ra_is_zr) {
674 mnemonic = "umull";
675 form = form_xww;
677 break;
679 case UMSUBL_x: {
680 mnemonic = "umsubl";
681 if (ra_is_zr) {
682 mnemonic = "umnegl";
683 form = form_xww;
685 break;
687 case SMULH_x: {
688 mnemonic = "smulh";
689 form = form_xxx;
690 break;
692 case UMULH_x: {
693 mnemonic = "umulh";
694 form = form_xxx;
695 break;
697 default: VIXL_UNREACHABLE();
699 Format(instr, mnemonic, form);
703 void Disassembler::VisitCompareBranch(const Instruction* instr) {
704 const char *mnemonic = "";
705 const char *form = "'Rt, 'BImmCmpa";
707 switch (instr->Mask(CompareBranchMask)) {
708 case CBZ_w:
709 case CBZ_x: mnemonic = "cbz"; break;
710 case CBNZ_w:
711 case CBNZ_x: mnemonic = "cbnz"; break;
712 default: VIXL_UNREACHABLE();
714 Format(instr, mnemonic, form);
718 void Disassembler::VisitTestBranch(const Instruction* instr) {
719 const char *mnemonic = "";
720 // If the top bit of the immediate is clear, the tested register is
721 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
722 // encoded in bit 31 of the instruction, we can reuse the Rt form, which
723 // uses bit 31 (normally "sf") to choose the register size.
724 const char *form = "'Rt, 'IS, 'BImmTest";
726 switch (instr->Mask(TestBranchMask)) {
727 case TBZ: mnemonic = "tbz"; break;
728 case TBNZ: mnemonic = "tbnz"; break;
729 default: VIXL_UNREACHABLE();
731 Format(instr, mnemonic, form);
735 void Disassembler::VisitMoveWideImmediate(const Instruction* instr) {
736 const char *mnemonic = "";
737 const char *form = "'Rd, 'IMoveImm";
739 // Print the shift separately for movk, to make it clear which half word will
740 // be overwritten. Movn and movz print the computed immediate, which includes
741 // shift calculation.
742 switch (instr->Mask(MoveWideImmediateMask)) {
743 case MOVN_w:
744 case MOVN_x:
745 if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0)) {
746 if ((instr->SixtyFourBits() == 0) && (instr->ImmMoveWide() == 0xffff)) {
747 mnemonic = "movn";
748 } else {
749 mnemonic = "mov";
750 form = "'Rd, 'IMoveNeg";
752 } else {
753 mnemonic = "movn";
755 break;
756 case MOVZ_w:
757 case MOVZ_x:
758 if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0))
759 mnemonic = "mov";
760 else
761 mnemonic = "movz";
762 break;
763 case MOVK_w:
764 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
765 default: VIXL_UNREACHABLE();
767 Format(instr, mnemonic, form);
771 #define LOAD_STORE_LIST(V) \
772 V(STRB_w, "strb", "'Wt") \
773 V(STRH_w, "strh", "'Wt") \
774 V(STR_w, "str", "'Wt") \
775 V(STR_x, "str", "'Xt") \
776 V(LDRB_w, "ldrb", "'Wt") \
777 V(LDRH_w, "ldrh", "'Wt") \
778 V(LDR_w, "ldr", "'Wt") \
779 V(LDR_x, "ldr", "'Xt") \
780 V(LDRSB_x, "ldrsb", "'Xt") \
781 V(LDRSH_x, "ldrsh", "'Xt") \
782 V(LDRSW_x, "ldrsw", "'Xt") \
783 V(LDRSB_w, "ldrsb", "'Wt") \
784 V(LDRSH_w, "ldrsh", "'Wt") \
785 V(STR_s, "str", "'St") \
786 V(STR_d, "str", "'Dt") \
787 V(LDR_s, "ldr", "'St") \
788 V(LDR_d, "ldr", "'Dt")
790 void Disassembler::VisitLoadStorePreIndex(const Instruction* instr) {
791 const char *mnemonic = "unimplemented";
792 const char *form = "(LoadStorePreIndex)";
794 switch (instr->Mask(LoadStorePreIndexMask)) {
795 #define LS_PREINDEX(A, B, C) \
796 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
797 LOAD_STORE_LIST(LS_PREINDEX)
798 #undef LS_PREINDEX
800 Format(instr, mnemonic, form);
804 void Disassembler::VisitLoadStorePostIndex(const Instruction* instr) {
805 const char *mnemonic = "unimplemented";
806 const char *form = "(LoadStorePostIndex)";
808 switch (instr->Mask(LoadStorePostIndexMask)) {
809 #define LS_POSTINDEX(A, B, C) \
810 case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
811 LOAD_STORE_LIST(LS_POSTINDEX)
812 #undef LS_POSTINDEX
814 Format(instr, mnemonic, form);
818 void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
819 const char *mnemonic = "unimplemented";
820 const char *form = "(LoadStoreUnsignedOffset)";
822 switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
823 #define LS_UNSIGNEDOFFSET(A, B, C) \
824 case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
825 LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
826 #undef LS_UNSIGNEDOFFSET
827 case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xns'ILU]";
829 Format(instr, mnemonic, form);
833 void Disassembler::VisitLoadStoreRegisterOffset(const Instruction* instr) {
834 const char *mnemonic = "unimplemented";
835 const char *form = "(LoadStoreRegisterOffset)";
837 switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
838 #define LS_REGISTEROFFSET(A, B, C) \
839 case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
840 LOAD_STORE_LIST(LS_REGISTEROFFSET)
841 #undef LS_REGISTEROFFSET
842 case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]";
844 Format(instr, mnemonic, form);
848 void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
849 const char *mnemonic = "unimplemented";
850 const char *form = "'Wt, ['Xns'ILS]";
851 const char *form_x = "'Xt, ['Xns'ILS]";
852 const char *form_s = "'St, ['Xns'ILS]";
853 const char *form_d = "'Dt, ['Xns'ILS]";
854 const char *form_prefetch = "'PrefOp, ['Xns'ILS]";
856 switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
857 case STURB_w: mnemonic = "sturb"; break;
858 case STURH_w: mnemonic = "sturh"; break;
859 case STUR_w: mnemonic = "stur"; break;
860 case STUR_x: mnemonic = "stur"; form = form_x; break;
861 case STUR_s: mnemonic = "stur"; form = form_s; break;
862 case STUR_d: mnemonic = "stur"; form = form_d; break;
863 case LDURB_w: mnemonic = "ldurb"; break;
864 case LDURH_w: mnemonic = "ldurh"; break;
865 case LDUR_w: mnemonic = "ldur"; break;
866 case LDUR_x: mnemonic = "ldur"; form = form_x; break;
867 case LDUR_s: mnemonic = "ldur"; form = form_s; break;
868 case LDUR_d: mnemonic = "ldur"; form = form_d; break;
869 case LDURSB_x: form = form_x; // Fall through.
870 case LDURSB_w: mnemonic = "ldursb"; break;
871 case LDURSH_x: form = form_x; // Fall through.
872 case LDURSH_w: mnemonic = "ldursh"; break;
873 case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
874 case PRFUM: mnemonic = "prfum"; form = form_prefetch; break;
875 default: form = "(LoadStoreUnscaledOffset)";
877 Format(instr, mnemonic, form);
881 void Disassembler::VisitLoadLiteral(const Instruction* instr) {
882 const char *mnemonic = "ldr";
883 const char *form = "(LoadLiteral)";
885 switch (instr->Mask(LoadLiteralMask)) {
886 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break;
887 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
888 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
889 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
890 case LDRSW_x_lit: {
891 mnemonic = "ldrsw";
892 form = "'Xt, 'ILLiteral 'LValue";
893 break;
895 case PRFM_lit: {
896 mnemonic = "prfm";
897 form = "'PrefOp, 'ILLiteral 'LValue";
898 break;
900 default: mnemonic = "unimplemented";
902 Format(instr, mnemonic, form);
906 #define LOAD_STORE_PAIR_LIST(V) \
907 V(STP_w, "stp", "'Wt, 'Wt2", "4") \
908 V(LDP_w, "ldp", "'Wt, 'Wt2", "4") \
909 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \
910 V(STP_x, "stp", "'Xt, 'Xt2", "8") \
911 V(LDP_x, "ldp", "'Xt, 'Xt2", "8") \
912 V(STP_s, "stp", "'St, 'St2", "4") \
913 V(LDP_s, "ldp", "'St, 'St2", "4") \
914 V(STP_d, "stp", "'Dt, 'Dt2", "8") \
915 V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
917 void Disassembler::VisitLoadStorePairPostIndex(const Instruction* instr) {
918 const char *mnemonic = "unimplemented";
919 const char *form = "(LoadStorePairPostIndex)";
921 switch (instr->Mask(LoadStorePairPostIndexMask)) {
922 #define LSP_POSTINDEX(A, B, C, D) \
923 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
924 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
925 #undef LSP_POSTINDEX
927 Format(instr, mnemonic, form);
931 void Disassembler::VisitLoadStorePairPreIndex(const Instruction* instr) {
932 const char *mnemonic = "unimplemented";
933 const char *form = "(LoadStorePairPreIndex)";
935 switch (instr->Mask(LoadStorePairPreIndexMask)) {
936 #define LSP_PREINDEX(A, B, C, D) \
937 case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
938 LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
939 #undef LSP_PREINDEX
941 Format(instr, mnemonic, form);
945 void Disassembler::VisitLoadStorePairOffset(const Instruction* instr) {
946 const char *mnemonic = "unimplemented";
947 const char *form = "(LoadStorePairOffset)";
949 switch (instr->Mask(LoadStorePairOffsetMask)) {
950 #define LSP_OFFSET(A, B, C, D) \
951 case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
952 LOAD_STORE_PAIR_LIST(LSP_OFFSET)
953 #undef LSP_OFFSET
955 Format(instr, mnemonic, form);
959 void Disassembler::VisitLoadStorePairNonTemporal(const Instruction* instr) {
960 const char *mnemonic = "unimplemented";
961 const char *form;
963 switch (instr->Mask(LoadStorePairNonTemporalMask)) {
964 case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
965 case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
966 case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
967 case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
968 case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
969 case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
970 case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
971 case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
972 default: form = "(LoadStorePairNonTemporal)";
974 Format(instr, mnemonic, form);
978 void Disassembler::VisitLoadStoreExclusive(const Instruction* instr) {
979 const char *mnemonic = "unimplemented";
980 const char *form;
982 switch (instr->Mask(LoadStoreExclusiveMask)) {
983 case STXRB_w: mnemonic = "stxrb"; form = "'Ws, 'Wt, ['Xns]"; break;
984 case STXRH_w: mnemonic = "stxrh"; form = "'Ws, 'Wt, ['Xns]"; break;
985 case STXR_w: mnemonic = "stxr"; form = "'Ws, 'Wt, ['Xns]"; break;
986 case STXR_x: mnemonic = "stxr"; form = "'Ws, 'Xt, ['Xns]"; break;
987 case LDXRB_w: mnemonic = "ldxrb"; form = "'Wt, ['Xns]"; break;
988 case LDXRH_w: mnemonic = "ldxrh"; form = "'Wt, ['Xns]"; break;
989 case LDXR_w: mnemonic = "ldxr"; form = "'Wt, ['Xns]"; break;
990 case LDXR_x: mnemonic = "ldxr"; form = "'Xt, ['Xns]"; break;
991 case STXP_w: mnemonic = "stxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break;
992 case STXP_x: mnemonic = "stxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break;
993 case LDXP_w: mnemonic = "ldxp"; form = "'Wt, 'Wt2, ['Xns]"; break;
994 case LDXP_x: mnemonic = "ldxp"; form = "'Xt, 'Xt2, ['Xns]"; break;
995 case STLXRB_w: mnemonic = "stlxrb"; form = "'Ws, 'Wt, ['Xns]"; break;
996 case STLXRH_w: mnemonic = "stlxrh"; form = "'Ws, 'Wt, ['Xns]"; break;
997 case STLXR_w: mnemonic = "stlxr"; form = "'Ws, 'Wt, ['Xns]"; break;
998 case STLXR_x: mnemonic = "stlxr"; form = "'Ws, 'Xt, ['Xns]"; break;
999 case LDAXRB_w: mnemonic = "ldaxrb"; form = "'Wt, ['Xns]"; break;
1000 case LDAXRH_w: mnemonic = "ldaxrh"; form = "'Wt, ['Xns]"; break;
1001 case LDAXR_w: mnemonic = "ldaxr"; form = "'Wt, ['Xns]"; break;
1002 case LDAXR_x: mnemonic = "ldaxr"; form = "'Xt, ['Xns]"; break;
1003 case STLXP_w: mnemonic = "stlxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break;
1004 case STLXP_x: mnemonic = "stlxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break;
1005 case LDAXP_w: mnemonic = "ldaxp"; form = "'Wt, 'Wt2, ['Xns]"; break;
1006 case LDAXP_x: mnemonic = "ldaxp"; form = "'Xt, 'Xt2, ['Xns]"; break;
1007 case STLRB_w: mnemonic = "stlrb"; form = "'Wt, ['Xns]"; break;
1008 case STLRH_w: mnemonic = "stlrh"; form = "'Wt, ['Xns]"; break;
1009 case STLR_w: mnemonic = "stlr"; form = "'Wt, ['Xns]"; break;
1010 case STLR_x: mnemonic = "stlr"; form = "'Xt, ['Xns]"; break;
1011 case LDARB_w: mnemonic = "ldarb"; form = "'Wt, ['Xns]"; break;
1012 case LDARH_w: mnemonic = "ldarh"; form = "'Wt, ['Xns]"; break;
1013 case LDAR_w: mnemonic = "ldar"; form = "'Wt, ['Xns]"; break;
1014 case LDAR_x: mnemonic = "ldar"; form = "'Xt, ['Xns]"; break;
1015 default: form = "(LoadStoreExclusive)";
1017 Format(instr, mnemonic, form);
1021 void Disassembler::VisitFPCompare(const Instruction* instr) {
1022 const char *mnemonic = "unimplemented";
1023 const char *form = "'Fn, 'Fm";
1024 const char *form_zero = "'Fn, #0.0";
1026 switch (instr->Mask(FPCompareMask)) {
1027 case FCMP_s_zero:
1028 case FCMP_d_zero: form = form_zero; // Fall through.
1029 case FCMP_s:
1030 case FCMP_d: mnemonic = "fcmp"; break;
1031 default: form = "(FPCompare)";
1033 Format(instr, mnemonic, form);
1037 void Disassembler::VisitFPConditionalCompare(const Instruction* instr) {
1038 const char *mnemonic = "unmplemented";
1039 const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
1041 switch (instr->Mask(FPConditionalCompareMask)) {
1042 case FCCMP_s:
1043 case FCCMP_d: mnemonic = "fccmp"; break;
1044 case FCCMPE_s:
1045 case FCCMPE_d: mnemonic = "fccmpe"; break;
1046 default: form = "(FPConditionalCompare)";
1048 Format(instr, mnemonic, form);
1052 void Disassembler::VisitFPConditionalSelect(const Instruction* instr) {
1053 const char *mnemonic = "";
1054 const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
1056 switch (instr->Mask(FPConditionalSelectMask)) {
1057 case FCSEL_s:
1058 case FCSEL_d: mnemonic = "fcsel"; break;
1059 default: VIXL_UNREACHABLE();
1061 Format(instr, mnemonic, form);
1065 void Disassembler::VisitFPDataProcessing1Source(const Instruction* instr) {
1066 const char *mnemonic = "unimplemented";
1067 const char *form = "'Fd, 'Fn";
1069 switch (instr->Mask(FPDataProcessing1SourceMask)) {
1070 #define FORMAT(A, B) \
1071 case A##_s: \
1072 case A##_d: mnemonic = B; break;
1073 FORMAT(FMOV, "fmov");
1074 FORMAT(FABS, "fabs");
1075 FORMAT(FNEG, "fneg");
1076 FORMAT(FSQRT, "fsqrt");
1077 FORMAT(FRINTN, "frintn");
1078 FORMAT(FRINTP, "frintp");
1079 FORMAT(FRINTM, "frintm");
1080 FORMAT(FRINTZ, "frintz");
1081 FORMAT(FRINTA, "frinta");
1082 FORMAT(FRINTX, "frintx");
1083 FORMAT(FRINTI, "frinti");
1084 #undef FORMAT
1085 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
1086 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
1087 default: form = "(FPDataProcessing1Source)";
1089 Format(instr, mnemonic, form);
1093 void Disassembler::VisitFPDataProcessing2Source(const Instruction* instr) {
1094 const char *mnemonic = "";
1095 const char *form = "'Fd, 'Fn, 'Fm";
1097 switch (instr->Mask(FPDataProcessing2SourceMask)) {
1098 #define FORMAT(A, B) \
1099 case A##_s: \
1100 case A##_d: mnemonic = B; break;
1101 FORMAT(FMUL, "fmul");
1102 FORMAT(FDIV, "fdiv");
1103 FORMAT(FADD, "fadd");
1104 FORMAT(FSUB, "fsub");
1105 FORMAT(FMAX, "fmax");
1106 FORMAT(FMIN, "fmin");
1107 FORMAT(FMAXNM, "fmaxnm");
1108 FORMAT(FMINNM, "fminnm");
1109 FORMAT(FNMUL, "fnmul");
1110 #undef FORMAT
1111 default: VIXL_UNREACHABLE();
1113 Format(instr, mnemonic, form);
1117 void Disassembler::VisitFPDataProcessing3Source(const Instruction* instr) {
1118 const char *mnemonic = "";
1119 const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
1121 switch (instr->Mask(FPDataProcessing3SourceMask)) {
1122 #define FORMAT(A, B) \
1123 case A##_s: \
1124 case A##_d: mnemonic = B; break;
1125 FORMAT(FMADD, "fmadd");
1126 FORMAT(FMSUB, "fmsub");
1127 FORMAT(FNMADD, "fnmadd");
1128 FORMAT(FNMSUB, "fnmsub");
1129 #undef FORMAT
1130 default: VIXL_UNREACHABLE();
1132 Format(instr, mnemonic, form);
1136 void Disassembler::VisitFPImmediate(const Instruction* instr) {
1137 const char *mnemonic = "";
1138 const char *form = "(FPImmediate)";
1140 switch (instr->Mask(FPImmediateMask)) {
1141 case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
1142 case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
1143 default: VIXL_UNREACHABLE();
1145 Format(instr, mnemonic, form);
1149 void Disassembler::VisitFPIntegerConvert(const Instruction* instr) {
1150 const char *mnemonic = "unimplemented";
1151 const char *form = "(FPIntegerConvert)";
1152 const char *form_rf = "'Rd, 'Fn";
1153 const char *form_fr = "'Fd, 'Rn";
1155 switch (instr->Mask(FPIntegerConvertMask)) {
1156 case FMOV_ws:
1157 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
1158 case FMOV_sw:
1159 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
1160 case FCVTAS_ws:
1161 case FCVTAS_xs:
1162 case FCVTAS_wd:
1163 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
1164 case FCVTAU_ws:
1165 case FCVTAU_xs:
1166 case FCVTAU_wd:
1167 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
1168 case FCVTMS_ws:
1169 case FCVTMS_xs:
1170 case FCVTMS_wd:
1171 case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
1172 case FCVTMU_ws:
1173 case FCVTMU_xs:
1174 case FCVTMU_wd:
1175 case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
1176 case FCVTNS_ws:
1177 case FCVTNS_xs:
1178 case FCVTNS_wd:
1179 case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
1180 case FCVTNU_ws:
1181 case FCVTNU_xs:
1182 case FCVTNU_wd:
1183 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
1184 case FCVTZU_xd:
1185 case FCVTZU_ws:
1186 case FCVTZU_wd:
1187 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
1188 case FCVTZS_xd:
1189 case FCVTZS_wd:
1190 case FCVTZS_xs:
1191 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
1192 case SCVTF_sw:
1193 case SCVTF_sx:
1194 case SCVTF_dw:
1195 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
1196 case UCVTF_sw:
1197 case UCVTF_sx:
1198 case UCVTF_dw:
1199 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
1201 Format(instr, mnemonic, form);
1205 void Disassembler::VisitFPFixedPointConvert(const Instruction* instr) {
1206 const char *mnemonic = "";
1207 const char *form = "'Rd, 'Fn, 'IFPFBits";
1208 const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
1210 switch (instr->Mask(FPFixedPointConvertMask)) {
1211 case FCVTZS_ws_fixed:
1212 case FCVTZS_xs_fixed:
1213 case FCVTZS_wd_fixed:
1214 case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
1215 case FCVTZU_ws_fixed:
1216 case FCVTZU_xs_fixed:
1217 case FCVTZU_wd_fixed:
1218 case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
1219 case SCVTF_sw_fixed:
1220 case SCVTF_sx_fixed:
1221 case SCVTF_dw_fixed:
1222 case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
1223 case UCVTF_sw_fixed:
1224 case UCVTF_sx_fixed:
1225 case UCVTF_dw_fixed:
1226 case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
1227 default: VIXL_UNREACHABLE();
1229 Format(instr, mnemonic, form);
1233 void Disassembler::VisitSystem(const Instruction* instr) {
1234 // Some system instructions hijack their Op and Cp fields to represent a
1235 // range of immediates instead of indicating a different instruction. This
1236 // makes the decoding tricky.
1237 const char *mnemonic = "unimplemented";
1238 const char *form = "(System)";
1240 if (instr->Mask(SystemExclusiveMonitorFMask) == SystemExclusiveMonitorFixed) {
1241 switch (instr->Mask(SystemExclusiveMonitorMask)) {
1242 case CLREX: {
1243 mnemonic = "clrex";
1244 form = (instr->CRm() == 0xf) ? NULL : "'IX";
1245 break;
1248 } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1249 switch (instr->Mask(SystemSysRegMask)) {
1250 case MRS: {
1251 mnemonic = "mrs";
1252 switch (instr->ImmSystemRegister()) {
1253 case NZCV: form = "'Xt, nzcv"; break;
1254 case FPCR: form = "'Xt, fpcr"; break;
1255 default: form = "'Xt, (unknown)"; break;
1257 break;
1259 case MSR: {
1260 mnemonic = "msr";
1261 switch (instr->ImmSystemRegister()) {
1262 case NZCV: form = "nzcv, 'Xt"; break;
1263 case FPCR: form = "fpcr, 'Xt"; break;
1264 default: form = "(unknown), 'Xt"; break;
1266 break;
1269 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1270 switch (instr->ImmHint()) {
1271 case NOP: {
1272 mnemonic = "nop";
1273 form = NULL;
1274 break;
1277 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
1278 switch (instr->Mask(MemBarrierMask)) {
1279 case DMB: {
1280 mnemonic = "dmb";
1281 form = "'M";
1282 break;
1284 case DSB: {
1285 mnemonic = "dsb";
1286 form = "'M";
1287 break;
1289 case ISB: {
1290 mnemonic = "isb";
1291 form = NULL;
1292 break;
1297 Format(instr, mnemonic, form);
1301 void Disassembler::VisitException(const Instruction* instr) {
1302 const char *mnemonic = "unimplemented";
1303 const char *form = "'IDebug";
1305 switch (instr->Mask(ExceptionMask)) {
1306 case HLT: mnemonic = "hlt"; break;
1307 case BRK: mnemonic = "brk"; break;
1308 case SVC: mnemonic = "svc"; break;
1309 case HVC: mnemonic = "hvc"; break;
1310 case SMC: mnemonic = "smc"; break;
1311 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
1312 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
1313 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
1314 default: form = "(Exception)";
1316 Format(instr, mnemonic, form);
1320 void Disassembler::VisitUnimplemented(const Instruction* instr) {
1321 Format(instr, "unimplemented", "(Unimplemented)");
1325 void Disassembler::VisitUnallocated(const Instruction* instr) {
1326 Format(instr, "unallocated", "(Unallocated)");
1330 void Disassembler::ProcessOutput(const Instruction* /*instr*/) {
1331 // The base disasm does nothing more than disassembling into a buffer.
1335 void Disassembler::AppendRegisterNameToOutput(const Instruction* instr,
1336 const CPURegister& reg) {
1337 USE(instr);
1338 VIXL_ASSERT(reg.IsValid());
1339 char reg_char;
1341 if (reg.IsRegister()) {
1342 reg_char = reg.Is64Bits() ? 'x' : 'w';
1343 } else {
1344 VIXL_ASSERT(reg.IsFPRegister());
1345 reg_char = reg.Is64Bits() ? 'd' : 's';
1348 if (reg.IsFPRegister() || !(reg.Aliases(sp) || reg.Aliases(xzr))) {
1349 // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
1350 AppendToOutput("%c%d", reg_char, reg.code());
1351 } else if (reg.Aliases(sp)) {
1352 // Disassemble w31/x31 as stack pointer wsp/sp.
1353 AppendToOutput("%s", reg.Is64Bits() ? "sp" : "wsp");
1354 } else {
1355 // Disassemble w31/x31 as zero register wzr/xzr.
1356 AppendToOutput("%czr", reg_char);
1361 void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction* instr,
1362 int64_t offset) {
1363 USE(instr);
1364 char sign = (offset < 0) ? '-' : '+';
1365 AppendToOutput("#%c0x%" PRIx64, sign, std::abs(offset));
1369 void Disassembler::AppendAddressToOutput(const Instruction* instr,
1370 const void* addr) {
1371 USE(instr);
1372 AppendToOutput("(addr 0x%" PRIxPTR ")", reinterpret_cast<uintptr_t>(addr));
1376 void Disassembler::AppendCodeAddressToOutput(const Instruction* instr,
1377 const void* addr) {
1378 AppendAddressToOutput(instr, addr);
1382 void Disassembler::AppendDataAddressToOutput(const Instruction* instr,
1383 const void* addr) {
1384 AppendAddressToOutput(instr, addr);
1388 void Disassembler::AppendCodeRelativeAddressToOutput(const Instruction* instr,
1389 const void* addr) {
1390 USE(instr);
1391 int64_t rel_addr = CodeRelativeAddress(addr);
1392 if (rel_addr >= 0) {
1393 AppendToOutput("(addr 0x%" PRIx64 ")", rel_addr);
1394 } else {
1395 AppendToOutput("(addr -0x%" PRIx64 ")", -rel_addr);
1400 void Disassembler::AppendCodeRelativeCodeAddressToOutput(
1401 const Instruction* instr, const void* addr) {
1402 AppendCodeRelativeAddressToOutput(instr, addr);
1406 void Disassembler::AppendCodeRelativeDataAddressToOutput(
1407 const Instruction* instr, const void* addr) {
1408 AppendCodeRelativeAddressToOutput(instr, addr);
1412 void Disassembler::MapCodeAddress(int64_t base_address,
1413 const Instruction* instr_address) {
1414 set_code_address_offset(
1415 base_address - reinterpret_cast<intptr_t>(instr_address));
1417 int64_t Disassembler::CodeRelativeAddress(const void* addr) {
1418 return reinterpret_cast<intptr_t>(addr) + code_address_offset();
1422 void Disassembler::Format(const Instruction* instr, const char* mnemonic,
1423 const char* format) {
1424 VIXL_ASSERT(mnemonic != NULL);
1425 ResetOutput();
1426 Substitute(instr, mnemonic);
1427 if (format != NULL) {
1428 buffer_[buffer_pos_++] = ' ';
1429 Substitute(instr, format);
1431 buffer_[buffer_pos_] = 0;
1432 ProcessOutput(instr);
1436 void Disassembler::Substitute(const Instruction* instr, const char* string) {
1437 char chr = *string++;
1438 while (chr != '\0') {
1439 if (chr == '\'') {
1440 string += SubstituteField(instr, string);
1441 } else {
1442 buffer_[buffer_pos_++] = chr;
1444 chr = *string++;
1449 int Disassembler::SubstituteField(const Instruction* instr,
1450 const char* format) {
1451 switch (format[0]) {
1452 case 'R': // Register. X or W, selected by sf bit.
1453 case 'F': // FP Register. S or D, selected by type field.
1454 case 'W':
1455 case 'X':
1456 case 'S':
1457 case 'D': return SubstituteRegisterField(instr, format);
1458 case 'I': return SubstituteImmediateField(instr, format);
1459 case 'L': return SubstituteLiteralField(instr, format);
1460 case 'H': return SubstituteShiftField(instr, format);
1461 case 'P': return SubstitutePrefetchField(instr, format);
1462 case 'C': return SubstituteConditionField(instr, format);
1463 case 'E': return SubstituteExtendField(instr, format);
1464 case 'A': return SubstitutePCRelAddressField(instr, format);
1465 case 'B': return SubstituteBranchTargetField(instr, format);
1466 case 'O': return SubstituteLSRegOffsetField(instr, format);
1467 case 'M': return SubstituteBarrierField(instr, format);
1468 default: {
1469 VIXL_UNREACHABLE();
1470 return 1;
1476 int Disassembler::SubstituteRegisterField(const Instruction* instr,
1477 const char* format) {
1478 unsigned reg_num = 0;
1479 unsigned field_len = 2;
1480 switch (format[1]) {
1481 case 'd': reg_num = instr->Rd(); break;
1482 case 'n': reg_num = instr->Rn(); break;
1483 case 'm': reg_num = instr->Rm(); break;
1484 case 'a': reg_num = instr->Ra(); break;
1485 case 's': reg_num = instr->Rs(); break;
1486 case 't': {
1487 if (format[2] == '2') {
1488 reg_num = instr->Rt2();
1489 field_len = 3;
1490 } else {
1491 reg_num = instr->Rt();
1493 break;
1495 default: VIXL_UNREACHABLE();
1498 // Increase field length for registers tagged as stack.
1499 if (format[2] == 's') {
1500 field_len = 3;
1503 CPURegister::RegisterType reg_type;
1504 unsigned reg_size;
1506 if (format[0] == 'R') {
1507 // Register type is R: use sf bit to choose X and W.
1508 reg_type = CPURegister::kRegister;
1509 reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1510 } else if (format[0] == 'F') {
1511 // Floating-point register: use type field to choose S or D.
1512 reg_type = CPURegister::kFPRegister;
1513 reg_size = ((instr->FPType() & 1) == 0) ? kSRegSize : kDRegSize;
1514 } else {
1515 // The register type is specified.
1516 switch (format[0]) {
1517 case 'W':
1518 reg_type = CPURegister::kRegister; reg_size = kWRegSize; break;
1519 case 'X':
1520 reg_type = CPURegister::kRegister; reg_size = kXRegSize; break;
1521 case 'S':
1522 reg_type = CPURegister::kFPRegister; reg_size = kSRegSize; break;
1523 case 'D':
1524 reg_type = CPURegister::kFPRegister; reg_size = kDRegSize; break;
1525 default:
1526 VIXL_UNREACHABLE();
1527 reg_type = CPURegister::kRegister;
1528 reg_size = kXRegSize;
1532 if ((reg_type == CPURegister::kRegister) &&
1533 (reg_num == kZeroRegCode) && (format[2] == 's')) {
1534 reg_num = kSPRegInternalCode;
1537 AppendRegisterNameToOutput(instr, CPURegister(reg_num, reg_size, reg_type));
1539 return field_len;
1543 int Disassembler::SubstituteImmediateField(const Instruction* instr,
1544 const char* format) {
1545 VIXL_ASSERT(format[0] == 'I');
1547 switch (format[1]) {
1548 case 'M': { // IMoveImm, IMoveNeg or IMoveLSL.
1549 if (format[5] == 'L') {
1550 AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
1551 if (instr->ShiftMoveWide() > 0) {
1552 AppendToOutput(", lsl #%" PRId64, 16 * instr->ShiftMoveWide());
1554 } else {
1555 VIXL_ASSERT((format[5] == 'I') || (format[5] == 'N'));
1556 uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
1557 if (format[5] == 'N')
1558 imm = ~imm;
1559 if (!instr->SixtyFourBits())
1560 imm &= UINT64_C(0xffffffff);
1561 AppendToOutput("#0x%" PRIx64, imm);
1563 return 8;
1565 case 'L': {
1566 switch (format[2]) {
1567 case 'L': { // ILLiteral - Immediate Load Literal.
1568 AppendToOutput("pc%+" PRId64,
1569 instr->ImmLLiteral() << kLiteralEntrySizeLog2);
1570 return 9;
1572 case 'S': { // ILS - Immediate Load/Store.
1573 if (instr->ImmLS() != 0) {
1574 AppendToOutput(", #%" PRId64, instr->ImmLS());
1576 return 3;
1578 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
1579 if (instr->ImmLSPair() != 0) {
1580 // format[3] is the scale value. Convert to a number.
1581 int scale = format[3] - 0x30;
1582 AppendToOutput(", #%" PRId64, instr->ImmLSPair() * scale);
1584 return 4;
1586 case 'U': { // ILU - Immediate Load/Store Unsigned.
1587 if (instr->ImmLSUnsigned() != 0) {
1588 AppendToOutput(", #%" PRIu64,
1589 instr->ImmLSUnsigned() << instr->SizeLS());
1591 return 3;
1595 case 'C': { // ICondB - Immediate Conditional Branch.
1596 int64_t offset = instr->ImmCondBranch() << 2;
1597 AppendPCRelativeOffsetToOutput(instr, offset);
1598 return 6;
1600 case 'A': { // IAddSub.
1601 VIXL_ASSERT(instr->ShiftAddSub() <= 1);
1602 int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
1603 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
1604 return 7;
1606 case 'F': { // IFPSingle, IFPDouble or IFPFBits.
1607 if (format[3] == 'F') { // IFPFbits.
1608 AppendToOutput("#%" PRId64, 64 - instr->FPScale());
1609 return 8;
1610 } else {
1611 AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
1612 format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
1613 return 9;
1616 case 'T': { // ITri - Immediate Triangular Encoded.
1617 AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
1618 return 4;
1620 case 'N': { // INzcv.
1621 int nzcv = (instr->Nzcv() << Flags_offset);
1622 AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
1623 ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
1624 ((nzcv & CFlag) == 0) ? 'c' : 'C',
1625 ((nzcv & VFlag) == 0) ? 'v' : 'V');
1626 return 5;
1628 case 'P': { // IP - Conditional compare.
1629 AppendToOutput("#%" PRId64, instr->ImmCondCmp());
1630 return 2;
1632 case 'B': { // Bitfields.
1633 return SubstituteBitfieldImmediateField(instr, format);
1635 case 'E': { // IExtract.
1636 AppendToOutput("#%" PRId64, instr->ImmS());
1637 return 8;
1639 case 'S': { // IS - Test and branch bit.
1640 AppendToOutput("#%" PRId64, (instr->ImmTestBranchBit5() << 5) |
1641 instr->ImmTestBranchBit40());
1642 return 2;
1644 case 'D': { // IDebug - HLT and BRK instructions.
1645 AppendToOutput("#0x%" PRIx64, instr->ImmException());
1646 return 6;
1648 case 'X': { // IX - CLREX instruction.
1649 AppendToOutput("#0x%" PRIx64, instr->CRm());
1650 return 2;
1652 default: {
1653 VIXL_UNIMPLEMENTED();
1654 return 0;
1660 int Disassembler::SubstituteBitfieldImmediateField(const Instruction* instr,
1661 const char* format) {
1662 VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
1663 unsigned r = instr->ImmR();
1664 unsigned s = instr->ImmS();
1666 switch (format[2]) {
1667 case 'r': { // IBr.
1668 AppendToOutput("#%d", r);
1669 return 3;
1671 case 's': { // IBs+1 or IBs-r+1.
1672 if (format[3] == '+') {
1673 AppendToOutput("#%d", s + 1);
1674 return 5;
1675 } else {
1676 VIXL_ASSERT(format[3] == '-');
1677 AppendToOutput("#%d", s - r + 1);
1678 return 7;
1681 case 'Z': { // IBZ-r.
1682 VIXL_ASSERT((format[3] == '-') && (format[4] == 'r'));
1683 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize;
1684 AppendToOutput("#%d", reg_size - r);
1685 return 5;
1687 default: {
1688 VIXL_UNREACHABLE();
1689 return 0;
1695 int Disassembler::SubstituteLiteralField(const Instruction* instr,
1696 const char* format) {
1697 VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
1698 USE(format);
1700 const void * address = instr->LiteralAddress<const void *>();
1701 switch (instr->Mask(LoadLiteralMask)) {
1702 case LDR_w_lit:
1703 case LDR_x_lit:
1704 case LDRSW_x_lit:
1705 case LDR_s_lit:
1706 case LDR_d_lit:
1707 AppendCodeRelativeDataAddressToOutput(instr, address);
1708 break;
1709 case PRFM_lit: {
1710 // Use the prefetch hint to decide how to print the address.
1711 switch (instr->PrefetchHint()) {
1712 case 0x0: // PLD: prefetch for load.
1713 case 0x2: // PST: prepare for store.
1714 AppendCodeRelativeDataAddressToOutput(instr, address);
1715 break;
1716 case 0x1: // PLI: preload instructions.
1717 AppendCodeRelativeCodeAddressToOutput(instr, address);
1718 break;
1719 case 0x3: // Unallocated hint.
1720 AppendCodeRelativeAddressToOutput(instr, address);
1721 break;
1723 break;
1725 default:
1726 VIXL_UNREACHABLE();
1729 return 6;
1733 int Disassembler::SubstituteShiftField(const Instruction* instr,
1734 const char* format) {
1735 VIXL_ASSERT(format[0] == 'H');
1736 VIXL_ASSERT(instr->ShiftDP() <= 0x3);
1738 switch (format[1]) {
1739 case 'D': { // HDP.
1740 VIXL_ASSERT(instr->ShiftDP() != ROR);
1741 } // Fall through.
1742 case 'L': { // HLo.
1743 if (instr->ImmDPShift() != 0) {
1744 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
1745 AppendToOutput(", %s #%" PRId64, shift_type[instr->ShiftDP()],
1746 instr->ImmDPShift());
1748 return 3;
1750 default:
1751 VIXL_UNIMPLEMENTED();
1752 return 0;
1757 int Disassembler::SubstituteConditionField(const Instruction* instr,
1758 const char* format) {
1759 VIXL_ASSERT(format[0] == 'C');
1760 const char* condition_code[] = { "eq", "ne", "hs", "lo",
1761 "mi", "pl", "vs", "vc",
1762 "hi", "ls", "ge", "lt",
1763 "gt", "le", "al", "nv" };
1764 int cond;
1765 switch (format[1]) {
1766 case 'B': cond = instr->ConditionBranch(); break;
1767 case 'I': {
1768 cond = InvertCondition(static_cast<Condition>(instr->Condition()));
1769 break;
1771 default: cond = instr->Condition();
1773 AppendToOutput("%s", condition_code[cond]);
1774 return 4;
1778 int Disassembler::SubstitutePCRelAddressField(const Instruction* instr,
1779 const char* format) {
1780 VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`.
1781 (strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`.
1783 int64_t offset = instr->ImmPCRel();
1785 // Compute the target address based on the effective address (after applying
1786 // code_address_offset). This is required for correct behaviour of adrp.
1787 const Instruction* base = instr + code_address_offset();
1788 if (format[9] == 'P') {
1789 offset *= kPageSize;
1790 base = AlignDown(base, kPageSize);
1792 // Strip code_address_offset before printing, so we can use the
1793 // semantically-correct AppendCodeRelativeAddressToOutput.
1794 const void* target =
1795 reinterpret_cast<const void*>(base + offset - code_address_offset());
1797 AppendPCRelativeOffsetToOutput(instr, offset);
1798 AppendToOutput(" ");
1799 AppendCodeRelativeAddressToOutput(instr, target);
1800 return 13;
1804 int Disassembler::SubstituteBranchTargetField(const Instruction* instr,
1805 const char* format) {
1806 VIXL_ASSERT(strncmp(format, "BImm", 4) == 0);
1808 int64_t offset = 0;
1809 switch (format[5]) {
1810 // BImmUncn - unconditional branch immediate.
1811 case 'n': offset = instr->ImmUncondBranch(); break;
1812 // BImmCond - conditional branch immediate.
1813 case 'o': offset = instr->ImmCondBranch(); break;
1814 // BImmCmpa - compare and branch immediate.
1815 case 'm': offset = instr->ImmCmpBranch(); break;
1816 // BImmTest - test and branch immediate.
1817 case 'e': offset = instr->ImmTestBranch(); break;
1818 default: VIXL_UNIMPLEMENTED();
1820 offset <<= kInstructionSizeLog2;
1821 const void* target_address = reinterpret_cast<const void*>(instr + offset);
1822 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
1824 AppendPCRelativeOffsetToOutput(instr, offset);
1825 AppendToOutput(" ");
1826 AppendCodeRelativeCodeAddressToOutput(instr, target_address);
1828 return 8;
1832 int Disassembler::SubstituteExtendField(const Instruction* instr,
1833 const char* format) {
1834 VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
1835 VIXL_ASSERT(instr->ExtendMode() <= 7);
1836 USE(format);
1838 const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
1839 "sxtb", "sxth", "sxtw", "sxtx" };
1841 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
1842 // registers becomes lsl.
1843 if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
1844 (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
1845 (instr->ExtendMode() == UXTX))) {
1846 if (instr->ImmExtendShift() > 0) {
1847 AppendToOutput(", lsl #%" PRId64, instr->ImmExtendShift());
1849 } else {
1850 AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
1851 if (instr->ImmExtendShift() > 0) {
1852 AppendToOutput(" #%" PRId64, instr->ImmExtendShift());
1855 return 3;
1859 int Disassembler::SubstituteLSRegOffsetField(const Instruction* instr,
1860 const char* format) {
1861 VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
1862 const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
1863 "undefined", "undefined", "sxtw", "sxtx" };
1864 USE(format);
1866 unsigned shift = instr->ImmShiftLS();
1867 Extend ext = static_cast<Extend>(instr->ExtendMode());
1868 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
1870 unsigned rm = instr->Rm();
1871 if (rm == kZeroRegCode) {
1872 AppendToOutput("%czr", reg_type);
1873 } else {
1874 AppendToOutput("%c%d", reg_type, rm);
1877 // Extend mode UXTX is an alias for shift mode LSL here.
1878 if (!((ext == UXTX) && (shift == 0))) {
1879 AppendToOutput(", %s", extend_mode[ext]);
1880 if (shift != 0) {
1881 AppendToOutput(" #%" PRId64, instr->SizeLS());
1884 return 9;
1888 int Disassembler::SubstitutePrefetchField(const Instruction* instr,
1889 const char* format) {
1890 VIXL_ASSERT(format[0] == 'P');
1891 USE(format);
1893 static const char* hints[] = {"ld", "li", "st"};
1894 static const char* stream_options[] = {"keep", "strm"};
1896 unsigned hint = instr->PrefetchHint();
1897 unsigned target = instr->PrefetchTarget() + 1;
1898 unsigned stream = instr->PrefetchStream();
1900 if ((hint >= (sizeof(hints) / sizeof(hints[0]))) || (target > 3)) {
1901 // Unallocated prefetch operations.
1902 int prefetch_mode = instr->ImmPrefetchOperation();
1903 AppendToOutput("#0b%c%c%c%c%c",
1904 (prefetch_mode & (1 << 4)) ? '1' : '0',
1905 (prefetch_mode & (1 << 3)) ? '1' : '0',
1906 (prefetch_mode & (1 << 2)) ? '1' : '0',
1907 (prefetch_mode & (1 << 1)) ? '1' : '0',
1908 (prefetch_mode & (1 << 0)) ? '1' : '0');
1909 } else {
1910 VIXL_ASSERT(stream < (sizeof(stream_options) / sizeof(stream_options[0])));
1911 AppendToOutput("p%sl%d%s", hints[hint], target, stream_options[stream]);
1913 return 6;
1916 int Disassembler::SubstituteBarrierField(const Instruction* instr,
1917 const char* format) {
1918 VIXL_ASSERT(format[0] == 'M');
1919 USE(format);
1921 static const char* options[4][4] = {
1922 { "sy (0b0000)", "oshld", "oshst", "osh" },
1923 { "sy (0b0100)", "nshld", "nshst", "nsh" },
1924 { "sy (0b1000)", "ishld", "ishst", "ish" },
1925 { "sy (0b1100)", "ld", "st", "sy" }
1927 int domain = instr->ImmBarrierDomain();
1928 int type = instr->ImmBarrierType();
1930 AppendToOutput("%s", options[domain][type]);
1931 return 1;
1934 void Disassembler::ResetOutput() {
1935 buffer_pos_ = 0;
1936 buffer_[buffer_pos_] = 0;
1940 void Disassembler::AppendToOutput(const char* format, ...) {
1941 va_list args;
1942 va_start(args, format);
1943 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
1944 va_end(args);
1948 void PrintDisassembler::ProcessOutput(const Instruction* instr) {
1949 fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
1950 reinterpret_cast<uint64_t>(instr),
1951 instr->InstructionBits(),
1952 GetOutput());
1954 } // namespace vixl