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