blob: 272dc46716e40efbe0c3db4b72792053524ac94e [file] [log] [blame]
buzbeeefc63692012-11-14 16:31:52 -08001/*
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 "../../compiler_internals.h"
18#include "arm_lir.h"
buzbee02031b12012-11-23 09:41:35 -080019#include "codegen_arm.h"
buzbeeeaf09bc2012-11-15 14:51:41 -080020#include "../ralloc_util.h"
21#include "../codegen_util.h"
buzbeeefc63692012-11-14 16:31:52 -080022
23#include <string>
24
25namespace art {
26
buzbeefa57c472012-11-21 12:06:18 -080027static int core_regs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10,
buzbeeefc63692012-11-14 16:31:52 -080028 r11, r12, rARM_SP, rARM_LR, rARM_PC};
buzbee52a77fc2012-11-20 19:50:46 -080029static int ReservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC};
30static int FpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
buzbeeefc63692012-11-14 16:31:52 -080031 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
32 fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
33 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
buzbeefa57c472012-11-21 12:06:18 -080034static int core_temps[] = {r0, r1, r2, r3, r12};
35static int fp_temps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
buzbeeefc63692012-11-14 16:31:52 -080036 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
37
buzbee02031b12012-11-23 09:41:35 -080038RegLocation ArmCodegen::LocCReturn()
buzbeeefc63692012-11-14 16:31:52 -080039{
40 RegLocation res = ARM_LOC_C_RETURN;
41 return res;
42}
43
buzbee02031b12012-11-23 09:41:35 -080044RegLocation ArmCodegen::LocCReturnWide()
buzbeeefc63692012-11-14 16:31:52 -080045{
46 RegLocation res = ARM_LOC_C_RETURN_WIDE;
47 return res;
48}
49
buzbee02031b12012-11-23 09:41:35 -080050RegLocation ArmCodegen::LocCReturnFloat()
buzbeeefc63692012-11-14 16:31:52 -080051{
52 RegLocation res = ARM_LOC_C_RETURN_FLOAT;
53 return res;
54}
55
buzbee02031b12012-11-23 09:41:35 -080056RegLocation ArmCodegen::LocCReturnDouble()
buzbeeefc63692012-11-14 16:31:52 -080057{
58 RegLocation res = ARM_LOC_C_RETURN_DOUBLE;
59 return res;
60}
61
62// Return a target-dependent special register.
buzbee02031b12012-11-23 09:41:35 -080063int ArmCodegen::TargetReg(SpecialTargetRegister reg) {
buzbeeefc63692012-11-14 16:31:52 -080064 int res = INVALID_REG;
65 switch (reg) {
66 case kSelf: res = rARM_SELF; break;
67 case kSuspend: res = rARM_SUSPEND; break;
68 case kLr: res = rARM_LR; break;
69 case kPc: res = rARM_PC; break;
70 case kSp: res = rARM_SP; break;
71 case kArg0: res = rARM_ARG0; break;
72 case kArg1: res = rARM_ARG1; break;
73 case kArg2: res = rARM_ARG2; break;
74 case kArg3: res = rARM_ARG3; break;
75 case kFArg0: res = rARM_FARG0; break;
76 case kFArg1: res = rARM_FARG1; break;
77 case kFArg2: res = rARM_FARG2; break;
78 case kFArg3: res = rARM_FARG3; break;
79 case kRet0: res = rARM_RET0; break;
80 case kRet1: res = rARM_RET1; break;
81 case kInvokeTgt: res = rARM_INVOKE_TGT; break;
82 case kCount: res = rARM_COUNT; break;
83 }
84 return res;
85}
86
87
88// Create a double from a pair of singles.
buzbee02031b12012-11-23 09:41:35 -080089int ArmCodegen::S2d(int low_reg, int high_reg)
buzbeeefc63692012-11-14 16:31:52 -080090{
buzbeefa57c472012-11-21 12:06:18 -080091 return ARM_S2D(low_reg, high_reg);
buzbeeefc63692012-11-14 16:31:52 -080092}
93
buzbeeefc63692012-11-14 16:31:52 -080094// Return mask to strip off fp reg flags and bias.
buzbee02031b12012-11-23 09:41:35 -080095uint32_t ArmCodegen::FpRegMask()
buzbeeefc63692012-11-14 16:31:52 -080096{
97 return ARM_FP_REG_MASK;
98}
99
100// True if both regs single, both core or both double.
buzbee02031b12012-11-23 09:41:35 -0800101bool ArmCodegen::SameRegType(int reg1, int reg2)
buzbeeefc63692012-11-14 16:31:52 -0800102{
103 return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2));
104}
105
106/*
107 * Decode the register id.
108 */
buzbee02031b12012-11-23 09:41:35 -0800109uint64_t ArmCodegen::GetRegMaskCommon(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800110{
buzbeeeaf09bc2012-11-15 14:51:41 -0800111 uint64_t seed;
buzbeeefc63692012-11-14 16:31:52 -0800112 int shift;
buzbeefa57c472012-11-21 12:06:18 -0800113 int reg_id;
buzbeeefc63692012-11-14 16:31:52 -0800114
115
buzbeefa57c472012-11-21 12:06:18 -0800116 reg_id = reg & 0x1f;
buzbeeefc63692012-11-14 16:31:52 -0800117 /* Each double register is equal to a pair of single-precision FP registers */
118 seed = ARM_DOUBLEREG(reg) ? 3 : 1;
119 /* FP register starts at bit position 16 */
120 shift = ARM_FPREG(reg) ? kArmFPReg0 : 0;
121 /* Expand the double register id into single offset */
buzbeefa57c472012-11-21 12:06:18 -0800122 shift += reg_id;
buzbeeefc63692012-11-14 16:31:52 -0800123 return (seed << shift);
124}
125
buzbee02031b12012-11-23 09:41:35 -0800126uint64_t ArmCodegen::GetPCUseDefEncoding()
buzbeeefc63692012-11-14 16:31:52 -0800127{
128 return ENCODE_ARM_REG_PC;
129}
130
buzbee02031b12012-11-23 09:41:35 -0800131void ArmCodegen::SetupTargetResourceMasks(CompilationUnit* cu, LIR* lir)
buzbeeefc63692012-11-14 16:31:52 -0800132{
buzbeefa57c472012-11-21 12:06:18 -0800133 DCHECK_EQ(cu->instruction_set, kThumb2);
buzbeeefc63692012-11-14 16:31:52 -0800134
135 // Thumb2 specific setup
buzbee02031b12012-11-23 09:41:35 -0800136 uint64_t flags = ArmCodegen::EncodingMap[lir->opcode].flags;
buzbeeefc63692012-11-14 16:31:52 -0800137 int opcode = lir->opcode;
138
139 if (flags & REG_DEF_SP) {
buzbeefa57c472012-11-21 12:06:18 -0800140 lir->def_mask |= ENCODE_ARM_REG_SP;
buzbeeefc63692012-11-14 16:31:52 -0800141 }
142
143 if (flags & REG_USE_SP) {
buzbeefa57c472012-11-21 12:06:18 -0800144 lir->use_mask |= ENCODE_ARM_REG_SP;
buzbeeefc63692012-11-14 16:31:52 -0800145 }
146
147 if (flags & REG_DEF_LIST0) {
buzbeefa57c472012-11-21 12:06:18 -0800148 lir->def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
buzbeeefc63692012-11-14 16:31:52 -0800149 }
150
151 if (flags & REG_DEF_LIST1) {
buzbeefa57c472012-11-21 12:06:18 -0800152 lir->def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
buzbeeefc63692012-11-14 16:31:52 -0800153 }
154
155 if (flags & REG_DEF_FPCS_LIST0) {
buzbeefa57c472012-11-21 12:06:18 -0800156 lir->def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
buzbeeefc63692012-11-14 16:31:52 -0800157 }
158
159 if (flags & REG_DEF_FPCS_LIST2) {
160 for (int i = 0; i < lir->operands[2]; i++) {
buzbeefa57c472012-11-21 12:06:18 -0800161 SetupRegMask(cu, &lir->def_mask, lir->operands[1] + i);
buzbeeefc63692012-11-14 16:31:52 -0800162 }
163 }
164
165 if (flags & REG_USE_PC) {
buzbeefa57c472012-11-21 12:06:18 -0800166 lir->use_mask |= ENCODE_ARM_REG_PC;
buzbeeefc63692012-11-14 16:31:52 -0800167 }
168
169 /* Conservatively treat the IT block */
170 if (flags & IS_IT) {
buzbeefa57c472012-11-21 12:06:18 -0800171 lir->def_mask = ENCODE_ALL;
buzbeeefc63692012-11-14 16:31:52 -0800172 }
173
174 if (flags & REG_USE_LIST0) {
buzbeefa57c472012-11-21 12:06:18 -0800175 lir->use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
buzbeeefc63692012-11-14 16:31:52 -0800176 }
177
178 if (flags & REG_USE_LIST1) {
buzbeefa57c472012-11-21 12:06:18 -0800179 lir->use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
buzbeeefc63692012-11-14 16:31:52 -0800180 }
181
182 if (flags & REG_USE_FPCS_LIST0) {
buzbeefa57c472012-11-21 12:06:18 -0800183 lir->use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
buzbeeefc63692012-11-14 16:31:52 -0800184 }
185
186 if (flags & REG_USE_FPCS_LIST2) {
187 for (int i = 0; i < lir->operands[2]; i++) {
buzbeefa57c472012-11-21 12:06:18 -0800188 SetupRegMask(cu, &lir->use_mask, lir->operands[1] + i);
buzbeeefc63692012-11-14 16:31:52 -0800189 }
190 }
191 /* Fixup for kThumbPush/lr and kThumbPop/pc */
192 if (opcode == kThumbPush || opcode == kThumbPop) {
buzbeefa57c472012-11-21 12:06:18 -0800193 uint64_t r8Mask = GetRegMaskCommon(cu, r8);
194 if ((opcode == kThumbPush) && (lir->use_mask & r8Mask)) {
195 lir->use_mask &= ~r8Mask;
196 lir->use_mask |= ENCODE_ARM_REG_LR;
197 } else if ((opcode == kThumbPop) && (lir->def_mask & r8Mask)) {
198 lir->def_mask &= ~r8Mask;
199 lir->def_mask |= ENCODE_ARM_REG_PC;
buzbeeefc63692012-11-14 16:31:52 -0800200 }
201 }
202 if (flags & REG_DEF_LR) {
buzbeefa57c472012-11-21 12:06:18 -0800203 lir->def_mask |= ENCODE_ARM_REG_LR;
buzbeeefc63692012-11-14 16:31:52 -0800204 }
205}
206
buzbee02031b12012-11-23 09:41:35 -0800207ArmConditionCode ArmCodegen::ArmConditionEncoding(ConditionCode ccode)
buzbeeefc63692012-11-14 16:31:52 -0800208{
209 ArmConditionCode res;
buzbeecbd6d442012-11-17 14:11:25 -0800210 switch (ccode) {
buzbeeefc63692012-11-14 16:31:52 -0800211 case kCondEq: res = kArmCondEq; break;
212 case kCondNe: res = kArmCondNe; break;
213 case kCondCs: res = kArmCondCs; break;
214 case kCondCc: res = kArmCondCc; break;
215 case kCondMi: res = kArmCondMi; break;
216 case kCondPl: res = kArmCondPl; break;
217 case kCondVs: res = kArmCondVs; break;
218 case kCondVc: res = kArmCondVc; break;
219 case kCondHi: res = kArmCondHi; break;
220 case kCondLs: res = kArmCondLs; break;
221 case kCondGe: res = kArmCondGe; break;
222 case kCondLt: res = kArmCondLt; break;
223 case kCondGt: res = kArmCondGt; break;
224 case kCondLe: res = kArmCondLe; break;
225 case kCondAl: res = kArmCondAl; break;
226 case kCondNv: res = kArmCondNv; break;
227 default:
buzbeecbd6d442012-11-17 14:11:25 -0800228 LOG(FATAL) << "Bad condition code " << ccode;
229 res = static_cast<ArmConditionCode>(0); // Quiet gcc
buzbeeefc63692012-11-14 16:31:52 -0800230 }
231 return res;
232}
233
buzbeefa57c472012-11-21 12:06:18 -0800234static const char* core_reg_names[16] = {
buzbeeefc63692012-11-14 16:31:52 -0800235 "r0",
236 "r1",
237 "r2",
238 "r3",
239 "r4",
240 "r5",
241 "r6",
242 "r7",
243 "r8",
244 "rSELF",
245 "r10",
246 "r11",
247 "r12",
248 "sp",
249 "lr",
250 "pc",
251};
252
253
buzbeefa57c472012-11-21 12:06:18 -0800254static const char* shift_names[4] = {
buzbeeefc63692012-11-14 16:31:52 -0800255 "lsl",
256 "lsr",
257 "asr",
258 "ror"};
259
260/* Decode and print a ARM register name */
buzbeeaad94382012-11-21 07:40:50 -0800261static char* DecodeRegList(int opcode, int vector, char* buf)
buzbeeefc63692012-11-14 16:31:52 -0800262{
263 int i;
264 bool printed = false;
265 buf[0] = 0;
266 for (i = 0; i < 16; i++, vector >>= 1) {
267 if (vector & 0x1) {
buzbeefa57c472012-11-21 12:06:18 -0800268 int reg_id = i;
buzbeeefc63692012-11-14 16:31:52 -0800269 if (opcode == kThumbPush && i == 8) {
buzbeefa57c472012-11-21 12:06:18 -0800270 reg_id = r14lr;
buzbeeefc63692012-11-14 16:31:52 -0800271 } else if (opcode == kThumbPop && i == 8) {
buzbeefa57c472012-11-21 12:06:18 -0800272 reg_id = r15pc;
buzbeeefc63692012-11-14 16:31:52 -0800273 }
274 if (printed) {
buzbeefa57c472012-11-21 12:06:18 -0800275 sprintf(buf + strlen(buf), ", r%d", reg_id);
buzbeeefc63692012-11-14 16:31:52 -0800276 } else {
277 printed = true;
buzbeefa57c472012-11-21 12:06:18 -0800278 sprintf(buf, "r%d", reg_id);
buzbeeefc63692012-11-14 16:31:52 -0800279 }
280 }
281 }
282 return buf;
283}
284
buzbeeaad94382012-11-21 07:40:50 -0800285static char* DecodeFPCSRegList(int count, int base, char* buf)
buzbeeefc63692012-11-14 16:31:52 -0800286{
287 sprintf(buf, "s%d", base);
288 for (int i = 1; i < count; i++) {
289 sprintf(buf + strlen(buf), ", s%d",base + i);
290 }
291 return buf;
292}
293
buzbeeaad94382012-11-21 07:40:50 -0800294static int ExpandImmediate(int value)
buzbeeefc63692012-11-14 16:31:52 -0800295{
296 int mode = (value & 0xf00) >> 8;
buzbeeeaf09bc2012-11-15 14:51:41 -0800297 uint32_t bits = value & 0xff;
buzbeeefc63692012-11-14 16:31:52 -0800298 switch (mode) {
299 case 0:
300 return bits;
301 case 1:
302 return (bits << 16) | bits;
303 case 2:
304 return (bits << 24) | (bits << 8);
305 case 3:
306 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
307 default:
308 break;
309 }
310 bits = (bits | 0x80) << 24;
311 return bits >> (((value & 0xf80) >> 7) - 8);
312}
313
buzbeefa57c472012-11-21 12:06:18 -0800314const char* cc_names[] = {"eq","ne","cs","cc","mi","pl","vs","vc",
buzbeeefc63692012-11-14 16:31:52 -0800315 "hi","ls","ge","lt","gt","le","al","nv"};
316/*
317 * Interpret a format string and build a string no longer than size
318 * See format key in Assemble.c.
319 */
buzbee02031b12012-11-23 09:41:35 -0800320std::string ArmCodegen::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr)
buzbeeefc63692012-11-14 16:31:52 -0800321{
322 std::string buf;
323 int i;
buzbeefa57c472012-11-21 12:06:18 -0800324 const char* fmt_end = &fmt[strlen(fmt)];
buzbeeefc63692012-11-14 16:31:52 -0800325 char tbuf[256];
326 const char* name;
327 char nc;
buzbeefa57c472012-11-21 12:06:18 -0800328 while (fmt < fmt_end) {
buzbeeefc63692012-11-14 16:31:52 -0800329 int operand;
330 if (*fmt == '!') {
331 fmt++;
buzbeefa57c472012-11-21 12:06:18 -0800332 DCHECK_LT(fmt, fmt_end);
buzbeeefc63692012-11-14 16:31:52 -0800333 nc = *fmt++;
334 if (nc=='!') {
335 strcpy(tbuf, "!");
336 } else {
buzbeefa57c472012-11-21 12:06:18 -0800337 DCHECK_LT(fmt, fmt_end);
buzbeecbd6d442012-11-17 14:11:25 -0800338 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
buzbeeefc63692012-11-14 16:31:52 -0800339 operand = lir->operands[nc-'0'];
340 switch (*fmt++) {
341 case 'H':
342 if (operand != 0) {
buzbeefa57c472012-11-21 12:06:18 -0800343 sprintf(tbuf, ", %s %d",shift_names[operand & 0x3], operand >> 2);
buzbeeefc63692012-11-14 16:31:52 -0800344 } else {
345 strcpy(tbuf,"");
346 }
347 break;
348 case 'B':
349 switch (operand) {
350 case kSY:
351 name = "sy";
352 break;
353 case kST:
354 name = "st";
355 break;
356 case kISH:
357 name = "ish";
358 break;
359 case kISHST:
360 name = "ishst";
361 break;
362 case kNSH:
363 name = "nsh";
364 break;
365 case kNSHST:
366 name = "shst";
367 break;
368 default:
369 name = "DecodeError2";
370 break;
371 }
372 strcpy(tbuf, name);
373 break;
374 case 'b':
375 strcpy(tbuf,"0000");
376 for (i=3; i>= 0; i--) {
377 tbuf[i] += operand & 1;
378 operand >>= 1;
379 }
380 break;
381 case 'n':
buzbee52a77fc2012-11-20 19:50:46 -0800382 operand = ~ExpandImmediate(operand);
buzbeeefc63692012-11-14 16:31:52 -0800383 sprintf(tbuf,"%d [%#x]", operand, operand);
384 break;
385 case 'm':
buzbee52a77fc2012-11-20 19:50:46 -0800386 operand = ExpandImmediate(operand);
buzbeeefc63692012-11-14 16:31:52 -0800387 sprintf(tbuf,"%d [%#x]", operand, operand);
388 break;
389 case 's':
390 sprintf(tbuf,"s%d",operand & ARM_FP_REG_MASK);
391 break;
392 case 'S':
393 sprintf(tbuf,"d%d",(operand & ARM_FP_REG_MASK) >> 1);
394 break;
395 case 'h':
396 sprintf(tbuf,"%04x", operand);
397 break;
398 case 'M':
399 case 'd':
400 sprintf(tbuf,"%d", operand);
401 break;
402 case 'C':
403 DCHECK_LT(operand, static_cast<int>(
buzbeefa57c472012-11-21 12:06:18 -0800404 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
405 sprintf(tbuf,"%s",core_reg_names[operand]);
buzbeeefc63692012-11-14 16:31:52 -0800406 break;
407 case 'E':
408 sprintf(tbuf,"%d", operand*4);
409 break;
410 case 'F':
411 sprintf(tbuf,"%d", operand*2);
412 break;
413 case 'c':
buzbeefa57c472012-11-21 12:06:18 -0800414 strcpy(tbuf, cc_names[operand]);
buzbeeefc63692012-11-14 16:31:52 -0800415 break;
416 case 't':
417 sprintf(tbuf,"0x%08x (L%p)",
buzbeefa57c472012-11-21 12:06:18 -0800418 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 +
buzbeeefc63692012-11-14 16:31:52 -0800419 (operand << 1),
420 lir->target);
421 break;
422 case 'u': {
423 int offset_1 = lir->operands[0];
424 int offset_2 = NEXT_LIR(lir)->operands[0];
buzbeecbd6d442012-11-17 14:11:25 -0800425 uintptr_t target =
buzbeefa57c472012-11-21 12:06:18 -0800426 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
buzbeeefc63692012-11-14 16:31:52 -0800427 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
428 0xfffffffc;
buzbeecbd6d442012-11-17 14:11:25 -0800429 sprintf(tbuf, "%p", reinterpret_cast<void *>(target));
buzbeeefc63692012-11-14 16:31:52 -0800430 break;
431 }
432
433 /* Nothing to print for BLX_2 */
434 case 'v':
435 strcpy(tbuf, "see above");
436 break;
437 case 'R':
buzbee52a77fc2012-11-20 19:50:46 -0800438 DecodeRegList(lir->opcode, operand, tbuf);
buzbeeefc63692012-11-14 16:31:52 -0800439 break;
440 case 'P':
buzbee52a77fc2012-11-20 19:50:46 -0800441 DecodeFPCSRegList(operand, 16, tbuf);
buzbeeefc63692012-11-14 16:31:52 -0800442 break;
443 case 'Q':
buzbee52a77fc2012-11-20 19:50:46 -0800444 DecodeFPCSRegList(operand, 0, tbuf);
buzbeeefc63692012-11-14 16:31:52 -0800445 break;
446 default:
447 strcpy(tbuf,"DecodeError1");
448 break;
449 }
450 buf += tbuf;
451 }
452 } else {
453 buf += *fmt++;
454 }
455 }
456 return buf;
457}
458
buzbee02031b12012-11-23 09:41:35 -0800459void ArmCodegen::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix)
buzbeeefc63692012-11-14 16:31:52 -0800460{
461 char buf[256];
462 buf[0] = 0;
buzbeeefc63692012-11-14 16:31:52 -0800463
464 if (mask == ENCODE_ALL) {
465 strcpy(buf, "all");
466 } else {
467 char num[8];
468 int i;
469
470 for (i = 0; i < kArmRegEnd; i++) {
471 if (mask & (1ULL << i)) {
472 sprintf(num, "%d ", i);
473 strcat(buf, num);
474 }
475 }
476
477 if (mask & ENCODE_CCODE) {
478 strcat(buf, "cc ");
479 }
480 if (mask & ENCODE_FP_STATUS) {
481 strcat(buf, "fpcc ");
482 }
483
484 /* Memory bits */
buzbeefa57c472012-11-21 12:06:18 -0800485 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
486 sprintf(buf + strlen(buf), "dr%d%s", arm_lir->alias_info & 0xffff,
487 (arm_lir->alias_info & 0x80000000) ? "(+1)" : "");
buzbeeefc63692012-11-14 16:31:52 -0800488 }
489 if (mask & ENCODE_LITERAL) {
490 strcat(buf, "lit ");
491 }
492
493 if (mask & ENCODE_HEAP_REF) {
494 strcat(buf, "heap ");
495 }
496 if (mask & ENCODE_MUST_NOT_ALIAS) {
497 strcat(buf, "noalias ");
498 }
499 }
500 if (buf[0]) {
501 LOG(INFO) << prefix << ": " << buf;
502 }
503}
504
buzbee02031b12012-11-23 09:41:35 -0800505bool ArmCodegen::IsUnconditionalBranch(LIR* lir)
buzbeeefc63692012-11-14 16:31:52 -0800506{
buzbeecbd6d442012-11-17 14:11:25 -0800507 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
buzbeeefc63692012-11-14 16:31:52 -0800508}
509
buzbee02031b12012-11-23 09:41:35 -0800510bool InitArmCodegen(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800511{
buzbee02031b12012-11-23 09:41:35 -0800512 cu->cg.reset(new ArmCodegen());
513 for (int i = 0; i < kArmLast; i++) {
514 if (ArmCodegen::EncodingMap[i].opcode != i) {
515 LOG(FATAL) << "Encoding order for " << ArmCodegen::EncodingMap[i].name
buzbeeefc63692012-11-14 16:31:52 -0800516 << " is wrong: expecting " << i << ", seeing "
buzbee02031b12012-11-23 09:41:35 -0800517 << static_cast<int>(ArmCodegen::EncodingMap[i].opcode);
buzbeeefc63692012-11-14 16:31:52 -0800518 }
519 }
buzbeeefc63692012-11-14 16:31:52 -0800520 return true;
521}
522
buzbeeefc63692012-11-14 16:31:52 -0800523/*
524 * Alloc a pair of core registers, or a double. Low reg in low byte,
525 * high reg in next byte.
526 */
buzbee02031b12012-11-23 09:41:35 -0800527int ArmCodegen::AllocTypedTempPair(CompilationUnit* cu, bool fp_hint, int reg_class)
buzbeeefc63692012-11-14 16:31:52 -0800528{
buzbeefa57c472012-11-21 12:06:18 -0800529 int high_reg;
530 int low_reg;
buzbeeefc63692012-11-14 16:31:52 -0800531 int res = 0;
532
buzbeefa57c472012-11-21 12:06:18 -0800533 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
534 low_reg = AllocTempDouble(cu);
535 high_reg = low_reg + 1;
buzbeeefc63692012-11-14 16:31:52 -0800536 } else {
buzbeefa57c472012-11-21 12:06:18 -0800537 low_reg = AllocTemp(cu);
538 high_reg = AllocTemp(cu);
buzbeeefc63692012-11-14 16:31:52 -0800539 }
buzbeefa57c472012-11-21 12:06:18 -0800540 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
buzbeeefc63692012-11-14 16:31:52 -0800541 return res;
542}
543
buzbee02031b12012-11-23 09:41:35 -0800544int ArmCodegen::AllocTypedTemp(CompilationUnit* cu, bool fp_hint, int reg_class)
buzbeeefc63692012-11-14 16:31:52 -0800545{
buzbeefa57c472012-11-21 12:06:18 -0800546 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
547 return AllocTempFloat(cu);
548 return AllocTemp(cu);
buzbeeefc63692012-11-14 16:31:52 -0800549}
550
buzbee02031b12012-11-23 09:41:35 -0800551void ArmCodegen::CompilerInitializeRegAlloc(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800552{
buzbeefa57c472012-11-21 12:06:18 -0800553 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
554 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
555 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
556 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
557 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
buzbeecbd6d442012-11-17 14:11:25 -0800558 RegisterPool *pool =
buzbeefa57c472012-11-21 12:06:18 -0800559 static_cast<RegisterPool*>(NewMem(cu, sizeof(*pool), true, kAllocRegAlloc));
560 cu->reg_pool = pool;
561 pool->num_core_regs = num_regs;
562 pool->core_regs = reinterpret_cast<RegisterInfo*>
563 (NewMem(cu, num_regs * sizeof(*cu->reg_pool->core_regs), true, kAllocRegAlloc));
564 pool->num_fp_regs = num_fp_regs;
buzbeecbd6d442012-11-17 14:11:25 -0800565 pool->FPRegs = static_cast<RegisterInfo*>
buzbeefa57c472012-11-21 12:06:18 -0800566 (NewMem(cu, num_fp_regs * sizeof(*cu->reg_pool->FPRegs), true, kAllocRegAlloc));
567 CompilerInitPool(pool->core_regs, core_regs, pool->num_core_regs);
568 CompilerInitPool(pool->FPRegs, FpRegs, pool->num_fp_regs);
buzbeeefc63692012-11-14 16:31:52 -0800569 // Keep special registers from being allocated
buzbeefa57c472012-11-21 12:06:18 -0800570 for (int i = 0; i < num_reserved; i++) {
buzbee52a77fc2012-11-20 19:50:46 -0800571 if (NO_SUSPEND && (ReservedRegs[i] == rARM_SUSPEND)) {
buzbeeefc63692012-11-14 16:31:52 -0800572 //To measure cost of suspend check
573 continue;
574 }
buzbeefa57c472012-11-21 12:06:18 -0800575 MarkInUse(cu, ReservedRegs[i]);
buzbeeefc63692012-11-14 16:31:52 -0800576 }
577 // Mark temp regs - all others not in use can be used for promotion
buzbeefa57c472012-11-21 12:06:18 -0800578 for (int i = 0; i < num_temps; i++) {
579 MarkTemp(cu, core_temps[i]);
buzbeeefc63692012-11-14 16:31:52 -0800580 }
buzbeefa57c472012-11-21 12:06:18 -0800581 for (int i = 0; i < num_fp_temps; i++) {
582 MarkTemp(cu, fp_temps[i]);
buzbeeefc63692012-11-14 16:31:52 -0800583 }
584
585 // Start allocation at r2 in an attempt to avoid clobbering return values
buzbeefa57c472012-11-21 12:06:18 -0800586 pool->next_core_reg = r2;
buzbeeefc63692012-11-14 16:31:52 -0800587
588 // Construct the alias map.
buzbeefa57c472012-11-21 12:06:18 -0800589 cu->phi_alias_map = static_cast<int*>
590 (NewMem(cu, cu->num_ssa_regs * sizeof(cu->phi_alias_map[0]), false, kAllocDFInfo));
591 for (int i = 0; i < cu->num_ssa_regs; i++) {
592 cu->phi_alias_map[i] = i;
buzbeeefc63692012-11-14 16:31:52 -0800593 }
buzbeefa57c472012-11-21 12:06:18 -0800594 for (MIR* phi = cu->phi_list; phi; phi = phi->meta.phi_next) {
595 int def_reg = phi->ssa_rep->defs[0];
596 for (int i = 0; i < phi->ssa_rep->num_uses; i++) {
597 for (int j = 0; j < cu->num_ssa_regs; j++) {
598 if (cu->phi_alias_map[j] == phi->ssa_rep->uses[i]) {
599 cu->phi_alias_map[j] = def_reg;
buzbeeefc63692012-11-14 16:31:52 -0800600 }
601 }
602 }
603 }
604}
605
buzbee02031b12012-11-23 09:41:35 -0800606void ArmCodegen::FreeRegLocTemps(CompilationUnit* cu, RegLocation rl_keep,
buzbeefa57c472012-11-21 12:06:18 -0800607 RegLocation rl_free)
buzbeeefc63692012-11-14 16:31:52 -0800608{
buzbeefa57c472012-11-21 12:06:18 -0800609 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
610 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
buzbeeefc63692012-11-14 16:31:52 -0800611 // No overlap, free both
buzbeefa57c472012-11-21 12:06:18 -0800612 FreeTemp(cu, rl_free.low_reg);
613 FreeTemp(cu, rl_free.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800614 }
615}
616/*
buzbeefa57c472012-11-21 12:06:18 -0800617 * TUNING: is leaf? Can't just use "has_invoke" to determine as some
buzbeeefc63692012-11-14 16:31:52 -0800618 * instructions might call out to C/assembly helper functions. Until
619 * machinery is in place, always spill lr.
620 */
621
buzbee02031b12012-11-23 09:41:35 -0800622void ArmCodegen::AdjustSpillMask(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800623{
buzbeefa57c472012-11-21 12:06:18 -0800624 cu->core_spill_mask |= (1 << rARM_LR);
625 cu->num_core_spills++;
buzbeeefc63692012-11-14 16:31:52 -0800626}
627
628/*
629 * Mark a callee-save fp register as promoted. Note that
630 * vpush/vpop uses contiguous register lists so we must
631 * include any holes in the mask. Associate holes with
632 * Dalvik register INVALID_VREG (0xFFFFU).
633 */
buzbee02031b12012-11-23 09:41:35 -0800634void ArmCodegen::MarkPreservedSingle(CompilationUnit* cu, int v_reg, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800635{
636 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
637 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
buzbeefa57c472012-11-21 12:06:18 -0800638 // Ensure fp_vmap_table is large enough
639 int table_size = cu->fp_vmap_table.size();
640 for (int i = table_size; i < (reg + 1); i++) {
641 cu->fp_vmap_table.push_back(INVALID_VREG);
buzbeeefc63692012-11-14 16:31:52 -0800642 }
643 // Add the current mapping
buzbeefa57c472012-11-21 12:06:18 -0800644 cu->fp_vmap_table[reg] = v_reg;
645 // Size of fp_vmap_table is high-water mark, use to set mask
646 cu->num_fp_spills = cu->fp_vmap_table.size();
647 cu->fp_spill_mask = ((1 << cu->num_fp_spills) - 1) << ARM_FP_CALLEE_SAVE_BASE;
buzbeeefc63692012-11-14 16:31:52 -0800648}
649
buzbee02031b12012-11-23 09:41:35 -0800650void ArmCodegen::FlushRegWide(CompilationUnit* cu, int reg1, int reg2)
buzbeeefc63692012-11-14 16:31:52 -0800651{
buzbeefa57c472012-11-21 12:06:18 -0800652 RegisterInfo* info1 = GetRegInfo(cu, reg1);
653 RegisterInfo* info2 = GetRegInfo(cu, reg2);
buzbeeefc63692012-11-14 16:31:52 -0800654 DCHECK(info1 && info2 && info1->pair && info2->pair &&
655 (info1->partner == info2->reg) &&
656 (info2->partner == info1->reg));
657 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
buzbeefa57c472012-11-21 12:06:18 -0800658 if (!(info1->is_temp && info2->is_temp)) {
659 /* Should not happen. If it does, there's a problem in eval_loc */
buzbeeefc63692012-11-14 16:31:52 -0800660 LOG(FATAL) << "Long half-temp, half-promoted";
661 }
662
663 info1->dirty = false;
664 info2->dirty = false;
buzbeefa57c472012-11-21 12:06:18 -0800665 if (SRegToVReg(cu, info2->s_reg) <
666 SRegToVReg(cu, info1->s_reg))
buzbeeefc63692012-11-14 16:31:52 -0800667 info1 = info2;
buzbeefa57c472012-11-21 12:06:18 -0800668 int v_reg = SRegToVReg(cu, info1->s_reg);
669 StoreBaseDispWide(cu, rARM_SP, VRegOffset(cu, v_reg), info1->reg, info1->partner);
buzbeeefc63692012-11-14 16:31:52 -0800670 }
671}
672
buzbee02031b12012-11-23 09:41:35 -0800673void ArmCodegen::FlushReg(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800674{
buzbeefa57c472012-11-21 12:06:18 -0800675 RegisterInfo* info = GetRegInfo(cu, reg);
buzbeeefc63692012-11-14 16:31:52 -0800676 if (info->live && info->dirty) {
677 info->dirty = false;
buzbeefa57c472012-11-21 12:06:18 -0800678 int v_reg = SRegToVReg(cu, info->s_reg);
679 StoreBaseDisp(cu, rARM_SP, VRegOffset(cu, v_reg), reg, kWord);
buzbeeefc63692012-11-14 16:31:52 -0800680 }
681}
682
683/* Give access to the target-dependent FP register encoding to common code */
buzbee02031b12012-11-23 09:41:35 -0800684bool ArmCodegen::IsFpReg(int reg) {
buzbeeefc63692012-11-14 16:31:52 -0800685 return ARM_FPREG(reg);
686}
687
buzbeeefc63692012-11-14 16:31:52 -0800688/* Clobber all regs that might be used by an external C call */
buzbee02031b12012-11-23 09:41:35 -0800689void ArmCodegen::ClobberCalleeSave(CompilationUnit *cu)
buzbeeefc63692012-11-14 16:31:52 -0800690{
buzbeefa57c472012-11-21 12:06:18 -0800691 Clobber(cu, r0);
692 Clobber(cu, r1);
693 Clobber(cu, r2);
694 Clobber(cu, r3);
695 Clobber(cu, r12);
696 Clobber(cu, r14lr);
697 Clobber(cu, fr0);
698 Clobber(cu, fr1);
699 Clobber(cu, fr2);
700 Clobber(cu, fr3);
701 Clobber(cu, fr4);
702 Clobber(cu, fr5);
703 Clobber(cu, fr6);
704 Clobber(cu, fr7);
705 Clobber(cu, fr8);
706 Clobber(cu, fr9);
707 Clobber(cu, fr10);
708 Clobber(cu, fr11);
709 Clobber(cu, fr12);
710 Clobber(cu, fr13);
711 Clobber(cu, fr14);
712 Clobber(cu, fr15);
buzbeeefc63692012-11-14 16:31:52 -0800713}
714
buzbee02031b12012-11-23 09:41:35 -0800715RegLocation ArmCodegen::GetReturnWideAlt(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800716{
buzbee52a77fc2012-11-20 19:50:46 -0800717 RegLocation res = LocCReturnWide();
buzbeefa57c472012-11-21 12:06:18 -0800718 res.low_reg = r2;
719 res.high_reg = r3;
720 Clobber(cu, r2);
721 Clobber(cu, r3);
722 MarkInUse(cu, r2);
723 MarkInUse(cu, r3);
724 MarkPair(cu, res.low_reg, res.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800725 return res;
726}
727
buzbee02031b12012-11-23 09:41:35 -0800728RegLocation ArmCodegen::GetReturnAlt(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800729{
buzbee52a77fc2012-11-20 19:50:46 -0800730 RegLocation res = LocCReturn();
buzbeefa57c472012-11-21 12:06:18 -0800731 res.low_reg = r1;
732 Clobber(cu, r1);
733 MarkInUse(cu, r1);
buzbeeefc63692012-11-14 16:31:52 -0800734 return res;
735}
736
buzbee02031b12012-11-23 09:41:35 -0800737RegisterInfo* ArmCodegen::GetRegInfo(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800738{
buzbeefa57c472012-11-21 12:06:18 -0800739 return ARM_FPREG(reg) ? &cu->reg_pool->FPRegs[reg & ARM_FP_REG_MASK]
740 : &cu->reg_pool->core_regs[reg];
buzbeeefc63692012-11-14 16:31:52 -0800741}
742
743/* To be used when explicitly managing register use */
buzbee02031b12012-11-23 09:41:35 -0800744void ArmCodegen::LockCallTemps(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800745{
buzbeefa57c472012-11-21 12:06:18 -0800746 LockTemp(cu, r0);
747 LockTemp(cu, r1);
748 LockTemp(cu, r2);
749 LockTemp(cu, r3);
buzbeeefc63692012-11-14 16:31:52 -0800750}
751
752/* To be used when explicitly managing register use */
buzbee02031b12012-11-23 09:41:35 -0800753void ArmCodegen::FreeCallTemps(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800754{
buzbeefa57c472012-11-21 12:06:18 -0800755 FreeTemp(cu, r0);
756 FreeTemp(cu, r1);
757 FreeTemp(cu, r2);
758 FreeTemp(cu, r3);
buzbeeefc63692012-11-14 16:31:52 -0800759}
760
buzbee02031b12012-11-23 09:41:35 -0800761int ArmCodegen::LoadHelper(CompilationUnit* cu, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800762{
buzbeefa57c472012-11-21 12:06:18 -0800763 LoadWordDisp(cu, rARM_SELF, offset, rARM_LR);
buzbeeefc63692012-11-14 16:31:52 -0800764 return rARM_LR;
765}
766
buzbee02031b12012-11-23 09:41:35 -0800767uint64_t ArmCodegen::GetTargetInstFlags(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800768{
buzbee02031b12012-11-23 09:41:35 -0800769 return ArmCodegen::EncodingMap[opcode].flags;
buzbee1bc37c62012-11-20 13:35:41 -0800770}
771
buzbee02031b12012-11-23 09:41:35 -0800772const char* ArmCodegen::GetTargetInstName(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800773{
buzbee02031b12012-11-23 09:41:35 -0800774 return ArmCodegen::EncodingMap[opcode].name;
buzbee1bc37c62012-11-20 13:35:41 -0800775}
776
buzbee02031b12012-11-23 09:41:35 -0800777const char* ArmCodegen::GetTargetInstFmt(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800778{
buzbee02031b12012-11-23 09:41:35 -0800779 return ArmCodegen::EncodingMap[opcode].fmt;
buzbee1bc37c62012-11-20 13:35:41 -0800780}
781
buzbeeefc63692012-11-14 16:31:52 -0800782} // namespace art