disasm-a64.cc (118972B)
1// Copyright 2015, ARM Limited 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are met: 6// 7// * Redistributions of source code must retain the above copyright notice, 8// this list of conditions and the following disclaimer. 9// * Redistributions in binary form must reproduce the above copyright notice, 10// this list of conditions and the following disclaimer in the documentation 11// and/or other materials provided with the distribution. 12// * Neither the name of ARM Limited nor the names of its contributors may be 13// used to endorse or promote products derived from this software without 14// specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27#include <cstdlib> 28#include "vixl/a64/disasm-a64.h" 29 30namespace vixl { 31 32Disassembler::Disassembler() { 33 buffer_size_ = 256; 34 buffer_ = reinterpret_cast<char*>(malloc(buffer_size_)); 35 buffer_pos_ = 0; 36 own_buffer_ = true; 37 code_address_offset_ = 0; 38} 39 40 41Disassembler::Disassembler(char* text_buffer, int buffer_size) { 42 buffer_size_ = buffer_size; 43 buffer_ = text_buffer; 44 buffer_pos_ = 0; 45 own_buffer_ = false; 46 code_address_offset_ = 0; 47} 48 49 50Disassembler::~Disassembler() { 51 if (own_buffer_) { 52 free(buffer_); 53 } 54} 55 56 57char* Disassembler::GetOutput() { 58 return buffer_; 59} 60 61 62void Disassembler::VisitAddSubImmediate(const Instruction* instr) { 63 bool rd_is_zr = RdIsZROrSP(instr); 64 bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) && 65 (instr->ImmAddSub() == 0) ? true : false; 66 const char *mnemonic = ""; 67 const char *form = "'Rds, 'Rns, 'IAddSub"; 68 const char *form_cmp = "'Rns, 'IAddSub"; 69 const char *form_mov = "'Rds, 'Rns"; 70 71 switch (instr->Mask(AddSubImmediateMask)) { 72 case ADD_w_imm: 73 case ADD_x_imm: { 74 mnemonic = "add"; 75 if (stack_op) { 76 mnemonic = "mov"; 77 form = form_mov; 78 } 79 break; 80 } 81 case ADDS_w_imm: 82 case ADDS_x_imm: { 83 mnemonic = "adds"; 84 if (rd_is_zr) { 85 mnemonic = "cmn"; 86 form = form_cmp; 87 } 88 break; 89 } 90 case SUB_w_imm: 91 case SUB_x_imm: mnemonic = "sub"; break; 92 case SUBS_w_imm: 93 case SUBS_x_imm: { 94 mnemonic = "subs"; 95 if (rd_is_zr) { 96 mnemonic = "cmp"; 97 form = form_cmp; 98 } 99 break; 100 } 101 default: VIXL_UNREACHABLE(); 102 } 103 Format(instr, mnemonic, form); 104} 105 106 107void Disassembler::VisitAddSubShifted(const Instruction* instr) { 108 bool rd_is_zr = RdIsZROrSP(instr); 109 bool rn_is_zr = RnIsZROrSP(instr); 110 const char *mnemonic = ""; 111 const char *form = "'Rd, 'Rn, 'Rm'NDP"; 112 const char *form_cmp = "'Rn, 'Rm'NDP"; 113 const char *form_neg = "'Rd, 'Rm'NDP"; 114 115 switch (instr->Mask(AddSubShiftedMask)) { 116 case ADD_w_shift: 117 case ADD_x_shift: mnemonic = "add"; break; 118 case ADDS_w_shift: 119 case ADDS_x_shift: { 120 mnemonic = "adds"; 121 if (rd_is_zr) { 122 mnemonic = "cmn"; 123 form = form_cmp; 124 } 125 break; 126 } 127 case SUB_w_shift: 128 case SUB_x_shift: { 129 mnemonic = "sub"; 130 if (rn_is_zr) { 131 mnemonic = "neg"; 132 form = form_neg; 133 } 134 break; 135 } 136 case SUBS_w_shift: 137 case SUBS_x_shift: { 138 mnemonic = "subs"; 139 if (rd_is_zr) { 140 mnemonic = "cmp"; 141 form = form_cmp; 142 } else if (rn_is_zr) { 143 mnemonic = "negs"; 144 form = form_neg; 145 } 146 break; 147 } 148 default: VIXL_UNREACHABLE(); 149 } 150 Format(instr, mnemonic, form); 151} 152 153 154void Disassembler::VisitAddSubExtended(const Instruction* instr) { 155 bool rd_is_zr = RdIsZROrSP(instr); 156 const char *mnemonic = ""; 157 Extend mode = static_cast<Extend>(instr->ExtendMode()); 158 const char *form = ((mode == UXTX) || (mode == SXTX)) ? 159 "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext"; 160 const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ? 161 "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext"; 162 163 switch (instr->Mask(AddSubExtendedMask)) { 164 case ADD_w_ext: 165 case ADD_x_ext: mnemonic = "add"; break; 166 case ADDS_w_ext: 167 case ADDS_x_ext: { 168 mnemonic = "adds"; 169 if (rd_is_zr) { 170 mnemonic = "cmn"; 171 form = form_cmp; 172 } 173 break; 174 } 175 case SUB_w_ext: 176 case SUB_x_ext: mnemonic = "sub"; break; 177 case SUBS_w_ext: 178 case SUBS_x_ext: { 179 mnemonic = "subs"; 180 if (rd_is_zr) { 181 mnemonic = "cmp"; 182 form = form_cmp; 183 } 184 break; 185 } 186 default: VIXL_UNREACHABLE(); 187 } 188 Format(instr, mnemonic, form); 189} 190 191 192void Disassembler::VisitAddSubWithCarry(const Instruction* instr) { 193 bool rn_is_zr = RnIsZROrSP(instr); 194 const char *mnemonic = ""; 195 const char *form = "'Rd, 'Rn, 'Rm"; 196 const char *form_neg = "'Rd, 'Rm"; 197 198 switch (instr->Mask(AddSubWithCarryMask)) { 199 case ADC_w: 200 case ADC_x: mnemonic = "adc"; break; 201 case ADCS_w: 202 case ADCS_x: mnemonic = "adcs"; break; 203 case SBC_w: 204 case SBC_x: { 205 mnemonic = "sbc"; 206 if (rn_is_zr) { 207 mnemonic = "ngc"; 208 form = form_neg; 209 } 210 break; 211 } 212 case SBCS_w: 213 case SBCS_x: { 214 mnemonic = "sbcs"; 215 if (rn_is_zr) { 216 mnemonic = "ngcs"; 217 form = form_neg; 218 } 219 break; 220 } 221 default: VIXL_UNREACHABLE(); 222 } 223 Format(instr, mnemonic, form); 224} 225 226 227void Disassembler::VisitLogicalImmediate(const Instruction* instr) { 228 bool rd_is_zr = RdIsZROrSP(instr); 229 bool rn_is_zr = RnIsZROrSP(instr); 230 const char *mnemonic = ""; 231 const char *form = "'Rds, 'Rn, 'ITri"; 232 233 if (instr->ImmLogical() == 0) { 234 // The immediate encoded in the instruction is not in the expected format. 235 Format(instr, "unallocated", "(LogicalImmediate)"); 236 return; 237 } 238 239 switch (instr->Mask(LogicalImmediateMask)) { 240 case AND_w_imm: 241 case AND_x_imm: mnemonic = "and"; break; 242 case ORR_w_imm: 243 case ORR_x_imm: { 244 mnemonic = "orr"; 245 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize 246 : kWRegSize; 247 if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) { 248 mnemonic = "mov"; 249 form = "'Rds, 'ITri"; 250 } 251 break; 252 } 253 case EOR_w_imm: 254 case EOR_x_imm: mnemonic = "eor"; break; 255 case ANDS_w_imm: 256 case ANDS_x_imm: { 257 mnemonic = "ands"; 258 if (rd_is_zr) { 259 mnemonic = "tst"; 260 form = "'Rn, 'ITri"; 261 } 262 break; 263 } 264 default: VIXL_UNREACHABLE(); 265 } 266 Format(instr, mnemonic, form); 267} 268 269 270bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) { 271 VIXL_ASSERT((reg_size == kXRegSize) || 272 ((reg_size == kWRegSize) && (value <= 0xffffffff))); 273 274 // Test for movz: 16 bits set at positions 0, 16, 32 or 48. 275 if (((value & UINT64_C(0xffffffffffff0000)) == 0) || 276 ((value & UINT64_C(0xffffffff0000ffff)) == 0) || 277 ((value & UINT64_C(0xffff0000ffffffff)) == 0) || 278 ((value & UINT64_C(0x0000ffffffffffff)) == 0)) { 279 return true; 280 } 281 282 // Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48). 283 if ((reg_size == kXRegSize) && 284 (((~value & UINT64_C(0xffffffffffff0000)) == 0) || 285 ((~value & UINT64_C(0xffffffff0000ffff)) == 0) || 286 ((~value & UINT64_C(0xffff0000ffffffff)) == 0) || 287 ((~value & UINT64_C(0x0000ffffffffffff)) == 0))) { 288 return true; 289 } 290 if ((reg_size == kWRegSize) && 291 (((value & 0xffff0000) == 0xffff0000) || 292 ((value & 0x0000ffff) == 0x0000ffff))) { 293 return true; 294 } 295 return false; 296} 297 298 299void Disassembler::VisitLogicalShifted(const Instruction* instr) { 300 bool rd_is_zr = RdIsZROrSP(instr); 301 bool rn_is_zr = RnIsZROrSP(instr); 302 const char *mnemonic = ""; 303 const char *form = "'Rd, 'Rn, 'Rm'NLo"; 304 305 switch (instr->Mask(LogicalShiftedMask)) { 306 case AND_w: 307 case AND_x: mnemonic = "and"; break; 308 case BIC_w: 309 case BIC_x: mnemonic = "bic"; break; 310 case EOR_w: 311 case EOR_x: mnemonic = "eor"; break; 312 case EON_w: 313 case EON_x: mnemonic = "eon"; break; 314 case BICS_w: 315 case BICS_x: mnemonic = "bics"; break; 316 case ANDS_w: 317 case ANDS_x: { 318 mnemonic = "ands"; 319 if (rd_is_zr) { 320 mnemonic = "tst"; 321 form = "'Rn, 'Rm'NLo"; 322 } 323 break; 324 } 325 case ORR_w: 326 case ORR_x: { 327 mnemonic = "orr"; 328 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) { 329 mnemonic = "mov"; 330 form = "'Rd, 'Rm"; 331 } 332 break; 333 } 334 case ORN_w: 335 case ORN_x: { 336 mnemonic = "orn"; 337 if (rn_is_zr) { 338 mnemonic = "mvn"; 339 form = "'Rd, 'Rm'NLo"; 340 } 341 break; 342 } 343 default: VIXL_UNREACHABLE(); 344 } 345 346 Format(instr, mnemonic, form); 347} 348 349 350void Disassembler::VisitConditionalCompareRegister(const Instruction* instr) { 351 const char *mnemonic = ""; 352 const char *form = "'Rn, 'Rm, 'INzcv, 'Cond"; 353 354 switch (instr->Mask(ConditionalCompareRegisterMask)) { 355 case CCMN_w: 356 case CCMN_x: mnemonic = "ccmn"; break; 357 case CCMP_w: 358 case CCMP_x: mnemonic = "ccmp"; break; 359 default: VIXL_UNREACHABLE(); 360 } 361 Format(instr, mnemonic, form); 362} 363 364 365void Disassembler::VisitConditionalCompareImmediate(const Instruction* instr) { 366 const char *mnemonic = ""; 367 const char *form = "'Rn, 'IP, 'INzcv, 'Cond"; 368 369 switch (instr->Mask(ConditionalCompareImmediateMask)) { 370 case CCMN_w_imm: 371 case CCMN_x_imm: mnemonic = "ccmn"; break; 372 case CCMP_w_imm: 373 case CCMP_x_imm: mnemonic = "ccmp"; break; 374 default: VIXL_UNREACHABLE(); 375 } 376 Format(instr, mnemonic, form); 377} 378 379 380void Disassembler::VisitConditionalSelect(const Instruction* instr) { 381 bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr)); 382 bool rn_is_rm = (instr->Rn() == instr->Rm()); 383 const char *mnemonic = ""; 384 const char *form = "'Rd, 'Rn, 'Rm, 'Cond"; 385 const char *form_test = "'Rd, 'CInv"; 386 const char *form_update = "'Rd, 'Rn, 'CInv"; 387 388 Condition cond = static_cast<Condition>(instr->Condition()); 389 bool invertible_cond = (cond != al) && (cond != nv); 390 391 switch (instr->Mask(ConditionalSelectMask)) { 392 case CSEL_w: 393 case CSEL_x: mnemonic = "csel"; break; 394 case CSINC_w: 395 case CSINC_x: { 396 mnemonic = "csinc"; 397 if (rnm_is_zr && invertible_cond) { 398 mnemonic = "cset"; 399 form = form_test; 400 } else if (rn_is_rm && invertible_cond) { 401 mnemonic = "cinc"; 402 form = form_update; 403 } 404 break; 405 } 406 case CSINV_w: 407 case CSINV_x: { 408 mnemonic = "csinv"; 409 if (rnm_is_zr && invertible_cond) { 410 mnemonic = "csetm"; 411 form = form_test; 412 } else if (rn_is_rm && invertible_cond) { 413 mnemonic = "cinv"; 414 form = form_update; 415 } 416 break; 417 } 418 case CSNEG_w: 419 case CSNEG_x: { 420 mnemonic = "csneg"; 421 if (rn_is_rm && invertible_cond) { 422 mnemonic = "cneg"; 423 form = form_update; 424 } 425 break; 426 } 427 default: VIXL_UNREACHABLE(); 428 } 429 Format(instr, mnemonic, form); 430} 431 432 433void Disassembler::VisitBitfield(const Instruction* instr) { 434 unsigned s = instr->ImmS(); 435 unsigned r = instr->ImmR(); 436 unsigned rd_size_minus_1 = 437 ((instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize) - 1; 438 const char *mnemonic = ""; 439 const char *form = ""; 440 const char *form_shift_right = "'Rd, 'Rn, 'IBr"; 441 const char *form_extend = "'Rd, 'Wn"; 442 const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1"; 443 const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1"; 444 const char *form_lsl = "'Rd, 'Rn, 'IBZ-r"; 445 446 switch (instr->Mask(BitfieldMask)) { 447 case SBFM_w: 448 case SBFM_x: { 449 mnemonic = "sbfx"; 450 form = form_bfx; 451 if (r == 0) { 452 form = form_extend; 453 if (s == 7) { 454 mnemonic = "sxtb"; 455 } else if (s == 15) { 456 mnemonic = "sxth"; 457 } else if ((s == 31) && (instr->SixtyFourBits() == 1)) { 458 mnemonic = "sxtw"; 459 } else { 460 form = form_bfx; 461 } 462 } else if (s == rd_size_minus_1) { 463 mnemonic = "asr"; 464 form = form_shift_right; 465 } else if (s < r) { 466 mnemonic = "sbfiz"; 467 form = form_bfiz; 468 } 469 break; 470 } 471 case UBFM_w: 472 case UBFM_x: { 473 mnemonic = "ubfx"; 474 form = form_bfx; 475 if (r == 0) { 476 form = form_extend; 477 if (s == 7) { 478 mnemonic = "uxtb"; 479 } else if (s == 15) { 480 mnemonic = "uxth"; 481 } else { 482 form = form_bfx; 483 } 484 } 485 if (s == rd_size_minus_1) { 486 mnemonic = "lsr"; 487 form = form_shift_right; 488 } else if (r == s + 1) { 489 mnemonic = "lsl"; 490 form = form_lsl; 491 } else if (s < r) { 492 mnemonic = "ubfiz"; 493 form = form_bfiz; 494 } 495 break; 496 } 497 case BFM_w: 498 case BFM_x: { 499 mnemonic = "bfxil"; 500 form = form_bfx; 501 if (s < r) { 502 mnemonic = "bfi"; 503 form = form_bfiz; 504 } 505 } 506 } 507 Format(instr, mnemonic, form); 508} 509 510 511void Disassembler::VisitExtract(const Instruction* instr) { 512 const char *mnemonic = ""; 513 const char *form = "'Rd, 'Rn, 'Rm, 'IExtract"; 514 515 switch (instr->Mask(ExtractMask)) { 516 case EXTR_w: 517 case EXTR_x: { 518 if (instr->Rn() == instr->Rm()) { 519 mnemonic = "ror"; 520 form = "'Rd, 'Rn, 'IExtract"; 521 } else { 522 mnemonic = "extr"; 523 } 524 break; 525 } 526 default: VIXL_UNREACHABLE(); 527 } 528 Format(instr, mnemonic, form); 529} 530 531 532void Disassembler::VisitPCRelAddressing(const Instruction* instr) { 533 switch (instr->Mask(PCRelAddressingMask)) { 534 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break; 535 case ADRP: Format(instr, "adrp", "'Xd, 'AddrPCRelPage"); break; 536 default: Format(instr, "unimplemented", "(PCRelAddressing)"); 537 } 538} 539 540 541void Disassembler::VisitConditionalBranch(const Instruction* instr) { 542 switch (instr->Mask(ConditionalBranchMask)) { 543 case B_cond: Format(instr, "b.'CBrn", "'TImmCond"); break; 544 default: VIXL_UNREACHABLE(); 545 } 546} 547 548 549void Disassembler::VisitUnconditionalBranchToRegister( 550 const Instruction* instr) { 551 const char *mnemonic = "unimplemented"; 552 const char *form = "'Xn"; 553 554 switch (instr->Mask(UnconditionalBranchToRegisterMask)) { 555 case BR: mnemonic = "br"; break; 556 case BLR: mnemonic = "blr"; break; 557 case RET: { 558 mnemonic = "ret"; 559 if (instr->Rn() == kLinkRegCode) { 560 form = NULL; 561 } 562 break; 563 } 564 default: form = "(UnconditionalBranchToRegister)"; 565 } 566 Format(instr, mnemonic, form); 567} 568 569 570void Disassembler::VisitUnconditionalBranch(const Instruction* instr) { 571 const char *mnemonic = ""; 572 const char *form = "'TImmUncn"; 573 574 switch (instr->Mask(UnconditionalBranchMask)) { 575 case B: mnemonic = "b"; break; 576 case BL: mnemonic = "bl"; break; 577 default: VIXL_UNREACHABLE(); 578 } 579 Format(instr, mnemonic, form); 580} 581 582 583void Disassembler::VisitDataProcessing1Source(const Instruction* instr) { 584 const char *mnemonic = ""; 585 const char *form = "'Rd, 'Rn"; 586 587 switch (instr->Mask(DataProcessing1SourceMask)) { 588 #define FORMAT(A, B) \ 589 case A##_w: \ 590 case A##_x: mnemonic = B; break; 591 FORMAT(RBIT, "rbit"); 592 FORMAT(REV16, "rev16"); 593 FORMAT(REV, "rev"); 594 FORMAT(CLZ, "clz"); 595 FORMAT(CLS, "cls"); 596 #undef FORMAT 597 case REV32_x: mnemonic = "rev32"; break; 598 default: VIXL_UNREACHABLE(); 599 } 600 Format(instr, mnemonic, form); 601} 602 603 604void Disassembler::VisitDataProcessing2Source(const Instruction* instr) { 605 const char *mnemonic = "unimplemented"; 606 const char *form = "'Rd, 'Rn, 'Rm"; 607 const char *form_wwx = "'Wd, 'Wn, 'Xm"; 608 609 switch (instr->Mask(DataProcessing2SourceMask)) { 610 #define FORMAT(A, B) \ 611 case A##_w: \ 612 case A##_x: mnemonic = B; break; 613 FORMAT(UDIV, "udiv"); 614 FORMAT(SDIV, "sdiv"); 615 FORMAT(LSLV, "lsl"); 616 FORMAT(LSRV, "lsr"); 617 FORMAT(ASRV, "asr"); 618 FORMAT(RORV, "ror"); 619 #undef FORMAT 620 case CRC32B: mnemonic = "crc32b"; break; 621 case CRC32H: mnemonic = "crc32h"; break; 622 case CRC32W: mnemonic = "crc32w"; break; 623 case CRC32X: mnemonic = "crc32x"; form = form_wwx; break; 624 case CRC32CB: mnemonic = "crc32cb"; break; 625 case CRC32CH: mnemonic = "crc32ch"; break; 626 case CRC32CW: mnemonic = "crc32cw"; break; 627 case CRC32CX: mnemonic = "crc32cx"; form = form_wwx; break; 628 default: form = "(DataProcessing2Source)"; 629 } 630 Format(instr, mnemonic, form); 631} 632 633 634void Disassembler::VisitDataProcessing3Source(const Instruction* instr) { 635 bool ra_is_zr = RaIsZROrSP(instr); 636 const char *mnemonic = ""; 637 const char *form = "'Xd, 'Wn, 'Wm, 'Xa"; 638 const char *form_rrr = "'Rd, 'Rn, 'Rm"; 639 const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra"; 640 const char *form_xww = "'Xd, 'Wn, 'Wm"; 641 const char *form_xxx = "'Xd, 'Xn, 'Xm"; 642 643 switch (instr->Mask(DataProcessing3SourceMask)) { 644 case MADD_w: 645 case MADD_x: { 646 mnemonic = "madd"; 647 form = form_rrrr; 648 if (ra_is_zr) { 649 mnemonic = "mul"; 650 form = form_rrr; 651 } 652 break; 653 } 654 case MSUB_w: 655 case MSUB_x: { 656 mnemonic = "msub"; 657 form = form_rrrr; 658 if (ra_is_zr) { 659 mnemonic = "mneg"; 660 form = form_rrr; 661 } 662 break; 663 } 664 case SMADDL_x: { 665 mnemonic = "smaddl"; 666 if (ra_is_zr) { 667 mnemonic = "smull"; 668 form = form_xww; 669 } 670 break; 671 } 672 case SMSUBL_x: { 673 mnemonic = "smsubl"; 674 if (ra_is_zr) { 675 mnemonic = "smnegl"; 676 form = form_xww; 677 } 678 break; 679 } 680 case UMADDL_x: { 681 mnemonic = "umaddl"; 682 if (ra_is_zr) { 683 mnemonic = "umull"; 684 form = form_xww; 685 } 686 break; 687 } 688 case UMSUBL_x: { 689 mnemonic = "umsubl"; 690 if (ra_is_zr) { 691 mnemonic = "umnegl"; 692 form = form_xww; 693 } 694 break; 695 } 696 case SMULH_x: { 697 mnemonic = "smulh"; 698 form = form_xxx; 699 break; 700 } 701 case UMULH_x: { 702 mnemonic = "umulh"; 703 form = form_xxx; 704 break; 705 } 706 default: VIXL_UNREACHABLE(); 707 } 708 Format(instr, mnemonic, form); 709} 710 711 712void Disassembler::VisitCompareBranch(const Instruction* instr) { 713 const char *mnemonic = ""; 714 const char *form = "'Rt, 'TImmCmpa"; 715 716 switch (instr->Mask(CompareBranchMask)) { 717 case CBZ_w: 718 case CBZ_x: mnemonic = "cbz"; break; 719 case CBNZ_w: 720 case CBNZ_x: mnemonic = "cbnz"; break; 721 default: VIXL_UNREACHABLE(); 722 } 723 Format(instr, mnemonic, form); 724} 725 726 727void Disassembler::VisitTestBranch(const Instruction* instr) { 728 const char *mnemonic = ""; 729 // If the top bit of the immediate is clear, the tested register is 730 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is 731 // encoded in bit 31 of the instruction, we can reuse the Rt form, which 732 // uses bit 31 (normally "sf") to choose the register size. 733 const char *form = "'Rt, 'IS, 'TImmTest"; 734 735 switch (instr->Mask(TestBranchMask)) { 736 case TBZ: mnemonic = "tbz"; break; 737 case TBNZ: mnemonic = "tbnz"; break; 738 default: VIXL_UNREACHABLE(); 739 } 740 Format(instr, mnemonic, form); 741} 742 743 744void Disassembler::VisitMoveWideImmediate(const Instruction* instr) { 745 const char *mnemonic = ""; 746 const char *form = "'Rd, 'IMoveImm"; 747 748 // Print the shift separately for movk, to make it clear which half word will 749 // be overwritten. Movn and movz print the computed immediate, which includes 750 // shift calculation. 751 switch (instr->Mask(MoveWideImmediateMask)) { 752 case MOVN_w: 753 case MOVN_x: 754 if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0)) { 755 if ((instr->SixtyFourBits() == 0) && (instr->ImmMoveWide() == 0xffff)) { 756 mnemonic = "movn"; 757 } else { 758 mnemonic = "mov"; 759 form = "'Rd, 'IMoveNeg"; 760 } 761 } else { 762 mnemonic = "movn"; 763 } 764 break; 765 case MOVZ_w: 766 case MOVZ_x: 767 if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0)) 768 mnemonic = "mov"; 769 else 770 mnemonic = "movz"; 771 break; 772 case MOVK_w: 773 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break; 774 default: VIXL_UNREACHABLE(); 775 } 776 Format(instr, mnemonic, form); 777} 778 779 780#define LOAD_STORE_LIST(V) \ 781 V(STRB_w, "strb", "'Wt") \ 782 V(STRH_w, "strh", "'Wt") \ 783 V(STR_w, "str", "'Wt") \ 784 V(STR_x, "str", "'Xt") \ 785 V(LDRB_w, "ldrb", "'Wt") \ 786 V(LDRH_w, "ldrh", "'Wt") \ 787 V(LDR_w, "ldr", "'Wt") \ 788 V(LDR_x, "ldr", "'Xt") \ 789 V(LDRSB_x, "ldrsb", "'Xt") \ 790 V(LDRSH_x, "ldrsh", "'Xt") \ 791 V(LDRSW_x, "ldrsw", "'Xt") \ 792 V(LDRSB_w, "ldrsb", "'Wt") \ 793 V(LDRSH_w, "ldrsh", "'Wt") \ 794 V(STR_b, "str", "'Bt") \ 795 V(STR_h, "str", "'Ht") \ 796 V(STR_s, "str", "'St") \ 797 V(STR_d, "str", "'Dt") \ 798 V(LDR_b, "ldr", "'Bt") \ 799 V(LDR_h, "ldr", "'Ht") \ 800 V(LDR_s, "ldr", "'St") \ 801 V(LDR_d, "ldr", "'Dt") \ 802 V(STR_q, "str", "'Qt") \ 803 V(LDR_q, "ldr", "'Qt") 804 805void Disassembler::VisitLoadStorePreIndex(const Instruction* instr) { 806 const char *mnemonic = "unimplemented"; 807 const char *form = "(LoadStorePreIndex)"; 808 809 switch (instr->Mask(LoadStorePreIndexMask)) { 810 #define LS_PREINDEX(A, B, C) \ 811 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break; 812 LOAD_STORE_LIST(LS_PREINDEX) 813 #undef LS_PREINDEX 814 } 815 Format(instr, mnemonic, form); 816} 817 818 819void Disassembler::VisitLoadStorePostIndex(const Instruction* instr) { 820 const char *mnemonic = "unimplemented"; 821 const char *form = "(LoadStorePostIndex)"; 822 823 switch (instr->Mask(LoadStorePostIndexMask)) { 824 #define LS_POSTINDEX(A, B, C) \ 825 case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break; 826 LOAD_STORE_LIST(LS_POSTINDEX) 827 #undef LS_POSTINDEX 828 } 829 Format(instr, mnemonic, form); 830} 831 832 833void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) { 834 const char *mnemonic = "unimplemented"; 835 const char *form = "(LoadStoreUnsignedOffset)"; 836 837 switch (instr->Mask(LoadStoreUnsignedOffsetMask)) { 838 #define LS_UNSIGNEDOFFSET(A, B, C) \ 839 case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break; 840 LOAD_STORE_LIST(LS_UNSIGNEDOFFSET) 841 #undef LS_UNSIGNEDOFFSET 842 case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xns'ILU]"; 843 } 844 Format(instr, mnemonic, form); 845} 846 847 848void Disassembler::VisitLoadStoreRegisterOffset(const Instruction* instr) { 849 const char *mnemonic = "unimplemented"; 850 const char *form = "(LoadStoreRegisterOffset)"; 851 852 switch (instr->Mask(LoadStoreRegisterOffsetMask)) { 853 #define LS_REGISTEROFFSET(A, B, C) \ 854 case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break; 855 LOAD_STORE_LIST(LS_REGISTEROFFSET) 856 #undef LS_REGISTEROFFSET 857 case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]"; 858 } 859 Format(instr, mnemonic, form); 860} 861 862 863void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) { 864 const char *mnemonic = "unimplemented"; 865 const char *form = "'Wt, ['Xns'ILS]"; 866 const char *form_x = "'Xt, ['Xns'ILS]"; 867 const char *form_b = "'Bt, ['Xns'ILS]"; 868 const char *form_h = "'Ht, ['Xns'ILS]"; 869 const char *form_s = "'St, ['Xns'ILS]"; 870 const char *form_d = "'Dt, ['Xns'ILS]"; 871 const char *form_q = "'Qt, ['Xns'ILS]"; 872 const char *form_prefetch = "'PrefOp, ['Xns'ILS]"; 873 874 switch (instr->Mask(LoadStoreUnscaledOffsetMask)) { 875 case STURB_w: mnemonic = "sturb"; break; 876 case STURH_w: mnemonic = "sturh"; break; 877 case STUR_w: mnemonic = "stur"; break; 878 case STUR_x: mnemonic = "stur"; form = form_x; break; 879 case STUR_b: mnemonic = "stur"; form = form_b; break; 880 case STUR_h: mnemonic = "stur"; form = form_h; break; 881 case STUR_s: mnemonic = "stur"; form = form_s; break; 882 case STUR_d: mnemonic = "stur"; form = form_d; break; 883 case STUR_q: mnemonic = "stur"; form = form_q; break; 884 case LDURB_w: mnemonic = "ldurb"; break; 885 case LDURH_w: mnemonic = "ldurh"; break; 886 case LDUR_w: mnemonic = "ldur"; break; 887 case LDUR_x: mnemonic = "ldur"; form = form_x; break; 888 case LDUR_b: mnemonic = "ldur"; form = form_b; break; 889 case LDUR_h: mnemonic = "ldur"; form = form_h; break; 890 case LDUR_s: mnemonic = "ldur"; form = form_s; break; 891 case LDUR_d: mnemonic = "ldur"; form = form_d; break; 892 case LDUR_q: mnemonic = "ldur"; form = form_q; break; 893 case LDURSB_x: form = form_x; VIXL_FALLTHROUGH(); 894 case LDURSB_w: mnemonic = "ldursb"; break; 895 case LDURSH_x: form = form_x; VIXL_FALLTHROUGH(); 896 case LDURSH_w: mnemonic = "ldursh"; break; 897 case LDURSW_x: mnemonic = "ldursw"; form = form_x; break; 898 case PRFUM: mnemonic = "prfum"; form = form_prefetch; break; 899 default: form = "(LoadStoreUnscaledOffset)"; 900 } 901 Format(instr, mnemonic, form); 902} 903 904 905void Disassembler::VisitLoadLiteral(const Instruction* instr) { 906 const char *mnemonic = "ldr"; 907 const char *form = "(LoadLiteral)"; 908 909 switch (instr->Mask(LoadLiteralMask)) { 910 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break; 911 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break; 912 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break; 913 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break; 914 case LDR_q_lit: form = "'Qt, 'ILLiteral 'LValue"; break; 915 case LDRSW_x_lit: { 916 mnemonic = "ldrsw"; 917 form = "'Xt, 'ILLiteral 'LValue"; 918 break; 919 } 920 case PRFM_lit: { 921 mnemonic = "prfm"; 922 form = "'PrefOp, 'ILLiteral 'LValue"; 923 break; 924 } 925 default: mnemonic = "unimplemented"; 926 } 927 Format(instr, mnemonic, form); 928} 929 930 931#define LOAD_STORE_PAIR_LIST(V) \ 932 V(STP_w, "stp", "'Wt, 'Wt2", "2") \ 933 V(LDP_w, "ldp", "'Wt, 'Wt2", "2") \ 934 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "2") \ 935 V(STP_x, "stp", "'Xt, 'Xt2", "3") \ 936 V(LDP_x, "ldp", "'Xt, 'Xt2", "3") \ 937 V(STP_s, "stp", "'St, 'St2", "2") \ 938 V(LDP_s, "ldp", "'St, 'St2", "2") \ 939 V(STP_d, "stp", "'Dt, 'Dt2", "3") \ 940 V(LDP_d, "ldp", "'Dt, 'Dt2", "3") \ 941 V(LDP_q, "ldp", "'Qt, 'Qt2", "4") \ 942 V(STP_q, "stp", "'Qt, 'Qt2", "4") 943 944void Disassembler::VisitLoadStorePairPostIndex(const Instruction* instr) { 945 const char *mnemonic = "unimplemented"; 946 const char *form = "(LoadStorePairPostIndex)"; 947 948 switch (instr->Mask(LoadStorePairPostIndexMask)) { 949 #define LSP_POSTINDEX(A, B, C, D) \ 950 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break; 951 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX) 952 #undef LSP_POSTINDEX 953 } 954 Format(instr, mnemonic, form); 955} 956 957 958void Disassembler::VisitLoadStorePairPreIndex(const Instruction* instr) { 959 const char *mnemonic = "unimplemented"; 960 const char *form = "(LoadStorePairPreIndex)"; 961 962 switch (instr->Mask(LoadStorePairPreIndexMask)) { 963 #define LSP_PREINDEX(A, B, C, D) \ 964 case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break; 965 LOAD_STORE_PAIR_LIST(LSP_PREINDEX) 966 #undef LSP_PREINDEX 967 } 968 Format(instr, mnemonic, form); 969} 970 971 972void Disassembler::VisitLoadStorePairOffset(const Instruction* instr) { 973 const char *mnemonic = "unimplemented"; 974 const char *form = "(LoadStorePairOffset)"; 975 976 switch (instr->Mask(LoadStorePairOffsetMask)) { 977 #define LSP_OFFSET(A, B, C, D) \ 978 case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break; 979 LOAD_STORE_PAIR_LIST(LSP_OFFSET) 980 #undef LSP_OFFSET 981 } 982 Format(instr, mnemonic, form); 983} 984 985 986void Disassembler::VisitLoadStorePairNonTemporal(const Instruction* instr) { 987 const char *mnemonic = "unimplemented"; 988 const char *form; 989 990 switch (instr->Mask(LoadStorePairNonTemporalMask)) { 991 case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP2]"; break; 992 case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP2]"; break; 993 case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP3]"; break; 994 case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP3]"; break; 995 case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP2]"; break; 996 case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP2]"; break; 997 case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP3]"; break; 998 case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP3]"; break; 999 case STNP_q: mnemonic = "stnp"; form = "'Qt, 'Qt2, ['Xns'ILP4]"; break; 1000 case LDNP_q: mnemonic = "ldnp"; form = "'Qt, 'Qt2, ['Xns'ILP4]"; break; 1001 default: form = "(LoadStorePairNonTemporal)"; 1002 } 1003 Format(instr, mnemonic, form); 1004} 1005 1006 1007void Disassembler::VisitLoadStoreExclusive(const Instruction* instr) { 1008 const char *mnemonic = "unimplemented"; 1009 const char *form; 1010 1011 switch (instr->Mask(LoadStoreExclusiveMask)) { 1012 case STXRB_w: mnemonic = "stxrb"; form = "'Ws, 'Wt, ['Xns]"; break; 1013 case STXRH_w: mnemonic = "stxrh"; form = "'Ws, 'Wt, ['Xns]"; break; 1014 case STXR_w: mnemonic = "stxr"; form = "'Ws, 'Wt, ['Xns]"; break; 1015 case STXR_x: mnemonic = "stxr"; form = "'Ws, 'Xt, ['Xns]"; break; 1016 case LDXRB_w: mnemonic = "ldxrb"; form = "'Wt, ['Xns]"; break; 1017 case LDXRH_w: mnemonic = "ldxrh"; form = "'Wt, ['Xns]"; break; 1018 case LDXR_w: mnemonic = "ldxr"; form = "'Wt, ['Xns]"; break; 1019 case LDXR_x: mnemonic = "ldxr"; form = "'Xt, ['Xns]"; break; 1020 case STXP_w: mnemonic = "stxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break; 1021 case STXP_x: mnemonic = "stxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break; 1022 case LDXP_w: mnemonic = "ldxp"; form = "'Wt, 'Wt2, ['Xns]"; break; 1023 case LDXP_x: mnemonic = "ldxp"; form = "'Xt, 'Xt2, ['Xns]"; break; 1024 case STLXRB_w: mnemonic = "stlxrb"; form = "'Ws, 'Wt, ['Xns]"; break; 1025 case STLXRH_w: mnemonic = "stlxrh"; form = "'Ws, 'Wt, ['Xns]"; break; 1026 case STLXR_w: mnemonic = "stlxr"; form = "'Ws, 'Wt, ['Xns]"; break; 1027 case STLXR_x: mnemonic = "stlxr"; form = "'Ws, 'Xt, ['Xns]"; break; 1028 case LDAXRB_w: mnemonic = "ldaxrb"; form = "'Wt, ['Xns]"; break; 1029 case LDAXRH_w: mnemonic = "ldaxrh"; form = "'Wt, ['Xns]"; break; 1030 case LDAXR_w: mnemonic = "ldaxr"; form = "'Wt, ['Xns]"; break; 1031 case LDAXR_x: mnemonic = "ldaxr"; form = "'Xt, ['Xns]"; break; 1032 case STLXP_w: mnemonic = "stlxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break; 1033 case STLXP_x: mnemonic = "stlxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break; 1034 case LDAXP_w: mnemonic = "ldaxp"; form = "'Wt, 'Wt2, ['Xns]"; break; 1035 case LDAXP_x: mnemonic = "ldaxp"; form = "'Xt, 'Xt2, ['Xns]"; break; 1036 case STLRB_w: mnemonic = "stlrb"; form = "'Wt, ['Xns]"; break; 1037 case STLRH_w: mnemonic = "stlrh"; form = "'Wt, ['Xns]"; break; 1038 case STLR_w: mnemonic = "stlr"; form = "'Wt, ['Xns]"; break; 1039 case STLR_x: mnemonic = "stlr"; form = "'Xt, ['Xns]"; break; 1040 case LDARB_w: mnemonic = "ldarb"; form = "'Wt, ['Xns]"; break; 1041 case LDARH_w: mnemonic = "ldarh"; form = "'Wt, ['Xns]"; break; 1042 case LDAR_w: mnemonic = "ldar"; form = "'Wt, ['Xns]"; break; 1043 case LDAR_x: mnemonic = "ldar"; form = "'Xt, ['Xns]"; break; 1044 default: form = "(LoadStoreExclusive)"; 1045 } 1046 Format(instr, mnemonic, form); 1047} 1048 1049 1050void Disassembler::VisitFPCompare(const Instruction* instr) { 1051 const char *mnemonic = "unimplemented"; 1052 const char *form = "'Fn, 'Fm"; 1053 const char *form_zero = "'Fn, #0.0"; 1054 1055 switch (instr->Mask(FPCompareMask)) { 1056 case FCMP_s_zero: 1057 case FCMP_d_zero: form = form_zero; VIXL_FALLTHROUGH(); 1058 case FCMP_s: 1059 case FCMP_d: mnemonic = "fcmp"; break; 1060 case FCMPE_s_zero: 1061 case FCMPE_d_zero: form = form_zero; VIXL_FALLTHROUGH(); 1062 case FCMPE_s: 1063 case FCMPE_d: mnemonic = "fcmpe"; break; 1064 default: form = "(FPCompare)"; 1065 } 1066 Format(instr, mnemonic, form); 1067} 1068 1069 1070void Disassembler::VisitFPConditionalCompare(const Instruction* instr) { 1071 const char *mnemonic = "unmplemented"; 1072 const char *form = "'Fn, 'Fm, 'INzcv, 'Cond"; 1073 1074 switch (instr->Mask(FPConditionalCompareMask)) { 1075 case FCCMP_s: 1076 case FCCMP_d: mnemonic = "fccmp"; break; 1077 case FCCMPE_s: 1078 case FCCMPE_d: mnemonic = "fccmpe"; break; 1079 default: form = "(FPConditionalCompare)"; 1080 } 1081 Format(instr, mnemonic, form); 1082} 1083 1084 1085void Disassembler::VisitFPConditionalSelect(const Instruction* instr) { 1086 const char *mnemonic = ""; 1087 const char *form = "'Fd, 'Fn, 'Fm, 'Cond"; 1088 1089 switch (instr->Mask(FPConditionalSelectMask)) { 1090 case FCSEL_s: 1091 case FCSEL_d: mnemonic = "fcsel"; break; 1092 default: VIXL_UNREACHABLE(); 1093 } 1094 Format(instr, mnemonic, form); 1095} 1096 1097 1098void Disassembler::VisitFPDataProcessing1Source(const Instruction* instr) { 1099 const char *mnemonic = "unimplemented"; 1100 const char *form = "'Fd, 'Fn"; 1101 1102 switch (instr->Mask(FPDataProcessing1SourceMask)) { 1103 #define FORMAT(A, B) \ 1104 case A##_s: \ 1105 case A##_d: mnemonic = B; break; 1106 FORMAT(FMOV, "fmov"); 1107 FORMAT(FABS, "fabs"); 1108 FORMAT(FNEG, "fneg"); 1109 FORMAT(FSQRT, "fsqrt"); 1110 FORMAT(FRINTN, "frintn"); 1111 FORMAT(FRINTP, "frintp"); 1112 FORMAT(FRINTM, "frintm"); 1113 FORMAT(FRINTZ, "frintz"); 1114 FORMAT(FRINTA, "frinta"); 1115 FORMAT(FRINTX, "frintx"); 1116 FORMAT(FRINTI, "frinti"); 1117 #undef FORMAT 1118 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break; 1119 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break; 1120 case FCVT_hs: mnemonic = "fcvt"; form = "'Hd, 'Sn"; break; 1121 case FCVT_sh: mnemonic = "fcvt"; form = "'Sd, 'Hn"; break; 1122 case FCVT_dh: mnemonic = "fcvt"; form = "'Dd, 'Hn"; break; 1123 case FCVT_hd: mnemonic = "fcvt"; form = "'Hd, 'Dn"; break; 1124 default: form = "(FPDataProcessing1Source)"; 1125 } 1126 Format(instr, mnemonic, form); 1127} 1128 1129 1130void Disassembler::VisitFPDataProcessing2Source(const Instruction* instr) { 1131 const char *mnemonic = ""; 1132 const char *form = "'Fd, 'Fn, 'Fm"; 1133 1134 switch (instr->Mask(FPDataProcessing2SourceMask)) { 1135 #define FORMAT(A, B) \ 1136 case A##_s: \ 1137 case A##_d: mnemonic = B; break; 1138 FORMAT(FMUL, "fmul"); 1139 FORMAT(FDIV, "fdiv"); 1140 FORMAT(FADD, "fadd"); 1141 FORMAT(FSUB, "fsub"); 1142 FORMAT(FMAX, "fmax"); 1143 FORMAT(FMIN, "fmin"); 1144 FORMAT(FMAXNM, "fmaxnm"); 1145 FORMAT(FMINNM, "fminnm"); 1146 FORMAT(FNMUL, "fnmul"); 1147 #undef FORMAT 1148 default: VIXL_UNREACHABLE(); 1149 } 1150 Format(instr, mnemonic, form); 1151} 1152 1153 1154void Disassembler::VisitFPDataProcessing3Source(const Instruction* instr) { 1155 const char *mnemonic = ""; 1156 const char *form = "'Fd, 'Fn, 'Fm, 'Fa"; 1157 1158 switch (instr->Mask(FPDataProcessing3SourceMask)) { 1159 #define FORMAT(A, B) \ 1160 case A##_s: \ 1161 case A##_d: mnemonic = B; break; 1162 FORMAT(FMADD, "fmadd"); 1163 FORMAT(FMSUB, "fmsub"); 1164 FORMAT(FNMADD, "fnmadd"); 1165 FORMAT(FNMSUB, "fnmsub"); 1166 #undef FORMAT 1167 default: VIXL_UNREACHABLE(); 1168 } 1169 Format(instr, mnemonic, form); 1170} 1171 1172 1173void Disassembler::VisitFPImmediate(const Instruction* instr) { 1174 const char *mnemonic = ""; 1175 const char *form = "(FPImmediate)"; 1176 1177 switch (instr->Mask(FPImmediateMask)) { 1178 case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break; 1179 case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break; 1180 default: VIXL_UNREACHABLE(); 1181 } 1182 Format(instr, mnemonic, form); 1183} 1184 1185 1186void Disassembler::VisitFPIntegerConvert(const Instruction* instr) { 1187 const char *mnemonic = "unimplemented"; 1188 const char *form = "(FPIntegerConvert)"; 1189 const char *form_rf = "'Rd, 'Fn"; 1190 const char *form_fr = "'Fd, 'Rn"; 1191 1192 switch (instr->Mask(FPIntegerConvertMask)) { 1193 case FMOV_ws: 1194 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break; 1195 case FMOV_sw: 1196 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break; 1197 case FMOV_d1_x: mnemonic = "fmov"; form = "'Vd.D[1], 'Rn"; break; 1198 case FMOV_x_d1: mnemonic = "fmov"; form = "'Rd, 'Vn.D[1]"; break; 1199 case FCVTAS_ws: 1200 case FCVTAS_xs: 1201 case FCVTAS_wd: 1202 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break; 1203 case FCVTAU_ws: 1204 case FCVTAU_xs: 1205 case FCVTAU_wd: 1206 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break; 1207 case FCVTMS_ws: 1208 case FCVTMS_xs: 1209 case FCVTMS_wd: 1210 case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break; 1211 case FCVTMU_ws: 1212 case FCVTMU_xs: 1213 case FCVTMU_wd: 1214 case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break; 1215 case FCVTNS_ws: 1216 case FCVTNS_xs: 1217 case FCVTNS_wd: 1218 case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break; 1219 case FCVTNU_ws: 1220 case FCVTNU_xs: 1221 case FCVTNU_wd: 1222 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break; 1223 case FCVTZU_xd: 1224 case FCVTZU_ws: 1225 case FCVTZU_wd: 1226 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break; 1227 case FCVTZS_xd: 1228 case FCVTZS_wd: 1229 case FCVTZS_xs: 1230 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break; 1231 case FCVTPU_xd: 1232 case FCVTPU_ws: 1233 case FCVTPU_wd: 1234 case FCVTPU_xs: mnemonic = "fcvtpu"; form = form_rf; break; 1235 case FCVTPS_xd: 1236 case FCVTPS_wd: 1237 case FCVTPS_xs: 1238 case FCVTPS_ws: mnemonic = "fcvtps"; form = form_rf; break; 1239 case SCVTF_sw: 1240 case SCVTF_sx: 1241 case SCVTF_dw: 1242 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break; 1243 case UCVTF_sw: 1244 case UCVTF_sx: 1245 case UCVTF_dw: 1246 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break; 1247 } 1248 Format(instr, mnemonic, form); 1249} 1250 1251 1252void Disassembler::VisitFPFixedPointConvert(const Instruction* instr) { 1253 const char *mnemonic = ""; 1254 const char *form = "'Rd, 'Fn, 'IFPFBits"; 1255 const char *form_fr = "'Fd, 'Rn, 'IFPFBits"; 1256 1257 switch (instr->Mask(FPFixedPointConvertMask)) { 1258 case FCVTZS_ws_fixed: 1259 case FCVTZS_xs_fixed: 1260 case FCVTZS_wd_fixed: 1261 case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break; 1262 case FCVTZU_ws_fixed: 1263 case FCVTZU_xs_fixed: 1264 case FCVTZU_wd_fixed: 1265 case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break; 1266 case SCVTF_sw_fixed: 1267 case SCVTF_sx_fixed: 1268 case SCVTF_dw_fixed: 1269 case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break; 1270 case UCVTF_sw_fixed: 1271 case UCVTF_sx_fixed: 1272 case UCVTF_dw_fixed: 1273 case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break; 1274 default: VIXL_UNREACHABLE(); 1275 } 1276 Format(instr, mnemonic, form); 1277} 1278 1279 1280void Disassembler::VisitSystem(const Instruction* instr) { 1281 // Some system instructions hijack their Op and Cp fields to represent a 1282 // range of immediates instead of indicating a different instruction. This 1283 // makes the decoding tricky. 1284 const char *mnemonic = "unimplemented"; 1285 const char *form = "(System)"; 1286 1287 if (instr->Mask(SystemExclusiveMonitorFMask) == SystemExclusiveMonitorFixed) { 1288 switch (instr->Mask(SystemExclusiveMonitorMask)) { 1289 case CLREX: { 1290 mnemonic = "clrex"; 1291 form = (instr->CRm() == 0xf) ? NULL : "'IX"; 1292 break; 1293 } 1294 } 1295 } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) { 1296 switch (instr->Mask(SystemSysRegMask)) { 1297 case MRS: { 1298 mnemonic = "mrs"; 1299 switch (instr->ImmSystemRegister()) { 1300 case NZCV: form = "'Xt, nzcv"; break; 1301 case FPCR: form = "'Xt, fpcr"; break; 1302 default: form = "'Xt, (unknown)"; break; 1303 } 1304 break; 1305 } 1306 case MSR: { 1307 mnemonic = "msr"; 1308 switch (instr->ImmSystemRegister()) { 1309 case NZCV: form = "nzcv, 'Xt"; break; 1310 case FPCR: form = "fpcr, 'Xt"; break; 1311 default: form = "(unknown), 'Xt"; break; 1312 } 1313 break; 1314 } 1315 } 1316 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) { 1317 switch (instr->ImmHint()) { 1318 case NOP: { 1319 mnemonic = "nop"; 1320 form = NULL; 1321 break; 1322 } 1323 } 1324 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) { 1325 switch (instr->Mask(MemBarrierMask)) { 1326 case DMB: { 1327 mnemonic = "dmb"; 1328 form = "'M"; 1329 break; 1330 } 1331 case DSB: { 1332 mnemonic = "dsb"; 1333 form = "'M"; 1334 break; 1335 } 1336 case ISB: { 1337 mnemonic = "isb"; 1338 form = NULL; 1339 break; 1340 } 1341 } 1342 } else if (instr->Mask(SystemSysFMask) == SystemSysFixed) { 1343 switch (instr->SysOp()) { 1344 case IVAU: 1345 mnemonic = "ic"; 1346 form = "ivau, 'Xt"; 1347 break; 1348 case CVAC: 1349 mnemonic = "dc"; 1350 form = "cvac, 'Xt"; 1351 break; 1352 case CVAU: 1353 mnemonic = "dc"; 1354 form = "cvau, 'Xt"; 1355 break; 1356 case CIVAC: 1357 mnemonic = "dc"; 1358 form = "civac, 'Xt"; 1359 break; 1360 case ZVA: 1361 mnemonic = "dc"; 1362 form = "zva, 'Xt"; 1363 break; 1364 default: 1365 mnemonic = "sys"; 1366 if (instr->Rt() == 31) { 1367 form = "'G1, 'Kn, 'Km, 'G2"; 1368 } else { 1369 form = "'G1, 'Kn, 'Km, 'G2, 'Xt"; 1370 } 1371 break; 1372 } 1373 } 1374 Format(instr, mnemonic, form); 1375} 1376 1377 1378void Disassembler::VisitException(const Instruction* instr) { 1379 const char *mnemonic = "unimplemented"; 1380 const char *form = "'IDebug"; 1381 1382 switch (instr->Mask(ExceptionMask)) { 1383 case HLT: mnemonic = "hlt"; break; 1384 case BRK: mnemonic = "brk"; break; 1385 case SVC: mnemonic = "svc"; break; 1386 case HVC: mnemonic = "hvc"; break; 1387 case SMC: mnemonic = "smc"; break; 1388 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break; 1389 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break; 1390 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break; 1391 default: form = "(Exception)"; 1392 } 1393 Format(instr, mnemonic, form); 1394} 1395 1396 1397void Disassembler::VisitCrypto2RegSHA(const Instruction* instr) { 1398 VisitUnimplemented(instr); 1399} 1400 1401 1402void Disassembler::VisitCrypto3RegSHA(const Instruction* instr) { 1403 VisitUnimplemented(instr); 1404} 1405 1406 1407void Disassembler::VisitCryptoAES(const Instruction* instr) { 1408 VisitUnimplemented(instr); 1409} 1410 1411 1412void Disassembler::VisitNEON2RegMisc(const Instruction* instr) { 1413 const char *mnemonic = "unimplemented"; 1414 const char *form = "'Vd.%s, 'Vn.%s"; 1415 const char *form_cmp_zero = "'Vd.%s, 'Vn.%s, #0"; 1416 const char *form_fcmp_zero = "'Vd.%s, 'Vn.%s, #0.0"; 1417 NEONFormatDecoder nfd(instr); 1418 1419 static const NEONFormatMap map_lp_ta = { 1420 {23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D} 1421 }; 1422 1423 static const NEONFormatMap map_cvt_ta = { 1424 {22}, {NF_4S, NF_2D} 1425 }; 1426 1427 static const NEONFormatMap map_cvt_tb = { 1428 {22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S} 1429 }; 1430 1431 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) { 1432 // These instructions all use a two bit size field, except NOT and RBIT, 1433 // which use the field to encode the operation. 1434 switch (instr->Mask(NEON2RegMiscMask)) { 1435 case NEON_REV64: mnemonic = "rev64"; break; 1436 case NEON_REV32: mnemonic = "rev32"; break; 1437 case NEON_REV16: mnemonic = "rev16"; break; 1438 case NEON_SADDLP: 1439 mnemonic = "saddlp"; 1440 nfd.SetFormatMap(0, &map_lp_ta); 1441 break; 1442 case NEON_UADDLP: 1443 mnemonic = "uaddlp"; 1444 nfd.SetFormatMap(0, &map_lp_ta); 1445 break; 1446 case NEON_SUQADD: mnemonic = "suqadd"; break; 1447 case NEON_USQADD: mnemonic = "usqadd"; break; 1448 case NEON_CLS: mnemonic = "cls"; break; 1449 case NEON_CLZ: mnemonic = "clz"; break; 1450 case NEON_CNT: mnemonic = "cnt"; break; 1451 case NEON_SADALP: 1452 mnemonic = "sadalp"; 1453 nfd.SetFormatMap(0, &map_lp_ta); 1454 break; 1455 case NEON_UADALP: 1456 mnemonic = "uadalp"; 1457 nfd.SetFormatMap(0, &map_lp_ta); 1458 break; 1459 case NEON_SQABS: mnemonic = "sqabs"; break; 1460 case NEON_SQNEG: mnemonic = "sqneg"; break; 1461 case NEON_CMGT_zero: mnemonic = "cmgt"; form = form_cmp_zero; break; 1462 case NEON_CMGE_zero: mnemonic = "cmge"; form = form_cmp_zero; break; 1463 case NEON_CMEQ_zero: mnemonic = "cmeq"; form = form_cmp_zero; break; 1464 case NEON_CMLE_zero: mnemonic = "cmle"; form = form_cmp_zero; break; 1465 case NEON_CMLT_zero: mnemonic = "cmlt"; form = form_cmp_zero; break; 1466 case NEON_ABS: mnemonic = "abs"; break; 1467 case NEON_NEG: mnemonic = "neg"; break; 1468 case NEON_RBIT_NOT: 1469 switch (instr->FPType()) { 1470 case 0: mnemonic = "mvn"; break; 1471 case 1: mnemonic = "rbit"; break; 1472 default: form = "(NEON2RegMisc)"; 1473 } 1474 nfd.SetFormatMaps(nfd.LogicalFormatMap()); 1475 break; 1476 } 1477 } else { 1478 // These instructions all use a one bit size field, except XTN, SQXTUN, 1479 // SHLL, SQXTN and UQXTN, which use a two bit size field. 1480 nfd.SetFormatMaps(nfd.FPFormatMap()); 1481 switch (instr->Mask(NEON2RegMiscFPMask)) { 1482 case NEON_FABS: mnemonic = "fabs"; break; 1483 case NEON_FNEG: mnemonic = "fneg"; break; 1484 case NEON_FCVTN: 1485 mnemonic = instr->Mask(NEON_Q) ? "fcvtn2" : "fcvtn"; 1486 nfd.SetFormatMap(0, &map_cvt_tb); 1487 nfd.SetFormatMap(1, &map_cvt_ta); 1488 break; 1489 case NEON_FCVTXN: 1490 mnemonic = instr->Mask(NEON_Q) ? "fcvtxn2" : "fcvtxn"; 1491 nfd.SetFormatMap(0, &map_cvt_tb); 1492 nfd.SetFormatMap(1, &map_cvt_ta); 1493 break; 1494 case NEON_FCVTL: 1495 mnemonic = instr->Mask(NEON_Q) ? "fcvtl2" : "fcvtl"; 1496 nfd.SetFormatMap(0, &map_cvt_ta); 1497 nfd.SetFormatMap(1, &map_cvt_tb); 1498 break; 1499 case NEON_FRINTN: mnemonic = "frintn"; break; 1500 case NEON_FRINTA: mnemonic = "frinta"; break; 1501 case NEON_FRINTP: mnemonic = "frintp"; break; 1502 case NEON_FRINTM: mnemonic = "frintm"; break; 1503 case NEON_FRINTX: mnemonic = "frintx"; break; 1504 case NEON_FRINTZ: mnemonic = "frintz"; break; 1505 case NEON_FRINTI: mnemonic = "frinti"; break; 1506 case NEON_FCVTNS: mnemonic = "fcvtns"; break; 1507 case NEON_FCVTNU: mnemonic = "fcvtnu"; break; 1508 case NEON_FCVTPS: mnemonic = "fcvtps"; break; 1509 case NEON_FCVTPU: mnemonic = "fcvtpu"; break; 1510 case NEON_FCVTMS: mnemonic = "fcvtms"; break; 1511 case NEON_FCVTMU: mnemonic = "fcvtmu"; break; 1512 case NEON_FCVTZS: mnemonic = "fcvtzs"; break; 1513 case NEON_FCVTZU: mnemonic = "fcvtzu"; break; 1514 case NEON_FCVTAS: mnemonic = "fcvtas"; break; 1515 case NEON_FCVTAU: mnemonic = "fcvtau"; break; 1516 case NEON_FSQRT: mnemonic = "fsqrt"; break; 1517 case NEON_SCVTF: mnemonic = "scvtf"; break; 1518 case NEON_UCVTF: mnemonic = "ucvtf"; break; 1519 case NEON_URSQRTE: mnemonic = "ursqrte"; break; 1520 case NEON_URECPE: mnemonic = "urecpe"; break; 1521 case NEON_FRSQRTE: mnemonic = "frsqrte"; break; 1522 case NEON_FRECPE: mnemonic = "frecpe"; break; 1523 case NEON_FCMGT_zero: mnemonic = "fcmgt"; form = form_fcmp_zero; break; 1524 case NEON_FCMGE_zero: mnemonic = "fcmge"; form = form_fcmp_zero; break; 1525 case NEON_FCMEQ_zero: mnemonic = "fcmeq"; form = form_fcmp_zero; break; 1526 case NEON_FCMLE_zero: mnemonic = "fcmle"; form = form_fcmp_zero; break; 1527 case NEON_FCMLT_zero: mnemonic = "fcmlt"; form = form_fcmp_zero; break; 1528 default: 1529 if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) && 1530 (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) { 1531 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); 1532 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); 1533 1534 switch (instr->Mask(NEON2RegMiscMask)) { 1535 case NEON_XTN: mnemonic = "xtn"; break; 1536 case NEON_SQXTN: mnemonic = "sqxtn"; break; 1537 case NEON_UQXTN: mnemonic = "uqxtn"; break; 1538 case NEON_SQXTUN: mnemonic = "sqxtun"; break; 1539 case NEON_SHLL: 1540 mnemonic = "shll"; 1541 nfd.SetFormatMap(0, nfd.LongIntegerFormatMap()); 1542 nfd.SetFormatMap(1, nfd.IntegerFormatMap()); 1543 switch (instr->NEONSize()) { 1544 case 0: form = "'Vd.%s, 'Vn.%s, #8"; break; 1545 case 1: form = "'Vd.%s, 'Vn.%s, #16"; break; 1546 case 2: form = "'Vd.%s, 'Vn.%s, #32"; break; 1547 default: form = "(NEON2RegMisc)"; 1548 } 1549 } 1550 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form)); 1551 return; 1552 } else { 1553 form = "(NEON2RegMisc)"; 1554 } 1555 } 1556 } 1557 Format(instr, mnemonic, nfd.Substitute(form)); 1558} 1559 1560 1561void Disassembler::VisitNEON3Same(const Instruction* instr) { 1562 const char *mnemonic = "unimplemented"; 1563 const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s"; 1564 NEONFormatDecoder nfd(instr); 1565 1566 if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) { 1567 switch (instr->Mask(NEON3SameLogicalMask)) { 1568 case NEON_AND: mnemonic = "and"; break; 1569 case NEON_ORR: 1570 mnemonic = "orr"; 1571 if (instr->Rm() == instr->Rn()) { 1572 mnemonic = "mov"; 1573 form = "'Vd.%s, 'Vn.%s"; 1574 } 1575 break; 1576 case NEON_ORN: mnemonic = "orn"; break; 1577 case NEON_EOR: mnemonic = "eor"; break; 1578 case NEON_BIC: mnemonic = "bic"; break; 1579 case NEON_BIF: mnemonic = "bif"; break; 1580 case NEON_BIT: mnemonic = "bit"; break; 1581 case NEON_BSL: mnemonic = "bsl"; break; 1582 default: form = "(NEON3Same)"; 1583 } 1584 nfd.SetFormatMaps(nfd.LogicalFormatMap()); 1585 } else { 1586 static const char *mnemonics[] = { 1587 "shadd", "uhadd", "shadd", "uhadd", 1588 "sqadd", "uqadd", "sqadd", "uqadd", 1589 "srhadd", "urhadd", "srhadd", "urhadd", 1590 NULL, NULL, NULL, NULL, // Handled by logical cases above. 1591 "shsub", "uhsub", "shsub", "uhsub", 1592 "sqsub", "uqsub", "sqsub", "uqsub", 1593 "cmgt", "cmhi", "cmgt", "cmhi", 1594 "cmge", "cmhs", "cmge", "cmhs", 1595 "sshl", "ushl", "sshl", "ushl", 1596 "sqshl", "uqshl", "sqshl", "uqshl", 1597 "srshl", "urshl", "srshl", "urshl", 1598 "sqrshl", "uqrshl", "sqrshl", "uqrshl", 1599 "smax", "umax", "smax", "umax", 1600 "smin", "umin", "smin", "umin", 1601 "sabd", "uabd", "sabd", "uabd", 1602 "saba", "uaba", "saba", "uaba", 1603 "add", "sub", "add", "sub", 1604 "cmtst", "cmeq", "cmtst", "cmeq", 1605 "mla", "mls", "mla", "mls", 1606 "mul", "pmul", "mul", "pmul", 1607 "smaxp", "umaxp", "smaxp", "umaxp", 1608 "sminp", "uminp", "sminp", "uminp", 1609 "sqdmulh", "sqrdmulh", "sqdmulh", "sqrdmulh", 1610 "addp", "unallocated", "addp", "unallocated", 1611 "fmaxnm", "fmaxnmp", "fminnm", "fminnmp", 1612 "fmla", "unallocated", "fmls", "unallocated", 1613 "fadd", "faddp", "fsub", "fabd", 1614 "fmulx", "fmul", "unallocated", "unallocated", 1615 "fcmeq", "fcmge", "unallocated", "fcmgt", 1616 "unallocated", "facge", "unallocated", "facgt", 1617 "fmax", "fmaxp", "fmin", "fminp", 1618 "frecps", "fdiv", "frsqrts", "unallocated"}; 1619 1620 // Operation is determined by the opcode bits (15-11), the top bit of 1621 // size (23) and the U bit (29). 1622 unsigned index = (instr->Bits(15, 11) << 2) | (instr->Bit(23) << 1) | 1623 instr->Bit(29); 1624 VIXL_ASSERT(index < (sizeof(mnemonics) / sizeof(mnemonics[0]))); 1625 mnemonic = mnemonics[index]; 1626 // Assert that index is not one of the previously handled logical 1627 // instructions. 1628 VIXL_ASSERT(mnemonic != NULL); 1629 1630 if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) { 1631 nfd.SetFormatMaps(nfd.FPFormatMap()); 1632 } 1633 } 1634 Format(instr, mnemonic, nfd.Substitute(form)); 1635} 1636 1637 1638void Disassembler::VisitNEON3Different(const Instruction* instr) { 1639 const char *mnemonic = "unimplemented"; 1640 const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s"; 1641 1642 NEONFormatDecoder nfd(instr); 1643 nfd.SetFormatMap(0, nfd.LongIntegerFormatMap()); 1644 1645 // Ignore the Q bit. Appending a "2" suffix is handled later. 1646 switch (instr->Mask(NEON3DifferentMask) & ~NEON_Q) { 1647 case NEON_PMULL: mnemonic = "pmull"; break; 1648 case NEON_SABAL: mnemonic = "sabal"; break; 1649 case NEON_SABDL: mnemonic = "sabdl"; break; 1650 case NEON_SADDL: mnemonic = "saddl"; break; 1651 case NEON_SMLAL: mnemonic = "smlal"; break; 1652 case NEON_SMLSL: mnemonic = "smlsl"; break; 1653 case NEON_SMULL: mnemonic = "smull"; break; 1654 case NEON_SSUBL: mnemonic = "ssubl"; break; 1655 case NEON_SQDMLAL: mnemonic = "sqdmlal"; break; 1656 case NEON_SQDMLSL: mnemonic = "sqdmlsl"; break; 1657 case NEON_SQDMULL: mnemonic = "sqdmull"; break; 1658 case NEON_UABAL: mnemonic = "uabal"; break; 1659 case NEON_UABDL: mnemonic = "uabdl"; break; 1660 case NEON_UADDL: mnemonic = "uaddl"; break; 1661 case NEON_UMLAL: mnemonic = "umlal"; break; 1662 case NEON_UMLSL: mnemonic = "umlsl"; break; 1663 case NEON_UMULL: mnemonic = "umull"; break; 1664 case NEON_USUBL: mnemonic = "usubl"; break; 1665 case NEON_SADDW: 1666 mnemonic = "saddw"; 1667 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); 1668 break; 1669 case NEON_SSUBW: 1670 mnemonic = "ssubw"; 1671 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); 1672 break; 1673 case NEON_UADDW: 1674 mnemonic = "uaddw"; 1675 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); 1676 break; 1677 case NEON_USUBW: 1678 mnemonic = "usubw"; 1679 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); 1680 break; 1681 case NEON_ADDHN: 1682 mnemonic = "addhn"; 1683 nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); 1684 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); 1685 break; 1686 case NEON_RADDHN: 1687 mnemonic = "raddhn"; 1688 nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); 1689 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); 1690 break; 1691 case NEON_RSUBHN: 1692 mnemonic = "rsubhn"; 1693 nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); 1694 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); 1695 break; 1696 case NEON_SUBHN: 1697 mnemonic = "subhn"; 1698 nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); 1699 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); 1700 break; 1701 default: form = "(NEON3Different)"; 1702 } 1703 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form)); 1704} 1705 1706 1707void Disassembler::VisitNEONAcrossLanes(const Instruction* instr) { 1708 const char *mnemonic = "unimplemented"; 1709 const char *form = "%sd, 'Vn.%s"; 1710 1711 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap(), 1712 NEONFormatDecoder::IntegerFormatMap()); 1713 1714 if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) { 1715 nfd.SetFormatMap(0, nfd.FPScalarFormatMap()); 1716 nfd.SetFormatMap(1, nfd.FPFormatMap()); 1717 switch (instr->Mask(NEONAcrossLanesFPMask)) { 1718 case NEON_FMAXV: mnemonic = "fmaxv"; break; 1719 case NEON_FMINV: mnemonic = "fminv"; break; 1720 case NEON_FMAXNMV: mnemonic = "fmaxnmv"; break; 1721 case NEON_FMINNMV: mnemonic = "fminnmv"; break; 1722 default: form = "(NEONAcrossLanes)"; break; 1723 } 1724 } else if (instr->Mask(NEONAcrossLanesFMask) == NEONAcrossLanesFixed) { 1725 switch (instr->Mask(NEONAcrossLanesMask)) { 1726 case NEON_ADDV: mnemonic = "addv"; break; 1727 case NEON_SMAXV: mnemonic = "smaxv"; break; 1728 case NEON_SMINV: mnemonic = "sminv"; break; 1729 case NEON_UMAXV: mnemonic = "umaxv"; break; 1730 case NEON_UMINV: mnemonic = "uminv"; break; 1731 case NEON_SADDLV: 1732 mnemonic = "saddlv"; 1733 nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); 1734 break; 1735 case NEON_UADDLV: 1736 mnemonic = "uaddlv"; 1737 nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); 1738 break; 1739 default: form = "(NEONAcrossLanes)"; break; 1740 } 1741 } 1742 Format(instr, mnemonic, nfd.Substitute(form, 1743 NEONFormatDecoder::kPlaceholder, NEONFormatDecoder::kFormat)); 1744} 1745 1746 1747void Disassembler::VisitNEONByIndexedElement(const Instruction* instr) { 1748 const char *mnemonic = "unimplemented"; 1749 bool l_instr = false; 1750 bool fp_instr = false; 1751 1752 const char *form = "'Vd.%s, 'Vn.%s, 'Ve.%s['IVByElemIndex]"; 1753 1754 static const NEONFormatMap map_ta = { 1755 {23, 22}, {NF_UNDEF, NF_4S, NF_2D} 1756 }; 1757 NEONFormatDecoder nfd(instr, &map_ta, 1758 NEONFormatDecoder::IntegerFormatMap(), 1759 NEONFormatDecoder::ScalarFormatMap()); 1760 1761 switch (instr->Mask(NEONByIndexedElementMask)) { 1762 case NEON_SMULL_byelement: mnemonic = "smull"; l_instr = true; break; 1763 case NEON_UMULL_byelement: mnemonic = "umull"; l_instr = true; break; 1764 case NEON_SMLAL_byelement: mnemonic = "smlal"; l_instr = true; break; 1765 case NEON_UMLAL_byelement: mnemonic = "umlal"; l_instr = true; break; 1766 case NEON_SMLSL_byelement: mnemonic = "smlsl"; l_instr = true; break; 1767 case NEON_UMLSL_byelement: mnemonic = "umlsl"; l_instr = true; break; 1768 case NEON_SQDMULL_byelement: mnemonic = "sqdmull"; l_instr = true; break; 1769 case NEON_SQDMLAL_byelement: mnemonic = "sqdmlal"; l_instr = true; break; 1770 case NEON_SQDMLSL_byelement: mnemonic = "sqdmlsl"; l_instr = true; break; 1771 case NEON_MUL_byelement: mnemonic = "mul"; break; 1772 case NEON_MLA_byelement: mnemonic = "mla"; break; 1773 case NEON_MLS_byelement: mnemonic = "mls"; break; 1774 case NEON_SQDMULH_byelement: mnemonic = "sqdmulh"; break; 1775 case NEON_SQRDMULH_byelement: mnemonic = "sqrdmulh"; break; 1776 default: 1777 switch (instr->Mask(NEONByIndexedElementFPMask)) { 1778 case NEON_FMUL_byelement: mnemonic = "fmul"; fp_instr = true; break; 1779 case NEON_FMLA_byelement: mnemonic = "fmla"; fp_instr = true; break; 1780 case NEON_FMLS_byelement: mnemonic = "fmls"; fp_instr = true; break; 1781 case NEON_FMULX_byelement: mnemonic = "fmulx"; fp_instr = true; break; 1782 } 1783 } 1784 1785 if (l_instr) { 1786 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form)); 1787 } else if (fp_instr) { 1788 nfd.SetFormatMap(0, nfd.FPFormatMap()); 1789 Format(instr, mnemonic, nfd.Substitute(form)); 1790 } else { 1791 nfd.SetFormatMap(0, nfd.IntegerFormatMap()); 1792 Format(instr, mnemonic, nfd.Substitute(form)); 1793 } 1794} 1795 1796 1797void Disassembler::VisitNEONCopy(const Instruction* instr) { 1798 const char *mnemonic = "unimplemented"; 1799 const char *form = "(NEONCopy)"; 1800 1801 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap(), 1802 NEONFormatDecoder::TriangularScalarFormatMap()); 1803 1804 if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) { 1805 mnemonic = "mov"; 1806 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); 1807 form = "'Vd.%s['IVInsIndex1], 'Vn.%s['IVInsIndex2]"; 1808 } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) { 1809 mnemonic = "mov"; 1810 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); 1811 if (nfd.GetVectorFormat() == kFormatD) { 1812 form = "'Vd.%s['IVInsIndex1], 'Xn"; 1813 } else { 1814 form = "'Vd.%s['IVInsIndex1], 'Wn"; 1815 } 1816 } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) { 1817 if (instr->Mask(NEON_Q) || ((instr->ImmNEON5() & 7) == 4)) { 1818 mnemonic = "mov"; 1819 } else { 1820 mnemonic = "umov"; 1821 } 1822 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); 1823 if (nfd.GetVectorFormat() == kFormatD) { 1824 form = "'Xd, 'Vn.%s['IVInsIndex1]"; 1825 } else { 1826 form = "'Wd, 'Vn.%s['IVInsIndex1]"; 1827 } 1828 } else if (instr->Mask(NEONCopySmovMask) == NEON_SMOV) { 1829 mnemonic = "smov"; 1830 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); 1831 form = "'Rdq, 'Vn.%s['IVInsIndex1]"; 1832 } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) { 1833 mnemonic = "dup"; 1834 form = "'Vd.%s, 'Vn.%s['IVInsIndex1]"; 1835 } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) { 1836 mnemonic = "dup"; 1837 if (nfd.GetVectorFormat() == kFormat2D) { 1838 form = "'Vd.%s, 'Xn"; 1839 } else { 1840 form = "'Vd.%s, 'Wn"; 1841 } 1842 } 1843 Format(instr, mnemonic, nfd.Substitute(form)); 1844} 1845 1846 1847void Disassembler::VisitNEONExtract(const Instruction* instr) { 1848 const char *mnemonic = "unimplemented"; 1849 const char *form = "(NEONExtract)"; 1850 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap()); 1851 if (instr->Mask(NEONExtractMask) == NEON_EXT) { 1852 mnemonic = "ext"; 1853 form = "'Vd.%s, 'Vn.%s, 'Vm.%s, 'IVExtract"; 1854 } 1855 Format(instr, mnemonic, nfd.Substitute(form)); 1856} 1857 1858 1859void Disassembler::VisitNEONLoadStoreMultiStruct(const Instruction* instr) { 1860 const char *mnemonic = "unimplemented"; 1861 const char *form = "(NEONLoadStoreMultiStruct)"; 1862 const char *form_1v = "{'Vt.%1$s}, ['Xns]"; 1863 const char *form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns]"; 1864 const char *form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns]"; 1865 const char *form_4v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]"; 1866 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); 1867 1868 switch (instr->Mask(NEONLoadStoreMultiStructMask)) { 1869 case NEON_LD1_1v: mnemonic = "ld1"; form = form_1v; break; 1870 case NEON_LD1_2v: mnemonic = "ld1"; form = form_2v; break; 1871 case NEON_LD1_3v: mnemonic = "ld1"; form = form_3v; break; 1872 case NEON_LD1_4v: mnemonic = "ld1"; form = form_4v; break; 1873 case NEON_LD2: mnemonic = "ld2"; form = form_2v; break; 1874 case NEON_LD3: mnemonic = "ld3"; form = form_3v; break; 1875 case NEON_LD4: mnemonic = "ld4"; form = form_4v; break; 1876 case NEON_ST1_1v: mnemonic = "st1"; form = form_1v; break; 1877 case NEON_ST1_2v: mnemonic = "st1"; form = form_2v; break; 1878 case NEON_ST1_3v: mnemonic = "st1"; form = form_3v; break; 1879 case NEON_ST1_4v: mnemonic = "st1"; form = form_4v; break; 1880 case NEON_ST2: mnemonic = "st2"; form = form_2v; break; 1881 case NEON_ST3: mnemonic = "st3"; form = form_3v; break; 1882 case NEON_ST4: mnemonic = "st4"; form = form_4v; break; 1883 default: break; 1884 } 1885 1886 Format(instr, mnemonic, nfd.Substitute(form)); 1887} 1888 1889 1890void Disassembler::VisitNEONLoadStoreMultiStructPostIndex( 1891 const Instruction* instr) { 1892 const char *mnemonic = "unimplemented"; 1893 const char *form = "(NEONLoadStoreMultiStructPostIndex)"; 1894 const char *form_1v = "{'Vt.%1$s}, ['Xns], 'Xmr1"; 1895 const char *form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns], 'Xmr2"; 1896 const char *form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns], 'Xmr3"; 1897 const char *form_4v = 1898 "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmr4"; 1899 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); 1900 1901 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) { 1902 case NEON_LD1_1v_post: mnemonic = "ld1"; form = form_1v; break; 1903 case NEON_LD1_2v_post: mnemonic = "ld1"; form = form_2v; break; 1904 case NEON_LD1_3v_post: mnemonic = "ld1"; form = form_3v; break; 1905 case NEON_LD1_4v_post: mnemonic = "ld1"; form = form_4v; break; 1906 case NEON_LD2_post: mnemonic = "ld2"; form = form_2v; break; 1907 case NEON_LD3_post: mnemonic = "ld3"; form = form_3v; break; 1908 case NEON_LD4_post: mnemonic = "ld4"; form = form_4v; break; 1909 case NEON_ST1_1v_post: mnemonic = "st1"; form = form_1v; break; 1910 case NEON_ST1_2v_post: mnemonic = "st1"; form = form_2v; break; 1911 case NEON_ST1_3v_post: mnemonic = "st1"; form = form_3v; break; 1912 case NEON_ST1_4v_post: mnemonic = "st1"; form = form_4v; break; 1913 case NEON_ST2_post: mnemonic = "st2"; form = form_2v; break; 1914 case NEON_ST3_post: mnemonic = "st3"; form = form_3v; break; 1915 case NEON_ST4_post: mnemonic = "st4"; form = form_4v; break; 1916 default: break; 1917 } 1918 1919 Format(instr, mnemonic, nfd.Substitute(form)); 1920} 1921 1922 1923void Disassembler::VisitNEONLoadStoreSingleStruct(const Instruction* instr) { 1924 const char *mnemonic = "unimplemented"; 1925 const char *form = "(NEONLoadStoreSingleStruct)"; 1926 1927 const char *form_1b = "{'Vt.b}['IVLSLane0], ['Xns]"; 1928 const char *form_1h = "{'Vt.h}['IVLSLane1], ['Xns]"; 1929 const char *form_1s = "{'Vt.s}['IVLSLane2], ['Xns]"; 1930 const char *form_1d = "{'Vt.d}['IVLSLane3], ['Xns]"; 1931 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); 1932 1933 switch (instr->Mask(NEONLoadStoreSingleStructMask)) { 1934 case NEON_LD1_b: mnemonic = "ld1"; form = form_1b; break; 1935 case NEON_LD1_h: mnemonic = "ld1"; form = form_1h; break; 1936 case NEON_LD1_s: 1937 mnemonic = "ld1"; 1938 VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d); 1939 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; 1940 break; 1941 case NEON_ST1_b: mnemonic = "st1"; form = form_1b; break; 1942 case NEON_ST1_h: mnemonic = "st1"; form = form_1h; break; 1943 case NEON_ST1_s: 1944 mnemonic = "st1"; 1945 VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d); 1946 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; 1947 break; 1948 case NEON_LD1R: 1949 mnemonic = "ld1r"; 1950 form = "{'Vt.%s}, ['Xns]"; 1951 break; 1952 case NEON_LD2_b: 1953 case NEON_ST2_b: 1954 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; 1955 form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns]"; 1956 break; 1957 case NEON_LD2_h: 1958 case NEON_ST2_h: 1959 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; 1960 form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns]"; 1961 break; 1962 case NEON_LD2_s: 1963 case NEON_ST2_s: 1964 VIXL_STATIC_ASSERT((NEON_ST2_s | (1 << NEONLSSize_offset)) == NEON_ST2_d); 1965 VIXL_STATIC_ASSERT((NEON_LD2_s | (1 << NEONLSSize_offset)) == NEON_LD2_d); 1966 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; 1967 if ((instr->NEONLSSize() & 1) == 0) 1968 form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns]"; 1969 else 1970 form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns]"; 1971 break; 1972 case NEON_LD2R: 1973 mnemonic = "ld2r"; 1974 form = "{'Vt.%s, 'Vt2.%s}, ['Xns]"; 1975 break; 1976 case NEON_LD3_b: 1977 case NEON_ST3_b: 1978 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; 1979 form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns]"; 1980 break; 1981 case NEON_LD3_h: 1982 case NEON_ST3_h: 1983 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; 1984 form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns]"; 1985 break; 1986 case NEON_LD3_s: 1987 case NEON_ST3_s: 1988 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; 1989 if ((instr->NEONLSSize() & 1) == 0) 1990 form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns]"; 1991 else 1992 form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns]"; 1993 break; 1994 case NEON_LD3R: 1995 mnemonic = "ld3r"; 1996 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns]"; 1997 break; 1998 case NEON_LD4_b: 1999 case NEON_ST4_b: 2000 mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4"; 2001 form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns]"; 2002 break; 2003 case NEON_LD4_h: 2004 case NEON_ST4_h: 2005 mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4"; 2006 form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns]"; 2007 break; 2008 case NEON_LD4_s: 2009 case NEON_ST4_s: 2010 VIXL_STATIC_ASSERT((NEON_LD4_s | (1 << NEONLSSize_offset)) == NEON_LD4_d); 2011 VIXL_STATIC_ASSERT((NEON_ST4_s | (1 << NEONLSSize_offset)) == NEON_ST4_d); 2012 mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4"; 2013 if ((instr->NEONLSSize() & 1) == 0) 2014 form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns]"; 2015 else 2016 form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns]"; 2017 break; 2018 case NEON_LD4R: 2019 mnemonic = "ld4r"; 2020 form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]"; 2021 break; 2022 default: break; 2023 } 2024 2025 Format(instr, mnemonic, nfd.Substitute(form)); 2026} 2027 2028 2029void Disassembler::VisitNEONLoadStoreSingleStructPostIndex( 2030 const Instruction* instr) { 2031 const char *mnemonic = "unimplemented"; 2032 const char *form = "(NEONLoadStoreSingleStructPostIndex)"; 2033 2034 const char *form_1b = "{'Vt.b}['IVLSLane0], ['Xns], 'Xmb1"; 2035 const char *form_1h = "{'Vt.h}['IVLSLane1], ['Xns], 'Xmb2"; 2036 const char *form_1s = "{'Vt.s}['IVLSLane2], ['Xns], 'Xmb4"; 2037 const char *form_1d = "{'Vt.d}['IVLSLane3], ['Xns], 'Xmb8"; 2038 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); 2039 2040 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) { 2041 case NEON_LD1_b_post: mnemonic = "ld1"; form = form_1b; break; 2042 case NEON_LD1_h_post: mnemonic = "ld1"; form = form_1h; break; 2043 case NEON_LD1_s_post: 2044 mnemonic = "ld1"; 2045 VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d); 2046 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; 2047 break; 2048 case NEON_ST1_b_post: mnemonic = "st1"; form = form_1b; break; 2049 case NEON_ST1_h_post: mnemonic = "st1"; form = form_1h; break; 2050 case NEON_ST1_s_post: 2051 mnemonic = "st1"; 2052 VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d); 2053 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; 2054 break; 2055 case NEON_LD1R_post: 2056 mnemonic = "ld1r"; 2057 form = "{'Vt.%s}, ['Xns], 'Xmz1"; 2058 break; 2059 case NEON_LD2_b_post: 2060 case NEON_ST2_b_post: 2061 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; 2062 form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns], 'Xmb2"; 2063 break; 2064 case NEON_ST2_h_post: 2065 case NEON_LD2_h_post: 2066 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; 2067 form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns], 'Xmb4"; 2068 break; 2069 case NEON_LD2_s_post: 2070 case NEON_ST2_s_post: 2071 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; 2072 if ((instr->NEONLSSize() & 1) == 0) 2073 form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns], 'Xmb8"; 2074 else 2075 form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns], 'Xmb16"; 2076 break; 2077 case NEON_LD2R_post: 2078 mnemonic = "ld2r"; 2079 form = "{'Vt.%s, 'Vt2.%s}, ['Xns], 'Xmz2"; 2080 break; 2081 case NEON_LD3_b_post: 2082 case NEON_ST3_b_post: 2083 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; 2084 form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns], 'Xmb3"; 2085 break; 2086 case NEON_LD3_h_post: 2087 case NEON_ST3_h_post: 2088 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; 2089 form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns], 'Xmb6"; 2090 break; 2091 case NEON_LD3_s_post: 2092 case NEON_ST3_s_post: 2093 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; 2094 if ((instr->NEONLSSize() & 1) == 0) 2095 form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns], 'Xmb12"; 2096 else 2097 form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns], 'Xmr3"; 2098 break; 2099 case NEON_LD3R_post: 2100 mnemonic = "ld3r"; 2101 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns], 'Xmz3"; 2102 break; 2103 case NEON_LD4_b_post: 2104 case NEON_ST4_b_post: 2105 mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4"; 2106 form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns], 'Xmb4"; 2107 break; 2108 case NEON_LD4_h_post: 2109 case NEON_ST4_h_post: 2110 mnemonic = (instr->LdStXLoad()) == 1 ? "ld4" : "st4"; 2111 form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns], 'Xmb8"; 2112 break; 2113 case NEON_LD4_s_post: 2114 case NEON_ST4_s_post: 2115 mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4"; 2116 if ((instr->NEONLSSize() & 1) == 0) 2117 form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns], 'Xmb16"; 2118 else 2119 form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns], 'Xmb32"; 2120 break; 2121 case NEON_LD4R_post: 2122 mnemonic = "ld4r"; 2123 form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmz4"; 2124 break; 2125 default: break; 2126 } 2127 2128 Format(instr, mnemonic, nfd.Substitute(form)); 2129} 2130 2131 2132void Disassembler::VisitNEONModifiedImmediate(const Instruction* instr) { 2133 const char *mnemonic = "unimplemented"; 2134 const char *form = "'Vt.%s, 'IVMIImm8, lsl 'IVMIShiftAmt1"; 2135 2136 int cmode = instr->NEONCmode(); 2137 int cmode_3 = (cmode >> 3) & 1; 2138 int cmode_2 = (cmode >> 2) & 1; 2139 int cmode_1 = (cmode >> 1) & 1; 2140 int cmode_0 = cmode & 1; 2141 int q = instr->NEONQ(); 2142 int op = instr->NEONModImmOp(); 2143 2144 static const NEONFormatMap map_b = { {30}, {NF_8B, NF_16B} }; 2145 static const NEONFormatMap map_h = { {30}, {NF_4H, NF_8H} }; 2146 static const NEONFormatMap map_s = { {30}, {NF_2S, NF_4S} }; 2147 NEONFormatDecoder nfd(instr, &map_b); 2148 2149 if (cmode_3 == 0) { 2150 if (cmode_0 == 0) { 2151 mnemonic = (op == 1) ? "mvni" : "movi"; 2152 } else { // cmode<0> == '1'. 2153 mnemonic = (op == 1) ? "bic" : "orr"; 2154 } 2155 nfd.SetFormatMap(0, &map_s); 2156 } else { // cmode<3> == '1'. 2157 if (cmode_2 == 0) { 2158 if (cmode_0 == 0) { 2159 mnemonic = (op == 1) ? "mvni" : "movi"; 2160 } else { // cmode<0> == '1'. 2161 mnemonic = (op == 1) ? "bic" : "orr"; 2162 } 2163 nfd.SetFormatMap(0, &map_h); 2164 } else { // cmode<2> == '1'. 2165 if (cmode_1 == 0) { 2166 mnemonic = (op == 1) ? "mvni" : "movi"; 2167 form = "'Vt.%s, 'IVMIImm8, msl 'IVMIShiftAmt2"; 2168 nfd.SetFormatMap(0, &map_s); 2169 } else { // cmode<1> == '1'. 2170 if (cmode_0 == 0) { 2171 mnemonic = "movi"; 2172 if (op == 0) { 2173 form = "'Vt.%s, 'IVMIImm8"; 2174 } else { 2175 form = (q == 0) ? "'Dd, 'IVMIImm" : "'Vt.2d, 'IVMIImm"; 2176 } 2177 } else { // cmode<0> == '1' 2178 mnemonic = "fmov"; 2179 if (op == 0) { 2180 form = "'Vt.%s, 'IVMIImmFPSingle"; 2181 nfd.SetFormatMap(0, &map_s); 2182 } else { 2183 if (q == 1) { 2184 form = "'Vt.2d, 'IVMIImmFPDouble"; 2185 } 2186 } 2187 } 2188 } 2189 } 2190 } 2191 Format(instr, mnemonic, nfd.Substitute(form)); 2192} 2193 2194 2195void Disassembler::VisitNEONScalar2RegMisc(const Instruction* instr) { 2196 const char *mnemonic = "unimplemented"; 2197 const char *form = "%sd, %sn"; 2198 const char *form_0 = "%sd, %sn, #0"; 2199 const char *form_fp0 = "%sd, %sn, #0.0"; 2200 2201 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); 2202 2203 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) { 2204 // These instructions all use a two bit size field, except NOT and RBIT, 2205 // which use the field to encode the operation. 2206 switch (instr->Mask(NEONScalar2RegMiscMask)) { 2207 case NEON_CMGT_zero_scalar: mnemonic = "cmgt"; form = form_0; break; 2208 case NEON_CMGE_zero_scalar: mnemonic = "cmge"; form = form_0; break; 2209 case NEON_CMLE_zero_scalar: mnemonic = "cmle"; form = form_0; break; 2210 case NEON_CMLT_zero_scalar: mnemonic = "cmlt"; form = form_0; break; 2211 case NEON_CMEQ_zero_scalar: mnemonic = "cmeq"; form = form_0; break; 2212 case NEON_NEG_scalar: mnemonic = "neg"; break; 2213 case NEON_SQNEG_scalar: mnemonic = "sqneg"; break; 2214 case NEON_ABS_scalar: mnemonic = "abs"; break; 2215 case NEON_SQABS_scalar: mnemonic = "sqabs"; break; 2216 case NEON_SUQADD_scalar: mnemonic = "suqadd"; break; 2217 case NEON_USQADD_scalar: mnemonic = "usqadd"; break; 2218 default: form = "(NEONScalar2RegMisc)"; 2219 } 2220 } else { 2221 // These instructions all use a one bit size field, except SQXTUN, SQXTN 2222 // and UQXTN, which use a two bit size field. 2223 nfd.SetFormatMaps(nfd.FPScalarFormatMap()); 2224 switch (instr->Mask(NEONScalar2RegMiscFPMask)) { 2225 case NEON_FRSQRTE_scalar: mnemonic = "frsqrte"; break; 2226 case NEON_FRECPE_scalar: mnemonic = "frecpe"; break; 2227 case NEON_SCVTF_scalar: mnemonic = "scvtf"; break; 2228 case NEON_UCVTF_scalar: mnemonic = "ucvtf"; break; 2229 case NEON_FCMGT_zero_scalar: mnemonic = "fcmgt"; form = form_fp0; break; 2230 case NEON_FCMGE_zero_scalar: mnemonic = "fcmge"; form = form_fp0; break; 2231 case NEON_FCMLE_zero_scalar: mnemonic = "fcmle"; form = form_fp0; break; 2232 case NEON_FCMLT_zero_scalar: mnemonic = "fcmlt"; form = form_fp0; break; 2233 case NEON_FCMEQ_zero_scalar: mnemonic = "fcmeq"; form = form_fp0; break; 2234 case NEON_FRECPX_scalar: mnemonic = "frecpx"; break; 2235 case NEON_FCVTNS_scalar: mnemonic = "fcvtns"; break; 2236 case NEON_FCVTNU_scalar: mnemonic = "fcvtnu"; break; 2237 case NEON_FCVTPS_scalar: mnemonic = "fcvtps"; break; 2238 case NEON_FCVTPU_scalar: mnemonic = "fcvtpu"; break; 2239 case NEON_FCVTMS_scalar: mnemonic = "fcvtms"; break; 2240 case NEON_FCVTMU_scalar: mnemonic = "fcvtmu"; break; 2241 case NEON_FCVTZS_scalar: mnemonic = "fcvtzs"; break; 2242 case NEON_FCVTZU_scalar: mnemonic = "fcvtzu"; break; 2243 case NEON_FCVTAS_scalar: mnemonic = "fcvtas"; break; 2244 case NEON_FCVTAU_scalar: mnemonic = "fcvtau"; break; 2245 case NEON_FCVTXN_scalar: 2246 nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); 2247 mnemonic = "fcvtxn"; 2248 break; 2249 default: 2250 nfd.SetFormatMap(0, nfd.ScalarFormatMap()); 2251 nfd.SetFormatMap(1, nfd.LongScalarFormatMap()); 2252 switch (instr->Mask(NEONScalar2RegMiscMask)) { 2253 case NEON_SQXTN_scalar: mnemonic = "sqxtn"; break; 2254 case NEON_UQXTN_scalar: mnemonic = "uqxtn"; break; 2255 case NEON_SQXTUN_scalar: mnemonic = "sqxtun"; break; 2256 default: form = "(NEONScalar2RegMisc)"; 2257 } 2258 } 2259 } 2260 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); 2261} 2262 2263 2264void Disassembler::VisitNEONScalar3Diff(const Instruction* instr) { 2265 const char *mnemonic = "unimplemented"; 2266 const char *form = "%sd, %sn, %sm"; 2267 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap(), 2268 NEONFormatDecoder::ScalarFormatMap()); 2269 2270 switch (instr->Mask(NEONScalar3DiffMask)) { 2271 case NEON_SQDMLAL_scalar : mnemonic = "sqdmlal"; break; 2272 case NEON_SQDMLSL_scalar : mnemonic = "sqdmlsl"; break; 2273 case NEON_SQDMULL_scalar : mnemonic = "sqdmull"; break; 2274 default: form = "(NEONScalar3Diff)"; 2275 } 2276 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); 2277} 2278 2279 2280void Disassembler::VisitNEONScalar3Same(const Instruction* instr) { 2281 const char *mnemonic = "unimplemented"; 2282 const char *form = "%sd, %sn, %sm"; 2283 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); 2284 2285 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) { 2286 nfd.SetFormatMaps(nfd.FPScalarFormatMap()); 2287 switch (instr->Mask(NEONScalar3SameFPMask)) { 2288 case NEON_FACGE_scalar: mnemonic = "facge"; break; 2289 case NEON_FACGT_scalar: mnemonic = "facgt"; break; 2290 case NEON_FCMEQ_scalar: mnemonic = "fcmeq"; break; 2291 case NEON_FCMGE_scalar: mnemonic = "fcmge"; break; 2292 case NEON_FCMGT_scalar: mnemonic = "fcmgt"; break; 2293 case NEON_FMULX_scalar: mnemonic = "fmulx"; break; 2294 case NEON_FRECPS_scalar: mnemonic = "frecps"; break; 2295 case NEON_FRSQRTS_scalar: mnemonic = "frsqrts"; break; 2296 case NEON_FABD_scalar: mnemonic = "fabd"; break; 2297 default: form = "(NEONScalar3Same)"; 2298 } 2299 } else { 2300 switch (instr->Mask(NEONScalar3SameMask)) { 2301 case NEON_ADD_scalar: mnemonic = "add"; break; 2302 case NEON_SUB_scalar: mnemonic = "sub"; break; 2303 case NEON_CMEQ_scalar: mnemonic = "cmeq"; break; 2304 case NEON_CMGE_scalar: mnemonic = "cmge"; break; 2305 case NEON_CMGT_scalar: mnemonic = "cmgt"; break; 2306 case NEON_CMHI_scalar: mnemonic = "cmhi"; break; 2307 case NEON_CMHS_scalar: mnemonic = "cmhs"; break; 2308 case NEON_CMTST_scalar: mnemonic = "cmtst"; break; 2309 case NEON_UQADD_scalar: mnemonic = "uqadd"; break; 2310 case NEON_SQADD_scalar: mnemonic = "sqadd"; break; 2311 case NEON_UQSUB_scalar: mnemonic = "uqsub"; break; 2312 case NEON_SQSUB_scalar: mnemonic = "sqsub"; break; 2313 case NEON_USHL_scalar: mnemonic = "ushl"; break; 2314 case NEON_SSHL_scalar: mnemonic = "sshl"; break; 2315 case NEON_UQSHL_scalar: mnemonic = "uqshl"; break; 2316 case NEON_SQSHL_scalar: mnemonic = "sqshl"; break; 2317 case NEON_URSHL_scalar: mnemonic = "urshl"; break; 2318 case NEON_SRSHL_scalar: mnemonic = "srshl"; break; 2319 case NEON_UQRSHL_scalar: mnemonic = "uqrshl"; break; 2320 case NEON_SQRSHL_scalar: mnemonic = "sqrshl"; break; 2321 case NEON_SQDMULH_scalar: mnemonic = "sqdmulh"; break; 2322 case NEON_SQRDMULH_scalar: mnemonic = "sqrdmulh"; break; 2323 default: form = "(NEONScalar3Same)"; 2324 } 2325 } 2326 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); 2327} 2328 2329 2330void Disassembler::VisitNEONScalarByIndexedElement(const Instruction* instr) { 2331 const char *mnemonic = "unimplemented"; 2332 const char *form = "%sd, %sn, 'Ve.%s['IVByElemIndex]"; 2333 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); 2334 bool long_instr = false; 2335 2336 switch (instr->Mask(NEONScalarByIndexedElementMask)) { 2337 case NEON_SQDMULL_byelement_scalar: 2338 mnemonic = "sqdmull"; 2339 long_instr = true; 2340 break; 2341 case NEON_SQDMLAL_byelement_scalar: 2342 mnemonic = "sqdmlal"; 2343 long_instr = true; 2344 break; 2345 case NEON_SQDMLSL_byelement_scalar: 2346 mnemonic = "sqdmlsl"; 2347 long_instr = true; 2348 break; 2349 case NEON_SQDMULH_byelement_scalar: 2350 mnemonic = "sqdmulh"; 2351 break; 2352 case NEON_SQRDMULH_byelement_scalar: 2353 mnemonic = "sqrdmulh"; 2354 break; 2355 default: 2356 nfd.SetFormatMap(0, nfd.FPScalarFormatMap()); 2357 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) { 2358 case NEON_FMUL_byelement_scalar: mnemonic = "fmul"; break; 2359 case NEON_FMLA_byelement_scalar: mnemonic = "fmla"; break; 2360 case NEON_FMLS_byelement_scalar: mnemonic = "fmls"; break; 2361 case NEON_FMULX_byelement_scalar: mnemonic = "fmulx"; break; 2362 default: form = "(NEONScalarByIndexedElement)"; 2363 } 2364 } 2365 2366 if (long_instr) { 2367 nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); 2368 } 2369 2370 Format(instr, mnemonic, nfd.Substitute( 2371 form, nfd.kPlaceholder, nfd.kPlaceholder, nfd.kFormat)); 2372} 2373 2374 2375void Disassembler::VisitNEONScalarCopy(const Instruction* instr) { 2376 const char *mnemonic = "unimplemented"; 2377 const char *form = "(NEONScalarCopy)"; 2378 2379 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap()); 2380 2381 if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) { 2382 mnemonic = "mov"; 2383 form = "%sd, 'Vn.%s['IVInsIndex1]"; 2384 } 2385 2386 Format(instr, mnemonic, nfd.Substitute(form, nfd.kPlaceholder, nfd.kFormat)); 2387} 2388 2389 2390void Disassembler::VisitNEONScalarPairwise(const Instruction* instr) { 2391 const char *mnemonic = "unimplemented"; 2392 const char *form = "%sd, 'Vn.%s"; 2393 NEONFormatMap map = { {22}, {NF_2S, NF_2D} }; 2394 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap(), &map); 2395 2396 switch (instr->Mask(NEONScalarPairwiseMask)) { 2397 case NEON_ADDP_scalar: mnemonic = "addp"; break; 2398 case NEON_FADDP_scalar: mnemonic = "faddp"; break; 2399 case NEON_FMAXP_scalar: mnemonic = "fmaxp"; break; 2400 case NEON_FMAXNMP_scalar: mnemonic = "fmaxnmp"; break; 2401 case NEON_FMINP_scalar: mnemonic = "fminp"; break; 2402 case NEON_FMINNMP_scalar: mnemonic = "fminnmp"; break; 2403 default: form = "(NEONScalarPairwise)"; 2404 } 2405 Format(instr, mnemonic, nfd.Substitute(form, 2406 NEONFormatDecoder::kPlaceholder, NEONFormatDecoder::kFormat)); 2407} 2408 2409 2410void Disassembler::VisitNEONScalarShiftImmediate(const Instruction* instr) { 2411 const char *mnemonic = "unimplemented"; 2412 const char *form = "%sd, %sn, 'Is1"; 2413 const char *form_2 = "%sd, %sn, 'Is2"; 2414 2415 static const NEONFormatMap map_shift = { 2416 {22, 21, 20, 19}, 2417 {NF_UNDEF, NF_B, NF_H, NF_H, NF_S, NF_S, NF_S, NF_S, 2418 NF_D, NF_D, NF_D, NF_D, NF_D, NF_D, NF_D, NF_D} 2419 }; 2420 static const NEONFormatMap map_shift_narrow = { 2421 {21, 20, 19}, 2422 {NF_UNDEF, NF_H, NF_S, NF_S, NF_D, NF_D, NF_D, NF_D} 2423 }; 2424 NEONFormatDecoder nfd(instr, &map_shift); 2425 2426 if (instr->ImmNEONImmh()) { // immh has to be non-zero. 2427 switch (instr->Mask(NEONScalarShiftImmediateMask)) { 2428 case NEON_FCVTZU_imm_scalar: mnemonic = "fcvtzu"; break; 2429 case NEON_FCVTZS_imm_scalar: mnemonic = "fcvtzs"; break; 2430 case NEON_SCVTF_imm_scalar: mnemonic = "scvtf"; break; 2431 case NEON_UCVTF_imm_scalar: mnemonic = "ucvtf"; break; 2432 case NEON_SRI_scalar: mnemonic = "sri"; break; 2433 case NEON_SSHR_scalar: mnemonic = "sshr"; break; 2434 case NEON_USHR_scalar: mnemonic = "ushr"; break; 2435 case NEON_SRSHR_scalar: mnemonic = "srshr"; break; 2436 case NEON_URSHR_scalar: mnemonic = "urshr"; break; 2437 case NEON_SSRA_scalar: mnemonic = "ssra"; break; 2438 case NEON_USRA_scalar: mnemonic = "usra"; break; 2439 case NEON_SRSRA_scalar: mnemonic = "srsra"; break; 2440 case NEON_URSRA_scalar: mnemonic = "ursra"; break; 2441 case NEON_SHL_scalar: mnemonic = "shl"; form = form_2; break; 2442 case NEON_SLI_scalar: mnemonic = "sli"; form = form_2; break; 2443 case NEON_SQSHLU_scalar: mnemonic = "sqshlu"; form = form_2; break; 2444 case NEON_SQSHL_imm_scalar: mnemonic = "sqshl"; form = form_2; break; 2445 case NEON_UQSHL_imm_scalar: mnemonic = "uqshl"; form = form_2; break; 2446 case NEON_UQSHRN_scalar: 2447 mnemonic = "uqshrn"; 2448 nfd.SetFormatMap(1, &map_shift_narrow); 2449 break; 2450 case NEON_UQRSHRN_scalar: 2451 mnemonic = "uqrshrn"; 2452 nfd.SetFormatMap(1, &map_shift_narrow); 2453 break; 2454 case NEON_SQSHRN_scalar: 2455 mnemonic = "sqshrn"; 2456 nfd.SetFormatMap(1, &map_shift_narrow); 2457 break; 2458 case NEON_SQRSHRN_scalar: 2459 mnemonic = "sqrshrn"; 2460 nfd.SetFormatMap(1, &map_shift_narrow); 2461 break; 2462 case NEON_SQSHRUN_scalar: 2463 mnemonic = "sqshrun"; 2464 nfd.SetFormatMap(1, &map_shift_narrow); 2465 break; 2466 case NEON_SQRSHRUN_scalar: 2467 mnemonic = "sqrshrun"; 2468 nfd.SetFormatMap(1, &map_shift_narrow); 2469 break; 2470 default: 2471 form = "(NEONScalarShiftImmediate)"; 2472 } 2473 } else { 2474 form = "(NEONScalarShiftImmediate)"; 2475 } 2476 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); 2477} 2478 2479 2480void Disassembler::VisitNEONShiftImmediate(const Instruction* instr) { 2481 const char *mnemonic = "unimplemented"; 2482 const char *form = "'Vd.%s, 'Vn.%s, 'Is1"; 2483 const char *form_shift_2 = "'Vd.%s, 'Vn.%s, 'Is2"; 2484 const char *form_xtl = "'Vd.%s, 'Vn.%s"; 2485 2486 // 0001->8H, 001x->4S, 01xx->2D, all others undefined. 2487 static const NEONFormatMap map_shift_ta = { 2488 {22, 21, 20, 19}, 2489 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D} 2490 }; 2491 2492 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H, 2493 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined. 2494 static const NEONFormatMap map_shift_tb = { 2495 {22, 21, 20, 19, 30}, 2496 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_4H, NF_8H, 2497 NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, 2498 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, 2499 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D} 2500 }; 2501 2502 NEONFormatDecoder nfd(instr, &map_shift_tb); 2503 2504 if (instr->ImmNEONImmh()) { // immh has to be non-zero. 2505 switch (instr->Mask(NEONShiftImmediateMask)) { 2506 case NEON_SQSHLU: mnemonic = "sqshlu"; form = form_shift_2; break; 2507 case NEON_SQSHL_imm: mnemonic = "sqshl"; form = form_shift_2; break; 2508 case NEON_UQSHL_imm: mnemonic = "uqshl"; form = form_shift_2; break; 2509 case NEON_SHL: mnemonic = "shl"; form = form_shift_2; break; 2510 case NEON_SLI: mnemonic = "sli"; form = form_shift_2; break; 2511 case NEON_SCVTF_imm: mnemonic = "scvtf"; break; 2512 case NEON_UCVTF_imm: mnemonic = "ucvtf"; break; 2513 case NEON_FCVTZU_imm: mnemonic = "fcvtzu"; break; 2514 case NEON_FCVTZS_imm: mnemonic = "fcvtzs"; break; 2515 case NEON_SRI: mnemonic = "sri"; break; 2516 case NEON_SSHR: mnemonic = "sshr"; break; 2517 case NEON_USHR: mnemonic = "ushr"; break; 2518 case NEON_SRSHR: mnemonic = "srshr"; break; 2519 case NEON_URSHR: mnemonic = "urshr"; break; 2520 case NEON_SSRA: mnemonic = "ssra"; break; 2521 case NEON_USRA: mnemonic = "usra"; break; 2522 case NEON_SRSRA: mnemonic = "srsra"; break; 2523 case NEON_URSRA: mnemonic = "ursra"; break; 2524 case NEON_SHRN: 2525 mnemonic = instr->Mask(NEON_Q) ? "shrn2" : "shrn"; 2526 nfd.SetFormatMap(1, &map_shift_ta); 2527 break; 2528 case NEON_RSHRN: 2529 mnemonic = instr->Mask(NEON_Q) ? "rshrn2" : "rshrn"; 2530 nfd.SetFormatMap(1, &map_shift_ta); 2531 break; 2532 case NEON_UQSHRN: 2533 mnemonic = instr->Mask(NEON_Q) ? "uqshrn2" : "uqshrn"; 2534 nfd.SetFormatMap(1, &map_shift_ta); 2535 break; 2536 case NEON_UQRSHRN: 2537 mnemonic = instr->Mask(NEON_Q) ? "uqrshrn2" : "uqrshrn"; 2538 nfd.SetFormatMap(1, &map_shift_ta); 2539 break; 2540 case NEON_SQSHRN: 2541 mnemonic = instr->Mask(NEON_Q) ? "sqshrn2" : "sqshrn"; 2542 nfd.SetFormatMap(1, &map_shift_ta); 2543 break; 2544 case NEON_SQRSHRN: 2545 mnemonic = instr->Mask(NEON_Q) ? "sqrshrn2" : "sqrshrn"; 2546 nfd.SetFormatMap(1, &map_shift_ta); 2547 break; 2548 case NEON_SQSHRUN: 2549 mnemonic = instr->Mask(NEON_Q) ? "sqshrun2" : "sqshrun"; 2550 nfd.SetFormatMap(1, &map_shift_ta); 2551 break; 2552 case NEON_SQRSHRUN: 2553 mnemonic = instr->Mask(NEON_Q) ? "sqrshrun2" : "sqrshrun"; 2554 nfd.SetFormatMap(1, &map_shift_ta); 2555 break; 2556 case NEON_SSHLL: 2557 nfd.SetFormatMap(0, &map_shift_ta); 2558 if (instr->ImmNEONImmb() == 0 && 2559 CountSetBits(instr->ImmNEONImmh(), 32) == 1) { // sxtl variant. 2560 form = form_xtl; 2561 mnemonic = instr->Mask(NEON_Q) ? "sxtl2" : "sxtl"; 2562 } else { // sshll variant. 2563 form = form_shift_2; 2564 mnemonic = instr->Mask(NEON_Q) ? "sshll2" : "sshll"; 2565 } 2566 break; 2567 case NEON_USHLL: 2568 nfd.SetFormatMap(0, &map_shift_ta); 2569 if (instr->ImmNEONImmb() == 0 && 2570 CountSetBits(instr->ImmNEONImmh(), 32) == 1) { // uxtl variant. 2571 form = form_xtl; 2572 mnemonic = instr->Mask(NEON_Q) ? "uxtl2" : "uxtl"; 2573 } else { // ushll variant. 2574 form = form_shift_2; 2575 mnemonic = instr->Mask(NEON_Q) ? "ushll2" : "ushll"; 2576 } 2577 break; 2578 default: form = "(NEONShiftImmediate)"; 2579 } 2580 } else { 2581 form = "(NEONShiftImmediate)"; 2582 } 2583 Format(instr, mnemonic, nfd.Substitute(form)); 2584} 2585 2586 2587void Disassembler::VisitNEONTable(const Instruction* instr) { 2588 const char *mnemonic = "unimplemented"; 2589 const char *form = "(NEONTable)"; 2590 const char form_1v[] = "'Vd.%%s, {'Vn.16b}, 'Vm.%%s"; 2591 const char form_2v[] = "'Vd.%%s, {'Vn.16b, v%d.16b}, 'Vm.%%s"; 2592 const char form_3v[] = "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b}, 'Vm.%%s"; 2593 const char form_4v[] = 2594 "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b, v%d.16b}, 'Vm.%%s"; 2595 static const NEONFormatMap map_b = { {30}, {NF_8B, NF_16B} }; 2596 NEONFormatDecoder nfd(instr, &map_b); 2597 2598 switch (instr->Mask(NEONTableMask)) { 2599 case NEON_TBL_1v: mnemonic = "tbl"; form = form_1v; break; 2600 case NEON_TBL_2v: mnemonic = "tbl"; form = form_2v; break; 2601 case NEON_TBL_3v: mnemonic = "tbl"; form = form_3v; break; 2602 case NEON_TBL_4v: mnemonic = "tbl"; form = form_4v; break; 2603 case NEON_TBX_1v: mnemonic = "tbx"; form = form_1v; break; 2604 case NEON_TBX_2v: mnemonic = "tbx"; form = form_2v; break; 2605 case NEON_TBX_3v: mnemonic = "tbx"; form = form_3v; break; 2606 case NEON_TBX_4v: mnemonic = "tbx"; form = form_4v; break; 2607 default: break; 2608 } 2609 2610 char re_form[sizeof(form_4v) + 6]; 2611 int reg_num = instr->Rn(); 2612 snprintf(re_form, sizeof(re_form), form, 2613 (reg_num + 1) % kNumberOfVRegisters, 2614 (reg_num + 2) % kNumberOfVRegisters, 2615 (reg_num + 3) % kNumberOfVRegisters); 2616 2617 Format(instr, mnemonic, nfd.Substitute(re_form)); 2618} 2619 2620 2621void Disassembler::VisitNEONPerm(const Instruction* instr) { 2622 const char *mnemonic = "unimplemented"; 2623 const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s"; 2624 NEONFormatDecoder nfd(instr); 2625 2626 switch (instr->Mask(NEONPermMask)) { 2627 case NEON_TRN1: mnemonic = "trn1"; break; 2628 case NEON_TRN2: mnemonic = "trn2"; break; 2629 case NEON_UZP1: mnemonic = "uzp1"; break; 2630 case NEON_UZP2: mnemonic = "uzp2"; break; 2631 case NEON_ZIP1: mnemonic = "zip1"; break; 2632 case NEON_ZIP2: mnemonic = "zip2"; break; 2633 default: form = "(NEONPerm)"; 2634 } 2635 Format(instr, mnemonic, nfd.Substitute(form)); 2636} 2637 2638 2639void Disassembler::VisitUnimplemented(const Instruction* instr) { 2640 Format(instr, "unimplemented", "(Unimplemented)"); 2641} 2642 2643 2644void Disassembler::VisitUnallocated(const Instruction* instr) { 2645 Format(instr, "unallocated", "(Unallocated)"); 2646} 2647 2648 2649void Disassembler::ProcessOutput(const Instruction* /*instr*/) { 2650 // The base disasm does nothing more than disassembling into a buffer. 2651} 2652 2653 2654void Disassembler::AppendRegisterNameToOutput(const Instruction* instr, 2655 const CPURegister& reg) { 2656 USE(instr); 2657 VIXL_ASSERT(reg.IsValid()); 2658 char reg_char; 2659 2660 if (reg.IsRegister()) { 2661 reg_char = reg.Is64Bits() ? 'x' : 'w'; 2662 } else { 2663 VIXL_ASSERT(reg.IsVRegister()); 2664 switch (reg.SizeInBits()) { 2665 case kBRegSize: reg_char = 'b'; break; 2666 case kHRegSize: reg_char = 'h'; break; 2667 case kSRegSize: reg_char = 's'; break; 2668 case kDRegSize: reg_char = 'd'; break; 2669 default: 2670 VIXL_ASSERT(reg.Is128Bits()); 2671 reg_char = 'q'; 2672 } 2673 } 2674 2675 if (reg.IsVRegister() || !(reg.Aliases(sp) || reg.Aliases(xzr))) { 2676 // A core or scalar/vector register: [wx]0 - 30, [bhsdq]0 - 31. 2677 AppendToOutput("%c%d", reg_char, reg.code()); 2678 } else if (reg.Aliases(sp)) { 2679 // Disassemble w31/x31 as stack pointer wsp/sp. 2680 AppendToOutput("%s", reg.Is64Bits() ? "sp" : "wsp"); 2681 } else { 2682 // Disassemble w31/x31 as zero register wzr/xzr. 2683 AppendToOutput("%czr", reg_char); 2684 } 2685} 2686 2687 2688void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction* instr, 2689 int64_t offset) { 2690 USE(instr); 2691 uint64_t abs_offset = offset; 2692 char sign = (offset < 0) ? '-' : '+'; 2693 if (offset < 0) { 2694 abs_offset = -abs_offset; 2695 } 2696 AppendToOutput("#%c0x%" PRIx64, sign, abs_offset); 2697} 2698 2699 2700void Disassembler::AppendAddressToOutput(const Instruction* instr, 2701 const void* addr) { 2702 USE(instr); 2703 AppendToOutput("(addr 0x%" PRIxPTR ")", reinterpret_cast<uintptr_t>(addr)); 2704} 2705 2706 2707void Disassembler::AppendCodeAddressToOutput(const Instruction* instr, 2708 const void* addr) { 2709 AppendAddressToOutput(instr, addr); 2710} 2711 2712 2713void Disassembler::AppendDataAddressToOutput(const Instruction* instr, 2714 const void* addr) { 2715 AppendAddressToOutput(instr, addr); 2716} 2717 2718 2719void Disassembler::AppendCodeRelativeAddressToOutput(const Instruction* instr, 2720 const void* addr) { 2721 USE(instr); 2722 int64_t rel_addr = CodeRelativeAddress(addr); 2723 if (rel_addr >= 0) { 2724 AppendToOutput("(addr 0x%" PRIx64 ")", rel_addr); 2725 } else { 2726 AppendToOutput("(addr -0x%" PRIx64 ")", -rel_addr); 2727 } 2728} 2729 2730 2731void Disassembler::AppendCodeRelativeCodeAddressToOutput( 2732 const Instruction* instr, const void* addr) { 2733 AppendCodeRelativeAddressToOutput(instr, addr); 2734} 2735 2736 2737void Disassembler::AppendCodeRelativeDataAddressToOutput( 2738 const Instruction* instr, const void* addr) { 2739 AppendCodeRelativeAddressToOutput(instr, addr); 2740} 2741 2742 2743void Disassembler::MapCodeAddress(int64_t base_address, 2744 const Instruction* instr_address) { 2745 set_code_address_offset( 2746 base_address - reinterpret_cast<intptr_t>(instr_address)); 2747} 2748int64_t Disassembler::CodeRelativeAddress(const void* addr) { 2749 return reinterpret_cast<intptr_t>(addr) + code_address_offset(); 2750} 2751 2752 2753void Disassembler::Format(const Instruction* instr, const char* mnemonic, 2754 const char* format) { 2755 VIXL_ASSERT(mnemonic != NULL); 2756 ResetOutput(); 2757 Substitute(instr, mnemonic); 2758 if (format != NULL) { 2759 VIXL_ASSERT(buffer_pos_ < buffer_size_); 2760 buffer_[buffer_pos_++] = ' '; 2761 Substitute(instr, format); 2762 } 2763 VIXL_ASSERT(buffer_pos_ < buffer_size_); 2764 buffer_[buffer_pos_] = 0; 2765 ProcessOutput(instr); 2766} 2767 2768 2769void Disassembler::Substitute(const Instruction* instr, const char* string) { 2770 char chr = *string++; 2771 while (chr != '\0') { 2772 if (chr == '\'') { 2773 string += SubstituteField(instr, string); 2774 } else { 2775 VIXL_ASSERT(buffer_pos_ < buffer_size_); 2776 buffer_[buffer_pos_++] = chr; 2777 } 2778 chr = *string++; 2779 } 2780} 2781 2782 2783int Disassembler::SubstituteField(const Instruction* instr, 2784 const char* format) { 2785 switch (format[0]) { 2786 // NB. The remaining substitution prefix characters are: GJKUZ. 2787 case 'R': // Register. X or W, selected by sf bit. 2788 case 'F': // FP register. S or D, selected by type field. 2789 case 'V': // Vector register, V, vector format. 2790 case 'W': 2791 case 'X': 2792 case 'B': 2793 case 'H': 2794 case 'S': 2795 case 'D': 2796 case 'Q': return SubstituteRegisterField(instr, format); 2797 case 'I': return SubstituteImmediateField(instr, format); 2798 case 'L': return SubstituteLiteralField(instr, format); 2799 case 'N': return SubstituteShiftField(instr, format); 2800 case 'P': return SubstitutePrefetchField(instr, format); 2801 case 'C': return SubstituteConditionField(instr, format); 2802 case 'E': return SubstituteExtendField(instr, format); 2803 case 'A': return SubstitutePCRelAddressField(instr, format); 2804 case 'T': return SubstituteBranchTargetField(instr, format); 2805 case 'O': return SubstituteLSRegOffsetField(instr, format); 2806 case 'M': return SubstituteBarrierField(instr, format); 2807 case 'K': return SubstituteCrField(instr, format); 2808 case 'G': return SubstituteSysOpField(instr, format); 2809 default: { 2810 VIXL_UNREACHABLE(); 2811 return 1; 2812 } 2813 } 2814} 2815 2816 2817int Disassembler::SubstituteRegisterField(const Instruction* instr, 2818 const char* format) { 2819 char reg_prefix = format[0]; 2820 unsigned reg_num = 0; 2821 unsigned field_len = 2; 2822 2823 switch (format[1]) { 2824 case 'd': 2825 reg_num = instr->Rd(); 2826 if (format[2] == 'q') { 2827 reg_prefix = instr->NEONQ() ? 'X' : 'W'; 2828 field_len = 3; 2829 } 2830 break; 2831 case 'n': reg_num = instr->Rn(); break; 2832 case 'm': 2833 reg_num = instr->Rm(); 2834 switch (format[2]) { 2835 // Handle registers tagged with b (bytes), z (instruction), or 2836 // r (registers), used for address updates in 2837 // NEON load/store instructions. 2838 case 'r': 2839 case 'b': 2840 case 'z': { 2841 field_len = 3; 2842 char* eimm; 2843 int imm = static_cast<int>(strtol(&format[3], &eimm, 10)); 2844 field_len += eimm - &format[3]; 2845 if (reg_num == 31) { 2846 switch (format[2]) { 2847 case 'z': 2848 imm *= (1 << instr->NEONLSSize()); 2849 break; 2850 case 'r': 2851 imm *= (instr->NEONQ() == 0) ? kDRegSizeInBytes 2852 : kQRegSizeInBytes; 2853 break; 2854 case 'b': 2855 break; 2856 } 2857 AppendToOutput("#%d", imm); 2858 return field_len; 2859 } 2860 break; 2861 } 2862 } 2863 break; 2864 case 'e': 2865 // This is register Rm, but using a 4-bit specifier. Used in NEON 2866 // by-element instructions. 2867 reg_num = (instr->Rm() & 0xf); 2868 break; 2869 case 'a': reg_num = instr->Ra(); break; 2870 case 's': reg_num = instr->Rs(); break; 2871 case 't': 2872 reg_num = instr->Rt(); 2873 if (format[0] == 'V') { 2874 if ((format[2] >= '2') && (format[2] <= '4')) { 2875 // Handle consecutive vector register specifiers Vt2, Vt3 and Vt4. 2876 reg_num = (reg_num + format[2] - '1') % 32; 2877 field_len = 3; 2878 } 2879 } else { 2880 if (format[2] == '2') { 2881 // Handle register specifier Rt2. 2882 reg_num = instr->Rt2(); 2883 field_len = 3; 2884 } 2885 } 2886 break; 2887 default: VIXL_UNREACHABLE(); 2888 } 2889 2890 // Increase field length for registers tagged as stack. 2891 if (format[2] == 's') { 2892 field_len = 3; 2893 } 2894 2895 CPURegister::RegisterType reg_type = CPURegister::kRegister; 2896 unsigned reg_size = kXRegSize; 2897 2898 if (reg_prefix == 'R') { 2899 reg_prefix = instr->SixtyFourBits() ? 'X' : 'W'; 2900 } else if (reg_prefix == 'F') { 2901 reg_prefix = ((instr->FPType() & 1) == 0) ? 'S' : 'D'; 2902 } 2903 2904 switch (reg_prefix) { 2905 case 'W': 2906 reg_type = CPURegister::kRegister; reg_size = kWRegSize; break; 2907 case 'X': 2908 reg_type = CPURegister::kRegister; reg_size = kXRegSize; break; 2909 case 'B': 2910 reg_type = CPURegister::kVRegister; reg_size = kBRegSize; break; 2911 case 'H': 2912 reg_type = CPURegister::kVRegister; reg_size = kHRegSize; break; 2913 case 'S': 2914 reg_type = CPURegister::kVRegister; reg_size = kSRegSize; break; 2915 case 'D': 2916 reg_type = CPURegister::kVRegister; reg_size = kDRegSize; break; 2917 case 'Q': 2918 reg_type = CPURegister::kVRegister; reg_size = kQRegSize; break; 2919 case 'V': 2920 AppendToOutput("v%d", reg_num); 2921 return field_len; 2922 default: 2923 VIXL_UNREACHABLE(); 2924 } 2925 2926 if ((reg_type == CPURegister::kRegister) && 2927 (reg_num == kZeroRegCode) && (format[2] == 's')) { 2928 reg_num = kSPRegInternalCode; 2929 } 2930 2931 AppendRegisterNameToOutput(instr, CPURegister(reg_num, reg_size, reg_type)); 2932 2933 return field_len; 2934} 2935 2936 2937int Disassembler::SubstituteImmediateField(const Instruction* instr, 2938 const char* format) { 2939 VIXL_ASSERT(format[0] == 'I'); 2940 2941 switch (format[1]) { 2942 case 'M': { // IMoveImm, IMoveNeg or IMoveLSL. 2943 if (format[5] == 'L') { 2944 AppendToOutput("#0x%" PRIx32, instr->ImmMoveWide()); 2945 if (instr->ShiftMoveWide() > 0) { 2946 AppendToOutput(", lsl #%" PRId32, 16 * instr->ShiftMoveWide()); 2947 } 2948 } else { 2949 VIXL_ASSERT((format[5] == 'I') || (format[5] == 'N')); 2950 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide()) << 2951 (16 * instr->ShiftMoveWide()); 2952 if (format[5] == 'N') 2953 imm = ~imm; 2954 if (!instr->SixtyFourBits()) 2955 imm &= UINT64_C(0xffffffff); 2956 AppendToOutput("#0x%" PRIx64, imm); 2957 } 2958 return 8; 2959 } 2960 case 'L': { 2961 switch (format[2]) { 2962 case 'L': { // ILLiteral - Immediate Load Literal. 2963 AppendToOutput("pc%+" PRId32, 2964 instr->ImmLLiteral() << kLiteralEntrySizeLog2); 2965 return 9; 2966 } 2967 case 'S': { // ILS - Immediate Load/Store. 2968 if (instr->ImmLS() != 0) { 2969 AppendToOutput(", #%" PRId32, instr->ImmLS()); 2970 } 2971 return 3; 2972 } 2973 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size. 2974 if (instr->ImmLSPair() != 0) { 2975 // format[3] is the scale value. Convert to a number. 2976 int scale = 1 << (format[3] - '0'); 2977 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale); 2978 } 2979 return 4; 2980 } 2981 case 'U': { // ILU - Immediate Load/Store Unsigned. 2982 if (instr->ImmLSUnsigned() != 0) { 2983 int shift = instr->SizeLS(); 2984 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned() << shift); 2985 } 2986 return 3; 2987 } 2988 default: { 2989 VIXL_UNIMPLEMENTED(); 2990 return 0; 2991 } 2992 } 2993 } 2994 case 'C': { // ICondB - Immediate Conditional Branch. 2995 int64_t offset = instr->ImmCondBranch() << 2; 2996 AppendPCRelativeOffsetToOutput(instr, offset); 2997 return 6; 2998 } 2999 case 'A': { // IAddSub. 3000 VIXL_ASSERT(instr->ShiftAddSub() <= 1); 3001 int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub()); 3002 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm); 3003 return 7; 3004 } 3005 case 'F': { // IFPSingle, IFPDouble or IFPFBits. 3006 if (format[3] == 'F') { // IFPFbits. 3007 AppendToOutput("#%" PRId32, 64 - instr->FPScale()); 3008 return 8; 3009 } else { 3010 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmFP(), 3011 format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64()); 3012 return 9; 3013 } 3014 } 3015 case 'T': { // ITri - Immediate Triangular Encoded. 3016 AppendToOutput("#0x%" PRIx64, instr->ImmLogical()); 3017 return 4; 3018 } 3019 case 'N': { // INzcv. 3020 int nzcv = (instr->Nzcv() << Flags_offset); 3021 AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N', 3022 ((nzcv & ZFlag) == 0) ? 'z' : 'Z', 3023 ((nzcv & CFlag) == 0) ? 'c' : 'C', 3024 ((nzcv & VFlag) == 0) ? 'v' : 'V'); 3025 return 5; 3026 } 3027 case 'P': { // IP - Conditional compare. 3028 AppendToOutput("#%" PRId32, instr->ImmCondCmp()); 3029 return 2; 3030 } 3031 case 'B': { // Bitfields. 3032 return SubstituteBitfieldImmediateField(instr, format); 3033 } 3034 case 'E': { // IExtract. 3035 AppendToOutput("#%" PRId32, instr->ImmS()); 3036 return 8; 3037 } 3038 case 'S': { // IS - Test and branch bit. 3039 AppendToOutput("#%" PRId32, (instr->ImmTestBranchBit5() << 5) | 3040 instr->ImmTestBranchBit40()); 3041 return 2; 3042 } 3043 case 's': { // Is - Shift (immediate). 3044 switch (format[2]) { 3045 case '1': { // Is1 - SSHR. 3046 int shift = 16 << HighestSetBitPosition(instr->ImmNEONImmh()); 3047 shift -= instr->ImmNEONImmhImmb(); 3048 AppendToOutput("#%d", shift); 3049 return 3; 3050 } 3051 case '2': { // Is2 - SLI. 3052 int shift = instr->ImmNEONImmhImmb(); 3053 shift -= 8 << HighestSetBitPosition(instr->ImmNEONImmh()); 3054 AppendToOutput("#%d", shift); 3055 return 3; 3056 } 3057 default: { 3058 VIXL_UNIMPLEMENTED(); 3059 return 0; 3060 } 3061 } 3062 } 3063 case 'D': { // IDebug - HLT and BRK instructions. 3064 AppendToOutput("#0x%" PRIx32, instr->ImmException()); 3065 return 6; 3066 } 3067 case 'V': { // Immediate Vector. 3068 switch (format[2]) { 3069 case 'E': { // IVExtract. 3070 AppendToOutput("#%" PRId32, instr->ImmNEONExt()); 3071 return 9; 3072 } 3073 case 'B': { // IVByElemIndex. 3074 int vm_index = (instr->NEONH() << 1) | instr->NEONL(); 3075 if (instr->NEONSize() == 1) { 3076 vm_index = (vm_index << 1) | instr->NEONM(); 3077 } 3078 AppendToOutput("%d", vm_index); 3079 return strlen("IVByElemIndex"); 3080 } 3081 case 'I': { // INS element. 3082 if (strncmp(format, "IVInsIndex", strlen("IVInsIndex")) == 0) { 3083 int rd_index, rn_index; 3084 int imm5 = instr->ImmNEON5(); 3085 int imm4 = instr->ImmNEON4(); 3086 int tz = CountTrailingZeros(imm5, 32); 3087 rd_index = imm5 >> (tz + 1); 3088 rn_index = imm4 >> tz; 3089 if (strncmp(format, "IVInsIndex1", strlen("IVInsIndex1")) == 0) { 3090 AppendToOutput("%d", rd_index); 3091 return strlen("IVInsIndex1"); 3092 } else if (strncmp(format, "IVInsIndex2", 3093 strlen("IVInsIndex2")) == 0) { 3094 AppendToOutput("%d", rn_index); 3095 return strlen("IVInsIndex2"); 3096 } else { 3097 VIXL_UNIMPLEMENTED(); 3098 return 0; 3099 } 3100 } 3101 VIXL_FALLTHROUGH(); 3102 } 3103 case 'L': { // IVLSLane[0123] - suffix indicates access size shift. 3104 AppendToOutput("%d", instr->NEONLSIndex(format[8] - '0')); 3105 return 9; 3106 } 3107 case 'M': { // Modified Immediate cases. 3108 if (strncmp(format, 3109 "IVMIImmFPSingle", 3110 strlen("IVMIImmFPSingle")) == 0) { 3111 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(), 3112 instr->ImmNEONFP32()); 3113 return strlen("IVMIImmFPSingle"); 3114 } else if (strncmp(format, 3115 "IVMIImmFPDouble", 3116 strlen("IVMIImmFPDouble")) == 0) { 3117 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(), 3118 instr->ImmNEONFP64()); 3119 return strlen("IVMIImmFPDouble"); 3120 } else if (strncmp(format, "IVMIImm8", strlen("IVMIImm8")) == 0) { 3121 uint64_t imm8 = instr->ImmNEONabcdefgh(); 3122 AppendToOutput("#0x%" PRIx64, imm8); 3123 return strlen("IVMIImm8"); 3124 } else if (strncmp(format, "IVMIImm", strlen("IVMIImm")) == 0) { 3125 uint64_t imm8 = instr->ImmNEONabcdefgh(); 3126 uint64_t imm = 0; 3127 for (int i = 0; i < 8; ++i) { 3128 if (imm8 & (1 << i)) { 3129 imm |= (UINT64_C(0xff) << (8 * i)); 3130 } 3131 } 3132 AppendToOutput("#0x%" PRIx64, imm); 3133 return strlen("IVMIImm"); 3134 } else if (strncmp(format, "IVMIShiftAmt1", 3135 strlen("IVMIShiftAmt1")) == 0) { 3136 int cmode = instr->NEONCmode(); 3137 int shift_amount = 8 * ((cmode >> 1) & 3); 3138 AppendToOutput("#%d", shift_amount); 3139 return strlen("IVMIShiftAmt1"); 3140 } else if (strncmp(format, "IVMIShiftAmt2", 3141 strlen("IVMIShiftAmt2")) == 0) { 3142 int cmode = instr->NEONCmode(); 3143 int shift_amount = 8 << (cmode & 1); 3144 AppendToOutput("#%d", shift_amount); 3145 return strlen("IVMIShiftAmt2"); 3146 } else { 3147 VIXL_UNIMPLEMENTED(); 3148 return 0; 3149 } 3150 } 3151 default: { 3152 VIXL_UNIMPLEMENTED(); 3153 return 0; 3154 } 3155 } 3156 } 3157 case 'X': { // IX - CLREX instruction. 3158 AppendToOutput("#0x%" PRIx32, instr->CRm()); 3159 return 2; 3160 } 3161 default: { 3162 VIXL_UNIMPLEMENTED(); 3163 return 0; 3164 } 3165 } 3166} 3167 3168 3169int Disassembler::SubstituteBitfieldImmediateField(const Instruction* instr, 3170 const char* format) { 3171 VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B')); 3172 unsigned r = instr->ImmR(); 3173 unsigned s = instr->ImmS(); 3174 3175 switch (format[2]) { 3176 case 'r': { // IBr. 3177 AppendToOutput("#%d", r); 3178 return 3; 3179 } 3180 case 's': { // IBs+1 or IBs-r+1. 3181 if (format[3] == '+') { 3182 AppendToOutput("#%d", s + 1); 3183 return 5; 3184 } else { 3185 VIXL_ASSERT(format[3] == '-'); 3186 AppendToOutput("#%d", s - r + 1); 3187 return 7; 3188 } 3189 } 3190 case 'Z': { // IBZ-r. 3191 VIXL_ASSERT((format[3] == '-') && (format[4] == 'r')); 3192 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize; 3193 AppendToOutput("#%d", reg_size - r); 3194 return 5; 3195 } 3196 default: { 3197 VIXL_UNREACHABLE(); 3198 return 0; 3199 } 3200 } 3201} 3202 3203 3204int Disassembler::SubstituteLiteralField(const Instruction* instr, 3205 const char* format) { 3206 VIXL_ASSERT(strncmp(format, "LValue", 6) == 0); 3207 USE(format); 3208 3209 const void * address = instr->LiteralAddress<const void *>(); 3210 switch (instr->Mask(LoadLiteralMask)) { 3211 case LDR_w_lit: 3212 case LDR_x_lit: 3213 case LDRSW_x_lit: 3214 case LDR_s_lit: 3215 case LDR_d_lit: 3216 case LDR_q_lit: 3217 AppendCodeRelativeDataAddressToOutput(instr, address); 3218 break; 3219 case PRFM_lit: { 3220 // Use the prefetch hint to decide how to print the address. 3221 switch (instr->PrefetchHint()) { 3222 case 0x0: // PLD: prefetch for load. 3223 case 0x2: // PST: prepare for store. 3224 AppendCodeRelativeDataAddressToOutput(instr, address); 3225 break; 3226 case 0x1: // PLI: preload instructions. 3227 AppendCodeRelativeCodeAddressToOutput(instr, address); 3228 break; 3229 case 0x3: // Unallocated hint. 3230 AppendCodeRelativeAddressToOutput(instr, address); 3231 break; 3232 } 3233 break; 3234 } 3235 default: 3236 VIXL_UNREACHABLE(); 3237 } 3238 3239 return 6; 3240} 3241 3242 3243int Disassembler::SubstituteShiftField(const Instruction* instr, 3244 const char* format) { 3245 VIXL_ASSERT(format[0] == 'N'); 3246 VIXL_ASSERT(instr->ShiftDP() <= 0x3); 3247 3248 switch (format[1]) { 3249 case 'D': { // HDP. 3250 VIXL_ASSERT(instr->ShiftDP() != ROR); 3251 VIXL_FALLTHROUGH(); 3252 } 3253 case 'L': { // HLo. 3254 if (instr->ImmDPShift() != 0) { 3255 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"}; 3256 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()], 3257 instr->ImmDPShift()); 3258 } 3259 return 3; 3260 } 3261 default: 3262 VIXL_UNIMPLEMENTED(); 3263 return 0; 3264 } 3265} 3266 3267 3268int Disassembler::SubstituteConditionField(const Instruction* instr, 3269 const char* format) { 3270 VIXL_ASSERT(format[0] == 'C'); 3271 const char* condition_code[] = { "eq", "ne", "hs", "lo", 3272 "mi", "pl", "vs", "vc", 3273 "hi", "ls", "ge", "lt", 3274 "gt", "le", "al", "nv" }; 3275 int cond; 3276 switch (format[1]) { 3277 case 'B': cond = instr->ConditionBranch(); break; 3278 case 'I': { 3279 cond = InvertCondition(static_cast<Condition>(instr->Condition())); 3280 break; 3281 } 3282 default: cond = instr->Condition(); 3283 } 3284 AppendToOutput("%s", condition_code[cond]); 3285 return 4; 3286} 3287 3288 3289int Disassembler::SubstitutePCRelAddressField(const Instruction* instr, 3290 const char* format) { 3291 VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`. 3292 (strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`. 3293 3294 int64_t offset = instr->ImmPCRel(); 3295 3296 // Compute the target address based on the effective address (after applying 3297 // code_address_offset). This is required for correct behaviour of adrp. 3298 const Instruction* base = instr + code_address_offset(); 3299 if (format[9] == 'P') { 3300 offset *= kPageSize; 3301 base = AlignDown(base, kPageSize); 3302 } 3303 // Strip code_address_offset before printing, so we can use the 3304 // semantically-correct AppendCodeRelativeAddressToOutput. 3305 const void* target = 3306 reinterpret_cast<const void*>(base + offset - code_address_offset()); 3307 3308 AppendPCRelativeOffsetToOutput(instr, offset); 3309 AppendToOutput(" "); 3310 AppendCodeRelativeAddressToOutput(instr, target); 3311 return 13; 3312} 3313 3314 3315int Disassembler::SubstituteBranchTargetField(const Instruction* instr, 3316 const char* format) { 3317 VIXL_ASSERT(strncmp(format, "TImm", 4) == 0); 3318 3319 int64_t offset = 0; 3320 switch (format[5]) { 3321 // BImmUncn - unconditional branch immediate. 3322 case 'n': offset = instr->ImmUncondBranch(); break; 3323 // BImmCond - conditional branch immediate. 3324 case 'o': offset = instr->ImmCondBranch(); break; 3325 // BImmCmpa - compare and branch immediate. 3326 case 'm': offset = instr->ImmCmpBranch(); break; 3327 // BImmTest - test and branch immediate. 3328 case 'e': offset = instr->ImmTestBranch(); break; 3329 default: VIXL_UNIMPLEMENTED(); 3330 } 3331 offset <<= kInstructionSizeLog2; 3332 const void* target_address = reinterpret_cast<const void*>(instr + offset); 3333 VIXL_STATIC_ASSERT(sizeof(*instr) == 1); 3334 3335 AppendPCRelativeOffsetToOutput(instr, offset); 3336 AppendToOutput(" "); 3337 AppendCodeRelativeCodeAddressToOutput(instr, target_address); 3338 3339 return 8; 3340} 3341 3342 3343int Disassembler::SubstituteExtendField(const Instruction* instr, 3344 const char* format) { 3345 VIXL_ASSERT(strncmp(format, "Ext", 3) == 0); 3346 VIXL_ASSERT(instr->ExtendMode() <= 7); 3347 USE(format); 3348 3349 const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx", 3350 "sxtb", "sxth", "sxtw", "sxtx" }; 3351 3352 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit 3353 // registers becomes lsl. 3354 if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) && 3355 (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) || 3356 (instr->ExtendMode() == UXTX))) { 3357 if (instr->ImmExtendShift() > 0) { 3358 AppendToOutput(", lsl #%" PRId32, instr->ImmExtendShift()); 3359 } 3360 } else { 3361 AppendToOutput(", %s", extend_mode[instr->ExtendMode()]); 3362 if (instr->ImmExtendShift() > 0) { 3363 AppendToOutput(" #%" PRId32, instr->ImmExtendShift()); 3364 } 3365 } 3366 return 3; 3367} 3368 3369 3370int Disassembler::SubstituteLSRegOffsetField(const Instruction* instr, 3371 const char* format) { 3372 VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0); 3373 const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl", 3374 "undefined", "undefined", "sxtw", "sxtx" }; 3375 USE(format); 3376 3377 unsigned shift = instr->ImmShiftLS(); 3378 Extend ext = static_cast<Extend>(instr->ExtendMode()); 3379 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x'; 3380 3381 unsigned rm = instr->Rm(); 3382 if (rm == kZeroRegCode) { 3383 AppendToOutput("%czr", reg_type); 3384 } else { 3385 AppendToOutput("%c%d", reg_type, rm); 3386 } 3387 3388 // Extend mode UXTX is an alias for shift mode LSL here. 3389 if (!((ext == UXTX) && (shift == 0))) { 3390 AppendToOutput(", %s", extend_mode[ext]); 3391 if (shift != 0) { 3392 AppendToOutput(" #%d", instr->SizeLS()); 3393 } 3394 } 3395 return 9; 3396} 3397 3398 3399int Disassembler::SubstitutePrefetchField(const Instruction* instr, 3400 const char* format) { 3401 VIXL_ASSERT(format[0] == 'P'); 3402 USE(format); 3403 3404 static const char* hints[] = {"ld", "li", "st"}; 3405 static const char* stream_options[] = {"keep", "strm"}; 3406 3407 unsigned hint = instr->PrefetchHint(); 3408 unsigned target = instr->PrefetchTarget() + 1; 3409 unsigned stream = instr->PrefetchStream(); 3410 3411 if ((hint >= (sizeof(hints) / sizeof(hints[0]))) || (target > 3)) { 3412 // Unallocated prefetch operations. 3413 int prefetch_mode = instr->ImmPrefetchOperation(); 3414 AppendToOutput("#0b%c%c%c%c%c", 3415 (prefetch_mode & (1 << 4)) ? '1' : '0', 3416 (prefetch_mode & (1 << 3)) ? '1' : '0', 3417 (prefetch_mode & (1 << 2)) ? '1' : '0', 3418 (prefetch_mode & (1 << 1)) ? '1' : '0', 3419 (prefetch_mode & (1 << 0)) ? '1' : '0'); 3420 } else { 3421 VIXL_ASSERT(stream < (sizeof(stream_options) / sizeof(stream_options[0]))); 3422 AppendToOutput("p%sl%d%s", hints[hint], target, stream_options[stream]); 3423 } 3424 return 6; 3425} 3426 3427int Disassembler::SubstituteBarrierField(const Instruction* instr, 3428 const char* format) { 3429 VIXL_ASSERT(format[0] == 'M'); 3430 USE(format); 3431 3432 static const char* options[4][4] = { 3433 { "sy (0b0000)", "oshld", "oshst", "osh" }, 3434 { "sy (0b0100)", "nshld", "nshst", "nsh" }, 3435 { "sy (0b1000)", "ishld", "ishst", "ish" }, 3436 { "sy (0b1100)", "ld", "st", "sy" } 3437 }; 3438 int domain = instr->ImmBarrierDomain(); 3439 int type = instr->ImmBarrierType(); 3440 3441 AppendToOutput("%s", options[domain][type]); 3442 return 1; 3443} 3444 3445int Disassembler::SubstituteSysOpField(const Instruction* instr, 3446 const char* format) { 3447 VIXL_ASSERT(format[0] == 'G'); 3448 int op = -1; 3449 switch (format[1]) { 3450 case '1': op = instr->SysOp1(); break; 3451 case '2': op = instr->SysOp2(); break; 3452 default: 3453 VIXL_UNREACHABLE(); 3454 } 3455 AppendToOutput("#%d", op); 3456 return 2; 3457} 3458 3459int Disassembler::SubstituteCrField(const Instruction* instr, 3460 const char* format) { 3461 VIXL_ASSERT(format[0] == 'K'); 3462 int cr = -1; 3463 switch (format[1]) { 3464 case 'n': cr = instr->CRn(); break; 3465 case 'm': cr = instr->CRm(); break; 3466 default: 3467 VIXL_UNREACHABLE(); 3468 } 3469 AppendToOutput("C%d", cr); 3470 return 2; 3471} 3472 3473void Disassembler::ResetOutput() { 3474 buffer_pos_ = 0; 3475 buffer_[buffer_pos_] = 0; 3476} 3477 3478 3479void Disassembler::AppendToOutput(const char* format, ...) { 3480 va_list args; 3481 va_start(args, format); 3482 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_ - buffer_pos_, 3483 format, args); 3484 va_end(args); 3485} 3486 3487 3488void PrintDisassembler::ProcessOutput(const Instruction* instr) { 3489 fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n", 3490 reinterpret_cast<uint64_t>(instr), 3491 instr->InstructionBits(), 3492 GetOutput()); 3493} 3494 3495} // namespace vixl