blob: ceec7d50ce3e716bd897c991c7dc403a13862c3c [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
Ian Rogers107c31e2014-01-23 20:55:29 -080017#include "codegen_arm.h"
18
19#include <inttypes.h>
20
Brian Carlstrom7940e442013-07-12 13:46:57 -070021#include <string>
22
Brian Carlstrom7940e442013-07-12 13:46:57 -070023#include "dex/compiler_internals.h"
24#include "dex/quick/mir_to_lir-inl.h"
25
26namespace art {
27
28static int core_regs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10,
29 r11, r12, rARM_SP, rARM_LR, rARM_PC};
30static int ReservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC};
31static int FpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
32 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
33 fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
34 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
35static int core_temps[] = {r0, r1, r2, r3, r12};
36static int fp_temps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
37 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
38
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070039RegLocation ArmMir2Lir::LocCReturn() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070040 RegLocation res = ARM_LOC_C_RETURN;
41 return res;
42}
43
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070044RegLocation ArmMir2Lir::LocCReturnWide() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070045 RegLocation res = ARM_LOC_C_RETURN_WIDE;
46 return res;
47}
48
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070049RegLocation ArmMir2Lir::LocCReturnFloat() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070050 RegLocation res = ARM_LOC_C_RETURN_FLOAT;
51 return res;
52}
53
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070054RegLocation ArmMir2Lir::LocCReturnDouble() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070055 RegLocation res = ARM_LOC_C_RETURN_DOUBLE;
56 return res;
57}
58
59// Return a target-dependent special register.
60int ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
61 int res = INVALID_REG;
62 switch (reg) {
63 case kSelf: res = rARM_SELF; break;
64 case kSuspend: res = rARM_SUSPEND; break;
65 case kLr: res = rARM_LR; break;
66 case kPc: res = rARM_PC; break;
67 case kSp: res = rARM_SP; break;
68 case kArg0: res = rARM_ARG0; break;
69 case kArg1: res = rARM_ARG1; break;
70 case kArg2: res = rARM_ARG2; break;
71 case kArg3: res = rARM_ARG3; break;
72 case kFArg0: res = rARM_FARG0; break;
73 case kFArg1: res = rARM_FARG1; break;
74 case kFArg2: res = rARM_FARG2; break;
75 case kFArg3: res = rARM_FARG3; break;
76 case kRet0: res = rARM_RET0; break;
77 case kRet1: res = rARM_RET1; break;
78 case kInvokeTgt: res = rARM_INVOKE_TGT; break;
Jeff Hao88474b42013-10-23 16:24:40 -070079 case kHiddenArg: res = r12; break;
80 case kHiddenFpArg: res = INVALID_REG; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -070081 case kCount: res = rARM_COUNT; break;
82 }
83 return res;
84}
85
86
87// Create a double from a pair of singles.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070088int ArmMir2Lir::S2d(int low_reg, int high_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070089 return ARM_S2D(low_reg, high_reg);
90}
91
92// Return mask to strip off fp reg flags and bias.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070093uint32_t ArmMir2Lir::FpRegMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070094 return ARM_FP_REG_MASK;
95}
96
97// True if both regs single, both core or both double.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070098bool ArmMir2Lir::SameRegType(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070099 return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2));
100}
101
102/*
103 * Decode the register id.
104 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700105uint64_t ArmMir2Lir::GetRegMaskCommon(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700106 uint64_t seed;
107 int shift;
108 int reg_id;
109
110
111 reg_id = reg & 0x1f;
112 /* Each double register is equal to a pair of single-precision FP registers */
113 seed = ARM_DOUBLEREG(reg) ? 3 : 1;
114 /* FP register starts at bit position 16 */
115 shift = ARM_FPREG(reg) ? kArmFPReg0 : 0;
116 /* Expand the double register id into single offset */
117 shift += reg_id;
118 return (seed << shift);
119}
120
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700121uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700122 return ENCODE_ARM_REG_PC;
123}
124
buzbeeb48819d2013-09-14 16:15:25 -0700125// Thumb2 specific setup. TODO: inline?:
126void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700127 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700128 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700129
Brian Carlstrom7940e442013-07-12 13:46:57 -0700130 int opcode = lir->opcode;
131
buzbeeb48819d2013-09-14 16:15:25 -0700132 // These flags are somewhat uncommon - bypass if we can.
133 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
134 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
135 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
136 if (flags & REG_DEF_SP) {
137 lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700138 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700139
buzbeeb48819d2013-09-14 16:15:25 -0700140 if (flags & REG_USE_SP) {
141 lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700142 }
buzbeeb48819d2013-09-14 16:15:25 -0700143
144 if (flags & REG_DEF_LIST0) {
145 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700146 }
buzbeeb48819d2013-09-14 16:15:25 -0700147
148 if (flags & REG_DEF_LIST1) {
149 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
150 }
151
152 if (flags & REG_DEF_FPCS_LIST0) {
153 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
154 }
155
156 if (flags & REG_DEF_FPCS_LIST2) {
157 for (int i = 0; i < lir->operands[2]; i++) {
158 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
159 }
160 }
161
162 if (flags & REG_USE_PC) {
163 lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
164 }
165
166 /* Conservatively treat the IT block */
167 if (flags & IS_IT) {
168 lir->u.m.def_mask = ENCODE_ALL;
169 }
170
171 if (flags & REG_USE_LIST0) {
172 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
173 }
174
175 if (flags & REG_USE_LIST1) {
176 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
177 }
178
179 if (flags & REG_USE_FPCS_LIST0) {
180 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
181 }
182
183 if (flags & REG_USE_FPCS_LIST2) {
184 for (int i = 0; i < lir->operands[2]; i++) {
185 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
186 }
187 }
188 /* Fixup for kThumbPush/lr and kThumbPop/pc */
189 if (opcode == kThumbPush || opcode == kThumbPop) {
190 uint64_t r8Mask = GetRegMaskCommon(r8);
191 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
192 lir->u.m.use_mask &= ~r8Mask;
193 lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
194 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
195 lir->u.m.def_mask &= ~r8Mask;
196 lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
197 }
198 }
199 if (flags & REG_DEF_LR) {
200 lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
201 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700202 }
203}
204
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700205ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700206 ArmConditionCode res;
207 switch (ccode) {
208 case kCondEq: res = kArmCondEq; break;
209 case kCondNe: res = kArmCondNe; break;
210 case kCondCs: res = kArmCondCs; break;
211 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000212 case kCondUlt: res = kArmCondCc; break;
213 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700214 case kCondMi: res = kArmCondMi; break;
215 case kCondPl: res = kArmCondPl; break;
216 case kCondVs: res = kArmCondVs; break;
217 case kCondVc: res = kArmCondVc; break;
218 case kCondHi: res = kArmCondHi; break;
219 case kCondLs: res = kArmCondLs; break;
220 case kCondGe: res = kArmCondGe; break;
221 case kCondLt: res = kArmCondLt; break;
222 case kCondGt: res = kArmCondGt; break;
223 case kCondLe: res = kArmCondLe; break;
224 case kCondAl: res = kArmCondAl; break;
225 case kCondNv: res = kArmCondNv; break;
226 default:
227 LOG(FATAL) << "Bad condition code " << ccode;
228 res = static_cast<ArmConditionCode>(0); // Quiet gcc
229 }
230 return res;
231}
232
233static const char* core_reg_names[16] = {
234 "r0",
235 "r1",
236 "r2",
237 "r3",
238 "r4",
239 "r5",
240 "r6",
241 "r7",
242 "r8",
243 "rSELF",
244 "r10",
245 "r11",
246 "r12",
247 "sp",
248 "lr",
249 "pc",
250};
251
252
253static const char* shift_names[4] = {
254 "lsl",
255 "lsr",
256 "asr",
257 "ror"};
258
259/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800260static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700261 int i;
262 bool printed = false;
263 buf[0] = 0;
264 for (i = 0; i < 16; i++, vector >>= 1) {
265 if (vector & 0x1) {
266 int reg_id = i;
267 if (opcode == kThumbPush && i == 8) {
268 reg_id = r14lr;
269 } else if (opcode == kThumbPop && i == 8) {
270 reg_id = r15pc;
271 }
272 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800273 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700274 } else {
275 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800276 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700277 }
278 }
279 }
280 return buf;
281}
282
Ian Rogers988e6ea2014-01-08 11:30:50 -0800283static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
284 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700285 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800286 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 }
288 return buf;
289}
290
buzbee0d829482013-10-11 15:24:55 -0700291static int32_t ExpandImmediate(int value) {
292 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700293 uint32_t bits = value & 0xff;
294 switch (mode) {
295 case 0:
296 return bits;
297 case 1:
298 return (bits << 16) | bits;
299 case 2:
300 return (bits << 24) | (bits << 8);
301 case 3:
302 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
303 default:
304 break;
305 }
306 bits = (bits | 0x80) << 24;
307 return bits >> (((value & 0xf80) >> 7) - 8);
308}
309
Brian Carlstromb1eba212013-07-17 18:07:19 -0700310const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
311 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700312/*
313 * Interpret a format string and build a string no longer than size
314 * See format key in Assemble.c.
315 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700316std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700317 std::string buf;
318 int i;
319 const char* fmt_end = &fmt[strlen(fmt)];
320 char tbuf[256];
321 const char* name;
322 char nc;
323 while (fmt < fmt_end) {
324 int operand;
325 if (*fmt == '!') {
326 fmt++;
327 DCHECK_LT(fmt, fmt_end);
328 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700329 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700330 strcpy(tbuf, "!");
331 } else {
332 DCHECK_LT(fmt, fmt_end);
333 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
334 operand = lir->operands[nc-'0'];
335 switch (*fmt++) {
336 case 'H':
337 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800338 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700339 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700340 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341 }
342 break;
343 case 'B':
344 switch (operand) {
345 case kSY:
346 name = "sy";
347 break;
348 case kST:
349 name = "st";
350 break;
351 case kISH:
352 name = "ish";
353 break;
354 case kISHST:
355 name = "ishst";
356 break;
357 case kNSH:
358 name = "nsh";
359 break;
360 case kNSHST:
361 name = "shst";
362 break;
363 default:
364 name = "DecodeError2";
365 break;
366 }
367 strcpy(tbuf, name);
368 break;
369 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700370 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700371 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700372 tbuf[i] += operand & 1;
373 operand >>= 1;
374 }
375 break;
376 case 'n':
377 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800378 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700379 break;
380 case 'm':
381 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800382 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700383 break;
384 case 's':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800385 snprintf(tbuf, arraysize(tbuf), "s%d", operand & ARM_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700386 break;
387 case 'S':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800388 snprintf(tbuf, arraysize(tbuf), "d%d", (operand & ARM_FP_REG_MASK) >> 1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700389 break;
390 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800391 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700392 break;
393 case 'M':
394 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800395 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700396 break;
397 case 'C':
398 DCHECK_LT(operand, static_cast<int>(
399 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800400 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700401 break;
402 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800403 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700404 break;
405 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800406 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700407 break;
408 case 'c':
409 strcpy(tbuf, cc_names[operand]);
410 break;
411 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800412 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
413 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700414 lir->target);
415 break;
416 case 'u': {
417 int offset_1 = lir->operands[0];
418 int offset_2 = NEXT_LIR(lir)->operands[0];
419 uintptr_t target =
420 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
421 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
422 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800423 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700424 break;
425 }
426
427 /* Nothing to print for BLX_2 */
428 case 'v':
429 strcpy(tbuf, "see above");
430 break;
431 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800432 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433 break;
434 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800435 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700436 break;
437 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800438 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700439 break;
440 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700441 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700442 break;
443 }
444 buf += tbuf;
445 }
446 } else {
447 buf += *fmt++;
448 }
449 }
450 return buf;
451}
452
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700453void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700454 char buf[256];
455 buf[0] = 0;
456
457 if (mask == ENCODE_ALL) {
458 strcpy(buf, "all");
459 } else {
460 char num[8];
461 int i;
462
463 for (i = 0; i < kArmRegEnd; i++) {
464 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800465 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700466 strcat(buf, num);
467 }
468 }
469
470 if (mask & ENCODE_CCODE) {
471 strcat(buf, "cc ");
472 }
473 if (mask & ENCODE_FP_STATUS) {
474 strcat(buf, "fpcc ");
475 }
476
477 /* Memory bits */
478 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800479 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
480 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
481 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700482 }
483 if (mask & ENCODE_LITERAL) {
484 strcat(buf, "lit ");
485 }
486
487 if (mask & ENCODE_HEAP_REF) {
488 strcat(buf, "heap ");
489 }
490 if (mask & ENCODE_MUST_NOT_ALIAS) {
491 strcat(buf, "noalias ");
492 }
493 }
494 if (buf[0]) {
495 LOG(INFO) << prefix << ": " << buf;
496 }
497}
498
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700499bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700500 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
501}
502
503ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
504 : Mir2Lir(cu, mir_graph, arena) {
505 // Sanity check - make sure encoding map lines up.
506 for (int i = 0; i < kArmLast; i++) {
507 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
508 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
509 << " is wrong: expecting " << i << ", seeing "
510 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
511 }
512 }
513}
514
515Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
516 ArenaAllocator* const arena) {
517 return new ArmMir2Lir(cu, mir_graph, arena);
518}
519
520/*
521 * Alloc a pair of core registers, or a double. Low reg in low byte,
522 * high reg in next byte.
523 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700524int ArmMir2Lir::AllocTypedTempPair(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700525 int high_reg;
526 int low_reg;
527 int res = 0;
528
529 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
530 low_reg = AllocTempDouble();
531 high_reg = low_reg + 1;
532 } else {
533 low_reg = AllocTemp();
534 high_reg = AllocTemp();
535 }
536 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
537 return res;
538}
539
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700540int ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700541 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
542 return AllocTempFloat();
543 return AllocTemp();
544}
545
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700546void ArmMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700547 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
548 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
549 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
550 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
551 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700552 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
553 ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700554 reg_pool_->num_core_regs = num_regs;
555 reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700556 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700557 reg_pool_->num_fp_regs = num_fp_regs;
558 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700559 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700560 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
561 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
562 // Keep special registers from being allocated
563 for (int i = 0; i < num_reserved; i++) {
564 if (NO_SUSPEND && (ReservedRegs[i] == rARM_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700565 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700566 continue;
567 }
568 MarkInUse(ReservedRegs[i]);
569 }
570 // Mark temp regs - all others not in use can be used for promotion
571 for (int i = 0; i < num_temps; i++) {
572 MarkTemp(core_temps[i]);
573 }
574 for (int i = 0; i < num_fp_temps; i++) {
575 MarkTemp(fp_temps[i]);
576 }
577
578 // Start allocation at r2 in an attempt to avoid clobbering return values
579 reg_pool_->next_core_reg = r2;
580}
581
582void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700583 RegLocation rl_free) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700584 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
585 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
586 // No overlap, free both
587 FreeTemp(rl_free.low_reg);
588 FreeTemp(rl_free.high_reg);
589 }
590}
591/*
592 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
593 * instructions might call out to C/assembly helper functions. Until
594 * machinery is in place, always spill lr.
595 */
596
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700597void ArmMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700598 core_spill_mask_ |= (1 << rARM_LR);
599 num_core_spills_++;
600}
601
602/*
603 * Mark a callee-save fp register as promoted. Note that
604 * vpush/vpop uses contiguous register lists so we must
605 * include any holes in the mask. Associate holes with
606 * Dalvik register INVALID_VREG (0xFFFFU).
607 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700608void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700609 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
610 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
611 // Ensure fp_vmap_table is large enough
612 int table_size = fp_vmap_table_.size();
613 for (int i = table_size; i < (reg + 1); i++) {
614 fp_vmap_table_.push_back(INVALID_VREG);
615 }
616 // Add the current mapping
617 fp_vmap_table_[reg] = v_reg;
618 // Size of fp_vmap_table is high-water mark, use to set mask
619 num_fp_spills_ = fp_vmap_table_.size();
620 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
621}
622
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700623void ArmMir2Lir::FlushRegWide(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700624 RegisterInfo* info1 = GetRegInfo(reg1);
625 RegisterInfo* info2 = GetRegInfo(reg2);
626 DCHECK(info1 && info2 && info1->pair && info2->pair &&
627 (info1->partner == info2->reg) &&
628 (info2->partner == info1->reg));
629 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
630 if (!(info1->is_temp && info2->is_temp)) {
631 /* Should not happen. If it does, there's a problem in eval_loc */
632 LOG(FATAL) << "Long half-temp, half-promoted";
633 }
634
635 info1->dirty = false;
636 info2->dirty = false;
637 if (mir_graph_->SRegToVReg(info2->s_reg) <
638 mir_graph_->SRegToVReg(info1->s_reg))
639 info1 = info2;
640 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
641 StoreBaseDispWide(rARM_SP, VRegOffset(v_reg), info1->reg, info1->partner);
642 }
643}
644
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700645void ArmMir2Lir::FlushReg(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700646 RegisterInfo* info = GetRegInfo(reg);
647 if (info->live && info->dirty) {
648 info->dirty = false;
649 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
650 StoreBaseDisp(rARM_SP, VRegOffset(v_reg), reg, kWord);
651 }
652}
653
654/* Give access to the target-dependent FP register encoding to common code */
655bool ArmMir2Lir::IsFpReg(int reg) {
656 return ARM_FPREG(reg);
657}
658
659/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000660void ArmMir2Lir::ClobberCallerSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700661 Clobber(r0);
662 Clobber(r1);
663 Clobber(r2);
664 Clobber(r3);
665 Clobber(r12);
666 Clobber(r14lr);
667 Clobber(fr0);
668 Clobber(fr1);
669 Clobber(fr2);
670 Clobber(fr3);
671 Clobber(fr4);
672 Clobber(fr5);
673 Clobber(fr6);
674 Clobber(fr7);
675 Clobber(fr8);
676 Clobber(fr9);
677 Clobber(fr10);
678 Clobber(fr11);
679 Clobber(fr12);
680 Clobber(fr13);
681 Clobber(fr14);
682 Clobber(fr15);
683}
684
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700685RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700686 RegLocation res = LocCReturnWide();
687 res.low_reg = r2;
688 res.high_reg = r3;
689 Clobber(r2);
690 Clobber(r3);
691 MarkInUse(r2);
692 MarkInUse(r3);
693 MarkPair(res.low_reg, res.high_reg);
694 return res;
695}
696
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700697RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700698 RegLocation res = LocCReturn();
699 res.low_reg = r1;
700 Clobber(r1);
701 MarkInUse(r1);
702 return res;
703}
704
Brian Carlstrom7940e442013-07-12 13:46:57 -0700705/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700706void ArmMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700707 LockTemp(r0);
708 LockTemp(r1);
709 LockTemp(r2);
710 LockTemp(r3);
711}
712
713/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700714void ArmMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700715 FreeTemp(r0);
716 FreeTemp(r1);
717 FreeTemp(r2);
718 FreeTemp(r3);
719}
720
Ian Rogers468532e2013-08-05 10:56:33 -0700721int ArmMir2Lir::LoadHelper(ThreadOffset offset) {
722 LoadWordDisp(rARM_SELF, offset.Int32Value(), rARM_LR);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700723 return rARM_LR;
724}
725
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700726uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700727 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700728 return ArmMir2Lir::EncodingMap[opcode].flags;
729}
730
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700731const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700732 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700733 return ArmMir2Lir::EncodingMap[opcode].name;
734}
735
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700736const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700737 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700738 return ArmMir2Lir::EncodingMap[opcode].fmt;
739}
740
741} // namespace art