# HG changeset patch # User enevill # Date 1464077637 25200 # Tue May 24 01:13:57 2016 -0700 # Node ID 36856adffad46a3f5cbb1ed240fee7e64a421922 # Parent 7b91a10881350ee0b0c3823fe13f4e4c98bbd8af 8156943: aarch64: string compare does not support CompactStrings Summary: Implement LL, UL and LU encodings for StrComp Reviewed-by: aph diff --git a/src/cpu/aarch64/vm/aarch64.ad b/src/cpu/aarch64/vm/aarch64.ad --- a/src/cpu/aarch64/vm/aarch64.ad +++ b/src/cpu/aarch64/vm/aarch64.ad @@ -3330,7 +3330,6 @@ const bool Matcher::match_rule_supported(int opcode) { switch (opcode) { - case Op_StrComp: case Op_StrIndexOf: if (CompactStrings) return false; break; @@ -14944,11 +14943,61 @@ format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1" %} ins_encode %{ // Count is in 8-bit bytes; non-Compact chars are 16 bits. - __ asrw($cnt1$$Register, $cnt1$$Register, 1); - __ asrw($cnt2$$Register, $cnt2$$Register, 1); __ string_compare($str1$$Register, $str2$$Register, $cnt1$$Register, $cnt2$$Register, $result$$Register, - $tmp1$$Register); + $tmp1$$Register, + fnoreg, fnoreg, 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, rFlagsReg cr) +%{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(KILL tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, + fnoreg, fnoreg, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_compareUL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2, + iRegI_R0 result, vRegD vtmp1, vRegD vtmp2, iRegP_R10 tmp1, rFlagsReg cr) +%{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(KILL tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP vtmp1, TEMP vtmp2, KILL cr); + + format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, + $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_compareLU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2, + iRegI_R0 result, vRegD vtmp1, vRegD vtmp2, iRegP_R10 tmp1, rFlagsReg cr) +%{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(KILL tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP vtmp1, TEMP vtmp2, KILL cr); + + format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result # KILL $tmp1" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, + $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, StrIntrinsicNode::LU); %} ins_pipe(pipe_class_memory); %} diff --git a/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp --- a/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -565,11 +565,6 @@ br(Assembler::EQ, done); } - -// added to make this compile - -REGISTER_DEFINITION(Register, noreg); - static void pass_arg0(MacroAssembler* masm, Register arg) { if (c_rarg0 != arg ) { masm->mov(c_rarg0, arg); @@ -4477,21 +4472,49 @@ BIND(DONE); } +typedef void (MacroAssembler::* chr_insn)(Register Rt, const Address &adr); +typedef void (MacroAssembler::* uxt_insn)(Register Rd, Register Rn); + // Compare strings. void MacroAssembler::string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, - Register tmp1) { + Register tmp1, + FloatRegister vtmp, FloatRegister vtmpZ, int ae) { Label LENGTH_DIFF, DONE, SHORT_LOOP, SHORT_STRING, NEXT_WORD, DIFFERENCE; + bool isLL = ae == StrIntrinsicNode::LL; + bool isLU = ae == StrIntrinsicNode::LU; + bool isUL = ae == StrIntrinsicNode::UL; + + bool str1_isL = isLL || isLU; + bool str2_isL = isLL || isUL; + + int str1_chr_shift = str1_isL ? 0 : 1; + int str2_chr_shift = str2_isL ? 0 : 1; + int str1_chr_size = str1_isL ? 1 : 2; + int str2_chr_size = str2_isL ? 1 : 2; + + chr_insn str1_load_chr = str1_isL ? (chr_insn)&MacroAssembler::ldrb : + (chr_insn)&MacroAssembler::ldrh; + chr_insn str2_load_chr = str2_isL ? (chr_insn)&MacroAssembler::ldrb : + (chr_insn)&MacroAssembler::ldrh; + uxt_insn ext_chr = isLL ? (uxt_insn)&MacroAssembler::uxtbw : + (uxt_insn)&MacroAssembler::uxthw; + BLOCK_COMMENT("string_compare {"); + // Bizzarely, the counts are passed in bytes, regardless of whether they + // are L or U strings, however the result is always in characters. + if (!str1_isL) asrw(cnt1, cnt1, 1); + if (!str2_isL) asrw(cnt2, cnt2, 1); + // Compute the minimum of the string lengths and save the difference. subsw(tmp1, cnt1, cnt2); cselw(cnt2, cnt1, cnt2, Assembler::LE); // min // A very short string - cmpw(cnt2, 4); + cmpw(cnt2, isLL ? 8:4); br(Assembler::LT, SHORT_STRING); // Check if the strings start at the same location. @@ -4500,20 +4523,37 @@ // Compare longwords { - subw(cnt2, cnt2, 4); // The last longword is a special case + subw(cnt2, cnt2, isLL ? 8:4); // The last longword is a special case // Move both string pointers to the last longword of their // strings, negate the remaining count, and convert it to bytes. - lea(str1, Address(str1, cnt2, Address::uxtw(1))); - lea(str2, Address(str2, cnt2, Address::uxtw(1))); - sub(cnt2, zr, cnt2, LSL, 1); + lea(str1, Address(str1, cnt2, Address::uxtw(str1_chr_shift))); + lea(str2, Address(str2, cnt2, Address::uxtw(str2_chr_shift))); + if (isLU || isUL) { + sub(cnt1, zr, cnt2, LSL, str1_chr_shift); + eor(vtmpZ, T16B, vtmpZ, vtmpZ); + } + sub(cnt2, zr, cnt2, LSL, str2_chr_shift); // Loop, loading longwords and comparing them into rscratch2. bind(NEXT_WORD); - ldr(result, Address(str1, cnt2)); - ldr(cnt1, Address(str2, cnt2)); - adds(cnt2, cnt2, wordSize); - eor(rscratch2, result, cnt1); + if (isLU) { + ldrs(vtmp, Address(str1, cnt1)); + zip1(vtmp, T8B, vtmp, vtmpZ); + umov(result, vtmp, D, 0); + } else { + ldr(result, Address(str1, isUL ? cnt1:cnt2)); + } + if (isUL) { + ldrs(vtmp, Address(str2, cnt2)); + zip1(vtmp, T8B, vtmp, vtmpZ); + umov(rscratch1, vtmp, D, 0); + } else { + ldr(rscratch1, Address(str2, cnt2)); + } + adds(cnt2, cnt2, isUL ? 4:8); + if (isLU || isUL) add(cnt1, cnt1, isLU ? 4:8); + eor(rscratch2, result, rscratch1); cbnz(rscratch2, DIFFERENCE); br(Assembler::LT, NEXT_WORD); @@ -4521,9 +4561,21 @@ // same longword twice, but that's still faster than another // conditional branch. - ldr(result, Address(str1)); - ldr(cnt1, Address(str2)); - eor(rscratch2, result, cnt1); + if (isLU) { + ldrs(vtmp, Address(str1)); + zip1(vtmp, T8B, vtmp, vtmpZ); + umov(result, vtmp, D, 0); + } else { + ldr(result, Address(str1)); + } + if (isUL) { + ldrs(vtmp, Address(str2)); + zip1(vtmp, T8B, vtmp, vtmpZ); + umov(rscratch1, vtmp, D, 0); + } else { + ldr(rscratch1, Address(str2)); + } + eor(rscratch2, result, rscratch1); cbz(rscratch2, LENGTH_DIFF); // Find the first different characters in the longwords and @@ -4531,12 +4583,12 @@ bind(DIFFERENCE); rev(rscratch2, rscratch2); clz(rscratch2, rscratch2); - andr(rscratch2, rscratch2, -16); + andr(rscratch2, rscratch2, isLL ? -8 : -16); lsrv(result, result, rscratch2); - uxthw(result, result); - lsrv(cnt1, cnt1, rscratch2); - uxthw(cnt1, cnt1); - subw(result, result, cnt1); + (this->*ext_chr)(result, result); + lsrv(rscratch1, rscratch1, rscratch2); + (this->*ext_chr)(rscratch1, rscratch1); + subw(result, result, rscratch1); b(DONE); } @@ -4545,8 +4597,8 @@ cbz(cnt2, LENGTH_DIFF); bind(SHORT_LOOP); - load_unsigned_short(result, Address(post(str1, 2))); - load_unsigned_short(cnt1, Address(post(str2, 2))); + (this->*str1_load_chr)(result, Address(post(str1, str1_chr_size))); + (this->*str2_load_chr)(cnt1, Address(post(str2, str2_chr_size))); subw(result, result, cnt1); cbnz(result, DONE); sub(cnt2, cnt2, 1); diff --git a/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp --- a/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -1189,7 +1189,8 @@ void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, - Register tmp1); + Register tmp1, + FloatRegister vtmp, FloatRegister vtmpZ, int ae); void arrays_equals(Register a1, Register a2, Register result, Register cnt1, diff --git a/src/cpu/aarch64/vm/register_definitions_aarch64.cpp b/src/cpu/aarch64/vm/register_definitions_aarch64.cpp --- a/src/cpu/aarch64/vm/register_definitions_aarch64.cpp +++ b/src/cpu/aarch64/vm/register_definitions_aarch64.cpp @@ -29,6 +29,8 @@ #include "register_aarch64.hpp" # include "interp_masm_aarch64.hpp" +REGISTER_DEFINITION(Register, noreg); + REGISTER_DEFINITION(Register, r0); REGISTER_DEFINITION(Register, r1); REGISTER_DEFINITION(Register, r2); @@ -62,6 +64,8 @@ REGISTER_DEFINITION(Register, r30); REGISTER_DEFINITION(Register, sp); +REGISTER_DEFINITION(FloatRegister, fnoreg); + REGISTER_DEFINITION(FloatRegister, v0); REGISTER_DEFINITION(FloatRegister, v1); REGISTER_DEFINITION(FloatRegister, v2);