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
8#include "src/arm64/constants-arm64.h"
9#include "src/arm64/utils-arm64.h"
10#include "src/globals.h"
11#include "src/utils.h"
12
13namespace v8 {
14namespace internal {
15
16
17// ISA constants. --------------------------------------------------------------
18
19typedef 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
33DEFINE_FLOAT(kFP32PositiveInfinity, 0x7f800000);
34DEFINE_FLOAT(kFP32NegativeInfinity, 0xff800000);
35DEFINE_DOUBLE(kFP64PositiveInfinity, 0x7ff0000000000000UL);
36DEFINE_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).
40DEFINE_DOUBLE(kFP64SignallingNaN, 0x7ff000007f800001);
41DEFINE_FLOAT(kFP32SignallingNaN, 0x7f800001);
42
43// A similar value, but as a quiet NaN.
44DEFINE_DOUBLE(kFP64QuietNaN, 0x7ff800007fc00001);
45DEFINE_FLOAT(kFP32QuietNaN, 0x7fc00001);
46
47// The default NaN values (for FPCR.DN=1).
48DEFINE_DOUBLE(kFP64DefaultNaN, 0x7ff8000000000000UL);
49DEFINE_FLOAT(kFP32DefaultNaN, 0x7fc00000);
50
51#undef DEFINE_FLOAT
52#undef DEFINE_DOUBLE
53
54
55enum LSDataSize {
56  LSByte        = 0,
57  LSHalfword    = 1,
58  LSWord        = 2,
59  LSDoubleWord  = 3
60};
61
62LSDataSize CalcLSPairDataSize(LoadStorePairOp op);
63
64enum ImmBranchType {
65  UnknownBranchType = 0,
66  CondBranchType    = 1,
67  UncondBranchType  = 2,
68  CompareBranchType = 3,
69  TestBranchType    = 4
70};
71
72enum AddrMode {
73  Offset,
74  PreIndex,
75  PostIndex
76};
77
78enum FPRounding {
79  // The first four values are encodable directly by FPCR<RMode>.
80  FPTieEven = 0x0,
81  FPPositiveInfinity = 0x1,
82  FPNegativeInfinity = 0x2,
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
90enum Reg31Mode {
91  Reg31IsStackPointer,
92  Reg31IsZeroRegister
93};
94
95// Instructions. ---------------------------------------------------------------
96
97class Instruction {
98 public:
99  V8_INLINE Instr InstructionBits() const {
100    return *reinterpret_cast<const Instr*>(this);
101  }
102
103  V8_INLINE void SetInstructionBits(Instr new_instr) {
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); }
134  INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)
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 {
140    DCHECK(IsPCRelAddressing());
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
150  LSDataSize SizeLSPair() const {
151    return CalcLSPairDataSize(
152        static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
153  }
154
155  // Helpers.
156  bool IsCondBranchImm() const {
157    return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
158  }
159
160  bool IsUncondBranchImm() const {
161    return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
162  }
163
164  bool IsCompareBranch() const {
165    return Mask(CompareBranchFMask) == CompareBranchFixed;
166  }
167
168  bool IsTestBranch() const {
169    return Mask(TestBranchFMask) == TestBranchFixed;
170  }
171
172  bool IsImmBranch() const {
173    return BranchType() != UnknownBranchType;
174  }
175
176  bool IsLdrLiteral() const {
177    return Mask(LoadLiteralFMask) == LoadLiteralFixed;
178  }
179
180  bool IsLdrLiteralX() const {
181    return Mask(LoadLiteralMask) == LDR_x_lit;
182  }
183
184  bool IsPCRelAddressing() const {
185    return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
186  }
187
188  bool IsAdr() const {
189    return Mask(PCRelAddressingMask) == ADR;
190  }
191
192  bool IsLogicalImmediate() const {
193    return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
194  }
195
196  bool IsAddSubImmediate() const {
197    return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
198  }
199
200  bool IsAddSubShifted() const {
201    return Mask(AddSubShiftedFMask) == AddSubShiftedFixed;
202  }
203
204  bool IsAddSubExtended() const {
205    return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
206  }
207
208  // Match any loads or stores, including pairs.
209  bool IsLoadOrStore() const {
210    return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
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.
238      if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) {
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.
255    if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) {
256      return Reg31IsStackPointer;
257    }
258    return Reg31IsZeroRegister;
259  }
260
261  ImmBranchType BranchType() const {
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 -
295      kInstructionSize;
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
309  bool IsBranchAndLinkToRegister() const {
310    return Mask(UnconditionalBranchToRegisterMask) == BLR;
311  }
312
313  bool IsMovz() const {
314    return (Mask(MoveWideImmediateMask) == MOVZ_x) ||
315           (Mask(MoveWideImmediateMask) == MOVZ_w);
316  }
317
318  bool IsMovk() const {
319    return (Mask(MoveWideImmediateMask) == MOVK_x) ||
320           (Mask(MoveWideImmediateMask) == MOVK_w);
321  }
322
323  bool IsMovn() const {
324    return (Mask(MoveWideImmediateMask) == MOVN_x) ||
325           (Mask(MoveWideImmediateMask) == MOVN_w);
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.
345  Instruction* ImmPCOffsetTarget();
346
347  static bool IsValidImmPCOffset(ImmBranchType branch_type, int32_t offset);
348  bool IsTargetInImmPCOffsetRange(Instruction* target);
349  // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
350  // a PC-relative addressing instruction.
351  void SetImmPCOffsetTarget(Instruction* target);
352  // Patch a literal load instruction to load from 'source'.
353  void SetImmLLiteral(Instruction* source);
354
355  uintptr_t LiteralAddress() {
356    int offset = ImmLLiteral() << kLoadLiteralScaleLog2;
357    return reinterpret_cast<uintptr_t>(this) + offset;
358  }
359
360  enum CheckAlignment { NO_CHECK, CHECK_ALIGNMENT };
361
362  V8_INLINE Instruction* InstructionAtOffset(
363      int64_t offset,
364      CheckAlignment check = CHECK_ALIGNMENT) {
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  }
384  void SetPCRelImmTarget(Instruction* target);
385  void SetBranchImmTarget(Instruction* target);
386};
387
388
389// Where Instruction looks at instructions generated by the Assembler,
390// InstructionSequence looks at instructions sequences generated by the
391// MacroAssembler.
392class InstructionSequence : public Instruction {
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.
410const Instr kImmExceptionIsRedirectedCall = 0xca11;
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.
414const Instr kImmExceptionIsUnreachable = 0xdebf;
415
416// A pseudo 'printf' instruction. The arguments will be passed to the platform
417// printf method.
418const Instr kImmExceptionIsPrintf = 0xdeb1;
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.
435const unsigned kPrintfArgCountOffset = 1 * kInstructionSize;
436const unsigned kPrintfArgPatternListOffset = 2 * kInstructionSize;
437const unsigned kPrintfLength = 3 * kInstructionSize;
438
439const unsigned kPrintfMaxArgCount = 4;
440
441// The argument pattern is a set of two-bit-fields, each with one of the
442// following values:
443enum PrintfArgPattern {
444  kPrintfArgW = 1,
445  kPrintfArgX = 2,
446  // There is no kPrintfArgS because floats are always converted to doubles in C
447  // varargs calls.
448  kPrintfArgD = 3
449};
450static const unsigned kPrintfArgPatternBits = 2;
451
452// A pseudo 'debug' instruction.
453const Instr kImmExceptionIsDebug = 0xdeb0;
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.
461const unsigned kDebugCodeOffset = 1 * kInstructionSize;
462const unsigned kDebugParamsOffset = 2 * kInstructionSize;
463const unsigned kDebugMessageOffset = 3 * 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.
486const unsigned kDebuggerTracingDirectivesMask = 3 << 6;
487enum DebugParameters {
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
496  LOG_STATE      = LOG_REGS | LOG_FP_REGS | LOG_SYS_REGS,
497  LOG_ALL        = LOG_DISASM | LOG_STATE | LOG_WRITE,
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_
510