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.
12 #if V8_TARGET_ARCH_ARM64
15 #include "arm64/decoder-arm64-inl.h"
16 #include "arm64/disasm-arm64.h"
17 #include "macro-assembler.h"
24 Disassembler::Disassembler() {
26 buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
32 Disassembler::Disassembler(char* text_buffer, int buffer_size) {
33 buffer_size_ = buffer_size;
34 buffer_ = text_buffer;
40 Disassembler::~Disassembler() {
47 char* Disassembler::GetOutput() {
52 void Disassembler::VisitAddSubImmediate(Instruction* instr) {
53 bool rd_is_zr = RdIsZROrSP(instr);
54 bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
55 (instr->ImmAddSub() == 0) ? true : false;
56 const char *mnemonic = "";
57 const char *form = "'Rds, 'Rns, 'IAddSub";
58 const char *form_cmp = "'Rns, 'IAddSub";
59 const char *form_mov = "'Rds, 'Rns";
61 switch (instr->Mask(AddSubImmediateMask)) {
81 case SUB_x_imm: mnemonic = "sub"; break;
91 default: UNREACHABLE();
93 Format(instr, mnemonic, form);
97 void Disassembler::VisitAddSubShifted(Instruction* instr) {
98 bool rd_is_zr = RdIsZROrSP(instr);
99 bool rn_is_zr = RnIsZROrSP(instr);
100 const char *mnemonic = "";
101 const char *form = "'Rd, 'Rn, 'Rm'HDP";
102 const char *form_cmp = "'Rn, 'Rm'HDP";
103 const char *form_neg = "'Rd, 'Rm'HDP";
105 switch (instr->Mask(AddSubShiftedMask)) {
107 case ADD_x_shift: mnemonic = "add"; break;
132 } else if (rn_is_zr) {
138 default: UNREACHABLE();
140 Format(instr, mnemonic, form);
144 void Disassembler::VisitAddSubExtended(Instruction* instr) {
145 bool rd_is_zr = RdIsZROrSP(instr);
146 const char *mnemonic = "";
147 Extend mode = static_cast<Extend>(instr->ExtendMode());
148 const char *form = ((mode == UXTX) || (mode == SXTX)) ?
149 "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext";
150 const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ?
151 "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
153 switch (instr->Mask(AddSubExtendedMask)) {
155 case ADD_x_ext: mnemonic = "add"; break;
166 case SUB_x_ext: mnemonic = "sub"; break;
176 default: UNREACHABLE();
178 Format(instr, mnemonic, form);
182 void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
183 bool rn_is_zr = RnIsZROrSP(instr);
184 const char *mnemonic = "";
185 const char *form = "'Rd, 'Rn, 'Rm";
186 const char *form_neg = "'Rd, 'Rm";
188 switch (instr->Mask(AddSubWithCarryMask)) {
190 case ADC_x: mnemonic = "adc"; break;
192 case ADCS_x: mnemonic = "adcs"; break;
211 default: UNREACHABLE();
213 Format(instr, mnemonic, form);
217 void Disassembler::VisitLogicalImmediate(Instruction* instr) {
218 bool rd_is_zr = RdIsZROrSP(instr);
219 bool rn_is_zr = RnIsZROrSP(instr);
220 const char *mnemonic = "";
221 const char *form = "'Rds, 'Rn, 'ITri";
223 if (instr->ImmLogical() == 0) {
224 // The immediate encoded in the instruction is not in the expected format.
225 Format(instr, "unallocated", "(LogicalImmediate)");
229 switch (instr->Mask(LogicalImmediateMask)) {
231 case AND_x_imm: mnemonic = "and"; break;
235 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
237 if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
239 form = "'Rds, 'ITri";
244 case EOR_x_imm: mnemonic = "eor"; break;
254 default: UNREACHABLE();
256 Format(instr, mnemonic, form);
260 bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
261 ASSERT((reg_size == kXRegSizeInBits) ||
262 ((reg_size == kWRegSizeInBits) && (value <= 0xffffffff)));
264 // Test for movz: 16-bits set at positions 0, 16, 32 or 48.
265 if (((value & 0xffffffffffff0000UL) == 0UL) ||
266 ((value & 0xffffffff0000ffffUL) == 0UL) ||
267 ((value & 0xffff0000ffffffffUL) == 0UL) ||
268 ((value & 0x0000ffffffffffffUL) == 0UL)) {
272 // Test for movn: NOT(16-bits set at positions 0, 16, 32 or 48).
273 if ((reg_size == kXRegSizeInBits) &&
274 (((value & 0xffffffffffff0000UL) == 0xffffffffffff0000UL) ||
275 ((value & 0xffffffff0000ffffUL) == 0xffffffff0000ffffUL) ||
276 ((value & 0xffff0000ffffffffUL) == 0xffff0000ffffffffUL) ||
277 ((value & 0x0000ffffffffffffUL) == 0x0000ffffffffffffUL))) {
280 if ((reg_size == kWRegSizeInBits) &&
281 (((value & 0xffff0000) == 0xffff0000) ||
282 ((value & 0x0000ffff) == 0x0000ffff))) {
289 void Disassembler::VisitLogicalShifted(Instruction* instr) {
290 bool rd_is_zr = RdIsZROrSP(instr);
291 bool rn_is_zr = RnIsZROrSP(instr);
292 const char *mnemonic = "";
293 const char *form = "'Rd, 'Rn, 'Rm'HLo";
295 switch (instr->Mask(LogicalShiftedMask)) {
297 case AND_x: mnemonic = "and"; break;
299 case BIC_x: mnemonic = "bic"; break;
301 case EOR_x: mnemonic = "eor"; break;
303 case EON_x: mnemonic = "eon"; break;
305 case BICS_x: mnemonic = "bics"; break;
311 form = "'Rn, 'Rm'HLo";
318 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
329 form = "'Rd, 'Rm'HLo";
333 default: UNREACHABLE();
336 Format(instr, mnemonic, form);
340 void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
341 const char *mnemonic = "";
342 const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
344 switch (instr->Mask(ConditionalCompareRegisterMask)) {
346 case CCMN_x: mnemonic = "ccmn"; break;
348 case CCMP_x: mnemonic = "ccmp"; break;
349 default: UNREACHABLE();
351 Format(instr, mnemonic, form);
355 void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
356 const char *mnemonic = "";
357 const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
359 switch (instr->Mask(ConditionalCompareImmediateMask)) {
361 case CCMN_x_imm: mnemonic = "ccmn"; break;
363 case CCMP_x_imm: mnemonic = "ccmp"; break;
364 default: UNREACHABLE();
366 Format(instr, mnemonic, form);
370 void Disassembler::VisitConditionalSelect(Instruction* instr) {
371 bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
372 bool rn_is_rm = (instr->Rn() == instr->Rm());
373 const char *mnemonic = "";
374 const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
375 const char *form_test = "'Rd, 'CInv";
376 const char *form_update = "'Rd, 'Rn, 'CInv";
378 Condition cond = static_cast<Condition>(instr->Condition());
379 bool invertible_cond = (cond != al) && (cond != nv);
381 switch (instr->Mask(ConditionalSelectMask)) {
383 case CSEL_x: mnemonic = "csel"; break;
387 if (rnm_is_zr && invertible_cond) {
390 } else if (rn_is_rm && invertible_cond) {
399 if (rnm_is_zr && invertible_cond) {
402 } else if (rn_is_rm && invertible_cond) {
411 if (rn_is_rm && invertible_cond) {
417 default: UNREACHABLE();
419 Format(instr, mnemonic, form);
423 void Disassembler::VisitBitfield(Instruction* instr) {
424 unsigned s = instr->ImmS();
425 unsigned r = instr->ImmR();
426 unsigned rd_size_minus_1 =
427 ((instr->SixtyFourBits() == 1) ? kXRegSizeInBits : kWRegSizeInBits) - 1;
428 const char *mnemonic = "";
429 const char *form = "";
430 const char *form_shift_right = "'Rd, 'Rn, 'IBr";
431 const char *form_extend = "'Rd, 'Wn";
432 const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
433 const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
434 const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
436 switch (instr->Mask(BitfieldMask)) {
445 } else if (s == 15) {
447 } else if ((s == 31) && (instr->SixtyFourBits() == 1)) {
452 } else if (s == rd_size_minus_1) {
454 form = form_shift_right;
469 } else if (s == 15) {
475 if (s == rd_size_minus_1) {
477 form = form_shift_right;
478 } else if (r == s + 1) {
497 Format(instr, mnemonic, form);
501 void Disassembler::VisitExtract(Instruction* instr) {
502 const char *mnemonic = "";
503 const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
505 switch (instr->Mask(ExtractMask)) {
508 if (instr->Rn() == instr->Rm()) {
510 form = "'Rd, 'Rn, 'IExtract";
516 default: UNREACHABLE();
518 Format(instr, mnemonic, form);
522 void Disassembler::VisitPCRelAddressing(Instruction* instr) {
523 switch (instr->Mask(PCRelAddressingMask)) {
524 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
525 // ADRP is not implemented.
526 default: Format(instr, "unimplemented", "(PCRelAddressing)");
531 void Disassembler::VisitConditionalBranch(Instruction* instr) {
532 switch (instr->Mask(ConditionalBranchMask)) {
533 case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
534 default: UNREACHABLE();
539 void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
540 const char *mnemonic = "unimplemented";
541 const char *form = "'Xn";
543 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
544 case BR: mnemonic = "br"; break;
545 case BLR: mnemonic = "blr"; break;
548 if (instr->Rn() == kLinkRegCode) {
553 default: form = "(UnconditionalBranchToRegister)";
555 Format(instr, mnemonic, form);
559 void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
560 const char *mnemonic = "";
561 const char *form = "'BImmUncn";
563 switch (instr->Mask(UnconditionalBranchMask)) {
564 case B: mnemonic = "b"; break;
565 case BL: mnemonic = "bl"; break;
566 default: UNREACHABLE();
568 Format(instr, mnemonic, form);
572 void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
573 const char *mnemonic = "";
574 const char *form = "'Rd, 'Rn";
576 switch (instr->Mask(DataProcessing1SourceMask)) {
577 #define FORMAT(A, B) \
579 case A##_x: mnemonic = B; break;
580 FORMAT(RBIT, "rbit");
581 FORMAT(REV16, "rev16");
586 case REV32_x: mnemonic = "rev32"; break;
587 default: UNREACHABLE();
589 Format(instr, mnemonic, form);
593 void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
594 const char *mnemonic = "unimplemented";
595 const char *form = "'Rd, 'Rn, 'Rm";
597 switch (instr->Mask(DataProcessing2SourceMask)) {
598 #define FORMAT(A, B) \
600 case A##_x: mnemonic = B; break;
601 FORMAT(UDIV, "udiv");
602 FORMAT(SDIV, "sdiv");
608 default: form = "(DataProcessing2Source)";
610 Format(instr, mnemonic, form);
614 void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
615 bool ra_is_zr = RaIsZROrSP(instr);
616 const char *mnemonic = "";
617 const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
618 const char *form_rrr = "'Rd, 'Rn, 'Rm";
619 const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
620 const char *form_xww = "'Xd, 'Wn, 'Wm";
621 const char *form_xxx = "'Xd, 'Xn, 'Xm";
623 switch (instr->Mask(DataProcessing3SourceMask)) {
686 default: UNREACHABLE();
688 Format(instr, mnemonic, form);
692 void Disassembler::VisitCompareBranch(Instruction* instr) {
693 const char *mnemonic = "";
694 const char *form = "'Rt, 'BImmCmpa";
696 switch (instr->Mask(CompareBranchMask)) {
698 case CBZ_x: mnemonic = "cbz"; break;
700 case CBNZ_x: mnemonic = "cbnz"; break;
701 default: UNREACHABLE();
703 Format(instr, mnemonic, form);
707 void Disassembler::VisitTestBranch(Instruction* instr) {
708 const char *mnemonic = "";
709 // If the top bit of the immediate is clear, the tested register is
710 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
711 // encoded in bit 31 of the instruction, we can reuse the Rt form, which
712 // uses bit 31 (normally "sf") to choose the register size.
713 const char *form = "'Rt, 'IS, 'BImmTest";
715 switch (instr->Mask(TestBranchMask)) {
716 case TBZ: mnemonic = "tbz"; break;
717 case TBNZ: mnemonic = "tbnz"; break;
718 default: UNREACHABLE();
720 Format(instr, mnemonic, form);
724 void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
725 const char *mnemonic = "";
726 const char *form = "'Rd, 'IMoveImm";
728 // Print the shift separately for movk, to make it clear which half word will
729 // be overwritten. Movn and movz print the computed immediate, which includes
730 // shift calculation.
731 switch (instr->Mask(MoveWideImmediateMask)) {
733 case MOVN_x: mnemonic = "movn"; break;
735 case MOVZ_x: mnemonic = "movz"; break;
737 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
738 default: UNREACHABLE();
740 Format(instr, mnemonic, form);
744 #define LOAD_STORE_LIST(V) \
745 V(STRB_w, "strb", "'Wt") \
746 V(STRH_w, "strh", "'Wt") \
747 V(STR_w, "str", "'Wt") \
748 V(STR_x, "str", "'Xt") \
749 V(LDRB_w, "ldrb", "'Wt") \
750 V(LDRH_w, "ldrh", "'Wt") \
751 V(LDR_w, "ldr", "'Wt") \
752 V(LDR_x, "ldr", "'Xt") \
753 V(LDRSB_x, "ldrsb", "'Xt") \
754 V(LDRSH_x, "ldrsh", "'Xt") \
755 V(LDRSW_x, "ldrsw", "'Xt") \
756 V(LDRSB_w, "ldrsb", "'Wt") \
757 V(LDRSH_w, "ldrsh", "'Wt") \
758 V(STR_s, "str", "'St") \
759 V(STR_d, "str", "'Dt") \
760 V(LDR_s, "ldr", "'St") \
761 V(LDR_d, "ldr", "'Dt")
763 void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
764 const char *mnemonic = "unimplemented";
765 const char *form = "(LoadStorePreIndex)";
767 switch (instr->Mask(LoadStorePreIndexMask)) {
768 #define LS_PREINDEX(A, B, C) \
769 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
770 LOAD_STORE_LIST(LS_PREINDEX)
773 Format(instr, mnemonic, form);
777 void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
778 const char *mnemonic = "unimplemented";
779 const char *form = "(LoadStorePostIndex)";
781 switch (instr->Mask(LoadStorePostIndexMask)) {
782 #define LS_POSTINDEX(A, B, C) \
783 case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
784 LOAD_STORE_LIST(LS_POSTINDEX)
787 Format(instr, mnemonic, form);
791 void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
792 const char *mnemonic = "unimplemented";
793 const char *form = "(LoadStoreUnsignedOffset)";
795 switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
796 #define LS_UNSIGNEDOFFSET(A, B, C) \
797 case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
798 LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
799 #undef LS_UNSIGNEDOFFSET
800 case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xn'ILU]";
802 Format(instr, mnemonic, form);
806 void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
807 const char *mnemonic = "unimplemented";
808 const char *form = "(LoadStoreRegisterOffset)";
810 switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
811 #define LS_REGISTEROFFSET(A, B, C) \
812 case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
813 LOAD_STORE_LIST(LS_REGISTEROFFSET)
814 #undef LS_REGISTEROFFSET
815 case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]";
817 Format(instr, mnemonic, form);
821 void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
822 const char *mnemonic = "unimplemented";
823 const char *form = "'Wt, ['Xns'ILS]";
824 const char *form_x = "'Xt, ['Xns'ILS]";
825 const char *form_s = "'St, ['Xns'ILS]";
826 const char *form_d = "'Dt, ['Xns'ILS]";
828 switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
829 case STURB_w: mnemonic = "sturb"; break;
830 case STURH_w: mnemonic = "sturh"; break;
831 case STUR_w: mnemonic = "stur"; break;
832 case STUR_x: mnemonic = "stur"; form = form_x; break;
833 case STUR_s: mnemonic = "stur"; form = form_s; break;
834 case STUR_d: mnemonic = "stur"; form = form_d; break;
835 case LDURB_w: mnemonic = "ldurb"; break;
836 case LDURH_w: mnemonic = "ldurh"; break;
837 case LDUR_w: mnemonic = "ldur"; break;
838 case LDUR_x: mnemonic = "ldur"; form = form_x; break;
839 case LDUR_s: mnemonic = "ldur"; form = form_s; break;
840 case LDUR_d: mnemonic = "ldur"; form = form_d; break;
841 case LDURSB_x: form = form_x; // Fall through.
842 case LDURSB_w: mnemonic = "ldursb"; break;
843 case LDURSH_x: form = form_x; // Fall through.
844 case LDURSH_w: mnemonic = "ldursh"; break;
845 case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
846 default: form = "(LoadStoreUnscaledOffset)";
848 Format(instr, mnemonic, form);
852 void Disassembler::VisitLoadLiteral(Instruction* instr) {
853 const char *mnemonic = "ldr";
854 const char *form = "(LoadLiteral)";
856 switch (instr->Mask(LoadLiteralMask)) {
857 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break;
858 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
859 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
860 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
861 default: mnemonic = "unimplemented";
863 Format(instr, mnemonic, form);
867 #define LOAD_STORE_PAIR_LIST(V) \
868 V(STP_w, "stp", "'Wt, 'Wt2", "4") \
869 V(LDP_w, "ldp", "'Wt, 'Wt2", "4") \
870 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \
871 V(STP_x, "stp", "'Xt, 'Xt2", "8") \
872 V(LDP_x, "ldp", "'Xt, 'Xt2", "8") \
873 V(STP_s, "stp", "'St, 'St2", "4") \
874 V(LDP_s, "ldp", "'St, 'St2", "4") \
875 V(STP_d, "stp", "'Dt, 'Dt2", "8") \
876 V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
878 void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
879 const char *mnemonic = "unimplemented";
880 const char *form = "(LoadStorePairPostIndex)";
882 switch (instr->Mask(LoadStorePairPostIndexMask)) {
883 #define LSP_POSTINDEX(A, B, C, D) \
884 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
885 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
888 Format(instr, mnemonic, form);
892 void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
893 const char *mnemonic = "unimplemented";
894 const char *form = "(LoadStorePairPreIndex)";
896 switch (instr->Mask(LoadStorePairPreIndexMask)) {
897 #define LSP_PREINDEX(A, B, C, D) \
898 case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
899 LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
902 Format(instr, mnemonic, form);
906 void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
907 const char *mnemonic = "unimplemented";
908 const char *form = "(LoadStorePairOffset)";
910 switch (instr->Mask(LoadStorePairOffsetMask)) {
911 #define LSP_OFFSET(A, B, C, D) \
912 case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
913 LOAD_STORE_PAIR_LIST(LSP_OFFSET)
916 Format(instr, mnemonic, form);
920 void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
921 const char *mnemonic = "unimplemented";
924 switch (instr->Mask(LoadStorePairNonTemporalMask)) {
925 case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
926 case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
927 case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
928 case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
929 case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
930 case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
931 case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
932 case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
933 default: form = "(LoadStorePairNonTemporal)";
935 Format(instr, mnemonic, form);
939 void Disassembler::VisitFPCompare(Instruction* instr) {
940 const char *mnemonic = "unimplemented";
941 const char *form = "'Fn, 'Fm";
942 const char *form_zero = "'Fn, #0.0";
944 switch (instr->Mask(FPCompareMask)) {
946 case FCMP_d_zero: form = form_zero; // Fall through.
948 case FCMP_d: mnemonic = "fcmp"; break;
949 default: form = "(FPCompare)";
951 Format(instr, mnemonic, form);
955 void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
956 const char *mnemonic = "unimplemented";
957 const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
959 switch (instr->Mask(FPConditionalCompareMask)) {
961 case FCCMP_d: mnemonic = "fccmp"; break;
963 case FCCMPE_d: mnemonic = "fccmpe"; break;
964 default: form = "(FPConditionalCompare)";
966 Format(instr, mnemonic, form);
970 void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
971 const char *mnemonic = "";
972 const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
974 switch (instr->Mask(FPConditionalSelectMask)) {
976 case FCSEL_d: mnemonic = "fcsel"; break;
977 default: UNREACHABLE();
979 Format(instr, mnemonic, form);
983 void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
984 const char *mnemonic = "unimplemented";
985 const char *form = "'Fd, 'Fn";
987 switch (instr->Mask(FPDataProcessing1SourceMask)) {
988 #define FORMAT(A, B) \
990 case A##_d: mnemonic = B; break;
991 FORMAT(FMOV, "fmov");
992 FORMAT(FABS, "fabs");
993 FORMAT(FNEG, "fneg");
994 FORMAT(FSQRT, "fsqrt");
995 FORMAT(FRINTN, "frintn");
996 FORMAT(FRINTP, "frintp");
997 FORMAT(FRINTM, "frintm");
998 FORMAT(FRINTZ, "frintz");
999 FORMAT(FRINTA, "frinta");
1000 FORMAT(FRINTX, "frintx");
1001 FORMAT(FRINTI, "frinti");
1003 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
1004 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
1005 default: form = "(FPDataProcessing1Source)";
1007 Format(instr, mnemonic, form);
1011 void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
1012 const char *mnemonic = "";
1013 const char *form = "'Fd, 'Fn, 'Fm";
1015 switch (instr->Mask(FPDataProcessing2SourceMask)) {
1016 #define FORMAT(A, B) \
1018 case A##_d: mnemonic = B; break;
1019 FORMAT(FMUL, "fmul");
1020 FORMAT(FDIV, "fdiv");
1021 FORMAT(FADD, "fadd");
1022 FORMAT(FSUB, "fsub");
1023 FORMAT(FMAX, "fmax");
1024 FORMAT(FMIN, "fmin");
1025 FORMAT(FMAXNM, "fmaxnm");
1026 FORMAT(FMINNM, "fminnm");
1027 FORMAT(FNMUL, "fnmul");
1029 default: UNREACHABLE();
1031 Format(instr, mnemonic, form);
1035 void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
1036 const char *mnemonic = "";
1037 const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
1039 switch (instr->Mask(FPDataProcessing3SourceMask)) {
1040 #define FORMAT(A, B) \
1042 case A##_d: mnemonic = B; break;
1043 FORMAT(FMADD, "fmadd");
1044 FORMAT(FMSUB, "fmsub");
1045 FORMAT(FNMADD, "fnmadd");
1046 FORMAT(FNMSUB, "fnmsub");
1048 default: UNREACHABLE();
1050 Format(instr, mnemonic, form);
1054 void Disassembler::VisitFPImmediate(Instruction* instr) {
1055 const char *mnemonic = "";
1056 const char *form = "(FPImmediate)";
1058 switch (instr->Mask(FPImmediateMask)) {
1059 case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
1060 case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
1061 default: UNREACHABLE();
1063 Format(instr, mnemonic, form);
1067 void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
1068 const char *mnemonic = "unimplemented";
1069 const char *form = "(FPIntegerConvert)";
1070 const char *form_rf = "'Rd, 'Fn";
1071 const char *form_fr = "'Fd, 'Rn";
1073 switch (instr->Mask(FPIntegerConvertMask)) {
1075 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
1077 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
1081 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
1085 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
1089 case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
1093 case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
1097 case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
1101 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
1105 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
1109 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
1113 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
1117 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
1119 Format(instr, mnemonic, form);
1123 void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
1124 const char *mnemonic = "";
1125 const char *form = "'Rd, 'Fn, 'IFPFBits";
1126 const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
1128 switch (instr->Mask(FPFixedPointConvertMask)) {
1129 case FCVTZS_ws_fixed:
1130 case FCVTZS_xs_fixed:
1131 case FCVTZS_wd_fixed:
1132 case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
1133 case FCVTZU_ws_fixed:
1134 case FCVTZU_xs_fixed:
1135 case FCVTZU_wd_fixed:
1136 case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
1137 case SCVTF_sw_fixed:
1138 case SCVTF_sx_fixed:
1139 case SCVTF_dw_fixed:
1140 case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
1141 case UCVTF_sw_fixed:
1142 case UCVTF_sx_fixed:
1143 case UCVTF_dw_fixed:
1144 case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
1146 Format(instr, mnemonic, form);
1150 void Disassembler::VisitSystem(Instruction* instr) {
1151 // Some system instructions hijack their Op and Cp fields to represent a
1152 // range of immediates instead of indicating a different instruction. This
1153 // makes the decoding tricky.
1154 const char *mnemonic = "unimplemented";
1155 const char *form = "(System)";
1157 if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1158 switch (instr->Mask(SystemSysRegMask)) {
1161 switch (instr->ImmSystemRegister()) {
1162 case NZCV: form = "'Xt, nzcv"; break;
1163 case FPCR: form = "'Xt, fpcr"; break;
1164 default: form = "'Xt, (unknown)"; break;
1170 switch (instr->ImmSystemRegister()) {
1171 case NZCV: form = "nzcv, 'Xt"; break;
1172 case FPCR: form = "fpcr, 'Xt"; break;
1173 default: form = "(unknown), 'Xt"; break;
1178 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1179 ASSERT(instr->Mask(SystemHintMask) == HINT);
1180 switch (instr->ImmHint()) {
1187 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
1188 switch (instr->Mask(MemBarrierMask)) {
1207 Format(instr, mnemonic, form);
1211 void Disassembler::VisitException(Instruction* instr) {
1212 const char *mnemonic = "unimplemented";
1213 const char *form = "'IDebug";
1215 switch (instr->Mask(ExceptionMask)) {
1216 case HLT: mnemonic = "hlt"; break;
1217 case BRK: mnemonic = "brk"; break;
1218 case SVC: mnemonic = "svc"; break;
1219 case HVC: mnemonic = "hvc"; break;
1220 case SMC: mnemonic = "smc"; break;
1221 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
1222 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
1223 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
1224 default: form = "(Exception)";
1226 Format(instr, mnemonic, form);
1230 void Disassembler::VisitUnimplemented(Instruction* instr) {
1231 Format(instr, "unimplemented", "(Unimplemented)");
1235 void Disassembler::VisitUnallocated(Instruction* instr) {
1236 Format(instr, "unallocated", "(Unallocated)");
1240 void Disassembler::ProcessOutput(Instruction* /*instr*/) {
1241 // The base disasm does nothing more than disassembling into a buffer.
1245 void Disassembler::Format(Instruction* instr, const char* mnemonic,
1246 const char* format) {
1247 // TODO(mcapewel) don't think I can use the instr address here - there needs
1248 // to be a base address too
1249 ASSERT(mnemonic != NULL);
1251 Substitute(instr, mnemonic);
1252 if (format != NULL) {
1253 buffer_[buffer_pos_++] = ' ';
1254 Substitute(instr, format);
1256 buffer_[buffer_pos_] = 0;
1257 ProcessOutput(instr);
1261 void Disassembler::Substitute(Instruction* instr, const char* string) {
1262 char chr = *string++;
1263 while (chr != '\0') {
1265 string += SubstituteField(instr, string);
1267 buffer_[buffer_pos_++] = chr;
1274 int Disassembler::SubstituteField(Instruction* instr, const char* format) {
1275 switch (format[0]) {
1276 case 'R': // Register. X or W, selected by sf bit.
1277 case 'F': // FP Register. S or D, selected by type field.
1281 case 'D': return SubstituteRegisterField(instr, format);
1282 case 'I': return SubstituteImmediateField(instr, format);
1283 case 'L': return SubstituteLiteralField(instr, format);
1284 case 'H': return SubstituteShiftField(instr, format);
1285 case 'P': return SubstitutePrefetchField(instr, format);
1286 case 'C': return SubstituteConditionField(instr, format);
1287 case 'E': return SubstituteExtendField(instr, format);
1288 case 'A': return SubstitutePCRelAddressField(instr, format);
1289 case 'B': return SubstituteBranchTargetField(instr, format);
1290 case 'O': return SubstituteLSRegOffsetField(instr, format);
1291 case 'M': return SubstituteBarrierField(instr, format);
1300 int Disassembler::SubstituteRegisterField(Instruction* instr,
1301 const char* format) {
1302 unsigned reg_num = 0;
1303 unsigned field_len = 2;
1304 switch (format[1]) {
1305 case 'd': reg_num = instr->Rd(); break;
1306 case 'n': reg_num = instr->Rn(); break;
1307 case 'm': reg_num = instr->Rm(); break;
1308 case 'a': reg_num = instr->Ra(); break;
1310 if (format[2] == '2') {
1311 reg_num = instr->Rt2();
1314 reg_num = instr->Rt();
1318 default: UNREACHABLE();
1321 // Increase field length for registers tagged as stack.
1322 if (format[2] == 's') {
1327 if (format[0] == 'R') {
1328 // Register type is R: use sf bit to choose X and W.
1329 reg_type = instr->SixtyFourBits() ? 'x' : 'w';
1330 } else if (format[0] == 'F') {
1331 // Floating-point register: use type field to choose S or D.
1332 reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
1334 // Register type is specified. Make it lower case.
1335 reg_type = format[0] + 0x20;
1338 if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
1339 // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
1341 // Filter special registers
1342 if ((reg_type == 'x') && (reg_num == 27)) {
1343 AppendToOutput("cp");
1344 } else if ((reg_type == 'x') && (reg_num == 28)) {
1345 AppendToOutput("jssp");
1346 } else if ((reg_type == 'x') && (reg_num == 29)) {
1347 AppendToOutput("fp");
1348 } else if ((reg_type == 'x') && (reg_num == 30)) {
1349 AppendToOutput("lr");
1351 AppendToOutput("%c%d", reg_type, reg_num);
1353 } else if (format[2] == 's') {
1354 // Disassemble w31/x31 as stack pointer wcsp/csp.
1355 AppendToOutput("%s", (reg_type == 'w') ? "wcsp" : "csp");
1357 // Disassemble w31/x31 as zero register wzr/xzr.
1358 AppendToOutput("%czr", reg_type);
1365 int Disassembler::SubstituteImmediateField(Instruction* instr,
1366 const char* format) {
1367 ASSERT(format[0] == 'I');
1369 switch (format[1]) {
1370 case 'M': { // IMoveImm or IMoveLSL.
1371 if (format[5] == 'I') {
1372 uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
1373 AppendToOutput("#0x%" PRIx64, imm);
1375 ASSERT(format[5] == 'L');
1376 AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
1377 if (instr->ShiftMoveWide() > 0) {
1378 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
1384 switch (format[2]) {
1385 case 'L': { // ILLiteral - Immediate Load Literal.
1386 AppendToOutput("pc%+" PRId64,
1387 instr->ImmLLiteral() << kLiteralEntrySizeLog2);
1390 case 'S': { // ILS - Immediate Load/Store.
1391 if (instr->ImmLS() != 0) {
1392 AppendToOutput(", #%" PRId64, instr->ImmLS());
1396 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
1397 if (instr->ImmLSPair() != 0) {
1398 // format[3] is the scale value. Convert to a number.
1399 int scale = format[3] - 0x30;
1400 AppendToOutput(", #%" PRId64, instr->ImmLSPair() * scale);
1404 case 'U': { // ILU - Immediate Load/Store Unsigned.
1405 if (instr->ImmLSUnsigned() != 0) {
1406 AppendToOutput(", #%" PRIu64,
1407 instr->ImmLSUnsigned() << instr->SizeLS());
1413 case 'C': { // ICondB - Immediate Conditional Branch.
1414 int64_t offset = instr->ImmCondBranch() << 2;
1415 char sign = (offset >= 0) ? '+' : '-';
1416 AppendToOutput("#%c0x%" PRIx64, sign, offset);
1419 case 'A': { // IAddSub.
1420 ASSERT(instr->ShiftAddSub() <= 1);
1421 int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
1422 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
1425 case 'F': { // IFPSingle, IFPDouble or IFPFBits.
1426 if (format[3] == 'F') { // IFPFBits.
1427 AppendToOutput("#%d", 64 - instr->FPScale());
1430 AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
1431 format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
1435 case 'T': { // ITri - Immediate Triangular Encoded.
1436 AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
1439 case 'N': { // INzcv.
1440 int nzcv = (instr->Nzcv() << Flags_offset);
1441 AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
1442 ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
1443 ((nzcv & CFlag) == 0) ? 'c' : 'C',
1444 ((nzcv & VFlag) == 0) ? 'v' : 'V');
1447 case 'P': { // IP - Conditional compare.
1448 AppendToOutput("#%d", instr->ImmCondCmp());
1451 case 'B': { // Bitfields.
1452 return SubstituteBitfieldImmediateField(instr, format);
1454 case 'E': { // IExtract.
1455 AppendToOutput("#%d", instr->ImmS());
1458 case 'S': { // IS - Test and branch bit.
1459 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
1460 instr->ImmTestBranchBit40());
1463 case 'D': { // IDebug - HLT and BRK instructions.
1464 AppendToOutput("#0x%x", instr->ImmException());
1475 int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
1476 const char* format) {
1477 ASSERT((format[0] == 'I') && (format[1] == 'B'));
1478 unsigned r = instr->ImmR();
1479 unsigned s = instr->ImmS();
1481 switch (format[2]) {
1483 AppendToOutput("#%d", r);
1486 case 's': { // IBs+1 or IBs-r+1.
1487 if (format[3] == '+') {
1488 AppendToOutput("#%d", s + 1);
1491 ASSERT(format[3] == '-');
1492 AppendToOutput("#%d", s - r + 1);
1496 case 'Z': { // IBZ-r.
1497 ASSERT((format[3] == '-') && (format[4] == 'r'));
1498 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
1500 AppendToOutput("#%d", reg_size - r);
1511 int Disassembler::SubstituteLiteralField(Instruction* instr,
1512 const char* format) {
1513 ASSERT(strncmp(format, "LValue", 6) == 0);
1516 switch (instr->Mask(LoadLiteralMask)) {
1520 case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
1521 default: UNREACHABLE();
1528 int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
1529 ASSERT(format[0] == 'H');
1530 ASSERT(instr->ShiftDP() <= 0x3);
1532 switch (format[1]) {
1534 ASSERT(instr->ShiftDP() != ROR);
1537 if (instr->ImmDPShift() != 0) {
1538 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
1539 AppendToOutput(", %s #%" PRId64, shift_type[instr->ShiftDP()],
1540 instr->ImmDPShift());
1551 int Disassembler::SubstituteConditionField(Instruction* instr,
1552 const char* format) {
1553 ASSERT(format[0] == 'C');
1554 const char* condition_code[] = { "eq", "ne", "hs", "lo",
1555 "mi", "pl", "vs", "vc",
1556 "hi", "ls", "ge", "lt",
1557 "gt", "le", "al", "nv" };
1559 switch (format[1]) {
1560 case 'B': cond = instr->ConditionBranch(); break;
1562 cond = InvertCondition(static_cast<Condition>(instr->Condition()));
1565 default: cond = instr->Condition();
1567 AppendToOutput("%s", condition_code[cond]);
1572 int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
1573 const char* format) {
1575 ASSERT(strncmp(format, "AddrPCRel", 9) == 0);
1577 int offset = instr->ImmPCRel();
1579 // Only ADR (AddrPCRelByte) is supported.
1580 ASSERT(strcmp(format, "AddrPCRelByte") == 0);
1587 AppendToOutput("#%c0x%x (addr %p)", sign, offset,
1588 instr->InstructionAtOffset(offset, Instruction::NO_CHECK));
1593 int Disassembler::SubstituteBranchTargetField(Instruction* instr,
1594 const char* format) {
1595 ASSERT(strncmp(format, "BImm", 4) == 0);
1598 switch (format[5]) {
1599 // BImmUncn - unconditional branch immediate.
1600 case 'n': offset = instr->ImmUncondBranch(); break;
1601 // BImmCond - conditional branch immediate.
1602 case 'o': offset = instr->ImmCondBranch(); break;
1603 // BImmCmpa - compare and branch immediate.
1604 case 'm': offset = instr->ImmCmpBranch(); break;
1605 // BImmTest - test and branch immediate.
1606 case 'e': offset = instr->ImmTestBranch(); break;
1607 default: UNREACHABLE();
1609 offset <<= kInstructionSizeLog2;
1614 AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset),
1615 instr->InstructionAtOffset(offset), Instruction::NO_CHECK);
1620 int Disassembler::SubstituteExtendField(Instruction* instr,
1621 const char* format) {
1622 ASSERT(strncmp(format, "Ext", 3) == 0);
1623 ASSERT(instr->ExtendMode() <= 7);
1626 const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
1627 "sxtb", "sxth", "sxtw", "sxtx" };
1629 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
1630 // registers becomes lsl.
1631 if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
1632 (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
1633 (instr->ExtendMode() == UXTX))) {
1634 if (instr->ImmExtendShift() > 0) {
1635 AppendToOutput(", lsl #%d", instr->ImmExtendShift());
1638 AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
1639 if (instr->ImmExtendShift() > 0) {
1640 AppendToOutput(" #%d", instr->ImmExtendShift());
1647 int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
1648 const char* format) {
1649 ASSERT(strncmp(format, "Offsetreg", 9) == 0);
1650 const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
1651 "undefined", "undefined", "sxtw", "sxtx" };
1654 unsigned shift = instr->ImmShiftLS();
1655 Extend ext = static_cast<Extend>(instr->ExtendMode());
1656 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
1658 unsigned rm = instr->Rm();
1659 if (rm == kZeroRegCode) {
1660 AppendToOutput("%czr", reg_type);
1662 AppendToOutput("%c%d", reg_type, rm);
1665 // Extend mode UXTX is an alias for shift mode LSL here.
1666 if (!((ext == UXTX) && (shift == 0))) {
1667 AppendToOutput(", %s", extend_mode[ext]);
1669 AppendToOutput(" #%d", instr->SizeLS());
1676 int Disassembler::SubstitutePrefetchField(Instruction* instr,
1677 const char* format) {
1678 ASSERT(format[0] == 'P');
1681 int prefetch_mode = instr->PrefetchMode();
1683 const char* ls = (prefetch_mode & 0x10) ? "st" : "ld";
1684 int level = (prefetch_mode >> 1) + 1;
1685 const char* ks = (prefetch_mode & 1) ? "strm" : "keep";
1687 AppendToOutput("p%sl%d%s", ls, level, ks);
1691 int Disassembler::SubstituteBarrierField(Instruction* instr,
1692 const char* format) {
1693 ASSERT(format[0] == 'M');
1696 static const char* options[4][4] = {
1697 { "sy (0b0000)", "oshld", "oshst", "osh" },
1698 { "sy (0b0100)", "nshld", "nshst", "nsh" },
1699 { "sy (0b1000)", "ishld", "ishst", "ish" },
1700 { "sy (0b1100)", "ld", "st", "sy" }
1702 int domain = instr->ImmBarrierDomain();
1703 int type = instr->ImmBarrierType();
1705 AppendToOutput("%s", options[domain][type]);
1710 void Disassembler::ResetOutput() {
1712 buffer_[buffer_pos_] = 0;
1716 void Disassembler::AppendToOutput(const char* format, ...) {
1718 va_start(args, format);
1719 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
1724 void PrintDisassembler::ProcessOutput(Instruction* instr) {
1725 fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
1726 reinterpret_cast<uint64_t>(instr), instr->InstructionBits(),
1730 } } // namespace v8::internal
1736 const char* NameConverter::NameOfAddress(byte* addr) const {
1737 v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
1738 return tmp_buffer_.start();
1742 const char* NameConverter::NameOfConstant(byte* addr) const {
1743 return NameOfAddress(addr);
1747 const char* NameConverter::NameOfCPURegister(int reg) const {
1748 unsigned ureg = reg; // Avoid warnings about signed/unsigned comparisons.
1749 if (ureg >= v8::internal::kNumberOfRegisters) {
1752 if (ureg == v8::internal::kZeroRegCode) {
1755 v8::internal::OS::SNPrintF(tmp_buffer_, "x%u", ureg);
1756 return tmp_buffer_.start();
1760 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1761 UNREACHABLE(); // ARM64 does not have the concept of a byte register
1766 const char* NameConverter::NameOfXMMRegister(int reg) const {
1767 UNREACHABLE(); // ARM64 does not have any XMM registers
1772 const char* NameConverter::NameInCode(byte* addr) const {
1773 // The default name converter is called for unknown code, so we will not try
1774 // to access any memory.
1779 //------------------------------------------------------------------------------
1781 class BufferDisassembler : public v8::internal::Disassembler {
1783 explicit BufferDisassembler(v8::internal::Vector<char> out_buffer)
1784 : out_buffer_(out_buffer) { }
1786 ~BufferDisassembler() { }
1788 virtual void ProcessOutput(v8::internal::Instruction* instr) {
1789 v8::internal::OS::SNPrintF(out_buffer_, "%s", GetOutput());
1793 v8::internal::Vector<char> out_buffer_;
1796 Disassembler::Disassembler(const NameConverter& converter)
1797 : converter_(converter) {}
1800 Disassembler::~Disassembler() {}
1803 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1805 v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder;
1806 BufferDisassembler disasm(buffer);
1807 decoder.AppendVisitor(&disasm);
1809 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(instr));
1810 return v8::internal::kInstructionSize;
1814 int Disassembler::ConstantPoolSizeAt(byte* instr) {
1815 return v8::internal::Assembler::ConstantPoolSizeAt(
1816 reinterpret_cast<v8::internal::Instruction*>(instr));
1820 void Disassembler::Disassemble(FILE* file, byte* start, byte* end) {
1821 v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder;
1822 v8::internal::PrintDisassembler disasm(file);
1823 decoder.AppendVisitor(&disasm);
1825 for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) {
1826 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc));
1830 } // namespace disasm
1832 #endif // V8_TARGET_ARCH_ARM64