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
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index a7fbc84..8a2f90d 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1833,11 +1833,19 @@
}
}
+auto InstructionCodeGeneratorMIPS::GetImplicitNullChecker(HInstruction* instruction) {
+ auto null_checker = [this, instruction]() {
+ this->codegen_->MaybeRecordImplicitNullCheck(instruction);
+ };
+ return null_checker;
+}
+
void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
Register obj = locations->InAt(0).AsRegister<Register>();
Location index = locations->InAt(1);
uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
+ auto null_checker = GetImplicitNullChecker(instruction);
Primitive::Type type = instruction->GetType();
switch (type) {
@@ -1846,10 +1854,10 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
- __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
+ __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset, null_checker);
} else {
__ Addu(TMP, obj, index.AsRegister<Register>());
- __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1859,10 +1867,10 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
- __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
+ __ LoadFromOffset(kLoadSignedByte, out, obj, offset, null_checker);
} else {
__ Addu(TMP, obj, index.AsRegister<Register>());
- __ LoadFromOffset(kLoadSignedByte, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadSignedByte, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1872,11 +1880,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
- __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
+ __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
__ Addu(TMP, obj, TMP);
- __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1886,11 +1894,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
- __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
+ __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
__ Addu(TMP, obj, TMP);
- __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1902,11 +1910,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- __ LoadFromOffset(kLoadWord, out, obj, offset);
+ __ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
__ Addu(TMP, obj, TMP);
- __ LoadFromOffset(kLoadWord, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1916,11 +1924,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
- __ LoadFromOffset(kLoadDoubleword, out, obj, offset);
+ __ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
__ Addu(TMP, obj, TMP);
- __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1930,11 +1938,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- __ LoadSFromOffset(out, obj, offset);
+ __ LoadSFromOffset(out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
__ Addu(TMP, obj, TMP);
- __ LoadSFromOffset(out, TMP, data_offset);
+ __ LoadSFromOffset(out, TMP, data_offset, null_checker);
}
break;
}
@@ -1944,11 +1952,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
- __ LoadDFromOffset(out, obj, offset);
+ __ LoadDFromOffset(out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
__ Addu(TMP, obj, TMP);
- __ LoadDFromOffset(out, TMP, data_offset);
+ __ LoadDFromOffset(out, TMP, data_offset, null_checker);
}
break;
}
@@ -1957,7 +1965,6 @@
LOG(FATAL) << "Unreachable type " << instruction->GetType();
UNREACHABLE();
}
- codegen_->MaybeRecordImplicitNullCheck(instruction);
}
void LocationsBuilderMIPS::VisitArrayLength(HArrayLength* instruction) {
@@ -2004,6 +2011,7 @@
bool needs_runtime_call = locations->WillCall();
bool needs_write_barrier =
CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+ auto null_checker = GetImplicitNullChecker(instruction);
switch (value_type) {
case Primitive::kPrimBoolean:
@@ -2013,10 +2021,10 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
- __ StoreToOffset(kStoreByte, value, obj, offset);
+ __ StoreToOffset(kStoreByte, value, obj, offset, null_checker);
} else {
__ Addu(TMP, obj, index.AsRegister<Register>());
- __ StoreToOffset(kStoreByte, value, TMP, data_offset);
+ __ StoreToOffset(kStoreByte, value, TMP, data_offset, null_checker);
}
break;
}
@@ -2028,11 +2036,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
- __ StoreToOffset(kStoreHalfword, value, obj, offset);
+ __ StoreToOffset(kStoreHalfword, value, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
__ Addu(TMP, obj, TMP);
- __ StoreToOffset(kStoreHalfword, value, TMP, data_offset);
+ __ StoreToOffset(kStoreHalfword, value, TMP, data_offset, null_checker);
}
break;
}
@@ -2045,14 +2053,13 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- __ StoreToOffset(kStoreWord, value, obj, offset);
+ __ StoreToOffset(kStoreWord, value, obj, offset, null_checker);
} else {
DCHECK(index.IsRegister()) << index;
__ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
__ Addu(TMP, obj, TMP);
- __ StoreToOffset(kStoreWord, value, TMP, data_offset);
+ __ StoreToOffset(kStoreWord, value, TMP, data_offset, null_checker);
}
- codegen_->MaybeRecordImplicitNullCheck(instruction);
if (needs_write_barrier) {
DCHECK_EQ(value_type, Primitive::kPrimNot);
codegen_->MarkGCCard(obj, value);
@@ -2075,11 +2082,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
- __ StoreToOffset(kStoreDoubleword, value, obj, offset);
+ __ StoreToOffset(kStoreDoubleword, value, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
__ Addu(TMP, obj, TMP);
- __ StoreToOffset(kStoreDoubleword, value, TMP, data_offset);
+ __ StoreToOffset(kStoreDoubleword, value, TMP, data_offset, null_checker);
}
break;
}
@@ -2091,11 +2098,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- __ StoreSToOffset(value, obj, offset);
+ __ StoreSToOffset(value, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
__ Addu(TMP, obj, TMP);
- __ StoreSToOffset(value, TMP, data_offset);
+ __ StoreSToOffset(value, TMP, data_offset, null_checker);
}
break;
}
@@ -2107,11 +2114,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
- __ StoreDToOffset(value, obj, offset);
+ __ StoreDToOffset(value, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
__ Addu(TMP, obj, TMP);
- __ StoreDToOffset(value, TMP, data_offset);
+ __ StoreDToOffset(value, TMP, data_offset, null_checker);
}
break;
}
@@ -2120,11 +2127,6 @@
LOG(FATAL) << "Unreachable type " << instruction->GetType();
UNREACHABLE();
}
-
- // Ints and objects are handled in the switch.
- if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- }
}
void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -3589,6 +3591,7 @@
LoadOperandType load_type = kLoadUnsignedByte;
bool is_volatile = field_info.IsVolatile();
uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+ auto null_checker = GetImplicitNullChecker(instruction);
switch (type) {
case Primitive::kPrimBoolean:
@@ -3654,34 +3657,20 @@
if (type == Primitive::kPrimLong) {
DCHECK(locations->Out().IsRegisterPair());
dst = locations->Out().AsRegisterPairLow<Register>();
- Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
- if (obj == dst) {
- __ LoadFromOffset(kLoadWord, dst_high, obj, offset + kMipsWordSize);
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- __ LoadFromOffset(kLoadWord, dst, obj, offset);
- } else {
- __ LoadFromOffset(kLoadWord, dst, obj, offset);
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- __ LoadFromOffset(kLoadWord, dst_high, obj, offset + kMipsWordSize);
- }
} else {
DCHECK(locations->Out().IsRegister());
dst = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(load_type, dst, obj, offset);
}
+ __ LoadFromOffset(load_type, dst, obj, offset, null_checker);
} else {
DCHECK(locations->Out().IsFpuRegister());
FRegister dst = locations->Out().AsFpuRegister<FRegister>();
if (type == Primitive::kPrimFloat) {
- __ LoadSFromOffset(dst, obj, offset);
+ __ LoadSFromOffset(dst, obj, offset, null_checker);
} else {
- __ LoadDFromOffset(dst, obj, offset);
+ __ LoadDFromOffset(dst, obj, offset, null_checker);
}
}
- // Longs are handled earlier.
- if (type != Primitive::kPrimLong) {
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- }
}
if (is_volatile) {
@@ -3729,6 +3718,7 @@
StoreOperandType store_type = kStoreByte;
bool is_volatile = field_info.IsVolatile();
uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+ auto null_checker = GetImplicitNullChecker(instruction);
switch (type) {
case Primitive::kPrimBoolean:
@@ -3800,28 +3790,20 @@
if (type == Primitive::kPrimLong) {
DCHECK(locations->InAt(1).IsRegisterPair());
src = locations->InAt(1).AsRegisterPairLow<Register>();
- Register src_high = locations->InAt(1).AsRegisterPairHigh<Register>();
- __ StoreToOffset(kStoreWord, src, obj, offset);
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- __ StoreToOffset(kStoreWord, src_high, obj, offset + kMipsWordSize);
} else {
DCHECK(locations->InAt(1).IsRegister());
src = locations->InAt(1).AsRegister<Register>();
- __ StoreToOffset(store_type, src, obj, offset);
}
+ __ StoreToOffset(store_type, src, obj, offset, null_checker);
} else {
DCHECK(locations->InAt(1).IsFpuRegister());
FRegister src = locations->InAt(1).AsFpuRegister<FRegister>();
if (type == Primitive::kPrimFloat) {
- __ StoreSToOffset(src, obj, offset);
+ __ StoreSToOffset(src, obj, offset, null_checker);
} else {
- __ StoreDToOffset(src, obj, offset);
+ __ StoreDToOffset(src, obj, offset, null_checker);
}
}
- // Longs are handled earlier.
- if (type != Primitive::kPrimLong) {
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- }
}
// TODO: memory barriers?