Skip to content

Commit

Permalink
[RISCV] Add attribute(riscv_rvv_vector_bits(N)) based on AArch64 arm_…
Browse files Browse the repository at this point in the history
…sve_vector_bits.

This allows the user to set the size of the scalable vector so they
can be used in structs and as the type of global variables. This works
by representing the type as a fixed vector instead of a scalable vector
in IR. Conversions to and from scalable vectors are made where necessary
like function arguments/returns and intrinsics.

This features has been requested here
riscv-non-isa/rvv-intrinsic-doc#176
I know arm_sve_vector_bits is used by the Eigen library so this
could be used to port Eigen to RVV.

This patch adds a new preprocessor define `__riscv_v_fixed_vlen` that
is set when -mrvv_vector_bits is passed on the command line.

The code is largely based on the AArch64 code. A lot of code was
copy/pasted and then modiied to RVV. There may be some opportunities
for sharing.

This first patch only supports the LMUL=1 types. Additional changes
will be needed to support other LMULs. I have also not supported
mask vectors.

Differential Revision: https://reviews.llvm.org/D145088
  • Loading branch information
topperc committed Apr 28, 2023
1 parent 1ce2015 commit 42e79d9
Show file tree
Hide file tree
Showing 45 changed files with 6,173 additions and 50 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,9 @@ RISC-V Support
FPR+FPR.
- Removed support for ``__attribute__((interrupt("user")))``. User-level
interrupts are not in version 1.12 of the privileged specification.
- Added ``attribute(riscv_rvv_vector_bits(__riscv_v_fixed_vlen))`` to allow
the size of a RVV (RISC-V Vector) scalable type to be specified. This allows
RVV scalable vector types to be used in structs or in global variables.

CUDA/HIP Language Changes
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -2253,6 +2253,17 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// false otherwise.
bool areLaxCompatibleSveTypes(QualType FirstType, QualType SecondType);

/// Return true if the given types are an RISC-V vector builtin type and a
/// VectorType that is a fixed-length representation of the RISC-V vector
/// builtin type for a specific vector-length.
bool areCompatibleRVVTypes(QualType FirstType, QualType SecondType);

/// Return true if the given vector types are lax-compatible RISC-V vector
/// types as defined by -flax-vector-conversions=, which permits implicit
/// conversions between vectors with different number of elements and/or
/// incompatible element types, false otherwise.
bool areLaxCompatibleRVVTypes(QualType FirstType, QualType SecondType);

/// Return true if the type has been explicitly qualified with ObjC ownership.
/// A type may be implicitly qualified with ownership under ObjC ARC, and in
/// some cases the compiler treats these differently.
Expand Down
17 changes: 15 additions & 2 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -1770,7 +1770,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {

/// The kind of vector, either a generic vector type or some
/// target-specific vector type such as for AltiVec or Neon.
unsigned VecKind : 3;
unsigned VecKind : 4;
/// The number of elements in the vector.
uint32_t NumElements;
};
Expand Down Expand Up @@ -2049,6 +2049,16 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
/// 'arm_sve_vector_bits' type attribute as VectorType.
QualType getSveEltType(const ASTContext &Ctx) const;

/// Determines if this is a sizeless type supported by the
/// 'riscv_rvv_vector_bits' type attribute, which can be applied to a single
/// RVV vector or mask.
bool isRVVVLSBuiltinType() const;

/// Returns the representative type for the element of an RVV builtin type.
/// This is used to represent fixed-length RVV vectors created with the
/// 'riscv_rvv_vector_bits' type attribute as VectorType.
QualType getRVVEltType(const ASTContext &Ctx) const;

/// Types are partitioned into 3 broad categories (C99 6.2.5p1):
/// object types, function types, and incomplete types.

Expand Down Expand Up @@ -3402,7 +3412,10 @@ class VectorType : public Type, public llvm::FoldingSetNode {
SveFixedLengthDataVector,

/// is AArch64 SVE fixed-length predicate vector
SveFixedLengthPredicateVector
SveFixedLengthPredicateVector,

/// is RISC-V RVV fixed-length data vector
RVVFixedLengthDataVector,
};

protected:
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1871,6 +1871,16 @@ def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
let Documentation = [RISCVInterruptDocs];
}

def RISCVRVVVectorBits : TypeAttr {
let Spellings = [GNU<"riscv_rvv_vector_bits">];
let Subjects = SubjectList<[TypedefName], ErrorDiag>;
let Args = [UnsignedArgument<"NumBits">];
let Documentation = [RISCVRVVVectorBitsDocs];
let PragmaAttributeSupport = 0;
// Represented as VectorType instead.
let ASTNode = 0;
}

// This is not a TargetSpecificAttr so that is silently accepted and
// ignored on other targets as encouraged by the OpenCL spec.
//
Expand Down
31 changes: 31 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -2317,6 +2317,37 @@ Version 1.10.
}];
}

def RISCVRVVVectorBitsDocs : Documentation {
let Category = DocCatType;
let Content = [{
On RISC-V targets, the ``riscv_rvv_vector_bits(N)`` attribute is used to define
fixed-length variants of sizeless types.

For example:

.. code-block:: c

#include <riscv_vector.h>

#if defined(__riscv_v_fixed_vlen)
typedef vint8m1_t fixed_vint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
#endif

Creates a type ``fixed_vint8m1_t_t`` that is a fixed-length variant of
``vint8m1_t`` that contains exactly 512 bits. Unlike ``vint8m1_t``, this type
can be used in globals, structs, unions, and arrays, all of which are
unsupported for sizeless types.

The attribute can be attached to a single RVV vector (such as ``vint8m1_t``).
The attribute will be rejected unless
``N==__riscv_v_fixed_vlen``, the implementation defined feature macro that
is enabled under the ``-mrvv-vector-bits`` flag. ``__riscv_v_fixed_vlen`` can
only be a power of 2 between 64 and 65536.

Only `*m1_t`(LMUL=1) types are supported at this time.
}];
}

def AVRInterruptDocs : Documentation {
let Category = DocCatFunction;
let Heading = "interrupt (AVR)";
Expand Down
13 changes: 11 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3055,6 +3055,14 @@ def err_attribute_arm_feature_sve_bits_unsupported : Error<
"value of 128, 256, 512, 1024 or 2048.">;
def err_sve_vector_in_non_sve_target : Error<
"SVE vector type %0 cannot be used in a target without sve">;
def err_attribute_riscv_rvv_bits_unsupported : Error<
"%0 is only supported when '-mrvv-vector-bits=<bits>' is specified with a "
"value of \"zvl\" or a power 2 in the range [64,65536]">;
def err_attribute_bad_rvv_vector_size : Error<
"invalid RVV vector size '%0', must match value set by "
"'-mrvv-vector-bits' ('%1')">;
def err_attribute_invalid_rvv_type : Error<
"%0 attribute applied to non-RVV type %1">;
def err_attribute_requires_positive_integer : Error<
"%0 attribute requires a %select{positive|non-negative}1 "
"integral compile time constant expression">;
Expand Down Expand Up @@ -3165,8 +3173,9 @@ def err_attribute_invalid_size : Error<
"vector size not an integral multiple of component size">;
def err_attribute_zero_size : Error<"zero %0 size">;
def err_attribute_size_too_large : Error<"%0 size too large">;
def err_typecheck_sve_ambiguous : Error<
"cannot combine fixed-length and sizeless SVE vectors in expression, result is ambiguous (%0 and %1)">;
def err_typecheck_sve_rvv_ambiguous : Error<
"cannot combine fixed-length and sizeless %select{SVE|RVV}0 vectors "
"in expression, result is ambiguous (%1 and %2)">;
def err_typecheck_sve_rvv_gnu_ambiguous : Error<
"cannot combine GNU and %select{SVE|RVV}0 vectors in expression, result is ambiguous (%1 and %2)">;
def err_typecheck_vector_not_convertable_implict_truncation : Error<
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/RISCVVTypes.def
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
//
//===----------------------------------------------------------------------===//

#ifndef RVV_TYPE
#define RVV_TYPE(Name, Id, SingletonId)
#endif

#ifndef RVV_VECTOR_TYPE
#define RVV_VECTOR_TYPE(Name, Id, SingletonId, NumEls, ElBits, NF, IsSigned, IsFP)\
RVV_TYPE(Name, Id, SingletonId)
Expand Down
8 changes: 5 additions & 3 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3646,9 +3646,11 @@ def mcmodel_EQ_medany : Flag<["-"], "mcmodel=medany">, Group<m_Group>,
def menable_experimental_extensions : Flag<["-"], "menable-experimental-extensions">, Group<m_Group>,
HelpText<"Enable use of experimental RISC-V extensions.">;
def mrvv_vector_bits_EQ : Joined<["-"], "mrvv-vector-bits=">, Group<m_Group>,
HelpText<"Specify the size in bits of an RVV vector register. Defaults to the"
" vector length agnostic value of \"scalable\". Also accepts \"zvl\""
" to use the value implied by -march/-mcpu (RISC-V only)">;
HelpText<"Specify the size in bits of an RVV vector register. Defaults to "
"the vector length agnostic value of \"scalable\". Accepts power of "
"2 values between 64 and 65536. Also accepts \"zvl\" "
"to use the value implied by -march/-mcpu. Value will be reflected "
"in __riscv_v_fixed_vlen preprocessor define (RISC-V only)">;

def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">;
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/Overload.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ class Sema;
/// Arm SVE Vector conversions
ICK_SVE_Vector_Conversion,

/// RISC-V RVV Vector conversions
ICK_RVV_Vector_Conversion,

/// A vector splat from an arithmetic type
ICK_Vector_Splat,

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -12683,6 +12683,7 @@ class Sema final {
SourceLocation Loc, bool IsCompAssign);

bool isValidSveBitcast(QualType srcType, QualType destType);
bool isValidRVVBitcast(QualType srcType, QualType destType);

bool areMatrixTypesOfTheSameDimension(QualType srcTy, QualType destTy);

Expand Down
87 changes: 86 additions & 1 deletion clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/RISCVTargetParser.h"
#include "llvm/TargetParser/Triple.h"
#include <algorithm>
#include <cassert>
Expand Down Expand Up @@ -2010,6 +2011,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
else if (VT->getVectorKind() == VectorType::SveFixedLengthPredicateVector)
// Adjust the alignment for fixed-length SVE predicates.
Align = 16;
else if (VT->getVectorKind() == VectorType::RVVFixedLengthDataVector)
// Adjust the alignment for fixed-length RVV vectors.
Align = 64;
break;
}

Expand Down Expand Up @@ -9468,7 +9472,9 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
First->getVectorKind() != VectorType::SveFixedLengthDataVector &&
First->getVectorKind() != VectorType::SveFixedLengthPredicateVector &&
Second->getVectorKind() != VectorType::SveFixedLengthDataVector &&
Second->getVectorKind() != VectorType::SveFixedLengthPredicateVector)
Second->getVectorKind() != VectorType::SveFixedLengthPredicateVector &&
First->getVectorKind() != VectorType::RVVFixedLengthDataVector &&
Second->getVectorKind() != VectorType::RVVFixedLengthDataVector)
return true;

return false;
Expand Down Expand Up @@ -9566,6 +9572,85 @@ bool ASTContext::areLaxCompatibleSveTypes(QualType FirstType,
IsLaxCompatible(SecondType, FirstType);
}

/// getRVVTypeSize - Return RVV vector register size.
static uint64_t getRVVTypeSize(ASTContext &Context, const BuiltinType *Ty) {
assert(Ty->isRVVVLSBuiltinType() && "Invalid RVV Type");
auto VScale = Context.getTargetInfo().getVScaleRange(Context.getLangOpts());
return VScale ? VScale->first * llvm::RISCV::RVVBitsPerBlock : 0;
}

bool ASTContext::areCompatibleRVVTypes(QualType FirstType,
QualType SecondType) {
assert(
((FirstType->isRVVSizelessBuiltinType() && SecondType->isVectorType()) ||
(FirstType->isVectorType() && SecondType->isRVVSizelessBuiltinType())) &&
"Expected RVV builtin type and vector type!");

auto IsValidCast = [this](QualType FirstType, QualType SecondType) {
if (const auto *BT = FirstType->getAs<BuiltinType>()) {
if (const auto *VT = SecondType->getAs<VectorType>()) {
// Predicates have the same representation as uint8 so we also have to
// check the kind to make these types incompatible.
if (VT->getVectorKind() == VectorType::RVVFixedLengthDataVector)
return FirstType->isRVVVLSBuiltinType() &&
VT->getElementType().getCanonicalType() ==
FirstType->getRVVEltType(*this);
if (VT->getVectorKind() == VectorType::GenericVector)
return getTypeSize(SecondType) == getRVVTypeSize(*this, BT) &&
hasSameType(VT->getElementType(),
getBuiltinVectorTypeInfo(BT).ElementType);
}
}
return false;
};

return IsValidCast(FirstType, SecondType) ||
IsValidCast(SecondType, FirstType);
}

bool ASTContext::areLaxCompatibleRVVTypes(QualType FirstType,
QualType SecondType) {
assert(
((FirstType->isRVVSizelessBuiltinType() && SecondType->isVectorType()) ||
(FirstType->isVectorType() && SecondType->isRVVSizelessBuiltinType())) &&
"Expected RVV builtin type and vector type!");

auto IsLaxCompatible = [this](QualType FirstType, QualType SecondType) {
const auto *BT = FirstType->getAs<BuiltinType>();
if (!BT)
return false;

const auto *VecTy = SecondType->getAs<VectorType>();
if (VecTy &&
(VecTy->getVectorKind() == VectorType::RVVFixedLengthDataVector ||
VecTy->getVectorKind() == VectorType::GenericVector)) {
const LangOptions::LaxVectorConversionKind LVCKind =
getLangOpts().getLaxVectorConversions();

// If __riscv_v_fixed_vlen != N do not allow GNU vector lax conversion.
if (VecTy->getVectorKind() == VectorType::GenericVector &&
getTypeSize(SecondType) != getRVVTypeSize(*this, BT))
return false;

// If -flax-vector-conversions=all is specified, the types are
// certainly compatible.
if (LVCKind == LangOptions::LaxVectorConversionKind::All)
return true;

// If -flax-vector-conversions=integer is specified, the types are
// compatible if the elements are integer types.
if (LVCKind == LangOptions::LaxVectorConversionKind::Integer)
return VecTy->getElementType().getCanonicalType()->isIntegerType() &&
FirstType->getRVVEltType(*this)->isIntegerType();
}

return false;
};

return IsLaxCompatible(FirstType, SecondType) ||
IsLaxCompatible(SecondType, FirstType);
}

bool ASTContext::hasDirectOwnershipQualifier(QualType Ty) const {
while (true) {
// __strong id
Expand Down
Loading

0 comments on commit 42e79d9

Please sign in to comment.