Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions clang/test/CodeGen/RISCV/riscv-inline-asm-fixed-length-vector.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// 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>
#include <stdbool.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)));

typedef bool bx2 __attribute__((ext_vector_type(16)));
typedef int i32x2 __attribute__((ext_vector_type(2)));
typedef char i8x4 __attribute__((ext_vector_type(4)));

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;
}

i32x2 test_vr2(i32x2 a) {
// CHECK-LABEL: define{{.*}} @test_vr2
// CHECK: %1 = tail call <2 x i32> asm sideeffect "vadd.vv $0, $1, $2", "=^vr,^vr,^vr"(<2 x i32> %0, <2 x i32> %0)
i32x2 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;
}

i8x4 test_vd2(i8x4 a) {
// CHECK-LABEL: define{{.*}} @test_vd2
// CHECK: %1 = tail call <4 x i8> asm sideeffect "vadd.vv $0, $1, $2", "=^vd,^vr,^vr"(<4 x i8> %0, <4 x i8> %0)
i8x4 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;
}

void test_vm2(bx2 a) {
// CHECK-LABEL: define{{.*}} @test_vm2
// CHECK: tail call void asm sideeffect "dummy $0", "^vm"(<16 x i1> %a1)
asm volatile ("dummy %0" :: "vm"(a));
}
39 changes: 36 additions & 3 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23408,6 +23408,12 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
&RISCV::VRN2M4RegClass}) {
if (TRI->isTypeLegalForClass(*RC, VT.SimpleTy))
return std::make_pair(0U, RC);

if (VT.isFixedLengthVector() && useRVVForFixedLengthVectorVT(VT)) {
MVT ContainerVT = getContainerForFixedLengthVector(VT);
if (TRI->isTypeLegalForClass(*RC, ContainerVT))
return std::make_pair(0U, RC);
}
}
} else if (Constraint == "vd") {
for (const auto *RC :
Expand All @@ -23421,10 +23427,24 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
&RISCV::VRN2M4NoV0RegClass}) {
if (TRI->isTypeLegalForClass(*RC, VT.SimpleTy))
return std::make_pair(0U, RC);

if (VT.isFixedLengthVector() && useRVVForFixedLengthVectorVT(VT)) {
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() && useRVVForFixedLengthVectorVT(VT)) {
MVT ContainerVT = getContainerForFixedLengthVector(VT);
// VT here might be 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);
Expand Down Expand Up @@ -24302,7 +24322,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();
Expand Down Expand Up @@ -24372,12 +24397,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);
Expand All @@ -24395,7 +24425,10 @@ SDValue RISCVTargetLowering::joinRegisterPartsIntoValue(
EVT::getVectorVT(Context, ValueEltVT, Count, /*IsScalable=*/true);
Val = DAG.getNode(ISD::BITCAST, DL, SameEltTypeVT, Val);
}
Val = DAG.getExtractSubvector(DL, ValueVT, Val, 0);
if (ValueVT.isFixedLengthVector())
Val = convertFromScalableVector(ValueVT, Val, DAG, Subtarget);
else
Val = DAG.getExtractSubvector(DL, ValueVT, Val, 0);
return Val;
}
}
Expand Down
68 changes: 68 additions & 0 deletions llvm/test/CodeGen/RISCV/inline-asm-fixed-v-constraint.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+v -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32I %s
; RUN: llc -mtriple=riscv64 -mattr=+v -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV64I %s

define <1 x i8> @constraint_vr_fixed(<1 x i8> %0, <1 x i8> %1) nounwind {
; RV32I-LABEL: constraint_vr_fixed:
; RV32I: # %bb.0:
; RV32I-NEXT: #APP
; RV32I-NEXT: vadd.vv v8, v8, v9
; RV32I-NEXT: #NO_APP
; RV32I-NEXT: ret
;
; RV64I-LABEL: constraint_vr_fixed:
; RV64I: # %bb.0:
; RV64I-NEXT: #APP
; RV64I-NEXT: vadd.vv v8, v8, v9
; RV64I-NEXT: #NO_APP
; RV64I-NEXT: ret
%a = tail call <1 x i8> asm "vadd.vv $0, $1, $2", "=^vr,^vr,^vr"(
<1 x i8> %0, <1 x i8> %1)
ret <1 x i8> %a
}

define <4 x i32> @constraint_vd_fixed(<4 x i32> %0, <4 x i32> %1) nounwind {
; RV32I-LABEL: constraint_vd_fixed:
; RV32I: # %bb.0:
; RV32I-NEXT: #APP
; RV32I-NEXT: vadd.vv v8, v8, v9
; RV32I-NEXT: #NO_APP
; RV32I-NEXT: ret
;
; RV64I-LABEL: constraint_vd_fixed:
; RV64I: # %bb.0:
; RV64I-NEXT: #APP
; RV64I-NEXT: vadd.vv v8, v8, v9
; RV64I-NEXT: #NO_APP
; RV64I-NEXT: ret
%a = tail call <4 x i32> asm "vadd.vv $0, $1, $2", "=^vd,^vr,^vr"(
<4 x i32> %0, <4 x i32> %1)
ret <4 x i32> %a
}

define <16 x i1> @constraint_vm_fixed(<16 x i1> %0, <16 x i1> %1) nounwind {
; RV32I-LABEL: constraint_vm_fixed:
; RV32I: # %bb.0:
; RV32I-NEXT: vsetivli zero, 1, e8, m1, ta, ma
; RV32I-NEXT: vmv1r.v v9, v0
; RV32I-NEXT: vmv1r.v v0, v8
; RV32I-NEXT: #APP
; RV32I-NEXT: vadd.vv v0, v9, v0
; RV32I-NEXT: #NO_APP
; RV32I-NEXT: ret
;
; RV64I-LABEL: constraint_vm_fixed:
; RV64I: # %bb.0:
; RV64I-NEXT: vsetivli zero, 1, e8, m1, ta, ma
; RV64I-NEXT: vmv1r.v v9, v0
; RV64I-NEXT: vmv1r.v v0, v8
; RV64I-NEXT: #APP
; RV64I-NEXT: vadd.vv v0, v9, v0
; RV64I-NEXT: #NO_APP
; RV64I-NEXT: ret
%a = tail call <16 x i1> asm "vadd.vv $0, $1, $2", "=^vr,^vr,^vm"(
<16 x i1> %0, <16 x i1> %1)
ret <16 x i1> %a
}