From d91ff3f2409a721b61b68c6a8438ea6c59323df8 Mon Sep 17 00:00:00 2001 From: Chris B Date: Sat, 13 Jul 2024 12:23:22 -0500 Subject: [PATCH] [HLSL] Rework implicit conversion sequences (#96011) 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. We've decided that we're going to break compatibility with DXC here, and we may port this new behavior over to DXC instead. 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 believe the added conversion rank values provide a simpler approach, but feedback is appreciated. The HLSL language spec updates are in the PR here: https://github.com/microsoft/hlsl-specs/pull/261 --- clang/docs/HLSL/ExpectedDifferences.rst | 11 ++ clang/include/clang/Sema/Overload.h | 38 +++- clang/lib/Sema/SemaExprCXX.cpp | 160 ++++++++--------- 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 --- .../test/SemaHLSL/OverloadResolutionBugs.hlsl | 63 ------- .../SemaHLSL/ScalarOverloadResolution.hlsl | 30 ++-- .../SemaHLSL/SplatOverloadResolution.hlsl | 166 ++++++++++++++++++ .../TruncationOverloadResolution.hlsl | 68 +++++++ .../Types/BuiltinVector/ScalarSwizzles.hlsl | 2 +- .../VectorElementOverloadResolution.hlsl | 38 ++-- .../SemaHLSL/VectorOverloadResolution.hlsl | 10 +- .../standard_conversion_sequences.hlsl | 16 +- 16 files changed, 446 insertions(+), 339 deletions(-) delete mode 100644 clang/test/SemaHLSL/OverloadResolutionBugs.hlsl 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 d0e963441d79a..bef7da239e6e5 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4294,6 +4294,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return From; } +// adjustVectorType - 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, QualType *ElTy = nullptr) { + auto *ToVec = ToType->castAs(); + QualType ElType = ToVec->getElementType(); + if (ElTy) + *ElTy = ElType; + if (!FromTy->isVectorType()) + return ElType; + auto *FromVec = FromTy->castAs(); + return Context.getExtVectorType(ElType, FromVec->getNumElements()); +} + ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, @@ -4443,27 +4457,36 @@ 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); + if (ElTy->isBooleanType()) { assert(FromType->castAs()->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: { @@ -4486,16 +4509,21 @@ 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 (ToType->isVectorType()) + StepTy = adjustVectorType(Context, FromType, ToType, &ElTy); + 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()) && @@ -4617,18 +4645,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()->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; @@ -4754,22 +4790,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(); - auto *ToVec = ToType->castAs(); - 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: @@ -4780,73 +4800,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()->getNumElements() == - ToType->getAs()->getNumElements() && - "Element conversion is only supported for vectors with the same " - "element counts."); - QualType FromElTy = From->getType()->getAs()->getElementType(); - unsigned NumElts = ToType->getAs()->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()->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(); + auto *ToVec = ToType->castAs(); + 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 f49635aa445a6..d4a48858ec419 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -164,13 +164,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) { @@ -208,6 +228,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]; @@ -218,7 +239,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; @@ -241,8 +262,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; @@ -1970,15 +1991,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. @@ -1987,6 +2008,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; } @@ -2201,7 +2227,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. @@ -2267,10 +2293,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)) { @@ -4257,24 +4283,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()) - LHS = VT->getElementType(); - - if (const auto *VT = RHS->getAs()) - RHS = VT->getElementType(); - - const auto L = LHS->castAs()->getKind(); - const auto R = RHS->castAs()->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). @@ -4515,22 +4523,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; } @@ -5074,7 +5066,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. @@ -5990,6 +5982,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: @@ -6276,7 +6269,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> , ptr [[d4]] // CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]] -// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> -// 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> // CHECK: store <2 x float> [[vecf2]], ptr [[f2]] void d4_to_f2() { vector d4 = 3.0; @@ -55,8 +55,8 @@ void f2_to_i2() { // CHECK: [[i2:%.*]] = alloca <2 x i32> // CHECK: store <4 x double> , ptr [[d4]] // CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]] -// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> -// 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> // CHECK: store <2 x i32> [[veci2]], ptr [[i2]] void d4_to_i2() { vector d4 = 5.0; @@ -81,8 +81,8 @@ void d4_to_l4() { // CHECK: [[i2:%.*]] = alloca <2 x i32> // CHECK: store <4 x i64> , ptr [[l4]] // CHECK: [[vecl4:%.*]] = load <4 x i64>, ptr [[l4]] -// CHECK: [[vecl2:%.*]] = shufflevector <4 x i64> [[vecl4]], <4 x i64> poison, <2 x i32> -// 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> // CHECK: store <2 x i32> [[veci2]], ptr [[i2]] void l4_to_i2() { vector l4 = 7; @@ -108,9 +108,9 @@ void i2_to_b2() { // CHECK: [[b2:%.*]] = alloca i8 // CHECK: store <4 x double> , ptr [[d4]] // CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]] -// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> -// CHECK: [[vecb2:%.*]] = fcmp une <2 x double> [[vecd2]], zeroinitializer -// CHECK: [[vecb8:%.*]] = shufflevector <2 x i1> [[vecb2]], <2 x i1> poison, <8 x i32> +// CHECK: [[vecb4:%.*]] = fcmp une <4 x double> [[vecd4]], zeroinitializer +// CHECK: [[vecd2:%.*]] = shufflevector <4 x i1> [[vecb4]], <4 x i1> poison, <2 x i32> +// CHECK: [[vecb8:%.*]] = shufflevector <2 x i1> [[vecd2]], <2 x i1> poison, <8 x i32> // 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/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) {} - -void Call() { - int64_t V; - Fn(V); -} diff --git a/clang/test/SemaHLSL/ScalarOverloadResolution.hlsl b/clang/test/SemaHLSL/ScalarOverloadResolution.hlsl index d1a47af228e24..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)' @@ -72,9 +72,9 @@ void Case1(half H, float F, double D) { HalfFloatDouble(D); } -// Case 2: A function declared with double and float overloads. -// (a) When called with half, it will resolve to float because float is lower -// ranked than double. +// Case 2: A function declared with double and float overlaods. +// (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)' - // 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)' @@ -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)' - // 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)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half)' lvalue Function {{.*}} 'HalfFloatDoubleV' 'void (half)' + HalfFloatDoubleV(H); + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'HalfFloatDoubleV' 'void (float)' + HalfFloatDoubleV(F); + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'HalfFloatDoubleV' 'void (double2)' + HalfFloatDoubleV(D); + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half)' lvalue Function {{.*}} 'HalfFloatVDouble' 'void (half)' + HalfFloatVDouble(H); + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'HalfFloatVDouble' 'void (float2)' + HalfFloatVDouble(F); + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'HalfFloatVDouble' 'void (double)' + HalfFloatVDouble(D); + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'HalfVFloatDouble' 'void (half2)' + HalfVFloatDouble(H); + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float)' lvalue Function {{.*}} 'HalfVFloatDouble' 'void (float)' + HalfVFloatDouble(F); + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double)' + // 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)' + // 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)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double)' lvalue Function {{.*}} 'DoubleV' 'void (double)' + DoubleV(F); + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half)' + // 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)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'FloatV24' 'void (float2)' + FloatV24(H3); // expected-warning{{implicit conversion truncates vector: 'half3' (aka 'vector') to 'vector' (vector of 2 'float' values)}} + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'FloatV24' 'void (float2)' + FloatV24(F3); // expected-warning{{implicit conversion truncates vector: 'float3' (aka 'vector') to 'vector' (vector of 2 'float' values)}} + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'FloatV24' 'void (float2)' + FloatV24(D3); // expected-warning{{implicit conversion truncates vector: 'double3' (aka 'vector') to 'vector' (vector of 2 'float' values)}} + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float4)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float4)' lvalue Function {{.*}} 'FloatV24' 'void (float4)' + FloatV24(H4); + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float4)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float4)' lvalue Function {{.*}} 'FloatV24' 'void (float4)' + FloatV24(F4); + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float4)' + // 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)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'Half4Float4Double2' 'void (double2)' + Half4Float4Double2(D); // expected-warning{{implicit conversion truncates vector: 'double4' (aka 'vector') to 'vector' (vector of 2 'double' values)}} + + // CHECK: CallExpr {{.*}} 'void' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'Half4Float2' 'void (float2)' + Half4Float2(F); // expected-warning{{implicit conversion truncates vector: 'float4' (aka 'vector') to 'vector' (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)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'Half2Double2' 'void (double2)' + Half2Double2(F); // expected-warning{{implicit conversion truncates vector: 'float4' (aka 'vector') to 'vector' (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' +// CHECK: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: ExtVectorElementExpr {{.*}} 'vector' rrr // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00 diff --git a/clang/test/SemaHLSL/VectorElementOverloadResolution.hlsl b/clang/test/SemaHLSL/VectorElementOverloadResolution.hlsl index bbf8d3b5e102c..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)' @@ -71,9 +71,8 @@ void Case1(half2 H, float2 F, double2 D) { HalfFloatDouble(D); } -// Case 2: A function declared with double and float overloads. -// (a) When called with half, it will resolve to float because float is lower -// ranked than double. +// Case 2: A function declared with double and float overlaods. +// (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)' - // 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)' @@ -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)' - // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'HalfFloat' 'void (float2)' - HalfFloat(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector') to 'float2' (aka 'vector')}} +#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)' // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'Float' 'void (float2)' - Float(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector') to 'float2' (aka 'vector')}} + Float(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector') to 'vector' (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)' // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'Half' 'void (half2)' - Half(F); // expected-warning{{implicit conversion loses floating-point precision: 'float2' (aka 'vector') to 'half2' (aka 'vector')}} + Half(F); // expected-warning{{implicit conversion loses floating-point precision: 'float2' (aka 'vector') to 'vector' (vector of 2 'half' values)}} // CHECK: CallExpr {{.*}} 'void' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half2)' // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half2)' lvalue Function {{.*}} 'Half' 'void (half2)' - Half(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector') to 'half2' (aka 'vector')}} + Half(D); // expected-warning{{implicit conversion loses floating-point precision: 'double2' (aka 'vector') to 'vector' (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)' // CHECK-NEXT: DeclRefExpr {{.*}}'void (double2)' lvalue Function {{.*}} 'Fn' 'void (double2)' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' // CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'F' 'float2':'vector' @@ -22,7 +22,7 @@ void Fn2(int16_t2 S); // CHECK: CallExpr {{.*}} 'void' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int64_t2)' // CHECK-NEXT: DeclRefExpr {{.*}} 'void (int64_t2)' lvalue Function {{.*}} 'Fn2' 'void (int64_t2)' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'vector' // CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector' lvalue ParmVar {{.*}} 'I' 'int2':'vector' @@ -36,7 +36,7 @@ void Fn3( int64_t2 p0); // CHECK: CallExpr {{.*}} 'void' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int64_t2)' // CHECK-NEXT: DeclRefExpr {{.*}} 'void (int64_t2)' lvalue Function {{.*}} 'Fn3' 'void (int64_t2)' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'half2':'vector' // CHECK-NEXT: DeclRefExpr {{.*}} 'half2':'vector' lvalue ParmVar {{.*}} 'p0' 'half2':'vector' // CHECKIR-LABEL: Call3 @@ -49,7 +49,7 @@ void Call3(half2 p0) { // CHECK: CallExpr {{.*}} 'void' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int64_t2)' // CHECK-NEXT: DeclRefExpr {{.*}} 'void (int64_t2)' lvalue Function {{.*}} 'Fn3' 'void (int64_t2)' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' // CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'p0' 'float2':'vector' // CHECKIR-LABEL: Call4 @@ -64,7 +64,7 @@ void Fn4( float2 p0); // CHECK: CallExpr {{.*}} 'void' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'Fn4' 'void (float2)' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t2':'vector' // CHECK-NEXT: DeclRefExpr {{.*}} 'int64_t2':'vector' lvalue ParmVar {{.*}} 'p0' 'int64_t2':'vector' // 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 f2 = f3; // #f2 // CHECK: VarDecl {{.*}} f2_2 'vector' cinit - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: DeclRefExpr {{.*}} 'vector' lvalue Var {{.*}} 'd4' 'vector' // expected-warning@#f2_2{{implicit conversion truncates vector: 'vector' (vector of 4 'double' values) to 'vector' (vector of 2 'float' values)}} @@ -39,8 +39,8 @@ void test() { vector i2 = f2; // #i2 // CHECK: VarDecl {{.*}} i2_2 'vector' cinit - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: DeclRefExpr {{.*}} 'vector' lvalue Var {{.*}} 'd4' 'vector' // expected-warning@#i2_2{{implicit conversion truncates vector: 'vector' (vector of 4 'double' values) to 'vector' (vector of 2 'int' values)}} @@ -56,8 +56,8 @@ void test() { vector i64_4 = d4; // #i64_4 // CHECK: VarDecl {{.*}} used i2_3 'vector' cinit - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: DeclRefExpr {{.*}} 'vector' lvalue Var {{.*}} 'i64_4' 'vector' // expected-warning@#i2_3{{implicit conversion loses integer precision: 'vector' (vector of 4 'long' values) to 'vector' (vector of 2 'int' values)}} @@ -71,8 +71,8 @@ void test() { vector b2 = i2_3; // No warning for integer to bool conversion. // CHECK: VarDecl {{.*}} b2_2 'vector' cinit - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' // CHECK-NEXT: DeclRefExpr {{.*}} 'vector' lvalue Var {{.*}} 'd4' 'vector' // expected-warning@#b2_2{{implicit conversion truncates vector: 'vector' (vector of 4 'double' values) to 'vector' (vector of 2 'bool' values)}}