| Index: src/s390/assembler-s390.h
|
| diff --git a/src/s390/assembler-s390.h b/src/s390/assembler-s390.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..05999611d75c12e8a3fcbac26c6ab14a0276ebd1
|
| --- /dev/null
|
| +++ b/src/s390/assembler-s390.h
|
| @@ -0,0 +1,1467 @@
|
| +// Copyright (c) 1994-2006 Sun Microsystems Inc.
|
| +// 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.
|
| +//
|
| +// - Redistribution 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 Sun Microsystems or the names of 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.
|
| +
|
| +// The original source code covered by the above license above has been
|
| +// modified significantly by Google Inc.
|
| +// Copyright 2014 the V8 project authors. All rights reserved.
|
| +
|
| +// A light-weight S390 Assembler
|
| +// Generates user mode instructions for z/Architecture
|
| +
|
| +#ifndef V8_S390_ASSEMBLER_S390_H_
|
| +#define V8_S390_ASSEMBLER_S390_H_
|
| +#include <stdio.h>
|
| +#if V8_HOST_ARCH_S390
|
| +// elf.h include is required for auxv check for STFLE facility used
|
| +// for hardware detection, which is sensible only on s390 hosts.
|
| +#include <elf.h>
|
| +#endif
|
| +
|
| +#include <fcntl.h>
|
| +#include <unistd.h>
|
| +#include "src/assembler.h"
|
| +#include "src/s390/constants-s390.h"
|
| +
|
| +#define ABI_USES_FUNCTION_DESCRIPTORS 0
|
| +
|
| +#define ABI_PASSES_HANDLES_IN_REGS 1
|
| +
|
| +// ObjectPair is defined under runtime/runtime-util.h.
|
| +// On 31-bit, ObjectPair == uint64_t. ABI dictates long long
|
| +// be returned with the lower addressed half in r2
|
| +// and the higher addressed half in r3. (Returns in Regs)
|
| +// On 64-bit, ObjectPair is a Struct. ABI dictaes Structs be
|
| +// returned in a storage buffer allocated by the caller,
|
| +// with the address of this buffer passed as a hidden
|
| +// argument in r2. (Does NOT return in Regs)
|
| +// For x86 linux, ObjectPair is returned in registers.
|
| +#if V8_TARGET_ARCH_S390X
|
| +#define ABI_RETURNS_OBJECTPAIR_IN_REGS 0
|
| +#else
|
| +#define ABI_RETURNS_OBJECTPAIR_IN_REGS 1
|
| +#endif
|
| +
|
| +#define ABI_CALL_VIA_IP 1
|
| +
|
| +#define INSTR_AND_DATA_CACHE_COHERENCY LWSYNC
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +
|
| +// clang-format off
|
| +#define GENERAL_REGISTERS(V) \
|
| + V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
| + V(r8) V(r9) V(r10) V(fp) V(ip) V(r13) V(r14) V(sp)
|
| +
|
| +#define ALLOCATABLE_GENERAL_REGISTERS(V) \
|
| + V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
|
| + V(r8) V(r9) V(r13)
|
| +
|
| +#define DOUBLE_REGISTERS(V) \
|
| + V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
| + V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) V(d14) V(d15)
|
| +
|
| +#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
|
| + V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
|
| + V(d8) V(d9) V(d10) V(d11) V(d12) V(d15) V(d0)
|
| +// clang-format on
|
| +
|
| +// CPU Registers.
|
| +//
|
| +// 1) We would prefer to use an enum, but enum values are assignment-
|
| +// compatible with int, which has caused code-generation bugs.
|
| +//
|
| +// 2) We would prefer to use a class instead of a struct but we don't like
|
| +// the register initialization to depend on the particular initialization
|
| +// order (which appears to be different on OS X, Linux, and Windows for the
|
| +// installed versions of C++ we tried). Using a struct permits C-style
|
| +// "initialization". Also, the Register objects cannot be const as this
|
| +// forces initialization stubs in MSVC, making us dependent on initialization
|
| +// order.
|
| +//
|
| +// 3) By not using an enum, we are possibly preventing the compiler from
|
| +// doing certain constant folds, which may significantly reduce the
|
| +// code generated for some assembly instructions (because they boil down
|
| +// to a few constants). If this is a problem, we could change the code
|
| +// such that we use an enum in optimized mode, and the struct in debug
|
| +// mode. This way we get the compile-time error checking in debug mode
|
| +// and best performance in optimized code.
|
| +
|
| +struct Register {
|
| + enum Code {
|
| +#define REGISTER_CODE(R) kCode_##R,
|
| + GENERAL_REGISTERS(REGISTER_CODE)
|
| +#undef REGISTER_CODE
|
| + kAfterLast,
|
| + kCode_no_reg = -1
|
| + };
|
| + static const int kNumRegisters = Code::kAfterLast;
|
| +
|
| +#define REGISTER_COUNT(R) 1 +
|
| + static const int kNumAllocatable =
|
| + ALLOCATABLE_GENERAL_REGISTERS(REGISTER_COUNT) 0;
|
| +#undef REGISTER_COUNT
|
| +
|
| +#define REGISTER_BIT(R) 1 << kCode_##R |
|
| + static const RegList kAllocatable =
|
| + ALLOCATABLE_GENERAL_REGISTERS(REGISTER_BIT) 0;
|
| +#undef REGISTER_BIT
|
| +
|
| + static Register from_code(int code) {
|
| + DCHECK(code >= 0);
|
| + DCHECK(code < kNumRegisters);
|
| + Register r = {code};
|
| + return r;
|
| + }
|
| +
|
| + const char* ToString();
|
| + bool IsAllocatable() const;
|
| + bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
|
| + bool is(Register reg) const { return reg_code == reg.reg_code; }
|
| + int code() const {
|
| + DCHECK(is_valid());
|
| + return reg_code;
|
| + }
|
| + int bit() const {
|
| + DCHECK(is_valid());
|
| + return 1 << reg_code;
|
| + }
|
| +
|
| + void set_code(int code) {
|
| + reg_code = code;
|
| + DCHECK(is_valid());
|
| + }
|
| +
|
| +#if V8_TARGET_LITTLE_ENDIAN
|
| + static const int kMantissaOffset = 0;
|
| + static const int kExponentOffset = 4;
|
| +#else
|
| + static const int kMantissaOffset = 4;
|
| + static const int kExponentOffset = 0;
|
| +#endif
|
| +
|
| + // Unfortunately we can't make this private in a struct.
|
| + int reg_code;
|
| +};
|
| +
|
| +typedef struct Register Register;
|
| +
|
| +#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
|
| +GENERAL_REGISTERS(DECLARE_REGISTER)
|
| +#undef DECLARE_REGISTER
|
| +const Register no_reg = {Register::kCode_no_reg};
|
| +
|
| +// Register aliases
|
| +const Register kLithiumScratch = r1; // lithium scratch.
|
| +const Register kRootRegister = r10; // Roots array pointer.
|
| +const Register cp = r13; // JavaScript context pointer.
|
| +
|
| +// Double word FP register.
|
| +struct DoubleRegister {
|
| + enum Code {
|
| +#define REGISTER_CODE(R) kCode_##R,
|
| + DOUBLE_REGISTERS(REGISTER_CODE)
|
| +#undef REGISTER_CODE
|
| + kAfterLast,
|
| + kCode_no_reg = -1
|
| + };
|
| +
|
| + static const int kNumRegisters = Code::kAfterLast;
|
| + static const int kMaxNumRegisters = kNumRegisters;
|
| +
|
| + const char* ToString();
|
| + bool IsAllocatable() const;
|
| + bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
|
| + bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
|
| +
|
| + int code() const {
|
| + DCHECK(is_valid());
|
| + return reg_code;
|
| + }
|
| +
|
| + int bit() const {
|
| + DCHECK(is_valid());
|
| + return 1 << reg_code;
|
| + }
|
| +
|
| + static DoubleRegister from_code(int code) {
|
| + DoubleRegister r = {code};
|
| + return r;
|
| + }
|
| +
|
| + int reg_code;
|
| +};
|
| +
|
| +typedef DoubleRegister DoubleRegister;
|
| +
|
| +#define DECLARE_REGISTER(R) \
|
| + const DoubleRegister R = {DoubleRegister::kCode_##R};
|
| +DOUBLE_REGISTERS(DECLARE_REGISTER)
|
| +#undef DECLARE_REGISTER
|
| +const Register no_dreg = {Register::kCode_no_reg};
|
| +
|
| +// Aliases for double registers. Defined using #define instead of
|
| +// "static const DoubleRegister&" because Clang complains otherwise when a
|
| +// compilation unit that includes this header doesn't use the variables.
|
| +#define kDoubleRegZero d14
|
| +#define kScratchDoubleReg d13
|
| +
|
| +Register ToRegister(int num);
|
| +
|
| +// Coprocessor register
|
| +struct CRegister {
|
| + bool is_valid() const { return 0 <= reg_code && reg_code < 16; }
|
| + bool is(CRegister creg) const { return reg_code == creg.reg_code; }
|
| + int code() const {
|
| + DCHECK(is_valid());
|
| + return reg_code;
|
| + }
|
| + int bit() const {
|
| + DCHECK(is_valid());
|
| + return 1 << reg_code;
|
| + }
|
| +
|
| + // Unfortunately we can't make this private in a struct.
|
| + int reg_code;
|
| +};
|
| +
|
| +const CRegister no_creg = {-1};
|
| +
|
| +const CRegister cr0 = {0};
|
| +const CRegister cr1 = {1};
|
| +const CRegister cr2 = {2};
|
| +const CRegister cr3 = {3};
|
| +const CRegister cr4 = {4};
|
| +const CRegister cr5 = {5};
|
| +const CRegister cr6 = {6};
|
| +const CRegister cr7 = {7};
|
| +const CRegister cr8 = {8};
|
| +const CRegister cr9 = {9};
|
| +const CRegister cr10 = {10};
|
| +const CRegister cr11 = {11};
|
| +const CRegister cr12 = {12};
|
| +const CRegister cr13 = {13};
|
| +const CRegister cr14 = {14};
|
| +const CRegister cr15 = {15};
|
| +
|
| +// TODO(john.yan) Define SIMD registers.
|
| +typedef DoubleRegister Simd128Register;
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +// Machine instruction Operands
|
| +
|
| +#if V8_TARGET_ARCH_S390X
|
| +const RelocInfo::Mode kRelocInfo_NONEPTR = RelocInfo::NONE64;
|
| +#else
|
| +const RelocInfo::Mode kRelocInfo_NONEPTR = RelocInfo::NONE32;
|
| +#endif
|
| +
|
| +// Class Operand represents a shifter operand in data processing instructions
|
| +// defining immediate numbers and masks
|
| +typedef uint8_t Length;
|
| +
|
| +struct Mask {
|
| + uint8_t mask;
|
| + uint8_t value() { return mask; }
|
| + static Mask from_value(uint8_t input) {
|
| + DCHECK(input <= 0x0F);
|
| + Mask m = {input};
|
| + return m;
|
| + }
|
| +};
|
| +
|
| +class Operand BASE_EMBEDDED {
|
| + public:
|
| + // immediate
|
| + INLINE(explicit Operand(intptr_t immediate,
|
| + RelocInfo::Mode rmode = kRelocInfo_NONEPTR));
|
| + INLINE(static Operand Zero()) { return Operand(static_cast<intptr_t>(0)); }
|
| + INLINE(explicit Operand(const ExternalReference& f));
|
| + explicit Operand(Handle<Object> handle);
|
| + INLINE(explicit Operand(Smi* value));
|
| +
|
| + // rm
|
| + INLINE(explicit Operand(Register rm));
|
| +
|
| + // Return true if this is a register operand.
|
| + INLINE(bool is_reg() const);
|
| +
|
| + bool must_output_reloc_info(const Assembler* assembler) const;
|
| +
|
| + inline intptr_t immediate() const {
|
| + DCHECK(!rm_.is_valid());
|
| + return imm_;
|
| + }
|
| +
|
| + inline void setBits(int n) {
|
| + imm_ = (static_cast<uint32_t>(imm_) << (32 - n)) >> (32 - n);
|
| + }
|
| +
|
| + Register rm() const { return rm_; }
|
| +
|
| + private:
|
| + Register rm_;
|
| + intptr_t imm_; // valid if rm_ == no_reg
|
| + RelocInfo::Mode rmode_;
|
| +
|
| + friend class Assembler;
|
| + friend class MacroAssembler;
|
| +};
|
| +
|
| +typedef int32_t Disp;
|
| +
|
| +// Class MemOperand represents a memory operand in load and store instructions
|
| +// On S390, we have various flavours of memory operands:
|
| +// 1) a base register + 16 bit unsigned displacement
|
| +// 2) a base register + index register + 16 bit unsigned displacement
|
| +// 3) a base register + index register + 20 bit signed displacement
|
| +class MemOperand BASE_EMBEDDED {
|
| + public:
|
| + explicit MemOperand(Register rx, Disp offset = 0);
|
| + explicit MemOperand(Register rx, Register rb, Disp offset = 0);
|
| +
|
| + int32_t offset() const { return offset_; }
|
| + uint32_t getDisplacement() const { return offset(); }
|
| +
|
| + // Base register
|
| + Register rb() const {
|
| + DCHECK(!baseRegister.is(no_reg));
|
| + return baseRegister;
|
| + }
|
| +
|
| + Register getBaseRegister() const { return rb(); }
|
| +
|
| + // Index Register
|
| + Register rx() const {
|
| + DCHECK(!indexRegister.is(no_reg));
|
| + return indexRegister;
|
| + }
|
| + Register getIndexRegister() const { return rx(); }
|
| +
|
| + private:
|
| + Register baseRegister; // base
|
| + Register indexRegister; // index
|
| + int32_t offset_; // offset
|
| +
|
| + friend class Assembler;
|
| +};
|
| +
|
| +class DeferredRelocInfo {
|
| + public:
|
| + DeferredRelocInfo() {}
|
| + DeferredRelocInfo(int position, RelocInfo::Mode rmode, intptr_t data)
|
| + : position_(position), rmode_(rmode), data_(data) {}
|
| +
|
| + int position() const { return position_; }
|
| + RelocInfo::Mode rmode() const { return rmode_; }
|
| + intptr_t data() const { return data_; }
|
| +
|
| + private:
|
| + int position_;
|
| + RelocInfo::Mode rmode_;
|
| + intptr_t data_;
|
| +};
|
| +
|
| +class Assembler : public AssemblerBase {
|
| + public:
|
| + // Create an assembler. Instructions and relocation information are emitted
|
| + // into a buffer, with the instructions starting from the beginning and the
|
| + // relocation information starting from the end of the buffer. See CodeDesc
|
| + // for a detailed comment on the layout (globals.h).
|
| + //
|
| + // If the provided buffer is NULL, the assembler allocates and grows its own
|
| + // buffer, and buffer_size determines the initial buffer size. The buffer is
|
| + // owned by the assembler and deallocated upon destruction of the assembler.
|
| + //
|
| + // If the provided buffer is not NULL, the assembler uses the provided buffer
|
| + // for code generation and assumes its size to be buffer_size. If the buffer
|
| + // is too small, a fatal error occurs. No deallocation of the buffer is done
|
| + // upon destruction of the assembler.
|
| + Assembler(Isolate* isolate, void* buffer, int buffer_size);
|
| + virtual ~Assembler() {}
|
| +
|
| + // GetCode emits any pending (non-emitted) code and fills the descriptor
|
| + // desc. GetCode() is idempotent; it returns the same result if no other
|
| + // Assembler functions are invoked in between GetCode() calls.
|
| + void GetCode(CodeDesc* desc);
|
| +
|
| + // Label operations & relative jumps (PPUM Appendix D)
|
| + //
|
| + // Takes a branch opcode (cc) and a label (L) and generates
|
| + // either a backward branch or a forward branch and links it
|
| + // to the label fixup chain. Usage:
|
| + //
|
| + // Label L; // unbound label
|
| + // j(cc, &L); // forward branch to unbound label
|
| + // bind(&L); // bind label to the current pc
|
| + // j(cc, &L); // backward branch to bound label
|
| + // bind(&L); // illegal: a label may be bound only once
|
| + //
|
| + // Note: The same Label can be used for forward and backward branches
|
| + // but it may be bound only once.
|
| +
|
| + void bind(Label* L); // binds an unbound label L to the current code position
|
| +
|
| + // Links a label at the current pc_offset(). If already bound, returns the
|
| + // bound position. If already linked, returns the position of the prior link.
|
| + // Otherwise, returns the current pc_offset().
|
| + int link(Label* L);
|
| +
|
| + // Determines if Label is bound and near enough so that a single
|
| + // branch instruction can be used to reach it.
|
| + bool is_near(Label* L, Condition cond);
|
| +
|
| + // Returns the branch offset to the given label from the current code position
|
| + // Links the label to the current position if it is still unbound
|
| + int branch_offset(Label* L) { return link(L) - pc_offset(); }
|
| +
|
| + // Puts a labels target address at the given position.
|
| + // The high 8 bits are set to zero.
|
| + void label_at_put(Label* L, int at_offset);
|
| + void load_label_offset(Register r1, Label* L);
|
| +
|
| + // Read/Modify the code target address in the branch/call instruction at pc.
|
| + INLINE(static Address target_address_at(Address pc, Address constant_pool));
|
| + INLINE(static void set_target_address_at(
|
| + Isolate* isolate, Address pc, Address constant_pool, Address target,
|
| + ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
|
| + INLINE(static Address target_address_at(Address pc, Code* code)) {
|
| + Address constant_pool = NULL;
|
| + return target_address_at(pc, constant_pool);
|
| + }
|
| + INLINE(static void set_target_address_at(
|
| + Isolate* isolate, Address pc, Code* code, Address target,
|
| + ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED)) {
|
| + Address constant_pool = NULL;
|
| + set_target_address_at(isolate, pc, constant_pool, target,
|
| + icache_flush_mode);
|
| + }
|
| +
|
| + // Return the code target address at a call site from the return address
|
| + // of that call in the instruction stream.
|
| + inline static Address target_address_from_return_address(Address pc);
|
| +
|
| + // Given the address of the beginning of a call, return the address
|
| + // in the instruction stream that the call will return to.
|
| + INLINE(static Address return_address_from_call_start(Address pc));
|
| +
|
| + inline Handle<Object> code_target_object_handle_at(Address pc);
|
| + // This sets the branch destination.
|
| + // This is for calls and branches within generated code.
|
| + inline static void deserialization_set_special_target_at(
|
| + Isolate* isolate, Address instruction_payload, Code* code,
|
| + Address target);
|
| +
|
| + // This sets the internal reference at the pc.
|
| + inline static void deserialization_set_target_internal_reference_at(
|
| + Isolate* isolate, Address pc, Address target,
|
| + RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
|
| +
|
| + // Here we are patching the address in the IIHF/IILF instruction pair.
|
| + // These values are used in the serialization process and must be zero for
|
| + // S390 platform, as Code, Embedded Object or External-reference pointers
|
| + // are split across two consecutive instructions and don't exist separately
|
| + // in the code, so the serializer should not step forwards in memory after
|
| + // a target is resolved and written.
|
| + static const int kSpecialTargetSize = 0;
|
| +
|
| +// Number of bytes for instructions used to store pointer sized constant.
|
| +#if V8_TARGET_ARCH_S390X
|
| + static const int kBytesForPtrConstant = 12; // IIHF + IILF
|
| +#else
|
| + static const int kBytesForPtrConstant = 6; // IILF
|
| +#endif
|
| +
|
| + // Distance between the instruction referring to the address of the call
|
| + // target and the return address.
|
| +
|
| + // Offset between call target address and return address
|
| + // for BRASL calls
|
| + // Patch will be appiled to other FIXED_SEQUENCE call
|
| + static const int kCallTargetAddressOffset = 6;
|
| +
|
| +// The length of FIXED_SEQUENCE call
|
| +// iihf r8, <address_hi> // <64-bit only>
|
| +// iilf r8, <address_lo>
|
| +// basr r14, r8
|
| +#if V8_TARGET_ARCH_S390X
|
| + static const int kCallSequenceLength = 14;
|
| +#else
|
| + static const int kCallSequenceLength = 8;
|
| +#endif
|
| +
|
| + // This is the length of the BreakLocationIterator::SetDebugBreakAtReturn()
|
| + // code patch FIXED_SEQUENCE in bytes!
|
| + // JS Return Sequence = Call Sequence + BKPT
|
| + // static const int kJSReturnSequenceLength = kCallSequenceLength + 2;
|
| +
|
| + // This is the length of the code sequence from SetDebugBreakAtSlot()
|
| + // FIXED_SEQUENCE in bytes!
|
| + static const int kDebugBreakSlotLength = kCallSequenceLength;
|
| + static const int kPatchDebugBreakSlotReturnOffset = kCallTargetAddressOffset;
|
| +
|
| + // Length to patch between the start of the JS return sequence
|
| + // from SetDebugBreakAtReturn and the address from
|
| + // break_address_from_return_address.
|
| + //
|
| + // frame->pc() in Debug::SetAfterBreakTarget will point to BKPT in
|
| + // JS return sequence, so the length to patch will not include BKPT
|
| + // instruction length.
|
| + // static const int kPatchReturnSequenceAddressOffset =
|
| + // kCallSequenceLength - kPatchDebugBreakSlotReturnOffset;
|
| +
|
| + // Length to patch between the start of the FIXED call sequence from
|
| + // SetDebugBreakAtSlot() and the the address from
|
| + // break_address_from_return_address.
|
| + static const int kPatchDebugBreakSlotAddressOffset =
|
| + kDebugBreakSlotLength - kPatchDebugBreakSlotReturnOffset;
|
| +
|
| + static inline int encode_crbit(const CRegister& cr, enum CRBit crbit) {
|
| + return ((cr.code() * CRWIDTH) + crbit);
|
| + }
|
| +
|
| + // ---------------------------------------------------------------------------
|
| + // Code generation
|
| +
|
| + // Helper for unconditional branch to Label with update to save register
|
| + void b(Register r, Label* l) {
|
| + positions_recorder()->WriteRecordedPositions();
|
| + int32_t halfwords = branch_offset(l) / 2;
|
| + brasl(r, Operand(halfwords));
|
| + }
|
| +
|
| + // Conditional Branch Instruction - Generates either BRC / BRCL
|
| + void branchOnCond(Condition c, int branch_offset, bool is_bound = false);
|
| +
|
| + // Helpers for conditional branch to Label
|
| + void b(Condition cond, Label* l, Label::Distance dist = Label::kFar) {
|
| + branchOnCond(cond, branch_offset(l),
|
| + l->is_bound() || (dist == Label::kNear));
|
| + }
|
| +
|
| + void bc_short(Condition cond, Label* l, Label::Distance dist = Label::kFar) {
|
| + b(cond, l, Label::kNear);
|
| + }
|
| + // Helpers for conditional branch to Label
|
| + void beq(Label* l, Label::Distance dist = Label::kFar) { b(eq, l, dist); }
|
| + void bne(Label* l, Label::Distance dist = Label::kFar) { b(ne, l, dist); }
|
| + void blt(Label* l, Label::Distance dist = Label::kFar) { b(lt, l, dist); }
|
| + void ble(Label* l, Label::Distance dist = Label::kFar) { b(le, l, dist); }
|
| + void bgt(Label* l, Label::Distance dist = Label::kFar) { b(gt, l, dist); }
|
| + void bge(Label* l, Label::Distance dist = Label::kFar) { b(ge, l, dist); }
|
| + void b(Label* l, Label::Distance dist = Label::kFar) { b(al, l, dist); }
|
| + void jmp(Label* l, Label::Distance dist = Label::kFar) { b(al, l, dist); }
|
| + void bunordered(Label* l, Label::Distance dist = Label::kFar) {
|
| + b(unordered, l, dist);
|
| + }
|
| + void bordered(Label* l, Label::Distance dist = Label::kFar) {
|
| + b(ordered, l, dist);
|
| + }
|
| +
|
| + // Helpers for conditional indirect branch off register
|
| + void b(Condition cond, Register r) { bcr(cond, r); }
|
| + void beq(Register r) { b(eq, r); }
|
| + void bne(Register r) { b(ne, r); }
|
| + void blt(Register r) { b(lt, r); }
|
| + void ble(Register r) { b(le, r); }
|
| + void bgt(Register r) { b(gt, r); }
|
| + void bge(Register r) { b(ge, r); }
|
| + void b(Register r) { b(al, r); }
|
| + void jmp(Register r) { b(al, r); }
|
| + void bunordered(Register r) { b(unordered, r); }
|
| + void bordered(Register r) { b(ordered, r); }
|
| +
|
| + // ---------------------------------------------------------------------------
|
| + // Code generation
|
| +
|
| + // Insert the smallest number of nop instructions
|
| + // possible to align the pc offset to a multiple
|
| + // of m. m must be a power of 2 (>= 4).
|
| + void Align(int m);
|
| + // Insert the smallest number of zero bytes possible to align the pc offset
|
| + // to a mulitple of m. m must be a power of 2 (>= 2).
|
| + void DataAlign(int m);
|
| + // Aligns code to something that's optimal for a jump target for the platform.
|
| + void CodeTargetAlign();
|
| +
|
| + void breakpoint(bool do_print) {
|
| + if (do_print) {
|
| + printf("DebugBreak is inserted to %p\n", pc_);
|
| + }
|
| +#if V8_HOST_ARCH_64_BIT
|
| + int64_t value = reinterpret_cast<uint64_t>(&v8::base::OS::DebugBreak);
|
| + int32_t hi_32 = static_cast<int64_t>(value) >> 32;
|
| + int32_t lo_32 = static_cast<int32_t>(value);
|
| +
|
| + iihf(r1, Operand(hi_32));
|
| + iilf(r1, Operand(lo_32));
|
| +#else
|
| + iilf(r1, Operand(reinterpret_cast<uint32_t>(&v8::base::OS::DebugBreak)));
|
| +#endif
|
| + basr(r14, r1);
|
| + }
|
| +
|
| + void call(Handle<Code> target, RelocInfo::Mode rmode,
|
| + TypeFeedbackId ast_id = TypeFeedbackId::None());
|
| + void jump(Handle<Code> target, RelocInfo::Mode rmode, Condition cond);
|
| +
|
| +// S390 instruction generation
|
| +#define I_FORM(name) void name(const Operand& i)
|
| +
|
| +#define RR_FORM(name) void name(Register r1, Register r2)
|
| +
|
| +#define RR2_FORM(name) void name(Condition m1, Register r2)
|
| +
|
| +#define RX_FORM(name) \
|
| + void name(Register r1, Register x2, Register b2, Disp d2); \
|
| + void name(Register r1, const MemOperand& opnd)
|
| +
|
| +#define RI1_FORM(name) void name(Register r, const Operand& i)
|
| +
|
| +#define RI2_FORM(name) void name(Condition m, const Operand& i)
|
| +
|
| +#define RIE_FORM(name) void name(Register r1, Register R3, const Operand& i)
|
| +
|
| +#define RIE_F_FORM(name) \
|
| + void name(Register r1, Register r2, const Operand& i3, const Operand& i4, \
|
| + const Operand& i5)
|
| +
|
| +#define RIL1_FORM(name) void name(Register r1, const Operand& i2)
|
| +
|
| +#define RIL2_FORM(name) void name(Condition m1, const Operand& i2)
|
| +
|
| +#define RXE_FORM(name) \
|
| + void name(Register r1, const MemOperand& opnd); \
|
| + void name(Register r1, Register b2, Register x2, Disp d2)
|
| +
|
| +#define RXF_FORM(name) \
|
| + void name(Register r1, Register r3, const MemOperand& opnd); \
|
| + void name(Register r1, Register r3, Register b2, Register x2, Disp d2)
|
| +
|
| +#define RXY_FORM(name) \
|
| + void name(Register r1, Register x2, Register b2, Disp d2); \
|
| + void name(Register r1, const MemOperand& opnd)
|
| +
|
| +#define RSI_FORM(name) void name(Register r1, Register r3, const Operand& i)
|
| +
|
| +#define RIS_FORM(name) \
|
| + void name(Register r1, Condition m3, Register b4, Disp d4, \
|
| + const Operand& i2); \
|
| + void name(Register r1, const Operand& i2, Condition m3, \
|
| + const MemOperand& opnd)
|
| +
|
| +#define SI_FORM(name) \
|
| + void name(const MemOperand& opnd, const Operand& i); \
|
| + void name(const Operand& i2, Register b1, Disp d1)
|
| +
|
| +#define SIL_FORM(name) \
|
| + void name(Register b1, Disp d1, const Operand& i2); \
|
| + void name(const MemOperand& opnd, const Operand& i2)
|
| +
|
| +#define RRE_FORM(name) void name(Register r1, Register r2)
|
| +
|
| +#define RRF1_FORM(name) void name(Register r1, Register r2, Register r3)
|
| +
|
| +#define RRF2_FORM(name) void name(Condition m1, Register r1, Register r2)
|
| +
|
| +#define RRF3_FORM(name) \
|
| + void name(Register r3, Condition m4, Register r1, Register r2)
|
| +
|
| +#define RS1_FORM(name) \
|
| + void name(Register r1, Register r3, const MemOperand& opnd); \
|
| + void name(Register r1, Register r3, Register b2, Disp d2)
|
| +
|
| +#define RS2_FORM(name) \
|
| + void name(Register r1, Condition m3, const MemOperand& opnd); \
|
| + void name(Register r1, Condition m3, Register b2, Disp d2)
|
| +
|
| +#define RSE_FORM(name) \
|
| + void name(Register r1, Register r3, const MemOperand& opnd); \
|
| + void name(Register r1, Register r3, Register b2, Disp d2)
|
| +
|
| +#define RSL_FORM(name) \
|
| + void name(Length l, Register b2, Disp d2); \
|
| + void name(const MemOperand& opnd)
|
| +
|
| +#define RSY1_FORM(name) \
|
| + void name(Register r1, Register r3, Register b2, Disp d2); \
|
| + void name(Register r1, Register r3, const MemOperand& opnd)
|
| +
|
| +#define RSY2_FORM(name) \
|
| + void name(Register r1, Condition m3, Register b2, Disp d2); \
|
| + void name(Register r1, Condition m3, const MemOperand& opnd)
|
| +
|
| +#define RRD_FORM(name) void name(Register r1, Register r3, Register r2)
|
| +
|
| +#define RRS_FORM(name) \
|
| + void name(Register r1, Register r2, Register b4, Disp d4, Condition m3); \
|
| + void name(Register r1, Register r2, Condition m3, const MemOperand& opnd)
|
| +
|
| +#define S_FORM(name) \
|
| + void name(Register b2, Disp d2); \
|
| + void name(const MemOperand& opnd)
|
| +
|
| +#define SIY_FORM(name) \
|
| + void name(const Operand& i2, Register b1, Disp d1); \
|
| + void name(const MemOperand& opnd, const Operand& i)
|
| +
|
| +#define SS1_FORM(name) \
|
| + void name(Register b1, Disp d1, Register b3, Disp d2, Length length); \
|
| + void name(const MemOperand& opnd1, const MemOperand& opnd2, Length length)
|
| +
|
| +#define SS2_FORM(name) \
|
| + void name(const MemOperand& opnd1, const MemOperand& opnd2, Length length1, \
|
| + Length length2); \
|
| + void name(Register b1, Disp d1, Register b2, Disp d2, Length l1, Length l2)
|
| +
|
| +#define SS3_FORM(name) \
|
| + void name(const MemOperand& opnd1, const MemOperand& opnd2, Length length); \
|
| + void name(const Operand& i3, Register b1, Disp d1, Register b2, Disp d2, \
|
| + Length l1)
|
| +
|
| +#define SS4_FORM(name) \
|
| + void name(const MemOperand& opnd1, const MemOperand& opnd2); \
|
| + void name(Register r1, Register r3, Register b1, Disp d1, Register b2, \
|
| + Disp d2)
|
| +
|
| +#define SS5_FORM(name) \
|
| + void name(const MemOperand& opnd1, const MemOperand& opnd2); \
|
| + void name(Register r1, Register r3, Register b3, Disp d2, Register b4, \
|
| + Disp d4)
|
| +
|
| +#define SSE_FORM(name) \
|
| + void name(Register b1, Disp d1, Register b2, Disp d2); \
|
| + void name(const MemOperand& opnd1, const MemOperand& opnd2)
|
| +
|
| +#define SSF_FORM(name) \
|
| + void name(Register r3, Register b1, Disp d1, Register b2, Disp d2); \
|
| + void name(Register r3, const MemOperand& opnd1, const MemOperand& opnd2)
|
| +
|
| + // S390 instruction sets
|
| + RX_FORM(bc);
|
| + RR_FORM(bctr);
|
| + RX_FORM(cd);
|
| + RRE_FORM(cdr);
|
| + RXE_FORM(cdb);
|
| + RXE_FORM(ceb);
|
| + RRE_FORM(cefbr);
|
| + RXE_FORM(ddb);
|
| + RRE_FORM(ddbr);
|
| + SS1_FORM(ed);
|
| + RRE_FORM(epair);
|
| + RX_FORM(ex);
|
| + RRF2_FORM(fidbr);
|
| + RRE_FORM(flogr);
|
| + RX_FORM(ic_z);
|
| + RXY_FORM(icy);
|
| + RIL1_FORM(iihf);
|
| + RI1_FORM(iihh);
|
| + RI1_FORM(iihl);
|
| + RIL1_FORM(iilf);
|
| + RI1_FORM(iilh);
|
| + RI1_FORM(iill);
|
| + RRE_FORM(lcgr);
|
| + RR_FORM(lcr);
|
| + RX_FORM(le_z);
|
| + RXY_FORM(ley);
|
| + RIL1_FORM(llihf);
|
| + RIL1_FORM(llilf);
|
| + RRE_FORM(lngr);
|
| + RR_FORM(lnr);
|
| + RSY1_FORM(loc);
|
| + RXY_FORM(lrv);
|
| + RXY_FORM(lrvh);
|
| + RXE_FORM(mdb);
|
| + RRE_FORM(mdbr);
|
| + SS4_FORM(mvck);
|
| + SSF_FORM(mvcos);
|
| + SS4_FORM(mvcs);
|
| + SS1_FORM(mvn);
|
| + SS1_FORM(nc);
|
| + SI_FORM(ni);
|
| + RIL1_FORM(nihf);
|
| + RIL1_FORM(nilf);
|
| + RI1_FORM(nilh);
|
| + RI1_FORM(nill);
|
| + RIL1_FORM(oihf);
|
| + RIL1_FORM(oilf);
|
| + RI1_FORM(oill);
|
| + RRE_FORM(popcnt);
|
| + RXE_FORM(sdb);
|
| + RRE_FORM(sdbr);
|
| + RIL1_FORM(slfi);
|
| + RXY_FORM(slgf);
|
| + RIL1_FORM(slgfi);
|
| + RS1_FORM(srdl);
|
| + RX_FORM(ste);
|
| + RXY_FORM(stey);
|
| + RXY_FORM(strv);
|
| + RI1_FORM(tmll);
|
| + SS1_FORM(tr);
|
| + S_FORM(ts);
|
| + RIL1_FORM(xihf);
|
| + RIL1_FORM(xilf);
|
| +
|
| + // Load Address Instructions
|
| + void la(Register r, const MemOperand& opnd);
|
| + void lay(Register r, const MemOperand& opnd);
|
| + void larl(Register r1, const Operand& opnd);
|
| + void larl(Register r, Label* l);
|
| +
|
| + // Load Instructions
|
| + void lb(Register r, const MemOperand& src);
|
| + void lbr(Register r1, Register r2);
|
| + void lgb(Register r, const MemOperand& src);
|
| + void lgbr(Register r1, Register r2);
|
| + void lh(Register r, const MemOperand& src);
|
| + void lhy(Register r, const MemOperand& src);
|
| + void lhr(Register r1, Register r2);
|
| + void lgh(Register r, const MemOperand& src);
|
| + void lghr(Register r1, Register r2);
|
| + void l(Register r, const MemOperand& src);
|
| + void ly(Register r, const MemOperand& src);
|
| + void lr(Register r1, Register r2);
|
| + void lg(Register r, const MemOperand& src);
|
| + void lgr(Register r1, Register r2);
|
| + void lgf(Register r, const MemOperand& src);
|
| + void lgfr(Register r1, Register r2);
|
| + void lhi(Register r, const Operand& imm);
|
| + void lghi(Register r, const Operand& imm);
|
| +
|
| + // Load And Test Instructions
|
| + void lt_z(Register r, const MemOperand& src);
|
| + void ltg(Register r, const MemOperand& src);
|
| + void ltr(Register r1, Register r2);
|
| + void ltgr(Register r1, Register r2);
|
| + void ltgfr(Register r1, Register r2);
|
| +
|
| + // Load Logical Instructions
|
| + void llc(Register r, const MemOperand& src);
|
| + void llgc(Register r, const MemOperand& src);
|
| + void llgf(Register r, const MemOperand& src);
|
| + void llgfr(Register r1, Register r2);
|
| + void llh(Register r, const MemOperand& src);
|
| + void llgh(Register r, const MemOperand& src);
|
| + void llhr(Register r1, Register r2);
|
| + void llghr(Register r1, Register r2);
|
| +
|
| + // Load Multiple Instructions
|
| + void lm(Register r1, Register r2, const MemOperand& src);
|
| + void lmy(Register r1, Register r2, const MemOperand& src);
|
| + void lmg(Register r1, Register r2, const MemOperand& src);
|
| +
|
| + // Store Instructions
|
| + void st(Register r, const MemOperand& src);
|
| + void stc(Register r, const MemOperand& src);
|
| + void stcy(Register r, const MemOperand& src);
|
| + void stg(Register r, const MemOperand& src);
|
| + void sth(Register r, const MemOperand& src);
|
| + void sthy(Register r, const MemOperand& src);
|
| + void sty(Register r, const MemOperand& src);
|
| +
|
| + // Store Multiple Instructions
|
| + void stm(Register r1, Register r2, const MemOperand& src);
|
| + void stmy(Register r1, Register r2, const MemOperand& src);
|
| + void stmg(Register r1, Register r2, const MemOperand& src);
|
| +
|
| + // Compare Instructions
|
| + void c(Register r, const MemOperand& opnd);
|
| + void cy(Register r, const MemOperand& opnd);
|
| + void cr_z(Register r1, Register r2);
|
| + void cg(Register r, const MemOperand& opnd);
|
| + void cgr(Register r1, Register r2);
|
| + void ch(Register r, const MemOperand& opnd);
|
| + void chy(Register r, const MemOperand& opnd);
|
| + void chi(Register r, const Operand& opnd);
|
| + void cghi(Register r, const Operand& opnd);
|
| + void cfi(Register r, const Operand& opnd);
|
| + void cgfi(Register r, const Operand& opnd);
|
| +
|
| + // Compare Logical Instructions
|
| + void cl(Register r, const MemOperand& opnd);
|
| + void cly(Register r, const MemOperand& opnd);
|
| + void clr(Register r1, Register r2);
|
| + void clg(Register r, const MemOperand& opnd);
|
| + void clgr(Register r1, Register r2);
|
| + void clfi(Register r, const Operand& opnd);
|
| + void clgfi(Register r, const Operand& opnd);
|
| + void cli(const MemOperand& mem, const Operand& imm);
|
| + void cliy(const MemOperand& mem, const Operand& imm);
|
| + void clc(const MemOperand& opnd1, const MemOperand& opnd2, Length length);
|
| +
|
| + // Test Under Mask Instructions
|
| + void tm(const MemOperand& mem, const Operand& imm);
|
| + void tmy(const MemOperand& mem, const Operand& imm);
|
| +
|
| + // Rotate Instructions
|
| + void rll(Register r1, Register r3, Register opnd);
|
| + void rll(Register r1, Register r3, const Operand& opnd);
|
| + void rll(Register r1, Register r3, Register r2, const Operand& opnd);
|
| + void rllg(Register r1, Register r3, const Operand& opnd);
|
| + void rllg(Register r1, Register r3, const Register opnd);
|
| + void rllg(Register r1, Register r3, Register r2, const Operand& opnd);
|
| +
|
| + // Shift Instructions (32)
|
| + void sll(Register r1, Register opnd);
|
| + void sll(Register r1, const Operand& opnd);
|
| + void sllk(Register r1, Register r3, Register opnd);
|
| + void sllk(Register r1, Register r3, const Operand& opnd);
|
| + void srl(Register r1, Register opnd);
|
| + void srl(Register r1, const Operand& opnd);
|
| + void srlk(Register r1, Register r3, Register opnd);
|
| + void srlk(Register r1, Register r3, const Operand& opnd);
|
| + void sra(Register r1, Register opnd);
|
| + void sra(Register r1, const Operand& opnd);
|
| + void srak(Register r1, Register r3, Register opnd);
|
| + void srak(Register r1, Register r3, const Operand& opnd);
|
| + void sla(Register r1, Register opnd);
|
| + void sla(Register r1, const Operand& opnd);
|
| + void slak(Register r1, Register r3, Register opnd);
|
| + void slak(Register r1, Register r3, const Operand& opnd);
|
| +
|
| + // Shift Instructions (64)
|
| + void sllg(Register r1, Register r3, const Operand& opnd);
|
| + void sllg(Register r1, Register r3, const Register opnd);
|
| + void srlg(Register r1, Register r3, const Operand& opnd);
|
| + void srlg(Register r1, Register r3, const Register opnd);
|
| + void srag(Register r1, Register r3, const Operand& opnd);
|
| + void srag(Register r1, Register r3, const Register opnd);
|
| + void srda(Register r1, const Operand& opnd);
|
| + void srdl(Register r1, const Operand& opnd);
|
| + void slag(Register r1, Register r3, const Operand& opnd);
|
| + void slag(Register r1, Register r3, const Register opnd);
|
| +
|
| + // Rotate and Insert Selected Bits
|
| + void risbg(Register dst, Register src, const Operand& startBit,
|
| + const Operand& endBit, const Operand& shiftAmt,
|
| + bool zeroBits = true);
|
| + void risbgn(Register dst, Register src, const Operand& startBit,
|
| + const Operand& endBit, const Operand& shiftAmt,
|
| + bool zeroBits = true);
|
| +
|
| + // Move Character (Mem to Mem)
|
| + void mvc(const MemOperand& opnd1, const MemOperand& opnd2, uint32_t length);
|
| +
|
| + // Branch Instructions
|
| + void basr(Register r1, Register r2);
|
| + void bcr(Condition m, Register target);
|
| + void bct(Register r, const MemOperand& opnd);
|
| + void bctg(Register r, const MemOperand& opnd);
|
| + void bras(Register r, const Operand& opnd);
|
| + void brasl(Register r, const Operand& opnd);
|
| + void brc(Condition c, const Operand& opnd);
|
| + void brcl(Condition m, const Operand& opnd, bool isCodeTarget = false);
|
| + void brct(Register r1, const Operand& opnd);
|
| + void brctg(Register r1, const Operand& opnd);
|
| +
|
| + // 32-bit Add Instructions
|
| + void a(Register r1, const MemOperand& opnd);
|
| + void ay(Register r1, const MemOperand& opnd);
|
| + void afi(Register r1, const Operand& opnd);
|
| + void ah(Register r1, const MemOperand& opnd);
|
| + void ahy(Register r1, const MemOperand& opnd);
|
| + void ahi(Register r1, const Operand& opnd);
|
| + void ahik(Register r1, Register r3, const Operand& opnd);
|
| + void ar(Register r1, Register r2);
|
| + void ark(Register r1, Register r2, Register r3);
|
| + void asi(const MemOperand&, const Operand&);
|
| +
|
| + // 64-bit Add Instructions
|
| + void ag(Register r1, const MemOperand& opnd);
|
| + void agf(Register r1, const MemOperand& opnd);
|
| + void agfi(Register r1, const Operand& opnd);
|
| + void agfr(Register r1, Register r2);
|
| + void aghi(Register r1, const Operand& opnd);
|
| + void aghik(Register r1, Register r3, const Operand& opnd);
|
| + void agr(Register r1, Register r2);
|
| + void agrk(Register r1, Register r2, Register r3);
|
| + void agsi(const MemOperand&, const Operand&);
|
| +
|
| + // 32-bit Add Logical Instructions
|
| + void al_z(Register r1, const MemOperand& opnd);
|
| + void aly(Register r1, const MemOperand& opnd);
|
| + void alfi(Register r1, const Operand& opnd);
|
| + void alr(Register r1, Register r2);
|
| + void alrk(Register r1, Register r2, Register r3);
|
| +
|
| + // 64-bit Add Logical Instructions
|
| + void alg(Register r1, const MemOperand& opnd);
|
| + void algfi(Register r1, const Operand& opnd);
|
| + void algr(Register r1, Register r2);
|
| + void algrk(Register r1, Register r2, Register r3);
|
| +
|
| + // 32-bit Subtract Instructions
|
| + void s(Register r1, const MemOperand& opnd);
|
| + void sy(Register r1, const MemOperand& opnd);
|
| + void sh(Register r1, const MemOperand& opnd);
|
| + void shy(Register r1, const MemOperand& opnd);
|
| + void sr(Register r1, Register r2);
|
| + void srk(Register r1, Register r2, Register r3);
|
| +
|
| + // 64-bit Subtract Instructions
|
| + void sg(Register r1, const MemOperand& opnd);
|
| + void sgf(Register r1, const MemOperand& opnd);
|
| + void sgr(Register r1, Register r2);
|
| + void sgfr(Register r1, Register r2);
|
| + void sgrk(Register r1, Register r2, Register r3);
|
| +
|
| + // 32-bit Subtract Logical Instructions
|
| + void sl(Register r1, const MemOperand& opnd);
|
| + void sly(Register r1, const MemOperand& opnd);
|
| + void slr(Register r1, Register r2);
|
| + void slrk(Register r1, Register r2, Register r3);
|
| +
|
| + // 64-bit Subtract Logical Instructions
|
| + void slg(Register r1, const MemOperand& opnd);
|
| + void slgr(Register r1, Register r2);
|
| + void slgrk(Register r1, Register r2, Register r3);
|
| +
|
| + // 32-bit Multiply Instructions
|
| + void m(Register r1, const MemOperand& opnd);
|
| + void mr_z(Register r1, Register r2);
|
| + void ml(Register r1, const MemOperand& opnd);
|
| + void mlr(Register r1, Register r2);
|
| + void ms(Register r1, const MemOperand& opnd);
|
| + void msy(Register r1, const MemOperand& opnd);
|
| + void msfi(Register r1, const Operand& opnd);
|
| + void msr(Register r1, Register r2);
|
| + void mh(Register r1, const MemOperand& opnd);
|
| + void mhy(Register r1, const MemOperand& opnd);
|
| + void mhi(Register r1, const Operand& opnd);
|
| +
|
| + // 64-bit Multiply Instructions
|
| + void mlg(Register r1, const MemOperand& opnd);
|
| + void mlgr(Register r1, Register r2);
|
| + void mghi(Register r1, const Operand& opnd);
|
| + void msgfi(Register r1, const Operand& opnd);
|
| + void msg(Register r1, const MemOperand& opnd);
|
| + void msgr(Register r1, Register r2);
|
| +
|
| + // 32-bit Divide Instructions
|
| + void d(Register r1, const MemOperand& opnd);
|
| + void dr(Register r1, Register r2);
|
| + void dl(Register r1, const MemOperand& opnd);
|
| + void dlr(Register r1, Register r2);
|
| +
|
| + // 64-bit Divide Instructions
|
| + void dlgr(Register r1, Register r2);
|
| + void dsgr(Register r1, Register r2);
|
| +
|
| + // Bitwise Instructions (AND / OR / XOR)
|
| + void n(Register r1, const MemOperand& opnd);
|
| + void ny(Register r1, const MemOperand& opnd);
|
| + void nr(Register r1, Register r2);
|
| + void nrk(Register r1, Register r2, Register r3);
|
| + void ng(Register r1, const MemOperand& opnd);
|
| + void ngr(Register r1, Register r2);
|
| + void ngrk(Register r1, Register r2, Register r3);
|
| + void o(Register r1, const MemOperand& opnd);
|
| + void oy(Register r1, const MemOperand& opnd);
|
| + void or_z(Register r1, Register r2);
|
| + void ork(Register r1, Register r2, Register r3);
|
| + void og(Register r1, const MemOperand& opnd);
|
| + void ogr(Register r1, Register r2);
|
| + void ogrk(Register r1, Register r2, Register r3);
|
| + void x(Register r1, const MemOperand& opnd);
|
| + void xy(Register r1, const MemOperand& opnd);
|
| + void xr(Register r1, Register r2);
|
| + void xrk(Register r1, Register r2, Register r3);
|
| + void xg(Register r1, const MemOperand& opnd);
|
| + void xgr(Register r1, Register r2);
|
| + void xgrk(Register r1, Register r2, Register r3);
|
| + void xc(const MemOperand& opnd1, const MemOperand& opnd2, Length length);
|
| +
|
| + // Bitwise GPR <-> FPR Conversion Instructions
|
| + void lgdr(Register r1, DoubleRegister f2);
|
| + void ldgr(DoubleRegister f1, Register r2);
|
| +
|
| + // Floating Point Load / Store Instructions
|
| + void ld(DoubleRegister r1, const MemOperand& opnd);
|
| + void ldy(DoubleRegister r1, const MemOperand& opnd);
|
| + void le_z(DoubleRegister r1, const MemOperand& opnd);
|
| + void ley(DoubleRegister r1, const MemOperand& opnd);
|
| + void ldr(DoubleRegister r1, DoubleRegister r2);
|
| + void ltdbr(DoubleRegister r1, DoubleRegister r2);
|
| + void ltebr(DoubleRegister r1, DoubleRegister r2);
|
| + void std(DoubleRegister r1, const MemOperand& opnd);
|
| + void stdy(DoubleRegister r1, const MemOperand& opnd);
|
| + void ste(DoubleRegister r1, const MemOperand& opnd);
|
| + void stey(DoubleRegister r1, const MemOperand& opnd);
|
| +
|
| + // Floating Point Load Rounded/Positive Instructions
|
| + void ledbr(DoubleRegister r1, DoubleRegister r2);
|
| + void ldebr(DoubleRegister r1, DoubleRegister r2);
|
| + void lpebr(DoubleRegister r1, DoubleRegister r2);
|
| + void lpdbr(DoubleRegister r1, DoubleRegister r2);
|
| +
|
| + // Floating <-> Fixed Point Conversion Instructions
|
| + void cdlfbr(Condition m3, Condition m4, DoubleRegister fltReg,
|
| + Register fixReg);
|
| + void cdlgbr(Condition m3, Condition m4, DoubleRegister fltReg,
|
| + Register fixReg);
|
| + void celgbr(Condition m3, Condition m4, DoubleRegister fltReg,
|
| + Register fixReg);
|
| + void celfbr(Condition m3, Condition m4, DoubleRegister fltReg,
|
| + Register fixReg);
|
| + void clfdbr(Condition m3, Condition m4, Register fixReg,
|
| + DoubleRegister fltReg);
|
| + void clfebr(Condition m3, Condition m4, Register fixReg,
|
| + DoubleRegister fltReg);
|
| + void clgdbr(Condition m3, Condition m4, Register fixReg,
|
| + DoubleRegister fltReg);
|
| + void clgebr(Condition m3, Condition m4, Register fixReg,
|
| + DoubleRegister fltReg);
|
| + void cfdbr(Condition m, Register fixReg, DoubleRegister fltReg);
|
| + void cdfbr(DoubleRegister fltReg, Register fixReg);
|
| + void cgebr(Condition m, Register fixReg, DoubleRegister fltReg);
|
| + void cgdbr(Condition m, Register fixReg, DoubleRegister fltReg);
|
| + void cegbr(DoubleRegister fltReg, Register fixReg);
|
| + void cdgbr(DoubleRegister fltReg, Register fixReg);
|
| + void cfebr(Condition m3, Register fixReg, DoubleRegister fltReg);
|
| + void cefbr(DoubleRegister fltReg, Register fixReg);
|
| +
|
| + // Floating Point Compare Instructions
|
| + void cebr(DoubleRegister r1, DoubleRegister r2);
|
| + void cdb(DoubleRegister r1, const MemOperand& opnd);
|
| + void cdbr(DoubleRegister r1, DoubleRegister r2);
|
| +
|
| + // Floating Point Arithmetic Instructions
|
| + void aebr(DoubleRegister r1, DoubleRegister r2);
|
| + void adb(DoubleRegister r1, const MemOperand& opnd);
|
| + void adbr(DoubleRegister r1, DoubleRegister r2);
|
| + void lzdr(DoubleRegister r1);
|
| + void sebr(DoubleRegister r1, DoubleRegister r2);
|
| + void sdb(DoubleRegister r1, const MemOperand& opnd);
|
| + void sdbr(DoubleRegister r1, DoubleRegister r2);
|
| + void meebr(DoubleRegister r1, DoubleRegister r2);
|
| + void mdb(DoubleRegister r1, const MemOperand& opnd);
|
| + void mdbr(DoubleRegister r1, DoubleRegister r2);
|
| + void debr(DoubleRegister r1, DoubleRegister r2);
|
| + void ddb(DoubleRegister r1, const MemOperand& opnd);
|
| + void ddbr(DoubleRegister r1, DoubleRegister r2);
|
| + void madbr(DoubleRegister r1, DoubleRegister r2, DoubleRegister r3);
|
| + void msdbr(DoubleRegister r1, DoubleRegister r2, DoubleRegister r3);
|
| + void sqebr(DoubleRegister r1, DoubleRegister r2);
|
| + void sqdb(DoubleRegister r1, const MemOperand& opnd);
|
| + void sqdbr(DoubleRegister r1, DoubleRegister r2);
|
| + void lcdbr(DoubleRegister r1, DoubleRegister r2);
|
| + void ldeb(DoubleRegister r1, const MemOperand& opnd);
|
| +
|
| + enum FIDBRA_MASK3 {
|
| + FIDBRA_CURRENT_ROUNDING_MODE = 0,
|
| + FIDBRA_ROUND_TO_NEAREST_AWAY_FROM_0 = 1,
|
| + // ...
|
| + FIDBRA_ROUND_TOWARD_0 = 5,
|
| + FIDBRA_ROUND_TOWARD_POS_INF = 6,
|
| + FIDBRA_ROUND_TOWARD_NEG_INF = 7
|
| + };
|
| + void fiebra(DoubleRegister d1, DoubleRegister d2, FIDBRA_MASK3 m3);
|
| + void fidbra(DoubleRegister d1, DoubleRegister d2, FIDBRA_MASK3 m3);
|
| +
|
| + // Move integer
|
| + void mvhi(const MemOperand& opnd1, const Operand& i2);
|
| + void mvghi(const MemOperand& opnd1, const Operand& i2);
|
| +
|
| + // Exception-generating instructions and debugging support
|
| + void stop(const char* msg, Condition cond = al,
|
| + int32_t code = kDefaultStopCode, CRegister cr = cr7);
|
| +
|
| + void bkpt(uint32_t imm16); // v5 and above
|
| +
|
| + // Different nop operations are used by the code generator to detect certain
|
| + // states of the generated code.
|
| + enum NopMarkerTypes {
|
| + NON_MARKING_NOP = 0,
|
| + GROUP_ENDING_NOP,
|
| + DEBUG_BREAK_NOP,
|
| + // IC markers.
|
| + PROPERTY_ACCESS_INLINED,
|
| + PROPERTY_ACCESS_INLINED_CONTEXT,
|
| + PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
|
| + // Helper values.
|
| + LAST_CODE_MARKER,
|
| + FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
|
| + };
|
| +
|
| + void nop(int type = 0); // 0 is the default non-marking type.
|
| +
|
| + // Check the code size generated from label to here.
|
| + int SizeOfCodeGeneratedSince(Label* label) {
|
| + return pc_offset() - label->pos();
|
| + }
|
| +
|
| + // Debugging
|
| +
|
| + // Mark generator continuation.
|
| + void RecordGeneratorContinuation();
|
| +
|
| + // Mark address of a debug break slot.
|
| + void RecordDebugBreakSlot(RelocInfo::Mode mode);
|
| +
|
| + // Record the AST id of the CallIC being compiled, so that it can be placed
|
| + // in the relocation information.
|
| + void SetRecordedAstId(TypeFeedbackId ast_id) { recorded_ast_id_ = ast_id; }
|
| +
|
| + TypeFeedbackId RecordedAstId() {
|
| + // roohack - another issue??? DCHECK(!recorded_ast_id_.IsNone());
|
| + return recorded_ast_id_;
|
| + }
|
| +
|
| + void ClearRecordedAstId() { recorded_ast_id_ = TypeFeedbackId::None(); }
|
| +
|
| + // Record a comment relocation entry that can be used by a disassembler.
|
| + // Use --code-comments to enable.
|
| + void RecordComment(const char* msg);
|
| +
|
| + // Record a deoptimization reason that can be used by a log or cpu profiler.
|
| + // Use --trace-deopt to enable.
|
| + void RecordDeoptReason(const int reason, int raw_position);
|
| +
|
| + // Writes a single byte or word of data in the code stream. Used
|
| + // for inline tables, e.g., jump-tables.
|
| + void db(uint8_t data);
|
| + void dd(uint32_t data);
|
| + void dq(uint64_t data);
|
| + void dp(uintptr_t data);
|
| +
|
| + PositionsRecorder* positions_recorder() { return &positions_recorder_; }
|
| +
|
| + void PatchConstantPoolAccessInstruction(int pc_offset, int offset,
|
| + ConstantPoolEntry::Access access,
|
| + ConstantPoolEntry::Type type) {
|
| + // No embedded constant pool support.
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + // Read/patch instructions
|
| + SixByteInstr instr_at(int pos) {
|
| + return Instruction::InstructionBits(buffer_ + pos);
|
| + }
|
| + template <typename T>
|
| + void instr_at_put(int pos, T instr) {
|
| + Instruction::SetInstructionBits<T>(buffer_ + pos, instr);
|
| + }
|
| +
|
| + // Decodes instruction at pos, and returns its length
|
| + int32_t instr_length_at(int pos) {
|
| + return Instruction::InstructionLength(buffer_ + pos);
|
| + }
|
| +
|
| + static SixByteInstr instr_at(byte* pc) {
|
| + return Instruction::InstructionBits(pc);
|
| + }
|
| +
|
| + static Condition GetCondition(Instr instr);
|
| +
|
| + static bool IsBranch(Instr instr);
|
| +#if V8_TARGET_ARCH_S390X
|
| + static bool Is64BitLoadIntoIP(SixByteInstr instr1, SixByteInstr instr2);
|
| +#else
|
| + static bool Is32BitLoadIntoIP(SixByteInstr instr);
|
| +#endif
|
| +
|
| + static bool IsCmpRegister(Instr instr);
|
| + static bool IsCmpImmediate(Instr instr);
|
| + static bool IsNop(SixByteInstr instr, int type = NON_MARKING_NOP);
|
| +
|
| + // The code currently calls CheckBuffer() too often. This has the side
|
| + // effect of randomly growing the buffer in the middle of multi-instruction
|
| + // sequences.
|
| + //
|
| + // This function allows outside callers to check and grow the buffer
|
| + void EnsureSpaceFor(int space_needed);
|
| +
|
| + void EmitRelocations();
|
| + void emit_label_addr(Label* label);
|
| +
|
| + public:
|
| + byte* buffer_pos() const { return buffer_; }
|
| +
|
| + protected:
|
| + // Relocation for a type-recording IC has the AST id added to it. This
|
| + // member variable is a way to pass the information from the call site to
|
| + // the relocation info.
|
| + TypeFeedbackId recorded_ast_id_;
|
| +
|
| + int buffer_space() const { return reloc_info_writer.pos() - pc_; }
|
| +
|
| + // Decode instruction(s) at pos and return backchain to previous
|
| + // label reference or kEndOfChain.
|
| + int target_at(int pos);
|
| +
|
| + // Patch instruction(s) at pos to target target_pos (e.g. branch)
|
| + void target_at_put(int pos, int target_pos, bool* is_branch = nullptr);
|
| +
|
| + // Record reloc info for current pc_
|
| + void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
|
| +
|
| + private:
|
| + // Code generation
|
| + // The relocation writer's position is at least kGap bytes below the end of
|
| + // the generated instructions. This is so that multi-instruction sequences do
|
| + // not have to check for overflow. The same is true for writes of large
|
| + // relocation info entries.
|
| + static const int kGap = 32;
|
| +
|
| + // Relocation info generation
|
| + // Each relocation is encoded as a variable size value
|
| + static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
|
| + RelocInfoWriter reloc_info_writer;
|
| + std::vector<DeferredRelocInfo> relocations_;
|
| +
|
| + // The bound position, before this we cannot do instruction elimination.
|
| + int last_bound_pos_;
|
| +
|
| + // Code emission
|
| + inline void CheckBuffer();
|
| + void GrowBuffer(int needed = 0);
|
| + inline void TrackBranch();
|
| + inline void UntrackBranch();
|
| +
|
| + inline int32_t emit_code_target(
|
| + Handle<Code> target, RelocInfo::Mode rmode,
|
| + TypeFeedbackId ast_id = TypeFeedbackId::None());
|
| +
|
| + // Helpers to emit binary encoding of 2/4/6 byte instructions.
|
| + inline void emit2bytes(uint16_t x);
|
| + inline void emit4bytes(uint32_t x);
|
| + inline void emit6bytes(uint64_t x);
|
| +
|
| + // Helpers to emit binary encoding for various instruction formats.
|
| +
|
| + inline void rr_form(Opcode op, Register r1, Register r2);
|
| + inline void rr_form(Opcode op, DoubleRegister r1, DoubleRegister r2);
|
| + inline void rr_form(Opcode op, Condition m1, Register r2);
|
| + inline void rr2_form(uint8_t op, Condition m1, Register r2);
|
| +
|
| + inline void rx_form(Opcode op, Register r1, Register x2, Register b2,
|
| + Disp d2);
|
| + inline void rx_form(Opcode op, DoubleRegister r1, Register x2, Register b2,
|
| + Disp d2);
|
| +
|
| + inline void ri_form(Opcode op, Register r1, const Operand& i2);
|
| + inline void ri_form(Opcode op, Condition m1, const Operand& i2);
|
| +
|
| + inline void rie_form(Opcode op, Register r1, Register r3, const Operand& i2);
|
| + inline void rie_f_form(Opcode op, Register r1, Register r2, const Operand& i3,
|
| + const Operand& i4, const Operand& i5);
|
| +
|
| + inline void ril_form(Opcode op, Register r1, const Operand& i2);
|
| + inline void ril_form(Opcode op, Condition m1, const Operand& i2);
|
| +
|
| + inline void ris_form(Opcode op, Register r1, Condition m3, Register b4,
|
| + Disp d4, const Operand& i2);
|
| +
|
| + inline void rrd_form(Opcode op, Register r1, Register r3, Register r2);
|
| +
|
| + inline void rre_form(Opcode op, Register r1, Register r2);
|
| + inline void rre_form(Opcode op, DoubleRegister r1, DoubleRegister r2);
|
| +
|
| + inline void rrf1_form(Opcode op, Register r1, Register r2, Register r3);
|
| + inline void rrf1_form(uint32_t x);
|
| + inline void rrf2_form(uint32_t x);
|
| + inline void rrf3_form(uint32_t x);
|
| + inline void rrfe_form(Opcode op, Condition m3, Condition m4, Register r1,
|
| + Register r2);
|
| +
|
| + inline void rrs_form(Opcode op, Register r1, Register r2, Register b4,
|
| + Disp d4, Condition m3);
|
| +
|
| + inline void rs_form(Opcode op, Register r1, Condition m3, Register b2,
|
| + const Disp d2);
|
| + inline void rs_form(Opcode op, Register r1, Register r3, Register b2,
|
| + const Disp d2);
|
| +
|
| + inline void rsi_form(Opcode op, Register r1, Register r3, const Operand& i2);
|
| + inline void rsl_form(Opcode op, Length l1, Register b2, Disp d2);
|
| +
|
| + inline void rsy_form(Opcode op, Register r1, Register r3, Register b2,
|
| + const Disp d2);
|
| + inline void rsy_form(Opcode op, Register r1, Condition m3, Register b2,
|
| + const Disp d2);
|
| +
|
| + inline void rxe_form(Opcode op, Register r1, Register x2, Register b2,
|
| + Disp d2);
|
| +
|
| + inline void rxf_form(Opcode op, Register r1, Register r3, Register b2,
|
| + Register x2, Disp d2);
|
| +
|
| + inline void rxy_form(Opcode op, Register r1, Register x2, Register b2,
|
| + Disp d2);
|
| + inline void rxy_form(Opcode op, DoubleRegister r1, Register x2, Register b2,
|
| + Disp d2);
|
| +
|
| + inline void s_form(Opcode op, Register b1, Disp d2);
|
| +
|
| + inline void si_form(Opcode op, const Operand& i2, Register b1, Disp d1);
|
| + inline void siy_form(Opcode op, const Operand& i2, Register b1, Disp d1);
|
| +
|
| + inline void sil_form(Opcode op, Register b1, Disp d1, const Operand& i2);
|
| +
|
| + inline void ss_form(Opcode op, Length l, Register b1, Disp d1, Register b2,
|
| + Disp d2);
|
| + inline void ss_form(Opcode op, Length l1, Length l2, Register b1, Disp d1,
|
| + Register b2, Disp d2);
|
| + inline void ss_form(Opcode op, Length l1, const Operand& i3, Register b1,
|
| + Disp d1, Register b2, Disp d2);
|
| + inline void ss_form(Opcode op, Register r1, Register r2, Register b1, Disp d1,
|
| + Register b2, Disp d2);
|
| + inline void sse_form(Opcode op, Register b1, Disp d1, Register b2, Disp d2);
|
| + inline void ssf_form(Opcode op, Register r3, Register b1, Disp d1,
|
| + Register b2, Disp d2);
|
| +
|
| + // Labels
|
| + void print(Label* L);
|
| + int max_reach_from(int pos);
|
| + void bind_to(Label* L, int pos);
|
| + void next(Label* L);
|
| +
|
| + friend class RegExpMacroAssemblerS390;
|
| + friend class RelocInfo;
|
| + friend class CodePatcher;
|
| +
|
| + List<Handle<Code> > code_targets_;
|
| +
|
| + PositionsRecorder positions_recorder_;
|
| + friend class PositionsRecorder;
|
| + friend class EnsureSpace;
|
| +};
|
| +
|
| +class EnsureSpace BASE_EMBEDDED {
|
| + public:
|
| + explicit EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); }
|
| +};
|
| +
|
| +} // namespace internal
|
| +} // namespace v8
|
| +
|
| +#endif // V8_S390_ASSEMBLER_S390_H_
|
|
|