blob: 47d3d974efc73075be4f9aaa6a9dae0262413cea [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
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700121void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700122 DCHECK_EQ(cu_->instruction_set, kThumb2);
123
124 // Thumb2 specific setup
125 uint64_t flags = ArmMir2Lir::EncodingMap[lir->opcode].flags;
126 int opcode = lir->opcode;
127
128 if (flags & REG_DEF_SP) {
129 lir->def_mask |= ENCODE_ARM_REG_SP;
130 }
131
132 if (flags & REG_USE_SP) {
133 lir->use_mask |= ENCODE_ARM_REG_SP;
134 }
135
136 if (flags & REG_DEF_LIST0) {
137 lir->def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
138 }
139
140 if (flags & REG_DEF_LIST1) {
141 lir->def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
142 }
143
144 if (flags & REG_DEF_FPCS_LIST0) {
145 lir->def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
146 }
147
148 if (flags & REG_DEF_FPCS_LIST2) {
149 for (int i = 0; i < lir->operands[2]; i++) {
150 SetupRegMask(&lir->def_mask, lir->operands[1] + i);
151 }
152 }
153
154 if (flags & REG_USE_PC) {
155 lir->use_mask |= ENCODE_ARM_REG_PC;
156 }
157
158 /* Conservatively treat the IT block */
159 if (flags & IS_IT) {
160 lir->def_mask = ENCODE_ALL;
161 }
162
163 if (flags & REG_USE_LIST0) {
164 lir->use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
165 }
166
167 if (flags & REG_USE_LIST1) {
168 lir->use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
169 }
170
171 if (flags & REG_USE_FPCS_LIST0) {
172 lir->use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
173 }
174
175 if (flags & REG_USE_FPCS_LIST2) {
176 for (int i = 0; i < lir->operands[2]; i++) {
177 SetupRegMask(&lir->use_mask, lir->operands[1] + i);
178 }
179 }
180 /* Fixup for kThumbPush/lr and kThumbPop/pc */
181 if (opcode == kThumbPush || opcode == kThumbPop) {
182 uint64_t r8Mask = GetRegMaskCommon(r8);
183 if ((opcode == kThumbPush) && (lir->use_mask & r8Mask)) {
184 lir->use_mask &= ~r8Mask;
185 lir->use_mask |= ENCODE_ARM_REG_LR;
186 } else if ((opcode == kThumbPop) && (lir->def_mask & r8Mask)) {
187 lir->def_mask &= ~r8Mask;
188 lir->def_mask |= ENCODE_ARM_REG_PC;
189 }
190 }
191 if (flags & REG_DEF_LR) {
192 lir->def_mask |= ENCODE_ARM_REG_LR;
193 }
194}
195
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700196ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700197 ArmConditionCode res;
198 switch (ccode) {
199 case kCondEq: res = kArmCondEq; break;
200 case kCondNe: res = kArmCondNe; break;
201 case kCondCs: res = kArmCondCs; break;
202 case kCondCc: res = kArmCondCc; break;
203 case kCondMi: res = kArmCondMi; break;
204 case kCondPl: res = kArmCondPl; break;
205 case kCondVs: res = kArmCondVs; break;
206 case kCondVc: res = kArmCondVc; break;
207 case kCondHi: res = kArmCondHi; break;
208 case kCondLs: res = kArmCondLs; break;
209 case kCondGe: res = kArmCondGe; break;
210 case kCondLt: res = kArmCondLt; break;
211 case kCondGt: res = kArmCondGt; break;
212 case kCondLe: res = kArmCondLe; break;
213 case kCondAl: res = kArmCondAl; break;
214 case kCondNv: res = kArmCondNv; break;
215 default:
216 LOG(FATAL) << "Bad condition code " << ccode;
217 res = static_cast<ArmConditionCode>(0); // Quiet gcc
218 }
219 return res;
220}
221
222static const char* core_reg_names[16] = {
223 "r0",
224 "r1",
225 "r2",
226 "r3",
227 "r4",
228 "r5",
229 "r6",
230 "r7",
231 "r8",
232 "rSELF",
233 "r10",
234 "r11",
235 "r12",
236 "sp",
237 "lr",
238 "pc",
239};
240
241
242static const char* shift_names[4] = {
243 "lsl",
244 "lsr",
245 "asr",
246 "ror"};
247
248/* Decode and print a ARM register name */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700249static char* DecodeRegList(int opcode, int vector, char* buf) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700250 int i;
251 bool printed = false;
252 buf[0] = 0;
253 for (i = 0; i < 16; i++, vector >>= 1) {
254 if (vector & 0x1) {
255 int reg_id = i;
256 if (opcode == kThumbPush && i == 8) {
257 reg_id = r14lr;
258 } else if (opcode == kThumbPop && i == 8) {
259 reg_id = r15pc;
260 }
261 if (printed) {
262 sprintf(buf + strlen(buf), ", r%d", reg_id);
263 } else {
264 printed = true;
265 sprintf(buf, "r%d", reg_id);
266 }
267 }
268 }
269 return buf;
270}
271
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700272static char* DecodeFPCSRegList(int count, int base, char* buf) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700273 sprintf(buf, "s%d", base);
274 for (int i = 1; i < count; i++) {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700275 sprintf(buf + strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700276 }
277 return buf;
278}
279
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700280static int ExpandImmediate(int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700281 int mode = (value & 0xf00) >> 8;
282 uint32_t bits = value & 0xff;
283 switch (mode) {
284 case 0:
285 return bits;
286 case 1:
287 return (bits << 16) | bits;
288 case 2:
289 return (bits << 24) | (bits << 8);
290 case 3:
291 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
292 default:
293 break;
294 }
295 bits = (bits | 0x80) << 24;
296 return bits >> (((value & 0xf80) >> 7) - 8);
297}
298
Brian Carlstromb1eba212013-07-17 18:07:19 -0700299const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
300 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700301/*
302 * Interpret a format string and build a string no longer than size
303 * See format key in Assemble.c.
304 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700305std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700306 std::string buf;
307 int i;
308 const char* fmt_end = &fmt[strlen(fmt)];
309 char tbuf[256];
310 const char* name;
311 char nc;
312 while (fmt < fmt_end) {
313 int operand;
314 if (*fmt == '!') {
315 fmt++;
316 DCHECK_LT(fmt, fmt_end);
317 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700318 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700319 strcpy(tbuf, "!");
320 } else {
321 DCHECK_LT(fmt, fmt_end);
322 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
323 operand = lir->operands[nc-'0'];
324 switch (*fmt++) {
325 case 'H':
326 if (operand != 0) {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700327 sprintf(tbuf, ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700328 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700329 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700330 }
331 break;
332 case 'B':
333 switch (operand) {
334 case kSY:
335 name = "sy";
336 break;
337 case kST:
338 name = "st";
339 break;
340 case kISH:
341 name = "ish";
342 break;
343 case kISHST:
344 name = "ishst";
345 break;
346 case kNSH:
347 name = "nsh";
348 break;
349 case kNSHST:
350 name = "shst";
351 break;
352 default:
353 name = "DecodeError2";
354 break;
355 }
356 strcpy(tbuf, name);
357 break;
358 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700359 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700360 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700361 tbuf[i] += operand & 1;
362 operand >>= 1;
363 }
364 break;
365 case 'n':
366 operand = ~ExpandImmediate(operand);
Brian Carlstromb1eba212013-07-17 18:07:19 -0700367 sprintf(tbuf, "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700368 break;
369 case 'm':
370 operand = ExpandImmediate(operand);
Brian Carlstromb1eba212013-07-17 18:07:19 -0700371 sprintf(tbuf, "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700372 break;
373 case 's':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700374 sprintf(tbuf, "s%d", operand & ARM_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700375 break;
376 case 'S':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700377 sprintf(tbuf, "d%d", (operand & ARM_FP_REG_MASK) >> 1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700378 break;
379 case 'h':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700380 sprintf(tbuf, "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700381 break;
382 case 'M':
383 case 'd':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700384 sprintf(tbuf, "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700385 break;
386 case 'C':
387 DCHECK_LT(operand, static_cast<int>(
388 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Brian Carlstromb1eba212013-07-17 18:07:19 -0700389 sprintf(tbuf, "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700390 break;
391 case 'E':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700392 sprintf(tbuf, "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700393 break;
394 case 'F':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700395 sprintf(tbuf, "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700396 break;
397 case 'c':
398 strcpy(tbuf, cc_names[operand]);
399 break;
400 case 't':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700401 sprintf(tbuf, "0x%08x (L%p)",
Brian Carlstrom7940e442013-07-12 13:46:57 -0700402 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 +
403 (operand << 1),
404 lir->target);
405 break;
406 case 'u': {
407 int offset_1 = lir->operands[0];
408 int offset_2 = NEXT_LIR(lir)->operands[0];
409 uintptr_t target =
410 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
411 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
412 0xfffffffc;
413 sprintf(tbuf, "%p", reinterpret_cast<void *>(target));
414 break;
415 }
416
417 /* Nothing to print for BLX_2 */
418 case 'v':
419 strcpy(tbuf, "see above");
420 break;
421 case 'R':
422 DecodeRegList(lir->opcode, operand, tbuf);
423 break;
424 case 'P':
425 DecodeFPCSRegList(operand, 16, tbuf);
426 break;
427 case 'Q':
428 DecodeFPCSRegList(operand, 0, tbuf);
429 break;
430 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700431 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700432 break;
433 }
434 buf += tbuf;
435 }
436 } else {
437 buf += *fmt++;
438 }
439 }
440 return buf;
441}
442
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700443void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700444 char buf[256];
445 buf[0] = 0;
446
447 if (mask == ENCODE_ALL) {
448 strcpy(buf, "all");
449 } else {
450 char num[8];
451 int i;
452
453 for (i = 0; i < kArmRegEnd; i++) {
454 if (mask & (1ULL << i)) {
455 sprintf(num, "%d ", i);
456 strcat(buf, num);
457 }
458 }
459
460 if (mask & ENCODE_CCODE) {
461 strcat(buf, "cc ");
462 }
463 if (mask & ENCODE_FP_STATUS) {
464 strcat(buf, "fpcc ");
465 }
466
467 /* Memory bits */
468 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
469 sprintf(buf + strlen(buf), "dr%d%s", arm_lir->alias_info & 0xffff,
470 (arm_lir->alias_info & 0x80000000) ? "(+1)" : "");
471 }
472 if (mask & ENCODE_LITERAL) {
473 strcat(buf, "lit ");
474 }
475
476 if (mask & ENCODE_HEAP_REF) {
477 strcat(buf, "heap ");
478 }
479 if (mask & ENCODE_MUST_NOT_ALIAS) {
480 strcat(buf, "noalias ");
481 }
482 }
483 if (buf[0]) {
484 LOG(INFO) << prefix << ": " << buf;
485 }
486}
487
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700488bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700489 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
490}
491
492ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
493 : Mir2Lir(cu, mir_graph, arena) {
494 // Sanity check - make sure encoding map lines up.
495 for (int i = 0; i < kArmLast; i++) {
496 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
497 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
498 << " is wrong: expecting " << i << ", seeing "
499 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
500 }
501 }
502}
503
504Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
505 ArenaAllocator* const arena) {
506 return new ArmMir2Lir(cu, mir_graph, arena);
507}
508
509/*
510 * Alloc a pair of core registers, or a double. Low reg in low byte,
511 * high reg in next byte.
512 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700513int ArmMir2Lir::AllocTypedTempPair(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700514 int high_reg;
515 int low_reg;
516 int res = 0;
517
518 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
519 low_reg = AllocTempDouble();
520 high_reg = low_reg + 1;
521 } else {
522 low_reg = AllocTemp();
523 high_reg = AllocTemp();
524 }
525 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
526 return res;
527}
528
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700529int ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700530 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
531 return AllocTempFloat();
532 return AllocTemp();
533}
534
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700535void ArmMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700536 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
537 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
538 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
539 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
540 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
541 reg_pool_ = static_cast<RegisterPool*>(arena_->NewMem(sizeof(*reg_pool_), true,
542 ArenaAllocator::kAllocRegAlloc));
543 reg_pool_->num_core_regs = num_regs;
544 reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
545 (arena_->NewMem(num_regs * sizeof(*reg_pool_->core_regs), true,
546 ArenaAllocator::kAllocRegAlloc));
547 reg_pool_->num_fp_regs = num_fp_regs;
548 reg_pool_->FPRegs = static_cast<RegisterInfo*>
549 (arena_->NewMem(num_fp_regs * sizeof(*reg_pool_->FPRegs), true,
550 ArenaAllocator::kAllocRegAlloc));
551 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
552 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
553 // Keep special registers from being allocated
554 for (int i = 0; i < num_reserved; i++) {
555 if (NO_SUSPEND && (ReservedRegs[i] == rARM_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700556 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700557 continue;
558 }
559 MarkInUse(ReservedRegs[i]);
560 }
561 // Mark temp regs - all others not in use can be used for promotion
562 for (int i = 0; i < num_temps; i++) {
563 MarkTemp(core_temps[i]);
564 }
565 for (int i = 0; i < num_fp_temps; i++) {
566 MarkTemp(fp_temps[i]);
567 }
568
569 // Start allocation at r2 in an attempt to avoid clobbering return values
570 reg_pool_->next_core_reg = r2;
571}
572
573void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700574 RegLocation rl_free) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700575 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
576 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
577 // No overlap, free both
578 FreeTemp(rl_free.low_reg);
579 FreeTemp(rl_free.high_reg);
580 }
581}
582/*
583 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
584 * instructions might call out to C/assembly helper functions. Until
585 * machinery is in place, always spill lr.
586 */
587
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700588void ArmMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700589 core_spill_mask_ |= (1 << rARM_LR);
590 num_core_spills_++;
591}
592
593/*
594 * Mark a callee-save fp register as promoted. Note that
595 * vpush/vpop uses contiguous register lists so we must
596 * include any holes in the mask. Associate holes with
597 * Dalvik register INVALID_VREG (0xFFFFU).
598 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700599void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700600 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
601 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
602 // Ensure fp_vmap_table is large enough
603 int table_size = fp_vmap_table_.size();
604 for (int i = table_size; i < (reg + 1); i++) {
605 fp_vmap_table_.push_back(INVALID_VREG);
606 }
607 // Add the current mapping
608 fp_vmap_table_[reg] = v_reg;
609 // Size of fp_vmap_table is high-water mark, use to set mask
610 num_fp_spills_ = fp_vmap_table_.size();
611 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
612}
613
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700614void ArmMir2Lir::FlushRegWide(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700615 RegisterInfo* info1 = GetRegInfo(reg1);
616 RegisterInfo* info2 = GetRegInfo(reg2);
617 DCHECK(info1 && info2 && info1->pair && info2->pair &&
618 (info1->partner == info2->reg) &&
619 (info2->partner == info1->reg));
620 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
621 if (!(info1->is_temp && info2->is_temp)) {
622 /* Should not happen. If it does, there's a problem in eval_loc */
623 LOG(FATAL) << "Long half-temp, half-promoted";
624 }
625
626 info1->dirty = false;
627 info2->dirty = false;
628 if (mir_graph_->SRegToVReg(info2->s_reg) <
629 mir_graph_->SRegToVReg(info1->s_reg))
630 info1 = info2;
631 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
632 StoreBaseDispWide(rARM_SP, VRegOffset(v_reg), info1->reg, info1->partner);
633 }
634}
635
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700636void ArmMir2Lir::FlushReg(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700637 RegisterInfo* info = GetRegInfo(reg);
638 if (info->live && info->dirty) {
639 info->dirty = false;
640 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
641 StoreBaseDisp(rARM_SP, VRegOffset(v_reg), reg, kWord);
642 }
643}
644
645/* Give access to the target-dependent FP register encoding to common code */
646bool ArmMir2Lir::IsFpReg(int reg) {
647 return ARM_FPREG(reg);
648}
649
650/* Clobber all regs that might be used by an external C call */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700651void ArmMir2Lir::ClobberCalleeSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700652 Clobber(r0);
653 Clobber(r1);
654 Clobber(r2);
655 Clobber(r3);
656 Clobber(r12);
657 Clobber(r14lr);
658 Clobber(fr0);
659 Clobber(fr1);
660 Clobber(fr2);
661 Clobber(fr3);
662 Clobber(fr4);
663 Clobber(fr5);
664 Clobber(fr6);
665 Clobber(fr7);
666 Clobber(fr8);
667 Clobber(fr9);
668 Clobber(fr10);
669 Clobber(fr11);
670 Clobber(fr12);
671 Clobber(fr13);
672 Clobber(fr14);
673 Clobber(fr15);
674}
675
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700676RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700677 RegLocation res = LocCReturnWide();
678 res.low_reg = r2;
679 res.high_reg = r3;
680 Clobber(r2);
681 Clobber(r3);
682 MarkInUse(r2);
683 MarkInUse(r3);
684 MarkPair(res.low_reg, res.high_reg);
685 return res;
686}
687
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700688RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700689 RegLocation res = LocCReturn();
690 res.low_reg = r1;
691 Clobber(r1);
692 MarkInUse(r1);
693 return res;
694}
695
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700696ArmMir2Lir::RegisterInfo* ArmMir2Lir::GetRegInfo(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700697 return ARM_FPREG(reg) ? &reg_pool_->FPRegs[reg & ARM_FP_REG_MASK]
698 : &reg_pool_->core_regs[reg];
699}
700
701/* 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) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700723 return ArmMir2Lir::EncodingMap[opcode].flags;
724}
725
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700726const char* ArmMir2Lir::GetTargetInstName(int 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) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700731 return ArmMir2Lir::EncodingMap[opcode].fmt;
732}
733
734} // namespace art