1 // Copyright 2015, ARM Limited
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
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.
28 #include "vixl/a64/disasm-a64.h"
32 Disassembler::Disassembler() {
34 buffer_
= reinterpret_cast<char*>(malloc(buffer_size_
));
37 code_address_offset_
= 0;
41 Disassembler::Disassembler(char* text_buffer
, int buffer_size
) {
42 buffer_size_
= buffer_size
;
43 buffer_
= text_buffer
;
46 code_address_offset_
= 0;
50 Disassembler::~Disassembler() {
57 char* Disassembler::GetOutput() {
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
)) {
91 case SUB_x_imm
: mnemonic
= "sub"; 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'NDP";
112 const char *form_cmp
= "'Rn, 'Rm'NDP";
113 const char *form_neg
= "'Rd, 'Rm'NDP";
115 switch (instr
->Mask(AddSubShiftedMask
)) {
117 case ADD_x_shift
: mnemonic
= "add"; break;
142 } else if (rn_is_zr
) {
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
)) {
165 case ADD_x_ext
: mnemonic
= "add"; break;
176 case SUB_x_ext
: mnemonic
= "sub"; 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
)) {
200 case ADC_x
: mnemonic
= "adc"; break;
202 case ADCS_x
: mnemonic
= "adcs"; 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)");
239 switch (instr
->Mask(LogicalImmediateMask
)) {
241 case AND_x_imm
: mnemonic
= "and"; break;
245 unsigned reg_size
= (instr
->SixtyFourBits() == 1) ? kXRegSize
247 if (rn_is_zr
&& !IsMovzMovnImm(reg_size
, instr
->ImmLogical())) {
249 form
= "'Rds, 'ITri";
254 case EOR_x_imm
: mnemonic
= "eor"; 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)) {
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))) {
290 if ((reg_size
== kWRegSize
) &&
291 (((value
& 0xffff0000) == 0xffff0000) ||
292 ((value
& 0x0000ffff) == 0x0000ffff))) {
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'NLo";
305 switch (instr
->Mask(LogicalShiftedMask
)) {
307 case AND_x
: mnemonic
= "and"; break;
309 case BIC_x
: mnemonic
= "bic"; break;
311 case EOR_x
: mnemonic
= "eor"; break;
313 case EON_x
: mnemonic
= "eon"; break;
315 case BICS_x
: mnemonic
= "bics"; break;
321 form
= "'Rn, 'Rm'NLo";
328 if (rn_is_zr
&& (instr
->ImmDPShift() == 0) && (instr
->ShiftDP() == LSL
)) {
339 form
= "'Rd, 'Rm'NLo";
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
)) {
356 case CCMN_x
: mnemonic
= "ccmn"; break;
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
)) {
371 case CCMN_x_imm
: mnemonic
= "ccmn"; break;
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
)) {
393 case CSEL_x
: mnemonic
= "csel"; break;
397 if (rnm_is_zr
&& invertible_cond
) {
400 } else if (rn_is_rm
&& invertible_cond
) {
409 if (rnm_is_zr
&& invertible_cond
) {
412 } else if (rn_is_rm
&& invertible_cond
) {
421 if (rn_is_rm
&& invertible_cond
) {
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
)) {
455 } else if (s
== 15) {
457 } else if ((s
== 31) && (instr
->SixtyFourBits() == 1)) {
462 } else if (s
== rd_size_minus_1
) {
464 form
= form_shift_right
;
479 } else if (s
== 15) {
485 if (s
== rd_size_minus_1
) {
487 form
= form_shift_right
;
488 } else if (r
== s
+ 1) {
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
)) {
518 if (instr
->Rn() == instr
->Rm()) {
520 form
= "'Rd, 'Rn, 'IExtract";
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", "'TImmCond"); 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;
559 if (instr
->Rn() == kLinkRegCode
) {
564 default: form
= "(UnconditionalBranchToRegister)";
566 Format(instr
, mnemonic
, form
);
570 void Disassembler::VisitUnconditionalBranch(const Instruction
* instr
) {
571 const char *mnemonic
= "";
572 const char *form
= "'TImmUncn";
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) \
590 case A##_x: mnemonic = B; break;
591 FORMAT(RBIT
, "rbit");
592 FORMAT(REV16
, "rev16");
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";
607 const char *form_wwx
= "'Wd, 'Wn, 'Xm";
609 switch (instr
->Mask(DataProcessing2SourceMask
)) {
610 #define FORMAT(A, B) \
612 case A##_x: mnemonic = B; break;
613 FORMAT(UDIV
, "udiv");
614 FORMAT(SDIV
, "sdiv");
620 case CRC32B
: mnemonic
= "crc32b"; break;
621 case CRC32H
: mnemonic
= "crc32h"; break;
622 case CRC32W
: mnemonic
= "crc32w"; break;
623 case CRC32X
: mnemonic
= "crc32x"; form
= form_wwx
; break;
624 case CRC32CB
: mnemonic
= "crc32cb"; break;
625 case CRC32CH
: mnemonic
= "crc32ch"; break;
626 case CRC32CW
: mnemonic
= "crc32cw"; break;
627 case CRC32CX
: mnemonic
= "crc32cx"; form
= form_wwx
; break;
628 default: form
= "(DataProcessing2Source)";
630 Format(instr
, mnemonic
, form
);
634 void Disassembler::VisitDataProcessing3Source(const Instruction
* instr
) {
635 bool ra_is_zr
= RaIsZROrSP(instr
);
636 const char *mnemonic
= "";
637 const char *form
= "'Xd, 'Wn, 'Wm, 'Xa";
638 const char *form_rrr
= "'Rd, 'Rn, 'Rm";
639 const char *form_rrrr
= "'Rd, 'Rn, 'Rm, 'Ra";
640 const char *form_xww
= "'Xd, 'Wn, 'Wm";
641 const char *form_xxx
= "'Xd, 'Xn, 'Xm";
643 switch (instr
->Mask(DataProcessing3SourceMask
)) {
706 default: VIXL_UNREACHABLE();
708 Format(instr
, mnemonic
, form
);
712 void Disassembler::VisitCompareBranch(const Instruction
* instr
) {
713 const char *mnemonic
= "";
714 const char *form
= "'Rt, 'TImmCmpa";
716 switch (instr
->Mask(CompareBranchMask
)) {
718 case CBZ_x
: mnemonic
= "cbz"; break;
720 case CBNZ_x
: mnemonic
= "cbnz"; break;
721 default: VIXL_UNREACHABLE();
723 Format(instr
, mnemonic
, form
);
727 void Disassembler::VisitTestBranch(const Instruction
* instr
) {
728 const char *mnemonic
= "";
729 // If the top bit of the immediate is clear, the tested register is
730 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
731 // encoded in bit 31 of the instruction, we can reuse the Rt form, which
732 // uses bit 31 (normally "sf") to choose the register size.
733 const char *form
= "'Rt, 'IS, 'TImmTest";
735 switch (instr
->Mask(TestBranchMask
)) {
736 case TBZ
: mnemonic
= "tbz"; break;
737 case TBNZ
: mnemonic
= "tbnz"; break;
738 default: VIXL_UNREACHABLE();
740 Format(instr
, mnemonic
, form
);
744 void Disassembler::VisitMoveWideImmediate(const Instruction
* instr
) {
745 const char *mnemonic
= "";
746 const char *form
= "'Rd, 'IMoveImm";
748 // Print the shift separately for movk, to make it clear which half word will
749 // be overwritten. Movn and movz print the computed immediate, which includes
750 // shift calculation.
751 switch (instr
->Mask(MoveWideImmediateMask
)) {
754 if ((instr
->ImmMoveWide()) || (instr
->ShiftMoveWide() == 0)) {
755 if ((instr
->SixtyFourBits() == 0) && (instr
->ImmMoveWide() == 0xffff)) {
759 form
= "'Rd, 'IMoveNeg";
767 if ((instr
->ImmMoveWide()) || (instr
->ShiftMoveWide() == 0))
773 case MOVK_x
: mnemonic
= "movk"; form
= "'Rd, 'IMoveLSL"; break;
774 default: VIXL_UNREACHABLE();
776 Format(instr
, mnemonic
, form
);
780 #define LOAD_STORE_LIST(V) \
781 V(STRB_w, "strb", "'Wt") \
782 V(STRH_w, "strh", "'Wt") \
783 V(STR_w, "str", "'Wt") \
784 V(STR_x, "str", "'Xt") \
785 V(LDRB_w, "ldrb", "'Wt") \
786 V(LDRH_w, "ldrh", "'Wt") \
787 V(LDR_w, "ldr", "'Wt") \
788 V(LDR_x, "ldr", "'Xt") \
789 V(LDRSB_x, "ldrsb", "'Xt") \
790 V(LDRSH_x, "ldrsh", "'Xt") \
791 V(LDRSW_x, "ldrsw", "'Xt") \
792 V(LDRSB_w, "ldrsb", "'Wt") \
793 V(LDRSH_w, "ldrsh", "'Wt") \
794 V(STR_b, "str", "'Bt") \
795 V(STR_h, "str", "'Ht") \
796 V(STR_s, "str", "'St") \
797 V(STR_d, "str", "'Dt") \
798 V(LDR_b, "ldr", "'Bt") \
799 V(LDR_h, "ldr", "'Ht") \
800 V(LDR_s, "ldr", "'St") \
801 V(LDR_d, "ldr", "'Dt") \
802 V(STR_q, "str", "'Qt") \
803 V(LDR_q, "ldr", "'Qt")
805 void Disassembler::VisitLoadStorePreIndex(const Instruction
* instr
) {
806 const char *mnemonic
= "unimplemented";
807 const char *form
= "(LoadStorePreIndex)";
809 switch (instr
->Mask(LoadStorePreIndexMask
)) {
810 #define LS_PREINDEX(A, B, C) \
811 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
812 LOAD_STORE_LIST(LS_PREINDEX
)
815 Format(instr
, mnemonic
, form
);
819 void Disassembler::VisitLoadStorePostIndex(const Instruction
* instr
) {
820 const char *mnemonic
= "unimplemented";
821 const char *form
= "(LoadStorePostIndex)";
823 switch (instr
->Mask(LoadStorePostIndexMask
)) {
824 #define LS_POSTINDEX(A, B, C) \
825 case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
826 LOAD_STORE_LIST(LS_POSTINDEX
)
829 Format(instr
, mnemonic
, form
);
833 void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction
* instr
) {
834 const char *mnemonic
= "unimplemented";
835 const char *form
= "(LoadStoreUnsignedOffset)";
837 switch (instr
->Mask(LoadStoreUnsignedOffsetMask
)) {
838 #define LS_UNSIGNEDOFFSET(A, B, C) \
839 case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
840 LOAD_STORE_LIST(LS_UNSIGNEDOFFSET
)
841 #undef LS_UNSIGNEDOFFSET
842 case PRFM_unsigned
: mnemonic
= "prfm"; form
= "'PrefOp, ['Xns'ILU]";
844 Format(instr
, mnemonic
, form
);
848 void Disassembler::VisitLoadStoreRegisterOffset(const Instruction
* instr
) {
849 const char *mnemonic
= "unimplemented";
850 const char *form
= "(LoadStoreRegisterOffset)";
852 switch (instr
->Mask(LoadStoreRegisterOffsetMask
)) {
853 #define LS_REGISTEROFFSET(A, B, C) \
854 case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
855 LOAD_STORE_LIST(LS_REGISTEROFFSET
)
856 #undef LS_REGISTEROFFSET
857 case PRFM_reg
: mnemonic
= "prfm"; form
= "'PrefOp, ['Xns, 'Offsetreg]";
859 Format(instr
, mnemonic
, form
);
863 void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction
* instr
) {
864 const char *mnemonic
= "unimplemented";
865 const char *form
= "'Wt, ['Xns'ILS]";
866 const char *form_x
= "'Xt, ['Xns'ILS]";
867 const char *form_b
= "'Bt, ['Xns'ILS]";
868 const char *form_h
= "'Ht, ['Xns'ILS]";
869 const char *form_s
= "'St, ['Xns'ILS]";
870 const char *form_d
= "'Dt, ['Xns'ILS]";
871 const char *form_q
= "'Qt, ['Xns'ILS]";
872 const char *form_prefetch
= "'PrefOp, ['Xns'ILS]";
874 switch (instr
->Mask(LoadStoreUnscaledOffsetMask
)) {
875 case STURB_w
: mnemonic
= "sturb"; break;
876 case STURH_w
: mnemonic
= "sturh"; break;
877 case STUR_w
: mnemonic
= "stur"; break;
878 case STUR_x
: mnemonic
= "stur"; form
= form_x
; break;
879 case STUR_b
: mnemonic
= "stur"; form
= form_b
; break;
880 case STUR_h
: mnemonic
= "stur"; form
= form_h
; break;
881 case STUR_s
: mnemonic
= "stur"; form
= form_s
; break;
882 case STUR_d
: mnemonic
= "stur"; form
= form_d
; break;
883 case STUR_q
: mnemonic
= "stur"; form
= form_q
; break;
884 case LDURB_w
: mnemonic
= "ldurb"; break;
885 case LDURH_w
: mnemonic
= "ldurh"; break;
886 case LDUR_w
: mnemonic
= "ldur"; break;
887 case LDUR_x
: mnemonic
= "ldur"; form
= form_x
; break;
888 case LDUR_b
: mnemonic
= "ldur"; form
= form_b
; break;
889 case LDUR_h
: mnemonic
= "ldur"; form
= form_h
; break;
890 case LDUR_s
: mnemonic
= "ldur"; form
= form_s
; break;
891 case LDUR_d
: mnemonic
= "ldur"; form
= form_d
; break;
892 case LDUR_q
: mnemonic
= "ldur"; form
= form_q
; break;
893 case LDURSB_x
: form
= form_x
; VIXL_FALLTHROUGH();
894 case LDURSB_w
: mnemonic
= "ldursb"; break;
895 case LDURSH_x
: form
= form_x
; VIXL_FALLTHROUGH();
896 case LDURSH_w
: mnemonic
= "ldursh"; break;
897 case LDURSW_x
: mnemonic
= "ldursw"; form
= form_x
; break;
898 case PRFUM
: mnemonic
= "prfum"; form
= form_prefetch
; break;
899 default: form
= "(LoadStoreUnscaledOffset)";
901 Format(instr
, mnemonic
, form
);
905 void Disassembler::VisitLoadLiteral(const Instruction
* instr
) {
906 const char *mnemonic
= "ldr";
907 const char *form
= "(LoadLiteral)";
909 switch (instr
->Mask(LoadLiteralMask
)) {
910 case LDR_w_lit
: form
= "'Wt, 'ILLiteral 'LValue"; break;
911 case LDR_x_lit
: form
= "'Xt, 'ILLiteral 'LValue"; break;
912 case LDR_s_lit
: form
= "'St, 'ILLiteral 'LValue"; break;
913 case LDR_d_lit
: form
= "'Dt, 'ILLiteral 'LValue"; break;
914 case LDR_q_lit
: form
= "'Qt, 'ILLiteral 'LValue"; break;
917 form
= "'Xt, 'ILLiteral 'LValue";
922 form
= "'PrefOp, 'ILLiteral 'LValue";
925 default: mnemonic
= "unimplemented";
927 Format(instr
, mnemonic
, form
);
931 #define LOAD_STORE_PAIR_LIST(V) \
932 V(STP_w, "stp", "'Wt, 'Wt2", "2") \
933 V(LDP_w, "ldp", "'Wt, 'Wt2", "2") \
934 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "2") \
935 V(STP_x, "stp", "'Xt, 'Xt2", "3") \
936 V(LDP_x, "ldp", "'Xt, 'Xt2", "3") \
937 V(STP_s, "stp", "'St, 'St2", "2") \
938 V(LDP_s, "ldp", "'St, 'St2", "2") \
939 V(STP_d, "stp", "'Dt, 'Dt2", "3") \
940 V(LDP_d, "ldp", "'Dt, 'Dt2", "3") \
941 V(LDP_q, "ldp", "'Qt, 'Qt2", "4") \
942 V(STP_q, "stp", "'Qt, 'Qt2", "4")
944 void Disassembler::VisitLoadStorePairPostIndex(const Instruction
* instr
) {
945 const char *mnemonic
= "unimplemented";
946 const char *form
= "(LoadStorePairPostIndex)";
948 switch (instr
->Mask(LoadStorePairPostIndexMask
)) {
949 #define LSP_POSTINDEX(A, B, C, D) \
950 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
951 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX
)
954 Format(instr
, mnemonic
, form
);
958 void Disassembler::VisitLoadStorePairPreIndex(const Instruction
* instr
) {
959 const char *mnemonic
= "unimplemented";
960 const char *form
= "(LoadStorePairPreIndex)";
962 switch (instr
->Mask(LoadStorePairPreIndexMask
)) {
963 #define LSP_PREINDEX(A, B, C, D) \
964 case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
965 LOAD_STORE_PAIR_LIST(LSP_PREINDEX
)
968 Format(instr
, mnemonic
, form
);
972 void Disassembler::VisitLoadStorePairOffset(const Instruction
* instr
) {
973 const char *mnemonic
= "unimplemented";
974 const char *form
= "(LoadStorePairOffset)";
976 switch (instr
->Mask(LoadStorePairOffsetMask
)) {
977 #define LSP_OFFSET(A, B, C, D) \
978 case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
979 LOAD_STORE_PAIR_LIST(LSP_OFFSET
)
982 Format(instr
, mnemonic
, form
);
986 void Disassembler::VisitLoadStorePairNonTemporal(const Instruction
* instr
) {
987 const char *mnemonic
= "unimplemented";
990 switch (instr
->Mask(LoadStorePairNonTemporalMask
)) {
991 case STNP_w
: mnemonic
= "stnp"; form
= "'Wt, 'Wt2, ['Xns'ILP2]"; break;
992 case LDNP_w
: mnemonic
= "ldnp"; form
= "'Wt, 'Wt2, ['Xns'ILP2]"; break;
993 case STNP_x
: mnemonic
= "stnp"; form
= "'Xt, 'Xt2, ['Xns'ILP3]"; break;
994 case LDNP_x
: mnemonic
= "ldnp"; form
= "'Xt, 'Xt2, ['Xns'ILP3]"; break;
995 case STNP_s
: mnemonic
= "stnp"; form
= "'St, 'St2, ['Xns'ILP2]"; break;
996 case LDNP_s
: mnemonic
= "ldnp"; form
= "'St, 'St2, ['Xns'ILP2]"; break;
997 case STNP_d
: mnemonic
= "stnp"; form
= "'Dt, 'Dt2, ['Xns'ILP3]"; break;
998 case LDNP_d
: mnemonic
= "ldnp"; form
= "'Dt, 'Dt2, ['Xns'ILP3]"; break;
999 case STNP_q
: mnemonic
= "stnp"; form
= "'Qt, 'Qt2, ['Xns'ILP4]"; break;
1000 case LDNP_q
: mnemonic
= "ldnp"; form
= "'Qt, 'Qt2, ['Xns'ILP4]"; break;
1001 default: form
= "(LoadStorePairNonTemporal)";
1003 Format(instr
, mnemonic
, form
);
1007 void Disassembler::VisitLoadStoreExclusive(const Instruction
* instr
) {
1008 const char *mnemonic
= "unimplemented";
1011 switch (instr
->Mask(LoadStoreExclusiveMask
)) {
1012 case STXRB_w
: mnemonic
= "stxrb"; form
= "'Ws, 'Wt, ['Xns]"; break;
1013 case STXRH_w
: mnemonic
= "stxrh"; form
= "'Ws, 'Wt, ['Xns]"; break;
1014 case STXR_w
: mnemonic
= "stxr"; form
= "'Ws, 'Wt, ['Xns]"; break;
1015 case STXR_x
: mnemonic
= "stxr"; form
= "'Ws, 'Xt, ['Xns]"; break;
1016 case LDXRB_w
: mnemonic
= "ldxrb"; form
= "'Wt, ['Xns]"; break;
1017 case LDXRH_w
: mnemonic
= "ldxrh"; form
= "'Wt, ['Xns]"; break;
1018 case LDXR_w
: mnemonic
= "ldxr"; form
= "'Wt, ['Xns]"; break;
1019 case LDXR_x
: mnemonic
= "ldxr"; form
= "'Xt, ['Xns]"; break;
1020 case STXP_w
: mnemonic
= "stxp"; form
= "'Ws, 'Wt, 'Wt2, ['Xns]"; break;
1021 case STXP_x
: mnemonic
= "stxp"; form
= "'Ws, 'Xt, 'Xt2, ['Xns]"; break;
1022 case LDXP_w
: mnemonic
= "ldxp"; form
= "'Wt, 'Wt2, ['Xns]"; break;
1023 case LDXP_x
: mnemonic
= "ldxp"; form
= "'Xt, 'Xt2, ['Xns]"; break;
1024 case STLXRB_w
: mnemonic
= "stlxrb"; form
= "'Ws, 'Wt, ['Xns]"; break;
1025 case STLXRH_w
: mnemonic
= "stlxrh"; form
= "'Ws, 'Wt, ['Xns]"; break;
1026 case STLXR_w
: mnemonic
= "stlxr"; form
= "'Ws, 'Wt, ['Xns]"; break;
1027 case STLXR_x
: mnemonic
= "stlxr"; form
= "'Ws, 'Xt, ['Xns]"; break;
1028 case LDAXRB_w
: mnemonic
= "ldaxrb"; form
= "'Wt, ['Xns]"; break;
1029 case LDAXRH_w
: mnemonic
= "ldaxrh"; form
= "'Wt, ['Xns]"; break;
1030 case LDAXR_w
: mnemonic
= "ldaxr"; form
= "'Wt, ['Xns]"; break;
1031 case LDAXR_x
: mnemonic
= "ldaxr"; form
= "'Xt, ['Xns]"; break;
1032 case STLXP_w
: mnemonic
= "stlxp"; form
= "'Ws, 'Wt, 'Wt2, ['Xns]"; break;
1033 case STLXP_x
: mnemonic
= "stlxp"; form
= "'Ws, 'Xt, 'Xt2, ['Xns]"; break;
1034 case LDAXP_w
: mnemonic
= "ldaxp"; form
= "'Wt, 'Wt2, ['Xns]"; break;
1035 case LDAXP_x
: mnemonic
= "ldaxp"; form
= "'Xt, 'Xt2, ['Xns]"; break;
1036 case STLRB_w
: mnemonic
= "stlrb"; form
= "'Wt, ['Xns]"; break;
1037 case STLRH_w
: mnemonic
= "stlrh"; form
= "'Wt, ['Xns]"; break;
1038 case STLR_w
: mnemonic
= "stlr"; form
= "'Wt, ['Xns]"; break;
1039 case STLR_x
: mnemonic
= "stlr"; form
= "'Xt, ['Xns]"; break;
1040 case LDARB_w
: mnemonic
= "ldarb"; form
= "'Wt, ['Xns]"; break;
1041 case LDARH_w
: mnemonic
= "ldarh"; form
= "'Wt, ['Xns]"; break;
1042 case LDAR_w
: mnemonic
= "ldar"; form
= "'Wt, ['Xns]"; break;
1043 case LDAR_x
: mnemonic
= "ldar"; form
= "'Xt, ['Xns]"; break;
1044 default: form
= "(LoadStoreExclusive)";
1046 Format(instr
, mnemonic
, form
);
1050 void Disassembler::VisitFPCompare(const Instruction
* instr
) {
1051 const char *mnemonic
= "unimplemented";
1052 const char *form
= "'Fn, 'Fm";
1053 const char *form_zero
= "'Fn, #0.0";
1055 switch (instr
->Mask(FPCompareMask
)) {
1057 case FCMP_d_zero
: form
= form_zero
; VIXL_FALLTHROUGH();
1059 case FCMP_d
: mnemonic
= "fcmp"; break;
1061 case FCMPE_d_zero
: form
= form_zero
; VIXL_FALLTHROUGH();
1063 case FCMPE_d
: mnemonic
= "fcmpe"; break;
1064 default: form
= "(FPCompare)";
1066 Format(instr
, mnemonic
, form
);
1070 void Disassembler::VisitFPConditionalCompare(const Instruction
* instr
) {
1071 const char *mnemonic
= "unmplemented";
1072 const char *form
= "'Fn, 'Fm, 'INzcv, 'Cond";
1074 switch (instr
->Mask(FPConditionalCompareMask
)) {
1076 case FCCMP_d
: mnemonic
= "fccmp"; break;
1078 case FCCMPE_d
: mnemonic
= "fccmpe"; break;
1079 default: form
= "(FPConditionalCompare)";
1081 Format(instr
, mnemonic
, form
);
1085 void Disassembler::VisitFPConditionalSelect(const Instruction
* instr
) {
1086 const char *mnemonic
= "";
1087 const char *form
= "'Fd, 'Fn, 'Fm, 'Cond";
1089 switch (instr
->Mask(FPConditionalSelectMask
)) {
1091 case FCSEL_d
: mnemonic
= "fcsel"; break;
1092 default: VIXL_UNREACHABLE();
1094 Format(instr
, mnemonic
, form
);
1098 void Disassembler::VisitFPDataProcessing1Source(const Instruction
* instr
) {
1099 const char *mnemonic
= "unimplemented";
1100 const char *form
= "'Fd, 'Fn";
1102 switch (instr
->Mask(FPDataProcessing1SourceMask
)) {
1103 #define FORMAT(A, B) \
1105 case A##_d: mnemonic = B; break;
1106 FORMAT(FMOV
, "fmov");
1107 FORMAT(FABS
, "fabs");
1108 FORMAT(FNEG
, "fneg");
1109 FORMAT(FSQRT
, "fsqrt");
1110 FORMAT(FRINTN
, "frintn");
1111 FORMAT(FRINTP
, "frintp");
1112 FORMAT(FRINTM
, "frintm");
1113 FORMAT(FRINTZ
, "frintz");
1114 FORMAT(FRINTA
, "frinta");
1115 FORMAT(FRINTX
, "frintx");
1116 FORMAT(FRINTI
, "frinti");
1118 case FCVT_ds
: mnemonic
= "fcvt"; form
= "'Dd, 'Sn"; break;
1119 case FCVT_sd
: mnemonic
= "fcvt"; form
= "'Sd, 'Dn"; break;
1120 case FCVT_hs
: mnemonic
= "fcvt"; form
= "'Hd, 'Sn"; break;
1121 case FCVT_sh
: mnemonic
= "fcvt"; form
= "'Sd, 'Hn"; break;
1122 case FCVT_dh
: mnemonic
= "fcvt"; form
= "'Dd, 'Hn"; break;
1123 case FCVT_hd
: mnemonic
= "fcvt"; form
= "'Hd, 'Dn"; break;
1124 default: form
= "(FPDataProcessing1Source)";
1126 Format(instr
, mnemonic
, form
);
1130 void Disassembler::VisitFPDataProcessing2Source(const Instruction
* instr
) {
1131 const char *mnemonic
= "";
1132 const char *form
= "'Fd, 'Fn, 'Fm";
1134 switch (instr
->Mask(FPDataProcessing2SourceMask
)) {
1135 #define FORMAT(A, B) \
1137 case A##_d: mnemonic = B; break;
1138 FORMAT(FMUL
, "fmul");
1139 FORMAT(FDIV
, "fdiv");
1140 FORMAT(FADD
, "fadd");
1141 FORMAT(FSUB
, "fsub");
1142 FORMAT(FMAX
, "fmax");
1143 FORMAT(FMIN
, "fmin");
1144 FORMAT(FMAXNM
, "fmaxnm");
1145 FORMAT(FMINNM
, "fminnm");
1146 FORMAT(FNMUL
, "fnmul");
1148 default: VIXL_UNREACHABLE();
1150 Format(instr
, mnemonic
, form
);
1154 void Disassembler::VisitFPDataProcessing3Source(const Instruction
* instr
) {
1155 const char *mnemonic
= "";
1156 const char *form
= "'Fd, 'Fn, 'Fm, 'Fa";
1158 switch (instr
->Mask(FPDataProcessing3SourceMask
)) {
1159 #define FORMAT(A, B) \
1161 case A##_d: mnemonic = B; break;
1162 FORMAT(FMADD
, "fmadd");
1163 FORMAT(FMSUB
, "fmsub");
1164 FORMAT(FNMADD
, "fnmadd");
1165 FORMAT(FNMSUB
, "fnmsub");
1167 default: VIXL_UNREACHABLE();
1169 Format(instr
, mnemonic
, form
);
1173 void Disassembler::VisitFPImmediate(const Instruction
* instr
) {
1174 const char *mnemonic
= "";
1175 const char *form
= "(FPImmediate)";
1177 switch (instr
->Mask(FPImmediateMask
)) {
1178 case FMOV_s_imm
: mnemonic
= "fmov"; form
= "'Sd, 'IFPSingle"; break;
1179 case FMOV_d_imm
: mnemonic
= "fmov"; form
= "'Dd, 'IFPDouble"; break;
1180 default: VIXL_UNREACHABLE();
1182 Format(instr
, mnemonic
, form
);
1186 void Disassembler::VisitFPIntegerConvert(const Instruction
* instr
) {
1187 const char *mnemonic
= "unimplemented";
1188 const char *form
= "(FPIntegerConvert)";
1189 const char *form_rf
= "'Rd, 'Fn";
1190 const char *form_fr
= "'Fd, 'Rn";
1192 switch (instr
->Mask(FPIntegerConvertMask
)) {
1194 case FMOV_xd
: mnemonic
= "fmov"; form
= form_rf
; break;
1196 case FMOV_dx
: mnemonic
= "fmov"; form
= form_fr
; break;
1197 case FMOV_d1_x
: mnemonic
= "fmov"; form
= "'Vd.D[1], 'Rn"; break;
1198 case FMOV_x_d1
: mnemonic
= "fmov"; form
= "'Rd, 'Vn.D[1]"; break;
1202 case FCVTAS_xd
: mnemonic
= "fcvtas"; form
= form_rf
; break;
1206 case FCVTAU_xd
: mnemonic
= "fcvtau"; form
= form_rf
; break;
1210 case FCVTMS_xd
: mnemonic
= "fcvtms"; form
= form_rf
; break;
1214 case FCVTMU_xd
: mnemonic
= "fcvtmu"; form
= form_rf
; break;
1218 case FCVTNS_xd
: mnemonic
= "fcvtns"; form
= form_rf
; break;
1222 case FCVTNU_xd
: mnemonic
= "fcvtnu"; form
= form_rf
; break;
1226 case FCVTZU_xs
: mnemonic
= "fcvtzu"; form
= form_rf
; break;
1230 case FCVTZS_ws
: mnemonic
= "fcvtzs"; form
= form_rf
; break;
1234 case FCVTPU_xs
: mnemonic
= "fcvtpu"; form
= form_rf
; break;
1238 case FCVTPS_ws
: mnemonic
= "fcvtps"; form
= form_rf
; break;
1242 case SCVTF_dx
: mnemonic
= "scvtf"; form
= form_fr
; break;
1246 case UCVTF_dx
: mnemonic
= "ucvtf"; form
= form_fr
; break;
1248 Format(instr
, mnemonic
, form
);
1252 void Disassembler::VisitFPFixedPointConvert(const Instruction
* instr
) {
1253 const char *mnemonic
= "";
1254 const char *form
= "'Rd, 'Fn, 'IFPFBits";
1255 const char *form_fr
= "'Fd, 'Rn, 'IFPFBits";
1257 switch (instr
->Mask(FPFixedPointConvertMask
)) {
1258 case FCVTZS_ws_fixed
:
1259 case FCVTZS_xs_fixed
:
1260 case FCVTZS_wd_fixed
:
1261 case FCVTZS_xd_fixed
: mnemonic
= "fcvtzs"; break;
1262 case FCVTZU_ws_fixed
:
1263 case FCVTZU_xs_fixed
:
1264 case FCVTZU_wd_fixed
:
1265 case FCVTZU_xd_fixed
: mnemonic
= "fcvtzu"; break;
1266 case SCVTF_sw_fixed
:
1267 case SCVTF_sx_fixed
:
1268 case SCVTF_dw_fixed
:
1269 case SCVTF_dx_fixed
: mnemonic
= "scvtf"; form
= form_fr
; break;
1270 case UCVTF_sw_fixed
:
1271 case UCVTF_sx_fixed
:
1272 case UCVTF_dw_fixed
:
1273 case UCVTF_dx_fixed
: mnemonic
= "ucvtf"; form
= form_fr
; break;
1274 default: VIXL_UNREACHABLE();
1276 Format(instr
, mnemonic
, form
);
1280 void Disassembler::VisitSystem(const Instruction
* instr
) {
1281 // Some system instructions hijack their Op and Cp fields to represent a
1282 // range of immediates instead of indicating a different instruction. This
1283 // makes the decoding tricky.
1284 const char *mnemonic
= "unimplemented";
1285 const char *form
= "(System)";
1287 if (instr
->Mask(SystemExclusiveMonitorFMask
) == SystemExclusiveMonitorFixed
) {
1288 switch (instr
->Mask(SystemExclusiveMonitorMask
)) {
1291 form
= (instr
->CRm() == 0xf) ? NULL
: "'IX";
1295 } else if (instr
->Mask(SystemSysRegFMask
) == SystemSysRegFixed
) {
1296 switch (instr
->Mask(SystemSysRegMask
)) {
1299 switch (instr
->ImmSystemRegister()) {
1300 case NZCV
: form
= "'Xt, nzcv"; break;
1301 case FPCR
: form
= "'Xt, fpcr"; break;
1302 default: form
= "'Xt, (unknown)"; break;
1308 switch (instr
->ImmSystemRegister()) {
1309 case NZCV
: form
= "nzcv, 'Xt"; break;
1310 case FPCR
: form
= "fpcr, 'Xt"; break;
1311 default: form
= "(unknown), 'Xt"; break;
1316 } else if (instr
->Mask(SystemHintFMask
) == SystemHintFixed
) {
1317 switch (instr
->ImmHint()) {
1324 } else if (instr
->Mask(MemBarrierFMask
) == MemBarrierFixed
) {
1325 switch (instr
->Mask(MemBarrierMask
)) {
1342 } else if (instr
->Mask(SystemSysFMask
) == SystemSysFixed
) {
1343 switch (instr
->SysOp()) {
1358 form
= "civac, 'Xt";
1366 if (instr
->Rt() == 31) {
1367 form
= "'G1, 'Kn, 'Km, 'G2";
1369 form
= "'G1, 'Kn, 'Km, 'G2, 'Xt";
1374 Format(instr
, mnemonic
, form
);
1378 void Disassembler::VisitException(const Instruction
* instr
) {
1379 const char *mnemonic
= "unimplemented";
1380 const char *form
= "'IDebug";
1382 switch (instr
->Mask(ExceptionMask
)) {
1383 case HLT
: mnemonic
= "hlt"; break;
1384 case BRK
: mnemonic
= "brk"; break;
1385 case SVC
: mnemonic
= "svc"; break;
1386 case HVC
: mnemonic
= "hvc"; break;
1387 case SMC
: mnemonic
= "smc"; break;
1388 case DCPS1
: mnemonic
= "dcps1"; form
= "{'IDebug}"; break;
1389 case DCPS2
: mnemonic
= "dcps2"; form
= "{'IDebug}"; break;
1390 case DCPS3
: mnemonic
= "dcps3"; form
= "{'IDebug}"; break;
1391 default: form
= "(Exception)";
1393 Format(instr
, mnemonic
, form
);
1397 void Disassembler::VisitCrypto2RegSHA(const Instruction
* instr
) {
1398 VisitUnimplemented(instr
);
1402 void Disassembler::VisitCrypto3RegSHA(const Instruction
* instr
) {
1403 VisitUnimplemented(instr
);
1407 void Disassembler::VisitCryptoAES(const Instruction
* instr
) {
1408 VisitUnimplemented(instr
);
1412 void Disassembler::VisitNEON2RegMisc(const Instruction
* instr
) {
1413 const char *mnemonic
= "unimplemented";
1414 const char *form
= "'Vd.%s, 'Vn.%s";
1415 const char *form_cmp_zero
= "'Vd.%s, 'Vn.%s, #0";
1416 const char *form_fcmp_zero
= "'Vd.%s, 'Vn.%s, #0.0";
1417 NEONFormatDecoder
nfd(instr
);
1419 static const NEONFormatMap map_lp_ta
= {
1420 {23, 22, 30}, {NF_4H
, NF_8H
, NF_2S
, NF_4S
, NF_1D
, NF_2D
}
1423 static const NEONFormatMap map_cvt_ta
= {
1424 {22}, {NF_4S
, NF_2D
}
1427 static const NEONFormatMap map_cvt_tb
= {
1428 {22, 30}, {NF_4H
, NF_8H
, NF_2S
, NF_4S
}
1431 if (instr
->Mask(NEON2RegMiscOpcode
) <= NEON_NEG_opcode
) {
1432 // These instructions all use a two bit size field, except NOT and RBIT,
1433 // which use the field to encode the operation.
1434 switch (instr
->Mask(NEON2RegMiscMask
)) {
1435 case NEON_REV64
: mnemonic
= "rev64"; break;
1436 case NEON_REV32
: mnemonic
= "rev32"; break;
1437 case NEON_REV16
: mnemonic
= "rev16"; break;
1439 mnemonic
= "saddlp";
1440 nfd
.SetFormatMap(0, &map_lp_ta
);
1443 mnemonic
= "uaddlp";
1444 nfd
.SetFormatMap(0, &map_lp_ta
);
1446 case NEON_SUQADD
: mnemonic
= "suqadd"; break;
1447 case NEON_USQADD
: mnemonic
= "usqadd"; break;
1448 case NEON_CLS
: mnemonic
= "cls"; break;
1449 case NEON_CLZ
: mnemonic
= "clz"; break;
1450 case NEON_CNT
: mnemonic
= "cnt"; break;
1452 mnemonic
= "sadalp";
1453 nfd
.SetFormatMap(0, &map_lp_ta
);
1456 mnemonic
= "uadalp";
1457 nfd
.SetFormatMap(0, &map_lp_ta
);
1459 case NEON_SQABS
: mnemonic
= "sqabs"; break;
1460 case NEON_SQNEG
: mnemonic
= "sqneg"; break;
1461 case NEON_CMGT_zero
: mnemonic
= "cmgt"; form
= form_cmp_zero
; break;
1462 case NEON_CMGE_zero
: mnemonic
= "cmge"; form
= form_cmp_zero
; break;
1463 case NEON_CMEQ_zero
: mnemonic
= "cmeq"; form
= form_cmp_zero
; break;
1464 case NEON_CMLE_zero
: mnemonic
= "cmle"; form
= form_cmp_zero
; break;
1465 case NEON_CMLT_zero
: mnemonic
= "cmlt"; form
= form_cmp_zero
; break;
1466 case NEON_ABS
: mnemonic
= "abs"; break;
1467 case NEON_NEG
: mnemonic
= "neg"; break;
1469 switch (instr
->FPType()) {
1470 case 0: mnemonic
= "mvn"; break;
1471 case 1: mnemonic
= "rbit"; break;
1472 default: form
= "(NEON2RegMisc)";
1474 nfd
.SetFormatMaps(nfd
.LogicalFormatMap());
1478 // These instructions all use a one bit size field, except XTN, SQXTUN,
1479 // SHLL, SQXTN and UQXTN, which use a two bit size field.
1480 nfd
.SetFormatMaps(nfd
.FPFormatMap());
1481 switch (instr
->Mask(NEON2RegMiscFPMask
)) {
1482 case NEON_FABS
: mnemonic
= "fabs"; break;
1483 case NEON_FNEG
: mnemonic
= "fneg"; break;
1485 mnemonic
= instr
->Mask(NEON_Q
) ? "fcvtn2" : "fcvtn";
1486 nfd
.SetFormatMap(0, &map_cvt_tb
);
1487 nfd
.SetFormatMap(1, &map_cvt_ta
);
1490 mnemonic
= instr
->Mask(NEON_Q
) ? "fcvtxn2" : "fcvtxn";
1491 nfd
.SetFormatMap(0, &map_cvt_tb
);
1492 nfd
.SetFormatMap(1, &map_cvt_ta
);
1495 mnemonic
= instr
->Mask(NEON_Q
) ? "fcvtl2" : "fcvtl";
1496 nfd
.SetFormatMap(0, &map_cvt_ta
);
1497 nfd
.SetFormatMap(1, &map_cvt_tb
);
1499 case NEON_FRINTN
: mnemonic
= "frintn"; break;
1500 case NEON_FRINTA
: mnemonic
= "frinta"; break;
1501 case NEON_FRINTP
: mnemonic
= "frintp"; break;
1502 case NEON_FRINTM
: mnemonic
= "frintm"; break;
1503 case NEON_FRINTX
: mnemonic
= "frintx"; break;
1504 case NEON_FRINTZ
: mnemonic
= "frintz"; break;
1505 case NEON_FRINTI
: mnemonic
= "frinti"; break;
1506 case NEON_FCVTNS
: mnemonic
= "fcvtns"; break;
1507 case NEON_FCVTNU
: mnemonic
= "fcvtnu"; break;
1508 case NEON_FCVTPS
: mnemonic
= "fcvtps"; break;
1509 case NEON_FCVTPU
: mnemonic
= "fcvtpu"; break;
1510 case NEON_FCVTMS
: mnemonic
= "fcvtms"; break;
1511 case NEON_FCVTMU
: mnemonic
= "fcvtmu"; break;
1512 case NEON_FCVTZS
: mnemonic
= "fcvtzs"; break;
1513 case NEON_FCVTZU
: mnemonic
= "fcvtzu"; break;
1514 case NEON_FCVTAS
: mnemonic
= "fcvtas"; break;
1515 case NEON_FCVTAU
: mnemonic
= "fcvtau"; break;
1516 case NEON_FSQRT
: mnemonic
= "fsqrt"; break;
1517 case NEON_SCVTF
: mnemonic
= "scvtf"; break;
1518 case NEON_UCVTF
: mnemonic
= "ucvtf"; break;
1519 case NEON_URSQRTE
: mnemonic
= "ursqrte"; break;
1520 case NEON_URECPE
: mnemonic
= "urecpe"; break;
1521 case NEON_FRSQRTE
: mnemonic
= "frsqrte"; break;
1522 case NEON_FRECPE
: mnemonic
= "frecpe"; break;
1523 case NEON_FCMGT_zero
: mnemonic
= "fcmgt"; form
= form_fcmp_zero
; break;
1524 case NEON_FCMGE_zero
: mnemonic
= "fcmge"; form
= form_fcmp_zero
; break;
1525 case NEON_FCMEQ_zero
: mnemonic
= "fcmeq"; form
= form_fcmp_zero
; break;
1526 case NEON_FCMLE_zero
: mnemonic
= "fcmle"; form
= form_fcmp_zero
; break;
1527 case NEON_FCMLT_zero
: mnemonic
= "fcmlt"; form
= form_fcmp_zero
; break;
1529 if ((NEON_XTN_opcode
<= instr
->Mask(NEON2RegMiscOpcode
)) &&
1530 (instr
->Mask(NEON2RegMiscOpcode
) <= NEON_UQXTN_opcode
)) {
1531 nfd
.SetFormatMap(0, nfd
.IntegerFormatMap());
1532 nfd
.SetFormatMap(1, nfd
.LongIntegerFormatMap());
1534 switch (instr
->Mask(NEON2RegMiscMask
)) {
1535 case NEON_XTN
: mnemonic
= "xtn"; break;
1536 case NEON_SQXTN
: mnemonic
= "sqxtn"; break;
1537 case NEON_UQXTN
: mnemonic
= "uqxtn"; break;
1538 case NEON_SQXTUN
: mnemonic
= "sqxtun"; break;
1541 nfd
.SetFormatMap(0, nfd
.LongIntegerFormatMap());
1542 nfd
.SetFormatMap(1, nfd
.IntegerFormatMap());
1543 switch (instr
->NEONSize()) {
1544 case 0: form
= "'Vd.%s, 'Vn.%s, #8"; break;
1545 case 1: form
= "'Vd.%s, 'Vn.%s, #16"; break;
1546 case 2: form
= "'Vd.%s, 'Vn.%s, #32"; break;
1547 default: form
= "(NEON2RegMisc)";
1550 Format(instr
, nfd
.Mnemonic(mnemonic
), nfd
.Substitute(form
));
1553 form
= "(NEON2RegMisc)";
1557 Format(instr
, mnemonic
, nfd
.Substitute(form
));
1561 void Disassembler::VisitNEON3Same(const Instruction
* instr
) {
1562 const char *mnemonic
= "unimplemented";
1563 const char *form
= "'Vd.%s, 'Vn.%s, 'Vm.%s";
1564 NEONFormatDecoder
nfd(instr
);
1566 if (instr
->Mask(NEON3SameLogicalFMask
) == NEON3SameLogicalFixed
) {
1567 switch (instr
->Mask(NEON3SameLogicalMask
)) {
1568 case NEON_AND
: mnemonic
= "and"; break;
1571 if (instr
->Rm() == instr
->Rn()) {
1573 form
= "'Vd.%s, 'Vn.%s";
1576 case NEON_ORN
: mnemonic
= "orn"; break;
1577 case NEON_EOR
: mnemonic
= "eor"; break;
1578 case NEON_BIC
: mnemonic
= "bic"; break;
1579 case NEON_BIF
: mnemonic
= "bif"; break;
1580 case NEON_BIT
: mnemonic
= "bit"; break;
1581 case NEON_BSL
: mnemonic
= "bsl"; break;
1582 default: form
= "(NEON3Same)";
1584 nfd
.SetFormatMaps(nfd
.LogicalFormatMap());
1586 static const char *mnemonics
[] = {
1587 "shadd", "uhadd", "shadd", "uhadd",
1588 "sqadd", "uqadd", "sqadd", "uqadd",
1589 "srhadd", "urhadd", "srhadd", "urhadd",
1590 NULL
, NULL
, NULL
, NULL
, // Handled by logical cases above.
1591 "shsub", "uhsub", "shsub", "uhsub",
1592 "sqsub", "uqsub", "sqsub", "uqsub",
1593 "cmgt", "cmhi", "cmgt", "cmhi",
1594 "cmge", "cmhs", "cmge", "cmhs",
1595 "sshl", "ushl", "sshl", "ushl",
1596 "sqshl", "uqshl", "sqshl", "uqshl",
1597 "srshl", "urshl", "srshl", "urshl",
1598 "sqrshl", "uqrshl", "sqrshl", "uqrshl",
1599 "smax", "umax", "smax", "umax",
1600 "smin", "umin", "smin", "umin",
1601 "sabd", "uabd", "sabd", "uabd",
1602 "saba", "uaba", "saba", "uaba",
1603 "add", "sub", "add", "sub",
1604 "cmtst", "cmeq", "cmtst", "cmeq",
1605 "mla", "mls", "mla", "mls",
1606 "mul", "pmul", "mul", "pmul",
1607 "smaxp", "umaxp", "smaxp", "umaxp",
1608 "sminp", "uminp", "sminp", "uminp",
1609 "sqdmulh", "sqrdmulh", "sqdmulh", "sqrdmulh",
1610 "addp", "unallocated", "addp", "unallocated",
1611 "fmaxnm", "fmaxnmp", "fminnm", "fminnmp",
1612 "fmla", "unallocated", "fmls", "unallocated",
1613 "fadd", "faddp", "fsub", "fabd",
1614 "fmulx", "fmul", "unallocated", "unallocated",
1615 "fcmeq", "fcmge", "unallocated", "fcmgt",
1616 "unallocated", "facge", "unallocated", "facgt",
1617 "fmax", "fmaxp", "fmin", "fminp",
1618 "frecps", "fdiv", "frsqrts", "unallocated"};
1620 // Operation is determined by the opcode bits (15-11), the top bit of
1621 // size (23) and the U bit (29).
1622 unsigned index
= (instr
->Bits(15, 11) << 2) | (instr
->Bit(23) << 1) |
1624 VIXL_ASSERT(index
< (sizeof(mnemonics
) / sizeof(mnemonics
[0])));
1625 mnemonic
= mnemonics
[index
];
1626 // Assert that index is not one of the previously handled logical
1628 VIXL_ASSERT(mnemonic
!= NULL
);
1630 if (instr
->Mask(NEON3SameFPFMask
) == NEON3SameFPFixed
) {
1631 nfd
.SetFormatMaps(nfd
.FPFormatMap());
1634 Format(instr
, mnemonic
, nfd
.Substitute(form
));
1638 void Disassembler::VisitNEON3Different(const Instruction
* instr
) {
1639 const char *mnemonic
= "unimplemented";
1640 const char *form
= "'Vd.%s, 'Vn.%s, 'Vm.%s";
1642 NEONFormatDecoder
nfd(instr
);
1643 nfd
.SetFormatMap(0, nfd
.LongIntegerFormatMap());
1645 // Ignore the Q bit. Appending a "2" suffix is handled later.
1646 switch (instr
->Mask(NEON3DifferentMask
) & ~NEON_Q
) {
1647 case NEON_PMULL
: mnemonic
= "pmull"; break;
1648 case NEON_SABAL
: mnemonic
= "sabal"; break;
1649 case NEON_SABDL
: mnemonic
= "sabdl"; break;
1650 case NEON_SADDL
: mnemonic
= "saddl"; break;
1651 case NEON_SMLAL
: mnemonic
= "smlal"; break;
1652 case NEON_SMLSL
: mnemonic
= "smlsl"; break;
1653 case NEON_SMULL
: mnemonic
= "smull"; break;
1654 case NEON_SSUBL
: mnemonic
= "ssubl"; break;
1655 case NEON_SQDMLAL
: mnemonic
= "sqdmlal"; break;
1656 case NEON_SQDMLSL
: mnemonic
= "sqdmlsl"; break;
1657 case NEON_SQDMULL
: mnemonic
= "sqdmull"; break;
1658 case NEON_UABAL
: mnemonic
= "uabal"; break;
1659 case NEON_UABDL
: mnemonic
= "uabdl"; break;
1660 case NEON_UADDL
: mnemonic
= "uaddl"; break;
1661 case NEON_UMLAL
: mnemonic
= "umlal"; break;
1662 case NEON_UMLSL
: mnemonic
= "umlsl"; break;
1663 case NEON_UMULL
: mnemonic
= "umull"; break;
1664 case NEON_USUBL
: mnemonic
= "usubl"; break;
1667 nfd
.SetFormatMap(1, nfd
.LongIntegerFormatMap());
1671 nfd
.SetFormatMap(1, nfd
.LongIntegerFormatMap());
1675 nfd
.SetFormatMap(1, nfd
.LongIntegerFormatMap());
1679 nfd
.SetFormatMap(1, nfd
.LongIntegerFormatMap());
1683 nfd
.SetFormatMaps(nfd
.LongIntegerFormatMap());
1684 nfd
.SetFormatMap(0, nfd
.IntegerFormatMap());
1687 mnemonic
= "raddhn";
1688 nfd
.SetFormatMaps(nfd
.LongIntegerFormatMap());
1689 nfd
.SetFormatMap(0, nfd
.IntegerFormatMap());
1692 mnemonic
= "rsubhn";
1693 nfd
.SetFormatMaps(nfd
.LongIntegerFormatMap());
1694 nfd
.SetFormatMap(0, nfd
.IntegerFormatMap());
1698 nfd
.SetFormatMaps(nfd
.LongIntegerFormatMap());
1699 nfd
.SetFormatMap(0, nfd
.IntegerFormatMap());
1701 default: form
= "(NEON3Different)";
1703 Format(instr
, nfd
.Mnemonic(mnemonic
), nfd
.Substitute(form
));
1707 void Disassembler::VisitNEONAcrossLanes(const Instruction
* instr
) {
1708 const char *mnemonic
= "unimplemented";
1709 const char *form
= "%sd, 'Vn.%s";
1711 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::ScalarFormatMap(),
1712 NEONFormatDecoder::IntegerFormatMap());
1714 if (instr
->Mask(NEONAcrossLanesFPFMask
) == NEONAcrossLanesFPFixed
) {
1715 nfd
.SetFormatMap(0, nfd
.FPScalarFormatMap());
1716 nfd
.SetFormatMap(1, nfd
.FPFormatMap());
1717 switch (instr
->Mask(NEONAcrossLanesFPMask
)) {
1718 case NEON_FMAXV
: mnemonic
= "fmaxv"; break;
1719 case NEON_FMINV
: mnemonic
= "fminv"; break;
1720 case NEON_FMAXNMV
: mnemonic
= "fmaxnmv"; break;
1721 case NEON_FMINNMV
: mnemonic
= "fminnmv"; break;
1722 default: form
= "(NEONAcrossLanes)"; break;
1724 } else if (instr
->Mask(NEONAcrossLanesFMask
) == NEONAcrossLanesFixed
) {
1725 switch (instr
->Mask(NEONAcrossLanesMask
)) {
1726 case NEON_ADDV
: mnemonic
= "addv"; break;
1727 case NEON_SMAXV
: mnemonic
= "smaxv"; break;
1728 case NEON_SMINV
: mnemonic
= "sminv"; break;
1729 case NEON_UMAXV
: mnemonic
= "umaxv"; break;
1730 case NEON_UMINV
: mnemonic
= "uminv"; break;
1732 mnemonic
= "saddlv";
1733 nfd
.SetFormatMap(0, nfd
.LongScalarFormatMap());
1736 mnemonic
= "uaddlv";
1737 nfd
.SetFormatMap(0, nfd
.LongScalarFormatMap());
1739 default: form
= "(NEONAcrossLanes)"; break;
1742 Format(instr
, mnemonic
, nfd
.Substitute(form
,
1743 NEONFormatDecoder::kPlaceholder
, NEONFormatDecoder::kFormat
));
1747 void Disassembler::VisitNEONByIndexedElement(const Instruction
* instr
) {
1748 const char *mnemonic
= "unimplemented";
1749 bool l_instr
= false;
1750 bool fp_instr
= false;
1752 const char *form
= "'Vd.%s, 'Vn.%s, 'Ve.%s['IVByElemIndex]";
1754 static const NEONFormatMap map_ta
= {
1755 {23, 22}, {NF_UNDEF
, NF_4S
, NF_2D
}
1757 NEONFormatDecoder
nfd(instr
, &map_ta
,
1758 NEONFormatDecoder::IntegerFormatMap(),
1759 NEONFormatDecoder::ScalarFormatMap());
1761 switch (instr
->Mask(NEONByIndexedElementMask
)) {
1762 case NEON_SMULL_byelement
: mnemonic
= "smull"; l_instr
= true; break;
1763 case NEON_UMULL_byelement
: mnemonic
= "umull"; l_instr
= true; break;
1764 case NEON_SMLAL_byelement
: mnemonic
= "smlal"; l_instr
= true; break;
1765 case NEON_UMLAL_byelement
: mnemonic
= "umlal"; l_instr
= true; break;
1766 case NEON_SMLSL_byelement
: mnemonic
= "smlsl"; l_instr
= true; break;
1767 case NEON_UMLSL_byelement
: mnemonic
= "umlsl"; l_instr
= true; break;
1768 case NEON_SQDMULL_byelement
: mnemonic
= "sqdmull"; l_instr
= true; break;
1769 case NEON_SQDMLAL_byelement
: mnemonic
= "sqdmlal"; l_instr
= true; break;
1770 case NEON_SQDMLSL_byelement
: mnemonic
= "sqdmlsl"; l_instr
= true; break;
1771 case NEON_MUL_byelement
: mnemonic
= "mul"; break;
1772 case NEON_MLA_byelement
: mnemonic
= "mla"; break;
1773 case NEON_MLS_byelement
: mnemonic
= "mls"; break;
1774 case NEON_SQDMULH_byelement
: mnemonic
= "sqdmulh"; break;
1775 case NEON_SQRDMULH_byelement
: mnemonic
= "sqrdmulh"; break;
1777 switch (instr
->Mask(NEONByIndexedElementFPMask
)) {
1778 case NEON_FMUL_byelement
: mnemonic
= "fmul"; fp_instr
= true; break;
1779 case NEON_FMLA_byelement
: mnemonic
= "fmla"; fp_instr
= true; break;
1780 case NEON_FMLS_byelement
: mnemonic
= "fmls"; fp_instr
= true; break;
1781 case NEON_FMULX_byelement
: mnemonic
= "fmulx"; fp_instr
= true; break;
1786 Format(instr
, nfd
.Mnemonic(mnemonic
), nfd
.Substitute(form
));
1787 } else if (fp_instr
) {
1788 nfd
.SetFormatMap(0, nfd
.FPFormatMap());
1789 Format(instr
, mnemonic
, nfd
.Substitute(form
));
1791 nfd
.SetFormatMap(0, nfd
.IntegerFormatMap());
1792 Format(instr
, mnemonic
, nfd
.Substitute(form
));
1797 void Disassembler::VisitNEONCopy(const Instruction
* instr
) {
1798 const char *mnemonic
= "unimplemented";
1799 const char *form
= "(NEONCopy)";
1801 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::TriangularFormatMap(),
1802 NEONFormatDecoder::TriangularScalarFormatMap());
1804 if (instr
->Mask(NEONCopyInsElementMask
) == NEON_INS_ELEMENT
) {
1806 nfd
.SetFormatMap(0, nfd
.TriangularScalarFormatMap());
1807 form
= "'Vd.%s['IVInsIndex1], 'Vn.%s['IVInsIndex2]";
1808 } else if (instr
->Mask(NEONCopyInsGeneralMask
) == NEON_INS_GENERAL
) {
1810 nfd
.SetFormatMap(0, nfd
.TriangularScalarFormatMap());
1811 if (nfd
.GetVectorFormat() == kFormatD
) {
1812 form
= "'Vd.%s['IVInsIndex1], 'Xn";
1814 form
= "'Vd.%s['IVInsIndex1], 'Wn";
1816 } else if (instr
->Mask(NEONCopyUmovMask
) == NEON_UMOV
) {
1817 if (instr
->Mask(NEON_Q
) || ((instr
->ImmNEON5() & 7) == 4)) {
1822 nfd
.SetFormatMap(0, nfd
.TriangularScalarFormatMap());
1823 if (nfd
.GetVectorFormat() == kFormatD
) {
1824 form
= "'Xd, 'Vn.%s['IVInsIndex1]";
1826 form
= "'Wd, 'Vn.%s['IVInsIndex1]";
1828 } else if (instr
->Mask(NEONCopySmovMask
) == NEON_SMOV
) {
1830 nfd
.SetFormatMap(0, nfd
.TriangularScalarFormatMap());
1831 form
= "'Rdq, 'Vn.%s['IVInsIndex1]";
1832 } else if (instr
->Mask(NEONCopyDupElementMask
) == NEON_DUP_ELEMENT
) {
1834 form
= "'Vd.%s, 'Vn.%s['IVInsIndex1]";
1835 } else if (instr
->Mask(NEONCopyDupGeneralMask
) == NEON_DUP_GENERAL
) {
1837 if (nfd
.GetVectorFormat() == kFormat2D
) {
1838 form
= "'Vd.%s, 'Xn";
1840 form
= "'Vd.%s, 'Wn";
1843 Format(instr
, mnemonic
, nfd
.Substitute(form
));
1847 void Disassembler::VisitNEONExtract(const Instruction
* instr
) {
1848 const char *mnemonic
= "unimplemented";
1849 const char *form
= "(NEONExtract)";
1850 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::LogicalFormatMap());
1851 if (instr
->Mask(NEONExtractMask
) == NEON_EXT
) {
1853 form
= "'Vd.%s, 'Vn.%s, 'Vm.%s, 'IVExtract";
1855 Format(instr
, mnemonic
, nfd
.Substitute(form
));
1859 void Disassembler::VisitNEONLoadStoreMultiStruct(const Instruction
* instr
) {
1860 const char *mnemonic
= "unimplemented";
1861 const char *form
= "(NEONLoadStoreMultiStruct)";
1862 const char *form_1v
= "{'Vt.%1$s}, ['Xns]";
1863 const char *form_2v
= "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns]";
1864 const char *form_3v
= "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns]";
1865 const char *form_4v
= "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]";
1866 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::LoadStoreFormatMap());
1868 switch (instr
->Mask(NEONLoadStoreMultiStructMask
)) {
1869 case NEON_LD1_1v
: mnemonic
= "ld1"; form
= form_1v
; break;
1870 case NEON_LD1_2v
: mnemonic
= "ld1"; form
= form_2v
; break;
1871 case NEON_LD1_3v
: mnemonic
= "ld1"; form
= form_3v
; break;
1872 case NEON_LD1_4v
: mnemonic
= "ld1"; form
= form_4v
; break;
1873 case NEON_LD2
: mnemonic
= "ld2"; form
= form_2v
; break;
1874 case NEON_LD3
: mnemonic
= "ld3"; form
= form_3v
; break;
1875 case NEON_LD4
: mnemonic
= "ld4"; form
= form_4v
; break;
1876 case NEON_ST1_1v
: mnemonic
= "st1"; form
= form_1v
; break;
1877 case NEON_ST1_2v
: mnemonic
= "st1"; form
= form_2v
; break;
1878 case NEON_ST1_3v
: mnemonic
= "st1"; form
= form_3v
; break;
1879 case NEON_ST1_4v
: mnemonic
= "st1"; form
= form_4v
; break;
1880 case NEON_ST2
: mnemonic
= "st2"; form
= form_2v
; break;
1881 case NEON_ST3
: mnemonic
= "st3"; form
= form_3v
; break;
1882 case NEON_ST4
: mnemonic
= "st4"; form
= form_4v
; break;
1886 Format(instr
, mnemonic
, nfd
.Substitute(form
));
1890 void Disassembler::VisitNEONLoadStoreMultiStructPostIndex(
1891 const Instruction
* instr
) {
1892 const char *mnemonic
= "unimplemented";
1893 const char *form
= "(NEONLoadStoreMultiStructPostIndex)";
1894 const char *form_1v
= "{'Vt.%1$s}, ['Xns], 'Xmr1";
1895 const char *form_2v
= "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns], 'Xmr2";
1896 const char *form_3v
= "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns], 'Xmr3";
1897 const char *form_4v
=
1898 "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmr4";
1899 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::LoadStoreFormatMap());
1901 switch (instr
->Mask(NEONLoadStoreMultiStructPostIndexMask
)) {
1902 case NEON_LD1_1v_post
: mnemonic
= "ld1"; form
= form_1v
; break;
1903 case NEON_LD1_2v_post
: mnemonic
= "ld1"; form
= form_2v
; break;
1904 case NEON_LD1_3v_post
: mnemonic
= "ld1"; form
= form_3v
; break;
1905 case NEON_LD1_4v_post
: mnemonic
= "ld1"; form
= form_4v
; break;
1906 case NEON_LD2_post
: mnemonic
= "ld2"; form
= form_2v
; break;
1907 case NEON_LD3_post
: mnemonic
= "ld3"; form
= form_3v
; break;
1908 case NEON_LD4_post
: mnemonic
= "ld4"; form
= form_4v
; break;
1909 case NEON_ST1_1v_post
: mnemonic
= "st1"; form
= form_1v
; break;
1910 case NEON_ST1_2v_post
: mnemonic
= "st1"; form
= form_2v
; break;
1911 case NEON_ST1_3v_post
: mnemonic
= "st1"; form
= form_3v
; break;
1912 case NEON_ST1_4v_post
: mnemonic
= "st1"; form
= form_4v
; break;
1913 case NEON_ST2_post
: mnemonic
= "st2"; form
= form_2v
; break;
1914 case NEON_ST3_post
: mnemonic
= "st3"; form
= form_3v
; break;
1915 case NEON_ST4_post
: mnemonic
= "st4"; form
= form_4v
; break;
1919 Format(instr
, mnemonic
, nfd
.Substitute(form
));
1923 void Disassembler::VisitNEONLoadStoreSingleStruct(const Instruction
* instr
) {
1924 const char *mnemonic
= "unimplemented";
1925 const char *form
= "(NEONLoadStoreSingleStruct)";
1927 const char *form_1b
= "{'Vt.b}['IVLSLane0], ['Xns]";
1928 const char *form_1h
= "{'Vt.h}['IVLSLane1], ['Xns]";
1929 const char *form_1s
= "{'Vt.s}['IVLSLane2], ['Xns]";
1930 const char *form_1d
= "{'Vt.d}['IVLSLane3], ['Xns]";
1931 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::LoadStoreFormatMap());
1933 switch (instr
->Mask(NEONLoadStoreSingleStructMask
)) {
1934 case NEON_LD1_b
: mnemonic
= "ld1"; form
= form_1b
; break;
1935 case NEON_LD1_h
: mnemonic
= "ld1"; form
= form_1h
; break;
1938 VIXL_STATIC_ASSERT((NEON_LD1_s
| (1 << NEONLSSize_offset
)) == NEON_LD1_d
);
1939 form
= ((instr
->NEONLSSize() & 1) == 0) ? form_1s
: form_1d
;
1941 case NEON_ST1_b
: mnemonic
= "st1"; form
= form_1b
; break;
1942 case NEON_ST1_h
: mnemonic
= "st1"; form
= form_1h
; break;
1945 VIXL_STATIC_ASSERT((NEON_ST1_s
| (1 << NEONLSSize_offset
)) == NEON_ST1_d
);
1946 form
= ((instr
->NEONLSSize() & 1) == 0) ? form_1s
: form_1d
;
1950 form
= "{'Vt.%s}, ['Xns]";
1954 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld2" : "st2";
1955 form
= "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns]";
1959 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld2" : "st2";
1960 form
= "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns]";
1964 VIXL_STATIC_ASSERT((NEON_ST2_s
| (1 << NEONLSSize_offset
)) == NEON_ST2_d
);
1965 VIXL_STATIC_ASSERT((NEON_LD2_s
| (1 << NEONLSSize_offset
)) == NEON_LD2_d
);
1966 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld2" : "st2";
1967 if ((instr
->NEONLSSize() & 1) == 0)
1968 form
= "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns]";
1970 form
= "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns]";
1974 form
= "{'Vt.%s, 'Vt2.%s}, ['Xns]";
1978 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld3" : "st3";
1979 form
= "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns]";
1983 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld3" : "st3";
1984 form
= "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns]";
1988 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld3" : "st3";
1989 if ((instr
->NEONLSSize() & 1) == 0)
1990 form
= "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns]";
1992 form
= "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns]";
1996 form
= "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns]";
2000 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld4" : "st4";
2001 form
= "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns]";
2005 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld4" : "st4";
2006 form
= "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns]";
2010 VIXL_STATIC_ASSERT((NEON_LD4_s
| (1 << NEONLSSize_offset
)) == NEON_LD4_d
);
2011 VIXL_STATIC_ASSERT((NEON_ST4_s
| (1 << NEONLSSize_offset
)) == NEON_ST4_d
);
2012 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld4" : "st4";
2013 if ((instr
->NEONLSSize() & 1) == 0)
2014 form
= "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns]";
2016 form
= "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns]";
2020 form
= "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]";
2025 Format(instr
, mnemonic
, nfd
.Substitute(form
));
2029 void Disassembler::VisitNEONLoadStoreSingleStructPostIndex(
2030 const Instruction
* instr
) {
2031 const char *mnemonic
= "unimplemented";
2032 const char *form
= "(NEONLoadStoreSingleStructPostIndex)";
2034 const char *form_1b
= "{'Vt.b}['IVLSLane0], ['Xns], 'Xmb1";
2035 const char *form_1h
= "{'Vt.h}['IVLSLane1], ['Xns], 'Xmb2";
2036 const char *form_1s
= "{'Vt.s}['IVLSLane2], ['Xns], 'Xmb4";
2037 const char *form_1d
= "{'Vt.d}['IVLSLane3], ['Xns], 'Xmb8";
2038 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::LoadStoreFormatMap());
2040 switch (instr
->Mask(NEONLoadStoreSingleStructPostIndexMask
)) {
2041 case NEON_LD1_b_post
: mnemonic
= "ld1"; form
= form_1b
; break;
2042 case NEON_LD1_h_post
: mnemonic
= "ld1"; form
= form_1h
; break;
2043 case NEON_LD1_s_post
:
2045 VIXL_STATIC_ASSERT((NEON_LD1_s
| (1 << NEONLSSize_offset
)) == NEON_LD1_d
);
2046 form
= ((instr
->NEONLSSize() & 1) == 0) ? form_1s
: form_1d
;
2048 case NEON_ST1_b_post
: mnemonic
= "st1"; form
= form_1b
; break;
2049 case NEON_ST1_h_post
: mnemonic
= "st1"; form
= form_1h
; break;
2050 case NEON_ST1_s_post
:
2052 VIXL_STATIC_ASSERT((NEON_ST1_s
| (1 << NEONLSSize_offset
)) == NEON_ST1_d
);
2053 form
= ((instr
->NEONLSSize() & 1) == 0) ? form_1s
: form_1d
;
2055 case NEON_LD1R_post
:
2057 form
= "{'Vt.%s}, ['Xns], 'Xmz1";
2059 case NEON_LD2_b_post
:
2060 case NEON_ST2_b_post
:
2061 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld2" : "st2";
2062 form
= "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns], 'Xmb2";
2064 case NEON_ST2_h_post
:
2065 case NEON_LD2_h_post
:
2066 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld2" : "st2";
2067 form
= "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns], 'Xmb4";
2069 case NEON_LD2_s_post
:
2070 case NEON_ST2_s_post
:
2071 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld2" : "st2";
2072 if ((instr
->NEONLSSize() & 1) == 0)
2073 form
= "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns], 'Xmb8";
2075 form
= "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns], 'Xmb16";
2077 case NEON_LD2R_post
:
2079 form
= "{'Vt.%s, 'Vt2.%s}, ['Xns], 'Xmz2";
2081 case NEON_LD3_b_post
:
2082 case NEON_ST3_b_post
:
2083 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld3" : "st3";
2084 form
= "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns], 'Xmb3";
2086 case NEON_LD3_h_post
:
2087 case NEON_ST3_h_post
:
2088 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld3" : "st3";
2089 form
= "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns], 'Xmb6";
2091 case NEON_LD3_s_post
:
2092 case NEON_ST3_s_post
:
2093 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld3" : "st3";
2094 if ((instr
->NEONLSSize() & 1) == 0)
2095 form
= "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns], 'Xmb12";
2097 form
= "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns], 'Xmr3";
2099 case NEON_LD3R_post
:
2101 form
= "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns], 'Xmz3";
2103 case NEON_LD4_b_post
:
2104 case NEON_ST4_b_post
:
2105 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld4" : "st4";
2106 form
= "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns], 'Xmb4";
2108 case NEON_LD4_h_post
:
2109 case NEON_ST4_h_post
:
2110 mnemonic
= (instr
->LdStXLoad()) == 1 ? "ld4" : "st4";
2111 form
= "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns], 'Xmb8";
2113 case NEON_LD4_s_post
:
2114 case NEON_ST4_s_post
:
2115 mnemonic
= (instr
->LdStXLoad() == 1) ? "ld4" : "st4";
2116 if ((instr
->NEONLSSize() & 1) == 0)
2117 form
= "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns], 'Xmb16";
2119 form
= "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns], 'Xmb32";
2121 case NEON_LD4R_post
:
2123 form
= "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmz4";
2128 Format(instr
, mnemonic
, nfd
.Substitute(form
));
2132 void Disassembler::VisitNEONModifiedImmediate(const Instruction
* instr
) {
2133 const char *mnemonic
= "unimplemented";
2134 const char *form
= "'Vt.%s, 'IVMIImm8, lsl 'IVMIShiftAmt1";
2136 int cmode
= instr
->NEONCmode();
2137 int cmode_3
= (cmode
>> 3) & 1;
2138 int cmode_2
= (cmode
>> 2) & 1;
2139 int cmode_1
= (cmode
>> 1) & 1;
2140 int cmode_0
= cmode
& 1;
2141 int q
= instr
->NEONQ();
2142 int op
= instr
->NEONModImmOp();
2144 static const NEONFormatMap map_b
= { {30}, {NF_8B
, NF_16B
} };
2145 static const NEONFormatMap map_h
= { {30}, {NF_4H
, NF_8H
} };
2146 static const NEONFormatMap map_s
= { {30}, {NF_2S
, NF_4S
} };
2147 NEONFormatDecoder
nfd(instr
, &map_b
);
2151 mnemonic
= (op
== 1) ? "mvni" : "movi";
2152 } else { // cmode<0> == '1'.
2153 mnemonic
= (op
== 1) ? "bic" : "orr";
2155 nfd
.SetFormatMap(0, &map_s
);
2156 } else { // cmode<3> == '1'.
2159 mnemonic
= (op
== 1) ? "mvni" : "movi";
2160 } else { // cmode<0> == '1'.
2161 mnemonic
= (op
== 1) ? "bic" : "orr";
2163 nfd
.SetFormatMap(0, &map_h
);
2164 } else { // cmode<2> == '1'.
2166 mnemonic
= (op
== 1) ? "mvni" : "movi";
2167 form
= "'Vt.%s, 'IVMIImm8, msl 'IVMIShiftAmt2";
2168 nfd
.SetFormatMap(0, &map_s
);
2169 } else { // cmode<1> == '1'.
2173 form
= "'Vt.%s, 'IVMIImm8";
2175 form
= (q
== 0) ? "'Dd, 'IVMIImm" : "'Vt.2d, 'IVMIImm";
2177 } else { // cmode<0> == '1'
2180 form
= "'Vt.%s, 'IVMIImmFPSingle";
2181 nfd
.SetFormatMap(0, &map_s
);
2184 form
= "'Vt.2d, 'IVMIImmFPDouble";
2191 Format(instr
, mnemonic
, nfd
.Substitute(form
));
2195 void Disassembler::VisitNEONScalar2RegMisc(const Instruction
* instr
) {
2196 const char *mnemonic
= "unimplemented";
2197 const char *form
= "%sd, %sn";
2198 const char *form_0
= "%sd, %sn, #0";
2199 const char *form_fp0
= "%sd, %sn, #0.0";
2201 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::ScalarFormatMap());
2203 if (instr
->Mask(NEON2RegMiscOpcode
) <= NEON_NEG_scalar_opcode
) {
2204 // These instructions all use a two bit size field, except NOT and RBIT,
2205 // which use the field to encode the operation.
2206 switch (instr
->Mask(NEONScalar2RegMiscMask
)) {
2207 case NEON_CMGT_zero_scalar
: mnemonic
= "cmgt"; form
= form_0
; break;
2208 case NEON_CMGE_zero_scalar
: mnemonic
= "cmge"; form
= form_0
; break;
2209 case NEON_CMLE_zero_scalar
: mnemonic
= "cmle"; form
= form_0
; break;
2210 case NEON_CMLT_zero_scalar
: mnemonic
= "cmlt"; form
= form_0
; break;
2211 case NEON_CMEQ_zero_scalar
: mnemonic
= "cmeq"; form
= form_0
; break;
2212 case NEON_NEG_scalar
: mnemonic
= "neg"; break;
2213 case NEON_SQNEG_scalar
: mnemonic
= "sqneg"; break;
2214 case NEON_ABS_scalar
: mnemonic
= "abs"; break;
2215 case NEON_SQABS_scalar
: mnemonic
= "sqabs"; break;
2216 case NEON_SUQADD_scalar
: mnemonic
= "suqadd"; break;
2217 case NEON_USQADD_scalar
: mnemonic
= "usqadd"; break;
2218 default: form
= "(NEONScalar2RegMisc)";
2221 // These instructions all use a one bit size field, except SQXTUN, SQXTN
2222 // and UQXTN, which use a two bit size field.
2223 nfd
.SetFormatMaps(nfd
.FPScalarFormatMap());
2224 switch (instr
->Mask(NEONScalar2RegMiscFPMask
)) {
2225 case NEON_FRSQRTE_scalar
: mnemonic
= "frsqrte"; break;
2226 case NEON_FRECPE_scalar
: mnemonic
= "frecpe"; break;
2227 case NEON_SCVTF_scalar
: mnemonic
= "scvtf"; break;
2228 case NEON_UCVTF_scalar
: mnemonic
= "ucvtf"; break;
2229 case NEON_FCMGT_zero_scalar
: mnemonic
= "fcmgt"; form
= form_fp0
; break;
2230 case NEON_FCMGE_zero_scalar
: mnemonic
= "fcmge"; form
= form_fp0
; break;
2231 case NEON_FCMLE_zero_scalar
: mnemonic
= "fcmle"; form
= form_fp0
; break;
2232 case NEON_FCMLT_zero_scalar
: mnemonic
= "fcmlt"; form
= form_fp0
; break;
2233 case NEON_FCMEQ_zero_scalar
: mnemonic
= "fcmeq"; form
= form_fp0
; break;
2234 case NEON_FRECPX_scalar
: mnemonic
= "frecpx"; break;
2235 case NEON_FCVTNS_scalar
: mnemonic
= "fcvtns"; break;
2236 case NEON_FCVTNU_scalar
: mnemonic
= "fcvtnu"; break;
2237 case NEON_FCVTPS_scalar
: mnemonic
= "fcvtps"; break;
2238 case NEON_FCVTPU_scalar
: mnemonic
= "fcvtpu"; break;
2239 case NEON_FCVTMS_scalar
: mnemonic
= "fcvtms"; break;
2240 case NEON_FCVTMU_scalar
: mnemonic
= "fcvtmu"; break;
2241 case NEON_FCVTZS_scalar
: mnemonic
= "fcvtzs"; break;
2242 case NEON_FCVTZU_scalar
: mnemonic
= "fcvtzu"; break;
2243 case NEON_FCVTAS_scalar
: mnemonic
= "fcvtas"; break;
2244 case NEON_FCVTAU_scalar
: mnemonic
= "fcvtau"; break;
2245 case NEON_FCVTXN_scalar
:
2246 nfd
.SetFormatMap(0, nfd
.LongScalarFormatMap());
2247 mnemonic
= "fcvtxn";
2250 nfd
.SetFormatMap(0, nfd
.ScalarFormatMap());
2251 nfd
.SetFormatMap(1, nfd
.LongScalarFormatMap());
2252 switch (instr
->Mask(NEONScalar2RegMiscMask
)) {
2253 case NEON_SQXTN_scalar
: mnemonic
= "sqxtn"; break;
2254 case NEON_UQXTN_scalar
: mnemonic
= "uqxtn"; break;
2255 case NEON_SQXTUN_scalar
: mnemonic
= "sqxtun"; break;
2256 default: form
= "(NEONScalar2RegMisc)";
2260 Format(instr
, mnemonic
, nfd
.SubstitutePlaceholders(form
));
2264 void Disassembler::VisitNEONScalar3Diff(const Instruction
* instr
) {
2265 const char *mnemonic
= "unimplemented";
2266 const char *form
= "%sd, %sn, %sm";
2267 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::LongScalarFormatMap(),
2268 NEONFormatDecoder::ScalarFormatMap());
2270 switch (instr
->Mask(NEONScalar3DiffMask
)) {
2271 case NEON_SQDMLAL_scalar
: mnemonic
= "sqdmlal"; break;
2272 case NEON_SQDMLSL_scalar
: mnemonic
= "sqdmlsl"; break;
2273 case NEON_SQDMULL_scalar
: mnemonic
= "sqdmull"; break;
2274 default: form
= "(NEONScalar3Diff)";
2276 Format(instr
, mnemonic
, nfd
.SubstitutePlaceholders(form
));
2280 void Disassembler::VisitNEONScalar3Same(const Instruction
* instr
) {
2281 const char *mnemonic
= "unimplemented";
2282 const char *form
= "%sd, %sn, %sm";
2283 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::ScalarFormatMap());
2285 if (instr
->Mask(NEONScalar3SameFPFMask
) == NEONScalar3SameFPFixed
) {
2286 nfd
.SetFormatMaps(nfd
.FPScalarFormatMap());
2287 switch (instr
->Mask(NEONScalar3SameFPMask
)) {
2288 case NEON_FACGE_scalar
: mnemonic
= "facge"; break;
2289 case NEON_FACGT_scalar
: mnemonic
= "facgt"; break;
2290 case NEON_FCMEQ_scalar
: mnemonic
= "fcmeq"; break;
2291 case NEON_FCMGE_scalar
: mnemonic
= "fcmge"; break;
2292 case NEON_FCMGT_scalar
: mnemonic
= "fcmgt"; break;
2293 case NEON_FMULX_scalar
: mnemonic
= "fmulx"; break;
2294 case NEON_FRECPS_scalar
: mnemonic
= "frecps"; break;
2295 case NEON_FRSQRTS_scalar
: mnemonic
= "frsqrts"; break;
2296 case NEON_FABD_scalar
: mnemonic
= "fabd"; break;
2297 default: form
= "(NEONScalar3Same)";
2300 switch (instr
->Mask(NEONScalar3SameMask
)) {
2301 case NEON_ADD_scalar
: mnemonic
= "add"; break;
2302 case NEON_SUB_scalar
: mnemonic
= "sub"; break;
2303 case NEON_CMEQ_scalar
: mnemonic
= "cmeq"; break;
2304 case NEON_CMGE_scalar
: mnemonic
= "cmge"; break;
2305 case NEON_CMGT_scalar
: mnemonic
= "cmgt"; break;
2306 case NEON_CMHI_scalar
: mnemonic
= "cmhi"; break;
2307 case NEON_CMHS_scalar
: mnemonic
= "cmhs"; break;
2308 case NEON_CMTST_scalar
: mnemonic
= "cmtst"; break;
2309 case NEON_UQADD_scalar
: mnemonic
= "uqadd"; break;
2310 case NEON_SQADD_scalar
: mnemonic
= "sqadd"; break;
2311 case NEON_UQSUB_scalar
: mnemonic
= "uqsub"; break;
2312 case NEON_SQSUB_scalar
: mnemonic
= "sqsub"; break;
2313 case NEON_USHL_scalar
: mnemonic
= "ushl"; break;
2314 case NEON_SSHL_scalar
: mnemonic
= "sshl"; break;
2315 case NEON_UQSHL_scalar
: mnemonic
= "uqshl"; break;
2316 case NEON_SQSHL_scalar
: mnemonic
= "sqshl"; break;
2317 case NEON_URSHL_scalar
: mnemonic
= "urshl"; break;
2318 case NEON_SRSHL_scalar
: mnemonic
= "srshl"; break;
2319 case NEON_UQRSHL_scalar
: mnemonic
= "uqrshl"; break;
2320 case NEON_SQRSHL_scalar
: mnemonic
= "sqrshl"; break;
2321 case NEON_SQDMULH_scalar
: mnemonic
= "sqdmulh"; break;
2322 case NEON_SQRDMULH_scalar
: mnemonic
= "sqrdmulh"; break;
2323 default: form
= "(NEONScalar3Same)";
2326 Format(instr
, mnemonic
, nfd
.SubstitutePlaceholders(form
));
2330 void Disassembler::VisitNEONScalarByIndexedElement(const Instruction
* instr
) {
2331 const char *mnemonic
= "unimplemented";
2332 const char *form
= "%sd, %sn, 'Ve.%s['IVByElemIndex]";
2333 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::ScalarFormatMap());
2334 bool long_instr
= false;
2336 switch (instr
->Mask(NEONScalarByIndexedElementMask
)) {
2337 case NEON_SQDMULL_byelement_scalar
:
2338 mnemonic
= "sqdmull";
2341 case NEON_SQDMLAL_byelement_scalar
:
2342 mnemonic
= "sqdmlal";
2345 case NEON_SQDMLSL_byelement_scalar
:
2346 mnemonic
= "sqdmlsl";
2349 case NEON_SQDMULH_byelement_scalar
:
2350 mnemonic
= "sqdmulh";
2352 case NEON_SQRDMULH_byelement_scalar
:
2353 mnemonic
= "sqrdmulh";
2356 nfd
.SetFormatMap(0, nfd
.FPScalarFormatMap());
2357 switch (instr
->Mask(NEONScalarByIndexedElementFPMask
)) {
2358 case NEON_FMUL_byelement_scalar
: mnemonic
= "fmul"; break;
2359 case NEON_FMLA_byelement_scalar
: mnemonic
= "fmla"; break;
2360 case NEON_FMLS_byelement_scalar
: mnemonic
= "fmls"; break;
2361 case NEON_FMULX_byelement_scalar
: mnemonic
= "fmulx"; break;
2362 default: form
= "(NEONScalarByIndexedElement)";
2367 nfd
.SetFormatMap(0, nfd
.LongScalarFormatMap());
2370 Format(instr
, mnemonic
, nfd
.Substitute(
2371 form
, nfd
.kPlaceholder
, nfd
.kPlaceholder
, nfd
.kFormat
));
2375 void Disassembler::VisitNEONScalarCopy(const Instruction
* instr
) {
2376 const char *mnemonic
= "unimplemented";
2377 const char *form
= "(NEONScalarCopy)";
2379 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::TriangularScalarFormatMap());
2381 if (instr
->Mask(NEONScalarCopyMask
) == NEON_DUP_ELEMENT_scalar
) {
2383 form
= "%sd, 'Vn.%s['IVInsIndex1]";
2386 Format(instr
, mnemonic
, nfd
.Substitute(form
, nfd
.kPlaceholder
, nfd
.kFormat
));
2390 void Disassembler::VisitNEONScalarPairwise(const Instruction
* instr
) {
2391 const char *mnemonic
= "unimplemented";
2392 const char *form
= "%sd, 'Vn.%s";
2393 NEONFormatMap map
= { {22}, {NF_2S
, NF_2D
} };
2394 NEONFormatDecoder
nfd(instr
, NEONFormatDecoder::FPScalarFormatMap(), &map
);
2396 switch (instr
->Mask(NEONScalarPairwiseMask
)) {
2397 case NEON_ADDP_scalar
: mnemonic
= "addp"; break;
2398 case NEON_FADDP_scalar
: mnemonic
= "faddp"; break;
2399 case NEON_FMAXP_scalar
: mnemonic
= "fmaxp"; break;
2400 case NEON_FMAXNMP_scalar
: mnemonic
= "fmaxnmp"; break;
2401 case NEON_FMINP_scalar
: mnemonic
= "fminp"; break;
2402 case NEON_FMINNMP_scalar
: mnemonic
= "fminnmp"; break;
2403 default: form
= "(NEONScalarPairwise)";
2405 Format(instr
, mnemonic
, nfd
.Substitute(form
,
2406 NEONFormatDecoder::kPlaceholder
, NEONFormatDecoder::kFormat
));
2410 void Disassembler::VisitNEONScalarShiftImmediate(const Instruction
* instr
) {
2411 const char *mnemonic
= "unimplemented";
2412 const char *form
= "%sd, %sn, 'Is1";
2413 const char *form_2
= "%sd, %sn, 'Is2";
2415 static const NEONFormatMap map_shift
= {
2417 {NF_UNDEF
, NF_B
, NF_H
, NF_H
, NF_S
, NF_S
, NF_S
, NF_S
,
2418 NF_D
, NF_D
, NF_D
, NF_D
, NF_D
, NF_D
, NF_D
, NF_D
}
2420 static const NEONFormatMap map_shift_narrow
= {
2422 {NF_UNDEF
, NF_H
, NF_S
, NF_S
, NF_D
, NF_D
, NF_D
, NF_D
}
2424 NEONFormatDecoder
nfd(instr
, &map_shift
);
2426 if (instr
->ImmNEONImmh()) { // immh has to be non-zero.
2427 switch (instr
->Mask(NEONScalarShiftImmediateMask
)) {
2428 case NEON_FCVTZU_imm_scalar
: mnemonic
= "fcvtzu"; break;
2429 case NEON_FCVTZS_imm_scalar
: mnemonic
= "fcvtzs"; break;
2430 case NEON_SCVTF_imm_scalar
: mnemonic
= "scvtf"; break;
2431 case NEON_UCVTF_imm_scalar
: mnemonic
= "ucvtf"; break;
2432 case NEON_SRI_scalar
: mnemonic
= "sri"; break;
2433 case NEON_SSHR_scalar
: mnemonic
= "sshr"; break;
2434 case NEON_USHR_scalar
: mnemonic
= "ushr"; break;
2435 case NEON_SRSHR_scalar
: mnemonic
= "srshr"; break;
2436 case NEON_URSHR_scalar
: mnemonic
= "urshr"; break;
2437 case NEON_SSRA_scalar
: mnemonic
= "ssra"; break;
2438 case NEON_USRA_scalar
: mnemonic
= "usra"; break;
2439 case NEON_SRSRA_scalar
: mnemonic
= "srsra"; break;
2440 case NEON_URSRA_scalar
: mnemonic
= "ursra"; break;
2441 case NEON_SHL_scalar
: mnemonic
= "shl"; form
= form_2
; break;
2442 case NEON_SLI_scalar
: mnemonic
= "sli"; form
= form_2
; break;
2443 case NEON_SQSHLU_scalar
: mnemonic
= "sqshlu"; form
= form_2
; break;
2444 case NEON_SQSHL_imm_scalar
: mnemonic
= "sqshl"; form
= form_2
; break;
2445 case NEON_UQSHL_imm_scalar
: mnemonic
= "uqshl"; form
= form_2
; break;
2446 case NEON_UQSHRN_scalar
:
2447 mnemonic
= "uqshrn";
2448 nfd
.SetFormatMap(1, &map_shift_narrow
);
2450 case NEON_UQRSHRN_scalar
:
2451 mnemonic
= "uqrshrn";
2452 nfd
.SetFormatMap(1, &map_shift_narrow
);
2454 case NEON_SQSHRN_scalar
:
2455 mnemonic
= "sqshrn";
2456 nfd
.SetFormatMap(1, &map_shift_narrow
);
2458 case NEON_SQRSHRN_scalar
:
2459 mnemonic
= "sqrshrn";
2460 nfd
.SetFormatMap(1, &map_shift_narrow
);
2462 case NEON_SQSHRUN_scalar
:
2463 mnemonic
= "sqshrun";
2464 nfd
.SetFormatMap(1, &map_shift_narrow
);
2466 case NEON_SQRSHRUN_scalar
:
2467 mnemonic
= "sqrshrun";
2468 nfd
.SetFormatMap(1, &map_shift_narrow
);
2471 form
= "(NEONScalarShiftImmediate)";
2474 form
= "(NEONScalarShiftImmediate)";
2476 Format(instr
, mnemonic
, nfd
.SubstitutePlaceholders(form
));
2480 void Disassembler::VisitNEONShiftImmediate(const Instruction
* instr
) {
2481 const char *mnemonic
= "unimplemented";
2482 const char *form
= "'Vd.%s, 'Vn.%s, 'Is1";
2483 const char *form_shift_2
= "'Vd.%s, 'Vn.%s, 'Is2";
2484 const char *form_xtl
= "'Vd.%s, 'Vn.%s";
2486 // 0001->8H, 001x->4S, 01xx->2D, all others undefined.
2487 static const NEONFormatMap map_shift_ta
= {
2489 {NF_UNDEF
, NF_8H
, NF_4S
, NF_4S
, NF_2D
, NF_2D
, NF_2D
, NF_2D
}
2492 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H,
2493 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined.
2494 static const NEONFormatMap map_shift_tb
= {
2495 {22, 21, 20, 19, 30},
2496 {NF_UNDEF
, NF_UNDEF
, NF_8B
, NF_16B
, NF_4H
, NF_8H
, NF_4H
, NF_8H
,
2497 NF_2S
, NF_4S
, NF_2S
, NF_4S
, NF_2S
, NF_4S
, NF_2S
, NF_4S
,
2498 NF_UNDEF
, NF_2D
, NF_UNDEF
, NF_2D
, NF_UNDEF
, NF_2D
, NF_UNDEF
, NF_2D
,
2499 NF_UNDEF
, NF_2D
, NF_UNDEF
, NF_2D
, NF_UNDEF
, NF_2D
, NF_UNDEF
, NF_2D
}
2502 NEONFormatDecoder
nfd(instr
, &map_shift_tb
);
2504 if (instr
->ImmNEONImmh()) { // immh has to be non-zero.
2505 switch (instr
->Mask(NEONShiftImmediateMask
)) {
2506 case NEON_SQSHLU
: mnemonic
= "sqshlu"; form
= form_shift_2
; break;
2507 case NEON_SQSHL_imm
: mnemonic
= "sqshl"; form
= form_shift_2
; break;
2508 case NEON_UQSHL_imm
: mnemonic
= "uqshl"; form
= form_shift_2
; break;
2509 case NEON_SHL
: mnemonic
= "shl"; form
= form_shift_2
; break;
2510 case NEON_SLI
: mnemonic
= "sli"; form
= form_shift_2
; break;
2511 case NEON_SCVTF_imm
: mnemonic
= "scvtf"; break;
2512 case NEON_UCVTF_imm
: mnemonic
= "ucvtf"; break;
2513 case NEON_FCVTZU_imm
: mnemonic
= "fcvtzu"; break;
2514 case NEON_FCVTZS_imm
: mnemonic
= "fcvtzs"; break;
2515 case NEON_SRI
: mnemonic
= "sri"; break;
2516 case NEON_SSHR
: mnemonic
= "sshr"; break;
2517 case NEON_USHR
: mnemonic
= "ushr"; break;
2518 case NEON_SRSHR
: mnemonic
= "srshr"; break;
2519 case NEON_URSHR
: mnemonic
= "urshr"; break;
2520 case NEON_SSRA
: mnemonic
= "ssra"; break;
2521 case NEON_USRA
: mnemonic
= "usra"; break;
2522 case NEON_SRSRA
: mnemonic
= "srsra"; break;
2523 case NEON_URSRA
: mnemonic
= "ursra"; break;
2525 mnemonic
= instr
->Mask(NEON_Q
) ? "shrn2" : "shrn";
2526 nfd
.SetFormatMap(1, &map_shift_ta
);
2529 mnemonic
= instr
->Mask(NEON_Q
) ? "rshrn2" : "rshrn";
2530 nfd
.SetFormatMap(1, &map_shift_ta
);
2533 mnemonic
= instr
->Mask(NEON_Q
) ? "uqshrn2" : "uqshrn";
2534 nfd
.SetFormatMap(1, &map_shift_ta
);
2537 mnemonic
= instr
->Mask(NEON_Q
) ? "uqrshrn2" : "uqrshrn";
2538 nfd
.SetFormatMap(1, &map_shift_ta
);
2541 mnemonic
= instr
->Mask(NEON_Q
) ? "sqshrn2" : "sqshrn";
2542 nfd
.SetFormatMap(1, &map_shift_ta
);
2545 mnemonic
= instr
->Mask(NEON_Q
) ? "sqrshrn2" : "sqrshrn";
2546 nfd
.SetFormatMap(1, &map_shift_ta
);
2549 mnemonic
= instr
->Mask(NEON_Q
) ? "sqshrun2" : "sqshrun";
2550 nfd
.SetFormatMap(1, &map_shift_ta
);
2553 mnemonic
= instr
->Mask(NEON_Q
) ? "sqrshrun2" : "sqrshrun";
2554 nfd
.SetFormatMap(1, &map_shift_ta
);
2557 nfd
.SetFormatMap(0, &map_shift_ta
);
2558 if (instr
->ImmNEONImmb() == 0 &&
2559 CountSetBits(instr
->ImmNEONImmh(), 32) == 1) { // sxtl variant.
2561 mnemonic
= instr
->Mask(NEON_Q
) ? "sxtl2" : "sxtl";
2562 } else { // sshll variant.
2563 form
= form_shift_2
;
2564 mnemonic
= instr
->Mask(NEON_Q
) ? "sshll2" : "sshll";
2568 nfd
.SetFormatMap(0, &map_shift_ta
);
2569 if (instr
->ImmNEONImmb() == 0 &&
2570 CountSetBits(instr
->ImmNEONImmh(), 32) == 1) { // uxtl variant.
2572 mnemonic
= instr
->Mask(NEON_Q
) ? "uxtl2" : "uxtl";
2573 } else { // ushll variant.
2574 form
= form_shift_2
;
2575 mnemonic
= instr
->Mask(NEON_Q
) ? "ushll2" : "ushll";
2578 default: form
= "(NEONShiftImmediate)";
2581 form
= "(NEONShiftImmediate)";
2583 Format(instr
, mnemonic
, nfd
.Substitute(form
));
2587 void Disassembler::VisitNEONTable(const Instruction
* instr
) {
2588 const char *mnemonic
= "unimplemented";
2589 const char *form
= "(NEONTable)";
2590 const char form_1v
[] = "'Vd.%%s, {'Vn.16b}, 'Vm.%%s";
2591 const char form_2v
[] = "'Vd.%%s, {'Vn.16b, v%d.16b}, 'Vm.%%s";
2592 const char form_3v
[] = "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b}, 'Vm.%%s";
2593 const char form_4v
[] =
2594 "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b, v%d.16b}, 'Vm.%%s";
2595 static const NEONFormatMap map_b
= { {30}, {NF_8B
, NF_16B
} };
2596 NEONFormatDecoder
nfd(instr
, &map_b
);
2598 switch (instr
->Mask(NEONTableMask
)) {
2599 case NEON_TBL_1v
: mnemonic
= "tbl"; form
= form_1v
; break;
2600 case NEON_TBL_2v
: mnemonic
= "tbl"; form
= form_2v
; break;
2601 case NEON_TBL_3v
: mnemonic
= "tbl"; form
= form_3v
; break;
2602 case NEON_TBL_4v
: mnemonic
= "tbl"; form
= form_4v
; break;
2603 case NEON_TBX_1v
: mnemonic
= "tbx"; form
= form_1v
; break;
2604 case NEON_TBX_2v
: mnemonic
= "tbx"; form
= form_2v
; break;
2605 case NEON_TBX_3v
: mnemonic
= "tbx"; form
= form_3v
; break;
2606 case NEON_TBX_4v
: mnemonic
= "tbx"; form
= form_4v
; break;
2610 char re_form
[sizeof(form_4v
) + 6];
2611 int reg_num
= instr
->Rn();
2612 snprintf(re_form
, sizeof(re_form
), form
,
2613 (reg_num
+ 1) % kNumberOfVRegisters
,
2614 (reg_num
+ 2) % kNumberOfVRegisters
,
2615 (reg_num
+ 3) % kNumberOfVRegisters
);
2617 Format(instr
, mnemonic
, nfd
.Substitute(re_form
));
2621 void Disassembler::VisitNEONPerm(const Instruction
* instr
) {
2622 const char *mnemonic
= "unimplemented";
2623 const char *form
= "'Vd.%s, 'Vn.%s, 'Vm.%s";
2624 NEONFormatDecoder
nfd(instr
);
2626 switch (instr
->Mask(NEONPermMask
)) {
2627 case NEON_TRN1
: mnemonic
= "trn1"; break;
2628 case NEON_TRN2
: mnemonic
= "trn2"; break;
2629 case NEON_UZP1
: mnemonic
= "uzp1"; break;
2630 case NEON_UZP2
: mnemonic
= "uzp2"; break;
2631 case NEON_ZIP1
: mnemonic
= "zip1"; break;
2632 case NEON_ZIP2
: mnemonic
= "zip2"; break;
2633 default: form
= "(NEONPerm)";
2635 Format(instr
, mnemonic
, nfd
.Substitute(form
));
2639 void Disassembler::VisitUnimplemented(const Instruction
* instr
) {
2640 Format(instr
, "unimplemented", "(Unimplemented)");
2644 void Disassembler::VisitUnallocated(const Instruction
* instr
) {
2645 Format(instr
, "unallocated", "(Unallocated)");
2649 void Disassembler::ProcessOutput(const Instruction
* /*instr*/) {
2650 // The base disasm does nothing more than disassembling into a buffer.
2654 void Disassembler::AppendRegisterNameToOutput(const Instruction
* instr
,
2655 const CPURegister
& reg
) {
2657 VIXL_ASSERT(reg
.IsValid());
2660 if (reg
.IsRegister()) {
2661 reg_char
= reg
.Is64Bits() ? 'x' : 'w';
2663 VIXL_ASSERT(reg
.IsVRegister());
2664 switch (reg
.SizeInBits()) {
2665 case kBRegSize
: reg_char
= 'b'; break;
2666 case kHRegSize
: reg_char
= 'h'; break;
2667 case kSRegSize
: reg_char
= 's'; break;
2668 case kDRegSize
: reg_char
= 'd'; break;
2670 VIXL_ASSERT(reg
.Is128Bits());
2675 if (reg
.IsVRegister() || !(reg
.Aliases(sp
) || reg
.Aliases(xzr
))) {
2676 // A core or scalar/vector register: [wx]0 - 30, [bhsdq]0 - 31.
2677 AppendToOutput("%c%d", reg_char
, reg
.code());
2678 } else if (reg
.Aliases(sp
)) {
2679 // Disassemble w31/x31 as stack pointer wsp/sp.
2680 AppendToOutput("%s", reg
.Is64Bits() ? "sp" : "wsp");
2682 // Disassemble w31/x31 as zero register wzr/xzr.
2683 AppendToOutput("%czr", reg_char
);
2688 void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction
* instr
,
2691 uint64_t abs_offset
= offset
;
2692 char sign
= (offset
< 0) ? '-' : '+';
2694 abs_offset
= -abs_offset
;
2696 AppendToOutput("#%c0x%" PRIx64
, sign
, abs_offset
);
2700 void Disassembler::AppendAddressToOutput(const Instruction
* instr
,
2703 AppendToOutput("(addr 0x%" PRIxPTR
")", reinterpret_cast<uintptr_t>(addr
));
2707 void Disassembler::AppendCodeAddressToOutput(const Instruction
* instr
,
2709 AppendAddressToOutput(instr
, addr
);
2713 void Disassembler::AppendDataAddressToOutput(const Instruction
* instr
,
2715 AppendAddressToOutput(instr
, addr
);
2719 void Disassembler::AppendCodeRelativeAddressToOutput(const Instruction
* instr
,
2722 int64_t rel_addr
= CodeRelativeAddress(addr
);
2723 if (rel_addr
>= 0) {
2724 AppendToOutput("(addr 0x%" PRIx64
")", rel_addr
);
2726 AppendToOutput("(addr -0x%" PRIx64
")", -rel_addr
);
2731 void Disassembler::AppendCodeRelativeCodeAddressToOutput(
2732 const Instruction
* instr
, const void* addr
) {
2733 AppendCodeRelativeAddressToOutput(instr
, addr
);
2737 void Disassembler::AppendCodeRelativeDataAddressToOutput(
2738 const Instruction
* instr
, const void* addr
) {
2739 AppendCodeRelativeAddressToOutput(instr
, addr
);
2743 void Disassembler::MapCodeAddress(int64_t base_address
,
2744 const Instruction
* instr_address
) {
2745 set_code_address_offset(
2746 base_address
- reinterpret_cast<intptr_t>(instr_address
));
2748 int64_t Disassembler::CodeRelativeAddress(const void* addr
) {
2749 return reinterpret_cast<intptr_t>(addr
) + code_address_offset();
2753 void Disassembler::Format(const Instruction
* instr
, const char* mnemonic
,
2754 const char* format
) {
2755 VIXL_ASSERT(mnemonic
!= NULL
);
2757 Substitute(instr
, mnemonic
);
2758 if (format
!= NULL
) {
2759 VIXL_ASSERT(buffer_pos_
< buffer_size_
);
2760 buffer_
[buffer_pos_
++] = ' ';
2761 Substitute(instr
, format
);
2763 VIXL_ASSERT(buffer_pos_
< buffer_size_
);
2764 buffer_
[buffer_pos_
] = 0;
2765 ProcessOutput(instr
);
2769 void Disassembler::Substitute(const Instruction
* instr
, const char* string
) {
2770 char chr
= *string
++;
2771 while (chr
!= '\0') {
2773 string
+= SubstituteField(instr
, string
);
2775 VIXL_ASSERT(buffer_pos_
< buffer_size_
);
2776 buffer_
[buffer_pos_
++] = chr
;
2783 int Disassembler::SubstituteField(const Instruction
* instr
,
2784 const char* format
) {
2785 switch (format
[0]) {
2786 // NB. The remaining substitution prefix characters are: GJKUZ.
2787 case 'R': // Register. X or W, selected by sf bit.
2788 case 'F': // FP register. S or D, selected by type field.
2789 case 'V': // Vector register, V, vector format.
2796 case 'Q': return SubstituteRegisterField(instr
, format
);
2797 case 'I': return SubstituteImmediateField(instr
, format
);
2798 case 'L': return SubstituteLiteralField(instr
, format
);
2799 case 'N': return SubstituteShiftField(instr
, format
);
2800 case 'P': return SubstitutePrefetchField(instr
, format
);
2801 case 'C': return SubstituteConditionField(instr
, format
);
2802 case 'E': return SubstituteExtendField(instr
, format
);
2803 case 'A': return SubstitutePCRelAddressField(instr
, format
);
2804 case 'T': return SubstituteBranchTargetField(instr
, format
);
2805 case 'O': return SubstituteLSRegOffsetField(instr
, format
);
2806 case 'M': return SubstituteBarrierField(instr
, format
);
2807 case 'K': return SubstituteCrField(instr
, format
);
2808 case 'G': return SubstituteSysOpField(instr
, format
);
2817 int Disassembler::SubstituteRegisterField(const Instruction
* instr
,
2818 const char* format
) {
2819 char reg_prefix
= format
[0];
2820 unsigned reg_num
= 0;
2821 unsigned field_len
= 2;
2823 switch (format
[1]) {
2825 reg_num
= instr
->Rd();
2826 if (format
[2] == 'q') {
2827 reg_prefix
= instr
->NEONQ() ? 'X' : 'W';
2831 case 'n': reg_num
= instr
->Rn(); break;
2833 reg_num
= instr
->Rm();
2834 switch (format
[2]) {
2835 // Handle registers tagged with b (bytes), z (instruction), or
2836 // r (registers), used for address updates in
2837 // NEON load/store instructions.
2843 int imm
= static_cast<int>(strtol(&format
[3], &eimm
, 10));
2844 field_len
+= eimm
- &format
[3];
2845 if (reg_num
== 31) {
2846 switch (format
[2]) {
2848 imm
*= (1 << instr
->NEONLSSize());
2851 imm
*= (instr
->NEONQ() == 0) ? kDRegSizeInBytes
2857 AppendToOutput("#%d", imm
);
2865 // This is register Rm, but using a 4-bit specifier. Used in NEON
2866 // by-element instructions.
2867 reg_num
= (instr
->Rm() & 0xf);
2869 case 'a': reg_num
= instr
->Ra(); break;
2870 case 's': reg_num
= instr
->Rs(); break;
2872 reg_num
= instr
->Rt();
2873 if (format
[0] == 'V') {
2874 if ((format
[2] >= '2') && (format
[2] <= '4')) {
2875 // Handle consecutive vector register specifiers Vt2, Vt3 and Vt4.
2876 reg_num
= (reg_num
+ format
[2] - '1') % 32;
2880 if (format
[2] == '2') {
2881 // Handle register specifier Rt2.
2882 reg_num
= instr
->Rt2();
2887 default: VIXL_UNREACHABLE();
2890 // Increase field length for registers tagged as stack.
2891 if (format
[2] == 's') {
2895 CPURegister::RegisterType reg_type
= CPURegister::kRegister
;
2896 unsigned reg_size
= kXRegSize
;
2898 if (reg_prefix
== 'R') {
2899 reg_prefix
= instr
->SixtyFourBits() ? 'X' : 'W';
2900 } else if (reg_prefix
== 'F') {
2901 reg_prefix
= ((instr
->FPType() & 1) == 0) ? 'S' : 'D';
2904 switch (reg_prefix
) {
2906 reg_type
= CPURegister::kRegister
; reg_size
= kWRegSize
; break;
2908 reg_type
= CPURegister::kRegister
; reg_size
= kXRegSize
; break;
2910 reg_type
= CPURegister::kVRegister
; reg_size
= kBRegSize
; break;
2912 reg_type
= CPURegister::kVRegister
; reg_size
= kHRegSize
; break;
2914 reg_type
= CPURegister::kVRegister
; reg_size
= kSRegSize
; break;
2916 reg_type
= CPURegister::kVRegister
; reg_size
= kDRegSize
; break;
2918 reg_type
= CPURegister::kVRegister
; reg_size
= kQRegSize
; break;
2920 AppendToOutput("v%d", reg_num
);
2926 if ((reg_type
== CPURegister::kRegister
) &&
2927 (reg_num
== kZeroRegCode
) && (format
[2] == 's')) {
2928 reg_num
= kSPRegInternalCode
;
2931 AppendRegisterNameToOutput(instr
, CPURegister(reg_num
, reg_size
, reg_type
));
2937 int Disassembler::SubstituteImmediateField(const Instruction
* instr
,
2938 const char* format
) {
2939 VIXL_ASSERT(format
[0] == 'I');
2941 switch (format
[1]) {
2942 case 'M': { // IMoveImm, IMoveNeg or IMoveLSL.
2943 if (format
[5] == 'L') {
2944 AppendToOutput("#0x%" PRIx32
, instr
->ImmMoveWide());
2945 if (instr
->ShiftMoveWide() > 0) {
2946 AppendToOutput(", lsl #%" PRId32
, 16 * instr
->ShiftMoveWide());
2949 VIXL_ASSERT((format
[5] == 'I') || (format
[5] == 'N'));
2950 uint64_t imm
= static_cast<uint64_t>(instr
->ImmMoveWide()) <<
2951 (16 * instr
->ShiftMoveWide());
2952 if (format
[5] == 'N')
2954 if (!instr
->SixtyFourBits())
2955 imm
&= UINT64_C(0xffffffff);
2956 AppendToOutput("#0x%" PRIx64
, imm
);
2961 switch (format
[2]) {
2962 case 'L': { // ILLiteral - Immediate Load Literal.
2963 AppendToOutput("pc%+" PRId32
,
2964 instr
->ImmLLiteral() << kLiteralEntrySizeLog2
);
2967 case 'S': { // ILS - Immediate Load/Store.
2968 if (instr
->ImmLS() != 0) {
2969 AppendToOutput(", #%" PRId32
, instr
->ImmLS());
2973 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
2974 if (instr
->ImmLSPair() != 0) {
2975 // format[3] is the scale value. Convert to a number.
2976 int scale
= 1 << (format
[3] - '0');
2977 AppendToOutput(", #%" PRId32
, instr
->ImmLSPair() * scale
);
2981 case 'U': { // ILU - Immediate Load/Store Unsigned.
2982 if (instr
->ImmLSUnsigned() != 0) {
2983 int shift
= instr
->SizeLS();
2984 AppendToOutput(", #%" PRId32
, instr
->ImmLSUnsigned() << shift
);
2990 case 'C': { // ICondB - Immediate Conditional Branch.
2991 int64_t offset
= instr
->ImmCondBranch() << 2;
2992 AppendPCRelativeOffsetToOutput(instr
, offset
);
2995 case 'A': { // IAddSub.
2996 VIXL_ASSERT(instr
->ShiftAddSub() <= 1);
2997 int64_t imm
= instr
->ImmAddSub() << (12 * instr
->ShiftAddSub());
2998 AppendToOutput("#0x%" PRIx64
" (%" PRId64
")", imm
, imm
);
3001 case 'F': { // IFPSingle, IFPDouble or IFPFBits.
3002 if (format
[3] == 'F') { // IFPFbits.
3003 AppendToOutput("#%" PRId32
, 64 - instr
->FPScale());
3006 AppendToOutput("#0x%" PRIx32
" (%.4f)", instr
->ImmFP(),
3007 format
[3] == 'S' ? instr
->ImmFP32() : instr
->ImmFP64());
3011 case 'T': { // ITri - Immediate Triangular Encoded.
3012 AppendToOutput("#0x%" PRIx64
, instr
->ImmLogical());
3015 case 'N': { // INzcv.
3016 int nzcv
= (instr
->Nzcv() << Flags_offset
);
3017 AppendToOutput("#%c%c%c%c", ((nzcv
& NFlag
) == 0) ? 'n' : 'N',
3018 ((nzcv
& ZFlag
) == 0) ? 'z' : 'Z',
3019 ((nzcv
& CFlag
) == 0) ? 'c' : 'C',
3020 ((nzcv
& VFlag
) == 0) ? 'v' : 'V');
3023 case 'P': { // IP - Conditional compare.
3024 AppendToOutput("#%" PRId32
, instr
->ImmCondCmp());
3027 case 'B': { // Bitfields.
3028 return SubstituteBitfieldImmediateField(instr
, format
);
3030 case 'E': { // IExtract.
3031 AppendToOutput("#%" PRId32
, instr
->ImmS());
3034 case 'S': { // IS - Test and branch bit.
3035 AppendToOutput("#%" PRId32
, (instr
->ImmTestBranchBit5() << 5) |
3036 instr
->ImmTestBranchBit40());
3039 case 's': { // Is - Shift (immediate).
3040 switch (format
[2]) {
3041 case '1': { // Is1 - SSHR.
3042 int shift
= 16 << HighestSetBitPosition(instr
->ImmNEONImmh());
3043 shift
-= instr
->ImmNEONImmhImmb();
3044 AppendToOutput("#%d", shift
);
3047 case '2': { // Is2 - SLI.
3048 int shift
= instr
->ImmNEONImmhImmb();
3049 shift
-= 8 << HighestSetBitPosition(instr
->ImmNEONImmh());
3050 AppendToOutput("#%d", shift
);
3054 VIXL_UNIMPLEMENTED();
3059 case 'D': { // IDebug - HLT and BRK instructions.
3060 AppendToOutput("#0x%" PRIx32
, instr
->ImmException());
3063 case 'V': { // Immediate Vector.
3064 switch (format
[2]) {
3065 case 'E': { // IVExtract.
3066 AppendToOutput("#%" PRId32
, instr
->ImmNEONExt());
3069 case 'B': { // IVByElemIndex.
3070 int vm_index
= (instr
->NEONH() << 1) | instr
->NEONL();
3071 if (instr
->NEONSize() == 1) {
3072 vm_index
= (vm_index
<< 1) | instr
->NEONM();
3074 AppendToOutput("%d", vm_index
);
3075 return strlen("IVByElemIndex");
3077 case 'I': { // INS element.
3078 if (strncmp(format
, "IVInsIndex", strlen("IVInsIndex")) == 0) {
3079 int rd_index
, rn_index
;
3080 int imm5
= instr
->ImmNEON5();
3081 int imm4
= instr
->ImmNEON4();
3082 int tz
= CountTrailingZeros(imm5
, 32);
3083 rd_index
= imm5
>> (tz
+ 1);
3084 rn_index
= imm4
>> tz
;
3085 if (strncmp(format
, "IVInsIndex1", strlen("IVInsIndex1")) == 0) {
3086 AppendToOutput("%d", rd_index
);
3087 return strlen("IVInsIndex1");
3088 } else if (strncmp(format
, "IVInsIndex2",
3089 strlen("IVInsIndex2")) == 0) {
3090 AppendToOutput("%d", rn_index
);
3091 return strlen("IVInsIndex2");
3093 VIXL_UNIMPLEMENTED();
3099 case 'L': { // IVLSLane[0123] - suffix indicates access size shift.
3100 AppendToOutput("%d", instr
->NEONLSIndex(format
[8] - '0'));
3103 case 'M': { // Modified Immediate cases.
3106 strlen("IVMIImmFPSingle")) == 0) {
3107 AppendToOutput("#0x%" PRIx32
" (%.4f)", instr
->ImmNEONabcdefgh(),
3108 instr
->ImmNEONFP32());
3109 return strlen("IVMIImmFPSingle");
3110 } else if (strncmp(format
,
3112 strlen("IVMIImmFPDouble")) == 0) {
3113 AppendToOutput("#0x%" PRIx32
" (%.4f)", instr
->ImmNEONabcdefgh(),
3114 instr
->ImmNEONFP64());
3115 return strlen("IVMIImmFPDouble");
3116 } else if (strncmp(format
, "IVMIImm8", strlen("IVMIImm8")) == 0) {
3117 uint64_t imm8
= instr
->ImmNEONabcdefgh();
3118 AppendToOutput("#0x%" PRIx64
, imm8
);
3119 return strlen("IVMIImm8");
3120 } else if (strncmp(format
, "IVMIImm", strlen("IVMIImm")) == 0) {
3121 uint64_t imm8
= instr
->ImmNEONabcdefgh();
3123 for (int i
= 0; i
< 8; ++i
) {
3124 if (imm8
& (1 << i
)) {
3125 imm
|= (UINT64_C(0xff) << (8 * i
));
3128 AppendToOutput("#0x%" PRIx64
, imm
);
3129 return strlen("IVMIImm");
3130 } else if (strncmp(format
, "IVMIShiftAmt1",
3131 strlen("IVMIShiftAmt1")) == 0) {
3132 int cmode
= instr
->NEONCmode();
3133 int shift_amount
= 8 * ((cmode
>> 1) & 3);
3134 AppendToOutput("#%d", shift_amount
);
3135 return strlen("IVMIShiftAmt1");
3136 } else if (strncmp(format
, "IVMIShiftAmt2",
3137 strlen("IVMIShiftAmt2")) == 0) {
3138 int cmode
= instr
->NEONCmode();
3139 int shift_amount
= 8 << (cmode
& 1);
3140 AppendToOutput("#%d", shift_amount
);
3141 return strlen("IVMIShiftAmt2");
3143 VIXL_UNIMPLEMENTED();
3148 VIXL_UNIMPLEMENTED();
3153 case 'X': { // IX - CLREX instruction.
3154 AppendToOutput("#0x%" PRIx32
, instr
->CRm());
3158 VIXL_UNIMPLEMENTED();
3165 int Disassembler::SubstituteBitfieldImmediateField(const Instruction
* instr
,
3166 const char* format
) {
3167 VIXL_ASSERT((format
[0] == 'I') && (format
[1] == 'B'));
3168 unsigned r
= instr
->ImmR();
3169 unsigned s
= instr
->ImmS();
3171 switch (format
[2]) {
3173 AppendToOutput("#%d", r
);
3176 case 's': { // IBs+1 or IBs-r+1.
3177 if (format
[3] == '+') {
3178 AppendToOutput("#%d", s
+ 1);
3181 VIXL_ASSERT(format
[3] == '-');
3182 AppendToOutput("#%d", s
- r
+ 1);
3186 case 'Z': { // IBZ-r.
3187 VIXL_ASSERT((format
[3] == '-') && (format
[4] == 'r'));
3188 unsigned reg_size
= (instr
->SixtyFourBits() == 1) ? kXRegSize
: kWRegSize
;
3189 AppendToOutput("#%d", reg_size
- r
);
3200 int Disassembler::SubstituteLiteralField(const Instruction
* instr
,
3201 const char* format
) {
3202 VIXL_ASSERT(strncmp(format
, "LValue", 6) == 0);
3205 const void * address
= instr
->LiteralAddress
<const void *>();
3206 switch (instr
->Mask(LoadLiteralMask
)) {
3213 AppendCodeRelativeDataAddressToOutput(instr
, address
);
3216 // Use the prefetch hint to decide how to print the address.
3217 switch (instr
->PrefetchHint()) {
3218 case 0x0: // PLD: prefetch for load.
3219 case 0x2: // PST: prepare for store.
3220 AppendCodeRelativeDataAddressToOutput(instr
, address
);
3222 case 0x1: // PLI: preload instructions.
3223 AppendCodeRelativeCodeAddressToOutput(instr
, address
);
3225 case 0x3: // Unallocated hint.
3226 AppendCodeRelativeAddressToOutput(instr
, address
);
3239 int Disassembler::SubstituteShiftField(const Instruction
* instr
,
3240 const char* format
) {
3241 VIXL_ASSERT(format
[0] == 'N');
3242 VIXL_ASSERT(instr
->ShiftDP() <= 0x3);
3244 switch (format
[1]) {
3246 VIXL_ASSERT(instr
->ShiftDP() != ROR
);
3250 if (instr
->ImmDPShift() != 0) {
3251 const char* shift_type
[] = {"lsl", "lsr", "asr", "ror"};
3252 AppendToOutput(", %s #%" PRId32
, shift_type
[instr
->ShiftDP()],
3253 instr
->ImmDPShift());
3258 VIXL_UNIMPLEMENTED();
3264 int Disassembler::SubstituteConditionField(const Instruction
* instr
,
3265 const char* format
) {
3266 VIXL_ASSERT(format
[0] == 'C');
3267 const char* condition_code
[] = { "eq", "ne", "hs", "lo",
3268 "mi", "pl", "vs", "vc",
3269 "hi", "ls", "ge", "lt",
3270 "gt", "le", "al", "nv" };
3272 switch (format
[1]) {
3273 case 'B': cond
= instr
->ConditionBranch(); break;
3275 cond
= InvertCondition(static_cast<Condition
>(instr
->Condition()));
3278 default: cond
= instr
->Condition();
3280 AppendToOutput("%s", condition_code
[cond
]);
3285 int Disassembler::SubstitutePCRelAddressField(const Instruction
* instr
,
3286 const char* format
) {
3287 VIXL_ASSERT((strcmp(format
, "AddrPCRelByte") == 0) || // Used by `adr`.
3288 (strcmp(format
, "AddrPCRelPage") == 0)); // Used by `adrp`.
3290 int64_t offset
= instr
->ImmPCRel();
3292 // Compute the target address based on the effective address (after applying
3293 // code_address_offset). This is required for correct behaviour of adrp.
3294 const Instruction
* base
= instr
+ code_address_offset();
3295 if (format
[9] == 'P') {
3296 offset
*= kPageSize
;
3297 base
= AlignDown(base
, kPageSize
);
3299 // Strip code_address_offset before printing, so we can use the
3300 // semantically-correct AppendCodeRelativeAddressToOutput.
3301 const void* target
=
3302 reinterpret_cast<const void*>(base
+ offset
- code_address_offset());
3304 AppendPCRelativeOffsetToOutput(instr
, offset
);
3305 AppendToOutput(" ");
3306 AppendCodeRelativeAddressToOutput(instr
, target
);
3311 int Disassembler::SubstituteBranchTargetField(const Instruction
* instr
,
3312 const char* format
) {
3313 VIXL_ASSERT(strncmp(format
, "TImm", 4) == 0);
3316 switch (format
[5]) {
3317 // BImmUncn - unconditional branch immediate.
3318 case 'n': offset
= instr
->ImmUncondBranch(); break;
3319 // BImmCond - conditional branch immediate.
3320 case 'o': offset
= instr
->ImmCondBranch(); break;
3321 // BImmCmpa - compare and branch immediate.
3322 case 'm': offset
= instr
->ImmCmpBranch(); break;
3323 // BImmTest - test and branch immediate.
3324 case 'e': offset
= instr
->ImmTestBranch(); break;
3325 default: VIXL_UNIMPLEMENTED();
3327 offset
<<= kInstructionSizeLog2
;
3328 const void* target_address
= reinterpret_cast<const void*>(instr
+ offset
);
3329 VIXL_STATIC_ASSERT(sizeof(*instr
) == 1);
3331 AppendPCRelativeOffsetToOutput(instr
, offset
);
3332 AppendToOutput(" ");
3333 AppendCodeRelativeCodeAddressToOutput(instr
, target_address
);
3339 int Disassembler::SubstituteExtendField(const Instruction
* instr
,
3340 const char* format
) {
3341 VIXL_ASSERT(strncmp(format
, "Ext", 3) == 0);
3342 VIXL_ASSERT(instr
->ExtendMode() <= 7);
3345 const char* extend_mode
[] = { "uxtb", "uxth", "uxtw", "uxtx",
3346 "sxtb", "sxth", "sxtw", "sxtx" };
3348 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
3349 // registers becomes lsl.
3350 if (((instr
->Rd() == kZeroRegCode
) || (instr
->Rn() == kZeroRegCode
)) &&
3351 (((instr
->ExtendMode() == UXTW
) && (instr
->SixtyFourBits() == 0)) ||
3352 (instr
->ExtendMode() == UXTX
))) {
3353 if (instr
->ImmExtendShift() > 0) {
3354 AppendToOutput(", lsl #%" PRId32
, instr
->ImmExtendShift());
3357 AppendToOutput(", %s", extend_mode
[instr
->ExtendMode()]);
3358 if (instr
->ImmExtendShift() > 0) {
3359 AppendToOutput(" #%" PRId32
, instr
->ImmExtendShift());
3366 int Disassembler::SubstituteLSRegOffsetField(const Instruction
* instr
,
3367 const char* format
) {
3368 VIXL_ASSERT(strncmp(format
, "Offsetreg", 9) == 0);
3369 const char* extend_mode
[] = { "undefined", "undefined", "uxtw", "lsl",
3370 "undefined", "undefined", "sxtw", "sxtx" };
3373 unsigned shift
= instr
->ImmShiftLS();
3374 Extend ext
= static_cast<Extend
>(instr
->ExtendMode());
3375 char reg_type
= ((ext
== UXTW
) || (ext
== SXTW
)) ? 'w' : 'x';
3377 unsigned rm
= instr
->Rm();
3378 if (rm
== kZeroRegCode
) {
3379 AppendToOutput("%czr", reg_type
);
3381 AppendToOutput("%c%d", reg_type
, rm
);
3384 // Extend mode UXTX is an alias for shift mode LSL here.
3385 if (!((ext
== UXTX
) && (shift
== 0))) {
3386 AppendToOutput(", %s", extend_mode
[ext
]);
3388 AppendToOutput(" #%d", instr
->SizeLS());
3395 int Disassembler::SubstitutePrefetchField(const Instruction
* instr
,
3396 const char* format
) {
3397 VIXL_ASSERT(format
[0] == 'P');
3400 static const char* hints
[] = {"ld", "li", "st"};
3401 static const char* stream_options
[] = {"keep", "strm"};
3403 unsigned hint
= instr
->PrefetchHint();
3404 unsigned target
= instr
->PrefetchTarget() + 1;
3405 unsigned stream
= instr
->PrefetchStream();
3407 if ((hint
>= (sizeof(hints
) / sizeof(hints
[0]))) || (target
> 3)) {
3408 // Unallocated prefetch operations.
3409 int prefetch_mode
= instr
->ImmPrefetchOperation();
3410 AppendToOutput("#0b%c%c%c%c%c",
3411 (prefetch_mode
& (1 << 4)) ? '1' : '0',
3412 (prefetch_mode
& (1 << 3)) ? '1' : '0',
3413 (prefetch_mode
& (1 << 2)) ? '1' : '0',
3414 (prefetch_mode
& (1 << 1)) ? '1' : '0',
3415 (prefetch_mode
& (1 << 0)) ? '1' : '0');
3417 VIXL_ASSERT(stream
< (sizeof(stream_options
) / sizeof(stream_options
[0])));
3418 AppendToOutput("p%sl%d%s", hints
[hint
], target
, stream_options
[stream
]);
3423 int Disassembler::SubstituteBarrierField(const Instruction
* instr
,
3424 const char* format
) {
3425 VIXL_ASSERT(format
[0] == 'M');
3428 static const char* options
[4][4] = {
3429 { "sy (0b0000)", "oshld", "oshst", "osh" },
3430 { "sy (0b0100)", "nshld", "nshst", "nsh" },
3431 { "sy (0b1000)", "ishld", "ishst", "ish" },
3432 { "sy (0b1100)", "ld", "st", "sy" }
3434 int domain
= instr
->ImmBarrierDomain();
3435 int type
= instr
->ImmBarrierType();
3437 AppendToOutput("%s", options
[domain
][type
]);
3441 int Disassembler::SubstituteSysOpField(const Instruction
* instr
,
3442 const char* format
) {
3443 VIXL_ASSERT(format
[0] == 'G');
3445 switch (format
[1]) {
3446 case '1': op
= instr
->SysOp1(); break;
3447 case '2': op
= instr
->SysOp2(); break;
3451 AppendToOutput("#%d", op
);
3455 int Disassembler::SubstituteCrField(const Instruction
* instr
,
3456 const char* format
) {
3457 VIXL_ASSERT(format
[0] == 'K');
3459 switch (format
[1]) {
3460 case 'n': cr
= instr
->CRn(); break;
3461 case 'm': cr
= instr
->CRm(); break;
3465 AppendToOutput("C%d", cr
);
3469 void Disassembler::ResetOutput() {
3471 buffer_
[buffer_pos_
] = 0;
3475 void Disassembler::AppendToOutput(const char* format
, ...) {
3477 va_start(args
, format
);
3478 buffer_pos_
+= vsnprintf(&buffer_
[buffer_pos_
], buffer_size_
- buffer_pos_
,
3484 void PrintDisassembler::ProcessOutput(const Instruction
* instr
) {
3485 fprintf(stream_
, "0x%016" PRIx64
" %08" PRIx32
"\t\t%s\n",
3486 reinterpret_cast<uint64_t>(instr
),
3487 instr
->InstructionBits(),