https://github.com/guy-david created https://github.com/llvm/llvm-project/pull/183506
None >From a7f77081674b6a32c0fc9d14d14867517197a0b1 Mon Sep 17 00:00:00 2001 From: Guy David <[email protected]> Date: Thu, 26 Feb 2026 11:35:08 +0200 Subject: [PATCH] [AArch64] Report accurate sizes for MOVaddr and MOVimm pseudos --- .../Target/AArch64/AArch64ExpandPseudo.cpp | 54 +++++++++---------- llvm/lib/Target/AArch64/AArch64ExpandPseudo.h | 2 +- .../Target/AArch64/AArch64ISelLowering.cpp | 3 +- llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 44 +++++++++------ 4 files changed, 58 insertions(+), 45 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64ExpandPseudo.cpp b/llvm/lib/Target/AArch64/AArch64ExpandPseudo.cpp index 4e15e082f01a7..2f618b67f21ea 100644 --- a/llvm/lib/Target/AArch64/AArch64ExpandPseudo.cpp +++ b/llvm/lib/Target/AArch64/AArch64ExpandPseudo.cpp @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// -#include "AArch64.h" #include "AArch64ExpandPseudo.h" +#include "AArch64.h" #include "MCTargetDesc/AArch64AddressingModes.h" using namespace llvm; @@ -41,7 +41,7 @@ static bool canUseOrr(uint64_t Chunk, uint64_t &Encoding) { /// of the chunks doesn't matter), assuming |A|A|A|A| can be materialized with /// an ORR instruction. static bool tryToreplicateChunks(uint64_t UImm, - SmallVectorImpl<ImmInsnModel> &Insn) { + SmallVectorImpl<ImmInsnModel> &Insn) { using CountMap = DenseMap<uint64_t, unsigned>; CountMap Counts; @@ -64,7 +64,7 @@ static bool tryToreplicateChunks(uint64_t UImm, const bool CountThree = Count == 3; - Insn.push_back({ AArch64::ORRXri, 0, Encoding }); + Insn.push_back({AArch64::ORRXri, 0, Encoding}); unsigned ShiftAmt = 0; uint64_t Imm16 = 0; @@ -77,8 +77,8 @@ static bool tryToreplicateChunks(uint64_t UImm, } // Create the first MOVK instruction. - Insn.push_back({ AArch64::MOVKXi, Imm16, - AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt) }); + Insn.push_back({AArch64::MOVKXi, Imm16, + AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt)}); // In case we have three instances the whole constant is now materialized // and we can exit. @@ -92,8 +92,8 @@ static bool tryToreplicateChunks(uint64_t UImm, if (Imm16 != ChunkVal) break; } - Insn.push_back({ AArch64::MOVKXi, Imm16, - AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt) }); + Insn.push_back({AArch64::MOVKXi, Imm16, + AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt)}); return true; } @@ -220,21 +220,21 @@ static bool trySequenceOfOnes(uint64_t UImm, // Create the ORR-immediate instruction. uint64_t Encoding = 0; AArch64_AM::processLogicalImmediate(OrrImm, 64, Encoding); - Insn.push_back({ AArch64::ORRXri, 0, Encoding }); + Insn.push_back({AArch64::ORRXri, 0, Encoding}); const bool SingleMovk = SecondMovkIdx == NotSet; - Insn.push_back({ AArch64::MOVKXi, getChunk(UImm, FirstMovkIdx), - AArch64_AM::getShifterImm(AArch64_AM::LSL, - FirstMovkIdx * 16) }); + Insn.push_back( + {AArch64::MOVKXi, getChunk(UImm, FirstMovkIdx), + AArch64_AM::getShifterImm(AArch64_AM::LSL, FirstMovkIdx * 16)}); // Early exit in case we only need to emit a single MOVK instruction. if (SingleMovk) return true; // Create the second MOVK instruction. - Insn.push_back({ AArch64::MOVKXi, getChunk(UImm, SecondMovkIdx), - AArch64_AM::getShifterImm(AArch64_AM::LSL, - SecondMovkIdx * 16) }); + Insn.push_back( + {AArch64::MOVKXi, getChunk(UImm, SecondMovkIdx), + AArch64_AM::getShifterImm(AArch64_AM::LSL, SecondMovkIdx * 16)}); return true; } @@ -529,8 +529,8 @@ static bool tryEorOfLogicalImmediates(uint64_t Imm, /// Describe the expansion of a MOVaddr-family pseudo instruction. /// Returns a sequence of opcodes that the pseudo expands into. void AArch64_ExpandPseudo::expandMOVAddr(unsigned Opcode, unsigned TargetFlags, - bool IsTargetMachO, - SmallVectorImpl<AddrInsnModel> &Insn) { + bool IsTargetMachO, + SmallVectorImpl<AddrInsnModel> &Insn) { if (Opcode == AArch64::MOVaddrBA && IsTargetMachO) { // Block address on MachO goes through a constant pool. Insn.push_back({AArch64::ADRP}); @@ -549,8 +549,8 @@ void AArch64_ExpandPseudo::expandMOVAddr(unsigned Opcode, unsigned TargetFlags, /// \brief Expand a MOVi32imm or MOVi64imm pseudo instruction to a /// MOVZ or MOVN of width BitSize followed by up to 3 MOVK instructions. static inline void expandMOVImmSimple(uint64_t Imm, unsigned BitSize, - unsigned OneChunks, unsigned ZeroChunks, - SmallVectorImpl<ImmInsnModel> &Insn) { + unsigned OneChunks, unsigned ZeroChunks, + SmallVectorImpl<ImmInsnModel> &Insn) { const unsigned Mask = 0xFFFF; // Use a MOVZ or MOVN instruction to set the high bits, followed by one or @@ -582,8 +582,8 @@ static inline void expandMOVImmSimple(uint64_t Imm, unsigned BitSize, } unsigned Imm16 = (Imm >> Shift) & Mask; - Insn.push_back({ FirstOpc, Imm16, - AArch64_AM::getShifterImm(AArch64_AM::LSL, Shift) }); + Insn.push_back( + {FirstOpc, Imm16, AArch64_AM::getShifterImm(AArch64_AM::LSL, Shift)}); if (Shift == LastShift) return; @@ -600,8 +600,8 @@ static inline void expandMOVImmSimple(uint64_t Imm, unsigned BitSize, if (Imm16 == (isNeg ? Mask : 0)) continue; // This 16-bit portion is already set correctly. - Insn.push_back({ Opc, Imm16, - AArch64_AM::getShifterImm(AArch64_AM::LSL, Shift) }); + Insn.push_back( + {Opc, Imm16, AArch64_AM::getShifterImm(AArch64_AM::LSL, Shift)}); } // Now, we get 16-bit divided Imm. If high and low bits are same in @@ -616,7 +616,7 @@ static inline void expandMOVImmSimple(uint64_t Imm, unsigned BitSize, /// Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more /// real move-immediate instructions to synthesize the immediate. void AArch64_ExpandPseudo::expandMOVImm(uint64_t Imm, unsigned BitSize, - SmallVectorImpl<ImmInsnModel> &Insn) { + SmallVectorImpl<ImmInsnModel> &Insn) { const unsigned Mask = 0xFFFF; // Scan the immediate and count the number of 16-bit chunks which are either @@ -644,7 +644,7 @@ void AArch64_ExpandPseudo::expandMOVImm(uint64_t Imm, unsigned BitSize, uint64_t Encoding; if (AArch64_AM::processLogicalImmediate(UImm, BitSize, Encoding)) { unsigned Opc = (BitSize == 32 ? AArch64::ORRWri : AArch64::ORRXri); - Insn.push_back({ Opc, 0, Encoding }); + Insn.push_back({Opc, 0, Encoding}); return; } @@ -679,12 +679,12 @@ void AArch64_ExpandPseudo::expandMOVImm(uint64_t Imm, unsigned BitSize, AArch64_AM::processLogicalImmediate(ReplicateChunk, BitSize, Encoding)) { // Create the ORR-immediate instruction. - Insn.push_back({ AArch64::ORRXri, 0, Encoding }); + Insn.push_back({AArch64::ORRXri, 0, Encoding}); // Create the MOVK instruction. const unsigned Imm16 = getChunk(UImm, Shift / 16); - Insn.push_back({ AArch64::MOVKXi, Imm16, - AArch64_AM::getShifterImm(AArch64_AM::LSL, Shift) }); + Insn.push_back({AArch64::MOVKXi, Imm16, + AArch64_AM::getShifterImm(AArch64_AM::LSL, Shift)}); return; } } diff --git a/llvm/lib/Target/AArch64/AArch64ExpandPseudo.h b/llvm/lib/Target/AArch64/AArch64ExpandPseudo.h index 790666a94ea29..af638b63fc856 100644 --- a/llvm/lib/Target/AArch64/AArch64ExpandPseudo.h +++ b/llvm/lib/Target/AArch64/AArch64ExpandPseudo.h @@ -30,7 +30,7 @@ struct AddrInsnModel { }; void expandMOVImm(uint64_t Imm, unsigned BitSize, - SmallVectorImpl<ImmInsnModel> &Insn); + SmallVectorImpl<ImmInsnModel> &Insn); void expandMOVAddr(unsigned Opcode, unsigned TargetFlags, bool IsTargetMachO, SmallVectorImpl<AddrInsnModel> &Insn); diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index b4b2837fe4a02..43f6b5d0b6a49 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -13213,7 +13213,8 @@ bool AArch64TargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, // movw+movk+fmov vs. adrp+ldr (it's one instruction longer, but the // movw+movk is fused). So we limit up to 2 instrdduction at most. SmallVector<AArch64_ExpandPseudo::ImmInsnModel, 4> Insn; - AArch64_ExpandPseudo::expandMOVImm(ImmInt.getZExtValue(), VT.getSizeInBits(), Insn); + AArch64_ExpandPseudo::expandMOVImm(ImmInt.getZExtValue(), + VT.getSizeInBits(), Insn); assert(Insn.size() <= 4 && "Should be able to build any value with at most 4 moves"); unsigned Limit = (OptForSize ? 1 : (Subtarget->hasFuseLiterals() ? 4 : 2)); diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp index f302b52a461e1..f6c6413e1622e 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -194,6 +194,33 @@ unsigned AArch64InstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { case AArch64::SPACE: NumBytes = MI.getOperand(1).getImm(); break; + + case AArch64::MOVaddr: + case AArch64::MOVaddrJT: + case AArch64::MOVaddrCP: + case AArch64::MOVaddrBA: + case AArch64::MOVaddrTLS: + case AArch64::MOVaddrEXT: { + // Use the same logic as the pseudo expansion to count instructions. + SmallVector<AArch64_ExpandPseudo::AddrInsnModel, 3> Insn; + AArch64_ExpandPseudo::expandMOVAddr(Desc.getOpcode(), + MI.getOperand(1).getTargetFlags(), + Subtarget.isTargetMachO(), Insn); + NumBytes = Insn.size() * 4; + break; + } + + case AArch64::MOVi32imm: + case AArch64::MOVi64imm: { + // Use the same logic as the pseudo expansion to count instructions. + unsigned BitSize = Desc.getOpcode() == AArch64::MOVi32imm ? 32 : 64; + SmallVector<AArch64_ExpandPseudo::ImmInsnModel, 4> Insn; + AArch64_ExpandPseudo::expandMOVImm(MI.getOperand(1).getImm(), BitSize, + Insn); + NumBytes = Insn.size() * 4; + break; + } + case TargetOpcode::BUNDLE: NumBytes = getInstBundleLength(MI); break; @@ -1215,20 +1242,6 @@ void AArch64InstrInfo::insertSelect(MachineBasicBlock &MBB, .addImm(CC); } -// Return true if Imm can be loaded into a register by a "cheap" sequence of -// instructions. For now, "cheap" means at most two instructions. -static bool isCheapImmediate(const MachineInstr &MI, unsigned BitSize) { - if (BitSize == 32) - return true; - - assert(BitSize == 64 && "Only bit sizes of 32 or 64 allowed"); - uint64_t Imm = static_cast<uint64_t>(MI.getOperand(1).getImm()); - SmallVector<AArch64_ExpandPseudo::ImmInsnModel, 4> Is; - AArch64_ExpandPseudo::expandMOVImm(Imm, BitSize, Is); - - return Is.size() <= 2; -} - // Check if a COPY instruction is cheap. static bool isCheapCopy(const MachineInstr &MI, const AArch64RegisterInfo &RI) { assert(MI.isCopy() && "Expected COPY instruction"); @@ -1277,9 +1290,8 @@ bool AArch64InstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const { // ORRXri, it is as cheap as MOV. // Likewise if it can be expanded to MOVZ/MOVN/MOVK. case AArch64::MOVi32imm: - return isCheapImmediate(MI, 32); case AArch64::MOVi64imm: - return isCheapImmediate(MI, 64); + return getInstSizeInBytes(MI) <= 8; } } _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
