diff options
Diffstat (limited to 'deps/v8/src/s390/assembler-s390.h')
-rw-r--r-- | deps/v8/src/s390/assembler-s390.h | 1466 |
1 files changed, 1466 insertions, 0 deletions
diff --git a/deps/v8/src/s390/assembler-s390.h b/deps/v8/src/s390/assembler-s390.h new file mode 100644 index 0000000000..0b9fa38539 --- /dev/null +++ b/deps/v8/src/s390/assembler-s390.h @@ -0,0 +1,1466 @@ +// 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 < 8; } + 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}; + +// 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); + void sldl(Register r1, Register b2, const Operand& opnd); + void srdl(Register r1, Register b2, const Operand& opnd); + void srda(Register r1, Register b2, const Operand& 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 alcr(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); + void slbr(Register r1, Register r2); + + // 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); + + AssemblerPositionsRecorder* 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_; + + AssemblerPositionsRecorder positions_recorder_; + friend class AssemblerPositionsRecorder; + friend class EnsureSpace; +}; + +class EnsureSpace BASE_EMBEDDED { + public: + explicit EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); } +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_S390_ASSEMBLER_S390_H_ |