[llvm] [AArch64] Allow high-II schedules only when vectorised (PR #206079)

William Huynh via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 26 07:19:35 PDT 2026


https://github.com/saturn691 created https://github.com/llvm/llvm-project/pull/206079

MachinePipeliner has a cap of II=27 which is reasonable, but it rejects a subset of profitable loops. These are vectorised loops, that have not been interleaved by the Loop Vectorizer (i.e. loops written with intrinsics).

However, this is still a draft, as we need to uncap the II limit in code. Also this is codex code, so there may be a better way to do this.

Assisted-by: codex, reviewed and tested by me

>From 85c753625a4064a2e644f36b6350c17f129cc483 Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Fri, 26 Jun 2026 15:06:53 +0100
Subject: [PATCH] [AArch64] Allow high-II schedules only when vectorised

MachinePipeliner has a cap of II=27 which is reasonable, but it rejects
a subset of profitable loops. These are vectorised loops, that have not
been interleaved by the Loop Vectorizer (i.e. loops written with
intrinsics).

However, this is still a draft, as we need to uncap the II limit in code.
Also this is codex code, so there may be a better way to do this.

Assisted-by: codex, reviewed and tested by me
---
 llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 55 ++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index ca1a729dd1dd1..cea03d08a902a 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -36,6 +36,7 @@
 #include "llvm/CodeGen/MachineMemOperand.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/CodeGen/MachinePipeliner.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/RegisterScavenging.h"
 #include "llvm/CodeGen/StackMaps.h"
@@ -103,6 +104,11 @@ static cl::opt<unsigned> GatherOptSearchLimit(
     cl::desc("Restrict range of instructions to search for the "
              "machine-combiner gather pattern optimization"));
 
+static cl::opt<int> AArch64PipelinerMaxScalarII(
+    "aarch64-pipeliner-max-scalar-ii", cl::Hidden, cl::init(-1),
+    cl::desc("Reject scalar-only AArch64 MachinePipeliner schedules above this "
+             "initiation interval (-1 disables the check)"));
+
 AArch64InstrInfo::AArch64InstrInfo(const AArch64Subtarget &STI)
     : AArch64GenInstrInfo(STI, RI, AArch64::ADJCALLSTACKDOWN,
                           AArch64::ADJCALLSTACKUP, AArch64::CATCHRET),
@@ -11695,6 +11701,8 @@ class AArch64PipelinerLoopInfo : public TargetInstrInfo::PipelinerLoopInfo {
   /// The normalized condition used by createTripCountGreaterCondition()
   SmallVector<MachineOperand, 4> Cond;
 
+  bool containsFpOrVectorRegisters(SwingSchedulerDAG &SSD) const;
+
 public:
   AArch64PipelinerLoopInfo(MachineBasicBlock *LoopBB, MachineInstr *CondBranch,
                            MachineInstr *Comp, unsigned CompCounterOprNum,
@@ -11715,6 +11723,15 @@ class AArch64PipelinerLoopInfo : public TargetInstrInfo::PipelinerLoopInfo {
     return MI == Comp;
   }
 
+  bool shouldUseSchedule(SwingSchedulerDAG &SSD, SMSchedule &SMS) override {
+    if (AArch64PipelinerMaxScalarII >= 0 &&
+        SMS.getInitiationInterval() > AArch64PipelinerMaxScalarII &&
+        !containsFpOrVectorRegisters(SSD))
+      return false;
+
+    return true;
+  }
+
   std::optional<bool> createTripCountGreaterCondition(
       int TC, MachineBasicBlock &MBB,
       SmallVectorImpl<MachineOperand> &CondParam) override {
@@ -11735,6 +11752,44 @@ class AArch64PipelinerLoopInfo : public TargetInstrInfo::PipelinerLoopInfo {
 
   bool isMVEExpanderSupported() override { return true; }
 };
+
+bool AArch64PipelinerLoopInfo::containsFpOrVectorRegisters(
+    SwingSchedulerDAG &SSD) const {
+  auto IsFpOrVectorRC = [](const TargetRegisterClass *RC) {
+    return RC && (AArch64::FPR8RegClass.hasSubClassEq(RC) ||
+                  AArch64::FPR16RegClass.hasSubClassEq(RC) ||
+                  AArch64::FPR32RegClass.hasSubClassEq(RC) ||
+                  AArch64::FPR64RegClass.hasSubClassEq(RC) ||
+                  AArch64::FPR128RegClass.hasSubClassEq(RC) ||
+                  AArch64::PPRRegClass.hasSubClassEq(RC) ||
+                  AArch64::PNRRegClass.hasSubClassEq(RC) ||
+                  AArch64::ZPRRegClass.hasSubClassEq(RC) ||
+                  AArch64::ZPR2RegClass.hasSubClassEq(RC) ||
+                  AArch64::ZPR3RegClass.hasSubClassEq(RC) ||
+                  AArch64::ZPR4RegClass.hasSubClassEq(RC));
+  };
+
+  for (SUnit &SU : SSD.SUnits) {
+    const MachineInstr *MI = SU.getInstr();
+    for (const MachineOperand &MO : MI->operands()) {
+      if (!MO.isReg() || !MO.getReg())
+        continue;
+
+      Register Reg = MO.getReg();
+      const TargetRegisterClass *RC = nullptr;
+      if (Reg.isVirtual())
+        RC = MRI.getRegClassOrNull(Reg);
+      else if (Reg.isPhysical())
+        RC = TRI->getMinimalPhysRegClass(Reg.asMCReg());
+
+      if (IsFpOrVectorRC(RC))
+        return true;
+    }
+  }
+
+  return false;
+}
+
 } // namespace
 
 /// Clone an instruction from MI. The register of ReplaceOprNum-th operand



More information about the llvm-commits mailing list