blob: bd9c8b4b75db49bd23310b940381cc9e8e473e47 [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
Brian Carlstrom7940e442013-07-12 13:46:57 -070023#include "dex/compiler_internals.h"
24#include "dex/quick/mir_to_lir-inl.h"
25
26namespace art {
27
Wei Jin04f4d8a2014-05-29 18:04:29 -070028#ifdef ARM_R4_SUSPEND_FLAG
Vladimir Marko089142c2014-06-05 10:57:05 +010029static constexpr RegStorage core_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070030 {rs_r0, rs_r1, rs_r2, rs_r3, rs_rARM_SUSPEND, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
31 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
Wei Jin04f4d8a2014-05-29 18:04:29 -070032#else
33static constexpr RegStorage core_regs_arr[] =
34 {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
35 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
36#endif
Vladimir Marko089142c2014-06-05 10:57:05 +010037static constexpr RegStorage sp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070038 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
39 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20,
40 rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30,
41 rs_fr31};
Vladimir Marko089142c2014-06-05 10:57:05 +010042static constexpr RegStorage dp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070043 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10,
44 rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15};
Wei Jin04f4d8a2014-05-29 18:04:29 -070045#ifdef ARM_R4_SUSPEND_FLAG
Vladimir Marko089142c2014-06-05 10:57:05 +010046static constexpr RegStorage reserved_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070047 {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
Vladimir Marko089142c2014-06-05 10:57:05 +010048static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
Wei Jin04f4d8a2014-05-29 18:04:29 -070049#else
50static constexpr RegStorage reserved_regs_arr[] =
51 {rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
52static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r12};
53#endif
Vladimir Marko089142c2014-06-05 10:57:05 +010054static constexpr RegStorage sp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070055 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
56 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
Vladimir Marko089142c2014-06-05 10:57:05 +010057static constexpr RegStorage dp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070058 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
59
Vladimir Marko089142c2014-06-05 10:57:05 +010060static constexpr ArrayRef<const RegStorage> empty_pool;
61static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
62static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
63static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
64static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
65static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
66static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
67static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
Brian Carlstrom7940e442013-07-12 13:46:57 -070068
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070069RegLocation ArmMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000070 return arm_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070071}
72
buzbeea0cd2d72014-06-01 09:33:49 -070073RegLocation ArmMir2Lir::LocCReturnRef() {
74 return arm_loc_c_return;
75}
76
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070077RegLocation ArmMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000078 return arm_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070079}
80
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070081RegLocation ArmMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000082 return arm_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070083}
84
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070085RegLocation ArmMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000086 return arm_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070087}
88
89// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080090RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
buzbee091cc402014-03-31 10:14:40 -070091 RegStorage res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -070092 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -070093 case kSelf: res_reg = rs_rARM_SELF; break;
Wei Jin04f4d8a2014-05-29 18:04:29 -070094#ifdef ARM_R4_SUSPEND_FLAG
buzbee091cc402014-03-31 10:14:40 -070095 case kSuspend: res_reg = rs_rARM_SUSPEND; break;
Wei Jin04f4d8a2014-05-29 18:04:29 -070096#else
97 case kSuspend: res_reg = RegStorage::InvalidReg(); break;
98#endif
buzbee091cc402014-03-31 10:14:40 -070099 case kLr: res_reg = rs_rARM_LR; break;
100 case kPc: res_reg = rs_rARM_PC; break;
101 case kSp: res_reg = rs_rARM_SP; break;
102 case kArg0: res_reg = rs_r0; break;
103 case kArg1: res_reg = rs_r1; break;
104 case kArg2: res_reg = rs_r2; break;
105 case kArg3: res_reg = rs_r3; break;
106 case kFArg0: res_reg = rs_r0; break;
107 case kFArg1: res_reg = rs_r1; break;
108 case kFArg2: res_reg = rs_r2; break;
109 case kFArg3: res_reg = rs_r3; break;
110 case kRet0: res_reg = rs_r0; break;
111 case kRet1: res_reg = rs_r1; break;
112 case kInvokeTgt: res_reg = rs_rARM_LR; break;
113 case kHiddenArg: res_reg = rs_r12; break;
114 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
115 case kCount: res_reg = RegStorage::InvalidReg(); break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700116 }
buzbee091cc402014-03-31 10:14:40 -0700117 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700118}
119
buzbee2700f7e2014-03-07 09:46:20 -0800120RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800121 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
122 switch (arg_num) {
123 case 0:
buzbee091cc402014-03-31 10:14:40 -0700124 return rs_r1;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800125 case 1:
buzbee091cc402014-03-31 10:14:40 -0700126 return rs_r2;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800127 case 2:
buzbee091cc402014-03-31 10:14:40 -0700128 return rs_r3;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800129 default:
buzbee2700f7e2014-03-07 09:46:20 -0800130 return RegStorage::InvalidReg();
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800131 }
132}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700133
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134/*
135 * Decode the register id.
136 */
buzbee091cc402014-03-31 10:14:40 -0700137uint64_t ArmMir2Lir::GetRegMaskCommon(RegStorage reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700138 uint64_t seed;
139 int shift;
buzbee091cc402014-03-31 10:14:40 -0700140 int reg_id = reg.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700141 /* Each double register is equal to a pair of single-precision FP registers */
buzbee091cc402014-03-31 10:14:40 -0700142 if (reg.IsDouble()) {
143 seed = 0x3;
144 reg_id = reg_id << 1;
145 } else {
146 seed = 1;
147 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700148 /* FP register starts at bit position 16 */
buzbee091cc402014-03-31 10:14:40 -0700149 shift = reg.IsFloat() ? kArmFPReg0 : 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700150 /* Expand the double register id into single offset */
151 shift += reg_id;
152 return (seed << shift);
153}
154
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700155uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700156 return ENCODE_ARM_REG_PC;
157}
158
buzbeeb48819d2013-09-14 16:15:25 -0700159// Thumb2 specific setup. TODO: inline?:
160void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700161 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700162 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700163
Brian Carlstrom7940e442013-07-12 13:46:57 -0700164 int opcode = lir->opcode;
165
buzbeeb48819d2013-09-14 16:15:25 -0700166 // These flags are somewhat uncommon - bypass if we can.
167 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
168 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
169 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
170 if (flags & REG_DEF_SP) {
171 lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700172 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700173
buzbeeb48819d2013-09-14 16:15:25 -0700174 if (flags & REG_USE_SP) {
175 lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700176 }
buzbeeb48819d2013-09-14 16:15:25 -0700177
178 if (flags & REG_DEF_LIST0) {
179 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700180 }
buzbeeb48819d2013-09-14 16:15:25 -0700181
182 if (flags & REG_DEF_LIST1) {
183 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
184 }
185
186 if (flags & REG_DEF_FPCS_LIST0) {
187 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
188 }
189
190 if (flags & REG_DEF_FPCS_LIST2) {
191 for (int i = 0; i < lir->operands[2]; i++) {
192 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
193 }
194 }
195
196 if (flags & REG_USE_PC) {
197 lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
198 }
199
200 /* Conservatively treat the IT block */
201 if (flags & IS_IT) {
202 lir->u.m.def_mask = ENCODE_ALL;
203 }
204
205 if (flags & REG_USE_LIST0) {
206 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
207 }
208
209 if (flags & REG_USE_LIST1) {
210 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
211 }
212
213 if (flags & REG_USE_FPCS_LIST0) {
214 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
215 }
216
217 if (flags & REG_USE_FPCS_LIST2) {
218 for (int i = 0; i < lir->operands[2]; i++) {
219 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
220 }
221 }
222 /* Fixup for kThumbPush/lr and kThumbPop/pc */
223 if (opcode == kThumbPush || opcode == kThumbPop) {
buzbee091cc402014-03-31 10:14:40 -0700224 uint64_t r8Mask = GetRegMaskCommon(rs_r8);
buzbeeb48819d2013-09-14 16:15:25 -0700225 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
226 lir->u.m.use_mask &= ~r8Mask;
227 lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
228 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
229 lir->u.m.def_mask &= ~r8Mask;
230 lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
231 }
232 }
233 if (flags & REG_DEF_LR) {
234 lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
235 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700236 }
237}
238
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700239ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700240 ArmConditionCode res;
241 switch (ccode) {
242 case kCondEq: res = kArmCondEq; break;
243 case kCondNe: res = kArmCondNe; break;
244 case kCondCs: res = kArmCondCs; break;
245 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000246 case kCondUlt: res = kArmCondCc; break;
247 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700248 case kCondMi: res = kArmCondMi; break;
249 case kCondPl: res = kArmCondPl; break;
250 case kCondVs: res = kArmCondVs; break;
251 case kCondVc: res = kArmCondVc; break;
252 case kCondHi: res = kArmCondHi; break;
253 case kCondLs: res = kArmCondLs; break;
254 case kCondGe: res = kArmCondGe; break;
255 case kCondLt: res = kArmCondLt; break;
256 case kCondGt: res = kArmCondGt; break;
257 case kCondLe: res = kArmCondLe; break;
258 case kCondAl: res = kArmCondAl; break;
259 case kCondNv: res = kArmCondNv; break;
260 default:
261 LOG(FATAL) << "Bad condition code " << ccode;
262 res = static_cast<ArmConditionCode>(0); // Quiet gcc
263 }
264 return res;
265}
266
267static const char* core_reg_names[16] = {
268 "r0",
269 "r1",
270 "r2",
271 "r3",
272 "r4",
273 "r5",
274 "r6",
275 "r7",
276 "r8",
277 "rSELF",
278 "r10",
279 "r11",
280 "r12",
281 "sp",
282 "lr",
283 "pc",
284};
285
286
287static const char* shift_names[4] = {
288 "lsl",
289 "lsr",
290 "asr",
291 "ror"};
292
293/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800294static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700295 int i;
296 bool printed = false;
297 buf[0] = 0;
298 for (i = 0; i < 16; i++, vector >>= 1) {
299 if (vector & 0x1) {
300 int reg_id = i;
301 if (opcode == kThumbPush && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700302 reg_id = rs_rARM_LR.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700303 } else if (opcode == kThumbPop && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700304 reg_id = rs_rARM_PC.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700305 }
306 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800307 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700308 } else {
309 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800310 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700311 }
312 }
313 }
314 return buf;
315}
316
Ian Rogers988e6ea2014-01-08 11:30:50 -0800317static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
318 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700319 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800320 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700321 }
322 return buf;
323}
324
buzbee0d829482013-10-11 15:24:55 -0700325static int32_t ExpandImmediate(int value) {
326 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700327 uint32_t bits = value & 0xff;
328 switch (mode) {
329 case 0:
330 return bits;
331 case 1:
332 return (bits << 16) | bits;
333 case 2:
334 return (bits << 24) | (bits << 8);
335 case 3:
336 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
337 default:
338 break;
339 }
340 bits = (bits | 0x80) << 24;
341 return bits >> (((value & 0xf80) >> 7) - 8);
342}
343
Brian Carlstromb1eba212013-07-17 18:07:19 -0700344const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
345 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700346/*
347 * Interpret a format string and build a string no longer than size
348 * See format key in Assemble.c.
349 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700350std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700351 std::string buf;
352 int i;
353 const char* fmt_end = &fmt[strlen(fmt)];
354 char tbuf[256];
355 const char* name;
356 char nc;
357 while (fmt < fmt_end) {
358 int operand;
359 if (*fmt == '!') {
360 fmt++;
361 DCHECK_LT(fmt, fmt_end);
362 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700363 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700364 strcpy(tbuf, "!");
365 } else {
366 DCHECK_LT(fmt, fmt_end);
367 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
368 operand = lir->operands[nc-'0'];
369 switch (*fmt++) {
370 case 'H':
371 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800372 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700373 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700374 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700375 }
376 break;
377 case 'B':
378 switch (operand) {
379 case kSY:
380 name = "sy";
381 break;
382 case kST:
383 name = "st";
384 break;
385 case kISH:
386 name = "ish";
387 break;
388 case kISHST:
389 name = "ishst";
390 break;
391 case kNSH:
392 name = "nsh";
393 break;
394 case kNSHST:
395 name = "shst";
396 break;
397 default:
398 name = "DecodeError2";
399 break;
400 }
401 strcpy(tbuf, name);
402 break;
403 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700404 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700405 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700406 tbuf[i] += operand & 1;
407 operand >>= 1;
408 }
409 break;
410 case 'n':
411 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800412 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700413 break;
414 case 'm':
415 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800416 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700417 break;
418 case 's':
buzbee091cc402014-03-31 10:14:40 -0700419 snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700420 break;
421 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700422 snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700423 break;
424 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800425 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700426 break;
427 case 'M':
428 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800429 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700430 break;
431 case 'C':
buzbee091cc402014-03-31 10:14:40 -0700432 operand = RegStorage::RegNum(operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433 DCHECK_LT(operand, static_cast<int>(
434 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800435 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700436 break;
437 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800438 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700439 break;
440 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800441 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700442 break;
443 case 'c':
444 strcpy(tbuf, cc_names[operand]);
445 break;
446 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800447 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
448 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700449 lir->target);
450 break;
451 case 'u': {
452 int offset_1 = lir->operands[0];
453 int offset_2 = NEXT_LIR(lir)->operands[0];
454 uintptr_t target =
455 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
456 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
457 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800458 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700459 break;
460 }
461
462 /* Nothing to print for BLX_2 */
463 case 'v':
464 strcpy(tbuf, "see above");
465 break;
466 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800467 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700468 break;
469 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800470 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700471 break;
472 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800473 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700474 break;
475 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700476 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700477 break;
478 }
479 buf += tbuf;
480 }
481 } else {
482 buf += *fmt++;
483 }
484 }
485 return buf;
486}
487
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700488void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700489 char buf[256];
490 buf[0] = 0;
491
492 if (mask == ENCODE_ALL) {
493 strcpy(buf, "all");
494 } else {
495 char num[8];
496 int i;
497
498 for (i = 0; i < kArmRegEnd; i++) {
499 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800500 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700501 strcat(buf, num);
502 }
503 }
504
505 if (mask & ENCODE_CCODE) {
506 strcat(buf, "cc ");
507 }
508 if (mask & ENCODE_FP_STATUS) {
509 strcat(buf, "fpcc ");
510 }
511
512 /* Memory bits */
513 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800514 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
515 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
516 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700517 }
518 if (mask & ENCODE_LITERAL) {
519 strcat(buf, "lit ");
520 }
521
522 if (mask & ENCODE_HEAP_REF) {
523 strcat(buf, "heap ");
524 }
525 if (mask & ENCODE_MUST_NOT_ALIAS) {
526 strcat(buf, "noalias ");
527 }
528 }
529 if (buf[0]) {
530 LOG(INFO) << prefix << ": " << buf;
531 }
532}
533
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700534bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700535 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
536}
537
Vladimir Marko674744e2014-04-24 15:18:26 +0100538bool ArmMir2Lir::SupportsVolatileLoadStore(OpSize size) {
539 return true;
540}
541
542RegisterClass ArmMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
543 if (UNLIKELY(is_volatile)) {
544 // On arm, atomic 64-bit load/store requires a core register pair.
545 // Smaller aligned load/store is atomic for both core and fp registers.
546 if (size == k64 || size == kDouble) {
547 return kCoreReg;
548 }
549 }
550 return RegClassBySize(size);
551}
552
Brian Carlstrom7940e442013-07-12 13:46:57 -0700553ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
554 : Mir2Lir(cu, mir_graph, arena) {
555 // Sanity check - make sure encoding map lines up.
556 for (int i = 0; i < kArmLast; i++) {
557 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
558 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
559 << " is wrong: expecting " << i << ", seeing "
560 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
561 }
562 }
563}
564
565Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
566 ArenaAllocator* const arena) {
567 return new ArmMir2Lir(cu, mir_graph, arena);
568}
569
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700570void ArmMir2Lir::CompilerInitializeRegAlloc() {
buzbeeb01bf152014-05-13 15:59:07 -0700571 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs,
572 dp_regs, reserved_regs, empty_pool /* reserved64 */,
573 core_temps, empty_pool /* core64_temps */, sp_temps,
574 dp_temps);
Dave Allisonf6b65c12014-04-01 17:45:18 -0700575
buzbee091cc402014-03-31 10:14:40 -0700576 // Target-specific adjustments.
577
578 // Alias single precision floats to appropriate half of overlapping double.
579 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
580 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
581 int sp_reg_num = info->GetReg().GetRegNum();
582 int dp_reg_num = sp_reg_num >> 1;
583 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
584 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
585 // Double precision register's master storage should refer to itself.
586 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
587 // Redirect single precision's master storage to master.
588 info->SetMaster(dp_reg_info);
589 // Singles should show a single 32-bit mask bit, at first referring to the low half.
buzbee85089dd2014-05-25 15:10:52 -0700590 DCHECK_EQ(info->StorageMask(), RegisterInfo::kLowSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700591 if (sp_reg_num & 1) {
buzbee85089dd2014-05-25 15:10:52 -0700592 // For odd singles, change to use the high word of the backing double.
593 info->SetStorageMask(RegisterInfo::kHighSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700594 }
595 }
596
Wei Jin04f4d8a2014-05-29 18:04:29 -0700597#ifdef ARM_R4_SUSPEND_FLAG
Dave Allison83252962014-04-03 16:33:48 -0700598 // TODO: re-enable this when we can safely save r4 over the suspension code path.
599 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
buzbee091cc402014-03-31 10:14:40 -0700600 if (no_suspend) {
601 GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700602 }
Wei Jin04f4d8a2014-05-29 18:04:29 -0700603#endif
Brian Carlstrom7940e442013-07-12 13:46:57 -0700604
buzbee091cc402014-03-31 10:14:40 -0700605 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
606 // TODO: adjust when we roll to hard float calling convention.
607 reg_pool_->next_core_reg_ = 2;
608 reg_pool_->next_sp_reg_ = 0;
609 reg_pool_->next_dp_reg_ = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700610}
611
Brian Carlstrom7940e442013-07-12 13:46:57 -0700612/*
613 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
614 * instructions might call out to C/assembly helper functions. Until
615 * machinery is in place, always spill lr.
616 */
617
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700618void ArmMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700619 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700620 num_core_spills_++;
621}
622
623/*
624 * Mark a callee-save fp register as promoted. Note that
625 * vpush/vpop uses contiguous register lists so we must
626 * include any holes in the mask. Associate holes with
627 * Dalvik register INVALID_VREG (0xFFFFU).
628 */
buzbee091cc402014-03-31 10:14:40 -0700629void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
630 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
631 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700632 // Ensure fp_vmap_table is large enough
633 int table_size = fp_vmap_table_.size();
buzbee091cc402014-03-31 10:14:40 -0700634 for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700635 fp_vmap_table_.push_back(INVALID_VREG);
636 }
637 // Add the current mapping
buzbee091cc402014-03-31 10:14:40 -0700638 fp_vmap_table_[adjusted_reg_num] = v_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700639 // Size of fp_vmap_table is high-water mark, use to set mask
640 num_fp_spills_ = fp_vmap_table_.size();
641 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
642}
643
buzbee091cc402014-03-31 10:14:40 -0700644void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
645 // TEMP: perform as 2 singles.
646 int reg_num = reg.GetRegNum() << 1;
647 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
648 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
649 MarkPreservedSingle(v_reg, lo);
650 MarkPreservedSingle(v_reg + 1, hi);
buzbee2700f7e2014-03-07 09:46:20 -0800651}
652
Brian Carlstrom7940e442013-07-12 13:46:57 -0700653/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000654void ArmMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700655 // TODO: rework this - it's gotten even more ugly.
656 Clobber(rs_r0);
657 Clobber(rs_r1);
658 Clobber(rs_r2);
659 Clobber(rs_r3);
660 Clobber(rs_r12);
661 Clobber(rs_r14lr);
662 Clobber(rs_fr0);
663 Clobber(rs_fr1);
664 Clobber(rs_fr2);
665 Clobber(rs_fr3);
666 Clobber(rs_fr4);
667 Clobber(rs_fr5);
668 Clobber(rs_fr6);
669 Clobber(rs_fr7);
670 Clobber(rs_fr8);
671 Clobber(rs_fr9);
672 Clobber(rs_fr10);
673 Clobber(rs_fr11);
674 Clobber(rs_fr12);
675 Clobber(rs_fr13);
676 Clobber(rs_fr14);
677 Clobber(rs_fr15);
678 Clobber(rs_dr0);
679 Clobber(rs_dr1);
680 Clobber(rs_dr2);
681 Clobber(rs_dr3);
682 Clobber(rs_dr4);
683 Clobber(rs_dr5);
684 Clobber(rs_dr6);
685 Clobber(rs_dr7);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700686}
687
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700688RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700689 RegLocation res = LocCReturnWide();
buzbee091cc402014-03-31 10:14:40 -0700690 res.reg.SetLowReg(rs_r2.GetReg());
691 res.reg.SetHighReg(rs_r3.GetReg());
692 Clobber(rs_r2);
693 Clobber(rs_r3);
694 MarkInUse(rs_r2);
695 MarkInUse(rs_r3);
696 MarkWide(res.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700697 return res;
698}
699
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700700RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700701 RegLocation res = LocCReturn();
buzbee091cc402014-03-31 10:14:40 -0700702 res.reg.SetReg(rs_r1.GetReg());
703 Clobber(rs_r1);
704 MarkInUse(rs_r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700705 return res;
706}
707
Brian Carlstrom7940e442013-07-12 13:46:57 -0700708/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700709void ArmMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700710 LockTemp(rs_r0);
711 LockTemp(rs_r1);
712 LockTemp(rs_r2);
713 LockTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700714}
715
716/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700717void ArmMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700718 FreeTemp(rs_r0);
719 FreeTemp(rs_r1);
720 FreeTemp(rs_r2);
721 FreeTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700722}
723
Ian Rogersdd7624d2014-03-14 17:43:00 -0700724RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
buzbee2700f7e2014-03-07 09:46:20 -0800725 LoadWordDisp(rs_rARM_SELF, offset.Int32Value(), rs_rARM_LR);
726 return rs_rARM_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700727}
728
Andreas Gampe2f244e92014-05-08 03:35:25 -0700729RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<8> offset) {
730 UNIMPLEMENTED(FATAL) << "Should not be called.";
731 return RegStorage::InvalidReg();
732}
733
Dave Allisonb373e092014-02-20 16:06:36 -0800734LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800735 RegStorage tmp = rs_r0;
buzbee695d13a2014-04-19 13:32:20 -0700736 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
737 LIR* load2 = Load32Disp(tmp, 0, tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800738 return load2;
739}
740
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700741uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700742 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700743 return ArmMir2Lir::EncodingMap[opcode].flags;
744}
745
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700746const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700747 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700748 return ArmMir2Lir::EncodingMap[opcode].name;
749}
750
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700751const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700752 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700753 return ArmMir2Lir::EncodingMap[opcode].fmt;
754}
755
buzbee091cc402014-03-31 10:14:40 -0700756/*
757 * Somewhat messy code here. We want to allocate a pair of contiguous
758 * physical single-precision floating point registers starting with
759 * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
760 * has already been allocated - try to fit if possible. Fail to
761 * allocate if we can't meet the requirements for the pair of
762 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
763 */
764// TODO: needs rewrite to support non-backed 64-bit float regs.
765RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
766 RegStorage res;
767 int v_reg = mir_graph_->SRegToVReg(s_reg);
768 int p_map_idx = SRegToPMap(s_reg);
769 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
770 // Upper reg is already allocated. Can we fit?
771 int high_reg = promotion_map_[p_map_idx+1].FpReg;
772 if ((high_reg & 1) == 0) {
773 // High reg is even - fail.
774 return res; // Invalid.
775 }
776 // Is the low reg of the pair free?
777 // FIXME: rework.
778 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
779 if (p->InUse() || p->IsTemp()) {
780 // Already allocated or not preserved - fail.
781 return res; // Invalid.
782 }
783 // OK - good to go.
784 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
785 p->MarkInUse();
786 MarkPreservedSingle(v_reg, p->GetReg());
787 } else {
788 /*
789 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
790 * different underlying physical registers.
791 */
792 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
793 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
794 if (!info->IsTemp() && !info->InUse()) {
795 res = info->GetReg();
796 info->MarkInUse();
797 MarkPreservedDouble(v_reg, info->GetReg());
798 break;
799 }
800 }
801 }
802 if (res.Valid()) {
buzbee85089dd2014-05-25 15:10:52 -0700803 RegisterInfo* info = GetRegInfo(res);
buzbee091cc402014-03-31 10:14:40 -0700804 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
buzbee85089dd2014-05-25 15:10:52 -0700805 promotion_map_[p_map_idx].FpReg =
806 info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700807 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
buzbee85089dd2014-05-25 15:10:52 -0700808 promotion_map_[p_map_idx+1].FpReg =
809 info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700810 }
811 return res;
812}
813
Brian Carlstrom7940e442013-07-12 13:46:57 -0700814} // namespace art