1 /* 2 * Copyright (c) 2023 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 MAPLEBE_INCLUDE_CG_OPERAND_H 17 #define MAPLEBE_INCLUDE_CG_OPERAND_H 18 19 #include "becommon.h" 20 #include "cg_option.h" 21 #include "visitor_common.h" 22 23 /* maple_ir */ 24 #include "mir_symbol.h" 25 #include "prim_types.h" /* for PrimType */ 26 #include "types_def.h" /* need uint8 etc */ 27 28 /* Mempool */ 29 #include "memlayout.h" 30 #include "mempool_allocator.h" /* MapleList */ 31 32 namespace maplebe { 33 class OpndDesc; 34 class Emitter; 35 class FuncEmitInfo; 36 37 bool IsBitSizeImmediate(maple::uint64 val, maple::uint32 bitLen, maple::uint32 nLowerZeroBits); 38 bool IsBitmaskImmediate(maple::uint64 val, maple::uint32 bitLen); 39 bool IsMoveWidableImmediate(uint64 val, uint32 bitLen); 40 bool BetterUseMOVZ(uint64 val); 41 42 using MOperator = uint32; 43 enum RegType : maple::uint8 { 44 kRegTyUndef, 45 kRegTyInt, 46 kRegTyFloat, 47 kRegTyCc, 48 kRegTyX87, 49 kRegTyVary, 50 kRegTyFpsc, 51 kRegTyIndex, 52 kRegTyLast, 53 }; 54 55 class Operand { 56 public: 57 enum OperandType : uint8 { 58 kOpdRegister, 59 kOpdImmediate, 60 kOpdMem, 61 kOpdCond, /* for condition code */ 62 kOpdPhi, /* for phi operand */ 63 kOpdFPImmediate, 64 kOpdStImmediate, /* use the symbol name as the offset */ 65 kOpdOffset, /* for the offset operand in MemOperand */ 66 kOpdBBAddress, 67 kOpdList, /* for list operand */ 68 kOpdShift, /* for imm shift operand */ 69 kOpdRegShift, /* for reg shift operand */ 70 kOpdExtend, /* for extend operand */ 71 kOpdString, /* for comments */ 72 kOpdUndef 73 }; 74 Operand(OperandType type,uint32 size)75 Operand(OperandType type, uint32 size) : opndKind(type), size(size) {} 76 virtual ~Operand() = default; 77 GetSize()78 uint32 GetSize() const 79 { 80 return size; 81 } 82 SetSize(uint32 sz)83 void SetSize(uint32 sz) 84 { 85 size = sz; 86 } 87 IsReference()88 bool IsReference() const 89 { 90 return isReference; 91 } 92 SetIsReference(bool isRef)93 void SetIsReference(bool isRef) 94 { 95 isReference = isRef; 96 } 97 GetKind()98 OperandType GetKind() const 99 { 100 return opndKind; 101 } 102 IsIntImmediate()103 bool IsIntImmediate() const 104 { 105 return opndKind == kOpdImmediate || opndKind == kOpdOffset; 106 } 107 IsConstImmediate()108 bool IsConstImmediate() const 109 { 110 return opndKind == kOpdImmediate || opndKind == kOpdOffset || opndKind == kOpdFPImmediate; 111 } 112 IsOfstImmediate()113 bool IsOfstImmediate() const 114 { 115 return opndKind == kOpdOffset; 116 } 117 IsStImmediate()118 bool IsStImmediate() const 119 { 120 return opndKind == kOpdStImmediate; 121 } 122 IsImmediate()123 bool IsImmediate() const 124 { 125 return (kOpdFPImmediate <= opndKind && opndKind <= kOpdOffset) || opndKind == kOpdImmediate; 126 } 127 IsRegister()128 bool IsRegister() const 129 { 130 return opndKind == kOpdRegister; 131 } 132 IsList()133 bool IsList() const 134 { 135 return opndKind == kOpdList; 136 } 137 IsPhi()138 bool IsPhi() const 139 { 140 return opndKind == kOpdPhi; 141 } 142 IsMemoryAccessOperand()143 bool IsMemoryAccessOperand() const 144 { 145 return opndKind == kOpdMem; 146 } 147 IsLabel()148 bool IsLabel() const 149 { 150 return opndKind == kOpdBBAddress; 151 } 152 IsZeroRegister()153 virtual bool IsZeroRegister() const 154 { 155 return false; 156 }; 157 IsConditionCode()158 bool IsConditionCode() const 159 { 160 return opndKind == kOpdCond; 161 } 162 IsOpdShift()163 bool IsOpdShift() const 164 { 165 return opndKind == kOpdShift; 166 } 167 IsRegShift()168 bool IsRegShift() const 169 { 170 return opndKind == kOpdRegShift; 171 } 172 IsOpdExtend()173 bool IsOpdExtend() const 174 { 175 return opndKind == kOpdExtend; 176 } 177 IsLabelOpnd()178 virtual bool IsLabelOpnd() const 179 { 180 return false; 181 } 182 IsFuncNameOpnd()183 virtual bool IsFuncNameOpnd() const 184 { 185 return false; 186 } 187 IsCommentOpnd()188 virtual bool IsCommentOpnd() const 189 { 190 return false; 191 } 192 193 virtual Operand *Clone(MemPool &memPool) const = 0; 194 195 /* 196 * A simple implementation here. 197 * Each subclass can elaborate on demand. 198 */ Equals(Operand & op)199 virtual bool Equals(Operand &op) const 200 { 201 return BasicEquals(op) && (&op == this); 202 } 203 BasicEquals(const Operand & op)204 bool BasicEquals(const Operand &op) const 205 { 206 return opndKind == op.GetKind() && size == op.GetSize(); 207 } 208 209 virtual void Dump() const = 0; 210 211 virtual bool Less(const Operand &right) const = 0; 212 213 virtual void Accept(OperandVisitorBase &v) = 0; 214 215 protected: 216 OperandType opndKind; /* operand type */ 217 uint32 size; /* size in bits */ 218 uint64 flag = 0; /* operand property*/ 219 bool isReference = false; 220 }; 221 222 /* RegOperand */ 223 enum RegOperandState : uint32 { kRegOpndNone = 0, kRegOpndSetLow32 = 0x1, kRegOpndSetHigh32 = 0x2 }; 224 225 template <typename VisitableTy> 226 class OperandVisitable : public Operand { 227 public: 228 using Operand::Operand; Accept(OperandVisitorBase & v)229 void Accept(OperandVisitorBase &v) override 230 { 231 if (OperandVisitor<VisitableTy> *typeV = dynamic_cast<OperandVisitor<VisitableTy> *>(&v)) { 232 typeV->Visit(static_cast<VisitableTy *>(this)); 233 } else { 234 /* the type which has no implements */ 235 } 236 } 237 }; 238 239 class RegOperand : public OperandVisitable<RegOperand> { 240 public: 241 RegOperand(regno_t regNum, uint32 size, RegType type, uint32 flg = 0) OperandVisitable(kOpdRegister,size)242 : OperandVisitable(kOpdRegister, size), regNO(regNum), regType(type), validBitsNum(size), regFlag(flg) 243 { 244 } 245 246 ~RegOperand() override = default; 247 using OperandVisitable<RegOperand>::OperandVisitable; 248 Clone(MemPool & memPool)249 Operand *Clone(MemPool &memPool) const override 250 { 251 return memPool.Clone<RegOperand>(*this); 252 } 253 SetValidBitsNum(uint32 validNum)254 void SetValidBitsNum(uint32 validNum) 255 { 256 validBitsNum = validNum; 257 } 258 GetValidBitsNum()259 uint32 GetValidBitsNum() const 260 { 261 return validBitsNum; 262 } 263 IsOfIntClass()264 bool IsOfIntClass() const 265 { 266 return regType == kRegTyInt; 267 } 268 IsOfFloatOrSIMDClass()269 bool IsOfFloatOrSIMDClass() const 270 { 271 return regType == kRegTyFloat; 272 } 273 IsOfCC()274 bool IsOfCC() const 275 { 276 return regType == kRegTyCc; 277 } 278 IsOfVary()279 bool IsOfVary() const 280 { 281 return regType == kRegTyVary; 282 } 283 GetRegisterType()284 RegType GetRegisterType() const 285 { 286 return regType; 287 } 288 SetRegisterType(RegType newTy)289 void SetRegisterType(RegType newTy) 290 { 291 regType = newTy; 292 } 293 IsBBLocalReg()294 virtual bool IsBBLocalReg() const 295 { 296 return isBBLocal; 297 } 298 SetRegNotBBLocal()299 void SetRegNotBBLocal() 300 { 301 isBBLocal = false; 302 } 303 GetRegisterNumber()304 regno_t GetRegisterNumber() const 305 { 306 return regNO; 307 } 308 SetRegisterNumber(regno_t regNum)309 void SetRegisterNumber(regno_t regNum) 310 { 311 regNO = regNum; 312 } 313 Dump()314 void Dump() const override 315 { 316 LogInfo::MapleLogger() << "reg "; 317 LogInfo::MapleLogger() << "size : " << GetSize(); 318 LogInfo::MapleLogger() << " NO_" << GetRegisterNumber(); 319 if (IsReference()) { 320 LogInfo::MapleLogger() << " is_ref"; 321 } 322 }; 323 Less(const Operand & right)324 bool Less(const Operand &right) const override 325 { 326 if (&right == this) { 327 return false; 328 } 329 330 /* For different type. */ 331 if (opndKind != right.GetKind()) { 332 return opndKind < right.GetKind(); 333 } 334 335 auto *rightOpnd = static_cast<const RegOperand *>(&right); 336 337 /* The same type. */ 338 return regNO < rightOpnd->regNO; 339 } 340 Less(const RegOperand & right)341 bool Less(const RegOperand &right) const 342 { 343 return regNO < right.regNO; 344 } 345 RegNumEqual(const RegOperand & right)346 bool RegNumEqual(const RegOperand &right) const 347 { 348 return regNO == right.GetRegisterNumber(); 349 } 350 RegCompare(const RegOperand & right)351 int32 RegCompare(const RegOperand &right) const 352 { 353 return (regNO - right.GetRegisterNumber()); 354 } 355 Equals(Operand & operand)356 bool Equals(Operand &operand) const override 357 { 358 if (!operand.IsRegister()) { 359 return false; 360 } 361 auto &op = static_cast<RegOperand &>(operand); 362 if (&op == this) { 363 return true; 364 } 365 return (BasicEquals(op) && regNO == op.GetRegisterNumber() && regType == op.GetRegisterType() && 366 IsBBLocalReg() == op.IsBBLocalReg()); 367 } 368 IsSameRegNO(const Operand & firstOpnd,const Operand & secondOpnd)369 static bool IsSameRegNO(const Operand &firstOpnd, const Operand &secondOpnd) 370 { 371 if (!firstOpnd.IsRegister() || !secondOpnd.IsRegister()) { 372 return false; 373 } 374 auto &firstReg = static_cast<const RegOperand &>(firstOpnd); 375 auto &secondReg = static_cast<const RegOperand &>(secondOpnd); 376 return firstReg.RegNumEqual(secondReg); 377 } 378 IsSameReg(const Operand & firstOpnd,const Operand & secondOpnd)379 static bool IsSameReg(const Operand &firstOpnd, const Operand &secondOpnd) 380 { 381 if (firstOpnd.GetSize() != secondOpnd.GetSize()) { 382 return false; 383 } 384 return IsSameRegNO(firstOpnd, secondOpnd); 385 } 386 SetOpndSSAForm()387 void SetOpndSSAForm() 388 { 389 isSSAForm = true; 390 } 391 SetOpndOutOfSSAForm()392 void SetOpndOutOfSSAForm() 393 { 394 isSSAForm = false; 395 } 396 IsSSAForm()397 bool IsSSAForm() const 398 { 399 return isSSAForm; 400 } 401 SetRefField(bool newIsRefField)402 void SetRefField(bool newIsRefField) 403 { 404 isRefField = newIsRefField; 405 } 406 IsPhysicalRegister()407 bool IsPhysicalRegister() const 408 { 409 constexpr uint32 maxPhysicalRegisterNumber = 100; 410 return GetRegisterNumber() > 0 && GetRegisterNumber() < maxPhysicalRegisterNumber && !IsOfCC(); 411 } 412 IsVirtualRegister()413 bool IsVirtualRegister() const 414 { 415 return !IsPhysicalRegister(); 416 } 417 IsBBLocalVReg()418 bool IsBBLocalVReg() const 419 { 420 return IsVirtualRegister() && IsBBLocalReg(); 421 } 422 SetIF64Vec()423 void SetIF64Vec() 424 { 425 if64Vec = true; 426 } 427 GetIF64Vec()428 bool GetIF64Vec() const 429 { 430 return if64Vec; 431 } 432 SetVecLanePosition(int32 pos)433 void SetVecLanePosition(int32 pos) 434 { 435 vecLane = static_cast<int16>(pos); 436 } 437 GetVecLanePosition()438 int32 GetVecLanePosition() const 439 { 440 return vecLane; 441 } 442 SetVecLaneSize(uint32 size)443 void SetVecLaneSize(uint32 size) 444 { 445 vecLaneSize = static_cast<uint16>(size); 446 } 447 GetVecLaneSize()448 uint32 GetVecLaneSize() const 449 { 450 return vecLaneSize; 451 } 452 SetVecElementSize(uint32 size)453 void SetVecElementSize(uint32 size) 454 { 455 vecElementSize = size; 456 } 457 GetVecElementSize()458 uint64 GetVecElementSize() const 459 { 460 return vecElementSize; 461 } 462 SetHigh8Bit()463 void SetHigh8Bit() 464 { 465 isHigh8Bit = true; 466 } 467 IsHigh8Bit()468 bool IsHigh8Bit() 469 { 470 return isHigh8Bit; 471 } 472 SetBaseRefOpnd(RegOperand & regOpnd)473 void SetBaseRefOpnd(RegOperand ®Opnd) 474 { 475 baseRefOpnd = ®Opnd; 476 } 477 GetBaseRefOpnd()478 const RegOperand *GetBaseRefOpnd() const 479 { 480 return baseRefOpnd; 481 } 482 GetBaseRefOpnd()483 RegOperand *GetBaseRefOpnd() 484 { 485 return baseRefOpnd; 486 } 487 488 bool operator==(const RegOperand &o) const; 489 490 bool operator<(const RegOperand &o) const; 491 492 protected: 493 regno_t regNO; 494 RegType regType; 495 496 /* 497 * used for EBO(-O1), it can recognize the registers whose use and def are in 498 * different BB. It is true by default. Sometime it should be false such as 499 * when handle intrinsiccall for target 500 * aarch64(AArch64CGFunc::SelectIntrinCall). 501 */ 502 bool isBBLocal = true; 503 uint32 validBitsNum; 504 /* use for SSA analysis */ 505 bool isSSAForm = false; 506 bool isRefField = false; 507 uint32 regFlag = 0; 508 int16 vecLane = -1; /* -1 for whole reg, 0 to 15 to specify each lane one at a time */ 509 uint16 vecLaneSize = 0; /* Number of lanes */ 510 uint64 vecElementSize = 0; /* size of vector element in each lane */ 511 bool if64Vec = false; /* operand returning 64x1's int value in FP/Simd register */ 512 bool isHigh8Bit = false; 513 RegOperand *baseRefOpnd = nullptr; 514 }; /* class RegOperand */ 515 516 enum VaryType : uint8 { 517 kNotVary = 0, 518 kUnAdjustVary, 519 kAdjustVary, 520 }; 521 522 class ImmOperand : public OperandVisitable<ImmOperand> { 523 public: 524 ImmOperand(int64 val, uint32 size, bool isSigned, VaryType isVar = kNotVary, bool isFloat = false) OperandVisitable(kOpdImmediate,size)525 : OperandVisitable(kOpdImmediate, size), value(val), isSigned(isSigned), isVary(isVar), isFmov(isFloat) 526 { 527 } 528 ImmOperand(OperandType type, int64 val, uint32 size, bool isSigned, VaryType isVar = kNotVary, bool isFloat = false) OperandVisitable(type,size)529 : OperandVisitable(type, size), value(val), isSigned(isSigned), isVary(isVar), isFmov(isFloat) 530 { 531 } 532 ImmOperand(const MIRSymbol &symbol, int64 val, int32 relocs, bool isSigned, VaryType isVar = kNotVary, 533 bool isFloat = false) 534 : OperandVisitable(kOpdStImmediate, 0), 535 value(val), 536 isSigned(isSigned), 537 isVary(isVar), 538 isFmov(isFloat), 539 symbol(&symbol), 540 relocs(relocs) 541 { 542 } 543 ~ImmOperand() override = default; 544 using OperandVisitable<ImmOperand>::OperandVisitable; 545 Clone(MemPool & memPool)546 Operand *Clone(MemPool &memPool) const override 547 { 548 return memPool.Clone<ImmOperand>(*this); 549 } 550 GetSymbol()551 const MIRSymbol *GetSymbol() const 552 { 553 return symbol; 554 } 555 GetName()556 const std::string &GetName() const 557 { 558 return symbol->GetName(); 559 } 560 GetRelocs()561 int32 GetRelocs() const 562 { 563 return relocs; 564 } 565 IsInBitSize(uint8 size,uint8 nLowerZeroBits)566 bool IsInBitSize(uint8 size, uint8 nLowerZeroBits) const 567 { 568 return maplebe::IsBitSizeImmediate(static_cast<uint64>(value), size, nLowerZeroBits); 569 } 570 IsBitmaskImmediate()571 bool IsBitmaskImmediate() const 572 { 573 DEBUG_ASSERT(!IsZero(), " 0 is reserved for bitmask immediate"); 574 DEBUG_ASSERT(!IsAllOnes(), " -1 is reserved for bitmask immediate"); 575 return maplebe::IsBitmaskImmediate(static_cast<uint64>(value), static_cast<uint32>(size)); 576 } 577 IsBitmaskImmediate(uint32 destSize)578 bool IsBitmaskImmediate(uint32 destSize) const 579 { 580 DEBUG_ASSERT(!IsZero(), " 0 is reserved for bitmask immediate"); 581 DEBUG_ASSERT(!IsAllOnes(), " -1 is reserved for bitmask immediate"); 582 return maplebe::IsBitmaskImmediate(static_cast<uint64>(value), static_cast<uint32>(destSize)); 583 } 584 IsSingleInstructionMovable()585 bool IsSingleInstructionMovable() const 586 { 587 return (IsMoveWidableImmediate(static_cast<uint64>(value), static_cast<uint32>(size)) || 588 IsMoveWidableImmediate(~static_cast<uint64>(value), static_cast<uint32>(size)) || IsBitmaskImmediate()); 589 } 590 IsSingleInstructionMovable(uint32 destSize)591 bool IsSingleInstructionMovable(uint32 destSize) const 592 { 593 return (IsMoveWidableImmediate(static_cast<uint64>(value), static_cast<uint32>(destSize)) || 594 IsMoveWidableImmediate(~static_cast<uint64>(value), static_cast<uint32>(destSize)) || 595 IsBitmaskImmediate(destSize)); 596 } 597 GetValue()598 int64 GetValue() const 599 { 600 return value; 601 } 602 SetValue(int64 val)603 void SetValue(int64 val) 604 { 605 value = val; 606 } 607 SetVary(VaryType flag)608 void SetVary(VaryType flag) 609 { 610 isVary = flag; 611 } 612 IsZero()613 bool IsZero() const 614 { 615 return value == 0; 616 } 617 GetVary()618 VaryType GetVary() const 619 { 620 return isVary; 621 } 622 IsOne()623 bool IsOne() const 624 { 625 return value == 1; 626 } 627 IsSignedValue()628 bool IsSignedValue() const 629 { 630 return isSigned; 631 } 632 SetSigned()633 void SetSigned() 634 { 635 isSigned = true; 636 } 637 SetSigned(bool flag)638 void SetSigned(bool flag) 639 { 640 isSigned = flag; 641 } 642 IsInBitSizeRot(uint8 size)643 bool IsInBitSizeRot(uint8 size) const 644 { 645 return IsInBitSizeRot(size, value); 646 } 647 IsInBitSizeRot(uint8 size,int64 val)648 static bool IsInBitSizeRot(uint8 size, int64 val) 649 { 650 /* to tell if the val is in a rotate window of size */ 651 #if __GNU_C__ || __clang__ 652 if (val == 0) { 653 return true; 654 } 655 int32 start = __builtin_ctzll(static_cast<uint64>(val)); 656 int32 end = static_cast<int32>(sizeof(val) * kBitsPerByte - __builtin_clzll(static_cast<uint64>(val)) - 1); 657 return (size >= end - start + 1); 658 #else 659 uint8 start = 0; 660 uint8 end = 0; 661 bool isFound = false; 662 CHECK_FATAL(val > 0, "do not perform bit operator operations on signed integers"); 663 for (uint32 i = 0; i < k64BitSize; ++i) { 664 /* check whether the ith bit of val is 1 or not */ 665 if (((static_cast<uint64>(val) >> i) & 0x1) == 0x1) { 666 if (!isFound) { 667 start = i; 668 end = i; 669 isFound = true; 670 } else { 671 end = i; 672 } 673 } 674 } 675 return !isFound || (size >= (end - start) + 1); 676 #endif 677 } 678 IsInValueRange(int32 lowVal,int32 highVal,int32 val)679 static bool IsInValueRange(int32 lowVal, int32 highVal, int32 val) 680 { 681 return val >= lowVal && val <= highVal; 682 } 683 IsNegative()684 bool IsNegative() const 685 { 686 return isSigned && value < 0; 687 } 688 Add(int64 delta)689 void Add(int64 delta) 690 { 691 value += delta; 692 } 693 Negate()694 void Negate() 695 { 696 value = -value; 697 } 698 BitwiseNegate()699 void BitwiseNegate() 700 { 701 value = ~(static_cast<uint64>(value)) & ((1ULL << size) - 1UL); 702 } 703 DivideByPow2(int32 shift)704 void DivideByPow2(int32 shift) 705 { 706 value = (static_cast<uint64>(value)) >> shift; 707 } 708 ModuloByPow2(int32 shift)709 void ModuloByPow2(int32 shift) 710 { 711 value = (static_cast<uint64>(value)) & ((1ULL << shift) - 1UL); 712 } 713 IsAllOnes()714 bool IsAllOnes() const 715 { 716 return value == -1; 717 } 718 IsAllOnes32bit()719 bool IsAllOnes32bit() const 720 { 721 return value == 0x0ffffffffLL; 722 } 723 724 bool operator<(const ImmOperand &iOpnd) const 725 { 726 return value < iOpnd.value || (value == iOpnd.value && isSigned < iOpnd.isSigned) || 727 (value == iOpnd.value && isSigned == iOpnd.isSigned && size < iOpnd.GetSize()); 728 } 729 730 bool operator==(const ImmOperand &iOpnd) const 731 { 732 return (value == iOpnd.value && isSigned == iOpnd.isSigned && size == iOpnd.GetSize()); 733 } 734 735 void Dump() const override; 736 Less(const Operand & right)737 bool Less(const Operand &right) const override 738 { 739 if (&right == this) { 740 return false; 741 } 742 743 /* For different type. */ 744 if (opndKind != right.GetKind()) { 745 return opndKind < right.GetKind(); 746 } 747 748 auto *rightOpnd = static_cast<const ImmOperand *>(&right); 749 750 /* The same type. */ 751 if (isSigned != rightOpnd->isSigned) { 752 return isSigned; 753 } 754 755 if (isVary != rightOpnd->isVary) { 756 return isVary; 757 } 758 759 return value < rightOpnd->value; 760 } 761 Equals(Operand & operand)762 bool Equals(Operand &operand) const override 763 { 764 if (!operand.IsImmediate()) { 765 return false; 766 } 767 auto &op = static_cast<ImmOperand &>(operand); 768 if (&op == this) { 769 return true; 770 } 771 return (BasicEquals(op) && value == op.GetValue() && isSigned == op.IsSignedValue()); 772 } 773 ValueEquals(const ImmOperand & op)774 bool ValueEquals(const ImmOperand &op) const 775 { 776 if (&op == this) { 777 return true; 778 } 779 return (value == op.GetValue() && isSigned == op.IsSignedValue()); 780 } IsFmov()781 bool IsFmov() const 782 { 783 return isFmov; 784 } 785 786 protected: 787 int64 value; 788 bool isSigned; 789 VaryType isVary; 790 bool isFmov = false; 791 const MIRSymbol *symbol; /* for Immediate in symbol form */ 792 int32 relocs; 793 }; 794 795 class OfstOperand : public ImmOperand { 796 public: 797 enum OfstType : uint8 { 798 kSymbolOffset, 799 kImmediateOffset, 800 kSymbolImmediateOffset, 801 }; 802 803 /* only for symbol offset */ OfstOperand(const MIRSymbol & mirSymbol,uint32 size,int32 relocs)804 OfstOperand(const MIRSymbol &mirSymbol, uint32 size, int32 relocs) 805 : ImmOperand(kOpdOffset, 0, size, true, kNotVary, false), 806 offsetType(kSymbolOffset), 807 symbol(&mirSymbol), 808 relocs(relocs) 809 { 810 } 811 /* only for Immediate offset */ 812 OfstOperand(int64 val, uint32 size, VaryType isVar = kNotVary) ImmOperand(kOpdOffset,static_cast<int64> (val),size,true,isVar,false)813 : ImmOperand(kOpdOffset, static_cast<int64>(val), size, true, isVar, false), 814 offsetType(kImmediateOffset), 815 symbol(nullptr), 816 relocs(0) 817 { 818 } 819 /* for symbol and Immediate offset */ 820 OfstOperand(const MIRSymbol &mirSymbol, int64 val, uint32 size, int32 relocs, VaryType isVar = kNotVary) ImmOperand(kOpdOffset,val,size,true,isVar,false)821 : ImmOperand(kOpdOffset, val, size, true, isVar, false), 822 offsetType(kSymbolImmediateOffset), 823 symbol(&mirSymbol), 824 relocs(relocs) 825 { 826 } 827 ~OfstOperand()828 ~OfstOperand() override 829 { 830 symbol = nullptr; 831 } 832 Clone(MemPool & memPool)833 Operand *Clone(MemPool &memPool) const override 834 { 835 return memPool.Clone<OfstOperand>(*this); 836 } 837 IsSymOffset()838 bool IsSymOffset() const 839 { 840 return offsetType == kSymbolOffset; 841 } IsImmOffset()842 bool IsImmOffset() const 843 { 844 return offsetType == kImmediateOffset; 845 } IsSymAndImmOffset()846 bool IsSymAndImmOffset() const 847 { 848 return offsetType == kSymbolImmediateOffset; 849 } 850 GetSymbol()851 const MIRSymbol *GetSymbol() const 852 { 853 return symbol; 854 } 855 GetSymbolName()856 const std::string &GetSymbolName() const 857 { 858 return symbol->GetName(); 859 } 860 GetOffsetValue()861 int64 GetOffsetValue() const 862 { 863 return GetValue(); 864 } 865 SetOffsetValue(int32 offVal)866 void SetOffsetValue(int32 offVal) 867 { 868 SetValue(static_cast<int64>(offVal)); 869 } 870 AdjustOffset(int32 delta)871 void AdjustOffset(int32 delta) 872 { 873 Add(static_cast<int64>(delta)); 874 } 875 876 bool operator==(const OfstOperand &opnd) const 877 { 878 return (offsetType == opnd.offsetType && symbol == opnd.symbol && ImmOperand::operator==(opnd) && 879 relocs == opnd.relocs); 880 } 881 882 bool operator<(const OfstOperand &opnd) const 883 { 884 return (offsetType < opnd.offsetType || (offsetType == opnd.offsetType && symbol < opnd.symbol) || 885 (offsetType == opnd.offsetType && symbol == opnd.symbol && GetValue() < opnd.GetValue())); 886 } 887 Dump()888 void Dump() const override 889 { 890 if (IsImmOffset()) { 891 LogInfo::MapleLogger() << "ofst:" << GetValue(); 892 } else { 893 LogInfo::MapleLogger() << GetSymbolName(); 894 LogInfo::MapleLogger() << "+offset:" << GetValue(); 895 } 896 } 897 898 private: 899 OfstType offsetType; 900 const MIRSymbol *symbol; 901 int32 relocs; 902 }; 903 904 /* 905 * Table C1-6 A64 Load/Store addressing modes 906 * | Offset 907 * Addressing Mode | Immediate | Register | Extended Register 908 * 909 * Base register only | [base{,#0}] | - | - 910 * (no offset) | B_OI_NONE | | 911 * imm=0 912 * 913 * Base plus offset | [base{,#imm}] | [base,Xm{,LSL #imm}] | [base,Wm,(S|U)XTW 914 * {#imm}] B_OI_NONE | B_OR_X | B_OR_X imm=0,1 (0,3) | 915 * imm=00,01,10,11 (0/2,s/u) 916 * 917 * Pre-indexed | [base, #imm]! | - | - 918 * 919 * Post-indexed | [base], #imm | [base], Xm(a) | - 920 * 921 * Literal | label | - | - 922 * (PC-relative) 923 * 924 * a) The post-indexed by register offset mode can be used with the SIMD 925 * Load/Store structure instructions described in Load/Store Vector on page 926 * C3-154. Otherwise the post-indexed by register offset mode is not available. 927 */ 928 class MemOperand : public OperandVisitable<MemOperand> { 929 public: 930 enum AArch64AddressingMode : uint8 { 931 kAddrModeUndef, 932 /* AddrMode_BO, base, offset. EA = [base] + offset; */ 933 kAddrModeBOi, /* INTACT: EA = [base]+immediate */ 934 /* 935 * PRE: base += immediate, EA = [base] 936 * POST: EA = [base], base += immediate 937 */ 938 kAddrModeBOrX, /* EA = [base]+Extend([offreg/idxreg]), OR=Wn/Xn */ 939 kAddrModeLiteral, /* AArch64 insruction LDR takes literal and */ 940 /* 941 * "calculates an address from the PC value and an immediate offset, 942 * loads a word from memory, and writes it to a register." 943 */ 944 kAddrModeLo12Li // EA = [base] + #:lo12:Label+immediate. (Example: [x0, 945 // #:lo12:__Label300+456] 946 }; 947 /* 948 * ARMv8-A A64 ISA Overview by Matteo Franchin @ ARM 949 * (presented at 64-bit terminal platform on ARM. Sep. 2015) p.14 950 * o Address to load from/store to is a 64-bit base register + an optional 951 * offset LDR X0, [X1] ; Load from address held in X1 STR X0, [X1] ; Store to 952 * address held in X1 953 * 954 * o Offset can be an immediate or a register 955 * LDR X0, [X1, #8] ; Load from address [X1 + 8 bytes] 956 * LDR X0, [X1, #-8] ; Load with negative offset 957 * LDR X0, [X1, X2] ; Load from address [X1 + X2] 958 * 959 * o A Wn register offset needs to be extended to 64 bits 960 * LDR X0, [X1, W2, SXTW] ; Sign-extend offset in W2 961 * LDR X0, [X1, W2, UXTW] ; Zero-extend offset in W2 962 * 963 * o Both Xn and Wn register offsets can include an optional left-shift 964 * LDR X0, [X1, W2, UXTW #2] ; Zero-extend offset in W2 & left-shift by 2 965 * LDR X0, [X1, X2, LSL #2] ; Left-shift offset in X2 by 2 966 * 967 * p.15 968 * Addressing Modes Analogous C Code 969 * int *intptr = ... // X1 970 * int out; // W0 971 * o Simple: X1 is not changed 972 * LDR W0, [X1] out = *intptr; 973 * o Offset: X1 is not changed 974 * LDR W0, [X1, #4] out = intptr[1]; 975 * o Pre-indexed: X1 changed before load 976 * LDR W0, [X1, #4]! =|ADD X1,X1,#4 out = *(++intptr); 977 * |LDR W0,[X1] 978 * o Post-indexed: X1 changed after load 979 * LDR W0, [X1], #4 =|LDR W0,[X1] out = *(intptr++); 980 * |ADD X1,X1,#4 981 */ 982 enum ExtendInfo : uint8 { 983 kShiftZero = 0x1, 984 kShiftOne = 0x2, 985 kShiftTwo = 0x4, 986 kShiftThree = 0x8, 987 kUnsignedExtend = 0x10, 988 kSignExtend = 0x20 989 }; 990 991 enum IndexingOption : uint8 { 992 kIntact, /* base register stays the same */ 993 kPreIndex, /* base register gets changed before load */ 994 kPostIndex, /* base register gets changed after load */ 995 }; 996 MemOperand(uint32 size)997 MemOperand(uint32 size) : OperandVisitable(Operand::kOpdMem, size) {} MemOperand(uint32 size,const MIRSymbol & mirSymbol)998 MemOperand(uint32 size, const MIRSymbol &mirSymbol) : OperandVisitable(Operand::kOpdMem, size), symbol(&mirSymbol) 999 { 1000 } 1001 1002 MemOperand(uint32 size, RegOperand *baseOp, RegOperand *indexOp, ImmOperand *ofstOp, const MIRSymbol *mirSymbol, 1003 ImmOperand *scaleOp = nullptr) OperandVisitable(Operand::kOpdMem,size)1004 : OperandVisitable(Operand::kOpdMem, size), 1005 baseOpnd(baseOp), 1006 indexOpnd(indexOp), 1007 offsetOpnd(ofstOp), 1008 scaleOpnd(scaleOp), 1009 symbol(mirSymbol) 1010 { 1011 } 1012 1013 MemOperand(RegOperand *base, OfstOperand *offset, uint32 size, IndexingOption idxOpt = kIntact) OperandVisitable(Operand::kOpdMem,size)1014 : OperandVisitable(Operand::kOpdMem, size), 1015 baseOpnd(base), 1016 indexOpnd(nullptr), 1017 offsetOpnd(offset), 1018 symbol(nullptr), 1019 addrMode(kAddrModeBOi), 1020 extend(0), 1021 idxOpt(idxOpt), 1022 noExtend(false), 1023 isStackMem(false) 1024 { 1025 } 1026 MemOperand(AArch64AddressingMode mode,uint32 size,RegOperand & base,RegOperand * index,ImmOperand * offset,const MIRSymbol * sym)1027 MemOperand(AArch64AddressingMode mode, uint32 size, RegOperand &base, RegOperand *index, ImmOperand *offset, 1028 const MIRSymbol *sym) 1029 : OperandVisitable(Operand::kOpdMem, size), 1030 baseOpnd(&base), 1031 indexOpnd(index), 1032 offsetOpnd(offset), 1033 symbol(sym), 1034 addrMode(mode), 1035 extend(0), 1036 idxOpt(kIntact), 1037 noExtend(false), 1038 isStackMem(false) 1039 { 1040 } 1041 MemOperand(AArch64AddressingMode mode,uint32 size,RegOperand & base,RegOperand & index,ImmOperand * offset,const MIRSymbol & sym,bool noExtend)1042 MemOperand(AArch64AddressingMode mode, uint32 size, RegOperand &base, RegOperand &index, ImmOperand *offset, 1043 const MIRSymbol &sym, bool noExtend) 1044 : OperandVisitable(Operand::kOpdMem, size), 1045 baseOpnd(&base), 1046 indexOpnd(&index), 1047 offsetOpnd(offset), 1048 symbol(&sym), 1049 addrMode(mode), 1050 extend(0), 1051 idxOpt(kIntact), 1052 noExtend(noExtend), 1053 isStackMem(false) 1054 { 1055 } 1056 1057 MemOperand(AArch64AddressingMode mode, uint32 dSize, RegOperand &baseOpnd, RegOperand &indexOpnd, uint32 shift, 1058 bool isSigned = false) OperandVisitable(Operand::kOpdMem,dSize)1059 : OperandVisitable(Operand::kOpdMem, dSize), 1060 baseOpnd(&baseOpnd), 1061 indexOpnd(&indexOpnd), 1062 offsetOpnd(nullptr), 1063 symbol(nullptr), 1064 addrMode(mode), 1065 extend((isSigned ? kSignExtend : kUnsignedExtend) | (1U << shift)), 1066 idxOpt(kIntact), 1067 noExtend(false), 1068 isStackMem(false) 1069 { 1070 } 1071 MemOperand(AArch64AddressingMode mode,uint32 dSize,const MIRSymbol & sym)1072 MemOperand(AArch64AddressingMode mode, uint32 dSize, const MIRSymbol &sym) 1073 : OperandVisitable(Operand::kOpdMem, dSize), 1074 baseOpnd(nullptr), 1075 indexOpnd(nullptr), 1076 offsetOpnd(nullptr), 1077 symbol(&sym), 1078 addrMode(mode), 1079 extend(0), 1080 idxOpt(kIntact), 1081 noExtend(false), 1082 isStackMem(false) 1083 { 1084 DEBUG_ASSERT(mode == kAddrModeLiteral, 1085 "This constructor version is supposed to be used with " 1086 "AddrMode_Literal only"); 1087 } 1088 1089 /* Copy constructor */ MemOperand(const MemOperand & memOpnd)1090 explicit MemOperand(const MemOperand &memOpnd) 1091 : OperandVisitable(Operand::kOpdMem, memOpnd.GetSize()), 1092 baseOpnd(memOpnd.baseOpnd), 1093 indexOpnd(memOpnd.indexOpnd), 1094 offsetOpnd(memOpnd.offsetOpnd), 1095 scaleOpnd(memOpnd.scaleOpnd), 1096 symbol(memOpnd.symbol), 1097 memoryOrder(memOpnd.memoryOrder), 1098 addrMode(memOpnd.addrMode), 1099 extend(memOpnd.extend), 1100 idxOpt(memOpnd.idxOpt), 1101 noExtend(memOpnd.noExtend), 1102 isStackMem(memOpnd.isStackMem), 1103 isStackArgMem(memOpnd.isStackArgMem) 1104 { 1105 } 1106 1107 MemOperand &operator=(const MemOperand &memOpnd) = default; 1108 1109 ~MemOperand() override = default; 1110 using OperandVisitable<MemOperand>::OperandVisitable; 1111 Clone(MemPool & memPool)1112 MemOperand *Clone(MemPool &memPool) const override 1113 { 1114 return memPool.Clone<MemOperand>(*this); 1115 } 1116 Dump()1117 void Dump() const override {}; 1118 GetBaseRegister()1119 RegOperand *GetBaseRegister() const 1120 { 1121 return baseOpnd; 1122 } 1123 SetBaseRegister(RegOperand & regOpnd)1124 void SetBaseRegister(RegOperand ®Opnd) 1125 { 1126 baseOpnd = ®Opnd; 1127 } 1128 GetIndexRegister()1129 RegOperand *GetIndexRegister() const 1130 { 1131 return indexOpnd; 1132 } 1133 SetIndexRegister(RegOperand & regOpnd)1134 void SetIndexRegister(RegOperand ®Opnd) 1135 { 1136 indexOpnd = ®Opnd; 1137 } 1138 GetOffsetOperand()1139 ImmOperand *GetOffsetOperand() const 1140 { 1141 return offsetOpnd; 1142 } 1143 SetOffsetOperand(ImmOperand & oftOpnd)1144 void SetOffsetOperand(ImmOperand &oftOpnd) 1145 { 1146 offsetOpnd = &oftOpnd; 1147 } 1148 GetScaleOperand()1149 const ImmOperand *GetScaleOperand() const 1150 { 1151 return scaleOpnd; 1152 } 1153 SetScaleOperand(ImmOperand & scaOpnd)1154 void SetScaleOperand(ImmOperand &scaOpnd) 1155 { 1156 scaleOpnd = &scaOpnd; 1157 } 1158 GetSymbol()1159 const MIRSymbol *GetSymbol() const 1160 { 1161 return symbol; 1162 } 1163 SetMemoryOrdering(uint32 memOrder)1164 void SetMemoryOrdering(uint32 memOrder) 1165 { 1166 memoryOrder |= memOrder; 1167 } 1168 HasMemoryOrdering(uint32 memOrder)1169 bool HasMemoryOrdering(uint32 memOrder) const 1170 { 1171 return (memoryOrder & memOrder) != 0; 1172 } 1173 SetAccessSize(uint8 size)1174 void SetAccessSize(uint8 size) 1175 { 1176 accessSize = size; 1177 } 1178 GetAccessSize()1179 uint8 GetAccessSize() const 1180 { 1181 return accessSize; 1182 } 1183 GetAddrMode()1184 AArch64AddressingMode GetAddrMode() const 1185 { 1186 return addrMode; 1187 } 1188 GetSymbolName()1189 const std::string &GetSymbolName() const 1190 { 1191 return GetSymbol()->GetName(); 1192 } 1193 IsStackMem()1194 bool IsStackMem() const 1195 { 1196 return isStackMem; 1197 } 1198 SetStackMem(bool isStack)1199 void SetStackMem(bool isStack) 1200 { 1201 isStackMem = isStack; 1202 } 1203 IsStackArgMem()1204 bool IsStackArgMem() const 1205 { 1206 return isStackArgMem; 1207 } 1208 SetStackArgMem(bool isStackArg)1209 void SetStackArgMem(bool isStackArg) 1210 { 1211 isStackArgMem = isStackArg; 1212 } 1213 1214 Operand *GetOffset() const; 1215 GetOffsetImmediate()1216 OfstOperand *GetOffsetImmediate() const 1217 { 1218 return static_cast<OfstOperand *>(GetOffsetOperand()); 1219 } 1220 1221 /* Returns N where alignment == 2^N */ GetImmediateOffsetAlignment(uint32 dSize)1222 static uint32 GetImmediateOffsetAlignment(uint32 dSize) 1223 { 1224 DEBUG_ASSERT(dSize >= k8BitSize, "error val:dSize"); 1225 DEBUG_ASSERT(dSize <= k128BitSize, "error val:dSize"); 1226 DEBUG_ASSERT((dSize & (dSize - 1)) == 0, "error val:dSize"); 1227 /* dSize==8: 0, dSize==16 : 1, dSize==32: 2, dSize==64: 3 */ 1228 return __builtin_ctz(dSize) - kBaseOffsetAlignment; 1229 } 1230 GetMaxPIMM(uint32 dSize)1231 static int32 GetMaxPIMM(uint32 dSize) 1232 { 1233 dSize = dSize > k64BitSize ? k64BitSize : dSize; 1234 DEBUG_ASSERT(dSize >= k8BitSize, "error val:dSize"); 1235 DEBUG_ASSERT(dSize <= k128BitSize, "error val:dSize"); 1236 DEBUG_ASSERT((dSize & (dSize - 1)) == 0, "error val:dSize"); 1237 uint32 alignment = GetImmediateOffsetAlignment(dSize); 1238 /* alignment is between kAlignmentOf8Bit and kAlignmentOf64Bit */ 1239 DEBUG_ASSERT(alignment >= kOffsetAlignmentOf8Bit, "error val:alignment"); 1240 DEBUG_ASSERT(alignment <= kOffsetAlignmentOf128Bit, "error val:alignment"); 1241 return (kMaxPimm[alignment]); 1242 } 1243 GetMaxPairPIMM(uint32 dSize)1244 static int32 GetMaxPairPIMM(uint32 dSize) 1245 { 1246 DEBUG_ASSERT(dSize >= k32BitSize, "error val:dSize"); 1247 DEBUG_ASSERT(dSize <= k128BitSize, "error val:dSize"); 1248 DEBUG_ASSERT((dSize & (dSize - 1)) == 0, "error val:dSize"); 1249 uint32 alignment = GetImmediateOffsetAlignment(dSize); 1250 /* alignment is between kAlignmentOf8Bit and kAlignmentOf64Bit */ 1251 DEBUG_ASSERT(alignment >= kOffsetAlignmentOf32Bit, "error val:alignment"); 1252 DEBUG_ASSERT(alignment <= kOffsetAlignmentOf128Bit, "error val:alignment"); 1253 return (kMaxPairPimm[alignment - k2BitSize]); 1254 } 1255 IsOffsetMisaligned(uint32 dSize)1256 bool IsOffsetMisaligned(uint32 dSize) const 1257 { 1258 DEBUG_ASSERT(dSize >= k8BitSize, "error val:dSize"); 1259 DEBUG_ASSERT(dSize <= k128BitSize, "error val:dSize"); 1260 DEBUG_ASSERT((dSize & (dSize - 1)) == 0, "error val:dSize"); 1261 if (dSize == k8BitSize || addrMode != kAddrModeBOi) { 1262 return false; 1263 } 1264 OfstOperand *ofstOpnd = GetOffsetImmediate(); 1265 if (ofstOpnd->GetOffsetValue() >= kNegative256BitSize && ofstOpnd->GetOffsetValue() < k256BitSizeInt) { 1266 return false; 1267 } 1268 return ((static_cast<uint32>(ofstOpnd->GetOffsetValue()) & 1269 static_cast<uint32>((1U << static_cast<uint32>(GetImmediateOffsetAlignment(dSize))) - 1)) != 0); 1270 } 1271 IsSIMMOffsetOutOfRange(int64 offset,bool is64bit,bool isLDSTPair)1272 static bool IsSIMMOffsetOutOfRange(int64 offset, bool is64bit, bool isLDSTPair) 1273 { 1274 if (!isLDSTPair) { 1275 return (offset < kMinSimm32 || offset > kMaxSimm32); 1276 } 1277 if (is64bit) { 1278 return (offset < kMinSimm64 || offset > kMaxSimm64Pair) || (static_cast<uint64>(offset) & k7BitSize); 1279 } 1280 return (offset < kMinSimm32 || offset > kMaxSimm32Pair) || (static_cast<uint64>(offset) & k3BitSize); 1281 } 1282 IsPIMMOffsetOutOfRange(int32 offset,uint32 dSize)1283 static bool IsPIMMOffsetOutOfRange(int32 offset, uint32 dSize) 1284 { 1285 DEBUG_ASSERT(dSize >= k8BitSize, "error val:dSize"); 1286 DEBUG_ASSERT(dSize <= k128BitSize, "error val:dSize"); 1287 DEBUG_ASSERT((dSize & (dSize - 1)) == 0, "error val:dSize"); 1288 return (offset < 0 || offset > GetMaxPIMM(dSize)); 1289 } 1290 1291 bool operator<(const MemOperand &opnd) const 1292 { 1293 if (addrMode != opnd.addrMode) { 1294 return addrMode < opnd.addrMode; 1295 } 1296 if (GetBaseRegister() != opnd.GetBaseRegister()) { 1297 return GetBaseRegister() < opnd.GetBaseRegister(); 1298 } 1299 if (GetIndexRegister() != opnd.GetIndexRegister()) { 1300 return GetIndexRegister() < opnd.GetIndexRegister(); 1301 } 1302 if (GetOffsetOperand() != opnd.GetOffsetOperand()) { 1303 return GetOffsetOperand() < opnd.GetOffsetOperand(); 1304 } 1305 if (GetSymbol() != opnd.GetSymbol()) { 1306 return GetSymbol() < opnd.GetSymbol(); 1307 } 1308 if (GetSize() != opnd.GetSize()) { 1309 return GetSize() < opnd.GetSize(); 1310 } 1311 if (extend != opnd.extend) { 1312 return extend < opnd.extend; 1313 } 1314 return false; 1315 } 1316 1317 bool operator==(const MemOperand &opnd) const 1318 { 1319 return (GetSize() == opnd.GetSize()) && (addrMode == opnd.addrMode) && (extend == opnd.extend) && 1320 (GetBaseRegister() == opnd.GetBaseRegister()) && (GetIndexRegister() == opnd.GetIndexRegister()) && 1321 (GetSymbol() == opnd.GetSymbol()) && (GetOffsetOperand() == opnd.GetOffsetOperand()); 1322 } 1323 GetMemVaryType()1324 VaryType GetMemVaryType() const 1325 { 1326 Operand *ofstOpnd = GetOffsetOperand(); 1327 if (ofstOpnd != nullptr) { 1328 auto *opnd = static_cast<OfstOperand *>(ofstOpnd); 1329 return opnd->GetVary(); 1330 } 1331 return kNotVary; 1332 } 1333 SetAddrMode(AArch64AddressingMode val)1334 void SetAddrMode(AArch64AddressingMode val) 1335 { 1336 addrMode = val; 1337 } 1338 IsExtendedRegisterMode()1339 bool IsExtendedRegisterMode() const 1340 { 1341 return addrMode == kAddrModeBOrX; 1342 } 1343 UpdateExtend(ExtendInfo flag)1344 void UpdateExtend(ExtendInfo flag) 1345 { 1346 extend = flag | (1U << ShiftAmount()); 1347 } 1348 SignedExtend()1349 bool SignedExtend() const 1350 { 1351 return IsExtendedRegisterMode() && ((extend & kSignExtend) != 0); 1352 } 1353 UnsignedExtend()1354 bool UnsignedExtend() const 1355 { 1356 return IsExtendedRegisterMode() && !SignedExtend(); 1357 } 1358 ShiftAmount()1359 uint32 ShiftAmount() const 1360 { 1361 uint32 scale = extend & 0xF; 1362 /* 8 is 1 << 3, 4 is 1 << 2, 2 is 1 << 1, 1 is 1 << 0; */ 1363 return (scale == 8) ? 3 : ((scale == 4) ? 2 : ((scale == 2) ? 1 : 0)); 1364 } 1365 ShouldEmitExtend()1366 bool ShouldEmitExtend() const 1367 { 1368 return !noExtend && ((extend & 0x3F) != 0); 1369 } 1370 GetIndexOpt()1371 IndexingOption GetIndexOpt() const 1372 { 1373 return idxOpt; 1374 } 1375 SetIndexOpt(IndexingOption newidxOpt)1376 void SetIndexOpt(IndexingOption newidxOpt) 1377 { 1378 idxOpt = newidxOpt; 1379 } 1380 GetNoExtend()1381 bool GetNoExtend() const 1382 { 1383 return noExtend; 1384 } 1385 SetNoExtend(bool val)1386 void SetNoExtend(bool val) 1387 { 1388 noExtend = val; 1389 } 1390 GetExtend()1391 uint32 GetExtend() const 1392 { 1393 return extend; 1394 } 1395 SetExtend(uint32 val)1396 void SetExtend(uint32 val) 1397 { 1398 extend = val; 1399 } 1400 IsIntactIndexed()1401 bool IsIntactIndexed() const 1402 { 1403 return idxOpt == kIntact; 1404 } 1405 IsPostIndexed()1406 bool IsPostIndexed() const 1407 { 1408 return idxOpt == kPostIndex; 1409 } 1410 IsPreIndexed()1411 bool IsPreIndexed() const 1412 { 1413 return idxOpt == kPreIndex; 1414 } 1415 GetExtendAsString()1416 std::string GetExtendAsString() const 1417 { 1418 if (GetIndexRegister()->GetSize() == k64BitSize) { 1419 return std::string("LSL"); 1420 } 1421 return ((extend & kSignExtend) != 0) ? std::string("SXTW") : std::string("UXTW"); 1422 } 1423 1424 /* Return true if given operand has the same base reg and offset with this. */ 1425 bool Equals(Operand &op) const override; 1426 bool Equals(const MemOperand &op) const; 1427 bool Less(const Operand &right) const override; 1428 1429 private: 1430 RegOperand *baseOpnd = nullptr; /* base register */ 1431 RegOperand *indexOpnd = nullptr; /* index register */ 1432 ImmOperand *offsetOpnd = nullptr; /* offset immediate */ 1433 ImmOperand *scaleOpnd = nullptr; 1434 const MIRSymbol *symbol; /* AddrMode_Literal */ 1435 uint32 memoryOrder = 0; 1436 uint8 accessSize = 0; /* temp, must be set right before use everytime. */ 1437 AArch64AddressingMode addrMode = kAddrModeBOi; 1438 uint32 extend = false; /* used with offset register ; AddrMode_B_OR_X */ 1439 IndexingOption idxOpt = kIntact; /* used with offset immediate ; AddrMode_B_OI */ 1440 bool noExtend = false; 1441 bool isStackMem = false; 1442 bool isStackArgMem = false; 1443 }; 1444 1445 class LabelOperand : public OperandVisitable<LabelOperand> { 1446 public: LabelOperand(const char * parent,LabelIdx labIdx)1447 LabelOperand(const char *parent, LabelIdx labIdx) 1448 : OperandVisitable(kOpdBBAddress, 0), labelIndex(labIdx), parentFunc(parent), orderID(-1u) 1449 { 1450 } 1451 1452 ~LabelOperand() override = default; 1453 using OperandVisitable<LabelOperand>::OperandVisitable; 1454 Clone(MemPool & memPool)1455 Operand *Clone(MemPool &memPool) const override 1456 { 1457 return memPool.Clone<LabelOperand>(*this); 1458 } 1459 IsLabelOpnd()1460 bool IsLabelOpnd() const override 1461 { 1462 return true; 1463 } 1464 GetLabelIndex()1465 LabelIdx GetLabelIndex() const 1466 { 1467 return labelIndex; 1468 } 1469 GetParentFunc()1470 const std::string &GetParentFunc() const 1471 { 1472 return parentFunc; 1473 } 1474 GetLabelOrder()1475 LabelIDOrder GetLabelOrder() const 1476 { 1477 return orderID; 1478 } 1479 SetLabelOrder(LabelIDOrder idx)1480 void SetLabelOrder(LabelIDOrder idx) 1481 { 1482 orderID = idx; 1483 } 1484 1485 void Dump() const override; 1486 Less(const Operand & right)1487 bool Less(const Operand &right) const override 1488 { 1489 if (&right == this) { 1490 return false; 1491 } 1492 1493 /* For different type. */ 1494 if (opndKind != right.GetKind()) { 1495 return opndKind < right.GetKind(); 1496 } 1497 1498 auto *rightOpnd = static_cast<const LabelOperand *>(&right); 1499 1500 int32 nRes = strcmp(parentFunc.c_str(), rightOpnd->parentFunc.c_str()); 1501 if (nRes == 0) { 1502 return labelIndex < rightOpnd->labelIndex; 1503 } else { 1504 return nRes < 0; 1505 } 1506 } 1507 Equals(Operand & operand)1508 bool Equals(Operand &operand) const override 1509 { 1510 if (!operand.IsLabel()) { 1511 return false; 1512 } 1513 auto &op = static_cast<LabelOperand &>(operand); 1514 return ((&op == this) || (op.GetLabelIndex() == labelIndex)); 1515 } 1516 1517 protected: 1518 LabelIdx labelIndex; 1519 const std::string parentFunc; 1520 1521 private: 1522 /* this index records the order this label is defined during code emit. */ 1523 LabelIDOrder orderID = -1u; 1524 }; 1525 1526 class ListOperand : public OperandVisitable<ListOperand> { 1527 public: ListOperand(MapleAllocator & allocator)1528 explicit ListOperand(MapleAllocator &allocator) 1529 : OperandVisitable(Operand::kOpdList, 0), opndList(allocator.Adapter()) 1530 { 1531 } 1532 1533 ~ListOperand() override = default; 1534 1535 using OperandVisitable<ListOperand>::OperandVisitable; 1536 Clone(MemPool & memPool)1537 Operand *Clone(MemPool &memPool) const override 1538 { 1539 return memPool.Clone<ListOperand>(*this); 1540 } 1541 PushOpnd(RegOperand & opnd)1542 void PushOpnd(RegOperand &opnd) 1543 { 1544 opndList.push_back(&opnd); 1545 } 1546 GetOperands()1547 MapleList<RegOperand *> &GetOperands() 1548 { 1549 return opndList; 1550 } 1551 Dump()1552 void Dump() const override 1553 { 1554 for (auto it = opndList.begin(); it != opndList.end();) { 1555 (*it)->Dump(); 1556 LogInfo::MapleLogger() << (++it == opndList.end() ? "" : " ,"); 1557 } 1558 } 1559 Less(const Operand & right)1560 bool Less(const Operand &right) const override 1561 { 1562 /* For different type. */ 1563 if (opndKind != right.GetKind()) { 1564 return opndKind < right.GetKind(); 1565 } 1566 1567 DEBUG_ASSERT(false, "We don't need to compare list operand."); 1568 return false; 1569 } 1570 Equals(Operand & operand)1571 bool Equals(Operand &operand) const override 1572 { 1573 if (!operand.IsList()) { 1574 return false; 1575 } 1576 auto &op = static_cast<ListOperand &>(operand); 1577 return (&op == this); 1578 } 1579 1580 protected: 1581 MapleList<RegOperand *> opndList; 1582 }; 1583 1584 /* representing for global variables address */ 1585 class StImmOperand : public OperandVisitable<StImmOperand> { 1586 public: StImmOperand(const MIRSymbol & symbol,int64 offset,int32 relocs)1587 StImmOperand(const MIRSymbol &symbol, int64 offset, int32 relocs) 1588 : OperandVisitable(kOpdStImmediate, 0), symbol(&symbol), offset(offset), relocs(relocs) 1589 { 1590 } 1591 1592 ~StImmOperand() override = default; 1593 using OperandVisitable<StImmOperand>::OperandVisitable; 1594 Clone(MemPool & memPool)1595 Operand *Clone(MemPool &memPool) const override 1596 { 1597 return memPool.Clone<StImmOperand>(*this); 1598 } 1599 GetSymbol()1600 const MIRSymbol *GetSymbol() const 1601 { 1602 return symbol; 1603 } 1604 GetName()1605 const std::string &GetName() const 1606 { 1607 return symbol->GetName(); 1608 } 1609 GetOffset()1610 int64 GetOffset() const 1611 { 1612 return offset; 1613 } 1614 SetOffset(int64 newOffset)1615 void SetOffset(int64 newOffset) 1616 { 1617 offset = newOffset; 1618 } 1619 GetRelocs()1620 int32 GetRelocs() const 1621 { 1622 return relocs; 1623 } 1624 1625 bool operator==(const StImmOperand &opnd) const 1626 { 1627 return (symbol == opnd.symbol && offset == opnd.offset && relocs == opnd.relocs); 1628 } 1629 1630 bool operator<(const StImmOperand &opnd) const 1631 { 1632 return (symbol < opnd.symbol || (symbol == opnd.symbol && offset < opnd.offset) || 1633 (symbol == opnd.symbol && offset == opnd.offset && relocs < opnd.relocs)); 1634 } 1635 1636 bool Less(const Operand &right) const override; 1637 Dump()1638 void Dump() const override 1639 { 1640 CHECK_FATAL(false, "dont run here"); 1641 } 1642 1643 private: 1644 const MIRSymbol *symbol; 1645 int64 offset; 1646 int32 relocs; 1647 }; 1648 1649 class ExtendShiftOperand : public OperandVisitable<ExtendShiftOperand> { 1650 public: 1651 /* if and only if at least one register is WSP, ARM Recommends use of the LSL 1652 * operator name rathe than UXTW */ 1653 enum ExtendOp : uint8 { 1654 kUndef, 1655 kUXTB, 1656 kUXTH, 1657 kUXTW, /* equal to lsl in 32bits */ 1658 kUXTX, /* equal to lsl in 64bits */ 1659 kSXTB, 1660 kSXTH, 1661 kSXTW, 1662 kSXTX, 1663 }; 1664 ExtendShiftOperand(ExtendOp op,uint32 amt,int32 bitLen)1665 ExtendShiftOperand(ExtendOp op, uint32 amt, int32 bitLen) 1666 : OperandVisitable(Operand::kOpdExtend, bitLen), extendOp(op), shiftAmount(amt) 1667 { 1668 } 1669 1670 ~ExtendShiftOperand() override = default; 1671 using OperandVisitable<ExtendShiftOperand>::OperandVisitable; 1672 Clone(MemPool & memPool)1673 Operand *Clone(MemPool &memPool) const override 1674 { 1675 return memPool.Clone<ExtendShiftOperand>(*this); 1676 } 1677 GetShiftAmount()1678 uint32 GetShiftAmount() const 1679 { 1680 return shiftAmount; 1681 } 1682 GetExtendOp()1683 ExtendOp GetExtendOp() const 1684 { 1685 return extendOp; 1686 } 1687 1688 bool Less(const Operand &right) const override; 1689 Dump()1690 void Dump() const override 1691 { 1692 CHECK_FATAL(false, "dont run here"); 1693 } 1694 1695 private: 1696 ExtendOp extendOp; 1697 uint32 shiftAmount; 1698 }; 1699 1700 class BitShiftOperand : public OperandVisitable<BitShiftOperand> { 1701 public: 1702 enum ShiftOp : uint8 { 1703 kUndef, 1704 kLSL, /* logical shift left */ 1705 kLSR, /* logical shift right */ 1706 kASR, /* arithmetic shift right */ 1707 }; 1708 1709 /* bitlength is equal to 5 or 6 */ BitShiftOperand(ShiftOp op,uint32 amt,int32 bitLen)1710 BitShiftOperand(ShiftOp op, uint32 amt, int32 bitLen) 1711 : OperandVisitable(Operand::kOpdShift, bitLen), shiftOp(op), shiftAmount(amt) 1712 { 1713 } 1714 1715 ~BitShiftOperand() override = default; 1716 using OperandVisitable<BitShiftOperand>::OperandVisitable; 1717 Clone(MemPool & memPool)1718 Operand *Clone(MemPool &memPool) const override 1719 { 1720 return memPool.Clone<BitShiftOperand>(*this); 1721 } 1722 Less(const Operand & right)1723 bool Less(const Operand &right) const override 1724 { 1725 if (&right == this) { 1726 return false; 1727 } 1728 1729 /* For different type. */ 1730 if (GetKind() != right.GetKind()) { 1731 return GetKind() < right.GetKind(); 1732 } 1733 1734 const BitShiftOperand *rightOpnd = static_cast<const BitShiftOperand *>(&right); 1735 1736 /* The same type. */ 1737 if (shiftOp != rightOpnd->shiftOp) { 1738 return shiftOp < rightOpnd->shiftOp; 1739 } 1740 return shiftAmount < rightOpnd->shiftAmount; 1741 } 1742 GetShiftAmount()1743 uint32 GetShiftAmount() const 1744 { 1745 return shiftAmount; 1746 } 1747 GetShiftOp()1748 ShiftOp GetShiftOp() const 1749 { 1750 return shiftOp; 1751 } 1752 Dump()1753 void Dump() const override 1754 { 1755 CHECK_FATAL(false, "dont run here"); 1756 } 1757 1758 private: 1759 ShiftOp shiftOp; 1760 uint32 shiftAmount; 1761 }; 1762 1763 class CommentOperand : public OperandVisitable<CommentOperand> { 1764 public: CommentOperand(const char * str,MemPool & memPool)1765 CommentOperand(const char *str, MemPool &memPool) : OperandVisitable(Operand::kOpdString, 0), comment(str, &memPool) 1766 { 1767 } 1768 CommentOperand(const std::string & str,MemPool & memPool)1769 CommentOperand(const std::string &str, MemPool &memPool) 1770 : OperandVisitable(Operand::kOpdString, 0), comment(str, &memPool) 1771 { 1772 } 1773 1774 ~CommentOperand() override = default; 1775 using OperandVisitable<CommentOperand>::OperandVisitable; 1776 GetComment()1777 const MapleString &GetComment() const 1778 { 1779 return comment; 1780 } 1781 Clone(MemPool & memPool)1782 Operand *Clone(MemPool &memPool) const override 1783 { 1784 return memPool.Clone<CommentOperand>(*this); 1785 } 1786 IsCommentOpnd()1787 bool IsCommentOpnd() const override 1788 { 1789 return true; 1790 } 1791 Less(const Operand & right)1792 bool Less(const Operand &right) const override 1793 { 1794 /* For different type. */ 1795 return GetKind() < right.GetKind(); 1796 } 1797 Dump()1798 void Dump() const override 1799 { 1800 LogInfo::MapleLogger() << "# "; 1801 if (!comment.empty()) { 1802 LogInfo::MapleLogger() << comment; 1803 } 1804 } 1805 1806 private: 1807 const MapleString comment; 1808 }; 1809 1810 using StringOperand = CommentOperand; 1811 1812 class ListConstraintOperand : public OperandVisitable<ListConstraintOperand> { 1813 public: ListConstraintOperand(MapleAllocator & allocator)1814 explicit ListConstraintOperand(MapleAllocator &allocator) 1815 : OperandVisitable(Operand::kOpdString, 0), stringList(allocator.Adapter()) {}; 1816 1817 ~ListConstraintOperand() override = default; 1818 using OperandVisitable<ListConstraintOperand>::OperandVisitable; 1819 Dump()1820 void Dump() const override 1821 { 1822 for (auto *str : stringList) { 1823 LogInfo::MapleLogger() << "(" << str->GetComment().c_str() << ")"; 1824 } 1825 } 1826 Clone(MemPool & memPool)1827 Operand *Clone(MemPool &memPool) const override 1828 { 1829 return memPool.Clone<ListConstraintOperand>(*this); 1830 } 1831 Less(const Operand & right)1832 bool Less(const Operand &right) const override 1833 { 1834 /* For different type. */ 1835 if (opndKind != right.GetKind()) { 1836 return opndKind < right.GetKind(); 1837 } 1838 1839 DEBUG_ASSERT(false, "We don't need to compare list operand."); 1840 return false; 1841 } 1842 1843 MapleVector<StringOperand *> stringList; 1844 }; 1845 1846 /* for cg ssa analysis */ 1847 class PhiOperand : public OperandVisitable<PhiOperand> { 1848 public: PhiOperand(MapleAllocator & allocator)1849 explicit PhiOperand(MapleAllocator &allocator) : OperandVisitable(Operand::kOpdPhi, 0), phiList(allocator.Adapter()) 1850 { 1851 } 1852 1853 ~PhiOperand() override = default; 1854 using OperandVisitable<PhiOperand>::OperandVisitable; 1855 Clone(MemPool & memPool)1856 Operand *Clone(MemPool &memPool) const override 1857 { 1858 return memPool.Clone<PhiOperand>(*this); 1859 } 1860 Dump()1861 void Dump() const override 1862 { 1863 CHECK_FATAL(false, "NIY"); 1864 } 1865 InsertOpnd(uint32 bbId,RegOperand & phiParam)1866 void InsertOpnd(uint32 bbId, RegOperand &phiParam) 1867 { 1868 DEBUG_ASSERT(!phiList.count(bbId), "cannot insert duplicate operand"); 1869 (void)phiList.emplace(std::pair(bbId, &phiParam)); 1870 } 1871 UpdateOpnd(uint32 bbId,uint32 newId,RegOperand & phiParam)1872 void UpdateOpnd(uint32 bbId, uint32 newId, RegOperand &phiParam) 1873 { 1874 (void)phiList.emplace(std::pair(newId, &phiParam)); 1875 phiList.erase(bbId); 1876 } 1877 GetOperands()1878 MapleMap<uint32, RegOperand *> &GetOperands() 1879 { 1880 return phiList; 1881 } 1882 1883 uint32 GetLeastCommonValidBit() const; 1884 1885 bool IsRedundancy() const; 1886 Less(const Operand & right)1887 bool Less(const Operand &right) const override 1888 { 1889 /* For different type. */ 1890 if (opndKind != right.GetKind()) { 1891 return opndKind < right.GetKind(); 1892 } 1893 DEBUG_ASSERT(false, "We don't need to compare list operand."); 1894 return false; 1895 } 1896 Equals(Operand & operand)1897 bool Equals(Operand &operand) const override 1898 { 1899 if (!operand.IsPhi()) { 1900 return false; 1901 } 1902 auto &op = static_cast<PhiOperand &>(operand); 1903 return (&op == this); 1904 } 1905 1906 protected: 1907 MapleMap<uint32, RegOperand *> phiList; /* ssa-operand && BBId */ 1908 }; 1909 1910 /* Use StImmOperand instead? */ 1911 class FuncNameOperand : public OperandVisitable<FuncNameOperand> { 1912 public: FuncNameOperand(const MIRSymbol & fsym)1913 explicit FuncNameOperand(const MIRSymbol &fsym) : OperandVisitable(kOpdBBAddress, 0), symbol(&fsym) {} 1914 ~FuncNameOperand()1915 ~FuncNameOperand() override 1916 { 1917 symbol = nullptr; 1918 } 1919 using OperandVisitable<FuncNameOperand>::OperandVisitable; 1920 GetName()1921 const std::string &GetName() const 1922 { 1923 return symbol->GetName(); 1924 } 1925 IsFuncNameOpnd()1926 bool IsFuncNameOpnd() const override 1927 { 1928 return true; 1929 } 1930 GetFunctionSymbol()1931 const MIRSymbol *GetFunctionSymbol() const 1932 { 1933 return symbol; 1934 } 1935 SetFunctionSymbol(const MIRSymbol & fsym)1936 void SetFunctionSymbol(const MIRSymbol &fsym) 1937 { 1938 symbol = &fsym; 1939 } 1940 Clone(MemPool & memPool)1941 Operand *Clone(MemPool &memPool) const override 1942 { 1943 return memPool.New<FuncNameOperand>(*this); 1944 } 1945 Less(const Operand & right)1946 bool Less(const Operand &right) const override 1947 { 1948 if (&right == this) { 1949 return false; 1950 } 1951 /* For different type. */ 1952 if (GetKind() != right.GetKind()) { 1953 return GetKind() < right.GetKind(); 1954 } 1955 1956 auto *rightOpnd = static_cast<const FuncNameOperand *>(&right); 1957 1958 return static_cast<const void *>(symbol) < static_cast<const void *>(rightOpnd->symbol); 1959 } 1960 Dump()1961 void Dump() const override 1962 { 1963 LogInfo::MapleLogger() << GetName(); 1964 } 1965 1966 private: 1967 const MIRSymbol *symbol; 1968 }; 1969 1970 namespace operand { 1971 /* bit 0-7 for common */ 1972 enum CommOpndDescProp : maple::uint64 { 1973 kIsDef = 1ULL, 1974 kIsUse = (1ULL << 1), 1975 kIsVector = (1ULL << 2) 1976 }; 1977 1978 /* bit 8-15 for reg */ 1979 enum RegOpndDescProp : maple::uint64 { 1980 kInt = (1ULL << 8), 1981 kFloat = (1ULL << 9), 1982 kRegTyCc = (1ULL << 10), 1983 kRegTyVary = (1ULL << 11), 1984 }; 1985 1986 /* bit 16-23 for imm */ 1987 enum ImmOpndDescProp : maple::uint64 { 1988 }; 1989 1990 /* bit 24-31 for mem */ 1991 enum MemOpndDescProp : maple::uint64 { 1992 kMemLow12 = (1ULL << 24), 1993 kLiteralLow12 = kMemLow12, 1994 kIsLoadLiteral = (1ULL << 25) 1995 }; 1996 } // namespace operand 1997 1998 class OpndDesc { 1999 public: OpndDesc(Operand::OperandType t,maple::uint64 p,maple::uint32 s)2000 OpndDesc(Operand::OperandType t, maple::uint64 p, maple::uint32 s) : opndType(t), property(p), size(s) {} 2001 virtual ~OpndDesc() = default; 2002 GetOperandType()2003 Operand::OperandType GetOperandType() const 2004 { 2005 return opndType; 2006 } 2007 GetSize()2008 maple::uint32 GetSize() const 2009 { 2010 return size; 2011 } 2012 IsImm()2013 bool IsImm() const 2014 { 2015 return opndType == Operand::kOpdImmediate; 2016 } 2017 IsRegister()2018 bool IsRegister() const 2019 { 2020 return opndType == Operand::kOpdRegister; 2021 } 2022 IsMem()2023 bool IsMem() const 2024 { 2025 return opndType == Operand::kOpdMem; 2026 } 2027 IsRegDef()2028 bool IsRegDef() const 2029 { 2030 return opndType == Operand::kOpdRegister && (property & operand::kIsDef); 2031 } 2032 IsRegUse()2033 bool IsRegUse() const 2034 { 2035 return opndType == Operand::kOpdRegister && (property & operand::kIsUse); 2036 } 2037 IsDef()2038 bool IsDef() const 2039 { 2040 return (property & operand::kIsDef) != 0; 2041 } 2042 IsUse()2043 bool IsUse() const 2044 { 2045 return (property & operand::kIsUse) != 0; 2046 } 2047 IsMemLow12()2048 bool IsMemLow12() const 2049 { 2050 return IsMem() && (property & operand::kMemLow12); 2051 } 2052 IsLiteralLow12()2053 bool IsLiteralLow12() const 2054 { 2055 return opndType == Operand::kOpdStImmediate && (property & operand::kLiteralLow12); 2056 } 2057 IsLoadLiteral()2058 bool IsLoadLiteral() const 2059 { 2060 return (property & operand::kIsLoadLiteral) != 0; 2061 } 2062 IsVectorOperand()2063 bool IsVectorOperand() const 2064 { 2065 return (property & operand::kIsVector); 2066 } 2067 2068 #define DEFINE_MOP(op, ...) static const OpndDesc op; 2069 #include "operand.def" 2070 #undef DEFINE_MOP 2071 2072 private: 2073 Operand::OperandType opndType; 2074 maple::uint64 property; 2075 maple::uint32 size; 2076 }; 2077 2078 class CondOperand : public OperandVisitable<CondOperand> { 2079 public: CondOperand(maplebe::ConditionCode cc)2080 explicit CondOperand(maplebe::ConditionCode cc) : OperandVisitable(Operand::kOpdCond, k4ByteSize), cc(cc) {} 2081 2082 ~CondOperand() override = default; 2083 using OperandVisitable<CondOperand>::OperandVisitable; 2084 Clone(MemPool & memPool)2085 Operand *Clone(MemPool &memPool) const override 2086 { 2087 return memPool.New<CondOperand>(cc); 2088 } 2089 GetCode()2090 ConditionCode GetCode() const 2091 { 2092 return cc; 2093 } 2094 2095 bool Less(const Operand &right) const override; 2096 Dump()2097 void Dump() const override 2098 { 2099 CHECK_FATAL(false, "dont run here"); 2100 } 2101 2102 static const char *ccStrs[kCcLast]; 2103 2104 private: 2105 ConditionCode cc; 2106 }; 2107 2108 class OpndDumpVisitor : public OperandVisitorBase, 2109 public OperandVisitors<RegOperand, ImmOperand, MemOperand, LabelOperand, FuncNameOperand, 2110 ListOperand, StImmOperand, CondOperand, CommentOperand, BitShiftOperand, 2111 ExtendShiftOperand, PhiOperand> { 2112 public: OpndDumpVisitor(const OpndDesc & operandDesc)2113 explicit OpndDumpVisitor(const OpndDesc &operandDesc) : opndDesc(&operandDesc) {} ~OpndDumpVisitor()2114 virtual ~OpndDumpVisitor() 2115 { 2116 opndDesc = nullptr; 2117 } 2118 2119 protected: DumpOpndPrefix()2120 virtual void DumpOpndPrefix() 2121 { 2122 LogInfo::MapleLogger() << " (opnd:"; 2123 } DumpOpndSuffix()2124 virtual void DumpOpndSuffix() 2125 { 2126 LogInfo::MapleLogger() << " )"; 2127 } DumpSize(const Operand & opnd)2128 void DumpSize(const Operand &opnd) const 2129 { 2130 LogInfo::MapleLogger() << " [size:" << opnd.GetSize() << "]"; 2131 } DumpReferenceInfo(const Operand & opnd)2132 void DumpReferenceInfo(const Operand &opnd) const 2133 { 2134 if (opnd.IsReference()) { 2135 LogInfo::MapleLogger() << "[is_ref]"; 2136 } 2137 } GetOpndDesc()2138 const OpndDesc *GetOpndDesc() const 2139 { 2140 return opndDesc; 2141 } 2142 2143 private: 2144 const OpndDesc *opndDesc; 2145 }; 2146 } /* namespace maplebe */ 2147 2148 #endif /* MAPLEBE_INCLUDE_CG_OPERAND_H */ 2149