// // Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2015-2018, Azul Systems, Inc. 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. // // AARCH32 Architecture Description File //----------REGISTER DEFINITION BLOCK------------------------------------------ // This information is used by the matcher and the register allocator to // describe individual registers and classes of registers within the target // archtecture. register %{ //----------Architecture Description Register Definitions---------------------- // General Registers // "reg_def" name ( register save type, C convention save type, // ideal register type, encoding, vm name ); // Register Save Types: // // NS = No-Save: The register allocator assumes that these registers // can be used without saving upon entry to the method, & // that they do not need to be saved at call sites. // // SOC = Save-On-Call: The register allocator assumes that these registers // can be used without saving upon entry to the method, // but that they must be saved at call sites. // // SOE = Save-On-Entry: The register allocator assumes that these registers // must be saved before using them upon entry to the // method, but they do not need to be saved at call // sites. // // AS = Always-Save: The register allocator assumes that these registers // must be saved before using them upon entry to the // method, & that they must be saved at call sites. // // Ideal Register Type is used to determine how to save & restore a // register. Op_RegI will get spilled with LoadI/StoreI, Op_RegP will get // spilled with LoadP/StoreP. If the register supports both, use Op_RegI. // // The encoding number is the actual bit-pattern placed into the opcodes. // ---------------------------- // Integer/Long Registers // ---------------------------- reg_def R_R0 (SOC, SOC, Op_RegI, 0, R(0)->as_VMReg()); reg_def R_R1 (SOC, SOC, Op_RegI, 1, R(1)->as_VMReg()); reg_def R_R2 (SOC, SOC, Op_RegI, 2, R(2)->as_VMReg()); reg_def R_R3 (SOC, SOC, Op_RegI, 3, R(3)->as_VMReg()); reg_def R_R4 (SOC, SOE, Op_RegI, 4, R(4)->as_VMReg()); reg_def R_R5 (SOC, SOE, Op_RegI, 5, R(5)->as_VMReg()); reg_def R_R6 (SOC, SOE, Op_RegI, 6, R(6)->as_VMReg()); reg_def R_R7 (SOC, SOE, Op_RegI, 7, R(7)->as_VMReg()); reg_def R_R8 (SOC, SOE, Op_RegI, 8, R(8)->as_VMReg()); reg_def R_R9 (SOC, SOE, Op_RegI, 9, R(9)->as_VMReg()); reg_def R_R10(NS, SOE, Op_RegI, 10, R(10)->as_VMReg()); reg_def R_R11(NS, SOE, Op_RegI, 11, R(11)->as_VMReg()); reg_def R_R12(SOC, SOC, Op_RegI, 12, R(12)->as_VMReg()); reg_def R_R13(NS, NS, Op_RegI, 13, R(13)->as_VMReg()); reg_def R_R14(SOC, SOC, Op_RegI, 14, R(14)->as_VMReg()); reg_def R_R15(NS, NS, Op_RegI, 15, R(15)->as_VMReg()); // ---------------------------- // Float/Double Registers // ---------------------------- // Float Registers reg_def R_S0 ( SOC, SOC, Op_RegF, 0, f0->as_VMReg()); reg_def R_S1 ( SOC, SOC, Op_RegF, 1, f1->as_VMReg()); reg_def R_S2 ( SOC, SOC, Op_RegF, 2, f2->as_VMReg()); reg_def R_S3 ( SOC, SOC, Op_RegF, 3, f3->as_VMReg()); reg_def R_S4 ( SOC, SOC, Op_RegF, 4, f4->as_VMReg()); reg_def R_S5 ( SOC, SOC, Op_RegF, 5, f5->as_VMReg()); reg_def R_S6 ( SOC, SOC, Op_RegF, 6, f6->as_VMReg()); reg_def R_S7 ( SOC, SOC, Op_RegF, 7, f7->as_VMReg()); reg_def R_S8 ( SOC, SOC, Op_RegF, 8, f8->as_VMReg()); reg_def R_S9 ( SOC, SOC, Op_RegF, 9, f9->as_VMReg()); reg_def R_S10( SOC, SOC, Op_RegF, 10,f10->as_VMReg()); reg_def R_S11( SOC, SOC, Op_RegF, 11,f11->as_VMReg()); reg_def R_S12( SOC, SOC, Op_RegF, 12,f12->as_VMReg()); reg_def R_S13( SOC, SOC, Op_RegF, 13,f13->as_VMReg()); reg_def R_S14( SOC, SOC, Op_RegF, 14,f14->as_VMReg()); reg_def R_S15( SOC, SOC, Op_RegF, 15,f15->as_VMReg()); reg_def R_S16( SOC, SOE, Op_RegF, 16,f16->as_VMReg()); reg_def R_S17( SOC, SOE, Op_RegF, 17,f17->as_VMReg()); reg_def R_S18( SOC, SOE, Op_RegF, 18,f18->as_VMReg()); reg_def R_S19( SOC, SOE, Op_RegF, 19,f19->as_VMReg()); reg_def R_S20( SOC, SOE, Op_RegF, 20,f20->as_VMReg()); reg_def R_S21( SOC, SOE, Op_RegF, 21,f21->as_VMReg()); reg_def R_S22( SOC, SOE, Op_RegF, 22,f22->as_VMReg()); reg_def R_S23( SOC, SOE, Op_RegF, 23,f23->as_VMReg()); reg_def R_S24( SOC, SOE, Op_RegF, 24,f24->as_VMReg()); reg_def R_S25( SOC, SOE, Op_RegF, 25,f25->as_VMReg()); reg_def R_S26( SOC, SOE, Op_RegF, 26,f26->as_VMReg()); reg_def R_S27( SOC, SOE, Op_RegF, 27,f27->as_VMReg()); reg_def R_S28( SOC, SOE, Op_RegF, 28,f28->as_VMReg()); reg_def R_S29( SOC, SOE, Op_RegF, 29,f29->as_VMReg()); reg_def R_S30( SOC, SOE, Op_RegF, 30,f30->as_VMReg()); reg_def R_S31( SOC, SOE, Op_RegF, 31,f31->as_VMReg()); // Double Registers // The rules of ADL require that double registers be defined in pairs. // Each pair must be two 32-bit values, but not necessarily a pair of // single float registers. In each pair, ADLC-assigned register numbers // must be adjacent, with the lower number even. Finally, when the // CPU stores such a register pair to memory, the word associated with // the lower ADLC-assigned number must be stored to the lower address. // TODO, the problem is that AArch32 port has same same numeric value for // d16->as_VMReg and f1->as_VMReg which breaks reverse mapping from // VMReg to OptoReg // reg_def R_D16 (SOC, SOC, Op_RegD, 32, d16->as_VMReg()); // reg_def R_D16x(SOC, SOC, Op_RegD,255, d16->as_VMReg()->next()); // reg_def R_D17 (SOC, SOC, Op_RegD, 34, d17->as_VMReg()); // reg_def R_D17x(SOC, SOC, Op_RegD,255, d17->as_VMReg()->next()); // reg_def R_D18 (SOC, SOC, Op_RegD, 36, d18->as_VMReg()); // reg_def R_D18x(SOC, SOC, Op_RegD,255, d18->as_VMReg()->next()); // reg_def R_D19 (SOC, SOC, Op_RegD, 38, d19->as_VMReg()); // reg_def R_D19x(SOC, SOC, Op_RegD,255, d19->as_VMReg()->next()); // reg_def R_D20 (SOC, SOC, Op_RegD, 40, d20->as_VMReg()); // reg_def R_D20x(SOC, SOC, Op_RegD,255, d20->as_VMReg()->next()); // reg_def R_D21 (SOC, SOC, Op_RegD, 42, d21->as_VMReg()); // reg_def R_D21x(SOC, SOC, Op_RegD,255, d21->as_VMReg()->next()); // reg_def R_D22 (SOC, SOC, Op_RegD, 44, d22->as_VMReg()); // reg_def R_D22x(SOC, SOC, Op_RegD,255, d22->as_VMReg()->next()); // reg_def R_D23 (SOC, SOC, Op_RegD, 46, d23->as_VMReg()); // reg_def R_D23x(SOC, SOC, Op_RegD,255, d23->as_VMReg()->next()); // reg_def R_D24 (SOC, SOC, Op_RegD, 48, d24->as_VMReg()); // reg_def R_D24x(SOC, SOC, Op_RegD,255, d24->as_VMReg()->next()); // reg_def R_D25 (SOC, SOC, Op_RegD, 50, d25->as_VMReg()); // reg_def R_D25x(SOC, SOC, Op_RegD,255, d25->as_VMReg()->next()); // reg_def R_D26 (SOC, SOC, Op_RegD, 52, d26->as_VMReg()); // reg_def R_D26x(SOC, SOC, Op_RegD,255, d26->as_VMReg()->next()); // reg_def R_D27 (SOC, SOC, Op_RegD, 54, d27->as_VMReg()); // reg_def R_D27x(SOC, SOC, Op_RegD,255, d27->as_VMReg()->next()); // reg_def R_D28 (SOC, SOC, Op_RegD, 56, d28->as_VMReg()); // reg_def R_D28x(SOC, SOC, Op_RegD,255, d28->as_VMReg()->next()); // reg_def R_D29 (SOC, SOC, Op_RegD, 58, d29->as_VMReg()); // reg_def R_D29x(SOC, SOC, Op_RegD,255, d29->as_VMReg()->next()); // reg_def R_D30 (SOC, SOC, Op_RegD, 60, d30->as_VMReg()); // reg_def R_D30x(SOC, SOC, Op_RegD,255, d30->as_VMReg()->next()); // reg_def R_D31 (SOC, SOC, Op_RegD, 62, d31->as_VMReg()); // reg_def R_D31x(SOC, SOC, Op_RegD,255, d31->as_VMReg()->next()); // ---------------------------- // Special Registers // Condition Codes Flag Registers reg_def APSR (SOC, SOC, Op_RegFlags, 0, VMRegImpl::Bad()); reg_def FPSCR(SOC, SOC, Op_RegFlags, 0, VMRegImpl::Bad()); // ---------------------------- // Specify the enum values for the registers. These enums are only used by the // OptoReg "class". We can convert these enum values at will to VMReg when needed // for visibility to the rest of the vm. The order of this enum influences the // register allocator so having the freedom to set this order and not be stuck // with the order that is natural for the rest of the vm is worth it. // registers in that order so that R11/R12 is an aligned pair that can be used for longs alloc_class chunk0( R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R11, R_R12, R_R10, R_R13, R_R14, R_R15, R_R0, R_R1, R_R2, R_R3); // Note that a register is not allocatable unless it is also mentioned // in a widely-used reg_class below. alloc_class chunk1( R_S16, R_S17, R_S18, R_S19, R_S20, R_S21, R_S22, R_S23, R_S24, R_S25, R_S26, R_S27, R_S28, R_S29, R_S30, R_S31, R_S0, R_S1, R_S2, R_S3, R_S4, R_S5, R_S6, R_S7, R_S8, R_S9, R_S10, R_S11, R_S12, R_S13, R_S14, R_S15 // , // R_D16, R_D16x,R_D17, R_D17x,R_D18, R_D18x,R_D19, R_D19x, // R_D20, R_D20x,R_D21, R_D21x,R_D22, R_D22x,R_D23, R_D23x, // R_D24, R_D24x,R_D25, R_D25x,R_D26, R_D26x,R_D27, R_D27x, // R_D28, R_D28x,R_D29, R_D29x,R_D30, R_D30x,R_D31, R_D31x ); alloc_class chunk2(APSR, FPSCR); //----------Architecture Description Register Classes-------------------------- // Several register classes are automatically defined based upon information in // this architecture description. // 1) reg_class inline_cache_reg ( as defined in frame section ) // 2) reg_class interpreter_method_oop_reg ( as defined in frame section ) // 3) reg_class stack_slots( /* one chunk of stack-based "registers" */ ) // // ---------------------------- // Integer Register Classes // ---------------------------- // Exclusions from i_reg: // sp (R13), PC (R15) // R10: reserved by HotSpot to the TLS register (invariant within Java) reg_class int_reg(R_R0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R11, R_R12, R_R14); reg_class R0_regI(R_R0); reg_class R1_regI(R_R1); reg_class R2_regI(R_R2); reg_class R3_regI(R_R3); reg_class R9_regI(R_R9); reg_class R12_regI(R_R12); // ---------------------------- // Pointer Register Classes // ---------------------------- reg_class ptr_reg(R_R0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R11, R_R12, R_R14); // Special class for storeP instructions, which can store SP or RPC to TLS. // It is also used for memory addressing, allowing direct TLS addressing. reg_class sp_ptr_reg(R_R0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R9, R_R11, R_R12, R_R14, R_R8, R_R10 /* TLS*/, R_R13 /* SP*/); #define R_Ricklass R_R12 #define R_Rmethod R_R8 #define R_Rthread R_R10 #define R_Rexception_obj R_R0 // Other special pointer regs reg_class R0_regP(R_R0); reg_class R1_regP(R_R1); reg_class R2_regP(R_R2); reg_class R4_regP(R_R4); reg_class Rexception_regP(R_Rexception_obj); reg_class Ricklass_regP(R_Ricklass); reg_class Rmethod_regP(R_Rmethod); reg_class Rthread_regP(R_Rthread); reg_class IP_regP(R_R12); reg_class LR_regP(R_R14); reg_class FP_regP(R_R11); // ---------------------------- // Long Register Classes // ---------------------------- reg_class long_reg ( R_R0,R_R1, R_R2,R_R3, R_R4,R_R5, R_R6,R_R7, R_R8,R_R9, R_R11,R_R12); // for ldrexd, strexd: first reg of pair must be even reg_class long_reg_align ( R_R0,R_R1, R_R2,R_R3, R_R4,R_R5, R_R6,R_R7, R_R8,R_R9); reg_class R0R1_regL(R_R0,R_R1); reg_class R2R3_regL(R_R2,R_R3); // ---------------------------- // Special Class for Condition Code Flags Register reg_class int_flags(APSR); reg_class float_flags(FPSCR); // ---------------------------- // Float Point Register Classes // ---------------------------- // Skip f14/f15, they are reserved for mem-mem copies reg_class sflt_reg(R_S0, R_S1, R_S2, R_S3, R_S4, R_S5, R_S6, R_S7, R_S8, R_S9, R_S10, R_S11, R_S12, R_S13, R_S16, R_S17, R_S18, R_S19, R_S20, R_S21, R_S22, R_S23, R_S24, R_S25, R_S26, R_S27, R_S28, R_S29, R_S30, R_S31); // Paired floating point registers--they show up in the same order as the floats, // but they are used with the "Op_RegD" type, and always occur in even/odd pairs. reg_class dflt_reg(R_S0,R_S1, R_S2,R_S3, R_S4,R_S5, R_S6,R_S7, R_S8,R_S9, R_S10,R_S11, R_S12,R_S13, R_S16,R_S17, R_S18,R_S19, R_S20,R_S21, R_S22,R_S23, R_S24,R_S25, R_S26,R_S27, R_S28,R_S29, R_S30,R_S31 // , // R_D16,R_D16x, R_D17,R_D17x, R_D18,R_D18x, R_D19,R_D19x, R_D20,R_D20x, R_D21,R_D21x, R_D22,R_D22x, // R_D23,R_D23x, R_D24,R_D24x, R_D25,R_D25x, R_D26,R_D26x, R_D27,R_D27x, R_D28,R_D28x, R_D29,R_D29x, // R_D30,R_D30x, R_D31,R_D31x ); reg_class dflt_low_reg(R_S0,R_S1, R_S2,R_S3, R_S4,R_S5, R_S6,R_S7, R_S8,R_S9, R_S10,R_S11, R_S12,R_S13, R_S16,R_S17, R_S18,R_S19, R_S20,R_S21, R_S22,R_S23, R_S24,R_S25, R_S26,R_S27, R_S28,R_S29, R_S30,R_S31); reg_class actual_dflt_reg %{ if (/*VM_Version::features() & FT_VFPV3D32*/0) { // TODO verify and enable return DFLT_REG_mask(); } else { return DFLT_LOW_REG_mask(); } %} reg_class f0_regF(R_S0); reg_class D0_regD(R_S0,R_S1); reg_class D1_regD(R_S2,R_S3); reg_class D2_regD(R_S4,R_S5); reg_class D3_regD(R_S6,R_S7); reg_class D4_regD(R_S8,R_S9); reg_class D5_regD(R_S10,R_S11); reg_class D6_regD(R_S12,R_S13); reg_class D7_regD(R_S14,R_S15); reg_class D0D1_regD(R_S0,R_S1,R_S2,R_S3); reg_class D2D3_regD(R_S4,R_S5,R_S6,R_S7); // reg_class D16_regD(R_D16,R_D16x); // reg_class D17_regD(R_D17,R_D17x); // reg_class D18_regD(R_D18,R_D18x); // reg_class D19_regD(R_D19,R_D19x); // reg_class D20_regD(R_D20,R_D20x); // reg_class D21_regD(R_D21,R_D21x); // reg_class D22_regD(R_D22,R_D22x); // reg_class D23_regD(R_D23,R_D23x); // reg_class D24_regD(R_D24,R_D24x); // reg_class D25_regD(R_D25,R_D25x); // reg_class D26_regD(R_D26,R_D26x); // reg_class D27_regD(R_D27,R_D27x); // reg_class D28_regD(R_D28,R_D28x); // reg_class D29_regD(R_D29,R_D29x); // reg_class D30_regD(R_D30,R_D30x); // reg_class D31_regD(R_D31,R_D31x); reg_class vectorx_reg(R_S0,R_S1,R_S2,R_S3, R_S4,R_S5,R_S6,R_S7, R_S8,R_S9,R_S10,R_S11, /* skip f14/f15 */ R_S16,R_S17,R_S18,R_S19, R_S20,R_S21,R_S22,R_S23, R_S24,R_S25,R_S26,R_S27, R_S28,R_S29,R_S30,R_S31 // , // R_D16,R_D16x,R_D17,R_D17x, R_D18,R_D18x,R_D19,R_D19x, // R_D20,R_D20x,R_D21,R_D21x, R_D22,R_D22x,R_D23,R_D23x, // R_D24,R_D24x,R_D25,R_D25x, R_D26,R_D26x,R_D27,R_D27x, // R_D28,R_D28x,R_D29,R_D29x, R_D30,R_D30x,R_D31,R_D31x ); %} source_hpp %{ // FIXME const MachRegisterNumbers R_mem_copy_lo_num = R_S14_num; const MachRegisterNumbers R_mem_copy_hi_num = R_S15_num; const FloatRegister Rmemcopy = f14; const MachRegisterNumbers R_hf_ret_lo_num = R_S0_num; const MachRegisterNumbers R_hf_ret_hi_num = R_S1_num; const MachRegisterNumbers R_Ricklass_num = R_R12_num; const MachRegisterNumbers R_Rmethod_num = R_R8_num; #define LDR_DOUBLE "FLDD" #define LDR_FLOAT "FLDS" #define STR_DOUBLE "FSTD" #define STR_FLOAT "FSTS" #define LDR_64 "LDRD" #define STR_64 "STRD" #define LDR_32 "LDR" #define STR_32 "STR" #define MOV_DOUBLE "FCPYD" #define MOV_FLOAT "FCPYS" #define FMSR "FMSR" #define FMRS "FMRS" #define LDREX "ldrex " #define STREX "strex " static inline bool is_memoryD(int offset) { return offset < 1024 && offset > -1024; } static inline bool is_memoryfp(int offset) { return offset < 1024 && offset > -1024; } static inline bool is_memoryI(int offset) { return offset < 4096 && offset > -4096; } static inline bool is_memoryP(int offset) { return offset < 4096 && offset > -4096; } static inline bool is_memoryHD(int offset) { return offset < 256 && offset > -256; } static inline bool is_aimm(int imm) { return Assembler::is_valid_for_imm12(imm); } static inline bool is_limmI(jint imm) { return Assembler::is_valid_for_imm12(imm); } static inline bool is_limmI_low(jint imm, int n) { int imml = imm & right_n_bits(n); return is_limmI(imml) || is_limmI(imm); } static inline int limmI_low(jint imm, int n) { int imml = imm & right_n_bits(n); return is_limmI(imml) ? imml : imm; } %} source %{ // Given a register encoding, produce a Integer Register object static Register reg_to_register_object(int register_encoding) { assert(r0->encoding() == R_R0_enc && r15->encoding() == R_R15_enc, "right coding"); return as_Register(register_encoding); } // Given a register encoding, produce a Float Register object static FloatRegister reg_to_FloatRegister_object(int register_encoding) { assert(f0->encoding() == R_S0_enc && f31->encoding() == R_S31_enc, "right coding"); // [d16,d31] share FloatRegister encoding with [f1,f31] since it numericall equals to ARM insn parameter encoding // in contrary OptoReg encoding for d16+ is different return as_FloatRegister((register_encoding&0x1f)|(register_encoding>>5)); } void Compile::pd_compiler2_init() { // Umimplemented } OptoRegPair c2::return_value(int ideal_reg) { assert( ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values" ); static int lo[Op_RegL+1] = { 0, 0, OptoReg::Bad, R_R0_num, R_R0_num, R_hf_ret_lo_num, R_hf_ret_lo_num, R_R0_num }; static int hi[Op_RegL+1] = { 0, 0, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, R_hf_ret_hi_num, R_R1_num }; #ifndef HARD_FLOAT_CC assert(hasFPU(), "non-VFP java ABI is not supported"); #endif return OptoRegPair( hi[ideal_reg], lo[ideal_reg]); } #ifndef HARD_FLOAT_CC OptoRegPair c2::c_return_value(int ideal_reg) { assert( ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values" ); static int lo[Op_RegL+1] = { 0, 0, OptoReg::Bad, R_R0_num, R_R0_num, R_R0_num, R_R0_num, R_R0_num }; static int hi[Op_RegL+1] = { 0, 0, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, R_R1_num, R_R1_num }; return OptoRegPair( hi[ideal_reg], lo[ideal_reg]); } #endif // !!!!! Special hack to get all type of calls to specify the byte offset // from the start of the call to the point where the return address // will point. static uint call_static_enc_size(const MachCallNode *n, ciMethod *_method, bool _method_handle_invoke) { int call_sz = (_method == NULL) ? (maybe_far_call(n) ? 3 : 1) : (far_branches() ? NativeCall::instruction_size / NativeInstruction::arm_insn_sz : 1); return (call_sz + (_method_handle_invoke ? 2 : 0)) * NativeInstruction::arm_insn_sz; } static uint call_dynamic_enc_size() { return 2 * NativeInstruction::arm_insn_sz + (far_branches() ? NativeCall::instruction_size : NativeInstruction::arm_insn_sz); } static uint call_runtime_enc_size(const MachCallNode *n) { // bl or movw; movt; blx bool far = maybe_far_call(n); return (far ? 3 : 1) * NativeInstruction::arm_insn_sz; } int MachCallStaticJavaNode::ret_addr_offset() { return call_static_enc_size(this, _method, _method_handle_invoke) - (_method_handle_invoke ? 1 : 0) * NativeInstruction::arm_insn_sz; } int MachCallDynamicJavaNode::ret_addr_offset() { return call_dynamic_enc_size(); } int MachCallRuntimeNode::ret_addr_offset() { return call_runtime_enc_size(this); } %} // The intptr_t operand types, defined by textual substitution. // (Cf. opto/type.hpp. This lets us avoid many, many other ifdefs.) #define immX immI #define immXRot immIRot #define iRegX iRegI #define aimmX aimmI #define limmX limmI #define immX10x2 immI10x2 #define LShiftX LShiftI #define shimmX immU5 // Compatibility interface #define aimmP immPRot #define immIMov immIRot #define store_RegL iRegL #define store_RegLd iRegLd #define store_RegI iRegI #define store_ptr_RegP iRegP //----------ATTRIBUTES--------------------------------------------------------- //----------Operand Attributes------------------------------------------------- op_attrib op_cost(1); // Required cost attribute //----------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 operand immIRot() %{ predicate(Assembler::is_valid_for_imm12(n->get_int())); match(ConI); op_cost(0); // formats are generated automatically for constants and base registers format %{ %} interface(CONST_INTER); %} operand immIRotn() %{ predicate(n->get_int() != 0 && Assembler::is_valid_for_imm12(~n->get_int())); match(ConI); op_cost(0); // formats are generated automatically for constants and base registers format %{ %} interface(CONST_INTER); %} operand immIRotneg() %{ // if Assembler::is_valid_for_imm12() is true for this constant, it is // a immIRot and an optimal instruction combination exists to handle the // constant as an immIRot predicate(!Assembler::is_valid_for_imm12(n->get_int()) && Assembler::is_valid_for_imm12(-n->get_int())); match(ConI); op_cost(0); // formats are generated automatically for constants and base registers format %{ %} interface(CONST_INTER); %} // Non-negative integer immediate that is encodable using the rotation scheme, // and that when expanded fits in 31 bits. operand immU31Rot() %{ predicate((0 <= n->get_int()) && Assembler::is_valid_for_imm12(n->get_int())); match(ConI); op_cost(0); // formats are generated automatically for constants and base registers format %{ %} interface(CONST_INTER); %} operand immPRot() %{ predicate(n->get_ptr() == 0 || (Assembler::is_valid_for_imm12(n->get_ptr()) && ((ConPNode*)n)->type()->reloc() == relocInfo::none)); match(ConP); op_cost(0); // formats are generated automatically for constants and base registers format %{ %} interface(CONST_INTER); %} operand immLlowRot() %{ predicate(n->get_long() >> 32 == 0 && Assembler::is_valid_for_imm12((int)n->get_long())); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immLRot2() %{ predicate(Assembler::is_valid_for_imm12((int)(n->get_long() >> 32)) && Assembler::is_valid_for_imm12((int)(n->get_long()))); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: 12-bit - for addressing mode operand immI12() %{ predicate((-4096 < n->get_int()) && (n->get_int() < 4096)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: 10-bit disp and disp+4 - for addressing float pair operand immI10x2() %{ predicate((-1024 < n->get_int()) && (n->get_int() < 1024 - 4)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: 12-bit disp and disp+4 - for addressing word pair operand immI12x2() %{ predicate((-4096 < n->get_int()) && (n->get_int() < 4096 - 4)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} //----------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. #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ #define STOP(error) __ stop(error) #else #define BLOCK_COMMENT(str) __ block_comment(str) #define STOP(error) __ block_comment(error); stop(error) #endif #define BIND(label) __ bind(label); BLOCK_COMMENT(#label ":") // 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(); } static inline bool far_branches() { return MacroAssembler::far_branches(); } extern bool PrintOptoAssembly; class c2 { public: static OptoRegPair return_value(int ideal_reg); #ifndef HARD_FLOAT_CC static OptoRegPair c_return_value(int ideal_reg); #endif }; class CallStubImpl { //-------------------------------------------------------------- //---< Used for optimization in Compile::Shorten_branches >--- //-------------------------------------------------------------- public: // Size of call trampoline stub. static uint size_call_trampoline() { return 0; // no call trampolines on this platform } // number of relocations needed by a call trampoline stub static uint reloc_call_trampoline() { return 0; // no call trampolines on this platform } }; class HandlerImpl { public: static int emit_exception_handler(CodeBuffer &cbuf); static int emit_deopt_handler(CodeBuffer& cbuf); static uint size_exception_handler() { return ( 3 * 4 ); } static uint size_deopt_handler() { return ( 9 * 4 ); } }; %} source %{ #define __ _masm. static FloatRegister reg_to_FloatRegister_object(int register_encoding); static Register reg_to_register_object(int register_encoding); // **************************************************************************** // REQUIRED FUNCTIONALITY // Indicate if the safepoint node needs the polling page as an input. // Since ARM does not have absolute addressing, it does. bool SafePointNode::needs_polling_address_input() { return true; } // emit an interrupt that is caught by the debugger (for debugging compiler) void emit_break(CodeBuffer &cbuf) { MacroAssembler _masm(&cbuf); __ bkpt(0); } #ifndef PRODUCT void MachBreakpointNode::format( PhaseRegAlloc *, outputStream *st ) const { st->print("TA"); } #endif void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { emit_break(cbuf); } uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const { return MachNode::size(ra_); } void emit_nop(CodeBuffer &cbuf) { MacroAssembler _masm(&cbuf); __ nop(); } void emit_call_reloc(CodeBuffer &cbuf, const MachCallNode *n, MachOper *m, RelocationHolder const& rspec) { int ret_addr_offset0 = n->as_MachCall()->ret_addr_offset(); int call_site_offset = cbuf.insts()->mark_off(); MacroAssembler _masm(&cbuf); __ set_inst_mark(); // needed in emit_to_interp_stub() to locate the call address target = (address)m->method(); assert(n->as_MachCall()->entry_point() == target, "sanity"); assert(maybe_far_call(n) == !__ reachable_from_cache(target), "sanity"); assert(cache_reachable() == __ cache_fully_reachable(), "sanity"); assert(target != NULL, "need real address"); if (rspec.type() == relocInfo::runtime_call_type || rspec.type() == relocInfo::none) { __ call(target, rspec); } else { __ trampoline_call(Address(target, rspec), NULL); } int ret_addr_offset = __ offset(); assert(ret_addr_offset - call_site_offset == ret_addr_offset0, "fix ret_addr_offset()"); } //============================================================================= // REQUIRED FUNCTIONALITY for encoding void emit_lo(CodeBuffer &cbuf, int val) { } void emit_hi(CodeBuffer &cbuf, int val) { } //============================================================================= const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask(); int Compile::ConstantTable::calculate_table_base_offset() const { int offset = -(size() / 2); // vldr_f32, vldr_f64: 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; Compile::ConstantTable& constant_table = C->constant_table(); MacroAssembler _masm(&cbuf); Register r = as_Register(ra_->get_encode(this)); CodeSection* consts_section = __ code()->consts(); int consts_size = consts_section->align_at_start(consts_section->size()); assert(constant_table.size() == consts_size, "must be: %d == %d", constant_table.size(), consts_size); // Materialize the constant table base. address baseaddr = consts_section->start() + -(constant_table.table_base_offset()); RelocationHolder rspec = internal_word_Relocation::spec(baseaddr); __ mov_address(r, baseaddr, rspec); } uint MachConstantBaseNode::size(PhaseRegAlloc*) const { return 8; } #ifndef PRODUCT void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const { char reg[128]; ra_->dump_register(this, reg); st->print("MOV_SLOW &constanttable,%s\t! constant table base", reg); } #endif #ifndef PRODUCT void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { Compile* C = ra_->C; for (int i = 0; i < OptoPrologueNops; i++) { st->print_cr("NOP"); st->print("\t"); } size_t framesize = C->frame_size_in_bytes(); assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); int bangsize = C->bang_size_in_bytes(); // Remove two words for return addr and rbp, framesize -= 2*wordSize; bangsize -= 2*wordSize; // Calls to C2R adapters often do not accept exceptional returns. // We require that their callers must bang for them. But be careful, because // some VM calls (such as call site linkage) can use several kilobytes of // stack. But the stack safety zone should account for that. // See bugs 4446381, 4468289, 4497237. if (C->need_stack_bang(bangsize)) { st->print_cr("! stack bang (%d bytes)", bangsize); st->print("\t"); } st->print_cr("PUSH R_FP|R_LR_LR"); st->print("\t"); if (framesize != 0) { st->print ("SUB R_SP, R_SP, " SIZE_FORMAT,framesize); } } #endif void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { Compile* C = ra_->C; MacroAssembler _masm(&cbuf); // insert a nop at the start of the prolog so we can patch in a // branch if we need to invalidate the method later __ nop(); size_t framesize = C->frame_size_in_bytes(); assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); int bangsize = C->bang_size_in_bytes(); // Remove two words for return addr and fp, framesize -= 2*wordSize; bangsize -= 2*wordSize; // Calls to C2R adapters often do not accept exceptional returns. // We require that their callers must bang for them. But be careful, because // some VM calls (such as call site linkage) can use several kilobytes of // stack. But the stack safety zone should account for that. // See bugs 4446381, 4468289, 4497237. if (C->need_stack_bang(bangsize)) { __ arm_stack_overflow_check(bangsize, r12); } __ push(RegSet::of(rfp, lr), sp); if (framesize != 0) { __ sub(sp, sp, framesize); } // offset from scratch buffer is not valid if (strcmp(cbuf.name(), "Compile::Fill_buffer") == 0) { C->set_frame_complete( __ offset() ); } if (C->has_mach_constant_base_node()) { // NOTE: We set the table base offset here because users might be // emitted before MachConstantBaseNode. Compile::ConstantTable& constant_table = C->constant_table(); constant_table.set_table_base_offset(constant_table.calculate_table_base_offset()); } } uint MachPrologNode::size(PhaseRegAlloc *ra_) const { return MachNode::size(ra_); } int MachPrologNode::reloc() const { return 10; // a large enough number } //============================================================================= #ifndef PRODUCT void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { Compile* C = ra_->C; size_t framesize = C->frame_size_in_bytes(); framesize -= 2*wordSize; if (framesize != 0) { st->print("ADD R_SP, R_SP, " SIZE_FORMAT "\n\t",framesize); } st->print("POP R_FP|R_LR_LR"); if (do_polling() && ra_->C->is_method_compilation()) { st->print("\n\t"); st->print("MOV r12, #PollAddr\t! Load Polling address\n\t"); st->print("LDR r12,[r12]\t!Poll for Safepointing"); } } #endif void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { MacroAssembler _masm(&cbuf); Compile* C = ra_->C; size_t framesize = C->frame_size_in_bytes(); framesize -= 2*wordSize; if (framesize != 0) { __ add(sp, sp, framesize); } __ pop(RegSet::of(rfp, lr), sp); if (StackReservedPages > 0 && C->has_reserved_stack_access()) { __ reserved_stack_check(); } // If this does safepoint polling, then do it here if (do_polling() && ra_->C->is_method_compilation()) { // mov here is usually one or two instruction __ mov_address(r12, (address)os::get_polling_page(), RelocationHolder::none); __ relocate(relocInfo::poll_return_type); __ ldr(r12, Address(r12)); } } uint MachEpilogNode::size(PhaseRegAlloc *ra_) const { return MachNode::size(ra_); } int MachEpilogNode::reloc() const { return 16; // a large enough number } const Pipeline * MachEpilogNode::pipeline() const { return MachNode::pipeline_class(); } int MachEpilogNode::safepoint_offset() const { assert( do_polling(), "no return for this epilog node"); // return MacroAssembler::size_of_sethi(os::get_polling_page()); Unimplemented(); return 0; } //============================================================================= // Figure out which register class each belongs in: rc_int, rc_float, rc_stack enum RC { rc_bad, rc_int, rc_float, rc_stack }; static enum RC rc_class( OptoReg::Name reg ) { if (!OptoReg::is_valid(reg)) return rc_bad; if (OptoReg::is_stack(reg)) return rc_stack; VMReg r = OptoReg::as_VMReg(reg); if (r->is_Register()) return rc_int; assert(r->is_FloatRegister(), "must be"); return rc_float; } static inline bool is_iRegLd_memhd(OptoReg::Name src_first, OptoReg::Name src_second, int offset) { int rlo = Matcher::_regEncode[src_first]; int rhi = Matcher::_regEncode[src_second]; // if (!((rlo&1)==0 && (rlo+1 == rhi))) { // tty->print_cr("CAUGHT BAD LDRD/STRD"); // } return (rlo&1)==0 && (rlo+1 == rhi) && is_memoryHD(offset); } uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, PhaseRegAlloc *ra_, bool do_size, outputStream* st ) const { // Get registers to move OptoReg::Name src_second = ra_->get_reg_second(in(1)); OptoReg::Name src_first = ra_->get_reg_first(in(1)); OptoReg::Name dst_second = ra_->get_reg_second(this ); OptoReg::Name dst_first = ra_->get_reg_first(this ); enum RC src_second_rc = rc_class(src_second); enum RC src_first_rc = rc_class(src_first); enum RC dst_second_rc = rc_class(dst_second); enum RC dst_first_rc = rc_class(dst_first); assert( OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first), "must move at least 1 register" ); // Generate spill code! int size = 0; if (src_first == dst_first && src_second == dst_second) return size; // Self copy, no move #ifdef TODO if (bottom_type()->isa_vect() != NULL) { } #endif // Shared code does not expect instruction set capability based bailouts here. // Handle offset unreachable bailout with minimal change in shared code. // Bailout only for real instruction emit. // This requires a single comment change in shared code. ( see output.cpp "Normal" instruction case ) MacroAssembler _masm(cbuf); // -------------------------------------- // Check for mem-mem move. Load into unused float registers and fall into // the float-store case. if (src_first_rc == rc_stack && dst_first_rc == rc_stack) { int offset = ra_->reg2offset(src_first); if (cbuf && !is_memoryfp(offset)) { ra_->C->record_method_not_compilable("unable to handle large constant offsets"); return 0; } else { if (src_second_rc != rc_bad) { assert((src_first&1)==0 && src_first+1 == src_second, "pair of registers must be aligned/contiguous"); src_first = OptoReg::Name(R_mem_copy_lo_num); src_second = OptoReg::Name(R_mem_copy_hi_num); src_first_rc = rc_float; src_second_rc = rc_float; if (cbuf) { __ vldr_f64(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) { __ vldr_f32(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) { __ strd(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(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) { __ ldrd(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(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) { __ vmov_f64(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) { __ vmov_f32(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) { __ vstr_f64(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) { __ vstr_f32(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) { __ vldr_f64(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) { __ vldr_f32(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) { __ vmov_f64(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) { __ vmov_f32(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) { __ vmov_f64(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) { __ vmov_f32(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first])); #ifndef PRODUCT } else if (!do_size) { if (size != 0) st->print("\n\t"); st->print(FMRS " R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first)); #endif } size += 4; } } // -------------------------------------------------------------------- // Check for hi bits still needing moving. Only happens for misaligned // arguments to native calls. if (src_second == dst_second) return size; // Self copy; no move assert( src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad" ); // Check for integer reg-reg copy. Hi bits are stuck up in the top // 32-bits of a 64-bit register, but are needed in low bits of another // register (else it's a hi-bits-to-hi-bits copy which should have // happened already as part of a 64-bit move) if (src_second_rc == rc_int && dst_second_rc == rc_int) { if (cbuf) { __ mov(reg_to_register_object(Matcher::_regEncode[dst_second]), reg_to_register_object(Matcher::_regEncode[src_second])); #ifndef PRODUCT } else if (!do_size) { if (size != 0) st->print("\n\t"); st->print("MOV R_%s, R_%s\t# spill high", Matcher::regName[dst_second], Matcher::regName[src_second]); #endif } return size+4; } // Check for high word integer store if (src_second_rc == rc_int && dst_second_rc == rc_stack) { int offset = ra_->reg2offset(dst_second); if (cbuf && !is_memoryP(offset)) { ra_->C->record_method_not_compilable("unable to handle large constant offsets"); return 0; } else { if (cbuf) { __ str(reg_to_register_object(Matcher::_regEncode[src_second]), Address(sp, offset)); #ifndef PRODUCT } else if (!do_size) { if (size != 0) st->print("\n\t"); st->print("STR R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_second), offset); #endif } } return size + 4; } // Check for high word integer load if (dst_second_rc == rc_int && src_second_rc == rc_stack) { int offset = ra_->reg2offset(src_second); if (cbuf && !is_memoryP(offset)) { ra_->C->record_method_not_compilable("unable to handle large constant offsets"); return 0; } else { if (cbuf) { __ ldr(reg_to_register_object(Matcher::_regEncode[dst_second]), Address(sp, offset)); #ifndef PRODUCT } else if (!do_size) { if (size != 0) st->print("\n\t"); st->print("LDR R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_second), offset); #endif } } return size + 4; } Unimplemented(); return 0; // Mute compiler } #ifndef PRODUCT void MachSpillCopyNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { implementation( NULL, ra_, false, st ); } #endif void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { implementation( &cbuf, ra_, false, NULL ); } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { return implementation( NULL, ra_, true, NULL ); } //============================================================================= #ifndef PRODUCT void MachNopNode::format( PhaseRegAlloc *, outputStream *st ) const { st->print("NOP \t# %d bytes pad for loops and calls", 4 * _count); } #endif void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc * ) const { MacroAssembler _masm(&cbuf); for(int i = 0; i < _count; i += 1) { __ nop(); } } uint MachNopNode::size(PhaseRegAlloc *ra_) const { return 4 * _count; } //============================================================================= #ifndef PRODUCT void BoxLockNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); int reg = ra_->get_reg_first(this); st->print("ADD %s,R_SP+#%d",Matcher::regName[reg], offset); } #endif void BoxLockNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { MacroAssembler _masm(&cbuf); int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); int reg = ra_->get_encode(this); Register dst = reg_to_register_object(reg); if (is_aimm(offset)) { __ add(dst, sp, offset); } else { __ mov(dst, offset); __ add(dst, sp, dst); } } uint BoxLockNode::size(PhaseRegAlloc *ra_) const { // BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_) assert(ra_ == ra_->C->regalloc(), "sanity"); return ra_->C->scratch_emit_size(this); } //============================================================================= #ifndef PRODUCT #define R_RTEMP "R_R12" void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { st->print_cr("\nUEP:"); if (UseCompressedClassPointers) { st->print_cr("\tLDR_w " R_RTEMP ",[R_R0 + oopDesc::klass_offset_in_bytes]\t! Inline cache check"); st->print_cr("\tdecode_klass " R_RTEMP); } else { st->print_cr("\tLDR " R_RTEMP ",[R_R0 + oopDesc::klass_offset_in_bytes]\t! Inline cache check"); } st->print_cr("\tCMP " R_RTEMP ",R_R12" ); st->print ("\tB.NE SharedRuntime::handle_ic_miss_stub"); } #endif void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { MacroAssembler _masm(&cbuf); Register iCache = reg_to_register_object(Matcher::inline_cache_reg_encode()); assert(iCache == rscratch2/*Ricklass*/, "should be"); Register receiver = r0; __ load_klass(r9, receiver); __ cmp(r9, iCache); // r9 seems temporary here __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, r9, Assembler::NE); } uint MachUEPNode::size(PhaseRegAlloc *ra_) const { return MachNode::size(ra_); } // REQUIRED EMIT CODE //============================================================================= // Emit exception handler code. int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) { MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); if (base == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } int offset = __ offset(); // OK to trash LR, because exception blob will kill it __ jump(OptoRuntime::exception_blob()->entry_point(), relocInfo::runtime_call_type, lr); assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); __ end_a_stub(); return offset; } int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { // Can't use any of the current frame's registers as we may have deopted // at a poll and everything can be live. MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_deopt_handler()); if (base == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } int offset = __ offset(); address deopt_pc = __ pc(); __ sub(sp, sp, wordSize); // make room for saved PC __ push(lr); // save LR that may be live when we get here __ mov_relative_address(lr, deopt_pc); __ str(lr, Address(sp, wordSize)); // save deopt PC __ pop(lr); // restore LR // rscratch1 seems killed at deopt_blob __ jump(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type, rscratch1); assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow"); __ end_a_stub(); return offset; } // REQUIRED MATCHER CODE //============================================================================= 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::features() & FT_AdvSIMD; case Op_LoadVector: case Op_StoreVector: case Op_AddVF: case Op_SubVF: case Op_MulVF: return VM_Version::features() & (FT_VFPV2 | FT_AdvSIMD); case Op_AddVD: case Op_SubVD: case Op_MulVD: case Op_DivVF: case Op_DivVD: return VM_Version::features() & FT_VFPV2; } return true; // Per default match rules are supported. } const bool Matcher::match_rule_supported_vector(int opcode, int vlen) { // TODO // identify extra cases that we might want to provide match rules for // e.g. Op_ vector nodes and other intrinsics while guarding with vlen bool ret_value = match_rule_supported(opcode); // Add rules here. return ret_value; // Per default match rules are supported. } const bool Matcher::has_predicated_vectors(void) { return false; } const int Matcher::float_pressure(int default_pressure_threshold) { return default_pressure_threshold; } int Matcher::regnum_to_fpu_offset(int regnum) { return regnum - 32; // The FP registers are in the second chunk } // Vector width in bytes const int Matcher::vector_width_in_bytes(BasicType bt) { return MaxVectorSize; } // Vector ideal reg corresponding to specified size in bytes const uint Matcher::vector_ideal_reg(int size) { assert(MaxVectorSize >= size, ""); switch(size) { case 8: return Op_VecD; case 16: return Op_VecX; } ShouldNotReachHere(); return 0; } const uint Matcher::vector_shift_count_ideal_reg(int size) { return vector_ideal_reg(size); } // Limits on vector size (number of elements) loaded into vector. const int Matcher::max_vector_size(const BasicType bt) { assert(is_java_primitive(bt), "only primitive type vectors"); return vector_width_in_bytes(bt)/type2aelembytes(bt); } const int Matcher::min_vector_size(const BasicType bt) { assert(is_java_primitive(bt), "only primitive type vectors"); return 8/type2aelembytes(bt); } // ARM doesn't support misaligned vectors store/load. const bool Matcher::misaligned_vectors_ok() { return false; } // ARM doesn't support AES intrinsics const bool Matcher::pass_original_key_for_aes() { return false; } const bool Matcher::convL2FSupported(void) { return false; // TODO why not? } // 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; // Should the Matcher clone shifts on addressing modes, expecting them // to be subsumed into complex addressing expressions or compute them // into registers? bool Matcher::clone_address_expressions(AddPNode* m, Matcher::MStack& mstack, VectorSet& address_visited) { return clone_base_plus_offset_address(m, mstack, address_visited); } void Compile::reshape_address(AddPNode* addp) { } bool Matcher::narrow_oop_use_complex_address() { ShouldNotCallThis(); return false; } bool Matcher::narrow_klass_use_complex_address() { ShouldNotCallThis(); return false; } bool Matcher::const_oop_prefer_decode() { ShouldNotCallThis(); return true; } bool Matcher::const_klass_prefer_decode() { ShouldNotCallThis(); return true; } // Is it better to copy float constants, or load them directly from memory? // Intel can load a float constant from a direct address, requiring no // extra registers. Most RISCs will have to materialize an address into a // register first, so they would do better to copy the constant from stack. const bool Matcher::rematerialize_float_constants = false; // If CPU can load and store mis-aligned doubles directly then no fixup is // needed. Else we split the double into 2 integer pieces and move it // piece-by-piece. Only happens when passing doubles into C code as the // Java calling convention forces doubles to be aligned. const bool Matcher::misaligned_doubles_ok = false; // No-op on ARM. void Matcher::pd_implicit_null_fixup(MachNode *node, uint idx) { } // Advertise here if the CPU requires explicit rounding operations // to implement the UseStrictFP mode. const bool Matcher::strict_fp_requires_explicit_rounding = false; // Are floats converted to double when stored to stack during deoptimization? // ARM does not handle callee-save floats. bool Matcher::float_in_double() { return false; } // Do ints take an entire long register or just half? // Note that we if-def off of _LP64. // The relevant question is how the int is callee-saved. In _LP64 // the whole long is written but de-opt'ing will have to extract // the relevant 32 bits, in not-_LP64 only the low 32 bits is written. const bool Matcher::int_in_long = false; // 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_S15_num) return true; return false; } bool Matcher::is_spillable_arg( int reg ) { return can_be_java_arg(reg); } bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) { return false; } // Register for DIVI projection of divmodI RegMask Matcher::divI_proj_mask() { ShouldNotReachHere(); return RegMask(); } // Register for MODI projection of divmodI RegMask Matcher::modI_proj_mask() { ShouldNotReachHere(); return RegMask(); } // Register for DIVL projection of divmodL RegMask Matcher::divL_proj_mask() { ShouldNotReachHere(); return RegMask(); } // Register for MODL projection of divmodL RegMask Matcher::modL_proj_mask() { ShouldNotReachHere(); return RegMask(); } const RegMask Matcher::method_handle_invoke_SP_save_mask() { return FP_REGP_mask(); } bool maybe_far_call(const CallNode *n) { return !MacroAssembler::_reachable_from_cache(n->as_Call()->entry_point()); } bool maybe_far_call(const MachCallNode *n) { return !MacroAssembler::_reachable_from_cache(n->as_MachCall()->entry_point()); } %} //----------ENCODING BLOCK----------------------------------------------------- // This block specifies the encoding classes used by the compiler to output // byte streams. Encoding classes are parameterized macros used by // Machine Instruction Nodes in order to generate the bit encoding of the // instruction. Operands specify their base encoding interface with the // interface keyword. There are currently supported four interfaces, // REG_INTER, CONST_INTER, MEMORY_INTER, & COND_INTER. REG_INTER causes an // operand to generate a function which returns its register number when // queried. CONST_INTER causes an operand to generate a function which // returns the value of the constant when queried. MEMORY_INTER causes an // operand to generate four functions which return the Base Register, the // Index Register, the Scale Value, and the Offset Value of the operand when // queried. COND_INTER causes an operand to generate six functions which // return the encoding code (ie - encoding bits for the instruction) // associated with each basic boolean condition for a conditional instruction. // // Instructions specify two basic values for encoding. Again, a function // is available to check if the constant displacement is an oop. They use the // ins_encode keyword to specify their encoding classes (which must be // a sequence of enc_class names, and their parameters, specified in // the encoding block), and they use the // opcode keyword to specify, in order, their primary, secondary, and // tertiary opcode. Only the opcode sections which a particular instruction // needs for encoding need to be specified. encode %{ enc_class call_epilog %{ // nothing %} enc_class Java_To_Runtime (method meth) %{ // CALL directly to the runtime emit_call_reloc(cbuf, as_MachCall(), $meth, runtime_call_Relocation::spec()); %} enc_class Java_Static_Call (method meth) %{ // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine // who we intended to call. if ( !_method) { emit_call_reloc(cbuf, as_MachCall(), $meth, runtime_call_Relocation::spec()); } else { int method_index = resolved_method_index(cbuf); RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) : static_call_Relocation::spec(method_index); emit_call_reloc(cbuf, as_MachCall(), $meth, rspec); // Emit stubs for static call. address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); if (stub == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } } %} enc_class save_last_PC %{ // preserve mark address mark = cbuf.insts()->mark(); debug_only(int off0 = cbuf.insts_size()); MacroAssembler _masm(&cbuf); int ret_addr_offset = as_MachCall()->ret_addr_offset(); __ adr(lr, mark + ret_addr_offset); __ str(lr, Address(Rthread, JavaThread::last_Java_pc_offset())); debug_only(int off1 = cbuf.insts_size()); assert(off1 - off0 == 2 * Assembler::InstructionSize, "correct size prediction"); // restore mark cbuf.insts()->set_mark(mark); %} enc_class preserve_SP %{ // preserve mark address mark = cbuf.insts()->mark(); debug_only(int off0 = cbuf.insts_size()); MacroAssembler _masm(&cbuf); // FP is preserved across all calls, even compiled calls. // Use it to preserve SP in places where the callee might change the SP. __ mov(Rmh_SP_save, sp); debug_only(int off1 = cbuf.insts_size()); assert(off1 - off0 == 4, "correct size prediction"); // restore mark cbuf.insts()->set_mark(mark); %} enc_class restore_SP %{ MacroAssembler _masm(&cbuf); __ mov(sp, Rmh_SP_save); %} enc_class Java_Dynamic_Call (method meth) %{ MacroAssembler _masm(&cbuf); Register R12_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode()); assert(R12_ic_reg == rscratch2/*Ricklass*/, "should be"); __ set_inst_mark(); __ movw_i(R12_ic_reg, ((unsigned int)Universe::non_oop_word()) & 0xffff); __ movt_i(R12_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); emit_call_reloc(cbuf, as_MachCall(), $meth, virtual_call_Relocation::spec(virtual_call_oop_addr, method_index)); %} enc_class LdReplImmI(immI src, regD dst, iRegI tmp, int cnt, int wth) %{ // FIXME: load from constant table? // Load a constant replicated "count" times with width "width" int count = $cnt$$constant; int width = $wth$$constant; assert(count*width == 4, "sanity"); int val = $src$$constant; if (width < 4) { int bit_width = width * 8; val &= (((int)1) << bit_width) - 1; // mask off sign bits for (int i = 0; i < count - 1; i++) { val |= (val << bit_width); } } MacroAssembler _masm(&cbuf); if (val == -1) { __ mvn_i($tmp$$Register, 0); } else if (val == 0) { __ mov_i($tmp$$Register, 0); } else { __ movw_i($tmp$$Register, val & 0xffff); __ movt_i($tmp$$Register, (unsigned int)val >> 16); } __ vmov_f64($dst$$FloatRegister, $tmp$$Register, $tmp$$Register); %} enc_class LdReplImmF(immF src, regD dst, iRegI tmp) %{ // Replicate float con 2 times and pack into vector (8 bytes) in regD. float fval = $src$$constant; int val = *((int*)&fval); MacroAssembler _masm(&cbuf); if (val == -1) { __ mvn_i($tmp$$Register, 0); } else if (val == 0) { __ mov_i($tmp$$Register, 0); } else { __ movw_i($tmp$$Register, val & 0xffff); __ movt_i($tmp$$Register, (unsigned int)val >> 16); } __ vmov_f64($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, Q0_regD ftmp1, Q1_regD ftmp2, int bytes_per_char1, int bytes_per_char2) %{ MacroAssembler _masm(&cbuf); Register str1 = $str1$$Register; Register str2 = $str2$$Register; Register cnt1 = $cnt1$$Register; Register cnt2 = $cnt2$$Register; Register tmp1 = $tmp1$$Register; Register tmp2 = $tmp2$$Register; FloatRegister ftmp1 = $ftmp1$$FloatRegister; FloatRegister ftmp2 = $ftmp2$$FloatRegister; Register result = $result$$Register; int bytes_per_char1 = $bytes_per_char1; int bytes_per_char2 = $bytes_per_char2; typedef void (Assembler::*ldfp)(Register, const Address &, Assembler::Condition); typedef void (Assembler::*usubp)(Register, Register, Register, Assembler::Condition); ldfp ldf_16 = &Assembler::ldrh; ldfp ldf_8 = &Assembler::ldrb; // slow path: single char load int cnt_per_char = bytes_per_char1==2 && bytes_per_char2==2 ? 2 : 1; ldfp lds1 = bytes_per_char1 == 2 ? ldf_16 : ldf_8; ldfp lds2 = bytes_per_char2 == 2 ? ldf_16 : ldf_8; usubp usub = bytes_per_char1 == 1 ? (usubp)&Assembler::usub8 : (usubp)&Assembler::usub16; assert_different_registers(str1, str2, cnt1, cnt2, tmp1, tmp2, result); Label Llength_diff, Ldone, Lshort_loop; BLOCK_COMMENT("string_compare {"); // for UU we count bytes (saves 1 insn) for others count in chars if (cnt_per_char == 1 && bytes_per_char1 == 2) __ lsr(cnt1, cnt1, 1); if (cnt_per_char == 1 && bytes_per_char2 == 2) __ lsr(cnt2, cnt2, 1); // Compute the minimum of the string lengths and save the difference. __ subs(tmp1, cnt1, cnt2); __ mov(cnt2, cnt1, Assembler::LE); // min // Check if the strings start at the same location. __ cmp(str1, str2); __ b(Llength_diff, Assembler::EQ); // without NEON only for UU and LL fast path is available if ((VM_Version::features() & FT_AdvSIMD) || bytes_per_char1 == bytes_per_char2) { Label Lshort_string, Lnext_word, Ldifference; // A very short string __ cmp(cnt2, 8+4); __ b(Lshort_string, Assembler::LT); // Compare words { const int bits_per_char = bytes_per_char1==1 && bytes_per_char2==1 ? 8 : 16; // Check first few chars to avoid excessive processing if (bytes_per_char1 == 1 && bytes_per_char2 == 1) { Label Lfull_speed; __ ldr(tmp2, __ post(str1, wordSize)); __ ldr(result, __ post(str2, wordSize)); (_masm.*usub)(result, tmp2, result, Assembler::AL); __ tst(result, result); __ b(Lfull_speed, Assembler::EQ); __ rbit(cnt1, result); __ clz(cnt1, cnt1); __ bic(cnt1, cnt1, bits_per_char-1); __ lsr(result, result, cnt1); __ lsr(tmp2, tmp2, cnt1); __ ubfx(result, result, 0, bits_per_char); __ ubfx(tmp2, tmp2, 0, bits_per_char); __ cmp(result, tmp2); __ sub(result, result, 1< 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. return_value %{ return c2::return_value(ideal_reg); %} // Location of C return values. c_return_value %{ #ifndef HARD_FLOAT_CC return c2::c_return_value(ideal_reg); #else return c2::return_value(ideal_reg); #endif %} %} //----------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::features() & FT_ARMV6T2)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: offset for half and double word loads and stores operand immIHD() %{ predicate(is_memoryHD(n->get_int())); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: offset for fp loads and stores operand immIFP() %{ predicate(is_memoryfp(n->get_int()) && ((n->get_int() & 3) == 0)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Valid scale values for addressing modes and shifts operand immU5() %{ predicate(0 <= n->get_int() && (n->get_int() <= 31)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: 6-bit operand immU6Big() %{ predicate(n->get_int() >= 32 && n->get_int() <= 63); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: 0-bit operand immI0() %{ predicate(n->get_int() == 0); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: the value 1 operand immI_1() %{ predicate(n->get_int() == 1); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: the value 2 operand immI_2() %{ predicate(n->get_int() == 2); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: the value 3 operand immI_3() %{ predicate(n->get_int() == 3); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: the value 4 operand immI_4() %{ predicate(n->get_int() == 4); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: the value 8 operand immI_8() %{ predicate(n->get_int() == 8); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Int Immediate non-negative operand immU31() %{ predicate(n->get_int() >= 0); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: the values 32-63 operand immI_32_63() %{ predicate(n->get_int() >= 32 && n->get_int() <= 63); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Immediates for special shifts (sign extend) // Integer Immediate: the value 16 operand immI_16() %{ predicate(n->get_int() == 16); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: the value 24 operand immI_24() %{ predicate(n->get_int() == 24); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: the value 255 operand immI_255() %{ predicate( n->get_int() == 255 ); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediate: the value 65535 operand immI_65535() %{ predicate(n->get_int() == 65535); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediates for arithmetic instructions operand aimmI() %{ predicate(is_aimm(n->get_int())); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand aimmIneg() %{ predicate(is_aimm(-n->get_int())); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand aimmU31() %{ predicate((0 <= n->get_int()) && is_aimm(n->get_int())); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer Immediates for logical instructions operand limmI() %{ predicate(is_limmI(n->get_int())); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand limmIlow8() %{ predicate(is_limmI_low(n->get_int(), 8)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand limmU31() %{ predicate(0 <= n->get_int() && is_limmI(n->get_int())); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand limmIn() %{ predicate(is_limmI(~n->get_int())); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Long Immediate: the value FF operand immL_FF() %{ predicate( n->get_long() == 0xFFL ); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // Long Immediate: the value FFFF operand immL_FFFF() %{ predicate( n->get_long() == 0xFFFFL ); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // Pointer Immediate: 32 or 64-bit operand immP() %{ match(ConP); op_cost(5); // formats are generated automatically for constants and base registers format %{ %} interface(CONST_INTER); %} operand immP0() %{ predicate(n->get_ptr() == 0); match(ConP); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immP_poll() %{ predicate(n->get_ptr() != 0 && n->get_ptr() == (intptr_t)os::get_polling_page()); match(ConP); // formats are generated automatically for constants and base registers format %{ %} interface(CONST_INTER); %} // Pointer Immediate operand immN() %{ match(ConN); op_cost(10); format %{ %} interface(CONST_INTER); %} operand immNKlass() %{ match(ConNKlass); op_cost(10); format %{ %} interface(CONST_INTER); %} // NULL Pointer Immediate operand immN0() %{ predicate(n->get_narrowcon() == 0); match(ConN); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immL() %{ match(ConL); op_cost(40); // formats are generated automatically for constants and base registers format %{ %} interface(CONST_INTER); %} operand immL0() %{ predicate(n->get_long() == 0L); match(ConL); op_cost(0); // formats are generated automatically for constants and base registers format %{ %} interface(CONST_INTER); %} // Long Immediate: 16-bit operand immL16() %{ predicate(n->get_long() >= 0 && n->get_long() < (1<<16) && (VM_Version::features() & FT_ARMV6T2)); 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::operand_valid_for_double_immediate(n->getd())); 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::operand_valid_for_float_immediate(n->getf())); 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(RmethodRegP); // R8 match(R9RegP); match(RthreadRegP); // R10, TODO Oracle FIXME: move to sp_ptr_RegP? match(R12RegP); match(LRRegP); match(sp_ptr_RegP); match(store_ptr_RegP); format %{ %} interface(REG_INTER); %} // GPRs + Rmethod + 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 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 RmethodRegP() %{ constraint(ALLOC_IN_RC(Rmethod_regP)); match(iRegP); format %{ %} interface(REG_INTER); %} operand IPRegP() %{ constraint(ALLOC_IN_RC(IP_regP)); match(iRegP); format %{ %} interface(REG_INTER); %} operand LRRegP() %{ constraint(ALLOC_IN_RC(LR_regP)); match(iRegP); format %{ %} interface(REG_INTER); %} operand R0RegI() %{ constraint(ALLOC_IN_RC(R0_regI)); match(iRegI); format %{ %} interface(REG_INTER); %} operand R1RegI() %{ constraint(ALLOC_IN_RC(R1_regI)); match(iRegI); format %{ %} interface(REG_INTER); %} operand R2RegI() %{ constraint(ALLOC_IN_RC(R2_regI)); match(iRegI); format %{ %} interface(REG_INTER); %} operand R3RegI() %{ constraint(ALLOC_IN_RC(R3_regI)); match(iRegI); format %{ %} interface(REG_INTER); %} operand R9RegI() %{ constraint(ALLOC_IN_RC(R9_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); 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 flagsRegUL() %{ constraint(ALLOC_IN_RC(int_flags)); match(RegFlags); format %{ "apsr_UL" %} 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); %} // 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 Q0_regD() %{ constraint(ALLOC_IN_RC(D0D1_regD)); match(RegD); match(regD_low); format %{ %} interface(REG_INTER); %} operand Q1_regD() %{ constraint(ALLOC_IN_RC(D2D3_regD)); 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 CLASSES---------------------------------------------------- // Operand Classes are groups of operands that are used to simplify // instruction definitions by not requiring the AD writer to specify separate // instructions for every form of operand when the instruction accepts // multiple operand types with the same basic encoding and format. The classic // case of this is memory operands. opclass memoryI ( indirect, indOffset12, indIndex, indIndexScale ); opclass memoryP ( indirect, indOffset12, indIndex, indIndexScale ); opclass memoryF ( indirect, indOffsetFP ); opclass memoryF2 ( indirect, indOffsetFPx2 ); opclass memoryD ( indirect, indOffsetFP ); opclass memoryfp( indirect, indOffsetFP ); opclass memoryB ( indirect, indIndex, indOffsetHD ); opclass memoryS ( indirect, indIndex, indOffsetHD ); opclass memoryL ( indirect, indIndex, indOffsetHD ); opclass memoryScaledI(indIndexScale); opclass memoryScaledP(indIndexScale); // when ldrex/strex is used: opclass memoryex ( indirect ); opclass indIndexMemory( indIndex ); opclass memorylong ( indirect, indOffset12x2 ); opclass memoryvld ( indirect /* , write back mode not implemented */ ); //----------PIPELINE----------------------------------------------------------- pipeline %{ //----------ATTRIBUTES--------------------------------------------------------- attributes %{ fixed_size_instructions; // Fixed size instructions max_instructions_per_bundle = 4; // Up to 4 instructions per bundle instruction_unit_size = 4; // An instruction is 4 bytes long instruction_fetch_unit_size = 16; // The processor fetches one line instruction_fetch_units = 1; // of 16 bytes // List of nop instructions nops( Nop_A0, Nop_A1, Nop_MS, Nop_FA, Nop_BR ); %} //----------RESOURCES---------------------------------------------------------- // Resources are the functional units available to the machine resources(A0, A1, MS, BR, FA, FM, IDIV, FDIV, IALU = A0 | A1); //----------PIPELINE DESCRIPTION----------------------------------------------- // Pipeline Description specifies the stages in the machine's pipeline pipe_desc(A, P, F, B, I, J, S, R, E, C, M, W, X, T, D); //----------PIPELINE CLASSES--------------------------------------------------- // Pipeline Classes describe the stages in which input and output are // referenced by the hardware pipeline. // Integer ALU reg-reg operation pipe_class ialu_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ single_instruction; dst : E(write); src1 : R(read); src2 : R(read); IALU : R; %} // Integer ALU reg-reg long operation pipe_class ialu_reg_reg_2(iRegL dst, iRegL src1, iRegL src2) %{ instruction_count(2); dst : E(write); src1 : R(read); src2 : R(read); IALU : R; IALU : R; %} // Integer ALU reg-reg long dependent operation pipe_class ialu_reg_reg_2_dep(iRegL dst, iRegL src1, iRegL src2, flagsReg cr) %{ instruction_count(1); multiple_bundles; dst : E(write); src1 : R(read); src2 : R(read); cr : E(write); IALU : R(2); %} // Integer ALU reg-imm operaion pipe_class ialu_reg_imm(iRegI dst, iRegI src1) %{ single_instruction; dst : E(write); src1 : R(read); IALU : R; %} // Integer ALU reg-reg operation with condition code pipe_class ialu_cc_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{ single_instruction; dst : E(write); cr : E(write); src1 : R(read); src2 : R(read); IALU : R; %} // Integer ALU zero-reg operation pipe_class ialu_zero_reg(iRegI dst, immI0 zero, iRegI src2) %{ single_instruction; dst : E(write); src2 : R(read); IALU : R; %} // Integer ALU zero-reg operation with condition code only pipe_class ialu_cconly_zero_reg(flagsReg cr, iRegI src) %{ single_instruction; cr : E(write); src : R(read); IALU : R; %} // Integer ALU reg-reg operation with condition code only pipe_class ialu_cconly_reg_reg(flagsReg cr, iRegI src1, iRegI src2) %{ single_instruction; cr : E(write); src1 : R(read); src2 : R(read); IALU : R; %} // Integer ALU reg-imm operation with condition code only pipe_class ialu_cconly_reg_imm(flagsReg cr, iRegI src1) %{ single_instruction; cr : E(write); src1 : R(read); IALU : R; %} // Integer ALU reg-reg-zero operation with condition code only pipe_class ialu_cconly_reg_reg_zero(flagsReg cr, iRegI src1, iRegI src2, immI0 zero) %{ single_instruction; cr : E(write); src1 : R(read); src2 : R(read); IALU : R; %} // Integer ALU reg-imm-zero operation with condition code only pipe_class ialu_cconly_reg_imm_zero(flagsReg cr, iRegI src1, immI0 zero) %{ single_instruction; cr : E(write); src1 : R(read); IALU : R; %} // Integer ALU reg-reg operation with condition code, src1 modified pipe_class ialu_cc_rwreg_reg(flagsReg cr, iRegI src1, iRegI src2) %{ single_instruction; cr : E(write); src1 : E(write); src1 : R(read); src2 : R(read); IALU : R; %} pipe_class cmpL_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg cr ) %{ multiple_bundles; dst : E(write)+4; cr : E(write); src1 : R(read); src2 : R(read); IALU : R(3); BR : R(2); %} // Integer ALU operation pipe_class ialu_none(iRegI dst) %{ single_instruction; dst : E(write); IALU : R; %} // Integer ALU reg operation pipe_class ialu_reg(iRegI dst, iRegI src) %{ single_instruction; may_have_no_code; dst : E(write); src : R(read); IALU : R; %} // Integer ALU reg conditional operation // This instruction has a 1 cycle stall, and cannot execute // in the same cycle as the instruction setting the condition // code. We kludge this by pretending to read the condition code // 1 cycle earlier, and by marking the functional units as busy // for 2 cycles with the result available 1 cycle later than // is really the case. pipe_class ialu_reg_flags( iRegI op2_out, iRegI op2_in, iRegI op1, flagsReg cr ) %{ single_instruction; op2_out : C(write); op1 : R(read); cr : R(read); // This is really E, with a 1 cycle stall BR : R(2); MS : R(2); %} // Integer ALU reg operation pipe_class ialu_move_reg_L_to_I(iRegI dst, iRegL src) %{ single_instruction; may_have_no_code; dst : E(write); src : R(read); IALU : R; %} pipe_class ialu_move_reg_I_to_L(iRegL dst, iRegI src) %{ single_instruction; may_have_no_code; dst : E(write); src : R(read); IALU : R; %} // Two integer ALU reg operations pipe_class ialu_reg_2(iRegL dst, iRegL src) %{ instruction_count(2); dst : E(write); src : R(read); A0 : R; A1 : R; %} // Two integer ALU reg operations pipe_class ialu_move_reg_L_to_L(iRegL dst, iRegL src) %{ instruction_count(2); may_have_no_code; dst : E(write); src : R(read); A0 : R; A1 : R; %} // Integer ALU imm operation pipe_class ialu_imm(iRegI dst) %{ single_instruction; dst : E(write); IALU : R; %} pipe_class ialu_imm_n(iRegI dst) %{ single_instruction; dst : E(write); IALU : R; %} // Integer ALU reg-reg with carry operation pipe_class ialu_reg_reg_cy(iRegI dst, iRegI src1, iRegI src2, iRegI cy) %{ single_instruction; dst : E(write); src1 : R(read); src2 : R(read); IALU : R; %} // Integer ALU cc operation pipe_class ialu_cc(iRegI dst, flagsReg cc) %{ single_instruction; dst : E(write); cc : R(read); IALU : R; %} // Integer ALU cc / second IALU operation pipe_class ialu_reg_ialu( iRegI dst, iRegI src ) %{ instruction_count(1); multiple_bundles; dst : E(write)+1; src : R(read); IALU : R; %} // Integer ALU cc / second IALU operation pipe_class ialu_reg_reg_ialu( iRegI dst, iRegI p, iRegI q ) %{ instruction_count(1); multiple_bundles; dst : E(write)+1; p : R(read); q : R(read); IALU : R; %} // Integer ALU hi-lo-reg operation pipe_class ialu_hi_lo_reg(iRegI dst, immI src) %{ instruction_count(1); multiple_bundles; dst : E(write)+1; IALU : R(2); %} // Long Constant pipe_class loadConL( iRegL dst, immL src ) %{ instruction_count(2); multiple_bundles; dst : E(write)+1; IALU : R(2); IALU : R(2); %} // Pointer Constant pipe_class loadConP( iRegP dst, immP src ) %{ instruction_count(0); multiple_bundles; fixed_latency(6); %} // Polling Address pipe_class loadConP_poll( iRegP dst, immP_poll src ) %{ dst : E(write); IALU : R; %} // Long Constant small pipe_class loadConLlo( iRegL dst, immL src ) %{ instruction_count(2); dst : E(write); IALU : R; IALU : R; %} // [PHH] This is wrong for 64-bit. See LdImmF/D. pipe_class loadConFD(regF dst, immF src, iRegP tmp) %{ instruction_count(1); multiple_bundles; src : R(read); dst : M(write)+1; IALU : R; MS : E; %} // Integer ALU nop operation pipe_class ialu_nop() %{ single_instruction; IALU : R; %} // Integer ALU nop operation pipe_class ialu_nop_A0() %{ single_instruction; A0 : R; %} // Integer ALU nop operation pipe_class ialu_nop_A1() %{ single_instruction; A1 : R; %} // Integer Multiply reg-reg operation pipe_class imul_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ single_instruction; dst : E(write); src1 : R(read); src2 : R(read); MS : R(5); %} pipe_class mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ single_instruction; dst : E(write)+4; src1 : R(read); src2 : R(read); MS : R(6); %} // Integer Divide reg-reg pipe_class sdiv_reg_reg_IDIV(iRegI dst, iRegI src1, iRegI src2, iRegI temp, flagsReg cr) %{ single_instruction; dst : E(write); temp : E(write); src1 : R(read); src2 : R(read); temp : R(read); MS : R(10); %} pipe_class sdiv_reg_reg_SW(iRegI dst, iRegI src1, iRegI src2, iRegI temp1, iRegI temp2, flagsReg cr) %{ instruction_count(1); multiple_bundles; dst : E(write); temp1 : E(write); temp2 : E(write); src1 : R(read); src2 : R(read); temp1 : R(read); temp2 : 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(), $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 %{ // High 32 bits are harmlessly set on Aarch64 __ ldrsb($dst$$Register, $mem$$Address); %} ins_pipe(iload_mask_mem); %} // Load Short (16bit signed) into a Long Register instruct loadS2L(iRegL dst, memoryS mem) %{ match(Set dst (ConvI2L (LoadS mem))); ins_cost(MEMORY_REF_COST); 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(), $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 $dst,$mem\t! int" %} ins_encode %{ __ ldr($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(), $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($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 %{ "ldrd $dst,$mem\t! long" %} ins_encode %{ __ ldrd($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 %{ "LDREXD $dst,$mem\t! long" %} ins_encode %{ __ atomic_ldrd($dst$$Register, reg_to_register_object($dst$$reg + 1), reg_to_register_object($mem$$base)); %} 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 %{ __ vldr_f64(f14, $mem$$Address); __ vmov_f64($dst$$Register, $dst$$Register->successor(), f14); %} 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($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); %} // 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); %} 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 %{ __ vldr_f64($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); __ vldr_f32($dst$$FloatRegister, Amemlo); __ vldr_f32($dst$$FloatRegister->successor(FloatRegisterImpl::SINGLE), 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 %{ __ vldr_f32($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($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_i($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_i($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) { __ movoop($dst$$Register, (jobject)val, true); } else if (constant_reloc == relocInfo::metadata_type) { __ mov_metadata($dst$$Register, (Metadata*)val); } else { __ mov($dst$$Register, val); } %} ins_pipe(loadConP); %} instruct loadConP_poll(iRegP dst, immP_poll src) %{ match(Set dst src); ins_cost(DEFAULT_COST); format %{ "MOV_SLOW $dst,$src\t!ptr" %} ins_encode %{ __ mov($dst$$Register, $src$$constant); %} ins_pipe(loadConP_poll); %} instruct loadConL(iRegL dst, immL src) %{ match(Set dst src); ins_cost(DEFAULT_COST * 4); format %{ "MOV_SLOW $dst.lo, $src & 0x0FFFFFFFFL \t! long\n\t" "MOV_SLOW $dst.hi, $src >> 32" %} ins_encode %{ __ mov(reg_to_register_object($dst$$reg), $src$$constant & 0x0FFFFFFFFL); __ mov(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_i($dst$$Register, $src$$constant); __ movw_i(reg_to_register_object($dst$$reg + 1), 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 %{ __ vmov_f32($dst$$FloatRegister, $src$$constant); %} 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($tmp$$Register, v.i); __ vmov_f32($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 %{ __ vmov_f64($dst$$FloatRegister, $src$$constant); %} 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($tmp$$Register, r, offset); r = $tmp$$Register; offset = 0; } __ vldr_f64($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::features() & FT_MP_EXT); 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::features() & FT_MP_EXT)); 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 $src,$mem" %} ins_encode %{ __ str($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 %{ "strd $src,$mem\t! long\n\t" %} ins_encode %{ __ strd($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 // TODO: need 3 temp registers to use atomic_strd __ stmia(reg_to_register_object($mem$$base), RegSet::of($src$$Register, reg_to_register_object($src$$reg + 1)).bits(), /*wb*/false); %} 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 %{ __ vmov_f64(f14, $src$$Register, $src$$Register->successor()); __ vstr_f64(f14, $mem$$Address); %} ins_pipe(istore_mem_reg); %} // 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); %} // 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 %{ __ vstr_f64($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 %{ __ vstr_f32($src$$FloatRegister, $mem$$Address); %} ins_pipe(fstoreF_mem_reg); %} //----------MemBar Instructions----------------------------------------------- // Memory barrier flavors // TODO: take advantage of Aarch64 load-acquire, store-release, etc // pattern-match out unnecessary membars instruct membar_storestore() %{ match(MemBarStoreStore); ins_cost(4*MEMORY_REF_COST); size(4); format %{ "MEMBAR-storestore" %} ins_encode %{ __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore)); %} 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)); %} 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)); %} 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); %} 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, (Assembler::Condition)($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, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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 %{ __ vmov_f32($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f32($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f32($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f32($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f64($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f64($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f64($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f64($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), $src$$Register->successor(), (Assembler::Condition)($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, (long)$src$$constant, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), 0, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), 0, (Assembler::Condition)($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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), $src$$Register->successor(), (Assembler::Condition)($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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), $src$$Register->successor(), (Assembler::Condition)($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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), 0, (Assembler::Condition)($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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), 0, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($cmp$$cmpcode)); __ movw_i($dst$$Register->successor(), 0, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($cmp$$cmpcode)); __ movw_i($dst$$Register->successor(), 0, (Assembler::Condition)($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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), $src$$Register->successor(), (Assembler::Condition)($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($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($dst$$Register, $src3$$Register, $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($dst$$Register, $src3$$Register, $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($dst$$Register, $src3$$Register, $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($dst$$Register, $src3$$Register, $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($dst$$Register, $src3$$Register, $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($dst$$Register, $src3$$Register, $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($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, 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); ins_cost(DEFAULT_COST*2); 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: 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, (long)$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. // TODO: optimize out barriers with AArch64 load-acquire/store-release // LoadP-locked. instruct loadPLocked(iRegP dst, memoryex mem) %{ match(Set dst (LoadPLocked mem)); size(4); format %{ "LDREX $dst,$mem" %} ins_encode %{ __ 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, Assembler::EQ); __ cmp($tmp$$Register, 1, Assembler::EQ); __ b(loop, Assembler::EQ); __ teq($tmp$$Register, 0); // used by biased locking only. Requires a membar. __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadStore | MacroAssembler::LoadLoad)); %} 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(), Assembler::EQ); __ strexd($tmp$$Register, $newval$$Register, $mem$$Address, Assembler::EQ); __ mov($tmp$$Register, 0, Assembler::NE); __ eors($tmp$$Register, $tmp$$Register, 1, Assembler::EQ); __ b(loop, Assembler::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, Assembler::EQ); __ mov($tmp$$Register, 0, Assembler::NE); __ eors($tmp$$Register, $tmp$$Register, 1, Assembler::EQ); __ b(loop, Assembler::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, Assembler::EQ); __ mov($tmp$$Register, 0, Assembler::NE); __ eors($tmp$$Register, $tmp$$Register, 1, Assembler::EQ); __ b(loop, Assembler::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, Assembler::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, Assembler::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, Assembler::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, Assembler::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, Assembler::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, (long)$add$$constant); __ adc($tmp1$$Register->successor(), $tmp1$$Register->successor(), 0); __ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address); __ cmp($tmp2$$Register, 0); __ b(loop, Assembler::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, Assembler::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, (long)$add$$constant); __ adc($tmp1$$Register->successor(), $res$$Register->successor(), 0); __ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address); __ cmp($tmp2$$Register, 0); __ b(loop, Assembler::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, Assembler::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, Assembler::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, Assembler::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($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, $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($dst$$Register, $src1$$Register, $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, $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($dst$$Register, $src1$$Register, $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, $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($dst$$Register, $src1$$Register, $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, $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, $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, $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, $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, $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, $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($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($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); %} // 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, (long)$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)); ins_cost(DEFAULT_COST); size(4); format %{ "mul_32 $dst,$src1,$src2" %} ins_encode %{ __ mul($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); ins_cost(DEFAULT_COST); 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); ins_cost(DEFAULT_COST*3/2); 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); ins_cost(DEFAULT_COST*3/2); 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)); ins_cost(DEFAULT_COST*8/2); expand %{ mulL_lo1_hi2(dst, src1, src2); mulL_hi1_lo2(dst, src1, src2); mulL_lo1_lo2(dst, src1, src2); %} %} instruct mla_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI srcA) %{ match(Set dst (AddI (MulI src1 src2) srcA)); ins_cost(DEFAULT_COST*3/2); size(4); format %{ "MLA $dst,$src1,$src2,$srcA" %} ins_encode %{ __ mla($dst$$Register, $src1$$Register, $src2$$Register, $srcA$$Register); %} ins_pipe(ialu_reg_reg); %} instruct mls_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI srcA) %{ match(Set dst (SubI srcA (MulI src1 src2))); ins_cost(DEFAULT_COST*3/2); size(4); format %{ "MLS $dst,$src1,$src2,$srcA" %} ins_encode %{ __ mls($dst$$Register, $src1$$Register, $src2$$Register, $srcA$$Register); %} ins_pipe(ialu_reg_reg); %} instruct smlal_reg_reg_reg(iRegL dst, iRegI src1, iRegI src2) %{ match(Set dst (AddL (MulL (ConvI2L src1) (ConvI2L src2)) dst)); ins_cost(DEFAULT_COST*3/2); size(4); format %{ "SMLAL $dst.lo,$dst.hi,$src1,$src2" %} ins_encode %{ __ smlal($dst$$Register, $dst$$Register->successor(), $src1$$Register, $src2$$Register); %} ins_pipe(ialu_reg_reg); %} instruct smull_reg_reg_reg(iRegL dst, iRegI src1, iRegI src2) %{ match(Set dst (MulL (ConvI2L src1) (ConvI2L src2))); ins_cost(DEFAULT_COST*3/2); size(4); format %{ "SMULL $dst.lo,$dst.hi,$src1,$src2" %} ins_encode %{ __ smull($dst$$Register, $dst$$Register->successor(), $src1$$Register, $src2$$Register); %} ins_pipe(ialu_reg_reg); %} // Integer Division // Register Division instruct divI_reg_reg_IDIV(iRegI dst, iRegI src1, iRegI src2) %{ match(Set dst (DivI src1 src2)); predicate(VM_Version::features() & FT_HW_DIVIDE); ins_cost(2*DEFAULT_COST); format %{ "SDIV $dst,$src1,$src2"%} ins_encode %{ __ sdiv($dst$$Register, $src1$$Register, $src2$$Register); %} ins_pipe(sdiv_reg_reg_IDIV); %} instruct divI_reg_reg_SW(R0RegI dst, R1RegI src1, R2RegI src2, R9RegI temp1, R12RegI temp2, LRRegP lr, flagsReg ccr) %{ match(Set dst (DivI src1 src2)); predicate(!(VM_Version::features() & FT_HW_DIVIDE)); effect( KILL ccr, TEMP temp1, TEMP temp2, USE_KILL src1,USE_KILL src2, KILL lr); ins_cost((2+71)*DEFAULT_COST); format %{ "DIV $dst,$src1,$src2 ! call to StubRoutines::aarch32::idiv_entry()" %} ins_encode %{ __ call(StubRoutines::aarch32::idiv_entry(), relocInfo::runtime_call_type); %} ins_pipe(sdiv_reg_reg_SW); %} // 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_IDIV(iRegI dst, iRegI src1, iRegI src2, iRegI temp) %{ match(Set dst (ModI src1 src2)); predicate(VM_Version::features() & FT_HW_DIVIDE); effect( TEMP temp); format %{ "SDIV $temp,$src1,$src2\n\t" "MLS $dst, $temp, $src2, $src1"%} ins_encode %{ __ sdiv($temp$$Register, $src1$$Register, $src2$$Register); __ mls($dst$$Register, $temp$$Register, $src2$$Register, $src1$$Register); %} ins_pipe(sdiv_reg_reg_IDIV); %} instruct modI_reg_reg_SW(R0RegI dst, R1RegI src1, R2RegI src2, R9RegI temp1, R12RegI temp2, LRRegP lr, flagsReg ccr ) %{ match(Set dst (ModI src1 src2)); predicate(!(VM_Version::features() & FT_HW_DIVIDE)); effect( KILL ccr, TEMP temp1, TEMP temp2, KILL lr, USE_KILL src1, USE_KILL src2); format %{ "MODI $dst,$src1,$src2\t ! call to StubRoutines::aarch32::irem_entry" %} ins_encode %{ __ call(StubRoutines::aarch32::irem_entry(), relocInfo::runtime_call_type); %} ins_pipe(sdiv_reg_reg_SW); %} // 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, $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 %{ __ lsl($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(), $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, $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(), $src1$$Register, lsl($dst$$Register->successor()), Assembler::PL); __ rsb($dst$$Register->successor(), $dst$$Register->successor(), 0, Assembler::MI); __ mov($dst$$Register->successor(), $src1$$Register, lsr($dst$$Register->successor()), Assembler::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(), $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(), $src1$$Register->successor(), lsl($src2$$constant)); __ orr($dst$$Register->successor(), $dst$$Register->successor(), $src1$$Register, lsr(32-$src2$$constant)); __ mov($dst$$Register, $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, $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, $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, $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(), $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, $src1$$Register->successor(), asr($dst$$Register), Assembler::PL); __ rsb($dst$$Register, $dst$$Register, 0, Assembler::MI); __ mov($dst$$Register, $src1$$Register->successor(), lsl($dst$$Register), Assembler::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, $src1$$Register->successor(), asr($src2$$constant-32)); } __ mov($dst$$Register->successor(), $src1$$Register->successor(), asr(32)); %} 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, $src1$$Register, lsr($src2$$constant)); __ orr($dst$$Register, $dst$$Register, $src1$$Register->successor(), lsl(32-$src2$$constant)); __ mov($dst$$Register->successor(), $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, $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, $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, $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(), $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, $src1$$Register->successor(), lsr($dst$$Register), Assembler::PL); __ rsb($dst$$Register, $dst$$Register, 0, Assembler::MI); __ mov($dst$$Register, $src1$$Register->successor(), lsl($dst$$Register), Assembler::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, $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, $src1$$Register, lsr($src2$$constant)); __ orr($dst$$Register, $dst$$Register, $src1$$Register->successor(), lsl(32-$src2$$constant)); __ mov($dst$$Register->successor(), $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 %{ __ lsr($dst$$Register, $src1$$Register, $src2$$constant); %} ins_pipe(ialu_reg_imm); %} // Overcomplicated unsigned math instruct umull_lreg32_lreg32(iRegL dst, iRegL src1, iRegL src2) %{ match(Set dst (MulL src1 src2)); predicate(n->in(1)->Opcode() == Op_AndL && (((unsigned long long)n->in(1)->in(2)->find_long_con(-1))>>32)==0 && n->in(2)->Opcode() == Op_AndL && (((unsigned long long)n->in(2)->in(2)->find_long_con(-1))>>32)==0); ins_cost(DEFAULT_COST*3/2); size(4); format %{ "UMULL $dst.lo,$dst.hi,$src1.lo,$src2.lo" %} ins_encode %{ __ umull($dst$$Register, $dst$$Register->successor(), $src1$$Register, $src2$$Register); %} ins_pipe(imul_reg_reg); %} instruct umlal_reg32_reg32(iRegL dst, iRegL src1, iRegL src2) %{ match(Set dst (AddL dst (MulL src1 src2))); predicate( n->in(2)->Opcode() == Op_MulL ? n->in(2)->in(1)->Opcode() == Op_AndL && (((unsigned long long)n->in(2)->in(1)->in(2)->find_long_con(-1))>>32)==0 && n->in(2)->in(2)->Opcode() == Op_AndL && (((unsigned long long)n->in(2)->in(2)->in(2)->find_long_con(-1))>>32)==0 : n->in(1)->in(1)->Opcode() == Op_AndL && (((unsigned long long)n->in(1)->in(1)->in(2)->find_long_con(-1))>>32)==0 && n->in(1)->in(2)->Opcode() == Op_AndL && (((unsigned long long)n->in(1)->in(2)->in(2)->find_long_con(-1))>>32)==0 ); ins_cost(DEFAULT_COST*3/2); size(4); format %{ "UMLAL $dst.lo,$dst.hi,$src1.lo,$src2.lo" %} ins_encode %{ __ umlal($dst$$Register, $dst$$Register->successor(), $src1$$Register, $src2$$Register); %} ins_pipe(ialu_reg_reg); %} //----------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 %{ __ vadd_f32($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 %{ __ vadd_f64($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 %{ __ vsub_f32($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 %{ __ vsub_f64($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 %{ __ vmul_f32($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 %{ __ vmul_f64($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 %{ __ vdiv_f32($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 %{ __ vdiv_f64($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 %{ __ vabs_f64($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 %{ __ vabs_f32($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 %{ __ vneg_f32($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 %{ __ vneg_f64($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 %{ __ vsqrt_f32($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 %{ __ vsqrt_f64($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 %{ __ andr($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, $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 %{ __ andr($dst$$Register, $src1$$Register, $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, $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 %{ __ andr($dst$$Register, $src1$$Register, $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, $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 %{ __ andr($dst$$Register, $src1$$Register, $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 %{ __ andr($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(), 0u); %} 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($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, $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($dst$$Register, $src1$$Register, $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, $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($dst$$Register, $src1$$Register, $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, $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($dst$$Register, $src1$$Register, $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($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(), 0u); %} 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($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, $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($dst$$Register, $src1$$Register, $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, $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($dst$$Register, $src1$$Register, $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, $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($dst$$Register, $src1$$Register, $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($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(), 0u); %} 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, Assembler::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, Assembler::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_i($dst$$Register, 0); __ mvn_i($dst$$Register, 0, Assembler::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_i($dst$$Register, 0); __ mvn_i($dst$$Register, 0, Assembler::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, Assembler::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, Assembler::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, Assembler::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 %{ __ vcvt_f32_f64($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 %{ __ vcvt_s32_f64($tmp$$FloatRegister, $src$$FloatRegister); __ vmov_f32($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 HARD_FLOAT_CC __ vmov_f64($dst$$Register, $dst$$Register->successor(), $src$$FloatRegister); #else if ($src$$FloatRegister != d0) { __ vmov_f64(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 %{ __ vcvt_f64_f32($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 %{ __ vcvt_s32_f32($tmp$$FloatRegister, $src$$FloatRegister); __ vmov_f32($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 HARD_FLOAT_CC __ vmov_f32($arg1$$Register, $src$$FloatRegister); #else if($src$$FloatRegister != f0) { __ vmov_f32(f0, $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 %{ __ vmov_f32($dst$$FloatRegister, $src$$Register); __ vcvt_f64_s32($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 %{ __ vmov_f32($dst$$FloatRegister, $src$$Register); __ vcvt_f32_s32($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(), $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 %{ __ vmov_f32($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 %{ __ vmov_f32($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 %{ __ vmov_f64($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 %{ __ vmov_f64($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($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($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 %{ __ vmov_f32($dst$$FloatRegister->successor(FloatRegisterImpl::SINGLE), $src1$$FloatRegister->successor(FloatRegisterImpl::SINGLE)); __ vmov_f32($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 %{ __ vcvt_f64_s32($dst$$FloatRegister, $src$$FloatRegister->successor(FloatRegisterImpl::SINGLE));// TODO verify the samentics is the same as was before %} 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 %{ __ vadd_f64($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 %{ __ vsub_f64($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 %{ __ vmul_f64($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 %{ __ vmov_f64($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 %{ __ vmov_f64($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, $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($op1$$Register, $op2$$Register); %} ins_pipe(ialu_cconly_reg_reg); %} 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($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($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($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 $op2,$op1" %} ins_encode %{ __ tst($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, $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 $op2,$op1<<$op3" %} ins_encode %{ __ tst($op1$$Register, $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, $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 $op2,$op1<<$op3" %} ins_encode %{ __ tst($op1$$Register, $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, $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 $op2,$op1<<$op3" %} ins_encode %{ __ tst($op1$$Register, $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 $op2,$op1" %} ins_encode %{ __ tst($op1$$Register, $op2$$constant); %} ins_pipe(ialu_cconly_reg_imm_zero); %} instruct compL_reg_reg_LTGE(flagsRegL_LTGE xcc, iRegL op1, iRegL op2, iRegI tmp) %{ match(Set xcc (CmpL op1 op2)); effect( DEF xcc, USE op1, USE op2, TEMP tmp ); size(8); format %{ "CMP $op1.low,$op2.low\t\t! long\n\t" "SBCS $tmp,$op1.hi,$op2.hi" %} ins_encode %{ __ cmp($op1$$Register, $op2$$Register); __ sbcs($tmp$$Register, $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, Assembler::EQ); %} ins_pipe(ialu_cconly_reg_reg); %} instruct compL_reg_reg_LEGT(flagsRegL_LEGT xcc, iRegL op1, iRegL op2, iRegI tmp) %{ match(Set xcc (CmpL op1 op2)); effect( DEF xcc, USE op1, USE op2, TEMP tmp ); size(8); format %{ "CMP $op2.low,$op1.low\t\t! long\n\t" "SBCS $tmp,$op2.hi,$op1.hi" %} ins_encode %{ __ cmp($op2$$Register, $op1$$Register); __ sbcs($tmp$$Register, $op2$$Register->successor(), $op1$$Register->successor()); %} ins_pipe(ialu_cconly_reg_reg); %} instruct compUL_reg_reg(flagsRegUL xcc, iRegL op1, iRegL op2) %{ match(Set xcc (CmpUL op1 op2)); effect( DEF xcc, USE op1, USE op2 ); size(8); format %{ "CMP $op1.hi,$op2.hi\t\t! long\n\t" "CMP.eq $op1.low,$op2.low" %} ins_encode %{ __ cmp($op1$$Register->successor(), $op2$$Register->successor()); __ cmp($op1$$Register, $op2$$Register, Assembler::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_LTGE(flagsRegL_LTGE xcc, iRegL op1, immLlowRot con, iRegI tmp) %{ match(Set xcc (CmpL op1 con)); effect( DEF xcc, USE op1, USE con, TEMP tmp ); size(8); format %{ "CMP $op1.low,$con\t\t! long\n\t" "SBCS $tmp,$op1.hi,0" %} ins_encode %{ __ cmp($op1$$Register, (int)$con$$constant); __ sbcs($tmp$$Register, $op1$$Register->successor(), 0); %} ins_pipe(ialu_cconly_reg_reg); %} instruct compUL_reg_con(flagsRegUL xcc, iRegL op1, immLlowRot con ) %{ match(Set xcc (CmpUL op1 con)); effect( DEF xcc, USE op1, USE con ); size(8); format %{ "CMP $op1.hi,0\t\t! long\n\t" "CMP.eq $op1.low,$con" %} ins_encode %{ __ cmp($op1$$Register->successor(), 0); __ cmp($op1$$Register, (int)$con$$constant, Assembler::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_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, (int)$con$$constant, Assembler::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, (long)$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($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, Assembler::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, Assembler::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 %{ __ vcmp_f32($src1$$FloatRegister, $src2$$FloatRegister); __ get_fpsr(); %} 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 %{ __ vcmp_f32($src1$$FloatRegister, 0); __ get_fpsr(); %} 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 %{ __ vcmp_f64($src1$$FloatRegister, $src2$$FloatRegister); __ get_fpsr(); %} 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 %{ __ vcmp_f64($src1$$FloatRegister, 0); __ get_fpsr(); %} 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 %{ __ vcmp_f32($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 %{ __ vcmp_f32($src1$$FloatRegister, 0); __ 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 %{ __ vcmp_f64($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 %{ __ vcmp_f64($src1$$FloatRegister, 0); __ 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(table_reg, $constantoffset); __ add(table_reg, $constanttablebase, table_reg); __ ldr(label_reg, Address(table_reg, $switch_val$$Register)); } } __ b(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), (Assembler::Condition)($cmp$$cmpcode)); %} ins_pipe(br_cc); %} 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), (Assembler::Condition)($cmp$$cmpcode)); %} ins_pipe(br_cc); %} 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), (Assembler::Condition)($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), (Assembler::Condition)($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), (Assembler::Condition)($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), (Assembler::Condition)($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), (Assembler::Condition)($cmp$$cmpcode)); %} ins_pipe(br_cc); %} instruct branchConUL(cmpOpU cmp, flagsRegUL xcc, label labl) %{ match(If cmp xcc); effect(USE labl); size(4); ins_cost(BRANCH_COST); format %{ "B$cmp $xcc,$labl" %} ins_encode %{ __ b(*($labl$$label), (Assembler::Condition)($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), (Assembler::Condition)($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_i($dst$$Register, 1, Assembler::GT); __ mvn_i($dst$$Register, 0, Assembler::LT); __ b(done, Assembler::NE); __ subs($dst$$Register, $src1$$Register, $src2$$Register); __ mov_i($dst$$Register, 1, Assembler::HI); __ mvn_i($dst$$Register, 0, Assembler::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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), $src$$Register->successor(), (Assembler::Condition)($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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), $src$$Register->successor(), (Assembler::Condition)($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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), $src$$Register->successor(), (Assembler::Condition)($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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), 0, (Assembler::Condition)($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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), 0, (Assembler::Condition)($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, (Assembler::Condition)($cmp$$cmpcode)); __ mov($dst$$Register->successor(), 0, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($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_i($dst$$Register, $src$$constant, (Assembler::Condition)($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 %{ __ vmov_f32($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f32($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f32($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f64($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f64($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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 %{ __ vmov_f64($dst$$FloatRegister, $src$$FloatRegister, (Assembler::Condition)($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); size(call_static_enc_size(this, _method, _method_handle_invoke)); 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); size(call_static_enc_size(this, _method, _method_handle_invoke)); // 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); size(call_dynamic_enc_size()); 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); size(call_runtime_enc_size(this)); 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); size(call_runtime_enc_size(this)); 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); size(call_runtime_enc_size(this)); 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(iRegP jump_target, inline_cache_regP method_oop) %{ match(TailCall jump_target method_oop ); ins_cost(CALL_COST); format %{ "MOV Rexception_pc, LR\n\t" "jump $jump_target \t! $method_oop holds method oop" %} ins_encode %{ __ mov(r3, lr); // this is used only to call // StubRoutines::forward_exception_entry() // which expects PC of exception in // R3. FIXME? __ b($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(r3, lr); __ b($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; assert_different_registers(scratch, c_rarg0, lr); __ jump(OptoRuntime::rethrow_stub(), relocInfo::runtime_call_type, scratch); %} ins_pipe(tail_call); %} // Die now instruct ShouldNotReachHere( ) %{ match(Halt); ins_cost(CALL_COST); size(4); // Use the following format syntax format %{ "ShouldNotReachHere" %} ins_encode %{ __ udf(0xdead); %} ins_pipe(tail_call); %} // ============================================================================ // The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass // array for an instance of the superklass. Set a hidden internal cache on a // hit (cache is checked with exposed code in gen_subtype_check()). Return // not zero for a miss or zero for a hit. The encoding ALSO sets flags. instruct partialSubtypeCheck( R0RegP index, R1RegP sub, R2RegP super, flagsRegP pcc, LRRegP lr, R9RegI r9, R12RegI r12 ) %{ match(Set index (PartialSubtypeCheck sub super)); effect( KILL pcc, KILL r9, KILL r12, KILL lr ); ins_cost(DEFAULT_COST*10); format %{ "CALL PartialSubtypeCheck" %} ins_encode %{ __ call(StubRoutines::aarch32::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 mark, iRegP scratch2, iRegP scratch ) %{ match(Set pcc (FastLock object box)); effect(TEMP mark, TEMP scratch, TEMP scratch2); ins_cost(100); format %{ "FASTLOCK $object, $box; KILL $mark, $scratch, $scratch2" %} ins_encode %{ __ fast_lock($object$$Register, $box$$Register, $mark$$Register, $scratch$$Register, $scratch2$$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), Assembler::GE); __ b(loop, Assembler::GT); %} ins_pipe(long_memory_op); %} instruct string_compareUU(R0RegP str1, R1RegP str2, R2RegI cnt1, R3RegI cnt2, iRegI result, iRegI tmp1, iRegI tmp2, Q0_regD tmp3, Q1_regD tmp4, flagsReg ccr) %{ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP result, KILL ccr); ins_cost(300); format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1, $tmp2, $tmp3, $tmp4" %} ins_encode( enc_String_Compare(str1, str2, cnt1, cnt2, result, tmp1, tmp2, tmp3, tmp4, (2), (2)) ); ins_pipe(long_memory_op); %} instruct string_compareLL(R0RegP str1, R1RegP str2, R2RegI cnt1, R3RegI cnt2, iRegI result, iRegI tmp1, iRegI tmp2, Q0_regD tmp3, Q1_regD tmp4, flagsReg ccr) %{ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP result, KILL ccr); ins_cost(300); format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1, $tmp2, $tmp3, $tmp4" %} ins_encode( enc_String_Compare(str1, str2, cnt1, cnt2, result, tmp1, tmp2, tmp3, tmp4, (1), (1)) ); ins_pipe(long_memory_op); %} instruct string_compareUL(R0RegP str1, R1RegP str2, R2RegI cnt1, R3RegI cnt2, iRegI result, iRegI tmp1, iRegI tmp2, Q0_regD tmp3, Q1_regD tmp4, flagsReg ccr) %{ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP result, KILL ccr); ins_cost(300); format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1, $tmp2, $tmp3, $tmp4" %} ins_encode( enc_String_Compare(str1, str2, cnt1, cnt2, result, tmp1, tmp2, tmp3, tmp4, (2), (1)) ); ins_pipe(long_memory_op); %} instruct string_compareLU(R0RegP str1, R1RegP str2, R2RegI cnt1, R3RegI cnt2, iRegI result, iRegI tmp1, iRegI tmp2, Q0_regD tmp3, Q1_regD tmp4, flagsReg ccr) %{ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP result, KILL ccr); ins_cost(300); format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1, $tmp2, $tmp3, $tmp4" %} ins_encode( enc_String_Compare(str1, str2, cnt1, cnt2, result, tmp1, tmp2, tmp3, tmp4, (1), (2)) ); ins_pipe(long_memory_op); %} instruct string_equalsUU(R0RegP str1, R1RegP str2, R2RegI cnt, iRegI result, iRegI tmp1, flagsReg ccr) %{ predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); match(Set result (StrEquals (Binary str1 str2) cnt)); effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp1, TEMP result, KILL ccr); ins_cost(300); format %{ "String Equals $str1,$str2,$cnt -> $result # KILL $tmp1" %} ins_encode( enc_Array_Equals(str1, str2, cnt, tmp1, result, (2), (false)) ); ins_pipe(long_memory_op); %} instruct string_equalsLL(R0RegP str1, R1RegP str2, R2RegI cnt, iRegI result, iRegI tmp1, flagsReg ccr) %{ predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL); match(Set result (StrEquals (Binary str1 str2) cnt)); effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp1, TEMP result, KILL ccr); ins_cost(300); format %{ "String Equals $str1,$str2,$cnt -> $result # KILL $tmp1" %} ins_encode( enc_Array_Equals(str1, str2, cnt, tmp1, result, (1), (false)) ); ins_pipe(long_memory_op); %} instruct array_equalsUU(R0RegP ary1, R1RegP ary2, iRegI tmp1, iRegI tmp2, 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 result, KILL ccr); ins_cost(300); format %{ "Array Equals $ary1,$ary2 -> $result # KILL $tmp1,$tmp2" %} ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result, (2), (true))); ins_pipe(long_memory_op); %} instruct array_equalsLL(R0RegP ary1, R1RegP ary2, iRegI tmp1, iRegI tmp2, iRegI result, flagsReg ccr) %{ predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); match(Set result (AryEq ary1 ary2)); effect(USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP result, KILL ccr); ins_cost(300); format %{ "Array Equals $ary1,$ary2 -> $result # KILL $tmp1,$tmp2" %} ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result, (1), (true))); ins_pipe(long_memory_op); %} instruct string_compress(R2RegP src, R1RegP dst, R3RegI len, R9RegI tmp1, Q0_regD tmp2, Q1_regD tmp3, R12RegI tmp4, LRRegP lr, R0RegI result, flagsReg ccr) %{ match(Set result (StrCompressedCopy src (Binary dst len))); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP lr, USE_KILL src, USE_KILL dst, USE_KILL len, KILL ccr); format %{ "String Compress $src,$dst -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4, $lr" %} ins_encode( enc_Char_Array_Compress(src, dst, len, tmp1, tmp2, tmp3, tmp4, result, ccr) ); ins_pipe(long_memory_op); %} instruct string_inflate(Universe dummy, R0RegP src, R1RegP dst, R2RegI len, iRegI tmp1, Q0_regD tmp2, LRRegP lr, flagsReg ccr) %{ match(Set dummy (StrInflatedCopy src (Binary dst len))); effect(TEMP tmp1, TEMP tmp2, TEMP lr, USE_KILL src, USE_KILL dst, USE_KILL len, KILL ccr); format %{ "String Inflate $src,$dst // KILL $tmp1, $tmp2, $lr" %} ins_encode( enc_Byte_Array_Inflate(src, dst, len, tmp1, tmp2, ccr) ); ins_pipe(long_memory_op); %} //---------- Zeros Count Instructions ------------------------------------------ instruct countLeadingZerosI(iRegI dst, iRegI src) %{ match(Set dst (CountLeadingZerosI src)); size(4); format %{ "CLZ_32 $dst,$src" %} ins_encode %{ __ clz($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, Assembler::EQ); __ add($dst$$Register, $dst$$Register, $tmp$$Register, Assembler::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($tmp$$Register, $src$$Register); __ clz($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, Assembler::EQ); __ add($dst$$Register, $dst$$Register, $tmp$$Register, Assembler::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 %{ __ vmov_f32($tmp$$FloatRegister, $src$$Register); __ vcnt_64($tmp$$FloatRegister, $tmp$$FloatRegister); __ vpaddl_64_u8($tmp$$FloatRegister, $tmp$$FloatRegister); __ vpaddl_64_u16($tmp$$FloatRegister, $tmp$$FloatRegister); __ vmov_f32($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 %{ __ vmov_f64($tmp$$FloatRegister, $src$$Register, $src$$Register->successor()); __ vcnt_64($tmp$$FloatRegister, $tmp$$FloatRegister); __ vpaddl_64_u8($tmp$$FloatRegister, $tmp$$FloatRegister); __ vpaddl_64_u16($tmp$$FloatRegister, $tmp$$FloatRegister); __ vpaddl_64_u32($tmp$$FloatRegister, $tmp$$FloatRegister); __ vmov_f32($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 %{ __ vldr_f64($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_16($dst$$FloatRegister, $dst$$FloatRegister->successor(FloatRegisterImpl::DOUBLE), $mem$$Address, Assembler::ALIGN_STD); %} 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 %{ __ vstr_f64($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_16($src$$FloatRegister, $src$$FloatRegister->successor(FloatRegisterImpl::DOUBLE), $mem$$Address, Assembler::ALIGN_STD); %} 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, $src$$Register, lsl(24)); __ orr($tmp$$Register, $tmp$$Register, $tmp$$Register, lsr(8)); __ orr($tmp$$Register, $tmp$$Register, $tmp$$Register, lsr(16)); __ vmov_f64($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::features() & FT_AdvSIMD)); match(Set dst (ReplicateB src)); size(4); format %{ "VDUP.8 $dst,$src\t" %} ins_encode %{ __ vdup_64_8($dst$$FloatRegister, $src$$Register); %} 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 %{ __ vdup_128_8($dst$$FloatRegister, $src$$Register); %} 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::features() & FT_AdvSIMD)); match(Set dst (ReplicateB src)); size(4); format %{ "VMOV.U8 $dst,$src" %} ins_encode %{ __ vmov_64_8($dst$$FloatRegister, $src$$constant); %} 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::features() & FT_AdvSIMD)); match(Set dst (ReplicateB src)); size(4); format %{ "VMOV.U8 $dst.Q,$src" %} ins_encode %{ __ vmov_128_8($dst$$FloatRegister, $src$$constant); %} 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, $src$$Register, lsl(16)); __ orr($tmp$$Register, $tmp$$Register, $tmp$$Register, lsr(16)); __ vmov_f64($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::features() & FT_AdvSIMD)); match(Set dst (ReplicateS src)); size(4); format %{ "VDUP.16 $dst,$src\t" %} ins_encode %{ __ vdup_64_16($dst$$FloatRegister, $src$$Register); %} 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::features() & FT_AdvSIMD)); match(Set dst (ReplicateS src)); size(4); format %{ "VDUP.16 $dst.Q,$src\t" %} ins_encode %{ __ vdup_128_16($dst$$FloatRegister, $src$$Register); %} 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::features() & FT_AdvSIMD)); match(Set dst (ReplicateS src)); size(4); format %{ "VMOV.U16 $dst,$src" %} ins_encode %{ __ vmov_64_16($dst$$FloatRegister, $src$$constant); %} 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::features() & FT_AdvSIMD)); match(Set dst (ReplicateS src)); size(4); format %{ "VMOV.U16 $dst.Q,$src" %} ins_encode %{ __ vmov_128_16($dst$$FloatRegister, $src$$constant); %} 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 %{ __ vmov_f64($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 %{ __ vmov_f64($dst$$FloatRegister, $src$$Register, $src$$Register); __ vmov_f64($dst$$FloatRegister->successor(FloatRegisterImpl::DOUBLE), $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::features() & FT_AdvSIMD)); match(Set dst (ReplicateI src)); size(4); format %{ "VDUP.32 $dst.D,$src\t" %} ins_encode %{ __ vdup_64_32($dst$$FloatRegister, $src$$Register); %} 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::features() & FT_AdvSIMD)); match(Set dst (ReplicateI src)); size(4); format %{ "VDUP.32 $dst.Q,$src\t" %} ins_encode %{ __ vdup_128_32($dst$$FloatRegister, $src$$Register); %} 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::features() & FT_AdvSIMD)); match(Set dst (ReplicateI src)); size(4); format %{ "VMOV.I32 $dst.D,$src" %} ins_encode %{ __ vmov_64_32($dst$$FloatRegister, $src$$constant); %} 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::features() & FT_AdvSIMD)); match(Set dst (ReplicateI src)); size(4); format %{ "VMOV.I32 $dst.Q,$src" %} ins_encode %{ __ vmov_128_32($dst$$FloatRegister, $src$$constant); %} 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 %{ __ vmov_f64($dst$$FloatRegister, $src$$Register, $src$$Register->successor()); __ vmov_f64($dst$$FloatRegister->successor(FloatRegisterImpl::DOUBLE), $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 %{ __ vmov_f64($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::features() & FT_AdvSIMD)); match(Set dst (ReplicateF src)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VDUP.32 $dst.D,$src.D\t" %} ins_encode %{ __ vdups_64($dst$$FloatRegister, $src$$FloatRegister); %} 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 %{ __ vmov_f32($tmp$$Register, $src$$FloatRegister); __ vmov_f64($dst$$FloatRegister, $tmp$$Register, $tmp$$Register); __ vmov_f64($dst$$FloatRegister->successor(FloatRegisterImpl::DOUBLE), $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::features() & FT_AdvSIMD)); match(Set dst (ReplicateF src)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VDUP.32 $dst.Q,$src.D\t" %} ins_encode %{ __ vdups_128($dst$$FloatRegister, $src$$FloatRegister); %} 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; __ vmov_f64(dsta, src); FloatRegister dstb = dsta->successor(FloatRegisterImpl::DOUBLE); __ vmov_f64(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 %{ __ vadd_64_8($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vadd_128_8($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vadd_64_16($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vadd_128_16($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vadd_64_32($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vadd_128_32($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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; __ vadd_128_64($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} ins_pipe( ialu_reg_reg ); // FIXME %} // Floats vector add instruct vadd2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{ predicate(n->as_Vector()->length() == 2); 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 %{ __ vadd_f32($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); __ vadd_f32($dst$$FloatRegister->successor(FloatRegisterImpl::SINGLE), $src1$$FloatRegister->successor(FloatRegisterImpl::SINGLE), $src2$$FloatRegister->successor(FloatRegisterImpl::SINGLE)); %} ins_pipe(faddF_reg_reg); // FIXME %} instruct vadd4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{ predicate(n->as_Vector()->length() == 4); 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; __ vadd_f32(dsta, src1a, src2a); FloatRegister dstb = dsta->successor(FloatRegisterImpl::SINGLE); FloatRegister src1b = src1a->successor(FloatRegisterImpl::SINGLE); FloatRegister src2b = src2a->successor(FloatRegisterImpl::SINGLE); __ vadd_f32(dstb, src1b, src2b); FloatRegister dstc = dstb->successor(FloatRegisterImpl::SINGLE); FloatRegister src1c = src1b->successor(FloatRegisterImpl::SINGLE); FloatRegister src2c = src2b->successor(FloatRegisterImpl::SINGLE); __ vadd_f32(dstc, src1c, src2c); FloatRegister dstd = dstc->successor(FloatRegisterImpl::SINGLE); FloatRegister src1d = src1c->successor(FloatRegisterImpl::SINGLE); FloatRegister src2d = src2c->successor(FloatRegisterImpl::SINGLE); __ vadd_f32(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; __ vadd_f64(dsta, src1a, src2a); FloatRegister dstb = dsta->successor(FloatRegisterImpl::DOUBLE); FloatRegister src1b = src1a->successor(FloatRegisterImpl::DOUBLE); FloatRegister src2b = src2a->successor(FloatRegisterImpl::DOUBLE); __ vadd_f64(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 %{ __ vsub_64_8($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vsub_128_8($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vsub_64_16($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vsub_128_16($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vsub_64_32($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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; __ vsub_128_32($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vsub_128_64($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} ins_pipe( ialu_reg_reg ); // FIXME %} // Floats vector sub instruct vsub2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{ predicate(n->as_Vector()->length() == 2); 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; __ vsub_f32(dsta, src1a, src2a); FloatRegister dstb = dsta->successor(FloatRegisterImpl::SINGLE); FloatRegister src1b = src1a->successor(FloatRegisterImpl::SINGLE); FloatRegister src2b = src2a->successor(FloatRegisterImpl::SINGLE); __ vsub_f32(dstb, src1b, src2b); %} ins_pipe(faddF_reg_reg); // FIXME %} instruct vsub4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{ predicate(n->as_Vector()->length() == 4); 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; __ vsub_f32(dsta, src1a, src2a); FloatRegister dstb = dsta->successor(FloatRegisterImpl::SINGLE); FloatRegister src1b = src1a->successor(FloatRegisterImpl::SINGLE); FloatRegister src2b = src2a->successor(FloatRegisterImpl::SINGLE); __ vsub_f32(dstb, src1b, src2b); FloatRegister dstc = dstb->successor(FloatRegisterImpl::SINGLE); FloatRegister src1c = src1b->successor(FloatRegisterImpl::SINGLE); FloatRegister src2c = src2b->successor(FloatRegisterImpl::SINGLE); __ vsub_f32(dstc, src1c, src2c); FloatRegister dstd = dstc->successor(FloatRegisterImpl::SINGLE); FloatRegister src1d = src1c->successor(FloatRegisterImpl::SINGLE); FloatRegister src2d = src2c->successor(FloatRegisterImpl::SINGLE); __ vsub_f32(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; __ vsub_f64(dsta, src1a, src2a); FloatRegister dstb = dsta->successor(FloatRegisterImpl::DOUBLE); FloatRegister src1b = src1a->successor(FloatRegisterImpl::DOUBLE); FloatRegister src2b = src2a->successor(FloatRegisterImpl::DOUBLE); __ vsub_f64(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 %{ __ vmul_64_16($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vmul_128_16($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vmul_64_32($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vmul_128_32($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} ins_pipe( ialu_reg_reg ); // FIXME %} // Floats vector mul instruct vmul2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{ predicate(n->as_Vector()->length() == 2); 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 %{ __ vmul_f32($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); __ vmul_f32($dst$$FloatRegister->successor(FloatRegisterImpl::SINGLE), $src1$$FloatRegister->successor(FloatRegisterImpl::SINGLE), $src2$$FloatRegister->successor(FloatRegisterImpl::SINGLE)); %} ins_pipe(fmulF_reg_reg); // FIXME %} instruct vmul4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{ predicate(n->as_Vector()->length() == 4); 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; __ vmul_f32(dsta, src1a, src2a); FloatRegister dstb = dsta->successor(FloatRegisterImpl::SINGLE); FloatRegister src1b = src1a->successor(FloatRegisterImpl::SINGLE); FloatRegister src2b = src2a->successor(FloatRegisterImpl::SINGLE); __ vmul_f32(dstb, src1b, src2b); FloatRegister dstc = dstb->successor(FloatRegisterImpl::SINGLE); FloatRegister src1c = src1b->successor(FloatRegisterImpl::SINGLE); FloatRegister src2c = src2b->successor(FloatRegisterImpl::SINGLE); __ vmul_f32(dstc, src1c, src2c); FloatRegister dstd = dstc->successor(FloatRegisterImpl::SINGLE); FloatRegister src1d = src1c->successor(FloatRegisterImpl::SINGLE); FloatRegister src2d = src2c->successor(FloatRegisterImpl::SINGLE); __ vmul_f32(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; __ vmul_f64(dsta, src1a, src2a); FloatRegister dstb = dsta->successor(FloatRegisterImpl::DOUBLE); FloatRegister src1b = src1a->successor(FloatRegisterImpl::DOUBLE); FloatRegister src2b = src2a->successor(FloatRegisterImpl::DOUBLE); __ vmul_f64(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 %{ __ vdiv_f32($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); __ vdiv_f32($dst$$FloatRegister->successor(FloatRegisterImpl::SINGLE), $src1$$FloatRegister->successor(FloatRegisterImpl::SINGLE), $src2$$FloatRegister->successor(FloatRegisterImpl::SINGLE)); %} 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; __ vdiv_f32(dsta, src1a, src2a); FloatRegister dstb = dsta->successor(FloatRegisterImpl::SINGLE); FloatRegister src1b = src1a->successor(FloatRegisterImpl::SINGLE); FloatRegister src2b = src2a->successor(FloatRegisterImpl::SINGLE); __ vdiv_f32(dstb, src1b, src2b); FloatRegister dstc = dstb->successor(FloatRegisterImpl::SINGLE); FloatRegister src1c = src1b->successor(FloatRegisterImpl::SINGLE); FloatRegister src2c = src2b->successor(FloatRegisterImpl::SINGLE); __ vdiv_f32(dstc, src1c, src2c); FloatRegister dstd = dstc->successor(FloatRegisterImpl::SINGLE); FloatRegister src1d = src1c->successor(FloatRegisterImpl::SINGLE); FloatRegister src2d = src2c->successor(FloatRegisterImpl::SINGLE); __ vdiv_f32(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; __ vdiv_f64(dsta, src1a, src2a); FloatRegister dstb = dsta->successor(FloatRegisterImpl::DOUBLE); FloatRegister src1b = src1a->successor(FloatRegisterImpl::DOUBLE); FloatRegister src2b = src2a->successor(FloatRegisterImpl::DOUBLE); __ vdiv_f64(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 %{ __ vneg_64_s8($dst$$FloatRegister, $src$$FloatRegister); %} 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 %{ __ vneg_128_s8($dst$$FloatRegister, $src$$FloatRegister); %} ins_pipe( ialu_reg_reg ); // FIXME %} // ------------------------------ Shift --------------------------------------- instruct vslcntD(vecD dst, iRegI cnt) %{ predicate(n->as_Vector()->length_in_bytes() == 8 && (VM_Version::features() & FT_AdvSIMD)); 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::features() & FT_AdvSIMD)); 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::features() & FT_AdvSIMD)); 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 %{ __ vdup_64_8($dst$$FloatRegister, $cnt$$Register); __ vneg_64_s8($dst$$FloatRegister, $dst$$FloatRegister); %} ins_pipe( ialu_reg_reg ); // FIXME %} instruct vsrcntX(vecX dst, iRegI cnt) %{ predicate(n->as_Vector()->length_in_bytes() == 16 && (VM_Version::features() & FT_AdvSIMD)); 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 %{ __ vdup_128_8($dst$$FloatRegister, $cnt$$Register); __ vneg_128_s8($dst$$FloatRegister, $dst$$FloatRegister); %} 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 %{ __ vshl_64_u8($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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; __ vshl_128_u8($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshl_64_u16($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshl_128_u16($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshl_64_u32($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshl_128_u32($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshl_128_u64($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} ins_pipe( ialu_reg_reg ); // FIXME %} // ------------------------------ LeftShift ----------------------------------- // Byte vector left shift instruct vsl8B_reg(vecD dst, vecD src, vecD shift) %{ predicate(n->as_Vector()->length() == 8); match(Set dst (LShiftVB src shift)); size(4*1); ins_cost(DEFAULT_COST*1); // FIXME expand %{ vsh8B_reg(dst, src, shift); %} %} instruct vsl16B_reg(vecX dst, vecX src, vecX shift) %{ predicate(n->as_Vector()->length() == 16); match(Set dst (LShiftVB src shift)); size(4*1); ins_cost(DEFAULT_COST*1); // FIXME expand %{ vsh16B_reg(dst, src, shift); %} %} instruct vsl8B_immI(vecD dst, vecD src, immI shift) %{ predicate(n->as_Vector()->length() == 8); match(Set dst (LShiftVB src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VSHL.I8 $dst.D,$src.D,$shift\t! logical left shift packed8B" %} ins_encode %{ __ vshl_64_8($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} ins_pipe( ialu_reg_reg ); // FIXME %} instruct vsl16B_immI(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 16); match(Set dst (LShiftVB src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VSHL.I8 $dst.Q,$src.Q,$shift\t! logical left shift packed16B" %} ins_encode %{ bool quad = true; __ vshl_128_8($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} ins_pipe( ialu_reg_reg ); // FIXME %} // Shorts/Chars vector logical left/right shift instruct vsl4S_reg(vecD dst, vecD src, vecD shift) %{ predicate(n->as_Vector()->length() == 4); match(Set dst (LShiftVS src shift)); match(Set dst (URShiftVS src shift)); size(4*1); ins_cost(DEFAULT_COST*1); // FIXME expand %{ vsh4S_reg(dst, src, shift); %} %} instruct vsl8S_reg(vecX dst, vecX src, vecX shift) %{ predicate(n->as_Vector()->length() == 8); match(Set dst (LShiftVS src shift)); match(Set dst (URShiftVS src shift)); size(4*1); ins_cost(DEFAULT_COST*1); // FIXME expand %{ vsh8S_reg(dst, src, shift); %} %} instruct vsl4S_immI(vecD dst, vecD src, immI shift) %{ predicate(n->as_Vector()->length() == 4); match(Set dst (LShiftVS src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VSHL.I16 $dst.D,$src.D,$shift\t! logical left shift packed4S" %} ins_encode %{ bool quad = false; __ vshl_64_16($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} 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; __ vshl_128_16($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} 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::features() & FT_AdvSIMD)); 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::features() & FT_AdvSIMD)); 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::features() & FT_AdvSIMD)); match(Set dst (LShiftVI src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VSHL.I32 $dst.D,$src.D,$shift\t! logical left shift packed2I" %} ins_encode %{ __ vshl_64_32($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} ins_pipe( ialu_reg_reg ); // FIXME %} instruct vsl4I_immI(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 4 && (VM_Version::features() & FT_AdvSIMD)); match(Set dst (LShiftVI src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VSHL.I32 $dst.Q,$src.Q,$shift\t! logical left shift packed4I" %} ins_encode %{ __ vshl_128_32($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} ins_pipe( ialu_reg_reg ); // FIXME %} // Longs vector logical left/right shift instruct vsl2L_reg(vecX dst, vecX src, vecX shift) %{ predicate(n->as_Vector()->length() == 2); match(Set dst (LShiftVL src shift)); match(Set dst (URShiftVL src shift)); size(4*1); ins_cost(DEFAULT_COST*1); // FIXME expand %{ vsh2L_reg(dst, src, shift); %} %} instruct vsl2L_immI(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 2); match(Set dst (LShiftVL src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VSHL.I64 $dst.Q,$src.Q,$shift\t! logical left shift packed2L" %} ins_encode %{ __ vshl_128_64($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} ins_pipe( ialu_reg_reg ); // FIXME %} // ----------------------- LogicalRightShift ----------------------------------- // Bytes/Shorts vector logical right shift produces incorrect Java result // for negative data because java code convert short value into int with // sign extension before a shift. // Chars vector logical right shift instruct vsrl4S_immI(vecD dst, vecD src, immI shift) %{ predicate(n->as_Vector()->length() == 4); match(Set dst (URShiftVS src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VSHR.U16 $dst.D,$src.D,$shift\t! logical right shift packed4S" %} ins_encode %{ __ vshr_64_u16($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} ins_pipe( ialu_reg_reg ); // FIXME %} instruct vsrl8S_immI(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 8); match(Set dst (URShiftVS src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VSHR.U16 $dst.Q,$src.Q,$shift\t! logical right shift packed8S" %} ins_encode %{ __ vshr_128_u16($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} 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::features() & FT_AdvSIMD)); match(Set dst (URShiftVI src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VSHR.U32 $dst.D,$src.D,$shift\t! logical right shift packed2I" %} ins_encode %{ __ vshr_64_u32($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} ins_pipe( ialu_reg_reg ); // FIXME %} instruct vsrl4I_immI(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 4 && (VM_Version::features() & FT_AdvSIMD)); match(Set dst (URShiftVI src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VSHR.U32 $dst.Q,$src.Q,$shift\t! logical right shift packed4I" %} ins_encode %{ __ vshr_128_u32($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} ins_pipe( ialu_reg_reg ); // FIXME %} // Longs vector logical right shift instruct vsrl2L_immI(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 2); match(Set dst (URShiftVL src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ "VSHR.U64 $dst.Q,$src.Q,$shift\t! logical right shift packed2L" %} ins_encode %{ __ vshr_128_u64($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} 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 %{ __ vshl_64_s8($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshl_128_s8($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshl_64_s16($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshl_128_s16($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshl_64_s32($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshl_128_s32($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshl_128_s64($dst$$FloatRegister, $src$$FloatRegister, $shift$$FloatRegister); %} 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 %{ __ vshr_64_s8($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} 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 %{ __ vshr_128_s8($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} 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 %{ __ vshr_64_s16($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} 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 %{ __ vshr_128_s16($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} 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 %{ __ vshr_64_s32($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} 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 %{ __ vshr_128_s32($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} 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 %{ __ vshr_128_s64($dst$$FloatRegister, $src$$FloatRegister, $shift$$constant); %} 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 %{ __ vand_64($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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; __ vand_128($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vorr_64($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ vorr_128($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ veor_64($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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 %{ __ veor_128($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister); %} 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.