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 #ifndef MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_IMM_VALID_H
16 #define MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_IMM_VALID_H
17
18 #include "common_utils.h"
19 #include "types_def.h"
20
21 namespace maplebe {
IsBitSizeImmediate(uint64 val,uint32 bitLen,uint32 nLowerZeroBits)22 inline bool IsBitSizeImmediate(uint64 val, uint32 bitLen, uint32 nLowerZeroBits)
23 {
24 // mask1 is a 64bits number that is all 1 shifts left size bits
25 const uint64 mask1 = 0xffffffffffffffffUL << bitLen;
26 // mask2 is a 64 bits number that nlowerZeroBits are all 1, higher bits aro all 0
27 uint64 mask2 = (1UL << static_cast<uint64>(nLowerZeroBits)) - 1UL;
28 return (mask2 & val) == 0UL && (mask1 & ((static_cast<uint64>(val)) >> nLowerZeroBits)) == 0UL;
29 };
30
31 // This is a copy from "operand.cpp", temporary fix for me_slp.cpp usage of this file
32 // was IsMoveWidableImmediate
IsMoveWidableImmediateCopy(uint64 val,uint32 bitLen)33 inline bool IsMoveWidableImmediateCopy(uint64 val, uint32 bitLen)
34 {
35 // When #imm is FFFFFFFF, ~val should return true, because ~val is 0, and it should be valid.
36 // But ~val and (~val & 0xffffffff) both will be 0, it will return false, so we judge this situation alone.
37 if (val == 0 || val == 0xffffffff) {
38 return true;
39 }
40 if (bitLen == k64BitSize) {
41 // 0xHHHH000000000000 or 0x0000HHHH00000000, return true
42 if (((val & ((static_cast<uint64>(0xffff)) << k48BitSize)) == val) ||
43 ((val & ((static_cast<uint64>(0xffff)) << k32BitSize)) == val)) {
44 return true;
45 }
46 } else {
47 // get lower 32 bits
48 val &= static_cast<uint64>(0xffffffff);
49 // If lower 32 bits are all 0, but higher 32 bits have 1, val will be 1 and return true, but it is false in
50 // fact.
51 if (val == 0) {
52 return false;
53 }
54 }
55 // 0x00000000HHHH0000 or 0x000000000000HHHH, return true
56 return ((val & ((static_cast<uint64>(0xffff)) << k16BitSize)) == val || (val & static_cast<uint64>(0xffff)) == val);
57 }
58 namespace aarch64 {
59 bool IsBitmaskImmediate(uint64 val, uint32 bitLen);
60 } // namespace aarch64
61
62 using namespace aarch64;
IsSingleInstructionMovable32(int64 value)63 inline bool IsSingleInstructionMovable32(int64 value)
64 {
65 // When value & ffffffff00000000 is 0, all high 32-bits are 0.
66 // When value & ffffffff00000000 is ffffffff00000000, all high 32-bits are 1.
67 // High 32-bits should be all 0 or all 1, when it comes to mov w0, #imm.
68 if ((static_cast<uint64>(value) & 0xffffffff00000000ULL) != 0 &&
69 (static_cast<uint64>(value) & 0xffffffff00000000ULL) != 0xffffffff00000000ULL) {
70 return false;
71 }
72 constexpr uint32 bitLen = 32;
73 return (IsMoveWidableImmediateCopy(static_cast<uint64>(value), bitLen) ||
74 IsMoveWidableImmediateCopy(~static_cast<uint64>(value), bitLen) ||
75 IsBitmaskImmediate(static_cast<uint64>(value), bitLen));
76 }
77
IsSingleInstructionMovable64(int64 value)78 inline bool IsSingleInstructionMovable64(int64 value)
79 {
80 constexpr uint32 bitLen = 64;
81 return (IsMoveWidableImmediateCopy(static_cast<uint64>(value), bitLen) ||
82 IsMoveWidableImmediateCopy(~static_cast<uint64>(value), bitLen) ||
83 IsBitmaskImmediate(static_cast<uint64>(value), bitLen));
84 }
85
Imm12BitValid(int64 value)86 inline bool Imm12BitValid(int64 value)
87 {
88 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal12Bits, 0);
89 // for target linux-aarch64-gnu
90 result = result || IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal12Bits, kMaxImmVal12Bits);
91 return result;
92 }
93
94 // For the 32-bit variant: is the bitmask immediate
Imm12BitMaskValid(int64 value)95 inline bool Imm12BitMaskValid(int64 value)
96 {
97 if (value == 0 || static_cast<int64>(value) == -1) {
98 return false;
99 }
100 return IsBitmaskImmediate(static_cast<uint64>(value), k32BitSize);
101 }
102
Imm13BitValid(int64 value)103 inline bool Imm13BitValid(int64 value)
104 {
105 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal13Bits, 0);
106 // for target linux-aarch64-gnu
107 result = result || IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal13Bits, kMaxImmVal13Bits);
108 return result;
109 }
110
111 // For the 64-bit variant: is the bitmask immediate
Imm13BitMaskValid(int64 value)112 inline bool Imm13BitMaskValid(int64 value)
113 {
114 if (value == 0 || static_cast<int64>(value) == -1) {
115 return false;
116 }
117 return IsBitmaskImmediate(static_cast<uint64>(value), k64BitSize);
118 }
119
Imm16BitValid(int64 value)120 inline bool Imm16BitValid(int64 value)
121 {
122 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal16Bits, 0);
123 // for target linux-aarch64-gnu
124 // aarch64 assembly takes up to 24-bits immediate, generating
125 // either cmp or cmp with shift 12 encoding
126 result = result || IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal12Bits, kMaxImmVal12Bits);
127 return result;
128 }
129
130 // For the 32-bit variant: is the shift amount, in the range 0 to 31, opnd input is bitshiftopnd
BitShift5BitValid(uint32 value)131 inline bool BitShift5BitValid(uint32 value)
132 {
133 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal5Bits, 0);
134 return result;
135 }
136
137 // For the 64-bit variant: is the shift amount, in the range 0 to 63, opnd input is bitshiftopnd
BitShift6BitValid(uint32 value)138 inline bool BitShift6BitValid(uint32 value)
139 {
140 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal6Bits, 0);
141 return result;
142 }
143
144 // For the 32-bit variant: is the shift amount, in the range 0 to 31, opnd input is immopnd
BitShift5BitValidImm(int64 value)145 inline bool BitShift5BitValidImm(int64 value)
146 {
147 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal5Bits, 0);
148 return result;
149 }
150
151 // For the 64-bit variant: is the shift amount, in the range 0 to 63, opnd input is immopnd
BitShift6BitValidImm(int64 value)152 inline bool BitShift6BitValidImm(int64 value)
153 {
154 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal6Bits, 0);
155 return result;
156 }
157
158 // Is a 16-bit unsigned immediate, in the range 0 to 65535, used by BRK
Imm16BitValidImm(int64 value)159 inline bool Imm16BitValidImm(int64 value)
160 {
161 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal16Bits, 0);
162 return result;
163 }
164
165 // Is the flag bit specifier, an immediate in the range 0 to 15, used by CCMP
Nzcv4BitValid(int64 value)166 inline bool Nzcv4BitValid(int64 value)
167 {
168 bool result = IsBitSizeImmediate(static_cast<uint64>(value), k4BitSize, 0);
169 return result;
170 }
171
172 // For the 32-bit variant: is the bit number of the lsb of the source bitfield, in the range 0 to 31
Lsb5BitValid(int64 value)173 inline bool Lsb5BitValid(int64 value)
174 {
175 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal5Bits, 0);
176 return result;
177 }
178
179 // For the 32-bit variant: is the width of the bitfield, in the range 1 to 32-<lsb>
Width5BitValid(int64 value,int64 lsb)180 inline bool Width5BitValid(int64 value, int64 lsb)
181 {
182 constexpr int64 offset = 32;
183 return (value >= 1) && (value <= offset - lsb);
184 }
185
186 // For the 32-bit variant: is the width of the bitfield, in the range 1 to 32, is used for only width verified
Width5BitOnlyValid(int64 value)187 inline bool Width5BitOnlyValid(int64 value)
188 {
189 constexpr int64 offset = 32;
190 return (value >= 1) && (value <= offset);
191 }
192
193 // For the 64-bit variant: is the bit number of the lsb of the source bitfield, in the range 0 to 63
Lsb6BitValid(int64 value)194 inline bool Lsb6BitValid(int64 value)
195 {
196 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal6Bits, 0);
197 return result;
198 }
199
200 // For the 64-bit variant: is the width of the bitfield, in the range 1 to 64-<lsb>
Width6BitValid(int64 value,int64 lsb)201 inline bool Width6BitValid(int64 value, int64 lsb)
202 {
203 constexpr int64 offset = 64;
204 return (value >= 1) && (value <= offset - lsb);
205 }
206
207 // For the 64-bit variant: is the width of the bitfield, in the range 1 to 64, is used for only width verified
Width6BitOnlyValid(int64 value)208 inline bool Width6BitOnlyValid(int64 value)
209 {
210 constexpr int64 offset = 64;
211 return (value >= 1) && (value <= offset);
212 }
213
214 // Is the left shift amount to be applied after extension in the range 0 to 4, uint32 means value non-negative
ExtendShift0To4Valid(uint32 value)215 inline bool ExtendShift0To4Valid(uint32 value)
216 {
217 return (value <= k4BitSize);
218 }
219
220 // Is the optional left shift to apply to the immediate, it can have the values: 0, 12
LeftShift12Valid(uint32 value)221 inline bool LeftShift12Valid(uint32 value)
222 {
223 return value == k0BitSize || value == k12BitSize;
224 }
225
226 // For the 32-bit variant: is the amount by which to shift the immediate left, either 0 or 16
ImmShift32Valid(uint32 value)227 inline bool ImmShift32Valid(uint32 value)
228 {
229 return value == k0BitSize || value == k16BitSize;
230 }
231
232 // For the 64-bit variant: is the amount by which to shift the immediate left, either 0, 16, 32 or 48
ImmShift64Valid(uint32 value)233 inline bool ImmShift64Valid(uint32 value)
234 {
235 return value == k0BitSize || value == k16BitSize || value == k32BitSize || value == k48BitSize;
236 }
237
IsSIMMValid(int64 value)238 inline bool IsSIMMValid(int64 value)
239 {
240 return (value <= kMaxSimm32) && (value >= kMinSimm32);
241 }
242
IsPIMMValid(int64 value,uint wordSize)243 inline bool IsPIMMValid(int64 value, uint wordSize)
244 {
245 if ((value >= k0BitSize) && (value <= kMaxPimm[wordSize])) {
246 uint64 mask = (1U << wordSize) - 1U;
247 return (static_cast<uint64>(value) & mask) > 0 ? false : true;
248 }
249 return false;
250 }
251
252 // Used for backend str/ldr memopnd offset judgment
StrLdrInsnSignedOfstValid(int64 value,uint wordSize,bool IsIntactIndexed)253 inline bool StrLdrInsnSignedOfstValid(int64 value, uint wordSize, bool IsIntactIndexed)
254 {
255 return IsSIMMValid(value) || (IsPIMMValid(value, wordSize) && IsIntactIndexed);
256 }
257
258 // 8bit : 0
259 // halfword : 1
260 // 32bit - word : 2
261 // 64bit - word : 3
262 // 128bit- word : 4
StrLdrSignedOfstValid(int64 value,uint wordSize)263 inline bool StrLdrSignedOfstValid(int64 value, uint wordSize)
264 {
265 return IsSIMMValid(value) || IsPIMMValid(value, wordSize);
266 }
267
StrLdr8ImmValid(int64 value)268 inline bool StrLdr8ImmValid(int64 value)
269 {
270 return StrLdrSignedOfstValid(value, 0);
271 }
272
StrLdr16ImmValid(int64 value)273 inline bool StrLdr16ImmValid(int64 value)
274 {
275 return StrLdrSignedOfstValid(value, k1ByteSize);
276 }
277
StrLdr32ImmValid(int64 value)278 inline bool StrLdr32ImmValid(int64 value)
279 {
280 return StrLdrSignedOfstValid(value, k2ByteSize);
281 }
282
StrLdr32PairImmValid(int64 value)283 inline bool StrLdr32PairImmValid(int64 value)
284 {
285 constexpr uint64 immValidOffset = 3;
286 if ((value <= kMaxSimm32Pair) && (value >= kMinSimm32)) {
287 return (static_cast<uint64>(value) & immValidOffset) > 0 ? false : true;
288 }
289 return false;
290 }
291
StrLdr64ImmValid(int64 value)292 inline bool StrLdr64ImmValid(int64 value)
293 {
294 return StrLdrSignedOfstValid(value, k3ByteSize);
295 }
296
StrLdr64PairImmValid(int64 value)297 inline bool StrLdr64PairImmValid(int64 value)
298 {
299 constexpr uint64 immValidOffset = 7;
300 if (value <= kMaxSimm64Pair && (value >= kMinSimm64)) {
301 return (static_cast<uint64>(value) & immValidOffset) > 0 ? false : true;
302 }
303 return false;
304 }
305
StrLdr128ImmValid(int64 value)306 inline bool StrLdr128ImmValid(int64 value)
307 {
308 return StrLdrSignedOfstValid(value, k4ByteSize);
309 }
310
StrLdr128PairImmValid(int64 value)311 inline bool StrLdr128PairImmValid(int64 value)
312 {
313 if (value < k1024BitSize && (value >= kNegative1024BitSize)) {
314 return (static_cast<uint64>(value) & 0xf) > 0 ? false : true;
315 }
316 return false;
317 }
318 } // namespace maplebe
319
320 #endif // MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_IMM_VALID_H
321