[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