Skip to content

Commit dcef30a

Browse files
committed
[clang][ExprConst] allow single element access of vector object to be constant expression (llvm#101126)
This is a slightly updated version of llvm#72607, originally authored by @yuanfang-chen Change-Id: Ifdf143d4d766b076bf3010048ab121932c83bb1e
1 parent 9a30a6c commit dcef30a

File tree

5 files changed

+177
-27
lines changed

5 files changed

+177
-27
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ sections with improvements to Clang's support for those languages.
177177

178178
C++ Language Changes
179179
--------------------
180+
- Allow single element access of GCC vector/ext_vector_type object to be
181+
constant expression. Supports the `V.xyzw` syntax and other tidbits
182+
as seen in OpenCL. Selecting multiple elements is left as a future work.
180183

181184
C++20 Feature Support
182185
^^^^^^^^^^^^^^^^^^^^^

clang/lib/AST/ExprConstant.cpp

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ namespace {
221221
ArraySize = 2;
222222
MostDerivedLength = I + 1;
223223
IsArray = true;
224+
} else if (const auto *VT = Type->getAs<VectorType>()) {
225+
Type = VT->getElementType();
226+
ArraySize = VT->getNumElements();
227+
MostDerivedLength = I + 1;
228+
IsArray = true;
224229
} else if (const FieldDecl *FD = getAsField(Path[I])) {
225230
Type = FD->getType();
226231
ArraySize = 0;
@@ -263,7 +268,6 @@ namespace {
263268
/// If the current array is an unsized array, the value of this is
264269
/// undefined.
265270
uint64_t MostDerivedArraySize;
266-
267271
/// The type of the most derived object referred to by this address.
268272
QualType MostDerivedType;
269273

@@ -437,6 +441,16 @@ namespace {
437441
MostDerivedArraySize = 2;
438442
MostDerivedPathLength = Entries.size();
439443
}
444+
445+
void addVectorElementUnchecked(QualType EltTy, uint64_t Size,
446+
uint64_t Idx) {
447+
Entries.push_back(PathEntry::ArrayIndex(Idx));
448+
MostDerivedType = EltTy;
449+
MostDerivedPathLength = Entries.size();
450+
MostDerivedArraySize = 0;
451+
MostDerivedIsArrayElement = false;
452+
}
453+
440454
void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E);
441455
void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E,
442456
const APSInt &N);
@@ -1732,6 +1746,11 @@ namespace {
17321746
if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real))
17331747
Designator.addComplexUnchecked(EltTy, Imag);
17341748
}
1749+
void addVectorElement(EvalInfo &Info, const Expr *E, QualType EltTy,
1750+
uint64_t Size, uint64_t Idx) {
1751+
if (checkSubobject(Info, E, CSK_VectorElement))
1752+
Designator.addVectorElementUnchecked(EltTy, Size, Idx);
1753+
}
17351754
void clearIsNullPointer() {
17361755
IsNullPtr = false;
17371756
}
@@ -3278,6 +3297,19 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
32783297
return true;
32793298
}
32803299

3300+
static bool HandleLValueVectorElement(EvalInfo &Info, const Expr *E,
3301+
LValue &LVal, QualType EltTy,
3302+
uint64_t Size, uint64_t Idx) {
3303+
if (Idx) {
3304+
CharUnits SizeOfElement;
3305+
if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfElement))
3306+
return false;
3307+
LVal.Offset += SizeOfElement * Idx;
3308+
}
3309+
LVal.addVectorElement(Info, E, EltTy, Size, Idx);
3310+
return true;
3311+
}
3312+
32813313
/// Try to evaluate the initializer for a variable declaration.
32823314
///
32833315
/// \param Info Information about the ongoing evaluation.
@@ -3823,6 +3855,27 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
38233855
return handler.found(Index ? O->getComplexFloatImag()
38243856
: O->getComplexFloatReal(), ObjType);
38253857
}
3858+
} else if (const auto *VT = ObjType->getAs<VectorType>()) {
3859+
uint64_t Index = Sub.Entries[I].getAsArrayIndex();
3860+
unsigned NumElements = VT->getNumElements();
3861+
if (Index == NumElements) {
3862+
if (Info.getLangOpts().CPlusPlus11)
3863+
Info.FFDiag(E, diag::note_constexpr_access_past_end)
3864+
<< handler.AccessKind;
3865+
else
3866+
Info.FFDiag(E);
3867+
return handler.failed();
3868+
}
3869+
3870+
if (Index > NumElements) {
3871+
Info.CCEDiag(E, diag::note_constexpr_array_index)
3872+
<< Index << /*array*/ 0 << NumElements;
3873+
return handler.failed();
3874+
}
3875+
3876+
ObjType = VT->getElementType();
3877+
assert(I == N - 1 && "extracting subobject of scalar?");
3878+
return handler.found(O->getVectorElt(Index), ObjType);
38263879
} else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
38273880
if (Field->isMutable() &&
38283881
!Obj.mayAccessMutableMembers(Info, handler.AccessKind)) {
@@ -8432,6 +8485,7 @@ class LValueExprEvaluator
84328485
bool VisitCXXTypeidExpr(const CXXTypeidExpr *E);
84338486
bool VisitCXXUuidofExpr(const CXXUuidofExpr *E);
84348487
bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
8488+
bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E);
84358489
bool VisitUnaryDeref(const UnaryOperator *E);
84368490
bool VisitUnaryReal(const UnaryOperator *E);
84378491
bool VisitUnaryImag(const UnaryOperator *E);
@@ -8755,15 +8809,63 @@ bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
87558809
return LValueExprEvaluatorBaseTy::VisitMemberExpr(E);
87568810
}
87578811

8812+
bool LValueExprEvaluator::VisitExtVectorElementExpr(
8813+
const ExtVectorElementExpr *E) {
8814+
bool Success = true;
8815+
8816+
APValue Val;
8817+
if (!Evaluate(Val, Info, E->getBase())) {
8818+
if (!Info.noteFailure())
8819+
return false;
8820+
Success = false;
8821+
}
8822+
8823+
SmallVector<uint32_t, 4> Indices;
8824+
E->getEncodedElementAccess(Indices);
8825+
// FIXME: support accessing more than one element
8826+
if (Indices.size() > 1)
8827+
return false;
8828+
8829+
if (Success) {
8830+
Result.setFrom(Info.Ctx, Val);
8831+
const auto *VT = E->getBase()->getType()->castAs<VectorType>();
8832+
HandleLValueVectorElement(Info, E, Result, VT->getElementType(),
8833+
VT->getNumElements(), Indices[0]);
8834+
}
8835+
8836+
return Success;
8837+
}
8838+
87588839
bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
8759-
// FIXME: Deal with vectors as array subscript bases.
8760-
if (E->getBase()->getType()->isVectorType() ||
8761-
E->getBase()->getType()->isSveVLSBuiltinType())
8840+
if (E->getBase()->getType()->isSveVLSBuiltinType())
87628841
return Error(E);
87638842

87648843
APSInt Index;
87658844
bool Success = true;
87668845

8846+
if (const auto *VT = E->getBase()->getType()->getAs<VectorType>()) {
8847+
APValue Val;
8848+
if (!Evaluate(Val, Info, E->getBase())) {
8849+
if (!Info.noteFailure())
8850+
return false;
8851+
Success = false;
8852+
}
8853+
8854+
if (!EvaluateInteger(E->getIdx(), Index, Info)) {
8855+
if (!Info.noteFailure())
8856+
return false;
8857+
Success = false;
8858+
}
8859+
8860+
if (Success) {
8861+
Result.setFrom(Info.Ctx, Val);
8862+
HandleLValueVectorElement(Info, E, Result, VT->getElementType(),
8863+
VT->getNumElements(), Index.getExtValue());
8864+
}
8865+
8866+
return Success;
8867+
}
8868+
87678869
// C++17's rules require us to evaluate the LHS first, regardless of which
87688870
// side is the base.
87698871
for (const Expr *SubExpr : {E->getLHS(), E->getRHS()}) {

clang/lib/AST/Interp/State.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ enum CheckSubobjectKind {
4444
CSK_ArrayToPointer,
4545
CSK_ArrayIndex,
4646
CSK_Real,
47-
CSK_Imag
47+
CSK_Imag,
48+
CSK_VectorElement
4849
};
4950

5051
namespace interp {

clang/test/CodeGenCXX/temporaries.cpp

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,26 @@ namespace RefTempSubobject {
6464
constexpr const SelfReferential &sr = SelfReferential();
6565
}
6666

67+
namespace Vector {
68+
typedef __attribute__((vector_size(16))) int vi4a;
69+
typedef __attribute__((ext_vector_type(4))) int vi4b;
70+
struct S {
71+
vi4a v;
72+
vi4b w;
73+
};
74+
75+
int &&r = S().v[1];
76+
// CHECK: @_ZGRN6Vector1rE_ = internal global i32 0, align 4
77+
// CHECK: @_ZN6Vector1rE = constant ptr @_ZGRN6Vector1rE_, align 8
78+
79+
int &&s = S().w[1];
80+
// CHECK: @_ZGRN6Vector1sE_ = internal global i32 0, align 4
81+
// CHECK: @_ZN6Vector1sE = constant ptr @_ZGRN6Vector1sE_, align 8
82+
83+
int &&t = S().w.y;
84+
// CHECK: @_ZGRN6Vector1tE_ = internal global i32 0, align 4
85+
// CHECK: @_ZN6Vector1tE = constant ptr @_ZGRN6Vector1tE_, align 8
86+
}
6787
struct A {
6888
A();
6989
~A();
@@ -666,28 +686,6 @@ namespace Bitfield {
666686
int &&r = S().a;
667687
}
668688

669-
namespace Vector {
670-
typedef __attribute__((vector_size(16))) int vi4a;
671-
typedef __attribute__((ext_vector_type(4))) int vi4b;
672-
struct S {
673-
vi4a v;
674-
vi4b w;
675-
};
676-
// CHECK: alloca
677-
// CHECK: extractelement
678-
// CHECK: store i32 {{.*}}, ptr @_ZGRN6Vector1rE_
679-
// CHECK: store ptr @_ZGRN6Vector1rE_, ptr @_ZN6Vector1rE,
680-
int &&r = S().v[1];
681-
682-
// CHECK: alloca
683-
// CHECK: extractelement
684-
// CHECK: store i32 {{.*}}, ptr @_ZGRN6Vector1sE_
685-
// CHECK: store ptr @_ZGRN6Vector1sE_, ptr @_ZN6Vector1sE,
686-
int &&s = S().w[1];
687-
// FIXME PR16204: The following code leads to an assertion in Sema.
688-
//int &&s = S().w.y;
689-
}
690-
691689
namespace ImplicitTemporaryCleanup {
692690
struct A { A(int); ~A(); };
693691
void g();
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %clang_cc1 %s -Wno-uninitialized -std=c++17 -fsyntax-only -verify
2+
3+
namespace Vector {
4+
5+
using TwoIntsVecSize __attribute__((vector_size(8))) = int;
6+
7+
constexpr TwoIntsVecSize a = {1,2};
8+
static_assert(a[1] == 2);
9+
static_assert(a[2]); // expected-error {{not an integral constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
10+
11+
constexpr struct {
12+
TwoIntsVecSize b;
13+
} Val = {{0,1}};
14+
15+
static_assert(Val.b[1] == 1);
16+
17+
constexpr TwoIntsVecSize c[3] = {{0,1}, {2,3}, {4,5}};
18+
static_assert(c[0][0] == 0);
19+
static_assert(c[1][1] == 3);
20+
static_assert(c[2][3]); // expected-error {{not an integral constant expression}} expected-note {{cannot refer to element 3 of array of 2 elements}}
21+
22+
// make sure clang rejects taking address of a vector element
23+
static_assert(&a[0]); // expected-error {{address of vector element requested}}
24+
25+
}
26+
27+
namespace ExtVector {
28+
29+
using FourIntsExtVec __attribute__((ext_vector_type(4))) = int;
30+
31+
constexpr FourIntsExtVec b = {1,2,3,4};
32+
static_assert(b[0] == 1 && b[1] == 2 && b[2] == 3 && b[3] == 4);
33+
static_assert(b.s0 == 1 && b.s1 == 2 && b.s2 == 3 && b.s3 == 4);
34+
static_assert(b.x == 1 && b.y == 2 && b.z == 3 && b.w == 4);
35+
static_assert(b.r == 1 && b.g == 2 && b.b == 3 && b.a == 4);
36+
static_assert(b[5]); // expected-error {{not an integral constant expression}} expected-note {{cannot refer to element 5 of array of 4 elements}}
37+
38+
// FIXME: support selecting multiple elements
39+
static_assert(b.lo.lo == 1); // expected-error {{not an integral constant expression}}
40+
// static_assert(b.lo.lo==1 && b.lo.hi==2 && b.hi.lo == 3 && b.hi.hi == 4);
41+
// static_assert(b.odd[0]==1 && b.odd[1]==2 && b.even[0] == 3 && b.even[1] == 4);
42+
43+
// make sure clang rejects taking address of a vector element
44+
static_assert(&b[1]); // expected-error {{address of vector element requested}}
45+
46+
}

0 commit comments

Comments
 (0)