blob: 3395ae7a44341d79a1d7bdfdc467da822584be98 [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;
77 case kCount: res = rARM_COUNT; break;
78 }
79 return res;
80}
81
82
83// Create a double from a pair of singles.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070084int ArmMir2Lir::S2d(int low_reg, int high_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070085 return ARM_S2D(low_reg, high_reg);
86}
87
88// Return mask to strip off fp reg flags and bias.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070089uint32_t ArmMir2Lir::FpRegMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070090 return ARM_FP_REG_MASK;
91}
92
93// True if both regs single, both core or both double.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070094bool ArmMir2Lir::SameRegType(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070095 return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2));
96}
97
98/*
99 * Decode the register id.
100 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700101uint64_t ArmMir2Lir::GetRegMaskCommon(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700102 uint64_t seed;
103 int shift;
104 int reg_id;
105
106
107 reg_id = reg & 0x1f;
108 /* Each double register is equal to a pair of single-precision FP registers */
109 seed = ARM_DOUBLEREG(reg) ? 3 : 1;
110 /* FP register starts at bit position 16 */
111 shift = ARM_FPREG(reg) ? kArmFPReg0 : 0;
112 /* Expand the double register id into single offset */
113 shift += reg_id;
114 return (seed << shift);
115}
116
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700117uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700118 return ENCODE_ARM_REG_PC;
119}
120
buzbeeb48819d2013-09-14 16:15:25 -0700121// Thumb2 specific setup. TODO: inline?:
122void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700123 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700124 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700125
Brian Carlstrom7940e442013-07-12 13:46:57 -0700126 int opcode = lir->opcode;
127
buzbeeb48819d2013-09-14 16:15:25 -0700128 // These flags are somewhat uncommon - bypass if we can.
129 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
130 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
131 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
132 if (flags & REG_DEF_SP) {
133 lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135
buzbeeb48819d2013-09-14 16:15:25 -0700136 if (flags & REG_USE_SP) {
137 lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700138 }
buzbeeb48819d2013-09-14 16:15:25 -0700139
140 if (flags & REG_DEF_LIST0) {
141 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700142 }
buzbeeb48819d2013-09-14 16:15:25 -0700143
144 if (flags & REG_DEF_LIST1) {
145 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
146 }
147
148 if (flags & REG_DEF_FPCS_LIST0) {
149 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
150 }
151
152 if (flags & REG_DEF_FPCS_LIST2) {
153 for (int i = 0; i < lir->operands[2]; i++) {
154 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
155 }
156 }
157
158 if (flags & REG_USE_PC) {
159 lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
160 }
161
162 /* Conservatively treat the IT block */
163 if (flags & IS_IT) {
164 lir->u.m.def_mask = ENCODE_ALL;
165 }
166
167 if (flags & REG_USE_LIST0) {
168 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
169 }
170
171 if (flags & REG_USE_LIST1) {
172 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
173 }
174
175 if (flags & REG_USE_FPCS_LIST0) {
176 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
177 }
178
179 if (flags & REG_USE_FPCS_LIST2) {
180 for (int i = 0; i < lir->operands[2]; i++) {
181 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
182 }
183 }
184 /* Fixup for kThumbPush/lr and kThumbPop/pc */
185 if (opcode == kThumbPush || opcode == kThumbPop) {
186 uint64_t r8Mask = GetRegMaskCommon(r8);
187 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
188 lir->u.m.use_mask &= ~r8Mask;
189 lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
190 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
191 lir->u.m.def_mask &= ~r8Mask;
192 lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
193 }
194 }
195 if (flags & REG_DEF_LR) {
196 lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
197 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700198 }
199}
200
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700201ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700202 ArmConditionCode res;
203 switch (ccode) {
204 case kCondEq: res = kArmCondEq; break;
205 case kCondNe: res = kArmCondNe; break;
206 case kCondCs: res = kArmCondCs; break;
207 case kCondCc: res = kArmCondCc; break;
208 case kCondMi: res = kArmCondMi; break;
209 case kCondPl: res = kArmCondPl; break;
210 case kCondVs: res = kArmCondVs; break;
211 case kCondVc: res = kArmCondVc; break;
212 case kCondHi: res = kArmCondHi; break;
213 case kCondLs: res = kArmCondLs; break;
214 case kCondGe: res = kArmCondGe; break;
215 case kCondLt: res = kArmCondLt; break;
216 case kCondGt: res = kArmCondGt; break;
217 case kCondLe: res = kArmCondLe; break;
218 case kCondAl: res = kArmCondAl; break;
219 case kCondNv: res = kArmCondNv; break;
220 default:
221 LOG(FATAL) << "Bad condition code " << ccode;
222 res = static_cast<ArmConditionCode>(0); // Quiet gcc
223 }
224 return res;
225}
226
227static const char* core_reg_names[16] = {
228 "r0",
229 "r1",
230 "r2",
231 "r3",
232 "r4",
233 "r5",
234 "r6",
235 "r7",
236 "r8",
237 "rSELF",
238 "r10",
239 "r11",
240 "r12",
241 "sp",
242 "lr",
243 "pc",
244};
245
246
247static const char* shift_names[4] = {
248 "lsl",
249 "lsr",
250 "asr",
251 "ror"};
252
253/* Decode and print a ARM register name */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700254static char* DecodeRegList(int opcode, int vector, char* buf) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700255 int i;
256 bool printed = false;
257 buf[0] = 0;
258 for (i = 0; i < 16; i++, vector >>= 1) {
259 if (vector & 0x1) {
260 int reg_id = i;
261 if (opcode == kThumbPush && i == 8) {
262 reg_id = r14lr;
263 } else if (opcode == kThumbPop && i == 8) {
264 reg_id = r15pc;
265 }
266 if (printed) {
267 sprintf(buf + strlen(buf), ", r%d", reg_id);
268 } else {
269 printed = true;
270 sprintf(buf, "r%d", reg_id);
271 }
272 }
273 }
274 return buf;
275}
276
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700277static char* DecodeFPCSRegList(int count, int base, char* buf) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700278 sprintf(buf, "s%d", base);
279 for (int i = 1; i < count; i++) {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700280 sprintf(buf + strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700281 }
282 return buf;
283}
284
buzbee0d829482013-10-11 15:24:55 -0700285static int32_t ExpandImmediate(int value) {
286 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 uint32_t bits = value & 0xff;
288 switch (mode) {
289 case 0:
290 return bits;
291 case 1:
292 return (bits << 16) | bits;
293 case 2:
294 return (bits << 24) | (bits << 8);
295 case 3:
296 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
297 default:
298 break;
299 }
300 bits = (bits | 0x80) << 24;
301 return bits >> (((value & 0xf80) >> 7) - 8);
302}
303
Brian Carlstromb1eba212013-07-17 18:07:19 -0700304const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
305 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700306/*
307 * Interpret a format string and build a string no longer than size
308 * See format key in Assemble.c.
309 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700310std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700311 std::string buf;
312 int i;
313 const char* fmt_end = &fmt[strlen(fmt)];
314 char tbuf[256];
315 const char* name;
316 char nc;
317 while (fmt < fmt_end) {
318 int operand;
319 if (*fmt == '!') {
320 fmt++;
321 DCHECK_LT(fmt, fmt_end);
322 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700323 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700324 strcpy(tbuf, "!");
325 } else {
326 DCHECK_LT(fmt, fmt_end);
327 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
328 operand = lir->operands[nc-'0'];
329 switch (*fmt++) {
330 case 'H':
331 if (operand != 0) {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700332 sprintf(tbuf, ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700333 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700334 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335 }
336 break;
337 case 'B':
338 switch (operand) {
339 case kSY:
340 name = "sy";
341 break;
342 case kST:
343 name = "st";
344 break;
345 case kISH:
346 name = "ish";
347 break;
348 case kISHST:
349 name = "ishst";
350 break;
351 case kNSH:
352 name = "nsh";
353 break;
354 case kNSHST:
355 name = "shst";
356 break;
357 default:
358 name = "DecodeError2";
359 break;
360 }
361 strcpy(tbuf, name);
362 break;
363 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700364 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700365 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700366 tbuf[i] += operand & 1;
367 operand >>= 1;
368 }
369 break;
370 case 'n':
371 operand = ~ExpandImmediate(operand);
Brian Carlstromb1eba212013-07-17 18:07:19 -0700372 sprintf(tbuf, "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700373 break;
374 case 'm':
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 's':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700379 sprintf(tbuf, "s%d", operand & ARM_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700380 break;
381 case 'S':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700382 sprintf(tbuf, "d%d", (operand & ARM_FP_REG_MASK) >> 1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700383 break;
384 case 'h':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700385 sprintf(tbuf, "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700386 break;
387 case 'M':
388 case 'd':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700389 sprintf(tbuf, "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700390 break;
391 case 'C':
392 DCHECK_LT(operand, static_cast<int>(
393 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Brian Carlstromb1eba212013-07-17 18:07:19 -0700394 sprintf(tbuf, "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700395 break;
396 case 'E':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700397 sprintf(tbuf, "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700398 break;
399 case 'F':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700400 sprintf(tbuf, "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700401 break;
402 case 'c':
403 strcpy(tbuf, cc_names[operand]);
404 break;
405 case 't':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700406 sprintf(tbuf, "0x%08x (L%p)",
Brian Carlstrom7940e442013-07-12 13:46:57 -0700407 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 +
408 (operand << 1),
409 lir->target);
410 break;
411 case 'u': {
412 int offset_1 = lir->operands[0];
413 int offset_2 = NEXT_LIR(lir)->operands[0];
414 uintptr_t target =
415 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
416 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
417 0xfffffffc;
418 sprintf(tbuf, "%p", reinterpret_cast<void *>(target));
419 break;
420 }
421
422 /* Nothing to print for BLX_2 */
423 case 'v':
424 strcpy(tbuf, "see above");
425 break;
426 case 'R':
427 DecodeRegList(lir->opcode, operand, tbuf);
428 break;
429 case 'P':
430 DecodeFPCSRegList(operand, 16, tbuf);
431 break;
432 case 'Q':
433 DecodeFPCSRegList(operand, 0, tbuf);
434 break;
435 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700436 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700437 break;
438 }
439 buf += tbuf;
440 }
441 } else {
442 buf += *fmt++;
443 }
444 }
445 return buf;
446}
447
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700448void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700449 char buf[256];
450 buf[0] = 0;
451
452 if (mask == ENCODE_ALL) {
453 strcpy(buf, "all");
454 } else {
455 char num[8];
456 int i;
457
458 for (i = 0; i < kArmRegEnd; i++) {
459 if (mask & (1ULL << i)) {
460 sprintf(num, "%d ", i);
461 strcat(buf, num);
462 }
463 }
464
465 if (mask & ENCODE_CCODE) {
466 strcat(buf, "cc ");
467 }
468 if (mask & ENCODE_FP_STATUS) {
469 strcat(buf, "fpcc ");
470 }
471
472 /* Memory bits */
473 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
buzbeeb48819d2013-09-14 16:15:25 -0700474 sprintf(buf + strlen(buf), "dr%d%s", DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
475 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700476 }
477 if (mask & ENCODE_LITERAL) {
478 strcat(buf, "lit ");
479 }
480
481 if (mask & ENCODE_HEAP_REF) {
482 strcat(buf, "heap ");
483 }
484 if (mask & ENCODE_MUST_NOT_ALIAS) {
485 strcat(buf, "noalias ");
486 }
487 }
488 if (buf[0]) {
489 LOG(INFO) << prefix << ": " << buf;
490 }
491}
492
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700493bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700494 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
495}
496
497ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
498 : Mir2Lir(cu, mir_graph, arena) {
499 // Sanity check - make sure encoding map lines up.
500 for (int i = 0; i < kArmLast; i++) {
501 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
502 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
503 << " is wrong: expecting " << i << ", seeing "
504 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
505 }
506 }
507}
508
509Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
510 ArenaAllocator* const arena) {
511 return new ArmMir2Lir(cu, mir_graph, arena);
512}
513
514/*
515 * Alloc a pair of core registers, or a double. Low reg in low byte,
516 * high reg in next byte.
517 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700518int ArmMir2Lir::AllocTypedTempPair(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700519 int high_reg;
520 int low_reg;
521 int res = 0;
522
523 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
524 low_reg = AllocTempDouble();
525 high_reg = low_reg + 1;
526 } else {
527 low_reg = AllocTemp();
528 high_reg = AllocTemp();
529 }
530 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
531 return res;
532}
533
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700534int ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700535 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
536 return AllocTempFloat();
537 return AllocTemp();
538}
539
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700540void ArmMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700541 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
542 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
543 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
544 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
545 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700546 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
547 ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700548 reg_pool_->num_core_regs = num_regs;
549 reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700550 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700551 reg_pool_->num_fp_regs = num_fp_regs;
552 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700553 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700554 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
555 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
556 // Keep special registers from being allocated
557 for (int i = 0; i < num_reserved; i++) {
558 if (NO_SUSPEND && (ReservedRegs[i] == rARM_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700559 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700560 continue;
561 }
562 MarkInUse(ReservedRegs[i]);
563 }
564 // Mark temp regs - all others not in use can be used for promotion
565 for (int i = 0; i < num_temps; i++) {
566 MarkTemp(core_temps[i]);
567 }
568 for (int i = 0; i < num_fp_temps; i++) {
569 MarkTemp(fp_temps[i]);
570 }
571
572 // Start allocation at r2 in an attempt to avoid clobbering return values
573 reg_pool_->next_core_reg = r2;
574}
575
576void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700577 RegLocation rl_free) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700578 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
579 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
580 // No overlap, free both
581 FreeTemp(rl_free.low_reg);
582 FreeTemp(rl_free.high_reg);
583 }
584}
585/*
586 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
587 * instructions might call out to C/assembly helper functions. Until
588 * machinery is in place, always spill lr.
589 */
590
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700591void ArmMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700592 core_spill_mask_ |= (1 << rARM_LR);
593 num_core_spills_++;
594}
595
596/*
597 * Mark a callee-save fp register as promoted. Note that
598 * vpush/vpop uses contiguous register lists so we must
599 * include any holes in the mask. Associate holes with
600 * Dalvik register INVALID_VREG (0xFFFFU).
601 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700602void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700603 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
604 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
605 // Ensure fp_vmap_table is large enough
606 int table_size = fp_vmap_table_.size();
607 for (int i = table_size; i < (reg + 1); i++) {
608 fp_vmap_table_.push_back(INVALID_VREG);
609 }
610 // Add the current mapping
611 fp_vmap_table_[reg] = v_reg;
612 // Size of fp_vmap_table is high-water mark, use to set mask
613 num_fp_spills_ = fp_vmap_table_.size();
614 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
615}
616
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700617void ArmMir2Lir::FlushRegWide(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700618 RegisterInfo* info1 = GetRegInfo(reg1);
619 RegisterInfo* info2 = GetRegInfo(reg2);
620 DCHECK(info1 && info2 && info1->pair && info2->pair &&
621 (info1->partner == info2->reg) &&
622 (info2->partner == info1->reg));
623 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
624 if (!(info1->is_temp && info2->is_temp)) {
625 /* Should not happen. If it does, there's a problem in eval_loc */
626 LOG(FATAL) << "Long half-temp, half-promoted";
627 }
628
629 info1->dirty = false;
630 info2->dirty = false;
631 if (mir_graph_->SRegToVReg(info2->s_reg) <
632 mir_graph_->SRegToVReg(info1->s_reg))
633 info1 = info2;
634 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
635 StoreBaseDispWide(rARM_SP, VRegOffset(v_reg), info1->reg, info1->partner);
636 }
637}
638
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700639void ArmMir2Lir::FlushReg(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700640 RegisterInfo* info = GetRegInfo(reg);
641 if (info->live && info->dirty) {
642 info->dirty = false;
643 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
644 StoreBaseDisp(rARM_SP, VRegOffset(v_reg), reg, kWord);
645 }
646}
647
648/* Give access to the target-dependent FP register encoding to common code */
649bool ArmMir2Lir::IsFpReg(int reg) {
650 return ARM_FPREG(reg);
651}
652
653/* Clobber all regs that might be used by an external C call */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700654void ArmMir2Lir::ClobberCalleeSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700655 Clobber(r0);
656 Clobber(r1);
657 Clobber(r2);
658 Clobber(r3);
659 Clobber(r12);
660 Clobber(r14lr);
661 Clobber(fr0);
662 Clobber(fr1);
663 Clobber(fr2);
664 Clobber(fr3);
665 Clobber(fr4);
666 Clobber(fr5);
667 Clobber(fr6);
668 Clobber(fr7);
669 Clobber(fr8);
670 Clobber(fr9);
671 Clobber(fr10);
672 Clobber(fr11);
673 Clobber(fr12);
674 Clobber(fr13);
675 Clobber(fr14);
676 Clobber(fr15);
677}
678
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700679RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700680 RegLocation res = LocCReturnWide();
681 res.low_reg = r2;
682 res.high_reg = r3;
683 Clobber(r2);
684 Clobber(r3);
685 MarkInUse(r2);
686 MarkInUse(r3);
687 MarkPair(res.low_reg, res.high_reg);
688 return res;
689}
690
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700691RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700692 RegLocation res = LocCReturn();
693 res.low_reg = r1;
694 Clobber(r1);
695 MarkInUse(r1);
696 return res;
697}
698
Brian Carlstrom7940e442013-07-12 13:46:57 -0700699/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700700void ArmMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700701 LockTemp(r0);
702 LockTemp(r1);
703 LockTemp(r2);
704 LockTemp(r3);
705}
706
707/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700708void ArmMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700709 FreeTemp(r0);
710 FreeTemp(r1);
711 FreeTemp(r2);
712 FreeTemp(r3);
713}
714
Ian Rogers468532e2013-08-05 10:56:33 -0700715int ArmMir2Lir::LoadHelper(ThreadOffset offset) {
716 LoadWordDisp(rARM_SELF, offset.Int32Value(), rARM_LR);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700717 return rARM_LR;
718}
719
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700720uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700721 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700722 return ArmMir2Lir::EncodingMap[opcode].flags;
723}
724
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700725const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700726 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700727 return ArmMir2Lir::EncodingMap[opcode].name;
728}
729
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700730const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700731 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700732 return ArmMir2Lir::EncodingMap[opcode].fmt;
733}
734
735} // namespace art