Apply String.equals() optimizations on MIPS32 and MIPS64
Also extended test 536-checker-intrinsic-optimization.
Test: mma test-art-target-run-test in QEMU (MIPS64R6 and MIPS32R6)
Test: mma test-art-target-run-test on CI20 (MIPS32R2)
Change-Id: I6bff42f81dcb05094ac698181df16c56193bb4a8
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 64a6840..5999677 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -1989,20 +1989,24 @@
__ LoadConst32(out, 1);
return;
}
-
- // Check if input is null, return false if it is.
- __ Beqz(arg, &return_false);
+ StringEqualsOptimizations optimizations(invoke);
+ if (!optimizations.GetArgumentNotNull()) {
+ // Check if input is null, return false if it is.
+ __ Beqz(arg, &return_false);
+ }
// Reference equality check, return true if same reference.
__ Beq(str, arg, &return_true);
- // Instanceof check for the argument by comparing class fields.
- // All string objects must have the same type since String cannot be subclassed.
- // Receiver must be a string object, so its class field is equal to all strings' class fields.
- // If the argument is a string object, its class field must be equal to receiver's class field.
- __ Lw(temp1, str, class_offset);
- __ Lw(temp2, arg, class_offset);
- __ Bne(temp1, temp2, &return_false);
+ if (!optimizations.GetArgumentIsString()) {
+ // Instanceof check for the argument by comparing class fields.
+ // All string objects must have the same type since String cannot be subclassed.
+ // Receiver must be a string object, so its class field is equal to all strings' class fields.
+ // If the argument is a string object, its class field must be equal to receiver's class field.
+ __ Lw(temp1, str, class_offset);
+ __ Lw(temp2, arg, class_offset);
+ __ Bne(temp1, temp2, &return_false);
+ }
// Load `count` fields of this and argument strings.
__ Lw(temp1, str, count_offset);
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 3888828..10da5c2 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -1593,19 +1593,24 @@
return;
}
- // Check if input is null, return false if it is.
- __ Beqzc(arg, &return_false);
+ StringEqualsOptimizations optimizations(invoke);
+ if (!optimizations.GetArgumentNotNull()) {
+ // Check if input is null, return false if it is.
+ __ Beqzc(arg, &return_false);
+ }
// Reference equality check, return true if same reference.
__ Beqc(str, arg, &return_true);
- // Instanceof check for the argument by comparing class fields.
- // All string objects must have the same type since String cannot be subclassed.
- // Receiver must be a string object, so its class field is equal to all strings' class fields.
- // If the argument is a string object, its class field must be equal to receiver's class field.
- __ Lw(temp1, str, class_offset);
- __ Lw(temp2, arg, class_offset);
- __ Bnec(temp1, temp2, &return_false);
+ if (!optimizations.GetArgumentIsString()) {
+ // Instanceof check for the argument by comparing class fields.
+ // All string objects must have the same type since String cannot be subclassed.
+ // Receiver must be a string object, so its class field is equal to all strings' class fields.
+ // If the argument is a string object, its class field must be equal to receiver's class field.
+ __ Lw(temp1, str, class_offset);
+ __ Lw(temp2, arg, class_offset);
+ __ Bnec(temp1, temp2, &return_false);
+ }
// Load `count` fields of this and argument strings.
__ Lw(temp1, str, count_offset);
diff --git a/test/536-checker-intrinsic-optimization/src/Main.java b/test/536-checker-intrinsic-optimization/src/Main.java
index 52f3f84..e395e28 100644
--- a/test/536-checker-intrinsic-optimization/src/Main.java
+++ b/test/536-checker-intrinsic-optimization/src/Main.java
@@ -330,6 +330,21 @@
// Terminate the scope for the CHECK-NOT search at the reference or length comparison,
// whichever comes first.
/// CHECK: cmp {{w.*,}} {{w.*|#.*}}
+
+ /// CHECK-START-MIPS: boolean Main.stringArgumentNotNull(java.lang.Object) disassembly (after)
+ /// CHECK: InvokeVirtual {{.*\.equals.*}} intrinsic:StringEquals
+ /// CHECK-NOT: beq r0,
+ /// CHECK-NOT: beqz
+ /// CHECK-NOT: beqzc
+ // Terminate the scope for the CHECK-NOT search at the class field or length comparison,
+ // whichever comes first.
+ /// CHECK: lw
+
+ /// CHECK-START-MIPS64: boolean Main.stringArgumentNotNull(java.lang.Object) disassembly (after)
+ /// CHECK: InvokeVirtual {{.*\.equals.*}} intrinsic:StringEquals
+ /// CHECK-NOT: beqzc
+ // Terminate the scope for the CHECK-NOT search at the reference comparison.
+ /// CHECK: beqc
public static boolean stringArgumentNotNull(Object obj) {
obj.getClass();
return "foo".equals(obj);
@@ -384,6 +399,22 @@
/// CHECK-NOT: ldr {{w\d+}}, [{{x\d+}}]
/// CHECK-NOT: ldr {{w\d+}}, [{{x\d+}}, #0]
/// CHECK: cmp {{w\d+}}, {{w\d+|#.*}}
+
+ // Test is brittle as it depends on the class offset being 0.
+ /// CHECK-START-MIPS: boolean Main.stringArgumentIsString() disassembly (after)
+ /// CHECK: InvokeVirtual intrinsic:StringEquals
+ /// CHECK: beq{{(zc)?}}
+ // Check that we don't try to compare the classes.
+ /// CHECK-NOT: lw {{r\d+}}, +0({{r\d+}})
+ /// CHECK: bne{{c?}}
+
+ // Test is brittle as it depends on the class offset being 0.
+ /// CHECK-START-MIPS64: boolean Main.stringArgumentIsString() disassembly (after)
+ /// CHECK: InvokeVirtual intrinsic:StringEquals
+ /// CHECK: beqzc
+ // Check that we don't try to compare the classes.
+ /// CHECK-NOT: lw {{r\d+}}, +0({{r\d+}})
+ /// CHECK: bnec
public static boolean stringArgumentIsString() {
return "foo".equals(myString);
}