diff options
author | 2016-08-20 01:55:47 -0700 | |
---|---|---|
committer | 2016-08-24 17:27:35 -0700 | |
commit | 2923db7314da613d50c9e6e44f38bb8d3e1c49f0 (patch) | |
tree | 063590a45f9f384872b8fa14f9f0bd2f014f0d66 /compiler/utils/mips/assembler_mips.h | |
parent | 897b8f5da90b38b030826273f4c9bd8fbc32759e (diff) |
MIPS32: Refactor implicit null checks in array/field get/set.
Rationale: on MIPS32 64-bit loads and stores may be performed
as pairs of 32-bit loads/stores. Implicit null checks must be
associated with the first 32-bit load/store in a pair and not
the last. This change ensures proper association of said checks
(a few were done after the last 32-bit load/store in a pair)
and lays ground for further improvements in array/field get/set.
Test: booted MIPS32 in QEMU
Test: test-art-host-gtest
Test: test-art-target-run-test-optimizing in QEMU
Change-Id: I3674947c00bb17930790a7a47c9b7aadc0c030b8
Diffstat (limited to 'compiler/utils/mips/assembler_mips.h')
-rw-r--r-- | compiler/utils/mips/assembler_mips.h | 200 |
1 files changed, 198 insertions, 2 deletions
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h index 41b6c6bd32..434ca679d5 100644 --- a/compiler/utils/mips/assembler_mips.h +++ b/compiler/utils/mips/assembler_mips.h @@ -412,8 +412,6 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi void LoadConst64(Register reg_hi, Register reg_lo, int64_t value); void LoadDConst64(FRegister rd, int64_t value, Register temp); void LoadSConst32(FRegister r, int32_t value, Register temp); - void StoreConst32ToOffset(int32_t value, Register base, int32_t offset, Register temp); - void StoreConst64ToOffset(int64_t value, Register base, int32_t offset, Register temp); void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT); // These will generate R2 branches or R6 branches as appropriate. @@ -444,6 +442,204 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi int32_t& offset, bool is_doubleword, bool is_float = false); + + private: + struct NoImplicitNullChecker { + void operator()() {} + }; + + public: + template <typename ImplicitNullChecker = NoImplicitNullChecker> + void StoreConst32ToOffset(int32_t value, + Register base, + int32_t offset, + Register temp, + ImplicitNullChecker null_checker = NoImplicitNullChecker()) { + CHECK_NE(temp, AT); // Must not use AT as temp, so as not to overwrite the adjusted base. + AdjustBaseAndOffset(base, offset, /* is_doubleword */ false); + if (value == 0) { + temp = ZERO; + } else { + LoadConst32(temp, value); + } + Sw(temp, base, offset); + null_checker(); + } + + template <typename ImplicitNullChecker = NoImplicitNullChecker> + void StoreConst64ToOffset(int64_t value, + Register base, + int32_t offset, + Register temp, + ImplicitNullChecker null_checker = NoImplicitNullChecker()) { + CHECK_NE(temp, AT); // Must not use AT as temp, so as not to overwrite the adjusted base. + AdjustBaseAndOffset(base, offset, /* is_doubleword */ true); + uint32_t low = Low32Bits(value); + uint32_t high = High32Bits(value); + if (low == 0) { + Sw(ZERO, base, offset); + } else { + LoadConst32(temp, low); + Sw(temp, base, offset); + } + null_checker(); + if (high == 0) { + Sw(ZERO, base, offset + kMipsWordSize); + } else { + if (high != low) { + LoadConst32(temp, high); + } + Sw(temp, base, offset + kMipsWordSize); + } + } + + template <typename ImplicitNullChecker = NoImplicitNullChecker> + void LoadFromOffset(LoadOperandType type, + Register reg, + Register base, + int32_t offset, + ImplicitNullChecker null_checker = NoImplicitNullChecker()) { + AdjustBaseAndOffset(base, offset, /* is_doubleword */ (type == kLoadDoubleword)); + switch (type) { + case kLoadSignedByte: + Lb(reg, base, offset); + break; + case kLoadUnsignedByte: + Lbu(reg, base, offset); + break; + case kLoadSignedHalfword: + Lh(reg, base, offset); + break; + case kLoadUnsignedHalfword: + Lhu(reg, base, offset); + break; + case kLoadWord: + Lw(reg, base, offset); + break; + case kLoadDoubleword: + if (reg == base) { + // This will clobber the base when loading the lower register. Since we have to load the + // higher register as well, this will fail. Solution: reverse the order. + Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); + null_checker(); + Lw(reg, base, offset); + } else { + Lw(reg, base, offset); + null_checker(); + Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); + } + break; + default: + LOG(FATAL) << "UNREACHABLE"; + } + if (type != kLoadDoubleword) { + null_checker(); + } + } + + template <typename ImplicitNullChecker = NoImplicitNullChecker> + void LoadSFromOffset(FRegister reg, + Register base, + int32_t offset, + ImplicitNullChecker null_checker = NoImplicitNullChecker()) { + AdjustBaseAndOffset(base, offset, /* is_doubleword */ false, /* is_float */ true); + Lwc1(reg, base, offset); + null_checker(); + } + + template <typename ImplicitNullChecker = NoImplicitNullChecker> + void LoadDFromOffset(FRegister reg, + Register base, + int32_t offset, + ImplicitNullChecker null_checker = NoImplicitNullChecker()) { + AdjustBaseAndOffset(base, offset, /* is_doubleword */ true, /* is_float */ true); + if (IsAligned<kMipsDoublewordSize>(offset)) { + Ldc1(reg, base, offset); + null_checker(); + } else { + if (Is32BitFPU()) { + Lwc1(reg, base, offset); + null_checker(); + Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize); + } else { + // 64-bit FPU. + Lwc1(reg, base, offset); + null_checker(); + Lw(T8, base, offset + kMipsWordSize); + Mthc1(T8, reg); + } + } + } + + template <typename ImplicitNullChecker = NoImplicitNullChecker> + void StoreToOffset(StoreOperandType type, + Register reg, + Register base, + int32_t offset, + ImplicitNullChecker null_checker = NoImplicitNullChecker()) { + // Must not use AT as `reg`, so as not to overwrite the value being stored + // with the adjusted `base`. + CHECK_NE(reg, AT); + AdjustBaseAndOffset(base, offset, /* is_doubleword */ (type == kStoreDoubleword)); + switch (type) { + case kStoreByte: + Sb(reg, base, offset); + break; + case kStoreHalfword: + Sh(reg, base, offset); + break; + case kStoreWord: + Sw(reg, base, offset); + break; + case kStoreDoubleword: + CHECK_NE(reg, base); + CHECK_NE(static_cast<Register>(reg + 1), base); + Sw(reg, base, offset); + null_checker(); + Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); + break; + default: + LOG(FATAL) << "UNREACHABLE"; + } + if (type != kStoreDoubleword) { + null_checker(); + } + } + + template <typename ImplicitNullChecker = NoImplicitNullChecker> + void StoreSToOffset(FRegister reg, + Register base, + int32_t offset, + ImplicitNullChecker null_checker = NoImplicitNullChecker()) { + AdjustBaseAndOffset(base, offset, /* is_doubleword */ false, /* is_float */ true); + Swc1(reg, base, offset); + null_checker(); + } + + template <typename ImplicitNullChecker = NoImplicitNullChecker> + void StoreDToOffset(FRegister reg, + Register base, + int32_t offset, + ImplicitNullChecker null_checker = NoImplicitNullChecker()) { + AdjustBaseAndOffset(base, offset, /* is_doubleword */ true, /* is_float */ true); + if (IsAligned<kMipsDoublewordSize>(offset)) { + Sdc1(reg, base, offset); + null_checker(); + } else { + if (Is32BitFPU()) { + Swc1(reg, base, offset); + null_checker(); + Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize); + } else { + // 64-bit FPU. + Mfhc1(T8, reg); + Swc1(reg, base, offset); + null_checker(); + Sw(T8, base, offset + kMipsWordSize); + } + } + } + void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset); void LoadSFromOffset(FRegister reg, Register base, int32_t offset); void LoadDFromOffset(FRegister reg, Register base, int32_t offset); |