MIPS32: java.lang.String.getChars
Use memcpy(3) to copy characters under the assumption that memcpy()
has been hand optimized for best performance on the platform being
tested.
Test: run-test --optimizing 020-string
Test: run-test 020-string
Test: run-test --no-prebuild --optimizing 020-string
Test: run-test --no-prebuild 020-string
Test: run-test --optimizing 082-inline-execute
Test: run-test 082-inline-execute
Test: run-test --no-prebuild --optimizing 082-inline-execute
Test: run-test --no-prebuild 082-inline-execute
Test: mma -j2 ART_TEST_OPTIMIZING=true test-art-target-run-test
Test: booted MIPS32R2 emulator.
Note: Tested against both the MIPS32R2, and MIPS64R6 emulators.
Change-Id: I4192cf6244db120c8de5cc4932d4132acfc9740d
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 9b5d7a0..bc35772 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -2464,6 +2464,94 @@
__ Bind(&done);
}
+// void java.lang.String.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
+void IntrinsicLocationsBuilderMIPS::VisitStringGetCharsNoCheck(HInvoke* invoke) {
+ LocationSummary* locations = new (arena_) LocationSummary(invoke,
+ LocationSummary::kCallOnMainOnly,
+ kIntrinsified);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetInAt(2, Location::RequiresRegister());
+ locations->SetInAt(3, Location::RequiresRegister());
+ locations->SetInAt(4, Location::RequiresRegister());
+
+ // We will call memcpy() to do the actual work. Allocate the temporary
+ // registers to use the correct input registers, and output register.
+ // memcpy() uses the normal MIPS calling convention.
+ InvokeRuntimeCallingConvention calling_convention;
+
+ locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+ locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+ locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
+
+ Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
+ locations->AddTemp(Location::RegisterLocation(outLocation.AsRegister<Register>()));
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitStringGetCharsNoCheck(HInvoke* invoke) {
+ MipsAssembler* assembler = GetAssembler();
+ LocationSummary* locations = invoke->GetLocations();
+
+ // Check assumption that sizeof(Char) is 2 (used in scaling below).
+ const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+ DCHECK_EQ(char_size, 2u);
+ const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
+
+ Register srcObj = locations->InAt(0).AsRegister<Register>();
+ Register srcBegin = locations->InAt(1).AsRegister<Register>();
+ Register srcEnd = locations->InAt(2).AsRegister<Register>();
+ Register dstObj = locations->InAt(3).AsRegister<Register>();
+ Register dstBegin = locations->InAt(4).AsRegister<Register>();
+
+ Register dstPtr = locations->GetTemp(0).AsRegister<Register>();
+ DCHECK_EQ(dstPtr, A0);
+ Register srcPtr = locations->GetTemp(1).AsRegister<Register>();
+ DCHECK_EQ(srcPtr, A1);
+ Register numChrs = locations->GetTemp(2).AsRegister<Register>();
+ DCHECK_EQ(numChrs, A2);
+
+ Register dstReturn = locations->GetTemp(3).AsRegister<Register>();
+ DCHECK_EQ(dstReturn, V0);
+
+ MipsLabel done;
+
+ // Location of data in char array buffer.
+ const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
+
+ // Get offset of value field within a string object.
+ const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
+
+ __ Beq(srcEnd, srcBegin, &done); // No characters to move.
+
+ // Calculate number of characters to be copied.
+ __ Subu(numChrs, srcEnd, srcBegin);
+
+ // Calculate destination address.
+ __ Addiu(dstPtr, dstObj, data_offset);
+ if (IsR6()) {
+ __ Lsa(dstPtr, dstBegin, dstPtr, char_shift);
+ } else {
+ __ Sll(AT, dstBegin, char_shift);
+ __ Addu(dstPtr, dstPtr, AT);
+ }
+
+ // Calculate source address.
+ __ Addiu(srcPtr, srcObj, value_offset);
+ if (IsR6()) {
+ __ Lsa(srcPtr, srcBegin, srcPtr, char_shift);
+ } else {
+ __ Sll(AT, srcBegin, char_shift);
+ __ Addu(srcPtr, srcPtr, AT);
+ }
+
+ // Calculate number of bytes to copy from number of characters.
+ __ Sll(numChrs, numChrs, char_shift);
+
+ codegen_->InvokeRuntime(kQuickMemcpy, invoke, invoke->GetDexPc(), nullptr);
+
+ __ Bind(&done);
+}
+
// Unimplemented intrinsics.
UNIMPLEMENTED_INTRINSIC(MIPS, MathCeil)
@@ -2473,7 +2561,6 @@
UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASLong)
UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
-UNIMPLEMENTED_INTRINSIC(MIPS, StringGetCharsNoCheck)
UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy)
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index 3dcad6a..5e83e82 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -635,6 +635,13 @@
DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04), rd, rd, rt);
}
+void MipsAssembler::Lsa(Register rd, Register rs, Register rt, int saPlusOne) {
+ CHECK(IsR6());
+ CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
+ int sa = saPlusOne - 1;
+ DsFsmInstrRrr(EmitR(0x0, rs, rt, rd, sa, 0x05), rd, rs, rt);
+}
+
void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
DsFsmInstrRrr(EmitI(0x20, rs, rt, imm16), rt, rs, rs);
}
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 800dc5f..2fca185 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -262,6 +262,7 @@
void Srav(Register rd, Register rt, Register rs);
void Ext(Register rd, Register rt, int pos, int size); // R2+
void Ins(Register rd, Register rt, int pos, int size); // R2+
+ void Lsa(Register rd, Register rs, Register rt, int saPlusOne); // R6
void Lb(Register rt, Register rs, uint16_t imm16);
void Lh(Register rt, Register rs, uint16_t imm16);
diff --git a/compiler/utils/mips/assembler_mips32r6_test.cc b/compiler/utils/mips/assembler_mips32r6_test.cc
index a52f519..30667ef 100644
--- a/compiler/utils/mips/assembler_mips32r6_test.cc
+++ b/compiler/utils/mips/assembler_mips32r6_test.cc
@@ -319,6 +319,14 @@
DriverStr(RepeatRR(&mips::MipsAssembler::Bitswap, "bitswap ${reg1}, ${reg2}"), "bitswap");
}
+TEST_F(AssemblerMIPS32r6Test, Lsa) {
+ DriverStr(RepeatRRRIb(&mips::MipsAssembler::Lsa,
+ 2,
+ "lsa ${reg1}, ${reg2}, ${reg3}, {imm}",
+ 1),
+ "lsa");
+}
+
TEST_F(AssemblerMIPS32r6Test, Seleqz) {
DriverStr(RepeatRRR(&mips::MipsAssembler::Seleqz, "seleqz ${reg1}, ${reg2}, ${reg3}"),
"seleqz");