Chromium Code Reviews| 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}}; | |
|
bbudge
2017/01/31 01:41:32
Could you define some constants to make it clearer
martyn.capewell
2017/02/03 11:01:31
They're just bit positions in the instruction, so
bbudge
2017/02/08 01:39:11
I see. It's OK like this then.
| |
| 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}}; | |
|
bbudge
2017/01/31 01:41:32
magic numbers
bbudge
2017/02/08 01:39:11
OK
| |
| 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}}; | |
|
bbudge
2017/01/31 01:41:32
magic numbers
bbudge
2017/02/08 01:39:11
OK
| |
| 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}, | |
|
bbudge
2017/01/31 01:41:32
magic numbers
bbudge
2017/02/08 01:39:11
OK
| |
| 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}, | |
|
bbudge
2017/01/31 01:41:32
magic numbers
bbudge
2017/02/08 01:39:11
OK
| |
| 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) + 6]; | |
|
bbudge
2017/01/31 01:41:32
magic number (6)
martyn.capewell
2017/02/03 11:01:31
Done.
| |
| 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 Instruction *instr, |
| 1252 void DisassemblingDecoder::Format(Instruction* instr, const char* mnemonic, | 3293 const CPURegister ®) { |
| 1253 const char* format) { | 3294 USE(instr); |
| 3295 DCHECK(reg.IsValid()); | |
| 3296 char reg_char; | |
| 3297 | |
| 3298 if (reg.IsRegister()) { | |
| 3299 reg_char = reg.Is64Bits() ? 'x' : 'w'; | |
| 3300 } else { | |
| 3301 DCHECK(reg.IsVRegister()); | |
| 3302 switch (reg.SizeInBits()) { | |
| 3303 case kBRegSizeInBits: | |
| 3304 reg_char = 'b'; | |
| 3305 break; | |
| 3306 case kHRegSizeInBits: | |
| 3307 reg_char = 'h'; | |
| 3308 break; | |
| 3309 case kSRegSizeInBits: | |
| 3310 reg_char = 's'; | |
| 3311 break; | |
| 3312 case kDRegSizeInBits: | |
| 3313 reg_char = 'd'; | |
| 3314 break; | |
| 3315 default: | |
| 3316 DCHECK(reg.Is128Bits()); | |
| 3317 reg_char = 'q'; | |
| 3318 } | |
| 3319 } | |
| 3320 | |
| 3321 if (reg.IsVRegister() || !(reg.Aliases(csp) || reg.Aliases(xzr))) { | |
| 3322 // Filter special registers | |
| 3323 if (reg.IsX() && (reg.code() == 27)) { | |
| 3324 AppendToOutput("cp"); | |
| 3325 } else if (reg.IsX() && (reg.code() == 28)) { | |
| 3326 AppendToOutput("jssp"); | |
| 3327 } else if (reg.IsX() && (reg.code() == 29)) { | |
| 3328 AppendToOutput("fp"); | |
| 3329 } else if (reg.IsX() && (reg.code() == 30)) { | |
| 3330 AppendToOutput("lr"); | |
| 3331 } else { | |
| 3332 // A core or scalar/vector register: [wx]0 - 30, [bhsdq]0 - 31. | |
| 3333 AppendToOutput("%c%d", reg_char, reg.code()); | |
| 3334 } | |
| 3335 } else if (reg.Aliases(csp)) { | |
| 3336 // Disassemble w31/x31 as stack pointer wcsp/csp. | |
| 3337 AppendToOutput("%s", reg.Is64Bits() ? "csp" : "wcsp"); | |
| 3338 } else { | |
| 3339 // Disassemble w31/x31 as zero register wzr/xzr. | |
| 3340 AppendToOutput("%czr", reg_char); | |
| 3341 } | |
| 3342 } | |
| 3343 | |
| 3344 void DisassemblingDecoder::Format(Instruction *instr, const char *mnemonic, | |
| 3345 const char *format) { | |
| 1254 // TODO(mcapewel) don't think I can use the instr address here - there needs | 3346 // TODO(mcapewel) don't think I can use the instr address here - there needs |
| 1255 // to be a base address too | 3347 // to be a base address too |
| 1256 DCHECK(mnemonic != NULL); | 3348 DCHECK(mnemonic != NULL); |
| 1257 ResetOutput(); | 3349 ResetOutput(); |
| 1258 Substitute(instr, mnemonic); | 3350 Substitute(instr, mnemonic); |
| 1259 if (format != NULL) { | 3351 if (format != NULL) { |
| 1260 buffer_[buffer_pos_++] = ' '; | 3352 buffer_[buffer_pos_++] = ' '; |
| 1261 Substitute(instr, format); | 3353 Substitute(instr, format); |
| 1262 } | 3354 } |
| 1263 buffer_[buffer_pos_] = 0; | 3355 buffer_[buffer_pos_] = 0; |
| 1264 ProcessOutput(instr); | 3356 ProcessOutput(instr); |
| 1265 } | 3357 } |
| 1266 | 3358 |
| 1267 | 3359 void DisassemblingDecoder::Substitute(Instruction *instr, const char *string) { |
| 1268 void DisassemblingDecoder::Substitute(Instruction* instr, const char* string) { | |
| 1269 char chr = *string++; | 3360 char chr = *string++; |
| 1270 while (chr != '\0') { | 3361 while (chr != '\0') { |
| 1271 if (chr == '\'') { | 3362 if (chr == '\'') { |
| 1272 string += SubstituteField(instr, string); | 3363 string += SubstituteField(instr, string); |
| 1273 } else { | 3364 } else { |
| 1274 buffer_[buffer_pos_++] = chr; | 3365 buffer_[buffer_pos_++] = chr; |
| 1275 } | 3366 } |
| 1276 chr = *string++; | 3367 chr = *string++; |
| 1277 } | 3368 } |
| 1278 } | 3369 } |
| 1279 | 3370 |
| 1280 | 3371 int DisassemblingDecoder::SubstituteField(Instruction *instr, |
| 1281 int DisassemblingDecoder::SubstituteField(Instruction* instr, | 3372 const char *format) { |
| 1282 const char* format) { | |
| 1283 switch (format[0]) { | 3373 switch (format[0]) { |
| 3374 // NB. The remaining substitution prefix characters are: GJKUZ. | |
| 1284 case 'R': // Register. X or W, selected by sf bit. | 3375 case 'R': // Register. X or W, selected by sf bit. |
| 1285 case 'F': // FP Register. S or D, selected by type field. | 3376 case 'F': // FP register. S or D, selected by type field. |
| 3377 case 'V': // Vector register, V, vector format. | |
| 1286 case 'W': | 3378 case 'W': |
| 1287 case 'X': | 3379 case 'X': |
| 3380 case 'B': | |
| 3381 case 'H': | |
| 1288 case 'S': | 3382 case 'S': |
| 1289 case 'D': return SubstituteRegisterField(instr, format); | 3383 case 'D': |
| 1290 case 'I': return SubstituteImmediateField(instr, format); | 3384 case 'Q': |
| 1291 case 'L': return SubstituteLiteralField(instr, format); | 3385 return SubstituteRegisterField(instr, format); |
| 1292 case 'H': return SubstituteShiftField(instr, format); | 3386 case 'I': |
| 1293 case 'P': return SubstitutePrefetchField(instr, format); | 3387 return SubstituteImmediateField(instr, format); |
| 1294 case 'C': return SubstituteConditionField(instr, format); | 3388 case 'L': |
| 1295 case 'E': return SubstituteExtendField(instr, format); | 3389 return SubstituteLiteralField(instr, format); |
| 1296 case 'A': return SubstitutePCRelAddressField(instr, format); | 3390 case 'N': |
| 1297 case 'B': return SubstituteBranchTargetField(instr, format); | 3391 return SubstituteShiftField(instr, format); |
| 1298 case 'O': return SubstituteLSRegOffsetField(instr, format); | 3392 case 'P': |
| 1299 case 'M': return SubstituteBarrierField(instr, format); | 3393 return SubstitutePrefetchField(instr, format); |
| 3394 case 'C': | |
| 3395 return SubstituteConditionField(instr, format); | |
| 3396 case 'E': | |
| 3397 return SubstituteExtendField(instr, format); | |
| 3398 case 'A': | |
| 3399 return SubstitutePCRelAddressField(instr, format); | |
| 3400 case 'T': | |
| 3401 return SubstituteBranchTargetField(instr, format); | |
| 3402 case 'O': | |
| 3403 return SubstituteLSRegOffsetField(instr, format); | |
| 3404 case 'M': | |
| 3405 return SubstituteBarrierField(instr, format); | |
| 1300 default: { | 3406 default: { |
| 1301 UNREACHABLE(); | 3407 UNREACHABLE(); |
| 1302 return 1; | 3408 return 1; |
| 1303 } | 3409 } |
| 1304 } | 3410 } |
| 1305 } | 3411 } |
| 1306 | 3412 |
| 1307 | 3413 int DisassemblingDecoder::SubstituteRegisterField(Instruction *instr, |
| 1308 int DisassemblingDecoder::SubstituteRegisterField(Instruction* instr, | 3414 const char *format) { |
| 1309 const char* format) { | 3415 char reg_prefix = format[0]; |
| 1310 unsigned reg_num = 0; | 3416 unsigned reg_num = 0; |
| 1311 unsigned field_len = 2; | 3417 unsigned field_len = 2; |
| 3418 | |
| 1312 switch (format[1]) { | 3419 switch (format[1]) { |
| 1313 case 'd': reg_num = instr->Rd(); break; | 3420 case 'd': |
| 1314 case 'n': reg_num = instr->Rn(); break; | 3421 reg_num = instr->Rd(); |
| 1315 case 'm': reg_num = instr->Rm(); break; | 3422 if (format[2] == 'q') { |
| 1316 case 'a': reg_num = instr->Ra(); break; | 3423 reg_prefix = instr->NEONQ() ? 'X' : 'W'; |
| 1317 case 't': { | |
| 1318 if (format[2] == '2') { | |
| 1319 reg_num = instr->Rt2(); | |
| 1320 field_len = 3; | 3424 field_len = 3; |
| 3425 } | |
| 3426 break; | |
| 3427 case 'n': | |
| 3428 reg_num = instr->Rn(); | |
| 3429 break; | |
| 3430 case 'm': | |
| 3431 reg_num = instr->Rm(); | |
| 3432 switch (format[2]) { | |
| 3433 // Handle registers tagged with b (bytes), z (instruction), or | |
| 3434 // r (registers), used for address updates in | |
| 3435 // NEON load/store instructions. | |
| 3436 case 'r': | |
| 3437 case 'b': | |
| 3438 case 'z': { | |
| 3439 field_len = 3; | |
| 3440 char *eimm; | |
| 3441 int imm = static_cast<int>(strtol(&format[3], &eimm, 10)); | |
| 3442 field_len += eimm - &format[3]; | |
| 3443 if (reg_num == 31) { | |
| 3444 switch (format[2]) { | |
| 3445 case 'z': | |
| 3446 imm *= (1 << instr->NEONLSSize()); | |
| 3447 break; | |
| 3448 case 'r': | |
| 3449 imm *= (instr->NEONQ() == 0) ? kDRegSize : kQRegSize; | |
| 3450 break; | |
| 3451 case 'b': | |
| 3452 break; | |
| 3453 } | |
| 3454 AppendToOutput("#%d", imm); | |
| 3455 return field_len; | |
| 3456 } | |
| 3457 break; | |
| 3458 } | |
| 3459 } | |
| 3460 break; | |
| 3461 case 'e': | |
| 3462 // This is register Rm, but using a 4-bit specifier. Used in NEON | |
| 3463 // by-element instructions. | |
| 3464 reg_num = (instr->Rm() & 0xf); | |
| 3465 break; | |
| 3466 case 'a': | |
| 3467 reg_num = instr->Ra(); | |
| 3468 break; | |
| 3469 case 't': | |
| 3470 reg_num = instr->Rt(); | |
| 3471 if (format[0] == 'V') { | |
| 3472 if ((format[2] >= '2') && (format[2] <= '4')) { | |
| 3473 // Handle consecutive vector register specifiers Vt2, Vt3 and Vt4. | |
| 3474 reg_num = (reg_num + format[2] - '1') % 32; | |
| 3475 field_len = 3; | |
| 3476 } | |
| 1321 } else { | 3477 } else { |
| 1322 reg_num = instr->Rt(); | 3478 if (format[2] == '2') { |
| 3479 // Handle register specifier Rt2. | |
| 3480 reg_num = instr->Rt2(); | |
| 3481 field_len = 3; | |
| 3482 } | |
| 1323 } | 3483 } |
| 1324 break; | 3484 break; |
| 1325 } | |
| 1326 case 's': | 3485 case 's': |
| 1327 reg_num = instr->Rs(); | 3486 reg_num = instr->Rs(); |
| 1328 break; | 3487 break; |
| 1329 default: UNREACHABLE(); | 3488 default: |
| 3489 UNREACHABLE(); | |
| 1330 } | 3490 } |
| 1331 | 3491 |
| 1332 // Increase field length for registers tagged as stack. | 3492 // Increase field length for registers tagged as stack. |
| 1333 if (format[2] == 's') { | 3493 if (format[2] == 's') { |
| 1334 field_len = 3; | 3494 field_len = 3; |
| 1335 } | 3495 } |
| 1336 | 3496 |
| 1337 char reg_type; | 3497 CPURegister::RegisterType reg_type; |
| 1338 if (format[0] == 'R') { | 3498 unsigned reg_size; |
| 1339 // Register type is R: use sf bit to choose X and W. | 3499 |
| 1340 reg_type = instr->SixtyFourBits() ? 'x' : 'w'; | 3500 if (reg_prefix == 'R') { |
| 1341 } else if (format[0] == 'F') { | 3501 reg_prefix = instr->SixtyFourBits() ? 'X' : 'W'; |
| 1342 // Floating-point register: use type field to choose S or D. | 3502 } else if (reg_prefix == 'F') { |
| 1343 reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd'; | 3503 reg_prefix = ((instr->FPType() & 1) == 0) ? 'S' : 'D'; |
| 1344 } else { | 3504 } |
| 1345 // Register type is specified. Make it lower case. | 3505 |
| 1346 reg_type = format[0] + 0x20; | 3506 switch (reg_prefix) { |
| 1347 } | 3507 case 'W': |
| 1348 | 3508 reg_type = CPURegister::kRegister; |
| 1349 if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) { | 3509 reg_size = kWRegSizeInBits; |
| 1350 // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31. | 3510 break; |
| 1351 | 3511 case 'X': |
| 1352 // Filter special registers | 3512 reg_type = CPURegister::kRegister; |
| 1353 if ((reg_type == 'x') && (reg_num == 27)) { | 3513 reg_size = kXRegSizeInBits; |
| 1354 AppendToOutput("cp"); | 3514 break; |
| 1355 } else if ((reg_type == 'x') && (reg_num == 28)) { | 3515 case 'B': |
| 1356 AppendToOutput("jssp"); | 3516 reg_type = CPURegister::kVRegister; |
| 1357 } else if ((reg_type == 'x') && (reg_num == 29)) { | 3517 reg_size = kBRegSizeInBits; |
| 1358 AppendToOutput("fp"); | 3518 break; |
| 1359 } else if ((reg_type == 'x') && (reg_num == 30)) { | 3519 case 'H': |
| 1360 AppendToOutput("lr"); | 3520 reg_type = CPURegister::kVRegister; |
| 1361 } else { | 3521 reg_size = kHRegSizeInBits; |
| 1362 AppendToOutput("%c%d", reg_type, reg_num); | 3522 break; |
| 1363 } | 3523 case 'S': |
| 1364 } else if (format[2] == 's') { | 3524 reg_type = CPURegister::kVRegister; |
| 1365 // Disassemble w31/x31 as stack pointer wcsp/csp. | 3525 reg_size = kSRegSizeInBits; |
| 1366 AppendToOutput("%s", (reg_type == 'w') ? "wcsp" : "csp"); | 3526 break; |
| 1367 } else { | 3527 case 'D': |
| 1368 // Disassemble w31/x31 as zero register wzr/xzr. | 3528 reg_type = CPURegister::kVRegister; |
| 1369 AppendToOutput("%czr", reg_type); | 3529 reg_size = kDRegSizeInBits; |
| 1370 } | 3530 break; |
| 3531 case 'Q': | |
| 3532 reg_type = CPURegister::kVRegister; | |
| 3533 reg_size = kQRegSizeInBits; | |
| 3534 break; | |
| 3535 case 'V': | |
| 3536 AppendToOutput("v%d", reg_num); | |
| 3537 return field_len; | |
| 3538 default: | |
| 3539 UNREACHABLE(); | |
| 3540 reg_type = CPURegister::kRegister; | |
| 3541 reg_size = kXRegSizeInBits; | |
| 3542 } | |
| 3543 | |
| 3544 if ((reg_type == CPURegister::kRegister) && (reg_num == kZeroRegCode) && | |
| 3545 (format[2] == 's')) { | |
| 3546 reg_num = kSPRegInternalCode; | |
| 3547 } | |
| 3548 | |
| 3549 AppendRegisterNameToOutput(instr, | |
| 3550 CPURegister::Create(reg_num, reg_size, reg_type)); | |
| 1371 | 3551 |
| 1372 return field_len; | 3552 return field_len; |
| 1373 } | 3553 } |
| 1374 | 3554 |
| 1375 | 3555 int DisassemblingDecoder::SubstituteImmediateField(Instruction *instr, |
| 1376 int DisassemblingDecoder::SubstituteImmediateField(Instruction* instr, | 3556 const char *format) { |
| 1377 const char* format) { | |
| 1378 DCHECK(format[0] == 'I'); | 3557 DCHECK(format[0] == 'I'); |
| 1379 | 3558 |
| 1380 switch (format[1]) { | 3559 switch (format[1]) { |
| 1381 case 'M': { // IMoveImm or IMoveLSL. | 3560 case 'M': { // IMoveImm or IMoveLSL. |
| 1382 if (format[5] == 'I') { | 3561 if (format[5] == 'I' || format[5] == 'N') { |
| 1383 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide()) | 3562 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide()) |
| 1384 << (16 * instr->ShiftMoveWide()); | 3563 << (16 * instr->ShiftMoveWide()); |
| 3564 if (format[5] == 'N') imm = ~imm; | |
| 3565 if (!instr->SixtyFourBits()) imm &= UINT64_C(0xffffffff); | |
| 1385 AppendToOutput("#0x%" PRIx64, imm); | 3566 AppendToOutput("#0x%" PRIx64, imm); |
| 1386 } else { | 3567 } else { |
| 1387 DCHECK(format[5] == 'L'); | 3568 DCHECK(format[5] == 'L'); |
| 1388 AppendToOutput("#0x%" PRIx32, instr->ImmMoveWide()); | 3569 AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide()); |
| 1389 if (instr->ShiftMoveWide() > 0) { | 3570 if (instr->ShiftMoveWide() > 0) { |
| 1390 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide()); | 3571 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide()); |
| 1391 } | 3572 } |
| 1392 } | 3573 } |
| 1393 return 8; | 3574 return 8; |
| 1394 } | 3575 } |
| 1395 case 'L': { | 3576 case 'L': { |
| 1396 switch (format[2]) { | 3577 switch (format[2]) { |
| 1397 case 'L': { // ILLiteral - Immediate Load Literal. | 3578 case 'L': { // ILLiteral - Immediate Load Literal. |
| 1398 AppendToOutput("pc%+" PRId32, instr->ImmLLiteral() | 3579 AppendToOutput("pc%+" PRId32, instr->ImmLLiteral() |
| 1399 << kLoadLiteralScaleLog2); | 3580 << kLoadLiteralScaleLog2); |
| 1400 return 9; | 3581 return 9; |
| 1401 } | 3582 } |
| 1402 case 'S': { // ILS - Immediate Load/Store. | 3583 case 'S': { // ILS - Immediate Load/Store. |
| 1403 if (instr->ImmLS() != 0) { | 3584 if (instr->ImmLS() != 0) { |
| 1404 AppendToOutput(", #%" PRId32, instr->ImmLS()); | 3585 AppendToOutput(", #%" PRId32, instr->ImmLS()); |
| 1405 } | 3586 } |
| 1406 return 3; | 3587 return 3; |
| 1407 } | 3588 } |
| 1408 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size. | 3589 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size. |
| 1409 if (instr->ImmLSPair() != 0) { | 3590 if (instr->ImmLSPair() != 0) { |
| 1410 // format[3] is the scale value. Convert to a number. | 3591 // format[3] is the scale value. Convert to a number. |
| 1411 int scale = format[3] - 0x30; | 3592 int scale = 1 << (format[3] - '0'); |
| 1412 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale); | 3593 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale); |
| 1413 } | 3594 } |
| 1414 return 4; | 3595 return 4; |
| 1415 } | 3596 } |
| 1416 case 'U': { // ILU - Immediate Load/Store Unsigned. | 3597 case 'U': { // ILU - Immediate Load/Store Unsigned. |
| 1417 if (instr->ImmLSUnsigned() != 0) { | 3598 if (instr->ImmLSUnsigned() != 0) { |
| 1418 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned() | 3599 int shift = instr->SizeLS(); |
| 1419 << instr->SizeLS()); | 3600 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned() << shift); |
| 1420 } | 3601 } |
| 1421 return 3; | 3602 return 3; |
| 1422 } | 3603 } |
| 1423 } | 3604 } |
| 1424 } | 3605 } |
| 1425 case 'C': { // ICondB - Immediate Conditional Branch. | 3606 case 'C': { // ICondB - Immediate Conditional Branch. |
| 1426 int64_t offset = instr->ImmCondBranch() << 2; | 3607 int64_t offset = instr->ImmCondBranch() << 2; |
| 1427 char sign = (offset >= 0) ? '+' : '-'; | 3608 char sign = (offset >= 0) ? '+' : '-'; |
| 1428 AppendToOutput("#%c0x%" PRIx64, sign, offset); | 3609 AppendToOutput("#%c0x%" PRIx64, sign, offset); |
| 1429 return 6; | 3610 return 6; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1465 } | 3646 } |
| 1466 case 'E': { // IExtract. | 3647 case 'E': { // IExtract. |
| 1467 AppendToOutput("#%d", instr->ImmS()); | 3648 AppendToOutput("#%d", instr->ImmS()); |
| 1468 return 8; | 3649 return 8; |
| 1469 } | 3650 } |
| 1470 case 'S': { // IS - Test and branch bit. | 3651 case 'S': { // IS - Test and branch bit. |
| 1471 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) | | 3652 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) | |
| 1472 instr->ImmTestBranchBit40()); | 3653 instr->ImmTestBranchBit40()); |
| 1473 return 2; | 3654 return 2; |
| 1474 } | 3655 } |
| 3656 case 's': { // Is - Shift (immediate). | |
| 3657 switch (format[2]) { | |
| 3658 case '1': { // Is1 - SSHR. | |
| 3659 int shift = 16 << HighestSetBitPosition(instr->ImmNEONImmh()); | |
| 3660 shift -= instr->ImmNEONImmhImmb(); | |
| 3661 AppendToOutput("#%d", shift); | |
| 3662 return 3; | |
| 3663 } | |
| 3664 case '2': { // Is2 - SLI. | |
| 3665 int shift = instr->ImmNEONImmhImmb(); | |
| 3666 shift -= 8 << HighestSetBitPosition(instr->ImmNEONImmh()); | |
| 3667 AppendToOutput("#%d", shift); | |
| 3668 return 3; | |
| 3669 } | |
| 3670 default: { | |
| 3671 UNIMPLEMENTED(); | |
| 3672 return 0; | |
| 3673 } | |
| 3674 } | |
| 3675 } | |
| 1475 case 'D': { // IDebug - HLT and BRK instructions. | 3676 case 'D': { // IDebug - HLT and BRK instructions. |
| 1476 AppendToOutput("#0x%x", instr->ImmException()); | 3677 AppendToOutput("#0x%x", instr->ImmException()); |
| 1477 return 6; | 3678 return 6; |
| 1478 } | 3679 } |
| 3680 case 'V': { // Immediate Vector. | |
| 3681 switch (format[2]) { | |
| 3682 case 'E': { // IVExtract. | |
| 3683 AppendToOutput("#%" PRId64, instr->ImmNEONExt()); | |
| 3684 return 9; | |
| 3685 } | |
| 3686 case 'B': { // IVByElemIndex. | |
| 3687 int vm_index = (instr->NEONH() << 1) | instr->NEONL(); | |
| 3688 if (instr->NEONSize() == 1) { | |
| 3689 vm_index = (vm_index << 1) | instr->NEONM(); | |
| 3690 } | |
| 3691 AppendToOutput("%d", vm_index); | |
| 3692 return strlen("IVByElemIndex"); | |
| 3693 } | |
| 3694 case 'I': { // INS element. | |
| 3695 if (strncmp(format, "IVInsIndex", strlen("IVInsIndex")) == 0) { | |
| 3696 unsigned rd_index, rn_index; | |
| 3697 unsigned imm5 = instr->ImmNEON5(); | |
| 3698 unsigned imm4 = instr->ImmNEON4(); | |
| 3699 int tz = CountTrailingZeros(imm5, 32); | |
| 3700 if (tz <= 3) { // Defined for 0 <= tz <= 3 only. | |
| 3701 rd_index = imm5 >> (tz + 1); | |
| 3702 rn_index = imm4 >> tz; | |
| 3703 if (strncmp(format, "IVInsIndex1", strlen("IVInsIndex1")) == 0) { | |
| 3704 AppendToOutput("%d", rd_index); | |
| 3705 return strlen("IVInsIndex1"); | |
| 3706 } else if (strncmp(format, "IVInsIndex2", | |
| 3707 strlen("IVInsIndex2")) == 0) { | |
| 3708 AppendToOutput("%d", rn_index); | |
| 3709 return strlen("IVInsIndex2"); | |
| 3710 } | |
| 3711 } | |
| 3712 return 0; | |
| 3713 } | |
| 3714 } | |
| 3715 case 'L': { // IVLSLane[0123] - suffix indicates access size shift. | |
| 3716 AppendToOutput("%d", instr->NEONLSIndex(format[8] - '0')); | |
| 3717 return 9; | |
| 3718 } | |
| 3719 case 'M': { // Modified Immediate cases. | |
| 3720 if (strncmp(format, "IVMIImmFPSingle", strlen("IVMIImmFPSingle")) == | |
| 3721 0) { | |
| 3722 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(), | |
| 3723 instr->ImmNEONFP32()); | |
| 3724 return strlen("IVMIImmFPSingle"); | |
| 3725 } else if (strncmp(format, "IVMIImmFPDouble", | |
| 3726 strlen("IVMIImmFPDouble")) == 0) { | |
| 3727 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(), | |
| 3728 instr->ImmNEONFP64()); | |
| 3729 return strlen("IVMIImmFPDouble"); | |
| 3730 } else if (strncmp(format, "IVMIImm8", strlen("IVMIImm8")) == 0) { | |
| 3731 uint64_t imm8 = instr->ImmNEONabcdefgh(); | |
| 3732 AppendToOutput("#0x%" PRIx64, imm8); | |
| 3733 return strlen("IVMIImm8"); | |
| 3734 } else if (strncmp(format, "IVMIImm", strlen("IVMIImm")) == 0) { | |
| 3735 uint64_t imm8 = instr->ImmNEONabcdefgh(); | |
| 3736 uint64_t imm = 0; | |
| 3737 for (int i = 0; i < 8; ++i) { | |
| 3738 if (imm8 & (1 << i)) { | |
| 3739 imm |= (UINT64_C(0xff) << (8 * i)); | |
| 3740 } | |
| 3741 } | |
| 3742 AppendToOutput("#0x%" PRIx64, imm); | |
| 3743 return strlen("IVMIImm"); | |
| 3744 } else if (strncmp(format, "IVMIShiftAmt1", | |
| 3745 strlen("IVMIShiftAmt1")) == 0) { | |
| 3746 int cmode = instr->NEONCmode(); | |
| 3747 int shift_amount = 8 * ((cmode >> 1) & 3); | |
| 3748 AppendToOutput("#%d", shift_amount); | |
| 3749 return strlen("IVMIShiftAmt1"); | |
| 3750 } else if (strncmp(format, "IVMIShiftAmt2", | |
| 3751 strlen("IVMIShiftAmt2")) == 0) { | |
| 3752 int cmode = instr->NEONCmode(); | |
| 3753 int shift_amount = 8 << (cmode & 1); | |
| 3754 AppendToOutput("#%d", shift_amount); | |
| 3755 return strlen("IVMIShiftAmt2"); | |
| 3756 } else { | |
| 3757 UNIMPLEMENTED(); | |
| 3758 return 0; | |
| 3759 } | |
| 3760 } | |
| 3761 default: { | |
| 3762 UNIMPLEMENTED(); | |
| 3763 return 0; | |
| 3764 } | |
| 3765 } | |
| 3766 } | |
| 1479 default: { | 3767 default: { |
| 3768 printf("%s", format); | |
| 1480 UNREACHABLE(); | 3769 UNREACHABLE(); |
| 1481 return 0; | 3770 return 0; |
| 1482 } | 3771 } |
| 1483 } | 3772 } |
| 1484 } | 3773 } |
| 1485 | 3774 |
| 1486 | 3775 |
| 1487 int DisassemblingDecoder::SubstituteBitfieldImmediateField(Instruction* instr, | 3776 int DisassemblingDecoder::SubstituteBitfieldImmediateField(Instruction* instr, |
| 1488 const char* format) { | 3777 const char* format) { |
| 1489 DCHECK((format[0] == 'I') && (format[1] == 'B')); | 3778 DCHECK((format[0] == 'I') && (format[1] == 'B')); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1534 break; | 3823 break; |
| 1535 default: UNREACHABLE(); | 3824 default: UNREACHABLE(); |
| 1536 } | 3825 } |
| 1537 | 3826 |
| 1538 return 6; | 3827 return 6; |
| 1539 } | 3828 } |
| 1540 | 3829 |
| 1541 | 3830 |
| 1542 int DisassemblingDecoder::SubstituteShiftField(Instruction* instr, | 3831 int DisassemblingDecoder::SubstituteShiftField(Instruction* instr, |
| 1543 const char* format) { | 3832 const char* format) { |
| 1544 DCHECK(format[0] == 'H'); | 3833 DCHECK_EQ(format[0], 'N'); |
| 1545 DCHECK(instr->ShiftDP() <= 0x3); | 3834 DCHECK_LE(instr->ShiftDP(), 0x3); |
| 1546 | 3835 |
| 1547 switch (format[1]) { | 3836 switch (format[1]) { |
| 1548 case 'D': { // HDP. | 3837 case 'D': { // NDP. |
| 1549 DCHECK(instr->ShiftDP() != ROR); | 3838 DCHECK(instr->ShiftDP() != ROR); |
| 1550 } // Fall through. | 3839 } // Fall through. |
| 1551 case 'L': { // HLo. | 3840 case 'L': { // NLo. |
| 1552 if (instr->ImmDPShift() != 0) { | 3841 if (instr->ImmDPShift() != 0) { |
| 1553 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"}; | 3842 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"}; |
| 1554 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()], | 3843 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()], |
| 1555 instr->ImmDPShift()); | 3844 instr->ImmDPShift()); |
| 1556 } | 3845 } |
| 1557 return 3; | 3846 return 3; |
| 1558 } | 3847 } |
| 1559 default: | 3848 default: |
| 1560 UNREACHABLE(); | 3849 UNREACHABLE(); |
| 1561 return 0; | 3850 return 0; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1600 sign = '-'; | 3889 sign = '-'; |
| 1601 } | 3890 } |
| 1602 AppendToOutput("#%c0x%x (addr %p)", sign, offset, | 3891 AppendToOutput("#%c0x%x (addr %p)", sign, offset, |
| 1603 instr->InstructionAtOffset(offset, Instruction::NO_CHECK)); | 3892 instr->InstructionAtOffset(offset, Instruction::NO_CHECK)); |
| 1604 return 13; | 3893 return 13; |
| 1605 } | 3894 } |
| 1606 | 3895 |
| 1607 | 3896 |
| 1608 int DisassemblingDecoder::SubstituteBranchTargetField(Instruction* instr, | 3897 int DisassemblingDecoder::SubstituteBranchTargetField(Instruction* instr, |
| 1609 const char* format) { | 3898 const char* format) { |
| 1610 DCHECK(strncmp(format, "BImm", 4) == 0); | 3899 DCHECK_EQ(strncmp(format, "TImm", 4), 0); |
| 1611 | 3900 |
| 1612 int64_t offset = 0; | 3901 int64_t offset = 0; |
| 1613 switch (format[5]) { | 3902 switch (format[5]) { |
| 1614 // BImmUncn - unconditional branch immediate. | 3903 // TImmUncn - unconditional branch immediate. |
| 1615 case 'n': offset = instr->ImmUncondBranch(); break; | 3904 case 'n': offset = instr->ImmUncondBranch(); break; |
| 1616 // BImmCond - conditional branch immediate. | 3905 // TImmCond - conditional branch immediate. |
| 1617 case 'o': offset = instr->ImmCondBranch(); break; | 3906 case 'o': offset = instr->ImmCondBranch(); break; |
| 1618 // BImmCmpa - compare and branch immediate. | 3907 // TImmCmpa - compare and branch immediate. |
| 1619 case 'm': offset = instr->ImmCmpBranch(); break; | 3908 case 'm': offset = instr->ImmCmpBranch(); break; |
| 1620 // BImmTest - test and branch immediate. | 3909 // TImmTest - test and branch immediate. |
| 1621 case 'e': offset = instr->ImmTestBranch(); break; | 3910 case 'e': offset = instr->ImmTestBranch(); break; |
| 1622 default: UNREACHABLE(); | 3911 default: UNREACHABLE(); |
| 1623 } | 3912 } |
| 1624 offset <<= kInstructionSizeLog2; | 3913 offset <<= kInstructionSizeLog2; |
| 1625 char sign = '+'; | 3914 char sign = '+'; |
| 1626 if (offset < 0) { | 3915 if (offset < 0) { |
| 1627 sign = '-'; | 3916 sign = '-'; |
| 1628 } | 3917 } |
| 1629 AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset), | 3918 AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset), |
| 1630 instr->InstructionAtOffset(offset), Instruction::NO_CHECK); | 3919 instr->InstructionAtOffset(offset), Instruction::NO_CHECK); |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1840 decoder.AppendVisitor(&disasm); | 4129 decoder.AppendVisitor(&disasm); |
| 1841 | 4130 |
| 1842 for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) { | 4131 for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) { |
| 1843 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc)); | 4132 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc)); |
| 1844 } | 4133 } |
| 1845 } | 4134 } |
| 1846 | 4135 |
| 1847 } // namespace disasm | 4136 } // namespace disasm |
| 1848 | 4137 |
| 1849 #endif // V8_TARGET_ARCH_ARM64 | 4138 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |