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