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 <douglas@mips.com>
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 @@
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 @@
// 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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
GrowableArray<RegisterInfo*>::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 @@
// 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 @@
}
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::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 @@
// 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 *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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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.