1 /* 2 * Copyright (C) 2014 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 "assembler_mips64.h" 18 19 #include "base/bit_utils.h" 20 #include "base/casts.h" 21 #include "entrypoints/quick/quick_entrypoints.h" 22 #include "entrypoints/quick/quick_entrypoints_enum.h" 23 #include "memory_region.h" 24 #include "thread.h" 25 26 namespace art { 27 namespace mips64 { 28 29 void Mips64Assembler::FinalizeCode() { 30 for (auto& exception_block : exception_blocks_) { 31 EmitExceptionPoll(&exception_block); 32 } 33 PromoteBranches(); 34 } 35 36 void Mips64Assembler::FinalizeInstructions(const MemoryRegion& region) { 37 EmitBranches(); 38 Assembler::FinalizeInstructions(region); 39 PatchCFI(); 40 } 41 42 void Mips64Assembler::PatchCFI() { 43 if (cfi().NumberOfDelayedAdvancePCs() == 0u) { 44 return; 45 } 46 47 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC; 48 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC(); 49 const std::vector<uint8_t>& old_stream = data.first; 50 const std::vector<DelayedAdvancePC>& advances = data.second; 51 52 // Refill our data buffer with patched opcodes. 53 cfi().ReserveCFIStream(old_stream.size() + advances.size() + 16); 54 size_t stream_pos = 0; 55 for (const DelayedAdvancePC& advance : advances) { 56 DCHECK_GE(advance.stream_pos, stream_pos); 57 // Copy old data up to the point where advance was issued. 58 cfi().AppendRawData(old_stream, stream_pos, advance.stream_pos); 59 stream_pos = advance.stream_pos; 60 // Insert the advance command with its final offset. 61 size_t final_pc = GetAdjustedPosition(advance.pc); 62 cfi().AdvancePC(final_pc); 63 } 64 // Copy the final segment if any. 65 cfi().AppendRawData(old_stream, stream_pos, old_stream.size()); 66 } 67 68 void Mips64Assembler::EmitBranches() { 69 CHECK(!overwriting_); 70 // Switch from appending instructions at the end of the buffer to overwriting 71 // existing instructions (branch placeholders) in the buffer. 72 overwriting_ = true; 73 for (auto& branch : branches_) { 74 EmitBranch(&branch); 75 } 76 overwriting_ = false; 77 } 78 79 void Mips64Assembler::Emit(uint32_t value) { 80 if (overwriting_) { 81 // Branches to labels are emitted into their placeholders here. 82 buffer_.Store<uint32_t>(overwrite_location_, value); 83 overwrite_location_ += sizeof(uint32_t); 84 } else { 85 // Other instructions are simply appended at the end here. 86 AssemblerBuffer::EnsureCapacity ensured(&buffer_); 87 buffer_.Emit<uint32_t>(value); 88 } 89 } 90 91 void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd, 92 int shamt, int funct) { 93 CHECK_NE(rs, kNoGpuRegister); 94 CHECK_NE(rt, kNoGpuRegister); 95 CHECK_NE(rd, kNoGpuRegister); 96 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 97 static_cast<uint32_t>(rs) << kRsShift | 98 static_cast<uint32_t>(rt) << kRtShift | 99 static_cast<uint32_t>(rd) << kRdShift | 100 shamt << kShamtShift | 101 funct; 102 Emit(encoding); 103 } 104 105 void Mips64Assembler::EmitRsd(int opcode, GpuRegister rs, GpuRegister rd, 106 int shamt, int funct) { 107 CHECK_NE(rs, kNoGpuRegister); 108 CHECK_NE(rd, kNoGpuRegister); 109 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 110 static_cast<uint32_t>(rs) << kRsShift | 111 static_cast<uint32_t>(ZERO) << kRtShift | 112 static_cast<uint32_t>(rd) << kRdShift | 113 shamt << kShamtShift | 114 funct; 115 Emit(encoding); 116 } 117 118 void Mips64Assembler::EmitRtd(int opcode, GpuRegister rt, GpuRegister rd, 119 int shamt, int funct) { 120 CHECK_NE(rt, kNoGpuRegister); 121 CHECK_NE(rd, kNoGpuRegister); 122 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 123 static_cast<uint32_t>(ZERO) << kRsShift | 124 static_cast<uint32_t>(rt) << kRtShift | 125 static_cast<uint32_t>(rd) << kRdShift | 126 shamt << kShamtShift | 127 funct; 128 Emit(encoding); 129 } 130 131 void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) { 132 CHECK_NE(rs, kNoGpuRegister); 133 CHECK_NE(rt, kNoGpuRegister); 134 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 135 static_cast<uint32_t>(rs) << kRsShift | 136 static_cast<uint32_t>(rt) << kRtShift | 137 imm; 138 Emit(encoding); 139 } 140 141 void Mips64Assembler::EmitI21(int opcode, GpuRegister rs, uint32_t imm21) { 142 CHECK_NE(rs, kNoGpuRegister); 143 CHECK(IsUint<21>(imm21)) << imm21; 144 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 145 static_cast<uint32_t>(rs) << kRsShift | 146 imm21; 147 Emit(encoding); 148 } 149 150 void Mips64Assembler::EmitI26(int opcode, uint32_t imm26) { 151 CHECK(IsUint<26>(imm26)) << imm26; 152 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26; 153 Emit(encoding); 154 } 155 156 void Mips64Assembler::EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd, 157 int funct) { 158 CHECK_NE(ft, kNoFpuRegister); 159 CHECK_NE(fs, kNoFpuRegister); 160 CHECK_NE(fd, kNoFpuRegister); 161 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 162 fmt << kFmtShift | 163 static_cast<uint32_t>(ft) << kFtShift | 164 static_cast<uint32_t>(fs) << kFsShift | 165 static_cast<uint32_t>(fd) << kFdShift | 166 funct; 167 Emit(encoding); 168 } 169 170 void Mips64Assembler::EmitFI(int opcode, int fmt, FpuRegister ft, uint16_t imm) { 171 CHECK_NE(ft, kNoFpuRegister); 172 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 173 fmt << kFmtShift | 174 static_cast<uint32_t>(ft) << kFtShift | 175 imm; 176 Emit(encoding); 177 } 178 179 void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 180 EmitR(0, rs, rt, rd, 0, 0x21); 181 } 182 183 void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 184 EmitI(0x9, rs, rt, imm16); 185 } 186 187 void Mips64Assembler::Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 188 EmitR(0, rs, rt, rd, 0, 0x2d); 189 } 190 191 void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 192 EmitI(0x19, rs, rt, imm16); 193 } 194 195 void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 196 EmitR(0, rs, rt, rd, 0, 0x23); 197 } 198 199 void Mips64Assembler::Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 200 EmitR(0, rs, rt, rd, 0, 0x2f); 201 } 202 203 void Mips64Assembler::MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 204 EmitR(0, rs, rt, rd, 2, 0x18); 205 } 206 207 void Mips64Assembler::MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 208 EmitR(0, rs, rt, rd, 3, 0x18); 209 } 210 211 void Mips64Assembler::DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 212 EmitR(0, rs, rt, rd, 2, 0x1a); 213 } 214 215 void Mips64Assembler::ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 216 EmitR(0, rs, rt, rd, 3, 0x1a); 217 } 218 219 void Mips64Assembler::DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 220 EmitR(0, rs, rt, rd, 2, 0x1b); 221 } 222 223 void Mips64Assembler::ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 224 EmitR(0, rs, rt, rd, 3, 0x1b); 225 } 226 227 void Mips64Assembler::Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 228 EmitR(0, rs, rt, rd, 2, 0x1c); 229 } 230 231 void Mips64Assembler::Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 232 EmitR(0, rs, rt, rd, 3, 0x1c); 233 } 234 235 void Mips64Assembler::Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 236 EmitR(0, rs, rt, rd, 2, 0x1e); 237 } 238 239 void Mips64Assembler::Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 240 EmitR(0, rs, rt, rd, 3, 0x1e); 241 } 242 243 void Mips64Assembler::Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 244 EmitR(0, rs, rt, rd, 2, 0x1f); 245 } 246 247 void Mips64Assembler::Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 248 EmitR(0, rs, rt, rd, 3, 0x1f); 249 } 250 251 void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 252 EmitR(0, rs, rt, rd, 0, 0x24); 253 } 254 255 void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 256 EmitI(0xc, rs, rt, imm16); 257 } 258 259 void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 260 EmitR(0, rs, rt, rd, 0, 0x25); 261 } 262 263 void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 264 EmitI(0xd, rs, rt, imm16); 265 } 266 267 void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 268 EmitR(0, rs, rt, rd, 0, 0x26); 269 } 270 271 void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 272 EmitI(0xe, rs, rt, imm16); 273 } 274 275 void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 276 EmitR(0, rs, rt, rd, 0, 0x27); 277 } 278 279 void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) { 280 EmitRtd(0x1f, rt, rd, 0x0, 0x20); 281 } 282 283 void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) { 284 EmitRtd(0x1f, rt, rd, 0x0, 0x24); 285 } 286 287 void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) { 288 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20); 289 } 290 291 void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) { 292 EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20); 293 } 294 295 void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) { 296 EmitRtd(0x1f, rt, rd, 0x2, 0x24); 297 } 298 299 void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) { 300 EmitRtd(0x1f, rt, rd, 0x5, 0x24); 301 } 302 303 void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) { 304 CHECK(IsUint<5>(pos)) << pos; 305 CHECK(IsUint<5>(size - 1)) << size; 306 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3); 307 } 308 309 void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) { 310 CHECK(IsUint<5>(pos - 32)) << pos; 311 CHECK(IsUint<5>(size - 1)) << size; 312 CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size; 313 EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6); 314 } 315 316 void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) { 317 EmitRtd(0x1f, rt, rd, 2, 0x20); 318 } 319 320 void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) { 321 CHECK(IsInt<9>(imm9)); 322 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26); 323 } 324 325 void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) { 326 CHECK(IsInt<9>(imm9)); 327 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27); 328 } 329 330 void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) { 331 CHECK(IsInt<9>(imm9)); 332 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36); 333 } 334 335 void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) { 336 CHECK(IsInt<9>(imm9)); 337 EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37); 338 } 339 340 void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) { 341 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00); 342 } 343 344 void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) { 345 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02); 346 } 347 348 void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) { 349 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02); 350 } 351 352 void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) { 353 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03); 354 } 355 356 void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { 357 EmitR(0, rs, rt, rd, 0, 0x04); 358 } 359 360 void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { 361 EmitR(0, rs, rt, rd, 1, 0x06); 362 } 363 364 void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { 365 EmitR(0, rs, rt, rd, 0, 0x06); 366 } 367 368 void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs) { 369 EmitR(0, rs, rt, rd, 0, 0x07); 370 } 371 372 void Mips64Assembler::Dsll(GpuRegister rd, GpuRegister rt, int shamt) { 373 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x38); 374 } 375 376 void Mips64Assembler::Dsrl(GpuRegister rd, GpuRegister rt, int shamt) { 377 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a); 378 } 379 380 void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) { 381 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a); 382 } 383 384 void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) { 385 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b); 386 } 387 388 void Mips64Assembler::Dsll32(GpuRegister rd, GpuRegister rt, int shamt) { 389 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3c); 390 } 391 392 void Mips64Assembler::Dsrl32(GpuRegister rd, GpuRegister rt, int shamt) { 393 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e); 394 } 395 396 void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) { 397 EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e); 398 } 399 400 void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) { 401 EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f); 402 } 403 404 void Mips64Assembler::Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { 405 EmitR(0, rs, rt, rd, 0, 0x14); 406 } 407 408 void Mips64Assembler::Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { 409 EmitR(0, rs, rt, rd, 0, 0x16); 410 } 411 412 void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) { 413 EmitR(0, rs, rt, rd, 1, 0x16); 414 } 415 416 void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) { 417 EmitR(0, rs, rt, rd, 0, 0x17); 418 } 419 420 void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 421 EmitI(0x20, rs, rt, imm16); 422 } 423 424 void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 425 EmitI(0x21, rs, rt, imm16); 426 } 427 428 void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 429 EmitI(0x23, rs, rt, imm16); 430 } 431 432 void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 433 EmitI(0x37, rs, rt, imm16); 434 } 435 436 void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 437 EmitI(0x24, rs, rt, imm16); 438 } 439 440 void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 441 EmitI(0x25, rs, rt, imm16); 442 } 443 444 void Mips64Assembler::Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 445 EmitI(0x27, rs, rt, imm16); 446 } 447 448 void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) { 449 EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16); 450 } 451 452 void Mips64Assembler::Dahi(GpuRegister rs, uint16_t imm16) { 453 EmitI(1, rs, static_cast<GpuRegister>(6), imm16); 454 } 455 456 void Mips64Assembler::Dati(GpuRegister rs, uint16_t imm16) { 457 EmitI(1, rs, static_cast<GpuRegister>(0x1e), imm16); 458 } 459 460 void Mips64Assembler::Sync(uint32_t stype) { 461 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0), 462 static_cast<GpuRegister>(0), stype & 0x1f, 0xf); 463 } 464 465 void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 466 EmitI(0x28, rs, rt, imm16); 467 } 468 469 void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 470 EmitI(0x29, rs, rt, imm16); 471 } 472 473 void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 474 EmitI(0x2b, rs, rt, imm16); 475 } 476 477 void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 478 EmitI(0x3f, rs, rt, imm16); 479 } 480 481 void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 482 EmitR(0, rs, rt, rd, 0, 0x2a); 483 } 484 485 void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 486 EmitR(0, rs, rt, rd, 0, 0x2b); 487 } 488 489 void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 490 EmitI(0xa, rs, rt, imm16); 491 } 492 493 void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) { 494 EmitI(0xb, rs, rt, imm16); 495 } 496 497 void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 498 EmitR(0, rs, rt, rd, 0, 0x35); 499 } 500 501 void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) { 502 EmitR(0, rs, rt, rd, 0, 0x37); 503 } 504 505 void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) { 506 EmitRsd(0, rs, rd, 0x01, 0x10); 507 } 508 509 void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) { 510 EmitRsd(0, rs, rd, 0x01, 0x11); 511 } 512 513 void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) { 514 EmitRsd(0, rs, rd, 0x01, 0x12); 515 } 516 517 void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) { 518 EmitRsd(0, rs, rd, 0x01, 0x13); 519 } 520 521 void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) { 522 EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09); 523 } 524 525 void Mips64Assembler::Jalr(GpuRegister rs) { 526 Jalr(RA, rs); 527 } 528 529 void Mips64Assembler::Jr(GpuRegister rs) { 530 Jalr(ZERO, rs); 531 } 532 533 void Mips64Assembler::Auipc(GpuRegister rs, uint16_t imm16) { 534 EmitI(0x3B, rs, static_cast<GpuRegister>(0x1E), imm16); 535 } 536 537 void Mips64Assembler::Addiupc(GpuRegister rs, uint32_t imm19) { 538 CHECK(IsUint<19>(imm19)) << imm19; 539 EmitI21(0x3B, rs, imm19); 540 } 541 542 void Mips64Assembler::Bc(uint32_t imm26) { 543 EmitI26(0x32, imm26); 544 } 545 546 void Mips64Assembler::Jic(GpuRegister rt, uint16_t imm16) { 547 EmitI(0x36, static_cast<GpuRegister>(0), rt, imm16); 548 } 549 550 void Mips64Assembler::Jialc(GpuRegister rt, uint16_t imm16) { 551 EmitI(0x3E, static_cast<GpuRegister>(0), rt, imm16); 552 } 553 554 void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16) { 555 CHECK_NE(rs, ZERO); 556 CHECK_NE(rt, ZERO); 557 CHECK_NE(rs, rt); 558 EmitI(0x17, rs, rt, imm16); 559 } 560 561 void Mips64Assembler::Bltzc(GpuRegister rt, uint16_t imm16) { 562 CHECK_NE(rt, ZERO); 563 EmitI(0x17, rt, rt, imm16); 564 } 565 566 void Mips64Assembler::Bgtzc(GpuRegister rt, uint16_t imm16) { 567 CHECK_NE(rt, ZERO); 568 EmitI(0x17, static_cast<GpuRegister>(0), rt, imm16); 569 } 570 571 void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16) { 572 CHECK_NE(rs, ZERO); 573 CHECK_NE(rt, ZERO); 574 CHECK_NE(rs, rt); 575 EmitI(0x16, rs, rt, imm16); 576 } 577 578 void Mips64Assembler::Bgezc(GpuRegister rt, uint16_t imm16) { 579 CHECK_NE(rt, ZERO); 580 EmitI(0x16, rt, rt, imm16); 581 } 582 583 void Mips64Assembler::Blezc(GpuRegister rt, uint16_t imm16) { 584 CHECK_NE(rt, ZERO); 585 EmitI(0x16, static_cast<GpuRegister>(0), rt, imm16); 586 } 587 588 void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) { 589 CHECK_NE(rs, ZERO); 590 CHECK_NE(rt, ZERO); 591 CHECK_NE(rs, rt); 592 EmitI(0x7, rs, rt, imm16); 593 } 594 595 void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16) { 596 CHECK_NE(rs, ZERO); 597 CHECK_NE(rt, ZERO); 598 CHECK_NE(rs, rt); 599 EmitI(0x6, rs, rt, imm16); 600 } 601 602 void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16) { 603 CHECK_NE(rs, ZERO); 604 CHECK_NE(rt, ZERO); 605 CHECK_NE(rs, rt); 606 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16); 607 } 608 609 void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16) { 610 CHECK_NE(rs, ZERO); 611 CHECK_NE(rt, ZERO); 612 CHECK_NE(rs, rt); 613 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16); 614 } 615 616 void Mips64Assembler::Beqzc(GpuRegister rs, uint32_t imm21) { 617 CHECK_NE(rs, ZERO); 618 EmitI21(0x36, rs, imm21); 619 } 620 621 void Mips64Assembler::Bnezc(GpuRegister rs, uint32_t imm21) { 622 CHECK_NE(rs, ZERO); 623 EmitI21(0x3E, rs, imm21); 624 } 625 626 void Mips64Assembler::Bc1eqz(FpuRegister ft, uint16_t imm16) { 627 EmitFI(0x11, 0x9, ft, imm16); 628 } 629 630 void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) { 631 EmitFI(0x11, 0xD, ft, imm16); 632 } 633 634 void Mips64Assembler::EmitBcondc(BranchCondition cond, 635 GpuRegister rs, 636 GpuRegister rt, 637 uint32_t imm16_21) { 638 switch (cond) { 639 case kCondLT: 640 Bltc(rs, rt, imm16_21); 641 break; 642 case kCondGE: 643 Bgec(rs, rt, imm16_21); 644 break; 645 case kCondLE: 646 Bgec(rt, rs, imm16_21); 647 break; 648 case kCondGT: 649 Bltc(rt, rs, imm16_21); 650 break; 651 case kCondLTZ: 652 CHECK_EQ(rt, ZERO); 653 Bltzc(rs, imm16_21); 654 break; 655 case kCondGEZ: 656 CHECK_EQ(rt, ZERO); 657 Bgezc(rs, imm16_21); 658 break; 659 case kCondLEZ: 660 CHECK_EQ(rt, ZERO); 661 Blezc(rs, imm16_21); 662 break; 663 case kCondGTZ: 664 CHECK_EQ(rt, ZERO); 665 Bgtzc(rs, imm16_21); 666 break; 667 case kCondEQ: 668 Beqc(rs, rt, imm16_21); 669 break; 670 case kCondNE: 671 Bnec(rs, rt, imm16_21); 672 break; 673 case kCondEQZ: 674 CHECK_EQ(rt, ZERO); 675 Beqzc(rs, imm16_21); 676 break; 677 case kCondNEZ: 678 CHECK_EQ(rt, ZERO); 679 Bnezc(rs, imm16_21); 680 break; 681 case kCondLTU: 682 Bltuc(rs, rt, imm16_21); 683 break; 684 case kCondGEU: 685 Bgeuc(rs, rt, imm16_21); 686 break; 687 case kCondF: 688 CHECK_EQ(rt, ZERO); 689 Bc1eqz(static_cast<FpuRegister>(rs), imm16_21); 690 break; 691 case kCondT: 692 CHECK_EQ(rt, ZERO); 693 Bc1nez(static_cast<FpuRegister>(rs), imm16_21); 694 break; 695 case kUncond: 696 LOG(FATAL) << "Unexpected branch condition " << cond; 697 UNREACHABLE(); 698 } 699 } 700 701 void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 702 EmitFR(0x11, 0x10, ft, fs, fd, 0x0); 703 } 704 705 void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 706 EmitFR(0x11, 0x10, ft, fs, fd, 0x1); 707 } 708 709 void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 710 EmitFR(0x11, 0x10, ft, fs, fd, 0x2); 711 } 712 713 void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 714 EmitFR(0x11, 0x10, ft, fs, fd, 0x3); 715 } 716 717 void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 718 EmitFR(0x11, 0x11, ft, fs, fd, 0x0); 719 } 720 721 void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 722 EmitFR(0x11, 0x11, ft, fs, fd, 0x1); 723 } 724 725 void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 726 EmitFR(0x11, 0x11, ft, fs, fd, 0x2); 727 } 728 729 void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 730 EmitFR(0x11, 0x11, ft, fs, fd, 0x3); 731 } 732 733 void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) { 734 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4); 735 } 736 737 void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) { 738 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4); 739 } 740 741 void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) { 742 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5); 743 } 744 745 void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) { 746 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5); 747 } 748 749 void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) { 750 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6); 751 } 752 753 void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) { 754 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x6); 755 } 756 757 void Mips64Assembler::NegS(FpuRegister fd, FpuRegister fs) { 758 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x7); 759 } 760 761 void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) { 762 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7); 763 } 764 765 void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) { 766 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8); 767 } 768 769 void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) { 770 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8); 771 } 772 773 void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) { 774 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc); 775 } 776 777 void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) { 778 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc); 779 } 780 781 void Mips64Assembler::TruncLS(FpuRegister fd, FpuRegister fs) { 782 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x9); 783 } 784 785 void Mips64Assembler::TruncLD(FpuRegister fd, FpuRegister fs) { 786 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x9); 787 } 788 789 void Mips64Assembler::TruncWS(FpuRegister fd, FpuRegister fs) { 790 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xd); 791 } 792 793 void Mips64Assembler::TruncWD(FpuRegister fd, FpuRegister fs) { 794 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xd); 795 } 796 797 void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) { 798 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa); 799 } 800 801 void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) { 802 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa); 803 } 804 805 void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) { 806 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe); 807 } 808 809 void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) { 810 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe); 811 } 812 813 void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) { 814 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb); 815 } 816 817 void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) { 818 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb); 819 } 820 821 void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) { 822 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf); 823 } 824 825 void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) { 826 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf); 827 } 828 829 void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 830 EmitFR(0x11, 0x10, ft, fs, fd, 0x10); 831 } 832 833 void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 834 EmitFR(0x11, 0x11, ft, fs, fd, 0x10); 835 } 836 837 void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) { 838 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a); 839 } 840 841 void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) { 842 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a); 843 } 844 845 void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) { 846 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b); 847 } 848 849 void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) { 850 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b); 851 } 852 853 void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 854 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c); 855 } 856 857 void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 858 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c); 859 } 860 861 void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 862 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e); 863 } 864 865 void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 866 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e); 867 } 868 869 void Mips64Assembler::CmpUnS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 870 EmitFR(0x11, 0x14, ft, fs, fd, 0x01); 871 } 872 873 void Mips64Assembler::CmpEqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 874 EmitFR(0x11, 0x14, ft, fs, fd, 0x02); 875 } 876 877 void Mips64Assembler::CmpUeqS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 878 EmitFR(0x11, 0x14, ft, fs, fd, 0x03); 879 } 880 881 void Mips64Assembler::CmpLtS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 882 EmitFR(0x11, 0x14, ft, fs, fd, 0x04); 883 } 884 885 void Mips64Assembler::CmpUltS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 886 EmitFR(0x11, 0x14, ft, fs, fd, 0x05); 887 } 888 889 void Mips64Assembler::CmpLeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 890 EmitFR(0x11, 0x14, ft, fs, fd, 0x06); 891 } 892 893 void Mips64Assembler::CmpUleS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 894 EmitFR(0x11, 0x14, ft, fs, fd, 0x07); 895 } 896 897 void Mips64Assembler::CmpOrS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 898 EmitFR(0x11, 0x14, ft, fs, fd, 0x11); 899 } 900 901 void Mips64Assembler::CmpUneS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 902 EmitFR(0x11, 0x14, ft, fs, fd, 0x12); 903 } 904 905 void Mips64Assembler::CmpNeS(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 906 EmitFR(0x11, 0x14, ft, fs, fd, 0x13); 907 } 908 909 void Mips64Assembler::CmpUnD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 910 EmitFR(0x11, 0x15, ft, fs, fd, 0x01); 911 } 912 913 void Mips64Assembler::CmpEqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 914 EmitFR(0x11, 0x15, ft, fs, fd, 0x02); 915 } 916 917 void Mips64Assembler::CmpUeqD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 918 EmitFR(0x11, 0x15, ft, fs, fd, 0x03); 919 } 920 921 void Mips64Assembler::CmpLtD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 922 EmitFR(0x11, 0x15, ft, fs, fd, 0x04); 923 } 924 925 void Mips64Assembler::CmpUltD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 926 EmitFR(0x11, 0x15, ft, fs, fd, 0x05); 927 } 928 929 void Mips64Assembler::CmpLeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 930 EmitFR(0x11, 0x15, ft, fs, fd, 0x06); 931 } 932 933 void Mips64Assembler::CmpUleD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 934 EmitFR(0x11, 0x15, ft, fs, fd, 0x07); 935 } 936 937 void Mips64Assembler::CmpOrD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 938 EmitFR(0x11, 0x15, ft, fs, fd, 0x11); 939 } 940 941 void Mips64Assembler::CmpUneD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 942 EmitFR(0x11, 0x15, ft, fs, fd, 0x12); 943 } 944 945 void Mips64Assembler::CmpNeD(FpuRegister fd, FpuRegister fs, FpuRegister ft) { 946 EmitFR(0x11, 0x15, ft, fs, fd, 0x13); 947 } 948 949 void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) { 950 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20); 951 } 952 953 void Mips64Assembler::Cvtdw(FpuRegister fd, FpuRegister fs) { 954 EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x21); 955 } 956 957 void Mips64Assembler::Cvtsd(FpuRegister fd, FpuRegister fs) { 958 EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x20); 959 } 960 961 void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) { 962 EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21); 963 } 964 965 void Mips64Assembler::Cvtsl(FpuRegister fd, FpuRegister fs) { 966 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x20); 967 } 968 969 void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) { 970 EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21); 971 } 972 973 void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) { 974 EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); 975 } 976 977 void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) { 978 EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); 979 } 980 981 void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) { 982 EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); 983 } 984 985 void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) { 986 EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); 987 } 988 989 void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) { 990 EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); 991 } 992 993 void Mips64Assembler::Dmtc1(GpuRegister rt, FpuRegister fs) { 994 EmitFR(0x11, 0x05, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0); 995 } 996 997 void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) { 998 EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16); 999 } 1000 1001 void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) { 1002 EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16); 1003 } 1004 1005 void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) { 1006 EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16); 1007 } 1008 1009 void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) { 1010 EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16); 1011 } 1012 1013 void Mips64Assembler::Break() { 1014 EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0), 1015 static_cast<GpuRegister>(0), 0, 0xD); 1016 } 1017 1018 void Mips64Assembler::Nop() { 1019 EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0), 1020 static_cast<GpuRegister>(0), 0, 0x0); 1021 } 1022 1023 void Mips64Assembler::Move(GpuRegister rd, GpuRegister rs) { 1024 Or(rd, rs, ZERO); 1025 } 1026 1027 void Mips64Assembler::Clear(GpuRegister rd) { 1028 Move(rd, ZERO); 1029 } 1030 1031 void Mips64Assembler::Not(GpuRegister rd, GpuRegister rs) { 1032 Nor(rd, rs, ZERO); 1033 } 1034 1035 void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) { 1036 if (IsUint<16>(value)) { 1037 // Use OR with (unsigned) immediate to encode 16b unsigned int. 1038 Ori(rd, ZERO, value); 1039 } else if (IsInt<16>(value)) { 1040 // Use ADD with (signed) immediate to encode 16b signed int. 1041 Addiu(rd, ZERO, value); 1042 } else { 1043 Lui(rd, value >> 16); 1044 if (value & 0xFFFF) 1045 Ori(rd, rd, value); 1046 } 1047 } 1048 1049 void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) { 1050 int bit31 = (value & UINT64_C(0x80000000)) != 0; 1051 1052 // Loads with 1 instruction. 1053 if (IsUint<16>(value)) { 1054 Ori(rd, ZERO, value); 1055 } else if (IsInt<16>(value)) { 1056 Daddiu(rd, ZERO, value); 1057 } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) { 1058 Lui(rd, value >> 16); 1059 } else if (IsInt<32>(value)) { 1060 // Loads with 2 instructions. 1061 Lui(rd, value >> 16); 1062 Ori(rd, rd, value); 1063 } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) { 1064 Ori(rd, ZERO, value); 1065 Dahi(rd, value >> 32); 1066 } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) { 1067 Ori(rd, ZERO, value); 1068 Dati(rd, value >> 48); 1069 } else if ((value & 0xFFFF) == 0 && 1070 (-32768 - bit31) <= (value >> 32) && (value >> 32) <= (32767 - bit31)) { 1071 Lui(rd, value >> 16); 1072 Dahi(rd, (value >> 32) + bit31); 1073 } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) { 1074 Lui(rd, value >> 16); 1075 Dati(rd, (value >> 48) + bit31); 1076 } else if (IsPowerOfTwo(value + UINT64_C(1))) { 1077 int shift_cnt = 64 - CTZ(value + UINT64_C(1)); 1078 Daddiu(rd, ZERO, -1); 1079 if (shift_cnt < 32) { 1080 Dsrl(rd, rd, shift_cnt); 1081 } else { 1082 Dsrl32(rd, rd, shift_cnt & 31); 1083 } 1084 } else { 1085 int shift_cnt = CTZ(value); 1086 int64_t tmp = value >> shift_cnt; 1087 if (IsUint<16>(tmp)) { 1088 Ori(rd, ZERO, tmp); 1089 if (shift_cnt < 32) { 1090 Dsll(rd, rd, shift_cnt); 1091 } else { 1092 Dsll32(rd, rd, shift_cnt & 31); 1093 } 1094 } else if (IsInt<16>(tmp)) { 1095 Daddiu(rd, ZERO, tmp); 1096 if (shift_cnt < 32) { 1097 Dsll(rd, rd, shift_cnt); 1098 } else { 1099 Dsll32(rd, rd, shift_cnt & 31); 1100 } 1101 } else if (IsInt<32>(tmp)) { 1102 // Loads with 3 instructions. 1103 Lui(rd, tmp >> 16); 1104 Ori(rd, rd, tmp); 1105 if (shift_cnt < 32) { 1106 Dsll(rd, rd, shift_cnt); 1107 } else { 1108 Dsll32(rd, rd, shift_cnt & 31); 1109 } 1110 } else { 1111 shift_cnt = 16 + CTZ(value >> 16); 1112 tmp = value >> shift_cnt; 1113 if (IsUint<16>(tmp)) { 1114 Ori(rd, ZERO, tmp); 1115 if (shift_cnt < 32) { 1116 Dsll(rd, rd, shift_cnt); 1117 } else { 1118 Dsll32(rd, rd, shift_cnt & 31); 1119 } 1120 Ori(rd, rd, value); 1121 } else if (IsInt<16>(tmp)) { 1122 Daddiu(rd, ZERO, tmp); 1123 if (shift_cnt < 32) { 1124 Dsll(rd, rd, shift_cnt); 1125 } else { 1126 Dsll32(rd, rd, shift_cnt & 31); 1127 } 1128 Ori(rd, rd, value); 1129 } else { 1130 // Loads with 3-4 instructions. 1131 uint64_t tmp2 = value; 1132 bool used_lui = false; 1133 if (((tmp2 >> 16) & 0xFFFF) != 0 || (tmp2 & 0xFFFFFFFF) == 0) { 1134 Lui(rd, tmp2 >> 16); 1135 used_lui = true; 1136 } 1137 if ((tmp2 & 0xFFFF) != 0) { 1138 if (used_lui) { 1139 Ori(rd, rd, tmp2); 1140 } else { 1141 Ori(rd, ZERO, tmp2); 1142 } 1143 } 1144 if (bit31) { 1145 tmp2 += UINT64_C(0x100000000); 1146 } 1147 if (((tmp2 >> 32) & 0xFFFF) != 0) { 1148 Dahi(rd, tmp2 >> 32); 1149 } 1150 if (tmp2 & UINT64_C(0x800000000000)) { 1151 tmp2 += UINT64_C(0x1000000000000); 1152 } 1153 if ((tmp2 >> 48) != 0) { 1154 Dati(rd, tmp2 >> 48); 1155 } 1156 } 1157 } 1158 } 1159 } 1160 1161 void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) { 1162 if (IsInt<16>(value)) { 1163 Daddiu(rt, rs, value); 1164 } else { 1165 LoadConst64(rtmp, value); 1166 Daddu(rt, rs, rtmp); 1167 } 1168 } 1169 1170 void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBits offset_size, 1171 Mips64Assembler::Branch::Type short_type, 1172 Mips64Assembler::Branch::Type long_type) { 1173 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type; 1174 } 1175 1176 void Mips64Assembler::Branch::InitializeType(bool is_call) { 1177 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_); 1178 if (is_call) { 1179 InitShortOrLong(offset_size, kCall, kLongCall); 1180 } else if (condition_ == kUncond) { 1181 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch); 1182 } else { 1183 if (condition_ == kCondEQZ || condition_ == kCondNEZ) { 1184 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions. 1185 type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch; 1186 } else { 1187 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch); 1188 } 1189 } 1190 old_type_ = type_; 1191 } 1192 1193 bool Mips64Assembler::Branch::IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs) { 1194 switch (condition) { 1195 case kCondLT: 1196 case kCondGT: 1197 case kCondNE: 1198 case kCondLTU: 1199 return lhs == rhs; 1200 default: 1201 return false; 1202 } 1203 } 1204 1205 bool Mips64Assembler::Branch::IsUncond(BranchCondition condition, 1206 GpuRegister lhs, 1207 GpuRegister rhs) { 1208 switch (condition) { 1209 case kUncond: 1210 return true; 1211 case kCondGE: 1212 case kCondLE: 1213 case kCondEQ: 1214 case kCondGEU: 1215 return lhs == rhs; 1216 default: 1217 return false; 1218 } 1219 } 1220 1221 Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target) 1222 : old_location_(location), 1223 location_(location), 1224 target_(target), 1225 lhs_reg_(ZERO), 1226 rhs_reg_(ZERO), 1227 condition_(kUncond) { 1228 InitializeType(false); 1229 } 1230 1231 Mips64Assembler::Branch::Branch(uint32_t location, 1232 uint32_t target, 1233 Mips64Assembler::BranchCondition condition, 1234 GpuRegister lhs_reg, 1235 GpuRegister rhs_reg) 1236 : old_location_(location), 1237 location_(location), 1238 target_(target), 1239 lhs_reg_(lhs_reg), 1240 rhs_reg_(rhs_reg), 1241 condition_(condition) { 1242 CHECK_NE(condition, kUncond); 1243 switch (condition) { 1244 case kCondEQ: 1245 case kCondNE: 1246 case kCondLT: 1247 case kCondGE: 1248 case kCondLE: 1249 case kCondGT: 1250 case kCondLTU: 1251 case kCondGEU: 1252 CHECK_NE(lhs_reg, ZERO); 1253 CHECK_NE(rhs_reg, ZERO); 1254 break; 1255 case kCondLTZ: 1256 case kCondGEZ: 1257 case kCondLEZ: 1258 case kCondGTZ: 1259 case kCondEQZ: 1260 case kCondNEZ: 1261 CHECK_NE(lhs_reg, ZERO); 1262 CHECK_EQ(rhs_reg, ZERO); 1263 break; 1264 case kCondF: 1265 case kCondT: 1266 CHECK_EQ(rhs_reg, ZERO); 1267 break; 1268 case kUncond: 1269 UNREACHABLE(); 1270 } 1271 CHECK(!IsNop(condition, lhs_reg, rhs_reg)); 1272 if (IsUncond(condition, lhs_reg, rhs_reg)) { 1273 // Branch condition is always true, make the branch unconditional. 1274 condition_ = kUncond; 1275 } 1276 InitializeType(false); 1277 } 1278 1279 Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, GpuRegister indirect_reg) 1280 : old_location_(location), 1281 location_(location), 1282 target_(target), 1283 lhs_reg_(indirect_reg), 1284 rhs_reg_(ZERO), 1285 condition_(kUncond) { 1286 CHECK_NE(indirect_reg, ZERO); 1287 CHECK_NE(indirect_reg, AT); 1288 InitializeType(true); 1289 } 1290 1291 Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition( 1292 Mips64Assembler::BranchCondition cond) { 1293 switch (cond) { 1294 case kCondLT: 1295 return kCondGE; 1296 case kCondGE: 1297 return kCondLT; 1298 case kCondLE: 1299 return kCondGT; 1300 case kCondGT: 1301 return kCondLE; 1302 case kCondLTZ: 1303 return kCondGEZ; 1304 case kCondGEZ: 1305 return kCondLTZ; 1306 case kCondLEZ: 1307 return kCondGTZ; 1308 case kCondGTZ: 1309 return kCondLEZ; 1310 case kCondEQ: 1311 return kCondNE; 1312 case kCondNE: 1313 return kCondEQ; 1314 case kCondEQZ: 1315 return kCondNEZ; 1316 case kCondNEZ: 1317 return kCondEQZ; 1318 case kCondLTU: 1319 return kCondGEU; 1320 case kCondGEU: 1321 return kCondLTU; 1322 case kCondF: 1323 return kCondT; 1324 case kCondT: 1325 return kCondF; 1326 case kUncond: 1327 LOG(FATAL) << "Unexpected branch condition " << cond; 1328 } 1329 UNREACHABLE(); 1330 } 1331 1332 Mips64Assembler::Branch::Type Mips64Assembler::Branch::GetType() const { 1333 return type_; 1334 } 1335 1336 Mips64Assembler::BranchCondition Mips64Assembler::Branch::GetCondition() const { 1337 return condition_; 1338 } 1339 1340 GpuRegister Mips64Assembler::Branch::GetLeftRegister() const { 1341 return lhs_reg_; 1342 } 1343 1344 GpuRegister Mips64Assembler::Branch::GetRightRegister() const { 1345 return rhs_reg_; 1346 } 1347 1348 uint32_t Mips64Assembler::Branch::GetTarget() const { 1349 return target_; 1350 } 1351 1352 uint32_t Mips64Assembler::Branch::GetLocation() const { 1353 return location_; 1354 } 1355 1356 uint32_t Mips64Assembler::Branch::GetOldLocation() const { 1357 return old_location_; 1358 } 1359 1360 uint32_t Mips64Assembler::Branch::GetLength() const { 1361 return branch_info_[type_].length; 1362 } 1363 1364 uint32_t Mips64Assembler::Branch::GetOldLength() const { 1365 return branch_info_[old_type_].length; 1366 } 1367 1368 uint32_t Mips64Assembler::Branch::GetSize() const { 1369 return GetLength() * sizeof(uint32_t); 1370 } 1371 1372 uint32_t Mips64Assembler::Branch::GetOldSize() const { 1373 return GetOldLength() * sizeof(uint32_t); 1374 } 1375 1376 uint32_t Mips64Assembler::Branch::GetEndLocation() const { 1377 return GetLocation() + GetSize(); 1378 } 1379 1380 uint32_t Mips64Assembler::Branch::GetOldEndLocation() const { 1381 return GetOldLocation() + GetOldSize(); 1382 } 1383 1384 bool Mips64Assembler::Branch::IsLong() const { 1385 switch (type_) { 1386 // Short branches. 1387 case kUncondBranch: 1388 case kCondBranch: 1389 case kCall: 1390 return false; 1391 // Long branches. 1392 case kLongUncondBranch: 1393 case kLongCondBranch: 1394 case kLongCall: 1395 return true; 1396 } 1397 UNREACHABLE(); 1398 } 1399 1400 bool Mips64Assembler::Branch::IsResolved() const { 1401 return target_ != kUnresolved; 1402 } 1403 1404 Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const { 1405 OffsetBits offset_size = 1406 (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ)) 1407 ? kOffset23 1408 : branch_info_[type_].offset_size; 1409 return offset_size; 1410 } 1411 1412 Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSizeNeeded(uint32_t location, 1413 uint32_t target) { 1414 // For unresolved targets assume the shortest encoding 1415 // (later it will be made longer if needed). 1416 if (target == kUnresolved) 1417 return kOffset16; 1418 int64_t distance = static_cast<int64_t>(target) - location; 1419 // To simplify calculations in composite branches consisting of multiple instructions 1420 // bump up the distance by a value larger than the max byte size of a composite branch. 1421 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize; 1422 if (IsInt<kOffset16>(distance)) 1423 return kOffset16; 1424 else if (IsInt<kOffset18>(distance)) 1425 return kOffset18; 1426 else if (IsInt<kOffset21>(distance)) 1427 return kOffset21; 1428 else if (IsInt<kOffset23>(distance)) 1429 return kOffset23; 1430 else if (IsInt<kOffset28>(distance)) 1431 return kOffset28; 1432 return kOffset32; 1433 } 1434 1435 void Mips64Assembler::Branch::Resolve(uint32_t target) { 1436 target_ = target; 1437 } 1438 1439 void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) { 1440 if (location_ > expand_location) { 1441 location_ += delta; 1442 } 1443 if (!IsResolved()) { 1444 return; // Don't know the target yet. 1445 } 1446 if (target_ > expand_location) { 1447 target_ += delta; 1448 } 1449 } 1450 1451 void Mips64Assembler::Branch::PromoteToLong() { 1452 switch (type_) { 1453 // Short branches. 1454 case kUncondBranch: 1455 type_ = kLongUncondBranch; 1456 break; 1457 case kCondBranch: 1458 type_ = kLongCondBranch; 1459 break; 1460 case kCall: 1461 type_ = kLongCall; 1462 break; 1463 default: 1464 // Note: 'type_' is already long. 1465 break; 1466 } 1467 CHECK(IsLong()); 1468 } 1469 1470 uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) { 1471 // If the branch is still unresolved or already long, nothing to do. 1472 if (IsLong() || !IsResolved()) { 1473 return 0; 1474 } 1475 // Promote the short branch to long if the offset size is too small 1476 // to hold the distance between location_ and target_. 1477 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) { 1478 PromoteToLong(); 1479 uint32_t old_size = GetOldSize(); 1480 uint32_t new_size = GetSize(); 1481 CHECK_GT(new_size, old_size); 1482 return new_size - old_size; 1483 } 1484 // The following logic is for debugging/testing purposes. 1485 // Promote some short branches to long when it's not really required. 1486 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) { 1487 int64_t distance = static_cast<int64_t>(target_) - location_; 1488 distance = (distance >= 0) ? distance : -distance; 1489 if (distance >= max_short_distance) { 1490 PromoteToLong(); 1491 uint32_t old_size = GetOldSize(); 1492 uint32_t new_size = GetSize(); 1493 CHECK_GT(new_size, old_size); 1494 return new_size - old_size; 1495 } 1496 } 1497 return 0; 1498 } 1499 1500 uint32_t Mips64Assembler::Branch::GetOffsetLocation() const { 1501 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t); 1502 } 1503 1504 uint32_t Mips64Assembler::Branch::GetOffset() const { 1505 CHECK(IsResolved()); 1506 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize()); 1507 // Calculate the byte distance between instructions and also account for 1508 // different PC-relative origins. 1509 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t); 1510 // Prepare the offset for encoding into the instruction(s). 1511 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift; 1512 return offset; 1513 } 1514 1515 Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) { 1516 CHECK_LT(branch_id, branches_.size()); 1517 return &branches_[branch_id]; 1518 } 1519 1520 const Mips64Assembler::Branch* Mips64Assembler::GetBranch(uint32_t branch_id) const { 1521 CHECK_LT(branch_id, branches_.size()); 1522 return &branches_[branch_id]; 1523 } 1524 1525 void Mips64Assembler::Bind(Mips64Label* label) { 1526 CHECK(!label->IsBound()); 1527 uint32_t bound_pc = buffer_.Size(); 1528 1529 // Walk the list of branches referring to and preceding this label. 1530 // Store the previously unknown target addresses in them. 1531 while (label->IsLinked()) { 1532 uint32_t branch_id = label->Position(); 1533 Branch* branch = GetBranch(branch_id); 1534 branch->Resolve(bound_pc); 1535 1536 uint32_t branch_location = branch->GetLocation(); 1537 // Extract the location of the previous branch in the list (walking the list backwards; 1538 // the previous branch ID was stored in the space reserved for this branch). 1539 uint32_t prev = buffer_.Load<uint32_t>(branch_location); 1540 1541 // On to the previous branch in the list... 1542 label->position_ = prev; 1543 } 1544 1545 // Now make the label object contain its own location (relative to the end of the preceding 1546 // branch, if any; it will be used by the branches referring to and following this label). 1547 label->prev_branch_id_plus_one_ = branches_.size(); 1548 if (label->prev_branch_id_plus_one_) { 1549 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1; 1550 const Branch* branch = GetBranch(branch_id); 1551 bound_pc -= branch->GetEndLocation(); 1552 } 1553 label->BindTo(bound_pc); 1554 } 1555 1556 uint32_t Mips64Assembler::GetLabelLocation(Mips64Label* label) const { 1557 CHECK(label->IsBound()); 1558 uint32_t target = label->Position(); 1559 if (label->prev_branch_id_plus_one_) { 1560 // Get label location based on the branch preceding it. 1561 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1; 1562 const Branch* branch = GetBranch(branch_id); 1563 target += branch->GetEndLocation(); 1564 } 1565 return target; 1566 } 1567 1568 uint32_t Mips64Assembler::GetAdjustedPosition(uint32_t old_position) { 1569 // We can reconstruct the adjustment by going through all the branches from the beginning 1570 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop 1571 // with increasing old_position, we can use the data from last AdjustedPosition() to 1572 // continue where we left off and the whole loop should be O(m+n) where m is the number 1573 // of positions to adjust and n is the number of branches. 1574 if (old_position < last_old_position_) { 1575 last_position_adjustment_ = 0; 1576 last_old_position_ = 0; 1577 last_branch_id_ = 0; 1578 } 1579 while (last_branch_id_ != branches_.size()) { 1580 const Branch* branch = GetBranch(last_branch_id_); 1581 if (branch->GetLocation() >= old_position + last_position_adjustment_) { 1582 break; 1583 } 1584 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize(); 1585 ++last_branch_id_; 1586 } 1587 last_old_position_ = old_position; 1588 return old_position + last_position_adjustment_; 1589 } 1590 1591 void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) { 1592 uint32_t length = branches_.back().GetLength(); 1593 if (!label->IsBound()) { 1594 // Branch forward (to a following label), distance is unknown. 1595 // The first branch forward will contain 0, serving as the terminator of 1596 // the list of forward-reaching branches. 1597 Emit(label->position_); 1598 length--; 1599 // Now make the label object point to this branch 1600 // (this forms a linked list of branches preceding this label). 1601 uint32_t branch_id = branches_.size() - 1; 1602 label->LinkTo(branch_id); 1603 } 1604 // Reserve space for the branch. 1605 while (length--) { 1606 Nop(); 1607 } 1608 } 1609 1610 void Mips64Assembler::Buncond(Mips64Label* label) { 1611 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 1612 branches_.emplace_back(buffer_.Size(), target); 1613 FinalizeLabeledBranch(label); 1614 } 1615 1616 void Mips64Assembler::Bcond(Mips64Label* label, 1617 BranchCondition condition, 1618 GpuRegister lhs, 1619 GpuRegister rhs) { 1620 // If lhs = rhs, this can be a NOP. 1621 if (Branch::IsNop(condition, lhs, rhs)) { 1622 return; 1623 } 1624 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 1625 branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs); 1626 FinalizeLabeledBranch(label); 1627 } 1628 1629 void Mips64Assembler::Call(Mips64Label* label, GpuRegister indirect_reg) { 1630 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 1631 branches_.emplace_back(buffer_.Size(), target, indirect_reg); 1632 FinalizeLabeledBranch(label); 1633 } 1634 1635 void Mips64Assembler::PromoteBranches() { 1636 // Promote short branches to long as necessary. 1637 bool changed; 1638 do { 1639 changed = false; 1640 for (auto& branch : branches_) { 1641 CHECK(branch.IsResolved()); 1642 uint32_t delta = branch.PromoteIfNeeded(); 1643 // If this branch has been promoted and needs to expand in size, 1644 // relocate all branches by the expansion size. 1645 if (delta) { 1646 changed = true; 1647 uint32_t expand_location = branch.GetLocation(); 1648 for (auto& branch2 : branches_) { 1649 branch2.Relocate(expand_location, delta); 1650 } 1651 } 1652 } 1653 } while (changed); 1654 1655 // Account for branch expansion by resizing the code buffer 1656 // and moving the code in it to its final location. 1657 size_t branch_count = branches_.size(); 1658 if (branch_count > 0) { 1659 // Resize. 1660 Branch& last_branch = branches_[branch_count - 1]; 1661 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation(); 1662 uint32_t old_size = buffer_.Size(); 1663 buffer_.Resize(old_size + size_delta); 1664 // Move the code residing between branch placeholders. 1665 uint32_t end = old_size; 1666 for (size_t i = branch_count; i > 0; ) { 1667 Branch& branch = branches_[--i]; 1668 uint32_t size = end - branch.GetOldEndLocation(); 1669 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size); 1670 end = branch.GetOldLocation(); 1671 } 1672 } 1673 } 1674 1675 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized. 1676 const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = { 1677 // Short branches. 1678 { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch 1679 { 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch 1680 // Exception: kOffset23 for beqzc/bnezc 1681 { 2, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kCall 1682 // Long branches. 1683 { 2, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongUncondBranch 1684 { 3, 1, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCondBranch 1685 { 3, 0, 0, Mips64Assembler::Branch::kOffset32, 0 }, // kLongCall 1686 }; 1687 1688 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized. 1689 void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) { 1690 CHECK(overwriting_); 1691 overwrite_location_ = branch->GetLocation(); 1692 uint32_t offset = branch->GetOffset(); 1693 BranchCondition condition = branch->GetCondition(); 1694 GpuRegister lhs = branch->GetLeftRegister(); 1695 GpuRegister rhs = branch->GetRightRegister(); 1696 switch (branch->GetType()) { 1697 // Short branches. 1698 case Branch::kUncondBranch: 1699 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1700 Bc(offset); 1701 break; 1702 case Branch::kCondBranch: 1703 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1704 EmitBcondc(condition, lhs, rhs, offset); 1705 Nop(); // TODO: improve by filling the forbidden/delay slot. 1706 break; 1707 case Branch::kCall: 1708 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1709 Addiupc(lhs, offset); 1710 Jialc(lhs, 0); 1711 break; 1712 1713 // Long branches. 1714 case Branch::kLongUncondBranch: 1715 offset += (offset & 0x8000) << 1; // Account for sign extension in jic. 1716 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1717 Auipc(AT, High16Bits(offset)); 1718 Jic(AT, Low16Bits(offset)); 1719 break; 1720 case Branch::kLongCondBranch: 1721 EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2); 1722 offset += (offset & 0x8000) << 1; // Account for sign extension in jic. 1723 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1724 Auipc(AT, High16Bits(offset)); 1725 Jic(AT, Low16Bits(offset)); 1726 break; 1727 case Branch::kLongCall: 1728 offset += (offset & 0x8000) << 1; // Account for sign extension in daddiu. 1729 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1730 Auipc(lhs, High16Bits(offset)); 1731 Daddiu(lhs, lhs, Low16Bits(offset)); 1732 Jialc(lhs, 0); 1733 break; 1734 } 1735 CHECK_EQ(overwrite_location_, branch->GetEndLocation()); 1736 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize)); 1737 } 1738 1739 void Mips64Assembler::Bc(Mips64Label* label) { 1740 Buncond(label); 1741 } 1742 1743 void Mips64Assembler::Jialc(Mips64Label* label, GpuRegister indirect_reg) { 1744 Call(label, indirect_reg); 1745 } 1746 1747 void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) { 1748 Bcond(label, kCondLT, rs, rt); 1749 } 1750 1751 void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) { 1752 Bcond(label, kCondLTZ, rt); 1753 } 1754 1755 void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) { 1756 Bcond(label, kCondGTZ, rt); 1757 } 1758 1759 void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) { 1760 Bcond(label, kCondGE, rs, rt); 1761 } 1762 1763 void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) { 1764 Bcond(label, kCondGEZ, rt); 1765 } 1766 1767 void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) { 1768 Bcond(label, kCondLEZ, rt); 1769 } 1770 1771 void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) { 1772 Bcond(label, kCondLTU, rs, rt); 1773 } 1774 1775 void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) { 1776 Bcond(label, kCondGEU, rs, rt); 1777 } 1778 1779 void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) { 1780 Bcond(label, kCondEQ, rs, rt); 1781 } 1782 1783 void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) { 1784 Bcond(label, kCondNE, rs, rt); 1785 } 1786 1787 void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) { 1788 Bcond(label, kCondEQZ, rs); 1789 } 1790 1791 void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) { 1792 Bcond(label, kCondNEZ, rs); 1793 } 1794 1795 void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) { 1796 Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO); 1797 } 1798 1799 void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) { 1800 Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO); 1801 } 1802 1803 void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base, 1804 int32_t offset) { 1805 if (!IsInt<16>(offset) || 1806 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) && 1807 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) { 1808 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1)); 1809 Daddu(AT, AT, base); 1810 base = AT; 1811 offset &= (kMips64DoublewordSize - 1); 1812 } 1813 1814 switch (type) { 1815 case kLoadSignedByte: 1816 Lb(reg, base, offset); 1817 break; 1818 case kLoadUnsignedByte: 1819 Lbu(reg, base, offset); 1820 break; 1821 case kLoadSignedHalfword: 1822 Lh(reg, base, offset); 1823 break; 1824 case kLoadUnsignedHalfword: 1825 Lhu(reg, base, offset); 1826 break; 1827 case kLoadWord: 1828 CHECK_ALIGNED(offset, kMips64WordSize); 1829 Lw(reg, base, offset); 1830 break; 1831 case kLoadUnsignedWord: 1832 CHECK_ALIGNED(offset, kMips64WordSize); 1833 Lwu(reg, base, offset); 1834 break; 1835 case kLoadDoubleword: 1836 if (!IsAligned<kMips64DoublewordSize>(offset)) { 1837 CHECK_ALIGNED(offset, kMips64WordSize); 1838 Lwu(reg, base, offset); 1839 Lwu(TMP2, base, offset + kMips64WordSize); 1840 Dinsu(reg, TMP2, 32, 32); 1841 } else { 1842 Ld(reg, base, offset); 1843 } 1844 break; 1845 } 1846 } 1847 1848 void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base, 1849 int32_t offset) { 1850 if (!IsInt<16>(offset) || 1851 (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) && 1852 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) { 1853 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1)); 1854 Daddu(AT, AT, base); 1855 base = AT; 1856 offset &= (kMips64DoublewordSize - 1); 1857 } 1858 1859 switch (type) { 1860 case kLoadWord: 1861 CHECK_ALIGNED(offset, kMips64WordSize); 1862 Lwc1(reg, base, offset); 1863 break; 1864 case kLoadDoubleword: 1865 if (!IsAligned<kMips64DoublewordSize>(offset)) { 1866 CHECK_ALIGNED(offset, kMips64WordSize); 1867 Lwc1(reg, base, offset); 1868 Lw(TMP2, base, offset + kMips64WordSize); 1869 Mthc1(TMP2, reg); 1870 } else { 1871 Ldc1(reg, base, offset); 1872 } 1873 break; 1874 default: 1875 LOG(FATAL) << "UNREACHABLE"; 1876 } 1877 } 1878 1879 void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset, 1880 size_t size) { 1881 Mips64ManagedRegister dst = m_dst.AsMips64(); 1882 if (dst.IsNoRegister()) { 1883 CHECK_EQ(0u, size) << dst; 1884 } else if (dst.IsGpuRegister()) { 1885 if (size == 4) { 1886 LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset); 1887 } else if (size == 8) { 1888 CHECK_EQ(8u, size) << dst; 1889 LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset); 1890 } else { 1891 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8"; 1892 } 1893 } else if (dst.IsFpuRegister()) { 1894 if (size == 4) { 1895 CHECK_EQ(4u, size) << dst; 1896 LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset); 1897 } else if (size == 8) { 1898 CHECK_EQ(8u, size) << dst; 1899 LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset); 1900 } else { 1901 UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8"; 1902 } 1903 } 1904 } 1905 1906 void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base, 1907 int32_t offset) { 1908 if (!IsInt<16>(offset) || 1909 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) && 1910 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) { 1911 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1)); 1912 Daddu(AT, AT, base); 1913 base = AT; 1914 offset &= (kMips64DoublewordSize - 1); 1915 } 1916 1917 switch (type) { 1918 case kStoreByte: 1919 Sb(reg, base, offset); 1920 break; 1921 case kStoreHalfword: 1922 Sh(reg, base, offset); 1923 break; 1924 case kStoreWord: 1925 CHECK_ALIGNED(offset, kMips64WordSize); 1926 Sw(reg, base, offset); 1927 break; 1928 case kStoreDoubleword: 1929 if (!IsAligned<kMips64DoublewordSize>(offset)) { 1930 CHECK_ALIGNED(offset, kMips64WordSize); 1931 Sw(reg, base, offset); 1932 Dsrl32(TMP2, reg, 0); 1933 Sw(TMP2, base, offset + kMips64WordSize); 1934 } else { 1935 Sd(reg, base, offset); 1936 } 1937 break; 1938 default: 1939 LOG(FATAL) << "UNREACHABLE"; 1940 } 1941 } 1942 1943 void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base, 1944 int32_t offset) { 1945 if (!IsInt<16>(offset) || 1946 (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) && 1947 !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) { 1948 LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1)); 1949 Daddu(AT, AT, base); 1950 base = AT; 1951 offset &= (kMips64DoublewordSize - 1); 1952 } 1953 1954 switch (type) { 1955 case kStoreWord: 1956 CHECK_ALIGNED(offset, kMips64WordSize); 1957 Swc1(reg, base, offset); 1958 break; 1959 case kStoreDoubleword: 1960 if (!IsAligned<kMips64DoublewordSize>(offset)) { 1961 CHECK_ALIGNED(offset, kMips64WordSize); 1962 Mfhc1(TMP2, reg); 1963 Swc1(reg, base, offset); 1964 Sw(TMP2, base, offset + kMips64WordSize); 1965 } else { 1966 Sdc1(reg, base, offset); 1967 } 1968 break; 1969 default: 1970 LOG(FATAL) << "UNREACHABLE"; 1971 } 1972 } 1973 1974 static dwarf::Reg DWARFReg(GpuRegister reg) { 1975 return dwarf::Reg::Mips64Core(static_cast<int>(reg)); 1976 } 1977 1978 constexpr size_t kFramePointerSize = 8; 1979 1980 void Mips64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, 1981 const std::vector<ManagedRegister>& callee_save_regs, 1982 const ManagedRegisterEntrySpills& entry_spills) { 1983 CHECK_ALIGNED(frame_size, kStackAlignment); 1984 DCHECK(!overwriting_); 1985 1986 // Increase frame to required size. 1987 IncreaseFrameSize(frame_size); 1988 1989 // Push callee saves and return address 1990 int stack_offset = frame_size - kFramePointerSize; 1991 StoreToOffset(kStoreDoubleword, RA, SP, stack_offset); 1992 cfi_.RelOffset(DWARFReg(RA), stack_offset); 1993 for (int i = callee_save_regs.size() - 1; i >= 0; --i) { 1994 stack_offset -= kFramePointerSize; 1995 GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister(); 1996 StoreToOffset(kStoreDoubleword, reg, SP, stack_offset); 1997 cfi_.RelOffset(DWARFReg(reg), stack_offset); 1998 } 1999 2000 // Write out Method*. 2001 StoreToOffset(kStoreDoubleword, method_reg.AsMips64().AsGpuRegister(), SP, 0); 2002 2003 // Write out entry spills. 2004 int32_t offset = frame_size + kFramePointerSize; 2005 for (size_t i = 0; i < entry_spills.size(); ++i) { 2006 Mips64ManagedRegister reg = entry_spills.at(i).AsMips64(); 2007 ManagedRegisterSpill spill = entry_spills.at(i); 2008 int32_t size = spill.getSize(); 2009 if (reg.IsNoRegister()) { 2010 // only increment stack offset. 2011 offset += size; 2012 } else if (reg.IsFpuRegister()) { 2013 StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword, 2014 reg.AsFpuRegister(), SP, offset); 2015 offset += size; 2016 } else if (reg.IsGpuRegister()) { 2017 StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword, 2018 reg.AsGpuRegister(), SP, offset); 2019 offset += size; 2020 } 2021 } 2022 } 2023 2024 void Mips64Assembler::RemoveFrame(size_t frame_size, 2025 const std::vector<ManagedRegister>& callee_save_regs) { 2026 CHECK_ALIGNED(frame_size, kStackAlignment); 2027 DCHECK(!overwriting_); 2028 cfi_.RememberState(); 2029 2030 // Pop callee saves and return address 2031 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize; 2032 for (size_t i = 0; i < callee_save_regs.size(); ++i) { 2033 GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister(); 2034 LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset); 2035 cfi_.Restore(DWARFReg(reg)); 2036 stack_offset += kFramePointerSize; 2037 } 2038 LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset); 2039 cfi_.Restore(DWARFReg(RA)); 2040 2041 // Decrease frame to required size. 2042 DecreaseFrameSize(frame_size); 2043 2044 // Then jump to the return address. 2045 Jr(RA); 2046 Nop(); 2047 2048 // The CFI should be restored for any code that follows the exit block. 2049 cfi_.RestoreState(); 2050 cfi_.DefCFAOffset(frame_size); 2051 } 2052 2053 void Mips64Assembler::IncreaseFrameSize(size_t adjust) { 2054 CHECK_ALIGNED(adjust, kFramePointerSize); 2055 DCHECK(!overwriting_); 2056 Daddiu64(SP, SP, static_cast<int32_t>(-adjust)); 2057 cfi_.AdjustCFAOffset(adjust); 2058 } 2059 2060 void Mips64Assembler::DecreaseFrameSize(size_t adjust) { 2061 CHECK_ALIGNED(adjust, kFramePointerSize); 2062 DCHECK(!overwriting_); 2063 Daddiu64(SP, SP, static_cast<int32_t>(adjust)); 2064 cfi_.AdjustCFAOffset(-adjust); 2065 } 2066 2067 void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { 2068 Mips64ManagedRegister src = msrc.AsMips64(); 2069 if (src.IsNoRegister()) { 2070 CHECK_EQ(0u, size); 2071 } else if (src.IsGpuRegister()) { 2072 CHECK(size == 4 || size == 8) << size; 2073 if (size == 8) { 2074 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value()); 2075 } else if (size == 4) { 2076 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value()); 2077 } else { 2078 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8"; 2079 } 2080 } else if (src.IsFpuRegister()) { 2081 CHECK(size == 4 || size == 8) << size; 2082 if (size == 8) { 2083 StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value()); 2084 } else if (size == 4) { 2085 StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value()); 2086 } else { 2087 UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8"; 2088 } 2089 } 2090 } 2091 2092 void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) { 2093 Mips64ManagedRegister src = msrc.AsMips64(); 2094 CHECK(src.IsGpuRegister()); 2095 StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value()); 2096 } 2097 2098 void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) { 2099 Mips64ManagedRegister src = msrc.AsMips64(); 2100 CHECK(src.IsGpuRegister()); 2101 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value()); 2102 } 2103 2104 void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm, 2105 ManagedRegister mscratch) { 2106 Mips64ManagedRegister scratch = mscratch.AsMips64(); 2107 CHECK(scratch.IsGpuRegister()) << scratch; 2108 LoadConst32(scratch.AsGpuRegister(), imm); 2109 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value()); 2110 } 2111 2112 void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs, 2113 FrameOffset fr_offs, 2114 ManagedRegister mscratch) { 2115 Mips64ManagedRegister scratch = mscratch.AsMips64(); 2116 CHECK(scratch.IsGpuRegister()) << scratch; 2117 Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value()); 2118 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value()); 2119 } 2120 2121 void Mips64Assembler::StoreStackPointerToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs) { 2122 StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value()); 2123 } 2124 2125 void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc, 2126 FrameOffset in_off, ManagedRegister mscratch) { 2127 Mips64ManagedRegister src = msrc.AsMips64(); 2128 Mips64ManagedRegister scratch = mscratch.AsMips64(); 2129 StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value()); 2130 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value()); 2131 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8); 2132 } 2133 2134 void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) { 2135 return EmitLoad(mdest, SP, src.Int32Value(), size); 2136 } 2137 2138 void Mips64Assembler::LoadFromThread64(ManagedRegister mdest, 2139 ThreadOffset<kMips64DoublewordSize> src, 2140 size_t size) { 2141 return EmitLoad(mdest, S1, src.Int32Value(), size); 2142 } 2143 2144 void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) { 2145 Mips64ManagedRegister dest = mdest.AsMips64(); 2146 CHECK(dest.IsGpuRegister()); 2147 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), SP, src.Int32Value()); 2148 } 2149 2150 void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs, 2151 bool unpoison_reference) { 2152 Mips64ManagedRegister dest = mdest.AsMips64(); 2153 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister()); 2154 LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(), 2155 base.AsMips64().AsGpuRegister(), offs.Int32Value()); 2156 if (kPoisonHeapReferences && unpoison_reference) { 2157 // TODO: review 2158 // Negate the 32-bit ref 2159 Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister()); 2160 // And constrain it to 32 bits (zero-extend into bits 32 through 63) as on Arm64 and x86/64 2161 Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 32); 2162 } 2163 } 2164 2165 void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, 2166 Offset offs) { 2167 Mips64ManagedRegister dest = mdest.AsMips64(); 2168 CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister()); 2169 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), 2170 base.AsMips64().AsGpuRegister(), offs.Int32Value()); 2171 } 2172 2173 void Mips64Assembler::LoadRawPtrFromThread64(ManagedRegister mdest, 2174 ThreadOffset<kMips64DoublewordSize> offs) { 2175 Mips64ManagedRegister dest = mdest.AsMips64(); 2176 CHECK(dest.IsGpuRegister()); 2177 LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value()); 2178 } 2179 2180 void Mips64Assembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED, 2181 size_t size ATTRIBUTE_UNUSED) { 2182 UNIMPLEMENTED(FATAL) << "No sign extension necessary for MIPS64"; 2183 } 2184 2185 void Mips64Assembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED, 2186 size_t size ATTRIBUTE_UNUSED) { 2187 UNIMPLEMENTED(FATAL) << "No zero extension necessary for MIPS64"; 2188 } 2189 2190 void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) { 2191 Mips64ManagedRegister dest = mdest.AsMips64(); 2192 Mips64ManagedRegister src = msrc.AsMips64(); 2193 if (!dest.Equals(src)) { 2194 if (dest.IsGpuRegister()) { 2195 CHECK(src.IsGpuRegister()) << src; 2196 Move(dest.AsGpuRegister(), src.AsGpuRegister()); 2197 } else if (dest.IsFpuRegister()) { 2198 CHECK(src.IsFpuRegister()) << src; 2199 if (size == 4) { 2200 MovS(dest.AsFpuRegister(), src.AsFpuRegister()); 2201 } else if (size == 8) { 2202 MovD(dest.AsFpuRegister(), src.AsFpuRegister()); 2203 } else { 2204 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; 2205 } 2206 } 2207 } 2208 } 2209 2210 void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src, 2211 ManagedRegister mscratch) { 2212 Mips64ManagedRegister scratch = mscratch.AsMips64(); 2213 CHECK(scratch.IsGpuRegister()) << scratch; 2214 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value()); 2215 StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value()); 2216 } 2217 2218 void Mips64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs, 2219 ThreadOffset<kMips64DoublewordSize> thr_offs, 2220 ManagedRegister mscratch) { 2221 Mips64ManagedRegister scratch = mscratch.AsMips64(); 2222 CHECK(scratch.IsGpuRegister()) << scratch; 2223 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value()); 2224 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value()); 2225 } 2226 2227 void Mips64Assembler::CopyRawPtrToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs, 2228 FrameOffset fr_offs, 2229 ManagedRegister mscratch) { 2230 Mips64ManagedRegister scratch = mscratch.AsMips64(); 2231 CHECK(scratch.IsGpuRegister()) << scratch; 2232 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), 2233 SP, fr_offs.Int32Value()); 2234 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), 2235 S1, thr_offs.Int32Value()); 2236 } 2237 2238 void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src, 2239 ManagedRegister mscratch, size_t size) { 2240 Mips64ManagedRegister scratch = mscratch.AsMips64(); 2241 CHECK(scratch.IsGpuRegister()) << scratch; 2242 CHECK(size == 4 || size == 8) << size; 2243 if (size == 4) { 2244 LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value()); 2245 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value()); 2246 } else if (size == 8) { 2247 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value()); 2248 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value()); 2249 } else { 2250 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; 2251 } 2252 } 2253 2254 void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, 2255 ManagedRegister mscratch, size_t size) { 2256 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister(); 2257 CHECK(size == 4 || size == 8) << size; 2258 if (size == 4) { 2259 LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(), 2260 src_offset.Int32Value()); 2261 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value()); 2262 } else if (size == 8) { 2263 LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(), 2264 src_offset.Int32Value()); 2265 StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value()); 2266 } else { 2267 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; 2268 } 2269 } 2270 2271 void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, 2272 ManagedRegister mscratch, size_t size) { 2273 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister(); 2274 CHECK(size == 4 || size == 8) << size; 2275 if (size == 4) { 2276 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value()); 2277 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(), 2278 dest_offset.Int32Value()); 2279 } else if (size == 8) { 2280 LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value()); 2281 StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(), 2282 dest_offset.Int32Value()); 2283 } else { 2284 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; 2285 } 2286 } 2287 2288 void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, 2289 FrameOffset src_base ATTRIBUTE_UNUSED, 2290 Offset src_offset ATTRIBUTE_UNUSED, 2291 ManagedRegister mscratch ATTRIBUTE_UNUSED, 2292 size_t size ATTRIBUTE_UNUSED) { 2293 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation"; 2294 } 2295 2296 void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset, 2297 ManagedRegister src, Offset src_offset, 2298 ManagedRegister mscratch, size_t size) { 2299 GpuRegister scratch = mscratch.AsMips64().AsGpuRegister(); 2300 CHECK(size == 4 || size == 8) << size; 2301 if (size == 4) { 2302 LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value()); 2303 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value()); 2304 } else if (size == 8) { 2305 LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(), 2306 src_offset.Int32Value()); 2307 StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), 2308 dest_offset.Int32Value()); 2309 } else { 2310 UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; 2311 } 2312 } 2313 2314 void Mips64Assembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, 2315 Offset dest_offset ATTRIBUTE_UNUSED, 2316 FrameOffset src ATTRIBUTE_UNUSED, 2317 Offset src_offset ATTRIBUTE_UNUSED, 2318 ManagedRegister mscratch ATTRIBUTE_UNUSED, 2319 size_t size ATTRIBUTE_UNUSED) { 2320 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation"; 2321 } 2322 2323 void Mips64Assembler::MemoryBarrier(ManagedRegister mreg ATTRIBUTE_UNUSED) { 2324 // TODO: sync? 2325 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation"; 2326 } 2327 2328 void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg, 2329 FrameOffset handle_scope_offset, 2330 ManagedRegister min_reg, 2331 bool null_allowed) { 2332 Mips64ManagedRegister out_reg = mout_reg.AsMips64(); 2333 Mips64ManagedRegister in_reg = min_reg.AsMips64(); 2334 CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg; 2335 CHECK(out_reg.IsGpuRegister()) << out_reg; 2336 if (null_allowed) { 2337 Mips64Label null_arg; 2338 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 2339 // the address in the handle scope holding the reference. 2340 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset) 2341 if (in_reg.IsNoRegister()) { 2342 LoadFromOffset(kLoadUnsignedWord, out_reg.AsGpuRegister(), 2343 SP, handle_scope_offset.Int32Value()); 2344 in_reg = out_reg; 2345 } 2346 if (!out_reg.Equals(in_reg)) { 2347 LoadConst32(out_reg.AsGpuRegister(), 0); 2348 } 2349 Beqzc(in_reg.AsGpuRegister(), &null_arg); 2350 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value()); 2351 Bind(&null_arg); 2352 } else { 2353 Daddiu64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value()); 2354 } 2355 } 2356 2357 void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off, 2358 FrameOffset handle_scope_offset, 2359 ManagedRegister mscratch, 2360 bool null_allowed) { 2361 Mips64ManagedRegister scratch = mscratch.AsMips64(); 2362 CHECK(scratch.IsGpuRegister()) << scratch; 2363 if (null_allowed) { 2364 Mips64Label null_arg; 2365 LoadFromOffset(kLoadUnsignedWord, scratch.AsGpuRegister(), SP, 2366 handle_scope_offset.Int32Value()); 2367 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 2368 // the address in the handle scope holding the reference. 2369 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset) 2370 Beqzc(scratch.AsGpuRegister(), &null_arg); 2371 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value()); 2372 Bind(&null_arg); 2373 } else { 2374 Daddiu64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value()); 2375 } 2376 StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value()); 2377 } 2378 2379 // Given a handle scope entry, load the associated reference. 2380 void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg, 2381 ManagedRegister min_reg) { 2382 Mips64ManagedRegister out_reg = mout_reg.AsMips64(); 2383 Mips64ManagedRegister in_reg = min_reg.AsMips64(); 2384 CHECK(out_reg.IsGpuRegister()) << out_reg; 2385 CHECK(in_reg.IsGpuRegister()) << in_reg; 2386 Mips64Label null_arg; 2387 if (!out_reg.Equals(in_reg)) { 2388 LoadConst32(out_reg.AsGpuRegister(), 0); 2389 } 2390 Beqzc(in_reg.AsGpuRegister(), &null_arg); 2391 LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(), 2392 in_reg.AsGpuRegister(), 0); 2393 Bind(&null_arg); 2394 } 2395 2396 void Mips64Assembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED, 2397 bool could_be_null ATTRIBUTE_UNUSED) { 2398 // TODO: not validating references 2399 } 2400 2401 void Mips64Assembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED, 2402 bool could_be_null ATTRIBUTE_UNUSED) { 2403 // TODO: not validating references 2404 } 2405 2406 void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) { 2407 Mips64ManagedRegister base = mbase.AsMips64(); 2408 Mips64ManagedRegister scratch = mscratch.AsMips64(); 2409 CHECK(base.IsGpuRegister()) << base; 2410 CHECK(scratch.IsGpuRegister()) << scratch; 2411 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), 2412 base.AsGpuRegister(), offset.Int32Value()); 2413 Jalr(scratch.AsGpuRegister()); 2414 Nop(); 2415 // TODO: place reference map on call 2416 } 2417 2418 void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) { 2419 Mips64ManagedRegister scratch = mscratch.AsMips64(); 2420 CHECK(scratch.IsGpuRegister()) << scratch; 2421 // Call *(*(SP + base) + offset) 2422 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), 2423 SP, base.Int32Value()); 2424 LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), 2425 scratch.AsGpuRegister(), offset.Int32Value()); 2426 Jalr(scratch.AsGpuRegister()); 2427 Nop(); 2428 // TODO: place reference map on call 2429 } 2430 2431 void Mips64Assembler::CallFromThread64(ThreadOffset<kMips64DoublewordSize> offset ATTRIBUTE_UNUSED, 2432 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 2433 UNIMPLEMENTED(FATAL) << "No MIPS64 implementation"; 2434 } 2435 2436 void Mips64Assembler::GetCurrentThread(ManagedRegister tr) { 2437 Move(tr.AsMips64().AsGpuRegister(), S1); 2438 } 2439 2440 void Mips64Assembler::GetCurrentThread(FrameOffset offset, 2441 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 2442 StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value()); 2443 } 2444 2445 void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) { 2446 Mips64ManagedRegister scratch = mscratch.AsMips64(); 2447 exception_blocks_.emplace_back(scratch, stack_adjust); 2448 LoadFromOffset(kLoadDoubleword, 2449 scratch.AsGpuRegister(), 2450 S1, 2451 Thread::ExceptionOffset<kMips64DoublewordSize>().Int32Value()); 2452 Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry()); 2453 } 2454 2455 void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) { 2456 Bind(exception->Entry()); 2457 if (exception->stack_adjust_ != 0) { // Fix up the frame. 2458 DecreaseFrameSize(exception->stack_adjust_); 2459 } 2460 // Pass exception object as argument. 2461 // Don't care about preserving A0 as this call won't return. 2462 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>(); 2463 Move(A0, exception->scratch_.AsGpuRegister()); 2464 // Set up call to Thread::Current()->pDeliverException 2465 LoadFromOffset(kLoadDoubleword, 2466 T9, 2467 S1, 2468 QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pDeliverException).Int32Value()); 2469 Jr(T9); 2470 Nop(); 2471 2472 // Call never returns 2473 Break(); 2474 } 2475 2476 } // namespace mips64 2477 } // namespace art 2478