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


Impressum aarch64_vector_ad.m4

  Sprache: Shell
 

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

dnl Generate the warning
// This file is automatically generated by running "m4 aarch64_vector_ad.m4"Do not edit!
dnl

// AArch64 VECTOR Architecture Description File


dnl
dnl OPERAND_VMEMORYA_IMMEDIATE_OFFSET($1,            $2      )
dnl OPERAND_VMEMORYA_IMMEDIATE_OFFSET(imm_type_abbr, imm_type)
define(`OPERAND_VMEMORYA_IMMEDIATE_OFFSET', `
operand vmemA_imm$1Offset4() %{
  // (esize / msize) = 1
  predicate(Address::offset_ok_for_sve_immed(n->get_$2(), 4,
            Matcher::scalable_vector_reg_size(T_BYTE)));
  match(Con$1);
  op_cost(0);
  format %{ %}
  interface(CONST_INTER);
%}')dnl
dnl
dnl OPERAND_VMEMORYA_INDIRECT_OFFSET($1           )
dnl OPERAND_VMEMORYA_INDIRECT_OFFSET(imm_type_abbr)
define(`OPERAND_VMEMORYA_INDIRECT_OFFSET', `
operand vmemA_indOff$1`'4(iRegP reg, vmemA_imm$1Offset4 off) %{
  constraint(ALLOC_IN_RC(ptr_reg));
  match(AddP reg off);
  op_cost(0);
  format %{ "[$reg, $off]" %}
  interface(MEMORY_INTER) %{
    base($reg);
    `index'(0xffffffff);
    scale(0x0);
    disp($off);
  %}
%}')dnl
dnl
// 4 bit signed offset -- for predicated load/store
OPERAND_VMEMORYA_IMMEDIATE_OFFSET(I, int)
OPERAND_VMEMORYA_IMMEDIATE_OFFSET(L, long)
OPERAND_VMEMORYA_INDIRECT_OFFSET(I)
OPERAND_VMEMORYA_INDIRECT_OFFSET(L)

// The indOff of vmemA is valid only when the vector element (load to/store from)
// size equals to memory element (load from/store to) size.
opclass vmemA(indirect, vmemA_indOffI4, vmemA_indOffL4);

source_hpp %{
  // Assert that the given node is not a variable shift.
  bool assert_not_var_shift(const Node* n);

  Assembler::SIMD_Arrangement get_arrangement(const Node* n);
%}

source %{

  typedef void (C2_MacroAssembler::* sve_mem_insn_predicate)(FloatRegister Rt, Assembler::SIMD_RegVariant T,
                                                             PRegister Pg, const Address &adr);

  // Predicated load/store, with optional ptrue to all elements of given predicate register.
  static void loadStoreA_predicated(C2_MacroAssembler masm, bool is_store, FloatRegister reg,
                                    PRegister pg, BasicType mem_elem_bt, BasicType vector_elem_bt,
                                    int opcode, Register base, int index, int size, int disp) {
    sve_mem_insn_predicate insn;
    int mesize = type2aelembytes(mem_elem_bt);
    if (index == -1) {
      assert(size == 0, "unsupported address mode: scale size = %d", size);
      switch(mesize) {
      case 1:
        insn = is_store ? &C2_MacroAssembler::sve_st1b : &C2_MacroAssembler::sve_ld1b;
        break;
      case 2:
        insn = is_store ? &C2_MacroAssembler::sve_st1h : &C2_MacroAssembler::sve_ld1h;
        break;
      case 4:
        insn = is_store ? &C2_MacroAssembler::sve_st1w : &C2_MacroAssembler::sve_ld1w;
        break;
      case 8:
        insn = is_store ? &C2_MacroAssembler::sve_st1d : &C2_MacroAssembler::sve_ld1d;
        break;
      default:
        assert(false, "unsupported");
        ShouldNotReachHere();
      }
      int imm4 = disp / mesize / Matcher::scalable_vector_reg_size(vector_elem_bt);
      (masm.*insn)(reg, Assembler::elemType_to_regVariant(vector_elem_bt), pg, Address(base, imm4));
    } else {
      assert(false, "unimplemented");
      ShouldNotReachHere();
    }
  }

  const bool Matcher::match_rule_supported_superword(int opcode, int vlen, BasicType bt) {
    if (UseSVE == 0) {
      // These operations are not profitable to be vectorized on NEON, because no direct
      // NEON instructions support them. But the match rule support for them is profitable for
      // Vector API intrinsics.
      if ((opcode == Op_VectorCastD2X && bt == T_INT) ||
          (opcode == Op_VectorCastL2X && bt == T_FLOAT) ||
          (opcode == Op_CountLeadingZerosV && bt == T_LONG) ||
          (opcode == Op_CountTrailingZerosV && bt == T_LONG) ||
          opcode == Op_AddReductionVD || opcode == Op_AddReductionVF ||
          opcode == Op_MulReductionVD || opcode == Op_MulReductionVF ||
          opcode == Op_MulVL) {
        return false;
      }
    }
    return match_rule_supported_vector(opcode, vlen, bt);
  }

  // Identify extra cases that we might want to provide match rules for vector nodes and
  // other intrinsics guarded with vector length (vlen) and element type (bt).
  const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) {
    if (!match_rule_supported(opcode)) {
      return false;
    }

    int length_in_bytes = vlen * type2aelembytes(bt);
    if (UseSVE == 0 && length_in_bytes > 16) {
      return false;
    }

    // Check whether specific Op is supported.
    // Fail fast, otherwise fall through to common vector_size_supported() check.
    switch (opcode) {
      case Op_AndVMask:
      case Op_OrVMask:
      case Op_XorVMask:
      case Op_MaskAll:
      case Op_VectorMaskGen:
      case Op_LoadVectorMasked:
      case Op_StoreVectorMasked:
      case Op_LoadVectorGather:
      case Op_StoreVectorScatter:
      case Op_LoadVectorGatherMasked:
      case Op_StoreVectorScatterMasked:
      case Op_PopulateIndex:
      case Op_CompressM:
      case Op_CompressV:
        if (UseSVE == 0) {
          return false;
        }
        break;
      case Op_MulAddVS2VI:
        if (length_in_bytes != 16) {
          return false;
        }
        break;
      case Op_MulReductionVD:
      case Op_MulReductionVF:
      case Op_MulReductionVI:
      case Op_MulReductionVL:
        // No vector multiply reduction instructions, but we do
        // emit scalar instructions for 64/128-bit vectors.
        if (length_in_bytes != 8 && length_in_bytes != 16) {
          return false;
        }
        break;
      case Op_VectorMaskCmp:
        if (length_in_bytes < 8) {
          return false;
        }
        break;
      case Op_VectorLoadShuffle:
      case Op_VectorRearrange:
        if (vlen < 4) {
          return false;
        }
        break;
      case Op_ExpandV:
        if (UseSVE < 2 || is_subword_type(bt)) {
          return false;
        }
        break;
      case Op_VectorMaskToLong:
        if (UseSVE > 0 && vlen > 64) {
          return false;
        }
        break;
      case Op_VectorLongToMask:
        if (UseSVE < 2 || vlen > 64 || !VM_Version::supports_svebitperm()) {
          return false;
        }
        break;
      default:
        break;
    }
    return vector_size_supported(bt, vlen);
  }

  const bool Matcher::match_rule_supported_vector_masked(int opcode, int vlen, BasicType bt) {
    // Only SVE supports masked operations.
    if (UseSVE == 0) {
      return false;
    }

    // If an opcode does not support the masked version,
    // unpredicated node with VectorBlend node will be used instead.
    switch(opcode) {
      case Op_VectorRearrange:
      case Op_MulReductionVD:
      case Op_MulReductionVF:
      case Op_MulReductionVI:
      case Op_MulReductionVL:
        return false;
      // We use Op_LoadVectorMasked to implement the predicated Op_LoadVector.
      // Hence we turn to check whether Op_LoadVectorMasked is supported. The
      // same as vector store/gather/scatter.
      case Op_LoadVector:
        opcode = Op_LoadVectorMasked;
        break;
      case Op_StoreVector:
        opcode = Op_StoreVectorMasked;
        break;
      case Op_LoadVectorGather:
        opcode = Op_LoadVectorGatherMasked;
        break;
      case Op_StoreVectorScatter:
        opcode = Op_StoreVectorScatterMasked;
        break;
      default:
        break;
    }

    return match_rule_supported_vector(opcode, vlen, bt);
  }

  const bool Matcher::vector_needs_partial_operations(Node* node, const TypeVect* vt) {
    // Only SVE has partial vector operations
    if (UseSVE == 0) {
      return false;
    }

    switch(node->Opcode()) {
      case Op_VectorLoadMask:
      case Op_VectorMaskCmp:
      case Op_LoadVectorGather:
      case Op_StoreVectorScatter:
      case Op_AddReductionVF:
      case Op_AddReductionVD:
      case Op_AndReductionV:
      case Op_OrReductionV:
      case Op_XorReductionV:
      // Mask is needed for partial Op_VectorMaskFirstTrue, because when the
      // input predicate is all-false, the result should be the vector length
      // instead of the vector register size.
      case Op_VectorMaskFirstTrue:
        return true;
      case Op_MaskAll:
        return !node->in(1)->is_Con();
      case Op_LoadVector:
      case Op_StoreVector:
        // We use NEON load/store instructions if the vector length is <= 128 bits.
        return vt->length_in_bytes() > 16;
      case Op_AddReductionVI:
      case Op_AddReductionVL:
        // We may prefer using NEON instructions rather than SVE partial operations.
        return !VM_Version::use_neon_for_vector(vt->length_in_bytes());
      case Op_MinReductionV:
      case Op_MaxReductionV:
        // For BYTE/SHORT/INT/FLOAT/DOUBLE types, we may prefer using NEON
        // instructions rather than SVE partial operations.
        return vt->element_basic_type() == T_LONG ||
               !VM_Version::use_neon_for_vector(vt->length_in_bytes());
      default:
        // For other ops whose vector size is smaller than the max vector size, a
        // full-sized unpredicated operation does not impact the final vector result.
        return false;
    }
  }

  // Assert that the given node is not a variable shift.
  bool assert_not_var_shift(const Node* n) {
    assert(!n->as_ShiftV()->is_var_shift(), "illegal variable shift");
    return true;
  }

  Assembler::SIMD_Arrangement get_arrangement(const Node* n) {
    BasicType bt = Matcher::vector_element_basic_type(n);
    uint length_in_bytes = Matcher::vector_length_in_bytes(n);
    return Assembler::esize2arrangement((uint)type2aelembytes(bt),
                                        /* isQ */ length_in_bytes == 16);
  }
%}


// All VECTOR instructions

// ------------------------------ Vector load/store ----------------------------
dnl
dnl VECTOR_LOAD_STORE($1,   $2,     $3,       $4,    $5  )
dnl VECTOR_LOAD_STORE(type, nbytes, arg_name, nbits, size)
define(`VECTOR_LOAD_STORE', `
// ifelse(load, $1, Load, Store) Vector ($4 bits)
instruct $1V$2(vReg $3, vmem$2 mem) %{
  predicate(`n->as_'ifelse(load, $1, Load, Store)Vector()->memory_size() == $2);
  match(Set ifelse(load, $1, dst (LoadVector mem), mem (StoreVector mem src)));
  format %{ "$1V$2 ifelse(load, $1, `$dst, $mem', `$mem, $src')\t# vector ($4 bits)" %}
  ins_encode( `aarch64_enc_'ifelse(load, $1, ldr, str)v$5($3, mem) );
  ins_pipe(pipe_slow);
%}')dnl
dnl
VECTOR_LOAD_STORE(load,  2,  dst, 16,  H)
VECTOR_LOAD_STORE(store, 2,  src, 16,  H)
VECTOR_LOAD_STORE(load,  4,  dst, 32,  S)
VECTOR_LOAD_STORE(store, 4,  src, 32,  S)
VECTOR_LOAD_STORE(load,  8,  dst, 64,  D)
VECTOR_LOAD_STORE(store, 8,  src, 64,  D)
VECTOR_LOAD_STORE(load,  16, dst, 128, Q)
VECTOR_LOAD_STORE(store, 16, src, 128, Q)

// Load Vector (> 128 bits)
instruct loadV(vReg dst, vmemA mem) %{
  predicate(n->as_LoadVector()->memory_size() > 16);
  match(Set dst (LoadVector mem));
  format %{ "loadV $dst, $mem\t# vector (sve)" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), /* is_store */ false,
                          $dst$$FloatRegister, ptrue, bt, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
  %}
  ins_pipe(pipe_slow);
%}

// Store Vector (> 128 bits)
instruct storeV(vReg src, vmemA mem) %{
  predicate(n->as_StoreVector()->memory_size() > 16);
  match(Set mem (StoreVector mem src));
  format %{ "storeV $mem, $src\t# vector (sve)" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), /* is_store */ true,
                          $src$$FloatRegister, ptrue, bt, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
  %}
  ins_pipe(pipe_slow);
%}

// vector load/store - predicated

instruct loadV_masked(vReg dst, vmemA mem, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst (LoadVectorMasked mem pg));
  format %{ "loadV_masked $dst, $pg, $mem" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), /* is_store */ false, $dst$$FloatRegister,
                          $pg$$PRegister, bt, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
  %}
  ins_pipe(pipe_slow);
%}

instruct storeV_masked(vReg src, vmemA mem, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set mem (StoreVectorMasked mem (Binary src pg)));
  format %{ "storeV_masked $mem, $pg, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), /* is_store */ true, $src$$FloatRegister,
                          $pg$$PRegister, bt, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
  %}
  ins_pipe(pipe_slow);
%}

// vector load const

instruct vloadcon(vReg dst, immI0 src) %{
  match(Set dst (VectorLoadConst src));
  format %{ "vloadcon $dst, $src\t# load/generate iota indices" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    if (UseSVE == 0) {
      uint length_in_bytes = Matcher::vector_length_in_bytes(this);
      assert(length_in_bytes <= 16, "must be");
      // The iota indices are ordered by type B/S/I/L/F/D, and the offset between two types is 16.
      int offset = exact_log2(type2aelembytes(bt)) << 4;
      if (is_floating_point_type(bt)) {
        offset += 32;
      }
      __ lea(rscratch1, ExternalAddress(StubRoutines::aarch64::vector_iota_indices() + offset));
      if (length_in_bytes == 16) {
        __ ldrq($dst$$FloatRegister, rscratch1);
      } else {
        __ ldrd($dst$$FloatRegister, rscratch1);
      }
    } else {
      Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
      __ sve_index($dst$$FloatRegister, size, 0, 1);
      if (is_floating_point_type(bt)) {
        __ sve_scvtf($dst$$FloatRegister, size, ptrue, $dst$$FloatRegister, size);
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

dnl
dnl BINARY_OP($1,        $2,      $3,        $4,       $5  )
dnl BINARY_OP(rule_name, op_name, insn_neon, insn_sve, size)
define(`BINARY_OP', `
instruct $1(vReg dst, vReg src1, vReg src2) %{
  match(Set dst ($2 src1 src2));
  format %{ "$1 $dst, $src1, $src2" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ $3($dst$$FloatRegister, get_arrangement(this),
              $src1$$FloatRegister, $src2$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ $4($dst$$FloatRegister, __ $5, $src1$$FloatRegister, $src2$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl BINARY_OP_PREDICATE($1,        $2,      $3,   $4  )
dnl BINARY_OP_PREDICATE(rule_name, op_name, insn, size)
define(`BINARY_OP_PREDICATE', `
instruct $1_masked(vReg dst_src1, vReg src2, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 ($2 (Binary dst_src1 src2) pg));
  format %{ "$1_masked $dst_src1, $pg, $dst_src1, $src2" %}
  ins_encode %{
    __ $3($dst_src1$$FloatRegister, __ $4, $pg$$PRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl VADD_IMM($1,   $2,       $3  )
dnl VADD_IMM(type, imm_type, size)
define(`VADD_IMM', `
instruct vaddImm$1(vReg dst_src, $2 con) %{
  predicate(UseSVE > 0);
  match(Set dst_src (AddV$1 dst_src (Replicate$1 con)));
  format %{ "vaddImm$1 $dst_src, $dst_src, $con" %}
  ins_encode %{
    int val = (int)$con$$constant;
    if (val > 0) {
      __ sve_add($dst_src$$FloatRegister, __ $3, val);
    } else {
      __ sve_sub($dst_src$$FloatRegister, __ $3, -val);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// ------------------------------ Vector add -----------------------------------

// vector add
BINARY_OP(vaddB, AddVB, addv, sve_add,  B)
BINARY_OP(vaddS, AddVS, addv, sve_add,  H)
BINARY_OP(vaddI, AddVI, addv, sve_add,  S)
BINARY_OP(vaddL, AddVL, addv, sve_add,  D)
BINARY_OP(vaddF, AddVF, fadd, sve_fadd, S)
BINARY_OP(vaddD, AddVD, fadd, sve_fadd, D)

// vector add - predicated
BINARY_OP_PREDICATE(vaddB, AddVB, sve_add,  B)
BINARY_OP_PREDICATE(vaddS, AddVS, sve_add,  H)
BINARY_OP_PREDICATE(vaddI, AddVI, sve_add,  S)
BINARY_OP_PREDICATE(vaddL, AddVL, sve_add,  D)
BINARY_OP_PREDICATE(vaddF, AddVF, sve_fadd, S)
BINARY_OP_PREDICATE(vaddD, AddVD, sve_fadd, D)

// vector add reg imm (unpredicated)
VADD_IMM(B, immBAddSubV, B)
VADD_IMM(S, immIAddSubV, H)
VADD_IMM(I, immIAddSubV, S)
VADD_IMM(L, immLAddSubV, D)

// ------------------------------ Vector sub -----------------------------------

// vector sub
BINARY_OP(vsubB, SubVB, subv, sve_sub,  B)
BINARY_OP(vsubS, SubVS, subv, sve_sub,  H)
BINARY_OP(vsubI, SubVI, subv, sve_sub,  S)
BINARY_OP(vsubL, SubVL, subv, sve_sub,  D)
BINARY_OP(vsubF, SubVF, fsub, sve_fsub, S)
BINARY_OP(vsubD, SubVD, fsub, sve_fsub, D)

// vector sub - predicated
BINARY_OP_PREDICATE(vsubB, SubVB, sve_sub,  B)
BINARY_OP_PREDICATE(vsubS, SubVS, sve_sub,  H)
BINARY_OP_PREDICATE(vsubI, SubVI, sve_sub,  S)
BINARY_OP_PREDICATE(vsubL, SubVL, sve_sub,  D)
BINARY_OP_PREDICATE(vsubF, SubVF, sve_fsub, S)
BINARY_OP_PREDICATE(vsubD, SubVD, sve_fsub, D)

dnl
dnl BINARY_OP_NEON_SVE_PAIRWISE($1,        $2,      $3,        $4,       $5  )
dnl BINARY_OP_NEON_SVE_PAIRWISE(rule_name, op_name, insn_neon, insn_sve, size)
define(`BINARY_OP_NEON_SVE_PAIRWISE', `
instruct $1_neon(vReg dst, vReg src1, vReg src2) %{
  predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)));
  match(Set dst ($2 src1 src2));
  format %{ "$1_neon $dst, $src1, $src2" %}
  ins_encode %{
    __ $3($dst$$FloatRegister, get_arrangement(this),
            $src1$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct $1_sve(vReg dst_src1, vReg src2) %{
  predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)));
  match(Set dst_src1 ($2 dst_src1 src2));
  format %{ "$1_sve $dst_src1, $dst_src1, $src2" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    __ $4($dst_src1$$FloatRegister, __ $5, ptrue, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// ------------------------------ Vector mul -----------------------------------

// vector mul - BYTE, CHAR, SHORT, INT
BINARY_OP_NEON_SVE_PAIRWISE(vmulB, MulVB, mulv, sve_mul, B)
BINARY_OP_NEON_SVE_PAIRWISE(vmulS, MulVS, mulv, sve_mul, H)
BINARY_OP_NEON_SVE_PAIRWISE(vmulI, MulVI, mulv, sve_mul, S)

// vector mul - LONG

instruct vmulL_neon(vReg dst, vReg src1, vReg src2) %{
  predicate(UseSVE == 0);
  match(Set dst (MulVL src1 src2));
  format %{ "vmulL_neon $dst, $src1, $src2\t# 2L" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == 16, "must be");
    __ umov(rscratch1, $src1$$FloatRegister, __ D, 0);
    __ umov(rscratch2, $src2$$FloatRegister, __ D, 0);
    __ mul(rscratch2, rscratch2, rscratch1);
    __ mov($dst$$FloatRegister, __ D, 0, rscratch2);
    __ umov(rscratch1, $src1$$FloatRegister, __ D, 1);
    __ umov(rscratch2, $src2$$FloatRegister, __ D, 1);
    __ mul(rscratch2, rscratch2, rscratch1);
    __ mov($dst$$FloatRegister, __ D, 1, rscratch2);
  %}
  ins_pipe(pipe_slow);
%}

instruct vmulL_sve(vReg dst_src1, vReg src2) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 (MulVL dst_src1 src2));
  format %{ "vmulL_sve $dst_src1, $dst_src1, $src2" %}
  ins_encode %{
    __ sve_mul($dst_src1$$FloatRegister, __ D, ptrue, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// vector mul - floating-point
BINARY_OP(vmulF, MulVF, fmul, sve_fmul, S)
BINARY_OP(vmulD, MulVD, fmul, sve_fmul, D)

// vector mul - predicated
BINARY_OP_PREDICATE(vmulB, MulVB, sve_mul,  B)
BINARY_OP_PREDICATE(vmulS, MulVS, sve_mul,  H)
BINARY_OP_PREDICATE(vmulI, MulVI, sve_mul,  S)
BINARY_OP_PREDICATE(vmulL, MulVL, sve_mul,  D)
BINARY_OP_PREDICATE(vmulF, MulVF, sve_fmul, S)
BINARY_OP_PREDICATE(vmulD, MulVD, sve_fmul, D)

// ------------------------------ Vector float div -----------------------------

// vector float div
BINARY_OP_NEON_SVE_PAIRWISE(vdivF, DivVF, fdiv, sve_fdiv, S)
BINARY_OP_NEON_SVE_PAIRWISE(vdivD, DivVD, fdiv, sve_fdiv, D)

// vector float div - predicated
BINARY_OP_PREDICATE(vdivF, DivVF, sve_fdiv, S)
BINARY_OP_PREDICATE(vdivD, DivVD, sve_fdiv, D)
dnl
dnl BITWISE_OP($1,        $2,      $3,        $4      )
dnl BITWISE_OP(rule_name, op_name, insn_neon, insn_sve)
define(`BITWISE_OP', `
instruct $1(vReg dst, vReg src1, vReg src2) %{
  match(Set dst ($2 src1 src2));
  format %{ "$1 $dst, $src1, $src2" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ $3($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
              $src1$$FloatRegister, $src2$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ $4($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl BITWISE_OP_PREDICATE($1,        $2,      $3  )
dnl BITWISE_OP_PREDICATE(rule_name, op_name, insn)
define(`BITWISE_OP_PREDICATE', `
instruct $1_masked(vReg dst_src1, vReg src2, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 ($2 (Binary dst_src1 src2) pg));
  format %{ "$1_masked $dst_src1, $pg, $dst_src1, $src2" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ $3($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
               $pg$$PRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl BITWISE_OP_IMM($1,        $2,   $3,      $4,   $5  )
dnl BITWISE_OP_IMM(rule_name, type, op_name, insn, size)
define(`BITWISE_OP_IMM', `
instruct $1(vReg dst_src, imm$2Log con) %{
  predicate(UseSVE > 0);
  match(Set dst_src ($3 dst_src (Replicate$2 con)));
  format %{ "$1 $dst_src, $dst_src, $con" %}
  ins_encode %{
    __ $4($dst_src$$FloatRegister, __ $5, (uint64_t)($con$$constant));
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl

// ------------------------------ Vector and -----------------------------------

// vector and
BITWISE_OP(vand, AndV, andr, sve_and)

// vector and - predicated
BITWISE_OP_PREDICATE(vand, AndV, sve_and)

// vector and reg imm (unpredicated)
BITWISE_OP_IMM(vandImmB, B, AndV, sve_and, B)
BITWISE_OP_IMM(vandImmS, S, AndV, sve_and, H)
BITWISE_OP_IMM(vandImmI, I, AndV, sve_and, S)
BITWISE_OP_IMM(vandImmL, L, AndV, sve_and, D)

// ------------------------------ Vector or ------------------------------------

// vector or
BITWISE_OP(vor, OrV, orr, sve_orr)

// vector or - predicated
BITWISE_OP_PREDICATE(vor, OrV, sve_orr)

// vector or reg imm (unpredicated)
BITWISE_OP_IMM(vorImmB, B, OrV, sve_orr, B)
BITWISE_OP_IMM(vorImmS, S, OrV, sve_orr, H)
BITWISE_OP_IMM(vorImmI, I, OrV, sve_orr, S)
BITWISE_OP_IMM(vorImmL, L, OrV, sve_orr, D)

// ------------------------------ Vector xor -----------------------------------

// vector xor
BITWISE_OP(vxor, XorV, eor, sve_eor)

// vector xor - predicated
BITWISE_OP_PREDICATE(vxor, XorV, sve_eor)

// vector xor reg imm (unpredicated)
BITWISE_OP_IMM(vxorImmB, B, XorV, sve_eor, B)
BITWISE_OP_IMM(vxorImmS, S, XorV, sve_eor, H)
BITWISE_OP_IMM(vxorImmI, I, XorV, sve_eor, S)
BITWISE_OP_IMM(vxorImmL, L, XorV, sve_eor, D)

// vector eor3 (unpredicated)

instruct veor3_neon(vReg dst, vReg src1, vReg src2, vReg src3) %{
  predicate(VM_Version::supports_sha3() &&
            VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)));
  match(Set dst (XorV src1 (XorV src2 src3)));
  format %{ "veor3_neon $dst, $src1, $src2, $src3" %}
  ins_encode %{
    __ eor3($dst$$FloatRegister, __ T16B, $src1$$FloatRegister,
            $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct veor3_sve(vReg dst_src1, vReg src2, vReg src3) %{
  predicate(UseSVE == 2 && !VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)));
  match(Set dst_src1 (XorV dst_src1 (XorV src2 src3)));
  format %{ "veor3_sve $dst_src1, $dst_src1, $src2, $src3" %}
  ins_encode %{
    __ sve_eor3($dst_src1$$FloatRegister, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector not -----------------------------------

dnl
define(`MATCH_RULE', `ifelse($1, I,
`match(Set dst (XorV src (ReplicateB m1)));
  match(Set dst (XorV src (ReplicateS m1)));
  match(Set dst (XorV src (ReplicateI m1)));',
`match(Set dst (XorV src (ReplicateL m1)));')')dnl
dnl
dnl VECTOR_NOT($1  )
dnl VECTOR_NOT(type)
define(`VECTOR_NOT', `
instruct vnot$1`'(vReg dst, vReg src, imm$1_M1 m1) %{
  MATCH_RULE($1)
  format %{ "vnot$1 $dst, $src" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ notr($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
              $src$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_not($dst$$FloatRegister, __ D, ptrue, $src$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// vector not
VECTOR_NOT(I)
VECTOR_NOT(L)
undefine(MATCH_RULE)
dnl
define(`MATCH_RULE', `ifelse($1, I,
`match(Set dst_src (XorV (Binary dst_src (ReplicateB m1)) pg));
  match(Set dst_src (XorV (Binary dst_src (ReplicateS m1)) pg));
  match(Set dst_src (XorV (Binary dst_src (ReplicateI m1)) pg));',
`match(Set dst_src (XorV (Binary dst_src (ReplicateL m1)) pg));')')dnl
dnl
dnl VECTOR_NOT_PREDICATE($1  )
dnl VECTOR_NOT_PREDICATE(type)
define(`VECTOR_NOT_PREDICATE', `
instruct vnot$1_masked`'(vReg dst_src, imm$1_M1 m1, pRegGov pg) %{
  predicate(UseSVE > 0);
  MATCH_RULE($1)
  format %{ "vnot$1_masked $dst_src, $pg, $dst_src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_not($dst_src$$FloatRegister, __ elemType_to_regVariant(bt),
               $pg$$PRegister, $dst_src$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// vector not - predicated
VECTOR_NOT_PREDICATE(I)
VECTOR_NOT_PREDICATE(L)
undefine(MATCH_RULE)
dnl
// ------------------------------ Vector and_not -------------------------------

dnl
define(`MATCH_RULE', `ifelse($1, I,
`match(Set dst (AndV src1 (XorV src2 (ReplicateB m1))));
  match(Set dst (AndV src1 (XorV src2 (ReplicateS m1))));
  match(Set dst (AndV src1 (XorV src2 (ReplicateI m1))));',
`match(Set dst (AndV src1 (XorV src2 (ReplicateL m1))));')')dnl
dnl
dnl VECTOR_AND_NOT($1  )
dnl VECTOR_AND_NOT(type)
define(`VECTOR_AND_NOT', `
instruct vand_not$1`'(vReg dst, vReg src1, vReg src2, imm$1_M1 m1) %{
  MATCH_RULE($1)
  format %{ "vand_not$1 $dst, $src1, $src2" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ bic($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
             $src1$$FloatRegister, $src2$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_bic($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// vector and_not
VECTOR_AND_NOT(I)
VECTOR_AND_NOT(L)
undefine(MATCH_RULE)
dnl
define(`MATCH_RULE', `ifelse($1, I,
`match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateB m1))) pg));
  match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateS m1))) pg));
  match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateI m1))) pg));',
`match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateL m1))) pg));')')dnl
dnl
dnl VECTOR_AND_NOT_PREDICATE($1  )
dnl VECTOR_AND_NOT_PREDICATE(type)
define(`VECTOR_AND_NOT_PREDICATE', `
instruct vand_not$1_masked`'(vReg dst_src1, vReg src2, imm$1_M1 m1, pRegGov pg) %{
  predicate(UseSVE > 0);
  MATCH_RULE($1)
  format %{ "vand_not$1_masked $dst_src1, $pg, $dst_src1, $src2" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_bic($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
               $pg$$PRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// vector and_not - predicated
VECTOR_AND_NOT_PREDICATE(I)
VECTOR_AND_NOT_PREDICATE(L)
undefine(MATCH_RULE)
dnl
dnl UNARY_OP($1,        $2,      $3,        $4,       $5  )
dnl UNARY_OP(rule_name, op_name, insn_neon, insn_sve, size)
define(`UNARY_OP', `
instruct $1(vReg dst, vReg src) %{
  match(Set dst ($2 src));
  format %{ "$1 $dst, $src" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ $3($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ $4($dst$$FloatRegister, __ $5, ptrue, $src$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl UNARY_OP_PREDICATE($1,        $2,      $3  )
dnl UNARY_OP_PREDICATE(rule_name, op_name, insn)
define(`UNARY_OP_PREDICATE', `
instruct $1_masked(vReg dst_src, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src ($2 dst_src pg));
  format %{ "$1_masked $dst_src, $pg, $dst_src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ $3($dst_src$$FloatRegister, __ elemType_to_regVariant(bt),
               $pg$$PRegister, $dst_src$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl UNARY_OP_PREDICATE_WITH_SIZE($1,        $2,      $3,   $4  )
dnl UNARY_OP_PREDICATE_WITH_SIZE(rule_name, op_name, insn, size)
define(`UNARY_OP_PREDICATE_WITH_SIZE', `
instruct $1_masked(vReg dst_src, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src ($2 dst_src pg));
  format %{ "$1_masked $dst_src, $pg, $dst_src" %}
  ins_encode %{
    __ $3($dst_src$$FloatRegister, __ $4, $pg$$PRegister, $dst_src$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// ------------------------------ Vector abs -----------------------------------

// vector abs
UNARY_OP(vabsB, AbsVB, absr, sve_abs,  B)
UNARY_OP(vabsS, AbsVS, absr, sve_abs,  H)
UNARY_OP(vabsI, AbsVI, absr, sve_abs,  S)
UNARY_OP(vabsL, AbsVL, absr, sve_abs,  D)
UNARY_OP(vabsF, AbsVF, fabs, sve_fabs, S)
UNARY_OP(vabsD, AbsVD, fabs, sve_fabs, D)

// vector abs - predicated
UNARY_OP_PREDICATE_WITH_SIZE(vabsB, AbsVB, sve_abs,  B)
UNARY_OP_PREDICATE_WITH_SIZE(vabsS, AbsVS, sve_abs,  H)
UNARY_OP_PREDICATE_WITH_SIZE(vabsI, AbsVI, sve_abs,  S)
UNARY_OP_PREDICATE_WITH_SIZE(vabsL, AbsVL, sve_abs,  D)
UNARY_OP_PREDICATE_WITH_SIZE(vabsF, AbsVF, sve_fabs, S)
UNARY_OP_PREDICATE_WITH_SIZE(vabsD, AbsVD, sve_fabs, D)

// ------------------------------ Vector fabd ----------------------------------

// vector fabs diff

instruct vfabd_neon(vReg dst, vReg src1, vReg src2) %{
  predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)));
  match(Set dst (AbsVF (SubVF src1 src2)));
  match(Set dst (AbsVD (SubVD src1 src2)));
  format %{ "vfabd_neon $dst, $src1, $src2" %}
  ins_encode %{
    __ fabd($dst$$FloatRegister, get_arrangement(this),
            $src1$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vfabd_sve(vReg dst_src1, vReg src2) %{
  predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)));
  match(Set dst_src1 (AbsVF (SubVF dst_src1 src2)));
  match(Set dst_src1 (AbsVD (SubVD dst_src1 src2)));
  format %{ "vfabd_sve $dst_src1, $dst_src1, $src2" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_fabd($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                ptrue, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// vector fabs diff - predicated

instruct vfabd_masked(vReg dst_src1, vReg src2, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 (AbsVF (SubVF (Binary dst_src1 src2) pg) pg));
  match(Set dst_src1 (AbsVD (SubVD (Binary dst_src1 src2) pg) pg));
  format %{ "vfabd_masked $dst_src1, $pg, $dst_src1, $src2" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_fabd($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                $pg$$PRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector neg -----------------------------------

// vector neg

instruct vnegI(vReg dst, vReg src) %{
  match(Set dst (NegVI src));
  format %{ "vnegI $dst, $src" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ negr($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      BasicType bt = Matcher::vector_element_basic_type(this);
      __ sve_neg($dst$$FloatRegister, __ elemType_to_regVariant(bt),
                 ptrue, $src$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}
UNARY_OP(vnegL, NegVL, negr, sve_neg,  D)
UNARY_OP(vnegF, NegVF, fneg, sve_fneg, S)
UNARY_OP(vnegD, NegVD, fneg, sve_fneg, D)

// vector neg - predicated
UNARY_OP_PREDICATE(vnegI, NegVI, sve_neg)
UNARY_OP_PREDICATE_WITH_SIZE(vnegL, NegVL, sve_neg,  D)
UNARY_OP_PREDICATE_WITH_SIZE(vnegF, NegVF, sve_fneg, S)
UNARY_OP_PREDICATE_WITH_SIZE(vnegD, NegVD, sve_fneg, D)

// ------------------------------ Vector sqrt ----------------------------------

// vector sqrt
UNARY_OP(vsqrtF, SqrtVF, fsqrt, sve_fsqrt, S)
UNARY_OP(vsqrtD, SqrtVD, fsqrt, sve_fsqrt, D)

// vector sqrt - predicated
UNARY_OP_PREDICATE_WITH_SIZE(vsqrtF, SqrtVF, sve_fsqrt, S)
UNARY_OP_PREDICATE_WITH_SIZE(vsqrtD, SqrtVD, sve_fsqrt, D)

dnl
dnl VMINMAX_L_NEON($1,   $2     )
dnl VMINMAX_L_NEON(type, op_name)
define(`VMINMAX_L_NEON', `
instruct v$1L_neon(vReg dst, vReg src1, vReg src2) %{
  predicate(UseSVE == 0 && Matcher::vector_element_basic_type(n) == T_LONG);
  match(Set dst ($2 src1 src2));
  effect(TEMP_DEF dst);
  format %{ "v$1L_neon $dst, $src1, $src2\t# 2L" %}
  ins_encode %{
    __ cmgt($dst$$FloatRegister, __ T2D, $src1$$FloatRegister, $src2$$FloatRegister);
    __ bsl($dst$$FloatRegister, __ T16B, ifelse(min, $1, $src2, $src1)$$FloatRegister, ifelse(min, $1, $src1, $src2)$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl VMINMAX_L_SVE($1,   $2,      $3  )
dnl VMINMAX_L_SVE(type, op_name, insn)
define(`VMINMAX_L_SVE', `
instruct v$1L_sve(vReg dst_src1, vReg src2) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_LONG);
  match(Set dst_src1 ($2 dst_src1 src2));
  format %{ "v$1L_sve $dst_src1, $dst_src1, $src2" %}
  ins_encode %{
    __ $3($dst_src1$$FloatRegister, __ D, ptrue, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl VMINMAX_NEON($1,   $2,      $3,      $4           )
dnl VMINMAX_NEON(type, op_name, insn_fp, insn_integral)
define(`VMINMAX_NEON', `
instruct v$1_neon(vReg dst, vReg src1, vReg src2) %{
  predicate(Matcher::vector_element_basic_type(n) != T_LONG &&
            VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)));
  match(Set dst ($2 src1 src2));
  format %{ "v$1_neon $dst, $src1, $src2\t# B/S/I/F/D" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    if (is_floating_point_type(bt)) {
      __ $3($dst$$FloatRegister, get_arrangement(this),
              $src1$$FloatRegister, $src2$$FloatRegister);
    } else {
      assert(is_integral_type(bt) && bt != T_LONG, "unsupported type");
      __ $4($dst$$FloatRegister, get_arrangement(this),
              $src1$$FloatRegister, $src2$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl VMINMAX_SVE($1,   $2,      $3,      $4           )
dnl VMINMAX_SVE(type, op_name, insn_fp, insn_integral)
define(`VMINMAX_SVE', `
instruct v$1_sve(vReg dst_src1, vReg src2) %{
  predicate(Matcher::vector_element_basic_type(n) != T_LONG &&
            !VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)));
  match(Set dst_src1 ($2 dst_src1 src2));
  format %{ "v$1_sve $dst_src1, $dst_src1, $src2\t# B/S/I/F/D" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this);
    if (is_floating_point_type(bt)) {
      __ $3($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                  ptrue, $src2$$FloatRegister);
    } else {
      assert(is_integral_type(bt) && bt != T_LONG, "unsupported type");
      __ $4($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                  ptrue, $src2$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl VMINMAX_PREDICATE($1,   $2,      $3,      $4           )
dnl VMINMAX_PREDICATE(type, op_name, insn_fp, insn_integral)
define(`VMINMAX_PREDICATE', `
instruct v$1_masked(vReg dst_src1, vReg src2, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 ($2 (Binary dst_src1 src2) pg));
  format %{ "v$1_masked $dst_src1, $pg, $dst_src1, $src2" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    if (is_floating_point_type(bt)) {
      __ $3($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                  $pg$$PRegister, $src2$$FloatRegister);
    } else {
      assert(is_integral_type(bt), "unsupported type");
      __ $4($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                  $pg$$PRegister, $src2$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// ------------------------------ Vector min -----------------------------------

// vector min - LONG
VMINMAX_L_NEON(min, MinV)
VMINMAX_L_SVE(min, MinV, sve_smin)

// vector min - B/S/I/F/D
VMINMAX_NEON(min, MinV, fmin, minv)
VMINMAX_SVE(min, MinV, sve_fmin, sve_smin)

// vector min - predicated
VMINMAX_PREDICATE(min, MinV, sve_fmin, sve_smin)

// ------------------------------ Vector max -----------------------------------

// vector max - LONG
VMINMAX_L_NEON(max, MaxV)
VMINMAX_L_SVE(max, MaxV, sve_smax)

// vector max - B/S/I/F/D
VMINMAX_NEON(max, MaxV, fmax, maxv)
VMINMAX_SVE(max, MaxV, sve_fmax, sve_smax)

// vector max - predicated
VMINMAX_PREDICATE(max, MaxV, sve_fmax, sve_smax)

// ------------------------------ MLA RELATED ----------------------------------

// vector mla
// dst_src1 = dst_src1 + src2 * src3

instruct vmla(vReg dst_src1, vReg src2, vReg src3) %{
  match(Set dst_src1 (AddVB dst_src1 (MulVB src2 src3)));
  match(Set dst_src1 (AddVS dst_src1 (MulVS src2 src3)));
  match(Set dst_src1 (AddVI dst_src1 (MulVI src2 src3)));
  format %{ "vmla $dst_src1, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ mlav($dst_src1$$FloatRegister, get_arrangement(this),
              $src2$$FloatRegister, $src3$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_mla($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                 ptrue, $src2$$FloatRegister, $src3$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}

instruct vmlaL(vReg dst_src1, vReg src2, vReg src3) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 (AddVL dst_src1 (MulVL src2 src3)));
  format %{ "vmlaL $dst_src1, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_mla($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
               ptrue, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vmla_masked(vReg dst_src1, vReg src2, vReg src3, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 (AddVB (Binary dst_src1 (MulVB src2 src3)) pg));
  match(Set dst_src1 (AddVS (Binary dst_src1 (MulVS src2 src3)) pg));
  match(Set dst_src1 (AddVI (Binary dst_src1 (MulVI src2 src3)) pg));
  match(Set dst_src1 (AddVL (Binary dst_src1 (MulVL src2 src3)) pg));
  format %{ "vmla_masked $dst_src1, $pg, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_mla($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
               $pg$$PRegister, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// vector fmla
// dst_src1 = dst_src1 + src2 * src3

instruct vfmla(vReg dst_src1, vReg src2, vReg src3) %{
  predicate(UseFMA);
  match(Set dst_src1 (FmaVF dst_src1 (Binary src2 src3)));
  match(Set dst_src1 (FmaVD dst_src1 (Binary src2 src3)));
  format %{ "vfmla $dst_src1, $src2, $src3" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ fmla($dst_src1$$FloatRegister, get_arrangement(this),
              $src2$$FloatRegister, $src3$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      BasicType bt = Matcher::vector_element_basic_type(this);
      __ sve_fmla($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                  ptrue, $src2$$FloatRegister, $src3$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}

// vector fmad - predicated
// dst_src1 = dst_src1 * src2 + src3

instruct vfmad_masked(vReg dst_src1, vReg src2, vReg src3, pRegGov pg) %{
  predicate(UseFMA && UseSVE > 0);
  match(Set dst_src1 (FmaVF (Binary dst_src1 src2) (Binary src3 pg)));
  match(Set dst_src1 (FmaVD (Binary dst_src1 src2) (Binary src3 pg)));
  format %{ "vfmad_masked $dst_src1, $pg, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_fmad($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                $pg$$PRegister, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// vector mls
// dst_src1 = dst_src1 - src2 * src3

instruct vmls(vReg dst_src1, vReg src2, vReg src3) %{
  match(Set dst_src1 (SubVB dst_src1 (MulVB src2 src3)));
  match(Set dst_src1 (SubVS dst_src1 (MulVS src2 src3)));
  match(Set dst_src1 (SubVI dst_src1 (MulVI src2 src3)));
  format %{ "vmls $dst_src1, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ mlsv($dst_src1$$FloatRegister, get_arrangement(this),
              $src2$$FloatRegister, $src3$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_mls($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                 ptrue, $src2$$FloatRegister, $src3$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}

instruct vmlsL(vReg dst_src1, vReg src2, vReg src3) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 (SubVL dst_src1 (MulVL src2 src3)));
  format %{ "vmlsL $dst_src1, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_mls($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                 ptrue, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vmls_masked(vReg dst_src1, vReg src2, vReg src3, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 (SubVB (Binary dst_src1 (MulVB src2 src3)) pg));
  match(Set dst_src1 (SubVS (Binary dst_src1 (MulVS src2 src3)) pg));
  match(Set dst_src1 (SubVI (Binary dst_src1 (MulVI src2 src3)) pg));
  match(Set dst_src1 (SubVL (Binary dst_src1 (MulVL src2 src3)) pg));
  format %{ "vmls_masked $dst_src1, $pg, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_mls($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
               $pg$$PRegister, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// vector fmls

// dst_src1 = dst_src1 + -src2 * src3
instruct vfmls1(vReg dst_src1, vReg src2, vReg src3) %{
  predicate(UseFMA);
  match(Set dst_src1 (FmaVF dst_src1 (Binary (NegVF src2) src3)));
  match(Set dst_src1 (FmaVD dst_src1 (Binary (NegVD src2) src3)));
  format %{ "vfmls1 $dst_src1, $src2, $src3" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ fmls($dst_src1$$FloatRegister, get_arrangement(this),
              $src2$$FloatRegister, $src3$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      BasicType bt = Matcher::vector_element_basic_type(this);
      __ sve_fmls($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                  ptrue, $src2$$FloatRegister, $src3$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}

// dst_src1 = dst_src1 + src2 * -src3
instruct vfmls2(vReg dst_src1, vReg src2, vReg src3) %{
  predicate(UseFMA);
  match(Set dst_src1 (FmaVF dst_src1 (Binary src2 (NegVF src3))));
  match(Set dst_src1 (FmaVD dst_src1 (Binary src2 (NegVD src3))));
  format %{ "vfmls2 $dst_src1, $src2, $src3" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ fmls($dst_src1$$FloatRegister, get_arrangement(this),
              $src2$$FloatRegister, $src3$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      BasicType bt = Matcher::vector_element_basic_type(this);
      __ sve_fmls($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                  ptrue, $src2$$FloatRegister, $src3$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}

// vector fmsb - predicated

// dst_src1 = dst_src1 * -src2 + src3
instruct vfmsb_masked(vReg dst_src1, vReg src2, vReg src3, pRegGov pg) %{
  predicate(UseFMA && UseSVE > 0);
  match(Set dst_src1 (FmaVF (Binary dst_src1 (NegVF src2)) (Binary src3 pg)));
  match(Set dst_src1 (FmaVD (Binary dst_src1 (NegVD src2)) (Binary src3 pg)));
  format %{ "vfmsb_masked $dst_src1, $pg, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_fmsb($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                $pg$$PRegister, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// vector fnmla (sve)

// dst_src1 = -dst_src1 + -src2 * src3
instruct vfnmla1(vReg dst_src1, vReg src2, vReg src3) %{
  predicate(UseFMA && UseSVE > 0);
  match(Set dst_src1 (FmaVF (NegVF dst_src1) (Binary (NegVF src2) src3)));
  match(Set dst_src1 (FmaVD (NegVD dst_src1) (Binary (NegVD src2) src3)));
  format %{ "vfnmla1 $dst_src1, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_fnmla($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                 ptrue, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// dst_src1 = -dst_src1 + src2 * -src3
instruct vfnmla2(vReg dst_src1, vReg src2, vReg src3) %{
  predicate(UseFMA && UseSVE > 0);
  match(Set dst_src1 (FmaVF (NegVF dst_src1) (Binary src2 (NegVF src3))));
  match(Set dst_src1 (FmaVD (NegVD dst_src1) (Binary src2 (NegVD src3))));
  format %{ "vfnmla2 $dst_src1, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_fnmla($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                 ptrue, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// vector fnmad - predicated

// dst_src1 = -src3 + dst_src1 * -src2
instruct vfnmad_masked(vReg dst_src1, vReg src2, vReg src3, pRegGov pg) %{
  predicate(UseFMA && UseSVE > 0);
  match(Set dst_src1 (FmaVF (Binary dst_src1 (NegVF src2)) (Binary (NegVF src3) pg)));
  match(Set dst_src1 (FmaVD (Binary dst_src1 (NegVD src2)) (Binary (NegVD src3) pg)));
  format %{ "vfnmad_masked $dst_src1, $pg, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_fnmad($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                 $pg$$PRegister, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// vector fnmls (sve)

// dst_src1 = -dst_src1 + src2 * src3
instruct vfnmls(vReg dst_src1, vReg src2, vReg src3) %{
  predicate(UseFMA && UseSVE > 0);
  match(Set dst_src1 (FmaVF (NegVF dst_src1) (Binary src2 src3)));
  match(Set dst_src1 (FmaVD (NegVD dst_src1) (Binary src2 src3)));
  format %{ "vfnmls $dst_src1, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_fnmls($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                 ptrue, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// vector fnmsb - predicated

// dst_src1 = -src3 + dst_src1 * src2
instruct vfnmsb_masked(vReg dst_src1, vReg src2, vReg src3, pRegGov pg) %{
  predicate(UseFMA && UseSVE > 0);
  match(Set dst_src1 (FmaVF (Binary dst_src1 src2) (Binary (NegVF src3) pg)));
  match(Set dst_src1 (FmaVD (Binary dst_src1 src2) (Binary (NegVD src3) pg)));
  format %{ "vfnmsb_masked $dst_src1, $pg, $src2, $src3" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_fnmsb($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
                 $pg$$PRegister, $src2$$FloatRegister, $src3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// MulAddVS2VI
// Vector Multiply-Add Shorts into Integer

instruct vmuladdS2I(vReg dst, vReg src1, vReg src2, vReg tmp) %{
  predicate(Matcher::vector_length_in_bytes(n) == 16 &&
            Matcher::vector_element_basic_type(n->in(1)) == T_SHORT);
  match(Set dst (MulAddVS2VI src1 src2));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "vmuladdS2I $dst, $src1, $src2\t# KILL $tmp" %}
  ins_encode %{
    __ smullv($tmp$$FloatRegister, __ T4H, $src1$$FloatRegister, $src2$$FloatRegister);
    __ smullv($dst$$FloatRegister, __ T8H, $src1$$FloatRegister, $src2$$FloatRegister);
    __ addpv($dst$$FloatRegister, __ T4S, $tmp$$FloatRegister, $dst$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector shift ---------------------------------

// Vector right shift in AArch64 ASIMD
//
// Right shifts with vector shift count on AArch64 ASIMD are implemented
// as left shift by negative shift count.
// There are two cases for vector shift count.
//
// Case 1: The vector shift count is from replication.
//        |            |
//    LoadVector  RShiftCntV
//        |       /
//     RShiftVI
//
// Case 2: The vector shift count is from loading.
// This case isn't supported by middle-end now. But it's supported by
// panama/vectorIntrinsics(JEP 338: Vector API).
//        |            |
//    LoadVector  LoadVector
//        |       /
//     RShiftVI
//
// The negate is conducted in RShiftCntV rule for case 1, whereas it's done in
// RShiftV* rules for case 2. Because there exists an optimization opportunity
// for case 1, that is, multiple neg instructions in inner loop can be hoisted
// to outer loop and merged into one neg instruction.
//
// Note that ShiftVNode::is_var_shift() indicates whether the vector shift
// count is a variable vector(case 2) or not(a vector generated by RShiftCntV,
// i.e. case 1).

// vector shift count

instruct vshiftcntL(vReg dst, iRegIorL2I cnt) %{
  match(Set dst (LShiftCntV cnt));
  format %{ "vshiftcntL $dst, $cnt" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ dup($dst$$FloatRegister, get_arrangement(this), $cnt$$Register);
    } else {
      assert(UseSVE > 0, "must be sve");
      BasicType bt = Matcher::vector_element_basic_type(this);
      __ sve_dup($dst$$FloatRegister, __ elemType_to_regVariant(bt), $cnt$$Register);
    }
  %}
  ins_pipe(pipe_slow);
%}

instruct vshiftcntR(vReg dst, iRegIorL2I cnt) %{
  match(Set dst (RShiftCntV cnt));
  format %{ "vshiftcntR $dst, $cnt" %}
  ins_encode %{
    if (UseSVE == 0) {
      uint length_in_bytes = Matcher::vector_length_in_bytes(this);
      assert(length_in_bytes <= 16, "must be");
      __ negw(rscratch1, $cnt$$Register);
      __ dup($dst$$FloatRegister, get_arrangement(this), rscratch1);
    } else {
      BasicType bt = Matcher::vector_element_basic_type(this);
      __ sve_dup($dst$$FloatRegister, __ elemType_to_regVariant(bt), $cnt$$Register);
    }
  %}
  ins_pipe(pipe_slow);
%}

// vector shift left

instruct vlsl_neon(vReg dst, vReg src, vReg shift) %{
  predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)));
  match(Set dst (LShiftVB src shift));
  match(Set dst (LShiftVS src shift));
  match(Set dst (LShiftVI src shift));
  match(Set dst (LShiftVL src shift));
  format %{ "vlsl_neon $dst, $src, $shift" %}
  ins_encode %{
    __ sshl($dst$$FloatRegister, get_arrangement(this),
            $src$$FloatRegister, $shift$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vlsl_sve(vReg dst_src, vReg shift) %{
  predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)));
  match(Set dst_src (LShiftVB dst_src shift));
  match(Set dst_src (LShiftVS dst_src shift));
  match(Set dst_src (LShiftVI dst_src shift));
  match(Set dst_src (LShiftVL dst_src shift));
  format %{ "vlsl_sve $dst_src, $dst_src, $shift" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_lsl($dst_src$$FloatRegister, __ elemType_to_regVariant(bt),
               ptrue, $shift$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

dnl
dnl VRSHIFT_NEON($1,   $2,      $3  )
dnl VRSHIFT_NEON(type, op_name, insn)
define(`VRSHIFT_NEON', `
instruct v$1_neon(vReg dst, vReg src, vReg shift) %{
  predicate(UseSVE == 0 && !n->as_ShiftV()->is_var_shift());
  match(Set dst ($2VB src shift));
  match(Set dst ($2VS src shift));
  match(Set dst ($2VI src shift));
  match(Set dst ($2VL src shift));
  format %{ "v$1_neon $dst, $src, $shift\t# not variable shift" %}
  ins_encode %{
    __ $3($dst$$FloatRegister, get_arrangement(this),
            $src$$FloatRegister, $shift$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl VRSHIFT_NEON_VAR($1,   $2,      $3  )
dnl VRSHIFT_NEON_VAR(type, op_name, insn)
define(`VRSHIFT_NEON_VAR', `
instruct v$1_neon_var(vReg dst, vReg src, vReg shift) %{
  predicate(UseSVE == 0 && n->as_ShiftV()->is_var_shift());
  match(Set dst ($2VB src shift));
  match(Set dst ($2VS src shift));
  match(Set dst ($2VI src shift));
  match(Set dst ($2VL src shift));
  effect(TEMP_DEF dst);
  format %{ "v$1_neon_var $dst, $src, $shift\t# variable shift" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    __ negr($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
            $shift$$FloatRegister);
    __ $3($dst$$FloatRegister, get_arrangement(this),
            $src$$FloatRegister, $dst$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl VRSHIFT_SVE($1,   $2,      $3  )
dnl VRSHIFT_SVE(type, op_name, insn)
define(`VRSHIFT_SVE', `
instruct v$1_sve(vReg dst_src, vReg shift) %{
  predicate(UseSVE > 0);
  match(Set dst_src ($2VB dst_src shift));
  match(Set dst_src ($2VS dst_src shift));
  match(Set dst_src ($2VI dst_src shift));
  match(Set dst_src ($2VL dst_src shift));
  format %{ "v$1_sve $dst_src, $dst_src, $shift" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ $3($dst_src$$FloatRegister, __ elemType_to_regVariant(bt),
               ptrue, $shift$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// vector shift right (arithmetic)
VRSHIFT_NEON(asr, RShift, sshl)
VRSHIFT_NEON_VAR(asr, RShift, sshl)
VRSHIFT_SVE(asr, RShift, sve_asr)

// vector shift right (logical)
VRSHIFT_NEON(lsr, URShift, ushl)
VRSHIFT_NEON_VAR(lsr, URShift, ushl)
VRSHIFT_SVE(lsr, URShift, sve_lsr)

// vector shift with imm

instruct vlsl_imm(vReg dst, vReg src, immI shift) %{
  predicate(assert_not_var_shift(n));
  match(Set dst (LShiftVB src (LShiftCntV shift)));
  match(Set dst (LShiftVS src (LShiftCntV shift)));
  match(Set dst (LShiftVI src (LShiftCntV shift)));
  match(Set dst (LShiftVL src (LShiftCntV shift)));
  format %{ "vlsl_imm $dst, $src, $shift" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    int con = (int)$shift$$constant;
    if (is_subword_type(bt)) {
      // Optimize for B/S
      int esize_in_bits = type2aelembytes(bt) * BitsPerByte;
      if (con >= esize_in_bits) {
        if (VM_Version::use_neon_for_vector(length_in_bytes)) {
          __ eor($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
                 $src$$FloatRegister, $src$$FloatRegister);
        } else {
          assert(UseSVE > 0, "must be sve");
          __ sve_eor($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister);
        }
        return;
      }
    }
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ shl($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister, con);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_lsl($dst$$FloatRegister, __ elemType_to_regVariant(bt), $src$$FloatRegister, con);
    }
  %}
  ins_pipe(pipe_slow);
%}

instruct vasr_imm(vReg dst, vReg src, immI_positive shift) %{
  predicate(assert_not_var_shift(n));
  match(Set dst (RShiftVB src (RShiftCntV shift)));
  match(Set dst (RShiftVS src (RShiftCntV shift)));
  match(Set dst (RShiftVI src (RShiftCntV shift)));
  match(Set dst (RShiftVL src (RShiftCntV shift)));
  format %{ "vasr_imm $dst, $src, $shift" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    int con = (int)$shift$$constant;
    if (is_subword_type(bt)) {
      // Refine con for B/S
      int esize_in_bits = type2aelembytes(bt) * BitsPerByte;
      if (con >= esize_in_bits) con = esize_in_bits - 1;
    }
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ sshr($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister, con);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_asr($dst$$FloatRegister, __ elemType_to_regVariant(bt), $src$$FloatRegister, con);
    }
  %}
  ins_pipe(pipe_slow);
%}

instruct vlsr_imm(vReg dst, vReg src, immI_positive shift) %{
  predicate(assert_not_var_shift(n));
  match(Set dst (URShiftVB src (RShiftCntV shift)));
  match(Set dst (URShiftVS src (RShiftCntV shift)));
  match(Set dst (URShiftVI src (RShiftCntV shift)));
  match(Set dst (URShiftVL src (RShiftCntV shift)));
  format %{ "vlsr_imm $dst, $src, $shift" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    int con = (int)$shift$$constant;
    if (is_subword_type(bt)) {
      // Optimize for B/S
      int esize_in_bits = type2aelembytes(bt) * BitsPerByte;
      if (con >= esize_in_bits) {
        if (VM_Version::use_neon_for_vector(length_in_bytes)) {
          __ eor($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
                 $src$$FloatRegister, $src$$FloatRegister);
        } else {
          assert(UseSVE > 0, "must be sve");
          __ sve_eor($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister);
        }
        return;
      }
    }
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ ushr($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister, con);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_lsr($dst$$FloatRegister, __ elemType_to_regVariant(bt), $src$$FloatRegister, con);
    }
  %}
  ins_pipe(pipe_slow);
%}

// shift right add with imm (vector length <= 128 bits only)

instruct vasra_imm(vReg dst, vReg src, immI_positive shift) %{
  predicate(Matcher::vector_length_in_bytes(n) <= 16);
  match(Set dst (AddVB dst (RShiftVB src (RShiftCntV shift))));
  match(Set dst (AddVS dst (RShiftVS src (RShiftCntV shift))));
  match(Set dst (AddVI dst (RShiftVI src (RShiftCntV shift))));
  match(Set dst (AddVL dst (RShiftVL src (RShiftCntV shift))));
  format %{ "vasra_imm $dst, $src, $shift" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    int con = (int)$shift$$constant;
    if (is_subword_type(bt)) {
      // Refine con for B/S
      int esize_in_bits = type2aelembytes(bt) * BitsPerByte;
      if (con >= esize_in_bits) con = esize_in_bits - 1;
    }
    __ ssra($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister, con);
  %}
  ins_pipe(pipe_slow);
%}

instruct vlsra_imm(vReg dst, vReg src, immI_positive shift) %{
  predicate(Matcher::vector_length_in_bytes(n) <= 16);
  match(Set dst (AddVB dst (URShiftVB src (RShiftCntV shift))));
  match(Set dst (AddVS dst (URShiftVS src (RShiftCntV shift))));
  match(Set dst (AddVI dst (URShiftVI src (RShiftCntV shift))));
  match(Set dst (AddVL dst (URShiftVL src (RShiftCntV shift))));
  format %{ "vlsra_imm $dst, $src, $shift" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    int con = (int)$shift$$constant;
    if (is_subword_type(bt)) { // for B/H
      int esize_in_bits = type2aelembytes(bt) * BitsPerByte;
      if (con < esize_in_bits) {
        __ usra($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister, con);
      }
    } else { // for S/D
      assert(type2aelembytes(bt) == 4 || type2aelembytes(bt) == 8, "unsupported type");
      __ usra($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister, con);
    }
  %}
  ins_pipe(pipe_slow);
%}

dnl
dnl VSHIFT_PREDICATE($1,   $2,      $3  )
dnl VSHIFT_PREDICATE(type, op_name, insn)
define(`VSHIFT_PREDICATE', `
instruct v$1_masked(vReg dst_src1, vReg src2, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 ($2VB (Binary dst_src1 src2) pg));
  match(Set dst_src1 ($2VS (Binary dst_src1 src2) pg));
  match(Set dst_src1 ($2VI (Binary dst_src1 src2) pg));
  match(Set dst_src1 ($2VL (Binary dst_src1 src2) pg));
  format %{ "v$1_masked $dst_src1, $pg, $dst_src1, $src2" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ $3($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt),
               $pg$$PRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl VSHIFT_IMM_PREDICATE($1,   $2,       $3,       $4,       $5  )
dnl VSHIFT_IMM_PREDICATE(type, arg_type, op_name1, op_name2, insn)
define(`VSHIFT_IMM_PREDICATE', `
instruct v$1_imm_masked(vReg dst_src, $2 shift, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src ($3VB (Binary dst_src ($4 shift)) pg));
  match(Set dst_src ($3VS (Binary dst_src ($4 shift)) pg));
  match(Set dst_src ($3VI (Binary dst_src ($4 shift)) pg));
  match(Set dst_src ($3VL (Binary dst_src ($4 shift)) pg));
  format %{ "v$1_imm_masked $dst_src, $pg, $dst_src, $shift" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    int esize_in_bits = type2aelembytes(bt) * BitsPerByte;
    int con = (int)$shift$$constant;
    assert(con ifelse($1, lsl, >=, >) 0 && con < esize_in_bits, "invalid shift immediate");
    __ $5($dst_src$$FloatRegister, __ elemType_to_regVariant(bt),
               $pg$$PRegister, con);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// vector shift - predicated
VSHIFT_PREDICATE(lsl, LShift,  sve_lsl)
VSHIFT_PREDICATE(asr, RShift,  sve_asr)
VSHIFT_PREDICATE(lsr, URShift, sve_lsr)

// vector shift with imm - predicated
VSHIFT_IMM_PREDICATE(lsl, immI,          LShift,  LShiftCntV, sve_lsl)
VSHIFT_IMM_PREDICATE(asr, immI_positive, RShift,  RShiftCntV, sve_asr)
VSHIFT_IMM_PREDICATE(lsr, immI_positive, URShift, RShiftCntV, sve_lsr)

// ------------------------------ Vector reduction add -------------------------

dnl
dnl REDUCE_ADD_INT_NEON_SVE_PAIRWISE($1,   $2      )
dnl REDUCE_ADD_INT_NEON_SVE_PAIRWISE(type, arg_type)
define(`REDUCE_ADD_INT_NEON_SVE_PAIRWISE', `
instruct reduce_add$1_neon(iReg$1NoSp dst, $2 isrc, vReg vsrc, vReg tmp) %{
  predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(2))));
  match(Set dst (AddReductionV$1 isrc vsrc));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "reduce_add$1_neon $dst, $isrc, $vsrc\t# KILL $tmp" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    __ neon_reduce_add_integral($dst$$Register, bt,
                                $isrc$$Register, $vsrc$$FloatRegister,
                                length_in_bytes, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct reduce_add$1_sve(iReg$1NoSp dst, $2 isrc, vReg vsrc, vRegD tmp) %{
  predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(2))));
  match(Set dst (AddReductionV$1 isrc vsrc));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "reduce_add$1_sve $dst, $isrc, $vsrc\t# KILL $tmp" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
                           $isrc$$Register, $vsrc$$FloatRegister,
                           ptrue, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// reduction addI
REDUCE_ADD_INT_NEON_SVE_PAIRWISE(I, iRegIorL2I)

// reduction addL
REDUCE_ADD_INT_NEON_SVE_PAIRWISE(L, iRegL)

// reduction addF

instruct reduce_addF_neon(vRegF dst, vRegF fsrc, vReg vsrc, vReg tmp) %{
  predicate(UseSVE == 0);
  match(Set dst (AddReductionVF fsrc vsrc));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "reduce_addF_neon $dst, $fsrc, $vsrc\t# KILL $tmp" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    __ fadds($dst$$FloatRegister, $fsrc$$FloatRegister, $vsrc$$FloatRegister);
    __ ins($tmp$$FloatRegister, __ S, $vsrc$$FloatRegister, 0, 1);
    __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
    if (length_in_bytes == 16) {
      __ ins($tmp$$FloatRegister, __ S, $vsrc$$FloatRegister, 0, 2);
      __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
      __ ins($tmp$$FloatRegister, __ S, $vsrc$$FloatRegister, 0, 3);
      __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}
dnl
dnl REDUCE_ADD_FP_SVE($1,   $2  )
dnl REDUCE_ADD_FP_SVE(type, size)
define(`REDUCE_ADD_FP_SVE', `
instruct reduce_add$1_sve(vReg$1 dst_src1, vReg src2) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 (AddReductionV$1 dst_src1 src2));
  format %{ "reduce_add$1_sve $dst_src1, $dst_src1, $src2" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src2);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_fadda($dst_src1$$FloatRegister, __ $2, ptrue, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
REDUCE_ADD_FP_SVE(F, S)

// reduction addD

instruct reduce_addD_neon(vRegD dst, vRegD dsrc, vReg vsrc, vReg tmp) %{
  predicate(UseSVE == 0);
  match(Set dst (AddReductionVD dsrc vsrc));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "reduce_addD_neon $dst, $dsrc, $vsrc\t# 2D. KILL $tmp" %}
  ins_encode %{
    __ faddd($dst$$FloatRegister, $dsrc$$FloatRegister, $vsrc$$FloatRegister);
    __ ins($tmp$$FloatRegister, __ D, $vsrc$$FloatRegister, 0, 1);
    __ faddd($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}
REDUCE_ADD_FP_SVE(D, D)

// reduction add - predicated
dnl
dnl REDUCE_ADD_INT_PREDICATE($1,        $2     )
dnl REDUCE_ADD_INT_PREDICATE(insn_name, op_name)
define(`REDUCE_ADD_INT_PREDICATE', `
instruct reduce_add$1_masked(iReg$1NoSp dst, $2 isrc, vReg vsrc, pRegGov pg, vRegD tmp) %{
  predicate(UseSVE > 0);
  match(Set dst (AddReductionV$1 (Binary isrc vsrc) pg));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "reduce_add$1_masked $dst, $isrc, $pg, $vsrc\t# KILL $tmp" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
    __ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
                           $isrc$$Register, $vsrc$$FloatRegister,
                           $pg$$PRegister, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REDUCE_ADD_FP_PREDICATE($1,        $2     )
dnl REDUCE_ADD_FP_PREDICATE(insn_name, op_name)
define(`REDUCE_ADD_FP_PREDICATE', `
instruct reduce_add$1_masked(vReg$1 dst_src1, vReg src2, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src1 (AddReductionV$1 (Binary dst_src1 src2) pg));
  format %{ "reduce_add$1_masked $dst_src1, $pg, $dst_src1, $src2" %}
  ins_encode %{
    __ sve_fadda($dst_src1$$FloatRegister, __ $2,
                 $pg$$PRegister, $src2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
REDUCE_ADD_INT_PREDICATE(I, iRegIorL2I)
REDUCE_ADD_INT_PREDICATE(L, iRegL)
REDUCE_ADD_FP_PREDICATE(F, S)
REDUCE_ADD_FP_PREDICATE(D, D)

// ------------------------------ Vector reduction mul -------------------------

instruct reduce_mulI(iRegINoSp dst, iRegIorL2I isrc, vReg vsrc,
                     vReg tmp1, vReg tmp2) %{
  predicate(Matcher::vector_length_in_bytes(n->in(2)) == 8 ||
            Matcher::vector_length_in_bytes(n->in(2)) == 16);
  match(Set dst (MulReductionVI isrc vsrc));
  effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2);
  format %{ "reduce_mulI $dst, $isrc, $vsrc\t# vector (64/128 bits). KILL $tmp1, $tmp2" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    __ neon_reduce_mul_integral($dst$$Register, bt, $isrc$$Register,
                                $vsrc$$FloatRegister, length_in_bytes,
                                $tmp1$$FloatRegister, $tmp2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct reduce_mulL(iRegLNoSp dst, iRegL isrc, vReg vsrc) %{
  predicate(Matcher::vector_length_in_bytes(n->in(2)) == 16);
  match(Set dst (MulReductionVL isrc vsrc));
  effect(TEMP_DEF dst);
  format %{ "reduce_mulL $dst, $isrc, $vsrc\t# 2L" %}
  ins_encode %{
    __ neon_reduce_mul_integral($dst$$Register, T_LONG, $isrc$$Register,
                                $vsrc$$FloatRegister, 16, fnoreg, fnoreg);
  %}
  ins_pipe(pipe_slow);
%}

instruct reduce_mulF(vRegF dst, vRegF fsrc, vReg vsrc, vReg tmp) %{
  predicate(Matcher::vector_length_in_bytes(n->in(2)) <= 16);
  match(Set dst (MulReductionVF fsrc vsrc));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "reduce_mulF $dst, $fsrc, $vsrc\t# 2F/4F. KILL $tmp" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    __ neon_reduce_mul_fp($dst$$FloatRegister, T_FLOAT, $fsrc$$FloatRegister,
                          $vsrc$$FloatRegister, length_in_bytes, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct reduce_mulD(vRegD dst, vRegD dsrc, vReg vsrc, vReg tmp) %{
  predicate(Matcher::vector_length_in_bytes(n->in(2)) == 16);
  match(Set dst (MulReductionVD dsrc vsrc));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "reduce_mulD $dst, $dsrc, $vsrc\t# 2D. KILL $tmp" %}
  ins_encode %{
    __ neon_reduce_mul_fp($dst$$FloatRegister, T_DOUBLE, $dsrc$$FloatRegister,
                          $vsrc$$FloatRegister, 16, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

dnl
dnl REDUCE_BITWISE_OP_NEON($1,        $2       $3    $4     )
dnl REDUCE_BITWISE_OP_NEON(insn_name, is_long, type, op_name)
define(`REDUCE_BITWISE_OP_NEON', `
instruct reduce_$1$2_neon(iReg$2NoSp dst, $3 isrc, vReg vsrc) %{
  predicate(UseSVE == 0 && Matcher::vector_element_basic_type(n->in(2)) ifelse($2, L, ==, !=) T_LONG);
  match(Set dst ($4 isrc vsrc));
  effect(TEMP_DEF dst);
  format %{ "reduce_$1$2_neon $dst, $isrc, $vsrc" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    __ neon_reduce_logical(this->ideal_Opcode(), $dst$$Register, bt,
                           $isrc$$Register, $vsrc$$FloatRegister, length_in_bytes);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REDUCE_BITWISE_OP_SVE($1,        $2       $3    $4     )
dnl REDUCE_BITWISE_OP_SVE(insn_name, is_long, type, op_name)
define(`REDUCE_BITWISE_OP_SVE', `
instruct reduce_$1$2_sve(iReg$2NoSp dst, $3 isrc, vReg vsrc, vRegD tmp) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n->in(2)) ifelse($2, L, ==, !=) T_LONG);
  match(Set dst ($4 isrc vsrc));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "reduce_$1$2_sve $dst, $isrc, $vsrc\t# KILL $tmp" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
                           $isrc$$Register, $vsrc$$FloatRegister,
                           ptrue, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REDUCE_BITWISE_OP_PREDICATE($1,        $2       $3    $4     )
dnl REDUCE_BITWISE_OP_PREDICATE(insn_name, is_long, type, op_name)
define(`REDUCE_BITWISE_OP_PREDICATE', `
instruct reduce_$1$2_masked(iReg$2NoSp dst, $3 isrc, vReg vsrc, pRegGov pg, vRegD tmp) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n->in(1)->in(2)) ifelse($2, L, ==, !=) T_LONG);
  match(Set dst ($4 (Binary isrc vsrc) pg));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "reduce_$1$2_masked $dst, $isrc, $pg, $vsrc\t# KILL $tmp" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
    __ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
                           $isrc$$Register, $vsrc$$FloatRegister,
                           $pg$$PRegister, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// ------------------------------ Vector reduction and -------------------------

// reduction andI
REDUCE_BITWISE_OP_NEON(and, I, iRegIorL2I, AndReductionV)
REDUCE_BITWISE_OP_SVE(and, I, iRegIorL2I, AndReductionV)

// reduction andL
REDUCE_BITWISE_OP_NEON(and, L, iRegL, AndReductionV)
REDUCE_BITWISE_OP_SVE(and, L, iRegL, AndReductionV)

// reduction and - predicated
REDUCE_BITWISE_OP_PREDICATE(and, I, iRegIorL2I, AndReductionV)
REDUCE_BITWISE_OP_PREDICATE(and, L, iRegL,      AndReductionV)

// ------------------------------ Vector reduction or --------------------------

// reduction orI
REDUCE_BITWISE_OP_NEON(or, I, iRegIorL2I, OrReductionV)
REDUCE_BITWISE_OP_SVE(or, I, iRegIorL2I, OrReductionV)

// reduction orL
REDUCE_BITWISE_OP_NEON(or, L, iRegL, OrReductionV)
REDUCE_BITWISE_OP_SVE(or, L, iRegL, OrReductionV)

// reduction or - predicated
REDUCE_BITWISE_OP_PREDICATE(or, I, iRegIorL2I, OrReductionV)
REDUCE_BITWISE_OP_PREDICATE(or, L, iRegL,      OrReductionV)

// ------------------------------ Vector reduction xor -------------------------

// reduction xorI
REDUCE_BITWISE_OP_NEON(xor, I, iRegIorL2I, XorReductionV)
REDUCE_BITWISE_OP_SVE(xor, I, iRegIorL2I, XorReductionV)

// reduction xorL
REDUCE_BITWISE_OP_NEON(xor, L, iRegL, XorReductionV)
REDUCE_BITWISE_OP_SVE(xor, L, iRegL, XorReductionV)

// reduction xor - predicated
REDUCE_BITWISE_OP_PREDICATE(xor, I, iRegIorL2I, XorReductionV)
REDUCE_BITWISE_OP_PREDICATE(xor, L, iRegL,      XorReductionV)

dnl
dnl REDUCE_MAXMIN_I_NEON($1,   $2     )
dnl REDUCE_MAXMIN_I_NEON(type, op_name)
define(`REDUCE_MAXMIN_I_NEON', `
instruct reduce_$1I_neon(iRegINoSp dst, iRegIorL2I isrc, vReg vsrc,
                          vReg tmp, rFlagsReg cr) %{
  predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(2))) &&
            (Matcher::vector_element_basic_type(n->in(2)) == T_BYTE ||
             Matcher::vector_element_basic_type(n->in(2)) == T_SHORT ||
             Matcher::vector_element_basic_type(n->in(2)) == T_INT));
  match(Set dst ($2 isrc vsrc));
  effect(TEMP_DEF dst, TEMP tmp, KILL cr);
  format %{ "reduce_$1I_neon $dst, $isrc, $vsrc\t# KILL $tmp, cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    __ neon_reduce_minmax_integral(this->ideal_Opcode(), $dst$$Register, bt,
                                   $isrc$$Register, $vsrc$$FloatRegister,
                                   length_in_bytes, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REDUCE_MAXMIN_I_SVE($1,   $2     )
dnl REDUCE_MAXMIN_I_SVE(type, op_name)
define(`REDUCE_MAXMIN_I_SVE', `
instruct reduce_$1I_sve(iRegINoSp dst, iRegIorL2I isrc, vReg vsrc,
                         vRegD tmp, rFlagsReg cr) %{
  predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(2))) &&
            (Matcher::vector_element_basic_type(n->in(2)) == T_BYTE ||
             Matcher::vector_element_basic_type(n->in(2)) == T_SHORT ||
             Matcher::vector_element_basic_type(n->in(2)) == T_INT));
  match(Set dst ($2 isrc vsrc));
  effect(TEMP_DEF dst, TEMP tmp, KILL cr);
  format %{ "reduce_$1I_sve $dst, $isrc, $vsrc\t# KILL $tmp, cr" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
                           $isrc$$Register, $vsrc$$FloatRegister,
                           ptrue, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REDUCE_MAXMIN_L_NEON($1,   $2     )
dnl REDUCE_MAXMIN_L_NEON(type, op_name)
define(`REDUCE_MAXMIN_L_NEON', `
instruct reduce_$1L_neon(iRegLNoSp dst, iRegL isrc, vReg vsrc, rFlagsReg cr) %{
  predicate(UseSVE == 0 && Matcher::vector_element_basic_type(n->in(2)) == T_LONG);
  match(Set dst ($2 isrc vsrc));
  effect(TEMP_DEF dst, KILL cr);
  format %{ "reduce_$1L_neon $dst, $isrc, $vsrc\t# 2L. KILL cr" %}
  ins_encode %{
    __ neon_reduce_minmax_integral(this->ideal_Opcode(), $dst$$Register, T_LONG,
                                   $isrc$$Register, $vsrc$$FloatRegister,
                                   /* vector_length_in_bytes */ 16, fnoreg);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REDUCE_MAXMIN_L_SVE($1,   $2     )
dnl REDUCE_MAXMIN_L_SVE(type, op_name)
define(`REDUCE_MAXMIN_L_SVE', `
instruct reduce_$1L_sve(iRegLNoSp dst, iRegL isrc, vReg vsrc,
                         vRegD tmp, rFlagsReg cr) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n->in(2)) == T_LONG);
  match(Set dst ($2 isrc vsrc));
  effect(TEMP_DEF dst, TEMP tmp, KILL cr);
  format %{ "reduce_$1L_sve $dst, $isrc, $vsrc\t# KILL $tmp, cr" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, T_LONG,
                           $isrc$$Register, $vsrc$$FloatRegister,
                           ptrue, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REDUCE_MAXMIN_F($1,   $2,      $3,    $4,    $5,    $6   )
dnl REDUCE_MAXMIN_F(type, op_name, insn1, insn2, insn3, insn4)
define(`REDUCE_MAXMIN_F', `
instruct reduce_$1F(vRegF dst, vRegF fsrc, vReg vsrc) %{
  predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT);
  match(Set dst ($2 fsrc vsrc));
  effect(TEMP_DEF dst);
  format %{ "reduce_$1F $dst, $fsrc, $vsrc" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      if (length_in_bytes == 8) {
        __ $3($dst$$FloatRegister, $vsrc$$FloatRegister, __ S);
      } else {
        __ $4($dst$$FloatRegister, __ T4S, $vsrc$$FloatRegister);
      }
    } else {
      assert(UseSVE > 0, "must be sve");
      assert(length_in_bytes == MaxVectorSize, "invalid vector length");
      __ $5($dst$$FloatRegister, __ S, ptrue, $vsrc$$FloatRegister);
    }
    __ $6($dst$$FloatRegister, $dst$$FloatRegister, $fsrc$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REDUCE_MAXMIN_D($1,   $2,      $3,    $4,    $5   )
dnl REDUCE_MAXMIN_D(type, op_name, insn1, insn2, insn3)
define(`REDUCE_MAXMIN_D', `
instruct reduce_$1D(vRegD dst, vRegD dsrc, vReg vsrc) %{
  predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE);
  match(Set dst ($2 dsrc vsrc));
  effect(TEMP_DEF dst);
  format %{ "reduce_$1D $dst, $dsrc, $vsrc" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ $3($dst$$FloatRegister, $vsrc$$FloatRegister, __ D);
    } else {
      assert(UseSVE > 0, "must be sve");
      assert(length_in_bytes == MaxVectorSize, "invalid vector length");
      __ $4($dst$$FloatRegister, __ D, ptrue, $vsrc$$FloatRegister);
    }
    __ $5($dst$$FloatRegister, $dst$$FloatRegister, $dsrc$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REDUCE_MAXMIN_INT_PREDICATE($1,   $2,      $3,       $4     )
dnl REDUCE_MAXMIN_INT_PREDICATE(type, is_long, arg_type, op_name)
define(`REDUCE_MAXMIN_INT_PREDICATE', `
instruct reduce_$1$2_masked(iReg$2NoSp dst, $3 isrc, vReg vsrc, pRegGov pg,
                            vRegD tmp, rFlagsReg cr) %{
  ifelse($2, I,
       `predicate(UseSVE > 0 &&
            (Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_BYTE ||
             Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_SHORT ||
             Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_INT));',
       `predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_LONG);')
  match(Set dst ($4 (Binary isrc vsrc) pg));
  effect(TEMP_DEF dst, TEMP tmp, KILL cr);
  format %{ "reduce_$1$2_masked $dst, $isrc, $pg, $vsrc\t# KILL $tmp, cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
    __ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
                           $isrc$$Register, $vsrc$$FloatRegister,
                           $pg$$PRegister, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REDUCE_MAXMIN_FP_PREDICATE($1,   $2,       $3,       $4,      $5,    $6   )
dnl REDUCE_MAXMIN_FP_PREDICATE(type, is_float, arg_name, op_name, insn1, insn2)
define(`REDUCE_MAXMIN_FP_PREDICATE', `
instruct reduce_$1$2_masked(vReg$2 dst, vReg$2 $3, vReg vsrc, pRegGov pg) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n->in(1)->in(2)) == ifelse($2, F, T_FLOAT, T_DOUBLE));
  match(Set dst ($4 (Binary $3 vsrc) pg));
  effect(TEMP_DEF dst);
  format %{ "reduce_$1$2_masked $dst, $$3, $pg, $vsrc" %}
  ins_encode %{
    __ $5($dst$$FloatRegister, __ ifelse($2, F, S, D), $pg$$PRegister, $vsrc$$FloatRegister);
    __ $6($dst$$FloatRegister, $dst$$FloatRegister, $$3$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// ------------------------------ Vector reduction max -------------------------

// reduction maxI
REDUCE_MAXMIN_I_NEON(max, MaxReductionV)
REDUCE_MAXMIN_I_SVE(max, MaxReductionV)

// reduction maxL
REDUCE_MAXMIN_L_NEON(max, MaxReductionV)
REDUCE_MAXMIN_L_SVE(max, MaxReductionV)

// reduction maxF
REDUCE_MAXMIN_F(max, MaxReductionV, fmaxp, fmaxv, sve_fmaxv, fmaxs)

// reduction maxD
REDUCE_MAXMIN_D(max, MaxReductionV, fmaxp, sve_fmaxv, fmaxd)

// reduction max - predicated
REDUCE_MAXMIN_INT_PREDICATE(max, I, iRegIorL2I, MaxReductionV)
REDUCE_MAXMIN_INT_PREDICATE(max, L, iRegL,      MaxReductionV)
REDUCE_MAXMIN_FP_PREDICATE(max, F, fsrc, MaxReductionV, sve_fmaxv, fmaxs)
REDUCE_MAXMIN_FP_PREDICATE(max, D, dsrc, MaxReductionV, sve_fmaxv, fmaxd)

// ------------------------------ Vector reduction min -------------------------

// reduction minI
REDUCE_MAXMIN_I_NEON(min, MinReductionV)
REDUCE_MAXMIN_I_SVE(min, MinReductionV)

// reduction minL
REDUCE_MAXMIN_L_NEON(min, MinReductionV)
REDUCE_MAXMIN_L_SVE(min, MinReductionV)

// reduction minF
REDUCE_MAXMIN_F(min, MinReductionV, fminp, fminv, sve_fminv, fmins)

// reduction minD
REDUCE_MAXMIN_D(min, MinReductionV, fminp, sve_fminv, fmind)

// reduction min - predicated
REDUCE_MAXMIN_INT_PREDICATE(min, I, iRegIorL2I, MinReductionV)
REDUCE_MAXMIN_INT_PREDICATE(min, L, iRegL,      MinReductionV)
REDUCE_MAXMIN_FP_PREDICATE(min, F, fsrc, MinReductionV, sve_fminv, fmins)
REDUCE_MAXMIN_FP_PREDICATE(min, D, dsrc, MinReductionV, sve_fminv, fmind)

// ------------------------------ Vector reinterpret ---------------------------

instruct reinterpret_same_size(vReg dst_src) %{
  predicate(Matcher::vector_length_in_bytes(n) == Matcher::vector_length_in_bytes(n->in(1)));
  match(Set dst_src (VectorReinterpret dst_src));
  ins_cost(0);
  format %{ "reinterpret_same_size $dst_src\t# do nothing" %}
  ins_encode(/* empty encoding */);
  ins_pipe(pipe_class_empty);
%}

instruct reinterpret_resize_le128b(vReg dst, vReg src) %{
  predicate(Matcher::vector_length_in_bytes(n) != Matcher::vector_length_in_bytes(n->in(1)) &&
            Matcher::vector_length_in_bytes(n) <= 16 &&
            Matcher::vector_length_in_bytes(n->in(1)) <= 16);
  match(Set dst (VectorReinterpret src));
  format %{ "reinterpret_resize_le128b $dst, $src\t# vector <= 128 bits." %}
  ins_encode %{
    uint length_in_bytes_src = Matcher::vector_length_in_bytes(this, $src);
    uint length_in_bytes_dst = Matcher::vector_length_in_bytes(this);
    // The higher bits in "dst" register must be cleared to zero.
    if ((length_in_bytes_src == 4 && length_in_bytes_dst == 8) ||
        (length_in_bytes_src == 8 && length_in_bytes_dst == 4)) {
      // Reinterpret between 32 bits and 64 bits
      __ dup($dst$$FloatRegister, __ S, $src$$FloatRegister);
    } else if ((length_in_bytes_src == 4 && length_in_bytes_dst == 16) ||
               (length_in_bytes_src == 16 && length_in_bytes_dst == 4)) {
      // Reinterpret between 32 bits and 128 bits
      __ dup($dst$$FloatRegister, __ S, $src$$FloatRegister);
    } else if ((length_in_bytes_src == 8 && length_in_bytes_dst == 16) ||
               (length_in_bytes_src == 16 && length_in_bytes_dst == 8)) {
      // Reinterpret between 64 bits and 128 bits
      __ orr($dst$$FloatRegister, __ T8B, $src$$FloatRegister, $src$$FloatRegister);
    } else {
      assert(false, "invalid vector length");
      ShouldNotReachHere();
    }
  %}
  ins_pipe(pipe_slow);
%}

instruct reinterpret_resize_gt128b(vReg dst, vReg src, pReg ptmp, rFlagsReg cr) %{
  predicate(Matcher::vector_length_in_bytes(n) != Matcher::vector_length_in_bytes(n->in(1)) &&
            (Matcher::vector_length_in_bytes(n) > 16 ||
             Matcher::vector_length_in_bytes(n->in(1)) > 16));
  match(Set dst (VectorReinterpret src));
  effect(TEMP_DEF dst, TEMP ptmp, KILL cr);
  format %{ "reinterpret_resize_gt128b $dst, $src\t# vector > 128 bits. KILL $ptmp, cr" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    uint length_in_bytes_src = Matcher::vector_length_in_bytes(this, $src);
    uint length_in_bytes_dst = Matcher::vector_length_in_bytes(this);
    uint length_in_bytes_resize = length_in_bytes_src < length_in_bytes_dst ?
                                  length_in_bytes_src : length_in_bytes_dst;
    assert(length_in_bytes_src <= MaxVectorSize && length_in_bytes_dst <= MaxVectorSize,
           "invalid vector length");
    __ sve_gen_mask_imm($ptmp$$PRegister, T_BYTE, length_in_bytes_resize);
    __ sve_dup($dst$$FloatRegister, __ B, 0);
    __ sve_sel($dst$$FloatRegister, __ B, $ptmp$$PRegister,
               $src$$FloatRegister, $dst$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector cast ----------------------------------

// VectorCastB2X

instruct vcvtBtoX(vReg dst, vReg src) %{
  match(Set dst (VectorCastB2X src));
  format %{ "vcvtBtoX $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      // 4B to 4S/4I/4F, 8B to 8S
      __ neon_vector_extend($dst$$FloatRegister, bt == T_FLOAT ? T_INT : bt,
                            length_in_bytes, $src$$FloatRegister, T_BYTE);
      if (bt == T_FLOAT) {
        __ scvtfv(__ T4S, $dst$$FloatRegister, $dst$$FloatRegister);
      }
    } else {
      assert(UseSVE > 0, "must be sve");
      Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
      __ sve_vector_extend($dst$$FloatRegister, size, $src$$FloatRegister, __ B);
      if (is_floating_point_type(bt)) {
        __ sve_scvtf($dst$$FloatRegister, size, ptrue, $dst$$FloatRegister, size);
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

// VectorCastS2X

instruct vcvtStoB_neon(vReg dst, vReg src) %{
  predicate(Matcher::vector_element_basic_type(n) == T_BYTE &&
            VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))));
  match(Set dst (VectorCastS2X src));
  format %{ "vcvtStoB_neon $dst, $src" %}
  ins_encode %{
    // 4S/8S to 4B/8B
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    __ neon_vector_narrow($dst$$FloatRegister, T_BYTE,
                          $src$$FloatRegister, T_SHORT, length_in_bytes);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtStoB_sve(vReg dst, vReg src, vReg tmp) %{
  predicate(Matcher::vector_element_basic_type(n) == T_BYTE &&
            !VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))));
  match(Set dst (VectorCastS2X src));
  effect(TEMP tmp);
  format %{ "vcvtStoB_sve $dst, $src\t# KILL $tmp" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    __ sve_vector_narrow($dst$$FloatRegister, __ B,
                         $src$$FloatRegister, __ H, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtStoX_extend(vReg dst, vReg src) %{
  predicate(type2aelembytes(Matcher::vector_element_basic_type(n)) >= 4);
  match(Set dst (VectorCastS2X src));
  format %{ "vcvtStoX_extend $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      // 4S to 4I/4F
      __ neon_vector_extend($dst$$FloatRegister, T_INT, length_in_bytes,
                            $src$$FloatRegister, T_SHORT);
      if (bt == T_FLOAT) {
        __ scvtfv(__ T4S, $dst$$FloatRegister, $dst$$FloatRegister);
      }
    } else {
      assert(UseSVE > 0, "must be sve");
      Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
      __ sve_vector_extend($dst$$FloatRegister, size, $src$$FloatRegister, __ H);
      if (is_floating_point_type(bt)) {
        __ sve_scvtf($dst$$FloatRegister, size, ptrue, $dst$$FloatRegister, size);
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

// VectorCastI2X

instruct vcvtItoX_narrow_neon(vReg dst, vReg src) %{
  predicate((Matcher::vector_element_basic_type(n) == T_BYTE ||
             Matcher::vector_element_basic_type(n) == T_SHORT) &&
            VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))));
  match(Set dst (VectorCastI2X src));
  effect(TEMP_DEF dst);
  format %{ "vcvtItoX_narrow_neon $dst, $src" %}
  ins_encode %{
    // 4I to 4B/4S
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    __ neon_vector_narrow($dst$$FloatRegister, bt,
                          $src$$FloatRegister, T_INT, length_in_bytes);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtItoX_narrow_sve(vReg dst, vReg src, vReg tmp) %{
  predicate((Matcher::vector_element_basic_type(n) == T_BYTE ||
             Matcher::vector_element_basic_type(n) == T_SHORT) &&
            !VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))));
  match(Set dst (VectorCastI2X src));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "vcvtItoX_narrow_sve $dst, $src\t# KILL $tmp" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_vector_narrow($dst$$FloatRegister, __ elemType_to_regVariant(bt),
                         $src$$FloatRegister, __ S, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtItoX(vReg dst, vReg src) %{
  predicate(type2aelembytes(Matcher::vector_element_basic_type(n)) >= 4);
  match(Set dst (VectorCastI2X src));
  format %{ "vcvtItoX $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes =  Matcher::vector_length_in_bytes(this);
    if (bt == T_FLOAT) {
      if (VM_Version::use_neon_for_vector(length_in_bytes)) {
        // 2I/4I to 2F/4F
        __ scvtfv(get_arrangement(this), $dst$$FloatRegister, $src$$FloatRegister);
      } else {
        assert(UseSVE > 0, "must be sve");
        __ sve_scvtf($dst$$FloatRegister, __ S, ptrue, $src$$FloatRegister, __ S);
      }
    } else {
      assert(type2aelembytes(bt) == 8, "unsupported type");
      if (VM_Version::use_neon_for_vector(length_in_bytes)) {
        // 2I to 2L/2D
        __ neon_vector_extend($dst$$FloatRegister, T_LONG, length_in_bytes,
                              $src$$FloatRegister, T_INT);
        if (bt == T_DOUBLE) {
          __ scvtfv(__ T2D, $dst$$FloatRegister, $dst$$FloatRegister);
        }
      } else {
        assert(UseSVE > 0, "must be sve");
        __ sve_vector_extend($dst$$FloatRegister, __ D, $src$$FloatRegister, __ S);
        if (bt == T_DOUBLE) {
          __ sve_scvtf($dst$$FloatRegister, __ D, ptrue, $dst$$FloatRegister, __ D);
        }
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

// VectorCastL2X

instruct vcvtLtoI_neon(vReg dst, vReg src) %{
  predicate(Matcher::vector_element_basic_type(n) == T_INT &&
            VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))));
  match(Set dst (VectorCastL2X src));
  format %{ "vcvtLtoI_neon $dst, $src" %}
  ins_encode %{
    // 2L to 2I
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    __ neon_vector_narrow($dst$$FloatRegister, T_INT,
                          $src$$FloatRegister, T_LONG, length_in_bytes);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtLtoI_sve(vReg dst, vReg src, vReg tmp) %{
  predicate((Matcher::vector_element_basic_type(n) == T_INT &&
             !VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1)))) ||
            Matcher::vector_element_basic_type(n) == T_BYTE ||
            Matcher::vector_element_basic_type(n) == T_SHORT);
  match(Set dst (VectorCastL2X src));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "vcvtLtoI_sve $dst, $src\t# KILL $tmp" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_vector_narrow($dst$$FloatRegister, __ elemType_to_regVariant(bt),
                         $src$$FloatRegister, __ D, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtLtoF_neon(vReg dst, vReg src, vRegF tmp) %{
  predicate(UseSVE == 0 && Matcher::vector_element_basic_type(n) == T_FLOAT);
  match(Set dst (VectorCastL2X src));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "vcvtLtoF_neon $dst, $src\t# 2L to 2F. KILL $tmp" %}
  ins_encode %{
    // 2L to 2F
    __ umov(rscratch1, $src$$FloatRegister, __ D, 0);
    __ scvtfs($dst$$FloatRegister, rscratch1);
    __ umov(rscratch1, $src$$FloatRegister, __ D, 1);
    __ scvtfs($tmp$$FloatRegister, rscratch1);
    __ ins($dst$$FloatRegister, __ S, $tmp$$FloatRegister, 1, 0);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtLtoF_sve(vReg dst, vReg src, vReg tmp) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_FLOAT);
  match(Set dst (VectorCastL2X src));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "vcvtLtoF_sve $dst, $src\t# KILL $tmp" %}
  ins_encode %{
    __ sve_scvtf($dst$$FloatRegister, __ S, ptrue, $src$$FloatRegister, __ D);
    __ sve_vector_narrow($dst$$FloatRegister, __ S,
                         $dst$$FloatRegister, __ D, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtLtoD(vReg dst, vReg src) %{
  predicate(Matcher::vector_element_basic_type(n) == T_DOUBLE);
  match(Set dst (VectorCastL2X src));
  format %{ "vcvtLtoD $dst, $src" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      // 2L to 2D
      __ scvtfv(__ T2D, $dst$$FloatRegister, $src$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_scvtf($dst$$FloatRegister, __ D, ptrue, $src$$FloatRegister, __ D);
    }
  %}
  ins_pipe(pipe_slow);
%}

// VectorCastF2X

instruct vcvtFtoX_narrow_neon(vReg dst, vReg src) %{
  predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))) &&
            (Matcher::vector_element_basic_type(n) == T_BYTE ||
             Matcher::vector_element_basic_type(n) == T_SHORT));
  match(Set dst (VectorCastF2X src));
  effect(TEMP_DEF dst);
  format %{ "vcvtFtoX_narrow_neon $dst, $src" %}
  ins_encode %{
    // 4F to 4B/4S
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    __ fcvtzs($dst$$FloatRegister, __ T4S, $src$$FloatRegister);
    __ neon_vector_narrow($dst$$FloatRegister, bt,
                          $dst$$FloatRegister, T_INT, length_in_bytes);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtFtoX_narrow_sve(vReg dst, vReg src, vReg tmp) %{
  predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))) &&
            (Matcher::vector_element_basic_type(n) == T_BYTE ||
             Matcher::vector_element_basic_type(n) == T_SHORT));
  match(Set dst (VectorCastF2X src));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "vcvtFtoX_narrow_sve $dst, $src\t# KILL $tmp" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_fcvtzs($dst$$FloatRegister, __ S, ptrue, $src$$FloatRegister, __ S);
    __ sve_vector_narrow($dst$$FloatRegister, __ elemType_to_regVariant(bt),
                         $dst$$FloatRegister, __ S, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtFtoX(vReg dst, vReg src) %{
  predicate(type2aelembytes(Matcher::vector_element_basic_type(n)) >= 4);
  match(Set dst (VectorCastF2X src));
  format %{ "vcvtFtoX $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes =  Matcher::vector_length_in_bytes(this);
    if (bt == T_INT) {
      if (VM_Version::use_neon_for_vector(length_in_bytes)) {
        // 2F/4F to 2I/4I
        __ fcvtzs($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister);
      } else {
        assert(UseSVE > 0, "must be sve");
        __ sve_fcvtzs($dst$$FloatRegister, __ S, ptrue, $src$$FloatRegister, __ S);
      }
    } else if (bt == T_LONG) {
      if (UseSVE == 0) {
        // 2F to 2L
        __ fcvtl($dst$$FloatRegister, __ T2D, $src$$FloatRegister, __ T2S);
        __ fcvtzs($dst$$FloatRegister, __ T2D, $dst$$FloatRegister);
      } else {
        __ sve_vector_extend($dst$$FloatRegister, __ D, $src$$FloatRegister, __ S);
        __ sve_fcvtzs($dst$$FloatRegister, __ D, ptrue, $dst$$FloatRegister, __ S);
      }
    } else {
      assert(bt == T_DOUBLE, "unsupported type");
      if (length_in_bytes == 16) {
        // 2F to 2D
        __ fcvtl($dst$$FloatRegister, __ T2D, $src$$FloatRegister, __ T2S);
      } else {
        assert(UseSVE > 0 && length_in_bytes > 16, "must be");
        __ sve_vector_extend($dst$$FloatRegister, __ D, $src$$FloatRegister, __ S);
        __ sve_fcvt($dst$$FloatRegister, __ D, ptrue, $dst$$FloatRegister, __ S);
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

// VectorCastD2X

instruct vcvtDtoI_neon(vReg dst, vReg src) %{
  predicate(UseSVE == 0 && Matcher::vector_element_basic_type(n) == T_INT);
  match(Set dst (VectorCastD2X src));
  effect(TEMP_DEF dst);
  format %{ "vcvtDtoI_neon $dst, $src\t# 2D to 2I" %}
  ins_encode %{
    // 2D to 2I
    __ ins($dst$$FloatRegister, __ D, $src$$FloatRegister, 0, 1);
    // We can't use fcvtzs(vector, integer) instruction here because we need
    // saturation arithmetic. See JDK-8276151.
    __ fcvtzdw(rscratch1, $src$$FloatRegister);
    __ fcvtzdw(rscratch2, $dst$$FloatRegister);
    __ fmovs($dst$$FloatRegister, rscratch1);
    __ mov($dst$$FloatRegister, __ S, 1, rscratch2);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtDtoI_sve(vReg dst, vReg src, vReg tmp) %{
  predicate(UseSVE > 0 &&
            (Matcher::vector_element_basic_type(n) == T_BYTE ||
             Matcher::vector_element_basic_type(n) == T_SHORT ||
             Matcher::vector_element_basic_type(n) == T_INT));
  match(Set dst (VectorCastD2X src));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "vcvtDtoI_sve $dst, $src\t# KILL $tmp" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_fcvtzs($dst$$FloatRegister, __ S, ptrue, $src$$FloatRegister, __ D);
    __ sve_vector_narrow($dst$$FloatRegister, __ elemType_to_regVariant(bt),
                         $dst$$FloatRegister, __ D, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtDtoL(vReg dst, vReg src) %{
  predicate(Matcher::vector_element_basic_type(n) == T_LONG);
  match(Set dst (VectorCastD2X src));
  format %{ "vcvtDtoL $dst, $src" %}
  ins_encode %{
    uint length_in_bytes =  Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      // 2D to 2L
      __ fcvtzs($dst$$FloatRegister, __ T2D, $src$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_fcvtzs($dst$$FloatRegister, __ D, ptrue, $src$$FloatRegister, __ D);
    }
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtDtoF_64b(vReg dst, vReg src) %{
  predicate(Matcher::vector_element_basic_type(n) == T_FLOAT &&
            Matcher::vector_length_in_bytes(n) == 8);
  match(Set dst (VectorCastD2X src));
  format %{ "vcvtDtoF_64b $dst, $src\t# 2D to 2F" %}
  ins_encode %{
    // 2D to 2F
    __ fcvtn($dst$$FloatRegister, __ T2S, $src$$FloatRegister, __ T2D);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcvtDtoF_gt64b(vReg dst, vReg src, vReg tmp) %{
  predicate(Matcher::vector_element_basic_type(n) == T_FLOAT &&
            Matcher::vector_length_in_bytes(n) > 8);
  match(Set dst (VectorCastD2X src));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "vcvtDtoF_gt64b $dst, $src\t# vector > 64 bits. KILL $tmp" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    __ sve_fcvt($dst$$FloatRegister, __ S, ptrue, $src$$FloatRegister, __ D);
    __ sve_vector_narrow($dst$$FloatRegister, __ S,
                         $dst$$FloatRegister, __ D, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Replicate ------------------------------------

dnl REPLICATE_INT($1,   $2,       $3  )
dnl REPLICATE_INT(type, arg_type, size)
define(`REPLICATE_INT', `
instruct replicate$1(vReg dst, $2 src) %{
  match(Set dst (Replicate$1 src));
  format %{ "replicate$1 $dst, $src" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ dup($dst$$FloatRegister, get_arrangement(this), $src$$Register);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_dup($dst$$FloatRegister, __ $3, $src$$Register);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REPLICATE_FP($1,   $2  )
dnl REPLICATE_FP(type, size)
define(`REPLICATE_FP', `
instruct replicate$1(vReg dst, vReg$1 src) %{
  match(Set dst (Replicate$1 src));
  format %{ "replicate$1 $dst, $src" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ dup($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_cpy($dst$$FloatRegister, __ $2, ptrue, $src$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl REPLICATE_IMM_SVE($1,   $2,       $3  )
dnl REPLICATE_IMM_SVE(type, arg_type, size)
define(`REPLICATE_IMM_SVE', `
instruct replicate$1_imm8_gt128b(vReg dst, $2 con) %{
  predicate(Matcher::vector_length_in_bytes(n) > 16);
  match(Set dst (Replicate$1 con));
  format %{ "replicate$1_imm8_gt128b $dst, $con\t# vector > 128 bits" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    __ sve_dup($dst$$FloatRegister, __ $3, (int)($con$$constant));
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// replicate from reg
REPLICATE_INT(B, iRegIorL2I, B)
REPLICATE_INT(S, iRegIorL2I, H)
REPLICATE_INT(I, iRegIorL2I, S)
REPLICATE_INT(L, iRegL,      D)
REPLICATE_FP(F, S)
REPLICATE_FP(D, D)

// replicate from imm

instruct replicateI_imm_le128b(vReg dst, immI con) %{
  predicate(Matcher::vector_length_in_bytes(n) <= 16);
  match(Set dst (ReplicateB con));
  match(Set dst (ReplicateS con));
  match(Set dst (ReplicateI con));
  format %{ "replicateI_imm_le128b $dst, $con\t# vector <= 128 bits" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    int imm = (int)$con$$constant;
    if (type2aelembytes(bt) == 1) {
      // Refine imm for B
      imm = imm & 0xff;
    } else if (type2aelembytes(bt) == 2) {
      // Refine imm for S
      imm = imm & 0xffff;
    }
    __ mov($dst$$FloatRegister, get_arrangement(this), imm);
  %}
  ins_pipe(pipe_slow);
%}
dnl
REPLICATE_IMM_SVE(B, immI8,        B)
REPLICATE_IMM_SVE(S, immI8_shift8, H)
REPLICATE_IMM_SVE(I, immI8_shift8, S)

instruct replicateL_imm_128b(vReg dst, immL con) %{
  predicate(Matcher::vector_length_in_bytes(n) == 16);
  match(Set dst (ReplicateL con));
  format %{ "replicateL_imm_128b $dst, $con\t# vector > 128 bits" %}
  ins_encode %{
    __ mov($dst$$FloatRegister, __ T2D, (uint64_t)($con$$constant));
  %}
  ins_pipe(pipe_slow);
%}
dnl
REPLICATE_IMM_SVE(L, immL8_shift8, D)

// ------------------------------ Vector insert --------------------------------

// BYTE, SHORT, INT

instruct insertI_le128b(vReg dst, vReg src, iRegIorL2I val, immI idx) %{
  predicate(Matcher::vector_length_in_bytes(n) <= 16 &&
            (Matcher::vector_element_basic_type(n) == T_BYTE ||
             Matcher::vector_element_basic_type(n) == T_SHORT ||
             Matcher::vector_element_basic_type(n) == T_INT));
  match(Set dst (VectorInsert (Binary src val) idx));
  format %{ "insertI_le128b $dst, $src, $val, $idx\t# vector <= 128 bits" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if ($dst$$FloatRegister != $src$$FloatRegister) {
      __ orr($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
             $src$$FloatRegister, $src$$FloatRegister);
    }
    __ mov($dst$$FloatRegister, __ elemType_to_regVariant(bt),
           (int)($idx$$constant), $val$$Register);
  %}
  ins_pipe(pipe_slow);
%}

instruct insertI_index_lt32(vReg dst, vReg src, iRegIorL2I val, immI idx,
                            vReg tmp, pRegGov pgtmp, rFlagsReg cr) %{
  predicate(n->in(2)->get_int() < 32 &&
            Matcher::vector_length_in_bytes(n) > 16 &&
            (Matcher::vector_element_basic_type(n) == T_BYTE ||
             Matcher::vector_element_basic_type(n) == T_SHORT ||
             Matcher::vector_element_basic_type(n) == T_INT));
  match(Set dst (VectorInsert (Binary src val) idx));
  effect(TEMP tmp, TEMP pgtmp, KILL cr);
  format %{ "insertI_index_lt32 $dst, $src, $val, $idx\t# vector > 128 bits, index < 31. KILL $tmp, $pgtmp, cr" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
    __ sve_index($tmp$$FloatRegister, size, -16, 1);
    __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, size, ptrue,
               $tmp$$FloatRegister, (int)($idx$$constant) - 16);
    if ($dst$$FloatRegister != $src$$FloatRegister) {
      __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister);
    }
    __ sve_cpy($dst$$FloatRegister, size, $pgtmp$$PRegister, $val$$Register);
  %}
  ins_pipe(pipe_slow);
%}

instruct insertI_index_ge32(vReg dst, vReg src, iRegIorL2I val, immI idx, vReg tmp1,
                            vReg tmp2, pRegGov pgtmp, rFlagsReg cr) %{
  predicate(n->in(2)->get_int() >= 32 &&
            (Matcher::vector_element_basic_type(n) == T_BYTE ||
             Matcher::vector_element_basic_type(n) == T_SHORT ||
             Matcher::vector_element_basic_type(n) == T_INT));
  match(Set dst (VectorInsert (Binary src val) idx));
  effect(TEMP tmp1, TEMP tmp2, TEMP pgtmp, KILL cr);
  format %{ "insertI_index_ge32 $dst, $src, $val, $idx\t# index >= 32. KILL $tmp1, $tmp2, $pgtmp, cr" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
    __ sve_index($tmp1$$FloatRegister, size, 0, 1);
    __ sve_dup($tmp2$$FloatRegister, size, (int)($idx$$constant));
    __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, size, ptrue,
               $tmp1$$FloatRegister, $tmp2$$FloatRegister);
    if ($dst$$FloatRegister != $src$$FloatRegister) {
      __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister);
    }
    __ sve_cpy($dst$$FloatRegister, size, $pgtmp$$PRegister, $val$$Register);
  %}
  ins_pipe(pipe_slow);
%}

// LONG

instruct insertL_128b(vReg dst, vReg src, iRegL val, immI idx) %{
  predicate(Matcher::vector_length_in_bytes(n) == 16 &&
            Matcher::vector_element_basic_type(n) == T_LONG);
  match(Set dst (VectorInsert (Binary src val) idx));
  format %{ "insertL_128b $dst, $src, $val, $idx\t# 2L" %}
  ins_encode %{
    if ($dst$$FloatRegister != $src$$FloatRegister) {
      __ orr($dst$$FloatRegister, __ T16B, $src$$FloatRegister, $src$$FloatRegister);
    }
    __ mov($dst$$FloatRegister, __ D, (int)($idx$$constant), $val$$Register);
  %}
  ins_pipe(pipe_slow);
%}

instruct insertL_gt128b(vReg dst, vReg src, iRegL val, immI idx,
                        vReg tmp, pRegGov pgtmp, rFlagsReg cr) %{
  predicate(Matcher::vector_length_in_bytes(n) > 16 &&
            Matcher::vector_element_basic_type(n) == T_LONG);
  match(Set dst (VectorInsert (Binary src val) idx));
  effect(TEMP tmp, TEMP pgtmp, KILL cr);
  format %{ "insertL_gt128b $dst, $src, $val, $idx\t# vector > 128 bits. KILL $tmp, $pgtmp, cr" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    __ sve_index($tmp$$FloatRegister, __ D, -16, 1);
    __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ D, ptrue,
               $tmp$$FloatRegister, (int)($idx$$constant) - 16);
    if ($dst$$FloatRegister != $src$$FloatRegister) {
      __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister);
    }
    __ sve_cpy($dst$$FloatRegister, __ D, $pgtmp$$PRegister, $val$$Register);
  %}
  ins_pipe(pipe_slow);
%}

// FLOAT

instruct insertF_le128b(vReg dst, vReg src, vRegF val, immI idx) %{
  predicate(Matcher::vector_length_in_bytes(n) <= 16 &&
            Matcher::vector_element_basic_type(n) == T_FLOAT);
  match(Set dst (VectorInsert (Binary src val) idx));
  effect(TEMP_DEF dst);
  format %{ "insertF_le128b $dst, $src, $val, $idx\t# vector <= 128 bits" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if ($dst$$FloatRegister != $src$$FloatRegister) {
      __ orr($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
             $src$$FloatRegister, $src$$FloatRegister);
    }
    __ ins($dst$$FloatRegister, __ S, $val$$FloatRegister, (int)($idx$$constant), 0);
  %}
  ins_pipe(pipe_slow);
%}

instruct insertF_index_lt32(vReg dst, vReg src, vRegF val, immI idx,
                            pRegGov pgtmp, rFlagsReg cr) %{
  predicate(n->in(2)->get_int() < 32 &&
            Matcher::vector_length_in_bytes(n) > 16 &&
            Matcher::vector_element_basic_type(n) == T_FLOAT);
  match(Set dst (VectorInsert (Binary src val) idx));
  effect(TEMP_DEF dst, TEMP pgtmp, KILL cr);
  format %{ "insertF_index_lt32 $dst, $src, $val, $idx\t# vector > 128 bits, index < 32. KILL $pgtmp, cr" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    __ sve_index($dst$$FloatRegister, __ S, -16, 1);
    __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ S, ptrue,
               $dst$$FloatRegister, (int)($idx$$constant) - 16);
    __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister);
    __ sve_cpy($dst$$FloatRegister, __ S, $pgtmp$$PRegister, $val$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct insertF_index_ge32(vReg dst, vReg src, vRegF val, immI idx, vReg tmp,
                            pRegGov pgtmp, rFlagsReg cr) %{
  predicate(n->in(2)->get_int() >= 32 &&
            Matcher::vector_element_basic_type(n) == T_FLOAT);
  match(Set dst (VectorInsert (Binary src val) idx));
  effect(TEMP_DEF dst, TEMP tmp, TEMP pgtmp, KILL cr);
  format %{ "insertF_index_ge32 $dst, $src, $val, $idx\t# index >= 32. KILL $tmp, $pgtmp, cr" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    __ sve_index($tmp$$FloatRegister, __ S, 0, 1);
    __ sve_dup($dst$$FloatRegister, __ S, (int)($idx$$constant));
    __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ S, ptrue,
               $tmp$$FloatRegister, $dst$$FloatRegister);
    __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister);
    __ sve_cpy($dst$$FloatRegister, __ S, $pgtmp$$PRegister, $val$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// DOUBLE

instruct insertD_128b(vReg dst, vReg src, vRegD val, immI idx) %{
  predicate(Matcher::vector_length_in_bytes(n) == 16 &&
            Matcher::vector_element_basic_type(n) == T_DOUBLE);
  match(Set dst (VectorInsert (Binary src val) idx));
  effect(TEMP_DEF dst);
  format %{ "insertD_128b $dst, $src, $val, $idx\t# 2D" %}
  ins_encode %{
    if ($dst$$FloatRegister != $src$$FloatRegister) {
      __ orr($dst$$FloatRegister, __ T16B, $src$$FloatRegister, $src$$FloatRegister);
    }
    __ ins($dst$$FloatRegister, __ D, $val$$FloatRegister, (int)($idx$$constant), 0);
  %}
  ins_pipe(pipe_slow);
%}

instruct insertD_gt128b(vReg dst, vReg src, vRegD val, immI idx,
                        pRegGov pgtmp, rFlagsReg cr) %{
  predicate(Matcher::vector_length_in_bytes(n) > 16 &&
            Matcher::vector_element_basic_type(n) == T_DOUBLE);
  match(Set dst (VectorInsert (Binary src val) idx));
  effect(TEMP_DEF dst, TEMP pgtmp, KILL cr);
  format %{ "insertD_gt128b $dst, $src, $val, $idx\t# vector > 128 bits. KILL $pgtmp, cr" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    __ sve_index($dst$$FloatRegister, __ D, -16, 1);
    __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ D, ptrue,
               $dst$$FloatRegister, (int)($idx$$constant) - 16);
    __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister);
    __ sve_cpy($dst$$FloatRegister, __ D, $pgtmp$$PRegister, $val$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Extract --------------------------------------
dnl
dnl EXTRACT_INT_SMALL($1,   $2,    $3,       $4,   $5  )
dnl EXTRACT_INT_SMALL(type, index, arg_type, insn, size)
define(`EXTRACT_INT_SMALL', `
instruct extract$1_index_lt$2($3 dst, vReg src, immI idx) %{
  predicate(n->in(2)->get_int() < $2);
  match(Set dst (Extract$1 src idx));
  format %{ "extract$1_index_lt$2 $dst, $src, $idx\t# index < $2" %}
  ins_encode %{
    __ $4($dst$$Register, $src$$FloatRegister, __ $5, (int)($idx$$constant));
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl
dnl EXTRACT_INT_LARGE($1,   $2,    $3,       $4       )
dnl EXTRACT_INT_LARGE(type, index, arg_type, data_type)
define(`EXTRACT_INT_LARGE', `
instruct extract$1_index_ge$2($3 dst, vReg src, immI idx, vReg tmp) %{
  predicate(n->in(2)->get_int() >= $2);
  match(Set dst (Extract$1 src idx));
  effect(TEMP tmp);
  format %{ "extract$1_index_ge$2 $dst, $src, $idx\t# index >=$2. KILL $tmp" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    __ sve_extract_integral($dst$$Register, $4, $src$$FloatRegister,
                            (int)($idx$$constant), $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// BYTE
EXTRACT_INT_SMALL(B, 16, iRegINoSp, smov, B)
EXTRACT_INT_LARGE(B, 16, iRegINoSp, T_BYTE)

// SHORT
EXTRACT_INT_SMALL(S, 8, iRegINoSp, smov, H)
EXTRACT_INT_LARGE(S, 8, iRegINoSp, T_SHORT)

// INT
EXTRACT_INT_SMALL(I, 4, iRegINoSp, umov, S)
EXTRACT_INT_LARGE(I, 4, iRegINoSp, T_INT)

// LONG
EXTRACT_INT_SMALL(L, 2, iRegLNoSp, umov, D)
EXTRACT_INT_LARGE(L, 2, iRegLNoSp, T_LONG)

dnl
dnl EXTRACT_FP($1,   $2,   $3,    $4,   $5   )
dnl EXTRACT_FP(type, insn, index, size, shift)
define(`EXTRACT_FP', `
instruct extract$1(vReg$1 dst, vReg src, immI idx) %{
  match(Set dst (Extract$1 src idx));
  effect(TEMP_DEF dst);
  format %{ "extract$1 $dst, $src, $idx" %}
  ins_encode %{
    int index = (int)$idx$$constant;
    if (index == 0) {
      __ $2($dst$$FloatRegister, $src$$FloatRegister);
    } else if (index < $3) {
      __ ins($dst$$FloatRegister, __ $4, $src$$FloatRegister, 0, index);
    } else {
      assert(UseSVE > 0, "must be sve");
      __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister);
      __ sve_ext($dst$$FloatRegister, $dst$$FloatRegister, index << $5);
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// FLOAT
EXTRACT_FP(F, fmovs, 4, S, 2)

// DOUBLE
EXTRACT_FP(D, fmovd, 2, D, 3)

// ------------------------------ Vector mask load/store -----------------------

// vector load mask

instruct vloadmask_neon(vReg dst, vReg src) %{
  predicate(UseSVE == 0 &&
            (Matcher::vector_length_in_bytes(n) == 8 ||
             Matcher::vector_length_in_bytes(n) == 16));
  match(Set dst (VectorLoadMask src ));
  format %{ "vloadmask_neon $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    if (bt == T_BYTE) {
      uint length_in_bytes = Matcher::vector_length_in_bytes(this);
      __ negr($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
              $src$$FloatRegister);
    } else {
      __ uxtl($dst$$FloatRegister, __ T8H, $src$$FloatRegister, __ T8B);
      if (type2aelembytes(bt) >= 4) {
        __ uxtl($dst$$FloatRegister, __ T4S, $dst$$FloatRegister, __ T4H);
      }
      if (type2aelembytes(bt) == 8) {
        __ uxtl($dst$$FloatRegister, __ T2D, $dst$$FloatRegister, __ T2S);
      }
      __ negr($dst$$FloatRegister, get_arrangement(this), $dst$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}

instruct vloadmaskB_sve(pReg dst, vReg src, rFlagsReg cr) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_BYTE);
  match(Set dst (VectorLoadMask src));
  effect(KILL cr);
  format %{ "vloadmaskB_sve $dst, $src\t# KILL cr" %}
  ins_encode %{
    __ sve_cmp(Assembler::NE, $dst$$PRegister, __ B,
               ptrue, $src$$FloatRegister, 0);
  %}
  ins_pipe(pipe_slow);
%}

instruct vloadmask_extend_sve(pReg dst, vReg src, vReg tmp, rFlagsReg cr) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) != T_BYTE);
  match(Set dst (VectorLoadMask src));
  effect(TEMP tmp, KILL cr);
  format %{ "vloadmask_extend_sve $dst, $src\t# KILL $tmp, cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
    __ sve_vector_extend($tmp$$FloatRegister, size, $src$$FloatRegister, __ B);
    __ sve_cmp(Assembler::NE, $dst$$PRegister, size, ptrue, $tmp$$FloatRegister, 0);
  %}
  ins_pipe(pipe_slow);
%}

instruct vloadmaskB_masked(pReg dst, vReg src, pRegGov pg, rFlagsReg cr) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_BYTE);
  match(Set dst (VectorLoadMask src pg));
  effect(KILL cr);
  format %{ "vloadmaskB_masked $dst, $pg, $src\t# KILL cr" %}
  ins_encode %{
    __ sve_cmp(Assembler::NE, $dst$$PRegister, __ B,
               $pg$$PRegister, $src$$FloatRegister, 0);
  %}
  ins_pipe(pipe_slow);
%}

instruct vloadmask_extend_masked(pReg dst, vReg src, pRegGov pg, vReg tmp, rFlagsReg cr) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) != T_BYTE);
  match(Set dst (VectorLoadMask src pg));
  effect(TEMP tmp, KILL cr);
  format %{ "vloadmask_extend_masked $dst, $pg, $src\t# KILL $tmp, cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
    __ sve_vector_extend($tmp$$FloatRegister, size, $src$$FloatRegister, __ B);
    __ sve_cmp(Assembler::NE, $dst$$PRegister, size,
               $pg$$PRegister, $tmp$$FloatRegister, 0);
  %}
  ins_pipe(pipe_slow);
%}

// vector store mask - neon

instruct vstoremaskB_neon(vReg dst, vReg src, immI_1 size) %{
  predicate(UseSVE == 0);
  match(Set dst (VectorStoreMask src size));
  format %{ "vstoremaskB_neon $dst, $src" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
    __ negr($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
            $src$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vstoremask_narrow_neon(vReg dst, vReg src, immI_gt_1 size) %{
  predicate(UseSVE == 0);
  match(Set dst (VectorStoreMask src size));
  format %{ "vstoremask_narrow_neon $dst, $src" %}
  ins_encode %{
    int esize = (int)$size$$constant;
    if (esize == 2) {
      __ xtn($dst$$FloatRegister, __ T8B, $src$$FloatRegister, __ T8H);
    } else if (esize == 4) {
      __ xtn($dst$$FloatRegister, __ T4H, $src$$FloatRegister, __ T4S);
      __ xtn($dst$$FloatRegister, __ T8B, $dst$$FloatRegister, __ T8H);
    } else {
      assert(esize == 8, "must be");
      __ xtn($dst$$FloatRegister, __ T2S, $src$$FloatRegister, __ T2D);
      __ xtn($dst$$FloatRegister, __ T4H, $dst$$FloatRegister, __ T4S);
      __ xtn($dst$$FloatRegister, __ T8B, $dst$$FloatRegister, __ T8H);
    }
    __ negr($dst$$FloatRegister, __ T8B, $dst$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// vector store mask - sve

instruct vstoremaskB_sve(vReg dst, pReg src, immI_1 size) %{
  predicate(UseSVE > 0);
  match(Set dst (VectorStoreMask src size));
  format %{ "vstoremaskB_sve $dst, $src" %}
  ins_encode %{
    __ sve_cpy($dst$$FloatRegister, __ B, $src$$PRegister, 1, false);
  %}
  ins_pipe(pipe_slow);
%}

instruct vstoremask_narrow_sve(vReg dst, pReg src, immI_gt_1 size, vReg tmp) %{
  predicate(UseSVE > 0);
  match(Set dst (VectorStoreMask src size));
  effect(TEMP_DEF dst, TEMP tmp);
  format %{ "vstoremask_narrow_sve $dst, $src\t# KILL $tmp" %}
  ins_encode %{
    Assembler::SIMD_RegVariant size = __ elemBytes_to_regVariant((int)$size$$constant);
    __ sve_cpy($dst$$FloatRegister, size, $src$$PRegister, 1, false);
    __ sve_vector_narrow($dst$$FloatRegister, __ B,
                         $dst$$FloatRegister, size, $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// Combined rules for vector mask load when the vector element type is not T_BYTE

// VectorLoadMask+LoadVector, and the VectorLoadMask is unpredicated.
instruct vloadmask_loadV(pReg dst, indirect mem, vReg tmp, rFlagsReg cr) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n)) > 1);
  match(Set dst (VectorLoadMask (LoadVector mem)));
  effect(TEMP tmp, KILL cr);
  format %{ "vloadmask_loadV $dst, $mem\t# KILL $tmp, cr" %}
  ins_encode %{
    // Load mask values which are boolean type, and extend them to the
    // defined vector element type. Convert the vector to predicate.
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), false, $tmp$$FloatRegister,
                          ptrue, T_BOOLEAN, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
    __ sve_cmp(Assembler::NE, $dst$$PRegister, __ elemType_to_regVariant(bt),
               ptrue, $tmp$$FloatRegister, 0);
  %}
  ins_pipe(pipe_slow);
%}

// VectorLoadMask+LoadVector, and the VectorLoadMask is predicated.
instruct vloadmask_loadV_masked(pReg dst, indirect mem, pRegGov pg,
                                vReg tmp, rFlagsReg cr) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n)) > 1);
  match(Set dst (VectorLoadMask (LoadVector mem) pg));
  effect(TEMP tmp, KILL cr);
  format %{ "vloadmask_loadV_masked $dst, $pg, $mem\t# KILL $tmp, cr" %}
  ins_encode %{
    // Load valid mask values which are boolean type, and extend them to the
    // defined vector element type. Convert the vector to predicate.
    BasicType bt = Matcher::vector_element_basic_type(this);
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), false, $tmp$$FloatRegister,
                          $pg$$PRegister, T_BOOLEAN, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
    __ sve_cmp(Assembler::NE, $dst$$PRegister, __ elemType_to_regVariant(bt),
               $pg$$PRegister, $tmp$$FloatRegister, 0);
  %}
  ins_pipe(pipe_slow);
%}

// VectorLoadMask+LoadVectorMasked, and the VectorLoadMask is unpredicated.
instruct vloadmask_loadVMasked(pReg dst, vmemA mem, pRegGov pg, vReg tmp, rFlagsReg cr) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n)) > 1);
  match(Set dst (VectorLoadMask (LoadVectorMasked mem pg)));
  effect(TEMP tmp, KILL cr);
  format %{ "vloadmask_loadVMasked $dst, $mem\t# KILL $tmp, cr" %}
  ins_encode %{
    // Load mask values which are boolean type, and extend them to the
    // defined vector element type. Convert the vector to predicate.
    //
    // Note that we cannot use "pg" here, since it is the predicate used
    // for the vector load with boolean type. But the predicate used in
    // the extending "sve_ld1b" is based on the final extended vector type,
    // which is the full-sized predicate (ptrue) used in VectorLoadMask.
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), false, $tmp$$FloatRegister,
                          ptrue, T_BOOLEAN, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
    __ sve_cmp(Assembler::NE, $dst$$PRegister, __ elemType_to_regVariant(bt),
               ptrue, $tmp$$FloatRegister, 0);
  %}
  ins_pipe(pipe_slow);
%}

// VectorLoadMask+LoadVectorMasked, and the VectorLoadMask is predicated.
instruct vloadmask_loadVMasked_masked(pReg dst, vmemA mem, pRegGov pg1, pRegGov pg2,
                                      vReg tmp, rFlagsReg cr) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n)) > 1);
  match(Set dst (VectorLoadMask (LoadVectorMasked mem pg1) pg2));
  effect(TEMP tmp, KILL cr);
  format %{ "vloadmask_loadVMasked_masked $dst, $pg2, $mem\t# KILL $tmp, cr" %}
  ins_encode %{
    // Load valid mask values which are boolean type, and extend them to the
    // defined vector element type. Convert the vector to predicate.
    //
    // Note that we cannot use "pg1" here, since it is the predicate used
    // for the vector load with boolean type. But the predicate used in
    // the extending "sve_ld1b" is based on the final extended vector type,
    // which is the "pg2" used in VectorLoadMask.
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), false, $tmp$$FloatRegister,
                          $pg2$$PRegister, T_BOOLEAN, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
    __ sve_cmp(Assembler::NE, $dst$$PRegister, __ elemType_to_regVariant(bt),
               $pg2$$PRegister, $tmp$$FloatRegister, 0);
  %}
  ins_pipe(pipe_slow);
%}

// Combined rules for vector mask store when the vector element type is not T_BYTE

// StoreVector+VectorStoreMask, and the vector size of "src" is equal to the MaxVectorSize.
instruct storeV_vstoremask(indirect mem, pReg src, immI_gt_1 esize, vReg tmp) %{
  predicate(UseSVE > 0 &&
            Matcher::vector_length_in_bytes(n->as_StoreVector()->in(MemNode::ValueIn)->in(1)) == MaxVectorSize);
  match(Set mem (StoreVector mem (VectorStoreMask src esize)));
  effect(TEMP tmp);
  format %{ "storeV_vstoremask $mem, $src\t# KILL $tmp" %}
  ins_encode %{
    // Convert the valid src predicate to vector, and store the vector elements
    // as boolean values.
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    assert(type2aelembytes(bt) == (int)$esize$$constant, "unsupported type");
    Assembler::SIMD_RegVariant size = __ elemBytes_to_regVariant($esize$$constant);
    __ sve_cpy($tmp$$FloatRegister, size, $src$$PRegister, 1, false);
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), true, $tmp$$FloatRegister,
                          ptrue, T_BOOLEAN, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
  %}
  ins_pipe(pipe_slow);
%}

// StoreVector+VectorStoreMask, and the vector size of "src" is less than the MaxVectorSize.
instruct storeV_vstoremask_masked(indirect mem, pReg src, immI_gt_1 esize,
                                  vReg tmp, pRegGov pgtmp, rFlagsReg cr) %{
  predicate(UseSVE > 0 &&
            Matcher::vector_length_in_bytes(n->as_StoreVector()->in(MemNode::ValueIn)->in(1)) < MaxVectorSize);
  match(Set mem (StoreVector mem (VectorStoreMask src esize)));
  effect(TEMP tmp, TEMP pgtmp, KILL cr);
  format %{ "storeV_vstoremask_masked $mem, $src\t# KILL $tmp, $pgtmp, cr" %}
  ins_encode %{
    // Convert the valid src predicate to vector, and store the vector elements
    // as boolean values.
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
    __ sve_cpy($tmp$$FloatRegister, size, $src$$PRegister, 1, false);
    __ sve_gen_mask_imm($pgtmp$$PRegister, bt, Matcher::vector_length(this, $src));
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), true, $tmp$$FloatRegister,
                          $pgtmp$$PRegister, T_BOOLEAN, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
  %}
  ins_pipe(pipe_slow);
%}

// StoreVectorMasked+VectorStoreMask, and the vector size of "src" is equal to the MaxVectorSize.
instruct storeVMasked_vstoremask(vmemA mem, pReg src, pRegGov pg, immI_gt_1 esize, vReg tmp) %{
  predicate(UseSVE > 0 &&
            Matcher::vector_length_in_bytes(n->as_StoreVector()->in(MemNode::ValueIn)->in(1)) == MaxVectorSize);
  match(Set mem (StoreVectorMasked mem (Binary (VectorStoreMask src esize) pg)));
  effect(TEMP tmp);
  format %{ "storeVMasked_vstoremask $mem, $src\t# KILL $tmp" %}
  ins_encode %{
    // Convert the valid src predicate to vector, and store the vector elements
    // as boolean values.
    //
    // Note that we cannot use "pg" here, since it is the predicate used
    // for the vector store with boolean type. But the predicate used in
    // the narrowing "sve_st1b" is based on the "src" vector type, which
    // is the full-sized predicate (ptrue) here.
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    assert(type2aelembytes(bt) == (int)$esize$$constant, "unsupported type.");
    Assembler::SIMD_RegVariant size = __ elemBytes_to_regVariant($esize$$constant);
    __ sve_cpy($tmp$$FloatRegister, size, $src$$PRegister, 1, false);
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), true, $tmp$$FloatRegister,
                          ptrue, T_BOOLEAN, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
  %}
  ins_pipe(pipe_slow);
%}

// StoreVectorMasked+VectorStoreMask, and the vector size of "src" is less than the MaxVectorSize.
instruct storeVMasked_vstoremask_masked(vmemA mem, pReg src, pRegGov pg, immI_gt_1 esize,
                                        vReg tmp, pRegGov pgtmp, rFlagsReg cr) %{
  predicate(UseSVE > 0 &&
            Matcher::vector_length_in_bytes(n->as_StoreVector()->in(MemNode::ValueIn)->in(1)) < MaxVectorSize);
  match(Set mem (StoreVectorMasked mem (Binary (VectorStoreMask src esize) pg)));
  effect(TEMP tmp, TEMP pgtmp, KILL cr);
  format %{ "storeVMasked_vstoremask_masked $mem, $src\t# KILL $tmp, $pgtmp, cr" %}
  ins_encode %{
    // Convert the valid src predicate to vector, and store the vector elements
    // as boolean values.
    //
    // Note that we cannot use "pg" here, since it is the predicate used for the
    // vector store with boolean type. But the predicate used in the narrowing
    // "sve_st1b" is based on the "src" vector type, which needed to be generated
    // here.
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
    __ sve_cpy($tmp$$FloatRegister, size, $src$$PRegister, 1, false);
    __ sve_gen_mask_imm($pgtmp$$PRegister, bt, Matcher::vector_length(this, $src));
    loadStoreA_predicated(C2_MacroAssembler(&cbuf), true, $tmp$$FloatRegister,
                          $pgtmp$$PRegister, T_BOOLEAN, bt, $mem->opcode(),
                          as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector mask basic OPs ------------------------

dnl
dnl VMASK_BITWISE_OP($1,   $2,      $3  )
dnl VMASK_BITWISE_OP(type, op_name, insn)
define(`VMASK_BITWISE_OP', `
instruct vmask_$1(pReg pd, pReg pn, pReg pm) %{
  predicate(UseSVE > 0);
  match(Set pd ($2 pn pm));
  format %{ "vmask_$1 $pd, $pn, $pm" %}
  ins_encode %{
    __ $3($pd$$PRegister, ptrue, $pn$$PRegister, $pm$$PRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl VMASK_AND_NOT($1  )
dnl VMASK_AND_NOT(type)
define(`VMASK_AND_NOT', `
instruct vmask_and_not$1(pReg pd, pReg pn, pReg pm, imm$1_M1 m1) %{
  predicate(UseSVE > 0);
  match(Set pd (AndVMask pn (XorVMask pm (MaskAll m1))));
  format %{ "vmask_and_not$1 $pd, $pn, $pm" %}
  ins_encode %{
    __ sve_bic($pd$$PRegister, ptrue, $pn$$PRegister, $pm$$PRegister);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
// vector mask logical ops: and/or/xor/and_not
VMASK_BITWISE_OP(and, AndVMask, sve_and)
VMASK_BITWISE_OP(or,  OrVMask,  sve_orr)
VMASK_BITWISE_OP(xor, XorVMask, sve_eor)
VMASK_AND_NOT(I)
VMASK_AND_NOT(L)

// vector mask compare

instruct vmaskcmp_neon(vReg dst, vReg src1, vReg src2, immI cond) %{
  predicate(UseSVE == 0 &&
            (Matcher::vector_length_in_bytes(n) == 8 ||
             Matcher::vector_length_in_bytes(n) == 16));
  match(Set dst (VectorMaskCmp (Binary src1 src2) cond));
  format %{ "vmaskcmp_neon $dst, $src1, $src2, $cond" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    __ neon_compare($dst$$FloatRegister, bt, $src1$$FloatRegister,
                    $src2$$FloatRegister, (int)($cond$$constant),
                    /* isQ */ length_in_bytes == 16);
  %}
  ins_pipe(pipe_slow);
%}

instruct vmaskcmp_sve(pReg dst, vReg src1, vReg src2, immI cond, rFlagsReg cr) %{
  predicate(UseSVE > 0);
  match(Set dst (VectorMaskCmp (Binary src1 src2) cond));
  effect(KILL cr);
  format %{ "vmaskcmp_sve $dst, $src1, $src2, $cond\t# KILL cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_compare($dst$$PRegister, bt, ptrue, $src1$$FloatRegister,
                   $src2$$FloatRegister, (int)($cond$$constant));
  %}
  ins_pipe(pipe_slow);
%}

instruct vmaskcmp_masked(pReg dst, vReg src1, vReg src2, immI cond,
                         pRegGov pg, rFlagsReg cr) %{
  predicate(UseSVE > 0);
  match(Set dst (VectorMaskCmp (Binary src1 src2) (Binary cond pg)));
  effect(KILL cr);
  format %{ "vmaskcmp_masked $dst, $pg, $src1, $src2, $cond\t# KILL cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_compare($dst$$PRegister, bt, $pg$$PRegister, $src1$$FloatRegister,
                   $src2$$FloatRegister, (int)($cond$$constant));
  %}
  ins_pipe(pipe_slow);
%}

// vector mask cast

instruct vmaskcast_same_esize_neon(vReg dst_src) %{
  predicate(UseSVE == 0 &&
            Matcher::vector_length_in_bytes(n) == Matcher::vector_length_in_bytes(n->in(1)) &&
            (Matcher::vector_length_in_bytes(n) == 8 || Matcher::vector_length_in_bytes(n) == 16));
  match(Set dst_src (VectorMaskCast dst_src));
  ins_cost(0);
  format %{ "vmaskcast_same_esize_neon $dst_src\t# do nothing" %}
  ins_encode(/* empty encoding */);
  ins_pipe(pipe_class_empty);
%}

instruct vmaskcast_extend_neon(vReg dst, vReg src) %{
  predicate(UseSVE == 0 &&
            Matcher::vector_length_in_bytes(n) > Matcher::vector_length_in_bytes(n->in(1)));
  match(Set dst (VectorMaskCast src));
  format %{ "vmaskcast_extend_neon $dst, $src" %}
  ins_encode %{
    BasicType dst_bt = Matcher::vector_element_basic_type(this);
    if (is_floating_point_type(dst_bt)) {
      dst_bt = (dst_bt == T_FLOAT) ? T_INT : T_LONG;
    }
    uint length_in_bytes_dst = Matcher::vector_length_in_bytes(this);
    BasicType src_bt = Matcher::vector_element_basic_type(this, $src);
    if (is_floating_point_type(src_bt)) {
      src_bt = (src_bt == T_FLOAT) ? T_INT : T_LONG;
    }
    __ neon_vector_extend($dst$$FloatRegister, dst_bt, length_in_bytes_dst,
                          $src$$FloatRegister, src_bt);
  %}
  ins_pipe(pipe_slow);
%}

instruct vmaskcast_narrow_neon(vReg dst, vReg src) %{
  predicate(UseSVE == 0 &&
            Matcher::vector_length_in_bytes(n) < Matcher::vector_length_in_bytes(n->in(1)));
  match(Set dst (VectorMaskCast src));
  format %{ "vmaskcast_narrow_neon $dst, $src" %}
  ins_encode %{
    BasicType dst_bt = Matcher::vector_element_basic_type(this);
    if (is_floating_point_type(dst_bt)) {
      dst_bt = (dst_bt == T_FLOAT) ? T_INT : T_LONG;
    }
    BasicType src_bt = Matcher::vector_element_basic_type(this, $src);
    if (is_floating_point_type(src_bt)) {
      src_bt = (src_bt == T_FLOAT) ? T_INT : T_LONG;
    }
    uint length_in_bytes_src = Matcher::vector_length_in_bytes(this, $src);
    __ neon_vector_narrow($dst$$FloatRegister, dst_bt,
                          $src$$FloatRegister, src_bt, length_in_bytes_src);
  %}
  ins_pipe(pipe_slow);
%}

instruct vmaskcast_same_esize_sve(pReg dst_src) %{
  predicate(UseSVE > 0 &&
            Matcher::vector_length_in_bytes(n) == Matcher::vector_length_in_bytes(n->in(1)));
  match(Set dst_src (VectorMaskCast dst_src));
  ins_cost(0);
  format %{ "vmaskcast_same_esize_sve $dst_src\t# do nothing" %}
  ins_encode(/* empty encoding */);
  ins_pipe(pipe_class_empty);
%}

instruct vmaskcast_extend_sve(pReg dst, pReg src) %{
  predicate(UseSVE > 0 &&
            Matcher::vector_length_in_bytes(n) > Matcher::vector_length_in_bytes(n->in(1)));
  match(Set dst (VectorMaskCast src));
  format %{ "vmaskcast_extend_sve $dst, $src" %}
  ins_encode %{
    uint length_in_bytes_dst = Matcher::vector_length_in_bytes(this);
    uint length_in_bytes_src = Matcher::vector_length_in_bytes(this, $src);
    assert(length_in_bytes_dst == 2 * length_in_bytes_src ||
           length_in_bytes_dst == 4 * length_in_bytes_src ||
           length_in_bytes_dst == 8 * length_in_bytes_src, "invalid vector length");
    __ sve_vmaskcast_extend($dst$$PRegister, $src$$PRegister,
                            length_in_bytes_dst, length_in_bytes_src);
  %}
  ins_pipe(pipe_slow);
%}

instruct vmaskcast_narrow_sve(pReg dst, pReg src) %{
  predicate(UseSVE > 0 &&
            Matcher::vector_length_in_bytes(n) < Matcher::vector_length_in_bytes(n->in(1)));
  match(Set dst (VectorMaskCast src));
  format %{ "vmaskcast_narrow_sve $dst, $src" %}
  ins_encode %{
    uint length_in_bytes_dst = Matcher::vector_length_in_bytes(this);
    uint length_in_bytes_src = Matcher::vector_length_in_bytes(this, $src);
    assert(length_in_bytes_dst * 2 == length_in_bytes_src ||
           length_in_bytes_dst * 4 == length_in_bytes_src ||
           length_in_bytes_dst * 8 == length_in_bytes_src, "invalid vector length");
    __ sve_vmaskcast_narrow($dst$$PRegister, $src$$PRegister,
                            length_in_bytes_dst, length_in_bytes_src);
  %}
  ins_pipe(pipe_slow);
%}

// vector mask reinterpret

instruct vmask_reinterpret_same_esize(pReg dst_src) %{
  predicate(UseSVE > 0 &&
            Matcher::vector_length(n) == Matcher::vector_length(n->in(1)) &&
            Matcher::vector_length_in_bytes(n) == Matcher::vector_length_in_bytes(n->in(1)));
  match(Set dst_src (VectorReinterpret dst_src));
  ins_cost(0);
  format %{ "vmask_reinterpret_same_esize $dst_src\t# do nothing" %}
  ins_encode(/* empty encoding */);
  ins_pipe(pipe_class_empty);
%}

instruct vmask_reinterpret_diff_esize(pReg dst, pReg src, vReg tmp, rFlagsReg cr) %{
  predicate(UseSVE > 0 &&
            Matcher::vector_length(n) != Matcher::vector_length(n->in(1)) &&
            Matcher::vector_length_in_bytes(n) == Matcher::vector_length_in_bytes(n->in(1)));
  match(Set dst (VectorReinterpret src));
  effect(TEMP tmp, KILL cr);
  format %{ "vmask_reinterpret_diff_esize $dst, $src\t# KILL $tmp, cr" %}
  ins_encode %{
    BasicType from_bt = Matcher::vector_element_basic_type(this, $src);
    Assembler::SIMD_RegVariant from_size = __ elemType_to_regVariant(from_bt);
    BasicType to_bt = Matcher::vector_element_basic_type(this);
    Assembler::SIMD_RegVariant to_size = __ elemType_to_regVariant(to_bt);
    __ sve_cpy($tmp$$FloatRegister, from_size, $src$$PRegister, -1, false);
    __ sve_cmp(Assembler::EQ, $dst$$PRegister, to_size, ptrue, $tmp$$FloatRegister, -1);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector mask reductions -----------------------

// true count

instruct vmask_truecount_neon(iRegINoSp dst, vReg src, vReg tmp) %{
  predicate(UseSVE == 0);
  match(Set dst (VectorMaskTrueCount src));
  effect(TEMP tmp);
  format %{ "vmask_truecount_neon $dst, $src\t# KILL $tmp" %}
  ins_encode %{
    // Input "src" is a vector of boolean represented as bytes with
    // 0x00/0x01 as element values.
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    assert(bt == T_BOOLEAN, "unsupported type");
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    __ addv($tmp$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
            $src$$FloatRegister);
    __ umov($dst$$Register, $tmp$$FloatRegister, __ B, 0);
  %}
  ins_pipe(pipe_slow);
%}

instruct vmask_truecount_sve(iRegINoSp dst, pReg src) %{
  predicate(UseSVE > 0);
  match(Set dst (VectorMaskTrueCount src));
  format %{ "vmask_truecount_sve $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    __ sve_cntp($dst$$Register, __ elemType_to_regVariant(bt),
                ptrue, $src$$PRegister);
  %}
  ins_pipe(pipe_slow);
%}

// first true

instruct vmask_firsttrue_lt8e(iRegINoSp dst, vReg src, rFlagsReg cr) %{
  predicate(UseSVE == 0 &&
            Matcher::vector_length(n->in(1)) < 8);
  match(Set dst (VectorMaskFirstTrue src));
  effect(KILL cr);
  format %{ "vmask_firsttrue_lt8e $dst, $src\t# vector < 8 elements (neon). KILL cr" %}
  ins_encode %{
    // Returns the index of the first active lane of the
    // vector mask, or VLENGTH if no lane is active.
    //
    // Input "src" is a vector of boolean represented as
    // bytes with 0x00/0x01 as element values.
    //
    // Computed by reversing the bits and counting the leading
    // zero bytes.
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    assert(bt == T_BOOLEAN, "unsupported type");
    __ fmovd($dst$$Register, $src$$FloatRegister);
    __ rbit($dst$$Register, $dst$$Register);
    __ clz($dst$$Register, $dst$$Register);
    __ lsrw($dst$$Register, $dst$$Register, 3);
    __ movw(rscratch1, Matcher::vector_length(this, $src));
    __ cmpw($dst$$Register, rscratch1);
    __ cselw($dst$$Register, rscratch1, $dst$$Register, Assembler::GE);
  %}
  ins_pipe(pipe_slow);
%}

instruct vmask_firsttrue_8or16e(iRegINoSp dst, vReg src) %{
  predicate(UseSVE == 0 &&
            (Matcher::vector_length(n->in(1)) == 8 || Matcher::vector_length(n->in(1)) == 16));
  match(Set dst (VectorMaskFirstTrue src));
  format %{ "vmask_firsttrue_8or16e $dst, $src\t# vector 8B/16B (neon)" %}
  ins_encode %{
    // Returns the index of the first active lane of the
    // vector mask, or VLENGTH if no lane is active.
    //
    // Input "src" is a vector of boolean represented as
    // bytes with 0x00/0x01 as element values.
    //
    // Computed by reversing the bits and counting the leading
    // zero bytes.

    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    assert(bt == T_BOOLEAN, "unsupported type");
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    if (length_in_bytes == 8) {
      __ fmovd($dst$$Register, $src$$FloatRegister);
      __ rbit($dst$$Register, $dst$$Register);
      __ clz($dst$$Register, $dst$$Register);
      __ lsrw($dst$$Register, $dst$$Register, 3);
    } else {
      assert(length_in_bytes == 16, "must be");
      Label FIRST_TRUE_INDEX;

      // Try to compute the result from lower 64 bits.
      __ fmovd($dst$$Register, $src$$FloatRegister);
      __ movw(rscratch1, zr);
      __ cbnz($dst$$Register, FIRST_TRUE_INDEX);

      // Compute the result from the higher 64 bits.
      __ fmovhid($dst$$Register, $src$$FloatRegister);
      __ movw(rscratch1, 8);

      // Reverse the bits and count the leading zero bytes.
      __ bind(FIRST_TRUE_INDEX);
      __ rbit($dst$$Register, $dst$$Register);
      __ clz($dst$$Register, $dst$$Register);
      __ addw($dst$$Register, rscratch1, $dst$$Register, Assembler::LSR, 3);
    }
  %}
  ins_pipe(pipe_slow);
%}

// Return the index of the first mask lane that is set, or vector length if none of
// them are set.

instruct vmask_firsttrue_sve(iRegINoSp dst, pReg src, pReg ptmp) %{
  predicate(UseSVE > 0);
  match(Set dst (VectorMaskFirstTrue src));
  effect(TEMP ptmp);
  format %{ "vmask_firsttrue_sve $dst, $src\t# KILL $ptmp" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_brkb($ptmp$$PRegister, ptrue, $src$$PRegister, false);
    __ sve_cntp($dst$$Register, __ elemType_to_regVariant(bt), ptrue, $ptmp$$PRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vmask_firsttrue_masked(iRegINoSp dst, pReg src, pReg pg, pReg ptmp) %{
  predicate(UseSVE > 0);
  match(Set dst (VectorMaskFirstTrue src pg));
  effect(TEMP ptmp);
  format %{ "vmask_firsttrue_masked $dst, $pg, $src\t# KILL $ptmp" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    __ sve_brkb($ptmp$$PRegister, $pg$$PRegister, $src$$PRegister, false);
    __ sve_cntp($dst$$Register, __ elemType_to_regVariant(bt), ptrue, $ptmp$$PRegister);
  %}
  ins_pipe(pipe_slow);
%}

// last true

instruct vmask_lasttrue_neon(iRegINoSp dst, vReg src) %{
  predicate(UseSVE == 0);
  match(Set dst (VectorMaskLastTrue src));
  format %{ "vmask_lasttrue_neon $dst, $src" %}
  ins_encode %{
    // Returns the index of the last active lane of the
    // vector mask, or -1 if no lane is active.
    //
    // Input "src" is a vector of boolean represented as
    // bytes with 0x00/0x01 as element values.

    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    assert(bt == T_BOOLEAN, "unsupported type");
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    if (length_in_bytes <= 8) {
      // Computed by counting the leading zero bytes and
      // subtracting it by 7 (VLENGTH - 1).
      __ fmovd($dst$$Register, $src$$FloatRegister);
      __ clz($dst$$Register, $dst$$Register);
      __ movw(rscratch1, 7);
      __ subw($dst$$Register, rscratch1, $dst$$Register, Assembler::LSR, 3);
    } else {
      assert(length_in_bytes == 16, "must be");
      Label LAST_TRUE_INDEX;

      // Try to compute the result from higher 64 bits.
      __ fmovhid($dst$$Register, $src$$FloatRegister);
      __ movw(rscratch1, 16 - 1);
      __ cbnz($dst$$Register, LAST_TRUE_INDEX);

      // Compute the result from the lower 64 bits.
      __ fmovd($dst$$Register, $src$$FloatRegister);
      __ movw(rscratch1, 8 - 1);

      // Count the leading zero bytes and subtract it by 15 (VLENGTH - 1).
      __ bind(LAST_TRUE_INDEX);
      __ clz($dst$$Register, $dst$$Register);
      __ subw($dst$$Register, rscratch1, $dst$$Register, Assembler::LSR, 3);
    }
  %}
  ins_pipe(pipe_slow);
%}

instruct vmask_lasttrue_sve(iRegINoSp dst, pReg src, pReg ptmp) %{
  predicate(UseSVE > 0);
  match(Set dst (VectorMaskLastTrue src));
  effect(TEMP ptmp);
  format %{ "vmask_lasttrue_sve $dst, $src\t# KILL $ptmp" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this, $src);
    __ sve_vmask_lasttrue($dst$$Register, bt, $src$$PRegister, $ptmp$$PRegister);
  %}
  ins_pipe(pipe_slow);
%}

// tolong

instruct vmask_tolong_neon(iRegLNoSp dst, vReg src) %{
  predicate(UseSVE == 0);
  match(Set dst (VectorMaskToLong src));
  format %{ "vmask_tolong_neon $dst, $src" %}
  ins_encode %{
    // Input "src" is a vector of boolean represented as
    // bytes with 0x00/0x01 as element values.

    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    if (length_in_bytes <= 8) {
      __ fmovd($dst$$Register, $src$$FloatRegister);
      __ bytemask_compress($dst$$Register);
    } else {
      assert(length_in_bytes == 16, "must be");
      __ umov($dst$$Register, $src$$FloatRegister, __ D, 0);
      __ umov(rscratch1, $src$$FloatRegister, __ D, 1);
      __ bytemask_compress($dst$$Register);
      __ bytemask_compress(rscratch1);
      __ orr($dst$$Register, $dst$$Register, rscratch1, Assembler::LSL, 8);
    }
  %}
  ins_pipe(pipe_slow);
%}

instruct vmask_tolong_sve(iRegLNoSp dst, pReg src, vReg tmp1, vReg tmp2) %{
  predicate(UseSVE > 0);
  match(Set dst (VectorMaskToLong src));
  effect(TEMP tmp1, TEMP tmp2);
  format %{ "vmask_tolong_sve $dst, $src\t# KILL $tmp1, $tmp2" %}
  ins_encode %{
    __ sve_vmask_tolong($dst$$Register, $src$$PRegister,
                        Matcher::vector_element_basic_type(this, $src),
                        Matcher::vector_length(this, $src),
                        $tmp1$$FloatRegister, $tmp2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// fromlong

instruct vmask_fromlong(pReg dst, iRegL src, vReg tmp1, vReg tmp2) %{
  match(Set dst (VectorLongToMask src));
  effect(TEMP tmp1, TEMP tmp2);
  format %{ "vmask_fromlong $dst, $src\t# vector (sve2). KILL $tmp1, $tmp2" %}
  ins_encode %{
    __ sve_vmask_fromlong($dst$$PRegister, $src$$Register,
                          Matcher::vector_element_basic_type(this),
                          Matcher::vector_length(this),
                          $tmp1$$FloatRegister, $tmp2$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector mask generation -----------------------

// maskAll
dnl
dnl VMASKALL_IMM($1,   $2      )
dnl VMASKALL_IMM(type, var_type)
define(`VMASKALL_IMM', `
instruct vmaskAll_imm$1(pReg dst, imm$1 src, rFlagsReg cr) %{
  predicate(UseSVE > 0);
  match(Set dst (MaskAll src));
  effect(KILL cr);
  format %{ "vmaskAll_imm$1 $dst, $src\t# KILL cr" %}
  ins_encode %{
    $2 con = ($2)$src$$constant;
    if (con == 0) {
      __ sve_pfalse($dst$$PRegister);
    } else {
      assert(con == -1, "invalid constant value for mask");
      BasicType bt = Matcher::vector_element_basic_type(this);
      __ sve_gen_mask_imm($dst$$PRegister, bt, Matcher::vector_length(this));
    }
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl VMASKALL($1,   $2      )
dnl VMASKALL(type, arg_type)
define(`VMASKALL', `
instruct vmaskAll$1(pReg dst, $2 src, vReg tmp, rFlagsReg cr) %{
  predicate(UseSVE > 0);
  match(Set dst (MaskAll src));
  effect(TEMP tmp, KILL cr);
  format %{ "vmaskAll$1 $dst, $src\t# KILL $tmp, cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_dup($tmp$$FloatRegister, size, $src$$Register);
    __ sve_cmp(Assembler::NE, $dst$$PRegister, size, ptrue, $tmp$$FloatRegister, 0);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
dnl VMASKALL_PREDICATE($1,   $2      )
dnl VMASKALL_PREDICATE(type, arg_type)
define(`VMASKALL_PREDICATE', `
instruct vmaskAll$1_masked(pReg dst, $2 src, pRegGov pg, vReg tmp, rFlagsReg cr) %{
  predicate(UseSVE > 0);
  match(Set dst (MaskAll src pg));
  effect(TEMP tmp, KILL cr);
  format %{ "vmaskAll$1_masked $dst, $pg, $src\t# KILL $tmp, cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
    __ sve_dup($tmp$$FloatRegister, size, $src$$Register);
    __ sve_cmp(Assembler::NE, $dst$$PRegister, size,
               $pg$$PRegister, $tmp$$FloatRegister, 0);
  %}
  ins_pipe(pipe_slow);
%}')dnl
dnl
VMASKALL_IMM(I, int)
VMASKALL(I, iRegIorL2I)
VMASKALL_PREDICATE(I, iRegIorL2I)
VMASKALL_IMM(L, long)
VMASKALL(L, iRegL)
VMASKALL_PREDICATE(L, iRegL)

// vetcor mask generation

instruct vmask_gen_I(pReg pd, iRegIorL2I src, rFlagsReg cr) %{
  predicate(UseSVE > 0);
  match(Set pd (VectorMaskGen (ConvI2L src)));
  effect(KILL cr);
  format %{ "vmask_gen_I $pd, $src\t# KILL cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_whilelow($pd$$PRegister, __ elemType_to_regVariant(bt), zr, $src$$Register);
  %}
  ins_pipe(pipe_class_default);
%}

instruct vmask_gen_L(pReg pd, iRegL src, rFlagsReg cr) %{
  predicate(UseSVE > 0);
  match(Set pd (VectorMaskGen src));
  effect(KILL cr);
  format %{ "vmask_gen_L $pd, $src\t# KILL cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_whilelo($pd$$PRegister, __ elemType_to_regVariant(bt), zr, $src$$Register);
  %}
  ins_pipe(pipe_slow);
%}

instruct vmask_gen_imm(pReg pd, immL con, rFlagsReg cr) %{
  predicate(UseSVE > 0);
  match(Set pd (VectorMaskGen con));
  effect(KILL cr);
  format %{ "vmask_gen_imm $pd, $con\t# KILL cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_gen_mask_imm($pd$$PRegister, bt, (uint)($con$$constant));
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Popcount vector ------------------------------

// vector popcount - INT

instruct vpopcountI(vReg dst, vReg src) %{
  match(Set dst (PopCountVI src));
  format %{ "vpopcountI $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (bt == T_BYTE) {
      if (VM_Version::use_neon_for_vector(length_in_bytes)) {
        __ cnt($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
               $src$$FloatRegister);
      } else {
        assert(UseSVE > 0, "must be sve");
        __ sve_cnt($dst$$FloatRegister, __ B, ptrue, $src$$FloatRegister);
      }
    } else {
      assert(bt == T_SHORT || bt == T_INT, "unsupported");
      if (UseSVE == 0) {
        assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
        __ cnt($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
               $src$$FloatRegister);
        __ uaddlp($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
                  $dst$$FloatRegister);
        if (bt == T_INT) {
          __ uaddlp($dst$$FloatRegister, length_in_bytes == 16 ? __ T8H : __ T4H,
                    $dst$$FloatRegister);
        }
      } else {
        __ sve_cnt($dst$$FloatRegister, __ elemType_to_regVariant(bt),
                   ptrue, $src$$FloatRegister);
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

// vector popcount - LONG

instruct vpopcountL(vReg dst, vReg src) %{
  match(Set dst (PopCountVL src));
  format %{ "vpopcountL $dst, $src" %}
  ins_encode %{
    if (UseSVE == 0) {
      __ cnt($dst$$FloatRegister, __ T16B, $src$$FloatRegister);
      __ uaddlp($dst$$FloatRegister, __ T16B, $dst$$FloatRegister);
      __ uaddlp($dst$$FloatRegister, __ T8H, $dst$$FloatRegister);
      __ uaddlp($dst$$FloatRegister, __ T4S, $dst$$FloatRegister);
    } else {
      __ sve_cnt($dst$$FloatRegister, __ D, ptrue, $src$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}

// vector popcount - predicated
UNARY_OP_PREDICATE(vpopcountI, PopCountVI, sve_cnt)

instruct vpopcountL_masked(vReg dst_src, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src (PopCountVL dst_src pg));
  format %{ "vpopcountL_masked $dst_src, $pg, $dst_src" %}
  ins_encode %{
    __ sve_cnt($dst_src$$FloatRegister, __ D,
               $pg$$PRegister, $dst_src$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector blend ---------------------------------

instruct vblend_neon(vReg dst, vReg src1, vReg src2) %{
  predicate(UseSVE == 0);
  match(Set dst (VectorBlend (Binary src1 src2) dst));
  format %{ "vblend_neon $dst, $src1, $src2" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
    __ bsl($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
           $src2$$FloatRegister, $src1$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vblend_sve(vReg dst, vReg src1, vReg src2, pReg pg) %{
  predicate(UseSVE > 0);
  match(Set dst (VectorBlend (Binary src1 src2) pg));
  format %{ "vblend_sve $dst, $pg, $src1, $src2" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_sel($dst$$FloatRegister, __ elemType_to_regVariant(bt),
               $pg$$PRegister, $src2$$FloatRegister, $src1$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------- Vector conditional move --------------------------

instruct vcmove_neon(vReg dst, vReg src1, vReg src2, immI cond, cmpOp copnd) %{
  predicate(UseSVE == 0 ||
            (VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)) &&
             n->in(1)->in(2)->get_int() != BoolTest::ne));
  match(Set dst (CMoveVF (Binary copnd cond) (Binary src1 src2)));
  match(Set dst (CMoveVD (Binary copnd cond) (Binary src1 src2)));
  effect(TEMP_DEF dst);
  format %{ "vcmove_neon.$copnd $dst, $src1, $src2\t# vector conditional move fp" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
    __ neon_compare($dst$$FloatRegister, bt, $src1$$FloatRegister,
                    $src2$$FloatRegister, (int)($cond$$constant),
                    /* isQ */ length_in_bytes == 16);
    __ bsl($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
           $src2$$FloatRegister, $src1$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcmove_sve(vReg dst, vReg src1, vReg src2, immI cond, cmpOp copnd, pRegGov pgtmp) %{
  predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n)) ||
            (UseSVE > 0 && n->in(1)->in(2)->get_int() == BoolTest::ne));
  match(Set dst (CMoveVF (Binary copnd cond) (Binary src1 src2)));
  match(Set dst (CMoveVD (Binary copnd cond) (Binary src1 src2)));
  effect(TEMP pgtmp);
  format %{ "vcmove_sve.$copnd $dst, $src1, $src2\t# vector conditional move fp. KILL $pgtmp" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    __ sve_compare($pgtmp$$PRegister, bt, ptrue, $src1$$FloatRegister,
                   $src2$$FloatRegister, (int)($cond$$constant));
    __ sve_sel($dst$$FloatRegister, __ elemType_to_regVariant(bt),
               $pgtmp$$PRegister, $src2$$FloatRegister, $src1$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector round ---------------------------------

// vector Math.round

instruct vround_le128b(vReg dst, vReg src, vReg tmp1, vReg tmp2,
                       vReg tmp3, rFlagsReg cr) %{
  predicate(Matcher::vector_length_in_bytes(n) <= 16);
  match(Set dst (RoundVF src));
  match(Set dst (RoundVD src));
  effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
  format %{ "vround_le128b $dst, $src\t# vector <= 128 bits. KILL $tmp1, $tmp2, $tmp3, cr" %}
  ins_encode %{
    __ vector_round_neon($dst$$FloatRegister, $src$$FloatRegister,
                         $tmp1$$FloatRegister, $tmp2$$FloatRegister,
                         $tmp3$$FloatRegister, get_arrangement(this));
  %}
  ins_pipe(pipe_slow);
%}

instruct vround_gt128b(vReg dst, vReg src, vReg tmp1, vReg tmp2,
                       pRegGov pgtmp, rFlagsReg cr) %{
  predicate(Matcher::vector_length_in_bytes(n) > 16);
  match(Set dst (RoundVF src));
  match(Set dst (RoundVD src));
  effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, TEMP pgtmp, KILL cr);
  format %{ "vround_gt128b $dst, $src\t# vector > 128 bits. KILL $tmp1, $tmp2, $pgtmp, cr" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ vector_round_sve($dst$$FloatRegister, $src$$FloatRegister,
                        $tmp1$$FloatRegister, $tmp2$$FloatRegister,
                        $pgtmp$$PRegister, __ elemType_to_regVariant(bt));
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ RoundDouble ----------------------------------

// vector Math.rint, floor, ceil

instruct vroundD(vReg dst, vReg src, immI rmode) %{
  predicate(Matcher::vector_element_basic_type(n) == T_DOUBLE);
  match(Set dst (RoundDoubleModeV src rmode));
  format %{ "vroundD $dst, $src, $rmode" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      switch ($rmode$$constant) {
        case RoundDoubleModeNode::rmode_rint:
          __ frintn($dst$$FloatRegister, __ T2D, $src$$FloatRegister);
          break;
        case RoundDoubleModeNode::rmode_floor:
          __ frintm($dst$$FloatRegister, __ T2D, $src$$FloatRegister);
          break;
        case RoundDoubleModeNode::rmode_ceil:
          __ frintp($dst$$FloatRegister, __ T2D, $src$$FloatRegister);
          break;
        default:
          assert(false, "unsupported");
          ShouldNotReachHere();
      }
    } else {
      assert(UseSVE > 0, "must be sve");
      switch ($rmode$$constant) {
        case RoundDoubleModeNode::rmode_rint:
          __ sve_frintn($dst$$FloatRegister, __ D, ptrue, $src$$FloatRegister);
          break;
        case RoundDoubleModeNode::rmode_floor:
          __ sve_frintm($dst$$FloatRegister, __ D, ptrue, $src$$FloatRegister);
          break;
        case RoundDoubleModeNode::rmode_ceil:
          __ sve_frintp($dst$$FloatRegister, __ D, ptrue, $src$$FloatRegister);
          break;
        default:
          assert(false, "unsupported");
          ShouldNotReachHere();
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ VectorTest -----------------------------------

// anytrue

instruct vtest_anytrue_neon(iRegINoSp dst, vReg src1, vReg src2, vReg tmp, rFlagsReg cr) %{
  predicate(UseSVE == 0 &&
            static_cast<const VectorTestNode*>(n)->get_predicate() == BoolTest::ne);
  match(Set dst (VectorTest src1 src2 ));
  effect(TEMP tmp, KILL cr);
  format %{ "vtest_anytrue_neon $dst, $src1\t# KILL $tmp, cr" %}
  ins_encode %{
    // No need to use src2.
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src1);
    assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
    __ addv($tmp$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B, $src1$$FloatRegister);
    __ umov($dst$$Register, $tmp$$FloatRegister, __ B, 0);
    __ cmpw($dst$$Register, zr);
    __ csetw($dst$$Register, Assembler::NE);
  %}
  ins_pipe(pipe_slow);
%}

instruct vtest_anytrue_sve(iRegINoSp dst, pReg src1, pReg src2, rFlagsReg cr) %{
  predicate(UseSVE > 0 &&
            static_cast<const VectorTestNode*>(n)->get_predicate() == BoolTest::ne);
  match(Set dst (VectorTest src1 src2));
  effect(KILL cr);
  format %{ "vtest_anytrue_sve $dst, $src1\t# KILL cr" %}
  ins_encode %{
    // "src2" is not used for sve.
    __ sve_ptest(ptrue, $src1$$PRegister);
    __ csetw($dst$$Register, Assembler::NE);
  %}
  ins_pipe(pipe_slow);
%}

// alltrue

instruct vtest_alltrue_neon(iRegINoSp dst, vReg src1, vReg src2, vReg tmp, rFlagsReg cr) %{
  predicate(UseSVE == 0 &&
            static_cast<const VectorTestNode*>(n)->get_predicate() == BoolTest::overflow);
  match(Set dst (VectorTest src1 src2));
  effect(TEMP tmp, KILL cr);
  format %{ "vtest_alltrue_neon $dst, $src1\t# KILL $tmp, cr" %}
  ins_encode %{
    // No need to use src2.
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src1);
    assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
    __ uminv($tmp$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B, $src1$$FloatRegister);
    __ umov($dst$$Register, $tmp$$FloatRegister, __ B, 0);
    __ cmpw($dst$$Register, 0xff);
    __ csetw($dst$$Register, Assembler::EQ);
  %}
  ins_pipe(pipe_slow);
%}

instruct vtest_alltrue_sve(iRegINoSp dst, pReg src1, pReg src2, pReg ptmp, rFlagsReg cr) %{
  predicate(UseSVE > 0 &&
            static_cast<const VectorTestNode*>(n)->get_predicate() == BoolTest::overflow);
  match(Set dst (VectorTest src1 src2));
  effect(TEMP ptmp, KILL cr);
  format %{ "vtest_alltrue_sve $dst, $src1, $src2\t# KILL $ptmp, cr" %}
  ins_encode %{
    __ sve_eors($ptmp$$PRegister, ptrue, $src1$$PRegister, $src2$$PRegister);
    __ csetw($dst$$Register, Assembler::EQ);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector shuffle -------------------------------

instruct loadshuffle(vReg dst, vReg src) %{
  match(Set dst (VectorLoadShuffle src));
  format %{ "loadshuffle $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (bt == T_BYTE) {
      if ($dst$$FloatRegister != $src$$FloatRegister) {
        if (VM_Version::use_neon_for_vector(length_in_bytes)) {
          __ orr($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
                 $src$$FloatRegister, $src$$FloatRegister);
        } else {
          assert(UseSVE > 0, "must be sve");
          __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister);
        }
      }
    } else {
      if (VM_Version::use_neon_for_vector(length_in_bytes)) {
        // 4S/8S, 4I, 4F
        __ uxtl($dst$$FloatRegister, __ T8H, $src$$FloatRegister, __ T8B);
        if (type2aelembytes(bt) == 4) {
          __ uxtl($dst$$FloatRegister, __ T4S, $dst$$FloatRegister, __ T4H);
        }
      } else {
        assert(UseSVE > 0, "must be sve");
        __ sve_vector_extend($dst$$FloatRegister,  __ elemType_to_regVariant(bt),
                             $src$$FloatRegister, __ B);
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector rearrange -----------------------------

// Here is an example that rearranges a NEON vector with 4 ints:
// Rearrange V1 int[a0, a1, a2, a3] to V2 int[a2, a3, a0, a1]
//   1. Get the indices of V1 and store them as Vi byte[0, 1, 2, 3].
//   2. Convert Vi byte[0, 1, 2, 3] to the indices of V2 and also store them as Vi byte[2, 3, 0, 1].
//   3. Unsigned extend Long Vi from byte[2, 3, 0, 1] to int[2, 3, 0, 1].
//   4. Multiply Vi int[2, 3, 0, 1] with constant int[0x04040404, 0x04040404, 0x04040404, 0x04040404]
//      and get tbl base Vm int[0x08080808, 0x0c0c0c0c, 0x00000000, 0x04040404].
//   5. Add Vm with constant int[0x03020100, 0x03020100, 0x03020100, 0x03020100]
//      and get tbl index Vm int[0x0b0a0908, 0x0f0e0d0c, 0x03020100, 0x07060504]
//   6. Use Vm as index register, and use V1 as table register.
//      Then get V2 as the result by tbl NEON instructions.
// Notes:
//   Step 1 matches VectorLoadConst.
//   Step 3 matches VectorLoadShuffle.
//   Step 4, 5, 6 match VectorRearrange.
//   For VectorRearrange short/int, the reason why such complex calculation is
//   required is because NEON tbl supports bytes table only, so for short/int, we
//   need to lookup 2/4 bytes as a group. For VectorRearrange long, we use bsl
//   to implement rearrange.

instruct rearrange_HS_neon(vReg dst, vReg src, vReg shuffle, vReg tmp1, vReg tmp2) %{
  predicate(UseSVE == 0 &&
            (Matcher::vector_element_basic_type(n) == T_SHORT ||
             (type2aelembytes(Matcher::vector_element_basic_type(n)) == 4 &&
              Matcher::vector_length_in_bytes(n) == 16)));
  match(Set dst (VectorRearrange src shuffle));
  effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2);
  format %{ "rearrange_HS_neon $dst, $src, $shuffle\t# vector (4S/8S/4I/4F). KILL $tmp1, $tmp2" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    if (bt == T_SHORT) {
      uint length_in_bytes = Matcher::vector_length_in_bytes(this);
      assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
      Assembler::SIMD_Arrangement size1 = length_in_bytes == 16 ? __ T16B : __ T8B;
      Assembler::SIMD_Arrangement size2 = length_in_bytes == 16 ? __ T8H : __ T4H;
      __ mov($tmp1$$FloatRegister, size1, 0x02);
      __ mov($tmp2$$FloatRegister, size2, 0x0100);
      __ mulv($dst$$FloatRegister, size2, $shuffle$$FloatRegister, $tmp1$$FloatRegister);
      __ addv($dst$$FloatRegister, size1, $dst$$FloatRegister, $tmp2$$FloatRegister);
      __ tbl($dst$$FloatRegister, size1, $src$$FloatRegister, 1, $dst$$FloatRegister);
    } else {
      assert(bt == T_INT || bt == T_FLOAT, "unsupported type");
      __ mov($tmp1$$FloatRegister, __ T16B, 0x04);
      __ mov($tmp2$$FloatRegister, __ T4S, 0x03020100);
      __ mulv($dst$$FloatRegister, __ T4S, $shuffle$$FloatRegister, $tmp1$$FloatRegister);
      __ addv($dst$$FloatRegister, __ T16B, $dst$$FloatRegister, $tmp2$$FloatRegister);
      __ tbl($dst$$FloatRegister, __ T16B, $src$$FloatRegister, 1, $dst$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}

instruct rearrange(vReg dst, vReg src, vReg shuffle) %{
  predicate(Matcher::vector_element_basic_type(n) == T_BYTE || UseSVE > 0);
  match(Set dst (VectorRearrange src shuffle));
  format %{ "rearrange $dst, $src, $shuffle" %}
  ins_encode %{
    BasicType bt_dst = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (bt_dst == T_BYTE && VM_Version::use_neon_for_vector(length_in_bytes)) {
      __ tbl($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
             $src$$FloatRegister, 1, $shuffle$$FloatRegister);
    } else {
      assert(UseSVE > 0, "must be sve");
      BasicType bt_src = Matcher::vector_element_basic_type(this, $src);
      __ sve_tbl($dst$$FloatRegister, __ elemType_to_regVariant(bt_src),
                 $src$$FloatRegister, $shuffle$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector Load Gather ---------------------------

instruct gather_loadS(vReg dst, indirect mem, vReg idx) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n)) == 4);
  match(Set dst (LoadVectorGather mem idx));
  format %{ "gather_loadS $dst, $mem, $idx\t# vector (sve)" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_ld1w_gather($dst$$FloatRegister, ptrue,
                       as_Register($mem$$base), $idx$$FloatRegister);
 %}
  ins_pipe(pipe_slow);
%}

instruct gather_loadD(vReg dst, indirect mem, vReg idx, vReg tmp) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n)) == 8);
  match(Set dst (LoadVectorGather mem idx));
  effect(TEMP tmp);
  format %{ "gather_loadD $dst, $mem, $idx\t# vector (sve). KILL $tmp" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_uunpklo($tmp$$FloatRegister, __ D, $idx$$FloatRegister);
    __ sve_ld1d_gather($dst$$FloatRegister, ptrue, as_Register($mem$$base),
                       $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct gather_loadS_masked(vReg dst, indirect mem, vReg idx, pRegGov pg) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n)) == 4);
  match(Set dst (LoadVectorGatherMasked mem (Binary idx pg)));
  format %{ "gather_loadS_masked $dst, $pg, $mem, $idx" %}
  ins_encode %{
    __ sve_ld1w_gather($dst$$FloatRegister, $pg$$PRegister,
                       as_Register($mem$$base), $idx$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct gather_loadD_masked(vReg dst, indirect mem, vReg idx, pRegGov pg, vReg tmp) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n)) == 8);
  match(Set dst (LoadVectorGatherMasked mem (Binary idx pg)));
  effect(TEMP tmp);
  format %{ "gather_loadD_masked $dst, $pg, $mem, $idx\t# KILL $tmp" %}
  ins_encode %{
    __ sve_uunpklo($tmp$$FloatRegister, __ D, $idx$$FloatRegister);
    __ sve_ld1d_gather($dst$$FloatRegister, $pg$$PRegister,
                       as_Register($mem$$base), $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector Store Scatter -------------------------

instruct scatter_storeS(indirect mem, vReg src, vReg idx) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 4);
  match(Set mem (StoreVectorScatter mem (Binary src idx)));
  format %{ "scatter_storeS $mem, $idx, $src\t# vector (sve)" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_st1w_scatter($src$$FloatRegister, ptrue,
                        as_Register($mem$$base), $idx$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct scatter_storeD(indirect mem, vReg src, vReg idx, vReg tmp) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 8);
  match(Set mem (StoreVectorScatter mem (Binary src idx)));
  effect(TEMP tmp);
  format %{ "scatter_storeD $mem, $idx, $src\t# vector (sve). KILL $tmp" %}
  ins_encode %{
    uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
    assert(length_in_bytes == MaxVectorSize, "invalid vector length");
    __ sve_uunpklo($tmp$$FloatRegister, __ D, $idx$$FloatRegister);
    __ sve_st1d_scatter($src$$FloatRegister, ptrue,
                        as_Register($mem$$base), $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct scatter_storeS_masked(indirect mem, vReg src, vReg idx, pRegGov pg) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 4);
  match(Set mem (StoreVectorScatterMasked mem (Binary src (Binary idx pg))));
  format %{ "scatter_storeS_masked $mem, $pg, $idx, $src" %}
  ins_encode %{
    __ sve_st1w_scatter($src$$FloatRegister, $pg$$PRegister,
                        as_Register($mem$$base), $idx$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct scatter_storeD_masked(indirect mem, vReg src, vReg idx, pRegGov pg, vReg tmp) %{
  predicate(UseSVE > 0 &&
            type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 8);
  match(Set mem (StoreVectorScatterMasked mem (Binary src (Binary idx pg))));
  effect(TEMP tmp);
  format %{ "scatter_storeD_masked $mem, $pg, $idx, $src\t# KILL $tmp" %}
  ins_encode %{
    __ sve_uunpklo($tmp$$FloatRegister, __ D, $idx$$FloatRegister);
    __ sve_st1d_scatter($src$$FloatRegister, $pg$$PRegister,
                        as_Register($mem$$base), $tmp$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ CountLeadingZerosV ---------------------------

instruct vcountLeadingZeros(vReg dst, vReg src) %{
  match(Set dst (CountLeadingZerosV src));
  format %{ "vcountLeadingZeros $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (bt == T_LONG) {
      if (UseSVE == 0) {
        __ umov(rscratch1, $src$$FloatRegister, __ D, 0);
        __ clz(rscratch1, rscratch1);
        __ mov($dst$$FloatRegister, __ D, 0, rscratch1);
        __ umov(rscratch1, $src$$FloatRegister, __ D, 1);
        __ clz(rscratch1, rscratch1);
        __ mov($dst$$FloatRegister, __ D, 1, rscratch1);
      } else {
        __ sve_clz($dst$$FloatRegister, __ D, ptrue, $src$$FloatRegister);
      }
    } else {
      if (VM_Version::use_neon_for_vector(length_in_bytes)) {
        __ clz($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister);
      } else {
        assert(UseSVE > 0, "must be sve");
        __ sve_clz($dst$$FloatRegister, __ elemType_to_regVariant(bt),
                   ptrue, $src$$FloatRegister);
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

// The dst and src should use the same register to make sure the
// inactive lanes in dst save the same elements as src.
UNARY_OP_PREDICATE(vcountLeadingZeros, CountLeadingZerosV, sve_clz)

// ------------------------------ CountTrailingZerosV --------------------------

instruct vcountTrailingZeros(vReg dst, vReg src) %{
  match(Set dst (CountTrailingZerosV src));
  format %{ "vcountTrailingZeros $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (bt == T_BYTE) {
      if (VM_Version::use_neon_for_vector(length_in_bytes)) {
        __ rbit($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
                $src$$FloatRegister);
        __ clz($dst$$FloatRegister, get_arrangement(this), $dst$$FloatRegister);
      } else {
        assert(UseSVE > 0, "must be sve");
        __ sve_rbit($dst$$FloatRegister, __ B, ptrue, $src$$FloatRegister);
        __ sve_clz($dst$$FloatRegister, __ B, ptrue, $dst$$FloatRegister);
      }
    } else {
      assert(bt == T_SHORT || bt == T_INT || bt == T_LONG, "unsupported type");
      if (UseSVE == 0) {
        assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
        __ neon_reverse_bits($dst$$FloatRegister, $src$$FloatRegister,
                             bt, /* isQ */ length_in_bytes == 16);
        if (bt != T_LONG) {
          __ clz($dst$$FloatRegister, get_arrangement(this), $dst$$FloatRegister);
        } else {
          __ umov(rscratch1, $dst$$FloatRegister, __ D, 0);
          __ clz(rscratch1, rscratch1);
          __ mov($dst$$FloatRegister, __ D, 0, rscratch1);
          __ umov(rscratch1, $dst$$FloatRegister, __ D, 1);
          __ clz(rscratch1, rscratch1);
          __ mov($dst$$FloatRegister, __ D, 1, rscratch1);
        }
      } else {
        Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
        __ sve_rbit($dst$$FloatRegister, size, ptrue, $src$$FloatRegister);
        __ sve_clz($dst$$FloatRegister, size, ptrue, $dst$$FloatRegister);
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

// The dst and src should use the same register to make sure the
// inactive lanes in dst save the same elements as src.
instruct vcountTrailingZeros_masked(vReg dst_src, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src (CountTrailingZerosV dst_src pg));
  format %{ "vcountTrailingZeros_masked $dst_src, $pg, $dst_src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
    __ sve_rbit($dst_src$$FloatRegister, size,
                $pg$$PRegister, $dst_src$$FloatRegister);
    __ sve_clz($dst_src$$FloatRegister, size,
               $pg$$PRegister, $dst_src$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ ReverseV -------------------------------------

instruct vreverse(vReg dst, vReg src) %{
  match(Set dst (ReverseV src));
  format %{ "vreverse $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (bt == T_BYTE) {
      if (VM_Version::use_neon_for_vector(length_in_bytes)) {
        __ rbit($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
                $src$$FloatRegister);
      } else {
        assert(UseSVE > 0, "must be sve");
        __ sve_rbit($dst$$FloatRegister, __ B, ptrue, $src$$FloatRegister);
      }
    } else {
      assert(bt == T_SHORT || bt == T_INT || bt == T_LONG, "unsupported type");
      if (UseSVE == 0) {
        assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
        __ neon_reverse_bits($dst$$FloatRegister, $src$$FloatRegister,
                             bt, /* isQ */ length_in_bytes == 16);
      } else {
        __ sve_rbit($dst$$FloatRegister, __ elemType_to_regVariant(bt),
                    ptrue, $src$$FloatRegister);
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

// The dst and src should use the same register to make sure the
// inactive lanes in dst save the same elements as src.
UNARY_OP_PREDICATE(vreverse, ReverseV, sve_rbit)

// ------------------------------ ReverseBytesV --------------------------------

instruct vreverseBytes(vReg dst, vReg src) %{
  match(Set dst (ReverseBytesV src));
  format %{ "vreverseBytes $dst, $src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    uint length_in_bytes = Matcher::vector_length_in_bytes(this);
    if (VM_Version::use_neon_for_vector(length_in_bytes)) {
      assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
      if (bt == T_BYTE) {
        if ($dst$$FloatRegister != $src$$FloatRegister) {
          __ orr($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
                 $src$$FloatRegister, $src$$FloatRegister);
        }
      } else {
        __ neon_reverse_bytes($dst$$FloatRegister, $src$$FloatRegister,
                              bt, /* isQ */ length_in_bytes == 16);
      }
    } else {
      assert(UseSVE > 0, "must be sve");
      if (bt == T_BYTE) {
        if ($dst$$FloatRegister != $src$$FloatRegister) {
          __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister);
        }
      } else {
        __ sve_revb($dst$$FloatRegister, __ elemType_to_regVariant(bt),
                    ptrue, $src$$FloatRegister);
      }
    }
  %}
  ins_pipe(pipe_slow);
%}

// The dst and src should use the same register to make sure the
// inactive lanes in dst save the same elements as src.
instruct vreverseBytes_masked(vReg dst_src, pRegGov pg) %{
  predicate(UseSVE > 0);
  match(Set dst_src (ReverseBytesV dst_src pg));
  format %{ "vreverseBytes_masked $dst_src, $pg, $dst_src" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    if (bt == T_BYTE) {
      // do nothing
    } else {
      __ sve_revb($dst_src$$FloatRegister, __ elemType_to_regVariant(bt),
                  $pg$$PRegister, $dst_src$$FloatRegister);
    }
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Populate Index to a Vector -------------------

instruct populateindex(vReg dst, iRegIorL2I src1, immI src2) %{
  predicate(UseSVE > 0);
  match(Set dst (PopulateIndex src1 src2));
  format %{ "populateindex $dst, $src1, $src2\t # populate index (sve)" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_index($dst$$FloatRegister, __ elemType_to_regVariant(bt),
                 $src1$$Register, (int)($src2$$constant));
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Compress/Expand Operations -------------------

instruct mcompress(pReg dst, pReg pg, rFlagsReg cr) %{
  predicate(UseSVE > 0);
  match(Set dst (CompressM pg));
  effect(KILL cr);
  format %{ "mcompress $dst, $pg\t# KILL cr" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
    __ sve_cntp(rscratch1, size, ptrue, $pg$$PRegister);
    __ sve_whilelo(as_PRegister($dst$$reg), size, zr, rscratch1);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcompress(vReg dst, vReg src, pRegGov pg) %{
  predicate(UseSVE > 0 &&
            !is_subword_type(Matcher::vector_element_basic_type(n)));
  match(Set dst (CompressV src pg));
  format %{ "vcompress $dst, $src, $pg" %}
  ins_encode %{
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ sve_compact($dst$$FloatRegister, __ elemType_to_regVariant(bt),
                   $src$$FloatRegister, $pg$$PRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcompressB(vReg dst, vReg src, pReg pg, vReg tmp1, vReg tmp2,
                    vReg tmp3, vReg tmp4, pReg ptmp, pRegGov pgtmp) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_BYTE);
  effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP ptmp, TEMP pgtmp);
  match(Set dst (CompressV src pg));
  format %{ "vcompressB $dst, $src, $pg\t# KILL $tmp1, $tmp2, $tmp3, tmp4, $ptmp, $pgtmp" %}
  ins_encode %{
    __ sve_compress_byte($dst$$FloatRegister, $src$$FloatRegister, $pg$$PRegister,
                         $tmp1$$FloatRegister,$tmp2$$FloatRegister,
                         $tmp3$$FloatRegister,$tmp4$$FloatRegister,
                         $ptmp$$PRegister, $pgtmp$$PRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vcompressS(vReg dst, vReg src, pReg pg,
                    vReg tmp1, vReg tmp2, pRegGov pgtmp) %{
  predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_SHORT);
  effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, TEMP pgtmp);
  match(Set dst (CompressV src pg));
  format %{ "vcompressS $dst, $src, $pg\t# KILL $tmp1, $tmp2, $pgtmp" %}
  ins_encode %{
    __ sve_compress_short($dst$$FloatRegister, $src$$FloatRegister, $pg$$PRegister,
                          $tmp1$$FloatRegister,$tmp2$$FloatRegister, $pgtmp$$PRegister);
  %}
  ins_pipe(pipe_slow);
%}

instruct vexpand(vReg dst, vReg src, pRegGov pg) %{
  match(Set dst (ExpandV src pg));
  effect(TEMP_DEF dst);
  format %{ "vexpand $dst, $pg, $src" %}
  ins_encode %{
    // Example input:   src   = 1 2 3 4 5 6 7 8
    //                  pg    = 1 0 0 1 1 0 1 1
    // Expected result: dst   = 4 0 0 5 6 0 7 8

    // The basic idea is to use TBL which can shuffle the elements in the given
    // vector flexibly. HISTCNT + SUB is used to generate the second source input
    // for TBL whose value is used to select the indexed element from src vector.

    BasicType bt = Matcher::vector_element_basic_type(this);
    assert(UseSVE == 2 && !is_subword_type(bt), "unsupported");
    Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt);
    // dst = 0 0 0 0 0 0 0 0
    __ sve_dup($dst$$FloatRegister, size, 0);
    // dst = 5 0 0 4 3 0 2 1
    __ sve_histcnt($dst$$FloatRegister, size, $pg$$PRegister,
                   $dst$$FloatRegister, $dst$$FloatRegister);
    // dst = 4 -1 -1 3 2 -1 1 0
    __ sve_sub($dst$$FloatRegister, size, 1);
    // dst = 4 0 0 5 6 0 7 8
    __ sve_tbl($dst$$FloatRegister, size, $src$$FloatRegister, $dst$$FloatRegister);
  %}
  ins_pipe(pipe_slow);
%}

// ------------------------------ Vector signum --------------------------------

// Vector Math.signum

instruct vsignum_le128b(vReg dst, vReg src, vReg zero, vReg one) %{
  predicate(Matcher::vector_length_in_bytes(n) <= 16);
  match(Set dst (SignumVF src (Binary zero one)));
  match(Set dst (SignumVD src (Binary zero one)));
  effect(TEMP_DEF dst);
  format %{ "vsignum_le128b $dst, $src\t# vector <= 128 bits" %}
  ins_encode %{
    __ vector_signum_neon($dst$$FloatRegister, $src$$FloatRegister, $zero$$FloatRegister,
                          $one$$FloatRegister, get_arrangement(this));
  %}
  ins_pipe(pipe_slow);
%}

instruct vsignum_gt128b(vReg dst, vReg src, vReg zero, vReg one, vReg tmp, pRegGov pgtmp) %{
  predicate(Matcher::vector_length_in_bytes(n) > 16);
  match(Set dst (SignumVF src (Binary zero one)));
  match(Set dst (SignumVD src (Binary zero one)));
  effect(TEMP_DEF dst, TEMP tmp, TEMP pgtmp);
  format %{ "vsignum_gt128b $dst, $src\t# vector > 128 bits. KILL $tmp, $pgtmp" %}
  ins_encode %{
    assert(UseSVE > 0, "must be sve");
    BasicType bt = Matcher::vector_element_basic_type(this);
    __ vector_signum_sve($dst$$FloatRegister, $src$$FloatRegister, $zero$$FloatRegister,
                         $one$$FloatRegister, $tmp$$FloatRegister, $pgtmp$$PRegister,
                         __ elemType_to_regVariant(bt));
  %}
  ins_pipe(pipe_slow);
%}

Messung V0.5 in Prozent
C=95 H=87 G=90

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.101Angebot  (Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-27) ¤

*Eine klare Vorstellung vom Zielzustand






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


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