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 #include "operand.h"
17 #include "common_utils.h"
18 #include "mpl_logging.h"
19 
20 namespace maplebe {
IsMoveWidableImmediate(uint64 val, uint32 bitLen)21 bool IsMoveWidableImmediate(uint64 val, uint32 bitLen)
22 {
23     if (bitLen == k64BitSize) {
24         /* 0xHHHH000000000000 or 0x0000HHHH00000000, return true */
25         if (((val & ((static_cast<uint64>(0xffff)) << k48BitSize)) == val) ||
26             ((val & ((static_cast<uint64>(0xffff)) << k32BitSize)) == val)) {
27             return true;
28         }
29     } else {
30         /* get lower 32 bits */
31         val &= static_cast<uint64>(0xffffffff);
32     }
33     /* 0x00000000HHHH0000 or 0x000000000000HHHH, return true */
34     return ((val & ((static_cast<uint64>(0xffff)) << k16BitSize)) == val ||
35             (val & ((static_cast<uint64>(0xffff)) << 0)) == val);
36 }
37 
BetterUseMOVZ(uint64 val)38 bool BetterUseMOVZ(uint64 val)
39 {
40     int32 n16zerosChunks = 0;
41     int32 n16onesChunks = 0;
42     uint64 sa = 0;
43     /* a 64 bits number is split 4 chunks, each chunk has 16 bits. check each chunk whether is all 1 or is all 0 */
44     for (uint64 i = 0; i < k4BitSize; ++i, sa += k16BitSize) {
45         uint64 chunkVal = (val >> (static_cast<uint64>(sa))) & 0x0000FFFFUL;
46         if (chunkVal == 0) {
47             ++n16zerosChunks;
48         } else if (chunkVal == 0xFFFFUL) {
49             ++n16onesChunks;
50         }
51     }
52     /*
53      * note that since we already check if the value
54      * can be movable with as a single mov instruction,
55      * we should not expect either n_16zeros_chunks>=3 or n_16ones_chunks>=3
56      */
57 #if DEBUG
58     constexpr uint32 kN16ChunksCheck = 2;
59     DEBUG_ASSERT(static_cast<uint32>(n16zerosChunks) <= kN16ChunksCheck, "n16zerosChunks ERR");
60     DEBUG_ASSERT(static_cast<uint32>(n16onesChunks) <= kN16ChunksCheck, "n16onesChunks ERR");
61 #endif
62     return (n16zerosChunks >= n16onesChunks);
63 }
64 
operator ==(const RegOperand &o) const65 bool RegOperand::operator==(const RegOperand &o) const
66 {
67     regno_t myRn = GetRegisterNumber();
68     uint32 mySz = GetSize();
69     uint32 myFl = regFlag;
70     regno_t otherRn = o.GetRegisterNumber();
71     uint32 otherSz = o.GetSize();
72     uint32 otherFl = o.regFlag;
73 
74     if (IsPhysicalRegister()) {
75         return (myRn == otherRn && mySz == otherSz && myFl == otherFl);
76     }
77     return (myRn == otherRn && mySz == otherSz);
78 }
79 
operator <(const RegOperand &o) const80 bool RegOperand::operator<(const RegOperand &o) const
81 {
82     regno_t myRn = GetRegisterNumber();
83     uint32 mySz = GetSize();
84     uint32 myFl = regFlag;
85     regno_t otherRn = o.GetRegisterNumber();
86     uint32 otherSz = o.GetSize();
87     uint32 otherFl = o.regFlag;
88     return myRn < otherRn || (myRn == otherRn && mySz < otherSz) ||
89            (myRn == otherRn && mySz == otherSz && myFl < otherFl);
90 }
91 
GetOffset() const92 Operand *MemOperand::GetOffset() const
93 {
94     switch (addrMode) {
95         case kAddrModeBOi:
96             return GetOffsetOperand();
97         case kAddrModeBOrX:
98             return GetIndexRegister();
99         case kAddrModeLiteral:
100             break;
101         case kAddrModeLo12Li:
102             break;
103         default:
104             DEBUG_ASSERT(false, "error memoperand dump");
105             break;
106     }
107     return nullptr;
108 }
109 
Equals(Operand &op) const110 bool MemOperand::Equals(Operand &op) const
111 {
112     if (!op.IsMemoryAccessOperand()) {
113         return false;
114     }
115     return Equals(static_cast<MemOperand &>(op));
116 }
117 
Equals(const MemOperand &op) const118 bool MemOperand::Equals(const MemOperand &op) const
119 {
120     if (&op == this) {
121         return true;
122     }
123 
124     if (addrMode == op.GetAddrMode()) {
125         switch (addrMode) {
126             case kAddrModeBOi:
127                 return (GetBaseRegister()->Equals(*op.GetBaseRegister()) &&
128                         GetOffsetImmediate()->Equals(*op.GetOffsetImmediate()));
129             case kAddrModeBOrX:
130                 return (GetBaseRegister()->Equals(*op.GetBaseRegister()) &&
131                         GetIndexRegister()->Equals(*op.GetIndexRegister()) &&
132                         GetExtendAsString() == op.GetExtendAsString() && ShiftAmount() == op.ShiftAmount());
133             case kAddrModeLiteral:
134                 return GetSymbolName() == op.GetSymbolName();
135             case kAddrModeLo12Li:
136                 return (GetBaseRegister()->Equals(*op.GetBaseRegister()) && GetSymbolName() == op.GetSymbolName() &&
137                         GetOffsetImmediate()->Equals(*op.GetOffsetImmediate()));
138             default:
139                 DEBUG_ASSERT(false, "error memoperand");
140                 break;
141         }
142     }
143     return false;
144 }
145 
Less(const Operand &right) const146 bool MemOperand::Less(const Operand &right) const
147 {
148     if (&right == this) {
149         return false;
150     }
151 
152     /* For different type. */
153     if (GetKind() != right.GetKind()) {
154         return GetKind() < right.GetKind();
155     }
156 
157     const MemOperand *rightOpnd = static_cast<const MemOperand *>(&right);
158     if (addrMode != rightOpnd->addrMode) {
159         return addrMode < rightOpnd->addrMode;
160     }
161 
162     switch (addrMode) {
163         case kAddrModeBOi: {
164             DEBUG_ASSERT(idxOpt == kIntact, "Should not compare pre/post index addressing.");
165 
166             RegOperand *baseReg = GetBaseRegister();
167             RegOperand *rbaseReg = rightOpnd->GetBaseRegister();
168             int32 nRet = baseReg->RegCompare(*rbaseReg);
169             if (nRet == 0) {
170                 Operand *ofstOpnd = GetOffsetOperand();
171                 const Operand *rofstOpnd = rightOpnd->GetOffsetOperand();
172                 return ofstOpnd->Less(*rofstOpnd);
173             }
174             return nRet < 0;
175         }
176         case kAddrModeBOrX: {
177             if (noExtend != rightOpnd->noExtend) {
178                 return noExtend;
179             }
180             if (!noExtend && extend != rightOpnd->extend) {
181                 return extend < rightOpnd->extend;
182             }
183             RegOperand *indexReg = GetIndexRegister();
184             const RegOperand *rindexReg = rightOpnd->GetIndexRegister();
185             return indexReg->Less(*rindexReg);
186         }
187         case kAddrModeLiteral: {
188             return static_cast<const void *>(GetSymbol()) < static_cast<const void *>(rightOpnd->GetSymbol());
189         }
190         case kAddrModeLo12Li: {
191             if (GetSymbol() != rightOpnd->GetSymbol()) {
192                 return static_cast<const void *>(GetSymbol()) < static_cast<const void *>(rightOpnd->GetSymbol());
193             }
194             Operand *ofstOpnd = GetOffsetOperand();
195             const Operand *rofstOpnd = rightOpnd->GetOffsetOperand();
196             return ofstOpnd->Less(*rofstOpnd);
197         }
198         default:
199             DEBUG_ASSERT(false, "Internal error.");
200             return false;
201     }
202 }
203 
204 const char *CondOperand::ccStrs[kCcLast] = {"EQ", "NE", "CS", "HS", "CC", "LO", "MI", "PL", "VS",
205                                             "VC", "HI", "LS", "GE", "LT", "GT", "LE", "AL"};
206 
Less(const Operand &right) const207 bool CondOperand::Less(const Operand &right) const
208 {
209     if (&right == this) {
210         return false;
211     }
212 
213     /* For different type. */
214     if (GetKind() != right.GetKind()) {
215         return GetKind() < right.GetKind();
216     }
217 
218     const CondOperand *rightOpnd = static_cast<const CondOperand *>(&right);
219 
220     /* The same type. */
221     if (cc == CC_AL || rightOpnd->cc == CC_AL) {
222         return false;
223     }
224     return cc < rightOpnd->cc;
225 }
226 
GetLeastCommonValidBit() const227 uint32 PhiOperand::GetLeastCommonValidBit() const
228 {
229     uint32 leastCommonVb = 0;
230     for (auto phiOpnd : phiList) {
231         uint32 curVb = phiOpnd.second->GetValidBitsNum();
232         if (curVb > leastCommonVb) {
233             leastCommonVb = curVb;
234         }
235     }
236     return leastCommonVb;
237 }
IsRedundancy() const238 bool PhiOperand::IsRedundancy() const
239 {
240     uint32 srcSsaIdx = 0;
241     for (auto phiOpnd : phiList) {
242         if (srcSsaIdx == 0) {
243             srcSsaIdx = phiOpnd.second->GetRegisterNumber();
244         }
245         if (srcSsaIdx != phiOpnd.second->GetRegisterNumber()) {
246             return false;
247         }
248     }
249     return true;
250 }
251 } /* namespace maplebe */
252