8272014: Better array indexing

Reviewed-by: thartmann, rhalade, ahgross, kvn
This commit is contained in:
Christian Hagedorn 2021-09-20 07:35:25 +00:00 committed by Henry Jen
parent ae7877df2e
commit cb7482d5bd
2 changed files with 52 additions and 4 deletions

View File

@ -207,8 +207,32 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o
LIR_Address* addr;
if (index_opr->is_constant()) {
addr = new LIR_Address(array_opr,
offset_in_bytes + (intx)(index_opr->as_jint()) * elem_size, type);
#ifdef _LP64
jint index = index_opr->as_jint();
jlong disp = offset_in_bytes + (jlong)(index) * elem_size;
if (disp > max_jint) {
// Displacement overflow. Cannot directly use instruction with 32-bit displacement for 64-bit addresses.
// Convert array index to long to do array offset computation with 64-bit values.
index_opr = new_register(T_LONG);
__ move(LIR_OprFact::longConst(index), index_opr);
addr = new LIR_Address(array_opr, index_opr, LIR_Address::scale(type), offset_in_bytes, type);
} else {
addr = new LIR_Address(array_opr, (intx)disp, type);
}
#else
// A displacement overflow can also occur for x86 but that is not a problem due to the 32-bit address range!
// Let's assume an array 'a' and an access with displacement 'disp'. When disp overflows, then "a + disp" will
// always be negative (i.e. underflows the 32-bit address range):
// Let N = 2^32: a + signed_overflow(disp) = a + disp - N.
// "a + disp" is always smaller than N. If an index was chosen which would point to an address beyond N, then
// range checks would catch that and throw an exception. Thus, a + disp < 0 holds which means that it always
// underflows the 32-bit address range:
// unsigned_underflow(a + signed_overflow(disp)) = unsigned_underflow(a + disp - N)
// = (a + disp - N) + N = a + disp
// This shows that we still end up at the correct address with a displacement overflow due to the 32-bit address
// range limitation. This overflow only needs to be handled if addresses can be larger as on 64-bit platforms.
addr = new LIR_Address(array_opr, offset_in_bytes + (intx)(index_opr->as_jint()) * elem_size, type);
#endif // _LP64
} else {
if (offset_in_bytes) {
LIR_Opr tmp = new_pointer_register();

View File

@ -192,8 +192,32 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o
LIR_Address* addr;
if (index_opr->is_constant()) {
int elem_size = type2aelembytes(type);
addr = new LIR_Address(array_opr,
offset_in_bytes + (intx)(index_opr->as_jint()) * elem_size, type);
#ifdef _LP64
jint index = index_opr->as_jint();
jlong disp = offset_in_bytes + (jlong)(index) * elem_size;
if (disp > max_jint) {
// Displacement overflow. Cannot directly use instruction with 32-bit displacement for 64-bit addresses.
// Convert array index to long to do array offset computation with 64-bit values.
index_opr = new_register(T_LONG);
__ move(LIR_OprFact::longConst(index), index_opr);
addr = new LIR_Address(array_opr, index_opr, LIR_Address::scale(type), offset_in_bytes, type);
} else {
addr = new LIR_Address(array_opr, (intx)disp, type);
}
#else
// A displacement overflow can also occur for x86 but that is not a problem due to the 32-bit address range!
// Let's assume an array 'a' and an access with displacement 'disp'. When disp overflows, then "a + disp" will
// always be negative (i.e. underflows the 32-bit address range):
// Let N = 2^32: a + signed_overflow(disp) = a + disp - N.
// "a + disp" is always smaller than N. If an index was chosen which would point to an address beyond N, then
// range checks would catch that and throw an exception. Thus, a + disp < 0 holds which means that it always
// underflows the 32-bit address range:
// unsigned_underflow(a + signed_overflow(disp)) = unsigned_underflow(a + disp - N)
// = (a + disp - N) + N = a + disp
// This shows that we still end up at the correct address with a displacement overflow due to the 32-bit address
// range limitation. This overflow only needs to be handled if addresses can be larger as on 64-bit platforms.
addr = new LIR_Address(array_opr, offset_in_bytes + (intx)(index_opr->as_jint()) * elem_size, type);
#endif // _LP64
} else {
#ifdef _LP64
if (index_opr->type() == T_INT) {