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


Quellcode-Bibliothek

© Kompilation durch diese Firma

[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]

Datei:   Sprache: Unknown

Columbo aufrufen.ad zum Wurzelverzeichnis wechselnSML {SML[185] C[216] BAT[486]}Datei anzeigen

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

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

[ Original von:0.545Diese Quellcodebibliothek enthält Beispiele in vielen Programmiersprachen. Man kann per Verzeichnistruktur darin navigieren. Der Code wird farblich markiert angezeigt.  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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