summaryrefslogtreecommitdiffstats
path: root/compiler/utils/arm
diff options
context:
space:
mode:
authorRoland Levillain <rpl@google.com>2014-11-04 17:43:11 +0000
committerRoland Levillain <rpl@google.com>2014-11-04 17:43:11 +0000
commit775ef49bad8e8d9d02fc5968858dce6a00a78475 (patch)
treeeb61ed86fcaa5c168b1bbb301c931179f107b7e7 /compiler/utils/arm
parente03864e99f5ab0e27a48a17275122ad8f324b615 (diff)
downloadandroid_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.cc30
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);
+ }
}