aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang/docs/ReleaseNotes.rst3
-rw-r--r--clang/lib/AST/ExprConstant.cpp102
-rw-r--r--clang/lib/AST/Interp/State.h3
-rw-r--r--clang/test/AST/Interp/builtin-functions.cpp26
-rw-r--r--clang/test/AST/Interp/vectors.cpp50
-rw-r--r--clang/test/CodeGenCXX/temporaries.cpp41
-rw-r--r--clang/test/SemaCXX/constexpr-vectors-access-elements.cpp29
7 files changed, 190 insertions, 64 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ddad083..2179aae 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -64,6 +64,9 @@ sections with improvements to Clang's support for those languages.
C++ Language Changes
--------------------
+- Allow single element access of vector object to be constant expression.
+ Supports the `V.xyzw` syntax and other tidbits as seen in OpenCL.
+ Selecting multiple elements is left as a future work.
C++17 Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 558e20e..08f49ac 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -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));
+ 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 @@ public:
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()}) {
diff --git a/clang/lib/AST/Interp/State.h b/clang/lib/AST/Interp/State.h
index f1e8e36..44d6c03 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/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp
index 0a17106..b179298 100644
--- a/clang/test/AST/Interp/builtin-functions.cpp
+++ b/clang/test/AST/Interp/builtin-functions.cpp
@@ -866,11 +866,11 @@ namespace convertvector {
constexpr vector8BitInt128 from_vector8BitInt128_to_vector8BitInt128_var =
__builtin_convertvector((vector8BitInt128){0, 1, 2, 3, 4, 5, 6, 7},
vector8BitInt128);
- static_assert(from_vector8BitInt128_to_vector8BitInt128_var[0] == 0, ""); // ref-error {{not an integral constant expression}}
- static_assert(from_vector8BitInt128_to_vector8BitInt128_var[1] == 1, ""); // ref-error {{not an integral constant expression}}
- static_assert(from_vector8BitInt128_to_vector8BitInt128_var[2] == 2, ""); // ref-error {{not an integral constant expression}}
- static_assert(from_vector8BitInt128_to_vector8BitInt128_var[3] == 3, ""); // ref-error {{not an integral constant expression}}
- static_assert(from_vector8BitInt128_to_vector8BitInt128_var[4] == 4, ""); // ref-error {{not an integral constant expression}}
+ static_assert(from_vector8BitInt128_to_vector8BitInt128_var[0] == 0, "");
+ static_assert(from_vector8BitInt128_to_vector8BitInt128_var[1] == 1, "");
+ static_assert(from_vector8BitInt128_to_vector8BitInt128_var[2] == 2, "");
+ static_assert(from_vector8BitInt128_to_vector8BitInt128_var[3] == 3, "");
+ static_assert(from_vector8BitInt128_to_vector8BitInt128_var[4] == 4, "");
}
namespace shufflevector {
@@ -890,14 +890,14 @@ namespace shufflevector {
constexpr vector8char vectorShuffle6 = __builtin_shufflevector(
vector4charConst1, vector4charConst2, 0, 2, 4, 6, 1, 3, 5, 7);
- static_assert(vectorShuffle6[0] == 0, "");// ref-error {{not an integral constant expression}}
- static_assert(vectorShuffle6[1] == 2, "");// ref-error {{not an integral constant expression}}
- static_assert(vectorShuffle6[2] == 4, "");// ref-error {{not an integral constant expression}}
- static_assert(vectorShuffle6[3] == 6, "");// ref-error {{not an integral constant expression}}
- static_assert(vectorShuffle6[4] == 1, "");// ref-error {{not an integral constant expression}}
- static_assert(vectorShuffle6[5] == 3, "");// ref-error {{not an integral constant expression}}
- static_assert(vectorShuffle6[6] == 5, "");// ref-error {{not an integral constant expression}}
- static_assert(vectorShuffle6[7] == 7, "");// ref-error {{not an integral constant expression}}
+ static_assert(vectorShuffle6[0] == 0, "");
+ static_assert(vectorShuffle6[1] == 2, "");
+ static_assert(vectorShuffle6[2] == 4, "");
+ static_assert(vectorShuffle6[3] == 6, "");
+ static_assert(vectorShuffle6[4] == 1, "");
+ static_assert(vectorShuffle6[5] == 3, "");
+ static_assert(vectorShuffle6[6] == 5, "");
+ static_assert(vectorShuffle6[7] == 7, "");
constexpr vector4char vectorShuffleFail1 = __builtin_shufflevector( // both-error {{must be initialized by a constant expression}}\
// ref-error {{index for __builtin_shufflevector not within the bounds of the input vectors; index of -1 found at position 0 is not permitted in a constexpr context}}
diff --git a/clang/test/AST/Interp/vectors.cpp b/clang/test/AST/Interp/vectors.cpp
index 6991a34..b6a9579 100644
--- a/clang/test/AST/Interp/vectors.cpp
+++ b/clang/test/AST/Interp/vectors.cpp
@@ -3,25 +3,25 @@
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'.
-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}}
/// 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);
@@ -29,14 +29,14 @@ constexpr int vec4_0_discarded = ((float4)12.0f, 0);
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 {
diff --git a/clang/test/CodeGenCXX/temporaries.cpp b/clang/test/CodeGenCXX/temporaries.cpp
index 9f697bd..0990c80 100644
--- a/clang/test/CodeGenCXX/temporaries.cpp
+++ b/clang/test/CodeGenCXX/temporaries.cpp
@@ -64,6 +64,26 @@ 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();
@@ -665,27 +685,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];
- int &&ss = 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 0000000..d31db4c
--- /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);
+
+}