simoll updated this revision to Diff 268140.
simoll added a comment.

NFC. Undid stray change.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81083/new/

https://reviews.llvm.org/D81083

Files:
  clang/docs/LanguageExtensions.rst
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/TypePrinter.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CGExprScalar.cpp
  clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/CodeGen/CodeGenTypes.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/SemaCXX/vector.cpp

Index: clang/test/SemaCXX/vector.cpp
===================================================================
--- clang/test/SemaCXX/vector.cpp
+++ clang/test/SemaCXX/vector.cpp
@@ -331,8 +331,7 @@
 typedef __attribute__((ext_vector_type(4))) int vi4;
 const int &reference_to_vec_element = vi4(1).x;
 
-// PR12649
-typedef bool bad __attribute__((__vector_size__(16)));  // expected-error {{invalid vector element type 'bool'}}
+typedef bool good __attribute__((__vector_size__(16)));
 
 namespace Templates {
 template <typename Elt, unsigned long long Size>
@@ -350,9 +349,7 @@
 void Init() {
   const TemplateVectorType<float, 32>::type Works = {};
   const TemplateVectorType<int, 32>::type Works2 = {};
-  // expected-error@#1 {{invalid vector element type 'bool'}}
-  // expected-note@+1 {{in instantiation of template class 'Templates::TemplateVectorType<bool, 32>' requested here}}
-  const TemplateVectorType<bool, 32>::type NoBool = {};
+  const TemplateVectorType<bool, 32>::type BoolWorks = {};
   // expected-error@#1 {{invalid vector element type 'int __attribute__((ext_vector_type(4)))' (vector of 4 'int' values)}}
   // expected-note@+1 {{in instantiation of template class 'Templates::TemplateVectorType<int __attribute__((ext_vector_type(4))), 32>' requested here}}
   const TemplateVectorType<vi4, 32>::type NoComplex = {};
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -2464,10 +2464,10 @@
 
 QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr,
                                SourceLocation AttrLoc) {
-  // The base type must be integer (not Boolean or enumeration) or float, and
+  // The base type must be boolean or integer (not enumeration) or float, and
   // can't already be a vector.
   if (!CurType->isDependentType() &&
-      (!CurType->isBuiltinType() || CurType->isBooleanType() ||
+      (!CurType->isBuiltinType() ||
        (!CurType->isIntegerType() && !CurType->isRealFloatingType()))) {
     Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << CurType;
     return QualType();
@@ -2496,8 +2496,14 @@
         << SizeExpr->getSourceRange() << "vector";
     return QualType();
   }
-  uint64_t VectorSizeBits = VecSize.getZExtValue() * 8;
-  unsigned TypeSize = static_cast<unsigned>(Context.getTypeSize(CurType));
+
+  uint64_t VectorSizeBits =
+      CurType->isBooleanType()
+          ? VecSize.getZExtValue()
+          : VecSize.getZExtValue() * 8; // FIXME "bitsof(CharUnit)"
+  unsigned TypeSize = CurType->isBooleanType()
+                          ? 1
+                          : static_cast<unsigned>(Context.getTypeSize(CurType));
 
   if (VectorSizeBits == 0) {
     Diag(AttrLoc, diag::err_attribute_zero_size)
@@ -7549,13 +7555,13 @@
   T = Context.getAdjustedType(T, Wrapped);
 }
 
-/// HandleVectorSizeAttribute - this attribute is only applicable to integral
-/// and float scalars, although arrays, pointers, and function return values are
-/// allowed in conjunction with this construct. Aggregates with this attribute
-/// are invalid, even if they are of the same size as a corresponding scalar.
-/// The raw attribute should contain precisely 1 argument, the vector size for
-/// the variable, measured in bytes. If curType and rawAttr are well formed,
-/// this routine will return a new vector type.
+/// HandleVectorSizeAttribute - this attribute is only applicable to boolean,
+/// integral and float scalars, although arrays, pointers, and function return
+/// values are allowed in conjunction with this construct. Aggregates with this
+/// attribute are invalid, even if they are of the same size as a corresponding
+/// scalar. The raw attribute should contain precisely 1 argument, the vector
+/// size for the variable, measured in bytes. If curType and rawAttr are well
+/// formed, this routine will return a new vector type.
 static void HandleVectorSizeAttr(QualType &CurType, const ParsedAttr &Attr,
                                  Sema &S) {
   // Check the attribute arguments.
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -5947,7 +5947,8 @@
   } else if (LHSVT || RHSVT) {
     ResultType = CheckVectorOperands(
         LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true,
-        /*AllowBoolConversions*/ false);
+        /*AllowBoolConversions*/ false,
+        /*AllowBoolOperator*/ false);
     if (ResultType.isNull())
       return {};
   } else {
@@ -6265,9 +6266,10 @@
 
   // Extension: conditional operator involving vector types.
   if (LTy->isVectorType() || RTy->isVectorType())
-    return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false,
-                               /*AllowBothBool*/true,
-                               /*AllowBoolConversions*/false);
+    return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/ false,
+                               /*AllowBothBool*/ true,
+                               /*AllowBoolConversions*/ false,
+                               /*AllowBoolOperator*/ false);
 
   //   -- The second and third operands have arithmetic or enumeration type;
   //      the usual arithmetic conversions are performed to bring them to a
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -8030,9 +8030,10 @@
   if (LHS.get()->getType()->isVectorType() ||
       RHS.get()->getType()->isVectorType()) {
     QualType VecResTy = S.CheckVectorOperands(LHS, RHS, QuestionLoc,
-                                              /*isCompAssign*/false,
-                                              /*AllowBothBool*/true,
-                                              /*AllowBoolConversions*/false);
+                                              /*isCompAssign*/ false,
+                                              /*AllowBothBool*/ true,
+                                              /*AllowBoolConversions*/ false,
+                                              /*AllowBooleanOperator*/ false);
     if (VecResTy.isNull()) return QualType();
     // The result type must match the condition type as specified in
     // OpenCL v1.1 s6.11.6.
@@ -8096,9 +8097,10 @@
   // Now check the two expressions.
   if (LHS.get()->getType()->isVectorType() ||
       RHS.get()->getType()->isVectorType())
-    return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false,
-                               /*AllowBothBool*/true,
-                               /*AllowBoolConversions*/false);
+    return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/ false,
+                               /*AllowBothBool*/ true,
+                               /*AllowBoolConversions*/ false,
+                               /*AllowBooleanOperator*/ false);
 
   QualType ResTy =
       UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
@@ -9775,10 +9777,17 @@
   return false;
 }
 
+static bool IsScalarOrVectorBool(QualType Ty) {
+  return Ty->isBooleanType() ||
+         (Ty->isVectorType() &&
+          Ty->getAs<VectorType>()->getElementType()->isBooleanType());
+}
+
 QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
                                    SourceLocation Loc, bool IsCompAssign,
                                    bool AllowBothBool,
-                                   bool AllowBoolConversions) {
+                                   bool AllowBoolConversions,
+                                   bool AllowBoolOperation) {
   if (!IsCompAssign) {
     LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
     if (LHS.isInvalid())
@@ -9804,6 +9813,11 @@
       RHSVecType && RHSVecType->getVectorKind() == VectorType::AltiVecBool)
     return InvalidOperands(Loc, LHS, RHS);
 
+  // This operation may not be performed on boolean vectors.
+  if (!AllowBoolOperation && IsScalarOrVectorBool(LHSType) &&
+      IsScalarOrVectorBool(RHSType))
+    return InvalidOperands(Loc, LHS, RHS);
+
   // If the vector types are identical, return.
   if (Context.hasSameType(LHSType, RHSType))
     return LHSType;
@@ -10051,8 +10065,9 @@
   if (LHS.get()->getType()->isVectorType() ||
       RHS.get()->getType()->isVectorType())
     return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign,
-                               /*AllowBothBool*/getLangOpts().AltiVec,
-                               /*AllowBoolConversions*/false);
+                               /*AllowBothBool*/ getLangOpts().AltiVec,
+                               /*AllowBoolConversions*/ false,
+                               /*AllowBooleanOperation*/ false);
 
   QualType compType = UsualArithmeticConversions(
       LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic);
@@ -10078,8 +10093,9 @@
     if (LHS.get()->getType()->hasIntegerRepresentation() &&
         RHS.get()->getType()->hasIntegerRepresentation())
       return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign,
-                                 /*AllowBothBool*/getLangOpts().AltiVec,
-                                 /*AllowBoolConversions*/false);
+                                 /*AllowBothBool*/ getLangOpts().AltiVec,
+                                 /*AllowBoolConversions*/ false,
+                                 /*AllowBooleanOperation*/ false);
     return InvalidOperands(Loc, LHS, RHS);
   }
 
@@ -10364,10 +10380,11 @@
 
   if (LHS.get()->getType()->isVectorType() ||
       RHS.get()->getType()->isVectorType()) {
-    QualType compType = CheckVectorOperands(
-        LHS, RHS, Loc, CompLHSTy,
-        /*AllowBothBool*/getLangOpts().AltiVec,
-        /*AllowBoolConversions*/getLangOpts().ZVector);
+    QualType compType =
+        CheckVectorOperands(LHS, RHS, Loc, CompLHSTy,
+                            /*AllowBothBool*/ getLangOpts().AltiVec,
+                            /*AllowBoolConversions*/ getLangOpts().ZVector,
+                            /*AllowBooleanOperation*/ false);
     if (CompLHSTy) *CompLHSTy = compType;
     return compType;
   }
@@ -10464,10 +10481,11 @@
 
   if (LHS.get()->getType()->isVectorType() ||
       RHS.get()->getType()->isVectorType()) {
-    QualType compType = CheckVectorOperands(
-        LHS, RHS, Loc, CompLHSTy,
-        /*AllowBothBool*/getLangOpts().AltiVec,
-        /*AllowBoolConversions*/getLangOpts().ZVector);
+    QualType compType =
+        CheckVectorOperands(LHS, RHS, Loc, CompLHSTy,
+                            /*AllowBothBool*/ getLangOpts().AltiVec,
+                            /*AllowBoolConversions*/ getLangOpts().ZVector,
+                            /*AllowBooleanOperation*/ false);
     if (CompLHSTy) *CompLHSTy = compType;
     return compType;
   }
@@ -11886,6 +11904,9 @@
   else if (TypeSize == Context.getTypeSize(Context.ShortTy))
     return Context.getVectorType(Context.ShortTy, VTy->getNumElements(),
                                  VectorType::GenericVector);
+  else if (TypeSize == Context.getTypeSize(Context.BoolTy))
+    return Context.getVectorType(Context.BoolTy, VTy->getNumElements(),
+                                 VectorType::GenericVector);
   assert(TypeSize == Context.getTypeSize(Context.CharTy) &&
          "Unhandled vector element size in vector compare");
   return Context.getVectorType(Context.CharTy, VTy->getNumElements(),
@@ -11906,9 +11927,11 @@
 
   // Check to make sure we're operating on vectors of the same type and width,
   // Allowing one side to be a scalar of element type.
-  QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false,
-                              /*AllowBothBool*/true,
-                              /*AllowBoolConversions*/getLangOpts().ZVector);
+  QualType vType =
+      CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/ false,
+                          /*AllowBothBool*/ true,
+                          /*AllowBoolConversions*/ getLangOpts().ZVector,
+                          /*AllowBooleanOperation*/ false);
   if (vType.isNull())
     return vType;
 
@@ -12055,8 +12078,9 @@
   // Ensure that either both operands are of the same vector type, or
   // one operand is of a vector type and the other is of its element type.
   QualType vType = CheckVectorOperands(LHS, RHS, Loc, false,
-                                       /*AllowBothBool*/true,
-                                       /*AllowBoolConversions*/false);
+                                       /*AllowBothBool*/ true,
+                                       /*AllowBoolConversions*/ false,
+                                       /*AllowBooleanOperation*/ false);
   if (vType.isNull())
     return InvalidOperands(Loc, LHS, RHS);
   if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 &&
@@ -12115,6 +12139,20 @@
   return InvalidOperands(Loc, LHS, RHS);
 }
 
+static bool isLegalBoolVectorBinaryOp(BinaryOperatorKind Opc) {
+  switch (Opc) {
+  default:
+    return false;
+  case BO_And:
+  case BO_AndAssign:
+  case BO_Or:
+  case BO_OrAssign:
+  case BO_Xor:
+  case BO_XorAssign:
+    return true;
+  }
+}
+
 inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
                                            SourceLocation Loc,
                                            BinaryOperatorKind Opc) {
@@ -12123,13 +12161,17 @@
   bool IsCompAssign =
       Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign;
 
+  bool LegalBoolVecOperator = isLegalBoolVectorBinaryOp(Opc);
+
   if (LHS.get()->getType()->isVectorType() ||
       RHS.get()->getType()->isVectorType()) {
     if (LHS.get()->getType()->hasIntegerRepresentation() &&
         RHS.get()->getType()->hasIntegerRepresentation())
-      return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign,
-                        /*AllowBothBool*/true,
-                        /*AllowBoolConversions*/getLangOpts().ZVector);
+      return CheckVectorOperands(
+          LHS, RHS, Loc, IsCompAssign,
+          /*AllowBothBool*/ true,
+          /*AllowBoolConversions*/ getLangOpts().ZVector,
+          /*AllowBooleanOperation*/ LegalBoolVecOperator);
     return InvalidOperands(Loc, LHS, RHS);
   }
 
Index: clang/lib/CodeGen/CodeGenTypes.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenTypes.cpp
+++ clang/lib/CodeGen/CodeGenTypes.cpp
@@ -91,6 +91,18 @@
 
   llvm::Type *R = ConvertType(T);
 
+  // Check for the boolean vector case
+  auto FixedVT = dyn_cast<llvm::FixedVectorType>(R);
+  if (T->isVectorType() && FixedVT &&
+      FixedVT->getElementType()->isIntegerTy(1)) {
+
+    // Find the smallest power-of-two integer that accomodates the boolean
+    // vector. eg <17 x i1> is stored as i32 <8 x i1> is stored as i8 <3 x i1>
+    // is stored as i8
+    uint64_t PaddedSize = getBoolVectorPaddedSize(FixedVT->getNumElements());
+    return llvm::IntegerType::get(FixedVT->getContext(), PaddedSize);
+  }
+
   // If this is a bool type, or an ExtIntType in a bitfield representation,
   // map this integer to the target-specified size.
   if ((ForBitField && T->isExtIntType()) || R->isIntegerTy(1))
@@ -649,8 +661,10 @@
   case Type::ExtVector:
   case Type::Vector: {
     const VectorType *VT = cast<VectorType>(Ty);
-    ResultType = llvm::FixedVectorType::get(ConvertType(VT->getElementType()),
-                                            VT->getNumElements());
+    llvm::Type *IRElemTy = VT->getElementType()->isBooleanType()
+                               ? llvm::Type::getInt1Ty(getLLVMContext())
+                               : ConvertType(VT->getElementType());
+    ResultType = llvm::VectorType::get(IRElemTy, VT->getNumElements());
     break;
   }
   case Type::ConstantMatrix: {
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -4344,6 +4344,11 @@
   /// Set the codegen fast-math flags.
   void SetFastMathFlags(FPOptions FPFeatures);
 
+  // Truncate or extend a boolean vector to the requested number of elements.
+  llvm::Value *emitBoolVecConversion(llvm::Value *SrcVec,
+                                     unsigned NumElementsDst,
+                                     const llvm::Twine &Name = "");
+
 private:
   llvm::MDNode *getRangeForLoadFromType(QualType Ty);
   void EmitReturnOfRValue(RValue RV, QualType Ty);
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -2453,3 +2453,22 @@
 
   return llvm::DebugLoc();
 }
+
+llvm::Value *CodeGenFunction::emitBoolVecConversion(llvm::Value *SrcVec,
+                                                    unsigned NumElementsDst,
+                                                    const llvm::Twine &Name) {
+  auto SrcTy = cast<llvm::FixedVectorType>(SrcVec->getType());
+  unsigned NumElementsSrc = SrcTy->getNumElements();
+  if (NumElementsSrc == NumElementsDst) {
+    return SrcVec;
+  }
+
+  std::vector<int> ShuffleMask(NumElementsDst, -1);
+  for (unsigned MaskIdx = 0;
+       MaskIdx < std::min<>(NumElementsDst, NumElementsSrc); ++MaskIdx) {
+    ShuffleMask[MaskIdx] = MaskIdx;
+  }
+
+  return Builder.CreateShuffleVector(SrcVec, llvm::UndefValue::get(SrcTy),
+                                     ShuffleMask, Name);
+}
Index: clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
===================================================================
--- clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -586,7 +586,8 @@
 
 void CGRecordLowering::clipTailPadding() {
   std::vector<MemberInfo>::iterator Prior = Members.begin();
-  CharUnits Tail = getSize(Prior->Data);
+  CharUnits Tail =
+      getSize(Prior->Data); // FIXME assumes `i8` multiples for boolean vector!
   for (std::vector<MemberInfo>::iterator Member = Prior + 1,
                                          MemberEnd = Members.end();
        Member != MemberEnd; ++Member) {
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -2071,7 +2071,30 @@
           CGF.getDebugInfo()->
               addHeapAllocSiteMetadata(CI, CE->getType(), CE->getExprLoc());
 
-    return Builder.CreateBitCast(Src, DstTy);
+    // SExt/Trunc Boolean vectors to fit the expected type
+    auto VecSrcTy = dyn_cast<llvm::VectorType>(Src->getType());
+    auto VecDstTy = dyn_cast<llvm::VectorType>(DstTy);
+    bool VectorElementCast =
+        VecSrcTy && VecDstTy &&
+        (VecSrcTy->getElementCount() == VecDstTy->getElementCount());
+    if (VecSrcTy && VecSrcTy->getElementType()->isIntegerTy(1)) {
+      // When casting with the same element count extend this to the native
+      // result size Otw, signextend to 'i8' as an intermediary
+      unsigned DstElemBits =
+          VectorElementCast ? DstTy->getScalarSizeInBits() : 8;
+
+      auto PlainIntTy = llvm::VectorType::get(Builder.getIntNTy(DstElemBits),
+                                              VecSrcTy->getElementCount());
+      Src = Builder.CreateSExt(Src, PlainIntTy);
+    }
+    Src = Builder.CreateBitCast(Src, DstTy);
+    if (VectorElementCast && VecDstTy->getElementType()->isIntegerTy(1)) {
+      auto PlainIntTy =
+          llvm::VectorType::get(Builder.getIntNTy(SrcTy->getScalarSizeInBits()),
+                                VecSrcTy->getElementCount());
+      Src = Builder.CreateTrunc(Src, PlainIntTy);
+    }
+    return Src;
   }
   case CK_AddressSpaceConversion: {
     Expr::EvalResult Result;
@@ -4639,6 +4662,17 @@
   return Builder.CreateIntToPtr(Src, DstTy, Name);
 }
 
+static bool IsGenericBoolVector(QualType Ty) {
+  auto ClangVecTy = dyn_cast<VectorType>(Ty);
+  if (!ClangVecTy)
+    return false;
+
+  if (ClangVecTy->getVectorKind() != VectorType::GenericVector)
+    return false;
+
+  return ClangVecTy->getElementType()->isBooleanType();
+}
+
 Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
   Value *Src  = CGF.EmitScalarExpr(E->getSrcExpr());
   llvm::Type *DstTy = ConvertType(E->getType());
@@ -4649,6 +4683,11 @@
   unsigned NumElementsDst = isa<llvm::VectorType>(DstTy) ?
     cast<llvm::VectorType>(DstTy)->getNumElements() : 0;
 
+  // Use bit vector expansion for generic boolean vectors
+  if (IsGenericBoolVector(E->getType())) {
+    return CGF.emitBoolVecConversion(Src, NumElementsDst, "astype");
+  }
+
   // Going from vec3 to non-vec3 is a special case and requires a shuffle
   // vector to get a vec4, then a bitcast if the target type is different.
   if (NumElementsSrc == 3 && NumElementsDst != 3) {
@@ -4668,7 +4707,7 @@
   // get a vec3.
   if (NumElementsSrc != 3 && NumElementsDst == 3) {
     if (!CGF.CGM.getCodeGenOpts().PreserveVec3Type) {
-      auto *Vec4Ty = llvm::FixedVectorType::get(
+      auto Vec4Ty = llvm::VectorType::get(
           cast<llvm::VectorType>(DstTy)->getElementType(), 4);
       Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src,
                                          Vec4Ty);
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -1669,27 +1669,47 @@
                                                LValueBaseInfo BaseInfo,
                                                TBAAAccessInfo TBAAInfo,
                                                bool isNontemporal) {
-  if (!CGM.getCodeGenOpts().PreserveVec3Type) {
-    // For better performance, handle vector loads differently.
-    if (Ty->isVectorType()) {
-      const llvm::Type *EltTy = Addr.getElementType();
-
-      const auto *VTy = cast<llvm::VectorType>(EltTy);
-
-      // Handle vectors of size 3 like size 4 for better performance.
-      if (VTy->getNumElements() == 3) {
-
-        // Bitcast to vec4 type.
-        auto *vec4Ty = llvm::FixedVectorType::get(VTy->getElementType(), 4);
-        Address Cast = Builder.CreateElementBitCast(Addr, vec4Ty, "castToVec4");
-        // Now load value.
-        llvm::Value *V = Builder.CreateLoad(Cast, Volatile, "loadVec4");
-
-        // Shuffle vector to get vec3.
-        V = Builder.CreateShuffleVector(V, llvm::UndefValue::get(vec4Ty),
-                                        ArrayRef<int>{0, 1, 2}, "extractVec");
-        return EmitFromMemory(V, Ty);
-      }
+  auto ClangVecTy = Ty->getAs<VectorType>();
+  if (ClangVecTy) {
+    QualType ClangElemTy = ClangVecTy->getElementType();
+    // Boolean vectors use `iN` as storage type
+    if (ClangVecTy->getVectorKind() == VectorType::GenericVector &&
+        ClangElemTy->isBooleanType()) {
+      llvm::Type *ValTy = ConvertType(Ty);
+      unsigned ValNumElems =
+          cast<llvm::FixedVectorType>(ValTy)->getNumElements();
+      // Load the `iP` storage object (P is the padded vector size).
+      auto RawIntV = Builder.CreateLoad(Addr, Volatile, "load_bits");
+      auto RawIntTy = RawIntV->getType();
+      assert(RawIntTy->isIntegerTy() && "compressed iN storage for bitvectors");
+      // Bitcast iP --> <P x i1>
+      auto PaddedVecTy = llvm::VectorType::get(
+          Builder.getInt1Ty(), RawIntTy->getPrimitiveSizeInBits());
+      llvm::Value *V = Builder.CreateBitCast(RawIntV, PaddedVecTy);
+      // Shuffle <P x i1> --> <N x i1> (N is the actual bit size)
+      V = emitBoolVecConversion(V, ValNumElems, "extractvec");
+
+      return EmitFromMemory(V, Ty);
+    }
+
+    // Handle vectors of size 3 like size 4 for better performance.
+    const llvm::Type *EltTy = Addr.getElementType();
+    const auto *IRVecTy = cast<llvm::VectorType>(EltTy);
+
+    if (!CGM.getCodeGenOpts().PreserveVec3Type &&
+        IRVecTy->getNumElements() == 3) {
+
+      // Bitcast to vec4 type.
+      llvm::VectorType *vec4Ty =
+          llvm::VectorType::get(IRVecTy->getElementType(), 4);
+      Address Cast = Builder.CreateElementBitCast(Addr, vec4Ty, "castToVec4");
+      // Now load value.
+      llvm::Value *V = Builder.CreateLoad(Cast, Volatile, "loadVec4");
+
+      // Shuffle vector to get vec3.
+      V = Builder.CreateShuffleVector(V, llvm::UndefValue::get(vec4Ty),
+                                      ArrayRef<int>{0, 1, 2}, "extractVec");
+      return EmitFromMemory(V, Ty);
     }
   }
 
@@ -1785,18 +1805,29 @@
                                         LValueBaseInfo BaseInfo,
                                         TBAAAccessInfo TBAAInfo,
                                         bool isInit, bool isNontemporal) {
-  if (!CGM.getCodeGenOpts().PreserveVec3Type) {
-    // Handle vectors differently to get better performance.
-    if (Ty->isVectorType()) {
-      llvm::Type *SrcTy = Value->getType();
-      auto *VecTy = dyn_cast<llvm::VectorType>(SrcTy);
+  llvm::Type *SrcTy = Value->getType();
+  auto ClangVecTy = Ty->getAs<VectorType>();
+  if (ClangVecTy) {
+    QualType ClangElemTy = ClangVecTy->getElementType();
+    auto *IRVecTy = dyn_cast<llvm::FixedVectorType>(SrcTy);
+    if (ClangElemTy->isBooleanType() &&
+        ClangVecTy->getVectorKind() == VectorType::GenericVector) {
+      auto MemIntTy =
+          cast<llvm::IntegerType>(Addr.getType()->getPointerElementType());
+      // Expand to the memory bit width
+      unsigned MemNumElems = MemIntTy->getPrimitiveSizeInBits();
+      // <N x i1> --> <P x i1>
+      Value = emitBoolVecConversion(Value, MemNumElems, "insertvec");
+      // <P x i1> --> iP
+      Value = Builder.CreateBitCast(Value, MemIntTy);
+    } else if (!CGM.getCodeGenOpts().PreserveVec3Type) {
       // Handle vec3 special.
-      if (VecTy && VecTy->getNumElements() == 3) {
+      if (IRVecTy && IRVecTy->getNumElements() == 3) {
         // Our source is a vec3, do a shuffle vector to make it a vec4.
-        Value = Builder.CreateShuffleVector(Value, llvm::UndefValue::get(VecTy),
-                                            ArrayRef<int>{0, 1, 2, -1},
-                                            "extractVec");
-        SrcTy = llvm::FixedVectorType::get(VecTy->getElementType(), 4);
+        Value = Builder.CreateShuffleVector(
+            Value, llvm::UndefValue::get(IRVecTy), ArrayRef<int>{0, 1, 2, -1},
+            "extractVec");
+        SrcTy = llvm::FixedVectorType::get(IRVecTy->getElementType(), 4);
       }
       if (Addr.getElementType() != SrcTy) {
         Addr = Builder.CreateElementBitCast(Addr, SrcTy, "storetmp");
@@ -2018,8 +2049,19 @@
       // Read/modify/write the vector, inserting the new element.
       llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddress(),
                                             Dst.isVolatileQualified());
+      auto IRStoreTy = dyn_cast<llvm::IntegerType>(Vec->getType());
+      if (IRStoreTy) {
+        auto IRVecTy = llvm::VectorType::get(
+            Builder.getInt1Ty(), IRStoreTy->getPrimitiveSizeInBits());
+        Vec = Builder.CreateBitCast(Vec, IRVecTy);
+        // iN --> <N x i1>
+      }
       Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(),
                                         Dst.getVectorIdx(), "vecins");
+      if (IRStoreTy) {
+        // <N x i1> --> <iN>
+        Vec = Builder.CreateBitCast(Vec, IRStoreTy);
+      }
       Builder.CreateStore(Vec, Dst.getVectorAddress(),
                           Dst.isVolatileQualified());
       return;
Index: clang/lib/AST/TypePrinter.cpp
===================================================================
--- clang/lib/AST/TypePrinter.cpp
+++ clang/lib/AST/TypePrinter.cpp
@@ -645,13 +645,18 @@
     printBefore(T->getElementType(), OS);
     break;
   case VectorType::GenericVector: {
-    // FIXME: We prefer to print the size directly here, but have no way
-    // to get the size of the type.
-    OS << "__attribute__((__vector_size__("
-       << T->getNumElements()
-       << " * sizeof(";
-    print(T->getElementType(), OS, StringRef());
-    OS << ")))) ";
+    if (T->getElementType()->isBooleanType()) {
+      // For a vector of boolean, the vector_size parameter is the number of
+      // bits.
+      OS << "__attribute__((__vector_size__(" << T->getNumElements() << "))) ";
+    } else {
+      // FIXME: We prefer to print the size directly here, but have no way
+      // to get the size of the type.
+      OS << "__attribute__((__vector_size__(" << T->getNumElements()
+         << " * sizeof(";
+      print(T->getElementType(), OS, StringRef());
+      OS << ")))) ";
+    }
     printBefore(T->getElementType(), OS);
     break;
   }
@@ -696,9 +701,13 @@
     OS << "__attribute__((__vector_size__(";
     if (T->getSizeExpr())
       T->getSizeExpr()->printPretty(OS, nullptr, Policy);
-    OS << " * sizeof(";
-    print(T->getElementType(), OS, StringRef());
-    OS << ")))) ";
+    if (T->getElementType()->isBooleanType()) {
+      OS << "))) ";
+    } else {
+      OS << " * sizeof(";
+      print(T->getElementType(), OS, StringRef());
+      OS << ")))) ";
+    }
     printBefore(T->getElementType(), OS);
     break;
   }
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -103,6 +103,20 @@
   Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank
 };
 
+unsigned getBoolVectorPaddedSize(unsigned TypeNumBits) {
+  const unsigned MinimalSize = 8; // FIXME Target->getCharWidth()
+  TypeNumBits = std::max<>(MinimalSize, TypeNumBits);
+
+  // Pad to the next power of two if above
+  bool IsNotPowerOfTwo = (TypeNumBits & (TypeNumBits - 1));
+  if (IsNotPowerOfTwo) {
+    TypeNumBits = llvm::NextPowerOf2(TypeNumBits);
+  }
+
+  assert(TypeNumBits != 0);
+  return TypeNumBits;
+}
+
 /// \returns location that is relevant when searching for Doc comments related
 /// to \p D.
 static SourceLocation getDeclLocForCommentSearch(const Decl *D,
@@ -1915,11 +1929,17 @@
     break;
   }
 
-  case Type::ExtVector:
-  case Type::Vector: {
+  case Type::Vector:
+  case Type::ExtVector: {
     const auto *VT = cast<VectorType>(T);
-    TypeInfo EltInfo = getTypeInfo(VT->getElementType());
-    Width = EltInfo.Width * VT->getNumElements();
+    bool IsBoolVector = VT->getElementType()->isBooleanType();
+    // 'vector_size' bool vectors are supported
+    if (IsBoolVector && (T->getTypeClass() == Type::Vector)) {
+      Width = getBoolVectorPaddedSize(VT->getNumElements());
+    } else {
+      TypeInfo EltInfo = getTypeInfo(VT->getElementType());
+      Width = EltInfo.Width * VT->getNumElements();
+    }
     Align = Width;
     // If the alignment is not a power of 2, round up to the next power of 2.
     // This happens for non-power-of-2 length vectors.
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -11202,7 +11202,8 @@
   /// type checking for vector binary operators.
   QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
                                SourceLocation Loc, bool IsCompAssign,
-                               bool AllowBothBool, bool AllowBoolConversion);
+                               bool AllowBothBool, bool AllowBoolConversion,
+                               bool AllowBoolOperation);
   QualType GetSignedVectorType(QualType V);
   QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
                                       SourceLocation Loc,
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -3138,4 +3138,6 @@
   return Value;
 }
 
+unsigned getBoolVectorPaddedSize(unsigned TypeNumBits);
+
 #endif // LLVM_CLANG_AST_ASTCONTEXT_H
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -433,6 +433,61 @@
     return v;
   }
 
+
+GCC vector types are created using the ``vector_size`` attribute.  Different
+than GCC, Clang also allows the attribute to be used with boolean element types.
+For example:
+
+.. code-block:: c++
+
+  typedef int int4 __attribute__((vector_size(16)));
+
+  int4 foo(int4 a) {
+    int4 v;
+    v = a;
+    return v;
+  }
+
+
+Boolean Vectors
+---------------
+
+.. code-block:: c++
+
+  // legal for Clang, error for GCC:
+  typedef bool bool8 __attribute__((vector_size(8)));
+  // Objects of bool8 type hold 8 bits, sizeof(bool8) == 1
+
+  bool8 foo(bool8 a) {
+    bool8 v;
+    v = a;
+    return v;
+  }
+
+Boolean vectors are a Clang extension of the GCC vector type
+(`attribute(vector_size)`).  Boolean vectors are intended, though not
+guaranteed, to map to vector mask registers.  The semantics of boolean vectors
+differs from the GCC vector of integer or floating point type.  This is mostly
+because bits are smaller than the smallest addressable unit in memory on most
+architectures.  The size parameter of a boolean vector type is the number of
+bits in the vector (for all non-bool vectors, the number refers to the number
+of bytes in the vector).
+
+The semantics of boolean vectors borrows from C bit-fields with the following
+differences:
+
+* Distinct boolean vectors are always distinct memory objects (there is no
+  packing).
+* Bitwise `~`, `|`, `&`, `^` and `~` are the only allowed operators on boolean
+  vectors.
+
+The memory representation of a boolean vector is the smallest fitting
+power-of-two integer with at least eight bits (`sizeof(char)`)'. The alignment
+is the alignment of that integer type.  This permits the use of these types in
+allocated arrays using the common ``sizeof(Array)/sizeof(ElementType)``
+pattern.
+
+
 Vector Literals
 ---------------
 
@@ -484,6 +539,7 @@
 reinterpret_cast                 yes     no        yes         no
 static_cast                      yes     no        yes         no
 const_cast                       no      no        no          no
+address &v[i]                    no      no        no [#]_     no
 ============================== ======= ======= ============= =======
 
 See also :ref:`langext-__builtin_shufflevector`, :ref:`langext-__builtin_convertvector`.
@@ -494,6 +550,9 @@
   it's only available in C++ and uses normal bool conversions (that is, != 0).
   If it's an extension (OpenCL) vector, it's only available in C and OpenCL C.
   And it selects base on signedness of the condition operands (OpenCL v1.1 s6.3.9).
+.. [#] Clang does not allow the address of an element to be taken while GCC
+   allows this. This is intentional for vectors with a boolean element type and
+   not implemented otherwise.
 
 Matrix Types
 ============
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to