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
18 namespace maplebe {
IsMoveWidableImmediate(uint64 val,uint32 bitLen)19 bool IsMoveWidableImmediate(uint64 val, uint32 bitLen)
20 {
21 if (bitLen == k64BitSize) {
22 /* 0xHHHH000000000000 or 0x0000HHHH00000000, return true */
23 if (((val & ((static_cast<uint64>(0xffff)) << k48BitSize)) == val) ||
24 ((val & ((static_cast<uint64>(0xffff)) << k32BitSize)) == val)) {
25 return true;
26 }
27 } else {
28 /* get lower 32 bits */
29 val &= static_cast<uint64>(0xffffffff);
30 }
31 /* 0x00000000HHHH0000 or 0x000000000000HHHH, return true */
32 return ((val & ((static_cast<uint64>(0xffff)) << k16BitSize)) == val ||
33 (val & ((static_cast<uint64>(0xffff)) << 0)) == val);
34 }
35
BetterUseMOVZ(uint64 val)36 bool BetterUseMOVZ(uint64 val)
37 {
38 int32 n16zerosChunks = 0;
39 int32 n16onesChunks = 0;
40 uint64 sa = 0;
41 /* a 64 bits number is split 4 chunks, each chunk has 16 bits. check each chunk whether is all 1 or is all 0 */
42 for (uint64 i = 0; i < k4BitSize; ++i, sa += k16BitSize) {
43 uint64 chunkVal = (val >> (static_cast<uint64>(sa))) & 0x0000FFFFUL;
44 if (chunkVal == 0) {
45 ++n16zerosChunks;
46 } else if (chunkVal == 0xFFFFUL) {
47 ++n16onesChunks;
48 }
49 }
50 /*
51 * note that since we already check if the value
52 * can be movable with as a single mov instruction,
53 * we should not expect either n_16zeros_chunks>=3 or n_16ones_chunks>=3
54 */
55 #if DEBUG
56 constexpr uint32 kN16ChunksCheck = 2;
57 DEBUG_ASSERT(static_cast<uint32>(n16zerosChunks) <= kN16ChunksCheck, "n16zerosChunks ERR");
58 DEBUG_ASSERT(static_cast<uint32>(n16onesChunks) <= kN16ChunksCheck, "n16onesChunks ERR");
59 #endif
60 return (n16zerosChunks >= n16onesChunks);
61 }
62
operator ==(const RegOperand & o) const63 bool RegOperand::operator==(const RegOperand &o) const
64 {
65 regno_t myRn = GetRegisterNumber();
66 uint32 mySz = GetSize();
67 uint32 myFl = regFlag;
68 regno_t otherRn = o.GetRegisterNumber();
69 uint32 otherSz = o.GetSize();
70 uint32 otherFl = o.regFlag;
71
72 if (IsPhysicalRegister()) {
73 return (myRn == otherRn && mySz == otherSz && myFl == otherFl);
74 }
75 return (myRn == otherRn && mySz == otherSz);
76 }
77
operator <(const RegOperand & o) const78 bool RegOperand::operator<(const RegOperand &o) const
79 {
80 regno_t myRn = GetRegisterNumber();
81 uint32 mySz = GetSize();
82 uint32 myFl = regFlag;
83 regno_t otherRn = o.GetRegisterNumber();
84 uint32 otherSz = o.GetSize();
85 uint32 otherFl = o.regFlag;
86 return myRn < otherRn || (myRn == otherRn && mySz < otherSz) ||
87 (myRn == otherRn && mySz == otherSz && myFl < otherFl);
88 }
89
GetOffset() const90 Operand *MemOperand::GetOffset() const
91 {
92 switch (addrMode) {
93 case kAddrModeBOi:
94 return GetOffsetOperand();
95 case kAddrModeBOrX:
96 return GetIndexRegister();
97 case kAddrModeLiteral:
98 break;
99 case kAddrModeLo12Li:
100 break;
101 default:
102 DEBUG_ASSERT(false, "error memoperand dump");
103 break;
104 }
105 return nullptr;
106 }
107
Equals(Operand & op) const108 bool MemOperand::Equals(Operand &op) const
109 {
110 if (!op.IsMemoryAccessOperand()) {
111 return false;
112 }
113 return Equals(static_cast<MemOperand &>(op));
114 }
115
Equals(const MemOperand & op) const116 bool MemOperand::Equals(const MemOperand &op) const
117 {
118 if (&op == this) {
119 return true;
120 }
121
122 if (addrMode == op.GetAddrMode()) {
123 switch (addrMode) {
124 case kAddrModeBOi:
125 return (GetBaseRegister()->Equals(*op.GetBaseRegister()) &&
126 GetOffsetImmediate()->Equals(*op.GetOffsetImmediate()));
127 case kAddrModeBOrX:
128 return (GetBaseRegister()->Equals(*op.GetBaseRegister()) &&
129 GetIndexRegister()->Equals(*op.GetIndexRegister()) &&
130 GetExtendAsString() == op.GetExtendAsString() && ShiftAmount() == op.ShiftAmount());
131 case kAddrModeLiteral:
132 return GetSymbolName() == op.GetSymbolName();
133 case kAddrModeLo12Li:
134 return (GetBaseRegister()->Equals(*op.GetBaseRegister()) && GetSymbolName() == op.GetSymbolName() &&
135 GetOffsetImmediate()->Equals(*op.GetOffsetImmediate()));
136 default:
137 DEBUG_ASSERT(false, "error memoperand");
138 break;
139 }
140 }
141 return false;
142 }
143
Less(const Operand & right) const144 bool MemOperand::Less(const Operand &right) const
145 {
146 if (&right == this) {
147 return false;
148 }
149
150 /* For different type. */
151 if (GetKind() != right.GetKind()) {
152 return GetKind() < right.GetKind();
153 }
154
155 const MemOperand *rightOpnd = static_cast<const MemOperand *>(&right);
156 if (addrMode != rightOpnd->addrMode) {
157 return addrMode < rightOpnd->addrMode;
158 }
159
160 switch (addrMode) {
161 case kAddrModeBOi: {
162 DEBUG_ASSERT(idxOpt == kIntact, "Should not compare pre/post index addressing.");
163
164 RegOperand *baseReg = GetBaseRegister();
165 RegOperand *rbaseReg = rightOpnd->GetBaseRegister();
166 CHECK_FATAL(baseReg != nullptr, "nullptr check");
167 int32 nRet = baseReg->RegCompare(*rbaseReg);
168 if (nRet == 0) {
169 Operand *ofstOpnd = GetOffsetOperand();
170 const Operand *rofstOpnd = rightOpnd->GetOffsetOperand();
171 return ofstOpnd->Less(*rofstOpnd);
172 }
173 return nRet < 0;
174 }
175 case kAddrModeBOrX: {
176 if (noExtend != rightOpnd->noExtend) {
177 return noExtend;
178 }
179 if (!noExtend && extend != rightOpnd->extend) {
180 return extend < rightOpnd->extend;
181 }
182 RegOperand *indexReg = GetIndexRegister();
183 const RegOperand *rindexReg = rightOpnd->GetIndexRegister();
184 CHECK_FATAL(indexReg != nullptr, "nullptr check");
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