blob: 1520c52a7ac78b6c4d02858640a295d426bb6d2f [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
buzbee091cc402014-03-31 10:14:40 -070028// TODO: rework this when c++11 support allows.
29static const RegStorage core_regs_arr[] =
30 {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};
32static const RegStorage sp_regs_arr[] =
33 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
34 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20,
35 rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30,
36 rs_fr31};
37static const RegStorage dp_regs_arr[] =
38 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10,
39 rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15};
40static const RegStorage reserved_regs_arr[] =
41 {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
42static const RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
43static const RegStorage sp_temps_arr[] =
44 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
45 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
46static const RegStorage dp_temps_arr[] =
47 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
48
buzbeeb01bf152014-05-13 15:59:07 -070049static const std::vector<RegStorage> empty_pool;
buzbee091cc402014-03-31 10:14:40 -070050static const std::vector<RegStorage> core_regs(core_regs_arr,
51 core_regs_arr + sizeof(core_regs_arr) / sizeof(core_regs_arr[0]));
52static const std::vector<RegStorage> sp_regs(sp_regs_arr,
53 sp_regs_arr + sizeof(sp_regs_arr) / sizeof(sp_regs_arr[0]));
54static const std::vector<RegStorage> dp_regs(dp_regs_arr,
55 dp_regs_arr + sizeof(dp_regs_arr) / sizeof(dp_regs_arr[0]));
56static const std::vector<RegStorage> reserved_regs(reserved_regs_arr,
57 reserved_regs_arr + sizeof(reserved_regs_arr) / sizeof(reserved_regs_arr[0]));
58static const std::vector<RegStorage> core_temps(core_temps_arr,
59 core_temps_arr + sizeof(core_temps_arr) / sizeof(core_temps_arr[0]));
60static const std::vector<RegStorage> sp_temps(sp_temps_arr,
61 sp_temps_arr + sizeof(sp_temps_arr) / sizeof(sp_temps_arr[0]));
62static const std::vector<RegStorage> dp_temps(dp_temps_arr,
63 dp_temps_arr + sizeof(dp_temps_arr) / sizeof(dp_temps_arr[0]));
Brian Carlstrom7940e442013-07-12 13:46:57 -070064
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070065RegLocation ArmMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000066 return arm_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070067}
68
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070069RegLocation ArmMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000070 return arm_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070071}
72
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070073RegLocation ArmMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000074 return arm_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070075}
76
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070077RegLocation ArmMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000078 return arm_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070079}
80
81// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080082RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
buzbee091cc402014-03-31 10:14:40 -070083 RegStorage res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -070084 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -070085 case kSelf: res_reg = rs_rARM_SELF; break;
86 case kSuspend: res_reg = rs_rARM_SUSPEND; break;
87 case kLr: res_reg = rs_rARM_LR; break;
88 case kPc: res_reg = rs_rARM_PC; break;
89 case kSp: res_reg = rs_rARM_SP; break;
90 case kArg0: res_reg = rs_r0; break;
91 case kArg1: res_reg = rs_r1; break;
92 case kArg2: res_reg = rs_r2; break;
93 case kArg3: res_reg = rs_r3; break;
94 case kFArg0: res_reg = rs_r0; break;
95 case kFArg1: res_reg = rs_r1; break;
96 case kFArg2: res_reg = rs_r2; break;
97 case kFArg3: res_reg = rs_r3; break;
98 case kRet0: res_reg = rs_r0; break;
99 case kRet1: res_reg = rs_r1; break;
100 case kInvokeTgt: res_reg = rs_rARM_LR; break;
101 case kHiddenArg: res_reg = rs_r12; break;
102 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
103 case kCount: res_reg = RegStorage::InvalidReg(); break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700104 }
buzbee091cc402014-03-31 10:14:40 -0700105 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700106}
107
buzbee2700f7e2014-03-07 09:46:20 -0800108RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800109 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
110 switch (arg_num) {
111 case 0:
buzbee091cc402014-03-31 10:14:40 -0700112 return rs_r1;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800113 case 1:
buzbee091cc402014-03-31 10:14:40 -0700114 return rs_r2;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800115 case 2:
buzbee091cc402014-03-31 10:14:40 -0700116 return rs_r3;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800117 default:
buzbee2700f7e2014-03-07 09:46:20 -0800118 return RegStorage::InvalidReg();
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800119 }
120}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700121
Brian Carlstrom7940e442013-07-12 13:46:57 -0700122/*
123 * Decode the register id.
124 */
buzbee091cc402014-03-31 10:14:40 -0700125uint64_t ArmMir2Lir::GetRegMaskCommon(RegStorage reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700126 uint64_t seed;
127 int shift;
buzbee091cc402014-03-31 10:14:40 -0700128 int reg_id = reg.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700129 /* Each double register is equal to a pair of single-precision FP registers */
buzbee091cc402014-03-31 10:14:40 -0700130 if (reg.IsDouble()) {
131 seed = 0x3;
132 reg_id = reg_id << 1;
133 } else {
134 seed = 1;
135 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700136 /* FP register starts at bit position 16 */
buzbee091cc402014-03-31 10:14:40 -0700137 shift = reg.IsFloat() ? kArmFPReg0 : 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700138 /* Expand the double register id into single offset */
139 shift += reg_id;
140 return (seed << shift);
141}
142
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700143uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700144 return ENCODE_ARM_REG_PC;
145}
146
buzbeeb48819d2013-09-14 16:15:25 -0700147// Thumb2 specific setup. TODO: inline?:
148void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700149 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700150 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700151
Brian Carlstrom7940e442013-07-12 13:46:57 -0700152 int opcode = lir->opcode;
153
buzbeeb48819d2013-09-14 16:15:25 -0700154 // These flags are somewhat uncommon - bypass if we can.
155 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
156 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
157 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
158 if (flags & REG_DEF_SP) {
159 lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700160 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700161
buzbeeb48819d2013-09-14 16:15:25 -0700162 if (flags & REG_USE_SP) {
163 lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700164 }
buzbeeb48819d2013-09-14 16:15:25 -0700165
166 if (flags & REG_DEF_LIST0) {
167 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700168 }
buzbeeb48819d2013-09-14 16:15:25 -0700169
170 if (flags & REG_DEF_LIST1) {
171 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
172 }
173
174 if (flags & REG_DEF_FPCS_LIST0) {
175 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
176 }
177
178 if (flags & REG_DEF_FPCS_LIST2) {
179 for (int i = 0; i < lir->operands[2]; i++) {
180 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
181 }
182 }
183
184 if (flags & REG_USE_PC) {
185 lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
186 }
187
188 /* Conservatively treat the IT block */
189 if (flags & IS_IT) {
190 lir->u.m.def_mask = ENCODE_ALL;
191 }
192
193 if (flags & REG_USE_LIST0) {
194 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
195 }
196
197 if (flags & REG_USE_LIST1) {
198 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
199 }
200
201 if (flags & REG_USE_FPCS_LIST0) {
202 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
203 }
204
205 if (flags & REG_USE_FPCS_LIST2) {
206 for (int i = 0; i < lir->operands[2]; i++) {
207 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
208 }
209 }
210 /* Fixup for kThumbPush/lr and kThumbPop/pc */
211 if (opcode == kThumbPush || opcode == kThumbPop) {
buzbee091cc402014-03-31 10:14:40 -0700212 uint64_t r8Mask = GetRegMaskCommon(rs_r8);
buzbeeb48819d2013-09-14 16:15:25 -0700213 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
214 lir->u.m.use_mask &= ~r8Mask;
215 lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
216 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
217 lir->u.m.def_mask &= ~r8Mask;
218 lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
219 }
220 }
221 if (flags & REG_DEF_LR) {
222 lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
223 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700224 }
225}
226
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700227ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700228 ArmConditionCode res;
229 switch (ccode) {
230 case kCondEq: res = kArmCondEq; break;
231 case kCondNe: res = kArmCondNe; break;
232 case kCondCs: res = kArmCondCs; break;
233 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000234 case kCondUlt: res = kArmCondCc; break;
235 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700236 case kCondMi: res = kArmCondMi; break;
237 case kCondPl: res = kArmCondPl; break;
238 case kCondVs: res = kArmCondVs; break;
239 case kCondVc: res = kArmCondVc; break;
240 case kCondHi: res = kArmCondHi; break;
241 case kCondLs: res = kArmCondLs; break;
242 case kCondGe: res = kArmCondGe; break;
243 case kCondLt: res = kArmCondLt; break;
244 case kCondGt: res = kArmCondGt; break;
245 case kCondLe: res = kArmCondLe; break;
246 case kCondAl: res = kArmCondAl; break;
247 case kCondNv: res = kArmCondNv; break;
248 default:
249 LOG(FATAL) << "Bad condition code " << ccode;
250 res = static_cast<ArmConditionCode>(0); // Quiet gcc
251 }
252 return res;
253}
254
255static const char* core_reg_names[16] = {
256 "r0",
257 "r1",
258 "r2",
259 "r3",
260 "r4",
261 "r5",
262 "r6",
263 "r7",
264 "r8",
265 "rSELF",
266 "r10",
267 "r11",
268 "r12",
269 "sp",
270 "lr",
271 "pc",
272};
273
274
275static const char* shift_names[4] = {
276 "lsl",
277 "lsr",
278 "asr",
279 "ror"};
280
281/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800282static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700283 int i;
284 bool printed = false;
285 buf[0] = 0;
286 for (i = 0; i < 16; i++, vector >>= 1) {
287 if (vector & 0x1) {
288 int reg_id = i;
289 if (opcode == kThumbPush && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700290 reg_id = rs_rARM_LR.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700291 } else if (opcode == kThumbPop && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700292 reg_id = rs_rARM_PC.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700293 }
294 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800295 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700296 } else {
297 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800298 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700299 }
300 }
301 }
302 return buf;
303}
304
Ian Rogers988e6ea2014-01-08 11:30:50 -0800305static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
306 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700307 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800308 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700309 }
310 return buf;
311}
312
buzbee0d829482013-10-11 15:24:55 -0700313static int32_t ExpandImmediate(int value) {
314 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700315 uint32_t bits = value & 0xff;
316 switch (mode) {
317 case 0:
318 return bits;
319 case 1:
320 return (bits << 16) | bits;
321 case 2:
322 return (bits << 24) | (bits << 8);
323 case 3:
324 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
325 default:
326 break;
327 }
328 bits = (bits | 0x80) << 24;
329 return bits >> (((value & 0xf80) >> 7) - 8);
330}
331
Brian Carlstromb1eba212013-07-17 18:07:19 -0700332const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
333 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700334/*
335 * Interpret a format string and build a string no longer than size
336 * See format key in Assemble.c.
337 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700338std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700339 std::string buf;
340 int i;
341 const char* fmt_end = &fmt[strlen(fmt)];
342 char tbuf[256];
343 const char* name;
344 char nc;
345 while (fmt < fmt_end) {
346 int operand;
347 if (*fmt == '!') {
348 fmt++;
349 DCHECK_LT(fmt, fmt_end);
350 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700351 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700352 strcpy(tbuf, "!");
353 } else {
354 DCHECK_LT(fmt, fmt_end);
355 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
356 operand = lir->operands[nc-'0'];
357 switch (*fmt++) {
358 case 'H':
359 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800360 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700361 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700362 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700363 }
364 break;
365 case 'B':
366 switch (operand) {
367 case kSY:
368 name = "sy";
369 break;
370 case kST:
371 name = "st";
372 break;
373 case kISH:
374 name = "ish";
375 break;
376 case kISHST:
377 name = "ishst";
378 break;
379 case kNSH:
380 name = "nsh";
381 break;
382 case kNSHST:
383 name = "shst";
384 break;
385 default:
386 name = "DecodeError2";
387 break;
388 }
389 strcpy(tbuf, name);
390 break;
391 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700392 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700393 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700394 tbuf[i] += operand & 1;
395 operand >>= 1;
396 }
397 break;
398 case 'n':
399 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800400 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700401 break;
402 case 'm':
403 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800404 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700405 break;
406 case 's':
buzbee091cc402014-03-31 10:14:40 -0700407 snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700408 break;
409 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700410 snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700411 break;
412 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800413 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700414 break;
415 case 'M':
416 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800417 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700418 break;
419 case 'C':
buzbee091cc402014-03-31 10:14:40 -0700420 operand = RegStorage::RegNum(operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700421 DCHECK_LT(operand, static_cast<int>(
422 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800423 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700424 break;
425 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800426 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700427 break;
428 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800429 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700430 break;
431 case 'c':
432 strcpy(tbuf, cc_names[operand]);
433 break;
434 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800435 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
436 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700437 lir->target);
438 break;
439 case 'u': {
440 int offset_1 = lir->operands[0];
441 int offset_2 = NEXT_LIR(lir)->operands[0];
442 uintptr_t target =
443 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
444 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
445 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800446 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700447 break;
448 }
449
450 /* Nothing to print for BLX_2 */
451 case 'v':
452 strcpy(tbuf, "see above");
453 break;
454 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800455 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700456 break;
457 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800458 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700459 break;
460 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800461 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700462 break;
463 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700464 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700465 break;
466 }
467 buf += tbuf;
468 }
469 } else {
470 buf += *fmt++;
471 }
472 }
473 return buf;
474}
475
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700476void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700477 char buf[256];
478 buf[0] = 0;
479
480 if (mask == ENCODE_ALL) {
481 strcpy(buf, "all");
482 } else {
483 char num[8];
484 int i;
485
486 for (i = 0; i < kArmRegEnd; i++) {
487 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800488 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700489 strcat(buf, num);
490 }
491 }
492
493 if (mask & ENCODE_CCODE) {
494 strcat(buf, "cc ");
495 }
496 if (mask & ENCODE_FP_STATUS) {
497 strcat(buf, "fpcc ");
498 }
499
500 /* Memory bits */
501 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800502 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
503 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
504 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700505 }
506 if (mask & ENCODE_LITERAL) {
507 strcat(buf, "lit ");
508 }
509
510 if (mask & ENCODE_HEAP_REF) {
511 strcat(buf, "heap ");
512 }
513 if (mask & ENCODE_MUST_NOT_ALIAS) {
514 strcat(buf, "noalias ");
515 }
516 }
517 if (buf[0]) {
518 LOG(INFO) << prefix << ": " << buf;
519 }
520}
521
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700522bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700523 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
524}
525
Vladimir Marko674744e2014-04-24 15:18:26 +0100526bool ArmMir2Lir::SupportsVolatileLoadStore(OpSize size) {
527 return true;
528}
529
530RegisterClass ArmMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
531 if (UNLIKELY(is_volatile)) {
532 // On arm, atomic 64-bit load/store requires a core register pair.
533 // Smaller aligned load/store is atomic for both core and fp registers.
534 if (size == k64 || size == kDouble) {
535 return kCoreReg;
536 }
537 }
538 return RegClassBySize(size);
539}
540
Brian Carlstrom7940e442013-07-12 13:46:57 -0700541ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
542 : Mir2Lir(cu, mir_graph, arena) {
543 // Sanity check - make sure encoding map lines up.
544 for (int i = 0; i < kArmLast; i++) {
545 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
546 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
547 << " is wrong: expecting " << i << ", seeing "
548 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
549 }
550 }
551}
552
553Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
554 ArenaAllocator* const arena) {
555 return new ArmMir2Lir(cu, mir_graph, arena);
556}
557
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700558void ArmMir2Lir::CompilerInitializeRegAlloc() {
buzbeeb01bf152014-05-13 15:59:07 -0700559 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs,
560 dp_regs, reserved_regs, empty_pool /* reserved64 */,
561 core_temps, empty_pool /* core64_temps */, sp_temps,
562 dp_temps);
Dave Allisonf6b65c12014-04-01 17:45:18 -0700563
buzbee091cc402014-03-31 10:14:40 -0700564 // Target-specific adjustments.
565
566 // Alias single precision floats to appropriate half of overlapping double.
567 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
568 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
569 int sp_reg_num = info->GetReg().GetRegNum();
570 int dp_reg_num = sp_reg_num >> 1;
571 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
572 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
573 // Double precision register's master storage should refer to itself.
574 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
575 // Redirect single precision's master storage to master.
576 info->SetMaster(dp_reg_info);
577 // Singles should show a single 32-bit mask bit, at first referring to the low half.
578 DCHECK_EQ(info->StorageMask(), 0x1U);
579 if (sp_reg_num & 1) {
580 // For odd singles, change to user the high word of the backing double.
581 info->SetStorageMask(0x2);
582 }
583 }
584
Dave Allison83252962014-04-03 16:33:48 -0700585 // TODO: re-enable this when we can safely save r4 over the suspension code path.
586 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
buzbee091cc402014-03-31 10:14:40 -0700587 if (no_suspend) {
588 GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700589 }
590
buzbee091cc402014-03-31 10:14:40 -0700591 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
592 // TODO: adjust when we roll to hard float calling convention.
593 reg_pool_->next_core_reg_ = 2;
594 reg_pool_->next_sp_reg_ = 0;
595 reg_pool_->next_dp_reg_ = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700596}
597
Brian Carlstrom7940e442013-07-12 13:46:57 -0700598/*
599 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
600 * instructions might call out to C/assembly helper functions. Until
601 * machinery is in place, always spill lr.
602 */
603
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700604void ArmMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700605 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700606 num_core_spills_++;
607}
608
609/*
610 * Mark a callee-save fp register as promoted. Note that
611 * vpush/vpop uses contiguous register lists so we must
612 * include any holes in the mask. Associate holes with
613 * Dalvik register INVALID_VREG (0xFFFFU).
614 */
buzbee091cc402014-03-31 10:14:40 -0700615void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
616 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
617 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700618 // Ensure fp_vmap_table is large enough
619 int table_size = fp_vmap_table_.size();
buzbee091cc402014-03-31 10:14:40 -0700620 for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700621 fp_vmap_table_.push_back(INVALID_VREG);
622 }
623 // Add the current mapping
buzbee091cc402014-03-31 10:14:40 -0700624 fp_vmap_table_[adjusted_reg_num] = v_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700625 // Size of fp_vmap_table is high-water mark, use to set mask
626 num_fp_spills_ = fp_vmap_table_.size();
627 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
628}
629
buzbee091cc402014-03-31 10:14:40 -0700630void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
631 // TEMP: perform as 2 singles.
632 int reg_num = reg.GetRegNum() << 1;
633 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
634 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
635 MarkPreservedSingle(v_reg, lo);
636 MarkPreservedSingle(v_reg + 1, hi);
buzbee2700f7e2014-03-07 09:46:20 -0800637}
638
Brian Carlstrom7940e442013-07-12 13:46:57 -0700639/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000640void ArmMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700641 // TODO: rework this - it's gotten even more ugly.
642 Clobber(rs_r0);
643 Clobber(rs_r1);
644 Clobber(rs_r2);
645 Clobber(rs_r3);
646 Clobber(rs_r12);
647 Clobber(rs_r14lr);
648 Clobber(rs_fr0);
649 Clobber(rs_fr1);
650 Clobber(rs_fr2);
651 Clobber(rs_fr3);
652 Clobber(rs_fr4);
653 Clobber(rs_fr5);
654 Clobber(rs_fr6);
655 Clobber(rs_fr7);
656 Clobber(rs_fr8);
657 Clobber(rs_fr9);
658 Clobber(rs_fr10);
659 Clobber(rs_fr11);
660 Clobber(rs_fr12);
661 Clobber(rs_fr13);
662 Clobber(rs_fr14);
663 Clobber(rs_fr15);
664 Clobber(rs_dr0);
665 Clobber(rs_dr1);
666 Clobber(rs_dr2);
667 Clobber(rs_dr3);
668 Clobber(rs_dr4);
669 Clobber(rs_dr5);
670 Clobber(rs_dr6);
671 Clobber(rs_dr7);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700672}
673
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700674RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700675 RegLocation res = LocCReturnWide();
buzbee091cc402014-03-31 10:14:40 -0700676 res.reg.SetLowReg(rs_r2.GetReg());
677 res.reg.SetHighReg(rs_r3.GetReg());
678 Clobber(rs_r2);
679 Clobber(rs_r3);
680 MarkInUse(rs_r2);
681 MarkInUse(rs_r3);
682 MarkWide(res.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700683 return res;
684}
685
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700686RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700687 RegLocation res = LocCReturn();
buzbee091cc402014-03-31 10:14:40 -0700688 res.reg.SetReg(rs_r1.GetReg());
689 Clobber(rs_r1);
690 MarkInUse(rs_r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700691 return res;
692}
693
Brian Carlstrom7940e442013-07-12 13:46:57 -0700694/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700695void ArmMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700696 LockTemp(rs_r0);
697 LockTemp(rs_r1);
698 LockTemp(rs_r2);
699 LockTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700700}
701
702/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700703void ArmMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700704 FreeTemp(rs_r0);
705 FreeTemp(rs_r1);
706 FreeTemp(rs_r2);
707 FreeTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700708}
709
Ian Rogersdd7624d2014-03-14 17:43:00 -0700710RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
buzbee2700f7e2014-03-07 09:46:20 -0800711 LoadWordDisp(rs_rARM_SELF, offset.Int32Value(), rs_rARM_LR);
712 return rs_rARM_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700713}
714
Andreas Gampe2f244e92014-05-08 03:35:25 -0700715RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<8> offset) {
716 UNIMPLEMENTED(FATAL) << "Should not be called.";
717 return RegStorage::InvalidReg();
718}
719
Dave Allisonb373e092014-02-20 16:06:36 -0800720LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800721 RegStorage tmp = rs_r0;
buzbee695d13a2014-04-19 13:32:20 -0700722 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
723 LIR* load2 = Load32Disp(tmp, 0, tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800724 return load2;
725}
726
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700727uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700728 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700729 return ArmMir2Lir::EncodingMap[opcode].flags;
730}
731
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700732const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700733 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700734 return ArmMir2Lir::EncodingMap[opcode].name;
735}
736
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700737const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700738 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700739 return ArmMir2Lir::EncodingMap[opcode].fmt;
740}
741
buzbee091cc402014-03-31 10:14:40 -0700742/*
743 * Somewhat messy code here. We want to allocate a pair of contiguous
744 * physical single-precision floating point registers starting with
745 * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
746 * has already been allocated - try to fit if possible. Fail to
747 * allocate if we can't meet the requirements for the pair of
748 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
749 */
750// TODO: needs rewrite to support non-backed 64-bit float regs.
751RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
752 RegStorage res;
753 int v_reg = mir_graph_->SRegToVReg(s_reg);
754 int p_map_idx = SRegToPMap(s_reg);
755 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
756 // Upper reg is already allocated. Can we fit?
757 int high_reg = promotion_map_[p_map_idx+1].FpReg;
758 if ((high_reg & 1) == 0) {
759 // High reg is even - fail.
760 return res; // Invalid.
761 }
762 // Is the low reg of the pair free?
763 // FIXME: rework.
764 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
765 if (p->InUse() || p->IsTemp()) {
766 // Already allocated or not preserved - fail.
767 return res; // Invalid.
768 }
769 // OK - good to go.
770 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
771 p->MarkInUse();
772 MarkPreservedSingle(v_reg, p->GetReg());
773 } else {
774 /*
775 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
776 * different underlying physical registers.
777 */
778 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
779 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
780 if (!info->IsTemp() && !info->InUse()) {
781 res = info->GetReg();
782 info->MarkInUse();
783 MarkPreservedDouble(v_reg, info->GetReg());
784 break;
785 }
786 }
787 }
788 if (res.Valid()) {
789 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
790 promotion_map_[p_map_idx].FpReg = res.DoubleToLowSingle().GetReg();
791 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
792 promotion_map_[p_map_idx+1].FpReg = res.DoubleToHighSingle().GetReg();
793 }
794 return res;
795}
796
Brian Carlstrom7940e442013-07-12 13:46:57 -0700797} // namespace art