OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <assert.h> | 5 #include <assert.h> |
6 #include <stdarg.h> | 6 #include <stdarg.h> |
7 #include <stdio.h> | 7 #include <stdio.h> |
8 #include <string.h> | 8 #include <string.h> |
9 | 9 |
10 #if V8_TARGET_ARCH_ARM64 | 10 #if V8_TARGET_ARCH_ARM64 |
11 | 11 |
12 #include "src/arm64/decoder-arm64-inl.h" | 12 #include "src/arm64/decoder-arm64-inl.h" |
13 #include "src/arm64/disasm-arm64.h" | 13 #include "src/arm64/disasm-arm64.h" |
14 #include "src/arm64/utils-arm64.h" | |
15 #include "src/base/platform/platform.h" | 14 #include "src/base/platform/platform.h" |
16 #include "src/disasm.h" | 15 #include "src/disasm.h" |
17 #include "src/macro-assembler.h" | 16 #include "src/macro-assembler.h" |
18 | 17 |
19 namespace v8 { | 18 namespace v8 { |
20 namespace internal { | 19 namespace internal { |
21 | 20 |
22 | 21 |
23 DisassemblingDecoder::DisassemblingDecoder() { | 22 DisassemblingDecoder::DisassemblingDecoder() { |
24 buffer_size_ = 256; | 23 buffer_size_ = 256; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 default: UNREACHABLE(); | 87 default: UNREACHABLE(); |
89 } | 88 } |
90 Format(instr, mnemonic, form); | 89 Format(instr, mnemonic, form); |
91 } | 90 } |
92 | 91 |
93 | 92 |
94 void DisassemblingDecoder::VisitAddSubShifted(Instruction* instr) { | 93 void DisassemblingDecoder::VisitAddSubShifted(Instruction* instr) { |
95 bool rd_is_zr = RdIsZROrSP(instr); | 94 bool rd_is_zr = RdIsZROrSP(instr); |
96 bool rn_is_zr = RnIsZROrSP(instr); | 95 bool rn_is_zr = RnIsZROrSP(instr); |
97 const char *mnemonic = ""; | 96 const char *mnemonic = ""; |
98 const char* form = "'Rd, 'Rn, 'Rm'NDP"; | 97 const char *form = "'Rd, 'Rn, 'Rm'HDP"; |
99 const char* form_cmp = "'Rn, 'Rm'NDP"; | 98 const char *form_cmp = "'Rn, 'Rm'HDP"; |
100 const char* form_neg = "'Rd, 'Rm'NDP"; | 99 const char *form_neg = "'Rd, 'Rm'HDP"; |
101 | 100 |
102 switch (instr->Mask(AddSubShiftedMask)) { | 101 switch (instr->Mask(AddSubShiftedMask)) { |
103 case ADD_w_shift: | 102 case ADD_w_shift: |
104 case ADD_x_shift: mnemonic = "add"; break; | 103 case ADD_x_shift: mnemonic = "add"; break; |
105 case ADDS_w_shift: | 104 case ADDS_w_shift: |
106 case ADDS_x_shift: { | 105 case ADDS_x_shift: { |
107 mnemonic = "adds"; | 106 mnemonic = "adds"; |
108 if (rd_is_zr) { | 107 if (rd_is_zr) { |
109 mnemonic = "cmn"; | 108 mnemonic = "cmn"; |
110 form = form_cmp; | 109 form = form_cmp; |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 return true; | 279 return true; |
281 } | 280 } |
282 return false; | 281 return false; |
283 } | 282 } |
284 | 283 |
285 | 284 |
286 void DisassemblingDecoder::VisitLogicalShifted(Instruction* instr) { | 285 void DisassemblingDecoder::VisitLogicalShifted(Instruction* instr) { |
287 bool rd_is_zr = RdIsZROrSP(instr); | 286 bool rd_is_zr = RdIsZROrSP(instr); |
288 bool rn_is_zr = RnIsZROrSP(instr); | 287 bool rn_is_zr = RnIsZROrSP(instr); |
289 const char *mnemonic = ""; | 288 const char *mnemonic = ""; |
290 const char* form = "'Rd, 'Rn, 'Rm'NLo"; | 289 const char *form = "'Rd, 'Rn, 'Rm'HLo"; |
291 | 290 |
292 switch (instr->Mask(LogicalShiftedMask)) { | 291 switch (instr->Mask(LogicalShiftedMask)) { |
293 case AND_w: | 292 case AND_w: |
294 case AND_x: mnemonic = "and"; break; | 293 case AND_x: mnemonic = "and"; break; |
295 case BIC_w: | 294 case BIC_w: |
296 case BIC_x: mnemonic = "bic"; break; | 295 case BIC_x: mnemonic = "bic"; break; |
297 case EOR_w: | 296 case EOR_w: |
298 case EOR_x: mnemonic = "eor"; break; | 297 case EOR_x: mnemonic = "eor"; break; |
299 case EON_w: | 298 case EON_w: |
300 case EON_x: mnemonic = "eon"; break; | 299 case EON_x: mnemonic = "eon"; break; |
301 case BICS_w: | 300 case BICS_w: |
302 case BICS_x: mnemonic = "bics"; break; | 301 case BICS_x: mnemonic = "bics"; break; |
303 case ANDS_w: | 302 case ANDS_w: |
304 case ANDS_x: { | 303 case ANDS_x: { |
305 mnemonic = "ands"; | 304 mnemonic = "ands"; |
306 if (rd_is_zr) { | 305 if (rd_is_zr) { |
307 mnemonic = "tst"; | 306 mnemonic = "tst"; |
308 form = "'Rn, 'Rm'NLo"; | 307 form = "'Rn, 'Rm'HLo"; |
309 } | 308 } |
310 break; | 309 break; |
311 } | 310 } |
312 case ORR_w: | 311 case ORR_w: |
313 case ORR_x: { | 312 case ORR_x: { |
314 mnemonic = "orr"; | 313 mnemonic = "orr"; |
315 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) { | 314 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) { |
316 mnemonic = "mov"; | 315 mnemonic = "mov"; |
317 form = "'Rd, 'Rm"; | 316 form = "'Rd, 'Rm"; |
318 } | 317 } |
319 break; | 318 break; |
320 } | 319 } |
321 case ORN_w: | 320 case ORN_w: |
322 case ORN_x: { | 321 case ORN_x: { |
323 mnemonic = "orn"; | 322 mnemonic = "orn"; |
324 if (rn_is_zr) { | 323 if (rn_is_zr) { |
325 mnemonic = "mvn"; | 324 mnemonic = "mvn"; |
326 form = "'Rd, 'Rm'NLo"; | 325 form = "'Rd, 'Rm'HLo"; |
327 } | 326 } |
328 break; | 327 break; |
329 } | 328 } |
330 default: UNREACHABLE(); | 329 default: UNREACHABLE(); |
331 } | 330 } |
332 | 331 |
333 Format(instr, mnemonic, form); | 332 Format(instr, mnemonic, form); |
334 } | 333 } |
335 | 334 |
336 | 335 |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
521 switch (instr->Mask(PCRelAddressingMask)) { | 520 switch (instr->Mask(PCRelAddressingMask)) { |
522 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break; | 521 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break; |
523 // ADRP is not implemented. | 522 // ADRP is not implemented. |
524 default: Format(instr, "unimplemented", "(PCRelAddressing)"); | 523 default: Format(instr, "unimplemented", "(PCRelAddressing)"); |
525 } | 524 } |
526 } | 525 } |
527 | 526 |
528 | 527 |
529 void DisassemblingDecoder::VisitConditionalBranch(Instruction* instr) { | 528 void DisassemblingDecoder::VisitConditionalBranch(Instruction* instr) { |
530 switch (instr->Mask(ConditionalBranchMask)) { | 529 switch (instr->Mask(ConditionalBranchMask)) { |
531 case B_cond: | 530 case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break; |
532 Format(instr, "b.'CBrn", "'TImmCond"); | |
533 break; | |
534 default: UNREACHABLE(); | 531 default: UNREACHABLE(); |
535 } | 532 } |
536 } | 533 } |
537 | 534 |
538 | 535 |
539 void DisassemblingDecoder::VisitUnconditionalBranchToRegister( | 536 void DisassemblingDecoder::VisitUnconditionalBranchToRegister( |
540 Instruction* instr) { | 537 Instruction* instr) { |
541 const char *mnemonic = "unimplemented"; | 538 const char *mnemonic = "unimplemented"; |
542 const char *form = "'Xn"; | 539 const char *form = "'Xn"; |
543 | 540 |
544 switch (instr->Mask(UnconditionalBranchToRegisterMask)) { | 541 switch (instr->Mask(UnconditionalBranchToRegisterMask)) { |
545 case BR: mnemonic = "br"; break; | 542 case BR: mnemonic = "br"; break; |
546 case BLR: mnemonic = "blr"; break; | 543 case BLR: mnemonic = "blr"; break; |
547 case RET: { | 544 case RET: { |
548 mnemonic = "ret"; | 545 mnemonic = "ret"; |
549 if (instr->Rn() == kLinkRegCode) { | 546 if (instr->Rn() == kLinkRegCode) { |
550 form = NULL; | 547 form = NULL; |
551 } | 548 } |
552 break; | 549 break; |
553 } | 550 } |
554 default: form = "(UnconditionalBranchToRegister)"; | 551 default: form = "(UnconditionalBranchToRegister)"; |
555 } | 552 } |
556 Format(instr, mnemonic, form); | 553 Format(instr, mnemonic, form); |
557 } | 554 } |
558 | 555 |
559 | 556 |
560 void DisassemblingDecoder::VisitUnconditionalBranch(Instruction* instr) { | 557 void DisassemblingDecoder::VisitUnconditionalBranch(Instruction* instr) { |
561 const char *mnemonic = ""; | 558 const char *mnemonic = ""; |
562 const char* form = "'TImmUncn"; | 559 const char *form = "'BImmUncn"; |
563 | 560 |
564 switch (instr->Mask(UnconditionalBranchMask)) { | 561 switch (instr->Mask(UnconditionalBranchMask)) { |
565 case B: mnemonic = "b"; break; | 562 case B: mnemonic = "b"; break; |
566 case BL: mnemonic = "bl"; break; | 563 case BL: mnemonic = "bl"; break; |
567 default: UNREACHABLE(); | 564 default: UNREACHABLE(); |
568 } | 565 } |
569 Format(instr, mnemonic, form); | 566 Format(instr, mnemonic, form); |
570 } | 567 } |
571 | 568 |
572 | 569 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 break; | 682 break; |
686 } | 683 } |
687 default: UNREACHABLE(); | 684 default: UNREACHABLE(); |
688 } | 685 } |
689 Format(instr, mnemonic, form); | 686 Format(instr, mnemonic, form); |
690 } | 687 } |
691 | 688 |
692 | 689 |
693 void DisassemblingDecoder::VisitCompareBranch(Instruction* instr) { | 690 void DisassemblingDecoder::VisitCompareBranch(Instruction* instr) { |
694 const char *mnemonic = ""; | 691 const char *mnemonic = ""; |
695 const char* form = "'Rt, 'TImmCmpa"; | 692 const char *form = "'Rt, 'BImmCmpa"; |
696 | 693 |
697 switch (instr->Mask(CompareBranchMask)) { | 694 switch (instr->Mask(CompareBranchMask)) { |
698 case CBZ_w: | 695 case CBZ_w: |
699 case CBZ_x: mnemonic = "cbz"; break; | 696 case CBZ_x: mnemonic = "cbz"; break; |
700 case CBNZ_w: | 697 case CBNZ_w: |
701 case CBNZ_x: mnemonic = "cbnz"; break; | 698 case CBNZ_x: mnemonic = "cbnz"; break; |
702 default: UNREACHABLE(); | 699 default: UNREACHABLE(); |
703 } | 700 } |
704 Format(instr, mnemonic, form); | 701 Format(instr, mnemonic, form); |
705 } | 702 } |
706 | 703 |
707 | 704 |
708 void DisassemblingDecoder::VisitTestBranch(Instruction* instr) { | 705 void DisassemblingDecoder::VisitTestBranch(Instruction* instr) { |
709 const char *mnemonic = ""; | 706 const char *mnemonic = ""; |
710 // If the top bit of the immediate is clear, the tested register is | 707 // If the top bit of the immediate is clear, the tested register is |
711 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is | 708 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is |
712 // encoded in bit 31 of the instruction, we can reuse the Rt form, which | 709 // encoded in bit 31 of the instruction, we can reuse the Rt form, which |
713 // uses bit 31 (normally "sf") to choose the register size. | 710 // uses bit 31 (normally "sf") to choose the register size. |
714 const char* form = "'Rt, 'IS, 'TImmTest"; | 711 const char *form = "'Rt, 'IS, 'BImmTest"; |
715 | 712 |
716 switch (instr->Mask(TestBranchMask)) { | 713 switch (instr->Mask(TestBranchMask)) { |
717 case TBZ: mnemonic = "tbz"; break; | 714 case TBZ: mnemonic = "tbz"; break; |
718 case TBNZ: mnemonic = "tbnz"; break; | 715 case TBNZ: mnemonic = "tbnz"; break; |
719 default: UNREACHABLE(); | 716 default: UNREACHABLE(); |
720 } | 717 } |
721 Format(instr, mnemonic, form); | 718 Format(instr, mnemonic, form); |
722 } | 719 } |
723 | 720 |
724 | 721 |
725 void DisassemblingDecoder::VisitMoveWideImmediate(Instruction* instr) { | 722 void DisassemblingDecoder::VisitMoveWideImmediate(Instruction* instr) { |
726 const char *mnemonic = ""; | 723 const char *mnemonic = ""; |
727 const char *form = "'Rd, 'IMoveImm"; | 724 const char *form = "'Rd, 'IMoveImm"; |
728 | 725 |
729 // Print the shift separately for movk, to make it clear which half word will | 726 // Print the shift separately for movk, to make it clear which half word will |
730 // be overwritten. Movn and movz print the computed immediate, which includes | 727 // be overwritten. Movn and movz print the computed immediate, which includes |
731 // shift calculation. | 728 // shift calculation. |
732 switch (instr->Mask(MoveWideImmediateMask)) { | 729 switch (instr->Mask(MoveWideImmediateMask)) { |
733 case MOVN_w: | 730 case MOVN_w: |
734 case MOVN_x: mnemonic = "movn"; break; | 731 case MOVN_x: mnemonic = "movn"; break; |
735 case MOVZ_w: | 732 case MOVZ_w: |
736 case MOVZ_x: mnemonic = "movz"; break; | 733 case MOVZ_x: mnemonic = "movz"; break; |
737 case MOVK_w: | 734 case MOVK_w: |
738 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break; | 735 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break; |
739 default: UNREACHABLE(); | 736 default: UNREACHABLE(); |
740 } | 737 } |
741 Format(instr, mnemonic, form); | 738 Format(instr, mnemonic, form); |
742 } | 739 } |
743 | 740 |
744 #define LOAD_STORE_LIST(V) \ | 741 |
745 V(STRB_w, "strb", "'Wt") \ | 742 #define LOAD_STORE_LIST(V) \ |
746 V(STRH_w, "strh", "'Wt") \ | 743 V(STRB_w, "strb", "'Wt") \ |
747 V(STR_w, "str", "'Wt") \ | 744 V(STRH_w, "strh", "'Wt") \ |
748 V(STR_x, "str", "'Xt") \ | 745 V(STR_w, "str", "'Wt") \ |
749 V(LDRB_w, "ldrb", "'Wt") \ | 746 V(STR_x, "str", "'Xt") \ |
750 V(LDRH_w, "ldrh", "'Wt") \ | 747 V(LDRB_w, "ldrb", "'Wt") \ |
751 V(LDR_w, "ldr", "'Wt") \ | 748 V(LDRH_w, "ldrh", "'Wt") \ |
752 V(LDR_x, "ldr", "'Xt") \ | 749 V(LDR_w, "ldr", "'Wt") \ |
753 V(LDRSB_x, "ldrsb", "'Xt") \ | 750 V(LDR_x, "ldr", "'Xt") \ |
754 V(LDRSH_x, "ldrsh", "'Xt") \ | 751 V(LDRSB_x, "ldrsb", "'Xt") \ |
755 V(LDRSW_x, "ldrsw", "'Xt") \ | 752 V(LDRSH_x, "ldrsh", "'Xt") \ |
756 V(LDRSB_w, "ldrsb", "'Wt") \ | 753 V(LDRSW_x, "ldrsw", "'Xt") \ |
757 V(LDRSH_w, "ldrsh", "'Wt") \ | 754 V(LDRSB_w, "ldrsb", "'Wt") \ |
758 V(STR_b, "str", "'Bt") \ | 755 V(LDRSH_w, "ldrsh", "'Wt") \ |
759 V(STR_h, "str", "'Ht") \ | 756 V(STR_s, "str", "'St") \ |
760 V(STR_s, "str", "'St") \ | 757 V(STR_d, "str", "'Dt") \ |
761 V(STR_d, "str", "'Dt") \ | 758 V(LDR_s, "ldr", "'St") \ |
762 V(LDR_b, "ldr", "'Bt") \ | 759 V(LDR_d, "ldr", "'Dt") |
763 V(LDR_h, "ldr", "'Ht") \ | |
764 V(LDR_s, "ldr", "'St") \ | |
765 V(LDR_d, "ldr", "'Dt") \ | |
766 V(STR_q, "str", "'Qt") \ | |
767 V(LDR_q, "ldr", "'Qt") | |
768 | 760 |
769 void DisassemblingDecoder::VisitLoadStorePreIndex(Instruction* instr) { | 761 void DisassemblingDecoder::VisitLoadStorePreIndex(Instruction* instr) { |
770 const char *mnemonic = "unimplemented"; | 762 const char *mnemonic = "unimplemented"; |
771 const char *form = "(LoadStorePreIndex)"; | 763 const char *form = "(LoadStorePreIndex)"; |
772 | 764 |
773 switch (instr->Mask(LoadStorePreIndexMask)) { | 765 switch (instr->Mask(LoadStorePreIndexMask)) { |
774 #define LS_PREINDEX(A, B, C) \ | 766 #define LS_PREINDEX(A, B, C) \ |
775 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break; | 767 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break; |
776 LOAD_STORE_LIST(LS_PREINDEX) | 768 LOAD_STORE_LIST(LS_PREINDEX) |
777 #undef LS_PREINDEX | 769 #undef LS_PREINDEX |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
862 switch (instr->Mask(LoadLiteralMask)) { | 854 switch (instr->Mask(LoadLiteralMask)) { |
863 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break; | 855 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break; |
864 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break; | 856 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break; |
865 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break; | 857 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break; |
866 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break; | 858 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break; |
867 default: mnemonic = "unimplemented"; | 859 default: mnemonic = "unimplemented"; |
868 } | 860 } |
869 Format(instr, mnemonic, form); | 861 Format(instr, mnemonic, form); |
870 } | 862 } |
871 | 863 |
| 864 |
872 #define LOAD_STORE_PAIR_LIST(V) \ | 865 #define LOAD_STORE_PAIR_LIST(V) \ |
873 V(STP_w, "stp", "'Wt, 'Wt2", "2") \ | 866 V(STP_w, "stp", "'Wt, 'Wt2", "4") \ |
874 V(LDP_w, "ldp", "'Wt, 'Wt2", "2") \ | 867 V(LDP_w, "ldp", "'Wt, 'Wt2", "4") \ |
875 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "2") \ | 868 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \ |
876 V(STP_x, "stp", "'Xt, 'Xt2", "3") \ | 869 V(STP_x, "stp", "'Xt, 'Xt2", "8") \ |
877 V(LDP_x, "ldp", "'Xt, 'Xt2", "3") \ | 870 V(LDP_x, "ldp", "'Xt, 'Xt2", "8") \ |
878 V(STP_s, "stp", "'St, 'St2", "2") \ | 871 V(STP_s, "stp", "'St, 'St2", "4") \ |
879 V(LDP_s, "ldp", "'St, 'St2", "2") \ | 872 V(LDP_s, "ldp", "'St, 'St2", "4") \ |
880 V(STP_d, "stp", "'Dt, 'Dt2", "3") \ | 873 V(STP_d, "stp", "'Dt, 'Dt2", "8") \ |
881 V(LDP_d, "ldp", "'Dt, 'Dt2", "3") \ | 874 V(LDP_d, "ldp", "'Dt, 'Dt2", "8") |
882 V(LDP_q, "ldp", "'Qt, 'Qt2", "4") \ | |
883 V(STP_q, "stp", "'Qt, 'Qt2", "4") | |
884 | 875 |
885 void DisassemblingDecoder::VisitLoadStorePairPostIndex(Instruction* instr) { | 876 void DisassemblingDecoder::VisitLoadStorePairPostIndex(Instruction* instr) { |
886 const char *mnemonic = "unimplemented"; | 877 const char *mnemonic = "unimplemented"; |
887 const char *form = "(LoadStorePairPostIndex)"; | 878 const char *form = "(LoadStorePairPostIndex)"; |
888 | 879 |
889 switch (instr->Mask(LoadStorePairPostIndexMask)) { | 880 switch (instr->Mask(LoadStorePairPostIndexMask)) { |
890 #define LSP_POSTINDEX(A, B, C, D) \ | 881 #define LSP_POSTINDEX(A, B, C, D) \ |
891 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break; | 882 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break; |
892 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX) | 883 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX) |
893 #undef LSP_POSTINDEX | 884 #undef LSP_POSTINDEX |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1012 FORMAT(FRINTN, "frintn"); | 1003 FORMAT(FRINTN, "frintn"); |
1013 FORMAT(FRINTP, "frintp"); | 1004 FORMAT(FRINTP, "frintp"); |
1014 FORMAT(FRINTM, "frintm"); | 1005 FORMAT(FRINTM, "frintm"); |
1015 FORMAT(FRINTZ, "frintz"); | 1006 FORMAT(FRINTZ, "frintz"); |
1016 FORMAT(FRINTA, "frinta"); | 1007 FORMAT(FRINTA, "frinta"); |
1017 FORMAT(FRINTX, "frintx"); | 1008 FORMAT(FRINTX, "frintx"); |
1018 FORMAT(FRINTI, "frinti"); | 1009 FORMAT(FRINTI, "frinti"); |
1019 #undef FORMAT | 1010 #undef FORMAT |
1020 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break; | 1011 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break; |
1021 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break; | 1012 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break; |
1022 case FCVT_hs: | |
1023 mnemonic = "fcvt"; | |
1024 form = "'Hd, 'Sn"; | |
1025 break; | |
1026 case FCVT_sh: | |
1027 mnemonic = "fcvt"; | |
1028 form = "'Sd, 'Hn"; | |
1029 break; | |
1030 case FCVT_dh: | |
1031 mnemonic = "fcvt"; | |
1032 form = "'Dd, 'Hn"; | |
1033 break; | |
1034 case FCVT_hd: | |
1035 mnemonic = "fcvt"; | |
1036 form = "'Hd, 'Dn"; | |
1037 break; | |
1038 default: form = "(FPDataProcessing1Source)"; | 1013 default: form = "(FPDataProcessing1Source)"; |
1039 } | 1014 } |
1040 Format(instr, mnemonic, form); | 1015 Format(instr, mnemonic, form); |
1041 } | 1016 } |
1042 | 1017 |
1043 | 1018 |
1044 void DisassemblingDecoder::VisitFPDataProcessing2Source(Instruction* instr) { | 1019 void DisassemblingDecoder::VisitFPDataProcessing2Source(Instruction* instr) { |
1045 const char *mnemonic = ""; | 1020 const char *mnemonic = ""; |
1046 const char *form = "'Fd, 'Fn, 'Fm"; | 1021 const char *form = "'Fd, 'Fn, 'Fm"; |
1047 | 1022 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1101 const char *mnemonic = "unimplemented"; | 1076 const char *mnemonic = "unimplemented"; |
1102 const char *form = "(FPIntegerConvert)"; | 1077 const char *form = "(FPIntegerConvert)"; |
1103 const char *form_rf = "'Rd, 'Fn"; | 1078 const char *form_rf = "'Rd, 'Fn"; |
1104 const char *form_fr = "'Fd, 'Rn"; | 1079 const char *form_fr = "'Fd, 'Rn"; |
1105 | 1080 |
1106 switch (instr->Mask(FPIntegerConvertMask)) { | 1081 switch (instr->Mask(FPIntegerConvertMask)) { |
1107 case FMOV_ws: | 1082 case FMOV_ws: |
1108 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break; | 1083 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break; |
1109 case FMOV_sw: | 1084 case FMOV_sw: |
1110 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break; | 1085 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break; |
1111 case FMOV_d1_x: | |
1112 mnemonic = "fmov"; | |
1113 form = "'Vd.D[1], 'Rn"; | |
1114 break; | |
1115 case FMOV_x_d1: | |
1116 mnemonic = "fmov"; | |
1117 form = "'Rd, 'Vn.D[1]"; | |
1118 break; | |
1119 case FCVTAS_ws: | 1086 case FCVTAS_ws: |
1120 case FCVTAS_xs: | 1087 case FCVTAS_xs: |
1121 case FCVTAS_wd: | 1088 case FCVTAS_wd: |
1122 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break; | 1089 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break; |
1123 case FCVTAU_ws: | 1090 case FCVTAU_ws: |
1124 case FCVTAU_xs: | 1091 case FCVTAU_xs: |
1125 case FCVTAU_wd: | 1092 case FCVTAU_wd: |
1126 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break; | 1093 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break; |
1127 case FCVTMS_ws: | 1094 case FCVTMS_ws: |
1128 case FCVTMS_xs: | 1095 case FCVTMS_xs: |
(...skipping 12 matching lines...) Expand all Loading... |
1141 case FCVTNU_wd: | 1108 case FCVTNU_wd: |
1142 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break; | 1109 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break; |
1143 case FCVTZU_xd: | 1110 case FCVTZU_xd: |
1144 case FCVTZU_ws: | 1111 case FCVTZU_ws: |
1145 case FCVTZU_wd: | 1112 case FCVTZU_wd: |
1146 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break; | 1113 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break; |
1147 case FCVTZS_xd: | 1114 case FCVTZS_xd: |
1148 case FCVTZS_wd: | 1115 case FCVTZS_wd: |
1149 case FCVTZS_xs: | 1116 case FCVTZS_xs: |
1150 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break; | 1117 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break; |
1151 case FCVTPU_xd: | |
1152 case FCVTPU_ws: | |
1153 case FCVTPU_wd: | |
1154 case FCVTPU_xs: | |
1155 mnemonic = "fcvtpu"; | |
1156 form = form_rf; | |
1157 break; | |
1158 case FCVTPS_xd: | |
1159 case FCVTPS_wd: | |
1160 case FCVTPS_xs: | |
1161 case FCVTPS_ws: | |
1162 mnemonic = "fcvtps"; | |
1163 form = form_rf; | |
1164 break; | |
1165 case SCVTF_sw: | 1118 case SCVTF_sw: |
1166 case SCVTF_sx: | 1119 case SCVTF_sx: |
1167 case SCVTF_dw: | 1120 case SCVTF_dw: |
1168 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break; | 1121 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break; |
1169 case UCVTF_sw: | 1122 case UCVTF_sw: |
1170 case UCVTF_sx: | 1123 case UCVTF_sx: |
1171 case UCVTF_dw: | 1124 case UCVTF_dw: |
1172 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break; | 1125 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break; |
1173 } | 1126 } |
1174 Format(instr, mnemonic, form); | 1127 Format(instr, mnemonic, form); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1274 case HVC: mnemonic = "hvc"; break; | 1227 case HVC: mnemonic = "hvc"; break; |
1275 case SMC: mnemonic = "smc"; break; | 1228 case SMC: mnemonic = "smc"; break; |
1276 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break; | 1229 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break; |
1277 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break; | 1230 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break; |
1278 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break; | 1231 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break; |
1279 default: form = "(Exception)"; | 1232 default: form = "(Exception)"; |
1280 } | 1233 } |
1281 Format(instr, mnemonic, form); | 1234 Format(instr, mnemonic, form); |
1282 } | 1235 } |
1283 | 1236 |
1284 void DisassemblingDecoder::VisitNEON3Same(Instruction* instr) { | |
1285 const char* mnemonic = "unimplemented"; | |
1286 const char* form = "'Vd.%s, 'Vn.%s, 'Vm.%s"; | |
1287 NEONFormatDecoder nfd(instr); | |
1288 | |
1289 if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) { | |
1290 switch (instr->Mask(NEON3SameLogicalMask)) { | |
1291 case NEON_AND: | |
1292 mnemonic = "and"; | |
1293 break; | |
1294 case NEON_ORR: | |
1295 mnemonic = "orr"; | |
1296 if (instr->Rm() == instr->Rn()) { | |
1297 mnemonic = "mov"; | |
1298 form = "'Vd.%s, 'Vn.%s"; | |
1299 } | |
1300 break; | |
1301 case NEON_ORN: | |
1302 mnemonic = "orn"; | |
1303 break; | |
1304 case NEON_EOR: | |
1305 mnemonic = "eor"; | |
1306 break; | |
1307 case NEON_BIC: | |
1308 mnemonic = "bic"; | |
1309 break; | |
1310 case NEON_BIF: | |
1311 mnemonic = "bif"; | |
1312 break; | |
1313 case NEON_BIT: | |
1314 mnemonic = "bit"; | |
1315 break; | |
1316 case NEON_BSL: | |
1317 mnemonic = "bsl"; | |
1318 break; | |
1319 default: | |
1320 form = "(NEON3Same)"; | |
1321 } | |
1322 nfd.SetFormatMaps(nfd.LogicalFormatMap()); | |
1323 } else { | |
1324 static const char* mnemonics[] = { | |
1325 "shadd", "uhadd", "shadd", "uhadd", | |
1326 "sqadd", "uqadd", "sqadd", "uqadd", | |
1327 "srhadd", "urhadd", "srhadd", "urhadd", | |
1328 NULL, NULL, NULL, | |
1329 NULL, // Handled by logical cases above. | |
1330 "shsub", "uhsub", "shsub", "uhsub", | |
1331 "sqsub", "uqsub", "sqsub", "uqsub", | |
1332 "cmgt", "cmhi", "cmgt", "cmhi", | |
1333 "cmge", "cmhs", "cmge", "cmhs", | |
1334 "sshl", "ushl", "sshl", "ushl", | |
1335 "sqshl", "uqshl", "sqshl", "uqshl", | |
1336 "srshl", "urshl", "srshl", "urshl", | |
1337 "sqrshl", "uqrshl", "sqrshl", "uqrshl", | |
1338 "smax", "umax", "smax", "umax", | |
1339 "smin", "umin", "smin", "umin", | |
1340 "sabd", "uabd", "sabd", "uabd", | |
1341 "saba", "uaba", "saba", "uaba", | |
1342 "add", "sub", "add", "sub", | |
1343 "cmtst", "cmeq", "cmtst", "cmeq", | |
1344 "mla", "mls", "mla", "mls", | |
1345 "mul", "pmul", "mul", "pmul", | |
1346 "smaxp", "umaxp", "smaxp", "umaxp", | |
1347 "sminp", "uminp", "sminp", "uminp", | |
1348 "sqdmulh", "sqrdmulh", "sqdmulh", "sqrdmulh", | |
1349 "addp", "unallocated", "addp", "unallocated", | |
1350 "fmaxnm", "fmaxnmp", "fminnm", "fminnmp", | |
1351 "fmla", "unallocated", "fmls", "unallocated", | |
1352 "fadd", "faddp", "fsub", "fabd", | |
1353 "fmulx", "fmul", "unallocated", "unallocated", | |
1354 "fcmeq", "fcmge", "unallocated", "fcmgt", | |
1355 "unallocated", "facge", "unallocated", "facgt", | |
1356 "fmax", "fmaxp", "fmin", "fminp", | |
1357 "frecps", "fdiv", "frsqrts", "unallocated"}; | |
1358 | |
1359 // Operation is determined by the opcode bits (15-11), the top bit of | |
1360 // size (23) and the U bit (29). | |
1361 unsigned index = | |
1362 (instr->Bits(15, 11) << 2) | (instr->Bit(23) << 1) | instr->Bit(29); | |
1363 DCHECK_LT(index, arraysize(mnemonics)); | |
1364 mnemonic = mnemonics[index]; | |
1365 // Assert that index is not one of the previously handled logical | |
1366 // instructions. | |
1367 DCHECK_NOT_NULL(mnemonic); | |
1368 | |
1369 if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) { | |
1370 nfd.SetFormatMaps(nfd.FPFormatMap()); | |
1371 } | |
1372 } | |
1373 Format(instr, mnemonic, nfd.Substitute(form)); | |
1374 } | |
1375 | |
1376 void DisassemblingDecoder::VisitNEON2RegMisc(Instruction* instr) { | |
1377 const char* mnemonic = "unimplemented"; | |
1378 const char* form = "'Vd.%s, 'Vn.%s"; | |
1379 const char* form_cmp_zero = "'Vd.%s, 'Vn.%s, #0"; | |
1380 const char* form_fcmp_zero = "'Vd.%s, 'Vn.%s, #0.0"; | |
1381 NEONFormatDecoder nfd(instr); | |
1382 | |
1383 static const NEONFormatMap map_lp_ta = { | |
1384 {23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}}; | |
1385 | |
1386 static const NEONFormatMap map_cvt_ta = {{22}, {NF_4S, NF_2D}}; | |
1387 | |
1388 static const NEONFormatMap map_cvt_tb = {{22, 30}, | |
1389 {NF_4H, NF_8H, NF_2S, NF_4S}}; | |
1390 | |
1391 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) { | |
1392 // These instructions all use a two bit size field, except NOT and RBIT, | |
1393 // which use the field to encode the operation. | |
1394 switch (instr->Mask(NEON2RegMiscMask)) { | |
1395 case NEON_REV64: | |
1396 mnemonic = "rev64"; | |
1397 break; | |
1398 case NEON_REV32: | |
1399 mnemonic = "rev32"; | |
1400 break; | |
1401 case NEON_REV16: | |
1402 mnemonic = "rev16"; | |
1403 break; | |
1404 case NEON_SADDLP: | |
1405 mnemonic = "saddlp"; | |
1406 nfd.SetFormatMap(0, &map_lp_ta); | |
1407 break; | |
1408 case NEON_UADDLP: | |
1409 mnemonic = "uaddlp"; | |
1410 nfd.SetFormatMap(0, &map_lp_ta); | |
1411 break; | |
1412 case NEON_SUQADD: | |
1413 mnemonic = "suqadd"; | |
1414 break; | |
1415 case NEON_USQADD: | |
1416 mnemonic = "usqadd"; | |
1417 break; | |
1418 case NEON_CLS: | |
1419 mnemonic = "cls"; | |
1420 break; | |
1421 case NEON_CLZ: | |
1422 mnemonic = "clz"; | |
1423 break; | |
1424 case NEON_CNT: | |
1425 mnemonic = "cnt"; | |
1426 break; | |
1427 case NEON_SADALP: | |
1428 mnemonic = "sadalp"; | |
1429 nfd.SetFormatMap(0, &map_lp_ta); | |
1430 break; | |
1431 case NEON_UADALP: | |
1432 mnemonic = "uadalp"; | |
1433 nfd.SetFormatMap(0, &map_lp_ta); | |
1434 break; | |
1435 case NEON_SQABS: | |
1436 mnemonic = "sqabs"; | |
1437 break; | |
1438 case NEON_SQNEG: | |
1439 mnemonic = "sqneg"; | |
1440 break; | |
1441 case NEON_CMGT_zero: | |
1442 mnemonic = "cmgt"; | |
1443 form = form_cmp_zero; | |
1444 break; | |
1445 case NEON_CMGE_zero: | |
1446 mnemonic = "cmge"; | |
1447 form = form_cmp_zero; | |
1448 break; | |
1449 case NEON_CMEQ_zero: | |
1450 mnemonic = "cmeq"; | |
1451 form = form_cmp_zero; | |
1452 break; | |
1453 case NEON_CMLE_zero: | |
1454 mnemonic = "cmle"; | |
1455 form = form_cmp_zero; | |
1456 break; | |
1457 case NEON_CMLT_zero: | |
1458 mnemonic = "cmlt"; | |
1459 form = form_cmp_zero; | |
1460 break; | |
1461 case NEON_ABS: | |
1462 mnemonic = "abs"; | |
1463 break; | |
1464 case NEON_NEG: | |
1465 mnemonic = "neg"; | |
1466 break; | |
1467 case NEON_RBIT_NOT: | |
1468 switch (instr->FPType()) { | |
1469 case 0: | |
1470 mnemonic = "mvn"; | |
1471 break; | |
1472 case 1: | |
1473 mnemonic = "rbit"; | |
1474 break; | |
1475 default: | |
1476 form = "(NEON2RegMisc)"; | |
1477 } | |
1478 nfd.SetFormatMaps(nfd.LogicalFormatMap()); | |
1479 break; | |
1480 } | |
1481 } else { | |
1482 // These instructions all use a one bit size field, except XTN, SQXTUN, | |
1483 // SHLL, SQXTN and UQXTN, which use a two bit size field. | |
1484 nfd.SetFormatMaps(nfd.FPFormatMap()); | |
1485 switch (instr->Mask(NEON2RegMiscFPMask)) { | |
1486 case NEON_FABS: | |
1487 mnemonic = "fabs"; | |
1488 break; | |
1489 case NEON_FNEG: | |
1490 mnemonic = "fneg"; | |
1491 break; | |
1492 case NEON_FCVTN: | |
1493 mnemonic = instr->Mask(NEON_Q) ? "fcvtn2" : "fcvtn"; | |
1494 nfd.SetFormatMap(0, &map_cvt_tb); | |
1495 nfd.SetFormatMap(1, &map_cvt_ta); | |
1496 break; | |
1497 case NEON_FCVTXN: | |
1498 mnemonic = instr->Mask(NEON_Q) ? "fcvtxn2" : "fcvtxn"; | |
1499 nfd.SetFormatMap(0, &map_cvt_tb); | |
1500 nfd.SetFormatMap(1, &map_cvt_ta); | |
1501 break; | |
1502 case NEON_FCVTL: | |
1503 mnemonic = instr->Mask(NEON_Q) ? "fcvtl2" : "fcvtl"; | |
1504 nfd.SetFormatMap(0, &map_cvt_ta); | |
1505 nfd.SetFormatMap(1, &map_cvt_tb); | |
1506 break; | |
1507 case NEON_FRINTN: | |
1508 mnemonic = "frintn"; | |
1509 break; | |
1510 case NEON_FRINTA: | |
1511 mnemonic = "frinta"; | |
1512 break; | |
1513 case NEON_FRINTP: | |
1514 mnemonic = "frintp"; | |
1515 break; | |
1516 case NEON_FRINTM: | |
1517 mnemonic = "frintm"; | |
1518 break; | |
1519 case NEON_FRINTX: | |
1520 mnemonic = "frintx"; | |
1521 break; | |
1522 case NEON_FRINTZ: | |
1523 mnemonic = "frintz"; | |
1524 break; | |
1525 case NEON_FRINTI: | |
1526 mnemonic = "frinti"; | |
1527 break; | |
1528 case NEON_FCVTNS: | |
1529 mnemonic = "fcvtns"; | |
1530 break; | |
1531 case NEON_FCVTNU: | |
1532 mnemonic = "fcvtnu"; | |
1533 break; | |
1534 case NEON_FCVTPS: | |
1535 mnemonic = "fcvtps"; | |
1536 break; | |
1537 case NEON_FCVTPU: | |
1538 mnemonic = "fcvtpu"; | |
1539 break; | |
1540 case NEON_FCVTMS: | |
1541 mnemonic = "fcvtms"; | |
1542 break; | |
1543 case NEON_FCVTMU: | |
1544 mnemonic = "fcvtmu"; | |
1545 break; | |
1546 case NEON_FCVTZS: | |
1547 mnemonic = "fcvtzs"; | |
1548 break; | |
1549 case NEON_FCVTZU: | |
1550 mnemonic = "fcvtzu"; | |
1551 break; | |
1552 case NEON_FCVTAS: | |
1553 mnemonic = "fcvtas"; | |
1554 break; | |
1555 case NEON_FCVTAU: | |
1556 mnemonic = "fcvtau"; | |
1557 break; | |
1558 case NEON_FSQRT: | |
1559 mnemonic = "fsqrt"; | |
1560 break; | |
1561 case NEON_SCVTF: | |
1562 mnemonic = "scvtf"; | |
1563 break; | |
1564 case NEON_UCVTF: | |
1565 mnemonic = "ucvtf"; | |
1566 break; | |
1567 case NEON_URSQRTE: | |
1568 mnemonic = "ursqrte"; | |
1569 break; | |
1570 case NEON_URECPE: | |
1571 mnemonic = "urecpe"; | |
1572 break; | |
1573 case NEON_FRSQRTE: | |
1574 mnemonic = "frsqrte"; | |
1575 break; | |
1576 case NEON_FRECPE: | |
1577 mnemonic = "frecpe"; | |
1578 break; | |
1579 case NEON_FCMGT_zero: | |
1580 mnemonic = "fcmgt"; | |
1581 form = form_fcmp_zero; | |
1582 break; | |
1583 case NEON_FCMGE_zero: | |
1584 mnemonic = "fcmge"; | |
1585 form = form_fcmp_zero; | |
1586 break; | |
1587 case NEON_FCMEQ_zero: | |
1588 mnemonic = "fcmeq"; | |
1589 form = form_fcmp_zero; | |
1590 break; | |
1591 case NEON_FCMLE_zero: | |
1592 mnemonic = "fcmle"; | |
1593 form = form_fcmp_zero; | |
1594 break; | |
1595 case NEON_FCMLT_zero: | |
1596 mnemonic = "fcmlt"; | |
1597 form = form_fcmp_zero; | |
1598 break; | |
1599 default: | |
1600 if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) && | |
1601 (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) { | |
1602 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); | |
1603 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); | |
1604 | |
1605 switch (instr->Mask(NEON2RegMiscMask)) { | |
1606 case NEON_XTN: | |
1607 mnemonic = "xtn"; | |
1608 break; | |
1609 case NEON_SQXTN: | |
1610 mnemonic = "sqxtn"; | |
1611 break; | |
1612 case NEON_UQXTN: | |
1613 mnemonic = "uqxtn"; | |
1614 break; | |
1615 case NEON_SQXTUN: | |
1616 mnemonic = "sqxtun"; | |
1617 break; | |
1618 case NEON_SHLL: | |
1619 mnemonic = "shll"; | |
1620 nfd.SetFormatMap(0, nfd.LongIntegerFormatMap()); | |
1621 nfd.SetFormatMap(1, nfd.IntegerFormatMap()); | |
1622 switch (instr->NEONSize()) { | |
1623 case 0: | |
1624 form = "'Vd.%s, 'Vn.%s, #8"; | |
1625 break; | |
1626 case 1: | |
1627 form = "'Vd.%s, 'Vn.%s, #16"; | |
1628 break; | |
1629 case 2: | |
1630 form = "'Vd.%s, 'Vn.%s, #32"; | |
1631 break; | |
1632 default: | |
1633 Format(instr, "unallocated", "(NEON2RegMisc)"); | |
1634 return; | |
1635 } | |
1636 } | |
1637 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form)); | |
1638 return; | |
1639 } else { | |
1640 form = "(NEON2RegMisc)"; | |
1641 } | |
1642 } | |
1643 } | |
1644 Format(instr, mnemonic, nfd.Substitute(form)); | |
1645 } | |
1646 | |
1647 void DisassemblingDecoder::VisitNEON3Different(Instruction* instr) { | |
1648 const char* mnemonic = "unimplemented"; | |
1649 const char* form = "'Vd.%s, 'Vn.%s, 'Vm.%s"; | |
1650 | |
1651 NEONFormatDecoder nfd(instr); | |
1652 nfd.SetFormatMap(0, nfd.LongIntegerFormatMap()); | |
1653 | |
1654 // Ignore the Q bit. Appending a "2" suffix is handled later. | |
1655 switch (instr->Mask(NEON3DifferentMask) & ~NEON_Q) { | |
1656 case NEON_PMULL: | |
1657 mnemonic = "pmull"; | |
1658 break; | |
1659 case NEON_SABAL: | |
1660 mnemonic = "sabal"; | |
1661 break; | |
1662 case NEON_SABDL: | |
1663 mnemonic = "sabdl"; | |
1664 break; | |
1665 case NEON_SADDL: | |
1666 mnemonic = "saddl"; | |
1667 break; | |
1668 case NEON_SMLAL: | |
1669 mnemonic = "smlal"; | |
1670 break; | |
1671 case NEON_SMLSL: | |
1672 mnemonic = "smlsl"; | |
1673 break; | |
1674 case NEON_SMULL: | |
1675 mnemonic = "smull"; | |
1676 break; | |
1677 case NEON_SSUBL: | |
1678 mnemonic = "ssubl"; | |
1679 break; | |
1680 case NEON_SQDMLAL: | |
1681 mnemonic = "sqdmlal"; | |
1682 break; | |
1683 case NEON_SQDMLSL: | |
1684 mnemonic = "sqdmlsl"; | |
1685 break; | |
1686 case NEON_SQDMULL: | |
1687 mnemonic = "sqdmull"; | |
1688 break; | |
1689 case NEON_UABAL: | |
1690 mnemonic = "uabal"; | |
1691 break; | |
1692 case NEON_UABDL: | |
1693 mnemonic = "uabdl"; | |
1694 break; | |
1695 case NEON_UADDL: | |
1696 mnemonic = "uaddl"; | |
1697 break; | |
1698 case NEON_UMLAL: | |
1699 mnemonic = "umlal"; | |
1700 break; | |
1701 case NEON_UMLSL: | |
1702 mnemonic = "umlsl"; | |
1703 break; | |
1704 case NEON_UMULL: | |
1705 mnemonic = "umull"; | |
1706 break; | |
1707 case NEON_USUBL: | |
1708 mnemonic = "usubl"; | |
1709 break; | |
1710 case NEON_SADDW: | |
1711 mnemonic = "saddw"; | |
1712 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); | |
1713 break; | |
1714 case NEON_SSUBW: | |
1715 mnemonic = "ssubw"; | |
1716 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); | |
1717 break; | |
1718 case NEON_UADDW: | |
1719 mnemonic = "uaddw"; | |
1720 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); | |
1721 break; | |
1722 case NEON_USUBW: | |
1723 mnemonic = "usubw"; | |
1724 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); | |
1725 break; | |
1726 case NEON_ADDHN: | |
1727 mnemonic = "addhn"; | |
1728 nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); | |
1729 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); | |
1730 break; | |
1731 case NEON_RADDHN: | |
1732 mnemonic = "raddhn"; | |
1733 nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); | |
1734 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); | |
1735 break; | |
1736 case NEON_RSUBHN: | |
1737 mnemonic = "rsubhn"; | |
1738 nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); | |
1739 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); | |
1740 break; | |
1741 case NEON_SUBHN: | |
1742 mnemonic = "subhn"; | |
1743 nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); | |
1744 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); | |
1745 break; | |
1746 default: | |
1747 form = "(NEON3Different)"; | |
1748 } | |
1749 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form)); | |
1750 } | |
1751 | |
1752 void DisassemblingDecoder::VisitNEONAcrossLanes(Instruction* instr) { | |
1753 const char* mnemonic = "unimplemented"; | |
1754 const char* form = "%sd, 'Vn.%s"; | |
1755 | |
1756 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap(), | |
1757 NEONFormatDecoder::IntegerFormatMap()); | |
1758 | |
1759 if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) { | |
1760 nfd.SetFormatMap(0, nfd.FPScalarFormatMap()); | |
1761 nfd.SetFormatMap(1, nfd.FPFormatMap()); | |
1762 switch (instr->Mask(NEONAcrossLanesFPMask)) { | |
1763 case NEON_FMAXV: | |
1764 mnemonic = "fmaxv"; | |
1765 break; | |
1766 case NEON_FMINV: | |
1767 mnemonic = "fminv"; | |
1768 break; | |
1769 case NEON_FMAXNMV: | |
1770 mnemonic = "fmaxnmv"; | |
1771 break; | |
1772 case NEON_FMINNMV: | |
1773 mnemonic = "fminnmv"; | |
1774 break; | |
1775 default: | |
1776 form = "(NEONAcrossLanes)"; | |
1777 break; | |
1778 } | |
1779 } else if (instr->Mask(NEONAcrossLanesFMask) == NEONAcrossLanesFixed) { | |
1780 switch (instr->Mask(NEONAcrossLanesMask)) { | |
1781 case NEON_ADDV: | |
1782 mnemonic = "addv"; | |
1783 break; | |
1784 case NEON_SMAXV: | |
1785 mnemonic = "smaxv"; | |
1786 break; | |
1787 case NEON_SMINV: | |
1788 mnemonic = "sminv"; | |
1789 break; | |
1790 case NEON_UMAXV: | |
1791 mnemonic = "umaxv"; | |
1792 break; | |
1793 case NEON_UMINV: | |
1794 mnemonic = "uminv"; | |
1795 break; | |
1796 case NEON_SADDLV: | |
1797 mnemonic = "saddlv"; | |
1798 nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); | |
1799 break; | |
1800 case NEON_UADDLV: | |
1801 mnemonic = "uaddlv"; | |
1802 nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); | |
1803 break; | |
1804 default: | |
1805 form = "(NEONAcrossLanes)"; | |
1806 break; | |
1807 } | |
1808 } | |
1809 Format(instr, mnemonic, | |
1810 nfd.Substitute(form, NEONFormatDecoder::kPlaceholder, | |
1811 NEONFormatDecoder::kFormat)); | |
1812 } | |
1813 | |
1814 void DisassemblingDecoder::VisitNEONByIndexedElement(Instruction* instr) { | |
1815 const char* mnemonic = "unimplemented"; | |
1816 bool l_instr = false; | |
1817 bool fp_instr = false; | |
1818 | |
1819 const char* form = "'Vd.%s, 'Vn.%s, 'Ve.%s['IVByElemIndex]"; | |
1820 | |
1821 static const NEONFormatMap map_ta = {{23, 22}, {NF_UNDEF, NF_4S, NF_2D}}; | |
1822 NEONFormatDecoder nfd(instr, &map_ta, NEONFormatDecoder::IntegerFormatMap(), | |
1823 NEONFormatDecoder::ScalarFormatMap()); | |
1824 | |
1825 switch (instr->Mask(NEONByIndexedElementMask)) { | |
1826 case NEON_SMULL_byelement: | |
1827 mnemonic = "smull"; | |
1828 l_instr = true; | |
1829 break; | |
1830 case NEON_UMULL_byelement: | |
1831 mnemonic = "umull"; | |
1832 l_instr = true; | |
1833 break; | |
1834 case NEON_SMLAL_byelement: | |
1835 mnemonic = "smlal"; | |
1836 l_instr = true; | |
1837 break; | |
1838 case NEON_UMLAL_byelement: | |
1839 mnemonic = "umlal"; | |
1840 l_instr = true; | |
1841 break; | |
1842 case NEON_SMLSL_byelement: | |
1843 mnemonic = "smlsl"; | |
1844 l_instr = true; | |
1845 break; | |
1846 case NEON_UMLSL_byelement: | |
1847 mnemonic = "umlsl"; | |
1848 l_instr = true; | |
1849 break; | |
1850 case NEON_SQDMULL_byelement: | |
1851 mnemonic = "sqdmull"; | |
1852 l_instr = true; | |
1853 break; | |
1854 case NEON_SQDMLAL_byelement: | |
1855 mnemonic = "sqdmlal"; | |
1856 l_instr = true; | |
1857 break; | |
1858 case NEON_SQDMLSL_byelement: | |
1859 mnemonic = "sqdmlsl"; | |
1860 l_instr = true; | |
1861 break; | |
1862 case NEON_MUL_byelement: | |
1863 mnemonic = "mul"; | |
1864 break; | |
1865 case NEON_MLA_byelement: | |
1866 mnemonic = "mla"; | |
1867 break; | |
1868 case NEON_MLS_byelement: | |
1869 mnemonic = "mls"; | |
1870 break; | |
1871 case NEON_SQDMULH_byelement: | |
1872 mnemonic = "sqdmulh"; | |
1873 break; | |
1874 case NEON_SQRDMULH_byelement: | |
1875 mnemonic = "sqrdmulh"; | |
1876 break; | |
1877 default: | |
1878 switch (instr->Mask(NEONByIndexedElementFPMask)) { | |
1879 case NEON_FMUL_byelement: | |
1880 mnemonic = "fmul"; | |
1881 fp_instr = true; | |
1882 break; | |
1883 case NEON_FMLA_byelement: | |
1884 mnemonic = "fmla"; | |
1885 fp_instr = true; | |
1886 break; | |
1887 case NEON_FMLS_byelement: | |
1888 mnemonic = "fmls"; | |
1889 fp_instr = true; | |
1890 break; | |
1891 case NEON_FMULX_byelement: | |
1892 mnemonic = "fmulx"; | |
1893 fp_instr = true; | |
1894 break; | |
1895 } | |
1896 } | |
1897 | |
1898 if (l_instr) { | |
1899 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form)); | |
1900 } else if (fp_instr) { | |
1901 nfd.SetFormatMap(0, nfd.FPFormatMap()); | |
1902 Format(instr, mnemonic, nfd.Substitute(form)); | |
1903 } else { | |
1904 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); | |
1905 Format(instr, mnemonic, nfd.Substitute(form)); | |
1906 } | |
1907 } | |
1908 | |
1909 void DisassemblingDecoder::VisitNEONCopy(Instruction* instr) { | |
1910 const char* mnemonic = "unimplemented"; | |
1911 const char* form = "(NEONCopy)"; | |
1912 | |
1913 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap(), | |
1914 NEONFormatDecoder::TriangularScalarFormatMap()); | |
1915 | |
1916 if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) { | |
1917 mnemonic = "mov"; | |
1918 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); | |
1919 form = "'Vd.%s['IVInsIndex1], 'Vn.%s['IVInsIndex2]"; | |
1920 } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) { | |
1921 mnemonic = "mov"; | |
1922 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); | |
1923 if (nfd.GetVectorFormat() == kFormatD) { | |
1924 form = "'Vd.%s['IVInsIndex1], 'Xn"; | |
1925 } else { | |
1926 form = "'Vd.%s['IVInsIndex1], 'Wn"; | |
1927 } | |
1928 } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) { | |
1929 if (instr->Mask(NEON_Q) || ((instr->ImmNEON5() & 7) == 4)) { | |
1930 mnemonic = "mov"; | |
1931 } else { | |
1932 mnemonic = "umov"; | |
1933 } | |
1934 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); | |
1935 if (nfd.GetVectorFormat() == kFormatD) { | |
1936 form = "'Xd, 'Vn.%s['IVInsIndex1]"; | |
1937 } else { | |
1938 form = "'Wd, 'Vn.%s['IVInsIndex1]"; | |
1939 } | |
1940 } else if (instr->Mask(NEONCopySmovMask) == NEON_SMOV) { | |
1941 mnemonic = "smov"; | |
1942 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); | |
1943 form = "'Rdq, 'Vn.%s['IVInsIndex1]"; | |
1944 } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) { | |
1945 mnemonic = "dup"; | |
1946 form = "'Vd.%s, 'Vn.%s['IVInsIndex1]"; | |
1947 } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) { | |
1948 mnemonic = "dup"; | |
1949 if (nfd.GetVectorFormat() == kFormat2D) { | |
1950 form = "'Vd.%s, 'Xn"; | |
1951 } else { | |
1952 form = "'Vd.%s, 'Wn"; | |
1953 } | |
1954 } | |
1955 Format(instr, mnemonic, nfd.Substitute(form)); | |
1956 } | |
1957 | |
1958 void DisassemblingDecoder::VisitNEONExtract(Instruction* instr) { | |
1959 const char* mnemonic = "unimplemented"; | |
1960 const char* form = "(NEONExtract)"; | |
1961 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap()); | |
1962 if (instr->Mask(NEONExtractMask) == NEON_EXT) { | |
1963 mnemonic = "ext"; | |
1964 form = "'Vd.%s, 'Vn.%s, 'Vm.%s, 'IVExtract"; | |
1965 } | |
1966 Format(instr, mnemonic, nfd.Substitute(form)); | |
1967 } | |
1968 | |
1969 void DisassemblingDecoder::VisitNEONLoadStoreMultiStruct(Instruction* instr) { | |
1970 const char* mnemonic = NULL; | |
1971 const char* form = NULL; | |
1972 const char* form_1v = "{'Vt.%1$s}, ['Xns]"; | |
1973 const char* form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns]"; | |
1974 const char* form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns]"; | |
1975 const char* form_4v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]"; | |
1976 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); | |
1977 | |
1978 switch (instr->Mask(NEONLoadStoreMultiStructMask)) { | |
1979 case NEON_LD1_1v: | |
1980 mnemonic = "ld1"; | |
1981 form = form_1v; | |
1982 break; | |
1983 case NEON_LD1_2v: | |
1984 mnemonic = "ld1"; | |
1985 form = form_2v; | |
1986 break; | |
1987 case NEON_LD1_3v: | |
1988 mnemonic = "ld1"; | |
1989 form = form_3v; | |
1990 break; | |
1991 case NEON_LD1_4v: | |
1992 mnemonic = "ld1"; | |
1993 form = form_4v; | |
1994 break; | |
1995 case NEON_LD2: | |
1996 mnemonic = "ld2"; | |
1997 form = form_2v; | |
1998 break; | |
1999 case NEON_LD3: | |
2000 mnemonic = "ld3"; | |
2001 form = form_3v; | |
2002 break; | |
2003 case NEON_LD4: | |
2004 mnemonic = "ld4"; | |
2005 form = form_4v; | |
2006 break; | |
2007 case NEON_ST1_1v: | |
2008 mnemonic = "st1"; | |
2009 form = form_1v; | |
2010 break; | |
2011 case NEON_ST1_2v: | |
2012 mnemonic = "st1"; | |
2013 form = form_2v; | |
2014 break; | |
2015 case NEON_ST1_3v: | |
2016 mnemonic = "st1"; | |
2017 form = form_3v; | |
2018 break; | |
2019 case NEON_ST1_4v: | |
2020 mnemonic = "st1"; | |
2021 form = form_4v; | |
2022 break; | |
2023 case NEON_ST2: | |
2024 mnemonic = "st2"; | |
2025 form = form_2v; | |
2026 break; | |
2027 case NEON_ST3: | |
2028 mnemonic = "st3"; | |
2029 form = form_3v; | |
2030 break; | |
2031 case NEON_ST4: | |
2032 mnemonic = "st4"; | |
2033 form = form_4v; | |
2034 break; | |
2035 default: | |
2036 break; | |
2037 } | |
2038 | |
2039 // Work out unallocated encodings. | |
2040 bool allocated = (mnemonic != NULL); | |
2041 switch (instr->Mask(NEONLoadStoreMultiStructMask)) { | |
2042 case NEON_LD2: | |
2043 case NEON_LD3: | |
2044 case NEON_LD4: | |
2045 case NEON_ST2: | |
2046 case NEON_ST3: | |
2047 case NEON_ST4: | |
2048 // LD[2-4] and ST[2-4] cannot use .1d format. | |
2049 allocated = (instr->NEONQ() != 0) || (instr->NEONLSSize() != 3); | |
2050 break; | |
2051 default: | |
2052 break; | |
2053 } | |
2054 if (allocated) { | |
2055 DCHECK_NOT_NULL(mnemonic); | |
2056 DCHECK_NOT_NULL(form); | |
2057 } else { | |
2058 mnemonic = "unallocated"; | |
2059 form = "(NEONLoadStoreMultiStruct)"; | |
2060 } | |
2061 | |
2062 Format(instr, mnemonic, nfd.Substitute(form)); | |
2063 } | |
2064 | |
2065 void DisassemblingDecoder::VisitNEONLoadStoreMultiStructPostIndex( | |
2066 Instruction* instr) { | |
2067 const char* mnemonic = NULL; | |
2068 const char* form = NULL; | |
2069 const char* form_1v = "{'Vt.%1$s}, ['Xns], 'Xmr1"; | |
2070 const char* form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns], 'Xmr2"; | |
2071 const char* form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns], 'Xmr3"; | |
2072 const char* form_4v = | |
2073 "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmr4"; | |
2074 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); | |
2075 | |
2076 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) { | |
2077 case NEON_LD1_1v_post: | |
2078 mnemonic = "ld1"; | |
2079 form = form_1v; | |
2080 break; | |
2081 case NEON_LD1_2v_post: | |
2082 mnemonic = "ld1"; | |
2083 form = form_2v; | |
2084 break; | |
2085 case NEON_LD1_3v_post: | |
2086 mnemonic = "ld1"; | |
2087 form = form_3v; | |
2088 break; | |
2089 case NEON_LD1_4v_post: | |
2090 mnemonic = "ld1"; | |
2091 form = form_4v; | |
2092 break; | |
2093 case NEON_LD2_post: | |
2094 mnemonic = "ld2"; | |
2095 form = form_2v; | |
2096 break; | |
2097 case NEON_LD3_post: | |
2098 mnemonic = "ld3"; | |
2099 form = form_3v; | |
2100 break; | |
2101 case NEON_LD4_post: | |
2102 mnemonic = "ld4"; | |
2103 form = form_4v; | |
2104 break; | |
2105 case NEON_ST1_1v_post: | |
2106 mnemonic = "st1"; | |
2107 form = form_1v; | |
2108 break; | |
2109 case NEON_ST1_2v_post: | |
2110 mnemonic = "st1"; | |
2111 form = form_2v; | |
2112 break; | |
2113 case NEON_ST1_3v_post: | |
2114 mnemonic = "st1"; | |
2115 form = form_3v; | |
2116 break; | |
2117 case NEON_ST1_4v_post: | |
2118 mnemonic = "st1"; | |
2119 form = form_4v; | |
2120 break; | |
2121 case NEON_ST2_post: | |
2122 mnemonic = "st2"; | |
2123 form = form_2v; | |
2124 break; | |
2125 case NEON_ST3_post: | |
2126 mnemonic = "st3"; | |
2127 form = form_3v; | |
2128 break; | |
2129 case NEON_ST4_post: | |
2130 mnemonic = "st4"; | |
2131 form = form_4v; | |
2132 break; | |
2133 default: | |
2134 break; | |
2135 } | |
2136 | |
2137 // Work out unallocated encodings. | |
2138 bool allocated = (mnemonic != NULL); | |
2139 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) { | |
2140 case NEON_LD2_post: | |
2141 case NEON_LD3_post: | |
2142 case NEON_LD4_post: | |
2143 case NEON_ST2_post: | |
2144 case NEON_ST3_post: | |
2145 case NEON_ST4_post: | |
2146 // LD[2-4] and ST[2-4] cannot use .1d format. | |
2147 allocated = (instr->NEONQ() != 0) || (instr->NEONLSSize() != 3); | |
2148 break; | |
2149 default: | |
2150 break; | |
2151 } | |
2152 if (allocated) { | |
2153 DCHECK_NOT_NULL(mnemonic); | |
2154 DCHECK_NOT_NULL(form); | |
2155 } else { | |
2156 mnemonic = "unallocated"; | |
2157 form = "(NEONLoadStoreMultiStructPostIndex)"; | |
2158 } | |
2159 | |
2160 Format(instr, mnemonic, nfd.Substitute(form)); | |
2161 } | |
2162 | |
2163 void DisassemblingDecoder::VisitNEONLoadStoreSingleStruct(Instruction* instr) { | |
2164 const char* mnemonic = NULL; | |
2165 const char* form = NULL; | |
2166 | |
2167 const char* form_1b = "{'Vt.b}['IVLSLane0], ['Xns]"; | |
2168 const char* form_1h = "{'Vt.h}['IVLSLane1], ['Xns]"; | |
2169 const char* form_1s = "{'Vt.s}['IVLSLane2], ['Xns]"; | |
2170 const char* form_1d = "{'Vt.d}['IVLSLane3], ['Xns]"; | |
2171 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); | |
2172 | |
2173 switch (instr->Mask(NEONLoadStoreSingleStructMask)) { | |
2174 case NEON_LD1_b: | |
2175 mnemonic = "ld1"; | |
2176 form = form_1b; | |
2177 break; | |
2178 case NEON_LD1_h: | |
2179 mnemonic = "ld1"; | |
2180 form = form_1h; | |
2181 break; | |
2182 case NEON_LD1_s: | |
2183 mnemonic = "ld1"; | |
2184 static_assert((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d, | |
2185 "LSB of size distinguishes S and D registers."); | |
2186 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; | |
2187 break; | |
2188 case NEON_ST1_b: | |
2189 mnemonic = "st1"; | |
2190 form = form_1b; | |
2191 break; | |
2192 case NEON_ST1_h: | |
2193 mnemonic = "st1"; | |
2194 form = form_1h; | |
2195 break; | |
2196 case NEON_ST1_s: | |
2197 mnemonic = "st1"; | |
2198 static_assert((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d, | |
2199 "LSB of size distinguishes S and D registers."); | |
2200 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; | |
2201 break; | |
2202 case NEON_LD1R: | |
2203 mnemonic = "ld1r"; | |
2204 form = "{'Vt.%s}, ['Xns]"; | |
2205 break; | |
2206 case NEON_LD2_b: | |
2207 case NEON_ST2_b: | |
2208 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2"; | |
2209 form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns]"; | |
2210 break; | |
2211 case NEON_LD2_h: | |
2212 case NEON_ST2_h: | |
2213 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2"; | |
2214 form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns]"; | |
2215 break; | |
2216 case NEON_LD2_s: | |
2217 case NEON_ST2_s: | |
2218 static_assert((NEON_ST2_s | (1 << NEONLSSize_offset)) == NEON_ST2_d, | |
2219 "LSB of size distinguishes S and D registers."); | |
2220 static_assert((NEON_LD2_s | (1 << NEONLSSize_offset)) == NEON_LD2_d, | |
2221 "LSB of size distinguishes S and D registers."); | |
2222 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2"; | |
2223 if ((instr->NEONLSSize() & 1) == 0) { | |
2224 form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns]"; | |
2225 } else { | |
2226 form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns]"; | |
2227 } | |
2228 break; | |
2229 case NEON_LD2R: | |
2230 mnemonic = "ld2r"; | |
2231 form = "{'Vt.%s, 'Vt2.%s}, ['Xns]"; | |
2232 break; | |
2233 case NEON_LD3_b: | |
2234 case NEON_ST3_b: | |
2235 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3"; | |
2236 form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns]"; | |
2237 break; | |
2238 case NEON_LD3_h: | |
2239 case NEON_ST3_h: | |
2240 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3"; | |
2241 form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns]"; | |
2242 break; | |
2243 case NEON_LD3_s: | |
2244 case NEON_ST3_s: | |
2245 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3"; | |
2246 if ((instr->NEONLSSize() & 1) == 0) { | |
2247 form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns]"; | |
2248 } else { | |
2249 form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns]"; | |
2250 } | |
2251 break; | |
2252 case NEON_LD3R: | |
2253 mnemonic = "ld3r"; | |
2254 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns]"; | |
2255 break; | |
2256 case NEON_LD4_b: | |
2257 case NEON_ST4_b: | |
2258 mnemonic = (instr->NEONLoad() == 1) ? "ld4" : "st4"; | |
2259 form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns]"; | |
2260 break; | |
2261 case NEON_LD4_h: | |
2262 case NEON_ST4_h: | |
2263 mnemonic = (instr->NEONLoad() == 1) ? "ld4" : "st4"; | |
2264 form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns]"; | |
2265 break; | |
2266 case NEON_LD4_s: | |
2267 case NEON_ST4_s: | |
2268 static_assert((NEON_LD4_s | (1 << NEONLSSize_offset)) == NEON_LD4_d, | |
2269 "LSB of size distinguishes S and D registers."); | |
2270 static_assert((NEON_ST4_s | (1 << NEONLSSize_offset)) == NEON_ST4_d, | |
2271 "LSB of size distinguishes S and D registers."); | |
2272 mnemonic = (instr->NEONLoad() == 1) ? "ld4" : "st4"; | |
2273 if ((instr->NEONLSSize() & 1) == 0) { | |
2274 form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns]"; | |
2275 } else { | |
2276 form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns]"; | |
2277 } | |
2278 break; | |
2279 case NEON_LD4R: | |
2280 mnemonic = "ld4r"; | |
2281 form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]"; | |
2282 break; | |
2283 default: | |
2284 break; | |
2285 } | |
2286 | |
2287 // Work out unallocated encodings. | |
2288 bool allocated = (mnemonic != NULL); | |
2289 switch (instr->Mask(NEONLoadStoreSingleStructMask)) { | |
2290 case NEON_LD1_h: | |
2291 case NEON_LD2_h: | |
2292 case NEON_LD3_h: | |
2293 case NEON_LD4_h: | |
2294 case NEON_ST1_h: | |
2295 case NEON_ST2_h: | |
2296 case NEON_ST3_h: | |
2297 case NEON_ST4_h: | |
2298 DCHECK(allocated); | |
2299 allocated = ((instr->NEONLSSize() & 1) == 0); | |
2300 break; | |
2301 case NEON_LD1_s: | |
2302 case NEON_LD2_s: | |
2303 case NEON_LD3_s: | |
2304 case NEON_LD4_s: | |
2305 case NEON_ST1_s: | |
2306 case NEON_ST2_s: | |
2307 case NEON_ST3_s: | |
2308 case NEON_ST4_s: | |
2309 DCHECK(allocated); | |
2310 allocated = (instr->NEONLSSize() <= 1) && | |
2311 ((instr->NEONLSSize() == 0) || (instr->NEONS() == 0)); | |
2312 break; | |
2313 case NEON_LD1R: | |
2314 case NEON_LD2R: | |
2315 case NEON_LD3R: | |
2316 case NEON_LD4R: | |
2317 DCHECK(allocated); | |
2318 allocated = (instr->NEONS() == 0); | |
2319 break; | |
2320 default: | |
2321 break; | |
2322 } | |
2323 if (allocated) { | |
2324 DCHECK_NOT_NULL(mnemonic); | |
2325 DCHECK_NOT_NULL(form); | |
2326 } else { | |
2327 mnemonic = "unallocated"; | |
2328 form = "(NEONLoadStoreSingleStruct)"; | |
2329 } | |
2330 | |
2331 Format(instr, mnemonic, nfd.Substitute(form)); | |
2332 } | |
2333 | |
2334 void DisassemblingDecoder::VisitNEONLoadStoreSingleStructPostIndex( | |
2335 Instruction* instr) { | |
2336 const char* mnemonic = NULL; | |
2337 const char* form = NULL; | |
2338 | |
2339 const char* form_1b = "{'Vt.b}['IVLSLane0], ['Xns], 'Xmb1"; | |
2340 const char* form_1h = "{'Vt.h}['IVLSLane1], ['Xns], 'Xmb2"; | |
2341 const char* form_1s = "{'Vt.s}['IVLSLane2], ['Xns], 'Xmb4"; | |
2342 const char* form_1d = "{'Vt.d}['IVLSLane3], ['Xns], 'Xmb8"; | |
2343 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); | |
2344 | |
2345 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) { | |
2346 case NEON_LD1_b_post: | |
2347 mnemonic = "ld1"; | |
2348 form = form_1b; | |
2349 break; | |
2350 case NEON_LD1_h_post: | |
2351 mnemonic = "ld1"; | |
2352 form = form_1h; | |
2353 break; | |
2354 case NEON_LD1_s_post: | |
2355 mnemonic = "ld1"; | |
2356 static_assert((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d, | |
2357 "LSB of size distinguishes S and D registers."); | |
2358 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; | |
2359 break; | |
2360 case NEON_ST1_b_post: | |
2361 mnemonic = "st1"; | |
2362 form = form_1b; | |
2363 break; | |
2364 case NEON_ST1_h_post: | |
2365 mnemonic = "st1"; | |
2366 form = form_1h; | |
2367 break; | |
2368 case NEON_ST1_s_post: | |
2369 mnemonic = "st1"; | |
2370 static_assert((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d, | |
2371 "LSB of size distinguishes S and D registers."); | |
2372 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; | |
2373 break; | |
2374 case NEON_LD1R_post: | |
2375 mnemonic = "ld1r"; | |
2376 form = "{'Vt.%s}, ['Xns], 'Xmz1"; | |
2377 break; | |
2378 case NEON_LD2_b_post: | |
2379 case NEON_ST2_b_post: | |
2380 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2"; | |
2381 form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns], 'Xmb2"; | |
2382 break; | |
2383 case NEON_ST2_h_post: | |
2384 case NEON_LD2_h_post: | |
2385 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2"; | |
2386 form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns], 'Xmb4"; | |
2387 break; | |
2388 case NEON_LD2_s_post: | |
2389 case NEON_ST2_s_post: | |
2390 mnemonic = (instr->NEONLoad() == 1) ? "ld2" : "st2"; | |
2391 if ((instr->NEONLSSize() & 1) == 0) | |
2392 form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns], 'Xmb8"; | |
2393 else | |
2394 form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns], 'Xmb16"; | |
2395 break; | |
2396 case NEON_LD2R_post: | |
2397 mnemonic = "ld2r"; | |
2398 form = "{'Vt.%s, 'Vt2.%s}, ['Xns], 'Xmz2"; | |
2399 break; | |
2400 case NEON_LD3_b_post: | |
2401 case NEON_ST3_b_post: | |
2402 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3"; | |
2403 form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns], 'Xmb3"; | |
2404 break; | |
2405 case NEON_LD3_h_post: | |
2406 case NEON_ST3_h_post: | |
2407 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3"; | |
2408 form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns], 'Xmb6"; | |
2409 break; | |
2410 case NEON_LD3_s_post: | |
2411 case NEON_ST3_s_post: | |
2412 mnemonic = (instr->NEONLoad() == 1) ? "ld3" : "st3"; | |
2413 if ((instr->NEONLSSize() & 1) == 0) | |
2414 form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns], 'Xmb12"; | |
2415 else | |
2416 form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns], 'Xmb24"; | |
2417 break; | |
2418 case NEON_LD3R_post: | |
2419 mnemonic = "ld3r"; | |
2420 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns], 'Xmz3"; | |
2421 break; | |
2422 case NEON_LD4_b_post: | |
2423 case NEON_ST4_b_post: | |
2424 mnemonic = (instr->NEONLoad() == 1) ? "ld4" : "st4"; | |
2425 form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns], 'Xmb4"; | |
2426 break; | |
2427 case NEON_LD4_h_post: | |
2428 case NEON_ST4_h_post: | |
2429 mnemonic = (instr->NEONLoad()) == 1 ? "ld4" : "st4"; | |
2430 form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns], 'Xmb8"; | |
2431 break; | |
2432 case NEON_LD4_s_post: | |
2433 case NEON_ST4_s_post: | |
2434 mnemonic = (instr->NEONLoad() == 1) ? "ld4" : "st4"; | |
2435 if ((instr->NEONLSSize() & 1) == 0) | |
2436 form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns], 'Xmb16"; | |
2437 else | |
2438 form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns], 'Xmb32"; | |
2439 break; | |
2440 case NEON_LD4R_post: | |
2441 mnemonic = "ld4r"; | |
2442 form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmz4"; | |
2443 break; | |
2444 default: | |
2445 break; | |
2446 } | |
2447 | |
2448 // Work out unallocated encodings. | |
2449 bool allocated = (mnemonic != NULL); | |
2450 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) { | |
2451 case NEON_LD1_h_post: | |
2452 case NEON_LD2_h_post: | |
2453 case NEON_LD3_h_post: | |
2454 case NEON_LD4_h_post: | |
2455 case NEON_ST1_h_post: | |
2456 case NEON_ST2_h_post: | |
2457 case NEON_ST3_h_post: | |
2458 case NEON_ST4_h_post: | |
2459 DCHECK(allocated); | |
2460 allocated = ((instr->NEONLSSize() & 1) == 0); | |
2461 break; | |
2462 case NEON_LD1_s_post: | |
2463 case NEON_LD2_s_post: | |
2464 case NEON_LD3_s_post: | |
2465 case NEON_LD4_s_post: | |
2466 case NEON_ST1_s_post: | |
2467 case NEON_ST2_s_post: | |
2468 case NEON_ST3_s_post: | |
2469 case NEON_ST4_s_post: | |
2470 DCHECK(allocated); | |
2471 allocated = (instr->NEONLSSize() <= 1) && | |
2472 ((instr->NEONLSSize() == 0) || (instr->NEONS() == 0)); | |
2473 break; | |
2474 case NEON_LD1R_post: | |
2475 case NEON_LD2R_post: | |
2476 case NEON_LD3R_post: | |
2477 case NEON_LD4R_post: | |
2478 DCHECK(allocated); | |
2479 allocated = (instr->NEONS() == 0); | |
2480 break; | |
2481 default: | |
2482 break; | |
2483 } | |
2484 if (allocated) { | |
2485 DCHECK_NOT_NULL(mnemonic); | |
2486 DCHECK_NOT_NULL(form); | |
2487 } else { | |
2488 mnemonic = "unallocated"; | |
2489 form = "(NEONLoadStoreSingleStructPostIndex)"; | |
2490 } | |
2491 | |
2492 Format(instr, mnemonic, nfd.Substitute(form)); | |
2493 } | |
2494 | |
2495 void DisassemblingDecoder::VisitNEONModifiedImmediate(Instruction* instr) { | |
2496 const char* mnemonic = "unimplemented"; | |
2497 const char* form = "'Vt.%s, 'IVMIImm8, lsl 'IVMIShiftAmt1"; | |
2498 | |
2499 int cmode = instr->NEONCmode(); | |
2500 int cmode_3 = (cmode >> 3) & 1; | |
2501 int cmode_2 = (cmode >> 2) & 1; | |
2502 int cmode_1 = (cmode >> 1) & 1; | |
2503 int cmode_0 = cmode & 1; | |
2504 int q = instr->NEONQ(); | |
2505 int op = instr->NEONModImmOp(); | |
2506 | |
2507 static const NEONFormatMap map_b = {{30}, {NF_8B, NF_16B}}; | |
2508 static const NEONFormatMap map_h = {{30}, {NF_4H, NF_8H}}; | |
2509 static const NEONFormatMap map_s = {{30}, {NF_2S, NF_4S}}; | |
2510 NEONFormatDecoder nfd(instr, &map_b); | |
2511 | |
2512 if (cmode_3 == 0) { | |
2513 if (cmode_0 == 0) { | |
2514 mnemonic = (op == 1) ? "mvni" : "movi"; | |
2515 } else { // cmode<0> == '1'. | |
2516 mnemonic = (op == 1) ? "bic" : "orr"; | |
2517 } | |
2518 nfd.SetFormatMap(0, &map_s); | |
2519 } else { // cmode<3> == '1'. | |
2520 if (cmode_2 == 0) { | |
2521 if (cmode_0 == 0) { | |
2522 mnemonic = (op == 1) ? "mvni" : "movi"; | |
2523 } else { // cmode<0> == '1'. | |
2524 mnemonic = (op == 1) ? "bic" : "orr"; | |
2525 } | |
2526 nfd.SetFormatMap(0, &map_h); | |
2527 } else { // cmode<2> == '1'. | |
2528 if (cmode_1 == 0) { | |
2529 mnemonic = (op == 1) ? "mvni" : "movi"; | |
2530 form = "'Vt.%s, 'IVMIImm8, msl 'IVMIShiftAmt2"; | |
2531 nfd.SetFormatMap(0, &map_s); | |
2532 } else { // cmode<1> == '1'. | |
2533 if (cmode_0 == 0) { | |
2534 mnemonic = "movi"; | |
2535 if (op == 0) { | |
2536 form = "'Vt.%s, 'IVMIImm8"; | |
2537 } else { | |
2538 form = (q == 0) ? "'Dd, 'IVMIImm" : "'Vt.2d, 'IVMIImm"; | |
2539 } | |
2540 } else { // cmode<0> == '1' | |
2541 mnemonic = "fmov"; | |
2542 if (op == 0) { | |
2543 form = "'Vt.%s, 'IVMIImmFPSingle"; | |
2544 nfd.SetFormatMap(0, &map_s); | |
2545 } else { | |
2546 if (q == 1) { | |
2547 form = "'Vt.2d, 'IVMIImmFPDouble"; | |
2548 } else { | |
2549 mnemonic = "unallocated"; | |
2550 form = "(NEONModifiedImmediate)"; | |
2551 } | |
2552 } | |
2553 } | |
2554 } | |
2555 } | |
2556 } | |
2557 Format(instr, mnemonic, nfd.Substitute(form)); | |
2558 } | |
2559 | |
2560 void DisassemblingDecoder::VisitNEONPerm(Instruction* instr) { | |
2561 const char* mnemonic = "unimplemented"; | |
2562 const char* form = "'Vd.%s, 'Vn.%s, 'Vm.%s"; | |
2563 NEONFormatDecoder nfd(instr); | |
2564 | |
2565 switch (instr->Mask(NEONPermMask)) { | |
2566 case NEON_TRN1: | |
2567 mnemonic = "trn1"; | |
2568 break; | |
2569 case NEON_TRN2: | |
2570 mnemonic = "trn2"; | |
2571 break; | |
2572 case NEON_UZP1: | |
2573 mnemonic = "uzp1"; | |
2574 break; | |
2575 case NEON_UZP2: | |
2576 mnemonic = "uzp2"; | |
2577 break; | |
2578 case NEON_ZIP1: | |
2579 mnemonic = "zip1"; | |
2580 break; | |
2581 case NEON_ZIP2: | |
2582 mnemonic = "zip2"; | |
2583 break; | |
2584 default: | |
2585 form = "(NEONPerm)"; | |
2586 } | |
2587 Format(instr, mnemonic, nfd.Substitute(form)); | |
2588 } | |
2589 | |
2590 void DisassemblingDecoder::VisitNEONScalar2RegMisc(Instruction* instr) { | |
2591 const char* mnemonic = "unimplemented"; | |
2592 const char* form = "%sd, %sn"; | |
2593 const char* form_0 = "%sd, %sn, #0"; | |
2594 const char* form_fp0 = "%sd, %sn, #0.0"; | |
2595 | |
2596 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); | |
2597 | |
2598 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) { | |
2599 // These instructions all use a two bit size field, except NOT and RBIT, | |
2600 // which use the field to encode the operation. | |
2601 switch (instr->Mask(NEONScalar2RegMiscMask)) { | |
2602 case NEON_CMGT_zero_scalar: | |
2603 mnemonic = "cmgt"; | |
2604 form = form_0; | |
2605 break; | |
2606 case NEON_CMGE_zero_scalar: | |
2607 mnemonic = "cmge"; | |
2608 form = form_0; | |
2609 break; | |
2610 case NEON_CMLE_zero_scalar: | |
2611 mnemonic = "cmle"; | |
2612 form = form_0; | |
2613 break; | |
2614 case NEON_CMLT_zero_scalar: | |
2615 mnemonic = "cmlt"; | |
2616 form = form_0; | |
2617 break; | |
2618 case NEON_CMEQ_zero_scalar: | |
2619 mnemonic = "cmeq"; | |
2620 form = form_0; | |
2621 break; | |
2622 case NEON_NEG_scalar: | |
2623 mnemonic = "neg"; | |
2624 break; | |
2625 case NEON_SQNEG_scalar: | |
2626 mnemonic = "sqneg"; | |
2627 break; | |
2628 case NEON_ABS_scalar: | |
2629 mnemonic = "abs"; | |
2630 break; | |
2631 case NEON_SQABS_scalar: | |
2632 mnemonic = "sqabs"; | |
2633 break; | |
2634 case NEON_SUQADD_scalar: | |
2635 mnemonic = "suqadd"; | |
2636 break; | |
2637 case NEON_USQADD_scalar: | |
2638 mnemonic = "usqadd"; | |
2639 break; | |
2640 default: | |
2641 form = "(NEONScalar2RegMisc)"; | |
2642 } | |
2643 } else { | |
2644 // These instructions all use a one bit size field, except SQXTUN, SQXTN | |
2645 // and UQXTN, which use a two bit size field. | |
2646 nfd.SetFormatMaps(nfd.FPScalarFormatMap()); | |
2647 switch (instr->Mask(NEONScalar2RegMiscFPMask)) { | |
2648 case NEON_FRSQRTE_scalar: | |
2649 mnemonic = "frsqrte"; | |
2650 break; | |
2651 case NEON_FRECPE_scalar: | |
2652 mnemonic = "frecpe"; | |
2653 break; | |
2654 case NEON_SCVTF_scalar: | |
2655 mnemonic = "scvtf"; | |
2656 break; | |
2657 case NEON_UCVTF_scalar: | |
2658 mnemonic = "ucvtf"; | |
2659 break; | |
2660 case NEON_FCMGT_zero_scalar: | |
2661 mnemonic = "fcmgt"; | |
2662 form = form_fp0; | |
2663 break; | |
2664 case NEON_FCMGE_zero_scalar: | |
2665 mnemonic = "fcmge"; | |
2666 form = form_fp0; | |
2667 break; | |
2668 case NEON_FCMLE_zero_scalar: | |
2669 mnemonic = "fcmle"; | |
2670 form = form_fp0; | |
2671 break; | |
2672 case NEON_FCMLT_zero_scalar: | |
2673 mnemonic = "fcmlt"; | |
2674 form = form_fp0; | |
2675 break; | |
2676 case NEON_FCMEQ_zero_scalar: | |
2677 mnemonic = "fcmeq"; | |
2678 form = form_fp0; | |
2679 break; | |
2680 case NEON_FRECPX_scalar: | |
2681 mnemonic = "frecpx"; | |
2682 break; | |
2683 case NEON_FCVTNS_scalar: | |
2684 mnemonic = "fcvtns"; | |
2685 break; | |
2686 case NEON_FCVTNU_scalar: | |
2687 mnemonic = "fcvtnu"; | |
2688 break; | |
2689 case NEON_FCVTPS_scalar: | |
2690 mnemonic = "fcvtps"; | |
2691 break; | |
2692 case NEON_FCVTPU_scalar: | |
2693 mnemonic = "fcvtpu"; | |
2694 break; | |
2695 case NEON_FCVTMS_scalar: | |
2696 mnemonic = "fcvtms"; | |
2697 break; | |
2698 case NEON_FCVTMU_scalar: | |
2699 mnemonic = "fcvtmu"; | |
2700 break; | |
2701 case NEON_FCVTZS_scalar: | |
2702 mnemonic = "fcvtzs"; | |
2703 break; | |
2704 case NEON_FCVTZU_scalar: | |
2705 mnemonic = "fcvtzu"; | |
2706 break; | |
2707 case NEON_FCVTAS_scalar: | |
2708 mnemonic = "fcvtas"; | |
2709 break; | |
2710 case NEON_FCVTAU_scalar: | |
2711 mnemonic = "fcvtau"; | |
2712 break; | |
2713 case NEON_FCVTXN_scalar: | |
2714 nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); | |
2715 mnemonic = "fcvtxn"; | |
2716 break; | |
2717 default: | |
2718 nfd.SetFormatMap(0, nfd.ScalarFormatMap()); | |
2719 nfd.SetFormatMap(1, nfd.LongScalarFormatMap()); | |
2720 switch (instr->Mask(NEONScalar2RegMiscMask)) { | |
2721 case NEON_SQXTN_scalar: | |
2722 mnemonic = "sqxtn"; | |
2723 break; | |
2724 case NEON_UQXTN_scalar: | |
2725 mnemonic = "uqxtn"; | |
2726 break; | |
2727 case NEON_SQXTUN_scalar: | |
2728 mnemonic = "sqxtun"; | |
2729 break; | |
2730 default: | |
2731 form = "(NEONScalar2RegMisc)"; | |
2732 } | |
2733 } | |
2734 } | |
2735 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); | |
2736 } | |
2737 | |
2738 void DisassemblingDecoder::VisitNEONScalar3Diff(Instruction* instr) { | |
2739 const char* mnemonic = "unimplemented"; | |
2740 const char* form = "%sd, %sn, %sm"; | |
2741 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap(), | |
2742 NEONFormatDecoder::ScalarFormatMap()); | |
2743 | |
2744 switch (instr->Mask(NEONScalar3DiffMask)) { | |
2745 case NEON_SQDMLAL_scalar: | |
2746 mnemonic = "sqdmlal"; | |
2747 break; | |
2748 case NEON_SQDMLSL_scalar: | |
2749 mnemonic = "sqdmlsl"; | |
2750 break; | |
2751 case NEON_SQDMULL_scalar: | |
2752 mnemonic = "sqdmull"; | |
2753 break; | |
2754 default: | |
2755 form = "(NEONScalar3Diff)"; | |
2756 } | |
2757 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); | |
2758 } | |
2759 | |
2760 void DisassemblingDecoder::VisitNEONScalar3Same(Instruction* instr) { | |
2761 const char* mnemonic = "unimplemented"; | |
2762 const char* form = "%sd, %sn, %sm"; | |
2763 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); | |
2764 | |
2765 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) { | |
2766 nfd.SetFormatMaps(nfd.FPScalarFormatMap()); | |
2767 switch (instr->Mask(NEONScalar3SameFPMask)) { | |
2768 case NEON_FACGE_scalar: | |
2769 mnemonic = "facge"; | |
2770 break; | |
2771 case NEON_FACGT_scalar: | |
2772 mnemonic = "facgt"; | |
2773 break; | |
2774 case NEON_FCMEQ_scalar: | |
2775 mnemonic = "fcmeq"; | |
2776 break; | |
2777 case NEON_FCMGE_scalar: | |
2778 mnemonic = "fcmge"; | |
2779 break; | |
2780 case NEON_FCMGT_scalar: | |
2781 mnemonic = "fcmgt"; | |
2782 break; | |
2783 case NEON_FMULX_scalar: | |
2784 mnemonic = "fmulx"; | |
2785 break; | |
2786 case NEON_FRECPS_scalar: | |
2787 mnemonic = "frecps"; | |
2788 break; | |
2789 case NEON_FRSQRTS_scalar: | |
2790 mnemonic = "frsqrts"; | |
2791 break; | |
2792 case NEON_FABD_scalar: | |
2793 mnemonic = "fabd"; | |
2794 break; | |
2795 default: | |
2796 form = "(NEONScalar3Same)"; | |
2797 } | |
2798 } else { | |
2799 switch (instr->Mask(NEONScalar3SameMask)) { | |
2800 case NEON_ADD_scalar: | |
2801 mnemonic = "add"; | |
2802 break; | |
2803 case NEON_SUB_scalar: | |
2804 mnemonic = "sub"; | |
2805 break; | |
2806 case NEON_CMEQ_scalar: | |
2807 mnemonic = "cmeq"; | |
2808 break; | |
2809 case NEON_CMGE_scalar: | |
2810 mnemonic = "cmge"; | |
2811 break; | |
2812 case NEON_CMGT_scalar: | |
2813 mnemonic = "cmgt"; | |
2814 break; | |
2815 case NEON_CMHI_scalar: | |
2816 mnemonic = "cmhi"; | |
2817 break; | |
2818 case NEON_CMHS_scalar: | |
2819 mnemonic = "cmhs"; | |
2820 break; | |
2821 case NEON_CMTST_scalar: | |
2822 mnemonic = "cmtst"; | |
2823 break; | |
2824 case NEON_UQADD_scalar: | |
2825 mnemonic = "uqadd"; | |
2826 break; | |
2827 case NEON_SQADD_scalar: | |
2828 mnemonic = "sqadd"; | |
2829 break; | |
2830 case NEON_UQSUB_scalar: | |
2831 mnemonic = "uqsub"; | |
2832 break; | |
2833 case NEON_SQSUB_scalar: | |
2834 mnemonic = "sqsub"; | |
2835 break; | |
2836 case NEON_USHL_scalar: | |
2837 mnemonic = "ushl"; | |
2838 break; | |
2839 case NEON_SSHL_scalar: | |
2840 mnemonic = "sshl"; | |
2841 break; | |
2842 case NEON_UQSHL_scalar: | |
2843 mnemonic = "uqshl"; | |
2844 break; | |
2845 case NEON_SQSHL_scalar: | |
2846 mnemonic = "sqshl"; | |
2847 break; | |
2848 case NEON_URSHL_scalar: | |
2849 mnemonic = "urshl"; | |
2850 break; | |
2851 case NEON_SRSHL_scalar: | |
2852 mnemonic = "srshl"; | |
2853 break; | |
2854 case NEON_UQRSHL_scalar: | |
2855 mnemonic = "uqrshl"; | |
2856 break; | |
2857 case NEON_SQRSHL_scalar: | |
2858 mnemonic = "sqrshl"; | |
2859 break; | |
2860 case NEON_SQDMULH_scalar: | |
2861 mnemonic = "sqdmulh"; | |
2862 break; | |
2863 case NEON_SQRDMULH_scalar: | |
2864 mnemonic = "sqrdmulh"; | |
2865 break; | |
2866 default: | |
2867 form = "(NEONScalar3Same)"; | |
2868 } | |
2869 } | |
2870 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); | |
2871 } | |
2872 | |
2873 void DisassemblingDecoder::VisitNEONScalarByIndexedElement(Instruction* instr) { | |
2874 const char* mnemonic = "unimplemented"; | |
2875 const char* form = "%sd, %sn, 'Ve.%s['IVByElemIndex]"; | |
2876 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); | |
2877 bool long_instr = false; | |
2878 | |
2879 switch (instr->Mask(NEONScalarByIndexedElementMask)) { | |
2880 case NEON_SQDMULL_byelement_scalar: | |
2881 mnemonic = "sqdmull"; | |
2882 long_instr = true; | |
2883 break; | |
2884 case NEON_SQDMLAL_byelement_scalar: | |
2885 mnemonic = "sqdmlal"; | |
2886 long_instr = true; | |
2887 break; | |
2888 case NEON_SQDMLSL_byelement_scalar: | |
2889 mnemonic = "sqdmlsl"; | |
2890 long_instr = true; | |
2891 break; | |
2892 case NEON_SQDMULH_byelement_scalar: | |
2893 mnemonic = "sqdmulh"; | |
2894 break; | |
2895 case NEON_SQRDMULH_byelement_scalar: | |
2896 mnemonic = "sqrdmulh"; | |
2897 break; | |
2898 default: | |
2899 nfd.SetFormatMap(0, nfd.FPScalarFormatMap()); | |
2900 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) { | |
2901 case NEON_FMUL_byelement_scalar: | |
2902 mnemonic = "fmul"; | |
2903 break; | |
2904 case NEON_FMLA_byelement_scalar: | |
2905 mnemonic = "fmla"; | |
2906 break; | |
2907 case NEON_FMLS_byelement_scalar: | |
2908 mnemonic = "fmls"; | |
2909 break; | |
2910 case NEON_FMULX_byelement_scalar: | |
2911 mnemonic = "fmulx"; | |
2912 break; | |
2913 default: | |
2914 form = "(NEONScalarByIndexedElement)"; | |
2915 } | |
2916 } | |
2917 | |
2918 if (long_instr) { | |
2919 nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); | |
2920 } | |
2921 | |
2922 Format(instr, mnemonic, | |
2923 nfd.Substitute(form, nfd.kPlaceholder, nfd.kPlaceholder, nfd.kFormat)); | |
2924 } | |
2925 | |
2926 void DisassemblingDecoder::VisitNEONScalarCopy(Instruction* instr) { | |
2927 const char* mnemonic = "unimplemented"; | |
2928 const char* form = "(NEONScalarCopy)"; | |
2929 | |
2930 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap()); | |
2931 | |
2932 if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) { | |
2933 mnemonic = "mov"; | |
2934 form = "%sd, 'Vn.%s['IVInsIndex1]"; | |
2935 } | |
2936 | |
2937 Format(instr, mnemonic, nfd.Substitute(form, nfd.kPlaceholder, nfd.kFormat)); | |
2938 } | |
2939 | |
2940 void DisassemblingDecoder::VisitNEONScalarPairwise(Instruction* instr) { | |
2941 const char* mnemonic = "unimplemented"; | |
2942 const char* form = "%sd, 'Vn.%s"; | |
2943 NEONFormatMap map = {{22}, {NF_2S, NF_2D}}; | |
2944 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap(), &map); | |
2945 | |
2946 switch (instr->Mask(NEONScalarPairwiseMask)) { | |
2947 case NEON_ADDP_scalar: | |
2948 mnemonic = "addp"; | |
2949 break; | |
2950 case NEON_FADDP_scalar: | |
2951 mnemonic = "faddp"; | |
2952 break; | |
2953 case NEON_FMAXP_scalar: | |
2954 mnemonic = "fmaxp"; | |
2955 break; | |
2956 case NEON_FMAXNMP_scalar: | |
2957 mnemonic = "fmaxnmp"; | |
2958 break; | |
2959 case NEON_FMINP_scalar: | |
2960 mnemonic = "fminp"; | |
2961 break; | |
2962 case NEON_FMINNMP_scalar: | |
2963 mnemonic = "fminnmp"; | |
2964 break; | |
2965 default: | |
2966 form = "(NEONScalarPairwise)"; | |
2967 } | |
2968 Format(instr, mnemonic, | |
2969 nfd.Substitute(form, NEONFormatDecoder::kPlaceholder, | |
2970 NEONFormatDecoder::kFormat)); | |
2971 } | |
2972 | |
2973 void DisassemblingDecoder::VisitNEONScalarShiftImmediate(Instruction* instr) { | |
2974 const char* mnemonic = "unimplemented"; | |
2975 const char* form = "%sd, %sn, 'Is1"; | |
2976 const char* form_2 = "%sd, %sn, 'Is2"; | |
2977 | |
2978 static const NEONFormatMap map_shift = { | |
2979 {22, 21, 20, 19}, | |
2980 {NF_UNDEF, NF_B, NF_H, NF_H, NF_S, NF_S, NF_S, NF_S, NF_D, NF_D, NF_D, | |
2981 NF_D, NF_D, NF_D, NF_D, NF_D}}; | |
2982 static const NEONFormatMap map_shift_narrow = { | |
2983 {21, 20, 19}, {NF_UNDEF, NF_H, NF_S, NF_S, NF_D, NF_D, NF_D, NF_D}}; | |
2984 NEONFormatDecoder nfd(instr, &map_shift); | |
2985 | |
2986 if (instr->ImmNEONImmh()) { // immh has to be non-zero. | |
2987 switch (instr->Mask(NEONScalarShiftImmediateMask)) { | |
2988 case NEON_FCVTZU_imm_scalar: | |
2989 mnemonic = "fcvtzu"; | |
2990 break; | |
2991 case NEON_FCVTZS_imm_scalar: | |
2992 mnemonic = "fcvtzs"; | |
2993 break; | |
2994 case NEON_SCVTF_imm_scalar: | |
2995 mnemonic = "scvtf"; | |
2996 break; | |
2997 case NEON_UCVTF_imm_scalar: | |
2998 mnemonic = "ucvtf"; | |
2999 break; | |
3000 case NEON_SRI_scalar: | |
3001 mnemonic = "sri"; | |
3002 break; | |
3003 case NEON_SSHR_scalar: | |
3004 mnemonic = "sshr"; | |
3005 break; | |
3006 case NEON_USHR_scalar: | |
3007 mnemonic = "ushr"; | |
3008 break; | |
3009 case NEON_SRSHR_scalar: | |
3010 mnemonic = "srshr"; | |
3011 break; | |
3012 case NEON_URSHR_scalar: | |
3013 mnemonic = "urshr"; | |
3014 break; | |
3015 case NEON_SSRA_scalar: | |
3016 mnemonic = "ssra"; | |
3017 break; | |
3018 case NEON_USRA_scalar: | |
3019 mnemonic = "usra"; | |
3020 break; | |
3021 case NEON_SRSRA_scalar: | |
3022 mnemonic = "srsra"; | |
3023 break; | |
3024 case NEON_URSRA_scalar: | |
3025 mnemonic = "ursra"; | |
3026 break; | |
3027 case NEON_SHL_scalar: | |
3028 mnemonic = "shl"; | |
3029 form = form_2; | |
3030 break; | |
3031 case NEON_SLI_scalar: | |
3032 mnemonic = "sli"; | |
3033 form = form_2; | |
3034 break; | |
3035 case NEON_SQSHLU_scalar: | |
3036 mnemonic = "sqshlu"; | |
3037 form = form_2; | |
3038 break; | |
3039 case NEON_SQSHL_imm_scalar: | |
3040 mnemonic = "sqshl"; | |
3041 form = form_2; | |
3042 break; | |
3043 case NEON_UQSHL_imm_scalar: | |
3044 mnemonic = "uqshl"; | |
3045 form = form_2; | |
3046 break; | |
3047 case NEON_UQSHRN_scalar: | |
3048 mnemonic = "uqshrn"; | |
3049 nfd.SetFormatMap(1, &map_shift_narrow); | |
3050 break; | |
3051 case NEON_UQRSHRN_scalar: | |
3052 mnemonic = "uqrshrn"; | |
3053 nfd.SetFormatMap(1, &map_shift_narrow); | |
3054 break; | |
3055 case NEON_SQSHRN_scalar: | |
3056 mnemonic = "sqshrn"; | |
3057 nfd.SetFormatMap(1, &map_shift_narrow); | |
3058 break; | |
3059 case NEON_SQRSHRN_scalar: | |
3060 mnemonic = "sqrshrn"; | |
3061 nfd.SetFormatMap(1, &map_shift_narrow); | |
3062 break; | |
3063 case NEON_SQSHRUN_scalar: | |
3064 mnemonic = "sqshrun"; | |
3065 nfd.SetFormatMap(1, &map_shift_narrow); | |
3066 break; | |
3067 case NEON_SQRSHRUN_scalar: | |
3068 mnemonic = "sqrshrun"; | |
3069 nfd.SetFormatMap(1, &map_shift_narrow); | |
3070 break; | |
3071 default: | |
3072 form = "(NEONScalarShiftImmediate)"; | |
3073 } | |
3074 } else { | |
3075 form = "(NEONScalarShiftImmediate)"; | |
3076 } | |
3077 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); | |
3078 } | |
3079 | |
3080 void DisassemblingDecoder::VisitNEONShiftImmediate(Instruction* instr) { | |
3081 const char* mnemonic = "unimplemented"; | |
3082 const char* form = "'Vd.%s, 'Vn.%s, 'Is1"; | |
3083 const char* form_shift_2 = "'Vd.%s, 'Vn.%s, 'Is2"; | |
3084 const char* form_xtl = "'Vd.%s, 'Vn.%s"; | |
3085 | |
3086 // 0001->8H, 001x->4S, 01xx->2D, all others undefined. | |
3087 static const NEONFormatMap map_shift_ta = { | |
3088 {22, 21, 20, 19}, | |
3089 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}}; | |
3090 | |
3091 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H, | |
3092 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined. | |
3093 static const NEONFormatMap map_shift_tb = { | |
3094 {22, 21, 20, 19, 30}, | |
3095 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_4H, NF_8H, | |
3096 NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, | |
3097 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, | |
3098 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}}; | |
3099 | |
3100 NEONFormatDecoder nfd(instr, &map_shift_tb); | |
3101 | |
3102 if (instr->ImmNEONImmh()) { // immh has to be non-zero. | |
3103 switch (instr->Mask(NEONShiftImmediateMask)) { | |
3104 case NEON_SQSHLU: | |
3105 mnemonic = "sqshlu"; | |
3106 form = form_shift_2; | |
3107 break; | |
3108 case NEON_SQSHL_imm: | |
3109 mnemonic = "sqshl"; | |
3110 form = form_shift_2; | |
3111 break; | |
3112 case NEON_UQSHL_imm: | |
3113 mnemonic = "uqshl"; | |
3114 form = form_shift_2; | |
3115 break; | |
3116 case NEON_SHL: | |
3117 mnemonic = "shl"; | |
3118 form = form_shift_2; | |
3119 break; | |
3120 case NEON_SLI: | |
3121 mnemonic = "sli"; | |
3122 form = form_shift_2; | |
3123 break; | |
3124 case NEON_SCVTF_imm: | |
3125 mnemonic = "scvtf"; | |
3126 break; | |
3127 case NEON_UCVTF_imm: | |
3128 mnemonic = "ucvtf"; | |
3129 break; | |
3130 case NEON_FCVTZU_imm: | |
3131 mnemonic = "fcvtzu"; | |
3132 break; | |
3133 case NEON_FCVTZS_imm: | |
3134 mnemonic = "fcvtzs"; | |
3135 break; | |
3136 case NEON_SRI: | |
3137 mnemonic = "sri"; | |
3138 break; | |
3139 case NEON_SSHR: | |
3140 mnemonic = "sshr"; | |
3141 break; | |
3142 case NEON_USHR: | |
3143 mnemonic = "ushr"; | |
3144 break; | |
3145 case NEON_SRSHR: | |
3146 mnemonic = "srshr"; | |
3147 break; | |
3148 case NEON_URSHR: | |
3149 mnemonic = "urshr"; | |
3150 break; | |
3151 case NEON_SSRA: | |
3152 mnemonic = "ssra"; | |
3153 break; | |
3154 case NEON_USRA: | |
3155 mnemonic = "usra"; | |
3156 break; | |
3157 case NEON_SRSRA: | |
3158 mnemonic = "srsra"; | |
3159 break; | |
3160 case NEON_URSRA: | |
3161 mnemonic = "ursra"; | |
3162 break; | |
3163 case NEON_SHRN: | |
3164 mnemonic = instr->Mask(NEON_Q) ? "shrn2" : "shrn"; | |
3165 nfd.SetFormatMap(1, &map_shift_ta); | |
3166 break; | |
3167 case NEON_RSHRN: | |
3168 mnemonic = instr->Mask(NEON_Q) ? "rshrn2" : "rshrn"; | |
3169 nfd.SetFormatMap(1, &map_shift_ta); | |
3170 break; | |
3171 case NEON_UQSHRN: | |
3172 mnemonic = instr->Mask(NEON_Q) ? "uqshrn2" : "uqshrn"; | |
3173 nfd.SetFormatMap(1, &map_shift_ta); | |
3174 break; | |
3175 case NEON_UQRSHRN: | |
3176 mnemonic = instr->Mask(NEON_Q) ? "uqrshrn2" : "uqrshrn"; | |
3177 nfd.SetFormatMap(1, &map_shift_ta); | |
3178 break; | |
3179 case NEON_SQSHRN: | |
3180 mnemonic = instr->Mask(NEON_Q) ? "sqshrn2" : "sqshrn"; | |
3181 nfd.SetFormatMap(1, &map_shift_ta); | |
3182 break; | |
3183 case NEON_SQRSHRN: | |
3184 mnemonic = instr->Mask(NEON_Q) ? "sqrshrn2" : "sqrshrn"; | |
3185 nfd.SetFormatMap(1, &map_shift_ta); | |
3186 break; | |
3187 case NEON_SQSHRUN: | |
3188 mnemonic = instr->Mask(NEON_Q) ? "sqshrun2" : "sqshrun"; | |
3189 nfd.SetFormatMap(1, &map_shift_ta); | |
3190 break; | |
3191 case NEON_SQRSHRUN: | |
3192 mnemonic = instr->Mask(NEON_Q) ? "sqrshrun2" : "sqrshrun"; | |
3193 nfd.SetFormatMap(1, &map_shift_ta); | |
3194 break; | |
3195 case NEON_SSHLL: | |
3196 nfd.SetFormatMap(0, &map_shift_ta); | |
3197 if (instr->ImmNEONImmb() == 0 && | |
3198 CountSetBits(instr->ImmNEONImmh(), 32) == 1) { // sxtl variant. | |
3199 form = form_xtl; | |
3200 mnemonic = instr->Mask(NEON_Q) ? "sxtl2" : "sxtl"; | |
3201 } else { // sshll variant. | |
3202 form = form_shift_2; | |
3203 mnemonic = instr->Mask(NEON_Q) ? "sshll2" : "sshll"; | |
3204 } | |
3205 break; | |
3206 case NEON_USHLL: | |
3207 nfd.SetFormatMap(0, &map_shift_ta); | |
3208 if (instr->ImmNEONImmb() == 0 && | |
3209 CountSetBits(instr->ImmNEONImmh(), 32) == 1) { // uxtl variant. | |
3210 form = form_xtl; | |
3211 mnemonic = instr->Mask(NEON_Q) ? "uxtl2" : "uxtl"; | |
3212 } else { // ushll variant. | |
3213 form = form_shift_2; | |
3214 mnemonic = instr->Mask(NEON_Q) ? "ushll2" : "ushll"; | |
3215 } | |
3216 break; | |
3217 default: | |
3218 form = "(NEONShiftImmediate)"; | |
3219 } | |
3220 } else { | |
3221 form = "(NEONShiftImmediate)"; | |
3222 } | |
3223 Format(instr, mnemonic, nfd.Substitute(form)); | |
3224 } | |
3225 | |
3226 void DisassemblingDecoder::VisitNEONTable(Instruction* instr) { | |
3227 const char* mnemonic = "unimplemented"; | |
3228 const char* form = "(NEONTable)"; | |
3229 const char form_1v[] = "'Vd.%%s, {'Vn.16b}, 'Vm.%%s"; | |
3230 const char form_2v[] = "'Vd.%%s, {'Vn.16b, v%d.16b}, 'Vm.%%s"; | |
3231 const char form_3v[] = "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b}, 'Vm.%%s"; | |
3232 const char form_4v[] = | |
3233 "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b, v%d.16b}, 'Vm.%%s"; | |
3234 static const NEONFormatMap map_b = {{30}, {NF_8B, NF_16B}}; | |
3235 NEONFormatDecoder nfd(instr, &map_b); | |
3236 | |
3237 switch (instr->Mask(NEONTableMask)) { | |
3238 case NEON_TBL_1v: | |
3239 mnemonic = "tbl"; | |
3240 form = form_1v; | |
3241 break; | |
3242 case NEON_TBL_2v: | |
3243 mnemonic = "tbl"; | |
3244 form = form_2v; | |
3245 break; | |
3246 case NEON_TBL_3v: | |
3247 mnemonic = "tbl"; | |
3248 form = form_3v; | |
3249 break; | |
3250 case NEON_TBL_4v: | |
3251 mnemonic = "tbl"; | |
3252 form = form_4v; | |
3253 break; | |
3254 case NEON_TBX_1v: | |
3255 mnemonic = "tbx"; | |
3256 form = form_1v; | |
3257 break; | |
3258 case NEON_TBX_2v: | |
3259 mnemonic = "tbx"; | |
3260 form = form_2v; | |
3261 break; | |
3262 case NEON_TBX_3v: | |
3263 mnemonic = "tbx"; | |
3264 form = form_3v; | |
3265 break; | |
3266 case NEON_TBX_4v: | |
3267 mnemonic = "tbx"; | |
3268 form = form_4v; | |
3269 break; | |
3270 default: | |
3271 break; | |
3272 } | |
3273 | |
3274 char re_form[sizeof(form_4v)]; | |
3275 int reg_num = instr->Rn(); | |
3276 snprintf(re_form, sizeof(re_form), form, (reg_num + 1) % kNumberOfVRegisters, | |
3277 (reg_num + 2) % kNumberOfVRegisters, | |
3278 (reg_num + 3) % kNumberOfVRegisters); | |
3279 | |
3280 Format(instr, mnemonic, nfd.Substitute(re_form)); | |
3281 } | |
3282 | 1237 |
3283 void DisassemblingDecoder::VisitUnimplemented(Instruction* instr) { | 1238 void DisassemblingDecoder::VisitUnimplemented(Instruction* instr) { |
3284 Format(instr, "unimplemented", "(Unimplemented)"); | 1239 Format(instr, "unimplemented", "(Unimplemented)"); |
3285 } | 1240 } |
3286 | 1241 |
| 1242 |
3287 void DisassemblingDecoder::VisitUnallocated(Instruction* instr) { | 1243 void DisassemblingDecoder::VisitUnallocated(Instruction* instr) { |
3288 Format(instr, "unallocated", "(Unallocated)"); | 1244 Format(instr, "unallocated", "(Unallocated)"); |
3289 } | 1245 } |
3290 | 1246 |
| 1247 |
3291 void DisassemblingDecoder::ProcessOutput(Instruction* /*instr*/) { | 1248 void DisassemblingDecoder::ProcessOutput(Instruction* /*instr*/) { |
3292 // The base disasm does nothing more than disassembling into a buffer. | 1249 // The base disasm does nothing more than disassembling into a buffer. |
3293 } | 1250 } |
3294 | 1251 |
3295 void DisassemblingDecoder::AppendRegisterNameToOutput(const CPURegister& reg) { | |
3296 DCHECK(reg.IsValid()); | |
3297 char reg_char; | |
3298 | |
3299 if (reg.IsRegister()) { | |
3300 reg_char = reg.Is64Bits() ? 'x' : 'w'; | |
3301 } else { | |
3302 DCHECK(reg.IsVRegister()); | |
3303 switch (reg.SizeInBits()) { | |
3304 case kBRegSizeInBits: | |
3305 reg_char = 'b'; | |
3306 break; | |
3307 case kHRegSizeInBits: | |
3308 reg_char = 'h'; | |
3309 break; | |
3310 case kSRegSizeInBits: | |
3311 reg_char = 's'; | |
3312 break; | |
3313 case kDRegSizeInBits: | |
3314 reg_char = 'd'; | |
3315 break; | |
3316 default: | |
3317 DCHECK(reg.Is128Bits()); | |
3318 reg_char = 'q'; | |
3319 } | |
3320 } | |
3321 | |
3322 if (reg.IsVRegister() || !(reg.Aliases(csp) || reg.Aliases(xzr))) { | |
3323 // Filter special registers | |
3324 if (reg.IsX() && (reg.code() == 27)) { | |
3325 AppendToOutput("cp"); | |
3326 } else if (reg.IsX() && (reg.code() == 28)) { | |
3327 AppendToOutput("jssp"); | |
3328 } else if (reg.IsX() && (reg.code() == 29)) { | |
3329 AppendToOutput("fp"); | |
3330 } else if (reg.IsX() && (reg.code() == 30)) { | |
3331 AppendToOutput("lr"); | |
3332 } else { | |
3333 // A core or scalar/vector register: [wx]0 - 30, [bhsdq]0 - 31. | |
3334 AppendToOutput("%c%d", reg_char, reg.code()); | |
3335 } | |
3336 } else if (reg.Aliases(csp)) { | |
3337 // Disassemble w31/x31 as stack pointer wcsp/csp. | |
3338 AppendToOutput("%s", reg.Is64Bits() ? "csp" : "wcsp"); | |
3339 } else { | |
3340 // Disassemble w31/x31 as zero register wzr/xzr. | |
3341 AppendToOutput("%czr", reg_char); | |
3342 } | |
3343 } | |
3344 | 1252 |
3345 void DisassemblingDecoder::Format(Instruction* instr, const char* mnemonic, | 1253 void DisassemblingDecoder::Format(Instruction* instr, const char* mnemonic, |
3346 const char* format) { | 1254 const char* format) { |
3347 // TODO(mcapewel) don't think I can use the instr address here - there needs | 1255 // TODO(mcapewel) don't think I can use the instr address here - there needs |
3348 // to be a base address too | 1256 // to be a base address too |
3349 DCHECK(mnemonic != NULL); | 1257 DCHECK(mnemonic != NULL); |
3350 ResetOutput(); | 1258 ResetOutput(); |
3351 Substitute(instr, mnemonic); | 1259 Substitute(instr, mnemonic); |
3352 if (format != NULL) { | 1260 if (format != NULL) { |
3353 buffer_[buffer_pos_++] = ' '; | 1261 buffer_[buffer_pos_++] = ' '; |
3354 Substitute(instr, format); | 1262 Substitute(instr, format); |
3355 } | 1263 } |
3356 buffer_[buffer_pos_] = 0; | 1264 buffer_[buffer_pos_] = 0; |
3357 ProcessOutput(instr); | 1265 ProcessOutput(instr); |
3358 } | 1266 } |
3359 | 1267 |
| 1268 |
3360 void DisassemblingDecoder::Substitute(Instruction* instr, const char* string) { | 1269 void DisassemblingDecoder::Substitute(Instruction* instr, const char* string) { |
3361 char chr = *string++; | 1270 char chr = *string++; |
3362 while (chr != '\0') { | 1271 while (chr != '\0') { |
3363 if (chr == '\'') { | 1272 if (chr == '\'') { |
3364 string += SubstituteField(instr, string); | 1273 string += SubstituteField(instr, string); |
3365 } else { | 1274 } else { |
3366 buffer_[buffer_pos_++] = chr; | 1275 buffer_[buffer_pos_++] = chr; |
3367 } | 1276 } |
3368 chr = *string++; | 1277 chr = *string++; |
3369 } | 1278 } |
3370 } | 1279 } |
3371 | 1280 |
| 1281 |
3372 int DisassemblingDecoder::SubstituteField(Instruction* instr, | 1282 int DisassemblingDecoder::SubstituteField(Instruction* instr, |
3373 const char* format) { | 1283 const char* format) { |
3374 switch (format[0]) { | 1284 switch (format[0]) { |
3375 // NB. The remaining substitution prefix characters are: GJKUZ. | |
3376 case 'R': // Register. X or W, selected by sf bit. | 1285 case 'R': // Register. X or W, selected by sf bit. |
3377 case 'F': // FP register. S or D, selected by type field. | 1286 case 'F': // FP Register. S or D, selected by type field. |
3378 case 'V': // Vector register, V, vector format. | |
3379 case 'W': | 1287 case 'W': |
3380 case 'X': | 1288 case 'X': |
3381 case 'B': | |
3382 case 'H': | |
3383 case 'S': | 1289 case 'S': |
3384 case 'D': | 1290 case 'D': return SubstituteRegisterField(instr, format); |
3385 case 'Q': | 1291 case 'I': return SubstituteImmediateField(instr, format); |
3386 return SubstituteRegisterField(instr, format); | 1292 case 'L': return SubstituteLiteralField(instr, format); |
3387 case 'I': | 1293 case 'H': return SubstituteShiftField(instr, format); |
3388 return SubstituteImmediateField(instr, format); | 1294 case 'P': return SubstitutePrefetchField(instr, format); |
3389 case 'L': | 1295 case 'C': return SubstituteConditionField(instr, format); |
3390 return SubstituteLiteralField(instr, format); | 1296 case 'E': return SubstituteExtendField(instr, format); |
3391 case 'N': | 1297 case 'A': return SubstitutePCRelAddressField(instr, format); |
3392 return SubstituteShiftField(instr, format); | 1298 case 'B': return SubstituteBranchTargetField(instr, format); |
3393 case 'P': | 1299 case 'O': return SubstituteLSRegOffsetField(instr, format); |
3394 return SubstitutePrefetchField(instr, format); | 1300 case 'M': return SubstituteBarrierField(instr, format); |
3395 case 'C': | |
3396 return SubstituteConditionField(instr, format); | |
3397 case 'E': | |
3398 return SubstituteExtendField(instr, format); | |
3399 case 'A': | |
3400 return SubstitutePCRelAddressField(instr, format); | |
3401 case 'T': | |
3402 return SubstituteBranchTargetField(instr, format); | |
3403 case 'O': | |
3404 return SubstituteLSRegOffsetField(instr, format); | |
3405 case 'M': | |
3406 return SubstituteBarrierField(instr, format); | |
3407 default: { | 1301 default: { |
3408 UNREACHABLE(); | 1302 UNREACHABLE(); |
3409 return 1; | 1303 return 1; |
3410 } | 1304 } |
3411 } | 1305 } |
3412 } | 1306 } |
3413 | 1307 |
| 1308 |
3414 int DisassemblingDecoder::SubstituteRegisterField(Instruction* instr, | 1309 int DisassemblingDecoder::SubstituteRegisterField(Instruction* instr, |
3415 const char* format) { | 1310 const char* format) { |
3416 char reg_prefix = format[0]; | |
3417 unsigned reg_num = 0; | 1311 unsigned reg_num = 0; |
3418 unsigned field_len = 2; | 1312 unsigned field_len = 2; |
3419 | |
3420 switch (format[1]) { | 1313 switch (format[1]) { |
3421 case 'd': | 1314 case 'd': reg_num = instr->Rd(); break; |
3422 reg_num = instr->Rd(); | 1315 case 'n': reg_num = instr->Rn(); break; |
3423 if (format[2] == 'q') { | 1316 case 'm': reg_num = instr->Rm(); break; |
3424 reg_prefix = instr->NEONQ() ? 'X' : 'W'; | 1317 case 'a': reg_num = instr->Ra(); break; |
| 1318 case 't': { |
| 1319 if (format[2] == '2') { |
| 1320 reg_num = instr->Rt2(); |
3425 field_len = 3; | 1321 field_len = 3; |
| 1322 } else { |
| 1323 reg_num = instr->Rt(); |
3426 } | 1324 } |
3427 break; | 1325 break; |
3428 case 'n': | 1326 } |
3429 reg_num = instr->Rn(); | |
3430 break; | |
3431 case 'm': | |
3432 reg_num = instr->Rm(); | |
3433 switch (format[2]) { | |
3434 // Handle registers tagged with b (bytes), z (instruction), or | |
3435 // r (registers), used for address updates in | |
3436 // NEON load/store instructions. | |
3437 case 'r': | |
3438 case 'b': | |
3439 case 'z': { | |
3440 field_len = 3; | |
3441 char* eimm; | |
3442 int imm = static_cast<int>(strtol(&format[3], &eimm, 10)); | |
3443 field_len += eimm - &format[3]; | |
3444 if (reg_num == 31) { | |
3445 switch (format[2]) { | |
3446 case 'z': | |
3447 imm *= (1 << instr->NEONLSSize()); | |
3448 break; | |
3449 case 'r': | |
3450 imm *= (instr->NEONQ() == 0) ? kDRegSize : kQRegSize; | |
3451 break; | |
3452 case 'b': | |
3453 break; | |
3454 } | |
3455 AppendToOutput("#%d", imm); | |
3456 return field_len; | |
3457 } | |
3458 break; | |
3459 } | |
3460 } | |
3461 break; | |
3462 case 'e': | |
3463 // This is register Rm, but using a 4-bit specifier. Used in NEON | |
3464 // by-element instructions. | |
3465 reg_num = (instr->Rm() & 0xf); | |
3466 break; | |
3467 case 'a': | |
3468 reg_num = instr->Ra(); | |
3469 break; | |
3470 case 't': | |
3471 reg_num = instr->Rt(); | |
3472 if (format[0] == 'V') { | |
3473 if ((format[2] >= '2') && (format[2] <= '4')) { | |
3474 // Handle consecutive vector register specifiers Vt2, Vt3 and Vt4. | |
3475 reg_num = (reg_num + format[2] - '1') % 32; | |
3476 field_len = 3; | |
3477 } | |
3478 } else { | |
3479 if (format[2] == '2') { | |
3480 // Handle register specifier Rt2. | |
3481 reg_num = instr->Rt2(); | |
3482 field_len = 3; | |
3483 } | |
3484 } | |
3485 break; | |
3486 case 's': | 1327 case 's': |
3487 reg_num = instr->Rs(); | 1328 reg_num = instr->Rs(); |
3488 break; | 1329 break; |
3489 default: | 1330 default: UNREACHABLE(); |
3490 UNREACHABLE(); | |
3491 } | 1331 } |
3492 | 1332 |
3493 // Increase field length for registers tagged as stack. | 1333 // Increase field length for registers tagged as stack. |
3494 if (format[2] == 's') { | 1334 if (format[2] == 's') { |
3495 field_len = 3; | 1335 field_len = 3; |
3496 } | 1336 } |
3497 | 1337 |
3498 CPURegister::RegisterType reg_type; | 1338 char reg_type; |
3499 unsigned reg_size; | 1339 if (format[0] == 'R') { |
3500 | 1340 // Register type is R: use sf bit to choose X and W. |
3501 if (reg_prefix == 'R') { | 1341 reg_type = instr->SixtyFourBits() ? 'x' : 'w'; |
3502 reg_prefix = instr->SixtyFourBits() ? 'X' : 'W'; | 1342 } else if (format[0] == 'F') { |
3503 } else if (reg_prefix == 'F') { | 1343 // Floating-point register: use type field to choose S or D. |
3504 reg_prefix = ((instr->FPType() & 1) == 0) ? 'S' : 'D'; | 1344 reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd'; |
| 1345 } else { |
| 1346 // Register type is specified. Make it lower case. |
| 1347 reg_type = format[0] + 0x20; |
3505 } | 1348 } |
3506 | 1349 |
3507 switch (reg_prefix) { | 1350 if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) { |
3508 case 'W': | 1351 // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31. |
3509 reg_type = CPURegister::kRegister; | 1352 |
3510 reg_size = kWRegSizeInBits; | 1353 // Filter special registers |
3511 break; | 1354 if ((reg_type == 'x') && (reg_num == 27)) { |
3512 case 'X': | 1355 AppendToOutput("cp"); |
3513 reg_type = CPURegister::kRegister; | 1356 } else if ((reg_type == 'x') && (reg_num == 28)) { |
3514 reg_size = kXRegSizeInBits; | 1357 AppendToOutput("jssp"); |
3515 break; | 1358 } else if ((reg_type == 'x') && (reg_num == 29)) { |
3516 case 'B': | 1359 AppendToOutput("fp"); |
3517 reg_type = CPURegister::kVRegister; | 1360 } else if ((reg_type == 'x') && (reg_num == 30)) { |
3518 reg_size = kBRegSizeInBits; | 1361 AppendToOutput("lr"); |
3519 break; | 1362 } else { |
3520 case 'H': | 1363 AppendToOutput("%c%d", reg_type, reg_num); |
3521 reg_type = CPURegister::kVRegister; | 1364 } |
3522 reg_size = kHRegSizeInBits; | 1365 } else if (format[2] == 's') { |
3523 break; | 1366 // Disassemble w31/x31 as stack pointer wcsp/csp. |
3524 case 'S': | 1367 AppendToOutput("%s", (reg_type == 'w') ? "wcsp" : "csp"); |
3525 reg_type = CPURegister::kVRegister; | 1368 } else { |
3526 reg_size = kSRegSizeInBits; | 1369 // Disassemble w31/x31 as zero register wzr/xzr. |
3527 break; | 1370 AppendToOutput("%czr", reg_type); |
3528 case 'D': | |
3529 reg_type = CPURegister::kVRegister; | |
3530 reg_size = kDRegSizeInBits; | |
3531 break; | |
3532 case 'Q': | |
3533 reg_type = CPURegister::kVRegister; | |
3534 reg_size = kQRegSizeInBits; | |
3535 break; | |
3536 case 'V': | |
3537 AppendToOutput("v%d", reg_num); | |
3538 return field_len; | |
3539 default: | |
3540 UNREACHABLE(); | |
3541 reg_type = CPURegister::kRegister; | |
3542 reg_size = kXRegSizeInBits; | |
3543 } | 1371 } |
3544 | 1372 |
3545 if ((reg_type == CPURegister::kRegister) && (reg_num == kZeroRegCode) && | |
3546 (format[2] == 's')) { | |
3547 reg_num = kSPRegInternalCode; | |
3548 } | |
3549 | |
3550 AppendRegisterNameToOutput(CPURegister::Create(reg_num, reg_size, reg_type)); | |
3551 | |
3552 return field_len; | 1373 return field_len; |
3553 } | 1374 } |
3554 | 1375 |
| 1376 |
3555 int DisassemblingDecoder::SubstituteImmediateField(Instruction* instr, | 1377 int DisassemblingDecoder::SubstituteImmediateField(Instruction* instr, |
3556 const char* format) { | 1378 const char* format) { |
3557 DCHECK(format[0] == 'I'); | 1379 DCHECK(format[0] == 'I'); |
3558 | 1380 |
3559 switch (format[1]) { | 1381 switch (format[1]) { |
3560 case 'M': { // IMoveImm or IMoveLSL. | 1382 case 'M': { // IMoveImm or IMoveLSL. |
3561 if (format[5] == 'I' || format[5] == 'N') { | 1383 if (format[5] == 'I') { |
3562 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide()) | 1384 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide()) |
3563 << (16 * instr->ShiftMoveWide()); | 1385 << (16 * instr->ShiftMoveWide()); |
3564 if (format[5] == 'N') imm = ~imm; | |
3565 if (!instr->SixtyFourBits()) imm &= UINT64_C(0xffffffff); | |
3566 AppendToOutput("#0x%" PRIx64, imm); | 1386 AppendToOutput("#0x%" PRIx64, imm); |
3567 } else { | 1387 } else { |
3568 DCHECK(format[5] == 'L'); | 1388 DCHECK(format[5] == 'L'); |
3569 AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide()); | 1389 AppendToOutput("#0x%" PRIx32, instr->ImmMoveWide()); |
3570 if (instr->ShiftMoveWide() > 0) { | 1390 if (instr->ShiftMoveWide() > 0) { |
3571 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide()); | 1391 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide()); |
3572 } | 1392 } |
3573 } | 1393 } |
3574 return 8; | 1394 return 8; |
3575 } | 1395 } |
3576 case 'L': { | 1396 case 'L': { |
3577 switch (format[2]) { | 1397 switch (format[2]) { |
3578 case 'L': { // ILLiteral - Immediate Load Literal. | 1398 case 'L': { // ILLiteral - Immediate Load Literal. |
3579 AppendToOutput("pc%+" PRId32, instr->ImmLLiteral() | 1399 AppendToOutput("pc%+" PRId32, instr->ImmLLiteral() |
3580 << kLoadLiteralScaleLog2); | 1400 << kLoadLiteralScaleLog2); |
3581 return 9; | 1401 return 9; |
3582 } | 1402 } |
3583 case 'S': { // ILS - Immediate Load/Store. | 1403 case 'S': { // ILS - Immediate Load/Store. |
3584 if (instr->ImmLS() != 0) { | 1404 if (instr->ImmLS() != 0) { |
3585 AppendToOutput(", #%" PRId32, instr->ImmLS()); | 1405 AppendToOutput(", #%" PRId32, instr->ImmLS()); |
3586 } | 1406 } |
3587 return 3; | 1407 return 3; |
3588 } | 1408 } |
3589 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size. | 1409 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size. |
3590 if (instr->ImmLSPair() != 0) { | 1410 if (instr->ImmLSPair() != 0) { |
3591 // format[3] is the scale value. Convert to a number. | 1411 // format[3] is the scale value. Convert to a number. |
3592 int scale = 1 << (format[3] - '0'); | 1412 int scale = format[3] - 0x30; |
3593 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale); | 1413 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale); |
3594 } | 1414 } |
3595 return 4; | 1415 return 4; |
3596 } | 1416 } |
3597 case 'U': { // ILU - Immediate Load/Store Unsigned. | 1417 case 'U': { // ILU - Immediate Load/Store Unsigned. |
3598 if (instr->ImmLSUnsigned() != 0) { | 1418 if (instr->ImmLSUnsigned() != 0) { |
3599 int shift = instr->SizeLS(); | 1419 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned() |
3600 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned() << shift); | 1420 << instr->SizeLS()); |
3601 } | 1421 } |
3602 return 3; | 1422 return 3; |
3603 } | 1423 } |
3604 } | 1424 } |
3605 } | 1425 } |
3606 case 'C': { // ICondB - Immediate Conditional Branch. | 1426 case 'C': { // ICondB - Immediate Conditional Branch. |
3607 int64_t offset = instr->ImmCondBranch() << 2; | 1427 int64_t offset = instr->ImmCondBranch() << 2; |
3608 char sign = (offset >= 0) ? '+' : '-'; | 1428 char sign = (offset >= 0) ? '+' : '-'; |
3609 AppendToOutput("#%c0x%" PRIx64, sign, offset); | 1429 AppendToOutput("#%c0x%" PRIx64, sign, offset); |
3610 return 6; | 1430 return 6; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3646 } | 1466 } |
3647 case 'E': { // IExtract. | 1467 case 'E': { // IExtract. |
3648 AppendToOutput("#%d", instr->ImmS()); | 1468 AppendToOutput("#%d", instr->ImmS()); |
3649 return 8; | 1469 return 8; |
3650 } | 1470 } |
3651 case 'S': { // IS - Test and branch bit. | 1471 case 'S': { // IS - Test and branch bit. |
3652 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) | | 1472 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) | |
3653 instr->ImmTestBranchBit40()); | 1473 instr->ImmTestBranchBit40()); |
3654 return 2; | 1474 return 2; |
3655 } | 1475 } |
3656 case 's': { // Is - Shift (immediate). | |
3657 switch (format[2]) { | |
3658 case '1': { // Is1 - SSHR. | |
3659 int shift = 16 << HighestSetBitPosition(instr->ImmNEONImmh()); | |
3660 shift -= instr->ImmNEONImmhImmb(); | |
3661 AppendToOutput("#%d", shift); | |
3662 return 3; | |
3663 } | |
3664 case '2': { // Is2 - SLI. | |
3665 int shift = instr->ImmNEONImmhImmb(); | |
3666 shift -= 8 << HighestSetBitPosition(instr->ImmNEONImmh()); | |
3667 AppendToOutput("#%d", shift); | |
3668 return 3; | |
3669 } | |
3670 default: { | |
3671 UNIMPLEMENTED(); | |
3672 return 0; | |
3673 } | |
3674 } | |
3675 } | |
3676 case 'D': { // IDebug - HLT and BRK instructions. | 1476 case 'D': { // IDebug - HLT and BRK instructions. |
3677 AppendToOutput("#0x%x", instr->ImmException()); | 1477 AppendToOutput("#0x%x", instr->ImmException()); |
3678 return 6; | 1478 return 6; |
3679 } | 1479 } |
3680 case 'V': { // Immediate Vector. | |
3681 switch (format[2]) { | |
3682 case 'E': { // IVExtract. | |
3683 AppendToOutput("#%" PRId64, instr->ImmNEONExt()); | |
3684 return 9; | |
3685 } | |
3686 case 'B': { // IVByElemIndex. | |
3687 int vm_index = (instr->NEONH() << 1) | instr->NEONL(); | |
3688 if (instr->NEONSize() == 1) { | |
3689 vm_index = (vm_index << 1) | instr->NEONM(); | |
3690 } | |
3691 AppendToOutput("%d", vm_index); | |
3692 return strlen("IVByElemIndex"); | |
3693 } | |
3694 case 'I': { // INS element. | |
3695 if (strncmp(format, "IVInsIndex", strlen("IVInsIndex")) == 0) { | |
3696 unsigned rd_index, rn_index; | |
3697 unsigned imm5 = instr->ImmNEON5(); | |
3698 unsigned imm4 = instr->ImmNEON4(); | |
3699 int tz = CountTrailingZeros(imm5, 32); | |
3700 if (tz <= 3) { // Defined for 0 <= tz <= 3 only. | |
3701 rd_index = imm5 >> (tz + 1); | |
3702 rn_index = imm4 >> tz; | |
3703 if (strncmp(format, "IVInsIndex1", strlen("IVInsIndex1")) == 0) { | |
3704 AppendToOutput("%d", rd_index); | |
3705 return strlen("IVInsIndex1"); | |
3706 } else if (strncmp(format, "IVInsIndex2", | |
3707 strlen("IVInsIndex2")) == 0) { | |
3708 AppendToOutput("%d", rn_index); | |
3709 return strlen("IVInsIndex2"); | |
3710 } | |
3711 } | |
3712 return 0; | |
3713 } | |
3714 } | |
3715 case 'L': { // IVLSLane[0123] - suffix indicates access size shift. | |
3716 AppendToOutput("%d", instr->NEONLSIndex(format[8] - '0')); | |
3717 return 9; | |
3718 } | |
3719 case 'M': { // Modified Immediate cases. | |
3720 if (strncmp(format, "IVMIImmFPSingle", strlen("IVMIImmFPSingle")) == | |
3721 0) { | |
3722 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(), | |
3723 instr->ImmNEONFP32()); | |
3724 return strlen("IVMIImmFPSingle"); | |
3725 } else if (strncmp(format, "IVMIImmFPDouble", | |
3726 strlen("IVMIImmFPDouble")) == 0) { | |
3727 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(), | |
3728 instr->ImmNEONFP64()); | |
3729 return strlen("IVMIImmFPDouble"); | |
3730 } else if (strncmp(format, "IVMIImm8", strlen("IVMIImm8")) == 0) { | |
3731 uint64_t imm8 = instr->ImmNEONabcdefgh(); | |
3732 AppendToOutput("#0x%" PRIx64, imm8); | |
3733 return strlen("IVMIImm8"); | |
3734 } else if (strncmp(format, "IVMIImm", strlen("IVMIImm")) == 0) { | |
3735 uint64_t imm8 = instr->ImmNEONabcdefgh(); | |
3736 uint64_t imm = 0; | |
3737 for (int i = 0; i < 8; ++i) { | |
3738 if (imm8 & (1 << i)) { | |
3739 imm |= (UINT64_C(0xff) << (8 * i)); | |
3740 } | |
3741 } | |
3742 AppendToOutput("#0x%" PRIx64, imm); | |
3743 return strlen("IVMIImm"); | |
3744 } else if (strncmp(format, "IVMIShiftAmt1", | |
3745 strlen("IVMIShiftAmt1")) == 0) { | |
3746 int cmode = instr->NEONCmode(); | |
3747 int shift_amount = 8 * ((cmode >> 1) & 3); | |
3748 AppendToOutput("#%d", shift_amount); | |
3749 return strlen("IVMIShiftAmt1"); | |
3750 } else if (strncmp(format, "IVMIShiftAmt2", | |
3751 strlen("IVMIShiftAmt2")) == 0) { | |
3752 int cmode = instr->NEONCmode(); | |
3753 int shift_amount = 8 << (cmode & 1); | |
3754 AppendToOutput("#%d", shift_amount); | |
3755 return strlen("IVMIShiftAmt2"); | |
3756 } else { | |
3757 UNIMPLEMENTED(); | |
3758 return 0; | |
3759 } | |
3760 } | |
3761 default: { | |
3762 UNIMPLEMENTED(); | |
3763 return 0; | |
3764 } | |
3765 } | |
3766 } | |
3767 default: { | 1480 default: { |
3768 printf("%s", format); | |
3769 UNREACHABLE(); | 1481 UNREACHABLE(); |
3770 return 0; | 1482 return 0; |
3771 } | 1483 } |
3772 } | 1484 } |
3773 } | 1485 } |
3774 | 1486 |
3775 | 1487 |
3776 int DisassemblingDecoder::SubstituteBitfieldImmediateField(Instruction* instr, | 1488 int DisassemblingDecoder::SubstituteBitfieldImmediateField(Instruction* instr, |
3777 const char* format) { | 1489 const char* format) { |
3778 DCHECK((format[0] == 'I') && (format[1] == 'B')); | 1490 DCHECK((format[0] == 'I') && (format[1] == 'B')); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3823 break; | 1535 break; |
3824 default: UNREACHABLE(); | 1536 default: UNREACHABLE(); |
3825 } | 1537 } |
3826 | 1538 |
3827 return 6; | 1539 return 6; |
3828 } | 1540 } |
3829 | 1541 |
3830 | 1542 |
3831 int DisassemblingDecoder::SubstituteShiftField(Instruction* instr, | 1543 int DisassemblingDecoder::SubstituteShiftField(Instruction* instr, |
3832 const char* format) { | 1544 const char* format) { |
3833 DCHECK_EQ(format[0], 'N'); | 1545 DCHECK(format[0] == 'H'); |
3834 DCHECK_LE(instr->ShiftDP(), 0x3); | 1546 DCHECK(instr->ShiftDP() <= 0x3); |
3835 | 1547 |
3836 switch (format[1]) { | 1548 switch (format[1]) { |
3837 case 'D': { // NDP. | 1549 case 'D': { // HDP. |
3838 DCHECK(instr->ShiftDP() != ROR); | 1550 DCHECK(instr->ShiftDP() != ROR); |
3839 } // Fall through. | 1551 } // Fall through. |
3840 case 'L': { // NLo. | 1552 case 'L': { // HLo. |
3841 if (instr->ImmDPShift() != 0) { | 1553 if (instr->ImmDPShift() != 0) { |
3842 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"}; | 1554 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"}; |
3843 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()], | 1555 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()], |
3844 instr->ImmDPShift()); | 1556 instr->ImmDPShift()); |
3845 } | 1557 } |
3846 return 3; | 1558 return 3; |
3847 } | 1559 } |
3848 default: | 1560 default: |
3849 UNREACHABLE(); | 1561 UNREACHABLE(); |
3850 return 0; | 1562 return 0; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3889 sign = '-'; | 1601 sign = '-'; |
3890 } | 1602 } |
3891 AppendToOutput("#%c0x%x (addr %p)", sign, offset, | 1603 AppendToOutput("#%c0x%x (addr %p)", sign, offset, |
3892 instr->InstructionAtOffset(offset, Instruction::NO_CHECK)); | 1604 instr->InstructionAtOffset(offset, Instruction::NO_CHECK)); |
3893 return 13; | 1605 return 13; |
3894 } | 1606 } |
3895 | 1607 |
3896 | 1608 |
3897 int DisassemblingDecoder::SubstituteBranchTargetField(Instruction* instr, | 1609 int DisassemblingDecoder::SubstituteBranchTargetField(Instruction* instr, |
3898 const char* format) { | 1610 const char* format) { |
3899 DCHECK_EQ(strncmp(format, "TImm", 4), 0); | 1611 DCHECK(strncmp(format, "BImm", 4) == 0); |
3900 | 1612 |
3901 int64_t offset = 0; | 1613 int64_t offset = 0; |
3902 switch (format[5]) { | 1614 switch (format[5]) { |
3903 // TImmUncn - unconditional branch immediate. | 1615 // BImmUncn - unconditional branch immediate. |
3904 case 'n': offset = instr->ImmUncondBranch(); break; | 1616 case 'n': offset = instr->ImmUncondBranch(); break; |
3905 // TImmCond - conditional branch immediate. | 1617 // BImmCond - conditional branch immediate. |
3906 case 'o': offset = instr->ImmCondBranch(); break; | 1618 case 'o': offset = instr->ImmCondBranch(); break; |
3907 // TImmCmpa - compare and branch immediate. | 1619 // BImmCmpa - compare and branch immediate. |
3908 case 'm': offset = instr->ImmCmpBranch(); break; | 1620 case 'm': offset = instr->ImmCmpBranch(); break; |
3909 // TImmTest - test and branch immediate. | 1621 // BImmTest - test and branch immediate. |
3910 case 'e': offset = instr->ImmTestBranch(); break; | 1622 case 'e': offset = instr->ImmTestBranch(); break; |
3911 default: UNREACHABLE(); | 1623 default: UNREACHABLE(); |
3912 } | 1624 } |
3913 offset <<= kInstructionSizeLog2; | 1625 offset <<= kInstructionSizeLog2; |
3914 char sign = '+'; | 1626 char sign = '+'; |
3915 if (offset < 0) { | 1627 if (offset < 0) { |
3916 sign = '-'; | 1628 sign = '-'; |
3917 } | 1629 } |
3918 AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset), | 1630 AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset), |
3919 instr->InstructionAtOffset(offset), Instruction::NO_CHECK); | 1631 instr->InstructionAtOffset(offset), Instruction::NO_CHECK); |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4129 decoder.AppendVisitor(&disasm); | 1841 decoder.AppendVisitor(&disasm); |
4130 | 1842 |
4131 for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) { | 1843 for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) { |
4132 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc)); | 1844 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc)); |
4133 } | 1845 } |
4134 } | 1846 } |
4135 | 1847 |
4136 } // namespace disasm | 1848 } // namespace disasm |
4137 | 1849 |
4138 #endif // V8_TARGET_ARCH_ARM64 | 1850 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |