v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
instructions-arm64.h
Go to the documentation of this file.
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_ARM64_INSTRUCTIONS_ARM64_H_
29 #define V8_ARM64_INSTRUCTIONS_ARM64_H_
30 
31 #include "globals.h"
32 #include "utils.h"
33 #include "arm64/constants-arm64.h"
34 #include "arm64/utils-arm64.h"
35 
36 namespace v8 {
37 namespace internal {
38 
39 
40 // ISA constants. --------------------------------------------------------------
41 
42 typedef uint32_t Instr;
43 
44 // The following macros initialize a float/double variable with a bit pattern
45 // without using static initializers: If ARM64_DEFINE_FP_STATICS is defined, the
46 // symbol is defined as uint32_t/uint64_t initialized with the desired bit
47 // pattern. Otherwise, the same symbol is declared as an external float/double.
48 #if defined(ARM64_DEFINE_FP_STATICS)
49 #define DEFINE_FLOAT(name, value) extern const uint32_t name = value
50 #define DEFINE_DOUBLE(name, value) extern const uint64_t name = value
51 #else
52 #define DEFINE_FLOAT(name, value) extern const float name
53 #define DEFINE_DOUBLE(name, value) extern const double name
54 #endif // defined(ARM64_DEFINE_FP_STATICS)
55 
56 DEFINE_FLOAT(kFP32PositiveInfinity, 0x7f800000);
57 DEFINE_FLOAT(kFP32NegativeInfinity, 0xff800000);
58 DEFINE_DOUBLE(kFP64PositiveInfinity, 0x7ff0000000000000UL);
59 DEFINE_DOUBLE(kFP64NegativeInfinity, 0xfff0000000000000UL);
60 
61 // This value is a signalling NaN as both a double and as a float (taking the
62 // least-significant word).
63 DEFINE_DOUBLE(kFP64SignallingNaN, 0x7ff000007f800001);
64 DEFINE_FLOAT(kFP32SignallingNaN, 0x7f800001);
65 
66 // A similar value, but as a quiet NaN.
67 DEFINE_DOUBLE(kFP64QuietNaN, 0x7ff800007fc00001);
68 DEFINE_FLOAT(kFP32QuietNaN, 0x7fc00001);
69 
70 // The default NaN values (for FPCR.DN=1).
71 DEFINE_DOUBLE(kFP64DefaultNaN, 0x7ff8000000000000UL);
72 DEFINE_FLOAT(kFP32DefaultNaN, 0x7fc00000);
73 
74 #undef DEFINE_FLOAT
75 #undef DEFINE_DOUBLE
76 
77 
78 enum LSDataSize {
79  LSByte = 0,
81  LSWord = 2,
83 };
84 
86 
93 };
94 
95 enum AddrMode {
96  Offset,
97  PreIndex,
98  PostIndex
99 };
100 
102  // The first four values are encodable directly by FPCR<RMode>.
103  FPTieEven = 0x0,
106  FPZero = 0x3,
107 
108  // The final rounding mode is only available when explicitly specified by the
109  // instruction (such as with fcvta). It cannot be set in FPCR.
111 };
112 
113 enum Reg31Mode {
116 };
117 
118 // Instructions. ---------------------------------------------------------------
119 
120 class Instruction {
121  public:
123  return *reinterpret_cast<const Instr*>(this);
124  }
125 
127  *reinterpret_cast<Instr*>(this) = new_instr;
128  }
129 
130  int Bit(int pos) const {
131  return (InstructionBits() >> pos) & 1;
132  }
133 
134  uint32_t Bits(int msb, int lsb) const {
135  return unsigned_bitextract_32(msb, lsb, InstructionBits());
136  }
137 
138  int32_t SignedBits(int msb, int lsb) const {
139  int32_t bits = *(reinterpret_cast<const int32_t*>(this));
140  return signed_bitextract_32(msb, lsb, bits);
141  }
142 
143  Instr Mask(uint32_t mask) const {
144  return InstructionBits() & mask;
145  }
146 
147  V8_INLINE Instruction* following(int count = 1) {
148  return InstructionAtOffset(count * static_cast<int>(kInstructionSize));
149  }
150 
151  V8_INLINE Instruction* preceding(int count = 1) {
152  return following(-count);
153  }
154 
155  #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \
156  int64_t Name() const { return Func(HighBit, LowBit); }
158  #undef DEFINE_GETTER
159 
160  // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST),
161  // formed from ImmPCRelLo and ImmPCRelHi.
162  int ImmPCRel() const {
163  int const offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
164  int const width = ImmPCRelLo_width + ImmPCRelHi_width;
165  return signed_bitextract_32(width-1, 0, offset);
166  }
167 
168  uint64_t ImmLogical();
169  float ImmFP32();
170  double ImmFP64();
171 
173  return CalcLSPairDataSize(
174  static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
175  }
176 
177  // Helpers.
178  bool IsCondBranchImm() const {
180  }
181 
182  bool IsUncondBranchImm() const {
184  }
185 
186  bool IsCompareBranch() const {
188  }
189 
190  bool IsTestBranch() const {
192  }
193 
194  bool IsLdrLiteral() const {
196  }
197 
198  bool IsLdrLiteralX() const {
199  return Mask(LoadLiteralMask) == LDR_x_lit;
200  }
201 
202  bool IsPCRelAddressing() const {
204  }
205 
206  bool IsLogicalImmediate() const {
208  }
209 
210  bool IsAddSubImmediate() const {
212  }
213 
214  bool IsAddSubExtended() const {
216  }
217 
218  // Match any loads or stores, including pairs.
219  bool IsLoadOrStore() const {
221  }
222 
223  // Match any loads, including pairs.
224  bool IsLoad() const;
225  // Match any stores, including pairs.
226  bool IsStore() const;
227 
228  // Indicate whether Rd can be the stack pointer or the zero register. This
229  // does not check that the instruction actually has an Rd field.
230  Reg31Mode RdMode() const {
231  // The following instructions use csp or wsp as Rd:
232  // Add/sub (immediate) when not setting the flags.
233  // Add/sub (extended) when not setting the flags.
234  // Logical (immediate) when not setting the flags.
235  // Otherwise, r31 is the zero register.
236  if (IsAddSubImmediate() || IsAddSubExtended()) {
237  if (Mask(AddSubSetFlagsBit)) {
238  return Reg31IsZeroRegister;
239  } else {
240  return Reg31IsStackPointer;
241  }
242  }
243  if (IsLogicalImmediate()) {
244  // Of the logical (immediate) instructions, only ANDS (and its aliases)
245  // can set the flags. The others can all write into csp.
246  // Note that some logical operations are not available to
247  // immediate-operand instructions, so we have to combine two masks here.
249  return Reg31IsZeroRegister;
250  } else {
251  return Reg31IsStackPointer;
252  }
253  }
254  return Reg31IsZeroRegister;
255  }
256 
257  // Indicate whether Rn can be the stack pointer or the zero register. This
258  // does not check that the instruction actually has an Rn field.
259  Reg31Mode RnMode() const {
260  // The following instructions use csp or wsp as Rn:
261  // All loads and stores.
262  // Add/sub (immediate).
263  // Add/sub (extended).
264  // Otherwise, r31 is the zero register.
266  return Reg31IsStackPointer;
267  }
268  return Reg31IsZeroRegister;
269  }
270 
272  if (IsCondBranchImm()) {
273  return CondBranchType;
274  } else if (IsUncondBranchImm()) {
275  return UncondBranchType;
276  } else if (IsCompareBranch()) {
277  return CompareBranchType;
278  } else if (IsTestBranch()) {
279  return TestBranchType;
280  } else {
281  return UnknownBranchType;
282  }
283  }
284 
285  static int ImmBranchRangeBitwidth(ImmBranchType branch_type) {
286  switch (branch_type) {
287  case UncondBranchType:
288  return ImmUncondBranch_width;
289  case CondBranchType:
290  return ImmCondBranch_width;
291  case CompareBranchType:
292  return ImmCmpBranch_width;
293  case TestBranchType:
294  return ImmTestBranch_width;
295  default:
296  UNREACHABLE();
297  return 0;
298  }
299  }
300 
301  // The range of the branch instruction, expressed as 'instr +- range'.
302  static int32_t ImmBranchRange(ImmBranchType branch_type) {
303  return
304  (1 << (ImmBranchRangeBitwidth(branch_type) + kInstructionSizeLog2)) / 2 -
306  }
307 
308  int ImmBranch() const {
309  switch (BranchType()) {
310  case CondBranchType: return ImmCondBranch();
311  case UncondBranchType: return ImmUncondBranch();
312  case CompareBranchType: return ImmCmpBranch();
313  case TestBranchType: return ImmTestBranch();
314  default: UNREACHABLE();
315  }
316  return 0;
317  }
318 
321  }
322 
323  bool IsMovz() const {
324  return (Mask(MoveWideImmediateMask) == MOVZ_x) ||
326  }
327 
328  bool IsMovk() const {
329  return (Mask(MoveWideImmediateMask) == MOVK_x) ||
331  }
332 
333  bool IsMovn() const {
334  return (Mask(MoveWideImmediateMask) == MOVN_x) ||
336  }
337 
338  bool IsNop(int n) {
339  // A marking nop is an instruction
340  // mov r<n>, r<n>
341  // which is encoded as
342  // orr r<n>, xzr, r<n>
343  return (Mask(LogicalShiftedMask) == ORR_x) &&
344  (Rd() == Rm()) &&
345  (Rd() == n);
346  }
347 
348  // Find the PC offset encoded in this instruction. 'this' may be a branch or
349  // a PC-relative addressing instruction.
350  // The offset returned is unscaled.
351  ptrdiff_t ImmPCOffset();
352 
353  // Find the target of this instruction. 'this' may be a branch or a
354  // PC-relative addressing instruction.
356 
357  static bool IsValidImmPCOffset(ImmBranchType branch_type, int32_t offset);
359  // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
360  // a PC-relative addressing instruction.
361  void SetImmPCOffsetTarget(Instruction* target);
362  // Patch a literal load instruction to load from 'source'.
363  void SetImmLLiteral(Instruction* source);
364 
365  uint8_t* LiteralAddress() {
366  int offset = ImmLLiteral() << kLiteralEntrySizeLog2;
367  return reinterpret_cast<uint8_t*>(this) + offset;
368  }
369 
371 
373  int64_t offset,
375  Address addr = reinterpret_cast<Address>(this) + offset;
376  // The FUZZ_disasm test relies on no check being done.
378  return Cast(addr);
379  }
380 
381  template<typename T> V8_INLINE static Instruction* Cast(T src) {
382  return reinterpret_cast<Instruction*>(src);
383  }
384 
385  V8_INLINE ptrdiff_t DistanceTo(Instruction* target) {
386  return reinterpret_cast<Address>(target) - reinterpret_cast<Address>(this);
387  }
388 
389 
390  void SetPCRelImmTarget(Instruction* target);
391  void SetBranchImmTarget(Instruction* target);
392 };
393 
394 
395 // Where Instruction looks at instructions generated by the Assembler,
396 // InstructionSequence looks at instructions sequences generated by the
397 // MacroAssembler.
399  public:
400  static InstructionSequence* At(Address address) {
401  return reinterpret_cast<InstructionSequence*>(address);
402  }
403 
404  // Sequences generated by MacroAssembler::InlineData().
405  bool IsInlineData() const;
406  uint64_t InlineData() const;
407 };
408 
409 
410 // Simulator/Debugger debug instructions ---------------------------------------
411 // Each debug marker is represented by a HLT instruction. The immediate comment
412 // field in the instruction is used to identify the type of debug marker. Each
413 // marker encodes arguments in a different way, as described below.
414 
415 // Indicate to the Debugger that the instruction is a redirected call.
417 
418 // Represent unreachable code. This is used as a guard in parts of the code that
419 // should not be reachable, such as in data encoded inline in the instructions.
421 
422 // A pseudo 'printf' instruction. The arguments will be passed to the platform
423 // printf method.
425 // Parameters are stored in ARM64 registers as if the printf pseudo-instruction
426 // was a call to the real printf method:
427 //
428 // x0: The format string, then either of:
429 // x1-x7: Optional arguments.
430 // d0-d7: Optional arguments.
431 //
432 // Floating-point and integer arguments are passed in separate sets of
433 // registers in AAPCS64 (even for varargs functions), so it is not possible to
434 // determine the type of location of each arguments without some information
435 // about the values that were passed in. This information could be retrieved
436 // from the printf format string, but the format string is not trivial to
437 // parse so we encode the relevant information with the HLT instruction.
438 // - Type
439 // Either kRegister or kFPRegister, but stored as a uint32_t because there's
440 // no way to guarantee the size of the CPURegister::RegisterType enum.
441 const unsigned kPrintfTypeOffset = 1 * kInstructionSize;
442 const unsigned kPrintfLength = 2 * kInstructionSize;
443 
444 // A pseudo 'debug' instruction.
446 // Parameters are inlined in the code after a debug pseudo-instruction:
447 // - Debug code.
448 // - Debug parameters.
449 // - Debug message string. This is a NULL-terminated ASCII string, padded to
450 // kInstructionSize so that subsequent instructions are correctly aligned.
451 // - A kImmExceptionIsUnreachable marker, to catch accidental execution of the
452 // string data.
453 const unsigned kDebugCodeOffset = 1 * kInstructionSize;
456 
457 // Debug parameters.
458 // Used without a TRACE_ option, the Debugger will print the arguments only
459 // once. Otherwise TRACE_ENABLE and TRACE_DISABLE will enable or disable tracing
460 // before every instruction for the specified LOG_ parameters.
461 //
462 // TRACE_OVERRIDE enables the specified LOG_ parameters, and disabled any
463 // others that were not specified.
464 //
465 // For example:
466 //
467 // __ debug("print registers and fp registers", 0, LOG_REGS | LOG_FP_REGS);
468 // will print the registers and fp registers only once.
469 //
470 // __ debug("trace disasm", 1, TRACE_ENABLE | LOG_DISASM);
471 // starts disassembling the code.
472 //
473 // __ debug("trace rets", 2, TRACE_ENABLE | LOG_REGS);
474 // adds the general purpose registers to the trace.
475 //
476 // __ debug("stop regs", 3, TRACE_DISABLE | LOG_REGS);
477 // stops tracing the registers.
478 const unsigned kDebuggerTracingDirectivesMask = 3 << 6;
480  NO_PARAM = 0,
481  BREAK = 1 << 0,
482  LOG_DISASM = 1 << 1, // Use only with TRACE. Disassemble the code.
483  LOG_REGS = 1 << 2, // Log general purpose registers.
484  LOG_FP_REGS = 1 << 3, // Log floating-point registers.
485  LOG_SYS_REGS = 1 << 4, // Log the status flags.
486  LOG_WRITE = 1 << 5, // Log any memory write.
487 
490 
491  // Trace control.
492  TRACE_ENABLE = 1 << 6,
493  TRACE_DISABLE = 2 << 6,
494  TRACE_OVERRIDE = 3 << 6
495 };
496 
497 
498 } } // namespace v8::internal
499 
500 
501 #endif // V8_ARM64_INSTRUCTIONS_ARM64_H_
byte * Address
Definition: globals.h:186
const unsigned kInstructionSizeLog2
DEFINE_DOUBLE(kFP64PositiveInfinity, 0x7ff0000000000000UL)
int32_t SignedBits(int msb, int lsb) const
const unsigned kDebugMessageOffset
bool IsAddressAligned(Address addr, intptr_t alignment, int offset=0)
Definition: utils.h:217
const Instr kImmExceptionIsRedirectedCall
#define INSTRUCTION_FIELDS_LIST(V_)
bool IsBranchAndLinkToRegister() const
const unsigned kLiteralEntrySizeLog2
int int32_t
Definition: unicode.cc:47
DEFINE_FLOAT(kFP32PositiveInfinity, 0x7f800000)
Instr InstructionBits() const
V8_INLINE ptrdiff_t DistanceTo(Instruction *target)
void SetBranchImmTarget(Instruction *target)
#define ASSERT(condition)
Definition: checks.h:329
#define DEFINE_GETTER(Name, HighBit, LowBit, Func)
static bool IsValidImmPCOffset(ImmBranchType branch_type, int32_t offset)
V8_INLINE Instruction * InstructionAtOffset(int64_t offset, CheckAlignment check=CHECK_ALIGNMENT)
const unsigned kDebuggerTracingDirectivesMask
static V8_INLINE Instruction * Cast(T src)
V8_INLINE Instr InstructionBits() const
const Instr kImmExceptionIsPrintf
V8_INLINE Instruction * preceding(int count=1)
LSDataSize SizeLSPair() const
void SetImmPCOffsetTarget(Instruction *target)
uint32_t Bits(int msb, int lsb) const
#define UNREACHABLE()
Definition: checks.h:52
void SetPCRelImmTarget(Instruction *target)
const unsigned kPrintfLength
Instruction * ImmPCOffsetTarget()
void check(i::Vector< const uint8_t > string)
const unsigned kInstructionSize
const unsigned kDebugParamsOffset
int32_t signed_bitextract_32(int msb, int lsb, int32_t x)
Definition: utils.h:1092
#define T(name, string, precedence)
Definition: token.cc:48
V8_INLINE Instruction * following(int count=1)
const Instr kImmExceptionIsUnreachable
static int ImmBranchRangeBitwidth(ImmBranchType branch_type)
const unsigned kDebugCodeOffset
bool IsTargetInImmPCOffsetRange(Instruction *target)
static int32_t ImmBranchRange(ImmBranchType branch_type)
void SetImmLLiteral(Instruction *source)
const unsigned kPrintfTypeOffset
V8_INLINE void SetInstructionBits(Instr new_instr)
LSDataSize CalcLSPairDataSize(LoadStorePairOp op)
uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x)
Definition: utils.h:1084
ImmBranchType BranchType() const
const Instr kImmExceptionIsDebug
#define V8_INLINE
Definition: v8config.h:316
static InstructionSequence * At(Address address)
Instr Mask(uint32_t mask) const