24 assert(ChunkIdx < 4 &&
"Out of range chunk index specified!");
26 return (
Imm >> (ChunkIdx * 16)) & 0xFFFF;
32 Chunk = (Chunk << 48) | (Chunk << 32) | (Chunk << 16) | Chunk;
51 for (
unsigned Idx = 0; Idx < 4; ++Idx)
55 for (
const auto &Chunk : Counts) {
56 const uint64_t ChunkVal = Chunk.first;
57 const unsigned Count = Chunk.second;
66 const bool CountThree =
Count == 3;
68 Insn.
push_back({ AArch64::ORRXri, 0, Encoding });
70 unsigned ShiftAmt = 0;
73 for (; ShiftAmt < 64; ShiftAmt += 16) {
74 Imm16 = (UImm >> ShiftAmt) & 0xFFFF;
76 if (Imm16 != ChunkVal)
90 for (ShiftAmt += 16; ShiftAmt < 64; ShiftAmt += 16) {
91 Imm16 = (UImm >> ShiftAmt) & 0xFFFF;
93 if (Imm16 != ChunkVal)
108 if (Chunk == 0 || Chunk == std::numeric_limits<uint64_t>::max())
118 if (Chunk == 0 || Chunk == std::numeric_limits<uint64_t>::max())
130 Imm &= ~(Mask << (Idx * 16));
133 Imm |= Mask << (Idx * 16);
153 const int NotSet = -1;
156 int StartIdx = NotSet;
159 for (
int Idx = 0; Idx < 4; ++Idx) {
160 int64_t Chunk =
getChunk(UImm, Idx);
162 Chunk = (Chunk << 48) >> 48;
171 if (StartIdx == NotSet || EndIdx == NotSet)
182 if (StartIdx > EndIdx) {
188 int FirstMovkIdx = NotSet;
189 int SecondMovkIdx = NotSet;
193 for (
int Idx = 0; Idx < 4; ++Idx) {
198 if ((Idx < StartIdx || EndIdx < Idx) && Chunk != Outside) {
199 OrrImm =
updateImm(OrrImm, Idx, Outside == 0);
202 if (FirstMovkIdx == NotSet)
209 }
else if (Idx > StartIdx && Idx < EndIdx && Chunk != Inside) {
210 OrrImm =
updateImm(OrrImm, Idx, Inside != Mask);
213 if (FirstMovkIdx == NotSet)
219 assert(FirstMovkIdx != NotSet &&
"Constant materializable with single ORR!");
224 Insn.
push_back({ AArch64::ORRXri, 0, Encoding });
226 const bool SingleMovk = SecondMovkIdx == NotSet;
229 FirstMovkIdx * 16) });
237 {AArch64::MOVKXi,
getChunk(UImm, SecondMovkIdx),
272 const unsigned Mask = 0xffff;
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)
282 Insn.
push_back({AArch64::MOVNXi, Imm0 ^ Mask, 0});
284 Insn.
push_back({AArch64::MOVKXi, Imm16, 16});
286 Insn.
push_back({AArch64::MOVNXi, Imm16 ^ Mask, 16});
293 for (
unsigned N = 17;
N < 48; ++
N) {
296 if ((
C ^ (
C <<
N)) ==
Imm && tryExpansion(AArch64::EORXrs,
C,
N))
300 C = 0xffffffff00000000ULL | (
Imm ^ ~(
~Imm <<
N));
301 if ((
C ^ ~(
C <<
N)) ==
Imm && tryExpansion(AArch64::EONXrs,
C,
N))
313 UnshiftedOnes = ~0ULL;
315 UnshiftedOnes = (1ULL << NumOnes) - 1;
317 return UnshiftedOnes << StartPosition;
325 uint64_t Rotation = 1ULL << (6 - i);
327 if (Closure != (Closure & V)) {
353static std::optional<std::pair<uint64_t, uint64_t>>
355 if (UImm == 0 || ~UImm == 0)
366 uint64_t RemainingBits = RotatedBits & ~MaximalImm1;
373 if (RemainingBits & ~MaximalImm2)
377 return std::make_pair(
rotl(MaximalImm1, InitialTrailingOnes),
378 rotl(MaximalImm2, InitialTrailingOnes));
385 if (MaybeDecomposition == std::nullopt)
387 uint64_t Imm1 = MaybeDecomposition->first;
388 uint64_t Imm2 = MaybeDecomposition->second;
394 if (Imm1Success && Imm2Success) {
396 Insn.
push_back({AArch64::ORRXri, 0, Encoding1});
397 Insn.
push_back({AArch64::ORRXri, 1, Encoding2});
411 if (MaybeDecomposition == std::nullopt)
413 uint64_t Imm1 = MaybeDecomposition->first;
414 uint64_t Imm2 = MaybeDecomposition->second;
420 if (Imm1Success && Imm2Success) {
422 Insn.
push_back({AArch64::ORRXri, 0, Encoding1});
424 Insn.
push_back({AArch64::ANDXri, 1, Encoding2});
443 unsigned BigSize = 64;
447 uint64_t Mask = (1ULL << BigSize) - 1;
449 if ((
Imm & Mask) != ((
Imm >> BigSize) & Mask)) {
453 }
while (BigSize > 2);
467 int RunsPerBigChunk =
popcount(RunStarts & BigMask);
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,
474 int BigToSmallShift = BigToSmallSizeTable[RunsPerBigChunk];
478 if (BigToSmallShift == -1)
481 unsigned SmallSize = BigSize >> BigToSmallShift;
484 static const uint64_t RepeatedOnesTable[] = {
485 0xffffffffffffffff, 0x5555555555555555, 0x1111111111111111,
486 0x0101010101010101, 0x0001000100010001, 0x0000000100000001,
503 for (
int Attempt = 0; Attempt < 3; ++Attempt) {
517 Insn.
push_back({AArch64::ORRXri, 0, SmallEncoding});
518 Insn.
push_back({AArch64::EORXri, 1, BigEncoding});
533 unsigned OneChunks,
unsigned ZeroChunks,
535 const unsigned Mask = 0xFFFF;
544 if (OneChunks > ZeroChunks) {
551 Imm &= (1LL << 32) - 1;
552 FirstOpc = (
isNeg ? AArch64::MOVNWi : AArch64::MOVZWi);
554 FirstOpc = (
isNeg ? AArch64::MOVNXi : AArch64::MOVZXi);
557 unsigned LastShift = 0;
561 Shift = (TZ / 16) * 16;
562 LastShift = ((63 - LZ) / 16) * 16;
564 unsigned Imm16 = (
Imm >> Shift) & Mask;
569 if (Shift == LastShift)
577 unsigned Opc = (BitSize == 32 ? AArch64::MOVKWi : AArch64::MOVKXi);
578 while (Shift < LastShift) {
580 Imm16 = (
Imm >> Shift) & Mask;
581 if (Imm16 == (
isNeg ? Mask : 0))
590 if (Insn.
size() > 2 && (
Imm >> 32) == (
Imm & 0xffffffffULL)) {
593 Insn.
push_back({AArch64::ORRXrs, 0, 32});
601 const unsigned Mask = 0xFFFF;
605 unsigned OneChunks = 0;
606 unsigned ZeroChunks = 0;
607 for (
unsigned Shift = 0; Shift < BitSize; Shift += 16) {
608 const unsigned Chunk = (
Imm >> Shift) & Mask;
616 if ((BitSize / 16) - OneChunks <= 1 || (BitSize / 16) - ZeroChunks <= 1) {
619 "Move of immediate should have expanded to a single MOVZ/MOVN");
624 uint64_t UImm =
Imm << (64 - BitSize) >> (64 - BitSize);
627 unsigned Opc = (BitSize == 32 ? AArch64::ORRWri : AArch64::ORRXri);
636 if (OneChunks >= (BitSize / 16) - 2 || ZeroChunks >= (BitSize / 16) - 2) {
641 assert(BitSize == 64 &&
"All 32-bit immediates can be expanded with a"
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;
657 uint64_t ReplicateChunk = ZeroChunk | (RotatedImm & ShiftedMask);
663 Insn.
push_back({ AArch64::ORRXri, 0, Encoding });
666 const unsigned Imm16 =
getChunk(UImm, Shift / 16);
697 if (OneChunks || ZeroChunks) {
728 if (Opcode == AArch64::MOVaddrBA && IsTargetMachO) {
743 assert((
Imm.getBitWidth() == 64 ||
Imm.getBitWidth() == 128) &&
744 "Expected vector sized constant");
745 bool Is64Bit =
Imm.getBitWidth() == 64;
747 if (ST.isNeonAvailable() &&
Imm.getHiBits(64) ==
Imm.getLoBits(64)) {
748 uint64_t
Value =
Imm.trunc(64).getZExtValue();
750 Insns.
push_back({AArch64::FMOVD0, std::nullopt, std::nullopt});
754 unsigned Opc = Is64Bit ? AArch64::MOVID : AArch64::MOVIv2d_ns;
760 unsigned Opc = Is64Bit ? AArch64::MOVIv2i32 : AArch64::MOVIv4i32;
765 unsigned Opc = Is64Bit ? AArch64::MOVIv2i32 : AArch64::MOVIv4i32;
770 unsigned Opc = Is64Bit ? AArch64::MOVIv2i32 : AArch64::MOVIv4i32;
775 unsigned Opc = Is64Bit ? AArch64::MOVIv2i32 : AArch64::MOVIv4i32;
780 unsigned Opc = Is64Bit ? AArch64::MOVIv4i16 : AArch64::MOVIv8i16;
785 unsigned Opc = Is64Bit ? AArch64::MOVIv4i16 : AArch64::MOVIv8i16;
790 unsigned Opc = Is64Bit ? AArch64::MOVIv2s_msl : AArch64::MOVIv4s_msl;
795 unsigned Opc = Is64Bit ? AArch64::MOVIv2s_msl : AArch64::MOVIv4s_msl;
800 unsigned Opc = Is64Bit ? AArch64::MOVIv8b_ns : AArch64::MOVIv16b_ns;
806 unsigned Opc = Is64Bit ? AArch64::FMOVv2f32_ns : AArch64::FMOVv4f32_ns;
812 unsigned Opc = Is64Bit ? AArch64::FMOVDi : AArch64::FMOVv2f64_ns;
821 unsigned Opc = Is64Bit ? AArch64::MVNIv2i32 : AArch64::MVNIv4i32;
826 unsigned Opc = Is64Bit ? AArch64::MVNIv2i32 : AArch64::MVNIv4i32;
831 unsigned Opc = Is64Bit ? AArch64::MVNIv2i32 : AArch64::MVNIv4i32;
836 unsigned Opc = Is64Bit ? AArch64::MVNIv2i32 : AArch64::MVNIv4i32;
841 unsigned Opc = Is64Bit ? AArch64::MVNIv4i16 : AArch64::MVNIv8i16;
846 unsigned Opc = Is64Bit ? AArch64::MVNIv4i16 : AArch64::MVNIv8i16;
851 unsigned Opc = Is64Bit ? AArch64::MVNIv2s_msl : AArch64::MVNIv4s_msl;
856 unsigned Opc = Is64Bit ? AArch64::MVNIv2s_msl : AArch64::MVNIv4s_msl;
862 if (ST.isNeonAvailable() && ST.hasFullFP16() &&
Imm.isSplat(16)) {
865 unsigned Opc = Is64Bit ? AArch64::FMOVv4f16_ns : AArch64::FMOVv8f16_ns;
872 if (ST.hasSVE() && !Is64Bit &&
Imm.getHiBits(64) ==
Imm.getLoBits(64)) {
875 int32_t ImmVal, ShiftVal;
879 {AArch64::DUP_ZI_D, (uint64_t)ImmVal, (uint64_t)ShiftVal});
884 Insns.
push_back({AArch64::DUPM_ZI, Encoding, std::nullopt});
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!")
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.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
int64_t getSExtValue() const
Get sign extended value.
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.
@ 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)
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
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...
int countl_zero(T Val)
Count number of 0's from the most significant bit to the least stopping at the first 1.
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...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
constexpr T rotl(T V, int R)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.