ART: ARM64 art_quick_string_compareto

A simple implementation of the assembly stub for ARM64.

Make the string_compareto test in stub_test more interesting by
having strings with offsets in their backing arrays.

Change-Id: Ibc3a1bdb70e3764baa6b8e793987166c67b6fb39
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 85a2c9e..7b66613 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1435,4 +1435,118 @@
 UNIMPLEMENTED art_quick_shr_long
 UNIMPLEMENTED art_quick_ushr_long
 UNIMPLEMENTED art_quick_indexof
-UNIMPLEMENTED art_quick_string_compareto
+
+   /*
+     * String's compareTo.
+     *
+     * TODO: Not very optimized.
+     *
+     * On entry:
+     *    x0:   this object pointer
+     *    x1:   comp object pointer
+     *
+     */
+    .extern __memcmp16
+ENTRY art_quick_string_compareto
+    mov    x2, x0         // x0 is return, use x2 for first input.
+    sub    x0, x2, x1     // Same string object?
+    cbnz   x0,1f
+    ret
+1:                        // Different string objects.
+
+    ldr    w6, [x2, #STRING_OFFSET_OFFSET]
+    ldr    w5, [x1, #STRING_OFFSET_OFFSET]
+    ldr    w4, [x2, #STRING_COUNT_OFFSET]
+    ldr    w3, [x1, #STRING_COUNT_OFFSET]
+    ldr    w2, [x2, #STRING_VALUE_OFFSET]
+    ldr    w1, [x1, #STRING_VALUE_OFFSET]
+
+    /*
+     * Now:           CharArray*    Offset   Count
+     *    first arg      x2          w6        w4
+     *   second arg      x1          w5        w3
+     */
+
+    // x0 := str1.length(w4) - str2.length(w3). ldr zero-extended w3/w4 into x3/x4.
+    subs x0, x4, x3
+    // Min(count1, count2) into w3.
+    csel x3, x3, x4, ge
+
+    // Build pointer into string data.
+
+    // Add offset in array (substr etc.) (sign extend and << 1).
+    add x2, x2, w6, sxtw #1
+    add x1, x1, w5, sxtw #1
+
+    // Add offset in CharArray to array.
+    add x2, x2, #STRING_DATA_OFFSET
+    add x1, x1, #STRING_DATA_OFFSET
+
+    // Check for long string, do memcmp16 for them.
+    cmp w3, #28  // Constant from arm32.
+    bgt .Ldo_memcmp16
+
+    /*
+     * Now:
+     *   x2: *first string data
+     *   x1: *second string data
+     *   w3: iteration count
+     *   x0: return value if comparison equal
+     *   x4, x5, x6, x7: free
+     */
+
+    // Do a simple unrolled loop.
+.Lloop:
+    // At least two more elements?
+    subs w3, w3, #2
+    b.lt .Lremainder_or_done
+
+    ldrh w4, [x2], #2
+    ldrh w5, [x1], #2
+
+    ldrh w6, [x2], #2
+    ldrh w7, [x1], #2
+
+    subs w4, w4, w5
+    b.ne .Lw4_result
+
+    subs w6, w6, w7
+    b.ne .Lw6_result
+
+    b .Lloop
+
+.Lremainder_or_done:
+    adds w3, w3, #1
+    b.eq .Lremainder
+    ret
+
+.Lremainder:
+    ldrh w4, [x2], #2
+    ldrh w5, [x1], #2
+    subs w4, w4, w5
+    b.ne .Lw4_result
+    ret
+
+// Result is in w4
+.Lw4_result:
+    sxtw x0, w4
+    ret
+
+// Result is in w6
+.Lw6_result:
+    sxtw x0, w6
+    ret
+
+.Ldo_memcmp16:
+    str x0, [sp,#-16]!           // Save x0
+
+    mov x0, x2
+    uxtw x2, w3
+    bl __memcmp16
+
+    ldr x1, [sp], #16            // Restore old x0 = length diff
+
+    cmp x0, #0                   // Check the memcmp difference
+    csel x0, x0, x1, ne          // x0 := x0 != 0 ? x0 : x1
+    ret
+END art_quick_string_compareto
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 1a93767..94a7598 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -784,14 +784,14 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
 extern "C" void art_quick_string_compareto(void);
 #endif
 
 TEST_F(StubTest, StringCompareTo) {
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
-#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
   // TODO: Check the "Unresolved" allocation stubs
 
   Thread* self = Thread::Current();