xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64ExpandImm.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- AArch64ExpandImm.h - AArch64 Immediate Expansion -------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the AArch64ExpandImm stuff.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "AArch64.h"
140b57cec5SDimitry Andric #include "AArch64ExpandImm.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/AArch64AddressingModes.h"
160b57cec5SDimitry Andric 
17fe6060f1SDimitry Andric using namespace llvm;
18fe6060f1SDimitry Andric using namespace llvm::AArch64_IMM;
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric /// Helper function which extracts the specified 16-bit chunk from a
210b57cec5SDimitry Andric /// 64-bit value.
220b57cec5SDimitry Andric static uint64_t getChunk(uint64_t Imm, unsigned ChunkIdx) {
230b57cec5SDimitry Andric   assert(ChunkIdx < 4 && "Out of range chunk index specified!");
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric   return (Imm >> (ChunkIdx * 16)) & 0xFFFF;
260b57cec5SDimitry Andric }
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric /// Check whether the given 16-bit chunk replicated to full 64-bit width
290b57cec5SDimitry Andric /// can be materialized with an ORR instruction.
300b57cec5SDimitry Andric static bool canUseOrr(uint64_t Chunk, uint64_t &Encoding) {
310b57cec5SDimitry Andric   Chunk = (Chunk << 48) | (Chunk << 32) | (Chunk << 16) | Chunk;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric   return AArch64_AM::processLogicalImmediate(Chunk, 64, Encoding);
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric /// Check for identical 16-bit chunks within the constant and if so
370b57cec5SDimitry Andric /// materialize them with a single ORR instruction. The remaining one or two
380b57cec5SDimitry Andric /// 16-bit chunks will be materialized with MOVK instructions.
390b57cec5SDimitry Andric ///
400b57cec5SDimitry Andric /// This allows us to materialize constants like |A|B|A|A| or |A|B|C|A| (order
410b57cec5SDimitry Andric /// of the chunks doesn't matter), assuming |A|A|A|A| can be materialized with
420b57cec5SDimitry Andric /// an ORR instruction.
430b57cec5SDimitry Andric static bool tryToreplicateChunks(uint64_t UImm,
440b57cec5SDimitry Andric 				 SmallVectorImpl<ImmInsnModel> &Insn) {
450b57cec5SDimitry Andric   using CountMap = DenseMap<uint64_t, unsigned>;
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   CountMap Counts;
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   // Scan the constant and count how often every chunk occurs.
500b57cec5SDimitry Andric   for (unsigned Idx = 0; Idx < 4; ++Idx)
510b57cec5SDimitry Andric     ++Counts[getChunk(UImm, Idx)];
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   // Traverse the chunks to find one which occurs more than once.
540eae32dcSDimitry Andric   for (const auto &Chunk : Counts) {
550eae32dcSDimitry Andric     const uint64_t ChunkVal = Chunk.first;
560eae32dcSDimitry Andric     const unsigned Count = Chunk.second;
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric     uint64_t Encoding = 0;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric     // We are looking for chunks which have two or three instances and can be
610b57cec5SDimitry Andric     // materialized with an ORR instruction.
620b57cec5SDimitry Andric     if ((Count != 2 && Count != 3) || !canUseOrr(ChunkVal, Encoding))
630b57cec5SDimitry Andric       continue;
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric     const bool CountThree = Count == 3;
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric     Insn.push_back({ AArch64::ORRXri, 0, Encoding });
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric     unsigned ShiftAmt = 0;
700b57cec5SDimitry Andric     uint64_t Imm16 = 0;
710b57cec5SDimitry Andric     // Find the first chunk not materialized with the ORR instruction.
720b57cec5SDimitry Andric     for (; ShiftAmt < 64; ShiftAmt += 16) {
730b57cec5SDimitry Andric       Imm16 = (UImm >> ShiftAmt) & 0xFFFF;
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric       if (Imm16 != ChunkVal)
760b57cec5SDimitry Andric         break;
770b57cec5SDimitry Andric     }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric     // Create the first MOVK instruction.
800b57cec5SDimitry Andric     Insn.push_back({ AArch64::MOVKXi, Imm16,
810b57cec5SDimitry Andric 		     AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt) });
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric     // In case we have three instances the whole constant is now materialized
840b57cec5SDimitry Andric     // and we can exit.
850b57cec5SDimitry Andric     if (CountThree)
860b57cec5SDimitry Andric       return true;
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric     // Find the remaining chunk which needs to be materialized.
890b57cec5SDimitry Andric     for (ShiftAmt += 16; ShiftAmt < 64; ShiftAmt += 16) {
900b57cec5SDimitry Andric       Imm16 = (UImm >> ShiftAmt) & 0xFFFF;
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric       if (Imm16 != ChunkVal)
930b57cec5SDimitry Andric         break;
940b57cec5SDimitry Andric     }
950b57cec5SDimitry Andric     Insn.push_back({ AArch64::MOVKXi, Imm16,
960b57cec5SDimitry Andric                      AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt) });
970b57cec5SDimitry Andric     return true;
980b57cec5SDimitry Andric   }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   return false;
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric /// Check whether this chunk matches the pattern '1...0...'. This pattern
1040b57cec5SDimitry Andric /// starts a contiguous sequence of ones if we look at the bits from the LSB
1050b57cec5SDimitry Andric /// towards the MSB.
1060b57cec5SDimitry Andric static bool isStartChunk(uint64_t Chunk) {
1070b57cec5SDimitry Andric   if (Chunk == 0 || Chunk == std::numeric_limits<uint64_t>::max())
1080b57cec5SDimitry Andric     return false;
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   return isMask_64(~Chunk);
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric /// Check whether this chunk matches the pattern '0...1...' This pattern
1140b57cec5SDimitry Andric /// ends a contiguous sequence of ones if we look at the bits from the LSB
1150b57cec5SDimitry Andric /// towards the MSB.
1160b57cec5SDimitry Andric static bool isEndChunk(uint64_t Chunk) {
1170b57cec5SDimitry Andric   if (Chunk == 0 || Chunk == std::numeric_limits<uint64_t>::max())
1180b57cec5SDimitry Andric     return false;
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   return isMask_64(Chunk);
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric /// Clear or set all bits in the chunk at the given index.
1240b57cec5SDimitry Andric static uint64_t updateImm(uint64_t Imm, unsigned Idx, bool Clear) {
1250b57cec5SDimitry Andric   const uint64_t Mask = 0xFFFF;
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   if (Clear)
1280b57cec5SDimitry Andric     // Clear chunk in the immediate.
1290b57cec5SDimitry Andric     Imm &= ~(Mask << (Idx * 16));
1300b57cec5SDimitry Andric   else
1310b57cec5SDimitry Andric     // Set all bits in the immediate for the particular chunk.
1320b57cec5SDimitry Andric     Imm |= Mask << (Idx * 16);
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   return Imm;
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric /// Check whether the constant contains a sequence of contiguous ones,
1380b57cec5SDimitry Andric /// which might be interrupted by one or two chunks. If so, materialize the
1390b57cec5SDimitry Andric /// sequence of contiguous ones with an ORR instruction.
1400b57cec5SDimitry Andric /// Materialize the chunks which are either interrupting the sequence or outside
1410b57cec5SDimitry Andric /// of the sequence with a MOVK instruction.
1420b57cec5SDimitry Andric ///
1430b57cec5SDimitry Andric /// Assuming S is a chunk which starts the sequence (1...0...), E is a chunk
1440b57cec5SDimitry Andric /// which ends the sequence (0...1...). Then we are looking for constants which
1450b57cec5SDimitry Andric /// contain at least one S and E chunk.
1460b57cec5SDimitry Andric /// E.g. |E|A|B|S|, |A|E|B|S| or |A|B|E|S|.
1470b57cec5SDimitry Andric ///
1480b57cec5SDimitry Andric /// We are also looking for constants like |S|A|B|E| where the contiguous
1490b57cec5SDimitry Andric /// sequence of ones wraps around the MSB into the LSB.
1500b57cec5SDimitry Andric static bool trySequenceOfOnes(uint64_t UImm,
1510b57cec5SDimitry Andric                               SmallVectorImpl<ImmInsnModel> &Insn) {
1520b57cec5SDimitry Andric   const int NotSet = -1;
1530b57cec5SDimitry Andric   const uint64_t Mask = 0xFFFF;
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   int StartIdx = NotSet;
1560b57cec5SDimitry Andric   int EndIdx = NotSet;
1570b57cec5SDimitry Andric   // Try to find the chunks which start/end a contiguous sequence of ones.
1580b57cec5SDimitry Andric   for (int Idx = 0; Idx < 4; ++Idx) {
1590b57cec5SDimitry Andric     int64_t Chunk = getChunk(UImm, Idx);
1600b57cec5SDimitry Andric     // Sign extend the 16-bit chunk to 64-bit.
1610b57cec5SDimitry Andric     Chunk = (Chunk << 48) >> 48;
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric     if (isStartChunk(Chunk))
1640b57cec5SDimitry Andric       StartIdx = Idx;
1650b57cec5SDimitry Andric     else if (isEndChunk(Chunk))
1660b57cec5SDimitry Andric       EndIdx = Idx;
1670b57cec5SDimitry Andric   }
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric   // Early exit in case we can't find a start/end chunk.
1700b57cec5SDimitry Andric   if (StartIdx == NotSet || EndIdx == NotSet)
1710b57cec5SDimitry Andric     return false;
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   // Outside of the contiguous sequence of ones everything needs to be zero.
1740b57cec5SDimitry Andric   uint64_t Outside = 0;
1750b57cec5SDimitry Andric   // Chunks between the start and end chunk need to have all their bits set.
1760b57cec5SDimitry Andric   uint64_t Inside = Mask;
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   // If our contiguous sequence of ones wraps around from the MSB into the LSB,
1790b57cec5SDimitry Andric   // just swap indices and pretend we are materializing a contiguous sequence
1800b57cec5SDimitry Andric   // of zeros surrounded by a contiguous sequence of ones.
1810b57cec5SDimitry Andric   if (StartIdx > EndIdx) {
1820b57cec5SDimitry Andric     std::swap(StartIdx, EndIdx);
1830b57cec5SDimitry Andric     std::swap(Outside, Inside);
1840b57cec5SDimitry Andric   }
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   uint64_t OrrImm = UImm;
1870b57cec5SDimitry Andric   int FirstMovkIdx = NotSet;
1880b57cec5SDimitry Andric   int SecondMovkIdx = NotSet;
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   // Find out which chunks we need to patch up to obtain a contiguous sequence
1910b57cec5SDimitry Andric   // of ones.
1920b57cec5SDimitry Andric   for (int Idx = 0; Idx < 4; ++Idx) {
1930b57cec5SDimitry Andric     const uint64_t Chunk = getChunk(UImm, Idx);
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric     // Check whether we are looking at a chunk which is not part of the
1960b57cec5SDimitry Andric     // contiguous sequence of ones.
1970b57cec5SDimitry Andric     if ((Idx < StartIdx || EndIdx < Idx) && Chunk != Outside) {
1980b57cec5SDimitry Andric       OrrImm = updateImm(OrrImm, Idx, Outside == 0);
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric       // Remember the index we need to patch.
2010b57cec5SDimitry Andric       if (FirstMovkIdx == NotSet)
2020b57cec5SDimitry Andric         FirstMovkIdx = Idx;
2030b57cec5SDimitry Andric       else
2040b57cec5SDimitry Andric         SecondMovkIdx = Idx;
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric       // Check whether we are looking a chunk which is part of the contiguous
2070b57cec5SDimitry Andric       // sequence of ones.
2080b57cec5SDimitry Andric     } else if (Idx > StartIdx && Idx < EndIdx && Chunk != Inside) {
2090b57cec5SDimitry Andric       OrrImm = updateImm(OrrImm, Idx, Inside != Mask);
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric       // Remember the index we need to patch.
2120b57cec5SDimitry Andric       if (FirstMovkIdx == NotSet)
2130b57cec5SDimitry Andric         FirstMovkIdx = Idx;
2140b57cec5SDimitry Andric       else
2150b57cec5SDimitry Andric         SecondMovkIdx = Idx;
2160b57cec5SDimitry Andric     }
2170b57cec5SDimitry Andric   }
2180b57cec5SDimitry Andric   assert(FirstMovkIdx != NotSet && "Constant materializable with single ORR!");
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   // Create the ORR-immediate instruction.
2210b57cec5SDimitry Andric   uint64_t Encoding = 0;
2220b57cec5SDimitry Andric   AArch64_AM::processLogicalImmediate(OrrImm, 64, Encoding);
2230b57cec5SDimitry Andric   Insn.push_back({ AArch64::ORRXri, 0, Encoding });
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   const bool SingleMovk = SecondMovkIdx == NotSet;
2260b57cec5SDimitry Andric   Insn.push_back({ AArch64::MOVKXi, getChunk(UImm, FirstMovkIdx),
2270b57cec5SDimitry Andric                    AArch64_AM::getShifterImm(AArch64_AM::LSL,
2280b57cec5SDimitry Andric                                              FirstMovkIdx * 16) });
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   // Early exit in case we only need to emit a single MOVK instruction.
2310b57cec5SDimitry Andric   if (SingleMovk)
2320b57cec5SDimitry Andric     return true;
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   // Create the second MOVK instruction.
2350b57cec5SDimitry Andric   Insn.push_back({ AArch64::MOVKXi, getChunk(UImm, SecondMovkIdx),
2360b57cec5SDimitry Andric 	           AArch64_AM::getShifterImm(AArch64_AM::LSL,
2370b57cec5SDimitry Andric                                              SecondMovkIdx * 16) });
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   return true;
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric 
24206c3fb27SDimitry Andric static uint64_t GetRunOfOnesStartingAt(uint64_t V, uint64_t StartPosition) {
24306c3fb27SDimitry Andric   uint64_t NumOnes = llvm::countr_one(V >> StartPosition);
24406c3fb27SDimitry Andric 
24506c3fb27SDimitry Andric   uint64_t UnshiftedOnes;
24606c3fb27SDimitry Andric   if (NumOnes == 64) {
24706c3fb27SDimitry Andric     UnshiftedOnes = ~0ULL;
24806c3fb27SDimitry Andric   } else {
24906c3fb27SDimitry Andric     UnshiftedOnes = (1ULL << NumOnes) - 1;
25006c3fb27SDimitry Andric   }
25106c3fb27SDimitry Andric   return UnshiftedOnes << StartPosition;
25206c3fb27SDimitry Andric }
25306c3fb27SDimitry Andric 
25406c3fb27SDimitry Andric static uint64_t MaximallyReplicateSubImmediate(uint64_t V, uint64_t Subset) {
25506c3fb27SDimitry Andric   uint64_t Result = Subset;
25606c3fb27SDimitry Andric 
25706c3fb27SDimitry Andric   // 64, 32, 16, 8, 4, 2
25806c3fb27SDimitry Andric   for (uint64_t i = 0; i < 6; ++i) {
25906c3fb27SDimitry Andric     uint64_t Rotation = 1ULL << (6 - i);
26006c3fb27SDimitry Andric     uint64_t Closure = Result | llvm::rotl<uint64_t>(Result, Rotation);
26106c3fb27SDimitry Andric     if (Closure != (Closure & V)) {
26206c3fb27SDimitry Andric       break;
26306c3fb27SDimitry Andric     }
26406c3fb27SDimitry Andric     Result = Closure;
26506c3fb27SDimitry Andric   }
26606c3fb27SDimitry Andric 
26706c3fb27SDimitry Andric   return Result;
26806c3fb27SDimitry Andric }
26906c3fb27SDimitry Andric 
27006c3fb27SDimitry Andric // Find the logical immediate that covers the most bits in RemainingBits,
27106c3fb27SDimitry Andric // allowing for additional bits to be set that were set in OriginalBits.
27206c3fb27SDimitry Andric static uint64_t maximalLogicalImmWithin(uint64_t RemainingBits,
27306c3fb27SDimitry Andric                                         uint64_t OriginalBits) {
27406c3fb27SDimitry Andric   // Find the first set bit.
27506c3fb27SDimitry Andric   uint32_t Position = llvm::countr_zero(RemainingBits);
27606c3fb27SDimitry Andric 
27706c3fb27SDimitry Andric   // Get the first run of set bits.
27806c3fb27SDimitry Andric   uint64_t FirstRun = GetRunOfOnesStartingAt(OriginalBits, Position);
27906c3fb27SDimitry Andric 
28006c3fb27SDimitry Andric   // Replicate the run as many times as possible, as long as the bits are set in
28106c3fb27SDimitry Andric   // RemainingBits.
28206c3fb27SDimitry Andric   uint64_t MaximalImm = MaximallyReplicateSubImmediate(OriginalBits, FirstRun);
28306c3fb27SDimitry Andric 
28406c3fb27SDimitry Andric   return MaximalImm;
28506c3fb27SDimitry Andric }
28606c3fb27SDimitry Andric 
28706c3fb27SDimitry Andric static std::optional<std::pair<uint64_t, uint64_t>>
28806c3fb27SDimitry Andric decomposeIntoOrrOfLogicalImmediates(uint64_t UImm) {
28906c3fb27SDimitry Andric   if (UImm == 0 || ~UImm == 0)
29006c3fb27SDimitry Andric     return std::nullopt;
29106c3fb27SDimitry Andric 
29206c3fb27SDimitry Andric   // Make sure we don't have a run of ones split around the rotation boundary.
29306c3fb27SDimitry Andric   uint32_t InitialTrailingOnes = llvm::countr_one(UImm);
29406c3fb27SDimitry Andric   uint64_t RotatedBits = llvm::rotr<uint64_t>(UImm, InitialTrailingOnes);
29506c3fb27SDimitry Andric 
29606c3fb27SDimitry Andric   // Find the largest logical immediate that fits within the full immediate.
29706c3fb27SDimitry Andric   uint64_t MaximalImm1 = maximalLogicalImmWithin(RotatedBits, RotatedBits);
29806c3fb27SDimitry Andric 
29906c3fb27SDimitry Andric   // Remove all bits that are set by this mask.
30006c3fb27SDimitry Andric   uint64_t RemainingBits = RotatedBits & ~MaximalImm1;
30106c3fb27SDimitry Andric 
30206c3fb27SDimitry Andric   // Find the largest logical immediate covering the remaining bits, allowing
30306c3fb27SDimitry Andric   // for additional bits to be set that were also set in the original immediate.
30406c3fb27SDimitry Andric   uint64_t MaximalImm2 = maximalLogicalImmWithin(RemainingBits, RotatedBits);
30506c3fb27SDimitry Andric 
30606c3fb27SDimitry Andric   // If any bits still haven't been covered, then give up.
30706c3fb27SDimitry Andric   if (RemainingBits & ~MaximalImm2)
30806c3fb27SDimitry Andric     return std::nullopt;
30906c3fb27SDimitry Andric 
31006c3fb27SDimitry Andric   // Make sure to un-rotate the immediates.
31106c3fb27SDimitry Andric   return std::make_pair(rotl(MaximalImm1, InitialTrailingOnes),
31206c3fb27SDimitry Andric                         rotl(MaximalImm2, InitialTrailingOnes));
31306c3fb27SDimitry Andric }
31406c3fb27SDimitry Andric 
31506c3fb27SDimitry Andric // Attempt to expand an immediate as the ORR of a pair of logical immediates.
31606c3fb27SDimitry Andric static bool tryOrrOfLogicalImmediates(uint64_t UImm,
31706c3fb27SDimitry Andric                                       SmallVectorImpl<ImmInsnModel> &Insn) {
31806c3fb27SDimitry Andric   auto MaybeDecomposition = decomposeIntoOrrOfLogicalImmediates(UImm);
31906c3fb27SDimitry Andric   if (MaybeDecomposition == std::nullopt)
32006c3fb27SDimitry Andric     return false;
32106c3fb27SDimitry Andric   uint64_t Imm1 = MaybeDecomposition->first;
32206c3fb27SDimitry Andric   uint64_t Imm2 = MaybeDecomposition->second;
32306c3fb27SDimitry Andric 
32406c3fb27SDimitry Andric   uint64_t Encoding1, Encoding2;
32506c3fb27SDimitry Andric   bool Imm1Success = AArch64_AM::processLogicalImmediate(Imm1, 64, Encoding1);
32606c3fb27SDimitry Andric   bool Imm2Success = AArch64_AM::processLogicalImmediate(Imm2, 64, Encoding2);
32706c3fb27SDimitry Andric 
32806c3fb27SDimitry Andric   if (Imm1Success && Imm2Success) {
32906c3fb27SDimitry Andric     // Create the ORR-immediate instructions.
33006c3fb27SDimitry Andric     Insn.push_back({AArch64::ORRXri, 0, Encoding1});
33106c3fb27SDimitry Andric     Insn.push_back({AArch64::ORRXri, 1, Encoding2});
33206c3fb27SDimitry Andric     return true;
33306c3fb27SDimitry Andric   }
33406c3fb27SDimitry Andric 
33506c3fb27SDimitry Andric   return false;
33606c3fb27SDimitry Andric }
33706c3fb27SDimitry Andric 
33806c3fb27SDimitry Andric // Attempt to expand an immediate as the AND of a pair of logical immediates.
33906c3fb27SDimitry Andric // This is done by applying DeMorgan's law, under which logical immediates
34006c3fb27SDimitry Andric // are closed.
34106c3fb27SDimitry Andric static bool tryAndOfLogicalImmediates(uint64_t UImm,
34206c3fb27SDimitry Andric                                       SmallVectorImpl<ImmInsnModel> &Insn) {
34306c3fb27SDimitry Andric   // Apply DeMorgan's law to turn this into an ORR problem.
34406c3fb27SDimitry Andric   auto MaybeDecomposition = decomposeIntoOrrOfLogicalImmediates(~UImm);
34506c3fb27SDimitry Andric   if (MaybeDecomposition == std::nullopt)
34606c3fb27SDimitry Andric     return false;
34706c3fb27SDimitry Andric   uint64_t Imm1 = MaybeDecomposition->first;
34806c3fb27SDimitry Andric   uint64_t Imm2 = MaybeDecomposition->second;
34906c3fb27SDimitry Andric 
35006c3fb27SDimitry Andric   uint64_t Encoding1, Encoding2;
35106c3fb27SDimitry Andric   bool Imm1Success = AArch64_AM::processLogicalImmediate(~Imm1, 64, Encoding1);
35206c3fb27SDimitry Andric   bool Imm2Success = AArch64_AM::processLogicalImmediate(~Imm2, 64, Encoding2);
35306c3fb27SDimitry Andric 
35406c3fb27SDimitry Andric   if (Imm1Success && Imm2Success) {
35506c3fb27SDimitry Andric     // Materialize Imm1, the LHS of the AND
35606c3fb27SDimitry Andric     Insn.push_back({AArch64::ORRXri, 0, Encoding1});
35706c3fb27SDimitry Andric     // AND Imm1 with Imm2
35806c3fb27SDimitry Andric     Insn.push_back({AArch64::ANDXri, 1, Encoding2});
35906c3fb27SDimitry Andric     return true;
36006c3fb27SDimitry Andric   }
36106c3fb27SDimitry Andric 
36206c3fb27SDimitry Andric   return false;
36306c3fb27SDimitry Andric }
36406c3fb27SDimitry Andric 
3655f757f3fSDimitry Andric // Check whether the constant can be represented by exclusive-or of two 64-bit
3665f757f3fSDimitry Andric // logical immediates. If so, materialize it with an ORR instruction followed
3675f757f3fSDimitry Andric // by an EOR instruction.
3685f757f3fSDimitry Andric //
3695f757f3fSDimitry Andric // This encoding allows all remaining repeated byte patterns, and many repeated
3705f757f3fSDimitry Andric // 16-bit values, to be encoded without needing four instructions. It can also
3715f757f3fSDimitry Andric // represent some irregular bitmasks (although those would mostly only need
3725f757f3fSDimitry Andric // three instructions otherwise).
3735f757f3fSDimitry Andric static bool tryEorOfLogicalImmediates(uint64_t Imm,
3745f757f3fSDimitry Andric                                       SmallVectorImpl<ImmInsnModel> &Insn) {
3755f757f3fSDimitry Andric   // Determine the larger repetition size of the two possible logical
3765f757f3fSDimitry Andric   // immediates, by finding the repetition size of Imm.
3775f757f3fSDimitry Andric   unsigned BigSize = 64;
3785f757f3fSDimitry Andric 
3795f757f3fSDimitry Andric   do {
3805f757f3fSDimitry Andric     BigSize /= 2;
3815f757f3fSDimitry Andric     uint64_t Mask = (1ULL << BigSize) - 1;
3825f757f3fSDimitry Andric 
3835f757f3fSDimitry Andric     if ((Imm & Mask) != ((Imm >> BigSize) & Mask)) {
3845f757f3fSDimitry Andric       BigSize *= 2;
3855f757f3fSDimitry Andric       break;
3865f757f3fSDimitry Andric     }
3875f757f3fSDimitry Andric   } while (BigSize > 2);
3885f757f3fSDimitry Andric 
3895f757f3fSDimitry Andric   uint64_t BigMask = ((uint64_t)-1LL) >> (64 - BigSize);
3905f757f3fSDimitry Andric 
3915f757f3fSDimitry Andric   // Find the last bit of each run of ones, circularly. For runs which wrap
3925f757f3fSDimitry Andric   // around from bit 0 to bit 63, this is the bit before the most-significant
3935f757f3fSDimitry Andric   // zero, otherwise it is the least-significant bit in the run of ones.
3945f757f3fSDimitry Andric   uint64_t RunStarts = Imm & ~rotl<uint64_t>(Imm, 1);
3955f757f3fSDimitry Andric 
3965f757f3fSDimitry Andric   // Find the smaller repetition size of the two possible logical immediates by
3975f757f3fSDimitry Andric   // counting the number of runs of one-bits within the BigSize-bit value. Both
3985f757f3fSDimitry Andric   // sizes may be the same. The EOR may add one or subtract one from the
3995f757f3fSDimitry Andric   // power-of-two count that can be represented by a logical immediate, or it
4005f757f3fSDimitry Andric   // may be left unchanged.
4015f757f3fSDimitry Andric   int RunsPerBigChunk = popcount(RunStarts & BigMask);
4025f757f3fSDimitry Andric 
4035f757f3fSDimitry Andric   static const int8_t BigToSmallSizeTable[32] = {
4045f757f3fSDimitry Andric       -1, -1, 0,  1,  2,  2,  -1, 3,  3,  3,  -1, -1, -1, -1, -1, 4,
4055f757f3fSDimitry Andric       4,  4,  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5,
4065f757f3fSDimitry Andric   };
4075f757f3fSDimitry Andric 
4085f757f3fSDimitry Andric   int BigToSmallShift = BigToSmallSizeTable[RunsPerBigChunk];
4095f757f3fSDimitry Andric 
4105f757f3fSDimitry Andric   // Early-exit if the big chunk couldn't be a power-of-two number of runs
4115f757f3fSDimitry Andric   // EORed with another single run.
4125f757f3fSDimitry Andric   if (BigToSmallShift == -1)
4135f757f3fSDimitry Andric     return false;
4145f757f3fSDimitry Andric 
4155f757f3fSDimitry Andric   unsigned SmallSize = BigSize >> BigToSmallShift;
4165f757f3fSDimitry Andric 
4175f757f3fSDimitry Andric   // 64-bit values with a bit set every (1 << index) bits.
4185f757f3fSDimitry Andric   static const uint64_t RepeatedOnesTable[] = {
4195f757f3fSDimitry Andric       0xffffffffffffffff, 0x5555555555555555, 0x1111111111111111,
4205f757f3fSDimitry Andric       0x0101010101010101, 0x0001000100010001, 0x0000000100000001,
4215f757f3fSDimitry Andric       0x0000000000000001,
4225f757f3fSDimitry Andric   };
4235f757f3fSDimitry Andric 
4245f757f3fSDimitry Andric   // This RepeatedOnesTable lookup is a faster implementation of the division
4255f757f3fSDimitry Andric   // 0xffffffffffffffff / ((1 << SmallSize) - 1), and can be thought of as
4265f757f3fSDimitry Andric   // dividing the 64-bit value into fields of width SmallSize, and placing a
4275f757f3fSDimitry Andric   // one in the least significant bit of each field.
4285f757f3fSDimitry Andric   uint64_t SmallOnes = RepeatedOnesTable[countr_zero(SmallSize)];
4295f757f3fSDimitry Andric 
4305f757f3fSDimitry Andric   // Now we try to find the number of ones in each of the smaller repetitions,
4315f757f3fSDimitry Andric   // by looking at runs of ones in Imm. This can take three attempts, as the
4325f757f3fSDimitry Andric   // EOR may have changed the length of the first two runs we find.
4335f757f3fSDimitry Andric 
4345f757f3fSDimitry Andric   // Rotate a run of ones so we can count the number of trailing set bits.
4355f757f3fSDimitry Andric   int Rotation = countr_zero(RunStarts);
4365f757f3fSDimitry Andric   uint64_t RotatedImm = rotr<uint64_t>(Imm, Rotation);
4375f757f3fSDimitry Andric   for (int Attempt = 0; Attempt < 3; ++Attempt) {
4385f757f3fSDimitry Andric     unsigned RunLength = countr_one(RotatedImm);
4395f757f3fSDimitry Andric 
4405f757f3fSDimitry Andric     // Construct candidate values BigImm and SmallImm, such that if these two
4415f757f3fSDimitry Andric     // values are encodable, we have a solution. (SmallImm is constructed to be
4425f757f3fSDimitry Andric     // encodable, but this isn't guaranteed when RunLength >= SmallSize)
4435f757f3fSDimitry Andric     uint64_t SmallImm =
4445f757f3fSDimitry Andric         rotl<uint64_t>((SmallOnes << RunLength) - SmallOnes, Rotation);
4455f757f3fSDimitry Andric     uint64_t BigImm = Imm ^ SmallImm;
4465f757f3fSDimitry Andric 
4475f757f3fSDimitry Andric     uint64_t BigEncoding = 0;
4485f757f3fSDimitry Andric     uint64_t SmallEncoding = 0;
4495f757f3fSDimitry Andric     if (AArch64_AM::processLogicalImmediate(BigImm, 64, BigEncoding) &&
4505f757f3fSDimitry Andric         AArch64_AM::processLogicalImmediate(SmallImm, 64, SmallEncoding)) {
4515f757f3fSDimitry Andric       Insn.push_back({AArch64::ORRXri, 0, SmallEncoding});
4525f757f3fSDimitry Andric       Insn.push_back({AArch64::EORXri, 1, BigEncoding});
4535f757f3fSDimitry Andric       return true;
4545f757f3fSDimitry Andric     }
4555f757f3fSDimitry Andric 
4565f757f3fSDimitry Andric     // Rotate to the next run of ones
4575f757f3fSDimitry Andric     Rotation += countr_zero(rotr<uint64_t>(RunStarts, Rotation) & ~1);
4585f757f3fSDimitry Andric     RotatedImm = rotr<uint64_t>(Imm, Rotation);
4595f757f3fSDimitry Andric   }
4605f757f3fSDimitry Andric 
4615f757f3fSDimitry Andric   return false;
4625f757f3fSDimitry Andric }
4635f757f3fSDimitry Andric 
4640b57cec5SDimitry Andric /// \brief Expand a MOVi32imm or MOVi64imm pseudo instruction to a
4650b57cec5SDimitry Andric /// MOVZ or MOVN of width BitSize followed by up to 3 MOVK instructions.
4660b57cec5SDimitry Andric static inline void expandMOVImmSimple(uint64_t Imm, unsigned BitSize,
4670b57cec5SDimitry Andric 				      unsigned OneChunks, unsigned ZeroChunks,
4680b57cec5SDimitry Andric 				      SmallVectorImpl<ImmInsnModel> &Insn) {
4690b57cec5SDimitry Andric   const unsigned Mask = 0xFFFF;
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric   // Use a MOVZ or MOVN instruction to set the high bits, followed by one or
4720b57cec5SDimitry Andric   // more MOVK instructions to insert additional 16-bit portions into the
4730b57cec5SDimitry Andric   // lower bits.
4740b57cec5SDimitry Andric   bool isNeg = false;
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric   // Use MOVN to materialize the high bits if we have more all one chunks
4770b57cec5SDimitry Andric   // than all zero chunks.
4780b57cec5SDimitry Andric   if (OneChunks > ZeroChunks) {
4790b57cec5SDimitry Andric     isNeg = true;
4800b57cec5SDimitry Andric     Imm = ~Imm;
4810b57cec5SDimitry Andric   }
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric   unsigned FirstOpc;
4840b57cec5SDimitry Andric   if (BitSize == 32) {
4850b57cec5SDimitry Andric     Imm &= (1LL << 32) - 1;
4860b57cec5SDimitry Andric     FirstOpc = (isNeg ? AArch64::MOVNWi : AArch64::MOVZWi);
4870b57cec5SDimitry Andric   } else {
4880b57cec5SDimitry Andric     FirstOpc = (isNeg ? AArch64::MOVNXi : AArch64::MOVZXi);
4890b57cec5SDimitry Andric   }
4900b57cec5SDimitry Andric   unsigned Shift = 0;     // LSL amount for high bits with MOVZ/MOVN
4910b57cec5SDimitry Andric   unsigned LastShift = 0; // LSL amount for last MOVK
4920b57cec5SDimitry Andric   if (Imm != 0) {
49306c3fb27SDimitry Andric     unsigned LZ = llvm::countl_zero(Imm);
49406c3fb27SDimitry Andric     unsigned TZ = llvm::countr_zero(Imm);
4950b57cec5SDimitry Andric     Shift = (TZ / 16) * 16;
4960b57cec5SDimitry Andric     LastShift = ((63 - LZ) / 16) * 16;
4970b57cec5SDimitry Andric   }
4980b57cec5SDimitry Andric   unsigned Imm16 = (Imm >> Shift) & Mask;
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric   Insn.push_back({ FirstOpc, Imm16,
5010b57cec5SDimitry Andric                    AArch64_AM::getShifterImm(AArch64_AM::LSL, Shift) });
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric   if (Shift == LastShift)
5040b57cec5SDimitry Andric     return;
5050b57cec5SDimitry Andric 
5060b57cec5SDimitry Andric   // If a MOVN was used for the high bits of a negative value, flip the rest
5070b57cec5SDimitry Andric   // of the bits back for use with MOVK.
5080b57cec5SDimitry Andric   if (isNeg)
5090b57cec5SDimitry Andric     Imm = ~Imm;
5100b57cec5SDimitry Andric 
5110b57cec5SDimitry Andric   unsigned Opc = (BitSize == 32 ? AArch64::MOVKWi : AArch64::MOVKXi);
5120b57cec5SDimitry Andric   while (Shift < LastShift) {
5130b57cec5SDimitry Andric     Shift += 16;
5140b57cec5SDimitry Andric     Imm16 = (Imm >> Shift) & Mask;
5150b57cec5SDimitry Andric     if (Imm16 == (isNeg ? Mask : 0))
5160b57cec5SDimitry Andric       continue; // This 16-bit portion is already set correctly.
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric     Insn.push_back({ Opc, Imm16,
5190b57cec5SDimitry Andric                      AArch64_AM::getShifterImm(AArch64_AM::LSL, Shift) });
5200b57cec5SDimitry Andric   }
521*0fca6ea1SDimitry Andric 
522*0fca6ea1SDimitry Andric   // Now, we get 16-bit divided Imm. If high and low bits are same in
523*0fca6ea1SDimitry Andric   // 32-bit, there is an opportunity to reduce instruction.
524*0fca6ea1SDimitry Andric   if (Insn.size() > 2 && (Imm >> 32) == (Imm & 0xffffffffULL)) {
525*0fca6ea1SDimitry Andric     for (int Size = Insn.size(); Size > 2; Size--)
526*0fca6ea1SDimitry Andric       Insn.pop_back();
527*0fca6ea1SDimitry Andric     Insn.push_back({AArch64::ORRXrs, 0, 32});
528*0fca6ea1SDimitry Andric   }
5290b57cec5SDimitry Andric }
5300b57cec5SDimitry Andric 
5310b57cec5SDimitry Andric /// Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more
5320b57cec5SDimitry Andric /// real move-immediate instructions to synthesize the immediate.
533fe6060f1SDimitry Andric void AArch64_IMM::expandMOVImm(uint64_t Imm, unsigned BitSize,
5340b57cec5SDimitry Andric                                SmallVectorImpl<ImmInsnModel> &Insn) {
5350b57cec5SDimitry Andric   const unsigned Mask = 0xFFFF;
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric   // Scan the immediate and count the number of 16-bit chunks which are either
5380b57cec5SDimitry Andric   // all ones or all zeros.
5390b57cec5SDimitry Andric   unsigned OneChunks = 0;
5400b57cec5SDimitry Andric   unsigned ZeroChunks = 0;
5410b57cec5SDimitry Andric   for (unsigned Shift = 0; Shift < BitSize; Shift += 16) {
5420b57cec5SDimitry Andric     const unsigned Chunk = (Imm >> Shift) & Mask;
5430b57cec5SDimitry Andric     if (Chunk == Mask)
5440b57cec5SDimitry Andric       OneChunks++;
5450b57cec5SDimitry Andric     else if (Chunk == 0)
5460b57cec5SDimitry Andric       ZeroChunks++;
5470b57cec5SDimitry Andric   }
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric   // Prefer MOVZ/MOVN over ORR because of the rules for the "mov" alias.
5500b57cec5SDimitry Andric   if ((BitSize / 16) - OneChunks <= 1 || (BitSize / 16) - ZeroChunks <= 1) {
5510b57cec5SDimitry Andric     expandMOVImmSimple(Imm, BitSize, OneChunks, ZeroChunks, Insn);
5520b57cec5SDimitry Andric     return;
5530b57cec5SDimitry Andric   }
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric   // Try a single ORR.
5560b57cec5SDimitry Andric   uint64_t UImm = Imm << (64 - BitSize) >> (64 - BitSize);
5570b57cec5SDimitry Andric   uint64_t Encoding;
5580b57cec5SDimitry Andric   if (AArch64_AM::processLogicalImmediate(UImm, BitSize, Encoding)) {
5590b57cec5SDimitry Andric     unsigned Opc = (BitSize == 32 ? AArch64::ORRWri : AArch64::ORRXri);
5600b57cec5SDimitry Andric     Insn.push_back({ Opc, 0, Encoding });
5610b57cec5SDimitry Andric     return;
5620b57cec5SDimitry Andric   }
5630b57cec5SDimitry Andric 
5640b57cec5SDimitry Andric   // One to up three instruction sequences.
5650b57cec5SDimitry Andric   //
5660b57cec5SDimitry Andric   // Prefer MOVZ/MOVN followed by MOVK; it's more readable, and possibly the
5670b57cec5SDimitry Andric   // fastest sequence with fast literal generation.
5680b57cec5SDimitry Andric   if (OneChunks >= (BitSize / 16) - 2 || ZeroChunks >= (BitSize / 16) - 2) {
5690b57cec5SDimitry Andric     expandMOVImmSimple(Imm, BitSize, OneChunks, ZeroChunks, Insn);
5700b57cec5SDimitry Andric     return;
5710b57cec5SDimitry Andric   }
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric   assert(BitSize == 64 && "All 32-bit immediates can be expanded with a"
5740b57cec5SDimitry Andric                           "MOVZ/MOVK pair");
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric   // Try other two-instruction sequences.
5770b57cec5SDimitry Andric 
5780b57cec5SDimitry Andric   // 64-bit ORR followed by MOVK.
5790b57cec5SDimitry Andric   // We try to construct the ORR immediate in three different ways: either we
5800b57cec5SDimitry Andric   // zero out the chunk which will be replaced, we fill the chunk which will
5810b57cec5SDimitry Andric   // be replaced with ones, or we take the bit pattern from the other half of
5820b57cec5SDimitry Andric   // the 64-bit immediate. This is comprehensive because of the way ORR
5830b57cec5SDimitry Andric   // immediates are constructed.
5840b57cec5SDimitry Andric   for (unsigned Shift = 0; Shift < BitSize; Shift += 16) {
5850b57cec5SDimitry Andric     uint64_t ShiftedMask = (0xFFFFULL << Shift);
5860b57cec5SDimitry Andric     uint64_t ZeroChunk = UImm & ~ShiftedMask;
5870b57cec5SDimitry Andric     uint64_t OneChunk = UImm | ShiftedMask;
5880b57cec5SDimitry Andric     uint64_t RotatedImm = (UImm << 32) | (UImm >> 32);
5890b57cec5SDimitry Andric     uint64_t ReplicateChunk = ZeroChunk | (RotatedImm & ShiftedMask);
5900b57cec5SDimitry Andric     if (AArch64_AM::processLogicalImmediate(ZeroChunk, BitSize, Encoding) ||
5910b57cec5SDimitry Andric         AArch64_AM::processLogicalImmediate(OneChunk, BitSize, Encoding) ||
5920b57cec5SDimitry Andric         AArch64_AM::processLogicalImmediate(ReplicateChunk, BitSize,
5930b57cec5SDimitry Andric                                             Encoding)) {
5940b57cec5SDimitry Andric       // Create the ORR-immediate instruction.
5950b57cec5SDimitry Andric       Insn.push_back({ AArch64::ORRXri, 0, Encoding });
5960b57cec5SDimitry Andric 
5970b57cec5SDimitry Andric       // Create the MOVK instruction.
5980b57cec5SDimitry Andric       const unsigned Imm16 = getChunk(UImm, Shift / 16);
5990b57cec5SDimitry Andric       Insn.push_back({ AArch64::MOVKXi, Imm16,
6000b57cec5SDimitry Andric 		       AArch64_AM::getShifterImm(AArch64_AM::LSL, Shift) });
6010b57cec5SDimitry Andric       return;
6020b57cec5SDimitry Andric     }
6030b57cec5SDimitry Andric   }
6040b57cec5SDimitry Andric 
60506c3fb27SDimitry Andric   // Attempt to use a sequence of two ORR-immediate instructions.
60606c3fb27SDimitry Andric   if (tryOrrOfLogicalImmediates(Imm, Insn))
60706c3fb27SDimitry Andric     return;
60806c3fb27SDimitry Andric 
60906c3fb27SDimitry Andric   // Attempt to use a sequence of ORR-immediate followed by AND-immediate.
61006c3fb27SDimitry Andric   if (tryAndOfLogicalImmediates(Imm, Insn))
61106c3fb27SDimitry Andric     return;
61206c3fb27SDimitry Andric 
6135f757f3fSDimitry Andric   // Attempt to use a sequence of ORR-immediate followed by EOR-immediate.
6145f757f3fSDimitry Andric   if (tryEorOfLogicalImmediates(UImm, Insn))
6155f757f3fSDimitry Andric     return;
6165f757f3fSDimitry Andric 
6170b57cec5SDimitry Andric   // FIXME: Add more two-instruction sequences.
6180b57cec5SDimitry Andric 
6190b57cec5SDimitry Andric   // Three instruction sequences.
6200b57cec5SDimitry Andric   //
6210b57cec5SDimitry Andric   // Prefer MOVZ/MOVN followed by two MOVK; it's more readable, and possibly
6220b57cec5SDimitry Andric   // the fastest sequence with fast literal generation. (If neither MOVK is
6230b57cec5SDimitry Andric   // part of a fast literal generation pair, it could be slower than the
6240b57cec5SDimitry Andric   // four-instruction sequence, but we won't worry about that for now.)
6250b57cec5SDimitry Andric   if (OneChunks || ZeroChunks) {
6260b57cec5SDimitry Andric     expandMOVImmSimple(Imm, BitSize, OneChunks, ZeroChunks, Insn);
6270b57cec5SDimitry Andric     return;
6280b57cec5SDimitry Andric   }
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric   // Check for identical 16-bit chunks within the constant and if so materialize
6310b57cec5SDimitry Andric   // them with a single ORR instruction. The remaining one or two 16-bit chunks
6320b57cec5SDimitry Andric   // will be materialized with MOVK instructions.
6330b57cec5SDimitry Andric   if (BitSize == 64 && tryToreplicateChunks(UImm, Insn))
6340b57cec5SDimitry Andric     return;
6350b57cec5SDimitry Andric 
6360b57cec5SDimitry Andric   // Check whether the constant contains a sequence of contiguous ones, which
6370b57cec5SDimitry Andric   // might be interrupted by one or two chunks. If so, materialize the sequence
6380b57cec5SDimitry Andric   // of contiguous ones with an ORR instruction. Materialize the chunks which
6390b57cec5SDimitry Andric   // are either interrupting the sequence or outside of the sequence with a
6400b57cec5SDimitry Andric   // MOVK instruction.
6410b57cec5SDimitry Andric   if (BitSize == 64 && trySequenceOfOnes(UImm, Insn))
6420b57cec5SDimitry Andric     return;
6430b57cec5SDimitry Andric 
6440b57cec5SDimitry Andric   // We found no possible two or three instruction sequence; use the general
6450b57cec5SDimitry Andric   // four-instruction sequence.
6460b57cec5SDimitry Andric   expandMOVImmSimple(Imm, BitSize, OneChunks, ZeroChunks, Insn);
6470b57cec5SDimitry Andric }
648