diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/optimizing/intrinsics_mips.cc | 95 | ||||
-rw-r--r-- | compiler/utils/mips/assembler_mips.cc | 22 | ||||
-rw-r--r-- | compiler/utils/mips/assembler_mips.h | 5 | ||||
-rw-r--r-- | compiler/utils/mips/assembler_mips_test.cc | 8 |
4 files changed, 128 insertions, 2 deletions
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc index 76e6bbd880..1280587276 100644 --- a/compiler/optimizing/intrinsics_mips.cc +++ b/compiler/optimizing/intrinsics_mips.cc @@ -1780,6 +1780,99 @@ void IntrinsicCodeGeneratorMIPS::VisitUnsafePutLongVolatile(HInvoke* invoke) { 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, MathFloor) 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 7c41813457..a1798c0f70 100644 --- a/compiler/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -485,6 +485,28 @@ void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) { 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 a7179fd1dc..ffac4c4168 100644 --- a/compiler/utils/mips/assembler_mips.h +++ b/compiler/utils/mips/assembler_mips.h @@ -191,6 +191,11 @@ class MipsAssembler FINAL : public Assembler { 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 9e27f07ff2..cec43badf8 100644 --- a/compiler/utils/mips/assembler_mips_test.cc +++ b/compiler/utils/mips/assembler_mips_test.cc @@ -489,6 +489,14 @@ TEST_F(AssemblerMIPSTest, Swr) { 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"); } |