• 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 #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