Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Clang] Add __builtin_vectorelements to get number of elements in vector #69010

Merged
merged 11 commits into from
Oct 19, 2023

Conversation

lawben
Copy link
Contributor

@lawben lawben commented Oct 13, 2023

Adds a new __builtin_vectorelements() function which returns the number of elements for a given vector either at compile-time for fixed-sized vectors, e.g., created via __attribute__((vector_size(N))) or at runtime via a call to @llvm.vscale.i32() for scalable vectors, e.g., SVE or RISCV V.

The new builtin follows a similar path as sizeof(), as it essentially does the same thing but for the number of elements in vector instead of the number of bytes. This allows us to re-use a lot of the existing logic to handle types etc.

A small side addition is Type::isSizelessVectorType(), which we need to distinguish between sizeless vectors (SVE, RISCV V) and sizeless types (WASM).

This is the corresponding discussion.

…-sized vector at compile-time or via a @llvm.vscale call at runtime.
…a fixed-sized vector at compile-time or via a @llvm.vscale call at runtime.
@lawben lawben requested a review from erichkeane October 13, 2023 16:28
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen labels Oct 13, 2023
@llvmbot
Copy link
Member

llvmbot commented Oct 13, 2023

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: Lawrence Benson (lawben)

Changes

Adds a new __builtin_vectorelements() function which returns the number of elements for a given vector either at compile-time for fixed-sized vectors, e.g., created via __attribute__((vector_size(N))) or at runtime via a call to @<!-- -->llvm.vscale.i32() for scalable vectors, e.g., SVE or RISCV V.

The new builtin follows a similar path as sizeof(), as it essentially does the same thing but for the number of elements in vector instead of the number of bytes. This allows us to re-use a lot of the existing logic to handle types etc.

A small side addition is Type::isSizelessVectorType(), which we need to distinguish between sizeless vectors (SVE, RISCV V) and sizeless types (WASM).

This is the corresponding discussion.


Full diff: https://github.com/llvm/llvm-project/pull/69010.diff

13 Files Affected:

  • (modified) clang/include/clang/AST/Type.h (+3)
  • (modified) clang/include/clang/Basic/Builtins.def (+1)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3)
  • (modified) clang/include/clang/Basic/TokenKinds.def (+1)
  • (modified) clang/lib/AST/ExprConstant.cpp (+9)
  • (modified) clang/lib/AST/ItaniumMangle.cpp (+8)
  • (modified) clang/lib/AST/Type.cpp (+5-1)
  • (modified) clang/lib/CodeGen/CGExprScalar.cpp (+13)
  • (modified) clang/lib/Parse/ParseExpr.cpp (+7-2)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+22)
  • (added) clang/test/CodeGen/builtin_vectorelements.c (+121)
  • (added) clang/test/Sema/builtin_vectorelements.c (+23)
  • (added) clang/test/SemaCXX/builtin_vectorelements.cpp (+33)
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/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/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..2ca080915a2367a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13595,6 +13595,15 @@ 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..f7a70881545f8ab 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -3083,6 +3083,19 @@ 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()));
+      uint64_t NumUnscaledElements = VecTy->getMinNumElements();
+
+      llvm::Value *VScale =
+          Builder.CreateVScale(llvm::ConstantInt::get(CGF.SizeTy, 1));
+      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..4d267c915ff2478 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,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_omp_required_simd_align,
+                       tok::kw___builtin_vectorelements) &&
          "Not a typeof/sizeof/alignof/vec_step expression!");
 
   ExprResult Operand;
@@ -2460,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_omp_required_simd_align,
+                     tok::kw___builtin_vectorelements) &&
          "Not a sizeof/alignof/vec_step expression!");
   Token OpTok = Tok;
   ConsumeToken();
@@ -2539,6 +2542,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/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index cf45fc388083ce6..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"
@@ -4351,6 +4352,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_vectorelements_non_vector) << T << ArgRange;
+    return true;
+  }
+  return false;
+}
+
 static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
                                            SourceLocation Loc,
                                            SourceRange ArgRange,
@@ -4452,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))
@@ -4743,6 +4759,10 @@ 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))
@@ -4849,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
new file mode 100644
index 000000000000000..d9b7dd14e1dad89
--- /dev/null
+++ b/clang/test/CodeGen/builtin_vectorelements.c
@@ -0,0 +1,121 @@
+// 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);
+}
+
+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>
+
+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
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>);
+}
+

@lawben
Copy link
Contributor Author

lawben commented Oct 13, 2023

@erichkeane This is my first PR to the frontend side of LLVM. Please let me know if there is something missing for a Clang PR that I should add.

@github-actions
Copy link

github-actions bot commented Oct 13, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

clang/include/clang/AST/Type.h Outdated Show resolved Hide resolved
clang/include/clang/Basic/DiagnosticSemaKinds.td Outdated Show resolved Hide resolved
clang/lib/AST/ExprConstant.cpp Show resolved Hide resolved
clang/lib/CodeGen/CGExprScalar.cpp Outdated Show resolved Hide resolved
clang/lib/CodeGen/CGExprScalar.cpp Outdated Show resolved Hide resolved
clang/lib/Sema/SemaExpr.cpp Outdated Show resolved Hide resolved
clang/test/Sema/builtin_vectorelements.c Outdated Show resolved Hide resolved
clang/test/CodeGen/builtin_vectorelements.c Outdated Show resolved Hide resolved
@erichkeane
Copy link
Collaborator

Also, needs a release note.

@lawben
Copy link
Contributor Author

lawben commented Oct 16, 2023

Also, needs a release note.

How do I do this? I cannot seem to find documentation on the process...

@erichkeane
Copy link
Collaborator

Also, needs a release note.

How do I do this? I cannot seem to find documentation on the process...

See docs/ReleaseNotes.rst.

@lawben
Copy link
Contributor Author

lawben commented Oct 17, 2023

@erichkeane I think I've addressed all of your comments so far. Please check if there is anything else missing.

Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

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

2 more nits, else LGTM.

@@ -5126,6 +5126,14 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
Diags.Report(DiagID);
return;
}
case UETT_VectorElements: {
Copy link
Collaborator

Choose a reason for hiding this comment

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

We probably need the equivilent here for the MicrosoftMangle.cpp as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know. But none of the other UETT_* types are covered in MicrosoftMangle.cpp. I'm not sure whether they are missing or if it not necessary to add this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

OK, SGTM at least, I just know this pattern of 'cannot yet mangle...' shows up primarily in the MicrosoftMangle, so figured it might need to be covered. There is some funny-business as to how much each mangles of expressions in template arguments.

This gets me thinking further though,the constexprness of this likely means you may need to mangle this. I'm open if others are to letting it be done in a follow-up however.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@philnik777 I'm adding you here because of your recent commit that adds __datasizeof (#67805). This is essentially the same code path and you also specify the "cannot mangle" for Itanium but not for Microsoft. Do you know if this is needed for Microsoft (see comments above)?

I'm happy to address this for __builtin_vectorelements, but I really don't know where to start and __datasizeof seems to be the same.

clang/lib/CodeGen/CGExprScalar.cpp Outdated Show resolved Hide resolved
Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

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

I'm good with it if the pre-commit is, and no one comes out and really needs the mangling done in this patch.

@@ -5126,6 +5126,14 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
Diags.Report(DiagID);
return;
}
case UETT_VectorElements: {
Copy link
Collaborator

Choose a reason for hiding this comment

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

OK, SGTM at least, I just know this pattern of 'cannot yet mangle...' shows up primarily in the MicrosoftMangle, so figured it might need to be covered. There is some funny-business as to how much each mangles of expressions in template arguments.

This gets me thinking further though,the constexprness of this likely means you may need to mangle this. I'm open if others are to letting it be done in a follow-up however.

@lawben
Copy link
Contributor Author

lawben commented Oct 19, 2023

As nobody has come forward in the the last two days, I'm gonna merge this now. I'll have a look a mangling this for Microsoft in a follow-up, as this may require a few changes. I'm not yet sure what has to be changed for mangling.

@lawben lawben merged commit de65b6b into llvm:main Oct 19, 2023
2 checks passed
@tbaederr
Copy link
Contributor

Have you seen the failing buildbots?

@lawben
Copy link
Contributor Author

lawben commented Oct 19, 2023

@tbaederr Jupp, I'm on it. I was not aware that I had to add REQUIRES to all the tests for it to find the header files. I assumed they are always available. See #69582.

lawben added a commit that referenced this pull request Oct 19, 2023
Small fix for failing tests after merge of #69010. The tests need
`REQUIRES` to ensure that the correct headers are available. I've also
added a generic x86 build which does not need headers, so there is at
least one run per test.
lawben added a commit that referenced this pull request Oct 19, 2023
In #69582, I accidentally disabled all tests for the changed introduced
in #69010. This change should use the correct `REQUIRES` syntax to
en-/disable target-specific tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants