V8 Project
instructions-arm64.h
Go to the documentation of this file.
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 #ifndef V8_ARM64_INSTRUCTIONS_ARM64_H_
6 #define V8_ARM64_INSTRUCTIONS_ARM64_H_
7 
10 #include "src/globals.h"
11 #include "src/utils.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 
17 // ISA constants. --------------------------------------------------------------
18 
19 typedef uint32_t Instr;
20 
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
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.
25 #if defined(ARM64_DEFINE_FP_STATICS)
26 #define DEFINE_FLOAT(name, value) extern const uint32_t name = value
27 #define DEFINE_DOUBLE(name, value) extern const uint64_t name = value
28 #else
29 #define DEFINE_FLOAT(name, value) extern const float name
30 #define DEFINE_DOUBLE(name, value) extern const double name
31 #endif // defined(ARM64_DEFINE_FP_STATICS)
32 
33 DEFINE_FLOAT(kFP32PositiveInfinity, 0x7f800000);
34 DEFINE_FLOAT(kFP32NegativeInfinity, 0xff800000);
35 DEFINE_DOUBLE(kFP64PositiveInfinity, 0x7ff0000000000000UL);
36 DEFINE_DOUBLE(kFP64NegativeInfinity, 0xfff0000000000000UL);
37 
38 // This value is a signalling NaN as both a double and as a float (taking the
39 // least-significant word).
40 DEFINE_DOUBLE(kFP64SignallingNaN, 0x7ff000007f800001);
41 DEFINE_FLOAT(kFP32SignallingNaN, 0x7f800001);
42 
43 // A similar value, but as a quiet NaN.
44 DEFINE_DOUBLE(kFP64QuietNaN, 0x7ff800007fc00001);
45 DEFINE_FLOAT(kFP32QuietNaN, 0x7fc00001);
46 
47 // The default NaN values (for FPCR.DN=1).
48 DEFINE_DOUBLE(kFP64DefaultNaN, 0x7ff8000000000000UL);
49 DEFINE_FLOAT(kFP32DefaultNaN, 0x7fc00000);
50 
51 #undef DEFINE_FLOAT
52 #undef DEFINE_DOUBLE
53 
54 
55 enum LSDataSize {
56  LSByte = 0,
58  LSWord = 2,
59  LSDoubleWord = 3
60 };
61 
63 
69  TestBranchType = 4
70 };
71 
72 enum AddrMode {
73  Offset,
74  PreIndex,
75  PostIndex
76 };
77 
78 enum FPRounding {
79  // The first four values are encodable directly by FPCR<RMode>.
80  FPTieEven = 0x0,
83  FPZero = 0x3,
84 
85  // The final rounding mode is only available when explicitly specified by the
86  // instruction (such as with fcvta). It cannot be set in FPCR.
87  FPTieAway
88 };
89 
90 enum Reg31Mode {
93 };
94 
95 // Instructions. ---------------------------------------------------------------
96 
97 class Instruction {
98  public:
100  return *reinterpret_cast<const Instr*>(this);
101  }
102 
104  *reinterpret_cast<Instr*>(this) = new_instr;
105  }
106 
107  int Bit(int pos) const {
108  return (InstructionBits() >> pos) & 1;
109  }
110 
111  uint32_t Bits(int msb, int lsb) const {
112  return unsigned_bitextract_32(msb, lsb, InstructionBits());
113  }
114 
115  int32_t SignedBits(int msb, int lsb) const {
116  int32_t bits = *(reinterpret_cast<const int32_t*>(this));
117  return signed_bitextract_32(msb, lsb, bits);
118  }
119 
120  Instr Mask(uint32_t mask) const {
121  return InstructionBits() & mask;
122  }
123 
124  V8_INLINE Instruction* following(int count = 1) {
125  return InstructionAtOffset(count * static_cast<int>(kInstructionSize));
126  }
127 
128  V8_INLINE Instruction* preceding(int count = 1) {
129  return following(-count);
130  }
131 
132  #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \
133  int64_t Name() const { return Func(HighBit, LowBit); }
135  #undef DEFINE_GETTER
136 
137  // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST),
138  // formed from ImmPCRelLo and ImmPCRelHi.
139  int ImmPCRel() const {
141  int const offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
142  int const width = ImmPCRelLo_width + ImmPCRelHi_width;
143  return signed_bitextract_32(width - 1, 0, offset);
144  }
145 
146  uint64_t ImmLogical();
147  float ImmFP32();
148  double ImmFP64();
149 
151  return CalcLSPairDataSize(
152  static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
153  }
154 
155  // Helpers.
156  bool IsCondBranchImm() const {
158  }
159 
160  bool IsUncondBranchImm() const {
162  }
163 
164  bool IsCompareBranch() const {
166  }
167 
168  bool IsTestBranch() const {
170  }
171 
172  bool IsImmBranch() const {
173  return BranchType() != UnknownBranchType;
174  }
175 
176  bool IsLdrLiteral() const {
178  }
179 
180  bool IsLdrLiteralX() const {
181  return Mask(LoadLiteralMask) == LDR_x_lit;
182  }
183 
184  bool IsPCRelAddressing() const {
186  }
187 
188  bool IsAdr() const {
189  return Mask(PCRelAddressingMask) == ADR;
190  }
191 
192  bool IsLogicalImmediate() const {
194  }
195 
196  bool IsAddSubImmediate() const {
198  }
199 
200  bool IsAddSubShifted() const {
202  }
203 
204  bool IsAddSubExtended() const {
206  }
207 
208  // Match any loads or stores, including pairs.
209  bool IsLoadOrStore() const {
211  }
212 
213  // Match any loads, including pairs.
214  bool IsLoad() const;
215  // Match any stores, including pairs.
216  bool IsStore() const;
217 
218  // Indicate whether Rd can be the stack pointer or the zero register. This
219  // does not check that the instruction actually has an Rd field.
220  Reg31Mode RdMode() const {
221  // The following instructions use csp or wsp as Rd:
222  // Add/sub (immediate) when not setting the flags.
223  // Add/sub (extended) when not setting the flags.
224  // Logical (immediate) when not setting the flags.
225  // Otherwise, r31 is the zero register.
226  if (IsAddSubImmediate() || IsAddSubExtended()) {
227  if (Mask(AddSubSetFlagsBit)) {
228  return Reg31IsZeroRegister;
229  } else {
230  return Reg31IsStackPointer;
231  }
232  }
233  if (IsLogicalImmediate()) {
234  // Of the logical (immediate) instructions, only ANDS (and its aliases)
235  // can set the flags. The others can all write into csp.
236  // Note that some logical operations are not available to
237  // immediate-operand instructions, so we have to combine two masks here.
239  return Reg31IsZeroRegister;
240  } else {
241  return Reg31IsStackPointer;
242  }
243  }
244  return Reg31IsZeroRegister;
245  }
246 
247  // Indicate whether Rn can be the stack pointer or the zero register. This
248  // does not check that the instruction actually has an Rn field.
249  Reg31Mode RnMode() const {
250  // The following instructions use csp or wsp as Rn:
251  // All loads and stores.
252  // Add/sub (immediate).
253  // Add/sub (extended).
254  // Otherwise, r31 is the zero register.
256  return Reg31IsStackPointer;
257  }
258  return Reg31IsZeroRegister;
259  }
260 
262  if (IsCondBranchImm()) {
263  return CondBranchType;
264  } else if (IsUncondBranchImm()) {
265  return UncondBranchType;
266  } else if (IsCompareBranch()) {
267  return CompareBranchType;
268  } else if (IsTestBranch()) {
269  return TestBranchType;
270  } else {
271  return UnknownBranchType;
272  }
273  }
274 
275  static int ImmBranchRangeBitwidth(ImmBranchType branch_type) {
276  switch (branch_type) {
277  case UncondBranchType:
278  return ImmUncondBranch_width;
279  case CondBranchType:
280  return ImmCondBranch_width;
281  case CompareBranchType:
282  return ImmCmpBranch_width;
283  case TestBranchType:
284  return ImmTestBranch_width;
285  default:
286  UNREACHABLE();
287  return 0;
288  }
289  }
290 
291  // The range of the branch instruction, expressed as 'instr +- range'.
292  static int32_t ImmBranchRange(ImmBranchType branch_type) {
293  return
294  (1 << (ImmBranchRangeBitwidth(branch_type) + kInstructionSizeLog2)) / 2 -
296  }
297 
298  int ImmBranch() const {
299  switch (BranchType()) {
300  case CondBranchType: return ImmCondBranch();
301  case UncondBranchType: return ImmUncondBranch();
302  case CompareBranchType: return ImmCmpBranch();
303  case TestBranchType: return ImmTestBranch();
304  default: UNREACHABLE();
305  }
306  return 0;
307  }
308 
311  }
312 
313  bool IsMovz() const {
314  return (Mask(MoveWideImmediateMask) == MOVZ_x) ||
316  }
317 
318  bool IsMovk() const {
319  return (Mask(MoveWideImmediateMask) == MOVK_x) ||
321  }
322 
323  bool IsMovn() const {
324  return (Mask(MoveWideImmediateMask) == MOVN_x) ||
326  }
327 
328  bool IsNop(int n) {
329  // A marking nop is an instruction
330  // mov r<n>, r<n>
331  // which is encoded as
332  // orr r<n>, xzr, r<n>
333  return (Mask(LogicalShiftedMask) == ORR_x) &&
334  (Rd() == Rm()) &&
335  (Rd() == n);
336  }
337 
338  // Find the PC offset encoded in this instruction. 'this' may be a branch or
339  // a PC-relative addressing instruction.
340  // The offset returned is unscaled.
341  int64_t ImmPCOffset();
342 
343  // Find the target of this instruction. 'this' may be a branch or a
344  // PC-relative addressing instruction.
346 
347  static bool IsValidImmPCOffset(ImmBranchType branch_type, int32_t offset);
349  // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
350  // a PC-relative addressing instruction.
352  // Patch a literal load instruction to load from 'source'.
354 
356  int offset = ImmLLiteral() << kLoadLiteralScaleLog2;
357  return reinterpret_cast<uintptr_t>(this) + offset;
358  }
359 
361 
363  int64_t offset,
365  Address addr = reinterpret_cast<Address>(this) + offset;
366  // The FUZZ_disasm test relies on no check being done.
367  DCHECK(check == NO_CHECK || IsAddressAligned(addr, kInstructionSize));
368  return Cast(addr);
369  }
370 
371  template<typename T> V8_INLINE static Instruction* Cast(T src) {
372  return reinterpret_cast<Instruction*>(src);
373  }
374 
375  V8_INLINE ptrdiff_t DistanceTo(Instruction* target) {
376  return reinterpret_cast<Address>(target) - reinterpret_cast<Address>(this);
377  }
378 
379 
380  static const int ImmPCRelRangeBitwidth = 21;
381  static bool IsValidPCRelOffset(int offset) {
382  return is_int21(offset);
383  }
386 };
387 
388 
389 // Where Instruction looks at instructions generated by the Assembler,
390 // InstructionSequence looks at instructions sequences generated by the
391 // MacroAssembler.
393  public:
394  static InstructionSequence* At(Address address) {
395  return reinterpret_cast<InstructionSequence*>(address);
396  }
397 
398  // Sequences generated by MacroAssembler::InlineData().
399  bool IsInlineData() const;
400  uint64_t InlineData() const;
401 };
402 
403 
404 // Simulator/Debugger debug instructions ---------------------------------------
405 // Each debug marker is represented by a HLT instruction. The immediate comment
406 // field in the instruction is used to identify the type of debug marker. Each
407 // marker encodes arguments in a different way, as described below.
408 
409 // Indicate to the Debugger that the instruction is a redirected call.
411 
412 // Represent unreachable code. This is used as a guard in parts of the code that
413 // should not be reachable, such as in data encoded inline in the instructions.
415 
416 // A pseudo 'printf' instruction. The arguments will be passed to the platform
417 // printf method.
419 // Most parameters are stored in ARM64 registers as if the printf
420 // pseudo-instruction was a call to the real printf method:
421 // x0: The format string.
422 // x1-x7: Optional arguments.
423 // d0-d7: Optional arguments.
424 //
425 // Also, the argument layout is described inline in the instructions:
426 // - arg_count: The number of arguments.
427 // - arg_pattern: A set of PrintfArgPattern values, packed into two-bit fields.
428 //
429 // Floating-point and integer arguments are passed in separate sets of registers
430 // in AAPCS64 (even for varargs functions), so it is not possible to determine
431 // the type of each argument without some information about the values that were
432 // passed in. This information could be retrieved from the printf format string,
433 // but the format string is not trivial to parse so we encode the relevant
434 // information with the HLT instruction.
437 const unsigned kPrintfLength = 3 * kInstructionSize;
438 
439 const unsigned kPrintfMaxArgCount = 4;
440 
441 // The argument pattern is a set of two-bit-fields, each with one of the
442 // following values:
446  // There is no kPrintfArgS because floats are always converted to doubles in C
447  // varargs calls.
448  kPrintfArgD = 3
449 };
450 static const unsigned kPrintfArgPatternBits = 2;
451 
452 // A pseudo 'debug' instruction.
454 // Parameters are inlined in the code after a debug pseudo-instruction:
455 // - Debug code.
456 // - Debug parameters.
457 // - Debug message string. This is a NULL-terminated ASCII string, padded to
458 // kInstructionSize so that subsequent instructions are correctly aligned.
459 // - A kImmExceptionIsUnreachable marker, to catch accidental execution of the
460 // string data.
461 const unsigned kDebugCodeOffset = 1 * kInstructionSize;
464 
465 // Debug parameters.
466 // Used without a TRACE_ option, the Debugger will print the arguments only
467 // once. Otherwise TRACE_ENABLE and TRACE_DISABLE will enable or disable tracing
468 // before every instruction for the specified LOG_ parameters.
469 //
470 // TRACE_OVERRIDE enables the specified LOG_ parameters, and disabled any
471 // others that were not specified.
472 //
473 // For example:
474 //
475 // __ debug("print registers and fp registers", 0, LOG_REGS | LOG_FP_REGS);
476 // will print the registers and fp registers only once.
477 //
478 // __ debug("trace disasm", 1, TRACE_ENABLE | LOG_DISASM);
479 // starts disassembling the code.
480 //
481 // __ debug("trace rets", 2, TRACE_ENABLE | LOG_REGS);
482 // adds the general purpose registers to the trace.
483 //
484 // __ debug("stop regs", 3, TRACE_DISABLE | LOG_REGS);
485 // stops tracing the registers.
486 const unsigned kDebuggerTracingDirectivesMask = 3 << 6;
488  NO_PARAM = 0,
489  BREAK = 1 << 0,
490  LOG_DISASM = 1 << 1, // Use only with TRACE. Disassemble the code.
491  LOG_REGS = 1 << 2, // Log general purpose registers.
492  LOG_FP_REGS = 1 << 3, // Log floating-point registers.
493  LOG_SYS_REGS = 1 << 4, // Log the status flags.
494  LOG_WRITE = 1 << 5, // Log any memory write.
495 
498 
499  // Trace control.
500  TRACE_ENABLE = 1 << 6,
501  TRACE_DISABLE = 2 << 6,
502  TRACE_OVERRIDE = 3 << 6
503 };
504 
505 
506 } } // namespace v8::internal
507 
508 
509 #endif // V8_ARM64_INSTRUCTIONS_ARM64_H_
static InstructionSequence * At(Address address)
int32_t SignedBits(int msb, int lsb) const
Instr Mask(uint32_t mask) const
Instruction * InstructionAtOffset(int64_t offset, CheckAlignment check=CHECK_ALIGNMENT)
static Instruction * Cast(T src)
static int32_t ImmBranchRange(ImmBranchType branch_type)
Instruction * following(int count=1)
void SetPCRelImmTarget(Instruction *target)
void SetImmPCOffsetTarget(Instruction *target)
Instruction * ImmPCOffsetTarget()
bool IsTargetInImmPCOffsetRange(Instruction *target)
static const int ImmPCRelRangeBitwidth
static bool IsValidImmPCOffset(ImmBranchType branch_type, int32_t offset)
static bool IsValidPCRelOffset(int offset)
LSDataSize SizeLSPair() const
void SetImmLLiteral(Instruction *source)
Instruction * preceding(int count=1)
void SetBranchImmTarget(Instruction *target)
static int ImmBranchRangeBitwidth(ImmBranchType branch_type)
void SetInstructionBits(Instr new_instr)
ImmBranchType BranchType() const
ptrdiff_t DistanceTo(Instruction *target)
uint32_t Bits(int msb, int lsb) const
#define INSTRUCTION_FIELDS_LIST(V_)
#define DEFINE_GETTER(Name, HighBit, LowBit, Func)
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK(condition)
Definition: logging.h:205
int int32_t
Definition: unicode.cc:24
bool IsAddressAligned(Address addr, intptr_t alignment, int offset=0)
Definition: utils.h:129
DEFINE_FLOAT(kFP32PositiveInfinity, 0x7f800000)
LSDataSize CalcLSPairDataSize(LoadStorePairOp op)
const Instr kImmExceptionIsRedirectedCall
const unsigned kDebuggerTracingDirectivesMask
static const unsigned kPrintfArgPatternBits
const unsigned kPrintfLength
const unsigned kDebugParamsOffset
const unsigned kPrintfMaxArgCount
const unsigned kLoadLiteralScaleLog2
const Instr kImmExceptionIsPrintf
const unsigned kPrintfArgPatternListOffset
byte * Address
Definition: globals.h:101
const Instr kImmExceptionIsDebug
int32_t signed_bitextract_32(int msb, int lsb, int32_t x)
Definition: utils.h:888
const Instr kImmExceptionIsUnreachable
const unsigned kDebugCodeOffset
const unsigned kInstructionSize
const unsigned kInstructionSizeLog2
@ UnconditionalBranchToRegisterMask
uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x)
Definition: utils.h:880
const unsigned kPrintfArgCountOffset
DEFINE_DOUBLE(kFP64PositiveInfinity, 0x7ff0000000000000UL)
const unsigned kDebugMessageOffset
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
#define T(name, string, precedence)
Definition: token.cc:25
#define V8_INLINE
Definition: v8config.h:306