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" |
14 #include "src/base/platform/platform.h" | 15 #include "src/base/platform/platform.h" |
15 #include "src/disasm.h" | 16 #include "src/disasm.h" |
16 #include "src/macro-assembler.h" | 17 #include "src/macro-assembler.h" |
17 | 18 |
18 namespace v8 { | 19 namespace v8 { |
19 namespace internal { | 20 namespace internal { |
20 | 21 |
21 | 22 |
22 DisassemblingDecoder::DisassemblingDecoder() { | 23 DisassemblingDecoder::DisassemblingDecoder() { |
23 buffer_size_ = 256; | 24 buffer_size_ = 256; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 default: UNREACHABLE(); | 88 default: UNREACHABLE(); |
88 } | 89 } |
89 Format(instr, mnemonic, form); | 90 Format(instr, mnemonic, form); |
90 } | 91 } |
91 | 92 |
92 | 93 |
93 void DisassemblingDecoder::VisitAddSubShifted(Instruction* instr) { | 94 void DisassemblingDecoder::VisitAddSubShifted(Instruction* instr) { |
94 bool rd_is_zr = RdIsZROrSP(instr); | 95 bool rd_is_zr = RdIsZROrSP(instr); |
95 bool rn_is_zr = RnIsZROrSP(instr); | 96 bool rn_is_zr = RnIsZROrSP(instr); |
96 const char *mnemonic = ""; | 97 const char *mnemonic = ""; |
97 const char *form = "'Rd, 'Rn, 'Rm'HDP"; | 98 const char* form = "'Rd, 'Rn, 'Rm'NDP"; |
98 const char *form_cmp = "'Rn, 'Rm'HDP"; | 99 const char* form_cmp = "'Rn, 'Rm'NDP"; |
99 const char *form_neg = "'Rd, 'Rm'HDP"; | 100 const char* form_neg = "'Rd, 'Rm'NDP"; |
100 | 101 |
101 switch (instr->Mask(AddSubShiftedMask)) { | 102 switch (instr->Mask(AddSubShiftedMask)) { |
102 case ADD_w_shift: | 103 case ADD_w_shift: |
103 case ADD_x_shift: mnemonic = "add"; break; | 104 case ADD_x_shift: mnemonic = "add"; break; |
104 case ADDS_w_shift: | 105 case ADDS_w_shift: |
105 case ADDS_x_shift: { | 106 case ADDS_x_shift: { |
106 mnemonic = "adds"; | 107 mnemonic = "adds"; |
107 if (rd_is_zr) { | 108 if (rd_is_zr) { |
108 mnemonic = "cmn"; | 109 mnemonic = "cmn"; |
109 form = form_cmp; | 110 form = form_cmp; |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 return true; | 280 return true; |
280 } | 281 } |
281 return false; | 282 return false; |
282 } | 283 } |
283 | 284 |
284 | 285 |
285 void DisassemblingDecoder::VisitLogicalShifted(Instruction* instr) { | 286 void DisassemblingDecoder::VisitLogicalShifted(Instruction* instr) { |
286 bool rd_is_zr = RdIsZROrSP(instr); | 287 bool rd_is_zr = RdIsZROrSP(instr); |
287 bool rn_is_zr = RnIsZROrSP(instr); | 288 bool rn_is_zr = RnIsZROrSP(instr); |
288 const char *mnemonic = ""; | 289 const char *mnemonic = ""; |
289 const char *form = "'Rd, 'Rn, 'Rm'HLo"; | 290 const char* form = "'Rd, 'Rn, 'Rm'NLo"; |
290 | 291 |
291 switch (instr->Mask(LogicalShiftedMask)) { | 292 switch (instr->Mask(LogicalShiftedMask)) { |
292 case AND_w: | 293 case AND_w: |
293 case AND_x: mnemonic = "and"; break; | 294 case AND_x: mnemonic = "and"; break; |
294 case BIC_w: | 295 case BIC_w: |
295 case BIC_x: mnemonic = "bic"; break; | 296 case BIC_x: mnemonic = "bic"; break; |
296 case EOR_w: | 297 case EOR_w: |
297 case EOR_x: mnemonic = "eor"; break; | 298 case EOR_x: mnemonic = "eor"; break; |
298 case EON_w: | 299 case EON_w: |
299 case EON_x: mnemonic = "eon"; break; | 300 case EON_x: mnemonic = "eon"; break; |
300 case BICS_w: | 301 case BICS_w: |
301 case BICS_x: mnemonic = "bics"; break; | 302 case BICS_x: mnemonic = "bics"; break; |
302 case ANDS_w: | 303 case ANDS_w: |
303 case ANDS_x: { | 304 case ANDS_x: { |
304 mnemonic = "ands"; | 305 mnemonic = "ands"; |
305 if (rd_is_zr) { | 306 if (rd_is_zr) { |
306 mnemonic = "tst"; | 307 mnemonic = "tst"; |
307 form = "'Rn, 'Rm'HLo"; | 308 form = "'Rn, 'Rm'NLo"; |
308 } | 309 } |
309 break; | 310 break; |
310 } | 311 } |
311 case ORR_w: | 312 case ORR_w: |
312 case ORR_x: { | 313 case ORR_x: { |
313 mnemonic = "orr"; | 314 mnemonic = "orr"; |
314 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) { | 315 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) { |
315 mnemonic = "mov"; | 316 mnemonic = "mov"; |
316 form = "'Rd, 'Rm"; | 317 form = "'Rd, 'Rm"; |
317 } | 318 } |
318 break; | 319 break; |
319 } | 320 } |
320 case ORN_w: | 321 case ORN_w: |
321 case ORN_x: { | 322 case ORN_x: { |
322 mnemonic = "orn"; | 323 mnemonic = "orn"; |
323 if (rn_is_zr) { | 324 if (rn_is_zr) { |
324 mnemonic = "mvn"; | 325 mnemonic = "mvn"; |
325 form = "'Rd, 'Rm'HLo"; | 326 form = "'Rd, 'Rm'NLo"; |
326 } | 327 } |
327 break; | 328 break; |
328 } | 329 } |
329 default: UNREACHABLE(); | 330 default: UNREACHABLE(); |
330 } | 331 } |
331 | 332 |
332 Format(instr, mnemonic, form); | 333 Format(instr, mnemonic, form); |
333 } | 334 } |
334 | 335 |
335 | 336 |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
520 switch (instr->Mask(PCRelAddressingMask)) { | 521 switch (instr->Mask(PCRelAddressingMask)) { |
521 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break; | 522 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break; |
522 // ADRP is not implemented. | 523 // ADRP is not implemented. |
523 default: Format(instr, "unimplemented", "(PCRelAddressing)"); | 524 default: Format(instr, "unimplemented", "(PCRelAddressing)"); |
524 } | 525 } |
525 } | 526 } |
526 | 527 |
527 | 528 |
528 void DisassemblingDecoder::VisitConditionalBranch(Instruction* instr) { | 529 void DisassemblingDecoder::VisitConditionalBranch(Instruction* instr) { |
529 switch (instr->Mask(ConditionalBranchMask)) { | 530 switch (instr->Mask(ConditionalBranchMask)) { |
530 case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break; | 531 case B_cond: |
| 532 Format(instr, "b.'CBrn", "'TImmCond"); |
| 533 break; |
531 default: UNREACHABLE(); | 534 default: UNREACHABLE(); |
532 } | 535 } |
533 } | 536 } |
534 | 537 |
535 | 538 |
536 void DisassemblingDecoder::VisitUnconditionalBranchToRegister( | 539 void DisassemblingDecoder::VisitUnconditionalBranchToRegister( |
537 Instruction* instr) { | 540 Instruction* instr) { |
538 const char *mnemonic = "unimplemented"; | 541 const char *mnemonic = "unimplemented"; |
539 const char *form = "'Xn"; | 542 const char *form = "'Xn"; |
540 | 543 |
541 switch (instr->Mask(UnconditionalBranchToRegisterMask)) { | 544 switch (instr->Mask(UnconditionalBranchToRegisterMask)) { |
542 case BR: mnemonic = "br"; break; | 545 case BR: mnemonic = "br"; break; |
543 case BLR: mnemonic = "blr"; break; | 546 case BLR: mnemonic = "blr"; break; |
544 case RET: { | 547 case RET: { |
545 mnemonic = "ret"; | 548 mnemonic = "ret"; |
546 if (instr->Rn() == kLinkRegCode) { | 549 if (instr->Rn() == kLinkRegCode) { |
547 form = NULL; | 550 form = NULL; |
548 } | 551 } |
549 break; | 552 break; |
550 } | 553 } |
551 default: form = "(UnconditionalBranchToRegister)"; | 554 default: form = "(UnconditionalBranchToRegister)"; |
552 } | 555 } |
553 Format(instr, mnemonic, form); | 556 Format(instr, mnemonic, form); |
554 } | 557 } |
555 | 558 |
556 | 559 |
557 void DisassemblingDecoder::VisitUnconditionalBranch(Instruction* instr) { | 560 void DisassemblingDecoder::VisitUnconditionalBranch(Instruction* instr) { |
558 const char *mnemonic = ""; | 561 const char *mnemonic = ""; |
559 const char *form = "'BImmUncn"; | 562 const char* form = "'TImmUncn"; |
560 | 563 |
561 switch (instr->Mask(UnconditionalBranchMask)) { | 564 switch (instr->Mask(UnconditionalBranchMask)) { |
562 case B: mnemonic = "b"; break; | 565 case B: mnemonic = "b"; break; |
563 case BL: mnemonic = "bl"; break; | 566 case BL: mnemonic = "bl"; break; |
564 default: UNREACHABLE(); | 567 default: UNREACHABLE(); |
565 } | 568 } |
566 Format(instr, mnemonic, form); | 569 Format(instr, mnemonic, form); |
567 } | 570 } |
568 | 571 |
569 | 572 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
682 break; | 685 break; |
683 } | 686 } |
684 default: UNREACHABLE(); | 687 default: UNREACHABLE(); |
685 } | 688 } |
686 Format(instr, mnemonic, form); | 689 Format(instr, mnemonic, form); |
687 } | 690 } |
688 | 691 |
689 | 692 |
690 void DisassemblingDecoder::VisitCompareBranch(Instruction* instr) { | 693 void DisassemblingDecoder::VisitCompareBranch(Instruction* instr) { |
691 const char *mnemonic = ""; | 694 const char *mnemonic = ""; |
692 const char *form = "'Rt, 'BImmCmpa"; | 695 const char* form = "'Rt, 'TImmCmpa"; |
693 | 696 |
694 switch (instr->Mask(CompareBranchMask)) { | 697 switch (instr->Mask(CompareBranchMask)) { |
695 case CBZ_w: | 698 case CBZ_w: |
696 case CBZ_x: mnemonic = "cbz"; break; | 699 case CBZ_x: mnemonic = "cbz"; break; |
697 case CBNZ_w: | 700 case CBNZ_w: |
698 case CBNZ_x: mnemonic = "cbnz"; break; | 701 case CBNZ_x: mnemonic = "cbnz"; break; |
699 default: UNREACHABLE(); | 702 default: UNREACHABLE(); |
700 } | 703 } |
701 Format(instr, mnemonic, form); | 704 Format(instr, mnemonic, form); |
702 } | 705 } |
703 | 706 |
704 | 707 |
705 void DisassemblingDecoder::VisitTestBranch(Instruction* instr) { | 708 void DisassemblingDecoder::VisitTestBranch(Instruction* instr) { |
706 const char *mnemonic = ""; | 709 const char *mnemonic = ""; |
707 // If the top bit of the immediate is clear, the tested register is | 710 // If the top bit of the immediate is clear, the tested register is |
708 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is | 711 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is |
709 // encoded in bit 31 of the instruction, we can reuse the Rt form, which | 712 // encoded in bit 31 of the instruction, we can reuse the Rt form, which |
710 // uses bit 31 (normally "sf") to choose the register size. | 713 // uses bit 31 (normally "sf") to choose the register size. |
711 const char *form = "'Rt, 'IS, 'BImmTest"; | 714 const char* form = "'Rt, 'IS, 'TImmTest"; |
712 | 715 |
713 switch (instr->Mask(TestBranchMask)) { | 716 switch (instr->Mask(TestBranchMask)) { |
714 case TBZ: mnemonic = "tbz"; break; | 717 case TBZ: mnemonic = "tbz"; break; |
715 case TBNZ: mnemonic = "tbnz"; break; | 718 case TBNZ: mnemonic = "tbnz"; break; |
716 default: UNREACHABLE(); | 719 default: UNREACHABLE(); |
717 } | 720 } |
718 Format(instr, mnemonic, form); | 721 Format(instr, mnemonic, form); |
719 } | 722 } |
720 | 723 |
721 | 724 |
722 void DisassemblingDecoder::VisitMoveWideImmediate(Instruction* instr) { | 725 void DisassemblingDecoder::VisitMoveWideImmediate(Instruction* instr) { |
723 const char *mnemonic = ""; | 726 const char *mnemonic = ""; |
724 const char *form = "'Rd, 'IMoveImm"; | 727 const char *form = "'Rd, 'IMoveImm"; |
725 | 728 |
726 // Print the shift separately for movk, to make it clear which half word will | 729 // Print the shift separately for movk, to make it clear which half word will |
727 // be overwritten. Movn and movz print the computed immediate, which includes | 730 // be overwritten. Movn and movz print the computed immediate, which includes |
728 // shift calculation. | 731 // shift calculation. |
729 switch (instr->Mask(MoveWideImmediateMask)) { | 732 switch (instr->Mask(MoveWideImmediateMask)) { |
730 case MOVN_w: | 733 case MOVN_w: |
731 case MOVN_x: mnemonic = "movn"; break; | 734 case MOVN_x: mnemonic = "movn"; break; |
732 case MOVZ_w: | 735 case MOVZ_w: |
733 case MOVZ_x: mnemonic = "movz"; break; | 736 case MOVZ_x: mnemonic = "movz"; break; |
734 case MOVK_w: | 737 case MOVK_w: |
735 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break; | 738 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break; |
736 default: UNREACHABLE(); | 739 default: UNREACHABLE(); |
737 } | 740 } |
738 Format(instr, mnemonic, form); | 741 Format(instr, mnemonic, form); |
739 } | 742 } |
740 | 743 |
741 | 744 #define LOAD_STORE_LIST(V) \ |
742 #define LOAD_STORE_LIST(V) \ | 745 V(STRB_w, "strb", "'Wt") \ |
743 V(STRB_w, "strb", "'Wt") \ | 746 V(STRH_w, "strh", "'Wt") \ |
744 V(STRH_w, "strh", "'Wt") \ | 747 V(STR_w, "str", "'Wt") \ |
745 V(STR_w, "str", "'Wt") \ | 748 V(STR_x, "str", "'Xt") \ |
746 V(STR_x, "str", "'Xt") \ | 749 V(LDRB_w, "ldrb", "'Wt") \ |
747 V(LDRB_w, "ldrb", "'Wt") \ | 750 V(LDRH_w, "ldrh", "'Wt") \ |
748 V(LDRH_w, "ldrh", "'Wt") \ | 751 V(LDR_w, "ldr", "'Wt") \ |
749 V(LDR_w, "ldr", "'Wt") \ | 752 V(LDR_x, "ldr", "'Xt") \ |
750 V(LDR_x, "ldr", "'Xt") \ | 753 V(LDRSB_x, "ldrsb", "'Xt") \ |
751 V(LDRSB_x, "ldrsb", "'Xt") \ | 754 V(LDRSH_x, "ldrsh", "'Xt") \ |
752 V(LDRSH_x, "ldrsh", "'Xt") \ | 755 V(LDRSW_x, "ldrsw", "'Xt") \ |
753 V(LDRSW_x, "ldrsw", "'Xt") \ | 756 V(LDRSB_w, "ldrsb", "'Wt") \ |
754 V(LDRSB_w, "ldrsb", "'Wt") \ | 757 V(LDRSH_w, "ldrsh", "'Wt") \ |
755 V(LDRSH_w, "ldrsh", "'Wt") \ | 758 V(STR_b, "str", "'Bt") \ |
756 V(STR_s, "str", "'St") \ | 759 V(STR_h, "str", "'Ht") \ |
757 V(STR_d, "str", "'Dt") \ | 760 V(STR_s, "str", "'St") \ |
758 V(LDR_s, "ldr", "'St") \ | 761 V(STR_d, "str", "'Dt") \ |
759 V(LDR_d, "ldr", "'Dt") | 762 V(LDR_b, "ldr", "'Bt") \ |
| 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") |
760 | 768 |
761 void DisassemblingDecoder::VisitLoadStorePreIndex(Instruction* instr) { | 769 void DisassemblingDecoder::VisitLoadStorePreIndex(Instruction* instr) { |
762 const char *mnemonic = "unimplemented"; | 770 const char *mnemonic = "unimplemented"; |
763 const char *form = "(LoadStorePreIndex)"; | 771 const char *form = "(LoadStorePreIndex)"; |
764 | 772 |
765 switch (instr->Mask(LoadStorePreIndexMask)) { | 773 switch (instr->Mask(LoadStorePreIndexMask)) { |
766 #define LS_PREINDEX(A, B, C) \ | 774 #define LS_PREINDEX(A, B, C) \ |
767 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break; | 775 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break; |
768 LOAD_STORE_LIST(LS_PREINDEX) | 776 LOAD_STORE_LIST(LS_PREINDEX) |
769 #undef LS_PREINDEX | 777 #undef LS_PREINDEX |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
854 switch (instr->Mask(LoadLiteralMask)) { | 862 switch (instr->Mask(LoadLiteralMask)) { |
855 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break; | 863 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break; |
856 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break; | 864 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break; |
857 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break; | 865 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break; |
858 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break; | 866 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break; |
859 default: mnemonic = "unimplemented"; | 867 default: mnemonic = "unimplemented"; |
860 } | 868 } |
861 Format(instr, mnemonic, form); | 869 Format(instr, mnemonic, form); |
862 } | 870 } |
863 | 871 |
864 | |
865 #define LOAD_STORE_PAIR_LIST(V) \ | 872 #define LOAD_STORE_PAIR_LIST(V) \ |
866 V(STP_w, "stp", "'Wt, 'Wt2", "4") \ | 873 V(STP_w, "stp", "'Wt, 'Wt2", "2") \ |
867 V(LDP_w, "ldp", "'Wt, 'Wt2", "4") \ | 874 V(LDP_w, "ldp", "'Wt, 'Wt2", "2") \ |
868 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \ | 875 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "2") \ |
869 V(STP_x, "stp", "'Xt, 'Xt2", "8") \ | 876 V(STP_x, "stp", "'Xt, 'Xt2", "3") \ |
870 V(LDP_x, "ldp", "'Xt, 'Xt2", "8") \ | 877 V(LDP_x, "ldp", "'Xt, 'Xt2", "3") \ |
871 V(STP_s, "stp", "'St, 'St2", "4") \ | 878 V(STP_s, "stp", "'St, 'St2", "2") \ |
872 V(LDP_s, "ldp", "'St, 'St2", "4") \ | 879 V(LDP_s, "ldp", "'St, 'St2", "2") \ |
873 V(STP_d, "stp", "'Dt, 'Dt2", "8") \ | 880 V(STP_d, "stp", "'Dt, 'Dt2", "3") \ |
874 V(LDP_d, "ldp", "'Dt, 'Dt2", "8") | 881 V(LDP_d, "ldp", "'Dt, 'Dt2", "3") \ |
| 882 V(LDP_q, "ldp", "'Qt, 'Qt2", "4") \ |
| 883 V(STP_q, "stp", "'Qt, 'Qt2", "4") |
875 | 884 |
876 void DisassemblingDecoder::VisitLoadStorePairPostIndex(Instruction* instr) { | 885 void DisassemblingDecoder::VisitLoadStorePairPostIndex(Instruction* instr) { |
877 const char *mnemonic = "unimplemented"; | 886 const char *mnemonic = "unimplemented"; |
878 const char *form = "(LoadStorePairPostIndex)"; | 887 const char *form = "(LoadStorePairPostIndex)"; |
879 | 888 |
880 switch (instr->Mask(LoadStorePairPostIndexMask)) { | 889 switch (instr->Mask(LoadStorePairPostIndexMask)) { |
881 #define LSP_POSTINDEX(A, B, C, D) \ | 890 #define LSP_POSTINDEX(A, B, C, D) \ |
882 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break; | 891 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break; |
883 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX) | 892 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX) |
884 #undef LSP_POSTINDEX | 893 #undef LSP_POSTINDEX |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1003 FORMAT(FRINTN, "frintn"); | 1012 FORMAT(FRINTN, "frintn"); |
1004 FORMAT(FRINTP, "frintp"); | 1013 FORMAT(FRINTP, "frintp"); |
1005 FORMAT(FRINTM, "frintm"); | 1014 FORMAT(FRINTM, "frintm"); |
1006 FORMAT(FRINTZ, "frintz"); | 1015 FORMAT(FRINTZ, "frintz"); |
1007 FORMAT(FRINTA, "frinta"); | 1016 FORMAT(FRINTA, "frinta"); |
1008 FORMAT(FRINTX, "frintx"); | 1017 FORMAT(FRINTX, "frintx"); |
1009 FORMAT(FRINTI, "frinti"); | 1018 FORMAT(FRINTI, "frinti"); |
1010 #undef FORMAT | 1019 #undef FORMAT |
1011 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break; | 1020 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break; |
1012 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break; | 1021 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; |
1013 default: form = "(FPDataProcessing1Source)"; | 1038 default: form = "(FPDataProcessing1Source)"; |
1014 } | 1039 } |
1015 Format(instr, mnemonic, form); | 1040 Format(instr, mnemonic, form); |
1016 } | 1041 } |
1017 | 1042 |
1018 | 1043 |
1019 void DisassemblingDecoder::VisitFPDataProcessing2Source(Instruction* instr) { | 1044 void DisassemblingDecoder::VisitFPDataProcessing2Source(Instruction* instr) { |
1020 const char *mnemonic = ""; | 1045 const char *mnemonic = ""; |
1021 const char *form = "'Fd, 'Fn, 'Fm"; | 1046 const char *form = "'Fd, 'Fn, 'Fm"; |
1022 | 1047 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1076 const char *mnemonic = "unimplemented"; | 1101 const char *mnemonic = "unimplemented"; |
1077 const char *form = "(FPIntegerConvert)"; | 1102 const char *form = "(FPIntegerConvert)"; |
1078 const char *form_rf = "'Rd, 'Fn"; | 1103 const char *form_rf = "'Rd, 'Fn"; |
1079 const char *form_fr = "'Fd, 'Rn"; | 1104 const char *form_fr = "'Fd, 'Rn"; |
1080 | 1105 |
1081 switch (instr->Mask(FPIntegerConvertMask)) { | 1106 switch (instr->Mask(FPIntegerConvertMask)) { |
1082 case FMOV_ws: | 1107 case FMOV_ws: |
1083 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break; | 1108 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break; |
1084 case FMOV_sw: | 1109 case FMOV_sw: |
1085 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break; | 1110 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; |
1086 case FCVTAS_ws: | 1119 case FCVTAS_ws: |
1087 case FCVTAS_xs: | 1120 case FCVTAS_xs: |
1088 case FCVTAS_wd: | 1121 case FCVTAS_wd: |
1089 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break; | 1122 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break; |
1090 case FCVTAU_ws: | 1123 case FCVTAU_ws: |
1091 case FCVTAU_xs: | 1124 case FCVTAU_xs: |
1092 case FCVTAU_wd: | 1125 case FCVTAU_wd: |
1093 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break; | 1126 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break; |
1094 case FCVTMS_ws: | 1127 case FCVTMS_ws: |
1095 case FCVTMS_xs: | 1128 case FCVTMS_xs: |
(...skipping 12 matching lines...) Expand all Loading... |
1108 case FCVTNU_wd: | 1141 case FCVTNU_wd: |
1109 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break; | 1142 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break; |
1110 case FCVTZU_xd: | 1143 case FCVTZU_xd: |
1111 case FCVTZU_ws: | 1144 case FCVTZU_ws: |
1112 case FCVTZU_wd: | 1145 case FCVTZU_wd: |
1113 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break; | 1146 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break; |
1114 case FCVTZS_xd: | 1147 case FCVTZS_xd: |
1115 case FCVTZS_wd: | 1148 case FCVTZS_wd: |
1116 case FCVTZS_xs: | 1149 case FCVTZS_xs: |
1117 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break; | 1150 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; |
1118 case SCVTF_sw: | 1165 case SCVTF_sw: |
1119 case SCVTF_sx: | 1166 case SCVTF_sx: |
1120 case SCVTF_dw: | 1167 case SCVTF_dw: |
1121 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break; | 1168 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break; |
1122 case UCVTF_sw: | 1169 case UCVTF_sw: |
1123 case UCVTF_sx: | 1170 case UCVTF_sx: |
1124 case UCVTF_dw: | 1171 case UCVTF_dw: |
1125 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break; | 1172 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break; |
1126 } | 1173 } |
1127 Format(instr, mnemonic, form); | 1174 Format(instr, mnemonic, form); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1227 case HVC: mnemonic = "hvc"; break; | 1274 case HVC: mnemonic = "hvc"; break; |
1228 case SMC: mnemonic = "smc"; break; | 1275 case SMC: mnemonic = "smc"; break; |
1229 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break; | 1276 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break; |
1230 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break; | 1277 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break; |
1231 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break; | 1278 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break; |
1232 default: form = "(Exception)"; | 1279 default: form = "(Exception)"; |
1233 } | 1280 } |
1234 Format(instr, mnemonic, form); | 1281 Format(instr, mnemonic, form); |
1235 } | 1282 } |
1236 | 1283 |
| 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 } |
1237 | 3282 |
1238 void DisassemblingDecoder::VisitUnimplemented(Instruction* instr) { | 3283 void DisassemblingDecoder::VisitUnimplemented(Instruction* instr) { |
1239 Format(instr, "unimplemented", "(Unimplemented)"); | 3284 Format(instr, "unimplemented", "(Unimplemented)"); |
1240 } | 3285 } |
1241 | 3286 |
1242 | |
1243 void DisassemblingDecoder::VisitUnallocated(Instruction* instr) { | 3287 void DisassemblingDecoder::VisitUnallocated(Instruction* instr) { |
1244 Format(instr, "unallocated", "(Unallocated)"); | 3288 Format(instr, "unallocated", "(Unallocated)"); |
1245 } | 3289 } |
1246 | 3290 |
1247 | |
1248 void DisassemblingDecoder::ProcessOutput(Instruction* /*instr*/) { | 3291 void DisassemblingDecoder::ProcessOutput(Instruction* /*instr*/) { |
1249 // The base disasm does nothing more than disassembling into a buffer. | 3292 // The base disasm does nothing more than disassembling into a buffer. |
1250 } | 3293 } |
1251 | 3294 |
| 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 } |
1252 | 3344 |
1253 void DisassemblingDecoder::Format(Instruction* instr, const char* mnemonic, | 3345 void DisassemblingDecoder::Format(Instruction* instr, const char* mnemonic, |
1254 const char* format) { | 3346 const char* format) { |
1255 // TODO(mcapewel) don't think I can use the instr address here - there needs | 3347 // TODO(mcapewel) don't think I can use the instr address here - there needs |
1256 // to be a base address too | 3348 // to be a base address too |
1257 DCHECK(mnemonic != NULL); | 3349 DCHECK(mnemonic != NULL); |
1258 ResetOutput(); | 3350 ResetOutput(); |
1259 Substitute(instr, mnemonic); | 3351 Substitute(instr, mnemonic); |
1260 if (format != NULL) { | 3352 if (format != NULL) { |
1261 buffer_[buffer_pos_++] = ' '; | 3353 buffer_[buffer_pos_++] = ' '; |
1262 Substitute(instr, format); | 3354 Substitute(instr, format); |
1263 } | 3355 } |
1264 buffer_[buffer_pos_] = 0; | 3356 buffer_[buffer_pos_] = 0; |
1265 ProcessOutput(instr); | 3357 ProcessOutput(instr); |
1266 } | 3358 } |
1267 | 3359 |
1268 | |
1269 void DisassemblingDecoder::Substitute(Instruction* instr, const char* string) { | 3360 void DisassemblingDecoder::Substitute(Instruction* instr, const char* string) { |
1270 char chr = *string++; | 3361 char chr = *string++; |
1271 while (chr != '\0') { | 3362 while (chr != '\0') { |
1272 if (chr == '\'') { | 3363 if (chr == '\'') { |
1273 string += SubstituteField(instr, string); | 3364 string += SubstituteField(instr, string); |
1274 } else { | 3365 } else { |
1275 buffer_[buffer_pos_++] = chr; | 3366 buffer_[buffer_pos_++] = chr; |
1276 } | 3367 } |
1277 chr = *string++; | 3368 chr = *string++; |
1278 } | 3369 } |
1279 } | 3370 } |
1280 | 3371 |
1281 | |
1282 int DisassemblingDecoder::SubstituteField(Instruction* instr, | 3372 int DisassemblingDecoder::SubstituteField(Instruction* instr, |
1283 const char* format) { | 3373 const char* format) { |
1284 switch (format[0]) { | 3374 switch (format[0]) { |
| 3375 // NB. The remaining substitution prefix characters are: GJKUZ. |
1285 case 'R': // Register. X or W, selected by sf bit. | 3376 case 'R': // Register. X or W, selected by sf bit. |
1286 case 'F': // FP Register. S or D, selected by type field. | 3377 case 'F': // FP register. S or D, selected by type field. |
| 3378 case 'V': // Vector register, V, vector format. |
1287 case 'W': | 3379 case 'W': |
1288 case 'X': | 3380 case 'X': |
| 3381 case 'B': |
| 3382 case 'H': |
1289 case 'S': | 3383 case 'S': |
1290 case 'D': return SubstituteRegisterField(instr, format); | 3384 case 'D': |
1291 case 'I': return SubstituteImmediateField(instr, format); | 3385 case 'Q': |
1292 case 'L': return SubstituteLiteralField(instr, format); | 3386 return SubstituteRegisterField(instr, format); |
1293 case 'H': return SubstituteShiftField(instr, format); | 3387 case 'I': |
1294 case 'P': return SubstitutePrefetchField(instr, format); | 3388 return SubstituteImmediateField(instr, format); |
1295 case 'C': return SubstituteConditionField(instr, format); | 3389 case 'L': |
1296 case 'E': return SubstituteExtendField(instr, format); | 3390 return SubstituteLiteralField(instr, format); |
1297 case 'A': return SubstitutePCRelAddressField(instr, format); | 3391 case 'N': |
1298 case 'B': return SubstituteBranchTargetField(instr, format); | 3392 return SubstituteShiftField(instr, format); |
1299 case 'O': return SubstituteLSRegOffsetField(instr, format); | 3393 case 'P': |
1300 case 'M': return SubstituteBarrierField(instr, format); | 3394 return SubstitutePrefetchField(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); |
1301 default: { | 3407 default: { |
1302 UNREACHABLE(); | 3408 UNREACHABLE(); |
1303 return 1; | 3409 return 1; |
1304 } | 3410 } |
1305 } | 3411 } |
1306 } | 3412 } |
1307 | 3413 |
1308 | |
1309 int DisassemblingDecoder::SubstituteRegisterField(Instruction* instr, | 3414 int DisassemblingDecoder::SubstituteRegisterField(Instruction* instr, |
1310 const char* format) { | 3415 const char* format) { |
| 3416 char reg_prefix = format[0]; |
1311 unsigned reg_num = 0; | 3417 unsigned reg_num = 0; |
1312 unsigned field_len = 2; | 3418 unsigned field_len = 2; |
| 3419 |
1313 switch (format[1]) { | 3420 switch (format[1]) { |
1314 case 'd': reg_num = instr->Rd(); break; | 3421 case 'd': |
1315 case 'n': reg_num = instr->Rn(); break; | 3422 reg_num = instr->Rd(); |
1316 case 'm': reg_num = instr->Rm(); break; | 3423 if (format[2] == 'q') { |
1317 case 'a': reg_num = instr->Ra(); break; | 3424 reg_prefix = instr->NEONQ() ? 'X' : 'W'; |
1318 case 't': { | |
1319 if (format[2] == '2') { | |
1320 reg_num = instr->Rt2(); | |
1321 field_len = 3; | 3425 field_len = 3; |
| 3426 } |
| 3427 break; |
| 3428 case 'n': |
| 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 } |
1322 } else { | 3478 } else { |
1323 reg_num = instr->Rt(); | 3479 if (format[2] == '2') { |
| 3480 // Handle register specifier Rt2. |
| 3481 reg_num = instr->Rt2(); |
| 3482 field_len = 3; |
| 3483 } |
1324 } | 3484 } |
1325 break; | 3485 break; |
1326 } | |
1327 case 's': | 3486 case 's': |
1328 reg_num = instr->Rs(); | 3487 reg_num = instr->Rs(); |
1329 break; | 3488 break; |
1330 default: UNREACHABLE(); | 3489 default: |
| 3490 UNREACHABLE(); |
1331 } | 3491 } |
1332 | 3492 |
1333 // Increase field length for registers tagged as stack. | 3493 // Increase field length for registers tagged as stack. |
1334 if (format[2] == 's') { | 3494 if (format[2] == 's') { |
1335 field_len = 3; | 3495 field_len = 3; |
1336 } | 3496 } |
1337 | 3497 |
1338 char reg_type; | 3498 CPURegister::RegisterType reg_type; |
1339 if (format[0] == 'R') { | 3499 unsigned reg_size; |
1340 // Register type is R: use sf bit to choose X and W. | 3500 |
1341 reg_type = instr->SixtyFourBits() ? 'x' : 'w'; | 3501 if (reg_prefix == 'R') { |
1342 } else if (format[0] == 'F') { | 3502 reg_prefix = instr->SixtyFourBits() ? 'X' : 'W'; |
1343 // Floating-point register: use type field to choose S or D. | 3503 } else if (reg_prefix == 'F') { |
1344 reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd'; | 3504 reg_prefix = ((instr->FPType() & 1) == 0) ? 'S' : 'D'; |
1345 } else { | 3505 } |
1346 // Register type is specified. Make it lower case. | 3506 |
1347 reg_type = format[0] + 0x20; | 3507 switch (reg_prefix) { |
1348 } | 3508 case 'W': |
1349 | 3509 reg_type = CPURegister::kRegister; |
1350 if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) { | 3510 reg_size = kWRegSizeInBits; |
1351 // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31. | 3511 break; |
1352 | 3512 case 'X': |
1353 // Filter special registers | 3513 reg_type = CPURegister::kRegister; |
1354 if ((reg_type == 'x') && (reg_num == 27)) { | 3514 reg_size = kXRegSizeInBits; |
1355 AppendToOutput("cp"); | 3515 break; |
1356 } else if ((reg_type == 'x') && (reg_num == 28)) { | 3516 case 'B': |
1357 AppendToOutput("jssp"); | 3517 reg_type = CPURegister::kVRegister; |
1358 } else if ((reg_type == 'x') && (reg_num == 29)) { | 3518 reg_size = kBRegSizeInBits; |
1359 AppendToOutput("fp"); | 3519 break; |
1360 } else if ((reg_type == 'x') && (reg_num == 30)) { | 3520 case 'H': |
1361 AppendToOutput("lr"); | 3521 reg_type = CPURegister::kVRegister; |
1362 } else { | 3522 reg_size = kHRegSizeInBits; |
1363 AppendToOutput("%c%d", reg_type, reg_num); | 3523 break; |
1364 } | 3524 case 'S': |
1365 } else if (format[2] == 's') { | 3525 reg_type = CPURegister::kVRegister; |
1366 // Disassemble w31/x31 as stack pointer wcsp/csp. | 3526 reg_size = kSRegSizeInBits; |
1367 AppendToOutput("%s", (reg_type == 'w') ? "wcsp" : "csp"); | 3527 break; |
1368 } else { | 3528 case 'D': |
1369 // Disassemble w31/x31 as zero register wzr/xzr. | 3529 reg_type = CPURegister::kVRegister; |
1370 AppendToOutput("%czr", reg_type); | 3530 reg_size = kDRegSizeInBits; |
1371 } | 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 } |
| 3544 |
| 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)); |
1372 | 3551 |
1373 return field_len; | 3552 return field_len; |
1374 } | 3553 } |
1375 | 3554 |
1376 | |
1377 int DisassemblingDecoder::SubstituteImmediateField(Instruction* instr, | 3555 int DisassemblingDecoder::SubstituteImmediateField(Instruction* instr, |
1378 const char* format) { | 3556 const char* format) { |
1379 DCHECK(format[0] == 'I'); | 3557 DCHECK(format[0] == 'I'); |
1380 | 3558 |
1381 switch (format[1]) { | 3559 switch (format[1]) { |
1382 case 'M': { // IMoveImm or IMoveLSL. | 3560 case 'M': { // IMoveImm or IMoveLSL. |
1383 if (format[5] == 'I') { | 3561 if (format[5] == 'I' || format[5] == 'N') { |
1384 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide()) | 3562 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide()) |
1385 << (16 * instr->ShiftMoveWide()); | 3563 << (16 * instr->ShiftMoveWide()); |
| 3564 if (format[5] == 'N') imm = ~imm; |
| 3565 if (!instr->SixtyFourBits()) imm &= UINT64_C(0xffffffff); |
1386 AppendToOutput("#0x%" PRIx64, imm); | 3566 AppendToOutput("#0x%" PRIx64, imm); |
1387 } else { | 3567 } else { |
1388 DCHECK(format[5] == 'L'); | 3568 DCHECK(format[5] == 'L'); |
1389 AppendToOutput("#0x%" PRIx32, instr->ImmMoveWide()); | 3569 AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide()); |
1390 if (instr->ShiftMoveWide() > 0) { | 3570 if (instr->ShiftMoveWide() > 0) { |
1391 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide()); | 3571 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide()); |
1392 } | 3572 } |
1393 } | 3573 } |
1394 return 8; | 3574 return 8; |
1395 } | 3575 } |
1396 case 'L': { | 3576 case 'L': { |
1397 switch (format[2]) { | 3577 switch (format[2]) { |
1398 case 'L': { // ILLiteral - Immediate Load Literal. | 3578 case 'L': { // ILLiteral - Immediate Load Literal. |
1399 AppendToOutput("pc%+" PRId32, instr->ImmLLiteral() | 3579 AppendToOutput("pc%+" PRId32, instr->ImmLLiteral() |
1400 << kLoadLiteralScaleLog2); | 3580 << kLoadLiteralScaleLog2); |
1401 return 9; | 3581 return 9; |
1402 } | 3582 } |
1403 case 'S': { // ILS - Immediate Load/Store. | 3583 case 'S': { // ILS - Immediate Load/Store. |
1404 if (instr->ImmLS() != 0) { | 3584 if (instr->ImmLS() != 0) { |
1405 AppendToOutput(", #%" PRId32, instr->ImmLS()); | 3585 AppendToOutput(", #%" PRId32, instr->ImmLS()); |
1406 } | 3586 } |
1407 return 3; | 3587 return 3; |
1408 } | 3588 } |
1409 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size. | 3589 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size. |
1410 if (instr->ImmLSPair() != 0) { | 3590 if (instr->ImmLSPair() != 0) { |
1411 // format[3] is the scale value. Convert to a number. | 3591 // format[3] is the scale value. Convert to a number. |
1412 int scale = format[3] - 0x30; | 3592 int scale = 1 << (format[3] - '0'); |
1413 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale); | 3593 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale); |
1414 } | 3594 } |
1415 return 4; | 3595 return 4; |
1416 } | 3596 } |
1417 case 'U': { // ILU - Immediate Load/Store Unsigned. | 3597 case 'U': { // ILU - Immediate Load/Store Unsigned. |
1418 if (instr->ImmLSUnsigned() != 0) { | 3598 if (instr->ImmLSUnsigned() != 0) { |
1419 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned() | 3599 int shift = instr->SizeLS(); |
1420 << instr->SizeLS()); | 3600 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned() << shift); |
1421 } | 3601 } |
1422 return 3; | 3602 return 3; |
1423 } | 3603 } |
1424 } | 3604 } |
1425 } | 3605 } |
1426 case 'C': { // ICondB - Immediate Conditional Branch. | 3606 case 'C': { // ICondB - Immediate Conditional Branch. |
1427 int64_t offset = instr->ImmCondBranch() << 2; | 3607 int64_t offset = instr->ImmCondBranch() << 2; |
1428 char sign = (offset >= 0) ? '+' : '-'; | 3608 char sign = (offset >= 0) ? '+' : '-'; |
1429 AppendToOutput("#%c0x%" PRIx64, sign, offset); | 3609 AppendToOutput("#%c0x%" PRIx64, sign, offset); |
1430 return 6; | 3610 return 6; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1466 } | 3646 } |
1467 case 'E': { // IExtract. | 3647 case 'E': { // IExtract. |
1468 AppendToOutput("#%d", instr->ImmS()); | 3648 AppendToOutput("#%d", instr->ImmS()); |
1469 return 8; | 3649 return 8; |
1470 } | 3650 } |
1471 case 'S': { // IS - Test and branch bit. | 3651 case 'S': { // IS - Test and branch bit. |
1472 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) | | 3652 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) | |
1473 instr->ImmTestBranchBit40()); | 3653 instr->ImmTestBranchBit40()); |
1474 return 2; | 3654 return 2; |
1475 } | 3655 } |
| 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 } |
1476 case 'D': { // IDebug - HLT and BRK instructions. | 3676 case 'D': { // IDebug - HLT and BRK instructions. |
1477 AppendToOutput("#0x%x", instr->ImmException()); | 3677 AppendToOutput("#0x%x", instr->ImmException()); |
1478 return 6; | 3678 return 6; |
1479 } | 3679 } |
| 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 } |
1480 default: { | 3767 default: { |
| 3768 printf("%s", format); |
1481 UNREACHABLE(); | 3769 UNREACHABLE(); |
1482 return 0; | 3770 return 0; |
1483 } | 3771 } |
1484 } | 3772 } |
1485 } | 3773 } |
1486 | 3774 |
1487 | 3775 |
1488 int DisassemblingDecoder::SubstituteBitfieldImmediateField(Instruction* instr, | 3776 int DisassemblingDecoder::SubstituteBitfieldImmediateField(Instruction* instr, |
1489 const char* format) { | 3777 const char* format) { |
1490 DCHECK((format[0] == 'I') && (format[1] == 'B')); | 3778 DCHECK((format[0] == 'I') && (format[1] == 'B')); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1535 break; | 3823 break; |
1536 default: UNREACHABLE(); | 3824 default: UNREACHABLE(); |
1537 } | 3825 } |
1538 | 3826 |
1539 return 6; | 3827 return 6; |
1540 } | 3828 } |
1541 | 3829 |
1542 | 3830 |
1543 int DisassemblingDecoder::SubstituteShiftField(Instruction* instr, | 3831 int DisassemblingDecoder::SubstituteShiftField(Instruction* instr, |
1544 const char* format) { | 3832 const char* format) { |
1545 DCHECK(format[0] == 'H'); | 3833 DCHECK_EQ(format[0], 'N'); |
1546 DCHECK(instr->ShiftDP() <= 0x3); | 3834 DCHECK_LE(instr->ShiftDP(), 0x3); |
1547 | 3835 |
1548 switch (format[1]) { | 3836 switch (format[1]) { |
1549 case 'D': { // HDP. | 3837 case 'D': { // NDP. |
1550 DCHECK(instr->ShiftDP() != ROR); | 3838 DCHECK(instr->ShiftDP() != ROR); |
1551 } // Fall through. | 3839 } // Fall through. |
1552 case 'L': { // HLo. | 3840 case 'L': { // NLo. |
1553 if (instr->ImmDPShift() != 0) { | 3841 if (instr->ImmDPShift() != 0) { |
1554 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"}; | 3842 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"}; |
1555 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()], | 3843 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()], |
1556 instr->ImmDPShift()); | 3844 instr->ImmDPShift()); |
1557 } | 3845 } |
1558 return 3; | 3846 return 3; |
1559 } | 3847 } |
1560 default: | 3848 default: |
1561 UNREACHABLE(); | 3849 UNREACHABLE(); |
1562 return 0; | 3850 return 0; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1601 sign = '-'; | 3889 sign = '-'; |
1602 } | 3890 } |
1603 AppendToOutput("#%c0x%x (addr %p)", sign, offset, | 3891 AppendToOutput("#%c0x%x (addr %p)", sign, offset, |
1604 instr->InstructionAtOffset(offset, Instruction::NO_CHECK)); | 3892 instr->InstructionAtOffset(offset, Instruction::NO_CHECK)); |
1605 return 13; | 3893 return 13; |
1606 } | 3894 } |
1607 | 3895 |
1608 | 3896 |
1609 int DisassemblingDecoder::SubstituteBranchTargetField(Instruction* instr, | 3897 int DisassemblingDecoder::SubstituteBranchTargetField(Instruction* instr, |
1610 const char* format) { | 3898 const char* format) { |
1611 DCHECK(strncmp(format, "BImm", 4) == 0); | 3899 DCHECK_EQ(strncmp(format, "TImm", 4), 0); |
1612 | 3900 |
1613 int64_t offset = 0; | 3901 int64_t offset = 0; |
1614 switch (format[5]) { | 3902 switch (format[5]) { |
1615 // BImmUncn - unconditional branch immediate. | 3903 // TImmUncn - unconditional branch immediate. |
1616 case 'n': offset = instr->ImmUncondBranch(); break; | 3904 case 'n': offset = instr->ImmUncondBranch(); break; |
1617 // BImmCond - conditional branch immediate. | 3905 // TImmCond - conditional branch immediate. |
1618 case 'o': offset = instr->ImmCondBranch(); break; | 3906 case 'o': offset = instr->ImmCondBranch(); break; |
1619 // BImmCmpa - compare and branch immediate. | 3907 // TImmCmpa - compare and branch immediate. |
1620 case 'm': offset = instr->ImmCmpBranch(); break; | 3908 case 'm': offset = instr->ImmCmpBranch(); break; |
1621 // BImmTest - test and branch immediate. | 3909 // TImmTest - test and branch immediate. |
1622 case 'e': offset = instr->ImmTestBranch(); break; | 3910 case 'e': offset = instr->ImmTestBranch(); break; |
1623 default: UNREACHABLE(); | 3911 default: UNREACHABLE(); |
1624 } | 3912 } |
1625 offset <<= kInstructionSizeLog2; | 3913 offset <<= kInstructionSizeLog2; |
1626 char sign = '+'; | 3914 char sign = '+'; |
1627 if (offset < 0) { | 3915 if (offset < 0) { |
1628 sign = '-'; | 3916 sign = '-'; |
1629 } | 3917 } |
1630 AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset), | 3918 AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset), |
1631 instr->InstructionAtOffset(offset), Instruction::NO_CHECK); | 3919 instr->InstructionAtOffset(offset), Instruction::NO_CHECK); |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1841 decoder.AppendVisitor(&disasm); | 4129 decoder.AppendVisitor(&disasm); |
1842 | 4130 |
1843 for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) { | 4131 for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) { |
1844 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc)); | 4132 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc)); |
1845 } | 4133 } |
1846 } | 4134 } |
1847 | 4135 |
1848 } // namespace disasm | 4136 } // namespace disasm |
1849 | 4137 |
1850 #endif // V8_TARGET_ARCH_ARM64 | 4138 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |