simoll created this revision.
simoll added reviewers: hfinkel, erichkeane, craig.topper, rsandifo-arm, kaz7, 
k-ishizaka.
simoll added a project: clang.
Herald added subscribers: cfe-commits, kristof.beyls.
Herald added a reviewer: rengolin.
simoll updated this revision to Diff 268140.
simoll added a comment.

NFC. Undid stray change.


This patch extends Clang to allow 'bool' as a valid vector element type 
(attribute `vector_size`).

This is the natural type for SIMD masks and facilitates clean vector intrinsic 
declarations.
Vectors of i1 are supported on IR level and below down to many SIMD ISAs, such 
as AVX512, ARM SVE (fixed vector length) and the VE target (NEC SX-Aurora 
TSUBASA).

The RFC on cfe-dev: 
https://lists.llvm.org/pipermail/cfe-dev/2020-May/065434.html


Repository:
  rG LLVM Github Monorepo

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