[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