[libcxx-commits] [libcxx] [Clang] Add __builtin_vectorelements to get number of elements in vector (PR #69010)
Lawrence Benson via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Oct 13 09:54:55 PDT 2023
https://github.com/lawben updated https://github.com/llvm/llvm-project/pull/69010
>From df8d0a53a31e1351bb6cd3b340e9012b489e9885 Mon Sep 17 00:00:00 2001
From: Lawrence Benson <github at lawben.com>
Date: Wed, 11 Oct 2023 17:26:11 +0200
Subject: [PATCH 1/5] Add __builtin_vectorelements to get the number of
elements in a fixed-sized vector at compile-time or via a @llvm.vscale call
at runtime.
---
clang/include/clang/AST/Type.h | 3 +++
clang/include/clang/Basic/Builtins.def | 1 +
clang/include/clang/Basic/TokenKinds.def | 1 +
clang/lib/AST/ExprConstant.cpp | 8 ++++++++
clang/lib/AST/ItaniumMangle.cpp | 8 ++++++++
clang/lib/AST/Type.cpp | 6 +++++-
clang/lib/CodeGen/CGExprScalar.cpp | 12 ++++++++++++
clang/lib/Parse/ParseExpr.cpp | 7 +++++--
clang/lib/Sema/SemaChecking.cpp | 18 ++++++++++++++++++
clang/lib/Sema/SemaExpr.cpp | 14 ++++++++++++++
10 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index a78d8f60462b231..f6e425783176ba2 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2058,6 +2058,9 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
bool isSizelessType() const;
bool isSizelessBuiltinType() const;
+ /// Returns true for all scalable vector types.
+ bool isSizelessVectorType() const;
+
/// Returns true for SVE scalable vector types.
bool isSVESizelessBuiltinType() const;
diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def
index 6ea8484606cfd5d..6033e8a955fb8bd 100644
--- a/clang/include/clang/Basic/Builtins.def
+++ b/clang/include/clang/Basic/Builtins.def
@@ -674,6 +674,7 @@ BUILTIN(__builtin_debugtrap, "v", "n")
BUILTIN(__builtin_unreachable, "v", "nr")
BUILTIN(__builtin_shufflevector, "v." , "nct")
BUILTIN(__builtin_convertvector, "v." , "nct")
+BUILTIN(__builtin_vectorelements, "v." , "nct")
BUILTIN(__builtin_alloca, "v*z" , "Fn")
BUILTIN(__builtin_alloca_uninitialized, "v*z", "Fn")
BUILTIN(__builtin_alloca_with_align, "v*zIz", "Fn")
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 94db56a9fd5d78c..bbae1200d376c0d 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -746,6 +746,7 @@ ALIAS("_pascal" , __pascal , KEYBORLAND)
// Clang Extensions.
KEYWORD(__builtin_convertvector , KEYALL)
+UNARY_EXPR_OR_TYPE_TRAIT(__builtin_vectorelements, VectorElements, KEYALL)
ALIAS("__char16_t" , char16_t , KEYCXX)
ALIAS("__char32_t" , char32_t , KEYCXX)
KEYWORD(__builtin_bit_cast , KEYALL)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index e5539dedec02a4b..eb36a57e462f3f1 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13595,6 +13595,14 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
Info.Ctx.getOpenMPDefaultSimdAlign(E->getArgumentType()))
.getQuantity(),
E);
+ case UETT_VectorElements: {
+ QualType Ty = E->getTypeOfArgument();
+ // If the vector has a fixed size, we can determine the number of elements at compile time.
+ if (Ty->isVectorType())
+ return Success(Ty->castAs<VectorType>()->getNumElements(), E);
+
+ return false;
+ }
}
llvm_unreachable("unknown expr/type trait");
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 23ec35cae4b7b40..171dfe429c12d31 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -5126,6 +5126,14 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
Diags.Report(DiagID);
return;
}
+ case UETT_VectorElements: {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "cannot yet mangle __builtin_vectorelements expression");
+ Diags.Report(DiagID);
+ return;
+ }
}
break;
}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 4c433f7fe9daca0..050761784498a9c 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2369,7 +2369,7 @@ bool Type::isIncompleteType(NamedDecl **Def) const {
}
bool Type::isSizelessBuiltinType() const {
- if (isSVESizelessBuiltinType() || isRVVSizelessBuiltinType())
+ if (isSizelessVectorType())
return true;
if (const BuiltinType *BT = getAs<BuiltinType>()) {
@@ -2403,6 +2403,10 @@ bool Type::isWebAssemblyTableType() const {
bool Type::isSizelessType() const { return isSizelessBuiltinType(); }
+bool Type::isSizelessVectorType() const {
+ return isSVESizelessBuiltinType() || isRVVSizelessBuiltinType();
+}
+
bool Type::isSVESizelessBuiltinType() const {
if (const BuiltinType *BT = getAs<BuiltinType>()) {
switch (BT->getKind()) {
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 93ab064bdf3915d..c1b66062877ef8b 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -3083,6 +3083,18 @@ ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
E->getTypeOfArgument()->getPointeeType()))
.getQuantity();
return llvm::ConstantInt::get(CGF.SizeTy, Alignment);
+ } else if (E->getKind() == UETT_VectorElements) {
+ // For scalable vectors, we don't know the size at compile time. We can use @llvm.vscale to calculate it at runtime.
+ if (E->getTypeOfArgument()->isSizelessVectorType()) {
+ auto *VecTy = dyn_cast<llvm::ScalableVectorType>(ConvertType(E->getTypeOfArgument()));
+ llvm::Type *ElementTy = VecTy->getElementType();
+ uint64_t NumUnscaledElements = VecTy->getMinNumElements();
+
+ llvm::Value *VScale = Builder.CreateVScale(llvm::ConstantInt::get(ElementTy, 1));
+ // We need to pass the element type to the vscale call. As it may be small, like i8, we need to extend here to avoid an overflow for large vectors.
+ VScale = Builder.CreateZExt(VScale, CGF.SizeTy);
+ return Builder.CreateMul(VScale, llvm::ConstantInt::get(CGF.SizeTy, NumUnscaledElements));
+ }
}
// If this isn't sizeof(vla), the result must be constant; use the constant
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 9dbfc1c8c5e9ffe..e01252f722b662e 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1463,6 +1463,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression
// unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')'
case tok::kw___builtin_omp_required_simd_align:
+ case tok::kw___builtin_vectorelements:
if (NotPrimaryExpression)
*NotPrimaryExpression = true;
AllowSuffix = false;
@@ -2339,7 +2340,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual, tok::kw_sizeof,
tok::kw___alignof, tok::kw_alignof, tok::kw__Alignof,
tok::kw_vec_step,
- tok::kw___builtin_omp_required_simd_align) &&
+ tok::kw___builtin_omp_required_simd_align, tok::kw___builtin_vectorelements) &&
"Not a typeof/sizeof/alignof/vec_step expression!");
ExprResult Operand;
@@ -2460,7 +2461,7 @@ ExprResult Parser::ParseSYCLUniqueStableNameExpression() {
ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof,
tok::kw__Alignof, tok::kw_vec_step,
- tok::kw___builtin_omp_required_simd_align) &&
+ tok::kw___builtin_omp_required_simd_align, tok::kw___builtin_vectorelements) &&
"Not a sizeof/alignof/vec_step expression!");
Token OpTok = Tok;
ConsumeToken();
@@ -2539,6 +2540,8 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
ExprKind = UETT_VecStep;
else if (OpTok.is(tok::kw___builtin_omp_required_simd_align))
ExprKind = UETT_OpenMPRequiredSimdAlign;
+ else if (OpTok.is(tok::kw___builtin_vectorelements))
+ ExprKind = UETT_VectorElements;
if (isCastExpr)
return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 2594a8f97f7d94e..70767a048eddaf9 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2836,6 +2836,24 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
break;
}
+// case Builtin::BI__builtin_vectorelements: {
+// if (checkArgCount(*this, TheCall, 1))
+// return ExprError();
+//
+// const Expr *Arg = TheCall->getArg(0);
+// QualType Ty = Arg->getType();
+// const auto *VecTy = Ty->getAs<VectorType>();
+// if (!VecTy && !Ty->isSizelessVectorType()) {
+// Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+// << 1 << Arg->getType();
+// return ExprError();
+// }
+//
+// // The number of elements in a vector is always an integer.
+// TheCall->setType(Context.IntTy);
+// break;
+// }
+
case Builtin::BI__builtin_matrix_transpose:
return SemaBuiltinMatrixTranspose(TheCall, TheCallResult);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index cf45fc388083ce6..191897ee71f48f8 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4351,6 +4351,17 @@ static bool CheckVecStepTraitOperandType(Sema &S, QualType T,
return false;
}
+static bool CheckVectorElementsTraitOperandType(Sema &S, QualType T,
+ SourceLocation Loc,
+ SourceRange ArgRange) {
+ // builtin_vectorelements supports both fixed-sized and scalable vectors.
+ if (!T->isVectorType() && !T->isSizelessVectorType()) {
+ S.Diag(Loc, diag::err_vec_elements_non_vector) << T << ArgRange;
+ return true;
+ }
+ return false;
+}
+
static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
SourceLocation Loc,
SourceRange ArgRange,
@@ -4743,6 +4754,9 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
if (ExprKind == UETT_VecStep)
return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange);
+ if (ExprKind == UETT_VectorElements)
+ return CheckVectorElementsTraitOperandType(*this, ExprType, OpLoc, ExprRange);
+
// Explicitly list some types as extensions.
if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange,
ExprKind))
>From 550f0ca8678866efd558b0226e2877921e3680d1 Mon Sep 17 00:00:00 2001
From: Lawrence Benson <github at lawben.com>
Date: Wed, 11 Oct 2023 17:36:19 +0200
Subject: [PATCH 2/5] fixup! Add __builtin_vectorelements to get the number of
elements in a fixed-sized vector at compile-time or via a @llvm.vscale call
at runtime.
---
clang/lib/AST/ExprConstant.cpp | 3 ++-
clang/lib/CodeGen/CGExprScalar.cpp | 16 +++++++++++-----
clang/lib/Parse/ParseExpr.cpp | 6 ++++--
clang/lib/Sema/SemaChecking.cpp | 18 ------------------
clang/lib/Sema/SemaExpr.cpp | 7 ++++---
5 files changed, 21 insertions(+), 29 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index eb36a57e462f3f1..2ca080915a2367a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13597,7 +13597,8 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
E);
case UETT_VectorElements: {
QualType Ty = E->getTypeOfArgument();
- // If the vector has a fixed size, we can determine the number of elements at compile time.
+ // If the vector has a fixed size, we can determine the number of elements
+ // at compile time.
if (Ty->isVectorType())
return Success(Ty->castAs<VectorType>()->getNumElements(), E);
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index c1b66062877ef8b..e35f40833ec962f 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -3084,16 +3084,22 @@ ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
.getQuantity();
return llvm::ConstantInt::get(CGF.SizeTy, Alignment);
} else if (E->getKind() == UETT_VectorElements) {
- // For scalable vectors, we don't know the size at compile time. We can use @llvm.vscale to calculate it at runtime.
+ // For scalable vectors, we don't know the size at compile time. We can use
+ // @llvm.vscale to calculate it at runtime.
if (E->getTypeOfArgument()->isSizelessVectorType()) {
- auto *VecTy = dyn_cast<llvm::ScalableVectorType>(ConvertType(E->getTypeOfArgument()));
+ auto *VecTy = dyn_cast<llvm::ScalableVectorType>(
+ ConvertType(E->getTypeOfArgument()));
llvm::Type *ElementTy = VecTy->getElementType();
uint64_t NumUnscaledElements = VecTy->getMinNumElements();
- llvm::Value *VScale = Builder.CreateVScale(llvm::ConstantInt::get(ElementTy, 1));
- // We need to pass the element type to the vscale call. As it may be small, like i8, we need to extend here to avoid an overflow for large vectors.
+ llvm::Value *VScale =
+ Builder.CreateVScale(llvm::ConstantInt::get(ElementTy, 1));
+ // We need to pass the element type to the vscale call. As it may be
+ // small, like i8, we need to extend here to avoid an overflow for large
+ // vectors.
VScale = Builder.CreateZExt(VScale, CGF.SizeTy);
- return Builder.CreateMul(VScale, llvm::ConstantInt::get(CGF.SizeTy, NumUnscaledElements));
+ return Builder.CreateMul(
+ VScale, llvm::ConstantInt::get(CGF.SizeTy, NumUnscaledElements));
}
}
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index e01252f722b662e..4d267c915ff2478 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -2340,7 +2340,8 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual, tok::kw_sizeof,
tok::kw___alignof, tok::kw_alignof, tok::kw__Alignof,
tok::kw_vec_step,
- tok::kw___builtin_omp_required_simd_align, tok::kw___builtin_vectorelements) &&
+ tok::kw___builtin_omp_required_simd_align,
+ tok::kw___builtin_vectorelements) &&
"Not a typeof/sizeof/alignof/vec_step expression!");
ExprResult Operand;
@@ -2461,7 +2462,8 @@ ExprResult Parser::ParseSYCLUniqueStableNameExpression() {
ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof,
tok::kw__Alignof, tok::kw_vec_step,
- tok::kw___builtin_omp_required_simd_align, tok::kw___builtin_vectorelements) &&
+ tok::kw___builtin_omp_required_simd_align,
+ tok::kw___builtin_vectorelements) &&
"Not a sizeof/alignof/vec_step expression!");
Token OpTok = Tok;
ConsumeToken();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 70767a048eddaf9..2594a8f97f7d94e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2836,24 +2836,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
break;
}
-// case Builtin::BI__builtin_vectorelements: {
-// if (checkArgCount(*this, TheCall, 1))
-// return ExprError();
-//
-// const Expr *Arg = TheCall->getArg(0);
-// QualType Ty = Arg->getType();
-// const auto *VecTy = Ty->getAs<VectorType>();
-// if (!VecTy && !Ty->isSizelessVectorType()) {
-// Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-// << 1 << Arg->getType();
-// return ExprError();
-// }
-//
-// // The number of elements in a vector is always an integer.
-// TheCall->setType(Context.IntTy);
-// break;
-// }
-
case Builtin::BI__builtin_matrix_transpose:
return SemaBuiltinMatrixTranspose(TheCall, TheCallResult);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 191897ee71f48f8..b48e915ade82fc2 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4352,8 +4352,8 @@ static bool CheckVecStepTraitOperandType(Sema &S, QualType T,
}
static bool CheckVectorElementsTraitOperandType(Sema &S, QualType T,
- SourceLocation Loc,
- SourceRange ArgRange) {
+ SourceLocation Loc,
+ SourceRange ArgRange) {
// builtin_vectorelements supports both fixed-sized and scalable vectors.
if (!T->isVectorType() && !T->isSizelessVectorType()) {
S.Diag(Loc, diag::err_vec_elements_non_vector) << T << ArgRange;
@@ -4755,7 +4755,8 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange);
if (ExprKind == UETT_VectorElements)
- return CheckVectorElementsTraitOperandType(*this, ExprType, OpLoc, ExprRange);
+ return CheckVectorElementsTraitOperandType(*this, ExprType, OpLoc,
+ ExprRange);
// Explicitly list some types as extensions.
if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange,
>From eb387d62a1648da4f18ecc5f5c969de4b9a2ab7b Mon Sep 17 00:00:00 2001
From: Lawrence Benson <github at lawben.com>
Date: Fri, 13 Oct 2023 14:35:49 +0200
Subject: [PATCH 3/5] Add tests
---
clang/lib/CodeGen/CGExprScalar.cpp | 7 +-
clang/test/CodeGen/builtin_vectorelements.c | 115 ++++++++++++++++++++
2 files changed, 116 insertions(+), 6 deletions(-)
create mode 100644 clang/test/CodeGen/builtin_vectorelements.c
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index e35f40833ec962f..f7a70881545f8ab 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -3089,15 +3089,10 @@ ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
if (E->getTypeOfArgument()->isSizelessVectorType()) {
auto *VecTy = dyn_cast<llvm::ScalableVectorType>(
ConvertType(E->getTypeOfArgument()));
- llvm::Type *ElementTy = VecTy->getElementType();
uint64_t NumUnscaledElements = VecTy->getMinNumElements();
llvm::Value *VScale =
- Builder.CreateVScale(llvm::ConstantInt::get(ElementTy, 1));
- // We need to pass the element type to the vscale call. As it may be
- // small, like i8, we need to extend here to avoid an overflow for large
- // vectors.
- VScale = Builder.CreateZExt(VScale, CGF.SizeTy);
+ Builder.CreateVScale(llvm::ConstantInt::get(CGF.SizeTy, 1));
return Builder.CreateMul(
VScale, llvm::ConstantInt::get(CGF.SizeTy, NumUnscaledElements));
}
diff --git a/clang/test/CodeGen/builtin_vectorelements.c b/clang/test/CodeGen/builtin_vectorelements.c
new file mode 100644
index 000000000000000..afd81a2ea4732fa
--- /dev/null
+++ b/clang/test/CodeGen/builtin_vectorelements.c
@@ -0,0 +1,115 @@
+// RUN: %clang_cc1 -O1 -triple aarch64 -target-feature +neon %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,NEON %s
+// RUN: %clang_cc1 -O1 -triple aarch64 -target-feature +sve %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,SVE %s
+// RUN: %clang_cc1 -O1 -triple riscv64 -target-feature +v %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,RISCV %s
+
+// Note that this does not make sense to check for x86 SIMD types, because
+// __m128i, __m256i, and __m512i do not specify the element type. There are no
+// "logical" number of elements in them.
+
+typedef int int1 __attribute__((vector_size(4)));
+typedef int int4 __attribute__((vector_size(16)));
+typedef int int8 __attribute__((vector_size(32)));
+typedef int int16 __attribute__((vector_size(64)));
+typedef float float2 __attribute__((vector_size(8)));
+typedef long extLong4 __attribute__((ext_vector_type(4)));;
+
+
+int test_builtin_vectorelements_int1() {
+ // CHECK-LABEL: i32 @test_builtin_vectorelements_int1(
+ // CHECK: ret i32 1
+ return __builtin_vectorelements(int1);
+}
+
+int test_builtin_vectorelements_int4() {
+ // CHECK-LABEL: i32 @test_builtin_vectorelements_int4(
+ // CHECK: ret i32 4
+ return __builtin_vectorelements(int4);
+}
+
+int test_builtin_vectorelements_int8() {
+ // CHECK-LABEL: i32 @test_builtin_vectorelements_int8(
+ // CHECK: ret i32 8
+ return __builtin_vectorelements(int8);
+}
+
+int test_builtin_vectorelements_int16() {
+ // CHECK-LABEL: i32 @test_builtin_vectorelements_int16(
+ // CHECK: ret i32 16
+ return __builtin_vectorelements(int16);
+}
+
+int test_builtin_vectorelements_float2() {
+ // CHECK-LABEL: i32 @test_builtin_vectorelements_float2(
+ // CHECK: ret i32 2
+ return __builtin_vectorelements(float2);
+}
+
+int test_builtin_vectorelements_extLong4() {
+ // CHECK-LABEL: i32 @test_builtin_vectorelements_extLong4(
+ // CHECK: ret i32 4
+ return __builtin_vectorelements(extLong4);
+}
+
+
+#if defined(__ARM_NEON)
+#include <arm_neon.h>
+
+int test_builtin_vectorelements_neon32x4() {
+ // NEON: i32 @test_builtin_vectorelements_neon32x4(
+ // NEON: ret i32 4
+ return __builtin_vectorelements(uint32x4_t);
+}
+
+int test_builtin_vectorelements_neon64x1() {
+ // NEON: i32 @test_builtin_vectorelements_neon64x1(
+ // NEON: ret i32 1
+ return __builtin_vectorelements(uint64x1_t);
+}
+#endif
+
+#if defined(__ARM_FEATURE_SVE)
+#include <arm_sve.h>
+
+int test_builtin_vectorelements_sve32() {
+ // SVE: i32 @test_builtin_vectorelements_sve32(
+ // SVE: [[VSCALE:%.+]] = tail call i32 @llvm.vscale.i32()
+ // SVE: [[RES:%.+]] = shl nuw nsw i32 [[VSCALE]], 2
+ // SVE: ret i32 [[RES]]
+ return __builtin_vectorelements(svuint32_t);
+}
+
+int test_builtin_vectorelements_sve16() {
+ // SVE: i32 @test_builtin_vectorelements_sve16(
+ // SVE: [[VSCALE:%.+]] = tail call i32 @llvm.vscale.i32()
+ // SVE: [[RES:%.+]] = shl nuw nsw i32 [[VSCALE]], 4
+ // SVE: ret i32 [[RES]]
+ return __builtin_vectorelements(svuint8_t);
+}
+#endif
+
+#if defined(__riscv)
+#include <riscv_vector.h>
+
+int test_builtin_vectorelements_riscv8() {
+ // RISCV: i32 @test_builtin_vectorelements_riscv8(
+ // RISCV: [[VSCALE:%.+]] = tail call i32 @llvm.vscale.i32()
+ // RISCV: [[RES:%.+]] = shl nuw nsw i32 [[VSCALE]], 3
+ // RISCV: ret i32 [[RES]]
+ return __builtin_vectorelements(vuint8m1_t);
+}
+
+int test_builtin_vectorelements_riscv64() {
+ // RISCV: i32 @test_builtin_vectorelements_riscv64(
+ // RISCV: [[VSCALE:%.+]] = tail call i32 @llvm.vscale.i32()
+ // RISCV: ret i32 [[VSCALE]]
+ return __builtin_vectorelements(vuint64m1_t);
+}
+
+int test_builtin_vectorelements_riscv32m2() {
+ // RISCV: i32 @test_builtin_vectorelements_riscv32m2(
+ // RISCV: [[VSCALE:%.+]] = tail call i32 @llvm.vscale.i32()
+ // RISCV: [[RES:%.+]] = shl nuw nsw i32 [[VSCALE]], 2
+ // RISCV: ret i32 [[RES]]
+ return __builtin_vectorelements(vuint32m2_t);
+}
+#endif
>From 6e8f1f0ea3777fb143ab7bc93be46a4e4c331983 Mon Sep 17 00:00:00 2001
From: Lawrence Benson <github at lawben.com>
Date: Fri, 13 Oct 2023 18:17:32 +0200
Subject: [PATCH 4/5] Fix passing value as argument
---
.../clang/Basic/DiagnosticSemaKinds.td | 3 ++
clang/lib/Sema/SemaExpr.cpp | 9 ++++-
clang/test/CodeGen/builtin_vectorelements.c | 8 ++++-
clang/test/Sema/builtin_vectorelements.c | 23 +++++++++++++
clang/test/SemaCXX/builtin_vectorelements.cpp | 33 +++++++++++++++++++
5 files changed, 74 insertions(+), 2 deletions(-)
create mode 100644 clang/test/Sema/builtin_vectorelements.c
create mode 100644 clang/test/SemaCXX/builtin_vectorelements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c1a6e3831127e56..1543d7fecfe032c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10136,6 +10136,9 @@ def err_vec_builtin_incompatible_vector : Error<
def err_vsx_builtin_nonconstant_argument : Error<
"argument %0 to %1 must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)">;
+def err_vectorelements_non_vector : Error<
+ "'__builtin_vectorelements' argument must be a vector">;
+
def err_shufflevector_nonconstant_argument : Error<
"index for __builtin_shufflevector must be a constant integer">;
def err_shufflevector_argument_too_large : Error<
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index b48e915ade82fc2..8710708a4889ca2 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -35,6 +35,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TypeTraits.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/AnalysisBasedWarnings.h"
@@ -4356,7 +4357,7 @@ static bool CheckVectorElementsTraitOperandType(Sema &S, QualType T,
SourceRange ArgRange) {
// builtin_vectorelements supports both fixed-sized and scalable vectors.
if (!T->isVectorType() && !T->isSizelessVectorType()) {
- S.Diag(Loc, diag::err_vec_elements_non_vector) << T << ArgRange;
+ S.Diag(Loc, diag::err_vectorelements_non_vector) << T << ArgRange;
return true;
}
return false;
@@ -4463,6 +4464,10 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(),
E->getSourceRange());
+ if (ExprKind == UETT_VectorElements)
+ return CheckVectorElementsTraitOperandType(*this, ExprTy, E->getExprLoc(),
+ E->getSourceRange());
+
// Explicitly list some types as extensions.
if (!CheckExtensionTraitOperandType(*this, ExprTy, E->getExprLoc(),
E->getSourceRange(), ExprKind))
@@ -4864,6 +4869,8 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
} else if (E->refersToBitField()) { // C99 6.5.3.4p1.
Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 0;
isInvalid = true;
+ } else if (ExprKind == UETT_VectorElements) {
+ isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_VectorElements);
} else {
isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf);
}
diff --git a/clang/test/CodeGen/builtin_vectorelements.c b/clang/test/CodeGen/builtin_vectorelements.c
index afd81a2ea4732fa..d9b7dd14e1dad89 100644
--- a/clang/test/CodeGen/builtin_vectorelements.c
+++ b/clang/test/CodeGen/builtin_vectorelements.c
@@ -11,7 +11,7 @@ typedef int int4 __attribute__((vector_size(16)));
typedef int int8 __attribute__((vector_size(32)));
typedef int int16 __attribute__((vector_size(64)));
typedef float float2 __attribute__((vector_size(8)));
-typedef long extLong4 __attribute__((ext_vector_type(4)));;
+typedef long extLong4 __attribute__((ext_vector_type(4)));
int test_builtin_vectorelements_int1() {
@@ -50,6 +50,12 @@ int test_builtin_vectorelements_extLong4() {
return __builtin_vectorelements(extLong4);
}
+int test_builtin_vectorelements_multiply_constant() {
+ // CHECK-LABEL: i32 @test_builtin_vectorelements_multiply_constant(
+ // CHECK: ret i32 32
+ return __builtin_vectorelements(int16) * 2;
+}
+
#if defined(__ARM_NEON)
#include <arm_neon.h>
diff --git a/clang/test/Sema/builtin_vectorelements.c b/clang/test/Sema/builtin_vectorelements.c
new file mode 100644
index 000000000000000..650d74cf4ee6e6b
--- /dev/null
+++ b/clang/test/Sema/builtin_vectorelements.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple aarch64 -fsyntax-only -verify %s
+
+void test_builtin_vectorelements() {
+ __builtin_vectorelements(int); // expected-error {{'__builtin_vectorelements' argument must be a vector}}
+ __builtin_vectorelements(float); // expected-error {{'__builtin_vectorelements' argument must be a vector}}
+ __builtin_vectorelements(long*); // expected-error {{'__builtin_vectorelements' argument must be a vector}}
+
+ int a;
+ __builtin_vectorelements(a); // expected-error {{'__builtin_vectorelements' argument must be a vector}}
+
+ typedef int veci4 __attribute__((vector_size(16)));
+ (void) __builtin_vectorelements(veci4);
+
+ veci4 vec;
+ (void) __builtin_vectorelements(vec);
+
+ typedef veci4 some_other_vec;
+ (void) __builtin_vectorelements(some_other_vec);
+
+ struct Foo { int a; };
+ __builtin_vectorelements(struct Foo); // expected-error {{'__builtin_vectorelements' argument must be a vector}}
+}
+
diff --git a/clang/test/SemaCXX/builtin_vectorelements.cpp b/clang/test/SemaCXX/builtin_vectorelements.cpp
new file mode 100644
index 000000000000000..df67722708b6f34
--- /dev/null
+++ b/clang/test/SemaCXX/builtin_vectorelements.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple aarch64 -std=c++17 -fsyntax-only -verify %s
+
+template <typename T>
+using VecT __attribute__((vector_size(16))) = T;
+
+struct FooT {
+ template <typename T>
+ using VecT __attribute__((vector_size(8))) = T;
+};
+
+void test_builtin_vectorelements() {
+ using veci4 __attribute__((vector_size(16))) = int;
+ (void) __builtin_vectorelements(veci4);
+
+ using some_other_vec = veci4;
+ (void) __builtin_vectorelements(some_other_vec);
+
+ using some_int = int;
+ (void) __builtin_vectorelements(some_int); // expected-error {{'__builtin_vectorelements' argument must be a vector}}
+
+ class Foo {};
+ __builtin_vectorelements(Foo); // expected-error {{'__builtin_vectorelements' argument must be a vector}}
+
+ struct Bar { veci4 vec; };
+ (void) __builtin_vectorelements(Bar{}.vec);
+
+ struct Baz { using VecT = veci4; };
+ (void) __builtin_vectorelements(Baz::VecT);
+
+ (void) __builtin_vectorelements(FooT::VecT<long>);
+ (void) __builtin_vectorelements(VecT<char>);
+}
+
>From 323c0180cf9b0d556d5364643e96fcf88d167078 Mon Sep 17 00:00:00 2001
From: Lawrence Benson <github at lawben.com>
Date: Fri, 13 Oct 2023 18:44:59 +0200
Subject: [PATCH 5/5] Fix formatting
---
clang/include/clang/AST/Type.h | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index f6e425783176ba2..8bafffee2c5970e 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -5459,9 +5459,8 @@ class DeducedTemplateSpecializationType : public DeducedType,
/// TemplateArguments, followed by a QualType representing the
/// non-canonical aliased type when the template is a type alias
/// template.
-class alignas(8) TemplateSpecializationType
- : public Type,
- public llvm::FoldingSetNode {
+class alignas(8) TemplateSpecializationType : public Type,
+ public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these
/// The name of the template being specialized. This is
More information about the libcxx-commits
mailing list