blob: d80ae3bc2359075298dcbc1b1ba9a68dc3e7902d [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
17#include <string>
18
19#include "arm_lir.h"
20#include "codegen_arm.h"
21#include "dex/compiler_internals.h"
22#include "dex/quick/mir_to_lir-inl.h"
23
24namespace art {
25
26static int core_regs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10,
27 r11, r12, rARM_SP, rARM_LR, rARM_PC};
28static int ReservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC};
29static int FpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
30 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
31 fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
32 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
33static int core_temps[] = {r0, r1, r2, r3, r12};
34static int fp_temps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
35 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
36
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070037RegLocation ArmMir2Lir::LocCReturn() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070038 RegLocation res = ARM_LOC_C_RETURN;
39 return res;
40}
41
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070042RegLocation ArmMir2Lir::LocCReturnWide() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070043 RegLocation res = ARM_LOC_C_RETURN_WIDE;
44 return res;
45}
46
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070047RegLocation ArmMir2Lir::LocCReturnFloat() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070048 RegLocation res = ARM_LOC_C_RETURN_FLOAT;
49 return res;
50}
51
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070052RegLocation ArmMir2Lir::LocCReturnDouble() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070053 RegLocation res = ARM_LOC_C_RETURN_DOUBLE;
54 return res;
55}
56
57// Return a target-dependent special register.
58int ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
59 int res = INVALID_REG;
60 switch (reg) {
61 case kSelf: res = rARM_SELF; break;
62 case kSuspend: res = rARM_SUSPEND; break;
63 case kLr: res = rARM_LR; break;
64 case kPc: res = rARM_PC; break;
65 case kSp: res = rARM_SP; break;
66 case kArg0: res = rARM_ARG0; break;
67 case kArg1: res = rARM_ARG1; break;
68 case kArg2: res = rARM_ARG2; break;
69 case kArg3: res = rARM_ARG3; break;
70 case kFArg0: res = rARM_FARG0; break;
71 case kFArg1: res = rARM_FARG1; break;
72 case kFArg2: res = rARM_FARG2; break;
73 case kFArg3: res = rARM_FARG3; break;
74 case kRet0: res = rARM_RET0; break;
75 case kRet1: res = rARM_RET1; break;
76 case kInvokeTgt: res = rARM_INVOKE_TGT; break;
Jeff Hao88474b42013-10-23 16:24:40 -070077 case kHiddenArg: res = r12; break;
78 case kHiddenFpArg: res = INVALID_REG; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -070079 case kCount: res = rARM_COUNT; break;
80 }
81 return res;
82}
83
84
85// Create a double from a pair of singles.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070086int ArmMir2Lir::S2d(int low_reg, int high_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070087 return ARM_S2D(low_reg, high_reg);
88}
89
90// Return mask to strip off fp reg flags and bias.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070091uint32_t ArmMir2Lir::FpRegMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070092 return ARM_FP_REG_MASK;
93}
94
95// True if both regs single, both core or both double.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070096bool ArmMir2Lir::SameRegType(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070097 return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2));
98}
99
100/*
101 * Decode the register id.
102 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700103uint64_t ArmMir2Lir::GetRegMaskCommon(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700104 uint64_t seed;
105 int shift;
106 int reg_id;
107
108
109 reg_id = reg & 0x1f;
110 /* Each double register is equal to a pair of single-precision FP registers */
111 seed = ARM_DOUBLEREG(reg) ? 3 : 1;
112 /* FP register starts at bit position 16 */
113 shift = ARM_FPREG(reg) ? kArmFPReg0 : 0;
114 /* Expand the double register id into single offset */
115 shift += reg_id;
116 return (seed << shift);
117}
118
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700119uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700120 return ENCODE_ARM_REG_PC;
121}
122
buzbeeb48819d2013-09-14 16:15:25 -0700123// Thumb2 specific setup. TODO: inline?:
124void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700125 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700126 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700127
Brian Carlstrom7940e442013-07-12 13:46:57 -0700128 int opcode = lir->opcode;
129
buzbeeb48819d2013-09-14 16:15:25 -0700130 // These flags are somewhat uncommon - bypass if we can.
131 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
132 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
133 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
134 if (flags & REG_DEF_SP) {
135 lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700136 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700137
buzbeeb48819d2013-09-14 16:15:25 -0700138 if (flags & REG_USE_SP) {
139 lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700140 }
buzbeeb48819d2013-09-14 16:15:25 -0700141
142 if (flags & REG_DEF_LIST0) {
143 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700144 }
buzbeeb48819d2013-09-14 16:15:25 -0700145
146 if (flags & REG_DEF_LIST1) {
147 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
148 }
149
150 if (flags & REG_DEF_FPCS_LIST0) {
151 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
152 }
153
154 if (flags & REG_DEF_FPCS_LIST2) {
155 for (int i = 0; i < lir->operands[2]; i++) {
156 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
157 }
158 }
159
160 if (flags & REG_USE_PC) {
161 lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
162 }
163
164 /* Conservatively treat the IT block */
165 if (flags & IS_IT) {
166 lir->u.m.def_mask = ENCODE_ALL;
167 }
168
169 if (flags & REG_USE_LIST0) {
170 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
171 }
172
173 if (flags & REG_USE_LIST1) {
174 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
175 }
176
177 if (flags & REG_USE_FPCS_LIST0) {
178 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
179 }
180
181 if (flags & REG_USE_FPCS_LIST2) {
182 for (int i = 0; i < lir->operands[2]; i++) {
183 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
184 }
185 }
186 /* Fixup for kThumbPush/lr and kThumbPop/pc */
187 if (opcode == kThumbPush || opcode == kThumbPop) {
188 uint64_t r8Mask = GetRegMaskCommon(r8);
189 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
190 lir->u.m.use_mask &= ~r8Mask;
191 lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
192 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
193 lir->u.m.def_mask &= ~r8Mask;
194 lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
195 }
196 }
197 if (flags & REG_DEF_LR) {
198 lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
199 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700200 }
201}
202
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700203ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700204 ArmConditionCode res;
205 switch (ccode) {
206 case kCondEq: res = kArmCondEq; break;
207 case kCondNe: res = kArmCondNe; break;
208 case kCondCs: res = kArmCondCs; break;
209 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000210 case kCondUlt: res = kArmCondCc; break;
211 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700212 case kCondMi: res = kArmCondMi; break;
213 case kCondPl: res = kArmCondPl; break;
214 case kCondVs: res = kArmCondVs; break;
215 case kCondVc: res = kArmCondVc; break;
216 case kCondHi: res = kArmCondHi; break;
217 case kCondLs: res = kArmCondLs; break;
218 case kCondGe: res = kArmCondGe; break;
219 case kCondLt: res = kArmCondLt; break;
220 case kCondGt: res = kArmCondGt; break;
221 case kCondLe: res = kArmCondLe; break;
222 case kCondAl: res = kArmCondAl; break;
223 case kCondNv: res = kArmCondNv; break;
224 default:
225 LOG(FATAL) << "Bad condition code " << ccode;
226 res = static_cast<ArmConditionCode>(0); // Quiet gcc
227 }
228 return res;
229}
230
231static const char* core_reg_names[16] = {
232 "r0",
233 "r1",
234 "r2",
235 "r3",
236 "r4",
237 "r5",
238 "r6",
239 "r7",
240 "r8",
241 "rSELF",
242 "r10",
243 "r11",
244 "r12",
245 "sp",
246 "lr",
247 "pc",
248};
249
250
251static const char* shift_names[4] = {
252 "lsl",
253 "lsr",
254 "asr",
255 "ror"};
256
257/* Decode and print a ARM register name */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700258static char* DecodeRegList(int opcode, int vector, char* buf) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700259 int i;
260 bool printed = false;
261 buf[0] = 0;
262 for (i = 0; i < 16; i++, vector >>= 1) {
263 if (vector & 0x1) {
264 int reg_id = i;
265 if (opcode == kThumbPush && i == 8) {
266 reg_id = r14lr;
267 } else if (opcode == kThumbPop && i == 8) {
268 reg_id = r15pc;
269 }
270 if (printed) {
271 sprintf(buf + strlen(buf), ", r%d", reg_id);
272 } else {
273 printed = true;
274 sprintf(buf, "r%d", reg_id);
275 }
276 }
277 }
278 return buf;
279}
280
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700281static char* DecodeFPCSRegList(int count, int base, char* buf) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700282 sprintf(buf, "s%d", base);
283 for (int i = 1; i < count; i++) {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700284 sprintf(buf + strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700285 }
286 return buf;
287}
288
buzbee0d829482013-10-11 15:24:55 -0700289static int32_t ExpandImmediate(int value) {
290 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700291 uint32_t bits = value & 0xff;
292 switch (mode) {
293 case 0:
294 return bits;
295 case 1:
296 return (bits << 16) | bits;
297 case 2:
298 return (bits << 24) | (bits << 8);
299 case 3:
300 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
301 default:
302 break;
303 }
304 bits = (bits | 0x80) << 24;
305 return bits >> (((value & 0xf80) >> 7) - 8);
306}
307
Brian Carlstromb1eba212013-07-17 18:07:19 -0700308const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
309 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700310/*
311 * Interpret a format string and build a string no longer than size
312 * See format key in Assemble.c.
313 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700314std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700315 std::string buf;
316 int i;
317 const char* fmt_end = &fmt[strlen(fmt)];
318 char tbuf[256];
319 const char* name;
320 char nc;
321 while (fmt < fmt_end) {
322 int operand;
323 if (*fmt == '!') {
324 fmt++;
325 DCHECK_LT(fmt, fmt_end);
326 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700327 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700328 strcpy(tbuf, "!");
329 } else {
330 DCHECK_LT(fmt, fmt_end);
331 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
332 operand = lir->operands[nc-'0'];
333 switch (*fmt++) {
334 case 'H':
335 if (operand != 0) {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700336 sprintf(tbuf, ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700337 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700338 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700339 }
340 break;
341 case 'B':
342 switch (operand) {
343 case kSY:
344 name = "sy";
345 break;
346 case kST:
347 name = "st";
348 break;
349 case kISH:
350 name = "ish";
351 break;
352 case kISHST:
353 name = "ishst";
354 break;
355 case kNSH:
356 name = "nsh";
357 break;
358 case kNSHST:
359 name = "shst";
360 break;
361 default:
362 name = "DecodeError2";
363 break;
364 }
365 strcpy(tbuf, name);
366 break;
367 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700368 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700369 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700370 tbuf[i] += operand & 1;
371 operand >>= 1;
372 }
373 break;
374 case 'n':
375 operand = ~ExpandImmediate(operand);
Brian Carlstromb1eba212013-07-17 18:07:19 -0700376 sprintf(tbuf, "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700377 break;
378 case 'm':
379 operand = ExpandImmediate(operand);
Brian Carlstromb1eba212013-07-17 18:07:19 -0700380 sprintf(tbuf, "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700381 break;
382 case 's':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700383 sprintf(tbuf, "s%d", operand & ARM_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700384 break;
385 case 'S':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700386 sprintf(tbuf, "d%d", (operand & ARM_FP_REG_MASK) >> 1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700387 break;
388 case 'h':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700389 sprintf(tbuf, "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700390 break;
391 case 'M':
392 case 'd':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700393 sprintf(tbuf, "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700394 break;
395 case 'C':
396 DCHECK_LT(operand, static_cast<int>(
397 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Brian Carlstromb1eba212013-07-17 18:07:19 -0700398 sprintf(tbuf, "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700399 break;
400 case 'E':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700401 sprintf(tbuf, "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700402 break;
403 case 'F':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700404 sprintf(tbuf, "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700405 break;
406 case 'c':
407 strcpy(tbuf, cc_names[operand]);
408 break;
409 case 't':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700410 sprintf(tbuf, "0x%08x (L%p)",
Brian Carlstrom7940e442013-07-12 13:46:57 -0700411 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 +
412 (operand << 1),
413 lir->target);
414 break;
415 case 'u': {
416 int offset_1 = lir->operands[0];
417 int offset_2 = NEXT_LIR(lir)->operands[0];
418 uintptr_t target =
419 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
420 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
421 0xfffffffc;
422 sprintf(tbuf, "%p", reinterpret_cast<void *>(target));
423 break;
424 }
425
426 /* Nothing to print for BLX_2 */
427 case 'v':
428 strcpy(tbuf, "see above");
429 break;
430 case 'R':
431 DecodeRegList(lir->opcode, operand, tbuf);
432 break;
433 case 'P':
434 DecodeFPCSRegList(operand, 16, tbuf);
435 break;
436 case 'Q':
437 DecodeFPCSRegList(operand, 0, tbuf);
438 break;
439 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700440 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700441 break;
442 }
443 buf += tbuf;
444 }
445 } else {
446 buf += *fmt++;
447 }
448 }
449 return buf;
450}
451
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700452void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700453 char buf[256];
454 buf[0] = 0;
455
456 if (mask == ENCODE_ALL) {
457 strcpy(buf, "all");
458 } else {
459 char num[8];
460 int i;
461
462 for (i = 0; i < kArmRegEnd; i++) {
463 if (mask & (1ULL << i)) {
464 sprintf(num, "%d ", i);
465 strcat(buf, num);
466 }
467 }
468
469 if (mask & ENCODE_CCODE) {
470 strcat(buf, "cc ");
471 }
472 if (mask & ENCODE_FP_STATUS) {
473 strcat(buf, "fpcc ");
474 }
475
476 /* Memory bits */
477 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
buzbeeb48819d2013-09-14 16:15:25 -0700478 sprintf(buf + strlen(buf), "dr%d%s", DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
479 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700480 }
481 if (mask & ENCODE_LITERAL) {
482 strcat(buf, "lit ");
483 }
484
485 if (mask & ENCODE_HEAP_REF) {
486 strcat(buf, "heap ");
487 }
488 if (mask & ENCODE_MUST_NOT_ALIAS) {
489 strcat(buf, "noalias ");
490 }
491 }
492 if (buf[0]) {
493 LOG(INFO) << prefix << ": " << buf;
494 }
495}
496
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700497bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700498 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
499}
500
501ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
502 : Mir2Lir(cu, mir_graph, arena) {
503 // Sanity check - make sure encoding map lines up.
504 for (int i = 0; i < kArmLast; i++) {
505 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
506 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
507 << " is wrong: expecting " << i << ", seeing "
508 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
509 }
510 }
511}
512
513Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
514 ArenaAllocator* const arena) {
515 return new ArmMir2Lir(cu, mir_graph, arena);
516}
517
518/*
519 * Alloc a pair of core registers, or a double. Low reg in low byte,
520 * high reg in next byte.
521 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700522int ArmMir2Lir::AllocTypedTempPair(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700523 int high_reg;
524 int low_reg;
525 int res = 0;
526
527 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
528 low_reg = AllocTempDouble();
529 high_reg = low_reg + 1;
530 } else {
531 low_reg = AllocTemp();
532 high_reg = AllocTemp();
533 }
534 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
535 return res;
536}
537
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700538int ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700539 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
540 return AllocTempFloat();
541 return AllocTemp();
542}
543
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700544void ArmMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700545 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
546 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
547 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
548 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
549 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700550 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
551 ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700552 reg_pool_->num_core_regs = num_regs;
553 reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700554 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700555 reg_pool_->num_fp_regs = num_fp_regs;
556 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700557 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700558 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
559 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
560 // Keep special registers from being allocated
561 for (int i = 0; i < num_reserved; i++) {
562 if (NO_SUSPEND && (ReservedRegs[i] == rARM_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700563 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700564 continue;
565 }
566 MarkInUse(ReservedRegs[i]);
567 }
568 // Mark temp regs - all others not in use can be used for promotion
569 for (int i = 0; i < num_temps; i++) {
570 MarkTemp(core_temps[i]);
571 }
572 for (int i = 0; i < num_fp_temps; i++) {
573 MarkTemp(fp_temps[i]);
574 }
575
576 // Start allocation at r2 in an attempt to avoid clobbering return values
577 reg_pool_->next_core_reg = r2;
578}
579
580void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700581 RegLocation rl_free) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700582 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
583 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
584 // No overlap, free both
585 FreeTemp(rl_free.low_reg);
586 FreeTemp(rl_free.high_reg);
587 }
588}
589/*
590 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
591 * instructions might call out to C/assembly helper functions. Until
592 * machinery is in place, always spill lr.
593 */
594
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700595void ArmMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700596 core_spill_mask_ |= (1 << rARM_LR);
597 num_core_spills_++;
598}
599
600/*
601 * Mark a callee-save fp register as promoted. Note that
602 * vpush/vpop uses contiguous register lists so we must
603 * include any holes in the mask. Associate holes with
604 * Dalvik register INVALID_VREG (0xFFFFU).
605 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700606void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700607 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
608 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
609 // Ensure fp_vmap_table is large enough
610 int table_size = fp_vmap_table_.size();
611 for (int i = table_size; i < (reg + 1); i++) {
612 fp_vmap_table_.push_back(INVALID_VREG);
613 }
614 // Add the current mapping
615 fp_vmap_table_[reg] = v_reg;
616 // Size of fp_vmap_table is high-water mark, use to set mask
617 num_fp_spills_ = fp_vmap_table_.size();
618 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
619}
620
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700621void ArmMir2Lir::FlushRegWide(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700622 RegisterInfo* info1 = GetRegInfo(reg1);
623 RegisterInfo* info2 = GetRegInfo(reg2);
624 DCHECK(info1 && info2 && info1->pair && info2->pair &&
625 (info1->partner == info2->reg) &&
626 (info2->partner == info1->reg));
627 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
628 if (!(info1->is_temp && info2->is_temp)) {
629 /* Should not happen. If it does, there's a problem in eval_loc */
630 LOG(FATAL) << "Long half-temp, half-promoted";
631 }
632
633 info1->dirty = false;
634 info2->dirty = false;
635 if (mir_graph_->SRegToVReg(info2->s_reg) <
636 mir_graph_->SRegToVReg(info1->s_reg))
637 info1 = info2;
638 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
639 StoreBaseDispWide(rARM_SP, VRegOffset(v_reg), info1->reg, info1->partner);
640 }
641}
642
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700643void ArmMir2Lir::FlushReg(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700644 RegisterInfo* info = GetRegInfo(reg);
645 if (info->live && info->dirty) {
646 info->dirty = false;
647 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
648 StoreBaseDisp(rARM_SP, VRegOffset(v_reg), reg, kWord);
649 }
650}
651
652/* Give access to the target-dependent FP register encoding to common code */
653bool ArmMir2Lir::IsFpReg(int reg) {
654 return ARM_FPREG(reg);
655}
656
657/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000658void ArmMir2Lir::ClobberCallerSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700659 Clobber(r0);
660 Clobber(r1);
661 Clobber(r2);
662 Clobber(r3);
663 Clobber(r12);
664 Clobber(r14lr);
665 Clobber(fr0);
666 Clobber(fr1);
667 Clobber(fr2);
668 Clobber(fr3);
669 Clobber(fr4);
670 Clobber(fr5);
671 Clobber(fr6);
672 Clobber(fr7);
673 Clobber(fr8);
674 Clobber(fr9);
675 Clobber(fr10);
676 Clobber(fr11);
677 Clobber(fr12);
678 Clobber(fr13);
679 Clobber(fr14);
680 Clobber(fr15);
681}
682
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700683RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700684 RegLocation res = LocCReturnWide();
685 res.low_reg = r2;
686 res.high_reg = r3;
687 Clobber(r2);
688 Clobber(r3);
689 MarkInUse(r2);
690 MarkInUse(r3);
691 MarkPair(res.low_reg, res.high_reg);
692 return res;
693}
694
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700695RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700696 RegLocation res = LocCReturn();
697 res.low_reg = r1;
698 Clobber(r1);
699 MarkInUse(r1);
700 return res;
701}
702
Brian Carlstrom7940e442013-07-12 13:46:57 -0700703/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700704void ArmMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700705 LockTemp(r0);
706 LockTemp(r1);
707 LockTemp(r2);
708 LockTemp(r3);
709}
710
711/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700712void ArmMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700713 FreeTemp(r0);
714 FreeTemp(r1);
715 FreeTemp(r2);
716 FreeTemp(r3);
717}
718
Ian Rogers468532e2013-08-05 10:56:33 -0700719int ArmMir2Lir::LoadHelper(ThreadOffset offset) {
720 LoadWordDisp(rARM_SELF, offset.Int32Value(), rARM_LR);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700721 return rARM_LR;
722}
723
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700724uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700725 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700726 return ArmMir2Lir::EncodingMap[opcode].flags;
727}
728
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700729const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700730 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700731 return ArmMir2Lir::EncodingMap[opcode].name;
732}
733
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700734const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700735 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700736 return ArmMir2Lir::EncodingMap[opcode].fmt;
737}
738
739} // namespace art