< prev index next >

src/cpu/aarch64/vm/macroAssembler_aarch64.cpp

Print this page
rev 11248 : 8156943: aarch64: string compare does not support CompactStrings
Summary: Implement LL, UL and LU encodings for StrComp
Reviewed-by: aph

*** 563,577 **** andr(temp_reg, temp_reg, markOopDesc::biased_lock_mask_in_place); cmp(temp_reg, markOopDesc::biased_lock_pattern); 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); } } --- 563,572 ----
*** 4475,4554 **** BIND(MATCH); add(result, result_tmp, cnt2_neg, ASR, 1); BIND(DONE); } // Compare strings. void MacroAssembler::string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, ! Register tmp1) { Label LENGTH_DIFF, DONE, SHORT_LOOP, SHORT_STRING, NEXT_WORD, DIFFERENCE; BLOCK_COMMENT("string_compare {"); // 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); br(Assembler::LT, SHORT_STRING); // Check if the strings start at the same location. cmp(str1, str2); br(Assembler::EQ, LENGTH_DIFF); // Compare longwords { ! subw(cnt2, cnt2, 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); // 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); cbnz(rscratch2, DIFFERENCE); 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(result, Address(str1)); ! ldr(cnt1, Address(str2)); ! eor(rscratch2, result, cnt1); cbz(rscratch2, LENGTH_DIFF); // Find the first different characters in the longwords and // compute their difference. bind(DIFFERENCE); rev(rscratch2, rscratch2); clz(rscratch2, rscratch2); ! andr(rscratch2, rscratch2, -16); lsrv(result, result, rscratch2); ! uxthw(result, result); ! lsrv(cnt1, cnt1, rscratch2); ! uxthw(cnt1, cnt1); ! subw(result, result, cnt1); b(DONE); } bind(SHORT_STRING); // Is the minimum length zero? cbz(cnt2, LENGTH_DIFF); bind(SHORT_LOOP); ! load_unsigned_short(result, Address(post(str1, 2))); ! load_unsigned_short(cnt1, Address(post(str2, 2))); subw(result, result, cnt1); cbnz(result, DONE); sub(cnt2, cnt2, 1); cbnz(cnt2, SHORT_LOOP); --- 4470,4606 ---- BIND(MATCH); add(result, result_tmp, cnt2_neg, ASR, 1); 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, ! 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, isLL ? 8:4); br(Assembler::LT, SHORT_STRING); // Check if the strings start at the same location. cmp(str1, str2); br(Assembler::EQ, LENGTH_DIFF); // Compare longwords { ! 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(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); ! 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); // Last longword. In the case where length == 4 we compare the // same longword twice, but that's still faster than another // conditional branch. + 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 // compute their difference. bind(DIFFERENCE); rev(rscratch2, rscratch2); clz(rscratch2, rscratch2); ! andr(rscratch2, rscratch2, isLL ? -8 : -16); lsrv(result, result, rscratch2); ! (this->*ext_chr)(result, result); ! lsrv(rscratch1, rscratch1, rscratch2); ! (this->*ext_chr)(rscratch1, rscratch1); ! subw(result, result, rscratch1); b(DONE); } bind(SHORT_STRING); // Is the minimum length zero? cbz(cnt2, LENGTH_DIFF); bind(SHORT_LOOP); ! (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); cbnz(cnt2, SHORT_LOOP);
< prev index next >