Merge "MIPS64: java.lang.String.getChars"
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 5a99886..3022e97 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -1846,6 +1846,84 @@
GenIsInfinite(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
}
+// void java.lang.String.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
+void IntrinsicLocationsBuilderMIPS64::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 conventions.
+ 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::kPrimLong);
+ locations->AddTemp(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
+ Mips64Assembler* 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);
+
+ GpuRegister srcObj = locations->InAt(0).AsRegister<GpuRegister>();
+ GpuRegister srcBegin = locations->InAt(1).AsRegister<GpuRegister>();
+ GpuRegister srcEnd = locations->InAt(2).AsRegister<GpuRegister>();
+ GpuRegister dstObj = locations->InAt(3).AsRegister<GpuRegister>();
+ GpuRegister dstBegin = locations->InAt(4).AsRegister<GpuRegister>();
+
+ GpuRegister dstPtr = locations->GetTemp(0).AsRegister<GpuRegister>();
+ DCHECK_EQ(dstPtr, A0);
+ GpuRegister srcPtr = locations->GetTemp(1).AsRegister<GpuRegister>();
+ DCHECK_EQ(srcPtr, A1);
+ GpuRegister numChrs = locations->GetTemp(2).AsRegister<GpuRegister>();
+ DCHECK_EQ(numChrs, A2);
+
+ GpuRegister dstReturn = locations->GetTemp(3).AsRegister<GpuRegister>();
+ DCHECK_EQ(dstReturn, V0);
+
+ Mips64Label 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();
+
+ __ Beqc(srcEnd, srcBegin, &done); // No characters to move.
+
+ // Calculate number of characters to be copied.
+ __ Dsubu(numChrs, srcEnd, srcBegin);
+
+ // Calculate destination address.
+ __ Daddiu(dstPtr, dstObj, data_offset);
+ __ Dlsa(dstPtr, dstBegin, dstPtr, char_shift);
+
+ // Calculate source address.
+ __ Daddiu(srcPtr, srcObj, value_offset);
+ __ Dlsa(srcPtr, srcBegin, srcPtr, char_shift);
+
+ // Calculate number of bytes to copy from number of characters.
+ __ Dsll(numChrs, numChrs, char_shift);
+
+ codegen_->InvokeRuntime(kQuickMemcpy, invoke, invoke->GetDexPc(), nullptr);
+
+ __ Bind(&done);
+}
+
static void GenHighestOneBit(LocationSummary* locations,
Primitive::Type type,
Mips64Assembler* assembler) {
@@ -1925,7 +2003,6 @@
}
UNIMPLEMENTED_INTRINSIC(MIPS64, ReferenceGetReferent)
-UNIMPLEMENTED_INTRINSIC(MIPS64, StringGetCharsNoCheck)
UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopy)
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index b34e125..5c48759 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -145,7 +145,8 @@
const std::vector<Reg2*> reg2_registers,
std::string (AssemblerTest::*GetName1)(const Reg1&),
std::string (AssemblerTest::*GetName2)(const Reg2&),
- const std::string& fmt) {
+ const std::string& fmt,
+ int bias = 0) {
std::string str;
std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
@@ -153,7 +154,7 @@
for (auto reg2 : reg2_registers) {
for (int64_t imm : imms) {
ImmType new_imm = CreateImmediate(imm);
- (assembler_.get()->*f)(*reg1, *reg2, new_imm);
+ (assembler_.get()->*f)(*reg1, *reg2, new_imm + bias);
std::string base = fmt;
std::string reg1_string = (this->*GetName1)(*reg1);
@@ -171,7 +172,7 @@
size_t imm_index = base.find(IMM_TOKEN);
if (imm_index != std::string::npos) {
std::ostringstream sreg;
- sreg << imm;
+ sreg << imm + bias;
std::string imm_string = sreg.str();
base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
}
@@ -188,6 +189,67 @@
return str;
}
+ template <typename Reg1, typename Reg2, typename Reg3, typename ImmType>
+ std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, Reg3, ImmType),
+ int imm_bits,
+ const std::vector<Reg1*> reg1_registers,
+ const std::vector<Reg2*> reg2_registers,
+ const std::vector<Reg3*> reg3_registers,
+ std::string (AssemblerTest::*GetName1)(const Reg1&),
+ std::string (AssemblerTest::*GetName2)(const Reg2&),
+ std::string (AssemblerTest::*GetName3)(const Reg3&),
+ std::string fmt,
+ int bias) {
+ std::string str;
+ std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
+
+ for (auto reg1 : reg1_registers) {
+ for (auto reg2 : reg2_registers) {
+ for (auto reg3 : reg3_registers) {
+ for (int64_t imm : imms) {
+ ImmType new_imm = CreateImmediate(imm);
+ (assembler_.get()->*f)(*reg1, *reg2, *reg3, new_imm + bias);
+ std::string base = fmt;
+
+ std::string reg1_string = (this->*GetName1)(*reg1);
+ size_t reg1_index;
+ while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
+ base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
+ }
+
+ std::string reg2_string = (this->*GetName2)(*reg2);
+ size_t reg2_index;
+ while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
+ base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
+ }
+
+ std::string reg3_string = (this->*GetName3)(*reg3);
+ size_t reg3_index;
+ while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
+ base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
+ }
+
+ size_t imm_index = base.find(IMM_TOKEN);
+ if (imm_index != std::string::npos) {
+ std::ostringstream sreg;
+ sreg << imm + bias;
+ std::string imm_string = sreg.str();
+ base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
+ }
+
+ if (str.size() > 0) {
+ str += "\n";
+ }
+ str += base;
+ }
+ }
+ }
+ }
+ // Add a newline at the end.
+ str += "\n";
+ return str;
+ }
+
template <typename ImmType, typename Reg1, typename Reg2>
std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2),
const std::vector<Reg1*> reg1_registers,
@@ -245,14 +307,15 @@
int imm_bits,
const std::vector<Reg*> registers,
std::string (AssemblerTest::*GetName)(const RegType&),
- const std::string& fmt) {
+ const std::string& fmt,
+ int bias) {
std::string str;
std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
for (auto reg : registers) {
for (int64_t imm : imms) {
ImmType new_imm = CreateImmediate(imm);
- (assembler_.get()->*f)(*reg, new_imm);
+ (assembler_.get()->*f)(*reg, new_imm + bias);
std::string base = fmt;
std::string reg_string = (this->*GetName)(*reg);
@@ -264,7 +327,7 @@
size_t imm_index = base.find(IMM_TOKEN);
if (imm_index != std::string::npos) {
std::ostringstream sreg;
- sreg << imm;
+ sreg << imm + bias;
std::string imm_string = sreg.str();
base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
}
@@ -281,36 +344,60 @@
}
template <typename ImmType>
- std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType), int imm_bits, const std::string& fmt) {
+ std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType),
+ int imm_bits,
+ const std::string& fmt,
+ int bias = 0) {
return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f,
imm_bits,
GetRegisters(),
GetRegisters(),
&AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
&AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
- fmt);
+ fmt,
+ bias);
}
template <typename ImmType>
- std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, const std::string& fmt) {
+ std::string RepeatRRRIb(void (Ass::*f)(Reg, Reg, Reg, ImmType),
+ int imm_bits,
+ const std::string& fmt,
+ int bias = 0) {
+ return RepeatTemplatedRegistersImmBits<Reg, Reg, Reg, ImmType>(f,
+ imm_bits,
+ GetRegisters(),
+ GetRegisters(),
+ GetRegisters(),
+ &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+ &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+ &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+ fmt,
+ bias);
+ }
+
+ template <typename ImmType>
+ std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt, int bias = 0) {
return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f,
imm_bits,
GetRegisters(),
&AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
- fmt);
+ fmt,
+ bias);
}
template <typename ImmType>
std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType),
int imm_bits,
- const std::string& fmt) {
+ const std::string& fmt,
+ int bias = 0) {
return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f,
imm_bits,
GetFPRegisters(),
GetRegisters(),
&AssemblerTest::GetFPRegName,
&AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
- fmt);
+ fmt,
+ bias);
}
std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), const std::string& fmt) {
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index 04430b1..5906a71 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -319,6 +319,18 @@
EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
}
+void Mips64Assembler::Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
+ CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
+ int sa = saPlusOne - 1;
+ EmitR(0x0, rs, rt, rd, sa, 0x05);
+}
+
+void Mips64Assembler::Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
+ CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
+ int sa = saPlusOne - 1;
+ EmitR(0x0, rs, rt, rd, sa, 0x15);
+}
+
void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
EmitRtd(0x1f, rt, rd, 2, 0x20);
}
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index 08a55ed..7ef5ab0 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -440,6 +440,8 @@
void Dshd(GpuRegister rd, GpuRegister rt); // MIPS64
void Dext(GpuRegister rs, GpuRegister rt, int pos, int size); // MIPS64
void Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64
+ void Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne);
+ void Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne); // MIPS64
void Wsbh(GpuRegister rd, GpuRegister rt);
void Sc(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
void Scd(GpuRegister rt, GpuRegister base, int16_t imm9 = 0); // MIPS64
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index 9d0d0fc..564559f 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -1141,6 +1141,22 @@
DriverStr(expected.str(), "Dinsu");
}
+TEST_F(AssemblerMIPS64Test, Lsa) {
+ DriverStr(RepeatRRRIb(&mips64::Mips64Assembler::Lsa,
+ 2,
+ "lsa ${reg1}, ${reg2}, ${reg3}, {imm}",
+ 1),
+ "lsa");
+}
+
+TEST_F(AssemblerMIPS64Test, Dlsa) {
+ DriverStr(RepeatRRRIb(&mips64::Mips64Assembler::Dlsa,
+ 2,
+ "dlsa ${reg1}, ${reg2}, ${reg3}, {imm}",
+ 1),
+ "dlsa");
+}
+
TEST_F(AssemblerMIPS64Test, Wsbh) {
DriverStr(RepeatRR(&mips64::Mips64Assembler::Wsbh, "wsbh ${reg1}, ${reg2}"), "wsbh");
}
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index c82600b..1f6b874 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -139,6 +139,8 @@
{ kSpecial0Mask | (0x1f << 16) | 0x7ff, (0x01 << 6) | 0x11, "clo", "DS" },
{ kSpecial0Mask | (0x1f << 16) | 0x7ff, (0x01 << 6) | 0x12, "dclz", "DS" },
{ kSpecial0Mask | (0x1f << 16) | 0x7ff, (0x01 << 6) | 0x13, "dclo", "DS" },
+ { kSpecial0Mask | 0x73f, 0x05, "lsa", "DSTj" },
+ { kSpecial0Mask | 0x73f, 0x15, "dlsa", "DSTj" },
// TODO: sdbbp
// SPECIAL2
@@ -490,6 +492,9 @@
case 'i': // Sign-extended lower 16-bit immediate.
args << static_cast<int16_t>(instruction & 0xffff);
break;
+ case 'j': // sa value for lsa/dlsa.
+ args << (sa + 1);
+ break;
case 'L': // Jump label.
{
// TODO: is this right?