[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