Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Impressum s390.ad   Interaktion und
Portierbarkeitunbekannt

 
Spracherkennung für: .ad vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

//
// Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2017, 2022 SAP SE. 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.
//

// z/Architecture Architecture Description File

// Major contributions by AS, JL, LS.

//
// Following information is derived from private mail communication
// (Oct. 2011).
//
// General branch target alignment considerations
//
// z/Architecture does not imply a general branch target alignment requirement.
// There are side effects and side considerations, though, which may
// provide some performance benefit. These are:
//  - Align branch target on octoword (32-byte) boundary
//    On more recent models (from z9 on), I-fetch is done on a Octoword
//    (32 bytes at a time) basis. To avoid I-fetching unnecessary
//    instructions, branch targets should be 32-byte aligend. If this
//    exact alignment cannot be achieved, having the branch target in
//    the first doubleword still provides some benefit.
//  - Avoid branch targets at the end of cache lines (> 64 bytes distance).
//    Sequential instruction prefetching after the branch target starts
//    immediately after having fetched the octoword containing the
//    branch target. When I-fetching crosses a cache line, there may be
//    a small stall. The worst case: the branch target (at the end of
//    a cache line) is a L1 I-cache miss and the next line as well.
//    Then, the entire target line must be filled first (to continue at the
//    branch target). Only then can the next sequential line be filled.
//  - Avoid multiple poorly predicted branches in a row.
//

//----------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
// architecture.

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.

// z/Architecture register definitions, based on the z/Architecture Principles
// of Operation, 5th Edition, September 2005, and z/Linux Elf ABI Supplement,
// 5th Edition, March 2001.
//
// For each 64-bit register we must define two registers: the register
// itself, e.g. Z_R3, and a corresponding virtual other (32-bit-)'half',
// e.g. Z_R3_H, which is needed by the allocator, but is not used
// for stores, loads, etc.

  // Integer/Long Registers
  // ----------------------------

  // z/Architecture has 16 64-bit integer registers.

  // types: v = volatile, nv = non-volatile, s = system
  reg_def Z_R0   (SOC, SOC, Op_RegI,  0, Z_R0->as_VMReg());   // v   scratch1
  reg_def Z_R0_H (SOC, SOC, Op_RegI, 99, Z_R0->as_VMReg()->next());
  reg_def Z_R1   (SOC, SOC, Op_RegI,  1, Z_R1->as_VMReg());   // v   scratch2
  reg_def Z_R1_H (SOC, SOC, Op_RegI, 99, Z_R1->as_VMReg()->next());
  reg_def Z_R2   (SOC, SOC, Op_RegI,  2, Z_R2->as_VMReg());   // v   iarg1 & iret
  reg_def Z_R2_H (SOC, SOC, Op_RegI, 99, Z_R2->as_VMReg()->next());
  reg_def Z_R3   (SOC, SOC, Op_RegI,  3, Z_R3->as_VMReg());   // v   iarg2
  reg_def Z_R3_H (SOC, SOC, Op_RegI, 99, Z_R3->as_VMReg()->next());
  reg_def Z_R4   (SOC, SOC, Op_RegI,  4, Z_R4->as_VMReg());   // v   iarg3
  reg_def Z_R4_H (SOC, SOC, Op_RegI, 99, Z_R4->as_VMReg()->next());
  reg_def Z_R5   (SOC, SOC, Op_RegI,  5, Z_R5->as_VMReg());   // v   iarg4
  reg_def Z_R5_H (SOC, SOC, Op_RegI, 99, Z_R5->as_VMReg()->next());
  reg_def Z_R6   (SOC, SOE, Op_RegI,  6, Z_R6->as_VMReg());   // v   iarg5
  reg_def Z_R6_H (SOC, SOE, Op_RegI, 99, Z_R6->as_VMReg()->next());
  reg_def Z_R7   (SOC, SOE, Op_RegI,  7, Z_R7->as_VMReg());
  reg_def Z_R7_H (SOC, SOE, Op_RegI, 99, Z_R7->as_VMReg()->next());
  reg_def Z_R8   (SOC, SOE, Op_RegI,  8, Z_R8->as_VMReg());
  reg_def Z_R8_H (SOC, SOE, Op_RegI, 99, Z_R8->as_VMReg()->next());
  reg_def Z_R9   (SOC, SOE, Op_RegI,  9, Z_R9->as_VMReg());
  reg_def Z_R9_H (SOC, SOE, Op_RegI, 99, Z_R9->as_VMReg()->next());
  reg_def Z_R10  (SOC, SOE, Op_RegI, 10, Z_R10->as_VMReg());
  reg_def Z_R10_H(SOC, SOE, Op_RegI, 99, Z_R10->as_VMReg()->next());
  reg_def Z_R11  (SOC, SOE, Op_RegI, 11, Z_R11->as_VMReg());
  reg_def Z_R11_H(SOC, SOE, Op_RegI, 99, Z_R11->as_VMReg()->next());
  reg_def Z_R12  (SOC, SOE, Op_RegI, 12, Z_R12->as_VMReg());
  reg_def Z_R12_H(SOC, SOE, Op_RegI, 99, Z_R12->as_VMReg()->next());
  reg_def Z_R13  (SOC, SOE, Op_RegI, 13, Z_R13->as_VMReg());
  reg_def Z_R13_H(SOC, SOE, Op_RegI, 99, Z_R13->as_VMReg()->next());
  reg_def Z_R14  (NS,  NS,  Op_RegI, 14, Z_R14->as_VMReg());   // s  return_pc
  reg_def Z_R14_H(NS,  NS,  Op_RegI, 99, Z_R14->as_VMReg()->next());
  reg_def Z_R15  (NS,  NS,  Op_RegI, 15, Z_R15->as_VMReg());   // s  SP
  reg_def Z_R15_H(NS,  NS,  Op_RegI, 99, Z_R15->as_VMReg()->next());

  // Float/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.

  // z/Architecture has 16 64-bit floating-point registers. Each can store a single
  // or double precision floating-point value.

  // types: v = volatile, nv = non-volatile, s = system
  reg_def Z_F0   (SOC, SOC, Op_RegF,  0, Z_F0->as_VMReg());   // v   farg1 & fret
  reg_def Z_F0_H (SOC, SOC, Op_RegF, 99, Z_F0->as_VMReg()->next());
  reg_def Z_F1   (SOC, SOC, Op_RegF,  1, Z_F1->as_VMReg());
  reg_def Z_F1_H (SOC, SOC, Op_RegF, 99, Z_F1->as_VMReg()->next());
  reg_def Z_F2   (SOC, SOC, Op_RegF,  2, Z_F2->as_VMReg());   // v   farg2
  reg_def Z_F2_H (SOC, SOC, Op_RegF, 99, Z_F2->as_VMReg()->next());
  reg_def Z_F3   (SOC, SOC, Op_RegF,  3, Z_F3->as_VMReg());
  reg_def Z_F3_H (SOC, SOC, Op_RegF, 99, Z_F3->as_VMReg()->next());
  reg_def Z_F4   (SOC, SOC, Op_RegF,  4, Z_F4->as_VMReg());   // v   farg3
  reg_def Z_F4_H (SOC, SOC, Op_RegF, 99, Z_F4->as_VMReg()->next());
  reg_def Z_F5   (SOC, SOC, Op_RegF,  5, Z_F5->as_VMReg());
  reg_def Z_F5_H (SOC, SOC, Op_RegF, 99, Z_F5->as_VMReg()->next());
  reg_def Z_F6   (SOC, SOC, Op_RegF,  6, Z_F6->as_VMReg());
  reg_def Z_F6_H (SOC, SOC, Op_RegF, 99, Z_F6->as_VMReg()->next());
  reg_def Z_F7   (SOC, SOC, Op_RegF,  7, Z_F7->as_VMReg());
  reg_def Z_F7_H (SOC, SOC, Op_RegF, 99, Z_F7->as_VMReg()->next());
  reg_def Z_F8   (SOC, SOE, Op_RegF,  8, Z_F8->as_VMReg());
  reg_def Z_F8_H (SOC, SOE, Op_RegF, 99, Z_F8->as_VMReg()->next());
  reg_def Z_F9   (SOC, SOE, Op_RegF,  9, Z_F9->as_VMReg());
  reg_def Z_F9_H (SOC, SOE, Op_RegF, 99, Z_F9->as_VMReg()->next());
  reg_def Z_F10  (SOC, SOE, Op_RegF, 10, Z_F10->as_VMReg());
  reg_def Z_F10_H(SOC, SOE, Op_RegF, 99, Z_F10->as_VMReg()->next());
  reg_def Z_F11  (SOC, SOE, Op_RegF, 11, Z_F11->as_VMReg());
  reg_def Z_F11_H(SOC, SOE, Op_RegF, 99, Z_F11->as_VMReg()->next());
  reg_def Z_F12  (SOC, SOE, Op_RegF, 12, Z_F12->as_VMReg());
  reg_def Z_F12_H(SOC, SOE, Op_RegF, 99, Z_F12->as_VMReg()->next());
  reg_def Z_F13  (SOC, SOE, Op_RegF, 13, Z_F13->as_VMReg());
  reg_def Z_F13_H(SOC, SOE, Op_RegF, 99, Z_F13->as_VMReg()->next());
  reg_def Z_F14  (SOC, SOE, Op_RegF, 14, Z_F14->as_VMReg());
  reg_def Z_F14_H(SOC, SOE, Op_RegF, 99, Z_F14->as_VMReg()->next());
  reg_def Z_F15  (SOC, SOE, Op_RegF, 15, Z_F15->as_VMReg());
  reg_def Z_F15_H(SOC, SOE, Op_RegF, 99, Z_F15->as_VMReg()->next());


  // Special Registers

  // Condition Codes Flag Registers

  // z/Architecture has the PSW (program status word) that contains
  // (among other information) the condition code. We treat this
  // part of the PSW as a condition register CR. It consists of 4
  // bits. Floating point instructions influence the same condition register CR.

  reg_def Z_CR(SOC, SOC, Op_RegFlags, 0, Z_CR->as_VMReg());   // volatile


// 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, and choose no-save registers before save-on-call, and
// save-on-call before save-on-entry. Registers which participate in
// fix calling sequences should come last. Registers which are used
// as pairs must fall on an even boundary.

// It's worth about 1% on SPEC geomean to get this right.

// Chunk0, chunk1, and chunk2 form the MachRegisterNumbers enumeration
// in adGlobals_s390.hpp which defines the <register>_num values, e.g.
// Z_R3_num. Therefore, Z_R3_num may not be (and in reality is not)
// the same as Z_R3->encoding()! Furthermore, we cannot make any
// assumptions on ordering, e.g. Z_R3_num may be less than Z_R2_num.
// Additionally, the function
//   static enum RC rc_class(OptoReg::Name reg)
// maps a given <register>_num value to its chunk type (except for flags)
// and its current implementation relies on chunk0 and chunk1 having a
// size of 64 each.

alloc_class chunk0(
  // chunk0 contains *all* 32 integer registers halves.

  // potential SOE regs
  Z_R13,Z_R13_H,
  Z_R12,Z_R12_H,
  Z_R11,Z_R11_H,
  Z_R10,Z_R10_H,

  Z_R9,Z_R9_H,
  Z_R8,Z_R8_H,
  Z_R7,Z_R7_H,

  Z_R1,Z_R1_H,
  Z_R0,Z_R0_H,

  // argument registers
  Z_R6,Z_R6_H,
  Z_R5,Z_R5_H,
  Z_R4,Z_R4_H,
  Z_R3,Z_R3_H,
  Z_R2,Z_R2_H,

  // special registers
  Z_R14,Z_R14_H,
  Z_R15,Z_R15_H
);

alloc_class chunk1(
  // Chunk1 contains *all* 64 floating-point registers halves.

  Z_F15,Z_F15_H,
  Z_F14,Z_F14_H,
  Z_F13,Z_F13_H,
  Z_F12,Z_F12_H,
  Z_F11,Z_F11_H,
  Z_F10,Z_F10_H,
  Z_F9,Z_F9_H,
  Z_F8,Z_F8_H,
  // scratch register
  Z_F7,Z_F7_H,
  Z_F5,Z_F5_H,
  Z_F3,Z_F3_H,
  Z_F1,Z_F1_H,
  // argument registers
  Z_F6,Z_F6_H,
  Z_F4,Z_F4_H,
  Z_F2,Z_F2_H,
  Z_F0,Z_F0_H
);

alloc_class chunk2(
  Z_CR
);


//-------Architecture Description Register Classes-----------------------

// Several register classes are automatically defined based upon
// information in this architecture description.

// 1) reg_class inline_cache_reg           (as defined in frame section)
// 2) reg_class stack_slots(/* one chunk of stack-based "registers" */)

// Integer Register Classes
reg_class z_int_reg(
/*Z_R0*/              // R0
/*Z_R1*/
  Z_R2,
  Z_R3,
  Z_R4,
  Z_R5,
  Z_R6,
  Z_R7,
/*Z_R8,*/             // Z_thread
  Z_R9,
  Z_R10,
  Z_R11,
  Z_R12,
  Z_R13
/*Z_R14*/             // return_pc
/*Z_R15*/             // SP
);

reg_class z_no_odd_int_reg(
/*Z_R0*/              // R0
/*Z_R1*/
  Z_R2,
  Z_R3,
  Z_R4,
/*Z_R5,*/             // odd part of fix register pair
  Z_R6,
  Z_R7,
/*Z_R8,*/             // Z_thread
  Z_R9,
  Z_R10,
  Z_R11,
  Z_R12,
  Z_R13
/*Z_R14*/             // return_pc
/*Z_R15*/             // SP
);

reg_class z_no_arg_int_reg(
/*Z_R0*/              // R0
/*Z_R1*/              // scratch
/*Z_R2*/
/*Z_R3*/
/*Z_R4*/
/*Z_R5*/
/*Z_R6*/
  Z_R7,
/*Z_R8*/              // Z_thread
  Z_R9,
  Z_R10,
  Z_R11,
  Z_R12,
  Z_R13
/*Z_R14*/             // return_pc
/*Z_R15*/             // SP
);

reg_class z_rarg1_int_reg(Z_R2);
reg_class z_rarg2_int_reg(Z_R3);
reg_class z_rarg3_int_reg(Z_R4);
reg_class z_rarg4_int_reg(Z_R5);
reg_class z_rarg5_int_reg(Z_R6);

// Pointer Register Classes

// 64-bit build means 64-bit pointers means hi/lo pairs.

reg_class z_rarg5_ptrN_reg(Z_R6);

reg_class z_rarg1_ptr_reg(Z_R2_H,Z_R2);
reg_class z_rarg2_ptr_reg(Z_R3_H,Z_R3);
reg_class z_rarg3_ptr_reg(Z_R4_H,Z_R4);
reg_class z_rarg4_ptr_reg(Z_R5_H,Z_R5);
reg_class z_rarg5_ptr_reg(Z_R6_H,Z_R6);
reg_class z_thread_ptr_reg(Z_R8_H,Z_R8);

reg_class z_ptr_reg(
/*Z_R0_H,Z_R0*/     // R0
/*Z_R1_H,Z_R1*/
  Z_R2_H,Z_R2,
  Z_R3_H,Z_R3,
  Z_R4_H,Z_R4,
  Z_R5_H,Z_R5,
  Z_R6_H,Z_R6,
  Z_R7_H,Z_R7,
/*Z_R8_H,Z_R8,*/    // Z_thread
  Z_R9_H,Z_R9,
  Z_R10_H,Z_R10,
  Z_R11_H,Z_R11,
  Z_R12_H,Z_R12,
  Z_R13_H,Z_R13
/*Z_R14_H,Z_R14*/   // return_pc
/*Z_R15_H,Z_R15*/   // SP
);

reg_class z_lock_ptr_reg(
/*Z_R0_H,Z_R0*/     // R0
/*Z_R1_H,Z_R1*/
  Z_R2_H,Z_R2,
  Z_R3_H,Z_R3,
  Z_R4_H,Z_R4,
/*Z_R5_H,Z_R5,*/
/*Z_R6_H,Z_R6,*/
  Z_R7_H,Z_R7,
/*Z_R8_H,Z_R8,*/    // Z_thread
  Z_R9_H,Z_R9,
  Z_R10_H,Z_R10,
  Z_R11_H,Z_R11,
  Z_R12_H,Z_R12,
  Z_R13_H,Z_R13
/*Z_R14_H,Z_R14*/   // return_pc
/*Z_R15_H,Z_R15*/   // SP
);

reg_class z_no_arg_ptr_reg(
/*Z_R0_H,Z_R0*/        // R0
/*Z_R1_H,Z_R1*/        // scratch
/*Z_R2_H,Z_R2*/
/*Z_R3_H,Z_R3*/
/*Z_R4_H,Z_R4*/
/*Z_R5_H,Z_R5*/
/*Z_R6_H,Z_R6*/
  Z_R7_H, Z_R7,
/*Z_R8_H,Z_R8*/        // Z_thread
  Z_R9_H,Z_R9,
  Z_R10_H,Z_R10,
  Z_R11_H,Z_R11,
  Z_R12_H,Z_R12,
  Z_R13_H,Z_R13
/*Z_R14_H,Z_R14*/      // return_pc
/*Z_R15_H,Z_R15*/      // SP
);

// Special class for storeP instructions, which can store SP or RPC to
// TLS. (Note: Do not generalize this to "any_reg". If you add
// another register, such as FP, to this mask, the allocator may try
// to put a temp in it.)
// Register class for memory access base registers,
// This class is a superset of z_ptr_reg including Z_thread.
reg_class z_memory_ptr_reg(
/*Z_R0_H,Z_R0*/     // R0
/*Z_R1_H,Z_R1*/
  Z_R2_H,Z_R2,
  Z_R3_H,Z_R3,
  Z_R4_H,Z_R4,
  Z_R5_H,Z_R5,
  Z_R6_H,Z_R6,
  Z_R7_H,Z_R7,
  Z_R8_H,Z_R8,      // Z_thread
  Z_R9_H,Z_R9,
  Z_R10_H,Z_R10,
  Z_R11_H,Z_R11,
  Z_R12_H,Z_R12,
  Z_R13_H,Z_R13
/*Z_R14_H,Z_R14*/   // return_pc
/*Z_R15_H,Z_R15*/   // SP
);

// Other special pointer regs.
reg_class z_r1_regP(Z_R1_H,Z_R1);
reg_class z_r9_regP(Z_R9_H,Z_R9);


// Long Register Classes

reg_class z_rarg1_long_reg(Z_R2_H,Z_R2);
reg_class z_rarg2_long_reg(Z_R3_H,Z_R3);
reg_class z_rarg3_long_reg(Z_R4_H,Z_R4);
reg_class z_rarg4_long_reg(Z_R5_H,Z_R5);
reg_class z_rarg5_long_reg(Z_R6_H,Z_R6);

// Longs in 1 register. Aligned adjacent hi/lo pairs.
reg_class z_long_reg(
/*Z_R0_H,Z_R0*/     // R0
/*Z_R1_H,Z_R1*/
  Z_R2_H,Z_R2,
  Z_R3_H,Z_R3,
  Z_R4_H,Z_R4,
  Z_R5_H,Z_R5,
  Z_R6_H,Z_R6,
  Z_R7_H,Z_R7,
/*Z_R8_H,Z_R8,*/    // Z_thread
  Z_R9_H,Z_R9,
  Z_R10_H,Z_R10,
  Z_R11_H,Z_R11,
  Z_R12_H,Z_R12,
  Z_R13_H,Z_R13
/*Z_R14_H,Z_R14,*/  // return_pc
/*Z_R15_H,Z_R15*/   // SP
);

// z_long_reg without even registers
reg_class z_long_odd_reg(
/*Z_R0_H,Z_R0*/     // R0
/*Z_R1_H,Z_R1*/
  Z_R3_H,Z_R3,
  Z_R5_H,Z_R5,
  Z_R7_H,Z_R7,
  Z_R9_H,Z_R9,
  Z_R11_H,Z_R11,
  Z_R13_H,Z_R13
/*Z_R14_H,Z_R14,*/  // return_pc
/*Z_R15_H,Z_R15*/   // SP
);

// Special Class for Condition Code Flags Register

reg_class z_condition_reg(
  Z_CR
);

// Scratch register for late profiling. Callee saved.
reg_class z_rscratch2_bits64_reg(Z_R2_H, Z_R2);


// Float Register Classes

reg_class z_flt_reg(
  Z_F0,
/*Z_F1,*/ // scratch
  Z_F2,
  Z_F3,
  Z_F4,
  Z_F5,
  Z_F6,
  Z_F7,
  Z_F8,
  Z_F9,
  Z_F10,
  Z_F11,
  Z_F12,
  Z_F13,
  Z_F14,
  Z_F15
);
reg_class z_rscratch1_flt_reg(Z_F1);

// Double precision float registers have virtual `high halves' that
// are needed by the allocator.
reg_class z_dbl_reg(
  Z_F0,Z_F0_H,
/*Z_F1,Z_F1_H,*/ // scratch
  Z_F2,Z_F2_H,
  Z_F3,Z_F3_H,
  Z_F4,Z_F4_H,
  Z_F5,Z_F5_H,
  Z_F6,Z_F6_H,
  Z_F7,Z_F7_H,
  Z_F8,Z_F8_H,
  Z_F9,Z_F9_H,
  Z_F10,Z_F10_H,
  Z_F11,Z_F11_H,
  Z_F12,Z_F12_H,
  Z_F13,Z_F13_H,
  Z_F14,Z_F14_H,
  Z_F15,Z_F15_H
);
reg_class z_rscratch1_dbl_reg(Z_F1,Z_F1_H);

%}

//----------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  <name>         (<int_value>, <expression>);
// Generated Code in ad_<arch>.hpp
//        #define  <name>   (<expression>)
//        // value == <int_value>
// Generated code in ad_<arch>.cpp adlc_verification()
//        assert(<name> == <int_value>, "Expect (<expression>) to equal <int_value>");
//
definitions %{
  // The default cost (of an ALU instruction).
  int_def DEFAULT_COST      (   100,     100);
  int_def DEFAULT_COST_LOW  (    80,      80);
  int_def DEFAULT_COST_HIGH (   120,     120);
  int_def HUGE_COST         (1000000, 1000000);

  // Put an advantage on REG_MEM vs. MEM+REG_REG operations.
  int_def ALU_REG_COST      (   100, DEFAULT_COST);
  int_def ALU_MEMORY_COST   (   150,          150);

  // Memory refs are twice as expensive as run-of-the-mill.
  int_def MEMORY_REF_COST_HI (   220, 2 * DEFAULT_COST+20);
  int_def MEMORY_REF_COST    (   200, 2 * DEFAULT_COST);
  int_def MEMORY_REF_COST_LO (   180, 2 * DEFAULT_COST-20);

  // Branches are even more expensive.
  int_def BRANCH_COST       (   300, DEFAULT_COST * 3);
  int_def CALL_COST         (   300, DEFAULT_COST * 3);
%}

source %{

#ifdef PRODUCT
#define BLOCK_COMMENT(str)
#define BIND(label)        __ bind(label)
#else
#define BLOCK_COMMENT(str) __ block_comment(str)
#define BIND(label)        __ bind(label); BLOCK_COMMENT(#label ":")
#endif

#define __ _masm.

#define Z_DISP_SIZE Immediate::is_uimm12((long)opnd_array(1)->disp(ra_,this,2)) ?  4 : 6
#define Z_DISP3_SIZE 6

// Tertiary op of a LoadP or StoreP encoding.
#define REGP_OP true

// Given a register encoding, produce an Integer Register object.
static Register reg_to_register_object(int register_encoding);

// ****************************************************************************

// REQUIRED FUNCTIONALITY

// !!!!! Special hack to get all type of calls to specify the byte offset
//       from the start of the call to the point where the return address
//       will point.

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;
}

int MachCallStaticJavaNode::ret_addr_offset() {
  if (_method) {
    return 8;
  } else {
    return MacroAssembler::call_far_patchable_ret_addr_offset();
  }
}

int MachCallDynamicJavaNode::ret_addr_offset() {
  // Consider size of receiver type profiling (C2 tiers).
  int profile_receiver_type_size = 0;

  int vtable_index = this->_vtable_index;
  if (vtable_index == -4) {
    return 14 + profile_receiver_type_size;
  } else {
    assert(!UseInlineCaches, "expect vtable calls only if not using ICs");
    return 36 + profile_receiver_type_size;
  }
}

int MachCallRuntimeNode::ret_addr_offset() {
  return 12 + MacroAssembler::call_far_patchable_ret_addr_offset();
}

// Compute padding required for nodes which need alignment
//
// The addresses of the call instructions needs to be 4-byte aligned to
// ensure that they don't span a cache line so that they are atomically patchable.
// The actual calls get emitted at different offsets within the node emitters.
// ins_alignment needs to be set to 2 which means that up to 1 nop may get inserted.

int CallStaticJavaDirect_dynTOCNode::compute_padding(int current_offset) const {
  return (0 - current_offset) & 2;
}

int CallDynamicJavaDirect_dynTOCNode::compute_padding(int current_offset) const {
  return (6 - current_offset) & 2;
}

int CallRuntimeDirectNode::compute_padding(int current_offset) const {
  return (12 - current_offset) & 2;
}

int CallLeafDirectNode::compute_padding(int current_offset) const {
  return (12 - current_offset) & 2;
}

int CallLeafNoFPDirectNode::compute_padding(int current_offset) const {
  return (12 - current_offset) & 2;
}

void emit_nop(CodeBuffer &cbuf) {
  C2_MacroAssembler _masm(&cbuf);
  __ z_nop();
}

// Emit an interrupt that is caught by the debugger (for debugging compiler).
void emit_break(CodeBuffer &cbuf) {
  C2_MacroAssembler _masm(&cbuf);
  __ z_illtrap();
}

#if !defined(PRODUCT)
void MachBreakpointNode::format(PhaseRegAlloc *, outputStream *os) const {
  os->print("TA");
}
#endif

void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  emit_break(cbuf);
}

uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const {
  return MachNode::size(ra_);
}

static inline void z_emit16(CodeBuffer &cbuf, long value) {
  C2_MacroAssembler _masm(&cbuf);
  __ emit_instruction((unsigned long)value, 2);
}

static inline void z_emit32(CodeBuffer &cbuf, long value) {
  C2_MacroAssembler _masm(&cbuf);
  __ emit_instruction((unsigned long)value, 4);
}

static inline void z_emit48(CodeBuffer &cbuf, long value) {
  C2_MacroAssembler _masm(&cbuf);
  __ emit_instruction((unsigned long)value, 6);
}

static inline unsigned int z_emit_inst(CodeBuffer &cbuf, long value) {
  if (value < 0) {
    // There obviously has been an unintended sign extension (int->long). Revert it.
    value = (long)((unsigned long)((unsigned int)value));
  }

  C2_MacroAssembler _masm(&cbuf);
  int len = __ emit_instruction((unsigned long)value, 0);
  return len;
}

// Check effective address (at runtime) for required alignment.
static inline void z_assert_aligned(CodeBuffer &cbuf, int disp, Register index, Register base, int alignment) {
  C2_MacroAssembler _masm(&cbuf);

  __ z_lay(Z_R0, disp, index, base);
  __ z_nill(Z_R0, alignment-1);
  __ z_brc(Assembler::bcondEqual, +3);
  __ z_illtrap();
}

int emit_call_reloc(C2_MacroAssembler &_masm, intptr_t entry_point, relocInfo::relocType rtype,
                    PhaseRegAlloc* ra_, bool is_native_call = false) {
  __ set_inst_mark(); // Used in z_enc_java_static_call() and emit_java_to_interp().
  address old_mark = __ inst_mark();
  unsigned int start_off = __ offset();

  if (is_native_call) {
    ShouldNotReachHere();
  }

  if (rtype == relocInfo::runtime_call_w_cp_type) {
    assert((__ offset() & 2) == 0, "misaligned emit_call_reloc");
    address call_addr = __ call_c_opt((address)entry_point);
    if (call_addr == NULL) {
      Compile::current()->env()->record_out_of_memory_failure();
      return -1;
    }
  } else {
    assert(rtype == relocInfo::none || rtype == relocInfo::opt_virtual_call_type ||
           rtype == relocInfo::static_call_type, "unexpected rtype");
    __ relocate(rtype);
    // BRASL must be prepended with a nop to identify it in the instruction stream.
    __ z_nop();
    __ z_brasl(Z_R14, (address)entry_point);
  }

  unsigned int ret_off = __ offset();

  return (ret_off - start_off);
}

static int emit_call_reloc(C2_MacroAssembler &_masm, intptr_t entry_point, RelocationHolder const& rspec) {
  __ set_inst_mark(); // Used in z_enc_java_static_call() and emit_java_to_interp().
  address old_mark = __ inst_mark();
  unsigned int start_off = __ offset();

  relocInfo::relocType rtype = rspec.type();
  assert(rtype == relocInfo::opt_virtual_call_type || rtype == relocInfo::static_call_type,
         "unexpected rtype");

  __ relocate(rspec);
  __ z_nop();
  __ z_brasl(Z_R14, (address)entry_point);

  unsigned int ret_off = __ offset();

  return (ret_off - start_off);
}

//=============================================================================

const RegMask& MachConstantBaseNode::_out_RegMask = _Z_PTR_REG_mask;
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 <Node *> *nodes, PhaseRegAlloc *ra_) {
  ShouldNotReachHere();
}

// Even with PC-relative TOC addressing, we still need this node.
// Float loads/stores do not support PC-relative addresses.
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
  C2_MacroAssembler _masm(&cbuf);
  Register Rtoc = as_Register(ra_->get_encode(this));
  __ load_toc(Rtoc);
}

uint MachConstantBaseNode::size(PhaseRegAlloc* ra_) const {
  // PCrelative TOC access.
  return 6;   // sizeof(LARL)
}

#if !defined(PRODUCT)
void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
  Register r = as_Register(ra_->get_encode(this));
  st->print("LARL    %s,&constant_pool # MachConstantBaseNode", r->name());
}
#endif

//=============================================================================

#include "gc/shared/barrierSetAssembler.hpp"

#if !defined(PRODUCT)
void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
  Compile* C = ra_->C;
  st->print_cr("--- MachPrologNode ---");
  st->print("\t");
  for (int i = 0; i < OptoPrologueNops; i++) {
    st->print_cr("NOP"); st->print("\t");
  }

  if (VerifyThread) {
    st->print_cr("Verify_Thread");
    st->print("\t");
  }

  long framesize = C->output()->frame_size_in_bytes();
  int bangsize   = C->output()->bang_size_in_bytes();

  // Calls to C2R adapters often do not accept exceptional returns.
  // We require that their callers must bang for them. But be
  // careful, because some VM calls (such as call site linkage) can
  // use several kilobytes of stack. But the stack safety zone should
  // account for that. See bugs 4446381, 4468289, 4497237.
  if (C->output()->need_stack_bang(bangsize)) {
    st->print_cr("# stack bang"); st->print("\t");
  }
  st->print_cr("push_frame %d", (int)-framesize);
  st->print("\t");

  if (C->stub_function() == NULL) {
    st->print("nmethod entry barrier\n\t");
  }
}
#endif

void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  Compile* C = ra_->C;
  C2_MacroAssembler _masm(&cbuf);

  __ verify_thread();

  size_t framesize = C->output()->frame_size_in_bytes();
  size_t bangsize  = C->output()->bang_size_in_bytes();

  assert(framesize % wordSize == 0, "must preserve wordSize alignment");

  if (C->clinit_barrier_on_entry()) {
    assert(!C->method()->holder()->is_not_initialized(), "initialization should have been started");

    Label L_skip_barrier;
    Register klass = Z_R1_scratch;

    // Notify OOP recorder (don't need the relocation)
    AddressLiteral md = __ constant_metadata_address(C->method()->holder()->constant_encoding());
    __ load_const_optimized(klass, md.value());
    __ clinit_barrier(klass, Z_thread, &L_skip_barrier /*L_fast_path*/);

    __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub());
    __ z_br(klass);

    __ bind(L_skip_barrier);
  }

  // Calls to C2R adapters often do not accept exceptional returns.
  // We require that their callers must bang for them. But be
  // careful, because some VM calls (such as call site linkage) can
  // use several kilobytes of stack. But the stack safety zone should
  // account for that. See bugs 4446381, 4468289, 4497237.
  if (C->output()->need_stack_bang(bangsize)) {
    __ generate_stack_overflow_check(bangsize);
  }

  assert(Immediate::is_uimm32((long)framesize), "to do: choose suitable types!");
  __ save_return_pc();

  // The z/Architecture abi is already accounted for in `framesize' via the
  // 'out_preserve_stack_slots' declaration.
  __ push_frame((unsigned int)framesize/*includes JIT ABI*/);

  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());
  }

  if (C->stub_function() == NULL) {
    BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
    bs->nmethod_entry_barrier(&_masm);
  }

  C->output()->set_frame_complete(cbuf.insts_size());
}

uint MachPrologNode::size(PhaseRegAlloc *ra_) const {
  // Variable size. Determine dynamically.
  return MachNode::size(ra_);
}

int MachPrologNode::reloc() const {
  // Return number of relocatable values contained in this instruction.
  return 1; // One reloc entry for load_const(toc).
}

//=============================================================================

#if !defined(PRODUCT)
void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *os) const {
  os->print_cr("epilog");
  os->print("\t");
  if (do_polling() && ra_->C->is_method_compilation()) {
    os->print_cr("load_from_polling_page Z_R1_scratch");
    os->print("\t");
  }
}
#endif

void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  C2_MacroAssembler _masm(&cbuf);
  Compile* C = ra_->C;
  __ verify_thread();

  // If this does safepoint polling, then do it here.
  bool need_polling = do_polling() && C->is_method_compilation();

  // Pop frame, restore return_pc, and all stuff needed by interpreter.
  int frame_size_in_bytes = Assembler::align((C->output()->frame_slots() << LogBytesPerInt), frame::alignment_in_bytes);
  __ pop_frame_restore_retPC(frame_size_in_bytes);

  if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
    __ reserved_stack_check(Z_R14);
  }

  // Touch the polling page.
  if (need_polling) {
    __ z_lg(Z_R1_scratch, Address(Z_thread, JavaThread::polling_page_offset()));
    // We need to mark the code position where the load from the safepoint
    // polling page was emitted as relocInfo::poll_return_type here.
    __ relocate(relocInfo::poll_return_type);
    __ load_from_polling_page(Z_R1_scratch);
  }
}

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; // One for load_from_polling_page.
}

const Pipeline * MachEpilogNode::pipeline() const {
  return MachNode::pipeline_class();
}

//=============================================================================

// Figure out which register class each belongs in: rc_int, rc_float, rc_stack.
enum RC { rc_bad, rc_int, rc_float, rc_stack };

static enum RC rc_class(OptoReg::Name reg) {
  // Return the register class for the given register. The given register
  // reg is a <register>_num value, which is an index into the MachRegisterNumbers
  // enumeration in adGlobals_s390.hpp.

  if (reg == OptoReg::Bad) {
    return rc_bad;
  }

  // We have 32 integer register halves, starting at index 0.
  if (reg < 32) {
    return rc_int;
  }

  // We have 32 floating-point register halves, starting at index 32.
  if (reg < 32+32) {
    return rc_float;
  }

  // Between float regs & stack are the flags regs.
  assert(reg >= OptoReg::stack0(), "blow up if spilling flags");
  return rc_stack;
}

// Returns size as obtained from z_emit_instr.
static unsigned int z_ld_st_helper(CodeBuffer *cbuf, const char *op_str, unsigned long opcode,
                                   int reg, int offset, bool do_print, outputStream *os) {

  if (cbuf) {
    if (opcode > (1L<<32)) {
      return z_emit_inst(*cbuf, opcode | Assembler::reg(Matcher::_regEncode[reg], 8, 48) |
                         Assembler::simm20(offset) | Assembler::reg(Z_R0, 12, 48) | Assembler::regz(Z_SP, 16, 48));
    } else {
      return z_emit_inst(*cbuf, opcode | Assembler::reg(Matcher::_regEncode[reg], 8, 32) |
                         Assembler::uimm12(offset, 20, 32) | Assembler::reg(Z_R0, 12, 32) | Assembler::regz(Z_SP, 16, 32));
    }
  }

#if !defined(PRODUCT)
  if (do_print) {
    os->print("%s    %s,#%d[,SP]\t # MachCopy spill code",op_str, Matcher::regName[reg], offset);
  }
#endif
  return (opcode > (1L << 32)) ? 6 : 4;
}

static unsigned int z_mvc_helper(CodeBuffer *cbuf, int len, int dst_off, int src_off, bool do_print, outputStream *os) {
  if (cbuf) {
    C2_MacroAssembler _masm(cbuf);
    __ z_mvc(dst_off, len-1, Z_SP, src_off, Z_SP);
  }

#if !defined(PRODUCT)
  else if (do_print) {
    os->print("MVC     %d(%d,SP),%d(SP)\t # MachCopy spill code",dst_off, len, src_off);
  }
#endif

  return 6;
}

uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, bool do_size, outputStream *os) const {
  // 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");
  bool is64 = (src_hi_rc != rc_bad);
  assert(!is64 ||
         ((src_lo&1) == 0 && src_lo+1 == src_hi && (dst_lo&1) == 0 && dst_lo+1 == dst_hi),
         "expected aligned-adjacent pairs");

  // Generate spill code!

  if (src_lo == dst_lo && src_hi == dst_hi) {
    return 0;            // Self copy, no move.
  }

  int  src_offset = ra_->reg2offset(src_lo);
  int  dst_offset = ra_->reg2offset(dst_lo);
  bool print = !do_size;
  bool src12 = Immediate::is_uimm12(src_offset);
  bool dst12 = Immediate::is_uimm12(dst_offset);

  const char   *mnemo = NULL;
  unsigned long opc = 0;

  // Memory->Memory Spill. Use Z_R0 to hold the value.
  if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {

    assert(!is64 || (src_hi_rc==rc_stack && dst_hi_rc==rc_stack),
           "expected same type of move for high parts");

    if (src12 && dst12) {
      return z_mvc_helper(cbuf, is64 ? 8 : 4, dst_offset, src_offset, print, os);
    }

    int r0 = Z_R0_num;
    if (is64) {
      return z_ld_st_helper(cbuf, "LG  ", LG_ZOPC, r0, src_offset, print, os) +
             z_ld_st_helper(cbuf, "STG ", STG_ZOPC, r0, dst_offset, print, os);
    }

    return z_ld_st_helper(cbuf, "LY   ", LY_ZOPC, r0, src_offset, print, os) +
           z_ld_st_helper(cbuf, "STY  ", STY_ZOPC, r0, dst_offset, print, os);
  }

  // Check for float->int copy. Requires a trip through memory.
  if (src_lo_rc == rc_float && dst_lo_rc == rc_int) {
    Unimplemented();  // Unsafe, do not remove!
  }

  // Check for integer reg-reg copy.
  if (src_lo_rc == rc_int && dst_lo_rc == rc_int) {
    if (cbuf) {
      C2_MacroAssembler _masm(cbuf);
      Register Rsrc = as_Register(Matcher::_regEncode[src_lo]);
      Register Rdst = as_Register(Matcher::_regEncode[dst_lo]);
      __ z_lgr(Rdst, Rsrc);
      return 4;
    }
#if !defined(PRODUCT)
    // else
    if (print) {
      os->print("LGR     %s,%s\t # MachCopy spill code", Matcher::regName[dst_lo], Matcher::regName[src_lo]);
    }
#endif
    return 4;
  }

  // Check for integer store.
  if (src_lo_rc == rc_int && dst_lo_rc == rc_stack) {
    assert(!is64 || (src_hi_rc==rc_int && dst_hi_rc==rc_stack),
           "expected same type of move for high parts");

    if (is64) {
      return z_ld_st_helper(cbuf, "STG ", STG_ZOPC, src_lo, dst_offset, print, os);
    }

    // else
    mnemo = dst12 ? "ST  " : "STY ";
    opc = dst12 ? ST_ZOPC : STY_ZOPC;

    return z_ld_st_helper(cbuf, mnemo, opc, src_lo, dst_offset, print, os);
  }

  // Check for integer load
  // Always load cOops zero-extended. That doesn't hurt int loads.
  if (dst_lo_rc == rc_int && src_lo_rc == rc_stack) {

    assert(!is64 || (dst_hi_rc==rc_int && src_hi_rc==rc_stack),
           "expected same type of move for high parts");

    mnemo = is64 ? "LG  " : "LLGF";
    opc = is64 ? LG_ZOPC : LLGF_ZOPC;

    return z_ld_st_helper(cbuf, mnemo, opc, dst_lo, src_offset, print, os);
  }

  // Check for float reg-reg copy.
  if (src_lo_rc == rc_float && dst_lo_rc == rc_float) {
    if (cbuf) {
      C2_MacroAssembler _masm(cbuf);
      FloatRegister Rsrc = as_FloatRegister(Matcher::_regEncode[src_lo]);
      FloatRegister Rdst = as_FloatRegister(Matcher::_regEncode[dst_lo]);
      __ z_ldr(Rdst, Rsrc);
      return 2;
    }
#if !defined(PRODUCT)
    // else
    if (print) {
      os->print("LDR      %s,%s\t # MachCopy spill code", Matcher::regName[dst_lo], Matcher::regName[src_lo]);
    }
#endif
    return 2;
  }

  // Check for float store.
  if (src_lo_rc == rc_float && dst_lo_rc == rc_stack) {
    assert(!is64 || (src_hi_rc==rc_float && dst_hi_rc==rc_stack),
           "expected same type of move for high parts");

    if (is64) {
      mnemo = dst12 ? "STD  " : "STDY ";
      opc = dst12 ? STD_ZOPC : STDY_ZOPC;
      return z_ld_st_helper(cbuf, mnemo, opc, src_lo, dst_offset, print, os);
    }
    // else

    mnemo = dst12 ? "STE  " : "STEY ";
    opc = dst12 ? STE_ZOPC : STEY_ZOPC;
    return z_ld_st_helper(cbuf, mnemo, opc, src_lo, dst_offset, print, os);
  }

  // Check for float load.
  if (dst_lo_rc == rc_float && src_lo_rc == rc_stack) {
    assert(!is64 || (dst_hi_rc==rc_float && src_hi_rc==rc_stack),
           "expected same type of move for high parts");

    if (is64) {
      mnemo = src12 ? "LD   " : "LDY  ";
      opc = src12 ? LD_ZOPC : LDY_ZOPC;
      return z_ld_st_helper(cbuf, mnemo, opc, dst_lo, src_offset, print, os);
    }
    // else

    mnemo = src12 ? "LE   " : "LEY  ";
    opc = src12 ? LE_ZOPC : LEY_ZOPC;
    return z_ld_st_helper(cbuf, mnemo, opc, dst_lo, src_offset, print, os);
  }

  // --------------------------------------------------------------------
  // Check for hi bits still needing moving. Only happens for misaligned
  // arguments to native calls.
  if (src_hi == dst_hi) {
    return 0;               // Self copy, no move.
  }

  assert(is64 && dst_hi_rc != rc_bad, "src_hi & dst_hi cannot be Bad");
  Unimplemented();  // Unsafe, do not remove!

  return 0; // never reached, but make the compiler shut up!
}

#if !defined(PRODUCT)
void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream *os) const {
  if (ra_ && ra_->node_regs_max_index() > 0) {
    implementation(NULL, ra_, false, os);
  } else {
    if (req() == 2 && in(1)) {
      os->print("N%d = N%d\n", _idx, in(1)->_idx);
    } else {
      const char *c = "(";
      os->print("N%d = ", _idx);
      for (uint i = 1; i < req(); ++i) {
        os->print("%sN%d", c, in(i)->_idx);
        c = ", ";
      }
      os->print(")");
    }
  }
}
#endif

void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  implementation(&cbuf, ra_, false, NULL);
}

uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const {
  return implementation(NULL, ra_, true, NULL);
}

//=============================================================================

#if !defined(PRODUCT)
void MachNopNode::format(PhaseRegAlloc *, outputStream *os) const {
  os->print("NOP     # pad for alignment (%d nops, %d bytes)", _count, _count*MacroAssembler::nop_size());
}
#endif

void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc * ra_) const {
  C2_MacroAssembler _masm(&cbuf);

  int rem_space = 0;
  if (!(ra_->C->output()->in_scratch_emit_size())) {
    rem_space = cbuf.insts()->remaining();
    if (rem_space <= _count*2 + 8) {
      tty->print("NopNode: _count = %3.3d, remaining space before = %d", _count, rem_space);
    }
  }

  for (int i = 0; i < _count; i++) {
    __ z_nop();
  }

  if (!(ra_->C->output()->in_scratch_emit_size())) {
    if (rem_space <= _count*2 + 8) {
      int rem_space2 = cbuf.insts()->remaining();
      tty->print_cr(", after = %d", rem_space2);
    }
  }
}

uint MachNopNode::size(PhaseRegAlloc *ra_) const {
   return 2 * _count;
}

#if !defined(PRODUCT)
void BoxLockNode::format(PhaseRegAlloc *ra_, outputStream *os) const {
  int offset = ra_->reg2offset(in_RegMask(0).find_first_elem());
  if (ra_ && ra_->node_regs_max_index() > 0) {
    int reg = ra_->get_reg_first(this);
    os->print("ADDHI  %s, SP, %d\t//box node", Matcher::regName[reg], offset);
  } else {
    os->print("ADDHI  N%d = SP + %d\t// box node", _idx, offset);
  }
}
#endif

// Take care of the size function, if you make changes here!
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);
  __ z_lay(as_Register(reg), offset, Z_SP);
}

uint BoxLockNode::size(PhaseRegAlloc *ra_) const {
  // BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_)
  return 6;
}

 %} // end source section

//----------SOURCE BLOCK-------------------------------------------------------
// This is a block of C++ code which provides values, functions, and
// definitions necessary in the rest of the architecture description

source_hpp %{

// Header information of the source block.
// Method declarations/definitions which are used outside
// the ad-scope can conveniently be defined here.
//
// To keep related declarations/definitions/uses close together,
// we switch between source %{ }% and source_hpp %{ }% freely as needed.

#include "oops/klass.inline.hpp"

//--------------------------------------------------------------
// Used for optimization in Compile::Shorten_branches
//--------------------------------------------------------------

class CallStubImpl {
 public:

  // call trampolines
  // Size of call trampoline stub. For add'l comments, see size_java_to_interp().
  static uint size_call_trampoline() {
    return 0; // no call trampolines on this platform
  }

  // call trampolines
  // Number of relocations needed by a call trampoline stub.
  static uint reloc_call_trampoline() {
    return 0; // No call trampolines on this platform.
  }
};

%} // end source_hpp section

source %{

#if !defined(PRODUCT)
void MachUEPNode::format(PhaseRegAlloc *ra_, outputStream *os) const {
  os->print_cr("---- MachUEPNode ----");
  os->print_cr("\tTA");
  os->print_cr("\tload_const Z_R1, SharedRuntime::get_ic_miss_stub()");
  os->print_cr("\tBR(Z_R1)");
  os->print_cr("\tTA  # pad with illtraps");
  os->print_cr("\t...");
  os->print_cr("\tTA");
  os->print_cr("\tLTGR    Z_R2, Z_R2");
  os->print_cr("\tBRU     ic_miss");
}
#endif

void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  C2_MacroAssembler _masm(&cbuf);
  const int ic_miss_offset = 2;

  // Inline_cache contains a klass.
  Register ic_klass = as_Register(Matcher::inline_cache_reg_encode());
  // ARG1 is the receiver oop.
  Register R2_receiver = Z_ARG1;
  int      klass_offset = oopDesc::klass_offset_in_bytes();
  AddressLiteral icmiss(SharedRuntime::get_ic_miss_stub());
  Register R1_ic_miss_stub_addr = Z_R1_scratch;

  // Null check of receiver.
  // This is the null check of the receiver that actually should be
  // done in the caller. It's here because in case of implicit null
  // checks we get it for free.
  assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()),
         "second word in oop should not require explicit null check.");
  if (!ImplicitNullChecks) {
    Label valid;
    if (VM_Version::has_CompareBranch()) {
      __ z_cgij(R2_receiver, 0, Assembler::bcondNotEqual, valid);
    } else {
      __ z_ltgr(R2_receiver, R2_receiver);
      __ z_bre(valid);
    }
    // The ic_miss_stub will handle the null pointer exception.
    __ load_const_optimized(R1_ic_miss_stub_addr, icmiss);
    __ z_br(R1_ic_miss_stub_addr);
    __ bind(valid);
  }

  // Check whether this method is the proper implementation for the class of
  // the receiver (ic miss check).
  {
    Label valid;
    // Compare cached class against klass from receiver.
    // This also does an implicit null check!
    __ compare_klass_ptr(ic_klass, klass_offset, R2_receiver, false);
    __ z_bre(valid);
    // The inline cache points to the wrong method. Call the
    // ic_miss_stub to find the proper method.
    __ load_const_optimized(R1_ic_miss_stub_addr, icmiss);
    __ z_br(R1_ic_miss_stub_addr);
    __ bind(valid);
  }
}

uint MachUEPNode::size(PhaseRegAlloc *ra_) const {
  // Determine size dynamically.
  return MachNode::size(ra_);
}

//=============================================================================

%} // interrupt source section

source_hpp %{ // Header information of the source block.

class HandlerImpl {
 public:

  static int emit_exception_handler(CodeBuffer &cbuf);
  static int emit_deopt_handler(CodeBuffer& cbuf);

  static uint size_exception_handler() {
    return NativeJump::max_instruction_size();
  }

  static uint size_deopt_handler() {
    return NativeCall::max_instruction_size();
  }
};

class Node::PD {
public:
  enum NodeFlags {
    _last_flag = Node::_last_flag
  };
};

%} // end source_hpp section

source %{

// This exception handler code snippet is placed after the method's
// code. It is the return point if an exception occurred. it jumps to
// the exception blob.
//
// If the method gets deoptimized, the method and this code snippet
// get patched.
//
// 1) Trampoline code gets patched into the end of this exception
//   handler. the trampoline code jumps to the deoptimization blob.
//
// 2) The return address in the method's code will get patched such
//   that it jumps to the trampoline.
//
// 3) The handler will get patched such that it does not jump to the
//   exception blob, but to an entry in the deoptimization blob being
//   aware of the exception.
int HandlerImpl::emit_exception_handler(CodeBuffer &cbuf) {
  Register temp_reg = Z_R1;
  C2_MacroAssembler _masm(&cbuf);

  address base = __ start_a_stub(size_exception_handler());
  if (base == NULL) {
    return 0;          // CodeBuffer::expand failed
  }

  int offset = __ offset();
  // Use unconditional pc-relative jump with 32-bit range here.
  __ load_const_optimized(temp_reg, (address)OptoRuntime::exception_blob()->content_begin());
  __ z_br(temp_reg);

  assert(__ offset() - offset <= (int) size_exception_handler(), "overflow");

  __ end_a_stub();

  return offset;
}

// Emit deopt handler code.
int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) {
  C2_MacroAssembler _masm(&cbuf);
  address        base = __ start_a_stub(size_deopt_handler());

  if (base == NULL) {
    return 0;  // CodeBuffer::expand failed
  }

  int offset = __ offset();

  // Size_deopt_handler() must be exact on zarch, so for simplicity
  // we do not use load_const_opt here.
  __ load_const(Z_R1, SharedRuntime::deopt_blob()->unpack());
  __ call(Z_R1);
  assert(__ offset() - offset == (int) size_deopt_handler(), "must be fixed size");

  __ end_a_stub();
  return offset;
}

//=============================================================================


// Given a register encoding, produce an Integer Register object.
static Register reg_to_register_object(int register_encoding) {
  assert(Z_R12->encoding() == Z_R12_enc, "wrong coding");
  return as_Register(register_encoding);
}

const bool Matcher::match_rule_supported(int opcode) {
  if (!has_match_rule(opcode)) {
    return false; // no match rule present
  }

  switch (opcode) {
    case Op_ReverseBytesI:
    case Op_ReverseBytesL:
      return UseByteReverseInstruction;
    case Op_PopCountI:
    case Op_PopCountL:
      // PopCount supported by H/W from z/Architecture G5 (z196) on.
      return (UsePopCountInstruction && VM_Version::has_PopCount());
  }

  return true; // Per default match rules are supported.
}

const bool Matcher::match_rule_supported_superword(int opcode, int vlen, BasicType bt) {
  return match_rule_supported_vector(opcode, vlen, 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;
  }
  return true; // Per default match rules are supported.
}

const bool Matcher::match_rule_supported_vector_masked(int opcode, int vlen, BasicType bt) {
  return false;
}

const bool Matcher::vector_needs_partial_operations(Node* node, const TypeVect* vt) {
  return false;
}

const RegMask* Matcher::predicate_reg_mask(void) {
  return NULL;
}

const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) {
  return NULL;
}

// 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);
}

//----------SUPERWORD HELPERS----------------------------------------

// Vector width in bytes.
const int Matcher::vector_width_in_bytes(BasicType bt) {
  assert(MaxVectorSize == 8, "");
  return 8;
}

// Vector ideal reg.
const uint Matcher::vector_ideal_reg(int size) {
  assert(MaxVectorSize == 8 && size == 8, "");
  return Op_RegL;
}

// Limits on vector size (number of elements) loaded into vector.
const int Matcher::max_vector_size(const BasicType bt) {
  assert(is_java_primitive(bt), "only primitive type vectors");
  return vector_width_in_bytes(bt)/type2aelembytes(bt);
}

const int Matcher::min_vector_size(const BasicType bt) {
  return max_vector_size(bt); // Same as max.
}

const int Matcher::scalable_vector_reg_size(const BasicType bt) {
  return -1;
}

// RETURNS: whether this branch offset is short enough that a short
// branch can be used.
//
// If the platform does not provide any short branch variants, then
// this method should return `false' for offset 0.
//
// `Compile::Fill_buffer' will decide on basis of this information
// whether to do the pass `Compile::Shorten_branches' at all.
//
// And `Compile::Shorten_branches' will decide on basis of this
// information whether to replace particular branch sites by short
// ones.
bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) {
  // On zarch short branches use a 16 bit signed immediate that
  // is the pc-relative offset in halfword (= 2 bytes) units.
  return Assembler::is_within_range_of_RelAddr16((address)((long)offset), (address)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_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;
}

// Constants for c2c and c calling conventions.

const MachRegisterNumbers z_iarg_reg[5] = {
  Z_R2_num, Z_R3_num, Z_R4_num, Z_R5_num, Z_R6_num
};

const MachRegisterNumbers z_farg_reg[4] = {
  Z_F0_num, Z_F2_num, Z_F4_num, Z_F6_num
};

const int z_num_iarg_registers = sizeof(z_iarg_reg) / sizeof(z_iarg_reg[0]);

const int z_num_farg_registers = sizeof(z_farg_reg) / sizeof(z_farg_reg[0]);

// 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) {
  // We return true for all registers contained in z_iarg_reg[] and
  // z_farg_reg[] and their virtual halves.
  // We must include the virtual halves in order to get STDs and LDs
  // instead of STWs and LWs in the trampoline stubs.

  if (reg == Z_R2_num || reg == Z_R2_H_num ||
      reg == Z_R3_num || reg == Z_R3_H_num ||
      reg == Z_R4_num || reg == Z_R4_H_num ||
      reg == Z_R5_num || reg == Z_R5_H_num ||
      reg == Z_R6_num || reg == Z_R6_H_num) {
    return true;
  }

  if (reg == Z_F0_num || reg == Z_F0_H_num ||
      reg == Z_F2_num || reg == Z_F2_H_num ||
      reg == Z_F4_num || reg == Z_F4_H_num ||
      reg == Z_F6_num || reg == Z_F6_H_num) {
    return true;
  }

  return false;
}

bool Matcher::is_spillable_arg(int reg) {
  return can_be_java_arg(reg);
}

uint Matcher::int_pressure_limit()
{
  // Medium size register set, 6 special purpose regs, 3 SOE regs.
  return (INTPRESSURE == -1) ? 10 : INTPRESSURE;
}

uint Matcher::float_pressure_limit()
{
  return (FLOATPRESSURE == -1) ? 15 : FLOATPRESSURE;
}

bool Matcher::use_asm_for_ldiv_by_con(jlong divisor) {
  return false;
}

// Register for DIVI projection of divmodI
RegMask Matcher::divI_proj_mask() {
  return _Z_RARG4_INT_REG_mask;
}

// Register for MODI projection of divmodI
RegMask Matcher::modI_proj_mask() {
  return _Z_RARG3_INT_REG_mask;
}

// Register for DIVL projection of divmodL
RegMask Matcher::divL_proj_mask() {
  return _Z_RARG4_LONG_REG_mask;
}

// Register for MODL projection of divmodL
RegMask Matcher::modL_proj_mask() {
  return _Z_RARG3_LONG_REG_mask;
}

// Copied from sparc.
const RegMask Matcher::method_handle_invoke_SP_save_mask() {
  return RegMask();
}

// Should the matcher clone input 'm' of node 'n'?
bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) {
  return false;
}

// Should the Matcher clone shifts on addressing modes, expecting them
// to be subsumed into complex addressing expressions or compute them
// into registers?
bool Matcher::pd_clone_address_expressions(AddPNode* m, Matcher::MStack& mstack, VectorSet& address_visited) {
  return clone_base_plus_offset_address(m, mstack, address_visited);
}

%} // source

//----------ENCODING BLOCK-----------------------------------------------------
// This block specifies the encoding classes used by the compiler to output
// byte streams. Encoding classes are parameterized macros used by
// Machine Instruction Nodes in order to generate the bit encoding of the
// instruction. Operands specify their base encoding interface with the
// interface keyword. There are currently supported four interfaces,
// REG_INTER, CONST_INTER, MEMORY_INTER, & COND_INTER. REG_INTER causes an
// operand to generate a function which returns its register number when
// queried. CONST_INTER causes an operand to generate a function which
// returns the value of the constant when queried. MEMORY_INTER causes an
// operand to generate four functions which return the Base Register, the
// Index Register, the Scale Value, and the Offset Value of the operand when
// queried. COND_INTER causes an operand to generate six functions which
// return the encoding code (ie - encoding bits for the instruction)
// associated with each basic boolean condition for a conditional instruction.
//
// Instructions specify two basic values for encoding. Again, a function
// is available to check if the constant displacement is an oop. They use the
// ins_encode keyword to specify their encoding classes (which must be
// a sequence of enc_class names, and their parameters, specified in
// the encoding block), and they use the
// opcode keyword to specify, in order, their primary, secondary, and
// tertiary opcode. Only the opcode sections which a particular instruction
// needs for encoding need to be specified.
encode %{
  enc_class enc_unimplemented %{
    C2_MacroAssembler _masm(&cbuf);
    __ unimplemented("Unimplemented mach node encoding in AD file.", 13);
  %}

  enc_class enc_untested %{
#ifdef ASSERT
    C2_MacroAssembler _masm(&cbuf);
    __ untested("Untested mach node encoding in AD file.");
#endif
  %}

  enc_class z_rrform(iRegI dst, iRegI src) %{
    assert((($primary >> 14) & 0x03) == 0, "Instruction format error");
    assert( ($primary >> 16)         == 0, "Instruction format error");
    z_emit16(cbuf, $primary |
             Assembler::reg($dst$$reg,8,16) |
             Assembler::reg($src$$reg,12,16));
  %}

  enc_class z_rreform(iRegI dst1, iRegI src2) %{
    assert((($primary >> 30) & 0x03) == 2, "Instruction format error");
    z_emit32(cbuf, $primary |
             Assembler::reg($dst1$$reg,24,32) |
             Assembler::reg($src2$$reg,28,32));
  %}

  enc_class z_rrfform(iRegI dst1, iRegI src2, iRegI src3) %{
    assert((($primary >> 30) & 0x03) == 2, "Instruction format error");
    z_emit32(cbuf, $primary |
             Assembler::reg($dst1$$reg,24,32) |
             Assembler::reg($src2$$reg,28,32) |
             Assembler::reg($src3$$reg,16,32));
  %}

  enc_class z_riform_signed(iRegI dst, immI16 src) %{
    assert((($primary>>30) & 0x03) == 2, "Instruction format error");
    z_emit32(cbuf, $primary |
             Assembler::reg($dst$$reg,8,32) |
             Assembler::simm16($src$$constant,16,32));
  %}

  enc_class z_riform_unsigned(iRegI dst, uimmI16 src) %{
    assert((($primary>>30) & 0x03) == 2, "Instruction format error");
    z_emit32(cbuf, $primary |
             Assembler::reg($dst$$reg,8,32) |
             Assembler::uimm16($src$$constant,16,32));
  %}

  enc_class z_rieform_d(iRegI dst1, iRegI src3, immI src2) %{
    assert((($primary>>46) & 0x03) == 3, "Instruction format error");
    z_emit48(cbuf, $primary |
             Assembler::reg($dst1$$reg,8,48) |
             Assembler::reg($src3$$reg,12,48) |
             Assembler::simm16($src2$$constant,16,48));
  %}

  enc_class z_rilform_signed(iRegI dst, immL32 src) %{
    assert((($primary>>46) & 0x03) == 3, "Instruction format error");
    z_emit48(cbuf, $primary |
             Assembler::reg($dst$$reg,8,48) |
             Assembler::simm32($src$$constant,16,48));
  %}

  enc_class z_rilform_unsigned(iRegI dst, uimmL32 src) %{
    assert((($primary>>46) & 0x03) == 3, "Instruction format error");
    z_emit48(cbuf, $primary |
             Assembler::reg($dst$$reg,8,48) |
             Assembler::uimm32($src$$constant,16,48));
  %}

  enc_class z_rsyform_const(iRegI dst, iRegI src1, immI src2) %{
    z_emit48(cbuf, $primary |
             Assembler::reg($dst$$reg,8,48) |
             Assembler::reg($src1$$reg,12,48) |
             Assembler::simm20($src2$$constant));
  %}

  enc_class z_rsyform_reg_reg(iRegI dst, iRegI src, iRegI shft) %{
    z_emit48(cbuf, $primary |
             Assembler::reg($dst$$reg,8,48) |
             Assembler::reg($src$$reg,12,48) |
             Assembler::reg($shft$$reg,16,48) |
             Assembler::simm20(0));
  %}

  enc_class z_rxform_imm_reg_reg(iRegL dst, immL con, iRegL src1, iRegL src2) %{
    assert((($primary>>30) & 0x03) == 1, "Instruction format error");
    z_emit32(cbuf, $primary |
             Assembler::reg($dst$$reg,8,32) |
             Assembler::reg($src1$$reg,12,32) |
             Assembler::reg($src2$$reg,16,32) |
             Assembler::uimm12($con$$constant,20,32));
  %}

  enc_class z_rxform_imm_reg(iRegL dst, immL con, iRegL src) %{
    assert((($primary>>30) & 0x03) == 1, "Instruction format error");
    z_emit32(cbuf, $primary |
             Assembler::reg($dst$$reg,8,32) |
             Assembler::reg($src$$reg,16,32) |
             Assembler::uimm12($con$$constant,20,32));
  %}

  enc_class z_rxyform_imm_reg_reg(iRegL dst, immL con, iRegL src1, iRegL src2) %{
    z_emit48(cbuf, $primary |
             Assembler::reg($dst$$reg,8,48) |
             Assembler::reg($src1$$reg,12,48) |
             Assembler::reg($src2$$reg,16,48) |
             Assembler::simm20($con$$constant));
  %}

  enc_class z_rxyform_imm_reg(iRegL dst, immL con, iRegL src) %{
    z_emit48(cbuf, $primary |
             Assembler::reg($dst$$reg,8,48) |
             Assembler::reg($src$$reg,16,48) |
             Assembler::simm20($con$$constant));
  %}

  // Direct memory arithmetic.
  enc_class z_siyform(memoryRSY mem, immI8 src) %{
    int      disp = $mem$$disp;
    Register base = reg_to_register_object($mem$$base);
    int      con  = $src$$constant;

    assert(VM_Version::has_MemWithImmALUOps(), "unsupported CPU");
    z_emit_inst(cbuf, $primary |
                Assembler::regz(base,16,48) |
                Assembler::simm20(disp) |
                Assembler::simm8(con,8,48));
  %}

  enc_class z_silform(memoryRS mem, immI16 src) %{
    z_emit_inst(cbuf, $primary |
                Assembler::regz(reg_to_register_object($mem$$base),16,48) |
                Assembler::uimm12($mem$$disp,20,48) |
                Assembler::simm16($src$$constant,32,48));
  %}

  // Encoder for FP ALU reg/mem instructions (support only short displacements).
  enc_class z_form_rt_memFP(RegF dst, memoryRX mem) %{
    Register Ridx = $mem$$index$$Register;
    if (Ridx == noreg) { Ridx = Z_R0; } // Index is 0.
    if ($primary > (1L << 32)) {
      z_emit_inst(cbuf, $primary |
                  Assembler::reg($dst$$reg, 8, 48) |
                  Assembler::uimm12($mem$$disp, 20, 48) |
                  Assembler::reg(Ridx, 12, 48) |
                  Assembler::regz(reg_to_register_object($mem$$base), 16, 48));
    } else {
      z_emit_inst(cbuf, $primary |
                  Assembler::reg($dst$$reg, 8, 32) |
                  Assembler::uimm12($mem$$disp, 20, 32) |
                  Assembler::reg(Ridx, 12, 32) |
                  Assembler::regz(reg_to_register_object($mem$$base), 16, 32));
    }
  %}

  enc_class z_form_rt_mem(iRegI dst, memory mem) %{
    Register Ridx = $mem$$index$$Register;
    if (Ridx == noreg) { Ridx = Z_R0; } // Index is 0.
    if ($primary > (1L<<32)) {
      z_emit_inst(cbuf, $primary |
                  Assembler::reg($dst$$reg, 8, 48) |
                  Assembler::simm20($mem$$disp) |
                  Assembler::reg(Ridx, 12, 48) |
                  Assembler::regz(reg_to_register_object($mem$$base), 16, 48));
    } else {
      z_emit_inst(cbuf, $primary |
                  Assembler::reg($dst$$reg, 8, 32) |
                  Assembler::uimm12($mem$$disp, 20, 32) |
                  Assembler::reg(Ridx, 12, 32) |
                  Assembler::regz(reg_to_register_object($mem$$base), 16, 32));
    }
  %}

  enc_class z_form_rt_mem_opt(iRegI dst, memory mem) %{
    int isize = $secondary > 1L << 32 ? 48 : 32;
    Register Ridx = $mem$$index$$Register;
    if (Ridx == noreg) { Ridx = Z_R0; } // Index is 0.

    if (Displacement::is_shortDisp((long)$mem$$disp)) {
      z_emit_inst(cbuf, $secondary |
                  Assembler::reg($dst$$reg, 8, isize) |
                  Assembler::uimm12($mem$$disp, 20, isize) |
                  Assembler::reg(Ridx, 12, isize) |
                  Assembler::regz(reg_to_register_object($mem$$base), 16, isize));
    } else if (Displacement::is_validDisp((long)$mem$$disp)) {
      z_emit_inst(cbuf, $primary |
                  Assembler::reg($dst$$reg, 8, 48) |
                  Assembler::simm20($mem$$disp) |
                  Assembler::reg(Ridx, 12, 48) |
                  Assembler::regz(reg_to_register_object($mem$$base), 16, 48));
    } else {
        C2_MacroAssembler _masm(&cbuf);
        __ load_const_optimized(Z_R1_scratch, $mem$$disp);
        if (Ridx != Z_R0) { __ z_agr(Z_R1_scratch, Ridx); }
        z_emit_inst(cbuf, $secondary |
                    Assembler::reg($dst$$reg, 8, isize) |
                    Assembler::uimm12(0, 20, isize) |
                    Assembler::reg(Z_R1_scratch, 12, isize) |
                    Assembler::regz(reg_to_register_object($mem$$base), 16, isize));
    }
  %}

  enc_class z_enc_brul(Label lbl) %{
    C2_MacroAssembler _masm(&cbuf);
    Label* p = $lbl$$label;

    // 'p' is `NULL' when this encoding class is used only to
    // determine the size of the encoded instruction.
    // Use a bound dummy label in that case.
    Label d;
    __ bind(d);
    Label& l = (NULL == p) ? d : *(p);
    __ z_brul(l);
  %}

  enc_class z_enc_bru(Label lbl) %{
    C2_MacroAssembler _masm(&cbuf);
    Label* p = $lbl$$label;

    // 'p' is `NULL' when this encoding class is used only to
    // determine the size of the encoded instruction.
    // Use a bound dummy label in that case.
    Label d;
    __ bind(d);
    Label& l = (NULL == p) ? d : *(p);
    __ z_bru(l);
  %}

  enc_class z_enc_branch_con_far(cmpOp cmp, Label lbl) %{
    C2_MacroAssembler _masm(&cbuf);
    Label* p = $lbl$$label;

    // 'p' is `NULL' when this encoding class is used only to
    // determine the size of the encoded instruction.
    // Use a bound dummy label in that case.
    Label d;
    __ bind(d);
    Label& l = (NULL == p) ? d : *(p);
    __ z_brcl((Assembler::branch_condition)$cmp$$cmpcode, l);
  %}

  enc_class z_enc_branch_con_short(cmpOp cmp, Label lbl) %{
    C2_MacroAssembler _masm(&cbuf);
    Label* p = $lbl$$label;

    // 'p' is `NULL' when this encoding class is used only to
    // determine the size of the encoded instruction.
    // Use a bound dummy label in that case.
    Label d;
    __ bind(d);
    Label& l = (NULL == p) ? d : *(p);
    __ z_brc((Assembler::branch_condition)$cmp$$cmpcode, l);
  %}

  enc_class z_enc_cmpb_regreg(iRegI src1, iRegI src2, Label lbl, cmpOpT cmp) %{
    C2_MacroAssembler _masm(&cbuf);
    Label* p = $lbl$$label;

    // 'p' is `NULL' when this encoding class is used only to
    // determine the size of the encoded instruction.
    // Use a bound dummy label in that case.
    Label d;
    __ bind(d);
    Label& l = (NULL == p) ? d : *(p);
    Assembler::branch_condition cc = (Assembler::branch_condition)$cmp$$cmpcode;
    unsigned long instr = $primary;
    if (instr == CRJ_ZOPC) {
      __ z_crj($src1$$Register, $src2$$Register, cc, l);
    } else if (instr == CLRJ_ZOPC) {
      __ z_clrj($src1$$Register, $src2$$Register, cc, l);
    } else if (instr == CGRJ_ZOPC) {
      __ z_cgrj($src1$$Register, $src2$$Register, cc, l);
    } else {
      guarantee(instr == CLGRJ_ZOPC, "opcode not implemented");
      __ z_clgrj($src1$$Register, $src2$$Register, cc, l);
    }
  %}

  enc_class z_enc_cmpb_regregFar(iRegI src1, iRegI src2, Label lbl, cmpOpT cmp) %{
    C2_MacroAssembler _masm(&cbuf);
    Label* p = $lbl$$label;

    // 'p' is `NULL' when this encoding class is used only to
    // determine the size of the encoded instruction.
    // Use a bound dummy label in that case.
    Label d;
    __ bind(d);
    Label& l = (NULL == p) ? d : *(p);

    unsigned long instr = $primary;
    if (instr == CR_ZOPC) {
      __ z_cr($src1$$Register, $src2$$Register);
    } else if (instr == CLR_ZOPC) {
      __ z_clr($src1$$Register, $src2$$Register);
    } else if (instr == CGR_ZOPC) {
      __ z_cgr($src1$$Register, $src2$$Register);
    } else {
      guarantee(instr == CLGR_ZOPC, "opcode not implemented");
      __ z_clgr($src1$$Register, $src2$$Register);
    }

    __ z_brcl((Assembler::branch_condition)$cmp$$cmpcode, l);
  %}

  enc_class z_enc_cmpb_regimm(iRegI src1, immI8 src2, Label lbl, cmpOpT cmp) %{
    C2_MacroAssembler _masm(&cbuf);
    Label* p = $lbl$$label;

    // 'p' is `NULL' when this encoding class is used only to
    // determine the size of the encoded instruction.
    // Use a bound dummy label in that case.
    Label d;
    __ bind(d);
    Label& l = (NULL == p) ? d : *(p);

    Assembler::branch_condition cc = (Assembler::branch_condition)$cmp$$cmpcode;
    unsigned long instr = $primary;
    if (instr == CIJ_ZOPC) {
      __ z_cij($src1$$Register, $src2$$constant, cc, l);
    } else if (instr == CLIJ_ZOPC) {
      __ z_clij($src1$$Register, $src2$$constant, cc, l);
    } else if (instr == CGIJ_ZOPC) {
      __ z_cgij($src1$$Register, $src2$$constant, cc, l);
    } else {
      guarantee(instr == CLGIJ_ZOPC, "opcode not implemented");
      __ z_clgij($src1$$Register, $src2$$constant, cc, l);
    }
  %}

  enc_class z_enc_cmpb_regimmFar(iRegI src1, immI8 src2, Label lbl, cmpOpT cmp) %{
    C2_MacroAssembler _masm(&cbuf);
    Label* p = $lbl$$label;

    // 'p' is `NULL' when this encoding class is used only to
    // determine the size of the encoded instruction.
    // Use a bound dummy label in that case.
    Label d;
    __ bind(d);
    Label& l = (NULL == p) ? d : *(p);

    unsigned long instr = $primary;
    if (instr == CHI_ZOPC) {
      __ z_chi($src1$$Register, $src2$$constant);
    } else if (instr == CLFI_ZOPC) {
      __ z_clfi($src1$$Register, $src2$$constant);
    } else if (instr == CGHI_ZOPC) {
      __ z_cghi($src1$$Register, $src2$$constant);
    } else {
      guarantee(instr == CLGFI_ZOPC, "opcode not implemented");
      __ z_clgfi($src1$$Register, $src2$$constant);
    }

    __ z_brcl((Assembler::branch_condition)$cmp$$cmpcode, l);
  %}

  // Call from Java to runtime.
  enc_class z_enc_java_to_runtime_call(method meth) %{
    C2_MacroAssembler _masm(&cbuf);

    // Save return pc before call to the place where we need it, since
    // callee doesn't.
    unsigned int start_off = __ offset();
    // Compute size of "larl + stg + call_c_opt".
    const int size_of_code = 6 + 6 + MacroAssembler::call_far_patchable_size();
    __ get_PC(Z_R14, size_of_code);
    __ save_return_pc();
    assert(__ offset() - start_off == 12, "bad prelude len: %d", __ offset() - start_off);

    assert((__ offset() & 2) == 0, "misaligned z_enc_java_to_runtime_call");
    address call_addr = __ call_c_opt((address)$meth$$method);
    if (call_addr == NULL) {
      Compile::current()->env()->record_out_of_memory_failure();
      return;
    }

#ifdef ASSERT
    // Plausibility check for size_of_code assumptions.
    unsigned int actual_ret_off = __ offset();
    assert(start_off + size_of_code == actual_ret_off, "wrong return_pc");
#endif
  %}

  enc_class z_enc_java_static_call(method meth) %{
    // Call to fixup routine. Fixup routine uses ScopeDesc info to determine
    // whom we intended to call.
    C2_MacroAssembler _masm(&cbuf);
    int ret_offset = 0;

    if (!_method) {
      ret_offset = emit_call_reloc(_masm, $meth$$method,
                                   relocInfo::runtime_call_w_cp_type, ra_);
    } else {
      int method_index = resolved_method_index(cbuf);
      if (_optimized_virtual) {
        ret_offset = emit_call_reloc(_masm, $meth$$method,
                                     opt_virtual_call_Relocation::spec(method_index));
      } else {
        ret_offset = emit_call_reloc(_masm, $meth$$method,
                                     static_call_Relocation::spec(method_index));
      }
    }
    assert(__ inst_mark() != NULL, "emit_call_reloc must set_inst_mark()");

    if (_method) { // Emit stub for static call.
      address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
      if (stub == NULL) {
        ciEnv::current()->record_failure("CodeCache is full");
        return;
      }
    }
  %}

  // Java dynamic call
  enc_class z_enc_java_dynamic_call(method meth) %{
    C2_MacroAssembler _masm(&cbuf);
    unsigned int start_off = __ offset();

    int vtable_index = this->_vtable_index;
    if (vtable_index == -4) {
      Register ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode());
      address virtual_call_oop_addr = NULL;

      AddressLiteral empty_ic((address) Universe::non_oop_word());
      virtual_call_oop_addr = __ pc();
      bool success = __ load_const_from_toc(ic_reg, empty_ic);
      if (!success) {
        Compile::current()->env()->record_out_of_memory_failure();
        return;
      }

      // Call to fixup routine. Fixup routine uses ScopeDesc info
      // to determine who we intended to call.
      int method_index = resolved_method_index(cbuf);
      __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr, method_index));
      unsigned int ret_off = __ offset();
      assert(__ offset() - start_off == 6, "bad prelude len: %d", __ offset() - start_off);
      ret_off += emit_call_reloc(_masm, $meth$$method, relocInfo::none, ra_);
      assert(_method, "lazy_constant may be wrong when _method==null");
    } else {
      assert(!UseInlineCaches, "expect vtable calls only if not using ICs");
      // Go through the vtable. Get receiver klass. Receiver already
      // checked for non-null. If we'll go thru a C2I adapter, the
      // interpreter expects method in Z_method.
      // Use Z_method to temporarily hold the klass oop.
      // Z_R1_scratch is destroyed.
      __ load_klass(Z_method, Z_R2);

      int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index * vtableEntry::size_in_bytes();
      int v_off        = entry_offset + vtableEntry::method_offset_in_bytes();

      if (Displacement::is_validDisp(v_off) ) {
        // Can use load instruction with large offset.
        __ z_lg(Z_method, Address(Z_method /*class oop*/, v_off /*method offset*/));
      } else {
        // Worse case, must load offset into register.
        __ load_const(Z_R1_scratch, v_off);
        __ z_lg(Z_method, Address(Z_method /*class oop*/, Z_R1_scratch /*method offset*/));
      }
      // NOTE: for vtable dispatches, the vtable entry will never be
      // null. However it may very well end up in handle_wrong_method
      // if the method is abstract for the particular class.
      __ z_lg(Z_R1_scratch, Address(Z_method, Method::from_compiled_offset()));
      // Call target. Either compiled code or C2I adapter.
      __ z_basr(Z_R14, Z_R1_scratch);
      unsigned int ret_off = __ offset();
    }
  %}

  enc_class z_enc_cmov_reg(cmpOp cmp, iRegI dst, iRegI src) %{
    C2_MacroAssembler _masm(&cbuf);
    Register Rdst = reg_to_register_object($dst$$reg);
    Register Rsrc = reg_to_register_object($src$$reg);

    // Don't emit code if operands are identical (same register).
    if (Rsrc != Rdst) {
      Assembler::branch_condition cc = (Assembler::branch_condition)$cmp$$cmpcode;

      if (VM_Version::has_LoadStoreConditional()) {
        __ z_locgr(Rdst, Rsrc, cc);
      } else {
        // Branch if not (cmp cr).
        Label done;
        __ z_brc(Assembler::inverse_condition(cc), done);
        __ z_lgr(Rdst, Rsrc); // Used for int and long+ptr.
        __ bind(done);
      }
    }
  %}

  enc_class z_enc_cmov_imm(cmpOp cmp, iRegI dst, immI16 src) %{
    C2_MacroAssembler _masm(&cbuf);
    Register Rdst = reg_to_register_object($dst$$reg);
    int      Csrc = $src$$constant;
    Assembler::branch_condition cc = (Assembler::branch_condition)$cmp$$cmpcode;
    Label done;
    // Branch if not (cmp cr).
    __ z_brc(Assembler::inverse_condition(cc), done);
    if (Csrc == 0) {
      // Don't set CC.
      __ clear_reg(Rdst, true, false);  // Use for int, long & ptr.
    } else {
      __ z_lghi(Rdst, Csrc); // Use for int, long & ptr.
    }
    __ bind(done);
  %}

  enc_class z_enc_cctobool(iRegI res) %{
    C2_MacroAssembler _masm(&cbuf);
    Register Rres = reg_to_register_object($res$$reg);

    if (VM_Version::has_LoadStoreConditional()) {
      __ load_const_optimized(Z_R0_scratch, 0L); // false (failed)
      __ load_const_optimized(Rres, 1L);         // true  (succeed)
      __ z_locgr(Rres, Z_R0_scratch, Assembler::bcondNotEqual);
    } else {
      Label done;
      __ load_const_optimized(Rres, 0L); // false (failed)
      __ z_brne(done);                   // Assume true to be the common case.
      __ load_const_optimized(Rres, 1L); // true  (succeed)
      __ bind(done);
    }
  %}

  enc_class z_enc_casI(iRegI compare_value, iRegI exchange_value, iRegP addr_ptr) %{
    C2_MacroAssembler _masm(&cbuf);
    Register Rcomp = reg_to_register_object($compare_value$$reg);
    Register Rnew  = reg_to_register_object($exchange_value$$reg);
    Register Raddr = reg_to_register_object($addr_ptr$$reg);

    __ z_cs(Rcomp, Rnew, 0, Raddr);
  %}

  enc_class z_enc_casL(iRegL compare_value, iRegL exchange_value, iRegP addr_ptr) %{
    C2_MacroAssembler _masm(&cbuf);
    Register Rcomp = reg_to_register_object($compare_value$$reg);
    Register Rnew  = reg_to_register_object($exchange_value$$reg);
    Register Raddr = reg_to_register_object($addr_ptr$$reg);

    __ z_csg(Rcomp, Rnew, 0, Raddr);
  %}

  enc_class z_enc_SwapI(memoryRSY mem, iRegI dst, iRegI tmp) %{
    C2_MacroAssembler _masm(&cbuf);
    Register Rdst = reg_to_register_object($dst$$reg);
    Register Rtmp = reg_to_register_object($tmp$$reg);
    guarantee(Rdst != Rtmp, "Fix match rule to use TEMP_DEF");
    Label    retry;

    // Iterate until swap succeeds.
    __ z_llgf(Rtmp, $mem$$Address);  // current contents
    __ bind(retry);
      // Calculate incremented value.
      __ z_csy(Rtmp, Rdst, $mem$$Address); // Try to store new value.
      __ z_brne(retry);                    // Yikes, concurrent update, need to retry.
    __ z_lgr(Rdst, Rtmp);                  // Exchanged value from memory is return value.
  %}

  enc_class z_enc_SwapL(memoryRSY mem, iRegL dst, iRegL tmp) %{
    C2_MacroAssembler _masm(&cbuf);
    Register Rdst = reg_to_register_object($dst$$reg);
    Register Rtmp = reg_to_register_object($tmp$$reg);
    guarantee(Rdst != Rtmp, "Fix match rule to use TEMP_DEF");
    Label    retry;

    // Iterate until swap succeeds.
    __ z_lg(Rtmp, $mem$$Address);  // current contents
    __ bind(retry);
      // Calculate incremented value.
      __ z_csg(Rtmp, Rdst, $mem$$Address); // Try to store new value.
      __ z_brne(retry);                    // Yikes, concurrent update, need to retry.
    __ z_lgr(Rdst, Rtmp);                  // Exchanged value from memory is return value.
  %}

%} // encode

source %{

  // Check whether outs are all Stores. If so, we can omit clearing the upper
  // 32 bits after encoding.
  static bool all_outs_are_Stores(const Node *n) {
    for (DUIterator_Fast imax, k = n->fast_outs(imax); k < imax; k++) {
      Node *out = n->fast_out(k);
      if (!out->is_Mach() || out->as_Mach()->ideal_Opcode() != Op_StoreN) {
        // Most other outs are SpillCopy, but there are various other.
        // jvm98 has arond 9% Encodes where we return false.
        return false;
      }
    }
    return true;
  }

%} // source


//----------FRAME--------------------------------------------------------------
// Definition of frame structure and management information.

frame %{
  // These two registers define part of the calling convention between
  // compiled code and the interpreter.

  // Inline Cache Register
  inline_cache_reg(Z_R9); // Z_inline_cache

  // Argument pointer for I2C adapters
  //
  // Tos is loaded in run_compiled_code to Z_ARG5=Z_R6.
  // interpreter_arg_ptr_reg(Z_R6);

  // Optional: name the operand used by cisc-spilling to access
  // [stack_pointer + offset].
  cisc_spilling_operand_name(indOffset12);

  // Number of stack slots consumed by a Monitor enter.
  sync_stack_slots(frame::jit_monitor_size_in_4_byte_units);

  // Compiled code's Frame Pointer
  //
  // z/Architecture stack pointer
  frame_pointer(Z_R15); // Z_SP

  // Interpreter stores its frame pointer in a register which is
  // stored to the stack by I2CAdaptors. I2CAdaptors convert from
  // interpreted java to compiled java.
  //
  // Z_state holds pointer to caller's cInterpreter.
  interpreter_frame_pointer(Z_R7); // Z_state

  // Use alignment_in_bytes instead of log_2_of_alignment_in_bits.
  stack_alignment(frame::alignment_in_bytes);

  // A `slot' is assumed 4 bytes here!
  // out_preserve_stack_slots(frame::jit_out_preserve_size_in_4_byte_units);

  // 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::z_abi_160_size - frame::z_jit_out_preserve_size) / VMRegImpl::stack_slot_size));

  // 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.
  return_addr(REG Z_R14);

  // Location of native (C/C++) and interpreter return values. This
  // is specified to be the same as Java. In the 32-bit VM, long
  // values are actually returned from native calls in O0:O1 and
  // returned to the interpreter in I0:I1. The copying to and from
  // the register pairs is done by the appropriate call and epilog
  // opcodes. This simplifies the register allocator.
  //
  // Use register pair for c return value.
  c_return_value %{
    assert(ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values");
    static int typeToRegLo[Op_RegL+1] = { 0, 0, Z_R2_num, Z_R2_num, Z_R2_num, Z_F0_num, Z_F0_num, Z_R2_num };
    static int typeToRegHi[Op_RegL+1] = { 0, 0, OptoReg::Bad, OptoReg::Bad, Z_R2_H_num, OptoReg::Bad, Z_F0_H_num, Z_R2_H_num };
    return OptoRegPair(typeToRegHi[ideal_reg], typeToRegLo[ideal_reg]);
  %}

  // Use register pair for return value.
  // Location of compiled Java return values. Same as C
  return_value %{
    assert(ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values");
    static int typeToRegLo[Op_RegL+1] = { 0, 0, Z_R2_num, Z_R2_num, Z_R2_num, Z_F0_num, Z_F0_num, Z_R2_num };
    static int typeToRegHi[Op_RegL+1] = { 0, 0, OptoReg::Bad, OptoReg::Bad, Z_R2_H_num, OptoReg::Bad, Z_F0_H_num, Z_R2_H_num };
    return OptoRegPair(typeToRegHi[ideal_reg], typeToRegLo[ideal_reg]);
  %}
%}


//----------ATTRIBUTES---------------------------------------------------------

//----------Operand Attributes-------------------------------------------------
op_attrib op_cost(1);          // Required cost attribute

//----------Instruction Attributes---------------------------------------------

// Cost attribute. required.
ins_attrib ins_cost(DEFAULT_COST);

// Is this instruction a non-matching short branch variant of some
// long branch? Not required.
ins_attrib ins_short_branch(0);

// Indicates this is a trap based check node and final control-flow fixup
// must generate a proper fall through.
ins_attrib ins_is_TrapBasedCheckNode(true);

// Attribute of instruction to tell how many constants the instruction will generate.
// (optional attribute). Default: 0.
ins_attrib ins_num_consts(0);

// 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.
//
// WARNING: Don't use size(FIXED_SIZE) or size(VARIABLE_SIZE) in
// instructions which depend on the proper alignment, because the
// desired alignment isn't guaranteed for the call to "emit()" during
// the size computation.
ins_attrib ins_alignment(1);

// Enforce/prohibit rematerializations.
// - If an instruction is attributed with 'ins_cannot_rematerialize(true)'
//   then rematerialization of that instruction is prohibited and the
//   instruction's value will be spilled if necessary.
// - If an instruction is attributed with 'ins_should_rematerialize(true)'
//   then rematerialization is enforced and the instruction's value will
//   never get spilled. a copy of the instruction will be inserted if
//   necessary.
//   Note: this may result in rematerializations in front of every use.
// (optional attribute)
ins_attrib ins_cannot_rematerialize(false);
ins_attrib ins_should_rematerialize(false);

//----------OPERANDS-----------------------------------------------------------
// Operand definitions must precede instruction definitions for correct
// parsing in the ADLC because operands constitute user defined types
// which are used in instruction definitions.

//----------Simple Operands----------------------------------------------------
// Immediate Operands
// Please note:
// Formats are generated automatically for constants and base registers.

//----------------------------------------------
// SIGNED (shorter than INT) immediate operands
//----------------------------------------------

// Byte Immediate: constant 'int -1'
operand immB_minus1() %{
  //         sign-ext constant      zero-ext constant
  predicate((n->get_int() == -1) || ((n->get_int()&0x000000ff) == 0x000000ff));
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Byte Immediate: constant, but not 'int 0' nor 'int -1'.
operand immB_n0m1() %{
  //                             sign-ext constant     zero-ext constant
  predicate(n->get_int() != 0 && n->get_int() != -1 && (n->get_int()&0x000000ff) != 0x000000ff);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Short Immediate: constant 'int -1'
operand immS_minus1() %{
  //         sign-ext constant      zero-ext constant
  predicate((n->get_int() == -1) || ((n->get_int()&0x0000ffff) == 0x0000ffff));
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Short Immediate: constant, but not 'int 0' nor 'int -1'.
operand immS_n0m1() %{
  //                             sign-ext constant     zero-ext constant
  predicate(n->get_int() != 0 && n->get_int() != -1 && (n->get_int()&0x0000ffff) != 0x0000ffff);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

//-----------------------------------------
//  SIGNED INT immediate operands
//-----------------------------------------

// Integer Immediate: 32-bit
operand immI() %{
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Int Immediate: 20-bit
operand immI20() %{
  predicate(Immediate::is_simm20(n->get_int()));
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: 16-bit
operand immI16() %{
  predicate(Immediate::is_simm16(n->get_int()));
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: 8-bit
operand immI8() %{
  predicate(Immediate::is_simm8(n->get_int()));
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: constant 'int 0'
operand immI_0() %{
  predicate(n->get_int() == 0);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: constant 'int -1'
operand immI_minus1() %{
  predicate(n->get_int() == -1);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: constant, but not 'int 0' nor 'int -1'.
operand immI_n0m1() %{
  predicate(n->get_int() != 0 && n->get_int() != -1);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

//-------------------------------------------
// UNSIGNED INT immediate operands
//-------------------------------------------

// Unsigned Integer Immediate: 32-bit
operand uimmI() %{
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Integer Immediate: 16-bit
operand uimmI16() %{
  predicate(Immediate::is_uimm16(n->get_int()));
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Integer Immediate: 12-bit
operand uimmI12() %{
  predicate(Immediate::is_uimm12(n->get_int()));
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Integer Immediate: 12-bit
operand uimmI8() %{
  predicate(Immediate::is_uimm8(n->get_int()));
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: 6-bit
operand uimmI6() %{
  predicate(Immediate::is_uimm(n->get_int(), 6));
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: 5-bit
operand uimmI5() %{
  predicate(Immediate::is_uimm(n->get_int(), 5));
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Length for SS instructions, given in DWs,
//   possible range [1..512], i.e. [8..4096] Bytes
//   used     range [1..256], i.e. [8..2048] Bytes
//   operand type int
// Unsigned Integer Immediate: 9-bit
operand SSlenDW() %{
  predicate(Immediate::is_uimm8(n->get_long()-1));
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

//------------------------------------------
// (UN)SIGNED INT specific values
//------------------------------------------

// Integer Immediate: the value 1
operand immI_1() %{
  predicate(n->get_int() == 1);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the value 16.
operand immI_16() %{
  predicate(n->get_int() == 16);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the value 24.
operand immI_24() %{
  predicate(n->get_int() == 24);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the value 255
operand immI_255() %{
  predicate(n->get_int() == 255);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the values 32-63
operand immI_32_63() %{
  predicate(n->get_int() >= 32 && n->get_int() <= 63);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Integer Immediate: LL-part, extended by 1s.
operand uimmI_LL1() %{
  predicate((n->get_int() & 0xFFFF0000) == 0xFFFF0000);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Integer Immediate: LH-part, extended by 1s.
operand uimmI_LH1() %{
  predicate((n->get_int() & 0xFFFF) == 0xFFFF);
  match(ConI);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

//------------------------------------------
// SIGNED LONG immediate operands
//------------------------------------------

operand immL() %{
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Long Immediate: 32-bit
operand immL32() %{
  predicate(Immediate::is_simm32(n->get_long()));
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Long Immediate: 20-bit
operand immL20() %{
  predicate(Immediate::is_simm20(n->get_long()));
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Long Immediate: 16-bit
operand immL16() %{
  predicate(Immediate::is_simm16(n->get_long()));
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Long Immediate: 8-bit
operand immL8() %{
  predicate(Immediate::is_simm8(n->get_long()));
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

//--------------------------------------------
// UNSIGNED LONG immediate operands
//--------------------------------------------

operand uimmL32() %{
  predicate(Immediate::is_uimm32(n->get_long()));
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Long Immediate: 16-bit
operand uimmL16() %{
  predicate(Immediate::is_uimm16(n->get_long()));
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Long Immediate: 12-bit
operand uimmL12() %{
  predicate(Immediate::is_uimm12(n->get_long()));
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Long Immediate: 8-bit
operand uimmL8() %{
  predicate(Immediate::is_uimm8(n->get_long()));
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

//-------------------------------------------
// (UN)SIGNED LONG specific values
//-------------------------------------------

// Long Immediate: the value FF
operand immL_FF() %{
  predicate(n->get_long() == 0xFFL);
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Long Immediate: the value FFFF
operand immL_FFFF() %{
  predicate(n->get_long() == 0xFFFFL);
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Long Immediate: the value FFFFFFFF
operand immL_FFFFFFFF() %{
  predicate(n->get_long() == 0xFFFFFFFFL);
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

operand immL_0() %{
  predicate(n->get_long() == 0L);
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Long Immediate: LL-part, extended by 1s.
operand uimmL_LL1() %{
  predicate((n->get_long() & 0xFFFFFFFFFFFF0000L) == 0xFFFFFFFFFFFF0000L);
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Long Immediate: LH-part, extended by 1s.
operand uimmL_LH1() %{
  predicate((n->get_long() & 0xFFFFFFFF0000FFFFL) == 0xFFFFFFFF0000FFFFL);
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Long Immediate: HL-part, extended by 1s.
operand uimmL_HL1() %{
  predicate((n->get_long() & 0xFFFF0000FFFFFFFFL) == 0xFFFF0000FFFFFFFFL);
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Unsigned Long Immediate: HH-part, extended by 1s.
operand uimmL_HH1() %{
  predicate((n->get_long() & 0xFFFFFFFFFFFFL) == 0xFFFFFFFFFFFFL);
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Long Immediate: low 32-bit mask
operand immL_32bits() %{
  predicate(n->get_long() == 0xFFFFFFFFL);
  match(ConL);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

//--------------------------------------
//  POINTER immediate operands
//--------------------------------------

// Pointer Immediate: 64-bit
operand immP() %{
  match(ConP);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Pointer Immediate: 32-bit
operand immP32() %{
  predicate(Immediate::is_uimm32(n->get_ptr()));
  match(ConP);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Pointer Immediate: 16-bit
operand immP16() %{
  predicate(Immediate::is_uimm16(n->get_ptr()));
  match(ConP);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Pointer Immediate: 8-bit
operand immP8() %{
  predicate(Immediate::is_uimm8(n->get_ptr()));
  match(ConP);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

//-----------------------------------
// POINTER specific values
//-----------------------------------

// Pointer Immediate: NULL
operand immP0() %{
  predicate(n->get_ptr() == 0);
  match(ConP);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

//---------------------------------------------
// NARROW POINTER immediate operands
//---------------------------------------------

// Narrow Pointer Immediate
operand immN() %{
  match(ConN);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

operand immNKlass() %{
  match(ConNKlass);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Narrow Pointer Immediate
operand immN8() %{
  predicate(Immediate::is_uimm8(n->get_narrowcon()));
  match(ConN);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Narrow NULL Pointer Immediate
operand immN0() %{
  predicate(n->get_narrowcon() == 0);
  match(ConN);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// FLOAT and DOUBLE immediate operands

// Double Immediate
operand immD() %{
  match(ConD);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Double Immediate: +-0
operand immDpm0() %{
  predicate(n->getd() == 0);
  match(ConD);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Double Immediate: +0
operand immDp0() %{
  predicate(jlong_cast(n->getd()) == 0);
  match(ConD);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Float Immediate
operand immF() %{
  match(ConF);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Float Immediate: +-0
operand immFpm0() %{
  predicate(n->getf() == 0);
  match(ConF);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// Float Immediate: +0
operand immFp0() %{
  predicate(jint_cast(n->getf()) == 0);
  match(ConF);
  op_cost(1);
  format %{ %}
  interface(CONST_INTER);
%}

// End of Immediate Operands

// Integer Register Operands
// Integer Register
operand iRegI() %{
  constraint(ALLOC_IN_RC(z_int_reg));
  match(RegI);
  match(noArg_iRegI);
  match(rarg1RegI);
  match(rarg2RegI);
  match(rarg3RegI);
  match(rarg4RegI);
  match(rarg5RegI);
  match(noOdd_iRegI);
  match(revenRegI);
  match(roddRegI);
  format %{ %}
  interface(REG_INTER);
%}

operand noArg_iRegI() %{
  constraint(ALLOC_IN_RC(z_no_arg_int_reg));
  match(RegI);
  format %{ %}
  interface(REG_INTER);
%}

// revenRegI and roddRegI constitute and even-odd-pair.
operand revenRegI() %{
  constraint(ALLOC_IN_RC(z_rarg3_int_reg));
  match(iRegI);
  format %{ %}
  interface(REG_INTER);
%}

// revenRegI and roddRegI constitute and even-odd-pair.
operand roddRegI() %{
  constraint(ALLOC_IN_RC(z_rarg4_int_reg));
  match(iRegI);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg1RegI() %{
  constraint(ALLOC_IN_RC(z_rarg1_int_reg));
  match(iRegI);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg2RegI() %{
  constraint(ALLOC_IN_RC(z_rarg2_int_reg));
  match(iRegI);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg3RegI() %{
  constraint(ALLOC_IN_RC(z_rarg3_int_reg));
  match(iRegI);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg4RegI() %{
  constraint(ALLOC_IN_RC(z_rarg4_int_reg));
  match(iRegI);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg5RegI() %{
  constraint(ALLOC_IN_RC(z_rarg5_int_reg));
  match(iRegI);
  format %{ %}
  interface(REG_INTER);
%}

operand noOdd_iRegI() %{
  constraint(ALLOC_IN_RC(z_no_odd_int_reg));
  match(RegI);
  match(revenRegI);
  format %{ %}
  interface(REG_INTER);
%}

// Pointer Register
operand iRegP() %{
  constraint(ALLOC_IN_RC(z_ptr_reg));
  match(RegP);
  match(noArg_iRegP);
  match(rarg1RegP);
  match(rarg2RegP);
  match(rarg3RegP);
  match(rarg4RegP);
  match(rarg5RegP);
  match(revenRegP);
  match(roddRegP);
  format %{ %}
  interface(REG_INTER);
%}

// thread operand
operand threadRegP() %{
  constraint(ALLOC_IN_RC(z_thread_ptr_reg));
  match(RegP);
  format %{ "Z_THREAD" %}
  interface(REG_INTER);
%}

operand noArg_iRegP() %{
  constraint(ALLOC_IN_RC(z_no_arg_ptr_reg));
  match(iRegP);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg1RegP() %{
  constraint(ALLOC_IN_RC(z_rarg1_ptr_reg));
  match(iRegP);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg2RegP() %{
  constraint(ALLOC_IN_RC(z_rarg2_ptr_reg));
  match(iRegP);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg3RegP() %{
  constraint(ALLOC_IN_RC(z_rarg3_ptr_reg));
  match(iRegP);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg4RegP() %{
  constraint(ALLOC_IN_RC(z_rarg4_ptr_reg));
  match(iRegP);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg5RegP() %{
  constraint(ALLOC_IN_RC(z_rarg5_ptr_reg));
  match(iRegP);
  format %{ %}
  interface(REG_INTER);
%}

operand memoryRegP() %{
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(RegP);
  match(iRegP);
  match(threadRegP);
  format %{ %}
  interface(REG_INTER);
%}

// revenRegP and roddRegP constitute and even-odd-pair.
operand revenRegP() %{
  constraint(ALLOC_IN_RC(z_rarg3_ptr_reg));
  match(iRegP);
  format %{ %}
  interface(REG_INTER);
%}

// revenRegP and roddRegP constitute and even-odd-pair.
operand roddRegP() %{
  constraint(ALLOC_IN_RC(z_rarg4_ptr_reg));
  match(iRegP);
  format %{ %}
  interface(REG_INTER);
%}

operand lock_ptr_RegP() %{
  constraint(ALLOC_IN_RC(z_lock_ptr_reg));
  match(RegP);
  format %{ %}
  interface(REG_INTER);
%}

operand rscratch2RegP() %{
  constraint(ALLOC_IN_RC(z_rscratch2_bits64_reg));
  match(RegP);
  format %{ %}
  interface(REG_INTER);
%}

operand iRegN() %{
  constraint(ALLOC_IN_RC(z_int_reg));
  match(RegN);
  match(noArg_iRegN);
  match(rarg1RegN);
  match(rarg2RegN);
  match(rarg3RegN);
  match(rarg4RegN);
  match(rarg5RegN);
  format %{ %}
  interface(REG_INTER);
%}

operand noArg_iRegN() %{
  constraint(ALLOC_IN_RC(z_no_arg_int_reg));
  match(iRegN);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg1RegN() %{
  constraint(ALLOC_IN_RC(z_rarg1_int_reg));
  match(iRegN);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg2RegN() %{
  constraint(ALLOC_IN_RC(z_rarg2_int_reg));
  match(iRegN);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg3RegN() %{
  constraint(ALLOC_IN_RC(z_rarg3_int_reg));
  match(iRegN);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg4RegN() %{
  constraint(ALLOC_IN_RC(z_rarg4_int_reg));
  match(iRegN);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg5RegN() %{
  constraint(ALLOC_IN_RC(z_rarg5_ptrN_reg));
  match(iRegN);
  format %{ %}
  interface(REG_INTER);
%}

// Long Register
operand iRegL() %{
  constraint(ALLOC_IN_RC(z_long_reg));
  match(RegL);
  match(revenRegL);
  match(roddRegL);
  match(allRoddRegL);
  match(rarg1RegL);
  match(rarg5RegL);
  format %{ %}
  interface(REG_INTER);
%}

// revenRegL and roddRegL constitute and even-odd-pair.
operand revenRegL() %{
  constraint(ALLOC_IN_RC(z_rarg3_long_reg));
  match(iRegL);
  format %{ %}
  interface(REG_INTER);
%}

// revenRegL and roddRegL constitute and even-odd-pair.
operand roddRegL() %{
  constraint(ALLOC_IN_RC(z_rarg4_long_reg));
  match(iRegL);
  format %{ %}
  interface(REG_INTER);
%}

// available odd registers for iRegL
operand allRoddRegL() %{
  constraint(ALLOC_IN_RC(z_long_odd_reg));
  match(iRegL);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg1RegL() %{
  constraint(ALLOC_IN_RC(z_rarg1_long_reg));
  match(iRegL);
  format %{ %}
  interface(REG_INTER);
%}

operand rarg5RegL() %{
  constraint(ALLOC_IN_RC(z_rarg5_long_reg));
  match(iRegL);
  format %{ %}
  interface(REG_INTER);
%}

// Condition Code Flag Registers
operand flagsReg() %{
  constraint(ALLOC_IN_RC(z_condition_reg));
  match(RegFlags);
  format %{ "CR" %}
  interface(REG_INTER);
%}

// Condition Code Flag Registers for rules with result tuples
operand TD_flagsReg() %{
  constraint(ALLOC_IN_RC(z_condition_reg));
  match(RegFlags);
  format %{ "CR" %}
  interface(REG_TUPLE_DEST_INTER);
%}

operand regD() %{
  constraint(ALLOC_IN_RC(z_dbl_reg));
  match(RegD);
  format %{ %}
  interface(REG_INTER);
%}

operand rscratchRegD() %{
  constraint(ALLOC_IN_RC(z_rscratch1_dbl_reg));
  match(RegD);
  format %{ %}
  interface(REG_INTER);
%}

operand regF() %{
  constraint(ALLOC_IN_RC(z_flt_reg));
  match(RegF);
  format %{ %}
  interface(REG_INTER);
%}

operand rscratchRegF() %{
  constraint(ALLOC_IN_RC(z_rscratch1_flt_reg));
  match(RegF);
  format %{ %}
  interface(REG_INTER);
%}

// Special Registers

// Method Register
operand inline_cache_regP(iRegP reg) %{
  constraint(ALLOC_IN_RC(z_r9_regP)); // inline_cache_reg
  match(reg);
  format %{ %}
  interface(REG_INTER);
%}

// Operands to remove register moves in unscaled mode.
// Match read/write registers with an EncodeP node if neither shift nor add are required.
operand iRegP2N(iRegP reg) %{
  predicate(CompressedOops::shift() == 0 && _leaf->as_EncodeP()->in(0) == NULL);
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(EncodeP reg);
  format %{ "$reg" %}
  interface(REG_INTER)
%}

operand iRegN2P(iRegN reg) %{
  predicate(CompressedOops::base() == NULL && CompressedOops::shift() == 0 &&
            _leaf->as_DecodeN()->in(0) == NULL);
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(DecodeN reg);
  format %{ "$reg" %}
  interface(REG_INTER)
%}


//----------Complex Operands---------------------------------------------------

// Indirect Memory Reference
operand indirect(memoryRegP base) %{
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(base);
  op_cost(1);
  format %{ "#0[,$base]" %}
  interface(MEMORY_INTER) %{
    base($base);
    index(0xffffFFFF); // noreg
    scale(0x0);
    disp(0x0);
  %}
%}

// Indirect with Offset (long)
operand indOffset20(memoryRegP base, immL20 offset) %{
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(AddP base offset);
  op_cost(1);
  format %{ "$offset[,$base]" %}
  interface(MEMORY_INTER) %{
    base($base);
    index(0xffffFFFF); // noreg
    scale(0x0);
    disp($offset);
  %}
%}

operand indOffset20Narrow(iRegN base, immL20 offset) %{
  predicate(Matcher::narrow_oop_use_complex_address());
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(AddP (DecodeN base) offset);
  op_cost(1);
  format %{ "$offset[,$base]" %}
  interface(MEMORY_INTER) %{
    base($base);
    index(0xffffFFFF); // noreg
    scale(0x0);
    disp($offset);
  %}
%}

// Indirect with Offset (short)
operand indOffset12(memoryRegP base, uimmL12 offset) %{
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(AddP base offset);
  op_cost(1);
  format %{ "$offset[[,$base]]" %}
  interface(MEMORY_INTER) %{
    base($base);
    index(0xffffFFFF); // noreg
    scale(0x0);
    disp($offset);
  %}
%}

operand indOffset12Narrow(iRegN base, uimmL12 offset) %{
  predicate(Matcher::narrow_oop_use_complex_address());
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(AddP (DecodeN base) offset);
  op_cost(1);
  format %{ "$offset[[,$base]]" %}
  interface(MEMORY_INTER) %{
    base($base);
    index(0xffffFFFF); // noreg
    scale(0x0);
    disp($offset);
  %}
%}

// Indirect with Register Index
operand indIndex(memoryRegP base, iRegL index) %{
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(AddP base index);
  op_cost(1);
  format %{ "#0[($index,$base)]" %}
  interface(MEMORY_INTER) %{
    base($base);
    index($index);
    scale(0x0);
    disp(0x0);
  %}
%}

// Indirect with Offset (long) and index
operand indOffset20index(memoryRegP base, immL20 offset, iRegL index) %{
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(AddP (AddP base index) offset);
  op_cost(1);
  format %{ "$offset[($index,$base)]" %}
  interface(MEMORY_INTER) %{
    base($base);
    index($index);
    scale(0x0);
    disp($offset);
  %}
%}

operand indOffset20indexNarrow(iRegN base, immL20 offset, iRegL index) %{
  predicate(Matcher::narrow_oop_use_complex_address());
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(AddP (AddP (DecodeN base) index) offset);
  op_cost(1);
  format %{ "$offset[($index,$base)]" %}
  interface(MEMORY_INTER) %{
    base($base);
    index($index);
    scale(0x0);
    disp($offset);
  %}
%}

// Indirect with Offset (short) and index
operand indOffset12index(memoryRegP base, uimmL12 offset, iRegL index) %{
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(AddP (AddP base index) offset);
  op_cost(1);
  format %{ "$offset[[($index,$base)]]" %}
  interface(MEMORY_INTER) %{
    base($base);
    index($index);
    scale(0x0);
    disp($offset);
  %}
%}

operand indOffset12indexNarrow(iRegN base, uimmL12 offset, iRegL index) %{
  predicate(Matcher::narrow_oop_use_complex_address());
  constraint(ALLOC_IN_RC(z_memory_ptr_reg));
  match(AddP (AddP (DecodeN base) index) offset);
  op_cost(1);
  format %{ "$offset[[($index,$base)]]" %}
  interface(MEMORY_INTER) %{
    base($base);
    index($index);
    scale(0x0);
    disp($offset);
  %}
%}

//----------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 stackSlotI(sRegI reg) %{
  constraint(ALLOC_IN_RC(stack_slots));
  op_cost(1);
  format %{ "[$reg(stackSlotI)]" %}
  interface(MEMORY_INTER) %{
    base(0xf);   // Z_SP
    index(0xffffFFFF); // noreg
    scale(0x0);
    disp($reg);  // stack offset
  %}
%}

operand stackSlotP(sRegP reg) %{
  constraint(ALLOC_IN_RC(stack_slots));
  op_cost(1);
  format %{ "[$reg(stackSlotP)]" %}
  interface(MEMORY_INTER) %{
    base(0xf);   // Z_SP
    index(0xffffFFFF); // noreg
    scale(0x0);
    disp($reg);  // Stack Offset
  %}
%}

operand stackSlotF(sRegF reg) %{
  constraint(ALLOC_IN_RC(stack_slots));
  op_cost(1);
  format %{ "[$reg(stackSlotF)]" %}
  interface(MEMORY_INTER) %{
    base(0xf);   // Z_SP
    index(0xffffFFFF); // noreg
    scale(0x0);
    disp($reg);  // Stack Offset
  %}
%}

operand stackSlotD(sRegD reg) %{
  constraint(ALLOC_IN_RC(stack_slots));
  op_cost(1);
  //match(RegD);
  format %{ "[$reg(stackSlotD)]" %}
  interface(MEMORY_INTER) %{
    base(0xf);   // Z_SP
    index(0xffffFFFF); // noreg
    scale(0x0);
    disp($reg);  // Stack Offset
  %}
%}

operand stackSlotL(sRegL reg) %{
  constraint(ALLOC_IN_RC(stack_slots));
  op_cost(1);  //match(RegL);
  format %{ "[$reg(stackSlotL)]" %}
  interface(MEMORY_INTER) %{
    base(0xf);   // Z_SP
    index(0xffffFFFF); // noreg
    scale(0x0);
    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.

// INT cmpOps for CompareAndBranch and CompareAndTrap instructions should not
// have mask bit #3 set.
operand cmpOpT() %{
  match(Bool);
  format %{ "" %}
  interface(COND_INTER) %{
    equal(0x8);         // Assembler::bcondEqual
    not_equal(0x6);     // Assembler::bcondNotEqual
    less(0x4);          // Assembler::bcondLow
    greater_equal(0xa); // Assembler::bcondNotLow
    less_equal(0xc);    // Assembler::bcondNotHigh
    greater(0x2);       // Assembler::bcondHigh
    overflow(0x1);      // Assembler::bcondOverflow
    no_overflow(0xe);   // Assembler::bcondNotOverflow
  %}
%}

// When used for floating point comparisons: unordered is treated as less.
operand cmpOpF() %{
  match(Bool);
  format %{ "" %}
  interface(COND_INTER) %{
    equal(0x8);
    not_equal(0x7);     // Includes 'unordered'.
    less(0x5);          // Includes 'unordered'.
    greater_equal(0xa);
    less_equal(0xd);    // Includes 'unordered'.
    greater(0x2);
    overflow(0x0);      // Not meaningful on z/Architecture.
    no_overflow(0x0);   // leave unchanged (zero) therefore
  %}
%}

// "Regular" cmpOp for int comparisons, includes bit #3 (overflow).
operand cmpOp() %{
  match(Bool);
  format %{ "" %}
  interface(COND_INTER) %{
    equal(0x8);
    not_equal(0x7);     // Includes 'unordered'.
    less(0x5);          // Includes 'unordered'.
    greater_equal(0xa);
    less_equal(0xd);    // Includes 'unordered'.
    greater(0x2);
    overflow(0x1);      // Assembler::bcondOverflow
    no_overflow(0xe);   // Assembler::bcondNotOverflow
  %}
%}

//----------OPERAND CLASSES----------------------------------------------------
// Operand Classes are groups of operands that are used to simplify
// instruction definitions by not requiring the AD writer to specify
// separate instructions for every form of operand when the
// instruction accepts multiple operand types with the same basic
// encoding and format.  The classic case of this is memory operands.
// Indirect is not included since its use is limited to Compare & Swap

// Most general memory operand, allows base, index, and long displacement.
opclass memory(indirect, indIndex, indOffset20, indOffset20Narrow, indOffset20index, indOffset20indexNarrow);
opclass memoryRXY(indirect, indIndex, indOffset20, indOffset20Narrow, indOffset20index, indOffset20indexNarrow);

// General memory operand, allows base, index, and short displacement.
opclass memoryRX(indirect, indIndex, indOffset12, indOffset12Narrow, indOffset12index, indOffset12indexNarrow);

// Memory operand, allows only base and long displacement.
opclass memoryRSY(indirect, indOffset20, indOffset20Narrow);

// Memory operand, allows only base and short displacement.
opclass memoryRS(indirect, indOffset12, indOffset12Narrow);

// Operand classes to match encode and decode.
opclass iRegN_P2N(iRegN);
opclass iRegP_N2P(iRegP);


//----------PIPELINE-----------------------------------------------------------
pipeline %{

//----------ATTRIBUTES---------------------------------------------------------
attributes %{
  // z/Architecture instructions are of length 2, 4, or 6 bytes.
  variable_size_instructions;
  instruction_unit_size = 2;

  // Meaningless on z/Architecture.
  max_instructions_per_bundle = 1;

  // The z/Architecture processor fetches 64 bytes...
  instruction_fetch_unit_size = 64;

  // ...in one line.
  instruction_fetch_units = 1
%}

//----------RESOURCES----------------------------------------------------------
// Resources are the functional units available to the machine.
resources(
   Z_BR,     // branch unit
   Z_CR,     // condition unit
   Z_FX1,    // integer arithmetic unit 1
   Z_FX2,    // integer arithmetic unit 2
   Z_LDST1,  // load/store unit 1
   Z_LDST2,  // load/store unit 2
   Z_FP1,    // float arithmetic unit 1
   Z_FP2,    // float arithmetic unit 2
   Z_LDST = Z_LDST1 | Z_LDST2,
   Z_FX   = Z_FX1 | Z_FX2,
   Z_FP   = Z_FP1 | Z_FP2
  );

//----------PIPELINE DESCRIPTION-----------------------------------------------
// Pipeline Description specifies the stages in the machine's pipeline.
pipe_desc(
   // TODO: adapt
   Z_IF,  // instruction fetch
   Z_IC,
   Z_D0,  // decode
   Z_D1,  // decode
   Z_D2,  // decode
   Z_D3,  // decode
   Z_Xfer1,
   Z_GD,  // group definition
   Z_MP,  // map
   Z_ISS, // issue
   Z_RF,  // resource fetch
   Z_EX1, // execute (all units)
   Z_EX2, // execute (FP, LDST)
   Z_EX3, // execute (FP, LDST)
   Z_EX4, // execute (FP)
   Z_EX5, // execute (FP)
   Z_EX6, // execute (FP)
   Z_WB,  // write back
   Z_Xfer2,
   Z_CP
  );

//----------PIPELINE CLASSES---------------------------------------------------
// Pipeline Classes describe the stages in which input and output are
// referenced by the hardware pipeline.

// Providing the `ins_pipe' declarations in the instruction
// specifications seems to be of little use. So we use
// `pipe_class_dummy' for all our instructions at present.
pipe_class pipe_class_dummy() %{
  single_instruction;
  fixed_latency(4);
%}

// SIGTRAP based implicit range checks in compiled code.
// Currently, no pipe classes are used on z/Architecture.
pipe_class pipe_class_trap() %{
  single_instruction;
%}

pipe_class pipe_class_fx_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
  single_instruction;
  dst  : Z_EX1(write);
  src1 : Z_RF(read);
  src2 : Z_RF(read);
  Z_FX : Z_RF;
%}

pipe_class pipe_class_ldst(iRegP dst, memory mem) %{
  single_instruction;
  mem : Z_RF(read);
  dst : Z_WB(write);
  Z_LDST : Z_RF;
%}

define %{
  MachNop = pipe_class_dummy;
%}

%}

//----------INSTRUCTIONS-------------------------------------------------------

//---------- Chain stack slots between similar types --------

// Load integer from stack slot.
instruct stkI_to_regI(iRegI dst, stackSlotI src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "L       $dst,$src\t # stk reload int" %}
  opcode(L_ZOPC);
  ins_encode(z_form_rt_mem(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Store integer to stack slot.
instruct regI_to_stkI(stackSlotI dst, iRegI src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "ST      $src,$dst\t # stk spill int" %}
  opcode(ST_ZOPC);
  ins_encode(z_form_rt_mem(src, dst)); // rs=rt
  ins_pipe(pipe_class_dummy);
%}

// Load long from stack slot.
instruct stkL_to_regL(iRegL dst, stackSlotL src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LG      $dst,$src\t # stk reload long" %}
  opcode(LG_ZOPC);
  ins_encode(z_form_rt_mem(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Store long to stack slot.
instruct regL_to_stkL(stackSlotL dst, iRegL src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "STG     $src,$dst\t # stk spill long" %}
  opcode(STG_ZOPC);
  ins_encode(z_form_rt_mem(src, dst)); // rs=rt
  ins_pipe(pipe_class_dummy);
%}

// Load pointer from stack slot, 64-bit encoding.
instruct stkP_to_regP(iRegP dst, stackSlotP src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LG      $dst,$src\t # stk reload ptr" %}
  opcode(LG_ZOPC);
  ins_encode(z_form_rt_mem(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Store pointer to stack slot.
instruct regP_to_stkP(stackSlotP dst, iRegP src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "STG     $src,$dst\t # stk spill ptr" %}
  opcode(STG_ZOPC);
  ins_encode(z_form_rt_mem(src, dst)); // rs=rt
  ins_pipe(pipe_class_dummy);
%}

//  Float types

// Load float value from stack slot.
instruct stkF_to_regF(regF dst, stackSlotF src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "LE(Y)   $dst,$src\t # stk reload float" %}
  opcode(LE_ZOPC);
  ins_encode(z_form_rt_mem(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Store float value to stack slot.
instruct regF_to_stkF(stackSlotF dst, regF src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "STE(Y)  $src,$dst\t # stk spill float" %}
  opcode(STE_ZOPC);
  ins_encode(z_form_rt_mem(src, dst));
  ins_pipe(pipe_class_dummy);
%}

// Load double value from stack slot.
instruct stkD_to_regD(regD dst, stackSlotD src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LD(Y)   $dst,$src\t # stk reload double" %}
  opcode(LD_ZOPC);
  ins_encode(z_form_rt_mem(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Store double value to stack slot.
instruct regD_to_stkD(stackSlotD dst, regD src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "STD(Y)  $src,$dst\t # stk spill double" %}
  opcode(STD_ZOPC);
  ins_encode(z_form_rt_mem(src, dst));
  ins_pipe(pipe_class_dummy);
%}

//----------Load/Store/Move Instructions---------------------------------------

//----------Load Instructions--------------------------------------------------

//------------------
//  MEMORY
//------------------

//  BYTE
// Load Byte (8bit signed)
instruct loadB(iRegI dst, memory mem) %{
  match(Set dst (LoadB mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LB      $dst, $mem\t # sign-extend byte to int" %}
  opcode(LB_ZOPC, LB_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load Byte (8bit signed)
instruct loadB2L(iRegL dst, memory mem) %{
  match(Set dst (ConvI2L (LoadB mem)));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LGB     $dst, $mem\t # sign-extend byte to long" %}
  opcode(LGB_ZOPC, LGB_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load Unsigned Byte (8bit UNsigned) into an int reg.
instruct loadUB(iRegI dst, memory mem) %{
  match(Set dst (LoadUB mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LLGC    $dst,$mem\t # zero-extend byte to int" %}
  opcode(LLGC_ZOPC, LLGC_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load Unsigned Byte (8bit UNsigned) into a Long Register.
instruct loadUB2L(iRegL dst, memory mem) %{
  match(Set dst (ConvI2L (LoadUB mem)));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LLGC    $dst,$mem\t # zero-extend byte to long" %}
  opcode(LLGC_ZOPC, LLGC_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// CHAR/SHORT

// Load Short (16bit signed)
instruct loadS(iRegI dst, memory mem) %{
  match(Set dst (LoadS mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "LH(Y)   $dst,$mem\t # sign-extend short to int" %}
  opcode(LHY_ZOPC, LH_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load Short (16bit signed)
instruct loadS2L(iRegL dst, memory mem) %{
  match(Set dst (ConvI2L (LoadS mem)));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LGH     $dst,$mem\t # sign-extend short to long" %}
  opcode(LGH_ZOPC, LGH_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load Char (16bit Unsigned)
instruct loadUS(iRegI dst, memory mem) %{
  match(Set dst (LoadUS mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LLGH    $dst,$mem\t # zero-extend short to int" %}
  opcode(LLGH_ZOPC, LLGH_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load Unsigned Short/Char (16bit UNsigned) into a Long Register.
instruct loadUS2L(iRegL dst, memory mem) %{
  match(Set dst (ConvI2L (LoadUS mem)));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LLGH    $dst,$mem\t # zero-extend short to long" %}
  opcode(LLGH_ZOPC, LLGH_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// INT

// Load Integer
instruct loadI(iRegI dst, memory mem) %{
  match(Set dst (LoadI mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "L(Y)    $dst,$mem\t #" %}
  opcode(LY_ZOPC, L_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load and convert to long.
instruct loadI2L(iRegL dst, memory mem) %{
  match(Set dst (ConvI2L (LoadI mem)));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LGF     $dst,$mem\t #" %}
  opcode(LGF_ZOPC, LGF_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load Unsigned Integer into a Long Register
instruct loadUI2L(iRegL dst, memory mem, immL_FFFFFFFF mask) %{
  match(Set dst (AndL (ConvI2L (LoadI mem)) mask));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LLGF    $dst,$mem\t # zero-extend int to long" %}
  opcode(LLGF_ZOPC, LLGF_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// range = array length (=jint)
// Load Range
instruct loadRange(iRegI dst, memory mem) %{
  match(Set dst (LoadRange mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "L(Y)    $dst,$mem\t # range" %}
  opcode(LY_ZOPC, L_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// LONG

// Load Long - aligned
instruct loadL(iRegL dst, memory mem) %{
  match(Set dst (LoadL mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LG      $dst,$mem\t # long" %}
  opcode(LG_ZOPC, LG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load Long - UNaligned
instruct loadL_unaligned(iRegL dst, memory mem) %{
  match(Set dst (LoadL_unaligned mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LG      $dst,$mem\t # unaligned long" %}
  opcode(LG_ZOPC, LG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}


// PTR

// Load Pointer
instruct loadP(iRegP dst, memory mem) %{
  match(Set dst (LoadP mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LG      $dst,$mem\t # ptr" %}
  opcode(LG_ZOPC, LG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// LoadP + CastP2L
instruct castP2X_loadP(iRegL dst, memory mem) %{
  match(Set dst (CastP2X (LoadP mem)));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LG      $dst,$mem\t # ptr + p2x" %}
  opcode(LG_ZOPC, LG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load Klass Pointer
instruct loadKlass(iRegP dst, memory mem) %{
  match(Set dst (LoadKlass mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LG      $dst,$mem\t # klass ptr" %}
  opcode(LG_ZOPC, LG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

instruct loadTOC(iRegL dst) %{
  effect(DEF dst);
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  // TODO: check why this attribute causes many unnecessary rematerializations.
  //
  // The graphs I saw just had high register pressure. Further the
  // register TOC is loaded to is overwritten by the constant short
  // after. Here something as round robin register allocation might
  // help. But rematerializing seems not to hurt, jack even seems to
  // improve slightly.
  //
  // Without this flag we get spill-split recycle sanity check
  // failures in
  // spec.benchmarks._228_jack.NfaState::GenerateCode. This happens in
  // a block with three loadConP_dynTOC nodes and a tlsLoadP. The
  // tlsLoadP has a huge amount of outs and forces the TOC down to the
  // stack. Later tlsLoadP is rematerialized, leaving the register
  // allocator with TOC on the stack and a badly placed reload.
  ins_should_rematerialize(true);
  format %{ "LARL    $dst, &constant_pool\t; load dynTOC" %}
  ins_encode %{ __ load_toc($dst$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

// FLOAT

// Load Float
instruct loadF(regF dst, memory mem) %{
  match(Set dst (LoadF mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "LE(Y)    $dst,$mem" %}
  opcode(LEY_ZOPC, LE_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// DOUBLE

// Load Double
instruct loadD(regD dst, memory mem) %{
  match(Set dst (LoadD mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "LD(Y)    $dst,$mem" %}
  opcode(LDY_ZOPC, LD_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load Double - UNaligned
instruct loadD_unaligned(regD dst, memory mem) %{
  match(Set dst (LoadD_unaligned mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "LD(Y)    $dst,$mem" %}
  opcode(LDY_ZOPC, LD_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}


//----------------------
//  IMMEDIATES
//----------------------

instruct loadConI(iRegI dst, immI src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "LGFI    $dst,$src\t # (int)" %}
  ins_encode %{ __ z_lgfi($dst$$Register, $src$$constant); %}  // Sign-extend to 64 bit, it's at no cost.
  ins_pipe(pipe_class_dummy);
%}

instruct loadConI16(iRegI dst, immI16 src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LGHI    $dst,$src\t # (int)" %}
  ins_encode %{ __ z_lghi($dst$$Register, $src$$constant); %}  // Sign-extend to 64 bit, it's at no cost.
  ins_pipe(pipe_class_dummy);
%}

instruct loadConI_0(iRegI dst, immI_0 src, flagsReg cr) %{
  match(Set dst src);
  effect(KILL cr);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "loadConI $dst,$src\t # (int) XGR because ZERO is loaded" %}
  opcode(XGR_ZOPC);
  ins_encode(z_rreform(dst, dst));
  ins_pipe(pipe_class_dummy);
%}

instruct loadConUI16(iRegI dst, uimmI16 src) %{
  match(Set dst src);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LLILL    $dst,$src" %}
  opcode(LLILL_ZOPC);
  ins_encode(z_riform_unsigned(dst, src) );
  ins_pipe(pipe_class_dummy);
%}

// Load long constant from TOC with pcrelative address.
instruct loadConL_pcrelTOC(iRegL dst, immL src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST_LO);
  size(6);
  format %{ "LGRL    $dst,[pcrelTOC]\t # load long $src from table" %}
  ins_encode %{
    address long_address = __ long_constant($src$$constant);
    if (long_address == NULL) {
      Compile::current()->env()->record_out_of_memory_failure();
      return;
    }
    __ load_long_pcrelative($dst$$Register, long_address);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct loadConL32(iRegL dst, immL32 src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "LGFI     $dst,$src\t # (long)" %}
  ins_encode %{ __ z_lgfi($dst$$Register, $src$$constant); %}  // Sign-extend to 64 bit, it's at no cost.
  ins_pipe(pipe_class_dummy);
%}

instruct loadConL16(iRegL dst, immL16 src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LGHI     $dst,$src\t # (long)" %}
  ins_encode %{ __ z_lghi($dst$$Register, $src$$constant); %}  // Sign-extend to 64 bit, it's at no cost.
  ins_pipe(pipe_class_dummy);
%}

instruct loadConL_0(iRegL dst, immL_0 src, flagsReg cr) %{
  match(Set dst src);
  effect(KILL cr);
  ins_cost(DEFAULT_COST_LOW);
  format %{ "LoadConL    $dst,$src\t # (long) XGR because ZERO is loaded" %}
  opcode(XGR_ZOPC);
  ins_encode(z_rreform(dst, dst));
  ins_pipe(pipe_class_dummy);
%}

// Load ptr constant from TOC with pc relative address.
// Special handling for oop constants required.
instruct loadConP_pcrelTOC(iRegP dst, immP src) %{
  match(Set dst src);
  ins_cost(MEMORY_REF_COST_LO);
  size(6);
  format %{ "LGRL    $dst,[pcrelTOC]\t # load ptr $src from table" %}
  ins_encode %{
    relocInfo::relocType constant_reloc = $src->constant_reloc();
    if (constant_reloc == relocInfo::oop_type) {
      AddressLiteral a = __ allocate_oop_address((jobject)$src$$constant);
      bool success = __ load_oop_from_toc($dst$$Register, a);
      if (!success) {
        Compile::current()->env()->record_out_of_memory_failure();
        return;
      }
    } else if (constant_reloc == relocInfo::metadata_type) {
      AddressLiteral a = __ constant_metadata_address((Metadata *)$src$$constant);
      address const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none);
      if (const_toc_addr == NULL) {
        Compile::current()->env()->record_out_of_memory_failure();
        return;
      }
      __ load_long_pcrelative($dst$$Register, const_toc_addr);
    } else {          // Non-oop pointers, e.g. card mark base, heap top.
      address long_address = __ long_constant((jlong)$src$$constant);
      if (long_address == NULL) {
        Compile::current()->env()->record_out_of_memory_failure();
        return;
      }
      __ load_long_pcrelative($dst$$Register, long_address);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// We don't use immP16 to avoid problems with oops.
instruct loadConP0(iRegP dst, immP0 src, flagsReg cr) %{
  match(Set dst src);
  effect(KILL cr);
  size(4);
  format %{ "XGR     $dst,$dst\t # NULL ptr" %}
  opcode(XGR_ZOPC);
  ins_encode(z_rreform(dst, dst));
  ins_pipe(pipe_class_dummy);
%}

//----------Load Float Constant Instructions-------------------------------------------------

// We may not specify this instruction via an `expand' rule. If we do,
// code selection will forget that this instruction needs a floating
// point constant inserted into the code buffer. So `Shorten_branches'
// will fail.
instruct loadConF_dynTOC(regF dst, immF src, flagsReg cr) %{
  match(Set dst src);
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  size(6);
  // If this instruction rematerializes, it prolongs the live range
  // of the toc node, causing illegal graphs.
  ins_cannot_rematerialize(true);
  format %{ "LE(Y)    $dst,$constantoffset[,$constanttablebase]\t # load FLOAT $src from table" %}
  ins_encode %{
    __ load_float_largeoffset($dst$$FloatRegister, $constantoffset($src), $constanttablebase, Z_R1_scratch);
  %}
  ins_pipe(pipe_class_dummy);
%}

// E may not specify this instruction via an `expand' rule. If we do,
// code selection will forget that this instruction needs a floating
// point constant inserted into the code buffer. So `Shorten_branches'
// will fail.
instruct loadConD_dynTOC(regD dst, immD src, flagsReg cr) %{
  match(Set dst src);
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  size(6);
  // If this instruction rematerializes, it prolongs the live range
  // of the toc node, causing illegal graphs.
  ins_cannot_rematerialize(true);
  format %{ "LD(Y)    $dst,$constantoffset[,$constanttablebase]\t # load DOUBLE $src from table" %}
  ins_encode %{
    __ load_double_largeoffset($dst$$FloatRegister, $constantoffset($src), $constanttablebase, Z_R1_scratch);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Special case: Load Const 0.0F

// There's a special instr to clear a FP register.
instruct loadConF0(regF dst, immFp0 src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LZER     $dst,$src\t # clear to zero" %}
  opcode(LZER_ZOPC);
  ins_encode(z_rreform(dst, Z_F0));
  ins_pipe(pipe_class_dummy);
%}

// There's a special instr to clear a FP register.
instruct loadConD0(regD dst, immDp0 src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LZDR     $dst,$src\t # clear to zero" %}
  opcode(LZDR_ZOPC);
  ins_encode(z_rreform(dst, Z_F0));
  ins_pipe(pipe_class_dummy);
%}


//----------Store Instructions-------------------------------------------------

// BYTE

// Store Byte
instruct storeB(memory mem, iRegI src) %{
  match(Set mem (StoreB mem src));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "STC(Y)  $src,$mem\t # byte" %}
  opcode(STCY_ZOPC, STC_ZOPC);
  ins_encode(z_form_rt_mem_opt(src, mem));
  ins_pipe(pipe_class_dummy);
%}

instruct storeCM(memory mem, immI_0 src) %{
  match(Set mem (StoreCM mem src));
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "STC(Y)  $src,$mem\t # CMS card-mark byte (must be 0!)" %}
  ins_encode %{
    guarantee($mem$$index$$Register != Z_R0, "content will not be used.");
    if ($mem$$index$$Register != noreg) {
      // Can't use clear_mem --> load const zero and store character.
      __ load_const_optimized(Z_R0_scratch, (long)0);
      if (Immediate::is_uimm12($mem$$disp)) {
        __ z_stc(Z_R0_scratch, $mem$$Address);
      } else {
        __ z_stcy(Z_R0_scratch, $mem$$Address);
      }
    } else {
      __ clear_mem(Address($mem$$Address), 1);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// CHAR/SHORT

// Store Char/Short
instruct storeC(memory mem, iRegI src) %{
  match(Set mem (StoreC mem src));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "STH(Y)  $src,$mem\t # short" %}
  opcode(STHY_ZOPC, STH_ZOPC);
  ins_encode(z_form_rt_mem_opt(src, mem));
  ins_pipe(pipe_class_dummy);
%}

// INT

// Store Integer
instruct storeI(memory mem, iRegI src) %{
  match(Set mem (StoreI mem src));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "ST(Y)   $src,$mem\t # int" %}
  opcode(STY_ZOPC, ST_ZOPC);
  ins_encode(z_form_rt_mem_opt(src, mem));
  ins_pipe(pipe_class_dummy);
%}

// LONG

// Store Long
instruct storeL(memory mem, iRegL src) %{
  match(Set mem (StoreL mem src));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "STG     $src,$mem\t # long" %}
  opcode(STG_ZOPC, STG_ZOPC);
  ins_encode(z_form_rt_mem_opt(src, mem));
  ins_pipe(pipe_class_dummy);
%}

// PTR

// Store Pointer
instruct storeP(memory dst, memoryRegP src) %{
  match(Set dst (StoreP dst src));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "STG     $src,$dst\t # ptr" %}
  opcode(STG_ZOPC, STG_ZOPC);
  ins_encode(z_form_rt_mem_opt(src, dst));
  ins_pipe(pipe_class_dummy);
%}

// FLOAT

// Store Float
instruct storeF(memory mem, regF src) %{
  match(Set mem (StoreF mem src));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "STE(Y)   $src,$mem\t # float" %}
  opcode(STEY_ZOPC, STE_ZOPC);
  ins_encode(z_form_rt_mem_opt(src, mem));
  ins_pipe(pipe_class_dummy);
%}

// DOUBLE

// Store Double
instruct storeD(memory mem, regD src) %{
  match(Set mem (StoreD mem src));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "STD(Y)   $src,$mem\t # double" %}
  opcode(STDY_ZOPC, STD_ZOPC);
  ins_encode(z_form_rt_mem_opt(src, mem));
  ins_pipe(pipe_class_dummy);
%}

// Prefetch instructions. Must be safe to execute with invalid address (cannot fault).

// Should support match rule for PrefetchAllocation.
// Still needed after 8068977 for PrefetchAllocate.
instruct prefetchAlloc(memory mem) %{
  match(PrefetchAllocation mem);
  predicate(VM_Version::has_Prefetch());
  ins_cost(DEFAULT_COST);
  format %{ "PREFETCH 2, $mem\t # Prefetch allocation, z10 only" %}
  ins_encode %{ __ z_pfd(0x02, $mem$$Address); %}
  ins_pipe(pipe_class_dummy);
%}

//----------Memory init instructions------------------------------------------

// Move Immediate to 1-byte memory.
instruct memInitB(memoryRSY mem, immI8 src) %{
  match(Set mem (StoreB mem src));
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MVI     $mem,$src\t # direct mem init 1" %}
  ins_encode %{
    if (Immediate::is_uimm12((long)$mem$$disp)) {
      __ z_mvi($mem$$Address, $src$$constant);
    } else {
      __ z_mviy($mem$$Address, $src$$constant);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// Move Immediate to 2-byte memory.
instruct memInitC(memoryRS mem, immI16 src) %{
  match(Set mem (StoreC mem src));
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "MVHHI   $mem,$src\t # direct mem init 2" %}
  opcode(MVHHI_ZOPC);
  ins_encode(z_silform(mem, src));
  ins_pipe(pipe_class_dummy);
%}

// Move Immediate to 4-byte memory.
instruct memInitI(memoryRS mem, immI16 src) %{
  match(Set mem (StoreI mem src));
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "MVHI    $mem,$src\t # direct mem init 4" %}
  opcode(MVHI_ZOPC);
  ins_encode(z_silform(mem, src));
  ins_pipe(pipe_class_dummy);
%}


// Move Immediate to 8-byte memory.
instruct memInitL(memoryRS mem, immL16 src) %{
  match(Set mem (StoreL mem src));
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "MVGHI   $mem,$src\t # direct mem init 8" %}
  opcode(MVGHI_ZOPC);
  ins_encode(z_silform(mem, src));
  ins_pipe(pipe_class_dummy);
%}

// Move Immediate to 8-byte memory.
instruct memInitP(memoryRS mem, immP16 src) %{
  match(Set mem (StoreP mem src));
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "MVGHI   $mem,$src\t # direct mem init 8" %}
  opcode(MVGHI_ZOPC);
  ins_encode(z_silform(mem, src));
  ins_pipe(pipe_class_dummy);
%}


//----------Instructions for compressed pointers (cOop and NKlass)-------------

// See cOop encoding classes for elaborate comment.

// Moved here because it is needed in expand rules for encode.
// Long negation.
instruct negL_reg_reg(iRegL dst, immL_0 zero, iRegL src, flagsReg cr) %{
  match(Set dst (SubL zero src));
  effect(KILL cr);
  size(4);
  format %{ "NEG     $dst, $src\t # long" %}
  ins_encode %{ __ z_lcgr($dst$$Register, $src$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

// Load Compressed Pointer

// Load narrow oop
instruct loadN(iRegN dst, memory mem) %{
  match(Set dst (LoadN mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LoadN   $dst,$mem\t # (cOop)" %}
  opcode(LLGF_ZOPC, LLGF_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load narrow Klass Pointer
instruct loadNKlass(iRegN dst, memory mem) %{
  match(Set dst (LoadNKlass mem));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "LoadNKlass $dst,$mem\t # (klass cOop)" %}
  opcode(LLGF_ZOPC, LLGF_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Load constant Compressed Pointer

instruct loadConN(iRegN dst, immN src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "loadConN    $dst,$src\t # (cOop)" %}
  ins_encode %{
    AddressLiteral cOop = __ constant_oop_address((jobject)$src$$constant);
    __ relocate(cOop.rspec(), 1);
    __ load_narrow_oop($dst$$Register, (narrowOop)cOop.value());
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct loadConN0(iRegN dst, immN0 src, flagsReg cr) %{
  match(Set dst src);
  effect(KILL cr);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "loadConN    $dst,$src\t # (cOop) XGR because ZERO is loaded" %}
  opcode(XGR_ZOPC);
  ins_encode(z_rreform(dst, dst));
  ins_pipe(pipe_class_dummy);
%}

instruct loadConNKlass(iRegN dst, immNKlass src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "loadConNKlass $dst,$src\t # (cKlass)" %}
  ins_encode %{
    AddressLiteral NKlass = __ constant_metadata_address((Metadata*)$src$$constant);
    __ relocate(NKlass.rspec(), 1);
    __ load_narrow_klass($dst$$Register, (Klass*)NKlass.value());
  %}
  ins_pipe(pipe_class_dummy);
%}

// Load and Decode Compressed Pointer
// optimized variants for Unscaled cOops

instruct decodeLoadN(iRegP dst, memory mem) %{
  match(Set dst (DecodeN (LoadN mem)));
  predicate(false && (CompressedOops::base()==NULL)&&(CompressedOops::shift()==0));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "DecodeLoadN  $dst,$mem\t # (cOop Load+Decode)" %}
  opcode(LLGF_ZOPC, LLGF_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

instruct decodeLoadNKlass(iRegP dst, memory mem) %{
  match(Set dst (DecodeNKlass (LoadNKlass mem)));
  predicate(false && (CompressedKlassPointers::base()==NULL)&&(CompressedKlassPointers::shift()==0));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "DecodeLoadNKlass  $dst,$mem\t # (load/decode NKlass)" %}
  opcode(LLGF_ZOPC, LLGF_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

instruct decodeLoadConNKlass(iRegP dst, immNKlass src) %{
  match(Set dst (DecodeNKlass src));
  ins_cost(3 * DEFAULT_COST);
  size(12);
  format %{ "DecodeLoadConNKlass  $dst,$src\t # decode(cKlass)" %}
  ins_encode %{
    AddressLiteral NKlass = __ constant_metadata_address((Metadata*)$src$$constant);
    __ relocate(NKlass.rspec(), 1);
    __ load_const($dst$$Register, (Klass*)NKlass.value());
  %}
  ins_pipe(pipe_class_dummy);
%}

// Decode Compressed Pointer

// General decoder
instruct decodeN(iRegP dst, iRegN src, flagsReg cr) %{
  match(Set dst (DecodeN src));
  effect(KILL cr);
  predicate(CompressedOops::base() == NULL || !ExpandLoadingBaseDecode);
  ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "decodeN  $dst,$src\t # (decode cOop)" %}
  ins_encode %{  __ oop_decoder($dst$$Register, $src$$Register, true); %}
  ins_pipe(pipe_class_dummy);
%}

// General Klass decoder
instruct decodeKlass(iRegP dst, iRegN src, flagsReg cr) %{
  match(Set dst (DecodeNKlass src));
  effect(KILL cr);
  ins_cost(3 * DEFAULT_COST);
  format %{ "decode_klass $dst,$src" %}
  ins_encode %{ __ decode_klass_not_null($dst$$Register, $src$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

// General decoder
instruct decodeN_NN(iRegP dst, iRegN src, flagsReg cr) %{
  match(Set dst (DecodeN src));
  effect(KILL cr);
  predicate((n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull ||
             n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) &&
            (CompressedOops::base()== NULL || !ExpandLoadingBaseDecode_NN));
  ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "decodeN  $dst,$src\t # (decode cOop NN)" %}
  ins_encode %{ __ oop_decoder($dst$$Register, $src$$Register, false); %}
  ins_pipe(pipe_class_dummy);
%}

  instruct loadBase(iRegL dst, immL baseImm) %{
    effect(DEF dst, USE baseImm);
    predicate(false);
    format %{ "llihl    $dst=$baseImm \t// load heap base" %}
    ins_encode %{ __ get_oop_base($dst$$Register, $baseImm$$constant); %}
    ins_pipe(pipe_class_dummy);
  %}

  // Decoder for heapbased mode peeling off loading the base.
  instruct decodeN_base(iRegP dst, iRegN src, iRegL base, flagsReg cr) %{
    match(Set dst (DecodeN src base));
    // Note: Effect TEMP dst was used with the intention to get
    // different regs for dst and base, but this has caused ADLC to
    // generate wrong code. Oop_decoder generates additional lgr when
    // dst==base.
    effect(KILL cr);
    predicate(false);
    // TODO: s390 port size(VARIABLE_SIZE);
    format %{ "decodeN  $dst = ($src == 0) ? NULL : ($src << 3) + $base + pow2_offset\t # (decode cOop)" %}
    ins_encode %{
      __ oop_decoder($dst$$Register, $src$$Register, true, $base$$Register,
                     (jlong)MacroAssembler::get_oop_base_pow2_offset((uint64_t)(intptr_t)CompressedOops::base()));
    %}
    ins_pipe(pipe_class_dummy);
  %}

  // Decoder for heapbased mode peeling off loading the base.
  instruct decodeN_NN_base(iRegP dst, iRegN src, iRegL base, flagsReg cr) %{
    match(Set dst (DecodeN src base));
    effect(KILL cr);
    predicate(false);
    // TODO: s390 port size(VARIABLE_SIZE);
    format %{ "decodeN  $dst = ($src << 3) + $base + pow2_offset\t # (decode cOop)" %}
    ins_encode %{
      __ oop_decoder($dst$$Register, $src$$Register, false, $base$$Register,
                     (jlong)MacroAssembler::get_oop_base_pow2_offset((uint64_t)(intptr_t)CompressedOops::base()));
    %}
    ins_pipe(pipe_class_dummy);
  %}

// Decoder for heapbased mode peeling off loading the base.
instruct decodeN_Ex(iRegP dst, iRegN src, flagsReg cr) %{
  match(Set dst (DecodeN src));
  predicate(CompressedOops::base() != NULL && ExpandLoadingBaseDecode);
  ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  expand %{
    immL baseImm %{ (jlong)(intptr_t)CompressedOops::base() %}
    iRegL base;
    loadBase(base, baseImm);
    decodeN_base(dst, src, base, cr);
  %}
%}

// Decoder for heapbased mode peeling off loading the base.
instruct decodeN_NN_Ex(iRegP dst, iRegN src, flagsReg cr) %{
  match(Set dst (DecodeN src));
  predicate((n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull ||
             n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) &&
            CompressedOops::base() != NULL && ExpandLoadingBaseDecode_NN);
  ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  expand %{
    immL baseImm %{ (jlong)(intptr_t)CompressedOops::base() %}
    iRegL base;
    loadBase(base, baseImm);
    decodeN_NN_base(dst, src, base, cr);
  %}
%}

//  Encode Compressed Pointer

// General encoder
instruct encodeP(iRegN dst, iRegP src, flagsReg cr) %{
  match(Set dst (EncodeP src));
  effect(KILL cr);
  predicate((n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull) &&
            (CompressedOops::base() == 0 ||
             CompressedOops::base_disjoint() ||
             !ExpandLoadingBaseEncode));
  ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "encodeP  $dst,$src\t # (encode cOop)" %}
  ins_encode %{ __ oop_encoder($dst$$Register, $src$$Register, true, Z_R1_scratch, -1, all_outs_are_Stores(this)); %}
  ins_pipe(pipe_class_dummy);
%}

// General class encoder
instruct encodeKlass(iRegN dst, iRegP src, flagsReg cr) %{
  match(Set dst (EncodePKlass src));
  effect(KILL cr);
  format %{ "encode_klass $dst,$src" %}
  ins_encode %{ __ encode_klass_not_null($dst$$Register, $src$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

instruct encodeP_NN(iRegN dst, iRegP src, flagsReg cr) %{
  match(Set dst (EncodeP src));
  effect(KILL cr);
  predicate((n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull) &&
            (CompressedOops::base() == 0 ||
             CompressedOops::base_disjoint() ||
             !ExpandLoadingBaseEncode_NN));
  ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "encodeP  $dst,$src\t # (encode cOop)" %}
  ins_encode %{ __ oop_encoder($dst$$Register, $src$$Register, false, Z_R1_scratch, -1, all_outs_are_Stores(this)); %}
  ins_pipe(pipe_class_dummy);
%}

  // Encoder for heapbased mode peeling off loading the base.
  instruct encodeP_base(iRegN dst, iRegP src, iRegL base) %{
    match(Set dst (EncodeP src (Binary base dst)));
    effect(TEMP_DEF dst);
    predicate(false);
    ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST);
    // TODO: s390 port size(VARIABLE_SIZE);
    format %{ "encodeP  $dst = ($src>>3) +$base + pow2_offset\t # (encode cOop)" %}
    ins_encode %{
      jlong offset = -(jlong)MacroAssembler::get_oop_base_pow2_offset
        (((uint64_t)(intptr_t)CompressedOops::base()) >> CompressedOops::shift());
      __ oop_encoder($dst$$Register, $src$$Register, true, $base$$Register, offset);
    %}
    ins_pipe(pipe_class_dummy);
  %}

  // Encoder for heapbased mode peeling off loading the base.
  instruct encodeP_NN_base(iRegN dst, iRegP src, iRegL base, immL pow2_offset) %{
    match(Set dst (EncodeP src base));
    effect(USE pow2_offset);
    predicate(false);
    ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST);
    // TODO: s390 port size(VARIABLE_SIZE);
    format %{ "encodeP  $dst = ($src>>3) +$base + $pow2_offset\t # (encode cOop)" %}
    ins_encode %{ __ oop_encoder($dst$$Register, $src$$Register, false, $base$$Register, $pow2_offset$$constant); %}
    ins_pipe(pipe_class_dummy);
  %}

// Encoder for heapbased mode peeling off loading the base.
instruct encodeP_Ex(iRegN dst, iRegP src, flagsReg cr) %{
  match(Set dst (EncodeP src));
  effect(KILL cr);
  predicate((n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull) &&
            (CompressedOops::base_overlaps() && ExpandLoadingBaseEncode));
  ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  expand %{
    immL baseImm %{ ((jlong)(intptr_t)CompressedOops::base()) >> CompressedOops::shift() %}
    immL_0 zero %{ (0) %}
    flagsReg ccr;
    iRegL base;
    iRegL negBase;
    loadBase(base, baseImm);
    negL_reg_reg(negBase, zero, base, ccr);
    encodeP_base(dst, src, negBase);
  %}
%}

// Encoder for heapbased mode peeling off loading the base.
instruct encodeP_NN_Ex(iRegN dst, iRegP src, flagsReg cr) %{
  match(Set dst (EncodeP src));
  effect(KILL cr);
  predicate((n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull) &&
            (CompressedOops::base_overlaps() && ExpandLoadingBaseEncode_NN));
  ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  expand %{
    immL baseImm %{ (jlong)(intptr_t)CompressedOops::base() %}
    immL pow2_offset %{ -(jlong)MacroAssembler::get_oop_base_pow2_offset(((uint64_t)(intptr_t)CompressedOops::base())) %}
    immL_0 zero %{ 0 %}
    flagsReg ccr;
    iRegL base;
    iRegL negBase;
    loadBase(base, baseImm);
    negL_reg_reg(negBase, zero, base, ccr);
    encodeP_NN_base(dst, src, negBase, pow2_offset);
  %}
%}

//  Store Compressed Pointer

// Store Compressed Pointer
instruct storeN(memory mem, iRegN_P2N src) %{
  match(Set mem (StoreN mem src));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "ST      $src,$mem\t # (cOop)" %}
  opcode(STY_ZOPC, ST_ZOPC);
  ins_encode(z_form_rt_mem_opt(src, mem));
  ins_pipe(pipe_class_dummy);
%}

// Store Compressed Klass pointer
instruct storeNKlass(memory mem, iRegN src) %{
  match(Set mem (StoreNKlass mem src));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP_SIZE);
  format %{ "ST      $src,$mem\t # (cKlass)" %}
  opcode(STY_ZOPC, ST_ZOPC);
  ins_encode(z_form_rt_mem_opt(src, mem));
  ins_pipe(pipe_class_dummy);
%}

// Compare Compressed Pointers

instruct compN_iRegN(iRegN_P2N src1, iRegN_P2N src2, flagsReg cr) %{
  match(Set cr (CmpN src1 src2));
  ins_cost(DEFAULT_COST);
  size(2);
  format %{ "CLR     $src1,$src2\t # (cOop)" %}
  opcode(CLR_ZOPC);
  ins_encode(z_rrform(src1, src2));
  ins_pipe(pipe_class_dummy);
%}

instruct compN_iRegN_immN(iRegN_P2N src1, immN src2, flagsReg cr) %{
  match(Set cr (CmpN src1 src2));
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "CLFI    $src1,$src2\t # (cOop) compare immediate narrow" %}
  ins_encode %{
    AddressLiteral cOop = __ constant_oop_address((jobject)$src2$$constant);
    __ relocate(cOop.rspec(), 1);
    __ compare_immediate_narrow_oop($src1$$Register, (narrowOop)cOop.value());
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct compNKlass_iRegN_immN(iRegN src1, immNKlass src2, flagsReg cr) %{
  match(Set cr (CmpN src1 src2));
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "CLFI    $src1,$src2\t # (NKlass) compare immediate narrow" %}
  ins_encode %{
    AddressLiteral NKlass = __ constant_metadata_address((Metadata*)$src2$$constant);
    __ relocate(NKlass.rspec(), 1);
    __ compare_immediate_narrow_klass($src1$$Register, (Klass*)NKlass.value());
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct compN_iRegN_immN0(iRegN_P2N src1, immN0 src2, flagsReg cr) %{
  match(Set cr (CmpN src1 src2));
  ins_cost(DEFAULT_COST);
  size(2);
  format %{ "LTR     $src1,$src2\t # (cOop) LTR because comparing against zero" %}
  opcode(LTR_ZOPC);
  ins_encode(z_rrform(src1, src1));
  ins_pipe(pipe_class_dummy);
%}


//----------MemBar Instructions-----------------------------------------------

// Memory barrier flavors

instruct membar_acquire() %{
  match(MemBarAcquire);
  match(LoadFence);
  ins_cost(4*MEMORY_REF_COST);
  size(0);
  format %{ "MEMBAR-acquire" %}
  ins_encode %{ __ z_acquire(); %}
  ins_pipe(pipe_class_dummy);
%}

instruct membar_acquire_lock() %{
  match(MemBarAcquireLock);
  ins_cost(0);
  size(0);
  format %{ "MEMBAR-acquire (CAS in prior FastLock so empty encoding)" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

instruct membar_release() %{
  match(MemBarRelease);
  match(StoreFence);
  ins_cost(4 * MEMORY_REF_COST);
  size(0);
  format %{ "MEMBAR-release" %}
  ins_encode %{ __ z_release(); %}
  ins_pipe(pipe_class_dummy);
%}

instruct membar_release_lock() %{
  match(MemBarReleaseLock);
  ins_cost(0);
  size(0);
  format %{ "MEMBAR-release (CAS in succeeding FastUnlock so empty encoding)" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

instruct membar_volatile() %{
  match(MemBarVolatile);
  ins_cost(4 * MEMORY_REF_COST);
  size(2);
  format %{ "MEMBAR-volatile" %}
  ins_encode %{ __ z_fence(); %}
  ins_pipe(pipe_class_dummy);
%}

instruct unnecessary_membar_volatile() %{
  match(MemBarVolatile);
  predicate(Matcher::post_store_load_barrier(n));
  ins_cost(0);
  size(0);
  format %{ "# MEMBAR-volatile (empty)" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

instruct membar_CPUOrder() %{
  match(MemBarCPUOrder);
  ins_cost(0);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "MEMBAR-CPUOrder (empty)" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

instruct membar_storestore() %{
  match(MemBarStoreStore);
  match(StoreStoreFence);
  ins_cost(0);
  size(0);
  format %{ "MEMBAR-storestore (empty)" %}
  ins_encode();
  ins_pipe(pipe_class_dummy);
%}


//----------Register Move Instructions-----------------------------------------
instruct roundDouble_nop(regD dst) %{
  match(Set dst (RoundDouble dst));
  ins_cost(0);
  // TODO: s390 port size(FIXED_SIZE);
  // z/Architecture results are already "rounded" (i.e., normal-format IEEE).
  ins_encode();
  ins_pipe(pipe_class_dummy);
%}

instruct roundFloat_nop(regF dst) %{
  match(Set dst (RoundFloat dst));
  ins_cost(0);
  // TODO: s390 port size(FIXED_SIZE);
  // z/Architecture results are already "rounded" (i.e., normal-format IEEE).
  ins_encode();
  ins_pipe(pipe_class_dummy);
%}

// Cast Long to Pointer for unsafe natives.
instruct castX2P(iRegP dst, iRegL src) %{
  match(Set dst (CastX2P src));
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "LGR     $dst,$src\t # CastX2P" %}
  ins_encode %{ __ lgr_if_needed($dst$$Register, $src$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

// Cast Pointer to Long for unsafe natives.
instruct castP2X(iRegL dst, iRegP_N2P src) %{
  match(Set dst (CastP2X src));
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "LGR     $dst,$src\t # CastP2X" %}
  ins_encode %{ __ lgr_if_needed($dst$$Register, $src$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

instruct stfSSD(stackSlotD stkSlot, regD src) %{
  // %%%% TODO: Tell the coalescer that this kind of node is a copy!
  match(Set stkSlot src);   // chain rule
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ " STD   $src,$stkSlot\t # stk" %}
  opcode(STD_ZOPC);
  ins_encode(z_form_rt_mem(src, stkSlot));
  ins_pipe(pipe_class_dummy);
%}

instruct stfSSF(stackSlotF stkSlot, regF src) %{
  // %%%% TODO: Tell the coalescer that this kind of node is a copy!
  match(Set stkSlot src);   // chain rule
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "STE   $src,$stkSlot\t # stk" %}
  opcode(STE_ZOPC);
  ins_encode(z_form_rt_mem(src, stkSlot));
  ins_pipe(pipe_class_dummy);
%}

//----------Conditional Move---------------------------------------------------

instruct cmovN_reg(cmpOp cmp, flagsReg cr, iRegN dst, iRegN_P2N src) %{
  match(Set dst (CMoveN (Binary cmp cr) (Binary dst src)));
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CMoveN,$cmp   $dst,$src" %}
  ins_encode(z_enc_cmov_reg(cmp,dst,src));
  ins_pipe(pipe_class_dummy);
%}

instruct cmovN_imm(cmpOp cmp, flagsReg cr, iRegN dst, immN0 src) %{
  match(Set dst (CMoveN (Binary cmp cr) (Binary dst src)));
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CMoveN,$cmp   $dst,$src" %}
  ins_encode(z_enc_cmov_imm(cmp,dst,src));
  ins_pipe(pipe_class_dummy);
%}

instruct cmovI_reg(cmpOp cmp, flagsReg cr, iRegI dst, iRegI src) %{
  match(Set dst (CMoveI (Binary cmp cr) (Binary dst src)));
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CMoveI,$cmp   $dst,$src" %}
  ins_encode(z_enc_cmov_reg(cmp,dst,src));
  ins_pipe(pipe_class_dummy);
%}

instruct cmovI_imm(cmpOp cmp, flagsReg cr, iRegI dst, immI16 src) %{
  match(Set dst (CMoveI (Binary cmp cr) (Binary dst src)));
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CMoveI,$cmp   $dst,$src" %}
  ins_encode(z_enc_cmov_imm(cmp,dst,src));
  ins_pipe(pipe_class_dummy);
%}

instruct cmovP_reg(cmpOp cmp, flagsReg cr, iRegP dst, iRegP_N2P src) %{
  match(Set dst (CMoveP (Binary cmp cr) (Binary dst src)));
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CMoveP,$cmp    $dst,$src" %}
  ins_encode(z_enc_cmov_reg(cmp,dst,src));
  ins_pipe(pipe_class_dummy);
%}

instruct cmovP_imm(cmpOp cmp, flagsReg cr, iRegP dst, immP0 src) %{
  match(Set dst (CMoveP (Binary cmp cr) (Binary dst src)));
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CMoveP,$cmp  $dst,$src" %}
  ins_encode(z_enc_cmov_imm(cmp,dst,src));
  ins_pipe(pipe_class_dummy);
%}

instruct cmovF_reg(cmpOpF cmp, flagsReg cr, regF dst, regF src) %{
  match(Set dst (CMoveF (Binary cmp cr) (Binary dst src)));
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CMoveF,$cmp   $dst,$src" %}
  ins_encode %{
    // Don't emit code if operands are identical (same register).
    if ($dst$$FloatRegister != $src$$FloatRegister) {
      Label done;
      __ z_brc(Assembler::inverse_float_condition((Assembler::branch_condition)$cmp$$cmpcode), done);
      __ z_ler($dst$$FloatRegister, $src$$FloatRegister);
      __ bind(done);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct cmovD_reg(cmpOpF cmp, flagsReg cr, regD dst, regD src) %{
  match(Set dst (CMoveD (Binary cmp cr) (Binary dst src)));
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CMoveD,$cmp   $dst,$src" %}
  ins_encode %{
    // Don't emit code if operands are identical (same register).
    if ($dst$$FloatRegister != $src$$FloatRegister) {
      Label done;
      __ z_brc(Assembler::inverse_float_condition((Assembler::branch_condition)$cmp$$cmpcode), done);
      __ z_ldr($dst$$FloatRegister, $src$$FloatRegister);
      __ bind(done);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct cmovL_reg(cmpOp cmp, flagsReg cr, iRegL dst, iRegL src) %{
  match(Set dst (CMoveL (Binary cmp cr) (Binary dst src)));
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CMoveL,$cmp  $dst,$src" %}
  ins_encode(z_enc_cmov_reg(cmp,dst,src));
  ins_pipe(pipe_class_dummy);
%}

instruct cmovL_imm(cmpOp cmp, flagsReg cr, iRegL dst, immL16 src) %{
  match(Set dst (CMoveL (Binary cmp cr) (Binary dst src)));
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CMoveL,$cmp  $dst,$src" %}
  ins_encode(z_enc_cmov_imm(cmp,dst,src));
  ins_pipe(pipe_class_dummy);
%}

//----------OS and Locking Instructions----------------------------------------

// This name is KNOWN by the ADLC and cannot be changed.
// The ADLC forces a 'TypeRawPtr::BOTTOM' output type
// for this guy.
instruct tlsLoadP(threadRegP dst) %{
  match(Set dst (ThreadLocal));
  ins_cost(0);
  size(0);
  ins_should_rematerialize(true);
  format %{ "# $dst=ThreadLocal" %}
  ins_encode(/* empty */);
  ins_pipe(pipe_class_dummy);
%}

instruct checkCastPP(iRegP dst) %{
  match(Set dst (CheckCastPP dst));
  size(0);
  format %{ "# checkcastPP of $dst" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

instruct castPP(iRegP dst) %{
  match(Set dst (CastPP dst));
  size(0);
  format %{ "# castPP of $dst" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

instruct castII(iRegI dst) %{
  match(Set dst (CastII dst));
  size(0);
  format %{ "# castII of $dst" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

instruct castLL(iRegL dst) %{
  match(Set dst (CastLL dst));
  size(0);
  format %{ "# castLL of $dst" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

instruct castFF(regF dst) %{
  match(Set dst (CastFF dst));
  size(0);
  format %{ "# castFF of $dst" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

instruct castDD(regD dst) %{
  match(Set dst (CastDD dst));
  size(0);
  format %{ "# castDD of $dst" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

instruct castVV(iRegL dst) %{
  match(Set dst (CastVV dst));
  size(0);
  format %{ "# castVV of $dst" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

// No flag versions for CompareAndSwap{P,I,L,N} because matcher can't match them.

instruct compareAndSwapI_bool(iRegP mem_ptr, rarg5RegI oldval, iRegI newval, iRegI res, flagsReg cr) %{
  match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval)));
  effect(USE mem_ptr, USE_KILL oldval, KILL cr);
  size(16);
  format %{ "$res = CompareAndSwapI $oldval,$newval,$mem_ptr" %}
  ins_encode(z_enc_casI(oldval, newval, mem_ptr),
             z_enc_cctobool(res));
  ins_pipe(pipe_class_dummy);
%}

instruct compareAndSwapL_bool(iRegP mem_ptr, rarg5RegL oldval, iRegL newval, iRegI res, flagsReg cr) %{
  match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval)));
  effect(USE mem_ptr, USE_KILL oldval, KILL cr);
  size(18);
  format %{ "$res = CompareAndSwapL $oldval,$newval,$mem_ptr" %}
  ins_encode(z_enc_casL(oldval, newval, mem_ptr),
             z_enc_cctobool(res));
  ins_pipe(pipe_class_dummy);
%}

instruct compareAndSwapP_bool(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, iRegI res, flagsReg cr) %{
  match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval)));
  effect(USE mem_ptr, USE_KILL oldval, KILL cr);
  size(18);
  format %{ "$res = CompareAndSwapP $oldval,$newval,$mem_ptr" %}
  ins_encode(z_enc_casL(oldval, newval, mem_ptr),
             z_enc_cctobool(res));
  ins_pipe(pipe_class_dummy);
%}

instruct compareAndSwapN_bool(iRegP mem_ptr, rarg5RegN oldval, iRegN_P2N newval, iRegI res, flagsReg cr) %{
  match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval)));
  effect(USE mem_ptr, USE_KILL oldval, KILL cr);
  size(16);
  format %{ "$res = CompareAndSwapN $oldval,$newval,$mem_ptr" %}
  ins_encode(z_enc_casI(oldval, newval, mem_ptr),
             z_enc_cctobool(res));
  ins_pipe(pipe_class_dummy);
%}

//----------Atomic operations on memory (GetAndSet*, GetAndAdd*)---------------

// Exploit: direct memory arithmetic
// Prereqs: - instructions available
//          - instructions guarantee atomicity
//          - immediate operand to be added
//          - immediate operand is small enough (8-bit signed).
//          - result of instruction is not used
instruct addI_mem_imm8_atomic_no_res(memoryRSY mem, Universe dummy, immI8 src, flagsReg cr) %{
  match(Set dummy (GetAndAddI mem src));
  effect(KILL cr);
  predicate(VM_Version::has_AtomicMemWithImmALUOps() && n->as_LoadStore()->result_not_used());
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "ASI     [$mem],$src\t # GetAndAddI (atomic)" %}
  opcode(ASI_ZOPC);
  ins_encode(z_siyform(mem, src));
  ins_pipe(pipe_class_dummy);
%}

// Fallback: direct memory arithmetic not available
// Disadvantages: - CS-Loop required, very expensive.
//                - more code generated (26 to xx bytes vs. 6 bytes)
instruct addI_mem_imm16_atomic(memoryRSY mem, iRegI dst, immI16 src, iRegI tmp, flagsReg cr) %{
  match(Set dst (GetAndAddI mem src));
  effect(KILL cr, TEMP_DEF dst, TEMP tmp);
  ins_cost(MEMORY_REF_COST+100*DEFAULT_COST);
  format %{ "BEGIN ATOMIC {\n\t"
            "  LGF     $dst,[$mem]\n\t"
            "  AHIK    $tmp,$dst,$src\n\t"
            "  CSY     $dst,$tmp,$mem\n\t"
            "  retry if failed\n\t"
            "} END ATOMIC"
         %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rtmp = $tmp$$Register;
    int      Isrc = $src$$constant;
    Label    retry;

    // Iterate until update with incremented value succeeds.
    __ z_lgf(Rdst, $mem$$Address);    // current contents
    __ bind(retry);
      // Calculate incremented value.
      if (VM_Version::has_DistinctOpnds()) {
        __ z_ahik(Rtmp, Rdst, Isrc);
      } else {
        __ z_lr(Rtmp, Rdst);
        __ z_ahi(Rtmp, Isrc);
      }
      // Swap into memory location.
      __ z_csy(Rdst, Rtmp, $mem$$Address); // Try to store new value.
    __ z_brne(retry);                      // Yikes, concurrent update, need to retry.
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct addI_mem_imm32_atomic(memoryRSY mem, iRegI dst, immI src, iRegI tmp, flagsReg cr) %{
  match(Set dst (GetAndAddI mem src));
  effect(KILL cr, TEMP_DEF dst, TEMP tmp);
  ins_cost(MEMORY_REF_COST+200*DEFAULT_COST);
  format %{ "BEGIN ATOMIC {\n\t"
            "  LGF     $dst,[$mem]\n\t"
            "  LGR     $tmp,$dst\n\t"
            "  AFI     $tmp,$src\n\t"
            "  CSY     $dst,$tmp,$mem\n\t"
            "  retry if failed\n\t"
            "} END ATOMIC"
         %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rtmp = $tmp$$Register;
    int      Isrc = $src$$constant;
    Label    retry;

    // Iterate until update with incremented value succeeds.
    __ z_lgf(Rdst, $mem$$Address);    // current contents
    __ bind(retry);
      // Calculate incremented value.
      __ z_lr(Rtmp, Rdst);
      __ z_afi(Rtmp, Isrc);
      // Swap into memory location.
      __ z_csy(Rdst, Rtmp, $mem$$Address); // Try to store new value.
    __ z_brne(retry);                      // Yikes, concurrent update, need to retry.
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct addI_mem_reg_atomic(memoryRSY mem, iRegI dst, iRegI src, iRegI tmp, flagsReg cr) %{
  match(Set dst (GetAndAddI mem src));
  effect(KILL cr, TEMP_DEF dst, TEMP tmp);
  ins_cost(MEMORY_REF_COST+100*DEFAULT_COST);
  format %{ "BEGIN ATOMIC {\n\t"
            "  LGF     $dst,[$mem]\n\t"
            "  ARK     $tmp,$dst,$src\n\t"
            "  CSY     $dst,$tmp,$mem\n\t"
            "  retry if failed\n\t"
            "} END ATOMIC"
         %}
  ins_encode %{
    Register Rsrc = $src$$Register;
    Register Rdst = $dst$$Register;
    Register Rtmp = $tmp$$Register;
    Label    retry;

    // Iterate until update with incremented value succeeds.
    __ z_lgf(Rdst, $mem$$Address);  // current contents
    __ bind(retry);
      // Calculate incremented value.
      if (VM_Version::has_DistinctOpnds()) {
        __ z_ark(Rtmp, Rdst, Rsrc);
      } else {
        __ z_lr(Rtmp, Rdst);
        __ z_ar(Rtmp, Rsrc);
      }
      __ z_csy(Rdst, Rtmp, $mem$$Address); // Try to store new value.
    __ z_brne(retry);                      // Yikes, concurrent update, need to retry.
  %}
  ins_pipe(pipe_class_dummy);
%}


// Exploit: direct memory arithmetic
// Prereqs: - instructions available
//          - instructions guarantee atomicity
//          - immediate operand to be added
//          - immediate operand is small enough (8-bit signed).
//          - result of instruction is not used
instruct addL_mem_imm8_atomic_no_res(memoryRSY mem, Universe dummy, immL8 src, flagsReg cr) %{
  match(Set dummy (GetAndAddL mem src));
  effect(KILL cr);
  predicate(VM_Version::has_AtomicMemWithImmALUOps() && n->as_LoadStore()->result_not_used());
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "AGSI    [$mem],$src\t # GetAndAddL (atomic)" %}
  opcode(AGSI_ZOPC);
  ins_encode(z_siyform(mem, src));
  ins_pipe(pipe_class_dummy);
%}

// Fallback: direct memory arithmetic not available
// Disadvantages: - CS-Loop required, very expensive.
//                - more code generated (26 to xx bytes vs. 6 bytes)
instruct addL_mem_imm16_atomic(memoryRSY mem, iRegL dst, immL16 src, iRegL tmp, flagsReg cr) %{
  match(Set dst (GetAndAddL mem src));
  effect(KILL cr, TEMP_DEF dst, TEMP tmp);
  ins_cost(MEMORY_REF_COST+100*DEFAULT_COST);
  format %{ "BEGIN ATOMIC {\n\t"
            "  LG      $dst,[$mem]\n\t"
            "  AGHIK   $tmp,$dst,$src\n\t"
            "  CSG     $dst,$tmp,$mem\n\t"
            "  retry if failed\n\t"
            "} END ATOMIC"
         %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rtmp = $tmp$$Register;
    int      Isrc = $src$$constant;
    Label    retry;

    // Iterate until update with incremented value succeeds.
    __ z_lg(Rdst, $mem$$Address);  // current contents
    __ bind(retry);
      // Calculate incremented value.
      if (VM_Version::has_DistinctOpnds()) {
        __ z_aghik(Rtmp, Rdst, Isrc);
      } else {
        __ z_lgr(Rtmp, Rdst);
        __ z_aghi(Rtmp, Isrc);
      }
      __ z_csg(Rdst, Rtmp, $mem$$Address); // Try to store new value.
    __ z_brne(retry);                      // Yikes, concurrent update, need to retry.
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct addL_mem_imm32_atomic(memoryRSY mem, iRegL dst, immL32 src, iRegL tmp, flagsReg cr) %{
  match(Set dst (GetAndAddL mem src));
  effect(KILL cr, TEMP_DEF dst, TEMP tmp);
  ins_cost(MEMORY_REF_COST+100*DEFAULT_COST);
  format %{ "BEGIN ATOMIC {\n\t"
            "  LG      $dst,[$mem]\n\t"
            "  LGR     $tmp,$dst\n\t"
            "  AGFI    $tmp,$src\n\t"
            "  CSG     $dst,$tmp,$mem\n\t"
            "  retry if failed\n\t"
            "} END ATOMIC"
         %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rtmp = $tmp$$Register;
    int      Isrc = $src$$constant;
    Label    retry;

    // Iterate until update with incremented value succeeds.
    __ z_lg(Rdst, $mem$$Address);  // current contents
    __ bind(retry);
      // Calculate incremented value.
      __ z_lgr(Rtmp, Rdst);
      __ z_agfi(Rtmp, Isrc);
      __ z_csg(Rdst, Rtmp, $mem$$Address); // Try to store new value.
    __ z_brne(retry);                      // Yikes, concurrent update, need to retry.
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct addL_mem_reg_atomic(memoryRSY mem, iRegL dst, iRegL src, iRegL tmp, flagsReg cr) %{
  match(Set dst (GetAndAddL mem src));
  effect(KILL cr, TEMP_DEF dst, TEMP tmp);
  ins_cost(MEMORY_REF_COST+100*DEFAULT_COST);
  format %{ "BEGIN ATOMIC {\n\t"
            "  LG      $dst,[$mem]\n\t"
            "  AGRK    $tmp,$dst,$src\n\t"
            "  CSG     $dst,$tmp,$mem\n\t"
            "  retry if failed\n\t"
            "} END ATOMIC"
         %}
  ins_encode %{
    Register Rsrc = $src$$Register;
    Register Rdst = $dst$$Register;
    Register Rtmp = $tmp$$Register;
    Label    retry;

    // Iterate until update with incremented value succeeds.
    __ z_lg(Rdst, $mem$$Address);  // current contents
    __ bind(retry);
      // Calculate incremented value.
      if (VM_Version::has_DistinctOpnds()) {
        __ z_agrk(Rtmp, Rdst, Rsrc);
      } else {
        __ z_lgr(Rtmp, Rdst);
        __ z_agr(Rtmp, Rsrc);
      }
      __ z_csg(Rdst, Rtmp, $mem$$Address); // Try to store new value.
    __ z_brne(retry);                      // Yikes, concurrent update, need to retry.
  %}
  ins_pipe(pipe_class_dummy);
%}

// Increment value in memory, save old value in dst.
instruct addI_mem_reg_atomic_z196(memoryRSY mem, iRegI dst, iRegI src) %{
  match(Set dst (GetAndAddI mem src));
  predicate(VM_Version::has_LoadAndALUAtomicV1());
  ins_cost(MEMORY_REF_COST + DEFAULT_COST);
  size(6);
  format %{ "LAA     $dst,$src,[$mem]" %}
  ins_encode %{ __ z_laa($dst$$Register, $src$$Register, $mem$$Address); %}
  ins_pipe(pipe_class_dummy);
%}

// Increment value in memory, save old value in dst.
instruct addL_mem_reg_atomic_z196(memoryRSY mem, iRegL dst, iRegL src) %{
  match(Set dst (GetAndAddL mem src));
  predicate(VM_Version::has_LoadAndALUAtomicV1());
  ins_cost(MEMORY_REF_COST + DEFAULT_COST);
  size(6);
  format %{ "LAAG    $dst,$src,[$mem]" %}
  ins_encode %{ __ z_laag($dst$$Register, $src$$Register, $mem$$Address); %}
  ins_pipe(pipe_class_dummy);
%}


instruct xchgI_reg_mem(memoryRSY mem, iRegI dst, iRegI tmp, flagsReg cr) %{
  match(Set dst (GetAndSetI mem dst));
  effect(KILL cr, TEMP tmp); // USE_DEF dst by match rule.
  format %{ "XCHGI   $dst,[$mem]\t # EXCHANGE (int, atomic), temp $tmp" %}
  ins_encode(z_enc_SwapI(mem, dst, tmp));
  ins_pipe(pipe_class_dummy);
%}

instruct xchgL_reg_mem(memoryRSY mem, iRegL dst, iRegL tmp, flagsReg cr) %{
  match(Set dst (GetAndSetL mem dst));
  effect(KILL cr, TEMP tmp); // USE_DEF dst by match rule.
  format %{ "XCHGL   $dst,[$mem]\t # EXCHANGE (long, atomic), temp $tmp" %}
  ins_encode(z_enc_SwapL(mem, dst, tmp));
  ins_pipe(pipe_class_dummy);
%}

instruct xchgN_reg_mem(memoryRSY mem, iRegN dst, iRegI tmp, flagsReg cr) %{
  match(Set dst (GetAndSetN mem dst));
  effect(KILL cr, TEMP tmp); // USE_DEF dst by match rule.
  format %{ "XCHGN   $dst,[$mem]\t # EXCHANGE (coop, atomic), temp $tmp" %}
  ins_encode(z_enc_SwapI(mem, dst, tmp));
  ins_pipe(pipe_class_dummy);
%}

instruct xchgP_reg_mem(memoryRSY mem, iRegP dst, iRegL tmp, flagsReg cr) %{
  match(Set dst (GetAndSetP mem dst));
  effect(KILL cr, TEMP tmp); // USE_DEF dst by match rule.
  format %{ "XCHGP   $dst,[$mem]\t # EXCHANGE (oop, atomic), temp $tmp" %}
  ins_encode(z_enc_SwapL(mem, dst, tmp));
  ins_pipe(pipe_class_dummy);
%}


//----------Arithmetic Instructions--------------------------------------------

// The rules are sorted by right operand type and operand length. Please keep
// it that way.
// Left operand type is always reg. Left operand len is I, L, P
// Right operand type is reg, imm, mem. Right operand len is S, I, L, P
// Special instruction formats, e.g. multi-operand, are inserted at the end.

// ADD

// REG = REG + REG

// Register Addition
instruct addI_reg_reg_CISC(iRegI dst, iRegI src, flagsReg cr) %{
  match(Set dst (AddI dst src));
  effect(KILL cr);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "AR      $dst,$src\t # int  CISC ALU" %}
  opcode(AR_ZOPC);
  ins_encode(z_rrform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Avoid use of LA(Y) for general ALU operation.
instruct addI_reg_reg_RISC(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
  match(Set dst (AddI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_DistinctOpnds());
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "ARK     $dst,$src1,$src2\t # int  RISC ALU" %}
  opcode(ARK_ZOPC);
  ins_encode(z_rrfform(dst, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

// REG = REG + IMM

// Avoid use of LA(Y) for general ALU operation.
// Immediate Addition
instruct addI_reg_imm16_CISC(iRegI dst, immI16 con, flagsReg cr) %{
  match(Set dst (AddI dst con));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "AHI     $dst,$con\t # int  CISC ALU" %}
  opcode(AHI_ZOPC);
  ins_encode(z_riform_signed(dst, con));
  ins_pipe(pipe_class_dummy);
%}

// Avoid use of LA(Y) for general ALU operation.
// Immediate Addition
instruct addI_reg_imm16_RISC(iRegI dst, iRegI src, immI16 con, flagsReg cr) %{
  match(Set dst (AddI src con));
  effect(KILL cr);
  predicate( VM_Version::has_DistinctOpnds());
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "AHIK    $dst,$src,$con\t # int  RISC ALU" %}
  opcode(AHIK_ZOPC);
  ins_encode(z_rieform_d(dst, src, con));
  ins_pipe(pipe_class_dummy);
%}

// Immediate Addition
instruct addI_reg_imm32(iRegI dst, immI src, flagsReg cr) %{
  match(Set dst (AddI dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_HIGH);
  size(6);
  format %{ "AFI     $dst,$src" %}
  opcode(AFI_ZOPC);
  ins_encode(z_rilform_signed(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Immediate Addition
instruct addI_reg_imm12(iRegI dst, iRegI src, uimmI12 con) %{
  match(Set dst (AddI src con));
  predicate(PreferLAoverADD);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LA      $dst,$con(,$src)\t # int d12(,b)" %}
  opcode(LA_ZOPC);
  ins_encode(z_rxform_imm_reg(dst, con, src));
  ins_pipe(pipe_class_dummy);
%}

// Immediate Addition
instruct addI_reg_imm20(iRegI dst, iRegI src, immI20 con) %{
  match(Set dst (AddI src con));
  predicate(PreferLAoverADD);
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "LAY     $dst,$con(,$src)\t # int d20(,b)" %}
  opcode(LAY_ZOPC);
  ins_encode(z_rxyform_imm_reg(dst, con, src));
  ins_pipe(pipe_class_dummy);
%}

instruct addI_reg_reg_imm12(iRegI dst, iRegI src1, iRegI src2, uimmI12 con) %{
  match(Set dst (AddI (AddI src1 src2) con));
  predicate( PreferLAoverADD);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LA      $dst,$con($src1,$src2)\t # int d12(x,b)" %}
  opcode(LA_ZOPC);
  ins_encode(z_rxform_imm_reg_reg(dst, con, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

instruct addI_reg_reg_imm20(iRegI dst, iRegI src1, iRegI src2, immI20 con) %{
  match(Set dst (AddI (AddI src1 src2) con));
  predicate(PreferLAoverADD);
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "LAY     $dst,$con($src1,$src2)\t # int d20(x,b)" %}
  opcode(LAY_ZOPC);
  ins_encode(z_rxyform_imm_reg_reg(dst, con, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

// REG = REG + MEM

instruct addI_Reg_mem(iRegI dst, memory src, flagsReg cr)%{
  match(Set dst (AddI dst (LoadI src)));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "A(Y)    $dst, $src\t # int" %}
  opcode(AY_ZOPC, A_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// MEM = MEM + IMM

// Add Immediate to 4-byte memory operand and result
instruct addI_mem_imm(memoryRSY mem, immI8 src, flagsReg cr) %{
  match(Set mem (StoreI mem (AddI (LoadI mem) src)));
  effect(KILL cr);
  predicate(VM_Version::has_MemWithImmALUOps());
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "ASI     $mem,$src\t # direct mem add 4" %}
  opcode(ASI_ZOPC);
  ins_encode(z_siyform(mem, src));
  ins_pipe(pipe_class_dummy);
%}


//

// REG = REG + REG

instruct addL_reg_regI(iRegL dst, iRegI src, flagsReg cr) %{
  match(Set dst (AddL dst (ConvI2L src)));
  effect(KILL cr);
  size(4);
  format %{ "AGFR    $dst,$src\t # long<-int CISC ALU" %}
  opcode(AGFR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct addL_reg_reg_CISC(iRegL dst, iRegL src, flagsReg cr) %{
  match(Set dst (AddL dst src));
  effect(KILL cr);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "AGR     $dst, $src\t # long CISC ALU" %}
  opcode(AGR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Avoid use of LA(Y) for general ALU operation.
instruct addL_reg_reg_RISC(iRegL dst, iRegL src1, iRegL src2, flagsReg cr) %{
  match(Set dst (AddL src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_DistinctOpnds());
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "AGRK    $dst,$src1,$src2\t # long RISC ALU" %}
  opcode(AGRK_ZOPC);
  ins_encode(z_rrfform(dst, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

// REG = REG + IMM

instruct addL_reg_imm12(iRegL dst, iRegL src, uimmL12 con) %{
  match(Set dst (AddL src con));
  predicate( PreferLAoverADD);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LA      $dst,$con(,$src)\t # long d12(,b)" %}
  opcode(LA_ZOPC);
  ins_encode(z_rxform_imm_reg(dst, con, src));
  ins_pipe(pipe_class_dummy);
%}

instruct addL_reg_imm20(iRegL dst, iRegL src, immL20 con) %{
  match(Set dst (AddL src con));
  predicate(PreferLAoverADD);
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "LAY     $dst,$con(,$src)\t # long d20(,b)" %}
  opcode(LAY_ZOPC);
  ins_encode(z_rxyform_imm_reg(dst, con, src));
  ins_pipe(pipe_class_dummy);
%}

instruct addL_reg_imm32(iRegL dst, immL32 con, flagsReg cr) %{
  match(Set dst (AddL dst con));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_HIGH);
  size(6);
  format %{ "AGFI    $dst,$con\t # long CISC ALU" %}
  opcode(AGFI_ZOPC);
  ins_encode(z_rilform_signed(dst, con));
  ins_pipe(pipe_class_dummy);
%}

// Avoid use of LA(Y) for general ALU operation.
instruct addL_reg_imm16_CISC(iRegL dst, immL16 con, flagsReg cr) %{
  match(Set dst (AddL dst con));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "AGHI    $dst,$con\t # long CISC ALU" %}
  opcode(AGHI_ZOPC);
  ins_encode(z_riform_signed(dst, con));
  ins_pipe(pipe_class_dummy);
%}

// Avoid use of LA(Y) for general ALU operation.
instruct addL_reg_imm16_RISC(iRegL dst, iRegL src, immL16 con, flagsReg cr) %{
  match(Set dst (AddL src con));
  effect(KILL cr);
  predicate( VM_Version::has_DistinctOpnds());
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "AGHIK   $dst,$src,$con\t # long RISC ALU" %}
  opcode(AGHIK_ZOPC);
  ins_encode(z_rieform_d(dst, src, con));
  ins_pipe(pipe_class_dummy);
%}

// REG = REG + MEM

instruct addL_Reg_memI(iRegL dst, memory src, flagsReg cr)%{
  match(Set dst (AddL dst (ConvI2L (LoadI src))));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "AGF     $dst, $src\t # long/int" %}
  opcode(AGF_ZOPC, AGF_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct addL_Reg_mem(iRegL dst, memory src, flagsReg cr)%{
  match(Set dst (AddL dst (LoadL src)));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "AG      $dst, $src\t # long" %}
  opcode(AG_ZOPC, AG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct addL_reg_reg_imm12(iRegL dst, iRegL src1, iRegL src2, uimmL12 con) %{
  match(Set dst (AddL (AddL src1 src2) con));
  predicate( PreferLAoverADD);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LA     $dst,$con($src1,$src2)\t # long d12(x,b)" %}
  opcode(LA_ZOPC);
  ins_encode(z_rxform_imm_reg_reg(dst, con, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

instruct addL_reg_reg_imm20(iRegL dst, iRegL src1, iRegL src2, immL20 con) %{
  match(Set dst (AddL (AddL src1 src2) con));
  predicate(PreferLAoverADD);
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "LAY    $dst,$con($src1,$src2)\t # long d20(x,b)" %}
  opcode(LAY_ZOPC);
  ins_encode(z_rxyform_imm_reg_reg(dst, con, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

// MEM = MEM + IMM

// Add Immediate to 8-byte memory operand and result.
instruct addL_mem_imm(memoryRSY mem, immL8 src, flagsReg cr) %{
  match(Set mem (StoreL mem (AddL (LoadL mem) src)));
  effect(KILL cr);
  predicate(VM_Version::has_MemWithImmALUOps());
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "AGSI    $mem,$src\t # direct mem add 8" %}
  opcode(AGSI_ZOPC);
  ins_encode(z_siyform(mem, src));
  ins_pipe(pipe_class_dummy);
%}


// REG = REG + REG

// Ptr Addition
instruct addP_reg_reg_LA(iRegP dst, iRegP_N2P src1, iRegL src2) %{
  match(Set dst (AddP src1 src2));
  predicate( PreferLAoverADD);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "LA      $dst,#0($src1,$src2)\t # ptr 0(x,b)" %}
  opcode(LA_ZOPC);
  ins_encode(z_rxform_imm_reg_reg(dst, 0x0, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

// Ptr Addition
// Avoid use of LA(Y) for general ALU operation.
instruct addP_reg_reg_CISC(iRegP dst, iRegL src, flagsReg cr) %{
  match(Set dst (AddP dst src));
  effect(KILL cr);
  predicate(!PreferLAoverADD && !VM_Version::has_DistinctOpnds());
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "ALGR    $dst,$src\t # ptr CICS ALU" %}
  opcode(ALGR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Ptr Addition
// Avoid use of LA(Y) for general ALU operation.
instruct addP_reg_reg_RISC(iRegP dst, iRegP_N2P src1, iRegL src2, flagsReg cr) %{
  match(Set dst (AddP src1 src2));
  effect(KILL cr);
  predicate(!PreferLAoverADD && VM_Version::has_DistinctOpnds());
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "ALGRK   $dst,$src1,$src2\t # ptr RISC ALU" %}
  opcode(ALGRK_ZOPC);
  ins_encode(z_rrfform(dst, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

// REG = REG + IMM

instruct addP_reg_imm12(iRegP dst, iRegP_N2P src, uimmL12 con) %{
  match(Set dst (AddP src con));
  predicate( PreferLAoverADD);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LA      $dst,$con(,$src)\t # ptr d12(,b)" %}
  opcode(LA_ZOPC);
  ins_encode(z_rxform_imm_reg(dst, con, src));
  ins_pipe(pipe_class_dummy);
%}

// Avoid use of LA(Y) for general ALU operation.
instruct addP_reg_imm16_CISC(iRegP dst, immL16 src, flagsReg cr) %{
  match(Set dst (AddP dst src));
  effect(KILL cr);
  predicate(!PreferLAoverADD && !VM_Version::has_DistinctOpnds());
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "AGHI    $dst,$src\t # ptr CISC ALU" %}
  opcode(AGHI_ZOPC);
  ins_encode(z_riform_signed(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Avoid use of LA(Y) for general ALU operation.
instruct addP_reg_imm16_RISC(iRegP dst, iRegP_N2P src, immL16 con, flagsReg cr) %{
  match(Set dst (AddP src con));
  effect(KILL cr);
  predicate(!PreferLAoverADD && VM_Version::has_DistinctOpnds());
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "ALGHSIK $dst,$src,$con\t # ptr RISC ALU" %}
  opcode(ALGHSIK_ZOPC);
  ins_encode(z_rieform_d(dst, src, con));
  ins_pipe(pipe_class_dummy);
%}

instruct addP_reg_imm20(iRegP dst, memoryRegP src, immL20 con) %{
  match(Set dst (AddP src con));
  predicate(PreferLAoverADD);
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "LAY     $dst,$con(,$src)\t # ptr d20(,b)" %}
  opcode(LAY_ZOPC);
  ins_encode(z_rxyform_imm_reg(dst, con, src));
  ins_pipe(pipe_class_dummy);
%}

// Pointer Immediate Addition
instruct addP_reg_imm32(iRegP dst, immL32 src, flagsReg cr) %{
  match(Set dst (AddP dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_HIGH);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "AGFI    $dst,$src\t # ptr" %}
  opcode(AGFI_ZOPC);
  ins_encode(z_rilform_signed(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// REG = REG1 + REG2 + IMM

instruct addP_reg_reg_imm12(iRegP dst, memoryRegP src1, iRegL src2, uimmL12 con) %{
  match(Set dst (AddP (AddP src1 src2) con));
  predicate( PreferLAoverADD);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LA      $dst,$con($src1,$src2)\t # ptr d12(x,b)" %}
  opcode(LA_ZOPC);
  ins_encode(z_rxform_imm_reg_reg(dst, con, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

instruct addP_regN_reg_imm12(iRegP dst, iRegP_N2P src1, iRegL src2, uimmL12 con) %{
  match(Set dst (AddP (AddP src1 src2) con));
  predicate( PreferLAoverADD && CompressedOops::base() == NULL && CompressedOops::shift() == 0);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LA      $dst,$con($src1,$src2)\t # ptr d12(x,b)" %}
  opcode(LA_ZOPC);
  ins_encode(z_rxform_imm_reg_reg(dst, con, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

instruct addP_reg_reg_imm20(iRegP dst, memoryRegP src1, iRegL src2, immL20 con) %{
  match(Set dst (AddP (AddP src1 src2) con));
  predicate(PreferLAoverADD);
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LAY     $dst,$con($src1,$src2)\t # ptr d20(x,b)" %}
  opcode(LAY_ZOPC);
  ins_encode(z_rxyform_imm_reg_reg(dst, con, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

instruct addP_regN_reg_imm20(iRegP dst, iRegP_N2P src1, iRegL src2, immL20 con) %{
  match(Set dst (AddP (AddP src1 src2) con));
  predicate( PreferLAoverADD && CompressedOops::base() == NULL && CompressedOops::shift() == 0);
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LAY     $dst,$con($src1,$src2)\t # ptr d20(x,b)" %}
  opcode(LAY_ZOPC);
  ins_encode(z_rxyform_imm_reg_reg(dst, con, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

// MEM = MEM + IMM

// Add Immediate to 8-byte memory operand and result
instruct addP_mem_imm(memoryRSY mem, immL8 src, flagsReg cr) %{
  match(Set mem (StoreP mem (AddP (LoadP mem) src)));
  effect(KILL cr);
  predicate(VM_Version::has_MemWithImmALUOps());
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "AGSI    $mem,$src\t # direct mem add 8 (ptr)" %}
  opcode(AGSI_ZOPC);
  ins_encode(z_siyform(mem, src));
  ins_pipe(pipe_class_dummy);
%}

// SUB

// Register Subtraction
instruct subI_reg_reg_CISC(iRegI dst, iRegI src, flagsReg cr) %{
  match(Set dst (SubI dst src));
  effect(KILL cr);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "SR      $dst,$src\t # int  CISC ALU" %}
  opcode(SR_ZOPC);
  ins_encode(z_rrform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct subI_reg_reg_RISC(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
  match(Set dst (SubI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_DistinctOpnds());
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "SRK     $dst,$src1,$src2\t # int  RISC ALU" %}
  opcode(SRK_ZOPC);
  ins_encode(z_rrfform(dst, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

instruct subI_Reg_mem(iRegI dst, memory src, flagsReg cr)%{
  match(Set dst (SubI dst (LoadI src)));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "S(Y)    $dst, $src\t # int" %}
  opcode(SY_ZOPC, S_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct subI_zero_reg(iRegI dst, immI_0 zero, iRegI src, flagsReg cr) %{
  match(Set dst (SubI zero src));
  effect(KILL cr);
  size(2);
  format %{ "NEG     $dst, $src" %}
  ins_encode %{ __ z_lcr($dst$$Register, $src$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

//

// Long subtraction
instruct subL_reg_reg_CISC(iRegL dst, iRegL src, flagsReg cr) %{
  match(Set dst (SubL dst src));
  effect(KILL cr);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "SGR     $dst,$src\t # int  CISC ALU" %}
  opcode(SGR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Avoid use of LA(Y) for general ALU operation.
instruct subL_reg_reg_RISC(iRegL dst, iRegL src1, iRegL src2, flagsReg cr) %{
  match(Set dst (SubL src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_DistinctOpnds());
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "SGRK    $dst,$src1,$src2\t # int  RISC ALU" %}
  opcode(SGRK_ZOPC);
  ins_encode(z_rrfform(dst, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

instruct subL_reg_regI_CISC(iRegL dst, iRegI src, flagsReg cr) %{
  match(Set dst (SubL dst (ConvI2L src)));
  effect(KILL cr);
  size(4);
  format %{ "SGFR    $dst, $src\t # int  CISC ALU" %}
  opcode(SGFR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct subL_Reg_memI(iRegL dst, memory src, flagsReg cr)%{
  match(Set dst (SubL dst (ConvI2L (LoadI src))));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "SGF     $dst, $src\t # long/int" %}
  opcode(SGF_ZOPC, SGF_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct subL_Reg_mem(iRegL dst, memory src, flagsReg cr)%{
  match(Set dst (SubL dst (LoadL src)));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "SG      $dst, $src\t # long" %}
  opcode(SG_ZOPC, SG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Moved declaration of negL_reg_reg before encode nodes, where it is used.

//  MUL

// Register Multiplication
instruct mulI_reg_reg(iRegI dst, iRegI src) %{
  match(Set dst (MulI dst src));
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "MSR     $dst, $src" %}
  opcode(MSR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Immediate Multiplication
instruct mulI_reg_imm16(iRegI dst, immI16 con) %{
  match(Set dst (MulI dst con));
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "MHI     $dst,$con" %}
  opcode(MHI_ZOPC);
  ins_encode(z_riform_signed(dst,con));
  ins_pipe(pipe_class_dummy);
%}

// Immediate (32bit) Multiplication
instruct mulI_reg_imm32(iRegI dst, immI con) %{
  match(Set dst (MulI dst con));
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "MSFI    $dst,$con" %}
  opcode(MSFI_ZOPC);
  ins_encode(z_rilform_signed(dst,con));
  ins_pipe(pipe_class_dummy);
%}

instruct mulI_Reg_mem(iRegI dst, memory src)%{
  match(Set dst (MulI dst (LoadI src)));
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MS(Y)   $dst, $src\t # int" %}
  opcode(MSY_ZOPC, MS_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

//

instruct mulL_reg_regI(iRegL dst, iRegI src) %{
  match(Set dst (MulL dst (ConvI2L src)));
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "MSGFR   $dst $src\t # long/int" %}
  opcode(MSGFR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct mulL_reg_reg(iRegL dst, iRegL src) %{
  match(Set dst (MulL dst src));
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "MSGR    $dst $src\t # long" %}
  opcode(MSGR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Immediate Multiplication
instruct mulL_reg_imm16(iRegL dst, immL16 src) %{
  match(Set dst (MulL dst src));
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "MGHI    $dst,$src\t # long" %}
  opcode(MGHI_ZOPC);
  ins_encode(z_riform_signed(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Immediate (32bit) Multiplication
instruct mulL_reg_imm32(iRegL dst, immL32 con) %{
  match(Set dst (MulL dst con));
  ins_cost(DEFAULT_COST);
  size(6);
  format %{ "MSGFI   $dst,$con" %}
  opcode(MSGFI_ZOPC);
  ins_encode(z_rilform_signed(dst,con));
  ins_pipe(pipe_class_dummy);
%}

instruct mulL_Reg_memI(iRegL dst, memory src)%{
  match(Set dst (MulL dst (ConvI2L (LoadI src))));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "MSGF    $dst, $src\t # long" %}
  opcode(MSGF_ZOPC, MSGF_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct mulL_Reg_mem(iRegL dst, memory src)%{
  match(Set dst (MulL dst (LoadL src)));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "MSG     $dst, $src\t # long" %}
  opcode(MSG_ZOPC, MSG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct mulHiL_reg_reg(revenRegL Rdst, roddRegL Rsrc1, iRegL Rsrc2, iRegL Rtmp1, flagsReg cr)%{
  match(Set Rdst (MulHiL Rsrc1 Rsrc2));
  effect(TEMP_DEF Rdst, USE_KILL Rsrc1, TEMP Rtmp1, KILL cr);
  ins_cost(7*DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MulHiL  $Rdst, $Rsrc1, $Rsrc2\t # Multiply High Long" %}
  ins_encode%{
    Register dst  = $Rdst$$Register;
    Register src1 = $Rsrc1$$Register;
    Register src2 = $Rsrc2$$Register;
    Register tmp1 = $Rtmp1$$Register;
    Register tmp2 = $Rdst$$Register;
    // z/Architecture has only unsigned multiply (64 * 64 -> 128).
    // implementing mulhs(a,b) = mulhu(a,b) – (a & (b>>63)) – (b & (a>>63))
    __ z_srag(tmp2, src1, 63);  // a>>63
    __ z_srag(tmp1, src2, 63);  // b>>63
    __ z_ngr(tmp2, src2);       // b & (a>>63)
    __ z_ngr(tmp1, src1);       // a & (b>>63)
    __ z_agr(tmp1, tmp2);       // ((a & (b>>63)) + (b & (a>>63)))
    __ z_mlgr(dst, src2);       // tricky: 128-bit product is written to even/odd pair (dst,src1),
                                //         multiplicand is taken from oddReg (src1), multiplier in src2.
    __ z_sgr(dst, tmp1);
  %}
  ins_pipe(pipe_class_dummy);
%}

//  DIV

// Integer DIVMOD with Register, both quotient and mod results
instruct divModI_reg_divmod(roddRegI dst1src1, revenRegI dst2, noOdd_iRegI src2, flagsReg cr) %{
  match(DivModI dst1src1 src2);
  effect(KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  size((VM_Version::has_CompareBranch() ? 24 : 26));
  format %{ "DIVMODI ($dst1src1, $dst2) $src2" %}
  ins_encode %{
    Register d1s1 = $dst1src1$$Register;
    Register d2   = $dst2$$Register;
    Register s2   = $src2$$Register;

    assert_different_registers(d1s1, s2);

    Label do_div, done_div;
    if (VM_Version::has_CompareBranch()) {
      __ z_cij(s2, -1, Assembler::bcondNotEqual, do_div);
    } else {
      __ z_chi(s2, -1);
      __ z_brne(do_div);
    }
    __ z_lcr(d1s1, d1s1);
    __ clear_reg(d2, false, false);
    __ z_bru(done_div);
    __ bind(do_div);
    __ z_lgfr(d1s1, d1s1);
    __ z_dsgfr(d2, s2);
    __ bind(done_div);
  %}
  ins_pipe(pipe_class_dummy);
%}


// Register Division
instruct divI_reg_reg(roddRegI dst, iRegI src1, noOdd_iRegI src2, revenRegI tmp, flagsReg cr) %{
  match(Set dst (DivI src1 src2));
  effect(KILL tmp, KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  size((VM_Version::has_CompareBranch() ? 20 : 22));
  format %{ "DIV_checked $dst, $src1,$src2\t # treats special case 0x80../-1" %}
  ins_encode %{
    Register a = $src1$$Register;
    Register b = $src2$$Register;
    Register t = $dst$$Register;

    assert_different_registers(t, b);

    Label do_div, done_div;
    if (VM_Version::has_CompareBranch()) {
      __ z_cij(b, -1, Assembler::bcondNotEqual, do_div);
    } else {
      __ z_chi(b, -1);
      __ z_brne(do_div);
    }
    __ z_lcr(t, a);
    __ z_bru(done_div);
    __ bind(do_div);
    __ z_lgfr(t, a);
    __ z_dsgfr(t->predecessor()/* t is odd part of a register pair. */, b);
    __ bind(done_div);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Immediate Division
instruct divI_reg_imm16(roddRegI dst, iRegI src1, immI16 src2, revenRegI tmp, flagsReg cr) %{
  match(Set dst (DivI src1 src2));
  effect(KILL tmp, KILL cr);  // R0 is killed, too.
  ins_cost(2 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "DIV_const  $dst,$src1,$src2" %}
  ins_encode %{
    // No sign extension of Rdividend needed here.
    if ($src2$$constant != -1) {
      __ z_lghi(Z_R0_scratch, $src2$$constant);
      __ z_lgfr($dst$$Register, $src1$$Register);
      __ z_dsgfr($dst$$Register->predecessor()/* Dst is odd part of a register pair. */, Z_R0_scratch);
    } else {
      __ z_lcr($dst$$Register, $src1$$Register);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// Long DIVMOD with Register, both quotient and mod results
instruct divModL_reg_divmod(roddRegL dst1src1, revenRegL dst2, iRegL src2, flagsReg cr) %{
  match(DivModL dst1src1 src2);
  effect(KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  size((VM_Version::has_CompareBranch() ? 22 : 24));
  format %{ "DIVMODL ($dst1src1, $dst2) $src2" %}
  ins_encode %{
    Register d1s1 = $dst1src1$$Register;
    Register d2   = $dst2$$Register;
    Register s2   = $src2$$Register;

    Label do_div, done_div;
    if (VM_Version::has_CompareBranch()) {
      __ z_cgij(s2, -1, Assembler::bcondNotEqual, do_div);
    } else {
      __ z_cghi(s2, -1);
      __ z_brne(do_div);
    }
    __ z_lcgr(d1s1, d1s1);
    // indicate unused result
    (void) __ clear_reg(d2, true, false);
    __ z_bru(done_div);
    __ bind(do_div);
    __ z_dsgr(d2, s2);
    __ bind(done_div);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Register Long Division
instruct divL_reg_reg(roddRegL dst, iRegL src, revenRegL tmp, flagsReg cr) %{
  match(Set dst (DivL dst src));
  effect(KILL tmp, KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  size((VM_Version::has_CompareBranch() ? 18 : 20));
  format %{ "DIVG_checked  $dst, $src\t # long, treats special case 0x80../-1" %}
  ins_encode %{
    Register b = $src$$Register;
    Register t = $dst$$Register;

    Label done_div;
    __ z_lcgr(t, t);    // Does no harm. divisor is in other register.
    if (VM_Version::has_CompareBranch()) {
      __ z_cgij(b, -1, Assembler::bcondEqual, done_div);
    } else {
      __ z_cghi(b, -1);
      __ z_bre(done_div);
    }
    __ z_lcgr(t, t);    // Restore sign.
    __ z_dsgr(t->predecessor()/* t is odd part of a register pair. */, b);
    __ bind(done_div);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Immediate Long Division
instruct divL_reg_imm16(roddRegL dst, iRegL src1, immL16 src2, revenRegL tmp, flagsReg cr) %{
  match(Set dst (DivL src1 src2));
  effect(KILL tmp, KILL cr);  // R0 is killed, too.
  ins_cost(2 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "DIVG_const  $dst,$src1,$src2\t # long" %}
  ins_encode %{
    if ($src2$$constant != -1) {
      __ z_lghi(Z_R0_scratch, $src2$$constant);
      __ lgr_if_needed($dst$$Register, $src1$$Register);
      __ z_dsgr($dst$$Register->predecessor()/* Dst is odd part of a register pair. */, Z_R0_scratch);
    } else {
      __ z_lcgr($dst$$Register, $src1$$Register);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// REM

// Integer Remainder
// Register Remainder
instruct modI_reg_reg(revenRegI dst, iRegI src1, noOdd_iRegI src2, roddRegI tmp, flagsReg cr) %{
  match(Set dst (ModI src1 src2));
  effect(KILL tmp, KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MOD_checked   $dst,$src1,$src2" %}
  ins_encode %{
    Register a = $src1$$Register;
    Register b = $src2$$Register;
    Register t = $dst$$Register;
    assert_different_registers(t->successor(), b);

    Label do_div, done_div;

    if ((t->encoding() != b->encoding()) && (t->encoding() != a->encoding())) {
      (void) __ clear_reg(t, true, false);  // Does no harm. Operands are in other regs.
      if (VM_Version::has_CompareBranch()) {
        __ z_cij(b, -1, Assembler::bcondEqual, done_div);
      } else {
        __ z_chi(b, -1);
        __ z_bre(done_div);
      }
      __ z_lgfr(t->successor(), a);
      __ z_dsgfr(t/* t is even part of a register pair. */, b);
    } else {
      if (VM_Version::has_CompareBranch()) {
        __ z_cij(b, -1, Assembler::bcondNotEqual, do_div);
      } else {
        __ z_chi(b, -1);
        __ z_brne(do_div);
      }
      __ clear_reg(t, true, false);
      __ z_bru(done_div);
      __ bind(do_div);
      __ z_lgfr(t->successor(), a);
      __ z_dsgfr(t/* t is even part of a register pair. */, b);
    }
    __ bind(done_div);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Immediate Remainder
instruct modI_reg_imm16(revenRegI dst, iRegI src1, immI16 src2, roddRegI tmp, flagsReg cr) %{
  match(Set dst (ModI src1 src2));
  effect(KILL tmp, KILL cr); // R0 is killed, too.
  ins_cost(3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MOD_const  $dst,src1,$src2" %}
  ins_encode %{
    assert_different_registers($dst$$Register, $src1$$Register);
    assert_different_registers($dst$$Register->successor(), $src1$$Register);
    int divisor = $src2$$constant;

    if (divisor != -1) {
      __ z_lghi(Z_R0_scratch, divisor);
      __ z_lgfr($dst$$Register->successor(), $src1$$Register);
      __ z_dsgfr($dst$$Register/* Dst is even part of a register pair. */, Z_R0_scratch); // Instruction kills tmp.
    } else {
      __ clear_reg($dst$$Register, true, false);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// Register Long Remainder
instruct modL_reg_reg(revenRegL dst, roddRegL src1, iRegL src2, flagsReg cr) %{
  match(Set dst (ModL src1 src2));
  effect(KILL src1, KILL cr); // R0 is killed, too.
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MODG_checked   $dst,$src1,$src2" %}
  ins_encode %{
    Register a = $src1$$Register;
    Register b = $src2$$Register;
    Register t = $dst$$Register;
    assert(t->successor() == a, "(t,a) is an even-odd pair" );

    Label do_div, done_div;
    if (t->encoding() != b->encoding()) {
      (void) __ clear_reg(t, true, false); // Does no harm. Dividend is in successor.
      if (VM_Version::has_CompareBranch()) {
        __ z_cgij(b, -1, Assembler::bcondEqual, done_div);
      } else {
        __ z_cghi(b, -1);
        __ z_bre(done_div);
      }
      __ z_dsgr(t, b);
    } else {
      if (VM_Version::has_CompareBranch()) {
        __ z_cgij(b, -1, Assembler::bcondNotEqual, do_div);
      } else {
        __ z_cghi(b, -1);
        __ z_brne(do_div);
      }
      __ clear_reg(t, true, false);
      __ z_bru(done_div);
      __ bind(do_div);
      __ z_dsgr(t, b);
    }
    __ bind(done_div);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Register Long Remainder
instruct modL_reg_imm16(revenRegL dst, iRegL src1, immL16 src2, roddRegL tmp, flagsReg cr) %{
  match(Set dst (ModL src1 src2));
  effect(KILL tmp, KILL cr); // R0 is killed, too.
  ins_cost(3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MODG_const  $dst,src1,$src2\t # long" %}
  ins_encode %{
    int divisor = $src2$$constant;
    if (divisor != -1) {
      __ z_lghi(Z_R0_scratch, divisor);
      __ z_lgr($dst$$Register->successor(), $src1$$Register);
      __ z_dsgr($dst$$Register /* Dst is even part of a register pair. */, Z_R0_scratch);  // Instruction kills tmp.
    } else {
      __ clear_reg($dst$$Register, true, false);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// SHIFT

// Shift left logical

// Register Shift Left variable
instruct sllI_reg_reg(iRegI dst, iRegI src, iRegI nbits, flagsReg cr) %{
  match(Set dst (LShiftI src nbits));
  effect(KILL cr); // R1 is killed, too.
  ins_cost(3 * DEFAULT_COST);
  size(14);
  format %{ "SLL     $dst,$src,[$nbits] & 31\t # use RISC-like SLLG also for int" %}
  ins_encode %{
    __ z_lgr(Z_R1_scratch, $nbits$$Register);
    __ z_nill(Z_R1_scratch, BitsPerJavaInteger-1);
    __ z_sllg($dst$$Register, $src$$Register, 0, Z_R1_scratch);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Register Shift Left Immediate
// Constant shift count is masked in ideal graph already.
instruct sllI_reg_imm(iRegI dst, iRegI src, immI nbits) %{
  match(Set dst (LShiftI src nbits));
  size(6);
  format %{ "SLL     $dst,$src,$nbits\t # use RISC-like SLLG also for int" %}
  ins_encode %{
    int Nbit = $nbits$$constant;
    assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
    __ z_sllg($dst$$Register, $src$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Register Shift Left Immediate by 1bit
instruct sllI_reg_imm_1(iRegI dst, iRegI src, immI_1 nbits) %{
  match(Set dst (LShiftI src nbits));
  predicate(PreferLAoverADD);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LA      $dst,#0($src,$src)\t # SLL by 1 (int)" %}
  ins_encode %{ __ z_la($dst$$Register, 0, $src$$Register, $src$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

// Register Shift Left Long
instruct sllL_reg_reg(iRegL dst, iRegL src1, iRegI nbits) %{
  match(Set dst (LShiftL src1 nbits));
  size(6);
  format %{ "SLLG    $dst,$src1,[$nbits]" %}
  opcode(SLLG_ZOPC);
  ins_encode(z_rsyform_reg_reg(dst, src1, nbits));
  ins_pipe(pipe_class_dummy);
%}

// Register Shift Left Long Immediate
instruct sllL_reg_imm(iRegL dst, iRegL src1, immI nbits) %{
  match(Set dst (LShiftL src1 nbits));
  size(6);
  format %{ "SLLG    $dst,$src1,$nbits" %}
  opcode(SLLG_ZOPC);
  ins_encode(z_rsyform_const(dst, src1, nbits));
  ins_pipe(pipe_class_dummy);
%}

// Register Shift Left Long Immediate by 1bit
instruct sllL_reg_imm_1(iRegL dst, iRegL src1, immI_1 nbits) %{
  match(Set dst (LShiftL src1 nbits));
  predicate(PreferLAoverADD);
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LA      $dst,#0($src1,$src1)\t # SLLG by 1 (long)" %}
  ins_encode %{ __ z_la($dst$$Register, 0, $src1$$Register, $src1$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

// Shift right arithmetic

// Register Arithmetic Shift Right
instruct sraI_reg_reg(iRegI dst, iRegI src, flagsReg cr) %{
  match(Set dst (RShiftI dst src));
  effect(KILL cr); // R1 is killed, too.
  ins_cost(3 * DEFAULT_COST);
  size(12);
  format %{ "SRA     $dst,[$src] & 31" %}
  ins_encode %{
    __ z_lgr(Z_R1_scratch, $src$$Register);
    __ z_nill(Z_R1_scratch, BitsPerJavaInteger-1);
    __ z_sra($dst$$Register, 0, Z_R1_scratch);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Register Arithmetic Shift Right Immediate
// Constant shift count is masked in ideal graph already.
instruct sraI_reg_imm(iRegI dst, immI src, flagsReg cr) %{
  match(Set dst (RShiftI dst src));
  effect(KILL cr);
  size(4);
  format %{ "SRA     $dst,$src" %}
  ins_encode %{
    int Nbit = $src$$constant;
    assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
    __ z_sra($dst$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Register Arithmetic Shift Right Long
instruct sraL_reg_reg(iRegL dst, iRegL src1, iRegI src2, flagsReg cr) %{
  match(Set dst (RShiftL src1 src2));
  effect(KILL cr);
  size(6);
  format %{ "SRAG    $dst,$src1,[$src2]" %}
  opcode(SRAG_ZOPC);
  ins_encode(z_rsyform_reg_reg(dst, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

// Register Arithmetic Shift Right Long Immediate
instruct sraL_reg_imm(iRegL dst, iRegL src1, immI src2, flagsReg cr) %{
  match(Set dst (RShiftL src1 src2));
  effect(KILL cr);
  size(6);
  format %{ "SRAG    $dst,$src1,$src2" %}
  opcode(SRAG_ZOPC);
  ins_encode(z_rsyform_const(dst, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

//  Shift right logical

// Register Shift Right
instruct srlI_reg_reg(iRegI dst, iRegI src, flagsReg cr) %{
  match(Set dst (URShiftI dst src));
  effect(KILL cr); // R1 is killed, too.
  ins_cost(3 * DEFAULT_COST);
  size(12);
  format %{ "SRL     $dst,[$src] & 31" %}
  ins_encode %{
    __ z_lgr(Z_R1_scratch, $src$$Register);
    __ z_nill(Z_R1_scratch, BitsPerJavaInteger-1);
    __ z_srl($dst$$Register, 0, Z_R1_scratch);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Register Shift Right Immediate
// Constant shift count is masked in ideal graph already.
instruct srlI_reg_imm(iRegI dst, immI src) %{
  match(Set dst (URShiftI dst src));
  size(4);
  format %{ "SRL     $dst,$src" %}
  ins_encode %{
    int Nbit = $src$$constant;
    assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
    __ z_srl($dst$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Register Shift Right Long
instruct srlL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
  match(Set dst (URShiftL src1 src2));
  size(6);
  format %{ "SRLG    $dst,$src1,[$src2]" %}
  opcode(SRLG_ZOPC);
  ins_encode(z_rsyform_reg_reg(dst, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

// Register Shift Right Long Immediate
instruct srlL_reg_imm(iRegL dst, iRegL src1, immI src2) %{
  match(Set dst (URShiftL src1 src2));
  size(6);
  format %{ "SRLG    $dst,$src1,$src2" %}
  opcode(SRLG_ZOPC);
  ins_encode(z_rsyform_const(dst, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

// Register Shift Right Immediate with a CastP2X
instruct srlP_reg_imm(iRegL dst, iRegP_N2P src1, immI src2) %{
  match(Set dst (URShiftL (CastP2X src1) src2));
  size(6);
  format %{ "SRLG    $dst,$src1,$src2\t # Cast ptr $src1 to long and shift" %}
  opcode(SRLG_ZOPC);
  ins_encode(z_rsyform_const(dst, src1, src2));
  ins_pipe(pipe_class_dummy);
%}

//----------Rotate Instructions------------------------------------------------

// Rotate left 32bit.
instruct rotlI_reg_immI8(iRegI dst, iRegI src, immI8 lshift, immI8 rshift) %{
  match(Set dst (OrI (LShiftI src lshift) (URShiftI src rshift)));
  predicate(0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & 0x1f));
  size(6);
  format %{ "RLL     $dst,$src,$lshift\t # ROTL32" %}
  opcode(RLL_ZOPC);
  ins_encode(z_rsyform_const(dst, src, lshift));
  ins_pipe(pipe_class_dummy);
%}

// Rotate left 64bit.
instruct rotlL_reg_immI8(iRegL dst, iRegL src, immI8 lshift, immI8 rshift) %{
  match(Set dst (OrL (LShiftL src lshift) (URShiftL src rshift)));
  predicate(0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & 0x3f));
  size(6);
  format %{ "RLLG    $dst,$src,$lshift\t # ROTL64" %}
  opcode(RLLG_ZOPC);
  ins_encode(z_rsyform_const(dst, src, lshift));
  ins_pipe(pipe_class_dummy);
%}

// Rotate right 32bit.
instruct rotrI_reg_immI8(iRegI dst, iRegI src, immI8 rshift, immI8 lshift) %{
  match(Set dst (OrI (URShiftI src rshift) (LShiftI src lshift)));
  predicate(0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & 0x1f));
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "RLL     $dst,$src,$rshift\t # ROTR32" %}
  opcode(RLL_ZOPC);
  ins_encode(z_rsyform_const(dst, src, rshift));
  ins_pipe(pipe_class_dummy);
%}

// Rotate right 64bit.
instruct rotrL_reg_immI8(iRegL dst, iRegL src, immI8 rshift, immI8 lshift) %{
  match(Set dst (OrL (URShiftL src rshift) (LShiftL src lshift)));
  predicate(0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & 0x3f));
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "RLLG    $dst,$src,$rshift\t # ROTR64" %}
  opcode(RLLG_ZOPC);
  ins_encode(z_rsyform_const(dst, src, rshift));
  ins_pipe(pipe_class_dummy);
%}


//----------Overflow Math Instructions-----------------------------------------

instruct overflowAddI_reg_reg(flagsReg cr, iRegI op1, iRegI op2) %{
  match(Set cr (OverflowAddI op1 op2));
  effect(DEF cr, USE op1, USE op2);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "AR      $op1,$op2\t # overflow check int" %}
  ins_encode %{
    __ z_lr(Z_R0_scratch, $op1$$Register);
    __ z_ar(Z_R0_scratch, $op2$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct overflowAddI_reg_imm(flagsReg cr, iRegI op1, immI op2) %{
  match(Set cr (OverflowAddI op1 op2));
  effect(DEF cr, USE op1, USE op2);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "AR      $op1,$op2\t # overflow check int" %}
  ins_encode %{
    __ load_const_optimized(Z_R0_scratch, $op2$$constant);
    __ z_ar(Z_R0_scratch, $op1$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct overflowAddL_reg_reg(flagsReg cr, iRegL op1, iRegL op2) %{
  match(Set cr (OverflowAddL op1 op2));
  effect(DEF cr, USE op1, USE op2);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "AGR     $op1,$op2\t # overflow check long" %}
  ins_encode %{
    __ z_lgr(Z_R0_scratch, $op1$$Register);
    __ z_agr(Z_R0_scratch, $op2$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct overflowAddL_reg_imm(flagsReg cr, iRegL op1, immL op2) %{
  match(Set cr (OverflowAddL op1 op2));
  effect(DEF cr, USE op1, USE op2);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "AGR     $op1,$op2\t # overflow check long" %}
  ins_encode %{
    __ load_const_optimized(Z_R0_scratch, $op2$$constant);
    __ z_agr(Z_R0_scratch, $op1$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct overflowSubI_reg_reg(flagsReg cr, iRegI op1, iRegI op2) %{
  match(Set cr (OverflowSubI op1 op2));
  effect(DEF cr, USE op1, USE op2);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "SR      $op1,$op2\t # overflow check int" %}
  ins_encode %{
    __ z_lr(Z_R0_scratch, $op1$$Register);
    __ z_sr(Z_R0_scratch, $op2$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct overflowSubI_reg_imm(flagsReg cr, iRegI op1, immI op2) %{
  match(Set cr (OverflowSubI op1 op2));
  effect(DEF cr, USE op1, USE op2);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "SR      $op1,$op2\t # overflow check int" %}
  ins_encode %{
    __ load_const_optimized(Z_R1_scratch, $op2$$constant);
    __ z_lr(Z_R0_scratch, $op1$$Register);
    __ z_sr(Z_R0_scratch, Z_R1_scratch);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct overflowSubL_reg_reg(flagsReg cr, iRegL op1, iRegL op2) %{
  match(Set cr (OverflowSubL op1 op2));
  effect(DEF cr, USE op1, USE op2);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "SGR     $op1,$op2\t # overflow check long" %}
  ins_encode %{
    __ z_lgr(Z_R0_scratch, $op1$$Register);
    __ z_sgr(Z_R0_scratch, $op2$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct overflowSubL_reg_imm(flagsReg cr, iRegL op1, immL op2) %{
  match(Set cr (OverflowSubL op1 op2));
  effect(DEF cr, USE op1, USE op2);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "SGR     $op1,$op2\t # overflow check long" %}
  ins_encode %{
    __ load_const_optimized(Z_R1_scratch, $op2$$constant);
    __ z_lgr(Z_R0_scratch, $op1$$Register);
    __ z_sgr(Z_R0_scratch, Z_R1_scratch);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct overflowNegI_rReg(flagsReg cr, immI_0 zero, iRegI op2) %{
  match(Set cr (OverflowSubI zero op2));
  effect(DEF cr, USE op2);
  format %{ "NEG    $op2\t # overflow check int" %}
  ins_encode %{
    __ clear_reg(Z_R0_scratch, false, false);
    __ z_sr(Z_R0_scratch, $op2$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct overflowNegL_rReg(flagsReg cr, immL_0 zero, iRegL op2) %{
  match(Set cr (OverflowSubL zero op2));
  effect(DEF cr, USE op2);
  format %{ "NEGG    $op2\t # overflow check long" %}
  ins_encode %{
    __ clear_reg(Z_R0_scratch, true, false);
    __ z_sgr(Z_R0_scratch, $op2$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

// No intrinsics for multiplication, since there is no easy way
// to check for overflow.


//----------Floating Point Arithmetic Instructions-----------------------------

//  ADD

//  Add float single precision
instruct addF_reg_reg(regF dst, regF src, flagsReg cr) %{
  match(Set dst (AddF dst src));
  effect(KILL cr);
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "AEBR     $dst,$src" %}
  opcode(AEBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct addF_reg_mem(regF dst, memoryRX src, flagsReg cr)%{
  match(Set dst (AddF dst (LoadF src)));
  effect(KILL cr);
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "AEB      $dst,$src\t # floatMemory" %}
  opcode(AEB_ZOPC);
  ins_encode(z_form_rt_memFP(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Add float double precision
instruct addD_reg_reg(regD dst, regD src, flagsReg cr) %{
  match(Set dst (AddD dst src));
  effect(KILL cr);
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "ADBR     $dst,$src" %}
  opcode(ADBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct addD_reg_mem(regD dst, memoryRX src, flagsReg cr)%{
  match(Set dst (AddD dst (LoadD src)));
  effect(KILL cr);
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "ADB      $dst,$src\t # doubleMemory" %}
  opcode(ADB_ZOPC);
  ins_encode(z_form_rt_memFP(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// SUB

// Sub float single precision
instruct subF_reg_reg(regF dst, regF src, flagsReg cr) %{
  match(Set dst (SubF dst src));
  effect(KILL cr);
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "SEBR     $dst,$src" %}
  opcode(SEBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct subF_reg_mem(regF dst, memoryRX src, flagsReg cr)%{
  match(Set dst (SubF dst (LoadF src)));
  effect(KILL cr);
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "SEB      $dst,$src\t # floatMemory" %}
  opcode(SEB_ZOPC);
  ins_encode(z_form_rt_memFP(dst, src));
  ins_pipe(pipe_class_dummy);
%}

//  Sub float double precision
instruct subD_reg_reg(regD dst, regD src, flagsReg cr) %{
  match(Set dst (SubD dst src));
  effect(KILL cr);
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "SDBR     $dst,$src" %}
  opcode(SDBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct subD_reg_mem(regD dst, memoryRX src, flagsReg cr)%{
  match(Set dst (SubD dst (LoadD src)));
  effect(KILL cr);
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "SDB      $dst,$src\t # doubleMemory" %}
  opcode(SDB_ZOPC);
  ins_encode(z_form_rt_memFP(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// MUL

// Mul float single precision
instruct mulF_reg_reg(regF dst, regF src) %{
  match(Set dst (MulF dst src));
  // CC unchanged by MUL.
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "MEEBR    $dst,$src" %}
  opcode(MEEBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct mulF_reg_mem(regF dst, memoryRX src)%{
  match(Set dst (MulF dst (LoadF src)));
  // CC unchanged by MUL.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "MEEB     $dst,$src\t # floatMemory" %}
  opcode(MEEB_ZOPC);
  ins_encode(z_form_rt_memFP(dst, src));
  ins_pipe(pipe_class_dummy);
%}

//  Mul float double precision
instruct mulD_reg_reg(regD dst, regD src) %{
  match(Set dst (MulD dst src));
  // CC unchanged by MUL.
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "MDBR     $dst,$src" %}
  opcode(MDBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct mulD_reg_mem(regD dst, memoryRX src)%{
  match(Set dst (MulD dst (LoadD src)));
  // CC unchanged by MUL.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "MDB      $dst,$src\t # doubleMemory" %}
  opcode(MDB_ZOPC);
  ins_encode(z_form_rt_memFP(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Multiply-Accumulate
// src1 * src2 + dst
instruct maddF_reg_reg(regF dst, regF src1, regF src2) %{
  match(Set dst (FmaF dst (Binary src1 src2)));
  // CC unchanged by MUL-ADD.
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "MAEBR    $dst, $src1, $src2" %}
  ins_encode %{
    __ z_maebr($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_class_dummy);
%}

// src1 * src2 + dst
instruct maddD_reg_reg(regD dst, regD src1, regD src2) %{
  match(Set dst (FmaD dst (Binary src1 src2)));
  // CC unchanged by MUL-ADD.
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "MADBR    $dst, $src1, $src2" %}
  ins_encode %{
    __ z_madbr($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_class_dummy);
%}

// src1 * src2 - dst
instruct msubF_reg_reg(regF dst, regF src1, regF src2) %{
  match(Set dst (FmaF (NegF dst) (Binary src1 src2)));
  // CC unchanged by MUL-SUB.
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "MSEBR    $dst, $src1, $src2" %}
  ins_encode %{
    __ z_msebr($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_class_dummy);
%}

// src1 * src2 - dst
instruct msubD_reg_reg(regD dst, regD src1, regD src2) %{
  match(Set dst (FmaD (NegD dst) (Binary src1 src2)));
  // CC unchanged by MUL-SUB.
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "MSDBR    $dst, $src1, $src2" %}
  ins_encode %{
    __ z_msdbr($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_class_dummy);
%}

// src1 * src2 + dst
instruct maddF_reg_mem(regF dst, regF src1, memoryRX src2) %{
  match(Set dst (FmaF dst (Binary src1 (LoadF src2))));
  // CC unchanged by MUL-ADD.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "MAEB     $dst, $src1, $src2" %}
  ins_encode %{
    __ z_maeb($dst$$FloatRegister, $src1$$FloatRegister,
              Address(reg_to_register_object($src2$$base), $src2$$index$$Register, $src2$$disp));
  %}
  ins_pipe(pipe_class_dummy);
%}

// src1 * src2 + dst
instruct maddD_reg_mem(regD dst, regD src1, memoryRX src2) %{
  match(Set dst (FmaD dst (Binary src1 (LoadD src2))));
  // CC unchanged by MUL-ADD.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "MADB     $dst, $src1, $src2" %}
  ins_encode %{
    __ z_madb($dst$$FloatRegister, $src1$$FloatRegister,
              Address(reg_to_register_object($src2$$base), $src2$$index$$Register, $src2$$disp));
  %}
  ins_pipe(pipe_class_dummy);
%}

// src1 * src2 - dst
instruct msubF_reg_mem(regF dst, regF src1, memoryRX src2) %{
  match(Set dst (FmaF (NegF dst) (Binary src1 (LoadF src2))));
  // CC unchanged by MUL-SUB.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "MSEB     $dst, $src1, $src2" %}
  ins_encode %{
    __ z_mseb($dst$$FloatRegister, $src1$$FloatRegister,
              Address(reg_to_register_object($src2$$base), $src2$$index$$Register, $src2$$disp));
  %}
  ins_pipe(pipe_class_dummy);
%}

// src1 * src2 - dst
instruct msubD_reg_mem(regD dst, regD src1, memoryRX src2) %{
  match(Set dst (FmaD (NegD dst) (Binary src1 (LoadD src2))));
  // CC unchanged by MUL-SUB.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "MSDB    $dst, $src1, $src2" %}
  ins_encode %{
    __ z_msdb($dst$$FloatRegister, $src1$$FloatRegister,
              Address(reg_to_register_object($src2$$base), $src2$$index$$Register, $src2$$disp));
  %}
  ins_pipe(pipe_class_dummy);
%}

// src1 * src2 + dst
instruct maddF_mem_reg(regF dst, memoryRX src1, regF src2) %{
  match(Set dst (FmaF dst (Binary (LoadF src1) src2)));
  // CC unchanged by MUL-ADD.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "MAEB     $dst, $src1, $src2" %}
  ins_encode %{
    __ z_maeb($dst$$FloatRegister, $src2$$FloatRegister,
              Address(reg_to_register_object($src1$$base), $src1$$index$$Register, $src1$$disp));
  %}
  ins_pipe(pipe_class_dummy);
%}

// src1 * src2 + dst
instruct maddD_mem_reg(regD dst, memoryRX src1, regD src2) %{
  match(Set dst (FmaD dst (Binary (LoadD src1) src2)));
  // CC unchanged by MUL-ADD.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "MADB     $dst, $src1, $src2" %}
  ins_encode %{
    __ z_madb($dst$$FloatRegister, $src2$$FloatRegister,
              Address(reg_to_register_object($src1$$base), $src1$$index$$Register, $src1$$disp));
  %}
  ins_pipe(pipe_class_dummy);
%}

// src1 * src2 - dst
instruct msubF_mem_reg(regF dst, memoryRX src1, regF src2) %{
  match(Set dst (FmaF (NegF dst) (Binary (LoadF src1) src2)));
  // CC unchanged by MUL-SUB.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "MSEB     $dst, $src1, $src2" %}
  ins_encode %{
    __ z_mseb($dst$$FloatRegister, $src2$$FloatRegister,
              Address(reg_to_register_object($src1$$base), $src1$$index$$Register, $src1$$disp));
  %}
  ins_pipe(pipe_class_dummy);
%}

// src1 * src2 - dst
instruct msubD_mem_reg(regD dst, memoryRX src1, regD src2) %{
  match(Set dst (FmaD (NegD dst) (Binary (LoadD src1) src2)));
  // CC unchanged by MUL-SUB.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "MSDB    $dst, $src1, $src2" %}
  ins_encode %{
    __ z_msdb($dst$$FloatRegister, $src2$$FloatRegister,
              Address(reg_to_register_object($src1$$base), $src1$$index$$Register, $src1$$disp));
  %}
  ins_pipe(pipe_class_dummy);
%}

//  DIV

//  Div float single precision
instruct divF_reg_reg(regF dst, regF src) %{
  match(Set dst (DivF dst src));
  // CC unchanged by DIV.
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "DEBR     $dst,$src" %}
  opcode(DEBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct divF_reg_mem(regF dst, memoryRX src)%{
  match(Set dst (DivF dst (LoadF src)));
  // CC unchanged by DIV.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "DEB      $dst,$src\t # floatMemory" %}
  opcode(DEB_ZOPC);
  ins_encode(z_form_rt_memFP(dst, src));
  ins_pipe(pipe_class_dummy);
%}

//  Div float double precision
instruct divD_reg_reg(regD dst, regD src) %{
  match(Set dst (DivD dst src));
  // CC unchanged by DIV.
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "DDBR     $dst,$src" %}
  opcode(DDBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct divD_reg_mem(regD dst, memoryRX src)%{
  match(Set dst (DivD dst (LoadD src)));
  // CC unchanged by DIV.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "DDB      $dst,$src\t # doubleMemory" %}
  opcode(DDB_ZOPC);
  ins_encode(z_form_rt_memFP(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// ABS

// Absolute float single precision
instruct absF_reg(regF dst, regF src, flagsReg cr) %{
  match(Set dst (AbsF src));
  effect(KILL cr);
  size(4);
  format %{ "LPEBR    $dst,$src\t float" %}
  opcode(LPEBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Absolute float double precision
instruct absD_reg(regD dst, regD src, flagsReg cr) %{
  match(Set dst (AbsD src));
  effect(KILL cr);
  size(4);
  format %{ "LPDBR    $dst,$src\t double" %}
  opcode(LPDBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

//  NEG(ABS)

// Negative absolute float single precision
instruct nabsF_reg(regF dst, regF src, flagsReg cr) %{
  match(Set dst (NegF (AbsF src)));
  effect(KILL cr);
  size(4);
  format %{ "LNEBR    $dst,$src\t float" %}
  opcode(LNEBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Negative absolute float double precision
instruct nabsD_reg(regD dst, regD src, flagsReg cr) %{
  match(Set dst (NegD (AbsD src)));
  effect(KILL cr);
  size(4);
  format %{ "LNDBR    $dst,$src\t double" %}
  opcode(LNDBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// NEG

instruct negF_reg(regF dst, regF src, flagsReg cr) %{
  match(Set dst (NegF src));
  effect(KILL cr);
  size(4);
  format %{ "NegF     $dst,$src\t float" %}
  ins_encode %{ __ z_lcebr($dst$$FloatRegister, $src$$FloatRegister); %}
  ins_pipe(pipe_class_dummy);
%}

instruct negD_reg(regD dst, regD src, flagsReg cr) %{
  match(Set dst (NegD src));
  effect(KILL cr);
  size(4);
  format %{ "NegD     $dst,$src\t double" %}
  ins_encode %{ __ z_lcdbr($dst$$FloatRegister, $src$$FloatRegister); %}
  ins_pipe(pipe_class_dummy);
%}

// SQRT

// Sqrt float precision
instruct sqrtF_reg(regF dst, regF src) %{
  match(Set dst (ConvD2F (SqrtD (ConvF2D src))));
  // CC remains unchanged.
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "SQEBR    $dst,$src" %}
  opcode(SQEBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Sqrt double precision
instruct sqrtD_reg(regD dst, regD src) %{
  match(Set dst (SqrtD src));
  // CC remains unchanged.
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "SQDBR    $dst,$src" %}
  opcode(SQDBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct sqrtF_mem(regF dst, memoryRX src) %{
  match(Set dst (ConvD2F (SqrtD (ConvF2D src))));
  // CC remains unchanged.
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "SQEB     $dst,$src\t # floatMemory" %}
  opcode(SQEB_ZOPC);
  ins_encode(z_form_rt_memFP(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct sqrtD_mem(regD dst, memoryRX src) %{
  match(Set dst (SqrtD src));
  // CC remains unchanged.
  ins_cost(ALU_MEMORY_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "SQDB     $dst,$src\t # doubleMemory" %}
  opcode(SQDB_ZOPC);
  ins_encode(z_form_rt_memFP(dst, src));
  ins_pipe(pipe_class_dummy);
%}

//----------Logical Instructions-----------------------------------------------

// Register And
instruct andI_reg_reg(iRegI dst, iRegI src, flagsReg cr) %{
  match(Set dst (AndI dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_LOW);
  size(2);
  format %{ "NR      $dst,$src\t # int" %}
  opcode(NR_ZOPC);
  ins_encode(z_rrform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct andI_Reg_mem(iRegI dst, memory src, flagsReg cr)%{
  match(Set dst (AndI dst (LoadI src)));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "N(Y)    $dst, $src\t # int" %}
  opcode(NY_ZOPC, N_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Immediate And
instruct andI_reg_uimm32(iRegI dst, uimmI src, flagsReg cr) %{
  match(Set dst (AndI dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_HIGH);
  size(6);
  format %{ "NILF    $dst,$src" %}
  opcode(NILF_ZOPC);
  ins_encode(z_rilform_unsigned(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct andI_reg_uimmI_LH1(iRegI dst, uimmI_LH1 src, flagsReg cr) %{
  match(Set dst (AndI dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "NILH    $dst,$src" %}
  ins_encode %{ __ z_nilh($dst$$Register, ($src$$constant >> 16) & 0xFFFF); %}
  ins_pipe(pipe_class_dummy);
%}

instruct andI_reg_uimmI_LL1(iRegI dst, uimmI_LL1 src, flagsReg cr) %{
  match(Set dst (AndI dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "NILL    $dst,$src" %}
  ins_encode %{ __ z_nill($dst$$Register, $src$$constant & 0xFFFF); %}
  ins_pipe(pipe_class_dummy);
%}

// Register And Long
instruct andL_reg_reg(iRegL dst, iRegL src, flagsReg cr) %{
  match(Set dst (AndL dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "NGR     $dst,$src\t # long" %}
  opcode(NGR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct andL_Reg_mem(iRegL dst, memory src, flagsReg cr)%{
  match(Set dst (AndL dst (LoadL src)));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "NG      $dst, $src\t # long" %}
  opcode(NG_ZOPC, NG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct andL_reg_uimmL_LL1(iRegL dst, uimmL_LL1 src, flagsReg cr) %{
  match(Set dst (AndL dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "NILL    $dst,$src\t # long" %}
  ins_encode %{ __ z_nill($dst$$Register, $src$$constant & 0xFFFF); %}
  ins_pipe(pipe_class_dummy);
%}

instruct andL_reg_uimmL_LH1(iRegL dst, uimmL_LH1 src, flagsReg cr) %{
  match(Set dst (AndL dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "NILH    $dst,$src\t # long" %}
  ins_encode %{ __ z_nilh($dst$$Register, ($src$$constant >> 16) & 0xFFFF); %}
  ins_pipe(pipe_class_dummy);
%}

instruct andL_reg_uimmL_HL1(iRegL dst, uimmL_HL1 src, flagsReg cr) %{
  match(Set dst (AndL dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "NIHL    $dst,$src\t # long" %}
  ins_encode %{ __ z_nihl($dst$$Register, ($src$$constant >> 32) & 0xFFFF); %}
  ins_pipe(pipe_class_dummy);
%}

instruct andL_reg_uimmL_HH1(iRegL dst, uimmL_HH1 src, flagsReg cr) %{
  match(Set dst (AndL dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "NIHH    $dst,$src\t # long" %}
  ins_encode %{ __ z_nihh($dst$$Register, ($src$$constant >> 48) & 0xFFFF); %}
  ins_pipe(pipe_class_dummy);
%}

//  OR

// Or Instructions
// Register Or
instruct orI_reg_reg(iRegI dst, iRegI src, flagsReg cr) %{
  match(Set dst (OrI dst src));
  effect(KILL cr);
  size(2);
  format %{ "OR      $dst,$src" %}
  opcode(OR_ZOPC);
  ins_encode(z_rrform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct orI_Reg_mem(iRegI dst, memory src, flagsReg cr)%{
  match(Set dst (OrI dst (LoadI src)));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "O(Y)    $dst, $src\t # int" %}
  opcode(OY_ZOPC, O_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Immediate Or
instruct orI_reg_uimm16(iRegI dst, uimmI16 con, flagsReg cr) %{
  match(Set dst (OrI dst con));
  effect(KILL cr);
  size(4);
  format %{ "OILL    $dst,$con" %}
  opcode(OILL_ZOPC);
  ins_encode(z_riform_unsigned(dst,con));
  ins_pipe(pipe_class_dummy);
%}

instruct orI_reg_uimm32(iRegI dst, uimmI con, flagsReg cr) %{
  match(Set dst (OrI dst con));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_HIGH);
  size(6);
  format %{ "OILF    $dst,$con" %}
  opcode(OILF_ZOPC);
  ins_encode(z_rilform_unsigned(dst,con));
  ins_pipe(pipe_class_dummy);
%}

// Register Or Long
instruct orL_reg_reg(iRegL dst, iRegL src, flagsReg cr) %{
  match(Set dst (OrL dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "OGR      $dst,$src\t # long" %}
  opcode(OGR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct orL_Reg_mem(iRegL dst, memory src, flagsReg cr)%{
  match(Set dst (OrL dst (LoadL src)));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "OG      $dst, $src\t # long" %}
  opcode(OG_ZOPC, OG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Immediate Or long
instruct orL_reg_uimm16(iRegL dst, uimmL16 con, flagsReg cr) %{
  match(Set dst (OrL dst con));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "OILL    $dst,$con\t # long" %}
  opcode(OILL_ZOPC);
  ins_encode(z_riform_unsigned(dst,con));
  ins_pipe(pipe_class_dummy);
%}

instruct orL_reg_uimm32(iRegI dst, uimmL32 con, flagsReg cr) %{
  match(Set dst (OrI dst con));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_HIGH);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "OILF    $dst,$con\t # long" %}
  opcode(OILF_ZOPC);
  ins_encode(z_rilform_unsigned(dst,con));
  ins_pipe(pipe_class_dummy);
%}

// XOR

// Register Xor
instruct xorI_reg_reg(iRegI dst, iRegI src, flagsReg cr) %{
  match(Set dst (XorI dst src));
  effect(KILL cr);
  size(2);
  format %{ "XR      $dst,$src" %}
  opcode(XR_ZOPC);
  ins_encode(z_rrform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct xorI_Reg_mem(iRegI dst, memory src, flagsReg cr)%{
  match(Set dst (XorI dst (LoadI src)));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "X(Y)    $dst, $src\t # int" %}
  opcode(XY_ZOPC, X_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Immediate Xor
instruct xorI_reg_uimm32(iRegI dst, uimmI src, flagsReg cr) %{
  match(Set dst (XorI dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_HIGH);
  size(6);
  format %{ "XILF    $dst,$src" %}
  opcode(XILF_ZOPC);
  ins_encode(z_rilform_unsigned(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Register Xor Long
instruct xorL_reg_reg(iRegL dst, iRegL src, flagsReg cr) %{
  match(Set dst (XorL dst src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "XGR     $dst,$src\t # long" %}
  opcode(XGR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct xorL_Reg_mem(iRegL dst, memory src, flagsReg cr)%{
  match(Set dst (XorL dst (LoadL src)));
  effect(KILL cr);
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "XG      $dst, $src\t # long" %}
  opcode(XG_ZOPC, XG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Immediate Xor Long
instruct xorL_reg_uimm32(iRegL dst, uimmL32 con, flagsReg cr) %{
  match(Set dst (XorL dst con));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_HIGH);
  size(6);
  format %{ "XILF    $dst,$con\t # long" %}
  opcode(XILF_ZOPC);
  ins_encode(z_rilform_unsigned(dst,con));
  ins_pipe(pipe_class_dummy);
%}

//----------Convert to Boolean-------------------------------------------------

// Convert integer to boolean.
instruct convI2B(iRegI dst, iRegI src, flagsReg cr) %{
  match(Set dst (Conv2B src));
  effect(KILL cr);
  ins_cost(3 * DEFAULT_COST);
  size(6);
  format %{ "convI2B $dst,$src" %}
  ins_encode %{
    __ z_lnr($dst$$Register, $src$$Register);  // Rdst := -|Rsrc|, i.e. Rdst == 0 <=> Rsrc == 0
    __ z_srl($dst$$Register, 31);              // Rdst := sign(Rdest)
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct convP2B(iRegI dst, iRegP_N2P src, flagsReg cr) %{
  match(Set dst (Conv2B src));
  effect(KILL cr);
  ins_cost(3 * DEFAULT_COST);
  size(10);
  format %{ "convP2B $dst,$src" %}
  ins_encode %{
    __ z_lngr($dst$$Register, $src$$Register);     // Rdst := -|Rsrc| i.e. Rdst == 0 <=> Rsrc == 0
    __ z_srlg($dst$$Register, $dst$$Register, 63); // Rdst := sign(Rdest)
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct cmpLTMask_reg_reg(iRegI dst, iRegI src, flagsReg cr) %{
  match(Set dst (CmpLTMask dst src));
  effect(KILL cr);
  ins_cost(2 * DEFAULT_COST);
  size(18);
  format %{ "Set $dst CmpLTMask $dst,$src" %}
  ins_encode %{
    // Avoid signed 32 bit overflow: Do sign extend and sub 64 bit.
    __ z_lgfr(Z_R0_scratch, $src$$Register);
    __ z_lgfr($dst$$Register, $dst$$Register);
    __ z_sgr($dst$$Register, Z_R0_scratch);
    __ z_srag($dst$$Register, $dst$$Register, 63);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct cmpLTMask_reg_zero(iRegI dst, immI_0 zero, flagsReg cr) %{
  match(Set dst (CmpLTMask dst zero));
  effect(KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "Set $dst CmpLTMask $dst,$zero" %}
  ins_encode %{ __ z_sra($dst$$Register, 31); %}
  ins_pipe(pipe_class_dummy);
%}


//----------Arithmetic Conversion Instructions---------------------------------
// The conversions operations are all Alpha sorted. Please keep it that way!

instruct convD2F_reg(regF dst, regD src) %{
  match(Set dst (ConvD2F src));
  // CC remains unchanged.
  size(4);
  format %{ "LEDBR   $dst,$src" %}
  opcode(LEDBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct convF2I_reg(iRegI dst, regF src, flagsReg cr) %{
  match(Set dst (ConvF2I src));
  effect(KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  size(16);
  format %{ "convF2I  $dst,$src" %}
  ins_encode %{
    Label done;
    __ clear_reg($dst$$Register, false, false);  // Initialize with result for unordered: 0.
    __ z_cebr($src$$FloatRegister, $src$$FloatRegister);   // Round.
    __ z_brno(done);                             // Result is zero if unordered argument.
    __ z_cfebr($dst$$Register, $src$$FloatRegister, Assembler::to_zero);
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct convD2I_reg(iRegI dst, regD src, flagsReg cr) %{
  match(Set dst (ConvD2I src));
  effect(KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  size(16);
  format %{ "convD2I  $dst,$src" %}
  ins_encode %{
    Label done;
    __ clear_reg($dst$$Register, false, false);  // Initialize with result for unordered: 0.
    __ z_cdbr($src$$FloatRegister, $src$$FloatRegister);   // Round.
    __ z_brno(done);                             // Result is zero if unordered argument.
    __ z_cfdbr($dst$$Register, $src$$FloatRegister, Assembler::to_zero);
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct convF2L_reg(iRegL dst, regF src, flagsReg cr) %{
  match(Set dst (ConvF2L src));
  effect(KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  size(16);
  format %{ "convF2L  $dst,$src" %}
  ins_encode %{
    Label done;
    __ clear_reg($dst$$Register, true, false);  // Initialize with result for unordered: 0.
    __ z_cebr($src$$FloatRegister, $src$$FloatRegister);   // Round.
    __ z_brno(done);                             // Result is zero if unordered argument.
    __ z_cgebr($dst$$Register, $src$$FloatRegister, Assembler::to_zero);
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct convD2L_reg(iRegL dst, regD src, flagsReg cr) %{
  match(Set dst (ConvD2L src));
  effect(KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  size(16);
  format %{ "convD2L  $dst,$src" %}
  ins_encode %{
    Label done;
    __ clear_reg($dst$$Register, true, false);  // Initialize with result for unordered: 0.
    __ z_cdbr($src$$FloatRegister, $src$$FloatRegister);   // Round.
    __ z_brno(done);                             // Result is zero if unordered argument.
    __ z_cgdbr($dst$$Register, $src$$FloatRegister, Assembler::to_zero);
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct convF2D_reg(regD dst, regF src) %{
  match(Set dst (ConvF2D src));
  // CC remains unchanged.
  size(4);
  format %{ "LDEBR   $dst,$src" %}
  opcode(LDEBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct convF2D_mem(regD dst, memoryRX src) %{
  match(Set dst (ConvF2D src));
  // CC remains unchanged.
  size(6);
  format %{ "LDEB    $dst,$src" %}
  opcode(LDEB_ZOPC);
  ins_encode(z_form_rt_memFP(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct convI2D_reg(regD dst, iRegI src) %{
  match(Set dst (ConvI2D src));
  // CC remains unchanged.
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "CDFBR   $dst,$src" %}
  opcode(CDFBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Optimization that saves up to two memory operations for each conversion.
instruct convI2F_ireg(regF dst, iRegI src) %{
  match(Set dst (ConvI2F src));
  // CC remains unchanged.
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "CEFBR   $dst,$src\t # convert int to float" %}
  opcode(CEFBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct convI2L_reg(iRegL dst, iRegI src) %{
  match(Set dst (ConvI2L src));
  size(4);
  format %{ "LGFR    $dst,$src\t # int->long" %}
  opcode(LGFR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Zero-extend convert int to long.
instruct convI2L_reg_zex(iRegL dst, iRegI src, immL_32bits mask) %{
  match(Set dst (AndL (ConvI2L src) mask));
  size(4);
  format %{ "LLGFR   $dst, $src \t # zero-extend int to long" %}
  ins_encode %{ __ z_llgfr($dst$$Register, $src$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

// Zero-extend convert int to long.
instruct convI2L_mem_zex(iRegL dst, memory src, immL_32bits mask) %{
  match(Set dst (AndL (ConvI2L (LoadI src)) mask));
  // Uses load_const_optmized, so size can vary.
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "LLGF    $dst, $src \t # zero-extend int to long" %}
  opcode(LLGF_ZOPC, LLGF_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Zero-extend long
instruct zeroExtend_long(iRegL dst, iRegL src, immL_32bits mask) %{
  match(Set dst (AndL src mask));
  size(4);
  format %{ "LLGFR   $dst, $src \t # zero-extend long to long" %}
  ins_encode %{ __ z_llgfr($dst$$Register, $src$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

instruct rShiftI16_lShiftI16_reg(iRegI dst, iRegI src, immI_16 amount) %{
  match(Set dst (RShiftI (LShiftI src amount) amount));
  size(4);
  format %{ "LHR     $dst,$src\t short->int" %}
  opcode(LHR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct rShiftI24_lShiftI24_reg(iRegI dst, iRegI src, immI_24 amount) %{
  match(Set dst (RShiftI (LShiftI src amount) amount));
  size(4);
  format %{ "LBR     $dst,$src\t byte->int" %}
  opcode(LBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct MoveF2I_stack_reg(iRegI dst, stackSlotF src) %{
  match(Set dst (MoveF2I src));
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "L       $dst,$src\t # MoveF2I" %}
  opcode(L_ZOPC);
  ins_encode(z_form_rt_mem(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// javax.imageio.stream.ImageInputStreamImpl.toFloats([B[FII)
instruct MoveI2F_stack_reg(regF dst, stackSlotI src) %{
  match(Set dst (MoveI2F src));
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LE      $dst,$src\t # MoveI2F" %}
  opcode(LE_ZOPC);
  ins_encode(z_form_rt_mem(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct MoveD2L_stack_reg(iRegL dst, stackSlotD src) %{
  match(Set dst (MoveD2L src));
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "LG      $src,$dst\t # MoveD2L" %}
  opcode(LG_ZOPC);
  ins_encode(z_form_rt_mem(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct MoveL2D_stack_reg(regD dst, stackSlotL src) %{
  match(Set dst (MoveL2D src));
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "LD      $dst,$src\t # MoveL2D" %}
  opcode(LD_ZOPC);
  ins_encode(z_form_rt_mem(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct MoveI2F_reg_stack(stackSlotF dst, iRegI src) %{
  match(Set dst (MoveI2F src));
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "ST      $src,$dst\t # MoveI2F" %}
  opcode(ST_ZOPC);
  ins_encode(z_form_rt_mem(src, dst));
  ins_pipe(pipe_class_dummy);
%}

instruct MoveD2L_reg_stack(stackSlotL dst, regD src) %{
  match(Set dst (MoveD2L src));
  effect(DEF dst, USE src);
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "STD     $src,$dst\t # MoveD2L" %}
  opcode(STD_ZOPC);
  ins_encode(z_form_rt_mem(src,dst));
  ins_pipe(pipe_class_dummy);
%}

instruct MoveL2D_reg_stack(stackSlotD dst, iRegL src) %{
  match(Set dst (MoveL2D src));
  ins_cost(MEMORY_REF_COST);
  size(6);
  format %{ "STG     $src,$dst\t # MoveL2D" %}
  opcode(STG_ZOPC);
  ins_encode(z_form_rt_mem(src,dst));
  ins_pipe(pipe_class_dummy);
%}

instruct convL2F_reg(regF dst, iRegL src) %{
  match(Set dst (ConvL2F src));
  // CC remains unchanged.
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "CEGBR   $dst,$src" %}
  opcode(CEGBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct convL2D_reg(regD dst, iRegL src) %{
  match(Set dst (ConvL2D src));
  // CC remains unchanged.
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "CDGBR   $dst,$src" %}
  opcode(CDGBR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct convL2I_reg(iRegI dst, iRegL src) %{
  match(Set dst (ConvL2I src));
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "LR      $dst,$src\t # long->int (if needed)" %}
  ins_encode %{ __ lr_if_needed($dst$$Register, $src$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

// Register Shift Right Immediate
instruct shrL_reg_imm6_L2I(iRegI dst, iRegL src, immI_32_63 cnt, flagsReg cr) %{
  match(Set dst (ConvL2I (RShiftL src cnt)));
  effect(KILL cr);
  size(6);
  format %{ "SRAG    $dst,$src,$cnt" %}
  opcode(SRAG_ZOPC);
  ins_encode(z_rsyform_const(dst, src, cnt));
  ins_pipe(pipe_class_dummy);
%}

//----------TRAP based zero checks and range checks----------------------------

// SIGTRAP based implicit range checks in compiled code.
// A range check in the ideal world has one of the following shapes:
//   - (If le (CmpU length index)), (IfTrue  throw exception)
//   - (If lt (CmpU index length)), (IfFalse throw exception)
//
// Match range check 'If le (CmpU length index)'
instruct rangeCheck_iReg_uimmI16(cmpOpT cmp, iRegI length, uimmI16 index, label labl) %{
  match(If cmp (CmpU length index));
  effect(USE labl);
  predicate(TrapBasedRangeChecks &&
            _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le &&
            PROB_UNLIKELY(_leaf->as_If ()->_prob) >= PROB_ALWAYS &&
            Matcher::branches_to_uncommon_trap(_leaf));
  ins_cost(1);
  // TODO: s390 port size(FIXED_SIZE);

  ins_is_TrapBasedCheckNode(true);

  format %{ "RangeCheck len=$length cmp=$cmp idx=$index => trap $labl" %}
  ins_encode %{ __ z_clfit($length$$Register, $index$$constant, $cmp$$cmpcode); %}
  ins_pipe(pipe_class_trap);
%}

// Match range check 'If lt (CmpU index length)'
instruct rangeCheck_iReg_iReg(cmpOpT cmp, iRegI index, iRegI length, label labl, flagsReg cr) %{
  match(If cmp (CmpU index length));
  effect(USE labl, KILL cr);
  predicate(TrapBasedRangeChecks &&
            _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt &&
            _leaf->as_If ()->_prob >= PROB_ALWAYS &&
            Matcher::branches_to_uncommon_trap(_leaf));
  ins_cost(1);
  // TODO: s390 port size(FIXED_SIZE);

  ins_is_TrapBasedCheckNode(true);

  format %{ "RangeCheck idx=$index cmp=$cmp len=$length => trap $labl" %}
  ins_encode %{ __ z_clrt($index$$Register, $length$$Register, $cmp$$cmpcode); %}
  ins_pipe(pipe_class_trap);
%}

// Match range check 'If lt (CmpU index length)'
instruct rangeCheck_uimmI16_iReg(cmpOpT cmp, iRegI index, uimmI16 length, label labl) %{
  match(If cmp (CmpU index length));
  effect(USE labl);
  predicate(TrapBasedRangeChecks &&
            _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt &&
            _leaf->as_If ()->_prob >= PROB_ALWAYS &&
            Matcher::branches_to_uncommon_trap(_leaf));
  ins_cost(1);
  // TODO: s390 port size(FIXED_SIZE);

  ins_is_TrapBasedCheckNode(true);

  format %{ "RangeCheck idx=$index cmp=$cmp len= $length => trap $labl" %}
  ins_encode %{ __ z_clfit($index$$Register, $length$$constant, $cmp$$cmpcode); %}
  ins_pipe(pipe_class_trap);
%}

// Implicit zero checks (more implicit null checks).
instruct zeroCheckP_iReg_imm0(cmpOpT cmp, iRegP_N2P value, immP0 zero, label labl) %{
  match(If cmp (CmpP value zero));
  effect(USE labl);
  predicate(TrapBasedNullChecks &&
            _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne &&
            _leaf->as_If ()->_prob >= PROB_LIKELY_MAG(4) &&
            Matcher::branches_to_uncommon_trap(_leaf));
  size(6);

  ins_is_TrapBasedCheckNode(true);

  format %{ "ZeroCheckP value=$value cmp=$cmp zero=$zero => trap $labl" %}
  ins_encode %{ __ z_cgit($value$$Register, 0, $cmp$$cmpcode); %}
  ins_pipe(pipe_class_trap);
%}

// Implicit zero checks (more implicit null checks).
instruct zeroCheckN_iReg_imm0(cmpOpT cmp, iRegN_P2N value, immN0 zero, label labl) %{
  match(If cmp (CmpN value zero));
  effect(USE labl);
  predicate(TrapBasedNullChecks &&
            _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne &&
            _leaf->as_If ()->_prob >= PROB_LIKELY_MAG(4) &&
            Matcher::branches_to_uncommon_trap(_leaf));
  size(6);

  ins_is_TrapBasedCheckNode(true);

  format %{ "ZeroCheckN value=$value cmp=$cmp zero=$zero => trap $labl" %}
  ins_encode %{ __ z_cit($value$$Register, 0, $cmp$$cmpcode); %}
  ins_pipe(pipe_class_trap);
%}

//----------Compare instructions-----------------------------------------------

// INT signed

// Compare Integers
instruct compI_reg_reg(flagsReg cr, iRegI op1, iRegI op2) %{
  match(Set cr (CmpI op1 op2));
  size(2);
  format %{ "CR      $op1,$op2" %}
  opcode(CR_ZOPC);
  ins_encode(z_rrform(op1, op2));
  ins_pipe(pipe_class_dummy);
%}

instruct compI_reg_imm(flagsReg cr, iRegI op1, immI op2) %{
  match(Set cr (CmpI op1 op2));
  size(6);
  format %{ "CFI     $op1,$op2" %}
  opcode(CFI_ZOPC);
  ins_encode(z_rilform_signed(op1, op2));
  ins_pipe(pipe_class_dummy);
%}

instruct compI_reg_imm16(flagsReg cr, iRegI op1, immI16 op2) %{
  match(Set cr (CmpI op1 op2));
  size(4);
  format %{ "CHI     $op1,$op2" %}
  opcode(CHI_ZOPC);
  ins_encode(z_riform_signed(op1, op2));
  ins_pipe(pipe_class_dummy);
%}

instruct compI_reg_imm0(flagsReg cr, iRegI op1, immI_0 zero) %{
  match(Set cr (CmpI op1 zero));
  ins_cost(DEFAULT_COST_LOW);
  size(2);
  format %{ "LTR     $op1,$op1" %}
  opcode(LTR_ZOPC);
  ins_encode(z_rrform(op1, op1));
  ins_pipe(pipe_class_dummy);
%}

instruct compI_reg_mem(flagsReg cr, iRegI op1, memory op2)%{
  match(Set cr (CmpI op1 (LoadI op2)));
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "C(Y)    $op1, $op2\t # int" %}
  opcode(CY_ZOPC, C_ZOPC);
  ins_encode(z_form_rt_mem_opt(op1, op2));
  ins_pipe(pipe_class_dummy);
%}

// INT unsigned

instruct compU_reg_reg(flagsReg cr, iRegI op1, iRegI op2) %{
  match(Set cr (CmpU op1 op2));
  size(2);
  format %{ "CLR     $op1,$op2\t # unsigned" %}
  opcode(CLR_ZOPC);
  ins_encode(z_rrform(op1, op2));
  ins_pipe(pipe_class_dummy);
%}

instruct compU_reg_uimm(flagsReg cr, iRegI op1, uimmI op2) %{
  match(Set cr (CmpU op1 op2));
  size(6);
  format %{ "CLFI    $op1,$op2\t # unsigned" %}
  opcode(CLFI_ZOPC);
  ins_encode(z_rilform_unsigned(op1, op2));
  ins_pipe(pipe_class_dummy);
%}

instruct compU_reg_mem(flagsReg cr, iRegI op1, memory op2)%{
  match(Set cr (CmpU op1 (LoadI op2)));
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CL(Y)   $op1, $op2\t # unsigned" %}
  opcode(CLY_ZOPC, CL_ZOPC);
  ins_encode(z_form_rt_mem_opt(op1, op2));
  ins_pipe(pipe_class_dummy);
%}

// LONG signed

instruct compL_reg_reg(flagsReg cr, iRegL op1, iRegL op2) %{
  match(Set cr (CmpL op1 op2));
  size(4);
  format %{ "CGR     $op1,$op2\t # long" %}
  opcode(CGR_ZOPC);
  ins_encode(z_rreform(op1, op2));
  ins_pipe(pipe_class_dummy);
%}

instruct compL_reg_regI(flagsReg cr, iRegL op1, iRegI op2) %{
  match(Set cr (CmpL op1 (ConvI2L op2)));
  size(4);
  format %{ "CGFR    $op1,$op2\t # long/int" %}
  opcode(CGFR_ZOPC);
  ins_encode(z_rreform(op1, op2));
  ins_pipe(pipe_class_dummy);
%}

instruct compL_reg_imm32(flagsReg cr, iRegL op1, immL32 con) %{
  match(Set cr (CmpL op1 con));
  size(6);
  format %{ "CGFI    $op1,$con" %}
  opcode(CGFI_ZOPC);
  ins_encode(z_rilform_signed(op1, con));
  ins_pipe(pipe_class_dummy);
%}

instruct compL_reg_imm16(flagsReg cr, iRegL op1, immL16 con) %{
  match(Set cr (CmpL op1 con));
  size(4);
  format %{ "CGHI    $op1,$con" %}
  opcode(CGHI_ZOPC);
  ins_encode(z_riform_signed(op1, con));
  ins_pipe(pipe_class_dummy);
%}

instruct compL_reg_imm0(flagsReg cr, iRegL op1, immL_0 con) %{
  match(Set cr (CmpL op1 con));
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LTGR    $op1,$op1" %}
  opcode(LTGR_ZOPC);
  ins_encode(z_rreform(op1, op1));
  ins_pipe(pipe_class_dummy);
%}

instruct compL_conv_reg_imm0(flagsReg cr, iRegI op1, immL_0 con) %{
  match(Set cr (CmpL (ConvI2L op1) con));
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LTGFR    $op1,$op1" %}
  opcode(LTGFR_ZOPC);
  ins_encode(z_rreform(op1, op1));
  ins_pipe(pipe_class_dummy);
%}

instruct compL_reg_mem(iRegL dst, memory src, flagsReg cr)%{
  match(Set cr (CmpL dst (LoadL src)));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "CG      $dst, $src\t # long" %}
  opcode(CG_ZOPC, CG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct compL_reg_memI(iRegL dst, memory src, flagsReg cr)%{
  match(Set cr (CmpL dst (ConvI2L (LoadI src))));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "CGF     $dst, $src\t # long/int" %}
  opcode(CGF_ZOPC, CGF_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

//  LONG unsigned
// Added CmpUL for LoopPredicate.
instruct compUL_reg_reg(flagsReg cr, iRegL op1, iRegL op2) %{
  match(Set cr (CmpUL op1 op2));
  size(4);
  format %{ "CLGR    $op1,$op2\t # long" %}
  opcode(CLGR_ZOPC);
  ins_encode(z_rreform(op1, op2));
  ins_pipe(pipe_class_dummy);
%}

instruct compUL_reg_imm32(flagsReg cr, iRegL op1, uimmL32 con) %{
  match(Set cr (CmpUL op1 con));
  size(6);
  format %{ "CLGFI   $op1,$con" %}
  opcode(CLGFI_ZOPC);
  ins_encode(z_rilform_unsigned(op1, con));
  ins_pipe(pipe_class_dummy);
%}

//  PTR unsigned

instruct compP_reg_reg(flagsReg cr, iRegP_N2P op1, iRegP_N2P op2) %{
  match(Set cr (CmpP op1 op2));
  size(4);
  format %{ "CLGR    $op1,$op2\t # ptr" %}
  opcode(CLGR_ZOPC);
  ins_encode(z_rreform(op1, op2));
  ins_pipe(pipe_class_dummy);
%}

instruct compP_reg_imm0(flagsReg cr, iRegP_N2P op1, immP0 op2) %{
  match(Set cr (CmpP op1 op2));
  ins_cost(DEFAULT_COST_LOW);
  size(4);
  format %{ "LTGR    $op1, $op1\t # ptr" %}
  opcode(LTGR_ZOPC);
  ins_encode(z_rreform(op1, op1));
  ins_pipe(pipe_class_dummy);
%}

// Don't use LTGFR which performs sign extend.
instruct compP_decode_reg_imm0(flagsReg cr, iRegN op1, immP0 op2) %{
  match(Set cr (CmpP (DecodeN op1) op2));
  predicate(CompressedOops::base() == NULL && CompressedOops::shift() == 0);
  ins_cost(DEFAULT_COST_LOW);
  size(2);
  format %{ "LTR    $op1, $op1\t # ptr" %}
  opcode(LTR_ZOPC);
  ins_encode(z_rrform(op1, op1));
  ins_pipe(pipe_class_dummy);
%}

instruct compP_reg_mem(iRegP dst, memory src, flagsReg cr)%{
  match(Set cr (CmpP dst (LoadP src)));
  ins_cost(MEMORY_REF_COST);
  size(Z_DISP3_SIZE);
  format %{ "CLG     $dst, $src\t # ptr" %}
  opcode(CLG_ZOPC, CLG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, src));
  ins_pipe(pipe_class_dummy);
%}

//----------Max and Min--------------------------------------------------------

// Max Register with Register
instruct z196_minI_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
  match(Set dst (MinI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_LoadStoreConditional());
  ins_cost(3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MinI $dst $src1,$src2\t MinI (z196 only)" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc1 = $src1$$Register;
    Register Rsrc2 = $src2$$Register;

    if (Rsrc1 == Rsrc2) {
      if (Rdst != Rsrc1) {
        __ z_lgfr(Rdst, Rsrc1);
      }
    } else if (Rdst == Rsrc1) {   // Rdst preset with src1.
      __ z_cr(Rsrc1, Rsrc2);      // Move src2 only if src1 is NotLow.
      __ z_locr(Rdst, Rsrc2, Assembler::bcondNotLow);
    } else if (Rdst == Rsrc2) {   // Rdst preset with src2.
      __ z_cr(Rsrc2, Rsrc1);      // Move src1 only if src2 is NotLow.
      __ z_locr(Rdst, Rsrc1, Assembler::bcondNotLow);
    } else {
      // Rdst is disjoint from operands, move in either case.
      __ z_cr(Rsrc1, Rsrc2);
      __ z_locr(Rdst, Rsrc2, Assembler::bcondNotLow);
      __ z_locr(Rdst, Rsrc1, Assembler::bcondLow);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// Min Register with Register.
instruct z10_minI_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
  match(Set dst (MinI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MinI $dst $src1,$src2\t MinI (z10 only)" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc1 = $src1$$Register;
    Register Rsrc2 = $src2$$Register;
    Label done;

    if (Rsrc1 == Rsrc2) {
      if (Rdst != Rsrc1) {
        __ z_lgfr(Rdst, Rsrc1);
      }
    } else if (Rdst == Rsrc1) {
      __ z_crj(Rsrc1, Rsrc2, Assembler::bcondLow, done);
      __ z_lgfr(Rdst, Rsrc2);
    } else if (Rdst == Rsrc2) {
      __ z_crj(Rsrc2, Rsrc1, Assembler::bcondLow, done);
      __ z_lgfr(Rdst, Rsrc1);
    } else {
      __ z_lgfr(Rdst, Rsrc1);
      __ z_crj(Rsrc1, Rsrc2, Assembler::bcondLow, done);
      __ z_lgfr(Rdst, Rsrc2);
    }
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct minI_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
  match(Set dst (MinI src1 src2));
  effect(KILL cr);
  predicate(!VM_Version::has_CompareBranch());
  ins_cost(3 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MinI $dst $src1,$src2\t MinI" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc1 = $src1$$Register;
    Register Rsrc2 = $src2$$Register;
    Label done;

    if (Rsrc1 == Rsrc2) {
      if (Rdst != Rsrc1) {
        __ z_lgfr(Rdst, Rsrc1);
      }
    } else if (Rdst == Rsrc1) {
      __ z_cr(Rsrc1, Rsrc2);
      __ z_brl(done);
      __ z_lgfr(Rdst, Rsrc2);
    } else if (Rdst == Rsrc2) {
      __ z_cr(Rsrc2, Rsrc1);
      __ z_brl(done);
      __ z_lgfr(Rdst, Rsrc1);
    } else {
      __ z_lgfr(Rdst, Rsrc1);
      __ z_cr(Rsrc1, Rsrc2);
      __ z_brl(done);
      __ z_lgfr(Rdst, Rsrc2);
    }
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct z196_minI_reg_imm32(iRegI dst, iRegI src1, immI src2, flagsReg cr) %{
  match(Set dst (MinI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_LoadStoreConditional());
  ins_cost(3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MinI $dst $src1,$src2\t MinI const32 (z196 only)" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc1 = $src1$$Register;
    int      Isrc2 = $src2$$constant;

    if (Rdst == Rsrc1) {
      __ load_const_optimized(Z_R0_scratch, Isrc2);
      __ z_cfi(Rsrc1, Isrc2);
      __ z_locr(Rdst, Z_R0_scratch, Assembler::bcondNotLow);
    } else {
      __ load_const_optimized(Rdst, Isrc2);
      __ z_cfi(Rsrc1, Isrc2);
      __ z_locr(Rdst, Rsrc1, Assembler::bcondLow);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct minI_reg_imm32(iRegI dst, iRegI src1, immI src2, flagsReg cr) %{
  match(Set dst (MinI src1 src2));
  effect(KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MinI $dst $src1,$src2\t MinI const32" %}
  ins_encode %{
    Label done;
    if ($dst$$Register != $src1$$Register) {
      __ z_lgfr($dst$$Register, $src1$$Register);
    }
    __ z_cfi($src1$$Register, $src2$$constant);
    __ z_brl(done);
    __ z_lgfi($dst$$Register, $src2$$constant);
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct z196_minI_reg_imm16(iRegI dst, iRegI src1, immI16 src2, flagsReg cr) %{
  match(Set dst (MinI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_LoadStoreConditional());
  ins_cost(3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MinI $dst $src1,$src2\t MinI const16 (z196 only)" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc1 = $src1$$Register;
    int      Isrc2 = $src2$$constant;

    if (Rdst == Rsrc1) {
      __ load_const_optimized(Z_R0_scratch, Isrc2);
      __ z_chi(Rsrc1, Isrc2);
      __ z_locr(Rdst, Z_R0_scratch, Assembler::bcondNotLow);
    } else {
      __ load_const_optimized(Rdst, Isrc2);
      __ z_chi(Rsrc1, Isrc2);
      __ z_locr(Rdst, Rsrc1, Assembler::bcondLow);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct minI_reg_imm16(iRegI dst, iRegI src1, immI16 src2, flagsReg cr) %{
  match(Set dst (MinI src1 src2));
  effect(KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MinI $dst $src1,$src2\t MinI const16" %}
  ins_encode %{
    Label done;
    if ($dst$$Register != $src1$$Register) {
      __ z_lgfr($dst$$Register, $src1$$Register);
    }
    __ z_chi($src1$$Register, $src2$$constant);
    __ z_brl(done);
    __ z_lghi($dst$$Register, $src2$$constant);
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct z10_minI_reg_imm8(iRegI dst, iRegI src1, immI8 src2, flagsReg cr) %{
  match(Set dst (MinI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MinI $dst $src1,$src2\t MinI const8 (z10 only)" %}
  ins_encode %{
    Label done;
    if ($dst$$Register != $src1$$Register) {
      __ z_lgfr($dst$$Register, $src1$$Register);
    }
    __ z_cij($src1$$Register, $src2$$constant, Assembler::bcondLow, done);
    __ z_lghi($dst$$Register, $src2$$constant);
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Max Register with Register
instruct z196_maxI_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
  match(Set dst (MaxI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_LoadStoreConditional());
  ins_cost(3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MaxI $dst $src1,$src2\t MaxI (z196 only)" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc1 = $src1$$Register;
    Register Rsrc2 = $src2$$Register;

    if (Rsrc1 == Rsrc2) {
      if (Rdst != Rsrc1) {
        __ z_lgfr(Rdst, Rsrc1);
      }
    } else if (Rdst == Rsrc1) { // Rdst preset with src1.
      __ z_cr(Rsrc1, Rsrc2);    // Move src2 only if src1 is NotHigh.
      __ z_locr(Rdst, Rsrc2, Assembler::bcondNotHigh);
    } else if (Rdst == Rsrc2) { // Rdst preset with src2.
      __ z_cr(Rsrc2, Rsrc1);    // Move src1 only if src2 is NotHigh.
      __ z_locr(Rdst, Rsrc1, Assembler::bcondNotHigh);
    } else {                    // Rdst is disjoint from operands, move in either case.
      __ z_cr(Rsrc1, Rsrc2);
      __ z_locr(Rdst, Rsrc2, Assembler::bcondNotHigh);
      __ z_locr(Rdst, Rsrc1, Assembler::bcondHigh);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// Max Register with Register
instruct z10_maxI_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
  match(Set dst (MaxI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MaxI $dst $src1,$src2\t MaxI (z10 only)" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc1 = $src1$$Register;
    Register Rsrc2 = $src2$$Register;
    Label done;

    if (Rsrc1 == Rsrc2) {
      if (Rdst != Rsrc1) {
        __ z_lgfr(Rdst, Rsrc1);
      }
    } else if (Rdst == Rsrc1) {
      __ z_crj(Rsrc1, Rsrc2, Assembler::bcondHigh, done);
      __ z_lgfr(Rdst, Rsrc2);
    } else if (Rdst == Rsrc2) {
      __ z_crj(Rsrc2, Rsrc1, Assembler::bcondHigh, done);
      __ z_lgfr(Rdst, Rsrc1);
    } else {
      __ z_lgfr(Rdst, Rsrc1);
      __ z_crj(Rsrc1, Rsrc2, Assembler::bcondHigh, done);
      __ z_lgfr(Rdst, Rsrc2);
    }
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct maxI_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
  match(Set dst (MaxI src1 src2));
  effect(KILL cr);
  predicate(!VM_Version::has_CompareBranch());
  ins_cost(3 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MaxI $dst $src1,$src2\t MaxI" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc1 = $src1$$Register;
    Register Rsrc2 = $src2$$Register;
    Label done;

    if (Rsrc1 == Rsrc2) {
      if (Rdst != Rsrc1) {
        __ z_lgfr(Rdst, Rsrc1);
      }
    } else if (Rdst == Rsrc1) {
      __ z_cr(Rsrc1, Rsrc2);
      __ z_brh(done);
      __ z_lgfr(Rdst, Rsrc2);
    } else if (Rdst == Rsrc2) {
      __ z_cr(Rsrc2, Rsrc1);
      __ z_brh(done);
      __ z_lgfr(Rdst, Rsrc1);
    } else {
      __ z_lgfr(Rdst, Rsrc1);
      __ z_cr(Rsrc1, Rsrc2);
      __ z_brh(done);
      __ z_lgfr(Rdst, Rsrc2);
    }

    __ bind(done);
  %}

  ins_pipe(pipe_class_dummy);
%}

instruct z196_maxI_reg_imm32(iRegI dst, iRegI src1, immI src2, flagsReg cr) %{
  match(Set dst (MaxI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_LoadStoreConditional());
  ins_cost(3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MaxI $dst $src1,$src2\t MaxI const32 (z196 only)" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc1 = $src1$$Register;
    int      Isrc2 = $src2$$constant;

    if (Rdst == Rsrc1) {
      __ load_const_optimized(Z_R0_scratch, Isrc2);
      __ z_cfi(Rsrc1, Isrc2);
      __ z_locr(Rdst, Z_R0_scratch, Assembler::bcondNotHigh);
    } else {
      __ load_const_optimized(Rdst, Isrc2);
      __ z_cfi(Rsrc1, Isrc2);
      __ z_locr(Rdst, Rsrc1, Assembler::bcondHigh);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct maxI_reg_imm32(iRegI dst, iRegI src1, immI src2, flagsReg cr) %{
  match(Set dst (MaxI src1 src2));
  effect(KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MaxI $dst $src1,$src2\t MaxI const32" %}
  ins_encode %{
    Label done;
    if ($dst$$Register != $src1$$Register) {
      __ z_lgfr($dst$$Register, $src1$$Register);
    }
    __ z_cfi($src1$$Register, $src2$$constant);
    __ z_brh(done);
    __ z_lgfi($dst$$Register, $src2$$constant);
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct z196_maxI_reg_imm16(iRegI dst, iRegI src1, immI16 src2, flagsReg cr) %{
  match(Set dst (MaxI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_LoadStoreConditional());
  ins_cost(3 * DEFAULT_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MaxI $dst $src1,$src2\t MaxI const16 (z196 only)" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc1 = $src1$$Register;
    int      Isrc2 = $src2$$constant;
    if (Rdst == Rsrc1) {
      __ load_const_optimized(Z_R0_scratch, Isrc2);
      __ z_chi(Rsrc1, Isrc2);
      __ z_locr(Rdst, Z_R0_scratch, Assembler::bcondNotHigh);
    } else {
      __ load_const_optimized(Rdst, Isrc2);
      __ z_chi(Rsrc1, Isrc2);
      __ z_locr(Rdst, Rsrc1, Assembler::bcondHigh);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct maxI_reg_imm16(iRegI dst, iRegI src1, immI16 src2, flagsReg cr) %{
  match(Set dst (MaxI src1 src2));
  effect(KILL cr);
  ins_cost(2 * DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MaxI $dst $src1,$src2\t MaxI const16" %}
  ins_encode %{
    Label done;
    if ($dst$$Register != $src1$$Register) {
      __ z_lgfr($dst$$Register, $src1$$Register);
    }
    __ z_chi($src1$$Register, $src2$$constant);
    __ z_brh(done);
    __ z_lghi($dst$$Register, $src2$$constant);
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct z10_maxI_reg_imm8(iRegI dst, iRegI src1, immI8 src2, flagsReg cr) %{
  match(Set dst (MaxI src1 src2));
  effect(KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(DEFAULT_COST + BRANCH_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "MaxI $dst $src1,$src2\t MaxI const8" %}
  ins_encode %{
    Label done;
    if ($dst$$Register != $src1$$Register) {
      __ z_lgfr($dst$$Register, $src1$$Register);
    }
    __ z_cij($src1$$Register, $src2$$constant, Assembler::bcondHigh, done);
    __ z_lghi($dst$$Register, $src2$$constant);
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

//----------Abs---------------------------------------------------------------

instruct absI_reg(iRegI dst, iRegI src, flagsReg cr) %{
  match(Set dst (AbsI src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_LOW);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LPR     $dst, $src" %}
  opcode(LPR_ZOPC);
  ins_encode(z_rrform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct absL_reg(iRegL dst, iRegL src, flagsReg cr) %{
  match(Set dst (AbsL src));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_LOW);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LPGR     $dst, $src" %}
  opcode(LPGR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct negabsI_reg(iRegI dst, iRegI src, immI_0 zero, flagsReg cr) %{
  match(Set dst (SubI zero (AbsI src)));
  effect(KILL cr);
  ins_cost(DEFAULT_COST_LOW);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LNR     $dst, $src" %}
  opcode(LNR_ZOPC);
  ins_encode(z_rrform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

//----------Float Compares----------------------------------------------------

// Compare floating, generate condition code.
instruct cmpF_cc(flagsReg cr, regF src1, regF src2) %{
  match(Set cr (CmpF src1 src2));
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "FCMPcc   $src1,$src2\t # float" %}
  ins_encode %{ __ z_cebr($src1$$FloatRegister, $src2$$FloatRegister); %}
  ins_pipe(pipe_class_dummy);
%}

instruct cmpD_cc(flagsReg cr, regD src1, regD src2) %{
  match(Set cr (CmpD src1 src2));
  ins_cost(ALU_REG_COST);
  size(4);
  format %{ "FCMPcc   $src1,$src2 \t # double" %}
  ins_encode %{ __ z_cdbr($src1$$FloatRegister, $src2$$FloatRegister); %}
  ins_pipe(pipe_class_dummy);
%}

instruct cmpF_cc_mem(flagsReg cr, regF src1, memoryRX src2) %{
  match(Set cr (CmpF src1 (LoadF src2)));
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "FCMPcc_mem $src1,$src2\t # floatMemory" %}
  opcode(CEB_ZOPC);
  ins_encode(z_form_rt_memFP(src1, src2));
  ins_pipe(pipe_class_dummy);
%}

instruct cmpD_cc_mem(flagsReg cr, regD src1, memoryRX src2) %{
  match(Set cr (CmpD src1 (LoadD src2)));
  ins_cost(ALU_MEMORY_COST);
  size(6);
  format %{ "DCMPcc_mem $src1,$src2\t # doubleMemory" %}
  opcode(CDB_ZOPC);
  ins_encode(z_form_rt_memFP(src1, src2));
  ins_pipe(pipe_class_dummy);
%}

// Compare floating, generate condition code
instruct cmpF0_cc(flagsReg cr, regF src1, immFpm0 src2) %{
  match(Set cr (CmpF src1 src2));
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "LTEBR    $src1,$src1\t # float" %}
  opcode(LTEBR_ZOPC);
  ins_encode(z_rreform(src1, src1));
  ins_pipe(pipe_class_dummy);
%}

instruct cmpD0_cc(flagsReg cr, regD src1, immDpm0 src2) %{
  match(Set cr (CmpD src1 src2));
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "LTDBR    $src1,$src1 \t # double" %}
  opcode(LTDBR_ZOPC);
  ins_encode(z_rreform(src1, src1));
  ins_pipe(pipe_class_dummy);
%}

// Compare floating, generate -1,0,1
instruct cmpF_reg(iRegI dst, regF src1, regF src2, flagsReg cr) %{
  match(Set dst (CmpF3 src1 src2));
  effect(KILL cr);
  ins_cost(DEFAULT_COST * 5 + BRANCH_COST);
  size(24);
  format %{ "CmpF3    $dst,$src1,$src2" %}
  ins_encode %{
    // compare registers
    __ z_cebr($src1$$FloatRegister, $src2$$FloatRegister);
    // Convert condition code into -1,0,1, where
    // -1 means unordered or less
    //  0 means equal
    //  1 means greater.
    if (VM_Version::has_LoadStoreConditional()) {
      Register one       = Z_R0_scratch;
      Register minus_one = Z_R1_scratch;
      __ z_lghi(minus_one, -1);
      __ z_lghi(one, 1);
      __ z_lghi( $dst$$Register, 0);
      __ z_locgr($dst$$Register, one,       Assembler::bcondHigh);
      __ z_locgr($dst$$Register, minus_one, Assembler::bcondLowOrNotOrdered);
    } else {
      Label done;
      __ clear_reg($dst$$Register, true, false);
      __ z_bre(done);
      __ z_lhi($dst$$Register, 1);
      __ z_brh(done);
      __ z_lhi($dst$$Register, -1);
      __ bind(done);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct cmpD_reg(iRegI dst, regD src1, regD src2, flagsReg cr) %{
  match(Set dst (CmpD3 src1 src2));
  effect(KILL cr);
  ins_cost(DEFAULT_COST * 5 + BRANCH_COST);
  size(24);
  format %{ "CmpD3    $dst,$src1,$src2" %}
  ins_encode %{
    // compare registers
    __ z_cdbr($src1$$FloatRegister, $src2$$FloatRegister);
    // Convert condition code into -1,0,1, where
    // -1 means unordered or less
    //  0 means equal
    //  1 means greater.
    if (VM_Version::has_LoadStoreConditional()) {
      Register one       = Z_R0_scratch;
      Register minus_one = Z_R1_scratch;
      __ z_lghi(minus_one, -1);
      __ z_lghi(one, 1);
      __ z_lghi( $dst$$Register, 0);
      __ z_locgr($dst$$Register, one,       Assembler::bcondHigh);
      __ z_locgr($dst$$Register, minus_one, Assembler::bcondLowOrNotOrdered);
    } else {
      Label done;
      // indicate unused result
      (void) __ clear_reg($dst$$Register, true, false);
      __ z_bre(done);
      __ z_lhi($dst$$Register, 1);
      __ z_brh(done);
      __ z_lhi($dst$$Register, -1);
      __ bind(done);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

//----------Branches---------------------------------------------------------
// Jump

// Direct Branch.
instruct branch(label labl) %{
  match(Goto);
  effect(USE labl);
  ins_cost(BRANCH_COST);
  size(4);
  format %{ "BRU     $labl" %}
  ins_encode(z_enc_bru(labl));
  ins_pipe(pipe_class_dummy);
  // 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);
%}

// Direct Branch.
instruct branchFar(label labl) %{
  match(Goto);
  effect(USE labl);
  ins_cost(BRANCH_COST);
  size(6);
  format %{ "BRUL   $labl" %}
  ins_encode(z_enc_brul(labl));
  ins_pipe(pipe_class_dummy);
  // This is not a short variant of a branch, but the long variant.
  ins_short_branch(0);
%}

// Conditional Near Branch
instruct branchCon(cmpOp cmp, flagsReg cr, label lbl) %{
  // Same match rule as `branchConFar'.
  match(If cmp cr);
  effect(USE lbl);
  ins_cost(BRANCH_COST);
  size(4);
  format %{ "branch_con_short,$cmp   $lbl" %}
  ins_encode(z_enc_branch_con_short(cmp, lbl));
  ins_pipe(pipe_class_dummy);
  // 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);
%}

// This is for cases when the z/Architecture conditional branch instruction
// does not reach far enough. So we emit a far branch here, which is
// more expensive.
//
// Conditional Far Branch
instruct branchConFar(cmpOp cmp, flagsReg cr, label lbl) %{
  // Same match rule as `branchCon'.
  match(If cmp cr);
  effect(USE cr, USE lbl);
  // Make more expensive to prefer compare_and_branch over separate instructions.
  ins_cost(2 * BRANCH_COST);
  size(6);
  format %{ "branch_con_far,$cmp   $lbl" %}
  ins_encode(z_enc_branch_con_far(cmp, lbl));
  ins_pipe(pipe_class_dummy);
  // This is not a short variant of a branch, but the long variant..
  ins_short_branch(0);
%}

instruct branchLoopEnd(cmpOp cmp, flagsReg cr, label labl) %{
  match(CountedLoopEnd cmp cr);
  effect(USE labl);
  ins_cost(BRANCH_COST);
  size(4);
  format %{ "branch_con_short,$cmp   $labl\t # counted loop end" %}
  ins_encode(z_enc_branch_con_short(cmp, labl));
  ins_pipe(pipe_class_dummy);
  // 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);
%}

instruct branchLoopEndFar(cmpOp cmp, flagsReg cr, label labl) %{
  match(CountedLoopEnd cmp cr);
  effect(USE labl);
  ins_cost(BRANCH_COST);
  size(6);
  format %{ "branch_con_far,$cmp   $labl\t # counted loop end" %}
  ins_encode(z_enc_branch_con_far(cmp, labl));
  ins_pipe(pipe_class_dummy);
  // This is not a short variant of a branch, but the long variant.
  ins_short_branch(0);
%}

//----------Compare and Branch (short distance)------------------------------

// INT REG operands for loop counter processing.
instruct testAndBranchLoopEnd_Reg(cmpOpT boolnode, iRegI src1, iRegI src2, label labl, flagsReg cr) %{
  match(CountedLoopEnd boolnode (CmpI src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "test_and_branch_loop_end,$boolnode  $src1,$src2,$labl\t # counted loop end SHORT" %}
  opcode(CRJ_ZOPC);
  ins_encode(z_enc_cmpb_regreg(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

// INT REG operands.
instruct cmpb_RegI(cmpOpT boolnode, iRegI src1, iRegI src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpI src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CRJ,$boolnode  $src1,$src2,$labl\t # SHORT" %}
  opcode(CRJ_ZOPC);
  ins_encode(z_enc_cmpb_regreg(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

// Unsigned INT REG operands
instruct cmpbU_RegI(cmpOpT boolnode, iRegI src1, iRegI src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpU src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLRJ,$boolnode  $src1,$src2,$labl\t # SHORT" %}
  opcode(CLRJ_ZOPC);
  ins_encode(z_enc_cmpb_regreg(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

// LONG REG operands
instruct cmpb_RegL(cmpOpT boolnode, iRegL src1, iRegL src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpL src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CGRJ,$boolnode $src1,$src2,$labl\t # SHORT" %}
  opcode(CGRJ_ZOPC);
  ins_encode(z_enc_cmpb_regreg(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

//  PTR REG operands

// Separate rules for regular and narrow oops.  ADLC can't recognize
// rules with polymorphic operands to be sisters -> shorten_branches
// will not shorten.

instruct cmpb_RegPP(cmpOpT boolnode, iRegP src1, iRegP src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpP src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLGRJ,$boolnode $src1,$src2,$labl\t # SHORT" %}
  opcode(CLGRJ_ZOPC);
  ins_encode(z_enc_cmpb_regreg(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

instruct cmpb_RegNN(cmpOpT boolnode, iRegN src1, iRegN src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpP (DecodeN src1) (DecodeN src2)));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLGRJ,$boolnode $src1,$src2,$labl\t # SHORT" %}
  opcode(CLGRJ_ZOPC);
  ins_encode(z_enc_cmpb_regreg(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

// INT REG/IMM operands for loop counter processing
instruct testAndBranchLoopEnd_Imm(cmpOpT boolnode, iRegI src1, immI8 src2, label labl, flagsReg cr) %{
  match(CountedLoopEnd boolnode (CmpI src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "test_and_branch_loop_end,$boolnode  $src1,$src2,$labl\t # counted loop end SHORT" %}
  opcode(CIJ_ZOPC);
  ins_encode(z_enc_cmpb_regimm(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

// INT REG/IMM operands
instruct cmpb_RegI_imm(cmpOpT boolnode, iRegI src1, immI8 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpI src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CIJ,$boolnode  $src1,$src2,$labl\t # SHORT" %}
  opcode(CIJ_ZOPC);
  ins_encode(z_enc_cmpb_regimm(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

// INT REG/IMM operands
instruct cmpbU_RegI_imm(cmpOpT boolnode, iRegI src1, uimmI8 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpU src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLIJ,$boolnode $src1,$src2,$labl\t # SHORT" %}
  opcode(CLIJ_ZOPC);
  ins_encode(z_enc_cmpb_regimm(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

// LONG REG/IMM operands
instruct cmpb_RegL_imm(cmpOpT boolnode, iRegL src1, immL8 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpL src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CGIJ,$boolnode $src1,$src2,$labl\t # SHORT" %}
  opcode(CGIJ_ZOPC);
  ins_encode(z_enc_cmpb_regimm(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

// PTR REG-imm operands

// Separate rules for regular and narrow oops. ADLC can't recognize
// rules with polymorphic operands to be sisters -> shorten_branches
// will not shorten.

instruct cmpb_RegP_immP(cmpOpT boolnode, iRegP src1, immP8 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpP src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLGIJ,$boolnode $src1,$src2,$labl\t # SHORT" %}
  opcode(CLGIJ_ZOPC);
  ins_encode(z_enc_cmpb_regimm(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

// Compare against zero only, do not mix N and P oops (encode/decode required).
instruct cmpb_RegN_immP0(cmpOpT boolnode, iRegN src1, immP0 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpP (DecodeN src1) src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLGIJ,$boolnode $src1,$src2,$labl\t # SHORT" %}
  opcode(CLGIJ_ZOPC);
  ins_encode(z_enc_cmpb_regimm(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}

instruct cmpb_RegN_imm(cmpOpT boolnode, iRegN src1, immN8 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpP (DecodeN src1) (DecodeN src2)));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLGIJ,$boolnode $src1,$src2,$labl\t # SHORT" %}
  opcode(CLGIJ_ZOPC);
  ins_encode(z_enc_cmpb_regimm(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(1);
%}


//----------Compare and Branch (far distance)------------------------------

// INT REG operands for loop counter processing
instruct testAndBranchLoopEnd_RegFar(cmpOpT boolnode, iRegI src1, iRegI src2, label labl, flagsReg cr) %{
  match(CountedLoopEnd boolnode (CmpI src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "test_and_branch_loop_end,$boolnode  $src1,$src2,$labl\t # counted loop end FAR" %}
  opcode(CR_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regregFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

// INT REG operands
instruct cmpb_RegI_Far(cmpOpT boolnode, iRegI src1, iRegI src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpI src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CRJ,$boolnode   $src1,$src2,$labl\t # FAR(substituted)" %}
  opcode(CR_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regregFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

// INT REG operands
instruct cmpbU_RegI_Far(cmpOpT boolnode, iRegI src1, iRegI src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpU src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLRJ,$boolnode   $src1,$src2,$labl\t # FAR(substituted)" %}
  opcode(CLR_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regregFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

// LONG REG operands
instruct cmpb_RegL_Far(cmpOpT boolnode, iRegL src1, iRegL src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpL src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CGRJ,$boolnode   $src1,$src2,$labl\t # FAR(substituted)" %}
  opcode(CGR_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regregFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

// PTR REG operands

// Separate rules for regular and narrow oops. ADLC can't recognize
// rules with polymorphic operands to be sisters -> shorten_branches
// will not shorten.

instruct cmpb_RegPP_Far(cmpOpT boolnode, iRegP src1, iRegP src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpP src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLGRJ,$boolnode   $src1,$src2,$labl\t # FAR(substituted)" %}
  opcode(CLGR_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regregFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

instruct cmpb_RegNN_Far(cmpOpT boolnode, iRegN src1, iRegN src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpP (DecodeN src1) (DecodeN src2)));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLGRJ,$boolnode   $src1,$src2,$labl\t # FAR(substituted)" %}
  opcode(CLGR_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regregFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

// INT REG/IMM operands for loop counter processing
instruct testAndBranchLoopEnd_ImmFar(cmpOpT boolnode, iRegI src1, immI8 src2, label labl, flagsReg cr) %{
  match(CountedLoopEnd boolnode (CmpI src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "test_and_branch_loop_end,$boolnode  $src1,$src2,$labl\t # counted loop end FAR" %}
  opcode(CHI_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regimmFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

// INT REG/IMM operands
instruct cmpb_RegI_imm_Far(cmpOpT boolnode, iRegI src1, immI8 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpI src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CIJ,$boolnode   $src1,$src2,$labl\t # FAR(substituted)" %}
  opcode(CHI_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regimmFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

// INT REG/IMM operands
instruct cmpbU_RegI_imm_Far(cmpOpT boolnode, iRegI src1, uimmI8 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpU src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLIJ,$boolnode   $src1,$src2,$labl\t # FAR(substituted)" %}
  opcode(CLFI_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regimmFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

// LONG REG/IMM operands
instruct cmpb_RegL_imm_Far(cmpOpT boolnode, iRegL src1, immL8 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpL src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CGIJ,$boolnode   $src1,$src2,$labl\t # FAR(substituted)" %}
  opcode(CGHI_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regimmFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

// PTR REG-imm operands

// Separate rules for regular and narrow oops. ADLC can't recognize
// rules with polymorphic operands to be sisters -> shorten_branches
// will not shorten.

instruct cmpb_RegP_immP_Far(cmpOpT boolnode, iRegP src1, immP8 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpP src1 src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLGIJ,$boolnode   $src1,$src2,$labl\t # FAR(substituted)" %}
  opcode(CLGFI_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regimmFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

// Compare against zero only, do not mix N and P oops (encode/decode required).
instruct cmpb_RegN_immP0_Far(cmpOpT boolnode, iRegN src1, immP0 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpP (DecodeN src1) src2));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLGIJ,$boolnode   $src1,$src2,$labl\t # FAR(substituted)" %}
  opcode(CLGFI_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regimmFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

instruct cmpb_RegN_immN_Far(cmpOpT boolnode, iRegN src1, immN8 src2, label labl, flagsReg cr) %{
  match(If boolnode (CmpP (DecodeN src1) (DecodeN src2)));
  effect(USE labl, KILL cr);
  predicate(VM_Version::has_CompareBranch());
  ins_cost(BRANCH_COST+DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CLGIJ,$boolnode   $src1,$src2,$labl\t # FAR(substituted)" %}
  opcode(CLGFI_ZOPC, BRCL_ZOPC);
  ins_encode(z_enc_cmpb_regimmFar(src1, src2, labl, boolnode));
  ins_pipe(pipe_class_dummy);
  ins_short_branch(0);
%}

// ============================================================================
// Long Compare

// Due to a shortcoming in the ADLC, it mixes up expressions like:
// (foo (CmpI (CmpL X Y) 0)) and (bar (CmpI (CmpL X 0L) 0)). Note the
// difference between 'Y' and '0L'. The tree-matches for the CmpI sections
// are collapsed internally in the ADLC's dfa-gen code. The match for
// (CmpI (CmpL X Y) 0) is silently replaced with (CmpI (CmpL X 0L) 0) and the
// foo match ends up with the wrong leaf. One fix is to not match both
// reg-reg and reg-zero forms of long-compare. This is unfortunate because
// both forms beat the trinary form of long-compare and both are very useful
// on platforms which have few registers.

// Manifest a CmpL3 result in an integer register. Very painful.
// This is the test to avoid.
instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg cr) %{
  match(Set dst (CmpL3 src1 src2));
  effect(KILL cr);
  ins_cost(DEFAULT_COST * 5 + BRANCH_COST);
  size(24);
  format %{ "CmpL3 $dst,$src1,$src2" %}
  ins_encode %{
    Label done;
    // compare registers
    __ z_cgr($src1$$Register, $src2$$Register);
    // Convert condition code into -1,0,1, where
    // -1 means less
    //  0 means equal
    //  1 means greater.
    if (VM_Version::has_LoadStoreConditional()) {
      Register one       = Z_R0_scratch;
      Register minus_one = Z_R1_scratch;
      __ z_lghi(minus_one, -1);
      __ z_lghi(one, 1);
      __ z_lghi( $dst$$Register, 0);
      __ z_locgr($dst$$Register, one,       Assembler::bcondHigh);
      __ z_locgr($dst$$Register, minus_one, Assembler::bcondLow);
    } else {
      __ clear_reg($dst$$Register, true, false);
      __ z_bre(done);
      __ z_lhi($dst$$Register, 1);
      __ z_brh(done);
      __ z_lhi($dst$$Register, -1);
    }
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

// ============================================================================
// Safepoint Instruction

instruct safePoint() %{
  match(SafePoint);
  predicate(false);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "UNIMPLEMENTED Safepoint_ " %}
  ins_encode(enc_unimplemented());
  ins_pipe(pipe_class_dummy);
%}

instruct safePoint_poll(iRegP poll, flagsReg cr) %{
  match(SafePoint poll);
  effect(USE poll, KILL cr); // R0 is killed, too.
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "TM      #0[,$poll],#111\t # Safepoint: poll for GC" %}
  ins_encode %{
    // Mark the code position where the load from the safepoint
    // polling page was emitted as relocInfo::poll_type.
    __ relocate(relocInfo::poll_type);
    __ load_from_polling_page($poll$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

// ============================================================================

// Call Instructions

// Call Java Static Instruction
instruct CallStaticJavaDirect_dynTOC(method meth) %{
  match(CallStaticJava);
  effect(USE meth);
  ins_cost(CALL_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CALL,static dynTOC $meth; ==> " %}
  ins_encode( z_enc_java_static_call(meth) );
  ins_pipe(pipe_class_dummy);
  ins_alignment(2);
%}

// Call Java Dynamic Instruction
instruct CallDynamicJavaDirect_dynTOC(method meth) %{
  match(CallDynamicJava);
  effect(USE meth);
  ins_cost(CALL_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "CALL,dynamic dynTOC $meth; ==> " %}
  ins_encode(z_enc_java_dynamic_call(meth));
  ins_pipe(pipe_class_dummy);
  ins_alignment(2);
%}

// Call Runtime Instruction
instruct CallRuntimeDirect(method meth) %{
  match(CallRuntime);
  effect(USE meth);
  ins_cost(CALL_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  ins_num_consts(1);
  ins_alignment(2);
  format %{ "CALL,runtime" %}
  ins_encode( z_enc_java_to_runtime_call(meth) );
  ins_pipe(pipe_class_dummy);
%}

// Call runtime without safepoint - same as CallRuntime
instruct CallLeafDirect(method meth) %{
  match(CallLeaf);
  effect(USE meth);
  ins_cost(CALL_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  ins_num_consts(1);
  ins_alignment(2);
  format %{ "CALL,runtime leaf $meth" %}
  ins_encode( z_enc_java_to_runtime_call(meth) );
  ins_pipe(pipe_class_dummy);
%}

// Call runtime without safepoint - same as CallLeaf
instruct CallLeafNoFPDirect(method meth) %{
  match(CallLeafNoFP);
  effect(USE meth);
  ins_cost(CALL_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  ins_num_consts(1);
  format %{ "CALL,runtime leaf nofp $meth" %}
  ins_encode( z_enc_java_to_runtime_call(meth) );
  ins_pipe(pipe_class_dummy);
  ins_alignment(2);
%}

// Tail Call; Jump from runtime stub to Java code.
// Also known as an 'interprocedural jump'.
// Target of jump will eventually return to caller.
// TailJump below removes the return address.
instruct TailCalljmpInd(iRegP jump_target, inline_cache_regP method_ptr) %{
  match(TailCall jump_target method_ptr);
  ins_cost(CALL_COST);
  size(2);
  format %{ "Jmp     $jump_target\t # $method_ptr holds method" %}
  ins_encode %{ __ z_br($jump_target$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

// Return Instruction
instruct Ret() %{
  match(Return);
  size(2);
  format %{ "BR(Z_R14) // branch to link register" %}
  ins_encode %{ __ z_br(Z_R14); %}
  ins_pipe(pipe_class_dummy);
%}

// Tail Jump; remove the return address; jump to target.
// TailCall above leaves the return address around.
// TailJump is used in only one place, the rethrow_Java stub (fancy_jump=2).
// ex_oop (Exception Oop) is needed in %o0 at the jump. As there would be a
// "restore" before this instruction (in Epilogue), we need to materialize it
// in %i0.
instruct tailjmpInd(iRegP jump_target, rarg1RegP ex_oop) %{
  match(TailJump jump_target ex_oop);
  ins_cost(CALL_COST);
  size(8);
  format %{ "TailJump $jump_target" %}
  ins_encode %{
    __ z_lg(Z_ARG2/* issuing pc */, _z_abi(return_pc), Z_SP);
    __ z_br($jump_target$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Create exception oop: created by stack-crawling runtime code.
// Created exception is now available to this handler, and is setup
// just prior to jumping to this handler. No code emitted.
instruct CreateException(rarg1RegP ex_oop) %{
  match(Set ex_oop (CreateEx));
  ins_cost(0);
  size(0);
  format %{ "# exception oop; no code emitted" %}
  ins_encode(/*empty*/);
  ins_pipe(pipe_class_dummy);
%}

// 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);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "Jmp    rethrow_stub" %}
  ins_encode %{
    cbuf.set_insts_mark();
    __ load_const_optimized(Z_R1_scratch, (address)OptoRuntime::rethrow_stub());
    __ z_br(Z_R1_scratch);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Die now.
instruct ShouldNotReachHere() %{
  match(Halt);
  ins_cost(CALL_COST);
  format %{ "ILLTRAP; ShouldNotReachHere" %}
  ins_encode %{
    if (is_reachable()) {
      __ stop(_halt_reason);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// ============================================================================
// The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass
// array for an instance of the superklass. Set a hidden internal cache on a
// hit (cache is checked with exposed code in gen_subtype_check()). Return
// not zero for a miss or zero for a hit. The encoding ALSO sets flags.
instruct partialSubtypeCheck(rarg1RegP index, rarg2RegP sub, rarg3RegP super, flagsReg pcc,
                             rarg4RegP scratch1, rarg5RegP scratch2) %{
  match(Set index (PartialSubtypeCheck sub super));
  effect(KILL pcc, KILL scratch1, KILL scratch2);
  ins_cost(10 * DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "  CALL   PartialSubtypeCheck\n" %}
  ins_encode %{
    AddressLiteral stub_address(StubRoutines::zarch::partial_subtype_check());
    __ load_const_optimized(Z_ARG4, stub_address);
    __ z_basr(Z_R14, Z_ARG4);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct partialSubtypeCheck_vs_zero(flagsReg pcc, rarg2RegP sub, rarg3RegP super, immP0 zero,
                                     rarg1RegP index, rarg4RegP scratch1, rarg5RegP scratch2) %{
  match(Set pcc (CmpI (PartialSubtypeCheck sub super) zero));
  effect(KILL scratch1, KILL scratch2, KILL index);
  ins_cost(10 * DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "CALL   PartialSubtypeCheck_vs_zero\n" %}
  ins_encode %{
    AddressLiteral stub_address(StubRoutines::zarch::partial_subtype_check());
    __ load_const_optimized(Z_ARG4, stub_address);
    __ z_basr(Z_R14, Z_ARG4);
  %}
  ins_pipe(pipe_class_dummy);
%}

// ============================================================================
// inlined locking and unlocking

instruct cmpFastLock(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRegP tmp2) %{
  match(Set pcc (FastLock oop box));
  effect(TEMP tmp1, TEMP tmp2);
  ins_cost(100);
  // TODO: s390 port size(VARIABLE_SIZE); // Uses load_const_optimized.
  format %{ "FASTLOCK  $oop, $box; KILL Z_ARG4, Z_ARG5" %}
  ins_encode %{ __ compiler_fast_lock_object($oop$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

instruct cmpFastUnlock(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRegP tmp2) %{
  match(Set pcc (FastUnlock oop box));
  effect(TEMP tmp1, TEMP tmp2);
  ins_cost(100);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "FASTUNLOCK  $oop, $box; KILL Z_ARG4, Z_ARG5" %}
  ins_encode %{ __ compiler_fast_unlock_object($oop$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

instruct inlineCallClearArrayConst(SSlenDW cnt, iRegP_N2P base, Universe dummy, flagsReg cr) %{
  match(Set dummy (ClearArray cnt base));
  effect(KILL cr);
  ins_cost(100);
  // TODO: s390 port size(VARIABLE_SIZE);       // Variable in size due to varying #instructions.
  format %{ "ClearArrayConst $cnt,$base" %}
  ins_encode %{ __ Clear_Array_Const($cnt$$constant, $base$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

instruct inlineCallClearArrayConstBig(immL cnt, iRegP_N2P base, Universe dummy, allRoddRegL tmpL, flagsReg cr) %{
  match(Set dummy (ClearArray cnt base));
  effect(TEMP tmpL, KILL cr); // R0, R1 are killed, too.
  ins_cost(200);
  // TODO: s390 port size(VARIABLE_SIZE);       // Variable in size due to optimized constant loader.
  format %{ "ClearArrayConstBig $cnt,$base" %}
  ins_encode %{ __ Clear_Array_Const_Big($cnt$$constant, $base$$Register, $tmpL$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

instruct inlineCallClearArray(iRegL cnt, iRegP_N2P base, Universe dummy, allRoddRegL tmpL, flagsReg cr) %{
  match(Set dummy (ClearArray cnt base));
  effect(TEMP tmpL, KILL cr); // R0, R1 are killed, too.
  ins_cost(300);
  // TODO: s390 port size(FIXED_SIZE);  // z/Architecture: emitted code depends on PreferLAoverADD being on/off.
  format %{ "ClearArrayVar $cnt,$base" %}
  ins_encode %{ __ Clear_Array($cnt$$Register, $base$$Register, $tmpL$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

// ============================================================================
// CompactStrings

// String equals
instruct string_equalsL(iRegP str1, iRegP str2, iRegI cnt, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrEquals (Binary str1 str2) cnt));
  effect(TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL);
  ins_cost(300);
  format %{ "String Equals byte[] $str1,$str2,$cnt -> $result" %}
  ins_encode %{
    __ array_equals(false, $str1$$Register, $str2$$Register,
                    $cnt$$Register, $oddReg$$Register, $evenReg$$Register,
                    $result$$Register, true /* byte */);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct string_equalsU(iRegP str1, iRegP str2, iRegI cnt, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrEquals (Binary str1 str2) cnt));
  effect(TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU || ((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::none);
  ins_cost(300);
  format %{ "String Equals char[] $str1,$str2,$cnt -> $result" %}
  ins_encode %{
    __ array_equals(false, $str1$$Register, $str2$$Register,
                    $cnt$$Register, $oddReg$$Register, $evenReg$$Register,
                    $result$$Register, false /* byte */);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct string_equals_imm(iRegP str1, iRegP str2, uimmI8 cnt, iRegI result, flagsReg cr) %{
  match(Set result (StrEquals (Binary str1 str2) cnt));
  effect(KILL cr); // R0 is killed, too.
  predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL || ((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU);
  ins_cost(100);
  format %{ "String Equals byte[] $str1,$str2,$cnt -> $result" %}
  ins_encode %{
    const int cnt_imm = $cnt$$constant;
    if (cnt_imm) { __ z_clc(0, cnt_imm - 1, $str1$$Register, 0, $str2$$Register); }
    __ z_lhi($result$$Register, 1);
    if (cnt_imm) {
      if (VM_Version::has_LoadStoreConditional()) {
        __ z_lhi(Z_R0_scratch, 0);
        __ z_locr($result$$Register, Z_R0_scratch, Assembler::bcondNotEqual);
      } else {
        Label Lskip;
        __ z_bre(Lskip);
        __ clear_reg($result$$Register);
        __ bind(Lskip);
      }
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct string_equalsC_imm(iRegP str1, iRegP str2, immI8 cnt, iRegI result, flagsReg cr) %{
  match(Set result (StrEquals (Binary str1 str2) cnt));
  effect(KILL cr); // R0 is killed, too.
  predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::none);
  ins_cost(100);
  format %{ "String Equals $str1,$str2,$cnt -> $result" %}
  ins_encode %{
    const int cnt_imm = $cnt$$constant; // positive immI8 (7 bits used)
    if (cnt_imm) { __ z_clc(0, (cnt_imm << 1) - 1, $str1$$Register, 0, $str2$$Register); }
    __ z_lhi($result$$Register, 1);
    if (cnt_imm) {
      if (VM_Version::has_LoadStoreConditional()) {
        __ z_lhi(Z_R0_scratch, 0);
        __ z_locr($result$$Register, Z_R0_scratch, Assembler::bcondNotEqual);
      } else {
        Label Lskip;
        __ z_bre(Lskip);
        __ clear_reg($result$$Register);
        __ bind(Lskip);
      }
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// Array equals
instruct array_equalsB(iRegP ary1, iRegP ary2, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (AryEq ary1 ary2));
  effect(TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL);
  ins_cost(300);
  format %{ "Array Equals $ary1,$ary2 -> $result" %}
  ins_encode %{
    __ array_equals(true, $ary1$$Register, $ary2$$Register,
                    noreg, $oddReg$$Register, $evenReg$$Register,
                    $result$$Register, true /* byte */);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct array_equalsC(iRegP ary1, iRegP ary2, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (AryEq ary1 ary2));
  effect(TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
  ins_cost(300);
  format %{ "Array Equals $ary1,$ary2 -> $result" %}
  ins_encode %{
    __ array_equals(true, $ary1$$Register, $ary2$$Register,
                    noreg, $oddReg$$Register, $evenReg$$Register,
                    $result$$Register, false /* byte */);
  %}
  ins_pipe(pipe_class_dummy);
%}

// String CompareTo
instruct string_compareL(iRegP str1, iRegP str2, rarg2RegI cnt1, rarg5RegI cnt2, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
  effect(TEMP_DEF result, USE_KILL cnt1, USE_KILL cnt2, TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL);
  ins_cost(300);
  format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result" %}
  ins_encode %{
    __ string_compare($str1$$Register, $str2$$Register,
                      $cnt1$$Register, $cnt2$$Register,
                      $oddReg$$Register, $evenReg$$Register,
                      $result$$Register, StrIntrinsicNode::LL);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct string_compareU(iRegP str1, iRegP str2, rarg2RegI cnt1, rarg5RegI cnt2, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
  effect(TEMP_DEF result, USE_KILL cnt1, USE_KILL cnt2, TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU || ((StrCompNode*)n)->encoding() == StrIntrinsicNode::none);
  ins_cost(300);
  format %{ "String Compare char[] $str1,$cnt1,$str2,$cnt2 -> $result" %}
  ins_encode %{
    __ string_compare($str1$$Register, $str2$$Register,
                      $cnt1$$Register, $cnt2$$Register,
                      $oddReg$$Register, $evenReg$$Register,
                      $result$$Register, StrIntrinsicNode::UU);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct string_compareLU(iRegP str1, iRegP str2, rarg2RegI cnt1, rarg5RegI cnt2, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
  effect(TEMP_DEF result, USE_KILL cnt1, USE_KILL cnt2, TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU);
  ins_cost(300);
  format %{ "String Compare byte[],char[] $str1,$cnt1,$str2,$cnt2 -> $result" %}
  ins_encode %{
    __ string_compare($str1$$Register, $str2$$Register,
                      $cnt1$$Register, $cnt2$$Register,
                      $oddReg$$Register, $evenReg$$Register,
                      $result$$Register, StrIntrinsicNode::LU);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct string_compareUL(iRegP str1, iRegP str2, rarg2RegI cnt1, rarg5RegI cnt2, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
  effect(TEMP_DEF result, USE_KILL cnt1, USE_KILL cnt2, TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL);
  ins_cost(300);
  format %{ "String Compare char[],byte[] $str1,$cnt1,$str2,$cnt2 -> $result" %}
  ins_encode %{
    __ string_compare($str2$$Register, $str1$$Register,
                      $cnt2$$Register, $cnt1$$Register,
                      $oddReg$$Register, $evenReg$$Register,
                      $result$$Register, StrIntrinsicNode::UL);
  %}
  ins_pipe(pipe_class_dummy);
%}

// String IndexOfChar
instruct indexOfChar_U(iRegP haystack, iRegI haycnt, iRegI ch, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrIndexOfChar (Binary haystack haycnt) ch));
  effect(TEMP_DEF result, TEMP evenReg, TEMP oddReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::U);
  ins_cost(200);
  format %{ "StringUTF16 IndexOfChar [0..$haycnt]($haystack), $ch -> $result" %}
  ins_encode %{
    __ string_indexof_char($result$$Register,
                           $haystack$$Register, $haycnt$$Register,
                           $ch$$Register, 0 /* unused, ch is in register */,
                           $oddReg$$Register, $evenReg$$Register, false /*is_byte*/);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct indexOfChar_L(iRegP haystack, iRegI haycnt, iRegI ch, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrIndexOfChar (Binary haystack haycnt) ch));
  effect(TEMP_DEF result, TEMP evenReg, TEMP oddReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::L);
  ins_cost(200);
  format %{ "StringLatin1 IndexOfChar [0..$haycnt]($haystack), $ch -> $result" %}
  ins_encode %{
    __ string_indexof_char($result$$Register,
                           $haystack$$Register, $haycnt$$Register,
                           $ch$$Register, 0 /* unused, ch is in register */,
                           $oddReg$$Register, $evenReg$$Register, true /*is_byte*/);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct indexOf_imm1_U(iRegP haystack, iRegI haycnt, immP needle, immI_1 needlecnt, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt)));
  effect(TEMP_DEF result, TEMP evenReg, TEMP oddReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU || ((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::none);
  ins_cost(200);
  format %{ "String IndexOf UL [0..$haycnt]($haystack), [0]($needle) -> $result" %}
  ins_encode %{
    immPOper *needleOper = (immPOper *)$needle;
    const TypeOopPtr *t = needleOper->type()->isa_oopptr();
    ciTypeArray* needle_values = t->const_oop()->as_type_array();  // Pointer to live char *
    jchar chr;
#ifdef VM_LITTLE_ENDIAN
    Unimplemented();
#else
    chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) |
           ((jchar)(unsigned char)needle_values->element_value(1).as_byte());
#endif
    __ string_indexof_char($result$$Register,
                           $haystack$$Register, $haycnt$$Register,
                           noreg, chr,
                           $oddReg$$Register, $evenReg$$Register, false /*is_byte*/);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct indexOf_imm1_L(iRegP haystack, iRegI haycnt, immP needle, immI_1 needlecnt, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt)));
  effect(TEMP_DEF result, TEMP evenReg, TEMP oddReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL);
  ins_cost(200);
  format %{ "String IndexOf L [0..$haycnt]($haystack), [0]($needle) -> $result" %}
  ins_encode %{
    immPOper *needleOper = (immPOper *)$needle;
    const TypeOopPtr *t = needleOper->type()->isa_oopptr();
    ciTypeArray* needle_values = t->const_oop()->as_type_array();  // Pointer to live char *
    jchar chr = (jchar)needle_values->element_value(0).as_byte();
    __ string_indexof_char($result$$Register,
                           $haystack$$Register, $haycnt$$Register,
                           noreg, chr,
                           $oddReg$$Register, $evenReg$$Register, true /*is_byte*/);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct indexOf_imm1_UL(iRegP haystack, iRegI haycnt, immP needle, immI_1 needlecnt, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt)));
  effect(TEMP_DEF result, TEMP evenReg, TEMP oddReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL);
  ins_cost(200);
  format %{ "String IndexOf UL [0..$haycnt]($haystack), [0]($needle) -> $result" %}
  ins_encode %{
    immPOper *needleOper = (immPOper *)$needle;
    const TypeOopPtr *t = needleOper->type()->isa_oopptr();
    ciTypeArray* needle_values = t->const_oop()->as_type_array();  // Pointer to live char *
    jchar chr = (jchar)needle_values->element_value(0).as_byte();
    __ string_indexof_char($result$$Register,
                           $haystack$$Register, $haycnt$$Register,
                           noreg, chr,
                           $oddReg$$Register, $evenReg$$Register, false /*is_byte*/);
  %}
  ins_pipe(pipe_class_dummy);
%}

// String IndexOf
instruct indexOf_imm_U(iRegP haystack, rarg2RegI haycnt, iRegP needle, immI16 needlecntImm, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm)));
  effect(TEMP_DEF result, USE_KILL haycnt, TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU || ((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::none);
  ins_cost(250);
  format %{ "String IndexOf U [0..$needlecntImm]($needle) .in. [0..$haycnt]($haystack) -> $result" %}
  ins_encode %{
    __ string_indexof($result$$Register,
                      $haystack$$Register, $haycnt$$Register,
                      $needle$$Register, noreg, $needlecntImm$$constant,
                      $oddReg$$Register, $evenReg$$Register, StrIntrinsicNode::UU);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct indexOf_imm_L(iRegP haystack, rarg2RegI haycnt, iRegP needle, immI16 needlecntImm, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm)));
  effect(TEMP_DEF result, USE_KILL haycnt, TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL);
  ins_cost(250);
  format %{ "String IndexOf L [0..$needlecntImm]($needle) .in. [0..$haycnt]($haystack) -> $result" %}
  ins_encode %{
    __ string_indexof($result$$Register,
                      $haystack$$Register, $haycnt$$Register,
                      $needle$$Register, noreg, $needlecntImm$$constant,
                      $oddReg$$Register, $evenReg$$Register, StrIntrinsicNode::LL);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct indexOf_imm_UL(iRegP haystack, rarg2RegI haycnt, iRegP needle, immI16 needlecntImm, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm)));
  effect(TEMP_DEF result, USE_KILL haycnt, TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL);
  ins_cost(250);
  format %{ "String IndexOf UL [0..$needlecntImm]($needle) .in. [0..$haycnt]($haystack) -> $result" %}
  ins_encode %{
    __ string_indexof($result$$Register,
                      $haystack$$Register, $haycnt$$Register,
                      $needle$$Register, noreg, $needlecntImm$$constant,
                      $oddReg$$Register, $evenReg$$Register, StrIntrinsicNode::UL);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct indexOf_U(iRegP haystack, rarg2RegI haycnt, iRegP needle, rarg5RegI needlecnt, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt)));
  effect(TEMP_DEF result, USE_KILL haycnt, USE_KILL needlecnt, TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU || ((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::none);
  ins_cost(300);
  format %{ "String IndexOf U [0..$needlecnt]($needle) .in. [0..$haycnt]($haystack) -> $result" %}
  ins_encode %{
    __ string_indexof($result$$Register,
                      $haystack$$Register, $haycnt$$Register,
                      $needle$$Register, $needlecnt$$Register, 0,
                      $oddReg$$Register, $evenReg$$Register, StrIntrinsicNode::UU);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct indexOf_L(iRegP haystack, rarg2RegI haycnt, iRegP needle, rarg5RegI needlecnt, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt)));
  effect(TEMP_DEF result, USE_KILL haycnt, USE_KILL needlecnt, TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL);
  ins_cost(300);
  format %{ "String IndexOf L [0..$needlecnt]($needle) .in. [0..$haycnt]($haystack) -> $result" %}
  ins_encode %{
    __ string_indexof($result$$Register,
                      $haystack$$Register, $haycnt$$Register,
                      $needle$$Register, $needlecnt$$Register, 0,
                      $oddReg$$Register, $evenReg$$Register, StrIntrinsicNode::LL);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct indexOf_UL(iRegP haystack, rarg2RegI haycnt, iRegP needle, rarg5RegI needlecnt, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
  match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt)));
  effect(TEMP_DEF result, USE_KILL haycnt, USE_KILL needlecnt, TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too.
  predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL);
  ins_cost(300);
  format %{ "String IndexOf UL [0..$needlecnt]($needle) .in. [0..$haycnt]($haystack) -> $result" %}
  ins_encode %{
    __ string_indexof($result$$Register,
                      $haystack$$Register, $haycnt$$Register,
                      $needle$$Register, $needlecnt$$Register, 0,
                      $oddReg$$Register, $evenReg$$Register, StrIntrinsicNode::UL);
  %}
  ins_pipe(pipe_class_dummy);
%}

// char[] to byte[] compression
instruct string_compress(iRegP src, iRegP dst, iRegI result, iRegI len, iRegI tmp, flagsReg cr) %{
  match(Set result (StrCompressedCopy src (Binary dst len)));
  effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too.
  ins_cost(300);
  format %{ "String Compress $src->$dst($len) -> $result" %}
  ins_encode %{
    __ string_compress($result$$Register, $src$$Register, $dst$$Register, $len$$Register,
                       $tmp$$Register, false, false);
  %}
  ins_pipe(pipe_class_dummy);
%}

// byte[] to char[] inflation. trot implementation is shorter, but slower than the unrolled icm(h) loop.
//instruct string_inflate_trot(Universe dummy, iRegP src, revenRegP dst, roddRegI len, iRegI tmp, flagsReg cr) %{
//  match(Set dummy (StrInflatedCopy src (Binary dst len)));
//  effect(USE_KILL dst, USE_KILL len, TEMP tmp, KILL cr); // R0, R1 are killed, too.
//  predicate(VM_Version::has_ETF2Enhancements());
//  ins_cost(300);
//  format %{ "String Inflate (trot) $dst,$src($len)" %}
//  ins_encode %{
//    __ string_inflate_trot($src$$Register, $dst$$Register, $len$$Register, $tmp$$Register);
//  %}
//  ins_pipe(pipe_class_dummy);
//%}

// byte[] to char[] inflation
instruct string_inflate(Universe dummy, iRegP src, iRegP dst, iRegI len, iRegI tmp, flagsReg cr) %{
  match(Set dummy (StrInflatedCopy src (Binary dst len)));
  effect(TEMP tmp, KILL cr); // R0, R1 are killed, too.
  ins_cost(300);
  format %{ "String Inflate $src->$dst($len)" %}
  ins_encode %{
    __ string_inflate($src$$Register, $dst$$Register, $len$$Register, $tmp$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

// byte[] to char[] inflation
instruct string_inflate_const(Universe dummy, iRegP src, iRegP dst, iRegI tmp, immI len, flagsReg cr) %{
  match(Set dummy (StrInflatedCopy src (Binary dst len)));
  effect(TEMP tmp, KILL cr); // R0, R1 are killed, too.
  ins_cost(300);
  format %{ "String Inflate (constLen) $src->$dst($len)" %}
  ins_encode %{
    __ string_inflate_const($src$$Register, $dst$$Register, $tmp$$Register, $len$$constant);
  %}
  ins_pipe(pipe_class_dummy);
%}

// StringCoding.java intrinsics
instruct count_positives(iRegP ary1, iRegI len, iRegI result, iRegI tmp, flagsReg cr) %{
  match(Set result (CountPositives ary1 len));
  effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too.
  ins_cost(300);
  format %{ "count positives byte[] $ary1($len) -> $result" %}
  ins_encode %{
    __ count_positives($result$$Register, $ary1$$Register, $len$$Register, $tmp$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

// encode char[] to byte[] in ISO_8859_1
instruct encode_iso_array(iRegP src, iRegP dst, iRegI result, iRegI len, iRegI tmp, flagsReg cr) %{
  predicate(!((EncodeISOArrayNode*)n)->is_ascii());
  match(Set result (EncodeISOArray src (Binary dst len)));
  effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too.
  ins_cost(300);
  format %{ "Encode iso array $src->$dst($len) -> $result" %}
  ins_encode %{
    __ string_compress($result$$Register, $src$$Register, $dst$$Register, $len$$Register,
                       $tmp$$Register, true, false);
  %}
  ins_pipe(pipe_class_dummy);
%}

// encode char[] to byte[] in ASCII
instruct encode_ascii_array(iRegP src, iRegP dst, iRegI result, iRegI len, iRegI tmp, flagsReg cr) %{
  predicate(((EncodeISOArrayNode*)n)->is_ascii());
  match(Set result (EncodeISOArray src (Binary dst len)));
  effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too.
  ins_cost(300);
  format %{ "Encode ascii array $src->$dst($len) -> $result" %}
  ins_encode %{
    __ string_compress($result$$Register, $src$$Register, $dst$$Register, $len$$Register,
                       $tmp$$Register, true, true);
  %}
  ins_pipe(pipe_class_dummy);
%}


//----------PEEPHOLE RULES-----------------------------------------------------
// These must follow all instruction definitions as they use the names
// defined in the instructions definitions.
//
// peepmatch (root_instr_name [preceeding_instruction]*);
//
// peepconstraint %{
// (instruction_number.operand_name relational_op instruction_number.operand_name
//  [, ...]);
// // instruction numbers are zero-based using left to right order in peepmatch
//
// peepreplace (instr_name([instruction_number.operand_name]*));
// // provide an instruction_number.operand_name for each operand that appears
// // in the replacement instruction's match rule
//
// ---------VM FLAGS---------------------------------------------------------
//
// All peephole optimizations can be turned off using -XX:-OptoPeephole
//
// Each peephole rule is given an identifying number starting with zero and
// increasing by one in the order seen by the parser. An individual peephole
// can be enabled, and all others disabled, by using -XX:OptoPeepholeAt=#
// on the command-line.
//
// ---------CURRENT LIMITATIONS----------------------------------------------
//
// Only match adjacent instructions in same basic block
// Only equality constraints
// Only constraints between operands, not (0.dest_reg == EAX_enc)
// Only one replacement instruction
//
// ---------EXAMPLE----------------------------------------------------------
//
// // pertinent parts of existing instructions in architecture description
// instruct movI(eRegI dst, eRegI src) %{
//   match(Set dst (CopyI src));
// %}
//
// instruct incI_eReg(eRegI dst, immI1 src, eFlagsReg cr) %{
//   match(Set dst (AddI dst src));
//   effect(KILL cr);
// %}
//
// // Change (inc mov) to lea
// peephole %{
//   // increment preceded by register-register move
//   peepmatch (incI_eReg movI);
//   // require that the destination register of the increment
//   // match the destination register of the move
//   peepconstraint (0.dst == 1.dst);
//   // construct a replacement instruction that sets
//   // the destination to (move's source register + one)
//   peepreplace (leaI_eReg_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_eReg movI);
//   peepconstraint (0.dst == 1.dst);
//   peepreplace (leaI_eReg_immI(0.dst 1.src 0.src));
// %}
//
// peephole %{
//   peepmatch (decI_eReg movI);
//   peepconstraint (0.dst == 1.dst);
//   peepreplace (leaI_eReg_immI(0.dst 1.src 0.src));
// %}
//
// peephole %{
//   peepmatch (addI_eReg_imm movI);
//   peepconstraint (0.dst == 1.dst);
//   peepreplace (leaI_eReg_immI(0.dst 1.src 0.src));
// %}
//
// peephole %{
//   peepmatch (addP_eReg_imm movP);
//   peepconstraint (0.dst == 1.dst);
//   peepreplace (leaP_eReg_immI(0.dst 1.src 0.src));
// %}


//  This peephole rule does not work, probably because ADLC can't handle two effects:
//  Effect 1 is defining 0.op1 and effect 2 is setting CC
// condense a load from memory and subsequent test for zero
// into a single, more efficient ICM instruction.
// peephole %{
//   peepmatch (compI_iReg_imm0 loadI);
//   peepconstraint (1.dst == 0.op1);
//   peepreplace (loadtest15_iReg_mem(0.op1 0.op1 1.mem));
// %}

// // Change load of spilled value to only a spill
// instruct storeI(memory mem, eRegI src) %{
//   match(Set mem (StoreI mem src));
// %}
//
// instruct loadI(eRegI dst, memory mem) %{
//   match(Set dst (LoadI mem));
// %}
//
peephole %{
  peepmatch (loadI storeI);
  peepconstraint (1.src == 0.dst, 1.mem == 0.mem);
  peepreplace (storeI(1.mem 1.mem 1.src));
%}

peephole %{
  peepmatch (loadL storeL);
  peepconstraint (1.src == 0.dst, 1.mem == 0.mem);
  peepreplace (storeL(1.mem 1.mem 1.src));
%}

peephole %{
  peepmatch (loadP storeP);
  peepconstraint (1.src == 0.dst, 1.dst == 0.mem);
  peepreplace (storeP(1.dst 1.dst 1.src));
%}

//----------SUPERWORD RULES---------------------------------------------------

//  Expand rules for special cases

instruct expand_storeF(stackSlotF mem, regF src) %{
  // No match rule, false predicate, for expand only.
  effect(DEF mem, USE src);
  predicate(false);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "STE      $src,$mem\t # replicate(float2stack)" %}
  opcode(STE_ZOPC, STE_ZOPC);
  ins_encode(z_form_rt_mem(src, mem));
  ins_pipe(pipe_class_dummy);
%}

instruct expand_LoadLogical_I2L(iRegL dst, stackSlotF mem) %{
  // No match rule, false predicate, for expand only.
  effect(DEF dst, USE mem);
  predicate(false);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LLGF     $dst,$mem\t # replicate(stack2reg(unsigned))" %}
  opcode(LLGF_ZOPC, LLGF_ZOPC);
  ins_encode(z_form_rt_mem(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar int to packed int values (8 Bytes)
instruct expand_Repl2I_reg(iRegL dst, iRegL src) %{
  // Dummy match rule, false predicate, for expand only.
  match(Set dst (ConvI2L src));
  predicate(false);
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "REPLIC2F $dst,$src\t # replicate(pack2F)" %}
  ins_encode %{
    if ($dst$$Register == $src$$Register) {
      __ z_sllg(Z_R0_scratch, $src$$Register, 64-32);
      __ z_ogr($dst$$Register, Z_R0_scratch);
    }  else {
      __ z_sllg($dst$$Register, $src$$Register, 64-32);
      __ z_ogr( $dst$$Register, $src$$Register);
    }
  %}
  ins_pipe(pipe_class_dummy);
%}

// Replication

// Exploit rotate_then_insert, if available
// Replicate scalar byte to packed byte values (8 Bytes).
instruct Repl8B_reg_risbg(iRegL dst, iRegI src, flagsReg cr) %{
  match(Set dst (ReplicateB src));
  effect(KILL cr);
  predicate((n->as_Vector()->length() == 8));
  format %{ "REPLIC8B $dst,$src\t # pack8B" %}
  ins_encode %{
    if ($dst$$Register != $src$$Register) {
      __ z_lgr($dst$$Register, $src$$Register);
    }
    __ rotate_then_insert($dst$$Register, $dst$$Register, 48, 55,  8, false);
    __ rotate_then_insert($dst$$Register, $dst$$Register, 32, 47, 16, false);
    __ rotate_then_insert($dst$$Register, $dst$$Register,  0, 31, 32, false);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar byte to packed byte values (8 Bytes).
instruct Repl8B_imm(iRegL dst, immB_n0m1 src) %{
  match(Set dst (ReplicateB src));
  predicate(n->as_Vector()->length() == 8);
  ins_should_rematerialize(true);
  format %{ "REPLIC8B $dst,$src\t # pack8B imm" %}
  ins_encode %{
    int64_t  Isrc8 = $src$$constant & 0x000000ff;
    int64_t Isrc16 =  Isrc8 <<  8 |  Isrc8;
    int64_t Isrc32 = Isrc16 << 16 | Isrc16;
    assert(Isrc8 != 0x000000ff && Isrc8 != 0, "should be handled by other match rules.");

    __ z_llilf($dst$$Register, Isrc32);
    __ z_iihf($dst$$Register, Isrc32);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar byte to packed byte values (8 Bytes).
instruct Repl8B_imm0(iRegL dst, immI_0 src) %{
  match(Set dst (ReplicateB src));
  predicate(n->as_Vector()->length() == 8);
  ins_should_rematerialize(true);
  format %{ "REPLIC8B $dst,$src\t # pack8B imm0" %}
  ins_encode %{ __ z_laz($dst$$Register, 0, Z_R0); %}
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar byte to packed byte values (8 Bytes).
instruct Repl8B_immm1(iRegL dst, immB_minus1 src) %{
  match(Set dst (ReplicateB src));
  predicate(n->as_Vector()->length() == 8);
  ins_should_rematerialize(true);
  format %{ "REPLIC8B $dst,$src\t # pack8B immm1" %}
  ins_encode %{ __ z_lghi($dst$$Register, -1); %}
  ins_pipe(pipe_class_dummy);
%}

// Exploit rotate_then_insert, if available
// Replicate scalar short to packed short values (8 Bytes).
instruct Repl4S_reg_risbg(iRegL dst, iRegI src, flagsReg cr) %{
  match(Set dst (ReplicateS src));
  effect(KILL cr);
  predicate((n->as_Vector()->length() == 4));
  format %{ "REPLIC4S $dst,$src\t # pack4S" %}
  ins_encode %{
    if ($dst$$Register != $src$$Register) {
      __ z_lgr($dst$$Register, $src$$Register);
    }
    __ rotate_then_insert($dst$$Register, $dst$$Register, 32, 47, 16, false);
    __ rotate_then_insert($dst$$Register, $dst$$Register,  0, 31, 32, false);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar short to packed short values (8 Bytes).
instruct Repl4S_imm(iRegL dst, immS_n0m1 src) %{
  match(Set dst (ReplicateS src));
  predicate(n->as_Vector()->length() == 4);
  ins_should_rematerialize(true);
  format %{ "REPLIC4S $dst,$src\t # pack4S imm" %}
  ins_encode %{
    int64_t Isrc16 = $src$$constant & 0x0000ffff;
    int64_t Isrc32 = Isrc16 << 16 | Isrc16;
    assert(Isrc16 != 0x0000ffff && Isrc16 != 0, "Repl4S_imm: (src == " INT64_FORMAT
           ") should be handled by other match rules.", $src$$constant);

    __ z_llilf($dst$$Register, Isrc32);
    __ z_iihf($dst$$Register, Isrc32);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar short to packed short values (8 Bytes).
instruct Repl4S_imm0(iRegL dst, immI_0 src) %{
  match(Set dst (ReplicateS src));
  predicate(n->as_Vector()->length() == 4);
  ins_should_rematerialize(true);
  format %{ "REPLIC4S $dst,$src\t # pack4S imm0" %}
  ins_encode %{ __ z_laz($dst$$Register, 0, Z_R0); %}
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar short to packed short values (8 Bytes).
instruct Repl4S_immm1(iRegL dst, immS_minus1 src) %{
  match(Set dst (ReplicateS src));
  predicate(n->as_Vector()->length() == 4);
  ins_should_rematerialize(true);
  format %{ "REPLIC4S $dst,$src\t # pack4S immm1" %}
  ins_encode %{ __ z_lghi($dst$$Register, -1); %}
  ins_pipe(pipe_class_dummy);
%}

// Exploit rotate_then_insert, if available.
// Replicate scalar int to packed int values (8 Bytes).
instruct Repl2I_reg_risbg(iRegL dst, iRegI src, flagsReg cr) %{
  match(Set dst (ReplicateI src));
  effect(KILL cr);
  predicate((n->as_Vector()->length() == 2));
  format %{ "REPLIC2I $dst,$src\t # pack2I" %}
  ins_encode %{
    if ($dst$$Register != $src$$Register) {
      __ z_lgr($dst$$Register, $src$$Register);
    }
    __ rotate_then_insert($dst$$Register, $dst$$Register, 0, 31, 32, false);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar int to packed int values (8 Bytes).
instruct Repl2I_imm(iRegL dst, immI_n0m1 src) %{
  match(Set dst (ReplicateI src));
  predicate(n->as_Vector()->length() == 2);
  ins_should_rematerialize(true);
  format %{ "REPLIC2I $dst,$src\t # pack2I imm" %}
  ins_encode %{
    int64_t Isrc32 = $src$$constant;
    assert(Isrc32 != -1 && Isrc32 != 0, "should be handled by other match rules.");

    __ z_llilf($dst$$Register, Isrc32);
    __ z_iihf($dst$$Register, Isrc32);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar int to packed int values (8 Bytes).
instruct Repl2I_imm0(iRegL dst, immI_0 src) %{
  match(Set dst (ReplicateI src));
  predicate(n->as_Vector()->length() == 2);
  ins_should_rematerialize(true);
  format %{ "REPLIC2I $dst,$src\t # pack2I imm0" %}
  ins_encode %{ __ z_laz($dst$$Register, 0, Z_R0); %}
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar int to packed int values (8 Bytes).
instruct Repl2I_immm1(iRegL dst, immI_minus1 src) %{
  match(Set dst (ReplicateI src));
  predicate(n->as_Vector()->length() == 2);
  ins_should_rematerialize(true);
  format %{ "REPLIC2I $dst,$src\t # pack2I immm1" %}
  ins_encode %{ __ z_lghi($dst$$Register, -1); %}
  ins_pipe(pipe_class_dummy);
%}

//

instruct Repl2F_reg_indirect(iRegL dst, regF src, flagsReg cr) %{
  match(Set dst (ReplicateF src));
  effect(KILL cr);
  predicate(!VM_Version::has_FPSupportEnhancements() && n->as_Vector()->length() == 2);
  format %{ "REPLIC2F $dst,$src\t # pack2F indirect" %}
  expand %{
    stackSlotF tmp;
    iRegL      tmp2;
    expand_storeF(tmp, src);
    expand_LoadLogical_I2L(tmp2, tmp);
    expand_Repl2I_reg(dst, tmp2);
  %}
%}

// Replicate scalar float to packed float values in GREG (8 Bytes).
instruct Repl2F_reg_direct(iRegL dst, regF src, flagsReg cr) %{
  match(Set dst (ReplicateF src));
  effect(KILL cr);
  predicate(VM_Version::has_FPSupportEnhancements() && n->as_Vector()->length() == 2);
  format %{ "REPLIC2F $dst,$src\t # pack2F direct" %}
  ins_encode %{
    assert(VM_Version::has_FPSupportEnhancements(), "encoder should never be called on old H/W");
    __ z_lgdr($dst$$Register, $src$$FloatRegister);

    __ z_srlg(Z_R0_scratch, $dst$$Register, 32);  // Floats are left-justified in 64bit reg.
    __ z_iilf($dst$$Register, 0);                 // Save a "result not ready" stall.
    __ z_ogr($dst$$Register, Z_R0_scratch);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar float immediate to packed float values in GREG (8 Bytes).
instruct Repl2F_imm(iRegL dst, immF src) %{
  match(Set dst (ReplicateF src));
  predicate(n->as_Vector()->length() == 2);
  ins_should_rematerialize(true);
  format %{ "REPLIC2F $dst,$src\t # pack2F imm" %}
  ins_encode %{
    union {
      int   Isrc32;
      float Fsrc32;
    };
    Fsrc32 = $src$$constant;
    __ z_llilf($dst$$Register, Isrc32);
    __ z_iihf($dst$$Register, Isrc32);
  %}
  ins_pipe(pipe_class_dummy);
%}

// Replicate scalar float immediate zeroes to packed float values in GREG (8 Bytes).
// Do this only for 'real' zeroes, especially don't loose sign of negative zeroes.
instruct Repl2F_imm0(iRegL dst, immFp0 src) %{
  match(Set dst (ReplicateF src));
  predicate(n->as_Vector()->length() == 2);
  ins_should_rematerialize(true);
  format %{ "REPLIC2F $dst,$src\t # pack2F imm0" %}
  ins_encode %{ __ z_laz($dst$$Register, 0, Z_R0); %}
  ins_pipe(pipe_class_dummy);
%}

// Load/Store vector

// Store Aligned Packed Byte register to memory (8 Bytes).
instruct storeA8B(memory mem, iRegL src) %{
  match(Set mem (StoreVector mem src));
  predicate(n->as_StoreVector()->memory_size() == 8);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "STG     $src,$mem\t # ST(packed8B)" %}
  opcode(STG_ZOPC, STG_ZOPC);
  ins_encode(z_form_rt_mem_opt(src, mem));
  ins_pipe(pipe_class_dummy);
%}

instruct loadV8(iRegL dst, memory mem) %{
  match(Set dst (LoadVector mem));
  predicate(n->as_LoadVector()->memory_size() == 8);
  ins_cost(MEMORY_REF_COST);
  // TODO: s390 port size(VARIABLE_SIZE);
  format %{ "LG      $dst,$mem\t # L(packed8B)" %}
  opcode(LG_ZOPC, LG_ZOPC);
  ins_encode(z_form_rt_mem_opt(dst, mem));
  ins_pipe(pipe_class_dummy);
%}

// Reinterpret: only one vector size used
instruct reinterpret(iRegL dst) %{
  match(Set dst (VectorReinterpret dst));
  ins_cost(0);
  format %{ "reinterpret $dst" %}
  ins_encode( /*empty*/ );
  ins_pipe(pipe_class_dummy);
%}

//----------POPULATION COUNT RULES--------------------------------------------

// Byte reverse

instruct bytes_reverse_int(iRegI dst, iRegI src) %{
  match(Set dst (ReverseBytesI src));
  predicate(UseByteReverseInstruction);  // See Matcher::match_rule_supported
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "LRVR    $dst,$src\t # byte reverse int" %}
  opcode(LRVR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

instruct bytes_reverse_long(iRegL dst, iRegL src) %{
  match(Set dst (ReverseBytesL src));
  predicate(UseByteReverseInstruction);  // See Matcher::match_rule_supported
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "LRVGR   $dst,$src\t # byte reverse long" %}
  opcode(LRVGR_ZOPC);
  ins_encode(z_rreform(dst, src));
  ins_pipe(pipe_class_dummy);
%}

// Leading zeroes

// The instruction FLOGR (Find Leftmost One in Grande (64bit) Register)
// returns the bit position of the leftmost 1 in the 64bit source register.
// As the bits are numbered from left to right (0..63), the returned
// position index is equivalent to the number of leading zeroes.
// If no 1-bit is found (i.e. the register contains zero), the instruction
// returns position 64. That's exactly what we need.

instruct countLeadingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr) %{
  match(Set dst (CountLeadingZerosI src));
  effect(KILL tmp, KILL cr);
  ins_cost(3 * DEFAULT_COST);
  size(14);
  format %{ "SLLG    $dst,$src,32\t # no need to always count 32 zeroes first\n\t"
            "IILH    $dst,0x8000 \t # insert \"stop bit\" to force result 32 for zero src.\n\t"
            "FLOGR   $dst,$dst"
         %}
  ins_encode %{
    // Performance experiments indicate that "FLOGR" is using some kind of
    // iteration to find the leftmost "1" bit.
    //
    // The prior implementation zero-extended the 32-bit argument to 64 bit,
    // thus forcing "FLOGR" to count 32 bits of which we know they are zero.
    // We could gain measurable speedup in micro benchmark:
    //
    //               leading   trailing
    //   z10:   int     2.04       1.68
    //         long     1.00       1.02
    //   z196:  int     0.99       1.23
    //         long     1.00       1.11
    //
    // By shifting the argument into the high-word instead of zero-extending it.
    // The add'l branch on condition (taken for a zero argument, very infrequent,
    // good prediction) is well compensated for by the savings.
    //
    // We leave the previous implementation in for some time in the future when
    // the "FLOGR" instruction may become less iterative.

    // Version 2: shows 62%(z9), 204%(z10), -1%(z196) improvement over original
    __ z_sllg($dst$$Register, $src$$Register, 32); // No need to always count 32 zeroes first.
    __ z_iilh($dst$$Register, 0x8000);   // Insert "stop bit" to force result 32 for zero src.
    __ z_flogr($dst$$Register, $dst$$Register);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct countLeadingZerosL(revenRegI dst, iRegL src, roddRegI tmp, flagsReg cr) %{
  match(Set dst (CountLeadingZerosL src));
  effect(KILL tmp, KILL cr);
  ins_cost(DEFAULT_COST);
  size(4);
  format %{ "FLOGR   $dst,$src \t # count leading zeros (long)\n\t" %}
  ins_encode %{ __ z_flogr($dst$$Register, $src$$Register); %}
  ins_pipe(pipe_class_dummy);
%}

// trailing zeroes

// We transform the trailing zeroes problem to a leading zeroes problem
// such that can use the FLOGR instruction to our advantage.

// With
//   tmp1 = src - 1
// we flip all trailing zeroes to ones and the rightmost one to zero.
// All other bits remain unchanged.
// With the complement
//   tmp2 = ~src
// we get all ones in the trailing zeroes positions. Thus,
//   tmp3 = tmp1 & tmp2
// yields ones in the trailing zeroes positions and zeroes elsewhere.
// Now we can apply FLOGR and get 64-(trailing zeroes).
instruct countTrailingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr) %{
  match(Set dst (CountTrailingZerosI src));
  effect(TEMP_DEF dst, TEMP tmp, KILL cr);
  ins_cost(8 * DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);  // Emitted code depends on PreferLAoverADD being on/off.
  format %{ "LLGFR   $dst,$src  \t # clear upper 32 bits (we are dealing with int)\n\t"
            "LCGFR   $tmp,$src  \t # load 2's complement (32->64 bit)\n\t"
            "AGHI    $dst,-1    \t # tmp1 = src-1\n\t"
            "AGHI    $tmp,-1    \t # tmp2 = -src-1 = ~src\n\t"
            "NGR     $dst,$tmp  \t # tmp3 = tmp1&tmp2\n\t"
            "FLOGR   $dst,$dst  \t # count trailing zeros (int)\n\t"
            "AHI     $dst,-64   \t # tmp4 = 64-(trailing zeroes)-64\n\t"
            "LCR     $dst,$dst  \t # res = -tmp4"
         %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc = $src$$Register;
    // Rtmp only needed for for zero-argument shortcut. With kill effect in
    // match rule Rsrc = roddReg would be possible, saving one register.
    Register Rtmp = $tmp$$Register;

    assert_different_registers(Rdst, Rsrc, Rtmp);

    // Algorithm:
    // - Isolate the least significant (rightmost) set bit using (src & (-src)).
    //   All other bits in the result are zero.
    // - Find the "leftmost one" bit position in the single-bit result from previous step.
    // - 63-("leftmost one" bit position) gives the # of trailing zeros.

    // Version 2: shows 79%(z9), 68%(z10), 23%(z196) improvement over original.
    Label done;
    __ load_const_optimized(Rdst, 32); // Prepare for shortcut (zero argument), result will be 32.
    __ z_lcgfr(Rtmp, Rsrc);
    __ z_bre(done);                    // Taken very infrequently, good prediction, no BHT entry.

    __ z_nr(Rtmp, Rsrc);               // (src) & (-src) leaves nothing but least significant bit.
    __ z_ahi(Rtmp,  -1);               // Subtract one to fill all trailing zero positions with ones.
                                       // Use 32bit op to prevent borrow propagation (case Rdst = 0x80000000)
                                       // into upper half of reg. Not relevant with sllg below.
    __ z_sllg(Rdst, Rtmp, 32);         // Shift interesting contents to upper half of register.
    __ z_bre(done);                    // Shortcut for argument = 1, result will be 0.
                                       // Depends on CC set by ahi above.
                                       // Taken very infrequently, good prediction, no BHT entry.
                                       // Branch delayed to have Rdst set correctly (Rtmp == 0(32bit)
                                       // after SLLG Rdst == 0(64bit)).
    __ z_flogr(Rdst, Rdst);            // Kills tmp which is the oddReg for dst.
    __ add2reg(Rdst,  -32);            // 32-pos(leftmost1) is #trailing zeros
    __ z_lcgfr(Rdst, Rdst);            // Provide 64bit result at no cost.
    __ bind(done);
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct countTrailingZerosL(revenRegI dst, iRegL src, roddRegL tmp, flagsReg cr) %{
  match(Set dst (CountTrailingZerosL src));
  effect(TEMP_DEF dst, KILL tmp, KILL cr);
  ins_cost(8 * DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);  // Emitted code depends on PreferLAoverADD being on/off.
  format %{ "LCGR    $dst,$src  \t # preserve src\n\t"
            "NGR     $dst,$src  \t #\n\t"
            "AGHI    $dst,-1    \t # tmp1 = src-1\n\t"
            "FLOGR   $dst,$dst  \t # count trailing zeros (long), kill $tmp\n\t"
            "AHI     $dst,-64   \t # tmp4 = 64-(trailing zeroes)-64\n\t"
            "LCR     $dst,$dst  \t #"
         %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc = $src$$Register;
    assert_different_registers(Rdst, Rsrc); // Rtmp == Rsrc allowed.

    // New version: shows 5%(z9), 2%(z10), 11%(z196) improvement over original.
    __ z_lcgr(Rdst, Rsrc);
    __ z_ngr(Rdst, Rsrc);
    __ add2reg(Rdst,   -1);
    __ z_flogr(Rdst, Rdst); // Kills tmp which is the oddReg for dst.
    __ add2reg(Rdst,  -64);
    __ z_lcgfr(Rdst, Rdst); // Provide 64bit result at no cost.
  %}
  ins_pipe(pipe_class_dummy);
%}


// bit count

instruct popCountI(iRegI dst, iRegI src, iRegI tmp, flagsReg cr) %{
  match(Set dst (PopCountI src));
  effect(TEMP_DEF dst, TEMP tmp, KILL cr);
  predicate(UsePopCountInstruction && VM_Version::has_PopCount());
  ins_cost(DEFAULT_COST);
  size(24);
  format %{ "POPCNT  $dst,$src\t # pop count int" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc = $src$$Register;
    Register Rtmp = $tmp$$Register;

    // Prefer compile-time assertion over run-time SIGILL.
    assert(VM_Version::has_PopCount(), "bad predicate for countLeadingZerosI");
    assert_different_registers(Rdst, Rtmp);

    // Version 2: shows 10%(z196) improvement over original.
    __ z_popcnt(Rdst, Rsrc);
    __ z_srlg(Rtmp, Rdst, 16); // calc  byte4+byte6 and byte5+byte7
    __ z_alr(Rdst, Rtmp);      //   into byte6 and byte7
    __ z_srlg(Rtmp, Rdst,  8); // calc (byte4+byte6) + (byte5+byte7)
    __ z_alr(Rdst, Rtmp);      //   into byte7
    __ z_llgcr(Rdst, Rdst);    // zero-extend sum
  %}
  ins_pipe(pipe_class_dummy);
%}

instruct popCountL(iRegI dst, iRegL src, iRegL tmp, flagsReg cr) %{
  match(Set dst (PopCountL src));
  effect(TEMP_DEF dst, TEMP tmp, KILL cr);
  predicate(UsePopCountInstruction && VM_Version::has_PopCount());
  ins_cost(DEFAULT_COST);
  // TODO: s390 port size(FIXED_SIZE);
  format %{ "POPCNT  $dst,$src\t # pop count long" %}
  ins_encode %{
    Register Rdst = $dst$$Register;
    Register Rsrc = $src$$Register;
    Register Rtmp = $tmp$$Register;

    // Prefer compile-time assertion over run-time SIGILL.
    assert(VM_Version::has_PopCount(), "bad predicate for countLeadingZerosI");
    assert_different_registers(Rdst, Rtmp);

    // Original version. Using LA instead of algr seems to be a really bad idea (-35%).
    __ z_popcnt(Rdst, Rsrc);
    __ z_ahhlr(Rdst, Rdst, Rdst);
    __ z_sllg(Rtmp, Rdst, 16);
    __ z_algr(Rdst, Rtmp);
    __ z_sllg(Rtmp, Rdst,  8);
    __ z_algr(Rdst, Rtmp);
    __ z_srlg(Rdst, Rdst, 56);
  %}
  ins_pipe(pipe_class_dummy);
%}

//----------SMARTSPILL RULES---------------------------------------------------
// These must follow all instruction definitions as they use the names
// defined in the instructions definitions.

// ============================================================================
// TYPE PROFILING RULES

[Seitenstruktur0.264Druckenetwas mehr zur Ethik2026-04-26]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge