[clang] [llvm] [RISCV][llvm] Support fixed-length vector inline assembly constraints (PR #150724)
Brandon Wu via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 25 16:51:37 PDT 2025
https://github.com/4vtomat created https://github.com/llvm/llvm-project/pull/150724
None
>From 689addb5c3aeffeac70abc69af0ac3b6b48439b8 Mon Sep 17 00:00:00 2001
From: Brandon Wu <songwu0813 at gmail.com>
Date: Fri, 25 Jul 2025 16:49:54 -0700
Subject: [PATCH] [RISCV][llvm] Support fixed-length vector inline assembly
constraints
---
.../riscv-inline-asm-fixed-length-vector.c | 39 +++++++++++++++++++
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 34 +++++++++++++++-
2 files changed, 71 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CodeGen/RISCV/riscv-inline-asm-fixed-length-vector.c
diff --git a/clang/test/CodeGen/RISCV/riscv-inline-asm-fixed-length-vector.c b/clang/test/CodeGen/RISCV/riscv-inline-asm-fixed-length-vector.c
new file mode 100644
index 0000000000000..0bfd9d6f158c6
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-inline-asm-fixed-length-vector.c
@@ -0,0 +1,39 @@
+// REQUIRES: riscv-registered-target
+
+// RUN: %clang_cc1 -triple riscv32 -target-feature +v \
+// RUN: -mvscale-min=2 -mvscale-max=2 -O2 -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -triple riscv64 -target-feature +v \
+// RUN: -mvscale-min=2 -mvscale-max=2 -O2 -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+
+// Test RISC-V V-extension fixed-length vector inline assembly constraints.
+#include <riscv_vector.h>
+
+typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
+typedef vint32m1_t fixed_i32m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
+typedef vint8mf2_t fixed_i8mf2_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 2)));
+
+fixed_i32m1_t test_vr(fixed_i32m1_t a) {
+// CHECK-LABEL: define{{.*}} @test_vr
+// CHECK: %0 = tail call <4 x i32> asm sideeffect "vadd.vv $0, $1, $2", "=^vr,^vr,^vr"(<4 x i32> %a, <4 x i32> %a)
+ fixed_i32m1_t ret;
+ asm volatile ("vadd.vv %0, %1, %2" : "=vr"(ret) : "vr"(a), "vr"(a));
+ return ret;
+}
+
+fixed_i8mf2_t test_vd(fixed_i8mf2_t a) {
+// CHECK-LABEL: define{{.*}} @test_vd
+// CHECK: %0 = tail call <8 x i8> asm sideeffect "vadd.vv $0, $1, $2", "=^vd,^vr,^vr"(<8 x i8> %a, <8 x i8> %a)
+ fixed_i8mf2_t ret;
+ asm volatile ("vadd.vv %0, %1, %2" : "=vd"(ret) : "vr"(a), "vr"(a));
+ return ret;
+}
+
+fixed_bool1_t test_vm(fixed_bool1_t a) {
+// CHECK-LABEL: define{{.*}} @test_vm
+// CHECK: %1 = tail call <16 x i8> asm sideeffect "vmand.mm $0, $1, $2", "=^vm,^vm,^vm"(<16 x i8> %a, <16 x i8> %a)
+ fixed_bool1_t ret;
+ asm volatile ("vmand.mm %0, %1, %2" : "=vm"(ret) : "vm"(a), "vm"(a));
+ return ret;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 809fbc8926e35..53550e69e4c6d 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -23133,6 +23133,12 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
&RISCV::VRN2M4RegClass}) {
if (TRI->isTypeLegalForClass(*RC, VT.SimpleTy))
return std::make_pair(0U, RC);
+
+ if (VT.isFixedLengthVector() && Subtarget.useRVVForFixedLengthVectors()) {
+ MVT ContainerVT = getContainerForFixedLengthVector(VT);
+ if (TRI->isTypeLegalForClass(*RC, ContainerVT))
+ return std::make_pair(0U, RC);
+ }
}
} else if (Constraint == "vd") {
for (const auto *RC :
@@ -23146,10 +23152,24 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
&RISCV::VRN2M4NoV0RegClass}) {
if (TRI->isTypeLegalForClass(*RC, VT.SimpleTy))
return std::make_pair(0U, RC);
+
+ if (VT.isFixedLengthVector() && Subtarget.useRVVForFixedLengthVectors()) {
+ MVT ContainerVT = getContainerForFixedLengthVector(VT);
+ if (TRI->isTypeLegalForClass(*RC, ContainerVT))
+ return std::make_pair(0U, RC);
+ }
}
} else if (Constraint == "vm") {
if (TRI->isTypeLegalForClass(RISCV::VMV0RegClass, VT.SimpleTy))
return std::make_pair(0U, &RISCV::VMV0RegClass);
+
+ if (VT.isFixedLengthVector() && Subtarget.useRVVForFixedLengthVectors()) {
+ MVT ContainerVT = getContainerForFixedLengthVector(VT);
+ // VT here is coerced to vector with i8 elements, so we need to check if
+ // this is a M1 register here instead of checking VMV0RegClass.
+ if (TRI->isTypeLegalForClass(RISCV::VRRegClass, ContainerVT))
+ return std::make_pair(0U, &RISCV::VMV0RegClass);
+ }
} else if (Constraint == "cr") {
if (VT == MVT::f16 && Subtarget.hasStdExtZhinxmin())
return std::make_pair(0U, &RISCV::GPRF16CRegClass);
@@ -24027,7 +24047,12 @@ bool RISCVTargetLowering::splitValueIntoRegisterParts(
return true;
}
- if (ValueVT.isScalableVector() && PartVT.isScalableVector()) {
+ if ((ValueVT.isScalableVector() || ValueVT.isFixedLengthVector()) &&
+ PartVT.isScalableVector()) {
+ if (ValueVT.isFixedLengthVector()) {
+ ValueVT = getContainerForFixedLengthVector(ValueVT.getSimpleVT());
+ Val = convertToScalableVector(ValueVT, Val, DAG, Subtarget);
+ }
LLVMContext &Context = *DAG.getContext();
EVT ValueEltVT = ValueVT.getVectorElementType();
EVT PartEltVT = PartVT.getVectorElementType();
@@ -24097,12 +24122,17 @@ SDValue RISCVTargetLowering::joinRegisterPartsIntoValue(
return Val;
}
- if (ValueVT.isScalableVector() && PartVT.isScalableVector()) {
+ if ((ValueVT.isScalableVector() || ValueVT.isFixedLengthVector()) &&
+ PartVT.isScalableVector()) {
LLVMContext &Context = *DAG.getContext();
SDValue Val = Parts[0];
EVT ValueEltVT = ValueVT.getVectorElementType();
EVT PartEltVT = PartVT.getVectorElementType();
unsigned ValueVTBitSize = ValueVT.getSizeInBits().getKnownMinValue();
+ if (ValueVT.isFixedLengthVector())
+ ValueVTBitSize = getContainerForFixedLengthVector(ValueVT.getSimpleVT())
+ .getSizeInBits()
+ .getKnownMinValue();
unsigned PartVTBitSize = PartVT.getSizeInBits().getKnownMinValue();
if (PartVTBitSize % ValueVTBitSize == 0) {
assert(PartVTBitSize >= ValueVTBitSize);
More information about the llvm-commits
mailing list