1 /*
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 "codegen_arm.h"
18
19 #include <inttypes.h>
20
21 #include <string>
22
23 #include "dex/compiler_internals.h"
24 #include "dex/quick/mir_to_lir-inl.h"
25
26 namespace art {
27
28 #ifdef ARM_R4_SUSPEND_FLAG
29 static constexpr RegStorage core_regs_arr[] =
30 {rs_r0, rs_r1, rs_r2, rs_r3, rs_rARM_SUSPEND, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
31 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
32 #else
33 static constexpr RegStorage core_regs_arr[] =
34 {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
35 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
36 #endif
37 static constexpr RegStorage sp_regs_arr[] =
38 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
39 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20,
40 rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30,
41 rs_fr31};
42 static constexpr RegStorage dp_regs_arr[] =
43 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10,
44 rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15};
45 #ifdef ARM_R4_SUSPEND_FLAG
46 static constexpr RegStorage reserved_regs_arr[] =
47 {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
48 static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
49 #else
50 static constexpr RegStorage reserved_regs_arr[] =
51 {rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
52 static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r12};
53 #endif
54 static constexpr RegStorage sp_temps_arr[] =
55 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
56 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
57 static constexpr RegStorage dp_temps_arr[] =
58 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
59
60 static constexpr ArrayRef<const RegStorage> empty_pool;
61 static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
62 static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
63 static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
64 static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
65 static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
66 static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
67 static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
68
LocCReturn()69 RegLocation ArmMir2Lir::LocCReturn() {
70 return arm_loc_c_return;
71 }
72
LocCReturnRef()73 RegLocation ArmMir2Lir::LocCReturnRef() {
74 return arm_loc_c_return;
75 }
76
LocCReturnWide()77 RegLocation ArmMir2Lir::LocCReturnWide() {
78 return arm_loc_c_return_wide;
79 }
80
LocCReturnFloat()81 RegLocation ArmMir2Lir::LocCReturnFloat() {
82 return arm_loc_c_return_float;
83 }
84
LocCReturnDouble()85 RegLocation ArmMir2Lir::LocCReturnDouble() {
86 return arm_loc_c_return_double;
87 }
88
89 // Return a target-dependent special register.
TargetReg(SpecialTargetRegister reg)90 RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
91 RegStorage res_reg = RegStorage::InvalidReg();
92 switch (reg) {
93 case kSelf: res_reg = rs_rARM_SELF; break;
94 #ifdef ARM_R4_SUSPEND_FLAG
95 case kSuspend: res_reg = rs_rARM_SUSPEND; break;
96 #else
97 case kSuspend: res_reg = RegStorage::InvalidReg(); break;
98 #endif
99 case kLr: res_reg = rs_rARM_LR; break;
100 case kPc: res_reg = rs_rARM_PC; break;
101 case kSp: res_reg = rs_rARM_SP; break;
102 case kArg0: res_reg = rs_r0; break;
103 case kArg1: res_reg = rs_r1; break;
104 case kArg2: res_reg = rs_r2; break;
105 case kArg3: res_reg = rs_r3; break;
106 case kFArg0: res_reg = rs_r0; break;
107 case kFArg1: res_reg = rs_r1; break;
108 case kFArg2: res_reg = rs_r2; break;
109 case kFArg3: res_reg = rs_r3; break;
110 case kRet0: res_reg = rs_r0; break;
111 case kRet1: res_reg = rs_r1; break;
112 case kInvokeTgt: res_reg = rs_rARM_LR; break;
113 case kHiddenArg: res_reg = rs_r12; break;
114 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
115 case kCount: res_reg = RegStorage::InvalidReg(); break;
116 default: res_reg = RegStorage::InvalidReg();
117 }
118 return res_reg;
119 }
120
GetArgMappingToPhysicalReg(int arg_num)121 RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
122 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
123 switch (arg_num) {
124 case 0:
125 return rs_r1;
126 case 1:
127 return rs_r2;
128 case 2:
129 return rs_r3;
130 default:
131 return RegStorage::InvalidReg();
132 }
133 }
134
135 /*
136 * Decode the register id.
137 */
GetRegMaskCommon(const RegStorage & reg) const138 ResourceMask ArmMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
139 return GetRegMaskArm(reg);
140 }
141
GetRegMaskArm(RegStorage reg)142 constexpr ResourceMask ArmMir2Lir::GetRegMaskArm(RegStorage reg) {
143 return reg.IsDouble()
144 /* Each double register is equal to a pair of single-precision FP registers */
145 ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kArmFPReg0)
146 : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kArmFPReg0 : reg.GetRegNum());
147 }
148
EncodeArmRegList(int reg_list)149 constexpr ResourceMask ArmMir2Lir::EncodeArmRegList(int reg_list) {
150 return ResourceMask::RawMask(static_cast<uint64_t >(reg_list), 0u);
151 }
152
EncodeArmRegFpcsList(int reg_list)153 constexpr ResourceMask ArmMir2Lir::EncodeArmRegFpcsList(int reg_list) {
154 return ResourceMask::RawMask(static_cast<uint64_t >(reg_list) << kArmFPReg16, 0u);
155 }
156
GetPCUseDefEncoding() const157 ResourceMask ArmMir2Lir::GetPCUseDefEncoding() const {
158 return ResourceMask::Bit(kArmRegPC);
159 }
160
161 // Thumb2 specific setup. TODO: inline?:
SetupTargetResourceMasks(LIR * lir,uint64_t flags,ResourceMask * use_mask,ResourceMask * def_mask)162 void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags,
163 ResourceMask* use_mask, ResourceMask* def_mask) {
164 DCHECK_EQ(cu_->instruction_set, kThumb2);
165 DCHECK(!lir->flags.use_def_invalid);
166
167 int opcode = lir->opcode;
168
169 // These flags are somewhat uncommon - bypass if we can.
170 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
171 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
172 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
173 if (flags & REG_DEF_SP) {
174 def_mask->SetBit(kArmRegSP);
175 }
176
177 if (flags & REG_USE_SP) {
178 use_mask->SetBit(kArmRegSP);
179 }
180
181 if (flags & REG_DEF_LIST0) {
182 def_mask->SetBits(EncodeArmRegList(lir->operands[0]));
183 }
184
185 if (flags & REG_DEF_LIST1) {
186 def_mask->SetBits(EncodeArmRegList(lir->operands[1]));
187 }
188
189 if (flags & REG_DEF_FPCS_LIST0) {
190 def_mask->SetBits(EncodeArmRegList(lir->operands[0]));
191 }
192
193 if (flags & REG_DEF_FPCS_LIST2) {
194 for (int i = 0; i < lir->operands[2]; i++) {
195 SetupRegMask(def_mask, lir->operands[1] + i);
196 }
197 }
198
199 if (flags & REG_USE_PC) {
200 use_mask->SetBit(kArmRegPC);
201 }
202
203 /* Conservatively treat the IT block */
204 if (flags & IS_IT) {
205 *def_mask = kEncodeAll;
206 }
207
208 if (flags & REG_USE_LIST0) {
209 use_mask->SetBits(EncodeArmRegList(lir->operands[0]));
210 }
211
212 if (flags & REG_USE_LIST1) {
213 use_mask->SetBits(EncodeArmRegList(lir->operands[1]));
214 }
215
216 if (flags & REG_USE_FPCS_LIST0) {
217 use_mask->SetBits(EncodeArmRegList(lir->operands[0]));
218 }
219
220 if (flags & REG_USE_FPCS_LIST2) {
221 for (int i = 0; i < lir->operands[2]; i++) {
222 SetupRegMask(use_mask, lir->operands[1] + i);
223 }
224 }
225 /* Fixup for kThumbPush/lr and kThumbPop/pc */
226 if (opcode == kThumbPush || opcode == kThumbPop) {
227 constexpr ResourceMask r8Mask = GetRegMaskArm(rs_r8);
228 if ((opcode == kThumbPush) && (use_mask->Intersects(r8Mask))) {
229 use_mask->ClearBits(r8Mask);
230 use_mask->SetBit(kArmRegLR);
231 } else if ((opcode == kThumbPop) && (def_mask->Intersects(r8Mask))) {
232 def_mask->ClearBits(r8Mask);
233 def_mask->SetBit(kArmRegPC);;
234 }
235 }
236 if (flags & REG_DEF_LR) {
237 def_mask->SetBit(kArmRegLR);
238 }
239 }
240 }
241
ArmConditionEncoding(ConditionCode ccode)242 ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
243 ArmConditionCode res;
244 switch (ccode) {
245 case kCondEq: res = kArmCondEq; break;
246 case kCondNe: res = kArmCondNe; break;
247 case kCondCs: res = kArmCondCs; break;
248 case kCondCc: res = kArmCondCc; break;
249 case kCondUlt: res = kArmCondCc; break;
250 case kCondUge: res = kArmCondCs; break;
251 case kCondMi: res = kArmCondMi; break;
252 case kCondPl: res = kArmCondPl; break;
253 case kCondVs: res = kArmCondVs; break;
254 case kCondVc: res = kArmCondVc; break;
255 case kCondHi: res = kArmCondHi; break;
256 case kCondLs: res = kArmCondLs; break;
257 case kCondGe: res = kArmCondGe; break;
258 case kCondLt: res = kArmCondLt; break;
259 case kCondGt: res = kArmCondGt; break;
260 case kCondLe: res = kArmCondLe; break;
261 case kCondAl: res = kArmCondAl; break;
262 case kCondNv: res = kArmCondNv; break;
263 default:
264 LOG(FATAL) << "Bad condition code " << ccode;
265 res = static_cast<ArmConditionCode>(0); // Quiet gcc
266 }
267 return res;
268 }
269
270 static const char* core_reg_names[16] = {
271 "r0",
272 "r1",
273 "r2",
274 "r3",
275 "r4",
276 "r5",
277 "r6",
278 "r7",
279 "r8",
280 "rSELF",
281 "r10",
282 "r11",
283 "r12",
284 "sp",
285 "lr",
286 "pc",
287 };
288
289
290 static const char* shift_names[4] = {
291 "lsl",
292 "lsr",
293 "asr",
294 "ror"};
295
296 /* Decode and print a ARM register name */
DecodeRegList(int opcode,int vector,char * buf,size_t buf_size)297 static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
298 int i;
299 bool printed = false;
300 buf[0] = 0;
301 for (i = 0; i < 16; i++, vector >>= 1) {
302 if (vector & 0x1) {
303 int reg_id = i;
304 if (opcode == kThumbPush && i == 8) {
305 reg_id = rs_rARM_LR.GetRegNum();
306 } else if (opcode == kThumbPop && i == 8) {
307 reg_id = rs_rARM_PC.GetRegNum();
308 }
309 if (printed) {
310 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
311 } else {
312 printed = true;
313 snprintf(buf, buf_size, "r%d", reg_id);
314 }
315 }
316 }
317 return buf;
318 }
319
DecodeFPCSRegList(int count,int base,char * buf,size_t buf_size)320 static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
321 snprintf(buf, buf_size, "s%d", base);
322 for (int i = 1; i < count; i++) {
323 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
324 }
325 return buf;
326 }
327
ExpandImmediate(int value)328 static int32_t ExpandImmediate(int value) {
329 int32_t mode = (value & 0xf00) >> 8;
330 uint32_t bits = value & 0xff;
331 switch (mode) {
332 case 0:
333 return bits;
334 case 1:
335 return (bits << 16) | bits;
336 case 2:
337 return (bits << 24) | (bits << 8);
338 case 3:
339 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
340 default:
341 break;
342 }
343 bits = (bits | 0x80) << 24;
344 return bits >> (((value & 0xf80) >> 7) - 8);
345 }
346
347 const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
348 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
349 /*
350 * Interpret a format string and build a string no longer than size
351 * See format key in Assemble.c.
352 */
BuildInsnString(const char * fmt,LIR * lir,unsigned char * base_addr)353 std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
354 std::string buf;
355 int i;
356 const char* fmt_end = &fmt[strlen(fmt)];
357 char tbuf[256];
358 const char* name;
359 char nc;
360 while (fmt < fmt_end) {
361 int operand;
362 if (*fmt == '!') {
363 fmt++;
364 DCHECK_LT(fmt, fmt_end);
365 nc = *fmt++;
366 if (nc == '!') {
367 strcpy(tbuf, "!");
368 } else {
369 DCHECK_LT(fmt, fmt_end);
370 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
371 operand = lir->operands[nc-'0'];
372 switch (*fmt++) {
373 case 'H':
374 if (operand != 0) {
375 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
376 } else {
377 strcpy(tbuf, "");
378 }
379 break;
380 case 'B':
381 switch (operand) {
382 case kSY:
383 name = "sy";
384 break;
385 case kST:
386 name = "st";
387 break;
388 case kISH:
389 name = "ish";
390 break;
391 case kISHST:
392 name = "ishst";
393 break;
394 case kNSH:
395 name = "nsh";
396 break;
397 case kNSHST:
398 name = "shst";
399 break;
400 default:
401 name = "DecodeError2";
402 break;
403 }
404 strcpy(tbuf, name);
405 break;
406 case 'b':
407 strcpy(tbuf, "0000");
408 for (i = 3; i >= 0; i--) {
409 tbuf[i] += operand & 1;
410 operand >>= 1;
411 }
412 break;
413 case 'n':
414 operand = ~ExpandImmediate(operand);
415 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
416 break;
417 case 'm':
418 operand = ExpandImmediate(operand);
419 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
420 break;
421 case 's':
422 snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
423 break;
424 case 'S':
425 snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
426 break;
427 case 'h':
428 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
429 break;
430 case 'M':
431 case 'd':
432 snprintf(tbuf, arraysize(tbuf), "%d", operand);
433 break;
434 case 'C':
435 operand = RegStorage::RegNum(operand);
436 DCHECK_LT(operand, static_cast<int>(
437 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
438 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
439 break;
440 case 'E':
441 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
442 break;
443 case 'F':
444 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
445 break;
446 case 'c':
447 strcpy(tbuf, cc_names[operand]);
448 break;
449 case 't':
450 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
451 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
452 lir->target);
453 break;
454 case 'u': {
455 int offset_1 = lir->operands[0];
456 int offset_2 = NEXT_LIR(lir)->operands[0];
457 uintptr_t target =
458 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
459 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
460 0xfffffffc;
461 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
462 break;
463 }
464
465 /* Nothing to print for BLX_2 */
466 case 'v':
467 strcpy(tbuf, "see above");
468 break;
469 case 'R':
470 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
471 break;
472 case 'P':
473 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
474 break;
475 case 'Q':
476 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
477 break;
478 default:
479 strcpy(tbuf, "DecodeError1");
480 break;
481 }
482 buf += tbuf;
483 }
484 } else {
485 buf += *fmt++;
486 }
487 }
488 return buf;
489 }
490
DumpResourceMask(LIR * arm_lir,const ResourceMask & mask,const char * prefix)491 void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, const ResourceMask& mask, const char* prefix) {
492 char buf[256];
493 buf[0] = 0;
494
495 if (mask.Equals(kEncodeAll)) {
496 strcpy(buf, "all");
497 } else {
498 char num[8];
499 int i;
500
501 for (i = 0; i < kArmRegEnd; i++) {
502 if (mask.HasBit(i)) {
503 snprintf(num, arraysize(num), "%d ", i);
504 strcat(buf, num);
505 }
506 }
507
508 if (mask.HasBit(ResourceMask::kCCode)) {
509 strcat(buf, "cc ");
510 }
511 if (mask.HasBit(ResourceMask::kFPStatus)) {
512 strcat(buf, "fpcc ");
513 }
514
515 /* Memory bits */
516 if (arm_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
517 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
518 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
519 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
520 }
521 if (mask.HasBit(ResourceMask::kLiteral)) {
522 strcat(buf, "lit ");
523 }
524
525 if (mask.HasBit(ResourceMask::kHeapRef)) {
526 strcat(buf, "heap ");
527 }
528 if (mask.HasBit(ResourceMask::kMustNotAlias)) {
529 strcat(buf, "noalias ");
530 }
531 }
532 if (buf[0]) {
533 LOG(INFO) << prefix << ": " << buf;
534 }
535 }
536
IsUnconditionalBranch(LIR * lir)537 bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
538 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
539 }
540
RegClassForFieldLoadStore(OpSize size,bool is_volatile)541 RegisterClass ArmMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
542 if (UNLIKELY(is_volatile)) {
543 // On arm, atomic 64-bit load/store requires a core register pair.
544 // Smaller aligned load/store is atomic for both core and fp registers.
545 if (size == k64 || size == kDouble) {
546 return kCoreReg;
547 }
548 }
549 return RegClassBySize(size);
550 }
551
ArmMir2Lir(CompilationUnit * cu,MIRGraph * mir_graph,ArenaAllocator * arena)552 ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
553 : Mir2Lir(cu, mir_graph, arena) {
554 // Sanity check - make sure encoding map lines up.
555 for (int i = 0; i < kArmLast; i++) {
556 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
557 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
558 << " is wrong: expecting " << i << ", seeing "
559 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
560 }
561 }
562 }
563
ArmCodeGenerator(CompilationUnit * const cu,MIRGraph * const mir_graph,ArenaAllocator * const arena)564 Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
565 ArenaAllocator* const arena) {
566 return new ArmMir2Lir(cu, mir_graph, arena);
567 }
568
CompilerInitializeRegAlloc()569 void ArmMir2Lir::CompilerInitializeRegAlloc() {
570 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs,
571 dp_regs, reserved_regs, empty_pool /* reserved64 */,
572 core_temps, empty_pool /* core64_temps */, sp_temps,
573 dp_temps);
574
575 // Target-specific adjustments.
576
577 // Alias single precision floats to appropriate half of overlapping double.
578 GrowableArray<RegisterInfo*>::Iterator it(®_pool_->sp_regs_);
579 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
580 int sp_reg_num = info->GetReg().GetRegNum();
581 int dp_reg_num = sp_reg_num >> 1;
582 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
583 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
584 // Double precision register's master storage should refer to itself.
585 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
586 // Redirect single precision's master storage to master.
587 info->SetMaster(dp_reg_info);
588 // Singles should show a single 32-bit mask bit, at first referring to the low half.
589 DCHECK_EQ(info->StorageMask(), RegisterInfo::kLowSingleStorageMask);
590 if (sp_reg_num & 1) {
591 // For odd singles, change to use the high word of the backing double.
592 info->SetStorageMask(RegisterInfo::kHighSingleStorageMask);
593 }
594 }
595
596 #ifdef ARM_R4_SUSPEND_FLAG
597 // TODO: re-enable this when we can safely save r4 over the suspension code path.
598 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
599 if (no_suspend) {
600 GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
601 }
602 #endif
603
604 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
605 // TODO: adjust when we roll to hard float calling convention.
606 reg_pool_->next_core_reg_ = 2;
607 reg_pool_->next_sp_reg_ = 0;
608 reg_pool_->next_dp_reg_ = 0;
609 }
610
611 /*
612 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
613 * instructions might call out to C/assembly helper functions. Until
614 * machinery is in place, always spill lr.
615 */
616
AdjustSpillMask()617 void ArmMir2Lir::AdjustSpillMask() {
618 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
619 num_core_spills_++;
620 }
621
622 /*
623 * Mark a callee-save fp register as promoted. Note that
624 * vpush/vpop uses contiguous register lists so we must
625 * include any holes in the mask. Associate holes with
626 * Dalvik register INVALID_VREG (0xFFFFU).
627 */
MarkPreservedSingle(int v_reg,RegStorage reg)628 void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
629 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
630 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
631 // Ensure fp_vmap_table is large enough
632 int table_size = fp_vmap_table_.size();
633 for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
634 fp_vmap_table_.push_back(INVALID_VREG);
635 }
636 // Add the current mapping
637 fp_vmap_table_[adjusted_reg_num] = v_reg;
638 // Size of fp_vmap_table is high-water mark, use to set mask
639 num_fp_spills_ = fp_vmap_table_.size();
640 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
641 }
642
MarkPreservedDouble(int v_reg,RegStorage reg)643 void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
644 // TEMP: perform as 2 singles.
645 int reg_num = reg.GetRegNum() << 1;
646 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
647 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
648 MarkPreservedSingle(v_reg, lo);
649 MarkPreservedSingle(v_reg + 1, hi);
650 }
651
652 /* Clobber all regs that might be used by an external C call */
ClobberCallerSave()653 void ArmMir2Lir::ClobberCallerSave() {
654 // TODO: rework this - it's gotten even more ugly.
655 Clobber(rs_r0);
656 Clobber(rs_r1);
657 Clobber(rs_r2);
658 Clobber(rs_r3);
659 Clobber(rs_r12);
660 Clobber(rs_r14lr);
661 Clobber(rs_fr0);
662 Clobber(rs_fr1);
663 Clobber(rs_fr2);
664 Clobber(rs_fr3);
665 Clobber(rs_fr4);
666 Clobber(rs_fr5);
667 Clobber(rs_fr6);
668 Clobber(rs_fr7);
669 Clobber(rs_fr8);
670 Clobber(rs_fr9);
671 Clobber(rs_fr10);
672 Clobber(rs_fr11);
673 Clobber(rs_fr12);
674 Clobber(rs_fr13);
675 Clobber(rs_fr14);
676 Clobber(rs_fr15);
677 Clobber(rs_dr0);
678 Clobber(rs_dr1);
679 Clobber(rs_dr2);
680 Clobber(rs_dr3);
681 Clobber(rs_dr4);
682 Clobber(rs_dr5);
683 Clobber(rs_dr6);
684 Clobber(rs_dr7);
685 }
686
GetReturnWideAlt()687 RegLocation ArmMir2Lir::GetReturnWideAlt() {
688 RegLocation res = LocCReturnWide();
689 res.reg.SetLowReg(rs_r2.GetReg());
690 res.reg.SetHighReg(rs_r3.GetReg());
691 Clobber(rs_r2);
692 Clobber(rs_r3);
693 MarkInUse(rs_r2);
694 MarkInUse(rs_r3);
695 MarkWide(res.reg);
696 return res;
697 }
698
GetReturnAlt()699 RegLocation ArmMir2Lir::GetReturnAlt() {
700 RegLocation res = LocCReturn();
701 res.reg.SetReg(rs_r1.GetReg());
702 Clobber(rs_r1);
703 MarkInUse(rs_r1);
704 return res;
705 }
706
707 /* To be used when explicitly managing register use */
LockCallTemps()708 void ArmMir2Lir::LockCallTemps() {
709 LockTemp(rs_r0);
710 LockTemp(rs_r1);
711 LockTemp(rs_r2);
712 LockTemp(rs_r3);
713 }
714
715 /* To be used when explicitly managing register use */
FreeCallTemps()716 void ArmMir2Lir::FreeCallTemps() {
717 FreeTemp(rs_r0);
718 FreeTemp(rs_r1);
719 FreeTemp(rs_r2);
720 FreeTemp(rs_r3);
721 FreeTemp(TargetReg(kHiddenArg));
722 }
723
LoadHelper(QuickEntrypointEnum trampoline)724 RegStorage ArmMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
725 LoadWordDisp(rs_rARM_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rARM_LR);
726 return rs_rARM_LR;
727 }
728
CheckSuspendUsingLoad()729 LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
730 RegStorage tmp = rs_r0;
731 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
732 LIR* load2 = Load32Disp(tmp, 0, tmp);
733 return load2;
734 }
735
GetTargetInstFlags(int opcode)736 uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
737 DCHECK(!IsPseudoLirOp(opcode));
738 return ArmMir2Lir::EncodingMap[opcode].flags;
739 }
740
GetTargetInstName(int opcode)741 const char* ArmMir2Lir::GetTargetInstName(int opcode) {
742 DCHECK(!IsPseudoLirOp(opcode));
743 return ArmMir2Lir::EncodingMap[opcode].name;
744 }
745
GetTargetInstFmt(int opcode)746 const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
747 DCHECK(!IsPseudoLirOp(opcode));
748 return ArmMir2Lir::EncodingMap[opcode].fmt;
749 }
750
751 /*
752 * Somewhat messy code here. We want to allocate a pair of contiguous
753 * physical single-precision floating point registers starting with
754 * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
755 * has already been allocated - try to fit if possible. Fail to
756 * allocate if we can't meet the requirements for the pair of
757 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
758 */
759 // TODO: needs rewrite to support non-backed 64-bit float regs.
AllocPreservedDouble(int s_reg)760 RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
761 RegStorage res;
762 int v_reg = mir_graph_->SRegToVReg(s_reg);
763 int p_map_idx = SRegToPMap(s_reg);
764 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
765 // Upper reg is already allocated. Can we fit?
766 int high_reg = promotion_map_[p_map_idx+1].fp_reg;
767 if ((high_reg & 1) == 0) {
768 // High reg is even - fail.
769 return res; // Invalid.
770 }
771 // Is the low reg of the pair free?
772 // FIXME: rework.
773 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
774 if (p->InUse() || p->IsTemp()) {
775 // Already allocated or not preserved - fail.
776 return res; // Invalid.
777 }
778 // OK - good to go.
779 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
780 p->MarkInUse();
781 MarkPreservedSingle(v_reg, p->GetReg());
782 } else {
783 /*
784 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
785 * different underlying physical registers.
786 */
787 GrowableArray<RegisterInfo*>::Iterator it(®_pool_->dp_regs_);
788 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
789 if (!info->IsTemp() && !info->InUse()) {
790 res = info->GetReg();
791 info->MarkInUse();
792 MarkPreservedDouble(v_reg, info->GetReg());
793 break;
794 }
795 }
796 }
797 if (res.Valid()) {
798 RegisterInfo* info = GetRegInfo(res);
799 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
800 promotion_map_[p_map_idx].fp_reg =
801 info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg().GetReg();
802 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
803 promotion_map_[p_map_idx+1].fp_reg =
804 info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg().GetReg();
805 }
806 return res;
807 }
808
809 // Reserve a callee-save sp single register.
AllocPreservedSingle(int s_reg)810 RegStorage ArmMir2Lir::AllocPreservedSingle(int s_reg) {
811 RegStorage res;
812 GrowableArray<RegisterInfo*>::Iterator it(®_pool_->sp_regs_);
813 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
814 if (!info->IsTemp() && !info->InUse()) {
815 res = info->GetReg();
816 int p_map_idx = SRegToPMap(s_reg);
817 int v_reg = mir_graph_->SRegToVReg(s_reg);
818 GetRegInfo(res)->MarkInUse();
819 MarkPreservedSingle(v_reg, res);
820 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
821 promotion_map_[p_map_idx].fp_reg = res.GetReg();
822 break;
823 }
824 }
825 return res;
826 }
827
828 } // namespace art
829