[clang] [Clang][Interp] Implement constexpr vector unary operators +, -, ~, ! (PR #105996)

via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 28 07:52:57 PDT 2024


https://github.com/yronglin updated https://github.com/llvm/llvm-project/pull/105996

>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 1/7] [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, "");
+}

>From 15dd97ff480d16eb7c587dede5cc4cd94fabecc5 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Mon, 26 Aug 2024 02:11:54 +0800
Subject: [PATCH 2/7] Format

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 clang/lib/AST/ByteCode/Compiler.cpp | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index fa329fa8ccc979..48f177d4d90218 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5316,7 +5316,7 @@ bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) {
 
 template <class Emitter>
 bool Compiler<Emitter>::VisitVectorUnaryOp(const UnaryOperator *E) {
-    const Expr *SubExpr = E->getSubExpr();
+  const Expr *SubExpr = E->getSubExpr();
   assert(SubExpr->getType()->isVectorType());
 
   if (DiscardResult)
@@ -5374,10 +5374,13 @@ bool Compiler<Emitter>::VisitVectorUnaryOp(const UnaryOperator *E) {
     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());
+    // 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;
@@ -5393,13 +5396,14 @@ bool Compiler<Emitter>::VisitVectorUnaryOp(const UnaryOperator *E) {
         if (!this->emitNeg(ElemT, E))
           return false;
         if (ElemT != SignedElemT &&
-          !this->emitPrimCast(ElemT, SignedElemT, SignedVecT, E))
-        return false;
+            !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.
+        // 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());
+        unsigned NumBits =
+            Ctx.getBitWidth(SignedVecT->getAs<VectorType>()->getElementType());
         auto Zero = APFloat::getZero(FpSemantics);
         APSInt SIntZero(APSInt::getZero(NumBits));
         APSInt SIntAllOne(APSInt::getAllOnes(NumBits));

>From d0a1b131f942ed1f5d31c6d544bea0612924e26e Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Mon, 26 Aug 2024 20:03:56 +0800
Subject: [PATCH 3/7] [Clang][Interp] Address review comments

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 clang/lib/AST/ByteCode/Compiler.cpp           | 20 +++++++++----------
 clang/lib/AST/ByteCode/Compiler.h             |  2 +-
 clang/test/AST/ByteCode/constexpr-vectors.cpp |  1 +
 3 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 48f177d4d90218..8326cdab4f339f 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -4992,7 +4992,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
   if (SubExpr->getType()->isAnyComplexType())
     return this->VisitComplexUnaryOperator(E);
   if (SubExpr->getType()->isVectorType())
-    return this->VisitVectorUnaryOp(E);
+    return this->VisitVectorUnaryOperator(E);
   std::optional<PrimType> T = classify(SubExpr->getType());
 
   switch (E->getOpcode()) {
@@ -5315,22 +5315,20 @@ bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) {
 }
 
 template <class Emitter>
-bool Compiler<Emitter>::VisitVectorUnaryOp(const UnaryOperator *E) {
+bool Compiler<Emitter>::VisitVectorUnaryOperator(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) {
+    if (!Initializing) {
       std::optional<unsigned> LocalIndex = allocateLocal(SubExpr);
       if (!LocalIndex)
         return false;
       return this->emitGetPtrLocal(*LocalIndex, E);
     }
-
     return true;
   };
 
@@ -5343,7 +5341,7 @@ bool Compiler<Emitter>::VisitVectorUnaryOp(const UnaryOperator *E) {
     return this->emitSetLocal(PT_Ptr, SubExprOffset, E);
   };
 
-  const auto *VecT = SubExpr->getType()->getAs<VectorType>();
+  const auto *VecTy = SubExpr->getType()->getAs<VectorType>();
   PrimType ElemT = classifyVectorElementType(SubExpr->getType());
   auto getElem = [=](unsigned Offset, unsigned Index) -> bool {
     if (!this->emitGetLocal(PT_Ptr, Offset, E))
@@ -5359,7 +5357,7 @@ bool Compiler<Emitter>::VisitVectorUnaryOp(const UnaryOperator *E) {
       return false;
     if (!createTemp())
       return false;
-    for (unsigned I = 0; I != VecT->getNumElements(); ++I) {
+    for (unsigned I = 0; I != VecTy->getNumElements(); ++I) {
       if (!getElem(SubExprOffset, I))
         return false;
       if (!this->emitNeg(ElemT, E))
@@ -5381,7 +5379,7 @@ bool Compiler<Emitter>::VisitVectorUnaryOp(const UnaryOperator *E) {
         Ctx.getASTContext().GetSignedVectorType(SubExpr->getType());
     PrimType SignedElemT =
         classifyPrim(SignedVecT->getAs<VectorType>()->getElementType());
-    for (unsigned I = 0; I != VecT->getNumElements(); ++I) {
+    for (unsigned I = 0; I != VecTy->getNumElements(); ++I) {
       if (!getElem(SubExprOffset, I))
         return false;
 
@@ -5391,7 +5389,7 @@ bool Compiler<Emitter>::VisitVectorUnaryOp(const UnaryOperator *E) {
           return false;
         if (!this->emitInv(E))
           return false;
-        if (!this->emitPrimCast(PT_Bool, ElemT, VecT->getElementType(), E))
+        if (!this->emitPrimCast(PT_Bool, ElemT, VecTy->getElementType(), E))
           return false;
         if (!this->emitNeg(ElemT, E))
           return false;
@@ -5401,7 +5399,7 @@ bool Compiler<Emitter>::VisitVectorUnaryOp(const UnaryOperator *E) {
       } 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());
+        auto &FpSemantics = Ctx.getFloatSemantics(VecTy->getElementType());
         unsigned NumBits =
             Ctx.getBitWidth(SignedVecT->getAs<VectorType>()->getElementType());
         auto Zero = APFloat::getZero(FpSemantics);
@@ -5436,7 +5434,7 @@ bool Compiler<Emitter>::VisitVectorUnaryOp(const UnaryOperator *E) {
       return false;
     if (!createTemp())
       return false;
-    for (unsigned I = 0; I != VecT->getNumElements(); ++I) {
+    for (unsigned I = 0; I != VecTy->getNumElements(); ++I) {
       if (!getElem(SubExprOffset, I))
         return false;
       if (ElemT == PT_Bool) {
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index b695b3e8e592f9..939cc0dae3546f 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -139,7 +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 VisitVectorUnaryOperator(const UnaryOperator *E);
   bool VisitComplexUnaryOperator(const UnaryOperator *E);
   bool VisitDeclRefExpr(const DeclRefExpr *E);
   bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
diff --git a/clang/test/AST/ByteCode/constexpr-vectors.cpp b/clang/test/AST/ByteCode/constexpr-vectors.cpp
index 9c396d580bfc5d..8d7cd1a721e454 100644
--- a/clang/test/AST/ByteCode/constexpr-vectors.cpp
+++ b/clang/test/AST/ByteCode/constexpr-vectors.cpp
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -Wno-uninitialized -std=c++14 -fsyntax-only -verify
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -fexperimental-new-constant-interpreter -Wno-uninitialized -std=c++14 -fsyntax-only -verify
 
 // expected-no-diagnostics

>From 88a8e4f89696f2660d88ed8c9b182e02c48ad8a5 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 27 Aug 2024 22:45:16 +0800
Subject: [PATCH 4/7] [clang][bytecode] recovery commented out test

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 clang/test/AST/ByteCode/constexpr-vectors.cpp | 23 ++++++++++---------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/clang/test/AST/ByteCode/constexpr-vectors.cpp b/clang/test/AST/ByteCode/constexpr-vectors.cpp
index 8d7cd1a721e454..d5026f17b95c68 100644
--- a/clang/test/AST/ByteCode/constexpr-vectors.cpp
+++ b/clang/test/AST/ByteCode/constexpr-vectors.cpp
@@ -1,8 +1,6 @@
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -Wno-uninitialized -std=c++14 -fsyntax-only -verify
 // 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;
@@ -45,7 +43,9 @@ void FloatUsage() {
   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.
+  // Operator ~ is illegal on floats.
+  constexpr auto ae = ~FourFloatsVecSize{0, 1, 8, -1}; // expected-error {{invalid argument type}}
+
   constexpr auto af = !FourFloatsVecSize{0, 1, 8, -1};
   static_assert(af[0] == -1 && af[1] == 0 && af[2] == 0 && af[3] == 0, "");
 }
@@ -55,34 +55,35 @@ void FloatVecUsage() {
   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.
+  // Operator ~ is illegal on floats.
+  constexpr auto ae = ~FourFloatsVecSize{0, 1, 8, -1}; // expected-error {{invalid argument type}}
+
   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, "");
+   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, "");
+  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, "");
+  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, "");
+  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 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, "");

>From 789a7ee25291bfe4818a3d7247bd410a387db4b4 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Wed, 28 Aug 2024 07:55:48 +0800
Subject: [PATCH 5/7] [clang][bytecode] Merge UO_LNot integer and floating code
 path and get signed vector type from E

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  | 61 +++++++------------------
 clang/lib/Sema/SemaChecking.cpp      |  2 +-
 clang/lib/Sema/SemaExpr.cpp          | 67 +++++++++++++++++++++++++---
 6 files changed, 87 insertions(+), 109 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 01dbf62a3db88c..58a820508da42b 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1558,14 +1558,6 @@ 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 dd637ef3dd822b..1f7e555d1b8717 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7393,6 +7393,14 @@ 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 408d4b006a7469..b201d201e1ea6a 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -4444,56 +4444,6 @@ 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 8326cdab4f339f..b09b1ea1d2fd98 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5374,56 +5374,29 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
 
     // In C++, the logic operators !, &&, || are available for vectors. !v is
     // equivalent to v == 0.
+    //
+    // The result of the comparison is a vector of the same width and number of
+    // elements as the comparison operands with a signed integral element type.
+    //
     // https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html
-    QualType SignedVecT =
-        Ctx.getASTContext().GetSignedVectorType(SubExpr->getType());
+    QualType SignedVecTy = E->getType();
     PrimType SignedElemT =
-        classifyPrim(SignedVecT->getAs<VectorType>()->getElementType());
+        classifyPrim(SignedVecTy->getAs<VectorType>()->getElementType());
     for (unsigned I = 0; I != VecTy->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, VecTy->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(VecTy->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->emitPrimCast(ElemT, PT_Bool, Ctx.getASTContext().BoolTy, E))
+        return false;
+      if (!this->emitInv(E))
+        return false;
+      if (!this->emitPrimCast(PT_Bool, ElemT, VecTy->getElementType(), E))
+        return false;
+      if (!this->emitNeg(ElemT, E))
+        return false;
+      if (ElemT != SignedElemT &&
+          !this->emitPrimCast(ElemT, SignedElemT, SignedVecTy, E))
+        return false;
       if (!this->emitInitElem(SignedElemT, I, E))
         return false;
     }
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 6fec88da40e526..ee143381cf4f79 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 = Context.GetSignedVectorType(ElementTy);
+    VectorResultTy = GetSignedVectorType(ElementTy);
     ElementTy = ElementTy->castAs<VectorType>()->getElementType();
   }
 
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bd2ff6c828525a..ea57316ad8014e 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12534,6 +12534,61 @@ 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) {
@@ -12592,7 +12647,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
   }
 
   // Return a signed type for the vector.
-  return Context.GetSignedVectorType(vType);
+  return GetSignedVectorType(vType);
 }
 
 QualType Sema::CheckSizelessVectorCompareOperands(ExprResult &LHS,
@@ -12633,7 +12688,7 @@ QualType Sema::CheckSizelessVectorCompareOperands(ExprResult &LHS,
     return LHSType;
 
   // Return a signed type for the vector.
-  return Context.GetSignedSizelessVectorType(vType);
+  return GetSignedSizelessVectorType(vType);
 }
 
 static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS,
@@ -12780,7 +12835,7 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
       !(isa<ExtVectorType>(vType->getAs<VectorType>())))
     return InvalidLogicalVectorOperands(Loc, LHS, RHS);
 
-  return Context.GetSignedVectorType(LHS.get()->getType());
+  return GetSignedVectorType(LHS.get()->getType());
 }
 
 QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS,
@@ -14480,7 +14535,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.Context.GetSignedVectorType(BinOpResTy);
+    BinOpResTy = S.GetSignedVectorType(BinOpResTy);
 
   if (IsCompAssign)
     return CompoundAssignOperator::Create(Context, LHS.get(), RHS.get(), Opc,
@@ -15394,7 +15449,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
                              << resultType << Input.get()->getSourceRange());
         }
         // Vector logical not returns the signed variant of the operand type.
-        resultType = Context.GetSignedVectorType(resultType);
+        resultType = GetSignedVectorType(resultType);
         break;
       } else if (Context.getLangOpts().CPlusPlus &&
                  resultType->isVectorType()) {
@@ -15404,7 +15459,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
                            << resultType << Input.get()->getSourceRange());
 
         // Vector logical not returns the signed variant of the operand type.
-        resultType = Context.GetSignedVectorType(resultType);
+        resultType = GetSignedVectorType(resultType);
         break;
       } else {
         return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)

>From 8c850dfaa4f68d7845767f388e2f32f1dc99b441 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Wed, 28 Aug 2024 21:13:17 +0800
Subject: [PATCH 6/7] [clang][bytecode] Refine implementation

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 clang/lib/AST/ByteCode/Compiler.cpp | 70 +++++++++++++----------------
 1 file changed, 30 insertions(+), 40 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index b09b1ea1d2fd98..6a77323d939791 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5322,24 +5322,30 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
   if (DiscardResult)
     return this->discard(SubExpr);
 
-  auto prepareResult = [=]() -> bool {
-    if (!Initializing) {
-      std::optional<unsigned> LocalIndex = allocateLocal(SubExpr);
-      if (!LocalIndex)
-        return false;
-      return this->emitGetPtrLocal(*LocalIndex, E);
-    }
-    return true;
-  };
+  auto UnaryOp = E->getOpcode();
+  if (UnaryOp != UO_Plus && UnaryOp != UO_Minus && UnaryOp != UO_LNot &&
+      UnaryOp != UO_Not)
+    return this->emitInvalid(E);
 
-  // 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))
+  // Nothing to do here.
+  if (UnaryOp == UO_Plus)
+    return this->delegate(SubExpr);
+
+  if (!Initializing) {
+    std::optional<unsigned> LocalIndex = allocateLocal(SubExpr);
+    if (!LocalIndex)
       return false;
-    return this->emitSetLocal(PT_Ptr, SubExprOffset, E);
-  };
+    if (!this->emitGetPtrLocal(*LocalIndex, E))
+      return false;
+  }
+
+  // The offset of the temporary, if we created one.
+  unsigned SubExprOffset =
+      this->allocateLocalPrimitive(SubExpr, PT_Ptr, true, false);
+  if (!this->visit(SubExpr))
+    return false;
+  if (!this->emitSetLocal(PT_Ptr, SubExprOffset, E))
+    return false;
 
   const auto *VecTy = SubExpr->getType()->getAs<VectorType>();
   PrimType ElemT = classifyVectorElementType(SubExpr->getType());
@@ -5349,14 +5355,8 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
     return this->emitArrayElemPop(ElemT, Index, E);
   };
 
-  switch (E->getOpcode()) {
-  case UO_Plus: // +x
-    return this->delegate(SubExpr);
+  switch (UnaryOp) {
   case UO_Minus:
-    if (!prepareResult())
-      return false;
-    if (!createTemp())
-      return false;
     for (unsigned I = 0; I != VecTy->getNumElements(); ++I) {
       if (!getElem(SubExprOffset, I))
         return false;
@@ -5367,11 +5367,6 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
     }
     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.
     //
@@ -5379,9 +5374,9 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
     // elements as the comparison operands with a signed integral element type.
     //
     // https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html
-    QualType SignedVecTy = E->getType();
-    PrimType SignedElemT =
-        classifyPrim(SignedVecTy->getAs<VectorType>()->getElementType());
+    QualType ResultVecTy = E->getType();
+    PrimType ResultVecElemT =
+        classifyPrim(ResultVecTy->getAs<VectorType>()->getElementType());
     for (unsigned I = 0; I != VecTy->getNumElements(); ++I) {
       if (!getElem(SubExprOffset, I))
         return false;
@@ -5394,19 +5389,15 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
         return false;
       if (!this->emitNeg(ElemT, E))
         return false;
-      if (ElemT != SignedElemT &&
-          !this->emitPrimCast(ElemT, SignedElemT, SignedVecTy, E))
+      if (ElemT != ResultVecElemT &&
+          !this->emitPrimCast(ElemT, ResultVecElemT, ResultVecTy, E))
         return false;
-      if (!this->emitInitElem(SignedElemT, I, E))
+      if (!this->emitInitElem(ResultVecElemT, I, E))
         return false;
     }
     break;
   }
   case UO_Not: // ~x
-    if (!prepareResult())
-      return false;
-    if (!createTemp())
-      return false;
     for (unsigned I = 0; I != VecTy->getNumElements(); ++I) {
       if (!getElem(SubExprOffset, I))
         return false;
@@ -5422,9 +5413,8 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
     }
     break;
   default:
-    return this->emitInvalid(E);
+    llvm_unreachable("Unsupported unary operators should be handled up front");
   }
-
   return true;
 }
 

>From 6ebbfec495a73f50fd9a338a8e4ca5811ad05a81 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Wed, 28 Aug 2024 22:52:33 +0800
Subject: [PATCH 7/7] Remove -Wno-uninitialized

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 clang/test/AST/ByteCode/constexpr-vectors.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/AST/ByteCode/constexpr-vectors.cpp b/clang/test/AST/ByteCode/constexpr-vectors.cpp
index d5026f17b95c68..a738cfe617a0e0 100644
--- a/clang/test/AST/ByteCode/constexpr-vectors.cpp
+++ b/clang/test/AST/ByteCode/constexpr-vectors.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -Wno-uninitialized -std=c++14 -fsyntax-only -verify
-// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -fexperimental-new-constant-interpreter -Wno-uninitialized -std=c++14 -fsyntax-only -verify
+// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++14 -fsyntax-only -verify
+// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -fexperimental-new-constant-interpreter -std=c++14 -fsyntax-only -verify
 
 using FourCharsVecSize __attribute__((vector_size(4))) = char;
 using FourIntsVecSize __attribute__((vector_size(16))) = int;



More information about the cfe-commits mailing list