| Index: src/a64/instructions-a64.h
|
| diff --git a/src/a64/instructions-a64.h b/src/a64/instructions-a64.h
|
| deleted file mode 100644
|
| index caeae9fefeb2e26b26204f26aabfa73fc6e5aabf..0000000000000000000000000000000000000000
|
| --- a/src/a64/instructions-a64.h
|
| +++ /dev/null
|
| @@ -1,501 +0,0 @@
|
| -// Copyright 2013 the V8 project authors. All rights reserved.
|
| -// Redistribution and use in source and binary forms, with or without
|
| -// modification, are permitted provided that the following conditions are
|
| -// met:
|
| -//
|
| -// * Redistributions of source code must retain the above copyright
|
| -// notice, this list of conditions and the following disclaimer.
|
| -// * Redistributions in binary form must reproduce the above
|
| -// copyright notice, this list of conditions and the following
|
| -// disclaimer in the documentation and/or other materials provided
|
| -// with the distribution.
|
| -// * Neither the name of Google Inc. nor the names of its
|
| -// contributors may be used to endorse or promote products derived
|
| -// from this software without specific prior written permission.
|
| -//
|
| -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| -
|
| -#ifndef V8_A64_INSTRUCTIONS_A64_H_
|
| -#define V8_A64_INSTRUCTIONS_A64_H_
|
| -
|
| -#include "globals.h"
|
| -#include "utils.h"
|
| -#include "a64/constants-a64.h"
|
| -#include "a64/utils-a64.h"
|
| -
|
| -namespace v8 {
|
| -namespace internal {
|
| -
|
| -
|
| -// ISA constants. --------------------------------------------------------------
|
| -
|
| -typedef uint32_t Instr;
|
| -
|
| -// The following macros initialize a float/double variable with a bit pattern
|
| -// without using static initializers: If A64_DEFINE_FP_STATICS is defined, the
|
| -// symbol is defined as uint32_t/uint64_t initialized with the desired bit
|
| -// pattern. Otherwise, the same symbol is declared as an external float/double.
|
| -#if defined(A64_DEFINE_FP_STATICS)
|
| -#define DEFINE_FLOAT(name, value) extern const uint32_t name = value
|
| -#define DEFINE_DOUBLE(name, value) extern const uint64_t name = value
|
| -#else
|
| -#define DEFINE_FLOAT(name, value) extern const float name
|
| -#define DEFINE_DOUBLE(name, value) extern const double name
|
| -#endif // defined(A64_DEFINE_FP_STATICS)
|
| -
|
| -DEFINE_FLOAT(kFP32PositiveInfinity, 0x7f800000);
|
| -DEFINE_FLOAT(kFP32NegativeInfinity, 0xff800000);
|
| -DEFINE_DOUBLE(kFP64PositiveInfinity, 0x7ff0000000000000UL);
|
| -DEFINE_DOUBLE(kFP64NegativeInfinity, 0xfff0000000000000UL);
|
| -
|
| -// This value is a signalling NaN as both a double and as a float (taking the
|
| -// least-significant word).
|
| -DEFINE_DOUBLE(kFP64SignallingNaN, 0x7ff000007f800001);
|
| -DEFINE_FLOAT(kFP32SignallingNaN, 0x7f800001);
|
| -
|
| -// A similar value, but as a quiet NaN.
|
| -DEFINE_DOUBLE(kFP64QuietNaN, 0x7ff800007fc00001);
|
| -DEFINE_FLOAT(kFP32QuietNaN, 0x7fc00001);
|
| -
|
| -// The default NaN values (for FPCR.DN=1).
|
| -DEFINE_DOUBLE(kFP64DefaultNaN, 0x7ff8000000000000UL);
|
| -DEFINE_FLOAT(kFP32DefaultNaN, 0x7fc00000);
|
| -
|
| -#undef DEFINE_FLOAT
|
| -#undef DEFINE_DOUBLE
|
| -
|
| -
|
| -enum LSDataSize {
|
| - LSByte = 0,
|
| - LSHalfword = 1,
|
| - LSWord = 2,
|
| - LSDoubleWord = 3
|
| -};
|
| -
|
| -LSDataSize CalcLSPairDataSize(LoadStorePairOp op);
|
| -
|
| -enum ImmBranchType {
|
| - UnknownBranchType = 0,
|
| - CondBranchType = 1,
|
| - UncondBranchType = 2,
|
| - CompareBranchType = 3,
|
| - TestBranchType = 4
|
| -};
|
| -
|
| -enum AddrMode {
|
| - Offset,
|
| - PreIndex,
|
| - PostIndex
|
| -};
|
| -
|
| -enum FPRounding {
|
| - // The first four values are encodable directly by FPCR<RMode>.
|
| - FPTieEven = 0x0,
|
| - FPPositiveInfinity = 0x1,
|
| - FPNegativeInfinity = 0x2,
|
| - FPZero = 0x3,
|
| -
|
| - // The final rounding mode is only available when explicitly specified by the
|
| - // instruction (such as with fcvta). It cannot be set in FPCR.
|
| - FPTieAway
|
| -};
|
| -
|
| -enum Reg31Mode {
|
| - Reg31IsStackPointer,
|
| - Reg31IsZeroRegister
|
| -};
|
| -
|
| -// Instructions. ---------------------------------------------------------------
|
| -
|
| -class Instruction {
|
| - public:
|
| - V8_INLINE Instr InstructionBits() const {
|
| - return *reinterpret_cast<const Instr*>(this);
|
| - }
|
| -
|
| - V8_INLINE void SetInstructionBits(Instr new_instr) {
|
| - *reinterpret_cast<Instr*>(this) = new_instr;
|
| - }
|
| -
|
| - int Bit(int pos) const {
|
| - return (InstructionBits() >> pos) & 1;
|
| - }
|
| -
|
| - uint32_t Bits(int msb, int lsb) const {
|
| - return unsigned_bitextract_32(msb, lsb, InstructionBits());
|
| - }
|
| -
|
| - int32_t SignedBits(int msb, int lsb) const {
|
| - int32_t bits = *(reinterpret_cast<const int32_t*>(this));
|
| - return signed_bitextract_32(msb, lsb, bits);
|
| - }
|
| -
|
| - Instr Mask(uint32_t mask) const {
|
| - return InstructionBits() & mask;
|
| - }
|
| -
|
| - V8_INLINE Instruction* following(int count = 1) {
|
| - return InstructionAtOffset(count * static_cast<int>(kInstructionSize));
|
| - }
|
| -
|
| - V8_INLINE Instruction* preceding(int count = 1) {
|
| - return following(-count);
|
| - }
|
| -
|
| - #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \
|
| - int64_t Name() const { return Func(HighBit, LowBit); }
|
| - INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)
|
| - #undef DEFINE_GETTER
|
| -
|
| - // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST),
|
| - // formed from ImmPCRelLo and ImmPCRelHi.
|
| - int ImmPCRel() const {
|
| - int const offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
|
| - int const width = ImmPCRelLo_width + ImmPCRelHi_width;
|
| - return signed_bitextract_32(width-1, 0, offset);
|
| - }
|
| -
|
| - uint64_t ImmLogical();
|
| - float ImmFP32();
|
| - double ImmFP64();
|
| -
|
| - LSDataSize SizeLSPair() const {
|
| - return CalcLSPairDataSize(
|
| - static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
|
| - }
|
| -
|
| - // Helpers.
|
| - bool IsCondBranchImm() const {
|
| - return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
|
| - }
|
| -
|
| - bool IsUncondBranchImm() const {
|
| - return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
|
| - }
|
| -
|
| - bool IsCompareBranch() const {
|
| - return Mask(CompareBranchFMask) == CompareBranchFixed;
|
| - }
|
| -
|
| - bool IsTestBranch() const {
|
| - return Mask(TestBranchFMask) == TestBranchFixed;
|
| - }
|
| -
|
| - bool IsLdrLiteral() const {
|
| - return Mask(LoadLiteralFMask) == LoadLiteralFixed;
|
| - }
|
| -
|
| - bool IsLdrLiteralX() const {
|
| - return Mask(LoadLiteralMask) == LDR_x_lit;
|
| - }
|
| -
|
| - bool IsPCRelAddressing() const {
|
| - return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
|
| - }
|
| -
|
| - bool IsLogicalImmediate() const {
|
| - return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
|
| - }
|
| -
|
| - bool IsAddSubImmediate() const {
|
| - return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
|
| - }
|
| -
|
| - bool IsAddSubExtended() const {
|
| - return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
|
| - }
|
| -
|
| - // Match any loads or stores, including pairs.
|
| - bool IsLoadOrStore() const {
|
| - return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
|
| - }
|
| -
|
| - // Match any loads, including pairs.
|
| - bool IsLoad() const;
|
| - // Match any stores, including pairs.
|
| - bool IsStore() const;
|
| -
|
| - // Indicate whether Rd can be the stack pointer or the zero register. This
|
| - // does not check that the instruction actually has an Rd field.
|
| - Reg31Mode RdMode() const {
|
| - // The following instructions use csp or wsp as Rd:
|
| - // Add/sub (immediate) when not setting the flags.
|
| - // Add/sub (extended) when not setting the flags.
|
| - // Logical (immediate) when not setting the flags.
|
| - // Otherwise, r31 is the zero register.
|
| - if (IsAddSubImmediate() || IsAddSubExtended()) {
|
| - if (Mask(AddSubSetFlagsBit)) {
|
| - return Reg31IsZeroRegister;
|
| - } else {
|
| - return Reg31IsStackPointer;
|
| - }
|
| - }
|
| - if (IsLogicalImmediate()) {
|
| - // Of the logical (immediate) instructions, only ANDS (and its aliases)
|
| - // can set the flags. The others can all write into csp.
|
| - // Note that some logical operations are not available to
|
| - // immediate-operand instructions, so we have to combine two masks here.
|
| - if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) {
|
| - return Reg31IsZeroRegister;
|
| - } else {
|
| - return Reg31IsStackPointer;
|
| - }
|
| - }
|
| - return Reg31IsZeroRegister;
|
| - }
|
| -
|
| - // Indicate whether Rn can be the stack pointer or the zero register. This
|
| - // does not check that the instruction actually has an Rn field.
|
| - Reg31Mode RnMode() const {
|
| - // The following instructions use csp or wsp as Rn:
|
| - // All loads and stores.
|
| - // Add/sub (immediate).
|
| - // Add/sub (extended).
|
| - // Otherwise, r31 is the zero register.
|
| - if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) {
|
| - return Reg31IsStackPointer;
|
| - }
|
| - return Reg31IsZeroRegister;
|
| - }
|
| -
|
| - ImmBranchType BranchType() const {
|
| - if (IsCondBranchImm()) {
|
| - return CondBranchType;
|
| - } else if (IsUncondBranchImm()) {
|
| - return UncondBranchType;
|
| - } else if (IsCompareBranch()) {
|
| - return CompareBranchType;
|
| - } else if (IsTestBranch()) {
|
| - return TestBranchType;
|
| - } else {
|
| - return UnknownBranchType;
|
| - }
|
| - }
|
| -
|
| - static int ImmBranchRangeBitwidth(ImmBranchType branch_type) {
|
| - switch (branch_type) {
|
| - case UncondBranchType:
|
| - return ImmUncondBranch_width;
|
| - case CondBranchType:
|
| - return ImmCondBranch_width;
|
| - case CompareBranchType:
|
| - return ImmCmpBranch_width;
|
| - case TestBranchType:
|
| - return ImmTestBranch_width;
|
| - default:
|
| - UNREACHABLE();
|
| - return 0;
|
| - }
|
| - }
|
| -
|
| - // The range of the branch instruction, expressed as 'instr +- range'.
|
| - static int32_t ImmBranchRange(ImmBranchType branch_type) {
|
| - return
|
| - (1 << (ImmBranchRangeBitwidth(branch_type) + kInstructionSizeLog2)) / 2 -
|
| - kInstructionSize;
|
| - }
|
| -
|
| - int ImmBranch() const {
|
| - switch (BranchType()) {
|
| - case CondBranchType: return ImmCondBranch();
|
| - case UncondBranchType: return ImmUncondBranch();
|
| - case CompareBranchType: return ImmCmpBranch();
|
| - case TestBranchType: return ImmTestBranch();
|
| - default: UNREACHABLE();
|
| - }
|
| - return 0;
|
| - }
|
| -
|
| - bool IsBranchAndLinkToRegister() const {
|
| - return Mask(UnconditionalBranchToRegisterMask) == BLR;
|
| - }
|
| -
|
| - bool IsMovz() const {
|
| - return (Mask(MoveWideImmediateMask) == MOVZ_x) ||
|
| - (Mask(MoveWideImmediateMask) == MOVZ_w);
|
| - }
|
| -
|
| - bool IsMovk() const {
|
| - return (Mask(MoveWideImmediateMask) == MOVK_x) ||
|
| - (Mask(MoveWideImmediateMask) == MOVK_w);
|
| - }
|
| -
|
| - bool IsMovn() const {
|
| - return (Mask(MoveWideImmediateMask) == MOVN_x) ||
|
| - (Mask(MoveWideImmediateMask) == MOVN_w);
|
| - }
|
| -
|
| - bool IsNop(int n) {
|
| - // A marking nop is an instruction
|
| - // mov r<n>, r<n>
|
| - // which is encoded as
|
| - // orr r<n>, xzr, r<n>
|
| - return (Mask(LogicalShiftedMask) == ORR_x) &&
|
| - (Rd() == Rm()) &&
|
| - (Rd() == n);
|
| - }
|
| -
|
| - // Find the PC offset encoded in this instruction. 'this' may be a branch or
|
| - // a PC-relative addressing instruction.
|
| - // The offset returned is unscaled.
|
| - ptrdiff_t ImmPCOffset();
|
| -
|
| - // Find the target of this instruction. 'this' may be a branch or a
|
| - // PC-relative addressing instruction.
|
| - Instruction* ImmPCOffsetTarget();
|
| -
|
| - static bool IsValidImmPCOffset(ImmBranchType branch_type, int32_t offset);
|
| - bool IsTargetInImmPCOffsetRange(Instruction* target);
|
| - // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
|
| - // a PC-relative addressing instruction.
|
| - void SetImmPCOffsetTarget(Instruction* target);
|
| - // Patch a literal load instruction to load from 'source'.
|
| - void SetImmLLiteral(Instruction* source);
|
| -
|
| - uint8_t* LiteralAddress() {
|
| - int offset = ImmLLiteral() << kLiteralEntrySizeLog2;
|
| - return reinterpret_cast<uint8_t*>(this) + offset;
|
| - }
|
| -
|
| - enum CheckAlignment { NO_CHECK, CHECK_ALIGNMENT };
|
| -
|
| - V8_INLINE Instruction* InstructionAtOffset(
|
| - int64_t offset,
|
| - CheckAlignment check = CHECK_ALIGNMENT) {
|
| - Address addr = reinterpret_cast<Address>(this) + offset;
|
| - // The FUZZ_disasm test relies on no check being done.
|
| - ASSERT(check == NO_CHECK || IsAddressAligned(addr, kInstructionSize));
|
| - return Cast(addr);
|
| - }
|
| -
|
| - template<typename T> V8_INLINE static Instruction* Cast(T src) {
|
| - return reinterpret_cast<Instruction*>(src);
|
| - }
|
| -
|
| - V8_INLINE ptrdiff_t DistanceTo(Instruction* target) {
|
| - return reinterpret_cast<Address>(target) - reinterpret_cast<Address>(this);
|
| - }
|
| -
|
| -
|
| - void SetPCRelImmTarget(Instruction* target);
|
| - void SetBranchImmTarget(Instruction* target);
|
| -};
|
| -
|
| -
|
| -// Where Instruction looks at instructions generated by the Assembler,
|
| -// InstructionSequence looks at instructions sequences generated by the
|
| -// MacroAssembler.
|
| -class InstructionSequence : public Instruction {
|
| - public:
|
| - static InstructionSequence* At(Address address) {
|
| - return reinterpret_cast<InstructionSequence*>(address);
|
| - }
|
| -
|
| - // Sequences generated by MacroAssembler::InlineData().
|
| - bool IsInlineData() const;
|
| - uint64_t InlineData() const;
|
| -};
|
| -
|
| -
|
| -// Simulator/Debugger debug instructions ---------------------------------------
|
| -// Each debug marker is represented by a HLT instruction. The immediate comment
|
| -// field in the instruction is used to identify the type of debug marker. Each
|
| -// marker encodes arguments in a different way, as described below.
|
| -
|
| -// Indicate to the Debugger that the instruction is a redirected call.
|
| -const Instr kImmExceptionIsRedirectedCall = 0xca11;
|
| -
|
| -// Represent unreachable code. This is used as a guard in parts of the code that
|
| -// should not be reachable, such as in data encoded inline in the instructions.
|
| -const Instr kImmExceptionIsUnreachable = 0xdebf;
|
| -
|
| -// A pseudo 'printf' instruction. The arguments will be passed to the platform
|
| -// printf method.
|
| -const Instr kImmExceptionIsPrintf = 0xdeb1;
|
| -// Parameters are stored in A64 registers as if the printf pseudo-instruction
|
| -// was a call to the real printf method:
|
| -//
|
| -// x0: The format string, then either of:
|
| -// x1-x7: Optional arguments.
|
| -// d0-d7: Optional arguments.
|
| -//
|
| -// Floating-point and integer arguments are passed in separate sets of
|
| -// registers in AAPCS64 (even for varargs functions), so it is not possible to
|
| -// determine the type of location of each arguments without some information
|
| -// about the values that were passed in. This information could be retrieved
|
| -// from the printf format string, but the format string is not trivial to
|
| -// parse so we encode the relevant information with the HLT instruction.
|
| -// - Type
|
| -// Either kRegister or kFPRegister, but stored as a uint32_t because there's
|
| -// no way to guarantee the size of the CPURegister::RegisterType enum.
|
| -const unsigned kPrintfTypeOffset = 1 * kInstructionSize;
|
| -const unsigned kPrintfLength = 2 * kInstructionSize;
|
| -
|
| -// A pseudo 'debug' instruction.
|
| -const Instr kImmExceptionIsDebug = 0xdeb0;
|
| -// Parameters are inlined in the code after a debug pseudo-instruction:
|
| -// - Debug code.
|
| -// - Debug parameters.
|
| -// - Debug message string. This is a NULL-terminated ASCII string, padded to
|
| -// kInstructionSize so that subsequent instructions are correctly aligned.
|
| -// - A kImmExceptionIsUnreachable marker, to catch accidental execution of the
|
| -// string data.
|
| -const unsigned kDebugCodeOffset = 1 * kInstructionSize;
|
| -const unsigned kDebugParamsOffset = 2 * kInstructionSize;
|
| -const unsigned kDebugMessageOffset = 3 * kInstructionSize;
|
| -
|
| -// Debug parameters.
|
| -// Used without a TRACE_ option, the Debugger will print the arguments only
|
| -// once. Otherwise TRACE_ENABLE and TRACE_DISABLE will enable or disable tracing
|
| -// before every instruction for the specified LOG_ parameters.
|
| -//
|
| -// TRACE_OVERRIDE enables the specified LOG_ parameters, and disabled any
|
| -// others that were not specified.
|
| -//
|
| -// For example:
|
| -//
|
| -// __ debug("print registers and fp registers", 0, LOG_REGS | LOG_FP_REGS);
|
| -// will print the registers and fp registers only once.
|
| -//
|
| -// __ debug("trace disasm", 1, TRACE_ENABLE | LOG_DISASM);
|
| -// starts disassembling the code.
|
| -//
|
| -// __ debug("trace rets", 2, TRACE_ENABLE | LOG_REGS);
|
| -// adds the general purpose registers to the trace.
|
| -//
|
| -// __ debug("stop regs", 3, TRACE_DISABLE | LOG_REGS);
|
| -// stops tracing the registers.
|
| -const unsigned kDebuggerTracingDirectivesMask = 3 << 6;
|
| -enum DebugParameters {
|
| - NO_PARAM = 0,
|
| - BREAK = 1 << 0,
|
| - LOG_DISASM = 1 << 1, // Use only with TRACE. Disassemble the code.
|
| - LOG_REGS = 1 << 2, // Log general purpose registers.
|
| - LOG_FP_REGS = 1 << 3, // Log floating-point registers.
|
| - LOG_SYS_REGS = 1 << 4, // Log the status flags.
|
| - LOG_WRITE = 1 << 5, // Log any memory write.
|
| -
|
| - LOG_STATE = LOG_REGS | LOG_FP_REGS | LOG_SYS_REGS,
|
| - LOG_ALL = LOG_DISASM | LOG_STATE | LOG_WRITE,
|
| -
|
| - // Trace control.
|
| - TRACE_ENABLE = 1 << 6,
|
| - TRACE_DISABLE = 2 << 6,
|
| - TRACE_OVERRIDE = 3 << 6
|
| -};
|
| -
|
| -
|
| -} } // namespace v8::internal
|
| -
|
| -
|
| -#endif // V8_A64_INSTRUCTIONS_A64_H_
|
|
|