# HG changeset patch # User hshi # Date 1455881682 28800 # Fri Feb 19 03:34:42 2016 -0800 # Node ID ff07f8832c4049ec74805dd90f3df8f7732177c5 # Parent 2c3c43037e14e355dbba9a84e99b7ac74b350f28 8149733: AArch64: refactor array_equals/string_equals Summary: combine similar code for string_equals/char_array_equals/byte_array_equals into same implemenation Reviewed-by: duke 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 @@ -14911,19 +14911,18 @@ %} instruct string_equals(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt, - iRegI_R0 result, iRegP_R10 tmp, rFlagsReg cr) + iRegI_R0 result, rFlagsReg cr) %{ predicate(!CompactStrings); match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(KILL tmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); - - format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp" %} + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); + + format %{ "String Equals $str1,$str2,$cnt -> $result" %} ins_encode %{ // Count is in 8-bit bytes; non-Compact chars are 16 bits. __ asrw($cnt$$Register, $cnt$$Register, 1); - __ string_equals($str1$$Register, $str2$$Register, - $cnt$$Register, $result$$Register, - $tmp$$Register); + __ generic_arrays_equals($str1$$Register, $str2$$Register, + $result$$Register, $cnt$$Register, 2, true); %} ins_pipe(pipe_class_memory); %} @@ -14937,8 +14936,9 @@ format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %} ins_encode %{ - __ byte_arrays_equals($ary1$$Register, $ary2$$Register, - $result$$Register, $tmp$$Register); + __ generic_arrays_equals($ary1$$Register, $ary2$$Register, + $result$$Register, $tmp$$Register, + 1, false); %} ins_pipe(pipe_class_memory); %} @@ -14952,12 +14952,14 @@ format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %} ins_encode %{ - __ char_arrays_equals($ary1$$Register, $ary2$$Register, - $result$$Register, $tmp$$Register); + __ generic_arrays_equals($ary1$$Register, $ary2$$Register, + $result$$Register, $tmp$$Register, + 2, false); %} ins_pipe(pipe_class_memory); %} + // encode char[] to byte[] in ISO_8859_1 instruct encode_iso_array(iRegP_R2 src, iRegP_R1 dst, iRegI_R3 len, vRegD_V0 Vtmp1, vRegD_V1 Vtmp2, 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 @@ -4481,223 +4481,119 @@ BLOCK_COMMENT("} string_compare"); } - -void MacroAssembler::string_equals(Register str1, Register str2, - Register cnt, Register result, - Register tmp1) { - Label SAME_CHARS, DONE, SHORT_LOOP, SHORT_STRING, - NEXT_WORD; - - const Register tmp2 = rscratch1; - assert_different_registers(str1, str2, cnt, result, tmp1, tmp2, rscratch2); - - BLOCK_COMMENT("string_equals {"); - - // Start by assuming that the strings are not equal. - mov(result, zr); - - // A very short string - cmpw(cnt, 4); - br(Assembler::LT, SHORT_STRING); - - // Check if the strings start at the same location. - cmp(str1, str2); - br(Assembler::EQ, SAME_CHARS); - - // Compare longwords - { - subw(cnt, cnt, 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, cnt, Address::uxtw(1))); - lea(str2, Address(str2, cnt, Address::uxtw(1))); - sub(cnt, zr, cnt, LSL, 1); - - // Loop, loading longwords and comparing them into rscratch2. - bind(NEXT_WORD); - ldr(tmp1, Address(str1, cnt)); - ldr(tmp2, Address(str2, cnt)); - adds(cnt, cnt, wordSize); - eor(rscratch2, tmp1, tmp2); - cbnz(rscratch2, DONE); - br(Assembler::LT, NEXT_WORD); - - // Last longword. In the case where length == 4 we compare the - // same longword twice, but that's still faster than another - // conditional branch. - - ldr(tmp1, Address(str1)); - ldr(tmp2, Address(str2)); - eor(rscratch2, tmp1, tmp2); - cbz(rscratch2, SAME_CHARS); - b(DONE); +// for string equals tmp1 is string length, stepSize is 2, is_array_equal false +// for array equals byte tmp1 is temp, stepSize is 1, is_string_equal false +// for array equals char tmp1 is temp, stepSize is 2, is_string_equal false +// if is_string_equal is true, ary1 and ary2 are string's value array element 0 address. +// +// current two implenetaions +// 1. current string eqauls, comapre 8 bytes at last ieration +// 2. current array equals, split compre for tail +// +// New implemenation in this method is +// 1. for array length GE 8 bytes, compare main body and tail both in 8 bytes +// 2. for array length LT 8 bytes, compare in test-ld-cmp sequence +// only support string equals, char array equals and byte array equals now. +void MacroAssembler::generic_arrays_equals(Register ary1, Register ary2, + Register result, Register tmp, + int step_size, bool is_string_equal) +{ + Label SAME, DONE, SHORT, NEXT_WORD; + Register cnt1 = tmp; + Register tmp1 = rscratch1; + Register tmp2 = rscratch2; + int elem_per_word = wordSize/step_size; + int exact_log = exact_log2(step_size); + int length_offset = arrayOopDesc::length_offset_in_bytes(); + int base_offset = -1; + switch (step_size) { + case 1: + base_offset = arrayOopDesc::base_offset_in_bytes(T_BYTE); + break; + case 2: + base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); + break; + default: + assert(false, "unexpected step size\n"); } - - bind(SHORT_STRING); - // Is the length zero? - cbz(cnt, SAME_CHARS); - - bind(SHORT_LOOP); - load_unsigned_short(tmp1, Address(post(str1, 2))); - load_unsigned_short(tmp2, Address(post(str2, 2))); - subw(tmp1, tmp1, tmp2); - cbnz(tmp1, DONE); - sub(cnt, cnt, 1); - cbnz(cnt, SHORT_LOOP); - - // Strings are equal. - bind(SAME_CHARS); - mov(result, true); - - // That's it - bind(DONE); - - BLOCK_COMMENT("} string_equals"); -} - - -void MacroAssembler::byte_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1) -{ - Register cnt1 = rscratch1; - Register cnt2 = rscratch2; - Register tmp2 = rscratch2; - - Label SAME, DIFFER, NEXT, TAIL07, TAIL03, TAIL01; - - int length_offset = arrayOopDesc::length_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_BYTE); - - BLOCK_COMMENT("byte_arrays_equals {"); - - // different until proven equal - mov(result, false); - - // same array? - cmp(ary1, ary2); - br(Assembler::EQ, SAME); - - // ne if either null - cbz(ary1, DIFFER); - cbz(ary2, DIFFER); - + assert_different_registers(ary1, ary2, result, cnt1, rscratch1, rscratch2); + + BLOCK_COMMENT("generic_arrays_equals {"); + + // same array check + cmp(ary1, ary2); + mov(result, false); + br(Assembler::EQ, SAME); + + // extra length/NULL compare for array equals + if (is_string_equal == false) { + cbz(ary1, DONE); + cbz(ary2, DONE); // lengths ne? ldrw(cnt1, Address(ary1, length_offset)); - ldrw(cnt2, Address(ary2, length_offset)); - cmp(cnt1, cnt2); - br(Assembler::NE, DIFFER); - + ldrw(tmp2, Address(ary2, length_offset)); + cmp(cnt1, tmp2); + br(Assembler::NE, DONE); lea(ary1, Address(ary1, base_offset)); lea(ary2, Address(ary2, base_offset)); - - subs(cnt1, cnt1, 8); - br(LT, TAIL07); - - BIND(NEXT); - ldr(tmp1, Address(post(ary1, 8))); - ldr(tmp2, Address(post(ary2, 8))); - subs(cnt1, cnt1, 8); + } + + // check short compare + subs(cnt1, cnt1, elem_per_word); // The last longword is a special case + br(Assembler::LT, SHORT); + + // 8 bytes compare + bind(NEXT_WORD); + ldr(tmp1, Address(post(ary1, wordSize))); + ldr(tmp2, Address(post(ary2, wordSize))); + subs(cnt1, cnt1, elem_per_word); eor(tmp1, tmp1, tmp2); - cbnz(tmp1, DIFFER); - br(GE, NEXT); - - BIND(TAIL07); // 0-7 bytes left, cnt1 = #bytes left - 4 - tst(cnt1, 0b100); - br(EQ, TAIL03); - ldrw(tmp1, Address(post(ary1, 4))); - ldrw(tmp2, Address(post(ary2, 4))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(TAIL03); // 0-3 bytes left, cnt1 = #bytes left - 4 - tst(cnt1, 0b10); - br(EQ, TAIL01); - ldrh(tmp1, Address(post(ary1, 2))); - ldrh(tmp2, Address(post(ary2, 2))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - BIND(TAIL01); // 0-1 byte left - tst(cnt1, 0b01); - br(EQ, SAME); + cbnz(tmp1, DONE); + br(GT, NEXT_WORD); + // Last longword. In the case where length == 4 we compare the + // same longword twice, but that's still faster than another + // conditional branch. + // cnt1 could be 0,-1,-2,-3,-4 for chars,-4 only happens when length is 4 + if (exact_log >0 ) { + add(cnt1, zr, cnt1, Assembler::LSL, exact_log); + } + ldr(tmp1, Address(ary1, cnt1)); + ldr(tmp2, Address(ary2, cnt1)); + eor(tmp1, tmp1, tmp2); + cbnz(tmp1, DONE); + b(SAME); + + bind(SHORT); + Label TAIL03, TAIL01; + + tbz(cnt1, 2-exact_log, TAIL03); + ldrw(tmp1, Address(post(ary1, 4))); + ldrw(tmp2, Address(post(ary2, 4))); + cmp(tmp1, tmp2); + br(NE, DONE); + + bind(TAIL03); + tbz(cnt1, 1-exact_log, TAIL01); + ldrh(tmp1, Address(post(ary1, 2))); + ldrh(tmp2, Address(post(ary2, 2))); + cmp(tmp1, tmp2); + br(NE, DONE); + + bind(TAIL01); + if (step_size == 1) { + tbz(cnt1, 0, SAME); ldrb(tmp1, ary1); ldrb(tmp2, ary2); cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(SAME); - mov(result, true); - BIND(DIFFER); // result already set - - BLOCK_COMMENT("} byte_arrays_equals"); -} - -// Compare char[] arrays aligned to 4 bytes -void MacroAssembler::char_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1) -{ - Register cnt1 = rscratch1; - Register cnt2 = rscratch2; - Register tmp2 = rscratch2; - - Label SAME, DIFFER, NEXT, TAIL03, TAIL01; - - int length_offset = arrayOopDesc::length_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - BLOCK_COMMENT("char_arrays_equals {"); - - // different until proven equal - mov(result, false); - - // same array? - cmp(ary1, ary2); - br(Assembler::EQ, SAME); - - // ne if either null - cbz(ary1, DIFFER); - cbz(ary2, DIFFER); - - // lengths ne? - ldrw(cnt1, Address(ary1, length_offset)); - ldrw(cnt2, Address(ary2, length_offset)); - cmp(cnt1, cnt2); - br(Assembler::NE, DIFFER); - - lea(ary1, Address(ary1, base_offset)); - lea(ary2, Address(ary2, base_offset)); - - subs(cnt1, cnt1, 4); - br(LT, TAIL03); - - BIND(NEXT); - ldr(tmp1, Address(post(ary1, 8))); - ldr(tmp2, Address(post(ary2, 8))); - subs(cnt1, cnt1, 4); - eor(tmp1, tmp1, tmp2); - cbnz(tmp1, DIFFER); - br(GE, NEXT); - - BIND(TAIL03); // 0-3 chars left, cnt1 = #chars left - 4 - tst(cnt1, 0b10); - br(EQ, TAIL01); - ldrw(tmp1, Address(post(ary1, 4))); - ldrw(tmp2, Address(post(ary2, 4))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - BIND(TAIL01); // 0-1 chars left - tst(cnt1, 0b01); - br(EQ, SAME); - ldrh(tmp1, ary1); - ldrh(tmp2, ary2); - cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(SAME); - mov(result, true); - BIND(DIFFER); // result already set - - BLOCK_COMMENT("} char_arrays_equals"); + br(NE, DONE); + } + // same + bind(SAME); + mov(result, true); + + // That's it + bind(DONE); + BLOCK_COMMENT("} generic_arrays_equals"); } // encode char[] to byte[] in ISO_8859_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 @@ -1186,13 +1186,11 @@ void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, Register tmp1); - void string_equals(Register str1, Register str2, - Register cnt, Register result, - Register tmp1); - void char_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1); - void byte_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1); + + void generic_arrays_equals(Register ary1, Register ary2, + Register result, Register tmp, + int step_size, bool is_string_equal); + void encode_iso_array(Register src, Register dst, Register len, Register result, FloatRegister Vtmp1, FloatRegister Vtmp2,