blob: f7a7fe89f990de1a39e72646370732460ee3f6f8 [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
Vladimir Marko674744e2014-04-24 15:18:26 +0100525bool ArmMir2Lir::SupportsVolatileLoadStore(OpSize size) {
526 return true;
527}
528
529RegisterClass ArmMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
530 if (UNLIKELY(is_volatile)) {
531 // On arm, atomic 64-bit load/store requires a core register pair.
532 // Smaller aligned load/store is atomic for both core and fp registers.
533 if (size == k64 || size == kDouble) {
534 return kCoreReg;
535 }
536 }
537 return RegClassBySize(size);
538}
539
Brian Carlstrom7940e442013-07-12 13:46:57 -0700540ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
541 : Mir2Lir(cu, mir_graph, arena) {
542 // Sanity check - make sure encoding map lines up.
543 for (int i = 0; i < kArmLast; i++) {
544 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
545 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
546 << " is wrong: expecting " << i << ", seeing "
547 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
548 }
549 }
550}
551
552Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
553 ArenaAllocator* const arena) {
554 return new ArmMir2Lir(cu, mir_graph, arena);
555}
556
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000557// Alloc a pair of core registers, or a double.
558RegStorage ArmMir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700559 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
buzbee2700f7e2014-03-07 09:46:20 -0800560 return AllocTempDouble();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700561 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800562 RegStorage low_reg = AllocTemp();
563 RegStorage high_reg = AllocTemp();
564 return RegStorage::MakeRegPair(low_reg, high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700565 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700566}
567
buzbee2700f7e2014-03-07 09:46:20 -0800568RegStorage ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700569 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
buzbee091cc402014-03-31 10:14:40 -0700570 return AllocTempSingle();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700571 return AllocTemp();
572}
573
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700574void ArmMir2Lir::CompilerInitializeRegAlloc() {
buzbee091cc402014-03-31 10:14:40 -0700575 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, sp_regs, dp_regs, reserved_regs,
576 core_temps, sp_temps, dp_temps);
Dave Allisonf6b65c12014-04-01 17:45:18 -0700577
buzbee091cc402014-03-31 10:14:40 -0700578 // Target-specific adjustments.
579
580 // Alias single precision floats to appropriate half of overlapping double.
581 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
582 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
583 int sp_reg_num = info->GetReg().GetRegNum();
584 int dp_reg_num = sp_reg_num >> 1;
585 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
586 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
587 // Double precision register's master storage should refer to itself.
588 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
589 // Redirect single precision's master storage to master.
590 info->SetMaster(dp_reg_info);
591 // Singles should show a single 32-bit mask bit, at first referring to the low half.
592 DCHECK_EQ(info->StorageMask(), 0x1U);
593 if (sp_reg_num & 1) {
594 // For odd singles, change to user the high word of the backing double.
595 info->SetStorageMask(0x2);
596 }
597 }
598
Dave Allison83252962014-04-03 16:33:48 -0700599 // TODO: re-enable this when we can safely save r4 over the suspension code path.
600 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
buzbee091cc402014-03-31 10:14:40 -0700601 if (no_suspend) {
602 GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700603 }
604
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()) {
803 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
804 promotion_map_[p_map_idx].FpReg = res.DoubleToLowSingle().GetReg();
805 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
806 promotion_map_[p_map_idx+1].FpReg = res.DoubleToHighSingle().GetReg();
807 }
808 return res;
809}
810
Brian Carlstrom7940e442013-07-12 13:46:57 -0700811} // namespace art