1 /* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef COMPILER_OPTIMIZER_CODEGEN_ENCODE_H 17 #define COMPILER_OPTIMIZER_CODEGEN_ENCODE_H 18 19 /* 20 Hi-level interface for encoding 21 Wrapper for specialize concrete used encoding 22 23 Responsible for 24 Primitive (not-branch) instruction encoding 25 Memory-instructions encoding 26 Immediate and Memory operands 27 */ 28 29 #include <variant> 30 31 #include "operands.h" 32 #include "registers_description.h" 33 #include "utils/cframe_layout.h" 34 #include "target_info.h" 35 36 namespace panda::compiler { 37 class Encoder; 38 class CompilerOptions; 39 class RelocationInfo; 40 41 namespace memory_order { 42 enum Order { ACQUIRE, RELEASE, FULL }; 43 } // namespace memory_order 44 45 class LabelHolder { 46 public: 47 using LabelId = uintptr_t; 48 static constexpr LabelId INVALID_LABEL = static_cast<uintptr_t>(-1); 49 LabelHolder(Encoder * enc)50 explicit LabelHolder(Encoder *enc) : enc_ {enc} {}; 51 virtual ~LabelHolder() = default; 52 53 // NOTE (igorban) : hide all this methods in CallConv 54 virtual void CreateLabels(LabelId size) = 0; 55 virtual LabelId CreateLabel() = 0; 56 virtual LabelId Size() = 0; 57 GetEncoder()58 Encoder *GetEncoder() const 59 { 60 return enc_; 61 } 62 63 NO_COPY_SEMANTIC(LabelHolder); 64 NO_MOVE_SEMANTIC(LabelHolder); 65 66 protected: 67 virtual void BindLabel(LabelId) = 0; 68 69 private: 70 Encoder *enc_ {nullptr}; 71 friend Encoder; 72 }; 73 74 class Encoder { 75 public: 76 // Main constructor Encoder(ArenaAllocator * aa,Arch arch)77 explicit Encoder(ArenaAllocator *aa, Arch arch) : Encoder(aa, arch, false) {} Encoder(ArenaAllocator * aa,Arch arch,bool jsNumberCast)78 Encoder(ArenaAllocator *aa, Arch arch, bool jsNumberCast) 79 : allocator_(aa), frameLayout_(arch, 0), target_(arch), jsNumberCast_(jsNumberCast) 80 { 81 } 82 virtual ~Encoder() = default; 83 GetAllocator()84 ArenaAllocator *GetAllocator() const 85 { 86 return allocator_; 87 } 88 IsLabelValid(LabelHolder::LabelId label)89 bool IsLabelValid(LabelHolder::LabelId label) 90 { 91 return label != LabelHolder::INVALID_LABEL; 92 } 93 GetTarget()94 Target GetTarget() const 95 { 96 return target_; 97 } 98 GetArch()99 Arch GetArch() const 100 { 101 return GetTarget().GetArch(); 102 } 103 IsJsNumberCast()104 bool IsJsNumberCast() const 105 { 106 return jsNumberCast_; 107 } 108 SetIsJsNumberCast(bool v)109 void SetIsJsNumberCast(bool v) 110 { 111 jsNumberCast_ = v; 112 } 113 114 /// Print instruction and return next pc DisasmInstr(std::ostream & stream,size_t pc,ssize_t codeOffset)115 virtual size_t DisasmInstr([[maybe_unused]] std::ostream &stream, [[maybe_unused]] size_t pc, 116 [[maybe_unused]] ssize_t codeOffset) const 117 { 118 return 0; 119 } 120 BufferData()121 virtual void *BufferData() const 122 { 123 return nullptr; 124 } 125 126 /// Size of used buffer BufferSize()127 virtual size_t BufferSize() const 128 { 129 return 0; 130 } 131 132 // Default behaviour - do nothing InitMasm()133 virtual bool InitMasm() 134 { 135 return true; 136 } 137 SetMaxAllocatedBytes(size_t size)138 virtual void SetMaxAllocatedBytes([[maybe_unused]] size_t size) {}; 139 140 // Define default math operations 141 // Encode (dst, src) 142 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 143 #define UNARY_OPERATION(opc) \ 144 virtual void Encode##opc(Reg, Reg) \ 145 { \ 146 SetFalseResult(); \ 147 } 148 149 // Encode (dst, src0, src1) 150 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 151 #define BINARY_OPERATION(opc) \ 152 virtual void Encode##opc(Reg, Reg, Reg) \ 153 { \ 154 SetFalseResult(); \ 155 } \ 156 virtual void Encode##opc(Reg, Reg, Imm) \ 157 { \ 158 SetFalseResult(); \ 159 } 160 161 // Encode (dst, src0, src1) 162 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 163 #define BINARY_SHIFTED_REGISTER_OPERATION(opc) \ 164 virtual void Encode##opc(Reg, Reg, Shift) \ 165 { \ 166 SetFalseResult(); \ 167 } 168 169 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 170 #define INST_DEF(OPCODE, TYPE) TYPE(OPCODE) 171 172 ENCODE_MATH_LIST(INST_DEF) 173 ENCODE_INST_WITH_SHIFTED_OPERAND(INST_DEF)174 ENCODE_INST_WITH_SHIFTED_OPERAND(INST_DEF) 175 176 #undef UNARY_OPERATION 177 #undef BINARY_OPERATION 178 #undef BINARY_SHIFTED_REGISTER_OPERATION 179 #undef INST_DEF 180 181 virtual void EncodeNop() 182 { 183 SetFalseResult(); 184 } 185 EncodeAddOverflow(compiler::LabelHolder::LabelId id,Reg dst,Reg src0,Reg src1,Condition cc)186 virtual void EncodeAddOverflow([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] Reg dst, 187 [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, [[maybe_unused]] Condition cc) 188 { 189 SetFalseResult(); 190 } 191 EncodeSubOverflow(compiler::LabelHolder::LabelId id,Reg dst,Reg src0,Reg src1,Condition cc)192 virtual void EncodeSubOverflow([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] Reg dst, 193 [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, [[maybe_unused]] Condition cc) 194 { 195 SetFalseResult(); 196 } 197 EncodeMulOverflow(compiler::LabelHolder::LabelId id,Reg dst,Reg src0,Reg src1,Condition cc)198 virtual void EncodeMulOverflow([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] Reg dst, 199 [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, [[maybe_unused]] Condition cc) 200 { 201 SetFalseResult(); 202 } 203 EncodeNegOverflowAndZero(compiler::LabelHolder::LabelId id,Reg dst,Reg src)204 virtual void EncodeNegOverflowAndZero([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] Reg dst, 205 [[maybe_unused]] Reg src) 206 { 207 SetFalseResult(); 208 } 209 EncodeFastPathDynamicCast(Reg dst,Reg src,LabelHolder::LabelId slow)210 virtual void EncodeFastPathDynamicCast([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src, 211 [[maybe_unused]] LabelHolder::LabelId slow) 212 { 213 SetFalseResult(); 214 } 215 EncodeCast(Reg dst,bool dstSigned,Reg src,bool srcSigned)216 virtual void EncodeCast([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] Reg src, 217 [[maybe_unused]] bool srcSigned) 218 { 219 SetFalseResult(); 220 } EncodeCastToBool(Reg dst,Reg src)221 virtual void EncodeCastToBool([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 222 { 223 SetFalseResult(); 224 } EncodeMin(Reg dst,bool dstSigned,Reg src0,Reg src1)225 virtual void EncodeMin([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] Reg src0, 226 [[maybe_unused]] Reg src1) 227 { 228 SetFalseResult(); 229 } EncodeDiv(Reg dst,bool dstSigned,Reg src0,Reg src1)230 virtual void EncodeDiv([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] Reg src0, 231 [[maybe_unused]] Reg src1) 232 { 233 SetFalseResult(); 234 } EncodeMod(Reg dst,bool dstSigned,Reg src0,Reg src1)235 virtual void EncodeMod([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] Reg src0, 236 [[maybe_unused]] Reg src1) 237 { 238 SetFalseResult(); 239 } EncodeMax(Reg dst,bool dstSigned,Reg src0,Reg src1)240 virtual void EncodeMax([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] Reg src0, 241 [[maybe_unused]] Reg src1) 242 { 243 SetFalseResult(); 244 } EncodeMov(Reg dst,Imm src)245 virtual void EncodeMov([[maybe_unused]] Reg dst, [[maybe_unused]] Imm src) 246 { 247 SetFalseResult(); 248 } 249 EncodeLdr(Reg dst,bool dstSigned,MemRef mem)250 virtual void EncodeLdr([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] MemRef mem) 251 { 252 SetFalseResult(); 253 } EncodeLdrAcquire(Reg dst,bool dstSigned,MemRef mem)254 virtual void EncodeLdrAcquire([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, 255 [[maybe_unused]] MemRef mem) 256 { 257 SetFalseResult(); 258 } EncodeStr(Reg src,MemRef mem)259 virtual void EncodeStr([[maybe_unused]] Reg src, [[maybe_unused]] MemRef mem) 260 { 261 SetFalseResult(); 262 } EncodeStrRelease(Reg src,MemRef mem)263 virtual void EncodeStrRelease([[maybe_unused]] Reg src, [[maybe_unused]] MemRef mem) 264 { 265 SetFalseResult(); 266 } EncodeLdrExclusive(Reg dst,Reg addr,bool acquire)267 virtual void EncodeLdrExclusive([[maybe_unused]] Reg dst, [[maybe_unused]] Reg addr, [[maybe_unused]] bool acquire) 268 { 269 SetFalseResult(); 270 } EncodeStrExclusive(Reg dst,Reg src,Reg addr,bool release)271 virtual void EncodeStrExclusive([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src, [[maybe_unused]] Reg addr, 272 [[maybe_unused]] bool release) 273 { 274 SetFalseResult(); 275 } 276 277 // zerod high part: [reg.size, 64) EncodeStrz(Reg src,MemRef mem)278 virtual void EncodeStrz([[maybe_unused]] Reg src, [[maybe_unused]] MemRef mem) 279 { 280 SetFalseResult(); 281 } Push(Reg src,MemRef mem)282 virtual void Push([[maybe_unused]] Reg src, [[maybe_unused]] MemRef mem) 283 { 284 SetFalseResult(); 285 } EncodeSti(int64_t src,uint8_t srcSizeBytes,MemRef mem)286 virtual void EncodeSti([[maybe_unused]] int64_t src, [[maybe_unused]] uint8_t srcSizeBytes, 287 [[maybe_unused]] MemRef mem) 288 { 289 SetFalseResult(); 290 } EncodeSti(double src,MemRef mem)291 virtual void EncodeSti([[maybe_unused]] double src, [[maybe_unused]] MemRef mem) 292 { 293 SetFalseResult(); 294 } EncodeSti(float src,MemRef mem)295 virtual void EncodeSti([[maybe_unused]] float src, [[maybe_unused]] MemRef mem) 296 { 297 SetFalseResult(); 298 } 299 // size must be 8, 16,32 or 64 EncodeMemCopy(MemRef memFrom,MemRef memTo,size_t size)300 virtual void EncodeMemCopy([[maybe_unused]] MemRef memFrom, [[maybe_unused]] MemRef memTo, 301 [[maybe_unused]] size_t size) 302 { 303 SetFalseResult(); 304 } 305 // size must be 8, 16,32 or 64 306 // zerod high part: [size, 64) EncodeMemCopyz(MemRef memFrom,MemRef memTo,size_t size)307 virtual void EncodeMemCopyz([[maybe_unused]] MemRef memFrom, [[maybe_unused]] MemRef memTo, 308 [[maybe_unused]] size_t size) 309 { 310 SetFalseResult(); 311 } 312 EncodeCmp(Reg dst,Reg src0,Reg src1,Condition cc)313 virtual void EncodeCmp([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, 314 [[maybe_unused]] Condition cc) 315 { 316 SetFalseResult(); 317 } 318 319 // Additional check for isnan-comparison EncodeCompare(Reg dst,Reg src0,Reg src1,Condition cc)320 virtual void EncodeCompare([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, 321 [[maybe_unused]] Condition cc) 322 { 323 SetFalseResult(); 324 } 325 EncodeCompareTest(Reg dst,Reg src0,Reg src1,Condition cc)326 virtual void EncodeCompareTest([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, 327 [[maybe_unused]] Condition cc) 328 { 329 SetFalseResult(); 330 } 331 EncodeCompressedStringCharAt(Reg dst,Reg str,Reg idx,Reg length,Reg tmp,size_t dataOffset,uint32_t shift)332 virtual void EncodeCompressedStringCharAt([[maybe_unused]] Reg dst, [[maybe_unused]] Reg str, 333 [[maybe_unused]] Reg idx, [[maybe_unused]] Reg length, 334 [[maybe_unused]] Reg tmp, [[maybe_unused]] size_t dataOffset, 335 [[maybe_unused]] uint32_t shift) 336 { 337 SetFalseResult(); 338 } 339 EncodeCompressedStringCharAtI(Reg dst,Reg str,Reg length,size_t dataOffset,uint32_t index,uint32_t shift)340 virtual void EncodeCompressedStringCharAtI([[maybe_unused]] Reg dst, [[maybe_unused]] Reg str, 341 [[maybe_unused]] Reg length, [[maybe_unused]] size_t dataOffset, 342 [[maybe_unused]] uint32_t index, [[maybe_unused]] uint32_t shift) 343 { 344 SetFalseResult(); 345 } 346 EncodeSelect(Reg dst,Reg src0,Reg src1,Reg src2,Reg src3,Condition cc)347 virtual void EncodeSelect([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, 348 [[maybe_unused]] Reg src2, [[maybe_unused]] Reg src3, [[maybe_unused]] Condition cc) 349 { 350 SetFalseResult(); 351 } 352 EncodeSelectTest(Reg dst,Reg src0,Reg src1,Reg src2,Reg src3,Condition cc)353 virtual void EncodeSelectTest([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, 354 [[maybe_unused]] Reg src2, [[maybe_unused]] Reg src3, [[maybe_unused]] Condition cc) 355 { 356 SetFalseResult(); 357 } 358 EncodeIsInf(Reg dst,Reg src0)359 virtual void EncodeIsInf([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0) 360 { 361 SetFalseResult(); 362 } 363 EncodeIsInteger(Reg dst,Reg src0)364 virtual void EncodeIsInteger([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0) 365 { 366 SetFalseResult(); 367 } 368 EncodeIsSafeInteger(Reg dst,Reg src0)369 virtual void EncodeIsSafeInteger([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0) 370 { 371 SetFalseResult(); 372 } 373 EncodeReverseBytes(Reg dst,Reg src)374 virtual void EncodeReverseBytes([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 375 { 376 SetFalseResult(); 377 } 378 EncodeReverseBits(Reg dst,Reg src)379 virtual void EncodeReverseBits([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 380 { 381 SetFalseResult(); 382 } 383 EncodeBitCount(Reg dst,Reg src)384 virtual void EncodeBitCount([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 385 { 386 SetFalseResult(); 387 } 388 EncodeRotate(Reg dst,Reg src1,Reg src2,bool isRor)389 virtual void EncodeRotate([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src1, [[maybe_unused]] Reg src2, 390 [[maybe_unused]] bool isRor) 391 { 392 SetFalseResult(); 393 } 394 EncodeSignum(Reg dst,Reg src)395 virtual void EncodeSignum([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 396 { 397 SetFalseResult(); 398 } 399 EncodeCountLeadingZeroBits(Reg dst,Reg src)400 virtual void EncodeCountLeadingZeroBits([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 401 { 402 SetFalseResult(); 403 } 404 EncodeCountTrailingZeroBits(Reg dst,Reg src)405 virtual void EncodeCountTrailingZeroBits([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 406 { 407 SetFalseResult(); 408 } 409 EncodeCeil(Reg dst,Reg src)410 virtual void EncodeCeil([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 411 { 412 SetFalseResult(); 413 } 414 EncodeFloor(Reg dst,Reg src)415 virtual void EncodeFloor([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 416 { 417 SetFalseResult(); 418 } 419 EncodeRint(Reg dst,Reg src)420 virtual void EncodeRint([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 421 { 422 SetFalseResult(); 423 } 424 EncodeTrunc(Reg dst,Reg src)425 virtual void EncodeTrunc([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 426 { 427 SetFalseResult(); 428 } 429 EncodeRoundAway(Reg dst,Reg src)430 virtual void EncodeRoundAway([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 431 { 432 SetFalseResult(); 433 } 434 EncodeRoundToPInf(Reg dst,Reg src)435 virtual void EncodeRoundToPInf([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 436 { 437 SetFalseResult(); 438 } 439 EncodeSelect(Reg dst,Reg src0,Reg src1,Reg src2,Imm imm,Condition cc)440 virtual void EncodeSelect([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, 441 [[maybe_unused]] Reg src2, [[maybe_unused]] Imm imm, [[maybe_unused]] Condition cc) 442 { 443 SetFalseResult(); 444 } 445 EncodeSelectTest(Reg dst,Reg src0,Reg src1,Reg src2,Imm imm,Condition cc)446 virtual void EncodeSelectTest([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, 447 [[maybe_unused]] Reg src2, [[maybe_unused]] Imm imm, [[maybe_unused]] Condition cc) 448 { 449 SetFalseResult(); 450 } 451 EncodeGetTypeSize(Reg size,Reg type)452 virtual void EncodeGetTypeSize([[maybe_unused]] Reg size, [[maybe_unused]] Reg type) 453 { 454 SetFalseResult(); 455 } 456 EncodeLdp(Reg dst0,Reg dst1,bool dstSigned,MemRef mem)457 virtual void EncodeLdp([[maybe_unused]] Reg dst0, [[maybe_unused]] Reg dst1, [[maybe_unused]] bool dstSigned, 458 [[maybe_unused]] MemRef mem) 459 { 460 SetFalseResult(); 461 } 462 EncodeStp(Reg src0,Reg src1,MemRef mem)463 virtual void EncodeStp([[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, [[maybe_unused]] MemRef mem) 464 { 465 SetFalseResult(); 466 } 467 EncodeMAdd(Reg dst,Reg src0,Reg src1,Reg src2)468 virtual void EncodeMAdd([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, 469 [[maybe_unused]] Reg src2) 470 { 471 SetFalseResult(); 472 } 473 EncodeMSub(Reg dst,Reg src0,Reg src1,Reg src2)474 virtual void EncodeMSub([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, 475 [[maybe_unused]] Reg src2) 476 { 477 SetFalseResult(); 478 } 479 EncodeMNeg(Reg dst,Reg src0,Reg src1)480 virtual void EncodeMNeg([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1) 481 { 482 SetFalseResult(); 483 } 484 EncodeOrNot(Reg dst,Reg src0,Reg src1)485 virtual void EncodeOrNot([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1) 486 { 487 SetFalseResult(); 488 } 489 EncodeAndNot(Reg dst,Reg src0,Reg src1)490 virtual void EncodeAndNot([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1) 491 { 492 SetFalseResult(); 493 } 494 EncodeXorNot(Reg dst,Reg src0,Reg src1)495 virtual void EncodeXorNot([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1) 496 { 497 SetFalseResult(); 498 } 499 EncodeNeg(Reg dst,Shift src)500 virtual void EncodeNeg([[maybe_unused]] Reg dst, [[maybe_unused]] Shift src) 501 { 502 SetFalseResult(); 503 } 504 EncodeFpToBits(Reg dst,Reg src)505 virtual void EncodeFpToBits([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 506 { 507 SetFalseResult(); 508 } 509 EncodeMoveBitsRaw(Reg dst,Reg src)510 virtual void EncodeMoveBitsRaw([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) 511 { 512 SetFalseResult(); 513 } 514 EncodeExtractBits(Reg dst,Reg src,Imm imm1,Imm imm2)515 virtual void EncodeExtractBits([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src, [[maybe_unused]] Imm imm1, 516 [[maybe_unused]] Imm imm2) 517 { 518 success_ = false; 519 } 520 EncodeCrc32Update(Reg dst,Reg crcReg,Reg valReg)521 virtual void EncodeCrc32Update([[maybe_unused]] Reg dst, [[maybe_unused]] Reg crcReg, [[maybe_unused]] Reg valReg) 522 { 523 SetFalseResult(); 524 } 525 526 /** 527 * Encode dummy load from the address [sp + offset]. 528 * @param offset offset from the stack pointer register 529 */ EncodeStackOverflowCheck(ssize_t offset)530 virtual void EncodeStackOverflowCheck([[maybe_unused]] ssize_t offset) 531 { 532 SetFalseResult(); 533 } 534 IsValid()535 virtual bool IsValid() const 536 { 537 return false; 538 } 539 GetResult()540 virtual bool GetResult() const 541 { 542 return success_; 543 } 544 SetFalseResult()545 void SetFalseResult() 546 { 547 success_ = false; 548 } 549 550 // Encoder builder - implement in target.cpp 551 static Encoder *Create(ArenaAllocator *arenaAllocator, Arch arch, bool printAsm, bool jsNumberCast = false); 552 553 // For now it is one function for Add/Sub and Cmp, it suits all considered targets (x86, amd64, arm32, arm64). 554 // We probably should revisit this if we add new targets, like Thumb-2 or others. CanEncodeImmAddSubCmp(int64_t imm,uint32_t size,bool signedCompare)555 virtual bool CanEncodeImmAddSubCmp([[maybe_unused]] int64_t imm, [[maybe_unused]] uint32_t size, 556 [[maybe_unused]] bool signedCompare) 557 { 558 return false; 559 } 560 CanEncodeImmMulDivMod(uint64_t imm,uint32_t size)561 virtual bool CanEncodeImmMulDivMod([[maybe_unused]] uint64_t imm, [[maybe_unused]] uint32_t size) 562 { 563 return false; 564 } 565 CanEncodeImmLogical(uint64_t imm,uint32_t size)566 virtual bool CanEncodeImmLogical([[maybe_unused]] uint64_t imm, [[maybe_unused]] uint32_t size) 567 { 568 return false; 569 } 570 CanEncodeScale(uint64_t imm,uint32_t size)571 virtual bool CanEncodeScale([[maybe_unused]] uint64_t imm, [[maybe_unused]] uint32_t size) 572 { 573 return false; 574 } 575 CanEncodeShift(uint32_t size)576 virtual bool CanEncodeShift([[maybe_unused]] uint32_t size) 577 { 578 return true; 579 } 580 CanEncodeBitCount()581 virtual bool CanEncodeBitCount() 582 { 583 return false; 584 } 585 CanEncodeMAdd()586 virtual bool CanEncodeMAdd() 587 { 588 return false; 589 } 590 CanEncodeMSub()591 virtual bool CanEncodeMSub() 592 { 593 return false; 594 } 595 CanEncodeMNeg()596 virtual bool CanEncodeMNeg() 597 { 598 return false; 599 } 600 CanEncodeOrNot()601 virtual bool CanEncodeOrNot() 602 { 603 return false; 604 } 605 CanEncodeAndNot()606 virtual bool CanEncodeAndNot() 607 { 608 return false; 609 } 610 CanEncodeXorNot()611 virtual bool CanEncodeXorNot() 612 { 613 return false; 614 } 615 616 // Check if encoder is capable of encoding operations where an operand is a register with 617 // a value shifted by shift operation with specified type by some immediate value. CanEncodeShiftedOperand(ShiftOpcode opcode,ShiftType shiftType)618 virtual bool CanEncodeShiftedOperand([[maybe_unused]] ShiftOpcode opcode, [[maybe_unused]] ShiftType shiftType) 619 { 620 return false; 621 } 622 CanEncodeCompressedStringCharAt()623 virtual bool CanEncodeCompressedStringCharAt() 624 { 625 return false; 626 } 627 CanEncodeCompressedStringCharAtI()628 virtual bool CanEncodeCompressedStringCharAtI() 629 { 630 return false; 631 } 632 CanEncodeFloatSelect()633 virtual bool CanEncodeFloatSelect() 634 { 635 return false; 636 } 637 EncodeCompareAndSwap(Reg dst,Reg obj,Reg offset,Reg val,Reg newval)638 virtual void EncodeCompareAndSwap([[maybe_unused]] Reg dst, [[maybe_unused]] Reg obj, [[maybe_unused]] Reg offset, 639 [[maybe_unused]] Reg val, [[maybe_unused]] Reg newval) 640 { 641 SetFalseResult(); 642 } 643 EncodeCompareAndSwap(Reg dst,Reg addr,Reg val,Reg newval)644 virtual void EncodeCompareAndSwap([[maybe_unused]] Reg dst, [[maybe_unused]] Reg addr, [[maybe_unused]] Reg val, 645 [[maybe_unused]] Reg newval) 646 { 647 SetFalseResult(); 648 } 649 EncodeUnsafeGetAndSet(Reg dst,Reg obj,Reg offset,Reg val)650 virtual void EncodeUnsafeGetAndSet([[maybe_unused]] Reg dst, [[maybe_unused]] Reg obj, [[maybe_unused]] Reg offset, 651 [[maybe_unused]] Reg val) 652 { 653 SetFalseResult(); 654 } 655 EncodeUnsafeGetAndAdd(Reg dst,Reg obj,Reg offset,Reg val,Reg tmp)656 virtual void EncodeUnsafeGetAndAdd([[maybe_unused]] Reg dst, [[maybe_unused]] Reg obj, [[maybe_unused]] Reg offset, 657 [[maybe_unused]] Reg val, [[maybe_unused]] Reg tmp) 658 { 659 SetFalseResult(); 660 } 661 EncodeMemoryBarrier(memory_order::Order order)662 virtual void EncodeMemoryBarrier([[maybe_unused]] memory_order::Order order) 663 { 664 SetFalseResult(); 665 } 666 GetCursorOffset()667 virtual size_t GetCursorOffset() const 668 { 669 return 0; 670 } 671 EncodeCompressEightUtf16ToUtf8CharsUsingSimd(Reg srcAddr,Reg dstAddr)672 virtual void EncodeCompressEightUtf16ToUtf8CharsUsingSimd([[maybe_unused]] Reg srcAddr, 673 [[maybe_unused]] Reg dstAddr) 674 { 675 SetFalseResult(); 676 } 677 EncodeCompressSixteenUtf16ToUtf8CharsUsingSimd(Reg srcAddr,Reg dstAddr)678 virtual void EncodeCompressSixteenUtf16ToUtf8CharsUsingSimd([[maybe_unused]] Reg srcAddr, 679 [[maybe_unused]] Reg dstAddr) 680 { 681 SetFalseResult(); 682 } 683 SetCursorOffset(size_t offset)684 virtual void SetCursorOffset([[maybe_unused]] size_t offset) {} 685 SaveRegisters(RegMask registers,ssize_t slot,size_t startReg,bool isFp)686 virtual void SaveRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] ssize_t slot, 687 [[maybe_unused]] size_t startReg, [[maybe_unused]] bool isFp) 688 { 689 SetFalseResult(); 690 } LoadRegisters(RegMask registers,ssize_t slot,size_t startReg,bool isFp)691 virtual void LoadRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] ssize_t slot, 692 [[maybe_unused]] size_t startReg, [[maybe_unused]] bool isFp) 693 { 694 SetFalseResult(); 695 } 696 697 /** 698 * Save/load registers to/from the memory. 699 * 700 * If `mask` is empty (all bits are zero), then registers will be saved densely, otherwise place for each register 701 * will be determined according to this mask. 702 * Example: registers' bits = [1, 3, 10], mask's bits = [0, 1, 2, 3, 8, 9, 10, 11] 703 * We can see that mask has the gap in 4-7 bits. So, registers will be saved in the following slots: 704 * slots: 0 1 2 3 4 5 6 7 705 * regs : 1 3 10 706 * If the mask would be zero, then the following layout will be used: 707 * slots: 0 1 2 708 * regs : 1 3 10 709 * 710 * @param registers mask of registers to be saved 711 * @param is_fp if true, registers are floating point registers 712 * @param slot offset from the `base` register to the destination address (in words) 713 * @param base base register 714 * @param mask determine memory layout for the registers 715 */ SaveRegisters(RegMask registers,bool isFp,ssize_t slot,Reg base,RegMask mask)716 virtual void SaveRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] bool isFp, 717 [[maybe_unused]] ssize_t slot, [[maybe_unused]] Reg base, [[maybe_unused]] RegMask mask) 718 { 719 SetFalseResult(); 720 } LoadRegisters(RegMask registers,bool isFp,ssize_t slot,Reg base,RegMask mask)721 virtual void LoadRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] bool isFp, 722 [[maybe_unused]] ssize_t slot, [[maybe_unused]] Reg base, [[maybe_unused]] RegMask mask) 723 { 724 SetFalseResult(); 725 } 726 727 void PushRegisters(RegMask regs, VRegMask fpRegs, bool isAligned = true) 728 { 729 ASSERT(GetArch() != Arch::AARCH64 || isAligned); 730 PushRegisters(regs, false); 731 PushRegisters(fpRegs, true); 732 733 bool isEven {(regs.Count() + fpRegs.Count()) % 2U == 0U}; 734 if (GetArch() != Arch::AARCH64 && isEven != isAligned) { 735 EncodeSub(GetTarget().GetStackReg(), GetTarget().GetStackReg(), Imm(GetTarget().WordSize())); 736 } 737 } 738 739 void PopRegisters(RegMask regs, VRegMask fpRegs, bool isAligned = true) 740 { 741 bool isEven {(regs.Count() + fpRegs.Count()) % 2U == 0U}; 742 if (GetArch() != Arch::AARCH64 && isEven != isAligned) { 743 EncodeAdd(GetTarget().GetStackReg(), GetTarget().GetStackReg(), Imm(GetTarget().WordSize())); 744 } 745 746 PopRegisters(fpRegs, true); 747 PopRegisters(regs, false); 748 } 749 PushRegisters(RegMask registers,bool isFp)750 virtual void PushRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] bool isFp) 751 { 752 SetFalseResult(); 753 } 754 PopRegisters(RegMask registers,bool isFp)755 virtual void PopRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] bool isFp) 756 { 757 SetFalseResult(); 758 } 759 GetRegfile()760 RegistersDescription *GetRegfile() const 761 { 762 ASSERT(regfile_ != nullptr); 763 return regfile_; 764 } 765 SetRegfile(RegistersDescription * regfile)766 void SetRegfile(RegistersDescription *regfile) 767 { 768 regfile_ = regfile; 769 } 770 AcquireScratchRegister(compiler::TypeInfo type)771 virtual compiler::Reg AcquireScratchRegister([[maybe_unused]] compiler::TypeInfo type) 772 { 773 return compiler::Reg(); 774 } 775 AcquireScratchRegister(compiler::Reg reg)776 virtual void AcquireScratchRegister([[maybe_unused]] compiler::Reg reg) 777 { 778 SetFalseResult(); 779 } 780 ReleaseScratchRegister(compiler::Reg reg)781 virtual void ReleaseScratchRegister([[maybe_unused]] compiler::Reg reg) 782 { 783 SetFalseResult(); 784 } 785 IsScratchRegisterReleased(compiler::Reg reg)786 virtual bool IsScratchRegisterReleased([[maybe_unused]] compiler::Reg reg) 787 { 788 return false; 789 } 790 GetScratchRegistersCount()791 size_t GetScratchRegistersCount() const 792 { 793 return GetScratchRegistersMask().Count(); 794 } 795 GetScratchRegistersMask()796 virtual RegMask GetScratchRegistersMask() const 797 { 798 return 0; 799 } 800 GetScratchFPRegistersCount()801 size_t GetScratchFPRegistersCount() const 802 { 803 return GetScratchFpRegistersMask().Count(); 804 } 805 GetScratchFpRegistersMask()806 virtual RegMask GetScratchFpRegistersMask() const 807 { 808 return 0; 809 } 810 811 // Get Scratch registers, that currently are not allocated GetAvailableScratchRegisters()812 virtual RegMask GetAvailableScratchRegisters() const 813 { 814 return 0; 815 } 816 817 // Get Floating Point Scratch registers, that currently are not allocated GetAvailableScratchFpRegisters()818 virtual VRegMask GetAvailableScratchFpRegisters() const 819 { 820 return 0; 821 } 822 MaxArchInstPerEncoded()823 virtual size_t MaxArchInstPerEncoded() 824 { 825 static constexpr size_t MAX_ARCH_INST_PER_ENCODE = 32; 826 return MAX_ARCH_INST_PER_ENCODE; 827 } 828 SetRegister(RegMask * mask,VRegMask * vmask,Reg reg)829 virtual void SetRegister(RegMask *mask, VRegMask *vmask, Reg reg) 830 { 831 SetRegister(mask, vmask, reg, true); 832 } 833 SetRegister(RegMask * mask,VRegMask * vmask,Reg reg,bool val)834 virtual void SetRegister(RegMask *mask, VRegMask *vmask, Reg reg, bool val) const 835 { 836 if (!reg.IsValid()) { 837 return; 838 } 839 if (reg.IsScalar()) { 840 ASSERT(mask != nullptr); 841 mask->set(reg.GetId(), val); 842 } else { 843 ASSERT(vmask != nullptr); 844 ASSERT(reg.IsFloat()); 845 if (vmask != nullptr) { 846 vmask->set(reg.GetId(), val); 847 } 848 } 849 } 850 GetRefType()851 virtual compiler::TypeInfo GetRefType() 852 { 853 return compiler::TypeInfo(); 854 } 855 856 virtual void Finalize() = 0; 857 858 public: 859 /// Label-holder interfaces CreateLabel()860 LabelHolder::LabelId CreateLabel() 861 { 862 auto labels = GetLabels(); 863 ASSERT(labels != nullptr); 864 return labels->CreateLabel(); 865 } 866 BindLabel(LabelHolder::LabelId id)867 void BindLabel(LabelHolder::LabelId id) 868 { 869 auto labels = GetLabels(); 870 ASSERT(labels != nullptr); 871 ASSERT(labels->Size() > id); 872 labels->BindLabel(id); 873 } 874 GetLabels()875 virtual LabelHolder *GetLabels() const 876 { 877 return nullptr; 878 } 879 virtual size_t GetLabelAddress(LabelHolder::LabelId label) = 0; 880 881 virtual bool LabelHasLinks(LabelHolder::LabelId label) = 0; 882 883 public: MakeCall(compiler::RelocationInfo * relocation)884 virtual void MakeCall([[maybe_unused]] compiler::RelocationInfo *relocation) 885 { 886 SetFalseResult(); 887 } 888 MakeCall(compiler::LabelHolder::LabelId id)889 virtual void MakeCall([[maybe_unused]] compiler::LabelHolder::LabelId id) 890 { 891 SetFalseResult(); 892 } 893 MakeCall(const void * entryPoint)894 virtual void MakeCall([[maybe_unused]] const void *entryPoint) 895 { 896 SetFalseResult(); 897 } 898 MakeCall(Reg reg)899 virtual void MakeCall([[maybe_unused]] Reg reg) 900 { 901 SetFalseResult(); 902 } 903 MakeCall(compiler::MemRef entryPoint)904 virtual void MakeCall([[maybe_unused]] compiler::MemRef entryPoint) 905 { 906 SetFalseResult(); 907 } 908 MakeCallAot(intptr_t offset)909 virtual void MakeCallAot([[maybe_unused]] intptr_t offset) 910 { 911 SetFalseResult(); 912 } 913 CanMakeCallByOffset(intptr_t offset)914 virtual bool CanMakeCallByOffset([[maybe_unused]] intptr_t offset) 915 { 916 return false; 917 } 918 MakeCallByOffset(intptr_t offset)919 virtual void MakeCallByOffset([[maybe_unused]] intptr_t offset) 920 { 921 SetFalseResult(); 922 } 923 MakeLoadAotTable(intptr_t offset,compiler::Reg reg)924 virtual void MakeLoadAotTable([[maybe_unused]] intptr_t offset, [[maybe_unused]] compiler::Reg reg) 925 { 926 SetFalseResult(); 927 } 928 MakeLoadAotTableAddr(intptr_t offset,compiler::Reg addr,compiler::Reg val)929 virtual void MakeLoadAotTableAddr([[maybe_unused]] intptr_t offset, [[maybe_unused]] compiler::Reg addr, 930 [[maybe_unused]] compiler::Reg val) 931 { 932 SetFalseResult(); 933 } 934 935 // Encode unconditional branch EncodeJump(compiler::LabelHolder::LabelId id)936 virtual void EncodeJump([[maybe_unused]] compiler::LabelHolder::LabelId id) 937 { 938 SetFalseResult(); 939 } 940 941 // Encode jump with compare to zero EncodeJump(compiler::LabelHolder::LabelId id,compiler::Reg reg,compiler::Condition cond)942 virtual void EncodeJump([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] compiler::Reg reg, 943 [[maybe_unused]] compiler::Condition cond) 944 { 945 SetFalseResult(); 946 } 947 948 // Compare reg and immediate and branch EncodeJump(compiler::LabelHolder::LabelId id,compiler::Reg reg,compiler::Imm imm,compiler::Condition c)949 virtual void EncodeJump([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] compiler::Reg reg, 950 [[maybe_unused]] compiler::Imm imm, [[maybe_unused]] compiler::Condition c) 951 { 952 SetFalseResult(); 953 } 954 955 // Compare two regs and branch EncodeJump(compiler::LabelHolder::LabelId id,compiler::Reg r,compiler::Reg reg,compiler::Condition c)956 virtual void EncodeJump([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] compiler::Reg r, 957 [[maybe_unused]] compiler::Reg reg, [[maybe_unused]] compiler::Condition c) 958 { 959 SetFalseResult(); 960 } 961 962 // Compare reg and immediate and branch EncodeJumpTest(compiler::LabelHolder::LabelId id,compiler::Reg reg,compiler::Imm imm,compiler::Condition c)963 virtual void EncodeJumpTest([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] compiler::Reg reg, 964 [[maybe_unused]] compiler::Imm imm, [[maybe_unused]] compiler::Condition c) 965 { 966 SetFalseResult(); 967 } 968 969 // Compare two regs and branch EncodeJumpTest(compiler::LabelHolder::LabelId id,compiler::Reg r,compiler::Reg reg,compiler::Condition c)970 virtual void EncodeJumpTest([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] compiler::Reg r, 971 [[maybe_unused]] compiler::Reg reg, [[maybe_unused]] compiler::Condition c) 972 { 973 SetFalseResult(); 974 } 975 976 // Encode jump by register value EncodeJump(compiler::Reg reg)977 virtual void EncodeJump([[maybe_unused]] compiler::Reg reg) 978 { 979 SetFalseResult(); 980 } 981 EncodeJump(RelocationInfo * relocation)982 virtual void EncodeJump([[maybe_unused]] RelocationInfo *relocation) 983 { 984 SetFalseResult(); 985 } 986 EncodeBitTestAndBranch(compiler::LabelHolder::LabelId id,compiler::Reg reg,uint32_t bitPos,bool bitValue)987 virtual void EncodeBitTestAndBranch([[maybe_unused]] compiler::LabelHolder::LabelId id, 988 [[maybe_unused]] compiler::Reg reg, [[maybe_unused]] uint32_t bitPos, 989 [[maybe_unused]] bool bitValue) 990 { 991 SetFalseResult(); 992 } 993 EncodeAbort()994 virtual void EncodeAbort() 995 { 996 SetFalseResult(); 997 } 998 EncodeReturn()999 virtual void EncodeReturn() 1000 { 1001 SetFalseResult(); 1002 } 1003 SetFrameLayout(CFrameLayout fl)1004 void SetFrameLayout(CFrameLayout fl) 1005 { 1006 frameLayout_ = fl; 1007 } 1008 GetFrameLayout()1009 const CFrameLayout &GetFrameLayout() const 1010 { 1011 return frameLayout_; 1012 } 1013 GetLiveTmpRegMask()1014 RegMask GetLiveTmpRegMask() 1015 { 1016 return liveTmpRegs_; 1017 } 1018 GetLiveTmpFpRegMask()1019 VRegMask GetLiveTmpFpRegMask() 1020 { 1021 return liveTmpFpRegs_; 1022 } 1023 AddRegInLiveMask(Reg reg)1024 void AddRegInLiveMask(Reg reg) 1025 { 1026 if (!reg.IsValid()) { 1027 return; 1028 } 1029 if (reg.IsScalar()) { 1030 liveTmpRegs_.set(reg.GetId(), true); 1031 } else { 1032 ASSERT(reg.IsFloat()); 1033 liveTmpFpRegs_.set(reg.GetId(), true); 1034 } 1035 } 1036 RemoveRegFromLiveMask(Reg reg)1037 void RemoveRegFromLiveMask(Reg reg) 1038 { 1039 if (!reg.IsValid()) { 1040 return; 1041 } 1042 if (reg.IsScalar()) { 1043 liveTmpRegs_.set(reg.GetId(), false); 1044 } else { 1045 ASSERT(reg.IsFloat()); 1046 liveTmpFpRegs_.set(reg.GetId(), false); 1047 } 1048 } 1049 SetCodeOffset(size_t offset)1050 void SetCodeOffset(size_t offset) 1051 { 1052 codeOffset_ = offset; 1053 } 1054 GetCodeOffset()1055 size_t GetCodeOffset() const 1056 { 1057 return codeOffset_; 1058 } 1059 EnableLrAsTempReg(bool value)1060 void EnableLrAsTempReg(bool value) 1061 { 1062 enableLrAsTempReg_ = value; 1063 } 1064 IsLrAsTempRegEnabled()1065 bool IsLrAsTempRegEnabled() const 1066 { 1067 return enableLrAsTempReg_; 1068 } 1069 IsLrAsTempRegEnabledAndReleased()1070 bool IsLrAsTempRegEnabledAndReleased() 1071 { 1072 return IsLrAsTempRegEnabled() && IsScratchRegisterReleased(GetTarget().GetLinkReg()); 1073 } 1074 1075 NO_COPY_SEMANTIC(Encoder); 1076 NO_MOVE_SEMANTIC(Encoder); 1077 1078 protected: SetFrameSize(size_t size)1079 void SetFrameSize(size_t size) 1080 { 1081 frameSize_ = size; 1082 } 1083 GetFrameSize()1084 size_t GetFrameSize() const 1085 { 1086 return frameSize_; 1087 } 1088 1089 static constexpr size_t INVALID_OFFSET = std::numeric_limits<size_t>::max(); 1090 1091 // Max integer that can be represented in float/double without losing precision MaxIntAsExactFloat()1092 constexpr float MaxIntAsExactFloat() const 1093 { 1094 return static_cast<float>((1U << static_cast<unsigned>(std::numeric_limits<float>::digits)) - 1); 1095 } 1096 MaxIntAsExactDouble()1097 constexpr double MaxIntAsExactDouble() const 1098 { 1099 return static_cast<double>((1ULL << static_cast<unsigned>(std::numeric_limits<double>::digits)) - 1); 1100 } 1101 1102 private: 1103 ArenaAllocator *allocator_; 1104 RegistersDescription *regfile_ {nullptr}; 1105 size_t frameSize_ {0}; 1106 1107 CFrameLayout frameLayout_; 1108 1109 RegMask liveTmpRegs_; 1110 VRegMask liveTmpFpRegs_; 1111 1112 // In case of AOT compilation, this variable specifies offset from the start of the AOT file. 1113 // It is needed for accessing to the entrypoints table and AOT table, that lie right before code. 1114 size_t codeOffset_ {INVALID_OFFSET}; 1115 1116 Target target_ {Arch::NONE}; 1117 1118 bool success_ {true}; 1119 bool jsNumberCast_ {false}; 1120 // If true, then ScopedTmpReg can use LR as a temp register. 1121 bool enableLrAsTempReg_ {false}; 1122 }; // Encoder 1123 1124 /** 1125 * This class is using to acquire/release temp register using RAII technique. 1126 * 1127 * @tparam lazy if true, temp register will be acquired in the constructor, otherwise user should acquire it explicitly. 1128 */ 1129 template <bool LAZY> 1130 class ScopedTmpRegImpl { 1131 public: ScopedTmpRegImpl(Encoder * encoder)1132 explicit ScopedTmpRegImpl(Encoder *encoder) : ScopedTmpRegImpl(encoder, false) {} ScopedTmpRegImpl(Encoder * encoder,bool withLr)1133 ScopedTmpRegImpl(Encoder *encoder, bool withLr) : encoder_(encoder) 1134 { 1135 if constexpr (!LAZY) { // NOLINT 1136 auto linkReg = encoder->GetTarget().GetLinkReg(); 1137 withLr &= encoder->IsLrAsTempRegEnabled(); 1138 if (withLr && encoder->IsScratchRegisterReleased(linkReg)) { 1139 reg_ = linkReg; 1140 encoder->AcquireScratchRegister(linkReg); 1141 } else { 1142 reg_ = encoder->AcquireScratchRegister(Is64BitsArch(encoder->GetArch()) ? INT64_TYPE : INT32_TYPE); 1143 } 1144 } 1145 } 1146 ScopedTmpRegImpl(Encoder * encoder,TypeInfo type)1147 ScopedTmpRegImpl(Encoder *encoder, TypeInfo type) : encoder_(encoder), reg_(encoder->AcquireScratchRegister(type)) 1148 { 1149 static_assert(!LAZY); 1150 } 1151 ScopedTmpRegImpl(Encoder * encoder,Reg reg)1152 ScopedTmpRegImpl(Encoder *encoder, Reg reg) : encoder_(encoder), reg_(reg) 1153 { 1154 static_assert(!LAZY); 1155 encoder->AcquireScratchRegister(reg); 1156 } 1157 ScopedTmpRegImpl(ScopedTmpRegImpl && other)1158 ScopedTmpRegImpl(ScopedTmpRegImpl &&other) noexcept 1159 { 1160 encoder_ = other.encoder_; 1161 reg_ = other.reg_; 1162 other.reg_ = Reg(); 1163 ASSERT(!other.reg_.IsValid()); 1164 } 1165 ~ScopedTmpRegImpl()1166 virtual ~ScopedTmpRegImpl() 1167 { 1168 if (reg_.IsValid()) { 1169 encoder_->ReleaseScratchRegister(reg_); 1170 } 1171 } 1172 1173 NO_COPY_SEMANTIC(ScopedTmpRegImpl); 1174 NO_MOVE_OPERATOR(ScopedTmpRegImpl); 1175 GetReg()1176 Reg GetReg() const 1177 { 1178 return reg_; 1179 } 1180 GetType()1181 TypeInfo GetType() const 1182 { 1183 return reg_.GetType(); 1184 } 1185 1186 // NOLINTNEXTLINE(google-explicit-constructor) Reg()1187 operator Reg() const 1188 { 1189 return reg_; 1190 } 1191 ChangeType(TypeInfo tp)1192 void ChangeType(TypeInfo tp) 1193 { 1194 ASSERT(tp.IsScalar() == reg_.IsScalar()); 1195 reg_ = Reg(reg_.GetId(), tp); 1196 } 1197 Release()1198 virtual void Release() 1199 { 1200 if (reg_.IsValid()) { 1201 encoder_->ReleaseScratchRegister(reg_); 1202 reg_ = INVALID_REGISTER; 1203 } 1204 } 1205 Acquire()1206 void Acquire() 1207 { 1208 ASSERT(!reg_.IsValid()); 1209 reg_ = encoder_->AcquireScratchRegister(Is64BitsArch(encoder_->GetArch()) ? INT64_TYPE : INT32_TYPE); 1210 ASSERT(reg_.IsValid()); 1211 } 1212 AcquireWithLr()1213 void AcquireWithLr() 1214 { 1215 ASSERT(!reg_.IsValid()); 1216 auto linkReg = encoder_->GetTarget().GetLinkReg(); 1217 if (encoder_->IsLrAsTempRegEnabled() && encoder_->IsScratchRegisterReleased(linkReg)) { 1218 reg_ = linkReg; 1219 encoder_->AcquireScratchRegister(linkReg); 1220 } else { 1221 reg_ = encoder_->AcquireScratchRegister(Is64BitsArch(encoder_->GetArch()) ? INT64_TYPE : INT32_TYPE); 1222 } 1223 ASSERT(reg_.IsValid()); 1224 } 1225 AcquireIfInvalid()1226 void AcquireIfInvalid() 1227 { 1228 if (!reg_.IsValid()) { 1229 reg_ = encoder_->AcquireScratchRegister(Is64BitsArch(encoder_->GetArch()) ? INT64_TYPE : INT32_TYPE); 1230 ASSERT(reg_.IsValid()); 1231 } 1232 } 1233 1234 protected: GetEncoder()1235 Encoder *GetEncoder() 1236 { 1237 return encoder_; 1238 } 1239 1240 private: 1241 Encoder *encoder_ {nullptr}; 1242 Reg reg_; 1243 }; 1244 1245 struct ScopedTmpReg : public ScopedTmpRegImpl<false> { 1246 using ScopedTmpRegImpl<false>::ScopedTmpRegImpl; 1247 }; 1248 1249 struct ScopedTmpRegLazy : public ScopedTmpRegImpl<true> { 1250 using ScopedTmpRegImpl<true>::ScopedTmpRegImpl; 1251 }; 1252 1253 struct ScopedTmpRegU16 : public ScopedTmpReg { ScopedTmpRegU16ScopedTmpRegU161254 explicit ScopedTmpRegU16(Encoder *encoder) : ScopedTmpReg(encoder, INT16_TYPE) {} 1255 }; 1256 1257 struct ScopedTmpRegU32 : public ScopedTmpReg { ScopedTmpRegU32ScopedTmpRegU321258 explicit ScopedTmpRegU32(Encoder *encoder) : ScopedTmpReg(encoder, INT32_TYPE) {} 1259 }; 1260 1261 struct ScopedTmpRegU64 : public ScopedTmpReg { ScopedTmpRegU64ScopedTmpRegU641262 explicit ScopedTmpRegU64(Encoder *encoder) : ScopedTmpReg(encoder, INT64_TYPE) {} 1263 }; 1264 1265 struct ScopedTmpRegF32 : public ScopedTmpReg { ScopedTmpRegF32ScopedTmpRegF321266 explicit ScopedTmpRegF32(Encoder *encoder) : ScopedTmpReg(encoder, FLOAT32_TYPE) {} 1267 }; 1268 1269 struct ScopedTmpRegF64 : public ScopedTmpReg { ScopedTmpRegF64ScopedTmpRegF641270 explicit ScopedTmpRegF64(Encoder *encoder) : ScopedTmpReg(encoder, FLOAT64_TYPE) {} 1271 }; 1272 1273 struct ScopedTmpRegRef : public ScopedTmpReg { ScopedTmpRegRefScopedTmpRegRef1274 explicit ScopedTmpRegRef(Encoder *encoder) : ScopedTmpReg(encoder, encoder->GetRefType()) {} 1275 }; 1276 1277 class ScopedLiveTmpReg : public ScopedTmpReg { 1278 public: ScopedLiveTmpReg(Encoder * encoder)1279 explicit ScopedLiveTmpReg(Encoder *encoder) : ScopedTmpReg(encoder) 1280 { 1281 encoder->AddRegInLiveMask(GetReg()); 1282 } ScopedLiveTmpReg(Encoder * encoder,TypeInfo type)1283 ScopedLiveTmpReg(Encoder *encoder, TypeInfo type) : ScopedTmpReg(encoder, type) 1284 { 1285 encoder->AddRegInLiveMask(GetReg()); 1286 } 1287 Release()1288 void Release() final 1289 { 1290 ASSERT(GetReg().IsValid()); 1291 GetEncoder()->RemoveRegFromLiveMask(GetReg()); 1292 ScopedTmpReg::Release(); 1293 } 1294 ~ScopedLiveTmpReg()1295 ~ScopedLiveTmpReg() override 1296 { 1297 if (GetReg().IsValid()) { 1298 GetEncoder()->RemoveRegFromLiveMask(GetReg()); 1299 } 1300 } 1301 1302 NO_COPY_SEMANTIC(ScopedLiveTmpReg); 1303 NO_MOVE_SEMANTIC(ScopedLiveTmpReg); 1304 }; 1305 1306 } // namespace panda::compiler 1307 1308 #endif // COMPILER_OPTIMIZER_CODEGEN_ENCODE_H 1309