[clang] [HLSL] Rework implicit conversion sequences (PR #96011)

Chris B via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 18 18:48:01 PDT 2024


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

>From 0baa7ec1ded4fa093092d491eaa2c803b736742b Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Tue, 18 Jun 2024 20:25:57 -0500
Subject: [PATCH 1/2] [HLSL] Rework implicit conversion sequences

This PR reworks HLSL's implicit conversion sequences. Initially I was
seeking to match DXC's behavior more closely, but that was leading to a
pile of special case rules to tie-break ambiguous cases that should
really be left as ambiguous.

This change is a bit closer to C++'s overload resolution rules, but it
does have a bit of nuance around how dimension adjustment conversions
are ranked. Conversion sequence ranks for HLSL are:

* Exact match
* Scalar Widening (i.e. splat)
* Promotion
* Scalar Widening with Promotion
* Conversion
* Scalar Widening with Conversion
* Dimension Reduction (i.e. truncation)
* Dimension Reduction with Promotion
* Dimension Reduction with Conversion

In this implementation I've folded the disambiguation into the
conversion sequence ranks which does add some complexity as compared to
C++, however this avoids needing to add special casing in
`CompareStandardConversionSequences`. I belive the added conversion
rank values provide a simpler approach, but welcome feedback.
---
 clang/docs/HLSL/ExpectedDifferences.rst       |  11 ++
 clang/include/clang/Sema/Overload.h           |  38 +++-
 clang/lib/Sema/SemaExprCXX.cpp                | 163 +++++++++--------
 clang/lib/Sema/SemaOverload.cpp               |  85 ++++-----
 .../standard_conversion_sequences.hlsl        |  18 +-
 clang/test/CodeGenHLSL/builtins/dot.hlsl      |  34 +---
 clang/test/CodeGenHLSL/builtins/lerp.hlsl     |  24 ---
 clang/test/CodeGenHLSL/builtins/mad.hlsl      |  22 ---
 .../SemaHLSL/ScalarOverloadResolution.hlsl    |  28 ++-
 .../SemaHLSL/SplatOverloadResolution.hlsl     | 166 ++++++++++++++++++
 .../TruncationOverloadResolution.hlsl         |  68 +++++++
 .../Types/BuiltinVector/ScalarSwizzles.hlsl   |   2 +-
 .../VectorElementOverloadResolution.hlsl      |  36 ++--
 .../SemaHLSL/VectorOverloadResolution.hlsl    |  10 +-
 .../standard_conversion_sequences.hlsl        |  16 +-
 15 files changed, 447 insertions(+), 274 deletions(-)
 create mode 100644 clang/test/SemaHLSL/SplatOverloadResolution.hlsl
 create mode 100644 clang/test/SemaHLSL/TruncationOverloadResolution.hlsl

diff --git a/clang/docs/HLSL/ExpectedDifferences.rst b/clang/docs/HLSL/ExpectedDifferences.rst
index d1b6010f10f43..a29b6348e0b8e 100644
--- a/clang/docs/HLSL/ExpectedDifferences.rst
+++ b/clang/docs/HLSL/ExpectedDifferences.rst
@@ -67,12 +67,16 @@ behavior between Clang and DXC. Some examples include:
   void takesDoubles(double, double, double);
 
   cbuffer CB {
+    bool B;
     uint U;
     int I;
     float X, Y, Z;
     double3 A, B;
   }
 
+  void twoParams(int, int);
+  void twoParams(float, float);
+
   export void call() {
     halfOrInt16(U); // DXC: Fails with call ambiguous between int16_t and uint16_t overloads
                     // Clang: Resolves to halfOrInt16(uint16_t).
@@ -98,6 +102,13 @@ behavior between Clang and DXC. Some examples include:
                           // FXC: Expands to compute double dot product with fmul/fadd
                           // Clang: Resolves to dot(float3, float3), emits conversion warnings.
 
+  #ifndef IGNORE_ERRORS
+    tan(B); // DXC: resolves to tan(float).
+            // Clang: Fails to resolve, ambiguous between integer types.
+
+    twoParams(I, X); // DXC: resolves twoParams(int, int).
+                     // Clang: Fails to resolve ambiguous conversions.
+  #endif
   }
 
 .. note::
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 4a5c9e8ca1229..9d8b797af6663 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -201,6 +201,9 @@ class Sema;
     /// HLSL non-decaying array rvalue cast.
     ICK_HLSL_Array_RValue,
 
+    // HLSL vector splat from scalar or boolean type.
+    ICK_HLSL_Vector_Splat,
+
     /// The number of conversion kinds
     ICK_Num_Conversion_Kinds,
   };
@@ -213,15 +216,27 @@ class Sema;
     /// Exact Match
     ICR_Exact_Match = 0,
 
+    /// HLSL Scalar Widening
+    ICR_HLSL_Scalar_Widening,
+
     /// Promotion
     ICR_Promotion,
 
+    /// HLSL Scalar Widening with promotion
+    ICR_HLSL_Scalar_Widening_Promotion,
+
+    /// HLSL Matching Dimension Reduction
+    ICR_HLSL_Dimension_Reduction,
+
     /// Conversion
     ICR_Conversion,
 
     /// OpenCL Scalar Widening
     ICR_OCL_Scalar_Widening,
 
+    /// HLSL Scalar Widening with conversion
+    ICR_HLSL_Scalar_Widening_Conversion,
+
     /// Complex <-> Real conversion
     ICR_Complex_Real_Conversion,
 
@@ -233,11 +248,21 @@ class Sema;
 
     /// Conversion not allowed by the C standard, but that we accept as an
     /// extension anyway.
-    ICR_C_Conversion_Extension
+    ICR_C_Conversion_Extension,
+
+    /// HLSL Dimension reduction with promotion
+    ICR_HLSL_Dimension_Reduction_Promotion,
+
+    /// HLSL Dimension reduction with conversion
+    ICR_HLSL_Dimension_Reduction_Conversion,
   };
 
   ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
 
+  ImplicitConversionRank
+  GetDimensionConversionRank(ImplicitConversionRank Base,
+                             ImplicitConversionKind Dimension);
+
   /// NarrowingKind - The kind of narrowing conversion being performed by a
   /// standard conversion sequence according to C++11 [dcl.init.list]p7.
   enum NarrowingKind {
@@ -277,11 +302,10 @@ 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;
+    /// Dimension - Between the second and third conversion a vector or matrix
+    /// dimension conversion may occur. If this is not ICK_Identity this
+    /// conversion truncates the vector or matrix, or extends a scalar.
+    ImplicitConversionKind Dimension : 8;
 
     /// Third - The third conversion can be a qualification conversion
     /// or a function conversion.
@@ -379,7 +403,7 @@ class Sema;
     void setAsIdentityConversion();
 
     bool isIdentityConversion() const {
-      return Second == ICK_Identity && Element == ICK_Identity &&
+      return Second == ICK_Identity && Dimension == ICK_Identity &&
              Third == ICK_Identity;
     }
 
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f3af8dee6b090..7b955cb7a8e24 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4361,6 +4361,19 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
   return From;
 }
 
+// GetIntermediateVectorType - Compute the intermediate cast type casting
+// elements of the from type to the elements of the to type without resizing the
+// vector.
+static QualType adjustVectorType(ASTContext &Context, QualType FromTy,
+                                 QualType ToType) {
+  auto *ToVec = ToType->castAs<VectorType>();
+  QualType ElType = ToVec->getElementType();
+  if (!FromTy->isVectorType())
+    return ElType;
+  auto *FromVec = FromTy->castAs<VectorType>();
+  return Context.getExtVectorType(ElType, FromVec->getNumElements());
+}
+
 /// PerformImplicitConversion - Perform an implicit conversion of the
 /// expression From to the type ToType by following the standard
 /// conversion sequence SCS. Returns the converted
@@ -4515,27 +4528,38 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
     break;
 
   case ICK_Integral_Promotion:
-  case ICK_Integral_Conversion:
-    if (ToType->isBooleanType()) {
+  case ICK_Integral_Conversion: {
+    QualType ElTy = ToType;
+    QualType StepTy = ToType;
+    if (ToType->isVectorType()) {
+      StepTy = adjustVectorType(Context, FromType, ToType);
+      ElTy = StepTy->castAs<VectorType>()->getElementType();
+    }
+    if (ElTy->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,
+      From = ImpCastExprToType(From, StepTy, CK_IntegralToBoolean, VK_PRValue,
                                /*BasePath=*/nullptr, CCK)
                  .get();
     } else {
-      From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_PRValue,
+      From = ImpCastExprToType(From, StepTy, 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,
+  case ICK_Floating_Conversion: {
+    QualType StepTy = ToType;
+    if (ToType->isVectorType())
+      StepTy = adjustVectorType(Context, FromType, ToType);
+    From = ImpCastExprToType(From, StepTy, CK_FloatingCast, VK_PRValue,
                              /*BasePath=*/nullptr, CCK)
                .get();
     break;
+  }
 
   case ICK_Complex_Promotion:
   case ICK_Complex_Conversion: {
@@ -4558,16 +4582,23 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
     break;
   }
 
-  case ICK_Floating_Integral:
-    if (ToType->isRealFloatingType())
-      From = ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_PRValue,
+  case ICK_Floating_Integral: {
+    QualType ElTy = ToType;
+    QualType StepTy = ToType;
+    if (FromType->isVectorType()) {
+      StepTy = adjustVectorType(Context, FromType, ToType);
+      ElTy = StepTy->castAs<VectorType>()->getElementType();
+    }
+    if (ElTy->isRealFloatingType())
+      From = ImpCastExprToType(From, StepTy, CK_IntegralToFloating, VK_PRValue,
                                /*BasePath=*/nullptr, CCK)
                  .get();
     else
-      From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_PRValue,
+      From = ImpCastExprToType(From, StepTy, CK_FloatingToIntegral, VK_PRValue,
                                /*BasePath=*/nullptr, CCK)
                  .get();
     break;
+  }
 
   case ICK_Fixed_Point_Conversion:
     assert((FromType->isFixedPointType() || ToType->isFixedPointType()) &&
@@ -4689,18 +4720,26 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
     break;
   }
 
-  case ICK_Boolean_Conversion:
+  case ICK_Boolean_Conversion: {
     // Perform half-to-boolean conversion via float.
     if (From->getType()->isHalfType()) {
       From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).get();
       FromType = Context.FloatTy;
     }
+    QualType ElTy = FromType;
+    QualType StepTy = ToType;
+    if (FromType->isVectorType()) {
+      if (getLangOpts().HLSL)
+        StepTy = adjustVectorType(Context, FromType, ToType);
+      ElTy = FromType->castAs<VectorType>()->getElementType();
+    }
 
-    From = ImpCastExprToType(From, Context.BoolTy,
-                             ScalarTypeToBooleanCastKind(FromType), VK_PRValue,
+    From = ImpCastExprToType(From, StepTy,
+                             ScalarTypeToBooleanCastKind(ElTy), VK_PRValue,
                              /*BasePath=*/nullptr, CCK)
                .get();
     break;
+  }
 
   case ICK_Derived_To_Base: {
     CXXCastPath BasePath;
@@ -4826,22 +4865,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
                              CK_ZeroToOCLOpaqueType,
                              From->getValueKind()).get();
     break;
-  case ICK_HLSL_Vector_Truncation: {
-    // Note: HLSL built-in 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.
-    assert(From->getType()->isExtVectorType() && ToType->isExtVectorType() &&
-           "HLSL vector truncation should only apply to ExtVectors");
-    auto *FromVec = From->getType()->castAs<VectorType>();
-    auto *ToVec = ToType->castAs<VectorType>();
-    QualType ElType = FromVec->getElementType();
-    QualType TruncTy =
-        Context.getExtVectorType(ElType, ToVec->getNumElements());
-    From = ImpCastExprToType(From, TruncTy, CK_HLSLVectorTruncation,
-                             From->getValueKind())
-               .get();
-    break;
-  }
 
   case ICK_Lvalue_To_Rvalue:
   case ICK_Array_To_Pointer:
@@ -4852,73 +4875,45 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
   case ICK_C_Only_Conversion:
   case ICK_Incompatible_Pointer_Conversion:
   case ICK_HLSL_Array_RValue:
+  case ICK_HLSL_Vector_Truncation:
+  case ICK_HLSL_Vector_Splat:
     llvm_unreachable("Improper second standard conversion");
   }
 
-  if (SCS.Element != ICK_Identity) {
+  if (SCS.Dimension != ICK_Identity) {
     // If SCS.Element is not ICK_Identity the To and From types must be HLSL
     // vectors or matrices.
 
     // TODO: Support HLSL matrices.
     assert((!From->getType()->isMatrixType() && !ToType->isMatrixType()) &&
-           "Element conversion for matrix types is not implemented yet.");
-    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_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,
+           "Dimension conversion for matrix types is not implemented yet.");
+    assert(ToType->isVectorType() &&
+           "Dimension conversion is only supported for vector types.");
+    switch (SCS.Dimension) {
+    case ICK_HLSL_Vector_Splat: {
+      // Vector splat from any arithmetic type to a vector.
+      Expr *Elem = prepareVectorSplat(ToType, From).get();
+      From = ImpCastExprToType(Elem, ToType, CK_VectorSplat, VK_PRValue,
                                /*BasePath=*/nullptr, CCK)
                  .get();
       break;
-    case ICK_Floating_Integral:
-      if (ToType->hasFloatingRepresentation())
-        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();
+    }
+    case ICK_HLSL_Vector_Truncation: {
+      // Note: HLSL built-in 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.
+      assert(From->getType()->isExtVectorType() && ToType->isExtVectorType() &&
+             "HLSL vector truncation should only apply to ExtVectors");
+      auto *FromVec = From->getType()->castAs<VectorType>();
+      auto *ToVec = ToType->castAs<VectorType>();
+      QualType ElType = FromVec->getElementType();
+      QualType TruncTy =
+          Context.getExtVectorType(ElType, ToVec->getNumElements());
+      From = ImpCastExprToType(From, TruncTy, CK_HLSLVectorTruncation,
+                               From->getValueKind())
+                 .get();
       break;
+    }
     case ICK_Identity:
     default:
       llvm_unreachable("Improper element standard conversion");
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index fb4ff72e42eb5..e17b62f32626a 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -163,13 +163,33 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
       ICR_C_Conversion,
       ICR_C_Conversion_Extension,
       ICR_Conversion,
+      ICR_HLSL_Dimension_Reduction,
       ICR_Conversion,
-      ICR_Conversion,
+      ICR_HLSL_Scalar_Widening,
   };
   static_assert(std::size(Rank) == (int)ICK_Num_Conversion_Kinds);
   return Rank[(int)Kind];
 }
 
+ImplicitConversionRank
+clang::GetDimensionConversionRank(ImplicitConversionRank Base,
+                                  ImplicitConversionKind Dimension) {
+  ImplicitConversionRank Rank = GetConversionRank(Dimension);
+  if (Rank == ICR_HLSL_Scalar_Widening) {
+    if (Base == ICR_Promotion)
+      return ICR_HLSL_Scalar_Widening_Promotion;
+    if (Base == ICR_Conversion)
+      return ICR_HLSL_Scalar_Widening_Conversion;
+  }
+  if (Rank == ICR_HLSL_Dimension_Reduction) {
+    if(Base == ICR_Promotion)
+      return ICR_HLSL_Dimension_Reduction_Promotion;
+    if (Base == ICR_Conversion)
+      return ICR_HLSL_Dimension_Reduction_Conversion;
+  }
+  return Rank;
+}
+
 /// GetImplicitConversionName - Return the name of this kind of
 /// implicit conversion.
 static const char *GetImplicitConversionName(ImplicitConversionKind Kind) {
@@ -207,6 +227,7 @@ static const char *GetImplicitConversionName(ImplicitConversionKind Kind) {
       "Fixed point conversion",
       "HLSL vector truncation",
       "Non-decaying array conversion",
+      "HLSL vector splat",
   };
   static_assert(std::size(Name) == (int)ICK_Num_Conversion_Kinds);
   return Name[Kind];
@@ -217,7 +238,7 @@ static const char *GetImplicitConversionName(ImplicitConversionKind Kind) {
 void StandardConversionSequence::setAsIdentityConversion() {
   First = ICK_Identity;
   Second = ICK_Identity;
-  Element = ICK_Identity;
+  Dimension = ICK_Identity;
   Third = ICK_Identity;
   DeprecatedStringLiteralToCharPtr = false;
   QualificationIncludesObjCLifetime = false;
@@ -240,8 +261,8 @@ ImplicitConversionRank StandardConversionSequence::getRank() const {
     Rank = GetConversionRank(First);
   if (GetConversionRank(Second) > Rank)
     Rank = GetConversionRank(Second);
-  if (GetConversionRank(Element) > Rank)
-    Rank = GetConversionRank(Element);
+  if (GetDimensionConversionRank(Rank, Dimension) > Rank)
+    Rank = GetDimensionConversionRank(Rank, Dimension);
   if (GetConversionRank(Third) > Rank)
     Rank = GetConversionRank(Third);
   return Rank;
@@ -1989,15 +2010,15 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
         if (FromElts < ToElts)
           return false;
         if (FromElts == ToElts)
-          ICK = ICK_Identity;
+          ElConv = ICK_Identity;
         else
-          ICK = ICK_HLSL_Vector_Truncation;
+          ElConv = ICK_HLSL_Vector_Truncation;
 
         QualType FromElTy = FromExtType->getElementType();
         QualType ToElTy = ToExtType->getElementType();
         if (S.Context.hasSameUnqualifiedType(FromElTy, ToElTy))
           return true;
-        return IsVectorElementConversion(S, FromElTy, ToElTy, ElConv, From);
+        return IsVectorElementConversion(S, FromElTy, ToElTy, ICK, From);
       }
       // There are no conversions between extended vector types other than the
       // identity conversion.
@@ -2006,6 +2027,11 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
 
     // Vector splat from any arithmetic type to a vector.
     if (FromType->isArithmeticType()) {
+      if (S.getLangOpts().HLSL) {
+        ElConv = ICK_HLSL_Vector_Splat;
+        QualType ToElTy = ToExtType->getElementType();
+        return IsVectorElementConversion(S, FromType, ToElTy, ICK, From);
+      }
       ICK = ICK_Vector_Splat;
       return true;
     }
@@ -2220,7 +2246,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
   // conversion.
   bool IncompatibleObjC = false;
   ImplicitConversionKind SecondICK = ICK_Identity;
-  ImplicitConversionKind ElementICK = ICK_Identity;
+  ImplicitConversionKind DimensionICK = ICK_Identity;
   if (S.Context.hasSameUnqualifiedType(FromType, ToType)) {
     // The unqualified versions of the types are the same: there's no
     // conversion to do.
@@ -2286,10 +2312,10 @@ 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, ElementICK,
+  } else if (IsVectorConversion(S, FromType, ToType, SecondICK, DimensionICK,
                                 From, InOverloadResolution, CStyle)) {
     SCS.Second = SecondICK;
-    SCS.Element = ElementICK;
+    SCS.Dimension = DimensionICK;
     FromType = ToType.getUnqualifiedType();
   } else if (!S.getLangOpts().CPlusPlus &&
              S.Context.typesAreCompatible(ToType, FromType)) {
@@ -4341,24 +4367,6 @@ getFixedEnumPromtion(Sema &S, const StandardConversionSequence &SCS) {
   return FixedEnumPromotion::ToPromotedUnderlyingType;
 }
 
-static ImplicitConversionSequence::CompareKind
-HLSLCompareFloatingRank(QualType LHS, QualType RHS) {
-  assert(LHS->isVectorType() == RHS->isVectorType() &&
-         "Either both elements should be vectors or neither should.");
-  if (const auto *VT = LHS->getAs<VectorType>())
-    LHS = VT->getElementType();
-
-  if (const auto *VT = RHS->getAs<VectorType>())
-    RHS = VT->getElementType();
-
-  const auto L = LHS->getAs<BuiltinType>()->getKind();
-  const auto R = RHS->getAs<BuiltinType>()->getKind();
-  if (L == R)
-    return ImplicitConversionSequence::Indistinguishable;
-  return L < R ? ImplicitConversionSequence::Better
-               : ImplicitConversionSequence::Worse;
-}
-
 /// CompareStandardConversionSequences - Compare two standard
 /// conversion sequences to determine whether one is better than the
 /// other or if they are indistinguishable (C++ 13.3.3.2p3).
@@ -4599,22 +4607,6 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
                  ? ImplicitConversionSequence::Better
                  : ImplicitConversionSequence::Worse;
   }
-
-  if (S.getLangOpts().HLSL) {
-    // On a promotion we prefer the lower rank to disambiguate.
-    if ((SCS1.Second == ICK_Floating_Promotion &&
-         SCS2.Second == ICK_Floating_Promotion) ||
-        (SCS1.Element == ICK_Floating_Promotion &&
-         SCS2.Element == ICK_Floating_Promotion))
-      return HLSLCompareFloatingRank(SCS1.getToType(2), SCS2.getToType(2));
-    // On a conversion we prefer the higher rank to disambiguate.
-    if ((SCS1.Second == ICK_Floating_Conversion &&
-         SCS2.Second == ICK_Floating_Conversion) ||
-        (SCS1.Element == ICK_Floating_Conversion &&
-         SCS2.Element == ICK_Floating_Conversion))
-      return HLSLCompareFloatingRank(SCS2.getToType(2), SCS1.getToType(2));
-  }
-
   return ImplicitConversionSequence::Indistinguishable;
 }
 
@@ -5164,7 +5156,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
                               : (RefConv & Sema::ReferenceConversions::ObjC)
                                     ? ICK_Compatible_Conversion
                                     : ICK_Identity;
-    ICS.Standard.Element = ICK_Identity;
+    ICS.Standard.Dimension = 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.
@@ -6082,6 +6074,7 @@ static bool CheckConvertedConstantConversions(Sema &S,
   case ICK_Vector_Conversion:
   case ICK_SVE_Vector_Conversion:
   case ICK_RVV_Vector_Conversion:
+  case ICK_HLSL_Vector_Splat:
   case ICK_Vector_Splat:
   case ICK_Complex_Real:
   case ICK_Block_Pointer_Conversion:
@@ -6371,7 +6364,7 @@ Sema::EvaluateConvertedConstantExpression(Expr *E, QualType T, APValue &Value,
 static void dropPointerConversion(StandardConversionSequence &SCS) {
   if (SCS.Second == ICK_Pointer_Conversion) {
     SCS.Second = ICK_Identity;
-    SCS.Element = ICK_Identity;
+    SCS.Dimension = ICK_Identity;
     SCS.Third = ICK_Identity;
     SCS.ToTypePtrs[2] = SCS.ToTypePtrs[1] = SCS.ToTypePtrs[0];
   }
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl
index 06e3cc5af87e1..5d751be6dae06 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl
@@ -30,8 +30,8 @@ void f3_to_f2() {
 // 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> <i32 0, i32 1>
-// CHECK: [[vecf2:%.*]] = fptrunc <2 x double> [[vecd2]] to <2 x float>
+// CHECK: [[vecf4:%.*]] = fptrunc <4 x double> [[vecd4]] to <4 x float>
+// CHECK: [[vecf2:%.*]] = shufflevector <4 x float> [[vecf4]], <4 x float> poison, <2 x i32> <i32 0, i32 1>
 // CHECK: store <2 x float> [[vecf2]], ptr [[f2]]
 void d4_to_f2() {
   vector<double,4> d4 = 3.0;
@@ -55,8 +55,8 @@ void f2_to_i2() {
 // 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> <i32 0, i32 1>
-// CHECK: [[veci2]] = fptosi <2 x double> [[vecd2]] to <2 x i32>
+// CHECK: [[veci4:%.*]] = fptosi <4 x double> [[vecd4]] to <4 x i32>
+// CHECK: [[veci2:%.*]] = shufflevector <4 x i32> [[veci4]], <4 x i32> poison, <2 x i32> <i32 0, i32 1>
 // CHECK: store <2 x i32> [[veci2]], ptr [[i2]]
 void d4_to_i2() {
   vector<double,4> d4 = 5.0;
@@ -81,8 +81,8 @@ void d4_to_l4() {
 // 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> <i32 0, i32 1>
-// CHECK: [[veci2:%.*]] = trunc <2 x i64> [[vecl2]] to <2 x i32>
+// CHECK: [[veci4:%.*]] = trunc <4 x i64> [[vecl4]] to <4 x i32>
+// CHECK: [[veci2:%.*]] = shufflevector <4 x i32> [[veci4]], <4 x i32> poison, <2 x i32> <i32 0, i32 1>
 // CHECK: store <2 x i32> [[veci2]], ptr [[i2]]
 void l4_to_i2() {
   vector<long, 4> l4 = 7;
@@ -108,9 +108,9 @@ void i2_to_b2() {
 // 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> <i32 0, i32 1>
-// 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: [[vecb4:%.*]] = fcmp une <4 x double> [[vecd4]], zeroinitializer
+// CHECK: [[vecd2:%.*]] = shufflevector <4 x i1> [[vecb4]], <4 x i1> poison, <2 x i32> <i32 0, i32 1>
+// CHECK: [[vecb8:%.*]] = shufflevector <2 x i1> [[vecd2]], <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() {
diff --git a/clang/test/CodeGenHLSL/builtins/dot.hlsl b/clang/test/CodeGenHLSL/builtins/dot.hlsl
index 307d71cce3cb6..ae6e45c3f9482 100644
--- a/clang/test/CodeGenHLSL/builtins/dot.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/dot.hlsl
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
 // RUN:   dxil-pc-shadermodel6.3-library %s -fnative-half-type \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s \ 
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
 // RUN:   --check-prefixes=CHECK,NATIVE_HALF
 // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
 // RUN:   dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
@@ -156,38 +156,6 @@ float test_dot_float3_splat(float p0, float3 p1) { return dot(p0, p1); }
 // CHECK: ret float %dx.dot
 float test_dot_float4_splat(float p0, float4 p1) { return dot(p0, p1); }
 
-// CHECK: %conv = sitofp i32 %1 to float
-// CHECK: %splat.splatinsert = insertelement <2 x float> poison, float %conv, i64 0
-// CHECK: %splat.splat = shufflevector <2 x float> %splat.splatinsert, <2 x float> poison, <2 x i32> zeroinitializer
-// CHECK: %dx.dot = call float @llvm.dx.dot2.v2f32(<2 x float> %0, <2 x float> %splat.splat)
-// CHECK: ret float %dx.dot
-float test_builtin_dot_float2_int_splat(float2 p0, int p1) {
-  return dot(p0, p1);
-}
-
-// CHECK: %conv = sitofp i32 %1 to float
-// CHECK: %splat.splatinsert = insertelement <3 x float> poison, float %conv, i64 0
-// CHECK: %splat.splat = shufflevector <3 x float> %splat.splatinsert, <3 x float> poison, <3 x i32> zeroinitializer
-// CHECK: %dx.dot = call float @llvm.dx.dot3.v3f32(<3 x float> %0, <3 x float> %splat.splat)
-// CHECK: ret float %dx.dot
-float test_builtin_dot_float3_int_splat(float3 p0, int p1) {
-  return dot(p0, p1);
-}
-
 // CHECK: %dx.dot = fmul double %0, %1
 // CHECK: ret double %dx.dot
 double test_dot_double(double p0, double p1) { return dot(p0, p1); }
-
-// CHECK: %conv = zext i1 %tobool to i32
-// CHECK: %dx.dot = mul i32 %conv, %1
-// CHECK: ret i32 %dx.dot
-int test_dot_bool_scalar_arg0_type_promotion(bool p0, int p1) {
-  return dot(p0, p1);
-}
-
-// CHECK: %conv = zext i1 %tobool to i32
-// CHECK: %dx.dot = mul i32 %0, %conv
-// CHECK: ret i32 %dx.dot
-int test_dot_bool_scalar_arg1_type_promotion(int p0, bool p1) {
-  return dot(p0, p1);
-}
diff --git a/clang/test/CodeGenHLSL/builtins/lerp.hlsl b/clang/test/CodeGenHLSL/builtins/lerp.hlsl
index bbb419acaf3ba..53ac24dd45693 100644
--- a/clang/test/CodeGenHLSL/builtins/lerp.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/lerp.hlsl
@@ -86,27 +86,3 @@ float3 test_lerp_float3_splat(float p0, float3 p1) { return lerp(p0, p1, p1); }
 // SPIR_CHECK: %hlsl.lerp = call <4 x float> @llvm.spv.lerp.v4f32(<4 x float> %splat.splat, <4 x float> %[[b]], <4 x float> %[[c]])
 // CHECK:  ret <4 x float> %hlsl.lerp
 float4 test_lerp_float4_splat(float p0, float4 p1) { return lerp(p0, p1, p1); }
-
-// CHECK: %[[a:.*]] = load <2 x float>, ptr %p0.addr, align 8
-// CHECK: %[[b:.*]] = load <2 x float>, ptr %p0.addr, align 8
-// CHECK: %conv = sitofp i32 {{.*}} to float
-// CHECK: %splat.splatinsert = insertelement <2 x float> poison, float %conv, i64 0
-// CHECK: %splat.splat = shufflevector <2 x float> %splat.splatinsert, <2 x float> poison, <2 x i32> zeroinitializer
-// DXIL_CHECK: %hlsl.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %[[a]], <2 x float> %[[b]], <2 x float> %splat.splat)
-// SPIR_CHECK: %hlsl.lerp = call <2 x float> @llvm.spv.lerp.v2f32(<2 x float> %[[a]], <2 x float> %[[b]], <2 x float> %splat.splat)
-// CHECK: ret <2 x float> %hlsl.lerp
-float2 test_lerp_float2_int_splat(float2 p0, int p1) {
-  return lerp(p0, p0, p1);
-}
-
-// CHECK: %[[a:.*]] = load <3 x float>, ptr %p0.addr, align 16
-// CHECK: %[[b:.*]] = load <3 x float>, ptr %p0.addr, align 16
-// CHECK: %conv = sitofp i32 {{.*}} to float
-// CHECK: %splat.splatinsert = insertelement <3 x float> poison, float %conv, i64 0
-// CHECK: %splat.splat = shufflevector <3 x float> %splat.splatinsert, <3 x float> poison, <3 x i32> zeroinitializer
-// DXIL_CHECK:  %hlsl.lerp = call <3 x float> @llvm.dx.lerp.v3f32(<3 x float> %[[a]], <3 x float> %[[b]], <3 x float> %splat.splat)
-// SPIR_CHECK:  %hlsl.lerp = call <3 x float> @llvm.spv.lerp.v3f32(<3 x float> %[[a]], <3 x float> %[[b]], <3 x float> %splat.splat)
-// CHECK: ret <3 x float> %hlsl.lerp
-float3 test_lerp_float3_int_splat(float3 p0, int p1) {
-  return lerp(p0, p0, p1);
-}
diff --git a/clang/test/CodeGenHLSL/builtins/mad.hlsl b/clang/test/CodeGenHLSL/builtins/mad.hlsl
index 559e1d1dd3903..449a793caf93b 100644
--- a/clang/test/CodeGenHLSL/builtins/mad.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/mad.hlsl
@@ -281,25 +281,3 @@ float3 test_mad_float3_splat(float p0, float3 p1, float3 p2) { return mad(p0, p1
 // CHECK:  %hlsl.fmad = call <4 x float>  @llvm.fmuladd.v4f32(<4 x float> %splat.splat, <4 x float> %[[p1]], <4 x float> %[[p2]])
 // CHECK:  ret <4 x float> %hlsl.fmad
 float4 test_mad_float4_splat(float p0, float4 p1, float4 p2) { return mad(p0, p1, p2); }
-
-// CHECK: %[[p0:.*]] = load <2 x float>, ptr %p0.addr, align 8
-// CHECK: %[[p1:.*]] = load <2 x float>, ptr %p1.addr, align 8
-// CHECK: %conv = sitofp i32 %{{.*}} to float
-// CHECK: %splat.splatinsert = insertelement <2 x float> poison, float %conv, i64 0
-// CHECK: %splat.splat = shufflevector <2 x float> %splat.splatinsert, <2 x float> poison, <2 x i32> zeroinitializer
-// CHECK: %hlsl.fmad = call <2 x float>  @llvm.fmuladd.v2f32(<2 x float> %[[p0]], <2 x float> %[[p1]], <2 x float> %splat.splat)
-// CHECK: ret <2 x float> %hlsl.fmad
-float2 test_mad_float2_int_splat(float2 p0, float2 p1, int p2) {
-  return mad(p0, p1, p2);
-}
-
-// CHECK: %[[p0:.*]] = load <3 x float>, ptr %p0.addr, align 16
-// CHECK: %[[p1:.*]] = load <3 x float>, ptr %p1.addr, align 16
-// CHECK: %conv = sitofp i32 %{{.*}} to float
-// CHECK: %splat.splatinsert = insertelement <3 x float> poison, float %conv, i64 0
-// CHECK: %splat.splat = shufflevector <3 x float> %splat.splatinsert, <3 x float> poison, <3 x i32> zeroinitializer
-// CHECK:  %hlsl.fmad = call <3 x float>  @llvm.fmuladd.v3f32(<3 x float> %[[p0]], <3 x float> %[[p1]], <3 x float> %splat.splat)
-// CHECK: ret <3 x float> %hlsl.fmad
-float3 test_mad_float3_int_splat(float3 p0, float3 p1, int p2) {
-  return mad(p0, p1, p2);
-}
diff --git a/clang/test/SemaHLSL/ScalarOverloadResolution.hlsl b/clang/test/SemaHLSL/ScalarOverloadResolution.hlsl
index 41702ef175320..77090b7fda257 100644
--- a/clang/test/SemaHLSL/ScalarOverloadResolution.hlsl
+++ b/clang/test/SemaHLSL/ScalarOverloadResolution.hlsl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -Wconversion -verify -o - %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -Wconversion -verify -o - -DERROR=1 %s
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -ast-dump %s | FileCheck %s
 
 // This test verifies floating point type implicit conversion ranks for overload
@@ -19,8 +19,8 @@ void HalfFloatDouble(half H);
 // CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (float)'
 // CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (half)'
 
-void FloatDouble(double D);
-void FloatDouble(float F);
+void FloatDouble(double D); // expected-note{{candidate function}}
+void FloatDouble(float F); // expected-note{{candidate function}}
 
 // CHECK: FunctionDecl {{.*}} used FloatDouble 'void (double)'
 // CHECK: FunctionDecl {{.*}} used FloatDouble 'void (float)'
@@ -31,8 +31,8 @@ void HalfDouble(half H);
 // CHECK: FunctionDecl {{.*}} used HalfDouble 'void (double)'
 // CHECK: FunctionDecl {{.*}} used HalfDouble 'void (half)'
 
-void HalfFloat(float F);
-void HalfFloat(half H);
+void HalfFloat(float F); // expected-note{{candidate function}}
+void HalfFloat(half H); // expected-note{{candidate function}}
 
 // CHECK: FunctionDecl {{.*}} used HalfFloat 'void (float)'
 // CHECK: FunctionDecl {{.*}} used HalfFloat 'void (half)'
@@ -73,8 +73,8 @@ void Case1(half H, float F, double D) {
 }
 
 // Case 2: A function declared with double and float overlaods.
-//   (a) When called with half, it will resolve to float because float is lower
-//   ranked than double.
+//   (a) When called with half, it will fail to resolve because it cannot
+//   disambiguate the promotions.
 //   (b) When called with float it will resolve to float because float is an
 //   exact match.
 //   (c) When called with double it will resolve to double because it is an
@@ -82,10 +82,9 @@ void Case1(half H, float F, double D) {
 
 // CHECK-LABEL: FunctionDecl {{.*}} Case2 'void (half, float, double)'
 void Case2(half H, float F, double D) {
-  // CHECK: CallExpr {{.*}} 'void'
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' <FunctionToPointerDecay>
-  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'FloatDouble' 'void (float)'
-  FloatDouble(H);
+  #if ERROR
+  FloatDouble(H); // expected-error{{call to 'FloatDouble' is ambiguous}}
+  #endif
 
   // CHECK: CallExpr {{.*}} 'void'
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' <FunctionToPointerDecay>
@@ -144,10 +143,9 @@ void Case4(half H, float F, double D) {
   // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'HalfFloat' 'void (float)'
   HalfFloat(F);
 
-  // CHECK: CallExpr {{.*}} 'void'
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' <FunctionToPointerDecay>
-  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'HalfFloat' 'void (float)'
-  HalfFloat(D); // expected-warning{{implicit conversion loses floating-point precision: 'double' to 'float'}}
+  #if ERROR
+  HalfFloat(D); // expected-error{{call to 'HalfFloat' is ambiguous}}
+  #endif
 }
 
 // Case 5: A function declared with only a double overload.
diff --git a/clang/test/SemaHLSL/SplatOverloadResolution.hlsl b/clang/test/SemaHLSL/SplatOverloadResolution.hlsl
new file mode 100644
index 0000000000000..f0798dfc72497
--- /dev/null
+++ b/clang/test/SemaHLSL/SplatOverloadResolution.hlsl
@@ -0,0 +1,166 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -fsyntax-only %s -DERROR=1 -verify
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -ast-dump %s | FileCheck %s
+
+
+// Case 1: Prioritize splat without conversion over conversion. In this case the
+// called functions have valid overloads for each type, however one of the
+// overloads is a vector rather than scalar. Each call should resolve to the
+// same type, and the vector should splat.
+void HalfFloatDoubleV(double2 D);
+void HalfFloatDoubleV(float F);
+void HalfFloatDoubleV(half H);
+
+void HalfFloatVDouble(double D);
+void HalfFloatVDouble(float2 F);
+void HalfFloatVDouble(half H);
+
+void HalfVFloatDouble(double D);
+void HalfVFloatDouble(float F);
+void HalfVFloatDouble(half2 H);
+
+
+// CHECK-LABEL: FunctionDecl {{.*}} Case1 'void (half, float, double)'
+void Case1(half H, float F, double D) {
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half)' lvalue Function {{.*}} 'HalfFloatDoubleV' 'void (half)'
+  HalfFloatDoubleV(H);
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'HalfFloatDoubleV' 'void (float)'
+  HalfFloatDoubleV(F);
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'HalfFloatDoubleV' 'void (double2)'
+  HalfFloatDoubleV(D);
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half)' lvalue Function {{.*}} 'HalfFloatVDouble' 'void (half)'
+  HalfFloatVDouble(H);
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'HalfFloatVDouble' 'void (float2)'
+  HalfFloatVDouble(F);
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'HalfFloatVDouble' 'void (double)'
+  HalfFloatVDouble(D);
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'HalfVFloatDouble' 'void (half2)'
+  HalfVFloatDouble(H);
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'HalfVFloatDouble' 'void (float)'
+  HalfVFloatDouble(F);
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'HalfVFloatDouble' 'void (double)'
+  HalfVFloatDouble(D);
+}
+
+// Case 2: Prefer splat+promotion over conversion. In this case the overloads
+// require a splat+promotion or a conversion. The call will resolve to the
+// splat+promotion.
+void HalfDoubleV(double2 D);
+void HalfDoubleV(half H);
+
+// CHECK-LABEL: FunctionDecl {{.*}} Case2 'void (float)'
+void Case2(float F) {
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'HalfDoubleV' 'void (double2)'
+  HalfDoubleV(F);
+}
+
+// Case 3: Prefer promotion or conversion without splat over the splat. In this
+// case the scalar value will overload to the scalar function.
+void DoubleV(double D);
+void DoubleV(double2 V);
+
+void HalfV(half D);
+void HalfV(half2 V);
+
+// CHECK-LABEL: FunctionDecl {{.*}} Case3 'void (float)'
+void Case3(float F) {
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'DoubleV' 'void (double)'
+  DoubleV(F);
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half)' lvalue Function {{.*}} 'HalfV' 'void (half)'
+  HalfV(F);
+}
+
+#if ERROR
+// Case 4: It is ambiguous to resolve two splat+conversion or splat+promotion
+// functions. In all the calls below an error occurs.
+void FloatVDoubleV(float2 F); // expected-note {{candidate function}}
+void FloatVDoubleV(double2 D); // expected-note {{candidate function}}
+
+void HalfVFloatV(half2 H); // expected-note {{candidate function}}
+void HalfVFloatV(float2 F); // expected-note {{candidate function}}
+
+void Case4(half H, double D) {
+  FloatVDoubleV(H); // expected-error {{call to 'FloatVDoubleV' is ambiguous}}
+
+  HalfVFloatV(D); // expected-error {{call to 'HalfVFloatV' is ambiguous}}
+}
+
+// Case 5: It is ambiguous to resolve two splats of different lengths.
+void FloatV(float2 V); // expected-note {{candidate function}} expected-note {{candidate function}} expected-note {{candidate function}}
+void FloatV(float4 V); // expected-note {{candidate function}} expected-note {{candidate function}} expected-note {{candidate function}}
+
+void Case5(half H, float F, double D) {
+  FloatV(H); // expected-error {{call to 'FloatV' is ambiguous}}
+  FloatV(F); // expected-error {{call to 'FloatV' is ambiguous}}
+  FloatV(D); // expected-error {{call to 'FloatV' is ambiguous}}
+}
+#endif
+
+// Case 5: Vectors truncate or match, but don't extend.
+void FloatV24(float2 V);
+void FloatV24(float4 V);
+
+// CHECK-LABEL: FunctionDecl {{.*}} Case5 'void (half3, float3, double3, half4, float4, double4)'
+void Case5(half3 H3, float3 F3, double3 D3, half4 H4, float4 F4, double4 D4) {
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'FloatV24' 'void (float2)'
+  FloatV24(H3); // expected-warning{{implicit conversion truncates vector: 'half3' (aka 'vector<half, 3>') to 'vector<float, 2>' (vector of 2 'float' values)}}
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'FloatV24' 'void (float2)'
+  FloatV24(F3); // expected-warning{{implicit conversion truncates vector: 'float3' (aka 'vector<float, 3>') to 'vector<float, 2>' (vector of 2 'float' values)}}
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'FloatV24' 'void (float2)'
+  FloatV24(D3); // expected-warning{{implicit conversion truncates vector: 'double3' (aka 'vector<double, 3>') to 'vector<float, 2>' (vector of 2 'float' values)}}
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float4)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float4)' lvalue Function {{.*}} 'FloatV24' 'void (float4)'
+  FloatV24(H4);
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float4)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float4)' lvalue Function {{.*}} 'FloatV24' 'void (float4)'
+  FloatV24(F4);
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float4)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float4)' lvalue Function {{.*}} 'FloatV24' 'void (float4)'
+  FloatV24(D4);
+}
diff --git a/clang/test/SemaHLSL/TruncationOverloadResolution.hlsl b/clang/test/SemaHLSL/TruncationOverloadResolution.hlsl
new file mode 100644
index 0000000000000..f8cfe22372e88
--- /dev/null
+++ b/clang/test/SemaHLSL/TruncationOverloadResolution.hlsl
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -fsyntax-only %s -DERROR=1 -verify
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -ast-dump %s | FileCheck %s
+
+// Case 1: Prefer exact-match truncation over conversion.
+void Half4Float4Double2(double2 D);
+void Half4Float4Double2(float4 D);
+void Half4Float4Double2(half4 D);
+
+void Half4Float2(float2 D);
+void Half4Float2(half4 D);
+
+void Case1(float4 F, double4 D) {
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'Half4Float4Double2' 'void (double2)'
+  Half4Float4Double2(D); // expected-warning{{implicit conversion truncates vector: 'double4' (aka 'vector<double, 4>') to 'vector<double, 2>' (vector of 2 'double' values)}}
+
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'Half4Float2' 'void (float2)'
+  Half4Float2(F); // expected-warning{{implicit conversion truncates vector: 'float4' (aka 'vector<float, 4>') to 'vector<float, 2>' (vector of 2 'float' values)}}
+}
+
+// Case 2: Prefer promotions over conversions when truncating.
+void Half2Double2(double2 D);
+void Half2Double2(half2 H);
+
+void Case2(float4 F) {
+  // CHECK: CallExpr {{.*}} 'void'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'Half2Double2' 'void (double2)'
+  Half2Double2(F); // expected-warning{{implicit conversion truncates vector: 'float4' (aka 'vector<float, 4>') to 'vector<double, 2>' (vector of 2 'double' values)}}
+}
+
+#if ERROR
+// Case 3: Two promotions or two conversions are ambiguous.
+void Float2Double2(double2 D); // expected-note{{candidate function}}
+void Float2Double2(float2 D); // expected-note{{candidate function}}
+
+void Half2Float2(float2 D); // expected-note{{candidate function}}
+void Half2Float2(half2 D); // expected-note{{candidate function}}
+
+void Half2Half3(half3 D); // expected-note{{candidate function}} expected-note{{candidate function}} expected-note{{candidate function}}
+void Half2Half3(half2 D); // expected-note{{candidate function}} expected-note{{candidate function}} expected-note{{candidate function}}
+
+void Double2Double3(double3 D); // expected-note{{candidate function}} expected-note{{candidate function}} expected-note{{candidate function}}
+void Double2Double3(double2 D); // expected-note{{candidate function}} expected-note{{candidate function}} expected-note{{candidate function}}
+
+void Case1(half4 H, float4 F, double4 D) {
+  Float2Double2(H); // expected-error {{call to 'Float2Double2' is ambiguous}}
+
+  Half2Float2(D); // expected-error {{call to 'Half2Float2' is ambiguous}}
+
+  Half2Half3(H); // expected-error {{call to 'Half2Half3' is ambiguous}}
+  Half2Half3(F); // expected-error {{call to 'Half2Half3' is ambiguous}}
+  Half2Half3(D); // expected-error {{call to 'Half2Half3' is ambiguous}}
+  Half2Half3(H.xyz);
+  Half2Half3(F.xyz);
+  Half2Half3(D.xyz);
+
+  Double2Double3(H); // expected-error {{call to 'Double2Double3' is ambiguous}}
+  Double2Double3(F); // expected-error {{call to 'Double2Double3' is ambiguous}}
+  Double2Double3(D); // expected-error {{call to 'Double2Double3' is ambiguous}}
+  Double2Double3(D.xyz);
+  Double2Double3(F.xyz);
+  Double2Double3(H.xyz);
+}
+#endif
diff --git a/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl b/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl
index 683c05b20c34e..78ff54987a5bf 100644
--- a/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl
+++ b/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl
@@ -113,7 +113,7 @@ int64_t4 HooBoy() {
 // list with float truncation casts.
 
 // CHECK-LABEL: AllRighty
-// CHECK: ImplicitCastExpr {{.*}} 'float3':'vector<float, 3>' <FloatingCast>
+// CHECK: ImplicitCastExpr {{.*}} 'vector<float, 3>' <FloatingCast>
 // CHECK-NEXT: ExtVectorElementExpr {{.*}} 'vector<double, 3>' rrr
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 1>' <VectorSplat>
 // CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
diff --git a/clang/test/SemaHLSL/VectorElementOverloadResolution.hlsl b/clang/test/SemaHLSL/VectorElementOverloadResolution.hlsl
index 12575084ead2b..a980cbd252965 100644
--- a/clang/test/SemaHLSL/VectorElementOverloadResolution.hlsl
+++ b/clang/test/SemaHLSL/VectorElementOverloadResolution.hlsl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -Wconversion -verify -o - %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -Wconversion -verify -o - %s -DERROR=1
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -Wno-conversion -ast-dump %s | FileCheck %s
 
 // This test verifies floating point type implicit conversion ranks for overload
@@ -19,8 +19,8 @@ void HalfFloatDouble(half2 H);
 // CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (float2)'
 // CHECK: FunctionDecl {{.*}} used HalfFloatDouble 'void (half2)'
 
-void FloatDouble(double2 D);
-void FloatDouble(float2 F);
+void FloatDouble(double2 D); // expected-note {{candidate function}}
+void FloatDouble(float2 F); // expected-note {{candidate function}}
 
 // CHECK: FunctionDecl {{.*}} used FloatDouble 'void (double2)'
 // CHECK: FunctionDecl {{.*}} used FloatDouble 'void (float2)'
@@ -31,8 +31,8 @@ void HalfDouble(half2 H);
 // CHECK: FunctionDecl {{.*}} used HalfDouble 'void (double2)'
 // CHECK: FunctionDecl {{.*}} used HalfDouble 'void (half2)'
 
-void HalfFloat(float2 F);
-void HalfFloat(half2 H);
+void HalfFloat(float2 F); // expected-note {{candidate function}}
+void HalfFloat(half2 H); // expected-note {{candidate function}}
 
 // CHECK: FunctionDecl {{.*}} used HalfFloat 'void (float2)'
 // CHECK: FunctionDecl {{.*}} used HalfFloat 'void (half2)'
@@ -72,8 +72,7 @@ void Case1(half2 H, float2 F, double2 D) {
 }
 
 // Case 2: A function declared with double and float overlaods.
-//   (a) When called with half, it will resolve to float because float is lower
-//   ranked than double.
+//   (a) When called with half, it fails to resulve the ambiguous promotion.
 //   (b) When called with float it will resolve to float because float is an
 //   exact match.
 //   (c) When called with double it will resolve to double because it is an
@@ -81,10 +80,9 @@ void Case1(half2 H, float2 F, double2 D) {
 
 // CHECK-LABEL: FunctionDecl {{.*}} Case2 'void (half2, float2, double2)'
 void Case2(half2 H, float2 F, double2 D) {
-  // CHECK: CallExpr {{.*}} 'void'
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
-  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'FloatDouble' 'void (float2)'
-  FloatDouble(H);
+#if ERROR
+  FloatDouble(H); // expected-error {{call to 'FloatDouble' is ambiguous}}
+#endif
 
   // CHECK: CallExpr {{.*}} 'void'
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
@@ -128,8 +126,7 @@ void Case3(half2 H, float2 F, double2 D) {
 //   match.
 //   (b) When called with float it will resolve to float because float is an
 //   exact match.
-//   (c) When called with double it will resolve to float because it is the
-//   float is higher rank than half.
+//   (c) When called with double it fails to resolve the ambigjuous conversion.
 
 // CHECK-LABEL: FunctionDecl {{.*}} Case4 'void (half2, float2, double2)'
 void Case4(half2 H, float2 F, double2 D) {
@@ -143,10 +140,9 @@ void Case4(half2 H, float2 F, double2 D) {
   // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'HalfFloat' 'void (float2)'
   HalfFloat(F);
 
-  // CHECK: CallExpr {{.*}} 'void'
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
-  // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'HalfFloat' 'void (float2)'
-  HalfFloat(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector<double, 2>') to 'float2' (aka 'vector<float, 2>')}}
+#if ERROR
+  HalfFloat(D); // expected-error{{call to 'HalfFloat' is ambiguous}}
+#endif
 }
 
 // Case 5: A function declared with only a double overload.
@@ -198,7 +194,7 @@ void Case6(half2 H, float2 F, double2 D) {
   // CHECK: CallExpr {{.*}} 'void'
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'Float' 'void (float2)'
-  Float(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector<double, 2>') to 'float2' (aka 'vector<float, 2>')}}
+  Float(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector<double, 2>') to 'vector<float, 2>' (vector of 2 'float' values)}}
 }
 
 // Case 7: A function declared with only a half overload.
@@ -219,10 +215,10 @@ void Case7(half2 H, float2 F, double2 D) {
   // CHECK: CallExpr {{.*}} 'void'
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2)' <FunctionToPointerDecay>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'Half' 'void (half2)'
-  Half(F); // expected-warning{{implicit conversion loses floating-point precision: 'float2' (aka 'vector<float, 2>') to 'half2' (aka 'vector<half, 2>')}}
+  Half(F); // expected-warning{{implicit conversion loses floating-point precision: 'float2' (aka 'vector<float, 2>') to 'vector<half, 2>' (vector of 2 'half' values)}}
 
   // CHECK: CallExpr {{.*}} 'void'
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2)' <FunctionToPointerDecay>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'Half' 'void (half2)'
-  Half(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector<double, 2>') to 'half2' (aka 'vector<half, 2>')}}
+  Half(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector<double, 2>') to 'vector<half, 2>' (vector of 2 'half' values)}}
 }
diff --git a/clang/test/SemaHLSL/VectorOverloadResolution.hlsl b/clang/test/SemaHLSL/VectorOverloadResolution.hlsl
index 485094fd09b3c..37d5068c3067c 100644
--- a/clang/test/SemaHLSL/VectorOverloadResolution.hlsl
+++ b/clang/test/SemaHLSL/VectorOverloadResolution.hlsl
@@ -7,7 +7,7 @@ void Fn(half2 H);
 // CHECK: CallExpr {{.*}}'void'
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
 // CHECK-NEXT: DeclRefExpr {{.*}}'void (double2)' lvalue Function {{.*}} 'Fn' 'void (double2)'
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double2':'vector<double, 2>' <FloatingCast>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 2>' <FloatingCast>
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector<float, 2>' <LValueToRValue>
 // CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector<float, 2>' lvalue ParmVar {{.*}} 'F' 'float2':'vector<float, 2>'
 
@@ -22,7 +22,7 @@ void Fn2(int16_t2 S);
 // CHECK: CallExpr {{.*}} 'void'
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int64_t2)' <FunctionToPointerDecay>
 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (int64_t2)' lvalue Function {{.*}} 'Fn2' 'void (int64_t2)'
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t2':'vector<long, 2>' <IntegralCast>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<long, 2>' <IntegralCast>
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'vector<int, 2>' <LValueToRValue>
 // CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector<int, 2>' lvalue ParmVar {{.*}} 'I' 'int2':'vector<int, 2>'
 
@@ -36,7 +36,7 @@ void Fn3( int64_t2 p0);
 // CHECK: CallExpr {{.*}} 'void'
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int64_t2)' <FunctionToPointerDecay>
 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (int64_t2)' lvalue Function {{.*}} 'Fn3' 'void (int64_t2)'
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t2':'vector<long, 2>' <FloatingToIntegral>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<long, 2>' <FloatingToIntegral>
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'half2':'vector<half, 2>' <LValueToRValue>
 // CHECK-NEXT: DeclRefExpr {{.*}} 'half2':'vector<half, 2>' lvalue ParmVar {{.*}} 'p0' 'half2':'vector<half, 2>'
 // CHECKIR-LABEL: Call3
@@ -49,7 +49,7 @@ void Call3(half2 p0) {
 // CHECK: CallExpr {{.*}} 'void'
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int64_t2)' <FunctionToPointerDecay>
 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (int64_t2)' lvalue Function {{.*}} 'Fn3' 'void (int64_t2)'
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t2':'vector<long, 2>' <FloatingToIntegral>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<long, 2>' <FloatingToIntegral>
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector<float, 2>' <LValueToRValue>
 // CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector<float, 2>' lvalue ParmVar {{.*}} 'p0' 'float2':'vector<float, 2>'
 // CHECKIR-LABEL: Call4
@@ -64,7 +64,7 @@ void Fn4( float2 p0);
 // CHECK: CallExpr {{.*}} 'void'
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' <FunctionToPointerDecay>
 // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'Fn4' 'void (float2)'
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector<float, 2>' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 2>' <IntegralToFloating>
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t2':'vector<long, 2>' <LValueToRValue>
 // CHECK-NEXT: DeclRefExpr {{.*}} 'int64_t2':'vector<long, 2>' lvalue ParmVar {{.*}} 'p0' 'int64_t2':'vector<long, 2>'
 // CHECKIR-LABEL: Call5
diff --git a/clang/test/SemaHLSL/standard_conversion_sequences.hlsl b/clang/test/SemaHLSL/standard_conversion_sequences.hlsl
index c8d9f2c156e31..59779708d9137 100644
--- a/clang/test/SemaHLSL/standard_conversion_sequences.hlsl
+++ b/clang/test/SemaHLSL/standard_conversion_sequences.hlsl
@@ -23,8 +23,8 @@ void test() {
   vector<float,2> f2 = f3; // #f2
 
   // CHECK: VarDecl {{.*}} f2_2 'vector<float, 2>' cinit
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 2>' <FloatingCast>
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 2>' <HLSLVectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 2>' <HLSLVectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 4>' <FloatingCast>
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>' <LValueToRValue>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>' lvalue Var {{.*}} 'd4' 'vector<double, 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)}}
@@ -39,8 +39,8 @@ void test() {
   vector<int,2> i2 = f2; // #i2
 
   // CHECK: VarDecl {{.*}} i2_2 'vector<int, 2>' cinit
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>' <FloatingToIntegral>
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 2>' <HLSLVectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>' <HLSLVectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <FloatingToIntegral>
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>' <LValueToRValue>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>' lvalue Var {{.*}} 'd4' 'vector<double, 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)}}
@@ -56,8 +56,8 @@ void test() {
   vector<long,4> i64_4 = d4; // #i64_4
 
   // CHECK: VarDecl {{.*}} used i2_3 'vector<int, 2>' cinit
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>' <IntegralCast>
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<long, 2>' <HLSLVectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>' <HLSLVectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <IntegralCast>
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<long, 4>' <LValueToRValue>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<long, 4>' lvalue Var {{.*}} 'i64_4' 'vector<long, 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)}}
@@ -71,8 +71,8 @@ void test() {
   vector<bool, 2> b2 = i2_3; // No warning for integer to bool conversion.
 
   // CHECK: VarDecl {{.*}} b2_2 'vector<bool, 2>' cinit
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 2>' <FloatingToBoolean>
-  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 2>' <HLSLVectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 2>' <HLSLVectorTruncation>
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 4>' <FloatingToBoolean>
   // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>' <LValueToRValue>
   // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>' lvalue Var {{.*}} 'd4' 'vector<double, 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 0df92ec3aa195847220e0540a23614383d0216c2 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Tue, 18 Jun 2024 20:47:45 -0500
Subject: [PATCH 2/2] Remove overload resolution bugs test

This PR resolves all outstanding overload resolution bugs. Several of
these cases will remain ambiguous as expected and documented in the
language spec.
---
 .../test/SemaHLSL/OverloadResolutionBugs.hlsl | 63 -------------------
 1 file changed, 63 deletions(-)
 delete mode 100644 clang/test/SemaHLSL/OverloadResolutionBugs.hlsl

diff --git a/clang/test/SemaHLSL/OverloadResolutionBugs.hlsl b/clang/test/SemaHLSL/OverloadResolutionBugs.hlsl
deleted file mode 100644
index 30de00063f542..0000000000000
--- a/clang/test/SemaHLSL/OverloadResolutionBugs.hlsl
+++ /dev/null
@@ -1,63 +0,0 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -o - -fsyntax-only %s -verify
-// XFAIL: *
-
-// https://github.com/llvm/llvm-project/issues/81047
-
-// expected-no-diagnostics
-void Fn4(int64_t2 L);
-void Fn4(int2 I);
-
-void Call4(int16_t H) { Fn4(H); }
-
-int test_builtin_dot_bool_type_promotion(bool p0, bool p1) {
-  return dot(p0, p1);
-}
-
-float test_dot_scalar_mismatch(float p0, int p1) { return dot(p0, p1); }
-
-float test_dot_element_type_mismatch(int2 p0, float2 p1) { return dot(p0, p1); }
-
-float test_builtin_dot_vec_int_to_float_promotion(int2 p0, float2 p1) {
-  return dot(p0, p1);
-}
-
-int64_t test_builtin_dot_vec_int_to_int64_promotion(int64_t2 p0, int2 p1) {
-  return dot(p0, p1);
-}
-
-float test_builtin_dot_vec_half_to_float_promotion(float2 p0, half2 p1) {
-  return dot(p0, p1);
-}
-
-float test_builtin_dot_vec_int16_to_float_promotion(float2 p0, int16_t2 p1) {
-  return dot(p0, p1);
-}
-
-half test_builtin_dot_vec_int16_to_half_promotion(half2 p0, int16_t2 p1) {
-  return dot(p0, p1);
-}
-
-int test_builtin_dot_vec_int16_to_int_promotion(int2 p0, int16_t2 p1) {
-  return dot(p0, p1);
-}
-
-int64_t test_builtin_dot_vec_int16_to_int64_promotion(int64_t2 p0,
-                                                      int16_t2 p1) {
-  return dot(p0, p1);
-}
-
-float4 test_frac_int4(int4 p0) { return frac(p0); }
-
-float test_frac_int(int p0) { return frac(p0); }
-
-float test_frac_bool(bool p0) { return frac(p0); }
-
-// This resolves the wrong overload. In clang this converts down to an int, in
-// DXC it extends the scalar to a vector.
-void Fn(int) {}
-void Fn(vector<int64_t,2>) {}
-
-void Call() {
-  int64_t V;
-  Fn(V);
-}



More information about the cfe-commits mailing list