blob: 83431ad235e46eb11d8430cb226f72a297fb3867 [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() {
Bill Buzbee86ec5202014-02-26 19:03:09 +000040 RegLocation res = ARM_LOC_C_RETURN;
41 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -070042}
43
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070044RegLocation ArmMir2Lir::LocCReturnWide() {
Bill Buzbee86ec5202014-02-26 19:03:09 +000045 RegLocation res = ARM_LOC_C_RETURN_WIDE;
46 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -070047}
48
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070049RegLocation ArmMir2Lir::LocCReturnFloat() {
Bill Buzbee86ec5202014-02-26 19:03:09 +000050 RegLocation res = ARM_LOC_C_RETURN_FLOAT;
51 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -070052}
53
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070054RegLocation ArmMir2Lir::LocCReturnDouble() {
Bill Buzbee86ec5202014-02-26 19:03:09 +000055 RegLocation res = ARM_LOC_C_RETURN_DOUBLE;
56 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -070057}
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
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080086int ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
87 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
88 switch (arg_num) {
89 case 0:
90 return rARM_ARG1;
91 case 1:
92 return rARM_ARG2;
93 case 2:
94 return rARM_ARG3;
95 default:
96 return INVALID_REG;
97 }
98}
Brian Carlstrom7940e442013-07-12 13:46:57 -070099
100// Create a double from a pair of singles.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700101int ArmMir2Lir::S2d(int low_reg, int high_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700102 return ARM_S2D(low_reg, high_reg);
103}
104
105// Return mask to strip off fp reg flags and bias.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700106uint32_t ArmMir2Lir::FpRegMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700107 return ARM_FP_REG_MASK;
108}
109
110// True if both regs single, both core or both double.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700111bool ArmMir2Lir::SameRegType(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700112 return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2));
113}
114
115/*
116 * Decode the register id.
117 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700118uint64_t ArmMir2Lir::GetRegMaskCommon(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700119 uint64_t seed;
120 int shift;
121 int reg_id;
122
123
124 reg_id = reg & 0x1f;
125 /* Each double register is equal to a pair of single-precision FP registers */
126 seed = ARM_DOUBLEREG(reg) ? 3 : 1;
127 /* FP register starts at bit position 16 */
128 shift = ARM_FPREG(reg) ? kArmFPReg0 : 0;
129 /* Expand the double register id into single offset */
130 shift += reg_id;
131 return (seed << shift);
132}
133
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700134uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135 return ENCODE_ARM_REG_PC;
136}
137
buzbeeb48819d2013-09-14 16:15:25 -0700138// Thumb2 specific setup. TODO: inline?:
139void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700140 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700141 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700142
Brian Carlstrom7940e442013-07-12 13:46:57 -0700143 int opcode = lir->opcode;
144
buzbeeb48819d2013-09-14 16:15:25 -0700145 // These flags are somewhat uncommon - bypass if we can.
146 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
147 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
148 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
149 if (flags & REG_DEF_SP) {
150 lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700151 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700152
buzbeeb48819d2013-09-14 16:15:25 -0700153 if (flags & REG_USE_SP) {
154 lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700155 }
buzbeeb48819d2013-09-14 16:15:25 -0700156
157 if (flags & REG_DEF_LIST0) {
158 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700159 }
buzbeeb48819d2013-09-14 16:15:25 -0700160
161 if (flags & REG_DEF_LIST1) {
162 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
163 }
164
165 if (flags & REG_DEF_FPCS_LIST0) {
166 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
167 }
168
169 if (flags & REG_DEF_FPCS_LIST2) {
170 for (int i = 0; i < lir->operands[2]; i++) {
171 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
172 }
173 }
174
175 if (flags & REG_USE_PC) {
176 lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
177 }
178
179 /* Conservatively treat the IT block */
180 if (flags & IS_IT) {
181 lir->u.m.def_mask = ENCODE_ALL;
182 }
183
184 if (flags & REG_USE_LIST0) {
185 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
186 }
187
188 if (flags & REG_USE_LIST1) {
189 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
190 }
191
192 if (flags & REG_USE_FPCS_LIST0) {
193 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
194 }
195
196 if (flags & REG_USE_FPCS_LIST2) {
197 for (int i = 0; i < lir->operands[2]; i++) {
198 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
199 }
200 }
201 /* Fixup for kThumbPush/lr and kThumbPop/pc */
202 if (opcode == kThumbPush || opcode == kThumbPop) {
203 uint64_t r8Mask = GetRegMaskCommon(r8);
204 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
205 lir->u.m.use_mask &= ~r8Mask;
206 lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
207 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
208 lir->u.m.def_mask &= ~r8Mask;
209 lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
210 }
211 }
212 if (flags & REG_DEF_LR) {
213 lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
214 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700215 }
216}
217
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700218ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700219 ArmConditionCode res;
220 switch (ccode) {
221 case kCondEq: res = kArmCondEq; break;
222 case kCondNe: res = kArmCondNe; break;
223 case kCondCs: res = kArmCondCs; break;
224 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000225 case kCondUlt: res = kArmCondCc; break;
226 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700227 case kCondMi: res = kArmCondMi; break;
228 case kCondPl: res = kArmCondPl; break;
229 case kCondVs: res = kArmCondVs; break;
230 case kCondVc: res = kArmCondVc; break;
231 case kCondHi: res = kArmCondHi; break;
232 case kCondLs: res = kArmCondLs; break;
233 case kCondGe: res = kArmCondGe; break;
234 case kCondLt: res = kArmCondLt; break;
235 case kCondGt: res = kArmCondGt; break;
236 case kCondLe: res = kArmCondLe; break;
237 case kCondAl: res = kArmCondAl; break;
238 case kCondNv: res = kArmCondNv; break;
239 default:
240 LOG(FATAL) << "Bad condition code " << ccode;
241 res = static_cast<ArmConditionCode>(0); // Quiet gcc
242 }
243 return res;
244}
245
246static const char* core_reg_names[16] = {
247 "r0",
248 "r1",
249 "r2",
250 "r3",
251 "r4",
252 "r5",
253 "r6",
254 "r7",
255 "r8",
256 "rSELF",
257 "r10",
258 "r11",
259 "r12",
260 "sp",
261 "lr",
262 "pc",
263};
264
265
266static const char* shift_names[4] = {
267 "lsl",
268 "lsr",
269 "asr",
270 "ror"};
271
272/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800273static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700274 int i;
275 bool printed = false;
276 buf[0] = 0;
277 for (i = 0; i < 16; i++, vector >>= 1) {
278 if (vector & 0x1) {
279 int reg_id = i;
280 if (opcode == kThumbPush && i == 8) {
281 reg_id = r14lr;
282 } else if (opcode == kThumbPop && i == 8) {
283 reg_id = r15pc;
284 }
285 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800286 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 } else {
288 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800289 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700290 }
291 }
292 }
293 return buf;
294}
295
Ian Rogers988e6ea2014-01-08 11:30:50 -0800296static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
297 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700298 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800299 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700300 }
301 return buf;
302}
303
buzbee0d829482013-10-11 15:24:55 -0700304static int32_t ExpandImmediate(int value) {
305 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700306 uint32_t bits = value & 0xff;
307 switch (mode) {
308 case 0:
309 return bits;
310 case 1:
311 return (bits << 16) | bits;
312 case 2:
313 return (bits << 24) | (bits << 8);
314 case 3:
315 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
316 default:
317 break;
318 }
319 bits = (bits | 0x80) << 24;
320 return bits >> (((value & 0xf80) >> 7) - 8);
321}
322
Brian Carlstromb1eba212013-07-17 18:07:19 -0700323const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
324 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700325/*
326 * Interpret a format string and build a string no longer than size
327 * See format key in Assemble.c.
328 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700329std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700330 std::string buf;
331 int i;
332 const char* fmt_end = &fmt[strlen(fmt)];
333 char tbuf[256];
334 const char* name;
335 char nc;
336 while (fmt < fmt_end) {
337 int operand;
338 if (*fmt == '!') {
339 fmt++;
340 DCHECK_LT(fmt, fmt_end);
341 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700342 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700343 strcpy(tbuf, "!");
344 } else {
345 DCHECK_LT(fmt, fmt_end);
346 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
347 operand = lir->operands[nc-'0'];
348 switch (*fmt++) {
349 case 'H':
350 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800351 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700352 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700353 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700354 }
355 break;
356 case 'B':
357 switch (operand) {
358 case kSY:
359 name = "sy";
360 break;
361 case kST:
362 name = "st";
363 break;
364 case kISH:
365 name = "ish";
366 break;
367 case kISHST:
368 name = "ishst";
369 break;
370 case kNSH:
371 name = "nsh";
372 break;
373 case kNSHST:
374 name = "shst";
375 break;
376 default:
377 name = "DecodeError2";
378 break;
379 }
380 strcpy(tbuf, name);
381 break;
382 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700383 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700384 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700385 tbuf[i] += operand & 1;
386 operand >>= 1;
387 }
388 break;
389 case 'n':
390 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800391 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700392 break;
393 case 'm':
394 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800395 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700396 break;
397 case 's':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800398 snprintf(tbuf, arraysize(tbuf), "s%d", operand & ARM_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700399 break;
400 case 'S':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800401 snprintf(tbuf, arraysize(tbuf), "d%d", (operand & ARM_FP_REG_MASK) >> 1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700402 break;
403 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800404 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700405 break;
406 case 'M':
407 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800408 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700409 break;
410 case 'C':
411 DCHECK_LT(operand, static_cast<int>(
412 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800413 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700414 break;
415 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800416 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700417 break;
418 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800419 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700420 break;
421 case 'c':
422 strcpy(tbuf, cc_names[operand]);
423 break;
424 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800425 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
426 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700427 lir->target);
428 break;
429 case 'u': {
430 int offset_1 = lir->operands[0];
431 int offset_2 = NEXT_LIR(lir)->operands[0];
432 uintptr_t target =
433 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
434 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
435 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800436 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700437 break;
438 }
439
440 /* Nothing to print for BLX_2 */
441 case 'v':
442 strcpy(tbuf, "see above");
443 break;
444 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800445 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700446 break;
447 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800448 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700449 break;
450 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800451 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700452 break;
453 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700454 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700455 break;
456 }
457 buf += tbuf;
458 }
459 } else {
460 buf += *fmt++;
461 }
462 }
463 return buf;
464}
465
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700466void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700467 char buf[256];
468 buf[0] = 0;
469
470 if (mask == ENCODE_ALL) {
471 strcpy(buf, "all");
472 } else {
473 char num[8];
474 int i;
475
476 for (i = 0; i < kArmRegEnd; i++) {
477 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800478 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700479 strcat(buf, num);
480 }
481 }
482
483 if (mask & ENCODE_CCODE) {
484 strcat(buf, "cc ");
485 }
486 if (mask & ENCODE_FP_STATUS) {
487 strcat(buf, "fpcc ");
488 }
489
490 /* Memory bits */
491 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800492 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
493 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
494 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700495 }
496 if (mask & ENCODE_LITERAL) {
497 strcat(buf, "lit ");
498 }
499
500 if (mask & ENCODE_HEAP_REF) {
501 strcat(buf, "heap ");
502 }
503 if (mask & ENCODE_MUST_NOT_ALIAS) {
504 strcat(buf, "noalias ");
505 }
506 }
507 if (buf[0]) {
508 LOG(INFO) << prefix << ": " << buf;
509 }
510}
511
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700512bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700513 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
514}
515
516ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
517 : Mir2Lir(cu, mir_graph, arena) {
518 // Sanity check - make sure encoding map lines up.
519 for (int i = 0; i < kArmLast; i++) {
520 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
521 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
522 << " is wrong: expecting " << i << ", seeing "
523 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
524 }
525 }
526}
527
528Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
529 ArenaAllocator* const arena) {
530 return new ArmMir2Lir(cu, mir_graph, arena);
531}
532
Bill Buzbee86ec5202014-02-26 19:03:09 +0000533/*
534 * Alloc a pair of core registers, or a double. Low reg in low byte,
535 * high reg in next byte.
536 */
537int ArmMir2Lir::AllocTypedTempPair(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700538 int high_reg;
539 int low_reg;
Bill Buzbee86ec5202014-02-26 19:03:09 +0000540 int res = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700541
542 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
543 low_reg = AllocTempDouble();
544 high_reg = low_reg + 1;
545 } else {
546 low_reg = AllocTemp();
547 high_reg = AllocTemp();
548 }
Bill Buzbee86ec5202014-02-26 19:03:09 +0000549 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
550 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700551}
552
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700553int ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700554 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
555 return AllocTempFloat();
556 return AllocTemp();
557}
558
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700559void ArmMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700560 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
561 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
562 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
563 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
564 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700565 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
566 ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700567 reg_pool_->num_core_regs = num_regs;
568 reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700569 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700570 reg_pool_->num_fp_regs = num_fp_regs;
571 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700572 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700573 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
574 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
575 // Keep special registers from being allocated
576 for (int i = 0; i < num_reserved; i++) {
577 if (NO_SUSPEND && (ReservedRegs[i] == rARM_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700578 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700579 continue;
580 }
581 MarkInUse(ReservedRegs[i]);
582 }
583 // Mark temp regs - all others not in use can be used for promotion
584 for (int i = 0; i < num_temps; i++) {
585 MarkTemp(core_temps[i]);
586 }
587 for (int i = 0; i < num_fp_temps; i++) {
588 MarkTemp(fp_temps[i]);
589 }
590
591 // Start allocation at r2 in an attempt to avoid clobbering return values
592 reg_pool_->next_core_reg = r2;
593}
594
595void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700596 RegLocation rl_free) {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000597 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
598 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700599 // No overlap, free both
Bill Buzbee86ec5202014-02-26 19:03:09 +0000600 FreeTemp(rl_free.low_reg);
601 FreeTemp(rl_free.high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700602 }
603}
604/*
605 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
606 * instructions might call out to C/assembly helper functions. Until
607 * machinery is in place, always spill lr.
608 */
609
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700610void ArmMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700611 core_spill_mask_ |= (1 << rARM_LR);
612 num_core_spills_++;
613}
614
615/*
616 * Mark a callee-save fp register as promoted. Note that
617 * vpush/vpop uses contiguous register lists so we must
618 * include any holes in the mask. Associate holes with
619 * Dalvik register INVALID_VREG (0xFFFFU).
620 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700621void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700622 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
623 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
624 // Ensure fp_vmap_table is large enough
625 int table_size = fp_vmap_table_.size();
626 for (int i = table_size; i < (reg + 1); i++) {
627 fp_vmap_table_.push_back(INVALID_VREG);
628 }
629 // Add the current mapping
630 fp_vmap_table_[reg] = v_reg;
631 // Size of fp_vmap_table is high-water mark, use to set mask
632 num_fp_spills_ = fp_vmap_table_.size();
633 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
634}
635
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700636void ArmMir2Lir::FlushRegWide(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700637 RegisterInfo* info1 = GetRegInfo(reg1);
638 RegisterInfo* info2 = GetRegInfo(reg2);
639 DCHECK(info1 && info2 && info1->pair && info2->pair &&
640 (info1->partner == info2->reg) &&
641 (info2->partner == info1->reg));
642 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
643 if (!(info1->is_temp && info2->is_temp)) {
644 /* Should not happen. If it does, there's a problem in eval_loc */
645 LOG(FATAL) << "Long half-temp, half-promoted";
646 }
647
648 info1->dirty = false;
649 info2->dirty = false;
650 if (mir_graph_->SRegToVReg(info2->s_reg) <
651 mir_graph_->SRegToVReg(info1->s_reg))
652 info1 = info2;
653 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
654 StoreBaseDispWide(rARM_SP, VRegOffset(v_reg), info1->reg, info1->partner);
655 }
656}
657
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700658void ArmMir2Lir::FlushReg(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700659 RegisterInfo* info = GetRegInfo(reg);
660 if (info->live && info->dirty) {
661 info->dirty = false;
662 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
663 StoreBaseDisp(rARM_SP, VRegOffset(v_reg), reg, kWord);
664 }
665}
666
667/* Give access to the target-dependent FP register encoding to common code */
668bool ArmMir2Lir::IsFpReg(int reg) {
669 return ARM_FPREG(reg);
670}
671
672/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000673void ArmMir2Lir::ClobberCallerSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700674 Clobber(r0);
675 Clobber(r1);
676 Clobber(r2);
677 Clobber(r3);
678 Clobber(r12);
679 Clobber(r14lr);
680 Clobber(fr0);
681 Clobber(fr1);
682 Clobber(fr2);
683 Clobber(fr3);
684 Clobber(fr4);
685 Clobber(fr5);
686 Clobber(fr6);
687 Clobber(fr7);
688 Clobber(fr8);
689 Clobber(fr9);
690 Clobber(fr10);
691 Clobber(fr11);
692 Clobber(fr12);
693 Clobber(fr13);
694 Clobber(fr14);
695 Clobber(fr15);
696}
697
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700698RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700699 RegLocation res = LocCReturnWide();
Bill Buzbee86ec5202014-02-26 19:03:09 +0000700 res.low_reg = r2;
701 res.high_reg = r3;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700702 Clobber(r2);
703 Clobber(r3);
704 MarkInUse(r2);
705 MarkInUse(r3);
Bill Buzbee86ec5202014-02-26 19:03:09 +0000706 MarkPair(res.low_reg, res.high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700707 return res;
708}
709
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700710RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700711 RegLocation res = LocCReturn();
Bill Buzbee86ec5202014-02-26 19:03:09 +0000712 res.low_reg = r1;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700713 Clobber(r1);
714 MarkInUse(r1);
715 return res;
716}
717
Brian Carlstrom7940e442013-07-12 13:46:57 -0700718/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700719void ArmMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700720 LockTemp(r0);
721 LockTemp(r1);
722 LockTemp(r2);
723 LockTemp(r3);
724}
725
726/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700727void ArmMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700728 FreeTemp(r0);
729 FreeTemp(r1);
730 FreeTemp(r2);
731 FreeTemp(r3);
732}
733
Ian Rogers468532e2013-08-05 10:56:33 -0700734int ArmMir2Lir::LoadHelper(ThreadOffset offset) {
735 LoadWordDisp(rARM_SELF, offset.Int32Value(), rARM_LR);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700736 return rARM_LR;
737}
738
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700739uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700740 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700741 return ArmMir2Lir::EncodingMap[opcode].flags;
742}
743
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700744const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700745 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700746 return ArmMir2Lir::EncodingMap[opcode].name;
747}
748
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700749const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700750 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700751 return ArmMir2Lir::EncodingMap[opcode].fmt;
752}
753
754} // namespace art