[llvm-branch-commits] [llvm] release/22.x: [ARM] Count register copies when estimating function size (#175763) (PR #178197)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Jan 27 04:53:12 PST 2026
https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/178197
Backport 0921542e3b0557e926af846a414676a6a5d0e43c
Requested by: @statham-arm
>From 1dd68716b1a563c2e84909b43bf5314f2c94477b Mon Sep 17 00:00:00 2001
From: Simon Tatham <simon.tatham at arm.com>
Date: Mon, 26 Jan 2026 09:28:38 +0000
Subject: [PATCH] [ARM] Count register copies when estimating function size
(#175763)
`EstimateFunctionSizeInBytes`, in `ARMFrameLowering.cpp`, provides an
early estimate of the compiled size of a function, in a context that
wants to overestimate rather than underestimate.
In some cases it was underestimating severely, by over 20%. The
discrepancy was entirely accounted for by the fact that `COPY`
operations were not being counted at all, even though each one (or at
least each one that survives any post-regalloc optimizations) takes 2
bytes in Thumb or 4 in Arm. This could lead to a compile failure, if the
underestimated function size led frame lowering to not stack LR, but
later, `ARMConstantIslandsPass` needed to insert an intra-function
branch long enough to require a `bl` instruction, needing LR to have
been stacked.
The result of `EstimateFunctionSizeInBytes` was not directly available
for testing, so I added an `LLVM_DEBUG` at the end of the function. That
way, the test file doesn't need to try to make a >2048 byte function
estimated at <2048 bytes; it just needs to exhibit a function with a
single `COPY` and make sure it's counted.
At the moment, `EstimateFunctionSizeInBytes` is only used at all in
Thumb-1 compilations, to decide whether the function is large enough to
justify stacking LR as a precaution. However, the subroutine
`ARMBaseInstrInfo::getInstSizeInBytes` which counts each individual
`MachineInstr` is called from other contexts too, so I've made it return
a sensible answer for `COPY` nodes in both of Arm and Thumb.
(cherry picked from commit 0921542e3b0557e926af846a414676a6a5d0e43c)
---
llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp | 5 +++
llvm/lib/Target/ARM/ARMFrameLowering.cpp | 2 ++
llvm/test/CodeGen/ARM/estimate-size-copy.mir | 37 ++++++++++++++++++++
3 files changed, 44 insertions(+)
create mode 100644 llvm/test/CodeGen/ARM/estimate-size-copy.mir
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index 402a4e30fe3ca..1c8ab6afb9095 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -619,6 +619,11 @@ unsigned ARMBaseInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
return MCID.getSize();
case TargetOpcode::BUNDLE:
return getInstBundleLength(MI);
+ case TargetOpcode::COPY:
+ if (!MF->getInfo<ARMFunctionInfo>()->isThumbFunction())
+ return 4;
+ else
+ return 2;
case ARM::CONSTPOOL_ENTRY:
case ARM::JUMPTABLE_INSTS:
case ARM::JUMPTABLE_ADDRS:
diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.cpp b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
index 2fc64894b0d34..a0b975072bd8e 100644
--- a/llvm/lib/Target/ARM/ARMFrameLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
@@ -2335,6 +2335,8 @@ static unsigned EstimateFunctionSizeInBytes(const MachineFunction &MF,
for (auto &Table: MF.getJumpTableInfo()->getJumpTables())
FnSize += Table.MBBs.size() * 4;
FnSize += MF.getConstantPool()->getConstants().size() * 4;
+ LLVM_DEBUG(dbgs() << "Estimated function size for " << MF.getName() << " = "
+ << FnSize << " bytes\n");
return FnSize;
}
diff --git a/llvm/test/CodeGen/ARM/estimate-size-copy.mir b/llvm/test/CodeGen/ARM/estimate-size-copy.mir
new file mode 100644
index 0000000000000..154117d1743d1
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/estimate-size-copy.mir
@@ -0,0 +1,37 @@
+# REQUIRES: asserts
+#
+# RUN: llc -mtriple=thumbv6m -start-before=machine-cp -debug -o - %s 2>%t | \
+# RUN: FileCheck %s --check-prefix=OUTPUT
+# RUN: FileCheck %s --check-prefix=DEBUG < %t
+#
+# DEBUG: Estimated function size for f = 4 bytes
+#
+# OUTPUT: mov r0, r1
+# OUTPUT: bx lr
+
+--- |
+ target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
+ target triple = "thumbv6m-unknown-none-eabi"
+
+ define i32 @f(i32 %x, i32 %y) {
+ entry:
+ ret i32 %y
+ }
+
+...
+---
+name: f
+tracksRegLiveness: true
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ localFrameSize: 0
+machineFunctionInfo:
+ isLRSpilled: false
+body: |
+ bb.0.entry:
+ liveins: $r1
+
+ renamable $r0 = COPY $r1
+ tBX_RET 14 /* CC::al */, $noreg, implicit $r0
+...
More information about the llvm-branch-commits
mailing list