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