Skip to content

[clang][bytecode] Implement constexpr vector unary operators +, -, ~, ! #105996

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 28, 2024

Conversation

yronglin
Copy link
Contributor

@yronglin yronglin commented Aug 25, 2024

Implement constexpr vector unary operators +, -, ~ and ! .

  • Follow the current constant interpreter. All of our boolean operations on vector types should be '-1' for the 'truth' type.

@yronglin yronglin requested a review from tbaederr August 25, 2024 18:11
@yronglin yronglin requested a review from Endilll as a code owner August 25, 2024 18:11
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Aug 25, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 25, 2024

@llvm/pr-subscribers-clang

Author: None (yronglin)

Changes

Patch is 22.02 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/105996.diff

8 Files Affected:

  • (modified) clang/include/clang/AST/ASTContext.h (+8)
  • (modified) clang/include/clang/Sema/Sema.h (-8)
  • (modified) clang/lib/AST/ASTContext.cpp (+50)
  • (modified) clang/lib/AST/ByteCode/Compiler.cpp (+141)
  • (modified) clang/lib/AST/ByteCode/Compiler.h (+6)
  • (modified) clang/lib/Sema/SemaChecking.cpp (+1-1)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+6-61)
  • (added) clang/test/AST/ByteCode/constexpr-vectors.cpp (+88)
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 = FourFloats...
[truncated]

Signed-off-by: yronglin <[email protected]>
Copy link

github-actions bot commented Aug 25, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@yronglin
Copy link
Contributor Author

Thank you for your review! I have reverted the modification of ASTContext.

Copy link
Contributor

@tbaederr tbaederr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these the only unary operators supported on vectors or are more to come? Since all (except for +, which doesn't do anything) cases call prepareResult() and createTemp() unconditionally, it would probably be cleaner to reject the unhandled cases via emitInvalid first, then do the prepareResult() + createTemp()(which don't even need to be lambdas anymore), then handle the actual operation.

Copy link
Contributor

@tbaederr tbaederr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If CI comes back, the rest looks good to me, thanks!

@tbaederr tbaederr changed the title [Clang][Interp] Implement constexpr vector unary operators +, -, ~, ! [clang][bytecode] Implement constexpr vector unary operators +, -, ~, ! Aug 28, 2024
@yronglin yronglin merged commit ee0d706 into llvm:main Aug 28, 2024
8 checks passed
yronglin added a commit that referenced this pull request Aug 30, 2024
The PR #105996 broke taking the
address of a vector:

**compound-literal.c**
```C
typedef int v4i32 __attribute((vector_size(16)));
v4i32 *y = &(v4i32){1,2,3,4};
```
That because the current interpreter handle vector unary operator as a
fallback when the generic code path fail. but the new interpreter was
not. we need to handle `UO_AddrOf` in
`Compiler<Emitter>::VisitVectorUnaryOperator`.

Signed-off-by: yronglin <[email protected]>
qiaojbao pushed a commit to GPUOpen-Drivers/llvm-project that referenced this pull request Sep 30, 2024
…4014f0059

Local branch amd-gfx 4684014 Merged main:898d52b819496ba70d0ca29cc7b60237108ae2b4 into amd-gfx:a6bdf8d91f90
Remote branch main ee0d706 [clang][bytecode] Implement constexpr vector unary operators +, -, ~, ! (llvm#105996)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants