blob: f59720bec978e5bb5706ff8b98936cba0a123734 [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
49static const std::vector<RegStorage> core_regs(core_regs_arr,
50 core_regs_arr + sizeof(core_regs_arr) / sizeof(core_regs_arr[0]));
51static const std::vector<RegStorage> sp_regs(sp_regs_arr,
52 sp_regs_arr + sizeof(sp_regs_arr) / sizeof(sp_regs_arr[0]));
53static const std::vector<RegStorage> dp_regs(dp_regs_arr,
54 dp_regs_arr + sizeof(dp_regs_arr) / sizeof(dp_regs_arr[0]));
55static const std::vector<RegStorage> reserved_regs(reserved_regs_arr,
56 reserved_regs_arr + sizeof(reserved_regs_arr) / sizeof(reserved_regs_arr[0]));
57static const std::vector<RegStorage> core_temps(core_temps_arr,
58 core_temps_arr + sizeof(core_temps_arr) / sizeof(core_temps_arr[0]));
59static const std::vector<RegStorage> sp_temps(sp_temps_arr,
60 sp_temps_arr + sizeof(sp_temps_arr) / sizeof(sp_temps_arr[0]));
61static const std::vector<RegStorage> dp_temps(dp_temps_arr,
62 dp_temps_arr + sizeof(dp_temps_arr) / sizeof(dp_temps_arr[0]));
Brian Carlstrom7940e442013-07-12 13:46:57 -070063
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070064RegLocation ArmMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000065 return arm_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070066}
67
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070068RegLocation ArmMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000069 return arm_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070070}
71
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070072RegLocation ArmMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000073 return arm_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070074}
75
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070076RegLocation ArmMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000077 return arm_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070078}
79
80// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080081RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
buzbee091cc402014-03-31 10:14:40 -070082 RegStorage res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -070083 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -070084 case kSelf: res_reg = rs_rARM_SELF; break;
85 case kSuspend: res_reg = rs_rARM_SUSPEND; break;
86 case kLr: res_reg = rs_rARM_LR; break;
87 case kPc: res_reg = rs_rARM_PC; break;
88 case kSp: res_reg = rs_rARM_SP; break;
89 case kArg0: res_reg = rs_r0; break;
90 case kArg1: res_reg = rs_r1; break;
91 case kArg2: res_reg = rs_r2; break;
92 case kArg3: res_reg = rs_r3; break;
93 case kFArg0: res_reg = rs_r0; break;
94 case kFArg1: res_reg = rs_r1; break;
95 case kFArg2: res_reg = rs_r2; break;
96 case kFArg3: res_reg = rs_r3; break;
97 case kRet0: res_reg = rs_r0; break;
98 case kRet1: res_reg = rs_r1; break;
99 case kInvokeTgt: res_reg = rs_rARM_LR; break;
100 case kHiddenArg: res_reg = rs_r12; break;
101 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
102 case kCount: res_reg = RegStorage::InvalidReg(); break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700103 }
buzbee091cc402014-03-31 10:14:40 -0700104 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700105}
106
buzbee2700f7e2014-03-07 09:46:20 -0800107RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800108 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
109 switch (arg_num) {
110 case 0:
buzbee091cc402014-03-31 10:14:40 -0700111 return rs_r1;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800112 case 1:
buzbee091cc402014-03-31 10:14:40 -0700113 return rs_r2;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800114 case 2:
buzbee091cc402014-03-31 10:14:40 -0700115 return rs_r3;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800116 default:
buzbee2700f7e2014-03-07 09:46:20 -0800117 return RegStorage::InvalidReg();
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800118 }
119}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700120
Brian Carlstrom7940e442013-07-12 13:46:57 -0700121/*
122 * Decode the register id.
123 */
buzbee091cc402014-03-31 10:14:40 -0700124uint64_t ArmMir2Lir::GetRegMaskCommon(RegStorage reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700125 uint64_t seed;
126 int shift;
buzbee091cc402014-03-31 10:14:40 -0700127 int reg_id = reg.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700128 /* Each double register is equal to a pair of single-precision FP registers */
buzbee091cc402014-03-31 10:14:40 -0700129 if (reg.IsDouble()) {
130 seed = 0x3;
131 reg_id = reg_id << 1;
132 } else {
133 seed = 1;
134 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135 /* FP register starts at bit position 16 */
buzbee091cc402014-03-31 10:14:40 -0700136 shift = reg.IsFloat() ? kArmFPReg0 : 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700137 /* Expand the double register id into single offset */
138 shift += reg_id;
139 return (seed << shift);
140}
141
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700142uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700143 return ENCODE_ARM_REG_PC;
144}
145
buzbeeb48819d2013-09-14 16:15:25 -0700146// Thumb2 specific setup. TODO: inline?:
147void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700148 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700149 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700150
Brian Carlstrom7940e442013-07-12 13:46:57 -0700151 int opcode = lir->opcode;
152
buzbeeb48819d2013-09-14 16:15:25 -0700153 // These flags are somewhat uncommon - bypass if we can.
154 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
155 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
156 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
157 if (flags & REG_DEF_SP) {
158 lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700159 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700160
buzbeeb48819d2013-09-14 16:15:25 -0700161 if (flags & REG_USE_SP) {
162 lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700163 }
buzbeeb48819d2013-09-14 16:15:25 -0700164
165 if (flags & REG_DEF_LIST0) {
166 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700167 }
buzbeeb48819d2013-09-14 16:15:25 -0700168
169 if (flags & REG_DEF_LIST1) {
170 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
171 }
172
173 if (flags & REG_DEF_FPCS_LIST0) {
174 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
175 }
176
177 if (flags & REG_DEF_FPCS_LIST2) {
178 for (int i = 0; i < lir->operands[2]; i++) {
179 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
180 }
181 }
182
183 if (flags & REG_USE_PC) {
184 lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
185 }
186
187 /* Conservatively treat the IT block */
188 if (flags & IS_IT) {
189 lir->u.m.def_mask = ENCODE_ALL;
190 }
191
192 if (flags & REG_USE_LIST0) {
193 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
194 }
195
196 if (flags & REG_USE_LIST1) {
197 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
198 }
199
200 if (flags & REG_USE_FPCS_LIST0) {
201 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
202 }
203
204 if (flags & REG_USE_FPCS_LIST2) {
205 for (int i = 0; i < lir->operands[2]; i++) {
206 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
207 }
208 }
209 /* Fixup for kThumbPush/lr and kThumbPop/pc */
210 if (opcode == kThumbPush || opcode == kThumbPop) {
buzbee091cc402014-03-31 10:14:40 -0700211 uint64_t r8Mask = GetRegMaskCommon(rs_r8);
buzbeeb48819d2013-09-14 16:15:25 -0700212 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
213 lir->u.m.use_mask &= ~r8Mask;
214 lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
215 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
216 lir->u.m.def_mask &= ~r8Mask;
217 lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
218 }
219 }
220 if (flags & REG_DEF_LR) {
221 lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
222 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700223 }
224}
225
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700226ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700227 ArmConditionCode res;
228 switch (ccode) {
229 case kCondEq: res = kArmCondEq; break;
230 case kCondNe: res = kArmCondNe; break;
231 case kCondCs: res = kArmCondCs; break;
232 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000233 case kCondUlt: res = kArmCondCc; break;
234 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700235 case kCondMi: res = kArmCondMi; break;
236 case kCondPl: res = kArmCondPl; break;
237 case kCondVs: res = kArmCondVs; break;
238 case kCondVc: res = kArmCondVc; break;
239 case kCondHi: res = kArmCondHi; break;
240 case kCondLs: res = kArmCondLs; break;
241 case kCondGe: res = kArmCondGe; break;
242 case kCondLt: res = kArmCondLt; break;
243 case kCondGt: res = kArmCondGt; break;
244 case kCondLe: res = kArmCondLe; break;
245 case kCondAl: res = kArmCondAl; break;
246 case kCondNv: res = kArmCondNv; break;
247 default:
248 LOG(FATAL) << "Bad condition code " << ccode;
249 res = static_cast<ArmConditionCode>(0); // Quiet gcc
250 }
251 return res;
252}
253
254static const char* core_reg_names[16] = {
255 "r0",
256 "r1",
257 "r2",
258 "r3",
259 "r4",
260 "r5",
261 "r6",
262 "r7",
263 "r8",
264 "rSELF",
265 "r10",
266 "r11",
267 "r12",
268 "sp",
269 "lr",
270 "pc",
271};
272
273
274static const char* shift_names[4] = {
275 "lsl",
276 "lsr",
277 "asr",
278 "ror"};
279
280/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800281static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700282 int i;
283 bool printed = false;
284 buf[0] = 0;
285 for (i = 0; i < 16; i++, vector >>= 1) {
286 if (vector & 0x1) {
287 int reg_id = i;
288 if (opcode == kThumbPush && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700289 reg_id = rs_rARM_LR.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700290 } else if (opcode == kThumbPop && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700291 reg_id = rs_rARM_PC.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700292 }
293 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800294 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700295 } else {
296 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800297 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700298 }
299 }
300 }
301 return buf;
302}
303
Ian Rogers988e6ea2014-01-08 11:30:50 -0800304static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
305 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700306 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800307 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700308 }
309 return buf;
310}
311
buzbee0d829482013-10-11 15:24:55 -0700312static int32_t ExpandImmediate(int value) {
313 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700314 uint32_t bits = value & 0xff;
315 switch (mode) {
316 case 0:
317 return bits;
318 case 1:
319 return (bits << 16) | bits;
320 case 2:
321 return (bits << 24) | (bits << 8);
322 case 3:
323 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
324 default:
325 break;
326 }
327 bits = (bits | 0x80) << 24;
328 return bits >> (((value & 0xf80) >> 7) - 8);
329}
330
Brian Carlstromb1eba212013-07-17 18:07:19 -0700331const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
332 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700333/*
334 * Interpret a format string and build a string no longer than size
335 * See format key in Assemble.c.
336 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700337std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700338 std::string buf;
339 int i;
340 const char* fmt_end = &fmt[strlen(fmt)];
341 char tbuf[256];
342 const char* name;
343 char nc;
344 while (fmt < fmt_end) {
345 int operand;
346 if (*fmt == '!') {
347 fmt++;
348 DCHECK_LT(fmt, fmt_end);
349 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700350 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700351 strcpy(tbuf, "!");
352 } else {
353 DCHECK_LT(fmt, fmt_end);
354 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
355 operand = lir->operands[nc-'0'];
356 switch (*fmt++) {
357 case 'H':
358 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800359 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700360 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700361 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700362 }
363 break;
364 case 'B':
365 switch (operand) {
366 case kSY:
367 name = "sy";
368 break;
369 case kST:
370 name = "st";
371 break;
372 case kISH:
373 name = "ish";
374 break;
375 case kISHST:
376 name = "ishst";
377 break;
378 case kNSH:
379 name = "nsh";
380 break;
381 case kNSHST:
382 name = "shst";
383 break;
384 default:
385 name = "DecodeError2";
386 break;
387 }
388 strcpy(tbuf, name);
389 break;
390 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700391 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700392 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700393 tbuf[i] += operand & 1;
394 operand >>= 1;
395 }
396 break;
397 case 'n':
398 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800399 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700400 break;
401 case 'm':
402 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800403 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700404 break;
405 case 's':
buzbee091cc402014-03-31 10:14:40 -0700406 snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700407 break;
408 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700409 snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700410 break;
411 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800412 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700413 break;
414 case 'M':
415 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800416 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700417 break;
418 case 'C':
buzbee091cc402014-03-31 10:14:40 -0700419 operand = RegStorage::RegNum(operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700420 DCHECK_LT(operand, static_cast<int>(
421 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800422 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700423 break;
424 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800425 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700426 break;
427 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800428 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700429 break;
430 case 'c':
431 strcpy(tbuf, cc_names[operand]);
432 break;
433 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800434 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
435 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700436 lir->target);
437 break;
438 case 'u': {
439 int offset_1 = lir->operands[0];
440 int offset_2 = NEXT_LIR(lir)->operands[0];
441 uintptr_t target =
442 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
443 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
444 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800445 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700446 break;
447 }
448
449 /* Nothing to print for BLX_2 */
450 case 'v':
451 strcpy(tbuf, "see above");
452 break;
453 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800454 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700455 break;
456 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800457 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700458 break;
459 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800460 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700461 break;
462 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700463 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700464 break;
465 }
466 buf += tbuf;
467 }
468 } else {
469 buf += *fmt++;
470 }
471 }
472 return buf;
473}
474
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700475void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700476 char buf[256];
477 buf[0] = 0;
478
479 if (mask == ENCODE_ALL) {
480 strcpy(buf, "all");
481 } else {
482 char num[8];
483 int i;
484
485 for (i = 0; i < kArmRegEnd; i++) {
486 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800487 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700488 strcat(buf, num);
489 }
490 }
491
492 if (mask & ENCODE_CCODE) {
493 strcat(buf, "cc ");
494 }
495 if (mask & ENCODE_FP_STATUS) {
496 strcat(buf, "fpcc ");
497 }
498
499 /* Memory bits */
500 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800501 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
502 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
503 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700504 }
505 if (mask & ENCODE_LITERAL) {
506 strcat(buf, "lit ");
507 }
508
509 if (mask & ENCODE_HEAP_REF) {
510 strcat(buf, "heap ");
511 }
512 if (mask & ENCODE_MUST_NOT_ALIAS) {
513 strcat(buf, "noalias ");
514 }
515 }
516 if (buf[0]) {
517 LOG(INFO) << prefix << ": " << buf;
518 }
519}
520
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700521bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700522 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
523}
524
525ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
526 : Mir2Lir(cu, mir_graph, arena) {
527 // Sanity check - make sure encoding map lines up.
528 for (int i = 0; i < kArmLast; i++) {
529 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
530 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
531 << " is wrong: expecting " << i << ", seeing "
532 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
533 }
534 }
535}
536
537Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
538 ArenaAllocator* const arena) {
539 return new ArmMir2Lir(cu, mir_graph, arena);
540}
541
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000542// Alloc a pair of core registers, or a double.
543RegStorage ArmMir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700544 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
buzbee2700f7e2014-03-07 09:46:20 -0800545 return AllocTempDouble();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700546 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800547 RegStorage low_reg = AllocTemp();
548 RegStorage high_reg = AllocTemp();
549 return RegStorage::MakeRegPair(low_reg, high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700550 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700551}
552
buzbee2700f7e2014-03-07 09:46:20 -0800553RegStorage ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700554 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
buzbee091cc402014-03-31 10:14:40 -0700555 return AllocTempSingle();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700556 return AllocTemp();
557}
558
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700559void ArmMir2Lir::CompilerInitializeRegAlloc() {
buzbee091cc402014-03-31 10:14:40 -0700560 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, sp_regs, dp_regs, reserved_regs,
561 core_temps, sp_temps, dp_temps);
Dave Allisonf6b65c12014-04-01 17:45:18 -0700562
buzbee091cc402014-03-31 10:14:40 -0700563 // Target-specific adjustments.
564
565 // Alias single precision floats to appropriate half of overlapping double.
566 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
567 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
568 int sp_reg_num = info->GetReg().GetRegNum();
569 int dp_reg_num = sp_reg_num >> 1;
570 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
571 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
572 // Double precision register's master storage should refer to itself.
573 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
574 // Redirect single precision's master storage to master.
575 info->SetMaster(dp_reg_info);
576 // Singles should show a single 32-bit mask bit, at first referring to the low half.
577 DCHECK_EQ(info->StorageMask(), 0x1U);
578 if (sp_reg_num & 1) {
579 // For odd singles, change to user the high word of the backing double.
580 info->SetStorageMask(0x2);
581 }
582 }
583
Dave Allison83252962014-04-03 16:33:48 -0700584 // TODO: re-enable this when we can safely save r4 over the suspension code path.
585 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
buzbee091cc402014-03-31 10:14:40 -0700586 if (no_suspend) {
587 GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700588 }
589
buzbee091cc402014-03-31 10:14:40 -0700590 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
591 // TODO: adjust when we roll to hard float calling convention.
592 reg_pool_->next_core_reg_ = 2;
593 reg_pool_->next_sp_reg_ = 0;
594 reg_pool_->next_dp_reg_ = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700595}
596
buzbee2700f7e2014-03-07 09:46:20 -0800597void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
598 DCHECK(rl_keep.wide);
599 DCHECK(rl_free.wide);
600 if ((rl_free.reg.GetLowReg() != rl_keep.reg.GetLowReg()) &&
601 (rl_free.reg.GetLowReg() != rl_keep.reg.GetHighReg()) &&
602 (rl_free.reg.GetHighReg() != rl_keep.reg.GetLowReg()) &&
603 (rl_free.reg.GetHighReg() != rl_keep.reg.GetHighReg())) {
604 // No overlap, free.
605 FreeTemp(rl_free.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700606 }
607}
buzbee2700f7e2014-03-07 09:46:20 -0800608
Brian Carlstrom7940e442013-07-12 13:46:57 -0700609/*
610 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
611 * instructions might call out to C/assembly helper functions. Until
612 * machinery is in place, always spill lr.
613 */
614
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700615void ArmMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700616 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700617 num_core_spills_++;
618}
619
620/*
621 * Mark a callee-save fp register as promoted. Note that
622 * vpush/vpop uses contiguous register lists so we must
623 * include any holes in the mask. Associate holes with
624 * Dalvik register INVALID_VREG (0xFFFFU).
625 */
buzbee091cc402014-03-31 10:14:40 -0700626void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
627 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
628 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700629 // Ensure fp_vmap_table is large enough
630 int table_size = fp_vmap_table_.size();
buzbee091cc402014-03-31 10:14:40 -0700631 for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700632 fp_vmap_table_.push_back(INVALID_VREG);
633 }
634 // Add the current mapping
buzbee091cc402014-03-31 10:14:40 -0700635 fp_vmap_table_[adjusted_reg_num] = v_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700636 // Size of fp_vmap_table is high-water mark, use to set mask
637 num_fp_spills_ = fp_vmap_table_.size();
638 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
639}
640
buzbee091cc402014-03-31 10:14:40 -0700641void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
642 // TEMP: perform as 2 singles.
643 int reg_num = reg.GetRegNum() << 1;
644 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
645 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
646 MarkPreservedSingle(v_reg, lo);
647 MarkPreservedSingle(v_reg + 1, hi);
buzbee2700f7e2014-03-07 09:46:20 -0800648}
649
Brian Carlstrom7940e442013-07-12 13:46:57 -0700650/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000651void ArmMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700652 // TODO: rework this - it's gotten even more ugly.
653 Clobber(rs_r0);
654 Clobber(rs_r1);
655 Clobber(rs_r2);
656 Clobber(rs_r3);
657 Clobber(rs_r12);
658 Clobber(rs_r14lr);
659 Clobber(rs_fr0);
660 Clobber(rs_fr1);
661 Clobber(rs_fr2);
662 Clobber(rs_fr3);
663 Clobber(rs_fr4);
664 Clobber(rs_fr5);
665 Clobber(rs_fr6);
666 Clobber(rs_fr7);
667 Clobber(rs_fr8);
668 Clobber(rs_fr9);
669 Clobber(rs_fr10);
670 Clobber(rs_fr11);
671 Clobber(rs_fr12);
672 Clobber(rs_fr13);
673 Clobber(rs_fr14);
674 Clobber(rs_fr15);
675 Clobber(rs_dr0);
676 Clobber(rs_dr1);
677 Clobber(rs_dr2);
678 Clobber(rs_dr3);
679 Clobber(rs_dr4);
680 Clobber(rs_dr5);
681 Clobber(rs_dr6);
682 Clobber(rs_dr7);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700683}
684
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700685RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700686 RegLocation res = LocCReturnWide();
buzbee091cc402014-03-31 10:14:40 -0700687 res.reg.SetLowReg(rs_r2.GetReg());
688 res.reg.SetHighReg(rs_r3.GetReg());
689 Clobber(rs_r2);
690 Clobber(rs_r3);
691 MarkInUse(rs_r2);
692 MarkInUse(rs_r3);
693 MarkWide(res.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700694 return res;
695}
696
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700697RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700698 RegLocation res = LocCReturn();
buzbee091cc402014-03-31 10:14:40 -0700699 res.reg.SetReg(rs_r1.GetReg());
700 Clobber(rs_r1);
701 MarkInUse(rs_r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700702 return res;
703}
704
Brian Carlstrom7940e442013-07-12 13:46:57 -0700705/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700706void ArmMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700707 LockTemp(rs_r0);
708 LockTemp(rs_r1);
709 LockTemp(rs_r2);
710 LockTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700711}
712
713/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700714void ArmMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700715 FreeTemp(rs_r0);
716 FreeTemp(rs_r1);
717 FreeTemp(rs_r2);
718 FreeTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700719}
720
Ian Rogersdd7624d2014-03-14 17:43:00 -0700721RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
buzbee2700f7e2014-03-07 09:46:20 -0800722 LoadWordDisp(rs_rARM_SELF, offset.Int32Value(), rs_rARM_LR);
723 return rs_rARM_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700724}
725
Dave Allisonb373e092014-02-20 16:06:36 -0800726LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800727 RegStorage tmp = rs_r0;
buzbee695d13a2014-04-19 13:32:20 -0700728 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
729 LIR* load2 = Load32Disp(tmp, 0, tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800730 return load2;
731}
732
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700733uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700734 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700735 return ArmMir2Lir::EncodingMap[opcode].flags;
736}
737
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700738const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700739 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700740 return ArmMir2Lir::EncodingMap[opcode].name;
741}
742
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700743const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700744 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700745 return ArmMir2Lir::EncodingMap[opcode].fmt;
746}
747
buzbee091cc402014-03-31 10:14:40 -0700748/*
749 * Somewhat messy code here. We want to allocate a pair of contiguous
750 * physical single-precision floating point registers starting with
751 * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
752 * has already been allocated - try to fit if possible. Fail to
753 * allocate if we can't meet the requirements for the pair of
754 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
755 */
756// TODO: needs rewrite to support non-backed 64-bit float regs.
757RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
758 RegStorage res;
759 int v_reg = mir_graph_->SRegToVReg(s_reg);
760 int p_map_idx = SRegToPMap(s_reg);
761 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
762 // Upper reg is already allocated. Can we fit?
763 int high_reg = promotion_map_[p_map_idx+1].FpReg;
764 if ((high_reg & 1) == 0) {
765 // High reg is even - fail.
766 return res; // Invalid.
767 }
768 // Is the low reg of the pair free?
769 // FIXME: rework.
770 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
771 if (p->InUse() || p->IsTemp()) {
772 // Already allocated or not preserved - fail.
773 return res; // Invalid.
774 }
775 // OK - good to go.
776 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
777 p->MarkInUse();
778 MarkPreservedSingle(v_reg, p->GetReg());
779 } else {
780 /*
781 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
782 * different underlying physical registers.
783 */
784 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
785 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
786 if (!info->IsTemp() && !info->InUse()) {
787 res = info->GetReg();
788 info->MarkInUse();
789 MarkPreservedDouble(v_reg, info->GetReg());
790 break;
791 }
792 }
793 }
794 if (res.Valid()) {
795 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
796 promotion_map_[p_map_idx].FpReg = res.DoubleToLowSingle().GetReg();
797 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
798 promotion_map_[p_map_idx+1].FpReg = res.DoubleToHighSingle().GetReg();
799 }
800 return res;
801}
802
Brian Carlstrom7940e442013-07-12 13:46:57 -0700803} // namespace art