-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[clang][ExprConst] allow single element access of vector object to be constant expression #72607
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 all commits
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 |
---|---|---|
|
@@ -221,6 +221,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; | ||
|
@@ -437,6 +442,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; | ||
Comment on lines
+451
to
+452
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'm not sure about this: it seems to indicate that an expression like That said, I see it's what the 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.
C23 6.2.5p17: Each complex type has the same representation and alignment requirements as an array type containing exactly two elements of the corresponding real type; the first element is equal to the real part, and the second element to the imaginary part, of the complex number. CC @jcranmer-intel @arsenm for some other opinions on whether you should be able to address a vector type 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. I think accessing individual fields should be OK. Taking the address of a vector element feels wrong, but I haven't thought too deeply about it 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. Until we have evidence that |
||
MostDerivedPathLength = Entries.size(); | ||
} | ||
void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E); | ||
void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, | ||
const APSInt &N); | ||
|
@@ -1732,6 +1747,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; | ||
} | ||
|
@@ -3278,6 +3298,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. | ||
|
@@ -3823,6 +3856,21 @@ 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)) { | ||
|
@@ -8432,6 +8480,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); | ||
|
@@ -8755,15 +8804,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 |
---|---|---|
@@ -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); | ||
|
||
} |
Uh oh!
There was an error while loading. Please reload this page.