-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[clang][ExprConst] allow single element access of vector object to be constant expression #101126
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -222,6 +222,11 @@ namespace { | |
ArraySize = 2; | ||
MostDerivedLength = I + 1; | ||
IsArray = true; | ||
} else if (const auto *VT = Type->getAs<VectorType>()) { | ||
Type = VT->getElementType(); | ||
ArraySize = VT->getNumElements(); | ||
MostDerivedLength = I + 1; | ||
IsArray = true; | ||
} else if (const FieldDecl *FD = getAsField(Path[I])) { | ||
Type = FD->getType(); | ||
ArraySize = 0; | ||
|
@@ -268,7 +273,6 @@ namespace { | |
/// If the current array is an unsized array, the value of this is | ||
/// undefined. | ||
uint64_t MostDerivedArraySize; | ||
|
||
/// The type of the most derived object referred to by this address. | ||
QualType MostDerivedType; | ||
|
||
|
@@ -442,6 +446,16 @@ namespace { | |
MostDerivedArraySize = 2; | ||
MostDerivedPathLength = Entries.size(); | ||
} | ||
|
||
void addVectorElementUnchecked(QualType EltTy, uint64_t Size, | ||
uint64_t Idx) { | ||
Entries.push_back(PathEntry::ArrayIndex(Idx)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sethp had a comment in the previous PR that is not address here: #72607 (comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I thought about having a new accessor of the sort "vectorIndex" but all it seems to achieve is just adding new API that returns does the exact same thing as array (other than perhaps adding a new meaning to PathEntry value). I will update it if you feel this makes sense. |
||
MostDerivedType = EltTy; | ||
MostDerivedPathLength = Entries.size(); | ||
MostDerivedArraySize = 0; | ||
MostDerivedIsArrayElement = false; | ||
} | ||
|
||
void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E); | ||
void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, | ||
const APSInt &N); | ||
|
@@ -1737,6 +1751,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.addVectorElementUnchecked(EltTy, Size, Idx); | ||
} | ||
void clearIsNullPointer() { | ||
IsNullPtr = false; | ||
} | ||
|
@@ -3310,6 +3329,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. | ||
|
@@ -3855,6 +3887,19 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, | |
return handler.found(Index ? O->getComplexFloatImag() | ||
: O->getComplexFloatReal(), ObjType); | ||
} | ||
} else if (const auto *VT = ObjType->getAs<VectorType>()) { | ||
uint64_t Index = Sub.Entries[I].getAsArrayIndex(); | ||
if (Index >= VT->getNumElements()) { | ||
if (Info.getLangOpts().CPlusPlus11) | ||
Info.FFDiag(E, diag::note_constexpr_access_past_end) | ||
<< handler.AccessKind; | ||
else | ||
Info.FFDiag(E); | ||
return handler.failed(); | ||
} | ||
ObjType = VT->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)) { | ||
|
@@ -8509,6 +8554,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); | ||
|
@@ -8850,15 +8896,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 auto *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 auto *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()}) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,40 +3,40 @@ | |
|
||
typedef int __attribute__((vector_size(16))) VI4; | ||
constexpr VI4 A = {1,2,3,4}; | ||
static_assert(A[0] == 1, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(A[1] == 2, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(A[2] == 3, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(A[3] == 4, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(A[0] == 1, ""); | ||
static_assert(A[1] == 2, ""); | ||
static_assert(A[2] == 3, ""); | ||
static_assert(A[3] == 4, ""); | ||
|
||
|
||
/// FIXME: It would be nice if the note said 'vector' instead of 'array'. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolving this fixme comment would be a nice follow-up. |
||
static_assert(A[12] == 4, ""); // ref-error {{not an integral constant expression}} \ | ||
// expected-error {{not an integral constant expression}} \ | ||
// expected-note {{cannot refer to element 12 of array of 4 elements in a constant expression}} | ||
static_assert(A[12] == 4, ""); // both-error {{not an integral constant expression}} \ | ||
// expected-note {{cannot refer to element 12 of array of 4 elements in a constant expression}} \ | ||
// ref-note {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain why this note is being generated? I don't see how There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just kept the original version of the PR, but the message "cannot refer to element 12 of array of 4 elements" seems correct here. I shall update this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done, let me know if the updated changes are okay |
||
|
||
|
||
/// VectorSplat casts | ||
typedef __attribute__(( ext_vector_type(4) )) float float4; | ||
constexpr float4 vec4_0 = (float4)0.5f; | ||
static_assert(vec4_0[0] == 0.5, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(vec4_0[1] == 0.5, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(vec4_0[2] == 0.5, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(vec4_0[3] == 0.5, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(vec4_0[0] == 0.5, ""); | ||
static_assert(vec4_0[1] == 0.5, ""); | ||
static_assert(vec4_0[2] == 0.5, ""); | ||
static_assert(vec4_0[3] == 0.5, ""); | ||
constexpr int vec4_0_discarded = ((float4)12.0f, 0); | ||
|
||
|
||
/// ImplicitValueInitExpr of vector type | ||
constexpr float4 arr4[2] = { | ||
{1,2,3,4}, | ||
}; | ||
static_assert(arr4[0][0] == 1, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(arr4[0][1] == 2, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(arr4[0][2] == 3, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(arr4[0][3] == 4, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(arr4[0][0] == 1, ""); | ||
static_assert(arr4[0][1] == 2, ""); | ||
static_assert(arr4[0][2] == 3, ""); | ||
static_assert(arr4[0][3] == 4, ""); | ||
static_assert(arr4[1][0] == 0, ""); | ||
static_assert(arr4[1][0] == 0, ""); | ||
static_assert(arr4[1][0] == 0, ""); | ||
static_assert(arr4[1][0] == 0, ""); | ||
|
||
|
||
/// From constant-expression-cxx11.cpp | ||
|
@@ -65,10 +65,10 @@ namespace { | |
namespace BoolToSignedIntegralCast{ | ||
typedef __attribute__((__ext_vector_type__(4))) unsigned int int4; | ||
constexpr int4 intsT = (int4)true; | ||
static_assert(intsT[0] == -1, "");// ref-error {{not an integral constant expression}} | ||
static_assert(intsT[1] == -1, "");// ref-error {{not an integral constant expression}} | ||
static_assert(intsT[2] == -1, "");// ref-error {{not an integral constant expression}} | ||
static_assert(intsT[3] == -1, "");// ref-error {{not an integral constant expression}} | ||
static_assert(intsT[0] == -1, ""); | ||
static_assert(intsT[1] == -1, ""); | ||
static_assert(intsT[2] == -1, ""); | ||
static_assert(intsT[3] == -1, ""); | ||
} | ||
|
||
namespace VectorElementExpr { | ||
|
@@ -78,8 +78,8 @@ namespace VectorElementExpr { | |
static_assert(oneElt == 3); | ||
|
||
constexpr int2 twoElts = ((int4){11, 22, 33, 44}).yz; | ||
static_assert(twoElts.x == 22, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(twoElts.y == 33, ""); // ref-error {{not an integral constant expression}} | ||
static_assert(twoElts.x == 22, ""); | ||
static_assert(twoElts.y == 33, ""); | ||
} | ||
|
||
namespace Temporaries { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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}} | ||
|
||
vikramRH marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// 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); | ||
|
||
} |
Uh oh!
There was an error while loading. Please reload this page.