blob: 48c9af5a166a25525d7824e1b48527ca85be430e [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;
210 case kCondMi: res = kArmCondMi; break;
211 case kCondPl: res = kArmCondPl; break;
212 case kCondVs: res = kArmCondVs; break;
213 case kCondVc: res = kArmCondVc; break;
214 case kCondHi: res = kArmCondHi; break;
215 case kCondLs: res = kArmCondLs; break;
216 case kCondGe: res = kArmCondGe; break;
217 case kCondLt: res = kArmCondLt; break;
218 case kCondGt: res = kArmCondGt; break;
219 case kCondLe: res = kArmCondLe; break;
220 case kCondAl: res = kArmCondAl; break;
221 case kCondNv: res = kArmCondNv; break;
222 default:
223 LOG(FATAL) << "Bad condition code " << ccode;
224 res = static_cast<ArmConditionCode>(0); // Quiet gcc
225 }
226 return res;
227}
228
229static const char* core_reg_names[16] = {
230 "r0",
231 "r1",
232 "r2",
233 "r3",
234 "r4",
235 "r5",
236 "r6",
237 "r7",
238 "r8",
239 "rSELF",
240 "r10",
241 "r11",
242 "r12",
243 "sp",
244 "lr",
245 "pc",
246};
247
248
249static const char* shift_names[4] = {
250 "lsl",
251 "lsr",
252 "asr",
253 "ror"};
254
255/* Decode and print a ARM register name */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700256static char* DecodeRegList(int opcode, int vector, char* buf) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700257 int i;
258 bool printed = false;
259 buf[0] = 0;
260 for (i = 0; i < 16; i++, vector >>= 1) {
261 if (vector & 0x1) {
262 int reg_id = i;
263 if (opcode == kThumbPush && i == 8) {
264 reg_id = r14lr;
265 } else if (opcode == kThumbPop && i == 8) {
266 reg_id = r15pc;
267 }
268 if (printed) {
269 sprintf(buf + strlen(buf), ", r%d", reg_id);
270 } else {
271 printed = true;
272 sprintf(buf, "r%d", reg_id);
273 }
274 }
275 }
276 return buf;
277}
278
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700279static char* DecodeFPCSRegList(int count, int base, char* buf) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700280 sprintf(buf, "s%d", base);
281 for (int i = 1; i < count; i++) {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700282 sprintf(buf + strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700283 }
284 return buf;
285}
286
buzbee0d829482013-10-11 15:24:55 -0700287static int32_t ExpandImmediate(int value) {
288 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700289 uint32_t bits = value & 0xff;
290 switch (mode) {
291 case 0:
292 return bits;
293 case 1:
294 return (bits << 16) | bits;
295 case 2:
296 return (bits << 24) | (bits << 8);
297 case 3:
298 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
299 default:
300 break;
301 }
302 bits = (bits | 0x80) << 24;
303 return bits >> (((value & 0xf80) >> 7) - 8);
304}
305
Brian Carlstromb1eba212013-07-17 18:07:19 -0700306const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
307 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700308/*
309 * Interpret a format string and build a string no longer than size
310 * See format key in Assemble.c.
311 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700312std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700313 std::string buf;
314 int i;
315 const char* fmt_end = &fmt[strlen(fmt)];
316 char tbuf[256];
317 const char* name;
318 char nc;
319 while (fmt < fmt_end) {
320 int operand;
321 if (*fmt == '!') {
322 fmt++;
323 DCHECK_LT(fmt, fmt_end);
324 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700325 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700326 strcpy(tbuf, "!");
327 } else {
328 DCHECK_LT(fmt, fmt_end);
329 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
330 operand = lir->operands[nc-'0'];
331 switch (*fmt++) {
332 case 'H':
333 if (operand != 0) {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700334 sprintf(tbuf, ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700336 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700337 }
338 break;
339 case 'B':
340 switch (operand) {
341 case kSY:
342 name = "sy";
343 break;
344 case kST:
345 name = "st";
346 break;
347 case kISH:
348 name = "ish";
349 break;
350 case kISHST:
351 name = "ishst";
352 break;
353 case kNSH:
354 name = "nsh";
355 break;
356 case kNSHST:
357 name = "shst";
358 break;
359 default:
360 name = "DecodeError2";
361 break;
362 }
363 strcpy(tbuf, name);
364 break;
365 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700366 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700367 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700368 tbuf[i] += operand & 1;
369 operand >>= 1;
370 }
371 break;
372 case 'n':
373 operand = ~ExpandImmediate(operand);
Brian Carlstromb1eba212013-07-17 18:07:19 -0700374 sprintf(tbuf, "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700375 break;
376 case 'm':
377 operand = ExpandImmediate(operand);
Brian Carlstromb1eba212013-07-17 18:07:19 -0700378 sprintf(tbuf, "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700379 break;
380 case 's':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700381 sprintf(tbuf, "s%d", operand & ARM_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700382 break;
383 case 'S':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700384 sprintf(tbuf, "d%d", (operand & ARM_FP_REG_MASK) >> 1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700385 break;
386 case 'h':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700387 sprintf(tbuf, "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700388 break;
389 case 'M':
390 case 'd':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700391 sprintf(tbuf, "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700392 break;
393 case 'C':
394 DCHECK_LT(operand, static_cast<int>(
395 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Brian Carlstromb1eba212013-07-17 18:07:19 -0700396 sprintf(tbuf, "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700397 break;
398 case 'E':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700399 sprintf(tbuf, "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700400 break;
401 case 'F':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700402 sprintf(tbuf, "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700403 break;
404 case 'c':
405 strcpy(tbuf, cc_names[operand]);
406 break;
407 case 't':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700408 sprintf(tbuf, "0x%08x (L%p)",
Brian Carlstrom7940e442013-07-12 13:46:57 -0700409 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 +
410 (operand << 1),
411 lir->target);
412 break;
413 case 'u': {
414 int offset_1 = lir->operands[0];
415 int offset_2 = NEXT_LIR(lir)->operands[0];
416 uintptr_t target =
417 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
418 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
419 0xfffffffc;
420 sprintf(tbuf, "%p", reinterpret_cast<void *>(target));
421 break;
422 }
423
424 /* Nothing to print for BLX_2 */
425 case 'v':
426 strcpy(tbuf, "see above");
427 break;
428 case 'R':
429 DecodeRegList(lir->opcode, operand, tbuf);
430 break;
431 case 'P':
432 DecodeFPCSRegList(operand, 16, tbuf);
433 break;
434 case 'Q':
435 DecodeFPCSRegList(operand, 0, tbuf);
436 break;
437 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700438 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700439 break;
440 }
441 buf += tbuf;
442 }
443 } else {
444 buf += *fmt++;
445 }
446 }
447 return buf;
448}
449
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700450void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700451 char buf[256];
452 buf[0] = 0;
453
454 if (mask == ENCODE_ALL) {
455 strcpy(buf, "all");
456 } else {
457 char num[8];
458 int i;
459
460 for (i = 0; i < kArmRegEnd; i++) {
461 if (mask & (1ULL << i)) {
462 sprintf(num, "%d ", i);
463 strcat(buf, num);
464 }
465 }
466
467 if (mask & ENCODE_CCODE) {
468 strcat(buf, "cc ");
469 }
470 if (mask & ENCODE_FP_STATUS) {
471 strcat(buf, "fpcc ");
472 }
473
474 /* Memory bits */
475 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
buzbeeb48819d2013-09-14 16:15:25 -0700476 sprintf(buf + strlen(buf), "dr%d%s", DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
477 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700478 }
479 if (mask & ENCODE_LITERAL) {
480 strcat(buf, "lit ");
481 }
482
483 if (mask & ENCODE_HEAP_REF) {
484 strcat(buf, "heap ");
485 }
486 if (mask & ENCODE_MUST_NOT_ALIAS) {
487 strcat(buf, "noalias ");
488 }
489 }
490 if (buf[0]) {
491 LOG(INFO) << prefix << ": " << buf;
492 }
493}
494
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700495bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700496 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
497}
498
499ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
500 : Mir2Lir(cu, mir_graph, arena) {
501 // Sanity check - make sure encoding map lines up.
502 for (int i = 0; i < kArmLast; i++) {
503 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
504 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
505 << " is wrong: expecting " << i << ", seeing "
506 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
507 }
508 }
509}
510
511Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
512 ArenaAllocator* const arena) {
513 return new ArmMir2Lir(cu, mir_graph, arena);
514}
515
516/*
517 * Alloc a pair of core registers, or a double. Low reg in low byte,
518 * high reg in next byte.
519 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700520int ArmMir2Lir::AllocTypedTempPair(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700521 int high_reg;
522 int low_reg;
523 int res = 0;
524
525 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
526 low_reg = AllocTempDouble();
527 high_reg = low_reg + 1;
528 } else {
529 low_reg = AllocTemp();
530 high_reg = AllocTemp();
531 }
532 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
533 return res;
534}
535
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700536int ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700537 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
538 return AllocTempFloat();
539 return AllocTemp();
540}
541
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700542void ArmMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700543 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
544 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
545 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
546 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
547 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700548 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
549 ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700550 reg_pool_->num_core_regs = num_regs;
551 reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700552 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700553 reg_pool_->num_fp_regs = num_fp_regs;
554 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700555 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700556 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
557 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
558 // Keep special registers from being allocated
559 for (int i = 0; i < num_reserved; i++) {
560 if (NO_SUSPEND && (ReservedRegs[i] == rARM_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700561 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700562 continue;
563 }
564 MarkInUse(ReservedRegs[i]);
565 }
566 // Mark temp regs - all others not in use can be used for promotion
567 for (int i = 0; i < num_temps; i++) {
568 MarkTemp(core_temps[i]);
569 }
570 for (int i = 0; i < num_fp_temps; i++) {
571 MarkTemp(fp_temps[i]);
572 }
573
574 // Start allocation at r2 in an attempt to avoid clobbering return values
575 reg_pool_->next_core_reg = r2;
576}
577
578void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700579 RegLocation rl_free) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700580 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
581 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
582 // No overlap, free both
583 FreeTemp(rl_free.low_reg);
584 FreeTemp(rl_free.high_reg);
585 }
586}
587/*
588 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
589 * instructions might call out to C/assembly helper functions. Until
590 * machinery is in place, always spill lr.
591 */
592
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700593void ArmMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700594 core_spill_mask_ |= (1 << rARM_LR);
595 num_core_spills_++;
596}
597
598/*
599 * Mark a callee-save fp register as promoted. Note that
600 * vpush/vpop uses contiguous register lists so we must
601 * include any holes in the mask. Associate holes with
602 * Dalvik register INVALID_VREG (0xFFFFU).
603 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700604void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700605 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
606 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
607 // Ensure fp_vmap_table is large enough
608 int table_size = fp_vmap_table_.size();
609 for (int i = table_size; i < (reg + 1); i++) {
610 fp_vmap_table_.push_back(INVALID_VREG);
611 }
612 // Add the current mapping
613 fp_vmap_table_[reg] = v_reg;
614 // Size of fp_vmap_table is high-water mark, use to set mask
615 num_fp_spills_ = fp_vmap_table_.size();
616 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
617}
618
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700619void ArmMir2Lir::FlushRegWide(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700620 RegisterInfo* info1 = GetRegInfo(reg1);
621 RegisterInfo* info2 = GetRegInfo(reg2);
622 DCHECK(info1 && info2 && info1->pair && info2->pair &&
623 (info1->partner == info2->reg) &&
624 (info2->partner == info1->reg));
625 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
626 if (!(info1->is_temp && info2->is_temp)) {
627 /* Should not happen. If it does, there's a problem in eval_loc */
628 LOG(FATAL) << "Long half-temp, half-promoted";
629 }
630
631 info1->dirty = false;
632 info2->dirty = false;
633 if (mir_graph_->SRegToVReg(info2->s_reg) <
634 mir_graph_->SRegToVReg(info1->s_reg))
635 info1 = info2;
636 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
637 StoreBaseDispWide(rARM_SP, VRegOffset(v_reg), info1->reg, info1->partner);
638 }
639}
640
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700641void ArmMir2Lir::FlushReg(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700642 RegisterInfo* info = GetRegInfo(reg);
643 if (info->live && info->dirty) {
644 info->dirty = false;
645 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
646 StoreBaseDisp(rARM_SP, VRegOffset(v_reg), reg, kWord);
647 }
648}
649
650/* Give access to the target-dependent FP register encoding to common code */
651bool ArmMir2Lir::IsFpReg(int reg) {
652 return ARM_FPREG(reg);
653}
654
655/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000656void ArmMir2Lir::ClobberCallerSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700657 Clobber(r0);
658 Clobber(r1);
659 Clobber(r2);
660 Clobber(r3);
661 Clobber(r12);
662 Clobber(r14lr);
663 Clobber(fr0);
664 Clobber(fr1);
665 Clobber(fr2);
666 Clobber(fr3);
667 Clobber(fr4);
668 Clobber(fr5);
669 Clobber(fr6);
670 Clobber(fr7);
671 Clobber(fr8);
672 Clobber(fr9);
673 Clobber(fr10);
674 Clobber(fr11);
675 Clobber(fr12);
676 Clobber(fr13);
677 Clobber(fr14);
678 Clobber(fr15);
679}
680
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700681RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700682 RegLocation res = LocCReturnWide();
683 res.low_reg = r2;
684 res.high_reg = r3;
685 Clobber(r2);
686 Clobber(r3);
687 MarkInUse(r2);
688 MarkInUse(r3);
689 MarkPair(res.low_reg, res.high_reg);
690 return res;
691}
692
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700693RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700694 RegLocation res = LocCReturn();
695 res.low_reg = r1;
696 Clobber(r1);
697 MarkInUse(r1);
698 return res;
699}
700
Brian Carlstrom7940e442013-07-12 13:46:57 -0700701/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700702void ArmMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700703 LockTemp(r0);
704 LockTemp(r1);
705 LockTemp(r2);
706 LockTemp(r3);
707}
708
709/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700710void ArmMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700711 FreeTemp(r0);
712 FreeTemp(r1);
713 FreeTemp(r2);
714 FreeTemp(r3);
715}
716
Ian Rogers468532e2013-08-05 10:56:33 -0700717int ArmMir2Lir::LoadHelper(ThreadOffset offset) {
718 LoadWordDisp(rARM_SELF, offset.Int32Value(), rARM_LR);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700719 return rARM_LR;
720}
721
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700722uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700723 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700724 return ArmMir2Lir::EncodingMap[opcode].flags;
725}
726
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700727const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700728 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700729 return ArmMir2Lir::EncodingMap[opcode].name;
730}
731
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700732const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700733 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700734 return ArmMir2Lir::EncodingMap[opcode].fmt;
735}
736
737} // namespace art