Quellcode-Bibliothek
© Kompilation durch diese Firma
[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]
Datei:
install.mf
Sprache: Unknown
Columbo aufrufen.ad zum Wurzelverzeichnis wechselnSML {SML[185] C[216] BAT[496]}Datei anzeigen //
// 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.353 Sekunden
]
|
|