[clang] [Clang][Interp] Implement constexpr vector unary operators +, -, ~, ! (PR #105996)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Aug 25 11:11:17 PDT 2024
https://github.com/yronglin created https://github.com/llvm/llvm-project/pull/105996
None
>From 0e4c511107f76da085a8019cf2eca78c3a5a0754 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Mon, 26 Aug 2024 02:09:31 +0800
Subject: [PATCH] [Clang][Interp] Implement constexpr vector unary operators +,
-, ~, !
Signed-off-by: yronglin <yronglin777 at gmail.com>
---
clang/include/clang/AST/ASTContext.h | 8 +
clang/include/clang/Sema/Sema.h | 8 -
clang/lib/AST/ASTContext.cpp | 50 +++++++
clang/lib/AST/ByteCode/Compiler.cpp | 141 ++++++++++++++++++
clang/lib/AST/ByteCode/Compiler.h | 6 +
clang/lib/Sema/SemaChecking.cpp | 2 +-
clang/lib/Sema/SemaExpr.cpp | 67 +--------
clang/test/AST/ByteCode/constexpr-vectors.cpp | 88 +++++++++++
8 files changed, 300 insertions(+), 70 deletions(-)
create mode 100644 clang/test/AST/ByteCode/constexpr-vectors.cpp
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 58a820508da42b..01dbf62a3db88c 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1558,6 +1558,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Return a WebAssembly externref type.
QualType getWebAssemblyExternrefType() const;
+ /// Return a signed ext_vector_type that is of identical size and number of
+ /// elements. For floating point vectors, return an integer type of identical
+ /// size and number of elements. In the non ext_vector_type case, search from
+ /// the largest type to the smallest type to avoid cases where long long ==
+ /// long, where long gets picked over long long.
+ QualType GetSignedVectorType(QualType V);
+ QualType GetSignedSizelessVectorType(QualType V);
+
/// Return the unique reference to a vector type of the specified
/// element type and size.
///
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 1f7e555d1b8717..dd637ef3dd822b 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7393,14 +7393,6 @@ class Sema final : public SemaBase {
bool AllowBothBool, bool AllowBoolConversion,
bool AllowBoolOperation, bool ReportInvalid);
- /// Return a signed ext_vector_type that is of identical size and number of
- /// elements. For floating point vectors, return an integer type of identical
- /// size and number of elements. In the non ext_vector_type case, search from
- /// the largest type to the smallest type to avoid cases where long long ==
- /// long, where long gets picked over long long.
- QualType GetSignedVectorType(QualType V);
- QualType GetSignedSizelessVectorType(QualType V);
-
/// CheckVectorCompareOperands - vector comparisons are a clang extension that
/// operates on extended vector types. Instead of producing an IntTy result,
/// like a scalar comparison, a vector comparison produces a vector of integer
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b201d201e1ea6a..408d4b006a7469 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -4444,6 +4444,56 @@ QualType ASTContext::getScalableVectorType(QualType EltTy, unsigned NumElts,
return QualType();
}
+QualType ASTContext::GetSignedVectorType(QualType V) {
+ const VectorType *VTy = V->castAs<VectorType>();
+ unsigned TypeSize = getTypeSize(VTy->getElementType());
+
+ if (isa<ExtVectorType>(VTy)) {
+ if (VTy->isExtVectorBoolType())
+ return getExtVectorType(BoolTy, VTy->getNumElements());
+ if (TypeSize == getTypeSize(CharTy))
+ return getExtVectorType(CharTy, VTy->getNumElements());
+ if (TypeSize == getTypeSize(ShortTy))
+ return getExtVectorType(ShortTy, VTy->getNumElements());
+ if (TypeSize == getTypeSize(IntTy))
+ return getExtVectorType(IntTy, VTy->getNumElements());
+ if (TypeSize == getTypeSize(Int128Ty))
+ return getExtVectorType(Int128Ty, VTy->getNumElements());
+ if (TypeSize == getTypeSize(LongTy))
+ return getExtVectorType(LongTy, VTy->getNumElements());
+ assert(TypeSize == getTypeSize(LongLongTy) &&
+ "Unhandled vector element size in vector compare");
+ return getExtVectorType(LongLongTy, VTy->getNumElements());
+ }
+
+ if (TypeSize == getTypeSize(Int128Ty))
+ return getVectorType(Int128Ty, VTy->getNumElements(), VectorKind::Generic);
+ if (TypeSize == getTypeSize(LongLongTy))
+ return getVectorType(LongLongTy, VTy->getNumElements(),
+ VectorKind::Generic);
+ if (TypeSize == getTypeSize(LongTy))
+ return getVectorType(LongTy, VTy->getNumElements(), VectorKind::Generic);
+ if (TypeSize == getTypeSize(IntTy))
+ return getVectorType(IntTy, VTy->getNumElements(), VectorKind::Generic);
+ if (TypeSize == getTypeSize(ShortTy))
+ return getVectorType(ShortTy, VTy->getNumElements(), VectorKind::Generic);
+ assert(TypeSize == getTypeSize(CharTy) &&
+ "Unhandled vector element size in vector compare");
+ return getVectorType(CharTy, VTy->getNumElements(), VectorKind::Generic);
+}
+
+QualType ASTContext::GetSignedSizelessVectorType(QualType V) {
+ const BuiltinType *VTy = V->castAs<BuiltinType>();
+ assert(VTy->isSizelessBuiltinType() && "expected sizeless type");
+
+ const QualType ETy = V->getSveEltType(*this);
+ const auto TypeSize = getTypeSize(ETy);
+
+ const QualType IntTy = getIntTypeForBitwidth(TypeSize, true);
+ const llvm::ElementCount VecSize = getBuiltinVectorTypeInfo(VTy).EC;
+ return getScalableVectorType(IntTy, VecSize.getKnownMinValue());
+}
+
/// getVectorType - Return the unique reference to a vector type of
/// the specified element type and size. VectorType must be a built-in type.
QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 0fc942a4f1bc4f..fa329fa8ccc979 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -4991,6 +4991,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
const Expr *SubExpr = E->getSubExpr();
if (SubExpr->getType()->isAnyComplexType())
return this->VisitComplexUnaryOperator(E);
+ if (SubExpr->getType()->isVectorType())
+ return this->VisitVectorUnaryOp(E);
std::optional<PrimType> T = classify(SubExpr->getType());
switch (E->getOpcode()) {
@@ -5312,6 +5314,145 @@ bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) {
return true;
}
+template <class Emitter>
+bool Compiler<Emitter>::VisitVectorUnaryOp(const UnaryOperator *E) {
+ const Expr *SubExpr = E->getSubExpr();
+ assert(SubExpr->getType()->isVectorType());
+
+ if (DiscardResult)
+ return this->discard(SubExpr);
+
+ std::optional<PrimType> ResT = classify(E);
+ auto prepareResult = [=]() -> bool {
+ if (!ResT && !Initializing) {
+ std::optional<unsigned> LocalIndex = allocateLocal(SubExpr);
+ if (!LocalIndex)
+ return false;
+ return this->emitGetPtrLocal(*LocalIndex, E);
+ }
+
+ return true;
+ };
+
+ // The offset of the temporary, if we created one.
+ unsigned SubExprOffset = ~0u;
+ auto createTemp = [=, &SubExprOffset]() -> bool {
+ SubExprOffset = this->allocateLocalPrimitive(SubExpr, PT_Ptr, true, false);
+ if (!this->visit(SubExpr))
+ return false;
+ return this->emitSetLocal(PT_Ptr, SubExprOffset, E);
+ };
+
+ const auto *VecT = SubExpr->getType()->getAs<VectorType>();
+ PrimType ElemT = classifyVectorElementType(SubExpr->getType());
+ auto getElem = [=](unsigned Offset, unsigned Index) -> bool {
+ if (!this->emitGetLocal(PT_Ptr, Offset, E))
+ return false;
+ return this->emitArrayElemPop(ElemT, Index, E);
+ };
+
+ switch (E->getOpcode()) {
+ case UO_Plus: // +x
+ return this->delegate(SubExpr);
+ case UO_Minus:
+ if (!prepareResult())
+ return false;
+ if (!createTemp())
+ return false;
+ for (unsigned I = 0; I != VecT->getNumElements(); ++I) {
+ if (!getElem(SubExprOffset, I))
+ return false;
+ if (!this->emitNeg(ElemT, E))
+ return false;
+ if (!this->emitInitElem(ElemT, I, E))
+ return false;
+ }
+ break;
+ case UO_LNot: { // !x
+ if (!prepareResult())
+ return false;
+ if (!createTemp())
+ return false;
+
+ // In C++, the logic operators !, &&, || are available for vectors. !v is equivalent to v == 0.
+ // https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html
+ QualType SignedVecT = Ctx.getASTContext().GetSignedVectorType(SubExpr->getType());
+ PrimType SignedElemT = classifyPrim(SignedVecT->getAs<VectorType>()->getElementType());
+ for (unsigned I = 0; I != VecT->getNumElements(); ++I) {
+ if (!getElem(SubExprOffset, I))
+ return false;
+
+ // operator ! on vectors returns -1 for 'truth', so negate it.
+ if (isIntegralType(ElemT)) {
+ if (!this->emitPrimCast(ElemT, PT_Bool, Ctx.getASTContext().BoolTy, E))
+ return false;
+ if (!this->emitInv(E))
+ return false;
+ if (!this->emitPrimCast(PT_Bool, ElemT, VecT->getElementType(), E))
+ return false;
+ if (!this->emitNeg(ElemT, E))
+ return false;
+ if (ElemT != SignedElemT &&
+ !this->emitPrimCast(ElemT, SignedElemT, SignedVecT, E))
+ return false;
+ } else {
+ // Float types result in an int of the same size, but -1 for true, or 0 for
+ // false.
+ auto &FpSemantics = Ctx.getFloatSemantics(VecT->getElementType());
+ unsigned NumBits = Ctx.getBitWidth(SignedVecT->getAs<VectorType>()->getElementType());
+ auto Zero = APFloat::getZero(FpSemantics);
+ APSInt SIntZero(APSInt::getZero(NumBits));
+ APSInt SIntAllOne(APSInt::getAllOnes(NumBits));
+ // Emit operations equivalent to isZero(Vec[I]) ? -1 : 0
+ if (!this->emitConstFloat(Zero, E))
+ return false;
+ if (!this->emitEQ(ElemT, E))
+ return false;
+ LabelTy LabelFalse = this->getLabel();
+ LabelTy LabelEnd = this->getLabel();
+ if (!this->jumpFalse(LabelFalse))
+ return false;
+ if (!this->emitConst(SIntAllOne, SignedElemT, E))
+ return false;
+ if (!this->jump(LabelEnd))
+ return false;
+ this->emitLabel(LabelFalse);
+ if (!this->emitConst(SIntZero, SignedElemT, E))
+ return false;
+ this->fallthrough(LabelEnd);
+ this->emitLabel(LabelEnd);
+ }
+ if (!this->emitInitElem(SignedElemT, I, E))
+ return false;
+ }
+ break;
+ }
+ case UO_Not: // ~x
+ if (!prepareResult())
+ return false;
+ if (!createTemp())
+ return false;
+ for (unsigned I = 0; I != VecT->getNumElements(); ++I) {
+ if (!getElem(SubExprOffset, I))
+ return false;
+ if (ElemT == PT_Bool) {
+ if (!this->emitInv(E))
+ return false;
+ } else {
+ if (!this->emitComp(ElemT, E))
+ return false;
+ }
+ if (!this->emitInitElem(ElemT, I, E))
+ return false;
+ }
+ break;
+ default:
+ return this->emitInvalid(E);
+ }
+
+ return true;
+}
+
template <class Emitter>
bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
if (DiscardResult)
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 5acfe3c41796c4..b695b3e8e592f9 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -139,6 +139,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
bool VisitGNUNullExpr(const GNUNullExpr *E);
bool VisitCXXThisExpr(const CXXThisExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
+ bool VisitVectorUnaryOp(const UnaryOperator *E);
bool VisitComplexUnaryOperator(const UnaryOperator *E);
bool VisitDeclRefExpr(const DeclRefExpr *E);
bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
@@ -349,6 +350,11 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
return *this->classify(ElemType);
}
+ PrimType classifyVectorElementType(QualType T) const {
+ assert(T->isVectorType());
+ return *this->classify(T->getAs<VectorType>()->getElementType());
+ }
+
bool emitComplexReal(const Expr *SubExpr);
bool emitComplexBoolCast(const Expr *E);
bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ee143381cf4f79..6fec88da40e526 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4906,7 +4906,7 @@ bool Sema::BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs,
// TODO: When all classification function are implemented with is_fpclass,
// vector argument can be supported in all of them.
if (ElementTy->isVectorType() && IsFPClass) {
- VectorResultTy = GetSignedVectorType(ElementTy);
+ VectorResultTy = Context.GetSignedVectorType(ElementTy);
ElementTy = ElementTy->castAs<VectorType>()->getElementType();
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ea57316ad8014e..bd2ff6c828525a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12534,61 +12534,6 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return InvalidOperands(Loc, LHS, RHS);
}
-QualType Sema::GetSignedVectorType(QualType V) {
- const VectorType *VTy = V->castAs<VectorType>();
- unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
-
- if (isa<ExtVectorType>(VTy)) {
- if (VTy->isExtVectorBoolType())
- return Context.getExtVectorType(Context.BoolTy, VTy->getNumElements());
- if (TypeSize == Context.getTypeSize(Context.CharTy))
- return Context.getExtVectorType(Context.CharTy, VTy->getNumElements());
- if (TypeSize == Context.getTypeSize(Context.ShortTy))
- return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements());
- if (TypeSize == Context.getTypeSize(Context.IntTy))
- return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
- if (TypeSize == Context.getTypeSize(Context.Int128Ty))
- return Context.getExtVectorType(Context.Int128Ty, VTy->getNumElements());
- if (TypeSize == Context.getTypeSize(Context.LongTy))
- return Context.getExtVectorType(Context.LongTy, VTy->getNumElements());
- assert(TypeSize == Context.getTypeSize(Context.LongLongTy) &&
- "Unhandled vector element size in vector compare");
- return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
- }
-
- if (TypeSize == Context.getTypeSize(Context.Int128Ty))
- return Context.getVectorType(Context.Int128Ty, VTy->getNumElements(),
- VectorKind::Generic);
- if (TypeSize == Context.getTypeSize(Context.LongLongTy))
- return Context.getVectorType(Context.LongLongTy, VTy->getNumElements(),
- VectorKind::Generic);
- if (TypeSize == Context.getTypeSize(Context.LongTy))
- return Context.getVectorType(Context.LongTy, VTy->getNumElements(),
- VectorKind::Generic);
- if (TypeSize == Context.getTypeSize(Context.IntTy))
- return Context.getVectorType(Context.IntTy, VTy->getNumElements(),
- VectorKind::Generic);
- if (TypeSize == Context.getTypeSize(Context.ShortTy))
- return Context.getVectorType(Context.ShortTy, VTy->getNumElements(),
- VectorKind::Generic);
- assert(TypeSize == Context.getTypeSize(Context.CharTy) &&
- "Unhandled vector element size in vector compare");
- return Context.getVectorType(Context.CharTy, VTy->getNumElements(),
- VectorKind::Generic);
-}
-
-QualType Sema::GetSignedSizelessVectorType(QualType V) {
- const BuiltinType *VTy = V->castAs<BuiltinType>();
- assert(VTy->isSizelessBuiltinType() && "expected sizeless type");
-
- const QualType ETy = V->getSveEltType(Context);
- const auto TypeSize = Context.getTypeSize(ETy);
-
- const QualType IntTy = Context.getIntTypeForBitwidth(TypeSize, true);
- const llvm::ElementCount VecSize = Context.getBuiltinVectorTypeInfo(VTy).EC;
- return Context.getScalableVectorType(IntTy, VecSize.getKnownMinValue());
-}
-
QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
BinaryOperatorKind Opc) {
@@ -12647,7 +12592,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
// Return a signed type for the vector.
- return GetSignedVectorType(vType);
+ return Context.GetSignedVectorType(vType);
}
QualType Sema::CheckSizelessVectorCompareOperands(ExprResult &LHS,
@@ -12688,7 +12633,7 @@ QualType Sema::CheckSizelessVectorCompareOperands(ExprResult &LHS,
return LHSType;
// Return a signed type for the vector.
- return GetSignedSizelessVectorType(vType);
+ return Context.GetSignedSizelessVectorType(vType);
}
static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS,
@@ -12835,7 +12780,7 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
!(isa<ExtVectorType>(vType->getAs<VectorType>())))
return InvalidLogicalVectorOperands(Loc, LHS, RHS);
- return GetSignedVectorType(LHS.get()->getType());
+ return Context.GetSignedVectorType(LHS.get()->getType());
}
QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS,
@@ -14535,7 +14480,7 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS,
// If Opc is a comparison, ResultType is a vector of shorts. In that case,
// change BinOpResTy to a vector of ints.
if (isVector(ResultTy, Context.ShortTy))
- BinOpResTy = S.GetSignedVectorType(BinOpResTy);
+ BinOpResTy = S.Context.GetSignedVectorType(BinOpResTy);
if (IsCompAssign)
return CompoundAssignOperator::Create(Context, LHS.get(), RHS.get(), Opc,
@@ -15449,7 +15394,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
<< resultType << Input.get()->getSourceRange());
}
// Vector logical not returns the signed variant of the operand type.
- resultType = GetSignedVectorType(resultType);
+ resultType = Context.GetSignedVectorType(resultType);
break;
} else if (Context.getLangOpts().CPlusPlus &&
resultType->isVectorType()) {
@@ -15459,7 +15404,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
<< resultType << Input.get()->getSourceRange());
// Vector logical not returns the signed variant of the operand type.
- resultType = GetSignedVectorType(resultType);
+ resultType = Context.GetSignedVectorType(resultType);
break;
} else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
diff --git a/clang/test/AST/ByteCode/constexpr-vectors.cpp b/clang/test/AST/ByteCode/constexpr-vectors.cpp
new file mode 100644
index 00000000000000..9c396d580bfc5d
--- /dev/null
+++ b/clang/test/AST/ByteCode/constexpr-vectors.cpp
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -fexperimental-new-constant-interpreter -Wno-uninitialized -std=c++14 -fsyntax-only -verify
+
+// expected-no-diagnostics
+
+using FourCharsVecSize __attribute__((vector_size(4))) = char;
+using FourIntsVecSize __attribute__((vector_size(16))) = int;
+using FourLongLongsVecSize __attribute__((vector_size(32))) = long long;
+using FourFloatsVecSize __attribute__((vector_size(16))) = float;
+using FourDoublesVecSize __attribute__((vector_size(32))) = double;
+using FourI128VecSize __attribute__((vector_size(64))) = __int128;
+
+using FourCharsExtVec __attribute__((ext_vector_type(4))) = char;
+using FourIntsExtVec __attribute__((ext_vector_type(4))) = int;
+using FourI128ExtVec __attribute__((ext_vector_type(4))) = __int128;
+
+// Only int vs float makes a difference here, so we only need to test 1 of each.
+// Test Char to make sure the mixed-nature of shifts around char is evident.
+void CharUsage() {
+ constexpr auto H = FourCharsVecSize{-1, -1, 0, -1};
+ constexpr auto InvH = -H;
+ static_assert(InvH[0] == 1 && InvH[1] == 1 && InvH[2] == 0 && InvH[3] == 1, "");
+
+ constexpr auto ae = ~FourCharsVecSize{1, 2, 10, 20};
+ static_assert(ae[0] == -2 && ae[1] == -3 && ae[2] == -11 && ae[3] == -21, "");
+
+ constexpr auto af = !FourCharsVecSize{0, 1, 8, -1};
+ static_assert(af[0] == -1 && af[1] == 0 && af[2] == 0 && af[3] == 0, "");
+}
+
+void CharExtVecUsage() {
+ constexpr auto H = FourCharsExtVec{-1, -1, 0, -1};
+ constexpr auto InvH = -H;
+ static_assert(InvH[0] == 1 && InvH[1] == 1 && InvH[2] == 0 && InvH[3] == 1, "");
+
+ constexpr auto ae = ~FourCharsExtVec{1, 2, 10, 20};
+ static_assert(ae[0] == -2 && ae[1] == -3 && ae[2] == -11 && ae[3] == -21, "");
+
+ constexpr auto af = !FourCharsExtVec{0, 1, 8, -1};
+ static_assert(af[0] == -1 && af[1] == 0 && af[2] == 0 && af[3] == 0, "");
+}
+
+void FloatUsage() {
+ constexpr auto Y = FourFloatsVecSize{1.200000e+01, 1.700000e+01, -1.000000e+00, -1.000000e+00};
+ constexpr auto Z = -Y;
+ static_assert(Z[0] == -1.200000e+01 && Z[1] == -1.700000e+01 && Z[2] == 1.000000e+00 && Z[3] == 1.000000e+00, "");
+
+ // Operator ~ is illegal on floats, so no test for that.
+ constexpr auto af = !FourFloatsVecSize{0, 1, 8, -1};
+ static_assert(af[0] == -1 && af[1] == 0 && af[2] == 0 && af[3] == 0, "");
+}
+
+void FloatVecUsage() {
+ constexpr auto Y = FourFloatsVecSize{1.200000e+01, 1.700000e+01, -1.000000e+00, -1.000000e+00};
+ constexpr auto Z = -Y;
+ static_assert(Z[0] == -1.200000e+01 && Z[1] == -1.700000e+01 && Z[2] == 1.000000e+00 && Z[3] == 1.000000e+00, "");
+
+ // Operator ~ is illegal on floats, so no test for that.
+ constexpr auto af = !FourFloatsVecSize{0, 1, 8, -1};
+ static_assert(af[0] == -1 && af[1] == 0 && af[2] == 0 && af[3] == 0, "");
+}
+
+// FIXME: Int128 vector element comparsion will cause new interpreter crash.
+void I128Usage() {
+ // Operator ~ is illegal on floats, so no test for that.
+ constexpr auto c = ~FourI128VecSize{1, 2, 10, 20};
+ // static_assert(c[0] == -2 && c[1] == -3 && c[2] == -11 && c[3] == -21, "");
+
+ constexpr auto d = !FourI128VecSize{0, 1, 8, -1};
+ // static_assert(d[0] == -1 && d[1] == 0 && d[2] == 0 && d[3] == 0, "");
+}
+
+void I128VecUsage() {
+ // Operator ~ is illegal on floats, so no test for that.
+ constexpr auto c = ~FourI128ExtVec{1, 2, 10, 20};
+ // static_assert(c[0] == -2 && c[1] == -3 && c[2] == -11 && c[3] == -21, "");
+
+ constexpr auto d = !FourI128ExtVec{0, 1, 8, -1};
+ // static_assert(d[0] == -1 && d[1] == 0 && d[2] == 0 && d[3] == 0, "");
+}
+
+using FourBoolsExtVec __attribute__((ext_vector_type(4))) = bool;
+void BoolVecUsage() {
+ // constexpr auto j = !FourBoolsExtVec{true, false, true, false};
+ // static_assert(j[0] == false && j[1] == true && j[2] == false && j[3] == true, "");
+
+ constexpr auto k = ~FourBoolsExtVec{true, false, true, false};
+ static_assert(k[0] == false && k[1] == true && k[2] == false && k[3] == true, "");
+}
More information about the cfe-commits
mailing list