< prev index next >

src/cpu/aarch64/vm/macroAssembler_aarch64.cpp

Print this page
rev 10236 : 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

@@ -4479,227 +4479,123 @@
   bind(DONE);
 
   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);
-  }
-
-  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)
+// 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)
 {
-  Register cnt1 = rscratch1;
-  Register cnt2 = rscratch2;
+  Label SAME, DONE, SHORT, NEXT_WORD;
+  Register cnt1 = tmp;
+  Register tmp1 = rscratch1;
   Register tmp2 = rscratch2;
-
-  Label SAME, DIFFER, NEXT, TAIL07, TAIL03, TAIL01;
-
+  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    = arrayOopDesc::base_offset_in_bytes(T_BYTE);
+  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");
+  }
+  assert_different_registers(ary1, ary2, result, cnt1, rscratch1, rscratch2);
 
-  BLOCK_COMMENT("byte_arrays_equals  {");
+  BLOCK_COMMENT("generic_arrays_equals {");
 
-    // different until proven equal
-    mov(result, false);
-
-    // same array?
+  // same array check
     cmp(ary1, ary2);
+  mov(result, false);
     br(Assembler::EQ, SAME);
 
-    // ne if either null
-    cbz(ary1, DIFFER);
-    cbz(ary2, DIFFER);
-
+  // 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);
+  // check short compare
+  subs(cnt1, cnt1, elem_per_word); // The last longword is a special case
+  br(Assembler::LT, SHORT);
 
-  BIND(NEXT);
-    ldr(tmp1, Address(post(ary1, 8)));
-    ldr(tmp2, Address(post(ary2, 8)));
-    subs(cnt1, cnt1, 8);
+  // 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);
+    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(TAIL07);  // 0-7 bytes left, cnt1 = #bytes left - 4
-    tst(cnt1, 0b100);
-    br(EQ, TAIL03);
+  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, DIFFER);
+  br(NE, DONE);
 
-  BIND(TAIL03);  // 0-3 bytes left, cnt1 = #bytes left - 4
-    tst(cnt1, 0b10);
-    br(EQ, TAIL01);
+  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, DIFFER);
-  BIND(TAIL01);  // 0-1 byte left
-    tst(cnt1, 0b01);
-    br(EQ, SAME);
+  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);
+    br(NE, DONE);
+  }
+  // same
+  bind(SAME);
     mov(result, true);
-  BIND(DIFFER); // result already set
 
-  BLOCK_COMMENT("} char_arrays_equals");
+  // That's it
+  bind(DONE);
+  BLOCK_COMMENT("} generic_arrays_equals");
 }
 
 // encode char[] to byte[] in ISO_8859_1
 void MacroAssembler::encode_iso_array(Register src, Register dst,
                       Register len, Register result,
< prev index next >