[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