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