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