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 #ifndef ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_ 18 #define ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_ 19 20 #include <utility> 21 #include <vector> 22 23 #include "arch/mips/instruction_set_features_mips.h" 24 #include "base/macros.h" 25 #include "constants_mips.h" 26 #include "globals.h" 27 #include "managed_register_mips.h" 28 #include "offsets.h" 29 #include "utils/assembler.h" 30 #include "utils/label.h" 31 32 namespace art { 33 namespace mips { 34 35 static constexpr size_t kMipsWordSize = 4; 36 static constexpr size_t kMipsDoublewordSize = 8; 37 38 enum LoadOperandType { 39 kLoadSignedByte, 40 kLoadUnsignedByte, 41 kLoadSignedHalfword, 42 kLoadUnsignedHalfword, 43 kLoadWord, 44 kLoadDoubleword 45 }; 46 47 enum StoreOperandType { 48 kStoreByte, 49 kStoreHalfword, 50 kStoreWord, 51 kStoreDoubleword 52 }; 53 54 // Used to test the values returned by ClassS/ClassD. 55 enum FPClassMaskType { 56 kSignalingNaN = 0x001, 57 kQuietNaN = 0x002, 58 kNegativeInfinity = 0x004, 59 kNegativeNormal = 0x008, 60 kNegativeSubnormal = 0x010, 61 kNegativeZero = 0x020, 62 kPositiveInfinity = 0x040, 63 kPositiveNormal = 0x080, 64 kPositiveSubnormal = 0x100, 65 kPositiveZero = 0x200, 66 }; 67 68 class MipsLabel : public Label { 69 public: MipsLabel()70 MipsLabel() : prev_branch_id_plus_one_(0) {} 71 MipsLabel(MipsLabel && src)72 MipsLabel(MipsLabel&& src) 73 : Label(std::move(src)), prev_branch_id_plus_one_(src.prev_branch_id_plus_one_) {} 74 75 private: 76 uint32_t prev_branch_id_plus_one_; // To get distance from preceding branch, if any. 77 78 friend class MipsAssembler; 79 DISALLOW_COPY_AND_ASSIGN(MipsLabel); 80 }; 81 82 // Slowpath entered when Thread::Current()->_exception is non-null. 83 class MipsExceptionSlowPath { 84 public: MipsExceptionSlowPath(MipsManagedRegister scratch,size_t stack_adjust)85 explicit MipsExceptionSlowPath(MipsManagedRegister scratch, size_t stack_adjust) 86 : scratch_(scratch), stack_adjust_(stack_adjust) {} 87 MipsExceptionSlowPath(MipsExceptionSlowPath && src)88 MipsExceptionSlowPath(MipsExceptionSlowPath&& src) 89 : scratch_(src.scratch_), 90 stack_adjust_(src.stack_adjust_), 91 exception_entry_(std::move(src.exception_entry_)) {} 92 93 private: Entry()94 MipsLabel* Entry() { return &exception_entry_; } 95 const MipsManagedRegister scratch_; 96 const size_t stack_adjust_; 97 MipsLabel exception_entry_; 98 99 friend class MipsAssembler; 100 DISALLOW_COPY_AND_ASSIGN(MipsExceptionSlowPath); 101 }; 102 103 class MipsAssembler FINAL : public Assembler { 104 public: 105 explicit MipsAssembler(ArenaAllocator* arena, 106 const MipsInstructionSetFeatures* instruction_set_features = nullptr) Assembler(arena)107 : Assembler(arena), 108 overwriting_(false), 109 overwrite_location_(0), 110 last_position_adjustment_(0), 111 last_old_position_(0), 112 last_branch_id_(0), 113 isa_features_(instruction_set_features) { 114 cfi().DelayEmittingAdvancePCs(); 115 } 116 ~MipsAssembler()117 virtual ~MipsAssembler() { 118 for (auto& branch : branches_) { 119 CHECK(branch.IsResolved()); 120 } 121 } 122 123 // Emit Machine Instructions. 124 void Addu(Register rd, Register rs, Register rt); 125 void Addiu(Register rt, Register rs, uint16_t imm16); 126 void Subu(Register rd, Register rs, Register rt); 127 128 void MultR2(Register rs, Register rt); // R2 129 void MultuR2(Register rs, Register rt); // R2 130 void DivR2(Register rs, Register rt); // R2 131 void DivuR2(Register rs, Register rt); // R2 132 void MulR2(Register rd, Register rs, Register rt); // R2 133 void DivR2(Register rd, Register rs, Register rt); // R2 134 void ModR2(Register rd, Register rs, Register rt); // R2 135 void DivuR2(Register rd, Register rs, Register rt); // R2 136 void ModuR2(Register rd, Register rs, Register rt); // R2 137 void MulR6(Register rd, Register rs, Register rt); // R6 138 void MuhR6(Register rd, Register rs, Register rt); // R6 139 void MuhuR6(Register rd, Register rs, Register rt); // R6 140 void DivR6(Register rd, Register rs, Register rt); // R6 141 void ModR6(Register rd, Register rs, Register rt); // R6 142 void DivuR6(Register rd, Register rs, Register rt); // R6 143 void ModuR6(Register rd, Register rs, Register rt); // R6 144 145 void And(Register rd, Register rs, Register rt); 146 void Andi(Register rt, Register rs, uint16_t imm16); 147 void Or(Register rd, Register rs, Register rt); 148 void Ori(Register rt, Register rs, uint16_t imm16); 149 void Xor(Register rd, Register rs, Register rt); 150 void Xori(Register rt, Register rs, uint16_t imm16); 151 void Nor(Register rd, Register rs, Register rt); 152 153 void Movz(Register rd, Register rs, Register rt); // R2 154 void Movn(Register rd, Register rs, Register rt); // R2 155 void Seleqz(Register rd, Register rs, Register rt); // R6 156 void Selnez(Register rd, Register rs, Register rt); // R6 157 void ClzR6(Register rd, Register rs); 158 void ClzR2(Register rd, Register rs); 159 void CloR6(Register rd, Register rs); 160 void CloR2(Register rd, Register rs); 161 162 void Seb(Register rd, Register rt); // R2+ 163 void Seh(Register rd, Register rt); // R2+ 164 void Wsbh(Register rd, Register rt); // R2+ 165 void Bitswap(Register rd, Register rt); // R6 166 167 void Sll(Register rd, Register rt, int shamt); 168 void Srl(Register rd, Register rt, int shamt); 169 void Rotr(Register rd, Register rt, int shamt); // R2+ 170 void Sra(Register rd, Register rt, int shamt); 171 void Sllv(Register rd, Register rt, Register rs); 172 void Srlv(Register rd, Register rt, Register rs); 173 void Rotrv(Register rd, Register rt, Register rs); // R2+ 174 void Srav(Register rd, Register rt, Register rs); 175 void Ext(Register rd, Register rt, int pos, int size); // R2+ 176 void Ins(Register rd, Register rt, int pos, int size); // R2+ 177 178 void Lb(Register rt, Register rs, uint16_t imm16); 179 void Lh(Register rt, Register rs, uint16_t imm16); 180 void Lw(Register rt, Register rs, uint16_t imm16); 181 void Lwl(Register rt, Register rs, uint16_t imm16); 182 void Lwr(Register rt, Register rs, uint16_t imm16); 183 void Lbu(Register rt, Register rs, uint16_t imm16); 184 void Lhu(Register rt, Register rs, uint16_t imm16); 185 void Lui(Register rt, uint16_t imm16); 186 void Sync(uint32_t stype); 187 void Mfhi(Register rd); // R2 188 void Mflo(Register rd); // R2 189 190 void Sb(Register rt, Register rs, uint16_t imm16); 191 void Sh(Register rt, Register rs, uint16_t imm16); 192 void Sw(Register rt, Register rs, uint16_t imm16); 193 void Swl(Register rt, Register rs, uint16_t imm16); 194 void Swr(Register rt, Register rs, uint16_t imm16); 195 196 void LlR2(Register rt, Register base, int16_t imm16 = 0); 197 void ScR2(Register rt, Register base, int16_t imm16 = 0); 198 void LlR6(Register rt, Register base, int16_t imm9 = 0); 199 void ScR6(Register rt, Register base, int16_t imm9 = 0); 200 201 void Slt(Register rd, Register rs, Register rt); 202 void Sltu(Register rd, Register rs, Register rt); 203 void Slti(Register rt, Register rs, uint16_t imm16); 204 void Sltiu(Register rt, Register rs, uint16_t imm16); 205 206 void B(uint16_t imm16); 207 void Beq(Register rs, Register rt, uint16_t imm16); 208 void Bne(Register rs, Register rt, uint16_t imm16); 209 void Beqz(Register rt, uint16_t imm16); 210 void Bnez(Register rt, uint16_t imm16); 211 void Bltz(Register rt, uint16_t imm16); 212 void Bgez(Register rt, uint16_t imm16); 213 void Blez(Register rt, uint16_t imm16); 214 void Bgtz(Register rt, uint16_t imm16); 215 void Bc1f(uint16_t imm16); // R2 216 void Bc1f(int cc, uint16_t imm16); // R2 217 void Bc1t(uint16_t imm16); // R2 218 void Bc1t(int cc, uint16_t imm16); // R2 219 void J(uint32_t addr26); 220 void Jal(uint32_t addr26); 221 void Jalr(Register rd, Register rs); 222 void Jalr(Register rs); 223 void Jr(Register rs); 224 void Nal(); 225 void Auipc(Register rs, uint16_t imm16); // R6 226 void Addiupc(Register rs, uint32_t imm19); // R6 227 void Bc(uint32_t imm26); // R6 228 void Jic(Register rt, uint16_t imm16); // R6 229 void Jialc(Register rt, uint16_t imm16); // R6 230 void Bltc(Register rs, Register rt, uint16_t imm16); // R6 231 void Bltzc(Register rt, uint16_t imm16); // R6 232 void Bgtzc(Register rt, uint16_t imm16); // R6 233 void Bgec(Register rs, Register rt, uint16_t imm16); // R6 234 void Bgezc(Register rt, uint16_t imm16); // R6 235 void Blezc(Register rt, uint16_t imm16); // R6 236 void Bltuc(Register rs, Register rt, uint16_t imm16); // R6 237 void Bgeuc(Register rs, Register rt, uint16_t imm16); // R6 238 void Beqc(Register rs, Register rt, uint16_t imm16); // R6 239 void Bnec(Register rs, Register rt, uint16_t imm16); // R6 240 void Beqzc(Register rs, uint32_t imm21); // R6 241 void Bnezc(Register rs, uint32_t imm21); // R6 242 void Bc1eqz(FRegister ft, uint16_t imm16); // R6 243 void Bc1nez(FRegister ft, uint16_t imm16); // R6 244 245 void AddS(FRegister fd, FRegister fs, FRegister ft); 246 void SubS(FRegister fd, FRegister fs, FRegister ft); 247 void MulS(FRegister fd, FRegister fs, FRegister ft); 248 void DivS(FRegister fd, FRegister fs, FRegister ft); 249 void AddD(FRegister fd, FRegister fs, FRegister ft); 250 void SubD(FRegister fd, FRegister fs, FRegister ft); 251 void MulD(FRegister fd, FRegister fs, FRegister ft); 252 void DivD(FRegister fd, FRegister fs, FRegister ft); 253 void SqrtS(FRegister fd, FRegister fs); 254 void SqrtD(FRegister fd, FRegister fs); 255 void AbsS(FRegister fd, FRegister fs); 256 void AbsD(FRegister fd, FRegister fs); 257 void MovS(FRegister fd, FRegister fs); 258 void MovD(FRegister fd, FRegister fs); 259 void NegS(FRegister fd, FRegister fs); 260 void NegD(FRegister fd, FRegister fs); 261 262 void CunS(FRegister fs, FRegister ft); // R2 263 void CunS(int cc, FRegister fs, FRegister ft); // R2 264 void CeqS(FRegister fs, FRegister ft); // R2 265 void CeqS(int cc, FRegister fs, FRegister ft); // R2 266 void CueqS(FRegister fs, FRegister ft); // R2 267 void CueqS(int cc, FRegister fs, FRegister ft); // R2 268 void ColtS(FRegister fs, FRegister ft); // R2 269 void ColtS(int cc, FRegister fs, FRegister ft); // R2 270 void CultS(FRegister fs, FRegister ft); // R2 271 void CultS(int cc, FRegister fs, FRegister ft); // R2 272 void ColeS(FRegister fs, FRegister ft); // R2 273 void ColeS(int cc, FRegister fs, FRegister ft); // R2 274 void CuleS(FRegister fs, FRegister ft); // R2 275 void CuleS(int cc, FRegister fs, FRegister ft); // R2 276 void CunD(FRegister fs, FRegister ft); // R2 277 void CunD(int cc, FRegister fs, FRegister ft); // R2 278 void CeqD(FRegister fs, FRegister ft); // R2 279 void CeqD(int cc, FRegister fs, FRegister ft); // R2 280 void CueqD(FRegister fs, FRegister ft); // R2 281 void CueqD(int cc, FRegister fs, FRegister ft); // R2 282 void ColtD(FRegister fs, FRegister ft); // R2 283 void ColtD(int cc, FRegister fs, FRegister ft); // R2 284 void CultD(FRegister fs, FRegister ft); // R2 285 void CultD(int cc, FRegister fs, FRegister ft); // R2 286 void ColeD(FRegister fs, FRegister ft); // R2 287 void ColeD(int cc, FRegister fs, FRegister ft); // R2 288 void CuleD(FRegister fs, FRegister ft); // R2 289 void CuleD(int cc, FRegister fs, FRegister ft); // R2 290 void CmpUnS(FRegister fd, FRegister fs, FRegister ft); // R6 291 void CmpEqS(FRegister fd, FRegister fs, FRegister ft); // R6 292 void CmpUeqS(FRegister fd, FRegister fs, FRegister ft); // R6 293 void CmpLtS(FRegister fd, FRegister fs, FRegister ft); // R6 294 void CmpUltS(FRegister fd, FRegister fs, FRegister ft); // R6 295 void CmpLeS(FRegister fd, FRegister fs, FRegister ft); // R6 296 void CmpUleS(FRegister fd, FRegister fs, FRegister ft); // R6 297 void CmpOrS(FRegister fd, FRegister fs, FRegister ft); // R6 298 void CmpUneS(FRegister fd, FRegister fs, FRegister ft); // R6 299 void CmpNeS(FRegister fd, FRegister fs, FRegister ft); // R6 300 void CmpUnD(FRegister fd, FRegister fs, FRegister ft); // R6 301 void CmpEqD(FRegister fd, FRegister fs, FRegister ft); // R6 302 void CmpUeqD(FRegister fd, FRegister fs, FRegister ft); // R6 303 void CmpLtD(FRegister fd, FRegister fs, FRegister ft); // R6 304 void CmpUltD(FRegister fd, FRegister fs, FRegister ft); // R6 305 void CmpLeD(FRegister fd, FRegister fs, FRegister ft); // R6 306 void CmpUleD(FRegister fd, FRegister fs, FRegister ft); // R6 307 void CmpOrD(FRegister fd, FRegister fs, FRegister ft); // R6 308 void CmpUneD(FRegister fd, FRegister fs, FRegister ft); // R6 309 void CmpNeD(FRegister fd, FRegister fs, FRegister ft); // R6 310 void Movf(Register rd, Register rs, int cc = 0); // R2 311 void Movt(Register rd, Register rs, int cc = 0); // R2 312 void MovfS(FRegister fd, FRegister fs, int cc = 0); // R2 313 void MovfD(FRegister fd, FRegister fs, int cc = 0); // R2 314 void MovtS(FRegister fd, FRegister fs, int cc = 0); // R2 315 void MovtD(FRegister fd, FRegister fs, int cc = 0); // R2 316 void SelS(FRegister fd, FRegister fs, FRegister ft); // R6 317 void SelD(FRegister fd, FRegister fs, FRegister ft); // R6 318 void ClassS(FRegister fd, FRegister fs); // R6 319 void ClassD(FRegister fd, FRegister fs); // R6 320 void MinS(FRegister fd, FRegister fs, FRegister ft); // R6 321 void MinD(FRegister fd, FRegister fs, FRegister ft); // R6 322 void MaxS(FRegister fd, FRegister fs, FRegister ft); // R6 323 void MaxD(FRegister fd, FRegister fs, FRegister ft); // R6 324 325 void TruncLS(FRegister fd, FRegister fs); // R2+, FR=1 326 void TruncLD(FRegister fd, FRegister fs); // R2+, FR=1 327 void TruncWS(FRegister fd, FRegister fs); 328 void TruncWD(FRegister fd, FRegister fs); 329 void Cvtsw(FRegister fd, FRegister fs); 330 void Cvtdw(FRegister fd, FRegister fs); 331 void Cvtsd(FRegister fd, FRegister fs); 332 void Cvtds(FRegister fd, FRegister fs); 333 void Cvtsl(FRegister fd, FRegister fs); // R2+, FR=1 334 void Cvtdl(FRegister fd, FRegister fs); // R2+, FR=1 335 void FloorWS(FRegister fd, FRegister fs); 336 void FloorWD(FRegister fd, FRegister fs); 337 338 void Mfc1(Register rt, FRegister fs); 339 void Mtc1(Register rt, FRegister fs); 340 void Mfhc1(Register rt, FRegister fs); 341 void Mthc1(Register rt, FRegister fs); 342 void MoveFromFpuHigh(Register rt, FRegister fs); 343 void MoveToFpuHigh(Register rt, FRegister fs); 344 void Lwc1(FRegister ft, Register rs, uint16_t imm16); 345 void Ldc1(FRegister ft, Register rs, uint16_t imm16); 346 void Swc1(FRegister ft, Register rs, uint16_t imm16); 347 void Sdc1(FRegister ft, Register rs, uint16_t imm16); 348 349 void Break(); 350 void Nop(); 351 void Move(Register rd, Register rs); 352 void Clear(Register rd); 353 void Not(Register rd, Register rs); 354 355 // Higher level composite instructions. 356 void LoadConst32(Register rd, int32_t value); 357 void LoadConst64(Register reg_hi, Register reg_lo, int64_t value); 358 void LoadDConst64(FRegister rd, int64_t value, Register temp); 359 void LoadSConst32(FRegister r, int32_t value, Register temp); 360 void StoreConst32ToOffset(int32_t value, Register base, int32_t offset, Register temp); 361 void StoreConst64ToOffset(int64_t value, Register base, int32_t offset, Register temp); 362 void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT); 363 364 // These will generate R2 branches or R6 branches as appropriate. 365 void Bind(MipsLabel* label); 366 void B(MipsLabel* label); 367 void Jalr(MipsLabel* label, Register indirect_reg); 368 void Beq(Register rs, Register rt, MipsLabel* label); 369 void Bne(Register rs, Register rt, MipsLabel* label); 370 void Beqz(Register rt, MipsLabel* label); 371 void Bnez(Register rt, MipsLabel* label); 372 void Bltz(Register rt, MipsLabel* label); 373 void Bgez(Register rt, MipsLabel* label); 374 void Blez(Register rt, MipsLabel* label); 375 void Bgtz(Register rt, MipsLabel* label); 376 void Blt(Register rs, Register rt, MipsLabel* label); 377 void Bge(Register rs, Register rt, MipsLabel* label); 378 void Bltu(Register rs, Register rt, MipsLabel* label); 379 void Bgeu(Register rs, Register rt, MipsLabel* label); 380 void Bc1f(MipsLabel* label); // R2 381 void Bc1f(int cc, MipsLabel* label); // R2 382 void Bc1t(MipsLabel* label); // R2 383 void Bc1t(int cc, MipsLabel* label); // R2 384 void Bc1eqz(FRegister ft, MipsLabel* label); // R6 385 void Bc1nez(FRegister ft, MipsLabel* label); // R6 386 387 void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size); 388 void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset); 389 void LoadSFromOffset(FRegister reg, Register base, int32_t offset); 390 void LoadDFromOffset(FRegister reg, Register base, int32_t offset); 391 void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset); 392 void StoreSToOffset(FRegister reg, Register base, int32_t offset); 393 void StoreDToOffset(FRegister reg, Register base, int32_t offset); 394 395 // Emit data (e.g. encoded instruction or immediate) to the instruction stream. 396 void Emit(uint32_t value); 397 398 // Push/pop composite routines. 399 void Push(Register rs); 400 void Pop(Register rd); 401 void PopAndReturn(Register rd, Register rt); 402 Bind(Label * label)403 void Bind(Label* label) OVERRIDE { 404 Bind(down_cast<MipsLabel*>(label)); 405 } Jump(Label * label ATTRIBUTE_UNUSED)406 void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE { 407 UNIMPLEMENTED(FATAL) << "Do not use Jump for MIPS"; 408 } 409 410 // 411 // Overridden common assembler high-level functionality. 412 // 413 414 // Emit code that will create an activation on the stack. 415 void BuildFrame(size_t frame_size, 416 ManagedRegister method_reg, 417 const std::vector<ManagedRegister>& callee_save_regs, 418 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE; 419 420 // Emit code that will remove an activation from the stack. 421 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs) 422 OVERRIDE; 423 424 void IncreaseFrameSize(size_t adjust) OVERRIDE; 425 void DecreaseFrameSize(size_t adjust) OVERRIDE; 426 427 // Store routines. 428 void Store(FrameOffset offs, ManagedRegister msrc, size_t size) OVERRIDE; 429 void StoreRef(FrameOffset dest, ManagedRegister msrc) OVERRIDE; 430 void StoreRawPtr(FrameOffset dest, ManagedRegister msrc) OVERRIDE; 431 432 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE; 433 434 void StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest, 435 uint32_t imm, 436 ManagedRegister mscratch) OVERRIDE; 437 438 void StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs, 439 FrameOffset fr_offs, 440 ManagedRegister mscratch) OVERRIDE; 441 442 void StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) OVERRIDE; 443 444 void StoreSpanning(FrameOffset dest, 445 ManagedRegister msrc, 446 FrameOffset in_off, 447 ManagedRegister mscratch) OVERRIDE; 448 449 // Load routines. 450 void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE; 451 452 void LoadFromThread32(ManagedRegister mdest, 453 ThreadOffset<kMipsWordSize> src, 454 size_t size) OVERRIDE; 455 456 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE; 457 458 void LoadRef(ManagedRegister mdest, 459 ManagedRegister base, 460 MemberOffset offs, 461 bool unpoison_reference) OVERRIDE; 462 463 void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE; 464 465 void LoadRawPtrFromThread32(ManagedRegister mdest, ThreadOffset<kMipsWordSize> offs) OVERRIDE; 466 467 // Copying routines. 468 void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE; 469 470 void CopyRawPtrFromThread32(FrameOffset fr_offs, 471 ThreadOffset<kMipsWordSize> thr_offs, 472 ManagedRegister mscratch) OVERRIDE; 473 474 void CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs, 475 FrameOffset fr_offs, 476 ManagedRegister mscratch) OVERRIDE; 477 478 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE; 479 480 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE; 481 482 void Copy(FrameOffset dest, 483 ManagedRegister src_base, 484 Offset src_offset, 485 ManagedRegister mscratch, 486 size_t size) OVERRIDE; 487 488 void Copy(ManagedRegister dest_base, 489 Offset dest_offset, 490 FrameOffset src, 491 ManagedRegister mscratch, 492 size_t size) OVERRIDE; 493 494 void Copy(FrameOffset dest, 495 FrameOffset src_base, 496 Offset src_offset, 497 ManagedRegister mscratch, 498 size_t size) OVERRIDE; 499 500 void Copy(ManagedRegister dest, 501 Offset dest_offset, 502 ManagedRegister src, 503 Offset src_offset, 504 ManagedRegister mscratch, 505 size_t size) OVERRIDE; 506 507 void Copy(FrameOffset dest, 508 Offset dest_offset, 509 FrameOffset src, 510 Offset src_offset, 511 ManagedRegister mscratch, 512 size_t size) OVERRIDE; 513 514 void MemoryBarrier(ManagedRegister) OVERRIDE; 515 516 // Sign extension. 517 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE; 518 519 // Zero extension. 520 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE; 521 522 // Exploit fast access in managed code to Thread::Current(). 523 void GetCurrentThread(ManagedRegister tr) OVERRIDE; 524 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) OVERRIDE; 525 526 // Set up out_reg to hold a Object** into the handle scope, or to be null if the 527 // value is null and null_allowed. in_reg holds a possibly stale reference 528 // that can be used to avoid loading the handle scope entry to see if the value is 529 // null. 530 void CreateHandleScopeEntry(ManagedRegister out_reg, 531 FrameOffset handlescope_offset, 532 ManagedRegister in_reg, 533 bool null_allowed) OVERRIDE; 534 535 // Set up out_off to hold a Object** into the handle scope, or to be null if the 536 // value is null and null_allowed. 537 void CreateHandleScopeEntry(FrameOffset out_off, 538 FrameOffset handlescope_offset, 539 ManagedRegister mscratch, 540 bool null_allowed) OVERRIDE; 541 542 // src holds a handle scope entry (Object**) load this into dst. 543 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE; 544 545 // Heap::VerifyObject on src. In some cases (such as a reference to this) we 546 // know that src may not be null. 547 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE; 548 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE; 549 550 // Call to address held at [base+offset]. 551 void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE; 552 void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE; 553 void CallFromThread32(ThreadOffset<kMipsWordSize> offset, ManagedRegister mscratch) OVERRIDE; 554 555 // Generate code to check if Thread::Current()->exception_ is non-null 556 // and branch to a ExceptionSlowPath if it is. 557 void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) OVERRIDE; 558 559 // Emit slow paths queued during assembly and promote short branches to long if needed. 560 void FinalizeCode() OVERRIDE; 561 562 // Emit branches and finalize all instructions. 563 void FinalizeInstructions(const MemoryRegion& region); 564 565 // Returns the (always-)current location of a label (can be used in class CodeGeneratorMIPS, 566 // must be used instead of MipsLabel::GetPosition()). 567 uint32_t GetLabelLocation(MipsLabel* label) const; 568 569 // Get the final position of a label after local fixup based on the old position 570 // recorded before FinalizeCode(). 571 uint32_t GetAdjustedPosition(uint32_t old_position); 572 573 enum BranchCondition { 574 kCondLT, 575 kCondGE, 576 kCondLE, 577 kCondGT, 578 kCondLTZ, 579 kCondGEZ, 580 kCondLEZ, 581 kCondGTZ, 582 kCondEQ, 583 kCondNE, 584 kCondEQZ, 585 kCondNEZ, 586 kCondLTU, 587 kCondGEU, 588 kCondF, // Floating-point predicate false. 589 kCondT, // Floating-point predicate true. 590 kUncond, 591 }; 592 friend std::ostream& operator<<(std::ostream& os, const BranchCondition& rhs); 593 594 private: 595 class Branch { 596 public: 597 enum Type { 598 // R2 short branches. 599 kUncondBranch, 600 kCondBranch, 601 kCall, 602 // R2 long branches. 603 kLongUncondBranch, 604 kLongCondBranch, 605 kLongCall, 606 // R6 short branches. 607 kR6UncondBranch, 608 kR6CondBranch, 609 kR6Call, 610 // R6 long branches. 611 kR6LongUncondBranch, 612 kR6LongCondBranch, 613 kR6LongCall, 614 }; 615 // Bit sizes of offsets defined as enums to minimize chance of typos. 616 enum OffsetBits { 617 kOffset16 = 16, 618 kOffset18 = 18, 619 kOffset21 = 21, 620 kOffset23 = 23, 621 kOffset28 = 28, 622 kOffset32 = 32, 623 }; 624 625 static constexpr uint32_t kUnresolved = 0xffffffff; // Unresolved target_ 626 static constexpr int32_t kMaxBranchLength = 32; 627 static constexpr int32_t kMaxBranchSize = kMaxBranchLength * sizeof(uint32_t); 628 629 struct BranchInfo { 630 // Branch length as a number of 4-byte-long instructions. 631 uint32_t length; 632 // Ordinal number (0-based) of the first (or the only) instruction that contains the branch's 633 // PC-relative offset (or its most significant 16-bit half, which goes first). 634 uint32_t instr_offset; 635 // Different MIPS instructions with PC-relative offsets apply said offsets to slightly 636 // different origins, e.g. to PC or PC+4. Encode the origin distance (as a number of 4-byte 637 // instructions) from the instruction containing the offset. 638 uint32_t pc_org; 639 // How large (in bits) a PC-relative offset can be for a given type of branch (kR6CondBranch 640 // is an exception: use kOffset23 for beqzc/bnezc). 641 OffsetBits offset_size; 642 // Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift 643 // count. 644 int offset_shift; 645 }; 646 static const BranchInfo branch_info_[/* Type */]; 647 648 // Unconditional branch. 649 Branch(bool is_r6, uint32_t location, uint32_t target); 650 // Conditional branch. 651 Branch(bool is_r6, 652 uint32_t location, 653 uint32_t target, 654 BranchCondition condition, 655 Register lhs_reg, 656 Register rhs_reg = ZERO); 657 // Call (branch and link) that stores the target address in a given register (i.e. T9). 658 Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg); 659 660 // Some conditional branches with lhs = rhs are effectively NOPs, while some 661 // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs. 662 // So, we need a way to identify such branches in order to emit no instructions for them 663 // or change them to unconditional. 664 static bool IsNop(BranchCondition condition, Register lhs, Register rhs); 665 static bool IsUncond(BranchCondition condition, Register lhs, Register rhs); 666 667 static BranchCondition OppositeCondition(BranchCondition cond); 668 669 Type GetType() const; 670 BranchCondition GetCondition() const; 671 Register GetLeftRegister() const; 672 Register GetRightRegister() const; 673 uint32_t GetTarget() const; 674 uint32_t GetLocation() const; 675 uint32_t GetOldLocation() const; 676 uint32_t GetLength() const; 677 uint32_t GetOldLength() const; 678 uint32_t GetSize() const; 679 uint32_t GetOldSize() const; 680 uint32_t GetEndLocation() const; 681 uint32_t GetOldEndLocation() const; 682 bool IsLong() const; 683 bool IsResolved() const; 684 685 // Returns the bit size of the signed offset that the branch instruction can handle. 686 OffsetBits GetOffsetSize() const; 687 688 // Calculates the distance between two byte locations in the assembler buffer and 689 // returns the number of bits needed to represent the distance as a signed integer. 690 // 691 // Branch instructions have signed offsets of 16, 19 (addiupc), 21 (beqzc/bnezc), 692 // and 26 (bc) bits, which are additionally shifted left 2 positions at run time. 693 // 694 // Composite branches (made of several instructions) with longer reach have 32-bit 695 // offsets encoded as 2 16-bit "halves" in two instructions (high half goes first). 696 // The composite branches cover the range of PC + +/-2GB on MIPS32 CPUs. However, 697 // the range is not end-to-end on MIPS64 (unless addresses are forced to zero- or 698 // sign-extend from 32 to 64 bits by the appropriate CPU configuration). 699 // Consider the following implementation of a long unconditional branch, for 700 // example: 701 // 702 // auipc at, offset_31_16 // at = pc + sign_extend(offset_31_16) << 16 703 // jic at, offset_15_0 // pc = at + sign_extend(offset_15_0) 704 // 705 // Both of the above instructions take 16-bit signed offsets as immediate operands. 706 // When bit 15 of offset_15_0 is 1, it effectively causes subtraction of 0x10000 707 // due to sign extension. This must be compensated for by incrementing offset_31_16 708 // by 1. offset_31_16 can only be incremented by 1 if it's not 0x7FFF. If it is 709 // 0x7FFF, adding 1 will overflow the positive offset into the negative range. 710 // Therefore, the long branch range is something like from PC - 0x80000000 to 711 // PC + 0x7FFF7FFF, IOW, shorter by 32KB on one side. 712 // 713 // The returned values are therefore: 18, 21, 23, 28 and 32. There's also a special 714 // case with the addiu instruction and a 16 bit offset. 715 static OffsetBits GetOffsetSizeNeeded(uint32_t location, uint32_t target); 716 717 // Resolve a branch when the target is known. 718 void Resolve(uint32_t target); 719 720 // Relocate a branch by a given delta if needed due to expansion of this or another 721 // branch at a given location by this delta (just changes location_ and target_). 722 void Relocate(uint32_t expand_location, uint32_t delta); 723 724 // If the branch is short, changes its type to long. 725 void PromoteToLong(); 726 727 // If necessary, updates the type by promoting a short branch to a long branch 728 // based on the branch location and target. Returns the amount (in bytes) by 729 // which the branch size has increased. 730 // max_short_distance caps the maximum distance between location_ and target_ 731 // that is allowed for short branches. This is for debugging/testing purposes. 732 // max_short_distance = 0 forces all short branches to become long. 733 // Use the implicit default argument when not debugging/testing. 734 uint32_t PromoteIfNeeded(uint32_t max_short_distance = std::numeric_limits<uint32_t>::max()); 735 736 // Returns the location of the instruction(s) containing the offset. 737 uint32_t GetOffsetLocation() const; 738 739 // Calculates and returns the offset ready for encoding in the branch instruction(s). 740 uint32_t GetOffset() const; 741 742 private: 743 // Completes branch construction by determining and recording its type. 744 void InitializeType(bool is_call, bool is_r6); 745 // Helper for the above. 746 void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type); 747 748 uint32_t old_location_; // Offset into assembler buffer in bytes. 749 uint32_t location_; // Offset into assembler buffer in bytes. 750 uint32_t target_; // Offset into assembler buffer in bytes. 751 752 uint32_t lhs_reg_; // Left-hand side register in conditional branches or 753 // indirect call register. 754 uint32_t rhs_reg_; // Right-hand side register in conditional branches. 755 BranchCondition condition_; // Condition for conditional branches. 756 757 Type type_; // Current type of the branch. 758 Type old_type_; // Initial type of the branch. 759 }; 760 friend std::ostream& operator<<(std::ostream& os, const Branch::Type& rhs); 761 friend std::ostream& operator<<(std::ostream& os, const Branch::OffsetBits& rhs); 762 763 void EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct); 764 void EmitI(int opcode, Register rs, Register rt, uint16_t imm); 765 void EmitI21(int opcode, Register rs, uint32_t imm21); 766 void EmitI26(int opcode, uint32_t imm26); 767 void EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct); 768 void EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm); 769 void EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16); 770 void EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21); 771 772 void Buncond(MipsLabel* label); 773 void Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs = ZERO); 774 void Call(MipsLabel* label, Register indirect_reg); 775 void FinalizeLabeledBranch(MipsLabel* label); 776 777 Branch* GetBranch(uint32_t branch_id); 778 const Branch* GetBranch(uint32_t branch_id) const; 779 780 void PromoteBranches(); 781 void EmitBranch(Branch* branch); 782 void EmitBranches(); 783 void PatchCFI(size_t number_of_delayed_adjust_pcs); 784 785 // Emits exception block. 786 void EmitExceptionPoll(MipsExceptionSlowPath* exception); 787 IsR6()788 bool IsR6() const { 789 if (isa_features_ != nullptr) { 790 return isa_features_->IsR6(); 791 } else { 792 return false; 793 } 794 } 795 Is32BitFPU()796 bool Is32BitFPU() const { 797 if (isa_features_ != nullptr) { 798 return isa_features_->Is32BitFloatingPoint(); 799 } else { 800 return true; 801 } 802 } 803 804 // List of exception blocks to generate at the end of the code cache. 805 std::vector<MipsExceptionSlowPath> exception_blocks_; 806 807 std::vector<Branch> branches_; 808 809 // Whether appending instructions at the end of the buffer or overwriting the existing ones. 810 bool overwriting_; 811 // The current overwrite location. 812 uint32_t overwrite_location_; 813 814 // Data for AdjustedPosition(), see the description there. 815 uint32_t last_position_adjustment_; 816 uint32_t last_old_position_; 817 uint32_t last_branch_id_; 818 819 const MipsInstructionSetFeatures* isa_features_; 820 821 DISALLOW_COPY_AND_ASSIGN(MipsAssembler); 822 }; 823 824 } // namespace mips 825 } // namespace art 826 827 #endif // ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_ 828