[llvm] [CodeGen] Sort fixed frame objects by stack offset (PR #219669)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 13 09:13:45 PDT 2026
https://github.com/zhouguangyuan0718 updated https://github.com/llvm/llvm-project/pull/219669
>From 4e8f3801f57ef12457d3ebaa16f23ff833676fe9 Mon Sep 17 00:00:00 2001
From: ZhouGuangyuan <zhouguangyuan.xian at gmail.com>
Date: Sat, 29 Aug 2026 19:01:46 +0800
Subject: [PATCH] [MachineScheduler] Order fixed-FI memory operations by object
offset
BaseMemOpClusterMutation sorts frame-index bases by frame-index number,
accounting for the stack growth direction. Fixed objects have explicit
offsets that do not have to follow their creation order, so this can pass
fixed-object bases to AArch64's clustering hook in reverse address order
and trigger the offset-ordering assertion in shouldClusterFI.
Compare fixed-object bases by their MachineFrameInfo object offsets, with
the existing frame-index ordering as a tie-breaker. Explicitly order fixed
and non-fixed bases as separate groups, preserving their previous relative
ordering: non-fixed bases first for downward-growing stacks, and fixed
bases first for upward-growing stacks. Keep frame-index ordering within
the non-fixed group, without relying on offsets before frame layout.
This only changes the ordering of memory-operation records used for
clustering; it does not change frame-object offsets or stack allocation.
Add AArch64 MIR coverage for out-of-order fixed objects and interleaved
accesses to fixed and non-fixed objects, using both machine-scheduler pass
forms.
---
llvm/lib/CodeGen/MachineScheduler.cpp | 19 +++++++
.../CodeGen/AArch64/cluster-frame-index.mir | 49 +++++++++++++++++++
2 files changed, 68 insertions(+)
diff --git a/llvm/lib/CodeGen/MachineScheduler.cpp b/llvm/lib/CodeGen/MachineScheduler.cpp
index 814ea3f8eeb05..5aab9f1d4cba4 100644
--- a/llvm/lib/CodeGen/MachineScheduler.cpp
+++ b/llvm/lib/CodeGen/MachineScheduler.cpp
@@ -25,6 +25,7 @@
#include "llvm/CodeGen/LiveInterval.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
@@ -1982,9 +1983,27 @@ class BaseMemOpClusterMutation : public ScheduleDAGMutation {
return A->getReg() < B->getReg();
if (A->isFI()) {
const MachineFunction &MF = *A->getParent()->getParent()->getParent();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
bool StackGrowsDown = TFI.getStackGrowthDirection() ==
TargetFrameLowering::StackGrowsDown;
+ bool AIsFixed = MFI.isFixedObjectIndex(A->getIndex());
+ bool BIsFixed = MFI.isFixedObjectIndex(B->getIndex());
+ // Sort fixed and non-fixed bases as separate groups, preserving the
+ // existing frame-index ordering between the groups. Do not rely on
+ // non-fixed object offsets before frame layout.
+ if (AIsFixed != BIsFixed)
+ return StackGrowsDown ? !AIsFixed : AIsFixed;
+ if (AIsFixed) {
+ // Fixed objects have explicit offsets, and targets may create their
+ // frame indices in an order unrelated to those offsets. Sort by the
+ // actual object offsets so target clustering hooks see fixed object
+ // bases in address order.
+ int64_t AOffset = MFI.getObjectOffset(A->getIndex());
+ int64_t BOffset = MFI.getObjectOffset(B->getIndex());
+ if (AOffset != BOffset)
+ return AOffset < BOffset;
+ }
return StackGrowsDown ? A->getIndex() > B->getIndex()
: A->getIndex() < B->getIndex();
}
diff --git a/llvm/test/CodeGen/AArch64/cluster-frame-index.mir b/llvm/test/CodeGen/AArch64/cluster-frame-index.mir
index 5d761f10be3b2..a32efb95df413 100644
--- a/llvm/test/CodeGen/AArch64/cluster-frame-index.mir
+++ b/llvm/test/CodeGen/AArch64/cluster-frame-index.mir
@@ -27,6 +27,55 @@ body: |
; CHECK-NEXT: RET
...
---
+name: merge_out_of_order_fixedstack
+# CHECK-LABEL: name: merge_out_of_order_fixedstack
+tracksRegLiveness: true
+fixedStack:
+ # Fixed object indices are allocated in reverse id order. Deliberately keep
+ # their explicit offsets in the opposite order: the scheduler must use the
+ # fixed object offsets, not frame-index creation order, when sorting memory
+ # operations for clustering.
+ - { id: 0, size: 8, alignment: 8, offset: -8 }
+ - { id: 1, size: 8, alignment: 8, offset: -16 }
+body: |
+ bb.0:
+ %0:gpr64 = LDRXui %fixed-stack.0, 0 :: (load (s64))
+ %1:gpr64 = LDRXui %fixed-stack.1, 0 :: (load (s64))
+ $x0 = ADDXrr %0, %1
+ RET_ReallyLR implicit $x0
+
+ ; CHECK: LDRXui %fixed-stack.1
+ ; CHECK-NEXT: LDRXui %fixed-stack.0
+ ; CHECK: ADDXrr
+ ; CHECK: RET
+...
+---
+name: merge_mixed_stack_objects
+# CHECK-LABEL: name: merge_mixed_stack_objects
+tracksRegLiveness: true
+# Keep fixed and non-fixed bases grouped for clustering, even when their
+# accesses are interleaved and the fixed objects are created out of offset order.
+fixedStack:
+ - { id: 0, size: 8, alignment: 8, offset: -8 }
+ - { id: 1, size: 8, alignment: 8, offset: -16 }
+stack:
+ - { id: 0, size: 8, alignment: 8 }
+body: |
+ bb.0:
+ %0:gpr64 = LDRXui %fixed-stack.0, 0 :: (load (s64))
+ %1:gpr64 = LDRXui %stack.0, 0 :: (load (s64))
+ %2:gpr64 = LDRXui %fixed-stack.1, 0 :: (load (s64))
+ %3:gpr64 = ADDXrr %0, %1
+ $x0 = ADDXrr %3, %2
+ RET_ReallyLR implicit $x0
+
+ ; CHECK: LDRXui %stack.0
+ ; CHECK: LDRXui %fixed-stack.1
+ ; CHECK-NEXT: LDRXui %fixed-stack.0
+ ; CHECK: ADDXrr
+ ; CHECK: RET
+...
+---
name: merge_fixedstack
# CHECK-LABEL: name: merge_fixedstack
tracksRegLiveness: true
More information about the llvm-commits
mailing list