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