[llvm] [AArch64] fix copy from GPR32 to FPR16 (PR #176594)
Folkert de Vries via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 22 11:04:36 PST 2026
https://github.com/folkertdev updated https://github.com/llvm/llvm-project/pull/176594
>From b5f05df0c24f58a8b551c395712f3fbcefb337d2 Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert at folkertdev.nl>
Date: Wed, 21 Jan 2026 15:49:37 +0100
Subject: [PATCH 1/3] force input register into the correct bank when tied to
destination
---
.../CodeGen/GlobalISel/InlineAsmLowering.cpp | 30 +++++++++++++++----
.../GlobalISel/irtranslator-inline-asm.ll | 5 ++--
.../CodeGen/AArch64/inlineasm-hreg-copy.ll | 29 ++++++++++++++++++
3 files changed, 57 insertions(+), 7 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll
diff --git a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
index a1f3d6b53d949..940df8affe031 100644
--- a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
@@ -408,13 +408,33 @@ bool InlineAsmLowering::lowerInlineAsm(
ArrayRef<Register> SrcRegs = GetOrCreateVRegs(*OpInfo.CallOperandVal);
assert(SrcRegs.size() == 1 && "Single register is expected here");
- // When Def is physreg: use given input.
+ // We need the tied input to live in the same register class as the def.
+ //
+ // - if Def is a vreg, we can just use its regclass.
+ // - if Def is a physreg, create a vreg in the minimal regclass for that
+ // physreg.
+ //
+ // Otherwise RegBankSelect may leave it in the wrong bank (e.g. GPR even
+ // though it's tied to an FP physreg).
Register In = SrcRegs[0];
- // When Def is vreg: copy input to new vreg with same reg class as Def.
+ const TargetRegisterClass *RC;
+
if (Def.isVirtual()) {
- In = MRI->createVirtualRegister(MRI->getRegClass(Def));
- if (!buildAnyextOrCopy(In, SrcRegs[0], MIRBuilder))
- return false;
+ RC = MRI->getRegClass(Def);
+ } else {
+ RC = TRI->getMinimalPhysRegClass(Def);
+ }
+
+ if (RC) {
+ // Materialize `In` in a new vreg if its register class does not match
+ // the register class of `Def`.
+ const TargetRegisterClass *InRC = MRI->getRegClassOrNull(In);
+ if (!InRC || InRC != RC) {
+ Register NewIn = MRI->createVirtualRegister(RC);
+ if (!buildAnyextOrCopy(NewIn, In, MIRBuilder))
+ return false;
+ In = NewIn;
+ }
}
// Add Flag and input register operand (In) to Inst. Tie In to Def.
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
index 2a490bc7d3d1c..74c60a1a3ecbd 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
@@ -269,8 +269,9 @@ define i16 @test_anyext_input_with_matching_constraint() {
define i64 @test_input_with_matching_constraint_to_physical_register() {
; CHECK-LABEL: name: test_input_with_matching_constraint_to_physical_register
; CHECK: bb.1 (%ir-block.0):
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
- ; CHECK-NEXT: INLINEASM &"", 0 /* attdialect */, 10 /* regdef */, implicit-def $x2, 2147483657 /* reguse tiedto:$0 */, [[C]](tied-def 3)(s64)
+ ; CHECK-NEXT: %0:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: %1:gpr64arg = COPY %0(s64)
+ ; CHECK-NEXT: INLINEASM &"", 0 /* attdialect */, 10 /* regdef */, implicit-def $x2, 2147483657 /* reguse tiedto:$0 */, %1(tied-def 3)
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x2
; CHECK-NEXT: $x0 = COPY [[COPY]](s64)
; CHECK-NEXT: RET_ReallyLR implicit $x0
diff --git a/llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll b/llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll
new file mode 100644
index 0000000000000..db75eb7d7686b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll
@@ -0,0 +1,29 @@
+; RUN: llc -mtriple=aarch64-unknown-linux-gnu -O0 < %s | FileCheck %s
+; RUN: llc -mtriple=aarch64-unknown-linux-gnu -O1 < %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+; regression test for https://github.com/llvm/llvm-project/issues/79822
+define i16 @test16(i16 %x) {
+; CHECK-LABEL: test16
+; CHECK: fmov s0, w0
+; CHECK: fmov w0, s0
+ %ret = call i16 asm "", "=&{h0},0"(i16 %x)
+ ret i16 %ret
+}
+
+define i32 @test32(i32 %x) {
+; CHECK-LABEL: test32
+; CHECK: fmov s0, w0
+; CHECK: fmov w0, s0
+ %ret = call i32 asm "", "=&{s0},0"(i32 %x)
+ ret i32 %ret
+}
+
+define i64 @test64(i64 %x) {
+; CHECK-LABEL: test64
+; CHECK: fmov d0, x0
+; CHECK: fmov x0, d0
+ %ret = call i64 asm "", "=&{d0},0"(i64 %x)
+ ret i64 %ret
+}
>From 940113bce9264c45564381dd884f0e4b5f5d71b6 Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert at folkertdev.nl>
Date: Thu, 22 Jan 2026 16:34:58 +0100
Subject: [PATCH 2/3] changes after code review
---
llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp | 10 +++-------
llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll | 4 ++--
2 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
index 940df8affe031..8f9fd9e64b8e9 100644
--- a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
@@ -417,13 +417,9 @@ bool InlineAsmLowering::lowerInlineAsm(
// Otherwise RegBankSelect may leave it in the wrong bank (e.g. GPR even
// though it's tied to an FP physreg).
Register In = SrcRegs[0];
- const TargetRegisterClass *RC;
-
- if (Def.isVirtual()) {
- RC = MRI->getRegClass(Def);
- } else {
- RC = TRI->getMinimalPhysRegClass(Def);
- }
+ const TargetRegisterClass *RC = Def.isVirtual()
+ ? MRI->getRegClass(Def)
+ : TRI->getMinimalPhysRegClass(Def);
if (RC) {
// Materialize `In` in a new vreg if its register class does not match
diff --git a/llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll b/llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll
index db75eb7d7686b..91fb07a0c6c83 100644
--- a/llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll
+++ b/llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll
@@ -1,5 +1,5 @@
-; RUN: llc -mtriple=aarch64-unknown-linux-gnu -O0 < %s | FileCheck %s
-; RUN: llc -mtriple=aarch64-unknown-linux-gnu -O1 < %s | FileCheck %s
+; RUN: llc -O0 < %s | FileCheck %s
+; RUN: llc -O1 < %s | FileCheck %s
target triple = "aarch64-unknown-linux-gnu"
>From f2d104406c581545deca7a42f434337eb4da3647 Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert at folkertdev.nl>
Date: Thu, 22 Jan 2026 20:04:19 +0100
Subject: [PATCH 3/3] changes after code review
---
.../CodeGen/GlobalISel/InlineAsmLowering.cpp | 17 +++++------
.../CodeGen/AArch64/GlobalISel/inline-asm.ll | 28 +++++++++++++++++-
.../CodeGen/AArch64/inlineasm-hreg-copy.ll | 29 -------------------
3 files changed, 34 insertions(+), 40 deletions(-)
delete mode 100644 llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll
diff --git a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
index 8f9fd9e64b8e9..e11c449ec1152 100644
--- a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
@@ -421,16 +421,13 @@ bool InlineAsmLowering::lowerInlineAsm(
? MRI->getRegClass(Def)
: TRI->getMinimalPhysRegClass(Def);
- if (RC) {
- // Materialize `In` in a new vreg if its register class does not match
- // the register class of `Def`.
- const TargetRegisterClass *InRC = MRI->getRegClassOrNull(In);
- if (!InRC || InRC != RC) {
- Register NewIn = MRI->createVirtualRegister(RC);
- if (!buildAnyextOrCopy(NewIn, In, MIRBuilder))
- return false;
- In = NewIn;
- }
+ // Materialize `In` in a new vreg if its register class does not match
+ // the register class of `Def`.
+ if (MRI->getRegClassOrNull(In) != RC) {
+ Register NewIn = MRI->createVirtualRegister(RC);
+ if (!buildAnyextOrCopy(NewIn, In, MIRBuilder))
+ return false;
+ In = NewIn;
}
// Add Flag and input register operand (In) to Inst. Tie In to Def.
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/inline-asm.ll b/llvm/test/CodeGen/AArch64/GlobalISel/inline-asm.ll
index 8ff7c4495dccb..1a54ccde533c2 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/inline-asm.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/inline-asm.ll
@@ -1,4 +1,5 @@
-; RUN: llc -mtriple=aarch64 -global-isel -global-isel-abort=2 %s -o - | FileCheck %s
+; RUN: llc -mtriple=aarch64 -global-isel -global-isel-abort=2 -O0 %s -o - | FileCheck %s
+; RUN: llc -mtriple=aarch64 -global-isel -global-isel-abort=2 -O1 %s -o - | FileCheck %s
; CHECK-LABEL: test_asm:
; CHECK: {{APP|InlineAsm Start}}
@@ -8,3 +9,28 @@ define void @test_asm() {
call void asm sideeffect "mov x0, $0", "r"(i64 42)
ret void
}
+
+; regression test for https://github.com/llvm/llvm-project/issues/79822
+define i16 @test_16bit_reg(i16 %x) {
+; CHECK-LABEL: test_16bit_reg
+; CHECK: fmov s0, w0
+; CHECK: fmov w0, s0
+ %ret = call i16 asm "", "=&{h0},0"(i16 %x)
+ ret i16 %ret
+}
+
+define i32 @test_32bit_reg(i32 %x) {
+; CHECK-LABEL: test_32bit_reg
+; CHECK: fmov s0, w0
+; CHECK: fmov w0, s0
+ %ret = call i32 asm "", "=&{s0},0"(i32 %x)
+ ret i32 %ret
+}
+
+define i64 @test_64bit_reg(i64 %x) {
+; CHECK-LABEL: test_64bit_reg
+; CHECK: fmov d0, x0
+; CHECK: fmov x0, d0
+ %ret = call i64 asm "", "=&{d0},0"(i64 %x)
+ ret i64 %ret
+}
diff --git a/llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll b/llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll
deleted file mode 100644
index 91fb07a0c6c83..0000000000000
--- a/llvm/test/CodeGen/AArch64/inlineasm-hreg-copy.ll
+++ /dev/null
@@ -1,29 +0,0 @@
-; RUN: llc -O0 < %s | FileCheck %s
-; RUN: llc -O1 < %s | FileCheck %s
-
-target triple = "aarch64-unknown-linux-gnu"
-
-; regression test for https://github.com/llvm/llvm-project/issues/79822
-define i16 @test16(i16 %x) {
-; CHECK-LABEL: test16
-; CHECK: fmov s0, w0
-; CHECK: fmov w0, s0
- %ret = call i16 asm "", "=&{h0},0"(i16 %x)
- ret i16 %ret
-}
-
-define i32 @test32(i32 %x) {
-; CHECK-LABEL: test32
-; CHECK: fmov s0, w0
-; CHECK: fmov w0, s0
- %ret = call i32 asm "", "=&{s0},0"(i32 %x)
- ret i32 %ret
-}
-
-define i64 @test64(i64 %x) {
-; CHECK-LABEL: test64
-; CHECK: fmov d0, x0
-; CHECK: fmov x0, d0
- %ret = call i64 asm "", "=&{d0},0"(i64 %x)
- ret i64 %ret
-}
More information about the llvm-commits
mailing list