blob: 0e8f64556dd331722eedfcd3d193b46079686222 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Ian Rogers107c31e2014-01-23 20:55:29 -080017#include "codegen_arm.h"
18
19#include <inttypes.h>
20
Brian Carlstrom7940e442013-07-12 13:46:57 -070021#include <string>
22
Andreas Gampe53c913b2014-08-12 23:19:23 -070023#include "backend_arm.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070024#include "dex/compiler_internals.h"
25#include "dex/quick/mir_to_lir-inl.h"
26
27namespace art {
28
Wei Jin04f4d8a2014-05-29 18:04:29 -070029#ifdef ARM_R4_SUSPEND_FLAG
Vladimir Marko089142c2014-06-05 10:57:05 +010030static constexpr RegStorage core_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070031 {rs_r0, rs_r1, rs_r2, rs_r3, rs_rARM_SUSPEND, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
32 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
Wei Jin04f4d8a2014-05-29 18:04:29 -070033#else
34static constexpr RegStorage core_regs_arr[] =
35 {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
36 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
37#endif
Vladimir Marko089142c2014-06-05 10:57:05 +010038static constexpr RegStorage sp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070039 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
40 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20,
41 rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30,
42 rs_fr31};
Vladimir Marko089142c2014-06-05 10:57:05 +010043static constexpr RegStorage dp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070044 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10,
45 rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15};
Wei Jin04f4d8a2014-05-29 18:04:29 -070046#ifdef ARM_R4_SUSPEND_FLAG
Vladimir Marko089142c2014-06-05 10:57:05 +010047static constexpr RegStorage reserved_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070048 {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
Vladimir Marko089142c2014-06-05 10:57:05 +010049static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
Wei Jin04f4d8a2014-05-29 18:04:29 -070050#else
51static constexpr RegStorage reserved_regs_arr[] =
52 {rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
53static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r12};
54#endif
Vladimir Marko089142c2014-06-05 10:57:05 +010055static constexpr RegStorage sp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070056 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
57 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
Vladimir Marko089142c2014-06-05 10:57:05 +010058static constexpr RegStorage dp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070059 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
60
Vladimir Marko089142c2014-06-05 10:57:05 +010061static constexpr ArrayRef<const RegStorage> empty_pool;
62static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
63static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
64static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
65static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
66static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
67static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
68static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
Brian Carlstrom7940e442013-07-12 13:46:57 -070069
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070070RegLocation ArmMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000071 return arm_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070072}
73
buzbeea0cd2d72014-06-01 09:33:49 -070074RegLocation ArmMir2Lir::LocCReturnRef() {
75 return arm_loc_c_return;
76}
77
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070078RegLocation ArmMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000079 return arm_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070080}
81
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070082RegLocation ArmMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000083 return arm_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070084}
85
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070086RegLocation ArmMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000087 return arm_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070088}
89
90// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080091RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
Zheng Xu5667fdb2014-10-23 18:29:55 +080092 RegStorage res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -070093 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -070094 case kSelf: res_reg = rs_rARM_SELF; break;
Wei Jin04f4d8a2014-05-29 18:04:29 -070095#ifdef ARM_R4_SUSPEND_FLAG
buzbee091cc402014-03-31 10:14:40 -070096 case kSuspend: res_reg = rs_rARM_SUSPEND; break;
Wei Jin04f4d8a2014-05-29 18:04:29 -070097#else
98 case kSuspend: res_reg = RegStorage::InvalidReg(); break;
99#endif
buzbee091cc402014-03-31 10:14:40 -0700100 case kLr: res_reg = rs_rARM_LR; break;
101 case kPc: res_reg = rs_rARM_PC; break;
102 case kSp: res_reg = rs_rARM_SP; break;
103 case kArg0: res_reg = rs_r0; break;
104 case kArg1: res_reg = rs_r1; break;
105 case kArg2: res_reg = rs_r2; break;
106 case kArg3: res_reg = rs_r3; break;
Zheng Xu5667fdb2014-10-23 18:29:55 +0800107 case kFArg0: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r0 : rs_fr0; break;
108 case kFArg1: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r1 : rs_fr1; break;
109 case kFArg2: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r2 : rs_fr2; break;
110 case kFArg3: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r3 : rs_fr3; break;
111 case kFArg4: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr4; break;
112 case kFArg5: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr5; break;
113 case kFArg6: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr6; break;
114 case kFArg7: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr7; break;
115 case kFArg8: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr8; break;
116 case kFArg9: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr9; break;
117 case kFArg10: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr10; break;
118 case kFArg11: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr11; break;
119 case kFArg12: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr12; break;
120 case kFArg13: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr13; break;
121 case kFArg14: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr14; break;
122 case kFArg15: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr15; break;
buzbee091cc402014-03-31 10:14:40 -0700123 case kRet0: res_reg = rs_r0; break;
124 case kRet1: res_reg = rs_r1; break;
125 case kInvokeTgt: res_reg = rs_rARM_LR; break;
126 case kHiddenArg: res_reg = rs_r12; break;
127 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
128 case kCount: res_reg = RegStorage::InvalidReg(); break;
Dmitry Petrochenko58994cd2014-05-17 01:02:18 +0700129 default: res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700130 }
buzbee091cc402014-03-31 10:14:40 -0700131 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700132}
133
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134/*
135 * Decode the register id.
136 */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100137ResourceMask ArmMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
138 return GetRegMaskArm(reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700139}
140
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100141constexpr ResourceMask ArmMir2Lir::GetRegMaskArm(RegStorage reg) {
142 return reg.IsDouble()
143 /* Each double register is equal to a pair of single-precision FP registers */
144 ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kArmFPReg0)
145 : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kArmFPReg0 : reg.GetRegNum());
146}
147
148constexpr ResourceMask ArmMir2Lir::EncodeArmRegList(int reg_list) {
149 return ResourceMask::RawMask(static_cast<uint64_t >(reg_list), 0u);
150}
151
152constexpr ResourceMask ArmMir2Lir::EncodeArmRegFpcsList(int reg_list) {
153 return ResourceMask::RawMask(static_cast<uint64_t >(reg_list) << kArmFPReg16, 0u);
154}
155
156ResourceMask ArmMir2Lir::GetPCUseDefEncoding() const {
157 return ResourceMask::Bit(kArmRegPC);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700158}
159
buzbeeb48819d2013-09-14 16:15:25 -0700160// Thumb2 specific setup. TODO: inline?:
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100161void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags,
162 ResourceMask* use_mask, ResourceMask* def_mask) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700163 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700164 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700165
Brian Carlstrom7940e442013-07-12 13:46:57 -0700166 int opcode = lir->opcode;
167
buzbeeb48819d2013-09-14 16:15:25 -0700168 // These flags are somewhat uncommon - bypass if we can.
169 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
170 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
171 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
172 if (flags & REG_DEF_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100173 def_mask->SetBit(kArmRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700174 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700175
buzbeeb48819d2013-09-14 16:15:25 -0700176 if (flags & REG_USE_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100177 use_mask->SetBit(kArmRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700178 }
buzbeeb48819d2013-09-14 16:15:25 -0700179
180 if (flags & REG_DEF_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100181 def_mask->SetBits(EncodeArmRegList(lir->operands[0]));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700182 }
buzbeeb48819d2013-09-14 16:15:25 -0700183
184 if (flags & REG_DEF_LIST1) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100185 def_mask->SetBits(EncodeArmRegList(lir->operands[1]));
buzbeeb48819d2013-09-14 16:15:25 -0700186 }
187
188 if (flags & REG_DEF_FPCS_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100189 def_mask->SetBits(EncodeArmRegList(lir->operands[0]));
buzbeeb48819d2013-09-14 16:15:25 -0700190 }
191
192 if (flags & REG_DEF_FPCS_LIST2) {
193 for (int i = 0; i < lir->operands[2]; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100194 SetupRegMask(def_mask, lir->operands[1] + i);
buzbeeb48819d2013-09-14 16:15:25 -0700195 }
196 }
197
198 if (flags & REG_USE_PC) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100199 use_mask->SetBit(kArmRegPC);
buzbeeb48819d2013-09-14 16:15:25 -0700200 }
201
202 /* Conservatively treat the IT block */
203 if (flags & IS_IT) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100204 *def_mask = kEncodeAll;
buzbeeb48819d2013-09-14 16:15:25 -0700205 }
206
207 if (flags & REG_USE_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100208 use_mask->SetBits(EncodeArmRegList(lir->operands[0]));
buzbeeb48819d2013-09-14 16:15:25 -0700209 }
210
211 if (flags & REG_USE_LIST1) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100212 use_mask->SetBits(EncodeArmRegList(lir->operands[1]));
buzbeeb48819d2013-09-14 16:15:25 -0700213 }
214
215 if (flags & REG_USE_FPCS_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100216 use_mask->SetBits(EncodeArmRegList(lir->operands[0]));
buzbeeb48819d2013-09-14 16:15:25 -0700217 }
218
219 if (flags & REG_USE_FPCS_LIST2) {
220 for (int i = 0; i < lir->operands[2]; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100221 SetupRegMask(use_mask, lir->operands[1] + i);
buzbeeb48819d2013-09-14 16:15:25 -0700222 }
223 }
224 /* Fixup for kThumbPush/lr and kThumbPop/pc */
225 if (opcode == kThumbPush || opcode == kThumbPop) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100226 constexpr ResourceMask r8Mask = GetRegMaskArm(rs_r8);
227 if ((opcode == kThumbPush) && (use_mask->Intersects(r8Mask))) {
228 use_mask->ClearBits(r8Mask);
229 use_mask->SetBit(kArmRegLR);
230 } else if ((opcode == kThumbPop) && (def_mask->Intersects(r8Mask))) {
231 def_mask->ClearBits(r8Mask);
232 def_mask->SetBit(kArmRegPC);;
buzbeeb48819d2013-09-14 16:15:25 -0700233 }
234 }
235 if (flags & REG_DEF_LR) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100236 def_mask->SetBit(kArmRegLR);
buzbeeb48819d2013-09-14 16:15:25 -0700237 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700238 }
239}
240
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700241ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700242 ArmConditionCode res;
243 switch (ccode) {
244 case kCondEq: res = kArmCondEq; break;
245 case kCondNe: res = kArmCondNe; break;
246 case kCondCs: res = kArmCondCs; break;
247 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000248 case kCondUlt: res = kArmCondCc; break;
249 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700250 case kCondMi: res = kArmCondMi; break;
251 case kCondPl: res = kArmCondPl; break;
252 case kCondVs: res = kArmCondVs; break;
253 case kCondVc: res = kArmCondVc; break;
254 case kCondHi: res = kArmCondHi; break;
255 case kCondLs: res = kArmCondLs; break;
256 case kCondGe: res = kArmCondGe; break;
257 case kCondLt: res = kArmCondLt; break;
258 case kCondGt: res = kArmCondGt; break;
259 case kCondLe: res = kArmCondLe; break;
260 case kCondAl: res = kArmCondAl; break;
261 case kCondNv: res = kArmCondNv; break;
262 default:
263 LOG(FATAL) << "Bad condition code " << ccode;
264 res = static_cast<ArmConditionCode>(0); // Quiet gcc
265 }
266 return res;
267}
268
269static const char* core_reg_names[16] = {
270 "r0",
271 "r1",
272 "r2",
273 "r3",
274 "r4",
275 "r5",
276 "r6",
277 "r7",
278 "r8",
279 "rSELF",
280 "r10",
281 "r11",
282 "r12",
283 "sp",
284 "lr",
285 "pc",
286};
287
288
289static const char* shift_names[4] = {
290 "lsl",
291 "lsr",
292 "asr",
293 "ror"};
294
295/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800296static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700297 int i;
298 bool printed = false;
299 buf[0] = 0;
300 for (i = 0; i < 16; i++, vector >>= 1) {
301 if (vector & 0x1) {
302 int reg_id = i;
303 if (opcode == kThumbPush && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700304 reg_id = rs_rARM_LR.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700305 } else if (opcode == kThumbPop && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700306 reg_id = rs_rARM_PC.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700307 }
308 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800309 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700310 } else {
311 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800312 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700313 }
314 }
315 }
316 return buf;
317}
318
Ian Rogers988e6ea2014-01-08 11:30:50 -0800319static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
320 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700321 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800322 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700323 }
324 return buf;
325}
326
buzbee0d829482013-10-11 15:24:55 -0700327static int32_t ExpandImmediate(int value) {
328 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700329 uint32_t bits = value & 0xff;
330 switch (mode) {
331 case 0:
332 return bits;
333 case 1:
334 return (bits << 16) | bits;
335 case 2:
336 return (bits << 24) | (bits << 8);
337 case 3:
338 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
339 default:
340 break;
341 }
342 bits = (bits | 0x80) << 24;
343 return bits >> (((value & 0xf80) >> 7) - 8);
344}
345
Brian Carlstromb1eba212013-07-17 18:07:19 -0700346const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
347 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700348/*
349 * Interpret a format string and build a string no longer than size
350 * See format key in Assemble.c.
351 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700352std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700353 std::string buf;
354 int i;
355 const char* fmt_end = &fmt[strlen(fmt)];
356 char tbuf[256];
357 const char* name;
358 char nc;
359 while (fmt < fmt_end) {
360 int operand;
361 if (*fmt == '!') {
362 fmt++;
363 DCHECK_LT(fmt, fmt_end);
364 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700365 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700366 strcpy(tbuf, "!");
367 } else {
368 DCHECK_LT(fmt, fmt_end);
369 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
370 operand = lir->operands[nc-'0'];
371 switch (*fmt++) {
372 case 'H':
373 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800374 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700375 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700376 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700377 }
378 break;
379 case 'B':
380 switch (operand) {
381 case kSY:
382 name = "sy";
383 break;
384 case kST:
385 name = "st";
386 break;
387 case kISH:
388 name = "ish";
389 break;
390 case kISHST:
391 name = "ishst";
392 break;
393 case kNSH:
394 name = "nsh";
395 break;
396 case kNSHST:
397 name = "shst";
398 break;
399 default:
400 name = "DecodeError2";
401 break;
402 }
403 strcpy(tbuf, name);
404 break;
405 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700406 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700407 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700408 tbuf[i] += operand & 1;
409 operand >>= 1;
410 }
411 break;
412 case 'n':
413 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800414 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700415 break;
416 case 'm':
417 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800418 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700419 break;
420 case 's':
buzbee091cc402014-03-31 10:14:40 -0700421 snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700422 break;
423 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700424 snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700425 break;
426 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800427 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700428 break;
429 case 'M':
430 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800431 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700432 break;
433 case 'C':
buzbee091cc402014-03-31 10:14:40 -0700434 operand = RegStorage::RegNum(operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700435 DCHECK_LT(operand, static_cast<int>(
436 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800437 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700438 break;
439 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800440 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700441 break;
442 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800443 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700444 break;
445 case 'c':
446 strcpy(tbuf, cc_names[operand]);
447 break;
448 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800449 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
450 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700451 lir->target);
452 break;
Vladimir Markof4da6752014-08-01 19:04:18 +0100453 case 'T':
454 snprintf(tbuf, arraysize(tbuf), "%s", PrettyMethod(
455 static_cast<uint32_t>(lir->operands[1]),
456 *reinterpret_cast<const DexFile*>(UnwrapPointer(lir->operands[2]))).c_str());
457 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700458 case 'u': {
459 int offset_1 = lir->operands[0];
460 int offset_2 = NEXT_LIR(lir)->operands[0];
461 uintptr_t target =
462 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
463 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
464 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800465 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700466 break;
467 }
468
469 /* Nothing to print for BLX_2 */
470 case 'v':
471 strcpy(tbuf, "see above");
472 break;
473 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800474 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700475 break;
476 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800477 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700478 break;
479 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800480 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700481 break;
482 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700483 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700484 break;
485 }
486 buf += tbuf;
487 }
488 } else {
489 buf += *fmt++;
490 }
491 }
492 return buf;
493}
494
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100495void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, const ResourceMask& mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700496 char buf[256];
497 buf[0] = 0;
498
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100499 if (mask.Equals(kEncodeAll)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700500 strcpy(buf, "all");
501 } else {
502 char num[8];
503 int i;
504
505 for (i = 0; i < kArmRegEnd; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100506 if (mask.HasBit(i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800507 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700508 strcat(buf, num);
509 }
510 }
511
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100512 if (mask.HasBit(ResourceMask::kCCode)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700513 strcat(buf, "cc ");
514 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100515 if (mask.HasBit(ResourceMask::kFPStatus)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700516 strcat(buf, "fpcc ");
517 }
518
519 /* Memory bits */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100520 if (arm_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800521 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
522 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
523 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700524 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100525 if (mask.HasBit(ResourceMask::kLiteral)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700526 strcat(buf, "lit ");
527 }
528
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100529 if (mask.HasBit(ResourceMask::kHeapRef)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700530 strcat(buf, "heap ");
531 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100532 if (mask.HasBit(ResourceMask::kMustNotAlias)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700533 strcat(buf, "noalias ");
534 }
535 }
536 if (buf[0]) {
537 LOG(INFO) << prefix << ": " << buf;
538 }
539}
540
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700541bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700542 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
543}
544
Vladimir Marko674744e2014-04-24 15:18:26 +0100545RegisterClass ArmMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
546 if (UNLIKELY(is_volatile)) {
547 // On arm, atomic 64-bit load/store requires a core register pair.
548 // Smaller aligned load/store is atomic for both core and fp registers.
549 if (size == k64 || size == kDouble) {
550 return kCoreReg;
551 }
552 }
553 return RegClassBySize(size);
554}
555
Brian Carlstrom7940e442013-07-12 13:46:57 -0700556ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
Vladimir Markof4da6752014-08-01 19:04:18 +0100557 : Mir2Lir(cu, mir_graph, arena),
558 call_method_insns_(arena->Adapter()) {
559 call_method_insns_.reserve(100);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700560 // Sanity check - make sure encoding map lines up.
561 for (int i = 0; i < kArmLast; i++) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700562 DCHECK_EQ(ArmMir2Lir::EncodingMap[i].opcode, i)
563 << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
564 << " is wrong: expecting " << i << ", seeing "
565 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700566 }
567}
568
569Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
570 ArenaAllocator* const arena) {
571 return new ArmMir2Lir(cu, mir_graph, arena);
572}
573
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700574void ArmMir2Lir::CompilerInitializeRegAlloc() {
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100575 reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */,
576 sp_regs, dp_regs,
577 reserved_regs, empty_pool /* reserved64 */,
578 core_temps, empty_pool /* core64_temps */,
579 sp_temps, dp_temps));
Dave Allisonf6b65c12014-04-01 17:45:18 -0700580
buzbee091cc402014-03-31 10:14:40 -0700581 // Target-specific adjustments.
582
583 // Alias single precision floats to appropriate half of overlapping double.
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100584 for (RegisterInfo* info : reg_pool_->sp_regs_) {
buzbee091cc402014-03-31 10:14:40 -0700585 int sp_reg_num = info->GetReg().GetRegNum();
586 int dp_reg_num = sp_reg_num >> 1;
587 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
588 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
589 // Double precision register's master storage should refer to itself.
590 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
591 // Redirect single precision's master storage to master.
592 info->SetMaster(dp_reg_info);
593 // Singles should show a single 32-bit mask bit, at first referring to the low half.
buzbee85089dd2014-05-25 15:10:52 -0700594 DCHECK_EQ(info->StorageMask(), RegisterInfo::kLowSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700595 if (sp_reg_num & 1) {
buzbee85089dd2014-05-25 15:10:52 -0700596 // For odd singles, change to use the high word of the backing double.
597 info->SetStorageMask(RegisterInfo::kHighSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700598 }
599 }
600
Wei Jin04f4d8a2014-05-29 18:04:29 -0700601#ifdef ARM_R4_SUSPEND_FLAG
Dave Allison83252962014-04-03 16:33:48 -0700602 // TODO: re-enable this when we can safely save r4 over the suspension code path.
603 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
buzbee091cc402014-03-31 10:14:40 -0700604 if (no_suspend) {
605 GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700606 }
Wei Jin04f4d8a2014-05-29 18:04:29 -0700607#endif
Brian Carlstrom7940e442013-07-12 13:46:57 -0700608
buzbee091cc402014-03-31 10:14:40 -0700609 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
610 // TODO: adjust when we roll to hard float calling convention.
611 reg_pool_->next_core_reg_ = 2;
612 reg_pool_->next_sp_reg_ = 0;
613 reg_pool_->next_dp_reg_ = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700614}
615
Brian Carlstrom7940e442013-07-12 13:46:57 -0700616/*
617 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
618 * instructions might call out to C/assembly helper functions. Until
619 * machinery is in place, always spill lr.
620 */
621
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700622void ArmMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700623 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700624 num_core_spills_++;
625}
626
627/*
628 * Mark a callee-save fp register as promoted. Note that
629 * vpush/vpop uses contiguous register lists so we must
630 * include any holes in the mask. Associate holes with
631 * Dalvik register INVALID_VREG (0xFFFFU).
632 */
buzbee091cc402014-03-31 10:14:40 -0700633void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
634 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
635 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700636 // Ensure fp_vmap_table is large enough
637 int table_size = fp_vmap_table_.size();
buzbee091cc402014-03-31 10:14:40 -0700638 for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700639 fp_vmap_table_.push_back(INVALID_VREG);
640 }
641 // Add the current mapping
buzbee091cc402014-03-31 10:14:40 -0700642 fp_vmap_table_[adjusted_reg_num] = v_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700643 // Size of fp_vmap_table is high-water mark, use to set mask
644 num_fp_spills_ = fp_vmap_table_.size();
645 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
646}
647
buzbee091cc402014-03-31 10:14:40 -0700648void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
649 // TEMP: perform as 2 singles.
650 int reg_num = reg.GetRegNum() << 1;
651 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
652 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
653 MarkPreservedSingle(v_reg, lo);
654 MarkPreservedSingle(v_reg + 1, hi);
buzbee2700f7e2014-03-07 09:46:20 -0800655}
656
Brian Carlstrom7940e442013-07-12 13:46:57 -0700657/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000658void ArmMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700659 // TODO: rework this - it's gotten even more ugly.
660 Clobber(rs_r0);
661 Clobber(rs_r1);
662 Clobber(rs_r2);
663 Clobber(rs_r3);
664 Clobber(rs_r12);
665 Clobber(rs_r14lr);
666 Clobber(rs_fr0);
667 Clobber(rs_fr1);
668 Clobber(rs_fr2);
669 Clobber(rs_fr3);
670 Clobber(rs_fr4);
671 Clobber(rs_fr5);
672 Clobber(rs_fr6);
673 Clobber(rs_fr7);
674 Clobber(rs_fr8);
675 Clobber(rs_fr9);
676 Clobber(rs_fr10);
677 Clobber(rs_fr11);
678 Clobber(rs_fr12);
679 Clobber(rs_fr13);
680 Clobber(rs_fr14);
681 Clobber(rs_fr15);
682 Clobber(rs_dr0);
683 Clobber(rs_dr1);
684 Clobber(rs_dr2);
685 Clobber(rs_dr3);
686 Clobber(rs_dr4);
687 Clobber(rs_dr5);
688 Clobber(rs_dr6);
689 Clobber(rs_dr7);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700690}
691
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700692RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700693 RegLocation res = LocCReturnWide();
buzbee091cc402014-03-31 10:14:40 -0700694 res.reg.SetLowReg(rs_r2.GetReg());
695 res.reg.SetHighReg(rs_r3.GetReg());
696 Clobber(rs_r2);
697 Clobber(rs_r3);
698 MarkInUse(rs_r2);
699 MarkInUse(rs_r3);
700 MarkWide(res.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700701 return res;
702}
703
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700704RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700705 RegLocation res = LocCReturn();
buzbee091cc402014-03-31 10:14:40 -0700706 res.reg.SetReg(rs_r1.GetReg());
707 Clobber(rs_r1);
708 MarkInUse(rs_r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700709 return res;
710}
711
Brian Carlstrom7940e442013-07-12 13:46:57 -0700712/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700713void ArmMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700714 LockTemp(rs_r0);
715 LockTemp(rs_r1);
716 LockTemp(rs_r2);
717 LockTemp(rs_r3);
Zheng Xu5667fdb2014-10-23 18:29:55 +0800718 if (!kArm32QuickCodeUseSoftFloat) {
719 LockTemp(rs_fr0);
720 LockTemp(rs_fr1);
721 LockTemp(rs_fr2);
722 LockTemp(rs_fr3);
723 LockTemp(rs_fr4);
724 LockTemp(rs_fr5);
725 LockTemp(rs_fr6);
726 LockTemp(rs_fr7);
727 LockTemp(rs_fr8);
728 LockTemp(rs_fr9);
729 LockTemp(rs_fr10);
730 LockTemp(rs_fr11);
731 LockTemp(rs_fr12);
732 LockTemp(rs_fr13);
733 LockTemp(rs_fr14);
734 LockTemp(rs_fr15);
735 LockTemp(rs_dr0);
736 LockTemp(rs_dr1);
737 LockTemp(rs_dr2);
738 LockTemp(rs_dr3);
739 LockTemp(rs_dr4);
740 LockTemp(rs_dr5);
741 LockTemp(rs_dr6);
742 LockTemp(rs_dr7);
743 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700744}
745
746/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700747void ArmMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700748 FreeTemp(rs_r0);
749 FreeTemp(rs_r1);
750 FreeTemp(rs_r2);
751 FreeTemp(rs_r3);
Zheng Xu5667fdb2014-10-23 18:29:55 +0800752 if (!kArm32QuickCodeUseSoftFloat) {
753 FreeTemp(rs_fr0);
754 FreeTemp(rs_fr1);
755 FreeTemp(rs_fr2);
756 FreeTemp(rs_fr3);
757 FreeTemp(rs_fr4);
758 FreeTemp(rs_fr5);
759 FreeTemp(rs_fr6);
760 FreeTemp(rs_fr7);
761 FreeTemp(rs_fr8);
762 FreeTemp(rs_fr9);
763 FreeTemp(rs_fr10);
764 FreeTemp(rs_fr11);
765 FreeTemp(rs_fr12);
766 FreeTemp(rs_fr13);
767 FreeTemp(rs_fr14);
768 FreeTemp(rs_fr15);
769 FreeTemp(rs_dr0);
770 FreeTemp(rs_dr1);
771 FreeTemp(rs_dr2);
772 FreeTemp(rs_dr3);
773 FreeTemp(rs_dr4);
774 FreeTemp(rs_dr5);
775 FreeTemp(rs_dr6);
776 FreeTemp(rs_dr7);
777 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700778}
779
Andreas Gampe98430592014-07-27 19:44:50 -0700780RegStorage ArmMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
781 LoadWordDisp(rs_rARM_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rARM_LR);
buzbee2700f7e2014-03-07 09:46:20 -0800782 return rs_rARM_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700783}
784
Dave Allisonb373e092014-02-20 16:06:36 -0800785LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800786 RegStorage tmp = rs_r0;
buzbee695d13a2014-04-19 13:32:20 -0700787 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
788 LIR* load2 = Load32Disp(tmp, 0, tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800789 return load2;
790}
791
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700792uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700793 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700794 return ArmMir2Lir::EncodingMap[opcode].flags;
795}
796
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700797const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700798 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700799 return ArmMir2Lir::EncodingMap[opcode].name;
800}
801
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700802const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700803 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700804 return ArmMir2Lir::EncodingMap[opcode].fmt;
805}
806
buzbee091cc402014-03-31 10:14:40 -0700807/*
808 * Somewhat messy code here. We want to allocate a pair of contiguous
809 * physical single-precision floating point registers starting with
810 * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
811 * has already been allocated - try to fit if possible. Fail to
812 * allocate if we can't meet the requirements for the pair of
813 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
814 */
815// TODO: needs rewrite to support non-backed 64-bit float regs.
816RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
817 RegStorage res;
818 int v_reg = mir_graph_->SRegToVReg(s_reg);
819 int p_map_idx = SRegToPMap(s_reg);
820 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
821 // Upper reg is already allocated. Can we fit?
buzbeeb5860fb2014-06-21 15:31:01 -0700822 int high_reg = promotion_map_[p_map_idx+1].fp_reg;
buzbee091cc402014-03-31 10:14:40 -0700823 if ((high_reg & 1) == 0) {
824 // High reg is even - fail.
825 return res; // Invalid.
826 }
827 // Is the low reg of the pair free?
828 // FIXME: rework.
829 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
830 if (p->InUse() || p->IsTemp()) {
831 // Already allocated or not preserved - fail.
832 return res; // Invalid.
833 }
834 // OK - good to go.
835 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
836 p->MarkInUse();
837 MarkPreservedSingle(v_reg, p->GetReg());
838 } else {
839 /*
840 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
841 * different underlying physical registers.
842 */
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100843 for (RegisterInfo* info : reg_pool_->dp_regs_) {
buzbee091cc402014-03-31 10:14:40 -0700844 if (!info->IsTemp() && !info->InUse()) {
845 res = info->GetReg();
846 info->MarkInUse();
847 MarkPreservedDouble(v_reg, info->GetReg());
848 break;
849 }
850 }
851 }
852 if (res.Valid()) {
buzbee85089dd2014-05-25 15:10:52 -0700853 RegisterInfo* info = GetRegInfo(res);
buzbee091cc402014-03-31 10:14:40 -0700854 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
buzbeeb5860fb2014-06-21 15:31:01 -0700855 promotion_map_[p_map_idx].fp_reg =
buzbee85089dd2014-05-25 15:10:52 -0700856 info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700857 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
buzbeeb5860fb2014-06-21 15:31:01 -0700858 promotion_map_[p_map_idx+1].fp_reg =
buzbee85089dd2014-05-25 15:10:52 -0700859 info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700860 }
861 return res;
862}
863
buzbeeb5860fb2014-06-21 15:31:01 -0700864// Reserve a callee-save sp single register.
865RegStorage ArmMir2Lir::AllocPreservedSingle(int s_reg) {
866 RegStorage res;
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100867 for (RegisterInfo* info : reg_pool_->sp_regs_) {
buzbeeb5860fb2014-06-21 15:31:01 -0700868 if (!info->IsTemp() && !info->InUse()) {
869 res = info->GetReg();
870 int p_map_idx = SRegToPMap(s_reg);
871 int v_reg = mir_graph_->SRegToVReg(s_reg);
872 GetRegInfo(res)->MarkInUse();
873 MarkPreservedSingle(v_reg, res);
874 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
875 promotion_map_[p_map_idx].fp_reg = res.GetReg();
876 break;
877 }
878 }
879 return res;
880}
881
Vladimir Markof4da6752014-08-01 19:04:18 +0100882void ArmMir2Lir::InstallLiteralPools() {
883 // PC-relative calls to methods.
884 patches_.reserve(call_method_insns_.size());
885 for (LIR* p : call_method_insns_) {
886 DCHECK_EQ(p->opcode, kThumb2Bl);
887 uint32_t target_method_idx = p->operands[1];
888 const DexFile* target_dex_file =
889 reinterpret_cast<const DexFile*>(UnwrapPointer(p->operands[2]));
890
891 patches_.push_back(LinkerPatch::RelativeCodePatch(p->offset,
892 target_dex_file, target_method_idx));
893 }
894
895 // And do the normal processing.
896 Mir2Lir::InstallLiteralPools();
897}
898
Zheng Xu5667fdb2014-10-23 18:29:55 +0800899RegStorage ArmMir2Lir::InToRegStorageArmMapper::GetNextReg(bool is_double_or_float, bool is_wide) {
900 const RegStorage coreArgMappingToPhysicalReg[] =
901 {rs_r1, rs_r2, rs_r3};
902 const int coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
903 const RegStorage fpArgMappingToPhysicalReg[] =
904 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7,
905 rs_fr8, rs_fr9, rs_fr10, rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
Andreas Gampe785d2f22014-11-03 22:57:30 -0800906 constexpr uint32_t fpArgMappingToPhysicalRegSize = arraysize(fpArgMappingToPhysicalReg);
907 static_assert(fpArgMappingToPhysicalRegSize % 2 == 0, "Number of FP Arg regs is not even");
Zheng Xu5667fdb2014-10-23 18:29:55 +0800908
909 if (kArm32QuickCodeUseSoftFloat) {
910 is_double_or_float = false; // Regard double as long, float as int.
911 is_wide = false; // Map long separately.
912 }
913
914 RegStorage result = RegStorage::InvalidReg();
915 if (is_double_or_float) {
916 // TODO: Remove "cur_fp_double_reg_ % 2 != 0" when we return double as double.
917 if (is_wide || cur_fp_double_reg_ % 2 != 0) {
918 cur_fp_double_reg_ = std::max(cur_fp_double_reg_, RoundUp(cur_fp_reg_, 2));
919 if (cur_fp_double_reg_ < fpArgMappingToPhysicalRegSize) {
920 // TODO: Replace by following code in the branch when FlushIns() support 64-bit registers.
921 // result = RegStorage::MakeRegPair(fpArgMappingToPhysicalReg[cur_fp_double_reg_],
922 // fpArgMappingToPhysicalReg[cur_fp_double_reg_ + 1]);
923 // result = As64BitFloatReg(result);
924 // cur_fp_double_reg_ += 2;
925 result = fpArgMappingToPhysicalReg[cur_fp_double_reg_];
926 cur_fp_double_reg_++;
927 }
928 } else {
929 // TODO: Remove the check when we return double as double.
930 DCHECK_EQ(cur_fp_double_reg_ % 2, 0U);
931 if (cur_fp_reg_ % 2 == 0) {
932 cur_fp_reg_ = std::max(cur_fp_double_reg_, cur_fp_reg_);
933 }
934 if (cur_fp_reg_ < fpArgMappingToPhysicalRegSize) {
935 result = fpArgMappingToPhysicalReg[cur_fp_reg_];
936 cur_fp_reg_++;
937 }
938 }
939 } else {
940 if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
941 result = coreArgMappingToPhysicalReg[cur_core_reg_++];
942 // TODO: Enable following code when FlushIns() support 64-bit registers.
943 // if (is_wide && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
944 // result = RegStorage::MakeRegPair(result, coreArgMappingToPhysicalReg[cur_core_reg_++]);
945 // }
946 }
947 }
948 return result;
949}
950
951RegStorage ArmMir2Lir::InToRegStorageMapping::Get(int in_position) const {
952 DCHECK(IsInitialized());
953 auto res = mapping_.find(in_position);
954 return res != mapping_.end() ? res->second : RegStorage::InvalidReg();
955}
956
957void ArmMir2Lir::InToRegStorageMapping::Initialize(RegLocation* arg_locs, int count,
958 InToRegStorageMapper* mapper) {
959 DCHECK(mapper != nullptr);
960 max_mapped_in_ = -1;
961 is_there_stack_mapped_ = false;
962 for (int in_position = 0; in_position < count; in_position++) {
963 RegStorage reg = mapper->GetNextReg(arg_locs[in_position].fp,
964 arg_locs[in_position].wide);
965 if (reg.Valid()) {
966 mapping_[in_position] = reg;
967 // TODO: Enable the following code when FlushIns() support 64-bit argument registers.
968 // if (arg_locs[in_position].wide) {
969 // if (reg.Is32Bit()) {
970 // // As it is a split long, the hi-part is on stack.
971 // is_there_stack_mapped_ = true;
972 // }
973 // // We covered 2 v-registers, so skip the next one
974 // in_position++;
975 // }
976 max_mapped_in_ = std::max(max_mapped_in_, in_position);
977 } else {
978 is_there_stack_mapped_ = true;
979 }
980 }
981 initialized_ = true;
982}
983
984// TODO: Should be able to return long, double registers.
985// Need check some common code as it will break some assumption.
986RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
987 if (!in_to_reg_storage_mapping_.IsInitialized()) {
988 int start_vreg = mir_graph_->GetFirstInVR();
989 RegLocation* arg_locs = &mir_graph_->reg_location_[start_vreg];
990
991 InToRegStorageArmMapper mapper;
992 in_to_reg_storage_mapping_.Initialize(arg_locs, mir_graph_->GetNumOfInVRs(), &mapper);
993 }
994 return in_to_reg_storage_mapping_.Get(arg_num);
995}
996
997int ArmMir2Lir::GenDalvikArgsNoRange(CallInfo* info,
998 int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
999 const MethodReference& target_method,
1000 uint32_t vtable_idx, uintptr_t direct_code,
1001 uintptr_t direct_method, InvokeType type, bool skip_this) {
1002 if (kArm32QuickCodeUseSoftFloat) {
1003 return Mir2Lir::GenDalvikArgsNoRange(info, call_state, pcrLabel, next_call_insn, target_method,
1004 vtable_idx, direct_code, direct_method, type, skip_this);
1005 } else {
1006 return GenDalvikArgsRange(info, call_state, pcrLabel, next_call_insn, target_method, vtable_idx,
1007 direct_code, direct_method, type, skip_this);
1008 }
1009}
1010
1011int ArmMir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
1012 LIR** pcrLabel, NextCallInsn next_call_insn,
1013 const MethodReference& target_method,
1014 uint32_t vtable_idx, uintptr_t direct_code,
1015 uintptr_t direct_method, InvokeType type, bool skip_this) {
1016 if (kArm32QuickCodeUseSoftFloat) {
1017 return Mir2Lir::GenDalvikArgsRange(info, call_state, pcrLabel, next_call_insn, target_method,
1018 vtable_idx, direct_code, direct_method, type, skip_this);
1019 }
1020
1021 // TODO: Rework the implementation when argument register can be long or double.
1022
1023 /* If no arguments, just return */
1024 if (info->num_arg_words == 0) {
1025 return call_state;
1026 }
1027
1028 const int start_index = skip_this ? 1 : 0;
1029
1030 InToRegStorageArmMapper mapper;
1031 InToRegStorageMapping in_to_reg_storage_mapping;
1032 in_to_reg_storage_mapping.Initialize(info->args, info->num_arg_words, &mapper);
1033 const int last_mapped_in = in_to_reg_storage_mapping.GetMaxMappedIn();
1034 int regs_left_to_pass_via_stack = info->num_arg_words - (last_mapped_in + 1);
1035
1036 // First of all, check whether it makes sense to use bulk copying.
1037 // Bulk copying is done only for the range case.
1038 // TODO: make a constant instead of 2
1039 if (info->is_range && regs_left_to_pass_via_stack >= 2) {
1040 // Scan the rest of the args - if in phys_reg flush to memory
1041 for (int next_arg = last_mapped_in + 1; next_arg < info->num_arg_words;) {
1042 RegLocation loc = info->args[next_arg];
1043 if (loc.wide) {
1044 // TODO: Only flush hi-part.
1045 if (loc.high_word) {
1046 loc = info->args[--next_arg];
1047 }
1048 loc = UpdateLocWide(loc);
1049 if (loc.location == kLocPhysReg) {
1050 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1051 StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64, kNotVolatile);
1052 }
1053 next_arg += 2;
1054 } else {
1055 loc = UpdateLoc(loc);
1056 if (loc.location == kLocPhysReg) {
1057 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1058 if (loc.ref) {
1059 StoreRefDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, kNotVolatile);
1060 } else {
1061 StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k32,
1062 kNotVolatile);
1063 }
1064 }
1065 next_arg++;
1066 }
1067 }
1068
1069 // The rest can be copied together
1070 int start_offset = SRegOffset(info->args[last_mapped_in + 1].s_reg_low);
1071 int outs_offset = StackVisitor::GetOutVROffset(last_mapped_in + 1,
1072 cu_->instruction_set);
1073
1074 int current_src_offset = start_offset;
1075 int current_dest_offset = outs_offset;
1076
1077 // Only davik regs are accessed in this loop; no next_call_insn() calls.
1078 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1079 while (regs_left_to_pass_via_stack > 0) {
1080 /*
1081 * TODO: Improve by adding block copy for large number of arguments. This
1082 * should be done, if possible, as a target-depending helper. For now, just
1083 * copy a Dalvik vreg at a time.
1084 */
1085 // Moving 32-bits via general purpose register.
1086 size_t bytes_to_move = sizeof(uint32_t);
1087
1088 // Instead of allocating a new temp, simply reuse one of the registers being used
1089 // for argument passing.
1090 RegStorage temp = TargetReg(kArg3, kNotWide);
1091
1092 // Now load the argument VR and store to the outs.
1093 Load32Disp(TargetPtrReg(kSp), current_src_offset, temp);
1094 Store32Disp(TargetPtrReg(kSp), current_dest_offset, temp);
1095
1096 current_src_offset += bytes_to_move;
1097 current_dest_offset += bytes_to_move;
1098 regs_left_to_pass_via_stack -= (bytes_to_move >> 2);
1099 }
1100 DCHECK_EQ(regs_left_to_pass_via_stack, 0);
1101 }
1102
1103 // Now handle rest not registers if they are
1104 if (in_to_reg_storage_mapping.IsThereStackMapped()) {
1105 RegStorage regWide = TargetReg(kArg2, kWide);
1106 for (int i = start_index; i <= last_mapped_in + regs_left_to_pass_via_stack; i++) {
1107 RegLocation rl_arg = info->args[i];
1108 rl_arg = UpdateRawLoc(rl_arg);
1109 RegStorage reg = in_to_reg_storage_mapping.Get(i);
1110 // TODO: Only pass split wide hi-part via stack.
1111 if (!reg.Valid() || rl_arg.wide) {
1112 int out_offset = StackVisitor::GetOutVROffset(i, cu_->instruction_set);
1113
1114 {
1115 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1116 if (rl_arg.wide) {
1117 if (rl_arg.location == kLocPhysReg) {
1118 StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k64, kNotVolatile);
1119 } else {
1120 LoadValueDirectWideFixed(rl_arg, regWide);
1121 StoreBaseDisp(TargetPtrReg(kSp), out_offset, regWide, k64, kNotVolatile);
1122 }
1123 } else {
1124 if (rl_arg.location == kLocPhysReg) {
1125 if (rl_arg.ref) {
1126 StoreRefDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, kNotVolatile);
1127 } else {
1128 StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k32, kNotVolatile);
1129 }
1130 } else {
1131 if (rl_arg.ref) {
1132 RegStorage regSingle = TargetReg(kArg2, kRef);
1133 LoadValueDirectFixed(rl_arg, regSingle);
1134 StoreRefDisp(TargetPtrReg(kSp), out_offset, regSingle, kNotVolatile);
1135 } else {
1136 RegStorage regSingle = TargetReg(kArg2, kNotWide);
1137 LoadValueDirectFixed(rl_arg, regSingle);
1138 StoreBaseDisp(TargetPtrReg(kSp), out_offset, regSingle, k32, kNotVolatile);
1139 }
1140 }
1141 }
1142 }
1143
1144 call_state = next_call_insn(cu_, info, call_state, target_method,
1145 vtable_idx, direct_code, direct_method, type);
1146 }
1147 if (rl_arg.wide) {
1148 i++;
1149 }
1150 }
1151 }
1152
1153 // Finish with mapped registers
1154 for (int i = start_index; i <= last_mapped_in; i++) {
1155 RegLocation rl_arg = info->args[i];
1156 rl_arg = UpdateRawLoc(rl_arg);
1157 RegStorage reg = in_to_reg_storage_mapping.Get(i);
1158 if (reg.Valid()) {
1159 if (reg.Is64Bit()) {
1160 LoadValueDirectWideFixed(rl_arg, reg);
1161 } else {
1162 // TODO: Only split long should be the case we need to care about.
1163 if (rl_arg.wide) {
1164 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1165 int high_word = rl_arg.high_word ? 1 : 0;
1166 rl_arg = high_word ? info->args[i - 1] : rl_arg;
1167 if (rl_arg.location == kLocPhysReg) {
1168 RegStorage rs_arg = rl_arg.reg;
1169 if (rs_arg.IsDouble() && rs_arg.Is64BitSolo()) {
1170 rs_arg = As64BitFloatRegPair(rs_arg);
1171 }
1172 RegStorage rs_arg_low = rs_arg.GetLow();
1173 RegStorage rs_arg_high = rs_arg.GetHigh();
1174 OpRegCopy(reg, high_word ? rs_arg_high : rs_arg_low);
1175 } else {
1176 Load32Disp(TargetPtrReg(kSp), SRegOffset(rl_arg.s_reg_low + high_word), reg);
1177 }
1178 } else {
1179 LoadValueDirectFixed(rl_arg, reg);
1180 }
1181 }
1182 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
1183 direct_code, direct_method, type);
1184 }
1185 if (reg.Is64Bit()) {
1186 i++;
1187 }
1188 }
1189
1190 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
1191 direct_code, direct_method, type);
1192 if (pcrLabel) {
1193 if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
1194 *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
1195 } else {
1196 *pcrLabel = nullptr;
1197 // In lieu of generating a check for kArg1 being null, we need to
1198 // perform a load when doing implicit checks.
1199 RegStorage tmp = AllocTemp();
1200 Load32Disp(TargetReg(kArg1, kRef), 0, tmp);
1201 MarkPossibleNullPointerException(info->opt_flags);
1202 FreeTemp(tmp);
1203 }
1204 }
1205 return call_state;
1206}
1207
Brian Carlstrom7940e442013-07-12 13:46:57 -07001208} // namespace art