deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / arm64 / instructions-arm64.h
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
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,
57   LSHalfword    = 1,
58   LSWord        = 2,
59   LSDoubleWord  = 3
60 };
61
62 LSDataSize CalcLSPairDataSize(LoadStorePairOp op);
63
64 enum ImmBranchType {
65   UnknownBranchType = 0,
66   CondBranchType    = 1,
67   UncondBranchType  = 2,
68   CompareBranchType = 3,
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,
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
90 enum Reg31Mode {
91   Reg31IsStackPointer,
92   Reg31IsZeroRegister
93 };
94
95 // Instructions. ---------------------------------------------------------------
96
97 class 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 const Instruction* following(int count = 1) const {
125     return InstructionAtOffset(count * static_cast<int>(kInstructionSize));
126   }
127
128   V8_INLINE Instruction* following(int count = 1) {
129     return InstructionAtOffset(count * static_cast<int>(kInstructionSize));
130   }
131
132   V8_INLINE const Instruction* preceding(int count = 1) const {
133     return following(-count);
134   }
135
136   V8_INLINE Instruction* preceding(int count = 1) {
137     return following(-count);
138   }
139
140   #define DEFINE_GETTER(Name, HighBit, LowBit, Func)             \
141   int64_t Name() const { return Func(HighBit, LowBit); }
142   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());
149     int const offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
150     int const width = ImmPCRelLo_width + ImmPCRelHi_width;
151     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
200   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
208   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
325   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
334   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
372   static bool IsValidImmPCOffset(ImmBranchType branch_type, int32_t offset);
373   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.
376   void SetImmPCOffsetTarget(Instruction* target);
377   void SetUnresolvedInternalReferenceImmTarget(Instruction* target);
378   // Patch a literal load instruction to load from 'source'.
379   void SetImmLLiteral(Instruction* source);
380
381   uintptr_t LiteralAddress() {
382     int offset = ImmLLiteral() << kLoadLiteralScaleLog2;
383     return reinterpret_cast<uintptr_t>(this) + offset;
384   }
385
386   enum CheckAlignment { NO_CHECK, CHECK_ALIGNMENT };
387
388   V8_INLINE const Instruction* InstructionAtOffset(
389       int64_t offset, CheckAlignment check = CHECK_ALIGNMENT) const {
390     // The FUZZ_disasm test relies on no check being done.
391     DCHECK(check == NO_CHECK || IsAligned(offset, kInstructionSize));
392     return this + offset;
393   }
394
395   V8_INLINE Instruction* InstructionAtOffset(
396       int64_t offset, CheckAlignment check = CHECK_ALIGNMENT) {
397     // The FUZZ_disasm test relies on no check being done.
398     DCHECK(check == NO_CHECK || IsAligned(offset, kInstructionSize));
399     return this + offset;
400   }
401
402   template<typename T> V8_INLINE static Instruction* Cast(T src) {
403     return reinterpret_cast<Instruction*>(src);
404   }
405
406   V8_INLINE ptrdiff_t DistanceTo(Instruction* target) {
407     return reinterpret_cast<Address>(target) - reinterpret_cast<Address>(this);
408   }
409
410
411   static const int ImmPCRelRangeBitwidth = 21;
412   static bool IsValidPCRelOffset(int offset) {
413     return is_int21(offset);
414   }
415   void SetPCRelImmTarget(Instruction* target);
416   void SetBranchImmTarget(Instruction* target);
417 };
418
419
420 // Where Instruction looks at instructions generated by the Assembler,
421 // InstructionSequence looks at instructions sequences generated by the
422 // MacroAssembler.
423 class InstructionSequence : public Instruction {
424  public:
425   static InstructionSequence* At(Address address) {
426     return reinterpret_cast<InstructionSequence*>(address);
427   }
428
429   // Sequences generated by MacroAssembler::InlineData().
430   bool IsInlineData() const;
431   uint64_t InlineData() const;
432 };
433
434
435 // Simulator/Debugger debug instructions ---------------------------------------
436 // Each debug marker is represented by a HLT instruction. The immediate comment
437 // field in the instruction is used to identify the type of debug marker. Each
438 // marker encodes arguments in a different way, as described below.
439
440 // Indicate to the Debugger that the instruction is a redirected call.
441 const Instr kImmExceptionIsRedirectedCall = 0xca11;
442
443 // Represent unreachable code. This is used as a guard in parts of the code that
444 // should not be reachable, such as in data encoded inline in the instructions.
445 const Instr kImmExceptionIsUnreachable = 0xdebf;
446
447 // A pseudo 'printf' instruction. The arguments will be passed to the platform
448 // printf method.
449 const Instr kImmExceptionIsPrintf = 0xdeb1;
450 // Most parameters are stored in ARM64 registers as if the printf
451 // pseudo-instruction was a call to the real printf method:
452 //      x0: The format string.
453 //   x1-x7: Optional arguments.
454 //   d0-d7: Optional arguments.
455 //
456 // Also, the argument layout is described inline in the instructions:
457 //  - arg_count: The number of arguments.
458 //  - arg_pattern: A set of PrintfArgPattern values, packed into two-bit fields.
459 //
460 // Floating-point and integer arguments are passed in separate sets of registers
461 // in AAPCS64 (even for varargs functions), so it is not possible to determine
462 // the type of each argument without some information about the values that were
463 // passed in. This information could be retrieved from the printf format string,
464 // but the format string is not trivial to parse so we encode the relevant
465 // information with the HLT instruction.
466 const unsigned kPrintfArgCountOffset = 1 * kInstructionSize;
467 const unsigned kPrintfArgPatternListOffset = 2 * kInstructionSize;
468 const unsigned kPrintfLength = 3 * kInstructionSize;
469
470 const unsigned kPrintfMaxArgCount = 4;
471
472 // The argument pattern is a set of two-bit-fields, each with one of the
473 // following values:
474 enum PrintfArgPattern {
475   kPrintfArgW = 1,
476   kPrintfArgX = 2,
477   // There is no kPrintfArgS because floats are always converted to doubles in C
478   // varargs calls.
479   kPrintfArgD = 3
480 };
481 static const unsigned kPrintfArgPatternBits = 2;
482
483 // A pseudo 'debug' instruction.
484 const Instr kImmExceptionIsDebug = 0xdeb0;
485 // Parameters are inlined in the code after a debug pseudo-instruction:
486 // - Debug code.
487 // - Debug parameters.
488 // - Debug message string. This is a NULL-terminated ASCII string, padded to
489 //   kInstructionSize so that subsequent instructions are correctly aligned.
490 // - A kImmExceptionIsUnreachable marker, to catch accidental execution of the
491 //   string data.
492 const unsigned kDebugCodeOffset = 1 * kInstructionSize;
493 const unsigned kDebugParamsOffset = 2 * kInstructionSize;
494 const unsigned kDebugMessageOffset = 3 * kInstructionSize;
495
496 // Debug parameters.
497 // Used without a TRACE_ option, the Debugger will print the arguments only
498 // once. Otherwise TRACE_ENABLE and TRACE_DISABLE will enable or disable tracing
499 // before every instruction for the specified LOG_ parameters.
500 //
501 // TRACE_OVERRIDE enables the specified LOG_ parameters, and disabled any
502 // others that were not specified.
503 //
504 // For example:
505 //
506 // __ debug("print registers and fp registers", 0, LOG_REGS | LOG_FP_REGS);
507 // will print the registers and fp registers only once.
508 //
509 // __ debug("trace disasm", 1, TRACE_ENABLE | LOG_DISASM);
510 // starts disassembling the code.
511 //
512 // __ debug("trace rets", 2, TRACE_ENABLE | LOG_REGS);
513 // adds the general purpose registers to the trace.
514 //
515 // __ debug("stop regs", 3, TRACE_DISABLE | LOG_REGS);
516 // stops tracing the registers.
517 const unsigned kDebuggerTracingDirectivesMask = 3 << 6;
518 enum DebugParameters {
519   NO_PARAM       = 0,
520   BREAK          = 1 << 0,
521   LOG_DISASM     = 1 << 1,  // Use only with TRACE. Disassemble the code.
522   LOG_REGS       = 1 << 2,  // Log general purpose registers.
523   LOG_FP_REGS    = 1 << 3,  // Log floating-point registers.
524   LOG_SYS_REGS   = 1 << 4,  // Log the status flags.
525   LOG_WRITE      = 1 << 5,  // Log any memory write.
526
527   LOG_STATE      = LOG_REGS | LOG_FP_REGS | LOG_SYS_REGS,
528   LOG_ALL        = LOG_DISASM | LOG_STATE | LOG_WRITE,
529
530   // Trace control.
531   TRACE_ENABLE   = 1 << 6,
532   TRACE_DISABLE  = 2 << 6,
533   TRACE_OVERRIDE = 3 << 6
534 };
535
536
537 } }  // namespace v8::internal
538
539
540 #endif  // V8_ARM64_INSTRUCTIONS_ARM64_H_