Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  x86_64.ad   Sprache: unbekannt

 
//
// Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 2 only, as
// published by the Free Software Foundation.
//
// This code is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// version 2 for more details (a copy is included in the LICENSE file that
// accompanied this code).
//
// You should have received a copy of the GNU General Public License version
// 2 along with this work; if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
// or visit www.oracle.com if you need additional information or have any
// questions.
//
//

// AMD64 Architecture Description File

//----------REGISTER DEFINITION BLOCK------------------------------------------
// This information is used by the matcher and the register allocator to
// describe individual registers and classes of registers within the target
// architecture.

register %{
//----------Architecture Description Register Definitions----------------------
// General Registers
// "reg_def"  name ( register save type, C convention save type,
//                   ideal register type, encoding );
// Register Save Types:
//
// NS  = No-Save:       The register allocator assumes that these registers
//                      can be used without saving upon entry to the method, &
//                      that they do not need to be saved at call sites.
//
// SOC = Save-On-Call:  The register allocator assumes that these registers
//                      can be used without saving upon entry to the method,
//                      but that they must be saved at call sites.
//
// SOE = Save-On-Entry: The register allocator assumes that these registers
//                      must be saved before using them upon entry to the
//                      method, but they do not need to be saved at call
//                      sites.
//
// AS  = Always-Save:   The register allocator assumes that these registers
//                      must be saved before using them upon entry to the
//                      method, & that they must be saved at call sites.
//
// Ideal Register Type is used to determine how to save & restore a
// register.  Op_RegI will get spilled with LoadI/StoreI, Op_RegP will get
// spilled with LoadP/StoreP.  If the register supports both, use Op_RegI.
//
// The encoding number is the actual bit-pattern placed into the opcodes.

// General Registers
// R8-R15 must be encoded with REX.  (RSP, RBP, RSI, RDI need REX when
// used as byte registers)

// Previously set RBX, RSI, and RDI as save-on-entry for java code
// Turn off SOE in java-code due to frequent use of uncommon-traps.
// Now that allocator is better, turn on RSI and RDI as SOE registers.

reg_def RAX  (SOC, SOC, Op_RegI,  0, rax->as_VMReg());
reg_def RAX_H(SOC, SOC, Op_RegI,  0, rax->as_VMReg()->next());

reg_def RCX  (SOC, SOC, Op_RegI,  1, rcx->as_VMReg());
reg_def RCX_H(SOC, SOC, Op_RegI,  1, rcx->as_VMReg()->next());

reg_def RDX  (SOC, SOC, Op_RegI,  2, rdx->as_VMReg());
reg_def RDX_H(SOC, SOC, Op_RegI,  2, rdx->as_VMReg()->next());

reg_def RBX  (SOC, SOE, Op_RegI,  3, rbx->as_VMReg());
reg_def RBX_H(SOC, SOE, Op_RegI,  3, rbx->as_VMReg()->next());

reg_def RSP  (NS,  NS,  Op_RegI,  4, rsp->as_VMReg());
reg_def RSP_H(NS,  NS,  Op_RegI,  4, rsp->as_VMReg()->next());

// now that adapter frames are gone RBP is always saved and restored by the prolog/epilog code
reg_def RBP  (NS, SOE, Op_RegI,  5, rbp->as_VMReg());
reg_def RBP_H(NS, SOE, Op_RegI,  5, rbp->as_VMReg()->next());

#ifdef _WIN64

reg_def RSI  (SOC, SOE, Op_RegI,  6, rsi->as_VMReg());
reg_def RSI_H(SOC, SOE, Op_RegI,  6, rsi->as_VMReg()->next());

reg_def RDI  (SOC, SOE, Op_RegI,  7, rdi->as_VMReg());
reg_def RDI_H(SOC, SOE, Op_RegI,  7, rdi->as_VMReg()->next());

#else

reg_def RSI  (SOC, SOC, Op_RegI,  6, rsi->as_VMReg());
reg_def RSI_H(SOC, SOC, Op_RegI,  6, rsi->as_VMReg()->next());

reg_def RDI  (SOC, SOC, Op_RegI,  7, rdi->as_VMReg());
reg_def RDI_H(SOC, SOC, Op_RegI,  7, rdi->as_VMReg()->next());

#endif

reg_def R8   (SOC, SOC, Op_RegI,  8, r8->as_VMReg());
reg_def R8_H (SOC, SOC, Op_RegI,  8, r8->as_VMReg()->next());

reg_def R9   (SOC, SOC, Op_RegI,  9, r9->as_VMReg());
reg_def R9_H (SOC, SOC, Op_RegI,  9, r9->as_VMReg()->next());

reg_def R10  (SOC, SOC, Op_RegI, 10, r10->as_VMReg());
reg_def R10_H(SOC, SOC, Op_RegI, 10, r10->as_VMReg()->next());

reg_def R11  (SOC, SOC, Op_RegI, 11, r11->as_VMReg());
reg_def R11_H(SOC, SOC, Op_RegI, 11, r11->as_VMReg()->next());

reg_def R12  (SOC, SOE, Op_RegI, 12, r12->as_VMReg());
reg_def R12_H(SOC, SOE, Op_RegI, 12, r12->as_VMReg()->next());

reg_def R13  (SOC, SOE, Op_RegI, 13, r13->as_VMReg());
reg_def R13_H(SOC, SOE, Op_RegI, 13, r13->as_VMReg()->next());

reg_def R14  (SOC, SOE, Op_RegI, 14, r14->as_VMReg());
reg_def R14_H(SOC, SOE, Op_RegI, 14, r14->as_VMReg()->next());

reg_def R15  (SOC, SOE, Op_RegI, 15, r15->as_VMReg());
reg_def R15_H(SOC, SOE, Op_RegI, 15, r15->as_VMReg()->next());


// Floating Point Registers

// Specify priority of register selection within phases of register
// allocation.  Highest priority is first.  A useful heuristic is to
// give registers a low priority when they are required by machine
// instructions, like EAX and EDX on I486, and choose no-save registers
// before save-on-call, & save-on-call before save-on-entry.  Registers
// which participate in fixed calling sequences should come last.
// Registers which are used as pairs must fall on an even boundary.

alloc_class chunk0(R10,         R10_H,
                   R11,         R11_H,
                   R8,          R8_H,
                   R9,          R9_H,
                   R12,         R12_H,
                   RCX,         RCX_H,
                   RBX,         RBX_H,
                   RDI,         RDI_H,
                   RDX,         RDX_H,
                   RSI,         RSI_H,
                   RAX,         RAX_H,
                   RBP,         RBP_H,
                   R13,         R13_H,
                   R14,         R14_H,
                   R15,         R15_H,
                   RSP,         RSP_H);


//----------Architecture Description Register Classes--------------------------
// Several register classes are automatically defined based upon information in
// this architecture description.
// 1) reg_class inline_cache_reg           ( /* as def'd in frame section */ )
// 2) reg_class stack_slots( /* one chunk of stack-based "registers" */ )
//

// Empty register class.
reg_class no_reg();

// Class for all pointer/long registers
reg_class all_reg(RAX, RAX_H,
                  RDX, RDX_H,
                  RBP, RBP_H,
                  RDI, RDI_H,
                  RSI, RSI_H,
                  RCX, RCX_H,
                  RBX, RBX_H,
                  RSP, RSP_H,
                  R8,  R8_H,
                  R9,  R9_H,
                  R10, R10_H,
                  R11, R11_H,
                  R12, R12_H,
                  R13, R13_H,
                  R14, R14_H,
                  R15, R15_H);

// Class for all int registers
reg_class all_int_reg(RAX
                      RDX,
                      RBP,
                      RDI,
                      RSI,
                      RCX,
                      RBX,
                      R8,
                      R9,
                      R10,
                      R11,
                      R12,
                      R13,
                      R14);

// Class for all pointer registers
reg_class any_reg %{
  return _ANY_REG_mask;
%}

// Class for all pointer registers (excluding RSP)
reg_class ptr_reg %{
  return _PTR_REG_mask;
%}

// Class for all pointer registers (excluding RSP and RBP)
reg_class ptr_reg_no_rbp %{
  return _PTR_REG_NO_RBP_mask;
%}

// Class for all pointer registers (excluding RAX and RSP)
reg_class ptr_no_rax_reg %{
  return _PTR_NO_RAX_REG_mask;
%}

// Class for all pointer registers (excluding RAX, RBX, and RSP)
reg_class ptr_no_rax_rbx_reg %{
  return _PTR_NO_RAX_RBX_REG_mask;
%}

// Class for all long registers (excluding RSP)
reg_class long_reg %{
  return _LONG_REG_mask;
%}

// Class for all long registers (excluding RAX, RDX and RSP)
reg_class long_no_rax_rdx_reg %{
  return _LONG_NO_RAX_RDX_REG_mask;
%}

// Class for all long registers (excluding RCX and RSP)
reg_class long_no_rcx_reg %{
  return _LONG_NO_RCX_REG_mask;
%}

// Class for all long registers (excluding RBP and R13)
reg_class long_no_rbp_r13_reg %{
  return _LONG_NO_RBP_R13_REG_mask;
%}

// Class for all int registers (excluding RSP)
reg_class int_reg %{
  return _INT_REG_mask;
%}

// Class for all int registers (excluding RAX, RDX, and RSP)
reg_class int_no_rax_rdx_reg %{
  return _INT_NO_RAX_RDX_REG_mask;
%}

// Class for all int registers (excluding RCX and RSP)
reg_class int_no_rcx_reg %{
  return _INT_NO_RCX_REG_mask;
%}

// Class for all int registers (excluding RBP and R13)
reg_class int_no_rbp_r13_reg %{
  return _INT_NO_RBP_R13_REG_mask;
%}

// Singleton class for RAX pointer register
reg_class ptr_rax_reg(RAX, RAX_H);

// Singleton class for RBX pointer register
reg_class ptr_rbx_reg(RBX, RBX_H);

// Singleton class for RSI pointer register
reg_class ptr_rsi_reg(RSI, RSI_H);

// Singleton class for RBP pointer register
reg_class ptr_rbp_reg(RBP, RBP_H);

// Singleton class for RDI pointer register
reg_class ptr_rdi_reg(RDI, RDI_H);

// Singleton class for stack pointer
reg_class ptr_rsp_reg(RSP, RSP_H);

// Singleton class for TLS pointer
reg_class ptr_r15_reg(R15, R15_H);

// Singleton class for RAX long register
reg_class long_rax_reg(RAX, RAX_H);

// Singleton class for RCX long register
reg_class long_rcx_reg(RCX, RCX_H);

// Singleton class for RDX long register
reg_class long_rdx_reg(RDX, RDX_H);

// Singleton class for RAX int register
reg_class int_rax_reg(RAX);

// Singleton class for RBX int register
reg_class int_rbx_reg(RBX);

// Singleton class for RCX int register
reg_class int_rcx_reg(RCX);

// Singleton class for RCX int register
reg_class int_rdx_reg(RDX);

// Singleton class for RCX int register
reg_class int_rdi_reg(RDI);

// Singleton class for instruction pointer
// reg_class ip_reg(RIP);

%}

//----------SOURCE BLOCK-------------------------------------------------------
// This is a block of C++ code which provides values, functions, and
// definitions necessary in the rest of the architecture description

source_hpp %{

#include "peephole_x86_64.hpp"

%}

// Register masks
source_hpp %{

extern RegMask _ANY_REG_mask;
extern RegMask _PTR_REG_mask;
extern RegMask _PTR_REG_NO_RBP_mask;
extern RegMask _PTR_NO_RAX_REG_mask;
extern RegMask _PTR_NO_RAX_RBX_REG_mask;
extern RegMask _LONG_REG_mask;
extern RegMask _LONG_NO_RAX_RDX_REG_mask;
extern RegMask _LONG_NO_RCX_REG_mask;
extern RegMask _LONG_NO_RBP_R13_REG_mask;
extern RegMask _INT_REG_mask;
extern RegMask _INT_NO_RAX_RDX_REG_mask;
extern RegMask _INT_NO_RCX_REG_mask;
extern RegMask _INT_NO_RBP_R13_REG_mask;
extern RegMask _FLOAT_REG_mask;

extern RegMask _STACK_OR_PTR_REG_mask;
extern RegMask _STACK_OR_LONG_REG_mask;
extern RegMask _STACK_OR_INT_REG_mask;

inline const RegMask& STACK_OR_PTR_REG_mask()  { return _STACK_OR_PTR_REG_mask;  }
inline const RegMask& STACK_OR_LONG_REG_mask() { return _STACK_OR_LONG_REG_mask; }
inline const RegMask& STACK_OR_INT_REG_mask()  { return _STACK_OR_INT_REG_mask;  }

%}

source %{
#define   RELOC_IMM64    Assembler::imm_operand
#define   RELOC_DISP32   Assembler::disp32_operand

#define __ _masm.

RegMask _ANY_REG_mask;
RegMask _PTR_REG_mask;
RegMask _PTR_REG_NO_RBP_mask;
RegMask _PTR_NO_RAX_REG_mask;
RegMask _PTR_NO_RAX_RBX_REG_mask;
RegMask _LONG_REG_mask;
RegMask _LONG_NO_RAX_RDX_REG_mask;
RegMask _LONG_NO_RCX_REG_mask;
RegMask _LONG_NO_RBP_R13_REG_mask;
RegMask _INT_REG_mask;
RegMask _INT_NO_RAX_RDX_REG_mask;
RegMask _INT_NO_RCX_REG_mask;
RegMask _INT_NO_RBP_R13_REG_mask;
RegMask _FLOAT_REG_mask;
RegMask _STACK_OR_PTR_REG_mask;
RegMask _STACK_OR_LONG_REG_mask;
RegMask _STACK_OR_INT_REG_mask;

static bool need_r12_heapbase() {
  return UseCompressedOops;
}

void reg_mask_init() {
  // _ALL_REG_mask is generated by adlc from the all_reg register class below.
  // We derive a number of subsets from it.
  _ANY_REG_mask = _ALL_REG_mask;

  if (PreserveFramePointer) {
    _ANY_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
    _ANY_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next()));
  }
  if (need_r12_heapbase()) {
    _ANY_REG_mask.Remove(OptoReg::as_OptoReg(r12->as_VMReg()));
    _ANY_REG_mask.Remove(OptoReg::as_OptoReg(r12->as_VMReg()->next()));
  }

  _PTR_REG_mask = _ANY_REG_mask;
  _PTR_REG_mask.Remove(OptoReg::as_OptoReg(rsp->as_VMReg()));
  _PTR_REG_mask.Remove(OptoReg::as_OptoReg(rsp->as_VMReg()->next()));
  _PTR_REG_mask.Remove(OptoReg::as_OptoReg(r15->as_VMReg()));
  _PTR_REG_mask.Remove(OptoReg::as_OptoReg(r15->as_VMReg()->next()));

  _STACK_OR_PTR_REG_mask = _PTR_REG_mask;
  _STACK_OR_PTR_REG_mask.OR(STACK_OR_STACK_SLOTS_mask());

  _PTR_REG_NO_RBP_mask = _PTR_REG_mask;
  _PTR_REG_NO_RBP_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
  _PTR_REG_NO_RBP_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next()));

  _PTR_NO_RAX_REG_mask = _PTR_REG_mask;
  _PTR_NO_RAX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()));
  _PTR_NO_RAX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()->next()));

  _PTR_NO_RAX_RBX_REG_mask = _PTR_NO_RAX_REG_mask;
  _PTR_NO_RAX_RBX_REG_mask.Remove(OptoReg::as_OptoReg(rbx->as_VMReg()));
  _PTR_NO_RAX_RBX_REG_mask.Remove(OptoReg::as_OptoReg(rbx->as_VMReg()->next()));

  _LONG_REG_mask = _PTR_REG_mask;
  _STACK_OR_LONG_REG_mask = _LONG_REG_mask;
  _STACK_OR_LONG_REG_mask.OR(STACK_OR_STACK_SLOTS_mask());

  _LONG_NO_RAX_RDX_REG_mask = _LONG_REG_mask;
  _LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()));
  _LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()->next()));
  _LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rdx->as_VMReg()));
  _LONG_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rdx->as_VMReg()->next()));

  _LONG_NO_RCX_REG_mask = _LONG_REG_mask;
  _LONG_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg()));
  _LONG_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg()->next()));

  _LONG_NO_RBP_R13_REG_mask = _LONG_REG_mask;
  _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
  _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next()));
  _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()));
  _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()->next()));

  _INT_REG_mask = _ALL_INT_REG_mask;
  if (PreserveFramePointer) {
    _INT_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
  }
  if (need_r12_heapbase()) {
    _INT_REG_mask.Remove(OptoReg::as_OptoReg(r12->as_VMReg()));
  }

  _STACK_OR_INT_REG_mask = _INT_REG_mask;
  _STACK_OR_INT_REG_mask.OR(STACK_OR_STACK_SLOTS_mask());

  _INT_NO_RAX_RDX_REG_mask = _INT_REG_mask;
  _INT_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rax->as_VMReg()));
  _INT_NO_RAX_RDX_REG_mask.Remove(OptoReg::as_OptoReg(rdx->as_VMReg()));

  _INT_NO_RCX_REG_mask = _INT_REG_mask;
  _INT_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg()));

  _INT_NO_RBP_R13_REG_mask = _INT_REG_mask;
  _INT_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
  _INT_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()));

  // _FLOAT_REG_LEGACY_mask/_FLOAT_REG_EVEX_mask is generated by adlc
  // from the float_reg_legacy/float_reg_evex register class.
  _FLOAT_REG_mask = VM_Version::supports_evex() ? _FLOAT_REG_EVEX_mask : _FLOAT_REG_LEGACY_mask;
}

static bool generate_vzeroupper(Compile* C) {
  return (VM_Version::supports_vzeroupper() && (C->max_vector_size() > 16 || C->clear_upper_avx() == true)) ? true: false;  // Generate vzeroupper
}

static int clear_avx_size() {
  return generate_vzeroupper(Compile::current()) ? 3: 0;  // vzeroupper
}

// !!!!! Special hack to get all types of calls to specify the byte offset
//       from the start of the call to the point where the return address
//       will point.
int MachCallStaticJavaNode::ret_addr_offset()
{
  int offset = 5; // 5 bytes from start of call to where return address points
  offset += clear_avx_size();
  return offset;
}

int MachCallDynamicJavaNode::ret_addr_offset()
{
  int offset = 15; // 15 bytes from start of call to where return address points
  offset += clear_avx_size();
  return offset;
}

int MachCallRuntimeNode::ret_addr_offset() {
  int offset = 13; // movq r10,#addr; callq (r10)
  if (this->ideal_Opcode() != Op_CallLeafVector) {
    offset += clear_avx_size();
  }
  return offset;
}
//
// Compute padding required for nodes which need alignment
//

// The address of the call instruction needs to be 4-byte aligned to
// ensure that it does not span a cache line so that it can be patched.
int CallStaticJavaDirectNode::compute_padding(int current_offset) const
{
  current_offset += clear_avx_size(); // skip vzeroupper
  current_offset += 1; // skip call opcode byte
  return align_up(current_offset, alignment_required()) - current_offset;
}

// The address of the call instruction needs to be 4-byte aligned to
// ensure that it does not span a cache line so that it can be patched.
int CallDynamicJavaDirectNode::compute_padding(int current_offset) const
{
  current_offset += clear_avx_size(); // skip vzeroupper
  current_offset += 11; // skip movq instruction + call opcode byte
  return align_up(current_offset, alignment_required()) - current_offset;
}

// EMIT_RM()
void emit_rm(CodeBuffer &cbuf, int f1, int f2, int f3) {
  unsigned char c = (unsigned char) ((f1 << 6) | (f2 << 3) | f3);
  cbuf.insts()->emit_int8(c);
}

// EMIT_CC()
void emit_cc(CodeBuffer &cbuf, int f1, int f2) {
  unsigned char c = (unsigned char) (f1 | f2);
  cbuf.insts()->emit_int8(c);
}

// EMIT_OPCODE()
void emit_opcode(CodeBuffer &cbuf, int code) {
  cbuf.insts()->emit_int8((unsigned char) code);
}

// EMIT_OPCODE() w/ relocation information
void emit_opcode(CodeBuffer &cbuf,
                 int code, relocInfo::relocType reloc, int offset, int format)
{
  cbuf.relocate(cbuf.insts_mark() + offset, reloc, format);
  emit_opcode(cbuf, code);
}

// EMIT_D8()
void emit_d8(CodeBuffer &cbuf, int d8) {
  cbuf.insts()->emit_int8((unsigned char) d8);
}

// EMIT_D16()
void emit_d16(CodeBuffer &cbuf, int d16) {
  cbuf.insts()->emit_int16(d16);
}

// EMIT_D32()
void emit_d32(CodeBuffer &cbuf, int d32) {
  cbuf.insts()->emit_int32(d32);
}

// EMIT_D64()
void emit_d64(CodeBuffer &cbuf, int64_t d64) {
  cbuf.insts()->emit_int64(d64);
}

// emit 32 bit value and construct relocation entry from relocInfo::relocType
void emit_d32_reloc(CodeBuffer& cbuf,
                    int d32,
                    relocInfo::relocType reloc,
                    int format)
{
  assert(reloc != relocInfo::external_word_type, "use 2-arg emit_d32_reloc");
  cbuf.relocate(cbuf.insts_mark(), reloc, format);
  cbuf.insts()->emit_int32(d32);
}

// emit 32 bit value and construct relocation entry from RelocationHolder
void emit_d32_reloc(CodeBuffer& cbuf, int d32, RelocationHolder const& rspec, int format) {
#ifdef ASSERT
  if (rspec.reloc()->type() == relocInfo::oop_type &&
      d32 != 0 && d32 != (intptr_t) Universe::non_oop_word()) {
    assert(Universe::heap()->is_in((address)(intptr_t)d32), "should be real oop");
    assert(oopDesc::is_oop(cast_to_oop((intptr_t)d32)), "cannot embed broken oops in code");
  }
#endif
  cbuf.relocate(cbuf.insts_mark(), rspec, format);
  cbuf.insts()->emit_int32(d32);
}

void emit_d32_reloc(CodeBuffer& cbuf, address addr) {
  address next_ip = cbuf.insts_end() + 4;
  emit_d32_reloc(cbuf, (int) (addr - next_ip),
                 external_word_Relocation::spec(addr),
                 RELOC_DISP32);
}


// emit 64 bit value and construct relocation entry from relocInfo::relocType
void emit_d64_reloc(CodeBuffer& cbuf, int64_t d64, relocInfo::relocType reloc, int format) {
  cbuf.relocate(cbuf.insts_mark(), reloc, format);
  cbuf.insts()->emit_int64(d64);
}

// emit 64 bit value and construct relocation entry from RelocationHolder
void emit_d64_reloc(CodeBuffer& cbuf, int64_t d64, RelocationHolder const& rspec, int format) {
#ifdef ASSERT
  if (rspec.reloc()->type() == relocInfo::oop_type &&
      d64 != 0 && d64 != (int64_t) Universe::non_oop_word()) {
    assert(Universe::heap()->is_in((address)d64), "should be real oop");
    assert(oopDesc::is_oop(cast_to_oop(d64)), "cannot embed broken oops in code");
  }
#endif
  cbuf.relocate(cbuf.insts_mark(), rspec, format);
  cbuf.insts()->emit_int64(d64);
}

// Access stack slot for load or store
void store_to_stackslot(CodeBuffer &cbuf, int opcode, int rm_field, int disp)
{
  emit_opcode(cbuf, opcode);                  // (e.g., FILD   [RSP+src])
  if (-0x80 <= disp && disp < 0x80) {
    emit_rm(cbuf, 0x01, rm_field, RSP_enc);   // R/M byte
    emit_rm(cbuf, 0x00, RSP_enc, RSP_enc);    // SIB byte
    emit_d8(cbuf, disp);     // Displacement  // R/M byte
  } else {
    emit_rm(cbuf, 0x02, rm_field, RSP_enc);   // R/M byte
    emit_rm(cbuf, 0x00, RSP_enc, RSP_enc);    // SIB byte
    emit_d32(cbuf, disp);     // Displacement // R/M byte
  }
}

   // rRegI ereg, memory mem) %{    // emit_reg_mem
void encode_RegMem(CodeBuffer &cbuf,
                   int reg,
                   int base, int index, int scale, int disp, relocInfo::relocType disp_reloc)
{
  assert(disp_reloc == relocInfo::none, "cannot have disp");
  int regenc = reg & 7;
  int baseenc = base & 7;
  int indexenc = index & 7;

  // There is no index & no scale, use form without SIB byte
  if (index == 0x4 && scale == 0 && base != RSP_enc && base != R12_enc) {
    // If no displacement, mode is 0x0; unless base is [RBP] or [R13]
    if (disp == 0 && base != RBP_enc && base != R13_enc) {
      emit_rm(cbuf, 0x0, regenc, baseenc); // *
    } else if (-0x80 <= disp && disp < 0x80 && disp_reloc == relocInfo::none) {
      // If 8-bit displacement, mode 0x1
      emit_rm(cbuf, 0x1, regenc, baseenc); // *
      emit_d8(cbuf, disp);
    } else {
      // If 32-bit displacement
      if (base == -1) { // Special flag for absolute address
        emit_rm(cbuf, 0x0, regenc, 0x5); // *
        if (disp_reloc != relocInfo::none) {
          emit_d32_reloc(cbuf, disp, relocInfo::oop_type, RELOC_DISP32);
        } else {
          emit_d32(cbuf, disp);
        }
      } else {
        // Normal base + offset
        emit_rm(cbuf, 0x2, regenc, baseenc); // *
        if (disp_reloc != relocInfo::none) {
          emit_d32_reloc(cbuf, disp, relocInfo::oop_type, RELOC_DISP32);
        } else {
          emit_d32(cbuf, disp);
        }
      }
    }
  } else {
    // Else, encode with the SIB byte
    // If no displacement, mode is 0x0; unless base is [RBP] or [R13]
    if (disp == 0 && base != RBP_enc && base != R13_enc) {
      // If no displacement
      emit_rm(cbuf, 0x0, regenc, 0x4); // *
      emit_rm(cbuf, scale, indexenc, baseenc);
    } else {
      if (-0x80 <= disp && disp < 0x80 && disp_reloc == relocInfo::none) {
        // If 8-bit displacement, mode 0x1
        emit_rm(cbuf, 0x1, regenc, 0x4); // *
        emit_rm(cbuf, scale, indexenc, baseenc);
        emit_d8(cbuf, disp);
      } else {
        // If 32-bit displacement
        if (base == 0x04 ) {
          emit_rm(cbuf, 0x2, regenc, 0x4);
          emit_rm(cbuf, scale, indexenc, 0x04); // XXX is this valid???
        } else {
          emit_rm(cbuf, 0x2, regenc, 0x4);
          emit_rm(cbuf, scale, indexenc, baseenc); // *
        }
        if (disp_reloc != relocInfo::none) {
          emit_d32_reloc(cbuf, disp, relocInfo::oop_type, RELOC_DISP32);
        } else {
          emit_d32(cbuf, disp);
        }
      }
    }
  }
}

// This could be in MacroAssembler but it's fairly C2 specific
void emit_cmpfp_fixup(MacroAssembler& _masm) {
  Label exit;
  __ jccb(Assembler::noParity, exit);
  __ pushf();
  //
  // comiss/ucomiss instructions set ZF,PF,CF flags and
  // zero OF,AF,SF for NaN values.
  // Fixup flags by zeroing ZF,PF so that compare of NaN
  // values returns 'less than' result (CF is set).
  // Leave the rest of flags unchanged.
  //
  //    7 6 5 4 3 2 1 0
  //   |S|Z|r|A|r|P|r|C|  (r - reserved bit)
  //    0 0 1 0 1 0 1 1   (0x2B)
  //
  __ andq(Address(rsp, 0), 0xffffff2b);
  __ popf();
  __ bind(exit);
}

void emit_cmpfp3(MacroAssembler& _masm, Register dst) {
  Label done;
  __ movl(dst, -1);
  __ jcc(Assembler::parity, done);
  __ jcc(Assembler::below, done);
  __ setb(Assembler::notEqual, dst);
  __ movzbl(dst, dst);
  __ bind(done);
}

// Math.min()    # Math.max()
// --------------------------
// ucomis[s/d]   #
// ja   -> b     # a
// jp   -> NaN   # NaN
// jb   -> a     # b
// je            #
// |-jz -> a | b # a & b
// |    -> a     #
void emit_fp_min_max(MacroAssembler& _masm, XMMRegister dst,
                     XMMRegister a, XMMRegister b,
                     XMMRegister xmmt, Register rt,
                     bool min, bool single) {

  Label nan, zero, below, above, done;

  if (single)
    __ ucomiss(a, b);
  else
    __ ucomisd(a, b);

  if (dst->encoding() != (min ? b : a)->encoding())
    __ jccb(Assembler::above, above); // CF=0 & ZF=0
  else
    __ jccb(Assembler::above, done);

  __ jccb(Assembler::parity, nan);  // PF=1
  __ jccb(Assembler::below, below); // CF=1

  // equal
  __ vpxor(xmmt, xmmt, xmmt, Assembler::AVX_128bit);
  if (single) {
    __ ucomiss(a, xmmt);
    __ jccb(Assembler::equal, zero);

    __ movflt(dst, a);
    __ jmp(done);
  }
  else {
    __ ucomisd(a, xmmt);
    __ jccb(Assembler::equal, zero);

    __ movdbl(dst, a);
    __ jmp(done);
  }

  __ bind(zero);
  if (min)
    __ vpor(dst, a, b, Assembler::AVX_128bit);
  else
    __ vpand(dst, a, b, Assembler::AVX_128bit);

  __ jmp(done);

  __ bind(above);
  if (single)
    __ movflt(dst, min ? b : a);
  else
    __ movdbl(dst, min ? b : a);

  __ jmp(done);

  __ bind(nan);
  if (single) {
    __ movl(rt, 0x7fc00000); // Float.NaN
    __ movdl(dst, rt);
  }
  else {
    __ mov64(rt, 0x7ff8000000000000L); // Double.NaN
    __ movdq(dst, rt);
  }
  __ jmp(done);

  __ bind(below);
  if (single)
    __ movflt(dst, min ? a : b);
  else
    __ movdbl(dst, min ? a : b);

  __ bind(done);
}

//=============================================================================
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;

int ConstantTable::calculate_table_base_offset() const {
  return 0;  // absolute addressing, no offset
}

bool MachConstantBaseNode::requires_postalloc_expand() const { return false; }
void MachConstantBaseNode::postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_) {
  ShouldNotReachHere();
}

void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
  // Empty encoding
}

uint MachConstantBaseNode::size(PhaseRegAlloc* ra_) const {
  return 0;
}

#ifndef PRODUCT
void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
  st->print("# MachConstantBaseNode (empty encoding)");
}
#endif


//=============================================================================
#ifndef PRODUCT
void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
  Compile* C = ra_->C;

  int framesize = C->output()->frame_size_in_bytes();
  int bangsize = C->output()->bang_size_in_bytes();
  assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
  // Remove wordSize for return addr which is already pushed.
  framesize -= wordSize;

  if (C->output()->need_stack_bang(bangsize)) {
    framesize -= wordSize;
    st->print("# stack bang (%d bytes)", bangsize);
    st->print("\n\t");
    st->print("pushq   rbp\t# Save rbp");
    if (PreserveFramePointer) {
        st->print("\n\t");
        st->print("movq    rbp, rsp\t# Save the caller's SP into rbp");
    }
    if (framesize) {
      st->print("\n\t");
      st->print("subq    rsp, #%d\t# Create frame",framesize);
    }
  } else {
    st->print("subq    rsp, #%d\t# Create frame",framesize);
    st->print("\n\t");
    framesize -= wordSize;
    st->print("movq    [rsp + #%d], rbp\t# Save rbp",framesize);
    if (PreserveFramePointer) {
      st->print("\n\t");
      st->print("movq    rbp, rsp\t# Save the caller's SP into rbp");
      if (framesize > 0) {
        st->print("\n\t");
        st->print("addq    rbp, #%d", framesize);
      }
    }
  }

  if (VerifyStackAtCalls) {
    st->print("\n\t");
    framesize -= wordSize;
    st->print("movq    [rsp + #%d], 0xbadb100d\t# Majik cookie for stack depth check",framesize);
#ifdef ASSERT
    st->print("\n\t");
    st->print("# stack alignment check");
#endif
  }
  if (C->stub_function() != NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) {
    st->print("\n\t");
    st->print("cmpl    [r15_thread + #disarmed_offset], #disarmed_value\t");
    st->print("\n\t");
    st->print("je      fast_entry\t");
    st->print("\n\t");
    st->print("call    #nmethod_entry_barrier_stub\t");
    st->print("\n\tfast_entry:");
  }
  st->cr();
}
#endif

void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  Compile* C = ra_->C;
  C2_MacroAssembler _masm(&cbuf);

  int framesize = C->output()->frame_size_in_bytes();
  int bangsize = C->output()->bang_size_in_bytes();

  if (C->clinit_barrier_on_entry()) {
    assert(VM_Version::supports_fast_class_init_checks(), "sanity");
    assert(!C->method()->holder()->is_not_initialized(), "initialization should have been started");

    Label L_skip_barrier;
    Register klass = rscratch1;

    __ mov_metadata(klass, C->method()->holder()->constant_encoding());
    __ clinit_barrier(klass, r15_thread, &L_skip_barrier /*L_fast_path*/);

    __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path

    __ bind(L_skip_barrier);
  }

  __ verified_entry(framesize, C->output()->need_stack_bang(bangsize)?bangsize:0, false, C->stub_function() != NULL);

  C->output()->set_frame_complete(cbuf.insts_size());

  if (C->has_mach_constant_base_node()) {
    // NOTE: We set the table base offset here because users might be
    // emitted before MachConstantBaseNode.
    ConstantTable& constant_table = C->output()->constant_table();
    constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
  }
}

uint MachPrologNode::size(PhaseRegAlloc* ra_) const
{
  return MachNode::size(ra_); // too many variables; just compute it
                              // the hard way
}

int MachPrologNode::reloc() const
{
  return 0; // a large enough number
}

//=============================================================================
#ifndef PRODUCT
void MachEpilogNode::format(PhaseRegAlloc* ra_, outputStream* st) const
{
  Compile* C = ra_->C;
  if (generate_vzeroupper(C)) {
    st->print("vzeroupper");
    st->cr(); st->print("\t");
  }

  int framesize = C->output()->frame_size_in_bytes();
  assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
  // Remove word for return adr already pushed
  // and RBP
  framesize -= 2*wordSize;

  if (framesize) {
    st->print_cr("addq    rsp, %d\t# Destroy frame", framesize);
    st->print("\t");
  }

  st->print_cr("popq    rbp");
  if (do_polling() && C->is_method_compilation()) {
    st->print("\t");
    st->print_cr("cmpq    rsp, poll_offset[r15_thread] \n\t"
                 "ja      #safepoint_stub\t"
                 "# Safepoint: poll for GC");
  }
}
#endif

void MachEpilogNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const
{
  Compile* C = ra_->C;
  MacroAssembler _masm(&cbuf);

  if (generate_vzeroupper(C)) {
    // Clear upper bits of YMM registers when current compiled code uses
    // wide vectors to avoid AVX <-> SSE transition penalty during call.
    __ vzeroupper();
  }

  int framesize = C->output()->frame_size_in_bytes();
  assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
  // Remove word for return adr already pushed
  // and RBP
  framesize -= 2*wordSize;

  // Note that VerifyStackAtCalls' Majik cookie does not change the frame size popped here

  if (framesize) {
    emit_opcode(cbuf, Assembler::REX_W);
    if (framesize < 0x80) {
      emit_opcode(cbuf, 0x83); // addq rsp, #framesize
      emit_rm(cbuf, 0x3, 0x00, RSP_enc);
      emit_d8(cbuf, framesize);
    } else {
      emit_opcode(cbuf, 0x81); // addq rsp, #framesize
      emit_rm(cbuf, 0x3, 0x00, RSP_enc);
      emit_d32(cbuf, framesize);
    }
  }

  // popq rbp
  emit_opcode(cbuf, 0x58 | RBP_enc);

  if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
    __ reserved_stack_check();
  }

  if (do_polling() && C->is_method_compilation()) {
    MacroAssembler _masm(&cbuf);
    Label dummy_label;
    Label* code_stub = &dummy_label;
    if (!C->output()->in_scratch_emit_size()) {
      code_stub = &C->output()->safepoint_poll_table()->add_safepoint(__ offset());
    }
    __ relocate(relocInfo::poll_return_type);
    __ safepoint_poll(*code_stub, r15_thread, true /* at_return */, true /* in_nmethod */);
  }
}

uint MachEpilogNode::size(PhaseRegAlloc* ra_) const
{
  return MachNode::size(ra_); // too many variables; just compute it
                              // the hard way
}

int MachEpilogNode::reloc() const
{
  return 2; // a large enough number
}

const Pipeline* MachEpilogNode::pipeline() const
{
  return MachNode::pipeline_class();
}

//=============================================================================

enum RC {
  rc_bad,
  rc_int,
  rc_kreg,
  rc_float,
  rc_stack
};

static enum RC rc_class(OptoReg::Name reg)
{
  if( !OptoReg::is_valid(reg)  ) return rc_bad;

  if (OptoReg::is_stack(reg)) return rc_stack;

  VMReg r = OptoReg::as_VMReg(reg);

  if (r->is_Register()) return rc_int;

  if (r->is_KRegister()) return rc_kreg;

  assert(r->is_XMMRegister(), "must be");
  return rc_float;
}

// Next two methods are shared by 32- and 64-bit VM. They are defined in x86.ad.
static void vec_mov_helper(CodeBuffer *cbuf, int src_lo, int dst_lo,
                          int src_hi, int dst_hi, uint ireg, outputStream* st);

void vec_spill_helper(CodeBuffer *cbuf, bool is_load,
                     int stack_offset, int reg, uint ireg, outputStream* st);

static void vec_stack_to_stack_helper(CodeBuffer *cbuf, int src_offset,
                                      int dst_offset, uint ireg, outputStream* st) {
  if (cbuf) {
    MacroAssembler _masm(cbuf);
    switch (ireg) {
    case Op_VecS:
      __ movq(Address(rsp, -8), rax);
      __ movl(rax, Address(rsp, src_offset));
      __ movl(Address(rsp, dst_offset), rax);
      __ movq(rax, Address(rsp, -8));
      break;
    case Op_VecD:
      __ pushq(Address(rsp, src_offset));
      __ popq (Address(rsp, dst_offset));
      break;
    case Op_VecX:
      __ pushq(Address(rsp, src_offset));
      __ popq (Address(rsp, dst_offset));
      __ pushq(Address(rsp, src_offset+8));
      __ popq (Address(rsp, dst_offset+8));
      break;
    case Op_VecY:
      __ vmovdqu(Address(rsp, -32), xmm0);
      __ vmovdqu(xmm0, Address(rsp, src_offset));
      __ vmovdqu(Address(rsp, dst_offset), xmm0);
      __ vmovdqu(xmm0, Address(rsp, -32));
      break;
    case Op_VecZ:
      __ evmovdquq(Address(rsp, -64), xmm0, 2);
      __ evmovdquq(xmm0, Address(rsp, src_offset), 2);
      __ evmovdquq(Address(rsp, dst_offset), xmm0, 2);
      __ evmovdquq(xmm0, Address(rsp, -64), 2);
      break;
    default:
      ShouldNotReachHere();
    }
#ifndef PRODUCT
  } else {
    switch (ireg) {
    case Op_VecS:
      st->print("movq    [rsp - #8], rax\t# 32-bit mem-mem spill\n\t"
                "movl    rax, [rsp + #%d]\n\t"
                "movl    [rsp + #%d], rax\n\t"
                "movq    rax, [rsp - #8]",
                src_offset, dst_offset);
      break;
    case Op_VecD:
      st->print("pushq   [rsp + #%d]\t# 64-bit mem-mem spill\n\t"
                "popq    [rsp + #%d]",
                src_offset, dst_offset);
      break;
     case Op_VecX:
      st->print("pushq   [rsp + #%d]\t# 128-bit mem-mem spill\n\t"
                "popq    [rsp + #%d]\n\t"
                "pushq   [rsp + #%d]\n\t"
                "popq    [rsp + #%d]",
                src_offset, dst_offset, src_offset+8, dst_offset+8);
      break;
    case Op_VecY:
      st->print("vmovdqu [rsp - #32], xmm0\t# 256-bit mem-mem spill\n\t"
                "vmovdqu xmm0, [rsp + #%d]\n\t"
                "vmovdqu [rsp + #%d], xmm0\n\t"
                "vmovdqu xmm0, [rsp - #32]",
                src_offset, dst_offset);
      break;
    case Op_VecZ:
      st->print("vmovdqu [rsp - #64], xmm0\t# 512-bit mem-mem spill\n\t"
                "vmovdqu xmm0, [rsp + #%d]\n\t"
                "vmovdqu [rsp + #%d], xmm0\n\t"
                "vmovdqu xmm0, [rsp - #64]",
                src_offset, dst_offset);
      break;
    default:
      ShouldNotReachHere();
    }
#endif
  }
}

uint MachSpillCopyNode::implementation(CodeBuffer* cbuf,
                                       PhaseRegAlloc* ra_,
                                       bool do_size,
                                       outputStream* st) const {
  assert(cbuf != NULL || st  != NULL, "sanity");
  // Get registers to move
  OptoReg::Name src_second = ra_->get_reg_second(in(1));
  OptoReg::Name src_first = ra_->get_reg_first(in(1));
  OptoReg::Name dst_second = ra_->get_reg_second(this);
  OptoReg::Name dst_first = ra_->get_reg_first(this);

  enum RC src_second_rc = rc_class(src_second);
  enum RC src_first_rc = rc_class(src_first);
  enum RC dst_second_rc = rc_class(dst_second);
  enum RC dst_first_rc = rc_class(dst_first);

  assert(OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first),
         "must move at least 1 register" );

  if (src_first == dst_first && src_second == dst_second) {
    // Self copy, no move
    return 0;
  }
  if (bottom_type()->isa_vect() != NULL && bottom_type()->isa_vectmask() == NULL) {
    uint ireg = ideal_reg();
    assert((src_first_rc != rc_int && dst_first_rc != rc_int), "sanity");
    assert((ireg == Op_VecS || ireg == Op_VecD || ireg == Op_VecX || ireg == Op_VecY || ireg == Op_VecZ ), "sanity");
    if( src_first_rc == rc_stack && dst_first_rc == rc_stack ) {
      // mem -> mem
      int src_offset = ra_->reg2offset(src_first);
      int dst_offset = ra_->reg2offset(dst_first);
      vec_stack_to_stack_helper(cbuf, src_offset, dst_offset, ireg, st);
    } else if (src_first_rc == rc_float && dst_first_rc == rc_float ) {
      vec_mov_helper(cbuf, src_first, dst_first, src_second, dst_second, ireg, st);
    } else if (src_first_rc == rc_float && dst_first_rc == rc_stack ) {
      int stack_offset = ra_->reg2offset(dst_first);
      vec_spill_helper(cbuf, false, stack_offset, src_first, ireg, st);
    } else if (src_first_rc == rc_stack && dst_first_rc == rc_float ) {
      int stack_offset = ra_->reg2offset(src_first);
      vec_spill_helper(cbuf, true,  stack_offset, dst_first, ireg, st);
    } else {
      ShouldNotReachHere();
    }
    return 0;
  }
  if (src_first_rc == rc_stack) {
    // mem ->
    if (dst_first_rc == rc_stack) {
      // mem -> mem
      assert(src_second != dst_first, "overlap");
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        int src_offset = ra_->reg2offset(src_first);
        int dst_offset = ra_->reg2offset(dst_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ pushq(Address(rsp, src_offset));
          __ popq (Address(rsp, dst_offset));
#ifndef PRODUCT
        } else {
          st->print("pushq   [rsp + #%d]\t# 64-bit mem-mem spill\n\t"
                    "popq    [rsp + #%d]",
                     src_offset, dst_offset);
#endif
        }
      } else {
        // 32-bit
        assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform");
        assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform");
        // No pushl/popl, so:
        int src_offset = ra_->reg2offset(src_first);
        int dst_offset = ra_->reg2offset(dst_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movq(Address(rsp, -8), rax);
          __ movl(rax, Address(rsp, src_offset));
          __ movl(Address(rsp, dst_offset), rax);
          __ movq(rax, Address(rsp, -8));
#ifndef PRODUCT
        } else {
          st->print("movq    [rsp - #8], rax\t# 32-bit mem-mem spill\n\t"
                    "movl    rax, [rsp + #%d]\n\t"
                    "movl    [rsp + #%d], rax\n\t"
                    "movq    rax, [rsp - #8]",
                     src_offset, dst_offset);
#endif
        }
      }
      return 0;
    } else if (dst_first_rc == rc_int) {
      // mem -> gpr
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        int offset = ra_->reg2offset(src_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movq(as_Register(Matcher::_regEncode[dst_first]), Address(rsp, offset));
#ifndef PRODUCT
        } else {
          st->print("movq    %s, [rsp + #%d]\t# spill",
                     Matcher::regName[dst_first],
                     offset);
#endif
        }
      } else {
        // 32-bit
        assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform");
        assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform");
        int offset = ra_->reg2offset(src_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movl(as_Register(Matcher::_regEncode[dst_first]), Address(rsp, offset));
#ifndef PRODUCT
        } else {
          st->print("movl    %s, [rsp + #%d]\t# spill",
                     Matcher::regName[dst_first],
                     offset);
#endif
        }
      }
      return 0;
    } else if (dst_first_rc == rc_float) {
      // mem-> xmm
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        int offset = ra_->reg2offset(src_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movdbl( as_XMMRegister(Matcher::_regEncode[dst_first]), Address(rsp, offset));
#ifndef PRODUCT
        } else {
          st->print("%s  %s, [rsp + #%d]\t# spill",
                     UseXmmLoadAndClearUpper ? "movsd " : "movlpd",
                     Matcher::regName[dst_first],
                     offset);
#endif
        }
      } else {
        // 32-bit
        assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform");
        assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform");
        int offset = ra_->reg2offset(src_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movflt( as_XMMRegister(Matcher::_regEncode[dst_first]), Address(rsp, offset));
#ifndef PRODUCT
        } else {
          st->print("movss   %s, [rsp + #%d]\t# spill",
                     Matcher::regName[dst_first],
                     offset);
#endif
        }
      }
      return 0;
    } else if (dst_first_rc == rc_kreg) {
      // mem -> kreg
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        int offset = ra_->reg2offset(src_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ kmov(as_KRegister(Matcher::_regEncode[dst_first]), Address(rsp, offset));
#ifndef PRODUCT
        } else {
          st->print("kmovq   %s, [rsp + #%d]\t# spill",
                     Matcher::regName[dst_first],
                     offset);
#endif
        }
      }
      return 0;
    }
  } else if (src_first_rc == rc_int) {
    // gpr ->
    if (dst_first_rc == rc_stack) {
      // gpr -> mem
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        int offset = ra_->reg2offset(dst_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movq(Address(rsp, offset), as_Register(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("movq    [rsp + #%d], %s\t# spill",
                     offset,
                     Matcher::regName[src_first]);
#endif
        }
      } else {
        // 32-bit
        assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform");
        assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform");
        int offset = ra_->reg2offset(dst_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movl(Address(rsp, offset), as_Register(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("movl    [rsp + #%d], %s\t# spill",
                     offset,
                     Matcher::regName[src_first]);
#endif
        }
      }
      return 0;
    } else if (dst_first_rc == rc_int) {
      // gpr -> gpr
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movq(as_Register(Matcher::_regEncode[dst_first]),
                  as_Register(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("movq    %s, %s\t# spill",
                     Matcher::regName[dst_first],
                     Matcher::regName[src_first]);
#endif
        }
        return 0;
      } else {
        // 32-bit
        assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform");
        assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform");
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movl(as_Register(Matcher::_regEncode[dst_first]),
                  as_Register(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("movl    %s, %s\t# spill",
                     Matcher::regName[dst_first],
                     Matcher::regName[src_first]);
#endif
        }
        return 0;
      }
    } else if (dst_first_rc == rc_float) {
      // gpr -> xmm
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movdq( as_XMMRegister(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("movdq   %s, %s\t# spill",
                     Matcher::regName[dst_first],
                     Matcher::regName[src_first]);
#endif
        }
      } else {
        // 32-bit
        assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform");
        assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform");
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movdl( as_XMMRegister(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("movdl   %s, %s\t# spill",
                     Matcher::regName[dst_first],
                     Matcher::regName[src_first]);
#endif
        }
      }
      return 0;
    } else if (dst_first_rc == rc_kreg) {
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ kmov(as_KRegister(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first]));
  #ifndef PRODUCT
        } else {
           st->print("kmovq   %s, %s\t# spill",
                       Matcher::regName[dst_first],
                       Matcher::regName[src_first]);
  #endif
        }
      }
      Unimplemented();
      return 0;
    }
  } else if (src_first_rc == rc_float) {
    // xmm ->
    if (dst_first_rc == rc_stack) {
      // xmm -> mem
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        int offset = ra_->reg2offset(dst_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movdbl( Address(rsp, offset), as_XMMRegister(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("movsd   [rsp + #%d], %s\t# spill",
                     offset,
                     Matcher::regName[src_first]);
#endif
        }
      } else {
        // 32-bit
        assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform");
        assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform");
        int offset = ra_->reg2offset(dst_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movflt(Address(rsp, offset), as_XMMRegister(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("movss   [rsp + #%d], %s\t# spill",
                     offset,
                     Matcher::regName[src_first]);
#endif
        }
      }
      return 0;
    } else if (dst_first_rc == rc_int) {
      // xmm -> gpr
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movdq( as_Register(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("movdq   %s, %s\t# spill",
                     Matcher::regName[dst_first],
                     Matcher::regName[src_first]);
#endif
        }
      } else {
        // 32-bit
        assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform");
        assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform");
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movdl( as_Register(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("movdl   %s, %s\t# spill",
                     Matcher::regName[dst_first],
                     Matcher::regName[src_first]);
#endif
        }
      }
      return 0;
    } else if (dst_first_rc == rc_float) {
      // xmm -> xmm
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movdbl( as_XMMRegister(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("%s  %s, %s\t# spill",
                     UseXmmRegToRegMoveAll ? "movapd" : "movsd ",
                     Matcher::regName[dst_first],
                     Matcher::regName[src_first]);
#endif
        }
      } else {
        // 32-bit
        assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform");
        assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform");
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ movflt( as_XMMRegister(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("%s  %s, %s\t# spill",
                     UseXmmRegToRegMoveAll ? "movaps" : "movss ",
                     Matcher::regName[dst_first],
                     Matcher::regName[src_first]);
#endif
        }
      }
      return 0;
    } else if (dst_first_rc == rc_kreg) {
      assert(false, "Illegal spilling");
      return 0;
    }
  } else if (src_first_rc == rc_kreg) {
    if (dst_first_rc == rc_stack) {
      // mem -> kreg
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        int offset = ra_->reg2offset(dst_first);
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ kmov(Address(rsp, offset), as_KRegister(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
          st->print("kmovq   [rsp + #%d] , %s\t# spill",
                     offset,
                     Matcher::regName[src_first]);
#endif
        }
      }
      return 0;
    } else if (dst_first_rc == rc_int) {
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ kmov(as_Register(Matcher::_regEncode[dst_first]), as_KRegister(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
         st->print("kmovq   %s, %s\t# spill",
                     Matcher::regName[dst_first],
                     Matcher::regName[src_first]);
#endif
        }
      }
      Unimplemented();
      return 0;
    } else if (dst_first_rc == rc_kreg) {
      if ((src_first & 1) == 0 && src_first + 1 == src_second &&
          (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
        // 64-bit
        if (cbuf) {
          MacroAssembler _masm(cbuf);
          __ kmov(as_KRegister(Matcher::_regEncode[dst_first]), as_KRegister(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
        } else {
         st->print("kmovq   %s, %s\t# spill",
                     Matcher::regName[dst_first],
                     Matcher::regName[src_first]);
#endif
        }
      }
      return 0;
    } else if (dst_first_rc == rc_float) {
      assert(false, "Illegal spill");
      return 0;
    }
  }

  assert(0," foo ");
  Unimplemented();
  return 0;
}

#ifndef PRODUCT
void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream* st) const {
  implementation(NULL, ra_, false, st);
}
#endif

void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  implementation(&cbuf, ra_, false, NULL);
}

uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const {
  return MachNode::size(ra_);
}

//=============================================================================
#ifndef PRODUCT
void BoxLockNode::format(PhaseRegAlloc* ra_, outputStream* st) const
{
  int offset = ra_->reg2offset(in_RegMask(0).find_first_elem());
  int reg = ra_->get_reg_first(this);
  st->print("leaq    %s, [rsp + #%d]\t# box lock",
            Matcher::regName[reg], offset);
}
#endif

void BoxLockNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const
{
  int offset = ra_->reg2offset(in_RegMask(0).find_first_elem());
  int reg = ra_->get_encode(this);
  if (offset >= 0x80) {
    emit_opcode(cbuf, reg < 8 ? Assembler::REX_W : Assembler::REX_WR);
    emit_opcode(cbuf, 0x8D); // LEA  reg,[SP+offset]
    emit_rm(cbuf, 0x2, reg & 7, 0x04);
    emit_rm(cbuf, 0x0, 0x04, RSP_enc);
    emit_d32(cbuf, offset);
  } else {
    emit_opcode(cbuf, reg < 8 ? Assembler::REX_W : Assembler::REX_WR);
    emit_opcode(cbuf, 0x8D); // LEA  reg,[SP+offset]
    emit_rm(cbuf, 0x1, reg & 7, 0x04);
    emit_rm(cbuf, 0x0, 0x04, RSP_enc);
    emit_d8(cbuf, offset);
  }
}

uint BoxLockNode::size(PhaseRegAlloc *ra_) const
{
  int offset = ra_->reg2offset(in_RegMask(0).find_first_elem());
  return (offset < 0x80) ? 5 : 8; // REX
}

//=============================================================================
#ifndef PRODUCT
void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const
{
  if (UseCompressedClassPointers) {
    st->print_cr("movl    rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass");
    st->print_cr("\tdecode_klass_not_null rscratch1, rscratch1");
    st->print_cr("\tcmpq    rax, rscratch1\t # Inline cache check");
  } else {
    st->print_cr("\tcmpq    rax, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t"
                 "# Inline cache check");
  }
  st->print_cr("\tjne     SharedRuntime::_ic_miss_stub");
  st->print_cr("\tnop\t# nops to align entry point");
}
#endif

void MachUEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const
{
  MacroAssembler masm(&cbuf);
  uint insts_size = cbuf.insts_size();
  if (UseCompressedClassPointers) {
    masm.load_klass(rscratch1, j_rarg0, rscratch2);
    masm.cmpptr(rax, rscratch1);
  } else {
    masm.cmpptr(rax, Address(j_rarg0, oopDesc::klass_offset_in_bytes()));
  }

  masm.jump_cc(Assembler::notEqual, RuntimeAddress(SharedRuntime::get_ic_miss_stub()));

  /* WARNING these NOPs are critical so that verified entry point is properly
     4 bytes aligned for patching by NativeJump::patch_verified_entry() */
  int nops_cnt = 4 - ((cbuf.insts_size() - insts_size) & 0x3);
  if (OptoBreakpoint) {
    // Leave space for int3
    nops_cnt -= 1;
  }
  nops_cnt &= 0x3; // Do not add nops if code is aligned.
  if (nops_cnt > 0)
    masm.nop(nops_cnt);
}

uint MachUEPNode::size(PhaseRegAlloc* ra_) const
{
  return MachNode::size(ra_); // too many variables; just compute it
                              // the hard way
}


//=============================================================================

const bool Matcher::supports_vector_calling_convention(void) {
  if (EnableVectorSupport && UseVectorStubs) {
    return true;
  }
  return false;
}

OptoRegPair Matcher::vector_return_value(uint ideal_reg) {
  assert(EnableVectorSupport && UseVectorStubs, "sanity");
  int lo = XMM0_num;
  int hi = XMM0b_num;
  if (ideal_reg == Op_VecX) hi = XMM0d_num;
  else if (ideal_reg == Op_VecY) hi = XMM0h_num;
  else if (ideal_reg == Op_VecZ) hi = XMM0p_num;
  return OptoRegPair(hi, lo);
}

// Is this branch offset short enough that a short branch can be used?
//
// NOTE: If the platform does not provide any short branch variants, then
//       this method should return false for offset 0.
bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) {
  // The passed offset is relative to address of the branch.
  // On 86 a branch displacement is calculated relative to address
  // of a next instruction.
  offset -= br_size;

  // the short version of jmpConUCF2 contains multiple branches,
  // making the reach slightly less
  if (rule == jmpConUCF2_rule)
    return (-126 <= offset && offset <= 125);
  return (-128 <= offset && offset <= 127);
}

// Return whether or not this register is ever used as an argument.
// This function is used on startup to build the trampoline stubs in
// generateOptoStub.  Registers not mentioned will be killed by the VM
// call in the trampoline, and arguments in those registers not be
// available to the callee.
bool Matcher::can_be_java_arg(int reg)
{
  return
    reg ==  RDI_num || reg == RDI_H_num ||
    reg ==  RSI_num || reg == RSI_H_num ||
    reg ==  RDX_num || reg == RDX_H_num ||
    reg ==  RCX_num || reg == RCX_H_num ||
    reg ==   R8_num || reg ==  R8_H_num ||
    reg ==   R9_num || reg ==  R9_H_num ||
    reg ==  R12_num || reg == R12_H_num ||
    reg == XMM0_num || reg == XMM0b_num ||
    reg == XMM1_num || reg == XMM1b_num ||
    reg == XMM2_num || reg == XMM2b_num ||
    reg == XMM3_num || reg == XMM3b_num ||
    reg == XMM4_num || reg == XMM4b_num ||
    reg == XMM5_num || reg == XMM5b_num ||
    reg == XMM6_num || reg == XMM6b_num ||
    reg == XMM7_num || reg == XMM7b_num;
}

bool Matcher::is_spillable_arg(int reg)
{
  return can_be_java_arg(reg);
}

uint Matcher::int_pressure_limit()
{
  return (INTPRESSURE == -1) ? _INT_REG_mask.Size() : INTPRESSURE;
}

uint Matcher::float_pressure_limit()
{
  // After experiment around with different values, the following default threshold
  // works best for LCM's register pressure scheduling on x64.
  uint dec_count  = VM_Version::supports_evex() ? 4 : 2;
  uint default_float_pressure_threshold = _FLOAT_REG_mask.Size() - dec_count;
  return (FLOATPRESSURE == -1) ? default_float_pressure_threshold : FLOATPRESSURE;
}

bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
  // In 64 bit mode a code which use multiply when
  // devisor is constant is faster than hardware
  // DIV instruction (it uses MulHiL).
  return false;
}

// Register for DIVI projection of divmodI
RegMask Matcher::divI_proj_mask() {
  return INT_RAX_REG_mask();
}

// Register for MODI projection of divmodI
RegMask Matcher::modI_proj_mask() {
  return INT_RDX_REG_mask();
}

// Register for DIVL projection of divmodL
RegMask Matcher::divL_proj_mask() {
  return LONG_RAX_REG_mask();
}

// Register for MODL projection of divmodL
RegMask Matcher::modL_proj_mask() {
  return LONG_RDX_REG_mask();
}

// Register for saving SP into on method handle invokes. Not used on x86_64.
const RegMask Matcher::method_handle_invoke_SP_save_mask() {
    return NO_REG_mask();
}

%}

//----------ENCODING BLOCK-----------------------------------------------------
// This block specifies the encoding classes used by the compiler to
// output byte streams.  Encoding classes are parameterized macros
// used by Machine Instruction Nodes in order to generate the bit
// encoding of the instruction.  Operands specify their base encoding
// interface with the interface keyword.  There are currently
// supported four interfaces, REG_INTER, CONST_INTER, MEMORY_INTER, &
// COND_INTER.  REG_INTER causes an operand to generate a function
// which returns its register number when queried.  CONST_INTER causes
// an operand to generate a function which returns the value of the
// constant when queried.  MEMORY_INTER causes an operand to generate
// four functions which return the Base Register, the Index Register,
// the Scale Value, and the Offset Value of the operand when queried.
// COND_INTER causes an operand to generate six functions which return
// the encoding code (ie - encoding bits for the instruction)
// associated with each basic boolean condition for a conditional
// instruction.
//
// Instructions specify two basic values for encoding.  Again, a
// function is available to check if the constant displacement is an
// oop. They use the ins_encode keyword to specify their encoding
// classes (which must be a sequence of enc_class names, and their
// parameters, specified in the encoding block), and they use the
// opcode keyword to specify, in order, their primary, secondary, and
// tertiary opcode.  Only the opcode sections which a particular
// instruction needs for encoding need to be specified.
encode %{
  // Build emit functions for each basic byte or larger field in the
  // intel encoding scheme (opcode, rm, sib, immediate), and call them
  // from C++ code in the enc_class source block.  Emit functions will
  // live in the main source block for now.  In future, we can
  // generalize this by adding a syntax that specifies the sizes of
  // fields in an order, so that the adlc can build the emit functions
  // automagically

  // Emit primary opcode
  enc_class OpcP
  %{
    emit_opcode(cbuf, $primary);
  %}

  // Emit secondary opcode
  enc_class OpcS
  %{
    emit_opcode(cbuf, $secondary);
  %}

  // Emit tertiary opcode
  enc_class OpcT
  %{
    emit_opcode(cbuf, $tertiary);
  %}

  // Emit opcode directly
  enc_class Opcode(immI d8)
  %{
    emit_opcode(cbuf, $d8$$constant);
  %}

  // Emit size prefix
  enc_class SizePrefix
  %{
    emit_opcode(cbuf, 0x66);
  %}

  enc_class reg(rRegI reg)
  %{
    emit_rm(cbuf, 0x3, 0, $reg$$reg & 7);
  %}

  enc_class reg_reg(rRegI dst, rRegI src)
  %{
    emit_rm(cbuf, 0x3, $dst$$reg & 7, $src$$reg & 7);
  %}

  enc_class opc_reg_reg(immI opcode, rRegI dst, rRegI src)
  %{
    emit_opcode(cbuf, $opcode$$constant);
    emit_rm(cbuf, 0x3, $dst$$reg & 7, $src$$reg & 7);
  %}

  enc_class cdql_enc(no_rax_rdx_RegI div)
  %{
    // Full implementation of Java idiv and irem; checks for
    // special case as described in JVM spec., p.243 & p.271.
    //
    //         normal case                           special case
    //
    // input : rax: dividend                         min_int
    //         reg: divisor                          -1
    //
    // output: rax: quotient  (= rax idiv reg)       min_int
    //         rdx: remainder (= rax irem reg)       0
    //
    //  Code sequnce:
    //
    //    0:   3d 00 00 00 80          cmp    $0x80000000,%eax
    //    5:   75 07/08                jne    e <normal>
    //    7:   33 d2                   xor    %edx,%edx
    //  [div >= 8 -> offset + 1]
    //  [REX_B]
    //    9:   83 f9 ff                cmp    $0xffffffffffffffff,$div
    //    c:   74 03/04                je     11 <done>
    // 000000000000000e <normal>:
    //    e:   99                      cltd
    //  [div >= 8 -> offset + 1]
    //  [REX_B]
    //    f:   f7 f9                   idiv   $div
    // 0000000000000011 <done>:
    MacroAssembler _masm(&cbuf);
    Label normal;
    Label done;

    // cmp    $0x80000000,%eax
    __ cmpl(as_Register(RAX_enc), 0x80000000);

--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge