8387594: AArch64: Support vector integer division for SVE

Reviewed-by: aph, xgong
This commit is contained in:
Eric Fang 2026-07-22 03:32:07 +00:00 committed by Dingli Zhang
parent 70868ac528
commit 694cebaadc
15 changed files with 746 additions and 139 deletions

View File

@ -324,6 +324,17 @@ source %{
return false;
}
break;
case Op_DivVB:
case Op_DivVS:
case Op_DivVI:
case Op_DivVL:
// Integer vector divide is only available on SVE (SDIV for 32-bit and
// 64-bit elements). NEON has no integer vector divide instruction.
// BYTE/SHORT are widened to 32-bit, divided, and narrowed back.
if (UseSVE == 0) {
return false;
}
break;
default:
break;
}
@ -348,6 +359,11 @@ source %{
case Op_CompressBitsV:
case Op_ExpandBitsV:
case Op_VectorBitwiseBlend:
// There is no native SVE divide for BYTE/SHORT elements (these are
// emulated by widening to 32-bit), so the masked variants are handled
// by an unpredicated divide combined with a VectorBlend.
case Op_DivVB:
case Op_DivVS:
return false;
case Op_SaturatingAddV:
case Op_SaturatingSubV:
@ -1477,6 +1493,83 @@ instruct vdivD_masked(vReg dst_src1, vReg src2, pRegGov pg) %{
ins_pipe(pipe_slow);
%}
// ------------------------------ Vector integer div ---------------------------
// BYTE and SHORT have no native integer divide on SVE (SDIV only supports 32-bit
// and 64-bit elements), so they are emulated by widening each element to 32-bit,
// performing SDIV, and narrowing the result back.
instruct vdivB_sve(vReg dst_src1, vReg src2, vReg vtmp1, vReg vtmp2, vReg vtmp3, vReg vtmp4) %{
predicate(UseSVE > 0);
match(Set dst_src1 (DivVB dst_src1 src2));
effect(TEMP_DEF dst_src1, TEMP vtmp1, TEMP vtmp2, TEMP vtmp3, TEMP vtmp4);
format %{ "vdivB_sve $dst_src1, $dst_src1, $src2" %}
ins_encode %{
__ sve_sdiv_byte($dst_src1$$FloatRegister, $src2$$FloatRegister,
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister,
$vtmp3$$FloatRegister, $vtmp4$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
instruct vdivS_sve(vReg dst_src1, vReg src2, vReg vtmp1, vReg vtmp2) %{
predicate(UseSVE > 0);
match(Set dst_src1 (DivVS dst_src1 src2));
effect(TEMP_DEF dst_src1, TEMP vtmp1, TEMP vtmp2);
format %{ "vdivS_sve $dst_src1, $dst_src1, $src2" %}
ins_encode %{
__ sve_sdiv_short($dst_src1$$FloatRegister, $src2$$FloatRegister,
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
instruct vdivI_sve(vReg dst_src1, vReg src2) %{
predicate(UseSVE > 0);
match(Set dst_src1 (DivVI dst_src1 src2));
format %{ "vdivI_sve $dst_src1, $dst_src1, $src2" %}
ins_encode %{
__ sve_sdiv($dst_src1$$FloatRegister, __ S, ptrue, $src2$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
instruct vdivL_sve(vReg dst_src1, vReg src2) %{
predicate(UseSVE > 0);
match(Set dst_src1 (DivVL dst_src1 src2));
format %{ "vdivL_sve $dst_src1, $dst_src1, $src2" %}
ins_encode %{
__ sve_sdiv($dst_src1$$FloatRegister, __ D, ptrue, $src2$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
// Vector integer div - predicated
//
// There is no native SVE divide for BYTE/SHORT elements (these are emulated by
// widening to 32-bit), so the masked variants are handled by an unpredicated
// divide combined with a VectorBlend.
instruct vdivI_masked(vReg dst_src1, vReg src2, pRegGov pg) %{
predicate(UseSVE > 0);
match(Set dst_src1 (DivVI (Binary dst_src1 src2) pg));
format %{ "vdivI_masked $dst_src1, $pg, $dst_src1, $src2" %}
ins_encode %{
__ sve_sdiv($dst_src1$$FloatRegister, __ S, $pg$$PRegister, $src2$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
instruct vdivL_masked(vReg dst_src1, vReg src2, pRegGov pg) %{
predicate(UseSVE > 0);
match(Set dst_src1 (DivVL (Binary dst_src1 src2) pg));
format %{ "vdivL_masked $dst_src1, $pg, $dst_src1, $src2" %}
ins_encode %{
__ sve_sdiv($dst_src1$$FloatRegister, __ D, $pg$$PRegister, $src2$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
// ------------------------------ Vector and -----------------------------------
// vector and

View File

@ -314,6 +314,17 @@ source %{
return false;
}
break;
case Op_DivVB:
case Op_DivVS:
case Op_DivVI:
case Op_DivVL:
// Integer vector divide is only available on SVE (SDIV for 32-bit and
// 64-bit elements). NEON has no integer vector divide instruction.
// BYTE/SHORT are widened to 32-bit, divided, and narrowed back.
if (UseSVE == 0) {
return false;
}
break;
default:
break;
}
@ -338,6 +349,11 @@ source %{
case Op_CompressBitsV:
case Op_ExpandBitsV:
case Op_VectorBitwiseBlend:
// There is no native SVE divide for BYTE/SHORT elements (these are
// emulated by widening to 32-bit), so the masked variants are handled
// by an unpredicated divide combined with a VectorBlend.
case Op_DivVB:
case Op_DivVS:
return false;
case Op_SaturatingAddV:
case Op_SaturatingSubV:
@ -842,6 +858,61 @@ 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 BINARY_OP_SVE_ONLY($1, $2, $3, $4 )
dnl BINARY_OP_SVE_ONLY(rule_name, op_name, insn, size)
define(`BINARY_OP_SVE_ONLY', `
instruct $1_sve(vReg dst_src1, vReg src2) %{
predicate(UseSVE > 0);
match(Set dst_src1 ($2 dst_src1 src2));
format %{ "$1_sve $dst_src1, $dst_src1, $src2" %}
ins_encode %{
__ $3($dst_src1$$FloatRegister, __ $4, ptrue, $src2$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}')dnl
dnl
// ------------------------------ Vector integer div ---------------------------
// BYTE and SHORT have no native integer divide on SVE (SDIV only supports 32-bit
// and 64-bit elements), so they are emulated by widening each element to 32-bit,
// performing SDIV, and narrowing the result back.
instruct vdivB_sve(vReg dst_src1, vReg src2, vReg vtmp1, vReg vtmp2, vReg vtmp3, vReg vtmp4) %{
predicate(UseSVE > 0);
match(Set dst_src1 (DivVB dst_src1 src2));
effect(TEMP_DEF dst_src1, TEMP vtmp1, TEMP vtmp2, TEMP vtmp3, TEMP vtmp4);
format %{ "vdivB_sve $dst_src1, $dst_src1, $src2" %}
ins_encode %{
__ sve_sdiv_byte($dst_src1$$FloatRegister, $src2$$FloatRegister,
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister,
$vtmp3$$FloatRegister, $vtmp4$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
instruct vdivS_sve(vReg dst_src1, vReg src2, vReg vtmp1, vReg vtmp2) %{
predicate(UseSVE > 0);
match(Set dst_src1 (DivVS dst_src1 src2));
effect(TEMP_DEF dst_src1, TEMP vtmp1, TEMP vtmp2);
format %{ "vdivS_sve $dst_src1, $dst_src1, $src2" %}
ins_encode %{
__ sve_sdiv_short($dst_src1$$FloatRegister, $src2$$FloatRegister,
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
BINARY_OP_SVE_ONLY(vdivI, DivVI, sve_sdiv, S)
BINARY_OP_SVE_ONLY(vdivL, DivVL, sve_sdiv, D)
// Vector integer div - predicated
//
// There is no native SVE divide for BYTE/SHORT elements (these are emulated by
// widening to 32-bit), so the masked variants are handled by an unpredicated
// divide combined with a VectorBlend.
BINARY_OP_PREDICATE(vdivI, DivVI, sve_sdiv, S)
BINARY_OP_PREDICATE(vdivL, DivVL, sve_sdiv, D)
dnl
dnl BITWISE_OP_IMM($1, $2, $3, $4, $5, $6 )
dnl BITWISE_OP_IMM(rule_name, type, op_name, insn, size, basic_type)

View File

@ -3475,13 +3475,15 @@ private:
public:
// SVE integer arithmetic - predicate
// SVE Arithmetic - Predicated
#define INSN(NAME, op1, op2) \
void NAME(FloatRegister Zdn_or_Zd_or_Vd, SIMD_RegVariant T, PRegister Pg, FloatRegister Znm_or_Vn) { \
assert(T != Q, "invalid register variant"); \
assert(ALLOWED, "invalid register variant"); \
sve_predicate_reg_insn(op1, op2, Zdn_or_Zd_or_Vd, T, Pg, Znm_or_Vn); \
}
// SVE Integer Arithmetic - Predicated (B/H/S/D element sizes).
#define ALLOWED (T != Q)
INSN(sve_abs, 0b00000100, 0b010110101); // vector abs, unary
INSN(sve_add, 0b00000100, 0b000000000); // vector add
INSN(sve_and, 0b00000100, 0b011010000); // vector and
@ -3511,15 +3513,16 @@ public:
INSN(sve_umaxv, 0b00000100, 0b001001001); // unsigned maximum reduction to scalar
INSN(sve_umin, 0b00000100, 0b001011000); // unsigned minimum vectors
INSN(sve_uminv, 0b00000100, 0b001011001); // unsigned minimum reduction to scalar
#undef INSN
#undef ALLOWED
// SVE floating-point arithmetic - predicate
#define INSN(NAME, op1, op2) \
void NAME(FloatRegister Zd_or_Zdn_or_Vd, SIMD_RegVariant T, PRegister Pg, FloatRegister Zn_or_Zm) { \
assert(T == H || T == S || T == D, "invalid register variant"); \
sve_predicate_reg_insn(op1, op2, Zd_or_Zdn_or_Vd, T, Pg, Zn_or_Zm); \
}
// SVE Integer Binary Arithmetic - Predicated (S/D element sizes).
#define ALLOWED (T == S || T == D)
INSN(sve_sdiv, 0b00000100, 0b010100000); // signed divide
INSN(sve_udiv, 0b00000100, 0b010101000); // unsigned divide
#undef ALLOWED
// SVE Floating-point Arithmetic - Predicated (H/S/D element sizes).
#define ALLOWED (T == H || T == S || T == D)
INSN(sve_fabd, 0b01100101, 0b001000100); // floating-point absolute difference
INSN(sve_fabs, 0b00000100, 0b011100101);
INSN(sve_fadd, 0b01100101, 0b000000100);
@ -3537,9 +3540,18 @@ public:
INSN(sve_frintp, 0b01100101, 0b000001101); // floating-point round to integral value, toward plus infinity
INSN(sve_fsqrt, 0b01100101, 0b001101101);
INSN(sve_fsub, 0b01100101, 0b000001100);
#undef ALLOWED
// SVE2 Signed/Unsigned Saturating Add/Sub - Predicated (B/H/S/D element sizes).
#define ALLOWED (T != Q)
INSN(sve_sqadd, 0b01000100, 0b011000100); // signed saturating add
INSN(sve_sqsub, 0b01000100, 0b011010100); // signed saturating sub
INSN(sve_uqadd, 0b01000100, 0b011001100); // unsigned saturating add
INSN(sve_uqsub, 0b01000100, 0b011011100); // unsigned saturating sub
#undef ALLOWED
#undef INSN
// SVE multiple-add/sub - predicated
// SVE multiple-add/sub - predicated
#define INSN(NAME, op0, op1, op2) \
void NAME(FloatRegister Zda, SIMD_RegVariant T, PRegister Pg, FloatRegister Zn, FloatRegister Zm) { \
starti; \
@ -4347,20 +4359,6 @@ public:
INSN(sve_smullt, /* is_unsigned */ false, /* is_top */ true ); // Signed widening multiply of top elements
#undef INSN
// SVE2 saturating operations - predicate
#define INSN(NAME, op1, op2) \
void NAME(FloatRegister Zdn, SIMD_RegVariant T, PRegister Pg, FloatRegister Znm) { \
assert(T != Q, "invalid register variant"); \
sve_predicate_reg_insn(op1, op2, Zdn, T, Pg, Znm); \
}
INSN(sve_sqadd, 0b01000100, 0b011000100); // signed saturating add
INSN(sve_sqsub, 0b01000100, 0b011010100); // signed saturating sub
INSN(sve_uqadd, 0b01000100, 0b011001100); // unsigned saturating add
INSN(sve_uqsub, 0b01000100, 0b011011100); // unsigned saturating sub
#undef INSN
Assembler(CodeBuffer* code) : AbstractAssembler(code) {
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
}

View File

@ -2970,3 +2970,42 @@ int C2_MacroAssembler::vector_iota_entry_index(BasicType bt) {
ShouldNotReachHere();
}
}
// Vector integer division for BYTE elements. Each BYTE is widened to SHORT for
// the low and high halves of the register, divided using the SHORT helper
// (which widens further to INT), and the two SHORT result halves are narrowed
// back to BYTE.
void C2_MacroAssembler::sve_sdiv_byte(FloatRegister dst_src1, FloatRegister src2,
FloatRegister vtmp1, FloatRegister vtmp2,
FloatRegister vtmp3, FloatRegister vtmp4) {
assert_different_registers(dst_src1, src2, vtmp1, vtmp2, vtmp3, vtmp4);
FloatRegister src1 = dst_src1;
// Low half of the bytes -> SHORT, then divide (result SHORT in vtmp1).
sve_sunpklo(vtmp1, H, src1);
sve_sunpklo(vtmp2, H, src2);
sve_sdiv_short(vtmp1, vtmp2, vtmp3, vtmp4);
// High half of the bytes -> SHORT, then divide (result SHORT in src1).
sve_sunpkhi(src1, H, src1);
sve_sunpkhi(vtmp2, H, src2);
sve_sdiv_short(src1, vtmp2, vtmp3, vtmp4);
// Narrow the two SHORT result halves back to BYTE.
sve_uzp1(dst_src1, B, vtmp1, src1);
}
// Vector integer division for SHORT elements, implemented by widening each
// element to 32 bits, performing SDIV, and narrowing back.
void C2_MacroAssembler::sve_sdiv_short(FloatRegister dst_src1, FloatRegister src2,
FloatRegister vtmp1, FloatRegister vtmp2) {
assert_different_registers(dst_src1, src2, vtmp1, vtmp2);
FloatRegister src1 = dst_src1;
// Low half: SHORT -> INT, then divide.
sve_sunpklo(vtmp1, S, src1);
sve_sunpklo(vtmp2, S, src2);
sve_sdiv(vtmp1, S, ptrue, vtmp2);
// High half: SHORT -> INT, then divide.
sve_sunpkhi(src1, S, src1);
sve_sunpkhi(vtmp2, S, src2);
sve_sdiv(src1, S, ptrue, vtmp2);
// Narrow the two INT result halves back to SHORT.
sve_uzp1(dst_src1, H, vtmp1, src1);
}

View File

@ -253,4 +253,9 @@
void sve_cpy(FloatRegister dst, SIMD_RegVariant T, PRegister pg, int imm8,
bool isMerge);
int vector_iota_entry_index(BasicType bt);
void sve_sdiv_byte(FloatRegister dst_src1, FloatRegister src2, FloatRegister vtmp1,
FloatRegister vtmp2, FloatRegister vtmp3, FloatRegister vtmp4);
void sve_sdiv_short(FloatRegister dst_src1, FloatRegister src2,
FloatRegister vtmp1, FloatRegister vtmp2);
#endif // CPU_AARCH64_C2_MACROASSEMBLER_AARCH64_HPP

View File

@ -1807,6 +1807,8 @@ public:
SVE_DESTRUCTIVE_BINARY_5(sve_fmul, sve_fsub, sve_lsl, sve_lsr, sve_mul)
SVE_DESTRUCTIVE_BINARY_5(sve_orr, sve_smax, sve_smin, sve_sqadd, sve_sqsub)
SVE_DESTRUCTIVE_BINARY_5(sve_sub, sve_uqadd, sve_uqsub, sve_umax, sve_umin)
SVE_DESTRUCTIVE_BINARY_INS(sve_sdiv);
SVE_DESTRUCTIVE_BINARY_INS(sve_udiv);
#undef SVE_DESTRUCTIVE_BINARY_INS
#undef SVE_DESTRUCTIVE_BINARY_5

View File

@ -414,6 +414,10 @@ macro(MulAddVS2VI)
macro(FmaVD)
macro(FmaVF)
macro(FmaVHF)
macro(DivVB)
macro(DivVS)
macro(DivVI)
macro(DivVL)
macro(DivVHF)
macro(DivVF)
macro(DivVD)

View File

@ -96,6 +96,15 @@ int VectorNode::opcode(int sopc, BasicType bt) {
return (bt == T_DOUBLE ? Op_VectorBlend : 0);
case Op_Bool:
return Op_VectorMaskCmp;
case Op_DivI:
switch (bt) {
case T_BYTE: return Op_DivVB;
case T_SHORT: return Op_DivVS;
case T_INT: return Op_DivVI;
default: return 0;
}
case Op_DivL:
return (bt == T_LONG ? Op_DivVL : 0);
case Op_DivHF:
return (bt == T_SHORT ? Op_DivVHF : 0);
case Op_DivF:
@ -333,6 +342,12 @@ int VectorNode::scalar_opcode(int vopc, BasicType bt) {
case Op_MulVD:
return Op_MulD;
case Op_DivVB:
case Op_DivVS:
case Op_DivVI:
return Op_DivI;
case Op_DivVL:
return Op_DivL;
case Op_DivVF:
return Op_DivF;
case Op_DivVD:
@ -680,7 +695,7 @@ void VectorNode::vector_operands(Node* n, uint* start, uint* end) {
case Op_AddI: case Op_AddL: case Op_AddHF: case Op_AddF: case Op_AddD:
case Op_SubI: case Op_SubL: case Op_SubHF: case Op_SubF: case Op_SubD:
case Op_MulI: case Op_MulL: case Op_MulHF: case Op_MulF: case Op_MulD:
case Op_DivHF: case Op_DivF: case Op_DivD:
case Op_DivI: case Op_DivL: case Op_DivHF: case Op_DivF: case Op_DivD:
case Op_AndI: case Op_AndL:
case Op_OrI: case Op_OrL:
case Op_XorI: case Op_XorL:
@ -759,6 +774,10 @@ VectorNode* VectorNode::make(int vopc, Node* n1, Node* n2, const TypeVect* vt, b
case Op_MulVF: return new MulVFNode(n1, n2, vt);
case Op_MulVD: return new MulVDNode(n1, n2, vt);
case Op_DivVB: return new DivVBNode(n1, n2, vt);
case Op_DivVS: return new DivVSNode(n1, n2, vt);
case Op_DivVI: return new DivVINode(n1, n2, vt);
case Op_DivVL: return new DivVLNode(n1, n2, vt);
case Op_DivVHF: return new DivVHFNode(n1, n2, vt);
case Op_DivVF: return new DivVFNode(n1, n2, vt);
case Op_DivVD: return new DivVDNode(n1, n2, vt);

View File

@ -696,6 +696,34 @@ public:
virtual uint size_of() const { return sizeof(*this); }
};
// Vector divide byte
class DivVBNode : public VectorNode {
public:
DivVBNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {}
virtual int Opcode() const;
};
// Vector divide short
class DivVSNode : public VectorNode {
public:
DivVSNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {}
virtual int Opcode() const;
};
// Vector divide int
class DivVINode : public VectorNode {
public:
DivVINode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {}
virtual int Opcode() const;
};
// Vector divide long
class DivVLNode : public VectorNode {
public:
DivVLNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {}
virtual int Opcode() const;
};
// Vector divide half float
class DivVHFNode : public VectorNode {
public:

View File

@ -1121,6 +1121,8 @@ class SVEVectorOp(Instruction):
self._bitwiseop = False
if name[0] == 'f':
self._width = RegVariant(2, 3)
elif name in ["sdiv", "udiv"]:
self._width = RegVariant(2, 3)
elif not self._isPredicated and (name in ["and", "bic", "bsl", "eor", "eor3", "orr"]):
self._width = RegVariant(3, 3)
self._bitwiseop = True
@ -2220,6 +2222,8 @@ generate(SVEVectorOp, [["add", "ZZZ"],
["lsl", "ZPZ", "m", "dn"],
["lsr", "ZPZ", "m", "dn"],
["mul", "ZPZ", "m", "dn"],
["sdiv", "ZPZ", "m", "dn"],
["udiv", "ZPZ", "m", "dn"],
["neg", "ZPZ", "m"],
["not", "ZPZ", "m"],
["orr", "ZPZ", "m", "dn"],

View File

@ -1382,80 +1382,82 @@
__ sve_lsl(z17, __ D, p1, z11); // lsl z17.d, p1/m, z17.d, z11.d
__ sve_lsr(z16, __ B, p0, z16); // lsr z16.b, p0/m, z16.b, z16.b
__ sve_mul(z28, __ D, p1, z23); // mul z28.d, p1/m, z28.d, z23.d
__ sve_neg(z28, __ S, p4, z10); // neg z28.s, p4/m, z10.s
__ sve_not(z17, __ S, p7, z7); // not z17.s, p7/m, z7.s
__ sve_orr(z4, __ H, p3, z24); // orr z4.h, p3/m, z4.h, z24.h
__ sve_rbit(z9, __ B, p2, z11); // rbit z9.b, p2/m, z11.b
__ sve_revb(z4, __ S, p5, z22); // revb z4.s, p5/m, z22.s
__ sve_smax(z4, __ H, p0, z15); // smax z4.h, p0/m, z4.h, z15.h
__ sve_smin(z4, __ D, p7, z26); // smin z4.d, p7/m, z4.d, z26.d
__ sve_umax(z5, __ H, p5, z26); // umax z5.h, p5/m, z5.h, z26.h
__ sve_umin(z31, __ B, p0, z25); // umin z31.b, p0/m, z31.b, z25.b
__ sve_sub(z8, __ S, p1, z3); // sub z8.s, p1/m, z8.s, z3.s
__ sve_fabs(z7, __ D, p6, z24); // fabs z7.d, p6/m, z24.d
__ sve_fadd(z24, __ S, p7, z17); // fadd z24.s, p7/m, z24.s, z17.s
__ sve_fdiv(z10, __ S, p3, z30); // fdiv z10.s, p3/m, z10.s, z30.s
__ sve_fmax(z8, __ S, p6, z29); // fmax z8.s, p6/m, z8.s, z29.s
__ sve_fmin(z31, __ D, p5, z31); // fmin z31.d, p5/m, z31.d, z31.d
__ sve_fmul(z0, __ D, p5, z7); // fmul z0.d, p5/m, z0.d, z7.d
__ sve_fneg(z29, __ S, p6, z22); // fneg z29.s, p6/m, z22.s
__ sve_frintm(z29, __ S, p6, z20); // frintm z29.s, p6/m, z20.s
__ sve_frintn(z6, __ S, p4, z18); // frintn z6.s, p4/m, z18.s
__ sve_frintp(z26, __ S, p5, z8); // frintp z26.s, p5/m, z8.s
__ sve_fsqrt(z19, __ S, p2, z28); // fsqrt z19.s, p2/m, z28.s
__ sve_fsub(z17, __ D, p1, z30); // fsub z17.d, p1/m, z17.d, z30.d
__ sve_fmad(z24, __ S, p7, z14, z17); // fmad z24.s, p7/m, z14.s, z17.s
__ sve_fmla(z19, __ D, p2, z26, z11); // fmla z19.d, p2/m, z26.d, z11.d
__ sve_fmls(z0, __ D, p2, z15, z28); // fmls z0.d, p2/m, z15.d, z28.d
__ sve_fmsb(z23, __ D, p5, z28, z23); // fmsb z23.d, p5/m, z28.d, z23.d
__ sve_fnmad(z29, __ S, p6, z0, z27); // fnmad z29.s, p6/m, z0.s, z27.s
__ sve_fnmsb(z23, __ S, p3, z12, z4); // fnmsb z23.s, p3/m, z12.s, z4.s
__ sve_fnmla(z31, __ S, p6, z23, z20); // fnmla z31.s, p6/m, z23.s, z20.s
__ sve_fnmls(z2, __ D, p7, z29, z0); // fnmls z2.d, p7/m, z29.d, z0.d
__ sve_mla(z23, __ H, p0, z4, z5); // mla z23.h, p0/m, z4.h, z5.h
__ sve_mls(z28, __ H, p3, z17, z13); // mls z28.h, p3/m, z17.h, z13.h
__ sve_and(z8, z10, z8); // and z8.d, z10.d, z8.d
__ sve_eor(z19, z0, z29); // eor z19.d, z0.d, z29.d
__ sve_orr(z16, z13, z23); // orr z16.d, z13.d, z23.d
__ sve_bic(z23, z30, z13); // bic z23.d, z30.d, z13.d
__ sve_uzp1(z25, __ H, z22, z0); // uzp1 z25.h, z22.h, z0.h
__ sve_uzp2(z25, __ H, z30, z11); // uzp2 z25.h, z30.h, z11.h
__ sve_fabd(z14, __ S, p5, z22); // fabd z14.s, p5/m, z14.s, z22.s
__ sve_bext(z5, __ H, z18, z0); // bext z5.h, z18.h, z0.h
__ sve_bdep(z9, __ D, z2, z3); // bdep z9.d, z2.d, z3.d
__ sve_bsl(z14, z4, z29); // bsl z14.d, z14.d, z4.d, z29.d
__ sve_eor3(z14, z22, z4); // eor3 z14.d, z14.d, z22.d, z4.d
__ sve_sqadd(z27, __ S, p3, z22); // sqadd z27.s, p3/m, z27.s, z22.s
__ sve_sqsub(z31, __ S, p6, z11); // sqsub z31.s, p6/m, z31.s, z11.s
__ sve_uqadd(z12, __ B, p4, z28); // uqadd z12.b, p4/m, z12.b, z28.b
__ sve_uqsub(z28, __ D, p4, z4); // uqsub z28.d, p4/m, z28.d, z4.d
__ sve_sdiv(z28, __ D, p4, z10); // sdiv z28.d, p4/m, z28.d, z10.d
__ sve_udiv(z17, __ D, p7, z7); // udiv z17.d, p7/m, z17.d, z7.d
__ sve_neg(z4, __ H, p3, z24); // neg z4.h, p3/m, z24.h
__ sve_not(z9, __ B, p2, z11); // not z9.b, p2/m, z11.b
__ sve_orr(z4, __ S, p5, z22); // orr z4.s, p5/m, z4.s, z22.s
__ sve_rbit(z4, __ H, p0, z15); // rbit z4.h, p0/m, z15.h
__ sve_revb(z4, __ D, p7, z26); // revb z4.d, p7/m, z26.d
__ sve_smax(z5, __ H, p5, z26); // smax z5.h, p5/m, z5.h, z26.h
__ sve_smin(z31, __ B, p0, z25); // smin z31.b, p0/m, z31.b, z25.b
__ sve_umax(z8, __ S, p1, z3); // umax z8.s, p1/m, z8.s, z3.s
__ sve_umin(z7, __ D, p6, z24); // umin z7.d, p6/m, z7.d, z24.d
__ sve_sub(z24, __ B, p7, z17); // sub z24.b, p7/m, z24.b, z17.b
__ sve_fabs(z10, __ S, p3, z30); // fabs z10.s, p3/m, z30.s
__ sve_fadd(z8, __ S, p6, z29); // fadd z8.s, p6/m, z8.s, z29.s
__ sve_fdiv(z31, __ D, p5, z31); // fdiv z31.d, p5/m, z31.d, z31.d
__ sve_fmax(z0, __ D, p5, z7); // fmax z0.d, p5/m, z0.d, z7.d
__ sve_fmin(z29, __ S, p6, z22); // fmin z29.s, p6/m, z29.s, z22.s
__ sve_fmul(z29, __ S, p6, z20); // fmul z29.s, p6/m, z29.s, z20.s
__ sve_fneg(z6, __ S, p4, z18); // fneg z6.s, p4/m, z18.s
__ sve_frintm(z26, __ S, p5, z8); // frintm z26.s, p5/m, z8.s
__ sve_frintn(z19, __ S, p2, z28); // frintn z19.s, p2/m, z28.s
__ sve_frintp(z17, __ D, p1, z30); // frintp z17.d, p1/m, z30.d
__ sve_fsqrt(z24, __ D, p7, z14); // fsqrt z24.d, p7/m, z14.d
__ sve_fsub(z14, __ D, p4, z10); // fsub z14.d, p4/m, z14.d, z10.d
__ sve_fmad(z11, __ S, p6, z0, z11); // fmad z11.s, p6/m, z0.s, z11.s
__ sve_fmla(z28, __ D, p5, z23, z20); // fmla z28.d, p5/m, z23.d, z20.d
__ sve_fmls(z23, __ S, p5, z29, z24); // fmls z23.s, p5/m, z29.s, z24.s
__ sve_fmsb(z27, __ S, p1, z23, z13); // fmsb z27.s, p1/m, z23.s, z13.s
__ sve_fnmad(z4, __ D, p3, z31, z26); // fnmad z4.d, p3/m, z31.d, z26.d
__ sve_fnmsb(z20, __ D, p1, z2, z29); // fnmsb z20.d, p1/m, z2.d, z29.d
__ sve_fnmla(z0, __ S, p7, z23, z3); // fnmla z0.s, p7/m, z23.s, z3.s
__ sve_fnmls(z5, __ D, p2, z28, z13); // fnmls z5.d, p2/m, z28.d, z13.d
__ sve_mla(z13, __ H, p3, z8, z10); // mla z13.h, p3/m, z8.h, z10.h
__ sve_mls(z9, __ S, p4, z0, z29); // mls z9.s, p4/m, z0.s, z29.s
__ sve_and(z16, z13, z23); // and z16.d, z13.d, z23.d
__ sve_eor(z23, z30, z13); // eor z23.d, z30.d, z13.d
__ sve_orr(z25, z22, z0); // orr z25.d, z22.d, z0.d
__ sve_bic(z25, z30, z11); // bic z25.d, z30.d, z11.d
__ sve_uzp1(z14, __ H, z23, z22); // uzp1 z14.h, z23.h, z22.h
__ sve_uzp2(z5, __ H, z18, z0); // uzp2 z5.h, z18.h, z0.h
__ sve_fabd(z9, __ D, p0, z3); // fabd z9.d, p0/m, z9.d, z3.d
__ sve_bext(z14, __ H, z4, z29); // bext z14.h, z4.h, z29.h
__ sve_bdep(z14, __ D, z22, z4); // bdep z14.d, z22.d, z4.d
__ sve_bsl(z27, z15, z22); // bsl z27.d, z27.d, z15.d, z22.d
__ sve_eor3(z31, z24, z11); // eor3 z31.d, z31.d, z24.d, z11.d
__ sve_sqadd(z12, __ B, p4, z28); // sqadd z12.b, p4/m, z12.b, z28.b
__ sve_sqsub(z28, __ D, p4, z4); // sqsub z28.d, p4/m, z28.d, z4.d
__ sve_uqadd(z6, __ S, p0, z15); // uqadd z6.s, p0/m, z6.s, z15.s
__ sve_uqsub(z1, __ S, p5, z18); // uqsub z1.s, p5/m, z1.s, z18.s
// SVEReductionOp
__ sve_andv(v6, __ S, p0, z15); // andv s6, p0, z15.s
__ sve_orv(v1, __ S, p5, z18); // orv s1, p5, z18.s
__ sve_eorv(v2, __ H, p2, z4); // eorv h2, p2, z4.h
__ sve_smaxv(v11, __ S, p2, z28); // smaxv s11, p2, z28.s
__ sve_sminv(v3, __ H, p5, z31); // sminv h3, p5, z31.h
__ sve_umaxv(v24, __ H, p5, z15); // umaxv h24, p5, z15.h
__ sve_uminv(v6, __ H, p3, z8); // uminv h6, p3, z8.h
__ sve_fminv(v21, __ D, p7, z4); // fminv d21, p7, z4.d
__ sve_fmaxv(v24, __ S, p5, z6); // fmaxv s24, p5, z6.s
__ sve_fadda(v4, __ D, p2, z9); // fadda d4, p2, d4, z9.d
__ sve_uaddv(v10, __ S, p1, z31); // uaddv d10, p1, z31.s
__ sve_andv(v2, __ H, p2, z4); // andv h2, p2, z4.h
__ sve_orv(v11, __ S, p2, z28); // orv s11, p2, z28.s
__ sve_eorv(v3, __ H, p5, z31); // eorv h3, p5, z31.h
__ sve_smaxv(v24, __ H, p5, z15); // smaxv h24, p5, z15.h
__ sve_sminv(v6, __ H, p3, z8); // sminv h6, p3, z8.h
__ sve_umaxv(v21, __ D, p7, z4); // umaxv d21, p7, z4.d
__ sve_uminv(v24, __ B, p5, z6); // uminv b24, p5, z6.b
__ sve_fminv(v4, __ D, p2, z9); // fminv d4, p2, z9.d
__ sve_fmaxv(v10, __ D, p1, z31); // fmaxv d10, p1, z31.d
__ sve_fadda(v25, __ D, p3, z3); // fadda d25, p3, d25, z3.d
__ sve_uaddv(v14, __ H, p2, z2); // uaddv d14, p2, z2.h
// AddWideNEONOp
__ saddwv(v25, v26, __ T8H, v27, __ T8B); // saddw v25.8H, v26.8H, v27.8B
__ saddwv2(v15, v16, __ T8H, v17, __ T16B); // saddw2 v15.8H, v16.8H, v17.16B
__ saddwv(v3, v4, __ T4S, v5, __ T4H); // saddw v3.4S, v4.4S, v5.4H
__ saddwv2(v18, v19, __ T4S, v20, __ T8H); // saddw2 v18.4S, v19.4S, v20.8H
__ saddwv(v14, v15, __ T2D, v16, __ T2S); // saddw v14.2D, v15.2D, v16.2S
__ saddwv2(v10, v11, __ T2D, v12, __ T4S); // saddw2 v10.2D, v11.2D, v12.4S
__ uaddwv(v2, v3, __ T8H, v4, __ T8B); // uaddw v2.8H, v3.8H, v4.8B
__ uaddwv2(v10, v11, __ T8H, v12, __ T16B); // uaddw2 v10.8H, v11.8H, v12.16B
__ uaddwv(v8, v9, __ T4S, v10, __ T4H); // uaddw v8.4S, v9.4S, v10.4H
__ uaddwv2(v11, v12, __ T4S, v13, __ T8H); // uaddw2 v11.4S, v12.4S, v13.8H
__ uaddwv(v22, v23, __ T2D, v24, __ T2S); // uaddw v22.2D, v23.2D, v24.2S
__ uaddwv2(v3, v4, __ T2D, v5, __ T4S); // uaddw2 v3.2D, v4.2D, v5.4S
__ saddwv(v8, v9, __ T8H, v10, __ T8B); // saddw v8.8H, v9.8H, v10.8B
__ saddwv2(v11, v12, __ T8H, v13, __ T16B); // saddw2 v11.8H, v12.8H, v13.16B
__ saddwv(v22, v23, __ T4S, v24, __ T4H); // saddw v22.4S, v23.4S, v24.4H
__ saddwv2(v3, v4, __ T4S, v5, __ T8H); // saddw2 v3.4S, v4.4S, v5.8H
__ saddwv(v12, v13, __ T2D, v14, __ T2S); // saddw v12.2D, v13.2D, v14.2S
__ saddwv2(v24, v25, __ T2D, v26, __ T4S); // saddw2 v24.2D, v25.2D, v26.4S
__ uaddwv(v9, v10, __ T8H, v11, __ T8B); // uaddw v9.8H, v10.8H, v11.8B
__ uaddwv2(v27, v28, __ T8H, v29, __ T16B); // uaddw2 v27.8H, v28.8H, v29.16B
__ uaddwv(v27, v28, __ T4S, v29, __ T4H); // uaddw v27.4S, v28.4S, v29.4H
__ uaddwv2(v6, v7, __ T4S, v8, __ T8H); // uaddw2 v6.4S, v7.4S, v8.8H
__ uaddwv(v20, v21, __ T2D, v22, __ T2S); // uaddw v20.2D, v21.2D, v22.2S
__ uaddwv2(v20, v21, __ T2D, v22, __ T4S); // uaddw2 v20.2D, v21.2D, v22.4S
__ bind(forth);
@ -1474,30 +1476,30 @@
0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061,
0x120cb166, 0x321764bc, 0x52174681, 0x720c0227,
0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01,
0x14000000, 0x17ffffd7, 0x140004d0, 0x94000000,
0x97ffffd4, 0x940004cd, 0x3400000a, 0x34fffa2a,
0x3400994a, 0x35000008, 0x35fff9c8, 0x350098e8,
0xb400000b, 0xb4fff96b, 0xb400988b, 0xb500001d,
0xb5fff91d, 0xb500983d, 0x10000013, 0x10fff8b3,
0x100097d3, 0x90000013, 0x36300016, 0x3637f836,
0x36309756, 0x3758000c, 0x375ff7cc, 0x375896ec,
0x14000000, 0x17ffffd7, 0x140004d2, 0x94000000,
0x97ffffd4, 0x940004cf, 0x3400000a, 0x34fffa2a,
0x3400998a, 0x35000008, 0x35fff9c8, 0x35009928,
0xb400000b, 0xb4fff96b, 0xb40098cb, 0xb500001d,
0xb5fff91d, 0xb500987d, 0x10000013, 0x10fff8b3,
0x10009813, 0x90000013, 0x36300016, 0x3637f836,
0x36309796, 0x3758000c, 0x375ff7cc, 0x3758972c,
0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc,
0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f,
0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016,
0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0,
0x540094c0, 0x54000001, 0x54fff541, 0x54009461,
0x54000002, 0x54fff4e2, 0x54009402, 0x54000002,
0x54fff482, 0x540093a2, 0x54000003, 0x54fff423,
0x54009343, 0x54000003, 0x54fff3c3, 0x540092e3,
0x54000004, 0x54fff364, 0x54009284, 0x54000005,
0x54fff305, 0x54009225, 0x54000006, 0x54fff2a6,
0x540091c6, 0x54000007, 0x54fff247, 0x54009167,
0x54000008, 0x54fff1e8, 0x54009108, 0x54000009,
0x54fff189, 0x540090a9, 0x5400000a, 0x54fff12a,
0x5400904a, 0x5400000b, 0x54fff0cb, 0x54008feb,
0x5400000c, 0x54fff06c, 0x54008f8c, 0x5400000d,
0x54fff00d, 0x54008f2d, 0x5400000e, 0x54ffefae,
0x54008ece, 0x5400000f, 0x54ffef4f, 0x54008e6f,
0x54009500, 0x54000001, 0x54fff541, 0x540094a1,
0x54000002, 0x54fff4e2, 0x54009442, 0x54000002,
0x54fff482, 0x540093e2, 0x54000003, 0x54fff423,
0x54009383, 0x54000003, 0x54fff3c3, 0x54009323,
0x54000004, 0x54fff364, 0x540092c4, 0x54000005,
0x54fff305, 0x54009265, 0x54000006, 0x54fff2a6,
0x54009206, 0x54000007, 0x54fff247, 0x540091a7,
0x54000008, 0x54fff1e8, 0x54009148, 0x54000009,
0x54fff189, 0x540090e9, 0x5400000a, 0x54fff12a,
0x5400908a, 0x5400000b, 0x54fff0cb, 0x5400902b,
0x5400000c, 0x54fff06c, 0x54008fcc, 0x5400000d,
0x54fff00d, 0x54008f6d, 0x5400000e, 0x54ffefae,
0x54008f0e, 0x5400000f, 0x54ffef4f, 0x54008eaf,
0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60,
0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f,
0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf,
@ -1540,7 +1542,7 @@
0x39598921, 0x795d3077, 0x399d0675, 0x7998d8f3,
0x79dbd02a, 0xb99d068a, 0xfd5d11a0, 0xbd58d76b,
0xfd1ac72d, 0xbd1d9c14, 0x5800001a, 0x18ffda33,
0xf8991100, 0xd8007920, 0xf8a758e0, 0xf9989d80,
0xf8991100, 0xd8007960, 0xf8a758e0, 0xf9989d80,
0x1a0b0298, 0x3a1c01a0, 0x5a0400ea, 0x7a02020f,
0x9a1d028c, 0xba0e01ad, 0xda140186, 0xfa19022c,
0x0b2b877e, 0x2b21c8ee, 0xcb3ba47d, 0x6b3ae9a0,
@ -1765,23 +1767,24 @@
0x04e71f54, 0x04d6b0d4, 0x044003ad, 0x041a0029,
0x041099fb, 0x04db1e24, 0x0419a302, 0x041abdba,
0x04d90e16, 0x04d38571, 0x04118210, 0x04d006fc,
0x0497b15c, 0x049ebcf1, 0x04580f04, 0x05278969,
0x05a496c4, 0x044801e4, 0x04ca1f44, 0x04491745,
0x040b033f, 0x04810468, 0x04dcbb07, 0x65809e38,
0x658d8fca, 0x65869ba8, 0x65c797ff, 0x65c294e0,
0x049dbadd, 0x6582ba9d, 0x6580b246, 0x6581b51a,
0x658dab93, 0x65c187d1, 0x65b19dd8, 0x65eb0b53,
0x65fc29e0, 0x65f7b797, 0x65bbd81d, 0x65a4ed97,
0x65b45aff, 0x65e07fa2, 0x04454097, 0x044d6e3c,
0x04283148, 0x04bd3013, 0x047731b0, 0x04ed33d7,
0x05606ad9, 0x056b6fd9, 0x658896ce, 0x4540b245,
0x45c3b449, 0x04243fae, 0x0436388e, 0x44988edb,
0x449a997f, 0x4419938c, 0x44db909c, 0x049a21e6,
0x04983641, 0x04592882, 0x04882b8b, 0x044a37e3,
0x044935f8, 0x044b2d06, 0x65c73c95, 0x658634d8,
0x65d82924, 0x048127ea, 0x0e3b1359, 0x4e31120f,
0x0e651083, 0x4e741272, 0x0eb011ee, 0x4eac116a,
0x2e241062, 0x6e2c116a, 0x2e6a1128, 0x6e6d118b,
0x2eb812f6, 0x6ea51083,
0x04d4115c, 0x04d51cf1, 0x0457af04, 0x041ea969,
0x049816c4, 0x056781e4, 0x05e49f44, 0x04481745,
0x040a033f, 0x04890468, 0x04cb1b07, 0x04011e38,
0x049cafca, 0x65809ba8, 0x65cd97ff, 0x65c694e0,
0x65879add, 0x65829a9d, 0x049db246, 0x6582b51a,
0x6580ab93, 0x65c1a7d1, 0x65cdbdd8, 0x65c1914e,
0x65ab980b, 0x65f416fc, 0x65b837b7, 0x65ada6fb,
0x65facfe4, 0x65fde454, 0x65a35ee0, 0x65ed6b85,
0x044a4d0d, 0x049d7009, 0x043731b0, 0x04ad33d7,
0x046032d9, 0x04eb33d9, 0x05766aee, 0x05606e45,
0x65c88069, 0x455db08e, 0x45c4b6ce, 0x042f3edb,
0x0438397f, 0x4418938c, 0x44da909c, 0x449981e6,
0x449b9641, 0x045a2882, 0x04982b8b, 0x045937e3,
0x044835f8, 0x044a2d06, 0x04c93c95, 0x040b34d8,
0x65c72924, 0x65c627ea, 0x65d82c79, 0x0441284e,
0x0e2a1128, 0x4e2d118b, 0x0e7812f6, 0x4e651083,
0x0eae11ac, 0x4eba1338, 0x2e2b1149, 0x6e3d139b,
0x2e7d139b, 0x6e6810e6, 0x2eb612b4, 0x6eb612b4,
};
// END Generated code -- do not edit

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026, Oracle and/or its affiliates. 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
@ -555,12 +555,16 @@ public class TestIntVect {
}
}
// Not vectorized: no vector div. NOTE: This check does not document the
// _desired_ behavior of the system but the current behavior (no
// vectorization)
// Not vectorized: On AArch64 SVE, vectorization for this example results in
// DivVI nodes.
@Test
@IR(counts = { IRNode.LOAD_VECTOR_I, "> 0",
IRNode.STORE_VECTOR, "> 0",
IRNode.DIV_VI, "> 0" },
applyIfCPUFeature = {"sve", "true"})
@IR(counts = { IRNode.LOAD_VECTOR_I, "= 0",
IRNode.STORE_VECTOR, "= 0" })
IRNode.STORE_VECTOR, "= 0" },
applyIfCPUFeature = {"sve", "false"})
void test_divv(int[] a0, int[] a1, int b) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (int)(a1[i]/b);

View File

@ -763,6 +763,26 @@ public class IRNode {
beforeMatchingNameRegex(DIV_MOD_L, "DivModL");
}
public static final String DIV_VB = VECTOR_PREFIX + "DIV_VB" + POSTFIX;
static {
vectorNode(DIV_VB, "DivVB", TYPE_BYTE);
}
public static final String DIV_VS = VECTOR_PREFIX + "DIV_VS" + POSTFIX;
static {
vectorNode(DIV_VS, "DivVS", TYPE_SHORT);
}
public static final String DIV_VI = VECTOR_PREFIX + "DIV_VI" + POSTFIX;
static {
vectorNode(DIV_VI, "DivVI", TYPE_INT);
}
public static final String DIV_VL = VECTOR_PREFIX + "DIV_VL" + POSTFIX;
static {
vectorNode(DIV_VL, "DivVL", TYPE_LONG);
}
public static final String DIV_VHF = VECTOR_PREFIX + "DIV_VHF" + POSTFIX;
static {
vectorNode(DIV_VHF, "DivVHF", TYPE_SHORT);

View File

@ -0,0 +1,238 @@
/*
* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. 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.
*/
/*
* @test
* @bug 8387594
* @key randomness
* @library /test/lib /
* @summary IR tests for Vector API lanewise DIV
* @modules jdk.incubator.vector
*
* @run driver ${test.main.class}
*/
package compiler.vectorapi;
import compiler.lib.generators.*;
import compiler.lib.ir_framework.*;
import jdk.incubator.vector.*;
public class VectorDivTest {
private static final Generators RD = Generators.G;
private static final VectorSpecies<Byte> B_SPECIES = ByteVector.SPECIES_MAX;
private static final VectorSpecies<Short> S_SPECIES = ShortVector.SPECIES_MAX;
private static final VectorSpecies<Integer> I_SPECIES = IntVector.SPECIES_MAX;
private static final VectorSpecies<Long> L_SPECIES = LongVector.SPECIES_MAX;
private static final VectorSpecies<Float> F_SPECIES = FloatVector.SPECIES_MAX;
private static final VectorSpecies<Double> D_SPECIES = DoubleVector.SPECIES_MAX;
private static final int BUF_LEN = 256;
private static final byte[] ba = new byte[BUF_LEN];
private static final byte[] bb = new byte[BUF_LEN];
private static final byte[] br = new byte[BUF_LEN];
private static final short[] sa = new short[BUF_LEN];
private static final short[] sb = new short[BUF_LEN];
private static final short[] sr = new short[BUF_LEN];
private static final int[] ia = new int[BUF_LEN];
private static final int[] ib = new int[BUF_LEN];
private static final int[] ir = new int[BUF_LEN];
private static final long[] la = new long[BUF_LEN];
private static final long[] lb = new long[BUF_LEN];
private static final long[] lr = new long[BUF_LEN];
private static final float[] fa = new float[BUF_LEN];
private static final float[] fb = new float[BUF_LEN];
private static final float[] fr = new float[BUF_LEN];
private static final double[] da = new double[BUF_LEN];
private static final double[] db = new double[BUF_LEN];
private static final double[] dr = new double[BUF_LEN];
private static final boolean[] mask_arr = new boolean[BUF_LEN];
static {
Generator<Integer> iGen = RD.ints();
Generator<Long> lGen = RD.longs();
Generator<Float> fGen = RD.floats();
Generator<Double> dGen = RD.doubles();
for (int i = 0; i < BUF_LEN; i++) {
mask_arr[i] = (i & 1) != 0;
ba[i] = iGen.next().byteValue();
// Integer divisors must be non-zero, otherwise lanewise DIV throws.
bb[i] = nonZeroByte(iGen.next().byteValue());
sa[i] = iGen.next().shortValue();
sb[i] = nonZeroShort(iGen.next().shortValue());
ib[i] = nonZeroInt(iGen.next());
lb[i] = nonZeroLong(lGen.next());
}
RD.fill(iGen, ia);
RD.fill(lGen, la);
RD.fill(fGen, fa);
// Floating-point division has no divide-by-zero exception.
RD.fill(fGen, fb);
RD.fill(dGen, da);
RD.fill(dGen, db);
}
private static byte nonZeroByte(byte v) { return v == 0 ? (byte) 1 : v; }
private static short nonZeroShort(short v) { return v == 0 ? (short) 1 : v; }
private static int nonZeroInt(int v) { return v == 0 ? 1 : v; }
private static long nonZeroLong(long v) { return v == 0 ? 1L : v; }
// Unmasked lanewise DIV.
@Test
@IR(counts = { IRNode.DIV_VB, ">= 1" },
applyIfCPUFeature = { "sve", "true" })
public static void testDivByte() {
ByteVector va = ByteVector.fromArray(B_SPECIES, ba, 0);
ByteVector vb = ByteVector.fromArray(B_SPECIES, bb, 0);
va.lanewise(VectorOperators.DIV, vb).intoArray(br, 0);
}
@Test
@IR(counts = { IRNode.DIV_VS, ">= 1" },
applyIfCPUFeature = { "sve", "true" })
public static void testDivShort() {
ShortVector va = ShortVector.fromArray(S_SPECIES, sa, 0);
ShortVector vb = ShortVector.fromArray(S_SPECIES, sb, 0);
va.lanewise(VectorOperators.DIV, vb).intoArray(sr, 0);
}
@Test
@IR(counts = { IRNode.DIV_VI, ">= 1" },
applyIfCPUFeature = { "sve", "true" })
public static void testDivInt() {
IntVector va = IntVector.fromArray(I_SPECIES, ia, 0);
IntVector vb = IntVector.fromArray(I_SPECIES, ib, 0);
va.lanewise(VectorOperators.DIV, vb).intoArray(ir, 0);
}
@Test
@IR(counts = { IRNode.DIV_VL, ">= 1" },
applyIfCPUFeature = { "sve", "true" })
public static void testDivLong() {
LongVector va = LongVector.fromArray(L_SPECIES, la, 0);
LongVector vb = LongVector.fromArray(L_SPECIES, lb, 0);
va.lanewise(VectorOperators.DIV, vb).intoArray(lr, 0);
}
@Test
@IR(counts = { IRNode.DIV_VF, ">= 1" },
applyIfCPUFeature = { "asimd", "true" })
public static void testDivFloat() {
FloatVector va = FloatVector.fromArray(F_SPECIES, fa, 0);
FloatVector vb = FloatVector.fromArray(F_SPECIES, fb, 0);
va.lanewise(VectorOperators.DIV, vb).intoArray(fr, 0);
}
@Test
@IR(counts = { IRNode.DIV_VD, ">= 1" },
applyIfCPUFeature = { "asimd", "true" })
public static void testDivDouble() {
DoubleVector va = DoubleVector.fromArray(D_SPECIES, da, 0);
DoubleVector vb = DoubleVector.fromArray(D_SPECIES, db, 0);
va.lanewise(VectorOperators.DIV, vb).intoArray(dr, 0);
}
// Masked lanewise DIV. On AArch64, BYTE/SHORT have no native predicated
// divide, so they are lowered to an unpredicated divide combined with a
// VectorBlend.
@Test
@IR(counts = { IRNode.DIV_VB, ">= 1",
IRNode.VECTOR_BLEND_B, ">= 1" },
applyIfCPUFeature = { "sve", "true" })
public static void testMaskedDivByte() {
VectorMask<Byte> mask = VectorMask.fromArray(B_SPECIES, mask_arr, 0);
ByteVector va = ByteVector.fromArray(B_SPECIES, ba, 0);
ByteVector vb = ByteVector.fromArray(B_SPECIES, bb, 0);
va.lanewise(VectorOperators.DIV, vb, mask).intoArray(br, 0);
}
@Test
@IR(counts = { IRNode.DIV_VS, ">= 1",
IRNode.VECTOR_BLEND_S, ">= 1" },
applyIfCPUFeature = { "sve", "true" })
public static void testMaskedDivShort() {
VectorMask<Short> mask = VectorMask.fromArray(S_SPECIES, mask_arr, 0);
ShortVector va = ShortVector.fromArray(S_SPECIES, sa, 0);
ShortVector vb = ShortVector.fromArray(S_SPECIES, sb, 0);
va.lanewise(VectorOperators.DIV, vb, mask).intoArray(sr, 0);
}
@Test
@IR(counts = { IRNode.DIV_VI, ">= 1" },
applyIfCPUFeature = { "sve", "true" })
public static void testMaskedDivInt() {
VectorMask<Integer> mask = VectorMask.fromArray(I_SPECIES, mask_arr, 0);
IntVector va = IntVector.fromArray(I_SPECIES, ia, 0);
IntVector vb = IntVector.fromArray(I_SPECIES, ib, 0);
va.lanewise(VectorOperators.DIV, vb, mask).intoArray(ir, 0);
}
@Test
@IR(counts = { IRNode.DIV_VL, ">= 1" },
applyIfCPUFeature = { "sve", "true" })
public static void testMaskedDivLong() {
VectorMask<Long> mask = VectorMask.fromArray(L_SPECIES, mask_arr, 0);
LongVector va = LongVector.fromArray(L_SPECIES, la, 0);
LongVector vb = LongVector.fromArray(L_SPECIES, lb, 0);
va.lanewise(VectorOperators.DIV, vb, mask).intoArray(lr, 0);
}
@Test
@IR(counts = { IRNode.DIV_VF, ">= 1" },
applyIfCPUFeature = { "sve", "true" })
public static void testMaskedDivFloat() {
VectorMask<Float> mask = VectorMask.fromArray(F_SPECIES, mask_arr, 0);
FloatVector va = FloatVector.fromArray(F_SPECIES, fa, 0);
FloatVector vb = FloatVector.fromArray(F_SPECIES, fb, 0);
va.lanewise(VectorOperators.DIV, vb, mask).intoArray(fr, 0);
}
@Test
@IR(counts = { IRNode.DIV_VD, ">= 1" },
applyIfCPUFeature = { "sve", "true" })
public static void testMaskedDivDouble() {
VectorMask<Double> mask = VectorMask.fromArray(D_SPECIES, mask_arr, 0);
DoubleVector va = DoubleVector.fromArray(D_SPECIES, da, 0);
DoubleVector vb = DoubleVector.fromArray(D_SPECIES, db, 0);
va.lanewise(VectorOperators.DIV, vb, mask).intoArray(dr, 0);
}
public static void main(String[] args) {
TestFramework testFramework = new TestFramework();
testFramework.setDefaultWarmup(10000)
.addFlags("--add-modules=jdk.incubator.vector")
.start();
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. 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.
*/
package org.openjdk.bench.vm.compiler;
import org.openjdk.jmh.annotations.*;
import java.util.Random;
import java.util.concurrent.TimeUnit;
// Measures auto-vectorization of integer division by a loop-invariant divisor.
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
@Warmup(iterations = 5, time = 2)
@Measurement(iterations = 5, time = 2)
@Fork(value = 3)
public class VectorIntegerDiv {
@Param({"1024"})
private int size;
// Loop-invariant divisors. These are non-final fields, so the JIT sees a
// runtime value and cannot strength-reduce the division to a multiply.
private int iDivisor;
private long lDivisor;
private int[] ia, ir;
private long[] la, lr;
@Setup
public void setup() {
Random r = new Random(42);
iDivisor = r.nextInt() | 1;
lDivisor = r.nextLong() | 1L;
ia = new int[size];
ir = new int[size];
la = new long[size];
lr = new long[size];
for (int i = 0; i < size; i++) {
ia[i] = r.nextInt();
la[i] = r.nextLong();
}
}
@Benchmark
public void intDiv() {
for (int i = 0; i < ia.length; i++) {
ir[i] = ia[i] / iDivisor;
}
}
@Benchmark
public void longDiv() {
for (int i = 0; i < la.length; i++) {
lr[i] = la[i] / lDivisor;
}
}
}