Merge "MIPS32: Implement UnsafeCASInt and UnsafeCASObject intrinsics."
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 76e6bbd..1280587 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -1780,6 +1780,99 @@
codegen_);
}
+static void CreateIntIntIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
+ LocationSummary* locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kNoCall,
+ kIntrinsified);
+ locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetInAt(2, Location::RequiresRegister());
+ locations->SetInAt(3, Location::RequiresRegister());
+ locations->SetInAt(4, Location::RequiresRegister());
+
+ locations->SetOut(Location::RequiresRegister());
+}
+
+static void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorMIPS* codegen) {
+ MipsAssembler* assembler = codegen->GetAssembler();
+ bool isR6 = codegen->GetInstructionSetFeatures().IsR6();
+ Register base = locations->InAt(1).AsRegister<Register>();
+ Register offset_lo = locations->InAt(2).AsRegisterPairLow<Register>();
+ Register expected = locations->InAt(3).AsRegister<Register>();
+ Register value = locations->InAt(4).AsRegister<Register>();
+ Register out = locations->Out().AsRegister<Register>();
+
+ DCHECK_NE(base, out);
+ DCHECK_NE(offset_lo, out);
+ DCHECK_NE(expected, out);
+
+ if (type == Primitive::kPrimNot) {
+ // Mark card for object assuming new value is stored.
+ codegen->MarkGCCard(base, value);
+ }
+
+ // do {
+ // tmp_value = [tmp_ptr] - expected;
+ // } while (tmp_value == 0 && failure([tmp_ptr] <- r_new_value));
+ // result = tmp_value != 0;
+
+ MipsLabel loop_head, exit_loop;
+ __ Addu(TMP, base, offset_lo);
+ __ Sync(0);
+ __ Bind(&loop_head);
+ if ((type == Primitive::kPrimInt) || (type == Primitive::kPrimNot)) {
+ if (isR6) {
+ __ LlR6(out, TMP);
+ } else {
+ __ LlR2(out, TMP);
+ }
+ } else {
+ LOG(FATAL) << "Unsupported op size " << type;
+ UNREACHABLE();
+ }
+ __ Subu(out, out, expected); // If we didn't get the 'expected'
+ __ Sltiu(out, out, 1); // value, set 'out' to false, and
+ __ Beqz(out, &exit_loop); // return.
+ __ Move(out, value); // Use 'out' for the 'store conditional' instruction.
+ // If we use 'value' directly, we would lose 'value'
+ // in the case that the store fails. Whether the
+ // store succeeds, or fails, it will load the
+ // correct boolean value into the 'out' register.
+ // This test isn't really necessary. We only support Primitive::kPrimInt,
+ // Primitive::kPrimNot, and we already verified that we're working on one
+ // of those two types. It's left here in case the code needs to support
+ // other types in the future.
+ if ((type == Primitive::kPrimInt) || (type == Primitive::kPrimNot)) {
+ if (isR6) {
+ __ ScR6(out, TMP);
+ } else {
+ __ ScR2(out, TMP);
+ }
+ }
+ __ Beqz(out, &loop_head); // If we couldn't do the read-modify-write
+ // cycle atomically then retry.
+ __ Bind(&exit_loop);
+ __ Sync(0);
+}
+
+// boolean sun.misc.Unsafe.compareAndSwapInt(Object o, long offset, int expected, int x)
+void IntrinsicLocationsBuilderMIPS::VisitUnsafeCASInt(HInvoke* invoke) {
+ CreateIntIntIntIntIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitUnsafeCASInt(HInvoke* invoke) {
+ GenCas(invoke->GetLocations(), Primitive::kPrimInt, codegen_);
+}
+
+// boolean sun.misc.Unsafe.compareAndSwapObject(Object o, long offset, Object expected, Object x)
+void IntrinsicLocationsBuilderMIPS::VisitUnsafeCASObject(HInvoke* invoke) {
+ CreateIntIntIntIntIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitUnsafeCASObject(HInvoke* invoke) {
+ GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_);
+}
+
// char java.lang.String.charAt(int index)
void IntrinsicLocationsBuilderMIPS::VisitStringCharAt(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
@@ -2347,9 +2440,7 @@
UNIMPLEMENTED_INTRINSIC(MIPS, MathRint)
UNIMPLEMENTED_INTRINSIC(MIPS, MathRoundDouble)
UNIMPLEMENTED_INTRINSIC(MIPS, MathRoundFloat)
-UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASInt)
UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASLong)
-UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASObject)
UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(MIPS, StringGetCharsNoCheck)
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index 7c41813..a1798c0 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -485,6 +485,28 @@
EmitI(0x2e, rs, rt, imm16);
}
+void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) {
+ CHECK(!IsR6());
+ EmitI(0x30, base, rt, imm16);
+}
+
+void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) {
+ CHECK(!IsR6());
+ EmitI(0x38, base, rt, imm16);
+}
+
+void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) {
+ CHECK(IsR6());
+ CHECK(IsInt<9>(imm9));
+ EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36);
+}
+
+void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) {
+ CHECK(IsR6());
+ CHECK(IsInt<9>(imm9));
+ EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26);
+}
+
void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
EmitR(0, rs, rt, rd, 0, 0x2a);
}
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index a7179fd..ffac4c4 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -191,6 +191,11 @@
void Swl(Register rt, Register rs, uint16_t imm16);
void Swr(Register rt, Register rs, uint16_t imm16);
+ void LlR2(Register rt, Register base, int16_t imm16 = 0);
+ void ScR2(Register rt, Register base, int16_t imm16 = 0);
+ void LlR6(Register rt, Register base, int16_t imm9 = 0);
+ void ScR6(Register rt, Register base, int16_t imm9 = 0);
+
void Slt(Register rd, Register rs, Register rt);
void Sltu(Register rd, Register rs, Register rt);
void Slti(Register rt, Register rs, uint16_t imm16);
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index 9e27f07..cec43ba 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -489,6 +489,14 @@
DriverStr(RepeatRRIb(&mips::MipsAssembler::Swr, -16, "swr ${reg1}, {imm}(${reg2})"), "Swr");
}
+TEST_F(AssemblerMIPSTest, LlR2) {
+ DriverStr(RepeatRRIb(&mips::MipsAssembler::LlR2, -16, "ll ${reg1}, {imm}(${reg2})"), "LlR2");
+}
+
+TEST_F(AssemblerMIPSTest, ScR2) {
+ DriverStr(RepeatRRIb(&mips::MipsAssembler::ScR2, -16, "sc ${reg1}, {imm}(${reg2})"), "ScR2");
+}
+
TEST_F(AssemblerMIPSTest, Slt) {
DriverStr(RepeatRRR(&mips::MipsAssembler::Slt, "slt ${reg1}, ${reg2}, ${reg3}"), "Slt");
}
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index 428266f..a95ea64 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -317,6 +317,7 @@
{ kITypeMask, 42u << kOpcodeShift, "swl", "TO", },
{ kITypeMask, 43u << kOpcodeShift, "sw", "TO", },
{ kITypeMask, 46u << kOpcodeShift, "swr", "TO", },
+ { kITypeMask, 48u << kOpcodeShift, "ll", "TO", },
{ kITypeMask, 49u << kOpcodeShift, "lwc1", "tO", },
{ kJTypeMask, 50u << kOpcodeShift, "bc", "P" },
{ kITypeMask, 53u << kOpcodeShift, "ldc1", "tO", },
@@ -327,6 +328,7 @@
{ kITypeMask | (1 << 24), (54u << kOpcodeShift) | (1 << 24), "beqzc", "Sb" },
{ kITypeMask | (1 << 25), (54u << kOpcodeShift) | (1 << 25), "beqzc", "Sb" },
{ kITypeMask, 55u << kOpcodeShift, "ld", "TO", },
+ { kITypeMask, 56u << kOpcodeShift, "sc", "TO", },
{ kITypeMask, 57u << kOpcodeShift, "swc1", "tO", },
{ kITypeMask | (0x1f << 16), (59u << kOpcodeShift) | (30 << 16), "auipc", "Si" },
{ kITypeMask | (0x3 << 19), (59u << kOpcodeShift) | (0 << 19), "addiupc", "Sp" },