Skip to content
Permalink
Browse files
8269559: AArch64: Implement string_compare intrinsic in SVE
Reviewed-by: ngasson, aph
  • Loading branch information
tatwaichong authored and nick-arm committed Oct 14, 2021
1 parent d9e03e4 commit 8b1b6f9fb375bbc2de339ad8f526ca4d5f83dc70
Showing 11 changed files with 516 additions and 96 deletions.
@@ -1199,6 +1199,9 @@ reg_class gov_pr (
// P7, non-allocatable, preserved with all elements preset to TRUE.
);

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

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

@@ -5537,6 +5540,24 @@ operand pRegGov()
interface(REG_INTER);
%}

operand pRegGov_P0()
%{
constraint(ALLOC_IN_RC(p0_reg));
match(RegVectMask);
op_cost(0);
format %{ %}
interface(REG_INTER);
%}

operand pRegGov_P1()
%{
constraint(ALLOC_IN_RC(p1_reg));
match(RegVectMask);
op_cost(0);
format %{ %}
interface(REG_INTER);
%}

// Flags register, used as output of signed compare instructions

// note that on AArch64 we also use this register as the output for
@@ -16491,7 +16512,7 @@ instruct partialSubtypeCheckVsZero(iRegP_R4 sub, iRegP_R0 super, iRegP_R2 temp,
instruct string_compareU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2, rFlagsReg cr)
%{
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU);
predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU));
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);

@@ -16501,15 +16522,15 @@ instruct string_compareU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 c
__ string_compare($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$Register, $tmp2$$Register,
fnoreg, fnoreg, fnoreg, StrIntrinsicNode::UU);
fnoreg, fnoreg, fnoreg, pnoreg, pnoreg, StrIntrinsicNode::UU);
%}
ins_pipe(pipe_class_memory);
%}

instruct string_compareL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2, rFlagsReg cr)
%{
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL);
predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL));
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);

@@ -16518,7 +16539,7 @@ instruct string_compareL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 c
__ string_compare($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$Register, $tmp2$$Register,
fnoreg, fnoreg, fnoreg, StrIntrinsicNode::LL);
fnoreg, fnoreg, fnoreg, pnoreg, pnoreg, StrIntrinsicNode::LL);
%}
ins_pipe(pipe_class_memory);
%}
@@ -16527,7 +16548,7 @@ instruct string_compareUL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
vRegD_V0 vtmp1, vRegD_V1 vtmp2, vRegD_V2 vtmp3, rFlagsReg cr)
%{
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL);
predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL));
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(KILL tmp1, KILL tmp2, KILL vtmp1, KILL vtmp2, KILL vtmp3,
USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
@@ -16537,8 +16558,8 @@ instruct string_compareUL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
__ string_compare($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$Register, $tmp2$$Register,
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister,
$vtmp3$$FloatRegister, StrIntrinsicNode::UL);
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $vtmp3$$FloatRegister,
pnoreg, pnoreg, StrIntrinsicNode::UL);
%}
ins_pipe(pipe_class_memory);
%}
@@ -16547,7 +16568,7 @@ instruct string_compareLU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
vRegD_V0 vtmp1, vRegD_V1 vtmp2, vRegD_V2 vtmp3, rFlagsReg cr)
%{
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU);
predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU));
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(KILL tmp1, KILL tmp2, KILL vtmp1, KILL vtmp2, KILL vtmp3,
USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
@@ -16557,8 +16578,8 @@ instruct string_compareLU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
__ string_compare($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$Register, $tmp2$$Register,
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister,
$vtmp3$$FloatRegister,StrIntrinsicNode::LU);
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $vtmp3$$FloatRegister,
pnoreg, pnoreg, StrIntrinsicNode::LU);
%}
ins_pipe(pipe_class_memory);
%}
@@ -3810,6 +3810,105 @@ instruct stringU_indexof_char_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegI_R3 ch,
ins_pipe(pipe_class_memory);
%}

// Intrisics for String.compareTo()

// Note that Z registers alias the corresponding NEON registers, we declare the vector operands of
// these string_compare variants as NEON register type for convenience so that the prototype of
// string_compare can be shared with all variants.


instruct string_compareLL_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
pRegGov_P1 pgtmp2, rFlagsReg cr)
%{
predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL));
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);

format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # USE sve" %}
ins_encode %{
// Count is in 8-bit bytes; non-Compact chars are 16 bits.
__ string_compare($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$Register, $tmp2$$Register,
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
StrIntrinsicNode::LL);
%}
ins_pipe(pipe_class_memory);
%}

instruct string_compareLU_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
pRegGov_P1 pgtmp2, rFlagsReg cr)
%{
predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU));
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);

format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # USE sve" %}
ins_encode %{
// Count is in 8-bit bytes; non-Compact chars are 16 bits.
__ string_compare($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$Register, $tmp2$$Register,
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
StrIntrinsicNode::LU);
%}
ins_pipe(pipe_class_memory);
%}

instruct string_compareUL_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
pRegGov_P1 pgtmp2, rFlagsReg cr)
%{
predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL));
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);

format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # USE sve" %}
ins_encode %{
// Count is in 8-bit bytes; non-Compact chars are 16 bits.
__ string_compare($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$Register, $tmp2$$Register,
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
StrIntrinsicNode::UL);
%}
ins_pipe(pipe_class_memory);
%}

instruct string_compareUU_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
pRegGov_P1 pgtmp2, rFlagsReg cr)
%{
predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU));
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);

format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # USE sve" %}
ins_encode %{
// Count is in 8-bit bytes; non-Compact chars are 16 bits.
__ string_compare($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$Register, $tmp2$$Register,
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
StrIntrinsicNode::UU);
%}
ins_pipe(pipe_class_memory);
%}

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

instruct vmask_truecount(iRegINoSp dst, vReg src, pReg ptmp, rFlagsReg cr) %{
@@ -2513,6 +2513,43 @@ dnl $1 $2 $3
STRING_INDEXOF_CHAR(L, Latin1, true)
STRING_INDEXOF_CHAR(U, UTF16, false)

// Intrisics for String.compareTo()

// Note that Z registers alias the corresponding NEON registers, we declare the vector operands of
// these string_compare variants as NEON register type for convenience so that the prototype of
// string_compare can be shared with all variants.

dnl
define(`STRING_COMPARETO', `
instruct string_compare$1_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
pRegGov_P1 pgtmp2, rFlagsReg cr)
%{
predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::$1));
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);

format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # USE sve" %}
ins_encode %{
// Count is in 8-bit bytes; non-Compact chars are 16 bits.
__ string_compare($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$Register, $tmp2$$Register,
$vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
StrIntrinsicNode::$1);
%}
ins_pipe(pipe_class_memory);
%}')dnl
dnl $1
STRING_COMPARETO(LL)
STRING_COMPARETO(LU)
STRING_COMPARETO(UL)
STRING_COMPARETO(UU)
dnl

dnl
dnl VMASK_REDUCTION($1, $2, $3 )
dnl VMASK_REDUCTION(suffix, op_name, cost)
@@ -676,7 +676,8 @@ void C2_MacroAssembler::stringL_indexof_char(Register str1, Register cnt1,
// Compare strings.
void C2_MacroAssembler::string_compare(Register str1, Register str2,
Register cnt1, Register cnt2, Register result, Register tmp1, Register tmp2,
FloatRegister vtmp1, FloatRegister vtmp2, FloatRegister vtmp3, int ae) {
FloatRegister vtmp1, FloatRegister vtmp2, FloatRegister vtmp3,
PRegister pgtmp1, PRegister pgtmp2, int ae) {
Label DONE, SHORT_LOOP, SHORT_STRING, SHORT_LAST, TAIL, STUB,
DIFF, NEXT_WORD, SHORT_LOOP_TAIL, SHORT_LAST2, SHORT_LAST_INIT,
SHORT_LOOP_START, TAIL_CHECK;
@@ -32,7 +32,8 @@
void string_compare(Register str1, Register str2,
Register cnt1, Register cnt2, Register result,
Register tmp1, Register tmp2, FloatRegister vtmp1,
FloatRegister vtmp2, FloatRegister vtmp3, int ae);
FloatRegister vtmp2, FloatRegister vtmp3,
PRegister pgtmp1, PRegister pgtmp2, int ae);

void string_indexof(Register str1, Register str2,
Register cnt1, Register cnt2,
@@ -263,6 +263,8 @@ class PRegisterImpl: public AbstractRegisterImpl {
};

// The predicate registers of SVE.
CONSTANT_REGISTER_DECLARATION(PRegister, pnoreg, (-1));

CONSTANT_REGISTER_DECLARATION(PRegister, p0, ( 0));
CONSTANT_REGISTER_DECLARATION(PRegister, p1, ( 1));
CONSTANT_REGISTER_DECLARATION(PRegister, p2, ( 2));
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -188,6 +188,8 @@ REGISTER_DEFINITION(FloatRegister, z29);
REGISTER_DEFINITION(FloatRegister, z30);
REGISTER_DEFINITION(FloatRegister, z31);

REGISTER_DEFINITION(PRegister, pnoreg);

REGISTER_DEFINITION(PRegister, p0);
REGISTER_DEFINITION(PRegister, p1);
REGISTER_DEFINITION(PRegister, p2);

1 comment on commit 8b1b6f9

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on 8b1b6f9 Oct 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.