[llvm] [AArch64][GlobalISel] Select integer vector reductions into GPRs (PR #212976)

Cullen Rhodes via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 31 02:41:00 PDT 2026


https://github.com/c-rhodes updated https://github.com/llvm/llvm-project/pull/212976

>From d2ab7c1c63e7029c1c1eb4e96e34d2aa2726805f Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Thu, 11 Jun 2026 11:34:58 +0000
Subject: [PATCH 1/2] [AArch64][GlobalISel] Select integer vector reductions
 into GPRs

Prototyping a new minimal type-based approach to RegBankSelect (#199040)
for compile-time purposes exposed various gaps in instruction selection
when not using the existing RegBankSelect pass. These manifested as new
fallbacks when compiling CTMark and the IR dataset from [1].

Imported patterns require an FPR result. This patch teaches instruction
selection to handle vector reductions with GPR results by using a
temporary FPR and inserting a cross-bank copy.

Assisted-by: codex

[1] https://davemgreen.github.io/gisel.html
---
 .../GISel/AArch64InstructionSelector.cpp      | 22 +++++++++++++++
 .../AArch64/GlobalISel/select-reduce-add.mir  | 28 +++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 0c2f3f97ec07d..1fcef85d5c9f6 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -2187,6 +2187,28 @@ bool AArch64InstructionSelector::preISelLower(MachineInstr &I) {
     MRI.setType(DstReg, LLT::scalar(64));
     return true;
   }
+  case TargetOpcode::G_VECREDUCE_ADD:
+  case TargetOpcode::G_VECREDUCE_SMAX:
+  case TargetOpcode::G_VECREDUCE_SMIN:
+  case TargetOpcode::G_VECREDUCE_UMAX:
+  case TargetOpcode::G_VECREDUCE_UMIN: {
+    // Imported patterns require an FPR result. For a GPR, use a temporary FPR
+    // and insert a cross-bank copy.
+    Register DstReg = I.getOperand(0).getReg();
+    if (RBI.getRegBank(DstReg, MRI, TRI)->getID() != AArch64::GPRRegBankID)
+      return false;
+
+    LLT DstTy = MRI.getType(DstReg);
+    Register FPRDst = MRI.createGenericVirtualRegister(DstTy);
+    MRI.setRegBank(FPRDst, RBI.getRegBank(AArch64::FPRRegBankID));
+    I.getOperand(0).setReg(FPRDst);
+
+    MIB.setInsertPt(MBB, std::next(I.getIterator()));
+    auto Copy = MIB.buildCopy(DstReg, FPRDst);
+    selectCopy(*Copy, TII, MRI, TRI, RBI);
+    MIB.setInstr(I);
+    return true;
+  }
   case AArch64::G_DUP: {
     // Convert the type from p0 to s64 to help selection.
     LLT DstTy = MRI.getType(I.getOperand(0).getReg());
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-reduce-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-reduce-add.mir
index e48664da8e97a..c216105197e58 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/select-reduce-add.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-reduce-add.mir
@@ -88,6 +88,34 @@ body:             |
     $w0 = COPY %2(i32)
     RET_ReallyLR implicit $w0
 
+...
+---
+name:            add_S_gpr_result
+alignment:       4
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+liveins:
+  - { reg: '$x0' }
+body:             |
+  bb.1:
+    liveins: $x0
+
+    ; CHECK-LABEL: name: add_S_gpr_result
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64sp = COPY $x0
+    ; CHECK-NEXT: [[LDRQui:%[0-9]+]]:fpr128 = LDRQui [[COPY]], 0 :: (load (<4 x s32>))
+    ; CHECK-NEXT: [[ADDVv4i32v:%[0-9]+]]:fpr32 = ADDVv4i32v [[LDRQui]]
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32all = COPY [[ADDVv4i32v]]
+    ; CHECK-NEXT: $w0 = COPY [[COPY1]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %0:gpr(p0) = COPY $x0
+    %1:fpr(<4 x i32>) = G_LOAD %0(p0) :: (load (<4 x s32>))
+    %2:gpr(i32) = G_VECREDUCE_ADD %1(<4 x i32>)
+    $w0 = COPY %2(i32)
+    RET_ReallyLR implicit $w0
+
 ...
 ---
 name:            add_S_v2i32

>From e6d41b142dc9a25f09556f19bc4370950324c228 Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Fri, 31 Jul 2026 09:39:37 +0000
Subject: [PATCH 2/2] address comments

---
 .../GlobalISel/select-reduce-minmax.mir       | 106 ++++++++++++++++++
 1 file changed, 106 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/select-reduce-minmax.mir

diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-reduce-minmax.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-reduce-minmax.mir
new file mode 100644
index 0000000000000..6b6036f34ca13
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-reduce-minmax.mir
@@ -0,0 +1,106 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=aarch64 -run-pass=instruction-select -verify-machineinstrs -global-isel-abort=1 %s -o - | FileCheck %s
+---
+name:            smax_S_gpr_result
+alignment:       4
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+liveins:
+  - { reg: '$q0' }
+body:             |
+  bb.1:
+    liveins: $q0
+
+    ; CHECK-LABEL: name: smax_S_gpr_result
+    ; CHECK: liveins: $q0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr128 = COPY $q0
+    ; CHECK-NEXT: [[SMAXVv4i32v:%[0-9]+]]:fpr32 = SMAXVv4i32v [[COPY]]
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32all = COPY [[SMAXVv4i32v]]
+    ; CHECK-NEXT: $w0 = COPY [[COPY1]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %0:fpr(<4 x i32>) = COPY $q0
+    %1:gpr(i32) = G_VECREDUCE_SMAX %0(<4 x i32>)
+    $w0 = COPY %1(i32)
+    RET_ReallyLR implicit $w0
+
+...
+---
+name:            smin_S_gpr_result
+alignment:       4
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+liveins:
+  - { reg: '$q0' }
+body:             |
+  bb.1:
+    liveins: $q0
+
+    ; CHECK-LABEL: name: smin_S_gpr_result
+    ; CHECK: liveins: $q0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr128 = COPY $q0
+    ; CHECK-NEXT: [[SMINVv4i32v:%[0-9]+]]:fpr32 = SMINVv4i32v [[COPY]]
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32all = COPY [[SMINVv4i32v]]
+    ; CHECK-NEXT: $w0 = COPY [[COPY1]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %0:fpr(<4 x i32>) = COPY $q0
+    %1:gpr(i32) = G_VECREDUCE_SMIN %0(<4 x i32>)
+    $w0 = COPY %1(i32)
+    RET_ReallyLR implicit $w0
+
+...
+---
+name:            umax_S_gpr_result
+alignment:       4
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+liveins:
+  - { reg: '$q0' }
+body:             |
+  bb.1:
+    liveins: $q0
+
+    ; CHECK-LABEL: name: umax_S_gpr_result
+    ; CHECK: liveins: $q0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr128 = COPY $q0
+    ; CHECK-NEXT: [[UMAXVv4i32v:%[0-9]+]]:fpr32 = UMAXVv4i32v [[COPY]]
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32all = COPY [[UMAXVv4i32v]]
+    ; CHECK-NEXT: $w0 = COPY [[COPY1]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %0:fpr(<4 x i32>) = COPY $q0
+    %1:gpr(i32) = G_VECREDUCE_UMAX %0(<4 x i32>)
+    $w0 = COPY %1(i32)
+    RET_ReallyLR implicit $w0
+
+...
+---
+name:            umin_S_gpr_result
+alignment:       4
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+liveins:
+  - { reg: '$q0' }
+body:             |
+  bb.1:
+    liveins: $q0
+
+    ; CHECK-LABEL: name: umin_S_gpr_result
+    ; CHECK: liveins: $q0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr128 = COPY $q0
+    ; CHECK-NEXT: [[UMINVv4i32v:%[0-9]+]]:fpr32 = UMINVv4i32v [[COPY]]
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32all = COPY [[UMINVv4i32v]]
+    ; CHECK-NEXT: $w0 = COPY [[COPY1]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %0:fpr(<4 x i32>) = COPY $q0
+    %1:gpr(i32) = G_VECREDUCE_UMIN %0(<4 x i32>)
+    $w0 = COPY %1(i32)
+    RET_ReallyLR implicit $w0
+
+...



More information about the llvm-commits mailing list