//
// Copyright (c) 2008, 2018, 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.
//
// ARM Architecture Description File
//----------DEFINITION BLOCK---------------------------------------------------
// Define name --> value mappings to inform the ADLC of an integer valued name
// Current support includes integer values in the range [0, 0x7FFFFFFF]
// Format:
// int_def <name> ( <int_value>, <expression>);
// Generated Code in ad_<arch>.hpp
// #define <name> (<expression>)
// // value == <int_value>
// Generated code in ad_<arch>.cpp adlc_verification()
// assert( <name> == <int_value>, "Expect (<expression>) to equal <int_value>");
//
definitions %{
// The default cost (of an ALU instruction).
int_def DEFAULT_COST ( 100, 100);
int_def HUGE_COST (1000000, 1000000);
// Memory refs are twice as expensive as run-of-the-mill.
int_def MEMORY_REF_COST ( 200, DEFAULT_COST * 2);
// Branches are even more expensive.
int_def BRANCH_COST ( 300, DEFAULT_COST * 3);
int_def CALL_COST ( 300, DEFAULT_COST * 3);
%}
//----------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 %{
// Header information of the source block.
// Method declarations/definitions which are used outside
// the ad-scope can conveniently be defined here.
//
// To keep related declarations/definitions/uses close together,
// we switch between source %{ }% and source_hpp %{ }% freely as needed.
// Does destination need to be loaded in a register then passed to a
// branch instruction?
extern bool maybe_far_call(const CallNode *n);
extern bool maybe_far_call(const MachCallNode *n);
static inline bool cache_reachable() {
return MacroAssembler::_cache_fully_reachable();
}
#define ldr_32 ldr
#define str_32 str
#define tst_32 tst
#define teq_32 teq
#if 1
extern bool PrintOptoAssembly;
#endif
class c2 {
public:
static OptoRegPair return_value(int ideal_reg);
};
class CallStubImpl {
//--------------------------------------------------------------
//---< Used for optimization in Compile::Shorten_branches >---
//--------------------------------------------------------------
public:
// Size of call trampoline stub.
static uint size_call_trampoline() {
return 0; // no call trampolines on this platform
}
// number of relocations needed by a call trampoline stub
static uint reloc_call_trampoline() {
return 0; // no call trampolines on this platform
}
};
class HandlerImpl {
public:
static int emit_exception_handler(CodeBuffer &cbuf);
static int emit_deopt_handler(CodeBuffer& cbuf);
static uint size_exception_handler() {
return ( 3 * 4 );
}
static uint size_deopt_handler() {
return ( 9 * 4 );
}
};
%}
source %{
#define __ _masm.
static FloatRegister reg_to_FloatRegister_object(int register_encoding);
static Register reg_to_register_object(int register_encoding);
// ****************************************************************************
// REQUIRED FUNCTIONALITY
// Indicate if the safepoint node needs the polling page as an input.
// Since ARM does not have absolute addressing, it does.
bool SafePointNode::needs_polling_address_input() {
return true;
}
// emit an interrupt that is caught by the debugger (for debugging compiler)
void emit_break(CodeBuffer &cbuf) {
MacroAssembler _masm(&cbuf);
__ breakpoint();
}
#ifndef PRODUCT
void MachBreakpointNode::format( PhaseRegAlloc *, outputStream *st ) const {
st->print("TA");
}
#endif
void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
emit_break(cbuf);
}
uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const {
return MachNode::size(ra_);
}
void emit_nop(CodeBuffer &cbuf) {
MacroAssembler _masm(&cbuf);
__ nop();
}
void emit_call_reloc(CodeBuffer &cbuf, const MachCallNode *n, MachOper *m, RelocationHolder const& rspec) {
int ret_addr_offset0 = n->as_MachCall()->ret_addr_offset();
int call_site_offset = cbuf.insts()->mark_off();
MacroAssembler _masm(&cbuf);
__ set_inst_mark(); // needed in emit_to_interp_stub() to locate the call
address target = (address)m->method();
assert(n->as_MachCall()->entry_point() == target, "sanity");
assert(maybe_far_call(n) == !__ reachable_from_cache(target), "sanity");
assert(cache_reachable() == __ cache_fully_reachable(), "sanity");
assert(target != NULL, "need real address");
int ret_addr_offset = -1;
if (rspec.type() == relocInfo::runtime_call_type) {
__ call(target, rspec);
ret_addr_offset = __ offset();
} else {
// scratches Rtemp
ret_addr_offset = __ patchable_call(target, rspec, true);
}
assert(ret_addr_offset - call_site_offset == ret_addr_offset0, "fix ret_addr_offset()");
}
//=============================================================================
// REQUIRED FUNCTIONALITY for encoding
void emit_lo(CodeBuffer &cbuf, int val) { }
void emit_hi(CodeBuffer &cbuf, int val) { }
//=============================================================================
const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask();
int Compile::ConstantTable::calculate_table_base_offset() const {
int offset = -(size() / 2);
// flds, fldd: 8-bit offset multiplied by 4: +/- 1024
// ldr, ldrb : 12-bit offset: +/- 4096
if (!Assembler::is_simm10(offset)) {
offset = Assembler::min_simm10();
}
return 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 {
Compile* C = ra_->C;
Compile::ConstantTable& constant_table = C->constant_table();
MacroAssembler _masm(&cbuf);
Register r = as_Register(ra_->get_encode(this));
CodeSection* consts_section = __ code()->consts();
int consts_size = consts_section->align_at_start(consts_section->size());
assert(constant_table.size() == consts_size, "must be: %d == %d", constant_table.size(), consts_size);
// Materialize the constant table base.
address baseaddr = consts_section->start() + -(constant_table.table_base_offset());
RelocationHolder rspec = internal_word_Relocation::spec(baseaddr);
__ mov_address(r, baseaddr, rspec);
}
uint MachConstantBaseNode::size(PhaseRegAlloc*) const {
return 8;
}
#ifndef PRODUCT
void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
char reg[128];
ra_->dump_register(this, reg);
st->print("MOV_SLOW &constanttable,%s\t! constant table base", reg);
}
#endif
#ifndef PRODUCT
void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
Compile* C = ra_->C;
for (int i = 0; i < OptoPrologueNops; i++) {
st->print_cr("NOP"); st->print("\t");
}
size_t framesize = C->frame_size_in_bytes();
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
int bangsize = C->bang_size_in_bytes();
// Remove two words for return addr and rbp,
framesize -= 2*wordSize;
bangsize -= 2*wordSize;
// Calls to C2R adapters often do not accept exceptional returns.
// We require that their callers must bang for them. But be careful, because
// some VM calls (such as call site linkage) can use several kilobytes of
// stack. But the stack safety zone should account for that.
// See bugs 4446381, 4468289, 4497237.
if (C->need_stack_bang(bangsize)) {
st->print_cr("! stack bang (%d bytes)", bangsize); st->print("\t");
}
st->print_cr("PUSH R_FP|R_LR_LR"); st->print("\t");
if (framesize != 0) {
st->print ("SUB R_SP, R_SP, " SIZE_FORMAT,framesize);
}
}
#endif
void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
Compile* C = ra_->C;
MacroAssembler _masm(&cbuf);
for (int i = 0; i < OptoPrologueNops; i++) {
__ nop();
}
size_t framesize = C->frame_size_in_bytes();
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
int bangsize = C->bang_size_in_bytes();
// Remove two words for return addr and fp,
framesize -= 2*wordSize;
bangsize -= 2*wordSize;
// Calls to C2R adapters often do not accept exceptional returns.
// We require that their callers must bang for them. But be careful, because
// some VM calls (such as call site linkage) can use several kilobytes of
// stack. But the stack safety zone should account for that.
// See bugs 4446381, 4468289, 4497237.
if (C->need_stack_bang(bangsize)) {
__ arm_stack_overflow_check(bangsize, Rtemp);
}
__ raw_push(FP, LR);
if (framesize != 0) {
__ sub_slow(SP, SP, framesize);
}
// offset from scratch buffer is not valid
if (strcmp(cbuf.name(), "Compile::Fill_buffer") == 0) {
C->set_frame_complete( __ offset() );
}
if (C->has_mach_constant_base_node()) {
// NOTE: We set the table base offset here because users might be
// emitted before MachConstantBaseNode.
Compile::ConstantTable& constant_table = C->constant_table();
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
}
}
uint MachPrologNode::size(PhaseRegAlloc *ra_) const {
return MachNode::size(ra_);
}
int MachPrologNode::reloc() const {
return 10; // a large enough number
}
//=============================================================================
#ifndef PRODUCT
void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
Compile* C = ra_->C;
size_t framesize = C->frame_size_in_bytes();
framesize -= 2*wordSize;
if (framesize != 0) {
st->print("ADD R_SP, R_SP, " SIZE_FORMAT "\n\t",framesize);
}
st->print("POP R_FP|R_LR_LR");
if (do_polling() && ra_->C->is_method_compilation()) {
st->print("\n\t");
st->print("MOV Rtemp, #PollAddr\t! Load Polling address\n\t");
st->print("LDR Rtemp,[Rtemp]\t!Poll for Safepointing");
}
}
#endif
void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
MacroAssembler _masm(&cbuf);
Compile* C = ra_->C;
size_t framesize = C->frame_size_in_bytes();
framesize -= 2*wordSize;
if (framesize != 0) {
__ add_slow(SP, SP, framesize);
}
__ raw_pop(FP, LR);
// If this does safepoint polling, then do it here
if (do_polling() && ra_->C->is_method_compilation()) {
// mov_slow here is usually one or two instruction
__ mov_address(Rtemp, (address)os::get_polling_page());
__ relocate(relocInfo::poll_return_type);
__ ldr(Rtemp, Address(Rtemp));
}
}
uint MachEpilogNode::size(PhaseRegAlloc *ra_) const {
return MachNode::size(ra_);
}
int MachEpilogNode::reloc() const {
return 16; // a large enough number
}
const Pipeline * MachEpilogNode::pipeline() const {
return MachNode::pipeline_class();
}
int MachEpilogNode::safepoint_offset() const {
assert( do_polling(), "no return for this epilog node");
// return MacroAssembler::size_of_sethi(os::get_polling_page());
Unimplemented();
return 0;
}
//=============================================================================
// Figure out which register class each belongs in: rc_int, rc_float, rc_stack
enum RC { rc_bad, rc_int, 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;
assert(r->is_FloatRegister(), "must be");
return rc_float;
}
static inline bool is_iRegLd_memhd(OptoReg::Name src_first, OptoReg::Name src_second, int offset) {
int rlo = Matcher::_regEncode[src_first];
int rhi = Matcher::_regEncode[src_second];
if (!((rlo&1)==0 && (rlo+1 == rhi))) {
tty->print_cr("CAUGHT BAD LDRD/STRD");
}
return (rlo&1)==0 && (rlo+1 == rhi) && is_memoryHD(offset);
}
uint MachSpillCopyNode::implementation( CodeBuffer *cbuf,
PhaseRegAlloc *ra_,
bool do_size,
outputStream* st ) const {
// 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" );
// Generate spill code!
int size = 0;
if (src_first == dst_first && src_second == dst_second)
return size; // Self copy, no move
#ifdef TODO
if (bottom_type()->isa_vect() != NULL) {
}
#endif
// Shared code does not expect instruction set capability based bailouts here.
// Handle offset unreachable bailout with minimal change in shared code.
// Bailout only for real instruction emit.
// This requires a single comment change in shared code. ( see output.cpp "Normal" instruction case )
MacroAssembler _masm(cbuf);
// --------------------------------------
// Check for mem-mem move. Load into unused float registers and fall into
// the float-store case.
if (src_first_rc == rc_stack && dst_first_rc == rc_stack) {
int offset = ra_->reg2offset(src_first);
if (cbuf && !is_memoryfp(offset)) {
ra_->C->record_method_not_compilable("unable to handle large constant offsets");
return 0;
} else {
if (src_second_rc != rc_bad) {
assert((src_first&1)==0 && src_first+1 == src_second, "pair of registers must be aligned/contiguous");
src_first = OptoReg::Name(R_mem_copy_lo_num);
src_second = OptoReg::Name(R_mem_copy_hi_num);
src_first_rc = rc_float;
src_second_rc = rc_float;
if (cbuf) {
__ ldr_double(Rmemcopy, Address(SP, offset));
} else if (!do_size) {
st->print(LDR_DOUBLE " R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
}
} else {
src_first = OptoReg::Name(R_mem_copy_lo_num);
src_first_rc = rc_float;
if (cbuf) {
__ ldr_float(Rmemcopy, Address(SP, offset));
} else if (!do_size) {
st->print(LDR_FLOAT " R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
}
}
size += 4;
}
}
if (src_second_rc == rc_stack && dst_second_rc == rc_stack) {
Unimplemented();
}
// --------------------------------------
// Check for integer reg-reg copy
if (src_first_rc == rc_int && dst_first_rc == rc_int) {
// Else normal reg-reg copy
assert( src_second != dst_first, "smashed second before evacuating it" );
if (cbuf) {
__ mov(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
} else if (!do_size) {
st->print("MOV R_%s, R_%s\t# spill",
Matcher::regName[dst_first],
Matcher::regName[src_first]);
#endif
}
size += 4;
}
// Check for integer store
if (src_first_rc == rc_int && dst_first_rc == rc_stack) {
int offset = ra_->reg2offset(dst_first);
if (cbuf && !is_memoryI(offset)) {
ra_->C->record_method_not_compilable("unable to handle large constant offsets");
return 0;
} else {
if (src_second_rc != rc_bad && is_iRegLd_memhd(src_first, src_second, offset)) {
assert((src_first&1)==0 && src_first+1 == src_second, "pair of registers must be aligned/contiguous");
if (cbuf) {
__ str_64(reg_to_register_object(Matcher::_regEncode[src_first]), Address(SP, offset));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print(STR_64 " R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first), offset);
#endif
}
return size + 4;
} else {
if (cbuf) {
__ str_32(reg_to_register_object(Matcher::_regEncode[src_first]), Address(SP, offset));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print(STR_32 " R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first), offset);
#endif
}
}
}
size += 4;
}
// Check for integer load
if (dst_first_rc == rc_int && src_first_rc == rc_stack) {
int offset = ra_->reg2offset(src_first);
if (cbuf && !is_memoryI(offset)) {
ra_->C->record_method_not_compilable("unable to handle large constant offsets");
return 0;
} else {
if (src_second_rc != rc_bad && is_iRegLd_memhd(dst_first, dst_second, offset)) {
assert((src_first&1)==0 && src_first+1 == src_second, "pair of registers must be aligned/contiguous");
if (cbuf) {
__ ldr_64(reg_to_register_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print(LDR_64 " R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first), offset);
#endif
}
return size + 4;
} else {
if (cbuf) {
__ ldr_32(reg_to_register_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print(LDR_32 " R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first), offset);
#endif
}
}
}
size += 4;
}
// Check for float reg-reg copy
if (src_first_rc == rc_float && dst_first_rc == rc_float) {
if (src_second_rc != rc_bad) {
assert((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers must be aligned/contiguous");
if (cbuf) {
__ mov_double(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
} else if (!do_size) {
st->print(MOV_DOUBLE " R_%s, R_%s\t# spill",
Matcher::regName[dst_first],
Matcher::regName[src_first]);
#endif
}
return 4;
}
if (cbuf) {
__ mov_float(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
} else if (!do_size) {
st->print(MOV_FLOAT " R_%s, R_%s\t# spill",
Matcher::regName[dst_first],
Matcher::regName[src_first]);
#endif
}
size = 4;
}
// Check for float store
if (src_first_rc == rc_float && dst_first_rc == rc_stack) {
int offset = ra_->reg2offset(dst_first);
if (cbuf && !is_memoryfp(offset)) {
ra_->C->record_method_not_compilable("unable to handle large constant offsets");
return 0;
} else {
// Further check for aligned-adjacent pair, so we can use a double store
if (src_second_rc != rc_bad) {
assert((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers and stack slots must be aligned/contiguous");
if (cbuf) {
__ str_double(reg_to_FloatRegister_object(Matcher::_regEncode[src_first]), Address(SP, offset));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print(STR_DOUBLE " R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
#endif
}
return size + 4;
} else {
if (cbuf) {
__ str_float(reg_to_FloatRegister_object(Matcher::_regEncode[src_first]), Address(SP, offset));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print(STR_FLOAT " R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
#endif
}
}
}
size += 4;
}
// Check for float load
if (dst_first_rc == rc_float && src_first_rc == rc_stack) {
int offset = ra_->reg2offset(src_first);
if (cbuf && !is_memoryfp(offset)) {
ra_->C->record_method_not_compilable("unable to handle large constant offsets");
return 0;
} else {
// Further check for aligned-adjacent pair, so we can use a double store
if (src_second_rc != rc_bad) {
assert((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers and stack slots must be aligned/contiguous");
if (cbuf) {
__ ldr_double(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print(LDR_DOUBLE " R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first),offset);
#endif
}
return size + 4;
} else {
if (cbuf) {
__ ldr_float(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print(LDR_FLOAT " R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first),offset);
#endif
}
}
}
size += 4;
}
// check for int reg -> float reg move
if (src_first_rc == rc_int && dst_first_rc == rc_float) {
// Further check for aligned-adjacent pair, so we can use a single instruction
if (src_second_rc != rc_bad) {
assert((dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers must be aligned/contiguous");
assert((src_first&1)==0 && src_first+1 == src_second, "pairs of registers must be aligned/contiguous");
assert(src_second_rc == rc_int && dst_second_rc == rc_float, "unsupported");
if (cbuf) {
__ fmdrr(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[src_first]), reg_to_register_object(Matcher::_regEncode[src_second]));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print("FMDRR R_%s, R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first), OptoReg::regname(src_second));
#endif
}
return size + 4;
} else {
if (cbuf) {
__ fmsr(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print(FMSR " R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first));
#endif
}
size += 4;
}
}
// check for float reg -> int reg move
if (src_first_rc == rc_float && dst_first_rc == rc_int) {
// Further check for aligned-adjacent pair, so we can use a single instruction
if (src_second_rc != rc_bad) {
assert((src_first&1)==0 && src_first+1 == src_second, "pairs of registers must be aligned/contiguous");
assert((dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers must be aligned/contiguous");
assert(src_second_rc == rc_float && dst_second_rc == rc_int, "unsupported");
if (cbuf) {
__ fmrrd(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[dst_second]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print("FMRRD R_%s, R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(dst_second), OptoReg::regname(src_first));
#endif
}
return size + 4;
} else {
if (cbuf) {
__ fmrs(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print(FMRS " R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first));
#endif
}
size += 4;
}
}
// --------------------------------------------------------------------
// Check for hi bits still needing moving. Only happens for misaligned
// arguments to native calls.
if (src_second == dst_second)
return size; // Self copy; no move
assert( src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad" );
// Check for integer reg-reg copy. Hi bits are stuck up in the top
// 32-bits of a 64-bit register, but are needed in low bits of another
// register (else it's a hi-bits-to-hi-bits copy which should have
// happened already as part of a 64-bit move)
if (src_second_rc == rc_int && dst_second_rc == rc_int) {
if (cbuf) {
__ mov(reg_to_register_object(Matcher::_regEncode[dst_second]), reg_to_register_object(Matcher::_regEncode[src_second]));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print("MOV R_%s, R_%s\t# spill high",
Matcher::regName[dst_second],
Matcher::regName[src_second]);
#endif
}
return size+4;
}
// Check for high word integer store
if (src_second_rc == rc_int && dst_second_rc == rc_stack) {
int offset = ra_->reg2offset(dst_second);
if (cbuf && !is_memoryP(offset)) {
ra_->C->record_method_not_compilable("unable to handle large constant offsets");
return 0;
} else {
if (cbuf) {
__ str(reg_to_register_object(Matcher::_regEncode[src_second]), Address(SP, offset));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print("STR R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_second), offset);
#endif
}
}
return size + 4;
}
// Check for high word integer load
if (dst_second_rc == rc_int && src_second_rc == rc_stack) {
int offset = ra_->reg2offset(src_second);
if (cbuf && !is_memoryP(offset)) {
ra_->C->record_method_not_compilable("unable to handle large constant offsets");
return 0;
} else {
if (cbuf) {
__ ldr(reg_to_register_object(Matcher::_regEncode[dst_second]), Address(SP, offset));
#ifndef PRODUCT
} else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print("LDR R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_second), offset);
#endif
}
}
return size + 4;
}
Unimplemented();
return 0; // Mute compiler
}
#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 implementation( NULL, ra_, true, NULL );
}
//=============================================================================
#ifndef PRODUCT
void MachNopNode::format( PhaseRegAlloc *, outputStream *st ) const {
st->print("NOP \t# %d bytes pad for loops and calls", 4 * _count);
}
#endif
void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc * ) const {
MacroAssembler _masm(&cbuf);
for(int i = 0; i < _count; i += 1) {
__ nop();
}
}
uint MachNopNode::size(PhaseRegAlloc *ra_) const {
return 4 * _count;
}
//=============================================================================
#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("ADD %s,R_SP+#%d",Matcher::regName[reg], offset);
}
#endif
void BoxLockNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
MacroAssembler _masm(&cbuf);
int offset = ra_->reg2offset(in_RegMask(0).find_first_elem());
int reg = ra_->get_encode(this);
Register dst = reg_to_register_object(reg);
if (is_aimm(offset)) {
__ add(dst, SP, offset);
} else {
__ mov_slow(dst, offset);
__ add(dst, SP, dst);
}
}
uint BoxLockNode::size(PhaseRegAlloc *ra_) const {
// BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_)
assert(ra_ == ra_->C->regalloc(), "sanity");
return ra_->C->scratch_emit_size(this);
}
//=============================================================================
#ifndef PRODUCT
#define R_RTEMP "R_R12"
void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
st->print_cr("\nUEP:");
if (UseCompressedClassPointers) {
st->print_cr("\tLDR_w " R_RTEMP ",[R_R0 + oopDesc::klass_offset_in_bytes]\t! Inline cache check");
st->print_cr("\tdecode_klass " R_RTEMP);
} else {
st->print_cr("\tLDR " R_RTEMP ",[R_R0 + oopDesc::klass_offset_in_bytes]\t! Inline cache check");
}
st->print_cr("\tCMP " R_RTEMP ",R_R8" );
st->print ("\tB.NE SharedRuntime::handle_ic_miss_stub");
}
#endif
void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
MacroAssembler _masm(&cbuf);
Register iCache = reg_to_register_object(Matcher::inline_cache_reg_encode());
assert(iCache == Ricklass, "should be");
Register receiver = R0;
__ load_klass(Rtemp, receiver);
__ cmp(Rtemp, iCache);
__ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, noreg, ne);
}
uint MachUEPNode::size(PhaseRegAlloc *ra_) const {
return MachNode::size(ra_);
}
//=============================================================================
// Emit exception handler code.
int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) {
MacroAssembler _masm(&cbuf);
address base = __ start_a_stub(size_exception_handler());
if (base == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset();
// OK to trash LR, because exception blob will kill it
__ jump(OptoRuntime::exception_blob()->entry_point(), relocInfo::runtime_call_type, LR_tmp);
assert(__ offset() - offset <= (int) size_exception_handler(), "overflow");
__ end_a_stub();
return offset;
}
int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) {
// Can't use any of the current frame's registers as we may have deopted
// at a poll and everything can be live.
MacroAssembler _masm(&cbuf);
address base = __ start_a_stub(size_deopt_handler());
if (base == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset();
address deopt_pc = __ pc();
__ sub(SP, SP, wordSize); // make room for saved PC
__ push(LR); // save LR that may be live when we get here
__ mov_relative_address(LR, deopt_pc);
__ str(LR, Address(SP, wordSize)); // save deopt PC
__ pop(LR); // restore LR
__ jump(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type, noreg);
assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow");
__ end_a_stub();
return offset;
}
const bool Matcher::match_rule_supported(int opcode) {
if (!has_match_rule(opcode))
return false;
switch (opcode) {
case Op_PopCountI:
case Op_PopCountL:
if (!UsePopCountInstruction)
return false;
break;
case Op_LShiftCntV:
case Op_RShiftCntV:
case Op_AddVB:
case Op_AddVS:
case Op_AddVI:
case Op_AddVL:
case Op_SubVB:
case Op_SubVS:
case Op_SubVI:
case Op_SubVL:
case Op_MulVS:
case Op_MulVI:
case Op_LShiftVB:
case Op_LShiftVS:
case Op_LShiftVI:
case Op_LShiftVL:
case Op_RShiftVB:
case Op_RShiftVS:
case Op_RShiftVI:
case Op_RShiftVL:
case Op_URShiftVB:
case Op_URShiftVS:
case Op_URShiftVI:
case Op_URShiftVL:
case Op_AndV:
case Op_OrV:
case Op_XorV:
return VM_Version::has_simd();
case Op_LoadVector:
case Op_StoreVector:
case Op_AddVF:
case Op_SubVF:
case Op_MulVF:
return VM_Version::has_vfp() || VM_Version::has_simd();
case Op_AddVD:
case Op_SubVD:
case Op_MulVD:
case Op_DivVF:
case Op_DivVD:
return VM_Version::has_vfp();
}
return true; // Per default match rules are supported.
}
const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) {
// TODO
// identify extra cases that we might want to provide match rules for
// e.g. Op_ vector nodes and other intrinsics while guarding with vlen
bool ret_value = match_rule_supported(opcode);
// Add rules here.
return ret_value; // Per default match rules are supported.
}
const bool Matcher::has_predicated_vectors(void) {
return false;
}
const int Matcher::float_pressure(int default_pressure_threshold) {
return default_pressure_threshold;
}
int Matcher::regnum_to_fpu_offset(int regnum) {
return regnum - 32; // The FP registers are in the second chunk
}
// Vector width in bytes
const int Matcher::vector_width_in_bytes(BasicType bt) {
return MaxVectorSize;
}
// Vector ideal reg corresponding to specified size in bytes
const uint Matcher::vector_ideal_reg(int size) {
assert(MaxVectorSize >= size, "");
switch(size) {
case 8: return Op_VecD;
case 16: return Op_VecX;
}
ShouldNotReachHere();
return 0;
}
const uint Matcher::vector_shift_count_ideal_reg(int size) {
return vector_ideal_reg(size);
}
// Limits on vector size (number of elements) loaded into vector.
const int Matcher::max_vector_size(const BasicType bt) {
assert(is_java_primitive(bt), "only primitive type vectors");
return vector_width_in_bytes(bt)/type2aelembytes(bt);
}
const int Matcher::min_vector_size(const BasicType bt) {
assert(is_java_primitive(bt), "only primitive type vectors");
return 8/type2aelembytes(bt);
}
// ARM doesn't support misaligned vectors store/load.
const bool Matcher::misaligned_vectors_ok() {
return false;
}
// ARM doesn't support AES intrinsics
const bool Matcher::pass_original_key_for_aes() {
return false;
}
const bool Matcher::convL2FSupported(void) {
return false;
}
// 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 ARM a branch displacement is calculated relative to address
// of the branch + 8.
//
// offset -= 8;
// return (Assembler::is_simm24(offset));
return false;
}
const bool Matcher::isSimpleConstant64(jlong value) {
// Will one (StoreL ConL) be cheaper than two (StoreI ConI)?.
return false;
}
// No scaling for the parameter the ClearArray node.
const bool Matcher::init_array_count_is_in_bytes = true;
// Needs 2 CMOV's for longs.
const int Matcher::long_cmove_cost() { return 2; }
// CMOVF/CMOVD are expensive on ARM.
const int Matcher::float_cmove_cost() { return ConditionalMoveLimit; }
// Does the CPU require late expand (see block.cpp for description of late expand)?
const bool Matcher::require_postalloc_expand = false;
// Do we need to mask the count passed to shift instructions or does
// the cpu only look at the lower 5/6 bits anyway?
// FIXME: does this handle vector shifts as well?
const bool Matcher::need_masked_shift_count = true;
const bool Matcher::convi2l_type_required = true;
// No support for generic vector operands.
const bool Matcher::supports_generic_vector_operands = false;
MachOper* Matcher::specialize_generic_vector_operand(MachOper* original_opnd, uint ideal_reg, bool is_temp) {
ShouldNotReachHere(); // generic vector operands not supported
return NULL;
}
bool Matcher::is_generic_reg2reg_move(MachNode* m) {
ShouldNotReachHere(); // generic vector operands not supported
return false;
}
bool Matcher::is_generic_vector(MachOper* opnd) {
ShouldNotReachHere(); // generic vector operands not supported
return false;
}
// Should the Matcher clone shifts on addressing modes, expecting them
// to be subsumed into complex addressing expressions or compute them
// into registers?
bool Matcher::clone_address_expressions(AddPNode* m, Matcher::MStack& mstack, VectorSet& address_visited) {
return clone_base_plus_offset_address(m, mstack, address_visited);
}
void Compile::reshape_address(AddPNode* addp) {
}
bool Matcher::narrow_oop_use_complex_address() {
NOT_LP64(ShouldNotCallThis());
assert(UseCompressedOops, "only for compressed oops code");
return false;
}
bool Matcher::narrow_klass_use_complex_address() {
NOT_LP64(ShouldNotCallThis());
assert(UseCompressedClassPointers, "only for compressed klass code");
return false;
}
bool Matcher::const_oop_prefer_decode() {
NOT_LP64(ShouldNotCallThis());
return true;
}
bool Matcher::const_klass_prefer_decode() {
NOT_LP64(ShouldNotCallThis());
return true;
}
// Is it better to copy float constants, or load them directly from memory?
// Intel can load a float constant from a direct address, requiring no
// extra registers. Most RISCs will have to materialize an address into a
// register first, so they would do better to copy the constant from stack.
const bool Matcher::rematerialize_float_constants = false;
// If CPU can load and store mis-aligned doubles directly then no fixup is
// needed. Else we split the double into 2 integer pieces and move it
// piece-by-piece. Only happens when passing doubles into C code as the
// Java calling convention forces doubles to be aligned.
const bool Matcher::misaligned_doubles_ok = false;
// No-op on ARM.
void Matcher::pd_implicit_null_fixup(MachNode *node, uint idx) {
}
// Advertise here if the CPU requires explicit rounding operations
// to implement the UseStrictFP mode.
const bool Matcher::strict_fp_requires_explicit_rounding = false;
// Are floats converted to double when stored to stack during deoptimization?
// ARM does not handle callee-save floats.
bool Matcher::float_in_double() {
return false;
}
// Do ints take an entire long register or just half?
// Note that we if-def off of _LP64.
// The relevant question is how the int is callee-saved. In _LP64
// the whole long is written but de-opt'ing will have to extract
// the relevant 32 bits, in not-_LP64 only the low 32 bits is written.
#ifdef _LP64
const bool Matcher::int_in_long = true;
#else
const bool Matcher::int_in_long = false;
#endif
// 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 ) {
if (reg == R_R0_num ||
reg == R_R1_num ||
reg == R_R2_num ||
reg == R_R3_num) return true;
if (reg >= R_S0_num &&
reg <= R_S13_num) return true;
return false;
}
bool Matcher::is_spillable_arg( int reg ) {
return can_be_java_arg(reg);
}
bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
return false;
}
// Register for DIVI projection of divmodI
RegMask Matcher::divI_proj_mask() {
ShouldNotReachHere();
return RegMask();
}
// Register for MODI projection of divmodI
RegMask Matcher::modI_proj_mask() {
ShouldNotReachHere();
return RegMask();
}
// Register for DIVL projection of divmodL
RegMask Matcher::divL_proj_mask() {
ShouldNotReachHere();
return RegMask();
}
// Register for MODL projection of divmodL
RegMask Matcher::modL_proj_mask() {
ShouldNotReachHere();
return RegMask();
}
const RegMask Matcher::method_handle_invoke_SP_save_mask() {
return FP_REGP_mask();
}
bool maybe_far_call(const CallNode *n) {
return !MacroAssembler::_reachable_from_cache(n->as_Call()->entry_point());
}
bool maybe_far_call(const MachCallNode *n) {
return !MacroAssembler::_reachable_from_cache(n->as_MachCall()->entry_point());
}
%}
//----------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 %{
enc_class call_epilog %{
// nothing
%}
enc_class Java_To_Runtime (method meth) %{
// CALL directly to the runtime
emit_call_reloc(cbuf, as_MachCall(), $meth, runtime_call_Relocation::spec());
%}
enc_class Java_Static_Call (method meth) %{
// CALL to fixup routine. Fixup routine uses ScopeDesc info to determine
// who we intended to call.
if ( !_method) {
emit_call_reloc(cbuf, as_MachCall(), $meth, runtime_call_Relocation::spec());
} else {
int method_index = resolved_method_index(cbuf);
RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
: static_call_Relocation::spec(method_index);
emit_call_reloc(cbuf, as_MachCall(), $meth, rspec);
// Emit stubs for static call.
address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
if (stub == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
return;
}
}
%}
enc_class save_last_PC %{
// preserve mark
address mark = cbuf.insts()->mark();
debug_only(int off0 = cbuf.insts_size());
MacroAssembler _masm(&cbuf);
int ret_addr_offset = as_MachCall()->ret_addr_offset();
__ adr(LR, mark + ret_addr_offset);
__ str(LR, Address(Rthread, JavaThread::last_Java_pc_offset()));
debug_only(int off1 = cbuf.insts_size());
assert(off1 - off0 == 2 * Assembler::InstructionSize, "correct size prediction");
// restore mark
cbuf.insts()->set_mark(mark);
%}
enc_class preserve_SP %{
// preserve mark
address mark = cbuf.insts()->mark();
debug_only(int off0 = cbuf.insts_size());
MacroAssembler _masm(&cbuf);
// FP is preserved across all calls, even compiled calls.
// Use it to preserve SP in places where the callee might change the SP.
__ mov(Rmh_SP_save, SP);
debug_only(int off1 = cbuf.insts_size());
assert(off1 - off0 == 4, "correct size prediction");
// restore mark
cbuf.insts()->set_mark(mark);
%}
enc_class restore_SP %{
MacroAssembler _masm(&cbuf);
__ mov(SP, Rmh_SP_save);
%}
enc_class Java_Dynamic_Call (method meth) %{
MacroAssembler _masm(&cbuf);
Register R8_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode());
assert(R8_ic_reg == Ricklass, "should be");
__ set_inst_mark();
__ movw(R8_ic_reg, ((unsigned int)Universe::non_oop_word()) & 0xffff);
__ movt(R8_ic_reg, ((unsigned int)Universe::non_oop_word()) >> 16);
address virtual_call_oop_addr = __ inst_mark();
// CALL to fixup routine. Fixup routine uses ScopeDesc info to determine
// who we intended to call.
int method_index = resolved_method_index(cbuf);
__ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr, method_index));
emit_call_reloc(cbuf, as_MachCall(), $meth, RelocationHolder::none);
%}
enc_class LdReplImmI(immI src, regD dst, iRegI tmp, int cnt, int wth) %{
// FIXME: load from constant table?
// Load a constant replicated "count" times with width "width"
int count = $cnt$$constant;
int width = $wth$$constant;
assert(count*width == 4, "sanity");
int val = $src$$constant;
if (width < 4) {
int bit_width = width * 8;
val &= (((int)1) << bit_width) - 1; // mask off sign bits
for (int i = 0; i < count - 1; i++) {
val |= (val << bit_width);
}
}
MacroAssembler _masm(&cbuf);
if (val == -1) {
__ mvn($tmp$$Register, 0);
} else if (val == 0) {
__ mov($tmp$$Register, 0);
} else {
__ movw($tmp$$Register, val & 0xffff);
__ movt($tmp$$Register, (unsigned int)val >> 16);
}
__ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
%}
enc_class LdReplImmF(immF src, regD dst, iRegI tmp) %{
// Replicate float con 2 times and pack into vector (8 bytes) in regD.
float fval = $src$$constant;
int val = *((int*)&fval);
MacroAssembler _masm(&cbuf);
if (val == -1) {
__ mvn($tmp$$Register, 0);
} else if (val == 0) {
__ mov($tmp$$Register, 0);
} else {
__ movw($tmp$$Register, val & 0xffff);
__ movt($tmp$$Register, (unsigned int)val >> 16);
}
__ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
%}
enc_class enc_String_Compare(R0RegP str1, R1RegP str2, R2RegI cnt1, R3RegI cnt2, iRegI result, iRegI tmp1, iRegI tmp2) %{
Label Ldone, Lloop;
MacroAssembler _masm(&cbuf);
Register str1_reg = $str1$$Register;
Register str2_reg = $str2$$Register;
Register cnt1_reg = $cnt1$$Register; // int
Register cnt2_reg = $cnt2$$Register; // int
Register tmp1_reg = $tmp1$$Register;
Register tmp2_reg = $tmp2$$Register;
Register result_reg = $result$$Register;
assert_different_registers(str1_reg, str2_reg, cnt1_reg, cnt2_reg, tmp1_reg, tmp2_reg);
// Compute the minimum of the string lengths(str1_reg) and the
// difference of the string lengths (stack)
// See if the lengths are different, and calculate min in str1_reg.
// Stash diff in tmp2 in case we need it for a tie-breaker.
__ subs_32(tmp2_reg, cnt1_reg, cnt2_reg);
__ mov(cnt1_reg, AsmOperand(cnt1_reg, lsl, exact_log2(sizeof(jchar)))); // scale the limit
__ mov(cnt1_reg, AsmOperand(cnt2_reg, lsl, exact_log2(sizeof(jchar))), pl); // scale the limit
// reallocate cnt1_reg, cnt2_reg, result_reg
// Note: limit_reg holds the string length pre-scaled by 2
Register limit_reg = cnt1_reg;
Register chr2_reg = cnt2_reg;
Register chr1_reg = tmp1_reg;
// str{12} are the base pointers
// Is the minimum length zero?
__ cmp_32(limit_reg, 0);
if (result_reg != tmp2_reg) {
__ mov(result_reg, tmp2_reg, eq);
}
__ b(Ldone, eq);
// Load first characters
__ ldrh(chr1_reg, Address(str1_reg, 0));
__ ldrh(chr2_reg, Address(str2_reg, 0));
// Compare first characters
__ subs(chr1_reg, chr1_reg, chr2_reg);
if (result_reg != chr1_reg) {
__ mov(result_reg, chr1_reg, ne);
}
__ b(Ldone, ne);
{
// Check after comparing first character to see if strings are equivalent
// Check if the strings start at same location
__ cmp(str1_reg, str2_reg);
// Check if the length difference is zero
__ cond_cmp(tmp2_reg, 0, eq);
__ mov(result_reg, 0, eq); // result is zero
__ b(Ldone, eq);
// Strings might not be equal
}
__ subs(chr1_reg, limit_reg, 1 * sizeof(jchar));
if (result_reg != tmp2_reg) {
__ mov(result_reg, tmp2_reg, eq);
}
__ b(Ldone, eq);
// Shift str1_reg and str2_reg to the end of the arrays, negate limit
__ add(str1_reg, str1_reg, limit_reg);
__ add(str2_reg, str2_reg, limit_reg);
__ neg(limit_reg, chr1_reg); // limit = -(limit-2)
// Compare the rest of the characters
__ bind(Lloop);
__ ldrh(chr1_reg, Address(str1_reg, limit_reg));
__ ldrh(chr2_reg, Address(str2_reg, limit_reg));
__ subs(chr1_reg, chr1_reg, chr2_reg);
if (result_reg != chr1_reg) {
__ mov(result_reg, chr1_reg, ne);
}
__ b(Ldone, ne);
__ adds(limit_reg, limit_reg, sizeof(jchar));
__ b(Lloop, ne);
// If strings are equal up to min length, return the length difference.
if (result_reg != tmp2_reg) {
__ mov(result_reg, tmp2_reg);
}
// Otherwise, return the difference between the first mismatched chars.
__ bind(Ldone);
%}
enc_class enc_String_Equals(R0RegP str1, R1RegP str2, R2RegI cnt, iRegI result, iRegI tmp1, iRegI tmp2) %{
Label Lchar, Lchar_loop, Ldone, Lequal;
MacroAssembler _masm(&cbuf);
Register str1_reg = $str1$$Register;
Register str2_reg = $str2$$Register;
Register cnt_reg = $cnt$$Register; // int
Register tmp1_reg = $tmp1$$Register;
Register tmp2_reg = $tmp2$$Register;
Register result_reg = $result$$Register;
assert_different_registers(str1_reg, str2_reg, cnt_reg, tmp1_reg, tmp2_reg, result_reg);
__ cmp(str1_reg, str2_reg); //same char[] ?
__ b(Lequal, eq);
__ cbz_32(cnt_reg, Lequal); // count == 0
//rename registers
Register limit_reg = cnt_reg;
Register chr1_reg = tmp1_reg;
Register chr2_reg = tmp2_reg;
__ logical_shift_left(limit_reg, limit_reg, exact_log2(sizeof(jchar)));
//check for alignment and position the pointers to the ends
__ orr(chr1_reg, str1_reg, str2_reg);
__ tst(chr1_reg, 0x3);
// notZero means at least one not 4-byte aligned.
// We could optimize the case when both arrays are not aligned
// but it is not frequent case and it requires additional checks.
__ b(Lchar, ne);
// Compare char[] arrays aligned to 4 bytes.
__ char_arrays_equals(str1_reg, str2_reg, limit_reg, result_reg,
chr1_reg, chr2_reg, Ldone);
__ b(Lequal); // equal
// char by char compare
__ bind(Lchar);
__ mov(result_reg, 0);
__ add(str1_reg, limit_reg, str1_reg);
__ add(str2_reg, limit_reg, str2_reg);
__ neg(limit_reg, limit_reg); //negate count
// Lchar_loop
__ bind(Lchar_loop);
__ ldrh(chr1_reg, Address(str1_reg, limit_reg));
__ ldrh(chr2_reg, Address(str2_reg, limit_reg));
__ cmp(chr1_reg, chr2_reg);
__ b(Ldone, ne);
__ adds(limit_reg, limit_reg, sizeof(jchar));
__ b(Lchar_loop, ne);
__ bind(Lequal);
__ mov(result_reg, 1); //equal
__ bind(Ldone);
%}
enc_class enc_Array_Equals(R0RegP ary1, R1RegP ary2, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI result) %{
Label Ldone, Lloop, Lequal;
MacroAssembler _masm(&cbuf);
Register ary1_reg = $ary1$$Register;
Register ary2_reg = $ary2$$Register;
Register tmp1_reg = $tmp1$$Register;
Register tmp2_reg = $tmp2$$Register;
Register tmp3_reg = $tmp3$$Register;
Register result_reg = $result$$Register;
assert_different_registers(ary1_reg, ary2_reg, tmp1_reg, tmp2_reg, tmp3_reg, result_reg);
int length_offset = arrayOopDesc::length_offset_in_bytes();
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
// return true if the same array
__ teq(ary1_reg, ary2_reg);
__ mov(result_reg, 1, eq);
__ b(Ldone, eq); // equal
__ tst(ary1_reg, ary1_reg);
__ mov(result_reg, 0, eq);
__ b(Ldone, eq); // not equal
__ tst(ary2_reg, ary2_reg);
__ mov(result_reg, 0, eq);
__ b(Ldone, eq); // not equal
//load the lengths of arrays
__ ldr_s32(tmp1_reg, Address(ary1_reg, length_offset)); // int
__ ldr_s32(tmp2_reg, Address(ary2_reg, length_offset)); // int
// return false if the two arrays are not equal length
__ teq_32(tmp1_reg, tmp2_reg);
__ mov(result_reg, 0, ne);
__ b(Ldone, ne); // not equal
__ tst(tmp1_reg, tmp1_reg);
__ mov(result_reg, 1, eq);
__ b(Ldone, eq); // zero-length arrays are equal
// load array addresses
__ add(ary1_reg, ary1_reg, base_offset);
__ add(ary2_reg, ary2_reg, base_offset);
// renaming registers
Register chr1_reg = tmp3_reg; // for characters in ary1
Register chr2_reg = tmp2_reg; // for characters in ary2
Register limit_reg = tmp1_reg; // length
// set byte count
__ logical_shift_left_32(limit_reg, limit_reg, exact_log2(sizeof(jchar)));
// Compare char[] arrays aligned to 4 bytes.
__ char_arrays_equals(ary1_reg, ary2_reg, limit_reg, result_reg,
chr1_reg, chr2_reg, Ldone);
__ bind(Lequal);
__ mov(result_reg, 1); //equal
__ bind(Ldone);
%}
%}
//----------FRAME--------------------------------------------------------------
// Definition of frame structure and management information.
//
// S T A C K L A Y O U T Allocators stack-slot number
// | (to get allocators register number
// G Owned by | | v add VMRegImpl::stack0)
// r CALLER | |
// o | +--------+ pad to even-align allocators stack-slot
// w V | pad0 | numbers; owned by CALLER
// t -----------+--------+----> Matcher::_in_arg_limit, unaligned
// h ^ | in | 5
// | | args | 4 Holes in incoming args owned by SELF
// | | | | 3
// | | +--------+
// V | | old out| Empty on Intel, window on Sparc
// | old |preserve| Must be even aligned.
// | SP-+--------+----> Matcher::_old_SP, 8 (or 16 in LP64)-byte aligned
// | | in | 3 area for Intel ret address
// Owned by |preserve| Empty on Sparc.
// SELF +--------+
// | | pad2 | 2 pad to align old SP
// | +--------+ 1
// | | locks | 0
// | +--------+----> VMRegImpl::stack0, 8 (or 16 in LP64)-byte aligned
// | | pad1 | 11 pad to align new SP
// | +--------+
// | | | 10
// | | spills | 9 spills
// V | | 8 (pad0 slot for callee)
// -----------+--------+----> Matcher::_out_arg_limit, unaligned
// ^ | out | 7
// | | args | 6 Holes in outgoing args owned by CALLEE
// Owned by +--------+
// CALLEE | new out| 6 Empty on Intel, window on Sparc
// | new |preserve| Must be even-aligned.
// | SP-+--------+----> Matcher::_new_SP, even aligned
// | | |
//
// Note 1: Only region 8-11 is determined by the allocator. Region 0-5 is
// known from SELF's arguments and the Java calling convention.
// Region 6-7 is determined per call site.
// Note 2: If the calling convention leaves holes in the incoming argument
// area, those holes are owned by SELF. Holes in the outgoing area
// are owned by the CALLEE. Holes should not be nessecary in the
// incoming area, as the Java calling convention is completely under
// the control of the AD file. Doubles can be sorted and packed to
// avoid holes. Holes in the outgoing arguments may be nessecary for
// varargs C calling conventions.
// Note 3: Region 0-3 is even aligned, with pad2 as needed. Region 3-5 is
// even aligned with pad0 as needed.
// Region 6 is even aligned. Region 6-7 is NOT even aligned;
// region 6-11 is even aligned; it may be padded out more so that
// the region from SP to FP meets the minimum stack alignment.
frame %{
// What direction does stack grow in (assumed to be same for native & Java)
stack_direction(TOWARDS_LOW);
// These two registers define part of the calling convention
// between compiled code and the interpreter.
inline_cache_reg(R_Ricklass); // Inline Cache Register or Method* for I2C
interpreter_method_oop_reg(R_Rmethod); // Method Oop Register when calling interpreter
// Optional: name the operand used by cisc-spilling to access [stack_pointer + offset]
cisc_spilling_operand_name(indOffset);
// Number of stack slots consumed by a Monitor enter
sync_stack_slots(1 * VMRegImpl::slots_per_word);
// Compiled code's Frame Pointer
frame_pointer(R_R13);
// Stack alignment requirement
stack_alignment(StackAlignmentInBytes);
// LP64: Alignment size in bytes (128-bit -> 16 bytes)
// !LP64: Alignment size in bytes (64-bit -> 8 bytes)
// Number of stack slots between incoming argument block and the start of
// a new frame. The PROLOG must add this many slots to the stack. The
// EPILOG must remove this many slots.
// FP + LR
in_preserve_stack_slots(2 * VMRegImpl::slots_per_word);
// Number of outgoing stack slots killed above the out_preserve_stack_slots
// for calls to C. Supports the var-args backing area for register parms.
// ADLC doesn't support parsing expressions, so I folded the math by hand.
varargs_C_out_slots_killed( 0);
// The after-PROLOG location of the return address. Location of
// return address specifies a type (REG or STACK) and a number
// representing the register number (i.e. - use a register name) or
// stack slot.
// Ret Addr is on stack in slot 0 if no locks or verification or alignment.
// Otherwise, it is above the locks and verification slot and alignment word
return_addr(STACK - 1*VMRegImpl::slots_per_word +
align_up((Compile::current()->in_preserve_stack_slots() +
Compile::current()->fixed_slots()),
stack_alignment_in_slots()));
// Body of function which returns an OptoRegs array locating
// arguments either in registers or in stack slots for calling
// java
calling_convention %{
(void) SharedRuntime::java_calling_convention(sig_bt, regs, length, is_outgoing);
%}
// Body of function which returns an OptoRegs array locating
// arguments either in registers or in stack slots for callin
// C.
c_calling_convention %{
// This is obviously always outgoing
(void) SharedRuntime::c_calling_convention(sig_bt, regs, /*regs2=*/NULL, length);
%}
// Location of compiled Java return values. Same as C
return_value %{
return c2::return_value(ideal_reg);
%}
%}
//----------ATTRIBUTES---------------------------------------------------------
//----------Instruction Attributes---------------------------------------------
ins_attrib ins_cost(DEFAULT_COST); // Required cost attribute
ins_attrib ins_size(32); // Required size attribute (in bits)
ins_attrib ins_short_branch(0); // Required flag: is this instruction a
// non-matching short branch variant of some
// long branch?
//----------OPERANDS-----------------------------------------------------------
// Operand definitions must precede instruction definitions for correct parsing
// in the ADLC because operands constitute user defined types which are used in
// instruction definitions.
//----------Simple Operands----------------------------------------------------
// Immediate Operands
// Integer Immediate: 32-bit
operand immI() %{
match(ConI);
op_cost(0);
// formats are generated automatically for constants and base registers
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: 8-bit unsigned - for VMOV
operand immU8() %{
predicate(0 <= n->get_int() && (n->get_int() <= 255));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: 16-bit
operand immI16() %{
predicate((n->get_int() >> 16) == 0 && VM_Version::supports_movw());
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: offset for half and double word loads and stores
operand immIHD() %{
predicate(is_memoryHD(n->get_int()));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: offset for fp loads and stores
operand immIFP() %{
predicate(is_memoryfp(n->get_int()) && ((n->get_int() & 3) == 0));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Valid scale values for addressing modes and shifts
operand immU5() %{
predicate(0 <= n->get_int() && (n->get_int() <= 31));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: 6-bit
operand immU6Big() %{
predicate(n->get_int() >= 32 && n->get_int() <= 63);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: 0-bit
operand immI0() %{
predicate(n->get_int() == 0);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: the value 1
operand immI_1() %{
predicate(n->get_int() == 1);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: the value 2
operand immI_2() %{
predicate(n->get_int() == 2);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: the value 3
operand immI_3() %{
predicate(n->get_int() == 3);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: the value 4
operand immI_4() %{
predicate(n->get_int() == 4);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: the value 8
operand immI_8() %{
predicate(n->get_int() == 8);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Int Immediate non-negative
operand immU31()
%{
predicate(n->get_int() >= 0);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: the values 32-63
operand immI_32_63() %{
predicate(n->get_int() >= 32 && n->get_int() <= 63);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Immediates for special shifts (sign extend)
// Integer Immediate: the value 16
operand immI_16() %{
predicate(n->get_int() == 16);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: the value 24
operand immI_24() %{
predicate(n->get_int() == 24);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: the value 255
operand immI_255() %{
predicate( n->get_int() == 255 );
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediate: the value 65535
operand immI_65535() %{
predicate(n->get_int() == 65535);
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediates for arithmetic instructions
operand aimmI() %{
predicate(is_aimm(n->get_int()));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
operand aimmIneg() %{
predicate(is_aimm(-n->get_int()));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
operand aimmU31() %{
predicate((0 <= n->get_int()) && is_aimm(n->get_int()));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Immediates for logical instructions
operand limmI() %{
predicate(is_limmI(n->get_int()));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
operand limmIlow8() %{
predicate(is_limmI_low(n->get_int(), 8));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
operand limmU31() %{
predicate(0 <= n->get_int() && is_limmI(n->get_int()));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
operand limmIn() %{
predicate(is_limmI(~n->get_int()));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Long Immediate: the value FF
operand immL_FF() %{
predicate( n->get_long() == 0xFFL );
match(ConL);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Long Immediate: the value FFFF
operand immL_FFFF() %{
predicate( n->get_long() == 0xFFFFL );
match(ConL);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Pointer Immediate: 32 or 64-bit
operand immP() %{
match(ConP);
op_cost(5);
// formats are generated automatically for constants and base registers
format %{ %}
interface(CONST_INTER);
%}
operand immP0() %{
predicate(n->get_ptr() == 0);
match(ConP);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
operand immP_poll() %{
predicate(n->get_ptr() != 0 && n->get_ptr() == (intptr_t)os::get_polling_page());
match(ConP);
// formats are generated automatically for constants and base registers
format %{ %}
interface(CONST_INTER);
%}
// Pointer Immediate
operand immN()
%{
match(ConN);
op_cost(10);
format %{ %}
interface(CONST_INTER);
%}
operand immNKlass()
%{
match(ConNKlass);
op_cost(10);
format %{ %}
interface(CONST_INTER);
%}
// NULL Pointer Immediate
operand immN0()
%{
predicate(n->get_narrowcon() == 0);
match(ConN);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
operand immL() %{
match(ConL);
op_cost(40);
// formats are generated automatically for constants and base registers
format %{ %}
interface(CONST_INTER);
%}
operand immL0() %{
predicate(n->get_long() == 0L);
match(ConL);
op_cost(0);
// formats are generated automatically for constants and base registers
format %{ %}
interface(CONST_INTER);
%}
// Long Immediate: 16-bit
operand immL16() %{
predicate(n->get_long() >= 0 && n->get_long() < (1<<16) && VM_Version::supports_movw());
match(ConL);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Long Immediate: low 32-bit mask
operand immL_32bits() %{
predicate(n->get_long() == 0xFFFFFFFFL);
match(ConL);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Double Immediate
operand immD() %{
match(ConD);
op_cost(40);
format %{ %}
interface(CONST_INTER);
%}
// Double Immediate: +0.0d.
operand immD0() %{
predicate(jlong_cast(n->getd()) == 0);
match(ConD);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
operand imm8D() %{
predicate(Assembler::double_num(n->getd()).can_be_imm8());
match(ConD);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Float Immediate
operand immF() %{
match(ConF);
op_cost(20);
format %{ %}
interface(CONST_INTER);
%}
// Float Immediate: +0.0f
operand immF0() %{
predicate(jint_cast(n->getf()) == 0);
match(ConF);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Float Immediate: encoded as 8 bits
operand imm8F() %{
predicate(Assembler::float_num(n->getf()).can_be_imm8());
match(ConF);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Integer Register Operands
// Integer Register
operand iRegI() %{
constraint(ALLOC_IN_RC(int_reg));
match(RegI);
match(R0RegI);
match(R1RegI);
match(R2RegI);
match(R3RegI);
match(R12RegI);
format %{ %}
interface(REG_INTER);
%}
// Pointer Register
operand iRegP() %{
constraint(ALLOC_IN_RC(ptr_reg));
match(RegP);
match(R0RegP);
match(R1RegP);
match(R2RegP);
match(RExceptionRegP);
match(R8RegP);
match(R9RegP);
match(RthreadRegP); // FIXME: move to sp_ptr_RegP?
match(R12RegP);
match(LRRegP);
match(sp_ptr_RegP);
match(store_ptr_RegP);
format %{ %}
interface(REG_INTER);
%}
// GPRs + Rthread + SP
operand sp_ptr_RegP() %{
constraint(ALLOC_IN_RC(sp_ptr_reg));
match(RegP);
match(iRegP);
match(SPRegP); // FIXME: check cost
format %{ %}
interface(REG_INTER);
%}
operand R0RegP() %{
constraint(ALLOC_IN_RC(R0_regP));
match(iRegP);
format %{ %}
interface(REG_INTER);
%}
operand R1RegP() %{
constraint(ALLOC_IN_RC(R1_regP));
match(iRegP);
format %{ %}
interface(REG_INTER);
%}
operand R8RegP() %{
constraint(ALLOC_IN_RC(R8_regP));
match(iRegP);
format %{ %}
interface(REG_INTER);
%}
operand R9RegP() %{
constraint(ALLOC_IN_RC(R9_regP));
match(iRegP);
format %{ %}
interface(REG_INTER);
%}
operand R12RegP() %{
constraint(ALLOC_IN_RC(R12_regP));
match(iRegP);
format %{ %}
interface(REG_INTER);
%}
operand R2RegP() %{
constraint(ALLOC_IN_RC(R2_regP));
match(iRegP);
format %{ %}
interface(REG_INTER);
%}
operand RExceptionRegP() %{
constraint(ALLOC_IN_RC(Rexception_regP));
match(iRegP);
format %{ %}
interface(REG_INTER);
%}
operand RthreadRegP() %{
constraint(ALLOC_IN_RC(Rthread_regP));
match(iRegP);
format %{ %}
interface(REG_INTER);
%}
operand IPRegP() %{
constraint(ALLOC_IN_RC(IP_regP));
match(iRegP);
format %{ %}
interface(REG_INTER);
%}
operand SPRegP() %{
constraint(ALLOC_IN_RC(SP_regP));
match(iRegP);
format %{ %}
interface(REG_INTER);
%}
operand LRRegP() %{
constraint(ALLOC_IN_RC(LR_regP));
match(iRegP);
format %{ %}
interface(REG_INTER);
%}
operand R0RegI() %{
constraint(ALLOC_IN_RC(R0_regI));
match(iRegI);
format %{ %}
interface(REG_INTER);
%}
operand R1RegI() %{
constraint(ALLOC_IN_RC(R1_regI));
match(iRegI);
format %{ %}
interface(REG_INTER);
%}
operand R2RegI() %{
constraint(ALLOC_IN_RC(R2_regI));
match(iRegI);
format %{ %}
interface(REG_INTER);
%}
operand R3RegI() %{
constraint(ALLOC_IN_RC(R3_regI));
match(iRegI);
format %{ %}
interface(REG_INTER);
%}
operand R12RegI() %{
constraint(ALLOC_IN_RC(R12_regI));
match(iRegI);
format %{ %}
interface(REG_INTER);
%}
// Long Register
operand iRegL() %{
constraint(ALLOC_IN_RC(long_reg));
match(RegL);
match(R0R1RegL);
match(R2R3RegL);
//match(iRegLex);
format %{ %}
interface(REG_INTER);
%}
operand iRegLd() %{
constraint(ALLOC_IN_RC(long_reg_align));
match(iRegL); // FIXME: allows unaligned R11/R12?
format %{ %}
interface(REG_INTER);
%}
// first long arg, or return value
operand R0R1RegL() %{
constraint(ALLOC_IN_RC(R0R1_regL));
match(iRegL);
format %{ %}
interface(REG_INTER);
%}
operand R2R3RegL() %{
constraint(ALLOC_IN_RC(R2R3_regL));
match(iRegL);
format %{ %}
interface(REG_INTER);
%}
// Condition Code Flag Register
operand flagsReg() %{
constraint(ALLOC_IN_RC(int_flags));
match(RegFlags);
format %{ "apsr" %}
interface(REG_INTER);
%}
// Result of compare to 0 (TST)
operand flagsReg_EQNELTGE() %{
constraint(ALLOC_IN_RC(int_flags));
match(RegFlags);
format %{ "apsr_EQNELTGE" %}
interface(REG_INTER);
%}
// Condition Code Register, unsigned comparisons.
operand flagsRegU() %{
constraint(ALLOC_IN_RC(int_flags));
match(RegFlags);
#ifdef TODO
match(RegFlagsP);
#endif
format %{ "apsr_U" %}
interface(REG_INTER);
%}
// Condition Code Register, pointer comparisons.
operand flagsRegP() %{
constraint(ALLOC_IN_RC(int_flags));
match(RegFlags);
format %{ "apsr_P" %}
interface(REG_INTER);
%}
// Condition Code Register, long comparisons.
operand flagsRegL_LTGE() %{
constraint(ALLOC_IN_RC(int_flags));
match(RegFlags);
format %{ "apsr_L_LTGE" %}
interface(REG_INTER);
%}
operand flagsRegL_EQNE() %{
constraint(ALLOC_IN_RC(int_flags));
match(RegFlags);
format %{ "apsr_L_EQNE" %}
interface(REG_INTER);
%}
operand flagsRegL_LEGT() %{
constraint(ALLOC_IN_RC(int_flags));
match(RegFlags);
format %{ "apsr_L_LEGT" %}
interface(REG_INTER);
%}
operand flagsRegUL_LTGE() %{
constraint(ALLOC_IN_RC(int_flags));
match(RegFlags);
format %{ "apsr_UL_LTGE" %}
interface(REG_INTER);
%}
operand flagsRegUL_EQNE() %{
constraint(ALLOC_IN_RC(int_flags));
match(RegFlags);
format %{ "apsr_UL_EQNE" %}
interface(REG_INTER);
%}
operand flagsRegUL_LEGT() %{
constraint(ALLOC_IN_RC(int_flags));
match(RegFlags);
format %{ "apsr_UL_LEGT" %}
interface(REG_INTER);
%}
// Condition Code Register, floating comparisons, unordered same as "less".
operand flagsRegF() %{
constraint(ALLOC_IN_RC(float_flags));
match(RegFlags);
format %{ "fpscr_F" %}
interface(REG_INTER);
%}
// Vectors
operand vecD() %{
constraint(ALLOC_IN_RC(actual_dflt_reg));
match(VecD);
format %{ %}
interface(REG_INTER);
%}
operand vecX() %{
constraint(ALLOC_IN_RC(vectorx_reg));
match(VecX);
format %{ %}
interface(REG_INTER);
%}
operand regD() %{
constraint(ALLOC_IN_RC(actual_dflt_reg));
match(RegD);
match(regD_low);
format %{ %}
interface(REG_INTER);
%}
operand regF() %{
constraint(ALLOC_IN_RC(sflt_reg));
match(RegF);
format %{ %}
interface(REG_INTER);
%}
operand regD_low() %{
constraint(ALLOC_IN_RC(dflt_low_reg));
match(RegD);
format %{ %}
interface(REG_INTER);
%}
// Special Registers
// Method Register
operand inline_cache_regP(iRegP reg) %{
constraint(ALLOC_IN_RC(Ricklass_regP));
match(reg);
format %{ %}
interface(REG_INTER);
%}
operand interpreter_method_oop_regP(iRegP reg) %{
constraint(ALLOC_IN_RC(Rmethod_regP));
match(reg);
format %{ %}
interface(REG_INTER);
%}
//----------Complex Operands---------------------------------------------------
// Indirect Memory Reference
operand indirect(sp_ptr_RegP reg) %{
constraint(ALLOC_IN_RC(sp_ptr_reg));
match(reg);
op_cost(100);
format %{ "[$reg]" %}
interface(MEMORY_INTER) %{
base($reg);
index(0xf); // PC => no index
scale(0x0);
disp(0x0);
%}
%}
// Indirect with Offset in ]-4096, 4096[
operand indOffset12(sp_ptr_RegP reg, immI12 offset) %{
constraint(ALLOC_IN_RC(sp_ptr_reg));
match(AddP reg offset);
op_cost(100);
format %{ "[$reg + $offset]" %}
interface(MEMORY_INTER) %{
base($reg);
index(0xf); // PC => no index
scale(0x0);
disp($offset);
%}
%}
// Indirect with offset for float load/store
operand indOffsetFP(sp_ptr_RegP reg, immIFP offset) %{
constraint(ALLOC_IN_RC(sp_ptr_reg));
match(AddP reg offset);
op_cost(100);
format %{ "[$reg + $offset]" %}
interface(MEMORY_INTER) %{
base($reg);
index(0xf); // PC => no index
scale(0x0);
disp($offset);
%}
%}
// Indirect with Offset for half and double words
operand indOffsetHD(sp_ptr_RegP reg, immIHD offset) %{
constraint(ALLOC_IN_RC(sp_ptr_reg));
match(AddP reg offset);
op_cost(100);
format %{ "[$reg + $offset]" %}
interface(MEMORY_INTER) %{
base($reg);
index(0xf); // PC => no index
scale(0x0);
disp($offset);
%}
%}
// Indirect with Offset and Offset+4 in ]-1024, 1024[
operand indOffsetFPx2(sp_ptr_RegP reg, immX10x2 offset) %{
constraint(ALLOC_IN_RC(sp_ptr_reg));
match(AddP reg offset);
op_cost(100);
format %{ "[$reg + $offset]" %}
interface(MEMORY_INTER) %{
base($reg);
index(0xf); // PC => no index
scale(0x0);
disp($offset);
%}
%}
// Indirect with Offset and Offset+4 in ]-4096, 4096[
operand indOffset12x2(sp_ptr_RegP reg, immI12x2 offset) %{
constraint(ALLOC_IN_RC(sp_ptr_reg));
match(AddP reg offset);
op_cost(100);
format %{ "[$reg + $offset]" %}
interface(MEMORY_INTER) %{
base($reg);
index(0xf); // PC => no index
scale(0x0);
disp($offset);
%}
%}
// Indirect with Register Index
operand indIndex(iRegP addr, iRegX index) %{
constraint(ALLOC_IN_RC(ptr_reg));
match(AddP addr index);
op_cost(100);
format %{ "[$addr + $index]" %}
interface(MEMORY_INTER) %{
base($addr);
index($index);
scale(0x0);
disp(0x0);
%}
%}
// Indirect Memory Times Scale Plus Index Register
operand indIndexScale(iRegP addr, iRegX index, immU5 scale) %{
constraint(ALLOC_IN_RC(ptr_reg));
match(AddP addr (LShiftX index scale));
op_cost(100);
format %{"[$addr + $index << $scale]" %}
interface(MEMORY_INTER) %{
base($addr);
index($index);
scale($scale);
disp(0x0);
%}
%}
// Operands for expressing Control Flow
// NOTE: Label is a predefined operand which should not be redefined in
// the AD file. It is generically handled within the ADLC.
//----------Conditional Branch Operands----------------------------------------
// Comparison Op - This is the operation of the comparison, and is limited to
// the following set of codes:
// L (<), LE (<=), G (>), GE (>=), E (==), NE (!=)
//
// Other attributes of the comparison, such as unsignedness, are specified
// by the comparison instruction that sets a condition code flags register.
// That result is represented by a flags operand whose subtype is appropriate
// to the unsignedness (etc.) of the comparison.
//
// Later, the instruction which matches both the Comparison Op (a Bool) and
// the flags (produced by the Cmp) specifies the coding of the comparison op
// by matching a specific subtype of Bool operand below, such as cmpOpU.
operand cmpOp() %{
match(Bool);
format %{ "" %}
interface(COND_INTER) %{
equal(0x0);
not_equal(0x1);
less(0xb);
greater_equal(0xa);
less_equal(0xd);
greater(0xc);
overflow(0x0); // unsupported/unimplemented
no_overflow(0x0); // unsupported/unimplemented
%}
%}
// integer comparison with 0, signed
operand cmpOp0() %{
match(Bool);
format %{ "" %}
interface(COND_INTER) %{
equal(0x0);
not_equal(0x1);
less(0x4);
greater_equal(0x5);
less_equal(0xd); // unsupported
greater(0xc); // unsupported
overflow(0x0); // unsupported/unimplemented
no_overflow(0x0); // unsupported/unimplemented
%}
%}
// Comparison Op, unsigned
operand cmpOpU() %{
match(Bool);
format %{ "u" %}
interface(COND_INTER) %{
equal(0x0);
not_equal(0x1);
less(0x3);
greater_equal(0x2);
less_equal(0x9);
greater(0x8);
overflow(0x0); // unsupported/unimplemented
no_overflow(0x0); // unsupported/unimplemented
%}
%}
// Comparison Op, pointer (same as unsigned)
operand cmpOpP() %{
match(Bool);
format %{ "p" %}
interface(COND_INTER) %{
equal(0x0);
not_equal(0x1);
less(0x3);
greater_equal(0x2);
less_equal(0x9);
greater(0x8);
overflow(0x0); // unsupported/unimplemented
no_overflow(0x0); // unsupported/unimplemented
%}
%}
operand cmpOpL() %{
match(Bool);
format %{ "L" %}
interface(COND_INTER) %{
equal(0x0);
not_equal(0x1);
less(0xb);
greater_equal(0xa);
less_equal(0xd);
greater(0xc);
overflow(0x0); // unsupported/unimplemented
no_overflow(0x0); // unsupported/unimplemented
%}
%}
operand cmpOpL_commute() %{
match(Bool);
format %{ "L" %}
interface(COND_INTER) %{
equal(0x0);
not_equal(0x1);
less(0xc);
greater_equal(0xd);
less_equal(0xa);
greater(0xb);
overflow(0x0); // unsupported/unimplemented
no_overflow(0x0); // unsupported/unimplemented
%}
%}
operand cmpOpUL() %{
match(Bool);
format %{ "UL" %}
interface(COND_INTER) %{
equal(0x0);
not_equal(0x1);
less(0x3);
greater_equal(0x2);
less_equal(0x9);
greater(0x8);
overflow(0x0); // unsupported/unimplemented
no_overflow(0x0); // unsupported/unimplemented
%}
%}
operand cmpOpUL_commute() %{
match(Bool);
format %{ "UL" %}
interface(COND_INTER) %{
equal(0x0);
not_equal(0x1);
less(0x8);
greater_equal(0x9);
less_equal(0x2);
greater(0x3);
overflow(0x0); // unsupported/unimplemented
no_overflow(0x0); // unsupported/unimplemented
%}
%}
//----------OPERAND CLASSES----------------------------------------------------
// Operand Classes are groups of operands that are used to simplify
// instruction definitions by not requiring the AD writer to specify separate
// instructions for every form of operand when the instruction accepts
// multiple operand types with the same basic encoding and format. The classic
// case of this is memory operands.
opclass memoryI ( indirect, indOffset12, indIndex, indIndexScale );
opclass memoryP ( indirect, indOffset12, indIndex, indIndexScale );
opclass memoryF ( indirect, indOffsetFP );
opclass memoryF2 ( indirect, indOffsetFPx2 );
opclass memoryD ( indirect, indOffsetFP );
opclass memoryfp( indirect, indOffsetFP );
opclass memoryB ( indirect, indIndex, indOffsetHD );
opclass memoryS ( indirect, indIndex, indOffsetHD );
opclass memoryL ( indirect, indIndex, indOffsetHD );
opclass memoryScaledI(indIndexScale);
opclass memoryScaledP(indIndexScale);
// when ldrex/strex is used:
opclass memoryex ( indirect );
opclass indIndexMemory( indIndex );
opclass memorylong ( indirect, indOffset12x2 );
opclass memoryvld ( indirect /* , write back mode not implemented */ );
//----------PIPELINE-----------------------------------------------------------
pipeline %{
//----------ATTRIBUTES---------------------------------------------------------
attributes %{
fixed_size_instructions; // Fixed size instructions
max_instructions_per_bundle = 4; // Up to 4 instructions per bundle
instruction_unit_size = 4; // An instruction is 4 bytes long
instruction_fetch_unit_size = 16; // The processor fetches one line
instruction_fetch_units = 1; // of 16 bytes
// List of nop instructions
nops( Nop_A0, Nop_A1, Nop_MS, Nop_FA, Nop_BR );
%}
//----------RESOURCES----------------------------------------------------------
// Resources are the functional units available to the machine
resources(A0, A1, MS, BR, FA, FM, IDIV, FDIV, IALU = A0 | A1);
//----------PIPELINE DESCRIPTION-----------------------------------------------
// Pipeline Description specifies the stages in the machine's pipeline
pipe_desc(A, P, F, B, I, J, S, R, E, C, M, W, X, T, D);
//----------PIPELINE CLASSES---------------------------------------------------
// Pipeline Classes describe the stages in which input and output are
// referenced by the hardware pipeline.
// Integer ALU reg-reg operation
pipe_class ialu_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
single_instruction;
dst : E(write);
src1 : R(read);
src2 : R(read);
IALU : R;
%}
// Integer ALU reg-reg long operation
pipe_class ialu_reg_reg_2(iRegL dst, iRegL src1, iRegL src2) %{
instruction_count(2);
dst : E(write);
src1 : R(read);
src2 : R(read);
IALU : R;
IALU : R;
%}
// Integer ALU reg-reg long dependent operation
pipe_class ialu_reg_reg_2_dep(iRegL dst, iRegL src1, iRegL src2, flagsReg cr) %{
instruction_count(1); multiple_bundles;
dst : E(write);
src1 : R(read);
src2 : R(read);
cr : E(write);
IALU : R(2);
%}
// Integer ALU reg-imm operaion
pipe_class ialu_reg_imm(iRegI dst, iRegI src1) %{
single_instruction;
dst : E(write);
src1 : R(read);
IALU : R;
%}
// Integer ALU reg-reg operation with condition code
pipe_class ialu_cc_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
single_instruction;
dst : E(write);
cr : E(write);
src1 : R(read);
src2 : R(read);
IALU : R;
%}
// Integer ALU zero-reg operation
pipe_class ialu_zero_reg(iRegI dst, immI0 zero, iRegI src2) %{
single_instruction;
dst : E(write);
src2 : R(read);
IALU : R;
%}
// Integer ALU zero-reg operation with condition code only
pipe_class ialu_cconly_zero_reg(flagsReg cr, iRegI src) %{
single_instruction;
cr : E(write);
src : R(read);
IALU : R;
%}
// Integer ALU reg-reg operation with condition code only
pipe_class ialu_cconly_reg_reg(flagsReg cr, iRegI src1, iRegI src2) %{
single_instruction;
cr : E(write);
src1 : R(read);
src2 : R(read);
IALU : R;
%}
// Integer ALU reg-imm operation with condition code only
pipe_class ialu_cconly_reg_imm(flagsReg cr, iRegI src1) %{
single_instruction;
cr : E(write);
src1 : R(read);
IALU : R;
%}
// Integer ALU reg-reg-zero operation with condition code only
pipe_class ialu_cconly_reg_reg_zero(flagsReg cr, iRegI src1, iRegI src2, immI0 zero) %{
single_instruction;
cr : E(write);
src1 : R(read);
src2 : R(read);
IALU : R;
%}
// Integer ALU reg-imm-zero operation with condition code only
pipe_class ialu_cconly_reg_imm_zero(flagsReg cr, iRegI src1, immI0 zero) %{
single_instruction;
cr : E(write);
src1 : R(read);
IALU : R;
%}
// Integer ALU reg-reg operation with condition code, src1 modified
pipe_class ialu_cc_rwreg_reg(flagsReg cr, iRegI src1, iRegI src2) %{
single_instruction;
cr : E(write);
src1 : E(write);
src1 : R(read);
src2 : R(read);
IALU : R;
%}
pipe_class cmpL_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg cr ) %{
multiple_bundles;
dst : E(write)+4;
cr : E(write);
src1 : R(read);
src2 : R(read);
IALU : R(3);
BR : R(2);
%}
// Integer ALU operation
pipe_class ialu_none(iRegI dst) %{
single_instruction;
dst : E(write);
IALU : R;
%}
// Integer ALU reg operation
pipe_class ialu_reg(iRegI dst, iRegI src) %{
single_instruction; may_have_no_code;
dst : E(write);
src : R(read);
IALU : R;
%}
// Integer ALU reg conditional operation
// This instruction has a 1 cycle stall, and cannot execute
// in the same cycle as the instruction setting the condition
// code. We kludge this by pretending to read the condition code
// 1 cycle earlier, and by marking the functional units as busy
// for 2 cycles with the result available 1 cycle later than
// is really the case.
pipe_class ialu_reg_flags( iRegI op2_out, iRegI op2_in, iRegI op1, flagsReg cr ) %{
single_instruction;
op2_out : C(write);
op1 : R(read);
cr : R(read); // This is really E, with a 1 cycle stall
BR : R(2);
MS : R(2);
%}
// Integer ALU reg operation
pipe_class ialu_move_reg_L_to_I(iRegI dst, iRegL src) %{
single_instruction; may_have_no_code;
dst : E(write);
src : R(read);
IALU : R;
%}
pipe_class ialu_move_reg_I_to_L(iRegL dst, iRegI src) %{
single_instruction; may_have_no_code;
dst : E(write);
src : R(read);
IALU : R;
%}
// Two integer ALU reg operations
pipe_class ialu_reg_2(iRegL dst, iRegL src) %{
instruction_count(2);
dst : E(write);
src : R(read);
A0 : R;
A1 : R;
%}
// Two integer ALU reg operations
pipe_class ialu_move_reg_L_to_L(iRegL dst, iRegL src) %{
instruction_count(2); may_have_no_code;
dst : E(write);
src : R(read);
A0 : R;
A1 : R;
%}
// Integer ALU imm operation
pipe_class ialu_imm(iRegI dst) %{
single_instruction;
dst : E(write);
IALU : R;
%}
pipe_class ialu_imm_n(iRegI dst) %{
single_instruction;
dst : E(write);
IALU : R;
%}
// Integer ALU reg-reg with carry operation
pipe_class ialu_reg_reg_cy(iRegI dst, iRegI src1, iRegI src2, iRegI cy) %{
single_instruction;
dst : E(write);
src1 : R(read);
src2 : R(read);
IALU : R;
%}
// Integer ALU cc operation
pipe_class ialu_cc(iRegI dst, flagsReg cc) %{
single_instruction;
dst : E(write);
cc : R(read);
IALU : R;
%}
// Integer ALU cc / second IALU operation
pipe_class ialu_reg_ialu( iRegI dst, iRegI src ) %{
instruction_count(1); multiple_bundles;
dst : E(write)+1;
src : R(read);
IALU : R;
%}
// Integer ALU cc / second IALU operation
pipe_class ialu_reg_reg_ialu( iRegI dst, iRegI p, iRegI q ) %{
instruction_count(1); multiple_bundles;
dst : E(write)+1;
p : R(read);
q : R(read);
IALU : R;
%}
// Integer ALU hi-lo-reg operation
pipe_class ialu_hi_lo_reg(iRegI dst, immI src) %{
instruction_count(1); multiple_bundles;
dst : E(write)+1;
IALU : R(2);
%}
// Long Constant
pipe_class loadConL( iRegL dst, immL src ) %{
instruction_count(2); multiple_bundles;
dst : E(write)+1;
IALU : R(2);
IALU : R(2);
%}
// Pointer Constant
pipe_class loadConP( iRegP dst, immP src ) %{
instruction_count(0); multiple_bundles;
fixed_latency(6);
%}
// Polling Address
pipe_class loadConP_poll( iRegP dst, immP_poll src ) %{
dst : E(write);
IALU : R;
%}
// Long Constant small
pipe_class loadConLlo( iRegL dst, immL src ) %{
instruction_count(2);
dst : E(write);
IALU : R;
IALU : R;
%}
// [PHH] This is wrong for 64-bit. See LdImmF/D.
pipe_class loadConFD(regF dst, immF src, iRegP tmp) %{
instruction_count(1); multiple_bundles;
src : R(read);
dst : M(write)+1;
IALU : R;
MS : E;
%}
// Integer ALU nop operation
pipe_class ialu_nop() %{
single_instruction;
IALU : R;
%}
// Integer ALU nop operation
pipe_class ialu_nop_A0() %{
single_instruction;
A0 : R;
%}
// Integer ALU nop operation
pipe_class ialu_nop_A1() %{
single_instruction;
A1 : R;
%}
// Integer Multiply reg-reg operation
pipe_class imul_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
single_instruction;
dst : E(write);
src1 : R(read);
src2 : R(read);
MS : R(5);
%}
pipe_class mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
single_instruction;
dst : E(write)+4;
src1 : R(read);
src2 : R(read);
MS : R(6);
%}
// Integer Divide reg-reg
pipe_class sdiv_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI temp, flagsReg cr) %{
instruction_count(1); multiple_bundles;
dst : E(write);
temp : E(write);
src1 : R(read);
src2 : R(read);
temp : R(read);
MS : R(38);
%}
// Long Divide
pipe_class divL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
dst : E(write)+71;
src1 : R(read);
src2 : R(read)+1;
MS : R(70);
%}
// Floating Point Add Float
pipe_class faddF_reg_reg(regF dst, regF src1, regF src2) %{
single_instruction;
dst : X(write);
src1 : E(read);
src2 : E(read);
FA : R;
%}
// Floating Point Add Double
pipe_class faddD_reg_reg(regD dst, regD src1, regD src2) %{
single_instruction;
dst : X(write);
src1 : E(read);
src2 : E(read);
FA : R;
%}
// Floating Point Conditional Move based on integer flags
pipe_class int_conditional_float_move (cmpOp cmp, flagsReg cr, regF dst, regF src) %{
single_instruction;
dst : X(write);
src : E(read);
cr : R(read);
FA : R(2);
BR : R(2);
%}
// Floating Point Conditional Move based on integer flags
pipe_class int_conditional_double_move (cmpOp cmp, flagsReg cr, regD dst, regD src) %{
single_instruction;
dst : X(write);
src : E(read);
cr : R(read);
FA : R(2);
BR : R(2);
%}
// Floating Point Multiply Float
pipe_class fmulF_reg_reg(regF dst, regF src1, regF src2) %{
single_instruction;
dst : X(write);
src1 : E(read);
src2 : E(read);
FM : R;
%}
// Floating Point Multiply Double
pipe_class fmulD_reg_reg(regD dst, regD src1, regD src2) %{
single_instruction;
dst : X(write);
src1 : E(read);
src2 : E(read);
FM : R;
%}
// Floating Point Divide Float
pipe_class fdivF_reg_reg(regF dst, regF src1, regF src2) %{
single_instruction;
dst : X(write);
src1 : E(read);
src2 : E(read);
FM : R;
FDIV : C(14);
%}
// Floating Point Divide Double
pipe_class fdivD_reg_reg(regD dst, regD src1, regD src2) %{
single_instruction;
dst : X(write);
src1 : E(read);
src2 : E(read);
FM : R;
FDIV : C(17);
%}
// Floating Point Move/Negate/Abs Float
pipe_class faddF_reg(regF dst, regF src) %{
single_instruction;
dst : W(write);
src : E(read);
FA : R(1);
%}
// Floating Point Move/Negate/Abs Double
pipe_class faddD_reg(regD dst, regD src) %{
single_instruction;
dst : W(write);
src : E(read);
FA : R;
%}
// Floating Point Convert F->D
pipe_class fcvtF2D(regD dst, regF src) %{
single_instruction;
dst : X(write);
src : E(read);
FA : R;
%}
// Floating Point Convert I->D
pipe_class fcvtI2D(regD dst, regF src) %{
single_instruction;
dst : X(write);
src : E(read);
FA : R;
%}
// Floating Point Convert LHi->D
pipe_class fcvtLHi2D(regD dst, regD src) %{
single_instruction;
dst : X(write);
src : E(read);
FA : R;
%}
// Floating Point Convert L->D
pipe_class fcvtL2D(regD dst, iRegL src) %{
single_instruction;
dst : X(write);
src : E(read);
FA : R;
%}
// Floating Point Convert L->F
pipe_class fcvtL2F(regF dst, iRegL src) %{
single_instruction;
dst : X(write);
src : E(read);
FA : R;
%}
// Floating Point Convert D->F
pipe_class fcvtD2F(regD dst, regF src) %{
single_instruction;
dst : X(write);
src : E(read);
FA : R;
%}
// Floating Point Convert I->L
pipe_class fcvtI2L(regD dst, regF src) %{
single_instruction;
dst : X(write);
src : E(read);
FA : R;
%}
// Floating Point Convert D->F
pipe_class fcvtD2I(iRegI dst, regD src, flagsReg cr) %{
instruction_count(1); multiple_bundles;
dst : X(write)+6;
src : E(read);
FA : R;
%}
// Floating Point Convert D->L
pipe_class fcvtD2L(regD dst, regD src, flagsReg cr) %{
instruction_count(1); multiple_bundles;
dst : X(write)+6;
src : E(read);
FA : R;
%}
// Floating Point Convert F->I
pipe_class fcvtF2I(regF dst, regF src, flagsReg cr) %{
instruction_count(1); multiple_bundles;
dst : X(write)+6;
src : E(read);
FA : R;
%}
// Floating Point Convert F->L
pipe_class fcvtF2L(regD dst, regF src, flagsReg cr) %{
instruction_count(1); multiple_bundles;
dst : X(write)+6;
src : E(read);
FA : R;
%}
// Floating Point Convert I->F
pipe_class fcvtI2F(regF dst, regF src) %{
single_instruction;
dst : X(write);
src : E(read);
FA : R;
%}
// Floating Point Compare
pipe_class faddF_fcc_reg_reg_zero(flagsRegF cr, regF src1, regF src2, immI0 zero) %{
single_instruction;
cr : X(write);
src1 : E(read);
src2 : E(read);
FA : R;
%}
// Floating Point Compare
pipe_class faddD_fcc_reg_reg_zero(flagsRegF cr, regD src1, regD src2, immI0 zero) %{
single_instruction;
cr : X(write);
src1 : E(read);
src2 : E(read);
FA : R;
%}
// Floating Add Nop
pipe_class fadd_nop() %{
single_instruction;
FA : R;
%}
// Integer Store to Memory
pipe_class istore_mem_reg(memoryI mem, iRegI src) %{
single_instruction;
mem : R(read);
src : C(read);
MS : R;
%}
// Integer Store to Memory
pipe_class istore_mem_spORreg(memoryI mem, sp_ptr_RegP src) %{
single_instruction;
mem : R(read);
src : C(read);
MS : R;
%}
// Float Store
pipe_class fstoreF_mem_reg(memoryF mem, RegF src) %{
single_instruction;
mem : R(read);
src : C(read);
MS : R;
%}
// Float Store
pipe_class fstoreF_mem_zero(memoryF mem, immF0 src) %{
single_instruction;
mem : R(read);
MS : R;
%}
// Double Store
pipe_class fstoreD_mem_reg(memoryD mem, RegD src) %{
instruction_count(1);
mem : R(read);
src : C(read);
MS : R;
%}
// Double Store
pipe_class fstoreD_mem_zero(memoryD mem, immD0 src) %{
single_instruction;
mem : R(read);
MS : R;
%}
// Integer Load (when sign bit propagation not needed)
pipe_class iload_mem(iRegI dst, memoryI mem) %{
single_instruction;
mem : R(read);
dst : C(write);
MS : R;
%}
// Integer Load (when sign bit propagation or masking is needed)
pipe_class iload_mask_mem(iRegI dst, memoryI mem) %{
single_instruction;
mem : R(read);
dst : M(write);
MS : R;
%}
// Float Load
pipe_class floadF_mem(regF dst, memoryF mem) %{
single_instruction;
mem : R(read);
dst : M(write);
MS : R;
%}
// Float Load
pipe_class floadD_mem(regD dst, memoryD mem) %{
instruction_count(1); multiple_bundles; // Again, unaligned argument is only multiple case
mem : R(read);
dst : M(write);
MS : R;
%}
// Memory Nop
pipe_class mem_nop() %{
single_instruction;
MS : R;
%}
pipe_class sethi(iRegP dst, immI src) %{
single_instruction;
dst : E(write);
IALU : R;
%}
pipe_class loadPollP(iRegP poll) %{
single_instruction;
poll : R(read);
MS : R;
%}
pipe_class br(Universe br, label labl) %{
single_instruction_with_delay_slot;
BR : R;
%}
pipe_class br_cc(Universe br, cmpOp cmp, flagsReg cr, label labl) %{
single_instruction_with_delay_slot;
cr : E(read);
BR : R;
%}
pipe_class br_reg(Universe br, cmpOp cmp, iRegI op1, label labl) %{
single_instruction_with_delay_slot;
op1 : E(read);
BR : R;
MS : R;
%}
pipe_class br_nop() %{
single_instruction;
BR : R;
%}
pipe_class simple_call(method meth) %{
instruction_count(2); multiple_bundles; force_serialization;
fixed_latency(100);
BR : R(1);
MS : R(1);
A0 : R(1);
%}
pipe_class compiled_call(method meth) %{
instruction_count(1); multiple_bundles; force_serialization;
fixed_latency(100);
MS : R(1);
%}
pipe_class call(method meth) %{
instruction_count(0); multiple_bundles; force_serialization;
fixed_latency(100);
%}
pipe_class tail_call(Universe ignore, label labl) %{
single_instruction; has_delay_slot;
fixed_latency(100);
BR : R(1);
MS : R(1);
%}
pipe_class ret(Universe ignore) %{
single_instruction; has_delay_slot;
BR : R(1);
MS : R(1);
%}
// The real do-nothing guy
pipe_class empty( ) %{
instruction_count(0);
%}
pipe_class long_memory_op() %{
instruction_count(0); multiple_bundles; force_serialization;
fixed_latency(25);
MS : R(1);
%}
// Check-cast
pipe_class partial_subtype_check_pipe(Universe ignore, iRegP array, iRegP match ) %{
array : R(read);
match : R(read);
IALU : R(2);
BR : R(2);
MS : R;
%}
// Convert FPU flags into +1,0,-1
pipe_class floating_cmp( iRegI dst, regF src1, regF src2 ) %{
src1 : E(read);
src2 : E(read);
dst : E(write);
FA : R;
MS : R(2);
BR : R(2);
%}
// Compare for p < q, and conditionally add y
pipe_class cadd_cmpltmask( iRegI p, iRegI q, iRegI y ) %{
p : E(read);
q : E(read);
y : E(read);
IALU : R(3)
%}
// Perform a compare, then move conditionally in a branch delay slot.
pipe_class min_max( iRegI src2, iRegI srcdst ) %{
src2 : E(read);
srcdst : E(read);
IALU : R;
BR : R;
%}
// Define the class for the Nop node
define %{
MachNop = ialu_nop;
%}
%}
//----------INSTRUCTIONS-------------------------------------------------------
//------------Special Nop instructions for bundling - no match rules-----------
// Nop using the A0 functional unit
instruct Nop_A0() %{
ins_pipe(ialu_nop_A0);
%}
// Nop using the A1 functional unit
instruct Nop_A1( ) %{
ins_pipe(ialu_nop_A1);
%}
// Nop using the memory functional unit
instruct Nop_MS( ) %{
ins_pipe(mem_nop);
%}
// Nop using the floating add functional unit
instruct Nop_FA( ) %{
ins_pipe(fadd_nop);
%}
// Nop using the branch functional unit
instruct Nop_BR( ) %{
ins_pipe(br_nop);
%}
//----------Load/Store/Move Instructions---------------------------------------
//----------Load Instructions--------------------------------------------------
// Load Byte (8bit signed)
instruct loadB(iRegI dst, memoryB mem) %{
match(Set dst (LoadB mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDRSB $dst,$mem\t! byte -> int" %}
ins_encode %{
__ ldrsb($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mask_mem);
%}
// Load Byte (8bit signed) into a Long Register
instruct loadB2L(iRegL dst, memoryB mem) %{
match(Set dst (ConvI2L (LoadB mem)));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "LDRSB $dst.lo,$mem\t! byte -> long\n\t"
"ASR $dst.hi,$dst.lo,31" %}
ins_encode %{
__ ldrsb($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), AsmOperand($dst$$Register, asr, 31));
%}
ins_pipe(iload_mask_mem);
%}
// Load Unsigned Byte (8bit UNsigned) into an int reg
instruct loadUB(iRegI dst, memoryB mem) %{
match(Set dst (LoadUB mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDRB $dst,$mem\t! ubyte -> int" %}
ins_encode %{
__ ldrb($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mem);
%}
// Load Unsigned Byte (8bit UNsigned) into a Long Register
instruct loadUB2L(iRegL dst, memoryB mem) %{
match(Set dst (ConvI2L (LoadUB mem)));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "LDRB $dst.lo,$mem\t! ubyte -> long\n\t"
"MOV $dst.hi,0" %}
ins_encode %{
__ ldrb($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), 0);
%}
ins_pipe(iload_mem);
%}
// Load Unsigned Byte (8 bit UNsigned) with immediate mask into Long Register
instruct loadUB2L_limmI(iRegL dst, memoryB mem, limmIlow8 mask) %{
match(Set dst (ConvI2L (AndI (LoadUB mem) mask)));
ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);
size(12);
format %{ "LDRB $dst.lo,$mem\t! ubyte -> long\n\t"
"MOV $dst.hi,0\n\t"
"AND $dst.lo,$dst.lo,$mask" %}
ins_encode %{
__ ldrb($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), 0);
__ andr($dst$$Register, $dst$$Register, limmI_low($mask$$constant, 8));
%}
ins_pipe(iload_mem);
%}
// Load Short (16bit signed)
instruct loadS(iRegI dst, memoryS mem) %{
match(Set dst (LoadS mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDRSH $dst,$mem\t! short" %}
ins_encode %{
__ ldrsh($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mask_mem);
%}
// Load Short (16 bit signed) to Byte (8 bit signed)
instruct loadS2B(iRegI dst, memoryS mem, immI_24 twentyfour) %{
match(Set dst (RShiftI (LShiftI (LoadS mem) twentyfour) twentyfour));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDRSB $dst,$mem\t! short -> byte" %}
ins_encode %{
__ ldrsb($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mask_mem);
%}
// Load Short (16bit signed) into a Long Register
instruct loadS2L(iRegL dst, memoryS mem) %{
match(Set dst (ConvI2L (LoadS mem)));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "LDRSH $dst.lo,$mem\t! short -> long\n\t"
"ASR $dst.hi,$dst.lo,31" %}
ins_encode %{
__ ldrsh($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), AsmOperand($dst$$Register, asr, 31));
%}
ins_pipe(iload_mask_mem);
%}
// Load Unsigned Short/Char (16bit UNsigned)
instruct loadUS(iRegI dst, memoryS mem) %{
match(Set dst (LoadUS mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDRH $dst,$mem\t! ushort/char" %}
ins_encode %{
__ ldrh($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mem);
%}
// Load Unsigned Short/Char (16 bit UNsigned) to Byte (8 bit signed)
instruct loadUS2B(iRegI dst, memoryB mem, immI_24 twentyfour) %{
match(Set dst (RShiftI (LShiftI (LoadUS mem) twentyfour) twentyfour));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDRSB $dst,$mem\t! ushort -> byte" %}
ins_encode %{
__ ldrsb($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mask_mem);
%}
// Load Unsigned Short/Char (16bit UNsigned) into a Long Register
instruct loadUS2L(iRegL dst, memoryS mem) %{
match(Set dst (ConvI2L (LoadUS mem)));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "LDRH $dst.lo,$mem\t! short -> long\n\t"
"MOV $dst.hi, 0" %}
ins_encode %{
__ ldrh($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), 0);
%}
ins_pipe(iload_mem);
%}
// Load Unsigned Short/Char (16bit UNsigned) with mask 0xFF into a Long Register
instruct loadUS2L_immI_255(iRegL dst, memoryB mem, immI_255 mask) %{
match(Set dst (ConvI2L (AndI (LoadUS mem) mask)));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "LDRB $dst.lo,$mem\t! \n\t"
"MOV $dst.hi, 0" %}
ins_encode %{
__ ldrb($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), 0);
%}
ins_pipe(iload_mem);
%}
// Load Unsigned Short/Char (16bit UNsigned) with a immediate mask into a Long Register
instruct loadUS2L_limmI(iRegL dst, memoryS mem, limmI mask) %{
match(Set dst (ConvI2L (AndI (LoadUS mem) mask)));
ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);
size(12);
format %{ "LDRH $dst,$mem\t! ushort/char & mask -> long\n\t"
"MOV $dst.hi, 0\n\t"
"AND $dst,$dst,$mask" %}
ins_encode %{
__ ldrh($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), 0);
__ andr($dst$$Register, $dst$$Register, $mask$$constant);
%}
ins_pipe(iload_mem);
%}
// Load Integer
instruct loadI(iRegI dst, memoryI mem) %{
match(Set dst (LoadI mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "ldr_s32 $dst,$mem\t! int" %}
ins_encode %{
__ ldr_s32($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mem);
%}
// Load Integer to Byte (8 bit signed)
instruct loadI2B(iRegI dst, memoryS mem, immI_24 twentyfour) %{
match(Set dst (RShiftI (LShiftI (LoadI mem) twentyfour) twentyfour));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDRSB $dst,$mem\t! int -> byte" %}
ins_encode %{
__ ldrsb($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mask_mem);
%}
// Load Integer to Unsigned Byte (8 bit UNsigned)
instruct loadI2UB(iRegI dst, memoryB mem, immI_255 mask) %{
match(Set dst (AndI (LoadI mem) mask));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDRB $dst,$mem\t! int -> ubyte" %}
ins_encode %{
__ ldrb($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mask_mem);
%}
// Load Integer to Short (16 bit signed)
instruct loadI2S(iRegI dst, memoryS mem, immI_16 sixteen) %{
match(Set dst (RShiftI (LShiftI (LoadI mem) sixteen) sixteen));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDRSH $dst,$mem\t! int -> short" %}
ins_encode %{
__ ldrsh($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mask_mem);
%}
// Load Integer to Unsigned Short (16 bit UNsigned)
instruct loadI2US(iRegI dst, memoryS mem, immI_65535 mask) %{
match(Set dst (AndI (LoadI mem) mask));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDRH $dst,$mem\t! int -> ushort/char" %}
ins_encode %{
__ ldrh($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mask_mem);
%}
// Load Integer into a Long Register
instruct loadI2L(iRegL dst, memoryI mem) %{
match(Set dst (ConvI2L (LoadI mem)));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "LDR $dst.lo,$mem\t! int -> long\n\t"
"ASR $dst.hi,$dst.lo,31\t! int->long" %}
ins_encode %{
__ ldr($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), AsmOperand($dst$$Register, asr, 31));
%}
ins_pipe(iload_mask_mem);
%}
// Load Integer with mask 0xFF into a Long Register
instruct loadI2L_immI_255(iRegL dst, memoryB mem, immI_255 mask) %{
match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "LDRB $dst.lo,$mem\t! int & 0xFF -> long\n\t"
"MOV $dst.hi, 0" %}
ins_encode %{
__ ldrb($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), 0);
%}
ins_pipe(iload_mem);
%}
// Load Integer with mask 0xFFFF into a Long Register
instruct loadI2L_immI_65535(iRegL dst, memoryS mem, immI_65535 mask) %{
match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "LDRH $dst,$mem\t! int & 0xFFFF -> long\n\t"
"MOV $dst.hi, 0" %}
ins_encode %{
__ ldrh($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), 0);
%}
ins_pipe(iload_mask_mem);
%}
// Load Integer with a 31-bit immediate mask into a Long Register
instruct loadI2L_limmU31(iRegL dst, memoryI mem, limmU31 mask) %{
match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);
size(12);
format %{ "LDR $dst.lo,$mem\t! int -> long\n\t"
"MOV $dst.hi, 0\n\t"
"AND $dst,$dst,$mask" %}
ins_encode %{
__ ldr($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), 0);
__ andr($dst$$Register, $dst$$Register, $mask$$constant);
%}
ins_pipe(iload_mem);
%}
// Load Integer with a 31-bit mask into a Long Register
// FIXME: use iRegI mask, remove tmp?
instruct loadI2L_immU31(iRegL dst, memoryI mem, immU31 mask, iRegI tmp) %{
match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
effect(TEMP dst, TEMP tmp);
ins_cost(MEMORY_REF_COST + 4*DEFAULT_COST);
size(20);
format %{ "LDR $mem,$dst\t! int & 31-bit mask -> long\n\t"
"MOV $dst.hi, 0\n\t"
"MOV_SLOW $tmp,$mask\n\t"
"AND $dst,$tmp,$dst" %}
ins_encode %{
__ ldr($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), 0);
__ mov_slow($tmp$$Register, $mask$$constant);
__ andr($dst$$Register, $dst$$Register, $tmp$$Register);
%}
ins_pipe(iload_mem);
%}
// Load Unsigned Integer into a Long Register
instruct loadUI2L(iRegL dst, memoryI mem, immL_32bits mask) %{
match(Set dst (AndL (ConvI2L (LoadI mem)) mask));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "LDR $dst.lo,$mem\t! uint -> long\n\t"
"MOV $dst.hi,0" %}
ins_encode %{
__ ldr($dst$$Register, $mem$$Address);
__ mov($dst$$Register->successor(), 0);
%}
ins_pipe(iload_mem);
%}
// Load Long
instruct loadL(iRegLd dst, memoryL mem ) %{
predicate(!((LoadLNode*)n)->require_atomic_access());
match(Set dst (LoadL mem));
effect(TEMP dst);
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "ldr_64 $dst,$mem\t! long" %}
ins_encode %{
__ ldr_64($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mem);
%}
instruct loadL_2instr(iRegL dst, memorylong mem ) %{
predicate(!((LoadLNode*)n)->require_atomic_access());
match(Set dst (LoadL mem));
ins_cost(MEMORY_REF_COST + DEFAULT_COST);
size(8);
format %{ "LDR $dst.lo,$mem \t! long order of instrs reversed if $dst.lo == base($mem)\n\t"
"LDR $dst.hi,$mem+4 or $mem" %}
ins_encode %{
Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);
if ($dst$$Register == reg_to_register_object($mem$$base)) {
__ ldr($dst$$Register->successor(), Amemhi);
__ ldr($dst$$Register, Amemlo);
} else {
__ ldr($dst$$Register, Amemlo);
__ ldr($dst$$Register->successor(), Amemhi);
}
%}
ins_pipe(iload_mem);
%}
instruct loadL_volatile(iRegL dst, indirect mem ) %{
predicate(((LoadLNode*)n)->require_atomic_access());
match(Set dst (LoadL mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDMIA $dst,$mem\t! long" %}
ins_encode %{
// FIXME: why is ldmia considered atomic? Should be ldrexd
RegisterSet set($dst$$Register);
set = set | reg_to_register_object($dst$$reg + 1);
__ ldmia(reg_to_register_object($mem$$base), set);
%}
ins_pipe(iload_mem);
%}
instruct loadL_volatile_fp(iRegL dst, memoryD mem ) %{
predicate(((LoadLNode*)n)->require_atomic_access());
match(Set dst (LoadL mem));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "FLDD S14, $mem"
"FMRRD $dst, S14\t! long \n't" %}
ins_encode %{
__ fldd(S14, $mem$$Address);
__ fmrrd($dst$$Register, $dst$$Register->successor(), S14);
%}
ins_pipe(iload_mem);
%}
instruct loadL_unaligned(iRegL dst, memorylong mem ) %{
match(Set dst (LoadL_unaligned mem));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "LDR $dst.lo,$mem\t! long order of instrs reversed if $dst.lo == base($mem)\n\t"
"LDR $dst.hi,$mem+4" %}
ins_encode %{
Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);
if ($dst$$Register == reg_to_register_object($mem$$base)) {
__ ldr($dst$$Register->successor(), Amemhi);
__ ldr($dst$$Register, Amemlo);
} else {
__ ldr($dst$$Register, Amemlo);
__ ldr($dst$$Register->successor(), Amemhi);
}
%}
ins_pipe(iload_mem);
%}
// Load Range
instruct loadRange(iRegI dst, memoryI mem) %{
match(Set dst (LoadRange mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDR_u32 $dst,$mem\t! range" %}
ins_encode %{
__ ldr_u32($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mem);
%}
// Load Pointer
instruct loadP(iRegP dst, memoryP mem) %{
match(Set dst (LoadP mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDR $dst,$mem\t! ptr" %}
ins_encode %{
__ ldr($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mem);
%}
#ifdef XXX
// FIXME XXXX
//instruct loadSP(iRegP dst, memoryP mem) %{
instruct loadSP(SPRegP dst, memoryP mem, iRegP tmp) %{
match(Set dst (LoadP mem));
effect(TEMP tmp);
ins_cost(MEMORY_REF_COST+1);
size(8);
format %{ "LDR $tmp,$mem\t! ptr\n\t"
"MOV $dst,$tmp\t! ptr" %}
ins_encode %{
__ ldr($tmp$$Register, $mem$$Address);
__ mov($dst$$Register, $tmp$$Register);
%}
ins_pipe(iload_mem);
%}
#endif
#ifdef _LP64
// Load Compressed Pointer
// XXX This variant shouldn't be necessary if 6217251 is implemented
instruct loadNoff(iRegN dst, memoryScaledI mem, aimmX off, iRegP tmp) %{
match(Set dst (LoadN (AddP mem off)));
ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
effect(TEMP tmp);
size(4 * 2);
format %{ "ldr_u32 $dst,$mem+$off\t! compressed ptr temp=$tmp" %}
ins_encode %{
Register base = reg_to_register_object($mem$$base);
__ add($tmp$$Register, base, $off$$constant);
Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
__ ldr_u32($dst$$Register, nmem);
%}
ins_pipe(iload_mem);
%}
instruct loadN(iRegN dst, memoryI mem) %{
match(Set dst (LoadN mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "ldr_u32 $dst,$mem\t! compressed ptr" %}
ins_encode %{
__ ldr_u32($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mem);
%}
#endif
// Load Klass Pointer
instruct loadKlass(iRegP dst, memoryI mem) %{
match(Set dst (LoadKlass mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDR $dst,$mem\t! klass ptr" %}
ins_encode %{
__ ldr($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mem);
%}
#ifdef _LP64
// Load narrow Klass Pointer
instruct loadNKlass(iRegN dst, memoryI mem) %{
match(Set dst (LoadNKlass mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "ldr_u32 $dst,$mem\t! compressed klass ptr" %}
ins_encode %{
__ ldr_u32($dst$$Register, $mem$$Address);
%}
ins_pipe(iload_mem);
%}
#endif
instruct loadD(regD dst, memoryD mem) %{
match(Set dst (LoadD mem));
ins_cost(MEMORY_REF_COST);
size(4);
// FIXME: needs to be atomic, but ARMv7 A.R.M. guarantees
// only LDREXD and STREXD are 64-bit single-copy atomic
format %{ "FLDD $dst,$mem" %}
ins_encode %{
__ ldr_double($dst$$FloatRegister, $mem$$Address);
%}
ins_pipe(floadD_mem);
%}
// Load Double - UNaligned
instruct loadD_unaligned(regD_low dst, memoryF2 mem ) %{
match(Set dst (LoadD_unaligned mem));
ins_cost(MEMORY_REF_COST*2+DEFAULT_COST);
size(8);
format %{ "FLDS $dst.lo,$mem\t! misaligned double\n"
"\tFLDS $dst.hi,$mem+4\t!" %}
ins_encode %{
Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);
__ flds($dst$$FloatRegister, Amemlo);
__ flds($dst$$FloatRegister->successor(), Amemhi);
%}
ins_pipe(iload_mem);
%}
instruct loadF(regF dst, memoryF mem) %{
match(Set dst (LoadF mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "FLDS $dst,$mem" %}
ins_encode %{
__ ldr_float($dst$$FloatRegister, $mem$$Address);
%}
ins_pipe(floadF_mem);
%}
// // Load Constant
instruct loadConI( iRegI dst, immI src ) %{
match(Set dst src);
ins_cost(DEFAULT_COST * 3/2);
format %{ "MOV_SLOW $dst, $src" %}
ins_encode %{
__ mov_slow($dst$$Register, $src$$constant);
%}
ins_pipe(ialu_hi_lo_reg);
%}
instruct loadConIMov( iRegI dst, immIMov src ) %{
match(Set dst src);
size(4);
format %{ "MOV $dst, $src" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant);
%}
ins_pipe(ialu_imm);
%}
instruct loadConIMovn( iRegI dst, immIRotn src ) %{
match(Set dst src);
size(4);
format %{ "MVN $dst, ~$src" %}
ins_encode %{
__ mvn($dst$$Register, ~$src$$constant);
%}
ins_pipe(ialu_imm_n);
%}
instruct loadConI16( iRegI dst, immI16 src ) %{
match(Set dst src);
size(4);
format %{ "MOVW $dst, $src" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant);
%}
ins_pipe(ialu_imm_n);
%}
instruct loadConP(iRegP dst, immP src) %{
match(Set dst src);
ins_cost(DEFAULT_COST * 3/2);
format %{ "MOV_SLOW $dst,$src\t!ptr" %}
ins_encode %{
relocInfo::relocType constant_reloc = _opnds[1]->constant_reloc();
intptr_t val = $src$$constant;
if (constant_reloc == relocInfo::oop_type) {
__ mov_oop($dst$$Register, (jobject)val);
} else if (constant_reloc == relocInfo::metadata_type) {
__ mov_metadata($dst$$Register, (Metadata*)val);
} else {
__ mov_slow($dst$$Register, val);
}
%}
ins_pipe(loadConP);
%}
instruct loadConP_poll(iRegP dst, immP_poll src) %{
match(Set dst src);
ins_cost(DEFAULT_COST);
format %{ "MOV_SLOW $dst,$src\t!ptr" %}
ins_encode %{
__ mov_slow($dst$$Register, $src$$constant);
%}
ins_pipe(loadConP_poll);
%}
instruct loadConL(iRegL dst, immL src) %{
match(Set dst src);
ins_cost(DEFAULT_COST * 4);
format %{ "MOV_SLOW $dst.lo, $src & 0x0FFFFFFFFL \t! long\n\t"
"MOV_SLOW $dst.hi, $src >> 32" %}
ins_encode %{
__ mov_slow(reg_to_register_object($dst$$reg), $src$$constant & 0x0FFFFFFFFL);
__ mov_slow(reg_to_register_object($dst$$reg + 1), ((julong)($src$$constant)) >> 32);
%}
ins_pipe(loadConL);
%}
instruct loadConL16( iRegL dst, immL16 src ) %{
match(Set dst src);
ins_cost(DEFAULT_COST * 2);
size(8);
format %{ "MOVW $dst.lo, $src \n\t"
"MOVW $dst.hi, 0 \n\t" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant);
__ movw($dst$$Register->successor(), 0);
%}
ins_pipe(ialu_imm);
%}
instruct loadConF_imm8(regF dst, imm8F src) %{
match(Set dst src);
ins_cost(DEFAULT_COST);
size(4);
format %{ "FCONSTS $dst, $src"%}
ins_encode %{
__ fconsts($dst$$FloatRegister, Assembler::float_num($src$$constant).imm8());
%}
ins_pipe(loadConFD); // FIXME
%}
instruct loadConF(regF dst, immF src, iRegI tmp) %{
match(Set dst src);
ins_cost(DEFAULT_COST * 2);
effect(TEMP tmp);
size(3*4);
format %{ "MOV_SLOW $tmp, $src\n\t"
"FMSR $dst, $tmp"%}
ins_encode %{
// FIXME revisit once 6961697 is in
union {
jfloat f;
int i;
} v;
v.f = $src$$constant;
__ mov_slow($tmp$$Register, v.i);
__ fmsr($dst$$FloatRegister, $tmp$$Register);
%}
ins_pipe(loadConFD); // FIXME
%}
instruct loadConD_imm8(regD dst, imm8D src) %{
match(Set dst src);
ins_cost(DEFAULT_COST);
size(4);
format %{ "FCONSTD $dst, $src"%}
ins_encode %{
__ fconstd($dst$$FloatRegister, Assembler::double_num($src$$constant).imm8());
%}
ins_pipe(loadConFD); // FIXME
%}
instruct loadConD(regD dst, immD src, iRegP tmp) %{
match(Set dst src);
effect(TEMP tmp);
ins_cost(MEMORY_REF_COST);
format %{ "FLDD $dst, [$constanttablebase + $constantoffset]\t! load from constant table: double=$src" %}
ins_encode %{
Register r = $constanttablebase;
int offset = $constantoffset($src);
if (!is_memoryD(offset)) { // can't use a predicate
// in load constant instructs
__ add_slow($tmp$$Register, r, offset);
r = $tmp$$Register;
offset = 0;
}
__ ldr_double($dst$$FloatRegister, Address(r, offset));
%}
ins_pipe(loadConFD);
%}
// Prefetch instructions.
// Must be safe to execute with invalid address (cannot fault).
instruct prefetchAlloc_mp( memoryP mem ) %{
predicate(VM_Version::has_multiprocessing_extensions());
match( PrefetchAllocation mem );
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "PLDW $mem\t! Prefetch allocation" %}
ins_encode %{
__ pldw($mem$$Address);
%}
ins_pipe(iload_mem);
%}
instruct prefetchAlloc_sp( memoryP mem ) %{
predicate(!VM_Version::has_multiprocessing_extensions());
match( PrefetchAllocation mem );
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "PLD $mem\t! Prefetch allocation" %}
ins_encode %{
__ pld($mem$$Address);
%}
ins_pipe(iload_mem);
%}
//----------Store Instructions-------------------------------------------------
// Store Byte
instruct storeB(memoryB mem, store_RegI src) %{
match(Set mem (StoreB mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STRB $src,$mem\t! byte" %}
ins_encode %{
__ strb($src$$Register, $mem$$Address);
%}
ins_pipe(istore_mem_reg);
%}
instruct storeCM(memoryB mem, store_RegI src) %{
match(Set mem (StoreCM mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STRB $src,$mem\t! CMS card-mark byte" %}
ins_encode %{
__ strb($src$$Register, $mem$$Address);
%}
ins_pipe(istore_mem_reg);
%}
// Store Char/Short
instruct storeC(memoryS mem, store_RegI src) %{
match(Set mem (StoreC mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STRH $src,$mem\t! short" %}
ins_encode %{
__ strh($src$$Register, $mem$$Address);
%}
ins_pipe(istore_mem_reg);
%}
// Store Integer
instruct storeI(memoryI mem, store_RegI src) %{
match(Set mem (StoreI mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "str_32 $src,$mem" %}
ins_encode %{
__ str_32($src$$Register, $mem$$Address);
%}
ins_pipe(istore_mem_reg);
%}
// Store Long
instruct storeL(memoryL mem, store_RegLd src) %{
predicate(!((StoreLNode*)n)->require_atomic_access());
match(Set mem (StoreL mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "str_64 $src,$mem\t! long\n\t" %}
ins_encode %{
__ str_64($src$$Register, $mem$$Address);
%}
ins_pipe(istore_mem_reg);
%}
instruct storeL_2instr(memorylong mem, iRegL src) %{
predicate(!((StoreLNode*)n)->require_atomic_access());
match(Set mem (StoreL mem src));
ins_cost(MEMORY_REF_COST + DEFAULT_COST);
size(8);
format %{ "STR $src.lo,$mem\t! long\n\t"
"STR $src.hi,$mem+4" %}
ins_encode %{
Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);
__ str($src$$Register, Amemlo);
__ str($src$$Register->successor(), Amemhi);
%}
ins_pipe(istore_mem_reg);
%}
instruct storeL_volatile(indirect mem, iRegL src) %{
predicate(((StoreLNode*)n)->require_atomic_access());
match(Set mem (StoreL mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STMIA $src,$mem\t! long" %}
ins_encode %{
// FIXME: why is stmia considered atomic? Should be strexd
RegisterSet set($src$$Register);
set = set | reg_to_register_object($src$$reg + 1);
__ stmia(reg_to_register_object($mem$$base), set);
%}
ins_pipe(istore_mem_reg);
%}
instruct storeL_volatile_fp(memoryD mem, iRegL src) %{
predicate(((StoreLNode*)n)->require_atomic_access());
match(Set mem (StoreL mem src));
ins_cost(MEMORY_REF_COST);
size(8);
format %{ "FMDRR S14, $src\t! long \n\t"
"FSTD S14, $mem" %}
ins_encode %{
__ fmdrr(S14, $src$$Register, $src$$Register->successor());
__ fstd(S14, $mem$$Address);
%}
ins_pipe(istore_mem_reg);
%}
#ifdef XXX
// Move SP Pointer
//instruct movSP(sp_ptr_RegP dst, SPRegP src) %{
//instruct movSP(iRegP dst, SPRegP src) %{
instruct movSP(store_ptr_RegP dst, SPRegP src) %{
match(Set dst src);
//predicate(!_kids[1]->_leaf->is_Proj() || _kids[1]->_leaf->as_Proj()->_con == TypeFunc::FramePtr);
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "MOV $dst,$src\t! SP ptr\n\t" %}
ins_encode %{
assert(false, "XXX1 got here");
__ mov($dst$$Register, SP);
__ mov($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_reg);
%}
#endif
// Store Pointer
instruct storeP(memoryP mem, store_ptr_RegP src) %{
match(Set mem (StoreP mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STR $src,$mem\t! ptr" %}
ins_encode %{
__ str($src$$Register, $mem$$Address);
%}
ins_pipe(istore_mem_spORreg);
%}
#ifdef _LP64
// Store Compressed Pointer
instruct storeN(memoryI mem, store_RegN src) %{
match(Set mem (StoreN mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "str_32 $src,$mem\t! compressed ptr" %}
ins_encode %{
__ str_32($src$$Register, $mem$$Address);
%}
ins_pipe(istore_mem_reg);
%}
// Store Compressed Klass Pointer
instruct storeNKlass(memoryI mem, store_RegN src) %{
match(Set mem (StoreNKlass mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "str_32 $src,$mem\t! compressed klass ptr" %}
ins_encode %{
__ str_32($src$$Register, $mem$$Address);
%}
ins_pipe(istore_mem_reg);
%}
#endif
// Store Double
instruct storeD(memoryD mem, regD src) %{
match(Set mem (StoreD mem src));
ins_cost(MEMORY_REF_COST);
size(4);
// FIXME: needs to be atomic, but ARMv7 A.R.M. guarantees
// only LDREXD and STREXD are 64-bit single-copy atomic
format %{ "FSTD $src,$mem" %}
ins_encode %{
__ str_double($src$$FloatRegister, $mem$$Address);
%}
ins_pipe(fstoreD_mem_reg);
%}
// Store Float
instruct storeF( memoryF mem, regF src) %{
match(Set mem (StoreF mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "FSTS $src,$mem" %}
ins_encode %{
__ str_float($src$$FloatRegister, $mem$$Address);
%}
ins_pipe(fstoreF_mem_reg);
%}
//----------MemBar Instructions-----------------------------------------------
// Memory barrier flavors
// pattern-match out unnecessary membars
instruct membar_storestore() %{
match(MemBarStoreStore);
ins_cost(4*MEMORY_REF_COST);
size(4);
format %{ "MEMBAR-storestore" %}
ins_encode %{
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore), noreg);
%}
ins_pipe(long_memory_op);
%}
instruct membar_acquire() %{
match(MemBarAcquire);
match(LoadFence);
ins_cost(4*MEMORY_REF_COST);
size(4);
format %{ "MEMBAR-acquire" %}
ins_encode %{
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), noreg);
%}
ins_pipe(long_memory_op);
%}
instruct membar_acquire_lock() %{
match(MemBarAcquireLock);
ins_cost(0);
size(0);
format %{ "!MEMBAR-acquire (CAS in prior FastLock so empty encoding)" %}
ins_encode( );
ins_pipe(empty);
%}
instruct membar_release() %{
match(MemBarRelease);
match(StoreFence);
ins_cost(4*MEMORY_REF_COST);
size(4);
format %{ "MEMBAR-release" %}
ins_encode %{
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), noreg);
%}
ins_pipe(long_memory_op);
%}
instruct membar_release_lock() %{
match(MemBarReleaseLock);
ins_cost(0);
size(0);
format %{ "!MEMBAR-release (CAS in succeeding FastUnlock so empty encoding)" %}
ins_encode( );
ins_pipe(empty);
%}
instruct membar_volatile() %{
match(MemBarVolatile);
ins_cost(4*MEMORY_REF_COST);
size(4);
format %{ "MEMBAR-volatile" %}
ins_encode %{
__ membar(MacroAssembler::StoreLoad, noreg);
%}
ins_pipe(long_memory_op);
%}
instruct unnecessary_membar_volatile() %{
match(MemBarVolatile);
predicate(Matcher::post_store_load_barrier(n));
ins_cost(0);
size(0);
format %{ "!MEMBAR-volatile (unnecessary so empty encoding)" %}
ins_encode( );
ins_pipe(empty);
%}
//----------Register Move Instructions-----------------------------------------
// instruct roundDouble_nop(regD dst) %{
// match(Set dst (RoundDouble dst));
// ins_pipe(empty);
// %}
// instruct roundFloat_nop(regF dst) %{
// match(Set dst (RoundFloat dst));
// ins_pipe(empty);
// %}
// Cast Index to Pointer for unsafe natives
instruct castX2P(iRegX src, iRegP dst) %{
match(Set dst (CastX2P src));
format %{ "MOV $dst,$src\t! IntX->Ptr if $dst != $src" %}
ins_encode %{
if ($dst$$Register != $src$$Register) {
__ mov($dst$$Register, $src$$Register);
}
%}
ins_pipe(ialu_reg);
%}
// Cast Pointer to Index for unsafe natives
instruct castP2X(iRegP src, iRegX dst) %{
match(Set dst (CastP2X src));
format %{ "MOV $dst,$src\t! Ptr->IntX if $dst != $src" %}
ins_encode %{
if ($dst$$Register != $src$$Register) {
__ mov($dst$$Register, $src$$Register);
}
%}
ins_pipe(ialu_reg);
%}
//----------Conditional Move---------------------------------------------------
// Conditional move
instruct cmovIP_reg(cmpOpP cmp, flagsRegP pcc, iRegI dst, iRegI src) %{
match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src\t! int" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovIP_immMov(cmpOpP cmp, flagsRegP pcc, iRegI dst, immIMov src) %{
match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src)));
ins_cost(140);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovIP_imm16(cmpOpP cmp, flagsRegP pcc, iRegI dst, immI16 src) %{
match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src)));
ins_cost(140);
size(4);
format %{ "MOVw$cmp $dst,$src" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovI_reg(cmpOp cmp, flagsReg icc, iRegI dst, iRegI src) %{
match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovI_immMov(cmpOp cmp, flagsReg icc, iRegI dst, immIMov src) %{
match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
ins_cost(140);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovII_imm16(cmpOp cmp, flagsReg icc, iRegI dst, immI16 src) %{
match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
ins_cost(140);
size(4);
format %{ "MOVw$cmp $dst,$src" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovII_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegI dst, iRegI src) %{
match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovII_immMov_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegI dst, immIMov src) %{
match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
ins_cost(140);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovII_imm16_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegI dst, immI16 src) %{
match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
ins_cost(140);
size(4);
format %{ "MOVW$cmp $dst,$src" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovIIu_reg(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src) %{
match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovIIu_immMov(cmpOpU cmp, flagsRegU icc, iRegI dst, immIMov src) %{
match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
ins_cost(140);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovIIu_imm16(cmpOpU cmp, flagsRegU icc, iRegI dst, immI16 src) %{
match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
ins_cost(140);
size(4);
format %{ "MOVW$cmp $dst,$src" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
// Conditional move
instruct cmovPP_reg(cmpOpP cmp, flagsRegP pcc, iRegP dst, iRegP src) %{
match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovPP_imm(cmpOpP cmp, flagsRegP pcc, iRegP dst, immP0 src) %{
match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src)));
ins_cost(140);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
// This instruction also works with CmpN so we don't need cmovPN_reg.
instruct cmovPI_reg(cmpOp cmp, flagsReg icc, iRegP dst, iRegP src) %{
match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src\t! ptr" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovPI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegP dst, iRegP src) %{
match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src\t! ptr" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovPIu_reg(cmpOpU cmp, flagsRegU icc, iRegP dst, iRegP src) %{
match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src\t! ptr" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovPI_imm(cmpOp cmp, flagsReg icc, iRegP dst, immP0 src) %{
match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
ins_cost(140);
size(4);
format %{ "MOV$cmp $dst,$src\t! ptr" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovPI_imm_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegP dst, immP0 src) %{
match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
ins_cost(140);
size(4);
format %{ "MOV$cmp $dst,$src\t! ptr" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovPIu_imm(cmpOpU cmp, flagsRegU icc, iRegP dst, immP0 src) %{
match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
ins_cost(140);
size(4);
format %{ "MOV$cmp $dst,$src\t! ptr" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
// Conditional move
instruct cmovFP_reg(cmpOpP cmp, flagsRegP pcc, regF dst, regF src) %{
match(Set dst (CMoveF (Binary cmp pcc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "FCPYS$cmp $dst,$src" %}
ins_encode %{
__ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_float_move);
%}
instruct cmovFI_reg(cmpOp cmp, flagsReg icc, regF dst, regF src) %{
match(Set dst (CMoveF (Binary cmp icc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "FCPYS$cmp $dst,$src" %}
ins_encode %{
__ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_float_move);
%}
instruct cmovFI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, regF dst, regF src) %{
match(Set dst (CMoveF (Binary cmp icc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
ins_cost(150);
size(4);
format %{ "FCPYS$cmp $dst,$src" %}
ins_encode %{
__ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_float_move);
%}
instruct cmovFIu_reg(cmpOpU cmp, flagsRegU icc, regF dst, regF src) %{
match(Set dst (CMoveF (Binary cmp icc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "FCPYS$cmp $dst,$src" %}
ins_encode %{
__ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_float_move);
%}
// Conditional move
instruct cmovDP_reg(cmpOpP cmp, flagsRegP pcc, regD dst, regD src) %{
match(Set dst (CMoveD (Binary cmp pcc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "FCPYD$cmp $dst,$src" %}
ins_encode %{
__ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_double_move);
%}
instruct cmovDI_reg(cmpOp cmp, flagsReg icc, regD dst, regD src) %{
match(Set dst (CMoveD (Binary cmp icc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "FCPYD$cmp $dst,$src" %}
ins_encode %{
__ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_double_move);
%}
instruct cmovDI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, regD dst, regD src) %{
match(Set dst (CMoveD (Binary cmp icc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
ins_cost(150);
size(4);
format %{ "FCPYD$cmp $dst,$src" %}
ins_encode %{
__ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_double_move);
%}
instruct cmovDIu_reg(cmpOpU cmp, flagsRegU icc, regD dst, regD src) %{
match(Set dst (CMoveD (Binary cmp icc) (Binary dst src)));
ins_cost(150);
size(4);
format %{ "FCPYD$cmp $dst,$src" %}
ins_encode %{
__ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_double_move);
%}
// Conditional move
instruct cmovLP_reg(cmpOpP cmp, flagsRegP pcc, iRegL dst, iRegL src) %{
match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src)));
ins_cost(150);
size(8);
format %{ "MOV$cmp $dst.lo,$src.lo\t! long\n\t"
"MOV$cmp $dst.hi,$src.hi" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct cmovLP_immRot(cmpOpP cmp, flagsRegP pcc, iRegL dst, immLlowRot src) %{
match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src)));
ins_cost(140);
size(8);
format %{ "MOV$cmp $dst.lo,$src\t! long\n\t"
"MOV$cmp $dst.hi,0" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovLP_imm16(cmpOpP cmp, flagsRegP pcc, iRegL dst, immL16 src) %{
match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src)));
ins_cost(140);
size(8);
format %{ "MOV$cmp $dst.lo,$src\t! long\n\t"
"MOV$cmp $dst.hi,0" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovLI_reg(cmpOp cmp, flagsReg icc, iRegL dst, iRegL src) %{
match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
ins_cost(150);
size(8);
format %{ "MOV$cmp $dst.lo,$src.lo\t! long\n\t"
"MOV$cmp $dst.hi,$src.hi" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovLI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegL dst, iRegL src) %{
match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
ins_cost(150);
size(8);
format %{ "MOV$cmp $dst.lo,$src.lo\t! long\n\t"
"MOV$cmp $dst.hi,$src.hi" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct cmovLI_immRot(cmpOp cmp, flagsReg icc, iRegL dst, immLlowRot src) %{
match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
ins_cost(140);
size(8);
format %{ "MOV$cmp $dst.lo,$src\t! long\n\t"
"MOV$cmp $dst.hi,0" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct cmovLI_immRot_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegL dst, immLlowRot src) %{
match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
ins_cost(140);
size(8);
format %{ "MOV$cmp $dst.lo,$src\t! long\n\t"
"MOV$cmp $dst.hi,0" %}
ins_encode %{
__ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovLI_imm16(cmpOp cmp, flagsReg icc, iRegL dst, immL16 src) %{
match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
ins_cost(140);
size(8);
format %{ "MOV$cmp $dst.lo,$src\t! long\n\t"
"MOV$cmp $dst.hi,0" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
__ movw($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovLI_imm16_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegL dst, immL16 src) %{
match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
ins_cost(140);
size(8);
format %{ "MOV$cmp $dst.lo,$src\t! long\n\t"
"MOV$cmp $dst.hi,0" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
__ movw($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovLIu_reg(cmpOpU cmp, flagsRegU icc, iRegL dst, iRegL src) %{
match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
ins_cost(150);
size(8);
format %{ "MOV$cmp $dst.lo,$src.lo\t! long\n\t"
"MOV$cmp $dst.hi,$src.hi" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
//----------OS and Locking Instructions----------------------------------------
// This name is KNOWN by the ADLC and cannot be changed.
// The ADLC forces a 'TypeRawPtr::BOTTOM' output type
// for this guy.
instruct tlsLoadP(RthreadRegP dst) %{
match(Set dst (ThreadLocal));
size(0);
ins_cost(0);
format %{ "! TLS is in $dst" %}
ins_encode( /*empty encoding*/ );
ins_pipe(ialu_none);
%}
instruct checkCastPP( iRegP dst ) %{
match(Set dst (CheckCastPP dst));
size(0);
format %{ "! checkcastPP of $dst" %}
ins_encode( /*empty encoding*/ );
ins_pipe(empty);
%}
instruct castPP( iRegP dst ) %{
match(Set dst (CastPP dst));
format %{ "! castPP of $dst" %}
ins_encode( /*empty encoding*/ );
ins_pipe(empty);
%}
instruct castII( iRegI dst ) %{
match(Set dst (CastII dst));
format %{ "! castII of $dst" %}
ins_encode( /*empty encoding*/ );
ins_cost(0);
ins_pipe(empty);
%}
instruct castLL( iRegL dst ) %{
match(Set dst (CastLL dst));
format %{ "! castLL of $dst" %}
ins_encode( /*empty encoding*/ );
ins_cost(0);
ins_pipe(empty);
%}
//----------Arithmetic Instructions--------------------------------------------
// Addition Instructions
// Register Addition
instruct addI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
match(Set dst (AddI src1 src2));
size(4);
format %{ "add_32 $dst,$src1,$src2\t! int" %}
ins_encode %{
__ add_32($dst$$Register, $src1$$Register, $src2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct addshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (AddI (LShiftI src1 src2) src3));
size(4);
format %{ "add_32 $dst,$src3,$src1<<$src2\t! int" %}
ins_encode %{
__ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct addshlI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
match(Set dst (AddI (LShiftI src1 src2) src3));
size(4);
format %{ "add_32 $dst,$src3,$src1<<$src2\t! int" %}
ins_encode %{
__ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct addsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (AddI (RShiftI src1 src2) src3));
size(4);
format %{ "add_32 $dst,$src3,$src1>>$src2\t! int" %}
ins_encode %{
__ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct addsarI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
match(Set dst (AddI (RShiftI src1 src2) src3));
size(4);
format %{ "add_32 $dst,$src3,$src1>>$src2\t! int" %}
ins_encode %{
__ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct addshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (AddI (URShiftI src1 src2) src3));
size(4);
format %{ "add_32 $dst,$src3,$src1>>>$src2\t! int" %}
ins_encode %{
__ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct addshrI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
match(Set dst (AddI (URShiftI src1 src2) src3));
size(4);
format %{ "add_32 $dst,$src3,$src1>>>$src2\t! int" %}
ins_encode %{
__ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
// Immediate Addition
instruct addI_reg_aimmI(iRegI dst, iRegI src1, aimmI src2) %{
match(Set dst (AddI src1 src2));
size(4);
format %{ "add_32 $dst,$src1,$src2\t! int" %}
ins_encode %{
__ add_32($dst$$Register, $src1$$Register, $src2$$constant);
%}
ins_pipe(ialu_reg_imm);
%}
// Pointer Register Addition
instruct addP_reg_reg(iRegP dst, iRegP src1, iRegX src2) %{
match(Set dst (AddP src1 src2));
size(4);
format %{ "ADD $dst,$src1,$src2\t! ptr" %}
ins_encode %{
__ add($dst$$Register, $src1$$Register, $src2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
// shifted iRegX operand
operand shiftedX(iRegX src2, shimmX src3) %{
//constraint(ALLOC_IN_RC(sp_ptr_reg));
match(LShiftX src2 src3);
op_cost(1);
format %{ "$src2 << $src3" %}
interface(MEMORY_INTER) %{
base($src2);
index(0xff);
scale($src3);
disp(0x0);
%}
%}
instruct addshlP_reg_reg_imm(iRegP dst, iRegP src1, shiftedX src2) %{
match(Set dst (AddP src1 src2));
ins_cost(DEFAULT_COST * 3/2);
size(4);
format %{ "ADD $dst,$src1,$src2\t! ptr" %}
ins_encode %{
Register base = reg_to_register_object($src2$$base);
__ add($dst$$Register, $src1$$Register, AsmOperand(base, lsl, $src2$$scale));
%}
ins_pipe(ialu_reg_reg);
%}
// Pointer Immediate Addition
instruct addP_reg_aimmX(iRegP dst, iRegP src1, aimmX src2) %{
match(Set dst (AddP src1 src2));
size(4);
format %{ "ADD $dst,$src1,$src2\t! ptr" %}
ins_encode %{
__ add($dst$$Register, $src1$$Register, $src2$$constant);
%}
ins_pipe(ialu_reg_imm);
%}
// Long Addition
instruct addL_reg_reg(iRegL dst, iRegL src1, iRegL src2, flagsReg ccr) %{
match(Set dst (AddL src1 src2));
effect(KILL ccr);
size(8);
format %{ "ADDS $dst.lo,$src1.lo,$src2.lo\t! long\n\t"
"ADC $dst.hi,$src1.hi,$src2.hi" %}
ins_encode %{
__ adds($dst$$Register, $src1$$Register, $src2$$Register);
__ adc($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
%}
ins_pipe(ialu_reg_reg);
%}
// TODO
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct addL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con, flagsReg ccr) %{
match(Set dst (AddL src1 con));
effect(KILL ccr);
size(8);
format %{ "ADDS $dst.lo,$src1.lo,$con\t! long\n\t"
"ADC $dst.hi,$src1.hi,0" %}
ins_encode %{
__ adds($dst$$Register, $src1$$Register, $con$$constant);
__ adc($dst$$Register->successor(), $src1$$Register->successor(), 0);
%}
ins_pipe(ialu_reg_imm);
%}
//----------Conditional_store--------------------------------------------------
// Conditional-store of the updated heap-top.
// Used during allocation of the shared heap.
// Sets flags (EQ) on success.
// LoadP-locked.
instruct loadPLocked(iRegP dst, memoryex mem) %{
match(Set dst (LoadPLocked mem));
size(4);
format %{ "LDREX $dst,$mem" %}
ins_encode %{
__ ldrex($dst$$Register,$mem$$Address);
%}
ins_pipe(iload_mem);
%}
instruct storePConditional( memoryex heap_top_ptr, iRegP oldval, iRegP newval, iRegI tmp, flagsRegP pcc ) %{
predicate(_kids[1]->_kids[0]->_leaf->Opcode() == Op_LoadPLocked); // only works in conjunction with a LoadPLocked node
match(Set pcc (StorePConditional heap_top_ptr (Binary oldval newval)));
effect( TEMP tmp );
size(8);
format %{ "STREX $tmp,$newval,$heap_top_ptr\n\t"
"CMP $tmp, 0" %}
ins_encode %{
__ strex($tmp$$Register, $newval$$Register, $heap_top_ptr$$Address);
__ cmp($tmp$$Register, 0);
%}
ins_pipe( long_memory_op );
%}
// Conditional-store of an intx value.
instruct storeXConditional( memoryex mem, iRegX oldval, iRegX newval, iRegX tmp, flagsReg icc ) %{
match(Set icc (StoreIConditional mem (Binary oldval newval)));
effect( TEMP tmp );
size(28);
format %{ "loop: \n\t"
"LDREX $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem], DOESN'T set $newval=[$mem] in any case\n\t"
"XORS $tmp,$tmp, $oldval\n\t"
"STREX.eq $tmp, $newval, $mem\n\t"
"CMP.eq $tmp, 1 \n\t"
"B.eq loop \n\t"
"TEQ $tmp, 0\n\t"
"membar LoadStore|LoadLoad" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrex($tmp$$Register, $mem$$Address);
__ eors($tmp$$Register, $tmp$$Register, $oldval$$Register);
__ strex($tmp$$Register, $newval$$Register, $mem$$Address, eq);
__ cmp($tmp$$Register, 1, eq);
__ b(loop, eq);
__ teq($tmp$$Register, 0);
// used by biased locking only. Requires a membar.
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadStore | MacroAssembler::LoadLoad), noreg);
%}
ins_pipe( long_memory_op );
%}
// No flag versions for CompareAndSwap{P,I,L} because matcher can't match them
instruct compareAndSwapL_bool(memoryex mem, iRegL oldval, iRegLd newval, iRegI res, iRegLd tmp, flagsReg ccr ) %{
match(Set res (CompareAndSwapL mem (Binary oldval newval)));
effect( KILL ccr, TEMP tmp);
size(32);
format %{ "loop: \n\t"
"LDREXD $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
"CMP $tmp.lo, $oldval.lo\n\t"
"CMP.eq $tmp.hi, $oldval.hi\n\t"
"STREXD.eq $tmp, $newval, $mem\n\t"
"MOV.ne $tmp, 0 \n\t"
"XORS.eq $tmp,$tmp, 1 \n\t"
"B.eq loop \n\t"
"MOV $res, $tmp" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrexd($tmp$$Register, $mem$$Address);
__ cmp($tmp$$Register, $oldval$$Register);
__ cmp($tmp$$Register->successor(), $oldval$$Register->successor(), eq);
__ strexd($tmp$$Register, $newval$$Register, $mem$$Address, eq);
__ mov($tmp$$Register, 0, ne);
__ eors($tmp$$Register, $tmp$$Register, 1, eq);
__ b(loop, eq);
__ mov($res$$Register, $tmp$$Register);
%}
ins_pipe( long_memory_op );
%}
instruct compareAndSwapI_bool(memoryex mem, iRegI oldval, iRegI newval, iRegI res, iRegI tmp, flagsReg ccr ) %{
match(Set res (CompareAndSwapI mem (Binary oldval newval)));
effect( KILL ccr, TEMP tmp);
size(28);
format %{ "loop: \n\t"
"LDREX $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
"CMP $tmp, $oldval\n\t"
"STREX.eq $tmp, $newval, $mem\n\t"
"MOV.ne $tmp, 0 \n\t"
"XORS.eq $tmp,$tmp, 1 \n\t"
"B.eq loop \n\t"
"MOV $res, $tmp" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrex($tmp$$Register,$mem$$Address);
__ cmp($tmp$$Register, $oldval$$Register);
__ strex($tmp$$Register, $newval$$Register, $mem$$Address, eq);
__ mov($tmp$$Register, 0, ne);
__ eors($tmp$$Register, $tmp$$Register, 1, eq);
__ b(loop, eq);
__ mov($res$$Register, $tmp$$Register);
%}
ins_pipe( long_memory_op );
%}
instruct compareAndSwapP_bool(memoryex mem, iRegP oldval, iRegP newval, iRegI res, iRegI tmp, flagsReg ccr ) %{
match(Set res (CompareAndSwapP mem (Binary oldval newval)));
effect( KILL ccr, TEMP tmp);
size(28);
format %{ "loop: \n\t"
"LDREX $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
"CMP $tmp, $oldval\n\t"
"STREX.eq $tmp, $newval, $mem\n\t"
"MOV.ne $tmp, 0 \n\t"
"EORS.eq $tmp,$tmp, 1 \n\t"
"B.eq loop \n\t"
"MOV $res, $tmp" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrex($tmp$$Register,$mem$$Address);
__ cmp($tmp$$Register, $oldval$$Register);
__ strex($tmp$$Register, $newval$$Register, $mem$$Address, eq);
__ mov($tmp$$Register, 0, ne);
__ eors($tmp$$Register, $tmp$$Register, 1, eq);
__ b(loop, eq);
__ mov($res$$Register, $tmp$$Register);
%}
ins_pipe( long_memory_op );
%}
instruct xaddI_aimmI_no_res(memoryex mem, aimmI add, Universe dummy, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
predicate(n->as_LoadStore()->result_not_used());
match(Set dummy (GetAndAddI mem add));
effect(KILL ccr, TEMP tmp1, TEMP tmp2);
size(20);
format %{ "loop: \n\t"
"LDREX $tmp1, $mem\n\t"
"ADD $tmp1, $tmp1, $add\n\t"
"STREX $tmp2, $tmp1, $mem\n\t"
"CMP $tmp2, 0 \n\t"
"B.ne loop \n\t" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrex($tmp1$$Register,$mem$$Address);
__ add($tmp1$$Register, $tmp1$$Register, $add$$constant);
__ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
__ cmp($tmp2$$Register, 0);
__ b(loop, ne);
%}
ins_pipe( long_memory_op );
%}
instruct xaddI_reg_no_res(memoryex mem, iRegI add, Universe dummy, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
predicate(n->as_LoadStore()->result_not_used());
match(Set dummy (GetAndAddI mem add));
effect(KILL ccr, TEMP tmp1, TEMP tmp2);
size(20);
format %{ "loop: \n\t"
"LDREX $tmp1, $mem\n\t"
"ADD $tmp1, $tmp1, $add\n\t"
"STREX $tmp2, $tmp1, $mem\n\t"
"CMP $tmp2, 0 \n\t"
"B.ne loop \n\t" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrex($tmp1$$Register,$mem$$Address);
__ add($tmp1$$Register, $tmp1$$Register, $add$$Register);
__ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
__ cmp($tmp2$$Register, 0);
__ b(loop, ne);
%}
ins_pipe( long_memory_op );
%}
instruct xaddI_aimmI(memoryex mem, aimmI add, iRegI res, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
match(Set res (GetAndAddI mem add));
effect(KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
size(20);
format %{ "loop: \n\t"
"LDREX $res, $mem\n\t"
"ADD $tmp1, $res, $add\n\t"
"STREX $tmp2, $tmp1, $mem\n\t"
"CMP $tmp2, 0 \n\t"
"B.ne loop \n\t" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrex($res$$Register,$mem$$Address);
__ add($tmp1$$Register, $res$$Register, $add$$constant);
__ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
__ cmp($tmp2$$Register, 0);
__ b(loop, ne);
%}
ins_pipe( long_memory_op );
%}
instruct xaddI_reg(memoryex mem, iRegI add, iRegI res, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
match(Set res (GetAndAddI mem add));
effect(KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
size(20);
format %{ "loop: \n\t"
"LDREX $res, $mem\n\t"
"ADD $tmp1, $res, $add\n\t"
"STREX $tmp2, $tmp1, $mem\n\t"
"CMP $tmp2, 0 \n\t"
"B.ne loop \n\t" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrex($res$$Register,$mem$$Address);
__ add($tmp1$$Register, $res$$Register, $add$$Register);
__ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
__ cmp($tmp2$$Register, 0);
__ b(loop, ne);
%}
ins_pipe( long_memory_op );
%}
instruct xaddL_reg_no_res(memoryex mem, iRegL add, Universe dummy, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
predicate(n->as_LoadStore()->result_not_used());
match(Set dummy (GetAndAddL mem add));
effect( KILL ccr, TEMP tmp1, TEMP tmp2);
size(24);
format %{ "loop: \n\t"
"LDREXD $tmp1, $mem\n\t"
"ADDS $tmp1.lo, $tmp1.lo, $add.lo\n\t"
"ADC $tmp1.hi, $tmp1.hi, $add.hi\n\t"
"STREXD $tmp2, $tmp1, $mem\n\t"
"CMP $tmp2, 0 \n\t"
"B.ne loop \n\t" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrexd($tmp1$$Register, $mem$$Address);
__ adds($tmp1$$Register, $tmp1$$Register, $add$$Register);
__ adc($tmp1$$Register->successor(), $tmp1$$Register->successor(), $add$$Register->successor());
__ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
__ cmp($tmp2$$Register, 0);
__ b(loop, ne);
%}
ins_pipe( long_memory_op );
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct xaddL_immRot_no_res(memoryex mem, immLlowRot add, Universe dummy, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
predicate(n->as_LoadStore()->result_not_used());
match(Set dummy (GetAndAddL mem add));
effect( KILL ccr, TEMP tmp1, TEMP tmp2);
size(24);
format %{ "loop: \n\t"
"LDREXD $tmp1, $mem\n\t"
"ADDS $tmp1.lo, $tmp1.lo, $add\n\t"
"ADC $tmp1.hi, $tmp1.hi, 0\n\t"
"STREXD $tmp2, $tmp1, $mem\n\t"
"CMP $tmp2, 0 \n\t"
"B.ne loop \n\t" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrexd($tmp1$$Register, $mem$$Address);
__ adds($tmp1$$Register, $tmp1$$Register, $add$$constant);
__ adc($tmp1$$Register->successor(), $tmp1$$Register->successor(), 0);
__ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
__ cmp($tmp2$$Register, 0);
__ b(loop, ne);
%}
ins_pipe( long_memory_op );
%}
instruct xaddL_reg(memoryex mem, iRegL add, iRegLd res, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
match(Set res (GetAndAddL mem add));
effect( KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
size(24);
format %{ "loop: \n\t"
"LDREXD $res, $mem\n\t"
"ADDS $tmp1.lo, $res.lo, $add.lo\n\t"
"ADC $tmp1.hi, $res.hi, $add.hi\n\t"
"STREXD $tmp2, $tmp1, $mem\n\t"
"CMP $tmp2, 0 \n\t"
"B.ne loop \n\t" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrexd($res$$Register, $mem$$Address);
__ adds($tmp1$$Register, $res$$Register, $add$$Register);
__ adc($tmp1$$Register->successor(), $res$$Register->successor(), $add$$Register->successor());
__ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
__ cmp($tmp2$$Register, 0);
__ b(loop, ne);
%}
ins_pipe( long_memory_op );
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct xaddL_immRot(memoryex mem, immLlowRot add, iRegLd res, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
match(Set res (GetAndAddL mem add));
effect( KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
size(24);
format %{ "loop: \n\t"
"LDREXD $res, $mem\n\t"
"ADDS $tmp1.lo, $res.lo, $add\n\t"
"ADC $tmp1.hi, $res.hi, 0\n\t"
"STREXD $tmp2, $tmp1, $mem\n\t"
"CMP $tmp2, 0 \n\t"
"B.ne loop \n\t" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrexd($res$$Register, $mem$$Address);
__ adds($tmp1$$Register, $res$$Register, $add$$constant);
__ adc($tmp1$$Register->successor(), $res$$Register->successor(), 0);
__ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
__ cmp($tmp2$$Register, 0);
__ b(loop, ne);
%}
ins_pipe( long_memory_op );
%}
instruct xchgI(memoryex mem, iRegI newval, iRegI res, iRegI tmp, flagsReg ccr) %{
match(Set res (GetAndSetI mem newval));
effect(KILL ccr, TEMP tmp, TEMP res);
size(16);
format %{ "loop: \n\t"
"LDREX $res, $mem\n\t"
"STREX $tmp, $newval, $mem\n\t"
"CMP $tmp, 0 \n\t"
"B.ne loop \n\t" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrex($res$$Register,$mem$$Address);
__ strex($tmp$$Register, $newval$$Register, $mem$$Address);
__ cmp($tmp$$Register, 0);
__ b(loop, ne);
%}
ins_pipe( long_memory_op );
%}
instruct xchgL(memoryex mem, iRegLd newval, iRegLd res, iRegI tmp, flagsReg ccr) %{
match(Set res (GetAndSetL mem newval));
effect( KILL ccr, TEMP tmp, TEMP res);
size(16);
format %{ "loop: \n\t"
"LDREXD $res, $mem\n\t"
"STREXD $tmp, $newval, $mem\n\t"
"CMP $tmp, 0 \n\t"
"B.ne loop \n\t" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrexd($res$$Register, $mem$$Address);
__ strexd($tmp$$Register, $newval$$Register, $mem$$Address);
__ cmp($tmp$$Register, 0);
__ b(loop, ne);
%}
ins_pipe( long_memory_op );
%}
instruct xchgP(memoryex mem, iRegP newval, iRegP res, iRegI tmp, flagsReg ccr) %{
match(Set res (GetAndSetP mem newval));
effect(KILL ccr, TEMP tmp, TEMP res);
size(16);
format %{ "loop: \n\t"
"LDREX $res, $mem\n\t"
"STREX $tmp, $newval, $mem\n\t"
"CMP $tmp, 0 \n\t"
"B.ne loop \n\t" %}
ins_encode %{
Label loop;
__ bind(loop);
__ ldrex($res$$Register,$mem$$Address);
__ strex($tmp$$Register, $newval$$Register, $mem$$Address);
__ cmp($tmp$$Register, 0);
__ b(loop, ne);
%}
ins_pipe( long_memory_op );
%}
//---------------------
// Subtraction Instructions
// Register Subtraction
instruct subI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
match(Set dst (SubI src1 src2));
size(4);
format %{ "sub_32 $dst,$src1,$src2\t! int" %}
ins_encode %{
__ sub_32($dst$$Register, $src1$$Register, $src2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct subshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (SubI src1 (LShiftI src2 src3)));
size(4);
format %{ "SUB $dst,$src1,$src2<<$src3" %}
ins_encode %{
__ sub($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct subshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (SubI src1 (LShiftI src2 src3)));
size(4);
format %{ "sub_32 $dst,$src1,$src2<<$src3\t! int" %}
ins_encode %{
__ sub_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct subsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (SubI src1 (RShiftI src2 src3)));
size(4);
format %{ "SUB $dst,$src1,$src2>>$src3" %}
ins_encode %{
__ sub($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct subsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (SubI src1 (RShiftI src2 src3)));
size(4);
format %{ "sub_32 $dst,$src1,$src2>>$src3\t! int" %}
ins_encode %{
__ sub_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct subshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (SubI src1 (URShiftI src2 src3)));
size(4);
format %{ "SUB $dst,$src1,$src2>>>$src3" %}
ins_encode %{
__ sub($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct subshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (SubI src1 (URShiftI src2 src3)));
size(4);
format %{ "sub_32 $dst,$src1,$src2>>>$src3\t! int" %}
ins_encode %{
__ sub_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct rsbshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (SubI (LShiftI src1 src2) src3));
size(4);
format %{ "RSB $dst,$src3,$src1<<$src2" %}
ins_encode %{
__ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct rsbshlI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
match(Set dst (SubI (LShiftI src1 src2) src3));
size(4);
format %{ "RSB $dst,$src3,$src1<<$src2" %}
ins_encode %{
__ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct rsbsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (SubI (RShiftI src1 src2) src3));
size(4);
format %{ "RSB $dst,$src3,$src1>>$src2" %}
ins_encode %{
__ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct rsbsarI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
match(Set dst (SubI (RShiftI src1 src2) src3));
size(4);
format %{ "RSB $dst,$src3,$src1>>$src2" %}
ins_encode %{
__ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct rsbshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (SubI (URShiftI src1 src2) src3));
size(4);
format %{ "RSB $dst,$src3,$src1>>>$src2" %}
ins_encode %{
__ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct rsbshrI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
match(Set dst (SubI (URShiftI src1 src2) src3));
size(4);
format %{ "RSB $dst,$src3,$src1>>>$src2" %}
ins_encode %{
__ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
// Immediate Subtraction
instruct subI_reg_aimmI(iRegI dst, iRegI src1, aimmI src2) %{
match(Set dst (SubI src1 src2));
size(4);
format %{ "sub_32 $dst,$src1,$src2\t! int" %}
ins_encode %{
__ sub_32($dst$$Register, $src1$$Register, $src2$$constant);
%}
ins_pipe(ialu_reg_imm);
%}
instruct subI_reg_immRotneg(iRegI dst, iRegI src1, aimmIneg src2) %{
match(Set dst (AddI src1 src2));
size(4);
format %{ "sub_32 $dst,$src1,-($src2)\t! int" %}
ins_encode %{
__ sub_32($dst$$Register, $src1$$Register, -$src2$$constant);
%}
ins_pipe(ialu_reg_imm);
%}
instruct subI_immRot_reg(iRegI dst, immIRot src1, iRegI src2) %{
match(Set dst (SubI src1 src2));
size(4);
format %{ "RSB $dst,$src2,src1" %}
ins_encode %{
__ rsb($dst$$Register, $src2$$Register, $src1$$constant);
%}
ins_pipe(ialu_zero_reg);
%}
// Register Subtraction
instruct subL_reg_reg(iRegL dst, iRegL src1, iRegL src2, flagsReg icc ) %{
match(Set dst (SubL src1 src2));
effect (KILL icc);
size(8);
format %{ "SUBS $dst.lo,$src1.lo,$src2.lo\t! long\n\t"
"SBC $dst.hi,$src1.hi,$src2.hi" %}
ins_encode %{
__ subs($dst$$Register, $src1$$Register, $src2$$Register);
__ sbc($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
%}
ins_pipe(ialu_reg_reg);
%}
// TODO
// Immediate Subtraction
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct subL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con, flagsReg icc) %{
match(Set dst (SubL src1 con));
effect (KILL icc);
size(8);
format %{ "SUB $dst.lo,$src1.lo,$con\t! long\n\t"
"SBC $dst.hi,$src1.hi,0" %}
ins_encode %{
__ subs($dst$$Register, $src1$$Register, $con$$constant);
__ sbc($dst$$Register->successor(), $src1$$Register->successor(), 0);
%}
ins_pipe(ialu_reg_imm);
%}
// Long negation
instruct negL_reg_reg(iRegL dst, immL0 zero, iRegL src2, flagsReg icc) %{
match(Set dst (SubL zero src2));
effect (KILL icc);
size(8);
format %{ "RSBS $dst.lo,$src2.lo,0\t! long\n\t"
"RSC $dst.hi,$src2.hi,0" %}
ins_encode %{
__ rsbs($dst$$Register, $src2$$Register, 0);
__ rsc($dst$$Register->successor(), $src2$$Register->successor(), 0);
%}
ins_pipe(ialu_zero_reg);
%}
// Multiplication Instructions
// Integer Multiplication
// Register Multiplication
instruct mulI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
match(Set dst (MulI src1 src2));
size(4);
format %{ "mul_32 $dst,$src1,$src2" %}
ins_encode %{
__ mul_32($dst$$Register, $src1$$Register, $src2$$Register);
%}
ins_pipe(imul_reg_reg);
%}
instruct mulL_lo1_hi2(iRegL dst, iRegL src1, iRegL src2) %{
effect(DEF dst, USE src1, USE src2);
size(4);
format %{ "MUL $dst.hi,$src1.lo,$src2.hi\t! long" %}
ins_encode %{
__ mul($dst$$Register->successor(), $src1$$Register, $src2$$Register->successor());
%}
ins_pipe(imul_reg_reg);
%}
instruct mulL_hi1_lo2(iRegL dst, iRegL src1, iRegL src2) %{
effect(USE_DEF dst, USE src1, USE src2);
size(8);
format %{ "MLA $dst.hi,$src1.hi,$src2.lo,$dst.hi\t! long\n\t"
"MOV $dst.lo, 0"%}
ins_encode %{
__ mla($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register, $dst$$Register->successor());
__ mov($dst$$Register, 0);
%}
ins_pipe(imul_reg_reg);
%}
instruct mulL_lo1_lo2(iRegL dst, iRegL src1, iRegL src2) %{
effect(USE_DEF dst, USE src1, USE src2);
size(4);
format %{ "UMLAL $dst.lo,$dst.hi,$src1,$src2\t! long" %}
ins_encode %{
__ umlal($dst$$Register, $dst$$Register->successor(), $src1$$Register, $src2$$Register);
%}
ins_pipe(imul_reg_reg);
%}
instruct mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
match(Set dst (MulL src1 src2));
expand %{
mulL_lo1_hi2(dst, src1, src2);
mulL_hi1_lo2(dst, src1, src2);
mulL_lo1_lo2(dst, src1, src2);
%}
%}
// Integer Division
// Register Division
instruct divI_reg_reg(R1RegI dst, R0RegI src1, R2RegI src2, LRRegP lr, flagsReg ccr) %{
match(Set dst (DivI src1 src2));
effect( KILL ccr, KILL src1, KILL src2, KILL lr);
ins_cost((2+71)*DEFAULT_COST);
format %{ "DIV $dst,$src1,$src2 ! call to StubRoutines::Arm::idiv_irem_entry()" %}
ins_encode %{
__ call(StubRoutines::Arm::idiv_irem_entry(), relocInfo::runtime_call_type);
%}
ins_pipe(sdiv_reg_reg);
%}
// Register Long Division
instruct divL_reg_reg(R0R1RegL dst, R2R3RegL src1, R0R1RegL src2) %{
match(Set dst (DivL src1 src2));
effect(CALL);
ins_cost(DEFAULT_COST*71);
format %{ "DIVL $src1,$src2,$dst\t! long ! call to SharedRuntime::ldiv" %}
ins_encode %{
address target = CAST_FROM_FN_PTR(address, SharedRuntime::ldiv);
__ call(target, relocInfo::runtime_call_type);
%}
ins_pipe(divL_reg_reg);
%}
// Integer Remainder
// Register Remainder
instruct modI_reg_reg(R0RegI dst, R0RegI src1, R2RegI src2, R1RegI temp, LRRegP lr, flagsReg ccr ) %{
match(Set dst (ModI src1 src2));
effect( KILL ccr, KILL temp, KILL src2, KILL lr);
format %{ "MODI $dst,$src1,$src2\t ! call to StubRoutines::Arm::idiv_irem_entry" %}
ins_encode %{
__ call(StubRoutines::Arm::idiv_irem_entry(), relocInfo::runtime_call_type);
%}
ins_pipe(sdiv_reg_reg);
%}
// Register Long Remainder
instruct modL_reg_reg(R0R1RegL dst, R2R3RegL src1, R0R1RegL src2) %{
match(Set dst (ModL src1 src2));
effect(CALL);
ins_cost(MEMORY_REF_COST); // FIXME
format %{ "modL $dst,$src1,$src2\t ! call to SharedRuntime::lrem" %}
ins_encode %{
address target = CAST_FROM_FN_PTR(address, SharedRuntime::lrem);
__ call(target, relocInfo::runtime_call_type);
%}
ins_pipe(divL_reg_reg);
%}
// Integer Shift Instructions
// Register Shift Left
instruct shlI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
match(Set dst (LShiftI src1 src2));
size(4);
format %{ "LSL $dst,$src1,$src2 \n\t" %}
ins_encode %{
__ mov($dst$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
// Register Shift Left Immediate
instruct shlI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
match(Set dst (LShiftI src1 src2));
size(4);
format %{ "LSL $dst,$src1,$src2\t! int" %}
ins_encode %{
__ logical_shift_left($dst$$Register, $src1$$Register, $src2$$constant);
%}
ins_pipe(ialu_reg_imm);
%}
instruct shlL_reg_reg_merge_hi(iRegL dst, iRegL src1, iRegI src2) %{
effect(USE_DEF dst, USE src1, USE src2);
size(4);
format %{"OR $dst.hi,$dst.hi,($src1.hi << $src2)" %}
ins_encode %{
__ orr($dst$$Register->successor(), $dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsl, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct shlL_reg_reg_merge_lo(iRegL dst, iRegL src1, iRegI src2) %{
effect(USE_DEF dst, USE src1, USE src2);
size(4);
format %{ "LSL $dst.lo,$src1.lo,$src2 \n\t" %}
ins_encode %{
__ mov($dst$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct shlL_reg_reg_overlap(iRegL dst, iRegL src1, iRegI src2, flagsReg ccr) %{
effect(DEF dst, USE src1, USE src2, KILL ccr);
size(16);
format %{ "SUBS $dst.hi,$src2,32 \n\t"
"LSLpl $dst.hi,$src1.lo,$dst.hi \n\t"
"RSBmi $dst.hi,$dst.hi,0 \n\t"
"LSRmi $dst.hi,$src1.lo,$dst.hi" %}
ins_encode %{
// $src1$$Register and $dst$$Register->successor() can't be the same
__ subs($dst$$Register->successor(), $src2$$Register, 32);
__ mov($dst$$Register->successor(), AsmOperand($src1$$Register, lsl, $dst$$Register->successor()), pl);
__ rsb($dst$$Register->successor(), $dst$$Register->successor(), 0, mi);
__ mov($dst$$Register->successor(), AsmOperand($src1$$Register, lsr, $dst$$Register->successor()), mi);
%}
ins_pipe(ialu_reg_reg);
%}
instruct shlL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
match(Set dst (LShiftL src1 src2));
expand %{
flagsReg ccr;
shlL_reg_reg_overlap(dst, src1, src2, ccr);
shlL_reg_reg_merge_hi(dst, src1, src2);
shlL_reg_reg_merge_lo(dst, src1, src2);
%}
%}
// Register Shift Left Immediate
instruct shlL_reg_imm6(iRegL dst, iRegL src1, immU6Big src2) %{
match(Set dst (LShiftL src1 src2));
size(8);
format %{ "LSL $dst.hi,$src1.lo,$src2-32\t! or mov if $src2==32\n\t"
"MOV $dst.lo, 0" %}
ins_encode %{
if ($src2$$constant == 32) {
__ mov($dst$$Register->successor(), $src1$$Register);
} else {
__ mov($dst$$Register->successor(), AsmOperand($src1$$Register, lsl, $src2$$constant-32));
}
__ mov($dst$$Register, 0);
%}
ins_pipe(ialu_reg_imm);
%}
instruct shlL_reg_imm5(iRegL dst, iRegL src1, immU5 src2) %{
match(Set dst (LShiftL src1 src2));
size(12);
format %{ "LSL $dst.hi,$src1.lo,$src2\n\t"
"OR $dst.hi, $dst.hi, $src1.lo >> 32-$src2\n\t"
"LSL $dst.lo,$src1.lo,$src2" %}
ins_encode %{
// The order of the following 3 instructions matters: src1.lo and
// dst.hi can't overlap but src.hi and dst.hi can.
__ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsl, $src2$$constant));
__ orr($dst$$Register->successor(), $dst$$Register->successor(), AsmOperand($src1$$Register, lsr, 32-$src2$$constant));
__ mov($dst$$Register, AsmOperand($src1$$Register, lsl, $src2$$constant));
%}
ins_pipe(ialu_reg_imm);
%}
// Register Arithmetic Shift Right
instruct sarI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
match(Set dst (RShiftI src1 src2));
size(4);
format %{ "ASR $dst,$src1,$src2\t! int" %}
ins_encode %{
__ mov($dst$$Register, AsmOperand($src1$$Register, asr, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
// Register Arithmetic Shift Right Immediate
instruct sarI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
match(Set dst (RShiftI src1 src2));
size(4);
format %{ "ASR $dst,$src1,$src2" %}
ins_encode %{
__ mov($dst$$Register, AsmOperand($src1$$Register, asr, $src2$$constant));
%}
ins_pipe(ialu_reg_imm);
%}
// Register Shift Right Arithmetic Long
instruct sarL_reg_reg_merge_lo(iRegL dst, iRegL src1, iRegI src2) %{
effect(USE_DEF dst, USE src1, USE src2);
size(4);
format %{ "OR $dst.lo,$dst.lo,($src1.lo >> $src2)" %}
ins_encode %{
__ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct sarL_reg_reg_merge_hi(iRegL dst, iRegL src1, iRegI src2) %{
effect(USE_DEF dst, USE src1, USE src2);
size(4);
format %{ "ASR $dst.hi,$src1.hi,$src2 \n\t" %}
ins_encode %{
__ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), asr, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct sarL_reg_reg_overlap(iRegL dst, iRegL src1, iRegI src2, flagsReg ccr) %{
effect(DEF dst, USE src1, USE src2, KILL ccr);
size(16);
format %{ "SUBS $dst.lo,$src2,32 \n\t"
"ASRpl $dst.lo,$src1.hi,$dst.lo \n\t"
"RSBmi $dst.lo,$dst.lo,0 \n\t"
"LSLmi $dst.lo,$src1.hi,$dst.lo" %}
ins_encode %{
// $src1$$Register->successor() and $dst$$Register can't be the same
__ subs($dst$$Register, $src2$$Register, 32);
__ mov($dst$$Register, AsmOperand($src1$$Register->successor(), asr, $dst$$Register), pl);
__ rsb($dst$$Register, $dst$$Register, 0, mi);
__ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsl, $dst$$Register), mi);
%}
ins_pipe(ialu_reg_reg);
%}
instruct sarL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
match(Set dst (RShiftL src1 src2));
expand %{
flagsReg ccr;
sarL_reg_reg_overlap(dst, src1, src2, ccr);
sarL_reg_reg_merge_lo(dst, src1, src2);
sarL_reg_reg_merge_hi(dst, src1, src2);
%}
%}
// Register Shift Left Immediate
instruct sarL_reg_imm6(iRegL dst, iRegL src1, immU6Big src2) %{
match(Set dst (RShiftL src1 src2));
size(8);
format %{ "ASR $dst.lo,$src1.hi,$src2-32\t! or mov if $src2==32\n\t"
"ASR $dst.hi,$src1.hi, $src2" %}
ins_encode %{
if ($src2$$constant == 32) {
__ mov($dst$$Register, $src1$$Register->successor());
} else{
__ mov($dst$$Register, AsmOperand($src1$$Register->successor(), asr, $src2$$constant-32));
}
__ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), asr, 0));
%}
ins_pipe(ialu_reg_imm);
%}
instruct sarL_reg_imm5(iRegL dst, iRegL src1, immU5 src2) %{
match(Set dst (RShiftL src1 src2));
size(12);
format %{ "LSR $dst.lo,$src1.lo,$src2\n\t"
"OR $dst.lo, $dst.lo, $src1.hi << 32-$src2\n\t"
"ASR $dst.hi,$src1.hi,$src2" %}
ins_encode %{
// The order of the following 3 instructions matters: src1.lo and
// dst.hi can't overlap but src.hi and dst.hi can.
__ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
__ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register->successor(), lsl, 32-$src2$$constant));
__ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), asr, $src2$$constant));
%}
ins_pipe(ialu_reg_imm);
%}
// Register Shift Right
instruct shrI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
match(Set dst (URShiftI src1 src2));
size(4);
format %{ "LSR $dst,$src1,$src2\t! int" %}
ins_encode %{
__ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
// Register Shift Right Immediate
instruct shrI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
match(Set dst (URShiftI src1 src2));
size(4);
format %{ "LSR $dst,$src1,$src2" %}
ins_encode %{
__ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
%}
ins_pipe(ialu_reg_imm);
%}
// Register Shift Right
instruct shrL_reg_reg_merge_lo(iRegL dst, iRegL src1, iRegI src2) %{
effect(USE_DEF dst, USE src1, USE src2);
size(4);
format %{ "OR $dst.lo,$dst,($src1.lo >>> $src2)" %}
ins_encode %{
__ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct shrL_reg_reg_merge_hi(iRegL dst, iRegL src1, iRegI src2) %{
effect(USE_DEF dst, USE src1, USE src2);
size(4);
format %{ "LSR $dst.hi,$src1.hi,$src2 \n\t" %}
ins_encode %{
__ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsr, $src2$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct shrL_reg_reg_overlap(iRegL dst, iRegL src1, iRegI src2, flagsReg ccr) %{
effect(DEF dst, USE src1, USE src2, KILL ccr);
size(16);
format %{ "SUBS $dst,$src2,32 \n\t"
"LSRpl $dst,$src1.hi,$dst \n\t"
"RSBmi $dst,$dst,0 \n\t"
"LSLmi $dst,$src1.hi,$dst" %}
ins_encode %{
// $src1$$Register->successor() and $dst$$Register can't be the same
__ subs($dst$$Register, $src2$$Register, 32);
__ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsr, $dst$$Register), pl);
__ rsb($dst$$Register, $dst$$Register, 0, mi);
__ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsl, $dst$$Register), mi);
%}
ins_pipe(ialu_reg_reg);
%}
instruct shrL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
match(Set dst (URShiftL src1 src2));
expand %{
flagsReg ccr;
shrL_reg_reg_overlap(dst, src1, src2, ccr);
shrL_reg_reg_merge_lo(dst, src1, src2);
shrL_reg_reg_merge_hi(dst, src1, src2);
%}
%}
// Register Shift Right Immediate
instruct shrL_reg_imm6(iRegL dst, iRegL src1, immU6Big src2) %{
match(Set dst (URShiftL src1 src2));
size(8);
format %{ "LSR $dst.lo,$src1.hi,$src2-32\t! or mov if $src2==32\n\t"
"MOV $dst.hi, 0" %}
ins_encode %{
if ($src2$$constant == 32) {
__ mov($dst$$Register, $src1$$Register->successor());
} else {
__ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsr, $src2$$constant-32));
}
__ mov($dst$$Register->successor(), 0);
%}
ins_pipe(ialu_reg_imm);
%}
instruct shrL_reg_imm5(iRegL dst, iRegL src1, immU5 src2) %{
match(Set dst (URShiftL src1 src2));
size(12);
format %{ "LSR $dst.lo,$src1.lo,$src2\n\t"
"OR $dst.lo, $dst.lo, $src1.hi << 32-$src2\n\t"
"LSR $dst.hi,$src1.hi,$src2" %}
ins_encode %{
// The order of the following 3 instructions matters: src1.lo and
// dst.hi can't overlap but src.hi and dst.hi can.
__ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
__ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register->successor(), lsl, 32-$src2$$constant));
__ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsr, $src2$$constant));
%}
ins_pipe(ialu_reg_imm);
%}
instruct shrP_reg_imm5(iRegX dst, iRegP src1, immU5 src2) %{
match(Set dst (URShiftI (CastP2X src1) src2));
size(4);
format %{ "LSR $dst,$src1,$src2\t! Cast ptr $src1 to int and shift" %}
ins_encode %{
__ logical_shift_right($dst$$Register, $src1$$Register, $src2$$constant);
%}
ins_pipe(ialu_reg_imm);
%}
//----------Floating Point Arithmetic Instructions-----------------------------
// Add float single precision
instruct addF_reg_reg(regF dst, regF src1, regF src2) %{
match(Set dst (AddF src1 src2));
size(4);
format %{ "FADDS $dst,$src1,$src2" %}
ins_encode %{
__ add_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(faddF_reg_reg);
%}
// Add float double precision
instruct addD_reg_reg(regD dst, regD src1, regD src2) %{
match(Set dst (AddD src1 src2));
size(4);
format %{ "FADDD $dst,$src1,$src2" %}
ins_encode %{
__ add_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(faddD_reg_reg);
%}
// Sub float single precision
instruct subF_reg_reg(regF dst, regF src1, regF src2) %{
match(Set dst (SubF src1 src2));
size(4);
format %{ "FSUBS $dst,$src1,$src2" %}
ins_encode %{
__ sub_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(faddF_reg_reg);
%}
// Sub float double precision
instruct subD_reg_reg(regD dst, regD src1, regD src2) %{
match(Set dst (SubD src1 src2));
size(4);
format %{ "FSUBD $dst,$src1,$src2" %}
ins_encode %{
__ sub_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(faddD_reg_reg);
%}
// Mul float single precision
instruct mulF_reg_reg(regF dst, regF src1, regF src2) %{
match(Set dst (MulF src1 src2));
size(4);
format %{ "FMULS $dst,$src1,$src2" %}
ins_encode %{
__ mul_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(fmulF_reg_reg);
%}
// Mul float double precision
instruct mulD_reg_reg(regD dst, regD src1, regD src2) %{
match(Set dst (MulD src1 src2));
size(4);
format %{ "FMULD $dst,$src1,$src2" %}
ins_encode %{
__ mul_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(fmulD_reg_reg);
%}
// Div float single precision
instruct divF_reg_reg(regF dst, regF src1, regF src2) %{
match(Set dst (DivF src1 src2));
size(4);
format %{ "FDIVS $dst,$src1,$src2" %}
ins_encode %{
__ div_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(fdivF_reg_reg);
%}
// Div float double precision
instruct divD_reg_reg(regD dst, regD src1, regD src2) %{
match(Set dst (DivD src1 src2));
size(4);
format %{ "FDIVD $dst,$src1,$src2" %}
ins_encode %{
__ div_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(fdivD_reg_reg);
%}
// Absolute float double precision
instruct absD_reg(regD dst, regD src) %{
match(Set dst (AbsD src));
size(4);
format %{ "FABSd $dst,$src" %}
ins_encode %{
__ abs_double($dst$$FloatRegister, $src$$FloatRegister);
%}
ins_pipe(faddD_reg);
%}
// Absolute float single precision
instruct absF_reg(regF dst, regF src) %{
match(Set dst (AbsF src));
format %{ "FABSs $dst,$src" %}
ins_encode %{
__ abs_float($dst$$FloatRegister, $src$$FloatRegister);
%}
ins_pipe(faddF_reg);
%}
instruct negF_reg(regF dst, regF src) %{
match(Set dst (NegF src));
size(4);
format %{ "FNEGs $dst,$src" %}
ins_encode %{
__ neg_float($dst$$FloatRegister, $src$$FloatRegister);
%}
ins_pipe(faddF_reg);
%}
instruct negD_reg(regD dst, regD src) %{
match(Set dst (NegD src));
format %{ "FNEGd $dst,$src" %}
ins_encode %{
__ neg_double($dst$$FloatRegister, $src$$FloatRegister);
%}
ins_pipe(faddD_reg);
%}
// Sqrt float double precision
instruct sqrtF_reg_reg(regF dst, regF src) %{
match(Set dst (ConvD2F (SqrtD (ConvF2D src))));
size(4);
format %{ "FSQRTS $dst,$src" %}
ins_encode %{
__ sqrt_float($dst$$FloatRegister, $src$$FloatRegister);
%}
ins_pipe(fdivF_reg_reg);
%}
// Sqrt float double precision
instruct sqrtD_reg_reg(regD dst, regD src) %{
match(Set dst (SqrtD src));
size(4);
format %{ "FSQRTD $dst,$src" %}
ins_encode %{
__ sqrt_double($dst$$FloatRegister, $src$$FloatRegister);
%}
ins_pipe(fdivD_reg_reg);
%}
//----------Logical Instructions-----------------------------------------------
// And Instructions
// Register And
instruct andI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
match(Set dst (AndI src1 src2));
size(4);
format %{ "and_32 $dst,$src1,$src2" %}
ins_encode %{
__ and_32($dst$$Register, $src1$$Register, $src2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct andshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (AndI src1 (LShiftI src2 src3)));
size(4);
format %{ "AND $dst,$src1,$src2<<$src3" %}
ins_encode %{
__ andr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct andshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (AndI src1 (LShiftI src2 src3)));
size(4);
format %{ "and_32 $dst,$src1,$src2<<$src3" %}
ins_encode %{
__ and_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct andsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (AndI src1 (RShiftI src2 src3)));
size(4);
format %{ "AND $dst,$src1,$src2>>$src3" %}
ins_encode %{
__ andr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct andsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (AndI src1 (RShiftI src2 src3)));
size(4);
format %{ "and_32 $dst,$src1,$src2>>$src3" %}
ins_encode %{
__ and_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct andshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (AndI src1 (URShiftI src2 src3)));
size(4);
format %{ "AND $dst,$src1,$src2>>>$src3" %}
ins_encode %{
__ andr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct andshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (AndI src1 (URShiftI src2 src3)));
size(4);
format %{ "and_32 $dst,$src1,$src2>>>$src3" %}
ins_encode %{
__ and_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
// Immediate And
instruct andI_reg_limm(iRegI dst, iRegI src1, limmI src2) %{
match(Set dst (AndI src1 src2));
size(4);
format %{ "and_32 $dst,$src1,$src2\t! int" %}
ins_encode %{
__ and_32($dst$$Register, $src1$$Register, $src2$$constant);
%}
ins_pipe(ialu_reg_imm);
%}
instruct andI_reg_limmn(iRegI dst, iRegI src1, limmIn src2) %{
match(Set dst (AndI src1 src2));
size(4);
format %{ "bic $dst,$src1,~$src2\t! int" %}
ins_encode %{
__ bic($dst$$Register, $src1$$Register, ~$src2$$constant);
%}
ins_pipe(ialu_reg_imm);
%}
// Register And Long
instruct andL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
match(Set dst (AndL src1 src2));
ins_cost(DEFAULT_COST);
size(8);
format %{ "AND $dst,$src1,$src2\t! long" %}
ins_encode %{
__ andr($dst$$Register, $src1$$Register, $src2$$Register);
__ andr($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
%}
ins_pipe(ialu_reg_reg);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct andL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con) %{
match(Set dst (AndL src1 con));
ins_cost(DEFAULT_COST);
size(8);
format %{ "AND $dst,$src1,$con\t! long" %}
ins_encode %{
__ andr($dst$$Register, $src1$$Register, $con$$constant);
__ andr($dst$$Register->successor(), $src1$$Register->successor(), 0);
%}
ins_pipe(ialu_reg_imm);
%}
// Or Instructions
// Register Or
instruct orI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
match(Set dst (OrI src1 src2));
size(4);
format %{ "orr_32 $dst,$src1,$src2\t! int" %}
ins_encode %{
__ orr_32($dst$$Register, $src1$$Register, $src2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct orshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (OrI src1 (LShiftI src2 src3)));
size(4);
format %{ "OR $dst,$src1,$src2<<$src3" %}
ins_encode %{
__ orr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct orshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (OrI src1 (LShiftI src2 src3)));
size(4);
format %{ "orr_32 $dst,$src1,$src2<<$src3" %}
ins_encode %{
__ orr_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct orsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (OrI src1 (RShiftI src2 src3)));
size(4);
format %{ "OR $dst,$src1,$src2>>$src3" %}
ins_encode %{
__ orr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct orsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (OrI src1 (RShiftI src2 src3)));
size(4);
format %{ "orr_32 $dst,$src1,$src2>>$src3" %}
ins_encode %{
__ orr_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct orshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (OrI src1 (URShiftI src2 src3)));
size(4);
format %{ "OR $dst,$src1,$src2>>>$src3" %}
ins_encode %{
__ orr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct orshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (OrI src1 (URShiftI src2 src3)));
size(4);
format %{ "orr_32 $dst,$src1,$src2>>>$src3" %}
ins_encode %{
__ orr_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
// Immediate Or
instruct orI_reg_limm(iRegI dst, iRegI src1, limmI src2) %{
match(Set dst (OrI src1 src2));
size(4);
format %{ "orr_32 $dst,$src1,$src2" %}
ins_encode %{
__ orr_32($dst$$Register, $src1$$Register, $src2$$constant);
%}
ins_pipe(ialu_reg_imm);
%}
// TODO: orn_32 with limmIn
// Register Or Long
instruct orL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
match(Set dst (OrL src1 src2));
ins_cost(DEFAULT_COST);
size(8);
format %{ "OR $dst.lo,$src1.lo,$src2.lo\t! long\n\t"
"OR $dst.hi,$src1.hi,$src2.hi" %}
ins_encode %{
__ orr($dst$$Register, $src1$$Register, $src2$$Register);
__ orr($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
%}
ins_pipe(ialu_reg_reg);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct orL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con) %{
match(Set dst (OrL src1 con));
ins_cost(DEFAULT_COST);
size(8);
format %{ "OR $dst.lo,$src1.lo,$con\t! long\n\t"
"OR $dst.hi,$src1.hi,$con" %}
ins_encode %{
__ orr($dst$$Register, $src1$$Register, $con$$constant);
__ orr($dst$$Register->successor(), $src1$$Register->successor(), 0);
%}
ins_pipe(ialu_reg_imm);
%}
#ifdef TODO
// Use SPRegP to match Rthread (TLS register) without spilling.
// Use store_ptr_RegP to match Rthread (TLS register) without spilling.
// Use sp_ptr_RegP to match Rthread (TLS register) without spilling.
instruct orI_reg_castP2X(iRegI dst, iRegI src1, sp_ptr_RegP src2) %{
match(Set dst (OrI src1 (CastP2X src2)));
size(4);
format %{ "OR $dst,$src1,$src2" %}
ins_encode %{
__ orr($dst$$Register, $src1$$Register, $src2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
#endif
// Xor Instructions
// Register Xor
instruct xorI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
match(Set dst (XorI src1 src2));
size(4);
format %{ "eor_32 $dst,$src1,$src2" %}
ins_encode %{
__ eor_32($dst$$Register, $src1$$Register, $src2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct xorshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (XorI src1 (LShiftI src2 src3)));
size(4);
format %{ "XOR $dst,$src1,$src2<<$src3" %}
ins_encode %{
__ eor($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct xorshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (XorI src1 (LShiftI src2 src3)));
size(4);
format %{ "eor_32 $dst,$src1,$src2<<$src3" %}
ins_encode %{
__ eor_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct xorsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (XorI src1 (RShiftI src2 src3)));
size(4);
format %{ "XOR $dst,$src1,$src2>>$src3" %}
ins_encode %{
__ eor($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct xorsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (XorI src1 (RShiftI src2 src3)));
size(4);
format %{ "eor_32 $dst,$src1,$src2>>$src3" %}
ins_encode %{
__ eor_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
instruct xorshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
match(Set dst (XorI src1 (URShiftI src2 src3)));
size(4);
format %{ "XOR $dst,$src1,$src2>>>$src3" %}
ins_encode %{
__ eor($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
instruct xorshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
match(Set dst (XorI src1 (URShiftI src2 src3)));
size(4);
format %{ "eor_32 $dst,$src1,$src2>>>$src3" %}
ins_encode %{
__ eor_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
%}
ins_pipe(ialu_reg_reg);
%}
// Immediate Xor
instruct xorI_reg_imm(iRegI dst, iRegI src1, limmI src2) %{
match(Set dst (XorI src1 src2));
size(4);
format %{ "eor_32 $dst,$src1,$src2" %}
ins_encode %{
__ eor_32($dst$$Register, $src1$$Register, $src2$$constant);
%}
ins_pipe(ialu_reg_imm);
%}
// Register Xor Long
instruct xorL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
match(Set dst (XorL src1 src2));
ins_cost(DEFAULT_COST);
size(8);
format %{ "XOR $dst.hi,$src1.hi,$src2.hi\t! long\n\t"
"XOR $dst.lo,$src1.lo,$src2.lo\t! long" %}
ins_encode %{
__ eor($dst$$Register, $src1$$Register, $src2$$Register);
__ eor($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
%}
ins_pipe(ialu_reg_reg);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct xorL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con) %{
match(Set dst (XorL src1 con));
ins_cost(DEFAULT_COST);
size(8);
format %{ "XOR $dst.hi,$src1.hi,$con\t! long\n\t"
"XOR $dst.lo,$src1.lo,0\t! long" %}
ins_encode %{
__ eor($dst$$Register, $src1$$Register, $con$$constant);
__ eor($dst$$Register->successor(), $src1$$Register->successor(), 0);
%}
ins_pipe(ialu_reg_imm);
%}
//----------Convert to Boolean-------------------------------------------------
instruct convI2B( iRegI dst, iRegI src, flagsReg ccr ) %{
match(Set dst (Conv2B src));
effect(KILL ccr);
size(12);
ins_cost(DEFAULT_COST*2);
format %{ "TST $src,$src \n\t"
"MOV $dst, 0 \n\t"
"MOV.ne $dst, 1" %}
ins_encode %{ // FIXME: can do better?
__ tst($src$$Register, $src$$Register);
__ mov($dst$$Register, 0);
__ mov($dst$$Register, 1, ne);
%}
ins_pipe(ialu_reg_ialu);
%}
instruct convP2B( iRegI dst, iRegP src, flagsReg ccr ) %{
match(Set dst (Conv2B src));
effect(KILL ccr);
size(12);
ins_cost(DEFAULT_COST*2);
format %{ "TST $src,$src \n\t"
"MOV $dst, 0 \n\t"
"MOV.ne $dst, 1" %}
ins_encode %{
__ tst($src$$Register, $src$$Register);
__ mov($dst$$Register, 0);
__ mov($dst$$Register, 1, ne);
%}
ins_pipe(ialu_reg_ialu);
%}
instruct cmpLTMask_reg_reg( iRegI dst, iRegI p, iRegI q, flagsReg ccr ) %{
match(Set dst (CmpLTMask p q));
effect( KILL ccr );
ins_cost(DEFAULT_COST*3);
format %{ "CMP $p,$q\n\t"
"MOV $dst, #0\n\t"
"MOV.lt $dst, #-1" %}
ins_encode %{
__ cmp($p$$Register, $q$$Register);
__ mov($dst$$Register, 0);
__ mvn($dst$$Register, 0, lt);
%}
ins_pipe(ialu_reg_reg_ialu);
%}
instruct cmpLTMask_reg_imm( iRegI dst, iRegI p, aimmI q, flagsReg ccr ) %{
match(Set dst (CmpLTMask p q));
effect( KILL ccr );
ins_cost(DEFAULT_COST*3);
format %{ "CMP $p,$q\n\t"
"MOV $dst, #0\n\t"
"MOV.lt $dst, #-1" %}
ins_encode %{
__ cmp($p$$Register, $q$$constant);
__ mov($dst$$Register, 0);
__ mvn($dst$$Register, 0, lt);
%}
ins_pipe(ialu_reg_reg_ialu);
%}
instruct cadd_cmpLTMask3( iRegI p, iRegI q, iRegI y, iRegI z, flagsReg ccr ) %{
match(Set z (AddI (AndI (CmpLTMask p q) y) z));
effect( KILL ccr );
ins_cost(DEFAULT_COST*2);
format %{ "CMP $p,$q\n\t"
"ADD.lt $z,$y,$z" %}
ins_encode %{
__ cmp($p$$Register, $q$$Register);
__ add($z$$Register, $y$$Register, $z$$Register, lt);
%}
ins_pipe( cadd_cmpltmask );
%}
// FIXME: remove unused "dst"
instruct cadd_cmpLTMask4( iRegI dst, iRegI p, aimmI q, iRegI y, iRegI z, flagsReg ccr ) %{
match(Set z (AddI (AndI (CmpLTMask p q) y) z));
effect( KILL ccr );
ins_cost(DEFAULT_COST*2);
format %{ "CMP $p,$q\n\t"
"ADD.lt $z,$y,$z" %}
ins_encode %{
__ cmp($p$$Register, $q$$constant);
__ add($z$$Register, $y$$Register, $z$$Register, lt);
%}
ins_pipe( cadd_cmpltmask );
%}
instruct cadd_cmpLTMask( iRegI p, iRegI q, iRegI y, flagsReg ccr ) %{
match(Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q)));
effect( KILL ccr );
ins_cost(DEFAULT_COST*2);
format %{ "SUBS $p,$p,$q\n\t"
"ADD.lt $p,$y,$p" %}
ins_encode %{
__ subs($p$$Register, $p$$Register, $q$$Register);
__ add($p$$Register, $y$$Register, $p$$Register, lt);
%}
ins_pipe( cadd_cmpltmask );
%}
//----------Arithmetic Conversion Instructions---------------------------------
// The conversions operations are all Alpha sorted. Please keep it that way!
instruct convD2F_reg(regF dst, regD src) %{
match(Set dst (ConvD2F src));
size(4);
format %{ "FCVTSD $dst,$src" %}
ins_encode %{
__ convert_d2f($dst$$FloatRegister, $src$$FloatRegister);
%}
ins_pipe(fcvtD2F);
%}
// Convert a double to an int in a float register.
// If the double is a NAN, stuff a zero in instead.
instruct convD2I_reg_reg(iRegI dst, regD src, regF tmp) %{
match(Set dst (ConvD2I src));
effect( TEMP tmp );
ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
format %{ "FTOSIZD $tmp,$src\n\t"
"FMRS $dst, $tmp" %}
ins_encode %{
__ ftosizd($tmp$$FloatRegister, $src$$FloatRegister);
__ fmrs($dst$$Register, $tmp$$FloatRegister);
%}
ins_pipe(fcvtD2I);
%}
// Convert a double to a long in a double register.
// If the double is a NAN, stuff a zero in instead.
// Double to Long conversion
instruct convD2L_reg(R0R1RegL dst, regD src) %{
match(Set dst (ConvD2L src));
effect(CALL);
ins_cost(MEMORY_REF_COST); // FIXME
format %{ "convD2L $dst,$src\t ! call to SharedRuntime::d2l" %}
ins_encode %{
#ifndef __ABI_HARD__
__ fmrrd($dst$$Register, $dst$$Register->successor(), $src$$FloatRegister);
#else
if ($src$$FloatRegister != D0) {
__ mov_double(D0, $src$$FloatRegister);
}
#endif
address target = CAST_FROM_FN_PTR(address, SharedRuntime::d2l);
__ call(target, relocInfo::runtime_call_type);
%}
ins_pipe(fcvtD2L);
%}
instruct convF2D_reg(regD dst, regF src) %{
match(Set dst (ConvF2D src));
size(4);
format %{ "FCVTDS $dst,$src" %}
ins_encode %{
__ convert_f2d($dst$$FloatRegister, $src$$FloatRegister);
%}
ins_pipe(fcvtF2D);
%}
instruct convF2I_reg_reg(iRegI dst, regF src, regF tmp) %{
match(Set dst (ConvF2I src));
effect( TEMP tmp );
ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
size(8);
format %{ "FTOSIZS $tmp,$src\n\t"
"FMRS $dst, $tmp" %}
ins_encode %{
__ ftosizs($tmp$$FloatRegister, $src$$FloatRegister);
__ fmrs($dst$$Register, $tmp$$FloatRegister);
%}
ins_pipe(fcvtF2I);
%}
// Float to Long conversion
instruct convF2L_reg(R0R1RegL dst, regF src, R0RegI arg1) %{
match(Set dst (ConvF2L src));
ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
effect(CALL);
format %{ "convF2L $dst,$src\t! call to SharedRuntime::f2l" %}
ins_encode %{
#ifndef __ABI_HARD__
__ fmrs($arg1$$Register, $src$$FloatRegister);
#else
if($src$$FloatRegister != S0) {
__ mov_float(S0, $src$$FloatRegister);
}
#endif
address target = CAST_FROM_FN_PTR(address, SharedRuntime::f2l);
__ call(target, relocInfo::runtime_call_type);
%}
ins_pipe(fcvtF2L);
%}
instruct convI2D_reg_reg(iRegI src, regD_low dst) %{
match(Set dst (ConvI2D src));
ins_cost(DEFAULT_COST + MEMORY_REF_COST); // FIXME
size(8);
format %{ "FMSR $dst,$src \n\t"
"FSITOD $dst $dst"%}
ins_encode %{
__ fmsr($dst$$FloatRegister, $src$$Register);
__ fsitod($dst$$FloatRegister, $dst$$FloatRegister);
%}
ins_pipe(fcvtI2D);
%}
instruct convI2F_reg_reg( regF dst, iRegI src ) %{
match(Set dst (ConvI2F src));
ins_cost(DEFAULT_COST + MEMORY_REF_COST); // FIXME
size(8);
format %{ "FMSR $dst,$src \n\t"
"FSITOS $dst, $dst"%}
ins_encode %{
__ fmsr($dst$$FloatRegister, $src$$Register);
__ fsitos($dst$$FloatRegister, $dst$$FloatRegister);
%}
ins_pipe(fcvtI2F);
%}
instruct convI2L_reg(iRegL dst, iRegI src) %{
match(Set dst (ConvI2L src));
size(8);
format %{ "MOV $dst.lo, $src \n\t"
"ASR $dst.hi,$src,31\t! int->long" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register);
__ mov($dst$$Register->successor(), AsmOperand($src$$Register, asr, 31));
%}
ins_pipe(ialu_reg_reg);
%}
// Zero-extend convert int to long
instruct convI2L_reg_zex(iRegL dst, iRegI src, immL_32bits mask ) %{
match(Set dst (AndL (ConvI2L src) mask) );
size(8);
format %{ "MOV $dst.lo,$src.lo\t! zero-extend int to long\n\t"
"MOV $dst.hi, 0"%}
ins_encode %{
__ mov($dst$$Register, $src$$Register);
__ mov($dst$$Register->successor(), 0);
%}
ins_pipe(ialu_reg_reg);
%}
// Zero-extend long
instruct zerox_long(iRegL dst, iRegL src, immL_32bits mask ) %{
match(Set dst (AndL src mask) );
size(8);
format %{ "MOV $dst.lo,$src.lo\t! zero-extend long\n\t"
"MOV $dst.hi, 0"%}
ins_encode %{
__ mov($dst$$Register, $src$$Register);
__ mov($dst$$Register->successor(), 0);
%}
ins_pipe(ialu_reg_reg);
%}
instruct MoveF2I_reg_reg(iRegI dst, regF src) %{
match(Set dst (MoveF2I src));
effect(DEF dst, USE src);
ins_cost(MEMORY_REF_COST); // FIXME
size(4);
format %{ "FMRS $dst,$src\t! MoveF2I" %}
ins_encode %{
__ fmrs($dst$$Register, $src$$FloatRegister);
%}
ins_pipe(iload_mem); // FIXME
%}
instruct MoveI2F_reg_reg(regF dst, iRegI src) %{
match(Set dst (MoveI2F src));
ins_cost(MEMORY_REF_COST); // FIXME
size(4);
format %{ "FMSR $dst,$src\t! MoveI2F" %}
ins_encode %{
__ fmsr($dst$$FloatRegister, $src$$Register);
%}
ins_pipe(iload_mem); // FIXME
%}
instruct MoveD2L_reg_reg(iRegL dst, regD src) %{
match(Set dst (MoveD2L src));
effect(DEF dst, USE src);
ins_cost(MEMORY_REF_COST); // FIXME
size(4);
format %{ "FMRRD $dst,$src\t! MoveD2L" %}
ins_encode %{
__ fmrrd($dst$$Register, $dst$$Register->successor(), $src$$FloatRegister);
%}
ins_pipe(iload_mem); // FIXME
%}
instruct MoveL2D_reg_reg(regD dst, iRegL src) %{
match(Set dst (MoveL2D src));
effect(DEF dst, USE src);
ins_cost(MEMORY_REF_COST); // FIXME
size(4);
format %{ "FMDRR $dst,$src\t! MoveL2D" %}
ins_encode %{
__ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register->successor());
%}
ins_pipe(ialu_reg_reg); // FIXME
%}
//-----------
// Long to Double conversion
// Magic constant, 0x43300000
instruct loadConI_x43300000(iRegI dst) %{
effect(DEF dst);
size(8);
format %{ "MOV_SLOW $dst,0x43300000\t! 2^52" %}
ins_encode %{
__ mov_slow($dst$$Register, 0x43300000);
%}
ins_pipe(ialu_none);
%}
// Magic constant, 0x41f00000
instruct loadConI_x41f00000(iRegI dst) %{
effect(DEF dst);
size(8);
format %{ "MOV_SLOW $dst, 0x41f00000\t! 2^32" %}
ins_encode %{
__ mov_slow($dst$$Register, 0x41f00000);
%}
ins_pipe(ialu_none);
%}
instruct loadConI_x0(iRegI dst) %{
effect(DEF dst);
size(4);
format %{ "MOV $dst, 0x0\t! 0" %}
ins_encode %{
__ mov($dst$$Register, 0);
%}
ins_pipe(ialu_none);
%}
// Construct a double from two float halves
instruct regDHi_regDLo_to_regD(regD_low dst, regD_low src1, regD_low src2) %{
effect(DEF dst, USE src1, USE src2);
size(8);
format %{ "FCPYS $dst.hi,$src1.hi\n\t"
"FCPYS $dst.lo,$src2.lo" %}
ins_encode %{
__ fcpys($dst$$FloatRegister->successor(), $src1$$FloatRegister->successor());
__ fcpys($dst$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(faddD_reg_reg);
%}
// Convert integer in high half of a double register (in the lower half of
// the double register file) to double
instruct convI2D_regDHi_regD(regD dst, regD_low src) %{
effect(DEF dst, USE src);
size(4);
format %{ "FSITOD $dst,$src" %}
ins_encode %{
__ fsitod($dst$$FloatRegister, $src$$FloatRegister->successor());
%}
ins_pipe(fcvtLHi2D);
%}
// Add float double precision
instruct addD_regD_regD(regD dst, regD src1, regD src2) %{
effect(DEF dst, USE src1, USE src2);
size(4);
format %{ "FADDD $dst,$src1,$src2" %}
ins_encode %{
__ add_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(faddD_reg_reg);
%}
// Sub float double precision
instruct subD_regD_regD(regD dst, regD src1, regD src2) %{
effect(DEF dst, USE src1, USE src2);
size(4);
format %{ "FSUBD $dst,$src1,$src2" %}
ins_encode %{
__ sub_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(faddD_reg_reg);
%}
// Mul float double precision
instruct mulD_regD_regD(regD dst, regD src1, regD src2) %{
effect(DEF dst, USE src1, USE src2);
size(4);
format %{ "FMULD $dst,$src1,$src2" %}
ins_encode %{
__ mul_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
%}
ins_pipe(fmulD_reg_reg);
%}
instruct regL_to_regD(regD dst, iRegL src) %{
// No match rule to avoid chain rule match.
effect(DEF dst, USE src);
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "FMDRR $dst,$src\t! regL to regD" %}
ins_encode %{
__ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register->successor());
%}
ins_pipe(ialu_reg_reg); // FIXME
%}
instruct regI_regI_to_regD(regD dst, iRegI src1, iRegI src2) %{
// No match rule to avoid chain rule match.
effect(DEF dst, USE src1, USE src2);
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "FMDRR $dst,$src1,$src2\t! regI,regI to regD" %}
ins_encode %{
__ fmdrr($dst$$FloatRegister, $src1$$Register, $src2$$Register);
%}
ins_pipe(ialu_reg_reg); // FIXME
%}
instruct convL2D_reg_slow_fxtof(regD dst, iRegL src) %{
match(Set dst (ConvL2D src));
ins_cost(DEFAULT_COST*8 + MEMORY_REF_COST*6); // FIXME
expand %{
regD_low tmpsrc;
iRegI ix43300000;
iRegI ix41f00000;
iRegI ix0;
regD_low dx43300000;
regD dx41f00000;
regD tmp1;
regD_low tmp2;
regD tmp3;
regD tmp4;
regL_to_regD(tmpsrc, src);
loadConI_x43300000(ix43300000);
loadConI_x41f00000(ix41f00000);
loadConI_x0(ix0);
regI_regI_to_regD(dx43300000, ix0, ix43300000);
regI_regI_to_regD(dx41f00000, ix0, ix41f00000);
convI2D_regDHi_regD(tmp1, tmpsrc);
regDHi_regDLo_to_regD(tmp2, dx43300000, tmpsrc);
subD_regD_regD(tmp3, tmp2, dx43300000);
mulD_regD_regD(tmp4, tmp1, dx41f00000);
addD_regD_regD(dst, tmp3, tmp4);
%}
%}
instruct convL2I_reg(iRegI dst, iRegL src) %{
match(Set dst (ConvL2I src));
size(4);
format %{ "MOV $dst,$src.lo\t! long->int" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_move_reg_I_to_L);
%}
// Register Shift Right Immediate
instruct shrL_reg_imm6_L2I(iRegI dst, iRegL src, immI_32_63 cnt) %{
match(Set dst (ConvL2I (RShiftL src cnt)));
size(4);
format %{ "ASR $dst,$src.hi,($cnt - 32)\t! long->int or mov if $cnt==32" %}
ins_encode %{
if ($cnt$$constant == 32) {
__ mov($dst$$Register, $src$$Register->successor());
} else {
__ mov($dst$$Register, AsmOperand($src$$Register->successor(), asr, $cnt$$constant - 32));
}
%}
ins_pipe(ialu_reg_imm);
%}
//----------Control Flow Instructions------------------------------------------
// Compare Instructions
// Compare Integers
instruct compI_iReg(flagsReg icc, iRegI op1, iRegI op2) %{
match(Set icc (CmpI op1 op2));
effect( DEF icc, USE op1, USE op2 );
size(4);
format %{ "cmp_32 $op1,$op2\t! int" %}
ins_encode %{
__ cmp_32($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
#ifdef _LP64
// Compare compressed pointers
instruct compN_reg2(flagsRegU icc, iRegN op1, iRegN op2) %{
match(Set icc (CmpN op1 op2));
effect( DEF icc, USE op1, USE op2 );
size(4);
format %{ "cmp_32 $op1,$op2\t! int" %}
ins_encode %{
__ cmp_32($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
#endif
instruct compU_iReg(flagsRegU icc, iRegI op1, iRegI op2) %{
match(Set icc (CmpU op1 op2));
size(4);
format %{ "cmp_32 $op1,$op2\t! unsigned int" %}
ins_encode %{
__ cmp_32($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
instruct compI_iReg_immneg(flagsReg icc, iRegI op1, aimmIneg op2) %{
match(Set icc (CmpI op1 op2));
effect( DEF icc, USE op1 );
size(4);
format %{ "cmn_32 $op1,-$op2\t! int" %}
ins_encode %{
__ cmn_32($op1$$Register, -$op2$$constant);
%}
ins_pipe(ialu_cconly_reg_imm);
%}
instruct compI_iReg_imm(flagsReg icc, iRegI op1, aimmI op2) %{
match(Set icc (CmpI op1 op2));
effect( DEF icc, USE op1 );
size(4);
format %{ "cmp_32 $op1,$op2\t! int" %}
ins_encode %{
__ cmp_32($op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_cconly_reg_imm);
%}
instruct testI_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immI0 zero ) %{
match(Set icc (CmpI (AndI op1 op2) zero));
size(4);
format %{ "tst_32 $op2,$op1" %}
ins_encode %{
__ tst_32($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_cconly_reg_reg_zero);
%}
instruct testshlI_reg_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, iRegI op3, immI0 zero ) %{
match(Set icc (CmpI (AndI op1 (LShiftI op2 op3)) zero));
size(4);
format %{ "TST $op2,$op1<<$op3" %}
ins_encode %{
__ tst($op1$$Register, AsmOperand($op2$$Register, lsl, $op3$$Register));
%}
ins_pipe(ialu_cconly_reg_reg_zero);
%}
instruct testshlI_reg_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immU5 op3, immI0 zero ) %{
match(Set icc (CmpI (AndI op1 (LShiftI op2 op3)) zero));
size(4);
format %{ "tst_32 $op2,$op1<<$op3" %}
ins_encode %{
__ tst_32($op1$$Register, AsmOperand($op2$$Register, lsl, $op3$$constant));
%}
ins_pipe(ialu_cconly_reg_reg_zero);
%}
instruct testsarI_reg_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, iRegI op3, immI0 zero ) %{
match(Set icc (CmpI (AndI op1 (RShiftI op2 op3)) zero));
size(4);
format %{ "TST $op2,$op1<<$op3" %}
ins_encode %{
__ tst($op1$$Register, AsmOperand($op2$$Register, asr, $op3$$Register));
%}
ins_pipe(ialu_cconly_reg_reg_zero);
%}
instruct testsarI_reg_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immU5 op3, immI0 zero ) %{
match(Set icc (CmpI (AndI op1 (RShiftI op2 op3)) zero));
size(4);
format %{ "tst_32 $op2,$op1<<$op3" %}
ins_encode %{
__ tst_32($op1$$Register, AsmOperand($op2$$Register, asr, $op3$$constant));
%}
ins_pipe(ialu_cconly_reg_reg_zero);
%}
instruct testshrI_reg_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, iRegI op3, immI0 zero ) %{
match(Set icc (CmpI (AndI op1 (URShiftI op2 op3)) zero));
size(4);
format %{ "TST $op2,$op1<<$op3" %}
ins_encode %{
__ tst($op1$$Register, AsmOperand($op2$$Register, lsr, $op3$$Register));
%}
ins_pipe(ialu_cconly_reg_reg_zero);
%}
instruct testshrI_reg_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immU5 op3, immI0 zero ) %{
match(Set icc (CmpI (AndI op1 (URShiftI op2 op3)) zero));
size(4);
format %{ "tst_32 $op2,$op1<<$op3" %}
ins_encode %{
__ tst_32($op1$$Register, AsmOperand($op2$$Register, lsr, $op3$$constant));
%}
ins_pipe(ialu_cconly_reg_reg_zero);
%}
instruct testI_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, limmI op2, immI0 zero ) %{
match(Set icc (CmpI (AndI op1 op2) zero));
size(4);
format %{ "tst_32 $op2,$op1" %}
ins_encode %{
__ tst_32($op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_cconly_reg_imm_zero);
%}
instruct compL_reg_reg_LTGE(flagsRegL_LTGE xcc, iRegL op1, iRegL op2, iRegL tmp) %{
match(Set xcc (CmpL op1 op2));
effect( DEF xcc, USE op1, USE op2, TEMP tmp );
size(8);
format %{ "SUBS $tmp,$op1.low,$op2.low\t\t! long\n\t"
"SBCS $tmp,$op1.hi,$op2.hi" %}
ins_encode %{
__ subs($tmp$$Register, $op1$$Register, $op2$$Register);
__ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), $op2$$Register->successor());
%}
ins_pipe(ialu_cconly_reg_reg);
%}
instruct compUL_reg_reg_LTGE(flagsRegUL_LTGE xcc, iRegL op1, iRegL op2, iRegL tmp) %{
match(Set xcc (CmpUL op1 op2));
effect(DEF xcc, USE op1, USE op2, TEMP tmp);
size(8);
format %{ "SUBS $tmp,$op1.low,$op2.low\t\t! unsigned long\n\t"
"SBCS $tmp,$op1.hi,$op2.hi" %}
ins_encode %{
__ subs($tmp$$Register, $op1$$Register, $op2$$Register);
__ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), $op2$$Register->successor());
%}
ins_pipe(ialu_cconly_reg_reg);
%}
instruct compL_reg_reg_EQNE(flagsRegL_EQNE xcc, iRegL op1, iRegL op2) %{
match(Set xcc (CmpL op1 op2));
effect( DEF xcc, USE op1, USE op2 );
size(8);
format %{ "TEQ $op1.hi,$op2.hi\t\t! long\n\t"
"TEQ.eq $op1.lo,$op2.lo" %}
ins_encode %{
__ teq($op1$$Register->successor(), $op2$$Register->successor());
__ teq($op1$$Register, $op2$$Register, eq);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
instruct compL_reg_reg_LEGT(flagsRegL_LEGT xcc, iRegL op1, iRegL op2, iRegL tmp) %{
match(Set xcc (CmpL op1 op2));
effect( DEF xcc, USE op1, USE op2, TEMP tmp );
size(8);
format %{ "SUBS $tmp,$op2.low,$op1.low\t\t! long\n\t"
"SBCS $tmp,$op2.hi,$op1.hi" %}
ins_encode %{
__ subs($tmp$$Register, $op2$$Register, $op1$$Register);
__ sbcs($tmp$$Register->successor(), $op2$$Register->successor(), $op1$$Register->successor());
%}
ins_pipe(ialu_cconly_reg_reg);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compL_reg_con_LTGE(flagsRegL_LTGE xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
match(Set xcc (CmpL op1 con));
effect( DEF xcc, USE op1, USE con, TEMP tmp );
size(8);
format %{ "SUBS $tmp,$op1.low,$con\t\t! long\n\t"
"SBCS $tmp,$op1.hi,0" %}
ins_encode %{
__ subs($tmp$$Register, $op1$$Register, $con$$constant);
__ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compL_reg_con_EQNE(flagsRegL_EQNE xcc, iRegL op1, immLlowRot con) %{
match(Set xcc (CmpL op1 con));
effect( DEF xcc, USE op1, USE con );
size(8);
format %{ "TEQ $op1.hi,0\t\t! long\n\t"
"TEQ.eq $op1.lo,$con" %}
ins_encode %{
__ teq($op1$$Register->successor(), 0);
__ teq($op1$$Register, $con$$constant, eq);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compL_reg_con_LEGT(flagsRegL_LEGT xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
match(Set xcc (CmpL op1 con));
effect( DEF xcc, USE op1, USE con, TEMP tmp );
size(8);
format %{ "RSBS $tmp,$op1.low,$con\t\t! long\n\t"
"RSCS $tmp,$op1.hi,0" %}
ins_encode %{
__ rsbs($tmp$$Register, $op1$$Register, $con$$constant);
__ rscs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
instruct compUL_reg_reg_EQNE(flagsRegUL_EQNE xcc, iRegL op1, iRegL op2) %{
match(Set xcc (CmpUL op1 op2));
effect(DEF xcc, USE op1, USE op2);
size(8);
format %{ "TEQ $op1.hi,$op2.hi\t\t! unsigned long\n\t"
"TEQ.eq $op1.lo,$op2.lo" %}
ins_encode %{
__ teq($op1$$Register->successor(), $op2$$Register->successor());
__ teq($op1$$Register, $op2$$Register, eq);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
instruct compUL_reg_reg_LEGT(flagsRegUL_LEGT xcc, iRegL op1, iRegL op2, iRegL tmp) %{
match(Set xcc (CmpUL op1 op2));
effect(DEF xcc, USE op1, USE op2, TEMP tmp);
size(8);
format %{ "SUBS $tmp,$op2.low,$op1.low\t\t! unsigned long\n\t"
"SBCS $tmp,$op2.hi,$op1.hi" %}
ins_encode %{
__ subs($tmp$$Register, $op2$$Register, $op1$$Register);
__ sbcs($tmp$$Register->successor(), $op2$$Register->successor(), $op1$$Register->successor());
%}
ins_pipe(ialu_cconly_reg_reg);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compUL_reg_con_LTGE(flagsRegUL_LTGE xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
match(Set xcc (CmpUL op1 con));
effect(DEF xcc, USE op1, USE con, TEMP tmp);
size(8);
format %{ "SUBS $tmp,$op1.low,$con\t\t! unsigned long\n\t"
"SBCS $tmp,$op1.hi,0" %}
ins_encode %{
__ subs($tmp$$Register, $op1$$Register, $con$$constant);
__ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compUL_reg_con_EQNE(flagsRegUL_EQNE xcc, iRegL op1, immLlowRot con) %{
match(Set xcc (CmpUL op1 con));
effect(DEF xcc, USE op1, USE con);
size(8);
format %{ "TEQ $op1.hi,0\t\t! unsigned long\n\t"
"TEQ.eq $op1.lo,$con" %}
ins_encode %{
__ teq($op1$$Register->successor(), 0);
__ teq($op1$$Register, $con$$constant, eq);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compUL_reg_con_LEGT(flagsRegUL_LEGT xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
match(Set xcc (CmpUL op1 con));
effect(DEF xcc, USE op1, USE con, TEMP tmp);
size(8);
format %{ "RSBS $tmp,$op1.low,$con\t\t! unsigned long\n\t"
"RSCS $tmp,$op1.hi,0" %}
ins_encode %{
__ rsbs($tmp$$Register, $op1$$Register, $con$$constant);
__ rscs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
/* instruct testL_reg_reg(flagsRegL xcc, iRegL op1, iRegL op2, immL0 zero) %{ */
/* match(Set xcc (CmpL (AndL op1 op2) zero)); */
/* ins_encode %{ */
/* __ stop("testL_reg_reg unimplemented"); */
/* %} */
/* ins_pipe(ialu_cconly_reg_reg); */
/* %} */
/* // useful for checking the alignment of a pointer: */
/* instruct testL_reg_con(flagsRegL xcc, iRegL op1, immLlowRot con, immL0 zero) %{ */
/* match(Set xcc (CmpL (AndL op1 con) zero)); */
/* ins_encode %{ */
/* __ stop("testL_reg_con unimplemented"); */
/* %} */
/* ins_pipe(ialu_cconly_reg_reg); */
/* %} */
instruct compU_iReg_imm(flagsRegU icc, iRegI op1, aimmU31 op2 ) %{
match(Set icc (CmpU op1 op2));
size(4);
format %{ "cmp_32 $op1,$op2\t! unsigned" %}
ins_encode %{
__ cmp_32($op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_cconly_reg_imm);
%}
// Compare Pointers
instruct compP_iRegP(flagsRegP pcc, iRegP op1, iRegP op2 ) %{
match(Set pcc (CmpP op1 op2));
size(4);
format %{ "CMP $op1,$op2\t! ptr" %}
ins_encode %{
__ cmp($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_cconly_reg_reg);
%}
instruct compP_iRegP_imm(flagsRegP pcc, iRegP op1, aimmP op2 ) %{
match(Set pcc (CmpP op1 op2));
size(4);
format %{ "CMP $op1,$op2\t! ptr" %}
ins_encode %{
assert($op2$$constant == 0 || _opnds[2]->constant_reloc() == relocInfo::none, "reloc in cmp?");
__ cmp($op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_cconly_reg_imm);
%}
//----------Max and Min--------------------------------------------------------
// Min Instructions
// Conditional move for min
instruct cmovI_reg_lt( iRegI op2, iRegI op1, flagsReg icc ) %{
effect( USE_DEF op2, USE op1, USE icc );
size(4);
format %{ "MOV.lt $op2,$op1\t! min" %}
ins_encode %{
__ mov($op2$$Register, $op1$$Register, lt);
%}
ins_pipe(ialu_reg_flags);
%}
// Min Register with Register.
instruct minI_eReg(iRegI op1, iRegI op2) %{
match(Set op2 (MinI op1 op2));
ins_cost(DEFAULT_COST*2);
expand %{
flagsReg icc;
compI_iReg(icc,op1,op2);
cmovI_reg_lt(op2,op1,icc);
%}
%}
// Max Instructions
// Conditional move for max
instruct cmovI_reg_gt( iRegI op2, iRegI op1, flagsReg icc ) %{
effect( USE_DEF op2, USE op1, USE icc );
format %{ "MOV.gt $op2,$op1\t! max" %}
ins_encode %{
__ mov($op2$$Register, $op1$$Register, gt);
%}
ins_pipe(ialu_reg_flags);
%}
// Max Register with Register
instruct maxI_eReg(iRegI op1, iRegI op2) %{
match(Set op2 (MaxI op1 op2));
ins_cost(DEFAULT_COST*2);
expand %{
flagsReg icc;
compI_iReg(icc,op1,op2);
cmovI_reg_gt(op2,op1,icc);
%}
%}
//----------Float Compares----------------------------------------------------
// Compare floating, generate condition code
instruct cmpF_cc(flagsRegF fcc, flagsReg icc, regF src1, regF src2) %{
match(Set icc (CmpF src1 src2));
effect(KILL fcc);
size(8);
format %{ "FCMPs $src1,$src2\n\t"
"FMSTAT" %}
ins_encode %{
__ fcmps($src1$$FloatRegister, $src2$$FloatRegister);
__ fmstat();
%}
ins_pipe(faddF_fcc_reg_reg_zero);
%}
instruct cmpF0_cc(flagsRegF fcc, flagsReg icc, regF src1, immF0 src2) %{
match(Set icc (CmpF src1 src2));
effect(KILL fcc);
size(8);
format %{ "FCMPs $src1,$src2\n\t"
"FMSTAT" %}
ins_encode %{
__ fcmpzs($src1$$FloatRegister);
__ fmstat();
%}
ins_pipe(faddF_fcc_reg_reg_zero);
%}
instruct cmpD_cc(flagsRegF fcc, flagsReg icc, regD src1, regD src2) %{
match(Set icc (CmpD src1 src2));
effect(KILL fcc);
size(8);
format %{ "FCMPd $src1,$src2 \n\t"
"FMSTAT" %}
ins_encode %{
__ fcmpd($src1$$FloatRegister, $src2$$FloatRegister);
__ fmstat();
%}
ins_pipe(faddD_fcc_reg_reg_zero);
%}
instruct cmpD0_cc(flagsRegF fcc, flagsReg icc, regD src1, immD0 src2) %{
match(Set icc (CmpD src1 src2));
effect(KILL fcc);
size(8);
format %{ "FCMPZd $src1,$src2 \n\t"
"FMSTAT" %}
ins_encode %{
__ fcmpzd($src1$$FloatRegister);
__ fmstat();
%}
ins_pipe(faddD_fcc_reg_reg_zero);
%}
// Compare floating, generate -1,0,1
instruct cmpF_reg(iRegI dst, regF src1, regF src2, flagsRegF fcc) %{
match(Set dst (CmpF3 src1 src2));
effect(KILL fcc);
ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
size(20);
// same number of instructions as code using conditional moves but
// doesn't kill integer condition register
format %{ "FCMPs $dst,$src1,$src2 \n\t"
"VMRS $dst, FPSCR \n\t"
"OR $dst, $dst, 0x08000000 \n\t"
"EOR $dst, $dst, $dst << 3 \n\t"
"MOV $dst, $dst >> 30" %}
ins_encode %{
__ fcmps($src1$$FloatRegister, $src2$$FloatRegister);
__ floating_cmp($dst$$Register);
%}
ins_pipe( floating_cmp );
%}
instruct cmpF0_reg(iRegI dst, regF src1, immF0 src2, flagsRegF fcc) %{
match(Set dst (CmpF3 src1 src2));
effect(KILL fcc);
ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
size(20);
// same number of instructions as code using conditional moves but
// doesn't kill integer condition register
format %{ "FCMPZs $dst,$src1,$src2 \n\t"
"VMRS $dst, FPSCR \n\t"
"OR $dst, $dst, 0x08000000 \n\t"
"EOR $dst, $dst, $dst << 3 \n\t"
"MOV $dst, $dst >> 30" %}
ins_encode %{
__ fcmpzs($src1$$FloatRegister);
__ floating_cmp($dst$$Register);
%}
ins_pipe( floating_cmp );
%}
instruct cmpD_reg(iRegI dst, regD src1, regD src2, flagsRegF fcc) %{
match(Set dst (CmpD3 src1 src2));
effect(KILL fcc);
ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
size(20);
// same number of instructions as code using conditional moves but
// doesn't kill integer condition register
format %{ "FCMPd $dst,$src1,$src2 \n\t"
"VMRS $dst, FPSCR \n\t"
"OR $dst, $dst, 0x08000000 \n\t"
"EOR $dst, $dst, $dst << 3 \n\t"
"MOV $dst, $dst >> 30" %}
ins_encode %{
__ fcmpd($src1$$FloatRegister, $src2$$FloatRegister);
__ floating_cmp($dst$$Register);
%}
ins_pipe( floating_cmp );
%}
instruct cmpD0_reg(iRegI dst, regD src1, immD0 src2, flagsRegF fcc) %{
match(Set dst (CmpD3 src1 src2));
effect(KILL fcc);
ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
size(20);
// same number of instructions as code using conditional moves but
// doesn't kill integer condition register
format %{ "FCMPZd $dst,$src1,$src2 \n\t"
"VMRS $dst, FPSCR \n\t"
"OR $dst, $dst, 0x08000000 \n\t"
"EOR $dst, $dst, $dst << 3 \n\t"
"MOV $dst, $dst >> 30" %}
ins_encode %{
__ fcmpzd($src1$$FloatRegister);
__ floating_cmp($dst$$Register);
%}
ins_pipe( floating_cmp );
%}
//----------Branches---------------------------------------------------------
// Jump
// (compare 'operand indIndex' and 'instruct addP_reg_reg' above)
// FIXME
instruct jumpXtnd(iRegX switch_val, iRegP tmp) %{
match(Jump switch_val);
effect(TEMP tmp);
ins_cost(350);
format %{ "ADD $tmp, $constanttablebase, $switch_val\n\t"
"LDR $tmp,[$tmp + $constantoffset]\n\t"
"BX $tmp" %}
size(20);
ins_encode %{
Register table_reg;
Register label_reg = $tmp$$Register;
if (constant_offset() == 0) {
table_reg = $constanttablebase;
__ ldr(label_reg, Address(table_reg, $switch_val$$Register));
} else {
table_reg = $tmp$$Register;
int offset = $constantoffset;
if (is_memoryP(offset)) {
__ add(table_reg, $constanttablebase, $switch_val$$Register);
__ ldr(label_reg, Address(table_reg, offset));
} else {
__ mov_slow(table_reg, $constantoffset);
__ add(table_reg, $constanttablebase, table_reg);
__ ldr(label_reg, Address(table_reg, $switch_val$$Register));
}
}
__ jump(label_reg); // ldr + b better than ldr to PC for branch predictor?
// __ ldr(PC, Address($table$$Register, $switch_val$$Register));
%}
ins_pipe(ialu_reg_reg);
%}
// // Direct Branch.
instruct branch(label labl) %{
match(Goto);
effect(USE labl);
size(4);
ins_cost(BRANCH_COST);
format %{ "B $labl" %}
ins_encode %{
__ b(*($labl$$label));
%}
ins_pipe(br);
%}
// Conditional Direct Branch
instruct branchCon(cmpOp cmp, flagsReg icc, label labl) %{
match(If cmp icc);
effect(USE labl);
size(4);
ins_cost(BRANCH_COST);
format %{ "B$cmp $icc,$labl" %}
ins_encode %{
__ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(br_cc);
%}
#ifdef ARM
instruct branchCon_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, label labl) %{
match(If cmp icc);
effect(USE labl);
predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
size(4);
ins_cost(BRANCH_COST);
format %{ "B$cmp $icc,$labl" %}
ins_encode %{
__ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(br_cc);
%}
#endif
instruct branchConU(cmpOpU cmp, flagsRegU icc, label labl) %{
match(If cmp icc);
effect(USE labl);
size(4);
ins_cost(BRANCH_COST);
format %{ "B$cmp $icc,$labl" %}
ins_encode %{
__ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(br_cc);
%}
instruct branchConP(cmpOpP cmp, flagsRegP pcc, label labl) %{
match(If cmp pcc);
effect(USE labl);
size(4);
ins_cost(BRANCH_COST);
format %{ "B$cmp $pcc,$labl" %}
ins_encode %{
__ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(br_cc);
%}
instruct branchConL_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, label labl) %{
match(If cmp xcc);
effect(USE labl);
predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
size(4);
ins_cost(BRANCH_COST);
format %{ "B$cmp $xcc,$labl" %}
ins_encode %{
__ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(br_cc);
%}
instruct branchConL_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, label labl) %{
match(If cmp xcc);
effect(USE labl);
predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
size(4);
ins_cost(BRANCH_COST);
format %{ "B$cmp $xcc,$labl" %}
ins_encode %{
__ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(br_cc);
%}
instruct branchConL_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, label labl) %{
match(If cmp xcc);
effect(USE labl);
predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le );
size(4);
ins_cost(BRANCH_COST);
format %{ "B$cmp $xcc,$labl" %}
ins_encode %{
__ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(br_cc);
%}
instruct branchConUL_LTGE(cmpOpUL cmp, flagsRegUL_LTGE xcc, label labl) %{
match(If cmp xcc);
effect(USE labl);
predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
size(4);
ins_cost(BRANCH_COST);
format %{ "B$cmp $xcc,$labl" %}
ins_encode %{
__ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(br_cc);
%}
instruct branchConUL_EQNE(cmpOpUL cmp, flagsRegUL_EQNE xcc, label labl) %{
match(If cmp xcc);
effect(USE labl);
predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);
size(4);
ins_cost(BRANCH_COST);
format %{ "B$cmp $xcc,$labl" %}
ins_encode %{
__ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(br_cc);
%}
instruct branchConUL_LEGT(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, label labl) %{
match(If cmp xcc);
effect(USE labl);
predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le);
size(4);
ins_cost(BRANCH_COST);
format %{ "B$cmp $xcc,$labl" %}
ins_encode %{
__ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(br_cc);
%}
instruct branchLoopEnd(cmpOp cmp, flagsReg icc, label labl) %{
match(CountedLoopEnd cmp icc);
effect(USE labl);
size(4);
ins_cost(BRANCH_COST);
format %{ "B$cmp $icc,$labl\t! Loop end" %}
ins_encode %{
__ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(br_cc);
%}
// instruct branchLoopEndU(cmpOpU cmp, flagsRegU icc, label labl) %{
// match(CountedLoopEnd cmp icc);
// ins_pipe(br_cc);
// %}
// ============================================================================
// Long Compare
//
// Currently we hold longs in 2 registers. Comparing such values efficiently
// is tricky. The flavor of compare used depends on whether we are testing
// for LT, LE, or EQ. For a simple LT test we can check just the sign bit.
// The GE test is the negated LT test. The LE test can be had by commuting
// the operands (yielding a GE test) and then negating; negate again for the
// GT test. The EQ test is done by ORcc'ing the high and low halves, and the
// NE test is negated from that.
// Due to a shortcoming in the ADLC, it mixes up expressions like:
// (foo (CmpI (CmpL X Y) 0)) and (bar (CmpI (CmpL X 0L) 0)). Note the
// difference between 'Y' and '0L'. The tree-matches for the CmpI sections
// are collapsed internally in the ADLC's dfa-gen code. The match for
// (CmpI (CmpL X Y) 0) is silently replaced with (CmpI (CmpL X 0L) 0) and the
// foo match ends up with the wrong leaf. One fix is to not match both
// reg-reg and reg-zero forms of long-compare. This is unfortunate because
// both forms beat the trinary form of long-compare and both are very useful
// on Intel which has so few registers.
// instruct branchCon_long(cmpOp cmp, flagsRegL xcc, label labl) %{
// match(If cmp xcc);
// ins_pipe(br_cc);
// %}
// Manifest a CmpL3 result in an integer register. Very painful.
// This is the test to avoid.
instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg ccr ) %{
match(Set dst (CmpL3 src1 src2) );
effect( KILL ccr );
ins_cost(6*DEFAULT_COST); // FIXME
size(32);
format %{
"CMP $src1.hi, $src2.hi\t\t! long\n"
"\tMOV.gt $dst, 1\n"
"\tmvn.lt $dst, 0\n"
"\tB.ne done\n"
"\tSUBS $dst, $src1.lo, $src2.lo\n"
"\tMOV.hi $dst, 1\n"
"\tmvn.lo $dst, 0\n"
"done:" %}
ins_encode %{
Label done;
__ cmp($src1$$Register->successor(), $src2$$Register->successor());
__ mov($dst$$Register, 1, gt);
__ mvn($dst$$Register, 0, lt);
__ b(done, ne);
__ subs($dst$$Register, $src1$$Register, $src2$$Register);
__ mov($dst$$Register, 1, hi);
__ mvn($dst$$Register, 0, lo);
__ bind(done);
%}
ins_pipe(cmpL_reg);
%}
// Conditional move
instruct cmovLL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegL dst, iRegL src) %{
match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
ins_cost(150);
size(8);
format %{ "MOV$cmp $dst.lo,$src.lo\t! long\n\t"
"MOV$cmp $dst,$src.hi" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovLL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegL dst, iRegL src) %{
match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
ins_cost(150);
size(8);
format %{ "MOV$cmp $dst.lo,$src.lo\t! long\n\t"
"MOV$cmp $dst,$src.hi" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovLL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegL dst, iRegL src) %{
match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
ins_cost(150);
size(8);
format %{ "MOV$cmp $dst.lo,$src.lo\t! long\n\t"
"MOV$cmp $dst,$src.hi" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovLL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegL dst, immL0 src) %{
match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
ins_cost(140);
size(8);
format %{ "MOV$cmp $dst.lo,0\t! long\n\t"
"MOV$cmp $dst,0" %}
ins_encode %{
__ mov($dst$$Register, 0, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovLL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegL dst, immL0 src) %{
match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
ins_cost(140);
size(8);
format %{ "MOV$cmp $dst.lo,0\t! long\n\t"
"MOV$cmp $dst,0" %}
ins_encode %{
__ mov($dst$$Register, 0, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovLL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegL dst, immL0 src) %{
match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
ins_cost(140);
size(8);
format %{ "MOV$cmp $dst.lo,0\t! long\n\t"
"MOV$cmp $dst,0" %}
ins_encode %{
__ mov($dst$$Register, 0, (AsmCondition)($cmp$$cmpcode));
__ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovIL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, iRegI src) %{
match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovIL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, iRegI src) %{
match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovIL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, iRegI src) %{
match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovIL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, immI16 src) %{
match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
ins_cost(140);
format %{ "MOVW$cmp $dst,$src" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovIL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, immI16 src) %{
match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
ins_cost(140);
format %{ "MOVW$cmp $dst,$src" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovIL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, immI16 src) %{
match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
ins_cost(140);
format %{ "MOVW$cmp $dst,$src" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovPL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegP dst, iRegP src) %{
match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovPL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegP dst, iRegP src) %{
match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovPL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegP dst, iRegP src) %{
match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
ins_cost(150);
size(4);
format %{ "MOV$cmp $dst,$src" %}
ins_encode %{
__ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_reg);
%}
instruct cmovPL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegP dst, immP0 src) %{
match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
ins_cost(140);
format %{ "MOVW$cmp $dst,$src" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovPL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegP dst, immP0 src) %{
match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
ins_cost(140);
format %{ "MOVW$cmp $dst,$src" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovPL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegP dst, immP0 src) %{
match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
ins_cost(140);
format %{ "MOVW$cmp $dst,$src" %}
ins_encode %{
__ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(ialu_imm);
%}
instruct cmovFL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, regF dst, regF src) %{
match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
ins_cost(150);
size(4);
format %{ "FCPYS$cmp $dst,$src" %}
ins_encode %{
__ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_float_move);
%}
instruct cmovFL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, regF dst, regF src) %{
match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
ins_cost(150);
size(4);
format %{ "FCPYS$cmp $dst,$src" %}
ins_encode %{
__ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_float_move);
%}
instruct cmovFL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, regF dst, regF src) %{
match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
ins_cost(150);
size(4);
format %{ "FCPYS$cmp $dst,$src" %}
ins_encode %{
__ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_float_move);
%}
instruct cmovDL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, regD dst, regD src) %{
match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
ins_cost(150);
size(4);
format %{ "FCPYD$cmp $dst,$src" %}
ins_encode %{
__ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_float_move);
%}
instruct cmovDL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, regD dst, regD src) %{
match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
ins_cost(150);
size(4);
format %{ "FCPYD$cmp $dst,$src" %}
ins_encode %{
__ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_float_move);
%}
instruct cmovDL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, regD dst, regD src) %{
match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src)));
predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
ins_cost(150);
size(4);
format %{ "FCPYD$cmp $dst,$src" %}
ins_encode %{
__ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
%}
ins_pipe(int_conditional_float_move);
%}
// ============================================================================
// Safepoint Instruction
// rather than KILL R12, it would be better to use any reg as
// TEMP. Can't do that at this point because it crashes the compiler
instruct safePoint_poll(iRegP poll, R12RegI tmp, flagsReg icc) %{
match(SafePoint poll);
effect(USE poll, KILL tmp, KILL icc);
size(4);
format %{ "LDR $tmp,[$poll]\t! Safepoint: poll for GC" %}
ins_encode %{
__ relocate(relocInfo::poll_type);
__ ldr($tmp$$Register, Address($poll$$Register));
%}
ins_pipe(loadPollP);
%}
// ============================================================================
// Call Instructions
// Call Java Static Instruction
instruct CallStaticJavaDirect( method meth ) %{
match(CallStaticJava);
predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke());
effect(USE meth);
ins_cost(CALL_COST);
format %{ "CALL,static ==> " %}
ins_encode( Java_Static_Call( meth ), call_epilog );
ins_pipe(simple_call);
%}
// Call Java Static Instruction (method handle version)
instruct CallStaticJavaHandle( method meth ) %{
match(CallStaticJava);
predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke());
effect(USE meth);
// FP is saved by all callees (for interpreter stack correction).
// We use it here for a similar purpose, in {preserve,restore}_FP.
ins_cost(CALL_COST);
format %{ "CALL,static/MethodHandle ==> " %}
ins_encode( preserve_SP, Java_Static_Call( meth ), restore_SP, call_epilog );
ins_pipe(simple_call);
%}
// Call Java Dynamic Instruction
instruct CallDynamicJavaDirect( method meth ) %{
match(CallDynamicJava);
effect(USE meth);
ins_cost(CALL_COST);
format %{ "MOV_OOP (empty),R_R8\n\t"
"CALL,dynamic ; NOP ==> " %}
ins_encode( Java_Dynamic_Call( meth ), call_epilog );
ins_pipe(call);
%}
// Call Runtime Instruction
instruct CallRuntimeDirect(method meth) %{
match(CallRuntime);
effect(USE meth);
ins_cost(CALL_COST);
format %{ "CALL,runtime" %}
ins_encode( Java_To_Runtime( meth ),
call_epilog );
ins_pipe(simple_call);
%}
// Call runtime without safepoint - same as CallRuntime
instruct CallLeafDirect(method meth) %{
match(CallLeaf);
effect(USE meth);
ins_cost(CALL_COST);
format %{ "CALL,runtime leaf" %}
// TODO: ned save_last_PC here?
ins_encode( Java_To_Runtime( meth ),
call_epilog );
ins_pipe(simple_call);
%}
// Call runtime without safepoint - same as CallLeaf
instruct CallLeafNoFPDirect(method meth) %{
match(CallLeafNoFP);
effect(USE meth);
ins_cost(CALL_COST);
format %{ "CALL,runtime leaf nofp" %}
// TODO: ned save_last_PC here?
ins_encode( Java_To_Runtime( meth ),
call_epilog );
ins_pipe(simple_call);
%}
// Tail Call; Jump from runtime stub to Java code.
// Also known as an 'interprocedural jump'.
// Target of jump will eventually return to caller.
// TailJump below removes the return address.
instruct TailCalljmpInd(IPRegP jump_target, inline_cache_regP method_oop) %{
match(TailCall jump_target method_oop );
ins_cost(CALL_COST);
format %{ "MOV Rexception_pc, LR\n\t"
"jump $jump_target \t! $method_oop holds method oop" %}
ins_encode %{
__ mov(Rexception_pc, LR); // this is used only to call
// StubRoutines::forward_exception_entry()
// which expects PC of exception in
// R5. FIXME?
__ jump($jump_target$$Register);
%}
ins_pipe(tail_call);
%}
// Return Instruction
instruct Ret() %{
match(Return);
format %{ "ret LR" %}
ins_encode %{
__ ret(LR);
%}
ins_pipe(br);
%}
// Tail Jump; remove the return address; jump to target.
// TailCall above leaves the return address around.
// TailJump is used in only one place, the rethrow_Java stub (fancy_jump=2).
// ex_oop (Exception Oop) is needed in %o0 at the jump. As there would be a
// "restore" before this instruction (in Epilogue), we need to materialize it
// in %i0.
instruct tailjmpInd(IPRegP jump_target, RExceptionRegP ex_oop) %{
match( TailJump jump_target ex_oop );
ins_cost(CALL_COST);
format %{ "MOV Rexception_pc, LR\n\t"
"jump $jump_target \t! $ex_oop holds exc. oop" %}
ins_encode %{
__ mov(Rexception_pc, LR);
__ jump($jump_target$$Register);
%}
ins_pipe(tail_call);
%}
// Create exception oop: created by stack-crawling runtime code.
// Created exception is now available to this handler, and is setup
// just prior to jumping to this handler. No code emitted.
instruct CreateException( RExceptionRegP ex_oop )
%{
match(Set ex_oop (CreateEx));
ins_cost(0);
size(0);
// use the following format syntax
format %{ "! exception oop is in Rexception_obj; no code emitted" %}
ins_encode();
ins_pipe(empty);
%}
// Rethrow exception:
// The exception oop will come in the first argument position.
// Then JUMP (not call) to the rethrow stub code.
instruct RethrowException()
%{
match(Rethrow);
ins_cost(CALL_COST);
// use the following format syntax
format %{ "b rethrow_stub" %}
ins_encode %{
Register scratch = R1_tmp;
assert_different_registers(scratch, c_rarg0, LR);
__ jump(OptoRuntime::rethrow_stub(), relocInfo::runtime_call_type, scratch);
%}
ins_pipe(tail_call);
%}
// Die now
instruct ShouldNotReachHere( )
%{
match(Halt);
ins_cost(CALL_COST);
size(4);
// Use the following format syntax
format %{ "ShouldNotReachHere" %}
ins_encode %{
__ udf(0xdead);
%}
ins_pipe(tail_call);
%}
// ============================================================================
// The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass
// array for an instance of the superklass. Set a hidden internal cache on a
// hit (cache is checked with exposed code in gen_subtype_check()). Return
// not zero for a miss or zero for a hit. The encoding ALSO sets flags.
instruct partialSubtypeCheck( R0RegP index, R1RegP sub, R2RegP super, flagsRegP pcc, LRRegP lr ) %{
match(Set index (PartialSubtypeCheck sub super));
effect( KILL pcc, KILL lr );
ins_cost(DEFAULT_COST*10);
format %{ "CALL PartialSubtypeCheck" %}
ins_encode %{
__ call(StubRoutines::Arm::partial_subtype_check(), relocInfo::runtime_call_type);
%}
ins_pipe(partial_subtype_check_pipe);
%}
/* instruct partialSubtypeCheck_vs_zero( flagsRegP pcc, o1RegP sub, o2RegP super, immP0 zero, o0RegP idx, o7RegP o7 ) %{ */
/* match(Set pcc (CmpP (PartialSubtypeCheck sub super) zero)); */
/* ins_pipe(partial_subtype_check_pipe); */
/* %} */
// ============================================================================
// inlined locking and unlocking
instruct cmpFastLock(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2, iRegP scratch )
%{
match(Set pcc (FastLock object box));
predicate(!(UseBiasedLocking && !UseOptoBiasInlining));
effect(TEMP scratch, TEMP scratch2);
ins_cost(DEFAULT_COST*3);
format %{ "FASTLOCK $object, $box; KILL $scratch, $scratch2" %}
ins_encode %{
__ fast_lock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register);
%}
ins_pipe(long_memory_op);
%}
instruct cmpFastLock_noBiasInline(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2,
iRegP scratch, iRegP scratch3) %{
match(Set pcc (FastLock object box));
predicate(UseBiasedLocking && !UseOptoBiasInlining);
effect(TEMP scratch, TEMP scratch2, TEMP scratch3);
ins_cost(DEFAULT_COST*5);
format %{ "FASTLOCK $object, $box; KILL $scratch, $scratch2, $scratch3" %}
ins_encode %{
__ fast_lock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register, $scratch3$$Register);
%}
ins_pipe(long_memory_op);
%}
instruct cmpFastUnlock(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2, iRegP scratch ) %{
match(Set pcc (FastUnlock object box));
effect(TEMP scratch, TEMP scratch2);
ins_cost(100);
format %{ "FASTUNLOCK $object, $box; KILL $scratch, $scratch2" %}
ins_encode %{
__ fast_unlock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register);
%}
ins_pipe(long_memory_op);
%}
// Count and Base registers are fixed because the allocator cannot
// kill unknown registers. The encodings are generic.
instruct clear_array(iRegX cnt, iRegP base, iRegI temp, iRegX zero, Universe dummy, flagsReg cpsr) %{
match(Set dummy (ClearArray cnt base));
effect(TEMP temp, TEMP zero, KILL cpsr);
ins_cost(300);
format %{ "MOV $zero,0\n"
" MOV $temp,$cnt\n"
"loop: SUBS $temp,$temp,4\t! Count down a dword of bytes\n"
" STR.ge $zero,[$base+$temp]\t! delay slot"
" B.gt loop\t\t! Clearing loop\n" %}
ins_encode %{
__ mov($zero$$Register, 0);
__ mov($temp$$Register, $cnt$$Register);
Label(loop);
__ bind(loop);
__ subs($temp$$Register, $temp$$Register, 4);
__ str($zero$$Register, Address($base$$Register, $temp$$Register), ge);
__ b(loop, gt);
%}
ins_pipe(long_memory_op);
%}
#ifdef XXX
// FIXME: Why R0/R1/R2/R3?
instruct string_compare(R0RegP str1, R1RegP str2, R2RegI cnt1, R3RegI cnt2, iRegI result,
iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
predicate(!CompactStrings);
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, TEMP tmp1, TEMP tmp2);
ins_cost(300);
format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result // TEMP $tmp1, $tmp2" %}
ins_encode( enc_String_Compare(str1, str2, cnt1, cnt2, result, tmp1, tmp2) );
ins_pipe(long_memory_op);
%}
// FIXME: Why R0/R1/R2?
instruct string_equals(R0RegP str1, R1RegP str2, R2RegI cnt, iRegI result, iRegI tmp1, iRegI tmp2,
flagsReg ccr) %{
predicate(!CompactStrings);
match(Set result (StrEquals (Binary str1 str2) cnt));
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp1, TEMP tmp2, TEMP result, KILL ccr);
ins_cost(300);
format %{ "String Equals $str1,$str2,$cnt -> $result // TEMP $tmp1, $tmp2" %}
ins_encode( enc_String_Equals(str1, str2, cnt, result, tmp1, tmp2) );
ins_pipe(long_memory_op);
%}
// FIXME: Why R0/R1?
instruct array_equals(R0RegP ary1, R1RegP ary2, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI result,
flagsReg ccr) %{
predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
match(Set result (AryEq ary1 ary2));
effect(USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP result, KILL ccr);
ins_cost(300);
format %{ "Array Equals $ary1,$ary2 -> $result // TEMP $tmp1,$tmp2,$tmp3" %}
ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, result));
ins_pipe(long_memory_op);
%}
#endif
//---------- Zeros Count Instructions ------------------------------------------
instruct countLeadingZerosI(iRegI dst, iRegI src) %{
match(Set dst (CountLeadingZerosI src));
size(4);
format %{ "CLZ_32 $dst,$src" %}
ins_encode %{
__ clz_32($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_reg);
%}
instruct countLeadingZerosL(iRegI dst, iRegL src, iRegI tmp, flagsReg ccr) %{
match(Set dst (CountLeadingZerosL src));
effect(TEMP tmp, TEMP dst, KILL ccr);
size(16);
format %{ "CLZ $dst,$src.hi\n\t"
"TEQ $dst,32\n\t"
"CLZ.eq $tmp,$src.lo\n\t"
"ADD.eq $dst, $dst, $tmp\n\t" %}
ins_encode %{
__ clz($dst$$Register, $src$$Register->successor());
__ teq($dst$$Register, 32);
__ clz($tmp$$Register, $src$$Register, eq);
__ add($dst$$Register, $dst$$Register, $tmp$$Register, eq);
%}
ins_pipe(ialu_reg);
%}
instruct countTrailingZerosI(iRegI dst, iRegI src, iRegI tmp) %{
match(Set dst (CountTrailingZerosI src));
effect(TEMP tmp);
size(8);
format %{ "RBIT_32 $tmp, $src\n\t"
"CLZ_32 $dst,$tmp" %}
ins_encode %{
__ rbit_32($tmp$$Register, $src$$Register);
__ clz_32($dst$$Register, $tmp$$Register);
%}
ins_pipe(ialu_reg);
%}
instruct countTrailingZerosL(iRegI dst, iRegL src, iRegI tmp, flagsReg ccr) %{
match(Set dst (CountTrailingZerosL src));
effect(TEMP tmp, TEMP dst, KILL ccr);
size(24);
format %{ "RBIT $tmp,$src.lo\n\t"
"CLZ $dst,$tmp\n\t"
"TEQ $dst,32\n\t"
"RBIT $tmp,$src.hi\n\t"
"CLZ.eq $tmp,$tmp\n\t"
"ADD.eq $dst,$dst,$tmp\n\t" %}
ins_encode %{
__ rbit($tmp$$Register, $src$$Register);
__ clz($dst$$Register, $tmp$$Register);
__ teq($dst$$Register, 32);
__ rbit($tmp$$Register, $src$$Register->successor());
__ clz($tmp$$Register, $tmp$$Register, eq);
__ add($dst$$Register, $dst$$Register, $tmp$$Register, eq);
%}
ins_pipe(ialu_reg);
%}
//---------- Population Count Instructions -------------------------------------
instruct popCountI(iRegI dst, iRegI src, regD_low tmp) %{
predicate(UsePopCountInstruction);
match(Set dst (PopCountI src));
effect(TEMP tmp);
format %{ "FMSR $tmp,$src\n\t"
"VCNT.8 $tmp,$tmp\n\t"
"VPADDL.U8 $tmp,$tmp\n\t"
"VPADDL.U16 $tmp,$tmp\n\t"
"FMRS $dst,$tmp" %}
size(20);
ins_encode %{
__ fmsr($tmp$$FloatRegister, $src$$Register);
__ vcnt($tmp$$FloatRegister, $tmp$$FloatRegister);
__ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 8, 0);
__ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 16, 0);
__ fmrs($dst$$Register, $tmp$$FloatRegister);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Note: Long.bitCount(long) returns an int.
instruct popCountL(iRegI dst, iRegL src, regD_low tmp) %{
predicate(UsePopCountInstruction);
match(Set dst (PopCountL src));
effect(TEMP tmp);
format %{ "FMDRR $tmp,$src.lo,$src.hi\n\t"
"VCNT.8 $tmp,$tmp\n\t"
"VPADDL.U8 $tmp,$tmp\n\t"
"VPADDL.U16 $tmp,$tmp\n\t"
"VPADDL.U32 $tmp,$tmp\n\t"
"FMRS $dst,$tmp" %}
size(32);
ins_encode %{
__ fmdrr($tmp$$FloatRegister, $src$$Register, $src$$Register->successor());
__ vcnt($tmp$$FloatRegister, $tmp$$FloatRegister);
__ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 8, 0);
__ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 16, 0);
__ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 32, 0);
__ fmrs($dst$$Register, $tmp$$FloatRegister);
%}
ins_pipe(ialu_reg);
%}
// ============================================================================
//------------Bytes reverse--------------------------------------------------
instruct bytes_reverse_int(iRegI dst, iRegI src) %{
match(Set dst (ReverseBytesI src));
size(4);
format %{ "REV32 $dst,$src" %}
ins_encode %{
__ rev($dst$$Register, $src$$Register);
%}
ins_pipe( iload_mem ); // FIXME
%}
instruct bytes_reverse_long(iRegL dst, iRegL src) %{
match(Set dst (ReverseBytesL src));
effect(TEMP dst);
size(8);
format %{ "REV $dst.lo,$src.lo\n\t"
"REV $dst.hi,$src.hi" %}
ins_encode %{
__ rev($dst$$Register, $src$$Register->successor());
__ rev($dst$$Register->successor(), $src$$Register);
%}
ins_pipe( iload_mem ); // FIXME
%}
instruct bytes_reverse_unsigned_short(iRegI dst, iRegI src) %{
match(Set dst (ReverseBytesUS src));
size(4);
format %{ "REV16 $dst,$src" %}
ins_encode %{
__ rev16($dst$$Register, $src$$Register);
%}
ins_pipe( iload_mem ); // FIXME
%}
instruct bytes_reverse_short(iRegI dst, iRegI src) %{
match(Set dst (ReverseBytesS src));
size(4);
format %{ "REVSH $dst,$src" %}
ins_encode %{
__ revsh($dst$$Register, $src$$Register);
%}
ins_pipe( iload_mem ); // FIXME
%}
// ====================VECTOR INSTRUCTIONS=====================================
// Load Aligned Packed values into a Double Register
instruct loadV8(vecD dst, memoryD mem) %{
predicate(n->as_LoadVector()->memory_size() == 8);
match(Set dst (LoadVector mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "FLDD $mem,$dst\t! load vector (8 bytes)" %}
ins_encode %{
__ ldr_double($dst$$FloatRegister, $mem$$Address);
%}
ins_pipe(floadD_mem);
%}
// Load Aligned Packed values into a Double Register Pair
instruct loadV16(vecX dst, memoryvld mem) %{
predicate(n->as_LoadVector()->memory_size() == 16);
match(Set dst (LoadVector mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "VLD1 $mem,$dst.Q\t! load vector (16 bytes)" %}
ins_encode %{
__ vld1($dst$$FloatRegister, $mem$$Address, MacroAssembler::VELEM_SIZE_16, 128);
%}
ins_pipe(floadD_mem); // FIXME
%}
// Store Vector in Double register to memory
instruct storeV8(memoryD mem, vecD src) %{
predicate(n->as_StoreVector()->memory_size() == 8);
match(Set mem (StoreVector mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "FSTD $src,$mem\t! store vector (8 bytes)" %}
ins_encode %{
__ str_double($src$$FloatRegister, $mem$$Address);
%}
ins_pipe(fstoreD_mem_reg);
%}
// Store Vector in Double Register Pair to memory
instruct storeV16(memoryvld mem, vecX src) %{
predicate(n->as_StoreVector()->memory_size() == 16);
match(Set mem (StoreVector mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "VST1 $src,$mem\t! store vector (16 bytes)" %}
ins_encode %{
__ vst1($src$$FloatRegister, $mem$$Address, MacroAssembler::VELEM_SIZE_16, 128);
%}
ins_pipe(fstoreD_mem_reg); // FIXME
%}
// Replicate scalar to packed byte values in Double register
instruct Repl8B_reg(vecD dst, iRegI src, iRegI tmp) %{
predicate(n->as_Vector()->length() == 8);
match(Set dst (ReplicateB src));
ins_cost(DEFAULT_COST*4);
effect(TEMP tmp);
size(16);
// FIXME: could use PKH instruction instead?
format %{ "LSL $tmp, $src, 24 \n\t"
"OR $tmp, $tmp, ($tmp >> 8) \n\t"
"OR $tmp, $tmp, ($tmp >> 16) \n\t"
"FMDRR $dst,$tmp,$tmp\t" %}
ins_encode %{
__ mov($tmp$$Register, AsmOperand($src$$Register, lsl, 24));
__ orr($tmp$$Register, $tmp$$Register, AsmOperand($tmp$$Register, lsr, 8));
__ orr($tmp$$Register, $tmp$$Register, AsmOperand($tmp$$Register, lsr, 16));
__ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar to packed byte values in Double register
instruct Repl8B_reg_simd(vecD dst, iRegI src) %{
predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
match(Set dst (ReplicateB src));
size(4);
format %{ "VDUP.8 $dst,$src\t" %}
ins_encode %{
bool quad = false;
__ vdupI($dst$$FloatRegister, $src$$Register,
MacroAssembler::VELEM_SIZE_8, quad);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar to packed byte values in Double register pair
instruct Repl16B_reg(vecX dst, iRegI src) %{
predicate(n->as_Vector()->length_in_bytes() == 16);
match(Set dst (ReplicateB src));
size(4);
format %{ "VDUP.8 $dst.Q,$src\t" %}
ins_encode %{
bool quad = true;
__ vdupI($dst$$FloatRegister, $src$$Register,
MacroAssembler::VELEM_SIZE_8, quad);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar constant to packed byte values in Double register
instruct Repl8B_immI(vecD dst, immI src, iRegI tmp) %{
predicate(n->as_Vector()->length() == 8);
match(Set dst (ReplicateB src));
ins_cost(DEFAULT_COST*2);
effect(TEMP tmp);
size(12);
format %{ "MOV $tmp, Repl4($src))\n\t"
"FMDRR $dst,$tmp,$tmp\t" %}
ins_encode( LdReplImmI(src, dst, tmp, (4), (1)) );
ins_pipe(loadConFD); // FIXME
%}
// Replicate scalar constant to packed byte values in Double register
// TODO: support negative constants with MVNI?
instruct Repl8B_immU8(vecD dst, immU8 src) %{
predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
match(Set dst (ReplicateB src));
size(4);
format %{ "VMOV.U8 $dst,$src" %}
ins_encode %{
bool quad = false;
__ vmovI($dst$$FloatRegister, $src$$constant,
MacroAssembler::VELEM_SIZE_8, quad);
%}
ins_pipe(loadConFD); // FIXME
%}
// Replicate scalar constant to packed byte values in Double register pair
instruct Repl16B_immU8(vecX dst, immU8 src) %{
predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
match(Set dst (ReplicateB src));
size(4);
format %{ "VMOV.U8 $dst.Q,$src" %}
ins_encode %{
bool quad = true;
__ vmovI($dst$$FloatRegister, $src$$constant,
MacroAssembler::VELEM_SIZE_8, quad);
%}
ins_pipe(loadConFD); // FIXME
%}
// Replicate scalar to packed short/char values into Double register
instruct Repl4S_reg(vecD dst, iRegI src, iRegI tmp) %{
predicate(n->as_Vector()->length() == 4);
match(Set dst (ReplicateS src));
ins_cost(DEFAULT_COST*3);
effect(TEMP tmp);
size(12);
// FIXME: could use PKH instruction instead?
format %{ "LSL $tmp, $src, 16 \n\t"
"OR $tmp, $tmp, ($tmp >> 16) \n\t"
"FMDRR $dst,$tmp,$tmp\t" %}
ins_encode %{
__ mov($tmp$$Register, AsmOperand($src$$Register, lsl, 16));
__ orr($tmp$$Register, $tmp$$Register, AsmOperand($tmp$$Register, lsr, 16));
__ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar to packed byte values in Double register
instruct Repl4S_reg_simd(vecD dst, iRegI src) %{
predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
match(Set dst (ReplicateS src));
size(4);
format %{ "VDUP.16 $dst,$src\t" %}
ins_encode %{
bool quad = false;
__ vdupI($dst$$FloatRegister, $src$$Register,
MacroAssembler::VELEM_SIZE_16, quad);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar to packed byte values in Double register pair
instruct Repl8S_reg(vecX dst, iRegI src) %{
predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
match(Set dst (ReplicateS src));
size(4);
format %{ "VDUP.16 $dst.Q,$src\t" %}
ins_encode %{
bool quad = true;
__ vdupI($dst$$FloatRegister, $src$$Register,
MacroAssembler::VELEM_SIZE_16, quad);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar constant to packed short/char values in Double register
instruct Repl4S_immI(vecD dst, immI src, iRegP tmp) %{
predicate(n->as_Vector()->length() == 4);
match(Set dst (ReplicateS src));
effect(TEMP tmp);
size(12);
ins_cost(DEFAULT_COST*4); // FIXME
format %{ "MOV $tmp, Repl2($src))\n\t"
"FMDRR $dst,$tmp,$tmp\t" %}
ins_encode( LdReplImmI(src, dst, tmp, (2), (2)) );
ins_pipe(loadConFD); // FIXME
%}
// Replicate scalar constant to packed byte values in Double register
instruct Repl4S_immU8(vecD dst, immU8 src) %{
predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
match(Set dst (ReplicateS src));
size(4);
format %{ "VMOV.U16 $dst,$src" %}
ins_encode %{
bool quad = false;
__ vmovI($dst$$FloatRegister, $src$$constant,
MacroAssembler::VELEM_SIZE_16, quad);
%}
ins_pipe(loadConFD); // FIXME
%}
// Replicate scalar constant to packed byte values in Double register pair
instruct Repl8S_immU8(vecX dst, immU8 src) %{
predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
match(Set dst (ReplicateS src));
size(4);
format %{ "VMOV.U16 $dst.Q,$src" %}
ins_encode %{
bool quad = true;
__ vmovI($dst$$FloatRegister, $src$$constant,
MacroAssembler::VELEM_SIZE_16, quad);
%}
ins_pipe(loadConFD); // FIXME
%}
// Replicate scalar to packed int values in Double register
instruct Repl2I_reg(vecD dst, iRegI src) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateI src));
size(4);
format %{ "FMDRR $dst,$src,$src\t" %}
ins_encode %{
__ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar to packed int values in Double register pair
instruct Repl4I_reg(vecX dst, iRegI src) %{
predicate(n->as_Vector()->length() == 4);
match(Set dst (ReplicateI src));
ins_cost(DEFAULT_COST*2);
size(8);
format %{ "FMDRR $dst.lo,$src,$src\n\t"
"FMDRR $dst.hi,$src,$src" %}
ins_encode %{
__ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register);
__ fmdrr($dst$$FloatRegister->successor()->successor(),
$src$$Register, $src$$Register);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar to packed int values in Double register
instruct Repl2I_reg_simd(vecD dst, iRegI src) %{
predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
match(Set dst (ReplicateI src));
size(4);
format %{ "VDUP.32 $dst.D,$src\t" %}
ins_encode %{
bool quad = false;
__ vdupI($dst$$FloatRegister, $src$$Register,
MacroAssembler::VELEM_SIZE_32, quad);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar to packed int values in Double register pair
instruct Repl4I_reg_simd(vecX dst, iRegI src) %{
predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
match(Set dst (ReplicateI src));
size(4);
format %{ "VDUP.32 $dst.Q,$src\t" %}
ins_encode %{
bool quad = true;
__ vdupI($dst$$FloatRegister, $src$$Register,
MacroAssembler::VELEM_SIZE_32, quad);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar zero constant to packed int values in Double register
instruct Repl2I_immI(vecD dst, immI src, iRegI tmp) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateI src));
effect(TEMP tmp);
size(12);
ins_cost(DEFAULT_COST*4); // FIXME
format %{ "MOV $tmp, Repl1($src))\n\t"
"FMDRR $dst,$tmp,$tmp\t" %}
ins_encode( LdReplImmI(src, dst, tmp, (1), (4)) );
ins_pipe(loadConFD); // FIXME
%}
// Replicate scalar constant to packed byte values in Double register
instruct Repl2I_immU8(vecD dst, immU8 src) %{
predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
match(Set dst (ReplicateI src));
size(4);
format %{ "VMOV.I32 $dst.D,$src" %}
ins_encode %{
bool quad = false;
__ vmovI($dst$$FloatRegister, $src$$constant,
MacroAssembler::VELEM_SIZE_32, quad);
%}
ins_pipe(loadConFD); // FIXME
%}
// Replicate scalar constant to packed byte values in Double register pair
instruct Repl4I_immU8(vecX dst, immU8 src) %{
predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
match(Set dst (ReplicateI src));
size(4);
format %{ "VMOV.I32 $dst.Q,$src" %}
ins_encode %{
bool quad = true;
__ vmovI($dst$$FloatRegister, $src$$constant,
MacroAssembler::VELEM_SIZE_32, quad);
%}
ins_pipe(loadConFD); // FIXME
%}
// Replicate scalar to packed byte values in Double register pair
instruct Repl2L_reg(vecX dst, iRegL src) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateL src));
size(8);
ins_cost(DEFAULT_COST*2); // FIXME
format %{ "FMDRR $dst.D,$src.lo,$src.hi\t\n"
"FMDRR $dst.D.next,$src.lo,$src.hi" %}
ins_encode %{
__ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register->successor());
__ fmdrr($dst$$FloatRegister->successor()->successor(),
$src$$Register, $src$$Register->successor());
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar to packed float values in Double register
instruct Repl2F_regI(vecD dst, iRegI src) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateF src));
size(4);
format %{ "FMDRR $dst.D,$src,$src\t" %}
ins_encode %{
__ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar to packed float values in Double register
instruct Repl2F_reg_vfp(vecD dst, regF src) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateF src));
size(4*2);
ins_cost(DEFAULT_COST*2); // FIXME
expand %{
iRegI tmp;
MoveF2I_reg_reg(tmp, src);
Repl2F_regI(dst,tmp);
%}
%}
// Replicate scalar to packed float values in Double register
instruct Repl2F_reg_simd(vecD dst, regF src) %{
predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
match(Set dst (ReplicateF src));
size(4);
ins_cost(DEFAULT_COST); // FIXME
format %{ "VDUP.32 $dst.D,$src.D\t" %}
ins_encode %{
bool quad = false;
__ vdupF($dst$$FloatRegister, $src$$FloatRegister, quad);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar to packed float values in Double register pair
instruct Repl4F_reg(vecX dst, regF src, iRegI tmp) %{
predicate(n->as_Vector()->length() == 4);
match(Set dst (ReplicateF src));
effect(TEMP tmp);
size(4*3);
ins_cost(DEFAULT_COST*3); // FIXME
format %{ "FMRS $tmp,$src\n\t"
"FMDRR $dst.D,$tmp,$tmp\n\t"
"FMDRR $dst.D.next,$tmp,$tmp\t" %}
ins_encode %{
__ fmrs($tmp$$Register, $src$$FloatRegister);
__ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
__ fmdrr($dst$$FloatRegister->successor()->successor(),
$tmp$$Register, $tmp$$Register);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar to packed float values in Double register pair
instruct Repl4F_reg_simd(vecX dst, regF src) %{
predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
match(Set dst (ReplicateF src));
size(4);
ins_cost(DEFAULT_COST); // FIXME
format %{ "VDUP.32 $dst.Q,$src.D\t" %}
ins_encode %{
bool quad = true;
__ vdupF($dst$$FloatRegister, $src$$FloatRegister, quad);
%}
ins_pipe(ialu_reg); // FIXME
%}
// Replicate scalar zero constant to packed float values in Double register
instruct Repl2F_immI(vecD dst, immF src, iRegI tmp) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateF src));
effect(TEMP tmp);
size(12);
ins_cost(DEFAULT_COST*4); // FIXME
format %{ "MOV $tmp, Repl1($src))\n\t"
"FMDRR $dst,$tmp,$tmp\t" %}
ins_encode( LdReplImmF(src, dst, tmp) );
ins_pipe(loadConFD); // FIXME
%}
// Replicate scalar to packed double float values in Double register pair
instruct Repl2D_reg(vecX dst, regD src) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateD src));
size(4*2);
ins_cost(DEFAULT_COST*2); // FIXME
format %{ "FCPYD $dst.D.a,$src\n\t"
"FCPYD $dst.D.b,$src\t" %}
ins_encode %{
FloatRegister dsta = $dst$$FloatRegister;
FloatRegister src = $src$$FloatRegister;
__ fcpyd(dsta, src);
FloatRegister dstb = dsta->successor()->successor();
__ fcpyd(dstb, src);
%}
ins_pipe(ialu_reg); // FIXME
%}
// ====================VECTOR ARITHMETIC=======================================
// --------------------------------- ADD --------------------------------------
// Bytes vector add
instruct vadd8B_reg(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 8);
match(Set dst (AddVB src1 src2));
format %{ "VADD.I8 $dst,$src1,$src2\t! add packed8B" %}
size(4);
ins_encode %{
bool quad = false;
__ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_8, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
instruct vadd16B_reg(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 16);
match(Set dst (AddVB src1 src2));
size(4);
format %{ "VADD.I8 $dst.Q,$src1.Q,$src2.Q\t! add packed16B" %}
ins_encode %{
bool quad = true;
__ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_8, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
// Shorts/Chars vector add
instruct vadd4S_reg(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 4);
match(Set dst (AddVS src1 src2));
size(4);
format %{ "VADD.I16 $dst,$src1,$src2\t! add packed4S" %}
ins_encode %{
bool quad = false;
__ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_16, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
instruct vadd8S_reg(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 8);
match(Set dst (AddVS src1 src2));
size(4);
format %{ "VADD.I16 $dst.Q,$src1.Q,$src2.Q\t! add packed8S" %}
ins_encode %{
bool quad = true;
__ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_16, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
// Integers vector add
instruct vadd2I_reg(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (AddVI src1 src2));
size(4);
format %{ "VADD.I32 $dst.D,$src1.D,$src2.D\t! add packed2I" %}
ins_encode %{
bool quad = false;
__ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_32, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
instruct vadd4I_reg(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 4);
match(Set dst (AddVI src1 src2));
size(4);
format %{ "VADD.I32 $dst.Q,$src1.Q,$src2.Q\t! add packed4I" %}
ins_encode %{
bool quad = true;
__ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_32, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
// Longs vector add
instruct vadd2L_reg(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (AddVL src1 src2));
size(4);
format %{ "VADD.I64 $dst.Q,$src1.Q,$src2.Q\t! add packed2L" %}
ins_encode %{
bool quad = true;
__ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_64, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
// Floats vector add
instruct vadd2F_reg(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant());
match(Set dst (AddVF src1 src2));
size(4);
format %{ "VADD.F32 $dst,$src1,$src2\t! add packed2F" %}
ins_encode %{
bool quad = false;
__ vaddF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VFA_SIZE_F32, quad);
%}
ins_pipe( faddD_reg_reg ); // FIXME
%}
instruct vadd2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 2 && !VM_Version::simd_math_is_compliant());
match(Set dst (AddVF src1 src2));
ins_cost(DEFAULT_COST*2); // FIXME
size(4*2);
format %{ "FADDS $dst.a,$src1.a,$src2.a\n\t"
"FADDS $dst.b,$src1.b,$src2.b" %}
ins_encode %{
__ add_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
__ add_float($dst$$FloatRegister->successor(),
$src1$$FloatRegister->successor(),
$src2$$FloatRegister->successor());
%}
ins_pipe(faddF_reg_reg); // FIXME
%}
instruct vadd4F_reg_simd(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 4 && VM_Version::simd_math_is_compliant());
match(Set dst (AddVF src1 src2));
size(4);
format %{ "VADD.F32 $dst.Q,$src1.Q,$src2.Q\t! add packed4F" %}
ins_encode %{
bool quad = true;
__ vaddF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VFA_SIZE_F32, quad);
%}
ins_pipe( faddD_reg_reg ); // FIXME
%}
instruct vadd4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 4 && !VM_Version::simd_math_is_compliant());
match(Set dst (AddVF src1 src2));
size(4*4);
ins_cost(DEFAULT_COST*4); // FIXME
format %{ "FADDS $dst.a,$src1.a,$src2.a\n\t"
"FADDS $dst.b,$src1.b,$src2.b\n\t"
"FADDS $dst.c,$src1.c,$src2.c\n\t"
"FADDS $dst.d,$src1.d,$src2.d" %}
ins_encode %{
FloatRegister dsta = $dst$$FloatRegister;
FloatRegister src1a = $src1$$FloatRegister;
FloatRegister src2a = $src2$$FloatRegister;
__ add_float(dsta, src1a, src2a);
FloatRegister dstb = dsta->successor();
FloatRegister src1b = src1a->successor();
FloatRegister src2b = src2a->successor();
__ add_float(dstb, src1b, src2b);
FloatRegister dstc = dstb->successor();
FloatRegister src1c = src1b->successor();
FloatRegister src2c = src2b->successor();
__ add_float(dstc, src1c, src2c);
FloatRegister dstd = dstc->successor();
FloatRegister src1d = src1c->successor();
FloatRegister src2d = src2c->successor();
__ add_float(dstd, src1d, src2d);
%}
ins_pipe(faddF_reg_reg); // FIXME
%}
instruct vadd2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (AddVD src1 src2));
size(4*2);
ins_cost(DEFAULT_COST*2); // FIXME
format %{ "FADDD $dst.a,$src1.a,$src2.a\n\t"
"FADDD $dst.b,$src1.b,$src2.b" %}
ins_encode %{
FloatRegister dsta = $dst$$FloatRegister;
FloatRegister src1a = $src1$$FloatRegister;
FloatRegister src2a = $src2$$FloatRegister;
__ add_double(dsta, src1a, src2a);
FloatRegister dstb = dsta->successor()->successor();
FloatRegister src1b = src1a->successor()->successor();
FloatRegister src2b = src2a->successor()->successor();
__ add_double(dstb, src1b, src2b);
%}
ins_pipe(faddF_reg_reg); // FIXME
%}
// Bytes vector sub
instruct vsub8B_reg(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 8);
match(Set dst (SubVB src1 src2));
size(4);
format %{ "VSUB.I8 $dst,$src1,$src2\t! sub packed8B" %}
ins_encode %{
bool quad = false;
__ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_8, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
instruct vsub16B_reg(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 16);
match(Set dst (SubVB src1 src2));
size(4);
format %{ "VSUB.I8 $dst.Q,$src1.Q,$src2.Q\t! sub packed16B" %}
ins_encode %{
bool quad = true;
__ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_8, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
// Shorts/Chars vector sub
instruct vsub4S_reg(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 4);
match(Set dst (SubVS src1 src2));
size(4);
format %{ "VSUB.I16 $dst,$src1,$src2\t! sub packed4S" %}
ins_encode %{
bool quad = false;
__ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_16, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
instruct vsub16S_reg(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 8);
match(Set dst (SubVS src1 src2));
size(4);
format %{ "VSUB.I16 $dst.Q,$src1.Q,$src2.Q\t! sub packed8S" %}
ins_encode %{
bool quad = true;
__ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_16, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
// Integers vector sub
instruct vsub2I_reg(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (SubVI src1 src2));
size(4);
format %{ "VSUB.I32 $dst,$src1,$src2\t! sub packed2I" %}
ins_encode %{
bool quad = false;
__ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_32, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
instruct vsub4I_reg(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 4);
match(Set dst (SubVI src1 src2));
size(4);
format %{ "VSUB.I32 $dst.Q,$src1.Q,$src2.Q\t! sub packed4I" %}
ins_encode %{
bool quad = true;
__ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_32, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
// Longs vector sub
instruct vsub2L_reg(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (SubVL src1 src2));
size(4);
format %{ "VSUB.I64 $dst.Q,$src1.Q,$src2.Q\t! sub packed2L" %}
ins_encode %{
bool quad = true;
__ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_64, quad);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
// Floats vector sub
instruct vsub2F_reg(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant());
match(Set dst (SubVF src1 src2));
size(4);
format %{ "VSUB.F32 $dst,$src1,$src2\t! sub packed2F" %}
ins_encode %{
bool quad = false;
__ vsubF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VFA_SIZE_F32, quad);
%}
ins_pipe( faddF_reg_reg ); // FIXME
%}
instruct vsub2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 2 && !VM_Version::simd_math_is_compliant());
match(Set dst (SubVF src1 src2));
size(4*2);
ins_cost(DEFAULT_COST*2); // FIXME
format %{ "FSUBS $dst.a,$src1.a,$src2.a\n\t"
"FSUBS $dst.b,$src1.b,$src2.b" %}
ins_encode %{
FloatRegister dsta = $dst$$FloatRegister;
FloatRegister src1a = $src1$$FloatRegister;
FloatRegister src2a = $src2$$FloatRegister;
__ sub_float(dsta, src1a, src2a);
FloatRegister dstb = dsta->successor();
FloatRegister src1b = src1a->successor();
FloatRegister src2b = src2a->successor();
__ sub_float(dstb, src1b, src2b);
%}
ins_pipe(faddF_reg_reg); // FIXME
%}
instruct vsub4F_reg(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 4 && VM_Version::simd_math_is_compliant());
match(Set dst (SubVF src1 src2));
size(4);
format %{ "VSUB.F32 $dst.Q,$src1.Q,$src2.Q\t! sub packed4F" %}
ins_encode %{
bool quad = true;
__ vsubF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VFA_SIZE_F32, quad);
%}
ins_pipe( faddF_reg_reg ); // FIXME
%}
instruct vsub4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 4 && !VM_Version::simd_math_is_compliant());
match(Set dst (SubVF src1 src2));
size(4*4);
ins_cost(DEFAULT_COST*4); // FIXME
format %{ "FSUBS $dst.a,$src1.a,$src2.a\n\t"
"FSUBS $dst.b,$src1.b,$src2.b\n\t"
"FSUBS $dst.c,$src1.c,$src2.c\n\t"
"FSUBS $dst.d,$src1.d,$src2.d" %}
ins_encode %{
FloatRegister dsta = $dst$$FloatRegister;
FloatRegister src1a = $src1$$FloatRegister;
FloatRegister src2a = $src2$$FloatRegister;
__ sub_float(dsta, src1a, src2a);
FloatRegister dstb = dsta->successor();
FloatRegister src1b = src1a->successor();
FloatRegister src2b = src2a->successor();
__ sub_float(dstb, src1b, src2b);
FloatRegister dstc = dstb->successor();
FloatRegister src1c = src1b->successor();
FloatRegister src2c = src2b->successor();
__ sub_float(dstc, src1c, src2c);
FloatRegister dstd = dstc->successor();
FloatRegister src1d = src1c->successor();
FloatRegister src2d = src2c->successor();
__ sub_float(dstd, src1d, src2d);
%}
ins_pipe(faddF_reg_reg); // FIXME
%}
instruct vsub2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (SubVD src1 src2));
size(4*2);
ins_cost(DEFAULT_COST*2); // FIXME
format %{ "FSUBD $dst.a,$src1.a,$src2.a\n\t"
"FSUBD $dst.b,$src1.b,$src2.b" %}
ins_encode %{
FloatRegister dsta = $dst$$FloatRegister;
FloatRegister src1a = $src1$$FloatRegister;
FloatRegister src2a = $src2$$FloatRegister;
__ sub_double(dsta, src1a, src2a);
FloatRegister dstb = dsta->successor()->successor();
FloatRegister src1b = src1a->successor()->successor();
FloatRegister src2b = src2a->successor()->successor();
__ sub_double(dstb, src1b, src2b);
%}
ins_pipe(faddF_reg_reg); // FIXME
%}
// Shorts/Chars vector mul
instruct vmul4S_reg(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 4);
match(Set dst (MulVS src1 src2));
size(4);
format %{ "VMUL.I16 $dst,$src1,$src2\t! mul packed4S" %}
ins_encode %{
__ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_16, 0);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
instruct vmul8S_reg(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 8);
match(Set dst (MulVS src1 src2));
size(4);
format %{ "VMUL.I16 $dst.Q,$src1.Q,$src2.Q\t! mul packed8S" %}
ins_encode %{
__ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_16, 1);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
// Integers vector mul
instruct vmul2I_reg(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (MulVI src1 src2));
size(4);
format %{ "VMUL.I32 $dst,$src1,$src2\t! mul packed2I" %}
ins_encode %{
__ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_32, 0);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
instruct vmul4I_reg(vecX dst, vecX src1, vecX src2) %{
predicate(n->as_Vector()->length() == 4);
match(Set dst (MulVI src1 src2));
size(4);
format %{ "VMUL.I32 $dst.Q,$src1.Q,$src2.Q\t! mul packed4I" %}
ins_encode %{
__ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VELEM_SIZE_32, 1);
%}
ins_pipe( ialu_reg_reg ); // FIXME
%}
// Floats vector mul
instruct vmul2F_reg(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant());
match(Set dst (MulVF src1 src2));
size(4);
format %{ "VMUL.F32 $dst,$src1,$src2\t! mul packed2F" %}
ins_encode %{
__ vmulF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
MacroAssembler::VFA_SIZE_F32, 0);
%}
ins_pipe( fmulF_reg_reg ); // FIXME
%}
instruct vmul2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{
predicate(n->as_Vector()->length() == 2 && !VM_Version::simd_math_is_compliant());
match(Set dst (MulVF src1 src2));
size(4*2);
ins_cost(DEFAULT_COST*2); // FIXME
format %{ "FMULS $dst.a,$src1.a,$src2.a\n\t"
"FMULS $dst.b,$src1.b,$src2.b" %}
ins_encode %{
__ mul_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
__ mul_float($dst$$FloatRegister->successor(),
/**代码未完, 请加载全部代码(NowJava.com).**/