[llvm] 21871bb - [RISCV] Add fractional LMUL register classes for inline assembly. (#171278)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 9 20:59:38 PST 2025
Author: Craig Topper
Date: 2025-12-09T20:59:33-08:00
New Revision: 21871bb650cde9386a4961329397ed36ba6bfe2b
URL: https://github.com/llvm/llvm-project/commit/21871bb650cde9386a4961329397ed36ba6bfe2b
DIFF: https://github.com/llvm/llvm-project/commit/21871bb650cde9386a4961329397ed36ba6bfe2b.diff
LOG: [RISCV] Add fractional LMUL register classes for inline assembly. (#171278)
Inline assembly uses the first type from the register class to
connect to the rest of SelectionDAG. By adding fractional LMUL
register classes, we can ensure that this type is the size of the
types we use for fractional LMUL in the rest of SelectionDAG.
This allows us to remove some of the handling we had in
splitValueIntoRegisterParts/joinRegisterPartsIntoValue. This code
was incorrectly handling v16i4 arguments/returns which should be
any_extend to v16i8 to match type legalization. Instead we widened
v16i4 -> v32i4 then bitcasted to v16i8. This merged pairs of i4
elements into an i8 element instead of keeping them as separate
elements that have been extended to i8.
This is an alternative to #171243.
Fixes #171141.
Added:
llvm/test/CodeGen/RISCV/rvv/pr171141.ll
Modified:
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
llvm/lib/Target/RISCV/RISCVRegisterInfo.td
llvm/test/CodeGen/RISCV/rvv/subregister-undef-early-clobber.mir
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 7cbb9c0da4874..f28772a74d433 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -24323,9 +24323,11 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
break;
}
} else if (Constraint == "vr") {
- // Check VM first so that mask types will use that instead of VR.
+ // Check VM and fractional LMUL first so that those types will use that
+ // class instead of VR.
for (const auto *RC :
- {&RISCV::VMRegClass, &RISCV::VRRegClass, &RISCV::VRM2RegClass,
+ {&RISCV::VMRegClass, &RISCV::VRMF8RegClass, &RISCV::VRMF4RegClass,
+ &RISCV::VRMF2RegClass, &RISCV::VRRegClass, &RISCV::VRM2RegClass,
&RISCV::VRM4RegClass, &RISCV::VRM8RegClass, &RISCV::VRN2M1RegClass,
&RISCV::VRN3M1RegClass, &RISCV::VRN4M1RegClass,
&RISCV::VRN5M1RegClass, &RISCV::VRN6M1RegClass,
@@ -24342,16 +24344,19 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
}
}
} else if (Constraint == "vd") {
- // Check VMNoV0 first so that mask types will use that instead of VRNoV0.
+ // Check VMNoV0 and fractional LMUL first so that those types will use that
+ // class instead of VRNoV0.
for (const auto *RC :
- {&RISCV::VMNoV0RegClass, &RISCV::VRNoV0RegClass,
- &RISCV::VRM2NoV0RegClass, &RISCV::VRM4NoV0RegClass,
- &RISCV::VRM8NoV0RegClass, &RISCV::VRN2M1NoV0RegClass,
- &RISCV::VRN3M1NoV0RegClass, &RISCV::VRN4M1NoV0RegClass,
- &RISCV::VRN5M1NoV0RegClass, &RISCV::VRN6M1NoV0RegClass,
- &RISCV::VRN7M1NoV0RegClass, &RISCV::VRN8M1NoV0RegClass,
- &RISCV::VRN2M2NoV0RegClass, &RISCV::VRN3M2NoV0RegClass,
- &RISCV::VRN4M2NoV0RegClass, &RISCV::VRN2M4NoV0RegClass}) {
+ {&RISCV::VMNoV0RegClass, &RISCV::VRMF8NoV0RegClass,
+ &RISCV::VRMF4NoV0RegClass, &RISCV::VRMF2NoV0RegClass,
+ &RISCV::VRNoV0RegClass, &RISCV::VRM2NoV0RegClass,
+ &RISCV::VRM4NoV0RegClass, &RISCV::VRM8NoV0RegClass,
+ &RISCV::VRN2M1NoV0RegClass, &RISCV::VRN3M1NoV0RegClass,
+ &RISCV::VRN4M1NoV0RegClass, &RISCV::VRN5M1NoV0RegClass,
+ &RISCV::VRN6M1NoV0RegClass, &RISCV::VRN7M1NoV0RegClass,
+ &RISCV::VRN8M1NoV0RegClass, &RISCV::VRN2M2NoV0RegClass,
+ &RISCV::VRN3M2NoV0RegClass, &RISCV::VRN4M2NoV0RegClass,
+ &RISCV::VRN2M4NoV0RegClass}) {
if (TRI->isTypeLegalForClass(*RC, VT.SimpleTy))
return std::make_pair(0U, RC);
@@ -25229,12 +25234,10 @@ bool RISCVTargetLowering::splitValueIntoRegisterParts(
return true;
}
- if ((ValueVT.isScalableVector() || ValueVT.isFixedLengthVector()) &&
- PartVT.isScalableVector()) {
- if (ValueVT.isFixedLengthVector()) {
- ValueVT = getContainerForFixedLengthVector(ValueVT.getSimpleVT());
- Val = convertToScalableVector(ValueVT, Val, DAG, Subtarget);
- }
+ if (ValueVT.isFixedLengthVector() && PartVT.isScalableVector()) {
+ ValueVT = getContainerForFixedLengthVector(ValueVT.getSimpleVT());
+ Val = convertToScalableVector(ValueVT, Val, DAG, Subtarget);
+
LLVMContext &Context = *DAG.getContext();
EVT ValueEltVT = ValueVT.getVectorElementType();
EVT PartEltVT = PartVT.getVectorElementType();
@@ -25304,17 +25307,17 @@ SDValue RISCVTargetLowering::joinRegisterPartsIntoValue(
return Val;
}
- if ((ValueVT.isScalableVector() || ValueVT.isFixedLengthVector()) &&
- PartVT.isScalableVector()) {
+ if (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 ValueVTBitSize =
+ getContainerForFixedLengthVector(ValueVT.getSimpleVT())
+ .getSizeInBits()
+ .getKnownMinValue();
+
unsigned PartVTBitSize = PartVT.getSizeInBits().getKnownMinValue();
if (PartVTBitSize % ValueVTBitSize == 0) {
assert(PartVTBitSize >= ValueVTBitSize);
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
index f354793eb0eac..e3657badfa9a4 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
@@ -766,6 +766,13 @@ class VReg<list<ValueType> regTypes, dag regList, int Vlmul, int nf = 1>
defvar VMaskVTs = [vbool1_t, vbool2_t, vbool4_t, vbool8_t, vbool16_t,
vbool32_t, vbool64_t];
+defvar VMF8VTs = [vint8mf8_t];
+
+defvar VMF4VTs = [vint8mf4_t, vint16mf4_t, vfloat16mf4_t, vbfloat16mf4_t];
+
+defvar VMF2VTs = [vint8mf2_t, vint16mf2_t, vint32mf2_t,
+ vfloat16mf2_t, vbfloat16mf2_t, vfloat32mf2_t];
+
defvar VM1VTs = [vint8m1_t, vint16m1_t, vint32m1_t, vint64m1_t,
vbfloat16m1_t, vfloat16m1_t, vfloat32m1_t,
vfloat64m1_t, vint8mf2_t, vint8mf4_t, vint8mf8_t,
@@ -809,11 +816,21 @@ def VRM8 : VReg<VM8VTs, (add V8M8, V16M8, V24M8, V0M8), 8>;
def VRM8NoV0 : VReg<VM8VTs, (sub VRM8, V0M8), 8>;
+// Fractional LMUL register classes for inline assembly.
+def VRMF8 : VReg<VMF8VTs, (add VR), 1>;
+def VRMF8NoV0 : VReg<VMF8VTs, (add VRNoV0), 1>;
+
+def VRMF4 : VReg<VMF4VTs, (add VR), 1>;
+def VRMF4NoV0 : VReg<VMF4VTs, (add VRNoV0), 1>;
+
+def VRMF2 : VReg<VMF2VTs, (add VR), 1>;
+def VRMF2NoV0 : VReg<VMF2VTs, (add VRNoV0), 1>;
+
def VMV0 : VReg<VMaskVTs, (add V0), 1>;
// The register class is added for inline assembly for vector mask types.
def VM : VReg<VMaskVTs, (add VR), 1>;
-def VMNoV0 : VReg<VMaskVTs, (sub VR, V0), 1>;
+def VMNoV0 : VReg<VMaskVTs, (add VRNoV0), 1>;
defvar VTupM1N2VTs = [riscv_nxv8i8x2, riscv_nxv4i8x2, riscv_nxv2i8x2, riscv_nxv1i8x2];
defvar VTupM1N3VTs = [riscv_nxv8i8x3, riscv_nxv4i8x3, riscv_nxv2i8x3, riscv_nxv1i8x3];
diff --git a/llvm/test/CodeGen/RISCV/rvv/pr171141.ll b/llvm/test/CodeGen/RISCV/rvv/pr171141.ll
new file mode 100644
index 0000000000000..5a0cb70d18b9a
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/pr171141.ll
@@ -0,0 +1,12 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=riscv64 -mattr=+v | FileCheck %s
+
+define <vscale x 16 x i4> @foo() {
+; CHECK-LABEL: foo:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: vsetvli a0, zero, e8, m2, ta, ma
+; CHECK-NEXT: vmv.v.i v8, 0
+; CHECK-NEXT: ret
+entry:
+ ret <vscale x 16 x i4> zeroinitializer
+}
diff --git a/llvm/test/CodeGen/RISCV/rvv/subregister-undef-early-clobber.mir b/llvm/test/CodeGen/RISCV/rvv/subregister-undef-early-clobber.mir
index 31d0996852b76..069799a47385d 100644
--- a/llvm/test/CodeGen/RISCV/rvv/subregister-undef-early-clobber.mir
+++ b/llvm/test/CodeGen/RISCV/rvv/subregister-undef-early-clobber.mir
@@ -55,7 +55,7 @@ body: |
; CHECK-NEXT: %pt2:vrm4 = IMPLICIT_DEF
; CHECK-NEXT: [[INIT_UNDEF:%[0-9]+]]:vrm2nov0 = INIT_UNDEF
; CHECK-NEXT: [[INSERT_SUBREG1:%[0-9]+]]:vrm4 = INSERT_SUBREG [[INSERT_SUBREG]], [[INIT_UNDEF]], %subreg.sub_vrm2_1
- ; CHECK-NEXT: [[INIT_UNDEF1:%[0-9]+]]:vr = INIT_UNDEF
+ ; CHECK-NEXT: [[INIT_UNDEF1:%[0-9]+]]:vrmf8 = INIT_UNDEF
; CHECK-NEXT: [[INSERT_SUBREG2:%[0-9]+]]:vrm4 = INSERT_SUBREG [[INSERT_SUBREG1]], [[INIT_UNDEF1]], %subreg.sub_vrm1_0
; CHECK-NEXT: early-clobber %6:vrm4 = PseudoVRGATHER_VI_M4 %pt2, killed [[INSERT_SUBREG2]], 0, 0, 5 /* e32 */, 0 /* tu, mu */, implicit $vl, implicit $vtype
; CHECK-NEXT: [[ADDI1:%[0-9]+]]:gpr = ADDI $x0, 0
@@ -284,7 +284,7 @@ body: |
; CHECK-NEXT: [[INSERT_SUBREG1:%[0-9]+]]:vrm8 = INSERT_SUBREG [[INSERT_SUBREG]], [[INIT_UNDEF]], %subreg.sub_vrm4_1
; CHECK-NEXT: [[INIT_UNDEF1:%[0-9]+]]:vrm2nov0 = INIT_UNDEF
; CHECK-NEXT: [[INSERT_SUBREG2:%[0-9]+]]:vrm8 = INSERT_SUBREG [[INSERT_SUBREG1]], [[INIT_UNDEF1]], %subreg.sub_vrm2_1
- ; CHECK-NEXT: [[INIT_UNDEF2:%[0-9]+]]:vr = INIT_UNDEF
+ ; CHECK-NEXT: [[INIT_UNDEF2:%[0-9]+]]:vrmf8 = INIT_UNDEF
; CHECK-NEXT: [[INSERT_SUBREG3:%[0-9]+]]:vrm8 = INSERT_SUBREG [[INSERT_SUBREG2]], [[INIT_UNDEF2]], %subreg.sub_vrm1_0
; CHECK-NEXT: early-clobber %6:vrm8 = PseudoVRGATHER_VI_M8 %pt2, killed [[INSERT_SUBREG3]], 0, 0, 5 /* e32 */, 0 /* tu, mu */, implicit $vl, implicit $vtype
; CHECK-NEXT: [[ADDI1:%[0-9]+]]:gpr = ADDI $x0, 0
More information about the llvm-commits
mailing list