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


Quellcode-Bibliothek aarch64.ad   Sprache: unbekannt

 
//
// Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2014, 2021, Red Hat, Inc. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 2 only, as
// published by the Free Software Foundation.
//
// This code is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// version 2 for more details (a copy is included in the LICENSE file that
// accompanied this code).
//
// You should have received a copy of the GNU General Public License version
// 2 along with this work; if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
// or visit www.oracle.com if you need additional information or have any
// questions.
//
//

// AArch64 Architecture Description File

//----------REGISTER DEFINITION BLOCK------------------------------------------
// This information is used by the matcher and the register allocator to
// describe individual registers and classes of registers within the target
// 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.

// We must define the 64 bit int registers in two 32 bit halves, the
// real lower register and a virtual upper half register. upper halves
// are used by the register allocator but are not actually supplied as
// operands to memory ops.
//
// follow the C1 compiler in making registers
//
//   r0-r7,r10-r26 volatile (caller save)
//   r27-r32 system (no save, no allocate)
//   r8-r9 non-allocatable (so we can use them as scratch regs)
//
// as regards Java usage. we don't use any callee save registers
// because this makes it difficult to de-optimise a frame (see comment
// in x86 implementation of Deoptimization::unwind_callee_save_values)
//

// General Registers

reg_def R0      ( SOC, SOC, Op_RegI,  0, r0->as_VMReg()         );
reg_def R0_H    ( SOC, SOC, Op_RegI,  0, r0->as_VMReg()->next() );
reg_def R1      ( SOC, SOC, Op_RegI,  1, r1->as_VMReg()         );
reg_def R1_H    ( SOC, SOC, Op_RegI,  1, r1->as_VMReg()->next() );
reg_def R2      ( SOC, SOC, Op_RegI,  2, r2->as_VMReg()         );
reg_def R2_H    ( SOC, SOC, Op_RegI,  2, r2->as_VMReg()->next() );
reg_def R3      ( SOC, SOC, Op_RegI,  3, r3->as_VMReg()         );
reg_def R3_H    ( SOC, SOC, Op_RegI,  3, r3->as_VMReg()->next() );
reg_def R4      ( SOC, SOC, Op_RegI,  4, r4->as_VMReg()         );
reg_def R4_H    ( SOC, SOC, Op_RegI,  4, r4->as_VMReg()->next() );
reg_def R5      ( SOC, SOC, Op_RegI,  5, r5->as_VMReg()         );
reg_def R5_H    ( SOC, SOC, Op_RegI,  5, r5->as_VMReg()->next() );
reg_def R6      ( SOC, SOC, Op_RegI,  6, r6->as_VMReg()         );
reg_def R6_H    ( SOC, SOC, Op_RegI,  6, r6->as_VMReg()->next() );
reg_def R7      ( SOC, SOC, Op_RegI,  7, r7->as_VMReg()         );
reg_def R7_H    ( SOC, SOC, Op_RegI,  7, r7->as_VMReg()->next() );
reg_def R8      ( NS,  SOC, Op_RegI,  8, r8->as_VMReg()         ); // rscratch1, non-allocatable
reg_def R8_H    ( NS,  SOC, Op_RegI,  8, r8->as_VMReg()->next() );
reg_def R9      ( NS,  SOC, Op_RegI,  9, r9->as_VMReg()         ); // rscratch2, non-allocatable
reg_def R9_H    ( NS,  SOC, Op_RegI,  9, r9->as_VMReg()->next() );
reg_def R10     ( SOC, SOC, Op_RegI, 10, r10->as_VMReg()        );
reg_def R10_H   ( SOC, SOC, Op_RegI, 10, r10->as_VMReg()->next());
reg_def R11     ( SOC, SOC, Op_RegI, 11, r11->as_VMReg()        );
reg_def R11_H   ( SOC, SOC, Op_RegI, 11, r11->as_VMReg()->next());
reg_def R12     ( SOC, SOC, Op_RegI, 12, r12->as_VMReg()        );
reg_def R12_H   ( SOC, SOC, Op_RegI, 12, r12->as_VMReg()->next());
reg_def R13     ( SOC, SOC, Op_RegI, 13, r13->as_VMReg()        );
reg_def R13_H   ( SOC, SOC, Op_RegI, 13, r13->as_VMReg()->next());
reg_def R14     ( SOC, SOC, Op_RegI, 14, r14->as_VMReg()        );
reg_def R14_H   ( SOC, SOC, Op_RegI, 14, r14->as_VMReg()->next());
reg_def R15     ( SOC, SOC, Op_RegI, 15, r15->as_VMReg()        );
reg_def R15_H   ( SOC, SOC, Op_RegI, 15, r15->as_VMReg()->next());
reg_def R16     ( SOC, SOC, Op_RegI, 16, r16->as_VMReg()        );
reg_def R16_H   ( SOC, SOC, Op_RegI, 16, r16->as_VMReg()->next());
reg_def R17     ( SOC, SOC, Op_RegI, 17, r17->as_VMReg()        );
reg_def R17_H   ( SOC, SOC, Op_RegI, 17, r17->as_VMReg()->next());
reg_def R18     ( SOC, SOC, Op_RegI, 18, r18_tls->as_VMReg()        );
reg_def R18_H   ( SOC, SOC, Op_RegI, 18, r18_tls->as_VMReg()->next());
reg_def R19     ( SOC, SOE, Op_RegI, 19, r19->as_VMReg()        );
reg_def R19_H   ( SOC, SOE, Op_RegI, 19, r19->as_VMReg()->next());
reg_def R20     ( SOC, SOE, Op_RegI, 20, r20->as_VMReg()        ); // caller esp
reg_def R20_H   ( SOC, SOE, Op_RegI, 20, r20->as_VMReg()->next());
reg_def R21     ( SOC, SOE, Op_RegI, 21, r21->as_VMReg()        );
reg_def R21_H   ( SOC, SOE, Op_RegI, 21, r21->as_VMReg()->next());
reg_def R22     ( SOC, SOE, Op_RegI, 22, r22->as_VMReg()        );
reg_def R22_H   ( SOC, SOE, Op_RegI, 22, r22->as_VMReg()->next());
reg_def R23     ( SOC, SOE, Op_RegI, 23, r23->as_VMReg()        );
reg_def R23_H   ( SOC, SOE, Op_RegI, 23, r23->as_VMReg()->next());
reg_def R24     ( SOC, SOE, Op_RegI, 24, r24->as_VMReg()        );
reg_def R24_H   ( SOC, SOE, Op_RegI, 24, r24->as_VMReg()->next());
reg_def R25     ( SOC, SOE, Op_RegI, 25, r25->as_VMReg()        );
reg_def R25_H   ( SOC, SOE, Op_RegI, 25, r25->as_VMReg()->next());
reg_def R26     ( SOC, SOE, Op_RegI, 26, r26->as_VMReg()        );
reg_def R26_H   ( SOC, SOE, Op_RegI, 26, r26->as_VMReg()->next());
reg_def R27     ( SOC, SOE, Op_RegI, 27, r27->as_VMReg()        ); // heapbase
reg_def R27_H   ( SOC, SOE, Op_RegI, 27, r27->as_VMReg()->next());
reg_def R28     (  NS, SOE, Op_RegI, 28, r28->as_VMReg()        ); // thread
reg_def R28_H   (  NS, SOE, Op_RegI, 28, r28->as_VMReg()->next());
reg_def R29     (  NS,  NS, Op_RegI, 29, r29->as_VMReg()        ); // fp
reg_def R29_H   (  NS,  NS, Op_RegI, 29, r29->as_VMReg()->next());
reg_def R30     (  NS,  NS, Op_RegI, 30, r30->as_VMReg()        ); // lr
reg_def R30_H   (  NS,  NS, Op_RegI, 30, r30->as_VMReg()->next());
reg_def R31     (  NS,  NS, Op_RegI, 31, r31_sp->as_VMReg()     ); // sp
reg_def R31_H   (  NS,  NS, Op_RegI, 31, r31_sp->as_VMReg()->next());

// ----------------------------
// Float/Double/Vector Registers
// ----------------------------

// Double Registers

// The rules of ADL require that double registers be defined in pairs.
// Each pair must be two 32-bit values, but not necessarily a pair of
// single float registers. In each pair, ADLC-assigned register numbers
// must be adjacent, with the lower number even. Finally, when the
// CPU stores such a register pair to memory, the word associated with
// the lower ADLC-assigned number must be stored to the lower address.

// AArch64 has 32 floating-point registers. Each can store a vector of
// single or double precision floating-point values up to 8 * 32
// floats, 4 * 64 bit floats or 2 * 128 bit floats.  We currently only
// use the first float or double element of the vector.

// for Java use float registers v0-v15 are always save on call whereas
// the platform ABI treats v8-v15 as callee save). float registers
// v16-v31 are SOC as per the platform spec

// For SVE vector registers, we simply extend vector register size to 8
// 'logical' slots. This is nominally 256 bits but it actually covers
// all possible 'physical' SVE vector register lengths from 128 ~ 2048
// bits. The 'physical' SVE vector register length is detected during
// startup, so the register allocator is able to identify the correct
// number of bytes needed for an SVE spill/unspill.
// Note that a vector register with 4 slots denotes a 128-bit NEON
// register allowing it to be distinguished from the corresponding SVE
// vector register when the SVE vector length is 128 bits.

  reg_def V0   ( SOC, SOC, Op_RegF, 0, v0->as_VMReg()          );
  reg_def V0_H ( SOC, SOC, Op_RegF, 0, v0->as_VMReg()->next()  );
  reg_def V0_J ( SOC, SOC, Op_RegF, 0, v0->as_VMReg()->next(2) );
  reg_def V0_K ( SOC, SOC, Op_RegF, 0, v0->as_VMReg()->next(3) );

  reg_def V1   ( SOC, SOC, Op_RegF, 1, v1->as_VMReg()          );
  reg_def V1_H ( SOC, SOC, Op_RegF, 1, v1->as_VMReg()->next()  );
  reg_def V1_J ( SOC, SOC, Op_RegF, 1, v1->as_VMReg()->next(2) );
  reg_def V1_K ( SOC, SOC, Op_RegF, 1, v1->as_VMReg()->next(3) );

  reg_def V2   ( SOC, SOC, Op_RegF, 2, v2->as_VMReg()          );
  reg_def V2_H ( SOC, SOC, Op_RegF, 2, v2->as_VMReg()->next()  );
  reg_def V2_J ( SOC, SOC, Op_RegF, 2, v2->as_VMReg()->next(2) );
  reg_def V2_K ( SOC, SOC, Op_RegF, 2, v2->as_VMReg()->next(3) );

  reg_def V3   ( SOC, SOC, Op_RegF, 3, v3->as_VMReg()          );
  reg_def V3_H ( SOC, SOC, Op_RegF, 3, v3->as_VMReg()->next()  );
  reg_def V3_J ( SOC, SOC, Op_RegF, 3, v3->as_VMReg()->next(2) );
  reg_def V3_K ( SOC, SOC, Op_RegF, 3, v3->as_VMReg()->next(3) );

  reg_def V4   ( SOC, SOC, Op_RegF, 4, v4->as_VMReg()          );
  reg_def V4_H ( SOC, SOC, Op_RegF, 4, v4->as_VMReg()->next()  );
  reg_def V4_J ( SOC, SOC, Op_RegF, 4, v4->as_VMReg()->next(2) );
  reg_def V4_K ( SOC, SOC, Op_RegF, 4, v4->as_VMReg()->next(3) );

  reg_def V5   ( SOC, SOC, Op_RegF, 5, v5->as_VMReg()          );
  reg_def V5_H ( SOC, SOC, Op_RegF, 5, v5->as_VMReg()->next()  );
  reg_def V5_J ( SOC, SOC, Op_RegF, 5, v5->as_VMReg()->next(2) );
  reg_def V5_K ( SOC, SOC, Op_RegF, 5, v5->as_VMReg()->next(3) );

  reg_def V6   ( SOC, SOC, Op_RegF, 6, v6->as_VMReg()          );
  reg_def V6_H ( SOC, SOC, Op_RegF, 6, v6->as_VMReg()->next()  );
  reg_def V6_J ( SOC, SOC, Op_RegF, 6, v6->as_VMReg()->next(2) );
  reg_def V6_K ( SOC, SOC, Op_RegF, 6, v6->as_VMReg()->next(3) );

  reg_def V7   ( SOC, SOC, Op_RegF, 7, v7->as_VMReg()          );
  reg_def V7_H ( SOC, SOC, Op_RegF, 7, v7->as_VMReg()->next()  );
  reg_def V7_J ( SOC, SOC, Op_RegF, 7, v7->as_VMReg()->next(2) );
  reg_def V7_K ( SOC, SOC, Op_RegF, 7, v7->as_VMReg()->next(3) );

  reg_def V8   ( SOC, SOE, Op_RegF, 8, v8->as_VMReg()          );
  reg_def V8_H ( SOC, SOE, Op_RegF, 8, v8->as_VMReg()->next()  );
  reg_def V8_J ( SOC, SOC, Op_RegF, 8, v8->as_VMReg()->next(2) );
  reg_def V8_K ( SOC, SOC, Op_RegF, 8, v8->as_VMReg()->next(3) );

  reg_def V9   ( SOC, SOE, Op_RegF, 9, v9->as_VMReg()          );
  reg_def V9_H ( SOC, SOE, Op_RegF, 9, v9->as_VMReg()->next()  );
  reg_def V9_J ( SOC, SOC, Op_RegF, 9, v9->as_VMReg()->next(2) );
  reg_def V9_K ( SOC, SOC, Op_RegF, 9, v9->as_VMReg()->next(3) );

  reg_def V10   ( SOC, SOE, Op_RegF, 10, v10->as_VMReg()          );
  reg_def V10_H ( SOC, SOE, Op_RegF, 10, v10->as_VMReg()->next()  );
  reg_def V10_J ( SOC, SOC, Op_RegF, 10, v10->as_VMReg()->next(2) );
  reg_def V10_K ( SOC, SOC, Op_RegF, 10, v10->as_VMReg()->next(3) );

  reg_def V11   ( SOC, SOE, Op_RegF, 11, v11->as_VMReg()          );
  reg_def V11_H ( SOC, SOE, Op_RegF, 11, v11->as_VMReg()->next()  );
  reg_def V11_J ( SOC, SOC, Op_RegF, 11, v11->as_VMReg()->next(2) );
  reg_def V11_K ( SOC, SOC, Op_RegF, 11, v11->as_VMReg()->next(3) );

  reg_def V12   ( SOC, SOE, Op_RegF, 12, v12->as_VMReg()          );
  reg_def V12_H ( SOC, SOE, Op_RegF, 12, v12->as_VMReg()->next()  );
  reg_def V12_J ( SOC, SOC, Op_RegF, 12, v12->as_VMReg()->next(2) );
  reg_def V12_K ( SOC, SOC, Op_RegF, 12, v12->as_VMReg()->next(3) );

  reg_def V13   ( SOC, SOE, Op_RegF, 13, v13->as_VMReg()          );
  reg_def V13_H ( SOC, SOE, Op_RegF, 13, v13->as_VMReg()->next()  );
  reg_def V13_J ( SOC, SOC, Op_RegF, 13, v13->as_VMReg()->next(2) );
  reg_def V13_K ( SOC, SOC, Op_RegF, 13, v13->as_VMReg()->next(3) );

  reg_def V14   ( SOC, SOE, Op_RegF, 14, v14->as_VMReg()          );
  reg_def V14_H ( SOC, SOE, Op_RegF, 14, v14->as_VMReg()->next()  );
  reg_def V14_J ( SOC, SOC, Op_RegF, 14, v14->as_VMReg()->next(2) );
  reg_def V14_K ( SOC, SOC, Op_RegF, 14, v14->as_VMReg()->next(3) );

  reg_def V15   ( SOC, SOE, Op_RegF, 15, v15->as_VMReg()          );
  reg_def V15_H ( SOC, SOE, Op_RegF, 15, v15->as_VMReg()->next()  );
  reg_def V15_J ( SOC, SOC, Op_RegF, 15, v15->as_VMReg()->next(2) );
  reg_def V15_K ( SOC, SOC, Op_RegF, 15, v15->as_VMReg()->next(3) );

  reg_def V16   ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()          );
  reg_def V16_H ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next()  );
  reg_def V16_J ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next(2) );
  reg_def V16_K ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next(3) );

  reg_def V17   ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()          );
  reg_def V17_H ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next()  );
  reg_def V17_J ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next(2) );
  reg_def V17_K ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next(3) );

  reg_def V18   ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()          );
  reg_def V18_H ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next()  );
  reg_def V18_J ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next(2) );
  reg_def V18_K ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next(3) );

  reg_def V19   ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()          );
  reg_def V19_H ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next()  );
  reg_def V19_J ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next(2) );
  reg_def V19_K ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next(3) );

  reg_def V20   ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()          );
  reg_def V20_H ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next()  );
  reg_def V20_J ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next(2) );
  reg_def V20_K ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next(3) );

  reg_def V21   ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()          );
  reg_def V21_H ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next()  );
  reg_def V21_J ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next(2) );
  reg_def V21_K ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next(3) );

  reg_def V22   ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()          );
  reg_def V22_H ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next()  );
  reg_def V22_J ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next(2) );
  reg_def V22_K ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next(3) );

  reg_def V23   ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()          );
  reg_def V23_H ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next()  );
  reg_def V23_J ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next(2) );
  reg_def V23_K ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next(3) );

  reg_def V24   ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()          );
  reg_def V24_H ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next()  );
  reg_def V24_J ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next(2) );
  reg_def V24_K ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next(3) );

  reg_def V25   ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()          );
  reg_def V25_H ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next()  );
  reg_def V25_J ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next(2) );
  reg_def V25_K ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next(3) );

  reg_def V26   ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()          );
  reg_def V26_H ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next()  );
  reg_def V26_J ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next(2) );
  reg_def V26_K ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next(3) );

  reg_def V27   ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()          );
  reg_def V27_H ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next()  );
  reg_def V27_J ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next(2) );
  reg_def V27_K ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next(3) );

  reg_def V28   ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()          );
  reg_def V28_H ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next()  );
  reg_def V28_J ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next(2) );
  reg_def V28_K ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next(3) );

  reg_def V29   ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()          );
  reg_def V29_H ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next()  );
  reg_def V29_J ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next(2) );
  reg_def V29_K ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next(3) );

  reg_def V30   ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()          );
  reg_def V30_H ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next()  );
  reg_def V30_J ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next(2) );
  reg_def V30_K ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next(3) );

  reg_def V31   ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()          );
  reg_def V31_H ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next()  );
  reg_def V31_J ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next(2) );
  reg_def V31_K ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next(3) );

// ----------------------------
// SVE Predicate Registers
// ----------------------------
  reg_def P0 (SOC, SOC, Op_RegVectMask, 0, p0->as_VMReg());
  reg_def P1 (SOC, SOC, Op_RegVectMask, 1, p1->as_VMReg());
  reg_def P2 (SOC, SOC, Op_RegVectMask, 2, p2->as_VMReg());
  reg_def P3 (SOC, SOC, Op_RegVectMask, 3, p3->as_VMReg());
  reg_def P4 (SOC, SOC, Op_RegVectMask, 4, p4->as_VMReg());
  reg_def P5 (SOC, SOC, Op_RegVectMask, 5, p5->as_VMReg());
  reg_def P6 (SOC, SOC, Op_RegVectMask, 6, p6->as_VMReg());
  reg_def P7 (SOC, SOC, Op_RegVectMask, 7, p7->as_VMReg());
  reg_def P8 (SOC, SOC, Op_RegVectMask, 8, p8->as_VMReg());
  reg_def P9 (SOC, SOC, Op_RegVectMask, 9, p9->as_VMReg());
  reg_def P10 (SOC, SOC, Op_RegVectMask, 10, p10->as_VMReg());
  reg_def P11 (SOC, SOC, Op_RegVectMask, 11, p11->as_VMReg());
  reg_def P12 (SOC, SOC, Op_RegVectMask, 12, p12->as_VMReg());
  reg_def P13 (SOC, SOC, Op_RegVectMask, 13, p13->as_VMReg());
  reg_def P14 (SOC, SOC, Op_RegVectMask, 14, p14->as_VMReg());
  reg_def P15 (SOC, SOC, Op_RegVectMask, 15, p15->as_VMReg());

// ----------------------------
// Special Registers
// ----------------------------

// the AArch64 CSPR status flag register is not directly accessible as
// instruction operand. the FPSR status flag register is a system
// register which can be written/read using MSR/MRS but again does not
// appear as an operand (a code identifying the FSPR occurs as an
// immediate value in the instruction).

reg_def RFLAGS(SOC, SOC, 0, 32, VMRegImpl::Bad());

// Specify priority of register selection within phases of register
// allocation.  Highest priority is first.  A useful heuristic is to
// give registers a low priority when they are required by machine
// instructions, like EAX and EDX on I486, and choose no-save registers
// before save-on-call, & save-on-call before save-on-entry.  Registers
// which participate in fixed calling sequences should come last.
// Registers which are used as pairs must fall on an even boundary.

alloc_class chunk0(
    // volatiles
    R10, R10_H,
    R11, R11_H,
    R12, R12_H,
    R13, R13_H,
    R14, R14_H,
    R15, R15_H,
    R16, R16_H,
    R17, R17_H,
    R18, R18_H,

    // arg registers
    R0, R0_H,
    R1, R1_H,
    R2, R2_H,
    R3, R3_H,
    R4, R4_H,
    R5, R5_H,
    R6, R6_H,
    R7, R7_H,

    // non-volatiles
    R19, R19_H,
    R20, R20_H,
    R21, R21_H,
    R22, R22_H,
    R23, R23_H,
    R24, R24_H,
    R25, R25_H,
    R26, R26_H,

    // non-allocatable registers

    R27, R27_H, // heapbase
    R28, R28_H, // thread
    R29, R29_H, // fp
    R30, R30_H, // lr
    R31, R31_H, // sp
    R8, R8_H,   // rscratch1
    R9, R9_H,   // rscratch2
);

alloc_class chunk1(

    // no save
    V16, V16_H, V16_J, V16_K,
    V17, V17_H, V17_J, V17_K,
    V18, V18_H, V18_J, V18_K,
    V19, V19_H, V19_J, V19_K,
    V20, V20_H, V20_J, V20_K,
    V21, V21_H, V21_J, V21_K,
    V22, V22_H, V22_J, V22_K,
    V23, V23_H, V23_J, V23_K,
    V24, V24_H, V24_J, V24_K,
    V25, V25_H, V25_J, V25_K,
    V26, V26_H, V26_J, V26_K,
    V27, V27_H, V27_J, V27_K,
    V28, V28_H, V28_J, V28_K,
    V29, V29_H, V29_J, V29_K,
    V30, V30_H, V30_J, V30_K,
    V31, V31_H, V31_J, V31_K,

    // arg registers
    V0, V0_H, V0_J, V0_K,
    V1, V1_H, V1_J, V1_K,
    V2, V2_H, V2_J, V2_K,
    V3, V3_H, V3_J, V3_K,
    V4, V4_H, V4_J, V4_K,
    V5, V5_H, V5_J, V5_K,
    V6, V6_H, V6_J, V6_K,
    V7, V7_H, V7_J, V7_K,

    // non-volatiles
    V8, V8_H, V8_J, V8_K,
    V9, V9_H, V9_J, V9_K,
    V10, V10_H, V10_J, V10_K,
    V11, V11_H, V11_J, V11_K,
    V12, V12_H, V12_J, V12_K,
    V13, V13_H, V13_J, V13_K,
    V14, V14_H, V14_J, V14_K,
    V15, V15_H, V15_J, V15_K,
);

alloc_class chunk2 (
    // Governing predicates for load/store and arithmetic
    P0,
    P1,
    P2,
    P3,
    P4,
    P5,
    P6,

    // Extra predicates
    P8,
    P9,
    P10,
    P11,
    P12,
    P13,
    P14,
    P15,

    // Preserved for all-true predicate
    P7,
);

alloc_class chunk3(RFLAGS);

//----------Architecture Description Register Classes--------------------------
// Several register classes are automatically defined based upon information in
// this architecture description.
// 1) reg_class inline_cache_reg           ( /* as def'd in frame section */ )
// 2) reg_class stack_slots( /* one chunk of stack-based "registers" */ )
//

// Class for all 32 bit general purpose registers
reg_class all_reg32(
    R0,
    R1,
    R2,
    R3,
    R4,
    R5,
    R6,
    R7,
    R10,
    R11,
    R12,
    R13,
    R14,
    R15,
    R16,
    R17,
    R18,
    R19,
    R20,
    R21,
    R22,
    R23,
    R24,
    R25,
    R26,
    R27,
    R28,
    R29,
    R30,
    R31
);


// Class for all 32 bit integer registers (excluding SP which
// will never be used as an integer register)
reg_class any_reg32 %{
  return _ANY_REG32_mask;
%}

// Singleton class for R0 int register
reg_class int_r0_reg(R0);

// Singleton class for R2 int register
reg_class int_r2_reg(R2);

// Singleton class for R3 int register
reg_class int_r3_reg(R3);

// Singleton class for R4 int register
reg_class int_r4_reg(R4);

// Singleton class for R31 int register
reg_class int_r31_reg(R31);

// Class for all 64 bit general purpose registers
reg_class all_reg(
    R0, R0_H,
    R1, R1_H,
    R2, R2_H,
    R3, R3_H,
    R4, R4_H,
    R5, R5_H,
    R6, R6_H,
    R7, R7_H,
    R10, R10_H,
    R11, R11_H,
    R12, R12_H,
    R13, R13_H,
    R14, R14_H,
    R15, R15_H,
    R16, R16_H,
    R17, R17_H,
    R18, R18_H,
    R19, R19_H,
    R20, R20_H,
    R21, R21_H,
    R22, R22_H,
    R23, R23_H,
    R24, R24_H,
    R25, R25_H,
    R26, R26_H,
    R27, R27_H,
    R28, R28_H,
    R29, R29_H,
    R30, R30_H,
    R31, R31_H
);

// Class for all long integer registers (including SP)
reg_class any_reg %{
  return _ANY_REG_mask;
%}

// Class for non-allocatable 32 bit registers
reg_class non_allocatable_reg32(
#ifdef R18_RESERVED
    // See comment in register_aarch64.hpp
    R18,                        // tls on Windows
#endif
    R28,                        // thread
    R30,                        // lr
    R31                         // sp
);

// Class for non-allocatable 64 bit registers
reg_class non_allocatable_reg(
#ifdef R18_RESERVED
    // See comment in register_aarch64.hpp
    R18, R18_H,                 // tls on Windows, platform register on macOS
#endif
    R28, R28_H,                 // thread
    R30, R30_H,                 // lr
    R31, R31_H                  // sp
);

// Class for all non-special integer registers
reg_class no_special_reg32 %{
  return _NO_SPECIAL_REG32_mask;
%}

// Class for all non-special long integer registers
reg_class no_special_reg %{
  return _NO_SPECIAL_REG_mask;
%}

// Class for 64 bit register r0
reg_class r0_reg(
    R0, R0_H
);

// Class for 64 bit register r1
reg_class r1_reg(
    R1, R1_H
);

// Class for 64 bit register r2
reg_class r2_reg(
    R2, R2_H
);

// Class for 64 bit register r3
reg_class r3_reg(
    R3, R3_H
);

// Class for 64 bit register r4
reg_class r4_reg(
    R4, R4_H
);

// Class for 64 bit register r5
reg_class r5_reg(
    R5, R5_H
);

// Class for 64 bit register r10
reg_class r10_reg(
    R10, R10_H
);

// Class for 64 bit register r11
reg_class r11_reg(
    R11, R11_H
);

// Class for method register
reg_class method_reg(
    R12, R12_H
);

// Class for heapbase register
reg_class heapbase_reg(
    R27, R27_H
);

// Class for thread register
reg_class thread_reg(
    R28, R28_H
);

// Class for frame pointer register
reg_class fp_reg(
    R29, R29_H
);

// Class for link register
reg_class lr_reg(
    R30, R30_H
);

// Class for long sp register
reg_class sp_reg(
  R31, R31_H
);

// Class for all pointer registers
reg_class ptr_reg %{
  return _PTR_REG_mask;
%}

// Class for all non_special pointer registers
reg_class no_special_ptr_reg %{
  return _NO_SPECIAL_PTR_REG_mask;
%}

// Class for all float registers
reg_class float_reg(
    V0,
    V1,
    V2,
    V3,
    V4,
    V5,
    V6,
    V7,
    V8,
    V9,
    V10,
    V11,
    V12,
    V13,
    V14,
    V15,
    V16,
    V17,
    V18,
    V19,
    V20,
    V21,
    V22,
    V23,
    V24,
    V25,
    V26,
    V27,
    V28,
    V29,
    V30,
    V31
);

// Double precision float registers have virtual `high halves' that
// are needed by the allocator.
// Class for all double registers
reg_class double_reg(
    V0, V0_H,
    V1, V1_H,
    V2, V2_H,
    V3, V3_H,
    V4, V4_H,
    V5, V5_H,
    V6, V6_H,
    V7, V7_H,
    V8, V8_H,
    V9, V9_H,
    V10, V10_H,
    V11, V11_H,
    V12, V12_H,
    V13, V13_H,
    V14, V14_H,
    V15, V15_H,
    V16, V16_H,
    V17, V17_H,
    V18, V18_H,
    V19, V19_H,
    V20, V20_H,
    V21, V21_H,
    V22, V22_H,
    V23, V23_H,
    V24, V24_H,
    V25, V25_H,
    V26, V26_H,
    V27, V27_H,
    V28, V28_H,
    V29, V29_H,
    V30, V30_H,
    V31, V31_H
);

// Class for all SVE vector registers.
reg_class vectora_reg (
    V0, V0_H, V0_J, V0_K,
    V1, V1_H, V1_J, V1_K,
    V2, V2_H, V2_J, V2_K,
    V3, V3_H, V3_J, V3_K,
    V4, V4_H, V4_J, V4_K,
    V5, V5_H, V5_J, V5_K,
    V6, V6_H, V6_J, V6_K,
    V7, V7_H, V7_J, V7_K,
    V8, V8_H, V8_J, V8_K,
    V9, V9_H, V9_J, V9_K,
    V10, V10_H, V10_J, V10_K,
    V11, V11_H, V11_J, V11_K,
    V12, V12_H, V12_J, V12_K,
    V13, V13_H, V13_J, V13_K,
    V14, V14_H, V14_J, V14_K,
    V15, V15_H, V15_J, V15_K,
    V16, V16_H, V16_J, V16_K,
    V17, V17_H, V17_J, V17_K,
    V18, V18_H, V18_J, V18_K,
    V19, V19_H, V19_J, V19_K,
    V20, V20_H, V20_J, V20_K,
    V21, V21_H, V21_J, V21_K,
    V22, V22_H, V22_J, V22_K,
    V23, V23_H, V23_J, V23_K,
    V24, V24_H, V24_J, V24_K,
    V25, V25_H, V25_J, V25_K,
    V26, V26_H, V26_J, V26_K,
    V27, V27_H, V27_J, V27_K,
    V28, V28_H, V28_J, V28_K,
    V29, V29_H, V29_J, V29_K,
    V30, V30_H, V30_J, V30_K,
    V31, V31_H, V31_J, V31_K,
);

// Class for all 64bit vector registers
reg_class vectord_reg(
    V0, V0_H,
    V1, V1_H,
    V2, V2_H,
    V3, V3_H,
    V4, V4_H,
    V5, V5_H,
    V6, V6_H,
    V7, V7_H,
    V8, V8_H,
    V9, V9_H,
    V10, V10_H,
    V11, V11_H,
    V12, V12_H,
    V13, V13_H,
    V14, V14_H,
    V15, V15_H,
    V16, V16_H,
    V17, V17_H,
    V18, V18_H,
    V19, V19_H,
    V20, V20_H,
    V21, V21_H,
    V22, V22_H,
    V23, V23_H,
    V24, V24_H,
    V25, V25_H,
    V26, V26_H,
    V27, V27_H,
    V28, V28_H,
    V29, V29_H,
    V30, V30_H,
    V31, V31_H
);

// Class for all 128bit vector registers
reg_class vectorx_reg(
    V0, V0_H, V0_J, V0_K,
    V1, V1_H, V1_J, V1_K,
    V2, V2_H, V2_J, V2_K,
    V3, V3_H, V3_J, V3_K,
    V4, V4_H, V4_J, V4_K,
    V5, V5_H, V5_J, V5_K,
    V6, V6_H, V6_J, V6_K,
    V7, V7_H, V7_J, V7_K,
    V8, V8_H, V8_J, V8_K,
    V9, V9_H, V9_J, V9_K,
    V10, V10_H, V10_J, V10_K,
    V11, V11_H, V11_J, V11_K,
    V12, V12_H, V12_J, V12_K,
    V13, V13_H, V13_J, V13_K,
    V14, V14_H, V14_J, V14_K,
    V15, V15_H, V15_J, V15_K,
    V16, V16_H, V16_J, V16_K,
    V17, V17_H, V17_J, V17_K,
    V18, V18_H, V18_J, V18_K,
    V19, V19_H, V19_J, V19_K,
    V20, V20_H, V20_J, V20_K,
    V21, V21_H, V21_J, V21_K,
    V22, V22_H, V22_J, V22_K,
    V23, V23_H, V23_J, V23_K,
    V24, V24_H, V24_J, V24_K,
    V25, V25_H, V25_J, V25_K,
    V26, V26_H, V26_J, V26_K,
    V27, V27_H, V27_J, V27_K,
    V28, V28_H, V28_J, V28_K,
    V29, V29_H, V29_J, V29_K,
    V30, V30_H, V30_J, V30_K,
    V31, V31_H, V31_J, V31_K
);

// Class for 128 bit register v0
reg_class v0_reg(
    V0, V0_H
);

// Class for 128 bit register v1
reg_class v1_reg(
    V1, V1_H
);

// Class for 128 bit register v2
reg_class v2_reg(
    V2, V2_H
);

// Class for 128 bit register v3
reg_class v3_reg(
    V3, V3_H
);

// Class for 128 bit register v4
reg_class v4_reg(
    V4, V4_H
);

// Class for 128 bit register v5
reg_class v5_reg(
    V5, V5_H
);

// Class for 128 bit register v6
reg_class v6_reg(
    V6, V6_H
);

// Class for 128 bit register v7
reg_class v7_reg(
    V7, V7_H
);

// Class for 128 bit register v8
reg_class v8_reg(
    V8, V8_H
);

// Class for 128 bit register v9
reg_class v9_reg(
    V9, V9_H
);

// Class for 128 bit register v10
reg_class v10_reg(
    V10, V10_H
);

// Class for 128 bit register v11
reg_class v11_reg(
    V11, V11_H
);

// Class for 128 bit register v12
reg_class v12_reg(
    V12, V12_H
);

// Class for 128 bit register v13
reg_class v13_reg(
    V13, V13_H
);

// Class for 128 bit register v14
reg_class v14_reg(
    V14, V14_H
);

// Class for 128 bit register v15
reg_class v15_reg(
    V15, V15_H
);

// Class for 128 bit register v16
reg_class v16_reg(
    V16, V16_H
);

// Class for 128 bit register v17
reg_class v17_reg(
    V17, V17_H
);

// Class for 128 bit register v18
reg_class v18_reg(
    V18, V18_H
);

// Class for 128 bit register v19
reg_class v19_reg(
    V19, V19_H
);

// Class for 128 bit register v20
reg_class v20_reg(
    V20, V20_H
);

// Class for 128 bit register v21
reg_class v21_reg(
    V21, V21_H
);

// Class for 128 bit register v22
reg_class v22_reg(
    V22, V22_H
);

// Class for 128 bit register v23
reg_class v23_reg(
    V23, V23_H
);

// Class for 128 bit register v24
reg_class v24_reg(
    V24, V24_H
);

// Class for 128 bit register v25
reg_class v25_reg(
    V25, V25_H
);

// Class for 128 bit register v26
reg_class v26_reg(
    V26, V26_H
);

// Class for 128 bit register v27
reg_class v27_reg(
    V27, V27_H
);

// Class for 128 bit register v28
reg_class v28_reg(
    V28, V28_H
);

// Class for 128 bit register v29
reg_class v29_reg(
    V29, V29_H
);

// Class for 128 bit register v30
reg_class v30_reg(
    V30, V30_H
);

// Class for 128 bit register v31
reg_class v31_reg(
    V31, V31_H
);

// Class for all SVE predicate registers.
reg_class pr_reg (
    P0,
    P1,
    P2,
    P3,
    P4,
    P5,
    P6,
    // P7, non-allocatable, preserved with all elements preset to TRUE.
    P8,
    P9,
    P10,
    P11,
    P12,
    P13,
    P14,
    P15
);

// Class for SVE governing predicate registers, which are used
// to determine the active elements of a predicated instruction.
reg_class gov_pr (
    P0,
    P1,
    P2,
    P3,
    P4,
    P5,
    P6,
    // P7, non-allocatable, preserved with all elements preset to TRUE.
);

reg_class p0_reg(P0);
reg_class p1_reg(P1);

// Singleton class for condition codes
reg_class int_flags(RFLAGS);

%}

//----------DEFINITION BLOCK---------------------------------------------------
// Define name --> value mappings to inform the ADLC of an integer valued name
// Current support includes integer values in the range [0, 0x7FFFFFFF]
// Format:
//        int_def  <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>");
//

// we follow the ppc-aix port in using a simple cost model which ranks
// register operations as cheap, memory ops as more expensive and
// branches as most expensive. the first two have a low as well as a
// normal cost. huge cost appears to be a way of saying don't do
// something

definitions %{
  // The default cost (of a register move instruction).
  int_def INSN_COST            (    100,     100);
  int_def BRANCH_COST          (    200,     2 * INSN_COST);
  int_def CALL_COST            (    200,     2 * INSN_COST);
  int_def VOLATILE_REF_COST    (   1000,     10 * INSN_COST);
%}


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

source_hpp %{

#include "asm/macroAssembler.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/cardTable.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "opto/addnode.hpp"
#include "opto/convertnode.hpp"
#include "runtime/objectMonitor.hpp"

extern RegMask _ANY_REG32_mask;
extern RegMask _ANY_REG_mask;
extern RegMask _PTR_REG_mask;
extern RegMask _NO_SPECIAL_REG32_mask;
extern RegMask _NO_SPECIAL_REG_mask;
extern RegMask _NO_SPECIAL_PTR_REG_mask;

class CallStubImpl {

  //--------------------------------------------------------------
  //---<  Used for optimization in Compile::shorten_branches  >---
  //--------------------------------------------------------------

 public:
  // Size of call trampoline stub.
  static uint size_call_trampoline() {
    return 0; // no call trampolines on this platform
  }

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

class HandlerImpl {

 public:

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

  static uint size_exception_handler() {
    return MacroAssembler::far_codestub_branch_size();
  }

  static uint size_deopt_handler() {
    // count one adr and one far branch instruction
    return NativeInstruction::instruction_size + MacroAssembler::far_codestub_branch_size();
  }
};

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

  bool is_CAS(int opcode, bool maybe_volatile);

  // predicates controlling emit of ldr<x>/ldar<x> and associated dmb

  bool unnecessary_acquire(const Node *barrier);
  bool needs_acquiring_load(const Node *load);

  // predicates controlling emit of str<x>/stlr<x> and associated dmbs

  bool unnecessary_release(const Node *barrier);
  bool unnecessary_volatile(const Node *barrier);
  bool needs_releasing_store(const Node *store);

  // predicate controlling translation of CompareAndSwapX
  bool needs_acquiring_load_exclusive(const Node *load);

  // predicate controlling addressing modes
  bool size_fits_all_mem_uses(AddPNode* addp, int shift);
%}

source %{

  // Derived RegMask with conditionally allocatable registers

  void PhaseOutput::pd_perform_mach_node_analysis() {
  }

  int MachNode::pd_alignment_required() const {
    return 1;
  }

  int MachNode::compute_padding(int current_offset) const {
    return 0;
  }

  RegMask _ANY_REG32_mask;
  RegMask _ANY_REG_mask;
  RegMask _PTR_REG_mask;
  RegMask _NO_SPECIAL_REG32_mask;
  RegMask _NO_SPECIAL_REG_mask;
  RegMask _NO_SPECIAL_PTR_REG_mask;

  void reg_mask_init() {
    // We derive below RegMask(s) from the ones which are auto-generated from
    // adlc register classes to make AArch64 rheapbase (r27) and rfp (r29)
    // registers conditionally reserved.

    _ANY_REG32_mask = _ALL_REG32_mask;
    _ANY_REG32_mask.Remove(OptoReg::as_OptoReg(r31_sp->as_VMReg()));

    _ANY_REG_mask = _ALL_REG_mask;

    _PTR_REG_mask = _ALL_REG_mask;

    _NO_SPECIAL_REG32_mask = _ALL_REG32_mask;
    _NO_SPECIAL_REG32_mask.SUBTRACT(_NON_ALLOCATABLE_REG32_mask);

    _NO_SPECIAL_REG_mask = _ALL_REG_mask;
    _NO_SPECIAL_REG_mask.SUBTRACT(_NON_ALLOCATABLE_REG_mask);

    _NO_SPECIAL_PTR_REG_mask = _ALL_REG_mask;
    _NO_SPECIAL_PTR_REG_mask.SUBTRACT(_NON_ALLOCATABLE_REG_mask);

    // r27 is not allocatable when compressed oops is on and heapbase is not
    // zero, compressed klass pointers doesn't use r27 after JDK-8234794
    if (UseCompressedOops && (CompressedOops::ptrs_base() != NULL)) {
      _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg()));
      _NO_SPECIAL_REG_mask.SUBTRACT(_HEAPBASE_REG_mask);
      _NO_SPECIAL_PTR_REG_mask.SUBTRACT(_HEAPBASE_REG_mask);
    }

    // r29 is not allocatable when PreserveFramePointer is on
    if (PreserveFramePointer) {
      _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg()));
      _NO_SPECIAL_REG_mask.SUBTRACT(_FP_REG_mask);
      _NO_SPECIAL_PTR_REG_mask.SUBTRACT(_FP_REG_mask);
    }
  }

  // Optimizaton of volatile gets and puts
  // -------------------------------------
  //
  // AArch64 has ldar<x> and stlr<x> instructions which we can safely
  // use to implement volatile reads and writes. For a volatile read
  // we simply need
  //
  //   ldar<x>
  //
  // and for a volatile write we need
  //
  //   stlr<x>
  //
  // Alternatively, we can implement them by pairing a normal
  // load/store with a memory barrier. For a volatile read we need
  //
  //   ldr<x>
  //   dmb ishld
  //
  // for a volatile write
  //
  //   dmb ish
  //   str<x>
  //   dmb ish
  //
  // We can also use ldaxr and stlxr to implement compare and swap CAS
  // sequences. These are normally translated to an instruction
  // sequence like the following
  //
  //   dmb      ish
  // retry:
  //   ldxr<x>   rval raddr
  //   cmp       rval rold
  //   b.ne done
  //   stlxr<x>  rval, rnew, rold
  //   cbnz      rval retry
  // done:
  //   cset      r0, eq
  //   dmb ishld
  //
  // Note that the exclusive store is already using an stlxr
  // instruction. That is required to ensure visibility to other
  // threads of the exclusive write (assuming it succeeds) before that
  // of any subsequent writes.
  //
  // The following instruction sequence is an improvement on the above
  //
  // retry:
  //   ldaxr<x>  rval raddr
  //   cmp       rval rold
  //   b.ne done
  //   stlxr<x>  rval, rnew, rold
  //   cbnz      rval retry
  // done:
  //   cset      r0, eq
  //
  // We don't need the leading dmb ish since the stlxr guarantees
  // visibility of prior writes in the case that the swap is
  // successful. Crucially we don't have to worry about the case where
  // the swap is not successful since no valid program should be
  // relying on visibility of prior changes by the attempting thread
  // in the case where the CAS fails.
  //
  // Similarly, we don't need the trailing dmb ishld if we substitute
  // an ldaxr instruction since that will provide all the guarantees we
  // require regarding observation of changes made by other threads
  // before any change to the CAS address observed by the load.
  //
  // In order to generate the desired instruction sequence we need to
  // be able to identify specific 'signature' ideal graph node
  // sequences which i) occur as a translation of a volatile reads or
  // writes or CAS operations and ii) do not occur through any other
  // translation or graph transformation. We can then provide
  // alternative aldc matching rules which translate these node
  // sequences to the desired machine code sequences. Selection of the
  // alternative rules can be implemented by predicates which identify
  // the relevant node sequences.
  //
  // The ideal graph generator translates a volatile read to the node
  // sequence
  //
  //   LoadX[mo_acquire]
  //   MemBarAcquire
  //
  // As a special case when using the compressed oops optimization we
  // may also see this variant
  //
  //   LoadN[mo_acquire]
  //   DecodeN
  //   MemBarAcquire
  //
  // A volatile write is translated to the node sequence
  //
  //   MemBarRelease
  //   StoreX[mo_release] {CardMark}-optional
  //   MemBarVolatile
  //
  // n.b. the above node patterns are generated with a strict
  // 'signature' configuration of input and output dependencies (see
  // the predicates below for exact details). The card mark may be as
  // simple as a few extra nodes or, in a few GC configurations, may
  // include more complex control flow between the leading and
  // trailing memory barriers. However, whatever the card mark
  // configuration these signatures are unique to translated volatile
  // reads/stores -- they will not appear as a result of any other
  // bytecode translation or inlining nor as a consequence of
  // optimizing transforms.
  //
  // We also want to catch inlined unsafe volatile gets and puts and
  // be able to implement them using either ldar<x>/stlr<x> or some
  // combination of ldr<x>/stlr<x> and dmb instructions.
  //
  // Inlined unsafe volatiles puts manifest as a minor variant of the
  // normal volatile put node sequence containing an extra cpuorder
  // membar
  //
  //   MemBarRelease
  //   MemBarCPUOrder
  //   StoreX[mo_release] {CardMark}-optional
  //   MemBarCPUOrder
  //   MemBarVolatile
  //
  // n.b. as an aside, a cpuorder membar is not itself subject to
  // matching and translation by adlc rules.  However, the rule
  // predicates need to detect its presence in order to correctly
  // select the desired adlc rules.
  //
  // Inlined unsafe volatile gets manifest as a slightly different
  // node sequence to a normal volatile get because of the
  // introduction of some CPUOrder memory barriers to bracket the
  // Load. However, but the same basic skeleton of a LoadX feeding a
  // MemBarAcquire, possibly through an optional DecodeN, is still
  // present
  //
  //   MemBarCPUOrder
  //        ||       \\
  //   MemBarCPUOrder LoadX[mo_acquire]
  //        ||            |
  //        ||       {DecodeN} optional
  //        ||       /
  //     MemBarAcquire
  //
  // In this case the acquire membar does not directly depend on the
  // load. However, we can be sure that the load is generated from an
  // inlined unsafe volatile get if we see it dependent on this unique
  // sequence of membar nodes. Similarly, given an acquire membar we
  // can know that it was added because of an inlined unsafe volatile
  // get if it is fed and feeds a cpuorder membar and if its feed
  // membar also feeds an acquiring load.
  //
  // Finally an inlined (Unsafe) CAS operation is translated to the
  // following ideal graph
  //
  //   MemBarRelease
  //   MemBarCPUOrder
  //   CompareAndSwapX {CardMark}-optional
  //   MemBarCPUOrder
  //   MemBarAcquire
  //
  // So, where we can identify these volatile read and write
  // signatures we can choose to plant either of the above two code
  // sequences. For a volatile read we can simply plant a normal
  // ldr<x> and translate the MemBarAcquire to a dmb. However, we can
  // also choose to inhibit translation of the MemBarAcquire and
  // inhibit planting of the ldr<x>, instead planting an ldar<x>.
  //
  // When we recognise a volatile store signature we can choose to
  // plant at a dmb ish as a translation for the MemBarRelease, a
  // normal str<x> and then a dmb ish for the MemBarVolatile.
  // Alternatively, we can inhibit translation of the MemBarRelease
  // and MemBarVolatile and instead plant a simple stlr<x>
  // instruction.
  //
  // when we recognise a CAS signature we can choose to plant a dmb
  // ish as a translation for the MemBarRelease, the conventional
  // macro-instruction sequence for the CompareAndSwap node (which
  // uses ldxr<x>) and then a dmb ishld for the MemBarAcquire.
  // Alternatively, we can elide generation of the dmb instructions
  // and plant the alternative CompareAndSwap macro-instruction
  // sequence (which uses ldaxr<x>).
  //
  // Of course, the above only applies when we see these signature
  // configurations. We still want to plant dmb instructions in any
  // other cases where we may see a MemBarAcquire, MemBarRelease or
  // MemBarVolatile. For example, at the end of a constructor which
  // writes final/volatile fields we will see a MemBarRelease
  // instruction and this needs a 'dmb ish' lest we risk the
  // constructed object being visible without making the
  // final/volatile field writes visible.
  //
  // n.b. the translation rules below which rely on detection of the
  // volatile signatures and insert ldar<x> or stlr<x> are failsafe.
  // If we see anything other than the signature configurations we
  // always just translate the loads and stores to ldr<x> and str<x>
  // and translate acquire, release and volatile membars to the
  // relevant dmb instructions.
  //

  // is_CAS(int opcode, bool maybe_volatile)
  //
  // return true if opcode is one of the possible CompareAndSwapX
  // values otherwise false.

  bool is_CAS(int opcode, bool maybe_volatile)
  {
    switch(opcode) {
      // We handle these
    case Op_CompareAndSwapI:
    case Op_CompareAndSwapL:
    case Op_CompareAndSwapP:
    case Op_CompareAndSwapN:
    case Op_ShenandoahCompareAndSwapP:
    case Op_ShenandoahCompareAndSwapN:
    case Op_CompareAndSwapB:
    case Op_CompareAndSwapS:
    case Op_GetAndSetI:
    case Op_GetAndSetL:
    case Op_GetAndSetP:
    case Op_GetAndSetN:
    case Op_GetAndAddI:
    case Op_GetAndAddL:
      return true;
    case Op_CompareAndExchangeI:
    case Op_CompareAndExchangeN:
    case Op_CompareAndExchangeB:
    case Op_CompareAndExchangeS:
    case Op_CompareAndExchangeL:
    case Op_CompareAndExchangeP:
    case Op_WeakCompareAndSwapB:
    case Op_WeakCompareAndSwapS:
    case Op_WeakCompareAndSwapI:
    case Op_WeakCompareAndSwapL:
    case Op_WeakCompareAndSwapP:
    case Op_WeakCompareAndSwapN:
    case Op_ShenandoahWeakCompareAndSwapP:
    case Op_ShenandoahWeakCompareAndSwapN:
    case Op_ShenandoahCompareAndExchangeP:
    case Op_ShenandoahCompareAndExchangeN:
      return maybe_volatile;
    default:
      return false;
    }
  }

  // helper to determine the maximum number of Phi nodes we may need to
  // traverse when searching from a card mark membar for the merge mem
  // feeding a trailing membar or vice versa

// predicates controlling emit of ldr<x>/ldar<x>

bool unnecessary_acquire(const Node *barrier)
{
  assert(barrier->is_MemBar(), "expecting a membar");

  MemBarNode* mb = barrier->as_MemBar();

  if (mb->trailing_load()) {
    return true;
  }

  if (mb->trailing_load_store()) {
    Node* load_store = mb->in(MemBarNode::Precedent);
    assert(load_store->is_LoadStore(), "unexpected graph shape");
    return is_CAS(load_store->Opcode(), true);
  }

  return false;
}

bool needs_acquiring_load(const Node *n)
{
  assert(n->is_Load(), "expecting a load");
  LoadNode *ld = n->as_Load();
  return ld->is_acquire();
}

bool unnecessary_release(const Node *n)
{
  assert((n->is_MemBar() &&
          n->Opcode() == Op_MemBarRelease),
         "expecting a release membar");

  MemBarNode *barrier = n->as_MemBar();
  if (!barrier->leading()) {
    return false;
  } else {
    Node* trailing = barrier->trailing_membar();
    MemBarNode* trailing_mb = trailing->as_MemBar();
    assert(trailing_mb->trailing(), "Not a trailing membar?");
    assert(trailing_mb->leading_membar() == n, "inconsistent leading/trailing membars");

    Node* mem = trailing_mb->in(MemBarNode::Precedent);
    if (mem->is_Store()) {
      assert(mem->as_Store()->is_release(), "");
      assert(trailing_mb->Opcode() == Op_MemBarVolatile, "");
      return true;
    } else {
      assert(mem->is_LoadStore(), "");
      assert(trailing_mb->Opcode() == Op_MemBarAcquire, "");
      return is_CAS(mem->Opcode(), true);
    }
  }
  return false;
}

bool unnecessary_volatile(const Node *n)
{
  // assert n->is_MemBar();
  MemBarNode *mbvol = n->as_MemBar();

  bool release = mbvol->trailing_store();
  assert(!release || (mbvol->in(MemBarNode::Precedent)->is_Store() && mbvol->in(MemBarNode::Precedent)->as_Store()->is_release()), "");
#ifdef ASSERT
  if (release) {
    Node* leading = mbvol->leading_membar();
    assert(leading->Opcode() == Op_MemBarRelease, "");
    assert(leading->as_MemBar()->leading_store(), "");
    assert(leading->as_MemBar()->trailing_membar() == mbvol, "");
  }
#endif

  return release;
}

// predicates controlling emit of str<x>/stlr<x>

bool needs_releasing_store(const Node *n)
{
  // assert n->is_Store();
  StoreNode *st = n->as_Store();
  return st->trailing_membar() != NULL;
}

// predicate controlling translation of CAS
//
// returns true if CAS needs to use an acquiring load otherwise false

bool needs_acquiring_load_exclusive(const Node *n)
{
  assert(is_CAS(n->Opcode(), true), "expecting a compare and swap");
  LoadStoreNode* ldst = n->as_LoadStore();
  if (is_CAS(n->Opcode(), false)) {
    assert(ldst->trailing_membar() != NULL, "expected trailing membar");
  } else {
    return ldst->trailing_membar() != NULL;
  }

  // so we can just return true here
  return true;
}

#define __ _masm.

// advance declarations for helper functions to convert register
// indices to register objects

// the ad file has to provide implementations of certain methods
// expected by the generic code
//
// REQUIRED FUNCTIONALITY

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

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

int MachCallStaticJavaNode::ret_addr_offset()
{
  // call should be a simple bl
  int off = 4;
  return off;
}

int MachCallDynamicJavaNode::ret_addr_offset()
{
  return 16; // movz, movk, movk, bl
}

int MachCallRuntimeNode::ret_addr_offset() {
  // for generated stubs the call will be
  //   bl(addr)
  // or with far branches
  //   bl(trampoline_stub)
  // for real runtime callouts it will be six instructions
  // see aarch64_enc_java_to_runtime
  //   adr(rscratch2, retaddr)
  //   lea(rscratch1, RuntimeAddress(addr)
  //   stp(zr, rscratch2, Address(__ pre(sp, -2 * wordSize)))
  //   blr(rscratch1)
  CodeBlob *cb = CodeCache::find_blob(_entry_point);
  if (cb) {
    return 1 * NativeInstruction::instruction_size;
  } else {
    return 6 * NativeInstruction::instruction_size;
  }
}

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

#ifndef PRODUCT
void MachBreakpointNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
  st->print("BREAKPOINT");
}
#endif

void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  C2_MacroAssembler _masm(&cbuf);
  __ brk(0);
}

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

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

#ifndef PRODUCT
  void MachNopNode::format(PhaseRegAlloc*, outputStream* st) const {
    st->print("nop \t# %d bytes pad for loops and calls", _count);
  }
#endif

  void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc*) const {
    C2_MacroAssembler _masm(&cbuf);
    for (int i = 0; i < _count; i++) {
      __ nop();
    }
  }

  uint MachNopNode::size(PhaseRegAlloc*) const {
    return _count * NativeInstruction::instruction_size;
  }

//=============================================================================
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;

int ConstantTable::calculate_table_base_offset() const {
  return 0;  // absolute addressing, no offset
}

bool MachConstantBaseNode::requires_postalloc_expand() const { return false; }
void MachConstantBaseNode::postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_) {
  ShouldNotReachHere();
}

void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
  // Empty encoding
}

uint MachConstantBaseNode::size(PhaseRegAlloc* ra_) const {
  return 0;
}

#ifndef PRODUCT
void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
  st->print("-- \t// MachConstantBaseNode (empty encoding)");
}
#endif

#ifndef PRODUCT
void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
  Compile* C = ra_->C;

  int framesize = C->output()->frame_slots() << LogBytesPerInt;

  if (C->output()->need_stack_bang(framesize))
    st->print("# stack bang size=%d\n\t", framesize);

  if (VM_Version::use_rop_protection()) {
    st->print("ldr zr, [lr]\n\t");
    st->print("pacia  lr, rfp\n\t");
  }
  if (framesize < ((1 << 9) + 2 * wordSize)) {
    st->print("sub  sp, sp, #%d\n\t", framesize);
    st->print("stp  rfp, lr, [sp, #%d]", framesize - 2 * wordSize);
    if (PreserveFramePointer) st->print("\n\tadd  rfp, sp, #%d", framesize - 2 * wordSize);
  } else {
    st->print("stp  lr, rfp, [sp, #%d]!\n\t", -(2 * wordSize));
    if (PreserveFramePointer) st->print("mov  rfp, sp\n\t");
    st->print("mov  rscratch1, #%d\n\t", framesize - 2 * wordSize);
    st->print("sub  sp, sp, rscratch1");
  }
  if (C->stub_function() == NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) {
    st->print("\n\t");
    st->print("ldr  rscratch1, [guard]\n\t");
    st->print("dmb ishld\n\t");
    st->print("ldr  rscratch2, [rthread, #thread_disarmed_offset]\n\t");
    st->print("cmp  rscratch1, rscratch2\n\t");
    st->print("b.eq skip");
    st->print("\n\t");
    st->print("blr #nmethod_entry_barrier_stub\n\t");
    st->print("b skip\n\t");
    st->print("guard: int\n\t");
    st->print("\n\t");
    st->print("skip:\n\t");
  }
}
#endif

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

  // n.b. frame size includes space for return pc and rfp
  const int framesize = C->output()->frame_size_in_bytes();

  // insert a nop at the start of the prolog so we can patch in a
  // branch if we need to invalidate the method later
  __ nop();

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

    Label L_skip_barrier;

    __ mov_metadata(rscratch2, C->method()->holder()->constant_encoding());
    __ clinit_barrier(rscratch2, rscratch1, &L_skip_barrier);
    __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub()));
    __ bind(L_skip_barrier);
  }

  if (C->max_vector_size() > 0) {
    __ reinitialize_ptrue();
  }

  int bangsize = C->output()->bang_size_in_bytes();
  if (C->output()->need_stack_bang(bangsize))
    __ generate_stack_overflow_check(bangsize);

  __ build_frame(framesize);

  if (C->stub_function() == NULL) {
    BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
    if (BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) {
      // Dummy labels for just measuring the code size
      Label dummy_slow_path;
      Label dummy_continuation;
      Label dummy_guard;
      Label* slow_path = &dummy_slow_path;
      Label* continuation = &dummy_continuation;
      Label* guard = &dummy_guard;
      if (!Compile::current()->output()->in_scratch_emit_size()) {
        // Use real labels from actual stub when not emitting code for the purpose of measuring its size
        C2EntryBarrierStub* stub = Compile::current()->output()->entry_barrier_table()->add_entry_barrier();
        slow_path = &stub->slow_path();
        continuation = &stub->continuation();
        guard = &stub->guard();
      }
      // In the C2 code, we move the non-hot part of nmethod entry barriers out-of-line to a stub.
      bs->nmethod_entry_barrier(&_masm, slow_path, continuation, guard);
    }
  }

  if (VerifyStackAtCalls) {
    Unimplemented();
  }

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

  if (C->has_mach_constant_base_node()) {
    // NOTE: We set the table base offset here because users might be
    // emitted before MachConstantBaseNode.
    ConstantTable& constant_table = C->output()->constant_table();
    constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
  }
}

uint MachPrologNode::size(PhaseRegAlloc* ra_) const
{
  return MachNode::size(ra_); // too many variables; just compute it
                              // the hard way
}

int MachPrologNode::reloc() const
{
  return 0;
}

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

#ifndef PRODUCT
void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
  Compile* C = ra_->C;
  int framesize = C->output()->frame_slots() << LogBytesPerInt;

  st->print("# pop frame %d\n\t",framesize);

  if (framesize == 0) {
    st->print("ldp  lr, rfp, [sp],#%d\n\t", (2 * wordSize));
  } else if (framesize < ((1 << 9) + 2 * wordSize)) {
    st->print("ldp  lr, rfp, [sp,#%d]\n\t", framesize - 2 * wordSize);
    st->print("add  sp, sp, #%d\n\t", framesize);
  } else {
    st->print("mov  rscratch1, #%d\n\t", framesize - 2 * wordSize);
    st->print("add  sp, sp, rscratch1\n\t");
    st->print("ldp  lr, rfp, [sp],#%d\n\t", (2 * wordSize));
  }
  if (VM_Version::use_rop_protection()) {
    st->print("autia lr, rfp\n\t");
    st->print("ldr zr, [lr]\n\t");
  }

  if (do_polling() && C->is_method_compilation()) {
    st->print("# test polling word\n\t");
    st->print("ldr  rscratch1, [rthread],#%d\n\t", in_bytes(JavaThread::polling_word_offset()));
    st->print("cmp  sp, rscratch1\n\t");
    st->print("bhi #slow_path");
  }
}
#endif

void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  Compile* C = ra_->C;
  C2_MacroAssembler _masm(&cbuf);
  int framesize = C->output()->frame_slots() << LogBytesPerInt;

  __ remove_frame(framesize);

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

  if (do_polling() && C->is_method_compilation()) {
    Label dummy_label;
    Label* code_stub = &dummy_label;
    if (!C->output()->in_scratch_emit_size()) {
      code_stub = &C->output()->safepoint_poll_table()->add_safepoint(__ offset());
    }
    __ relocate(relocInfo::poll_return_type);
    __ safepoint_poll(*code_stub, true /* at_return */, false /* acquire */, true /* in_nmethod */);
  }
}

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

int MachEpilogNode::reloc() const {
  // Return number of relocatable values contained in this instruction.
  return 1; // 1 for polling page.
}

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

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

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

static enum RC rc_class(OptoReg::Name reg) {

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

  // we have 32 int registers * 2 halves
  int slots_of_int_registers = Register::number_of_registers * Register::max_slots_per_register;

  if (reg < slots_of_int_registers) {
    return rc_int;
  }

  // we have 32 float register * 8 halves
  int slots_of_float_registers = FloatRegister::number_of_registers * FloatRegister::max_slots_per_register;
  if (reg < slots_of_int_registers + slots_of_float_registers) {
    return rc_float;
  }

  int slots_of_predicate_registers = PRegister::number_of_registers * PRegister::max_slots_per_register;
  if (reg < slots_of_int_registers + slots_of_float_registers + slots_of_predicate_registers) {
    return rc_predicate;
  }

  // Between predicate regs & stack is the flags.
  assert(OptoReg::is_stack(reg), "blow up if spilling flags");

  return rc_stack;
}

uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, bool do_size, outputStream *st) const {
  Compile* C = ra_->C;

  // Get registers to move.
  OptoReg::Name src_hi = ra_->get_reg_second(in(1));
  OptoReg::Name src_lo = ra_->get_reg_first(in(1));
  OptoReg::Name dst_hi = ra_->get_reg_second(this);
  OptoReg::Name dst_lo = ra_->get_reg_first(this);

  enum RC src_hi_rc = rc_class(src_hi);
  enum RC src_lo_rc = rc_class(src_lo);
  enum RC dst_hi_rc = rc_class(dst_hi);
  enum RC dst_lo_rc = rc_class(dst_lo);

  assert(src_lo != OptoReg::Bad && dst_lo != OptoReg::Bad, "must move at least 1 register");

  if (src_hi != OptoReg::Bad && !bottom_type()->isa_vectmask()) {
    assert((src_lo&1)==0 && src_lo+1==src_hi &&
           (dst_lo&1)==0 && dst_lo+1==dst_hi,
           "expected aligned-adjacent pairs");
  }

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

  bool is64 = (src_lo & 1) == 0 && src_lo + 1 == src_hi &&
              (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi;
  int src_offset = ra_->reg2offset(src_lo);
  int dst_offset = ra_->reg2offset(dst_lo);

  if (bottom_type()->isa_vect() && !bottom_type()->isa_vectmask()) {
    uint ireg = ideal_reg();
    if (ireg == Op_VecA && cbuf) {
      C2_MacroAssembler _masm(cbuf);
      int sve_vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE);
      if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {
        // stack->stack
        __ spill_copy_sve_vector_stack_to_stack(src_offset, dst_offset,
                                                sve_vector_reg_size_in_bytes);
      } else if (src_lo_rc == rc_float && dst_lo_rc == rc_stack) {
        __ spill_sve_vector(as_FloatRegister(Matcher::_regEncode[src_lo]), ra_->reg2offset(dst_lo),
                            sve_vector_reg_size_in_bytes);
      } else if (src_lo_rc == rc_stack && dst_lo_rc == rc_float) {
        __ unspill_sve_vector(as_FloatRegister(Matcher::_regEncode[dst_lo]), ra_->reg2offset(src_lo),
                              sve_vector_reg_size_in_bytes);
      } else if (src_lo_rc == rc_float && dst_lo_rc == rc_float) {
        __ sve_orr(as_FloatRegister(Matcher::_regEncode[dst_lo]),
                   as_FloatRegister(Matcher::_regEncode[src_lo]),
                   as_FloatRegister(Matcher::_regEncode[src_lo]));
      } else {
        ShouldNotReachHere();
      }
    } else if (cbuf) {
      assert(ireg == Op_VecD || ireg == Op_VecX, "must be 64 bit or 128 bit vector");
      C2_MacroAssembler _masm(cbuf);
      assert((src_lo_rc != rc_int && dst_lo_rc != rc_int), "sanity");
      if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {
        // stack->stack
        assert((src_offset & 7) == 0 && (dst_offset & 7) == 0, "unaligned stack offset");
        if (ireg == Op_VecD) {
          __ unspill(rscratch1, true, src_offset);
          __ spill(rscratch1, true, dst_offset);
        } else {
          __ spill_copy128(src_offset, dst_offset);
        }
      } else if (src_lo_rc == rc_float && dst_lo_rc == rc_float) {
        __ mov(as_FloatRegister(Matcher::_regEncode[dst_lo]),
               ireg == Op_VecD ? __ T8B : __ T16B,
               as_FloatRegister(Matcher::_regEncode[src_lo]));
      } else if (src_lo_rc == rc_float && dst_lo_rc == rc_stack) {
        __ spill(as_FloatRegister(Matcher::_regEncode[src_lo]),
                 ireg == Op_VecD ? __ D : __ Q,
                 ra_->reg2offset(dst_lo));
      } else if (src_lo_rc == rc_stack && dst_lo_rc == rc_float) {
        __ unspill(as_FloatRegister(Matcher::_regEncode[dst_lo]),
                   ireg == Op_VecD ? __ D : __ Q,
                   ra_->reg2offset(src_lo));
      } else {
        ShouldNotReachHere();
      }
    }
  } else if (cbuf) {
    C2_MacroAssembler _masm(cbuf);
    switch (src_lo_rc) {
    case rc_int:
      if (dst_lo_rc == rc_int) {  // gpr --> gpr copy
        if (is64) {
            __ mov(as_Register(Matcher::_regEncode[dst_lo]),
                   as_Register(Matcher::_regEncode[src_lo]));
        } else {
            C2_MacroAssembler _masm(cbuf);
            __ movw(as_Register(Matcher::_regEncode[dst_lo]),
                    as_Register(Matcher::_regEncode[src_lo]));
        }
      } else if (dst_lo_rc == rc_float) { // gpr --> fpr copy
        if (is64) {
            __ fmovd(as_FloatRegister(Matcher::_regEncode[dst_lo]),
                     as_Register(Matcher::_regEncode[src_lo]));
        } else {
            __ fmovs(as_FloatRegister(Matcher::_regEncode[dst_lo]),
--> --------------------

--> maximum size reached

--> --------------------

[ 0.44Quellennavigators  Projekt   ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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