blob: 5e9a8b0b5cec8e18d6dc7b1cd10324eed7366c02 [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
28static int core_regs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10,
29 r11, r12, rARM_SP, rARM_LR, rARM_PC};
30static int ReservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC};
31static int FpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
32 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
33 fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
34 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
35static int core_temps[] = {r0, r1, r2, r3, r12};
36static int fp_temps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
37 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
38
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070039RegLocation ArmMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000040 return arm_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070041}
42
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070043RegLocation ArmMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000044 return arm_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070045}
46
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070047RegLocation ArmMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000048 return arm_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070049}
50
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070051RegLocation ArmMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000052 return arm_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070053}
54
55// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080056RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
57 int res_reg = RegStorage::kInvalidRegVal;
Brian Carlstrom7940e442013-07-12 13:46:57 -070058 switch (reg) {
buzbee2700f7e2014-03-07 09:46:20 -080059 case kSelf: res_reg = rARM_SELF; break;
60 case kSuspend: res_reg = rARM_SUSPEND; break;
61 case kLr: res_reg = rARM_LR; break;
62 case kPc: res_reg = rARM_PC; break;
63 case kSp: res_reg = rARM_SP; break;
64 case kArg0: res_reg = rARM_ARG0; break;
65 case kArg1: res_reg = rARM_ARG1; break;
66 case kArg2: res_reg = rARM_ARG2; break;
67 case kArg3: res_reg = rARM_ARG3; break;
68 case kFArg0: res_reg = rARM_FARG0; break;
69 case kFArg1: res_reg = rARM_FARG1; break;
70 case kFArg2: res_reg = rARM_FARG2; break;
71 case kFArg3: res_reg = rARM_FARG3; break;
72 case kRet0: res_reg = rARM_RET0; break;
73 case kRet1: res_reg = rARM_RET1; break;
74 case kInvokeTgt: res_reg = rARM_INVOKE_TGT; break;
75 case kHiddenArg: res_reg = r12; break;
76 case kHiddenFpArg: res_reg = RegStorage::kInvalidRegVal; break;
77 case kCount: res_reg = rARM_COUNT; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -070078 }
buzbee2700f7e2014-03-07 09:46:20 -080079 return RegStorage::Solo32(res_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -070080}
81
buzbee2700f7e2014-03-07 09:46:20 -080082RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080083 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
84 switch (arg_num) {
85 case 0:
buzbee2700f7e2014-03-07 09:46:20 -080086 return rs_rARM_ARG1;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080087 case 1:
buzbee2700f7e2014-03-07 09:46:20 -080088 return rs_rARM_ARG2;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080089 case 2:
buzbee2700f7e2014-03-07 09:46:20 -080090 return rs_rARM_ARG3;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080091 default:
buzbee2700f7e2014-03-07 09:46:20 -080092 return RegStorage::InvalidReg();
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080093 }
94}
Brian Carlstrom7940e442013-07-12 13:46:57 -070095
96// Create a double from a pair of singles.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070097int ArmMir2Lir::S2d(int low_reg, int high_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070098 return ARM_S2D(low_reg, high_reg);
99}
100
101// Return mask to strip off fp reg flags and bias.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700102uint32_t ArmMir2Lir::FpRegMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700103 return ARM_FP_REG_MASK;
104}
105
106// True if both regs single, both core or both double.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700107bool ArmMir2Lir::SameRegType(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700108 return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2));
109}
110
111/*
112 * Decode the register id.
113 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700114uint64_t ArmMir2Lir::GetRegMaskCommon(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700115 uint64_t seed;
116 int shift;
117 int reg_id;
118
119
120 reg_id = reg & 0x1f;
121 /* Each double register is equal to a pair of single-precision FP registers */
122 seed = ARM_DOUBLEREG(reg) ? 3 : 1;
123 /* FP register starts at bit position 16 */
124 shift = ARM_FPREG(reg) ? kArmFPReg0 : 0;
125 /* Expand the double register id into single offset */
126 shift += reg_id;
127 return (seed << shift);
128}
129
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700130uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700131 return ENCODE_ARM_REG_PC;
132}
133
buzbeeb48819d2013-09-14 16:15:25 -0700134// Thumb2 specific setup. TODO: inline?:
135void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700136 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700137 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700138
Brian Carlstrom7940e442013-07-12 13:46:57 -0700139 int opcode = lir->opcode;
140
buzbeeb48819d2013-09-14 16:15:25 -0700141 // These flags are somewhat uncommon - bypass if we can.
142 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
143 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
144 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
145 if (flags & REG_DEF_SP) {
146 lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700147 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700148
buzbeeb48819d2013-09-14 16:15:25 -0700149 if (flags & REG_USE_SP) {
150 lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700151 }
buzbeeb48819d2013-09-14 16:15:25 -0700152
153 if (flags & REG_DEF_LIST0) {
154 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700155 }
buzbeeb48819d2013-09-14 16:15:25 -0700156
157 if (flags & REG_DEF_LIST1) {
158 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
159 }
160
161 if (flags & REG_DEF_FPCS_LIST0) {
162 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
163 }
164
165 if (flags & REG_DEF_FPCS_LIST2) {
166 for (int i = 0; i < lir->operands[2]; i++) {
167 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
168 }
169 }
170
171 if (flags & REG_USE_PC) {
172 lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
173 }
174
175 /* Conservatively treat the IT block */
176 if (flags & IS_IT) {
177 lir->u.m.def_mask = ENCODE_ALL;
178 }
179
180 if (flags & REG_USE_LIST0) {
181 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
182 }
183
184 if (flags & REG_USE_LIST1) {
185 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
186 }
187
188 if (flags & REG_USE_FPCS_LIST0) {
189 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
190 }
191
192 if (flags & REG_USE_FPCS_LIST2) {
193 for (int i = 0; i < lir->operands[2]; i++) {
194 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
195 }
196 }
197 /* Fixup for kThumbPush/lr and kThumbPop/pc */
198 if (opcode == kThumbPush || opcode == kThumbPop) {
199 uint64_t r8Mask = GetRegMaskCommon(r8);
200 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
201 lir->u.m.use_mask &= ~r8Mask;
202 lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
203 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
204 lir->u.m.def_mask &= ~r8Mask;
205 lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
206 }
207 }
208 if (flags & REG_DEF_LR) {
209 lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
210 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700211 }
212}
213
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700214ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700215 ArmConditionCode res;
216 switch (ccode) {
217 case kCondEq: res = kArmCondEq; break;
218 case kCondNe: res = kArmCondNe; break;
219 case kCondCs: res = kArmCondCs; break;
220 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000221 case kCondUlt: res = kArmCondCc; break;
222 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700223 case kCondMi: res = kArmCondMi; break;
224 case kCondPl: res = kArmCondPl; break;
225 case kCondVs: res = kArmCondVs; break;
226 case kCondVc: res = kArmCondVc; break;
227 case kCondHi: res = kArmCondHi; break;
228 case kCondLs: res = kArmCondLs; break;
229 case kCondGe: res = kArmCondGe; break;
230 case kCondLt: res = kArmCondLt; break;
231 case kCondGt: res = kArmCondGt; break;
232 case kCondLe: res = kArmCondLe; break;
233 case kCondAl: res = kArmCondAl; break;
234 case kCondNv: res = kArmCondNv; break;
235 default:
236 LOG(FATAL) << "Bad condition code " << ccode;
237 res = static_cast<ArmConditionCode>(0); // Quiet gcc
238 }
239 return res;
240}
241
242static const char* core_reg_names[16] = {
243 "r0",
244 "r1",
245 "r2",
246 "r3",
247 "r4",
248 "r5",
249 "r6",
250 "r7",
251 "r8",
252 "rSELF",
253 "r10",
254 "r11",
255 "r12",
256 "sp",
257 "lr",
258 "pc",
259};
260
261
262static const char* shift_names[4] = {
263 "lsl",
264 "lsr",
265 "asr",
266 "ror"};
267
268/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800269static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700270 int i;
271 bool printed = false;
272 buf[0] = 0;
273 for (i = 0; i < 16; i++, vector >>= 1) {
274 if (vector & 0x1) {
275 int reg_id = i;
276 if (opcode == kThumbPush && i == 8) {
277 reg_id = r14lr;
278 } else if (opcode == kThumbPop && i == 8) {
279 reg_id = r15pc;
280 }
281 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800282 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700283 } else {
284 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800285 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700286 }
287 }
288 }
289 return buf;
290}
291
Ian Rogers988e6ea2014-01-08 11:30:50 -0800292static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
293 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700294 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800295 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700296 }
297 return buf;
298}
299
buzbee0d829482013-10-11 15:24:55 -0700300static int32_t ExpandImmediate(int value) {
301 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700302 uint32_t bits = value & 0xff;
303 switch (mode) {
304 case 0:
305 return bits;
306 case 1:
307 return (bits << 16) | bits;
308 case 2:
309 return (bits << 24) | (bits << 8);
310 case 3:
311 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
312 default:
313 break;
314 }
315 bits = (bits | 0x80) << 24;
316 return bits >> (((value & 0xf80) >> 7) - 8);
317}
318
Brian Carlstromb1eba212013-07-17 18:07:19 -0700319const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
320 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700321/*
322 * Interpret a format string and build a string no longer than size
323 * See format key in Assemble.c.
324 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700325std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700326 std::string buf;
327 int i;
328 const char* fmt_end = &fmt[strlen(fmt)];
329 char tbuf[256];
330 const char* name;
331 char nc;
332 while (fmt < fmt_end) {
333 int operand;
334 if (*fmt == '!') {
335 fmt++;
336 DCHECK_LT(fmt, fmt_end);
337 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700338 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700339 strcpy(tbuf, "!");
340 } else {
341 DCHECK_LT(fmt, fmt_end);
342 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
343 operand = lir->operands[nc-'0'];
344 switch (*fmt++) {
345 case 'H':
346 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800347 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700348 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700349 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700350 }
351 break;
352 case 'B':
353 switch (operand) {
354 case kSY:
355 name = "sy";
356 break;
357 case kST:
358 name = "st";
359 break;
360 case kISH:
361 name = "ish";
362 break;
363 case kISHST:
364 name = "ishst";
365 break;
366 case kNSH:
367 name = "nsh";
368 break;
369 case kNSHST:
370 name = "shst";
371 break;
372 default:
373 name = "DecodeError2";
374 break;
375 }
376 strcpy(tbuf, name);
377 break;
378 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700379 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700380 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700381 tbuf[i] += operand & 1;
382 operand >>= 1;
383 }
384 break;
385 case 'n':
386 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800387 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700388 break;
389 case 'm':
390 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800391 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700392 break;
393 case 's':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800394 snprintf(tbuf, arraysize(tbuf), "s%d", operand & ARM_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700395 break;
396 case 'S':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800397 snprintf(tbuf, arraysize(tbuf), "d%d", (operand & ARM_FP_REG_MASK) >> 1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700398 break;
399 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800400 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700401 break;
402 case 'M':
403 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800404 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700405 break;
406 case 'C':
407 DCHECK_LT(operand, static_cast<int>(
408 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800409 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700410 break;
411 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800412 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700413 break;
414 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800415 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700416 break;
417 case 'c':
418 strcpy(tbuf, cc_names[operand]);
419 break;
420 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800421 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
422 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700423 lir->target);
424 break;
425 case 'u': {
426 int offset_1 = lir->operands[0];
427 int offset_2 = NEXT_LIR(lir)->operands[0];
428 uintptr_t target =
429 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
430 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
431 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800432 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433 break;
434 }
435
436 /* Nothing to print for BLX_2 */
437 case 'v':
438 strcpy(tbuf, "see above");
439 break;
440 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800441 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700442 break;
443 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800444 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700445 break;
446 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800447 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700448 break;
449 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700450 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700451 break;
452 }
453 buf += tbuf;
454 }
455 } else {
456 buf += *fmt++;
457 }
458 }
459 return buf;
460}
461
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700462void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700463 char buf[256];
464 buf[0] = 0;
465
466 if (mask == ENCODE_ALL) {
467 strcpy(buf, "all");
468 } else {
469 char num[8];
470 int i;
471
472 for (i = 0; i < kArmRegEnd; i++) {
473 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800474 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700475 strcat(buf, num);
476 }
477 }
478
479 if (mask & ENCODE_CCODE) {
480 strcat(buf, "cc ");
481 }
482 if (mask & ENCODE_FP_STATUS) {
483 strcat(buf, "fpcc ");
484 }
485
486 /* Memory bits */
487 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800488 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
489 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
490 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700491 }
492 if (mask & ENCODE_LITERAL) {
493 strcat(buf, "lit ");
494 }
495
496 if (mask & ENCODE_HEAP_REF) {
497 strcat(buf, "heap ");
498 }
499 if (mask & ENCODE_MUST_NOT_ALIAS) {
500 strcat(buf, "noalias ");
501 }
502 }
503 if (buf[0]) {
504 LOG(INFO) << prefix << ": " << buf;
505 }
506}
507
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700508bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700509 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
510}
511
512ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
513 : Mir2Lir(cu, mir_graph, arena) {
514 // Sanity check - make sure encoding map lines up.
515 for (int i = 0; i < kArmLast; i++) {
516 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
517 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
518 << " is wrong: expecting " << i << ", seeing "
519 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
520 }
521 }
522}
523
524Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
525 ArenaAllocator* const arena) {
526 return new ArmMir2Lir(cu, mir_graph, arena);
527}
528
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000529// Alloc a pair of core registers, or a double.
530RegStorage ArmMir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700531 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
buzbee2700f7e2014-03-07 09:46:20 -0800532 return AllocTempDouble();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700533 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800534 RegStorage low_reg = AllocTemp();
535 RegStorage high_reg = AllocTemp();
536 return RegStorage::MakeRegPair(low_reg, high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700537 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700538}
539
buzbee2700f7e2014-03-07 09:46:20 -0800540RegStorage ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700541 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
542 return AllocTempFloat();
543 return AllocTemp();
544}
545
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700546void ArmMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700547 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
548 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
549 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
550 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
551 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700552 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000553 kArenaAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700554 reg_pool_->num_core_regs = num_regs;
555 reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000556 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), kArenaAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700557 reg_pool_->num_fp_regs = num_fp_regs;
558 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000559 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), kArenaAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700560 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
561 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
Dave Allisonf6b65c12014-04-01 17:45:18 -0700562
Brian Carlstrom7940e442013-07-12 13:46:57 -0700563 // Keep special registers from being allocated
Dave Allisonf6b65c12014-04-01 17:45:18 -0700564 // Don't reserve the r4 if we are doing implicit suspend checks.
565 bool no_suspend = NO_SUSPEND || !Runtime::Current()->ExplicitSuspendChecks();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700566 for (int i = 0; i < num_reserved; i++) {
Dave Allisonf6b65c12014-04-01 17:45:18 -0700567 if (no_suspend && (ReservedRegs[i] == rARM_SUSPEND)) {
568 // Don't reserve the suspend register.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700569 continue;
570 }
571 MarkInUse(ReservedRegs[i]);
572 }
573 // Mark temp regs - all others not in use can be used for promotion
574 for (int i = 0; i < num_temps; i++) {
575 MarkTemp(core_temps[i]);
576 }
577 for (int i = 0; i < num_fp_temps; i++) {
578 MarkTemp(fp_temps[i]);
579 }
580
581 // Start allocation at r2 in an attempt to avoid clobbering return values
582 reg_pool_->next_core_reg = r2;
583}
584
buzbee2700f7e2014-03-07 09:46:20 -0800585void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
586 DCHECK(rl_keep.wide);
587 DCHECK(rl_free.wide);
588 if ((rl_free.reg.GetLowReg() != rl_keep.reg.GetLowReg()) &&
589 (rl_free.reg.GetLowReg() != rl_keep.reg.GetHighReg()) &&
590 (rl_free.reg.GetHighReg() != rl_keep.reg.GetLowReg()) &&
591 (rl_free.reg.GetHighReg() != rl_keep.reg.GetHighReg())) {
592 // No overlap, free.
593 FreeTemp(rl_free.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700594 }
595}
buzbee2700f7e2014-03-07 09:46:20 -0800596
Brian Carlstrom7940e442013-07-12 13:46:57 -0700597/*
598 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
599 * instructions might call out to C/assembly helper functions. Until
600 * machinery is in place, always spill lr.
601 */
602
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700603void ArmMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700604 core_spill_mask_ |= (1 << rARM_LR);
605 num_core_spills_++;
606}
607
608/*
609 * Mark a callee-save fp register as promoted. Note that
610 * vpush/vpop uses contiguous register lists so we must
611 * include any holes in the mask. Associate holes with
612 * Dalvik register INVALID_VREG (0xFFFFU).
613 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700614void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700615 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
616 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
617 // Ensure fp_vmap_table is large enough
618 int table_size = fp_vmap_table_.size();
619 for (int i = table_size; i < (reg + 1); i++) {
620 fp_vmap_table_.push_back(INVALID_VREG);
621 }
622 // Add the current mapping
623 fp_vmap_table_[reg] = v_reg;
624 // Size of fp_vmap_table is high-water mark, use to set mask
625 num_fp_spills_ = fp_vmap_table_.size();
626 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
627}
628
buzbee2700f7e2014-03-07 09:46:20 -0800629void ArmMir2Lir::FlushRegWide(RegStorage reg) {
630 RegisterInfo* info1 = GetRegInfo(reg.GetLowReg());
631 RegisterInfo* info2 = GetRegInfo(reg.GetHighReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700632 DCHECK(info1 && info2 && info1->pair && info2->pair &&
633 (info1->partner == info2->reg) &&
634 (info2->partner == info1->reg));
635 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
636 if (!(info1->is_temp && info2->is_temp)) {
637 /* Should not happen. If it does, there's a problem in eval_loc */
638 LOG(FATAL) << "Long half-temp, half-promoted";
639 }
640
641 info1->dirty = false;
642 info2->dirty = false;
643 if (mir_graph_->SRegToVReg(info2->s_reg) <
644 mir_graph_->SRegToVReg(info1->s_reg))
645 info1 = info2;
646 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
buzbee2700f7e2014-03-07 09:46:20 -0800647 StoreBaseDispWide(rs_rARM_SP, VRegOffset(v_reg),
648 RegStorage(RegStorage::k64BitPair, info1->reg, info1->partner));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700649 }
650}
651
buzbee2700f7e2014-03-07 09:46:20 -0800652void ArmMir2Lir::FlushReg(RegStorage reg) {
653 DCHECK(!reg.IsPair());
654 RegisterInfo* info = GetRegInfo(reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700655 if (info->live && info->dirty) {
656 info->dirty = false;
657 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
buzbee2700f7e2014-03-07 09:46:20 -0800658 StoreBaseDisp(rs_rARM_SP, VRegOffset(v_reg), reg, kWord);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700659 }
660}
661
662/* Give access to the target-dependent FP register encoding to common code */
663bool ArmMir2Lir::IsFpReg(int reg) {
664 return ARM_FPREG(reg);
665}
666
buzbee2700f7e2014-03-07 09:46:20 -0800667bool ArmMir2Lir::IsFpReg(RegStorage reg) {
668 return IsFpReg(reg.IsPair() ? reg.GetLowReg() : reg.GetReg());
669}
670
Brian Carlstrom7940e442013-07-12 13:46:57 -0700671/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000672void ArmMir2Lir::ClobberCallerSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700673 Clobber(r0);
674 Clobber(r1);
675 Clobber(r2);
676 Clobber(r3);
677 Clobber(r12);
678 Clobber(r14lr);
679 Clobber(fr0);
680 Clobber(fr1);
681 Clobber(fr2);
682 Clobber(fr3);
683 Clobber(fr4);
684 Clobber(fr5);
685 Clobber(fr6);
686 Clobber(fr7);
687 Clobber(fr8);
688 Clobber(fr9);
689 Clobber(fr10);
690 Clobber(fr11);
691 Clobber(fr12);
692 Clobber(fr13);
693 Clobber(fr14);
694 Clobber(fr15);
695}
696
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700697RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700698 RegLocation res = LocCReturnWide();
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000699 res.reg.SetReg(r2);
700 res.reg.SetHighReg(r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700701 Clobber(r2);
702 Clobber(r3);
703 MarkInUse(r2);
704 MarkInUse(r3);
buzbee2700f7e2014-03-07 09:46:20 -0800705 MarkPair(res.reg.GetLowReg(), res.reg.GetHighReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700706 return res;
707}
708
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700709RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700710 RegLocation res = LocCReturn();
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000711 res.reg.SetReg(r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700712 Clobber(r1);
713 MarkInUse(r1);
714 return res;
715}
716
Brian Carlstrom7940e442013-07-12 13:46:57 -0700717/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700718void ArmMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700719 LockTemp(r0);
720 LockTemp(r1);
721 LockTemp(r2);
722 LockTemp(r3);
723}
724
725/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700726void ArmMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700727 FreeTemp(r0);
728 FreeTemp(r1);
729 FreeTemp(r2);
730 FreeTemp(r3);
731}
732
Ian Rogersdd7624d2014-03-14 17:43:00 -0700733RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
buzbee2700f7e2014-03-07 09:46:20 -0800734 LoadWordDisp(rs_rARM_SELF, offset.Int32Value(), rs_rARM_LR);
735 return rs_rARM_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700736}
737
Dave Allisonb373e092014-02-20 16:06:36 -0800738LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800739 RegStorage tmp = rs_r0;
Ian Rogersdd7624d2014-03-14 17:43:00 -0700740 LoadWordDisp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800741 LIR* load2 = LoadWordDisp(tmp, 0, tmp);
742 return load2;
743}
744
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700745uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700746 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700747 return ArmMir2Lir::EncodingMap[opcode].flags;
748}
749
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700750const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700751 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700752 return ArmMir2Lir::EncodingMap[opcode].name;
753}
754
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700755const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700756 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700757 return ArmMir2Lir::EncodingMap[opcode].fmt;
758}
759
760} // namespace art