blob: a50b90a0ecc8c8b38cc81687efb60f7684fb42e0 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Ian Rogers107c31e2014-01-23 20:55:29 -080017#include "codegen_arm.h"
18
19#include <inttypes.h>
20
Brian Carlstrom7940e442013-07-12 13:46:57 -070021#include <string>
22
Brian Carlstrom7940e442013-07-12 13:46:57 -070023#include "dex/compiler_internals.h"
24#include "dex/quick/mir_to_lir-inl.h"
25
26namespace art {
27
buzbee091cc402014-03-31 10:14:40 -070028// TODO: rework this when c++11 support allows.
29static const RegStorage core_regs_arr[] =
30 {rs_r0, rs_r1, rs_r2, rs_r3, rs_rARM_SUSPEND, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
31 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
32static const RegStorage sp_regs_arr[] =
33 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
34 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20,
35 rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30,
36 rs_fr31};
37static const RegStorage dp_regs_arr[] =
38 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10,
39 rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15};
40static const RegStorage reserved_regs_arr[] =
41 {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
42static const RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
43static const RegStorage sp_temps_arr[] =
44 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
45 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
46static const RegStorage dp_temps_arr[] =
47 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
48
buzbeeb01bf152014-05-13 15:59:07 -070049static const std::vector<RegStorage> empty_pool;
buzbee091cc402014-03-31 10:14:40 -070050static const std::vector<RegStorage> core_regs(core_regs_arr,
51 core_regs_arr + sizeof(core_regs_arr) / sizeof(core_regs_arr[0]));
52static const std::vector<RegStorage> sp_regs(sp_regs_arr,
53 sp_regs_arr + sizeof(sp_regs_arr) / sizeof(sp_regs_arr[0]));
54static const std::vector<RegStorage> dp_regs(dp_regs_arr,
55 dp_regs_arr + sizeof(dp_regs_arr) / sizeof(dp_regs_arr[0]));
56static const std::vector<RegStorage> reserved_regs(reserved_regs_arr,
57 reserved_regs_arr + sizeof(reserved_regs_arr) / sizeof(reserved_regs_arr[0]));
58static const std::vector<RegStorage> core_temps(core_temps_arr,
59 core_temps_arr + sizeof(core_temps_arr) / sizeof(core_temps_arr[0]));
60static const std::vector<RegStorage> sp_temps(sp_temps_arr,
61 sp_temps_arr + sizeof(sp_temps_arr) / sizeof(sp_temps_arr[0]));
62static const std::vector<RegStorage> dp_temps(dp_temps_arr,
63 dp_temps_arr + sizeof(dp_temps_arr) / sizeof(dp_temps_arr[0]));
Brian Carlstrom7940e442013-07-12 13:46:57 -070064
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070065RegLocation ArmMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000066 return arm_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070067}
68
buzbeea0cd2d72014-06-01 09:33:49 -070069RegLocation ArmMir2Lir::LocCReturnRef() {
70 return arm_loc_c_return;
71}
72
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070073RegLocation ArmMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000074 return arm_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070075}
76
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070077RegLocation ArmMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000078 return arm_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070079}
80
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070081RegLocation ArmMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000082 return arm_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070083}
84
85// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080086RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
buzbee091cc402014-03-31 10:14:40 -070087 RegStorage res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -070088 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -070089 case kSelf: res_reg = rs_rARM_SELF; break;
90 case kSuspend: res_reg = rs_rARM_SUSPEND; break;
91 case kLr: res_reg = rs_rARM_LR; break;
92 case kPc: res_reg = rs_rARM_PC; break;
93 case kSp: res_reg = rs_rARM_SP; break;
94 case kArg0: res_reg = rs_r0; break;
95 case kArg1: res_reg = rs_r1; break;
96 case kArg2: res_reg = rs_r2; break;
97 case kArg3: res_reg = rs_r3; break;
98 case kFArg0: res_reg = rs_r0; break;
99 case kFArg1: res_reg = rs_r1; break;
100 case kFArg2: res_reg = rs_r2; break;
101 case kFArg3: res_reg = rs_r3; break;
102 case kRet0: res_reg = rs_r0; break;
103 case kRet1: res_reg = rs_r1; break;
104 case kInvokeTgt: res_reg = rs_rARM_LR; break;
105 case kHiddenArg: res_reg = rs_r12; break;
106 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
107 case kCount: res_reg = RegStorage::InvalidReg(); break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700108 }
buzbee091cc402014-03-31 10:14:40 -0700109 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700110}
111
buzbee2700f7e2014-03-07 09:46:20 -0800112RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800113 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
114 switch (arg_num) {
115 case 0:
buzbee091cc402014-03-31 10:14:40 -0700116 return rs_r1;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800117 case 1:
buzbee091cc402014-03-31 10:14:40 -0700118 return rs_r2;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800119 case 2:
buzbee091cc402014-03-31 10:14:40 -0700120 return rs_r3;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800121 default:
buzbee2700f7e2014-03-07 09:46:20 -0800122 return RegStorage::InvalidReg();
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800123 }
124}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700125
Brian Carlstrom7940e442013-07-12 13:46:57 -0700126/*
127 * Decode the register id.
128 */
buzbee091cc402014-03-31 10:14:40 -0700129uint64_t ArmMir2Lir::GetRegMaskCommon(RegStorage reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700130 uint64_t seed;
131 int shift;
buzbee091cc402014-03-31 10:14:40 -0700132 int reg_id = reg.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700133 /* Each double register is equal to a pair of single-precision FP registers */
buzbee091cc402014-03-31 10:14:40 -0700134 if (reg.IsDouble()) {
135 seed = 0x3;
136 reg_id = reg_id << 1;
137 } else {
138 seed = 1;
139 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700140 /* FP register starts at bit position 16 */
buzbee091cc402014-03-31 10:14:40 -0700141 shift = reg.IsFloat() ? kArmFPReg0 : 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700142 /* Expand the double register id into single offset */
143 shift += reg_id;
144 return (seed << shift);
145}
146
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700147uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700148 return ENCODE_ARM_REG_PC;
149}
150
buzbeeb48819d2013-09-14 16:15:25 -0700151// Thumb2 specific setup. TODO: inline?:
152void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700153 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700154 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700155
Brian Carlstrom7940e442013-07-12 13:46:57 -0700156 int opcode = lir->opcode;
157
buzbeeb48819d2013-09-14 16:15:25 -0700158 // These flags are somewhat uncommon - bypass if we can.
159 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
160 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
161 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
162 if (flags & REG_DEF_SP) {
163 lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700164 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700165
buzbeeb48819d2013-09-14 16:15:25 -0700166 if (flags & REG_USE_SP) {
167 lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700168 }
buzbeeb48819d2013-09-14 16:15:25 -0700169
170 if (flags & REG_DEF_LIST0) {
171 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700172 }
buzbeeb48819d2013-09-14 16:15:25 -0700173
174 if (flags & REG_DEF_LIST1) {
175 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
176 }
177
178 if (flags & REG_DEF_FPCS_LIST0) {
179 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
180 }
181
182 if (flags & REG_DEF_FPCS_LIST2) {
183 for (int i = 0; i < lir->operands[2]; i++) {
184 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
185 }
186 }
187
188 if (flags & REG_USE_PC) {
189 lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
190 }
191
192 /* Conservatively treat the IT block */
193 if (flags & IS_IT) {
194 lir->u.m.def_mask = ENCODE_ALL;
195 }
196
197 if (flags & REG_USE_LIST0) {
198 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
199 }
200
201 if (flags & REG_USE_LIST1) {
202 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
203 }
204
205 if (flags & REG_USE_FPCS_LIST0) {
206 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
207 }
208
209 if (flags & REG_USE_FPCS_LIST2) {
210 for (int i = 0; i < lir->operands[2]; i++) {
211 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
212 }
213 }
214 /* Fixup for kThumbPush/lr and kThumbPop/pc */
215 if (opcode == kThumbPush || opcode == kThumbPop) {
buzbee091cc402014-03-31 10:14:40 -0700216 uint64_t r8Mask = GetRegMaskCommon(rs_r8);
buzbeeb48819d2013-09-14 16:15:25 -0700217 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
218 lir->u.m.use_mask &= ~r8Mask;
219 lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
220 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
221 lir->u.m.def_mask &= ~r8Mask;
222 lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
223 }
224 }
225 if (flags & REG_DEF_LR) {
226 lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
227 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700228 }
229}
230
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700231ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700232 ArmConditionCode res;
233 switch (ccode) {
234 case kCondEq: res = kArmCondEq; break;
235 case kCondNe: res = kArmCondNe; break;
236 case kCondCs: res = kArmCondCs; break;
237 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000238 case kCondUlt: res = kArmCondCc; break;
239 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700240 case kCondMi: res = kArmCondMi; break;
241 case kCondPl: res = kArmCondPl; break;
242 case kCondVs: res = kArmCondVs; break;
243 case kCondVc: res = kArmCondVc; break;
244 case kCondHi: res = kArmCondHi; break;
245 case kCondLs: res = kArmCondLs; break;
246 case kCondGe: res = kArmCondGe; break;
247 case kCondLt: res = kArmCondLt; break;
248 case kCondGt: res = kArmCondGt; break;
249 case kCondLe: res = kArmCondLe; break;
250 case kCondAl: res = kArmCondAl; break;
251 case kCondNv: res = kArmCondNv; break;
252 default:
253 LOG(FATAL) << "Bad condition code " << ccode;
254 res = static_cast<ArmConditionCode>(0); // Quiet gcc
255 }
256 return res;
257}
258
259static const char* core_reg_names[16] = {
260 "r0",
261 "r1",
262 "r2",
263 "r3",
264 "r4",
265 "r5",
266 "r6",
267 "r7",
268 "r8",
269 "rSELF",
270 "r10",
271 "r11",
272 "r12",
273 "sp",
274 "lr",
275 "pc",
276};
277
278
279static const char* shift_names[4] = {
280 "lsl",
281 "lsr",
282 "asr",
283 "ror"};
284
285/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800286static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 int i;
288 bool printed = false;
289 buf[0] = 0;
290 for (i = 0; i < 16; i++, vector >>= 1) {
291 if (vector & 0x1) {
292 int reg_id = i;
293 if (opcode == kThumbPush && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700294 reg_id = rs_rARM_LR.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700295 } else if (opcode == kThumbPop && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700296 reg_id = rs_rARM_PC.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700297 }
298 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800299 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700300 } else {
301 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800302 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700303 }
304 }
305 }
306 return buf;
307}
308
Ian Rogers988e6ea2014-01-08 11:30:50 -0800309static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
310 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700311 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800312 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700313 }
314 return buf;
315}
316
buzbee0d829482013-10-11 15:24:55 -0700317static int32_t ExpandImmediate(int value) {
318 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700319 uint32_t bits = value & 0xff;
320 switch (mode) {
321 case 0:
322 return bits;
323 case 1:
324 return (bits << 16) | bits;
325 case 2:
326 return (bits << 24) | (bits << 8);
327 case 3:
328 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
329 default:
330 break;
331 }
332 bits = (bits | 0x80) << 24;
333 return bits >> (((value & 0xf80) >> 7) - 8);
334}
335
Brian Carlstromb1eba212013-07-17 18:07:19 -0700336const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
337 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700338/*
339 * Interpret a format string and build a string no longer than size
340 * See format key in Assemble.c.
341 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700342std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700343 std::string buf;
344 int i;
345 const char* fmt_end = &fmt[strlen(fmt)];
346 char tbuf[256];
347 const char* name;
348 char nc;
349 while (fmt < fmt_end) {
350 int operand;
351 if (*fmt == '!') {
352 fmt++;
353 DCHECK_LT(fmt, fmt_end);
354 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700355 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700356 strcpy(tbuf, "!");
357 } else {
358 DCHECK_LT(fmt, fmt_end);
359 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
360 operand = lir->operands[nc-'0'];
361 switch (*fmt++) {
362 case 'H':
363 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800364 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700365 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700366 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700367 }
368 break;
369 case 'B':
370 switch (operand) {
371 case kSY:
372 name = "sy";
373 break;
374 case kST:
375 name = "st";
376 break;
377 case kISH:
378 name = "ish";
379 break;
380 case kISHST:
381 name = "ishst";
382 break;
383 case kNSH:
384 name = "nsh";
385 break;
386 case kNSHST:
387 name = "shst";
388 break;
389 default:
390 name = "DecodeError2";
391 break;
392 }
393 strcpy(tbuf, name);
394 break;
395 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700396 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700397 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700398 tbuf[i] += operand & 1;
399 operand >>= 1;
400 }
401 break;
402 case 'n':
403 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800404 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700405 break;
406 case 'm':
407 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800408 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700409 break;
410 case 's':
buzbee091cc402014-03-31 10:14:40 -0700411 snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700412 break;
413 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700414 snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700415 break;
416 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800417 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700418 break;
419 case 'M':
420 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800421 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700422 break;
423 case 'C':
buzbee091cc402014-03-31 10:14:40 -0700424 operand = RegStorage::RegNum(operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700425 DCHECK_LT(operand, static_cast<int>(
426 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800427 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700428 break;
429 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800430 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700431 break;
432 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800433 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700434 break;
435 case 'c':
436 strcpy(tbuf, cc_names[operand]);
437 break;
438 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800439 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
440 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700441 lir->target);
442 break;
443 case 'u': {
444 int offset_1 = lir->operands[0];
445 int offset_2 = NEXT_LIR(lir)->operands[0];
446 uintptr_t target =
447 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
448 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
449 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800450 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700451 break;
452 }
453
454 /* Nothing to print for BLX_2 */
455 case 'v':
456 strcpy(tbuf, "see above");
457 break;
458 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800459 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700460 break;
461 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800462 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700463 break;
464 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800465 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700466 break;
467 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700468 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700469 break;
470 }
471 buf += tbuf;
472 }
473 } else {
474 buf += *fmt++;
475 }
476 }
477 return buf;
478}
479
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700480void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700481 char buf[256];
482 buf[0] = 0;
483
484 if (mask == ENCODE_ALL) {
485 strcpy(buf, "all");
486 } else {
487 char num[8];
488 int i;
489
490 for (i = 0; i < kArmRegEnd; i++) {
491 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800492 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700493 strcat(buf, num);
494 }
495 }
496
497 if (mask & ENCODE_CCODE) {
498 strcat(buf, "cc ");
499 }
500 if (mask & ENCODE_FP_STATUS) {
501 strcat(buf, "fpcc ");
502 }
503
504 /* Memory bits */
505 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800506 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
507 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
508 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700509 }
510 if (mask & ENCODE_LITERAL) {
511 strcat(buf, "lit ");
512 }
513
514 if (mask & ENCODE_HEAP_REF) {
515 strcat(buf, "heap ");
516 }
517 if (mask & ENCODE_MUST_NOT_ALIAS) {
518 strcat(buf, "noalias ");
519 }
520 }
521 if (buf[0]) {
522 LOG(INFO) << prefix << ": " << buf;
523 }
524}
525
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700526bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700527 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
528}
529
Vladimir Marko674744e2014-04-24 15:18:26 +0100530bool ArmMir2Lir::SupportsVolatileLoadStore(OpSize size) {
531 return true;
532}
533
534RegisterClass ArmMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
535 if (UNLIKELY(is_volatile)) {
536 // On arm, atomic 64-bit load/store requires a core register pair.
537 // Smaller aligned load/store is atomic for both core and fp registers.
538 if (size == k64 || size == kDouble) {
539 return kCoreReg;
540 }
541 }
542 return RegClassBySize(size);
543}
544
Brian Carlstrom7940e442013-07-12 13:46:57 -0700545ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
546 : Mir2Lir(cu, mir_graph, arena) {
547 // Sanity check - make sure encoding map lines up.
548 for (int i = 0; i < kArmLast; i++) {
549 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
550 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
551 << " is wrong: expecting " << i << ", seeing "
552 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
553 }
554 }
555}
556
557Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
558 ArenaAllocator* const arena) {
559 return new ArmMir2Lir(cu, mir_graph, arena);
560}
561
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700562void ArmMir2Lir::CompilerInitializeRegAlloc() {
buzbeeb01bf152014-05-13 15:59:07 -0700563 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs,
564 dp_regs, reserved_regs, empty_pool /* reserved64 */,
565 core_temps, empty_pool /* core64_temps */, sp_temps,
566 dp_temps);
Dave Allisonf6b65c12014-04-01 17:45:18 -0700567
buzbee091cc402014-03-31 10:14:40 -0700568 // Target-specific adjustments.
569
570 // Alias single precision floats to appropriate half of overlapping double.
571 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
572 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
573 int sp_reg_num = info->GetReg().GetRegNum();
574 int dp_reg_num = sp_reg_num >> 1;
575 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
576 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
577 // Double precision register's master storage should refer to itself.
578 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
579 // Redirect single precision's master storage to master.
580 info->SetMaster(dp_reg_info);
581 // Singles should show a single 32-bit mask bit, at first referring to the low half.
buzbee85089dd2014-05-25 15:10:52 -0700582 DCHECK_EQ(info->StorageMask(), RegisterInfo::kLowSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700583 if (sp_reg_num & 1) {
buzbee85089dd2014-05-25 15:10:52 -0700584 // For odd singles, change to use the high word of the backing double.
585 info->SetStorageMask(RegisterInfo::kHighSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700586 }
587 }
588
Dave Allison83252962014-04-03 16:33:48 -0700589 // TODO: re-enable this when we can safely save r4 over the suspension code path.
590 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
buzbee091cc402014-03-31 10:14:40 -0700591 if (no_suspend) {
592 GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700593 }
594
buzbee091cc402014-03-31 10:14:40 -0700595 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
596 // TODO: adjust when we roll to hard float calling convention.
597 reg_pool_->next_core_reg_ = 2;
598 reg_pool_->next_sp_reg_ = 0;
599 reg_pool_->next_dp_reg_ = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700600}
601
Brian Carlstrom7940e442013-07-12 13:46:57 -0700602/*
603 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
604 * instructions might call out to C/assembly helper functions. Until
605 * machinery is in place, always spill lr.
606 */
607
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700608void ArmMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700609 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700610 num_core_spills_++;
611}
612
613/*
614 * Mark a callee-save fp register as promoted. Note that
615 * vpush/vpop uses contiguous register lists so we must
616 * include any holes in the mask. Associate holes with
617 * Dalvik register INVALID_VREG (0xFFFFU).
618 */
buzbee091cc402014-03-31 10:14:40 -0700619void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
620 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
621 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700622 // Ensure fp_vmap_table is large enough
623 int table_size = fp_vmap_table_.size();
buzbee091cc402014-03-31 10:14:40 -0700624 for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700625 fp_vmap_table_.push_back(INVALID_VREG);
626 }
627 // Add the current mapping
buzbee091cc402014-03-31 10:14:40 -0700628 fp_vmap_table_[adjusted_reg_num] = v_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700629 // Size of fp_vmap_table is high-water mark, use to set mask
630 num_fp_spills_ = fp_vmap_table_.size();
631 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
632}
633
buzbee091cc402014-03-31 10:14:40 -0700634void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
635 // TEMP: perform as 2 singles.
636 int reg_num = reg.GetRegNum() << 1;
637 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
638 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
639 MarkPreservedSingle(v_reg, lo);
640 MarkPreservedSingle(v_reg + 1, hi);
buzbee2700f7e2014-03-07 09:46:20 -0800641}
642
Brian Carlstrom7940e442013-07-12 13:46:57 -0700643/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000644void ArmMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700645 // TODO: rework this - it's gotten even more ugly.
646 Clobber(rs_r0);
647 Clobber(rs_r1);
648 Clobber(rs_r2);
649 Clobber(rs_r3);
650 Clobber(rs_r12);
651 Clobber(rs_r14lr);
652 Clobber(rs_fr0);
653 Clobber(rs_fr1);
654 Clobber(rs_fr2);
655 Clobber(rs_fr3);
656 Clobber(rs_fr4);
657 Clobber(rs_fr5);
658 Clobber(rs_fr6);
659 Clobber(rs_fr7);
660 Clobber(rs_fr8);
661 Clobber(rs_fr9);
662 Clobber(rs_fr10);
663 Clobber(rs_fr11);
664 Clobber(rs_fr12);
665 Clobber(rs_fr13);
666 Clobber(rs_fr14);
667 Clobber(rs_fr15);
668 Clobber(rs_dr0);
669 Clobber(rs_dr1);
670 Clobber(rs_dr2);
671 Clobber(rs_dr3);
672 Clobber(rs_dr4);
673 Clobber(rs_dr5);
674 Clobber(rs_dr6);
675 Clobber(rs_dr7);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700676}
677
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700678RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700679 RegLocation res = LocCReturnWide();
buzbee091cc402014-03-31 10:14:40 -0700680 res.reg.SetLowReg(rs_r2.GetReg());
681 res.reg.SetHighReg(rs_r3.GetReg());
682 Clobber(rs_r2);
683 Clobber(rs_r3);
684 MarkInUse(rs_r2);
685 MarkInUse(rs_r3);
686 MarkWide(res.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700687 return res;
688}
689
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700690RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700691 RegLocation res = LocCReturn();
buzbee091cc402014-03-31 10:14:40 -0700692 res.reg.SetReg(rs_r1.GetReg());
693 Clobber(rs_r1);
694 MarkInUse(rs_r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700695 return res;
696}
697
Brian Carlstrom7940e442013-07-12 13:46:57 -0700698/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700699void ArmMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700700 LockTemp(rs_r0);
701 LockTemp(rs_r1);
702 LockTemp(rs_r2);
703 LockTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700704}
705
706/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700707void ArmMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700708 FreeTemp(rs_r0);
709 FreeTemp(rs_r1);
710 FreeTemp(rs_r2);
711 FreeTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700712}
713
Ian Rogersdd7624d2014-03-14 17:43:00 -0700714RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
buzbee2700f7e2014-03-07 09:46:20 -0800715 LoadWordDisp(rs_rARM_SELF, offset.Int32Value(), rs_rARM_LR);
716 return rs_rARM_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700717}
718
Andreas Gampe2f244e92014-05-08 03:35:25 -0700719RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<8> offset) {
720 UNIMPLEMENTED(FATAL) << "Should not be called.";
721 return RegStorage::InvalidReg();
722}
723
Dave Allisonb373e092014-02-20 16:06:36 -0800724LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800725 RegStorage tmp = rs_r0;
buzbee695d13a2014-04-19 13:32:20 -0700726 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
727 LIR* load2 = Load32Disp(tmp, 0, tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800728 return load2;
729}
730
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700731uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700732 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700733 return ArmMir2Lir::EncodingMap[opcode].flags;
734}
735
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700736const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700737 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700738 return ArmMir2Lir::EncodingMap[opcode].name;
739}
740
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700741const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700742 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700743 return ArmMir2Lir::EncodingMap[opcode].fmt;
744}
745
buzbee091cc402014-03-31 10:14:40 -0700746/*
747 * Somewhat messy code here. We want to allocate a pair of contiguous
748 * physical single-precision floating point registers starting with
749 * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
750 * has already been allocated - try to fit if possible. Fail to
751 * allocate if we can't meet the requirements for the pair of
752 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
753 */
754// TODO: needs rewrite to support non-backed 64-bit float regs.
755RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
756 RegStorage res;
757 int v_reg = mir_graph_->SRegToVReg(s_reg);
758 int p_map_idx = SRegToPMap(s_reg);
759 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
760 // Upper reg is already allocated. Can we fit?
761 int high_reg = promotion_map_[p_map_idx+1].FpReg;
762 if ((high_reg & 1) == 0) {
763 // High reg is even - fail.
764 return res; // Invalid.
765 }
766 // Is the low reg of the pair free?
767 // FIXME: rework.
768 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
769 if (p->InUse() || p->IsTemp()) {
770 // Already allocated or not preserved - fail.
771 return res; // Invalid.
772 }
773 // OK - good to go.
774 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
775 p->MarkInUse();
776 MarkPreservedSingle(v_reg, p->GetReg());
777 } else {
778 /*
779 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
780 * different underlying physical registers.
781 */
782 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
783 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
784 if (!info->IsTemp() && !info->InUse()) {
785 res = info->GetReg();
786 info->MarkInUse();
787 MarkPreservedDouble(v_reg, info->GetReg());
788 break;
789 }
790 }
791 }
792 if (res.Valid()) {
buzbee85089dd2014-05-25 15:10:52 -0700793 RegisterInfo* info = GetRegInfo(res);
buzbee091cc402014-03-31 10:14:40 -0700794 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
buzbee85089dd2014-05-25 15:10:52 -0700795 promotion_map_[p_map_idx].FpReg =
796 info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700797 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
buzbee85089dd2014-05-25 15:10:52 -0700798 promotion_map_[p_map_idx+1].FpReg =
799 info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700800 }
801 return res;
802}
803
Brian Carlstrom7940e442013-07-12 13:46:57 -0700804} // namespace art