target_arm64.cc revision 2f244e9faccfcca68af3c5484c397a01a1c3a342
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_arm64.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 26namespace art { 27 28// TODO: rework this when c++11 support allows. 29static const RegStorage core_regs_arr[] = 30 {rs_x0, rs_x1, rs_x2, rs_x3, rs_x4, rs_x5, rs_x6, rs_x7, 31 rs_x8, rs_x9, rs_x10, rs_x11, rs_x12, rs_x13, rs_x14, rs_x15, 32 rs_x16, rs_x17, rs_x18, rs_x19, rs_x20, rs_x21, rs_x22, rs_x23, 33 rs_x24, rs_x25, rs_x26, rs_x27, rs_x28, rs_x29, rs_x30, rs_x31}; 34static const RegStorage sp_regs_arr[] = 35 {rs_f0, rs_f1, rs_f2, rs_f3, rs_f4, rs_f5, rs_f6, rs_f7, 36 rs_f8, rs_f9, rs_f10, rs_f11, rs_f12, rs_f13, rs_f14, rs_f15, 37 rs_f16, rs_f17, rs_f18, rs_f19, rs_f20, rs_f21, rs_f22, rs_f23, 38 rs_f24, rs_f25, rs_f26, rs_f27, rs_f28, rs_f29, rs_f30, rs_f31}; 39static const RegStorage dp_regs_arr[] = 40 {rs_d0, rs_d1, rs_d2, rs_d3, rs_d4, rs_d5, rs_d6, rs_d7, 41 rs_d8, rs_d9, rs_d10, rs_d11, rs_d12, rs_d13, rs_d14, rs_d15}; 42static const RegStorage reserved_regs_arr[] = 43 {rs_rA64_SUSPEND, rs_rA64_SELF, rs_rA64_SP, rs_rA64_LR}; 44static const RegStorage core_temps_arr[] = 45 {rs_x0, rs_x1, rs_x2, rs_x3, rs_x12}; 46static const RegStorage sp_temps_arr[] = 47 {rs_f0, rs_f1, rs_f2, rs_f3, rs_f4, rs_f5, rs_f6, rs_f7, 48 rs_f8, rs_f9, rs_f10, rs_f11, rs_f12, rs_f13, rs_f14, rs_f15}; 49static const RegStorage dp_temps_arr[] = 50 {rs_d0, rs_d1, rs_d2, rs_d3, rs_d4, rs_d5, rs_d6, rs_d7}; 51 52static const std::vector<RegStorage> core_regs(core_regs_arr, 53 core_regs_arr + arraysize(core_regs_arr)); 54static const std::vector<RegStorage> sp_regs(sp_regs_arr, 55 sp_regs_arr + arraysize(sp_regs_arr)); 56static const std::vector<RegStorage> dp_regs(dp_regs_arr, 57 dp_regs_arr + arraysize(dp_regs_arr)); 58static const std::vector<RegStorage> reserved_regs(reserved_regs_arr, 59 reserved_regs_arr + arraysize(reserved_regs_arr)); 60static const std::vector<RegStorage> core_temps(core_temps_arr, 61 core_temps_arr + arraysize(core_temps_arr)); 62static const std::vector<RegStorage> sp_temps(sp_temps_arr, sp_temps_arr + arraysize(sp_temps_arr)); 63static const std::vector<RegStorage> dp_temps(dp_temps_arr, dp_temps_arr + arraysize(dp_temps_arr)); 64 65RegLocation Arm64Mir2Lir::LocCReturn() { 66 return arm_loc_c_return; 67} 68 69RegLocation Arm64Mir2Lir::LocCReturnWide() { 70 return arm_loc_c_return_wide; 71} 72 73RegLocation Arm64Mir2Lir::LocCReturnFloat() { 74 return arm_loc_c_return_float; 75} 76 77RegLocation Arm64Mir2Lir::LocCReturnDouble() { 78 return arm_loc_c_return_double; 79} 80 81// Return a target-dependent special register. 82RegStorage Arm64Mir2Lir::TargetReg(SpecialTargetRegister reg) { 83 // TODO(Arm64): this function doesn't work for hard-float ABI. 84 RegStorage res_reg = RegStorage::InvalidReg(); 85 switch (reg) { 86 case kSelf: res_reg = rs_rA64_SELF; break; 87 case kSuspend: res_reg = rs_rA64_SUSPEND; break; 88 case kLr: res_reg = rs_rA64_LR; break; 89 case kPc: res_reg = RegStorage::InvalidReg(); break; 90 case kSp: res_reg = rs_rA64_SP; break; 91 case kArg0: res_reg = rs_x0; break; 92 case kArg1: res_reg = rs_x1; break; 93 case kArg2: res_reg = rs_x2; break; 94 case kArg3: res_reg = rs_x3; break; 95 case kFArg0: res_reg = rs_f0; break; 96 case kFArg1: res_reg = rs_f1; break; 97 case kFArg2: res_reg = rs_f2; break; 98 case kFArg3: res_reg = rs_f3; break; 99 case kRet0: res_reg = rs_x0; break; 100 case kRet1: res_reg = rs_x0; break; 101 case kInvokeTgt: res_reg = rs_rA64_LR; break; 102 case kHiddenArg: res_reg = rs_x12; break; 103 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break; 104 case kCount: res_reg = RegStorage::InvalidReg(); break; 105 } 106 return res_reg; 107} 108 109RegStorage Arm64Mir2Lir::GetArgMappingToPhysicalReg(int arg_num) { 110 return RegStorage::InvalidReg(); 111} 112 113/* 114 * Decode the register id. This routine makes assumptions on the encoding made by RegStorage. 115 */ 116uint64_t Arm64Mir2Lir::GetRegMaskCommon(RegStorage reg) { 117 // TODO(Arm64): this function depends too much on the internal RegStorage encoding. Refactor. 118 119 int reg_raw = reg.GetRawBits(); 120 // Check if the shape mask is zero (i.e. invalid). 121 if (UNLIKELY(reg == rs_wzr || reg == rs_xzr)) { 122 // The zero register is not a true register. It is just an immediate zero. 123 return 0; 124 } 125 126 return UINT64_C(1) << (reg_raw & RegStorage::kRegTypeMask); 127} 128 129uint64_t Arm64Mir2Lir::GetPCUseDefEncoding() { 130 LOG(FATAL) << "Unexpected call to GetPCUseDefEncoding for Arm64"; 131 return 0ULL; 132} 133 134// Arm64 specific setup. TODO: inline?: 135void Arm64Mir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) { 136 DCHECK_EQ(cu_->instruction_set, kArm64); 137 DCHECK(!lir->flags.use_def_invalid); 138 139 // These flags are somewhat uncommon - bypass if we can. 140 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LR)) != 0) { 141 if (flags & REG_DEF_SP) { 142 lir->u.m.def_mask |= ENCODE_ARM_REG_SP; 143 } 144 145 if (flags & REG_USE_SP) { 146 lir->u.m.use_mask |= ENCODE_ARM_REG_SP; 147 } 148 149 if (flags & REG_DEF_LR) { 150 lir->u.m.def_mask |= ENCODE_ARM_REG_LR; 151 } 152 } 153} 154 155ArmConditionCode Arm64Mir2Lir::ArmConditionEncoding(ConditionCode ccode) { 156 ArmConditionCode res; 157 switch (ccode) { 158 case kCondEq: res = kArmCondEq; break; 159 case kCondNe: res = kArmCondNe; break; 160 case kCondCs: res = kArmCondCs; break; 161 case kCondCc: res = kArmCondCc; break; 162 case kCondUlt: res = kArmCondCc; break; 163 case kCondUge: res = kArmCondCs; break; 164 case kCondMi: res = kArmCondMi; break; 165 case kCondPl: res = kArmCondPl; break; 166 case kCondVs: res = kArmCondVs; break; 167 case kCondVc: res = kArmCondVc; break; 168 case kCondHi: res = kArmCondHi; break; 169 case kCondLs: res = kArmCondLs; break; 170 case kCondGe: res = kArmCondGe; break; 171 case kCondLt: res = kArmCondLt; break; 172 case kCondGt: res = kArmCondGt; break; 173 case kCondLe: res = kArmCondLe; break; 174 case kCondAl: res = kArmCondAl; break; 175 case kCondNv: res = kArmCondNv; break; 176 default: 177 LOG(FATAL) << "Bad condition code " << ccode; 178 res = static_cast<ArmConditionCode>(0); // Quiet gcc 179 } 180 return res; 181} 182 183static const char *shift_names[4] = { 184 "lsl", 185 "lsr", 186 "asr", 187 "ror" 188}; 189 190static const char* extend_names[8] = { 191 "uxtb", 192 "uxth", 193 "uxtw", 194 "uxtx", 195 "sxtb", 196 "sxth", 197 "sxtw", 198 "sxtx", 199}; 200 201/* Decode and print a register extension (e.g. ", uxtb #1") */ 202static void DecodeRegExtendOrShift(int operand, char *buf, size_t buf_size) { 203 if ((operand & (1 << 6)) == 0) { 204 const char *shift_name = shift_names[(operand >> 7) & 0x3]; 205 int amount = operand & 0x3f; 206 snprintf(buf, buf_size, ", %s #%d", shift_name, amount); 207 } else { 208 const char *extend_name = extend_names[(operand >> 3) & 0x7]; 209 int amount = operand & 0x7; 210 if (amount == 0) { 211 snprintf(buf, buf_size, ", %s", extend_name); 212 } else { 213 snprintf(buf, buf_size, ", %s #%d", extend_name, amount); 214 } 215 } 216} 217 218#define BIT_MASK(w) ((UINT64_C(1) << (w)) - UINT64_C(1)) 219 220static uint64_t RotateRight(uint64_t value, unsigned rotate, unsigned width) { 221 DCHECK_LE(width, 64U); 222 rotate &= 63; 223 value = value & BIT_MASK(width); 224 return ((value & BIT_MASK(rotate)) << (width - rotate)) | (value >> rotate); 225} 226 227static uint64_t RepeatBitsAcrossReg(bool is_wide, uint64_t value, unsigned width) { 228 unsigned i; 229 unsigned reg_size = (is_wide) ? 64 : 32; 230 uint64_t result = value & BIT_MASK(width); 231 DCHECK_NE(width, reg_size); 232 for (i = width; i < reg_size; i *= 2) { 233 result |= (result << i); 234 } 235 DCHECK_EQ(i, reg_size); 236 return result; 237} 238 239/** 240 * @brief Decode an immediate in the form required by logical instructions. 241 * 242 * @param is_wide Whether @p value encodes a 64-bit (as opposed to 32-bit) immediate. 243 * @param value The encoded logical immediates that is to be decoded. 244 * @return The decoded logical immediate. 245 * @note This is the inverse of Arm64Mir2Lir::EncodeLogicalImmediate(). 246 */ 247uint64_t Arm64Mir2Lir::DecodeLogicalImmediate(bool is_wide, int value) { 248 unsigned n = (value >> 12) & 0x01; 249 unsigned imm_r = (value >> 6) & 0x3f; 250 unsigned imm_s = (value >> 0) & 0x3f; 251 252 // An integer is constructed from the n, imm_s and imm_r bits according to 253 // the following table: 254 // 255 // N imms immr size S R 256 // 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr) 257 // 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr) 258 // 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr) 259 // 0 110sss xxxrrr 8 UInt(sss) UInt(rrr) 260 // 0 1110ss xxxxrr 4 UInt(ss) UInt(rr) 261 // 0 11110s xxxxxr 2 UInt(s) UInt(r) 262 // (s bits must not be all set) 263 // 264 // A pattern is constructed of size bits, where the least significant S+1 265 // bits are set. The pattern is rotated right by R, and repeated across a 266 // 32 or 64-bit value, depending on destination register width. 267 268 if (n == 1) { 269 DCHECK_NE(imm_s, 0x3fU); 270 uint64_t bits = BIT_MASK(imm_s + 1); 271 return RotateRight(bits, imm_r, 64); 272 } else { 273 DCHECK_NE((imm_s >> 1), 0x1fU); 274 for (unsigned width = 0x20; width >= 0x2; width >>= 1) { 275 if ((imm_s & width) == 0) { 276 unsigned mask = (unsigned)(width - 1); 277 DCHECK_NE((imm_s & mask), mask); 278 uint64_t bits = BIT_MASK((imm_s & mask) + 1); 279 return RepeatBitsAcrossReg(is_wide, RotateRight(bits, imm_r & mask, width), width); 280 } 281 } 282 } 283 return 0; 284} 285 286/** 287 * @brief Decode an 8-bit single point number encoded with EncodeImmSingle(). 288 */ 289static float DecodeImmSingle(uint8_t small_float) { 290 int mantissa = (small_float & 0x0f) + 0x10; 291 int sign = ((small_float & 0x80) == 0) ? 1 : -1; 292 float signed_mantissa = static_cast<float>(sign*mantissa); 293 int exponent = (((small_float >> 4) & 0x7) + 4) & 0x7; 294 return signed_mantissa*static_cast<float>(1 << exponent)*0.0078125f; 295} 296 297static const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", 298 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"}; 299/* 300 * Interpret a format string and build a string no longer than size 301 * See format key in assemble_arm64.cc. 302 */ 303std::string Arm64Mir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) { 304 std::string buf; 305 const char* fmt_end = &fmt[strlen(fmt)]; 306 char tbuf[256]; 307 const char* name; 308 char nc; 309 while (fmt < fmt_end) { 310 int operand; 311 if (*fmt == '!') { 312 fmt++; 313 DCHECK_LT(fmt, fmt_end); 314 nc = *fmt++; 315 if (nc == '!') { 316 strcpy(tbuf, "!"); 317 } else { 318 DCHECK_LT(fmt, fmt_end); 319 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U); 320 operand = lir->operands[nc-'0']; 321 switch (*fmt++) { 322 case 'e': { 323 // Omit ", uxtw #0" in strings like "add w0, w1, w3, uxtw #0" and 324 // ", uxtx #0" in strings like "add x0, x1, x3, uxtx #0" 325 int omittable = ((IS_WIDE(lir->opcode)) ? EncodeExtend(kA64Uxtw, 0) : 326 EncodeExtend(kA64Uxtw, 0)); 327 if (LIKELY(operand == omittable)) { 328 strcpy(tbuf, ""); 329 } else { 330 DecodeRegExtendOrShift(operand, tbuf, arraysize(tbuf)); 331 } 332 } 333 break; 334 case 'o': 335 // Omit ", lsl #0" 336 if (LIKELY(operand == EncodeShift(kA64Lsl, 0))) { 337 strcpy(tbuf, ""); 338 } else { 339 DecodeRegExtendOrShift(operand, tbuf, arraysize(tbuf)); 340 } 341 break; 342 case 'B': 343 switch (operand) { 344 case kSY: 345 name = "sy"; 346 break; 347 case kST: 348 name = "st"; 349 break; 350 case kISH: 351 name = "ish"; 352 break; 353 case kISHST: 354 name = "ishst"; 355 break; 356 case kNSH: 357 name = "nsh"; 358 break; 359 case kNSHST: 360 name = "shst"; 361 break; 362 default: 363 name = "DecodeError2"; 364 break; 365 } 366 strcpy(tbuf, name); 367 break; 368 case 's': 369 snprintf(tbuf, arraysize(tbuf), "s%d", operand & ARM_FP_REG_MASK); 370 break; 371 case 'S': 372 snprintf(tbuf, arraysize(tbuf), "d%d", operand & ARM_FP_REG_MASK); 373 break; 374 case 'f': 375 snprintf(tbuf, arraysize(tbuf), "%c%d", (IS_FWIDE(lir->opcode)) ? 'd' : 's', 376 operand & ARM_FP_REG_MASK); 377 break; 378 case 'l': { 379 bool is_wide = IS_WIDE(lir->opcode); 380 uint64_t imm = DecodeLogicalImmediate(is_wide, operand); 381 snprintf(tbuf, arraysize(tbuf), "%" PRId64 " (%#" PRIx64 ")", imm, imm); 382 } 383 break; 384 case 'I': 385 snprintf(tbuf, arraysize(tbuf), "%f", DecodeImmSingle(operand)); 386 break; 387 case 'M': 388 if (LIKELY(operand == 0)) 389 strcpy(tbuf, ""); 390 else 391 snprintf(tbuf, arraysize(tbuf), ", lsl #%d", 16*operand); 392 break; 393 case 'd': 394 snprintf(tbuf, arraysize(tbuf), "%d", operand); 395 break; 396 case 'w': 397 if (LIKELY(operand != rwzr)) 398 snprintf(tbuf, arraysize(tbuf), "w%d", operand & RegStorage::kRegNumMask); 399 else 400 strcpy(tbuf, "wzr"); 401 break; 402 case 'W': 403 if (LIKELY(operand != rwsp)) 404 snprintf(tbuf, arraysize(tbuf), "w%d", operand & RegStorage::kRegNumMask); 405 else 406 strcpy(tbuf, "wsp"); 407 break; 408 case 'x': 409 if (LIKELY(operand != rxzr)) 410 snprintf(tbuf, arraysize(tbuf), "x%d", operand & RegStorage::kRegNumMask); 411 else 412 strcpy(tbuf, "xzr"); 413 break; 414 case 'X': 415 if (LIKELY(operand != rsp)) 416 snprintf(tbuf, arraysize(tbuf), "x%d", operand & RegStorage::kRegNumMask); 417 else 418 strcpy(tbuf, "sp"); 419 break; 420 case 'D': 421 snprintf(tbuf, arraysize(tbuf), "%d", operand*((IS_WIDE(lir->opcode)) ? 8 : 4)); 422 break; 423 case 'E': 424 snprintf(tbuf, arraysize(tbuf), "%d", operand*4); 425 break; 426 case 'F': 427 snprintf(tbuf, arraysize(tbuf), "%d", operand*2); 428 break; 429 case 'G': 430 if (LIKELY(operand == 0)) 431 strcpy(tbuf, ""); 432 else 433 strcpy(tbuf, (IS_WIDE(lir->opcode)) ? ", lsl #3" : ", lsl #2"); 434 break; 435 case 'c': 436 strcpy(tbuf, cc_names[operand]); 437 break; 438 case 't': 439 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)", 440 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + (operand << 2), 441 lir->target); 442 break; 443 case 'r': { 444 bool is_wide = IS_WIDE(lir->opcode); 445 if (LIKELY(operand != rwzr && operand != rxzr)) { 446 snprintf(tbuf, arraysize(tbuf), "%c%d", (is_wide) ? 'x' : 'w', 447 operand & RegStorage::kRegNumMask); 448 } else { 449 strcpy(tbuf, (is_wide) ? "xzr" : "wzr"); 450 } 451 } 452 break; 453 case 'R': { 454 bool is_wide = IS_WIDE(lir->opcode); 455 if (LIKELY(operand != rwsp || operand != rsp)) { 456 snprintf(tbuf, arraysize(tbuf), "%c%d", (is_wide) ? 'x' : 'w', 457 operand & RegStorage::kRegNumMask); 458 } else { 459 strcpy(tbuf, (is_wide) ? "sp" : "wsp"); 460 } 461 } 462 break; 463 case 'p': 464 snprintf(tbuf, arraysize(tbuf), ".+%d (addr %#" PRIxPTR ")", 4*operand, 465 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4*operand); 466 break; 467 case 'T': 468 if (LIKELY(operand == 0)) 469 strcpy(tbuf, ""); 470 else if (operand == 1) 471 strcpy(tbuf, ", lsl #12"); 472 else 473 strcpy(tbuf, ", DecodeError3"); 474 break; 475 default: 476 strcpy(tbuf, "DecodeError1"); 477 break; 478 } 479 buf += tbuf; 480 } 481 } else { 482 buf += *fmt++; 483 } 484 } 485 return buf; 486} 487 488void Arm64Mir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) { 489 char buf[256]; 490 buf[0] = 0; 491 492 if (mask == ENCODE_ALL) { 493 strcpy(buf, "all"); 494 } else { 495 char num[8]; 496 int i; 497 498 for (i = 0; i < kArmRegEnd; i++) { 499 if (mask & (1ULL << i)) { 500 snprintf(num, arraysize(num), "%d ", i); 501 strcat(buf, num); 502 } 503 } 504 505 if (mask & ENCODE_CCODE) { 506 strcat(buf, "cc "); 507 } 508 if (mask & ENCODE_FP_STATUS) { 509 strcat(buf, "fpcc "); 510 } 511 512 /* Memory bits */ 513 if (arm_lir && (mask & ENCODE_DALVIK_REG)) { 514 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s", 515 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info), 516 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : ""); 517 } 518 if (mask & ENCODE_LITERAL) { 519 strcat(buf, "lit "); 520 } 521 522 if (mask & ENCODE_HEAP_REF) { 523 strcat(buf, "heap "); 524 } 525 if (mask & ENCODE_MUST_NOT_ALIAS) { 526 strcat(buf, "noalias "); 527 } 528 } 529 if (buf[0]) { 530 LOG(INFO) << prefix << ": " << buf; 531 } 532} 533 534bool Arm64Mir2Lir::IsUnconditionalBranch(LIR* lir) { 535 return (lir->opcode == kA64B1t); 536} 537 538bool Arm64Mir2Lir::SupportsVolatileLoadStore(OpSize size) { 539 return true; 540} 541 542RegisterClass Arm64Mir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) { 543 if (UNLIKELY(is_volatile)) { 544 // On arm64, fp register load/store is atomic only for single bytes. 545 if (size != kSignedByte && size != kUnsignedByte) { 546 return kCoreReg; 547 } 548 } 549 return RegClassBySize(size); 550} 551 552Arm64Mir2Lir::Arm64Mir2Lir(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 < kA64Last; i++) { 556 if (UNWIDE(Arm64Mir2Lir::EncodingMap[i].opcode) != i) { 557 LOG(FATAL) << "Encoding order for " << Arm64Mir2Lir::EncodingMap[i].name 558 << " is wrong: expecting " << i << ", seeing " 559 << static_cast<int>(Arm64Mir2Lir::EncodingMap[i].opcode); 560 } 561 } 562} 563 564Mir2Lir* Arm64CodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, 565 ArenaAllocator* const arena) { 566 return new Arm64Mir2Lir(cu, mir_graph, arena); 567} 568 569// Alloc a pair of core registers, or a double. 570RegStorage Arm64Mir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class) { 571 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) { 572 return AllocTempDouble(); 573 } else { 574 RegStorage low_reg = AllocTemp(); 575 RegStorage high_reg = AllocTemp(); 576 return RegStorage::MakeRegPair(low_reg, high_reg); 577 } 578} 579 580RegStorage Arm64Mir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) { 581 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) 582 return AllocTempSingle(); 583 return AllocTemp(); 584} 585 586void Arm64Mir2Lir::CompilerInitializeRegAlloc() { 587 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, sp_regs, dp_regs, reserved_regs, 588 core_temps, sp_temps, dp_temps); 589 590 // Target-specific adjustments. 591 592 // Alias single precision floats to appropriate half of overlapping double. 593 GrowableArray<RegisterInfo*>::Iterator it(®_pool_->sp_regs_); 594 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) { 595 int sp_reg_num = info->GetReg().GetRegNum(); 596 int dp_reg_num = sp_reg_num >> 1; 597 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num); 598 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg); 599 // Double precision register's master storage should refer to itself. 600 DCHECK_EQ(dp_reg_info, dp_reg_info->Master()); 601 // Redirect single precision's master storage to master. 602 info->SetMaster(dp_reg_info); 603 // Singles should show a single 32-bit mask bit, at first referring to the low half. 604 DCHECK_EQ(info->StorageMask(), 0x1U); 605 if (sp_reg_num & 1) { 606 // For odd singles, change to user the high word of the backing double. 607 info->SetStorageMask(0x2); 608 } 609 } 610 611 // TODO: re-enable this when we can safely save r4 over the suspension code path. 612 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks(); 613 if (no_suspend) { 614 GetRegInfo(rs_rA64_SUSPEND)->MarkFree(); 615 } 616 617 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods. 618 // TODO: adjust when we roll to hard float calling convention. 619 reg_pool_->next_core_reg_ = 2; 620 reg_pool_->next_sp_reg_ = 0; 621 reg_pool_->next_dp_reg_ = 0; 622} 623 624void Arm64Mir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) { 625 LOG(FATAL) << "Unexpected call to FreeRegLocTemps for Arm64"; 626} 627 628/* 629 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some 630 * instructions might call out to C/assembly helper functions. Until 631 * machinery is in place, always spill lr. 632 */ 633 634void Arm64Mir2Lir::AdjustSpillMask() { 635 core_spill_mask_ |= (1 << rs_rA64_LR.GetRegNum()); 636 num_core_spills_++; 637} 638 639/* 640 * Mark a callee-save fp register as promoted. Note that 641 * vpush/vpop uses contiguous register lists so we must 642 * include any holes in the mask. Associate holes with 643 * Dalvik register INVALID_VREG (0xFFFFU). 644 */ 645void Arm64Mir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) { 646 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE); 647 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE; 648 // Ensure fp_vmap_table is large enough 649 int table_size = fp_vmap_table_.size(); 650 for (int i = table_size; i < (adjusted_reg_num + 1); i++) { 651 fp_vmap_table_.push_back(INVALID_VREG); 652 } 653 // Add the current mapping 654 fp_vmap_table_[adjusted_reg_num] = v_reg; 655 // Size of fp_vmap_table is high-water mark, use to set mask 656 num_fp_spills_ = fp_vmap_table_.size(); 657 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE; 658} 659 660void Arm64Mir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) { 661 // TEMP: perform as 2 singles. 662 int reg_num = reg.GetRegNum() << 1; 663 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num); 664 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1); 665 MarkPreservedSingle(v_reg, lo); 666 MarkPreservedSingle(v_reg + 1, hi); 667} 668 669/* Clobber all regs that might be used by an external C call */ 670void Arm64Mir2Lir::ClobberCallerSave() { 671 // TODO(Arm64): implement this. 672 UNIMPLEMENTED(WARNING); 673 674 Clobber(rs_x0); 675 Clobber(rs_x1); 676 Clobber(rs_x2); 677 Clobber(rs_x3); 678 Clobber(rs_x12); 679 Clobber(rs_x30); 680 Clobber(rs_f0); 681 Clobber(rs_f1); 682 Clobber(rs_f2); 683 Clobber(rs_f3); 684 Clobber(rs_f4); 685 Clobber(rs_f5); 686 Clobber(rs_f6); 687 Clobber(rs_f7); 688 Clobber(rs_f8); 689 Clobber(rs_f9); 690 Clobber(rs_f10); 691 Clobber(rs_f11); 692 Clobber(rs_f12); 693 Clobber(rs_f13); 694 Clobber(rs_f14); 695 Clobber(rs_f15); 696} 697 698RegLocation Arm64Mir2Lir::GetReturnWideAlt() { 699 RegLocation res = LocCReturnWide(); 700 res.reg.SetReg(rx2); 701 res.reg.SetHighReg(rx3); 702 Clobber(rs_x2); 703 Clobber(rs_x3); 704 MarkInUse(rs_x2); 705 MarkInUse(rs_x3); 706 MarkWide(res.reg); 707 return res; 708} 709 710RegLocation Arm64Mir2Lir::GetReturnAlt() { 711 RegLocation res = LocCReturn(); 712 res.reg.SetReg(rx1); 713 Clobber(rs_x1); 714 MarkInUse(rs_x1); 715 return res; 716} 717 718/* To be used when explicitly managing register use */ 719void Arm64Mir2Lir::LockCallTemps() { 720 LockTemp(rs_x0); 721 LockTemp(rs_x1); 722 LockTemp(rs_x2); 723 LockTemp(rs_x3); 724} 725 726/* To be used when explicitly managing register use */ 727void Arm64Mir2Lir::FreeCallTemps() { 728 FreeTemp(rs_x0); 729 FreeTemp(rs_x1); 730 FreeTemp(rs_x2); 731 FreeTemp(rs_x3); 732} 733 734RegStorage Arm64Mir2Lir::LoadHelper(ThreadOffset<4> offset) { 735 UNIMPLEMENTED(FATAL) << "Should not be called."; 736 return RegStorage::InvalidReg(); 737} 738 739RegStorage Arm64Mir2Lir::LoadHelper(ThreadOffset<8> offset) { 740 // TODO(Arm64): use LoadWordDisp instead. 741 // e.g. LoadWordDisp(rs_rA64_SELF, offset.Int32Value(), rs_rA64_LR); 742 LoadBaseDisp(rs_rA64_SELF, offset.Int32Value(), rs_rA64_LR, k64); 743 return rs_rA64_LR; 744} 745 746LIR* Arm64Mir2Lir::CheckSuspendUsingLoad() { 747 RegStorage tmp = rs_x0; 748 LoadWordDisp(rs_rA64_SELF, Thread::ThreadSuspendTriggerOffset<8>().Int32Value(), tmp); 749 LIR* load2 = LoadWordDisp(tmp, 0, tmp); 750 return load2; 751} 752 753uint64_t Arm64Mir2Lir::GetTargetInstFlags(int opcode) { 754 DCHECK(!IsPseudoLirOp(opcode)); 755 return Arm64Mir2Lir::EncodingMap[UNWIDE(opcode)].flags; 756} 757 758const char* Arm64Mir2Lir::GetTargetInstName(int opcode) { 759 DCHECK(!IsPseudoLirOp(opcode)); 760 return Arm64Mir2Lir::EncodingMap[UNWIDE(opcode)].name; 761} 762 763const char* Arm64Mir2Lir::GetTargetInstFmt(int opcode) { 764 DCHECK(!IsPseudoLirOp(opcode)); 765 return Arm64Mir2Lir::EncodingMap[UNWIDE(opcode)].fmt; 766} 767 768/* 769 * Somewhat messy code here. We want to allocate a pair of contiguous 770 * physical single-precision floating point registers starting with 771 * an even numbered reg. It is possible that the paired s_reg (s_reg+1) 772 * has already been allocated - try to fit if possible. Fail to 773 * allocate if we can't meet the requirements for the pair of 774 * s_reg<=sX[even] & (s_reg+1)<= sX+1. 775 */ 776// TODO: needs rewrite to support non-backed 64-bit float regs. 777RegStorage Arm64Mir2Lir::AllocPreservedDouble(int s_reg) { 778 RegStorage res; 779 int v_reg = mir_graph_->SRegToVReg(s_reg); 780 int p_map_idx = SRegToPMap(s_reg); 781 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) { 782 // Upper reg is already allocated. Can we fit? 783 int high_reg = promotion_map_[p_map_idx+1].FpReg; 784 if ((high_reg & 1) == 0) { 785 // High reg is even - fail. 786 return res; // Invalid. 787 } 788 // Is the low reg of the pair free? 789 // FIXME: rework. 790 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1)); 791 if (p->InUse() || p->IsTemp()) { 792 // Already allocated or not preserved - fail. 793 return res; // Invalid. 794 } 795 // OK - good to go. 796 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1); 797 p->MarkInUse(); 798 MarkPreservedSingle(v_reg, p->GetReg()); 799 } else { 800 /* 801 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to 802 * different underlying physical registers. 803 */ 804 GrowableArray<RegisterInfo*>::Iterator it(®_pool_->dp_regs_); 805 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) { 806 if (!info->IsTemp() && !info->InUse()) { 807 res = info->GetReg(); 808 info->MarkInUse(); 809 MarkPreservedDouble(v_reg, info->GetReg()); 810 break; 811 } 812 } 813 } 814 if (res.Valid()) { 815 promotion_map_[p_map_idx].fp_location = kLocPhysReg; 816 promotion_map_[p_map_idx].FpReg = res.DoubleToLowSingle().GetReg(); 817 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg; 818 promotion_map_[p_map_idx+1].FpReg = res.DoubleToHighSingle().GetReg(); 819 } 820 return res; 821} 822 823// TODO(Arm64): reuse info in QuickArgumentVisitor? 824static RegStorage GetArgPhysicalReg(RegLocation* loc, int* num_gpr_used, int* num_fpr_used, 825 OpSize* op_size) { 826 if (loc->fp) { 827 int n = *num_fpr_used; 828 if (n < 8) { 829 *num_fpr_used = n + 1; 830 RegStorage::RegStorageKind reg_kind; 831 if (loc->wide) { 832 *op_size = kDouble; 833 reg_kind = RegStorage::k64BitSolo; 834 } else { 835 *op_size = kSingle; 836 reg_kind = RegStorage::k32BitSolo; 837 } 838 return RegStorage(RegStorage::kValid | reg_kind | RegStorage::kFloatingPoint | n); 839 } 840 } else { 841 int n = *num_gpr_used; 842 if (n < 7) { 843 *num_gpr_used = n + 1; 844 if (loc->wide) { 845 *op_size = k64; 846 return RegStorage::Solo64(n); 847 } else { 848 *op_size = k32; 849 return RegStorage::Solo32(n); 850 } 851 } 852 } 853 854 return RegStorage::InvalidReg(); 855} 856 857/* 858 * If there are any ins passed in registers that have not been promoted 859 * to a callee-save register, flush them to the frame. Perform initial 860 * assignment of promoted arguments. 861 * 862 * ArgLocs is an array of location records describing the incoming arguments 863 * with one location record per word of argument. 864 */ 865void Arm64Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) { 866 int num_gpr_used = 1; 867 int num_fpr_used = 0; 868 869 /* 870 * Dummy up a RegLocation for the incoming Method* 871 * It will attempt to keep kArg0 live (or copy it to home location 872 * if promoted). 873 */ 874 RegLocation rl_src = rl_method; 875 rl_src.location = kLocPhysReg; 876 rl_src.reg = TargetReg(kArg0); 877 rl_src.home = false; 878 MarkLive(rl_src); 879 880 // TODO(Arm64): compress the Method pointer? 881 StoreValueWide(rl_method, rl_src); 882 883 // If Method* has been promoted, explicitly flush 884 if (rl_method.location == kLocPhysReg) { 885 StoreWordDisp(TargetReg(kSp), 0, TargetReg(kArg0)); 886 } 887 888 if (cu_->num_ins == 0) { 889 return; 890 } 891 892 int start_vreg = cu_->num_dalvik_registers - cu_->num_ins; 893 for (int i = 0; i < cu_->num_ins; i++) { 894 PromotionMap* v_map = &promotion_map_[start_vreg + i]; 895 RegLocation* t_loc = &ArgLocs[i]; 896 OpSize op_size; 897 RegStorage reg = GetArgPhysicalReg(t_loc, &num_gpr_used, &num_fpr_used, &op_size); 898 899 if (reg.Valid()) { 900 if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) { 901 OpRegCopy(RegStorage::Solo32(v_map->core_reg), reg); 902 } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) { 903 OpRegCopy(RegStorage::Solo32(v_map->FpReg), reg); 904 } else { 905 StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i), reg, op_size); 906 if (reg.Is64Bit()) { 907 if (SRegOffset(start_vreg + i) + 4 != SRegOffset(start_vreg + i + 1)) { 908 LOG(FATAL) << "64 bit value stored in non-consecutive 4 bytes slots"; 909 } 910 i += 1; 911 } 912 } 913 } else { 914 // If arriving in frame & promoted 915 if (v_map->core_location == kLocPhysReg) { 916 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i), 917 RegStorage::Solo32(v_map->core_reg)); 918 } 919 if (v_map->fp_location == kLocPhysReg) { 920 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i), RegStorage::Solo32(v_map->FpReg)); 921 } 922 } 923 } 924} 925 926int Arm64Mir2Lir::LoadArgRegs(CallInfo* info, int call_state, 927 NextCallInsn next_call_insn, 928 const MethodReference& target_method, 929 uint32_t vtable_idx, uintptr_t direct_code, 930 uintptr_t direct_method, InvokeType type, bool skip_this) { 931 int last_arg_reg = TargetReg(kArg3).GetReg(); 932 int next_reg = TargetReg(kArg1).GetReg(); 933 int next_arg = 0; 934 if (skip_this) { 935 next_reg++; 936 next_arg++; 937 } 938 for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) { 939 RegLocation rl_arg = info->args[next_arg++]; 940 rl_arg = UpdateRawLoc(rl_arg); 941 if (rl_arg.wide && (next_reg <= TargetReg(kArg2).GetReg())) { 942 RegStorage r_tmp(RegStorage::k64BitPair, next_reg, next_reg + 1); 943 LoadValueDirectWideFixed(rl_arg, r_tmp); 944 next_reg++; 945 next_arg++; 946 } else { 947 if (rl_arg.wide) { 948 rl_arg = NarrowRegLoc(rl_arg); 949 rl_arg.is_const = false; 950 } 951 LoadValueDirectFixed(rl_arg, RegStorage::Solo32(next_reg)); 952 } 953 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, 954 direct_code, direct_method, type); 955 } 956 return call_state; 957} 958 959} // namespace art 960