diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11499,6 +11499,8 @@ QualType CheckMatrixMultiplyOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign); + bool isValidSveBitcast(QualType srcType, QualType destType); + bool areLaxCompatibleVectorTypes(QualType srcType, QualType destType); bool isLaxVectorConversion(QualType srcType, QualType destType); diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2214,11 +2214,17 @@ return TC_Success; } - // Allow reinterpret_casts between vectors of the same size and - // between vectors and integers of the same size. + // Allow reinterpret_casts between SVE VLATs/VLSTs, vectors of the same + // size and between vectors and integers of the same size. bool destIsVector = DestType->isVectorType(); bool srcIsVector = SrcType->isVectorType(); if (srcIsVector || destIsVector) { + // We can bitcast between SVE VLATs and VLSTs, and vice-versa. + if (Self.isValidSveBitcast(SrcType, DestType)) { + Kind = CK_BitCast; + return TC_Success; + } + // The non-vector type, if any, must have integral type. This is // the same rule that C vector casts use; note, however, that enum // types are not integral in C++. @@ -2752,6 +2758,14 @@ return; } + // If either the src or dest are a vector, it's possible that we want to do an + // SVE bitcast. We can bitcast between SVE VLATs and VLSTs, and vice-versa. + if (SrcType->isVectorType() || DestType->isVectorType()) + if (Self.isValidSveBitcast(SrcType, DestType)) { + Kind = CK_BitCast; + return; + } + if (!DestType->isScalarType() && !DestType->isVectorType()) { const RecordType *DestRecordTy = DestType->getAs(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7197,6 +7197,27 @@ return true; } +/// Are the two types SVE-bitcast-compatible types? I.e. can we bitcast from the +/// first SVE type (e.g. an SVE VLAT) to the second type (e.g. an SVE VLST)? +/// +/// This will also return false if the two given types do not make sense from +/// the perspective of SVE bitcasts. +bool Sema::isValidSveBitcast(QualType srcTy, QualType destTy) { + assert(srcTy->isVectorType() || destTy->isVectorType()); + + auto ValidScalableConversion = [](QualType FirstType, QualType SecondType) { + if (!FirstType->getAs()) + return false; + + const auto *VecTy = SecondType->getAs(); + return VecTy && + VecTy->getVectorKind() == VectorType::SveFixedLengthDataVector; + }; + + return ValidScalableConversion(srcTy, destTy) || + ValidScalableConversion(destTy, srcTy); +} + /// Are the two types lax-compatible vector types? That is, given /// that one of them is a vector, do they have equal storage sizes, /// where the storage size is the number of elements times the element diff --git a/clang/test/Sema/aarch64-sve-explicit-casts-fixed-size.c b/clang/test/Sema/aarch64-sve-explicit-casts-fixed-size.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/aarch64-sve-explicit-casts-fixed-size.c @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=128 -flax-vector-conversions=none -fallow-half-arguments-and-returns -ffreestanding -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=256 -flax-vector-conversions=none -fallow-half-arguments-and-returns -ffreestanding -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=512 -flax-vector-conversions=none -fallow-half-arguments-and-returns -ffreestanding -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=1024 -flax-vector-conversions=none -fallow-half-arguments-and-returns -ffreestanding -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=2048 -flax-vector-conversions=none -fallow-half-arguments-and-returns -ffreestanding -fsyntax-only -verify %s + +// expected-no-diagnostics + +#include + +#define N __ARM_FEATURE_SVE_BITS +#define FIXED_ATTR __attribute__((arm_sve_vector_bits(N))) + +typedef svfloat32_t fixed_float32_t FIXED_ATTR; +typedef svfloat64_t fixed_float64_t FIXED_ATTR; +typedef svint32_t fixed_int32_t FIXED_ATTR; +typedef svint64_t fixed_int64_t FIXED_ATTR; + +// SVE VLSTs can be cast to SVE VLATs, regardless of lane size. +// NOTE: the list below is NOT exhaustive for all SVE types. + +#define TESTCASE(from, to) \ + void from##_to_##to() {\ + from a; \ + to b; \ + \ + b = (to) a; \ + } + +TESTCASE(fixed_float32_t, svfloat32_t) +TESTCASE(fixed_float32_t, svfloat64_t) +TESTCASE(fixed_float32_t, svint32_t) +TESTCASE(fixed_float32_t, svint64_t) + +TESTCASE(fixed_float64_t, svfloat32_t) +TESTCASE(fixed_float64_t, svfloat64_t) +TESTCASE(fixed_float64_t, svint32_t) +TESTCASE(fixed_float64_t, svint64_t) + +TESTCASE(fixed_int32_t, svfloat32_t) +TESTCASE(fixed_int32_t, svfloat64_t) +TESTCASE(fixed_int32_t, svint32_t) +TESTCASE(fixed_int32_t, svint64_t) + +TESTCASE(fixed_int64_t, svfloat32_t) +TESTCASE(fixed_int64_t, svfloat64_t) +TESTCASE(fixed_int64_t, svint32_t) +TESTCASE(fixed_int64_t, svint64_t) + +TESTCASE(svfloat32_t, fixed_float32_t) +TESTCASE(svfloat32_t, fixed_float64_t) +TESTCASE(svfloat32_t, fixed_int32_t) +TESTCASE(svfloat32_t, fixed_int64_t) + +TESTCASE(svfloat64_t, fixed_float32_t) +TESTCASE(svfloat64_t, fixed_float64_t) +TESTCASE(svfloat64_t, fixed_int32_t) +TESTCASE(svfloat64_t, fixed_int64_t) + +TESTCASE(svint32_t, fixed_float32_t) +TESTCASE(svint32_t, fixed_float64_t) +TESTCASE(svint32_t, fixed_int32_t) +TESTCASE(svint32_t, fixed_int64_t) + +TESTCASE(svint64_t, fixed_float32_t) +TESTCASE(svint64_t, fixed_float64_t) +TESTCASE(svint64_t, fixed_int32_t) +TESTCASE(svint64_t, fixed_int64_t) diff --git a/clang/test/SemaCXX/aarch64-sve-explicit-casts-fixed-size.cpp b/clang/test/SemaCXX/aarch64-sve-explicit-casts-fixed-size.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/aarch64-sve-explicit-casts-fixed-size.cpp @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=128 -flax-vector-conversions=none -fallow-half-arguments-and-returns -ffreestanding -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=256 -flax-vector-conversions=none -fallow-half-arguments-and-returns -ffreestanding -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=512 -flax-vector-conversions=none -fallow-half-arguments-and-returns -ffreestanding -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=1024 -flax-vector-conversions=none -fallow-half-arguments-and-returns -ffreestanding -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=2048 -flax-vector-conversions=none -fallow-half-arguments-and-returns -ffreestanding -fsyntax-only -verify %s + +// expected-no-diagnostics + +#include + +#define N __ARM_FEATURE_SVE_BITS +#define FIXED_ATTR __attribute__((arm_sve_vector_bits(N))) + +typedef svfloat32_t fixed_float32_t FIXED_ATTR; +typedef svfloat64_t fixed_float64_t FIXED_ATTR; +typedef svint32_t fixed_int32_t FIXED_ATTR; +typedef svint64_t fixed_int64_t FIXED_ATTR; + +// SVE VLSTs can be cast to SVE VLATs, regardless of lane size. +// NOTE: the list below is NOT exhaustive for all SVE types. + +#define TESTCASE(from, to) \ + void from##_to_##to() {\ + from a; \ + to b; \ + \ + b = (to) a; \ + } + +TESTCASE(fixed_float32_t, svfloat32_t) +TESTCASE(fixed_float32_t, svfloat64_t) +TESTCASE(fixed_float32_t, svint32_t) +TESTCASE(fixed_float32_t, svint64_t) + +TESTCASE(fixed_float64_t, svfloat32_t) +TESTCASE(fixed_float64_t, svfloat64_t) +TESTCASE(fixed_float64_t, svint32_t) +TESTCASE(fixed_float64_t, svint64_t) + +TESTCASE(fixed_int32_t, svfloat32_t) +TESTCASE(fixed_int32_t, svfloat64_t) +TESTCASE(fixed_int32_t, svint32_t) +TESTCASE(fixed_int32_t, svint64_t) + +TESTCASE(fixed_int64_t, svfloat32_t) +TESTCASE(fixed_int64_t, svfloat64_t) +TESTCASE(fixed_int64_t, svint32_t) +TESTCASE(fixed_int64_t, svint64_t) + +TESTCASE(svfloat32_t, fixed_float32_t) +TESTCASE(svfloat32_t, fixed_float64_t) +TESTCASE(svfloat32_t, fixed_int32_t) +TESTCASE(svfloat32_t, fixed_int64_t) + +TESTCASE(svfloat64_t, fixed_float32_t) +TESTCASE(svfloat64_t, fixed_float64_t) +TESTCASE(svfloat64_t, fixed_int32_t) +TESTCASE(svfloat64_t, fixed_int64_t) + +TESTCASE(svint32_t, fixed_float32_t) +TESTCASE(svint32_t, fixed_float64_t) +TESTCASE(svint32_t, fixed_int32_t) +TESTCASE(svint32_t, fixed_int64_t) + +TESTCASE(svint64_t, fixed_float32_t) +TESTCASE(svint64_t, fixed_float64_t) +TESTCASE(svint64_t, fixed_int32_t) +TESTCASE(svint64_t, fixed_int64_t)