LLVM 24.0.0git
AArch64ExpandImm.cpp
Go to the documentation of this file.
1//===- AArch64ExpandImm.h - AArch64 Immediate Expansion -------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the AArch64ExpandImm stuff.
10//
11//===----------------------------------------------------------------------===//
12
13#include "AArch64ExpandImm.h"
14#include "AArch64.h"
15#include "AArch64Subtarget.h"
17
18using namespace llvm;
19using namespace llvm::AArch64_IMM;
20
21/// Helper function which extracts the specified 16-bit chunk from a
22/// 64-bit value.
23static uint64_t getChunk(uint64_t Imm, unsigned ChunkIdx) {
24 assert(ChunkIdx < 4 && "Out of range chunk index specified!");
25
26 return (Imm >> (ChunkIdx * 16)) & 0xFFFF;
27}
28
29/// Check whether the given 16-bit chunk replicated to full 64-bit width
30/// can be materialized with an ORR instruction.
31static bool canUseOrr(uint64_t Chunk, uint64_t &Encoding) {
32 Chunk = (Chunk << 48) | (Chunk << 32) | (Chunk << 16) | Chunk;
33
34 return AArch64_AM::processLogicalImmediate(Chunk, 64, Encoding);
35}
36
37/// Check for identical 16-bit chunks within the constant and if so
38/// materialize them with a single ORR instruction. The remaining one or two
39/// 16-bit chunks will be materialized with MOVK instructions.
40///
41/// This allows us to materialize constants like |A|B|A|A| or |A|B|C|A| (order
42/// of the chunks doesn't matter), assuming |A|A|A|A| can be materialized with
43/// an ORR instruction.
46 using CountMap = DenseMap<uint64_t, unsigned>;
47
48 CountMap Counts;
49
50 // Scan the constant and count how often every chunk occurs.
51 for (unsigned Idx = 0; Idx < 4; ++Idx)
52 ++Counts[getChunk(UImm, Idx)];
53
54 // Traverse the chunks to find one which occurs more than once.
55 for (const auto &Chunk : Counts) {
56 const uint64_t ChunkVal = Chunk.first;
57 const unsigned Count = Chunk.second;
58
59 uint64_t Encoding = 0;
60
61 // We are looking for chunks which have two or three instances and can be
62 // materialized with an ORR instruction.
63 if ((Count != 2 && Count != 3) || !canUseOrr(ChunkVal, Encoding))
64 continue;
65
66 const bool CountThree = Count == 3;
67
68 Insn.push_back({ AArch64::ORRXri, 0, Encoding });
69
70 unsigned ShiftAmt = 0;
71 uint64_t Imm16 = 0;
72 // Find the first chunk not materialized with the ORR instruction.
73 for (; ShiftAmt < 64; ShiftAmt += 16) {
74 Imm16 = (UImm >> ShiftAmt) & 0xFFFF;
75
76 if (Imm16 != ChunkVal)
77 break;
78 }
79
80 // Create the first MOVK instruction.
81 Insn.push_back({ AArch64::MOVKXi, Imm16,
83
84 // In case we have three instances the whole constant is now materialized
85 // and we can exit.
86 if (CountThree)
87 return true;
88
89 // Find the remaining chunk which needs to be materialized.
90 for (ShiftAmt += 16; ShiftAmt < 64; ShiftAmt += 16) {
91 Imm16 = (UImm >> ShiftAmt) & 0xFFFF;
92
93 if (Imm16 != ChunkVal)
94 break;
95 }
96 Insn.push_back({ AArch64::MOVKXi, Imm16,
98 return true;
99 }
100
101 return false;
102}
103
104/// Check whether this chunk matches the pattern '1...0...'. This pattern
105/// starts a contiguous sequence of ones if we look at the bits from the LSB
106/// towards the MSB.
107static bool isStartChunk(uint64_t Chunk) {
108 if (Chunk == 0 || Chunk == std::numeric_limits<uint64_t>::max())
109 return false;
110
111 return isMask_64(~Chunk);
112}
113
114/// Check whether this chunk matches the pattern '0...1...' This pattern
115/// ends a contiguous sequence of ones if we look at the bits from the LSB
116/// towards the MSB.
117static bool isEndChunk(uint64_t Chunk) {
118 if (Chunk == 0 || Chunk == std::numeric_limits<uint64_t>::max())
119 return false;
120
121 return isMask_64(Chunk);
122}
123
124/// Clear or set all bits in the chunk at the given index.
125static uint64_t updateImm(uint64_t Imm, unsigned Idx, bool Clear) {
126 const uint64_t Mask = 0xFFFF;
127
128 if (Clear)
129 // Clear chunk in the immediate.
130 Imm &= ~(Mask << (Idx * 16));
131 else
132 // Set all bits in the immediate for the particular chunk.
133 Imm |= Mask << (Idx * 16);
134
135 return Imm;
136}
137
138/// Check whether the constant contains a sequence of contiguous ones,
139/// which might be interrupted by one or two chunks. If so, materialize the
140/// sequence of contiguous ones with an ORR instruction.
141/// Materialize the chunks which are either interrupting the sequence or outside
142/// of the sequence with a MOVK instruction.
143///
144/// Assuming S is a chunk which starts the sequence (1...0...), E is a chunk
145/// which ends the sequence (0...1...). Then we are looking for constants which
146/// contain at least one S and E chunk.
147/// E.g. |E|A|B|S|, |A|E|B|S| or |A|B|E|S|.
148///
149/// We are also looking for constants like |S|A|B|E| where the contiguous
150/// sequence of ones wraps around the MSB into the LSB.
153 const int NotSet = -1;
154 const uint64_t Mask = 0xFFFF;
155
156 int StartIdx = NotSet;
157 int EndIdx = NotSet;
158 // Try to find the chunks which start/end a contiguous sequence of ones.
159 for (int Idx = 0; Idx < 4; ++Idx) {
160 int64_t Chunk = getChunk(UImm, Idx);
161 // Sign extend the 16-bit chunk to 64-bit.
162 Chunk = (Chunk << 48) >> 48;
163
164 if (isStartChunk(Chunk))
165 StartIdx = Idx;
166 else if (isEndChunk(Chunk))
167 EndIdx = Idx;
168 }
169
170 // Early exit in case we can't find a start/end chunk.
171 if (StartIdx == NotSet || EndIdx == NotSet)
172 return false;
173
174 // Outside of the contiguous sequence of ones everything needs to be zero.
175 uint64_t Outside = 0;
176 // Chunks between the start and end chunk need to have all their bits set.
177 uint64_t Inside = Mask;
178
179 // If our contiguous sequence of ones wraps around from the MSB into the LSB,
180 // just swap indices and pretend we are materializing a contiguous sequence
181 // of zeros surrounded by a contiguous sequence of ones.
182 if (StartIdx > EndIdx) {
183 std::swap(StartIdx, EndIdx);
184 std::swap(Outside, Inside);
185 }
186
187 uint64_t OrrImm = UImm;
188 int FirstMovkIdx = NotSet;
189 int SecondMovkIdx = NotSet;
190
191 // Find out which chunks we need to patch up to obtain a contiguous sequence
192 // of ones.
193 for (int Idx = 0; Idx < 4; ++Idx) {
194 const uint64_t Chunk = getChunk(UImm, Idx);
195
196 // Check whether we are looking at a chunk which is not part of the
197 // contiguous sequence of ones.
198 if ((Idx < StartIdx || EndIdx < Idx) && Chunk != Outside) {
199 OrrImm = updateImm(OrrImm, Idx, Outside == 0);
200
201 // Remember the index we need to patch.
202 if (FirstMovkIdx == NotSet)
203 FirstMovkIdx = Idx;
204 else
205 SecondMovkIdx = Idx;
206
207 // Check whether we are looking a chunk which is part of the contiguous
208 // sequence of ones.
209 } else if (Idx > StartIdx && Idx < EndIdx && Chunk != Inside) {
210 OrrImm = updateImm(OrrImm, Idx, Inside != Mask);
211
212 // Remember the index we need to patch.
213 if (FirstMovkIdx == NotSet)
214 FirstMovkIdx = Idx;
215 else
216 SecondMovkIdx = Idx;
217 }
218 }
219 assert(FirstMovkIdx != NotSet && "Constant materializable with single ORR!");
220
221 // Create the ORR-immediate instruction.
222 uint64_t Encoding = 0;
223 AArch64_AM::processLogicalImmediate(OrrImm, 64, Encoding);
224 Insn.push_back({ AArch64::ORRXri, 0, Encoding });
225
226 const bool SingleMovk = SecondMovkIdx == NotSet;
227 Insn.push_back({ AArch64::MOVKXi, getChunk(UImm, FirstMovkIdx),
229 FirstMovkIdx * 16) });
230
231 // Early exit in case we only need to emit a single MOVK instruction.
232 if (SingleMovk)
233 return true;
234
235 // Create the second MOVK instruction.
236 Insn.push_back(
237 {AArch64::MOVKXi, getChunk(UImm, SecondMovkIdx),
238 AArch64_AM::getShifterImm(AArch64_AM::LSL, SecondMovkIdx * 16)});
239
240 return true;
241}
242
243// Attempt to expand 64-bit immediate values that consist of shifted negated
244// components such as 0x1234'5678'edcb'a987, where the upper half is the
245// negation of the lower half. Immediates of this form can generally be
246// expanded via a sequence of MOVN+MOVK to expand the lower half, followed by
247// an EOR or EON to shift and negate the result to the upper half, for example:
248// mov x0, #-22137 // =0xffffffffffffa987
249// movk x0, #60875, lsl #16 // =0xffffffffedcba987
250// eor x0, x0, x0, lsl #32 // =0xffffffffedcba987 ^ 0xedcba98700000000
251// =0x12345678edcba987.
252// The logic extends to other shift amounts in the range [17, 48) (outside that
253// range we get runs of ones/zeros that are optimised separately).
254//
255// When the lower half contains a 16-bit chunk of ones, such as
256// 0x0000'5678'ffff'a987, the intermediate MOVK is redundant.
257// Similarly, when it contains a 16-bit chunk of zeros, such as
258// 0xffff'5678'0000'a987, the expansion can instead be effected by expanding
259// the negation of the lower half and negating the result with an EON, e.g.:
260// mov x0, #-43400 // =0xffffffffffff5678
261// eon x0, x0, x0, lsl #32 // =0xffffffffffff5678 ^ ~0xffff567800000000
262// =0xffffffffffff5678 ^ 0x0000a987ffffffff
263// =0xffff56780000a987.
264// In any of these cases, the expansion with EOR/EON saves an instruction
265// compared to the default expansion based on MOV and MOVKs.
266static bool tryCopyWithNegation(uint64_t Imm, bool AllowThreeSequence,
268 // Degenerate cases where Imm is a run of ones should be handled separately.
270 return false;
271
272 const unsigned Mask = 0xffff;
273
274 auto tryExpansion = [&](unsigned Opc, uint64_t C, unsigned N) {
275 assert((C >> 32) == 0xffffffffULL && "Invalid immediate");
276 const unsigned Imm0 = C & Mask;
277 const unsigned Imm16 = (C >> 16) & Mask;
278 if (Imm0 != Mask && Imm16 != Mask && !AllowThreeSequence)
279 return false;
280
281 if (Imm0 != Mask) {
282 Insn.push_back({AArch64::MOVNXi, Imm0 ^ Mask, 0});
283 if (Imm16 != Mask)
284 Insn.push_back({AArch64::MOVKXi, Imm16, 16});
285 } else {
286 Insn.push_back({AArch64::MOVNXi, Imm16 ^ Mask, 16});
287 }
288
289 Insn.push_back({Opc, std::nullopt, N});
290 return true;
291 };
292
293 for (unsigned N = 17; N < 48; ++N) {
294 // Attempt EOR.
295 uint64_t C = 0xffffffff00000000ULL | (Imm ^ (Imm << N));
296 if ((C ^ (C << N)) == Imm && tryExpansion(AArch64::EORXrs, C, N))
297 return true;
298
299 // Attempt EON.
300 C = 0xffffffff00000000ULL | (Imm ^ ~(~Imm << N));
301 if ((C ^ ~(C << N)) == Imm && tryExpansion(AArch64::EONXrs, C, N))
302 return true;
303 }
304
305 return false;
306}
307
309 uint64_t NumOnes = llvm::countr_one(V >> StartPosition);
310
311 uint64_t UnshiftedOnes;
312 if (NumOnes == 64) {
313 UnshiftedOnes = ~0ULL;
314 } else {
315 UnshiftedOnes = (1ULL << NumOnes) - 1;
316 }
317 return UnshiftedOnes << StartPosition;
318}
319
321 uint64_t Result = Subset;
322
323 // 64, 32, 16, 8, 4, 2
324 for (uint64_t i = 0; i < 6; ++i) {
325 uint64_t Rotation = 1ULL << (6 - i);
326 uint64_t Closure = Result | llvm::rotl<uint64_t>(Result, Rotation);
327 if (Closure != (Closure & V)) {
328 break;
329 }
330 Result = Closure;
331 }
332
333 return Result;
334}
335
336// Find the logical immediate that covers the most bits in RemainingBits,
337// allowing for additional bits to be set that were set in OriginalBits.
339 uint64_t OriginalBits) {
340 // Find the first set bit.
341 uint32_t Position = llvm::countr_zero(RemainingBits);
342
343 // Get the first run of set bits.
344 uint64_t FirstRun = GetRunOfOnesStartingAt(OriginalBits, Position);
345
346 // Replicate the run as many times as possible, as long as the bits are set in
347 // RemainingBits.
348 uint64_t MaximalImm = MaximallyReplicateSubImmediate(OriginalBits, FirstRun);
349
350 return MaximalImm;
351}
352
353static std::optional<std::pair<uint64_t, uint64_t>>
355 if (UImm == 0 || ~UImm == 0)
356 return std::nullopt;
357
358 // Make sure we don't have a run of ones split around the rotation boundary.
359 uint32_t InitialTrailingOnes = llvm::countr_one(UImm);
360 uint64_t RotatedBits = llvm::rotr<uint64_t>(UImm, InitialTrailingOnes);
361
362 // Find the largest logical immediate that fits within the full immediate.
363 uint64_t MaximalImm1 = maximalLogicalImmWithin(RotatedBits, RotatedBits);
364
365 // Remove all bits that are set by this mask.
366 uint64_t RemainingBits = RotatedBits & ~MaximalImm1;
367
368 // Find the largest logical immediate covering the remaining bits, allowing
369 // for additional bits to be set that were also set in the original immediate.
370 uint64_t MaximalImm2 = maximalLogicalImmWithin(RemainingBits, RotatedBits);
371
372 // If any bits still haven't been covered, then give up.
373 if (RemainingBits & ~MaximalImm2)
374 return std::nullopt;
375
376 // Make sure to un-rotate the immediates.
377 return std::make_pair(rotl(MaximalImm1, InitialTrailingOnes),
378 rotl(MaximalImm2, InitialTrailingOnes));
379}
380
381// Attempt to expand an immediate as the ORR of a pair of logical immediates.
384 auto MaybeDecomposition = decomposeIntoOrrOfLogicalImmediates(UImm);
385 if (MaybeDecomposition == std::nullopt)
386 return false;
387 uint64_t Imm1 = MaybeDecomposition->first;
388 uint64_t Imm2 = MaybeDecomposition->second;
389
390 uint64_t Encoding1, Encoding2;
391 bool Imm1Success = AArch64_AM::processLogicalImmediate(Imm1, 64, Encoding1);
392 bool Imm2Success = AArch64_AM::processLogicalImmediate(Imm2, 64, Encoding2);
393
394 if (Imm1Success && Imm2Success) {
395 // Create the ORR-immediate instructions.
396 Insn.push_back({AArch64::ORRXri, 0, Encoding1});
397 Insn.push_back({AArch64::ORRXri, 1, Encoding2});
398 return true;
399 }
400
401 return false;
402}
403
404// Attempt to expand an immediate as the AND of a pair of logical immediates.
405// This is done by applying DeMorgan's law, under which logical immediates
406// are closed.
409 // Apply DeMorgan's law to turn this into an ORR problem.
410 auto MaybeDecomposition = decomposeIntoOrrOfLogicalImmediates(~UImm);
411 if (MaybeDecomposition == std::nullopt)
412 return false;
413 uint64_t Imm1 = MaybeDecomposition->first;
414 uint64_t Imm2 = MaybeDecomposition->second;
415
416 uint64_t Encoding1, Encoding2;
417 bool Imm1Success = AArch64_AM::processLogicalImmediate(~Imm1, 64, Encoding1);
418 bool Imm2Success = AArch64_AM::processLogicalImmediate(~Imm2, 64, Encoding2);
419
420 if (Imm1Success && Imm2Success) {
421 // Materialize Imm1, the LHS of the AND
422 Insn.push_back({AArch64::ORRXri, 0, Encoding1});
423 // AND Imm1 with Imm2
424 Insn.push_back({AArch64::ANDXri, 1, Encoding2});
425 return true;
426 }
427
428 return false;
429}
430
431// Check whether the constant can be represented by exclusive-or of two 64-bit
432// logical immediates. If so, materialize it with an ORR instruction followed
433// by an EOR instruction.
434//
435// This encoding allows all remaining repeated byte patterns, and many repeated
436// 16-bit values, to be encoded without needing four instructions. It can also
437// represent some irregular bitmasks (although those would mostly only need
438// three instructions otherwise).
441 // Determine the larger repetition size of the two possible logical
442 // immediates, by finding the repetition size of Imm.
443 unsigned BigSize = 64;
444
445 do {
446 BigSize /= 2;
447 uint64_t Mask = (1ULL << BigSize) - 1;
448
449 if ((Imm & Mask) != ((Imm >> BigSize) & Mask)) {
450 BigSize *= 2;
451 break;
452 }
453 } while (BigSize > 2);
454
455 uint64_t BigMask = ((uint64_t)-1LL) >> (64 - BigSize);
456
457 // Find the last bit of each run of ones, circularly. For runs which wrap
458 // around from bit 0 to bit 63, this is the bit before the most-significant
459 // zero, otherwise it is the least-significant bit in the run of ones.
460 uint64_t RunStarts = Imm & ~rotl<uint64_t>(Imm, 1);
461
462 // Find the smaller repetition size of the two possible logical immediates by
463 // counting the number of runs of one-bits within the BigSize-bit value. Both
464 // sizes may be the same. The EOR may add one or subtract one from the
465 // power-of-two count that can be represented by a logical immediate, or it
466 // may be left unchanged.
467 int RunsPerBigChunk = popcount(RunStarts & BigMask);
468
469 static const int8_t BigToSmallSizeTable[32] = {
470 -1, -1, 0, 1, 2, 2, -1, 3, 3, 3, -1, -1, -1, -1, -1, 4,
471 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5,
472 };
473
474 int BigToSmallShift = BigToSmallSizeTable[RunsPerBigChunk];
475
476 // Early-exit if the big chunk couldn't be a power-of-two number of runs
477 // EORed with another single run.
478 if (BigToSmallShift == -1)
479 return false;
480
481 unsigned SmallSize = BigSize >> BigToSmallShift;
482
483 // 64-bit values with a bit set every (1 << index) bits.
484 static const uint64_t RepeatedOnesTable[] = {
485 0xffffffffffffffff, 0x5555555555555555, 0x1111111111111111,
486 0x0101010101010101, 0x0001000100010001, 0x0000000100000001,
487 0x0000000000000001,
488 };
489
490 // This RepeatedOnesTable lookup is a faster implementation of the division
491 // 0xffffffffffffffff / ((1 << SmallSize) - 1), and can be thought of as
492 // dividing the 64-bit value into fields of width SmallSize, and placing a
493 // one in the least significant bit of each field.
494 uint64_t SmallOnes = RepeatedOnesTable[countr_zero(SmallSize)];
495
496 // Now we try to find the number of ones in each of the smaller repetitions,
497 // by looking at runs of ones in Imm. This can take three attempts, as the
498 // EOR may have changed the length of the first two runs we find.
499
500 // Rotate a run of ones so we can count the number of trailing set bits.
501 int Rotation = countr_zero(RunStarts);
502 uint64_t RotatedImm = rotr<uint64_t>(Imm, Rotation);
503 for (int Attempt = 0; Attempt < 3; ++Attempt) {
504 unsigned RunLength = countr_one(RotatedImm);
505
506 // Construct candidate values BigImm and SmallImm, such that if these two
507 // values are encodable, we have a solution. (SmallImm is constructed to be
508 // encodable, but this isn't guaranteed when RunLength >= SmallSize)
509 uint64_t SmallImm =
510 rotl<uint64_t>((SmallOnes << RunLength) - SmallOnes, Rotation);
511 uint64_t BigImm = Imm ^ SmallImm;
512
513 uint64_t BigEncoding = 0;
514 uint64_t SmallEncoding = 0;
515 if (AArch64_AM::processLogicalImmediate(BigImm, 64, BigEncoding) &&
516 AArch64_AM::processLogicalImmediate(SmallImm, 64, SmallEncoding)) {
517 Insn.push_back({AArch64::ORRXri, 0, SmallEncoding});
518 Insn.push_back({AArch64::EORXri, 1, BigEncoding});
519 return true;
520 }
521
522 // Rotate to the next run of ones
523 Rotation += countr_zero(rotr<uint64_t>(RunStarts, Rotation) & ~1);
524 RotatedImm = rotr<uint64_t>(Imm, Rotation);
525 }
526
527 return false;
528}
529
530/// \brief Expand a MOVi32imm or MOVi64imm pseudo instruction to a
531/// MOVZ or MOVN of width BitSize followed by up to 3 MOVK instructions.
532static inline void expandMOVImmSimple(uint64_t Imm, unsigned BitSize,
533 unsigned OneChunks, unsigned ZeroChunks,
535 const unsigned Mask = 0xFFFF;
536
537 // Use a MOVZ or MOVN instruction to set the high bits, followed by one or
538 // more MOVK instructions to insert additional 16-bit portions into the
539 // lower bits.
540 bool isNeg = false;
541
542 // Use MOVN to materialize the high bits if we have more all one chunks
543 // than all zero chunks.
544 if (OneChunks > ZeroChunks) {
545 isNeg = true;
546 Imm = ~Imm;
547 }
548
549 unsigned FirstOpc;
550 if (BitSize == 32) {
551 Imm &= (1LL << 32) - 1;
552 FirstOpc = (isNeg ? AArch64::MOVNWi : AArch64::MOVZWi);
553 } else {
554 FirstOpc = (isNeg ? AArch64::MOVNXi : AArch64::MOVZXi);
555 }
556 unsigned Shift = 0; // LSL amount for high bits with MOVZ/MOVN
557 unsigned LastShift = 0; // LSL amount for last MOVK
558 if (Imm != 0) {
559 unsigned LZ = llvm::countl_zero(Imm);
560 unsigned TZ = llvm::countr_zero(Imm);
561 Shift = (TZ / 16) * 16;
562 LastShift = ((63 - LZ) / 16) * 16;
563 }
564 unsigned Imm16 = (Imm >> Shift) & Mask;
565
566 Insn.push_back({ FirstOpc, Imm16,
568
569 if (Shift == LastShift)
570 return;
571
572 // If a MOVN was used for the high bits of a negative value, flip the rest
573 // of the bits back for use with MOVK.
574 if (isNeg)
575 Imm = ~Imm;
576
577 unsigned Opc = (BitSize == 32 ? AArch64::MOVKWi : AArch64::MOVKXi);
578 while (Shift < LastShift) {
579 Shift += 16;
580 Imm16 = (Imm >> Shift) & Mask;
581 if (Imm16 == (isNeg ? Mask : 0))
582 continue; // This 16-bit portion is already set correctly.
583
584 Insn.push_back({ Opc, Imm16,
586 }
587
588 // Now, we get 16-bit divided Imm. If high and low bits are same in
589 // 32-bit, there is an opportunity to reduce instruction.
590 if (Insn.size() > 2 && (Imm >> 32) == (Imm & 0xffffffffULL)) {
591 for (int Size = Insn.size(); Size > 2; Size--)
592 Insn.pop_back();
593 Insn.push_back({AArch64::ORRXrs, 0, 32});
594 }
595}
596
597/// Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more
598/// real move-immediate instructions to synthesize the immediate.
599void AArch64_IMM::expandMOVImm(uint64_t Imm, unsigned BitSize,
601 const unsigned Mask = 0xFFFF;
602
603 // Scan the immediate and count the number of 16-bit chunks which are either
604 // all ones or all zeros.
605 unsigned OneChunks = 0;
606 unsigned ZeroChunks = 0;
607 for (unsigned Shift = 0; Shift < BitSize; Shift += 16) {
608 const unsigned Chunk = (Imm >> Shift) & Mask;
609 if (Chunk == Mask)
610 OneChunks++;
611 else if (Chunk == 0)
612 ZeroChunks++;
613 }
614
615 // Prefer MOVZ/MOVN over ORR because of the rules for the "mov" alias.
616 if ((BitSize / 16) - OneChunks <= 1 || (BitSize / 16) - ZeroChunks <= 1) {
617 expandMOVImmSimple(Imm, BitSize, OneChunks, ZeroChunks, Insn);
618 assert(Insn.size() == 1 &&
619 "Move of immediate should have expanded to a single MOVZ/MOVN");
620 return;
621 }
622
623 // Try a single ORR.
624 uint64_t UImm = Imm << (64 - BitSize) >> (64 - BitSize);
625 uint64_t Encoding;
626 if (AArch64_AM::processLogicalImmediate(UImm, BitSize, Encoding)) {
627 unsigned Opc = (BitSize == 32 ? AArch64::ORRWri : AArch64::ORRXri);
628 Insn.push_back({ Opc, 0, Encoding });
629 return;
630 }
631
632 // One to up three instruction sequences.
633 //
634 // Prefer MOVZ/MOVN followed by MOVK; it's more readable, and possibly the
635 // fastest sequence with fast literal generation.
636 if (OneChunks >= (BitSize / 16) - 2 || ZeroChunks >= (BitSize / 16) - 2) {
637 expandMOVImmSimple(Imm, BitSize, OneChunks, ZeroChunks, Insn);
638 return;
639 }
640
641 assert(BitSize == 64 && "All 32-bit immediates can be expanded with a"
642 "MOVZ/MOVK pair");
643
644 // Try other two-instruction sequences.
645
646 // 64-bit ORR followed by MOVK.
647 // We try to construct the ORR immediate in three different ways: either we
648 // zero out the chunk which will be replaced, we fill the chunk which will
649 // be replaced with ones, or we take the bit pattern from the other half of
650 // the 64-bit immediate. This is comprehensive because of the way ORR
651 // immediates are constructed.
652 for (unsigned Shift = 0; Shift < BitSize; Shift += 16) {
653 uint64_t ShiftedMask = (0xFFFFULL << Shift);
654 uint64_t ZeroChunk = UImm & ~ShiftedMask;
655 uint64_t OneChunk = UImm | ShiftedMask;
656 uint64_t RotatedImm = llvm::rotl(UImm, 32);
657 uint64_t ReplicateChunk = ZeroChunk | (RotatedImm & ShiftedMask);
658 if (AArch64_AM::processLogicalImmediate(ZeroChunk, BitSize, Encoding) ||
659 AArch64_AM::processLogicalImmediate(OneChunk, BitSize, Encoding) ||
660 AArch64_AM::processLogicalImmediate(ReplicateChunk, BitSize,
661 Encoding)) {
662 // Create the ORR-immediate instruction.
663 Insn.push_back({ AArch64::ORRXri, 0, Encoding });
664
665 // Create the MOVK instruction.
666 const unsigned Imm16 = getChunk(UImm, Shift / 16);
667 Insn.push_back({ AArch64::MOVKXi, Imm16,
669 return;
670 }
671 }
672
673 // Attempt to use a sequence of two ORR-immediate instructions.
675 return;
676
677 // Attempt to use a sequence of ORR-immediate followed by AND-immediate.
679 return;
680
681 // Attempt to use a sequence of ORR-immediate followed by EOR-immediate.
682 if (tryEorOfLogicalImmediates(UImm, Insn))
683 return;
684
685 // Attempt to use a sequence of MOVN+EOR/EON (shifted register).
686 if (tryCopyWithNegation(Imm, /*AllowThreeSequence=*/false, Insn))
687 return;
688
689 // FIXME: Add more two-instruction sequences.
690
691 // Three instruction sequences.
692 //
693 // Prefer MOVZ/MOVN followed by two MOVK; it's more readable, and possibly
694 // the fastest sequence with fast literal generation. (If neither MOVK is
695 // part of a fast literal generation pair, it could be slower than the
696 // four-instruction sequence, but we won't worry about that for now.)
697 if (OneChunks || ZeroChunks) {
698 expandMOVImmSimple(Imm, BitSize, OneChunks, ZeroChunks, Insn);
699 return;
700 }
701
702 // Check for identical 16-bit chunks within the constant and if so materialize
703 // them with a single ORR instruction. The remaining one or two 16-bit chunks
704 // will be materialized with MOVK instructions.
705 if (BitSize == 64 && tryToreplicateChunks(UImm, Insn))
706 return;
707
708 // Check whether the constant contains a sequence of contiguous ones, which
709 // might be interrupted by one or two chunks. If so, materialize the sequence
710 // of contiguous ones with an ORR instruction. Materialize the chunks which
711 // are either interrupting the sequence or outside of the sequence with a
712 // MOVK instruction.
713 if (BitSize == 64 && trySequenceOfOnes(UImm, Insn))
714 return;
715
716 // Attempt to use a sequence of MOVN+MOVK+EOR/EON (shifted register).
717 if (tryCopyWithNegation(Imm, /*AllowThreeSequence=*/true, Insn))
718 return;
719
720 // We found no possible two or three instruction sequence; use the general
721 // four-instruction sequence.
722 expandMOVImmSimple(Imm, BitSize, OneChunks, ZeroChunks, Insn);
723}
724
725void AArch64_IMM::expandMOVAddr(unsigned Opcode, unsigned TargetFlags,
726 bool IsTargetMachO,
728 if (Opcode == AArch64::MOVaddrBA && IsTargetMachO) {
729 // Block address on Mach-O goes through a constant pool.
730 Insn.push_back({AArch64::ADRP});
731 Insn.push_back({AArch64::LDRXui});
732 return;
733 }
734 Insn.push_back({AArch64::ADRP});
735 if (TargetFlags & AArch64II::MO_TAGGED)
736 Insn.push_back({AArch64::MOVKXi});
737 Insn.push_back({AArch64::ADDXri});
738}
739
742 const AArch64Subtarget &ST) {
743 assert((Imm.getBitWidth() == 64 || Imm.getBitWidth() == 128) &&
744 "Expected vector sized constant");
745 bool Is64Bit = Imm.getBitWidth() == 64;
746
747 if (ST.isNeonAvailable() && Imm.getHiBits(64) == Imm.getLoBits(64)) {
748 uint64_t Value = Imm.trunc(64).getZExtValue();
749 if (Value == 0) {
750 Insns.push_back({AArch64::FMOVD0, std::nullopt, std::nullopt});
751 return true;
752 }
754 unsigned Opc = Is64Bit ? AArch64::MOVID : AArch64::MOVIv2d_ns;
755 Insns.push_back(
757 return true;
758 }
760 unsigned Opc = Is64Bit ? AArch64::MOVIv2i32 : AArch64::MOVIv4i32;
762 return true;
763 }
765 unsigned Opc = Is64Bit ? AArch64::MOVIv2i32 : AArch64::MOVIv4i32;
767 return true;
768 }
770 unsigned Opc = Is64Bit ? AArch64::MOVIv2i32 : AArch64::MOVIv4i32;
772 return true;
773 }
775 unsigned Opc = Is64Bit ? AArch64::MOVIv2i32 : AArch64::MOVIv4i32;
777 return true;
778 }
780 unsigned Opc = Is64Bit ? AArch64::MOVIv4i16 : AArch64::MOVIv8i16;
782 return true;
783 }
785 unsigned Opc = Is64Bit ? AArch64::MOVIv4i16 : AArch64::MOVIv8i16;
787 return true;
788 }
790 unsigned Opc = Is64Bit ? AArch64::MOVIv2s_msl : AArch64::MOVIv4s_msl;
792 return true;
793 }
795 unsigned Opc = Is64Bit ? AArch64::MOVIv2s_msl : AArch64::MOVIv4s_msl;
797 return true;
798 }
800 unsigned Opc = Is64Bit ? AArch64::MOVIv8b_ns : AArch64::MOVIv16b_ns;
801 Insns.push_back(
803 return true;
804 }
806 unsigned Opc = Is64Bit ? AArch64::FMOVv2f32_ns : AArch64::FMOVv4f32_ns;
807 Insns.push_back(
809 return true;
810 }
812 unsigned Opc = Is64Bit ? AArch64::FMOVDi : AArch64::FMOVv2f64_ns;
813 Insns.push_back(
815 return true;
816 }
817
818 APInt NotImm = ~Imm;
819 Value = NotImm.trunc(64).getZExtValue();
821 unsigned Opc = Is64Bit ? AArch64::MVNIv2i32 : AArch64::MVNIv4i32;
823 return true;
824 }
826 unsigned Opc = Is64Bit ? AArch64::MVNIv2i32 : AArch64::MVNIv4i32;
828 return true;
829 }
831 unsigned Opc = Is64Bit ? AArch64::MVNIv2i32 : AArch64::MVNIv4i32;
833 return true;
834 }
836 unsigned Opc = Is64Bit ? AArch64::MVNIv2i32 : AArch64::MVNIv4i32;
838 return true;
839 }
841 unsigned Opc = Is64Bit ? AArch64::MVNIv4i16 : AArch64::MVNIv8i16;
843 return true;
844 }
846 unsigned Opc = Is64Bit ? AArch64::MVNIv4i16 : AArch64::MVNIv8i16;
848 return true;
849 }
851 unsigned Opc = Is64Bit ? AArch64::MVNIv2s_msl : AArch64::MVNIv4s_msl;
853 return true;
854 }
856 unsigned Opc = Is64Bit ? AArch64::MVNIv2s_msl : AArch64::MVNIv4s_msl;
858 return true;
859 }
860 }
861
862 if (ST.isNeonAvailable() && ST.hasFullFP16() && Imm.isSplat(16)) {
863 int Enc = AArch64_AM::getFP16Imm(Imm.trunc(16));
864 if (Enc != -1) {
865 unsigned Opc = Is64Bit ? AArch64::FMOVv4f16_ns : AArch64::FMOVv8f16_ns;
866 Insns.push_back({Opc, Enc, std::nullopt});
867 return true;
868 }
869 }
870
871 // TODO: We should be able to support 64-bit destinations too
872 if (ST.hasSVE() && !Is64Bit && Imm.getHiBits(64) == Imm.getLoBits(64)) {
873 // See if we can make use of the SVE dup instruction.
874 APInt Val64 = Imm.trunc(64);
875 int32_t ImmVal, ShiftVal;
876 if (AArch64_AM::isSVECpyDupImm(64, Val64.getSExtValue(), ImmVal,
877 ShiftVal)) {
878 Insns.push_back(
879 {AArch64::DUP_ZI_D, (uint64_t)ImmVal, (uint64_t)ShiftVal});
880 return true;
881 }
882 uint64_t Encoding;
883 if (AArch64_AM::isSVELogicalImm(64, Val64.getZExtValue(), Encoding)) {
884 Insns.push_back({AArch64::DUPM_ZI, Encoding, std::nullopt});
885 return true;
886 }
887 }
888
889 return false;
890}
static bool tryCopyWithNegation(uint64_t Imm, bool AllowThreeSequence, SmallVectorImpl< ImmInsnModel > &Insn)
static uint64_t GetRunOfOnesStartingAt(uint64_t V, uint64_t StartPosition)
static void expandMOVImmSimple(uint64_t Imm, unsigned BitSize, unsigned OneChunks, unsigned ZeroChunks, SmallVectorImpl< ImmInsnModel > &Insn)
Expand a MOVi32imm or MOVi64imm pseudo instruction to a MOVZ or MOVN of width BitSize followed by up ...
static uint64_t updateImm(uint64_t Imm, unsigned Idx, bool Clear)
Clear or set all bits in the chunk at the given index.
static bool canUseOrr(uint64_t Chunk, uint64_t &Encoding)
Check whether the given 16-bit chunk replicated to full 64-bit width can be materialized with an ORR ...
static bool tryToreplicateChunks(uint64_t UImm, SmallVectorImpl< ImmInsnModel > &Insn)
Check for identical 16-bit chunks within the constant and if so materialize them with a single ORR in...
static bool trySequenceOfOnes(uint64_t UImm, SmallVectorImpl< ImmInsnModel > &Insn)
Check whether the constant contains a sequence of contiguous ones, which might be interrupted by one ...
static uint64_t MaximallyReplicateSubImmediate(uint64_t V, uint64_t Subset)
static bool tryAndOfLogicalImmediates(uint64_t UImm, SmallVectorImpl< ImmInsnModel > &Insn)
static uint64_t getChunk(uint64_t Imm, unsigned ChunkIdx)
Helper function which extracts the specified 16-bit chunk from a 64-bit value.
static bool tryEorOfLogicalImmediates(uint64_t Imm, SmallVectorImpl< ImmInsnModel > &Insn)
static uint64_t maximalLogicalImmWithin(uint64_t RemainingBits, uint64_t OriginalBits)
static bool isStartChunk(uint64_t Chunk)
Check whether this chunk matches the pattern '1...0...'.
static bool isEndChunk(uint64_t Chunk)
Check whether this chunk matches the pattern '0...1...' This pattern ends a contiguous sequence of on...
static bool tryOrrOfLogicalImmediates(uint64_t UImm, SmallVectorImpl< ImmInsnModel > &Insn)
static std::optional< std::pair< uint64_t, uint64_t > > decomposeIntoOrrOfLogicalImmediates(uint64_t UImm)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned Imm
unsigned uint64_t
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static bool isNeg(Value *V)
Returns true if the operation is a negation of V, and it works for both integers and floats.
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:970
int64_t getSExtValue() const
Get sign extended value.
Definition APInt.h:1582
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
LLVM Value Representation.
Definition Value.h:75
@ MO_TAGGED
MO_TAGGED - With MO_PAGE, indicates that the page includes a memory tag in bits 56-63.
static uint8_t encodeAdvSIMDModImmType2(uint64_t Imm)
static bool processLogicalImmediate(uint64_t Imm, unsigned RegSize, uint64_t &Encoding)
processLogicalImmediate - Determine if an immediate value can be encoded as the immediate operand of ...
static bool isAdvSIMDModImmType9(uint64_t Imm)
static bool isAdvSIMDModImmType4(uint64_t Imm)
static bool isAdvSIMDModImmType5(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType10(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType9(uint64_t Imm)
static bool isAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType5(uint64_t Imm)
static bool isAdvSIMDModImmType10(uint64_t Imm)
static int getFP16Imm(const APInt &Imm)
getFP16Imm - Return an 8-bit floating-point version of the 16-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType8(uint64_t Imm)
static bool isAdvSIMDModImmType12(uint64_t Imm)
static bool isSVELogicalImm(unsigned SizeInBits, uint64_t ImmVal, uint64_t &Encoding)
static uint8_t encodeAdvSIMDModImmType11(uint64_t Imm)
static bool isSVECpyDupImm(int SizeInBits, int64_t Val, int32_t &Imm, int32_t &Shift)
static bool isAdvSIMDModImmType11(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType6(uint64_t Imm)
static bool isAdvSIMDModImmType8(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType4(uint64_t Imm)
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
static bool isAdvSIMDModImmType6(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType1(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType3(uint64_t Imm)
static bool isAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType3(uint64_t Imm)
static bool isAdvSIMDModImmType1(uint64_t Imm)
void expandMOVAddr(unsigned Opcode, unsigned TargetFlags, bool IsTargetMachO, SmallVectorImpl< AddrInsnModel > &Insn)
bool expandVectorMOVImm(APInt Imm, SmallVectorImpl< ImmInsnModel > &Insn, const AArch64Subtarget &ST)
void expandMOVImm(uint64_t Imm, unsigned BitSize, SmallVectorImpl< ImmInsnModel > &Insn)
Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more real move-immediate instructions to...
This is an optimization pass for GlobalISel generic memory operations.
constexpr T rotr(T V, int R)
Definition bit.h:399
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
Definition bit.h:315
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
Definition bit.h:156
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
Definition bit.h:204
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
Definition MathExtras.h:274
int countl_zero(T Val)
Count number of 0's from the most significant bit to the least stopping at the first 1.
Definition bit.h:263
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
Definition MathExtras.h:262
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
constexpr T rotl(T V, int R)
Definition bit.h:386
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N