blob: 9c1223732ade885e2911f7cb5f29836b7eb84509 [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"
buzbeeeaf09bc2012-11-15 14:51:41 -080019#include "../ralloc_util.h"
20#include "../codegen_util.h"
buzbeeefc63692012-11-14 16:31:52 -080021
22#include <string>
23
24namespace art {
25
buzbeefa57c472012-11-21 12:06:18 -080026static int core_regs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10,
buzbeeefc63692012-11-14 16:31:52 -080027 r11, r12, rARM_SP, rARM_LR, rARM_PC};
buzbee52a77fc2012-11-20 19:50:46 -080028static int ReservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC};
29static int FpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
buzbeeefc63692012-11-14 16:31:52 -080030 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
31 fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
32 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
buzbeefa57c472012-11-21 12:06:18 -080033static int core_temps[] = {r0, r1, r2, r3, r12};
34static int fp_temps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
buzbeeefc63692012-11-14 16:31:52 -080035 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
36
buzbee52a77fc2012-11-20 19:50:46 -080037RegLocation LocCReturn()
buzbeeefc63692012-11-14 16:31:52 -080038{
39 RegLocation res = ARM_LOC_C_RETURN;
40 return res;
41}
42
buzbee52a77fc2012-11-20 19:50:46 -080043RegLocation LocCReturnWide()
buzbeeefc63692012-11-14 16:31:52 -080044{
45 RegLocation res = ARM_LOC_C_RETURN_WIDE;
46 return res;
47}
48
buzbee52a77fc2012-11-20 19:50:46 -080049RegLocation LocCReturnFloat()
buzbeeefc63692012-11-14 16:31:52 -080050{
51 RegLocation res = ARM_LOC_C_RETURN_FLOAT;
52 return res;
53}
54
buzbee52a77fc2012-11-20 19:50:46 -080055RegLocation LocCReturnDouble()
buzbeeefc63692012-11-14 16:31:52 -080056{
57 RegLocation res = ARM_LOC_C_RETURN_DOUBLE;
58 return res;
59}
60
61// Return a target-dependent special register.
buzbee52a77fc2012-11-20 19:50:46 -080062int TargetReg(SpecialTargetRegister reg) {
buzbeeefc63692012-11-14 16:31:52 -080063 int res = INVALID_REG;
64 switch (reg) {
65 case kSelf: res = rARM_SELF; break;
66 case kSuspend: res = rARM_SUSPEND; break;
67 case kLr: res = rARM_LR; break;
68 case kPc: res = rARM_PC; break;
69 case kSp: res = rARM_SP; break;
70 case kArg0: res = rARM_ARG0; break;
71 case kArg1: res = rARM_ARG1; break;
72 case kArg2: res = rARM_ARG2; break;
73 case kArg3: res = rARM_ARG3; break;
74 case kFArg0: res = rARM_FARG0; break;
75 case kFArg1: res = rARM_FARG1; break;
76 case kFArg2: res = rARM_FARG2; break;
77 case kFArg3: res = rARM_FARG3; break;
78 case kRet0: res = rARM_RET0; break;
79 case kRet1: res = rARM_RET1; break;
80 case kInvokeTgt: res = rARM_INVOKE_TGT; break;
81 case kCount: res = rARM_COUNT; break;
82 }
83 return res;
84}
85
86
87// Create a double from a pair of singles.
buzbeefa57c472012-11-21 12:06:18 -080088int S2d(int low_reg, int high_reg)
buzbeeefc63692012-11-14 16:31:52 -080089{
buzbeefa57c472012-11-21 12:06:18 -080090 return ARM_S2D(low_reg, high_reg);
buzbeeefc63692012-11-14 16:31:52 -080091}
92
93// Is reg a single or double?
buzbee52a77fc2012-11-20 19:50:46 -080094bool FpReg(int reg)
buzbeeefc63692012-11-14 16:31:52 -080095{
96 return ARM_FPREG(reg);
97}
98
99// Is reg a single?
buzbee52a77fc2012-11-20 19:50:46 -0800100bool SingleReg(int reg)
buzbeeefc63692012-11-14 16:31:52 -0800101{
102 return ARM_SINGLEREG(reg);
103}
104
105// Is reg a double?
buzbee52a77fc2012-11-20 19:50:46 -0800106bool DoubleReg(int reg)
buzbeeefc63692012-11-14 16:31:52 -0800107{
108 return ARM_DOUBLEREG(reg);
109}
110
111// Return mask to strip off fp reg flags and bias.
buzbee52a77fc2012-11-20 19:50:46 -0800112uint32_t FpRegMask()
buzbeeefc63692012-11-14 16:31:52 -0800113{
114 return ARM_FP_REG_MASK;
115}
116
117// True if both regs single, both core or both double.
buzbee52a77fc2012-11-20 19:50:46 -0800118bool SameRegType(int reg1, int reg2)
buzbeeefc63692012-11-14 16:31:52 -0800119{
120 return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2));
121}
122
123/*
124 * Decode the register id.
125 */
buzbeefa57c472012-11-21 12:06:18 -0800126uint64_t GetRegMaskCommon(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800127{
buzbeeeaf09bc2012-11-15 14:51:41 -0800128 uint64_t seed;
buzbeeefc63692012-11-14 16:31:52 -0800129 int shift;
buzbeefa57c472012-11-21 12:06:18 -0800130 int reg_id;
buzbeeefc63692012-11-14 16:31:52 -0800131
132
buzbeefa57c472012-11-21 12:06:18 -0800133 reg_id = reg & 0x1f;
buzbeeefc63692012-11-14 16:31:52 -0800134 /* Each double register is equal to a pair of single-precision FP registers */
135 seed = ARM_DOUBLEREG(reg) ? 3 : 1;
136 /* FP register starts at bit position 16 */
137 shift = ARM_FPREG(reg) ? kArmFPReg0 : 0;
138 /* Expand the double register id into single offset */
buzbeefa57c472012-11-21 12:06:18 -0800139 shift += reg_id;
buzbeeefc63692012-11-14 16:31:52 -0800140 return (seed << shift);
141}
142
buzbee52a77fc2012-11-20 19:50:46 -0800143uint64_t GetPCUseDefEncoding()
buzbeeefc63692012-11-14 16:31:52 -0800144{
145 return ENCODE_ARM_REG_PC;
146}
147
buzbeefa57c472012-11-21 12:06:18 -0800148void SetupTargetResourceMasks(CompilationUnit* cu, LIR* lir)
buzbeeefc63692012-11-14 16:31:52 -0800149{
buzbeefa57c472012-11-21 12:06:18 -0800150 DCHECK_EQ(cu->instruction_set, kThumb2);
buzbeeefc63692012-11-14 16:31:52 -0800151
152 // Thumb2 specific setup
153 uint64_t flags = EncodingMap[lir->opcode].flags;
154 int opcode = lir->opcode;
155
156 if (flags & REG_DEF_SP) {
buzbeefa57c472012-11-21 12:06:18 -0800157 lir->def_mask |= ENCODE_ARM_REG_SP;
buzbeeefc63692012-11-14 16:31:52 -0800158 }
159
160 if (flags & REG_USE_SP) {
buzbeefa57c472012-11-21 12:06:18 -0800161 lir->use_mask |= ENCODE_ARM_REG_SP;
buzbeeefc63692012-11-14 16:31:52 -0800162 }
163
164 if (flags & REG_DEF_LIST0) {
buzbeefa57c472012-11-21 12:06:18 -0800165 lir->def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
buzbeeefc63692012-11-14 16:31:52 -0800166 }
167
168 if (flags & REG_DEF_LIST1) {
buzbeefa57c472012-11-21 12:06:18 -0800169 lir->def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
buzbeeefc63692012-11-14 16:31:52 -0800170 }
171
172 if (flags & REG_DEF_FPCS_LIST0) {
buzbeefa57c472012-11-21 12:06:18 -0800173 lir->def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
buzbeeefc63692012-11-14 16:31:52 -0800174 }
175
176 if (flags & REG_DEF_FPCS_LIST2) {
177 for (int i = 0; i < lir->operands[2]; i++) {
buzbeefa57c472012-11-21 12:06:18 -0800178 SetupRegMask(cu, &lir->def_mask, lir->operands[1] + i);
buzbeeefc63692012-11-14 16:31:52 -0800179 }
180 }
181
182 if (flags & REG_USE_PC) {
buzbeefa57c472012-11-21 12:06:18 -0800183 lir->use_mask |= ENCODE_ARM_REG_PC;
buzbeeefc63692012-11-14 16:31:52 -0800184 }
185
186 /* Conservatively treat the IT block */
187 if (flags & IS_IT) {
buzbeefa57c472012-11-21 12:06:18 -0800188 lir->def_mask = ENCODE_ALL;
buzbeeefc63692012-11-14 16:31:52 -0800189 }
190
191 if (flags & REG_USE_LIST0) {
buzbeefa57c472012-11-21 12:06:18 -0800192 lir->use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
buzbeeefc63692012-11-14 16:31:52 -0800193 }
194
195 if (flags & REG_USE_LIST1) {
buzbeefa57c472012-11-21 12:06:18 -0800196 lir->use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
buzbeeefc63692012-11-14 16:31:52 -0800197 }
198
199 if (flags & REG_USE_FPCS_LIST0) {
buzbeefa57c472012-11-21 12:06:18 -0800200 lir->use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
buzbeeefc63692012-11-14 16:31:52 -0800201 }
202
203 if (flags & REG_USE_FPCS_LIST2) {
204 for (int i = 0; i < lir->operands[2]; i++) {
buzbeefa57c472012-11-21 12:06:18 -0800205 SetupRegMask(cu, &lir->use_mask, lir->operands[1] + i);
buzbeeefc63692012-11-14 16:31:52 -0800206 }
207 }
208 /* Fixup for kThumbPush/lr and kThumbPop/pc */
209 if (opcode == kThumbPush || opcode == kThumbPop) {
buzbeefa57c472012-11-21 12:06:18 -0800210 uint64_t r8Mask = GetRegMaskCommon(cu, r8);
211 if ((opcode == kThumbPush) && (lir->use_mask & r8Mask)) {
212 lir->use_mask &= ~r8Mask;
213 lir->use_mask |= ENCODE_ARM_REG_LR;
214 } else if ((opcode == kThumbPop) && (lir->def_mask & r8Mask)) {
215 lir->def_mask &= ~r8Mask;
216 lir->def_mask |= ENCODE_ARM_REG_PC;
buzbeeefc63692012-11-14 16:31:52 -0800217 }
218 }
219 if (flags & REG_DEF_LR) {
buzbeefa57c472012-11-21 12:06:18 -0800220 lir->def_mask |= ENCODE_ARM_REG_LR;
buzbeeefc63692012-11-14 16:31:52 -0800221 }
222}
223
buzbee52a77fc2012-11-20 19:50:46 -0800224ArmConditionCode ArmConditionEncoding(ConditionCode ccode)
buzbeeefc63692012-11-14 16:31:52 -0800225{
226 ArmConditionCode res;
buzbeecbd6d442012-11-17 14:11:25 -0800227 switch (ccode) {
buzbeeefc63692012-11-14 16:31:52 -0800228 case kCondEq: res = kArmCondEq; break;
229 case kCondNe: res = kArmCondNe; break;
230 case kCondCs: res = kArmCondCs; break;
231 case kCondCc: res = kArmCondCc; break;
232 case kCondMi: res = kArmCondMi; break;
233 case kCondPl: res = kArmCondPl; break;
234 case kCondVs: res = kArmCondVs; break;
235 case kCondVc: res = kArmCondVc; break;
236 case kCondHi: res = kArmCondHi; break;
237 case kCondLs: res = kArmCondLs; break;
238 case kCondGe: res = kArmCondGe; break;
239 case kCondLt: res = kArmCondLt; break;
240 case kCondGt: res = kArmCondGt; break;
241 case kCondLe: res = kArmCondLe; break;
242 case kCondAl: res = kArmCondAl; break;
243 case kCondNv: res = kArmCondNv; break;
244 default:
buzbeecbd6d442012-11-17 14:11:25 -0800245 LOG(FATAL) << "Bad condition code " << ccode;
246 res = static_cast<ArmConditionCode>(0); // Quiet gcc
buzbeeefc63692012-11-14 16:31:52 -0800247 }
248 return res;
249}
250
buzbeefa57c472012-11-21 12:06:18 -0800251static const char* core_reg_names[16] = {
buzbeeefc63692012-11-14 16:31:52 -0800252 "r0",
253 "r1",
254 "r2",
255 "r3",
256 "r4",
257 "r5",
258 "r6",
259 "r7",
260 "r8",
261 "rSELF",
262 "r10",
263 "r11",
264 "r12",
265 "sp",
266 "lr",
267 "pc",
268};
269
270
buzbeefa57c472012-11-21 12:06:18 -0800271static const char* shift_names[4] = {
buzbeeefc63692012-11-14 16:31:52 -0800272 "lsl",
273 "lsr",
274 "asr",
275 "ror"};
276
277/* Decode and print a ARM register name */
buzbeeaad94382012-11-21 07:40:50 -0800278static char* DecodeRegList(int opcode, int vector, char* buf)
buzbeeefc63692012-11-14 16:31:52 -0800279{
280 int i;
281 bool printed = false;
282 buf[0] = 0;
283 for (i = 0; i < 16; i++, vector >>= 1) {
284 if (vector & 0x1) {
buzbeefa57c472012-11-21 12:06:18 -0800285 int reg_id = i;
buzbeeefc63692012-11-14 16:31:52 -0800286 if (opcode == kThumbPush && i == 8) {
buzbeefa57c472012-11-21 12:06:18 -0800287 reg_id = r14lr;
buzbeeefc63692012-11-14 16:31:52 -0800288 } else if (opcode == kThumbPop && i == 8) {
buzbeefa57c472012-11-21 12:06:18 -0800289 reg_id = r15pc;
buzbeeefc63692012-11-14 16:31:52 -0800290 }
291 if (printed) {
buzbeefa57c472012-11-21 12:06:18 -0800292 sprintf(buf + strlen(buf), ", r%d", reg_id);
buzbeeefc63692012-11-14 16:31:52 -0800293 } else {
294 printed = true;
buzbeefa57c472012-11-21 12:06:18 -0800295 sprintf(buf, "r%d", reg_id);
buzbeeefc63692012-11-14 16:31:52 -0800296 }
297 }
298 }
299 return buf;
300}
301
buzbeeaad94382012-11-21 07:40:50 -0800302static char* DecodeFPCSRegList(int count, int base, char* buf)
buzbeeefc63692012-11-14 16:31:52 -0800303{
304 sprintf(buf, "s%d", base);
305 for (int i = 1; i < count; i++) {
306 sprintf(buf + strlen(buf), ", s%d",base + i);
307 }
308 return buf;
309}
310
buzbeeaad94382012-11-21 07:40:50 -0800311static int ExpandImmediate(int value)
buzbeeefc63692012-11-14 16:31:52 -0800312{
313 int mode = (value & 0xf00) >> 8;
buzbeeeaf09bc2012-11-15 14:51:41 -0800314 uint32_t bits = value & 0xff;
buzbeeefc63692012-11-14 16:31:52 -0800315 switch (mode) {
316 case 0:
317 return bits;
318 case 1:
319 return (bits << 16) | bits;
320 case 2:
321 return (bits << 24) | (bits << 8);
322 case 3:
323 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
324 default:
325 break;
326 }
327 bits = (bits | 0x80) << 24;
328 return bits >> (((value & 0xf80) >> 7) - 8);
329}
330
buzbeefa57c472012-11-21 12:06:18 -0800331const char* cc_names[] = {"eq","ne","cs","cc","mi","pl","vs","vc",
buzbeeefc63692012-11-14 16:31:52 -0800332 "hi","ls","ge","lt","gt","le","al","nv"};
333/*
334 * Interpret a format string and build a string no longer than size
335 * See format key in Assemble.c.
336 */
buzbeefa57c472012-11-21 12:06:18 -0800337std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr)
buzbeeefc63692012-11-14 16:31:52 -0800338{
339 std::string buf;
340 int i;
buzbeefa57c472012-11-21 12:06:18 -0800341 const char* fmt_end = &fmt[strlen(fmt)];
buzbeeefc63692012-11-14 16:31:52 -0800342 char tbuf[256];
343 const char* name;
344 char nc;
buzbeefa57c472012-11-21 12:06:18 -0800345 while (fmt < fmt_end) {
buzbeeefc63692012-11-14 16:31:52 -0800346 int operand;
347 if (*fmt == '!') {
348 fmt++;
buzbeefa57c472012-11-21 12:06:18 -0800349 DCHECK_LT(fmt, fmt_end);
buzbeeefc63692012-11-14 16:31:52 -0800350 nc = *fmt++;
351 if (nc=='!') {
352 strcpy(tbuf, "!");
353 } else {
buzbeefa57c472012-11-21 12:06:18 -0800354 DCHECK_LT(fmt, fmt_end);
buzbeecbd6d442012-11-17 14:11:25 -0800355 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
buzbeeefc63692012-11-14 16:31:52 -0800356 operand = lir->operands[nc-'0'];
357 switch (*fmt++) {
358 case 'H':
359 if (operand != 0) {
buzbeefa57c472012-11-21 12:06:18 -0800360 sprintf(tbuf, ", %s %d",shift_names[operand & 0x3], operand >> 2);
buzbeeefc63692012-11-14 16:31:52 -0800361 } else {
362 strcpy(tbuf,"");
363 }
364 break;
365 case 'B':
366 switch (operand) {
367 case kSY:
368 name = "sy";
369 break;
370 case kST:
371 name = "st";
372 break;
373 case kISH:
374 name = "ish";
375 break;
376 case kISHST:
377 name = "ishst";
378 break;
379 case kNSH:
380 name = "nsh";
381 break;
382 case kNSHST:
383 name = "shst";
384 break;
385 default:
386 name = "DecodeError2";
387 break;
388 }
389 strcpy(tbuf, name);
390 break;
391 case 'b':
392 strcpy(tbuf,"0000");
393 for (i=3; i>= 0; i--) {
394 tbuf[i] += operand & 1;
395 operand >>= 1;
396 }
397 break;
398 case 'n':
buzbee52a77fc2012-11-20 19:50:46 -0800399 operand = ~ExpandImmediate(operand);
buzbeeefc63692012-11-14 16:31:52 -0800400 sprintf(tbuf,"%d [%#x]", operand, operand);
401 break;
402 case 'm':
buzbee52a77fc2012-11-20 19:50:46 -0800403 operand = ExpandImmediate(operand);
buzbeeefc63692012-11-14 16:31:52 -0800404 sprintf(tbuf,"%d [%#x]", operand, operand);
405 break;
406 case 's':
407 sprintf(tbuf,"s%d",operand & ARM_FP_REG_MASK);
408 break;
409 case 'S':
410 sprintf(tbuf,"d%d",(operand & ARM_FP_REG_MASK) >> 1);
411 break;
412 case 'h':
413 sprintf(tbuf,"%04x", operand);
414 break;
415 case 'M':
416 case 'd':
417 sprintf(tbuf,"%d", operand);
418 break;
419 case 'C':
420 DCHECK_LT(operand, static_cast<int>(
buzbeefa57c472012-11-21 12:06:18 -0800421 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
422 sprintf(tbuf,"%s",core_reg_names[operand]);
buzbeeefc63692012-11-14 16:31:52 -0800423 break;
424 case 'E':
425 sprintf(tbuf,"%d", operand*4);
426 break;
427 case 'F':
428 sprintf(tbuf,"%d", operand*2);
429 break;
430 case 'c':
buzbeefa57c472012-11-21 12:06:18 -0800431 strcpy(tbuf, cc_names[operand]);
buzbeeefc63692012-11-14 16:31:52 -0800432 break;
433 case 't':
434 sprintf(tbuf,"0x%08x (L%p)",
buzbeefa57c472012-11-21 12:06:18 -0800435 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 +
buzbeeefc63692012-11-14 16:31:52 -0800436 (operand << 1),
437 lir->target);
438 break;
439 case 'u': {
440 int offset_1 = lir->operands[0];
441 int offset_2 = NEXT_LIR(lir)->operands[0];
buzbeecbd6d442012-11-17 14:11:25 -0800442 uintptr_t target =
buzbeefa57c472012-11-21 12:06:18 -0800443 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
buzbeeefc63692012-11-14 16:31:52 -0800444 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
445 0xfffffffc;
buzbeecbd6d442012-11-17 14:11:25 -0800446 sprintf(tbuf, "%p", reinterpret_cast<void *>(target));
buzbeeefc63692012-11-14 16:31:52 -0800447 break;
448 }
449
450 /* Nothing to print for BLX_2 */
451 case 'v':
452 strcpy(tbuf, "see above");
453 break;
454 case 'R':
buzbee52a77fc2012-11-20 19:50:46 -0800455 DecodeRegList(lir->opcode, operand, tbuf);
buzbeeefc63692012-11-14 16:31:52 -0800456 break;
457 case 'P':
buzbee52a77fc2012-11-20 19:50:46 -0800458 DecodeFPCSRegList(operand, 16, tbuf);
buzbeeefc63692012-11-14 16:31:52 -0800459 break;
460 case 'Q':
buzbee52a77fc2012-11-20 19:50:46 -0800461 DecodeFPCSRegList(operand, 0, tbuf);
buzbeeefc63692012-11-14 16:31:52 -0800462 break;
463 default:
464 strcpy(tbuf,"DecodeError1");
465 break;
466 }
467 buf += tbuf;
468 }
469 } else {
470 buf += *fmt++;
471 }
472 }
473 return buf;
474}
475
buzbeefa57c472012-11-21 12:06:18 -0800476void DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix)
buzbeeefc63692012-11-14 16:31:52 -0800477{
478 char buf[256];
479 buf[0] = 0;
buzbeeefc63692012-11-14 16:31:52 -0800480
481 if (mask == ENCODE_ALL) {
482 strcpy(buf, "all");
483 } else {
484 char num[8];
485 int i;
486
487 for (i = 0; i < kArmRegEnd; i++) {
488 if (mask & (1ULL << i)) {
489 sprintf(num, "%d ", i);
490 strcat(buf, num);
491 }
492 }
493
494 if (mask & ENCODE_CCODE) {
495 strcat(buf, "cc ");
496 }
497 if (mask & ENCODE_FP_STATUS) {
498 strcat(buf, "fpcc ");
499 }
500
501 /* Memory bits */
buzbeefa57c472012-11-21 12:06:18 -0800502 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
503 sprintf(buf + strlen(buf), "dr%d%s", arm_lir->alias_info & 0xffff,
504 (arm_lir->alias_info & 0x80000000) ? "(+1)" : "");
buzbeeefc63692012-11-14 16:31:52 -0800505 }
506 if (mask & ENCODE_LITERAL) {
507 strcat(buf, "lit ");
508 }
509
510 if (mask & ENCODE_HEAP_REF) {
511 strcat(buf, "heap ");
512 }
513 if (mask & ENCODE_MUST_NOT_ALIAS) {
514 strcat(buf, "noalias ");
515 }
516 }
517 if (buf[0]) {
518 LOG(INFO) << prefix << ": " << buf;
519 }
520}
521
buzbee52a77fc2012-11-20 19:50:46 -0800522bool BranchUnconditional(LIR* lir)
buzbeeefc63692012-11-14 16:31:52 -0800523{
buzbeecbd6d442012-11-17 14:11:25 -0800524 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
buzbeeefc63692012-11-14 16:31:52 -0800525}
526
527/* Common initialization routine for an architecture family */
buzbee52a77fc2012-11-20 19:50:46 -0800528bool ArchInit()
buzbeeefc63692012-11-14 16:31:52 -0800529{
530 int i;
531
532 for (i = 0; i < kArmLast; i++) {
533 if (EncodingMap[i].opcode != i) {
534 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
535 << " is wrong: expecting " << i << ", seeing "
buzbeecbd6d442012-11-17 14:11:25 -0800536 << static_cast<int>(EncodingMap[i].opcode);
buzbeeefc63692012-11-14 16:31:52 -0800537 }
538 }
539
buzbee52a77fc2012-11-20 19:50:46 -0800540 return ArchVariantInit();
buzbeeefc63692012-11-14 16:31:52 -0800541}
542
543/* Architecture-specific initializations and checks go here */
buzbee52a77fc2012-11-20 19:50:46 -0800544bool ArchVariantInit(void)
buzbeeefc63692012-11-14 16:31:52 -0800545{
546 return true;
547}
548
buzbeeefc63692012-11-14 16:31:52 -0800549/*
550 * Alloc a pair of core registers, or a double. Low reg in low byte,
551 * high reg in next byte.
552 */
buzbeefa57c472012-11-21 12:06:18 -0800553int AllocTypedTempPair(CompilationUnit* cu, bool fp_hint, int reg_class)
buzbeeefc63692012-11-14 16:31:52 -0800554{
buzbeefa57c472012-11-21 12:06:18 -0800555 int high_reg;
556 int low_reg;
buzbeeefc63692012-11-14 16:31:52 -0800557 int res = 0;
558
buzbeefa57c472012-11-21 12:06:18 -0800559 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
560 low_reg = AllocTempDouble(cu);
561 high_reg = low_reg + 1;
buzbeeefc63692012-11-14 16:31:52 -0800562 } else {
buzbeefa57c472012-11-21 12:06:18 -0800563 low_reg = AllocTemp(cu);
564 high_reg = AllocTemp(cu);
buzbeeefc63692012-11-14 16:31:52 -0800565 }
buzbeefa57c472012-11-21 12:06:18 -0800566 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
buzbeeefc63692012-11-14 16:31:52 -0800567 return res;
568}
569
buzbeefa57c472012-11-21 12:06:18 -0800570int AllocTypedTemp(CompilationUnit* cu, bool fp_hint, int reg_class)
buzbeeefc63692012-11-14 16:31:52 -0800571{
buzbeefa57c472012-11-21 12:06:18 -0800572 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
573 return AllocTempFloat(cu);
574 return AllocTemp(cu);
buzbeeefc63692012-11-14 16:31:52 -0800575}
576
buzbeefa57c472012-11-21 12:06:18 -0800577void CompilerInitializeRegAlloc(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800578{
buzbeefa57c472012-11-21 12:06:18 -0800579 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
580 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
581 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
582 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
583 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
buzbeecbd6d442012-11-17 14:11:25 -0800584 RegisterPool *pool =
buzbeefa57c472012-11-21 12:06:18 -0800585 static_cast<RegisterPool*>(NewMem(cu, sizeof(*pool), true, kAllocRegAlloc));
586 cu->reg_pool = pool;
587 pool->num_core_regs = num_regs;
588 pool->core_regs = reinterpret_cast<RegisterInfo*>
589 (NewMem(cu, num_regs * sizeof(*cu->reg_pool->core_regs), true, kAllocRegAlloc));
590 pool->num_fp_regs = num_fp_regs;
buzbeecbd6d442012-11-17 14:11:25 -0800591 pool->FPRegs = static_cast<RegisterInfo*>
buzbeefa57c472012-11-21 12:06:18 -0800592 (NewMem(cu, num_fp_regs * sizeof(*cu->reg_pool->FPRegs), true, kAllocRegAlloc));
593 CompilerInitPool(pool->core_regs, core_regs, pool->num_core_regs);
594 CompilerInitPool(pool->FPRegs, FpRegs, pool->num_fp_regs);
buzbeeefc63692012-11-14 16:31:52 -0800595 // Keep special registers from being allocated
buzbeefa57c472012-11-21 12:06:18 -0800596 for (int i = 0; i < num_reserved; i++) {
buzbee52a77fc2012-11-20 19:50:46 -0800597 if (NO_SUSPEND && (ReservedRegs[i] == rARM_SUSPEND)) {
buzbeeefc63692012-11-14 16:31:52 -0800598 //To measure cost of suspend check
599 continue;
600 }
buzbeefa57c472012-11-21 12:06:18 -0800601 MarkInUse(cu, ReservedRegs[i]);
buzbeeefc63692012-11-14 16:31:52 -0800602 }
603 // Mark temp regs - all others not in use can be used for promotion
buzbeefa57c472012-11-21 12:06:18 -0800604 for (int i = 0; i < num_temps; i++) {
605 MarkTemp(cu, core_temps[i]);
buzbeeefc63692012-11-14 16:31:52 -0800606 }
buzbeefa57c472012-11-21 12:06:18 -0800607 for (int i = 0; i < num_fp_temps; i++) {
608 MarkTemp(cu, fp_temps[i]);
buzbeeefc63692012-11-14 16:31:52 -0800609 }
610
611 // Start allocation at r2 in an attempt to avoid clobbering return values
buzbeefa57c472012-11-21 12:06:18 -0800612 pool->next_core_reg = r2;
buzbeeefc63692012-11-14 16:31:52 -0800613
614 // Construct the alias map.
buzbeefa57c472012-11-21 12:06:18 -0800615 cu->phi_alias_map = static_cast<int*>
616 (NewMem(cu, cu->num_ssa_regs * sizeof(cu->phi_alias_map[0]), false, kAllocDFInfo));
617 for (int i = 0; i < cu->num_ssa_regs; i++) {
618 cu->phi_alias_map[i] = i;
buzbeeefc63692012-11-14 16:31:52 -0800619 }
buzbeefa57c472012-11-21 12:06:18 -0800620 for (MIR* phi = cu->phi_list; phi; phi = phi->meta.phi_next) {
621 int def_reg = phi->ssa_rep->defs[0];
622 for (int i = 0; i < phi->ssa_rep->num_uses; i++) {
623 for (int j = 0; j < cu->num_ssa_regs; j++) {
624 if (cu->phi_alias_map[j] == phi->ssa_rep->uses[i]) {
625 cu->phi_alias_map[j] = def_reg;
buzbeeefc63692012-11-14 16:31:52 -0800626 }
627 }
628 }
629 }
630}
631
buzbeefa57c472012-11-21 12:06:18 -0800632void FreeRegLocTemps(CompilationUnit* cu, RegLocation rl_keep,
633 RegLocation rl_free)
buzbeeefc63692012-11-14 16:31:52 -0800634{
buzbeefa57c472012-11-21 12:06:18 -0800635 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
636 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
buzbeeefc63692012-11-14 16:31:52 -0800637 // No overlap, free both
buzbeefa57c472012-11-21 12:06:18 -0800638 FreeTemp(cu, rl_free.low_reg);
639 FreeTemp(cu, rl_free.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800640 }
641}
642/*
buzbeefa57c472012-11-21 12:06:18 -0800643 * TUNING: is leaf? Can't just use "has_invoke" to determine as some
buzbeeefc63692012-11-14 16:31:52 -0800644 * instructions might call out to C/assembly helper functions. Until
645 * machinery is in place, always spill lr.
646 */
647
buzbeefa57c472012-11-21 12:06:18 -0800648void AdjustSpillMask(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800649{
buzbeefa57c472012-11-21 12:06:18 -0800650 cu->core_spill_mask |= (1 << rARM_LR);
651 cu->num_core_spills++;
buzbeeefc63692012-11-14 16:31:52 -0800652}
653
654/*
655 * Mark a callee-save fp register as promoted. Note that
656 * vpush/vpop uses contiguous register lists so we must
657 * include any holes in the mask. Associate holes with
658 * Dalvik register INVALID_VREG (0xFFFFU).
659 */
buzbeefa57c472012-11-21 12:06:18 -0800660void MarkPreservedSingle(CompilationUnit* cu, int v_reg, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800661{
662 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
663 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
buzbeefa57c472012-11-21 12:06:18 -0800664 // Ensure fp_vmap_table is large enough
665 int table_size = cu->fp_vmap_table.size();
666 for (int i = table_size; i < (reg + 1); i++) {
667 cu->fp_vmap_table.push_back(INVALID_VREG);
buzbeeefc63692012-11-14 16:31:52 -0800668 }
669 // Add the current mapping
buzbeefa57c472012-11-21 12:06:18 -0800670 cu->fp_vmap_table[reg] = v_reg;
671 // Size of fp_vmap_table is high-water mark, use to set mask
672 cu->num_fp_spills = cu->fp_vmap_table.size();
673 cu->fp_spill_mask = ((1 << cu->num_fp_spills) - 1) << ARM_FP_CALLEE_SAVE_BASE;
buzbeeefc63692012-11-14 16:31:52 -0800674}
675
buzbeefa57c472012-11-21 12:06:18 -0800676void FlushRegWide(CompilationUnit* cu, int reg1, int reg2)
buzbeeefc63692012-11-14 16:31:52 -0800677{
buzbeefa57c472012-11-21 12:06:18 -0800678 RegisterInfo* info1 = GetRegInfo(cu, reg1);
679 RegisterInfo* info2 = GetRegInfo(cu, reg2);
buzbeeefc63692012-11-14 16:31:52 -0800680 DCHECK(info1 && info2 && info1->pair && info2->pair &&
681 (info1->partner == info2->reg) &&
682 (info2->partner == info1->reg));
683 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
buzbeefa57c472012-11-21 12:06:18 -0800684 if (!(info1->is_temp && info2->is_temp)) {
685 /* Should not happen. If it does, there's a problem in eval_loc */
buzbeeefc63692012-11-14 16:31:52 -0800686 LOG(FATAL) << "Long half-temp, half-promoted";
687 }
688
689 info1->dirty = false;
690 info2->dirty = false;
buzbeefa57c472012-11-21 12:06:18 -0800691 if (SRegToVReg(cu, info2->s_reg) <
692 SRegToVReg(cu, info1->s_reg))
buzbeeefc63692012-11-14 16:31:52 -0800693 info1 = info2;
buzbeefa57c472012-11-21 12:06:18 -0800694 int v_reg = SRegToVReg(cu, info1->s_reg);
695 StoreBaseDispWide(cu, rARM_SP, VRegOffset(cu, v_reg), info1->reg, info1->partner);
buzbeeefc63692012-11-14 16:31:52 -0800696 }
697}
698
buzbeefa57c472012-11-21 12:06:18 -0800699void FlushReg(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800700{
buzbeefa57c472012-11-21 12:06:18 -0800701 RegisterInfo* info = GetRegInfo(cu, reg);
buzbeeefc63692012-11-14 16:31:52 -0800702 if (info->live && info->dirty) {
703 info->dirty = false;
buzbeefa57c472012-11-21 12:06:18 -0800704 int v_reg = SRegToVReg(cu, info->s_reg);
705 StoreBaseDisp(cu, rARM_SP, VRegOffset(cu, v_reg), reg, kWord);
buzbeeefc63692012-11-14 16:31:52 -0800706 }
707}
708
709/* Give access to the target-dependent FP register encoding to common code */
buzbee52a77fc2012-11-20 19:50:46 -0800710bool IsFpReg(int reg) {
buzbeeefc63692012-11-14 16:31:52 -0800711 return ARM_FPREG(reg);
712}
713
buzbeeefc63692012-11-14 16:31:52 -0800714/* Clobber all regs that might be used by an external C call */
buzbeefa57c472012-11-21 12:06:18 -0800715void ClobberCalleeSave(CompilationUnit *cu)
buzbeeefc63692012-11-14 16:31:52 -0800716{
buzbeefa57c472012-11-21 12:06:18 -0800717 Clobber(cu, r0);
718 Clobber(cu, r1);
719 Clobber(cu, r2);
720 Clobber(cu, r3);
721 Clobber(cu, r12);
722 Clobber(cu, r14lr);
723 Clobber(cu, fr0);
724 Clobber(cu, fr1);
725 Clobber(cu, fr2);
726 Clobber(cu, fr3);
727 Clobber(cu, fr4);
728 Clobber(cu, fr5);
729 Clobber(cu, fr6);
730 Clobber(cu, fr7);
731 Clobber(cu, fr8);
732 Clobber(cu, fr9);
733 Clobber(cu, fr10);
734 Clobber(cu, fr11);
735 Clobber(cu, fr12);
736 Clobber(cu, fr13);
737 Clobber(cu, fr14);
738 Clobber(cu, fr15);
buzbeeefc63692012-11-14 16:31:52 -0800739}
740
buzbeefa57c472012-11-21 12:06:18 -0800741RegLocation GetReturnWideAlt(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800742{
buzbee52a77fc2012-11-20 19:50:46 -0800743 RegLocation res = LocCReturnWide();
buzbeefa57c472012-11-21 12:06:18 -0800744 res.low_reg = r2;
745 res.high_reg = r3;
746 Clobber(cu, r2);
747 Clobber(cu, r3);
748 MarkInUse(cu, r2);
749 MarkInUse(cu, r3);
750 MarkPair(cu, res.low_reg, res.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800751 return res;
752}
753
buzbeefa57c472012-11-21 12:06:18 -0800754RegLocation GetReturnAlt(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800755{
buzbee52a77fc2012-11-20 19:50:46 -0800756 RegLocation res = LocCReturn();
buzbeefa57c472012-11-21 12:06:18 -0800757 res.low_reg = r1;
758 Clobber(cu, r1);
759 MarkInUse(cu, r1);
buzbeeefc63692012-11-14 16:31:52 -0800760 return res;
761}
762
buzbeefa57c472012-11-21 12:06:18 -0800763RegisterInfo* GetRegInfo(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800764{
buzbeefa57c472012-11-21 12:06:18 -0800765 return ARM_FPREG(reg) ? &cu->reg_pool->FPRegs[reg & ARM_FP_REG_MASK]
766 : &cu->reg_pool->core_regs[reg];
buzbeeefc63692012-11-14 16:31:52 -0800767}
768
769/* To be used when explicitly managing register use */
buzbeefa57c472012-11-21 12:06:18 -0800770void LockCallTemps(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800771{
buzbeefa57c472012-11-21 12:06:18 -0800772 LockTemp(cu, r0);
773 LockTemp(cu, r1);
774 LockTemp(cu, r2);
775 LockTemp(cu, r3);
buzbeeefc63692012-11-14 16:31:52 -0800776}
777
778/* To be used when explicitly managing register use */
buzbeefa57c472012-11-21 12:06:18 -0800779void FreeCallTemps(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800780{
buzbeefa57c472012-11-21 12:06:18 -0800781 FreeTemp(cu, r0);
782 FreeTemp(cu, r1);
783 FreeTemp(cu, r2);
784 FreeTemp(cu, r3);
buzbeeefc63692012-11-14 16:31:52 -0800785}
786
buzbeefa57c472012-11-21 12:06:18 -0800787int LoadHelper(CompilationUnit* cu, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800788{
buzbeefa57c472012-11-21 12:06:18 -0800789 LoadWordDisp(cu, rARM_SELF, offset, rARM_LR);
buzbeeefc63692012-11-14 16:31:52 -0800790 return rARM_LR;
791}
792
buzbee52a77fc2012-11-20 19:50:46 -0800793uint64_t GetTargetInstFlags(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800794{
795 return EncodingMap[opcode].flags;
796}
797
buzbee52a77fc2012-11-20 19:50:46 -0800798const char* GetTargetInstName(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800799{
800 return EncodingMap[opcode].name;
801}
802
buzbee52a77fc2012-11-20 19:50:46 -0800803const char* GetTargetInstFmt(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800804{
805 return EncodingMap[opcode].fmt;
806}
807
buzbeeefc63692012-11-14 16:31:52 -0800808} // namespace art