From 2db3e269e3051dacb3c8a4af8f03fdad9b0fd740 Mon Sep 17 00:00:00 2001 From: Douglas Leung Date: Wed, 25 Jun 2014 16:02:55 -0700 Subject: Fix quick mode bugs for Mips. This patch enable quick mode for Mips and allows the emulator to boot. However the emulator is still not 100% functional. It still have problems launching some apps. Change-Id: Id46a39a649a2fd431a9f13b06ecf34cbd1d20930 Signed-off-by: Douglas Leung --- compiler/dex/quick/gen_common.cc | 5 ++- compiler/dex/quick/gen_invoke.cc | 15 +++++-- compiler/dex/quick/mips/codegen_mips.h | 5 ++- compiler/dex/quick/mips/int_mips.cc | 9 +++- compiler/dex/quick/mips/mips_lir.h | 25 +++++++++++ compiler/dex/quick/mips/target_mips.cc | 28 ++++++++++++- compiler/dex/quick/mips/utility_mips.cc | 73 +++++++++++++++------------------ compiler/dex/quick/ralloc_util.cc | 8 +++- dex2oat/dex2oat.cc | 4 +- runtime/instruction_set.h | 3 +- 10 files changed, 119 insertions(+), 56 deletions(-) diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index b00cbeb..04a23cf 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -749,11 +749,12 @@ void Mir2Lir::GenSget(MIR* mir, RegLocation rl_dest, } else { GenSgetCall<4>(this, is_long_or_double, is_object, &field_info); } + // FIXME: pGetXXStatic always return an int or int64 regardless of rl_dest.fp. if (is_long_or_double) { - RegLocation rl_result = GetReturnWide(LocToRegClass(rl_dest)); + RegLocation rl_result = GetReturnWide(kCoreReg); StoreValueWide(rl_dest, rl_result); } else { - RegLocation rl_result = GetReturn(LocToRegClass(rl_dest)); + RegLocation rl_result = GetReturn(rl_dest.ref ? kRefReg : kCoreReg); StoreValue(rl_dest, rl_result); } } diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 008ebfb..569c97f 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -153,13 +153,14 @@ void Mir2Lir::CallRuntimeHelperRegLocation(ThreadOffset helper_off RegLocation arg0, bool safepoint_pc) { RegStorage r_tgt = CallHelperSetup(helper_offset); if (arg0.wide == 0) { - LoadValueDirectFixed(arg0, TargetReg(kArg0)); + LoadValueDirectFixed(arg0, TargetReg(arg0.fp ? kFArg0 : kArg0)); } else { RegStorage r_tmp; if (cu_->target64) { r_tmp = RegStorage::Solo64(TargetReg(kArg0).GetReg()); } else { - r_tmp = RegStorage::MakeRegPair(TargetReg(kArg0), TargetReg(kArg1)); + r_tmp = RegStorage::MakeRegPair(TargetReg(arg0.fp ? kFArg0 : kArg0), + TargetReg(arg0.fp ? kFArg1 : kArg1)); } LoadValueDirectWideFixed(arg0, r_tmp); } @@ -190,7 +191,12 @@ void Mir2Lir::CallRuntimeHelperImmRegLocation(ThreadOffset helper_ if (cu_->target64) { r_tmp = RegStorage::Solo64(TargetReg(kArg1).GetReg()); } else { - r_tmp = RegStorage::MakeRegPair(TargetReg(kArg1), TargetReg(kArg2)); + if (cu_->instruction_set == kMips) { + // skip kArg1 for stack alignment. + r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3)); + } else { + r_tmp = RegStorage::MakeRegPair(TargetReg(kArg1), TargetReg(kArg2)); + } } LoadValueDirectWideFixed(arg1, r_tmp); } @@ -304,7 +310,8 @@ void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset if (arg1.fp) { r_tmp = RegStorage::MakeRegPair(TargetReg(kFArg2), TargetReg(kFArg3)); } else { - r_tmp = RegStorage::MakeRegPair(TargetReg(kArg1), TargetReg(kArg2)); + // skip kArg1 for stack alignment. + r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3)); } LoadValueDirectWideFixed(arg1, r_tmp); } else { diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h index c0ad916..61a047d 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -50,6 +50,7 @@ class MipsMir2Lir FINAL : public Mir2Lir { void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg); // Required for target - register utilities. + RegStorage Solo64ToPair64(RegStorage reg); RegStorage TargetReg(SpecialTargetRegister reg); RegStorage GetArgMappingToPhysicalReg(int arg_num); RegLocation GetReturnAlt(); @@ -181,10 +182,10 @@ class MipsMir2Lir FINAL : public Mir2Lir { // TODO: collapse r_dest. LIR* LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest, - RegStorage r_dest_hi, OpSize size); + OpSize size); // TODO: collapse r_src. LIR* StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src, - RegStorage r_src_hi, OpSize size); + OpSize size); void SpillCoreRegs(); void UnSpillCoreRegs(); static const MipsEncodingMap EncodingMap[kMipsLast]; diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc index 903a770..cd29e78 100644 --- a/compiler/dex/quick/mips/int_mips.cc +++ b/compiler/dex/quick/mips/int_mips.cc @@ -485,9 +485,11 @@ void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array, int len_offset = mirror::Array::LengthOffset().Int32Value(); int data_offset; RegLocation rl_result; - rl_array = LoadValue(rl_array, kCoreReg); + rl_array = LoadValue(rl_array, kRefReg); rl_index = LoadValue(rl_index, kCoreReg); + // FIXME: need to add support for rl_index.is_const. + if (size == k64 || size == kDouble) { data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); } else { @@ -558,8 +560,11 @@ void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); } - rl_array = LoadValue(rl_array, kCoreReg); + rl_array = LoadValue(rl_array, kRefReg); rl_index = LoadValue(rl_index, kCoreReg); + + // FIXME: need to add support for rl_index.is_const. + RegStorage reg_ptr; bool allocated_reg_ptr_temp = false; if (IsTemp(rl_array.reg) && !card_mark) { diff --git a/compiler/dex/quick/mips/mips_lir.h b/compiler/dex/quick/mips/mips_lir.h index 5b2cb9d..495eb16 100644 --- a/compiler/dex/quick/mips/mips_lir.h +++ b/compiler/dex/quick/mips/mips_lir.h @@ -138,6 +138,10 @@ enum MipsResourceEncodingPos { #define ENCODE_MIPS_REG_HI (1ULL << kMipsRegHI) #define ENCODE_MIPS_REG_LO (1ULL << kMipsRegLO) +// Set FR_BIT to 0 +// This bit determines how the CPU access FP registers. +#define FR_BIT 0 + enum MipsNativeRegisterPool { rZERO = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 0, rAT = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 1, @@ -210,6 +214,26 @@ enum MipsNativeRegisterPool { rF30 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 30, rF31 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 31, #endif +#if (FR_BIT == 0) + rD0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 0, + rD1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 2, + rD2 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 4, + rD3 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 6, + rD4 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 8, + rD5 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10, + rD6 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12, + rD7 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14, +#if 0 // TODO: expand resource mask to enable use of all MIPS fp registers. + rD8 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 16, + rD9 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 18, + rD10 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 20, + rD11 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 22, + rD12 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 24, + rD13 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 26, + rD14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 28, + rD15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 30, +#endif +#else rD0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 0, rD1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 1, rD2 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 2, @@ -228,6 +252,7 @@ enum MipsNativeRegisterPool { rD14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14, rD15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15, #endif +#endif }; constexpr RegStorage rs_rZERO(RegStorage::kValid | rZERO); diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc index 76b5243..1d02cf7 100644 --- a/compiler/dex/quick/mips/target_mips.cc +++ b/compiler/dex/quick/mips/target_mips.cc @@ -75,6 +75,13 @@ RegLocation MipsMir2Lir::LocCReturnDouble() { return mips_loc_c_return_double; } +// Convert k64BitSolo into k64BitPair +RegStorage MipsMir2Lir::Solo64ToPair64(RegStorage reg) { + DCHECK(reg.IsDouble()); + int reg_num = (reg.GetRegNum() & ~1) | RegStorage::kFloatingPoint; + return RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1); +} + // Return a target-dependent special register. RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) { RegStorage res_reg; @@ -123,7 +130,11 @@ RegStorage MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) { ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const { return reg.IsDouble() /* Each double register is equal to a pair of single-precision FP registers */ +#if (FR_BIT == 0) + ? ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0) +#else ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0) +#endif : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kMipsFPReg0 : reg.GetRegNum()); } @@ -443,7 +454,11 @@ void MipsMir2Lir::CompilerInitializeRegAlloc() { GrowableArray::Iterator it(®_pool_->sp_regs_); for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) { int sp_reg_num = info->GetReg().GetRegNum(); +#if (FR_BIT == 0) + int dp_reg_num = sp_reg_num & ~1; +#else int dp_reg_num = sp_reg_num >> 1; +#endif RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num); RegisterInfo* dp_reg_info = GetRegInfo(dp_reg); // Double precision register's master storage should refer to itself. @@ -462,7 +477,11 @@ void MipsMir2Lir::CompilerInitializeRegAlloc() { // TODO: adjust when we roll to hard float calling convention. reg_pool_->next_core_reg_ = 2; reg_pool_->next_sp_reg_ = 2; +#if (FR_BIT == 0) + reg_pool_->next_dp_reg_ = 2; +#else reg_pool_->next_dp_reg_ = 1; +#endif } /* @@ -531,8 +550,13 @@ bool MipsMir2Lir::SupportsVolatileLoadStore(OpSize size) { } RegisterClass MipsMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) { - // No support for 64-bit atomic load/store on mips. - DCHECK(size != k64 && size != kDouble); + if (UNLIKELY(is_volatile)) { + // On Mips, atomic 64-bit load/store requires an fp register. + // Smaller aligned load/store is atomic for both core and fp registers. + if (size == k64 || size == kDouble) { + return kFPReg; + } + } // TODO: Verify that both core and fp registers are suitable for smaller sizes. return RegClassBySize(size); } diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc index b49f436..d28abbf 100644 --- a/compiler/dex/quick/mips/utility_mips.cc +++ b/compiler/dex/quick/mips/utility_mips.cc @@ -342,6 +342,10 @@ LIR* MipsMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, R LIR* MipsMir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) { LIR *res; + if (!r_dest.IsPair()) { + // Form 64-bit pair + r_dest = Solo64ToPair64(r_dest); + } res = LoadConstantNoClobber(r_dest.GetLow(), Low32Bits(value)); LoadConstantNoClobber(r_dest.GetHigh(), High32Bits(value)); return res; @@ -448,7 +452,7 @@ LIR* MipsMir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegSto // FIXME: don't split r_dest into 2 containers. LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest, - RegStorage r_dest_hi, OpSize size) { + OpSize size) { /* * Load value from base + displacement. Optionally perform null check * on base (which must have an associated s_reg and MIR). If not @@ -462,23 +466,21 @@ LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStora LIR *load2 = NULL; MipsOpCode opcode = kMipsNop; bool short_form = IS_SIMM16(displacement); - bool pair = false; + bool pair = r_dest.IsPair(); switch (size) { case k64: case kDouble: - pair = true; - opcode = kMipsLw; + if (!pair) { + // Form 64-bit pair + r_dest = Solo64ToPair64(r_dest); + pair = 1; + } if (r_dest.IsFloat()) { + DCHECK_EQ(r_dest.GetLowReg(), r_dest.GetHighReg() - 1); opcode = kMipsFlwc1; - if (r_dest.IsDouble()) { - int reg_num = (r_dest.GetRegNum() << 1) | RegStorage::kFloatingPoint; - r_dest = RegStorage(RegStorage::k64BitSolo, reg_num, reg_num + 1); - } else { - DCHECK(r_dest_hi.IsFloat()); - DCHECK_EQ(r_dest.GetReg(), r_dest_hi.GetReg() - 1); - r_dest_hi.SetReg(r_dest.GetReg() + 1); - } + } else { + opcode = kMipsLw; } short_form = IS_SIMM16_2WORD(displacement); DCHECK_EQ((displacement & 0x3), 0); @@ -515,15 +517,15 @@ LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStora if (!pair) { load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg()); } else { - load = res = NewLIR3(opcode, r_dest.GetReg(), displacement + LOWORD_OFFSET, r_base.GetReg()); - load2 = NewLIR3(opcode, r_dest_hi.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg()); + load = res = NewLIR3(opcode, r_dest.GetLowReg(), displacement + LOWORD_OFFSET, r_base.GetReg()); + load2 = NewLIR3(opcode, r_dest.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg()); } } else { if (pair) { RegStorage r_tmp = AllocTemp(); res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement); - load = NewLIR3(opcode, r_dest.GetReg(), LOWORD_OFFSET, r_tmp.GetReg()); - load2 = NewLIR3(opcode, r_dest_hi.GetReg(), HIWORD_OFFSET, r_tmp.GetReg()); + load = NewLIR3(opcode, r_dest.GetLowReg(), LOWORD_OFFSET, r_tmp.GetReg()); + load2 = NewLIR3(opcode, r_dest.GetHighReg(), HIWORD_OFFSET, r_tmp.GetReg()); FreeTemp(r_tmp); } else { RegStorage r_tmp = (r_base == r_dest) ? AllocTemp() : r_dest; @@ -557,11 +559,7 @@ LIR* MipsMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r size = k32; } LIR* load; - if (size == k64 || size == kDouble) { - load = LoadBaseDispBody(r_base, displacement, r_dest.GetLow(), r_dest.GetHigh(), size); - } else { - load = LoadBaseDispBody(r_base, displacement, r_dest, RegStorage::InvalidReg(), size); - } + load = LoadBaseDispBody(r_base, displacement, r_dest, size); if (UNLIKELY(is_volatile == kVolatile)) { // Without context sensitive analysis, we must issue the most conservative barriers. @@ -575,7 +573,7 @@ LIR* MipsMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r // FIXME: don't split r_dest into 2 containers. LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, - RegStorage r_src, RegStorage r_src_hi, OpSize size) { + RegStorage r_src, OpSize size) { LIR *res; LIR *store = NULL; LIR *store2 = NULL; @@ -586,17 +584,16 @@ LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, switch (size) { case k64: case kDouble: - opcode = kMipsSw; + if (!pair) { + // Form 64-bit pair + r_src = Solo64ToPair64(r_src); + pair = 1; + } if (r_src.IsFloat()) { + DCHECK_EQ(r_src.GetLowReg(), r_src.GetHighReg() - 1); opcode = kMipsFswc1; - if (r_src.IsDouble()) { - int reg_num = (r_src.GetRegNum() << 1) | RegStorage::kFloatingPoint; - r_src = RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1); - } else { - DCHECK(r_src_hi.IsFloat()); - DCHECK_EQ(r_src.GetReg(), (r_src_hi.GetReg() - 1)); - r_src_hi.SetReg(r_src.GetReg() + 1); - } + } else { + opcode = kMipsSw; } short_form = IS_SIMM16_2WORD(displacement); DCHECK_EQ((displacement & 0x3), 0); @@ -628,8 +625,8 @@ LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, if (!pair) { store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg()); } else { - store = res = NewLIR3(opcode, r_src.GetReg(), displacement + LOWORD_OFFSET, r_base.GetReg()); - store2 = NewLIR3(opcode, r_src_hi.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg()); + store = res = NewLIR3(opcode, r_src.GetLowReg(), displacement + LOWORD_OFFSET, r_base.GetReg()); + store2 = NewLIR3(opcode, r_src.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg()); } } else { RegStorage r_scratch = AllocTemp(); @@ -637,8 +634,8 @@ LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, if (!pair) { store = NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg()); } else { - store = NewLIR3(opcode, r_src.GetReg(), LOWORD_OFFSET, r_scratch.GetReg()); - store2 = NewLIR3(opcode, r_src_hi.GetReg(), HIWORD_OFFSET, r_scratch.GetReg()); + store = NewLIR3(opcode, r_src.GetLowReg(), LOWORD_OFFSET, r_scratch.GetReg()); + store2 = NewLIR3(opcode, r_src.GetHighReg(), HIWORD_OFFSET, r_scratch.GetReg()); } FreeTemp(r_scratch); } @@ -669,11 +666,7 @@ LIR* MipsMir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage size = k32; } LIR* store; - if (size == k64 || size == kDouble) { - store = StoreBaseDispBody(r_base, displacement, r_src.GetLow(), r_src.GetHigh(), size); - } else { - store = StoreBaseDispBody(r_base, displacement, r_src, RegStorage::InvalidReg(), size); - } + store = StoreBaseDispBody(r_base, displacement, r_src, size); if (UNLIKELY(is_volatile == kVolatile)) { // A load might follow the volatile store so insert a StoreLoad barrier. diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc index 60eebe4..81dabd4 100644 --- a/compiler/dex/quick/ralloc_util.cc +++ b/compiler/dex/quick/ralloc_util.cc @@ -359,7 +359,13 @@ RegStorage Mir2Lir::AllocTempBody(GrowableArray ®s, int* next_ * NOTE: "wideness" is an attribute of how the container is used, not its physical size. * The caller will set wideness as appropriate. */ - info->SetIsWide(false); + if (info->IsWide()) { + RegisterInfo* partner = GetRegInfo(info->Partner()); + DCHECK_EQ(info->GetReg().GetRegNum(), partner->Partner().GetRegNum()); + DCHECK(partner->IsWide()); + info->SetIsWide(false); + partner->SetIsWide(false); + } *next_temp = next + 1; return info->GetReg(); } diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index de2960c..bf04a54 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1130,8 +1130,8 @@ static int dex2oat(int argc, char** argv) { } if (compiler_filter_string == nullptr) { - if (instruction_set == kMips) { - // TODO: fix compiler for Mips. + if (instruction_set == kMips64) { + // TODO: fix compiler for Mips64. compiler_filter_string = "interpret-only"; } else if (image) { compiler_filter_string = "speed"; diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h index 96eeb8d..6e10a4c 100644 --- a/runtime/instruction_set.h +++ b/runtime/instruction_set.h @@ -33,7 +33,8 @@ enum InstructionSet { kThumb2, kX86, kX86_64, - kMips + kMips, + kMips64 }; std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs); -- cgit v1.1