--- /dev/null 2016-08-24 15:41:39.598575000 -0400 +++ new/src/cpu/arm/vm/arm.ad 2016-12-13 12:45:11.950296881 -0500 @@ -0,0 +1,14428 @@ +// +// Copyright (c) 2008, 2015, 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 ( , ); +// Generated Code in ad_.hpp +// #define () +// // value == +// Generated code in ad_.cpp adlc_verification() +// assert( == , "Expect () to equal "); +// +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(); +} + +#ifdef AARCH64 +#define ldr_32 ldr_w +#define str_32 str_w +#else +#define ldr_32 ldr +#define str_32 str +#define tst_32 tst +#define teq_32 teq +#endif +#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() { +#ifdef AARCH64 + // ldr_literal; br; (pad); + return 3 * Assembler::InstructionSize + wordSize; +#else + return ( 3 * 4 ); +#endif + } + + + 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 { +#ifdef AARCH64 + return 0; +#else + 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; +#endif +} + +bool MachConstantBaseNode::requires_postalloc_expand() const { return false; } +void MachConstantBaseNode::postalloc_expand(GrowableArray *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 { +#ifdef AARCH64 + return 5 * Assembler::InstructionSize; +#else + return 8; +#endif +} + +#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"); + } +#ifdef AARCH64 + if (OptoPrologueNops <= 0) { + st->print_cr("NOP\t! required for safe patching"); + st->print("\t"); + } +#endif + + 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(); + } +#ifdef AARCH64 + if (OptoPrologueNops <= 0) { + __ nop(); // required for safe patching by patch_verified_entry() + } +#endif + + 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"); +#ifdef AARCH64 + if (MacroAssembler::page_reachable_from_cache(os::get_polling_page())) { + st->print("ADRP Rtemp, #PollAddr\t! Load Polling address\n\t"); + st->print("LDR ZR,[Rtemp + #PollAddr & 0xfff]\t!Poll for Safepointing"); + } else { + st->print("mov_slow Rtemp, #PollAddr\t! Load Polling address\n\t"); + st->print("LDR ZR,[Rtemp]\t!Poll for Safepointing"); + } +#else + st->print("MOV Rtemp, #PollAddr\t! Load Polling address\n\t"); + st->print("LDR Rtemp,[Rtemp]\t!Poll for Safepointing"); +#endif + } +} +#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()) { +#ifdef AARCH64 + if (false && MacroAssembler::page_reachable_from_cache(os::get_polling_page())) { +/* FIXME: TODO + __ relocate(relocInfo::xxx); + __ adrp(Rtemp, (intptr_t)os::get_polling_page()); + __ relocate(relocInfo::poll_return_type); + int offset = os::get_polling_page() & 0xfff; + __ ldr(ZR, Address(Rtemp + offset)); +*/ + } else { + __ mov_address(Rtemp, (address)os::get_polling_page(), symbolic_Relocation::polling_page_reference); + __ relocate(relocInfo::poll_return_type); + __ ldr(ZR, Address(Rtemp)); + } +#else + // mov_slow here is usually one or two instruction + __ mov_address(Rtemp, (address)os::get_polling_page(), symbolic_Relocation::polling_page_reference); + __ relocate(relocInfo::poll_return_type); + __ ldr(Rtemp, Address(Rtemp)); +#endif + } +} + +uint MachEpilogNode::size(PhaseRegAlloc *ra_) const { +#ifdef AARCH64 + // allow for added alignment nop from mov_address bind_literal + return MachNode::size(ra_) + 1 * Assembler::InstructionSize; +#else + return MachNode::size(ra_); +#endif +} + +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) { +#ifdef AARCH64 + return is_memoryHD(offset); +#else + 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); +#endif +} + +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 + } +#ifdef AARCH64 + if (src_first+1 == src_second && dst_first+1 == dst_second) { + return size + 4; + } +#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) { +#ifdef AARCH64 + __ fmov_dx(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[src_first])); +#else + __ 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])); +#endif +#ifndef PRODUCT + } else if (!do_size) { + if (size != 0) st->print("\n\t"); +#ifdef AARCH64 + st->print("FMOV_DX R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first)); +#else + st->print("FMDRR R_%s, R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first), OptoReg::regname(src_second)); +#endif +#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) { +#ifdef AARCH64 + __ fmov_xd(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first])); +#else + __ 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])); +#endif +#ifndef PRODUCT + } else if (!do_size) { + if (size != 0) st->print("\n\t"); +#ifdef AARCH64 + st->print("FMOV_XD R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first)); +#else + st->print("FMRRD R_%s, R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(dst_second), OptoReg::regname(src_first)); +#endif +#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" ); + +#ifndef AARCH64 + // 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; + } +#endif + + 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); +#ifdef AARCH64 + __ add(dst, SP, dst, ex_lsl); +#else + __ add(dst, SP, dst); +#endif + } +} + +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 +#ifdef AARCH64 +#define R_RTEMP "R_R16" +#else +#define R_RTEMP "R_R12" +#endif +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); +#ifdef AARCH64 + Label match; + __ b(match, eq); + __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, Rtemp); + __ bind(match); +#else + __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, noreg, ne); +#endif +} + +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(); + +#ifdef AARCH64 + // See LR saved by caller in sharedRuntime_arm.cpp + // see also hse1 ws + // see also LIR_Assembler::emit_deopt_handler + + __ raw_push(LR, LR); // preserve LR in both slots + __ mov_relative_address(LR, deopt_pc); + __ str(LR, Address(SP, 1 * wordSize)); // save deopt PC + // OK to kill LR, because deopt blob will restore it from SP[0] + __ jump(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type, LR_tmp); +#else + __ 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); +#endif + + 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: +#ifdef AARCH64 + return VM_Version::has_simd(); +#else + return VM_Version::has_vfp() || VM_Version::has_simd(); +#endif + case Op_AddVD: + case Op_SubVD: + case Op_MulVD: + case Op_DivVF: + case Op_DivVD: +#ifdef AARCH64 + return VM_Version::has_simd(); +#else + return VM_Version::has_vfp(); +#endif + } + + return true; // Per default match rules are supported. +} + +const bool Matcher::match_rule_supported_vector(int opcode, int vlen) { + + // 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 int 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 int 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) { +#ifdef AARCH64 + return true; +#else + return false; +#endif +} + +// 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)?. +#ifdef AARCH64 + return (value == 0); +#else + return false; +#endif +} + +// No scaling for the parameter the ClearArray node. +const bool Matcher::init_array_count_is_in_bytes = true; + +#ifdef AARCH64 +const int Matcher::long_cmove_cost() { return 1; } +#else +// Needs 2 CMOV's for longs. +const int Matcher::long_cmove_cost() { return 2; } +#endif + +#ifdef AARCH64 +const int Matcher::float_cmove_cost() { return 1; } +#else +// CMOVF/CMOVD are expensive on ARM. +const int Matcher::float_cmove_cost() { return ConditionalMoveLimit; } +#endif + +// 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? +#ifdef AARCH64 +const bool Matcher::need_masked_shift_count = false; +#else +const bool Matcher::need_masked_shift_count = true; +#endif + +const bool Matcher::convi2l_type_required = true; + +// 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. +#ifdef AARCH64 +// On stack replacement support: +// We don't need Load[DL]_unaligned support, because interpreter stack +// has correct alignment +const bool Matcher::misaligned_doubles_ok = true; +#else +const bool Matcher::misaligned_doubles_ok = false; +#endif + +// 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 ) { +#ifdef AARCH64 + if (reg >= R_R0_num && reg < R_R8_num) return true; + if (reg >= R_V0_num && reg <= R_V7b_num && ((reg & 3) < 2)) return true; +#else + 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; +#endif + 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(); +#ifdef AARCH64 +// TODO: see C1 LIR_Assembler::ic_call() + InlinedAddress oop_literal((address)Universe::non_oop_word()); + int offset = __ offset(); + int fixed_size = mov_oop_size * 4; + if (VM_Version::prefer_moves_over_load_literal()) { + uintptr_t val = (uintptr_t)Universe::non_oop_word(); + __ movz(R8_ic_reg, (val >> 0) & 0xffff, 0); + __ movk(R8_ic_reg, (val >> 16) & 0xffff, 16); + __ movk(R8_ic_reg, (val >> 32) & 0xffff, 32); + __ movk(R8_ic_reg, (val >> 48) & 0xffff, 48); + } else { + __ ldr_literal(R8_ic_reg, oop_literal); + } + assert(__ offset() - offset == fixed_size, "bad mov_oop size"); +#else + __ movw(R8_ic_reg, ((unsigned int)Universe::non_oop_word()) & 0xffff); + __ movt(R8_ic_reg, ((unsigned int)Universe::non_oop_word()) >> 16); +#endif + 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); +#ifdef AARCH64 + if (!VM_Version::prefer_moves_over_load_literal()) { + Label skip_literal; + __ b(skip_literal); + int off2 = __ offset(); + __ bind_literal(oop_literal); + if (__ offset() - off2 == wordSize) { + // no padding, so insert nop for worst-case sizing + __ nop(); + } + __ bind(skip_literal); + } +#endif + %} + + 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); +#ifdef AARCH64 + Label Lskip; + __ _lsl_w(cnt1_reg, cnt1_reg, exact_log2(sizeof(jchar))); // scale the limit + __ b(Lskip, mi); + __ _lsl_w(cnt1_reg, cnt2_reg, exact_log2(sizeof(jchar))); // scale the limit + __ bind(Lskip); +#else + __ 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 +#endif + + // 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 Lword_loop, Lpost_word, 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 Lvector, 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 +#ifdef AARCH64 + __ cmp(ary1_reg, ary2_reg); + __ b(Lequal, eq); + + __ mov(result_reg, 0); + + __ cbz(ary1_reg, Ldone); // not equal + + __ cbz(ary2_reg, Ldone); // not equal +#else + __ 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 +#endif + + //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 +#ifdef AARCH64 + __ cmp_w(tmp1_reg, tmp2_reg); + __ b(Ldone, ne); // not equal + + __ cbz_w(tmp1_reg, Lequal); // zero-length arrays are equal +#else + __ 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 +#endif + + // 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 +#ifdef AARCH64 + frame_pointer(R_SP); +#else + frame_pointer(R_R13); +#endif + + // 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 + + round_to((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); +%} + +#ifndef AARCH64 +// 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); +%} +#endif + +// 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); +%} + +#ifdef AARCH64 +// Long Immediate: for logical instruction +operand limmL() %{ + predicate(is_limmL(n->get_long())); + match(ConL); + op_cost(0); + + format %{ %} + interface(CONST_INTER); +%} + +operand limmLn() %{ + predicate(is_limmL(~n->get_long())); + match(ConL); + op_cost(0); + + format %{ %} + interface(CONST_INTER); +%} + +// Long Immediate: for arithmetic instruction +operand aimmL() %{ + predicate(is_aimm(n->get_long())); + match(ConL); + op_cost(0); + + format %{ %} + interface(CONST_INTER); +%} + +operand aimmLneg() %{ + predicate(is_aimm(-n->get_long())); + match(ConL); + op_cost(0); + + format %{ %} + interface(CONST_INTER); +%} +#endif // AARCH64 + +// 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); +#ifdef AARCH64 + match(ZRRegI); +#else + match(R12RegI); +#endif + + 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); +%} + +#ifdef AARCH64 +// Like sp_ptr_reg, but exclude regs (Aarch64 SP) that can't be +// stored directly. Includes ZR, so can't be used as a destination. +operand store_ptr_RegP() %{ + constraint(ALLOC_IN_RC(store_ptr_reg)); + match(RegP); + match(iRegP); + match(ZRRegP); + + format %{ %} + interface(REG_INTER); +%} + +operand store_RegI() %{ + constraint(ALLOC_IN_RC(store_reg)); + match(RegI); + match(iRegI); + match(ZRRegI); + + format %{ %} + interface(REG_INTER); +%} + +operand store_RegL() %{ + constraint(ALLOC_IN_RC(store_ptr_reg)); + match(RegL); + match(iRegL); + match(ZRRegL); + + format %{ %} + interface(REG_INTER); +%} + +operand store_RegN() %{ + constraint(ALLOC_IN_RC(store_reg)); + match(RegN); + match(iRegN); + match(ZRRegN); + + format %{ %} + interface(REG_INTER); +%} +#endif + +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 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 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); +%} + +#ifndef AARCH64 +operand R12RegI() %{ + constraint(ALLOC_IN_RC(R12_regI)); + match(iRegI); + + format %{ %} + interface(REG_INTER); +%} +#endif + +// Long Register +operand iRegL() %{ + constraint(ALLOC_IN_RC(long_reg)); + match(RegL); +#ifdef AARCH64 + match(iRegLd); +#else + match(R0R1RegL); + match(R2R3RegL); +#endif +//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); +%} + +#ifndef AARCH64 +// 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); +%} +#endif + +// 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. +#ifndef AARCH64 +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); +%} +#endif + +// 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); +#ifdef AARCH64 + index(0xff); // 0xff => no index +#else + index(0xf); // PC => no index +#endif + scale(0x0); + disp(0x0); + %} +%} + +#ifdef AARCH64 +// Indirect with scaled*1 uimm12 offset +operand indOffsetU12ScaleB(sp_ptr_RegP reg, immUL12 offset) %{ + constraint(ALLOC_IN_RC(sp_ptr_reg)); + match(AddP reg offset); + + op_cost(100); + format %{ "[$reg + $offset]" %} + interface(MEMORY_INTER) %{ + base($reg); +#ifdef AARCH64 + index(0xff); // 0xff => no index +#else + index(0xf); // PC => no index +#endif + scale(0x0); + disp($offset); + %} +%} + +// Indirect with scaled*2 uimm12 offset +operand indOffsetU12ScaleS(sp_ptr_RegP reg, immUL12x2 offset) %{ + constraint(ALLOC_IN_RC(sp_ptr_reg)); + match(AddP reg offset); + + op_cost(100); + format %{ "[$reg + $offset]" %} + interface(MEMORY_INTER) %{ + base($reg); +#ifdef AARCH64 + index(0xff); // 0xff => no index +#else + index(0xf); // PC => no index +#endif + scale(0x0); + disp($offset); + %} +%} + +// Indirect with scaled*4 uimm12 offset +operand indOffsetU12ScaleI(sp_ptr_RegP reg, immUL12x4 offset) %{ + constraint(ALLOC_IN_RC(sp_ptr_reg)); + match(AddP reg offset); + + op_cost(100); + format %{ "[$reg + $offset]" %} + interface(MEMORY_INTER) %{ + base($reg); +#ifdef AARCH64 + index(0xff); // 0xff => no index +#else + index(0xf); // PC => no index +#endif + scale(0x0); + disp($offset); + %} +%} + +// Indirect with scaled*8 uimm12 offset +operand indOffsetU12ScaleL(sp_ptr_RegP reg, immUL12x8 offset) %{ + constraint(ALLOC_IN_RC(sp_ptr_reg)); + match(AddP reg offset); + + op_cost(100); + format %{ "[$reg + $offset]" %} + interface(MEMORY_INTER) %{ + base($reg); +#ifdef AARCH64 + index(0xff); // 0xff => no index +#else + index(0xf); // PC => no index +#endif + scale(0x0); + disp($offset); + %} +%} + +// Indirect with scaled*16 uimm12 offset +operand indOffsetU12ScaleQ(sp_ptr_RegP reg, immUL12x16 offset) %{ + constraint(ALLOC_IN_RC(sp_ptr_reg)); + match(AddP reg offset); + + op_cost(100); + format %{ "[$reg + $offset]" %} + interface(MEMORY_INTER) %{ + base($reg); +#ifdef AARCH64 + index(0xff); // 0xff => no index +#else + index(0xf); // PC => no index +#endif + scale(0x0); + disp($offset); + %} +%} + +#else // ! AARCH64 + +// 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); +#ifdef AARCH64 + index(0xff); // 0xff => no index +#else + index(0xf); // PC => no index +#endif + 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); +#ifdef AARCH64 + index(0xff); // 0xff => no index +#else + index(0xf); // PC => no index +#endif + 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); +#ifdef AARCH64 + index(0xff); // 0xff => no index +#else + index(0xf); // PC => no index +#endif + 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); +#ifdef AARCH64 + index(0xff); // 0xff => no index +#else + index(0xf); // PC => no index +#endif + 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); +#ifdef AARCH64 + index(0xff); // 0xff => no index +#else + index(0xf); // PC => no index +#endif + scale(0x0); + disp($offset); + %} +%} +#endif // !AARCH64 + +// 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); + %} +%} + +#ifdef AARCH64 +// Indirect Memory Times Scale Plus Index Register +operand indIndexScaleS(iRegP addr, iRegX index, immI_1 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); + %} +%} + +// Indirect Memory Times Scale Plus 32-bit Index Register +operand indIndexIScaleS(iRegP addr, iRegI index, immI_1 scale) %{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP addr (LShiftX (ConvI2L index) scale)); + + op_cost(100); + format %{"[$addr + $index.w << $scale]" %} + interface(MEMORY_INTER) %{ + base($addr); + index($index); + scale($scale); + disp(0x7fffffff); // sxtw + %} +%} + +// Indirect Memory Times Scale Plus Index Register +operand indIndexScaleI(iRegP addr, iRegX index, immI_2 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); + %} +%} + +// Indirect Memory Times Scale Plus 32-bit Index Register +operand indIndexIScaleI(iRegP addr, iRegI index, immI_2 scale) %{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP addr (LShiftX (ConvI2L index) scale)); + + op_cost(100); + format %{"[$addr + $index.w << $scale]" %} + interface(MEMORY_INTER) %{ + base($addr); + index($index); + scale($scale); + disp(0x7fffffff); // sxtw + %} +%} + +// Indirect Memory Times Scale Plus Index Register +operand indIndexScaleL(iRegP addr, iRegX index, immI_3 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); + %} +%} + +// Indirect Memory Times Scale Plus 32-bit Index Register +operand indIndexIScaleL(iRegP addr, iRegI index, immI_3 scale) %{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP addr (LShiftX (ConvI2L index) scale)); + + op_cost(100); + format %{"[$addr + $index.w << $scale]" %} + interface(MEMORY_INTER) %{ + base($addr); + index($index); + scale($scale); + disp(0x7fffffff); // sxtw + %} +%} + +// Indirect Memory Times Scale Plus Index Register +operand indIndexScaleQ(iRegP addr, iRegX index, immI_4 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); + %} +%} + +// Indirect Memory Times Scale Plus 32-bit Index Register +operand indIndexIScaleQ(iRegP addr, iRegI index, immI_4 scale) %{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP addr (LShiftX (ConvI2L index) scale)); + + op_cost(100); + format %{"[$addr + $index.w << $scale]" %} + interface(MEMORY_INTER) %{ + base($addr); + index($index); + scale($scale); + disp(0x7fffffff); // sxtw + %} +%} +#else +// 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); + %} +%} +#endif + +// 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 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. +#ifdef AARCH64 +opclass memoryB(indirect, indIndex, indOffsetU12ScaleB); +opclass memoryS(indirect, indIndex, indIndexScaleS, indIndexIScaleS, indOffsetU12ScaleS); +opclass memoryI(indirect, indIndex, indIndexScaleI, indIndexIScaleI, indOffsetU12ScaleI); +opclass memoryL(indirect, indIndex, indIndexScaleL, indIndexIScaleL, indOffsetU12ScaleL); +opclass memoryP(indirect, indIndex, indIndexScaleL, indIndexIScaleL, indOffsetU12ScaleL); +opclass memoryQ(indirect, indIndex, indIndexScaleQ, indIndexIScaleQ, indOffsetU12ScaleQ); +opclass memoryF(indirect, indIndex, indIndexScaleI, indIndexIScaleI, indOffsetU12ScaleI); +opclass memoryD(indirect, indIndex, indIndexScaleL, indIndexIScaleL, indOffsetU12ScaleL); + +opclass memoryScaledS(indIndexScaleS, indIndexIScaleS); +opclass memoryScaledI(indIndexScaleI, indIndexIScaleI); +opclass memoryScaledL(indIndexScaleL, indIndexIScaleL); +opclass memoryScaledP(indIndexScaleL, indIndexIScaleL); +opclass memoryScaledQ(indIndexScaleQ, indIndexIScaleQ); +opclass memoryScaledF(indIndexScaleI, indIndexIScaleI); +opclass memoryScaledD(indIndexScaleL, indIndexIScaleL); +// when ldrex/strex is used: +opclass memoryex ( indirect ); +opclass indIndexMemory( indIndex ); +opclass memoryvld ( indirect /* , write back mode not implemented */ ); + +#else + +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 */ ); +#endif + +//----------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 %{ + // High 32 bits are harmlessly set on Aarch64 + __ 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); + +#ifdef AARCH64 + size(4); + format %{ "LDRSB $dst,$mem\t! byte -> long" %} + ins_encode %{ + __ ldrsb($dst$$Register, $mem$$Address); + %} +#else + 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)); + %} +#endif + 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); + +#ifdef AARCH64 + size(4); + format %{ "LDRB $dst,$mem\t! ubyte -> long" %} + ins_encode %{ + __ ldrb($dst$$Register, $mem$$Address); + %} +#else + 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); + %} +#endif + 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))); + +#ifdef AARCH64 + ins_cost(MEMORY_REF_COST + DEFAULT_COST); + size(8); + format %{ "LDRB $dst,$mem\t! ubyte -> long\n\t" + "AND $dst,$dst,$mask" %} + ins_encode %{ + __ ldrb($dst$$Register, $mem$$Address); + __ andr($dst$$Register, $dst$$Register, limmI_low($mask$$constant, 8)); + %} +#else + 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)); + %} +#endif + ins_pipe(iload_mem); +%} + +// Load Short (16bit signed) +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct loadSoff(iRegI dst, memoryScaledS mem, aimmX off, iRegP tmp) %{ + match(Set dst (LoadS (AddP mem off))); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "LDRSH $dst,$mem+$off\t! short 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); + __ ldrsh($dst$$Register, nmem); + %} + ins_pipe(iload_mask_mem); +%} +#endif + +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 %{ + // High 32 bits are harmlessly set on Aarch64 + __ 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); + +#ifdef AARCH64 + size(4); + format %{ "LDRSH $dst,$mem\t! short -> long" %} + ins_encode %{ + __ ldrsh($dst$$Register, $mem$$Address); + %} +#else + 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)); + %} +#endif + ins_pipe(iload_mask_mem); +%} + +// Load Unsigned Short/Char (16bit UNsigned) + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct loadUSoff(iRegI dst, memoryScaledS mem, aimmX off, iRegP tmp) %{ + match(Set dst (LoadUS (AddP mem off))); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "LDRH $dst,$mem+$off\t! ushort/char 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); + __ ldrh($dst$$Register, nmem); + %} + ins_pipe(iload_mem); +%} +#endif + +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); + +#ifdef AARCH64 + size(4); + format %{ "LDRH $dst,$mem\t! short -> long" %} + ins_encode %{ + __ ldrh($dst$$Register, $mem$$Address); + %} +#else + 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); + %} +#endif + 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); + +#ifdef AARCH64 + size(4); + format %{ "LDRB $dst,$mem" %} + ins_encode %{ + __ ldrb($dst$$Register, $mem$$Address); + %} +#else + 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); + %} +#endif + 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))); +#ifdef AARCH64 + ins_cost(MEMORY_REF_COST + 1*DEFAULT_COST); + + size(8); + format %{ "LDRH $dst,$mem\t! ushort/char & mask -> long\n\t" + "AND $dst,$dst,$mask" %} + ins_encode %{ + __ ldrh($dst$$Register, $mem$$Address); + __ andr($dst$$Register, $dst$$Register, (uintx)$mask$$constant); + %} +#else + 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); + %} +#endif + ins_pipe(iload_mem); +%} + +// Load Integer + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct loadIoff(iRegI dst, memoryScaledI mem, aimmX off, iRegP tmp) %{ + match(Set dst (LoadI (AddP mem off))); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "ldr_s32 $dst,$mem+$off\t! int 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_s32($dst$$Register, nmem); + %} + ins_pipe(iload_mem); +%} +#endif + +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))); +#ifdef AARCH64 + ins_cost(MEMORY_REF_COST); + + size(4); + format %{ "LDRSW $dst.lo,$mem\t! int -> long" %} + ins_encode %{ + __ ldr_s32($dst$$Register, $mem$$Address); + %} +#else + 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)); + %} +#endif + 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))); +#ifdef AARCH64 + ins_cost(MEMORY_REF_COST); + + size(4); + format %{ "LDRB $dst.lo,$mem\t! int & 0xFF -> long" %} + ins_encode %{ + __ ldrb($dst$$Register, $mem$$Address); + %} +#else + 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); + %} +#endif + 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); + +#ifdef AARCH64 + size(4); + format %{ "LDRH $dst,$mem\t! int & 0xFFFF -> long" %} + ins_encode %{ + __ ldrh($dst$$Register, $mem$$Address); + %} +#else + 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); + %} +#endif + ins_pipe(iload_mask_mem); +%} + +#ifdef AARCH64 +// Load Integer with an immediate mask into a Long Register +instruct loadI2L_limmI(iRegL dst, memoryI mem, limmI mask) %{ + match(Set dst (ConvI2L (AndI (LoadI mem) mask))); + ins_cost(MEMORY_REF_COST + 1*DEFAULT_COST); + + size(8); + format %{ "LDRSW $dst,$mem\t! int -> long\n\t" + "AND $dst,$dst,$mask" %} + + ins_encode %{ + __ ldr_s32($dst$$Register, $mem$$Address); + __ andr($dst$$Register, $dst$$Register, (uintx)$mask$$constant); + %} + ins_pipe(iload_mem); +%} +#else +// 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); +%} +#endif + +#ifdef AARCH64 +// Load Integer with mask into a Long Register +// FIXME: use signedRegI mask, remove tmp? +instruct loadI2L_immI(iRegL dst, memoryI mem, immI mask, iRegI tmp) %{ + match(Set dst (ConvI2L (AndI (LoadI mem) mask))); + effect(TEMP dst, TEMP tmp); + + ins_cost(MEMORY_REF_COST + 3*DEFAULT_COST); + format %{ "LDRSW $mem,$dst\t! int & 31-bit mask -> long\n\t" + "MOV_SLOW $tmp,$mask\n\t" + "AND $dst,$tmp,$dst" %} + ins_encode %{ + __ ldrsw($dst$$Register, $mem$$Address); + __ mov_slow($tmp$$Register, $mask$$constant); + __ andr($dst$$Register, $dst$$Register, $tmp$$Register); + %} + ins_pipe(iload_mem); +%} +#else +// 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); +%} +#endif + +// 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); + +#ifdef AARCH64 +//size(4); + format %{ "LDR_w $dst,$mem\t! uint -> long" %} + ins_encode %{ + __ ldr_w($dst$$Register, $mem$$Address); + %} +#else + 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); + %} +#endif + ins_pipe(iload_mem); +%} + +// Load Long + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct loadLoff(iRegLd dst, memoryScaledL mem, aimmX off, iRegP tmp) %{ + match(Set dst (LoadL (AddP mem off))); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "LDR $dst,$mem+$off\t! long 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($dst$$Register, nmem); + %} + ins_pipe(iload_mem); +%} +#endif + +instruct loadL(iRegLd dst, memoryL mem ) %{ +#ifdef AARCH64 + // already atomic for Aarch64 +#else + predicate(!((LoadLNode*)n)->require_atomic_access()); +#endif + 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); +%} + +#ifndef AARCH64 +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); +%} +#endif // !AARCH64 + +// 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 + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct loadPoff(iRegP dst, memoryScaledP mem, aimmX off, iRegP tmp) %{ + match(Set dst (LoadP (AddP mem off))); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "LDR $dst,$mem+$off\t! 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($dst$$Register, nmem); + %} + ins_pipe(iload_mem); +%} +#endif + +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 + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct loadDoff(regD dst, memoryScaledD mem, aimmX off, iRegP tmp) %{ + match(Set dst (LoadD (AddP mem off))); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "ldr $dst,$mem+$off\t! double 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_d($dst$$FloatRegister, nmem); + %} + ins_pipe(floadD_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); +%} + +#ifndef AARCH64 +// 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); +%} +#endif + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct loadFoff(regF dst, memoryScaledF mem, aimmX off, iRegP tmp) %{ + match(Set dst (LoadF (AddP mem off))); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "ldr $dst,$mem+$off\t! float 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_s($dst$$FloatRegister, nmem); + %} + ins_pipe(floadF_mem); +%} +#endif + +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); +%} + +#ifdef AARCH64 +instruct load_limmI(iRegI dst, limmI src) %{ + match(Set dst src); + ins_cost(DEFAULT_COST + 1); // + 1 because MOV is preferred + format %{ "ORR_w $dst, ZR, $src\t! int" %} + ins_encode %{ + __ orr_w($dst$$Register, ZR, (uintx)$src$$constant); + %} + ins_pipe(ialu_imm); +%} +#endif + +// // 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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +instruct loadConI16( iRegI dst, immI16 src ) %{ + match(Set dst src); + size(4); +#ifdef AARCH64 + format %{ "MOVZ_w $dst, $src" %} +#else + format %{ "MOVW $dst, $src" %} +#endif + ins_encode %{ +#ifdef AARCH64 + __ mov_w($dst$$Register, $src$$constant); +#else + __ movw($dst$$Register, $src$$constant); +#endif + %} + 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); +%} + +#ifdef AARCH64 +instruct loadConP0(iRegP dst, immP0 src) %{ + match(Set dst src); + ins_cost(DEFAULT_COST); + format %{ "MOV $dst,ZR\t!ptr" %} + ins_encode %{ + __ mov($dst$$Register, ZR); + %} + ins_pipe(ialu_none); +%} + +instruct loadConN(iRegN dst, immN src) %{ + match(Set dst src); + ins_cost(DEFAULT_COST * 3/2); + format %{ "SET $dst,$src\t! compressed ptr" %} + ins_encode %{ + Register dst = $dst$$Register; + // FIXME: use $constanttablebase? + __ set_narrow_oop(dst, (jobject)$src$$constant); + %} + ins_pipe(ialu_hi_lo_reg); +%} + +instruct loadConN0(iRegN dst, immN0 src) %{ + match(Set dst src); + ins_cost(DEFAULT_COST); + format %{ "MOV $dst,ZR\t! compressed ptr" %} + ins_encode %{ + __ mov($dst$$Register, ZR); + %} + ins_pipe(ialu_none); +%} + +instruct loadConNKlass(iRegN dst, immNKlass src) %{ + match(Set dst src); + ins_cost(DEFAULT_COST * 3/2); + format %{ "SET $dst,$src\t! compressed klass ptr" %} + ins_encode %{ + Register dst = $dst$$Register; + // FIXME: use $constanttablebase? + __ set_narrow_klass(dst, (Klass*)$src$$constant); + %} + ins_pipe(ialu_hi_lo_reg); +%} + +instruct load_limmL(iRegL dst, limmL src) %{ + match(Set dst src); + ins_cost(DEFAULT_COST); + format %{ "ORR $dst, ZR, $src\t! long" %} + ins_encode %{ + __ orr($dst$$Register, ZR, (uintx)$src$$constant); + %} + ins_pipe(loadConL); +%} +instruct load_immLMov(iRegL dst, immLMov src) %{ + match(Set dst src); + ins_cost(DEFAULT_COST); + format %{ "MOV $dst, $src\t! long" %} + ins_encode %{ + __ mov($dst$$Register, $src$$constant); + %} + ins_pipe(loadConL); +%} +instruct loadConL(iRegL dst, immL src) %{ + match(Set dst src); + ins_cost(DEFAULT_COST * 4); // worst case + format %{ "mov_slow $dst, $src\t! long" %} + ins_encode %{ + // FIXME: use $constanttablebase? + __ mov_slow($dst$$Register, $src$$constant); + %} + ins_pipe(loadConL); +%} +#else +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); +%} +#endif + +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 +%} + +#ifdef AARCH64 +instruct loadIConF(iRegI dst, immF src) %{ + match(Set dst src); + ins_cost(DEFAULT_COST * 2); + + format %{ "MOV_SLOW $dst, $src\t! loadIConF" %} + + ins_encode %{ + // FIXME revisit once 6961697 is in + union { + jfloat f; + int i; + } v; + v.f = $src$$constant; + __ mov_slow($dst$$Register, v.i); + %} + ins_pipe(ialu_imm); +%} +#endif + +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(os::is_MP()); + match( PrefetchAllocation mem ); + ins_cost(MEMORY_REF_COST); + size(4); + + format %{ "PLDW $mem\t! Prefetch allocation" %} + ins_encode %{ +#ifdef AARCH64 + __ prfm(pstl1keep, $mem$$Address); +#else + __ pldw($mem$$Address); +#endif + %} + ins_pipe(iload_mem); +%} + +instruct prefetchAlloc_sp( memoryP mem ) %{ + predicate(!os::is_MP()); + match( PrefetchAllocation mem ); + ins_cost(MEMORY_REF_COST); + size(4); + + format %{ "PLD $mem\t! Prefetch allocation" %} + ins_encode %{ +#ifdef AARCH64 + __ prfm(pstl1keep, $mem$$Address); +#else + __ pld($mem$$Address); +#endif + %} + 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 + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct storeCoff(store_RegI src, memoryScaledS mem, aimmX off, iRegP tmp) %{ + match(Set mem (StoreC (AddP mem off) src)); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "STRH $src,$mem+$off\t! short 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); + __ strh($src$$Register, nmem); + %} + ins_pipe(istore_mem_reg); +%} +#endif + +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 + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct storeIoff(store_RegI src, memoryScaledI mem, aimmX off, iRegP tmp) %{ + match(Set mem (StoreI (AddP mem off) src)); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "str_32 $src,$mem+$off\t! int 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); + __ str_32($src$$Register, nmem); + %} + ins_pipe(istore_mem_reg); +%} +#endif + +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 + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct storeLoff(store_RegLd src, memoryScaledL mem, aimmX off, iRegP tmp) %{ + match(Set mem (StoreL (AddP mem off) src)); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "str_64 $src,$mem+$off\t! long 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); + __ str_64($src$$Register, nmem); + %} + ins_pipe(istore_mem_reg); +%} +#endif + +instruct storeL(memoryL mem, store_RegLd src) %{ +#ifdef AARCH64 + // already atomic for Aarch64 +#else + predicate(!((StoreLNode*)n)->require_atomic_access()); +#endif + 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); +%} + +#ifndef AARCH64 +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); +%} +#endif // !AARCH64 + +#ifndef AARCH64 +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); +%} +#endif + +#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 + +#ifdef AARCH64 +// FIXME +// Store SP Pointer +instruct storeSP(memoryP mem, SPRegP src, iRegP tmp) %{ + match(Set mem (StoreP mem src)); + predicate(_kids[1]->_leaf->is_Proj() && _kids[1]->_leaf->as_Proj()->_con == TypeFunc::FramePtr); + // Multiple StoreP rules, different only in register mask. + // Matcher makes the last always valid. The others will + // only be valid if they cost less than the last valid + // rule. So cost(rule1) < cost(rule2) < cost(last) + // Unlike immediates, register constraints are not checked + // at match time. + ins_cost(MEMORY_REF_COST+DEFAULT_COST+4); + effect(TEMP tmp); + size(8); + + format %{ "MOV $tmp,$src\t! SP ptr\n\t" + "STR $tmp,$mem\t! SP ptr" %} + ins_encode %{ + assert($src$$Register == SP, "SP expected"); + __ mov($tmp$$Register, $src$$Register); + __ str($tmp$$Register, $mem$$Address); + %} + ins_pipe(istore_mem_spORreg); // FIXME +%} +#endif // AARCH64 + +// Store Pointer + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct storePoff(store_ptr_RegP src, memoryScaledP mem, aimmX off, iRegP tmp) %{ + predicate(!_kids[1]->_leaf->is_Proj() || _kids[1]->_leaf->as_Proj()->_con != TypeFunc::FramePtr); + match(Set mem (StoreP (AddP mem off) src)); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "STR $src,$mem+$off\t! 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); + __ str($src$$Register, nmem); + %} + ins_pipe(istore_mem_reg); +%} +#endif + +instruct storeP(memoryP mem, store_ptr_RegP src) %{ + match(Set mem (StoreP mem src)); +#ifdef AARCH64 + predicate(!_kids[1]->_leaf->is_Proj() || _kids[1]->_leaf->as_Proj()->_con != TypeFunc::FramePtr); +#endif + 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 AARCH64 +// Store NULL Pointer +instruct storeP0(memoryP mem, immP0 src) %{ + match(Set mem (StoreP mem src)); + ins_cost(MEMORY_REF_COST); + size(4); + + format %{ "STR ZR,$mem\t! ptr" %} + ins_encode %{ + __ str(ZR, $mem$$Address); + %} + ins_pipe(istore_mem_spORreg); +%} +#endif // AARCH64 + +#ifdef _LP64 +// Store Compressed Pointer + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct storeNoff(store_RegN src, memoryScaledI mem, aimmX off, iRegP tmp) %{ + match(Set mem (StoreN (AddP mem off) src)); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "str_32 $src,$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); + __ str_32($src$$Register, nmem); + %} + ins_pipe(istore_mem_reg); +%} +#endif + +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); +%} + +#ifdef AARCH64 +// Store NULL Pointer +instruct storeN0(memoryI mem, immN0 src) %{ + match(Set mem (StoreN mem src)); + ins_cost(MEMORY_REF_COST); + size(4); + + format %{ "str_32 ZR,$mem\t! compressed ptr" %} + ins_encode %{ + __ str_32(ZR, $mem$$Address); + %} + ins_pipe(istore_mem_reg); +%} +#endif + +// 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 + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct storeDoff(regD src, memoryScaledD mem, aimmX off, iRegP tmp) %{ + match(Set mem (StoreD (AddP mem off) src)); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "STR $src,$mem+$off\t! double 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); + __ str_d($src$$FloatRegister, nmem); + %} + ins_pipe(fstoreD_mem_reg); +%} +#endif + +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); +%} + +#ifdef AARCH64 +instruct movI2F(regF dst, iRegI src) %{ + match(Set dst src); + size(4); + + format %{ "FMOV_sw $dst,$src\t! movI2F" %} + ins_encode %{ + __ fmov_sw($dst$$FloatRegister, $src$$Register); + %} + ins_pipe(ialu_reg); // FIXME +%} + +instruct movF2I(iRegI dst, regF src) %{ + match(Set dst src); + size(4); + + format %{ "FMOV_ws $dst,$src\t! movF2I" %} + ins_encode %{ + __ fmov_ws($dst$$Register, $src$$FloatRegister); + %} + ins_pipe(ialu_reg); // FIXME +%} +#endif + +// Store Float + +#ifdef AARCH64 +// XXX This variant shouldn't be necessary if 6217251 is implemented +instruct storeFoff(regF src, memoryScaledF mem, aimmX off, iRegP tmp) %{ + match(Set mem (StoreF (AddP mem off) src)); + ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free + effect(TEMP tmp); + size(4 * 2); + + format %{ "str_s $src,$mem+$off\t! float 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); + __ str_s($src$$FloatRegister, nmem); + %} + ins_pipe(fstoreF_mem_reg); +%} +#endif + +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); +%} + +#ifdef AARCH64 +// Convert oop pointer into compressed form +instruct encodeHeapOop(iRegN dst, iRegP src, flagsReg ccr) %{ + predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull); + match(Set dst (EncodeP src)); + effect(KILL ccr); + format %{ "encode_heap_oop $dst, $src" %} + ins_encode %{ + __ encode_heap_oop($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct encodeHeapOop_not_null(iRegN dst, iRegP src) %{ + predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull); + match(Set dst (EncodeP src)); + format %{ "encode_heap_oop_not_null $dst, $src" %} + ins_encode %{ + __ encode_heap_oop_not_null($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct decodeHeapOop(iRegP dst, iRegN src, flagsReg ccr) %{ + predicate(n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull && + n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant); + match(Set dst (DecodeN src)); + effect(KILL ccr); + format %{ "decode_heap_oop $dst, $src" %} + ins_encode %{ + __ decode_heap_oop($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct decodeHeapOop_not_null(iRegP dst, iRegN src) %{ + predicate(n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull || + n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant); + match(Set dst (DecodeN src)); + format %{ "decode_heap_oop_not_null $dst, $src" %} + ins_encode %{ + __ decode_heap_oop_not_null($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct encodeKlass_not_null(iRegN dst, iRegP src) %{ + match(Set dst (EncodePKlass src)); + format %{ "encode_klass_not_null $dst, $src" %} + ins_encode %{ + __ encode_klass_not_null($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct decodeKlass_not_null(iRegP dst, iRegN src) %{ + match(Set dst (DecodeNKlass src)); + format %{ "decode_klass_not_null $dst, $src" %} + ins_encode %{ + __ decode_klass_not_null($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} +#endif // AARCH64 + +//----------MemBar Instructions----------------------------------------------- +// Memory barrier flavors + +// TODO: take advantage of Aarch64 load-acquire, store-release, etc +// 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); +// %} + + +#ifdef AARCH64 +// 0 constant in register +instruct zrImmI0(ZRRegI dst, immI0 imm) %{ + match(Set dst imm); + size(0); + ins_cost(0); + + format %{ "! ZR (int 0)" %} + ins_encode( /*empty encoding*/ ); + ins_pipe(ialu_none); +%} + +// 0 constant in register +instruct zrImmL0(ZRRegL dst, immL0 imm) %{ + match(Set dst imm); + size(0); + ins_cost(0); + + format %{ "! ZR (long 0)" %} + ins_encode( /*empty encoding*/ ); + ins_pipe(ialu_none); +%} + +#ifdef XXX +// 0 constant in register +instruct zrImmN0(ZRRegN dst, immN0 imm) %{ + match(Set dst imm); + size(0); + ins_cost(0); + + format %{ "! ZR (compressed pointer NULL)" %} + ins_encode( /*empty encoding*/ ); + ins_pipe(ialu_none); +%} + +// 0 constant in register +instruct zrImmP0(ZRRegP dst, immP0 imm) %{ + match(Set dst imm); + size(0); + ins_cost(0); + + format %{ "! ZR (NULL)" %} + ins_encode( /*empty encoding*/ ); + ins_pipe(ialu_none); +%} +#endif +#endif // AARCH64 + +// 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); +%} + +#ifndef AARCH64 +//----------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); +%} +#endif + +#ifdef AARCH64 +instruct cmovI_reg3(cmpOp cmp, flagsReg icc, iRegI dst, iRegI src1, iRegI src2) %{ + match(Set dst (CMoveI (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! int" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovL_reg3(cmpOp cmp, flagsReg icc, iRegL dst, iRegL src1, iRegL src2) %{ + match(Set dst (CMoveL (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! long" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovP_reg3(cmpOp cmp, flagsReg icc, iRegP dst, iRegP src1, iRegP src2) %{ + match(Set dst (CMoveP (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! ptr" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovN_reg3(cmpOp cmp, flagsReg icc, iRegN dst, iRegN src1, iRegN src2) %{ + match(Set dst (CMoveN (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! compressed ptr" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovIP_reg3(cmpOpP cmp, flagsRegP icc, iRegI dst, iRegI src1, iRegI src2) %{ + match(Set dst (CMoveI (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! int" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovLP_reg3(cmpOpP cmp, flagsRegP icc, iRegL dst, iRegL src1, iRegL src2) %{ + match(Set dst (CMoveL (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! long" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovPP_reg3(cmpOpP cmp, flagsRegP icc, iRegP dst, iRegP src1, iRegP src2) %{ + match(Set dst (CMoveP (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! ptr" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovNP_reg3(cmpOpP cmp, flagsRegP icc, iRegN dst, iRegN src1, iRegN src2) %{ + match(Set dst (CMoveN (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! compressed ptr" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovIU_reg3(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src1, iRegI src2) %{ + match(Set dst (CMoveI (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! int" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovLU_reg3(cmpOpU cmp, flagsRegU icc, iRegL dst, iRegL src1, iRegL src2) %{ + match(Set dst (CMoveL (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! long" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovPU_reg3(cmpOpU cmp, flagsRegU icc, iRegP dst, iRegP src1, iRegP src2) %{ + match(Set dst (CMoveP (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! ptr" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovNU_reg3(cmpOpU cmp, flagsRegU icc, iRegN dst, iRegN src1, iRegN src2) %{ + match(Set dst (CMoveN (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! compressed ptr" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovIZ_reg3(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegI dst, iRegI src1, iRegI src2) %{ + match(Set dst (CMoveI (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! int" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovLZ_reg3(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegL dst, iRegL src1, iRegL src2) %{ + match(Set dst (CMoveL (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! long" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovPZ_reg3(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegP dst, iRegP src1, iRegP src2) %{ + match(Set dst (CMoveP (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! ptr" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovNZ_reg3(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegN dst, iRegN src1, iRegN src2) %{ + match(Set dst (CMoveN (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "CSEL $dst,$src1,$src2,$cmp\t! compressed ptr" %} + ins_encode %{ + __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} +#endif // AARCH64 + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifdef AARCH64 +instruct cmovL_reg(cmpOp cmp, flagsReg icc, iRegL dst, iRegL src) %{ + match(Set dst (CMoveL (Binary cmp icc) (Binary dst src))); + ins_cost(150); + size(4); + format %{ "MOV$cmp $dst,$src\t! long" %} + ins_encode %{ + __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} +#endif + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +// 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); +#ifdef AARCH64 + format %{ "MOV$cmp $dst,ZR" %} +#else + format %{ "MOV$cmp $dst,$src" %} +#endif + ins_encode %{ +#ifdef AARCH64 + __ mov($dst$$Register, ZR, (AsmCondition)($cmp$$cmpcode)); +#else + __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); +#endif + %} + 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); +#ifdef AARCH64 + format %{ "MOV$cmp $dst,ZR\t! ptr" %} +#else + format %{ "MOV$cmp $dst,$src\t! ptr" %} +#endif + ins_encode %{ +#ifdef AARCH64 + __ mov($dst$$Register, ZR, (AsmCondition)($cmp$$cmpcode)); +#else + __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); +#endif + %} + 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); +#ifdef AARCH64 + format %{ "MOV$cmp $dst,ZR\t! ptr" %} +#else + format %{ "MOV$cmp $dst,$src\t! ptr" %} +#endif + ins_encode %{ +#ifdef AARCH64 + __ mov($dst$$Register, ZR, (AsmCondition)($cmp$$cmpcode)); +#else + __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); +#endif + %} + 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); +#ifdef AARCH64 + format %{ "MOV$cmp $dst,ZR\t! ptr" %} +#else + format %{ "MOV$cmp $dst,$src\t! ptr" %} +#endif + ins_encode %{ +#ifdef AARCH64 + __ mov($dst$$Register, ZR, (AsmCondition)($cmp$$cmpcode)); +#else + __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); +#endif + %} + ins_pipe(ialu_imm); +%} + +#ifdef AARCH64 +// Conditional move +instruct cmovF_reg(cmpOp cmp, flagsReg icc, regF dst, regF src1, regF src2) %{ + match(Set dst (CMoveF (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "FCSEL_s $dst,$src1,$src2,$cmp" %} + ins_encode %{ + __ fcsel_s($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(int_conditional_float_move); +%} + +instruct cmovD_reg(cmpOp cmp, flagsReg icc, regD dst, regD src1, regD src2) %{ + match(Set dst (CMoveD (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "FCSEL_d $dst,$src1,$src2,$cmp" %} + ins_encode %{ + __ fcsel_d($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(int_conditional_float_move); +%} + +instruct cmovFP_reg(cmpOpP cmp, flagsRegP icc, regF dst, regF src1, regF src2) %{ + match(Set dst (CMoveF (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "FCSEL_s $dst,$src1,$src2,$cmp" %} + ins_encode %{ + __ fcsel_s($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(int_conditional_float_move); +%} + +instruct cmovDP_reg(cmpOpP cmp, flagsRegP icc, regD dst, regD src1, regD src2) %{ + match(Set dst (CMoveD (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "FCSEL_d $dst,$src1,$src2,$cmp" %} + ins_encode %{ + __ fcsel_d($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(int_conditional_float_move); +%} + +instruct cmovFU_reg(cmpOpU cmp, flagsRegU icc, regF dst, regF src1, regF src2) %{ + match(Set dst (CMoveF (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "FCSEL_s $dst,$src1,$src2,$cmp" %} + ins_encode %{ + __ fcsel_s($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(int_conditional_float_move); +%} + +instruct cmovDU_reg(cmpOpU cmp, flagsRegU icc, regD dst, regD src1, regD src2) %{ + match(Set dst (CMoveD (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "FCSEL_d $dst,$src1,$src2,$cmp" %} + ins_encode %{ + __ fcsel_d($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(int_conditional_float_move); +%} + +instruct cmovFZ_reg(cmpOp0 cmp, flagsReg_EQNELTGE icc, regF dst, regF src1, regF src2) %{ + match(Set dst (CMoveF (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "FCSEL_s $dst,$src1,$src2,$cmp" %} + ins_encode %{ + __ fcsel_s($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(int_conditional_float_move); +%} + +instruct cmovDZ_reg(cmpOp0 cmp, flagsReg_EQNELTGE icc, regD dst, regD src1, regD src2) %{ + match(Set dst (CMoveD (Binary cmp icc) (Binary src2 src1))); + ins_cost(150); + size(4); + format %{ "FCSEL_d $dst,$src1,$src2,$cmp" %} + ins_encode %{ + __ fcsel_d($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(int_conditional_float_move); +%} + +#else // !AARCH64 + +// 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); +%} +#endif // !AARCH64 + + +//----------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); +%} + +//----------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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +#ifdef AARCH64 +#ifdef TODO +instruct addshlL_reg_imm_reg(iRegL dst, iRegL src1, immU6 src2, iRegL src3) %{ + match(Set dst (AddL (LShiftL src1 src2) src3)); + + size(4); + format %{ "ADD $dst,$src3,$src1<<$src2\t! long" %} + ins_encode %{ + __ add($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} +#endif +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifdef AARCH64 +// unshifted I2L operand +operand unshiftedI2L(iRegI src2) %{ +//constraint(ALLOC_IN_RC(sp_ptr_reg)); + match(ConvI2L src2); + + op_cost(1); + format %{ "$src2.w" %} + interface(MEMORY_INTER) %{ + base($src2); + index(0xff); + scale(0x0); + disp(0x0); + %} +%} + +// shifted I2L operand +operand shiftedI2L(iRegI src2, immI_0_4 src3) %{ +//constraint(ALLOC_IN_RC(sp_ptr_reg)); + match(LShiftX (ConvI2L src2) src3); + + op_cost(1); + format %{ "$src2.w << $src3" %} + interface(MEMORY_INTER) %{ + base($src2); + index(0xff); + scale($src3); + disp(0x0); + %} +%} + +opclass shiftedRegI(shiftedI2L, unshiftedI2L); + +instruct shlL_reg_regI(iRegL dst, iRegI src1, immU6 src2) %{ + match(Set dst (LShiftL (ConvI2L src1) src2)); + + size(4); + format %{ "LSL $dst,$src1.w,$src2\t! ptr" %} + ins_encode %{ + int c = $src2$$constant; + int r = 64 - c; + int s = 31; + if (s >= r) { + s = r - 1; + } + __ sbfm($dst$$Register, $src1$$Register, r, s); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addP_reg_regI(iRegP dst, iRegP src1, shiftedRegI src2) %{ + match(Set dst (AddP src1 src2)); + + ins_cost(DEFAULT_COST * 3/2); + size(4); + format %{ "ADD $dst,$src1,$src2, sxtw\t! ptr" %} + ins_encode %{ + Register base = reg_to_register_object($src2$$base); + __ add($dst$$Register, $src1$$Register, base, ex_sxtw, $src2$$scale); + %} + ins_pipe(ialu_reg_reg); +%} +#endif + +// 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 +#ifdef AARCH64 +instruct addL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ + match(Set dst (AddL src1 src2)); + size(4); + format %{ "ADD $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ add($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addL_reg_regI(iRegL dst, iRegL src1, shiftedRegI src2) %{ + match(Set dst (AddL src1 src2)); + + ins_cost(DEFAULT_COST * 3/2); + size(4); + format %{ "ADD $dst,$src1,$src2, sxtw\t! long" %} + ins_encode %{ + Register base = reg_to_register_object($src2$$base); + __ add($dst$$Register, $src1$$Register, base, ex_sxtw, $src2$$scale); + %} + ins_pipe(ialu_reg_reg); +%} +#else +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); +%} +#endif + +#ifdef AARCH64 +// Immediate Addition +instruct addL_reg_aimm(iRegL dst, iRegL src1, aimmL src2) %{ + match(Set dst (AddL src1 src2)); + + size(4); + format %{ "ADD $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ add($dst$$Register, $src1$$Register, $src2$$constant); + %} + ins_pipe(ialu_reg_imm); +%} + +instruct addL_reg_immLneg(iRegL dst, iRegL src1, aimmLneg src2) %{ + match(Set dst (SubL src1 src2)); + + size(4); + format %{ "ADD $dst,$src1,-($src2)\t! long" %} + ins_encode %{ + __ add($dst$$Register, $src1$$Register, -$src2$$constant); + %} + ins_pipe(ialu_reg_imm); +%} +#else +// TODO +#endif + +#ifndef AARCH64 +// 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); +%} +#endif + +//----------Conditional_store-------------------------------------------------- +// Conditional-store of the updated heap-top. +// Used during allocation of the shared heap. +// Sets flags (EQ) on success. + +// TODO: optimize out barriers with AArch64 load-acquire/store-release +// LoadP-locked. +instruct loadPLocked(iRegP dst, memoryex mem) %{ + match(Set dst (LoadPLocked mem)); + size(4); + format %{ "LDREX $dst,$mem" %} + ins_encode %{ +#ifdef AARCH64 + Register base = reg_to_register_object($mem$$base); + __ ldxr($dst$$Register, base); +#else + __ ldrex($dst$$Register,$mem$$Address); +#endif + %} + 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 %{ +#ifdef AARCH64 + Register base = reg_to_register_object($heap_top_ptr$$base); + __ stxr($tmp$$Register, $newval$$Register, base); +#else + __ strex($tmp$$Register, $newval$$Register, $heap_top_ptr$$Address); +#endif + __ 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 ) %{ +#ifdef AARCH64 + match(Set icc (StoreLConditional mem (Binary oldval newval))); + effect( TEMP tmp ); + size(28); + format %{ "loop:\n\t" + "LDXR $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem], DOESN'T set $newval=[$mem] in any case\n\t" + "SUBS $tmp, $tmp, $oldval\n\t" + "B.ne done\n\t" + "STXR $tmp, $newval, $mem\n\t" + "CBNZ_w $tmp, loop\n\t" + "CMP $tmp, 0\n\t" + "done:\n\t" + "membar LoadStore|LoadLoad" %} +#else + 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" %} +#endif + ins_encode %{ + Label loop; + __ bind(loop); +#ifdef AARCH64 +// FIXME: use load-acquire/store-release, remove membar? + Label done; + Register base = reg_to_register_object($mem$$base); + __ ldxr($tmp$$Register, base); + __ subs($tmp$$Register, $tmp$$Register, $oldval$$Register); + __ b(done, ne); + __ stxr($tmp$$Register, $newval$$Register, base); + __ cbnz_w($tmp$$Register, loop); + __ cmp($tmp$$Register, 0); + __ bind(done); +#else + __ 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); +#endif + // 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 + +#ifdef AARCH64 +// TODO: if combined with membar, elide membar and use +// load-acquire/store-release if appropriate +instruct compareAndSwapL_bool(memoryex mem, iRegL oldval, iRegL newval, iRegI res, iRegI tmp, flagsReg ccr) %{ + match(Set res (CompareAndSwapL mem (Binary oldval newval))); + effect( KILL ccr, TEMP tmp); + size(24); + format %{ "loop:\n\t" + "LDXR $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t" + "CMP $tmp, $oldval\n\t" + "B.ne done\n\t" + "STXR $tmp, $newval, $mem\n\t" + "CBNZ_w $tmp, loop\n\t" + "done:\n\t" + "CSET_w $res, eq" %} + ins_encode %{ + Register base = reg_to_register_object($mem$$base); + Label loop, done; + __ bind(loop); + __ ldxr($tmp$$Register, base); + __ cmp($tmp$$Register, $oldval$$Register); + __ b(done, ne); + __ stxr($tmp$$Register, $newval$$Register, base); + __ cbnz_w($tmp$$Register, loop); + __ bind(done); + __ cset_w($res$$Register, eq); + %} + 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(24); + format %{ "loop:\n\t" + "LDXR_w $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t" + "CMP_w $tmp, $oldval\n\t" + "B.ne done\n\t" + "STXR_w $tmp, $newval, $mem\n\t" + "CBNZ_w $tmp, loop\n\t" + "done:\n\t" + "CSET_w $res, eq" %} + ins_encode %{ + Register base = reg_to_register_object($mem$$base); + Label loop, done; + __ bind(loop); + __ ldxr_w($tmp$$Register, base); + __ cmp_w($tmp$$Register, $oldval$$Register); + __ b(done, ne); + __ stxr_w($tmp$$Register, $newval$$Register, base); + __ cbnz_w($tmp$$Register, loop); + __ bind(done); + __ cset_w($res$$Register, eq); + %} + ins_pipe( long_memory_op ); +%} + +// tmp must use iRegI instead of iRegN until 8051805 is fixed. +instruct compareAndSwapN_bool(memoryex mem, iRegN oldval, iRegN newval, iRegI res, iRegI tmp, flagsReg ccr) %{ + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + effect( KILL ccr, TEMP tmp); + size(24); + format %{ "loop:\n\t" + "LDXR_w $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t" + "CMP_w $tmp, $oldval\n\t" + "B.ne done\n\t" + "STXR_w $tmp, $newval, $mem\n\t" + "CBNZ_w $tmp, loop\n\t" + "done:\n\t" + "CSET_w $res, eq" %} + ins_encode %{ + Register base = reg_to_register_object($mem$$base); + Label loop, done; + __ bind(loop); + __ ldxr_w($tmp$$Register, base); + __ cmp_w($tmp$$Register, $oldval$$Register); + __ b(done, ne); + __ stxr_w($tmp$$Register, $newval$$Register, base); + __ cbnz_w($tmp$$Register, loop); + __ bind(done); + __ cset_w($res$$Register, eq); + %} + 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(24); + format %{ "loop:\n\t" + "LDXR $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t" + "CMP $tmp, $oldval\n\t" + "B.ne done\n\t" + "STXR $tmp, $newval, $mem\n\t" + "CBNZ_w $tmp, loop\n\t" + "done:\n\t" + "CSET_w $res, eq" %} + ins_encode %{ + Register base = reg_to_register_object($mem$$base); + Label loop, done; + __ bind(loop); + __ ldxr($tmp$$Register, base); + __ cmp($tmp$$Register, $oldval$$Register); + __ b(done, ne); + __ stxr($tmp$$Register, $newval$$Register, base); + __ cbnz_w($tmp$$Register, loop); + __ bind(done); + __ cset_w($res$$Register, eq); + %} + ins_pipe( long_memory_op ); +%} +#else // !AARCH64 +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 ); +%} +#endif // !AARCH64 + +#ifdef AARCH64 +instruct xaddI_aimmI_no_res(memoryex mem, aimmI add, Universe dummy, iRegI tmp1, iRegI tmp2) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddI mem add)); + effect(TEMP tmp1, TEMP tmp2); + size(16); + format %{ "loop:\n\t" + "LDXR_w $tmp1, $mem\n\t" + "ADD_w $tmp1, $tmp1, $add\n\t" + "STXR_w $tmp2, $tmp1, $mem\n\t" + "CBNZ_w $tmp2, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldxr_w($tmp1$$Register, base); + __ add_w($tmp1$$Register, $tmp1$$Register, $add$$constant); + __ stxr_w($tmp2$$Register, $tmp1$$Register, base); + __ cbnz_w($tmp2$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} +#else +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 ); +%} +#endif + +#ifdef AARCH64 +instruct xaddI_reg_no_res(memoryex mem, iRegI add, Universe dummy, iRegI tmp1, iRegI tmp2) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddI mem add)); + effect(TEMP tmp1, TEMP tmp2); + size(16); + format %{ "loop:\n\t" + "LDXR_w $tmp1, $mem\n\t" + "ADD_w $tmp1, $tmp1, $add\n\t" + "STXR_w $tmp2, $tmp1, $mem\n\t" + "CBNZ_w $tmp2, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldxr_w($tmp1$$Register, base); + __ add_w($tmp1$$Register, $tmp1$$Register, $add$$Register); + __ stxr_w($tmp2$$Register, $tmp1$$Register, base); + __ cbnz_w($tmp2$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} +#else +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 ); +%} +#endif + +#ifdef AARCH64 +instruct xaddI_aimmI(memoryex mem, aimmI add, iRegI res, iRegI tmp1, iRegI tmp2) %{ + match(Set res (GetAndAddI mem add)); + effect(TEMP tmp1, TEMP tmp2, TEMP res); + size(16); + format %{ "loop:\n\t" + "LDXR_w $res, $mem\n\t" + "ADD_w $tmp1, $res, $add\n\t" + "STXR_w $tmp2, $tmp1, $mem\n\t" + "CBNZ_w $tmp2, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldxr_w($res$$Register, base); + __ add_w($tmp1$$Register, $res$$Register, $add$$constant); + __ stxr_w($tmp2$$Register, $tmp1$$Register, base); + __ cbnz_w($tmp2$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} +#else +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 ); +%} +#endif + +#ifdef AARCH64 +instruct xaddI_reg(memoryex mem, iRegI add, iRegI res, iRegI tmp1, iRegI tmp2) %{ + match(Set res (GetAndAddI mem add)); + effect(TEMP tmp1, TEMP tmp2, TEMP res); + size(16); + format %{ "loop:\n\t" + "LDXR_w $res, $mem\n\t" + "ADD_w $tmp1, $res, $add\n\t" + "STXR_w $tmp2, $tmp1, $mem\n\t" + "CBNZ_w $tmp2, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldxr_w($res$$Register, base); + __ add_w($tmp1$$Register, $res$$Register, $add$$Register); + __ stxr_w($tmp2$$Register, $tmp1$$Register, base); + __ cbnz_w($tmp2$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} +#else +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 ); +%} +#endif + +#ifdef AARCH64 +instruct xaddL_reg_no_res(memoryex mem, iRegL add, Universe dummy, iRegL tmp1, iRegI tmp2) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddL mem add)); + effect(TEMP tmp1, TEMP tmp2); + size(16); + format %{ "loop:\n\t" + "LDXR $tmp1, $mem\n\t" + "ADD $tmp1, $tmp1, $add\n\t" + "STXR $tmp2, $tmp1, $mem\n\t" + "CBNZ_w $tmp2, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldxr($tmp1$$Register, base); + __ add($tmp1$$Register, $tmp1$$Register, $add$$Register); + __ stxr($tmp2$$Register, $tmp1$$Register, base); + __ cbnz_w($tmp2$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} +#else +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 ); +%} +#endif + +#ifdef AARCH64 +instruct xaddL_imm_no_res(memoryex mem, aimmL add, Universe dummy, iRegL tmp1, iRegI tmp2) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddL mem add)); + effect(TEMP tmp1, TEMP tmp2); + size(16); + format %{ "loop:\n\t" + "LDXR $tmp1, $mem\n\t" + "ADD $tmp1, $tmp1, $add\n\t" + "STXR $tmp2, $tmp1, $mem\n\t" + "CBNZ_w $tmp2, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldxr($tmp1$$Register, base); + __ add($tmp1$$Register, $tmp1$$Register, $add$$constant); + __ stxr($tmp2$$Register, $tmp1$$Register, base); + __ cbnz_w($tmp2$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} +#else +// 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 ); +%} +#endif + +#ifdef AARCH64 +instruct xaddL_reg(memoryex mem, iRegL add, iRegL res, iRegL tmp1, iRegI tmp2) %{ + match(Set res (GetAndAddL mem add)); + effect(TEMP tmp1, TEMP tmp2, TEMP res); + size(16); + format %{ "loop:\n\t" + "LDXR $res, $mem\n\t" + "ADD $tmp1, $res, $add\n\t" + "STXR $tmp2, $tmp1, $mem\n\t" + "CBNZ_w $tmp2, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldxr($res$$Register, base); + __ add($tmp1$$Register, $res$$Register, $add$$Register); + __ stxr($tmp2$$Register, $tmp1$$Register, base); + __ cbnz_w($tmp2$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} +#else +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 ); +%} +#endif + +#ifdef AARCH64 +instruct xaddL_imm(memoryex mem, aimmL add, iRegL res, iRegL tmp1, iRegI tmp2) %{ + match(Set res (GetAndAddL mem add)); + effect(TEMP tmp1, TEMP tmp2, TEMP res); + size(16); + format %{ "loop:\n\t" + "LDXR $res, $mem\n\t" + "ADD $tmp1, $res, $add\n\t" + "STXR $tmp2, $tmp1, $mem\n\t" + "CBNZ_w $tmp2, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldxr($res$$Register, base); + __ add($tmp1$$Register, $res$$Register, $add$$constant); + __ stxr($tmp2$$Register, $tmp1$$Register, base); + __ cbnz_w($tmp2$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} +#else +// 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 ); +%} +#endif + +#ifdef AARCH64 +instruct xchgI(memoryex mem, iRegI newval, iRegI res, iRegI tmp) %{ + match(Set res (GetAndSetI mem newval)); + effect(TEMP tmp, TEMP res); + size(12); + format %{ "loop:\n\t" + "LDXR_w $res, $mem\n\t" + "STXR_w $tmp, $newval, $mem\n\t" + "CBNZ_w $tmp, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldxr_w($res$$Register, base); + __ stxr_w($tmp$$Register, $newval$$Register, base); + __ cbnz_w($tmp$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} + +#ifdef XXX +// Disabled until 8051805 is fixed. +instruct xchgN(memoryex mem, iRegN newval, iRegN res, iRegN tmp) %{ + match(Set res (GetAndSetN mem newval)); + effect(TEMP tmp, TEMP res); + size(12); + format %{ "loop:\n\t" + "LDXR_w $res, $mem\n\t" + "STXR_w $tmp, $newval, $mem\n\t" + "CBNZ_w $tmp, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldxr_w($res$$Register, base); + __ stxr_w($tmp$$Register, $newval$$Register, base); + __ cbnz_w($tmp$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} +#endif +#else +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 ); +%} +#endif + +#ifdef AARCH64 +instruct xchgL(memoryex mem, iRegL newval, iRegL res, iRegI tmp) %{ + match(Set res (GetAndSetL mem newval)); + effect(TEMP tmp, TEMP res); + size(12); + format %{ "loop:\n\t" + "LDXR $res, $mem\n\t" + "STXR $tmp, $newval, $mem\n\t" + "CBNZ_w $tmp, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldxr($res$$Register, base); + __ stxr($tmp$$Register, $newval$$Register, base); + __ cbnz_w($tmp$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} +#else +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 ); +%} +#endif // !AARCH64 + +#ifdef AARCH64 +instruct xchgP(memoryex mem, iRegP newval, iRegP res, iRegI tmp) %{ + match(Set res (GetAndSetP mem newval)); + effect(TEMP tmp, TEMP res); + size(12); + format %{ "loop:\n\t" + "LDREX $res, $mem\n\t" + "STREX $tmp, $newval, $mem\n\t" + "CBNZ_w $tmp, loop" %} + + ins_encode %{ + Label loop; + Register base = reg_to_register_object($mem$$base); + __ bind(loop); + __ ldrex($res$$Register, base); + __ strex($tmp$$Register, $newval$$Register, base); + __ cbnz_w($tmp$$Register, loop); + %} + ins_pipe( long_memory_op ); +%} +#else +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 ); +%} +#endif // !AARCH64 + +//--------------------- +// 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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +// 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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +// Register Subtraction +#ifdef AARCH64 +instruct subL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ + match(Set dst (SubL src1 src2)); + + size(4); + format %{ "SUB $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ sub($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg_reg); +%} +#else +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); +%} +#endif + +#ifdef AARCH64 +// Immediate Subtraction +instruct subL_reg_aimm(iRegL dst, iRegL src1, aimmL src2) %{ + match(Set dst (SubL src1 src2)); + + size(4); + format %{ "SUB $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ sub($dst$$Register, $src1$$Register, $src2$$constant); + %} + ins_pipe(ialu_reg_imm); +%} + +instruct subL_reg_immLneg(iRegL dst, iRegL src1, aimmLneg src2) %{ + match(Set dst (AddL src1 src2)); + + size(4); + format %{ "SUB $dst,$src1,-($src2)\t! long" %} + ins_encode %{ + __ sub($dst$$Register, $src1$$Register, -$src2$$constant); + %} + ins_pipe(ialu_reg_imm); +%} +#else +// TODO +#endif + +#ifndef AARCH64 +// 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); +%} +#endif // !AARCH64 + +// 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); +%} + +#ifdef AARCH64 +instruct mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ + match(Set dst (MulL src1 src2)); + size(4); + format %{ "MUL $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ mul($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(imul_reg_reg); +%} +#else +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); + %} +%} +#endif // !AARCH64 + +// Integer Division +// Register Division +#ifdef AARCH64 +instruct divI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ + match(Set dst (DivI src1 src2)); + + size(4); + format %{ "SDIV $dst,$src1,$src2\t! 32-bit" %} + ins_encode %{ + __ sdiv_w($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg_reg); // FIXME +%} +#else +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); +%} +#endif + +// Register Long Division +#ifdef AARCH64 +instruct divL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ + match(Set dst (DivL src1 src2)); + + size(4); + format %{ "SDIV $dst,$src1,$src2" %} + ins_encode %{ + __ sdiv($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg_reg); // FIXME +%} +#else +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); +%} +#endif + +// Integer Remainder +// Register Remainder +#ifdef AARCH64 +#ifdef TODO +instruct msubI_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{ + match(Set dst (SubI src1 (MulI src2 src3))); + + size(4); + format %{ "MSUB $dst,$src2,$src3,$src1\t! 32-bit\n\t" %} + ins_encode %{ + __ msub_w($dst$$Register, $src2$$Register, $src3$$Register, $src1$$Register); + %} + ins_pipe(ialu_reg_reg); // FIXME +%} +#endif + +instruct modI_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI temp) %{ + match(Set dst (ModI src1 src2)); + effect(TEMP temp); + + size(8); + format %{ "SDIV $temp,$src1,$src2\t! 32-bit\n\t" + "MSUB $dst,$src2,$temp,$src1\t! 32-bit\n\t" %} + ins_encode %{ + __ sdiv_w($temp$$Register, $src1$$Register, $src2$$Register); + __ msub_w($dst$$Register, $src2$$Register, $temp$$Register, $src1$$Register); + %} + ins_pipe(ialu_reg_reg); // FIXME +%} +#else +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); +%} +#endif + +// Register Long Remainder +#ifdef AARCH64 +instruct modL_reg_reg(iRegL dst, iRegL src1, iRegL src2, iRegL temp) %{ + match(Set dst (ModL src1 src2)); + effect(TEMP temp); + + size(8); + format %{ "SDIV $temp,$src1,$src2\n\t" + "MSUB $dst,$src2,$temp,$src1" %} + ins_encode %{ + __ sdiv($temp$$Register, $src1$$Register, $src2$$Register); + __ msub($dst$$Register, $src2$$Register, $temp$$Register, $src1$$Register); + %} + ins_pipe(ialu_reg_reg); // FIXME +%} +#else +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); +%} +#endif + +// Integer Shift Instructions + +// Register Shift Left +instruct shlI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ + match(Set dst (LShiftI src1 src2)); + + size(4); +#ifdef AARCH64 + format %{ "LSLV $dst,$src1,$src2\t! int" %} + ins_encode %{ + __ lslv_w($dst$$Register, $src1$$Register, $src2$$Register); + %} +#else + format %{ "LSL $dst,$src1,$src2 \n\t" %} + ins_encode %{ + __ mov($dst$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register)); + %} +#endif + 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); +#ifdef AARCH64 + format %{ "LSL_w $dst,$src1,$src2\t! int" %} + ins_encode %{ + __ _lsl($dst$$Register, $src1$$Register, $src2$$constant); + %} +#else + format %{ "LSL $dst,$src1,$src2\t! int" %} + ins_encode %{ + __ logical_shift_left($dst$$Register, $src1$$Register, $src2$$constant); + %} +#endif + ins_pipe(ialu_reg_imm); +%} + +#ifndef AARCH64 +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); +%} +#endif // !AARCH64 + +instruct shlL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{ + match(Set dst (LShiftL src1 src2)); + +#ifdef AARCH64 + size(4); + format %{ "LSLV $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ lslv($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg_reg); +#else + 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); + %} +#endif +%} + +#ifdef AARCH64 +instruct shlL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{ + match(Set dst (LShiftL src1 src2)); + + size(4); + format %{ "LSL $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ logical_shift_left($dst$$Register, $src1$$Register, $src2$$constant); + %} + ins_pipe(ialu_reg_imm); +%} +#else +// 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); +%} +#endif // !AARCH64 + +// Register Arithmetic Shift Right +instruct sarI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ + match(Set dst (RShiftI src1 src2)); + size(4); +#ifdef AARCH64 + format %{ "ASRV $dst,$src1,$src2\t! int" %} + ins_encode %{ + __ asrv_w($dst$$Register, $src1$$Register, $src2$$Register); + %} +#else + format %{ "ASR $dst,$src1,$src2\t! int" %} + ins_encode %{ + __ mov($dst$$Register, AsmOperand($src1$$Register, asr, $src2$$Register)); + %} +#endif + 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); +#ifdef AARCH64 + format %{ "ASR_w $dst,$src1,$src2" %} + ins_encode %{ + __ _asr_w($dst$$Register, $src1$$Register, $src2$$constant); + %} +#else + format %{ "ASR $dst,$src1,$src2" %} + ins_encode %{ + __ mov($dst$$Register, AsmOperand($src1$$Register, asr, $src2$$constant)); + %} +#endif + ins_pipe(ialu_reg_imm); +%} + +#ifndef AARCH64 +// 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); +%} +#endif // !AARCH64 + +instruct sarL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{ + match(Set dst (RShiftL src1 src2)); + +#ifdef AARCH64 + size(4); + format %{ "ASRV $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ asrv($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg_reg); +#else + 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); + %} +#endif +%} + +// Register Shift Left Immediate +#ifdef AARCH64 +instruct sarL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{ + match(Set dst (RShiftL src1 src2)); + + size(4); + format %{ "ASR $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ _asr($dst$$Register, $src1$$Register, $src2$$constant); + %} + ins_pipe(ialu_reg_imm); +%} +#else +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); +%} +#endif + +// Register Shift Right +instruct shrI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ + match(Set dst (URShiftI src1 src2)); + size(4); +#ifdef AARCH64 + format %{ "LSRV $dst,$src1,$src2\t! int" %} + ins_encode %{ + __ lsrv_w($dst$$Register, $src1$$Register, $src2$$Register); + %} +#else + format %{ "LSR $dst,$src1,$src2\t! int" %} + ins_encode %{ + __ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register)); + %} +#endif + 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); +#ifdef AARCH64 + format %{ "LSR_w $dst,$src1,$src2" %} + ins_encode %{ + __ _lsr_w($dst$$Register, $src1$$Register, $src2$$constant); + %} +#else + format %{ "LSR $dst,$src1,$src2" %} + ins_encode %{ + __ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant)); + %} +#endif + ins_pipe(ialu_reg_imm); +%} + +#ifndef AARCH64 +// 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); +%} +#endif // !AARCH64 + +instruct shrL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{ + match(Set dst (URShiftL src1 src2)); + +#ifdef AARCH64 + size(4); + format %{ "LSRV $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ lsrv($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg_reg); +#else + 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); + %} +#endif +%} + +// Register Shift Right Immediate +#ifdef AARCH64 +instruct shrL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{ + match(Set dst (URShiftL src1 src2)); + + size(4); + format %{ "LSR $dst,$src1,$src2" %} + ins_encode %{ + __ _lsr($dst$$Register, $src1$$Register, $src2$$constant); + %} + ins_pipe(ialu_reg_imm); +%} +#else +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); +%} +#endif // !AARCH64 + + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +// Register And Long +instruct andL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ + match(Set dst (AndL src1 src2)); + + ins_cost(DEFAULT_COST); +#ifdef AARCH64 + size(4); + format %{ "AND $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ andr($dst$$Register, $src1$$Register, $src2$$Register); + %} +#else + 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()); + %} +#endif + ins_pipe(ialu_reg_reg); +%} + +#ifdef AARCH64 +// Immediate And +instruct andL_reg_limm(iRegL dst, iRegL src1, limmL src2) %{ + match(Set dst (AndL src1 src2)); + + size(4); + format %{ "AND $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ andr($dst$$Register, $src1$$Register, (uintx)$src2$$constant); + %} + ins_pipe(ialu_reg_imm); +%} +#else +// 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); +%} +#endif + +// 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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +#ifdef AARCH64 + size(4); + format %{ "OR $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ orr($dst$$Register, $src1$$Register, $src2$$Register); + %} +#else + 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()); + %} +#endif + ins_pipe(ialu_reg_reg); +%} + +#ifdef AARCH64 +instruct orL_reg_limm(iRegL dst, iRegL src1, limmL src2) %{ + match(Set dst (OrL src1 src2)); + + size(4); + format %{ "ORR $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ orr($dst$$Register, $src1$$Register, (uintx)$src2$$constant); + %} + ins_pipe(ialu_reg_imm); +%} +#else +// 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); +%} +#endif + +#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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +#ifdef AARCH64 + size(4); + format %{ "XOR $dst,$src1,$src2\t! long" %} + ins_encode %{ + __ eor($dst$$Register, $src1$$Register, $src2$$Register); + %} +#else + 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()); + %} +#endif + ins_pipe(ialu_reg_reg); +%} + +#ifdef AARCH64 +instruct xorL_reg_limmL(iRegL dst, iRegL src1, limmL con) %{ + match(Set dst (XorL src1 con)); + ins_cost(DEFAULT_COST); + size(4); + format %{ "EOR $dst,$src1,$con\t! long" %} + ins_encode %{ + __ eor($dst$$Register, $src1$$Register, (uintx)$con$$constant); + %} + ins_pipe(ialu_reg_imm); +%} +#else +// 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); +%} +#endif // AARCH64 + +//----------Convert to Boolean------------------------------------------------- +instruct convI2B( iRegI dst, iRegI src, flagsReg ccr ) %{ + match(Set dst (Conv2B src)); + effect(KILL ccr); +#ifdef AARCH64 + size(8); + ins_cost(DEFAULT_COST*2); + format %{ "cmp_32 $src,ZR\n\t" + "cset_w $dst, ne" %} + ins_encode %{ + __ cmp_32($src$$Register, ZR); + __ cset_w($dst$$Register, ne); + %} +#else + 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); + %} +#endif + ins_pipe(ialu_reg_ialu); +%} + +instruct convP2B( iRegI dst, iRegP src, flagsReg ccr ) %{ + match(Set dst (Conv2B src)); + effect(KILL ccr); +#ifdef AARCH64 + size(8); + ins_cost(DEFAULT_COST*2); + format %{ "CMP $src,ZR\n\t" + "cset $dst, ne" %} + ins_encode %{ + __ cmp($src$$Register, ZR); + __ cset($dst$$Register, ne); + %} +#else + 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); + %} +#endif + 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 ); +#ifdef AARCH64 + size(8); + ins_cost(DEFAULT_COST*2); + format %{ "CMP_w $p,$q\n\t" + "CSETM_w $dst, lt" %} + ins_encode %{ + __ cmp_w($p$$Register, $q$$Register); + __ csetm_w($dst$$Register, lt); + %} +#else + 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); + %} +#endif + 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 ); +#ifdef AARCH64 + size(8); + ins_cost(DEFAULT_COST*2); + format %{ "CMP_w $p,$q\n\t" + "CSETM_w $dst, lt" %} + ins_encode %{ + __ cmp_w($p$$Register, $q$$constant); + __ csetm_w($dst$$Register, lt); + %} +#else + 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); + %} +#endif + ins_pipe(ialu_reg_reg_ialu); +%} + +#ifdef AARCH64 +instruct cadd_cmpLTMask3( iRegI dst, iRegI p, iRegI q, iRegI y, iRegI x, flagsReg ccr ) %{ + match(Set dst (AddI (AndI (CmpLTMask p q) y) x)); + effect( TEMP dst, KILL ccr ); + size(12); + ins_cost(DEFAULT_COST*3); + format %{ "CMP_w $p,$q\n\t" + "ADD_w $dst,$y,$x\n\t" + "CSEL_w $dst,$dst,$x,lt" %} + ins_encode %{ + __ cmp_w($p$$Register, $q$$Register); + __ add_w($dst$$Register, $y$$Register, $x$$Register); + __ csel_w($dst$$Register, $dst$$Register, $x$$Register, lt); + %} + ins_pipe( cadd_cmpltmask ); +%} +#else +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 ); +%} +#endif + +#ifdef AARCH64 +instruct cadd_cmpLTMask4( iRegI dst, iRegI p, aimmI q, iRegI y, iRegI x, flagsReg ccr ) %{ + match(Set dst (AddI (AndI (CmpLTMask p q) y) x)); + effect( TEMP dst, KILL ccr ); + size(12); + ins_cost(DEFAULT_COST*3); + format %{ "CMP_w $p,$q\n\t" + "ADD_w $dst,$y,$x\n\t" + "CSEL_w $dst,$dst,$x,lt" %} + ins_encode %{ + __ cmp_w($p$$Register, $q$$constant); + __ add_w($dst$$Register, $y$$Register, $x$$Register); + __ csel_w($dst$$Register, $dst$$Register, $x$$Register, lt); + %} + ins_pipe( cadd_cmpltmask ); +%} +#else +// 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 ); +%} +#endif // !AARCH64 + +#ifdef AARCH64 +instruct cadd_cmpLTMask( iRegI dst, iRegI p, iRegI q, iRegI y, flagsReg ccr ) %{ + match(Set dst (AddI (AndI (CmpLTMask p q) y) (SubI p q))); + effect( TEMP dst, KILL ccr ); + size(12); + ins_cost(DEFAULT_COST*3); + format %{ "SUBS_w $p,$p,$q\n\t" + "ADD_w $dst,$y,$p\n\t" + "CSEL_w $dst,$dst,$p,lt" %} + ins_encode %{ + __ subs_w($p$$Register, $p$$Register, $q$$Register); + __ add_w($dst$$Register, $y$$Register, $p$$Register); + __ csel_w($dst$$Register, $dst$$Register, $p$$Register, lt); + %} + ins_pipe( cadd_cmpltmask ); // FIXME +%} +#else +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 ); +%} +#endif + +//----------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. + +#ifdef AARCH64 +instruct convD2I_reg_reg(iRegI dst, regD src) %{ + match(Set dst (ConvD2I src)); + ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME + format %{ "FCVTZS_wd $dst, $src" %} + ins_encode %{ + __ fcvtzs_wd($dst$$Register, $src$$FloatRegister); + %} + ins_pipe(fcvtD2I); +%} + +instruct convD2L_reg_reg(iRegL dst, regD src) %{ + match(Set dst (ConvD2L src)); + ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME + format %{ "FCVTZS_xd $dst, $src" %} + ins_encode %{ + __ fcvtzs_xd($dst$$Register, $src$$FloatRegister); + %} + ins_pipe(fcvtD2L); +%} +#else +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); +%} +#endif + +// Convert a double to a long in a double register. +// If the double is a NAN, stuff a zero in instead. + +#ifndef AARCH64 +// 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); +%} +#endif + +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); +%} + +#ifdef AARCH64 +instruct convF2I_reg_reg(iRegI dst, regF src) %{ + match(Set dst (ConvF2I src)); + ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME + size(4); + format %{ "FCVTZS_ws $dst, $src" %} + ins_encode %{ + __ fcvtzs_ws($dst$$Register, $src$$FloatRegister); + %} + ins_pipe(fcvtF2I); +%} + +instruct convF2L_reg_reg(iRegL dst, regF src) %{ + match(Set dst (ConvF2L src)); + ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME + size(4); + format %{ "FCVTZS_xs $dst, $src" %} + ins_encode %{ + __ fcvtzs_xs($dst$$Register, $src$$FloatRegister); + %} + ins_pipe(fcvtF2L); +%} +#else +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); +%} +#endif + +#ifdef AARCH64 +instruct convI2D_reg_reg(iRegI src, regD dst) %{ + match(Set dst (ConvI2D src)); + ins_cost(DEFAULT_COST + MEMORY_REF_COST); // FIXME + size(4); + format %{ "SCVTF_dw $dst,$src" %} + ins_encode %{ + __ scvtf_dw($dst$$FloatRegister, $src$$Register); + %} + ins_pipe(fcvtI2D); +%} +#else +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); +%} +#endif + +instruct convI2F_reg_reg( regF dst, iRegI src ) %{ + match(Set dst (ConvI2F src)); + ins_cost(DEFAULT_COST + MEMORY_REF_COST); // FIXME +#ifdef AARCH64 + size(4); + format %{ "SCVTF_sw $dst,$src" %} + ins_encode %{ + __ scvtf_sw($dst$$FloatRegister, $src$$Register); + %} +#else + size(8); + format %{ "FMSR $dst,$src \n\t" + "FSITOS $dst, $dst"%} + ins_encode %{ + __ fmsr($dst$$FloatRegister, $src$$Register); + __ fsitos($dst$$FloatRegister, $dst$$FloatRegister); + %} +#endif + ins_pipe(fcvtI2F); +%} + +instruct convI2L_reg(iRegL dst, iRegI src) %{ + match(Set dst (ConvI2L src)); +#ifdef AARCH64 + size(4); + format %{ "SXTW $dst,$src\t! int->long" %} + ins_encode %{ + __ sxtw($dst$$Register, $src$$Register); + %} +#else + 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)); + %} +#endif + 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) ); +#ifdef AARCH64 + size(4); + format %{ "mov_w $dst,$src\t! zero-extend int to long" %} + ins_encode %{ + __ mov_w($dst$$Register, $src$$Register); + %} +#else + 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); + %} +#endif + ins_pipe(ialu_reg_reg); +%} + +// Zero-extend long +instruct zerox_long(iRegL dst, iRegL src, immL_32bits mask ) %{ + match(Set dst (AndL src mask) ); +#ifdef AARCH64 + size(4); + format %{ "mov_w $dst,$src\t! zero-extend long" %} + ins_encode %{ + __ mov_w($dst$$Register, $src$$Register); + %} +#else + 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); + %} +#endif + 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); +#ifdef AARCH64 + format %{ "FMOV_xd $dst,$src\t! MoveD2L" %} + ins_encode %{ + __ fmov_xd($dst$$Register, $src$$FloatRegister); + %} +#else + format %{ "FMRRD $dst,$src\t! MoveD2L" %} + ins_encode %{ + __ fmrrd($dst$$Register, $dst$$Register->successor(), $src$$FloatRegister); + %} +#endif + 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); +#ifdef AARCH64 + format %{ "FMOV_dx $dst,$src\t! MoveL2D" %} + ins_encode %{ + __ fmov_dx($dst$$FloatRegister, $src$$Register); + %} +#else + format %{ "FMDRR $dst,$src\t! MoveL2D" %} + ins_encode %{ + __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register->successor()); + %} +#endif + ins_pipe(ialu_reg_reg); // FIXME +%} + +//----------- +// Long to Double conversion + +#ifdef AARCH64 +instruct convL2D(regD dst, iRegL src) %{ + match(Set dst (ConvL2D src)); + ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME + size(4); + format %{ "SCVTF_dx $dst, $src" %} + ins_encode %{ + __ scvtf_dx($dst$$FloatRegister, $src$$Register); + %} + ins_pipe(fcvtL2D); +%} + +instruct convL2F(regF dst, iRegL src) %{ + match(Set dst (ConvL2F src)); + ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME + size(4); + format %{ "SCVTF_sx $dst, $src" %} + ins_encode %{ + __ scvtf_sx($dst$$FloatRegister, $src$$Register); + %} + ins_pipe(fcvtL2F); +%} +#else +// 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); +%} + +#ifndef AARCH64 +// 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); +%} +#endif + +// 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); + %} +%} +#endif // !AARCH64 + +instruct convL2I_reg(iRegI dst, iRegL src) %{ + match(Set dst (ConvL2I src)); + size(4); +#ifdef AARCH64 + format %{ "MOV_w $dst,$src\t! long->int" %} + ins_encode %{ + __ mov_w($dst$$Register, $src$$Register); + %} +#else + format %{ "MOV $dst,$src.lo\t! long->int" %} + ins_encode %{ + __ mov($dst$$Register, $src$$Register); + %} +#endif + ins_pipe(ialu_move_reg_I_to_L); +%} + +#ifndef AARCH64 +// 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); +%} +#endif + + +//----------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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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); +%} + +#ifdef AARCH64 +instruct compL_reg_reg(flagsReg xcc, iRegL op1, iRegL op2) +%{ + match(Set xcc (CmpL op1 op2)); + effect( DEF xcc, USE op1, USE op2 ); + + size(4); + format %{ "CMP $op1,$op2\t! long" %} + ins_encode %{ + __ cmp($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_cconly_reg_reg); +%} +#else +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); +%} +#endif + +#ifdef AARCH64 +instruct compL_reg_con(flagsReg xcc, iRegL op1, aimmL con) %{ + match(Set xcc (CmpL op1 con)); + effect( DEF xcc, USE op1, USE con ); + + size(8); + format %{ "CMP $op1,$con\t\t! long" %} + ins_encode %{ + __ cmp($op1$$Register, $con$$constant); + %} + + ins_pipe(ialu_cconly_reg_imm); +%} +#else +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); +%} +#endif + +/* 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); + +#ifdef AARCH64 + size(4); + format %{ "FCMP_s $src1,$src2" %} + ins_encode %{ + __ fcmp_s($src1$$FloatRegister, $src2$$FloatRegister); + %} +#else + size(8); + format %{ "FCMPs $src1,$src2\n\t" + "FMSTAT" %} + ins_encode %{ + __ fcmps($src1$$FloatRegister, $src2$$FloatRegister); + __ fmstat(); + %} +#endif + 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); + +#ifdef AARCH64 + size(4); + format %{ "FCMP0_s $src1" %} + ins_encode %{ + __ fcmp0_s($src1$$FloatRegister); + %} +#else + size(8); + format %{ "FCMPs $src1,$src2\n\t" + "FMSTAT" %} + ins_encode %{ + __ fcmpzs($src1$$FloatRegister); + __ fmstat(); + %} +#endif + 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); + +#ifdef AARCH64 + size(4); + format %{ "FCMP_d $src1,$src2" %} + ins_encode %{ + __ fcmp_d($src1$$FloatRegister, $src2$$FloatRegister); + %} +#else + size(8); + format %{ "FCMPd $src1,$src2 \n\t" + "FMSTAT" %} + ins_encode %{ + __ fcmpd($src1$$FloatRegister, $src2$$FloatRegister); + __ fmstat(); + %} +#endif + 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); + +#ifdef AARCH64 + size(8); + format %{ "FCMP0_d $src1" %} + ins_encode %{ + __ fcmp0_d($src1$$FloatRegister); + %} +#else + size(8); + format %{ "FCMPZd $src1,$src2 \n\t" + "FMSTAT" %} + ins_encode %{ + __ fcmpzd($src1$$FloatRegister); + __ fmstat(); + %} +#endif + ins_pipe(faddD_fcc_reg_reg_zero); +%} + +#ifdef AARCH64 +// Compare floating, generate -1,0,1 +instruct cmpF_reg(iRegI dst, regF src1, regF src2, flagsReg icc) %{ + match(Set dst (CmpF3 src1 src2)); + // effect(KILL fcc); // nobody cares if flagsRegF is killed + effect(KILL icc); + ins_cost(DEFAULT_COST*3); // FIXME + size(12); + format %{ "FCMP_s $src1,$src2\n\t" + "CSET $dst, gt\n\t" + "CSINV $dst, $dst, ZR, ge" %} + ins_encode %{ + Register dst = $dst$$Register; + __ fcmp_s($src1$$FloatRegister, $src2$$FloatRegister); + __ cset(dst, gt); // 1 if '>', else 0 + __ csinv(dst, dst, ZR, ge); // previous value if '>=', else -1 + %} + ins_pipe( floating_cmp ); // FIXME +%} + +// Compare floating, generate -1,0,1 +instruct cmpD_reg(iRegI dst, regD src1, regD src2, flagsReg icc) %{ + match(Set dst (CmpD3 src1 src2)); + // effect(KILL fcc); // nobody cares if flagsRegF is killed + effect(KILL icc); + ins_cost(DEFAULT_COST*3); // FIXME + size(12); + format %{ "FCMP_d $src1,$src2\n\t" + "CSET $dst, gt\n\t" + "CSINV $dst, $dst, ZR, ge" %} + ins_encode %{ + Register dst = $dst$$Register; + __ fcmp_d($src1$$FloatRegister, $src2$$FloatRegister); + __ cset(dst, gt); // 1 if '>', else 0 + __ csinv(dst, dst, ZR, ge); // previous value if '>=', else -1 + %} + ins_pipe( floating_cmp ); // FIXME +%} + +// Compare floating, generate -1,0,1 +instruct cmpF0_reg(iRegI dst, regF src1, immF0 src2, flagsReg icc) %{ + match(Set dst (CmpF3 src1 src2)); + // effect(KILL fcc); // nobody cares if flagsRegF is killed + effect(KILL icc); + ins_cost(DEFAULT_COST*3); // FIXME + size(12); + format %{ "FCMP0_s $src1\n\t" + "CSET $dst, gt\n\t" + "CSINV $dst, $dst, ZR, ge" %} + ins_encode %{ + Register dst = $dst$$Register; + __ fcmp0_s($src1$$FloatRegister); + __ cset(dst, gt); // 1 if '>', else 0 + __ csinv(dst, dst, ZR, ge); // previous value if '>=', else -1 + %} + ins_pipe( floating_cmp ); // FIXME +%} + +// Compare floating, generate -1,0,1 +instruct cmpD0_reg(iRegI dst, regD src1, immD0 src2, flagsReg icc) %{ + match(Set dst (CmpD3 src1 src2)); + // effect(KILL fcc); // nobody cares if flagsRegF is killed + effect(KILL icc); + ins_cost(DEFAULT_COST*3); // FIXME + size(12); + format %{ "FCMP0_d $src1\n\t" + "CSET $dst, gt\n\t" + "CSINV $dst, $dst, ZR, ge" %} + ins_encode %{ + Register dst = $dst$$Register; + __ fcmp0_d($src1$$FloatRegister); + __ cset(dst, gt); // 1 if '>', else 0 + __ csinv(dst, dst, ZR, ge); // previous value if '>=', else -1 + %} + ins_pipe( floating_cmp ); // FIXME +%} +#else +// 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 ); +%} +#endif // !AARCH64 + +//----------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 + +#ifdef AARCH64 +instruct cbzI(cmpOp cmp, iRegI op1, immI0 op2, label labl) %{ + match(If cmp (CmpI op1 op2)); + 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 %{ "CB{N}Z $op1, $labl\t! int $cmp" %} + ins_encode %{ + if ($cmp$$cmpcode == eq) { + __ cbz_w($op1$$Register, *($labl$$label)); + } else { + __ cbnz_w($op1$$Register, *($labl$$label)); + } + %} + ins_pipe(br_cc); // FIXME +%} + +instruct cbzP(cmpOpP cmp, iRegP op1, immP0 op2, label labl) %{ + match(If cmp (CmpP op1 op2)); + 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 %{ "CB{N}Z $op1, $labl\t! ptr $cmp" %} + ins_encode %{ + if ($cmp$$cmpcode == eq) { + __ cbz($op1$$Register, *($labl$$label)); + } else { + __ cbnz($op1$$Register, *($labl$$label)); + } + %} + ins_pipe(br_cc); // FIXME +%} + +instruct cbzL(cmpOpL cmp, iRegL op1, immL0 op2, label labl) %{ + match(If cmp (CmpL op1 op2)); + 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 %{ "CB{N}Z $op1, $labl\t! long $cmp" %} + ins_encode %{ + if ($cmp$$cmpcode == eq) { + __ cbz($op1$$Register, *($labl$$label)); + } else { + __ cbnz($op1$$Register, *($labl$$label)); + } + %} + ins_pipe(br_cc); // FIXME +%} +#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); +%} + +#ifndef AARCH64 +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); +%} +#endif + +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. +#ifdef AARCH64 +instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg ccr) %{ + match(Set dst (CmpL3 src1 src2)); + // effect(KILL fcc); // nobody cares if flagsRegF is killed + effect(KILL ccr); + ins_cost(DEFAULT_COST*3); // FIXME + size(12); + format %{ "CMP $src1,$src2\n\t" + "CSET $dst, gt\n\t" + "CSINV $dst, $dst, ZR, ge" %} + ins_encode %{ + Register dst = $dst$$Register; + __ cmp($src1$$Register, $src2$$Register); + __ cset(dst, gt); // 1 if '>', else 0 + __ csinv(dst, dst, ZR, ge); // previous value if '>=', else -1 + %} + ins_pipe( ialu_cconly_reg_reg ); // FIXME +%} +// TODO cmpL3_reg_imm +#else +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); +%} +#endif + +#ifndef AARCH64 +// 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); +%} +#endif // !AARCH64 + +#ifndef AARCH64 +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); +%} +#endif // !AARCH64 + +#ifndef AARCH64 +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); +%} +#endif // !AARCH64 + +// ============================================================================ +// Safepoint Instruction +#ifdef AARCH64 +instruct safePoint_poll(iRegP poll, flagsReg icc, RtempRegP tmp) %{ + match(SafePoint poll); + // The handler stub kills Rtemp + effect(USE poll, KILL tmp, KILL icc); + + size(4); + format %{ "LDR ZR,[$poll]\t! Safepoint: poll for GC" %} + ins_encode %{ + __ relocate(relocInfo::poll_type); + __ ldr(ZR, Address($poll$$Register)); + %} + ins_pipe(loadPollP); +%} +#else +// 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); +%} +#endif + + +// ============================================================================ +// 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" %} +#ifdef AARCH64 + ins_encode( save_last_PC, Java_To_Runtime( meth ), + call_epilog ); +#else + ins_encode( Java_To_Runtime( meth ), + call_epilog ); +#endif + 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 %{ "breakpoint ; ShouldNotReachHere" %} + ins_encode %{ + __ breakpoint(); + %} + 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 + +#ifdef AARCH64 +instruct cmpFastLock(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2, iRegP scratch, iRegP scratch3 ) +#else +instruct cmpFastLock(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2, iRegP scratch ) +#endif +%{ + match(Set pcc (FastLock object box)); + +#ifdef AARCH64 + effect(TEMP scratch, TEMP scratch2, TEMP scratch3); +#else + effect(TEMP scratch, TEMP scratch2); +#endif + ins_cost(100); + +#ifdef AARCH64 + format %{ "FASTLOCK $object, $box; KILL $scratch, $scratch2, $scratch3" %} + ins_encode %{ + __ fast_lock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register, $scratch3$$Register); + %} +#else + format %{ "FASTLOCK $object, $box; KILL $scratch, $scratch2" %} + ins_encode %{ + __ fast_lock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register); + %} +#endif + ins_pipe(long_memory_op); +%} + + +#ifdef AARCH64 +instruct cmpFastUnlock(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2, iRegP scratch, iRegP scratch3 ) %{ + match(Set pcc (FastUnlock object box)); + effect(TEMP scratch, TEMP scratch2, TEMP scratch3); + ins_cost(100); + + format %{ "FASTUNLOCK $object, $box; KILL $scratch, $scratch2, $scratch3" %} + ins_encode %{ + __ fast_unlock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register, $scratch3$$Register); + %} + ins_pipe(long_memory_op); +%} +#else +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); +%} +#endif + +#ifdef AARCH64 +// TODO: add version that takes immI cnt? +instruct clear_array(iRegX cnt, iRegP base, iRegP ptr, iRegX temp, Universe dummy, flagsReg cpsr) %{ + match(Set dummy (ClearArray cnt base)); + effect(TEMP temp, TEMP ptr, KILL cpsr); + ins_cost(300); + format %{ + " MOV $temp,$cnt\n" + " ADD $ptr,$base,$cnt\n" + " SUBS $temp,$temp,16\t! Count down dword pair in bytes\n" + " B.lt done16\n" + "loop: STP ZR,ZR,[$ptr,-16]!\n" + " SUBS $temp,$temp,16\t! Count down dword pair in bytes\n" + " B.ge loop\t! Clearing loop\n" + "done16: ADDS $temp,$temp,8\t! Room for 1 more long?\n" + " B.lt done\n" + " STR ZR,[$base+$temp]\n" + "done:" + %} + ins_encode %{ + // TODO: preload? + __ mov($temp$$Register, $cnt$$Register); + __ add($ptr$$Register, $base$$Register, $cnt$$Register); + Label loop, done, done16; + __ subs($temp$$Register, $temp$$Register, 16); + __ b(done16, lt); + __ bind(loop); + __ stp(ZR, ZR, Address($ptr$$Register, -16, pre_indexed)); + __ subs($temp$$Register, $temp$$Register, 16); + __ b(loop, ge); + __ bind(done16); + __ adds($temp$$Register, $temp$$Register, 8); + __ b(done, lt); + // $temp should be 0 here + __ str(ZR, Address($base$$Register, $temp$$Register)); + __ bind(done); + %} + ins_pipe(long_memory_op); +%} +#else +// 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); +%} +#endif + +#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); +%} + +#ifdef AARCH64 +instruct countLeadingZerosL(iRegI dst, iRegL src) %{ + match(Set dst (CountLeadingZerosL src)); + size(4); + format %{ "CLZ $dst,$src" %} + ins_encode %{ + __ clz($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} +#else +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); +%} +#endif + +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); +%} + +#ifdef AARCH64 +instruct countTrailingZerosL(iRegI dst, iRegL src, iRegL tmp) %{ + match(Set dst (CountTrailingZerosL src)); + effect(TEMP tmp); + size(8); + format %{ "RBIT $tmp, $src\n\t" + "CLZ $dst,$tmp" %} + ins_encode %{ + __ rbit($tmp$$Register, $src$$Register); + __ clz($dst$$Register, $tmp$$Register); + %} + ins_pipe(ialu_reg); +%} +#else +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); +%} +#endif + + +//---------- Population Count Instructions ------------------------------------- + +#ifdef AARCH64 +instruct popCountI(iRegI dst, iRegI src, regD_low tmp) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI src)); + effect(TEMP tmp); + size(20); + + format %{ "MOV_W $dst,$src\n\t" + "FMOV_dx $tmp,$dst\n\t" + "VCNT $tmp.8B,$tmp.8B\n\t" + "ADDV $tmp.B,$tmp.8B\n\t" + "FMRS $dst,$tmp" %} + + ins_encode %{ + __ mov_w($dst$$Register, $src$$Register); + __ fmov_dx($tmp$$FloatRegister, $dst$$Register); + int quad = 0; + int cnt_size = 0; // VELEM_SIZE_8 + __ vcnt($tmp$$FloatRegister, $tmp$$FloatRegister, quad, cnt_size); + int add_size = 0; // VELEM_SIZE_8 + __ addv($tmp$$FloatRegister, $tmp$$FloatRegister, quad, add_size); + __ fmrs($dst$$Register, $tmp$$FloatRegister); + %} + ins_pipe(ialu_reg); // FIXME +%} +#else +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 +%} +#endif + +#ifdef AARCH64 +instruct popCountL(iRegI dst, iRegL src, regD tmp) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL src)); + effect(TEMP tmp); + size(16); + + format %{ "FMOV_dx $tmp,$src\n\t" + "VCNT $tmp.8B,$tmp.8B\n\t" + "ADDV $tmp.B,$tmp.8B\n\t" + "FMOV_ws $dst,$tmp" %} + + ins_encode %{ + __ fmov_dx($tmp$$FloatRegister, $src$$Register); + int quad = 0; + int cnt_size = 0; + __ vcnt($tmp$$FloatRegister, $tmp$$FloatRegister, quad, cnt_size); + int add_size = 0; + __ addv($tmp$$FloatRegister, $tmp$$FloatRegister, quad, add_size); + __ fmov_ws($dst$$Register, $tmp$$FloatRegister); + %} + ins_pipe(ialu_reg); // FIXME +%} +#else +// 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); +%} +#endif + + +// ============================================================================ +//------------Bytes reverse-------------------------------------------------- + +instruct bytes_reverse_int(iRegI dst, iRegI src) %{ + match(Set dst (ReverseBytesI src)); + + size(4); + format %{ "REV32 $dst,$src" %} + ins_encode %{ +#ifdef AARCH64 + __ rev_w($dst$$Register, $src$$Register); + // high 32 bits zeroed, not sign extended +#else + __ rev($dst$$Register, $src$$Register); +#endif + %} + ins_pipe( iload_mem ); // FIXME +%} + +instruct bytes_reverse_long(iRegL dst, iRegL src) %{ + match(Set dst (ReverseBytesL src)); +#ifdef AARCH64 +//size(4); + format %{ "REV $dst,$src" %} + ins_encode %{ + __ rev($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); // FIXME +#else + 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 +#endif +%} + +instruct bytes_reverse_unsigned_short(iRegI dst, iRegI src) %{ + match(Set dst (ReverseBytesUS src)); +#ifdef AARCH64 + size(4); + format %{ "REV16_W $dst,$src" %} + ins_encode %{ + __ rev16_w($dst$$Register, $src$$Register); + // high 32 bits zeroed + %} +#else + size(4); + format %{ "REV16 $dst,$src" %} + ins_encode %{ + __ rev16($dst$$Register, $src$$Register); + %} +#endif + ins_pipe( iload_mem ); // FIXME +%} + +instruct bytes_reverse_short(iRegI dst, iRegI src) %{ + match(Set dst (ReverseBytesS src)); +#ifdef AARCH64 + size(8); + format %{ "REV16_W $dst,$src\n\t" + "SIGN_EXT16 $dst" %} + ins_encode %{ + __ rev16_w($dst$$Register, $src$$Register); + __ sign_extend($dst$$Register, $dst$$Register, 16); + %} +#else + size(4); + format %{ "REVSH $dst,$src" %} + ins_encode %{ + __ revsh($dst$$Register, $src$$Register); + %} +#endif + 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 +%} + +#ifndef AARCH64 +// 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 +%} +#endif /* !AARCH64 */ + +// 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 +%} + +#ifndef AARCH64 +// 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 +%} +#endif /* !AARCH64 */ + +// 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 +%} + +#ifndef AARCH64 +// 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 +%} +#endif /* !AARCH64 */ + +// 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 +%} + + +#ifndef AARCH64 +// 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 +%} +#endif /* !AARCH64 */ + +// 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 +%} + +#ifndef AARCH64 +// 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 +%} +#endif /* !AARCH64 */ + +// 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 +%} + + +#ifndef AARCH64 +// 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 +%} +#endif /* !AARCH64 */ + +// 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 +%} + +#ifdef AARCH64 +// 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(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + + format %{ "VDUP.2D $dst.Q,$src\t" %} + ins_encode %{ + bool quad = true; + __ vdupI($dst$$FloatRegister, $src$$Register, + MacroAssembler::VELEM_SIZE_64, quad); + %} + ins_pipe(ialu_reg); // FIXME +%} +#else /* !AARCH64 */ +// 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); + %} +%} +#endif /* !AARCH64 */ + +// 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 +%} + +#ifndef AARCH64 +// 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 +%} +#endif /* !AARCH64 */ + +// 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 +%} + +#ifndef AARCH64 +// 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 +%} +#endif /* !AAARCH64 */ + +// Replicate scalar to packed double float values in Double register pair +instruct Repl2D_reg(vecX dst, regD src) %{ +#ifdef AARCH64 + predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd()); + match(Set dst (ReplicateD src)); + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + + format %{ "VDUP $dst.2D,$src\t" %} + ins_encode %{ + bool quad = true; + __ vdupD($dst$$FloatRegister, $src$$FloatRegister, quad); + %} +#else + 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); + %} +#endif + 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 +%} + +#ifndef AARCH64 +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 +%} +#endif + +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 +%} + +#ifdef AARCH64 +instruct vadd2D_reg_simd(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant()); + match(Set dst (AddVD src1 src2)); + size(4); + format %{ "VADD.F64 $dst.Q,$src1.Q,$src2.Q\t! add packed2D" %} + ins_encode %{ + bool quad = true; + __ vaddF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + MacroAssembler::VFA_SIZE_F64, quad); + %} + ins_pipe( faddD_reg_reg ); // FIXME +%} +#else +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 +%} +#endif + + +// 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 +%} + +#ifndef AARCH64 +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 +%} +#endif + + +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 +%} + +#ifdef AARCH64 +instruct vsub2D_reg_simd(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant()); + match(Set dst (SubVD src1 src2)); + size(4); + format %{ "VSUB.F64 $dst.Q,$src1.Q,$src2.Q\t! add packed2D" %} + ins_encode %{ + bool quad = true; + __ vsubF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + MacroAssembler::VFA_SIZE_F64, quad); + %} + ins_pipe( faddD_reg_reg ); // FIXME +%} +#else +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 +%} +#endif + +// 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 +%} + +#ifndef AARCH64 +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(), + $src1$$FloatRegister->successor(), + $src2$$FloatRegister->successor()); + %} + + ins_pipe(fmulF_reg_reg); // FIXME +%} +#endif + +instruct vmul4F_reg(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length() == 4 && VM_Version::simd_math_is_compliant()); + match(Set dst (MulVF src1 src2)); + size(4); + format %{ "VMUL.F32 $dst.Q,$src1.Q,$src2.Q\t! mul packed4F" %} + ins_encode %{ + __ vmulF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + MacroAssembler::VFA_SIZE_F32, 1); + %} + ins_pipe( fmulF_reg_reg ); // FIXME +%} + +#ifndef AARCH64 +instruct vmul4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length() == 4 && !VM_Version::simd_math_is_compliant()); + match(Set dst (MulVF src1 src2)); + size(4*4); + ins_cost(DEFAULT_COST*4); // FIXME + + format %{ "FMULS $dst.a,$src1.a,$src2.a\n\t" + "FMULS $dst.b,$src1.b,$src2.b\n\t" + "FMULS $dst.c,$src1.c,$src2.c\n\t" + "FMULS $dst.d,$src1.d,$src2.d" %} + + ins_encode %{ + FloatRegister dsta = $dst$$FloatRegister; + FloatRegister src1a = $src1$$FloatRegister; + FloatRegister src2a = $src2$$FloatRegister; + __ mul_float(dsta, src1a, src2a); + FloatRegister dstb = dsta->successor(); + FloatRegister src1b = src1a->successor(); + FloatRegister src2b = src2a->successor(); + __ mul_float(dstb, src1b, src2b); + FloatRegister dstc = dstb->successor(); + FloatRegister src1c = src1b->successor(); + FloatRegister src2c = src2b->successor(); + __ mul_float(dstc, src1c, src2c); + FloatRegister dstd = dstc->successor(); + FloatRegister src1d = src1c->successor(); + FloatRegister src2d = src2c->successor(); + __ mul_float(dstd, src1d, src2d); + %} + + ins_pipe(fmulF_reg_reg); // FIXME +%} +#endif + +#ifdef AARCH64 +instruct vmul2D_reg(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd()); + match(Set dst (MulVD src1 src2)); + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + + format %{ "FMUL.2D $dst,$src1,$src2\t! double[2]" %} + ins_encode %{ + int quad = 1; + __ vmulF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + MacroAssembler::VFA_SIZE_F64, quad); + %} + + ins_pipe(fdivF_reg_reg); // FIXME +%} +#else +instruct vmul2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (MulVD src1 src2)); + size(4*2); + ins_cost(DEFAULT_COST*2); // FIXME + + format %{ "FMULD $dst.D.a,$src1.D.a,$src2.D.a\n\t" + "FMULD $dst.D.b,$src1.D.b,$src2.D.b" %} + ins_encode %{ + FloatRegister dsta = $dst$$FloatRegister; + FloatRegister src1a = $src1$$FloatRegister; + FloatRegister src2a = $src2$$FloatRegister; + __ mul_double(dsta, src1a, src2a); + FloatRegister dstb = dsta->successor()->successor(); + FloatRegister src1b = src1a->successor()->successor(); + FloatRegister src2b = src2a->successor()->successor(); + __ mul_double(dstb, src1b, src2b); + %} + + ins_pipe(fmulD_reg_reg); // FIXME +%} +#endif + + +// Floats vector div +instruct vdiv2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (DivVF src1 src2)); +#ifdef AARCH64 + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + + format %{ "FDIV.2S $dst,$src1,$src2\t! float[2]" %} + ins_encode %{ + int quad = 0; + __ vdivF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + MacroAssembler::VFA_SIZE_F32, quad); + %} + + ins_pipe(fdivF_reg_reg); // FIXME +#else + size(4*2); + ins_cost(DEFAULT_COST*2); // FIXME + + format %{ "FDIVS $dst.a,$src1.a,$src2.a\n\t" + "FDIVS $dst.b,$src1.b,$src2.b" %} + ins_encode %{ + __ div_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); + __ div_float($dst$$FloatRegister->successor(), + $src1$$FloatRegister->successor(), + $src2$$FloatRegister->successor()); + %} + + ins_pipe(fdivF_reg_reg); // FIXME +#endif +%} + +instruct vdiv4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (DivVF src1 src2)); +#ifdef AARCH64 + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + + format %{ "FDIV.4S $dst,$src1,$src2\t! float[4]" %} + ins_encode %{ + int quad = 1; + __ vdivF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + MacroAssembler::VFA_SIZE_F32, quad); + %} + + ins_pipe(fdivF_reg_reg); // FIXME +#else + size(4*4); + ins_cost(DEFAULT_COST*4); // FIXME + + format %{ "FDIVS $dst.a,$src1.a,$src2.a\n\t" + "FDIVS $dst.b,$src1.b,$src2.b\n\t" + "FDIVS $dst.c,$src1.c,$src2.c\n\t" + "FDIVS $dst.d,$src1.d,$src2.d" %} + + ins_encode %{ + FloatRegister dsta = $dst$$FloatRegister; + FloatRegister src1a = $src1$$FloatRegister; + FloatRegister src2a = $src2$$FloatRegister; + __ div_float(dsta, src1a, src2a); + FloatRegister dstb = dsta->successor(); + FloatRegister src1b = src1a->successor(); + FloatRegister src2b = src2a->successor(); + __ div_float(dstb, src1b, src2b); + FloatRegister dstc = dstb->successor(); + FloatRegister src1c = src1b->successor(); + FloatRegister src2c = src2b->successor(); + __ div_float(dstc, src1c, src2c); + FloatRegister dstd = dstc->successor(); + FloatRegister src1d = src1c->successor(); + FloatRegister src2d = src2c->successor(); + __ div_float(dstd, src1d, src2d); + %} + + ins_pipe(fdivF_reg_reg); // FIXME +#endif +%} + +#ifdef AARCH64 +instruct vdiv2D_reg(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd()); + match(Set dst (DivVD src1 src2)); + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + + format %{ "FDIV.2D $dst,$src1,$src2\t! double[2]" %} + ins_encode %{ + int quad = 1; + __ vdivF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + MacroAssembler::VFA_SIZE_F64, quad); + %} + + ins_pipe(fdivF_reg_reg); // FIXME +%} +#else +instruct vdiv2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (DivVD src1 src2)); + size(4*2); + ins_cost(DEFAULT_COST*2); // FIXME + + format %{ "FDIVD $dst.D.a,$src1.D.a,$src2.D.a\n\t" + "FDIVD $dst.D.b,$src1.D.b,$src2.D.b" %} + ins_encode %{ + FloatRegister dsta = $dst$$FloatRegister; + FloatRegister src1a = $src1$$FloatRegister; + FloatRegister src2a = $src2$$FloatRegister; + __ div_double(dsta, src1a, src2a); + FloatRegister dstb = dsta->successor()->successor(); + FloatRegister src1b = src1a->successor()->successor(); + FloatRegister src2b = src2a->successor()->successor(); + __ div_double(dstb, src1b, src2b); + %} + + ins_pipe(fdivD_reg_reg); // FIXME +%} +#endif + +// --------------------------------- NEG -------------------------------------- + +instruct vneg8B_reg(vecD dst, vecD src) %{ + predicate(n->as_Vector()->length_in_bytes() == 8); + effect(DEF dst, USE src); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ "VNEG.S8 $dst.D,$src.D\t! neg packed8B" %} + ins_encode %{ + bool quad = false; + __ vnegI($dst$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vneg16B_reg(vecX dst, vecX src) %{ + predicate(n->as_Vector()->length_in_bytes() == 16); + effect(DEF dst, USE src); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ "VNEG.S8 $dst.Q,$src.Q\t! neg0 packed16B" %} + ins_encode %{ + bool _float = false; + bool quad = true; + __ vnegI($dst$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// ------------------------------ Shift --------------------------------------- + +instruct vslcntD(vecD dst, iRegI cnt) %{ + predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd()); + match(Set dst (LShiftCntV cnt)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + expand %{ + Repl8B_reg_simd(dst, cnt); + %} +%} + +instruct vslcntX(vecX dst, iRegI cnt) %{ + predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd()); + match(Set dst (LShiftCntV cnt)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + expand %{ + Repl16B_reg(dst, cnt); + %} +%} + +// Low bits of vector "shift" elements are used, so it +// doesn't matter if we treat it as ints or bytes here. +instruct vsrcntD(vecD dst, iRegI cnt) %{ + predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd()); + match(Set dst (RShiftCntV cnt)); + size(4*2); + ins_cost(DEFAULT_COST*2); // FIXME + + format %{ "VDUP.8 $dst.D,$cnt\n\t" + "VNEG.S8 $dst.D,$dst.D\t! neg packed8B" %} + ins_encode %{ + bool quad = false; + __ vdupI($dst$$FloatRegister, $cnt$$Register, + MacroAssembler::VELEM_SIZE_8, quad); + __ vnegI($dst$$FloatRegister, $dst$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsrcntX(vecX dst, iRegI cnt) %{ + predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd()); + match(Set dst (RShiftCntV cnt)); + size(4*2); + ins_cost(DEFAULT_COST*2); // FIXME + format %{ "VDUP.8 $dst.Q,$cnt\n\t" + "VNEG.S8 $dst.Q,$dst.Q\t! neg packed16B" %} + ins_encode %{ + bool quad = true; + __ vdupI($dst$$FloatRegister, $cnt$$Register, + MacroAssembler::VELEM_SIZE_8, quad); + __ vnegI($dst$$FloatRegister, $dst$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Byte vector logical left/right shift based on sign +instruct vsh8B_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 8); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.U8 $dst.D,$src.D,$shift.D\t! logical left/right shift packed8B" + %} + ins_encode %{ + bool quad = false; + __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsh16B_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 16); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.U8 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed16B" + %} + ins_encode %{ + bool quad = true; + __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Shorts/Char vector logical left/right shift based on sign +instruct vsh4S_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 4); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.U16 $dst.D,$src.D,$shift.D\t! logical left/right shift packed4S" + %} + ins_encode %{ + bool quad = false; + __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_16, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsh8S_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 8); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.U16 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed8S" + %} + ins_encode %{ + bool quad = true; + __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_16, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Integers vector logical left/right shift based on sign +instruct vsh2I_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 2); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.U32 $dst.D,$src.D,$shift.D\t! logical left/right shift packed2I" + %} + ins_encode %{ + bool quad = false; + __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_32, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsh4I_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 4); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.U32 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed4I" + %} + ins_encode %{ + bool quad = true; + __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_32, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Longs vector logical left/right shift based on sign +instruct vsh2L_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 2); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.U64 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed2L" + %} + ins_encode %{ + bool quad = true; + __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_64, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// ------------------------------ LeftShift ----------------------------------- + +// Byte vector left shift +instruct vsl8B_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (LShiftVB src shift)); + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + expand %{ + vsh8B_reg(dst, src, shift); + %} +%} + +instruct vsl16B_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 16); + match(Set dst (LShiftVB src shift)); + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + expand %{ + vsh16B_reg(dst, src, shift); + %} +%} + +instruct vsl8B_immI(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (LShiftVB src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.I8 $dst.D,$src.D,$shift\t! logical left shift packed8B" + %} + ins_encode %{ + bool quad = false; + __ vshli($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsl16B_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 16); + match(Set dst (LShiftVB src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.I8 $dst.Q,$src.Q,$shift\t! logical left shift packed16B" + %} + ins_encode %{ + bool quad = true; + __ vshli($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Shorts/Chars vector logical left/right shift +instruct vsl4S_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (LShiftVS src shift)); + match(Set dst (URShiftVS src shift)); + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + expand %{ + vsh4S_reg(dst, src, shift); + %} +%} + +instruct vsl8S_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (LShiftVS src shift)); + match(Set dst (URShiftVS src shift)); + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + expand %{ + vsh8S_reg(dst, src, shift); + %} +%} + +instruct vsl4S_immI(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (LShiftVS src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.I16 $dst.D,$src.D,$shift\t! logical left shift packed4S" + %} + ins_encode %{ + bool quad = false; + __ vshli($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsl8S_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (LShiftVS src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.I16 $dst.Q,$src.Q,$shift\t! logical left shift packed8S" + %} + ins_encode %{ + bool quad = true; + __ vshli($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Integers vector logical left/right shift +instruct vsl2I_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd()); + match(Set dst (LShiftVI src shift)); + match(Set dst (URShiftVI src shift)); + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + expand %{ + vsh2I_reg(dst, src, shift); + %} +%} + +instruct vsl4I_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 4 && VM_Version::has_simd()); + match(Set dst (LShiftVI src shift)); + match(Set dst (URShiftVI src shift)); + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + expand %{ + vsh4I_reg(dst, src, shift); + %} +%} + +instruct vsl2I_immI(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd()); + match(Set dst (LShiftVI src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.I32 $dst.D,$src.D,$shift\t! logical left shift packed2I" + %} + ins_encode %{ + bool quad = false; + __ vshli($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsl4I_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 4 && VM_Version::has_simd()); + match(Set dst (LShiftVI src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.I32 $dst.Q,$src.Q,$shift\t! logical left shift packed4I" + %} + ins_encode %{ + bool quad = true; + __ vshli($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Longs vector logical left/right shift +instruct vsl2L_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (LShiftVL src shift)); + match(Set dst (URShiftVL src shift)); + size(4*1); + ins_cost(DEFAULT_COST*1); // FIXME + expand %{ + vsh2L_reg(dst, src, shift); + %} +%} + +instruct vsl2L_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (LShiftVL src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.I64 $dst.Q,$src.Q,$shift\t! logical left shift packed2L" + %} + ins_encode %{ + bool quad = true; + __ vshli($dst$$FloatRegister, $src$$FloatRegister, 64, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// ----------------------- LogicalRightShift ----------------------------------- + +// Bytes/Shorts vector logical right shift produces incorrect Java result +// for negative data because java code convert short value into int with +// sign extension before a shift. + +// Chars vector logical right shift +instruct vsrl4S_immI(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (URShiftVS src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.U16 $dst.D,$src.D,$shift\t! logical right shift packed4S" + %} + ins_encode %{ + bool quad = false; + __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsrl8S_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (URShiftVS src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.U16 $dst.Q,$src.Q,$shift\t! logical right shift packed8S" + %} + ins_encode %{ + bool quad = true; + __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Integers vector logical right shift +instruct vsrl2I_immI(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd()); + match(Set dst (URShiftVI src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.U32 $dst.D,$src.D,$shift\t! logical right shift packed2I" + %} + ins_encode %{ + bool quad = false; + __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsrl4I_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 4 && VM_Version::has_simd()); + match(Set dst (URShiftVI src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.U32 $dst.Q,$src.Q,$shift\t! logical right shift packed4I" + %} + ins_encode %{ + bool quad = true; + __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Longs vector logical right shift +instruct vsrl2L_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (URShiftVL src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.U64 $dst.Q,$src.Q,$shift\t! logical right shift packed2L" + %} + ins_encode %{ + bool quad = true; + __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 64, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// ------------------- ArithmeticRightShift ----------------------------------- + +// Bytes vector arithmetic left/right shift based on sign +instruct vsha8B_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 8); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.S8 $dst.D,$src.D,$shift.D\t! arithmetic right shift packed8B" + %} + ins_encode %{ + bool quad = false; + __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsha16B_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 16); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.S8 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed16B" + %} + ins_encode %{ + bool quad = true; + __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Shorts vector arithmetic left/right shift based on sign +instruct vsha4S_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 4); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.S16 $dst.D,$src.D,$shift.D\t! arithmetic right shift packed4S" + %} + ins_encode %{ + bool quad = false; + __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_16, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsha8S_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 8); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.S16 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed8S" + %} + ins_encode %{ + bool quad = true; + __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_16, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Integers vector arithmetic left/right shift based on sign +instruct vsha2I_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 2); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.S32 $dst.D,$src.D,$shift.D\t! arithmetic right shift packed2I" + %} + ins_encode %{ + bool quad = false; + __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_32, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsha4I_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 4); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.S32 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed4I" + %} + ins_encode %{ + bool quad = true; + __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_32, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Longs vector arithmetic left/right shift based on sign +instruct vsha2L_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 2); + effect(DEF dst, USE src, USE shift); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHL.S64 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed2L" + %} + ins_encode %{ + bool quad = true; + __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_64, quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Byte vector arithmetic right shift + +instruct vsra8B_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (RShiftVB src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + expand %{ + vsha8B_reg(dst, src, shift); + %} +%} + +instruct vsrl16B_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 16); + match(Set dst (RShiftVB src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + expand %{ + vsha16B_reg(dst, src, shift); + %} +%} + +instruct vsrl8B_immI(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (RShiftVB src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.S8 $dst.D,$src.D,$shift\t! logical right shift packed8B" + %} + ins_encode %{ + bool quad = false; + __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsrl16B_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 16); + match(Set dst (RShiftVB src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.S8 $dst.Q,$src.Q,$shift\t! logical right shift packed16B" + %} + ins_encode %{ + bool quad = true; + __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Shorts vector arithmetic right shift +instruct vsra4S_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (RShiftVS src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + expand %{ + vsha4S_reg(dst, src, shift); + %} +%} + +instruct vsra8S_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (RShiftVS src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + expand %{ + vsha8S_reg(dst, src, shift); + %} +%} + +instruct vsra4S_immI(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (RShiftVS src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.S16 $dst.D,$src.D,$shift\t! logical right shift packed4S" + %} + ins_encode %{ + bool quad = false; + __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsra8S_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (RShiftVS src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.S16 $dst.Q,$src.Q,$shift\t! logical right shift packed8S" + %} + ins_encode %{ + bool quad = true; + __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Integers vector arithmetic right shift +instruct vsra2I_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (RShiftVI src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + expand %{ + vsha2I_reg(dst, src, shift); + %} +%} + +instruct vsra4I_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (RShiftVI src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + expand %{ + vsha4I_reg(dst, src, shift); + %} +%} + +instruct vsra2I_immI(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (RShiftVI src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.S32 $dst.D,$src.D,$shift\t! logical right shift packed2I" + %} + ins_encode %{ + bool quad = false; + __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vsra4I_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (RShiftVI src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.S32 $dst.Q,$src.Q,$shift\t! logical right shift packed4I" + %} + ins_encode %{ + bool quad = true; + __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// Longs vector arithmetic right shift +instruct vsra2L_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (RShiftVL src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + expand %{ + vsha2L_reg(dst, src, shift); + %} +%} + +instruct vsra2L_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (RShiftVL src shift)); + size(4); + ins_cost(DEFAULT_COST); // FIXME + format %{ + "VSHR.S64 $dst.Q,$src.Q,$shift\t! logical right shift packed2L" + %} + ins_encode %{ + bool quad = true; + __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 64, $shift$$constant, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// --------------------------------- AND -------------------------------------- + +instruct vandD(vecD dst, vecD src1, vecD src2) %{ + predicate(n->as_Vector()->length_in_bytes() == 8); + match(Set dst (AndV src1 src2)); + format %{ "VAND $dst.D,$src1.D,$src2.D\t! and vectors (8 bytes)" %} + ins_encode %{ + bool quad = false; + __ vandI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vandX(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length_in_bytes() == 16); + match(Set dst (AndV src1 src2)); + format %{ "VAND $dst.Q,$src1.Q,$src2.Q\t! and vectors (16 bytes)" %} + ins_encode %{ + bool quad = true; + __ vandI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// --------------------------------- OR --------------------------------------- + +instruct vorD(vecD dst, vecD src1, vecD src2) %{ + predicate(n->as_Vector()->length_in_bytes() == 8); + match(Set dst (OrV src1 src2)); + format %{ "VOR $dst.D,$src1.D,$src2.D\t! and vectors (8 bytes)" %} + ins_encode %{ + bool quad = false; + __ vorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vorX(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length_in_bytes() == 16); + match(Set dst (OrV src1 src2)); + format %{ "VOR $dst.Q,$src1.Q,$src2.Q\t! and vectors (16 bytes)" %} + ins_encode %{ + bool quad = true; + __ vorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +// --------------------------------- XOR -------------------------------------- + +instruct vxorD(vecD dst, vecD src1, vecD src2) %{ + predicate(n->as_Vector()->length_in_bytes() == 8); + match(Set dst (XorV src1 src2)); + format %{ "VXOR $dst.D,$src1.D,$src2.D\t! and vectors (8 bytes)" %} + ins_encode %{ + bool quad = false; + __ vxorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + +instruct vxorX(vecX dst, vecX src1, vecX src2) %{ + predicate(n->as_Vector()->length_in_bytes() == 16); + match(Set dst (XorV src1 src2)); + format %{ "VXOR $dst.Q,$src1.Q,$src2.Q\t! and vectors (16 bytes)" %} + ins_encode %{ + bool quad = true; + __ vxorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, + quad); + %} + ins_pipe( ialu_reg_reg ); // FIXME +%} + + +//----------PEEPHOLE RULES----------------------------------------------------- +// These must follow all instruction definitions as they use the names +// defined in the instructions definitions. +// +// peepmatch ( root_instr_name [preceding_instruction]* ); +// +// peepconstraint %{ +// (instruction_number.operand_name relational_op instruction_number.operand_name +// [, ...] ); +// // instruction numbers are zero-based using left to right order in peepmatch +// +// peepreplace ( instr_name ( [instruction_number.operand_name]* ) ); +// // provide an instruction_number.operand_name for each operand that appears +// // in the replacement instruction's match rule +// +// ---------VM FLAGS--------------------------------------------------------- +// +// All peephole optimizations can be turned off using -XX:-OptoPeephole +// +// Each peephole rule is given an identifying number starting with zero and +// increasing by one in the order seen by the parser. An individual peephole +// can be enabled, and all others disabled, by using -XX:OptoPeepholeAt=# +// on the command-line. +// +// ---------CURRENT LIMITATIONS---------------------------------------------- +// +// Only match adjacent instructions in same basic block +// Only equality constraints +// Only constraints between operands, not (0.dest_reg == EAX_enc) +// Only one replacement instruction +// +// ---------EXAMPLE---------------------------------------------------------- +// +// // pertinent parts of existing instructions in architecture description +// instruct movI(eRegI dst, eRegI src) %{ +// match(Set dst (CopyI src)); +// %} +// +// instruct incI_eReg(eRegI dst, immI1 src, eFlagsReg cr) %{ +// match(Set dst (AddI dst src)); +// effect(KILL cr); +// %} +// +// // Change (inc mov) to lea +// peephole %{ +// // increment preceeded by register-register move +// peepmatch ( incI_eReg movI ); +// // require that the destination register of the increment +// // match the destination register of the move +// peepconstraint ( 0.dst == 1.dst ); +// // construct a replacement instruction that sets +// // the destination to ( move's source register + one ) +// peepreplace ( incI_eReg_immI1( 0.dst 1.src 0.src ) ); +// %} +// + +// // Change load of spilled value to only a spill +// instruct storeI(memory mem, eRegI src) %{ +// match(Set mem (StoreI mem src)); +// %} +// +// instruct loadI(eRegI dst, memory mem) %{ +// match(Set dst (LoadI mem)); +// %} +// +// peephole %{ +// peepmatch ( loadI storeI ); +// peepconstraint ( 1.src == 0.dst, 1.mem == 0.mem ); +// peepreplace ( storeI( 1.mem 1.mem 1.src ) ); +// %} + +//----------SMARTSPILL RULES--------------------------------------------------- +// These must follow all instruction definitions as they use the names +// defined in the instructions definitions. +// +// ARM will probably not have any of these rules due to RISC instruction set. + +//----------PIPELINE----------------------------------------------------------- +// Rules which define the behavior of the target architectures pipeline.