products/sources/formale Sprachen/Java/openjdk-20-36_src/src/hotspot/cpu/x86 image not shown  

Quellcode-Bibliothek

© Kompilation durch diese Firma

[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]

Datei: tomcat.nsi   Sprache: C

Quellsprache: Binärcode.ad aufgebrochen in jeweils 16 ZeichenSML {SML[185] C[216] BAT[496]}zum Wurzelverzeichnis wechseln

//
// 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)) ? truefalse;  // 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.450 Sekunden  ]