1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #if V8_TARGET_ARCH_ARM64 6 7 #include "src/arm64/assembler-arm64-inl.h" 8 #include "src/arm64/instructions-arm64.h" 9 10 namespace v8 { 11 namespace internal { 12 13 bool Instruction::IsLoad() const { 14 if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) { 15 return false; 16 } 17 18 if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) { 19 return Mask(LoadStorePairLBit) != 0; 20 } else { 21 LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreMask)); 22 switch (op) { 23 case LDRB_w: 24 case LDRH_w: 25 case LDR_w: 26 case LDR_x: 27 case LDRSB_w: 28 case LDRSB_x: 29 case LDRSH_w: 30 case LDRSH_x: 31 case LDRSW_x: 32 case LDR_b: 33 case LDR_h: 34 case LDR_s: 35 case LDR_d: 36 case LDR_q: 37 return true; 38 default: return false; 39 } 40 } 41 } 42 43 44 bool Instruction::IsStore() const { 45 if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) { 46 return false; 47 } 48 49 if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) { 50 return Mask(LoadStorePairLBit) == 0; 51 } else { 52 LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreMask)); 53 switch (op) { 54 case STRB_w: 55 case STRH_w: 56 case STR_w: 57 case STR_x: 58 case STR_b: 59 case STR_h: 60 case STR_s: 61 case STR_d: 62 case STR_q: 63 return true; 64 default: return false; 65 } 66 } 67 } 68 69 70 static uint64_t RotateRight(uint64_t value, 71 unsigned int rotate, 72 unsigned int width) { 73 DCHECK_LE(width, 64); 74 rotate &= 63; 75 return ((value & ((1UL << rotate) - 1UL)) << (width - rotate)) | 76 (value >> rotate); 77 } 78 79 80 static uint64_t RepeatBitsAcrossReg(unsigned reg_size, 81 uint64_t value, 82 unsigned width) { 83 DCHECK((width == 2) || (width == 4) || (width == 8) || (width == 16) || 84 (width == 32)); 85 DCHECK((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits)); 86 uint64_t result = value & ((1UL << width) - 1UL); 87 for (unsigned i = width; i < reg_size; i *= 2) { 88 result |= (result << i); 89 } 90 return result; 91 } 92 93 94 // Logical immediates can't encode zero, so a return value of zero is used to 95 // indicate a failure case. Specifically, where the constraints on imm_s are not 96 // met. 97 uint64_t Instruction::ImmLogical() { 98 unsigned reg_size = SixtyFourBits() ? kXRegSizeInBits : kWRegSizeInBits; 99 int32_t n = BitN(); 100 int32_t imm_s = ImmSetBits(); 101 int32_t imm_r = ImmRotate(); 102 103 // An integer is constructed from the n, imm_s and imm_r bits according to 104 // the following table: 105 // 106 // N imms immr size S R 107 // 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr) 108 // 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr) 109 // 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr) 110 // 0 110sss xxxrrr 8 UInt(sss) UInt(rrr) 111 // 0 1110ss xxxxrr 4 UInt(ss) UInt(rr) 112 // 0 11110s xxxxxr 2 UInt(s) UInt(r) 113 // (s bits must not be all set) 114 // 115 // A pattern is constructed of size bits, where the least significant S+1 116 // bits are set. The pattern is rotated right by R, and repeated across a 117 // 32 or 64-bit value, depending on destination register width. 118 // 119 120 if (n == 1) { 121 if (imm_s == 0x3F) { 122 return 0; 123 } 124 uint64_t bits = (1UL << (imm_s + 1)) - 1; 125 return RotateRight(bits, imm_r, 64); 126 } else { 127 if ((imm_s >> 1) == 0x1F) { 128 return 0; 129 } 130 for (int width = 0x20; width >= 0x2; width >>= 1) { 131 if ((imm_s & width) == 0) { 132 int mask = width - 1; 133 if ((imm_s & mask) == mask) { 134 return 0; 135 } 136 uint64_t bits = (1UL << ((imm_s & mask) + 1)) - 1; 137 return RepeatBitsAcrossReg(reg_size, 138 RotateRight(bits, imm_r & mask, width), 139 width); 140 } 141 } 142 } 143 UNREACHABLE(); 144 } 145 146 uint32_t Instruction::ImmNEONabcdefgh() const { 147 return ImmNEONabc() << 5 | ImmNEONdefgh(); 148 } 149 150 float Instruction::ImmFP32() { return Imm8ToFP32(ImmFP()); } 151 152 double Instruction::ImmFP64() { return Imm8ToFP64(ImmFP()); } 153 154 float Instruction::ImmNEONFP32() const { return Imm8ToFP32(ImmNEONabcdefgh()); } 155 156 double Instruction::ImmNEONFP64() const { 157 return Imm8ToFP64(ImmNEONabcdefgh()); 158 } 159 160 unsigned CalcLSDataSize(LoadStoreOp op) { 161 DCHECK_EQ(static_cast<unsigned>(LSSize_offset + LSSize_width), 162 kInstrSize * 8); 163 unsigned size = static_cast<Instr>(op) >> LSSize_offset; 164 if ((op & LSVector_mask) != 0) { 165 // Vector register memory operations encode the access size in the "size" 166 // and "opc" fields. 167 if ((size == 0) && ((op & LSOpc_mask) >> LSOpc_offset) >= 2) { 168 size = kQRegSizeLog2; 169 } 170 } 171 return size; 172 } 173 174 unsigned CalcLSPairDataSize(LoadStorePairOp op) { 175 static_assert(kXRegSize == kDRegSize, "X and D registers must be same size."); 176 static_assert(kWRegSize == kSRegSize, "W and S registers must be same size."); 177 switch (op) { 178 case STP_q: 179 case LDP_q: 180 return kQRegSizeLog2; 181 case STP_x: 182 case LDP_x: 183 case STP_d: 184 case LDP_d: 185 return kXRegSizeLog2; 186 default: 187 return kWRegSizeLog2; 188 } 189 } 190 191 192 int64_t Instruction::ImmPCOffset() { 193 int64_t offset; 194 if (IsPCRelAddressing()) { 195 // PC-relative addressing. Only ADR is supported. 196 offset = ImmPCRel(); 197 } else if (BranchType() != UnknownBranchType) { 198 // All PC-relative branches. 199 // Relative branch offsets are instruction-size-aligned. 200 offset = ImmBranch() << kInstrSizeLog2; 201 } else if (IsUnresolvedInternalReference()) { 202 // Internal references are always word-aligned. 203 offset = ImmUnresolvedInternalReference() << kInstrSizeLog2; 204 } else { 205 // Load literal (offset from PC). 206 DCHECK(IsLdrLiteral()); 207 // The offset is always shifted by 2 bits, even for loads to 64-bits 208 // registers. 209 offset = ImmLLiteral() << kInstrSizeLog2; 210 } 211 return offset; 212 } 213 214 215 Instruction* Instruction::ImmPCOffsetTarget() { 216 return InstructionAtOffset(ImmPCOffset()); 217 } 218 219 220 bool Instruction::IsValidImmPCOffset(ImmBranchType branch_type, 221 ptrdiff_t offset) { 222 return is_intn(offset, ImmBranchRangeBitwidth(branch_type)); 223 } 224 225 226 bool Instruction::IsTargetInImmPCOffsetRange(Instruction* target) { 227 return IsValidImmPCOffset(BranchType(), DistanceTo(target)); 228 } 229 230 void Instruction::SetImmPCOffsetTarget(const AssemblerOptions& options, 231 Instruction* target) { 232 if (IsPCRelAddressing()) { 233 SetPCRelImmTarget(options, target); 234 } else if (BranchType() != UnknownBranchType) { 235 SetBranchImmTarget(target); 236 } else if (IsUnresolvedInternalReference()) { 237 SetUnresolvedInternalReferenceImmTarget(options, target); 238 } else { 239 // Load literal (offset from PC). 240 SetImmLLiteral(target); 241 } 242 } 243 244 void Instruction::SetPCRelImmTarget(const AssemblerOptions& options, 245 Instruction* target) { 246 // ADRP is not supported, so 'this' must point to an ADR instruction. 247 DCHECK(IsAdr()); 248 249 ptrdiff_t target_offset = DistanceTo(target); 250 Instr imm; 251 if (Instruction::IsValidPCRelOffset(target_offset)) { 252 imm = Assembler::ImmPCRelAddress(static_cast<int>(target_offset)); 253 SetInstructionBits(Mask(~ImmPCRel_mask) | imm); 254 } else { 255 PatchingAssembler patcher(options, reinterpret_cast<byte*>(this), 256 PatchingAssembler::kAdrFarPatchableNInstrs); 257 patcher.PatchAdrFar(target_offset); 258 } 259 } 260 261 262 void Instruction::SetBranchImmTarget(Instruction* target) { 263 DCHECK(IsAligned(DistanceTo(target), kInstrSize)); 264 DCHECK( 265 IsValidImmPCOffset(BranchType(), DistanceTo(target) >> kInstrSizeLog2)); 266 int offset = static_cast<int>(DistanceTo(target) >> kInstrSizeLog2); 267 Instr branch_imm = 0; 268 uint32_t imm_mask = 0; 269 switch (BranchType()) { 270 case CondBranchType: { 271 branch_imm = Assembler::ImmCondBranch(offset); 272 imm_mask = ImmCondBranch_mask; 273 break; 274 } 275 case UncondBranchType: { 276 branch_imm = Assembler::ImmUncondBranch(offset); 277 imm_mask = ImmUncondBranch_mask; 278 break; 279 } 280 case CompareBranchType: { 281 branch_imm = Assembler::ImmCmpBranch(offset); 282 imm_mask = ImmCmpBranch_mask; 283 break; 284 } 285 case TestBranchType: { 286 branch_imm = Assembler::ImmTestBranch(offset); 287 imm_mask = ImmTestBranch_mask; 288 break; 289 } 290 default: UNREACHABLE(); 291 } 292 SetInstructionBits(Mask(~imm_mask) | branch_imm); 293 } 294 295 void Instruction::SetUnresolvedInternalReferenceImmTarget( 296 const AssemblerOptions& options, Instruction* target) { 297 DCHECK(IsUnresolvedInternalReference()); 298 DCHECK(IsAligned(DistanceTo(target), kInstrSize)); 299 DCHECK(is_int32(DistanceTo(target) >> kInstrSizeLog2)); 300 int32_t target_offset = 301 static_cast<int32_t>(DistanceTo(target) >> kInstrSizeLog2); 302 uint32_t high16 = unsigned_bitextract_32(31, 16, target_offset); 303 uint32_t low16 = unsigned_bitextract_32(15, 0, target_offset); 304 305 PatchingAssembler patcher(options, reinterpret_cast<byte*>(this), 2); 306 patcher.brk(high16); 307 patcher.brk(low16); 308 } 309 310 311 void Instruction::SetImmLLiteral(Instruction* source) { 312 DCHECK(IsLdrLiteral()); 313 DCHECK(IsAligned(DistanceTo(source), kInstrSize)); 314 DCHECK(Assembler::IsImmLLiteral(DistanceTo(source))); 315 Instr imm = Assembler::ImmLLiteral( 316 static_cast<int>(DistanceTo(source) >> kLoadLiteralScaleLog2)); 317 Instr mask = ImmLLiteral_mask; 318 319 SetInstructionBits(Mask(~mask) | imm); 320 } 321 322 323 // TODO(jbramley): We can't put this inline in the class because things like 324 // xzr and Register are not defined in that header. Consider adding 325 // instructions-arm64-inl.h to work around this. 326 bool InstructionSequence::IsInlineData() const { 327 // Inline data is encoded as a single movz instruction which writes to xzr 328 // (x31). 329 return IsMovz() && SixtyFourBits() && (Rd() == kZeroRegCode); 330 // TODO(all): If we extend ::InlineData() to support bigger data, we need 331 // to update this method too. 332 } 333 334 335 // TODO(jbramley): We can't put this inline in the class because things like 336 // xzr and Register are not defined in that header. Consider adding 337 // instructions-arm64-inl.h to work around this. 338 uint64_t InstructionSequence::InlineData() const { 339 DCHECK(IsInlineData()); 340 uint64_t payload = ImmMoveWide(); 341 // TODO(all): If we extend ::InlineData() to support bigger data, we need 342 // to update this method too. 343 return payload; 344 } 345 346 VectorFormat VectorFormatHalfWidth(VectorFormat vform) { 347 DCHECK(vform == kFormat8H || vform == kFormat4S || vform == kFormat2D || 348 vform == kFormatH || vform == kFormatS || vform == kFormatD); 349 switch (vform) { 350 case kFormat8H: 351 return kFormat8B; 352 case kFormat4S: 353 return kFormat4H; 354 case kFormat2D: 355 return kFormat2S; 356 case kFormatH: 357 return kFormatB; 358 case kFormatS: 359 return kFormatH; 360 case kFormatD: 361 return kFormatS; 362 default: 363 UNREACHABLE(); 364 } 365 } 366 367 VectorFormat VectorFormatDoubleWidth(VectorFormat vform) { 368 DCHECK(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S || 369 vform == kFormatB || vform == kFormatH || vform == kFormatS); 370 switch (vform) { 371 case kFormat8B: 372 return kFormat8H; 373 case kFormat4H: 374 return kFormat4S; 375 case kFormat2S: 376 return kFormat2D; 377 case kFormatB: 378 return kFormatH; 379 case kFormatH: 380 return kFormatS; 381 case kFormatS: 382 return kFormatD; 383 default: 384 UNREACHABLE(); 385 } 386 } 387 388 VectorFormat VectorFormatFillQ(VectorFormat vform) { 389 switch (vform) { 390 case kFormatB: 391 case kFormat8B: 392 case kFormat16B: 393 return kFormat16B; 394 case kFormatH: 395 case kFormat4H: 396 case kFormat8H: 397 return kFormat8H; 398 case kFormatS: 399 case kFormat2S: 400 case kFormat4S: 401 return kFormat4S; 402 case kFormatD: 403 case kFormat1D: 404 case kFormat2D: 405 return kFormat2D; 406 default: 407 UNREACHABLE(); 408 } 409 } 410 411 VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform) { 412 switch (vform) { 413 case kFormat4H: 414 return kFormat8B; 415 case kFormat8H: 416 return kFormat16B; 417 case kFormat2S: 418 return kFormat4H; 419 case kFormat4S: 420 return kFormat8H; 421 case kFormat1D: 422 return kFormat2S; 423 case kFormat2D: 424 return kFormat4S; 425 default: 426 UNREACHABLE(); 427 } 428 } 429 430 VectorFormat VectorFormatDoubleLanes(VectorFormat vform) { 431 DCHECK(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S); 432 switch (vform) { 433 case kFormat8B: 434 return kFormat16B; 435 case kFormat4H: 436 return kFormat8H; 437 case kFormat2S: 438 return kFormat4S; 439 default: 440 UNREACHABLE(); 441 } 442 } 443 444 VectorFormat VectorFormatHalfLanes(VectorFormat vform) { 445 DCHECK(vform == kFormat16B || vform == kFormat8H || vform == kFormat4S); 446 switch (vform) { 447 case kFormat16B: 448 return kFormat8B; 449 case kFormat8H: 450 return kFormat4H; 451 case kFormat4S: 452 return kFormat2S; 453 default: 454 UNREACHABLE(); 455 } 456 } 457 458 VectorFormat ScalarFormatFromLaneSize(int laneSize) { 459 switch (laneSize) { 460 case 8: 461 return kFormatB; 462 case 16: 463 return kFormatH; 464 case 32: 465 return kFormatS; 466 case 64: 467 return kFormatD; 468 default: 469 UNREACHABLE(); 470 } 471 } 472 473 VectorFormat ScalarFormatFromFormat(VectorFormat vform) { 474 return ScalarFormatFromLaneSize(LaneSizeInBitsFromFormat(vform)); 475 } 476 477 unsigned RegisterSizeInBytesFromFormat(VectorFormat vform) { 478 return RegisterSizeInBitsFromFormat(vform) / 8; 479 } 480 481 unsigned RegisterSizeInBitsFromFormat(VectorFormat vform) { 482 DCHECK_NE(vform, kFormatUndefined); 483 switch (vform) { 484 case kFormatB: 485 return kBRegSizeInBits; 486 case kFormatH: 487 return kHRegSizeInBits; 488 case kFormatS: 489 return kSRegSizeInBits; 490 case kFormatD: 491 return kDRegSizeInBits; 492 case kFormat8B: 493 case kFormat4H: 494 case kFormat2S: 495 case kFormat1D: 496 return kDRegSizeInBits; 497 default: 498 return kQRegSizeInBits; 499 } 500 } 501 502 unsigned LaneSizeInBitsFromFormat(VectorFormat vform) { 503 DCHECK_NE(vform, kFormatUndefined); 504 switch (vform) { 505 case kFormatB: 506 case kFormat8B: 507 case kFormat16B: 508 return 8; 509 case kFormatH: 510 case kFormat4H: 511 case kFormat8H: 512 return 16; 513 case kFormatS: 514 case kFormat2S: 515 case kFormat4S: 516 return 32; 517 case kFormatD: 518 case kFormat1D: 519 case kFormat2D: 520 return 64; 521 default: 522 UNREACHABLE(); 523 } 524 } 525 526 int LaneSizeInBytesFromFormat(VectorFormat vform) { 527 return LaneSizeInBitsFromFormat(vform) / 8; 528 } 529 530 int LaneSizeInBytesLog2FromFormat(VectorFormat vform) { 531 DCHECK_NE(vform, kFormatUndefined); 532 switch (vform) { 533 case kFormatB: 534 case kFormat8B: 535 case kFormat16B: 536 return 0; 537 case kFormatH: 538 case kFormat4H: 539 case kFormat8H: 540 return 1; 541 case kFormatS: 542 case kFormat2S: 543 case kFormat4S: 544 return 2; 545 case kFormatD: 546 case kFormat1D: 547 case kFormat2D: 548 return 3; 549 default: 550 UNREACHABLE(); 551 } 552 } 553 554 int LaneCountFromFormat(VectorFormat vform) { 555 DCHECK_NE(vform, kFormatUndefined); 556 switch (vform) { 557 case kFormat16B: 558 return 16; 559 case kFormat8B: 560 case kFormat8H: 561 return 8; 562 case kFormat4H: 563 case kFormat4S: 564 return 4; 565 case kFormat2S: 566 case kFormat2D: 567 return 2; 568 case kFormat1D: 569 case kFormatB: 570 case kFormatH: 571 case kFormatS: 572 case kFormatD: 573 return 1; 574 default: 575 UNREACHABLE(); 576 } 577 } 578 579 int MaxLaneCountFromFormat(VectorFormat vform) { 580 DCHECK_NE(vform, kFormatUndefined); 581 switch (vform) { 582 case kFormatB: 583 case kFormat8B: 584 case kFormat16B: 585 return 16; 586 case kFormatH: 587 case kFormat4H: 588 case kFormat8H: 589 return 8; 590 case kFormatS: 591 case kFormat2S: 592 case kFormat4S: 593 return 4; 594 case kFormatD: 595 case kFormat1D: 596 case kFormat2D: 597 return 2; 598 default: 599 UNREACHABLE(); 600 } 601 } 602 603 // Does 'vform' indicate a vector format or a scalar format? 604 bool IsVectorFormat(VectorFormat vform) { 605 DCHECK_NE(vform, kFormatUndefined); 606 switch (vform) { 607 case kFormatB: 608 case kFormatH: 609 case kFormatS: 610 case kFormatD: 611 return false; 612 default: 613 return true; 614 } 615 } 616 617 int64_t MaxIntFromFormat(VectorFormat vform) { 618 return INT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform)); 619 } 620 621 int64_t MinIntFromFormat(VectorFormat vform) { 622 return INT64_MIN >> (64 - LaneSizeInBitsFromFormat(vform)); 623 } 624 625 uint64_t MaxUintFromFormat(VectorFormat vform) { 626 return UINT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform)); 627 } 628 629 NEONFormatDecoder::NEONFormatDecoder(const Instruction* instr) { 630 instrbits_ = instr->InstructionBits(); 631 SetFormatMaps(IntegerFormatMap()); 632 } 633 634 NEONFormatDecoder::NEONFormatDecoder(const Instruction* instr, 635 const NEONFormatMap* format) { 636 instrbits_ = instr->InstructionBits(); 637 SetFormatMaps(format); 638 } 639 640 NEONFormatDecoder::NEONFormatDecoder(const Instruction* instr, 641 const NEONFormatMap* format0, 642 const NEONFormatMap* format1) { 643 instrbits_ = instr->InstructionBits(); 644 SetFormatMaps(format0, format1); 645 } 646 647 NEONFormatDecoder::NEONFormatDecoder(const Instruction* instr, 648 const NEONFormatMap* format0, 649 const NEONFormatMap* format1, 650 const NEONFormatMap* format2) { 651 instrbits_ = instr->InstructionBits(); 652 SetFormatMaps(format0, format1, format2); 653 } 654 655 void NEONFormatDecoder::SetFormatMaps(const NEONFormatMap* format0, 656 const NEONFormatMap* format1, 657 const NEONFormatMap* format2) { 658 DCHECK_NOT_NULL(format0); 659 formats_[0] = format0; 660 formats_[1] = (format1 == nullptr) ? formats_[0] : format1; 661 formats_[2] = (format2 == nullptr) ? formats_[1] : format2; 662 } 663 664 void NEONFormatDecoder::SetFormatMap(unsigned index, 665 const NEONFormatMap* format) { 666 DCHECK_LT(index, arraysize(formats_)); 667 DCHECK_NOT_NULL(format); 668 formats_[index] = format; 669 } 670 671 const char* NEONFormatDecoder::SubstitutePlaceholders(const char* string) { 672 return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder); 673 } 674 675 const char* NEONFormatDecoder::Substitute(const char* string, 676 SubstitutionMode mode0, 677 SubstitutionMode mode1, 678 SubstitutionMode mode2) { 679 snprintf(form_buffer_, sizeof(form_buffer_), string, GetSubstitute(0, mode0), 680 GetSubstitute(1, mode1), GetSubstitute(2, mode2)); 681 return form_buffer_; 682 } 683 684 const char* NEONFormatDecoder::Mnemonic(const char* mnemonic) { 685 if ((instrbits_ & NEON_Q) != 0) { 686 snprintf(mne_buffer_, sizeof(mne_buffer_), "%s2", mnemonic); 687 return mne_buffer_; 688 } 689 return mnemonic; 690 } 691 692 VectorFormat NEONFormatDecoder::GetVectorFormat(int format_index) { 693 return GetVectorFormat(formats_[format_index]); 694 } 695 696 VectorFormat NEONFormatDecoder::GetVectorFormat( 697 const NEONFormatMap* format_map) { 698 static const VectorFormat vform[] = { 699 kFormatUndefined, kFormat8B, kFormat16B, kFormat4H, kFormat8H, 700 kFormat2S, kFormat4S, kFormat1D, kFormat2D, kFormatB, 701 kFormatH, kFormatS, kFormatD}; 702 DCHECK_LT(GetNEONFormat(format_map), arraysize(vform)); 703 return vform[GetNEONFormat(format_map)]; 704 } 705 706 const char* NEONFormatDecoder::GetSubstitute(int index, SubstitutionMode mode) { 707 if (mode == kFormat) { 708 return NEONFormatAsString(GetNEONFormat(formats_[index])); 709 } 710 DCHECK_EQ(mode, kPlaceholder); 711 return NEONFormatAsPlaceholder(GetNEONFormat(formats_[index])); 712 } 713 714 NEONFormat NEONFormatDecoder::GetNEONFormat(const NEONFormatMap* format_map) { 715 return format_map->map[PickBits(format_map->bits)]; 716 } 717 718 const char* NEONFormatDecoder::NEONFormatAsString(NEONFormat format) { 719 static const char* formats[] = {"undefined", "8b", "16b", "4h", "8h", 720 "2s", "4s", "1d", "2d", "b", 721 "h", "s", "d"}; 722 DCHECK_LT(format, arraysize(formats)); 723 return formats[format]; 724 } 725 726 const char* NEONFormatDecoder::NEONFormatAsPlaceholder(NEONFormat format) { 727 DCHECK((format == NF_B) || (format == NF_H) || (format == NF_S) || 728 (format == NF_D) || (format == NF_UNDEF)); 729 static const char* formats[] = { 730 "undefined", "undefined", "undefined", "undefined", "undefined", 731 "undefined", "undefined", "undefined", "undefined", "'B", 732 "'H", "'S", "'D"}; 733 return formats[format]; 734 } 735 736 uint8_t NEONFormatDecoder::PickBits(const uint8_t bits[]) { 737 uint8_t result = 0; 738 for (unsigned b = 0; b < kNEONFormatMaxBits; b++) { 739 if (bits[b] == 0) break; 740 result <<= 1; 741 result |= ((instrbits_ & (1 << bits[b])) == 0) ? 0 : 1; 742 } 743 return result; 744 } 745 } // namespace internal 746 } // namespace v8 747 748 #endif // V8_TARGET_ARCH_ARM64 749