| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_ARM64_INSTRUCTIONS_ARM64_H_ | 5 #ifndef V8_ARM64_INSTRUCTIONS_ARM64_H_ |
| 6 #define V8_ARM64_INSTRUCTIONS_ARM64_H_ | 6 #define V8_ARM64_INSTRUCTIONS_ARM64_H_ |
| 7 | 7 |
| 8 #include "src/arm64/constants-arm64.h" | 8 #include "src/arm64/constants-arm64.h" |
| 9 #include "src/arm64/utils-arm64.h" | 9 #include "src/arm64/utils-arm64.h" |
| 10 #include "src/assembler.h" | 10 #include "src/assembler.h" |
| 11 #include "src/globals.h" | 11 #include "src/globals.h" |
| 12 #include "src/utils.h" | 12 #include "src/utils.h" |
| 13 | 13 |
| 14 namespace v8 { | 14 namespace v8 { |
| 15 namespace internal { | 15 namespace internal { |
| 16 | 16 |
| 17 // ISA constants. -------------------------------------------------------------- | 17 // ISA constants. -------------------------------------------------------------- |
| 18 | 18 |
| 19 typedef uint32_t Instr; | 19 typedef uint32_t Instr; |
| 20 | 20 |
| 21 // The following macros initialize a float/double variable with a bit pattern | 21 // The following macros initialize a float/double variable with a bit pattern |
| 22 // without using static initializers: If ARM64_DEFINE_FP_STATICS is defined, the | 22 // without using static initializers: If ARM64_DEFINE_FP_STATICS is defined, the |
| 23 // symbol is defined as uint32_t/uint64_t initialized with the desired bit | 23 // symbol is defined as uint32_t/uint64_t initialized with the desired bit |
| 24 // pattern. Otherwise, the same symbol is declared as an external float/double. | 24 // pattern. Otherwise, the same symbol is declared as an external float/double. |
| 25 #if defined(ARM64_DEFINE_FP_STATICS) | 25 #if defined(ARM64_DEFINE_FP_STATICS) |
| 26 #define DEFINE_FLOAT16(name, value) extern const uint16_t name = value | |
| 27 #define DEFINE_FLOAT(name, value) extern const uint32_t name = value | 26 #define DEFINE_FLOAT(name, value) extern const uint32_t name = value |
| 28 #define DEFINE_DOUBLE(name, value) extern const uint64_t name = value | 27 #define DEFINE_DOUBLE(name, value) extern const uint64_t name = value |
| 29 #else | 28 #else |
| 30 #define DEFINE_FLOAT16(name, value) extern const float16 name | |
| 31 #define DEFINE_FLOAT(name, value) extern const float name | 29 #define DEFINE_FLOAT(name, value) extern const float name |
| 32 #define DEFINE_DOUBLE(name, value) extern const double name | 30 #define DEFINE_DOUBLE(name, value) extern const double name |
| 33 #endif // defined(ARM64_DEFINE_FP_STATICS) | 31 #endif // defined(ARM64_DEFINE_FP_STATICS) |
| 34 | 32 |
| 35 DEFINE_FLOAT16(kFP16PositiveInfinity, 0x7c00); | |
| 36 DEFINE_FLOAT16(kFP16NegativeInfinity, 0xfc00); | |
| 37 DEFINE_FLOAT(kFP32PositiveInfinity, 0x7f800000); | 33 DEFINE_FLOAT(kFP32PositiveInfinity, 0x7f800000); |
| 38 DEFINE_FLOAT(kFP32NegativeInfinity, 0xff800000); | 34 DEFINE_FLOAT(kFP32NegativeInfinity, 0xff800000); |
| 39 DEFINE_DOUBLE(kFP64PositiveInfinity, 0x7ff0000000000000UL); | 35 DEFINE_DOUBLE(kFP64PositiveInfinity, 0x7ff0000000000000UL); |
| 40 DEFINE_DOUBLE(kFP64NegativeInfinity, 0xfff0000000000000UL); | 36 DEFINE_DOUBLE(kFP64NegativeInfinity, 0xfff0000000000000UL); |
| 41 | 37 |
| 42 // This value is a signalling NaN as both a double and as a float (taking the | 38 // This value is a signalling NaN as both a double and as a float (taking the |
| 43 // least-significant word). | 39 // least-significant word). |
| 44 DEFINE_DOUBLE(kFP64SignallingNaN, 0x7ff000007f800001); | 40 DEFINE_DOUBLE(kFP64SignallingNaN, 0x7ff000007f800001); |
| 45 DEFINE_FLOAT(kFP32SignallingNaN, 0x7f800001); | 41 DEFINE_FLOAT(kFP32SignallingNaN, 0x7f800001); |
| 46 | 42 |
| 47 // A similar value, but as a quiet NaN. | 43 // A similar value, but as a quiet NaN. |
| 48 DEFINE_DOUBLE(kFP64QuietNaN, 0x7ff800007fc00001); | 44 DEFINE_DOUBLE(kFP64QuietNaN, 0x7ff800007fc00001); |
| 49 DEFINE_FLOAT(kFP32QuietNaN, 0x7fc00001); | 45 DEFINE_FLOAT(kFP32QuietNaN, 0x7fc00001); |
| 50 | 46 |
| 51 // The default NaN values (for FPCR.DN=1). | 47 // The default NaN values (for FPCR.DN=1). |
| 52 DEFINE_DOUBLE(kFP64DefaultNaN, 0x7ff8000000000000UL); | 48 DEFINE_DOUBLE(kFP64DefaultNaN, 0x7ff8000000000000UL); |
| 53 DEFINE_FLOAT(kFP32DefaultNaN, 0x7fc00000); | 49 DEFINE_FLOAT(kFP32DefaultNaN, 0x7fc00000); |
| 54 DEFINE_FLOAT16(kFP16DefaultNaN, 0x7e00); | |
| 55 | 50 |
| 56 #undef DEFINE_FLOAT16 | |
| 57 #undef DEFINE_FLOAT | 51 #undef DEFINE_FLOAT |
| 58 #undef DEFINE_DOUBLE | 52 #undef DEFINE_DOUBLE |
| 59 | 53 |
| 60 unsigned CalcLSDataSize(LoadStoreOp op); | 54 |
| 61 unsigned CalcLSPairDataSize(LoadStorePairOp op); | 55 enum LSDataSize { |
| 56 LSByte = 0, |
| 57 LSHalfword = 1, |
| 58 LSWord = 2, |
| 59 LSDoubleWord = 3 |
| 60 }; |
| 61 |
| 62 LSDataSize CalcLSPairDataSize(LoadStorePairOp op); |
| 62 | 63 |
| 63 enum ImmBranchType { | 64 enum ImmBranchType { |
| 64 UnknownBranchType = 0, | 65 UnknownBranchType = 0, |
| 65 CondBranchType = 1, | 66 CondBranchType = 1, |
| 66 UncondBranchType = 2, | 67 UncondBranchType = 2, |
| 67 CompareBranchType = 3, | 68 CompareBranchType = 3, |
| 68 TestBranchType = 4 | 69 TestBranchType = 4 |
| 69 }; | 70 }; |
| 70 | 71 |
| 71 enum AddrMode { | 72 enum AddrMode { |
| 72 Offset, | 73 Offset, |
| 73 PreIndex, | 74 PreIndex, |
| 74 PostIndex | 75 PostIndex |
| 75 }; | 76 }; |
| 76 | 77 |
| 77 enum FPRounding { | 78 enum FPRounding { |
| 78 // The first four values are encodable directly by FPCR<RMode>. | 79 // The first four values are encodable directly by FPCR<RMode>. |
| 79 FPTieEven = 0x0, | 80 FPTieEven = 0x0, |
| 80 FPPositiveInfinity = 0x1, | 81 FPPositiveInfinity = 0x1, |
| 81 FPNegativeInfinity = 0x2, | 82 FPNegativeInfinity = 0x2, |
| 82 FPZero = 0x3, | 83 FPZero = 0x3, |
| 83 | 84 |
| 84 // The final rounding modes are only available when explicitly specified by | 85 // The final rounding mode is only available when explicitly specified by the |
| 85 // the instruction (such as with fcvta). They cannot be set in FPCR. | 86 // instruction (such as with fcvta). It cannot be set in FPCR. |
| 86 FPTieAway, | 87 FPTieAway |
| 87 FPRoundOdd | |
| 88 }; | 88 }; |
| 89 | 89 |
| 90 enum Reg31Mode { | 90 enum Reg31Mode { |
| 91 Reg31IsStackPointer, | 91 Reg31IsStackPointer, |
| 92 Reg31IsZeroRegister | 92 Reg31IsZeroRegister |
| 93 }; | 93 }; |
| 94 | 94 |
| 95 // Instructions. --------------------------------------------------------------- | 95 // Instructions. --------------------------------------------------------------- |
| 96 | 96 |
| 97 class Instruction { | 97 class Instruction { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST), | 145 // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST), |
| 146 // formed from ImmPCRelLo and ImmPCRelHi. | 146 // formed from ImmPCRelLo and ImmPCRelHi. |
| 147 int ImmPCRel() const { | 147 int ImmPCRel() const { |
| 148 DCHECK(IsPCRelAddressing()); | 148 DCHECK(IsPCRelAddressing()); |
| 149 int offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo()); | 149 int offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo()); |
| 150 int width = ImmPCRelLo_width + ImmPCRelHi_width; | 150 int width = ImmPCRelLo_width + ImmPCRelHi_width; |
| 151 return signed_bitextract_32(width - 1, 0, offset); | 151 return signed_bitextract_32(width - 1, 0, offset); |
| 152 } | 152 } |
| 153 | 153 |
| 154 uint64_t ImmLogical(); | 154 uint64_t ImmLogical(); |
| 155 unsigned ImmNEONabcdefgh() const; | |
| 156 float ImmFP32(); | 155 float ImmFP32(); |
| 157 double ImmFP64(); | 156 double ImmFP64(); |
| 158 float ImmNEONFP32() const; | |
| 159 double ImmNEONFP64() const; | |
| 160 | 157 |
| 161 unsigned SizeLS() const { | 158 LSDataSize SizeLSPair() const { |
| 162 return CalcLSDataSize(static_cast<LoadStoreOp>(Mask(LoadStoreMask))); | |
| 163 } | |
| 164 | |
| 165 unsigned SizeLSPair() const { | |
| 166 return CalcLSPairDataSize( | 159 return CalcLSPairDataSize( |
| 167 static_cast<LoadStorePairOp>(Mask(LoadStorePairMask))); | 160 static_cast<LoadStorePairOp>(Mask(LoadStorePairMask))); |
| 168 } | 161 } |
| 169 | 162 |
| 170 int NEONLSIndex(int access_size_shift) const { | |
| 171 int q = NEONQ(); | |
| 172 int s = NEONS(); | |
| 173 int size = NEONLSSize(); | |
| 174 int index = (q << 3) | (s << 2) | size; | |
| 175 return index >> access_size_shift; | |
| 176 } | |
| 177 | |
| 178 // Helpers. | 163 // Helpers. |
| 179 bool IsCondBranchImm() const { | 164 bool IsCondBranchImm() const { |
| 180 return Mask(ConditionalBranchFMask) == ConditionalBranchFixed; | 165 return Mask(ConditionalBranchFMask) == ConditionalBranchFixed; |
| 181 } | 166 } |
| 182 | 167 |
| 183 bool IsUncondBranchImm() const { | 168 bool IsUncondBranchImm() const { |
| 184 return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed; | 169 return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed; |
| 185 } | 170 } |
| 186 | 171 |
| 187 bool IsCompareBranch() const { | 172 bool IsCompareBranch() const { |
| 188 return Mask(CompareBranchFMask) == CompareBranchFixed; | 173 return Mask(CompareBranchFMask) == CompareBranchFixed; |
| 189 } | 174 } |
| 190 | 175 |
| 191 bool IsTestBranch() const { | 176 bool IsTestBranch() const { |
| 192 return Mask(TestBranchFMask) == TestBranchFixed; | 177 return Mask(TestBranchFMask) == TestBranchFixed; |
| 193 } | 178 } |
| 194 | 179 |
| 195 bool IsImmBranch() const { | 180 bool IsImmBranch() const { |
| 196 return BranchType() != UnknownBranchType; | 181 return BranchType() != UnknownBranchType; |
| 197 } | 182 } |
| 198 | 183 |
| 199 static float Imm8ToFP32(uint32_t imm8) { | |
| 200 // Imm8: abcdefgh (8 bits) | |
| 201 // Single: aBbb.bbbc.defg.h000.0000.0000.0000.0000 (32 bits) | |
| 202 // where B is b ^ 1 | |
| 203 uint32_t bits = imm8; | |
| 204 uint32_t bit7 = (bits >> 7) & 0x1; | |
| 205 uint32_t bit6 = (bits >> 6) & 0x1; | |
| 206 uint32_t bit5_to_0 = bits & 0x3f; | |
| 207 uint32_t result = (bit7 << 31) | ((32 - bit6) << 25) | (bit5_to_0 << 19); | |
| 208 | |
| 209 return bit_cast<float>(result); | |
| 210 } | |
| 211 | |
| 212 static double Imm8ToFP64(uint32_t imm8) { | |
| 213 // Imm8: abcdefgh (8 bits) | |
| 214 // Double: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 | |
| 215 // 0000.0000.0000.0000.0000.0000.0000.0000 (64 bits) | |
| 216 // where B is b ^ 1 | |
| 217 uint32_t bits = imm8; | |
| 218 uint64_t bit7 = (bits >> 7) & 0x1; | |
| 219 uint64_t bit6 = (bits >> 6) & 0x1; | |
| 220 uint64_t bit5_to_0 = bits & 0x3f; | |
| 221 uint64_t result = (bit7 << 63) | ((256 - bit6) << 54) | (bit5_to_0 << 48); | |
| 222 | |
| 223 return bit_cast<double>(result); | |
| 224 } | |
| 225 | |
| 226 bool IsLdrLiteral() const { | 184 bool IsLdrLiteral() const { |
| 227 return Mask(LoadLiteralFMask) == LoadLiteralFixed; | 185 return Mask(LoadLiteralFMask) == LoadLiteralFixed; |
| 228 } | 186 } |
| 229 | 187 |
| 230 bool IsLdrLiteralX() const { | 188 bool IsLdrLiteralX() const { |
| 231 return Mask(LoadLiteralMask) == LDR_x_lit; | 189 return Mask(LoadLiteralMask) == LDR_x_lit; |
| 232 } | 190 } |
| 233 | 191 |
| 234 bool IsPCRelAddressing() const { | 192 bool IsPCRelAddressing() const { |
| 235 return Mask(PCRelAddressingFMask) == PCRelAddressingFixed; | 193 return Mask(PCRelAddressingFMask) == PCRelAddressingFixed; |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 } | 410 } |
| 453 | 411 |
| 454 | 412 |
| 455 static const int ImmPCRelRangeBitwidth = 21; | 413 static const int ImmPCRelRangeBitwidth = 21; |
| 456 static bool IsValidPCRelOffset(ptrdiff_t offset) { return is_int21(offset); } | 414 static bool IsValidPCRelOffset(ptrdiff_t offset) { return is_int21(offset); } |
| 457 void SetPCRelImmTarget(AssemblerBase::IsolateData isolate_data, | 415 void SetPCRelImmTarget(AssemblerBase::IsolateData isolate_data, |
| 458 Instruction* target); | 416 Instruction* target); |
| 459 void SetBranchImmTarget(Instruction* target); | 417 void SetBranchImmTarget(Instruction* target); |
| 460 }; | 418 }; |
| 461 | 419 |
| 462 // Functions for handling NEON vector format information. | |
| 463 enum VectorFormat { | |
| 464 kFormatUndefined = 0xffffffff, | |
| 465 kFormat8B = NEON_8B, | |
| 466 kFormat16B = NEON_16B, | |
| 467 kFormat4H = NEON_4H, | |
| 468 kFormat8H = NEON_8H, | |
| 469 kFormat2S = NEON_2S, | |
| 470 kFormat4S = NEON_4S, | |
| 471 kFormat1D = NEON_1D, | |
| 472 kFormat2D = NEON_2D, | |
| 473 | |
| 474 // Scalar formats. We add the scalar bit to distinguish between scalar and | |
| 475 // vector enumerations; the bit is always set in the encoding of scalar ops | |
| 476 // and always clear for vector ops. Although kFormatD and kFormat1D appear | |
| 477 // to be the same, their meaning is subtly different. The first is a scalar | |
| 478 // operation, the second a vector operation that only affects one lane. | |
| 479 kFormatB = NEON_B | NEONScalar, | |
| 480 kFormatH = NEON_H | NEONScalar, | |
| 481 kFormatS = NEON_S | NEONScalar, | |
| 482 kFormatD = NEON_D | NEONScalar | |
| 483 }; | |
| 484 | |
| 485 VectorFormat VectorFormatHalfWidth(VectorFormat vform); | |
| 486 VectorFormat VectorFormatDoubleWidth(VectorFormat vform); | |
| 487 VectorFormat VectorFormatDoubleLanes(VectorFormat vform); | |
| 488 VectorFormat VectorFormatHalfLanes(VectorFormat vform); | |
| 489 VectorFormat ScalarFormatFromLaneSize(int lanesize); | |
| 490 VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform); | |
| 491 VectorFormat VectorFormatFillQ(VectorFormat vform); | |
| 492 VectorFormat ScalarFormatFromFormat(VectorFormat vform); | |
| 493 unsigned RegisterSizeInBitsFromFormat(VectorFormat vform); | |
| 494 unsigned RegisterSizeInBytesFromFormat(VectorFormat vform); | |
| 495 int LaneSizeInBytesFromFormat(VectorFormat vform); | |
| 496 unsigned LaneSizeInBitsFromFormat(VectorFormat vform); | |
| 497 int LaneSizeInBytesLog2FromFormat(VectorFormat vform); | |
| 498 int LaneCountFromFormat(VectorFormat vform); | |
| 499 int MaxLaneCountFromFormat(VectorFormat vform); | |
| 500 bool IsVectorFormat(VectorFormat vform); | |
| 501 int64_t MaxIntFromFormat(VectorFormat vform); | |
| 502 int64_t MinIntFromFormat(VectorFormat vform); | |
| 503 uint64_t MaxUintFromFormat(VectorFormat vform); | |
| 504 | 420 |
| 505 // Where Instruction looks at instructions generated by the Assembler, | 421 // Where Instruction looks at instructions generated by the Assembler, |
| 506 // InstructionSequence looks at instructions sequences generated by the | 422 // InstructionSequence looks at instructions sequences generated by the |
| 507 // MacroAssembler. | 423 // MacroAssembler. |
| 508 class InstructionSequence : public Instruction { | 424 class InstructionSequence : public Instruction { |
| 509 public: | 425 public: |
| 510 static InstructionSequence* At(Address address) { | 426 static InstructionSequence* At(Address address) { |
| 511 return reinterpret_cast<InstructionSequence*>(address); | 427 return reinterpret_cast<InstructionSequence*>(address); |
| 512 } | 428 } |
| 513 | 429 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 581 // Debug parameters. | 497 // Debug parameters. |
| 582 // Used without a TRACE_ option, the Debugger will print the arguments only | 498 // Used without a TRACE_ option, the Debugger will print the arguments only |
| 583 // once. Otherwise TRACE_ENABLE and TRACE_DISABLE will enable or disable tracing | 499 // once. Otherwise TRACE_ENABLE and TRACE_DISABLE will enable or disable tracing |
| 584 // before every instruction for the specified LOG_ parameters. | 500 // before every instruction for the specified LOG_ parameters. |
| 585 // | 501 // |
| 586 // TRACE_OVERRIDE enables the specified LOG_ parameters, and disabled any | 502 // TRACE_OVERRIDE enables the specified LOG_ parameters, and disabled any |
| 587 // others that were not specified. | 503 // others that were not specified. |
| 588 // | 504 // |
| 589 // For example: | 505 // For example: |
| 590 // | 506 // |
| 591 // __ debug("print registers and fp registers", 0, LOG_REGS | LOG_VREGS); | 507 // __ debug("print registers and fp registers", 0, LOG_REGS | LOG_FP_REGS); |
| 592 // will print the registers and fp registers only once. | 508 // will print the registers and fp registers only once. |
| 593 // | 509 // |
| 594 // __ debug("trace disasm", 1, TRACE_ENABLE | LOG_DISASM); | 510 // __ debug("trace disasm", 1, TRACE_ENABLE | LOG_DISASM); |
| 595 // starts disassembling the code. | 511 // starts disassembling the code. |
| 596 // | 512 // |
| 597 // __ debug("trace rets", 2, TRACE_ENABLE | LOG_REGS); | 513 // __ debug("trace rets", 2, TRACE_ENABLE | LOG_REGS); |
| 598 // adds the general purpose registers to the trace. | 514 // adds the general purpose registers to the trace. |
| 599 // | 515 // |
| 600 // __ debug("stop regs", 3, TRACE_DISABLE | LOG_REGS); | 516 // __ debug("stop regs", 3, TRACE_DISABLE | LOG_REGS); |
| 601 // stops tracing the registers. | 517 // stops tracing the registers. |
| 602 const unsigned kDebuggerTracingDirectivesMask = 3 << 6; | 518 const unsigned kDebuggerTracingDirectivesMask = 3 << 6; |
| 603 enum DebugParameters { | 519 enum DebugParameters { |
| 604 NO_PARAM = 0, | 520 NO_PARAM = 0, |
| 605 BREAK = 1 << 0, | 521 BREAK = 1 << 0, |
| 606 LOG_DISASM = 1 << 1, // Use only with TRACE. Disassemble the code. | 522 LOG_DISASM = 1 << 1, // Use only with TRACE. Disassemble the code. |
| 607 LOG_REGS = 1 << 2, // Log general purpose registers. | 523 LOG_REGS = 1 << 2, // Log general purpose registers. |
| 608 LOG_VREGS = 1 << 3, // Log NEON and floating-point registers. | 524 LOG_FP_REGS = 1 << 3, // Log floating-point registers. |
| 609 LOG_SYS_REGS = 1 << 4, // Log the status flags. | 525 LOG_SYS_REGS = 1 << 4, // Log the status flags. |
| 610 LOG_WRITE = 1 << 5, // Log any memory write. | 526 LOG_WRITE = 1 << 5, // Log any memory write. |
| 611 | 527 |
| 612 LOG_NONE = 0, | 528 LOG_STATE = LOG_REGS | LOG_FP_REGS | LOG_SYS_REGS, |
| 613 LOG_STATE = LOG_REGS | LOG_VREGS | LOG_SYS_REGS, | 529 LOG_ALL = LOG_DISASM | LOG_STATE | LOG_WRITE, |
| 614 LOG_ALL = LOG_DISASM | LOG_STATE | LOG_WRITE, | |
| 615 | 530 |
| 616 // Trace control. | 531 // Trace control. |
| 617 TRACE_ENABLE = 1 << 6, | 532 TRACE_ENABLE = 1 << 6, |
| 618 TRACE_DISABLE = 2 << 6, | 533 TRACE_DISABLE = 2 << 6, |
| 619 TRACE_OVERRIDE = 3 << 6 | 534 TRACE_OVERRIDE = 3 << 6 |
| 620 }; | 535 }; |
| 621 | 536 |
| 622 enum NEONFormat { | |
| 623 NF_UNDEF = 0, | |
| 624 NF_8B = 1, | |
| 625 NF_16B = 2, | |
| 626 NF_4H = 3, | |
| 627 NF_8H = 4, | |
| 628 NF_2S = 5, | |
| 629 NF_4S = 6, | |
| 630 NF_1D = 7, | |
| 631 NF_2D = 8, | |
| 632 NF_B = 9, | |
| 633 NF_H = 10, | |
| 634 NF_S = 11, | |
| 635 NF_D = 12 | |
| 636 }; | |
| 637 | 537 |
| 638 static const unsigned kNEONFormatMaxBits = 6; | |
| 639 | |
| 640 struct NEONFormatMap { | |
| 641 // The bit positions in the instruction to consider. | |
| 642 uint8_t bits[kNEONFormatMaxBits]; | |
| 643 | |
| 644 // Mapping from concatenated bits to format. | |
| 645 NEONFormat map[1 << kNEONFormatMaxBits]; | |
| 646 }; | |
| 647 | |
| 648 class NEONFormatDecoder { | |
| 649 public: | |
| 650 enum SubstitutionMode { kPlaceholder, kFormat }; | |
| 651 | |
| 652 // Construct a format decoder with increasingly specific format maps for each | |
| 653 // substitution. If no format map is specified, the default is the integer | |
| 654 // format map. | |
| 655 explicit NEONFormatDecoder(const Instruction* instr); | |
| 656 NEONFormatDecoder(const Instruction* instr, const NEONFormatMap* format); | |
| 657 NEONFormatDecoder(const Instruction* instr, const NEONFormatMap* format0, | |
| 658 const NEONFormatMap* format1); | |
| 659 NEONFormatDecoder(const Instruction* instr, const NEONFormatMap* format0, | |
| 660 const NEONFormatMap* format1, const NEONFormatMap* format2); | |
| 661 | |
| 662 // Set the format mapping for all or individual substitutions. | |
| 663 void SetFormatMaps(const NEONFormatMap* format0, | |
| 664 const NEONFormatMap* format1 = NULL, | |
| 665 const NEONFormatMap* format2 = NULL); | |
| 666 void SetFormatMap(unsigned index, const NEONFormatMap* format); | |
| 667 | |
| 668 // Substitute %s in the input string with the placeholder string for each | |
| 669 // register, ie. "'B", "'H", etc. | |
| 670 const char* SubstitutePlaceholders(const char* string); | |
| 671 | |
| 672 // Substitute %s in the input string with a new string based on the | |
| 673 // substitution mode. | |
| 674 const char* Substitute(const char* string, SubstitutionMode mode0 = kFormat, | |
| 675 SubstitutionMode mode1 = kFormat, | |
| 676 SubstitutionMode mode2 = kFormat); | |
| 677 | |
| 678 // Append a "2" to a mnemonic string based of the state of the Q bit. | |
| 679 const char* Mnemonic(const char* mnemonic); | |
| 680 | |
| 681 VectorFormat GetVectorFormat(int format_index = 0); | |
| 682 VectorFormat GetVectorFormat(const NEONFormatMap* format_map); | |
| 683 | |
| 684 // Built in mappings for common cases. | |
| 685 | |
| 686 // The integer format map uses three bits (Q, size<1:0>) to encode the | |
| 687 // "standard" set of NEON integer vector formats. | |
| 688 static const NEONFormatMap* IntegerFormatMap() { | |
| 689 static const NEONFormatMap map = { | |
| 690 {23, 22, 30}, | |
| 691 {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_2D}}; | |
| 692 return ↦ | |
| 693 } | |
| 694 | |
| 695 // The long integer format map uses two bits (size<1:0>) to encode the | |
| 696 // long set of NEON integer vector formats. These are used in narrow, wide | |
| 697 // and long operations. | |
| 698 static const NEONFormatMap* LongIntegerFormatMap() { | |
| 699 static const NEONFormatMap map = {{23, 22}, {NF_8H, NF_4S, NF_2D}}; | |
| 700 return ↦ | |
| 701 } | |
| 702 | |
| 703 // The FP format map uses two bits (Q, size<0>) to encode the NEON FP vector | |
| 704 // formats: NF_2S, NF_4S, NF_2D. | |
| 705 static const NEONFormatMap* FPFormatMap() { | |
| 706 // The FP format map assumes two bits (Q, size<0>) are used to encode the | |
| 707 // NEON FP vector formats: NF_2S, NF_4S, NF_2D. | |
| 708 static const NEONFormatMap map = {{22, 30}, | |
| 709 {NF_2S, NF_4S, NF_UNDEF, NF_2D}}; | |
| 710 return ↦ | |
| 711 } | |
| 712 | |
| 713 // The load/store format map uses three bits (Q, 11, 10) to encode the | |
| 714 // set of NEON vector formats. | |
| 715 static const NEONFormatMap* LoadStoreFormatMap() { | |
| 716 static const NEONFormatMap map = { | |
| 717 {11, 10, 30}, | |
| 718 {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}}; | |
| 719 return ↦ | |
| 720 } | |
| 721 | |
| 722 // The logical format map uses one bit (Q) to encode the NEON vector format: | |
| 723 // NF_8B, NF_16B. | |
| 724 static const NEONFormatMap* LogicalFormatMap() { | |
| 725 static const NEONFormatMap map = {{30}, {NF_8B, NF_16B}}; | |
| 726 return ↦ | |
| 727 } | |
| 728 | |
| 729 // The triangular format map uses between two and five bits to encode the NEON | |
| 730 // vector format: | |
| 731 // xxx10->8B, xxx11->16B, xx100->4H, xx101->8H | |
| 732 // x1000->2S, x1001->4S, 10001->2D, all others undefined. | |
| 733 static const NEONFormatMap* TriangularFormatMap() { | |
| 734 static const NEONFormatMap map = { | |
| 735 {19, 18, 17, 16, 30}, | |
| 736 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, | |
| 737 NF_2S, NF_4S, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, | |
| 738 NF_UNDEF, NF_2D, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, | |
| 739 NF_2S, NF_4S, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B}}; | |
| 740 return ↦ | |
| 741 } | |
| 742 | |
| 743 // The scalar format map uses two bits (size<1:0>) to encode the NEON scalar | |
| 744 // formats: NF_B, NF_H, NF_S, NF_D. | |
| 745 static const NEONFormatMap* ScalarFormatMap() { | |
| 746 static const NEONFormatMap map = {{23, 22}, {NF_B, NF_H, NF_S, NF_D}}; | |
| 747 return ↦ | |
| 748 } | |
| 749 | |
| 750 // The long scalar format map uses two bits (size<1:0>) to encode the longer | |
| 751 // NEON scalar formats: NF_H, NF_S, NF_D. | |
| 752 static const NEONFormatMap* LongScalarFormatMap() { | |
| 753 static const NEONFormatMap map = {{23, 22}, {NF_H, NF_S, NF_D}}; | |
| 754 return ↦ | |
| 755 } | |
| 756 | |
| 757 // The FP scalar format map assumes one bit (size<0>) is used to encode the | |
| 758 // NEON FP scalar formats: NF_S, NF_D. | |
| 759 static const NEONFormatMap* FPScalarFormatMap() { | |
| 760 static const NEONFormatMap map = {{22}, {NF_S, NF_D}}; | |
| 761 return ↦ | |
| 762 } | |
| 763 | |
| 764 // The triangular scalar format map uses between one and four bits to encode | |
| 765 // the NEON FP scalar formats: | |
| 766 // xxx1->B, xx10->H, x100->S, 1000->D, all others undefined. | |
| 767 static const NEONFormatMap* TriangularScalarFormatMap() { | |
| 768 static const NEONFormatMap map = { | |
| 769 {19, 18, 17, 16}, | |
| 770 {NF_UNDEF, NF_B, NF_H, NF_B, NF_S, NF_B, NF_H, NF_B, NF_D, NF_B, NF_H, | |
| 771 NF_B, NF_S, NF_B, NF_H, NF_B}}; | |
| 772 return ↦ | |
| 773 } | |
| 774 | |
| 775 private: | |
| 776 // Get a pointer to a string that represents the format or placeholder for | |
| 777 // the specified substitution index, based on the format map and instruction. | |
| 778 const char* GetSubstitute(int index, SubstitutionMode mode); | |
| 779 | |
| 780 // Get the NEONFormat enumerated value for bits obtained from the | |
| 781 // instruction based on the specified format mapping. | |
| 782 NEONFormat GetNEONFormat(const NEONFormatMap* format_map); | |
| 783 | |
| 784 // Convert a NEONFormat into a string. | |
| 785 static const char* NEONFormatAsString(NEONFormat format); | |
| 786 | |
| 787 // Convert a NEONFormat into a register placeholder string. | |
| 788 static const char* NEONFormatAsPlaceholder(NEONFormat format); | |
| 789 | |
| 790 // Select bits from instrbits_ defined by the bits array, concatenate them, | |
| 791 // and return the value. | |
| 792 uint8_t PickBits(const uint8_t bits[]); | |
| 793 | |
| 794 Instr instrbits_; | |
| 795 const NEONFormatMap* formats_[3]; | |
| 796 char form_buffer_[64]; | |
| 797 char mne_buffer_[16]; | |
| 798 }; | |
| 799 } // namespace internal | 538 } // namespace internal |
| 800 } // namespace v8 | 539 } // namespace v8 |
| 801 | 540 |
| 802 | 541 |
| 803 #endif // V8_ARM64_INSTRUCTIONS_ARM64_H_ | 542 #endif // V8_ARM64_INSTRUCTIONS_ARM64_H_ |
| OLD | NEW |