[aarch64-port-dev ] String.equals()

Andrew Haley aph at redhat.com
Thu Jul 3 09:44:29 UTC 2014


As before.

I tried to combine the logic for String.equals() and String.compare()
because they should be very similar, but the result was a mess.  Ths
is better, even at the expense of some code duplication.

Andrew.



# HG changeset patch
# User aph
# Date 1404310864 14400
#      Wed Jul 02 10:21:04 2014 -0400
# Node ID fd73d7b8ba5d7b51da2289cc4239108382cf52a3
# Parent  1f7e1e16a5341f557a58c20fab339b874089da82
Fast String.equals

diff -r 1f7e1e16a534 -r fd73d7b8ba5d src/cpu/aarch64/vm/aarch64.ad
--- a/src/cpu/aarch64/vm/aarch64.ad	Fri Jun 27 06:13:30 2014 -0400
+++ b/src/cpu/aarch64/vm/aarch64.ad	Wed Jul 02 10:21:04 2014 -0400
@@ -11348,6 +11348,21 @@
   ins_pipe(pipe_class_memory);
 %}

+instruct string_equals(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt,
+                        iRegI_R0 result, iRegP tmp, rFlagsReg cr)
+%{
+  match(Set result (StrEquals (Binary str1 str2) cnt));
+  effect(TEMP tmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr);
+
+  format %{ "String Equals $str1,$str2,$cnt -> $result    // KILL $tmp" %}
+  ins_encode %{
+    __ string_equals($str1$$Register, $str2$$Register,
+		      $cnt$$Register, $result$$Register,
+                      $tmp$$Register);
+  %}
+  ins_pipe(pipe_class_memory);
+%}
+
 // ============================================================================
 // This name is KNOWN by the ADLC and cannot be changed.
 // The ADLC forces a 'TypeRawPtr::BOTTOM' output type
diff -r 1f7e1e16a534 -r fd73d7b8ba5d src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
--- a/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp	Fri Jun 27 06:13:30 2014 -0400
+++ b/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp	Wed Jul 02 10:21:04 2014 -0400
@@ -3436,3 +3436,78 @@

   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");
+}
diff -r 1f7e1e16a534 -r fd73d7b8ba5d src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
--- a/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp	Fri Jun 27 06:13:30 2014 -0400
+++ b/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp	Wed Jul 02 10:21:04 2014 -0400
@@ -1292,8 +1292,11 @@
         bool upper = false);

   void string_compare(Register str1, Register str2,
-                                    Register cnt1, Register cnt2, Register result,
-                                    Register vec1);
+		      Register cnt1, Register cnt2, Register result,
+		      Register vec1);
+  void string_equals(Register str1, Register str2,
+		     Register cnt, Register result,
+		     Register tmp1);
 };

 // Used by aarch64.ad to control code generation


More information about the aarch64-port-dev mailing list