blob: 5340d8370a3c5e8f8ef87841b08c5a844f461746 [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
Vladimir Marko089142c2014-06-05 10:57:05 +010028static constexpr RegStorage core_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070029 {rs_r0, rs_r1, rs_r2, rs_r3, rs_rARM_SUSPEND, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
30 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
Vladimir Marko089142c2014-06-05 10:57:05 +010031static constexpr RegStorage sp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070032 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
33 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20,
34 rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30,
35 rs_fr31};
Vladimir Marko089142c2014-06-05 10:57:05 +010036static constexpr RegStorage dp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070037 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10,
38 rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15};
Vladimir Marko089142c2014-06-05 10:57:05 +010039static constexpr RegStorage reserved_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070040 {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
Vladimir Marko089142c2014-06-05 10:57:05 +010041static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
42static constexpr RegStorage sp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070043 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
44 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
Vladimir Marko089142c2014-06-05 10:57:05 +010045static constexpr RegStorage dp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070046 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
47
Vladimir Marko089142c2014-06-05 10:57:05 +010048static constexpr ArrayRef<const RegStorage> empty_pool;
49static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
50static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
51static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
52static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
53static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
54static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
55static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
Brian Carlstrom7940e442013-07-12 13:46:57 -070056
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070057RegLocation ArmMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000058 return arm_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070059}
60
buzbeea0cd2d72014-06-01 09:33:49 -070061RegLocation ArmMir2Lir::LocCReturnRef() {
62 return arm_loc_c_return;
63}
64
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070065RegLocation ArmMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000066 return arm_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070067}
68
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070069RegLocation ArmMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000070 return arm_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070071}
72
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070073RegLocation ArmMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000074 return arm_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070075}
76
77// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080078RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
buzbee091cc402014-03-31 10:14:40 -070079 RegStorage res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -070080 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -070081 case kSelf: res_reg = rs_rARM_SELF; break;
82 case kSuspend: res_reg = rs_rARM_SUSPEND; break;
83 case kLr: res_reg = rs_rARM_LR; break;
84 case kPc: res_reg = rs_rARM_PC; break;
85 case kSp: res_reg = rs_rARM_SP; break;
86 case kArg0: res_reg = rs_r0; break;
87 case kArg1: res_reg = rs_r1; break;
88 case kArg2: res_reg = rs_r2; break;
89 case kArg3: res_reg = rs_r3; break;
90 case kFArg0: res_reg = rs_r0; break;
91 case kFArg1: res_reg = rs_r1; break;
92 case kFArg2: res_reg = rs_r2; break;
93 case kFArg3: res_reg = rs_r3; break;
94 case kRet0: res_reg = rs_r0; break;
95 case kRet1: res_reg = rs_r1; break;
96 case kInvokeTgt: res_reg = rs_rARM_LR; break;
97 case kHiddenArg: res_reg = rs_r12; break;
98 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
99 case kCount: res_reg = RegStorage::InvalidReg(); break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700100 }
buzbee091cc402014-03-31 10:14:40 -0700101 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700102}
103
buzbee2700f7e2014-03-07 09:46:20 -0800104RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800105 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
106 switch (arg_num) {
107 case 0:
buzbee091cc402014-03-31 10:14:40 -0700108 return rs_r1;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800109 case 1:
buzbee091cc402014-03-31 10:14:40 -0700110 return rs_r2;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800111 case 2:
buzbee091cc402014-03-31 10:14:40 -0700112 return rs_r3;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800113 default:
buzbee2700f7e2014-03-07 09:46:20 -0800114 return RegStorage::InvalidReg();
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800115 }
116}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700117
Brian Carlstrom7940e442013-07-12 13:46:57 -0700118/*
119 * Decode the register id.
120 */
buzbee091cc402014-03-31 10:14:40 -0700121uint64_t ArmMir2Lir::GetRegMaskCommon(RegStorage reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700122 uint64_t seed;
123 int shift;
buzbee091cc402014-03-31 10:14:40 -0700124 int reg_id = reg.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700125 /* Each double register is equal to a pair of single-precision FP registers */
buzbee091cc402014-03-31 10:14:40 -0700126 if (reg.IsDouble()) {
127 seed = 0x3;
128 reg_id = reg_id << 1;
129 } else {
130 seed = 1;
131 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700132 /* FP register starts at bit position 16 */
buzbee091cc402014-03-31 10:14:40 -0700133 shift = reg.IsFloat() ? kArmFPReg0 : 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134 /* Expand the double register id into single offset */
135 shift += reg_id;
136 return (seed << shift);
137}
138
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700139uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700140 return ENCODE_ARM_REG_PC;
141}
142
buzbeeb48819d2013-09-14 16:15:25 -0700143// Thumb2 specific setup. TODO: inline?:
144void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700145 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700146 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700147
Brian Carlstrom7940e442013-07-12 13:46:57 -0700148 int opcode = lir->opcode;
149
buzbeeb48819d2013-09-14 16:15:25 -0700150 // These flags are somewhat uncommon - bypass if we can.
151 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
152 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
153 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
154 if (flags & REG_DEF_SP) {
155 lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700156 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700157
buzbeeb48819d2013-09-14 16:15:25 -0700158 if (flags & REG_USE_SP) {
159 lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700160 }
buzbeeb48819d2013-09-14 16:15:25 -0700161
162 if (flags & REG_DEF_LIST0) {
163 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700164 }
buzbeeb48819d2013-09-14 16:15:25 -0700165
166 if (flags & REG_DEF_LIST1) {
167 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
168 }
169
170 if (flags & REG_DEF_FPCS_LIST0) {
171 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
172 }
173
174 if (flags & REG_DEF_FPCS_LIST2) {
175 for (int i = 0; i < lir->operands[2]; i++) {
176 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
177 }
178 }
179
180 if (flags & REG_USE_PC) {
181 lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
182 }
183
184 /* Conservatively treat the IT block */
185 if (flags & IS_IT) {
186 lir->u.m.def_mask = ENCODE_ALL;
187 }
188
189 if (flags & REG_USE_LIST0) {
190 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
191 }
192
193 if (flags & REG_USE_LIST1) {
194 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
195 }
196
197 if (flags & REG_USE_FPCS_LIST0) {
198 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
199 }
200
201 if (flags & REG_USE_FPCS_LIST2) {
202 for (int i = 0; i < lir->operands[2]; i++) {
203 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
204 }
205 }
206 /* Fixup for kThumbPush/lr and kThumbPop/pc */
207 if (opcode == kThumbPush || opcode == kThumbPop) {
buzbee091cc402014-03-31 10:14:40 -0700208 uint64_t r8Mask = GetRegMaskCommon(rs_r8);
buzbeeb48819d2013-09-14 16:15:25 -0700209 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
210 lir->u.m.use_mask &= ~r8Mask;
211 lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
212 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
213 lir->u.m.def_mask &= ~r8Mask;
214 lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
215 }
216 }
217 if (flags & REG_DEF_LR) {
218 lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
219 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700220 }
221}
222
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700223ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700224 ArmConditionCode res;
225 switch (ccode) {
226 case kCondEq: res = kArmCondEq; break;
227 case kCondNe: res = kArmCondNe; break;
228 case kCondCs: res = kArmCondCs; break;
229 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000230 case kCondUlt: res = kArmCondCc; break;
231 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700232 case kCondMi: res = kArmCondMi; break;
233 case kCondPl: res = kArmCondPl; break;
234 case kCondVs: res = kArmCondVs; break;
235 case kCondVc: res = kArmCondVc; break;
236 case kCondHi: res = kArmCondHi; break;
237 case kCondLs: res = kArmCondLs; break;
238 case kCondGe: res = kArmCondGe; break;
239 case kCondLt: res = kArmCondLt; break;
240 case kCondGt: res = kArmCondGt; break;
241 case kCondLe: res = kArmCondLe; break;
242 case kCondAl: res = kArmCondAl; break;
243 case kCondNv: res = kArmCondNv; break;
244 default:
245 LOG(FATAL) << "Bad condition code " << ccode;
246 res = static_cast<ArmConditionCode>(0); // Quiet gcc
247 }
248 return res;
249}
250
251static const char* core_reg_names[16] = {
252 "r0",
253 "r1",
254 "r2",
255 "r3",
256 "r4",
257 "r5",
258 "r6",
259 "r7",
260 "r8",
261 "rSELF",
262 "r10",
263 "r11",
264 "r12",
265 "sp",
266 "lr",
267 "pc",
268};
269
270
271static const char* shift_names[4] = {
272 "lsl",
273 "lsr",
274 "asr",
275 "ror"};
276
277/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800278static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700279 int i;
280 bool printed = false;
281 buf[0] = 0;
282 for (i = 0; i < 16; i++, vector >>= 1) {
283 if (vector & 0x1) {
284 int reg_id = i;
285 if (opcode == kThumbPush && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700286 reg_id = rs_rARM_LR.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 } else if (opcode == kThumbPop && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700288 reg_id = rs_rARM_PC.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700289 }
290 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800291 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700292 } else {
293 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800294 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700295 }
296 }
297 }
298 return buf;
299}
300
Ian Rogers988e6ea2014-01-08 11:30:50 -0800301static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
302 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700303 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800304 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700305 }
306 return buf;
307}
308
buzbee0d829482013-10-11 15:24:55 -0700309static int32_t ExpandImmediate(int value) {
310 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700311 uint32_t bits = value & 0xff;
312 switch (mode) {
313 case 0:
314 return bits;
315 case 1:
316 return (bits << 16) | bits;
317 case 2:
318 return (bits << 24) | (bits << 8);
319 case 3:
320 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
321 default:
322 break;
323 }
324 bits = (bits | 0x80) << 24;
325 return bits >> (((value & 0xf80) >> 7) - 8);
326}
327
Brian Carlstromb1eba212013-07-17 18:07:19 -0700328const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
329 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700330/*
331 * Interpret a format string and build a string no longer than size
332 * See format key in Assemble.c.
333 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700334std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335 std::string buf;
336 int i;
337 const char* fmt_end = &fmt[strlen(fmt)];
338 char tbuf[256];
339 const char* name;
340 char nc;
341 while (fmt < fmt_end) {
342 int operand;
343 if (*fmt == '!') {
344 fmt++;
345 DCHECK_LT(fmt, fmt_end);
346 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700347 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700348 strcpy(tbuf, "!");
349 } else {
350 DCHECK_LT(fmt, fmt_end);
351 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
352 operand = lir->operands[nc-'0'];
353 switch (*fmt++) {
354 case 'H':
355 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800356 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700357 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700358 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700359 }
360 break;
361 case 'B':
362 switch (operand) {
363 case kSY:
364 name = "sy";
365 break;
366 case kST:
367 name = "st";
368 break;
369 case kISH:
370 name = "ish";
371 break;
372 case kISHST:
373 name = "ishst";
374 break;
375 case kNSH:
376 name = "nsh";
377 break;
378 case kNSHST:
379 name = "shst";
380 break;
381 default:
382 name = "DecodeError2";
383 break;
384 }
385 strcpy(tbuf, name);
386 break;
387 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700388 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700389 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700390 tbuf[i] += operand & 1;
391 operand >>= 1;
392 }
393 break;
394 case 'n':
395 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800396 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700397 break;
398 case 'm':
399 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800400 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700401 break;
402 case 's':
buzbee091cc402014-03-31 10:14:40 -0700403 snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700404 break;
405 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700406 snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700407 break;
408 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800409 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700410 break;
411 case 'M':
412 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800413 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700414 break;
415 case 'C':
buzbee091cc402014-03-31 10:14:40 -0700416 operand = RegStorage::RegNum(operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700417 DCHECK_LT(operand, static_cast<int>(
418 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800419 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700420 break;
421 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800422 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700423 break;
424 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800425 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700426 break;
427 case 'c':
428 strcpy(tbuf, cc_names[operand]);
429 break;
430 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800431 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
432 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433 lir->target);
434 break;
435 case 'u': {
436 int offset_1 = lir->operands[0];
437 int offset_2 = NEXT_LIR(lir)->operands[0];
438 uintptr_t target =
439 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
440 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
441 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800442 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700443 break;
444 }
445
446 /* Nothing to print for BLX_2 */
447 case 'v':
448 strcpy(tbuf, "see above");
449 break;
450 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800451 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700452 break;
453 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800454 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700455 break;
456 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800457 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700458 break;
459 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700460 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700461 break;
462 }
463 buf += tbuf;
464 }
465 } else {
466 buf += *fmt++;
467 }
468 }
469 return buf;
470}
471
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700472void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700473 char buf[256];
474 buf[0] = 0;
475
476 if (mask == ENCODE_ALL) {
477 strcpy(buf, "all");
478 } else {
479 char num[8];
480 int i;
481
482 for (i = 0; i < kArmRegEnd; i++) {
483 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800484 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700485 strcat(buf, num);
486 }
487 }
488
489 if (mask & ENCODE_CCODE) {
490 strcat(buf, "cc ");
491 }
492 if (mask & ENCODE_FP_STATUS) {
493 strcat(buf, "fpcc ");
494 }
495
496 /* Memory bits */
497 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800498 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
499 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
500 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700501 }
502 if (mask & ENCODE_LITERAL) {
503 strcat(buf, "lit ");
504 }
505
506 if (mask & ENCODE_HEAP_REF) {
507 strcat(buf, "heap ");
508 }
509 if (mask & ENCODE_MUST_NOT_ALIAS) {
510 strcat(buf, "noalias ");
511 }
512 }
513 if (buf[0]) {
514 LOG(INFO) << prefix << ": " << buf;
515 }
516}
517
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700518bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700519 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
520}
521
Vladimir Marko674744e2014-04-24 15:18:26 +0100522bool ArmMir2Lir::SupportsVolatileLoadStore(OpSize size) {
523 return true;
524}
525
526RegisterClass ArmMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
527 if (UNLIKELY(is_volatile)) {
528 // On arm, atomic 64-bit load/store requires a core register pair.
529 // Smaller aligned load/store is atomic for both core and fp registers.
530 if (size == k64 || size == kDouble) {
531 return kCoreReg;
532 }
533 }
534 return RegClassBySize(size);
535}
536
Brian Carlstrom7940e442013-07-12 13:46:57 -0700537ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
538 : Mir2Lir(cu, mir_graph, arena) {
539 // Sanity check - make sure encoding map lines up.
540 for (int i = 0; i < kArmLast; i++) {
541 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
542 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
543 << " is wrong: expecting " << i << ", seeing "
544 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
545 }
546 }
547}
548
549Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
550 ArenaAllocator* const arena) {
551 return new ArmMir2Lir(cu, mir_graph, arena);
552}
553
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700554void ArmMir2Lir::CompilerInitializeRegAlloc() {
buzbeeb01bf152014-05-13 15:59:07 -0700555 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs,
556 dp_regs, reserved_regs, empty_pool /* reserved64 */,
557 core_temps, empty_pool /* core64_temps */, sp_temps,
558 dp_temps);
Dave Allisonf6b65c12014-04-01 17:45:18 -0700559
buzbee091cc402014-03-31 10:14:40 -0700560 // Target-specific adjustments.
561
562 // Alias single precision floats to appropriate half of overlapping double.
563 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
564 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
565 int sp_reg_num = info->GetReg().GetRegNum();
566 int dp_reg_num = sp_reg_num >> 1;
567 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
568 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
569 // Double precision register's master storage should refer to itself.
570 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
571 // Redirect single precision's master storage to master.
572 info->SetMaster(dp_reg_info);
573 // Singles should show a single 32-bit mask bit, at first referring to the low half.
buzbee85089dd2014-05-25 15:10:52 -0700574 DCHECK_EQ(info->StorageMask(), RegisterInfo::kLowSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700575 if (sp_reg_num & 1) {
buzbee85089dd2014-05-25 15:10:52 -0700576 // For odd singles, change to use the high word of the backing double.
577 info->SetStorageMask(RegisterInfo::kHighSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700578 }
579 }
580
Dave Allison83252962014-04-03 16:33:48 -0700581 // TODO: re-enable this when we can safely save r4 over the suspension code path.
582 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
buzbee091cc402014-03-31 10:14:40 -0700583 if (no_suspend) {
584 GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700585 }
586
buzbee091cc402014-03-31 10:14:40 -0700587 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
588 // TODO: adjust when we roll to hard float calling convention.
589 reg_pool_->next_core_reg_ = 2;
590 reg_pool_->next_sp_reg_ = 0;
591 reg_pool_->next_dp_reg_ = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700592}
593
Brian Carlstrom7940e442013-07-12 13:46:57 -0700594/*
595 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
596 * instructions might call out to C/assembly helper functions. Until
597 * machinery is in place, always spill lr.
598 */
599
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700600void ArmMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700601 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700602 num_core_spills_++;
603}
604
605/*
606 * Mark a callee-save fp register as promoted. Note that
607 * vpush/vpop uses contiguous register lists so we must
608 * include any holes in the mask. Associate holes with
609 * Dalvik register INVALID_VREG (0xFFFFU).
610 */
buzbee091cc402014-03-31 10:14:40 -0700611void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
612 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
613 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700614 // Ensure fp_vmap_table is large enough
615 int table_size = fp_vmap_table_.size();
buzbee091cc402014-03-31 10:14:40 -0700616 for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700617 fp_vmap_table_.push_back(INVALID_VREG);
618 }
619 // Add the current mapping
buzbee091cc402014-03-31 10:14:40 -0700620 fp_vmap_table_[adjusted_reg_num] = v_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700621 // Size of fp_vmap_table is high-water mark, use to set mask
622 num_fp_spills_ = fp_vmap_table_.size();
623 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
624}
625
buzbee091cc402014-03-31 10:14:40 -0700626void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
627 // TEMP: perform as 2 singles.
628 int reg_num = reg.GetRegNum() << 1;
629 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
630 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
631 MarkPreservedSingle(v_reg, lo);
632 MarkPreservedSingle(v_reg + 1, hi);
buzbee2700f7e2014-03-07 09:46:20 -0800633}
634
Brian Carlstrom7940e442013-07-12 13:46:57 -0700635/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000636void ArmMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700637 // TODO: rework this - it's gotten even more ugly.
638 Clobber(rs_r0);
639 Clobber(rs_r1);
640 Clobber(rs_r2);
641 Clobber(rs_r3);
642 Clobber(rs_r12);
643 Clobber(rs_r14lr);
644 Clobber(rs_fr0);
645 Clobber(rs_fr1);
646 Clobber(rs_fr2);
647 Clobber(rs_fr3);
648 Clobber(rs_fr4);
649 Clobber(rs_fr5);
650 Clobber(rs_fr6);
651 Clobber(rs_fr7);
652 Clobber(rs_fr8);
653 Clobber(rs_fr9);
654 Clobber(rs_fr10);
655 Clobber(rs_fr11);
656 Clobber(rs_fr12);
657 Clobber(rs_fr13);
658 Clobber(rs_fr14);
659 Clobber(rs_fr15);
660 Clobber(rs_dr0);
661 Clobber(rs_dr1);
662 Clobber(rs_dr2);
663 Clobber(rs_dr3);
664 Clobber(rs_dr4);
665 Clobber(rs_dr5);
666 Clobber(rs_dr6);
667 Clobber(rs_dr7);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700668}
669
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700670RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700671 RegLocation res = LocCReturnWide();
buzbee091cc402014-03-31 10:14:40 -0700672 res.reg.SetLowReg(rs_r2.GetReg());
673 res.reg.SetHighReg(rs_r3.GetReg());
674 Clobber(rs_r2);
675 Clobber(rs_r3);
676 MarkInUse(rs_r2);
677 MarkInUse(rs_r3);
678 MarkWide(res.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700679 return res;
680}
681
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700682RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700683 RegLocation res = LocCReturn();
buzbee091cc402014-03-31 10:14:40 -0700684 res.reg.SetReg(rs_r1.GetReg());
685 Clobber(rs_r1);
686 MarkInUse(rs_r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700687 return res;
688}
689
Brian Carlstrom7940e442013-07-12 13:46:57 -0700690/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700691void ArmMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700692 LockTemp(rs_r0);
693 LockTemp(rs_r1);
694 LockTemp(rs_r2);
695 LockTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700696}
697
698/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700699void ArmMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700700 FreeTemp(rs_r0);
701 FreeTemp(rs_r1);
702 FreeTemp(rs_r2);
703 FreeTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700704}
705
Ian Rogersdd7624d2014-03-14 17:43:00 -0700706RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
buzbee2700f7e2014-03-07 09:46:20 -0800707 LoadWordDisp(rs_rARM_SELF, offset.Int32Value(), rs_rARM_LR);
708 return rs_rARM_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700709}
710
Andreas Gampe2f244e92014-05-08 03:35:25 -0700711RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<8> offset) {
712 UNIMPLEMENTED(FATAL) << "Should not be called.";
713 return RegStorage::InvalidReg();
714}
715
Dave Allisonb373e092014-02-20 16:06:36 -0800716LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800717 RegStorage tmp = rs_r0;
buzbee695d13a2014-04-19 13:32:20 -0700718 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
719 LIR* load2 = Load32Disp(tmp, 0, tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800720 return load2;
721}
722
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700723uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700724 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700725 return ArmMir2Lir::EncodingMap[opcode].flags;
726}
727
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700728const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700729 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700730 return ArmMir2Lir::EncodingMap[opcode].name;
731}
732
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700733const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700734 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700735 return ArmMir2Lir::EncodingMap[opcode].fmt;
736}
737
buzbee091cc402014-03-31 10:14:40 -0700738/*
739 * Somewhat messy code here. We want to allocate a pair of contiguous
740 * physical single-precision floating point registers starting with
741 * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
742 * has already been allocated - try to fit if possible. Fail to
743 * allocate if we can't meet the requirements for the pair of
744 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
745 */
746// TODO: needs rewrite to support non-backed 64-bit float regs.
747RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
748 RegStorage res;
749 int v_reg = mir_graph_->SRegToVReg(s_reg);
750 int p_map_idx = SRegToPMap(s_reg);
751 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
752 // Upper reg is already allocated. Can we fit?
753 int high_reg = promotion_map_[p_map_idx+1].FpReg;
754 if ((high_reg & 1) == 0) {
755 // High reg is even - fail.
756 return res; // Invalid.
757 }
758 // Is the low reg of the pair free?
759 // FIXME: rework.
760 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
761 if (p->InUse() || p->IsTemp()) {
762 // Already allocated or not preserved - fail.
763 return res; // Invalid.
764 }
765 // OK - good to go.
766 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
767 p->MarkInUse();
768 MarkPreservedSingle(v_reg, p->GetReg());
769 } else {
770 /*
771 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
772 * different underlying physical registers.
773 */
774 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
775 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
776 if (!info->IsTemp() && !info->InUse()) {
777 res = info->GetReg();
778 info->MarkInUse();
779 MarkPreservedDouble(v_reg, info->GetReg());
780 break;
781 }
782 }
783 }
784 if (res.Valid()) {
buzbee85089dd2014-05-25 15:10:52 -0700785 RegisterInfo* info = GetRegInfo(res);
buzbee091cc402014-03-31 10:14:40 -0700786 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
buzbee85089dd2014-05-25 15:10:52 -0700787 promotion_map_[p_map_idx].FpReg =
788 info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700789 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
buzbee85089dd2014-05-25 15:10:52 -0700790 promotion_map_[p_map_idx+1].FpReg =
791 info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700792 }
793 return res;
794}
795
Brian Carlstrom7940e442013-07-12 13:46:57 -0700796} // namespace art