blob: d0c81d5bbcd2e7f695203b02b2a56bc1dfe7fdcd [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
buzbee2700f7e2014-03-07 09:46:20 -0800612void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
613 DCHECK(rl_keep.wide);
614 DCHECK(rl_free.wide);
615 if ((rl_free.reg.GetLowReg() != rl_keep.reg.GetLowReg()) &&
616 (rl_free.reg.GetLowReg() != rl_keep.reg.GetHighReg()) &&
617 (rl_free.reg.GetHighReg() != rl_keep.reg.GetLowReg()) &&
618 (rl_free.reg.GetHighReg() != rl_keep.reg.GetHighReg())) {
619 // No overlap, free.
620 FreeTemp(rl_free.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700621 }
622}
buzbee2700f7e2014-03-07 09:46:20 -0800623
Brian Carlstrom7940e442013-07-12 13:46:57 -0700624/*
625 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
626 * instructions might call out to C/assembly helper functions. Until
627 * machinery is in place, always spill lr.
628 */
629
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700630void ArmMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700631 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700632 num_core_spills_++;
633}
634
635/*
636 * Mark a callee-save fp register as promoted. Note that
637 * vpush/vpop uses contiguous register lists so we must
638 * include any holes in the mask. Associate holes with
639 * Dalvik register INVALID_VREG (0xFFFFU).
640 */
buzbee091cc402014-03-31 10:14:40 -0700641void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
642 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
643 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700644 // Ensure fp_vmap_table is large enough
645 int table_size = fp_vmap_table_.size();
buzbee091cc402014-03-31 10:14:40 -0700646 for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700647 fp_vmap_table_.push_back(INVALID_VREG);
648 }
649 // Add the current mapping
buzbee091cc402014-03-31 10:14:40 -0700650 fp_vmap_table_[adjusted_reg_num] = v_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700651 // Size of fp_vmap_table is high-water mark, use to set mask
652 num_fp_spills_ = fp_vmap_table_.size();
653 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
654}
655
buzbee091cc402014-03-31 10:14:40 -0700656void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
657 // TEMP: perform as 2 singles.
658 int reg_num = reg.GetRegNum() << 1;
659 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
660 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
661 MarkPreservedSingle(v_reg, lo);
662 MarkPreservedSingle(v_reg + 1, hi);
buzbee2700f7e2014-03-07 09:46:20 -0800663}
664
Brian Carlstrom7940e442013-07-12 13:46:57 -0700665/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000666void ArmMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700667 // TODO: rework this - it's gotten even more ugly.
668 Clobber(rs_r0);
669 Clobber(rs_r1);
670 Clobber(rs_r2);
671 Clobber(rs_r3);
672 Clobber(rs_r12);
673 Clobber(rs_r14lr);
674 Clobber(rs_fr0);
675 Clobber(rs_fr1);
676 Clobber(rs_fr2);
677 Clobber(rs_fr3);
678 Clobber(rs_fr4);
679 Clobber(rs_fr5);
680 Clobber(rs_fr6);
681 Clobber(rs_fr7);
682 Clobber(rs_fr8);
683 Clobber(rs_fr9);
684 Clobber(rs_fr10);
685 Clobber(rs_fr11);
686 Clobber(rs_fr12);
687 Clobber(rs_fr13);
688 Clobber(rs_fr14);
689 Clobber(rs_fr15);
690 Clobber(rs_dr0);
691 Clobber(rs_dr1);
692 Clobber(rs_dr2);
693 Clobber(rs_dr3);
694 Clobber(rs_dr4);
695 Clobber(rs_dr5);
696 Clobber(rs_dr6);
697 Clobber(rs_dr7);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700698}
699
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700700RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700701 RegLocation res = LocCReturnWide();
buzbee091cc402014-03-31 10:14:40 -0700702 res.reg.SetLowReg(rs_r2.GetReg());
703 res.reg.SetHighReg(rs_r3.GetReg());
704 Clobber(rs_r2);
705 Clobber(rs_r3);
706 MarkInUse(rs_r2);
707 MarkInUse(rs_r3);
708 MarkWide(res.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700709 return res;
710}
711
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700712RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700713 RegLocation res = LocCReturn();
buzbee091cc402014-03-31 10:14:40 -0700714 res.reg.SetReg(rs_r1.GetReg());
715 Clobber(rs_r1);
716 MarkInUse(rs_r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700717 return res;
718}
719
Brian Carlstrom7940e442013-07-12 13:46:57 -0700720/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700721void ArmMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700722 LockTemp(rs_r0);
723 LockTemp(rs_r1);
724 LockTemp(rs_r2);
725 LockTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700726}
727
728/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700729void ArmMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700730 FreeTemp(rs_r0);
731 FreeTemp(rs_r1);
732 FreeTemp(rs_r2);
733 FreeTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700734}
735
Ian Rogersdd7624d2014-03-14 17:43:00 -0700736RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
buzbee2700f7e2014-03-07 09:46:20 -0800737 LoadWordDisp(rs_rARM_SELF, offset.Int32Value(), rs_rARM_LR);
738 return rs_rARM_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700739}
740
Dave Allisonb373e092014-02-20 16:06:36 -0800741LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800742 RegStorage tmp = rs_r0;
buzbee695d13a2014-04-19 13:32:20 -0700743 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
744 LIR* load2 = Load32Disp(tmp, 0, tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800745 return load2;
746}
747
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700748uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700749 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700750 return ArmMir2Lir::EncodingMap[opcode].flags;
751}
752
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700753const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700754 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700755 return ArmMir2Lir::EncodingMap[opcode].name;
756}
757
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700758const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700759 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700760 return ArmMir2Lir::EncodingMap[opcode].fmt;
761}
762
buzbee091cc402014-03-31 10:14:40 -0700763/*
764 * Somewhat messy code here. We want to allocate a pair of contiguous
765 * physical single-precision floating point registers starting with
766 * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
767 * has already been allocated - try to fit if possible. Fail to
768 * allocate if we can't meet the requirements for the pair of
769 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
770 */
771// TODO: needs rewrite to support non-backed 64-bit float regs.
772RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
773 RegStorage res;
774 int v_reg = mir_graph_->SRegToVReg(s_reg);
775 int p_map_idx = SRegToPMap(s_reg);
776 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
777 // Upper reg is already allocated. Can we fit?
778 int high_reg = promotion_map_[p_map_idx+1].FpReg;
779 if ((high_reg & 1) == 0) {
780 // High reg is even - fail.
781 return res; // Invalid.
782 }
783 // Is the low reg of the pair free?
784 // FIXME: rework.
785 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
786 if (p->InUse() || p->IsTemp()) {
787 // Already allocated or not preserved - fail.
788 return res; // Invalid.
789 }
790 // OK - good to go.
791 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
792 p->MarkInUse();
793 MarkPreservedSingle(v_reg, p->GetReg());
794 } else {
795 /*
796 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
797 * different underlying physical registers.
798 */
799 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
800 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
801 if (!info->IsTemp() && !info->InUse()) {
802 res = info->GetReg();
803 info->MarkInUse();
804 MarkPreservedDouble(v_reg, info->GetReg());
805 break;
806 }
807 }
808 }
809 if (res.Valid()) {
810 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
811 promotion_map_[p_map_idx].FpReg = res.DoubleToLowSingle().GetReg();
812 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
813 promotion_map_[p_map_idx+1].FpReg = res.DoubleToHighSingle().GetReg();
814 }
815 return res;
816}
817
Brian Carlstrom7940e442013-07-12 13:46:57 -0700818} // namespace art