MIPS64: Improve storing of constants in fields and array elements
Test: booted MIPS64 in QEMU
Test: mma test-art-target-run-test
Test: mma test-art-host-gtest-assembler_mips64_test
Change-Id: I8e0002166174eebea1309358eb9d96f34eee3225
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index 8bbe862..b98db65 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -782,6 +782,86 @@
public:
template <typename ImplicitNullChecker = NoImplicitNullChecker>
+ void StoreConstToOffset(StoreOperandType type,
+ int64_t value,
+ GpuRegister base,
+ int32_t offset,
+ GpuRegister temp,
+ ImplicitNullChecker null_checker = NoImplicitNullChecker()) {
+ // We permit `base` and `temp` to coincide (however, we check that neither is AT),
+ // in which case the `base` register may be overwritten in the process.
+ CHECK_NE(temp, AT); // Must not use AT as temp, so as not to overwrite the adjusted base.
+ if (!IsInt<16>(offset) ||
+ (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
+ !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
+ LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
+ Daddu(AT, AT, base);
+ base = AT;
+ offset &= (kMips64DoublewordSize - 1);
+ }
+ GpuRegister reg;
+ // If the adjustment left `base` unchanged and equal to `temp`, we can't use `temp`
+ // to load and hold the value but we can use AT instead as AT hasn't been used yet.
+ // Otherwise, `temp` can be used for the value. And if `temp` is the same as the
+ // original `base` (that is, `base` prior to the adjustment), the original `base`
+ // register will be overwritten.
+ if (base == temp) {
+ temp = AT;
+ }
+
+ if (type == kStoreDoubleword && IsAligned<kMips64DoublewordSize>(offset)) {
+ if (value == 0) {
+ reg = ZERO;
+ } else {
+ reg = temp;
+ LoadConst64(reg, value);
+ }
+ Sd(reg, base, offset);
+ null_checker();
+ } else {
+ uint32_t low = Low32Bits(value);
+ uint32_t high = High32Bits(value);
+ if (low == 0) {
+ reg = ZERO;
+ } else {
+ reg = temp;
+ LoadConst32(reg, low);
+ }
+ 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:
+ // not aligned to kMips64DoublewordSize
+ CHECK_ALIGNED(offset, kMips64WordSize);
+ Sw(reg, base, offset);
+ null_checker();
+ if (high == 0) {
+ reg = ZERO;
+ } else {
+ reg = temp;
+ if (high != low) {
+ LoadConst32(reg, high);
+ }
+ }
+ Sw(reg, base, offset + kMips64WordSize);
+ break;
+ default:
+ LOG(FATAL) << "UNREACHABLE";
+ }
+ if (type != kStoreDoubleword) {
+ null_checker();
+ }
+ }
+ }
+
+ template <typename ImplicitNullChecker = NoImplicitNullChecker>
void LoadFromOffset(LoadOperandType type,
GpuRegister reg,
GpuRegister base,