// // Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2014, 2021, Red Hat, 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. // // // AArch64 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 ); // 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. // We must define the 64 bit int registers in two 32 bit halves, the // real lower register and a virtual upper half register. upper halves // are used by the register allocator but are not actually supplied as // operands to memory ops. // // follow the C1 compiler in making registers // // r0-r7,r10-r26 volatile (caller save) // r27-r32 system (no save, no allocate) // r8-r9 non-allocatable (so we can use them as scratch regs) // // as regards Java usage. we don't use any callee save registers // because this makes it difficult to de-optimise a frame (see comment // in x86 implementation of Deoptimization::unwind_callee_save_values) // // General Registers reg_def R0 ( SOC, SOC, Op_RegI, 0, r0->as_VMReg() ); reg_def R0_H ( SOC, SOC, Op_RegI, 0, r0->as_VMReg()->next() ); reg_def R1 ( SOC, SOC, Op_RegI, 1, r1->as_VMReg() ); reg_def R1_H ( SOC, SOC, Op_RegI, 1, r1->as_VMReg()->next() ); reg_def R2 ( SOC, SOC, Op_RegI, 2, r2->as_VMReg() ); reg_def R2_H ( SOC, SOC, Op_RegI, 2, r2->as_VMReg()->next() ); reg_def R3 ( SOC, SOC, Op_RegI, 3, r3->as_VMReg() ); reg_def R3_H ( SOC, SOC, Op_RegI, 3, r3->as_VMReg()->next() ); reg_def R4 ( SOC, SOC, Op_RegI, 4, r4->as_VMReg() ); reg_def R4_H ( SOC, SOC, Op_RegI, 4, r4->as_VMReg()->next() ); reg_def R5 ( SOC, SOC, Op_RegI, 5, r5->as_VMReg() ); reg_def R5_H ( SOC, SOC, Op_RegI, 5, r5->as_VMReg()->next() ); reg_def R6 ( SOC, SOC, Op_RegI, 6, r6->as_VMReg() ); reg_def R6_H ( SOC, SOC, Op_RegI, 6, r6->as_VMReg()->next() ); reg_def R7 ( SOC, SOC, Op_RegI, 7, r7->as_VMReg() ); reg_def R7_H ( SOC, SOC, Op_RegI, 7, r7->as_VMReg()->next() ); reg_def R8 ( NS, SOC, Op_RegI, 8, r8->as_VMReg() ); // rscratch1, non-allocatable reg_def R8_H ( NS, SOC, Op_RegI, 8, r8->as_VMReg()->next() ); reg_def R9 ( NS, SOC, Op_RegI, 9, r9->as_VMReg() ); // rscratch2, non-allocatable reg_def R9_H ( NS, SOC, Op_RegI, 9, r9->as_VMReg()->next() ); reg_def R10 ( SOC, SOC, Op_RegI, 10, r10->as_VMReg() ); reg_def R10_H ( SOC, SOC, Op_RegI, 10, r10->as_VMReg()->next()); reg_def R11 ( SOC, SOC, Op_RegI, 11, r11->as_VMReg() ); reg_def R11_H ( SOC, SOC, Op_RegI, 11, r11->as_VMReg()->next()); reg_def R12 ( SOC, SOC, Op_RegI, 12, r12->as_VMReg() ); reg_def R12_H ( SOC, SOC, Op_RegI, 12, r12->as_VMReg()->next()); reg_def R13 ( SOC, SOC, Op_RegI, 13, r13->as_VMReg() ); reg_def R13_H ( SOC, SOC, Op_RegI, 13, r13->as_VMReg()->next()); reg_def R14 ( SOC, SOC, Op_RegI, 14, r14->as_VMReg() ); reg_def R14_H ( SOC, SOC, Op_RegI, 14, r14->as_VMReg()->next()); reg_def R15 ( SOC, SOC, Op_RegI, 15, r15->as_VMReg() ); reg_def R15_H ( SOC, SOC, Op_RegI, 15, r15->as_VMReg()->next()); reg_def R16 ( SOC, SOC, Op_RegI, 16, r16->as_VMReg() ); reg_def R16_H ( SOC, SOC, Op_RegI, 16, r16->as_VMReg()->next()); reg_def R17 ( SOC, SOC, Op_RegI, 17, r17->as_VMReg() ); reg_def R17_H ( SOC, SOC, Op_RegI, 17, r17->as_VMReg()->next()); reg_def R18 ( SOC, SOC, Op_RegI, 18, r18_tls->as_VMReg() ); reg_def R18_H ( SOC, SOC, Op_RegI, 18, r18_tls->as_VMReg()->next()); reg_def R19 ( SOC, SOE, Op_RegI, 19, r19->as_VMReg() ); reg_def R19_H ( SOC, SOE, Op_RegI, 19, r19->as_VMReg()->next()); reg_def R20 ( SOC, SOE, Op_RegI, 20, r20->as_VMReg() ); // caller esp reg_def R20_H ( SOC, SOE, Op_RegI, 20, r20->as_VMReg()->next()); reg_def R21 ( SOC, SOE, Op_RegI, 21, r21->as_VMReg() ); reg_def R21_H ( SOC, SOE, Op_RegI, 21, r21->as_VMReg()->next()); reg_def R22 ( SOC, SOE, Op_RegI, 22, r22->as_VMReg() ); reg_def R22_H ( SOC, SOE, Op_RegI, 22, r22->as_VMReg()->next()); reg_def R23 ( SOC, SOE, Op_RegI, 23, r23->as_VMReg() ); reg_def R23_H ( SOC, SOE, Op_RegI, 23, r23->as_VMReg()->next()); reg_def R24 ( SOC, SOE, Op_RegI, 24, r24->as_VMReg() ); reg_def R24_H ( SOC, SOE, Op_RegI, 24, r24->as_VMReg()->next()); reg_def R25 ( SOC, SOE, Op_RegI, 25, r25->as_VMReg() ); reg_def R25_H ( SOC, SOE, Op_RegI, 25, r25->as_VMReg()->next()); reg_def R26 ( SOC, SOE, Op_RegI, 26, r26->as_VMReg() ); reg_def R26_H ( SOC, SOE, Op_RegI, 26, r26->as_VMReg()->next()); reg_def R27 ( SOC, SOE, Op_RegI, 27, r27->as_VMReg() ); // heapbase reg_def R27_H ( SOC, SOE, Op_RegI, 27, r27->as_VMReg()->next()); reg_def R28 ( NS, SOE, Op_RegI, 28, r28->as_VMReg() ); // thread reg_def R28_H ( NS, SOE, Op_RegI, 28, r28->as_VMReg()->next()); reg_def R29 ( NS, NS, Op_RegI, 29, r29->as_VMReg() ); // fp reg_def R29_H ( NS, NS, Op_RegI, 29, r29->as_VMReg()->next()); reg_def R30 ( NS, NS, Op_RegI, 30, r30->as_VMReg() ); // lr reg_def R30_H ( NS, NS, Op_RegI, 30, r30->as_VMReg()->next()); reg_def R31 ( NS, NS, Op_RegI, 31, r31_sp->as_VMReg() ); // sp reg_def R31_H ( NS, NS, Op_RegI, 31, r31_sp->as_VMReg()->next()); // ---------------------------- // Float/Double/Vector Registers // ---------------------------- // 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. // AArch64 has 32 floating-point registers. Each can store a vector of // single or double precision floating-point values up to 8 * 32 // floats, 4 * 64 bit floats or 2 * 128 bit floats. We currently only // use the first float or double element of the vector. // for Java use float registers v0-v15 are always save on call whereas // the platform ABI treats v8-v15 as callee save). float registers // v16-v31 are SOC as per the platform spec // For SVE vector registers, we simply extend vector register size to 8 // 'logical' slots. This is nominally 256 bits but it actually covers // all possible 'physical' SVE vector register lengths from 128 ~ 2048 // bits. The 'physical' SVE vector register length is detected during // startup, so the register allocator is able to identify the correct // number of bytes needed for an SVE spill/unspill. // Note that a vector register with 4 slots denotes a 128-bit NEON // register allowing it to be distinguished from the corresponding SVE // vector register when the SVE vector length is 128 bits. reg_def V0 ( SOC, SOC, Op_RegF, 0, v0->as_VMReg() ); reg_def V0_H ( SOC, SOC, Op_RegF, 0, v0->as_VMReg()->next() ); reg_def V0_J ( SOC, SOC, Op_RegF, 0, v0->as_VMReg()->next(2) ); reg_def V0_K ( SOC, SOC, Op_RegF, 0, v0->as_VMReg()->next(3) ); reg_def V0_L ( SOC, SOC, Op_RegF, 0, v0->as_VMReg()->next(4) ); reg_def V0_M ( SOC, SOC, Op_RegF, 0, v0->as_VMReg()->next(5) ); reg_def V0_N ( SOC, SOC, Op_RegF, 0, v0->as_VMReg()->next(6) ); reg_def V0_O ( SOC, SOC, Op_RegF, 0, v0->as_VMReg()->next(7) ); reg_def V1 ( SOC, SOC, Op_RegF, 1, v1->as_VMReg() ); reg_def V1_H ( SOC, SOC, Op_RegF, 1, v1->as_VMReg()->next() ); reg_def V1_J ( SOC, SOC, Op_RegF, 1, v1->as_VMReg()->next(2) ); reg_def V1_K ( SOC, SOC, Op_RegF, 1, v1->as_VMReg()->next(3) ); reg_def V1_L ( SOC, SOC, Op_RegF, 1, v1->as_VMReg()->next(4) ); reg_def V1_M ( SOC, SOC, Op_RegF, 1, v1->as_VMReg()->next(5) ); reg_def V1_N ( SOC, SOC, Op_RegF, 1, v1->as_VMReg()->next(6) ); reg_def V1_O ( SOC, SOC, Op_RegF, 1, v1->as_VMReg()->next(7) ); reg_def V2 ( SOC, SOC, Op_RegF, 2, v2->as_VMReg() ); reg_def V2_H ( SOC, SOC, Op_RegF, 2, v2->as_VMReg()->next() ); reg_def V2_J ( SOC, SOC, Op_RegF, 2, v2->as_VMReg()->next(2) ); reg_def V2_K ( SOC, SOC, Op_RegF, 2, v2->as_VMReg()->next(3) ); reg_def V2_L ( SOC, SOC, Op_RegF, 2, v2->as_VMReg()->next(4) ); reg_def V2_M ( SOC, SOC, Op_RegF, 2, v2->as_VMReg()->next(5) ); reg_def V2_N ( SOC, SOC, Op_RegF, 2, v2->as_VMReg()->next(6) ); reg_def V2_O ( SOC, SOC, Op_RegF, 2, v2->as_VMReg()->next(7) ); reg_def V3 ( SOC, SOC, Op_RegF, 3, v3->as_VMReg() ); reg_def V3_H ( SOC, SOC, Op_RegF, 3, v3->as_VMReg()->next() ); reg_def V3_J ( SOC, SOC, Op_RegF, 3, v3->as_VMReg()->next(2) ); reg_def V3_K ( SOC, SOC, Op_RegF, 3, v3->as_VMReg()->next(3) ); reg_def V3_L ( SOC, SOC, Op_RegF, 3, v3->as_VMReg()->next(4) ); reg_def V3_M ( SOC, SOC, Op_RegF, 3, v3->as_VMReg()->next(5) ); reg_def V3_N ( SOC, SOC, Op_RegF, 3, v3->as_VMReg()->next(6) ); reg_def V3_O ( SOC, SOC, Op_RegF, 3, v3->as_VMReg()->next(7) ); reg_def V4 ( SOC, SOC, Op_RegF, 4, v4->as_VMReg() ); reg_def V4_H ( SOC, SOC, Op_RegF, 4, v4->as_VMReg()->next() ); reg_def V4_J ( SOC, SOC, Op_RegF, 4, v4->as_VMReg()->next(2) ); reg_def V4_K ( SOC, SOC, Op_RegF, 4, v4->as_VMReg()->next(3) ); reg_def V4_L ( SOC, SOC, Op_RegF, 4, v4->as_VMReg()->next(4) ); reg_def V4_M ( SOC, SOC, Op_RegF, 4, v4->as_VMReg()->next(5) ); reg_def V4_N ( SOC, SOC, Op_RegF, 4, v4->as_VMReg()->next(6) ); reg_def V4_O ( SOC, SOC, Op_RegF, 4, v4->as_VMReg()->next(7) ); reg_def V5 ( SOC, SOC, Op_RegF, 5, v5->as_VMReg() ); reg_def V5_H ( SOC, SOC, Op_RegF, 5, v5->as_VMReg()->next() ); reg_def V5_J ( SOC, SOC, Op_RegF, 5, v5->as_VMReg()->next(2) ); reg_def V5_K ( SOC, SOC, Op_RegF, 5, v5->as_VMReg()->next(3) ); reg_def V5_L ( SOC, SOC, Op_RegF, 5, v5->as_VMReg()->next(4) ); reg_def V5_M ( SOC, SOC, Op_RegF, 5, v5->as_VMReg()->next(5) ); reg_def V5_N ( SOC, SOC, Op_RegF, 5, v5->as_VMReg()->next(6) ); reg_def V5_O ( SOC, SOC, Op_RegF, 5, v5->as_VMReg()->next(7) ); reg_def V6 ( SOC, SOC, Op_RegF, 6, v6->as_VMReg() ); reg_def V6_H ( SOC, SOC, Op_RegF, 6, v6->as_VMReg()->next() ); reg_def V6_J ( SOC, SOC, Op_RegF, 6, v6->as_VMReg()->next(2) ); reg_def V6_K ( SOC, SOC, Op_RegF, 6, v6->as_VMReg()->next(3) ); reg_def V6_L ( SOC, SOC, Op_RegF, 6, v6->as_VMReg()->next(4) ); reg_def V6_M ( SOC, SOC, Op_RegF, 6, v6->as_VMReg()->next(5) ); reg_def V6_N ( SOC, SOC, Op_RegF, 6, v6->as_VMReg()->next(6) ); reg_def V6_O ( SOC, SOC, Op_RegF, 6, v6->as_VMReg()->next(7) ); reg_def V7 ( SOC, SOC, Op_RegF, 7, v7->as_VMReg() ); reg_def V7_H ( SOC, SOC, Op_RegF, 7, v7->as_VMReg()->next() ); reg_def V7_J ( SOC, SOC, Op_RegF, 7, v7->as_VMReg()->next(2) ); reg_def V7_K ( SOC, SOC, Op_RegF, 7, v7->as_VMReg()->next(3) ); reg_def V7_L ( SOC, SOC, Op_RegF, 7, v7->as_VMReg()->next(4) ); reg_def V7_M ( SOC, SOC, Op_RegF, 7, v7->as_VMReg()->next(5) ); reg_def V7_N ( SOC, SOC, Op_RegF, 7, v7->as_VMReg()->next(6) ); reg_def V7_O ( SOC, SOC, Op_RegF, 7, v7->as_VMReg()->next(7) ); reg_def V8 ( SOC, SOE, Op_RegF, 8, v8->as_VMReg() ); reg_def V8_H ( SOC, SOE, Op_RegF, 8, v8->as_VMReg()->next() ); reg_def V8_J ( SOC, SOC, Op_RegF, 8, v8->as_VMReg()->next(2) ); reg_def V8_K ( SOC, SOC, Op_RegF, 8, v8->as_VMReg()->next(3) ); reg_def V8_L ( SOC, SOC, Op_RegF, 8, v8->as_VMReg()->next(4) ); reg_def V8_M ( SOC, SOC, Op_RegF, 8, v8->as_VMReg()->next(5) ); reg_def V8_N ( SOC, SOC, Op_RegF, 8, v8->as_VMReg()->next(6) ); reg_def V8_O ( SOC, SOC, Op_RegF, 8, v8->as_VMReg()->next(7) ); reg_def V9 ( SOC, SOE, Op_RegF, 9, v9->as_VMReg() ); reg_def V9_H ( SOC, SOE, Op_RegF, 9, v9->as_VMReg()->next() ); reg_def V9_J ( SOC, SOC, Op_RegF, 9, v9->as_VMReg()->next(2) ); reg_def V9_K ( SOC, SOC, Op_RegF, 9, v9->as_VMReg()->next(3) ); reg_def V9_L ( SOC, SOC, Op_RegF, 9, v9->as_VMReg()->next(4) ); reg_def V9_M ( SOC, SOC, Op_RegF, 9, v9->as_VMReg()->next(5) ); reg_def V9_N ( SOC, SOC, Op_RegF, 9, v9->as_VMReg()->next(6) ); reg_def V9_O ( SOC, SOC, Op_RegF, 9, v9->as_VMReg()->next(7) ); reg_def V10 ( SOC, SOE, Op_RegF, 10, v10->as_VMReg() ); reg_def V10_H ( SOC, SOE, Op_RegF, 10, v10->as_VMReg()->next() ); reg_def V10_J ( SOC, SOC, Op_RegF, 10, v10->as_VMReg()->next(2) ); reg_def V10_K ( SOC, SOC, Op_RegF, 10, v10->as_VMReg()->next(3) ); reg_def V10_L ( SOC, SOC, Op_RegF, 10, v10->as_VMReg()->next(4) ); reg_def V10_M ( SOC, SOC, Op_RegF, 10, v10->as_VMReg()->next(5) ); reg_def V10_N ( SOC, SOC, Op_RegF, 10, v10->as_VMReg()->next(6) ); reg_def V10_O ( SOC, SOC, Op_RegF, 10, v10->as_VMReg()->next(7) ); reg_def V11 ( SOC, SOE, Op_RegF, 11, v11->as_VMReg() ); reg_def V11_H ( SOC, SOE, Op_RegF, 11, v11->as_VMReg()->next() ); reg_def V11_J ( SOC, SOC, Op_RegF, 11, v11->as_VMReg()->next(2) ); reg_def V11_K ( SOC, SOC, Op_RegF, 11, v11->as_VMReg()->next(3) ); reg_def V11_L ( SOC, SOC, Op_RegF, 11, v11->as_VMReg()->next(4) ); reg_def V11_M ( SOC, SOC, Op_RegF, 11, v11->as_VMReg()->next(5) ); reg_def V11_N ( SOC, SOC, Op_RegF, 11, v11->as_VMReg()->next(6) ); reg_def V11_O ( SOC, SOC, Op_RegF, 11, v11->as_VMReg()->next(7) ); reg_def V12 ( SOC, SOE, Op_RegF, 12, v12->as_VMReg() ); reg_def V12_H ( SOC, SOE, Op_RegF, 12, v12->as_VMReg()->next() ); reg_def V12_J ( SOC, SOC, Op_RegF, 12, v12->as_VMReg()->next(2) ); reg_def V12_K ( SOC, SOC, Op_RegF, 12, v12->as_VMReg()->next(3) ); reg_def V12_L ( SOC, SOC, Op_RegF, 12, v12->as_VMReg()->next(4) ); reg_def V12_M ( SOC, SOC, Op_RegF, 12, v12->as_VMReg()->next(5) ); reg_def V12_N ( SOC, SOC, Op_RegF, 12, v12->as_VMReg()->next(6) ); reg_def V12_O ( SOC, SOC, Op_RegF, 12, v12->as_VMReg()->next(7) ); reg_def V13 ( SOC, SOE, Op_RegF, 13, v13->as_VMReg() ); reg_def V13_H ( SOC, SOE, Op_RegF, 13, v13->as_VMReg()->next() ); reg_def V13_J ( SOC, SOC, Op_RegF, 13, v13->as_VMReg()->next(2) ); reg_def V13_K ( SOC, SOC, Op_RegF, 13, v13->as_VMReg()->next(3) ); reg_def V13_L ( SOC, SOC, Op_RegF, 13, v13->as_VMReg()->next(4) ); reg_def V13_M ( SOC, SOC, Op_RegF, 13, v13->as_VMReg()->next(5) ); reg_def V13_N ( SOC, SOC, Op_RegF, 13, v13->as_VMReg()->next(6) ); reg_def V13_O ( SOC, SOC, Op_RegF, 13, v13->as_VMReg()->next(7) ); reg_def V14 ( SOC, SOE, Op_RegF, 14, v14->as_VMReg() ); reg_def V14_H ( SOC, SOE, Op_RegF, 14, v14->as_VMReg()->next() ); reg_def V14_J ( SOC, SOC, Op_RegF, 14, v14->as_VMReg()->next(2) ); reg_def V14_K ( SOC, SOC, Op_RegF, 14, v14->as_VMReg()->next(3) ); reg_def V14_L ( SOC, SOC, Op_RegF, 14, v14->as_VMReg()->next(4) ); reg_def V14_M ( SOC, SOC, Op_RegF, 14, v14->as_VMReg()->next(5) ); reg_def V14_N ( SOC, SOC, Op_RegF, 14, v14->as_VMReg()->next(6) ); reg_def V14_O ( SOC, SOC, Op_RegF, 14, v14->as_VMReg()->next(7) ); reg_def V15 ( SOC, SOE, Op_RegF, 15, v15->as_VMReg() ); reg_def V15_H ( SOC, SOE, Op_RegF, 15, v15->as_VMReg()->next() ); reg_def V15_J ( SOC, SOC, Op_RegF, 15, v15->as_VMReg()->next(2) ); reg_def V15_K ( SOC, SOC, Op_RegF, 15, v15->as_VMReg()->next(3) ); reg_def V15_L ( SOC, SOC, Op_RegF, 15, v15->as_VMReg()->next(4) ); reg_def V15_M ( SOC, SOC, Op_RegF, 15, v15->as_VMReg()->next(5) ); reg_def V15_N ( SOC, SOC, Op_RegF, 15, v15->as_VMReg()->next(6) ); reg_def V15_O ( SOC, SOC, Op_RegF, 15, v15->as_VMReg()->next(7) ); reg_def V16 ( SOC, SOC, Op_RegF, 16, v16->as_VMReg() ); reg_def V16_H ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next() ); reg_def V16_J ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next(2) ); reg_def V16_K ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next(3) ); reg_def V16_L ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next(4) ); reg_def V16_M ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next(5) ); reg_def V16_N ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next(6) ); reg_def V16_O ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next(7) ); reg_def V17 ( SOC, SOC, Op_RegF, 17, v17->as_VMReg() ); reg_def V17_H ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next() ); reg_def V17_J ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next(2) ); reg_def V17_K ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next(3) ); reg_def V17_L ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next(4) ); reg_def V17_M ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next(5) ); reg_def V17_N ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next(6) ); reg_def V17_O ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next(7) ); reg_def V18 ( SOC, SOC, Op_RegF, 18, v18->as_VMReg() ); reg_def V18_H ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next() ); reg_def V18_J ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next(2) ); reg_def V18_K ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next(3) ); reg_def V18_L ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next(4) ); reg_def V18_M ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next(5) ); reg_def V18_N ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next(6) ); reg_def V18_O ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next(7) ); reg_def V19 ( SOC, SOC, Op_RegF, 19, v19->as_VMReg() ); reg_def V19_H ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next() ); reg_def V19_J ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next(2) ); reg_def V19_K ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next(3) ); reg_def V19_L ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next(4) ); reg_def V19_M ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next(5) ); reg_def V19_N ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next(6) ); reg_def V19_O ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next(7) ); reg_def V20 ( SOC, SOC, Op_RegF, 20, v20->as_VMReg() ); reg_def V20_H ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next() ); reg_def V20_J ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next(2) ); reg_def V20_K ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next(3) ); reg_def V20_L ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next(4) ); reg_def V20_M ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next(5) ); reg_def V20_N ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next(6) ); reg_def V20_O ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next(7) ); reg_def V21 ( SOC, SOC, Op_RegF, 21, v21->as_VMReg() ); reg_def V21_H ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next() ); reg_def V21_J ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next(2) ); reg_def V21_K ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next(3) ); reg_def V21_L ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next(4) ); reg_def V21_M ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next(5) ); reg_def V21_N ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next(6) ); reg_def V21_O ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next(7) ); reg_def V22 ( SOC, SOC, Op_RegF, 22, v22->as_VMReg() ); reg_def V22_H ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next() ); reg_def V22_J ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next(2) ); reg_def V22_K ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next(3) ); reg_def V22_L ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next(4) ); reg_def V22_M ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next(5) ); reg_def V22_N ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next(6) ); reg_def V22_O ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next(7) ); reg_def V23 ( SOC, SOC, Op_RegF, 23, v23->as_VMReg() ); reg_def V23_H ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next() ); reg_def V23_J ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next(2) ); reg_def V23_K ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next(3) ); reg_def V23_L ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next(4) ); reg_def V23_M ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next(5) ); reg_def V23_N ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next(6) ); reg_def V23_O ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next(7) ); reg_def V24 ( SOC, SOC, Op_RegF, 24, v24->as_VMReg() ); reg_def V24_H ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next() ); reg_def V24_J ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next(2) ); reg_def V24_K ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next(3) ); reg_def V24_L ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next(4) ); reg_def V24_M ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next(5) ); reg_def V24_N ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next(6) ); reg_def V24_O ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next(7) ); reg_def V25 ( SOC, SOC, Op_RegF, 25, v25->as_VMReg() ); reg_def V25_H ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next() ); reg_def V25_J ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next(2) ); reg_def V25_K ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next(3) ); reg_def V25_L ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next(4) ); reg_def V25_M ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next(5) ); reg_def V25_N ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next(6) ); reg_def V25_O ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next(7) ); reg_def V26 ( SOC, SOC, Op_RegF, 26, v26->as_VMReg() ); reg_def V26_H ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next() ); reg_def V26_J ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next(2) ); reg_def V26_K ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next(3) ); reg_def V26_L ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next(4) ); reg_def V26_M ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next(5) ); reg_def V26_N ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next(6) ); reg_def V26_O ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next(7) ); reg_def V27 ( SOC, SOC, Op_RegF, 27, v27->as_VMReg() ); reg_def V27_H ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next() ); reg_def V27_J ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next(2) ); reg_def V27_K ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next(3) ); reg_def V27_L ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next(4) ); reg_def V27_M ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next(5) ); reg_def V27_N ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next(6) ); reg_def V27_O ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next(7) ); reg_def V28 ( SOC, SOC, Op_RegF, 28, v28->as_VMReg() ); reg_def V28_H ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next() ); reg_def V28_J ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next(2) ); reg_def V28_K ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next(3) ); reg_def V28_L ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next(4) ); reg_def V28_M ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next(5) ); reg_def V28_N ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next(6) ); reg_def V28_O ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next(7) ); reg_def V29 ( SOC, SOC, Op_RegF, 29, v29->as_VMReg() ); reg_def V29_H ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next() ); reg_def V29_J ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next(2) ); reg_def V29_K ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next(3) ); reg_def V29_L ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next(4) ); reg_def V29_M ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next(5) ); reg_def V29_N ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next(6) ); reg_def V29_O ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next(7) ); reg_def V30 ( SOC, SOC, Op_RegF, 30, v30->as_VMReg() ); reg_def V30_H ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next() ); reg_def V30_J ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next(2) ); reg_def V30_K ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next(3) ); reg_def V30_L ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next(4) ); reg_def V30_M ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next(5) ); reg_def V30_N ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next(6) ); reg_def V30_O ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next(7) ); reg_def V31 ( SOC, SOC, Op_RegF, 31, v31->as_VMReg() ); reg_def V31_H ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next() ); reg_def V31_J ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next(2) ); reg_def V31_K ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next(3) ); reg_def V31_L ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next(4) ); reg_def V31_M ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next(5) ); reg_def V31_N ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next(6) ); reg_def V31_O ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next(7) ); // ---------------------------- // SVE Predicate Registers // ---------------------------- reg_def P0 (SOC, SOC, Op_RegVectMask, 0, p0->as_VMReg()); reg_def P1 (SOC, SOC, Op_RegVectMask, 1, p1->as_VMReg()); reg_def P2 (SOC, SOC, Op_RegVectMask, 2, p2->as_VMReg()); reg_def P3 (SOC, SOC, Op_RegVectMask, 3, p3->as_VMReg()); reg_def P4 (SOC, SOC, Op_RegVectMask, 4, p4->as_VMReg()); reg_def P5 (SOC, SOC, Op_RegVectMask, 5, p5->as_VMReg()); reg_def P6 (SOC, SOC, Op_RegVectMask, 6, p6->as_VMReg()); reg_def P7 (SOC, SOC, Op_RegVectMask, 7, p7->as_VMReg()); reg_def P8 (SOC, SOC, Op_RegVectMask, 8, p8->as_VMReg()); reg_def P9 (SOC, SOC, Op_RegVectMask, 9, p9->as_VMReg()); reg_def P10 (SOC, SOC, Op_RegVectMask, 10, p10->as_VMReg()); reg_def P11 (SOC, SOC, Op_RegVectMask, 11, p11->as_VMReg()); reg_def P12 (SOC, SOC, Op_RegVectMask, 12, p12->as_VMReg()); reg_def P13 (SOC, SOC, Op_RegVectMask, 13, p13->as_VMReg()); reg_def P14 (SOC, SOC, Op_RegVectMask, 14, p14->as_VMReg()); reg_def P15 (SOC, SOC, Op_RegVectMask, 15, p15->as_VMReg()); // ---------------------------- // Special Registers // ---------------------------- // the AArch64 CSPR status flag register is not directly acessible as // instruction operand. the FPSR status flag register is a system // register which can be written/read using MSR/MRS but again does not // appear as an operand (a code identifying the FSPR occurs as an // immediate value in the instruction). reg_def RFLAGS(SOC, SOC, 0, 32, VMRegImpl::Bad()); // Specify priority of register selection within phases of register // allocation. Highest priority is first. A useful heuristic is to // give registers a low priority when they are required by machine // instructions, like EAX and EDX on I486, and choose no-save registers // before save-on-call, & save-on-call before save-on-entry. Registers // which participate in fixed calling sequences should come last. // Registers which are used as pairs must fall on an even boundary. alloc_class chunk0( // volatiles R10, R10_H, R11, R11_H, R12, R12_H, R13, R13_H, R14, R14_H, R15, R15_H, R16, R16_H, R17, R17_H, R18, R18_H, // arg registers R0, R0_H, R1, R1_H, R2, R2_H, R3, R3_H, R4, R4_H, R5, R5_H, R6, R6_H, R7, R7_H, // non-volatiles R19, R19_H, R20, R20_H, R21, R21_H, R22, R22_H, R23, R23_H, R24, R24_H, R25, R25_H, R26, R26_H, // non-allocatable registers R27, R27_H, // heapbase R28, R28_H, // thread R29, R29_H, // fp R30, R30_H, // lr R31, R31_H, // sp R8, R8_H, // rscratch1 R9, R9_H, // rscratch2 ); alloc_class chunk1( // no save V16, V16_H, V16_J, V16_K, V16_L, V16_M, V16_N, V16_O, V17, V17_H, V17_J, V17_K, V17_L, V17_M, V17_N, V17_O, V18, V18_H, V18_J, V18_K, V18_L, V18_M, V18_N, V18_O, V19, V19_H, V19_J, V19_K, V19_L, V19_M, V19_N, V19_O, V20, V20_H, V20_J, V20_K, V20_L, V20_M, V20_N, V20_O, V21, V21_H, V21_J, V21_K, V21_L, V21_M, V21_N, V21_O, V22, V22_H, V22_J, V22_K, V22_L, V22_M, V22_N, V22_O, V23, V23_H, V23_J, V23_K, V23_L, V23_M, V23_N, V23_O, V24, V24_H, V24_J, V24_K, V24_L, V24_M, V24_N, V24_O, V25, V25_H, V25_J, V25_K, V25_L, V25_M, V25_N, V25_O, V26, V26_H, V26_J, V26_K, V26_L, V26_M, V26_N, V26_O, V27, V27_H, V27_J, V27_K, V27_L, V27_M, V27_N, V27_O, V28, V28_H, V28_J, V28_K, V28_L, V28_M, V28_N, V28_O, V29, V29_H, V29_J, V29_K, V29_L, V29_M, V29_N, V29_O, V30, V30_H, V30_J, V30_K, V30_L, V30_M, V30_N, V30_O, V31, V31_H, V31_J, V31_K, V31_L, V31_M, V31_N, V31_O, // arg registers V0, V0_H, V0_J, V0_K, V0_L, V0_M, V0_N, V0_O, V1, V1_H, V1_J, V1_K, V1_L, V1_M, V1_N, V1_O, V2, V2_H, V2_J, V2_K, V2_L, V2_M, V2_N, V2_O, V3, V3_H, V3_J, V3_K, V3_L, V3_M, V3_N, V3_O, V4, V4_H, V4_J, V4_K, V4_L, V4_M, V4_N, V4_O, V5, V5_H, V5_J, V5_K, V5_L, V5_M, V5_N, V5_O, V6, V6_H, V6_J, V6_K, V6_L, V6_M, V6_N, V6_O, V7, V7_H, V7_J, V7_K, V7_L, V7_M, V7_N, V7_O, // non-volatiles V8, V8_H, V8_J, V8_K, V8_L, V8_M, V8_N, V8_O, V9, V9_H, V9_J, V9_K, V9_L, V9_M, V9_N, V9_O, V10, V10_H, V10_J, V10_K, V10_L, V10_M, V10_N, V10_O, V11, V11_H, V11_J, V11_K, V11_L, V11_M, V11_N, V11_O, V12, V12_H, V12_J, V12_K, V12_L, V12_M, V12_N, V12_O, V13, V13_H, V13_J, V13_K, V13_L, V13_M, V13_N, V13_O, V14, V14_H, V14_J, V14_K, V14_L, V14_M, V14_N, V14_O, V15, V15_H, V15_J, V15_K, V15_L, V15_M, V15_N, V15_O, ); alloc_class chunk2 ( P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, ); alloc_class chunk3(RFLAGS); //----------Architecture Description Register Classes-------------------------- // Several register classes are automatically defined based upon information in // this architecture description. // 1) reg_class inline_cache_reg ( /* as def'd in frame section */ ) // 2) reg_class stack_slots( /* one chunk of stack-based "registers" */ ) // // Class for all 32 bit general purpose registers reg_class all_reg32( R0, R1, R2, R3, R4, R5, R6, R7, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, R31 ); // Class for all 32 bit integer registers (excluding SP which // will never be used as an integer register) reg_class any_reg32 %{ return _ANY_REG32_mask; %} // Singleton class for R0 int register reg_class int_r0_reg(R0); // Singleton class for R2 int register reg_class int_r2_reg(R2); // Singleton class for R3 int register reg_class int_r3_reg(R3); // Singleton class for R4 int register reg_class int_r4_reg(R4); // Singleton class for R31 int register reg_class int_r31_reg(R31); // Class for all 64 bit general purpose registers reg_class all_reg( R0, R0_H, R1, R1_H, R2, R2_H, R3, R3_H, R4, R4_H, R5, R5_H, R6, R6_H, R7, R7_H, R10, R10_H, R11, R11_H, R12, R12_H, R13, R13_H, R14, R14_H, R15, R15_H, R16, R16_H, R17, R17_H, R18, R18_H, R19, R19_H, R20, R20_H, R21, R21_H, R22, R22_H, R23, R23_H, R24, R24_H, R25, R25_H, R26, R26_H, R27, R27_H, R28, R28_H, R29, R29_H, R30, R30_H, R31, R31_H ); // Class for all long integer registers (including SP) reg_class any_reg %{ return _ANY_REG_mask; %} // Class for non-allocatable 32 bit registers reg_class non_allocatable_reg32( #ifdef R18_RESERVED // See comment in register_aarch64.hpp R18, // tls on Windows #endif R28, // thread R30, // lr R31 // sp ); // Class for non-allocatable 64 bit registers reg_class non_allocatable_reg( #ifdef R18_RESERVED // See comment in register_aarch64.hpp R18, R18_H, // tls on Windows, platform register on macOS #endif R28, R28_H, // thread R30, R30_H, // lr R31, R31_H // sp ); // Class for all non-special integer registers reg_class no_special_reg32 %{ return _NO_SPECIAL_REG32_mask; %} // Class for all non-special long integer registers reg_class no_special_reg %{ return _NO_SPECIAL_REG_mask; %} // Class for 64 bit register r0 reg_class r0_reg( R0, R0_H ); // Class for 64 bit register r1 reg_class r1_reg( R1, R1_H ); // Class for 64 bit register r2 reg_class r2_reg( R2, R2_H ); // Class for 64 bit register r3 reg_class r3_reg( R3, R3_H ); // Class for 64 bit register r4 reg_class r4_reg( R4, R4_H ); // Class for 64 bit register r5 reg_class r5_reg( R5, R5_H ); // Class for 64 bit register r10 reg_class r10_reg( R10, R10_H ); // Class for 64 bit register r11 reg_class r11_reg( R11, R11_H ); // Class for method register reg_class method_reg( R12, R12_H ); // Class for heapbase register reg_class heapbase_reg( R27, R27_H ); // Class for thread register reg_class thread_reg( R28, R28_H ); // Class for frame pointer register reg_class fp_reg( R29, R29_H ); // Class for link register reg_class lr_reg( R30, R30_H ); // Class for long sp register reg_class sp_reg( R31, R31_H ); // Class for all pointer registers reg_class ptr_reg %{ return _PTR_REG_mask; %} // Class for all non_special pointer registers reg_class no_special_ptr_reg %{ return _NO_SPECIAL_PTR_REG_mask; %} // Class for all float registers reg_class float_reg( V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V30, V31 ); // Double precision float registers have virtual `high halves' that // are needed by the allocator. // Class for all double registers reg_class double_reg( V0, V0_H, V1, V1_H, V2, V2_H, V3, V3_H, V4, V4_H, V5, V5_H, V6, V6_H, V7, V7_H, V8, V8_H, V9, V9_H, V10, V10_H, V11, V11_H, V12, V12_H, V13, V13_H, V14, V14_H, V15, V15_H, V16, V16_H, V17, V17_H, V18, V18_H, V19, V19_H, V20, V20_H, V21, V21_H, V22, V22_H, V23, V23_H, V24, V24_H, V25, V25_H, V26, V26_H, V27, V27_H, V28, V28_H, V29, V29_H, V30, V30_H, V31, V31_H ); // Class for all SVE vector registers. reg_class vectora_reg ( V0, V0_H, V0_J, V0_K, V0_L, V0_M, V0_N, V0_O, V1, V1_H, V1_J, V1_K, V1_L, V1_M, V1_N, V1_O, V2, V2_H, V2_J, V2_K, V2_L, V2_M, V2_N, V2_O, V3, V3_H, V3_J, V3_K, V3_L, V3_M, V3_N, V3_O, V4, V4_H, V4_J, V4_K, V4_L, V4_M, V4_N, V4_O, V5, V5_H, V5_J, V5_K, V5_L, V5_M, V5_N, V5_O, V6, V6_H, V6_J, V6_K, V6_L, V6_M, V6_N, V6_O, V7, V7_H, V7_J, V7_K, V7_L, V7_M, V7_N, V7_O, V8, V8_H, V8_J, V8_K, V8_L, V8_M, V8_N, V8_O, V9, V9_H, V9_J, V9_K, V9_L, V9_M, V9_N, V9_O, V10, V10_H, V10_J, V10_K, V10_L, V10_M, V10_N, V10_O, V11, V11_H, V11_J, V11_K, V11_L, V11_M, V11_N, V11_O, V12, V12_H, V12_J, V12_K, V12_L, V12_M, V12_N, V12_O, V13, V13_H, V13_J, V13_K, V13_L, V13_M, V13_N, V13_O, V14, V14_H, V14_J, V14_K, V14_L, V14_M, V14_N, V14_O, V15, V15_H, V15_J, V15_K, V15_L, V15_M, V15_N, V15_O, V16, V16_H, V16_J, V16_K, V16_L, V16_M, V16_N, V16_O, V17, V17_H, V17_J, V17_K, V17_L, V17_M, V17_N, V17_O, V18, V18_H, V18_J, V18_K, V18_L, V18_M, V18_N, V18_O, V19, V19_H, V19_J, V19_K, V19_L, V19_M, V19_N, V19_O, V20, V20_H, V20_J, V20_K, V20_L, V20_M, V20_N, V20_O, V21, V21_H, V21_J, V21_K, V21_L, V21_M, V21_N, V21_O, V22, V22_H, V22_J, V22_K, V22_L, V22_M, V22_N, V22_O, V23, V23_H, V23_J, V23_K, V23_L, V23_M, V23_N, V23_O, V24, V24_H, V24_J, V24_K, V24_L, V24_M, V24_N, V24_O, V25, V25_H, V25_J, V25_K, V25_L, V25_M, V25_N, V25_O, V26, V26_H, V26_J, V26_K, V26_L, V26_M, V26_N, V26_O, V27, V27_H, V27_J, V27_K, V27_L, V27_M, V27_N, V27_O, V28, V28_H, V28_J, V28_K, V28_L, V28_M, V28_N, V28_O, V29, V29_H, V29_J, V29_K, V29_L, V29_M, V29_N, V29_O, V30, V30_H, V30_J, V30_K, V30_L, V30_M, V30_N, V30_O, V31, V31_H, V31_J, V31_K, V31_L, V31_M, V31_N, V31_O, ); // Class for all 64bit vector registers reg_class vectord_reg( V0, V0_H, V1, V1_H, V2, V2_H, V3, V3_H, V4, V4_H, V5, V5_H, V6, V6_H, V7, V7_H, V8, V8_H, V9, V9_H, V10, V10_H, V11, V11_H, V12, V12_H, V13, V13_H, V14, V14_H, V15, V15_H, V16, V16_H, V17, V17_H, V18, V18_H, V19, V19_H, V20, V20_H, V21, V21_H, V22, V22_H, V23, V23_H, V24, V24_H, V25, V25_H, V26, V26_H, V27, V27_H, V28, V28_H, V29, V29_H, V30, V30_H, V31, V31_H ); // Class for all 128bit vector registers reg_class vectorx_reg( V0, V0_H, V0_J, V0_K, V1, V1_H, V1_J, V1_K, V2, V2_H, V2_J, V2_K, V3, V3_H, V3_J, V3_K, V4, V4_H, V4_J, V4_K, V5, V5_H, V5_J, V5_K, V6, V6_H, V6_J, V6_K, V7, V7_H, V7_J, V7_K, V8, V8_H, V8_J, V8_K, V9, V9_H, V9_J, V9_K, V10, V10_H, V10_J, V10_K, V11, V11_H, V11_J, V11_K, V12, V12_H, V12_J, V12_K, V13, V13_H, V13_J, V13_K, V14, V14_H, V14_J, V14_K, V15, V15_H, V15_J, V15_K, V16, V16_H, V16_J, V16_K, V17, V17_H, V17_J, V17_K, V18, V18_H, V18_J, V18_K, V19, V19_H, V19_J, V19_K, V20, V20_H, V20_J, V20_K, V21, V21_H, V21_J, V21_K, V22, V22_H, V22_J, V22_K, V23, V23_H, V23_J, V23_K, V24, V24_H, V24_J, V24_K, V25, V25_H, V25_J, V25_K, V26, V26_H, V26_J, V26_K, V27, V27_H, V27_J, V27_K, V28, V28_H, V28_J, V28_K, V29, V29_H, V29_J, V29_K, V30, V30_H, V30_J, V30_K, V31, V31_H, V31_J, V31_K ); // Class for 128 bit register v0 reg_class v0_reg( V0, V0_H ); // Class for 128 bit register v1 reg_class v1_reg( V1, V1_H ); // Class for 128 bit register v2 reg_class v2_reg( V2, V2_H ); // Class for 128 bit register v3 reg_class v3_reg( V3, V3_H ); // Class for 128 bit register v4 reg_class v4_reg( V4, V4_H ); // Class for 128 bit register v5 reg_class v5_reg( V5, V5_H ); // Class for 128 bit register v6 reg_class v6_reg( V6, V6_H ); // Class for 128 bit register v7 reg_class v7_reg( V7, V7_H ); // Class for 128 bit register v8 reg_class v8_reg( V8, V8_H ); // Class for 128 bit register v9 reg_class v9_reg( V9, V9_H ); // Class for 128 bit register v10 reg_class v10_reg( V10, V10_H ); // Class for 128 bit register v11 reg_class v11_reg( V11, V11_H ); // Class for 128 bit register v12 reg_class v12_reg( V12, V12_H ); // Class for 128 bit register v13 reg_class v13_reg( V13, V13_H ); // Class for 128 bit register v14 reg_class v14_reg( V14, V14_H ); // Class for 128 bit register v15 reg_class v15_reg( V15, V15_H ); // Class for 128 bit register v16 reg_class v16_reg( V16, V16_H ); // Class for 128 bit register v17 reg_class v17_reg( V17, V17_H ); // Class for 128 bit register v18 reg_class v18_reg( V18, V18_H ); // Class for 128 bit register v19 reg_class v19_reg( V19, V19_H ); // Class for 128 bit register v20 reg_class v20_reg( V20, V20_H ); // Class for 128 bit register v21 reg_class v21_reg( V21, V21_H ); // Class for 128 bit register v22 reg_class v22_reg( V22, V22_H ); // Class for 128 bit register v23 reg_class v23_reg( V23, V23_H ); // Class for 128 bit register v24 reg_class v24_reg( V24, V24_H ); // Class for 128 bit register v25 reg_class v25_reg( V25, V25_H ); // Class for 128 bit register v26 reg_class v26_reg( V26, V26_H ); // Class for 128 bit register v27 reg_class v27_reg( V27, V27_H ); // Class for 128 bit register v28 reg_class v28_reg( V28, V28_H ); // Class for 128 bit register v29 reg_class v29_reg( V29, V29_H ); // Class for 128 bit register v30 reg_class v30_reg( V30, V30_H ); // Class for 128 bit register v31 reg_class v31_reg( V31, V31_H ); // Class for all SVE predicate registers. reg_class pr_reg ( P0, P1, P2, P3, P4, P5, P6, // P7, non-allocatable, preserved with all elements preset to TRUE. P8, P9, P10, P11, P12, P13, P14, P15 ); // Class for SVE governing predicate registers, which are used // to determine the active elements of a predicated instruction. reg_class gov_pr ( P0, P1, P2, P3, P4, P5, P6, // P7, non-allocatable, preserved with all elements preset to TRUE. ); // Singleton class for condition codes reg_class int_flags(RFLAGS); %} //----------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 "); // // we follow the ppc-aix port in using a simple cost model which ranks // register operations as cheap, memory ops as more expensive and // branches as most expensive. the first two have a low as well as a // normal cost. huge cost appears to be a way of saying don't do // something definitions %{ // The default cost (of a register move instruction). int_def INSN_COST ( 100, 100); int_def BRANCH_COST ( 200, 2 * INSN_COST); int_def CALL_COST ( 200, 2 * INSN_COST); int_def VOLATILE_REF_COST ( 1000, 10 * INSN_COST); %} //----------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 %{ #include "asm/macroAssembler.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/cardTable.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "gc/shared/collectedHeap.hpp" #include "opto/addnode.hpp" #include "opto/convertnode.hpp" #include "runtime/objectMonitor.hpp" extern RegMask _ANY_REG32_mask; extern RegMask _ANY_REG_mask; extern RegMask _PTR_REG_mask; extern RegMask _NO_SPECIAL_REG32_mask; extern RegMask _NO_SPECIAL_REG_mask; extern RegMask _NO_SPECIAL_PTR_REG_mask; 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 MacroAssembler::far_codestub_branch_size(); } static uint size_deopt_handler() { // count one adr and one far branch instruction return NativeInstruction::instruction_size + MacroAssembler::far_codestub_branch_size(); } }; class Node::PD { public: enum NodeFlags { _last_flag = Node::_last_flag }; }; bool is_CAS(int opcode, bool maybe_volatile); // predicates controlling emit of ldr/ldar and associated dmb bool unnecessary_acquire(const Node *barrier); bool needs_acquiring_load(const Node *load); // predicates controlling emit of str/stlr and associated dmbs bool unnecessary_release(const Node *barrier); bool unnecessary_volatile(const Node *barrier); bool needs_releasing_store(const Node *store); // predicate controlling translation of CompareAndSwapX bool needs_acquiring_load_exclusive(const Node *load); // predicate controlling addressing modes bool size_fits_all_mem_uses(AddPNode* addp, int shift); %} source %{ // Derived RegMask with conditionally allocatable registers void PhaseOutput::pd_perform_mach_node_analysis() { } int MachNode::pd_alignment_required() const { return 1; } int MachNode::compute_padding(int current_offset) const { return 0; } RegMask _ANY_REG32_mask; RegMask _ANY_REG_mask; RegMask _PTR_REG_mask; RegMask _NO_SPECIAL_REG32_mask; RegMask _NO_SPECIAL_REG_mask; RegMask _NO_SPECIAL_PTR_REG_mask; void reg_mask_init() { // We derive below RegMask(s) from the ones which are auto-generated from // adlc register classes to make AArch64 rheapbase (r27) and rfp (r29) // registers conditionally reserved. _ANY_REG32_mask = _ALL_REG32_mask; _ANY_REG32_mask.Remove(OptoReg::as_OptoReg(r31_sp->as_VMReg())); _ANY_REG_mask = _ALL_REG_mask; _PTR_REG_mask = _ALL_REG_mask; _NO_SPECIAL_REG32_mask = _ALL_REG32_mask; _NO_SPECIAL_REG32_mask.SUBTRACT(_NON_ALLOCATABLE_REG32_mask); _NO_SPECIAL_REG_mask = _ALL_REG_mask; _NO_SPECIAL_REG_mask.SUBTRACT(_NON_ALLOCATABLE_REG_mask); _NO_SPECIAL_PTR_REG_mask = _ALL_REG_mask; _NO_SPECIAL_PTR_REG_mask.SUBTRACT(_NON_ALLOCATABLE_REG_mask); // r27 is not allocatable when compressed oops is on and heapbase is not // zero, compressed klass pointers doesn't use r27 after JDK-8234794 if (UseCompressedOops && (CompressedOops::ptrs_base() != NULL)) { _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg())); _NO_SPECIAL_REG_mask.SUBTRACT(_HEAPBASE_REG_mask); _NO_SPECIAL_PTR_REG_mask.SUBTRACT(_HEAPBASE_REG_mask); } // r29 is not allocatable when PreserveFramePointer is on if (PreserveFramePointer) { _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg())); _NO_SPECIAL_REG_mask.SUBTRACT(_FP_REG_mask); _NO_SPECIAL_PTR_REG_mask.SUBTRACT(_FP_REG_mask); } } // Optimizaton of volatile gets and puts // ------------------------------------- // // AArch64 has ldar and stlr instructions which we can safely // use to implement volatile reads and writes. For a volatile read // we simply need // // ldar // // and for a volatile write we need // // stlr // // Alternatively, we can implement them by pairing a normal // load/store with a memory barrier. For a volatile read we need // // ldr // dmb ishld // // for a volatile write // // dmb ish // str // dmb ish // // We can also use ldaxr and stlxr to implement compare and swap CAS // sequences. These are normally translated to an instruction // sequence like the following // // dmb ish // retry: // ldxr rval raddr // cmp rval rold // b.ne done // stlxr rval, rnew, rold // cbnz rval retry // done: // cset r0, eq // dmb ishld // // Note that the exclusive store is already using an stlxr // instruction. That is required to ensure visibility to other // threads of the exclusive write (assuming it succeeds) before that // of any subsequent writes. // // The following instruction sequence is an improvement on the above // // retry: // ldaxr rval raddr // cmp rval rold // b.ne done // stlxr rval, rnew, rold // cbnz rval retry // done: // cset r0, eq // // We don't need the leading dmb ish since the stlxr guarantees // visibility of prior writes in the case that the swap is // successful. Crucially we don't have to worry about the case where // the swap is not successful since no valid program should be // relying on visibility of prior changes by the attempting thread // in the case where the CAS fails. // // Similarly, we don't need the trailing dmb ishld if we substitute // an ldaxr instruction since that will provide all the guarantees we // require regarding observation of changes made by other threads // before any change to the CAS address observed by the load. // // In order to generate the desired instruction sequence we need to // be able to identify specific 'signature' ideal graph node // sequences which i) occur as a translation of a volatile reads or // writes or CAS operations and ii) do not occur through any other // translation or graph transformation. We can then provide // alternative aldc matching rules which translate these node // sequences to the desired machine code sequences. Selection of the // alternative rules can be implemented by predicates which identify // the relevant node sequences. // // The ideal graph generator translates a volatile read to the node // sequence // // LoadX[mo_acquire] // MemBarAcquire // // As a special case when using the compressed oops optimization we // may also see this variant // // LoadN[mo_acquire] // DecodeN // MemBarAcquire // // A volatile write is translated to the node sequence // // MemBarRelease // StoreX[mo_release] {CardMark}-optional // MemBarVolatile // // n.b. the above node patterns are generated with a strict // 'signature' configuration of input and output dependencies (see // the predicates below for exact details). The card mark may be as // simple as a few extra nodes or, in a few GC configurations, may // include more complex control flow between the leading and // trailing memory barriers. However, whatever the card mark // configuration these signatures are unique to translated volatile // reads/stores -- they will not appear as a result of any other // bytecode translation or inlining nor as a consequence of // optimizing transforms. // // We also want to catch inlined unsafe volatile gets and puts and // be able to implement them using either ldar/stlr or some // combination of ldr/stlr and dmb instructions. // // Inlined unsafe volatiles puts manifest as a minor variant of the // normal volatile put node sequence containing an extra cpuorder // membar // // MemBarRelease // MemBarCPUOrder // StoreX[mo_release] {CardMark}-optional // MemBarCPUOrder // MemBarVolatile // // n.b. as an aside, a cpuorder membar is not itself subject to // matching and translation by adlc rules. However, the rule // predicates need to detect its presence in order to correctly // select the desired adlc rules. // // Inlined unsafe volatile gets manifest as a slightly different // node sequence to a normal volatile get because of the // introduction of some CPUOrder memory barriers to bracket the // Load. However, but the same basic skeleton of a LoadX feeding a // MemBarAcquire, possibly thorugh an optional DecodeN, is still // present // // MemBarCPUOrder // || \\ // MemBarCPUOrder LoadX[mo_acquire] // || | // || {DecodeN} optional // || / // MemBarAcquire // // In this case the acquire membar does not directly depend on the // load. However, we can be sure that the load is generated from an // inlined unsafe volatile get if we see it dependent on this unique // sequence of membar nodes. Similarly, given an acquire membar we // can know that it was added because of an inlined unsafe volatile // get if it is fed and feeds a cpuorder membar and if its feed // membar also feeds an acquiring load. // // Finally an inlined (Unsafe) CAS operation is translated to the // following ideal graph // // MemBarRelease // MemBarCPUOrder // CompareAndSwapX {CardMark}-optional // MemBarCPUOrder // MemBarAcquire // // So, where we can identify these volatile read and write // signatures we can choose to plant either of the above two code // sequences. For a volatile read we can simply plant a normal // ldr and translate the MemBarAcquire to a dmb. However, we can // also choose to inhibit translation of the MemBarAcquire and // inhibit planting of the ldr, instead planting an ldar. // // When we recognise a volatile store signature we can choose to // plant at a dmb ish as a translation for the MemBarRelease, a // normal str and then a dmb ish for the MemBarVolatile. // Alternatively, we can inhibit translation of the MemBarRelease // and MemBarVolatile and instead plant a simple stlr // instruction. // // when we recognise a CAS signature we can choose to plant a dmb // ish as a translation for the MemBarRelease, the conventional // macro-instruction sequence for the CompareAndSwap node (which // uses ldxr) and then a dmb ishld for the MemBarAcquire. // Alternatively, we can elide generation of the dmb instructions // and plant the alternative CompareAndSwap macro-instruction // sequence (which uses ldaxr). // // Of course, the above only applies when we see these signature // configurations. We still want to plant dmb instructions in any // other cases where we may see a MemBarAcquire, MemBarRelease or // MemBarVolatile. For example, at the end of a constructor which // writes final/volatile fields we will see a MemBarRelease // instruction and this needs a 'dmb ish' lest we risk the // constructed object being visible without making the // final/volatile field writes visible. // // n.b. the translation rules below which rely on detection of the // volatile signatures and insert ldar or stlr are failsafe. // If we see anything other than the signature configurations we // always just translate the loads and stores to ldr and str // and translate acquire, release and volatile membars to the // relevant dmb instructions. // // is_CAS(int opcode, bool maybe_volatile) // // return true if opcode is one of the possible CompareAndSwapX // values otherwise false. bool is_CAS(int opcode, bool maybe_volatile) { switch(opcode) { // We handle these case Op_CompareAndSwapI: case Op_CompareAndSwapL: case Op_CompareAndSwapP: case Op_CompareAndSwapN: case Op_ShenandoahCompareAndSwapP: case Op_ShenandoahCompareAndSwapN: case Op_CompareAndSwapB: case Op_CompareAndSwapS: case Op_GetAndSetI: case Op_GetAndSetL: case Op_GetAndSetP: case Op_GetAndSetN: case Op_GetAndAddI: case Op_GetAndAddL: return true; case Op_CompareAndExchangeI: case Op_CompareAndExchangeN: case Op_CompareAndExchangeB: case Op_CompareAndExchangeS: case Op_CompareAndExchangeL: case Op_CompareAndExchangeP: case Op_WeakCompareAndSwapB: case Op_WeakCompareAndSwapS: case Op_WeakCompareAndSwapI: case Op_WeakCompareAndSwapL: case Op_WeakCompareAndSwapP: case Op_WeakCompareAndSwapN: case Op_ShenandoahWeakCompareAndSwapP: case Op_ShenandoahWeakCompareAndSwapN: case Op_ShenandoahCompareAndExchangeP: case Op_ShenandoahCompareAndExchangeN: return maybe_volatile; default: return false; } } // helper to determine the maximum number of Phi nodes we may need to // traverse when searching from a card mark membar for the merge mem // feeding a trailing membar or vice versa // predicates controlling emit of ldr/ldar bool unnecessary_acquire(const Node *barrier) { assert(barrier->is_MemBar(), "expecting a membar"); MemBarNode* mb = barrier->as_MemBar(); if (mb->trailing_load()) { return true; } if (mb->trailing_load_store()) { Node* load_store = mb->in(MemBarNode::Precedent); assert(load_store->is_LoadStore(), "unexpected graph shape"); return is_CAS(load_store->Opcode(), true); } return false; } bool needs_acquiring_load(const Node *n) { assert(n->is_Load(), "expecting a load"); LoadNode *ld = n->as_Load(); return ld->is_acquire(); } bool unnecessary_release(const Node *n) { assert((n->is_MemBar() && n->Opcode() == Op_MemBarRelease), "expecting a release membar"); MemBarNode *barrier = n->as_MemBar(); if (!barrier->leading()) { return false; } else { Node* trailing = barrier->trailing_membar(); MemBarNode* trailing_mb = trailing->as_MemBar(); assert(trailing_mb->trailing(), "Not a trailing membar?"); assert(trailing_mb->leading_membar() == n, "inconsistent leading/trailing membars"); Node* mem = trailing_mb->in(MemBarNode::Precedent); if (mem->is_Store()) { assert(mem->as_Store()->is_release(), ""); assert(trailing_mb->Opcode() == Op_MemBarVolatile, ""); return true; } else { assert(mem->is_LoadStore(), ""); assert(trailing_mb->Opcode() == Op_MemBarAcquire, ""); return is_CAS(mem->Opcode(), true); } } return false; } bool unnecessary_volatile(const Node *n) { // assert n->is_MemBar(); MemBarNode *mbvol = n->as_MemBar(); bool release = mbvol->trailing_store(); assert(!release || (mbvol->in(MemBarNode::Precedent)->is_Store() && mbvol->in(MemBarNode::Precedent)->as_Store()->is_release()), ""); #ifdef ASSERT if (release) { Node* leading = mbvol->leading_membar(); assert(leading->Opcode() == Op_MemBarRelease, ""); assert(leading->as_MemBar()->leading_store(), ""); assert(leading->as_MemBar()->trailing_membar() == mbvol, ""); } #endif return release; } // predicates controlling emit of str/stlr bool needs_releasing_store(const Node *n) { // assert n->is_Store(); StoreNode *st = n->as_Store(); return st->trailing_membar() != NULL; } // predicate controlling translation of CAS // // returns true if CAS needs to use an acquiring load otherwise false bool needs_acquiring_load_exclusive(const Node *n) { assert(is_CAS(n->Opcode(), true), "expecting a compare and swap"); LoadStoreNode* ldst = n->as_LoadStore(); if (is_CAS(n->Opcode(), false)) { assert(ldst->trailing_membar() != NULL, "expected trailing membar"); } else { return ldst->trailing_membar() != NULL; } // so we can just return true here return true; } #define __ _masm. // advance declarations for helper functions to convert register // indices to register objects // the ad file has to provide implementations of certain methods // expected by the generic code // // REQUIRED FUNCTIONALITY //============================================================================= // !!!!! Special hack to get all types of calls to specify the byte offset // from the start of the call to the point where the return address // will point. int MachCallStaticJavaNode::ret_addr_offset() { // call should be a simple bl int off = 4; return off; } int MachCallDynamicJavaNode::ret_addr_offset() { return 16; // movz, movk, movk, bl } int MachCallRuntimeNode::ret_addr_offset() { // for generated stubs the call will be // bl(addr) // or with far branches // bl(trampoline_stub) // for real runtime callouts it will be six instructions // see aarch64_enc_java_to_runtime // adr(rscratch2, retaddr) // lea(rscratch1, RuntimeAddress(addr) // stp(zr, rscratch2, Address(__ pre(sp, -2 * wordSize))) // blr(rscratch1) CodeBlob *cb = CodeCache::find_blob(_entry_point); if (cb) { return 1 * NativeInstruction::instruction_size; } else { return 6 * NativeInstruction::instruction_size; } } int MachCallNativeNode::ret_addr_offset() { // This is implemented using aarch64_enc_java_to_runtime as above. CodeBlob *cb = CodeCache::find_blob(_entry_point); if (cb) { return 1 * NativeInstruction::instruction_size; } else { return 6 * NativeInstruction::instruction_size; } } //============================================================================= #ifndef PRODUCT void MachBreakpointNode::format(PhaseRegAlloc *ra_, outputStream *st) const { st->print("BREAKPOINT"); } #endif void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { C2_MacroAssembler _masm(&cbuf); __ brk(0); } uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const { return MachNode::size(ra_); } //============================================================================= #ifndef PRODUCT void MachNopNode::format(PhaseRegAlloc*, outputStream* st) const { st->print("nop \t# %d bytes pad for loops and calls", _count); } #endif void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc*) const { C2_MacroAssembler _masm(&cbuf); for (int i = 0; i < _count; i++) { __ nop(); } } uint MachNopNode::size(PhaseRegAlloc*) const { return _count * NativeInstruction::instruction_size; } //============================================================================= const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty; int ConstantTable::calculate_table_base_offset() const { return 0; // absolute addressing, no 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 { // Empty encoding } uint MachConstantBaseNode::size(PhaseRegAlloc* ra_) const { return 0; } #ifndef PRODUCT void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const { st->print("-- \t// MachConstantBaseNode (empty encoding)"); } #endif #ifndef PRODUCT void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const { Compile* C = ra_->C; int framesize = C->output()->frame_slots() << LogBytesPerInt; if (C->output()->need_stack_bang(framesize)) st->print("# stack bang size=%d\n\t", framesize); if (framesize < ((1 << 9) + 2 * wordSize)) { st->print("sub sp, sp, #%d\n\t", framesize); st->print("stp rfp, lr, [sp, #%d]", framesize - 2 * wordSize); if (PreserveFramePointer) st->print("\n\tadd rfp, sp, #%d", framesize - 2 * wordSize); } else { st->print("stp lr, rfp, [sp, #%d]!\n\t", -(2 * wordSize)); if (PreserveFramePointer) st->print("mov rfp, sp\n\t"); st->print("mov rscratch1, #%d\n\t", framesize - 2 * wordSize); st->print("sub sp, sp, rscratch1"); } if (C->stub_function() == NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) { st->print("\n\t"); st->print("ldr rscratch1, [guard]\n\t"); st->print("dmb ishld\n\t"); st->print("ldr rscratch2, [rthread, #thread_disarmed_offset]\n\t"); st->print("cmp rscratch1, rscratch2\n\t"); st->print("b.eq skip"); st->print("\n\t"); st->print("blr #nmethod_entry_barrier_stub\n\t"); st->print("b skip\n\t"); st->print("guard: int\n\t"); st->print("\n\t"); st->print("skip:\n\t"); } } #endif void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { Compile* C = ra_->C; C2_MacroAssembler _masm(&cbuf); // n.b. frame size includes space for return pc and rfp const int framesize = C->output()->frame_size_in_bytes(); // 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(); if (C->clinit_barrier_on_entry()) { assert(!C->method()->holder()->is_not_initialized(), "initialization should have been started"); Label L_skip_barrier; __ mov_metadata(rscratch2, C->method()->holder()->constant_encoding()); __ clinit_barrier(rscratch2, rscratch1, &L_skip_barrier); __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); __ bind(L_skip_barrier); } if (C->max_vector_size() >= 16) { __ reinitialize_ptrue(); } int bangsize = C->output()->bang_size_in_bytes(); if (C->output()->need_stack_bang(bangsize)) __ generate_stack_overflow_check(bangsize); __ build_frame(framesize); if (C->stub_function() == NULL) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->nmethod_entry_barrier(&_masm); } if (VerifyStackAtCalls) { Unimplemented(); } C->output()->set_frame_complete(cbuf.insts_size()); if (C->has_mach_constant_base_node()) { // NOTE: We set the table base offset here because users might be // emitted before MachConstantBaseNode. ConstantTable& constant_table = C->output()->constant_table(); constant_table.set_table_base_offset(constant_table.calculate_table_base_offset()); } } uint MachPrologNode::size(PhaseRegAlloc* ra_) const { return MachNode::size(ra_); // too many variables; just compute it // the hard way } int MachPrologNode::reloc() const { return 0; } //============================================================================= #ifndef PRODUCT void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const { Compile* C = ra_->C; int framesize = C->output()->frame_slots() << LogBytesPerInt; st->print("# pop frame %d\n\t",framesize); if (framesize == 0) { st->print("ldp lr, rfp, [sp],#%d\n\t", (2 * wordSize)); } else if (framesize < ((1 << 9) + 2 * wordSize)) { st->print("ldp lr, rfp, [sp,#%d]\n\t", framesize - 2 * wordSize); st->print("add sp, sp, #%d\n\t", framesize); } else { st->print("mov rscratch1, #%d\n\t", framesize - 2 * wordSize); st->print("add sp, sp, rscratch1\n\t"); st->print("ldp lr, rfp, [sp],#%d\n\t", (2 * wordSize)); } if (do_polling() && C->is_method_compilation()) { st->print("# test polling word\n\t"); st->print("ldr rscratch1, [rthread],#%d\n\t", in_bytes(JavaThread::polling_word_offset())); st->print("cmp sp, rscratch1\n\t"); st->print("bhi #slow_path"); } } #endif void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { Compile* C = ra_->C; C2_MacroAssembler _masm(&cbuf); int framesize = C->output()->frame_slots() << LogBytesPerInt; __ remove_frame(framesize); if (StackReservedPages > 0 && C->has_reserved_stack_access()) { __ reserved_stack_check(); } if (do_polling() && C->is_method_compilation()) { Label dummy_label; Label* code_stub = &dummy_label; if (!C->output()->in_scratch_emit_size()) { C2SafepointPollStub* stub = new (C->comp_arena()) C2SafepointPollStub(__ offset()); C->output()->add_stub(stub); code_stub = &stub->entry(); } __ relocate(relocInfo::poll_return_type); __ safepoint_poll(*code_stub, true /* at_return */, false /* acquire */, true /* in_nmethod */); } } uint MachEpilogNode::size(PhaseRegAlloc *ra_) const { // Variable size. Determine dynamically. return MachNode::size(ra_); } int MachEpilogNode::reloc() const { // Return number of relocatable values contained in this instruction. return 1; // 1 for polling page. } const Pipeline * MachEpilogNode::pipeline() const { return MachNode::pipeline_class(); } //============================================================================= // Figure out which register class each belongs in: rc_int, rc_float or // rc_stack. enum RC { rc_bad, rc_int, rc_float, rc_predicate, rc_stack }; static enum RC rc_class(OptoReg::Name reg) { if (reg == OptoReg::Bad) { return rc_bad; } // we have 32 int registers * 2 halves int slots_of_int_registers = RegisterImpl::max_slots_per_register * RegisterImpl::number_of_registers; if (reg < slots_of_int_registers) { return rc_int; } // we have 32 float register * 8 halves int slots_of_float_registers = FloatRegisterImpl::max_slots_per_register * FloatRegisterImpl::number_of_registers; if (reg < slots_of_int_registers + slots_of_float_registers) { return rc_float; } int slots_of_predicate_registers = PRegisterImpl::max_slots_per_register * PRegisterImpl::number_of_registers; if (reg < slots_of_int_registers + slots_of_float_registers + slots_of_predicate_registers) { return rc_predicate; } // Between predicate regs & stack is the flags. assert(OptoReg::is_stack(reg), "blow up if spilling flags"); return rc_stack; } uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, bool do_size, outputStream *st) const { Compile* C = ra_->C; // Get registers to move. OptoReg::Name src_hi = ra_->get_reg_second(in(1)); OptoReg::Name src_lo = ra_->get_reg_first(in(1)); OptoReg::Name dst_hi = ra_->get_reg_second(this); OptoReg::Name dst_lo = ra_->get_reg_first(this); enum RC src_hi_rc = rc_class(src_hi); enum RC src_lo_rc = rc_class(src_lo); enum RC dst_hi_rc = rc_class(dst_hi); enum RC dst_lo_rc = rc_class(dst_lo); assert(src_lo != OptoReg::Bad && dst_lo != OptoReg::Bad, "must move at least 1 register"); if (src_hi != OptoReg::Bad) { assert((src_lo&1)==0 && src_lo+1==src_hi && (dst_lo&1)==0 && dst_lo+1==dst_hi, "expected aligned-adjacent pairs"); } if (src_lo == dst_lo && src_hi == dst_hi) { return 0; // Self copy, no move. } bool is64 = (src_lo & 1) == 0 && src_lo + 1 == src_hi && (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi; int src_offset = ra_->reg2offset(src_lo); int dst_offset = ra_->reg2offset(dst_lo); if (bottom_type()->isa_vect() != NULL) { uint ireg = ideal_reg(); if (ireg == Op_VecA && cbuf) { C2_MacroAssembler _masm(cbuf); int sve_vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { // stack->stack __ spill_copy_sve_vector_stack_to_stack(src_offset, dst_offset, sve_vector_reg_size_in_bytes); } else if (src_lo_rc == rc_float && dst_lo_rc == rc_stack) { __ spill_sve_vector(as_FloatRegister(Matcher::_regEncode[src_lo]), ra_->reg2offset(dst_lo), sve_vector_reg_size_in_bytes); } else if (src_lo_rc == rc_stack && dst_lo_rc == rc_float) { __ unspill_sve_vector(as_FloatRegister(Matcher::_regEncode[dst_lo]), ra_->reg2offset(src_lo), sve_vector_reg_size_in_bytes); } else if (src_lo_rc == rc_float && dst_lo_rc == rc_float) { __ sve_orr(as_FloatRegister(Matcher::_regEncode[dst_lo]), as_FloatRegister(Matcher::_regEncode[src_lo]), as_FloatRegister(Matcher::_regEncode[src_lo])); } else { ShouldNotReachHere(); } } else if (cbuf) { assert(ireg == Op_VecD || ireg == Op_VecX, "must be 64 bit or 128 bit vector"); C2_MacroAssembler _masm(cbuf); assert((src_lo_rc != rc_int && dst_lo_rc != rc_int), "sanity"); if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { // stack->stack assert((src_offset & 7) == 0 && (dst_offset & 7) == 0, "unaligned stack offset"); if (ireg == Op_VecD) { __ unspill(rscratch1, true, src_offset); __ spill(rscratch1, true, dst_offset); } else { __ spill_copy128(src_offset, dst_offset); } } else if (src_lo_rc == rc_float && dst_lo_rc == rc_float) { __ mov(as_FloatRegister(Matcher::_regEncode[dst_lo]), ireg == Op_VecD ? __ T8B : __ T16B, as_FloatRegister(Matcher::_regEncode[src_lo])); } else if (src_lo_rc == rc_float && dst_lo_rc == rc_stack) { __ spill(as_FloatRegister(Matcher::_regEncode[src_lo]), ireg == Op_VecD ? __ D : __ Q, ra_->reg2offset(dst_lo)); } else if (src_lo_rc == rc_stack && dst_lo_rc == rc_float) { __ unspill(as_FloatRegister(Matcher::_regEncode[dst_lo]), ireg == Op_VecD ? __ D : __ Q, ra_->reg2offset(src_lo)); } else { ShouldNotReachHere(); } } } else if (cbuf) { C2_MacroAssembler _masm(cbuf); switch (src_lo_rc) { case rc_int: if (dst_lo_rc == rc_int) { // gpr --> gpr copy if (is64) { __ mov(as_Register(Matcher::_regEncode[dst_lo]), as_Register(Matcher::_regEncode[src_lo])); } else { C2_MacroAssembler _masm(cbuf); __ movw(as_Register(Matcher::_regEncode[dst_lo]), as_Register(Matcher::_regEncode[src_lo])); } } else if (dst_lo_rc == rc_float) { // gpr --> fpr copy if (is64) { __ fmovd(as_FloatRegister(Matcher::_regEncode[dst_lo]), as_Register(Matcher::_regEncode[src_lo])); } else { __ fmovs(as_FloatRegister(Matcher::_regEncode[dst_lo]), as_Register(Matcher::_regEncode[src_lo])); } } else { // gpr --> stack spill assert(dst_lo_rc == rc_stack, "spill to bad register class"); __ spill(as_Register(Matcher::_regEncode[src_lo]), is64, dst_offset); } break; case rc_float: if (dst_lo_rc == rc_int) { // fpr --> gpr copy if (is64) { __ fmovd(as_Register(Matcher::_regEncode[dst_lo]), as_FloatRegister(Matcher::_regEncode[src_lo])); } else { __ fmovs(as_Register(Matcher::_regEncode[dst_lo]), as_FloatRegister(Matcher::_regEncode[src_lo])); } } else if (dst_lo_rc == rc_float) { // fpr --> fpr copy if (cbuf) { __ fmovd(as_FloatRegister(Matcher::_regEncode[dst_lo]), as_FloatRegister(Matcher::_regEncode[src_lo])); } else { __ fmovs(as_FloatRegister(Matcher::_regEncode[dst_lo]), as_FloatRegister(Matcher::_regEncode[src_lo])); } } else { // fpr --> stack spill assert(dst_lo_rc == rc_stack, "spill to bad register class"); __ spill(as_FloatRegister(Matcher::_regEncode[src_lo]), is64 ? __ D : __ S, dst_offset); } break; case rc_stack: if (dst_lo_rc == rc_int) { // stack --> gpr load __ unspill(as_Register(Matcher::_regEncode[dst_lo]), is64, src_offset); } else if (dst_lo_rc == rc_float) { // stack --> fpr load __ unspill(as_FloatRegister(Matcher::_regEncode[dst_lo]), is64 ? __ D : __ S, src_offset); } else { // stack --> stack copy assert(dst_lo_rc == rc_stack, "spill to bad register class"); __ unspill(rscratch1, is64, src_offset); __ spill(rscratch1, is64, dst_offset); } break; default: assert(false, "bad rc_class for spill"); ShouldNotReachHere(); } } if (st) { st->print("spill "); if (src_lo_rc == rc_stack) { st->print("[sp, #%d] -> ", ra_->reg2offset(src_lo)); } else { st->print("%s -> ", Matcher::regName[src_lo]); } if (dst_lo_rc == rc_stack) { st->print("[sp, #%d]", ra_->reg2offset(dst_lo)); } else { st->print("%s", Matcher::regName[dst_lo]); } if (bottom_type()->isa_vect() != NULL) { int vsize = 0; switch (ideal_reg()) { case Op_VecD: vsize = 64; break; case Op_VecX: vsize = 128; break; case Op_VecA: vsize = Matcher::scalable_vector_reg_size(T_BYTE) * 8; break; default: assert(false, "bad register type for spill"); ShouldNotReachHere(); } st->print("\t# vector spill size = %d", vsize); } else { st->print("\t# spill size = %d", is64 ? 64 : 32); } } return 0; } #ifndef PRODUCT void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream *st) const { if (!ra_) st->print("N%d = SpillCopy(N%d)", _idx, in(1)->_idx); else 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 MachNode::size(ra_); } //============================================================================= #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, rsp, #%d]\t# box lock", Matcher::regName[reg], offset); } #endif void BoxLockNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { C2_MacroAssembler _masm(&cbuf); int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); int reg = ra_->get_encode(this); // This add will handle any 24-bit signed offset. 24 bits allows an // 8 megabyte stack frame. __ add(as_Register(reg), sp, offset); } uint BoxLockNode::size(PhaseRegAlloc *ra_) const { // BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_). int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); if (Assembler::operand_valid_for_add_sub_immediate(offset)) { return NativeInstruction::instruction_size; } else { return 2 * NativeInstruction::instruction_size; } } //============================================================================= #ifndef PRODUCT void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const { st->print_cr("# MachUEPNode"); if (UseCompressedClassPointers) { st->print_cr("\tldrw rscratch1, j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); if (CompressedKlassPointers::shift() != 0) { st->print_cr("\tdecode_klass_not_null rscratch1, rscratch1"); } } else { st->print_cr("\tldr rscratch1, j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); } st->print_cr("\tcmp r0, rscratch1\t # Inline cache check"); st->print_cr("\tbne, SharedRuntime::_ic_miss_stub"); } #endif void MachUEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { // This is the unverified entry point. C2_MacroAssembler _masm(&cbuf); __ cmp_klass(j_rarg0, rscratch2, rscratch1); Label skip; // TODO // can we avoid this skip and still use a reloc? __ br(Assembler::EQ, skip); __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); __ bind(skip); } uint MachUEPNode::size(PhaseRegAlloc* ra_) const { return MachNode::size(ra_); } // REQUIRED EMIT CODE //============================================================================= // Emit exception handler code. int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) { // mov rscratch1 #exception_blob_entry_point // br rscratch1 // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a handler. C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); if (base == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } int offset = __ offset(); __ far_jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); __ end_a_stub(); return offset; } // Emit deopt handler code. int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a handler. C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_deopt_handler()); if (base == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } int offset = __ offset(); __ adr(lr, __ pc()); __ far_jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); 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; bool ret_value = true; switch (opcode) { case Op_OnSpinWait: return VM_Version::supports_on_spin_wait(); case Op_CacheWB: case Op_CacheWBPreSync: case Op_CacheWBPostSync: if (!VM_Version::supports_data_cache_line_flush()) { ret_value = false; } break; } return ret_value; // Per default match rules are supported. } // Identify extra cases that we might want to provide match rules for vector nodes and // other intrinsics guarded with vector length (vlen) and element type (bt). const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { if (!match_rule_supported(opcode) || !vector_size_supported(bt, vlen)) { return false; } int bit_size = vlen * type2aelembytes(bt) * 8; if (UseSVE == 0 && bit_size > 128) { return false; } if (UseSVE > 0) { return op_sve_supported(opcode); } else { // NEON // Special cases switch (opcode) { case Op_VectorMaskCmp: // We don't have VectorReinterpret with bit_size less than 64 support for // now, even for byte type. To be refined with fully VectorCast support. case Op_VectorReinterpret: if (vlen < 2 || bit_size < 64) { return false; } break; case Op_MulAddVS2VI: if (bit_size < 128) { return false; } break; case Op_MulVL: return false; case Op_VectorLoadShuffle: case Op_VectorRearrange: if (vlen < 4) { return false; } break; // Some types of VectorCast are not implemented for now. case Op_VectorCastI2X: if (bt == T_BYTE) { return false; } break; case Op_VectorCastS2X: if (vlen < 4 || bit_size < 64) { return false; } break; case Op_VectorCastF2X: case Op_VectorCastD2X: if (bt == T_INT || bt == T_SHORT || bt == T_BYTE || bt == T_LONG) { return false; } break; default: break; } } return true; // Per default match rules are supported. } const RegMask* Matcher::predicate_reg_mask(void) { return &_PR_REG_mask; } const TypeVect* Matcher::predicate_reg_type(const Type* elemTy, int length) { return new TypeVectMask(elemTy, length); } // Vector calling convention not yet implemented. const bool Matcher::supports_vector_calling_convention(void) { return false; } OptoRegPair Matcher::vector_return_value(uint ideal_reg) { Unimplemented(); return OptoRegPair(0, 0); } const int Matcher::float_pressure(int default_pressure_threshold) { return default_pressure_threshold; } // 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. return (-32768 <= offset && offset < 32768); } // Vector width in bytes. const int Matcher::vector_width_in_bytes(BasicType bt) { // The MaxVectorSize should have been set by detecting SVE max vector register size. int size = MIN2((UseSVE > 0) ? 256 : 16, (int)MaxVectorSize); // Minimum 2 values in vector if (size < 2*type2aelembytes(bt)) size = 0; // But never < 4 if (size < 4) size = 0; return size; } // Limits on vector size (number of elements) loaded into vector. const int Matcher::max_vector_size(const BasicType bt) { return vector_width_in_bytes(bt)/type2aelembytes(bt); } const int Matcher::min_vector_size(const BasicType bt) { int max_size = max_vector_size(bt); if ((UseSVE > 0) && (MaxVectorSize >= 16)) { // Currently vector length less than SVE vector register size is not supported. return max_size; } else { // NEON // Limit the vector size to 8 bytes int size = 8 / type2aelembytes(bt); if (bt == T_BYTE) { // To support vector api shuffle/rearrange. size = 4; } else if (bt == T_BOOLEAN) { // To support vector api load/store mask. size = 2; } if (size < 2) size = 2; return MIN2(size,max_size); } } // Actual max scalable vector register length. const int Matcher::scalable_vector_reg_size(const BasicType bt) { return Matcher::max_vector_size(bt); } // Vector ideal reg. const uint Matcher::vector_ideal_reg(int len) { if (UseSVE > 0 && 16 <= len && len <= 256) { return Op_VecA; } switch(len) { // For 16-bit/32-bit mask vector, reuse VecD. case 2: case 4: case 8: return Op_VecD; case 16: return Op_VecX; } ShouldNotReachHere(); return 0; } MachOper* Matcher::pd_specialize_generic_vector_operand(MachOper* original_opnd, uint ideal_reg, bool is_temp) { ShouldNotReachHere(); // generic vector operands not supported return NULL; } bool Matcher::is_generic_reg2reg_move(MachNode* m) { ShouldNotReachHere(); // generic vector operands not supported return false; } bool Matcher::is_generic_vector(MachOper* opnd) { ShouldNotReachHere(); // generic vector operands not supported return false; } // 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) { return reg == R0_num || reg == R0_H_num || reg == R1_num || reg == R1_H_num || reg == R2_num || reg == R2_H_num || reg == R3_num || reg == R3_H_num || reg == R4_num || reg == R4_H_num || reg == R5_num || reg == R5_H_num || reg == R6_num || reg == R6_H_num || reg == R7_num || reg == R7_H_num || reg == V0_num || reg == V0_H_num || reg == V1_num || reg == V1_H_num || reg == V2_num || reg == V2_H_num || reg == V3_num || reg == V3_H_num || reg == V4_num || reg == V4_H_num || reg == V5_num || reg == V5_H_num || reg == V6_num || reg == V6_H_num || reg == V7_num || reg == V7_H_num; } 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; } 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_REG_mask(); } bool size_fits_all_mem_uses(AddPNode* addp, int shift) { for (DUIterator_Fast imax, i = addp->fast_outs(imax); i < imax; i++) { Node* u = addp->fast_out(i); if (u->is_LoadStore()) { // On AArch64, LoadStoreNodes (i.e. compare and swap // instructions) only take register indirect as an operand, so // any attempt to use an AddPNode as an input to a LoadStoreNode // must fail. return false; } if (u->is_Mem()) { int opsize = u->as_Mem()->memory_size(); assert(opsize > 0, "unexpected memory operand size"); if (u->as_Mem()->memory_size() != (1<in(AddPNode::Offset); if (off->Opcode() == Op_LShiftL && off->in(2)->is_Con() && size_fits_all_mem_uses(m, off->in(2)->get_int()) && // Are there other uses besides address expressions? !is_visited(off)) { address_visited.set(off->_idx); // Flag as address_visited mstack.push(off->in(2), Visit); Node *conv = off->in(1); if (conv->Opcode() == Op_ConvI2L && // Are there other uses besides address expressions? !is_visited(conv)) { address_visited.set(conv->_idx); // Flag as address_visited mstack.push(conv->in(1), Pre_Visit); } else { mstack.push(conv, Pre_Visit); } address_visited.test_set(m->_idx); // Flag as address_visited mstack.push(m->in(AddPNode::Address), Pre_Visit); mstack.push(m->in(AddPNode::Base), Pre_Visit); return true; } else if (off->Opcode() == Op_ConvI2L && // Are there other uses besides address expressions? !is_visited(off)) { address_visited.test_set(m->_idx); // Flag as address_visited address_visited.set(off->_idx); // Flag as address_visited mstack.push(off->in(1), Pre_Visit); mstack.push(m->in(AddPNode::Address), Pre_Visit); mstack.push(m->in(AddPNode::Base), Pre_Visit); return true; } return false; } #define MOV_VOLATILE(REG, BASE, INDEX, SCALE, DISP, SCRATCH, INSN) \ C2_MacroAssembler _masm(&cbuf); \ { \ guarantee(INDEX == -1, "mode not permitted for volatile"); \ guarantee(DISP == 0, "mode not permitted for volatile"); \ guarantee(SCALE == 0, "mode not permitted for volatile"); \ __ INSN(REG, as_Register(BASE)); \ } static Address mem2address(int opcode, Register base, int index, int size, int disp) { Address::extend scale; // Hooboy, this is fugly. We need a way to communicate to the // encoder that the index needs to be sign extended, so we have to // enumerate all the cases. switch (opcode) { case INDINDEXSCALEDI2L: case INDINDEXSCALEDI2LN: case INDINDEXI2L: case INDINDEXI2LN: scale = Address::sxtw(size); break; default: scale = Address::lsl(size); } if (index == -1) { return Address(base, disp); } else { assert(disp == 0, "unsupported address mode: disp = %d", disp); return Address(base, as_Register(index), scale); } } typedef void (MacroAssembler::* mem_insn)(Register Rt, const Address &adr); typedef void (MacroAssembler::* mem_insn2)(Register Rt, Register adr); typedef void (MacroAssembler::* mem_float_insn)(FloatRegister Rt, const Address &adr); typedef void (MacroAssembler::* mem_vector_insn)(FloatRegister Rt, MacroAssembler::SIMD_RegVariant T, const Address &adr); // Used for all non-volatile memory accesses. The use of // $mem->opcode() to discover whether this pattern uses sign-extended // offsets is something of a kludge. static void loadStore(C2_MacroAssembler masm, mem_insn insn, Register reg, int opcode, Register base, int index, int scale, int disp, int size_in_memory) { Address addr = mem2address(opcode, base, index, scale, disp); if (addr.getMode() == Address::base_plus_offset) { /* If we get an out-of-range offset it is a bug in the compiler, so we assert here. */ assert(Address::offset_ok_for_immed(addr.offset(), exact_log2(size_in_memory)), "c2 compiler bug"); /* Fix up any out-of-range offsets. */ assert_different_registers(rscratch1, base); assert_different_registers(rscratch1, reg); addr = masm.legitimize_address(addr, size_in_memory, rscratch1); } (masm.*insn)(reg, addr); } static void loadStore(C2_MacroAssembler masm, mem_float_insn insn, FloatRegister reg, int opcode, Register base, int index, int size, int disp, int size_in_memory) { Address::extend scale; switch (opcode) { case INDINDEXSCALEDI2L: case INDINDEXSCALEDI2LN: scale = Address::sxtw(size); break; default: scale = Address::lsl(size); } if (index == -1) { /* If we get an out-of-range offset it is a bug in the compiler, so we assert here. */ assert(Address::offset_ok_for_immed(disp, exact_log2(size_in_memory)), "c2 compiler bug"); /* Fix up any out-of-range offsets. */ assert_different_registers(rscratch1, base); Address addr = Address(base, disp); addr = masm.legitimize_address(addr, size_in_memory, rscratch1); (masm.*insn)(reg, addr); } else { assert(disp == 0, "unsupported address mode: disp = %d", disp); (masm.*insn)(reg, Address(base, as_Register(index), scale)); } } static void loadStore(C2_MacroAssembler masm, mem_vector_insn insn, FloatRegister reg, MacroAssembler::SIMD_RegVariant T, int opcode, Register base, int index, int size, int disp) { if (index == -1) { (masm.*insn)(reg, T, Address(base, disp)); } else { assert(disp == 0, "unsupported address mode"); (masm.*insn)(reg, T, Address(base, as_Register(index), Address::lsl(size))); } } %} //----------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 %{ // Build emit functions for each basic byte or larger field in the // intel encoding scheme (opcode, rm, sib, immediate), and call them // from C++ code in the enc_class source block. Emit functions will // live in the main source block for now. In future, we can // generalize this by adding a syntax that specifies the sizes of // fields in an order, so that the adlc can build the emit functions // automagically // catch all for unimplemented encodings enc_class enc_unimplemented %{ C2_MacroAssembler _masm(&cbuf); __ unimplemented("C2 catch all"); %} // BEGIN Non-volatile memory access // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrsbw(iRegI dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrsbw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrsb(iRegI dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrsb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrb(iRegI dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrb(iRegL dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrshw(iRegI dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrshw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrsh(iRegI dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrsh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrh(iRegI dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrh(iRegL dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrw(iRegI dst, memory4 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrw(iRegL dst, memory4 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrsw(iRegL dst, memory4 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrsw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldr(iRegL dst, memory8 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldr, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrs(vRegF dst, memory4 mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrs, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_ldrd(vRegD dst, memory8 mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrd, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_strb(iRegI src, memory1 mem) %{ Register src_reg = as_Register($src$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::strb, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_strb0(memory1 mem) %{ C2_MacroAssembler _masm(&cbuf); loadStore(_masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_strh(iRegI src, memory2 mem) %{ Register src_reg = as_Register($src$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::strh, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_strh0(memory2 mem) %{ C2_MacroAssembler _masm(&cbuf); loadStore(_masm, &MacroAssembler::strh, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_strw(iRegI src, memory4 mem) %{ Register src_reg = as_Register($src$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::strw, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_strw0(memory4 mem) %{ C2_MacroAssembler _masm(&cbuf); loadStore(_masm, &MacroAssembler::strw, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_str(iRegL src, memory8 mem) %{ Register src_reg = as_Register($src$$reg); // we sometimes get asked to store the stack pointer into the // current thread -- we cannot do that directly on AArch64 if (src_reg == r31_sp) { C2_MacroAssembler _masm(&cbuf); assert(as_Register($mem$$base) == rthread, "unexpected store for sp"); __ mov(rscratch2, sp); src_reg = rscratch2; } loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::str, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_str0(memory8 mem) %{ C2_MacroAssembler _masm(&cbuf); loadStore(_masm, &MacroAssembler::str, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_strs(vRegF src, memory4 mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::strs, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_strd(vRegD src, memory8 mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::strd, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE enc_class aarch64_enc_strb0_ordered(memory4 mem) %{ C2_MacroAssembler _masm(&cbuf); __ membar(Assembler::StoreStore); loadStore(_masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); %} // END Non-volatile memory access // Vector loads and stores enc_class aarch64_enc_ldrvH(vecD dst, memory mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldr, dst_reg, MacroAssembler::H, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp); %} enc_class aarch64_enc_ldrvS(vecD dst, memory mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldr, dst_reg, MacroAssembler::S, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp); %} enc_class aarch64_enc_ldrvD(vecD dst, memory mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldr, dst_reg, MacroAssembler::D, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp); %} enc_class aarch64_enc_ldrvQ(vecX dst, memory mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldr, dst_reg, MacroAssembler::Q, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp); %} enc_class aarch64_enc_strvH(vecD src, memory mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::str, src_reg, MacroAssembler::H, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp); %} enc_class aarch64_enc_strvS(vecD src, memory mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::str, src_reg, MacroAssembler::S, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp); %} enc_class aarch64_enc_strvD(vecD src, memory mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::str, src_reg, MacroAssembler::D, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp); %} enc_class aarch64_enc_strvQ(vecX src, memory mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::str, src_reg, MacroAssembler::Q, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp); %} // volatile loads and stores enc_class aarch64_enc_stlrb(iRegI src, memory mem) %{ MOV_VOLATILE(as_Register($src$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlrb); %} enc_class aarch64_enc_stlrb0(memory mem) %{ MOV_VOLATILE(zr, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlrb); %} enc_class aarch64_enc_stlrh(iRegI src, memory mem) %{ MOV_VOLATILE(as_Register($src$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlrh); %} enc_class aarch64_enc_stlrh0(memory mem) %{ MOV_VOLATILE(zr, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlrh); %} enc_class aarch64_enc_stlrw(iRegI src, memory mem) %{ MOV_VOLATILE(as_Register($src$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlrw); %} enc_class aarch64_enc_stlrw0(memory mem) %{ MOV_VOLATILE(zr, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlrw); %} enc_class aarch64_enc_ldarsbw(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); MOV_VOLATILE(dst_reg, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldarb); __ sxtbw(dst_reg, dst_reg); %} enc_class aarch64_enc_ldarsb(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); MOV_VOLATILE(dst_reg, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldarb); __ sxtb(dst_reg, dst_reg); %} enc_class aarch64_enc_ldarbw(iRegI dst, memory mem) %{ MOV_VOLATILE(as_Register($dst$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldarb); %} enc_class aarch64_enc_ldarb(iRegL dst, memory mem) %{ MOV_VOLATILE(as_Register($dst$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldarb); %} enc_class aarch64_enc_ldarshw(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); MOV_VOLATILE(dst_reg, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldarh); __ sxthw(dst_reg, dst_reg); %} enc_class aarch64_enc_ldarsh(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); MOV_VOLATILE(dst_reg, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldarh); __ sxth(dst_reg, dst_reg); %} enc_class aarch64_enc_ldarhw(iRegI dst, memory mem) %{ MOV_VOLATILE(as_Register($dst$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldarh); %} enc_class aarch64_enc_ldarh(iRegL dst, memory mem) %{ MOV_VOLATILE(as_Register($dst$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldarh); %} enc_class aarch64_enc_ldarw(iRegI dst, memory mem) %{ MOV_VOLATILE(as_Register($dst$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldarw); %} enc_class aarch64_enc_ldarw(iRegL dst, memory mem) %{ MOV_VOLATILE(as_Register($dst$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldarw); %} enc_class aarch64_enc_ldar(iRegL dst, memory mem) %{ MOV_VOLATILE(as_Register($dst$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldar); %} enc_class aarch64_enc_fldars(vRegF dst, memory mem) %{ MOV_VOLATILE(rscratch1, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldarw); __ fmovs(as_FloatRegister($dst$$reg), rscratch1); %} enc_class aarch64_enc_fldard(vRegD dst, memory mem) %{ MOV_VOLATILE(rscratch1, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, ldar); __ fmovd(as_FloatRegister($dst$$reg), rscratch1); %} enc_class aarch64_enc_stlr(iRegL src, memory mem) %{ Register src_reg = as_Register($src$$reg); // we sometimes get asked to store the stack pointer into the // current thread -- we cannot do that directly on AArch64 if (src_reg == r31_sp) { C2_MacroAssembler _masm(&cbuf); assert(as_Register($mem$$base) == rthread, "unexpected store for sp"); __ mov(rscratch2, sp); src_reg = rscratch2; } MOV_VOLATILE(src_reg, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlr); %} enc_class aarch64_enc_stlr0(memory mem) %{ MOV_VOLATILE(zr, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlr); %} enc_class aarch64_enc_fstlrs(vRegF src, memory mem) %{ { C2_MacroAssembler _masm(&cbuf); FloatRegister src_reg = as_FloatRegister($src$$reg); __ fmovs(rscratch2, src_reg); } MOV_VOLATILE(rscratch2, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlrw); %} enc_class aarch64_enc_fstlrd(vRegD src, memory mem) %{ { C2_MacroAssembler _masm(&cbuf); FloatRegister src_reg = as_FloatRegister($src$$reg); __ fmovd(rscratch2, src_reg); } MOV_VOLATILE(rscratch2, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlr); %} // synchronized read/update encodings enc_class aarch64_enc_ldaxr(iRegL dst, memory8 mem) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); Register base = as_Register($mem$$base); int index = $mem$$index; int scale = $mem$$scale; int disp = $mem$$disp; if (index == -1) { if (disp != 0) { __ lea(rscratch1, Address(base, disp)); __ ldaxr(dst_reg, rscratch1); } else { // TODO // should we ever get anything other than this case? __ ldaxr(dst_reg, base); } } else { Register index_reg = as_Register(index); if (disp == 0) { __ lea(rscratch1, Address(base, index_reg, Address::lsl(scale))); __ ldaxr(dst_reg, rscratch1); } else { __ lea(rscratch1, Address(base, disp)); __ lea(rscratch1, Address(rscratch1, index_reg, Address::lsl(scale))); __ ldaxr(dst_reg, rscratch1); } } %} enc_class aarch64_enc_stlxr(iRegLNoSp src, memory8 mem) %{ C2_MacroAssembler _masm(&cbuf); Register src_reg = as_Register($src$$reg); Register base = as_Register($mem$$base); int index = $mem$$index; int scale = $mem$$scale; int disp = $mem$$disp; if (index == -1) { if (disp != 0) { __ lea(rscratch2, Address(base, disp)); __ stlxr(rscratch1, src_reg, rscratch2); } else { // TODO // should we ever get anything other than this case? __ stlxr(rscratch1, src_reg, base); } } else { Register index_reg = as_Register(index); if (disp == 0) { __ lea(rscratch2, Address(base, index_reg, Address::lsl(scale))); __ stlxr(rscratch1, src_reg, rscratch2); } else { __ lea(rscratch2, Address(base, disp)); __ lea(rscratch2, Address(rscratch2, index_reg, Address::lsl(scale))); __ stlxr(rscratch1, src_reg, rscratch2); } } __ cmpw(rscratch1, zr); %} enc_class aarch64_enc_cmpxchg(memory mem, iRegLNoSp oldval, iRegLNoSp newval) %{ C2_MacroAssembler _masm(&cbuf); guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, /*acquire*/ false, /*release*/ true, /*weak*/ false, noreg); %} enc_class aarch64_enc_cmpxchgw(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ C2_MacroAssembler _masm(&cbuf); guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::word, /*acquire*/ false, /*release*/ true, /*weak*/ false, noreg); %} enc_class aarch64_enc_cmpxchgs(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ C2_MacroAssembler _masm(&cbuf); guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::halfword, /*acquire*/ false, /*release*/ true, /*weak*/ false, noreg); %} enc_class aarch64_enc_cmpxchgb(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ C2_MacroAssembler _masm(&cbuf); guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::byte, /*acquire*/ false, /*release*/ true, /*weak*/ false, noreg); %} // The only difference between aarch64_enc_cmpxchg and // aarch64_enc_cmpxchg_acq is that we use load-acquire in the // CompareAndSwap sequence to serve as a barrier on acquiring a // lock. enc_class aarch64_enc_cmpxchg_acq(memory mem, iRegLNoSp oldval, iRegLNoSp newval) %{ C2_MacroAssembler _masm(&cbuf); guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, /*acquire*/ true, /*release*/ true, /*weak*/ false, noreg); %} enc_class aarch64_enc_cmpxchgw_acq(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ C2_MacroAssembler _masm(&cbuf); guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::word, /*acquire*/ true, /*release*/ true, /*weak*/ false, noreg); %} enc_class aarch64_enc_cmpxchgs_acq(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ C2_MacroAssembler _masm(&cbuf); guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::halfword, /*acquire*/ true, /*release*/ true, /*weak*/ false, noreg); %} enc_class aarch64_enc_cmpxchgb_acq(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ C2_MacroAssembler _masm(&cbuf); guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, Assembler::byte, /*acquire*/ true, /*release*/ true, /*weak*/ false, noreg); %} // auxiliary used for CompareAndSwapX to set result register enc_class aarch64_enc_cset_eq(iRegINoSp res) %{ C2_MacroAssembler _masm(&cbuf); Register res_reg = as_Register($res$$reg); __ cset(res_reg, Assembler::EQ); %} // prefetch encodings enc_class aarch64_enc_prefetchw(memory mem) %{ C2_MacroAssembler _masm(&cbuf); Register base = as_Register($mem$$base); int index = $mem$$index; int scale = $mem$$scale; int disp = $mem$$disp; if (index == -1) { __ prfm(Address(base, disp), PSTL1KEEP); } else { Register index_reg = as_Register(index); if (disp == 0) { __ prfm(Address(base, index_reg, Address::lsl(scale)), PSTL1KEEP); } else { __ lea(rscratch1, Address(base, disp)); __ prfm(Address(rscratch1, index_reg, Address::lsl(scale)), PSTL1KEEP); } } %} /// mov envcodings enc_class aarch64_enc_movw_imm(iRegI dst, immI src) %{ C2_MacroAssembler _masm(&cbuf); uint32_t con = (uint32_t)$src$$constant; Register dst_reg = as_Register($dst$$reg); if (con == 0) { __ movw(dst_reg, zr); } else { __ movw(dst_reg, con); } %} enc_class aarch64_enc_mov_imm(iRegL dst, immL src) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); uint64_t con = (uint64_t)$src$$constant; if (con == 0) { __ mov(dst_reg, zr); } else { __ mov(dst_reg, con); } %} enc_class aarch64_enc_mov_p(iRegP dst, immP src) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); address con = (address)$src$$constant; if (con == NULL || con == (address)1) { ShouldNotReachHere(); } else { relocInfo::relocType rtype = $src->constant_reloc(); if (rtype == relocInfo::oop_type) { __ movoop(dst_reg, (jobject)con, /*immediate*/true); } else if (rtype == relocInfo::metadata_type) { __ mov_metadata(dst_reg, (Metadata*)con); } else { assert(rtype == relocInfo::none, "unexpected reloc type"); if (! __ is_valid_AArch64_address(con) || con < (address)(uintptr_t)os::vm_page_size()) { __ mov(dst_reg, con); } else { uint64_t offset; __ adrp(dst_reg, con, offset); __ add(dst_reg, dst_reg, offset); } } } %} enc_class aarch64_enc_mov_p0(iRegP dst, immP0 src) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); __ mov(dst_reg, zr); %} enc_class aarch64_enc_mov_p1(iRegP dst, immP_1 src) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); __ mov(dst_reg, (uint64_t)1); %} enc_class aarch64_enc_mov_byte_map_base(iRegP dst, immByteMapBase src) %{ C2_MacroAssembler _masm(&cbuf); __ load_byte_map_base($dst$$Register); %} enc_class aarch64_enc_mov_n(iRegN dst, immN src) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); address con = (address)$src$$constant; if (con == NULL) { ShouldNotReachHere(); } else { relocInfo::relocType rtype = $src->constant_reloc(); assert(rtype == relocInfo::oop_type, "unexpected reloc type"); __ set_narrow_oop(dst_reg, (jobject)con); } %} enc_class aarch64_enc_mov_n0(iRegN dst, immN0 src) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); __ mov(dst_reg, zr); %} enc_class aarch64_enc_mov_nk(iRegN dst, immNKlass src) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); address con = (address)$src$$constant; if (con == NULL) { ShouldNotReachHere(); } else { relocInfo::relocType rtype = $src->constant_reloc(); assert(rtype == relocInfo::metadata_type, "unexpected reloc type"); __ set_narrow_klass(dst_reg, (Klass *)con); } %} // arithmetic encodings enc_class aarch64_enc_addsubw_imm(iRegI dst, iRegI src1, immIAddSub src2) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); Register src_reg = as_Register($src1$$reg); int32_t con = (int32_t)$src2$$constant; // add has primary == 0, subtract has primary == 1 if ($primary) { con = -con; } if (con < 0) { __ subw(dst_reg, src_reg, -con); } else { __ addw(dst_reg, src_reg, con); } %} enc_class aarch64_enc_addsub_imm(iRegL dst, iRegL src1, immLAddSub src2) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); Register src_reg = as_Register($src1$$reg); int32_t con = (int32_t)$src2$$constant; // add has primary == 0, subtract has primary == 1 if ($primary) { con = -con; } if (con < 0) { __ sub(dst_reg, src_reg, -con); } else { __ add(dst_reg, src_reg, con); } %} enc_class aarch64_enc_divw(iRegI dst, iRegI src1, iRegI src2) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); Register src1_reg = as_Register($src1$$reg); Register src2_reg = as_Register($src2$$reg); __ corrected_idivl(dst_reg, src1_reg, src2_reg, false, rscratch1); %} enc_class aarch64_enc_div(iRegI dst, iRegI src1, iRegI src2) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); Register src1_reg = as_Register($src1$$reg); Register src2_reg = as_Register($src2$$reg); __ corrected_idivq(dst_reg, src1_reg, src2_reg, false, rscratch1); %} enc_class aarch64_enc_modw(iRegI dst, iRegI src1, iRegI src2) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); Register src1_reg = as_Register($src1$$reg); Register src2_reg = as_Register($src2$$reg); __ corrected_idivl(dst_reg, src1_reg, src2_reg, true, rscratch1); %} enc_class aarch64_enc_mod(iRegI dst, iRegI src1, iRegI src2) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); Register src1_reg = as_Register($src1$$reg); Register src2_reg = as_Register($src2$$reg); __ corrected_idivq(dst_reg, src1_reg, src2_reg, true, rscratch1); %} // compare instruction encodings enc_class aarch64_enc_cmpw(iRegI src1, iRegI src2) %{ C2_MacroAssembler _masm(&cbuf); Register reg1 = as_Register($src1$$reg); Register reg2 = as_Register($src2$$reg); __ cmpw(reg1, reg2); %} enc_class aarch64_enc_cmpw_imm_addsub(iRegI src1, immIAddSub src2) %{ C2_MacroAssembler _masm(&cbuf); Register reg = as_Register($src1$$reg); int32_t val = $src2$$constant; if (val >= 0) { __ subsw(zr, reg, val); } else { __ addsw(zr, reg, -val); } %} enc_class aarch64_enc_cmpw_imm(iRegI src1, immI src2) %{ C2_MacroAssembler _masm(&cbuf); Register reg1 = as_Register($src1$$reg); uint32_t val = (uint32_t)$src2$$constant; __ movw(rscratch1, val); __ cmpw(reg1, rscratch1); %} enc_class aarch64_enc_cmp(iRegL src1, iRegL src2) %{ C2_MacroAssembler _masm(&cbuf); Register reg1 = as_Register($src1$$reg); Register reg2 = as_Register($src2$$reg); __ cmp(reg1, reg2); %} enc_class aarch64_enc_cmp_imm_addsub(iRegL src1, immL12 src2) %{ C2_MacroAssembler _masm(&cbuf); Register reg = as_Register($src1$$reg); int64_t val = $src2$$constant; if (val >= 0) { __ subs(zr, reg, val); } else if (val != -val) { __ adds(zr, reg, -val); } else { // aargh, Long.MIN_VALUE is a special case __ orr(rscratch1, zr, (uint64_t)val); __ subs(zr, reg, rscratch1); } %} enc_class aarch64_enc_cmp_imm(iRegL src1, immL src2) %{ C2_MacroAssembler _masm(&cbuf); Register reg1 = as_Register($src1$$reg); uint64_t val = (uint64_t)$src2$$constant; __ mov(rscratch1, val); __ cmp(reg1, rscratch1); %} enc_class aarch64_enc_cmpp(iRegP src1, iRegP src2) %{ C2_MacroAssembler _masm(&cbuf); Register reg1 = as_Register($src1$$reg); Register reg2 = as_Register($src2$$reg); __ cmp(reg1, reg2); %} enc_class aarch64_enc_cmpn(iRegN src1, iRegN src2) %{ C2_MacroAssembler _masm(&cbuf); Register reg1 = as_Register($src1$$reg); Register reg2 = as_Register($src2$$reg); __ cmpw(reg1, reg2); %} enc_class aarch64_enc_testp(iRegP src) %{ C2_MacroAssembler _masm(&cbuf); Register reg = as_Register($src$$reg); __ cmp(reg, zr); %} enc_class aarch64_enc_testn(iRegN src) %{ C2_MacroAssembler _masm(&cbuf); Register reg = as_Register($src$$reg); __ cmpw(reg, zr); %} enc_class aarch64_enc_b(label lbl) %{ C2_MacroAssembler _masm(&cbuf); Label *L = $lbl$$label; __ b(*L); %} enc_class aarch64_enc_br_con(cmpOp cmp, label lbl) %{ C2_MacroAssembler _masm(&cbuf); Label *L = $lbl$$label; __ br ((Assembler::Condition)$cmp$$cmpcode, *L); %} enc_class aarch64_enc_br_conU(cmpOpU cmp, label lbl) %{ C2_MacroAssembler _masm(&cbuf); Label *L = $lbl$$label; __ br ((Assembler::Condition)$cmp$$cmpcode, *L); %} enc_class aarch64_enc_partial_subtype_check(iRegP sub, iRegP super, iRegP temp, iRegP result) %{ Register sub_reg = as_Register($sub$$reg); Register super_reg = as_Register($super$$reg); Register temp_reg = as_Register($temp$$reg); Register result_reg = as_Register($result$$reg); Label miss; C2_MacroAssembler _masm(&cbuf); __ check_klass_subtype_slow_path(sub_reg, super_reg, temp_reg, result_reg, NULL, &miss, /*set_cond_codes:*/ true); if ($primary) { __ mov(result_reg, zr); } __ bind(miss); %} enc_class aarch64_enc_java_static_call(method meth) %{ C2_MacroAssembler _masm(&cbuf); address addr = (address)$meth$$method; address call; if (!_method) { // A call to a runtime wrapper, e.g. new, new_typeArray_Java, uncommon_trap. call = __ trampoline_call(Address(addr, relocInfo::runtime_call_type), &cbuf); if (call == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } } 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); call = __ trampoline_call(Address(addr, rspec), &cbuf); if (call == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } // Emit stub for static call address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); if (stub == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } } // Only non uncommon_trap calls need to reinitialize ptrue. if (Compile::current()->max_vector_size() >= 16 && uncommon_trap_request() == 0) { __ reinitialize_ptrue(); } %} enc_class aarch64_enc_java_dynamic_call(method meth) %{ C2_MacroAssembler _masm(&cbuf); int method_index = resolved_method_index(cbuf); address call = __ ic_call((address)$meth$$method, method_index); if (call == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } else if (Compile::current()->max_vector_size() >= 16) { __ reinitialize_ptrue(); } %} enc_class aarch64_enc_call_epilog() %{ C2_MacroAssembler _masm(&cbuf); if (VerifyStackAtCalls) { // Check that stack depth is unchanged: find majik cookie on stack __ call_Unimplemented(); } %} enc_class aarch64_enc_java_to_runtime(method meth) %{ C2_MacroAssembler _masm(&cbuf); // some calls to generated routines (arraycopy code) are scheduled // by C2 as runtime calls. if so we can call them using a br (they // will be in a reachable segment) otherwise we have to use a blr // which loads the absolute address into a register. address entry = (address)$meth$$method; CodeBlob *cb = CodeCache::find_blob(entry); if (cb) { address call = __ trampoline_call(Address(entry, relocInfo::runtime_call_type)); if (call == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } } else { Label retaddr; __ adr(rscratch2, retaddr); __ lea(rscratch1, RuntimeAddress(entry)); // Leave a breadcrumb for JavaFrameAnchor::capture_last_Java_pc() __ stp(zr, rscratch2, Address(__ pre(sp, -2 * wordSize))); __ blr(rscratch1); __ bind(retaddr); __ add(sp, sp, 2 * wordSize); } if (Compile::current()->max_vector_size() >= 16) { __ reinitialize_ptrue(); } %} enc_class aarch64_enc_rethrow() %{ C2_MacroAssembler _masm(&cbuf); __ far_jump(RuntimeAddress(OptoRuntime::rethrow_stub())); %} enc_class aarch64_enc_ret() %{ C2_MacroAssembler _masm(&cbuf); #ifdef ASSERT if (Compile::current()->max_vector_size() >= 16) { __ verify_ptrue(); } #endif __ ret(lr); %} enc_class aarch64_enc_tail_call(iRegP jump_target) %{ C2_MacroAssembler _masm(&cbuf); Register target_reg = as_Register($jump_target$$reg); __ br(target_reg); %} enc_class aarch64_enc_tail_jmp(iRegP jump_target) %{ C2_MacroAssembler _masm(&cbuf); Register target_reg = as_Register($jump_target$$reg); // exception oop should be in r0 // ret addr has been popped into lr // callee expects it in r3 __ mov(r3, lr); __ br(target_reg); %} enc_class aarch64_enc_fast_lock(iRegP object, iRegP box, iRegP tmp, iRegP tmp2) %{ C2_MacroAssembler _masm(&cbuf); Register oop = as_Register($object$$reg); Register box = as_Register($box$$reg); Register disp_hdr = as_Register($tmp$$reg); Register tmp = as_Register($tmp2$$reg); Label cont; Label object_has_monitor; Label cas_failed; assert_different_registers(oop, box, tmp, disp_hdr); // Load markWord from object into displaced_header. __ ldr(disp_hdr, Address(oop, oopDesc::mark_offset_in_bytes())); if (DiagnoseSyncOnValueBasedClasses != 0) { __ load_klass(tmp, oop); __ ldrw(tmp, Address(tmp, Klass::access_flags_offset())); __ tstw(tmp, JVM_ACC_IS_VALUE_BASED_CLASS); __ br(Assembler::NE, cont); } if (UseBiasedLocking && !UseOptoBiasInlining) { __ biased_locking_enter(box, oop, disp_hdr, tmp, true, cont); } // Check for existing monitor __ tbnz(disp_hdr, exact_log2(markWord::monitor_value), object_has_monitor); if (LockingMode == LM_MONITOR) { __ tst(oop, oop); // Set NE to indicate 'failure' -> take slow-path. We know that oop != 0. __ b(cont); } else if (LockingMode == LM_LEGACY) { // Set tmp to be (markWord of object | UNLOCK_VALUE). __ orr(tmp, disp_hdr, markWord::unlocked_value); // Initialize the box. (Must happen before we update the object mark!) __ str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); // Compare object markWord with an unlocked value (tmp) and if // equal exchange the stack address of our box with object markWord. // On failure disp_hdr contains the possibly locked markWord. __ cmpxchg(oop, tmp, box, Assembler::xword, /*acquire*/ true, /*release*/ true, /*weak*/ false, disp_hdr); __ br(Assembler::EQ, cont); assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); // If the compare-and-exchange succeeded, then we found an unlocked // object, will have now locked it will continue at label cont __ bind(cas_failed); // We did not see an unlocked object so try the fast recursive case. // Check if the owner is self by comparing the value in the // markWord of object (disp_hdr) with the stack pointer. __ mov(rscratch1, sp); __ sub(disp_hdr, disp_hdr, rscratch1); __ mov(tmp, (address) (~(os::vm_page_size()-1) | markWord::lock_mask_in_place)); // If condition is true we are cont and hence we can store 0 as the // displaced header in the box, which indicates that it is a recursive lock. __ ands(tmp/*==0?*/, disp_hdr, tmp); // Sets flags for result __ str(tmp/*==0, perhaps*/, Address(box, BasicLock::displaced_header_offset_in_bytes())); __ b(cont); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); __ fast_lock(oop, disp_hdr, tmp, rscratch1, cont); __ b(cont); } // Handle existing monitor. __ bind(object_has_monitor); // The object's monitor m is unlocked iff m->owner == NULL, // otherwise m->owner may contain a thread or a stack address. // // Try to CAS m->owner from NULL to current thread. __ add(tmp, disp_hdr, (ObjectMonitor::owner_offset_in_bytes()-markWord::monitor_value)); __ cmpxchg(tmp, zr, rthread, Assembler::xword, /*acquire*/ true, /*release*/ true, /*weak*/ false, rscratch1); // Sets flags for result if (LockingMode != LM_LIGHTWEIGHT) { // Store a non-null value into the box to avoid looking like a re-entrant // lock. The fast-path monitor unlock code checks for // markWord::monitor_value so use markWord::unused_mark which has the // relevant bit set, and also matches ObjectSynchronizer::enter. __ mov(tmp, (address)markWord::unused_mark().value()); __ str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); } __ br(Assembler::EQ, cont); // CAS success means locking succeeded __ cmp(rscratch1, rthread); __ br(Assembler::NE, cont); // Check for recursive locking // Recursive lock case __ increment(Address(disp_hdr, ObjectMonitor::recursions_offset_in_bytes() - markWord::monitor_value), 1); // flag == EQ still from the cmp above, checking if this is a reentrant lock __ bind(cont); // flag == EQ indicates success // flag == NE indicates failure %} enc_class aarch64_enc_fast_unlock(iRegP object, iRegP box, iRegP tmp, iRegP tmp2) %{ C2_MacroAssembler _masm(&cbuf); Register oop = as_Register($object$$reg); Register box = as_Register($box$$reg); Register disp_hdr = as_Register($tmp$$reg); Register tmp = as_Register($tmp2$$reg); Label cont; Label object_has_monitor; assert_different_registers(oop, box, tmp, disp_hdr); if (UseBiasedLocking && !UseOptoBiasInlining) { __ biased_locking_exit(oop, tmp, cont); } if (LockingMode == LM_LEGACY) { // Find the lock address and load the displaced header from the stack. __ ldr(disp_hdr, Address(box, BasicLock::displaced_header_offset_in_bytes())); // If the displaced header is 0, we have a recursive unlock. __ cmp(disp_hdr, zr); __ br(Assembler::EQ, cont); } // Handle existing monitor. __ ldr(tmp, Address(oop, oopDesc::mark_offset_in_bytes())); __ tbnz(tmp, exact_log2(markWord::monitor_value), object_has_monitor); if (LockingMode == LM_MONITOR) { __ tst(oop, oop); // Set NE to indicate 'failure' -> take slow-path. We know that oop != 0. __ b(cont); } else if (LockingMode == LM_LEGACY) { // Check if it is still a light weight lock, this is is true if we // see the stack address of the basicLock in the markWord of the // object. __ cmpxchg(oop, box, disp_hdr, Assembler::xword, /*acquire*/ false, /*release*/ true, /*weak*/ false, tmp); __ b(cont); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); __ fast_unlock(oop, tmp, box, disp_hdr, cont); __ b(cont); } assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); // Handle existing monitor. __ bind(object_has_monitor); STATIC_ASSERT(markWord::monitor_value <= INT_MAX); __ add(tmp, tmp, -(int)markWord::monitor_value); // monitor if (LockingMode == LM_LIGHTWEIGHT) { // If the owner is anonymous, we need to fix it -- in an outline stub. Register tmp2 = disp_hdr; __ ldr(tmp2, Address(tmp, ObjectMonitor::owner_offset_in_bytes())); // We cannot use tbnz here, the target might be too far away and cannot // be encoded. __ tst(tmp2, (uint64_t)ObjectMonitor::ANONYMOUS_OWNER); C2HandleAnonOMOwnerStub* stub = new (Compile::current()->comp_arena()) C2HandleAnonOMOwnerStub(tmp, tmp2); Compile::current()->output()->add_stub(stub); __ br(Assembler::NE, stub->entry()); __ bind(stub->continuation()); } __ ldr(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset_in_bytes())); Label notRecursive; __ cbz(disp_hdr, notRecursive); // Recursive lock __ sub(disp_hdr, disp_hdr, 1u); __ str(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset_in_bytes())); __ cmp(disp_hdr, disp_hdr); // Sets flags for result __ b(cont); __ bind(notRecursive); __ ldr(rscratch1, Address(tmp, ObjectMonitor::EntryList_offset_in_bytes())); __ ldr(disp_hdr, Address(tmp, ObjectMonitor::cxq_offset_in_bytes())); __ orr(rscratch1, rscratch1, disp_hdr); // Will be 0 if both are 0. __ cmp(rscratch1, zr); // Sets flags for result __ cbnz(rscratch1, cont); // need a release store here __ lea(tmp, Address(tmp, ObjectMonitor::owner_offset_in_bytes())); __ stlr(zr, tmp); // set unowned __ bind(cont); // flag == EQ indicates success // flag == NE indicates failure %} %} //----------FRAME-------------------------------------------------------------- // Definition of frame structure and management information. // // S T A C K L A Y O U T Allocators stack-slot number // | (to get allocators register number // G Owned by | | v add OptoReg::stack0()) // r CALLER | | // o | +--------+ pad to even-align allocators stack-slot // w V | pad0 | numbers; owned by CALLER // t -----------+--------+----> Matcher::_in_arg_limit, unaligned // h ^ | in | 5 // | | args | 4 Holes in incoming args owned by SELF // | | | | 3 // | | +--------+ // V | | old out| Empty on Intel, window on Sparc // | old |preserve| Must be even aligned. // | SP-+--------+----> Matcher::_old_SP, even 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 // | +--------+----> OptoReg::stack0(), even 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; // (the latter is true on Intel but is it false on AArch64?) // 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. // Note 4: For I2C adapters, the incoming FP may not meet the minimum stack // alignment. Region 11, pad1, may be dynamically extended so that // SP meets the minimum alignment. frame %{ // These three registers define part of the calling convention // between compiled code and the interpreter. // Inline Cache Register or Method for I2C. inline_cache_reg(R12); // Number of stack slots consumed by locking an object sync_stack_slots(2); // Compiled code's Frame Pointer frame_pointer(R31); // Interpreter stores its frame pointer in a register which is // stored to the stack by I2CAdaptors. // I2CAdaptors convert from interpreted java to compiled java. interpreter_frame_pointer(R29); // Stack alignment requirement stack_alignment(StackAlignmentInBytes); // Alignment size in bytes (128-bit -> 16 bytes) // 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. varargs_C_out_slots_killed(frame::arg_reg_save_area_bytes/BytesPerInt); // 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 // TODO this may well be correct but need to check why that - 2 is there // ppc port uses 0 but we definitely need to allow for fixed_slots // which folds in the space used for monitors return_addr(STACK - 2 + align_up((Compile::current()->in_preserve_stack_slots() + Compile::current()->fixed_slots()), stack_alignment_in_slots())); // Location of compiled Java return values. Same as C for now. return_value %{ // TODO do we allow ideal_reg == Op_RegN??? assert(ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values"); static const int lo[Op_RegL + 1] = { // enum name 0, // Op_Node 0, // Op_Set R0_num, // Op_RegN R0_num, // Op_RegI R0_num, // Op_RegP V0_num, // Op_RegF V0_num, // Op_RegD R0_num // Op_RegL }; static const int hi[Op_RegL + 1] = { // enum name 0, // Op_Node 0, // Op_Set OptoReg::Bad, // Op_RegN OptoReg::Bad, // Op_RegI R0_H_num, // Op_RegP OptoReg::Bad, // Op_RegF V0_H_num, // Op_RegD R0_H_num // Op_RegL }; return OptoRegPair(hi[ideal_reg], lo[ideal_reg]); %} %} //----------ATTRIBUTES--------------------------------------------------------- //----------Operand Attributes------------------------------------------------- op_attrib op_cost(1); // Required cost attribute //----------Instruction Attributes--------------------------------------------- ins_attrib ins_cost(INSN_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? ins_attrib ins_alignment(4); // Required alignment attribute (must // be a power of 2) specifies the // alignment that some part of the // instruction (not necessarily the // start) requires. If > 1, a // compute_padding() function must be // provided for the instruction //----------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---------------------------------------------------- // Integer operands 32 bit // 32 bit immediate operand immI() %{ match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // 32 bit zero operand immI0() %{ predicate(n->get_int() == 0); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // 32 bit unit increment operand immI_1() %{ predicate(n->get_int() == 1); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // 32 bit unit decrement operand immI_M1() %{ predicate(n->get_int() == -1); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Shift values for add/sub extension shift operand immIExt() %{ predicate(0 <= n->get_int() && (n->get_int() <= 4)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_le_4() %{ predicate(n->get_int() <= 4); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_31() %{ predicate(n->get_int() == 31); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_2() %{ predicate(n->get_int() == 2); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_4() %{ predicate(n->get_int() == 4); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_8() %{ predicate(n->get_int() == 8); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_16() %{ predicate(n->get_int() == 16); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_24() %{ predicate(n->get_int() == 24); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_32() %{ predicate(n->get_int() == 32); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_48() %{ predicate(n->get_int() == 48); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_56() %{ predicate(n->get_int() == 56); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_63() %{ predicate(n->get_int() == 63); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_64() %{ predicate(n->get_int() == 64); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_255() %{ predicate(n->get_int() == 255); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_65535() %{ predicate(n->get_int() == 65535); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_positive() %{ predicate(n->get_int() > 0); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immL_255() %{ predicate(n->get_long() == 255L); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immL_65535() %{ predicate(n->get_long() == 65535L); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immL_4294967295() %{ predicate(n->get_long() == 4294967295L); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immL_bitmask() %{ predicate((n->get_long() != 0) && ((n->get_long() & 0xc000000000000000l) == 0) && is_power_of_2(n->get_long() + 1)); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immI_bitmask() %{ predicate((n->get_int() != 0) && ((n->get_int() & 0xc0000000) == 0) && is_power_of_2(n->get_int() + 1)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immL_positive_bitmaskI() %{ predicate((n->get_long() != 0) && ((julong)n->get_long() < 0x80000000ULL) && is_power_of_2(n->get_long() + 1)); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // Scale values for scaled offset addressing modes (up to long but not quad) operand immIScale() %{ predicate(0 <= n->get_int() && (n->get_int() <= 3)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // 26 bit signed offset -- for pc-relative branches operand immI26() %{ predicate(((-(1 << 25)) <= n->get_int()) && (n->get_int() < (1 << 25))); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // 19 bit signed offset -- for pc-relative loads operand immI19() %{ predicate(((-(1 << 18)) <= n->get_int()) && (n->get_int() < (1 << 18))); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // 12 bit unsigned offset -- for base plus immediate loads operand immIU12() %{ predicate((0 <= n->get_int()) && (n->get_int() < (1 << 12))); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immLU12() %{ predicate((0 <= n->get_long()) && (n->get_long() < (1 << 12))); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // Offset for scaled or unscaled immediate loads and stores operand immIOffset() %{ predicate(Address::offset_ok_for_immed(n->get_int(), 0)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immIOffset1() %{ predicate(Address::offset_ok_for_immed(n->get_int(), 0)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immIOffset2() %{ predicate(Address::offset_ok_for_immed(n->get_int(), 1)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immIOffset4() %{ predicate(Address::offset_ok_for_immed(n->get_int(), 2)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immIOffset8() %{ predicate(Address::offset_ok_for_immed(n->get_int(), 3)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immIOffset16() %{ predicate(Address::offset_ok_for_immed(n->get_int(), 4)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immLoffset() %{ predicate(Address::offset_ok_for_immed(n->get_long(), 0)); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immLoffset1() %{ predicate(Address::offset_ok_for_immed(n->get_long(), 0)); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immLoffset2() %{ predicate(Address::offset_ok_for_immed(n->get_long(), 1)); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immLoffset4() %{ predicate(Address::offset_ok_for_immed(n->get_long(), 2)); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immLoffset8() %{ predicate(Address::offset_ok_for_immed(n->get_long(), 3)); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immLoffset16() %{ predicate(Address::offset_ok_for_immed(n->get_long(), 4)); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // 8 bit signed value. operand immI8() %{ predicate(n->get_int() <= 127 && n->get_int() >= -128); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // 8 bit signed value (simm8), or #simm8 LSL 8. operand immI8_shift8() %{ predicate((n->get_int() <= 127 && n->get_int() >= -128) || (n->get_int() <= 32512 && n->get_int() >= -32768 && (n->get_int() & 0xff) == 0)); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // 8 bit signed value (simm8), or #simm8 LSL 8. operand immL8_shift8() %{ predicate((n->get_long() <= 127 && n->get_long() >= -128) || (n->get_long() <= 32512 && n->get_long() >= -32768 && (n->get_long() & 0xff) == 0)); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // 32 bit integer valid for add sub immediate operand immIAddSub() %{ predicate(Assembler::operand_valid_for_add_sub_immediate((int64_t)n->get_int())); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // 32 bit unsigned integer valid for logical immediate // TODO -- check this is right when e.g the mask is 0x80000000 operand immILog() %{ predicate(Assembler::operand_valid_for_logical_immediate(/*is32*/true, (uint64_t)n->get_int())); match(ConI); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer operands 64 bit // 64 bit immediate operand immL() %{ match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // 64 bit zero operand immL0() %{ predicate(n->get_long() == 0); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // 64 bit unit increment operand immL_1() %{ predicate(n->get_long() == 1); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // 64 bit unit decrement operand immL_M1() %{ predicate(n->get_long() == -1); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // 32 bit offset of pc in thread anchor operand immL_pc_off() %{ predicate(n->get_long() == in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::last_Java_pc_offset())); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // 64 bit integer valid for add sub immediate operand immLAddSub() %{ predicate(Assembler::operand_valid_for_add_sub_immediate(n->get_long())); match(ConL); op_cost(0); format %{ %} interface(CONST_INTER); %} // 64 bit integer valid for logical immediate operand immLLog() %{ predicate(Assembler::operand_valid_for_logical_immediate(/*is32*/false, (uint64_t)n->get_long())); 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); %} // Pointer operands // Pointer Immediate operand immP() %{ match(ConP); op_cost(0); format %{ %} interface(CONST_INTER); %} // NULL Pointer Immediate operand immP0() %{ predicate(n->get_ptr() == 0); match(ConP); op_cost(0); format %{ %} interface(CONST_INTER); %} // Pointer Immediate One // this is used in object initialization (initial object header) operand immP_1() %{ predicate(n->get_ptr() == 1); match(ConP); op_cost(0); format %{ %} interface(CONST_INTER); %} // Card Table Byte Map Base operand immByteMapBase() %{ // Get base of card map predicate(BarrierSet::barrier_set()->is_a(BarrierSet::CardTableBarrierSet) && (CardTable::CardValue*)n->get_ptr() == ((CardTableBarrierSet*)(BarrierSet::barrier_set()))->card_table()->byte_map_base()); match(ConP); op_cost(0); format %{ %} interface(CONST_INTER); %} // Pointer Immediate Minus One // this is used when we want to write the current PC to the thread anchor operand immP_M1() %{ predicate(n->get_ptr() == -1); match(ConP); op_cost(0); format %{ %} interface(CONST_INTER); %} // Pointer Immediate Minus Two // this is used when we want to write the current PC to the thread anchor operand immP_M2() %{ predicate(n->get_ptr() == -2); match(ConP); op_cost(0); format %{ %} interface(CONST_INTER); %} // Float and Double operands // Double Immediate operand immD() %{ match(ConD); op_cost(0); 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); %} // constant 'double +0.0'. operand immDPacked() %{ predicate(Assembler::operand_valid_for_float_immediate(n->getd())); match(ConD); op_cost(0); format %{ %} interface(CONST_INTER); %} // Float Immediate operand immF() %{ match(ConF); op_cost(0); 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); %} // operand immFPacked() %{ predicate(Assembler::operand_valid_for_float_immediate((double)n->getf())); match(ConF); op_cost(0); format %{ %} interface(CONST_INTER); %} // Narrow pointer operands // Narrow Pointer Immediate operand immN() %{ match(ConN); op_cost(0); format %{ %} interface(CONST_INTER); %} // Narrow NULL Pointer Immediate operand immN0() %{ predicate(n->get_narrowcon() == 0); match(ConN); op_cost(0); format %{ %} interface(CONST_INTER); %} operand immNKlass() %{ match(ConNKlass); op_cost(0); format %{ %} interface(CONST_INTER); %} // Integer 32 bit Register Operands // Integer 32 bitRegister (excludes SP) operand iRegI() %{ constraint(ALLOC_IN_RC(any_reg32)); match(RegI); match(iRegINoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Integer 32 bit Register not Special operand iRegINoSp() %{ constraint(ALLOC_IN_RC(no_special_reg32)); match(RegI); op_cost(0); format %{ %} interface(REG_INTER); %} // Integer 64 bit Register Operands // Integer 64 bit Register (includes SP) operand iRegL() %{ constraint(ALLOC_IN_RC(any_reg)); match(RegL); match(iRegLNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Integer 64 bit Register not Special operand iRegLNoSp() %{ constraint(ALLOC_IN_RC(no_special_reg)); match(RegL); match(iRegL_R0); format %{ %} interface(REG_INTER); %} // Pointer Register Operands // Pointer Register operand iRegP() %{ constraint(ALLOC_IN_RC(ptr_reg)); match(RegP); match(iRegPNoSp); match(iRegP_R0); //match(iRegP_R2); //match(iRegP_R4); match(iRegP_R5); match(thread_RegP); op_cost(0); format %{ %} interface(REG_INTER); %} // Pointer 64 bit Register not Special operand iRegPNoSp() %{ constraint(ALLOC_IN_RC(no_special_ptr_reg)); match(RegP); // match(iRegP); // match(iRegP_R0); // match(iRegP_R2); // match(iRegP_R4); // match(iRegP_R5); // match(thread_RegP); op_cost(0); format %{ %} interface(REG_INTER); %} // Pointer 64 bit Register R0 only operand iRegP_R0() %{ constraint(ALLOC_IN_RC(r0_reg)); match(RegP); // match(iRegP); match(iRegPNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Pointer 64 bit Register R1 only operand iRegP_R1() %{ constraint(ALLOC_IN_RC(r1_reg)); match(RegP); // match(iRegP); match(iRegPNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Pointer 64 bit Register R2 only operand iRegP_R2() %{ constraint(ALLOC_IN_RC(r2_reg)); match(RegP); // match(iRegP); match(iRegPNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Pointer 64 bit Register R3 only operand iRegP_R3() %{ constraint(ALLOC_IN_RC(r3_reg)); match(RegP); // match(iRegP); match(iRegPNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Pointer 64 bit Register R4 only operand iRegP_R4() %{ constraint(ALLOC_IN_RC(r4_reg)); match(RegP); // match(iRegP); match(iRegPNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Pointer 64 bit Register R5 only operand iRegP_R5() %{ constraint(ALLOC_IN_RC(r5_reg)); match(RegP); // match(iRegP); match(iRegPNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Pointer 64 bit Register R10 only operand iRegP_R10() %{ constraint(ALLOC_IN_RC(r10_reg)); match(RegP); // match(iRegP); match(iRegPNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Long 64 bit Register R0 only operand iRegL_R0() %{ constraint(ALLOC_IN_RC(r0_reg)); match(RegL); match(iRegLNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Long 64 bit Register R2 only operand iRegL_R2() %{ constraint(ALLOC_IN_RC(r2_reg)); match(RegL); match(iRegLNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Long 64 bit Register R3 only operand iRegL_R3() %{ constraint(ALLOC_IN_RC(r3_reg)); match(RegL); match(iRegLNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Long 64 bit Register R11 only operand iRegL_R11() %{ constraint(ALLOC_IN_RC(r11_reg)); match(RegL); match(iRegLNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Pointer 64 bit Register FP only operand iRegP_FP() %{ constraint(ALLOC_IN_RC(fp_reg)); match(RegP); // match(iRegP); op_cost(0); format %{ %} interface(REG_INTER); %} // Register R0 only operand iRegI_R0() %{ constraint(ALLOC_IN_RC(int_r0_reg)); match(RegI); match(iRegINoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Register R2 only operand iRegI_R2() %{ constraint(ALLOC_IN_RC(int_r2_reg)); match(RegI); match(iRegINoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Register R3 only operand iRegI_R3() %{ constraint(ALLOC_IN_RC(int_r3_reg)); match(RegI); match(iRegINoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Register R4 only operand iRegI_R4() %{ constraint(ALLOC_IN_RC(int_r4_reg)); match(RegI); match(iRegINoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Pointer Register Operands // Narrow Pointer Register operand iRegN() %{ constraint(ALLOC_IN_RC(any_reg32)); match(RegN); match(iRegNNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} operand iRegN_R0() %{ constraint(ALLOC_IN_RC(r0_reg)); match(iRegN); op_cost(0); format %{ %} interface(REG_INTER); %} operand iRegN_R2() %{ constraint(ALLOC_IN_RC(r2_reg)); match(iRegN); op_cost(0); format %{ %} interface(REG_INTER); %} operand iRegN_R3() %{ constraint(ALLOC_IN_RC(r3_reg)); match(iRegN); op_cost(0); format %{ %} interface(REG_INTER); %} // Integer 64 bit Register not Special operand iRegNNoSp() %{ constraint(ALLOC_IN_RC(no_special_reg32)); match(RegN); op_cost(0); format %{ %} interface(REG_INTER); %} // heap base register -- used for encoding immN0 operand iRegIHeapbase() %{ constraint(ALLOC_IN_RC(heapbase_reg)); match(RegI); op_cost(0); format %{ %} interface(REG_INTER); %} // Float Register // Float register operands operand vRegF() %{ constraint(ALLOC_IN_RC(float_reg)); match(RegF); op_cost(0); format %{ %} interface(REG_INTER); %} // Double Register // Double register operands operand vRegD() %{ constraint(ALLOC_IN_RC(double_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} // Generic vector class. This will be used for // all vector operands, including NEON and SVE, // but currently only used for SVE VecA. operand vReg() %{ constraint(ALLOC_IN_RC(vectora_reg)); match(VecA); op_cost(0); format %{ %} interface(REG_INTER); %} operand vecD() %{ constraint(ALLOC_IN_RC(vectord_reg)); match(VecD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vecX() %{ constraint(ALLOC_IN_RC(vectorx_reg)); match(VecX); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V0() %{ constraint(ALLOC_IN_RC(v0_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V1() %{ constraint(ALLOC_IN_RC(v1_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V2() %{ constraint(ALLOC_IN_RC(v2_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V3() %{ constraint(ALLOC_IN_RC(v3_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V4() %{ constraint(ALLOC_IN_RC(v4_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V5() %{ constraint(ALLOC_IN_RC(v5_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V6() %{ constraint(ALLOC_IN_RC(v6_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V7() %{ constraint(ALLOC_IN_RC(v7_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V8() %{ constraint(ALLOC_IN_RC(v8_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V9() %{ constraint(ALLOC_IN_RC(v9_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V10() %{ constraint(ALLOC_IN_RC(v10_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V11() %{ constraint(ALLOC_IN_RC(v11_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V12() %{ constraint(ALLOC_IN_RC(v12_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V13() %{ constraint(ALLOC_IN_RC(v13_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V14() %{ constraint(ALLOC_IN_RC(v14_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V15() %{ constraint(ALLOC_IN_RC(v15_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V16() %{ constraint(ALLOC_IN_RC(v16_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V17() %{ constraint(ALLOC_IN_RC(v17_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V18() %{ constraint(ALLOC_IN_RC(v18_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V19() %{ constraint(ALLOC_IN_RC(v19_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V20() %{ constraint(ALLOC_IN_RC(v20_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V21() %{ constraint(ALLOC_IN_RC(v21_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V22() %{ constraint(ALLOC_IN_RC(v22_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V23() %{ constraint(ALLOC_IN_RC(v23_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V24() %{ constraint(ALLOC_IN_RC(v24_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V25() %{ constraint(ALLOC_IN_RC(v25_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V26() %{ constraint(ALLOC_IN_RC(v26_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V27() %{ constraint(ALLOC_IN_RC(v27_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V28() %{ constraint(ALLOC_IN_RC(v28_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V29() %{ constraint(ALLOC_IN_RC(v29_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V30() %{ constraint(ALLOC_IN_RC(v30_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand vRegD_V31() %{ constraint(ALLOC_IN_RC(v31_reg)); match(RegD); op_cost(0); format %{ %} interface(REG_INTER); %} operand pRegGov() %{ constraint(ALLOC_IN_RC(gov_pr)); match(RegVectMask); op_cost(0); format %{ %} interface(REG_INTER); %} // Flags register, used as output of signed compare instructions // note that on AArch64 we also use this register as the output for // for floating point compare instructions (CmpF CmpD). this ensures // that ordered inequality tests use GT, GE, LT or LE none of which // pass through cases where the result is unordered i.e. one or both // inputs to the compare is a NaN. this means that the ideal code can // replace e.g. a GT with an LE and not end up capturing the NaN case // (where the comparison should always fail). EQ and NE tests are // always generated in ideal code so that unordered folds into the NE // case, matching the behaviour of AArch64 NE. // // This differs from x86 where the outputs of FP compares use a // special FP flags registers and where compares based on this // register are distinguished into ordered inequalities (cmpOpUCF) and // EQ/NEQ tests (cmpOpUCF2). x86 has to special case the latter tests // to explicitly handle the unordered case in branches. x86 also has // to include extra CMoveX rules to accept a cmpOpUCF input. operand rFlagsReg() %{ constraint(ALLOC_IN_RC(int_flags)); match(RegFlags); op_cost(0); format %{ "RFLAGS" %} interface(REG_INTER); %} // Flags register, used as output of unsigned compare instructions operand rFlagsRegU() %{ constraint(ALLOC_IN_RC(int_flags)); match(RegFlags); op_cost(0); format %{ "RFLAGSU" %} interface(REG_INTER); %} // Special Registers // Method Register operand inline_cache_RegP(iRegP reg) %{ constraint(ALLOC_IN_RC(method_reg)); // inline_cache_reg match(reg); match(iRegPNoSp); op_cost(0); format %{ %} interface(REG_INTER); %} // Thread Register operand thread_RegP(iRegP reg) %{ constraint(ALLOC_IN_RC(thread_reg)); // link_reg match(reg); op_cost(0); format %{ %} interface(REG_INTER); %} operand lr_RegP(iRegP reg) %{ constraint(ALLOC_IN_RC(lr_reg)); // link_reg match(reg); op_cost(0); format %{ %} interface(REG_INTER); %} //----------Memory Operands---------------------------------------------------- operand indirect(iRegP reg) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(reg); op_cost(0); format %{ "[$reg]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp(0x0); %} %} operand indIndexScaledI2L(iRegP reg, iRegI ireg, immIScale scale) %{ constraint(ALLOC_IN_RC(ptr_reg)); predicate(size_fits_all_mem_uses(n->as_AddP(), n->in(AddPNode::Offset)->in(2)->get_int())); match(AddP reg (LShiftL (ConvI2L ireg) scale)); op_cost(0); format %{ "$reg, $ireg sxtw($scale), 0, I2L" %} interface(MEMORY_INTER) %{ base($reg); index($ireg); scale($scale); disp(0x0); %} %} operand indIndexScaled(iRegP reg, iRegL lreg, immIScale scale) %{ constraint(ALLOC_IN_RC(ptr_reg)); predicate(size_fits_all_mem_uses(n->as_AddP(), n->in(AddPNode::Offset)->in(2)->get_int())); match(AddP reg (LShiftL lreg scale)); op_cost(0); format %{ "$reg, $lreg lsl($scale)" %} interface(MEMORY_INTER) %{ base($reg); index($lreg); scale($scale); disp(0x0); %} %} operand indIndexI2L(iRegP reg, iRegI ireg) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg (ConvI2L ireg)); op_cost(0); format %{ "$reg, $ireg, 0, I2L" %} interface(MEMORY_INTER) %{ base($reg); index($ireg); scale(0x0); disp(0x0); %} %} operand indIndex(iRegP reg, iRegL lreg) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg lreg); op_cost(0); format %{ "$reg, $lreg" %} interface(MEMORY_INTER) %{ base($reg); index($lreg); scale(0x0); disp(0x0); %} %} operand indOffI(iRegP reg, immIOffset off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffI1(iRegP reg, immIOffset1 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffI2(iRegP reg, immIOffset2 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffI4(iRegP reg, immIOffset4 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffI8(iRegP reg, immIOffset8 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffI16(iRegP reg, immIOffset16 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffL(iRegP reg, immLoffset off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffL1(iRegP reg, immLoffset1 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffL2(iRegP reg, immLoffset2 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffL4(iRegP reg, immLoffset4 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffL8(iRegP reg, immLoffset8 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffL16(iRegP reg, immLoffset16 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indirectN(iRegN reg) %{ predicate(CompressedOops::shift() == 0); constraint(ALLOC_IN_RC(ptr_reg)); match(DecodeN reg); op_cost(0); format %{ "[$reg]\t# narrow" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp(0x0); %} %} operand indIndexScaledI2LN(iRegN reg, iRegI ireg, immIScale scale) %{ predicate(CompressedOops::shift() == 0 && size_fits_all_mem_uses(n->as_AddP(), n->in(AddPNode::Offset)->in(2)->get_int())); constraint(ALLOC_IN_RC(ptr_reg)); match(AddP (DecodeN reg) (LShiftL (ConvI2L ireg) scale)); op_cost(0); format %{ "$reg, $ireg sxtw($scale), 0, I2L\t# narrow" %} interface(MEMORY_INTER) %{ base($reg); index($ireg); scale($scale); disp(0x0); %} %} operand indIndexScaledN(iRegN reg, iRegL lreg, immIScale scale) %{ predicate(CompressedOops::shift() == 0 && size_fits_all_mem_uses(n->as_AddP(), n->in(AddPNode::Offset)->in(2)->get_int())); constraint(ALLOC_IN_RC(ptr_reg)); match(AddP (DecodeN reg) (LShiftL lreg scale)); op_cost(0); format %{ "$reg, $lreg lsl($scale)\t# narrow" %} interface(MEMORY_INTER) %{ base($reg); index($lreg); scale($scale); disp(0x0); %} %} operand indIndexI2LN(iRegN reg, iRegI ireg) %{ predicate(CompressedOops::shift() == 0); constraint(ALLOC_IN_RC(ptr_reg)); match(AddP (DecodeN reg) (ConvI2L ireg)); op_cost(0); format %{ "$reg, $ireg, 0, I2L\t# narrow" %} interface(MEMORY_INTER) %{ base($reg); index($ireg); scale(0x0); disp(0x0); %} %} operand indIndexN(iRegN reg, iRegL lreg) %{ predicate(CompressedOops::shift() == 0); constraint(ALLOC_IN_RC(ptr_reg)); match(AddP (DecodeN reg) lreg); op_cost(0); format %{ "$reg, $lreg\t# narrow" %} interface(MEMORY_INTER) %{ base($reg); index($lreg); scale(0x0); disp(0x0); %} %} operand indOffIN(iRegN reg, immIOffset off) %{ predicate(CompressedOops::shift() == 0); constraint(ALLOC_IN_RC(ptr_reg)); match(AddP (DecodeN reg) off); op_cost(0); format %{ "[$reg, $off]\t# narrow" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} operand indOffLN(iRegN reg, immLoffset off) %{ predicate(CompressedOops::shift() == 0); constraint(ALLOC_IN_RC(ptr_reg)); match(AddP (DecodeN reg) off); op_cost(0); format %{ "[$reg, $off]\t# narrow" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} // AArch64 opto stubs need to write to the pc slot in the thread anchor operand thread_anchor_pc(thread_RegP reg, immL_pc_off off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); index(0xffffffff); scale(0x0); disp($off); %} %} //----------Special Memory Operands-------------------------------------------- // Stack Slot Operand - This operand is used for loading and storing temporary // values on the stack where a match requires a value to // flow through memory. operand stackSlotP(sRegP reg) %{ constraint(ALLOC_IN_RC(stack_slots)); op_cost(100); // No match rule because this operand is only generated in matching // match(RegP); format %{ "[$reg]" %} interface(MEMORY_INTER) %{ base(0x1e); // RSP index(0x0); // No Index scale(0x0); // No Scale disp($reg); // Stack Offset %} %} operand stackSlotI(sRegI reg) %{ constraint(ALLOC_IN_RC(stack_slots)); // No match rule because this operand is only generated in matching // match(RegI); format %{ "[$reg]" %} interface(MEMORY_INTER) %{ base(0x1e); // RSP index(0x0); // No Index scale(0x0); // No Scale disp($reg); // Stack Offset %} %} operand stackSlotF(sRegF reg) %{ constraint(ALLOC_IN_RC(stack_slots)); // No match rule because this operand is only generated in matching // match(RegF); format %{ "[$reg]" %} interface(MEMORY_INTER) %{ base(0x1e); // RSP index(0x0); // No Index scale(0x0); // No Scale disp($reg); // Stack Offset %} %} operand stackSlotD(sRegD reg) %{ constraint(ALLOC_IN_RC(stack_slots)); // No match rule because this operand is only generated in matching // match(RegD); format %{ "[$reg]" %} interface(MEMORY_INTER) %{ base(0x1e); // RSP index(0x0); // No Index scale(0x0); // No Scale disp($reg); // Stack Offset %} %} operand stackSlotL(sRegL reg) %{ constraint(ALLOC_IN_RC(stack_slots)); // No match rule because this operand is only generated in matching // match(RegL); format %{ "[$reg]" %} interface(MEMORY_INTER) %{ base(0x1e); // RSP index(0x0); // No Index scale(0x0); // No Scale disp($reg); // Stack Offset %} %} // 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. // used for signed integral comparisons and fp comparisons operand cmpOp() %{ match(Bool); format %{ "" %} interface(COND_INTER) %{ equal(0x0, "eq"); not_equal(0x1, "ne"); less(0xb, "lt"); greater_equal(0xa, "ge"); less_equal(0xd, "le"); greater(0xc, "gt"); overflow(0x6, "vs"); no_overflow(0x7, "vc"); %} %} // used for unsigned integral comparisons operand cmpOpU() %{ match(Bool); format %{ "" %} interface(COND_INTER) %{ equal(0x0, "eq"); not_equal(0x1, "ne"); less(0x3, "lo"); greater_equal(0x2, "hs"); less_equal(0x9, "ls"); greater(0x8, "hi"); overflow(0x6, "vs"); no_overflow(0x7, "vc"); %} %} // used for certain integral comparisons which can be // converted to cbxx or tbxx instructions operand cmpOpEqNe() %{ match(Bool); op_cost(0); predicate(n->as_Bool()->_test._test == BoolTest::ne || n->as_Bool()->_test._test == BoolTest::eq); format %{ "" %} interface(COND_INTER) %{ equal(0x0, "eq"); not_equal(0x1, "ne"); less(0xb, "lt"); greater_equal(0xa, "ge"); less_equal(0xd, "le"); greater(0xc, "gt"); overflow(0x6, "vs"); no_overflow(0x7, "vc"); %} %} // used for certain integral comparisons which can be // converted to cbxx or tbxx instructions operand cmpOpLtGe() %{ match(Bool); op_cost(0); predicate(n->as_Bool()->_test._test == BoolTest::lt || n->as_Bool()->_test._test == BoolTest::ge); format %{ "" %} interface(COND_INTER) %{ equal(0x0, "eq"); not_equal(0x1, "ne"); less(0xb, "lt"); greater_equal(0xa, "ge"); less_equal(0xd, "le"); greater(0xc, "gt"); overflow(0x6, "vs"); no_overflow(0x7, "vc"); %} %} // used for certain unsigned integral comparisons which can be // converted to cbxx or tbxx instructions operand cmpOpUEqNeLtGe() %{ match(Bool); op_cost(0); predicate(n->as_Bool()->_test._test == BoolTest::eq || n->as_Bool()->_test._test == BoolTest::ne || n->as_Bool()->_test._test == BoolTest::lt || n->as_Bool()->_test._test == BoolTest::ge); format %{ "" %} interface(COND_INTER) %{ equal(0x0, "eq"); not_equal(0x1, "ne"); less(0xb, "lt"); greater_equal(0xa, "ge"); less_equal(0xd, "le"); greater(0xc, "gt"); overflow(0x6, "vs"); no_overflow(0x7, "vc"); %} %} // Special operand allowing long args to int ops to be truncated for free operand iRegL2I(iRegL reg) %{ op_cost(0); match(ConvL2I reg); format %{ "l2i($reg)" %} interface(REG_INTER) %} opclass vmem2(indirect, indIndex, indOffI2, indOffL2); opclass vmem4(indirect, indIndex, indOffI4, indOffL4); opclass vmem8(indirect, indIndex, indOffI8, indOffL8); opclass vmem16(indirect, indIndex, indOffI16, indOffL16); //----------OPERAND CLASSES---------------------------------------------------- // Operand Classes are groups of operands that are used as 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. // memory is used to define read/write location for load/store // instruction defs. we can turn a memory op into an Address opclass memory1(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI1, indOffL1, indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN); opclass memory2(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI2, indOffL2, indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN); opclass memory4(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI4, indOffL4, indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN); opclass memory8(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI8, indOffL8, indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN); // All of the memory operands. For the pipeline description. opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI1, indOffL1, indOffI2, indOffL2, indOffI4, indOffL4, indOffI8, indOffL8, indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN); // iRegIorL2I is used for src inputs in rules for 32 bit int (I) // operations. it allows the src to be either an iRegI or a (ConvL2I // iRegL). in the latter case the l2i normally planted for a ConvL2I // can be elided because the 32-bit instruction will just employ the // lower 32 bits anyway. // // n.b. this does not elide all L2I conversions. if the truncated // value is consumed by more than one operation then the ConvL2I // cannot be bundled into the consuming nodes so an l2i gets planted // (actually a movw $dst $src) and the downstream instructions consume // the result of the l2i as an iRegI input. That's a shame since the // movw is actually redundant but its not too costly. opclass iRegIorL2I(iRegI, iRegL2I); //----------PIPELINE----------------------------------------------------------- // Rules which define the behavior of the target architectures pipeline. // For specific pipelines, eg A53, define the stages of that pipeline //pipe_desc(ISS, EX1, EX2, WR); #define ISS S0 #define EX1 S1 #define EX2 S2 #define WR S3 // Integer ALU reg operation pipeline %{ attributes %{ // ARM instructions are of fixed length fixed_size_instructions; // Fixed size instructions TODO does max_instructions_per_bundle = 4; // A53 = 2, A57 = 4 // ARM instructions come in 32-bit word units instruction_unit_size = 4; // An instruction is 4 bytes long instruction_fetch_unit_size = 64; // The processor fetches one line instruction_fetch_units = 1; // of 64 bytes // List of nop instructions nops( MachNop ); %} // We don't use an actual pipeline model so don't care about resources // or description. we do use pipeline classes to introduce fixed // latencies //----------RESOURCES---------------------------------------------------------- // Resources are the functional units available to the machine resources( INS0, INS1, INS01 = INS0 | INS1, ALU0, ALU1, ALU = ALU0 | ALU1, MAC, DIV, BRANCH, LDST, NEON_FP); //----------PIPELINE DESCRIPTION----------------------------------------------- // Pipeline Description specifies the stages in the machine's pipeline // Define the pipeline as a generic 6 stage pipeline pipe_desc(S0, S1, S2, S3, S4, S5); //----------PIPELINE CLASSES--------------------------------------------------- // Pipeline Classes describe the stages in which input and output are // referenced by the hardware pipeline. pipe_class fp_dop_reg_reg_s(vRegF dst, vRegF src1, vRegF src2) %{ single_instruction; src1 : S1(read); src2 : S2(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_dop_reg_reg_d(vRegD dst, vRegD src1, vRegD src2) %{ single_instruction; src1 : S1(read); src2 : S2(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_uop_s(vRegF dst, vRegF src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_uop_d(vRegD dst, vRegD src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_d2f(vRegF dst, vRegD src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_f2d(vRegD dst, vRegF src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_f2i(iRegINoSp dst, vRegF src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_f2l(iRegLNoSp dst, vRegF src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_i2f(vRegF dst, iRegIorL2I src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_l2f(vRegF dst, iRegL src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_d2i(iRegINoSp dst, vRegD src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_d2l(iRegLNoSp dst, vRegD src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_i2d(vRegD dst, iRegIorL2I src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_l2d(vRegD dst, iRegIorL2I src) %{ single_instruction; src : S1(read); dst : S5(write); INS01 : ISS; NEON_FP : S5; %} pipe_class fp_div_s(vRegF dst, vRegF src1, vRegF src2) %{ single_instruction; src1 : S1(read); src2 : S2(read); dst : S5(write); INS0 : ISS; NEON_FP : S5; %} pipe_class fp_div_d(vRegD dst, vRegD src1, vRegD src2) %{ single_instruction; src1 : S1(read); src2 : S2(read); dst : S5(write); INS0 : ISS; NEON_FP : S5; %} pipe_class fp_cond_reg_reg_s(vRegF dst, vRegF src1, vRegF src2, rFlagsReg cr) %{ single_instruction; cr : S1(read); src1 : S1(read); src2 : S1(read); dst : S3(write); INS01 : ISS; NEON_FP : S3; %} pipe_class fp_cond_reg_reg_d(vRegD dst, vRegD src1, vRegD src2, rFlagsReg cr) %{ single_instruction; cr : S1(read); src1 : S1(read); src2 : S1(read); dst : S3(write); INS01 : ISS; NEON_FP : S3; %} pipe_class fp_imm_s(vRegF dst) %{ single_instruction; dst : S3(write); INS01 : ISS; NEON_FP : S3; %} pipe_class fp_imm_d(vRegD dst) %{ single_instruction; dst : S3(write); INS01 : ISS; NEON_FP : S3; %} pipe_class fp_load_constant_s(vRegF dst) %{ single_instruction; dst : S4(write); INS01 : ISS; NEON_FP : S4; %} pipe_class fp_load_constant_d(vRegD dst) %{ single_instruction; dst : S4(write); INS01 : ISS; NEON_FP : S4; %} pipe_class vmul64(vecD dst, vecD src1, vecD src2) %{ single_instruction; dst : S5(write); src1 : S1(read); src2 : S1(read); INS01 : ISS; NEON_FP : S5; %} pipe_class vmul128(vecX dst, vecX src1, vecX src2) %{ single_instruction; dst : S5(write); src1 : S1(read); src2 : S1(read); INS0 : ISS; NEON_FP : S5; %} pipe_class vmla64(vecD dst, vecD src1, vecD src2) %{ single_instruction; dst : S5(write); src1 : S1(read); src2 : S1(read); dst : S1(read); INS01 : ISS; NEON_FP : S5; %} pipe_class vmla128(vecX dst, vecX src1, vecX src2) %{ single_instruction; dst : S5(write); src1 : S1(read); src2 : S1(read); dst : S1(read); INS0 : ISS; NEON_FP : S5; %} pipe_class vdop64(vecD dst, vecD src1, vecD src2) %{ single_instruction; dst : S4(write); src1 : S2(read); src2 : S2(read); INS01 : ISS; NEON_FP : S4; %} pipe_class vdop128(vecX dst, vecX src1, vecX src2) %{ single_instruction; dst : S4(write); src1 : S2(read); src2 : S2(read); INS0 : ISS; NEON_FP : S4; %} pipe_class vlogical64(vecD dst, vecD src1, vecD src2) %{ single_instruction; dst : S3(write); src1 : S2(read); src2 : S2(read); INS01 : ISS; NEON_FP : S3; %} pipe_class vlogical128(vecX dst, vecX src1, vecX src2) %{ single_instruction; dst : S3(write); src1 : S2(read); src2 : S2(read); INS0 : ISS; NEON_FP : S3; %} pipe_class vshift64(vecD dst, vecD src, vecX shift) %{ single_instruction; dst : S3(write); src : S1(read); shift : S1(read); INS01 : ISS; NEON_FP : S3; %} pipe_class vshift128(vecX dst, vecX src, vecX shift) %{ single_instruction; dst : S3(write); src : S1(read); shift : S1(read); INS0 : ISS; NEON_FP : S3; %} pipe_class vshift64_imm(vecD dst, vecD src, immI shift) %{ single_instruction; dst : S3(write); src : S1(read); INS01 : ISS; NEON_FP : S3; %} pipe_class vshift128_imm(vecX dst, vecX src, immI shift) %{ single_instruction; dst : S3(write); src : S1(read); INS0 : ISS; NEON_FP : S3; %} pipe_class vdop_fp64(vecD dst, vecD src1, vecD src2) %{ single_instruction; dst : S5(write); src1 : S1(read); src2 : S1(read); INS01 : ISS; NEON_FP : S5; %} pipe_class vdop_fp128(vecX dst, vecX src1, vecX src2) %{ single_instruction; dst : S5(write); src1 : S1(read); src2 : S1(read); INS0 : ISS; NEON_FP : S5; %} pipe_class vmuldiv_fp64(vecD dst, vecD src1, vecD src2) %{ single_instruction; dst : S5(write); src1 : S1(read); src2 : S1(read); INS0 : ISS; NEON_FP : S5; %} pipe_class vmuldiv_fp128(vecX dst, vecX src1, vecX src2) %{ single_instruction; dst : S5(write); src1 : S1(read); src2 : S1(read); INS0 : ISS; NEON_FP : S5; %} pipe_class vsqrt_fp128(vecX dst, vecX src) %{ single_instruction; dst : S5(write); src : S1(read); INS0 : ISS; NEON_FP : S5; %} pipe_class vunop_fp64(vecD dst, vecD src) %{ single_instruction; dst : S5(write); src : S1(read); INS01 : ISS; NEON_FP : S5; %} pipe_class vunop_fp128(vecX dst, vecX src) %{ single_instruction; dst : S5(write); src : S1(read); INS0 : ISS; NEON_FP : S5; %} pipe_class vdup_reg_reg64(vecD dst, iRegI src) %{ single_instruction; dst : S3(write); src : S1(read); INS01 : ISS; NEON_FP : S3; %} pipe_class vdup_reg_reg128(vecX dst, iRegI src) %{ single_instruction; dst : S3(write); src : S1(read); INS01 : ISS; NEON_FP : S3; %} pipe_class vdup_reg_freg64(vecD dst, vRegF src) %{ single_instruction; dst : S3(write); src : S1(read); INS01 : ISS; NEON_FP : S3; %} pipe_class vdup_reg_freg128(vecX dst, vRegF src) %{ single_instruction; dst : S3(write); src : S1(read); INS01 : ISS; NEON_FP : S3; %} pipe_class vdup_reg_dreg128(vecX dst, vRegD src) %{ single_instruction; dst : S3(write); src : S1(read); INS01 : ISS; NEON_FP : S3; %} pipe_class vmovi_reg_imm64(vecD dst) %{ single_instruction; dst : S3(write); INS01 : ISS; NEON_FP : S3; %} pipe_class vmovi_reg_imm128(vecX dst) %{ single_instruction; dst : S3(write); INS0 : ISS; NEON_FP : S3; %} pipe_class vload_reg_mem64(vecD dst, vmem8 mem) %{ single_instruction; dst : S5(write); mem : ISS(read); INS01 : ISS; NEON_FP : S3; %} pipe_class vload_reg_mem128(vecX dst, vmem16 mem) %{ single_instruction; dst : S5(write); mem : ISS(read); INS01 : ISS; NEON_FP : S3; %} pipe_class vstore_reg_mem64(vecD src, vmem8 mem) %{ single_instruction; mem : ISS(read); src : S2(read); INS01 : ISS; NEON_FP : S3; %} pipe_class vstore_reg_mem128(vecD src, vmem16 mem) %{ single_instruction; mem : ISS(read); src : S2(read); INS01 : ISS; NEON_FP : S3; %} //------- Integer ALU operations -------------------------- // Integer ALU reg-reg operation // Operands needed in EX1, result generated in EX2 // Eg. ADD x0, x1, x2 pipe_class ialu_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ single_instruction; dst : EX2(write); src1 : EX1(read); src2 : EX1(read); INS01 : ISS; // Dual issue as instruction 0 or 1 ALU : EX2; %} // Integer ALU reg-reg operation with constant shift // Shifted register must be available in LATE_ISS instead of EX1 // Eg. ADD x0, x1, x2, LSL #2 pipe_class ialu_reg_reg_shift(iRegI dst, iRegI src1, iRegI src2, immI shift) %{ single_instruction; dst : EX2(write); src1 : EX1(read); src2 : ISS(read); INS01 : ISS; ALU : EX2; %} // Integer ALU reg operation with constant shift // Eg. LSL x0, x1, #shift pipe_class ialu_reg_shift(iRegI dst, iRegI src1) %{ single_instruction; dst : EX2(write); src1 : ISS(read); INS01 : ISS; ALU : EX2; %} // Integer ALU reg-reg operation with variable shift // Both operands must be available in LATE_ISS instead of EX1 // Result is available in EX1 instead of EX2 // Eg. LSLV x0, x1, x2 pipe_class ialu_reg_reg_vshift(iRegI dst, iRegI src1, iRegI src2) %{ single_instruction; dst : EX1(write); src1 : ISS(read); src2 : ISS(read); INS01 : ISS; ALU : EX1; %} // Integer ALU reg-reg operation with extract // As for _vshift above, but result generated in EX2 // Eg. EXTR x0, x1, x2, #N pipe_class ialu_reg_reg_extr(iRegI dst, iRegI src1, iRegI src2) %{ single_instruction; dst : EX2(write); src1 : ISS(read); src2 : ISS(read); INS1 : ISS; // Can only dual issue as Instruction 1 ALU : EX1; %} // Integer ALU reg operation // Eg. NEG x0, x1 pipe_class ialu_reg(iRegI dst, iRegI src) %{ single_instruction; dst : EX2(write); src : EX1(read); INS01 : ISS; ALU : EX2; %} // Integer ALU reg mmediate operation // Eg. ADD x0, x1, #N pipe_class ialu_reg_imm(iRegI dst, iRegI src1) %{ single_instruction; dst : EX2(write); src1 : EX1(read); INS01 : ISS; ALU : EX2; %} // Integer ALU immediate operation (no source operands) // Eg. MOV x0, #N pipe_class ialu_imm(iRegI dst) %{ single_instruction; dst : EX1(write); INS01 : ISS; ALU : EX1; %} //------- Compare operation ------------------------------- // Compare reg-reg // Eg. CMP x0, x1 pipe_class icmp_reg_reg(rFlagsReg cr, iRegI op1, iRegI op2) %{ single_instruction; // fixed_latency(16); cr : EX2(write); op1 : EX1(read); op2 : EX1(read); INS01 : ISS; ALU : EX2; %} // Compare reg-reg // Eg. CMP x0, #N pipe_class icmp_reg_imm(rFlagsReg cr, iRegI op1) %{ single_instruction; // fixed_latency(16); cr : EX2(write); op1 : EX1(read); INS01 : ISS; ALU : EX2; %} //------- Conditional instructions ------------------------ // Conditional no operands // Eg. CSINC x0, zr, zr, pipe_class icond_none(iRegI dst, rFlagsReg cr) %{ single_instruction; cr : EX1(read); dst : EX2(write); INS01 : ISS; ALU : EX2; %} // Conditional 2 operand // EG. CSEL X0, X1, X2, pipe_class icond_reg_reg(iRegI dst, iRegI src1, iRegI src2, rFlagsReg cr) %{ single_instruction; cr : EX1(read); src1 : EX1(read); src2 : EX1(read); dst : EX2(write); INS01 : ISS; ALU : EX2; %} // Conditional 2 operand // EG. CSEL X0, X1, X2, pipe_class icond_reg(iRegI dst, iRegI src, rFlagsReg cr) %{ single_instruction; cr : EX1(read); src : EX1(read); dst : EX2(write); INS01 : ISS; ALU : EX2; %} //------- Multiply pipeline operations -------------------- // Multiply reg-reg // Eg. MUL w0, w1, w2 pipe_class imul_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ single_instruction; dst : WR(write); src1 : ISS(read); src2 : ISS(read); INS01 : ISS; MAC : WR; %} // Multiply accumulate // Eg. MADD w0, w1, w2, w3 pipe_class imac_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{ single_instruction; dst : WR(write); src1 : ISS(read); src2 : ISS(read); src3 : ISS(read); INS01 : ISS; MAC : WR; %} // Eg. MUL w0, w1, w2 pipe_class lmul_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ single_instruction; fixed_latency(3); // Maximum latency for 64 bit mul dst : WR(write); src1 : ISS(read); src2 : ISS(read); INS01 : ISS; MAC : WR; %} // Multiply accumulate // Eg. MADD w0, w1, w2, w3 pipe_class lmac_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{ single_instruction; fixed_latency(3); // Maximum latency for 64 bit mul dst : WR(write); src1 : ISS(read); src2 : ISS(read); src3 : ISS(read); INS01 : ISS; MAC : WR; %} //------- Divide pipeline operations -------------------- // Eg. SDIV w0, w1, w2 pipe_class idiv_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ single_instruction; fixed_latency(8); // Maximum latency for 32 bit divide dst : WR(write); src1 : ISS(read); src2 : ISS(read); INS0 : ISS; // Can only dual issue as instruction 0 DIV : WR; %} // Eg. SDIV x0, x1, x2 pipe_class ldiv_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ single_instruction; fixed_latency(16); // Maximum latency for 64 bit divide dst : WR(write); src1 : ISS(read); src2 : ISS(read); INS0 : ISS; // Can only dual issue as instruction 0 DIV : WR; %} //------- Load pipeline operations ------------------------ // Load - prefetch // Eg. PFRM pipe_class iload_prefetch(memory mem) %{ single_instruction; mem : ISS(read); INS01 : ISS; LDST : WR; %} // Load - reg, mem // Eg. LDR x0, pipe_class iload_reg_mem(iRegI dst, memory mem) %{ single_instruction; dst : WR(write); mem : ISS(read); INS01 : ISS; LDST : WR; %} // Load - reg, reg // Eg. LDR x0, [sp, x1] pipe_class iload_reg_reg(iRegI dst, iRegI src) %{ single_instruction; dst : WR(write); src : ISS(read); INS01 : ISS; LDST : WR; %} //------- Store pipeline operations ----------------------- // Store - zr, mem // Eg. STR zr, pipe_class istore_mem(memory mem) %{ single_instruction; mem : ISS(read); INS01 : ISS; LDST : WR; %} // Store - reg, mem // Eg. STR x0, pipe_class istore_reg_mem(iRegI src, memory mem) %{ single_instruction; mem : ISS(read); src : EX2(read); INS01 : ISS; LDST : WR; %} // Store - reg, reg // Eg. STR x0, [sp, x1] pipe_class istore_reg_reg(iRegI dst, iRegI src) %{ single_instruction; dst : ISS(read); src : EX2(read); INS01 : ISS; LDST : WR; %} //------- Store pipeline operations ----------------------- // Branch pipe_class pipe_branch() %{ single_instruction; INS01 : ISS; BRANCH : EX1; %} // Conditional branch pipe_class pipe_branch_cond(rFlagsReg cr) %{ single_instruction; cr : EX1(read); INS01 : ISS; BRANCH : EX1; %} // Compare & Branch // EG. CBZ/CBNZ pipe_class pipe_cmp_branch(iRegI op1) %{ single_instruction; op1 : EX1(read); INS01 : ISS; BRANCH : EX1; %} //------- Synchronisation operations ---------------------- // Any operation requiring serialization. // EG. DMB/Atomic Ops/Load Acquire/Str Release pipe_class pipe_serial() %{ single_instruction; force_serialization; fixed_latency(16); INS01 : ISS(2); // Cannot dual issue with any other instruction LDST : WR; %} // Generic big/slow expanded idiom - also serialized pipe_class pipe_slow() %{ instruction_count(10); multiple_bundles; force_serialization; fixed_latency(16); INS01 : ISS(2); // Cannot dual issue with any other instruction LDST : WR; %} // Empty pipeline class pipe_class pipe_class_empty() %{ single_instruction; fixed_latency(0); %} // Default pipeline class. pipe_class pipe_class_default() %{ single_instruction; fixed_latency(2); %} // Pipeline class for compares. pipe_class pipe_class_compare() %{ single_instruction; fixed_latency(16); %} // Pipeline class for memory operations. pipe_class pipe_class_memory() %{ single_instruction; fixed_latency(16); %} // Pipeline class for call. pipe_class pipe_class_call() %{ single_instruction; fixed_latency(100); %} // Define the class for the Nop node. define %{ MachNop = pipe_class_empty; %} %} //----------INSTRUCTIONS------------------------------------------------------- // // match -- States which machine-independent subtree may be replaced // by this instruction. // ins_cost -- The estimated cost of this instruction is used by instruction // selection to identify a minimum cost tree of machine // instructions that matches a tree of machine-independent // instructions. // format -- A string providing the disassembly for this instruction. // The value of an instruction's operand may be inserted // by referring to it with a '$' prefix. // opcode -- Three instruction opcodes may be provided. These are referred // to within an encode class as $primary, $secondary, and $tertiary // rrspectively. The primary opcode is commonly used to // indicate the type of machine instruction, while secondary // and tertiary are often used for prefix options or addressing // modes. // ins_encode -- A list of encode classes with parameters. The encode class // name must have been defined in an 'enc_class' specification // in the encode section of the architecture description. // ============================================================================ // Memory (Load/Store) Instructions // Load Instructions // Load Byte (8 bit signed) instruct loadB(iRegINoSp dst, memory1 mem) %{ match(Set dst (LoadB mem)); predicate(!needs_acquiring_load(n)); ins_cost(4 * INSN_COST); format %{ "ldrsbw $dst, $mem\t# byte" %} ins_encode(aarch64_enc_ldrsbw(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Byte (8 bit signed) into long instruct loadB2L(iRegLNoSp dst, memory1 mem) %{ match(Set dst (ConvI2L (LoadB mem))); predicate(!needs_acquiring_load(n->in(1))); ins_cost(4 * INSN_COST); format %{ "ldrsb $dst, $mem\t# byte" %} ins_encode(aarch64_enc_ldrsb(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Byte (8 bit unsigned) instruct loadUB(iRegINoSp dst, memory1 mem) %{ match(Set dst (LoadUB mem)); predicate(!needs_acquiring_load(n)); ins_cost(4 * INSN_COST); format %{ "ldrbw $dst, $mem\t# byte" %} ins_encode(aarch64_enc_ldrb(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Byte (8 bit unsigned) into long instruct loadUB2L(iRegLNoSp dst, memory1 mem) %{ match(Set dst (ConvI2L (LoadUB mem))); predicate(!needs_acquiring_load(n->in(1))); ins_cost(4 * INSN_COST); format %{ "ldrb $dst, $mem\t# byte" %} ins_encode(aarch64_enc_ldrb(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Short (16 bit signed) instruct loadS(iRegINoSp dst, memory2 mem) %{ match(Set dst (LoadS mem)); predicate(!needs_acquiring_load(n)); ins_cost(4 * INSN_COST); format %{ "ldrshw $dst, $mem\t# short" %} ins_encode(aarch64_enc_ldrshw(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Short (16 bit signed) into long instruct loadS2L(iRegLNoSp dst, memory2 mem) %{ match(Set dst (ConvI2L (LoadS mem))); predicate(!needs_acquiring_load(n->in(1))); ins_cost(4 * INSN_COST); format %{ "ldrsh $dst, $mem\t# short" %} ins_encode(aarch64_enc_ldrsh(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Char (16 bit unsigned) instruct loadUS(iRegINoSp dst, memory2 mem) %{ match(Set dst (LoadUS mem)); predicate(!needs_acquiring_load(n)); ins_cost(4 * INSN_COST); format %{ "ldrh $dst, $mem\t# short" %} ins_encode(aarch64_enc_ldrh(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Short/Char (16 bit unsigned) into long instruct loadUS2L(iRegLNoSp dst, memory2 mem) %{ match(Set dst (ConvI2L (LoadUS mem))); predicate(!needs_acquiring_load(n->in(1))); ins_cost(4 * INSN_COST); format %{ "ldrh $dst, $mem\t# short" %} ins_encode(aarch64_enc_ldrh(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Integer (32 bit signed) instruct loadI(iRegINoSp dst, memory4 mem) %{ match(Set dst (LoadI mem)); predicate(!needs_acquiring_load(n)); ins_cost(4 * INSN_COST); format %{ "ldrw $dst, $mem\t# int" %} ins_encode(aarch64_enc_ldrw(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Integer (32 bit signed) into long instruct loadI2L(iRegLNoSp dst, memory4 mem) %{ match(Set dst (ConvI2L (LoadI mem))); predicate(!needs_acquiring_load(n->in(1))); ins_cost(4 * INSN_COST); format %{ "ldrsw $dst, $mem\t# int" %} ins_encode(aarch64_enc_ldrsw(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Integer (32 bit unsigned) into long instruct loadUI2L(iRegLNoSp dst, memory4 mem, immL_32bits mask) %{ match(Set dst (AndL (ConvI2L (LoadI mem)) mask)); predicate(!needs_acquiring_load(n->in(1)->in(1)->as_Load())); ins_cost(4 * INSN_COST); format %{ "ldrw $dst, $mem\t# int" %} ins_encode(aarch64_enc_ldrw(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Long (64 bit signed) instruct loadL(iRegLNoSp dst, memory8 mem) %{ match(Set dst (LoadL mem)); predicate(!needs_acquiring_load(n)); ins_cost(4 * INSN_COST); format %{ "ldr $dst, $mem\t# int" %} ins_encode(aarch64_enc_ldr(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Range instruct loadRange(iRegINoSp dst, memory4 mem) %{ match(Set dst (LoadRange mem)); ins_cost(4 * INSN_COST); format %{ "ldrw $dst, $mem\t# range" %} ins_encode(aarch64_enc_ldrw(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Pointer instruct loadP(iRegPNoSp dst, memory8 mem) %{ match(Set dst (LoadP mem)); predicate(!needs_acquiring_load(n) && (n->as_Load()->barrier_data() == 0)); ins_cost(4 * INSN_COST); format %{ "ldr $dst, $mem\t# ptr" %} ins_encode(aarch64_enc_ldr(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Compressed Pointer instruct loadN(iRegNNoSp dst, memory4 mem) %{ match(Set dst (LoadN mem)); predicate(!needs_acquiring_load(n)); ins_cost(4 * INSN_COST); format %{ "ldrw $dst, $mem\t# compressed ptr" %} ins_encode(aarch64_enc_ldrw(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Klass Pointer instruct loadKlass(iRegPNoSp dst, memory8 mem) %{ match(Set dst (LoadKlass mem)); predicate(!needs_acquiring_load(n)); ins_cost(4 * INSN_COST); format %{ "ldr $dst, $mem\t# class" %} ins_encode(aarch64_enc_ldr(dst, mem)); ins_pipe(iload_reg_mem); %} // Load Narrow Klass Pointer instruct loadNKlass(iRegNNoSp dst, memory4 mem) %{ match(Set dst (LoadNKlass mem)); predicate(!needs_acquiring_load(n) && !UseCompactObjectHeaders); ins_cost(4 * INSN_COST); format %{ "ldrw $dst, $mem\t# compressed class ptr" %} ins_encode(aarch64_enc_ldrw(dst, mem)); ins_pipe(iload_reg_mem); %} instruct loadNKlassCompactHeaders(iRegNNoSp dst, memory4 mem, rFlagsReg cr) %{ match(Set dst (LoadNKlass mem)); effect(KILL cr); predicate(!needs_acquiring_load(n) && UseCompactObjectHeaders); ins_cost(4 * INSN_COST); format %{ "ldrw $dst, $mem\t# compressed class ptr" %} ins_encode %{ __ load_nklass_compact($dst$$Register, $mem$$base$$Register, $mem$$index$$Register, $mem$$scale, $mem$$disp); %} ins_pipe(pipe_slow); %} // Load Float instruct loadF(vRegF dst, memory4 mem) %{ match(Set dst (LoadF mem)); predicate(!needs_acquiring_load(n)); ins_cost(4 * INSN_COST); format %{ "ldrs $dst, $mem\t# float" %} ins_encode( aarch64_enc_ldrs(dst, mem) ); ins_pipe(pipe_class_memory); %} // Load Double instruct loadD(vRegD dst, memory8 mem) %{ match(Set dst (LoadD mem)); predicate(!needs_acquiring_load(n)); ins_cost(4 * INSN_COST); format %{ "ldrd $dst, $mem\t# double" %} ins_encode( aarch64_enc_ldrd(dst, mem) ); ins_pipe(pipe_class_memory); %} // Load Int Constant instruct loadConI(iRegINoSp dst, immI src) %{ match(Set dst src); ins_cost(INSN_COST); format %{ "mov $dst, $src\t# int" %} ins_encode( aarch64_enc_movw_imm(dst, src) ); ins_pipe(ialu_imm); %} // Load Long Constant instruct loadConL(iRegLNoSp dst, immL src) %{ match(Set dst src); ins_cost(INSN_COST); format %{ "mov $dst, $src\t# long" %} ins_encode( aarch64_enc_mov_imm(dst, src) ); ins_pipe(ialu_imm); %} // Load Pointer Constant instruct loadConP(iRegPNoSp dst, immP con) %{ match(Set dst con); ins_cost(INSN_COST * 4); format %{ "mov $dst, $con\t# ptr\n\t" %} ins_encode(aarch64_enc_mov_p(dst, con)); ins_pipe(ialu_imm); %} // Load Null Pointer Constant instruct loadConP0(iRegPNoSp dst, immP0 con) %{ match(Set dst con); ins_cost(INSN_COST); format %{ "mov $dst, $con\t# NULL ptr" %} ins_encode(aarch64_enc_mov_p0(dst, con)); ins_pipe(ialu_imm); %} // Load Pointer Constant One instruct loadConP1(iRegPNoSp dst, immP_1 con) %{ match(Set dst con); ins_cost(INSN_COST); format %{ "mov $dst, $con\t# NULL ptr" %} ins_encode(aarch64_enc_mov_p1(dst, con)); ins_pipe(ialu_imm); %} // Load Byte Map Base Constant instruct loadByteMapBase(iRegPNoSp dst, immByteMapBase con) %{ match(Set dst con); ins_cost(INSN_COST); format %{ "adr $dst, $con\t# Byte Map Base" %} ins_encode(aarch64_enc_mov_byte_map_base(dst, con)); ins_pipe(ialu_imm); %} // Load Narrow Pointer Constant instruct loadConN(iRegNNoSp dst, immN con) %{ match(Set dst con); ins_cost(INSN_COST * 4); format %{ "mov $dst, $con\t# compressed ptr" %} ins_encode(aarch64_enc_mov_n(dst, con)); ins_pipe(ialu_imm); %} // Load Narrow Null Pointer Constant instruct loadConN0(iRegNNoSp dst, immN0 con) %{ match(Set dst con); ins_cost(INSN_COST); format %{ "mov $dst, $con\t# compressed NULL ptr" %} ins_encode(aarch64_enc_mov_n0(dst, con)); ins_pipe(ialu_imm); %} // Load Narrow Klass Constant instruct loadConNKlass(iRegNNoSp dst, immNKlass con) %{ match(Set dst con); ins_cost(INSN_COST); format %{ "mov $dst, $con\t# compressed klass ptr" %} ins_encode(aarch64_enc_mov_nk(dst, con)); ins_pipe(ialu_imm); %} // Load Packed Float Constant instruct loadConF_packed(vRegF dst, immFPacked con) %{ match(Set dst con); ins_cost(INSN_COST * 4); format %{ "fmovs $dst, $con"%} ins_encode %{ __ fmovs(as_FloatRegister($dst$$reg), (double)$con$$constant); %} ins_pipe(fp_imm_s); %} // Load Float Constant instruct loadConF(vRegF dst, immF con) %{ match(Set dst con); ins_cost(INSN_COST * 4); format %{ "ldrs $dst, [$constantaddress]\t# load from constant table: float=$con\n\t" %} ins_encode %{ __ ldrs(as_FloatRegister($dst$$reg), $constantaddress($con)); %} ins_pipe(fp_load_constant_s); %} // Load Packed Double Constant instruct loadConD_packed(vRegD dst, immDPacked con) %{ match(Set dst con); ins_cost(INSN_COST); format %{ "fmovd $dst, $con"%} ins_encode %{ __ fmovd(as_FloatRegister($dst$$reg), $con$$constant); %} ins_pipe(fp_imm_d); %} // Load Double Constant instruct loadConD(vRegD dst, immD con) %{ match(Set dst con); ins_cost(INSN_COST * 5); format %{ "ldrd $dst, [$constantaddress]\t# load from constant table: float=$con\n\t" %} ins_encode %{ __ ldrd(as_FloatRegister($dst$$reg), $constantaddress($con)); %} ins_pipe(fp_load_constant_d); %} // Store Instructions // Store CMS card-mark Immediate instruct storeimmCM0(immI0 zero, memory1 mem) %{ match(Set mem (StoreCM mem zero)); ins_cost(INSN_COST); format %{ "storestore (elided)\n\t" "strb zr, $mem\t# byte" %} ins_encode(aarch64_enc_strb0(mem)); ins_pipe(istore_mem); %} // Store CMS card-mark Immediate with intervening StoreStore // needed when using CMS with no conditional card marking instruct storeimmCM0_ordered(immI0 zero, memory1 mem) %{ match(Set mem (StoreCM mem zero)); ins_cost(INSN_COST * 2); format %{ "storestore\n\t" "dmb ishst" "\n\tstrb zr, $mem\t# byte" %} ins_encode(aarch64_enc_strb0_ordered(mem)); ins_pipe(istore_mem); %} // Store Byte instruct storeB(iRegIorL2I src, memory1 mem) %{ match(Set mem (StoreB mem src)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "strb $src, $mem\t# byte" %} ins_encode(aarch64_enc_strb(src, mem)); ins_pipe(istore_reg_mem); %} instruct storeimmB0(immI0 zero, memory1 mem) %{ match(Set mem (StoreB mem zero)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "strb rscractch2, $mem\t# byte" %} ins_encode(aarch64_enc_strb0(mem)); ins_pipe(istore_mem); %} // Store Char/Short instruct storeC(iRegIorL2I src, memory2 mem) %{ match(Set mem (StoreC mem src)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "strh $src, $mem\t# short" %} ins_encode(aarch64_enc_strh(src, mem)); ins_pipe(istore_reg_mem); %} instruct storeimmC0(immI0 zero, memory2 mem) %{ match(Set mem (StoreC mem zero)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "strh zr, $mem\t# short" %} ins_encode(aarch64_enc_strh0(mem)); ins_pipe(istore_mem); %} // Store Integer instruct storeI(iRegIorL2I src, memory4 mem) %{ match(Set mem(StoreI mem src)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "strw $src, $mem\t# int" %} ins_encode(aarch64_enc_strw(src, mem)); ins_pipe(istore_reg_mem); %} instruct storeimmI0(immI0 zero, memory4 mem) %{ match(Set mem(StoreI mem zero)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "strw zr, $mem\t# int" %} ins_encode(aarch64_enc_strw0(mem)); ins_pipe(istore_mem); %} // Store Long (64 bit signed) instruct storeL(iRegL src, memory8 mem) %{ match(Set mem (StoreL mem src)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "str $src, $mem\t# int" %} ins_encode(aarch64_enc_str(src, mem)); ins_pipe(istore_reg_mem); %} // Store Long (64 bit signed) instruct storeimmL0(immL0 zero, memory8 mem) %{ match(Set mem (StoreL mem zero)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "str zr, $mem\t# int" %} ins_encode(aarch64_enc_str0(mem)); ins_pipe(istore_mem); %} // Store Pointer instruct storeP(iRegP src, memory8 mem) %{ match(Set mem (StoreP mem src)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "str $src, $mem\t# ptr" %} ins_encode(aarch64_enc_str(src, mem)); ins_pipe(istore_reg_mem); %} // Store Pointer instruct storeimmP0(immP0 zero, memory8 mem) %{ match(Set mem (StoreP mem zero)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "str zr, $mem\t# ptr" %} ins_encode(aarch64_enc_str0(mem)); ins_pipe(istore_mem); %} // Store Compressed Pointer instruct storeN(iRegN src, memory4 mem) %{ match(Set mem (StoreN mem src)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "strw $src, $mem\t# compressed ptr" %} ins_encode(aarch64_enc_strw(src, mem)); ins_pipe(istore_reg_mem); %} instruct storeImmN0(immN0 zero, memory4 mem) %{ match(Set mem (StoreN mem zero)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "strw zr, $mem\t# compressed ptr" %} ins_encode(aarch64_enc_strw0(mem)); ins_pipe(istore_mem); %} // Store Float instruct storeF(vRegF src, memory4 mem) %{ match(Set mem (StoreF mem src)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "strs $src, $mem\t# float" %} ins_encode( aarch64_enc_strs(src, mem) ); ins_pipe(pipe_class_memory); %} // TODO // implement storeImmF0 and storeFImmPacked // Store Double instruct storeD(vRegD src, memory8 mem) %{ match(Set mem (StoreD mem src)); predicate(!needs_releasing_store(n)); ins_cost(INSN_COST); format %{ "strd $src, $mem\t# double" %} ins_encode( aarch64_enc_strd(src, mem) ); ins_pipe(pipe_class_memory); %} // Store Compressed Klass Pointer instruct storeNKlass(iRegN src, memory4 mem) %{ predicate(!needs_releasing_store(n)); match(Set mem (StoreNKlass mem src)); ins_cost(INSN_COST); format %{ "strw $src, $mem\t# compressed klass ptr" %} ins_encode(aarch64_enc_strw(src, mem)); ins_pipe(istore_reg_mem); %} // TODO // implement storeImmD0 and storeDImmPacked // prefetch instructions // Must be safe to execute with invalid address (cannot fault). instruct prefetchalloc( memory8 mem ) %{ match(PrefetchAllocation mem); ins_cost(INSN_COST); format %{ "prfm $mem, PSTL1KEEP\t# Prefetch into level 1 cache write keep" %} ins_encode( aarch64_enc_prefetchw(mem) ); ins_pipe(iload_prefetch); %} // ---------------- volatile loads and stores ---------------- // Load Byte (8 bit signed) instruct loadB_volatile(iRegINoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadB mem)); ins_cost(VOLATILE_REF_COST); format %{ "ldarsb $dst, $mem\t# byte" %} ins_encode(aarch64_enc_ldarsb(dst, mem)); ins_pipe(pipe_serial); %} // Load Byte (8 bit signed) into long instruct loadB2L_volatile(iRegLNoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (ConvI2L (LoadB mem))); ins_cost(VOLATILE_REF_COST); format %{ "ldarsb $dst, $mem\t# byte" %} ins_encode(aarch64_enc_ldarsb(dst, mem)); ins_pipe(pipe_serial); %} // Load Byte (8 bit unsigned) instruct loadUB_volatile(iRegINoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadUB mem)); ins_cost(VOLATILE_REF_COST); format %{ "ldarb $dst, $mem\t# byte" %} ins_encode(aarch64_enc_ldarb(dst, mem)); ins_pipe(pipe_serial); %} // Load Byte (8 bit unsigned) into long instruct loadUB2L_volatile(iRegLNoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (ConvI2L (LoadUB mem))); ins_cost(VOLATILE_REF_COST); format %{ "ldarb $dst, $mem\t# byte" %} ins_encode(aarch64_enc_ldarb(dst, mem)); ins_pipe(pipe_serial); %} // Load Short (16 bit signed) instruct loadS_volatile(iRegINoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadS mem)); ins_cost(VOLATILE_REF_COST); format %{ "ldarshw $dst, $mem\t# short" %} ins_encode(aarch64_enc_ldarshw(dst, mem)); ins_pipe(pipe_serial); %} instruct loadUS_volatile(iRegINoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadUS mem)); ins_cost(VOLATILE_REF_COST); format %{ "ldarhw $dst, $mem\t# short" %} ins_encode(aarch64_enc_ldarhw(dst, mem)); ins_pipe(pipe_serial); %} // Load Short/Char (16 bit unsigned) into long instruct loadUS2L_volatile(iRegLNoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (ConvI2L (LoadUS mem))); ins_cost(VOLATILE_REF_COST); format %{ "ldarh $dst, $mem\t# short" %} ins_encode(aarch64_enc_ldarh(dst, mem)); ins_pipe(pipe_serial); %} // Load Short/Char (16 bit signed) into long instruct loadS2L_volatile(iRegLNoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (ConvI2L (LoadS mem))); ins_cost(VOLATILE_REF_COST); format %{ "ldarh $dst, $mem\t# short" %} ins_encode(aarch64_enc_ldarsh(dst, mem)); ins_pipe(pipe_serial); %} // Load Integer (32 bit signed) instruct loadI_volatile(iRegINoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadI mem)); ins_cost(VOLATILE_REF_COST); format %{ "ldarw $dst, $mem\t# int" %} ins_encode(aarch64_enc_ldarw(dst, mem)); ins_pipe(pipe_serial); %} // Load Integer (32 bit unsigned) into long instruct loadUI2L_volatile(iRegLNoSp dst, /* sync_memory*/indirect mem, immL_32bits mask) %{ match(Set dst (AndL (ConvI2L (LoadI mem)) mask)); ins_cost(VOLATILE_REF_COST); format %{ "ldarw $dst, $mem\t# int" %} ins_encode(aarch64_enc_ldarw(dst, mem)); ins_pipe(pipe_serial); %} // Load Long (64 bit signed) instruct loadL_volatile(iRegLNoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadL mem)); ins_cost(VOLATILE_REF_COST); format %{ "ldar $dst, $mem\t# int" %} ins_encode(aarch64_enc_ldar(dst, mem)); ins_pipe(pipe_serial); %} // Load Pointer instruct loadP_volatile(iRegPNoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadP mem)); predicate(n->as_Load()->barrier_data() == 0); ins_cost(VOLATILE_REF_COST); format %{ "ldar $dst, $mem\t# ptr" %} ins_encode(aarch64_enc_ldar(dst, mem)); ins_pipe(pipe_serial); %} // Load Compressed Pointer instruct loadN_volatile(iRegNNoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadN mem)); ins_cost(VOLATILE_REF_COST); format %{ "ldarw $dst, $mem\t# compressed ptr" %} ins_encode(aarch64_enc_ldarw(dst, mem)); ins_pipe(pipe_serial); %} // Load Float instruct loadF_volatile(vRegF dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadF mem)); ins_cost(VOLATILE_REF_COST); format %{ "ldars $dst, $mem\t# float" %} ins_encode( aarch64_enc_fldars(dst, mem) ); ins_pipe(pipe_serial); %} // Load Double instruct loadD_volatile(vRegD dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadD mem)); ins_cost(VOLATILE_REF_COST); format %{ "ldard $dst, $mem\t# double" %} ins_encode( aarch64_enc_fldard(dst, mem) ); ins_pipe(pipe_serial); %} // Store Byte instruct storeB_volatile(iRegIorL2I src, /* sync_memory*/indirect mem) %{ match(Set mem (StoreB mem src)); ins_cost(VOLATILE_REF_COST); format %{ "stlrb $src, $mem\t# byte" %} ins_encode(aarch64_enc_stlrb(src, mem)); ins_pipe(pipe_class_memory); %} instruct storeimmB0_volatile(immI0 zero, /* sync_memory*/indirect mem) %{ match(Set mem (StoreB mem zero)); ins_cost(VOLATILE_REF_COST); format %{ "stlrb zr, $mem\t# byte" %} ins_encode(aarch64_enc_stlrb0(mem)); ins_pipe(pipe_class_memory); %} // Store Char/Short instruct storeC_volatile(iRegIorL2I src, /* sync_memory*/indirect mem) %{ match(Set mem (StoreC mem src)); ins_cost(VOLATILE_REF_COST); format %{ "stlrh $src, $mem\t# short" %} ins_encode(aarch64_enc_stlrh(src, mem)); ins_pipe(pipe_class_memory); %} instruct storeimmC0_volatile(immI0 zero, /* sync_memory*/indirect mem) %{ match(Set mem (StoreC mem zero)); ins_cost(VOLATILE_REF_COST); format %{ "stlrh zr, $mem\t# short" %} ins_encode(aarch64_enc_stlrh0(mem)); ins_pipe(pipe_class_memory); %} // Store Integer instruct storeI_volatile(iRegIorL2I src, /* sync_memory*/indirect mem) %{ match(Set mem(StoreI mem src)); ins_cost(VOLATILE_REF_COST); format %{ "stlrw $src, $mem\t# int" %} ins_encode(aarch64_enc_stlrw(src, mem)); ins_pipe(pipe_class_memory); %} instruct storeimmI0_volatile(immI0 zero, /* sync_memory*/indirect mem) %{ match(Set mem(StoreI mem zero)); ins_cost(VOLATILE_REF_COST); format %{ "stlrw zr, $mem\t# int" %} ins_encode(aarch64_enc_stlrw0(mem)); ins_pipe(pipe_class_memory); %} // Store Long (64 bit signed) instruct storeL_volatile(iRegL src, /* sync_memory*/indirect mem) %{ match(Set mem (StoreL mem src)); ins_cost(VOLATILE_REF_COST); format %{ "stlr $src, $mem\t# int" %} ins_encode(aarch64_enc_stlr(src, mem)); ins_pipe(pipe_class_memory); %} instruct storeimmL0_volatile(immL0 zero, /* sync_memory*/indirect mem) %{ match(Set mem (StoreL mem zero)); ins_cost(VOLATILE_REF_COST); format %{ "stlr zr, $mem\t# int" %} ins_encode(aarch64_enc_stlr0(mem)); ins_pipe(pipe_class_memory); %} // Store Pointer instruct storeP_volatile(iRegP src, /* sync_memory*/indirect mem) %{ match(Set mem (StoreP mem src)); ins_cost(VOLATILE_REF_COST); format %{ "stlr $src, $mem\t# ptr" %} ins_encode(aarch64_enc_stlr(src, mem)); ins_pipe(pipe_class_memory); %} instruct storeimmP0_volatile(immP0 zero, /* sync_memory*/indirect mem) %{ match(Set mem (StoreP mem zero)); ins_cost(VOLATILE_REF_COST); format %{ "stlr zr, $mem\t# ptr" %} ins_encode(aarch64_enc_stlr0(mem)); ins_pipe(pipe_class_memory); %} // Store Compressed Pointer instruct storeN_volatile(iRegN src, /* sync_memory*/indirect mem) %{ match(Set mem (StoreN mem src)); ins_cost(VOLATILE_REF_COST); format %{ "stlrw $src, $mem\t# compressed ptr" %} ins_encode(aarch64_enc_stlrw(src, mem)); ins_pipe(pipe_class_memory); %} instruct storeimmN0_volatile(immN0 zero, /* sync_memory*/indirect mem) %{ match(Set mem (StoreN mem zero)); ins_cost(VOLATILE_REF_COST); format %{ "stlrw zr, $mem\t# compressed ptr" %} ins_encode(aarch64_enc_stlrw0(mem)); ins_pipe(pipe_class_memory); %} // Store Float instruct storeF_volatile(vRegF src, /* sync_memory*/indirect mem) %{ match(Set mem (StoreF mem src)); ins_cost(VOLATILE_REF_COST); format %{ "stlrs $src, $mem\t# float" %} ins_encode( aarch64_enc_fstlrs(src, mem) ); ins_pipe(pipe_class_memory); %} // TODO // implement storeImmF0 and storeFImmPacked // Store Double instruct storeD_volatile(vRegD src, /* sync_memory*/indirect mem) %{ match(Set mem (StoreD mem src)); ins_cost(VOLATILE_REF_COST); format %{ "stlrd $src, $mem\t# double" %} ins_encode( aarch64_enc_fstlrd(src, mem) ); ins_pipe(pipe_class_memory); %} // ---------------- end of volatile loads and stores ---------------- instruct cacheWB(indirect addr) %{ predicate(VM_Version::supports_data_cache_line_flush()); match(CacheWB addr); ins_cost(100); format %{"cache wb $addr" %} ins_encode %{ assert($addr->index_position() < 0, "should be"); assert($addr$$disp == 0, "should be"); __ cache_wb(Address($addr$$base$$Register, 0)); %} ins_pipe(pipe_slow); // XXX %} instruct cacheWBPreSync() %{ predicate(VM_Version::supports_data_cache_line_flush()); match(CacheWBPreSync); ins_cost(100); format %{"cache wb presync" %} ins_encode %{ __ cache_wbsync(true); %} ins_pipe(pipe_slow); // XXX %} instruct cacheWBPostSync() %{ predicate(VM_Version::supports_data_cache_line_flush()); match(CacheWBPostSync); ins_cost(100); format %{"cache wb postsync" %} ins_encode %{ __ cache_wbsync(false); %} ins_pipe(pipe_slow); // XXX %} // ============================================================================ // BSWAP Instructions instruct bytes_reverse_int(iRegINoSp dst, iRegIorL2I src) %{ match(Set dst (ReverseBytesI src)); ins_cost(INSN_COST); format %{ "revw $dst, $src" %} ins_encode %{ __ revw(as_Register($dst$$reg), as_Register($src$$reg)); %} ins_pipe(ialu_reg); %} instruct bytes_reverse_long(iRegLNoSp dst, iRegL src) %{ match(Set dst (ReverseBytesL src)); ins_cost(INSN_COST); format %{ "rev $dst, $src" %} ins_encode %{ __ rev(as_Register($dst$$reg), as_Register($src$$reg)); %} ins_pipe(ialu_reg); %} instruct bytes_reverse_unsigned_short(iRegINoSp dst, iRegIorL2I src) %{ match(Set dst (ReverseBytesUS src)); ins_cost(INSN_COST); format %{ "rev16w $dst, $src" %} ins_encode %{ __ rev16w(as_Register($dst$$reg), as_Register($src$$reg)); %} ins_pipe(ialu_reg); %} instruct bytes_reverse_short(iRegINoSp dst, iRegIorL2I src) %{ match(Set dst (ReverseBytesS src)); ins_cost(INSN_COST); format %{ "rev16w $dst, $src\n\t" "sbfmw $dst, $dst, #0, #15" %} ins_encode %{ __ rev16w(as_Register($dst$$reg), as_Register($src$$reg)); __ sbfmw(as_Register($dst$$reg), as_Register($dst$$reg), 0U, 15U); %} ins_pipe(ialu_reg); %} // ============================================================================ // Zero Count Instructions instruct countLeadingZerosI(iRegINoSp dst, iRegIorL2I src) %{ match(Set dst (CountLeadingZerosI src)); ins_cost(INSN_COST); format %{ "clzw $dst, $src" %} ins_encode %{ __ clzw(as_Register($dst$$reg), as_Register($src$$reg)); %} ins_pipe(ialu_reg); %} instruct countLeadingZerosL(iRegINoSp dst, iRegL src) %{ match(Set dst (CountLeadingZerosL src)); ins_cost(INSN_COST); format %{ "clz $dst, $src" %} ins_encode %{ __ clz(as_Register($dst$$reg), as_Register($src$$reg)); %} ins_pipe(ialu_reg); %} instruct countTrailingZerosI(iRegINoSp dst, iRegIorL2I src) %{ match(Set dst (CountTrailingZerosI src)); ins_cost(INSN_COST * 2); format %{ "rbitw $dst, $src\n\t" "clzw $dst, $dst" %} ins_encode %{ __ rbitw(as_Register($dst$$reg), as_Register($src$$reg)); __ clzw(as_Register($dst$$reg), as_Register($dst$$reg)); %} ins_pipe(ialu_reg); %} instruct countTrailingZerosL(iRegINoSp dst, iRegL src) %{ match(Set dst (CountTrailingZerosL src)); ins_cost(INSN_COST * 2); format %{ "rbit $dst, $src\n\t" "clz $dst, $dst" %} ins_encode %{ __ rbit(as_Register($dst$$reg), as_Register($src$$reg)); __ clz(as_Register($dst$$reg), as_Register($dst$$reg)); %} ins_pipe(ialu_reg); %} //---------- Population Count Instructions ------------------------------------- // instruct popCountI(iRegINoSp dst, iRegIorL2I src, vRegF tmp) %{ predicate(UsePopCountInstruction); match(Set dst (PopCountI src)); effect(TEMP tmp); ins_cost(INSN_COST * 13); format %{ "movw $src, $src\n\t" "mov $tmp, $src\t# vector (1D)\n\t" "cnt $tmp, $tmp\t# vector (8B)\n\t" "addv $tmp, $tmp\t# vector (8B)\n\t" "mov $dst, $tmp\t# vector (1D)" %} ins_encode %{ __ movw($src$$Register, $src$$Register); // ensure top 32 bits 0 __ mov($tmp$$FloatRegister, __ T1D, 0, $src$$Register); __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0); %} ins_pipe(pipe_class_default); %} instruct popCountI_mem(iRegINoSp dst, memory4 mem, vRegF tmp) %{ predicate(UsePopCountInstruction); match(Set dst (PopCountI (LoadI mem))); effect(TEMP tmp); ins_cost(INSN_COST * 13); format %{ "ldrs $tmp, $mem\n\t" "cnt $tmp, $tmp\t# vector (8B)\n\t" "addv $tmp, $tmp\t# vector (8B)\n\t" "mov $dst, $tmp\t# vector (1D)" %} ins_encode %{ FloatRegister tmp_reg = as_FloatRegister($tmp$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrs, tmp_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0); %} ins_pipe(pipe_class_default); %} // Note: Long.bitCount(long) returns an int. instruct popCountL(iRegINoSp dst, iRegL src, vRegD tmp) %{ predicate(UsePopCountInstruction); match(Set dst (PopCountL src)); effect(TEMP tmp); ins_cost(INSN_COST * 13); format %{ "mov $tmp, $src\t# vector (1D)\n\t" "cnt $tmp, $tmp\t# vector (8B)\n\t" "addv $tmp, $tmp\t# vector (8B)\n\t" "mov $dst, $tmp\t# vector (1D)" %} ins_encode %{ __ mov($tmp$$FloatRegister, __ T1D, 0, $src$$Register); __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0); %} ins_pipe(pipe_class_default); %} instruct popCountL_mem(iRegINoSp dst, memory8 mem, vRegD tmp) %{ predicate(UsePopCountInstruction); match(Set dst (PopCountL (LoadL mem))); effect(TEMP tmp); ins_cost(INSN_COST * 13); format %{ "ldrd $tmp, $mem\n\t" "cnt $tmp, $tmp\t# vector (8B)\n\t" "addv $tmp, $tmp\t# vector (8B)\n\t" "mov $dst, $tmp\t# vector (1D)" %} ins_encode %{ FloatRegister tmp_reg = as_FloatRegister($tmp$$reg); loadStore(C2_MacroAssembler(&cbuf), &MacroAssembler::ldrd, tmp_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0); %} ins_pipe(pipe_class_default); %} // ============================================================================ // MemBar Instruction instruct load_fence() %{ match(LoadFence); ins_cost(VOLATILE_REF_COST); format %{ "load_fence" %} ins_encode %{ __ membar(Assembler::LoadLoad|Assembler::LoadStore); %} ins_pipe(pipe_serial); %} instruct unnecessary_membar_acquire() %{ predicate(unnecessary_acquire(n)); match(MemBarAcquire); ins_cost(0); format %{ "membar_acquire (elided)" %} ins_encode %{ __ block_comment("membar_acquire (elided)"); %} ins_pipe(pipe_class_empty); %} instruct membar_acquire() %{ match(MemBarAcquire); ins_cost(VOLATILE_REF_COST); format %{ "membar_acquire\n\t" "dmb ish" %} ins_encode %{ __ block_comment("membar_acquire"); __ membar(Assembler::LoadLoad|Assembler::LoadStore); %} ins_pipe(pipe_serial); %} instruct membar_acquire_lock() %{ match(MemBarAcquireLock); ins_cost(VOLATILE_REF_COST); format %{ "membar_acquire_lock (elided)" %} ins_encode %{ __ block_comment("membar_acquire_lock (elided)"); %} ins_pipe(pipe_serial); %} instruct store_fence() %{ match(StoreFence); ins_cost(VOLATILE_REF_COST); format %{ "store_fence" %} ins_encode %{ __ membar(Assembler::LoadStore|Assembler::StoreStore); %} ins_pipe(pipe_serial); %} instruct unnecessary_membar_release() %{ predicate(unnecessary_release(n)); match(MemBarRelease); ins_cost(0); format %{ "membar_release (elided)" %} ins_encode %{ __ block_comment("membar_release (elided)"); %} ins_pipe(pipe_serial); %} instruct membar_release() %{ match(MemBarRelease); ins_cost(VOLATILE_REF_COST); format %{ "membar_release\n\t" "dmb ish" %} ins_encode %{ __ block_comment("membar_release"); __ membar(Assembler::LoadStore|Assembler::StoreStore); %} ins_pipe(pipe_serial); %} instruct membar_storestore() %{ match(MemBarStoreStore); match(StoreStoreFence); ins_cost(VOLATILE_REF_COST); format %{ "MEMBAR-store-store" %} ins_encode %{ __ membar(Assembler::StoreStore); %} ins_pipe(pipe_serial); %} instruct membar_release_lock() %{ match(MemBarReleaseLock); ins_cost(VOLATILE_REF_COST); format %{ "membar_release_lock (elided)" %} ins_encode %{ __ block_comment("membar_release_lock (elided)"); %} ins_pipe(pipe_serial); %} instruct unnecessary_membar_volatile() %{ predicate(unnecessary_volatile(n)); match(MemBarVolatile); ins_cost(0); format %{ "membar_volatile (elided)" %} ins_encode %{ __ block_comment("membar_volatile (elided)"); %} ins_pipe(pipe_serial); %} instruct membar_volatile() %{ match(MemBarVolatile); ins_cost(VOLATILE_REF_COST*100); format %{ "membar_volatile\n\t" "dmb ish"%} ins_encode %{ __ block_comment("membar_volatile"); __ membar(Assembler::StoreLoad); %} ins_pipe(pipe_serial); %} // ============================================================================ // Cast/Convert Instructions instruct castX2P(iRegPNoSp dst, iRegL src) %{ match(Set dst (CastX2P src)); ins_cost(INSN_COST); format %{ "mov $dst, $src\t# long -> ptr" %} ins_encode %{ if ($dst$$reg != $src$$reg) { __ mov(as_Register($dst$$reg), as_Register($src$$reg)); } %} ins_pipe(ialu_reg); %} instruct castP2X(iRegLNoSp dst, iRegP src) %{ match(Set dst (CastP2X src)); ins_cost(INSN_COST); format %{ "mov $dst, $src\t# ptr -> long" %} ins_encode %{ if ($dst$$reg != $src$$reg) { __ mov(as_Register($dst$$reg), as_Register($src$$reg)); } %} ins_pipe(ialu_reg); %} // Convert oop into int for vectors alignment masking instruct convP2I(iRegINoSp dst, iRegP src) %{ match(Set dst (ConvL2I (CastP2X src))); ins_cost(INSN_COST); format %{ "movw $dst, $src\t# ptr -> int" %} ins_encode %{ __ movw($dst$$Register, $src$$Register); %} ins_pipe(ialu_reg); %} // Convert compressed oop into int for vectors alignment masking // in case of 32bit oops (heap < 4Gb). instruct convN2I(iRegINoSp dst, iRegN src) %{ predicate(CompressedOops::shift() == 0); match(Set dst (ConvL2I (CastP2X (DecodeN src)))); ins_cost(INSN_COST); format %{ "mov dst, $src\t# compressed ptr -> int" %} ins_encode %{ __ movw($dst$$Register, $src$$Register); %} ins_pipe(ialu_reg); %} // Convert oop pointer into compressed form instruct encodeHeapOop(iRegNNoSp dst, iRegP src, rFlagsReg cr) %{ predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull); match(Set dst (EncodeP src)); effect(KILL cr); ins_cost(INSN_COST * 3); format %{ "encode_heap_oop $dst, $src" %} ins_encode %{ Register s = $src$$Register; Register d = $dst$$Register; __ encode_heap_oop(d, s); %} ins_pipe(ialu_reg); %} instruct encodeHeapOop_not_null(iRegNNoSp dst, iRegP src, rFlagsReg cr) %{ predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull); match(Set dst (EncodeP src)); ins_cost(INSN_COST * 3); format %{ "encode_heap_oop_not_null $dst, $src" %} ins_encode %{ __ encode_heap_oop_not_null($dst$$Register, $src$$Register); %} ins_pipe(ialu_reg); %} instruct decodeHeapOop(iRegPNoSp dst, iRegN src, rFlagsReg cr) %{ predicate(n->bottom_type()->is_ptr()->ptr() != TypePtr::NotNull && n->bottom_type()->is_ptr()->ptr() != TypePtr::Constant); match(Set dst (DecodeN src)); ins_cost(INSN_COST * 3); format %{ "decode_heap_oop $dst, $src" %} ins_encode %{ Register s = $src$$Register; Register d = $dst$$Register; __ decode_heap_oop(d, s); %} ins_pipe(ialu_reg); %} instruct decodeHeapOop_not_null(iRegPNoSp dst, iRegN src, rFlagsReg cr) %{ predicate(n->bottom_type()->is_ptr()->ptr() == TypePtr::NotNull || n->bottom_type()->is_ptr()->ptr() == TypePtr::Constant); match(Set dst (DecodeN src)); ins_cost(INSN_COST * 3); format %{ "decode_heap_oop_not_null $dst, $src" %} ins_encode %{ Register s = $src$$Register; Register d = $dst$$Register; __ decode_heap_oop_not_null(d, s); %} ins_pipe(ialu_reg); %} // n.b. AArch64 implementations of encode_klass_not_null and // decode_klass_not_null do not modify the flags register so, unlike // Intel, we don't kill CR as a side effect here instruct encodeKlass_not_null(iRegNNoSp dst, iRegP src) %{ match(Set dst (EncodePKlass src)); ins_cost(INSN_COST * 3); format %{ "encode_klass_not_null $dst,$src" %} ins_encode %{ Register src_reg = as_Register($src$$reg); Register dst_reg = as_Register($dst$$reg); __ encode_klass_not_null(dst_reg, src_reg); %} ins_pipe(ialu_reg); %} instruct decodeKlass_not_null(iRegPNoSp dst, iRegN src) %{ match(Set dst (DecodeNKlass src)); ins_cost(INSN_COST * 3); format %{ "decode_klass_not_null $dst,$src" %} ins_encode %{ Register src_reg = as_Register($src$$reg); Register dst_reg = as_Register($dst$$reg); if (dst_reg != src_reg) { __ decode_klass_not_null(dst_reg, src_reg); } else { __ decode_klass_not_null(dst_reg); } %} ins_pipe(ialu_reg); %} instruct checkCastPP(iRegPNoSp dst) %{ match(Set dst (CheckCastPP dst)); size(0); format %{ "# checkcastPP of $dst" %} ins_encode(/* empty encoding */); ins_pipe(pipe_class_empty); %} instruct castPP(iRegPNoSp dst) %{ match(Set dst (CastPP dst)); size(0); format %{ "# castPP of $dst" %} ins_encode(/* empty encoding */); ins_pipe(pipe_class_empty); %} instruct castII(iRegI dst) %{ match(Set dst (CastII dst)); size(0); format %{ "# castII of $dst" %} ins_encode(/* empty encoding */); ins_cost(0); ins_pipe(pipe_class_empty); %} instruct castLL(iRegL dst) %{ match(Set dst (CastLL dst)); size(0); format %{ "# castLL of $dst" %} ins_encode(/* empty encoding */); ins_cost(0); ins_pipe(pipe_class_empty); %} instruct castFF(vRegF dst) %{ match(Set dst (CastFF dst)); size(0); format %{ "# castFF of $dst" %} ins_encode(/* empty encoding */); ins_cost(0); ins_pipe(pipe_class_empty); %} instruct castDD(vRegD dst) %{ match(Set dst (CastDD dst)); size(0); format %{ "# castDD of $dst" %} ins_encode(/* empty encoding */); ins_cost(0); ins_pipe(pipe_class_empty); %} instruct castVVD(vecD dst) %{ match(Set dst (CastVV dst)); size(0); format %{ "# castVV of $dst" %} ins_encode(/* empty encoding */); ins_cost(0); ins_pipe(pipe_class_empty); %} instruct castVVX(vecX dst) %{ match(Set dst (CastVV dst)); size(0); format %{ "# castVV of $dst" %} ins_encode(/* empty encoding */); ins_cost(0); ins_pipe(pipe_class_empty); %} instruct castVV(vReg dst) %{ match(Set dst (CastVV dst)); size(0); format %{ "# castVV of $dst" %} ins_encode(/* empty encoding */); ins_cost(0); ins_pipe(pipe_class_empty); %} // ============================================================================ // Atomic operation instructions // // Intel and SPARC both implement Ideal Node LoadPLocked and // Store{PIL}Conditional instructions using a normal load for the // LoadPLocked and a CAS for the Store{PIL}Conditional. // // The ideal code appears only to use LoadPLocked/StorePLocked as a // pair to lock object allocations from Eden space when not using // TLABs. // // There does not appear to be a Load{IL}Locked Ideal Node and the // Ideal code appears to use Store{IL}Conditional as an alias for CAS // and to use StoreIConditional only for 32-bit and StoreLConditional // only for 64-bit. // // We implement LoadPLocked and StorePLocked instructions using, // respectively the AArch64 hw load-exclusive and store-conditional // instructions. Whereas we must implement each of // Store{IL}Conditional using a CAS which employs a pair of // instructions comprising a load-exclusive followed by a // store-conditional. // Locked-load (linked load) of the current heap-top // used when updating the eden heap top // implemented using ldaxr on AArch64 instruct loadPLocked(iRegPNoSp dst, indirect mem) %{ match(Set dst (LoadPLocked mem)); ins_cost(VOLATILE_REF_COST); format %{ "ldaxr $dst, $mem\t# ptr linked acquire" %} ins_encode(aarch64_enc_ldaxr(dst, mem)); ins_pipe(pipe_serial); %} // Conditional-store of the updated heap-top. // Used during allocation of the shared heap. // Sets flag (EQ) on success. // implemented using stlxr on AArch64. instruct storePConditional(memory8 heap_top_ptr, iRegP oldval, iRegP newval, rFlagsReg cr) %{ match(Set cr (StorePConditional heap_top_ptr (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); // TODO // do we need to do a store-conditional release or can we just use a // plain store-conditional? format %{ "stlxr rscratch1, $newval, $heap_top_ptr\t# ptr cond release" "cmpw rscratch1, zr\t# EQ on successful write" %} ins_encode(aarch64_enc_stlxr(newval, heap_top_ptr)); ins_pipe(pipe_serial); %} // storeLConditional is used by PhaseMacroExpand::expand_lock_node // when attempting to rebias a lock towards the current thread. We // must use the acquire form of cmpxchg in order to guarantee acquire // semantics in this case. instruct storeLConditional(indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) %{ match(Set cr (StoreLConditional mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); format %{ "cmpxchg rscratch1, $mem, $oldval, $newval, $mem\t# if $mem == $oldval then $mem <-- $newval" "cmpw rscratch1, zr\t# EQ on successful write" %} ins_encode(aarch64_enc_cmpxchg_acq(mem, oldval, newval)); ins_pipe(pipe_slow); %} // storeIConditional also has acquire semantics, for no better reason // than matching storeLConditional. At the time of writing this // comment storeIConditional was not used anywhere by AArch64. instruct storeIConditional(indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ match(Set cr (StoreIConditional mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); format %{ "cmpxchgw rscratch1, $mem, $oldval, $newval, $mem\t# if $mem == $oldval then $mem <-- $newval" "cmpw rscratch1, zr\t# EQ on successful write" %} ins_encode(aarch64_enc_cmpxchgw_acq(mem, oldval, newval)); ins_pipe(pipe_slow); %} // standard CompareAndSwapX when we are using barriers // these have higher priority than the rules selected by a predicate // XXX No flag versions for CompareAndSwap{I,L,P,N} because matcher // can't match them instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapB mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgb $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchgb(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapS mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgs $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchgs(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapI mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgw $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchgw(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapL mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchg $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchg(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); predicate(n->as_LoadStore()->barrier_data() == 0); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchg $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchg(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapN mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgw $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchgw(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} // alternative CompareAndSwapX when we are eliding barriers instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndSwapB mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgb_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchgb_acq(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndSwapS mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgs_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchgs_acq(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndSwapI mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgw_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchgw_acq(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndSwapL mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchg_acq(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); match(Set res (CompareAndSwapP mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchg_acq(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndSwapN mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgw_acq $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode(aarch64_enc_cmpxchgw_acq(mem, oldval, newval), aarch64_enc_cset_eq(res)); ins_pipe(pipe_slow); %} // --------------------------------------------------------------------- // BEGIN This section of the file is automatically generated. Do not edit -------------- // Sundry CAS operations. Note that release is always true, // regardless of the memory ordering of the CAS. This is because we // need the volatile case to be sequentially consistent but there is // no trailing StoreLoad barrier emitted by C2. Unfortunately we // can't check the type of memory ordering here, so we always emit a // STLXR. // This section is generated from aarch64_ad_cas.m4 // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ match(Set res (CompareAndExchangeB mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchgb $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::byte, /*acquire*/ false, /*release*/ true, /*weak*/ false, $res$$Register); __ sxtbw($res$$Register, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ match(Set res (CompareAndExchangeS mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchgs $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::halfword, /*acquire*/ false, /*release*/ true, /*weak*/ false, $res$$Register); __ sxthw($res$$Register, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ match(Set res (CompareAndExchangeI mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchgw $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, /*acquire*/ false, /*release*/ true, /*weak*/ false, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ match(Set res (CompareAndExchangeL mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchg $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, /*acquire*/ false, /*release*/ true, /*weak*/ false, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ match(Set res (CompareAndExchangeN mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchgw $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, /*acquire*/ false, /*release*/ true, /*weak*/ false, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndExchangeP mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchg $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, /*acquire*/ false, /*release*/ true, /*weak*/ false, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndExchangeB mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchgb_acq $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::byte, /*acquire*/ true, /*release*/ true, /*weak*/ false, $res$$Register); __ sxtbw($res$$Register, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndExchangeS mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchgs_acq $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::halfword, /*acquire*/ true, /*release*/ true, /*weak*/ false, $res$$Register); __ sxthw($res$$Register, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndExchangeI mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, /*acquire*/ true, /*release*/ true, /*weak*/ false, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndExchangeL mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, /*acquire*/ true, /*release*/ true, /*weak*/ false, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, /*acquire*/ true, /*release*/ true, /*weak*/ false, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); match(Set res (CompareAndExchangeP mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, /*acquire*/ true, /*release*/ true, /*weak*/ false, $res$$Register); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgb $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::byte, /*acquire*/ false, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgs $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::halfword, /*acquire*/ false, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgw $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, /*acquire*/ false, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchg $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, /*acquire*/ false, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgw $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, /*acquire*/ false, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchg $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, /*acquire*/ false, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgb_acq $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::byte, /*acquire*/ true, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgs_acq $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::halfword, /*acquire*/ true, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, /*acquire*/ true, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, /*acquire*/ true, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, /*acquire*/ true, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval" "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" %} ins_encode %{ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, /*acquire*/ true, /*release*/ true, /*weak*/ true, noreg); __ csetw($res$$Register, Assembler::EQ); %} ins_pipe(pipe_slow); %} // END This section of the file is automatically generated. Do not edit -------------- // --------------------------------------------------------------------- instruct get_and_setI(indirect mem, iRegI newv, iRegINoSp prev) %{ match(Set prev (GetAndSetI mem newv)); ins_cost(2 * VOLATILE_REF_COST); format %{ "atomic_xchgw $prev, $newv, [$mem]" %} ins_encode %{ __ atomic_xchgw($prev$$Register, $newv$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) %{ match(Set prev (GetAndSetL mem newv)); ins_cost(2 * VOLATILE_REF_COST); format %{ "atomic_xchg $prev, $newv, [$mem]" %} ins_encode %{ __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{ match(Set prev (GetAndSetN mem newv)); ins_cost(2 * VOLATILE_REF_COST); format %{ "atomic_xchgw $prev, $newv, [$mem]" %} ins_encode %{ __ atomic_xchgw($prev$$Register, $newv$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_setP(indirect mem, iRegP newv, iRegPNoSp prev) %{ predicate(n->as_LoadStore()->barrier_data() == 0); match(Set prev (GetAndSetP mem newv)); ins_cost(2 * VOLATILE_REF_COST); format %{ "atomic_xchg $prev, $newv, [$mem]" %} ins_encode %{ __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_setIAcq(indirect mem, iRegI newv, iRegINoSp prev) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set prev (GetAndSetI mem newv)); ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchgw_acq $prev, $newv, [$mem]" %} ins_encode %{ __ atomic_xchgalw($prev$$Register, $newv$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_setLAcq(indirect mem, iRegL newv, iRegLNoSp prev) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set prev (GetAndSetL mem newv)); ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchg_acq $prev, $newv, [$mem]" %} ins_encode %{ __ atomic_xchgal($prev$$Register, $newv$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_setNAcq(indirect mem, iRegN newv, iRegINoSp prev) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set prev (GetAndSetN mem newv)); ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchgw_acq $prev, $newv, [$mem]" %} ins_encode %{ __ atomic_xchgalw($prev$$Register, $newv$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_setPAcq(indirect mem, iRegP newv, iRegPNoSp prev) %{ predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); match(Set prev (GetAndSetP mem newv)); ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchg_acq $prev, $newv, [$mem]" %} ins_encode %{ __ atomic_xchgal($prev$$Register, $newv$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addL(indirect mem, iRegLNoSp newval, iRegL incr) %{ match(Set newval (GetAndAddL mem incr)); ins_cost(2 * VOLATILE_REF_COST + 1); format %{ "get_and_addL $newval, [$mem], $incr" %} ins_encode %{ __ atomic_add($newval$$Register, $incr$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addL_no_res(indirect mem, Universe dummy, iRegL incr) %{ predicate(n->as_LoadStore()->result_not_used()); match(Set dummy (GetAndAddL mem incr)); ins_cost(2 * VOLATILE_REF_COST); format %{ "get_and_addL [$mem], $incr" %} ins_encode %{ __ atomic_add(noreg, $incr$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addLi(indirect mem, iRegLNoSp newval, immLAddSub incr) %{ match(Set newval (GetAndAddL mem incr)); ins_cost(2 * VOLATILE_REF_COST + 1); format %{ "get_and_addL $newval, [$mem], $incr" %} ins_encode %{ __ atomic_add($newval$$Register, $incr$$constant, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addLi_no_res(indirect mem, Universe dummy, immLAddSub incr) %{ predicate(n->as_LoadStore()->result_not_used()); match(Set dummy (GetAndAddL mem incr)); ins_cost(2 * VOLATILE_REF_COST); format %{ "get_and_addL [$mem], $incr" %} ins_encode %{ __ atomic_add(noreg, $incr$$constant, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addI(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{ match(Set newval (GetAndAddI mem incr)); ins_cost(2 * VOLATILE_REF_COST + 1); format %{ "get_and_addI $newval, [$mem], $incr" %} ins_encode %{ __ atomic_addw($newval$$Register, $incr$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addI_no_res(indirect mem, Universe dummy, iRegIorL2I incr) %{ predicate(n->as_LoadStore()->result_not_used()); match(Set dummy (GetAndAddI mem incr)); ins_cost(2 * VOLATILE_REF_COST); format %{ "get_and_addI [$mem], $incr" %} ins_encode %{ __ atomic_addw(noreg, $incr$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addIi(indirect mem, iRegINoSp newval, immIAddSub incr) %{ match(Set newval (GetAndAddI mem incr)); ins_cost(2 * VOLATILE_REF_COST + 1); format %{ "get_and_addI $newval, [$mem], $incr" %} ins_encode %{ __ atomic_addw($newval$$Register, $incr$$constant, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addIi_no_res(indirect mem, Universe dummy, immIAddSub incr) %{ predicate(n->as_LoadStore()->result_not_used()); match(Set dummy (GetAndAddI mem incr)); ins_cost(2 * VOLATILE_REF_COST); format %{ "get_and_addI [$mem], $incr" %} ins_encode %{ __ atomic_addw(noreg, $incr$$constant, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addLAcq(indirect mem, iRegLNoSp newval, iRegL incr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set newval (GetAndAddL mem incr)); ins_cost(VOLATILE_REF_COST + 1); format %{ "get_and_addL_acq $newval, [$mem], $incr" %} ins_encode %{ __ atomic_addal($newval$$Register, $incr$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addL_no_resAcq(indirect mem, Universe dummy, iRegL incr) %{ predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); match(Set dummy (GetAndAddL mem incr)); ins_cost(VOLATILE_REF_COST); format %{ "get_and_addL_acq [$mem], $incr" %} ins_encode %{ __ atomic_addal(noreg, $incr$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addLiAcq(indirect mem, iRegLNoSp newval, immLAddSub incr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set newval (GetAndAddL mem incr)); ins_cost(VOLATILE_REF_COST + 1); format %{ "get_and_addL_acq $newval, [$mem], $incr" %} ins_encode %{ __ atomic_addal($newval$$Register, $incr$$constant, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addLi_no_resAcq(indirect mem, Universe dummy, immLAddSub incr) %{ predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); match(Set dummy (GetAndAddL mem incr)); ins_cost(VOLATILE_REF_COST); format %{ "get_and_addL_acq [$mem], $incr" %} ins_encode %{ __ atomic_addal(noreg, $incr$$constant, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addIAcq(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set newval (GetAndAddI mem incr)); ins_cost(VOLATILE_REF_COST + 1); format %{ "get_and_addI_acq $newval, [$mem], $incr" %} ins_encode %{ __ atomic_addalw($newval$$Register, $incr$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addI_no_resAcq(indirect mem, Universe dummy, iRegIorL2I incr) %{ predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); match(Set dummy (GetAndAddI mem incr)); ins_cost(VOLATILE_REF_COST); format %{ "get_and_addI_acq [$mem], $incr" %} ins_encode %{ __ atomic_addalw(noreg, $incr$$Register, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addIiAcq(indirect mem, iRegINoSp newval, immIAddSub incr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set newval (GetAndAddI mem incr)); ins_cost(VOLATILE_REF_COST + 1); format %{ "get_and_addI_acq $newval, [$mem], $incr" %} ins_encode %{ __ atomic_addalw($newval$$Register, $incr$$constant, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} instruct get_and_addIi_no_resAcq(indirect mem, Universe dummy, immIAddSub incr) %{ predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); match(Set dummy (GetAndAddI mem incr)); ins_cost(VOLATILE_REF_COST); format %{ "get_and_addI_acq [$mem], $incr" %} ins_encode %{ __ atomic_addalw(noreg, $incr$$constant, as_Register($mem$$base)); %} ins_pipe(pipe_serial); %} // Manifest a CmpL result in an integer register. // (src1 < src2) ? -1 : ((src1 > src2) ? 1 : 0) instruct cmpL3_reg_reg(iRegINoSp dst, iRegL src1, iRegL src2, rFlagsReg flags) %{ match(Set dst (CmpL3 src1 src2)); effect(KILL flags); ins_cost(INSN_COST * 6); format %{ "cmp $src1, $src2" "csetw $dst, ne" "cnegw $dst, lt" %} // format %{ "CmpL3 $dst, $src1, $src2" %} ins_encode %{ __ cmp($src1$$Register, $src2$$Register); __ csetw($dst$$Register, Assembler::NE); __ cnegw($dst$$Register, $dst$$Register, Assembler::LT); %} ins_pipe(pipe_class_default); %} instruct cmpL3_reg_imm(iRegINoSp dst, iRegL src1, immLAddSub src2, rFlagsReg flags) %{ match(Set dst (CmpL3 src1 src2)); effect(KILL flags); ins_cost(INSN_COST * 6); format %{ "cmp $src1, $src2" "csetw $dst, ne" "cnegw $dst, lt" %} ins_encode %{ int32_t con = (int32_t)$src2$$constant; if (con < 0) { __ adds(zr, $src1$$Register, -con); } else { __ subs(zr, $src1$$Register, con); } __ csetw($dst$$Register, Assembler::NE); __ cnegw($dst$$Register, $dst$$Register, Assembler::LT); %} ins_pipe(pipe_class_default); %} // ============================================================================ // Conditional Move Instructions // n.b. we have identical rules for both a signed compare op (cmpOp) // and an unsigned compare op (cmpOpU). it would be nice if we could // define an op class which merged both inputs and use it to type the // argument to a single rule. unfortunatelyt his fails because the // opclass does not live up to the COND_INTER interface of its // component operands. When the generic code tries to negate the // operand it ends up running the generci Machoper::negate method // which throws a ShouldNotHappen. So, we have to provide two flavours // of each rule, one for a cmpOp and a second for a cmpOpU (sigh). instruct cmovI_reg_reg(cmpOp cmp, rFlagsReg cr, iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (CMoveI (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src2, $src1 $cmp\t# signed, int" %} ins_encode %{ __ cselw(as_Register($dst$$reg), as_Register($src2$$reg), as_Register($src1$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg_reg); %} instruct cmovUI_reg_reg(cmpOpU cmp, rFlagsRegU cr, iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (CMoveI (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src2, $src1 $cmp\t# unsigned, int" %} ins_encode %{ __ cselw(as_Register($dst$$reg), as_Register($src2$$reg), as_Register($src1$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg_reg); %} // special cases where one arg is zero // n.b. this is selected in preference to the rule above because it // avoids loading constant 0 into a source register // TODO // we ought only to be able to cull one of these variants as the ideal // transforms ought always to order the zero consistently (to left/right?) instruct cmovI_zero_reg(cmpOp cmp, rFlagsReg cr, iRegINoSp dst, immI0 zero, iRegIorL2I src) %{ match(Set dst (CMoveI (Binary cmp cr) (Binary zero src))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src, zr $cmp\t# signed, int" %} ins_encode %{ __ cselw(as_Register($dst$$reg), as_Register($src$$reg), zr, (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovUI_zero_reg(cmpOpU cmp, rFlagsRegU cr, iRegINoSp dst, immI0 zero, iRegIorL2I src) %{ match(Set dst (CMoveI (Binary cmp cr) (Binary zero src))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src, zr $cmp\t# unsigned, int" %} ins_encode %{ __ cselw(as_Register($dst$$reg), as_Register($src$$reg), zr, (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovI_reg_zero(cmpOp cmp, rFlagsReg cr, iRegINoSp dst, iRegIorL2I src, immI0 zero) %{ match(Set dst (CMoveI (Binary cmp cr) (Binary src zero))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, zr, $src $cmp\t# signed, int" %} ins_encode %{ __ cselw(as_Register($dst$$reg), zr, as_Register($src$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovUI_reg_zero(cmpOpU cmp, rFlagsRegU cr, iRegINoSp dst, iRegIorL2I src, immI0 zero) %{ match(Set dst (CMoveI (Binary cmp cr) (Binary src zero))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, zr, $src $cmp\t# unsigned, int" %} ins_encode %{ __ cselw(as_Register($dst$$reg), zr, as_Register($src$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} // special case for creating a boolean 0 or 1 // n.b. this is selected in preference to the rule above because it // avoids loading constants 0 and 1 into a source register instruct cmovI_reg_zero_one(cmpOp cmp, rFlagsReg cr, iRegINoSp dst, immI0 zero, immI_1 one) %{ match(Set dst (CMoveI (Binary cmp cr) (Binary one zero))); ins_cost(INSN_COST * 2); format %{ "csincw $dst, zr, zr $cmp\t# signed, int" %} ins_encode %{ // equivalently // cset(as_Register($dst$$reg), // negate_condition((Assembler::Condition)$cmp$$cmpcode)); __ csincw(as_Register($dst$$reg), zr, zr, (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_none); %} instruct cmovUI_reg_zero_one(cmpOpU cmp, rFlagsRegU cr, iRegINoSp dst, immI0 zero, immI_1 one) %{ match(Set dst (CMoveI (Binary cmp cr) (Binary one zero))); ins_cost(INSN_COST * 2); format %{ "csincw $dst, zr, zr $cmp\t# unsigned, int" %} ins_encode %{ // equivalently // cset(as_Register($dst$$reg), // negate_condition((Assembler::Condition)$cmp$$cmpcode)); __ csincw(as_Register($dst$$reg), zr, zr, (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_none); %} instruct cmovL_reg_reg(cmpOp cmp, rFlagsReg cr, iRegLNoSp dst, iRegL src1, iRegL src2) %{ match(Set dst (CMoveL (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 2); format %{ "csel $dst, $src2, $src1 $cmp\t# signed, long" %} ins_encode %{ __ csel(as_Register($dst$$reg), as_Register($src2$$reg), as_Register($src1$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg_reg); %} instruct cmovUL_reg_reg(cmpOpU cmp, rFlagsRegU cr, iRegLNoSp dst, iRegL src1, iRegL src2) %{ match(Set dst (CMoveL (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 2); format %{ "csel $dst, $src2, $src1 $cmp\t# unsigned, long" %} ins_encode %{ __ csel(as_Register($dst$$reg), as_Register($src2$$reg), as_Register($src1$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg_reg); %} // special cases where one arg is zero instruct cmovL_reg_zero(cmpOp cmp, rFlagsReg cr, iRegLNoSp dst, iRegL src, immL0 zero) %{ match(Set dst (CMoveL (Binary cmp cr) (Binary src zero))); ins_cost(INSN_COST * 2); format %{ "csel $dst, zr, $src $cmp\t# signed, long" %} ins_encode %{ __ csel(as_Register($dst$$reg), zr, as_Register($src$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovUL_reg_zero(cmpOpU cmp, rFlagsRegU cr, iRegLNoSp dst, iRegL src, immL0 zero) %{ match(Set dst (CMoveL (Binary cmp cr) (Binary src zero))); ins_cost(INSN_COST * 2); format %{ "csel $dst, zr, $src $cmp\t# unsigned, long" %} ins_encode %{ __ csel(as_Register($dst$$reg), zr, as_Register($src$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovL_zero_reg(cmpOp cmp, rFlagsReg cr, iRegLNoSp dst, immL0 zero, iRegL src) %{ match(Set dst (CMoveL (Binary cmp cr) (Binary zero src))); ins_cost(INSN_COST * 2); format %{ "csel $dst, $src, zr $cmp\t# signed, long" %} ins_encode %{ __ csel(as_Register($dst$$reg), as_Register($src$$reg), zr, (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovUL_zero_reg(cmpOpU cmp, rFlagsRegU cr, iRegLNoSp dst, immL0 zero, iRegL src) %{ match(Set dst (CMoveL (Binary cmp cr) (Binary zero src))); ins_cost(INSN_COST * 2); format %{ "csel $dst, $src, zr $cmp\t# unsigned, long" %} ins_encode %{ __ csel(as_Register($dst$$reg), as_Register($src$$reg), zr, (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovP_reg_reg(cmpOp cmp, rFlagsReg cr, iRegPNoSp dst, iRegP src1, iRegP src2) %{ match(Set dst (CMoveP (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 2); format %{ "csel $dst, $src2, $src1 $cmp\t# signed, ptr" %} ins_encode %{ __ csel(as_Register($dst$$reg), as_Register($src2$$reg), as_Register($src1$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg_reg); %} instruct cmovUP_reg_reg(cmpOpU cmp, rFlagsRegU cr, iRegPNoSp dst, iRegP src1, iRegP src2) %{ match(Set dst (CMoveP (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 2); format %{ "csel $dst, $src2, $src1 $cmp\t# unsigned, ptr" %} ins_encode %{ __ csel(as_Register($dst$$reg), as_Register($src2$$reg), as_Register($src1$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg_reg); %} // special cases where one arg is zero instruct cmovP_reg_zero(cmpOp cmp, rFlagsReg cr, iRegPNoSp dst, iRegP src, immP0 zero) %{ match(Set dst (CMoveP (Binary cmp cr) (Binary src zero))); ins_cost(INSN_COST * 2); format %{ "csel $dst, zr, $src $cmp\t# signed, ptr" %} ins_encode %{ __ csel(as_Register($dst$$reg), zr, as_Register($src$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovUP_reg_zero(cmpOpU cmp, rFlagsRegU cr, iRegPNoSp dst, iRegP src, immP0 zero) %{ match(Set dst (CMoveP (Binary cmp cr) (Binary src zero))); ins_cost(INSN_COST * 2); format %{ "csel $dst, zr, $src $cmp\t# unsigned, ptr" %} ins_encode %{ __ csel(as_Register($dst$$reg), zr, as_Register($src$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovP_zero_reg(cmpOp cmp, rFlagsReg cr, iRegPNoSp dst, immP0 zero, iRegP src) %{ match(Set dst (CMoveP (Binary cmp cr) (Binary zero src))); ins_cost(INSN_COST * 2); format %{ "csel $dst, $src, zr $cmp\t# signed, ptr" %} ins_encode %{ __ csel(as_Register($dst$$reg), as_Register($src$$reg), zr, (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovUP_zero_reg(cmpOpU cmp, rFlagsRegU cr, iRegPNoSp dst, immP0 zero, iRegP src) %{ match(Set dst (CMoveP (Binary cmp cr) (Binary zero src))); ins_cost(INSN_COST * 2); format %{ "csel $dst, $src, zr $cmp\t# unsigned, ptr" %} ins_encode %{ __ csel(as_Register($dst$$reg), as_Register($src$$reg), zr, (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovN_reg_reg(cmpOp cmp, rFlagsReg cr, iRegNNoSp dst, iRegN src1, iRegN src2) %{ match(Set dst (CMoveN (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src2, $src1 $cmp\t# signed, compressed ptr" %} ins_encode %{ __ cselw(as_Register($dst$$reg), as_Register($src2$$reg), as_Register($src1$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg_reg); %} instruct cmovUN_reg_reg(cmpOpU cmp, rFlagsRegU cr, iRegNNoSp dst, iRegN src1, iRegN src2) %{ match(Set dst (CMoveN (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src2, $src1 $cmp\t# signed, compressed ptr" %} ins_encode %{ __ cselw(as_Register($dst$$reg), as_Register($src2$$reg), as_Register($src1$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg_reg); %} // special cases where one arg is zero instruct cmovN_reg_zero(cmpOp cmp, rFlagsReg cr, iRegNNoSp dst, iRegN src, immN0 zero) %{ match(Set dst (CMoveN (Binary cmp cr) (Binary src zero))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, zr, $src $cmp\t# signed, compressed ptr" %} ins_encode %{ __ cselw(as_Register($dst$$reg), zr, as_Register($src$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovUN_reg_zero(cmpOpU cmp, rFlagsRegU cr, iRegNNoSp dst, iRegN src, immN0 zero) %{ match(Set dst (CMoveN (Binary cmp cr) (Binary src zero))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, zr, $src $cmp\t# unsigned, compressed ptr" %} ins_encode %{ __ cselw(as_Register($dst$$reg), zr, as_Register($src$$reg), (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovN_zero_reg(cmpOp cmp, rFlagsReg cr, iRegNNoSp dst, immN0 zero, iRegN src) %{ match(Set dst (CMoveN (Binary cmp cr) (Binary zero src))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src, zr $cmp\t# signed, compressed ptr" %} ins_encode %{ __ cselw(as_Register($dst$$reg), as_Register($src$$reg), zr, (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovUN_zero_reg(cmpOpU cmp, rFlagsRegU cr, iRegNNoSp dst, immN0 zero, iRegN src) %{ match(Set dst (CMoveN (Binary cmp cr) (Binary zero src))); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src, zr $cmp\t# unsigned, compressed ptr" %} ins_encode %{ __ cselw(as_Register($dst$$reg), as_Register($src$$reg), zr, (Assembler::Condition)$cmp$$cmpcode); %} ins_pipe(icond_reg); %} instruct cmovF_reg(cmpOp cmp, rFlagsReg cr, vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (CMoveF (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 3); format %{ "fcsels $dst, $src1, $src2, $cmp\t# signed cmove float\n\t" %} ins_encode %{ Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; __ fcsels(as_FloatRegister($dst$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src1$$reg), cond); %} ins_pipe(fp_cond_reg_reg_s); %} instruct cmovUF_reg(cmpOpU cmp, rFlagsRegU cr, vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (CMoveF (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 3); format %{ "fcsels $dst, $src1, $src2, $cmp\t# unsigned cmove float\n\t" %} ins_encode %{ Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; __ fcsels(as_FloatRegister($dst$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src1$$reg), cond); %} ins_pipe(fp_cond_reg_reg_s); %} instruct cmovD_reg(cmpOp cmp, rFlagsReg cr, vRegD dst, vRegD src1, vRegD src2) %{ match(Set dst (CMoveD (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 3); format %{ "fcseld $dst, $src1, $src2, $cmp\t# signed cmove float\n\t" %} ins_encode %{ Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; __ fcseld(as_FloatRegister($dst$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src1$$reg), cond); %} ins_pipe(fp_cond_reg_reg_d); %} instruct cmovUD_reg(cmpOpU cmp, rFlagsRegU cr, vRegD dst, vRegD src1, vRegD src2) %{ match(Set dst (CMoveD (Binary cmp cr) (Binary src1 src2))); ins_cost(INSN_COST * 3); format %{ "fcseld $dst, $src1, $src2, $cmp\t# unsigned cmove float\n\t" %} ins_encode %{ Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; __ fcseld(as_FloatRegister($dst$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src1$$reg), cond); %} ins_pipe(fp_cond_reg_reg_d); %} // ============================================================================ // Arithmetic Instructions // // Integer Addition // TODO // these currently employ operations which do not set CR and hence are // not flagged as killing CR but we would like to isolate the cases // where we want to set flags from those where we don't. need to work // out how to do that. instruct addI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (AddI src1 src2)); ins_cost(INSN_COST); format %{ "addw $dst, $src1, $src2" %} ins_encode %{ __ addw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg); %} instruct addI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immIAddSub src2) %{ match(Set dst (AddI src1 src2)); ins_cost(INSN_COST); format %{ "addw $dst, $src1, $src2" %} // use opcode to indicate that this is an add not a sub opcode(0x0); ins_encode(aarch64_enc_addsubw_imm(dst, src1, src2)); ins_pipe(ialu_reg_imm); %} instruct addI_reg_imm_i2l(iRegINoSp dst, iRegL src1, immIAddSub src2) %{ match(Set dst (AddI (ConvL2I src1) src2)); ins_cost(INSN_COST); format %{ "addw $dst, $src1, $src2" %} // use opcode to indicate that this is an add not a sub opcode(0x0); ins_encode(aarch64_enc_addsubw_imm(dst, src1, src2)); ins_pipe(ialu_reg_imm); %} // Pointer Addition instruct addP_reg_reg(iRegPNoSp dst, iRegP src1, iRegL src2) %{ match(Set dst (AddP src1 src2)); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2\t# ptr" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg); %} instruct addP_reg_reg_ext(iRegPNoSp dst, iRegP src1, iRegIorL2I src2) %{ match(Set dst (AddP src1 (ConvI2L src2))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, sxtw\t# ptr" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtw); %} ins_pipe(ialu_reg_reg); %} instruct addP_reg_reg_lsl(iRegPNoSp dst, iRegP src1, iRegL src2, immIScale scale) %{ match(Set dst (AddP src1 (LShiftL src2 scale))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, LShiftL $scale\t# ptr" %} ins_encode %{ __ lea(as_Register($dst$$reg), Address(as_Register($src1$$reg), as_Register($src2$$reg), Address::lsl($scale$$constant))); %} ins_pipe(ialu_reg_reg_shift); %} instruct addP_reg_reg_ext_shift(iRegPNoSp dst, iRegP src1, iRegIorL2I src2, immIScale scale) %{ match(Set dst (AddP src1 (LShiftL (ConvI2L src2) scale))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, I2L $scale\t# ptr" %} ins_encode %{ __ lea(as_Register($dst$$reg), Address(as_Register($src1$$reg), as_Register($src2$$reg), Address::sxtw($scale$$constant))); %} ins_pipe(ialu_reg_reg_shift); %} instruct lshift_ext(iRegLNoSp dst, iRegIorL2I src, immI scale, rFlagsReg cr) %{ match(Set dst (LShiftL (ConvI2L src) scale)); ins_cost(INSN_COST); format %{ "sbfiz $dst, $src, $scale & 63, -$scale & 63\t" %} ins_encode %{ __ sbfiz(as_Register($dst$$reg), as_Register($src$$reg), $scale$$constant & 63, MIN2(32, (int)((-$scale$$constant) & 63))); %} ins_pipe(ialu_reg_shift); %} // Pointer Immediate Addition // n.b. this needs to be more expensive than using an indirect memory // operand instruct addP_reg_imm(iRegPNoSp dst, iRegP src1, immLAddSub src2) %{ match(Set dst (AddP src1 src2)); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2\t# ptr" %} // use opcode to indicate that this is an add not a sub opcode(0x0); ins_encode( aarch64_enc_addsub_imm(dst, src1, src2) ); ins_pipe(ialu_reg_imm); %} // Long Addition instruct addL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ match(Set dst (AddL src1 src2)); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg); %} // No constant pool entries requiredLong Immediate Addition. instruct addL_reg_imm(iRegLNoSp dst, iRegL src1, immLAddSub src2) %{ match(Set dst (AddL src1 src2)); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2" %} // use opcode to indicate that this is an add not a sub opcode(0x0); ins_encode( aarch64_enc_addsub_imm(dst, src1, src2) ); ins_pipe(ialu_reg_imm); %} // Integer Subtraction instruct subI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (SubI src1 src2)); ins_cost(INSN_COST); format %{ "subw $dst, $src1, $src2" %} ins_encode %{ __ subw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg); %} // Immediate Subtraction instruct subI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immIAddSub src2) %{ match(Set dst (SubI src1 src2)); ins_cost(INSN_COST); format %{ "subw $dst, $src1, $src2" %} // use opcode to indicate that this is a sub not an add opcode(0x1); ins_encode(aarch64_enc_addsubw_imm(dst, src1, src2)); ins_pipe(ialu_reg_imm); %} // Long Subtraction instruct subL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ match(Set dst (SubL src1 src2)); ins_cost(INSN_COST); format %{ "sub $dst, $src1, $src2" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg); %} // No constant pool entries requiredLong Immediate Subtraction. instruct subL_reg_imm(iRegLNoSp dst, iRegL src1, immLAddSub src2) %{ match(Set dst (SubL src1 src2)); ins_cost(INSN_COST); format %{ "sub$dst, $src1, $src2" %} // use opcode to indicate that this is a sub not an add opcode(0x1); ins_encode( aarch64_enc_addsub_imm(dst, src1, src2) ); ins_pipe(ialu_reg_imm); %} // Integer Negation (special case for sub) instruct negI_reg(iRegINoSp dst, iRegIorL2I src, immI0 zero, rFlagsReg cr) %{ match(Set dst (SubI zero src)); ins_cost(INSN_COST); format %{ "negw $dst, $src\t# int" %} ins_encode %{ __ negw(as_Register($dst$$reg), as_Register($src$$reg)); %} ins_pipe(ialu_reg); %} // Long Negation instruct negL_reg(iRegLNoSp dst, iRegL src, immL0 zero, rFlagsReg cr) %{ match(Set dst (SubL zero src)); ins_cost(INSN_COST); format %{ "neg $dst, $src\t# long" %} ins_encode %{ __ neg(as_Register($dst$$reg), as_Register($src$$reg)); %} ins_pipe(ialu_reg); %} // Integer Multiply instruct mulI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (MulI src1 src2)); ins_cost(INSN_COST * 3); format %{ "mulw $dst, $src1, $src2" %} ins_encode %{ __ mulw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(imul_reg_reg); %} instruct smulI(iRegLNoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (MulL (ConvI2L src1) (ConvI2L src2))); ins_cost(INSN_COST * 3); format %{ "smull $dst, $src1, $src2" %} ins_encode %{ __ smull(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(imul_reg_reg); %} // Long Multiply instruct mulL(iRegLNoSp dst, iRegL src1, iRegL src2) %{ match(Set dst (MulL src1 src2)); ins_cost(INSN_COST * 5); format %{ "mul $dst, $src1, $src2" %} ins_encode %{ __ mul(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(lmul_reg_reg); %} instruct mulHiL_rReg(iRegLNoSp dst, iRegL src1, iRegL src2, rFlagsReg cr) %{ match(Set dst (MulHiL src1 src2)); ins_cost(INSN_COST * 7); format %{ "smulh $dst, $src1, $src2, \t# mulhi" %} ins_encode %{ __ smulh(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(lmul_reg_reg); %} // Combined Integer Multiply & Add/Sub instruct maddI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, iRegIorL2I src3) %{ match(Set dst (AddI src3 (MulI src1 src2))); ins_cost(INSN_COST * 3); format %{ "madd $dst, $src1, $src2, $src3" %} ins_encode %{ __ maddw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), as_Register($src3$$reg)); %} ins_pipe(imac_reg_reg); %} instruct msubI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, iRegIorL2I src3) %{ match(Set dst (SubI src3 (MulI src1 src2))); ins_cost(INSN_COST * 3); format %{ "msub $dst, $src1, $src2, $src3" %} ins_encode %{ __ msubw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), as_Register($src3$$reg)); %} ins_pipe(imac_reg_reg); %} // Combined Integer Multiply & Neg instruct mnegI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI0 zero) %{ match(Set dst (MulI (SubI zero src1) src2)); match(Set dst (MulI src1 (SubI zero src2))); ins_cost(INSN_COST * 3); format %{ "mneg $dst, $src1, $src2" %} ins_encode %{ __ mnegw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(imac_reg_reg); %} // Combined Long Multiply & Add/Sub instruct maddL(iRegLNoSp dst, iRegL src1, iRegL src2, iRegL src3) %{ match(Set dst (AddL src3 (MulL src1 src2))); ins_cost(INSN_COST * 5); format %{ "madd $dst, $src1, $src2, $src3" %} ins_encode %{ __ madd(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), as_Register($src3$$reg)); %} ins_pipe(lmac_reg_reg); %} instruct msubL(iRegLNoSp dst, iRegL src1, iRegL src2, iRegL src3) %{ match(Set dst (SubL src3 (MulL src1 src2))); ins_cost(INSN_COST * 5); format %{ "msub $dst, $src1, $src2, $src3" %} ins_encode %{ __ msub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), as_Register($src3$$reg)); %} ins_pipe(lmac_reg_reg); %} // Combined Long Multiply & Neg instruct mnegL(iRegLNoSp dst, iRegL src1, iRegL src2, immL0 zero) %{ match(Set dst (MulL (SubL zero src1) src2)); match(Set dst (MulL src1 (SubL zero src2))); ins_cost(INSN_COST * 5); format %{ "mneg $dst, $src1, $src2" %} ins_encode %{ __ mneg(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(lmac_reg_reg); %} // Combine Integer Signed Multiply & Add/Sub/Neg Long instruct smaddL(iRegLNoSp dst, iRegIorL2I src1, iRegIorL2I src2, iRegLNoSp src3) %{ match(Set dst (AddL src3 (MulL (ConvI2L src1) (ConvI2L src2)))); ins_cost(INSN_COST * 3); format %{ "smaddl $dst, $src1, $src2, $src3" %} ins_encode %{ __ smaddl(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), as_Register($src3$$reg)); %} ins_pipe(imac_reg_reg); %} instruct smsubL(iRegLNoSp dst, iRegIorL2I src1, iRegIorL2I src2, iRegLNoSp src3) %{ match(Set dst (SubL src3 (MulL (ConvI2L src1) (ConvI2L src2)))); ins_cost(INSN_COST * 3); format %{ "smsubl $dst, $src1, $src2, $src3" %} ins_encode %{ __ smsubl(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), as_Register($src3$$reg)); %} ins_pipe(imac_reg_reg); %} instruct smnegL(iRegLNoSp dst, iRegIorL2I src1, iRegIorL2I src2, immL0 zero) %{ match(Set dst (MulL (SubL zero (ConvI2L src1)) (ConvI2L src2))); match(Set dst (MulL (ConvI2L src1) (SubL zero (ConvI2L src2)))); ins_cost(INSN_COST * 3); format %{ "smnegl $dst, $src1, $src2" %} ins_encode %{ __ smnegl(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(imac_reg_reg); %} // Combined Multiply-Add Shorts into Integer (dst = src1 * src2 + src3 * src4) instruct muladdS2I(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, iRegIorL2I src3, iRegIorL2I src4) %{ match(Set dst (MulAddS2I (Binary src1 src2) (Binary src3 src4))); ins_cost(INSN_COST * 5); format %{ "mulw rscratch1, $src1, $src2\n\t" "maddw $dst, $src3, $src4, rscratch1" %} ins_encode %{ __ mulw(rscratch1, as_Register($src1$$reg), as_Register($src2$$reg)); __ maddw(as_Register($dst$$reg), as_Register($src3$$reg), as_Register($src4$$reg), rscratch1); %} ins_pipe(imac_reg_reg); %} // Integer Divide instruct divI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (DivI src1 src2)); ins_cost(INSN_COST * 19); format %{ "sdivw $dst, $src1, $src2" %} ins_encode(aarch64_enc_divw(dst, src1, src2)); ins_pipe(idiv_reg_reg); %} // Long Divide instruct divL(iRegLNoSp dst, iRegL src1, iRegL src2) %{ match(Set dst (DivL src1 src2)); ins_cost(INSN_COST * 35); format %{ "sdiv $dst, $src1, $src2" %} ins_encode(aarch64_enc_div(dst, src1, src2)); ins_pipe(ldiv_reg_reg); %} // Integer Remainder instruct modI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (ModI src1 src2)); ins_cost(INSN_COST * 22); format %{ "sdivw rscratch1, $src1, $src2\n\t" "msubw($dst, rscratch1, $src2, $src1" %} ins_encode(aarch64_enc_modw(dst, src1, src2)); ins_pipe(idiv_reg_reg); %} // Long Remainder instruct modL(iRegLNoSp dst, iRegL src1, iRegL src2) %{ match(Set dst (ModL src1 src2)); ins_cost(INSN_COST * 38); format %{ "sdiv rscratch1, $src1, $src2\n" "msub($dst, rscratch1, $src2, $src1" %} ins_encode(aarch64_enc_mod(dst, src1, src2)); ins_pipe(ldiv_reg_reg); %} // Integer Shifts // Shift Left Register instruct lShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (LShiftI src1 src2)); ins_cost(INSN_COST * 2); format %{ "lslvw $dst, $src1, $src2" %} ins_encode %{ __ lslvw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg_vshift); %} // Shift Left Immediate instruct lShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ match(Set dst (LShiftI src1 src2)); ins_cost(INSN_COST); format %{ "lslw $dst, $src1, ($src2 & 0x1f)" %} ins_encode %{ __ lslw(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant & 0x1f); %} ins_pipe(ialu_reg_shift); %} // Shift Right Logical Register instruct urShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (URShiftI src1 src2)); ins_cost(INSN_COST * 2); format %{ "lsrvw $dst, $src1, $src2" %} ins_encode %{ __ lsrvw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg_vshift); %} // Shift Right Logical Immediate instruct urShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ match(Set dst (URShiftI src1 src2)); ins_cost(INSN_COST); format %{ "lsrw $dst, $src1, ($src2 & 0x1f)" %} ins_encode %{ __ lsrw(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant & 0x1f); %} ins_pipe(ialu_reg_shift); %} // Shift Right Arithmetic Register instruct rShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (RShiftI src1 src2)); ins_cost(INSN_COST * 2); format %{ "asrvw $dst, $src1, $src2" %} ins_encode %{ __ asrvw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg_vshift); %} // Shift Right Arithmetic Immediate instruct rShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ match(Set dst (RShiftI src1 src2)); ins_cost(INSN_COST); format %{ "asrw $dst, $src1, ($src2 & 0x1f)" %} ins_encode %{ __ asrw(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant & 0x1f); %} ins_pipe(ialu_reg_shift); %} // Combined Int Mask and Right Shift (using UBFM) // TODO // Long Shifts // Shift Left Register instruct lShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ match(Set dst (LShiftL src1 src2)); ins_cost(INSN_COST * 2); format %{ "lslv $dst, $src1, $src2" %} ins_encode %{ __ lslv(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg_vshift); %} // Shift Left Immediate instruct lShiftL_reg_imm(iRegLNoSp dst, iRegL src1, immI src2) %{ match(Set dst (LShiftL src1 src2)); ins_cost(INSN_COST); format %{ "lsl $dst, $src1, ($src2 & 0x3f)" %} ins_encode %{ __ lsl(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant & 0x3f); %} ins_pipe(ialu_reg_shift); %} // Shift Right Logical Register instruct urShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ match(Set dst (URShiftL src1 src2)); ins_cost(INSN_COST * 2); format %{ "lsrv $dst, $src1, $src2" %} ins_encode %{ __ lsrv(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg_vshift); %} // Shift Right Logical Immediate instruct urShiftL_reg_imm(iRegLNoSp dst, iRegL src1, immI src2) %{ match(Set dst (URShiftL src1 src2)); ins_cost(INSN_COST); format %{ "lsr $dst, $src1, ($src2 & 0x3f)" %} ins_encode %{ __ lsr(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant & 0x3f); %} ins_pipe(ialu_reg_shift); %} // A special-case pattern for card table stores. instruct urShiftP_reg_imm(iRegLNoSp dst, iRegP src1, immI src2) %{ match(Set dst (URShiftL (CastP2X src1) src2)); ins_cost(INSN_COST); format %{ "lsr $dst, p2x($src1), ($src2 & 0x3f)" %} ins_encode %{ __ lsr(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant & 0x3f); %} ins_pipe(ialu_reg_shift); %} // Shift Right Arithmetic Register instruct rShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ match(Set dst (RShiftL src1 src2)); ins_cost(INSN_COST * 2); format %{ "asrv $dst, $src1, $src2" %} ins_encode %{ __ asrv(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg_vshift); %} // Shift Right Arithmetic Immediate instruct rShiftL_reg_imm(iRegLNoSp dst, iRegL src1, immI src2) %{ match(Set dst (RShiftL src1 src2)); ins_cost(INSN_COST); format %{ "asr $dst, $src1, ($src2 & 0x3f)" %} ins_encode %{ __ asr(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant & 0x3f); %} ins_pipe(ialu_reg_shift); %} // BEGIN This section of the file is automatically generated. Do not edit -------------- // This section is generated from aarch64_ad.m4 // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct regL_not_reg(iRegLNoSp dst, iRegL src1, immL_M1 m1, rFlagsReg cr) %{ match(Set dst (XorL src1 m1)); ins_cost(INSN_COST); format %{ "eon $dst, $src1, zr" %} ins_encode %{ __ eon(as_Register($dst$$reg), as_Register($src1$$reg), zr, Assembler::LSL, 0); %} ins_pipe(ialu_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct regI_not_reg(iRegINoSp dst, iRegIorL2I src1, immI_M1 m1, rFlagsReg cr) %{ match(Set dst (XorI src1 m1)); ins_cost(INSN_COST); format %{ "eonw $dst, $src1, zr" %} ins_encode %{ __ eonw(as_Register($dst$$reg), as_Register($src1$$reg), zr, Assembler::LSL, 0); %} ins_pipe(ialu_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct NegI_reg_URShift_reg(iRegINoSp dst, immI0 zero, iRegIorL2I src1, immI src2) %{ match(Set dst (SubI zero (URShiftI src1 src2))); ins_cost(1.9 * INSN_COST); format %{ "negw $dst, $src1, LSR $src2" %} ins_encode %{ __ negw(as_Register($dst$$reg), as_Register($src1$$reg), Assembler::LSR, $src2$$constant & 0x1f); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct NegI_reg_RShift_reg(iRegINoSp dst, immI0 zero, iRegIorL2I src1, immI src2) %{ match(Set dst (SubI zero (RShiftI src1 src2))); ins_cost(1.9 * INSN_COST); format %{ "negw $dst, $src1, ASR $src2" %} ins_encode %{ __ negw(as_Register($dst$$reg), as_Register($src1$$reg), Assembler::ASR, $src2$$constant & 0x1f); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct NegI_reg_LShift_reg(iRegINoSp dst, immI0 zero, iRegIorL2I src1, immI src2) %{ match(Set dst (SubI zero (LShiftI src1 src2))); ins_cost(1.9 * INSN_COST); format %{ "negw $dst, $src1, LSL $src2" %} ins_encode %{ __ negw(as_Register($dst$$reg), as_Register($src1$$reg), Assembler::LSL, $src2$$constant & 0x1f); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct NegL_reg_URShift_reg(iRegLNoSp dst, immL0 zero, iRegL src1, immI src2) %{ match(Set dst (SubL zero (URShiftL src1 src2))); ins_cost(1.9 * INSN_COST); format %{ "neg $dst, $src1, LSR $src2" %} ins_encode %{ __ neg(as_Register($dst$$reg), as_Register($src1$$reg), Assembler::LSR, $src2$$constant & 0x3f); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct NegL_reg_RShift_reg(iRegLNoSp dst, immL0 zero, iRegL src1, immI src2) %{ match(Set dst (SubL zero (RShiftL src1 src2))); ins_cost(1.9 * INSN_COST); format %{ "neg $dst, $src1, ASR $src2" %} ins_encode %{ __ neg(as_Register($dst$$reg), as_Register($src1$$reg), Assembler::ASR, $src2$$constant & 0x3f); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct NegL_reg_LShift_reg(iRegLNoSp dst, immL0 zero, iRegL src1, immI src2) %{ match(Set dst (SubL zero (LShiftL src1 src2))); ins_cost(1.9 * INSN_COST); format %{ "neg $dst, $src1, LSL $src2" %} ins_encode %{ __ neg(as_Register($dst$$reg), as_Register($src1$$reg), Assembler::LSL, $src2$$constant & 0x3f); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AndI_reg_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_M1 m1) %{ match(Set dst (AndI src1 (XorI src2 m1))); ins_cost(INSN_COST); format %{ "bicw $dst, $src1, $src2" %} ins_encode %{ __ bicw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, 0); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AndL_reg_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immL_M1 m1) %{ match(Set dst (AndL src1 (XorL src2 m1))); ins_cost(INSN_COST); format %{ "bic $dst, $src1, $src2" %} ins_encode %{ __ bic(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, 0); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct OrI_reg_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_M1 m1) %{ match(Set dst (OrI src1 (XorI src2 m1))); ins_cost(INSN_COST); format %{ "ornw $dst, $src1, $src2" %} ins_encode %{ __ ornw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, 0); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct OrL_reg_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immL_M1 m1) %{ match(Set dst (OrL src1 (XorL src2 m1))); ins_cost(INSN_COST); format %{ "orn $dst, $src1, $src2" %} ins_encode %{ __ orn(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, 0); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct XorI_reg_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_M1 m1) %{ match(Set dst (XorI m1 (XorI src2 src1))); ins_cost(INSN_COST); format %{ "eonw $dst, $src1, $src2" %} ins_encode %{ __ eonw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, 0); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct XorL_reg_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immL_M1 m1) %{ match(Set dst (XorL m1 (XorL src2 src1))); ins_cost(INSN_COST); format %{ "eon $dst, $src1, $src2" %} ins_encode %{ __ eon(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, 0); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val & (-1 ^ (val >>> shift)) ==> bicw instruct AndI_reg_URShift_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (AndI src1 (XorI(URShiftI src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "bicw $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ bicw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val & (-1 ^ (val >>> shift)) ==> bic instruct AndL_reg_URShift_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (AndL src1 (XorL(URShiftL src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "bic $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ bic(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val & (-1 ^ (val >> shift)) ==> bicw instruct AndI_reg_RShift_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (AndI src1 (XorI(RShiftI src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "bicw $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ bicw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val & (-1 ^ (val >> shift)) ==> bic instruct AndL_reg_RShift_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (AndL src1 (XorL(RShiftL src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "bic $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ bic(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val & (-1 ^ (val ror shift)) ==> bicw instruct AndI_reg_RotateRight_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (AndI src1 (XorI(RotateRight src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "bicw $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ bicw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val & (-1 ^ (val ror shift)) ==> bic instruct AndL_reg_RotateRight_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (AndL src1 (XorL(RotateRight src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "bic $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ bic(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val & (-1 ^ (val << shift)) ==> bicw instruct AndI_reg_LShift_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (AndI src1 (XorI(LShiftI src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "bicw $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ bicw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val & (-1 ^ (val << shift)) ==> bic instruct AndL_reg_LShift_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (AndL src1 (XorL(LShiftL src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "bic $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ bic(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val ^ (-1 ^ (val >>> shift)) ==> eonw instruct XorI_reg_URShift_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (XorI src4 (XorI(URShiftI src2 src3) src1))); ins_cost(1.9 * INSN_COST); format %{ "eonw $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ eonw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val ^ (-1 ^ (val >>> shift)) ==> eon instruct XorL_reg_URShift_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (XorL src4 (XorL(URShiftL src2 src3) src1))); ins_cost(1.9 * INSN_COST); format %{ "eon $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ eon(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val ^ (-1 ^ (val >> shift)) ==> eonw instruct XorI_reg_RShift_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (XorI src4 (XorI(RShiftI src2 src3) src1))); ins_cost(1.9 * INSN_COST); format %{ "eonw $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ eonw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val ^ (-1 ^ (val >> shift)) ==> eon instruct XorL_reg_RShift_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (XorL src4 (XorL(RShiftL src2 src3) src1))); ins_cost(1.9 * INSN_COST); format %{ "eon $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ eon(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val ^ (-1 ^ (val ror shift)) ==> eonw instruct XorI_reg_RotateRight_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (XorI src4 (XorI(RotateRight src2 src3) src1))); ins_cost(1.9 * INSN_COST); format %{ "eonw $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ eonw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val ^ (-1 ^ (val ror shift)) ==> eon instruct XorL_reg_RotateRight_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (XorL src4 (XorL(RotateRight src2 src3) src1))); ins_cost(1.9 * INSN_COST); format %{ "eon $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ eon(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val ^ (-1 ^ (val << shift)) ==> eonw instruct XorI_reg_LShift_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (XorI src4 (XorI(LShiftI src2 src3) src1))); ins_cost(1.9 * INSN_COST); format %{ "eonw $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ eonw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val ^ (-1 ^ (val << shift)) ==> eon instruct XorL_reg_LShift_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (XorL src4 (XorL(LShiftL src2 src3) src1))); ins_cost(1.9 * INSN_COST); format %{ "eon $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ eon(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val | (-1 ^ (val >>> shift)) ==> ornw instruct OrI_reg_URShift_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (OrI src1 (XorI(URShiftI src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "ornw $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ ornw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val | (-1 ^ (val >>> shift)) ==> orn instruct OrL_reg_URShift_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (OrL src1 (XorL(URShiftL src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "orn $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ orn(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val | (-1 ^ (val >> shift)) ==> ornw instruct OrI_reg_RShift_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (OrI src1 (XorI(RShiftI src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "ornw $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ ornw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val | (-1 ^ (val >> shift)) ==> orn instruct OrL_reg_RShift_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (OrL src1 (XorL(RShiftL src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "orn $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ orn(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val | (-1 ^ (val ror shift)) ==> ornw instruct OrI_reg_RotateRight_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (OrI src1 (XorI(RotateRight src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "ornw $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ ornw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val | (-1 ^ (val ror shift)) ==> orn instruct OrL_reg_RotateRight_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (OrL src1 (XorL(RotateRight src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "orn $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ orn(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val | (-1 ^ (val << shift)) ==> ornw instruct OrI_reg_LShift_not_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3, immI_M1 src4) %{ match(Set dst (OrI src1 (XorI(LShiftI src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "ornw $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ ornw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // val | (-1 ^ (val << shift)) ==> orn instruct OrL_reg_LShift_not_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3, immL_M1 src4) %{ match(Set dst (OrL src1 (XorL(LShiftL src2 src3) src4))); ins_cost(1.9 * INSN_COST); format %{ "orn $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ orn(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AndI_reg_URShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (AndI src1 (URShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "andw $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ andw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AndL_reg_URShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (AndL src1 (URShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "andr $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ andr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AndI_reg_RShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (AndI src1 (RShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "andw $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ andw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AndL_reg_RShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (AndL src1 (RShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "andr $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ andr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AndI_reg_LShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (AndI src1 (LShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "andw $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ andw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AndL_reg_LShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (AndL src1 (LShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "andr $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ andr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AndI_reg_RotateRight_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (AndI src1 (RotateRight src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "andw $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ andw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AndL_reg_RotateRight_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (AndL src1 (RotateRight src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "andr $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ andr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct XorI_reg_URShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (XorI src1 (URShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "eorw $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ eorw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct XorL_reg_URShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (XorL src1 (URShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "eor $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ eor(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct XorI_reg_RShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (XorI src1 (RShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "eorw $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ eorw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct XorL_reg_RShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (XorL src1 (RShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "eor $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ eor(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct XorI_reg_LShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (XorI src1 (LShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "eorw $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ eorw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct XorL_reg_LShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (XorL src1 (LShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "eor $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ eor(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct XorI_reg_RotateRight_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (XorI src1 (RotateRight src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "eorw $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ eorw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct XorL_reg_RotateRight_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (XorL src1 (RotateRight src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "eor $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ eor(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct OrI_reg_URShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (OrI src1 (URShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "orrw $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ orrw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct OrL_reg_URShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (OrL src1 (URShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "orr $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ orr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct OrI_reg_RShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (OrI src1 (RShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "orrw $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ orrw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct OrL_reg_RShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (OrL src1 (RShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "orr $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ orr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct OrI_reg_LShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (OrI src1 (LShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "orrw $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ orrw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct OrL_reg_LShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (OrL src1 (LShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "orr $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ orr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct OrI_reg_RotateRight_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (OrI src1 (RotateRight src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "orrw $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ orrw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct OrL_reg_RotateRight_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (OrL src1 (RotateRight src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "orr $dst, $src1, $src2, ROR $src3" %} ins_encode %{ __ orr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ROR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddI_reg_URShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (AddI src1 (URShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "addw $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ addw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddL_reg_URShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (AddL src1 (URShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddI_reg_RShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (AddI src1 (RShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "addw $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ addw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddL_reg_RShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (AddL src1 (RShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddI_reg_LShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (AddI src1 (LShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "addw $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ addw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddL_reg_LShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (AddL src1 (LShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubI_reg_URShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (SubI src1 (URShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "subw $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ subw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubL_reg_URShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (SubL src1 (URShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "sub $dst, $src1, $src2, LSR $src3" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubI_reg_RShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (SubI src1 (RShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "subw $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ subw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubL_reg_RShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (SubL src1 (RShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "sub $dst, $src1, $src2, ASR $src3" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::ASR, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubI_reg_LShift_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI src3) %{ match(Set dst (SubI src1 (LShiftI src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "subw $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ subw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubL_reg_LShift_reg(iRegLNoSp dst, iRegL src1, iRegL src2, immI src3) %{ match(Set dst (SubL src1 (LShiftL src2 src3))); ins_cost(1.9 * INSN_COST); format %{ "sub $dst, $src1, $src2, LSL $src3" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), Assembler::LSL, $src3$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // Shift Left followed by Shift Right. // This idiom is used by the compiler for the i2b bytecode etc. instruct sbfmL(iRegLNoSp dst, iRegL src, immI lshift_count, immI rshift_count) %{ match(Set dst (RShiftL (LShiftL src lshift_count) rshift_count)); ins_cost(INSN_COST * 2); format %{ "sbfm $dst, $src, $rshift_count - $lshift_count, #63 - $lshift_count" %} ins_encode %{ int lshift = $lshift_count$$constant & 63; int rshift = $rshift_count$$constant & 63; int s = 63 - lshift; int r = (rshift - lshift) & 63; __ sbfm(as_Register($dst$$reg), as_Register($src$$reg), r, s); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // Shift Left followed by Shift Right. // This idiom is used by the compiler for the i2b bytecode etc. instruct sbfmwI(iRegINoSp dst, iRegIorL2I src, immI lshift_count, immI rshift_count) %{ match(Set dst (RShiftI (LShiftI src lshift_count) rshift_count)); ins_cost(INSN_COST * 2); format %{ "sbfmw $dst, $src, $rshift_count - $lshift_count, #31 - $lshift_count" %} ins_encode %{ int lshift = $lshift_count$$constant & 31; int rshift = $rshift_count$$constant & 31; int s = 31 - lshift; int r = (rshift - lshift) & 31; __ sbfmw(as_Register($dst$$reg), as_Register($src$$reg), r, s); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // Shift Left followed by Shift Right. // This idiom is used by the compiler for the i2b bytecode etc. instruct ubfmL(iRegLNoSp dst, iRegL src, immI lshift_count, immI rshift_count) %{ match(Set dst (URShiftL (LShiftL src lshift_count) rshift_count)); ins_cost(INSN_COST * 2); format %{ "ubfm $dst, $src, $rshift_count - $lshift_count, #63 - $lshift_count" %} ins_encode %{ int lshift = $lshift_count$$constant & 63; int rshift = $rshift_count$$constant & 63; int s = 63 - lshift; int r = (rshift - lshift) & 63; __ ubfm(as_Register($dst$$reg), as_Register($src$$reg), r, s); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // Shift Left followed by Shift Right. // This idiom is used by the compiler for the i2b bytecode etc. instruct ubfmwI(iRegINoSp dst, iRegIorL2I src, immI lshift_count, immI rshift_count) %{ match(Set dst (URShiftI (LShiftI src lshift_count) rshift_count)); ins_cost(INSN_COST * 2); format %{ "ubfmw $dst, $src, $rshift_count - $lshift_count, #31 - $lshift_count" %} ins_encode %{ int lshift = $lshift_count$$constant & 31; int rshift = $rshift_count$$constant & 31; int s = 31 - lshift; int r = (rshift - lshift) & 31; __ ubfmw(as_Register($dst$$reg), as_Register($src$$reg), r, s); %} ins_pipe(ialu_reg_shift); %} // Bitfield extract with shift & mask // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct ubfxwI(iRegINoSp dst, iRegIorL2I src, immI rshift, immI_bitmask mask) %{ match(Set dst (AndI (URShiftI src rshift) mask)); // Make sure we are not going to exceed what ubfxw can do. predicate((exact_log2(n->in(2)->get_int() + 1) + (n->in(1)->in(2)->get_int() & 31)) <= (31 + 1)); ins_cost(INSN_COST); format %{ "ubfxw $dst, $src, $rshift, $mask" %} ins_encode %{ int rshift = $rshift$$constant & 31; intptr_t mask = $mask$$constant; int width = exact_log2(mask+1); __ ubfxw(as_Register($dst$$reg), as_Register($src$$reg), rshift, width); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct ubfxL(iRegLNoSp dst, iRegL src, immI rshift, immL_bitmask mask) %{ match(Set dst (AndL (URShiftL src rshift) mask)); // Make sure we are not going to exceed what ubfx can do. predicate((exact_log2_long(n->in(2)->get_long() + 1) + (n->in(1)->in(2)->get_int() & 63)) <= (63 + 1)); ins_cost(INSN_COST); format %{ "ubfx $dst, $src, $rshift, $mask" %} ins_encode %{ int rshift = $rshift$$constant & 63; intptr_t mask = $mask$$constant; int width = exact_log2_long(mask+1); __ ubfx(as_Register($dst$$reg), as_Register($src$$reg), rshift, width); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // We can use ubfx when extending an And with a mask when we know mask // is positive. We know that because immI_bitmask guarantees it. instruct ubfxIConvI2L(iRegLNoSp dst, iRegIorL2I src, immI rshift, immI_bitmask mask) %{ match(Set dst (ConvI2L (AndI (URShiftI src rshift) mask))); // Make sure we are not going to exceed what ubfxw can do. predicate((exact_log2(n->in(1)->in(2)->get_int() + 1) + (n->in(1)->in(1)->in(2)->get_int() & 31)) <= (31 + 1)); ins_cost(INSN_COST * 2); format %{ "ubfx $dst, $src, $rshift, $mask" %} ins_encode %{ int rshift = $rshift$$constant & 31; intptr_t mask = $mask$$constant; int width = exact_log2(mask+1); __ ubfx(as_Register($dst$$reg), as_Register($src$$reg), rshift, width); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // We can use ubfiz when masking by a positive number and then left shifting the result. // We know that the mask is positive because immI_bitmask guarantees it. instruct ubfizwI(iRegINoSp dst, iRegIorL2I src, immI lshift, immI_bitmask mask) %{ match(Set dst (LShiftI (AndI src mask) lshift)); predicate((exact_log2(n->in(1)->in(2)->get_int() + 1) + (n->in(2)->get_int() & 31)) <= (31 + 1)); ins_cost(INSN_COST); format %{ "ubfizw $dst, $src, $lshift, $mask" %} ins_encode %{ int lshift = $lshift$$constant & 31; intptr_t mask = $mask$$constant; int width = exact_log2(mask+1); __ ubfizw(as_Register($dst$$reg), as_Register($src$$reg), lshift, width); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // We can use ubfiz when masking by a positive number and then left shifting the result. // We know that the mask is positive because immL_bitmask guarantees it. instruct ubfizL(iRegLNoSp dst, iRegL src, immI lshift, immL_bitmask mask) %{ match(Set dst (LShiftL (AndL src mask) lshift)); predicate((exact_log2_long(n->in(1)->in(2)->get_long() + 1) + (n->in(2)->get_int() & 63)) <= (63 + 1)); ins_cost(INSN_COST); format %{ "ubfiz $dst, $src, $lshift, $mask" %} ins_encode %{ int lshift = $lshift$$constant & 63; intptr_t mask = $mask$$constant; int width = exact_log2_long(mask+1); __ ubfiz(as_Register($dst$$reg), as_Register($src$$reg), lshift, width); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // We can use ubfiz when masking by a positive number and then left shifting the result. // We know that the mask is positive because immI_bitmask guarantees it. instruct ubfizwIConvI2L(iRegLNoSp dst, iRegIorL2I src, immI lshift, immI_bitmask mask) %{ match(Set dst (ConvI2L (LShiftI (AndI src mask) lshift))); predicate((exact_log2(n->in(1)->in(1)->in(2)->get_int() + 1) + (n->in(1)->in(2)->get_int() & 31)) <= 31); ins_cost(INSN_COST); format %{ "ubfizw $dst, $src, $lshift, $mask" %} ins_encode %{ int lshift = $lshift$$constant & 31; intptr_t mask = $mask$$constant; int width = exact_log2(mask+1); __ ubfizw(as_Register($dst$$reg), as_Register($src$$reg), lshift, width); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // We can use ubfiz when masking by a positive number and then left shifting the result. // We know that the mask is positive because immL_bitmask guarantees it. instruct ubfizLConvL2I(iRegINoSp dst, iRegL src, immI lshift, immL_positive_bitmaskI mask) %{ match(Set dst (ConvL2I (LShiftL (AndL src mask) lshift))); predicate((exact_log2_long(n->in(1)->in(1)->in(2)->get_long() + 1) + (n->in(1)->in(2)->get_int() & 63)) <= 31); ins_cost(INSN_COST); format %{ "ubfiz $dst, $src, $lshift, $mask" %} ins_encode %{ int lshift = $lshift$$constant & 63; intptr_t mask = $mask$$constant; int width = exact_log2_long(mask+1); __ ubfiz(as_Register($dst$$reg), as_Register($src$$reg), lshift, width); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // If there is a convert I to L block between and AndI and a LShiftL, we can also match ubfiz instruct ubfizIConvI2L(iRegLNoSp dst, iRegIorL2I src, immI lshift, immI_bitmask mask) %{ match(Set dst (LShiftL (ConvI2L (AndI src mask)) lshift)); predicate((exact_log2(n->in(1)->in(1)->in(2)->get_int() + 1) + (n->in(2)->get_int() & 63)) <= (63 + 1)); ins_cost(INSN_COST); format %{ "ubfiz $dst, $src, $lshift, $mask" %} ins_encode %{ int lshift = $lshift$$constant & 63; intptr_t mask = $mask$$constant; int width = exact_log2(mask+1); __ ubfiz(as_Register($dst$$reg), as_Register($src$$reg), lshift, width); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // If there is a convert L to I block between and AndL and a LShiftI, we can also match ubfiz instruct ubfizLConvL2Ix(iRegINoSp dst, iRegL src, immI lshift, immL_positive_bitmaskI mask) %{ match(Set dst (LShiftI (ConvL2I (AndL src mask)) lshift)); predicate((exact_log2_long(n->in(1)->in(1)->in(2)->get_long() + 1) + (n->in(2)->get_int() & 31)) <= 31); ins_cost(INSN_COST); format %{ "ubfiz $dst, $src, $lshift, $mask" %} ins_encode %{ int lshift = $lshift$$constant & 31; intptr_t mask = $mask$$constant; int width = exact_log2(mask+1); __ ubfiz(as_Register($dst$$reg), as_Register($src$$reg), lshift, width); %} ins_pipe(ialu_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE // Can skip int2long conversions after AND with small bitmask instruct ubfizIConvI2LAndI(iRegLNoSp dst, iRegI src, immI_bitmask msk) %{ match(Set dst (ConvI2L (AndI src msk))); ins_cost(INSN_COST); format %{ "ubfiz $dst, $src, 0, exact_log2($msk + 1) " %} ins_encode %{ __ ubfiz(as_Register($dst$$reg), as_Register($src$$reg), 0, exact_log2($msk$$constant + 1)); %} ins_pipe(ialu_reg_shift); %} // Rotations // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct extrOrL(iRegLNoSp dst, iRegL src1, iRegL src2, immI lshift, immI rshift, rFlagsReg cr) %{ match(Set dst (OrL (LShiftL src1 lshift) (URShiftL src2 rshift))); predicate(0 == (((n->in(1)->in(2)->get_int() & 63) + (n->in(2)->in(2)->get_int() & 63)) & 63)); ins_cost(INSN_COST); format %{ "extr $dst, $src1, $src2, #$rshift" %} ins_encode %{ __ extr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), $rshift$$constant & 63); %} ins_pipe(ialu_reg_reg_extr); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct extrOrI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI lshift, immI rshift, rFlagsReg cr) %{ match(Set dst (OrI (LShiftI src1 lshift) (URShiftI src2 rshift))); predicate(0 == (((n->in(1)->in(2)->get_int() & 31) + (n->in(2)->in(2)->get_int() & 31)) & 31)); ins_cost(INSN_COST); format %{ "extr $dst, $src1, $src2, #$rshift" %} ins_encode %{ __ extrw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), $rshift$$constant & 31); %} ins_pipe(ialu_reg_reg_extr); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct extrAddL(iRegLNoSp dst, iRegL src1, iRegL src2, immI lshift, immI rshift, rFlagsReg cr) %{ match(Set dst (AddL (LShiftL src1 lshift) (URShiftL src2 rshift))); predicate(0 == (((n->in(1)->in(2)->get_int() & 63) + (n->in(2)->in(2)->get_int() & 63)) & 63)); ins_cost(INSN_COST); format %{ "extr $dst, $src1, $src2, #$rshift" %} ins_encode %{ __ extr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), $rshift$$constant & 63); %} ins_pipe(ialu_reg_reg_extr); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct extrAddI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI lshift, immI rshift, rFlagsReg cr) %{ match(Set dst (AddI (LShiftI src1 lshift) (URShiftI src2 rshift))); predicate(0 == (((n->in(1)->in(2)->get_int() & 31) + (n->in(2)->in(2)->get_int() & 31)) & 31)); ins_cost(INSN_COST); format %{ "extr $dst, $src1, $src2, #$rshift" %} ins_encode %{ __ extrw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), $rshift$$constant & 31); %} ins_pipe(ialu_reg_reg_extr); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct rorI_imm(iRegINoSp dst, iRegI src, immI shift) %{ match(Set dst (RotateRight src shift)); ins_cost(INSN_COST); format %{ "ror $dst, $src, $shift" %} ins_encode %{ __ extrw(as_Register($dst$$reg), as_Register($src$$reg), as_Register($src$$reg), $shift$$constant & 0x1f); %} ins_pipe(ialu_reg_reg_vshift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct rorL_imm(iRegLNoSp dst, iRegL src, immI shift) %{ match(Set dst (RotateRight src shift)); ins_cost(INSN_COST); format %{ "ror $dst, $src, $shift" %} ins_encode %{ __ extr(as_Register($dst$$reg), as_Register($src$$reg), as_Register($src$$reg), $shift$$constant & 0x3f); %} ins_pipe(ialu_reg_reg_vshift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct rorI_reg(iRegINoSp dst, iRegI src, iRegI shift) %{ match(Set dst (RotateRight src shift)); ins_cost(INSN_COST); format %{ "ror $dst, $src, $shift" %} ins_encode %{ __ rorvw(as_Register($dst$$reg), as_Register($src$$reg), as_Register($shift$$reg)); %} ins_pipe(ialu_reg_reg_vshift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct rorL_reg(iRegLNoSp dst, iRegL src, iRegI shift) %{ match(Set dst (RotateRight src shift)); ins_cost(INSN_COST); format %{ "ror $dst, $src, $shift" %} ins_encode %{ __ rorv(as_Register($dst$$reg), as_Register($src$$reg), as_Register($shift$$reg)); %} ins_pipe(ialu_reg_reg_vshift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct rolI_reg(iRegINoSp dst, iRegI src, iRegI shift) %{ match(Set dst (RotateLeft src shift)); ins_cost(INSN_COST); format %{ "rol $dst, $src, $shift" %} ins_encode %{ __ subw(rscratch1, zr, as_Register($shift$$reg)); __ rorvw(as_Register($dst$$reg), as_Register($src$$reg), rscratch1); %} ins_pipe(ialu_reg_reg_vshift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct rolL_reg(iRegLNoSp dst, iRegL src, iRegI shift) %{ match(Set dst (RotateLeft src shift)); ins_cost(INSN_COST); format %{ "rol $dst, $src, $shift" %} ins_encode %{ __ subw(rscratch1, zr, as_Register($shift$$reg)); __ rorv(as_Register($dst$$reg), as_Register($src$$reg), rscratch1); %} ins_pipe(ialu_reg_reg_vshift); %} // Add/subtract (extended) // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtI(iRegLNoSp dst, iRegL src1, iRegIorL2I src2, rFlagsReg cr) %{ match(Set dst (AddL src1 (ConvI2L src2))); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2, sxtw" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtw); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtI(iRegLNoSp dst, iRegL src1, iRegIorL2I src2, rFlagsReg cr) %{ match(Set dst (SubL src1 (ConvI2L src2))); ins_cost(INSN_COST); format %{ "sub $dst, $src1, $src2, sxtw" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtw); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtI_sxth(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_16 lshift, immI_16 rshift, rFlagsReg cr) %{ match(Set dst (AddI src1 (RShiftI (LShiftI src2 lshift) rshift))); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2, sxth" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxth); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtI_sxtb(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_24 lshift, immI_24 rshift, rFlagsReg cr) %{ match(Set dst (AddI src1 (RShiftI (LShiftI src2 lshift) rshift))); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2, sxtb" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtb); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtI_uxtb(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_24 lshift, immI_24 rshift, rFlagsReg cr) %{ match(Set dst (AddI src1 (URShiftI (LShiftI src2 lshift) rshift))); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2, uxtb" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtb); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_sxth(iRegLNoSp dst, iRegL src1, iRegL src2, immI_48 lshift, immI_48 rshift, rFlagsReg cr) %{ match(Set dst (AddL src1 (RShiftL (LShiftL src2 lshift) rshift))); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2, sxth" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxth); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_sxtw(iRegLNoSp dst, iRegL src1, iRegL src2, immI_32 lshift, immI_32 rshift, rFlagsReg cr) %{ match(Set dst (AddL src1 (RShiftL (LShiftL src2 lshift) rshift))); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2, sxtw" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtw); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_sxtb(iRegLNoSp dst, iRegL src1, iRegL src2, immI_56 lshift, immI_56 rshift, rFlagsReg cr) %{ match(Set dst (AddL src1 (RShiftL (LShiftL src2 lshift) rshift))); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2, sxtb" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtb); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_uxtb(iRegLNoSp dst, iRegL src1, iRegL src2, immI_56 lshift, immI_56 rshift, rFlagsReg cr) %{ match(Set dst (AddL src1 (URShiftL (LShiftL src2 lshift) rshift))); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2, uxtb" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtb); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtI_uxtb_and(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_255 mask, rFlagsReg cr) %{ match(Set dst (AddI src1 (AndI src2 mask))); ins_cost(INSN_COST); format %{ "addw $dst, $src1, $src2, uxtb" %} ins_encode %{ __ addw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtb); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtI_uxth_and(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_65535 mask, rFlagsReg cr) %{ match(Set dst (AddI src1 (AndI src2 mask))); ins_cost(INSN_COST); format %{ "addw $dst, $src1, $src2, uxth" %} ins_encode %{ __ addw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxth); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_uxtb_and(iRegLNoSp dst, iRegL src1, iRegL src2, immL_255 mask, rFlagsReg cr) %{ match(Set dst (AddL src1 (AndL src2 mask))); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2, uxtb" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtb); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_uxth_and(iRegLNoSp dst, iRegL src1, iRegL src2, immL_65535 mask, rFlagsReg cr) %{ match(Set dst (AddL src1 (AndL src2 mask))); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2, uxth" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxth); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_uxtw_and(iRegLNoSp dst, iRegL src1, iRegL src2, immL_4294967295 mask, rFlagsReg cr) %{ match(Set dst (AddL src1 (AndL src2 mask))); ins_cost(INSN_COST); format %{ "add $dst, $src1, $src2, uxtw" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtw); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtI_uxtb_and(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_255 mask, rFlagsReg cr) %{ match(Set dst (SubI src1 (AndI src2 mask))); ins_cost(INSN_COST); format %{ "subw $dst, $src1, $src2, uxtb" %} ins_encode %{ __ subw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtb); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtI_uxth_and(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_65535 mask, rFlagsReg cr) %{ match(Set dst (SubI src1 (AndI src2 mask))); ins_cost(INSN_COST); format %{ "subw $dst, $src1, $src2, uxth" %} ins_encode %{ __ subw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxth); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtL_uxtb_and(iRegLNoSp dst, iRegL src1, iRegL src2, immL_255 mask, rFlagsReg cr) %{ match(Set dst (SubL src1 (AndL src2 mask))); ins_cost(INSN_COST); format %{ "sub $dst, $src1, $src2, uxtb" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtb); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtL_uxth_and(iRegLNoSp dst, iRegL src1, iRegL src2, immL_65535 mask, rFlagsReg cr) %{ match(Set dst (SubL src1 (AndL src2 mask))); ins_cost(INSN_COST); format %{ "sub $dst, $src1, $src2, uxth" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxth); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtL_uxtw_and(iRegLNoSp dst, iRegL src1, iRegL src2, immL_4294967295 mask, rFlagsReg cr) %{ match(Set dst (SubL src1 (AndL src2 mask))); ins_cost(INSN_COST); format %{ "sub $dst, $src1, $src2, uxtw" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtw); %} ins_pipe(ialu_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_sxtb_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immIExt lshift2, immI_56 lshift1, immI_56 rshift1, rFlagsReg cr) %{ match(Set dst (AddL src1 (LShiftL (RShiftL (LShiftL src2 lshift1) rshift1) lshift2))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, sxtb #lshift2" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtb, ($lshift2$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_sxth_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immIExt lshift2, immI_48 lshift1, immI_48 rshift1, rFlagsReg cr) %{ match(Set dst (AddL src1 (LShiftL (RShiftL (LShiftL src2 lshift1) rshift1) lshift2))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, sxth #lshift2" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxth, ($lshift2$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_sxtw_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immIExt lshift2, immI_32 lshift1, immI_32 rshift1, rFlagsReg cr) %{ match(Set dst (AddL src1 (LShiftL (RShiftL (LShiftL src2 lshift1) rshift1) lshift2))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, sxtw #lshift2" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtw, ($lshift2$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtL_sxtb_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immIExt lshift2, immI_56 lshift1, immI_56 rshift1, rFlagsReg cr) %{ match(Set dst (SubL src1 (LShiftL (RShiftL (LShiftL src2 lshift1) rshift1) lshift2))); ins_cost(1.9 * INSN_COST); format %{ "sub $dst, $src1, $src2, sxtb #lshift2" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtb, ($lshift2$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtL_sxth_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immIExt lshift2, immI_48 lshift1, immI_48 rshift1, rFlagsReg cr) %{ match(Set dst (SubL src1 (LShiftL (RShiftL (LShiftL src2 lshift1) rshift1) lshift2))); ins_cost(1.9 * INSN_COST); format %{ "sub $dst, $src1, $src2, sxth #lshift2" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxth, ($lshift2$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtL_sxtw_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immIExt lshift2, immI_32 lshift1, immI_32 rshift1, rFlagsReg cr) %{ match(Set dst (SubL src1 (LShiftL (RShiftL (LShiftL src2 lshift1) rshift1) lshift2))); ins_cost(1.9 * INSN_COST); format %{ "sub $dst, $src1, $src2, sxtw #lshift2" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtw, ($lshift2$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtI_sxtb_shift(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immIExt lshift2, immI_24 lshift1, immI_24 rshift1, rFlagsReg cr) %{ match(Set dst (AddI src1 (LShiftI (RShiftI (LShiftI src2 lshift1) rshift1) lshift2))); ins_cost(1.9 * INSN_COST); format %{ "addw $dst, $src1, $src2, sxtb #lshift2" %} ins_encode %{ __ addw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtb, ($lshift2$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtI_sxth_shift(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immIExt lshift2, immI_16 lshift1, immI_16 rshift1, rFlagsReg cr) %{ match(Set dst (AddI src1 (LShiftI (RShiftI (LShiftI src2 lshift1) rshift1) lshift2))); ins_cost(1.9 * INSN_COST); format %{ "addw $dst, $src1, $src2, sxth #lshift2" %} ins_encode %{ __ addw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxth, ($lshift2$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtI_sxtb_shift(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immIExt lshift2, immI_24 lshift1, immI_24 rshift1, rFlagsReg cr) %{ match(Set dst (SubI src1 (LShiftI (RShiftI (LShiftI src2 lshift1) rshift1) lshift2))); ins_cost(1.9 * INSN_COST); format %{ "subw $dst, $src1, $src2, sxtb #lshift2" %} ins_encode %{ __ subw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtb, ($lshift2$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtI_sxth_shift(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immIExt lshift2, immI_16 lshift1, immI_16 rshift1, rFlagsReg cr) %{ match(Set dst (SubI src1 (LShiftI (RShiftI (LShiftI src2 lshift1) rshift1) lshift2))); ins_cost(1.9 * INSN_COST); format %{ "subw $dst, $src1, $src2, sxth #lshift2" %} ins_encode %{ __ subw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxth, ($lshift2$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtI_shift(iRegLNoSp dst, iRegL src1, iRegIorL2I src2, immIExt lshift, rFlagsReg cr) %{ match(Set dst (AddL src1 (LShiftL (ConvI2L src2) lshift))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, sxtw #lshift" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtw, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtI_shift(iRegLNoSp dst, iRegL src1, iRegIorL2I src2, immIExt lshift, rFlagsReg cr) %{ match(Set dst (SubL src1 (LShiftL (ConvI2L src2) lshift))); ins_cost(1.9 * INSN_COST); format %{ "sub $dst, $src1, $src2, sxtw #lshift" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::sxtw, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_uxtb_and_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immL_255 mask, immIExt lshift, rFlagsReg cr) %{ match(Set dst (AddL src1 (LShiftL (AndL src2 mask) lshift))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, uxtb #lshift" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtb, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_uxth_and_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immL_65535 mask, immIExt lshift, rFlagsReg cr) %{ match(Set dst (AddL src1 (LShiftL (AndL src2 mask) lshift))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, uxth #lshift" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxth, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtL_uxtw_and_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immL_4294967295 mask, immIExt lshift, rFlagsReg cr) %{ match(Set dst (AddL src1 (LShiftL (AndL src2 mask) lshift))); ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, uxtw #lshift" %} ins_encode %{ __ add(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtw, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtL_uxtb_and_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immL_255 mask, immIExt lshift, rFlagsReg cr) %{ match(Set dst (SubL src1 (LShiftL (AndL src2 mask) lshift))); ins_cost(1.9 * INSN_COST); format %{ "sub $dst, $src1, $src2, uxtb #lshift" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtb, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtL_uxth_and_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immL_65535 mask, immIExt lshift, rFlagsReg cr) %{ match(Set dst (SubL src1 (LShiftL (AndL src2 mask) lshift))); ins_cost(1.9 * INSN_COST); format %{ "sub $dst, $src1, $src2, uxth #lshift" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxth, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtL_uxtw_and_shift(iRegLNoSp dst, iRegL src1, iRegL src2, immL_4294967295 mask, immIExt lshift, rFlagsReg cr) %{ match(Set dst (SubL src1 (LShiftL (AndL src2 mask) lshift))); ins_cost(1.9 * INSN_COST); format %{ "sub $dst, $src1, $src2, uxtw #lshift" %} ins_encode %{ __ sub(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtw, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtI_uxtb_and_shift(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_255 mask, immIExt lshift, rFlagsReg cr) %{ match(Set dst (AddI src1 (LShiftI (AndI src2 mask) lshift))); ins_cost(1.9 * INSN_COST); format %{ "addw $dst, $src1, $src2, uxtb #lshift" %} ins_encode %{ __ addw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtb, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct AddExtI_uxth_and_shift(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_65535 mask, immIExt lshift, rFlagsReg cr) %{ match(Set dst (AddI src1 (LShiftI (AndI src2 mask) lshift))); ins_cost(1.9 * INSN_COST); format %{ "addw $dst, $src1, $src2, uxth #lshift" %} ins_encode %{ __ addw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxth, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtI_uxtb_and_shift(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_255 mask, immIExt lshift, rFlagsReg cr) %{ match(Set dst (SubI src1 (LShiftI (AndI src2 mask) lshift))); ins_cost(1.9 * INSN_COST); format %{ "subw $dst, $src1, $src2, uxtb #lshift" %} ins_encode %{ __ subw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxtb, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct SubExtI_uxth_and_shift(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI_65535 mask, immIExt lshift, rFlagsReg cr) %{ match(Set dst (SubI src1 (LShiftI (AndI src2 mask) lshift))); ins_cost(1.9 * INSN_COST); format %{ "subw $dst, $src1, $src2, uxth #lshift" %} ins_encode %{ __ subw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg), ext::uxth, ($lshift$$constant)); %} ins_pipe(ialu_reg_reg_shift); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct cmovI_reg_reg_lt(iRegINoSp dst, iRegI src1, iRegI src2, rFlagsReg cr) %{ effect(DEF dst, USE src1, USE src2, USE cr); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src1, $src2 lt\t" %} ins_encode %{ __ cselw($dst$$Register, $src1$$Register, $src2$$Register, Assembler::LT); %} ins_pipe(icond_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct cmovI_reg_reg_gt(iRegINoSp dst, iRegI src1, iRegI src2, rFlagsReg cr) %{ effect(DEF dst, USE src1, USE src2, USE cr); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src1, $src2 gt\t" %} ins_encode %{ __ cselw($dst$$Register, $src1$$Register, $src2$$Register, Assembler::GT); %} ins_pipe(icond_reg_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct cmovI_reg_imm0_lt(iRegINoSp dst, iRegI src1, rFlagsReg cr) %{ effect(DEF dst, USE src1, USE cr); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src1, zr lt\t" %} ins_encode %{ __ cselw($dst$$Register, $src1$$Register, zr, Assembler::LT); %} ins_pipe(icond_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct cmovI_reg_imm0_gt(iRegINoSp dst, iRegI src1, rFlagsReg cr) %{ effect(DEF dst, USE src1, USE cr); ins_cost(INSN_COST * 2); format %{ "cselw $dst, $src1, zr gt\t" %} ins_encode %{ __ cselw($dst$$Register, $src1$$Register, zr, Assembler::GT); %} ins_pipe(icond_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct cmovI_reg_imm1_le(iRegINoSp dst, iRegI src1, rFlagsReg cr) %{ effect(DEF dst, USE src1, USE cr); ins_cost(INSN_COST * 2); format %{ "csincw $dst, $src1, zr le\t" %} ins_encode %{ __ csincw($dst$$Register, $src1$$Register, zr, Assembler::LE); %} ins_pipe(icond_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct cmovI_reg_imm1_gt(iRegINoSp dst, iRegI src1, rFlagsReg cr) %{ effect(DEF dst, USE src1, USE cr); ins_cost(INSN_COST * 2); format %{ "csincw $dst, $src1, zr gt\t" %} ins_encode %{ __ csincw($dst$$Register, $src1$$Register, zr, Assembler::GT); %} ins_pipe(icond_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct cmovI_reg_immM1_lt(iRegINoSp dst, iRegI src1, rFlagsReg cr) %{ effect(DEF dst, USE src1, USE cr); ins_cost(INSN_COST * 2); format %{ "csinvw $dst, $src1, zr lt\t" %} ins_encode %{ __ csinvw($dst$$Register, $src1$$Register, zr, Assembler::LT); %} ins_pipe(icond_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct cmovI_reg_immM1_ge(iRegINoSp dst, iRegI src1, rFlagsReg cr) %{ effect(DEF dst, USE src1, USE cr); ins_cost(INSN_COST * 2); format %{ "csinvw $dst, $src1, zr ge\t" %} ins_encode %{ __ csinvw($dst$$Register, $src1$$Register, zr, Assembler::GE); %} ins_pipe(icond_reg); %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct minI_reg_imm0(iRegINoSp dst, iRegIorL2I src, immI0 imm) %{ match(Set dst (MinI src imm)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_imm0_lt(dst, src, cr); %} %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct minI_imm0_reg(iRegINoSp dst, immI0 imm, iRegIorL2I src) %{ match(Set dst (MinI imm src)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_imm0_lt(dst, src, cr); %} %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct minI_reg_imm1(iRegINoSp dst, iRegIorL2I src, immI_1 imm) %{ match(Set dst (MinI src imm)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_imm1_le(dst, src, cr); %} %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct minI_imm1_reg(iRegINoSp dst, immI_1 imm, iRegIorL2I src) %{ match(Set dst (MinI imm src)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_imm1_le(dst, src, cr); %} %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct minI_reg_immM1(iRegINoSp dst, iRegIorL2I src, immI_M1 imm) %{ match(Set dst (MinI src imm)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_immM1_lt(dst, src, cr); %} %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct minI_immM1_reg(iRegINoSp dst, immI_M1 imm, iRegIorL2I src) %{ match(Set dst (MinI imm src)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_immM1_lt(dst, src, cr); %} %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct maxI_reg_imm0(iRegINoSp dst, iRegIorL2I src, immI0 imm) %{ match(Set dst (MaxI src imm)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_imm0_gt(dst, src, cr); %} %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct maxI_imm0_reg(iRegINoSp dst, immI0 imm, iRegIorL2I src) %{ match(Set dst (MaxI imm src)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_imm0_gt(dst, src, cr); %} %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct maxI_reg_imm1(iRegINoSp dst, iRegIorL2I src, immI_1 imm) %{ match(Set dst (MaxI src imm)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_imm1_gt(dst, src, cr); %} %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct maxI_imm1_reg(iRegINoSp dst, immI_1 imm, iRegIorL2I src) %{ match(Set dst (MaxI imm src)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_imm1_gt(dst, src, cr); %} %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct maxI_reg_immM1(iRegINoSp dst, iRegIorL2I src, immI_M1 imm) %{ match(Set dst (MaxI src imm)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_immM1_ge(dst, src, cr); %} %} // This pattern is automatically generated from aarch64_ad.m4 // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct maxI_immM1_reg(iRegINoSp dst, immI_M1 imm, iRegIorL2I src) %{ match(Set dst (MaxI imm src)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_imm0(cr, src); cmovI_reg_immM1_ge(dst, src, cr); %} %} // END This section of the file is automatically generated. Do not edit -------------- // ============================================================================ // Floating Point Arithmetic Instructions instruct addF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (AddF src1 src2)); ins_cost(INSN_COST * 5); format %{ "fadds $dst, $src1, $src2" %} ins_encode %{ __ fadds(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_dop_reg_reg_s); %} instruct addD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ match(Set dst (AddD src1 src2)); ins_cost(INSN_COST * 5); format %{ "faddd $dst, $src1, $src2" %} ins_encode %{ __ faddd(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_dop_reg_reg_d); %} instruct subF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (SubF src1 src2)); ins_cost(INSN_COST * 5); format %{ "fsubs $dst, $src1, $src2" %} ins_encode %{ __ fsubs(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_dop_reg_reg_s); %} instruct subD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ match(Set dst (SubD src1 src2)); ins_cost(INSN_COST * 5); format %{ "fsubd $dst, $src1, $src2" %} ins_encode %{ __ fsubd(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_dop_reg_reg_d); %} instruct mulF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (MulF src1 src2)); ins_cost(INSN_COST * 6); format %{ "fmuls $dst, $src1, $src2" %} ins_encode %{ __ fmuls(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_dop_reg_reg_s); %} instruct mulD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ match(Set dst (MulD src1 src2)); ins_cost(INSN_COST * 6); format %{ "fmuld $dst, $src1, $src2" %} ins_encode %{ __ fmuld(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_dop_reg_reg_d); %} // src1 * src2 + src3 instruct maddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{ predicate(UseFMA); match(Set dst (FmaF src3 (Binary src1 src2))); format %{ "fmadds $dst, $src1, $src2, $src3" %} ins_encode %{ __ fmadds(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg)); %} ins_pipe(pipe_class_default); %} // src1 * src2 + src3 instruct maddD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{ predicate(UseFMA); match(Set dst (FmaD src3 (Binary src1 src2))); format %{ "fmaddd $dst, $src1, $src2, $src3" %} ins_encode %{ __ fmaddd(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg)); %} ins_pipe(pipe_class_default); %} // -src1 * src2 + src3 instruct msubF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{ predicate(UseFMA); match(Set dst (FmaF src3 (Binary (NegF src1) src2))); match(Set dst (FmaF src3 (Binary src1 (NegF src2)))); format %{ "fmsubs $dst, $src1, $src2, $src3" %} ins_encode %{ __ fmsubs(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg)); %} ins_pipe(pipe_class_default); %} // -src1 * src2 + src3 instruct msubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{ predicate(UseFMA); match(Set dst (FmaD src3 (Binary (NegD src1) src2))); match(Set dst (FmaD src3 (Binary src1 (NegD src2)))); format %{ "fmsubd $dst, $src1, $src2, $src3" %} ins_encode %{ __ fmsubd(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg)); %} ins_pipe(pipe_class_default); %} // -src1 * src2 - src3 instruct mnaddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{ predicate(UseFMA); match(Set dst (FmaF (NegF src3) (Binary (NegF src1) src2))); match(Set dst (FmaF (NegF src3) (Binary src1 (NegF src2)))); format %{ "fnmadds $dst, $src1, $src2, $src3" %} ins_encode %{ __ fnmadds(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg)); %} ins_pipe(pipe_class_default); %} // -src1 * src2 - src3 instruct mnaddD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{ predicate(UseFMA); match(Set dst (FmaD (NegD src3) (Binary (NegD src1) src2))); match(Set dst (FmaD (NegD src3) (Binary src1 (NegD src2)))); format %{ "fnmaddd $dst, $src1, $src2, $src3" %} ins_encode %{ __ fnmaddd(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg)); %} ins_pipe(pipe_class_default); %} // src1 * src2 - src3 instruct mnsubF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3, immF0 zero) %{ predicate(UseFMA); match(Set dst (FmaF (NegF src3) (Binary src1 src2))); format %{ "fnmsubs $dst, $src1, $src2, $src3" %} ins_encode %{ __ fnmsubs(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg)); %} ins_pipe(pipe_class_default); %} // src1 * src2 - src3 instruct mnsubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3, immD0 zero) %{ predicate(UseFMA); match(Set dst (FmaD (NegD src3) (Binary src1 src2))); format %{ "fnmsubd $dst, $src1, $src2, $src3" %} ins_encode %{ // n.b. insn name should be fnmsubd __ fnmsub(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg)); %} ins_pipe(pipe_class_default); %} // Math.max(FF)F instruct maxF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (MaxF src1 src2)); format %{ "fmaxs $dst, $src1, $src2" %} ins_encode %{ __ fmaxs(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_dop_reg_reg_s); %} // Math.min(FF)F instruct minF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (MinF src1 src2)); format %{ "fmins $dst, $src1, $src2" %} ins_encode %{ __ fmins(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_dop_reg_reg_s); %} // Math.max(DD)D instruct maxD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ match(Set dst (MaxD src1 src2)); format %{ "fmaxd $dst, $src1, $src2" %} ins_encode %{ __ fmaxd(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_dop_reg_reg_d); %} // Math.min(DD)D instruct minD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ match(Set dst (MinD src1 src2)); format %{ "fmind $dst, $src1, $src2" %} ins_encode %{ __ fmind(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_dop_reg_reg_d); %} instruct divF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (DivF src1 src2)); ins_cost(INSN_COST * 18); format %{ "fdivs $dst, $src1, $src2" %} ins_encode %{ __ fdivs(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_div_s); %} instruct divD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ match(Set dst (DivD src1 src2)); ins_cost(INSN_COST * 32); format %{ "fdivd $dst, $src1, $src2" %} ins_encode %{ __ fdivd(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_div_d); %} instruct negF_reg_reg(vRegF dst, vRegF src) %{ match(Set dst (NegF src)); ins_cost(INSN_COST * 3); format %{ "fneg $dst, $src" %} ins_encode %{ __ fnegs(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_uop_s); %} instruct negD_reg_reg(vRegD dst, vRegD src) %{ match(Set dst (NegD src)); ins_cost(INSN_COST * 3); format %{ "fnegd $dst, $src" %} ins_encode %{ __ fnegd(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_uop_d); %} instruct absI_reg(iRegINoSp dst, iRegIorL2I src, rFlagsReg cr) %{ match(Set dst (AbsI src)); effect(KILL cr); ins_cost(INSN_COST * 2); format %{ "cmpw $src, zr\n\t" "cnegw $dst, $src, Assembler::LT\t# int abs" %} ins_encode %{ __ cmpw(as_Register($src$$reg), zr); __ cnegw(as_Register($dst$$reg), as_Register($src$$reg), Assembler::LT); %} ins_pipe(pipe_class_default); %} instruct absL_reg(iRegLNoSp dst, iRegL src, rFlagsReg cr) %{ match(Set dst (AbsL src)); effect(KILL cr); ins_cost(INSN_COST * 2); format %{ "cmp $src, zr\n\t" "cneg $dst, $src, Assembler::LT\t# long abs" %} ins_encode %{ __ cmp(as_Register($src$$reg), zr); __ cneg(as_Register($dst$$reg), as_Register($src$$reg), Assembler::LT); %} ins_pipe(pipe_class_default); %} instruct absF_reg(vRegF dst, vRegF src) %{ match(Set dst (AbsF src)); ins_cost(INSN_COST * 3); format %{ "fabss $dst, $src" %} ins_encode %{ __ fabss(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_uop_s); %} instruct absD_reg(vRegD dst, vRegD src) %{ match(Set dst (AbsD src)); ins_cost(INSN_COST * 3); format %{ "fabsd $dst, $src" %} ins_encode %{ __ fabsd(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_uop_d); %} instruct absdF_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (AbsF (SubF src1 src2))); ins_cost(INSN_COST * 3); format %{ "fabds $dst, $src1, $src2" %} ins_encode %{ __ fabds(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_uop_s); %} instruct absdD_reg(vRegD dst, vRegD src1, vRegD src2) %{ match(Set dst (AbsD (SubD src1 src2))); ins_cost(INSN_COST * 3); format %{ "fabdd $dst, $src1, $src2" %} ins_encode %{ __ fabdd(as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(fp_uop_d); %} instruct sqrtD_reg(vRegD dst, vRegD src) %{ match(Set dst (SqrtD src)); ins_cost(INSN_COST * 50); format %{ "fsqrtd $dst, $src" %} ins_encode %{ __ fsqrtd(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_div_s); %} instruct sqrtF_reg(vRegF dst, vRegF src) %{ match(Set dst (SqrtF src)); ins_cost(INSN_COST * 50); format %{ "fsqrts $dst, $src" %} ins_encode %{ __ fsqrts(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_div_d); %} // Math.rint, floor, ceil instruct roundD_reg(vRegD dst, vRegD src, immI rmode) %{ match(Set dst (RoundDoubleMode src rmode)); format %{ "frint $dst, $src, $rmode" %} ins_encode %{ switch ($rmode$$constant) { case RoundDoubleModeNode::rmode_rint: __ frintnd(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); break; case RoundDoubleModeNode::rmode_floor: __ frintmd(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); break; case RoundDoubleModeNode::rmode_ceil: __ frintpd(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); break; } %} ins_pipe(fp_uop_d); %} instruct copySignD_reg(vRegD dst, vRegD src1, vRegD src2, vRegD zero) %{ match(Set dst (CopySignD src1 (Binary src2 zero))); effect(TEMP_DEF dst, USE src1, USE src2, USE zero); format %{ "CopySignD $dst $src1 $src2" %} ins_encode %{ FloatRegister dst = as_FloatRegister($dst$$reg), src1 = as_FloatRegister($src1$$reg), src2 = as_FloatRegister($src2$$reg), zero = as_FloatRegister($zero$$reg); __ fnegd(dst, zero); __ bsl(dst, __ T8B, src2, src1); %} ins_pipe(fp_uop_d); %} instruct copySignF_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (CopySignF src1 src2)); effect(TEMP_DEF dst, USE src1, USE src2); format %{ "CopySignF $dst $src1 $src2" %} ins_encode %{ FloatRegister dst = as_FloatRegister($dst$$reg), src1 = as_FloatRegister($src1$$reg), src2 = as_FloatRegister($src2$$reg); __ movi(dst, __ T2S, 0x80, 24); __ bsl(dst, __ T8B, src2, src1); %} ins_pipe(fp_uop_d); %} instruct signumD_reg(vRegD dst, vRegD src, vRegD zero, vRegD one) %{ match(Set dst (SignumD src (Binary zero one))); effect(TEMP_DEF dst, USE src, USE zero, USE one); format %{ "signumD $dst, $src" %} ins_encode %{ FloatRegister src = as_FloatRegister($src$$reg), dst = as_FloatRegister($dst$$reg), zero = as_FloatRegister($zero$$reg), one = as_FloatRegister($one$$reg); __ facgtd(dst, src, zero); // dst=0 for +-0.0 and NaN. 0xFFF..F otherwise __ ushrd(dst, dst, 1); // dst=0 for +-0.0 and NaN. 0x7FF..F otherwise // Bit selection instruction gets bit from "one" for each enabled bit in // "dst", otherwise gets a bit from "src". For "src" that contains +-0.0 or // NaN the whole "src" will be copied because "dst" is zero. For all other // "src" values dst is 0x7FF..F, which means only the sign bit is copied // from "src", and all other bits are copied from 1.0. __ bsl(dst, __ T8B, one, src); %} ins_pipe(fp_uop_d); %} instruct signumF_reg(vRegF dst, vRegF src, vRegF zero, vRegF one) %{ match(Set dst (SignumF src (Binary zero one))); effect(TEMP_DEF dst, USE src, USE zero, USE one); format %{ "signumF $dst, $src" %} ins_encode %{ FloatRegister src = as_FloatRegister($src$$reg), dst = as_FloatRegister($dst$$reg), zero = as_FloatRegister($zero$$reg), one = as_FloatRegister($one$$reg); __ facgts(dst, src, zero); // dst=0 for +-0.0 and NaN. 0xFFF..F otherwise __ ushr(dst, __ T2S, dst, 1); // dst=0 for +-0.0 and NaN. 0x7FF..F otherwise // Bit selection instruction gets bit from "one" for each enabled bit in // "dst", otherwise gets a bit from "src". For "src" that contains +-0.0 or // NaN the whole "src" will be copied because "dst" is zero. For all other // "src" values dst is 0x7FF..F, which means only the sign bit is copied // from "src", and all other bits are copied from 1.0. __ bsl(dst, __ T8B, one, src); %} ins_pipe(fp_uop_d); %} instruct onspinwait() %{ match(OnSpinWait); ins_cost(INSN_COST); format %{ "onspinwait" %} ins_encode %{ __ spin_wait(); %} ins_pipe(pipe_class_empty); %} // ============================================================================ // Logical Instructions // Integer Logical Instructions // And Instructions instruct andI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, rFlagsReg cr) %{ match(Set dst (AndI src1 src2)); format %{ "andw $dst, $src1, $src2\t# int" %} ins_cost(INSN_COST); ins_encode %{ __ andw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg); %} instruct andI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immILog src2, rFlagsReg cr) %{ match(Set dst (AndI src1 src2)); format %{ "andsw $dst, $src1, $src2\t# int" %} ins_cost(INSN_COST); ins_encode %{ __ andw(as_Register($dst$$reg), as_Register($src1$$reg), (uint64_t)($src2$$constant)); %} ins_pipe(ialu_reg_imm); %} // Or Instructions instruct orI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (OrI src1 src2)); format %{ "orrw $dst, $src1, $src2\t# int" %} ins_cost(INSN_COST); ins_encode %{ __ orrw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg); %} instruct orI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immILog src2) %{ match(Set dst (OrI src1 src2)); format %{ "orrw $dst, $src1, $src2\t# int" %} ins_cost(INSN_COST); ins_encode %{ __ orrw(as_Register($dst$$reg), as_Register($src1$$reg), (uint64_t)($src2$$constant)); %} ins_pipe(ialu_reg_imm); %} // Xor Instructions instruct xorI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (XorI src1 src2)); format %{ "eorw $dst, $src1, $src2\t# int" %} ins_cost(INSN_COST); ins_encode %{ __ eorw(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg); %} instruct xorI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immILog src2) %{ match(Set dst (XorI src1 src2)); format %{ "eorw $dst, $src1, $src2\t# int" %} ins_cost(INSN_COST); ins_encode %{ __ eorw(as_Register($dst$$reg), as_Register($src1$$reg), (uint64_t)($src2$$constant)); %} ins_pipe(ialu_reg_imm); %} // Long Logical Instructions // TODO instruct andL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2, rFlagsReg cr) %{ match(Set dst (AndL src1 src2)); format %{ "and $dst, $src1, $src2\t# int" %} ins_cost(INSN_COST); ins_encode %{ __ andr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg); %} instruct andL_reg_imm(iRegLNoSp dst, iRegL src1, immLLog src2, rFlagsReg cr) %{ match(Set dst (AndL src1 src2)); format %{ "and $dst, $src1, $src2\t# int" %} ins_cost(INSN_COST); ins_encode %{ __ andr(as_Register($dst$$reg), as_Register($src1$$reg), (uint64_t)($src2$$constant)); %} ins_pipe(ialu_reg_imm); %} // Or Instructions instruct orL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ match(Set dst (OrL src1 src2)); format %{ "orr $dst, $src1, $src2\t# int" %} ins_cost(INSN_COST); ins_encode %{ __ orr(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg); %} instruct orL_reg_imm(iRegLNoSp dst, iRegL src1, immLLog src2) %{ match(Set dst (OrL src1 src2)); format %{ "orr $dst, $src1, $src2\t# int" %} ins_cost(INSN_COST); ins_encode %{ __ orr(as_Register($dst$$reg), as_Register($src1$$reg), (uint64_t)($src2$$constant)); %} ins_pipe(ialu_reg_imm); %} // Xor Instructions instruct xorL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ match(Set dst (XorL src1 src2)); format %{ "eor $dst, $src1, $src2\t# int" %} ins_cost(INSN_COST); ins_encode %{ __ eor(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); %} ins_pipe(ialu_reg_reg); %} instruct xorL_reg_imm(iRegLNoSp dst, iRegL src1, immLLog src2) %{ match(Set dst (XorL src1 src2)); ins_cost(INSN_COST); format %{ "eor $dst, $src1, $src2\t# int" %} ins_encode %{ __ eor(as_Register($dst$$reg), as_Register($src1$$reg), (uint64_t)($src2$$constant)); %} ins_pipe(ialu_reg_imm); %} instruct convI2L_reg_reg(iRegLNoSp dst, iRegIorL2I src) %{ match(Set dst (ConvI2L src)); ins_cost(INSN_COST); format %{ "sxtw $dst, $src\t# i2l" %} ins_encode %{ __ sbfm($dst$$Register, $src$$Register, 0, 31); %} ins_pipe(ialu_reg_shift); %} // this pattern occurs in bigmath arithmetic instruct convUI2L_reg_reg(iRegLNoSp dst, iRegIorL2I src, immL_32bits mask) %{ match(Set dst (AndL (ConvI2L src) mask)); ins_cost(INSN_COST); format %{ "ubfm $dst, $src, 0, 31\t# ui2l" %} ins_encode %{ __ ubfm($dst$$Register, $src$$Register, 0, 31); %} ins_pipe(ialu_reg_shift); %} instruct convL2I_reg(iRegINoSp dst, iRegL src) %{ match(Set dst (ConvL2I src)); ins_cost(INSN_COST); format %{ "movw $dst, $src \t// l2i" %} ins_encode %{ __ movw(as_Register($dst$$reg), as_Register($src$$reg)); %} ins_pipe(ialu_reg); %} instruct convI2B(iRegINoSp dst, iRegIorL2I src, rFlagsReg cr) %{ match(Set dst (Conv2B src)); effect(KILL cr); format %{ "cmpw $src, zr\n\t" "cset $dst, ne" %} ins_encode %{ __ cmpw(as_Register($src$$reg), zr); __ cset(as_Register($dst$$reg), Assembler::NE); %} ins_pipe(ialu_reg); %} instruct convP2B(iRegINoSp dst, iRegP src, rFlagsReg cr) %{ match(Set dst (Conv2B src)); effect(KILL cr); format %{ "cmp $src, zr\n\t" "cset $dst, ne" %} ins_encode %{ __ cmp(as_Register($src$$reg), zr); __ cset(as_Register($dst$$reg), Assembler::NE); %} ins_pipe(ialu_reg); %} instruct convD2F_reg(vRegF dst, vRegD src) %{ match(Set dst (ConvD2F src)); ins_cost(INSN_COST * 5); format %{ "fcvtd $dst, $src \t// d2f" %} ins_encode %{ __ fcvtd(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_d2f); %} instruct convF2D_reg(vRegD dst, vRegF src) %{ match(Set dst (ConvF2D src)); ins_cost(INSN_COST * 5); format %{ "fcvts $dst, $src \t// f2d" %} ins_encode %{ __ fcvts(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_f2d); %} instruct convF2I_reg_reg(iRegINoSp dst, vRegF src) %{ match(Set dst (ConvF2I src)); ins_cost(INSN_COST * 5); format %{ "fcvtzsw $dst, $src \t// f2i" %} ins_encode %{ __ fcvtzsw(as_Register($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_f2i); %} instruct convF2L_reg_reg(iRegLNoSp dst, vRegF src) %{ match(Set dst (ConvF2L src)); ins_cost(INSN_COST * 5); format %{ "fcvtzs $dst, $src \t// f2l" %} ins_encode %{ __ fcvtzs(as_Register($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_f2l); %} instruct convI2F_reg_reg(vRegF dst, iRegIorL2I src) %{ match(Set dst (ConvI2F src)); ins_cost(INSN_COST * 5); format %{ "scvtfws $dst, $src \t// i2f" %} ins_encode %{ __ scvtfws(as_FloatRegister($dst$$reg), as_Register($src$$reg)); %} ins_pipe(fp_i2f); %} instruct convL2F_reg_reg(vRegF dst, iRegL src) %{ match(Set dst (ConvL2F src)); ins_cost(INSN_COST * 5); format %{ "scvtfs $dst, $src \t// l2f" %} ins_encode %{ __ scvtfs(as_FloatRegister($dst$$reg), as_Register($src$$reg)); %} ins_pipe(fp_l2f); %} instruct convD2I_reg_reg(iRegINoSp dst, vRegD src) %{ match(Set dst (ConvD2I src)); ins_cost(INSN_COST * 5); format %{ "fcvtzdw $dst, $src \t// d2i" %} ins_encode %{ __ fcvtzdw(as_Register($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_d2i); %} instruct convD2L_reg_reg(iRegLNoSp dst, vRegD src) %{ match(Set dst (ConvD2L src)); ins_cost(INSN_COST * 5); format %{ "fcvtzd $dst, $src \t// d2l" %} ins_encode %{ __ fcvtzd(as_Register($dst$$reg), as_FloatRegister($src$$reg)); %} ins_pipe(fp_d2l); %} instruct convI2D_reg_reg(vRegD dst, iRegIorL2I src) %{ match(Set dst (ConvI2D src)); ins_cost(INSN_COST * 5); format %{ "scvtfwd $dst, $src \t// i2d" %} ins_encode %{ __ scvtfwd(as_FloatRegister($dst$$reg), as_Register($src$$reg)); %} ins_pipe(fp_i2d); %} instruct convL2D_reg_reg(vRegD dst, iRegL src) %{ match(Set dst (ConvL2D src)); ins_cost(INSN_COST * 5); format %{ "scvtfd $dst, $src \t// l2d" %} ins_encode %{ __ scvtfd(as_FloatRegister($dst$$reg), as_Register($src$$reg)); %} ins_pipe(fp_l2d); %} // stack <-> reg and reg <-> reg shuffles with no conversion instruct MoveF2I_stack_reg(iRegINoSp dst, stackSlotF src) %{ match(Set dst (MoveF2I src)); effect(DEF dst, USE src); ins_cost(4 * INSN_COST); format %{ "ldrw $dst, $src\t# MoveF2I_stack_reg" %} ins_encode %{ __ ldrw($dst$$Register, Address(sp, $src$$disp)); %} ins_pipe(iload_reg_reg); %} instruct MoveI2F_stack_reg(vRegF dst, stackSlotI src) %{ match(Set dst (MoveI2F src)); effect(DEF dst, USE src); ins_cost(4 * INSN_COST); format %{ "ldrs $dst, $src\t# MoveI2F_stack_reg" %} ins_encode %{ __ ldrs(as_FloatRegister($dst$$reg), Address(sp, $src$$disp)); %} ins_pipe(pipe_class_memory); %} instruct MoveD2L_stack_reg(iRegLNoSp dst, stackSlotD src) %{ match(Set dst (MoveD2L src)); effect(DEF dst, USE src); ins_cost(4 * INSN_COST); format %{ "ldr $dst, $src\t# MoveD2L_stack_reg" %} ins_encode %{ __ ldr($dst$$Register, Address(sp, $src$$disp)); %} ins_pipe(iload_reg_reg); %} instruct MoveL2D_stack_reg(vRegD dst, stackSlotL src) %{ match(Set dst (MoveL2D src)); effect(DEF dst, USE src); ins_cost(4 * INSN_COST); format %{ "ldrd $dst, $src\t# MoveL2D_stack_reg" %} ins_encode %{ __ ldrd(as_FloatRegister($dst$$reg), Address(sp, $src$$disp)); %} ins_pipe(pipe_class_memory); %} instruct MoveF2I_reg_stack(stackSlotI dst, vRegF src) %{ match(Set dst (MoveF2I src)); effect(DEF dst, USE src); ins_cost(INSN_COST); format %{ "strs $src, $dst\t# MoveF2I_reg_stack" %} ins_encode %{ __ strs(as_FloatRegister($src$$reg), Address(sp, $dst$$disp)); %} ins_pipe(pipe_class_memory); %} instruct MoveI2F_reg_stack(stackSlotF dst, iRegI src) %{ match(Set dst (MoveI2F src)); effect(DEF dst, USE src); ins_cost(INSN_COST); format %{ "strw $src, $dst\t# MoveI2F_reg_stack" %} ins_encode %{ __ strw($src$$Register, Address(sp, $dst$$disp)); %} ins_pipe(istore_reg_reg); %} instruct MoveD2L_reg_stack(stackSlotL dst, vRegD src) %{ match(Set dst (MoveD2L src)); effect(DEF dst, USE src); ins_cost(INSN_COST); format %{ "strd $dst, $src\t# MoveD2L_reg_stack" %} ins_encode %{ __ strd(as_FloatRegister($src$$reg), Address(sp, $dst$$disp)); %} ins_pipe(pipe_class_memory); %} instruct MoveL2D_reg_stack(stackSlotD dst, iRegL src) %{ match(Set dst (MoveL2D src)); effect(DEF dst, USE src); ins_cost(INSN_COST); format %{ "str $src, $dst\t# MoveL2D_reg_stack" %} ins_encode %{ __ str($src$$Register, Address(sp, $dst$$disp)); %} ins_pipe(istore_reg_reg); %} instruct MoveF2I_reg_reg(iRegINoSp dst, vRegF src) %{ match(Set dst (MoveF2I src)); effect(DEF dst, USE src); ins_cost(INSN_COST); format %{ "fmovs $dst, $src\t# MoveF2I_reg_reg" %} ins_encode %{ __ fmovs($dst$$Register, as_FloatRegister($src$$reg)); %} ins_pipe(fp_f2i); %} instruct MoveI2F_reg_reg(vRegF dst, iRegI src) %{ match(Set dst (MoveI2F src)); effect(DEF dst, USE src); ins_cost(INSN_COST); format %{ "fmovs $dst, $src\t# MoveI2F_reg_reg" %} ins_encode %{ __ fmovs(as_FloatRegister($dst$$reg), $src$$Register); %} ins_pipe(fp_i2f); %} instruct MoveD2L_reg_reg(iRegLNoSp dst, vRegD src) %{ match(Set dst (MoveD2L src)); effect(DEF dst, USE src); ins_cost(INSN_COST); format %{ "fmovd $dst, $src\t# MoveD2L_reg_reg" %} ins_encode %{ __ fmovd($dst$$Register, as_FloatRegister($src$$reg)); %} ins_pipe(fp_d2l); %} instruct MoveL2D_reg_reg(vRegD dst, iRegL src) %{ match(Set dst (MoveL2D src)); effect(DEF dst, USE src); ins_cost(INSN_COST); format %{ "fmovd $dst, $src\t# MoveL2D_reg_reg" %} ins_encode %{ __ fmovd(as_FloatRegister($dst$$reg), $src$$Register); %} ins_pipe(fp_l2d); %} // ============================================================================ // clearing of an array instruct clearArray_reg_reg(iRegL_R11 cnt, iRegP_R10 base, Universe dummy, rFlagsReg cr) %{ match(Set dummy (ClearArray cnt base)); effect(USE_KILL cnt, USE_KILL base, KILL cr); ins_cost(4 * INSN_COST); format %{ "ClearArray $cnt, $base" %} ins_encode %{ address tpc = __ zero_words($base$$Register, $cnt$$Register); if (tpc == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } %} ins_pipe(pipe_class_memory); %} instruct clearArray_imm_reg(immL cnt, iRegP_R10 base, iRegL_R11 temp, Universe dummy, rFlagsReg cr) %{ predicate((uint64_t)n->in(2)->get_long() < (uint64_t)(BlockZeroingLowLimit >> LogBytesPerWord)); match(Set dummy (ClearArray cnt base)); effect(TEMP temp, USE_KILL base, KILL cr); ins_cost(4 * INSN_COST); format %{ "ClearArray $cnt, $base" %} ins_encode %{ address tpc = __ zero_words($base$$Register, (uint64_t)$cnt$$constant); if (tpc == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } %} ins_pipe(pipe_class_memory); %} // ============================================================================ // Overflow Math Instructions instruct overflowAddI_reg_reg(rFlagsReg cr, iRegIorL2I op1, iRegIorL2I op2) %{ match(Set cr (OverflowAddI op1 op2)); format %{ "cmnw $op1, $op2\t# overflow check int" %} ins_cost(INSN_COST); ins_encode %{ __ cmnw($op1$$Register, $op2$$Register); %} ins_pipe(icmp_reg_reg); %} instruct overflowAddI_reg_imm(rFlagsReg cr, iRegIorL2I op1, immIAddSub op2) %{ match(Set cr (OverflowAddI op1 op2)); format %{ "cmnw $op1, $op2\t# overflow check int" %} ins_cost(INSN_COST); ins_encode %{ __ cmnw($op1$$Register, $op2$$constant); %} ins_pipe(icmp_reg_imm); %} instruct overflowAddL_reg_reg(rFlagsReg cr, iRegL op1, iRegL op2) %{ match(Set cr (OverflowAddL op1 op2)); format %{ "cmn $op1, $op2\t# overflow check long" %} ins_cost(INSN_COST); ins_encode %{ __ cmn($op1$$Register, $op2$$Register); %} ins_pipe(icmp_reg_reg); %} instruct overflowAddL_reg_imm(rFlagsReg cr, iRegL op1, immLAddSub op2) %{ match(Set cr (OverflowAddL op1 op2)); format %{ "adds zr, $op1, $op2\t# overflow check long" %} ins_cost(INSN_COST); ins_encode %{ __ adds(zr, $op1$$Register, $op2$$constant); %} ins_pipe(icmp_reg_imm); %} instruct overflowSubI_reg_reg(rFlagsReg cr, iRegIorL2I op1, iRegIorL2I op2) %{ match(Set cr (OverflowSubI op1 op2)); format %{ "cmpw $op1, $op2\t# overflow check int" %} ins_cost(INSN_COST); ins_encode %{ __ cmpw($op1$$Register, $op2$$Register); %} ins_pipe(icmp_reg_reg); %} instruct overflowSubI_reg_imm(rFlagsReg cr, iRegIorL2I op1, immIAddSub op2) %{ match(Set cr (OverflowSubI op1 op2)); format %{ "cmpw $op1, $op2\t# overflow check int" %} ins_cost(INSN_COST); ins_encode %{ __ cmpw($op1$$Register, $op2$$constant); %} ins_pipe(icmp_reg_imm); %} instruct overflowSubL_reg_reg(rFlagsReg cr, iRegL op1, iRegL op2) %{ match(Set cr (OverflowSubL op1 op2)); format %{ "cmp $op1, $op2\t# overflow check long" %} ins_cost(INSN_COST); ins_encode %{ __ cmp($op1$$Register, $op2$$Register); %} ins_pipe(icmp_reg_reg); %} instruct overflowSubL_reg_imm(rFlagsReg cr, iRegL op1, immLAddSub op2) %{ match(Set cr (OverflowSubL op1 op2)); format %{ "cmp $op1, $op2\t# overflow check long" %} ins_cost(INSN_COST); ins_encode %{ __ subs(zr, $op1$$Register, $op2$$constant); %} ins_pipe(icmp_reg_imm); %} instruct overflowNegI_reg(rFlagsReg cr, immI0 zero, iRegIorL2I op1) %{ match(Set cr (OverflowSubI zero op1)); format %{ "cmpw zr, $op1\t# overflow check int" %} ins_cost(INSN_COST); ins_encode %{ __ cmpw(zr, $op1$$Register); %} ins_pipe(icmp_reg_imm); %} instruct overflowNegL_reg(rFlagsReg cr, immI0 zero, iRegL op1) %{ match(Set cr (OverflowSubL zero op1)); format %{ "cmp zr, $op1\t# overflow check long" %} ins_cost(INSN_COST); ins_encode %{ __ cmp(zr, $op1$$Register); %} ins_pipe(icmp_reg_imm); %} instruct overflowMulI_reg(rFlagsReg cr, iRegIorL2I op1, iRegIorL2I op2) %{ match(Set cr (OverflowMulI op1 op2)); format %{ "smull rscratch1, $op1, $op2\t# overflow check int\n\t" "cmp rscratch1, rscratch1, sxtw\n\t" "movw rscratch1, #0x80000000\n\t" "cselw rscratch1, rscratch1, zr, NE\n\t" "cmpw rscratch1, #1" %} ins_cost(5 * INSN_COST); ins_encode %{ __ smull(rscratch1, $op1$$Register, $op2$$Register); __ subs(zr, rscratch1, rscratch1, ext::sxtw); // NE => overflow __ movw(rscratch1, 0x80000000); // Develop 0 (EQ), __ cselw(rscratch1, rscratch1, zr, Assembler::NE); // or 0x80000000 (NE) __ cmpw(rscratch1, 1); // 0x80000000 - 1 => VS %} ins_pipe(pipe_slow); %} instruct overflowMulI_reg_branch(cmpOp cmp, iRegIorL2I op1, iRegIorL2I op2, label labl, rFlagsReg cr) %{ match(If cmp (OverflowMulI op1 op2)); predicate(n->in(1)->as_Bool()->_test._test == BoolTest::overflow || n->in(1)->as_Bool()->_test._test == BoolTest::no_overflow); effect(USE labl, KILL cr); format %{ "smull rscratch1, $op1, $op2\t# overflow check int\n\t" "cmp rscratch1, rscratch1, sxtw\n\t" "b$cmp $labl" %} ins_cost(3 * INSN_COST); // Branch is rare so treat as INSN_COST ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; __ smull(rscratch1, $op1$$Register, $op2$$Register); __ subs(zr, rscratch1, rscratch1, ext::sxtw); // NE => overflow __ br(cond == Assembler::VS ? Assembler::NE : Assembler::EQ, *L); %} ins_pipe(pipe_serial); %} instruct overflowMulL_reg(rFlagsReg cr, iRegL op1, iRegL op2) %{ match(Set cr (OverflowMulL op1 op2)); format %{ "mul rscratch1, $op1, $op2\t#overflow check long\n\t" "smulh rscratch2, $op1, $op2\n\t" "cmp rscratch2, rscratch1, ASR #63\n\t" "movw rscratch1, #0x80000000\n\t" "cselw rscratch1, rscratch1, zr, NE\n\t" "cmpw rscratch1, #1" %} ins_cost(6 * INSN_COST); ins_encode %{ __ mul(rscratch1, $op1$$Register, $op2$$Register); // Result bits 0..63 __ smulh(rscratch2, $op1$$Register, $op2$$Register); // Result bits 64..127 __ cmp(rscratch2, rscratch1, Assembler::ASR, 63); // Top is pure sign ext __ movw(rscratch1, 0x80000000); // Develop 0 (EQ), __ cselw(rscratch1, rscratch1, zr, Assembler::NE); // or 0x80000000 (NE) __ cmpw(rscratch1, 1); // 0x80000000 - 1 => VS %} ins_pipe(pipe_slow); %} instruct overflowMulL_reg_branch(cmpOp cmp, iRegL op1, iRegL op2, label labl, rFlagsReg cr) %{ match(If cmp (OverflowMulL op1 op2)); predicate(n->in(1)->as_Bool()->_test._test == BoolTest::overflow || n->in(1)->as_Bool()->_test._test == BoolTest::no_overflow); effect(USE labl, KILL cr); format %{ "mul rscratch1, $op1, $op2\t#overflow check long\n\t" "smulh rscratch2, $op1, $op2\n\t" "cmp rscratch2, rscratch1, ASR #63\n\t" "b$cmp $labl" %} ins_cost(4 * INSN_COST); // Branch is rare so treat as INSN_COST ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; __ mul(rscratch1, $op1$$Register, $op2$$Register); // Result bits 0..63 __ smulh(rscratch2, $op1$$Register, $op2$$Register); // Result bits 64..127 __ cmp(rscratch2, rscratch1, Assembler::ASR, 63); // Top is pure sign ext __ br(cond == Assembler::VS ? Assembler::NE : Assembler::EQ, *L); %} ins_pipe(pipe_serial); %} // ============================================================================ // Compare Instructions instruct compI_reg_reg(rFlagsReg cr, iRegI op1, iRegI op2) %{ match(Set cr (CmpI op1 op2)); effect(DEF cr, USE op1, USE op2); ins_cost(INSN_COST); format %{ "cmpw $op1, $op2" %} ins_encode(aarch64_enc_cmpw(op1, op2)); ins_pipe(icmp_reg_reg); %} instruct compI_reg_immI0(rFlagsReg cr, iRegI op1, immI0 zero) %{ match(Set cr (CmpI op1 zero)); effect(DEF cr, USE op1); ins_cost(INSN_COST); format %{ "cmpw $op1, 0" %} ins_encode(aarch64_enc_cmpw_imm_addsub(op1, zero)); ins_pipe(icmp_reg_imm); %} instruct compI_reg_immIAddSub(rFlagsReg cr, iRegI op1, immIAddSub op2) %{ match(Set cr (CmpI op1 op2)); effect(DEF cr, USE op1); ins_cost(INSN_COST); format %{ "cmpw $op1, $op2" %} ins_encode(aarch64_enc_cmpw_imm_addsub(op1, op2)); ins_pipe(icmp_reg_imm); %} instruct compI_reg_immI(rFlagsReg cr, iRegI op1, immI op2) %{ match(Set cr (CmpI op1 op2)); effect(DEF cr, USE op1); ins_cost(INSN_COST * 2); format %{ "cmpw $op1, $op2" %} ins_encode(aarch64_enc_cmpw_imm(op1, op2)); ins_pipe(icmp_reg_imm); %} // Unsigned compare Instructions; really, same as signed compare // except it should only be used to feed an If or a CMovI which takes a // cmpOpU. instruct compU_reg_reg(rFlagsRegU cr, iRegI op1, iRegI op2) %{ match(Set cr (CmpU op1 op2)); effect(DEF cr, USE op1, USE op2); ins_cost(INSN_COST); format %{ "cmpw $op1, $op2\t# unsigned" %} ins_encode(aarch64_enc_cmpw(op1, op2)); ins_pipe(icmp_reg_reg); %} instruct compU_reg_immI0(rFlagsRegU cr, iRegI op1, immI0 zero) %{ match(Set cr (CmpU op1 zero)); effect(DEF cr, USE op1); ins_cost(INSN_COST); format %{ "cmpw $op1, #0\t# unsigned" %} ins_encode(aarch64_enc_cmpw_imm_addsub(op1, zero)); ins_pipe(icmp_reg_imm); %} instruct compU_reg_immIAddSub(rFlagsRegU cr, iRegI op1, immIAddSub op2) %{ match(Set cr (CmpU op1 op2)); effect(DEF cr, USE op1); ins_cost(INSN_COST); format %{ "cmpw $op1, $op2\t# unsigned" %} ins_encode(aarch64_enc_cmpw_imm_addsub(op1, op2)); ins_pipe(icmp_reg_imm); %} instruct compU_reg_immI(rFlagsRegU cr, iRegI op1, immI op2) %{ match(Set cr (CmpU op1 op2)); effect(DEF cr, USE op1); ins_cost(INSN_COST * 2); format %{ "cmpw $op1, $op2\t# unsigned" %} ins_encode(aarch64_enc_cmpw_imm(op1, op2)); ins_pipe(icmp_reg_imm); %} instruct compL_reg_reg(rFlagsReg cr, iRegL op1, iRegL op2) %{ match(Set cr (CmpL op1 op2)); effect(DEF cr, USE op1, USE op2); ins_cost(INSN_COST); format %{ "cmp $op1, $op2" %} ins_encode(aarch64_enc_cmp(op1, op2)); ins_pipe(icmp_reg_reg); %} instruct compL_reg_immL0(rFlagsReg cr, iRegL op1, immL0 zero) %{ match(Set cr (CmpL op1 zero)); effect(DEF cr, USE op1); ins_cost(INSN_COST); format %{ "tst $op1" %} ins_encode(aarch64_enc_cmp_imm_addsub(op1, zero)); ins_pipe(icmp_reg_imm); %} instruct compL_reg_immLAddSub(rFlagsReg cr, iRegL op1, immLAddSub op2) %{ match(Set cr (CmpL op1 op2)); effect(DEF cr, USE op1); ins_cost(INSN_COST); format %{ "cmp $op1, $op2" %} ins_encode(aarch64_enc_cmp_imm_addsub(op1, op2)); ins_pipe(icmp_reg_imm); %} instruct compL_reg_immL(rFlagsReg cr, iRegL op1, immL op2) %{ match(Set cr (CmpL op1 op2)); effect(DEF cr, USE op1); ins_cost(INSN_COST * 2); format %{ "cmp $op1, $op2" %} ins_encode(aarch64_enc_cmp_imm(op1, op2)); ins_pipe(icmp_reg_imm); %} instruct compUL_reg_reg(rFlagsRegU cr, iRegL op1, iRegL op2) %{ match(Set cr (CmpUL op1 op2)); effect(DEF cr, USE op1, USE op2); ins_cost(INSN_COST); format %{ "cmp $op1, $op2" %} ins_encode(aarch64_enc_cmp(op1, op2)); ins_pipe(icmp_reg_reg); %} instruct compUL_reg_immL0(rFlagsRegU cr, iRegL op1, immL0 zero) %{ match(Set cr (CmpUL op1 zero)); effect(DEF cr, USE op1); ins_cost(INSN_COST); format %{ "tst $op1" %} ins_encode(aarch64_enc_cmp_imm_addsub(op1, zero)); ins_pipe(icmp_reg_imm); %} instruct compUL_reg_immLAddSub(rFlagsRegU cr, iRegL op1, immLAddSub op2) %{ match(Set cr (CmpUL op1 op2)); effect(DEF cr, USE op1); ins_cost(INSN_COST); format %{ "cmp $op1, $op2" %} ins_encode(aarch64_enc_cmp_imm_addsub(op1, op2)); ins_pipe(icmp_reg_imm); %} instruct compUL_reg_immL(rFlagsRegU cr, iRegL op1, immL op2) %{ match(Set cr (CmpUL op1 op2)); effect(DEF cr, USE op1); ins_cost(INSN_COST * 2); format %{ "cmp $op1, $op2" %} ins_encode(aarch64_enc_cmp_imm(op1, op2)); ins_pipe(icmp_reg_imm); %} instruct compP_reg_reg(rFlagsRegU cr, iRegP op1, iRegP op2) %{ match(Set cr (CmpP op1 op2)); effect(DEF cr, USE op1, USE op2); ins_cost(INSN_COST); format %{ "cmp $op1, $op2\t // ptr" %} ins_encode(aarch64_enc_cmpp(op1, op2)); ins_pipe(icmp_reg_reg); %} instruct compN_reg_reg(rFlagsRegU cr, iRegN op1, iRegN op2) %{ match(Set cr (CmpN op1 op2)); effect(DEF cr, USE op1, USE op2); ins_cost(INSN_COST); format %{ "cmp $op1, $op2\t // compressed ptr" %} ins_encode(aarch64_enc_cmpn(op1, op2)); ins_pipe(icmp_reg_reg); %} instruct testP_reg(rFlagsRegU cr, iRegP op1, immP0 zero) %{ match(Set cr (CmpP op1 zero)); effect(DEF cr, USE op1, USE zero); ins_cost(INSN_COST); format %{ "cmp $op1, 0\t // ptr" %} ins_encode(aarch64_enc_testp(op1)); ins_pipe(icmp_reg_imm); %} instruct testN_reg(rFlagsRegU cr, iRegN op1, immN0 zero) %{ match(Set cr (CmpN op1 zero)); effect(DEF cr, USE op1, USE zero); ins_cost(INSN_COST); format %{ "cmp $op1, 0\t // compressed ptr" %} ins_encode(aarch64_enc_testn(op1)); ins_pipe(icmp_reg_imm); %} // FP comparisons // // n.b. CmpF/CmpD set a normal flags reg which then gets compared // using normal cmpOp. See declaration of rFlagsReg for details. instruct compF_reg_reg(rFlagsReg cr, vRegF src1, vRegF src2) %{ match(Set cr (CmpF src1 src2)); ins_cost(3 * INSN_COST); format %{ "fcmps $src1, $src2" %} ins_encode %{ __ fcmps(as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(pipe_class_compare); %} instruct compF_reg_zero(rFlagsReg cr, vRegF src1, immF0 src2) %{ match(Set cr (CmpF src1 src2)); ins_cost(3 * INSN_COST); format %{ "fcmps $src1, 0.0" %} ins_encode %{ __ fcmps(as_FloatRegister($src1$$reg), 0.0); %} ins_pipe(pipe_class_compare); %} // FROM HERE instruct compD_reg_reg(rFlagsReg cr, vRegD src1, vRegD src2) %{ match(Set cr (CmpD src1 src2)); ins_cost(3 * INSN_COST); format %{ "fcmpd $src1, $src2" %} ins_encode %{ __ fcmpd(as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg)); %} ins_pipe(pipe_class_compare); %} instruct compD_reg_zero(rFlagsReg cr, vRegD src1, immD0 src2) %{ match(Set cr (CmpD src1 src2)); ins_cost(3 * INSN_COST); format %{ "fcmpd $src1, 0.0" %} ins_encode %{ __ fcmpd(as_FloatRegister($src1$$reg), 0.0); %} ins_pipe(pipe_class_compare); %} instruct compF3_reg_reg(iRegINoSp dst, vRegF src1, vRegF src2, rFlagsReg cr) %{ match(Set dst (CmpF3 src1 src2)); effect(KILL cr); ins_cost(5 * INSN_COST); format %{ "fcmps $src1, $src2\n\t" "csinvw($dst, zr, zr, eq\n\t" "csnegw($dst, $dst, $dst, lt)" %} ins_encode %{ Label done; FloatRegister s1 = as_FloatRegister($src1$$reg); FloatRegister s2 = as_FloatRegister($src2$$reg); Register d = as_Register($dst$$reg); __ fcmps(s1, s2); // installs 0 if EQ else -1 __ csinvw(d, zr, zr, Assembler::EQ); // keeps -1 if less or unordered else installs 1 __ csnegw(d, d, d, Assembler::LT); __ bind(done); %} ins_pipe(pipe_class_default); %} instruct compD3_reg_reg(iRegINoSp dst, vRegD src1, vRegD src2, rFlagsReg cr) %{ match(Set dst (CmpD3 src1 src2)); effect(KILL cr); ins_cost(5 * INSN_COST); format %{ "fcmpd $src1, $src2\n\t" "csinvw($dst, zr, zr, eq\n\t" "csnegw($dst, $dst, $dst, lt)" %} ins_encode %{ Label done; FloatRegister s1 = as_FloatRegister($src1$$reg); FloatRegister s2 = as_FloatRegister($src2$$reg); Register d = as_Register($dst$$reg); __ fcmpd(s1, s2); // installs 0 if EQ else -1 __ csinvw(d, zr, zr, Assembler::EQ); // keeps -1 if less or unordered else installs 1 __ csnegw(d, d, d, Assembler::LT); __ bind(done); %} ins_pipe(pipe_class_default); %} instruct compF3_reg_immF0(iRegINoSp dst, vRegF src1, immF0 zero, rFlagsReg cr) %{ match(Set dst (CmpF3 src1 zero)); effect(KILL cr); ins_cost(5 * INSN_COST); format %{ "fcmps $src1, 0.0\n\t" "csinvw($dst, zr, zr, eq\n\t" "csnegw($dst, $dst, $dst, lt)" %} ins_encode %{ Label done; FloatRegister s1 = as_FloatRegister($src1$$reg); Register d = as_Register($dst$$reg); __ fcmps(s1, 0.0); // installs 0 if EQ else -1 __ csinvw(d, zr, zr, Assembler::EQ); // keeps -1 if less or unordered else installs 1 __ csnegw(d, d, d, Assembler::LT); __ bind(done); %} ins_pipe(pipe_class_default); %} instruct compD3_reg_immD0(iRegINoSp dst, vRegD src1, immD0 zero, rFlagsReg cr) %{ match(Set dst (CmpD3 src1 zero)); effect(KILL cr); ins_cost(5 * INSN_COST); format %{ "fcmpd $src1, 0.0\n\t" "csinvw($dst, zr, zr, eq\n\t" "csnegw($dst, $dst, $dst, lt)" %} ins_encode %{ Label done; FloatRegister s1 = as_FloatRegister($src1$$reg); Register d = as_Register($dst$$reg); __ fcmpd(s1, 0.0); // installs 0 if EQ else -1 __ csinvw(d, zr, zr, Assembler::EQ); // keeps -1 if less or unordered else installs 1 __ csnegw(d, d, d, Assembler::LT); __ bind(done); %} ins_pipe(pipe_class_default); %} instruct cmpLTMask_reg_reg(iRegINoSp dst, iRegIorL2I p, iRegIorL2I q, rFlagsReg cr) %{ match(Set dst (CmpLTMask p q)); effect(KILL cr); ins_cost(3 * INSN_COST); format %{ "cmpw $p, $q\t# cmpLTMask\n\t" "csetw $dst, lt\n\t" "subw $dst, zr, $dst" %} ins_encode %{ __ cmpw(as_Register($p$$reg), as_Register($q$$reg)); __ csetw(as_Register($dst$$reg), Assembler::LT); __ subw(as_Register($dst$$reg), zr, as_Register($dst$$reg)); %} ins_pipe(ialu_reg_reg); %} instruct cmpLTMask_reg_zero(iRegINoSp dst, iRegIorL2I src, immI0 zero, rFlagsReg cr) %{ match(Set dst (CmpLTMask src zero)); effect(KILL cr); ins_cost(INSN_COST); format %{ "asrw $dst, $src, #31\t# cmpLTMask0" %} ins_encode %{ __ asrw(as_Register($dst$$reg), as_Register($src$$reg), 31); %} ins_pipe(ialu_reg_shift); %} // ============================================================================ // Max and Min // Like compI_reg_reg or compI_reg_immI0 but without match rule and second zero parameter. instruct compI_reg_imm0(rFlagsReg cr, iRegI src) %{ effect(DEF cr, USE src); ins_cost(INSN_COST); format %{ "cmpw $src, 0" %} ins_encode %{ __ cmpw($src$$Register, 0); %} ins_pipe(icmp_reg_imm); %} instruct minI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (MinI src1 src2)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_reg(cr, src1, src2); cmovI_reg_reg_lt(dst, src1, src2, cr); %} %} instruct maxI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (MaxI src1 src2)); ins_cost(INSN_COST * 3); expand %{ rFlagsReg cr; compI_reg_reg(cr, src1, src2); cmovI_reg_reg_gt(dst, src1, src2, cr); %} %} // ============================================================================ // Branch Instructions // Direct Branch. instruct branch(label lbl) %{ match(Goto); effect(USE lbl); ins_cost(BRANCH_COST); format %{ "b $lbl" %} ins_encode(aarch64_enc_b(lbl)); ins_pipe(pipe_branch); %} // Conditional Near Branch instruct branchCon(cmpOp cmp, rFlagsReg cr, label lbl) %{ // Same match rule as `branchConFar'. match(If cmp cr); effect(USE lbl); ins_cost(BRANCH_COST); // If set to 1 this indicates that the current instruction is a // short variant of a long branch. This avoids using this // instruction in first-pass matching. It will then only be used in // the `Shorten_branches' pass. // ins_short_branch(1); format %{ "b$cmp $lbl" %} ins_encode(aarch64_enc_br_con(cmp, lbl)); ins_pipe(pipe_branch_cond); %} // Conditional Near Branch Unsigned instruct branchConU(cmpOpU cmp, rFlagsRegU cr, label lbl) %{ // Same match rule as `branchConFar'. match(If cmp cr); effect(USE lbl); ins_cost(BRANCH_COST); // If set to 1 this indicates that the current instruction is a // short variant of a long branch. This avoids using this // instruction in first-pass matching. It will then only be used in // the `Shorten_branches' pass. // ins_short_branch(1); format %{ "b$cmp $lbl\t# unsigned" %} ins_encode(aarch64_enc_br_conU(cmp, lbl)); ins_pipe(pipe_branch_cond); %} // Make use of CBZ and CBNZ. These instructions, as well as being // shorter than (cmp; branch), have the additional benefit of not // killing the flags. instruct cmpI_imm0_branch(cmpOpEqNe cmp, iRegIorL2I op1, immI0 op2, label labl, rFlagsReg cr) %{ match(If cmp (CmpI op1 op2)); effect(USE labl); ins_cost(BRANCH_COST); format %{ "cbw$cmp $op1, $labl" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; if (cond == Assembler::EQ) __ cbzw($op1$$Register, *L); else __ cbnzw($op1$$Register, *L); %} ins_pipe(pipe_cmp_branch); %} instruct cmpL_imm0_branch(cmpOpEqNe cmp, iRegL op1, immL0 op2, label labl, rFlagsReg cr) %{ match(If cmp (CmpL op1 op2)); effect(USE labl); ins_cost(BRANCH_COST); format %{ "cb$cmp $op1, $labl" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; if (cond == Assembler::EQ) __ cbz($op1$$Register, *L); else __ cbnz($op1$$Register, *L); %} ins_pipe(pipe_cmp_branch); %} instruct cmpP_imm0_branch(cmpOpEqNe cmp, iRegP op1, immP0 op2, label labl, rFlagsReg cr) %{ match(If cmp (CmpP op1 op2)); effect(USE labl); ins_cost(BRANCH_COST); format %{ "cb$cmp $op1, $labl" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; if (cond == Assembler::EQ) __ cbz($op1$$Register, *L); else __ cbnz($op1$$Register, *L); %} ins_pipe(pipe_cmp_branch); %} instruct cmpN_imm0_branch(cmpOpEqNe cmp, iRegN op1, immN0 op2, label labl, rFlagsReg cr) %{ match(If cmp (CmpN op1 op2)); effect(USE labl); ins_cost(BRANCH_COST); format %{ "cbw$cmp $op1, $labl" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; if (cond == Assembler::EQ) __ cbzw($op1$$Register, *L); else __ cbnzw($op1$$Register, *L); %} ins_pipe(pipe_cmp_branch); %} instruct cmpP_narrowOop_imm0_branch(cmpOpEqNe cmp, iRegN oop, immP0 zero, label labl, rFlagsReg cr) %{ match(If cmp (CmpP (DecodeN oop) zero)); effect(USE labl); ins_cost(BRANCH_COST); format %{ "cb$cmp $oop, $labl" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; if (cond == Assembler::EQ) __ cbzw($oop$$Register, *L); else __ cbnzw($oop$$Register, *L); %} ins_pipe(pipe_cmp_branch); %} instruct cmpUI_imm0_branch(cmpOpUEqNeLtGe cmp, iRegIorL2I op1, immI0 op2, label labl, rFlagsRegU cr) %{ match(If cmp (CmpU op1 op2)); effect(USE labl); ins_cost(BRANCH_COST); format %{ "cbw$cmp $op1, $labl" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; if (cond == Assembler::EQ || cond == Assembler::LS) __ cbzw($op1$$Register, *L); else __ cbnzw($op1$$Register, *L); %} ins_pipe(pipe_cmp_branch); %} instruct cmpUL_imm0_branch(cmpOpUEqNeLtGe cmp, iRegL op1, immL0 op2, label labl, rFlagsRegU cr) %{ match(If cmp (CmpUL op1 op2)); effect(USE labl); ins_cost(BRANCH_COST); format %{ "cb$cmp $op1, $labl" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; if (cond == Assembler::EQ || cond == Assembler::LS) __ cbz($op1$$Register, *L); else __ cbnz($op1$$Register, *L); %} ins_pipe(pipe_cmp_branch); %} // Test bit and Branch // Patterns for short (< 32KiB) variants instruct cmpL_branch_sign(cmpOpLtGe cmp, iRegL op1, immL0 op2, label labl) %{ match(If cmp (CmpL op1 op2)); effect(USE labl); ins_cost(BRANCH_COST); format %{ "cb$cmp $op1, $labl # long" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; __ tbr(cond, $op1$$Register, 63, *L); %} ins_pipe(pipe_cmp_branch); ins_short_branch(1); %} instruct cmpI_branch_sign(cmpOpLtGe cmp, iRegIorL2I op1, immI0 op2, label labl) %{ match(If cmp (CmpI op1 op2)); effect(USE labl); ins_cost(BRANCH_COST); format %{ "cb$cmp $op1, $labl # int" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; __ tbr(cond, $op1$$Register, 31, *L); %} ins_pipe(pipe_cmp_branch); ins_short_branch(1); %} instruct cmpL_branch_bit(cmpOpEqNe cmp, iRegL op1, immL op2, immL0 op3, label labl) %{ match(If cmp (CmpL (AndL op1 op2) op3)); predicate(is_power_of_2((julong)n->in(2)->in(1)->in(2)->get_long())); effect(USE labl); ins_cost(BRANCH_COST); format %{ "tb$cmp $op1, $op2, $labl" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; int bit = exact_log2_long($op2$$constant); __ tbr(cond, $op1$$Register, bit, *L); %} ins_pipe(pipe_cmp_branch); ins_short_branch(1); %} instruct cmpI_branch_bit(cmpOpEqNe cmp, iRegIorL2I op1, immI op2, immI0 op3, label labl) %{ match(If cmp (CmpI (AndI op1 op2) op3)); predicate(is_power_of_2((juint)n->in(2)->in(1)->in(2)->get_int())); effect(USE labl); ins_cost(BRANCH_COST); format %{ "tb$cmp $op1, $op2, $labl" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; int bit = exact_log2((juint)$op2$$constant); __ tbr(cond, $op1$$Register, bit, *L); %} ins_pipe(pipe_cmp_branch); ins_short_branch(1); %} // And far variants instruct far_cmpL_branch_sign(cmpOpLtGe cmp, iRegL op1, immL0 op2, label labl) %{ match(If cmp (CmpL op1 op2)); effect(USE labl); ins_cost(BRANCH_COST); format %{ "cb$cmp $op1, $labl # long" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; __ tbr(cond, $op1$$Register, 63, *L, /*far*/true); %} ins_pipe(pipe_cmp_branch); %} instruct far_cmpI_branch_sign(cmpOpLtGe cmp, iRegIorL2I op1, immI0 op2, label labl) %{ match(If cmp (CmpI op1 op2)); effect(USE labl); ins_cost(BRANCH_COST); format %{ "cb$cmp $op1, $labl # int" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; __ tbr(cond, $op1$$Register, 31, *L, /*far*/true); %} ins_pipe(pipe_cmp_branch); %} instruct far_cmpL_branch_bit(cmpOpEqNe cmp, iRegL op1, immL op2, immL0 op3, label labl) %{ match(If cmp (CmpL (AndL op1 op2) op3)); predicate(is_power_of_2((julong)n->in(2)->in(1)->in(2)->get_long())); effect(USE labl); ins_cost(BRANCH_COST); format %{ "tb$cmp $op1, $op2, $labl" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; int bit = exact_log2_long($op2$$constant); __ tbr(cond, $op1$$Register, bit, *L, /*far*/true); %} ins_pipe(pipe_cmp_branch); %} instruct far_cmpI_branch_bit(cmpOpEqNe cmp, iRegIorL2I op1, immI op2, immI0 op3, label labl) %{ match(If cmp (CmpI (AndI op1 op2) op3)); predicate(is_power_of_2((juint)n->in(2)->in(1)->in(2)->get_int())); effect(USE labl); ins_cost(BRANCH_COST); format %{ "tb$cmp $op1, $op2, $labl" %} ins_encode %{ Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; int bit = exact_log2((juint)$op2$$constant); __ tbr(cond, $op1$$Register, bit, *L, /*far*/true); %} ins_pipe(pipe_cmp_branch); %} // Test bits instruct cmpL_and(cmpOp cmp, iRegL op1, immL op2, immL0 op3, rFlagsReg cr) %{ match(Set cr (CmpL (AndL op1 op2) op3)); predicate(Assembler::operand_valid_for_logical_immediate (/*is_32*/false, n->in(1)->in(2)->get_long())); ins_cost(INSN_COST); format %{ "tst $op1, $op2 # long" %} ins_encode %{ __ tst($op1$$Register, $op2$$constant); %} ins_pipe(ialu_reg_reg); %} instruct cmpI_and(cmpOp cmp, iRegIorL2I op1, immI op2, immI0 op3, rFlagsReg cr) %{ match(Set cr (CmpI (AndI op1 op2) op3)); predicate(Assembler::operand_valid_for_logical_immediate (/*is_32*/true, n->in(1)->in(2)->get_int())); ins_cost(INSN_COST); format %{ "tst $op1, $op2 # int" %} ins_encode %{ __ tstw($op1$$Register, $op2$$constant); %} ins_pipe(ialu_reg_reg); %} instruct cmpL_and_reg(cmpOp cmp, iRegL op1, iRegL op2, immL0 op3, rFlagsReg cr) %{ match(Set cr (CmpL (AndL op1 op2) op3)); ins_cost(INSN_COST); format %{ "tst $op1, $op2 # long" %} ins_encode %{ __ tst($op1$$Register, $op2$$Register); %} ins_pipe(ialu_reg_reg); %} instruct cmpI_and_reg(cmpOp cmp, iRegIorL2I op1, iRegIorL2I op2, immI0 op3, rFlagsReg cr) %{ match(Set cr (CmpI (AndI op1 op2) op3)); ins_cost(INSN_COST); format %{ "tstw $op1, $op2 # int" %} ins_encode %{ __ tstw($op1$$Register, $op2$$Register); %} ins_pipe(ialu_reg_reg); %} // Conditional Far Branch // Conditional Far Branch Unsigned // TODO: fixme // counted loop end branch near instruct branchLoopEnd(cmpOp cmp, rFlagsReg cr, label lbl) %{ match(CountedLoopEnd cmp cr); effect(USE lbl); ins_cost(BRANCH_COST); // short variant. // ins_short_branch(1); format %{ "b$cmp $lbl \t// counted loop end" %} ins_encode(aarch64_enc_br_con(cmp, lbl)); ins_pipe(pipe_branch); %} // counted loop end branch near Unsigned instruct branchLoopEndU(cmpOpU cmp, rFlagsRegU cr, label lbl) %{ match(CountedLoopEnd cmp cr); effect(USE lbl); ins_cost(BRANCH_COST); // short variant. // ins_short_branch(1); format %{ "b$cmp $lbl \t// counted loop end unsigned" %} ins_encode(aarch64_enc_br_conU(cmp, lbl)); ins_pipe(pipe_branch); %} // counted loop end branch far // counted loop end branch far unsigned // TODO: fixme // ============================================================================ // inlined locking and unlocking instruct cmpFastLock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2) %{ match(Set cr (FastLock object box)); effect(TEMP tmp, TEMP tmp2); // TODO // identify correct cost ins_cost(5 * INSN_COST); format %{ "fastlock $object,$box\t! kills $tmp,$tmp2" %} ins_encode(aarch64_enc_fast_lock(object, box, tmp, tmp2)); ins_pipe(pipe_serial); %} instruct cmpFastUnlock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2) %{ match(Set cr (FastUnlock object box)); effect(TEMP tmp, TEMP tmp2); ins_cost(5 * INSN_COST); format %{ "fastunlock $object,$box\t! kills $tmp, $tmp2" %} ins_encode(aarch64_enc_fast_unlock(object, box, tmp, tmp2)); ins_pipe(pipe_serial); %} // ============================================================================ // Safepoint Instructions // TODO // provide a near and far version of this code instruct safePoint(rFlagsReg cr, iRegP poll) %{ match(SafePoint poll); effect(KILL cr); format %{ "ldrw zr, [$poll]\t# Safepoint: poll for GC" %} ins_encode %{ __ read_polling_page(as_Register($poll$$reg), relocInfo::poll_type); %} ins_pipe(pipe_serial); // ins_pipe(iload_reg_mem); %} // ============================================================================ // Procedure Call/Return Instructions // Call Java Static Instruction instruct CallStaticJavaDirect(method meth) %{ match(CallStaticJava); effect(USE meth); ins_cost(CALL_COST); format %{ "call,static $meth \t// ==> " %} ins_encode(aarch64_enc_java_static_call(meth), aarch64_enc_call_epilog); ins_pipe(pipe_class_call); %} // TO HERE // Call Java Dynamic Instruction instruct CallDynamicJavaDirect(method meth) %{ match(CallDynamicJava); effect(USE meth); ins_cost(CALL_COST); format %{ "CALL,dynamic $meth \t// ==> " %} ins_encode(aarch64_enc_java_dynamic_call(meth), aarch64_enc_call_epilog); ins_pipe(pipe_class_call); %} // Call Runtime Instruction instruct CallRuntimeDirect(method meth) %{ match(CallRuntime); effect(USE meth); ins_cost(CALL_COST); format %{ "CALL, runtime $meth" %} ins_encode( aarch64_enc_java_to_runtime(meth) ); ins_pipe(pipe_class_call); %} // Call Runtime Instruction instruct CallLeafDirect(method meth) %{ match(CallLeaf); effect(USE meth); ins_cost(CALL_COST); format %{ "CALL, runtime leaf $meth" %} ins_encode( aarch64_enc_java_to_runtime(meth) ); ins_pipe(pipe_class_call); %} // Call Runtime Instruction instruct CallLeafNoFPDirect(method meth) %{ match(CallLeafNoFP); effect(USE meth); ins_cost(CALL_COST); format %{ "CALL, runtime leaf nofp $meth" %} ins_encode( aarch64_enc_java_to_runtime(meth) ); ins_pipe(pipe_class_call); %} instruct CallNativeDirect(method meth) %{ match(CallNative); effect(USE meth); ins_cost(CALL_COST); format %{ "CALL, native $meth" %} ins_encode( aarch64_enc_java_to_runtime(meth) ); ins_pipe(pipe_class_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(iRegPNoSp jump_target, inline_cache_RegP method_ptr) %{ match(TailCall jump_target method_ptr); ins_cost(CALL_COST); format %{ "br $jump_target\t# $method_ptr holds method" %} ins_encode(aarch64_enc_tail_call(jump_target)); ins_pipe(pipe_class_call); %} instruct TailjmpInd(iRegPNoSp jump_target, iRegP_R0 ex_oop) %{ match(TailJump jump_target ex_oop); ins_cost(CALL_COST); format %{ "br $jump_target\t# $ex_oop holds exception oop" %} ins_encode(aarch64_enc_tail_jmp(jump_target)); ins_pipe(pipe_class_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. // TODO check // should ex_oop be in r0? intel uses rax, ppc cannot use r0 so uses rarg1 instruct CreateException(iRegP_R0 ex_oop) %{ match(Set ex_oop (CreateEx)); format %{ " -- \t// exception oop; no code emitted" %} size(0); ins_encode( /*empty*/ ); ins_pipe(pipe_class_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); format %{ "b rethrow_stub" %} ins_encode( aarch64_enc_rethrow() ); ins_pipe(pipe_class_call); %} // Return Instruction // epilog node loads ret address into lr as part of frame pop instruct Ret() %{ match(Return); format %{ "ret\t// return register" %} ins_encode( aarch64_enc_ret() ); ins_pipe(pipe_branch); %} // Die now. instruct ShouldNotReachHere() %{ match(Halt); ins_cost(CALL_COST); format %{ "ShouldNotReachHere" %} ins_encode %{ if (is_reachable()) { __ stop(_halt_reason); } %} ins_pipe(pipe_class_default); %} // ============================================================================ // Partial Subtype Check // // 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 NZ for a miss or zero for a hit. The // encoding ALSO sets flags. instruct partialSubtypeCheck(iRegP_R4 sub, iRegP_R0 super, iRegP_R2 temp, iRegP_R5 result, rFlagsReg cr) %{ match(Set result (PartialSubtypeCheck sub super)); effect(KILL cr, KILL temp); ins_cost(1100); // slightly larger than the next version format %{ "partialSubtypeCheck $result, $sub, $super" %} ins_encode(aarch64_enc_partial_subtype_check(sub, super, temp, result)); opcode(0x1); // Force zero of result reg on hit ins_pipe(pipe_class_memory); %} instruct partialSubtypeCheckVsZero(iRegP_R4 sub, iRegP_R0 super, iRegP_R2 temp, iRegP_R5 result, immP0 zero, rFlagsReg cr) %{ match(Set cr (CmpP (PartialSubtypeCheck sub super) zero)); effect(KILL temp, KILL result); ins_cost(1100); // slightly larger than the next version format %{ "partialSubtypeCheck $result, $sub, $super == 0" %} ins_encode(aarch64_enc_partial_subtype_check(sub, super, temp, result)); opcode(0x0); // Don't zero result reg on hit ins_pipe(pipe_class_memory); %} instruct string_compareU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2, iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2, rFlagsReg cr) %{ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1" %} ins_encode %{ // Count is in 8-bit bytes; non-Compact chars are 16 bits. __ string_compare($str1$$Register, $str2$$Register, $cnt1$$Register, $cnt2$$Register, $result$$Register, $tmp1$$Register, $tmp2$$Register, fnoreg, fnoreg, fnoreg, StrIntrinsicNode::UU); %} ins_pipe(pipe_class_memory); %} instruct string_compareL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2, iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2, rFlagsReg cr) %{ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1" %} ins_encode %{ __ string_compare($str1$$Register, $str2$$Register, $cnt1$$Register, $cnt2$$Register, $result$$Register, $tmp1$$Register, $tmp2$$Register, fnoreg, fnoreg, fnoreg, StrIntrinsicNode::LL); %} ins_pipe(pipe_class_memory); %} instruct string_compareUL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2, iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2, vRegD_V0 vtmp1, vRegD_V1 vtmp2, vRegD_V2 vtmp3, rFlagsReg cr) %{ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(KILL tmp1, KILL tmp2, KILL vtmp1, KILL vtmp2, KILL vtmp3, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1, $tmp2, $vtmp1, $vtmp2, $vtmp3" %} ins_encode %{ __ string_compare($str1$$Register, $str2$$Register, $cnt1$$Register, $cnt2$$Register, $result$$Register, $tmp1$$Register, $tmp2$$Register, $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $vtmp3$$FloatRegister, StrIntrinsicNode::UL); %} ins_pipe(pipe_class_memory); %} instruct string_compareLU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2, iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2, vRegD_V0 vtmp1, vRegD_V1 vtmp2, vRegD_V2 vtmp3, rFlagsReg cr) %{ predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(KILL tmp1, KILL tmp2, KILL vtmp1, KILL vtmp2, KILL vtmp3, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1, $tmp2, $vtmp1, $vtmp2, $vtmp3" %} ins_encode %{ __ string_compare($str1$$Register, $str2$$Register, $cnt1$$Register, $cnt2$$Register, $result$$Register, $tmp1$$Register, $tmp2$$Register, $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $vtmp3$$FloatRegister,StrIntrinsicNode::LU); %} ins_pipe(pipe_class_memory); %} instruct string_indexofUU(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, iRegINoSp tmp4, iRegINoSp tmp5, iRegINoSp tmp6, vRegD_V0 vtmp0, vRegD_V1 vtmp1, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6, TEMP vtmp0, TEMP vtmp1, KILL cr); format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (UU) " "# KILL $str1 $cnt1 $str2 $cnt2 $tmp1 $tmp2 $tmp3 $tmp4 $tmp5 $tmp6 V0-V1 cr" %} ins_encode %{ __ string_indexof($str1$$Register, $str2$$Register, $cnt1$$Register, $cnt2$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, $tmp6$$Register, -1, $result$$Register, StrIntrinsicNode::UU); %} ins_pipe(pipe_class_memory); %} instruct string_indexofLL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, iRegINoSp tmp4, iRegINoSp tmp5, iRegINoSp tmp6, vRegD_V0 vtmp0, vRegD_V1 vtmp1, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6, TEMP vtmp0, TEMP vtmp1, KILL cr); format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (LL) " "# KILL $str1 $cnt1 $str2 $cnt2 $tmp1 $tmp2 $tmp3 $tmp4 $tmp5 $tmp6 V0-V1 cr" %} ins_encode %{ __ string_indexof($str1$$Register, $str2$$Register, $cnt1$$Register, $cnt2$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, $tmp6$$Register, -1, $result$$Register, StrIntrinsicNode::LL); %} ins_pipe(pipe_class_memory); %} instruct string_indexofUL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2,iRegINoSp tmp3, iRegINoSp tmp4, iRegINoSp tmp5, iRegINoSp tmp6, vRegD_V0 vtmp0, vRegD_V1 vtmp1, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6, TEMP vtmp0, TEMP vtmp1, KILL cr); format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (UL) " "# KILL $str1 cnt1 $str2 $cnt2 $tmp1 $tmp2 $tmp3 $tmp4 $tmp5 $tmp6 V0-V1 cr" %} ins_encode %{ __ string_indexof($str1$$Register, $str2$$Register, $cnt1$$Register, $cnt2$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, $tmp6$$Register, -1, $result$$Register, StrIntrinsicNode::UL); %} ins_pipe(pipe_class_memory); %} instruct string_indexof_conUU(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, immI_le_4 int_cnt2, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr); format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (UU) " "# KILL $str1 $cnt1 $str2 $tmp1 $tmp2 $tmp3 $tmp4 cr" %} ins_encode %{ int icnt2 = (int)$int_cnt2$$constant; __ string_indexof($str1$$Register, $str2$$Register, $cnt1$$Register, zr, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, zr, zr, icnt2, $result$$Register, StrIntrinsicNode::UU); %} ins_pipe(pipe_class_memory); %} instruct string_indexof_conLL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, immI_le_4 int_cnt2, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr); format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (LL) " "# KILL $str1 $cnt1 $str2 $tmp1 $tmp2 $tmp3 $tmp4 cr" %} ins_encode %{ int icnt2 = (int)$int_cnt2$$constant; __ string_indexof($str1$$Register, $str2$$Register, $cnt1$$Register, zr, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, zr, zr, icnt2, $result$$Register, StrIntrinsicNode::LL); %} ins_pipe(pipe_class_memory); %} instruct string_indexof_conUL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, immI_1 int_cnt2, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr); format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (UL) " "# KILL $str1 $cnt1 $str2 $tmp1 $tmp2 $tmp3 $tmp4 cr" %} ins_encode %{ int icnt2 = (int)$int_cnt2$$constant; __ string_indexof($str1$$Register, $str2$$Register, $cnt1$$Register, zr, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, zr, zr, icnt2, $result$$Register, StrIntrinsicNode::UL); %} ins_pipe(pipe_class_memory); %} instruct string_indexof_char(iRegP_R1 str1, iRegI_R2 cnt1, iRegI_R3 ch, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); predicate(((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::U); effect(USE_KILL str1, USE_KILL cnt1, USE_KILL ch, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); format %{ "StringUTF16 IndexOf char[] $str1,$cnt1,$ch -> $result" %} ins_encode %{ __ string_indexof_char($str1$$Register, $cnt1$$Register, $ch$$Register, $result$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); %} ins_pipe(pipe_class_memory); %} instruct stringL_indexof_char(iRegP_R1 str1, iRegI_R2 cnt1, iRegI_R3 ch, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); predicate(((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::L); effect(USE_KILL str1, USE_KILL cnt1, USE_KILL ch, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); format %{ "StringLatin1 IndexOf char[] $str1,$cnt1,$ch -> $result" %} ins_encode %{ __ stringL_indexof_char($str1$$Register, $cnt1$$Register, $ch$$Register, $result$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); %} ins_pipe(pipe_class_memory); %} instruct string_equalsL(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt, iRegI_R0 result, rFlagsReg cr) %{ predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL); match(Set result (StrEquals (Binary str1 str2) cnt)); effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); format %{ "String Equals $str1,$str2,$cnt -> $result" %} ins_encode %{ // Count is in 8-bit bytes; non-Compact chars are 16 bits. __ string_equals($str1$$Register, $str2$$Register, $result$$Register, $cnt$$Register, 1); %} ins_pipe(pipe_class_memory); %} instruct string_equalsU(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt, iRegI_R0 result, rFlagsReg cr) %{ predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); match(Set result (StrEquals (Binary str1 str2) cnt)); effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); format %{ "String Equals $str1,$str2,$cnt -> $result" %} ins_encode %{ // Count is in 8-bit bytes; non-Compact chars are 16 bits. __ string_equals($str1$$Register, $str2$$Register, $result$$Register, $cnt$$Register, 2); %} ins_pipe(pipe_class_memory); %} instruct array_equalsB(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, iRegP_R3 tmp1, iRegP_R4 tmp2, iRegP_R5 tmp3, vRegD_V0 vtmp0, vRegD_V1 vtmp1, vRegD_V2 vtmp2, vRegD_V3 vtmp3, vRegD_V4 vtmp4, vRegD_V5 vtmp5, vRegD_V6 vtmp6, vRegD_V7 vtmp7, iRegP_R10 tmp, rFlagsReg cr) %{ predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); match(Set result (AryEq ary1 ary2)); effect(KILL tmp, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP vtmp0, TEMP vtmp1, TEMP vtmp2, TEMP vtmp3, TEMP vtmp4, TEMP vtmp5, TEMP vtmp6, TEMP vtmp7, KILL cr); format %{ "Array Equals $ary1,ary2 -> $result # KILL $ary1 $ary2 $tmp $tmp1 $tmp2 $tmp3 V0-V7 cr" %} ins_encode %{ address tpc = __ arrays_equals($ary1$$Register, $ary2$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $result$$Register, $tmp$$Register, 1); if (tpc == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } %} ins_pipe(pipe_class_memory); %} instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, iRegP_R3 tmp1, iRegP_R4 tmp2, iRegP_R5 tmp3, vRegD_V0 vtmp0, vRegD_V1 vtmp1, vRegD_V2 vtmp2, vRegD_V3 vtmp3, vRegD_V4 vtmp4, vRegD_V5 vtmp5, vRegD_V6 vtmp6, vRegD_V7 vtmp7, iRegP_R10 tmp, rFlagsReg cr) %{ predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); match(Set result (AryEq ary1 ary2)); effect(KILL tmp, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP vtmp0, TEMP vtmp1, TEMP vtmp2, TEMP vtmp3, TEMP vtmp4, TEMP vtmp5, TEMP vtmp6, TEMP vtmp7, KILL cr); format %{ "Array Equals $ary1,ary2 -> $result # KILL $ary1 $ary2 $tmp $tmp1 $tmp2 $tmp3 V0-V7 cr" %} ins_encode %{ address tpc = __ arrays_equals($ary1$$Register, $ary2$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $result$$Register, $tmp$$Register, 2); if (tpc == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } %} ins_pipe(pipe_class_memory); %} instruct has_negatives(iRegP_R1 ary1, iRegI_R2 len, iRegI_R0 result, rFlagsReg cr) %{ match(Set result (HasNegatives ary1 len)); effect(USE_KILL ary1, USE_KILL len, KILL cr); format %{ "has negatives byte[] $ary1,$len -> $result" %} ins_encode %{ address tpc = __ has_negatives($ary1$$Register, $len$$Register, $result$$Register); if (tpc == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } %} ins_pipe( pipe_slow ); %} // fast char[] to byte[] compression instruct string_compress(iRegP_R2 src, iRegP_R1 dst, iRegI_R3 len, vRegD_V0 vtmp0, vRegD_V1 vtmp1, vRegD_V2 vtmp2, vRegD_V3 vtmp3, vRegD_V4 vtmp4, vRegD_V5 vtmp5, iRegI_R0 result, rFlagsReg cr) %{ match(Set result (StrCompressedCopy src (Binary dst len))); effect(TEMP vtmp0, TEMP vtmp1, TEMP vtmp2, TEMP vtmp3, TEMP vtmp4, TEMP vtmp5, USE_KILL src, USE_KILL dst, USE len, KILL cr); format %{ "String Compress $src,$dst,$len -> $result # KILL $src $dst V0-V5 cr" %} ins_encode %{ __ char_array_compress($src$$Register, $dst$$Register, $len$$Register, $result$$Register, $vtmp0$$FloatRegister, $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $vtmp3$$FloatRegister, $vtmp4$$FloatRegister, $vtmp5$$FloatRegister); %} ins_pipe(pipe_slow); %} // fast byte[] to char[] inflation instruct string_inflate(Universe dummy, iRegP_R0 src, iRegP_R1 dst, iRegI_R2 len, iRegP_R3 tmp, vRegD_V0 vtmp0, vRegD_V1 vtmp1, vRegD_V2 vtmp2, vRegD_V3 vtmp3, vRegD_V4 vtmp4, vRegD_V5 vtmp5, vRegD_V6 vtmp6, rFlagsReg cr) %{ match(Set dummy (StrInflatedCopy src (Binary dst len))); effect(TEMP vtmp0, TEMP vtmp1, TEMP vtmp2, TEMP vtmp3, TEMP vtmp4, TEMP vtmp5, TEMP vtmp6, TEMP tmp, USE_KILL src, USE_KILL dst, USE_KILL len, KILL cr); format %{ "String Inflate $src,$dst # KILL $tmp $src $dst $len V0-V6 cr" %} ins_encode %{ address tpc = __ byte_array_inflate($src$$Register, $dst$$Register, $len$$Register, $vtmp0$$FloatRegister, $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $tmp$$Register); if (tpc == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; } %} ins_pipe(pipe_class_memory); %} // encode char[] to byte[] in ISO_8859_1 instruct encode_iso_array(iRegP_R2 src, iRegP_R1 dst, iRegI_R3 len, vRegD_V0 vtmp0, vRegD_V1 vtmp1, vRegD_V2 vtmp2, vRegD_V3 vtmp3, vRegD_V4 vtmp4, vRegD_V5 vtmp5, iRegI_R0 result, rFlagsReg cr) %{ predicate(!((EncodeISOArrayNode*)n)->is_ascii()); match(Set result (EncodeISOArray src (Binary dst len))); effect(USE_KILL src, USE_KILL dst, USE len, KILL vtmp0, KILL vtmp1, KILL vtmp2, KILL vtmp3, KILL vtmp4, KILL vtmp5, KILL cr); format %{ "Encode ISO array $src,$dst,$len -> $result # KILL $src $dst V0-V5 cr" %} ins_encode %{ __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, $result$$Register, false, $vtmp0$$FloatRegister, $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $vtmp3$$FloatRegister, $vtmp4$$FloatRegister, $vtmp5$$FloatRegister); %} ins_pipe(pipe_class_memory); %} instruct encode_ascii_array(iRegP_R2 src, iRegP_R1 dst, iRegI_R3 len, vRegD_V0 vtmp0, vRegD_V1 vtmp1, vRegD_V2 vtmp2, vRegD_V3 vtmp3, vRegD_V4 vtmp4, vRegD_V5 vtmp5, iRegI_R0 result, rFlagsReg cr) %{ predicate(((EncodeISOArrayNode*)n)->is_ascii()); match(Set result (EncodeISOArray src (Binary dst len))); effect(USE_KILL src, USE_KILL dst, USE len, KILL vtmp0, KILL vtmp1, KILL vtmp2, KILL vtmp3, KILL vtmp4, KILL vtmp5, KILL cr); format %{ "Encode ASCII array $src,$dst,$len -> $result # KILL $src $dst V0-V5 cr" %} ins_encode %{ __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, $result$$Register, true, $vtmp0$$FloatRegister, $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $vtmp3$$FloatRegister, $vtmp4$$FloatRegister, $vtmp5$$FloatRegister); %} ins_pipe(pipe_class_memory); %} // ============================================================================ // This name is KNOWN by the ADLC and cannot be changed. // The ADLC forces a 'TypeRawPtr::BOTTOM' output type // for this guy. instruct tlsLoadP(thread_RegP dst) %{ match(Set dst (ThreadLocal)); ins_cost(0); format %{ " -- \t// $dst=Thread::current(), empty" %} size(0); ins_encode( /*empty*/ ); ins_pipe(pipe_class_empty); %} //----------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 == RAX_enc) // Only one replacement instruction // // ---------EXAMPLE---------------------------------------------------------- // // // pertinent parts of existing instructions in architecture description // instruct movI(iRegINoSp dst, iRegI src) // %{ // match(Set dst (CopyI src)); // %} // // instruct incI_iReg(iRegINoSp dst, immI1 src, rFlagsReg cr) // %{ // match(Set dst (AddI dst src)); // effect(KILL cr); // %} // // // Change (inc mov) to lea // peephole %{ // // increment preceeded by register-register move // peepmatch ( incI_iReg 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 ( leaI_iReg_immI( 0.dst 1.src 0.src ) ); // %} // // Implementation no longer uses movX instructions since // machine-independent system no longer uses CopyX nodes. // // peephole // %{ // peepmatch (incI_iReg movI); // peepconstraint (0.dst == 1.dst); // peepreplace (leaI_iReg_immI(0.dst 1.src 0.src)); // %} // peephole // %{ // peepmatch (decI_iReg movI); // peepconstraint (0.dst == 1.dst); // peepreplace (leaI_iReg_immI(0.dst 1.src 0.src)); // %} // peephole // %{ // peepmatch (addI_iReg_imm movI); // peepconstraint (0.dst == 1.dst); // peepreplace (leaI_iReg_immI(0.dst 1.src 0.src)); // %} // peephole // %{ // peepmatch (incL_iReg movL); // peepconstraint (0.dst == 1.dst); // peepreplace (leaL_iReg_immL(0.dst 1.src 0.src)); // %} // peephole // %{ // peepmatch (decL_iReg movL); // peepconstraint (0.dst == 1.dst); // peepreplace (leaL_iReg_immL(0.dst 1.src 0.src)); // %} // peephole // %{ // peepmatch (addL_iReg_imm movL); // peepconstraint (0.dst == 1.dst); // peepreplace (leaL_iReg_immL(0.dst 1.src 0.src)); // %} // peephole // %{ // peepmatch (addP_iReg_imm movP); // peepconstraint (0.dst == 1.dst); // peepreplace (leaP_iReg_imm(0.dst 1.src 0.src)); // %} // // Change load of spilled value to only a spill // instruct storeI(memory mem, iRegI src) // %{ // match(Set mem (StoreI mem src)); // %} // // instruct loadI(iRegINoSp dst, memory mem) // %{ // match(Set dst (LoadI mem)); // %} // //----------SMARTSPILL RULES--------------------------------------------------- // These must follow all instruction definitions as they use the names // defined in the instructions definitions. // Local Variables: // mode: c++ // End: