blob: 759104150d467414dca084e63b2cfbf6cf9ed32b [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 */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800258static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
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) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800271 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700272 } else {
273 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800274 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700275 }
276 }
277 }
278 return buf;
279}
280
Ian Rogers988e6ea2014-01-08 11:30:50 -0800281static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
282 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700283 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800284 snprintf(buf + strlen(buf), buf_size - 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) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800336 snprintf(tbuf, arraysize(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);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800376 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700377 break;
378 case 'm':
379 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800380 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700381 break;
382 case 's':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800383 snprintf(tbuf, arraysize(tbuf), "s%d", operand & ARM_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700384 break;
385 case 'S':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800386 snprintf(tbuf, arraysize(tbuf), "d%d", (operand & ARM_FP_REG_MASK) >> 1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700387 break;
388 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800389 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700390 break;
391 case 'M':
392 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800393 snprintf(tbuf, arraysize(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])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800398 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700399 break;
400 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800401 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700402 break;
403 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800404 snprintf(tbuf, arraysize(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':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800410 snprintf(tbuf, arraysize(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;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800422 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700423 break;
424 }
425
426 /* Nothing to print for BLX_2 */
427 case 'v':
428 strcpy(tbuf, "see above");
429 break;
430 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800431 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700432 break;
433 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800434 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700435 break;
436 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800437 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700438 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)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800464 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700465 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)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800478 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
479 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
480 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700481 }
482 if (mask & ENCODE_LITERAL) {
483 strcat(buf, "lit ");
484 }
485
486 if (mask & ENCODE_HEAP_REF) {
487 strcat(buf, "heap ");
488 }
489 if (mask & ENCODE_MUST_NOT_ALIAS) {
490 strcat(buf, "noalias ");
491 }
492 }
493 if (buf[0]) {
494 LOG(INFO) << prefix << ": " << buf;
495 }
496}
497
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700498bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700499 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
500}
501
502ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
503 : Mir2Lir(cu, mir_graph, arena) {
504 // Sanity check - make sure encoding map lines up.
505 for (int i = 0; i < kArmLast; i++) {
506 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
507 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
508 << " is wrong: expecting " << i << ", seeing "
509 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
510 }
511 }
512}
513
514Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
515 ArenaAllocator* const arena) {
516 return new ArmMir2Lir(cu, mir_graph, arena);
517}
518
519/*
520 * Alloc a pair of core registers, or a double. Low reg in low byte,
521 * high reg in next byte.
522 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700523int ArmMir2Lir::AllocTypedTempPair(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700524 int high_reg;
525 int low_reg;
526 int res = 0;
527
528 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
529 low_reg = AllocTempDouble();
530 high_reg = low_reg + 1;
531 } else {
532 low_reg = AllocTemp();
533 high_reg = AllocTemp();
534 }
535 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
536 return res;
537}
538
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700539int ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700540 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
541 return AllocTempFloat();
542 return AllocTemp();
543}
544
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700545void ArmMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700546 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
547 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
548 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
549 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
550 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700551 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
552 ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700553 reg_pool_->num_core_regs = num_regs;
554 reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700555 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700556 reg_pool_->num_fp_regs = num_fp_regs;
557 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700558 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700559 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
560 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
561 // Keep special registers from being allocated
562 for (int i = 0; i < num_reserved; i++) {
563 if (NO_SUSPEND && (ReservedRegs[i] == rARM_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700564 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700565 continue;
566 }
567 MarkInUse(ReservedRegs[i]);
568 }
569 // Mark temp regs - all others not in use can be used for promotion
570 for (int i = 0; i < num_temps; i++) {
571 MarkTemp(core_temps[i]);
572 }
573 for (int i = 0; i < num_fp_temps; i++) {
574 MarkTemp(fp_temps[i]);
575 }
576
577 // Start allocation at r2 in an attempt to avoid clobbering return values
578 reg_pool_->next_core_reg = r2;
579}
580
581void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700582 RegLocation rl_free) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700583 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
584 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
585 // No overlap, free both
586 FreeTemp(rl_free.low_reg);
587 FreeTemp(rl_free.high_reg);
588 }
589}
590/*
591 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
592 * instructions might call out to C/assembly helper functions. Until
593 * machinery is in place, always spill lr.
594 */
595
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700596void ArmMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700597 core_spill_mask_ |= (1 << rARM_LR);
598 num_core_spills_++;
599}
600
601/*
602 * Mark a callee-save fp register as promoted. Note that
603 * vpush/vpop uses contiguous register lists so we must
604 * include any holes in the mask. Associate holes with
605 * Dalvik register INVALID_VREG (0xFFFFU).
606 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700607void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700608 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
609 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
610 // Ensure fp_vmap_table is large enough
611 int table_size = fp_vmap_table_.size();
612 for (int i = table_size; i < (reg + 1); i++) {
613 fp_vmap_table_.push_back(INVALID_VREG);
614 }
615 // Add the current mapping
616 fp_vmap_table_[reg] = v_reg;
617 // Size of fp_vmap_table is high-water mark, use to set mask
618 num_fp_spills_ = fp_vmap_table_.size();
619 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
620}
621
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700622void ArmMir2Lir::FlushRegWide(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700623 RegisterInfo* info1 = GetRegInfo(reg1);
624 RegisterInfo* info2 = GetRegInfo(reg2);
625 DCHECK(info1 && info2 && info1->pair && info2->pair &&
626 (info1->partner == info2->reg) &&
627 (info2->partner == info1->reg));
628 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
629 if (!(info1->is_temp && info2->is_temp)) {
630 /* Should not happen. If it does, there's a problem in eval_loc */
631 LOG(FATAL) << "Long half-temp, half-promoted";
632 }
633
634 info1->dirty = false;
635 info2->dirty = false;
636 if (mir_graph_->SRegToVReg(info2->s_reg) <
637 mir_graph_->SRegToVReg(info1->s_reg))
638 info1 = info2;
639 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
640 StoreBaseDispWide(rARM_SP, VRegOffset(v_reg), info1->reg, info1->partner);
641 }
642}
643
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700644void ArmMir2Lir::FlushReg(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700645 RegisterInfo* info = GetRegInfo(reg);
646 if (info->live && info->dirty) {
647 info->dirty = false;
648 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
649 StoreBaseDisp(rARM_SP, VRegOffset(v_reg), reg, kWord);
650 }
651}
652
653/* Give access to the target-dependent FP register encoding to common code */
654bool ArmMir2Lir::IsFpReg(int reg) {
655 return ARM_FPREG(reg);
656}
657
658/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000659void ArmMir2Lir::ClobberCallerSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700660 Clobber(r0);
661 Clobber(r1);
662 Clobber(r2);
663 Clobber(r3);
664 Clobber(r12);
665 Clobber(r14lr);
666 Clobber(fr0);
667 Clobber(fr1);
668 Clobber(fr2);
669 Clobber(fr3);
670 Clobber(fr4);
671 Clobber(fr5);
672 Clobber(fr6);
673 Clobber(fr7);
674 Clobber(fr8);
675 Clobber(fr9);
676 Clobber(fr10);
677 Clobber(fr11);
678 Clobber(fr12);
679 Clobber(fr13);
680 Clobber(fr14);
681 Clobber(fr15);
682}
683
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700684RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700685 RegLocation res = LocCReturnWide();
686 res.low_reg = r2;
687 res.high_reg = r3;
688 Clobber(r2);
689 Clobber(r3);
690 MarkInUse(r2);
691 MarkInUse(r3);
692 MarkPair(res.low_reg, res.high_reg);
693 return res;
694}
695
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700696RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700697 RegLocation res = LocCReturn();
698 res.low_reg = r1;
699 Clobber(r1);
700 MarkInUse(r1);
701 return res;
702}
703
Brian Carlstrom7940e442013-07-12 13:46:57 -0700704/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700705void ArmMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700706 LockTemp(r0);
707 LockTemp(r1);
708 LockTemp(r2);
709 LockTemp(r3);
710}
711
712/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700713void ArmMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700714 FreeTemp(r0);
715 FreeTemp(r1);
716 FreeTemp(r2);
717 FreeTemp(r3);
718}
719
Ian Rogers468532e2013-08-05 10:56:33 -0700720int ArmMir2Lir::LoadHelper(ThreadOffset offset) {
721 LoadWordDisp(rARM_SELF, offset.Int32Value(), rARM_LR);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700722 return rARM_LR;
723}
724
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700725uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700726 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700727 return ArmMir2Lir::EncodingMap[opcode].flags;
728}
729
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700730const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700731 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700732 return ArmMir2Lir::EncodingMap[opcode].name;
733}
734
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700735const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700736 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700737 return ArmMir2Lir::EncodingMap[opcode].fmt;
738}
739
740} // namespace art