[llvm] [AArch64][GlobalISel] Select unmerging s128 FPR value into two s64 GPR values (PR #215995)
Cullen Rhodes via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 20 23:33:58 PDT 2026
https://github.com/c-rhodes updated https://github.com/llvm/llvm-project/pull/215995
>From 0e8bb00eca7beb1eac39e7e3569952a31ba197ef Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Thu, 11 Jun 2026 11:39:50 +0000
Subject: [PATCH 1/2] [AArch64][GlobalISel] Select unmerging s128 FPR value
into two s64 GPR values
RegBankSelect treats s128s like vectors when unmerging and assigns the
s64 results to FPR. Prototyping an alternative type-based RBS (#199040)
that assigns 64-bit scalar values to GPR exposed a gap in the
instruction selector.
Select the two s64 results directly with UMOVvi64.
Assisted-by: codex
---
.../GISel/AArch64InstructionSelector.cpp | 44 ++++++++++++++-----
.../AArch64/GlobalISel/select-unmerge.mir | 24 ++++++++++
2 files changed, 57 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index ad8c1eb728e7b..1c6abf3777a62 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -4029,22 +4029,44 @@ bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &I,
assert(I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
"unexpected opcode");
- // TODO: Handle unmerging into GPRs and from scalars to scalars.
- if (RBI.getRegBank(I.getOperand(0).getReg(), MRI, TRI)->getID() !=
- AArch64::FPRRegBankID ||
- RBI.getRegBank(I.getOperand(1).getReg(), MRI, TRI)->getID() !=
- AArch64::FPRRegBankID) {
- LLVM_DEBUG(dbgs() << "Unmerging vector-to-gpr and scalar-to-scalar "
- "currently unsupported.\n");
- return false;
- }
-
// The last operand is the vector source register, and every other operand is
// a register to unpack into.
unsigned NumElts = I.getNumOperands() - 1;
Register SrcReg = I.getOperand(NumElts).getReg();
- const LLT NarrowTy = MRI.getType(I.getOperand(0).getReg());
+ Register LoReg = I.getOperand(0).getReg();
+ Register HiReg = I.getOperand(1).getReg();
+ const LLT NarrowTy = MRI.getType(LoReg);
const LLT WideTy = MRI.getType(SrcReg);
+ const RegisterBank &LoRB = *RBI.getRegBank(LoReg, MRI, TRI);
+ const RegisterBank &HiRB = *RBI.getRegBank(HiReg, MRI, TRI);
+ const RegisterBank &SrcRB = *RBI.getRegBank(SrcReg, MRI, TRI);
+
+ // Handle unmerging an s128 FPR value into two s64 GPR values.
+ if (NarrowTy == LLT::scalar(64) && WideTy == LLT::scalar(128) &&
+ LoRB.getID() == AArch64::GPRRegBankID &&
+ HiRB.getID() == AArch64::GPRRegBankID &&
+ SrcRB.getID() == AArch64::FPRRegBankID) {
+ MachineInstr &Lo = *BuildMI(*I.getParent(), I, I.getDebugLoc(),
+ TII.get(AArch64::UMOVvi64), LoReg)
+ .addUse(SrcReg)
+ .addImm(0);
+ MachineInstr &Hi = *BuildMI(*I.getParent(), I, I.getDebugLoc(),
+ TII.get(AArch64::UMOVvi64), HiReg)
+ .addUse(SrcReg)
+ .addImm(1);
+ constrainSelectedInstRegOperands(Lo, TII, TRI, RBI);
+ constrainSelectedInstRegOperands(Hi, TII, TRI, RBI);
+ I.eraseFromParent();
+ return true;
+ }
+
+ // TODO: Handle other unmerges into GPRs and from scalars to scalars.
+ if (LoRB.getID() != AArch64::FPRRegBankID ||
+ HiRB.getID() != AArch64::FPRRegBankID) {
+ LLVM_DEBUG(dbgs() << "Unmerging vector-to-gpr and scalar-to-scalar "
+ "currently unsupported.\n");
+ return false;
+ }
assert(WideTy.getSizeInBits() > NarrowTy.getSizeInBits() &&
"source register size too small!");
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-unmerge.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-unmerge.mir
index da58fa4815d94..09a6504a17a83 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/select-unmerge.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-unmerge.mir
@@ -461,6 +461,30 @@ body: |
RET_ReallyLR implicit $d0, implicit $d1
...
---
+name: test_s128_fpr_to_gpr
+alignment: 4
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+body: |
+ bb.1:
+ liveins: $q0
+ ; CHECK-LABEL: name: test_s128_fpr_to_gpr
+ ; CHECK: liveins: $q0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr128 = COPY $q0
+ ; CHECK-NEXT: [[UMOVvi64_:%[0-9]+]]:gpr64 = UMOVvi64 [[COPY]], 0
+ ; CHECK-NEXT: [[UMOVvi64_1:%[0-9]+]]:gpr64 = UMOVvi64 [[COPY]], 1
+ ; CHECK-NEXT: $x0 = COPY [[UMOVvi64_]]
+ ; CHECK-NEXT: $x1 = COPY [[UMOVvi64_1]]
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0, implicit $x1
+ %0:fpr(s128) = COPY $q0
+ %1:gpr(s64), %2:gpr(s64) = G_UNMERGE_VALUES %0(s128)
+ $x0 = COPY %1(s64)
+ $x1 = COPY %2(s64)
+ RET_ReallyLR implicit $x0, implicit $x1
+...
+---
name: test_s32_to_2s16_unmerge
alignment: 4
legalized: true
>From 76db03418606feabf7f344c9e2d4553c96099fc9 Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Fri, 21 Aug 2026 06:33:43 +0000
Subject: [PATCH 2/2] address comments
---
.../AArch64/GISel/AArch64InstructionSelector.cpp | 2 +-
.../CodeGen/AArch64/GlobalISel/select-unmerge.mir | 12 ++++++------
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 1c6abf3777a62..6761d5dfb586b 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -4041,7 +4041,7 @@ bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &I,
const RegisterBank &HiRB = *RBI.getRegBank(HiReg, MRI, TRI);
const RegisterBank &SrcRB = *RBI.getRegBank(SrcReg, MRI, TRI);
- // Handle unmerging an s128 FPR value into two s64 GPR values.
+ // Handle unmerging a 128-bit FPR value into two 64-bit GPR values.
if (NarrowTy == LLT::scalar(64) && WideTy == LLT::scalar(128) &&
LoRB.getID() == AArch64::GPRRegBankID &&
HiRB.getID() == AArch64::GPRRegBankID &&
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-unmerge.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-unmerge.mir
index 09a6504a17a83..4a9ce40982f61 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/select-unmerge.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-unmerge.mir
@@ -461,7 +461,7 @@ body: |
RET_ReallyLR implicit $d0, implicit $d1
...
---
-name: test_s128_fpr_to_gpr
+name: test_i128_fpr_to_gpr
alignment: 4
legalized: true
regBankSelected: true
@@ -469,7 +469,7 @@ tracksRegLiveness: true
body: |
bb.1:
liveins: $q0
- ; CHECK-LABEL: name: test_s128_fpr_to_gpr
+ ; CHECK-LABEL: name: test_i128_fpr_to_gpr
; CHECK: liveins: $q0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr128 = COPY $q0
@@ -478,10 +478,10 @@ body: |
; CHECK-NEXT: $x0 = COPY [[UMOVvi64_]]
; CHECK-NEXT: $x1 = COPY [[UMOVvi64_1]]
; CHECK-NEXT: RET_ReallyLR implicit $x0, implicit $x1
- %0:fpr(s128) = COPY $q0
- %1:gpr(s64), %2:gpr(s64) = G_UNMERGE_VALUES %0(s128)
- $x0 = COPY %1(s64)
- $x1 = COPY %2(s64)
+ %0:fpr(i128) = COPY $q0
+ %1:gpr(i64), %2:gpr(i64) = G_UNMERGE_VALUES %0(i128)
+ $x0 = COPY %1(i64)
+ $x1 = COPY %2(i64)
RET_ReallyLR implicit $x0, implicit $x1
...
---
More information about the llvm-commits
mailing list