// // Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License version 2 only, as // published by the Free Software Foundation. // // This code is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // version 2 for more details (a copy is included in the LICENSE file that // accompanied this code). // // You should have received a copy of the GNU General Public License version // 2 along with this work; if not, write to the Free Software Foundation, // Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. // // Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA // or visit www.oracle.com if you need additional information or have any // questions. // // ARM Architecture Description File //----------DEFINITION BLOCK--------------------------------------------------- // Define name --> value mappings to inform the ADLC of an integer valued name // Current support includes integer values in the range [0, 0x7FFFFFFF] // Format: // int_def ( , ); // 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 uint Matcher::vector_ideal_reg(int size) { assert(MaxVectorSize >= size, ""); switch(size) { case 8: return Op_VecD; case 16: return Op_VecX; } ShouldNotReachHere(); return 0; } const uint Matcher::vector_shift_count_ideal_reg(int size) { return vector_ideal_reg(size); } // Limits on vector size (number of elements) loaded into vector. const int Matcher::max_vector_size(const BasicType bt) { assert(is_java_primitive(bt), "only primitive type vectors"); return vector_width_in_bytes(bt)/type2aelembytes(bt); } const int Matcher::min_vector_size(const BasicType bt) { assert(is_java_primitive(bt), "only primitive type vectors"); return 8/type2aelembytes(bt); } // ARM doesn't support misaligned vectors store/load. const bool Matcher::misaligned_vectors_ok() { return false; } // ARM doesn't support AES intrinsics const bool Matcher::pass_original_key_for_aes() { return false; } const bool Matcher::convL2FSupported(void) { #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 Lchar, Lchar_loop, Ldone, Lequal; MacroAssembler _masm(&cbuf); Register str1_reg = $str1$$Register; Register str2_reg = $str2$$Register; Register cnt_reg = $cnt$$Register; // int Register tmp1_reg = $tmp1$$Register; Register tmp2_reg = $tmp2$$Register; Register result_reg = $result$$Register; assert_different_registers(str1_reg, str2_reg, cnt_reg, tmp1_reg, tmp2_reg, result_reg); __ cmp(str1_reg, str2_reg); //same char[] ? __ b(Lequal, eq); __ cbz_32(cnt_reg, Lequal); // count == 0 //rename registers Register limit_reg = cnt_reg; Register chr1_reg = tmp1_reg; Register chr2_reg = tmp2_reg; __ logical_shift_left(limit_reg, limit_reg, exact_log2(sizeof(jchar))); //check for alignment and position the pointers to the ends __ orr(chr1_reg, str1_reg, str2_reg); __ tst(chr1_reg, 0x3); // notZero means at least one not 4-byte aligned. // We could optimize the case when both arrays are not aligned // but it is not frequent case and it requires additional checks. __ b(Lchar, ne); // Compare char[] arrays aligned to 4 bytes. __ char_arrays_equals(str1_reg, str2_reg, limit_reg, result_reg, chr1_reg, chr2_reg, Ldone); __ b(Lequal); // equal // char by char compare __ bind(Lchar); __ mov(result_reg, 0); __ add(str1_reg, limit_reg, str1_reg); __ add(str2_reg, limit_reg, str2_reg); __ neg(limit_reg, limit_reg); //negate count // Lchar_loop __ bind(Lchar_loop); __ ldrh(chr1_reg, Address(str1_reg, limit_reg)); __ ldrh(chr2_reg, Address(str2_reg, limit_reg)); __ cmp(chr1_reg, chr2_reg); __ b(Ldone, ne); __ adds(limit_reg, limit_reg, sizeof(jchar)); __ b(Lchar_loop, ne); __ bind(Lequal); __ mov(result_reg, 1); //equal __ bind(Ldone); %} enc_class enc_Array_Equals(R0RegP ary1, R1RegP ary2, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI result) %{ Label Ldone, Lloop, Lequal; MacroAssembler _masm(&cbuf); Register ary1_reg = $ary1$$Register; Register ary2_reg = $ary2$$Register; Register tmp1_reg = $tmp1$$Register; Register tmp2_reg = $tmp2$$Register; Register tmp3_reg = $tmp3$$Register; Register result_reg = $result$$Register; assert_different_registers(ary1_reg, ary2_reg, tmp1_reg, tmp2_reg, tmp3_reg, result_reg); int length_offset = arrayOopDesc::length_offset_in_bytes(); int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); // return true if the same array #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 + align_up((Compile::current()->in_preserve_stack_slots() + Compile::current()->fixed_slots()), stack_alignment_in_slots())); // Body of function which returns an OptoRegs array locating // arguments either in registers or in stack slots for calling // java calling_convention %{ (void) SharedRuntime::java_calling_convention(sig_bt, regs, length, is_outgoing); %} // Body of function which returns an OptoRegs array locating // arguments either in registers or in stack slots for callin // C. c_calling_convention %{ // This is obviously always outgoing (void) SharedRuntime::c_calling_convention(sig_bt, regs, /*regs2=*/NULL, length); %} // Location of compiled Java return values. Same as C return_value %{ return c2::return_value(ideal_reg); %} %} //----------ATTRIBUTES--------------------------------------------------------- //----------Instruction Attributes--------------------------------------------- ins_attrib ins_cost(DEFAULT_COST); // Required cost attribute ins_attrib ins_size(32); // Required size attribute (in bits) ins_attrib ins_short_branch(0); // Required flag: is this instruction a // non-matching short branch variant of some // long branch? //----------OPERANDS----------------------------------------------------------- // Operand definitions must precede instruction definitions for correct parsing // in the ADLC because operands constitute user defined types which are used in // instruction definitions. //----------Simple Operands---------------------------------------------------- // Immediate Operands // Integer Immediate: 32-bit operand immI() %{ match(ConI); op_cost(0); // formats are generated automatically for constants and base registers format %{ %} interface(CONST_INTER); %} // Integer Immediate: 8-bit unsigned - for VMOV operand immU8() %{ predicate(0 <= n->get_int() && (n->get_int() <= 255)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: 16-bit operand immI16() %{ predicate((n->get_int() >> 16) == 0 && VM_Version::supports_movw()); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} #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); %} operand flagsRegUL_LTGE() %{ constraint(ALLOC_IN_RC(int_flags)); match(RegFlags); format %{ "apsr_UL_LTGE" %} interface(REG_INTER); %} operand flagsRegUL_EQNE() %{ constraint(ALLOC_IN_RC(int_flags)); match(RegFlags); format %{ "apsr_UL_EQNE" %} interface(REG_INTER); %} operand flagsRegUL_LEGT() %{ constraint(ALLOC_IN_RC(int_flags)); match(RegFlags); format %{ "apsr_UL_LEGT" %} interface(REG_INTER); %} #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 cmpOpUL() %{ match(Bool); format %{ "UL" %} interface(COND_INTER) %{ equal(0x0); not_equal(0x1); less(0x3); greater_equal(0x2); less_equal(0x9); greater(0x8); overflow(0x0); // unsupported/unimplemented no_overflow(0x0); // unsupported/unimplemented %} %} operand cmpOpUL_commute() %{ match(Bool); format %{ "UL" %} interface(COND_INTER) %{ equal(0x0); not_equal(0x1); less(0x8); greater_equal(0x9); less_equal(0x2); greater(0x3); overflow(0x0); // unsupported/unimplemented no_overflow(0x0); // unsupported/unimplemented %} %} //----------OPERAND CLASSES---------------------------------------------------- // Operand Classes are groups of operands that are used to simplify // instruction definitions by not requiring the AD writer to specify separate // instructions for every form of operand when the instruction accepts // multiple operand types with the same basic encoding and format. The classic // case of this is memory operands. #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( memoryP mem ) %{ 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); %} //----------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); %} instruct compUL_iReg(flagsRegU xcc, iRegL op1, iRegL op2) %{ match(Set xcc (CmpUL op1 op2)); size(4); format %{ "CMP $op1,$op2\t! unsigned 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); %} instruct compUL_reg_reg_LTGE(flagsRegUL_LTGE xcc, iRegL op1, iRegL op2, iRegL tmp) %{ match(Set xcc (CmpUL op1 op2)); effect(DEF xcc, USE op1, USE op2, TEMP tmp); size(8); format %{ "SUBS $tmp,$op1.low,$op2.low\t\t! unsigned long\n\t" "SBCS $tmp,$op1.hi,$op2.hi" %} ins_encode %{ __ subs($tmp$$Register, $op1$$Register, $op2$$Register); __ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), $op2$$Register->successor()); %} ins_pipe(ialu_cconly_reg_reg); %} #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); %} instruct compUL_reg_con(flagsRegU xcc, iRegL op1, aimmL con) %{ match(Set xcc (CmpUL op1 con)); effect(DEF xcc, USE op1, USE con); size(8); format %{ "CMP $op1,$con\t\t! unsigned 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); %} instruct compUL_reg_reg_EQNE(flagsRegUL_EQNE xcc, iRegL op1, iRegL op2) %{ match(Set xcc (CmpUL op1 op2)); effect(DEF xcc, USE op1, USE op2); size(8); format %{ "TEQ $op1.hi,$op2.hi\t\t! unsigned long\n\t" "TEQ.eq $op1.lo,$op2.lo" %} ins_encode %{ __ teq($op1$$Register->successor(), $op2$$Register->successor()); __ teq($op1$$Register, $op2$$Register, eq); %} ins_pipe(ialu_cconly_reg_reg); %} instruct compUL_reg_reg_LEGT(flagsRegUL_LEGT xcc, iRegL op1, iRegL op2, iRegL tmp) %{ match(Set xcc (CmpUL op1 op2)); effect(DEF xcc, USE op1, USE op2, TEMP tmp); size(8); format %{ "SUBS $tmp,$op2.low,$op1.low\t\t! unsigned long\n\t" "SBCS $tmp,$op2.hi,$op1.hi" %} ins_encode %{ __ subs($tmp$$Register, $op2$$Register, $op1$$Register); __ sbcs($tmp$$Register->successor(), $op2$$Register->successor(), $op1$$Register->successor()); %} ins_pipe(ialu_cconly_reg_reg); %} // TODO: try immLRot2 instead, (0, $con$$constant) becomes // (hi($con$$constant), lo($con$$constant)) becomes instruct compUL_reg_con_LTGE(flagsRegUL_LTGE xcc, iRegL op1, immLlowRot con, iRegL tmp) %{ match(Set xcc (CmpUL op1 con)); effect(DEF xcc, USE op1, USE con, TEMP tmp); size(8); format %{ "SUBS $tmp,$op1.low,$con\t\t! unsigned long\n\t" "SBCS $tmp,$op1.hi,0" %} ins_encode %{ __ subs($tmp$$Register, $op1$$Register, $con$$constant); __ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), 0); %} ins_pipe(ialu_cconly_reg_reg); %} // TODO: try immLRot2 instead, (0, $con$$constant) becomes // (hi($con$$constant), lo($con$$constant)) becomes instruct compUL_reg_con_EQNE(flagsRegUL_EQNE xcc, iRegL op1, immLlowRot con) %{ match(Set xcc (CmpUL op1 con)); effect(DEF xcc, USE op1, USE con); size(8); format %{ "TEQ $op1.hi,0\t\t! unsigned long\n\t" "TEQ.eq $op1.lo,$con" %} ins_encode %{ __ teq($op1$$Register->successor(), 0); __ teq($op1$$Register, $con$$constant, eq); %} ins_pipe(ialu_cconly_reg_reg); %} // TODO: try immLRot2 instead, (0, $con$$constant) becomes // (hi($con$$constant), lo($con$$constant)) becomes instruct compUL_reg_con_LEGT(flagsRegUL_LEGT xcc, iRegL op1, immLlowRot con, iRegL tmp) %{ match(Set xcc (CmpUL op1 con)); effect(DEF xcc, USE op1, USE con, TEMP tmp); size(8); format %{ "RSBS $tmp,$op1.low,$con\t\t! unsigned long\n\t" "RSCS $tmp,$op1.hi,0" %} ins_encode %{ __ rsbs($tmp$$Register, $op1$$Register, $con$$constant); __ rscs($tmp$$Register->successor(), $op1$$Register->successor(), 0); %} ins_pipe(ialu_cconly_reg_reg); %} #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); %} instruct branchConUL_LTGE(cmpOpUL cmp, flagsRegUL_LTGE xcc, label labl) %{ match(If cmp xcc); effect(USE labl); predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); size(4); ins_cost(BRANCH_COST); format %{ "B$cmp $xcc,$labl" %} ins_encode %{ __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode)); %} ins_pipe(br_cc); %} instruct branchConUL_EQNE(cmpOpUL cmp, flagsRegUL_EQNE xcc, label labl) %{ match(If cmp xcc); effect(USE labl); predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); size(4); ins_cost(BRANCH_COST); format %{ "B$cmp $xcc,$labl" %} ins_encode %{ __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode)); %} ins_pipe(br_cc); %} instruct branchConUL_LEGT(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, label labl) %{ match(If cmp xcc); effect(USE labl); predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le); size(4); ins_cost(BRANCH_COST); format %{ "B$cmp $xcc,$labl" %} ins_encode %{ __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode)); %} ins_pipe(br_cc); %} #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 %{ "ShouldNotReachHere" %} ins_encode %{ #ifdef AARCH64 __ dpcs1(0xdead); #else __ udf(0xdead); #endif %} 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.