• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &regOpnd)
474     {
475         baseRefOpnd = &regOpnd;
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 &regOpnd)
1125     {
1126         baseOpnd = &regOpnd;
1127     }
1128 
GetIndexRegister()1129     RegOperand *GetIndexRegister() const
1130     {
1131         return indexOpnd;
1132     }
1133 
SetIndexRegister(RegOperand & regOpnd)1134     void SetIndexRegister(RegOperand &regOpnd)
1135     {
1136         indexOpnd = &regOpnd;
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