diff options
author | 2015-08-24 12:58:55 +0000 | |
---|---|---|
committer | 2015-08-25 17:17:22 +0200 | |
commit | ff73498a5539d87424a964265e43765e788aec44 (patch) | |
tree | 3f8a525ef91d2f12e4b2a71c04fc8147a12c12bd | |
parent | 9dc601eb65da0cd5f53172699dacd6e5dd38ab44 (diff) |
Revert "Revert "[MIPS] Use hard float calling convention for managed code""
This reverts commit 7fee84c087e0f903e7d43bef180df047db1c8051.
Fixed issue with temporary registers on Mips32r6.
Change-Id: I93018927e6a6036cff2d55e6cda66d3212a4316b
-rw-r--r-- | compiler/dex/quick/mips/codegen_mips.h | 5 | ||||
-rw-r--r-- | compiler/dex/quick/mips/target_mips.cc | 55 | ||||
-rw-r--r-- | compiler/jni/jni_cfi_test_expected.inc | 82 | ||||
-rw-r--r-- | compiler/jni/quick/mips/calling_convention_mips.cc | 55 | ||||
-rw-r--r-- | compiler/utils/mips/assembler_mips.cc | 48 | ||||
-rw-r--r-- | compiler/utils/mips/assembler_mips.h | 15 | ||||
-rw-r--r-- | runtime/arch/mips/asm_support_mips.h | 2 | ||||
-rw-r--r-- | runtime/arch/mips/context_mips.cc | 5 | ||||
-rw-r--r-- | runtime/arch/mips/jni_entrypoints_mips.S | 26 | ||||
-rw-r--r-- | runtime/arch/mips/quick_entrypoints_mips.S | 324 | ||||
-rw-r--r-- | runtime/arch/mips/quick_method_frame_info_mips.h | 15 | ||||
-rw-r--r-- | runtime/art_method.cc | 6 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 53 |
13 files changed, 516 insertions, 175 deletions
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h index 43fbcbdd2b..2173253363 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -29,15 +29,18 @@ class MipsMir2Lir FINAL : public Mir2Lir { protected: class InToRegStorageMipsMapper : public InToRegStorageMapper { public: - explicit InToRegStorageMipsMapper(Mir2Lir* m2l) : m2l_(m2l), cur_core_reg_(0) {} + explicit InToRegStorageMipsMapper(Mir2Lir* m2l) : m2l_(m2l), cur_core_reg_(0), cur_fpu_reg_(0) + {} virtual RegStorage GetNextReg(ShortyArg arg); virtual void Reset() OVERRIDE { cur_core_reg_ = 0; + cur_fpu_reg_ = 0; } protected: Mir2Lir* m2l_; private: size_t cur_core_reg_; + size_t cur_fpu_reg_; }; class InToRegStorageMips64Mapper : public InToRegStorageMapper { diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc index ec4bad778c..09d37f8dbf 100644 --- a/compiler/dex/quick/mips/target_mips.cc +++ b/compiler/dex/quick/mips/target_mips.cc @@ -195,7 +195,7 @@ RegStorage MipsMir2Lir::Fp64ToSolo32(RegStorage reg) { // Return a target-dependent special register. RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg, WideKind wide_kind) { if (!cu_->target64 && wide_kind == kWide) { - DCHECK((kArg0 <= reg && reg < kArg7) || (kFArg0 <= reg && reg < kFArg15) || (kRet0 == reg)); + DCHECK((kArg0 <= reg && reg < kArg7) || (kFArg0 == reg) || (kFArg2 == reg) || (kRet0 == reg)); RegStorage ret_reg = RegStorage::MakeRegPair(TargetReg(reg), TargetReg(static_cast<SpecialTargetRegister>(reg + 1))); if (!fpuIs32Bit_ && ret_reg.IsFloat()) { @@ -250,14 +250,27 @@ RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) { RegStorage MipsMir2Lir::InToRegStorageMipsMapper::GetNextReg(ShortyArg arg) { const SpecialTargetRegister coreArgMappingToPhysicalReg[] = {kArg1, kArg2, kArg3}; const size_t coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg); + const SpecialTargetRegister fpuArgMappingToPhysicalReg[] = {kFArg0, kFArg2}; + const size_t fpuArgMappingToPhysicalRegSize = arraysize(fpuArgMappingToPhysicalReg); RegStorage result = RegStorage::InvalidReg(); - if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) { - result = m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], - arg.IsRef() ? kRef : kNotWide); - if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) { - result = RegStorage::MakeRegPair( - result, m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], kNotWide)); + if (arg.IsFP()) { + if (cur_fpu_reg_ < fpuArgMappingToPhysicalRegSize) { + result = m2l_->TargetReg(fpuArgMappingToPhysicalReg[cur_fpu_reg_++], + arg.IsWide() ? kWide : kNotWide); + } + } else { + if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) { + if (arg.IsWide() && cur_core_reg_ == 0) { + // Don't use a1-a2 as a register pair, move to a2-a3 instead. + cur_core_reg_++; + } + result = m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], + arg.IsRef() ? kRef : kNotWide); + if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) { + result = RegStorage::MakeRegPair( + result, m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], kNotWide)); + } } } return result; @@ -654,6 +667,20 @@ void MipsMir2Lir::LockCallTemps() { LockTemp(TargetReg(kArg5)); LockTemp(TargetReg(kArg6)); LockTemp(TargetReg(kArg7)); + } else { + if (fpuIs32Bit_) { + LockTemp(TargetReg(kFArg0)); + LockTemp(TargetReg(kFArg1)); + LockTemp(TargetReg(kFArg2)); + LockTemp(TargetReg(kFArg3)); + LockTemp(rs_rD6_fr0); + LockTemp(rs_rD7_fr0); + } else { + LockTemp(TargetReg(kFArg0)); + LockTemp(TargetReg(kFArg2)); + LockTemp(rs_rD6_fr1); + LockTemp(rs_rD7_fr1); + } } } @@ -668,6 +695,20 @@ void MipsMir2Lir::FreeCallTemps() { FreeTemp(TargetReg(kArg5)); FreeTemp(TargetReg(kArg6)); FreeTemp(TargetReg(kArg7)); + } else { + if (fpuIs32Bit_) { + FreeTemp(TargetReg(kFArg0)); + FreeTemp(TargetReg(kFArg1)); + FreeTemp(TargetReg(kFArg2)); + FreeTemp(TargetReg(kFArg3)); + FreeTemp(rs_rD6_fr0); + FreeTemp(rs_rD7_fr0); + } else { + FreeTemp(TargetReg(kFArg0)); + FreeTemp(TargetReg(kFArg2)); + FreeTemp(rs_rD6_fr1); + FreeTemp(rs_rD7_fr1); + } } FreeTemp(TargetReg(kHiddenArg)); } diff --git a/compiler/jni/jni_cfi_test_expected.inc b/compiler/jni/jni_cfi_test_expected.inc index dd4496fe69..8b5fdc3fcb 100644 --- a/compiler/jni/jni_cfi_test_expected.inc +++ b/compiler/jni/jni_cfi_test_expected.inc @@ -329,17 +329,18 @@ static constexpr uint8_t expected_asm_kMips[] = { 0x34, 0x00, 0xAF, 0xAF, 0x30, 0x00, 0xAE, 0xAF, 0x2C, 0x00, 0xAD, 0xAF, 0x28, 0x00, 0xAC, 0xAF, 0x24, 0x00, 0xAB, 0xAF, 0x20, 0x00, 0xAA, 0xAF, 0x1C, 0x00, 0xA9, 0xAF, 0x18, 0x00, 0xA8, 0xAF, 0x00, 0x00, 0xA4, 0xAF, - 0x44, 0x00, 0xA5, 0xAF, 0x48, 0x00, 0xA6, 0xAF, 0x4C, 0x00, 0xA7, 0xAF, - 0xE0, 0xFF, 0xBD, 0x27, 0x20, 0x00, 0xBD, 0x27, 0x18, 0x00, 0xA8, 0x8F, - 0x1C, 0x00, 0xA9, 0x8F, 0x20, 0x00, 0xAA, 0x8F, 0x24, 0x00, 0xAB, 0x8F, - 0x28, 0x00, 0xAC, 0x8F, 0x2C, 0x00, 0xAD, 0x8F, 0x30, 0x00, 0xAE, 0x8F, - 0x34, 0x00, 0xAF, 0x8F, 0x38, 0x00, 0xB8, 0x8F, 0x3C, 0x00, 0xBF, 0x8F, - 0x40, 0x00, 0xBD, 0x27, 0x09, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x00, 0xA5, 0xAF, 0x48, 0x00, 0xAC, 0xE7, 0x4C, 0x00, 0xA6, 0xAF, + 0x50, 0x00, 0xA7, 0xAF, 0xE0, 0xFF, 0xBD, 0x27, 0x20, 0x00, 0xBD, 0x27, + 0x18, 0x00, 0xA8, 0x8F, 0x1C, 0x00, 0xA9, 0x8F, 0x20, 0x00, 0xAA, 0x8F, + 0x24, 0x00, 0xAB, 0x8F, 0x28, 0x00, 0xAC, 0x8F, 0x2C, 0x00, 0xAD, 0x8F, + 0x30, 0x00, 0xAE, 0x8F, 0x34, 0x00, 0xAF, 0x8F, 0x38, 0x00, 0xB8, 0x8F, + 0x3C, 0x00, 0xBF, 0x8F, 0x40, 0x00, 0xBD, 0x27, 0x09, 0x00, 0xE0, 0x03, + 0x00, 0x00, 0x00, 0x00, }; static constexpr uint8_t expected_cfi_kMips[] = { 0x44, 0x0E, 0x40, 0x44, 0x9F, 0x01, 0x44, 0x98, 0x02, 0x44, 0x8F, 0x03, 0x44, 0x8E, 0x04, 0x44, 0x8D, 0x05, 0x44, 0x8C, 0x06, 0x44, 0x8B, 0x07, - 0x44, 0x8A, 0x08, 0x44, 0x89, 0x09, 0x44, 0x88, 0x0A, 0x54, 0x0E, 0x60, + 0x44, 0x8A, 0x08, 0x44, 0x89, 0x09, 0x44, 0x88, 0x0A, 0x58, 0x0E, 0x60, 0x44, 0x0E, 0x40, 0x0A, 0x44, 0xC8, 0x44, 0xC9, 0x44, 0xCA, 0x44, 0xCB, 0x44, 0xCC, 0x44, 0xCD, 0x44, 0xCE, 0x44, 0xCF, 0x44, 0xD8, 0x44, 0xDF, 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, 0x40, @@ -368,39 +369,40 @@ static constexpr uint8_t expected_cfi_kMips[] = { // 0x0000002c: .cfi_offset: r8 at cfa-40 // 0x0000002c: sw r4, +0(r29) // 0x00000030: sw r5, +68(r29) -// 0x00000034: sw r6, +72(r29) -// 0x00000038: sw r7, +76(r29) -// 0x0000003c: addiu r29, r29, -32 -// 0x00000040: .cfi_def_cfa_offset: 96 -// 0x00000040: addiu r29, r29, 32 -// 0x00000044: .cfi_def_cfa_offset: 64 -// 0x00000044: .cfi_remember_state -// 0x00000044: lw r8, +24(r29) -// 0x00000048: .cfi_restore: r8 -// 0x00000048: lw r9, +28(r29) -// 0x0000004c: .cfi_restore: r9 -// 0x0000004c: lw r10, +32(r29) -// 0x00000050: .cfi_restore: r10 -// 0x00000050: lw r11, +36(r29) -// 0x00000054: .cfi_restore: r11 -// 0x00000054: lw r12, +40(r29) -// 0x00000058: .cfi_restore: r12 -// 0x00000058: lw r13, +44(r29) -// 0x0000005c: .cfi_restore: r13 -// 0x0000005c: lw r14, +48(r29) -// 0x00000060: .cfi_restore: r14 -// 0x00000060: lw r15, +52(r29) -// 0x00000064: .cfi_restore: r15 -// 0x00000064: lw r24, +56(r29) -// 0x00000068: .cfi_restore: r24 -// 0x00000068: lw r31, +60(r29) -// 0x0000006c: .cfi_restore: r31 -// 0x0000006c: addiu r29, r29, 64 -// 0x00000070: .cfi_def_cfa_offset: 0 -// 0x00000070: jr r31 -// 0x00000074: nop -// 0x00000078: .cfi_restore_state -// 0x00000078: .cfi_def_cfa_offset: 64 +// 0x00000034: swc1 f12, +72(r29) +// 0x00000038: sw r6, +76(r29) +// 0x0000003c: sw r7, +80(r29) +// 0x00000040: addiu r29, r29, -32 +// 0x00000044: .cfi_def_cfa_offset: 96 +// 0x00000044: addiu r29, r29, 32 +// 0x00000048: .cfi_def_cfa_offset: 64 +// 0x00000048: .cfi_remember_state +// 0x00000048: lw r8, +24(r29) +// 0x0000004c: .cfi_restore: r8 +// 0x0000004c: lw r9, +28(r29) +// 0x00000050: .cfi_restore: r9 +// 0x00000050: lw r10, +32(r29) +// 0x00000054: .cfi_restore: r10 +// 0x00000054: lw r11, +36(r29) +// 0x00000058: .cfi_restore: r11 +// 0x00000058: lw r12, +40(r29) +// 0x0000005c: .cfi_restore: r12 +// 0x0000005c: lw r13, +44(r29) +// 0x00000060: .cfi_restore: r13 +// 0x00000060: lw r14, +48(r29) +// 0x00000064: .cfi_restore: r14 +// 0x00000064: lw r15, +52(r29) +// 0x00000068: .cfi_restore: r15 +// 0x00000068: lw r24, +56(r29) +// 0x0000006c: .cfi_restore: r24 +// 0x0000006c: lw r31, +60(r29) +// 0x00000070: .cfi_restore: r31 +// 0x00000070: addiu r29, r29, 64 +// 0x00000074: .cfi_def_cfa_offset: 0 +// 0x00000074: jr r31 +// 0x00000078: nop +// 0x0000007c: .cfi_restore_state +// 0x0000007c: .cfi_def_cfa_offset: 64 static constexpr uint8_t expected_asm_kMips64[] = { 0xA0, 0xFF, 0xBD, 0x67, 0x58, 0x00, 0xBF, 0xFF, 0x50, 0x00, 0xBE, 0xFF, diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc index 4e716b54de..be2397f518 100644 --- a/compiler/jni/quick/mips/calling_convention_mips.cc +++ b/compiler/jni/quick/mips/calling_convention_mips.cc @@ -23,6 +23,10 @@ namespace art { namespace mips { +static const Register kCoreArgumentRegisters[] = { A0, A1, A2, A3 }; +static const FRegister kFArgumentRegisters[] = { F12, F14 }; +static const DRegister kDArgumentRegisters[] = { D6, D7 }; + // Calling convention ManagedRegister MipsManagedRuntimeCallingConvention::InterproceduralScratchRegister() { return MipsManagedRegister::FromCoreRegister(T9); @@ -89,14 +93,49 @@ FrameOffset MipsManagedRuntimeCallingConvention::CurrentParamStackOffset() { const ManagedRegisterEntrySpills& MipsManagedRuntimeCallingConvention::EntrySpills() { // We spill the argument registers on MIPS to free them up for scratch use, we then assume // all arguments are on the stack. - if (entry_spills_.size() == 0) { - size_t num_spills = NumArgs() + NumLongOrDoubleArgs(); - if (num_spills > 0) { - entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A1)); - if (num_spills > 1) { - entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A2)); - if (num_spills > 2) { - entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A3)); + if ((entry_spills_.size() == 0) && (NumArgs() > 0)) { + uint32_t gpr_index = 1; // Skip A0, it is used for ArtMethod*. + uint32_t fpr_index = 0; + + for (ResetIterator(FrameOffset(0)); HasNext(); Next()) { + if (IsCurrentParamAFloatOrDouble()) { + if (IsCurrentParamADouble()) { + if (fpr_index < arraysize(kDArgumentRegisters)) { + entry_spills_.push_back( + MipsManagedRegister::FromDRegister(kDArgumentRegisters[fpr_index++])); + } else { + entry_spills_.push_back(ManagedRegister::NoRegister(), 8); + } + } else { + if (fpr_index < arraysize(kFArgumentRegisters)) { + entry_spills_.push_back( + MipsManagedRegister::FromFRegister(kFArgumentRegisters[fpr_index++])); + } else { + entry_spills_.push_back(ManagedRegister::NoRegister(), 4); + } + } + } else { + if (IsCurrentParamALong() && !IsCurrentParamAReference()) { + if (gpr_index == 1) { + // Don't use a1-a2 as a register pair, move to a2-a3 instead. + gpr_index++; + } + if (gpr_index < arraysize(kCoreArgumentRegisters) - 1) { + entry_spills_.push_back( + MipsManagedRegister::FromCoreRegister(kCoreArgumentRegisters[gpr_index++])); + } else if (gpr_index == arraysize(kCoreArgumentRegisters) - 1) { + gpr_index++; + entry_spills_.push_back(ManagedRegister::NoRegister(), 4); + } else { + entry_spills_.push_back(ManagedRegister::NoRegister(), 4); + } + } + + if (gpr_index < arraysize(kCoreArgumentRegisters)) { + entry_spills_.push_back( + MipsManagedRegister::FromCoreRegister(kCoreArgumentRegisters[gpr_index++])); + } else { + entry_spills_.push_back(ManagedRegister::NoRegister(), 4); } } } diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc index c09dfcce4f..c5fae92f3c 100644 --- a/compiler/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -359,23 +359,19 @@ void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) { } void MipsAssembler::AddD(DRegister fd, DRegister fs, DRegister ft) { - EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), - static_cast<FRegister>(fd), 0x0); + EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x0); } void MipsAssembler::SubD(DRegister fd, DRegister fs, DRegister ft) { - EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), - static_cast<FRegister>(fd), 0x1); + EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x1); } void MipsAssembler::MulD(DRegister fd, DRegister fs, DRegister ft) { - EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), - static_cast<FRegister>(fd), 0x2); + EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x2); } void MipsAssembler::DivD(DRegister fd, DRegister fs, DRegister ft) { - EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), - static_cast<FRegister>(fd), 0x3); + EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x3); } void MipsAssembler::MovS(FRegister fd, FRegister fs) { @@ -383,32 +379,31 @@ void MipsAssembler::MovS(FRegister fd, FRegister fs) { } void MipsAssembler::MovD(DRegister fd, DRegister fs) { - EmitFR(0x11, 0x11, static_cast<FRegister>(0), static_cast<FRegister>(fs), - static_cast<FRegister>(fd), 0x6); + EmitFR(0x11, 0x11, static_cast<FRegister>(0), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x6); } void MipsAssembler::Mfc1(Register rt, FRegister fs) { - EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); + EmitFR(0x11, 0x00, ConvertRegToFReg(rt), fs, static_cast<FRegister>(0), 0x0); } void MipsAssembler::Mtc1(FRegister ft, Register rs) { - EmitFR(0x11, 0x04, ft, static_cast<FRegister>(rs), static_cast<FRegister>(0), 0x0); + EmitFR(0x11, 0x04, ft, ConvertRegToFReg(rs), static_cast<FRegister>(0), 0x0); } void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) { - EmitI(0x31, rs, static_cast<Register>(ft), imm16); + EmitI(0x31, rs, ConvertFRegToReg(ft), imm16); } void MipsAssembler::Ldc1(DRegister ft, Register rs, uint16_t imm16) { - EmitI(0x35, rs, static_cast<Register>(ft), imm16); + EmitI(0x35, rs, ConvertDRegToReg(ft), imm16); } void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) { - EmitI(0x39, rs, static_cast<Register>(ft), imm16); + EmitI(0x39, rs, ConvertFRegToReg(ft), imm16); } void MipsAssembler::Sdc1(DRegister ft, Register rs, uint16_t imm16) { - EmitI(0x3d, rs, static_cast<Register>(ft), imm16); + EmitI(0x3d, rs, ConvertDRegToReg(ft), imm16); } void MipsAssembler::Break() { @@ -529,7 +524,7 @@ void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register } } -void MipsAssembler::StoreFToOffset(FRegister reg, Register base, int32_t offset) { +void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) { Swc1(reg, base, offset); } @@ -566,9 +561,22 @@ void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0); // Write out entry spills. + int32_t offset = frame_size + kFramePointerSize; for (size_t i = 0; i < entry_spills.size(); ++i) { - Register reg = entry_spills.at(i).AsMips().AsCoreRegister(); - StoreToOffset(kStoreWord, reg, SP, frame_size + kFramePointerSize + (i * kFramePointerSize)); + MipsManagedRegister reg = entry_spills.at(i).AsMips(); + if (reg.IsNoRegister()) { + ManagedRegisterSpill spill = entry_spills.at(i); + offset += spill.getSize(); + } else if (reg.IsCoreRegister()) { + StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset); + offset += 4; + } else if (reg.IsFRegister()) { + StoreSToOffset(reg.AsFRegister(), SP, offset); + offset += 4; + } else if (reg.IsDRegister()) { + StoreDToOffset(reg.AsDRegister(), SP, offset); + offset += 8; + } } } @@ -624,7 +632,7 @@ void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { StoreToOffset(kStoreWord, src.AsRegisterPairHigh(), SP, dest.Int32Value() + 4); } else if (src.IsFRegister()) { - StoreFToOffset(src.AsFRegister(), SP, dest.Int32Value()); + StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value()); } else { CHECK(src.IsDRegister()); StoreDToOffset(src.AsDRegister(), SP, dest.Int32Value()); diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h index df95daddc1..6c8b162d62 100644 --- a/compiler/utils/mips/assembler_mips.h +++ b/compiler/utils/mips/assembler_mips.h @@ -141,7 +141,7 @@ class MipsAssembler FINAL : public Assembler { void LoadSFromOffset(FRegister reg, Register base, int32_t offset); void LoadDFromOffset(DRegister reg, Register base, int32_t offset); void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset); - void StoreFToOffset(FRegister reg, Register base, int32_t offset); + void StoreSToOffset(FRegister reg, Register base, int32_t offset); void StoreDToOffset(DRegister reg, Register base, int32_t offset); // Emit data (e.g. encoded instruction or immediate) to the instruction stream. @@ -277,6 +277,19 @@ class MipsAssembler FINAL : public Assembler { int32_t EncodeBranchOffset(int offset, int32_t inst, bool is_jump); int DecodeBranchOffset(int32_t inst, bool is_jump); + FRegister ConvertDRegToFReg(DRegister reg) { + return static_cast<FRegister>(reg * 2); + } + Register ConvertDRegToReg(DRegister reg) { + return static_cast<Register>(reg * 2); + } + Register ConvertFRegToReg(FRegister reg) { + return static_cast<Register>(reg); + } + FRegister ConvertRegToFReg(Register reg) { + return static_cast<FRegister>(reg); + } + DISALLOW_COPY_AND_ASSIGN(MipsAssembler); }; diff --git a/runtime/arch/mips/asm_support_mips.h b/runtime/arch/mips/asm_support_mips.h index 390c606374..453056d7bf 100644 --- a/runtime/arch/mips/asm_support_mips.h +++ b/runtime/arch/mips/asm_support_mips.h @@ -21,6 +21,6 @@ #define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 96 #define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 48 -#define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 64 +#define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 80 #endif // ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_H_ diff --git a/runtime/arch/mips/context_mips.cc b/runtime/arch/mips/context_mips.cc index 53f2b65eec..bc2bf68993 100644 --- a/runtime/arch/mips/context_mips.cc +++ b/runtime/arch/mips/context_mips.cc @@ -76,6 +76,11 @@ void MipsContext::SmashCallerSaves() { gprs_[A1] = nullptr; gprs_[A2] = nullptr; gprs_[A3] = nullptr; + + fprs_[F12] = nullptr; + fprs_[F13] = nullptr; + fprs_[F14] = nullptr; + fprs_[F15] = nullptr; } extern "C" NO_RETURN void art_quick_do_long_jump(uint32_t*, uint32_t*); diff --git a/runtime/arch/mips/jni_entrypoints_mips.S b/runtime/arch/mips/jni_entrypoints_mips.S index fbc81d584b..3558efd41f 100644 --- a/runtime/arch/mips/jni_entrypoints_mips.S +++ b/runtime/arch/mips/jni_entrypoints_mips.S @@ -24,17 +24,19 @@ */ .extern artFindNativeMethod ENTRY art_jni_dlsym_lookup_stub - addiu $sp, $sp, -32 # leave room for $a0, $a1, $a2, $a3, and $ra - .cfi_adjust_cfa_offset 32 - sw $ra, 16($sp) - .cfi_rel_offset 31, 16 - sw $a3, 12($sp) + addiu $sp, $sp, -48 # leave room for $f12, $f13, $f14, $f15, $a0, $a1, $a2, $a3, and $ra + .cfi_adjust_cfa_offset 48 + sw $ra, 32($sp) + .cfi_rel_offset 31, 32 + SDu $f14, $f15, 24, $sp, $t0 + SDu $f12, $f13, 16, $sp, $t0 + sw $a3, 12($sp) .cfi_rel_offset 7, 12 - sw $a2, 8($sp) + sw $a2, 8($sp) .cfi_rel_offset 6, 8 - sw $a1, 4($sp) + sw $a1, 4($sp) .cfi_rel_offset 5, 4 - sw $a0, 0($sp) + sw $a0, 0($sp) .cfi_rel_offset 4, 0 jal artFindNativeMethod # (Thread*) move $a0, $s1 # pass Thread::Current() @@ -42,10 +44,12 @@ ENTRY art_jni_dlsym_lookup_stub lw $a1, 4($sp) lw $a2, 8($sp) lw $a3, 12($sp) - lw $ra, 16($sp) + LDu $f12, $f13, 16, $sp, $t0 + LDu $f14, $f15, 24, $sp, $t0 + lw $ra, 32($sp) beq $v0, $zero, .Lno_native_code_found - addiu $sp, $sp, 32 # restore the stack - .cfi_adjust_cfa_offset -32 + addiu $sp, $sp, 48 # restore the stack + .cfi_adjust_cfa_offset -48 move $t9, $v0 # put method code result in $t9 jalr $zero, $t9 # leaf call to method's code nop diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S index 4d5004f444..8bc75e546a 100644 --- a/runtime/arch/mips/quick_entrypoints_mips.S +++ b/runtime/arch/mips/quick_entrypoints_mips.S @@ -170,45 +170,47 @@ * callee-save: $a1-$a3, $s2-$s8 + $gp + $ra, 12 total + 3 words padding + method* */ .macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY - addiu $sp, $sp, -64 - .cfi_adjust_cfa_offset 64 + addiu $sp, $sp, -80 + .cfi_adjust_cfa_offset 80 // Ugly compile-time check, but we only have the preprocessor. -#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 64) +#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 80) #error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(MIPS) size not as expected." #endif - sw $ra, 60($sp) - .cfi_rel_offset 31, 60 - sw $s8, 56($sp) - .cfi_rel_offset 30, 56 - sw $gp, 52($sp) - .cfi_rel_offset 28, 52 - sw $s7, 48($sp) - .cfi_rel_offset 23, 48 - sw $s6, 44($sp) - .cfi_rel_offset 22, 44 - sw $s5, 40($sp) - .cfi_rel_offset 21, 40 - sw $s4, 36($sp) - .cfi_rel_offset 20, 36 - sw $s3, 32($sp) - .cfi_rel_offset 19, 32 - sw $s2, 28($sp) - .cfi_rel_offset 18, 28 - sw $a3, 24($sp) - .cfi_rel_offset 7, 24 - sw $a2, 20($sp) - .cfi_rel_offset 6, 20 - sw $a1, 16($sp) - .cfi_rel_offset 5, 16 + sw $ra, 76($sp) + .cfi_rel_offset 31, 76 + sw $s8, 72($sp) + .cfi_rel_offset 30, 72 + sw $gp, 68($sp) + .cfi_rel_offset 28, 68 + sw $s7, 64($sp) + .cfi_rel_offset 23, 64 + sw $s6, 60($sp) + .cfi_rel_offset 22, 60 + sw $s5, 56($sp) + .cfi_rel_offset 21, 56 + sw $s4, 52($sp) + .cfi_rel_offset 20, 52 + sw $s3, 48($sp) + .cfi_rel_offset 19, 48 + sw $s2, 44($sp) + .cfi_rel_offset 18, 44 + sw $a3, 40($sp) + .cfi_rel_offset 7, 40 + sw $a2, 36($sp) + .cfi_rel_offset 6, 36 + sw $a1, 32($sp) + .cfi_rel_offset 5, 32 + SDu $f14, $f15, 24, $sp, $t0 + SDu $f12, $f13, 16, $sp, $t0 # bottom will hold Method* .endm /* * Macro that sets up the callee save frame to conform with * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes non-moving GC. - * callee-save: $a1-$a3, $s2-$s8 + $gp + $ra, 12 total + 3 words padding + method* + * callee-save: $a1-$a3, $f12-$f15, $s2-$s8 + $gp + $ra, 12 total + 3 words padding + method* * Clobbers $t0 and $sp * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots. * Reserves FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE + ARG_SLOT_SIZE bytes on the stack @@ -227,7 +229,7 @@ /* * Macro that sets up the callee save frame to conform with * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes non-moving GC. - * callee-save: $a1-$a3, $s2-$s8 + $gp + $ra, 12 total + 3 words padding + method* + * callee-save: $a1-$a3, $f12-$f15, $s2-$s8 + $gp + $ra, 12 total + 3 words padding + method* * Clobbers $sp * Use $a0 as the Method* and loads it into bottom of stack. * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots. @@ -244,32 +246,34 @@ .macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME addiu $sp, $sp, ARG_SLOT_SIZE # remove argument slots on the stack .cfi_adjust_cfa_offset -ARG_SLOT_SIZE - lw $ra, 60($sp) + lw $ra, 76($sp) .cfi_restore 31 - lw $s8, 56($sp) + lw $s8, 72($sp) .cfi_restore 30 - lw $gp, 52($sp) + lw $gp, 68($sp) .cfi_restore 28 - lw $s7, 48($sp) + lw $s7, 64($sp) .cfi_restore 23 - lw $s6, 44($sp) + lw $s6, 60($sp) .cfi_restore 22 - lw $s5, 40($sp) + lw $s5, 56($sp) .cfi_restore 21 - lw $s4, 36($sp) + lw $s4, 52($sp) .cfi_restore 20 - lw $s3, 32($sp) + lw $s3, 48($sp) .cfi_restore 19 - lw $s2, 28($sp) + lw $s2, 44($sp) .cfi_restore 18 - lw $a3, 24($sp) + lw $a3, 40($sp) .cfi_restore 7 - lw $a2, 20($sp) + lw $a2, 36($sp) .cfi_restore 6 - lw $a1, 16($sp) + lw $a1, 32($sp) .cfi_restore 5 - addiu $sp, $sp, 64 # pop frame - .cfi_adjust_cfa_offset -64 + LDu $f14, $f15, 24, $sp, $t1 + LDu $f12, $f13, 16, $sp, $t1 + addiu $sp, $sp, 80 # pop frame + .cfi_adjust_cfa_offset -80 .endm /* @@ -484,6 +488,32 @@ INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvok INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck +.macro LOAD_WORD_TO_REG reg, next_arg, index, label + lw $\reg, -4($\next_arg) # next_arg points to argument after the current one (offset is 4) + b \label + addiu $\index, 1 +.endm + +.macro LOAD_LONG_TO_REG reg1, reg2, next_arg, index, label + lw $\reg1, -8($\next_arg) # next_arg points to argument after the current one (offset is 8) + lw $\reg2, -4($\next_arg) + b \label + li $\index, 4 # long can be loaded only to a2_a3 pair so index will be always 4 +.endm + +.macro LOAD_FLOAT_TO_REG reg, next_arg, index, label + lwc1 $\reg, -4($\next_arg) # next_arg points to argument after the current one (offset is 4) + b \label + addiu $\index, 1 +.endm + +.macro LOAD_DOUBLE_TO_REG reg1, reg2, next_arg, index, tmp, label + LDu $\reg1, $\reg2, -8, $\next_arg, $\tmp # next_arg points to argument after the current one + # (offset is 8) + b \label + addiu $\index, 1 +.endm + /* * Invocation stub for quick code. * On entry: @@ -510,21 +540,76 @@ ENTRY art_quick_invoke_stub .cfi_def_cfa_register 30 move $s1, $a3 # move managed thread pointer into s1 addiu $s0, $zero, SUSPEND_CHECK_INTERVAL # reset s0 to suspend check interval - addiu $t0, $a2, 4 # create space for method pointer in frame. + addiu $t0, $a2, 4 # create space for ArtMethod* in frame. subu $t0, $sp, $t0 # reserve & align *stack* to 16 bytes: - srl $t0, $t0, 4 # native calling convention only aligns to 8B, - sll $sp, $t0, 4 # so we have to ensure ART 16B alignment ourselves. - addiu $a0, $sp, 4 # pass stack pointer + method ptr as dest for memcpy + srl $t0, $t0, 4 # native calling convention only aligns to 8B, + sll $sp, $t0, 4 # so we have to ensure ART 16B alignment ourselves. + addiu $a0, $sp, 4 # pass stack pointer + ArtMethod* as dest for memcpy jal memcpy # (dest, src, bytes) addiu $sp, $sp, -16 # make space for argument slots for memcpy addiu $sp, $sp, 16 # restore stack after memcpy - lw $a0, 16($fp) # restore method* - lw $a1, 4($sp) # copy arg value for a1 - lw $a2, 8($sp) # copy arg value for a2 - lw $a3, 12($sp) # copy arg value for a3 + lw $a0, 16($fp) # restore ArtMethod* + lw $a1, 4($sp) # a1 = this* + addiu $t0, $sp, 8 # t0 = pointer to the current argument (skip ArtMethod* and this*) + li $t3, 2 # t3 = gpr_index = 2 (skip A0 and A1) + move $t4, $zero # t4 = fp_index = 0 + lw $t1, 20+16($fp) # get shorty (20 is offset from the $sp on entry + 16 as the $fp is + # 16 bytes below the $sp on entry) + addiu $t1, 1 # t1 = shorty + 1 (skip 1 for return type) +loop: + lbu $t2, 0($t1) # t2 = shorty[i] + beqz $t2, loopEnd # finish getting args when shorty[i] == '\0' + addiu $t1, 1 + + li $t9, 'J' # put char 'J' into t9 + beq $t9, $t2, isLong # branch if result type char == 'J' + li $t9, 'D' # put char 'D' into t9 + beq $t9, $t2, isDouble # branch if result type char == 'D' + li $t9, 'F' # put char 'F' into t9 + beq $t9, $t2, isSingle # branch if result type char == 'F' + addiu $t0, 4 # next_arg = curr_arg + 4 (in branch delay slot, + # for both, int and single) + + li $t5, 2 # skip a0 and a1 (ArtMethod* and this*) + bne $t5, $t3, 1f # if (gpr_index == 2) + addiu $t5, 1 + LOAD_WORD_TO_REG a2, t0, t3, loop # a2 = current argument, gpr_index++ +1: bne $t5, $t3, loop # else if (gpr_index == 3) + nop + LOAD_WORD_TO_REG a3, t0, t3, loop # a3 = current argument, gpr_index++ + +isLong: + addiu $t0, 8 # next_arg = curr_arg + 8 + slti $t5, $t3, 3 + beqz $t5, 2f # if (gpr_index < 3) + nop + LOAD_LONG_TO_REG a2, a3, t0, t3, loop # a2_a3 = curr_arg, gpr_index = 4 +2: b loop # else + li $t3, 4 # gpr_index = 4 + +isDouble: + addiu $t0, 8 # next_arg = curr_arg + 8 + li $t5, 0 + bne $t5, $t4, 3f # if (fp_index == 0) + addiu $t5, 1 + LOAD_DOUBLE_TO_REG f12, f13, t0, t4, t9, loop # f12_f13 = curr_arg, fp_index++ +3: bne $t5, $t4, loop # else if (fp_index == 1) + nop + LOAD_DOUBLE_TO_REG f14, f15, t0, t4, t9, loop # f14_f15 = curr_arg, fp_index++ + +isSingle: + li $t5, 0 + bne $t5, $t4, 4f # if (fp_index == 0) + addiu $t5, 1 + LOAD_FLOAT_TO_REG f12, t0, t4, loop # f12 = curr_arg, fp_index++ +4: bne $t5, $t4, loop # else if (fp_index == 1) + nop + LOAD_FLOAT_TO_REG f14, t0, t4, loop # f14 = curr_arg, fp_index++ + +loopEnd: lw $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0) # get pointer to the code jalr $t9 # call the method - sw $zero, 0($sp) # store null for method* at bottom of frame + sw $zero, 0($sp) # store null for ArtMethod* at bottom of frame move $sp, $fp # restore the stack lw $s0, 0($sp) .cfi_restore 16 @@ -539,20 +624,145 @@ ENTRY art_quick_invoke_stub lw $t0, 16($sp) # get result pointer lw $t1, 20($sp) # get shorty lb $t1, 0($t1) # get result type char - li $t2, 68 # put char 'D' into t2 - beq $t1, $t2, 1f # branch if result type char == 'D' - li $t3, 70 # put char 'F' into t3 - beq $t1, $t3, 1f # branch if result type char == 'F' + li $t2, 'D' # put char 'D' into t2 + beq $t1, $t2, 5f # branch if result type char == 'D' + li $t3, 'F' # put char 'F' into t3 + beq $t1, $t3, 5f # branch if result type char == 'F' sw $v0, 0($t0) # store the result jalr $zero, $ra sw $v1, 4($t0) # store the other half of the result -1: +5: SDu $f0, $f1, 0, $t0, $t1 # store floating point result jalr $zero, $ra nop END art_quick_invoke_stub /* + * Invocation static stub for quick code. + * On entry: + * a0 = method pointer + * a1 = argument array or null for no argument methods + * a2 = size of argument array in bytes + * a3 = (managed) thread pointer + * [sp + 16] = JValue* result + * [sp + 20] = shorty + */ +ENTRY art_quick_invoke_static_stub + sw $a0, 0($sp) # save out a0 + addiu $sp, $sp, -16 # spill s0, s1, fp, ra + .cfi_adjust_cfa_offset 16 + sw $ra, 12($sp) + .cfi_rel_offset 31, 12 + sw $fp, 8($sp) + .cfi_rel_offset 30, 8 + sw $s1, 4($sp) + .cfi_rel_offset 17, 4 + sw $s0, 0($sp) + .cfi_rel_offset 16, 0 + move $fp, $sp # save sp in fp + .cfi_def_cfa_register 30 + move $s1, $a3 # move managed thread pointer into s1 + addiu $s0, $zero, SUSPEND_CHECK_INTERVAL # reset s0 to suspend check interval + addiu $t0, $a2, 4 # create space for ArtMethod* in frame. + subu $t0, $sp, $t0 # reserve & align *stack* to 16 bytes: + srl $t0, $t0, 4 # native calling convention only aligns to 8B, + sll $sp, $t0, 4 # so we have to ensure ART 16B alignment ourselves. + addiu $a0, $sp, 4 # pass stack pointer + ArtMethod* as dest for memcpy + jal memcpy # (dest, src, bytes) + addiu $sp, $sp, -16 # make space for argument slots for memcpy + addiu $sp, $sp, 16 # restore stack after memcpy + lw $a0, 16($fp) # restore ArtMethod* + addiu $t0, $sp, 4 # t0 = pointer to the current argument (skip ArtMethod*) + li $t3, 1 # t3 = gpr_index = 1 (skip A0) + move $t4, $zero # t4 = fp_index = 0 + lw $t1, 20+16($fp) # get shorty (20 is offset from the $sp on entry + 16 as the $fp is + # 16 bytes below the $sp on entry) + addiu $t1, 1 # t1 = shorty + 1 (skip 1 for return type) +loopS: + lbu $t2, 0($t1) # t2 = shorty[i] + beqz $t2, loopEndS # finish getting args when shorty[i] == '\0' + addiu $t1, 1 + + li $t9, 'J' # put char 'J' into t9 + beq $t9, $t2, isLongS # branch if result type char == 'J' + li $t9, 'D' # put char 'D' into t9 + beq $t9, $t2, isDoubleS # branch if result type char == 'D' + li $t9, 'F' # put char 'F' into t9 + beq $t9, $t2, isSingleS # branch if result type char == 'F' + addiu $t0, 4 # next_arg = curr_arg + 4 (in branch delay slot, + # for both, int and single) + + li $t5, 1 # skip a0 (ArtMethod*) + bne $t5, $t3, 1f # if (gpr_index == 1) + addiu $t5, 1 + LOAD_WORD_TO_REG a1, t0, t3, loopS # a1 = current argument, gpr_index++ +1: bne $t5, $t3, 2f # else if (gpr_index == 2) + addiu $t5, 1 + LOAD_WORD_TO_REG a2, t0, t3, loopS # a2 = current argument, gpr_index++ +2: bne $t5, $t3, loopS # else if (gpr_index == 3) + nop + LOAD_WORD_TO_REG a3, t0, t3, loopS # a3 = current argument, gpr_index++ + +isLongS: + addiu $t0, 8 # next_arg = curr_arg + 8 + slti $t5, $t3, 3 + beqz $t5, 3f # if (gpr_index < 3) + nop + LOAD_LONG_TO_REG a2, a3, t0, t3, loopS # a2_a3 = curr_arg, gpr_index = 4 +3: b loopS # else + li $t3, 4 # gpr_index = 4 + +isDoubleS: + addiu $t0, 8 # next_arg = curr_arg + 8 + li $t5, 0 + bne $t5, $t4, 4f # if (fp_index == 0) + addiu $t5, 1 + LOAD_DOUBLE_TO_REG f12, f13, t0, t4, t9, loopS # f12_f13 = curr_arg, fp_index++ +4: bne $t5, $t4, loopS # else if (fp_index == 1) + nop + LOAD_DOUBLE_TO_REG f14, f15, t0, t4, t9, loopS # f14_f15 = curr_arg, fp_index++ + +isSingleS: + li $t5, 0 + bne $t5, $t4, 5f # if (fp_index == 0) + addiu $t5, 1 + LOAD_FLOAT_TO_REG f12, t0, t4, loopS # f12 = curr_arg, fp_index++ +5: bne $t5, $t4, loopS # else if (fp_index == 1) + nop + LOAD_FLOAT_TO_REG f14, t0, t4, loopS # f14 = curr_arg, fp_index++ + +loopEndS: + lw $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0) # get pointer to the code + jalr $t9 # call the method + sw $zero, 0($sp) # store null for ArtMethod* at bottom of frame + move $sp, $fp # restore the stack + lw $s0, 0($sp) + .cfi_restore 16 + lw $s1, 4($sp) + .cfi_restore 17 + lw $fp, 8($sp) + .cfi_restore 30 + lw $ra, 12($sp) + .cfi_restore 31 + addiu $sp, $sp, 16 + .cfi_adjust_cfa_offset -16 + lw $t0, 16($sp) # get result pointer + lw $t1, 20($sp) # get shorty + lb $t1, 0($t1) # get result type char + li $t2, 'D' # put char 'D' into t2 + beq $t1, $t2, 6f # branch if result type char == 'D' + li $t3, 'F' # put char 'F' into t3 + beq $t1, $t3, 6f # branch if result type char == 'F' + sw $v0, 0($t0) # store the result + jalr $zero, $ra + sw $v1, 4($t0) # store the other half of the result +6: + SDu $f0, $f1, 0, $t0, $t1 # store floating point result + jalr $zero, $ra + nop +END art_quick_invoke_static_stub + + /* * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on * failure. */ diff --git a/runtime/arch/mips/quick_method_frame_info_mips.h b/runtime/arch/mips/quick_method_frame_info_mips.h index dd5ac800e2..f5d13c2b52 100644 --- a/runtime/arch/mips/quick_method_frame_info_mips.h +++ b/runtime/arch/mips/quick_method_frame_info_mips.h @@ -25,6 +25,8 @@ namespace art { namespace mips { +static constexpr uint32_t kMipsCalleeSaveAlwaysSpills = + (1 << art::mips::RA); static constexpr uint32_t kMipsCalleeSaveRefSpills = (1 << art::mips::S2) | (1 << art::mips::S3) | (1 << art::mips::S4) | (1 << art::mips::S5) | (1 << art::mips::S6) | (1 << art::mips::S7) | (1 << art::mips::GP) | (1 << art::mips::FP); @@ -32,19 +34,26 @@ static constexpr uint32_t kMipsCalleeSaveArgSpills = (1 << art::mips::A1) | (1 << art::mips::A2) | (1 << art::mips::A3); static constexpr uint32_t kMipsCalleeSaveAllSpills = (1 << art::mips::S0) | (1 << art::mips::S1); + +static constexpr uint32_t kMipsCalleeSaveFpAlwaysSpills = 0; +static constexpr uint32_t kMipsCalleeSaveFpRefSpills = 0; +static constexpr uint32_t kMipsCalleeSaveFpArgSpills = + (1 << art::mips::F12) | (1 << art::mips::F13) | (1 << art::mips::F14) | (1 << art::mips::F15); static constexpr uint32_t kMipsCalleeSaveAllFPSpills = (1 << art::mips::F20) | (1 << art::mips::F21) | (1 << art::mips::F22) | (1 << art::mips::F23) | (1 << art::mips::F24) | (1 << art::mips::F25) | (1 << art::mips::F26) | (1 << art::mips::F27) | (1 << art::mips::F28) | (1 << art::mips::F29) | (1 << art::mips::F30) | (1 << art::mips::F31); constexpr uint32_t MipsCalleeSaveCoreSpills(Runtime::CalleeSaveType type) { - return kMipsCalleeSaveRefSpills | + return kMipsCalleeSaveAlwaysSpills | kMipsCalleeSaveRefSpills | (type == Runtime::kRefsAndArgs ? kMipsCalleeSaveArgSpills : 0) | - (type == Runtime::kSaveAll ? kMipsCalleeSaveAllSpills : 0) | (1 << art::mips::RA); + (type == Runtime::kSaveAll ? kMipsCalleeSaveAllSpills : 0); } constexpr uint32_t MipsCalleeSaveFPSpills(Runtime::CalleeSaveType type) { - return type == Runtime::kSaveAll ? kMipsCalleeSaveAllFPSpills : 0; + return kMipsCalleeSaveFpAlwaysSpills | kMipsCalleeSaveFpRefSpills | + (type == Runtime::kRefsAndArgs ? kMipsCalleeSaveFpArgSpills : 0) | + (type == Runtime::kSaveAll ? kMipsCalleeSaveAllFPSpills : 0); } constexpr uint32_t MipsCalleeSaveFrameSize(Runtime::CalleeSaveType type) { diff --git a/runtime/art_method.cc b/runtime/art_method.cc index f4c6473521..56f7b35501 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -45,10 +45,8 @@ namespace art { extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, const char*); -#if defined(__LP64__) || defined(__arm__) || defined(__i386__) extern "C" void art_quick_invoke_static_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, const char*); -#endif ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject jlr_method) { @@ -417,15 +415,11 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* << "Don't call compiled code when -Xint " << PrettyMethod(this); } -#if defined(__LP64__) || defined(__arm__) || defined(__i386__) if (!IsStatic()) { (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty); } else { (*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty); } -#else - (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty); -#endif if (UNLIKELY(self->GetException() == Thread::GetDeoptimizationException())) { // Unusual case where we were running generated code and an // exception was thrown to force the activations to be removed from the diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index da4b82c43b..aa35ec1ca2 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -65,6 +65,7 @@ class QuickArgumentVisitor { static constexpr bool kAlignPairRegister = !kArm32QuickCodeUseSoftFloat; static constexpr bool kQuickSoftFloatAbi = kArm32QuickCodeUseSoftFloat; static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = !kArm32QuickCodeUseSoftFloat; + static constexpr bool kQuickSkipOddFpRegisters = false; static constexpr size_t kNumQuickGprArgs = 3; static constexpr size_t kNumQuickFprArgs = kArm32QuickCodeUseSoftFloat ? 0 : 16; static constexpr bool kGprFprLockstep = false; @@ -102,6 +103,7 @@ class QuickArgumentVisitor { static constexpr bool kAlignPairRegister = false; static constexpr bool kQuickSoftFloatAbi = false; // This is a hard float ABI. static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false; + static constexpr bool kQuickSkipOddFpRegisters = false; static constexpr size_t kNumQuickGprArgs = 7; // 7 arguments passed in GPRs. static constexpr size_t kNumQuickFprArgs = 8; // 8 arguments passed in FPRs. static constexpr bool kGprFprLockstep = false; @@ -128,17 +130,25 @@ class QuickArgumentVisitor { // | A3 | arg3 // | A2 | arg2 // | A1 | arg1 + // | F15 | + // | F14 | f_arg1 + // | F13 | + // | F12 | f_arg0 + // | | padding // | A0/Method* | <- sp - static constexpr bool kSplitPairAcrossRegisterAndStack = true; - static constexpr bool kAlignPairRegister = false; - static constexpr bool kQuickSoftFloatAbi = true; // This is a soft float ABI. + static constexpr bool kSplitPairAcrossRegisterAndStack = false; + static constexpr bool kAlignPairRegister = true; + static constexpr bool kQuickSoftFloatAbi = false; static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false; + static constexpr bool kQuickSkipOddFpRegisters = true; static constexpr size_t kNumQuickGprArgs = 3; // 3 arguments passed in GPRs. - static constexpr size_t kNumQuickFprArgs = 0; // 0 arguments passed in FPRs. + static constexpr size_t kNumQuickFprArgs = 4; // 2 arguments passed in FPRs. Floats can be passed + // only in even numbered registers and each double + // occupies two registers. static constexpr bool kGprFprLockstep = false; - static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 0; // Offset of first FPR arg. - static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 16; // Offset of first GPR arg. - static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 60; // Offset of return address. + static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 16; // Offset of first FPR arg. + static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 32; // Offset of first GPR arg. + static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 76; // Offset of return address. static size_t GprIndexToGprOffset(uint32_t gpr_index) { return gpr_index * GetBytesPerGprSpillLocation(kRuntimeISA); } @@ -153,14 +163,6 @@ class QuickArgumentVisitor { // | Method* | --- // | RA | // | ... | callee saves - // | F7 | f_arg7 - // | F6 | f_arg6 - // | F5 | f_arg5 - // | F4 | f_arg4 - // | F3 | f_arg3 - // | F2 | f_arg2 - // | F1 | f_arg1 - // | F0 | f_arg0 // | A7 | arg7 // | A6 | arg6 // | A5 | arg5 @@ -168,6 +170,14 @@ class QuickArgumentVisitor { // | A3 | arg3 // | A2 | arg2 // | A1 | arg1 + // | F19 | f_arg7 + // | F18 | f_arg6 + // | F17 | f_arg5 + // | F16 | f_arg4 + // | F15 | f_arg3 + // | F14 | f_arg2 + // | F13 | f_arg1 + // | F12 | f_arg0 // | | padding // | A0/Method* | <- sp // NOTE: for Mip64, when A0 is skipped, F0 is also skipped. @@ -175,9 +185,7 @@ class QuickArgumentVisitor { static constexpr bool kAlignPairRegister = false; static constexpr bool kQuickSoftFloatAbi = false; static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false; - // These values are set to zeros because GPR and FPR register - // assignments for Mips64 are interleaved, which the current VisitArguments() - // function does not support. + static constexpr bool kQuickSkipOddFpRegisters = false; static constexpr size_t kNumQuickGprArgs = 7; // 7 arguments passed in GPRs. static constexpr size_t kNumQuickFprArgs = 7; // 7 arguments passed in FPRs. static constexpr bool kGprFprLockstep = true; @@ -211,6 +219,7 @@ class QuickArgumentVisitor { static constexpr bool kAlignPairRegister = false; static constexpr bool kQuickSoftFloatAbi = false; // This is a hard float ABI. static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false; + static constexpr bool kQuickSkipOddFpRegisters = false; static constexpr size_t kNumQuickGprArgs = 3; // 3 arguments passed in GPRs. static constexpr size_t kNumQuickFprArgs = 4; // 4 arguments passed in FPRs. static constexpr bool kGprFprLockstep = false; @@ -252,6 +261,7 @@ class QuickArgumentVisitor { static constexpr bool kAlignPairRegister = false; static constexpr bool kQuickSoftFloatAbi = false; // This is a hard float ABI. static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false; + static constexpr bool kQuickSkipOddFpRegisters = false; static constexpr size_t kNumQuickGprArgs = 5; // 5 arguments passed in GPRs. static constexpr size_t kNumQuickFprArgs = 8; // 8 arguments passed in FPRs. static constexpr bool kGprFprLockstep = false; @@ -475,6 +485,8 @@ class QuickArgumentVisitor { if (fpr_index_ % 2 == 0) { fpr_index_ = std::max(fpr_double_index_, fpr_index_); } + } else if (kQuickSkipOddFpRegisters) { + IncFprIndex(); } } } @@ -483,8 +495,9 @@ class QuickArgumentVisitor { case Primitive::kPrimLong: if (kQuickSoftFloatAbi || (cur_type_ == Primitive::kPrimLong)) { if (cur_type_ == Primitive::kPrimLong && kAlignPairRegister && gpr_index_ == 0) { - // Currently, this is only for ARM, where the first available parameter register - // is R1. So we skip it, and use R2 instead. + // Currently, this is only for ARM and MIPS, where the first available parameter + // register is R1 (on ARM) or A1 (on MIPS). So we skip it, and use R2 (on ARM) or + // A2 (on MIPS) instead. IncGprIndex(); } is_split_long_or_double_ = (GetBytesPerGprSpillLocation(kRuntimeISA) == 4) && |