[llvm-branch-commits] [llvm] [AArch64] Report accurate sizes for MOVaddr and MOVimm pseudos (PR #183506)
Guy David via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Feb 26 03:54:52 PST 2026
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 <guyda96 at gmail.com>
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;
}
}
More information about the llvm-branch-commits
mailing list