https://github.com/yuanfang-chen created https://github.com/llvm/llvm-project/pull/72607
Supports both v[0] and v.x/v.r/v.s0 syntax. Selecting multiple elements is left as a future work. >From 26a20b1c3594676b138395f91143356d87ec72cd Mon Sep 17 00:00:00 2001 From: Yuanfang Chen <tabloid.adr...@gmail.com> Date: Fri, 17 Nov 2023 03:16:38 +0000 Subject: [PATCH] [clang][ExprConst] allow single element access of vector object to be constant expression Supports both v[0] and v.x/v.r/v.s0 syntax. Selecting multiple elements is left as a future work. --- clang/lib/AST/ExprConstant.cpp | 98 ++++++++++++++++++- clang/lib/AST/Interp/State.h | 3 +- clang/test/CodeGenCXX/temporaries.cpp | 43 ++++---- .../constexpr-vectors-access-elements.cpp | 29 ++++++ 4 files changed, 147 insertions(+), 26 deletions(-) create mode 100644 clang/test/SemaCXX/constexpr-vectors-access-elements.cpp diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index eea0827d6f7a8a1..7468dc5c71fa895 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -436,6 +436,16 @@ namespace { MostDerivedArraySize = 2; MostDerivedPathLength = Entries.size(); } + void addVectorUnchecked(QualType EltTy, uint64_t Size, uint64_t Idx) { + Entries.push_back(PathEntry::ArrayIndex(Idx)); + + // This is technically a most-derived object, though in practice this + // is unlikely to matter. + MostDerivedType = EltTy; + MostDerivedIsArrayElement = true; + MostDerivedArraySize = Size; + MostDerivedPathLength = Entries.size(); + } void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E); void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, const APSInt &N); @@ -1714,6 +1724,11 @@ namespace { if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real)) Designator.addComplexUnchecked(EltTy, Imag); } + void addVectorElement(EvalInfo &Info, const Expr *E, QualType EltTy, + uint64_t Size, uint64_t Idx) { + if (checkSubobject(Info, E, CSK_VectorElement)) + Designator.addVectorUnchecked(EltTy, Size, Idx); + } void clearIsNullPointer() { IsNullPtr = false; } @@ -3294,6 +3309,19 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E, return true; } +static bool HandleLValueVectorElement(EvalInfo &Info, const Expr *E, + LValue &LVal, QualType EltTy, + uint64_t Size, uint64_t Idx) { + if (Idx) { + CharUnits SizeOfElement; + if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfElement)) + return false; + LVal.Offset += SizeOfElement * Idx; + } + LVal.addVectorElement(Info, E, EltTy, Size, Idx); + return true; +} + /// Try to evaluate the initializer for a variable declaration. /// /// \param Info Information about the ongoing evaluation. @@ -3839,6 +3867,21 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, return handler.found(Index ? O->getComplexFloatImag() : O->getComplexFloatReal(), ObjType); } + } else if (ObjType->isVectorType()) { + uint64_t Index = Sub.Entries[I].getAsArrayIndex(); + if (Index >= ObjType->castAs<VectorType>()->getNumElements()) { + if (Info.getLangOpts().CPlusPlus11) + Info.FFDiag(E, diag::note_constexpr_access_past_end) + << handler.AccessKind; + else + Info.FFDiag(E); + return handler.failed(); + } + + ObjType = ObjType->castAs<VectorType>()->getElementType(); + + assert(I == N - 1 && "extracting subobject of scalar?"); + return handler.found(O->getVectorElt(Index), ObjType); } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) { if (Field->isMutable() && !Obj.mayAccessMutableMembers(Info, handler.AccessKind)) { @@ -8294,6 +8337,7 @@ class LValueExprEvaluator bool VisitCXXTypeidExpr(const CXXTypeidExpr *E); bool VisitCXXUuidofExpr(const CXXUuidofExpr *E); bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E); + bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E); bool VisitUnaryDeref(const UnaryOperator *E); bool VisitUnaryReal(const UnaryOperator *E); bool VisitUnaryImag(const UnaryOperator *E); @@ -8607,15 +8651,63 @@ bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { return LValueExprEvaluatorBaseTy::VisitMemberExpr(E); } +bool LValueExprEvaluator::VisitExtVectorElementExpr( + const ExtVectorElementExpr *E) { + bool Success = true; + + APValue Val; + if (!Evaluate(Val, Info, E->getBase())) { + if (!Info.noteFailure()) + return false; + Success = false; + } + + SmallVector<uint32_t, 4> Indices; + E->getEncodedElementAccess(Indices); + // FIXME: support accessing more than one element + if (Indices.size() > 1) + return false; + + if (Success) { + Result.setFrom(Info.Ctx, Val); + const VectorType *VT = E->getBase()->getType()->castAs<VectorType>(); + HandleLValueVectorElement(Info, E, Result, VT->getElementType(), + VT->getNumElements(), Indices[0]); + } + + return Success; +} + bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { - // FIXME: Deal with vectors as array subscript bases. - if (E->getBase()->getType()->isVectorType() || - E->getBase()->getType()->isSveVLSBuiltinType()) + if (E->getBase()->getType()->isSveVLSBuiltinType()) return Error(E); APSInt Index; bool Success = true; + if (const VectorType *VT = E->getBase()->getType()->getAs<VectorType>()) { + APValue Val; + if (!Evaluate(Val, Info, E->getBase())) { + if (!Info.noteFailure()) + return false; + Success = false; + } + + if (!EvaluateInteger(E->getIdx(), Index, Info)) { + if (!Info.noteFailure()) + return false; + Success = false; + } + + if (Success) { + Result.setFrom(Info.Ctx, Val); + HandleLValueVectorElement(Info, E, Result, VT->getElementType(), + VT->getNumElements(), Index.getExtValue()); + } + + return Success; + } + // C++17's rules require us to evaluate the LHS first, regardless of which // side is the base. for (const Expr *SubExpr : {E->getLHS(), E->getRHS()}) { diff --git a/clang/lib/AST/Interp/State.h b/clang/lib/AST/Interp/State.h index f1e8e3618f34fe5..44d6c037c5ad955 100644 --- a/clang/lib/AST/Interp/State.h +++ b/clang/lib/AST/Interp/State.h @@ -44,7 +44,8 @@ enum CheckSubobjectKind { CSK_ArrayToPointer, CSK_ArrayIndex, CSK_Real, - CSK_Imag + CSK_Imag, + CSK_VectorElement }; namespace interp { diff --git a/clang/test/CodeGenCXX/temporaries.cpp b/clang/test/CodeGenCXX/temporaries.cpp index c5adb42a6f17374..135d2a356459272 100644 --- a/clang/test/CodeGenCXX/temporaries.cpp +++ b/clang/test/CodeGenCXX/temporaries.cpp @@ -64,6 +64,27 @@ namespace RefTempSubobject { constexpr const SelfReferential &sr = SelfReferential(); } +namespace Vector { + typedef __attribute__((vector_size(16))) int vi4a; + typedef __attribute__((ext_vector_type(4))) int vi4b; + struct S { + vi4a v; + vi4b w; + }; + + int &&r = S().v[1]; + // CHECK: @_ZGRN6Vector1rE_ = internal global i32 0, align 4 + // CHECK: @_ZN6Vector1rE = constant ptr @_ZGRN6Vector1rE_, align 8 + + int &&s = S().w[1]; + // CHECK: @_ZGRN6Vector1sE_ = internal global i32 0, align 4 + // CHECK: @_ZN6Vector1sE = constant ptr @_ZGRN6Vector1sE_, align 8 + + int &&t = S().w.y; + // CHECK: @_ZGRN6Vector1tE_ = internal global i32 0, align 4 + // CHECK: @_ZN6Vector1tE = constant ptr @_ZGRN6Vector1tE_, align 8 +} + struct A { A(); ~A(); @@ -666,28 +687,6 @@ namespace Bitfield { int &&r = S().a; } -namespace Vector { - typedef __attribute__((vector_size(16))) int vi4a; - typedef __attribute__((ext_vector_type(4))) int vi4b; - struct S { - vi4a v; - vi4b w; - }; - // CHECK: alloca - // CHECK: extractelement - // CHECK: store i32 {{.*}}, ptr @_ZGRN6Vector1rE_ - // CHECK: store ptr @_ZGRN6Vector1rE_, ptr @_ZN6Vector1rE, - int &&r = S().v[1]; - - // CHECK: alloca - // CHECK: extractelement - // CHECK: store i32 {{.*}}, ptr @_ZGRN6Vector1sE_ - // CHECK: store ptr @_ZGRN6Vector1sE_, ptr @_ZN6Vector1sE, - int &&s = S().w[1]; - // FIXME PR16204: The following code leads to an assertion in Sema. - //int &&s = S().w.y; -} - namespace ImplicitTemporaryCleanup { struct A { A(int); ~A(); }; void g(); diff --git a/clang/test/SemaCXX/constexpr-vectors-access-elements.cpp b/clang/test/SemaCXX/constexpr-vectors-access-elements.cpp new file mode 100644 index 000000000000000..d31db4c496840e1 --- /dev/null +++ b/clang/test/SemaCXX/constexpr-vectors-access-elements.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 %s -Wno-uninitialized -std=c++17 -fsyntax-only -verify + +namespace Vector { + +using TwoIntsVecSize __attribute__((vector_size(8))) = int; + +constexpr TwoIntsVecSize a = {1,2}; +static_assert(a[1] == 2); +static_assert(a[2]); // expected-error {{not an integral constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}} + +} + +namespace ExtVector { + +using FourIntsExtVec __attribute__((ext_vector_type(4))) = int; + +constexpr FourIntsExtVec b = {1,2,3,4}; +static_assert(b[0] == 1 && b[1] == 2 && b[2] == 3 && b[3] == 4); +static_assert(b.s0 == 1 && b.s1 == 2 && b.s2 == 3 && b.s3 == 4); +static_assert(b.x == 1 && b.y == 2 && b.z == 3 && b.w == 4); +static_assert(b.r == 1 && b.g == 2 && b.b == 3 && b.a == 4); +static_assert(b[5]); // expected-error {{not an integral constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}} + +// FIXME: support selecting multiple elements +static_assert(b.lo.lo == 1); // expected-error {{not an integral constant expression}} +// static_assert(b.lo.lo==1 && b.lo.hi==2 && b.hi.lo == 3 && b.hi.hi == 4); +// static_assert(b.odd[0]==1 && b.odd[1]==2 && b.even[0] == 3 && b.even[1] == 4); + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits