diff options
author | Roland Levillain <rpl@google.com> | 2014-11-04 17:43:11 +0000 |
---|---|---|
committer | Roland Levillain <rpl@google.com> | 2014-11-04 17:43:11 +0000 |
commit | 775ef49bad8e8d9d02fc5968858dce6a00a78475 (patch) | |
tree | eb61ed86fcaa5c168b1bbb301c931179f107b7e7 /compiler/utils/arm | |
parent | e03864e99f5ab0e27a48a17275122ad8f324b615 (diff) | |
download | android_art-775ef49bad8e8d9d02fc5968858dce6a00a78475.tar.gz android_art-775ef49bad8e8d9d02fc5968858dce6a00a78475.tar.bz2 android_art-775ef49bad8e8d9d02fc5968858dce6a00a78475.zip |
Fix store instructions to large frames in ARM opt. compiler.
When accessing a stack frame at a large offset, use an
additional core register (R5 or R6) as a temporary register
whenever IP contains the value to store (and thus cannot be
used by art::Thumb2Assembler::StoreToOffset as a temporary
register to compute the memory address where the value is
to be stored). The previous value of R5 (or R6) is saved
on the stack before the emission of the store instruction
and restored afterwards.
Change-Id: Ic5fd5ab2c09d8327dd1f0f241d40d2c397ce64cd
Diffstat (limited to 'compiler/utils/arm')
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index fd2613a89e..9801108dd0 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -2391,7 +2391,7 @@ void Thumb2Assembler::LoadFromOffset(LoadOperandType type, int32_t offset, Condition cond) { if (!Address::CanHoldLoadOffsetThumb(type, offset)) { - CHECK(base != IP); + CHECK_NE(base, IP); LoadImmediate(IP, offset, cond); add(IP, IP, ShifterOperand(base), cond); base = IP; @@ -2467,12 +2467,26 @@ void Thumb2Assembler::StoreToOffset(StoreOperandType type, Register base, int32_t offset, Condition cond) { + Register tmp_reg = kNoRegister; if (!Address::CanHoldStoreOffsetThumb(type, offset)) { - CHECK(reg != IP); - CHECK(base != IP); - LoadImmediate(IP, offset, cond); - add(IP, IP, ShifterOperand(base), cond); - base = IP; + CHECK_NE(base, IP); + if (reg != IP) { + tmp_reg = IP; + } else { + // Be careful not to use IP twice (for `reg` and to build the + // Address object used by the store instruction(s) below). + // Instead, save R5 on the stack (or R6 if R5 is not available), + // use it as secondary temporary register, and restore it after + // the store instruction has been emitted. + tmp_reg = base != R5 ? R5 : R6; + Push(tmp_reg); + if (base == SP) { + offset += kRegisterSize; + } + } + LoadImmediate(tmp_reg, offset, cond); + add(tmp_reg, tmp_reg, ShifterOperand(base), cond); + base = tmp_reg; offset = 0; } CHECK(Address::CanHoldStoreOffsetThumb(type, offset)); @@ -2493,6 +2507,10 @@ void Thumb2Assembler::StoreToOffset(StoreOperandType type, LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } + if (tmp_reg != kNoRegister && tmp_reg != IP) { + DCHECK(tmp_reg == R5 || tmp_reg == R6); + Pop(tmp_reg); + } } |