MIPS32R2: Share address computation
For array accesses the element address has the following structure:
Address = CONST_OFFSET + base_addr + index << ELEM_SHIFT
The address part (index << ELEM_SHIFT) can be shared across array
accesses with the same data type and index.
For example, in the following loop 5 accesses can share address
computation:
void foo(int[] a, int[] b, int[] c) {
for (i...) {
a[i] = a[i] + 5;
b[i] = b[i] + c[i];
}
}
Test: test-art-host, test-art-target
Change-Id: Id09fa782934aad4ee47669275e7e1a4d7d23b0fa
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 70c8a5b..3c592e7 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -2665,6 +2665,9 @@
__ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
__ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
__ Bind(&done);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index_reg, obj);
+ __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
} else {
__ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
__ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
@@ -2679,6 +2682,9 @@
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
__ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index.AsRegister<Register>(), obj);
+ __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
} else {
__ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_2, TMP);
__ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
@@ -2693,6 +2699,9 @@
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
__ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index.AsRegister<Register>(), obj);
+ __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
} else {
__ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
__ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
@@ -2766,6 +2775,9 @@
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
__ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index.AsRegister<Register>(), obj);
+ __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
} else {
__ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
__ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
@@ -2779,6 +2791,9 @@
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
__ LoadSFromOffset(out, obj, offset, null_checker);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index.AsRegister<Register>(), obj);
+ __ LoadSFromOffset(out, TMP, data_offset, null_checker);
} else {
__ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
__ LoadSFromOffset(out, TMP, data_offset, null_checker);
@@ -2792,6 +2807,9 @@
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
__ LoadDFromOffset(out, obj, offset, null_checker);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index.AsRegister<Register>(), obj);
+ __ LoadDFromOffset(out, TMP, data_offset, null_checker);
} else {
__ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
__ LoadDFromOffset(out, TMP, data_offset, null_checker);
@@ -2906,6 +2924,8 @@
uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_2, base_reg);
}
@@ -2923,6 +2943,8 @@
uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
}
@@ -2972,6 +2994,8 @@
uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
}
@@ -3055,6 +3079,8 @@
uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
}
@@ -3072,6 +3098,8 @@
uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
}
@@ -3089,6 +3117,8 @@
uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
}
@@ -3108,6 +3138,26 @@
}
}
+void LocationsBuilderMIPS::VisitIntermediateArrayAddressIndex(
+ HIntermediateArrayAddressIndex* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+
+ HIntConstant* shift = instruction->GetShift()->AsIntConstant();
+
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::ConstantLocation(shift));
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorMIPS::VisitIntermediateArrayAddressIndex(
+ HIntermediateArrayAddressIndex* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ Register index_reg = locations->InAt(0).AsRegister<Register>();
+ uint32_t shift = instruction->GetShift()->AsIntConstant()->GetValue();
+ __ Sll(locations->Out().AsRegister<Register>(), index_reg, shift);
+}
+
void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
RegisterSet caller_saves = RegisterSet::Empty();
InvokeRuntimeCallingConvention calling_convention;