blob: f871f3da7ad27dbdeae985718851abd75f226aec [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
Brian Carlstrom641ce032013-01-31 15:21:37 -080017#include <string>
18
buzbeeefc63692012-11-14 16:31:52 -080019#include "arm_lir.h"
buzbee02031b12012-11-23 09:41:35 -080020#include "codegen_arm.h"
Brian Carlstrom641ce032013-01-31 15:21:37 -080021#include "compiler/codegen/codegen_util.h"
22#include "compiler/compiler_internals.h"
23#include "compiler/codegen/ralloc_util.h"
buzbeeefc63692012-11-14 16:31:52 -080024
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
buzbee02031b12012-11-23 09:41:35 -0800589void ArmCodegen::FreeRegLocTemps(CompilationUnit* cu, RegLocation rl_keep,
buzbeefa57c472012-11-21 12:06:18 -0800590 RegLocation rl_free)
buzbeeefc63692012-11-14 16:31:52 -0800591{
buzbeefa57c472012-11-21 12:06:18 -0800592 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
593 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
buzbeeefc63692012-11-14 16:31:52 -0800594 // No overlap, free both
buzbeefa57c472012-11-21 12:06:18 -0800595 FreeTemp(cu, rl_free.low_reg);
596 FreeTemp(cu, rl_free.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800597 }
598}
599/*
buzbeefa57c472012-11-21 12:06:18 -0800600 * TUNING: is leaf? Can't just use "has_invoke" to determine as some
buzbeeefc63692012-11-14 16:31:52 -0800601 * instructions might call out to C/assembly helper functions. Until
602 * machinery is in place, always spill lr.
603 */
604
buzbee02031b12012-11-23 09:41:35 -0800605void ArmCodegen::AdjustSpillMask(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800606{
buzbeefa57c472012-11-21 12:06:18 -0800607 cu->core_spill_mask |= (1 << rARM_LR);
608 cu->num_core_spills++;
buzbeeefc63692012-11-14 16:31:52 -0800609}
610
611/*
612 * Mark a callee-save fp register as promoted. Note that
613 * vpush/vpop uses contiguous register lists so we must
614 * include any holes in the mask. Associate holes with
615 * Dalvik register INVALID_VREG (0xFFFFU).
616 */
buzbee02031b12012-11-23 09:41:35 -0800617void ArmCodegen::MarkPreservedSingle(CompilationUnit* cu, int v_reg, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800618{
619 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
620 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
buzbeefa57c472012-11-21 12:06:18 -0800621 // Ensure fp_vmap_table is large enough
622 int table_size = cu->fp_vmap_table.size();
623 for (int i = table_size; i < (reg + 1); i++) {
624 cu->fp_vmap_table.push_back(INVALID_VREG);
buzbeeefc63692012-11-14 16:31:52 -0800625 }
626 // Add the current mapping
buzbeefa57c472012-11-21 12:06:18 -0800627 cu->fp_vmap_table[reg] = v_reg;
628 // Size of fp_vmap_table is high-water mark, use to set mask
629 cu->num_fp_spills = cu->fp_vmap_table.size();
630 cu->fp_spill_mask = ((1 << cu->num_fp_spills) - 1) << ARM_FP_CALLEE_SAVE_BASE;
buzbeeefc63692012-11-14 16:31:52 -0800631}
632
buzbee02031b12012-11-23 09:41:35 -0800633void ArmCodegen::FlushRegWide(CompilationUnit* cu, int reg1, int reg2)
buzbeeefc63692012-11-14 16:31:52 -0800634{
buzbeefa57c472012-11-21 12:06:18 -0800635 RegisterInfo* info1 = GetRegInfo(cu, reg1);
636 RegisterInfo* info2 = GetRegInfo(cu, reg2);
buzbeeefc63692012-11-14 16:31:52 -0800637 DCHECK(info1 && info2 && info1->pair && info2->pair &&
638 (info1->partner == info2->reg) &&
639 (info2->partner == info1->reg));
640 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
buzbeefa57c472012-11-21 12:06:18 -0800641 if (!(info1->is_temp && info2->is_temp)) {
642 /* Should not happen. If it does, there's a problem in eval_loc */
buzbeeefc63692012-11-14 16:31:52 -0800643 LOG(FATAL) << "Long half-temp, half-promoted";
644 }
645
646 info1->dirty = false;
647 info2->dirty = false;
buzbeefa57c472012-11-21 12:06:18 -0800648 if (SRegToVReg(cu, info2->s_reg) <
649 SRegToVReg(cu, info1->s_reg))
buzbeeefc63692012-11-14 16:31:52 -0800650 info1 = info2;
buzbeefa57c472012-11-21 12:06:18 -0800651 int v_reg = SRegToVReg(cu, info1->s_reg);
652 StoreBaseDispWide(cu, rARM_SP, VRegOffset(cu, v_reg), info1->reg, info1->partner);
buzbeeefc63692012-11-14 16:31:52 -0800653 }
654}
655
buzbee02031b12012-11-23 09:41:35 -0800656void ArmCodegen::FlushReg(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800657{
buzbeefa57c472012-11-21 12:06:18 -0800658 RegisterInfo* info = GetRegInfo(cu, reg);
buzbeeefc63692012-11-14 16:31:52 -0800659 if (info->live && info->dirty) {
660 info->dirty = false;
buzbeefa57c472012-11-21 12:06:18 -0800661 int v_reg = SRegToVReg(cu, info->s_reg);
662 StoreBaseDisp(cu, rARM_SP, VRegOffset(cu, v_reg), reg, kWord);
buzbeeefc63692012-11-14 16:31:52 -0800663 }
664}
665
666/* Give access to the target-dependent FP register encoding to common code */
buzbee02031b12012-11-23 09:41:35 -0800667bool ArmCodegen::IsFpReg(int reg) {
buzbeeefc63692012-11-14 16:31:52 -0800668 return ARM_FPREG(reg);
669}
670
buzbeeefc63692012-11-14 16:31:52 -0800671/* Clobber all regs that might be used by an external C call */
buzbee02031b12012-11-23 09:41:35 -0800672void ArmCodegen::ClobberCalleeSave(CompilationUnit *cu)
buzbeeefc63692012-11-14 16:31:52 -0800673{
buzbeefa57c472012-11-21 12:06:18 -0800674 Clobber(cu, r0);
675 Clobber(cu, r1);
676 Clobber(cu, r2);
677 Clobber(cu, r3);
678 Clobber(cu, r12);
679 Clobber(cu, r14lr);
680 Clobber(cu, fr0);
681 Clobber(cu, fr1);
682 Clobber(cu, fr2);
683 Clobber(cu, fr3);
684 Clobber(cu, fr4);
685 Clobber(cu, fr5);
686 Clobber(cu, fr6);
687 Clobber(cu, fr7);
688 Clobber(cu, fr8);
689 Clobber(cu, fr9);
690 Clobber(cu, fr10);
691 Clobber(cu, fr11);
692 Clobber(cu, fr12);
693 Clobber(cu, fr13);
694 Clobber(cu, fr14);
695 Clobber(cu, fr15);
buzbeeefc63692012-11-14 16:31:52 -0800696}
697
buzbee02031b12012-11-23 09:41:35 -0800698RegLocation ArmCodegen::GetReturnWideAlt(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800699{
buzbee52a77fc2012-11-20 19:50:46 -0800700 RegLocation res = LocCReturnWide();
buzbeefa57c472012-11-21 12:06:18 -0800701 res.low_reg = r2;
702 res.high_reg = r3;
703 Clobber(cu, r2);
704 Clobber(cu, r3);
705 MarkInUse(cu, r2);
706 MarkInUse(cu, r3);
707 MarkPair(cu, res.low_reg, res.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800708 return res;
709}
710
buzbee02031b12012-11-23 09:41:35 -0800711RegLocation ArmCodegen::GetReturnAlt(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800712{
buzbee52a77fc2012-11-20 19:50:46 -0800713 RegLocation res = LocCReturn();
buzbeefa57c472012-11-21 12:06:18 -0800714 res.low_reg = r1;
715 Clobber(cu, r1);
716 MarkInUse(cu, r1);
buzbeeefc63692012-11-14 16:31:52 -0800717 return res;
718}
719
buzbee02031b12012-11-23 09:41:35 -0800720RegisterInfo* ArmCodegen::GetRegInfo(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800721{
buzbeefa57c472012-11-21 12:06:18 -0800722 return ARM_FPREG(reg) ? &cu->reg_pool->FPRegs[reg & ARM_FP_REG_MASK]
723 : &cu->reg_pool->core_regs[reg];
buzbeeefc63692012-11-14 16:31:52 -0800724}
725
726/* To be used when explicitly managing register use */
buzbee02031b12012-11-23 09:41:35 -0800727void ArmCodegen::LockCallTemps(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800728{
buzbeefa57c472012-11-21 12:06:18 -0800729 LockTemp(cu, r0);
730 LockTemp(cu, r1);
731 LockTemp(cu, r2);
732 LockTemp(cu, r3);
buzbeeefc63692012-11-14 16:31:52 -0800733}
734
735/* To be used when explicitly managing register use */
buzbee02031b12012-11-23 09:41:35 -0800736void ArmCodegen::FreeCallTemps(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800737{
buzbeefa57c472012-11-21 12:06:18 -0800738 FreeTemp(cu, r0);
739 FreeTemp(cu, r1);
740 FreeTemp(cu, r2);
741 FreeTemp(cu, r3);
buzbeeefc63692012-11-14 16:31:52 -0800742}
743
buzbee02031b12012-11-23 09:41:35 -0800744int ArmCodegen::LoadHelper(CompilationUnit* cu, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800745{
buzbeefa57c472012-11-21 12:06:18 -0800746 LoadWordDisp(cu, rARM_SELF, offset, rARM_LR);
buzbeeefc63692012-11-14 16:31:52 -0800747 return rARM_LR;
748}
749
buzbee02031b12012-11-23 09:41:35 -0800750uint64_t ArmCodegen::GetTargetInstFlags(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800751{
buzbee02031b12012-11-23 09:41:35 -0800752 return ArmCodegen::EncodingMap[opcode].flags;
buzbee1bc37c62012-11-20 13:35:41 -0800753}
754
buzbee02031b12012-11-23 09:41:35 -0800755const char* ArmCodegen::GetTargetInstName(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800756{
buzbee02031b12012-11-23 09:41:35 -0800757 return ArmCodegen::EncodingMap[opcode].name;
buzbee1bc37c62012-11-20 13:35:41 -0800758}
759
buzbee02031b12012-11-23 09:41:35 -0800760const char* ArmCodegen::GetTargetInstFmt(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800761{
buzbee02031b12012-11-23 09:41:35 -0800762 return ArmCodegen::EncodingMap[opcode].fmt;
buzbee1bc37c62012-11-20 13:35:41 -0800763}
764
buzbeeefc63692012-11-14 16:31:52 -0800765} // namespace art