[llvm] [clang] [clang-tools-extra] [HLSL] Vector standard conversions (PR #71098)

Chris B via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 13 17:56:46 PST 2023


https://github.com/llvm-beanz updated https://github.com/llvm/llvm-project/pull/71098

>From 91e8d9d9f63fe2ac481bb01549e3d69ac59d68f8 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Wed, 1 Nov 2023 12:18:43 -0500
Subject: [PATCH 1/7] [HLSL] Vector vector standard conversions

HLSL supports vector truncation and element conversions as part of
standard conversion sequences. The vector truncation conversion is a C++
second conversion in the conversion sequence. If a vector truncation is
in a conversion sequence an element conversion may occur after it before
the standard C++ third conversion.

Vector element conversions can be boolean conversions, floating point or
integral conversions or promotions.

[HLSL Draft
Specification](https://microsoft.github.io/hlsl-specs/specs/hlsl.pdf)

../clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hl
sl
../clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl
../clang/test/SemaHLSL/standard_conversion_sequences.hlsl
---
 clang/include/clang/AST/OperationKinds.def    |   3 +
 .../clang/Basic/DiagnosticSemaKinds.td        |   3 +
 clang/include/clang/Sema/Overload.h           |  12 +-
 clang/lib/AST/Expr.cpp                        |   1 +
 clang/lib/AST/ExprConstant.cpp                |   2 +
 clang/lib/CodeGen/CGExpr.cpp                  |   2 +
 clang/lib/CodeGen/CGExprAgg.cpp               |   2 +
 clang/lib/CodeGen/CGExprComplex.cpp           |   1 +
 clang/lib/CodeGen/CGExprConstant.cpp          |   1 +
 clang/lib/CodeGen/CGExprScalar.cpp            |  23 +-
 clang/lib/Edit/RewriteObjCFoundationAPI.cpp   |   4 +
 clang/lib/Sema/SemaChecking.cpp               |  11 +-
 clang/lib/Sema/SemaExprCXX.cpp                |  84 ++++++
 clang/lib/Sema/SemaInit.cpp                   |   2 +-
 clang/lib/Sema/SemaOverload.cpp               | 281 +++++++++++-------
 clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp |   3 +-
 .../standard_conversion_sequences.hlsl        | 119 ++++++++
 .../BuiltIns/vector-constructors-erros.hlsl   |   2 +-
 .../standard_conversion_sequences.hlsl        |  92 ++++++
 19 files changed, 536 insertions(+), 112 deletions(-)
 create mode 100644 clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl
 create mode 100644 clang/test/SemaHLSL/standard_conversion_sequences.hlsl

diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def
index 8dd98730dff742..e497fe4d1f93ff 100644
--- a/clang/include/clang/AST/OperationKinds.def
+++ b/clang/include/clang/AST/OperationKinds.def
@@ -361,6 +361,9 @@ CAST_OPERATION(AddressSpaceConversion)
 // Convert an integer initializer to an OpenCL sampler.
 CAST_OPERATION(IntToOCLSampler)
 
+// Truncate a vector type (HLSL only).
+CAST_OPERATION(VectorTruncation)
+
 //===- Binary Operations  -------------------------------------------------===//
 // Operators listed in order of precedence.
 // Note that additions to this should also update the StmtVisitor class,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d164177251e4db..6f21674d21fa54 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12023,6 +12023,9 @@ def err_hlsl_operator_unsupported : Error<
 def err_hlsl_param_qualifier_mismatch :
   Error<"conflicting parameter qualifier %0 on parameter %1">;
 
+def warn_hlsl_impcast_vector_truncation : Warning<
+  "implicit conversion truncates vector: %0 to %1">, InGroup<Conversion>;
+
 // Layout randomization diagnostics.
 def err_non_designated_init_used : Error<
   "a randomized struct can only be initialized with a designated initializer">;
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 6ccabad3af5446..2f93fee4d9806a 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -195,6 +195,9 @@ class Sema;
     /// Fixed point type conversions according to N1169.
     ICK_Fixed_Point_Conversion,
 
+    /// HLSL vector truncation.
+    ICK_HLSL_Vector_Truncation,
+
     /// The number of conversion kinds
     ICK_Num_Conversion_Kinds,
   };
@@ -271,6 +274,12 @@ class Sema;
     /// pointer-to-member conversion, or boolean conversion.
     ImplicitConversionKind Second : 8;
 
+    /// Element - Between the second and third conversion a vector or matrix
+    /// element conversion may occur. If this is not ICK_Identity this
+    /// conversion is applied element-wise to each element in the vector or
+    /// matrix.
+    ImplicitConversionKind Element : 8;
+
     /// Third - The third conversion can be a qualification conversion
     /// or a function conversion.
     ImplicitConversionKind Third : 8;
@@ -357,7 +366,8 @@ class Sema;
     void setAsIdentityConversion();
 
     bool isIdentityConversion() const {
-      return Second == ICK_Identity && Third == ICK_Identity;
+      return Second == ICK_Identity && Element == ICK_Identity &&
+             Third == ICK_Identity;
     }
 
     ImplicitConversionRank getRank() const;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 55c6b732b7081f..bfbdb6cf0f929d 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1898,6 +1898,7 @@ bool CastExpr::CastConsistency() const {
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
   case CK_MatrixCast:
+  case CK_VectorTruncation:
     assert(!getType()->isBooleanType() && "unheralded conversion to bool");
     goto CheckNoBasePath;
 
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 16697e5f076a8f..24c12cd0fd939d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13875,6 +13875,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_FixedPointCast:
   case CK_IntegralToFixedPoint:
   case CK_MatrixCast:
+  case CK_VectorTruncation:
     llvm_unreachable("invalid cast kind for integral value");
 
   case CK_BitCast:
@@ -14713,6 +14714,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
   case CK_MatrixCast:
+  case CK_VectorTruncation:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_LValueToRValue:
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 9d1f1a58f9e1c5..9101f81c718b71 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4933,6 +4933,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
   case CK_MatrixCast:
+  case CK_VectorTruncation:
     return EmitUnsupportedLValue(E, "unexpected cast lvalue");
 
   case CK_Dependent:
@@ -5060,6 +5061,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
     return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(),
                           CGM.getTBAAInfoForSubobject(LV, E->getType()));
   }
+
   case CK_ZeroToOCLOpaqueType:
     llvm_unreachable("NULL to OpenCL opaque type lvalue cast is not valid");
 
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 810b28f25fa18b..f9278133e5ddc6 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -930,6 +930,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
   case CK_BuiltinFnToFnPtr:
   case CK_ZeroToOCLOpaqueType:
   case CK_MatrixCast:
+  case CK_VectorTruncation:
 
   case CK_IntToOCLSampler:
   case CK_FloatingToFixedPoint:
@@ -1454,6 +1455,7 @@ static bool castPreservesZero(const CastExpr *CE) {
   case CK_MatrixCast:
   case CK_NonAtomicToAtomic:
   case CK_AtomicToNonAtomic:
+  case CK_VectorTruncation:
     return true;
 
   case CK_BaseToDerivedMemberPointer:
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index f3cbd1d0451ebe..45862701d59bb4 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -556,6 +556,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
   case CK_MatrixCast:
+  case CK_VectorTruncation:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_FloatingRealToComplex:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 604e3958161db2..577eee2ee1ff0f 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1225,6 +1225,7 @@ class ConstExprEmitter :
     case CK_IntegralToFixedPoint:
     case CK_ZeroToOCLOpaqueType:
     case CK_MatrixCast:
+    case CK_VectorTruncation:
       return nullptr;
     }
     llvm_unreachable("Invalid CastKind");
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 378437364767f6..7b57f33865c03b 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -610,6 +610,8 @@ class ScalarExprEmitter
   llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
                                        bool isInc, bool isPre);
 
+  llvm::Value *EmitVectorElementConversion(QualType SrcType, QualType DstType,
+                                           llvm::Value *Src);
 
   Value *VisitUnaryAddrOf(const UnaryOperator *E) {
     if (isa<MemberPointerType>(E->getType())) // never sugared
@@ -1422,6 +1424,9 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
     return Builder.CreateVectorSplat(NumElements, Src, "splat");
   }
 
+  if (SrcType->isExtVectorType() && DstType->isExtVectorType())
+    return EmitVectorElementConversion(SrcType, DstType, Src);
+
   if (SrcType->isMatrixType() && DstType->isMatrixType())
     return EmitScalarCast(Src, SrcType, DstType, SrcTy, DstTy, Opts);
 
@@ -1701,10 +1706,14 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
 }
 
 Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
-  QualType SrcType = E->getSrcExpr()->getType(),
-           DstType = E->getType();
+  QualType SrcType = E->getSrcExpr()->getType(), DstType = E->getType();
+  Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
+  return EmitVectorElementConversion(SrcType, DstType, Src);
+}
 
-  Value *Src  = CGF.EmitScalarExpr(E->getSrcExpr());
+llvm::Value *ScalarExprEmitter::EmitVectorElementConversion(QualType SrcType,
+                                                            QualType DstType,
+                                                            Value *Src) {
 
   SrcType = CGF.getContext().getCanonicalType(SrcType);
   DstType = CGF.getContext().getCanonicalType(DstType);
@@ -2466,6 +2475,14 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
   case CK_IntToOCLSampler:
     return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
 
+  case CK_VectorTruncation: {
+    assert(DestTy->isVectorType() && "Expected dest type to be vector type");
+    Value *Vec = Visit(const_cast<Expr *>(E));
+    SmallVector<int, 16> Mask;
+    Mask.insert(Mask.begin(), DestTy->getAs<VectorType>()->getNumElements(), 0);
+    return Builder.CreateShuffleVector(Vec, Mask, "trunc");
+  }
+
   } // end of switch
 
   llvm_unreachable("unknown scalar cast");
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index adb34eba497030..d42532cc15d27e 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1087,6 +1087,10 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
     case CK_BooleanToSignedIntegral:
       llvm_unreachable("OpenCL-specific cast in Objective-C?");
 
+    case CK_VectorTruncation:
+      llvm_unreachable("HLSL-specific cast in Objective-C?");
+      break;
+
     case CK_FloatingToFixedPoint:
     case CK_FixedPointToFloating:
     case CK_FixedPointCast:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 9dfff132cd88db..4d35dc35139a32 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -15433,11 +15433,18 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
       if (S.SourceMgr.isInSystemMacro(CC))
         return;
       return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar);
+    } else if (S.getLangOpts().HLSL &&
+               Target->getAs<VectorType>()->getNumElements() <
+                   Source->getAs<VectorType>()->getNumElements()) {
+      // Diagnose vector truncation but don't return. We may also want to
+      // diagnose an element conversion.
+      DiagnoseImpCast(S, E, T, CC, diag::warn_hlsl_impcast_vector_truncation);
     }
 
     // If the vector cast is cast between two vectors of the same size, it is
-    // a bitcast, not a conversion.
-    if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target))
+    // a bitcast, not a conversion, except under HLSL where it is a conversion.
+    if (!S.getLangOpts().HLSL &&
+        S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target))
       return;
 
     Source = cast<VectorType>(Source)->getElementType().getTypePtr();
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 081b568762ae22..5052af7905ca14 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4763,6 +4763,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
                              CK_ZeroToOCLOpaqueType,
                              From->getValueKind()).get();
     break;
+  case ICK_HLSL_Vector_Truncation: {
+    // Note: HLSL vectors are ExtVectors. Since this truncates a vector to a
+    // smaller vector, this can only operate on arguments where the source and
+    // destination types are ExtVectors.
+    auto *FromVec = From->getType()->castAs<ExtVectorType>();
+    auto *ToVec = ToType->castAs<ExtVectorType>();
+    QualType ElType = FromVec->getElementType();
+    QualType TruncTy =
+        Context.getExtVectorType(ElType, ToVec->getNumElements());
+    From = ImpCastExprToType(From, TruncTy, CK_VectorTruncation,
+                             From->getValueKind())
+               .get();
+    break;
+  }
 
   case ICK_Lvalue_To_Rvalue:
   case ICK_Array_To_Pointer:
@@ -4775,6 +4789,76 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
     llvm_unreachable("Improper second standard conversion");
   }
 
+  if (SCS.Element != ICK_Identity) {
+    // if SCS.Element is not ICK_Identity the To and From types must be HLSL
+    // vectors or matrices. HLSL matrices aren't yet supported so this code only
+    // handles vectors for now.
+
+    assert(From->getType()->isVectorType() && ToType->isVectorType() &&
+           "Element conversion is only supported for vector types.");
+    assert(From->getType()->getAs<VectorType>()->getNumElements() ==
+               ToType->getAs<VectorType>()->getNumElements() &&
+           "Element conversion is only supported for vectors with the same "
+           "element counts.");
+    QualType FromElTy = From->getType()->getAs<VectorType>()->getElementType();
+    unsigned NumElts = ToType->getAs<VectorType>()->getNumElements();
+    switch (SCS.Element) {
+    case ICK_Identity:
+      // Nothing to do.
+      break;
+    case ICK_Boolean_Conversion:
+      // Perform half-to-boolean conversion via float.
+      if (FromElTy->isHalfType()) {
+        QualType FPExtType = Context.getExtVectorType(FromElTy, NumElts);
+        From = ImpCastExprToType(From, FPExtType, CK_FloatingCast).get();
+        FromType = FPExtType;
+      }
+
+      From =
+          ImpCastExprToType(From, ToType, ScalarTypeToBooleanCastKind(FromElTy),
+                            VK_PRValue,
+                            /*BasePath=*/nullptr, CCK)
+              .get();
+      break;
+    case ICK_Integral_Promotion:
+    case ICK_Integral_Conversion:
+      if (ToType->isBooleanType()) {
+        assert(FromType->castAs<EnumType>()->getDecl()->isFixed() &&
+               SCS.Second == ICK_Integral_Promotion &&
+               "only enums with fixed underlying type can promote to bool");
+        From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, VK_PRValue,
+                                 /*BasePath=*/nullptr, CCK)
+                   .get();
+      } else {
+        From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_PRValue,
+                                 /*BasePath=*/nullptr, CCK)
+                   .get();
+      }
+      break;
+
+    case ICK_Floating_Promotion:
+    case ICK_Floating_Conversion:
+      From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_PRValue,
+                               /*BasePath=*/nullptr, CCK)
+                 .get();
+      break;
+    case ICK_Floating_Integral:
+      if (ToType->isRealFloatingType())
+        From =
+            ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_PRValue,
+                              /*BasePath=*/nullptr, CCK)
+                .get();
+      else
+        From =
+            ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_PRValue,
+                              /*BasePath=*/nullptr, CCK)
+                .get();
+      break;
+    default:
+      llvm_unreachable("Improper element standard conversion");
+    }
+  }
+
   switch (SCS.Third) {
   case ICK_Identity:
     // Nothing to do.
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 50ee0a5acb5586..b2f7eb65be3f13 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6427,7 +6427,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
   // For HLSL ext vector types we allow list initialization behavior for C++
   // constructor syntax. This is accomplished by converting initialization
   // arguments an InitListExpr late.
-  if (S.getLangOpts().HLSL && DestType->isExtVectorType() &&
+  if (S.getLangOpts().HLSL && Args.size() > 1 && DestType->isExtVectorType() &&
       (SourceType.isNull() ||
        !Context.hasSameUnqualifiedType(SourceType, DestType))) {
 
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 3a3e9234469d39..e3509546acc0c7 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -120,87 +120,88 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
                                 const StandardConversionSequence& SCS1,
                                 const StandardConversionSequence& SCS2);
 
+// clang-format off - disable clang format for this block.
 /// GetConversionRank - Retrieve the implicit conversion rank
 /// corresponding to the given implicit conversion kind.
 ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
-  static const ImplicitConversionRank
-    Rank[] = {
-    ICR_Exact_Match,
-    ICR_Exact_Match,
-    ICR_Exact_Match,
-    ICR_Exact_Match,
-    ICR_Exact_Match,
-    ICR_Exact_Match,
-    ICR_Promotion,
-    ICR_Promotion,
-    ICR_Promotion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_OCL_Scalar_Widening,
-    ICR_Complex_Real_Conversion,
-    ICR_Conversion,
-    ICR_Conversion,
-    ICR_Writeback_Conversion,
-    ICR_Exact_Match, // NOTE(gbiv): This may not be completely right --
-                     // it was omitted by the patch that added
-                     // ICK_Zero_Event_Conversion
-    ICR_Exact_Match, // NOTE(ctopper): This may not be completely right --
-                     // it was omitted by the patch that added
-                     // ICK_Zero_Queue_Conversion
-    ICR_C_Conversion,
-    ICR_C_Conversion_Extension,
-    ICR_Conversion,
+  static const ImplicitConversionRank Rank[] = {
+      ICR_Exact_Match,
+      ICR_Exact_Match,
+      ICR_Exact_Match,
+      ICR_Exact_Match,
+      ICR_Exact_Match,
+      ICR_Exact_Match,
+      ICR_Promotion,
+      ICR_Promotion,
+      ICR_Promotion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_OCL_Scalar_Widening,
+      ICR_Complex_Real_Conversion,
+      ICR_Conversion,
+      ICR_Conversion,
+      ICR_Writeback_Conversion,
+      ICR_Exact_Match, // NOTE(gbiv): This may not be completely right --
+                       // it was omitted by the patch that added
+                       // ICK_Zero_Event_Conversion
+      ICR_Exact_Match, // NOTE(ctopper): This may not be completely right --
+                       // it was omitted by the patch that added
+                       // ICK_Zero_Queue_Conversion
+      ICR_C_Conversion,
+      ICR_C_Conversion_Extension,
+      ICR_Conversion,
+      ICR_Conversion,
   };
   static_assert(std::size(Rank) == (int)ICK_Num_Conversion_Kinds);
   return Rank[(int)Kind];
 }
+// clang-format on
 
 /// GetImplicitConversionName - Return the name of this kind of
 /// implicit conversion.
-static const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
-  static const char* const Name[] = {
-    "No conversion",
-    "Lvalue-to-rvalue",
-    "Array-to-pointer",
-    "Function-to-pointer",
-    "Function pointer conversion",
-    "Qualification",
-    "Integral promotion",
-    "Floating point promotion",
-    "Complex promotion",
-    "Integral conversion",
-    "Floating conversion",
-    "Complex conversion",
-    "Floating-integral conversion",
-    "Pointer conversion",
-    "Pointer-to-member conversion",
-    "Boolean conversion",
-    "Compatible-types conversion",
-    "Derived-to-base conversion",
-    "Vector conversion",
-    "SVE Vector conversion",
-    "RVV Vector conversion",
-    "Vector splat",
-    "Complex-real conversion",
-    "Block Pointer conversion",
-    "Transparent Union Conversion",
-    "Writeback conversion",
-    "OpenCL Zero Event Conversion",
-    "OpenCL Zero Queue Conversion",
-    "C specific type conversion",
-    "Incompatible pointer conversion",
-    "Fixed point conversion",
-  };
+static const char *GetImplicitConversionName(ImplicitConversionKind Kind) {
+  static const char *const Name[] = {"No conversion",
+                                     "Lvalue-to-rvalue",
+                                     "Array-to-pointer",
+                                     "Function-to-pointer",
+                                     "Function pointer conversion",
+                                     "Qualification",
+                                     "Integral promotion",
+                                     "Floating point promotion",
+                                     "Complex promotion",
+                                     "Integral conversion",
+                                     "Floating conversion",
+                                     "Complex conversion",
+                                     "Floating-integral conversion",
+                                     "Pointer conversion",
+                                     "Pointer-to-member conversion",
+                                     "Boolean conversion",
+                                     "Compatible-types conversion",
+                                     "Derived-to-base conversion",
+                                     "Vector conversion",
+                                     "SVE Vector conversion",
+                                     "RVV Vector conversion",
+                                     "Vector splat",
+                                     "Complex-real conversion",
+                                     "Block Pointer conversion",
+                                     "Transparent Union Conversion",
+                                     "Writeback conversion",
+                                     "OpenCL Zero Event Conversion",
+                                     "OpenCL Zero Queue Conversion",
+                                     "C specific type conversion",
+                                     "Incompatible pointer conversion",
+                                     "Fixed point conversion",
+                                     "HLSL vector truncation"};
   static_assert(std::size(Name) == (int)ICK_Num_Conversion_Kinds);
   return Name[Kind];
 }
@@ -210,6 +211,7 @@ static const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
 void StandardConversionSequence::setAsIdentityConversion() {
   First = ICK_Identity;
   Second = ICK_Identity;
+  Element = ICK_Identity;
   Third = ICK_Identity;
   DeprecatedStringLiteralToCharPtr = false;
   QualificationIncludesObjCLifetime = false;
@@ -1843,13 +1845,86 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
   return true;
 }
 
+/// Determine whether the conversion from FromType to ToType is a valid
+/// floating point conversion.
+///
+static bool IsFloatingPointConversion(Sema &S, QualType FromType,
+                                      QualType ToType) {
+  if (!FromType->isRealFloatingType() || !ToType->isRealFloatingType())
+    return false;
+  // FIXME: disable conversions between long double, __ibm128 and __float128
+  // if their representation is different until there is back end support
+  // We of course allow this conversion if long double is really double.
+
+  // Conversions between bfloat16 and float16 are currently not supported.
+  if ((FromType->isBFloat16Type() &&
+       (ToType->isFloat16Type() || ToType->isHalfType())) ||
+      (ToType->isBFloat16Type() &&
+       (FromType->isFloat16Type() || FromType->isHalfType())))
+    return false;
+
+  // Conversions between IEEE-quad and IBM-extended semantics are not
+  // permitted.
+  const llvm::fltSemantics &FromSem = S.Context.getFloatTypeSemantics(FromType);
+  const llvm::fltSemantics &ToSem = S.Context.getFloatTypeSemantics(ToType);
+  if ((&FromSem == &llvm::APFloat::PPCDoubleDouble() &&
+       &ToSem == &llvm::APFloat::IEEEquad()) ||
+      (&FromSem == &llvm::APFloat::IEEEquad() &&
+       &ToSem == &llvm::APFloat::PPCDoubleDouble()))
+    return false;
+  return true;
+}
+
+static bool IsVectorElementConversion(Sema &S, QualType FromType,
+                                      QualType ToType,
+                                      ImplicitConversionKind &ICK, Expr *From) {
+  if (S.Context.hasSameUnqualifiedType(FromType, ToType))
+    return true;
+
+  if (IsFloatingPointConversion(S, FromType, ToType)) {
+    ICK = ICK_Floating_Conversion;
+    return true;
+  }
+
+  if (S.IsFloatingPointPromotion(FromType, ToType)) {
+    ICK = ICK_Floating_Promotion;
+    return true;
+  }
+
+  if (ToType->isBooleanType() && FromType->isArithmeticType()) {
+    ICK = ICK_Boolean_Conversion;
+    return true;
+  }
+
+  if (FromType->isIntegralOrUnscopedEnumerationType() &&
+      ToType->isIntegralType(S.Context)) {
+    ICK = ICK_Integral_Conversion;
+    return true;
+  }
+
+  if (S.IsIntegralPromotion(From, FromType, ToType)) {
+    ICK = ICK_Integral_Promotion;
+    return true;
+  }
+
+  if ((FromType->isRealFloatingType() && ToType->isIntegralType(S.Context)) ||
+      (FromType->isIntegralOrUnscopedEnumerationType() &&
+       ToType->isRealFloatingType())) {
+    ICK = ICK_Floating_Integral;
+    return true;
+  }
+
+  return false;
+}
+
 /// Determine whether the conversion from FromType to ToType is a valid
 /// vector conversion.
 ///
 /// \param ICK Will be set to the vector conversion kind, if this is a vector
 /// conversion.
 static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
-                               ImplicitConversionKind &ICK, Expr *From,
+                               ImplicitConversionKind &ICK,
+                               ImplicitConversionKind &ElConv, Expr *From,
                                bool InOverloadResolution, bool CStyle) {
   // We need at least one of these types to be a vector type to have a vector
   // conversion.
@@ -1862,10 +1937,28 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
 
   // There are no conversions between extended vector types, only identity.
   if (ToType->isExtVectorType()) {
-    // There are no conversions between extended vector types other than the
-    // identity conversion.
-    if (FromType->isExtVectorType())
+    if (FromType->isExtVectorType()) {
+      // HLSL allows implicit truncation of vector types.
+      if (S.getLangOpts().HLSL) {
+        unsigned FromElts = FromType->getAs<VectorType>()->getNumElements();
+        unsigned ToElts = ToType->getAs<VectorType>()->getNumElements();
+        if (FromElts < ToElts)
+          return false;
+        if (FromElts == ToElts)
+          ICK = ICK_Identity;
+        else
+          ICK = ICK_HLSL_Vector_Truncation;
+
+        QualType FromElTy = FromType->getAs<VectorType>()->getElementType();
+        QualType ToElTy = ToType->getAs<VectorType>()->getElementType();
+        if (S.Context.hasSameUnqualifiedType(FromElTy, ToElTy))
+          return true;
+        return IsVectorElementConversion(S, FromElTy, ToElTy, ElConv, From);
+      }
+      // There are no conversions between extended vector types other than the
+      // identity conversion.
       return false;
+    }
 
     // Vector splat from any arithmetic type to a vector.
     if (FromType->isArithmeticType()) {
@@ -2071,6 +2164,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
   // conversion.
   bool IncompatibleObjC = false;
   ImplicitConversionKind SecondICK = ICK_Identity;
+  ImplicitConversionKind ElementICK = ICK_Identity;
   if (S.Context.hasSameUnqualifiedType(FromType, ToType)) {
     // The unqualified versions of the types are the same: there's no
     // conversion to do.
@@ -2109,29 +2203,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
     // Complex-real conversions (C99 6.3.1.7)
     SCS.Second = ICK_Complex_Real;
     FromType = ToType.getUnqualifiedType();
-  } else if (FromType->isRealFloatingType() && ToType->isRealFloatingType()) {
-    // FIXME: disable conversions between long double, __ibm128 and __float128
-    // if their representation is different until there is back end support
-    // We of course allow this conversion if long double is really double.
-
-    // Conversions between bfloat16 and float16 are currently not supported.
-    if ((FromType->isBFloat16Type() &&
-         (ToType->isFloat16Type() || ToType->isHalfType())) ||
-        (ToType->isBFloat16Type() &&
-         (FromType->isFloat16Type() || FromType->isHalfType())))
-      return false;
-
-    // Conversions between IEEE-quad and IBM-extended semantics are not
-    // permitted.
-    const llvm::fltSemantics &FromSem =
-        S.Context.getFloatTypeSemantics(FromType);
-    const llvm::fltSemantics &ToSem = S.Context.getFloatTypeSemantics(ToType);
-    if ((&FromSem == &llvm::APFloat::PPCDoubleDouble() &&
-         &ToSem == &llvm::APFloat::IEEEquad()) ||
-        (&FromSem == &llvm::APFloat::IEEEquad() &&
-         &ToSem == &llvm::APFloat::PPCDoubleDouble()))
-      return false;
-
+  } else if (IsFloatingPointConversion(S, FromType, ToType)) {
     // Floating point conversions (C++ 4.8).
     SCS.Second = ICK_Floating_Conversion;
     FromType = ToType.getUnqualifiedType();
@@ -2158,18 +2230,18 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
                                          InOverloadResolution, FromType)) {
     // Pointer to member conversions (4.11).
     SCS.Second = ICK_Pointer_Member;
-  } else if (IsVectorConversion(S, FromType, ToType, SecondICK, From,
-                                InOverloadResolution, CStyle)) {
+  } else if (IsVectorConversion(S, FromType, ToType, SecondICK, ElementICK,
+                                From, InOverloadResolution, CStyle)) {
     SCS.Second = SecondICK;
+    SCS.Element = ElementICK;
     FromType = ToType.getUnqualifiedType();
   } else if (!S.getLangOpts().CPlusPlus &&
              S.Context.typesAreCompatible(ToType, FromType)) {
     // Compatible conversions (Clang extension for C function overloading)
     SCS.Second = ICK_Compatible_Conversion;
     FromType = ToType.getUnqualifiedType();
-  } else if (IsTransparentUnionStandardConversion(S, From, ToType,
-                                             InOverloadResolution,
-                                             SCS, CStyle)) {
+  } else if (IsTransparentUnionStandardConversion(
+                 S, From, ToType, InOverloadResolution, SCS, CStyle)) {
     SCS.Second = ICK_TransparentUnionConversion;
     FromType = ToType;
   } else if (tryAtomicConversion(S, From, ToType, InOverloadResolution, SCS,
@@ -5054,6 +5126,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
                               : (RefConv & Sema::ReferenceConversions::ObjC)
                                     ? ICK_Compatible_Conversion
                                     : ICK_Identity;
+    ICS.Standard.Element = ICK_Identity;
     // FIXME: As a speculative fix to a defect introduced by CWG2352, we rank
     // a reference binding that performs a non-top-level qualification
     // conversion as a qualification conversion, not as an identity conversion.
@@ -5975,6 +6048,7 @@ static bool CheckConvertedConstantConversions(Sema &S,
   case ICK_C_Only_Conversion:
   case ICK_Incompatible_Pointer_Conversion:
   case ICK_Fixed_Point_Conversion:
+  case ICK_HLSL_Vector_Truncation:
     return false;
 
   case ICK_Lvalue_To_Rvalue:
@@ -6233,6 +6307,7 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
 static void dropPointerConversion(StandardConversionSequence &SCS) {
   if (SCS.Second == ICK_Pointer_Conversion) {
     SCS.Second = ICK_Identity;
+    SCS.Element = ICK_Identity;
     SCS.Third = ICK_Identity;
     SCS.ToTypePtrs[2] = SCS.ToTypePtrs[1] = SCS.ToTypePtrs[0];
   }
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 7e431f7e598c4c..c90423784a3425 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -520,7 +520,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
       // Various C++ casts that are not handled yet.
       case CK_ToUnion:
       case CK_MatrixCast:
-      case CK_VectorSplat: {
+      case CK_VectorSplat:
+      case CK_VectorTruncation: {
         QualType resultType = CastE->getType();
         if (CastE->isGLValue())
           resultType = getContext().getPointerType(resultType);
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl
new file mode 100644
index 00000000000000..85b8eed4dafbe5
--- /dev/null
+++ b/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl
@@ -0,0 +1,119 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// CHECK-LABEL: f3_to_d4
+// CHECK: [[f3:%.*]] = alloca <3 x float>
+// CHECK: [[d4:%.*]] = alloca <4 x double>
+// CHECK: store <3 x float> <float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>, ptr [[f3]]
+// CHECK: [[vecf3:%.*]] = load <3 x float>, ptr [[f3]]
+// CHECK: [[vecf4:%.*]] = shufflevector <3 x float> [[vecf3]], <3 x float> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 0>
+// CHECK: [[vecd4:%.*]] = fpext <4 x float> [[vecf4]] to <4 x double>
+// CHECK: store <4 x double> [[vecd4]], ptr [[d4]]
+void f3_to_d4() {
+  vector<float,3> f3 = 1.0;
+  vector<double,4> d4 = f3.xyzx;
+}
+
+// CHECK-LABEL: f3_to_f2
+// CHECK: [[f3:%.*]] = alloca <3 x float>
+// CHECK: [[f2:%.*]] = alloca <2 x float>
+// CHECK: store <3 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00>, ptr [[f3]]
+// CHECK: [[vecf3:%.*]] = load <3 x float>, ptr [[f3]]
+// CHECK: [[vecf2:%.*]] = shufflevector <3 x float> [[vecf3]], <3 x float> poison, <2 x i32> zeroinitializer
+// CHECK: store <2 x float> [[vecf2]], ptr [[f2]]
+void f3_to_f2() {
+  vector<float,3> f3 = 2.0;
+  vector<float,2> f2 = f3;
+}
+
+// CHECK-LABEL: d4_to_f2
+// CHECK: [[d4:%.*]] = alloca <4 x double>
+// CHECK: [[f2:%.*]] = alloca <2 x float>
+// CHECK: store <4 x double> <double 3.000000e+00, double 3.000000e+00, double 3.000000e+00, double 3.000000e+00>, ptr [[d4]]
+// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
+// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> zeroinitializer
+// CHECK: [[vecf2:%.*]] = fptrunc <2 x double> [[vecd2]] to <2 x float>
+// CHECK: store <2 x float> [[vecf2]], ptr [[f2]]
+void d4_to_f2() {
+  vector<double,4> d4 = 3.0;
+  vector<float,2> f2 = d4;
+}
+
+// CHECK-LABEL: f2_to_i2
+// CHECK: [[f2:%.*]] = alloca <2 x float>
+// CHECK: [[i2:%.*]] = alloca <2 x i32>
+// CHECK: store <2 x float> <float 4.000000e+00, float 4.000000e+00>, ptr [[f2]]
+// CHECK: [[vecf2:%.*]] = load <2 x float>, ptr [[f2]]
+// CHECK: [[veci2:%.*]] = fptosi <2 x float> [[vecf2]] to <2 x i32>
+// CHECK: store <2 x i32> [[veci2]], ptr [[i2]]
+void f2_to_i2() {
+  vector<float,2> f2 = 4.0;
+  vector<int,2> i2 = f2;
+}
+
+// CHECK-LABEL: d4_to_i2
+// CHECK: [[f4:%.*]] = alloca <4 x double>
+// CHECK: [[i2:%.*]] = alloca <2 x i32>
+// CHECK: store <4 x double> <double 5.000000e+00, double 5.000000e+00, double 5.000000e+00, double 5.000000e+00>, ptr [[d4]]
+// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
+// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> zeroinitializer
+// CHECK: [[veci2]] = fptosi <2 x double> [[vecd2]] to <2 x i32>
+// CHECK: store <2 x i32> [[veci2]], ptr [[i2]]
+void d4_to_i2() {
+  vector<double,4> d4 = 5.0;
+  vector<int,2> i2 = d4;
+}
+
+// CHECK-LABEL: d4_to_l4
+// CHECK: [[d4:%.*]] = alloca <4 x double>
+// CHECK: [[l4:%.*]] = alloca <4 x i64>
+// CHECK: store <4 x double> <double 6.000000e+00, double 6.000000e+00, double 6.000000e+00, double 6.000000e+00>, ptr [[d4]]
+// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
+// CHECK: [[vecl4:%.*]] = fptosi <4 x double> [[vecd4]] to <4 x i64>
+// CHECK: store <4 x i64> [[vecl4]], ptr [[l4]]
+void d4_to_l4() {
+  vector<double,4> d4 = 6.0;
+  vector<long,4> l4 = d4;
+}
+
+
+// CHECK-LABEL: l4_to_i2
+// CHECK: [[l4:%.*]] = alloca <4 x i64>
+// CHECK: [[i2:%.*]] = alloca <2 x i32>
+// CHECK: store <4 x i64> <i64 7, i64 7, i64 7, i64 7>, ptr [[l4]]
+// CHECK: [[vecl4:%.*]] = load <4 x i64>, ptr [[l4]]
+// CHECK: [[vecl2:%.*]] = shufflevector <4 x i64> [[vecl4]], <4 x i64> poison, <2 x i32> zeroinitializer
+// CHECK: [[veci2:%.*]] = trunc <2 x i64> [[vecl2]] to <2 x i32>
+// CHECK: store <2 x i32> [[veci2]], ptr [[i2]]
+void l4_to_i2() {
+  vector<long, 4> l4 = 7;
+  vector<int,2> i2 = l4;
+}
+
+// CHECK-LABEL: i2_to_b2
+// CHECK: [[l2:%.*]] = alloca <2 x i32>
+// CHECK: [[b2:%.*]] = alloca i8
+// CHECK: store <2 x i32> <i32 8, i32 8>, ptr [[i2]]
+// CHECK: [[veci2:%.*]] = load <2 x i32>, ptr [[i2]]
+// CHECK: [[vecb2:%.*]] = icmp ne <2 x i32> [[veci2]], zeroinitializer
+// CHECK: [[vecb8:%.*]] = shufflevector <2 x i1> [[vecb2]], <2 x i1> poison, <8 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
+// CHECK: [[i8:%.*]] = bitcast <8 x i1> [[vecb8]] to i8
+// CHECK: store i8 [[i8]], ptr [[b2]]
+void i2_to_b2() {
+  vector<int, 2> i2 = 8;
+  vector<bool, 2> b2 = i2;
+}
+
+// CHECK-LABEL: d4_to_b2
+// CHECK: [[d4:%.*]] = alloca <4 x double>
+// CHECK: [[b2:%.*]] = alloca i8
+// CHECK: store <4 x double> <double 9.000000e+00, double 9.000000e+00, double 9.000000e+00, double 9.000000e+00>, ptr [[d4]]
+// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
+// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> zeroinitializer
+// CHECK: [[vecb2:%.*]] = fcmp une <2 x double> [[vecd2]], zeroinitializer
+// CHECK: [[vecb8:%.*]] = shufflevector <2 x i1> [[vecb2]], <2 x i1> poison, <8 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
+// CHECK: [[i8:%.*]] = bitcast <8 x i1> [[vecb8]] to i8
+// CHECK: store i8 [[i8]], ptr [[b2]]
+void d4_to_b2() {
+  vector<double,4> d4 = 9.0;
+  vector<bool, 2> b2 = d4;
+}
diff --git a/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl b/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl
index 73b5a192793e0c..7f6bdc7e67836b 100644
--- a/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl
@@ -18,5 +18,5 @@ void entry() {
   S s;
   float2 GettingStrange = float2(s, s); // expected-error{{no viable conversion from 'S' to 'float'}} expected-error{{no viable conversion from 'S' to 'float'}}
   S2 s2;
-  float2 EvenStranger = float2(s2); // expected-error{{no viable conversion from 'S2' to 'float'}} expected-error{{too few elements in vector initialization (expected 2 elements, have 1)}}
+  float2 EvenStranger = float2(s2); // expected-error{{cannot convert 'S2' to 'float2' (vector of 2 'float' values) without a conversion operator}}
 }
diff --git a/clang/test/SemaHLSL/standard_conversion_sequences.hlsl b/clang/test/SemaHLSL/standard_conversion_sequences.hlsl
new file mode 100644
index 00000000000000..ca9f2a372c0261
--- /dev/null
+++ b/clang/test/SemaHLSL/standard_conversion_sequences.hlsl
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -Wconversion -verify -o - %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -Wno-conversion -DNO_ERR -ast-dump %s | FileCheck %s
+
+void test() {
+  
+  // CHECK: VarDecl {{.*}} used f3 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' cinit
+  // CHECK-NEXt: ImplicitCastExpr {{.*}} 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' <VectorSplat>
+  // CHECK-NEXt: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
+  // CHECK-NEXt: FloatingLiteral {{.*}} 'double' 1.000000e+00
+  vector<float,3> f3 = 1.0; // No warning for splatting to a vector from a literal.
+
+
+  // CHECK: VarDecl {{.*}} used d4 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' cinit
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <FloatingCast>
+  // CHECK-NEXT: ExtVectorElementExpr {{.*}} 'float __attribute__((ext_vector_type(4)))' xyzx
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' lvalue Var {{.*}} 'f3' 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))'
+  vector<double,4> d4 = f3.xyzx; // No warnings for promotion or explicit extension.
+
+  // CHECK: VarDecl {{.*}} used f2 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' cinit
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float __attribute__((ext_vector_type(2)))' <VectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' lvalue Var {{.*}} 'f3' 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))'
+  // expected-warning@#f2{{implicit conversion truncates vector: 'vector<float, 3>' (vector of 3 'float' values) to 'float __attribute__((ext_vector_type(2)))' (vector of 2 'float' values)}}
+  vector<float,2> f2 = f3; // #f2
+
+  // CHECK: VarDecl {{.*}} f2_2 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' cinit
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' <FloatingCast>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <VectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'd4' 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))'
+  // expected-warning@#f2_2{{implicit conversion truncates vector: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<float, 2>' (vector of 2 'float' values)}}
+  // expected-warning@#f2_2{{implicit conversion loses floating-point precision: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<float, 2>' (vector of 2 'float' values)}}
+  vector<float,2> f2_2 = d4; // #f2_2
+
+  // CHECK: VarDecl {{.*}} i2 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' cinit
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' <FloatingToIntegral>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' lvalue Var {{.*}} 'f2' 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))'
+  // expected-warning@#i2{{mplicit conversion turns floating-point number into integer: 'vector<float, 2>' (vector of 2 'float' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
+  vector<int,2> i2 = f2; // #i2
+  
+  // CHECK: VarDecl {{.*}} i2_2 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' cinit
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' <FloatingToIntegral>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <VectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'd4' 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))'
+  // expected-warning@#i2_2{{implicit conversion truncates vector: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
+  // expected-warning@#i2_2{{implicit conversion turns floating-point number into integer: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
+  vector<int,2> i2_2 = d4; // #i2_2
+
+
+  // CHECK: VarDecl {{.*}} used i64_4 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))' cinit
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))' <FloatingToIntegral>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'd4' 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))'
+  // expected-warning@#i64_4{{implicit conversion turns floating-point number into integer: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<long, 4>' (vector of 4 'long' values)}}
+  vector<long,4> i64_4 = d4; // #i64_4
+
+  // CHECK: VarDecl {{.*}} used i2_3 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' cinit
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' <IntegralCast>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'long __attribute__((ext_vector_type(2)))' <VectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'i64_4' 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))'
+  // expected-warning@#i2_3{{implicit conversion loses integer precision: 'vector<long, 4>' (vector of 4 'long' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
+  // expected-warning@#i2_3{{implicit conversion truncates vector: 'vector<long, 4>' (vector of 4 'long' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
+  vector<int,2> i2_3 = i64_4; // #i2_3
+
+  //CHECK: VarDecl {{.*}} b2 'vector<bool, 2>':'bool __attribute__((ext_vector_type(2)))' cinit
+  //CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 2>':'bool __attribute__((ext_vector_type(2)))' <IntegralToBoolean>
+  //CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' <LValueToRValue>
+  //CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' lvalue Var {{.*}} 'i2_3' 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))'
+  vector<bool, 2> b2 = i2_3; // No warning for integer to bool conversion.
+
+  // CHECK: VarDecl {{.*}} b2_2 'vector<bool, 2>':'bool __attribute__((ext_vector_type(2)))' cinit
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 2>':'bool __attribute__((ext_vector_type(2)))' <FloatingToBoolean>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <VectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <LValueToRValue>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'd4' 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))'
+  // expected-warning@#b2_2{{implicit conversion truncates vector: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<bool, 2>' (vector of 2 'bool' values)}}
+  // expected-warning@#b2_2{{implicit conversion turns floating-point number into integer: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<bool, 2>' (vector of 2 'bool' values)}}
+  vector<bool, 2> b2_2 = d4; // #b2_2
+}
+
+#ifndef NO_ERR
+
+void illegal() {
+  // vector extension is illegal
+  vector<float,3> f3 = 1.0;
+  vector<float,4> f4 = f3; // expected-error{{cannot initialize a variable of type 'vector<[...], 4>' with an lvalue of type 'vector<[...], 3>'}}
+}
+
+#endif

>From 06c7a72d8894ccca3f045d30c62e929630d07900 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Wed, 29 Nov 2023 11:52:47 -0600
Subject: [PATCH 2/7] Rename VectorTruncation to HLSLVectorTruncation

../clang/test/SemaHLSL/standard_conversion_sequences.hlsl
../clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl
../clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl
---
 clang/include/clang/AST/OperationKinds.def             |  2 +-
 clang/lib/AST/Expr.cpp                                 |  2 +-
 clang/lib/AST/ExprConstant.cpp                         |  4 ++--
 clang/lib/CodeGen/CGExpr.cpp                           |  2 +-
 clang/lib/CodeGen/CGExprAgg.cpp                        |  4 ++--
 clang/lib/CodeGen/CGExprComplex.cpp                    |  2 +-
 clang/lib/CodeGen/CGExprConstant.cpp                   |  2 +-
 clang/lib/CodeGen/CGExprScalar.cpp                     |  2 +-
 clang/lib/Edit/RewriteObjCFoundationAPI.cpp            |  2 +-
 clang/lib/Sema/SemaExprCXX.cpp                         |  2 +-
 clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp          |  2 +-
 clang/test/SemaHLSL/standard_conversion_sequences.hlsl | 10 +++++-----
 12 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def
index e497fe4d1f93ff..e8d934782d4482 100644
--- a/clang/include/clang/AST/OperationKinds.def
+++ b/clang/include/clang/AST/OperationKinds.def
@@ -362,7 +362,7 @@ CAST_OPERATION(AddressSpaceConversion)
 CAST_OPERATION(IntToOCLSampler)
 
 // Truncate a vector type (HLSL only).
-CAST_OPERATION(VectorTruncation)
+CAST_OPERATION(HLSLVectorTruncation)
 
 //===- Binary Operations  -------------------------------------------------===//
 // Operators listed in order of precedence.
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index bfbdb6cf0f929d..135f04fb93c7df 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1898,7 +1898,7 @@ bool CastExpr::CastConsistency() const {
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
   case CK_MatrixCast:
-  case CK_VectorTruncation:
+  case CK_HLSLVectorTruncation:
     assert(!getType()->isBooleanType() && "unheralded conversion to bool");
     goto CheckNoBasePath;
 
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 24c12cd0fd939d..f737a64656a5b2 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13875,7 +13875,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_FixedPointCast:
   case CK_IntegralToFixedPoint:
   case CK_MatrixCast:
-  case CK_VectorTruncation:
+  case CK_HLSLVectorTruncation:
     llvm_unreachable("invalid cast kind for integral value");
 
   case CK_BitCast:
@@ -14714,7 +14714,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
   case CK_MatrixCast:
-  case CK_VectorTruncation:
+  case CK_HLSLVectorTruncation:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_LValueToRValue:
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 9101f81c718b71..e748af5f89d32b 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4933,7 +4933,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
   case CK_MatrixCast:
-  case CK_VectorTruncation:
+  case CK_HLSLVectorTruncation:
     return EmitUnsupportedLValue(E, "unexpected cast lvalue");
 
   case CK_Dependent:
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index f9278133e5ddc6..8949ad8a4dce46 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -930,7 +930,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
   case CK_BuiltinFnToFnPtr:
   case CK_ZeroToOCLOpaqueType:
   case CK_MatrixCast:
-  case CK_VectorTruncation:
+  case CK_HLSLVectorTruncation:
 
   case CK_IntToOCLSampler:
   case CK_FloatingToFixedPoint:
@@ -1455,7 +1455,7 @@ static bool castPreservesZero(const CastExpr *CE) {
   case CK_MatrixCast:
   case CK_NonAtomicToAtomic:
   case CK_AtomicToNonAtomic:
-  case CK_VectorTruncation:
+  case CK_HLSLVectorTruncation:
     return true;
 
   case CK_BaseToDerivedMemberPointer:
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 45862701d59bb4..6ffcb418666512 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -556,7 +556,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
   case CK_MatrixCast:
-  case CK_VectorTruncation:
+  case CK_HLSLVectorTruncation:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_FloatingRealToComplex:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 577eee2ee1ff0f..f5b144a0736467 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1225,7 +1225,7 @@ class ConstExprEmitter :
     case CK_IntegralToFixedPoint:
     case CK_ZeroToOCLOpaqueType:
     case CK_MatrixCast:
-    case CK_VectorTruncation:
+    case CK_HLSLVectorTruncation:
       return nullptr;
     }
     llvm_unreachable("Invalid CastKind");
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 7b57f33865c03b..121a26a3b5df83 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2475,7 +2475,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
   case CK_IntToOCLSampler:
     return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
 
-  case CK_VectorTruncation: {
+  case CK_HLSLVectorTruncation: {
     assert(DestTy->isVectorType() && "Expected dest type to be vector type");
     Value *Vec = Visit(const_cast<Expr *>(E));
     SmallVector<int, 16> Mask;
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index d42532cc15d27e..3c5ddcc3bb0faf 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1087,7 +1087,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
     case CK_BooleanToSignedIntegral:
       llvm_unreachable("OpenCL-specific cast in Objective-C?");
 
-    case CK_VectorTruncation:
+    case CK_HLSLVectorTruncation:
       llvm_unreachable("HLSL-specific cast in Objective-C?");
       break;
 
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 5052af7905ca14..f628f2ff9b02c9 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4772,7 +4772,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
     QualType ElType = FromVec->getElementType();
     QualType TruncTy =
         Context.getExtVectorType(ElType, ToVec->getNumElements());
-    From = ImpCastExprToType(From, TruncTy, CK_VectorTruncation,
+    From = ImpCastExprToType(From, TruncTy, CK_HLSLVectorTruncation,
                              From->getValueKind())
                .get();
     break;
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index c90423784a3425..c3fc56ac30ee9f 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -521,7 +521,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
       case CK_ToUnion:
       case CK_MatrixCast:
       case CK_VectorSplat:
-      case CK_VectorTruncation: {
+      case CK_HLSLVectorTruncation: {
         QualType resultType = CastE->getType();
         if (CastE->isGLValue())
           resultType = getContext().getPointerType(resultType);
diff --git a/clang/test/SemaHLSL/standard_conversion_sequences.hlsl b/clang/test/SemaHLSL/standard_conversion_sequences.hlsl
index ca9f2a372c0261..a0d398105f15d6 100644
--- a/clang/test/SemaHLSL/standard_conversion_sequences.hlsl
+++ b/clang/test/SemaHLSL/standard_conversion_sequences.hlsl
@@ -17,7 +17,7 @@ void test() {
   vector<double,4> d4 = f3.xyzx; // No warnings for promotion or explicit extension.
 
   // CHECK: VarDecl {{.*}} used f2 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' cinit
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float __attribute__((ext_vector_type(2)))' <VectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float __attribute__((ext_vector_type(2)))' <HLSLVectorTruncation>
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' <LValueToRValue>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' lvalue Var {{.*}} 'f3' 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))'
   // expected-warning@#f2{{implicit conversion truncates vector: 'vector<float, 3>' (vector of 3 'float' values) to 'float __attribute__((ext_vector_type(2)))' (vector of 2 'float' values)}}
@@ -25,7 +25,7 @@ void test() {
 
   // CHECK: VarDecl {{.*}} f2_2 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' cinit
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' <FloatingCast>
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <VectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <HLSLVectorTruncation>
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <LValueToRValue>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'd4' 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))'
   // expected-warning@#f2_2{{implicit conversion truncates vector: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<float, 2>' (vector of 2 'float' values)}}
@@ -41,7 +41,7 @@ void test() {
   
   // CHECK: VarDecl {{.*}} i2_2 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' cinit
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' <FloatingToIntegral>
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <VectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <HLSLVectorTruncation>
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <LValueToRValue>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'd4' 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))'
   // expected-warning@#i2_2{{implicit conversion truncates vector: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
@@ -58,7 +58,7 @@ void test() {
 
   // CHECK: VarDecl {{.*}} used i2_3 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' cinit
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' <IntegralCast>
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'long __attribute__((ext_vector_type(2)))' <VectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'long __attribute__((ext_vector_type(2)))' <HLSLVectorTruncation>
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))' <LValueToRValue>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'i64_4' 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))'
   // expected-warning@#i2_3{{implicit conversion loses integer precision: 'vector<long, 4>' (vector of 4 'long' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
@@ -73,7 +73,7 @@ void test() {
 
   // CHECK: VarDecl {{.*}} b2_2 'vector<bool, 2>':'bool __attribute__((ext_vector_type(2)))' cinit
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 2>':'bool __attribute__((ext_vector_type(2)))' <FloatingToBoolean>
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <VectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <HLSLVectorTruncation>
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <LValueToRValue>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'd4' 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))'
   // expected-warning@#b2_2{{implicit conversion truncates vector: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<bool, 2>' (vector of 2 'bool' values)}}

>From 6cbf74c358895edb8dba02182fe5fffd38bf6bd8 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Wed, 29 Nov 2023 13:09:47 -0600
Subject: [PATCH 3/7] Remove clang-format comments
 ../clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl
 ../clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl

---
 clang/lib/Sema/SemaOverload.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index e3509546acc0c7..39418bd9c7a3b6 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -120,7 +120,6 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
                                 const StandardConversionSequence& SCS1,
                                 const StandardConversionSequence& SCS2);
 
-// clang-format off - disable clang format for this block.
 /// GetConversionRank - Retrieve the implicit conversion rank
 /// corresponding to the given implicit conversion kind.
 ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
@@ -165,7 +164,6 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
   static_assert(std::size(Rank) == (int)ICK_Num_Conversion_Kinds);
   return Rank[(int)Kind];
 }
-// clang-format on
 
 /// GetImplicitConversionName - Return the name of this kind of
 /// implicit conversion.

>From 899d5298c1dd1847ac4c022f9da6d5be1cab91f8 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Wed, 29 Nov 2023 13:10:07 -0600
Subject: [PATCH 4/7] Update scalar swizzle tests

The new "correct" implicit conversion sequences change how some of these
ASTs are formed and the initial code generation.
../clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl
../clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl
---
 .../CodeGenHLSL/builtins/ScalarSwizzles.hlsl  | 34 +++++--------------
 .../Types/BuiltinVector/ScalarSwizzles.hlsl   | 25 ++------------
 2 files changed, 11 insertions(+), 48 deletions(-)

diff --git a/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl b/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl
index 2e169ef60c70c4..73bab556b9a6db 100644
--- a/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl
@@ -85,7 +85,9 @@ float4 FillTwoPointFiveFloat(){
 // CHECK: [[vec1Ptr:%.*]] = alloca <1 x float>, align 4
 // CHECK: store <1 x float> <float 5.000000e-01>, ptr [[vec1Ptr]], align 4
 // CHECK: [[vec1:%.*]] = load <1 x float>, ptr [[vec1Ptr]], align 4
-// CHECK: [[vec1Ret:%.*]] = shufflevector <1 x float> [[vec1]], <1 x float> undef, <1 x i32> zeroinitializer
+// CHECK: [[el0:%.*]] = extractelement <1 x float> [[vec1]], i32 0
+// CHECK: [[vec1Splat:%.*]] = insertelement <1 x float> poison, float [[el0]], i64 0
+// CHECK: [[vec1Ret:%.*]] = shufflevector <1 x float> [[vec1Splat]], <1 x float> poison, <1 x i32> zeroinitializer
 // CHECK: ret <1 x float> [[vec1Ret]]
 vector<float, 1> FillOneHalfFloat(){
   return .5f.r;
@@ -113,30 +115,12 @@ float2 HowManyFloats(float V) {
 // up nicely too.
 
 // CHECK-LABEL: AllRighty
-// CHECK: [[XTmp:%.*]] = alloca <1 x double>, align 8
-// CHECK: [[YTmp:%.*]] = alloca <1 x double>, align 8
-// CHECK: [[ZTmp:%.*]] = alloca <1 x double>, align 8
-
-// CHECK: store <1 x double> <double 1.000000e+00>, ptr [[XTmp]], align 8
-// CHECK: [[XVec:%.*]] = load <1 x double>, ptr [[XTmp]], align 8
-// CHECK: [[XVec3:%.*]] = shufflevector <1 x double> [[XVec]], <1 x double> poison, <3 x i32> zeroinitializer
-// CHECK: [[XVal:%.*]] = extractelement <3 x double> [[XVec3]], i32 0
-// CHECK: [[XValF:%.*]] = fptrunc double [[XVal]] to float
-// CHECK: [[Vec3F1:%.*]] = insertelement <3 x float> undef, float [[XValF]], i32 0
-
-// CHECK: store <1 x double> <double 1.000000e+00>, ptr [[YTmp]], align 8
-// CHECK: [[YVec:%.*]] = load <1 x double>, ptr [[YTmp]], align 8
-// CHECK: [[YVec3:%.*]] = shufflevector <1 x double> [[YVec]], <1 x double> poison, <3 x i32> zeroinitializer
-// CHECK: [[YVal:%.*]] = extractelement <3 x double> [[YVec3]], i32 1
-// CHECK: [[YValF:%.*]] = fptrunc double [[YVal]] to float
-// CHECK: [[Vec3F2:%.*]] = insertelement <3 x float> [[Vec3F1]], float [[YValF]], i32 1
-
-// CHECK: store <1 x double> <double 1.000000e+00>, ptr [[ZTmp]], align 8
-// CHECK: [[ZVec:%.*]] = load <1 x double>, ptr [[ZTmp]], align 8
-// CHECK: [[ZVec3:%.*]] = shufflevector <1 x double> [[ZVec]], <1 x double> poison, <3 x i32> zeroinitializer
-// CHECK: [[ZVal:%.*]] = extractelement <3 x double> [[ZVec3]], i32 2
-// CHECK: [[ZValF:%.*]] = fptrunc double [[ZVal]] to float
-// CHECK: [[Vec3F3:%.*]] = insertelement <3 x float> [[Vec3F2]], float [[ZValF]], i32 2
+// CHECK: [[Tmp:%.*]] = alloca <1 x double>, align 8
+// CHECK: store <1 x double> <double 1.000000e+00>, ptr [[Tmp]], align 8
+// CHECK: [[vec1:%.*]] = load <1 x double>, ptr [[Tmp]], align 8
+// CHECK: [[vec3:%.*]] = shufflevector <1 x double> [[vec1]], <1 x double> poison, <3 x i32> zeroinitializer
+// CHECK: [[vec3f:%.*]] = fptrunc <3 x double> [[vec3]] to <3 x float>
+// ret <3 x float> [[vec3f]]
 
 // ret <3 x float> [[Vec3F3]]
 float3 AllRighty() {
diff --git a/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl b/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl
index 4ffbcacf3f30c0..a2e9a5f865ece1 100644
--- a/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl
+++ b/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl
@@ -80,7 +80,7 @@ float4 FillTwoPointFiveFloat(){
 // initialze the returned vector.
 
 // CHECK-LABEL: FillOneHalfFloat
-// CHECK: InitListExpr {{.*}} 'vector<float, 1>':'float __attribute__((ext_vector_type(1)))'
+// CHECK: ImplicitCastExpr {{.*}} 'vector<float, 1>':'float __attribute__((ext_vector_type(1)))' <VectorSplat>
 // CHECK-NEXT: ExtVectorElementExpr {{.*}} 'float' r
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float __attribute__((ext_vector_type(1)))' <VectorSplat>
 // CHECK-NEXT: FloatingLiteral {{.*}} 'float' 5.000000e-01
@@ -113,31 +113,10 @@ int64_t4 HooBoy() {
 // list with float truncation casts.
 
 // CHECK-LABEL: AllRighty
-// CHECK: InitListExpr {{.*}} 'float3':'float __attribute__((ext_vector_type(3)))'
-
-// Vector element 0:
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
-// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'double'
-// CHECK-NEXT: ExtVectorElementExpr {{.*}} 'double __attribute__((ext_vector_type(3)))' rrr
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(1)))' <VectorSplat>
-// CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
-// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
-
-// Vector element 1:
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
-// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'double'
-// CHECK-NEXT: ExtVectorElementExpr {{.*}} 'double __attribute__((ext_vector_type(3)))' rrr
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(1)))' <VectorSplat>
-// CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
-// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
-
-// Vector element 2:
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
-// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'double'
+// CHECK: ImplicitCastExpr {{.*}} 'float3':'float __attribute__((ext_vector_type(3)))' <FloatingCast>
 // CHECK-NEXT: ExtVectorElementExpr {{.*}} 'double __attribute__((ext_vector_type(3)))' rrr
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(1)))' <VectorSplat>
 // CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
-// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
 
 float3 AllRighty() {
   return 1..rrr;

>From 86c0dc0ce139dd4370523b54393133ce8f72def0 Mon Sep 17 00:00:00 2001
From: Chris B <cbieneman at microsoft.com>
Date: Wed, 29 Nov 2023 13:34:54 -0600
Subject: [PATCH 5/7] Update clang/lib/Sema/SemaExprCXX.cpp

Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
---
 clang/lib/Sema/SemaExprCXX.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f628f2ff9b02c9..0e1acf6bd5dddd 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4790,7 +4790,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
   }
 
   if (SCS.Element != ICK_Identity) {
-    // if SCS.Element is not ICK_Identity the To and From types must be HLSL
+    // If SCS.Element is not ICK_Identity the To and From types must be HLSL
     // vectors or matrices. HLSL matrices aren't yet supported so this code only
     // handles vectors for now.
 

>From ac9711e3212b666ac4e6a2fd28c43bc7e66bf0fd Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Wed, 29 Nov 2023 13:37:02 -0600
Subject: [PATCH 6/7] Remove spurious whitespace change

---
 clang/lib/CodeGen/CGExpr.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index e748af5f89d32b..107c1c86f3c8fb 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -5061,7 +5061,6 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
     return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(),
                           CGM.getTBAAInfoForSubobject(LV, E->getType()));
   }
-
   case CK_ZeroToOCLOpaqueType:
     llvm_unreachable("NULL to OpenCL opaque type lvalue cast is not valid");
 

>From b9585121c4424de4540ae332b5ed9a57068708d2 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Wed, 13 Dec 2023 19:50:11 -0600
Subject: [PATCH 7/7] Avoid falling into EmitScalarConversion

'beanz/cbieneman/hlsl-standard-conversions-trunc' by 1664 commits.
---
 clang/lib/CodeGen/CGExprScalar.cpp | 59 ++++++++++++++++++++++--------
 1 file changed, 44 insertions(+), 15 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 53ab09f8e63f17..769b17ca1bbb3b 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -610,8 +610,6 @@ class ScalarExprEmitter
   llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
                                        bool isInc, bool isPre);
 
-  llvm::Value *EmitVectorElementConversion(QualType SrcType, QualType DstType,
-                                           llvm::Value *Src);
 
   Value *VisitUnaryAddrOf(const UnaryOperator *E) {
     if (isa<MemberPointerType>(E->getType())) // never sugared
@@ -1424,9 +1422,6 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
     return Builder.CreateVectorSplat(NumElements, Src, "splat");
   }
 
-  if (SrcType->isExtVectorType() && DstType->isExtVectorType())
-    return EmitVectorElementConversion(SrcType, DstType, Src);
-
   if (SrcType->isMatrixType() && DstType->isMatrixType())
     return EmitScalarCast(Src, SrcType, DstType, SrcTy, DstTy, Opts);
 
@@ -1706,14 +1701,10 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
 }
 
 Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
-  QualType SrcType = E->getSrcExpr()->getType(), DstType = E->getType();
-  Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
-  return EmitVectorElementConversion(SrcType, DstType, Src);
-}
+  QualType SrcType = E->getSrcExpr()->getType(),
+           DstType = E->getType();
 
-llvm::Value *ScalarExprEmitter::EmitVectorElementConversion(QualType SrcType,
-                                                            QualType DstType,
-                                                            Value *Src) {
+  Value *Src  = CGF.EmitScalarExpr(E->getSrcExpr());
 
   SrcType = CGF.getContext().getCanonicalType(SrcType);
   DstType = CGF.getContext().getCanonicalType(DstType);
@@ -2415,6 +2406,12 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
                                 CE->getExprLoc());
 
   case CK_IntegralCast: {
+    if (E->getType()->isExtVectorType() && DestTy->isExtVectorType()) {
+      QualType SrcElTy = E->getType()->castAs<VectorType>()->getElementType();
+      return Builder.CreateIntCast(Visit(E), ConvertType(DestTy),
+                                   SrcElTy->isSignedIntegerOrEnumerationType(),
+                                   "conv");
+    }
     ScalarConversionOpts Opts;
     if (auto *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
       if (!ICE->isPartOfExplicitCast())
@@ -2423,9 +2420,41 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
     return EmitScalarConversion(Visit(E), E->getType(), DestTy,
                                 CE->getExprLoc(), Opts);
   }
-  case CK_IntegralToFloating:
-  case CK_FloatingToIntegral:
-  case CK_FloatingCast:
+  case CK_IntegralToFloating: {
+    if (E->getType()->isExtVectorType() && DestTy->isExtVectorType()) {
+      QualType SrcElTy = E->getType()->castAs<VectorType>()->getElementType();
+      if (SrcElTy->isSignedIntegerOrEnumerationType())
+        return Builder.CreateSIToFP(Visit(E), ConvertType(DestTy), "conv");
+      return Builder.CreateUIToFP(Visit(E), ConvertType(DestTy), "conv");
+    }
+    CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, CE);
+    return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+                                CE->getExprLoc());
+  }
+  case CK_FloatingToIntegral: {
+    if (E->getType()->isExtVectorType() && DestTy->isExtVectorType()) {
+      QualType DstElTy = DestTy->castAs<VectorType>()->getElementType();
+      if (DstElTy->isSignedIntegerOrEnumerationType())
+        return Builder.CreateFPToSI(Visit(E), ConvertType(DestTy), "conv");
+      return Builder.CreateFPToUI(Visit(E), ConvertType(DestTy), "conv");
+    }
+    CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, CE);
+    return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+                                CE->getExprLoc());
+  }
+  case CK_FloatingCast: {
+    if (E->getType()->isExtVectorType() && DestTy->isExtVectorType()) {
+      QualType SrcElTy = E->getType()->castAs<VectorType>()->getElementType();
+      QualType DstElTy = DestTy->castAs<VectorType>()->getElementType();
+      if (DstElTy->castAs<BuiltinType>()->getKind() <
+          SrcElTy->castAs<BuiltinType>()->getKind())
+        return Builder.CreateFPTrunc(Visit(E), ConvertType(DestTy), "conv");
+      return Builder.CreateFPExt(Visit(E), ConvertType(DestTy), "conv");
+    }
+    CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, CE);
+    return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+                                CE->getExprLoc());
+  }
   case CK_FixedPointToFloating:
   case CK_FloatingToFixedPoint: {
     CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, CE);



More information about the cfe-commits mailing list