blob: db4e3d03a818420681c08196a80898ee1bf0ccbf [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124 V8_INLINE const Instruction* following(int count = 1) const {
125 return InstructionAtOffset(count * static_cast<int>(kInstructionSize));
126 }
127
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128 V8_INLINE Instruction* following(int count = 1) {
129 return InstructionAtOffset(count * static_cast<int>(kInstructionSize));
130 }
131
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132 V8_INLINE const Instruction* preceding(int count = 1) const {
133 return following(-count);
134 }
135
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136 V8_INLINE Instruction* preceding(int count = 1) {
137 return following(-count);
138 }
139
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000140#define DEFINE_GETTER(Name, HighBit, LowBit, Func) \
141 int32_t Name() const { return Func(HighBit, LowBit); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000142 INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)
143 #undef DEFINE_GETTER
144
145 // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST),
146 // formed from ImmPCRelLo and ImmPCRelHi.
147 int ImmPCRel() const {
148 DCHECK(IsPCRelAddressing());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 int offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
150 int width = ImmPCRelLo_width + ImmPCRelHi_width;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000151 return signed_bitextract_32(width - 1, 0, offset);
152 }
153
154 uint64_t ImmLogical();
155 float ImmFP32();
156 double ImmFP64();
157
158 LSDataSize SizeLSPair() const {
159 return CalcLSPairDataSize(
160 static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
161 }
162
163 // Helpers.
164 bool IsCondBranchImm() const {
165 return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
166 }
167
168 bool IsUncondBranchImm() const {
169 return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
170 }
171
172 bool IsCompareBranch() const {
173 return Mask(CompareBranchFMask) == CompareBranchFixed;
174 }
175
176 bool IsTestBranch() const {
177 return Mask(TestBranchFMask) == TestBranchFixed;
178 }
179
180 bool IsImmBranch() const {
181 return BranchType() != UnknownBranchType;
182 }
183
184 bool IsLdrLiteral() const {
185 return Mask(LoadLiteralFMask) == LoadLiteralFixed;
186 }
187
188 bool IsLdrLiteralX() const {
189 return Mask(LoadLiteralMask) == LDR_x_lit;
190 }
191
192 bool IsPCRelAddressing() const {
193 return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
194 }
195
196 bool IsAdr() const {
197 return Mask(PCRelAddressingMask) == ADR;
198 }
199
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 bool IsBrk() const { return Mask(ExceptionMask) == BRK; }
201
202 bool IsUnresolvedInternalReference() const {
203 // Unresolved internal references are encoded as two consecutive brk
204 // instructions.
205 return IsBrk() && following()->IsBrk();
206 }
207
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208 bool IsLogicalImmediate() const {
209 return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
210 }
211
212 bool IsAddSubImmediate() const {
213 return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
214 }
215
216 bool IsAddSubShifted() const {
217 return Mask(AddSubShiftedFMask) == AddSubShiftedFixed;
218 }
219
220 bool IsAddSubExtended() const {
221 return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
222 }
223
224 // Match any loads or stores, including pairs.
225 bool IsLoadOrStore() const {
226 return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
227 }
228
229 // Match any loads, including pairs.
230 bool IsLoad() const;
231 // Match any stores, including pairs.
232 bool IsStore() const;
233
234 // Indicate whether Rd can be the stack pointer or the zero register. This
235 // does not check that the instruction actually has an Rd field.
236 Reg31Mode RdMode() const {
237 // The following instructions use csp or wsp as Rd:
238 // Add/sub (immediate) when not setting the flags.
239 // Add/sub (extended) when not setting the flags.
240 // Logical (immediate) when not setting the flags.
241 // Otherwise, r31 is the zero register.
242 if (IsAddSubImmediate() || IsAddSubExtended()) {
243 if (Mask(AddSubSetFlagsBit)) {
244 return Reg31IsZeroRegister;
245 } else {
246 return Reg31IsStackPointer;
247 }
248 }
249 if (IsLogicalImmediate()) {
250 // Of the logical (immediate) instructions, only ANDS (and its aliases)
251 // can set the flags. The others can all write into csp.
252 // Note that some logical operations are not available to
253 // immediate-operand instructions, so we have to combine two masks here.
254 if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) {
255 return Reg31IsZeroRegister;
256 } else {
257 return Reg31IsStackPointer;
258 }
259 }
260 return Reg31IsZeroRegister;
261 }
262
263 // Indicate whether Rn can be the stack pointer or the zero register. This
264 // does not check that the instruction actually has an Rn field.
265 Reg31Mode RnMode() const {
266 // The following instructions use csp or wsp as Rn:
267 // All loads and stores.
268 // Add/sub (immediate).
269 // Add/sub (extended).
270 // Otherwise, r31 is the zero register.
271 if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) {
272 return Reg31IsStackPointer;
273 }
274 return Reg31IsZeroRegister;
275 }
276
277 ImmBranchType BranchType() const {
278 if (IsCondBranchImm()) {
279 return CondBranchType;
280 } else if (IsUncondBranchImm()) {
281 return UncondBranchType;
282 } else if (IsCompareBranch()) {
283 return CompareBranchType;
284 } else if (IsTestBranch()) {
285 return TestBranchType;
286 } else {
287 return UnknownBranchType;
288 }
289 }
290
291 static int ImmBranchRangeBitwidth(ImmBranchType branch_type) {
292 switch (branch_type) {
293 case UncondBranchType:
294 return ImmUncondBranch_width;
295 case CondBranchType:
296 return ImmCondBranch_width;
297 case CompareBranchType:
298 return ImmCmpBranch_width;
299 case TestBranchType:
300 return ImmTestBranch_width;
301 default:
302 UNREACHABLE();
303 return 0;
304 }
305 }
306
307 // The range of the branch instruction, expressed as 'instr +- range'.
308 static int32_t ImmBranchRange(ImmBranchType branch_type) {
309 return
310 (1 << (ImmBranchRangeBitwidth(branch_type) + kInstructionSizeLog2)) / 2 -
311 kInstructionSize;
312 }
313
314 int ImmBranch() const {
315 switch (BranchType()) {
316 case CondBranchType: return ImmCondBranch();
317 case UncondBranchType: return ImmUncondBranch();
318 case CompareBranchType: return ImmCmpBranch();
319 case TestBranchType: return ImmTestBranch();
320 default: UNREACHABLE();
321 }
322 return 0;
323 }
324
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000325 int ImmUnresolvedInternalReference() const {
326 DCHECK(IsUnresolvedInternalReference());
327 // Unresolved references are encoded as two consecutive brk instructions.
328 // The associated immediate is made of the two 16-bit payloads.
329 int32_t high16 = ImmException();
330 int32_t low16 = following()->ImmException();
331 return (high16 << 16) | low16;
332 }
333
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000334 bool IsBranchAndLinkToRegister() const {
335 return Mask(UnconditionalBranchToRegisterMask) == BLR;
336 }
337
338 bool IsMovz() const {
339 return (Mask(MoveWideImmediateMask) == MOVZ_x) ||
340 (Mask(MoveWideImmediateMask) == MOVZ_w);
341 }
342
343 bool IsMovk() const {
344 return (Mask(MoveWideImmediateMask) == MOVK_x) ||
345 (Mask(MoveWideImmediateMask) == MOVK_w);
346 }
347
348 bool IsMovn() const {
349 return (Mask(MoveWideImmediateMask) == MOVN_x) ||
350 (Mask(MoveWideImmediateMask) == MOVN_w);
351 }
352
353 bool IsNop(int n) {
354 // A marking nop is an instruction
355 // mov r<n>, r<n>
356 // which is encoded as
357 // orr r<n>, xzr, r<n>
358 return (Mask(LogicalShiftedMask) == ORR_x) &&
359 (Rd() == Rm()) &&
360 (Rd() == n);
361 }
362
363 // Find the PC offset encoded in this instruction. 'this' may be a branch or
364 // a PC-relative addressing instruction.
365 // The offset returned is unscaled.
366 int64_t ImmPCOffset();
367
368 // Find the target of this instruction. 'this' may be a branch or a
369 // PC-relative addressing instruction.
370 Instruction* ImmPCOffsetTarget();
371
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000372 static bool IsValidImmPCOffset(ImmBranchType branch_type, ptrdiff_t offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000373 bool IsTargetInImmPCOffsetRange(Instruction* target);
374 // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
375 // a PC-relative addressing instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000376 void SetImmPCOffsetTarget(Isolate* isolate, Instruction* target);
377 void SetUnresolvedInternalReferenceImmTarget(Isolate* isolate,
378 Instruction* target);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000379 // Patch a literal load instruction to load from 'source'.
380 void SetImmLLiteral(Instruction* source);
381
382 uintptr_t LiteralAddress() {
383 int offset = ImmLLiteral() << kLoadLiteralScaleLog2;
384 return reinterpret_cast<uintptr_t>(this) + offset;
385 }
386
387 enum CheckAlignment { NO_CHECK, CHECK_ALIGNMENT };
388
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000389 V8_INLINE const Instruction* InstructionAtOffset(
390 int64_t offset, CheckAlignment check = CHECK_ALIGNMENT) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000391 // The FUZZ_disasm test relies on no check being done.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 DCHECK(check == NO_CHECK || IsAligned(offset, kInstructionSize));
393 return this + offset;
394 }
395
396 V8_INLINE Instruction* InstructionAtOffset(
397 int64_t offset, CheckAlignment check = CHECK_ALIGNMENT) {
398 // The FUZZ_disasm test relies on no check being done.
399 DCHECK(check == NO_CHECK || IsAligned(offset, kInstructionSize));
400 return this + offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000401 }
402
403 template<typename T> V8_INLINE static Instruction* Cast(T src) {
404 return reinterpret_cast<Instruction*>(src);
405 }
406
407 V8_INLINE ptrdiff_t DistanceTo(Instruction* target) {
408 return reinterpret_cast<Address>(target) - reinterpret_cast<Address>(this);
409 }
410
411
412 static const int ImmPCRelRangeBitwidth = 21;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000413 static bool IsValidPCRelOffset(ptrdiff_t offset) { return is_int21(offset); }
414 void SetPCRelImmTarget(Isolate* isolate, Instruction* target);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000415 void SetBranchImmTarget(Instruction* target);
416};
417
418
419// Where Instruction looks at instructions generated by the Assembler,
420// InstructionSequence looks at instructions sequences generated by the
421// MacroAssembler.
422class InstructionSequence : public Instruction {
423 public:
424 static InstructionSequence* At(Address address) {
425 return reinterpret_cast<InstructionSequence*>(address);
426 }
427
428 // Sequences generated by MacroAssembler::InlineData().
429 bool IsInlineData() const;
430 uint64_t InlineData() const;
431};
432
433
434// Simulator/Debugger debug instructions ---------------------------------------
435// Each debug marker is represented by a HLT instruction. The immediate comment
436// field in the instruction is used to identify the type of debug marker. Each
437// marker encodes arguments in a different way, as described below.
438
439// Indicate to the Debugger that the instruction is a redirected call.
440const Instr kImmExceptionIsRedirectedCall = 0xca11;
441
442// Represent unreachable code. This is used as a guard in parts of the code that
443// should not be reachable, such as in data encoded inline in the instructions.
444const Instr kImmExceptionIsUnreachable = 0xdebf;
445
446// A pseudo 'printf' instruction. The arguments will be passed to the platform
447// printf method.
448const Instr kImmExceptionIsPrintf = 0xdeb1;
449// Most parameters are stored in ARM64 registers as if the printf
450// pseudo-instruction was a call to the real printf method:
451// x0: The format string.
452// x1-x7: Optional arguments.
453// d0-d7: Optional arguments.
454//
455// Also, the argument layout is described inline in the instructions:
456// - arg_count: The number of arguments.
457// - arg_pattern: A set of PrintfArgPattern values, packed into two-bit fields.
458//
459// Floating-point and integer arguments are passed in separate sets of registers
460// in AAPCS64 (even for varargs functions), so it is not possible to determine
461// the type of each argument without some information about the values that were
462// passed in. This information could be retrieved from the printf format string,
463// but the format string is not trivial to parse so we encode the relevant
464// information with the HLT instruction.
465const unsigned kPrintfArgCountOffset = 1 * kInstructionSize;
466const unsigned kPrintfArgPatternListOffset = 2 * kInstructionSize;
467const unsigned kPrintfLength = 3 * kInstructionSize;
468
469const unsigned kPrintfMaxArgCount = 4;
470
471// The argument pattern is a set of two-bit-fields, each with one of the
472// following values:
473enum PrintfArgPattern {
474 kPrintfArgW = 1,
475 kPrintfArgX = 2,
476 // There is no kPrintfArgS because floats are always converted to doubles in C
477 // varargs calls.
478 kPrintfArgD = 3
479};
480static const unsigned kPrintfArgPatternBits = 2;
481
482// A pseudo 'debug' instruction.
483const Instr kImmExceptionIsDebug = 0xdeb0;
484// Parameters are inlined in the code after a debug pseudo-instruction:
485// - Debug code.
486// - Debug parameters.
487// - Debug message string. This is a NULL-terminated ASCII string, padded to
488// kInstructionSize so that subsequent instructions are correctly aligned.
489// - A kImmExceptionIsUnreachable marker, to catch accidental execution of the
490// string data.
491const unsigned kDebugCodeOffset = 1 * kInstructionSize;
492const unsigned kDebugParamsOffset = 2 * kInstructionSize;
493const unsigned kDebugMessageOffset = 3 * kInstructionSize;
494
495// Debug parameters.
496// Used without a TRACE_ option, the Debugger will print the arguments only
497// once. Otherwise TRACE_ENABLE and TRACE_DISABLE will enable or disable tracing
498// before every instruction for the specified LOG_ parameters.
499//
500// TRACE_OVERRIDE enables the specified LOG_ parameters, and disabled any
501// others that were not specified.
502//
503// For example:
504//
505// __ debug("print registers and fp registers", 0, LOG_REGS | LOG_FP_REGS);
506// will print the registers and fp registers only once.
507//
508// __ debug("trace disasm", 1, TRACE_ENABLE | LOG_DISASM);
509// starts disassembling the code.
510//
511// __ debug("trace rets", 2, TRACE_ENABLE | LOG_REGS);
512// adds the general purpose registers to the trace.
513//
514// __ debug("stop regs", 3, TRACE_DISABLE | LOG_REGS);
515// stops tracing the registers.
516const unsigned kDebuggerTracingDirectivesMask = 3 << 6;
517enum DebugParameters {
518 NO_PARAM = 0,
519 BREAK = 1 << 0,
520 LOG_DISASM = 1 << 1, // Use only with TRACE. Disassemble the code.
521 LOG_REGS = 1 << 2, // Log general purpose registers.
522 LOG_FP_REGS = 1 << 3, // Log floating-point registers.
523 LOG_SYS_REGS = 1 << 4, // Log the status flags.
524 LOG_WRITE = 1 << 5, // Log any memory write.
525
526 LOG_STATE = LOG_REGS | LOG_FP_REGS | LOG_SYS_REGS,
527 LOG_ALL = LOG_DISASM | LOG_STATE | LOG_WRITE,
528
529 // Trace control.
530 TRACE_ENABLE = 1 << 6,
531 TRACE_DISABLE = 2 << 6,
532 TRACE_OVERRIDE = 3 << 6
533};
534
535
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000536} // namespace internal
537} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000538
539
540#endif // V8_ARM64_INSTRUCTIONS_ARM64_H_