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.
5 #ifndef V8_ARM64_INSTRUCTIONS_ARM64_H_
6 #define V8_ARM64_INSTRUCTIONS_ARM64_H_
8 #include "src/arm64/constants-arm64.h"
9 #include "src/arm64/utils-arm64.h"
10 #include "src/globals.h"
11 #include "src/utils.h"
17 // ISA constants. --------------------------------------------------------------
19 typedef uint32_t Instr;
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
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)
33 DEFINE_FLOAT(kFP32PositiveInfinity, 0x7f800000);
34 DEFINE_FLOAT(kFP32NegativeInfinity, 0xff800000);
35 DEFINE_DOUBLE(kFP64PositiveInfinity, 0x7ff0000000000000UL);
36 DEFINE_DOUBLE(kFP64NegativeInfinity, 0xfff0000000000000UL);
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);
43 // A similar value, but as a quiet NaN.
44 DEFINE_DOUBLE(kFP64QuietNaN, 0x7ff800007fc00001);
45 DEFINE_FLOAT(kFP32QuietNaN, 0x7fc00001);
47 // The default NaN values (for FPCR.DN=1).
48 DEFINE_DOUBLE(kFP64DefaultNaN, 0x7ff8000000000000UL);
49 DEFINE_FLOAT(kFP32DefaultNaN, 0x7fc00000);
62 LSDataSize CalcLSPairDataSize(LoadStorePairOp op);
65 UnknownBranchType = 0,
68 CompareBranchType = 3,
79 // The first four values are encodable directly by FPCR<RMode>.
81 FPPositiveInfinity = 0x1,
82 FPNegativeInfinity = 0x2,
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.
95 // Instructions. ---------------------------------------------------------------
99 V8_INLINE Instr InstructionBits() const {
100 return *reinterpret_cast<const Instr*>(this);
103 V8_INLINE void SetInstructionBits(Instr new_instr) {
104 *reinterpret_cast<Instr*>(this) = new_instr;
107 int Bit(int pos) const {
108 return (InstructionBits() >> pos) & 1;
111 uint32_t Bits(int msb, int lsb) const {
112 return unsigned_bitextract_32(msb, lsb, InstructionBits());
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);
120 Instr Mask(uint32_t mask) const {
121 return InstructionBits() & mask;
124 V8_INLINE Instruction* following(int count = 1) {
125 return InstructionAtOffset(count * static_cast<int>(kInstructionSize));
128 V8_INLINE Instruction* preceding(int count = 1) {
129 return following(-count);
132 #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \
133 int64_t Name() const { return Func(HighBit, LowBit); }
134 INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)
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);
146 uint64_t ImmLogical();
150 LSDataSize SizeLSPair() const {
151 return CalcLSPairDataSize(
152 static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
156 bool IsCondBranchImm() const {
157 return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
160 bool IsUncondBranchImm() const {
161 return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
164 bool IsCompareBranch() const {
165 return Mask(CompareBranchFMask) == CompareBranchFixed;
168 bool IsTestBranch() const {
169 return Mask(TestBranchFMask) == TestBranchFixed;
172 bool IsImmBranch() const {
173 return BranchType() != UnknownBranchType;
176 bool IsLdrLiteral() const {
177 return Mask(LoadLiteralFMask) == LoadLiteralFixed;
180 bool IsLdrLiteralX() const {
181 return Mask(LoadLiteralMask) == LDR_x_lit;
184 bool IsPCRelAddressing() const {
185 return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
189 return Mask(PCRelAddressingMask) == ADR;
192 bool IsLogicalImmediate() const {
193 return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
196 bool IsAddSubImmediate() const {
197 return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
200 bool IsAddSubShifted() const {
201 return Mask(AddSubShiftedFMask) == AddSubShiftedFixed;
204 bool IsAddSubExtended() const {
205 return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
208 // Match any loads or stores, including pairs.
209 bool IsLoadOrStore() const {
210 return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
213 // Match any loads, including pairs.
215 // Match any stores, including pairs.
216 bool IsStore() const;
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;
230 return Reg31IsStackPointer;
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;
241 return Reg31IsStackPointer;
244 return Reg31IsZeroRegister;
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;
258 return Reg31IsZeroRegister;
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;
271 return UnknownBranchType;
275 static int ImmBranchRangeBitwidth(ImmBranchType branch_type) {
276 switch (branch_type) {
277 case UncondBranchType:
278 return ImmUncondBranch_width;
280 return ImmCondBranch_width;
281 case CompareBranchType:
282 return ImmCmpBranch_width;
284 return ImmTestBranch_width;
291 // The range of the branch instruction, expressed as 'instr +- range'.
292 static int32_t ImmBranchRange(ImmBranchType branch_type) {
294 (1 << (ImmBranchRangeBitwidth(branch_type) + kInstructionSizeLog2)) / 2 -
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();
309 bool IsBranchAndLinkToRegister() const {
310 return Mask(UnconditionalBranchToRegisterMask) == BLR;
313 bool IsMovz() const {
314 return (Mask(MoveWideImmediateMask) == MOVZ_x) ||
315 (Mask(MoveWideImmediateMask) == MOVZ_w);
318 bool IsMovk() const {
319 return (Mask(MoveWideImmediateMask) == MOVK_x) ||
320 (Mask(MoveWideImmediateMask) == MOVK_w);
323 bool IsMovn() const {
324 return (Mask(MoveWideImmediateMask) == MOVN_x) ||
325 (Mask(MoveWideImmediateMask) == MOVN_w);
329 // A marking nop is an instruction
331 // which is encoded as
332 // orr r<n>, xzr, r<n>
333 return (Mask(LogicalShiftedMask) == ORR_x) &&
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();
343 // Find the target of this instruction. 'this' may be a branch or a
344 // PC-relative addressing instruction.
345 Instruction* ImmPCOffsetTarget();
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);
355 uintptr_t LiteralAddress() {
356 int offset = ImmLLiteral() << kLoadLiteralScaleLog2;
357 return reinterpret_cast<uintptr_t>(this) + offset;
360 enum CheckAlignment { NO_CHECK, CHECK_ALIGNMENT };
362 V8_INLINE Instruction* InstructionAtOffset(
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));
371 template<typename T> V8_INLINE static Instruction* Cast(T src) {
372 return reinterpret_cast<Instruction*>(src);
375 V8_INLINE ptrdiff_t DistanceTo(Instruction* target) {
376 return reinterpret_cast<Address>(target) - reinterpret_cast<Address>(this);
380 static const int ImmPCRelRangeBitwidth = 21;
381 static bool IsValidPCRelOffset(int offset) {
382 return is_int21(offset);
384 void SetPCRelImmTarget(Instruction* target);
385 void SetBranchImmTarget(Instruction* target);
389 // Where Instruction looks at instructions generated by the Assembler,
390 // InstructionSequence looks at instructions sequences generated by the
392 class InstructionSequence : public Instruction {
394 static InstructionSequence* At(Address address) {
395 return reinterpret_cast<InstructionSequence*>(address);
398 // Sequences generated by MacroAssembler::InlineData().
399 bool IsInlineData() const;
400 uint64_t InlineData() const;
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.
409 // Indicate to the Debugger that the instruction is a redirected call.
410 const Instr kImmExceptionIsRedirectedCall = 0xca11;
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.
414 const Instr kImmExceptionIsUnreachable = 0xdebf;
416 // A pseudo 'printf' instruction. The arguments will be passed to the platform
418 const 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.
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.
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.
435 const unsigned kPrintfArgCountOffset = 1 * kInstructionSize;
436 const unsigned kPrintfArgPatternListOffset = 2 * kInstructionSize;
437 const unsigned kPrintfLength = 3 * kInstructionSize;
439 const unsigned kPrintfMaxArgCount = 4;
441 // The argument pattern is a set of two-bit-fields, each with one of the
443 enum PrintfArgPattern {
446 // There is no kPrintfArgS because floats are always converted to doubles in C
450 static const unsigned kPrintfArgPatternBits = 2;
452 // A pseudo 'debug' instruction.
453 const Instr kImmExceptionIsDebug = 0xdeb0;
454 // Parameters are inlined in the code after a debug pseudo-instruction:
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
461 const unsigned kDebugCodeOffset = 1 * kInstructionSize;
462 const unsigned kDebugParamsOffset = 2 * kInstructionSize;
463 const unsigned kDebugMessageOffset = 3 * kInstructionSize;
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.
470 // TRACE_OVERRIDE enables the specified LOG_ parameters, and disabled any
471 // others that were not specified.
475 // __ debug("print registers and fp registers", 0, LOG_REGS | LOG_FP_REGS);
476 // will print the registers and fp registers only once.
478 // __ debug("trace disasm", 1, TRACE_ENABLE | LOG_DISASM);
479 // starts disassembling the code.
481 // __ debug("trace rets", 2, TRACE_ENABLE | LOG_REGS);
482 // adds the general purpose registers to the trace.
484 // __ debug("stop regs", 3, TRACE_DISABLE | LOG_REGS);
485 // stops tracing the registers.
486 const unsigned kDebuggerTracingDirectivesMask = 3 << 6;
487 enum DebugParameters {
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.
496 LOG_STATE = LOG_REGS | LOG_FP_REGS | LOG_SYS_REGS,
497 LOG_ALL = LOG_DISASM | LOG_STATE | LOG_WRITE,
500 TRACE_ENABLE = 1 << 6,
501 TRACE_DISABLE = 2 << 6,
502 TRACE_OVERRIDE = 3 << 6
506 } } // namespace v8::internal
509 #endif // V8_ARM64_INSTRUCTIONS_ARM64_H_