Skip to content
Merged
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
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
@@ -975,6 +975,8 @@ RISC-V Support
- Default ABI with F but without D was changed to ilp32f for RV32 and to lp64f
for RV64.

- ``__attribute__((rvv_vector_bits(N))) is now supported for RVV vbool*_t types.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line breaks the documentation build (missing ending ``).


CUDA/HIP Language Changes
^^^^^^^^^^^^^^^^^^^^^^^^^

3 changes: 3 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
@@ -3492,6 +3492,9 @@ enum class VectorKind {

/// is RISC-V RVV fixed-length data vector
RVVFixedLengthData,

/// is RISC-V RVV fixed-length mask vector
RVVFixedLengthMask,
};

/// Represents a GCC generic vector type. This type is created using
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
@@ -2415,7 +2415,10 @@ only be a power of 2 between 64 and 65536.
For types where LMUL!=1, ``__riscv_v_fixed_vlen`` needs to be scaled by the LMUL
of the type before passing to the attribute.

``vbool*_t`` types are not supported at this time.
For ``vbool*_t`` types, ``__riscv_v_fixed_vlen`` needs to be divided by the
number from the type name. For example, ``vbool8_t`` needs to use
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__riscv_v_fixed_vlen needs to be divided by the number from the type name.

Can this be done by compiler?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could, but the intention was that the value passed to the attribute should be the size of the type. That's the way LMUL is handled. LMUL 2 needs to pass 2*__riscv_v_fixed_vlen.

``__riscv_v_fixed_vlen`` / 8. If the resulting value is not a multiple of 8,
the type is not supported for that value of ``__riscv_v_fixed_vlen``.
}];
}

20 changes: 16 additions & 4 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
@@ -1938,7 +1938,8 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
else if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate)
// Adjust the alignment for fixed-length SVE predicates.
Align = 16;
else if (VT->getVectorKind() == VectorKind::RVVFixedLengthData)
else if (VT->getVectorKind() == VectorKind::RVVFixedLengthData ||
VT->getVectorKind() == VectorKind::RVVFixedLengthMask)
// Adjust the alignment for fixed-length RVV vectors.
Align = std::min<unsigned>(64, Width);
break;
@@ -9404,7 +9405,9 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
Second->getVectorKind() != VectorKind::SveFixedLengthData &&
Second->getVectorKind() != VectorKind::SveFixedLengthPredicate &&
First->getVectorKind() != VectorKind::RVVFixedLengthData &&
Second->getVectorKind() != VectorKind::RVVFixedLengthData)
Second->getVectorKind() != VectorKind::RVVFixedLengthData &&
First->getVectorKind() != VectorKind::RVVFixedLengthMask &&
Second->getVectorKind() != VectorKind::RVVFixedLengthMask)
return true;

return false;
@@ -9510,8 +9513,11 @@ static uint64_t getRVVTypeSize(ASTContext &Context, const BuiltinType *Ty) {

ASTContext::BuiltinVectorTypeInfo Info = Context.getBuiltinVectorTypeInfo(Ty);

uint64_t EltSize = Context.getTypeSize(Info.ElementType);
uint64_t MinElts = Info.EC.getKnownMinValue();
unsigned EltSize = Context.getTypeSize(Info.ElementType);
if (Info.ElementType == Context.BoolTy)
EltSize = 1;

unsigned MinElts = Info.EC.getKnownMinValue();
return VScale->first * MinElts * EltSize;
}

@@ -9525,6 +9531,12 @@ bool ASTContext::areCompatibleRVVTypes(QualType FirstType,
auto IsValidCast = [this](QualType FirstType, QualType SecondType) {
if (const auto *BT = FirstType->getAs<BuiltinType>()) {
if (const auto *VT = SecondType->getAs<VectorType>()) {
if (VT->getVectorKind() == VectorKind::RVVFixedLengthMask) {
BuiltinVectorTypeInfo Info = getBuiltinVectorTypeInfo(BT);
return FirstType->isRVVVLSBuiltinType() &&
Info.ElementType == BoolTy &&
getTypeSize(SecondType) == getRVVTypeSize(*this, BT);
}
if (VT->getVectorKind() == VectorKind::RVVFixedLengthData ||
VT->getVectorKind() == VectorKind::Generic)
return FirstType->isRVVVLSBuiltinType() &&
25 changes: 17 additions & 8 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
@@ -3994,7 +3994,8 @@ void CXXNameMangler::mangleAArch64FixedSveVectorType(
}

void CXXNameMangler::mangleRISCVFixedRVVVectorType(const VectorType *T) {
assert(T->getVectorKind() == VectorKind::RVVFixedLengthData &&
assert((T->getVectorKind() == VectorKind::RVVFixedLengthData ||
T->getVectorKind() == VectorKind::RVVFixedLengthMask) &&
"expected fixed-length RVV vector!");

QualType EltType = T->getElementType();
@@ -4009,7 +4010,10 @@ void CXXNameMangler::mangleRISCVFixedRVVVectorType(const VectorType *T) {
TypeNameOS << "int8";
break;
case BuiltinType::UChar:
TypeNameOS << "uint8";
if (T->getVectorKind() == VectorKind::RVVFixedLengthData)
TypeNameOS << "uint8";
else
TypeNameOS << "bool";
break;
case BuiltinType::Short:
TypeNameOS << "int16";
@@ -4048,12 +4052,16 @@ void CXXNameMangler::mangleRISCVFixedRVVVectorType(const VectorType *T) {
auto VScale = getASTContext().getTargetInfo().getVScaleRange(
getASTContext().getLangOpts());
unsigned VLen = VScale->first * llvm::RISCV::RVVBitsPerBlock;
TypeNameOS << 'm';
if (VecSizeInBits >= VLen)
TypeNameOS << (VecSizeInBits / VLen);
else
TypeNameOS << 'f' << (VLen / VecSizeInBits);

if (T->getVectorKind() == VectorKind::RVVFixedLengthData) {
TypeNameOS << 'm';
if (VecSizeInBits >= VLen)
TypeNameOS << (VecSizeInBits / VLen);
else
TypeNameOS << 'f' << (VLen / VecSizeInBits);
} else {
TypeNameOS << (VLen / VecSizeInBits);
}
TypeNameOS << "_t";

Out << "9__RVV_VLSI" << 'u' << TypeNameStr.size() << TypeNameStr << "Lj"
@@ -4093,7 +4101,8 @@ void CXXNameMangler::mangleType(const VectorType *T) {
T->getVectorKind() == VectorKind::SveFixedLengthPredicate) {
mangleAArch64FixedSveVectorType(T);
return;
} else if (T->getVectorKind() == VectorKind::RVVFixedLengthData) {
} else if (T->getVectorKind() == VectorKind::RVVFixedLengthData ||
T->getVectorKind() == VectorKind::RVVFixedLengthMask) {
mangleRISCVFixedRVVVectorType(T);
return;
}
3 changes: 3 additions & 0 deletions clang/lib/AST/JSONNodeDumper.cpp
Original file line number Diff line number Diff line change
@@ -703,6 +703,9 @@ void JSONNodeDumper::VisitVectorType(const VectorType *VT) {
case VectorKind::RVVFixedLengthData:
JOS.attribute("vectorKind", "fixed-length rvv data vector");
break;
case VectorKind::RVVFixedLengthMask:
JOS.attribute("vectorKind", "fixed-length rvv mask vector");
break;
}
}

3 changes: 3 additions & 0 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
@@ -1613,6 +1613,9 @@ void TextNodeDumper::VisitVectorType(const VectorType *T) {
case VectorKind::RVVFixedLengthData:
OS << " fixed-length rvv data vector";
break;
case VectorKind::RVVFixedLengthMask:
OS << " fixed-length rvv mask vector";
break;
}
OS << " " << T->getNumElements();
}
15 changes: 14 additions & 1 deletion clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
@@ -2479,6 +2479,9 @@ bool Type::isRVVVLSBuiltinType() const {
IsFP, IsBF) \
case BuiltinType::Id: \
return NF == 1;
#define RVV_PREDICATE_TYPE(Name, Id, SingletonId, NumEls) \
case BuiltinType::Id: \
return true;
#include "clang/Basic/RISCVVTypes.def"
default:
return false;
@@ -2491,7 +2494,17 @@ QualType Type::getRVVEltType(const ASTContext &Ctx) const {
assert(isRVVVLSBuiltinType() && "unsupported type!");

const BuiltinType *BTy = castAs<BuiltinType>();
return Ctx.getBuiltinVectorTypeInfo(BTy).ElementType;

switch (BTy->getKind()) {
#define RVV_PREDICATE_TYPE(Name, Id, SingletonId, NumEls) \
case BuiltinType::Id: \
return Ctx.UnsignedCharTy;
default:
return Ctx.getBuiltinVectorTypeInfo(BTy).ElementType;
#include "clang/Basic/RISCVVTypes.def"
}

llvm_unreachable("Unhandled type");
}

bool QualType::isPODType(const ASTContext &Context) const {
2 changes: 2 additions & 0 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
@@ -694,6 +694,7 @@ void TypePrinter::printVectorBefore(const VectorType *T, raw_ostream &OS) {
printBefore(T->getElementType(), OS);
break;
case VectorKind::RVVFixedLengthData:
case VectorKind::RVVFixedLengthMask:
// FIXME: We prefer to print the size directly here, but have no way
// to get the size of the type.
OS << "__attribute__((__riscv_rvv_vector_bits__(";
@@ -773,6 +774,7 @@ void TypePrinter::printDependentVectorBefore(
printBefore(T->getElementType(), OS);
break;
case VectorKind::RVVFixedLengthData:
case VectorKind::RVVFixedLengthMask:
// FIXME: We prefer to print the size directly here, but have no way
// to get the size of the type.
OS << "__attribute__((__riscv_rvv_vector_bits__(";
21 changes: 15 additions & 6 deletions clang/lib/CodeGen/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
@@ -318,20 +318,28 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty) const {
assert(Ty->isVectorType() && "expected vector type!");

const auto *VT = Ty->castAs<VectorType>();
assert(VT->getVectorKind() == VectorKind::RVVFixedLengthData &&
"Unexpected vector kind");

assert(VT->getElementType()->isBuiltinType() && "expected builtin type!");

auto VScale =
getContext().getTargetInfo().getVScaleRange(getContext().getLangOpts());

unsigned NumElts = VT->getNumElements();
llvm::Type *EltType;
if (VT->getVectorKind() == VectorKind::RVVFixedLengthMask) {
NumElts *= 8;
EltType = llvm::Type::getInt1Ty(getVMContext());
} else {
assert(VT->getVectorKind() == VectorKind::RVVFixedLengthData &&
"Unexpected vector kind");
EltType = CGT.ConvertType(VT->getElementType());
}

// The MinNumElts is simplified from equation:
// NumElts / VScale =
// (EltSize * NumElts / (VScale * RVVBitsPerBlock))
// * (RVVBitsPerBlock / EltSize)
llvm::ScalableVectorType *ResType =
llvm::ScalableVectorType::get(CGT.ConvertType(VT->getElementType()),
VT->getNumElements() / VScale->first);
llvm::ScalableVectorType::get(EltType, NumElts / VScale->first);
return ABIArgInfo::getDirect(ResType);
}

@@ -431,7 +439,8 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
}

if (const VectorType *VT = Ty->getAs<VectorType>())
if (VT->getVectorKind() == VectorKind::RVVFixedLengthData)
if (VT->getVectorKind() == VectorKind::RVVFixedLengthData ||
VT->getVectorKind() == VectorKind::RVVFixedLengthMask)
return coerceVLSVector(Ty);

// Aggregates which are <= 2*XLen will be passed in registers if possible,
6 changes: 4 additions & 2 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
@@ -11167,7 +11167,8 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
if (VecType->getVectorKind() == VectorKind::SveFixedLengthData ||
VecType->getVectorKind() == VectorKind::SveFixedLengthPredicate)
return true;
if (VecType->getVectorKind() == VectorKind::RVVFixedLengthData) {
if (VecType->getVectorKind() == VectorKind::RVVFixedLengthData ||
VecType->getVectorKind() == VectorKind::RVVFixedLengthMask) {
SVEorRVV = 1;
return true;
}
@@ -11198,7 +11199,8 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
SecondVecType->getVectorKind() ==
VectorKind::SveFixedLengthPredicate)
return true;
if (SecondVecType->getVectorKind() == VectorKind::RVVFixedLengthData) {
if (SecondVecType->getVectorKind() == VectorKind::RVVFixedLengthData ||
SecondVecType->getVectorKind() == VectorKind::RVVFixedLengthMask) {
SVEorRVV = 1;
return true;
}
21 changes: 15 additions & 6 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
@@ -8542,21 +8542,30 @@ static void HandleRISCVRVVVectorBitsTypeAttr(QualType &CurType,

ASTContext::BuiltinVectorTypeInfo Info =
S.Context.getBuiltinVectorTypeInfo(CurType->castAs<BuiltinType>());
unsigned EltSize = S.Context.getTypeSize(Info.ElementType);
unsigned MinElts = Info.EC.getKnownMinValue();

VectorKind VecKind = VectorKind::RVVFixedLengthData;
unsigned ExpectedSize = VScale->first * MinElts;
QualType EltType = CurType->getRVVEltType(S.Context);
unsigned EltSize = S.Context.getTypeSize(EltType);
unsigned NumElts;
if (Info.ElementType == S.Context.BoolTy) {
NumElts = VecSize / S.Context.getCharWidth();
VecKind = VectorKind::RVVFixedLengthMask;
} else {
ExpectedSize *= EltSize;
NumElts = VecSize / EltSize;
}

// The attribute vector size must match -mrvv-vector-bits.
unsigned ExpectedSize = VScale->first * MinElts * EltSize;
if (VecSize != ExpectedSize) {
if (ExpectedSize % 8 != 0 || VecSize != ExpectedSize) {
S.Diag(Attr.getLoc(), diag::err_attribute_bad_rvv_vector_size)
<< VecSize << ExpectedSize;
Attr.setInvalid();
return;
}

VectorKind VecKind = VectorKind::RVVFixedLengthData;
VecSize /= EltSize;
CurType = S.Context.getVectorType(Info.ElementType, VecSize, VecKind);
CurType = S.Context.getVectorType(EltType, NumElts, VecKind);
}

/// Handle OpenCL Access Qualifier Attribute.
100 changes: 100 additions & 0 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-bitcast.c
Original file line number Diff line number Diff line change
@@ -18,8 +18,29 @@ typedef __rvv_uint64m1_t vuint64m1_t;
typedef __rvv_float32m1_t vfloat32m1_t;
typedef __rvv_float64m1_t vfloat64m1_t;

typedef __rvv_bool1_t vbool1_t;
typedef __rvv_bool2_t vbool2_t;
typedef __rvv_bool4_t vbool4_t;
typedef __rvv_bool8_t vbool8_t;
typedef __rvv_bool16_t vbool16_t;
typedef __rvv_bool32_t vbool32_t;
typedef __rvv_bool64_t vbool64_t;

typedef vint64m1_t fixed_int64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vfloat64m1_t fixed_float64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool2_t fixed_bool2_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 2)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 4)));
typedef vbool8_t fixed_bool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 8)));
#if __riscv_v_fixed_vlen >= 128
typedef vbool16_t fixed_bool16_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 16)));
#endif
#if __riscv_v_fixed_vlen >= 256
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 32)));
#endif
#if __riscv_v_fixed_vlen >= 512
typedef vbool64_t fixed_bool64_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 64)));
#endif

#define DEFINE_STRUCT(ty) \
struct struct_##ty { \
@@ -28,6 +49,19 @@ typedef vfloat64m1_t fixed_float64m1_t __attribute__((riscv_rvv_vector_bits(__ri

DEFINE_STRUCT(int64m1)
DEFINE_STRUCT(float64m1)
DEFINE_STRUCT(bool1)
DEFINE_STRUCT(bool2)
DEFINE_STRUCT(bool4)
DEFINE_STRUCT(bool8)
#if __riscv_v_fixed_vlen >= 128
DEFINE_STRUCT(bool16)
#endif
#if __riscv_v_fixed_vlen >= 256
DEFINE_STRUCT(bool32)
#endif
#if __riscv_v_fixed_vlen >= 512
DEFINE_STRUCT(bool64)
#endif

//===----------------------------------------------------------------------===//
// int64
@@ -136,3 +170,69 @@ vfloat64m1_t read_float64m1(struct struct_float64m1 *s) {
void write_float64m1(struct struct_float64m1 *s, vfloat64m1_t x) {
s->y[0] = x;
}

//===----------------------------------------------------------------------===//
// bool
//===----------------------------------------------------------------------===//

// CHECK-64-LABEL: @read_bool1(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[SAVED_VALUE:%.*]] = alloca <8 x i8>, align 8
// CHECK-64-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-64-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: store <8 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
// CHECK-128-LABEL: @read_bool1(
// CHECK-128-NEXT: entry:
// CHECK-128-NEXT: [[SAVED_VALUE:%.*]] = alloca <16 x i8>, align 16
// CHECK-128-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-128-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-128-NEXT: store <16 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 16, !tbaa [[TBAA4]]
// CHECK-128-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 16, !tbaa [[TBAA4]]
// CHECK-128-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
// CHECK-256-LABEL: @read_bool1(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <32 x i8>, align 32
// CHECK-256-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-256-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: store <32 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 32, !tbaa [[TBAA4]]
// CHECK-256-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 32, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
vbool1_t read_bool1(struct struct_bool1 *s) {
return s->y[0];
}

// CHECK-64-LABEL: @write_bool1(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-64-NEXT: store <vscale x 64 x i1> [[X:%.*]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA7:![0-9]+]]
// CHECK-64-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-64-NEXT: store <8 x i8> [[TMP0]], ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: ret void
//
// CHECK-128-LABEL: @write_bool1(
// CHECK-128-NEXT: entry:
// CHECK-128-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 16
// CHECK-128-NEXT: store <vscale x 64 x i1> [[X:%.*]], ptr [[SAVED_VALUE]], align 16, !tbaa [[TBAA7:![0-9]+]]
// CHECK-128-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[SAVED_VALUE]], align 16, !tbaa [[TBAA4]]
// CHECK-128-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-128-NEXT: store <16 x i8> [[TMP0]], ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-128-NEXT: ret void
//
// CHECK-256-LABEL: @write_bool1(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-256-NEXT: store <vscale x 64 x i1> [[X:%.*]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA7:![0-9]+]]
// CHECK-256-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-256-NEXT: store <32 x i8> [[TMP0]], ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret void
//
void write_bool1(struct struct_bool1 *s, vbool1_t x) {
s->y[0] = x;
}
74 changes: 74 additions & 0 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-call.c
Original file line number Diff line number Diff line change
@@ -7,6 +7,8 @@

typedef vint32m1_t fixed_int32m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vfloat64m1_t fixed_float64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/4)));

//===----------------------------------------------------------------------===//
// Test caller/callee with VLST <-> VLAT
@@ -66,6 +68,30 @@ fixed_float64m1_t call_float64_ff(fixed_float64m1_t op1, fixed_float64m1_t op2)
return __riscv_vfadd(op1, op2, __riscv_v_fixed_vlen/64);
}

// CHECK-LABEL: @call_bool1_ff(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[SAVED_VALUE4:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[TMP0:%.*]] = tail call <vscale x 64 x i1> @llvm.riscv.vmand.nxv64i1.i64(<vscale x 64 x i1> [[OP1_COERCE:%.*]], <vscale x 64 x i1> [[OP2_COERCE:%.*]], i64 256)
// CHECK-NEXT: store <vscale x 64 x i1> [[TMP0]], ptr [[SAVED_VALUE4]], align 8, !tbaa [[TBAA4:![0-9]+]]
// CHECK-NEXT: [[TMP1:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE4]], align 8, !tbaa [[TBAA8:![0-9]+]]
// CHECK-NEXT: store <32 x i8> [[TMP1]], ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 64 x i1>, ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: ret <vscale x 64 x i1> [[TMP2]]
//
fixed_bool1_t call_bool1_ff(fixed_bool1_t op1, fixed_bool1_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen);
}

// CHECK-LABEL: @call_bool4_ff(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP2:%.*]] = tail call <vscale x 16 x i1> @llvm.riscv.vmand.nxv16i1.i64(<vscale x 16 x i1> [[TMP0:%.*]], <vscale x 16 x i1> [[TMP1:%.*]], i64 64)
// CHECK-NEXT: ret <vscale x 16 x i1> [[TMP2]]
//
fixed_bool4_t call_bool4_ff(fixed_bool4_t op1, fixed_bool4_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen / 4);
}

//===----------------------------------------------------------------------===//
// fixed, scalable
//===----------------------------------------------------------------------===//
@@ -88,6 +114,30 @@ fixed_float64m1_t call_float64_fs(fixed_float64m1_t op1, vfloat64m1_t op2) {
return __riscv_vfadd(op1, op2, __riscv_v_fixed_vlen/64);
}

// CHECK-LABEL: @call_bool1_fs(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[SAVED_VALUE2:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[TMP0:%.*]] = tail call <vscale x 64 x i1> @llvm.riscv.vmand.nxv64i1.i64(<vscale x 64 x i1> [[OP1_COERCE:%.*]], <vscale x 64 x i1> [[OP2:%.*]], i64 256)
// CHECK-NEXT: store <vscale x 64 x i1> [[TMP0]], ptr [[SAVED_VALUE2]], align 8, !tbaa [[TBAA4]]
// CHECK-NEXT: [[TMP1:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE2]], align 8, !tbaa [[TBAA8]]
// CHECK-NEXT: store <32 x i8> [[TMP1]], ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 64 x i1>, ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: ret <vscale x 64 x i1> [[TMP2]]
//
fixed_bool1_t call_bool1_fs(fixed_bool1_t op1, vbool1_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen);
}

// CHECK-LABEL: @call_bool4_fs(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP1:%.*]] = tail call <vscale x 16 x i1> @llvm.riscv.vmand.nxv16i1.i64(<vscale x 16 x i1> [[TMP0:%.*]], <vscale x 16 x i1> [[OP2:%.*]], i64 64)
// CHECK-NEXT: ret <vscale x 16 x i1> [[TMP1]]
//
fixed_bool4_t call_bool4_fs(fixed_bool4_t op1, vbool4_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen / 4);
}

//===----------------------------------------------------------------------===//
// scalable, scalable
//===----------------------------------------------------------------------===//
@@ -109,3 +159,27 @@ fixed_int32m1_t call_int32_ss(vint32m1_t op1, vint32m1_t op2) {
fixed_float64m1_t call_float64_ss(vfloat64m1_t op1, vfloat64m1_t op2) {
return __riscv_vfadd(op1, op2, __riscv_v_fixed_vlen/64);
}

// CHECK-LABEL: @call_bool1_ss(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[TMP0:%.*]] = tail call <vscale x 64 x i1> @llvm.riscv.vmand.nxv64i1.i64(<vscale x 64 x i1> [[OP1:%.*]], <vscale x 64 x i1> [[OP2:%.*]], i64 256)
// CHECK-NEXT: store <vscale x 64 x i1> [[TMP0]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-NEXT: [[TMP1:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA8]]
// CHECK-NEXT: store <32 x i8> [[TMP1]], ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 64 x i1>, ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: ret <vscale x 64 x i1> [[TMP2]]
//
fixed_bool1_t call_bool1_ss(vbool1_t op1, vbool1_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen);
}

// CHECK-LABEL: @call_bool4_ss(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = tail call <vscale x 16 x i1> @llvm.riscv.vmand.nxv16i1.i64(<vscale x 16 x i1> [[OP1:%.*]], <vscale x 16 x i1> [[OP2:%.*]], i64 64)
// CHECK-NEXT: ret <vscale x 16 x i1> [[TMP0]]
//
fixed_bool4_t call_bool4_ss(vbool4_t op1, vbool4_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen / 4);
}
76 changes: 72 additions & 4 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-cast.c
Original file line number Diff line number Diff line change
@@ -16,13 +16,21 @@ typedef __rvv_uint64m1_t vuint64m1_t;
typedef __rvv_float32m1_t vfloat32m1_t;
typedef __rvv_float64m1_t vfloat64m1_t;

typedef __rvv_bool1_t vbool1_t;
typedef __rvv_bool4_t vbool4_t;
typedef __rvv_bool32_t vbool32_t;

typedef vint64m1_t fixed_int64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vfloat64m1_t fixed_float64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));

typedef vint32m1_t fixed_int32m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vfloat64m1_t fixed_float64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef int32_t gnu_int32m1_t __attribute__((vector_size(__riscv_v_fixed_vlen / 8)));

typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/4)));
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/32)));

// CHECK-LABEL: @to_vint32m1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <vscale x 2 x i32> [[TYPE_COERCE:%.*]]
@@ -55,9 +63,69 @@ fixed_float64m1_t from_vfloat64m1_t(vfloat64m1_t type) {
return type;
}

// CHECK-LABEL: @from_vbool1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: store <vscale x 64 x i1> [[TYPE:%.*]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4:![0-9]+]]
// CHECK-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA8:![0-9]+]]
// CHECK-NEXT: store <32 x i8> [[TMP0]], ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
fixed_bool1_t from_vbool1_t(vbool1_t type) {
return type;
}

// CHECK-LABEL: @to_vbool1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <vscale x 64 x i1> [[TYPE_COERCE:%.*]]
//
vbool1_t to_vbool1_t(fixed_bool1_t type) {
return type;
}

// CHECK-LABEL: @from_vbool4_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <vscale x 16 x i1> [[TYPE:%.*]]
//
fixed_bool4_t from_vbool4_t(vbool4_t type) {
return type;
}

// CHECK-LABEL: @to_vbool4_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <vscale x 16 x i1> [[TMP0:%.*]]
//
vbool4_t to_vbool4_t(fixed_bool4_t type) {
return type;
}

// CHECK-LABEL: @from_vbool32_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-NEXT: store <vscale x 2 x i1> [[TYPE:%.*]], ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA9:![0-9]+]]
// CHECK-NEXT: [[TMP0:%.*]] = load <1 x i8>, ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA8]]
// CHECK-NEXT: store <1 x i8> [[TMP0]], ptr [[RETVAL_COERCE]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load <vscale x 2 x i1>, ptr [[RETVAL_COERCE]], align 1
// CHECK-NEXT: ret <vscale x 2 x i1> [[TMP1]]
//
fixed_bool32_t from_vbool32_t(vbool32_t type) {
return type;
}

// CHECK-LABEL: @to_vbool32_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <vscale x 2 x i1> [[TYPE_COERCE:%.*]]
//
vbool32_t to_vbool32_t(fixed_bool32_t type) {
return type;
}

// CHECK-LABEL: @to_vint32m1_t__from_gnu_int32m1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TYPE:%.*]] = load <8 x i32>, ptr [[TMP0:%.*]], align 32, !tbaa [[TBAA4:![0-9]+]]
// CHECK-NEXT: [[TYPE:%.*]] = load <8 x i32>, ptr [[TMP0:%.*]], align 32, !tbaa [[TBAA8]]
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = tail call <vscale x 2 x i32> @llvm.vector.insert.nxv2i32.v8i32(<vscale x 2 x i32> undef, <8 x i32> [[TYPE]], i64 0)
// CHECK-NEXT: ret <vscale x 2 x i32> [[CAST_SCALABLE]]
//
@@ -68,7 +136,7 @@ vint32m1_t to_vint32m1_t__from_gnu_int32m1_t(gnu_int32m1_t type) {
// CHECK-LABEL: @from_vint32m1_t__to_gnu_int32m1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[CAST_FIXED:%.*]] = tail call <8 x i32> @llvm.vector.extract.v8i32.nxv2i32(<vscale x 2 x i32> [[TYPE:%.*]], i64 0)
// CHECK-NEXT: store <8 x i32> [[CAST_FIXED]], ptr [[AGG_RESULT:%.*]], align 32, !tbaa [[TBAA4]]
// CHECK-NEXT: store <8 x i32> [[CAST_FIXED]], ptr [[AGG_RESULT:%.*]], align 32, !tbaa [[TBAA8]]
// CHECK-NEXT: ret void
//
gnu_int32m1_t from_vint32m1_t__to_gnu_int32m1_t(vint32m1_t type) {
@@ -77,7 +145,7 @@ gnu_int32m1_t from_vint32m1_t__to_gnu_int32m1_t(vint32m1_t type) {

// CHECK-LABEL: @to_fixed_int32m1_t__from_gnu_int32m1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TYPE:%.*]] = load <8 x i32>, ptr [[TMP0:%.*]], align 32, !tbaa [[TBAA4]]
// CHECK-NEXT: [[TYPE:%.*]] = load <8 x i32>, ptr [[TMP0:%.*]], align 32, !tbaa [[TBAA8]]
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = tail call <vscale x 2 x i32> @llvm.vector.insert.nxv2i32.v8i32(<vscale x 2 x i32> undef, <8 x i32> [[TYPE]], i64 0)
// CHECK-NEXT: ret <vscale x 2 x i32> [[CAST_SCALABLE]]
//
@@ -88,7 +156,7 @@ fixed_int32m1_t to_fixed_int32m1_t__from_gnu_int32m1_t(gnu_int32m1_t type) {
// CHECK-LABEL: @from_fixed_int32m1_t__to_gnu_int32m1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TYPE:%.*]] = tail call <8 x i32> @llvm.vector.extract.v8i32.nxv2i32(<vscale x 2 x i32> [[TYPE_COERCE:%.*]], i64 0)
// CHECK-NEXT: store <8 x i32> [[TYPE]], ptr [[AGG_RESULT:%.*]], align 32, !tbaa [[TBAA4]]
// CHECK-NEXT: store <8 x i32> [[TYPE]], ptr [[AGG_RESULT:%.*]], align 32, !tbaa [[TBAA8]]
// CHECK-NEXT: ret void
//
gnu_int32m1_t from_fixed_int32m1_t__to_gnu_int32m1_t(fixed_int32m1_t type) {
172 changes: 172 additions & 0 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-codegen.c
Original file line number Diff line number Diff line change
@@ -27,11 +27,117 @@ typedef __rvv_uint64m2_t vuint64m2_t;
typedef __rvv_float32m2_t vfloat32m2_t;
typedef __rvv_float64m2_t vfloat64m2_t;

typedef __rvv_bool1_t vbool1_t;
typedef __rvv_bool4_t vbool4_t;
typedef __rvv_bool32_t vbool32_t;

typedef vint32m1_t fixed_int32m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vint32m2_t fixed_int32m2_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen * 2)));
typedef vint16m4_t fixed_int16m4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen * 4)));
typedef vint8m8_t fixed_int8m8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen * 8)));
typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/4)));
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/32)));

fixed_int32m1_t global_vec;
fixed_int32m2_t global_vec_m2;
fixed_int8m8_t global_vec_int8m8;
fixed_int16m4_t global_vec_int16m4;
fixed_bool1_t global_bool1;
fixed_bool4_t global_bool4;
fixed_bool32_t global_bool32;

// CHECK-LABEL: @test_bool1(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <256 x i8>, align 8
// CHECK-NEXT: [[M_ADDR:%.*]] = alloca <vscale x 64 x i1>, align 1
// CHECK-NEXT: [[VEC_ADDR:%.*]] = alloca <vscale x 64 x i8>, align 1
// CHECK-NEXT: [[MASK:%.*]] = alloca <vscale x 64 x i1>, align 1
// CHECK-NEXT: [[SAVED_VALUE:%.*]] = alloca <32 x i8>, align 32
// CHECK-NEXT: store <vscale x 64 x i1> [[M:%.*]], ptr [[M_ADDR]], align 1
// CHECK-NEXT: store <vscale x 64 x i8> [[VEC:%.*]], ptr [[VEC_ADDR]], align 1
// CHECK-NEXT: [[TMP0:%.*]] = load <vscale x 64 x i1>, ptr [[M_ADDR]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load <32 x i8>, ptr @global_bool1, align 8
// CHECK-NEXT: store <32 x i8> [[TMP1]], ptr [[SAVED_VALUE]], align 32
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 32
// CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 64 x i1> @llvm.riscv.vmand.nxv64i1.i64(<vscale x 64 x i1> [[TMP0]], <vscale x 64 x i1> [[TMP2]], i64 256)
// CHECK-NEXT: store <vscale x 64 x i1> [[TMP3]], ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP4:%.*]] = load <vscale x 64 x i1>, ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP5:%.*]] = load <vscale x 64 x i8>, ptr [[VEC_ADDR]], align 1
// CHECK-NEXT: [[TMP6:%.*]] = load <256 x i8>, ptr @global_vec_int8m8, align 8
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call <vscale x 64 x i8> @llvm.vector.insert.nxv64i8.v256i8(<vscale x 64 x i8> undef, <256 x i8> [[TMP6]], i64 0)
// CHECK-NEXT: [[TMP7:%.*]] = call <vscale x 64 x i8> @llvm.riscv.vadd.mask.nxv64i8.nxv64i8.i64(<vscale x 64 x i8> poison, <vscale x 64 x i8> [[TMP5]], <vscale x 64 x i8> [[CAST_SCALABLE]], <vscale x 64 x i1> [[TMP4]], i64 256, i64 3)
// CHECK-NEXT: [[CAST_FIXED:%.*]] = call <256 x i8> @llvm.vector.extract.v256i8.nxv64i8(<vscale x 64 x i8> [[TMP7]], i64 0)
// CHECK-NEXT: store <256 x i8> [[CAST_FIXED]], ptr [[RETVAL]], align 8
// CHECK-NEXT: [[TMP8:%.*]] = load <256 x i8>, ptr [[RETVAL]], align 8
// CHECK-NEXT: [[CAST_SCALABLE1:%.*]] = call <vscale x 64 x i8> @llvm.vector.insert.nxv64i8.v256i8(<vscale x 64 x i8> undef, <256 x i8> [[TMP8]], i64 0)
// CHECK-NEXT: ret <vscale x 64 x i8> [[CAST_SCALABLE1]]
//
fixed_int8m8_t test_bool1(vbool1_t m, vint8m8_t vec) {
vbool1_t mask = __riscv_vmand(m, global_bool1, __riscv_v_fixed_vlen);
return __riscv_vadd(mask, vec, global_vec_int8m8, __riscv_v_fixed_vlen);
}

// CHECK-LABEL: @test_bool4(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <64 x i16>, align 8
// CHECK-NEXT: [[M_ADDR:%.*]] = alloca <vscale x 16 x i1>, align 1
// CHECK-NEXT: [[VEC_ADDR:%.*]] = alloca <vscale x 16 x i16>, align 2
// CHECK-NEXT: [[MASK:%.*]] = alloca <vscale x 16 x i1>, align 1
// CHECK-NEXT: store <vscale x 16 x i1> [[M:%.*]], ptr [[M_ADDR]], align 1
// CHECK-NEXT: store <vscale x 16 x i16> [[VEC:%.*]], ptr [[VEC_ADDR]], align 2
// CHECK-NEXT: [[TMP0:%.*]] = load <vscale x 16 x i1>, ptr [[M_ADDR]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i8>, ptr @global_bool4, align 8
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call <vscale x 2 x i8> @llvm.vector.insert.nxv2i8.v8i8(<vscale x 2 x i8> undef, <8 x i8> [[TMP1]], i64 0)
// CHECK-NEXT: [[TMP2:%.*]] = bitcast <vscale x 2 x i8> [[CAST_SCALABLE]] to <vscale x 16 x i1>
// CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i1> @llvm.riscv.vmand.nxv16i1.i64(<vscale x 16 x i1> [[TMP0]], <vscale x 16 x i1> [[TMP2]], i64 64)
// CHECK-NEXT: store <vscale x 16 x i1> [[TMP3]], ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP4:%.*]] = load <vscale x 16 x i1>, ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP5:%.*]] = load <vscale x 16 x i16>, ptr [[VEC_ADDR]], align 2
// CHECK-NEXT: [[TMP6:%.*]] = load <64 x i16>, ptr @global_vec_int16m4, align 8
// CHECK-NEXT: [[CAST_SCALABLE1:%.*]] = call <vscale x 16 x i16> @llvm.vector.insert.nxv16i16.v64i16(<vscale x 16 x i16> undef, <64 x i16> [[TMP6]], i64 0)
// CHECK-NEXT: [[TMP7:%.*]] = call <vscale x 16 x i16> @llvm.riscv.vadd.mask.nxv16i16.nxv16i16.i64(<vscale x 16 x i16> poison, <vscale x 16 x i16> [[TMP5]], <vscale x 16 x i16> [[CAST_SCALABLE1]], <vscale x 16 x i1> [[TMP4]], i64 64, i64 3)
// CHECK-NEXT: [[CAST_FIXED:%.*]] = call <64 x i16> @llvm.vector.extract.v64i16.nxv16i16(<vscale x 16 x i16> [[TMP7]], i64 0)
// CHECK-NEXT: store <64 x i16> [[CAST_FIXED]], ptr [[RETVAL]], align 8
// CHECK-NEXT: [[TMP8:%.*]] = load <64 x i16>, ptr [[RETVAL]], align 8
// CHECK-NEXT: [[CAST_SCALABLE2:%.*]] = call <vscale x 16 x i16> @llvm.vector.insert.nxv16i16.v64i16(<vscale x 16 x i16> undef, <64 x i16> [[TMP8]], i64 0)
// CHECK-NEXT: ret <vscale x 16 x i16> [[CAST_SCALABLE2]]
//
fixed_int16m4_t test_bool4(vbool4_t m, vint16m4_t vec) {
vbool4_t mask = __riscv_vmand(m, global_bool4, __riscv_v_fixed_vlen/4);
return __riscv_vadd(mask, vec, global_vec_int16m4, __riscv_v_fixed_vlen/4);
}

// CHECK-LABEL: @test_bool32(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <8 x i32>, align 8
// CHECK-NEXT: [[M_ADDR:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-NEXT: [[VEC_ADDR:%.*]] = alloca <vscale x 2 x i32>, align 4
// CHECK-NEXT: [[MASK:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-NEXT: [[SAVED_VALUE:%.*]] = alloca <1 x i8>, align 1
// CHECK-NEXT: store <vscale x 2 x i1> [[M:%.*]], ptr [[M_ADDR]], align 1
// CHECK-NEXT: store <vscale x 2 x i32> [[VEC:%.*]], ptr [[VEC_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load <vscale x 2 x i1>, ptr [[M_ADDR]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load <1 x i8>, ptr @global_bool32, align 1
// CHECK-NEXT: store <1 x i8> [[TMP1]], ptr [[SAVED_VALUE]], align 1
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 2 x i1>, ptr [[SAVED_VALUE]], align 1
// CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 2 x i1> @llvm.riscv.vmand.nxv2i1.i64(<vscale x 2 x i1> [[TMP0]], <vscale x 2 x i1> [[TMP2]], i64 8)
// CHECK-NEXT: store <vscale x 2 x i1> [[TMP3]], ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP4:%.*]] = load <vscale x 2 x i1>, ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP5:%.*]] = load <vscale x 2 x i32>, ptr [[VEC_ADDR]], align 4
// CHECK-NEXT: [[TMP6:%.*]] = load <8 x i32>, ptr @global_vec, align 8
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call <vscale x 2 x i32> @llvm.vector.insert.nxv2i32.v8i32(<vscale x 2 x i32> undef, <8 x i32> [[TMP6]], i64 0)
// CHECK-NEXT: [[TMP7:%.*]] = call <vscale x 2 x i32> @llvm.riscv.vadd.mask.nxv2i32.nxv2i32.i64(<vscale x 2 x i32> poison, <vscale x 2 x i32> [[TMP5]], <vscale x 2 x i32> [[CAST_SCALABLE]], <vscale x 2 x i1> [[TMP4]], i64 8, i64 3)
// CHECK-NEXT: [[CAST_FIXED:%.*]] = call <8 x i32> @llvm.vector.extract.v8i32.nxv2i32(<vscale x 2 x i32> [[TMP7]], i64 0)
// CHECK-NEXT: store <8 x i32> [[CAST_FIXED]], ptr [[RETVAL]], align 8
// CHECK-NEXT: [[TMP8:%.*]] = load <8 x i32>, ptr [[RETVAL]], align 8
// CHECK-NEXT: [[CAST_SCALABLE1:%.*]] = call <vscale x 2 x i32> @llvm.vector.insert.nxv2i32.v8i32(<vscale x 2 x i32> undef, <8 x i32> [[TMP8]], i64 0)
// CHECK-NEXT: ret <vscale x 2 x i32> [[CAST_SCALABLE1]]
//
fixed_int32m1_t test_bool32(vbool32_t m, vint32m1_t vec) {
vbool32_t mask = __riscv_vmand(m, global_bool32, __riscv_v_fixed_vlen/32);
return __riscv_vadd(mask, vec, global_vec, __riscv_v_fixed_vlen/32);
}

// CHECK-LABEL: @test_ptr_to_global(
// CHECK-NEXT: entry:
@@ -70,6 +176,72 @@ fixed_int32m1_t array_arg(fixed_int32m1_t arr[]) {
return arr[0];
}

// CHECK-LABEL: @address_of_array_idx_bool1(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <32 x i8>, align 8
// CHECK-NEXT: [[ARR:%.*]] = alloca [3 x <32 x i8>], align 8
// CHECK-NEXT: [[PARR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x <32 x i8>], ptr [[ARR]], i64 0, i64 0
// CHECK-NEXT: store ptr [[ARRAYIDX]], ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = load <32 x i8>, ptr [[TMP0]], align 8
// CHECK-NEXT: store <32 x i8> [[TMP1]], ptr [[RETVAL]], align 8
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL_COERCE]], ptr align 8 [[RETVAL]], i64 32, i1 false)
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 64 x i1>, ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: ret <vscale x 64 x i1> [[TMP2]]
//
fixed_bool1_t address_of_array_idx_bool1() {
fixed_bool1_t arr[3];
fixed_bool1_t *parr;
parr = &arr[0];
return *parr;
}

// CHECK-LABEL: @address_of_array_idx_bool4(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <8 x i8>, align 8
// CHECK-NEXT: [[ARR:%.*]] = alloca [3 x <8 x i8>], align 8
// CHECK-NEXT: [[PARR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x <8 x i8>], ptr [[ARR]], i64 0, i64 0
// CHECK-NEXT: store ptr [[ARRAYIDX]], ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i8>, ptr [[TMP0]], align 8
// CHECK-NEXT: store <8 x i8> [[TMP1]], ptr [[RETVAL]], align 8
// CHECK-NEXT: [[TMP2:%.*]] = load <8 x i8>, ptr [[RETVAL]], align 8
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call <vscale x 2 x i8> @llvm.vector.insert.nxv2i8.v8i8(<vscale x 2 x i8> undef, <8 x i8> [[TMP2]], i64 0)
// CHECK-NEXT: [[TMP3:%.*]] = bitcast <vscale x 2 x i8> [[CAST_SCALABLE]] to <vscale x 16 x i1>
// CHECK-NEXT: ret <vscale x 16 x i1> [[TMP3]]
//
fixed_bool4_t address_of_array_idx_bool4() {
fixed_bool4_t arr[3];
fixed_bool4_t *parr;
parr = &arr[0];
return *parr;
}

// CHECK-LABEL: @address_of_array_idx_bool32(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <1 x i8>, align 1
// CHECK-NEXT: [[ARR:%.*]] = alloca [3 x <1 x i8>], align 1
// CHECK-NEXT: [[PARR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x <1 x i8>], ptr [[ARR]], i64 0, i64 0
// CHECK-NEXT: store ptr [[ARRAYIDX]], ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = load <1 x i8>, ptr [[TMP0]], align 1
// CHECK-NEXT: store <1 x i8> [[TMP1]], ptr [[RETVAL]], align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[RETVAL_COERCE]], ptr align 1 [[RETVAL]], i64 1, i1 false)
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 2 x i1>, ptr [[RETVAL_COERCE]], align 1
// CHECK-NEXT: ret <vscale x 2 x i1> [[TMP2]]
//
fixed_bool32_t address_of_array_idx_bool32() {
fixed_bool32_t arr[3];
fixed_bool32_t *parr;
parr = &arr[0];
return *parr;
}

// CHECK-LABEL: @test_cast(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <8 x i32>, align 8
107 changes: 107 additions & 0 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-globals.c
Original file line number Diff line number Diff line change
@@ -17,10 +17,25 @@ typedef __rvv_uint64m1_t vuint64m1_t;
typedef __rvv_float32m1_t vfloat32m1_t;
typedef __rvv_float64m1_t vfloat64m1_t;

typedef __rvv_bool1_t vbool1_t;
typedef __rvv_bool4_t vbool4_t;
typedef __rvv_bool32_t vbool32_t;

typedef vint64m1_t fixed_int64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/4)));
#if __riscv_v_fixed_vlen >= 256
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/32)));
#endif

fixed_int64m1_t global_i64;

fixed_bool1_t global_bool1;
fixed_bool4_t global_bool4;
#if __riscv_v_fixed_vlen >= 256
fixed_bool32_t global_bool32;
#endif

//===----------------------------------------------------------------------===//
// WRITES
//===----------------------------------------------------------------------===//
@@ -39,6 +54,52 @@ fixed_int64m1_t global_i64;
//
void write_global_i64(vint64m1_t v) { global_i64 = v; }

// CHECK-64-LABEL: @write_global_bool1(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-64-NEXT: store <vscale x 64 x i1> [[V:%.*]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA7:![0-9]+]]
// CHECK-64-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: store <8 x i8> [[TMP0]], ptr @global_bool1, align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: ret void
//
// CHECK-256-LABEL: @write_global_bool1(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-256-NEXT: store <vscale x 64 x i1> [[V:%.*]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA7:![0-9]+]]
// CHECK-256-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: store <32 x i8> [[TMP0]], ptr @global_bool1, align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret void
//
void write_global_bool1(vbool1_t v) { global_bool1 = v; }

// CHECK-64-LABEL: @write_global_bool4(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[TMP0:%.*]] = bitcast <vscale x 16 x i1> [[V:%.*]] to <vscale x 2 x i8>
// CHECK-64-NEXT: [[CAST_FIXED:%.*]] = tail call <2 x i8> @llvm.vector.extract.v2i8.nxv2i8(<vscale x 2 x i8> [[TMP0]], i64 0)
// CHECK-64-NEXT: store <2 x i8> [[CAST_FIXED]], ptr @global_bool4, align 2, !tbaa [[TBAA4]]
// CHECK-64-NEXT: ret void
//
// CHECK-256-LABEL: @write_global_bool4(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[TMP0:%.*]] = bitcast <vscale x 16 x i1> [[V:%.*]] to <vscale x 2 x i8>
// CHECK-256-NEXT: [[CAST_FIXED:%.*]] = tail call <8 x i8> @llvm.vector.extract.v8i8.nxv2i8(<vscale x 2 x i8> [[TMP0]], i64 0)
// CHECK-256-NEXT: store <8 x i8> [[CAST_FIXED]], ptr @global_bool4, align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret void
//
void write_global_bool4(vbool4_t v) { global_bool4 = v; }

#if __riscv_v_fixed_vlen >= 256
// CHECK-256-LABEL: @write_global_bool32(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-256-NEXT: store <vscale x 2 x i1> [[V:%.*]], ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA9:![0-9]+]]
// CHECK-256-NEXT: [[TMP0:%.*]] = load <1 x i8>, ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA4]]
// CHECK-256-NEXT: store <1 x i8> [[TMP0]], ptr @global_bool32, align 1, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret void
//
void write_global_bool32(vbool32_t v) { global_bool32 = v; }
#endif

//===----------------------------------------------------------------------===//
// READS
//===----------------------------------------------------------------------===//
@@ -56,3 +117,49 @@ void write_global_i64(vint64m1_t v) { global_i64 = v; }
// CHECK-256-NEXT: ret <vscale x 1 x i64> [[CAST_SCALABLE]]
//
vint64m1_t read_global_i64() { return global_i64; }

// CHECK-64-LABEL: @read_global_bool1(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[SAVED_VALUE:%.*]] = alloca <8 x i8>, align 8
// CHECK-64-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr @global_bool1, align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: store <8 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
// CHECK-256-LABEL: @read_global_bool1(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <32 x i8>, align 32
// CHECK-256-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr @global_bool1, align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: store <32 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 32, !tbaa [[TBAA4]]
// CHECK-256-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 32, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
vbool1_t read_global_bool1() { return global_bool1; }

// CHECK-64-LABEL: @read_global_bool4(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[TMP0:%.*]] = load <2 x i8>, ptr @global_bool4, align 2, !tbaa [[TBAA4]]
// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call <vscale x 2 x i8> @llvm.vector.insert.nxv2i8.v2i8(<vscale x 2 x i8> undef, <2 x i8> [[TMP0]], i64 0)
// CHECK-64-NEXT: [[TMP1:%.*]] = bitcast <vscale x 2 x i8> [[CAST_SCALABLE]] to <vscale x 16 x i1>
// CHECK-64-NEXT: ret <vscale x 16 x i1> [[TMP1]]
//
// CHECK-256-LABEL: @read_global_bool4(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr @global_bool4, align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call <vscale x 2 x i8> @llvm.vector.insert.nxv2i8.v8i8(<vscale x 2 x i8> undef, <8 x i8> [[TMP0]], i64 0)
// CHECK-256-NEXT: [[TMP1:%.*]] = bitcast <vscale x 2 x i8> [[CAST_SCALABLE]] to <vscale x 16 x i1>
// CHECK-256-NEXT: ret <vscale x 16 x i1> [[TMP1]]
//
vbool4_t read_global_bool4() { return global_bool4; }

#if __riscv_v_fixed_vlen >= 256
// CHECK-256-LABEL: @read_global_bool32(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <1 x i8>, align 1
// CHECK-256-NEXT: [[TMP0:%.*]] = load <1 x i8>, ptr @global_bool32, align 1, !tbaa [[TBAA4]]
// CHECK-256-NEXT: store <1 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA4]]
// CHECK-256-NEXT: [[TMP1:%.*]] = load <vscale x 2 x i1>, ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret <vscale x 2 x i1> [[TMP1]]
//
vbool32_t read_global_bool32() { return global_bool32; }
#endif
284 changes: 284 additions & 0 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-types.c

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions clang/test/CodeGenCXX/riscv-mangle-rvv-fixed-vectors.cpp
Original file line number Diff line number Diff line change
@@ -85,6 +85,14 @@ typedef __rvv_float16m8_t vfloat16m8_t;
typedef __rvv_float32m8_t vfloat32m8_t;
typedef __rvv_float64m8_t vfloat64m8_t;

typedef __rvv_bool1_t vbool1_t;
typedef __rvv_bool2_t vbool2_t;
typedef __rvv_bool4_t vbool4_t;
typedef __rvv_bool8_t vbool8_t;
typedef __rvv_bool16_t vbool16_t;
typedef __rvv_bool32_t vbool32_t;
typedef __rvv_bool64_t vbool64_t;

typedef vint8mf8_t fixed_int8mf8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8)));

typedef vuint8mf8_t fixed_uint8mf8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8)));
@@ -164,6 +172,20 @@ typedef vfloat16m8_t fixed_float16m8_t __attribute__((riscv_rvv_vector_bits(__ri
typedef vfloat32m8_t fixed_float32m8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen*8)));
typedef vfloat64m8_t fixed_float64m8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen*8)));

typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool2_t fixed_bool2_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/2)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/4)));
typedef vbool8_t fixed_bool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8)));
#if __riscv_v_fixed_vlen >= 128
typedef vbool16_t fixed_bool16_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/16)));
#endif
#if __riscv_v_fixed_vlen >= 256
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/32)));
#endif
#if __riscv_v_fixed_vlen >= 512
typedef vbool64_t fixed_bool64_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/64)));
#endif

template <typename T> struct S {};

// CHECK-64: _Z2f11SI9__RVV_VLSIu14__rvv_int8m1_tLj64EEE
@@ -578,3 +600,53 @@ void mf8f1(S<fixed_int8mf8_t>) {}
// CHECK-512: _Z5mf8f51SI9__RVV_VLSIu16__rvv_uint8mf8_tLj64EEE
// CHECK-1024: _Z5mf8f51SI9__RVV_VLSIu16__rvv_uint8mf8_tLj128EEE
void mf8f5(S<fixed_uint8mf8_t>) {}

// CHECK-64: _Z5bool11SI9__RVV_VLSIu13__rvv_bool1_tLj64EEE
// CHECK-128: _Z5bool11SI9__RVV_VLSIu13__rvv_bool1_tLj128EEE
// CHECK-256: _Z5bool11SI9__RVV_VLSIu13__rvv_bool1_tLj256EEE
// CHECK-512: _Z5bool11SI9__RVV_VLSIu13__rvv_bool1_tLj512EEE
// CHECK-1024: _Z5bool11SI9__RVV_VLSIu13__rvv_bool1_tLj1024EEE
void bool1(S<fixed_bool1_t>) {}

// CHECK-64: _Z5bool21SI9__RVV_VLSIu13__rvv_bool2_tLj32EEE
// CHECK-128: _Z5bool21SI9__RVV_VLSIu13__rvv_bool2_tLj64EEE
// CHECK-256: _Z5bool21SI9__RVV_VLSIu13__rvv_bool2_tLj128EEE
// CHECK-512: _Z5bool21SI9__RVV_VLSIu13__rvv_bool2_tLj256EEE
// CHECK-1024: _Z5bool21SI9__RVV_VLSIu13__rvv_bool2_tLj512EEE
void bool2(S<fixed_bool2_t>) {}

// CHECK-64: _Z5bool41SI9__RVV_VLSIu13__rvv_bool4_tLj16EEE
// CHECK-128: _Z5bool41SI9__RVV_VLSIu13__rvv_bool4_tLj32EEE
// CHECK-256: _Z5bool41SI9__RVV_VLSIu13__rvv_bool4_tLj64EEE
// CHECK-512: _Z5bool41SI9__RVV_VLSIu13__rvv_bool4_tLj128EEE
// CHECK-1024: _Z5bool41SI9__RVV_VLSIu13__rvv_bool4_tLj256EEE
void bool4(S<fixed_bool4_t>) {}

// CHECK-64: _Z5bool81SI9__RVV_VLSIu13__rvv_bool8_tLj8EEE
// CHECK-128: _Z5bool81SI9__RVV_VLSIu13__rvv_bool8_tLj16EEE
// CHECK-256: _Z5bool81SI9__RVV_VLSIu13__rvv_bool8_tLj32EEE
// CHECK-512: _Z5bool81SI9__RVV_VLSIu13__rvv_bool8_tLj64EEE
// CHECK-1024: _Z5bool81SI9__RVV_VLSIu13__rvv_bool8_tLj128EEE
void bool8(S<fixed_bool8_t>) {}

#if __riscv_v_fixed_vlen >= 128
// CHECK-128: _Z6bool161SI9__RVV_VLSIu14__rvv_bool16_tLj8EEE
// CHECK-256: _Z6bool161SI9__RVV_VLSIu14__rvv_bool16_tLj16EEE
// CHECK-512: _Z6bool161SI9__RVV_VLSIu14__rvv_bool16_tLj32EEE
// CHECK-1024: _Z6bool161SI9__RVV_VLSIu14__rvv_bool16_tLj64EEE
//
void bool16(S<fixed_bool16_t>) {}
#endif

#if __riscv_v_fixed_vlen >= 256
// CHECK-256: _Z6bool321SI9__RVV_VLSIu14__rvv_bool32_tLj8EEE
// CHECK-512: _Z6bool321SI9__RVV_VLSIu14__rvv_bool32_tLj16EEE
// CHECK-1024: _Z6bool321SI9__RVV_VLSIu14__rvv_bool32_tLj32EEE
void bool32(S<fixed_bool32_t>) {}
#endif

#if __riscv_v_fixed_vlen >= 512
// CHECK-512: _Z6bool641SI9__RVV_VLSIu14__rvv_bool64_tLj8EEE
// CHECK-1024: _Z6bool641SI9__RVV_VLSIu14__rvv_bool64_tLj16EEE
void bool64(S<fixed_bool64_t>) {}
#endif
88 changes: 86 additions & 2 deletions clang/test/Sema/attr-riscv-rvv-vector-bits.c
Original file line number Diff line number Diff line change
@@ -228,8 +228,19 @@ typedef vint8m1_t two_arguments __attribute__((riscv_rvv_vector_bits(2, 4))); //
typedef vint8m1_t non_int_size1 __attribute__((riscv_rvv_vector_bits(2.0))); // expected-error {{'riscv_rvv_vector_bits' attribute requires an integer constant}}
typedef vint8m1_t non_int_size2 __attribute__((riscv_rvv_vector_bits("256"))); // expected-error {{'riscv_rvv_vector_bits' attribute requires an integer constant}}

// bool types and LMUL != 1 are not supported.
typedef vbool1_t fixed_vbool1_t_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); // expected-error {{'riscv_rvv_vector_bits' attribute applied to non-RVV type 'vbool1_t'}}
typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool2_t fixed_bool2_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 2)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 4)));
typedef vbool8_t fixed_bool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 8)));
#if __riscv_v_fixed_vlen / 16 >= 8
typedef vbool16_t fixed_bool16_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 16)));
#endif
#if __riscv_v_fixed_vlen / 32 >= 8
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 32)));
#endif
#if __riscv_v_fixed_vlen / 64 >= 8
typedef vbool64_t fixed_bool64_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 64)));
#endif

// Attribute must be attached to a single RVV vector or predicate type.
typedef void *badtype1 __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); // expected-error {{'riscv_rvv_vector_bits' attribute applied to non-RVV type 'void *'}}
@@ -242,10 +253,13 @@ vint8m1_t non_typedef_type __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_
// Test that we can define non-local fixed-length RVV types (unsupported for
// sizeless types).
fixed_int8m1_t global_int8;
fixed_bool1_t global_bool1;

extern fixed_int8m1_t extern_int8;
extern fixed_bool1_t extern_bool1;

static fixed_int8m1_t static_int8;
static fixed_bool1_t static_bool1;

fixed_int8m1_t *global_int8_ptr;
extern fixed_int8m1_t *extern_int8_ptr;
@@ -398,6 +412,20 @@ _Static_assert(sizeof(fixed_int64m8_t) == VECTOR_SIZE * 8, "");
_Static_assert(sizeof(fixed_float32m8_t) == VECTOR_SIZE * 8, "");
_Static_assert(sizeof(fixed_float64m8_t) == VECTOR_SIZE * 8, "");

_Static_assert(sizeof(fixed_bool1_t) == VECTOR_SIZE, "");
_Static_assert(sizeof(fixed_bool2_t) == VECTOR_SIZE / 2, "");
_Static_assert(sizeof(fixed_bool4_t) == VECTOR_SIZE / 4, "");
_Static_assert(sizeof(fixed_bool8_t) == VECTOR_SIZE / 8, "");
#if __riscv_v_fixed_vlen / 16 >= 8
_Static_assert(sizeof(fixed_bool16_t) == VECTOR_SIZE / 16, "");
#endif
#if __riscv_v_fixed_vlen / 32 >= 8
_Static_assert(sizeof(fixed_bool32_t) == VECTOR_SIZE / 32, "");
#endif
#if __riscv_v_fixed_vlen / 64 >= 8
_Static_assert(sizeof(fixed_bool64_t) == VECTOR_SIZE / 64, "");
#endif

// --------------------------------------------------------------------------//
// Alignof

@@ -475,6 +503,20 @@ _Static_assert(__alignof__(fixed_uint64m8_t) == VECTOR_ALIGN, "");
_Static_assert(__alignof__(fixed_float32m8_t) == VECTOR_ALIGN, "");
_Static_assert(__alignof__(fixed_float64m8_t) == VECTOR_ALIGN, "");

_Static_assert(__alignof__(fixed_bool1_t) == VECTOR_ALIGN, "");
_Static_assert(__alignof__(fixed_bool2_t) == (sizeof(fixed_bool2_t) < VECTOR_ALIGN ? sizeof(fixed_bool2_t) : VECTOR_ALIGN), "");
_Static_assert(__alignof__(fixed_bool4_t) == (sizeof(fixed_bool4_t) < VECTOR_ALIGN ? sizeof(fixed_bool4_t) : VECTOR_ALIGN), "");
_Static_assert(__alignof__(fixed_bool8_t) == (sizeof(fixed_bool8_t) < VECTOR_ALIGN ? sizeof(fixed_bool8_t) : VECTOR_ALIGN), "");
#if __riscv_v_fixed_vlen / 16 >= 8
_Static_assert(__alignof__(fixed_bool16_t) == (sizeof(fixed_bool16_t) < VECTOR_ALIGN ? sizeof(fixed_bool16_t) : VECTOR_ALIGN), "");
#endif
#if __riscv_v_fixed_vlen / 32 >= 8
_Static_assert(__alignof__(fixed_bool32_t) == (sizeof(fixed_bool32_t) < VECTOR_ALIGN ? sizeof(fixed_bool32_t) : VECTOR_ALIGN), "");
#endif
#if __riscv_v_fixed_vlen / 64 >= 8
_Static_assert(__alignof__(fixed_bool64_t) == (sizeof(fixed_bool64_t) < VECTOR_ALIGN ? sizeof(fixed_bool64_t) : VECTOR_ALIGN), "");
#endif

// --------------------------------------------------------------------------//
// Structs

@@ -580,6 +622,26 @@ TEST_CAST_VECTOR(uint64m8)
TEST_CAST_VECTOR(float32m8)
TEST_CAST_VECTOR(float64m8)

TEST_CAST_COMMON(bool1);
TEST_CAST_COMMON(bool2);
TEST_CAST_COMMON(bool4);
TEST_CAST_COMMON(bool8);
#if __riscv_v_fixed_vlen / 16 >= 8
TEST_CAST_COMMON(bool16);
#endif
#if __riscv_v_fixed_vlen / 32 >= 8
TEST_CAST_COMMON(bool32);
#endif
#if __riscv_v_fixed_vlen / 64 >= 8
TEST_CAST_COMMON(bool64);
#endif

// Test conversion between mask and uint8 is invalid, both have the same
// memory representation.
fixed_bool1_t to_fixed_bool1_t__from_vuint8m1_t(vuint8m1_t x) { return x; } // expected-error-re {{returning 'vuint8m1_t' (aka '__rvv_uint8m1_t') from a function with incompatible result type 'fixed_bool1_t' (vector of {{[0-9]+}} 'unsigned char' values)}}

// --------------------------------------------------------------------------//

// --------------------------------------------------------------------------//
// Test the scalable and fixed-length types can be used interchangeably

@@ -595,6 +657,14 @@ vfloat64m4_t __attribute__((overloadable)) vfunc(vfloat64m4_t op1, vfloat64m4_t
vint32m8_t __attribute__((overloadable)) vfunc(vint32m8_t op1, vint32m8_t op2);
vfloat64m8_t __attribute__((overloadable)) vfunc(vfloat64m8_t op1, vfloat64m8_t op2);

vbool1_t __attribute__((overloadable)) vfunc(vbool1_t op1, vbool1_t op2);
vbool2_t __attribute__((overloadable)) vfunc(vbool2_t op1, vbool2_t op2);
vbool4_t __attribute__((overloadable)) vfunc(vbool4_t op1, vbool4_t op2);
vbool8_t __attribute__((overloadable)) vfunc(vbool8_t op1, vbool8_t op2);
vbool16_t __attribute__((overloadable)) vfunc(vbool16_t op1, vbool16_t op2);
vbool32_t __attribute__((overloadable)) vfunc(vbool32_t op1, vbool32_t op2);
vbool64_t __attribute__((overloadable)) vfunc(vbool64_t op1, vbool64_t op2);

#define TEST_CALL(TYPE) \
fixed_##TYPE##_t \
call_##TYPE##_ff(fixed_##TYPE##_t op1, fixed_##TYPE##_t op2) { \
@@ -621,6 +691,20 @@ TEST_CALL(float64m4)
TEST_CALL(int32m8)
TEST_CALL(float64m8)

TEST_CALL(bool1)
TEST_CALL(bool2)
TEST_CALL(bool4)
TEST_CALL(bool8)
#if __riscv_v_fixed_vlen / 16 >= 8
TEST_CALL(bool16)
#endif
#if __riscv_v_fixed_vlen / 32 >= 8
TEST_CALL(bool32)
#endif
#if __riscv_v_fixed_vlen / 64 >= 8
TEST_CALL(bool64)
#endif

// --------------------------------------------------------------------------//
// Vector initialization