[clang] [llvm] [LoongArch] Support i128 operands for LSX inline assembly (PR #211464)

via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 22 22:55:51 PDT 2026


https://github.com/heiher created https://github.com/llvm/llvm-project/pull/211464

Allow `i128` values to be used with the `f` inline assembly constraint when targeting LSX.

Although `i128` is not a legal LSX value type, it naturally maps to a single 128-bit LSX vector register for inline assembly. This enables instructions such as `vadd.q` to operate directly on `__int128` operands without requiring explicit vector types.

>From 8b45a363a2aea09568a34467ed3b9d96edca27aa Mon Sep 17 00:00:00 2001
From: WANG Rui <wangrui at loongson.cn>
Date: Thu, 9 Jul 2026 14:52:13 +0800
Subject: [PATCH] [LoongArch] Support i128 operands for LSX inline assembly

Allow `i128` values to be used with the `f` inline assembly constraint when
targeting LSX.

Although `i128` is not a legal LSX value type, it naturally maps to a single
128-bit LSX vector register for inline assembly. This enables instructions
such as `vadd.q` to operate directly on `__int128` operands without requiring
explicit vector types.
---
 .../LoongArch/lsx/inline-asm-operand-types.c  | 15 +++++++++++++
 .../LoongArch/LoongArchISelLowering.cpp       |  2 ++
 .../LoongArch/lsx/inline-asm-operand-types.ll | 21 +++++++++++++++++++
 3 files changed, 38 insertions(+)
 create mode 100644 clang/test/CodeGen/LoongArch/lsx/inline-asm-operand-types.c
 create mode 100644 llvm/test/CodeGen/LoongArch/lsx/inline-asm-operand-types.ll

diff --git a/clang/test/CodeGen/LoongArch/lsx/inline-asm-operand-types.c b/clang/test/CodeGen/LoongArch/lsx/inline-asm-operand-types.c
new file mode 100644
index 0000000000000..6fdf1a8eac255
--- /dev/null
+++ b/clang/test/CodeGen/LoongArch/lsx/inline-asm-operand-types.c
@@ -0,0 +1,15 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
+// RUN: %clang_cc1 -triple loongarch64 -emit-llvm -O2 %s -o - | FileCheck %s
+
+// CHECK-LABEL: define dso_local void @test_i128
+// CHECK-SAME: (ptr nofree noundef readonly captures(none) [[A:%.*]], ptr nofree noundef readonly captures(none) [[B:%.*]], ptr nofree noundef writeonly captures(none) initializes((0, 16)) [[R:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i128, ptr [[A]], align 16, !tbaa [[TBAA6:![0-9]+]]
+// CHECK-NEXT:    [[TMP1:%.*]] = load i128, ptr [[B]], align 16, !tbaa [[TBAA6]]
+// CHECK-NEXT:    [[TMP2:%.*]] = tail call i128 asm sideeffect "vadd.q ${0:w}, ${1:w}, ${2:w}", "=f,f,f"(i128 [[TMP0]], i128 [[TMP1]]) #[[ATTR1:[0-9]+]], !srcloc [[META8:![0-9]+]]
+// CHECK-NEXT:    store i128 [[TMP2]], ptr [[R]], align 16, !tbaa [[TBAA6]]
+// CHECK-NEXT:    ret void
+//
+void test_i128(__int128 *a, __int128 *b, __int128 *r) {
+  asm volatile ("vadd.q %w0, %w1, %w2" : "=f" (*r) : "f" (*a), "f" (*b));
+}
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 4c5bb28a5e42f..409e23f292c93 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -11332,6 +11332,8 @@ LoongArchTargetLowering::getRegForInlineAsmConstraint(
       if (Subtarget.hasExtLSX() &&
           TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
         return std::make_pair(0U, &LoongArch::LSX128RegClass);
+      if (Subtarget.hasExtLSX() && VT == MVT::i128)
+        return std::make_pair(0U, &LoongArch::LSX128RegClass);
       if (Subtarget.hasExtLASX() &&
           TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
         return std::make_pair(0U, &LoongArch::LASX256RegClass);
diff --git a/llvm/test/CodeGen/LoongArch/lsx/inline-asm-operand-types.ll b/llvm/test/CodeGen/LoongArch/lsx/inline-asm-operand-types.ll
new file mode 100644
index 0000000000000..77081f0aaad7c
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lsx/inline-asm-operand-types.ll
@@ -0,0 +1,21 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc --mtriple=loongarch32 -mattr=+32s,+lsx < %s | FileCheck %s
+; RUN: llc --mtriple=loongarch64 -mattr=+lsx < %s | FileCheck %s
+
+define void @i128(ptr %a, ptr %b, ptr %r) nounwind {
+; CHECK-LABEL: i128:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vld $vr0, $a1, 0
+; CHECK-NEXT:    vld $vr1, $a0, 0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    vadd.q $vr2, $vr1, $vr0
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vst $vr2, $a2, 0
+; CHECK-NEXT:    ret
+entry:
+  %0 = load i128, ptr %a, align 16
+  %1 = load i128, ptr %b, align 16
+  %2 = tail call i128 asm sideeffect "vadd.q ${0:w}, ${1:w}, ${2:w}", "=&f,f,f"(i128 %0, i128 %1)
+  store i128 %2, ptr %r, align 16
+  ret void
+}



More information about the cfe-commits mailing list