From 5a6dc614527332254b2b230ff2ff7527ca6d0785 Mon Sep 17 00:00:00 2001 From: Chris B Date: Thu, 26 Sep 2024 19:34:39 -0500 Subject: [PATCH] Revert "[HLSL] Vector Usual Arithmetic Conversions" (#110191) Reverts llvm/llvm-project#108659 Reverting due to bot breakage. --- .../clang/Basic/DiagnosticSemaKinds.td | 3 - clang/include/clang/Driver/Options.td | 2 +- clang/include/clang/Sema/Sema.h | 3 +- clang/include/clang/Sema/SemaHLSL.h | 5 - clang/lib/Sema/SemaExpr.cpp | 18 +- clang/lib/Sema/SemaHLSL.cpp | 188 --------- .../Language/UsualArithmeticConversions.hlsl | 379 ------------------ 7 files changed, 4 insertions(+), 594 deletions(-) delete mode 100644 clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9e8f152852fd1e..f3d5d4c56606cc 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12395,9 +12395,6 @@ def err_hlsl_operator_unsupported : Error< def err_hlsl_param_qualifier_mismatch : Error<"conflicting parameter qualifier %0 on parameter %1">; -def err_hlsl_vector_compound_assignment_truncation : Error< - "left hand operand of type %0 to compound assignment cannot be truncated " - "when used with right hand operand of type %1">; def warn_hlsl_impcast_vector_truncation : Warning< "implicit conversion truncates vector: %0 to %1">, InGroup; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 1dc2ff18170abf..932cf13edab53d 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2978,7 +2978,7 @@ def flax_vector_conversions_EQ : Joined<["-"], "flax-vector-conversions=">, Grou "LangOptions::LaxVectorConversionKind::Integer", "LangOptions::LaxVectorConversionKind::All"]>, MarshallingInfoEnum, - !strconcat("(", open_cl.KeyPath, " || ", hlsl.KeyPath, ")") # + open_cl.KeyPath # " ? LangOptions::LaxVectorConversionKind::None" # " : LangOptions::LaxVectorConversionKind::All">; def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a9ce3681338d46..e1c3a99cfa167e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7423,8 +7423,7 @@ class Sema final : public SemaBase { SourceLocation Loc, BinaryOperatorKind Opc); QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, - SourceLocation Loc, - BinaryOperatorKind Opc); + SourceLocation Loc); /// Context in which we're performing a usual arithmetic conversion. enum ArithConvKind { diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index fa957abc9791af..311cd58bbcac2c 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -63,11 +63,6 @@ class SemaHLSL : public SemaBase { std::initializer_list AllowedStages); void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU); - QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, - QualType LHSType, QualType RHSType, - bool IsCompAssign); - void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc); - void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e072fb65b81328..66df9c969256a2 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10133,10 +10133,6 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, const VectorType *RHSVecType = RHSType->getAs(); assert(LHSVecType || RHSVecType); - if (getLangOpts().HLSL) - return HLSL().handleVectorBinOpConversion(LHS, RHS, LHSType, RHSType, - IsCompAssign); - // AltiVec-style "vector bool op vector bool" combinations are allowed // for some operators but not others. if (!AllowBothBool && LHSVecType && @@ -12867,8 +12863,7 @@ static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS, } QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, - SourceLocation Loc, - BinaryOperatorKind Opc) { + SourceLocation Loc) { // Ensure that either both operands are of the same vector type, or // one operand is of a vector type and the other is of its element type. QualType vType = CheckVectorOperands(LHS, RHS, Loc, false, @@ -12888,15 +12883,6 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, if (!getLangOpts().CPlusPlus && !(isa(vType->getAs()))) return InvalidLogicalVectorOperands(Loc, LHS, RHS); - // Beginning with HLSL 2021, HLSL disallows logical operators on vector - // operands and instead requires the use of the `and`, `or`, `any`, `all`, and - // `select` functions. - if (getLangOpts().HLSL && - getLangOpts().getHLSLVersion() >= LangOptionsBase::HLSL_2021) { - (void)InvalidOperands(Loc, LHS, RHS); - HLSL().emitLogicalOperatorFixIt(LHS.get(), RHS.get(), Opc); - return QualType(); - } return GetSignedVectorType(LHS.get()->getType()); } @@ -13068,7 +13054,7 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, // Check vector operands differently. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) - return CheckVectorLogicalOperands(LHS, RHS, Loc, Opc); + return CheckVectorLogicalOperands(LHS, RHS, Loc); bool EnumConstantInBoolContext = false; for (const ExprResult &HS : {LHS, RHS}) { diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index f17b606a8f262a..1d8ccdda45573f 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -401,194 +401,6 @@ void SemaHLSL::DiagnoseAttrStageMismatch( << (AllowedStages.size() != 1) << join(StageStrings, ", "); } -template -static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) { - if (const auto *VTy = Ty->getAs()) - Ty = VTy->getElementType(); - Ty = S.getASTContext().getExtVectorType(Ty, Sz); - E = S.ImpCastExprToType(E.get(), Ty, Kind); -} - -template -static QualType castElement(Sema &S, ExprResult &E, QualType Ty) { - E = S.ImpCastExprToType(E.get(), Ty, Kind); - return Ty; -} - -static QualType handleFloatVectorBinOpConversion( - Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, - QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) { - bool LHSFloat = LElTy->isRealFloatingType(); - bool RHSFloat = RElTy->isRealFloatingType(); - - if (LHSFloat && RHSFloat) { - if (IsCompAssign || - SemaRef.getASTContext().getFloatingTypeOrder(LElTy, RElTy) > 0) - return castElement(SemaRef, RHS, LHSType); - - return castElement(SemaRef, LHS, RHSType); - } - - if (LHSFloat) - return castElement(SemaRef, RHS, LHSType); - - assert(RHSFloat); - if (IsCompAssign) - return castElement(SemaRef, RHS, LHSType); - - return castElement(SemaRef, LHS, RHSType); -} - -static QualType handleIntegerVectorBinOpConversion( - Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, - QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) { - - int IntOrder = SemaRef.Context.getIntegerTypeOrder(LElTy, RElTy); - bool LHSSigned = LElTy->hasSignedIntegerRepresentation(); - bool RHSSigned = RElTy->hasSignedIntegerRepresentation(); - auto &Ctx = SemaRef.getASTContext(); - - // If both types have the same signedness, use the higher ranked type. - if (LHSSigned == RHSSigned) { - if (IsCompAssign || IntOrder >= 0) - return castElement(SemaRef, RHS, LHSType); - - return castElement(SemaRef, LHS, RHSType); - } - - // If the unsigned type has greater than or equal rank of the signed type, use - // the unsigned type. - if (IntOrder != (LHSSigned ? 1 : -1)) { - if (IsCompAssign || RHSSigned) - return castElement(SemaRef, RHS, LHSType); - return castElement(SemaRef, LHS, RHSType); - } - - // At this point the signed type has higher rank than the unsigned type, which - // means it will be the same size or bigger. If the signed type is bigger, it - // can represent all the values of the unsigned type, so select it. - if (Ctx.getIntWidth(LElTy) != Ctx.getIntWidth(RElTy)) { - if (IsCompAssign || LHSSigned) - return castElement(SemaRef, RHS, LHSType); - return castElement(SemaRef, LHS, RHSType); - } - - // This is a bit of an odd duck case in HLSL. It shouldn't happen, but can due - // to C/C++ leaking through. The place this happens today is long vs long - // long. When arguments are vector and vector, - // the long long has higher rank than long even though they are the same size. - - // If this is a compound assignment cast the right hand side to the left hand - // side's type. - if (IsCompAssign) - return castElement(SemaRef, RHS, LHSType); - - // If this isn't a compound assignment we convert to unsigned long long. - QualType ElTy = Ctx.getCorrespondingUnsignedType(LHSSigned ? LElTy : RElTy); - QualType NewTy = Ctx.getExtVectorType( - ElTy, RHSType->castAs()->getNumElements()); - (void)castElement(SemaRef, RHS, NewTy); - - return castElement(SemaRef, LHS, NewTy); -} - -static CastKind getScalarCastKind(ASTContext &Ctx, QualType DestTy, - QualType SrcTy) { - if (DestTy->isRealFloatingType() && SrcTy->isRealFloatingType()) - return CK_FloatingCast; - if (DestTy->isIntegralType(Ctx) && SrcTy->isIntegralType(Ctx)) - return CK_IntegralCast; - if (DestTy->isRealFloatingType()) - return CK_IntegralToFloating; - assert(SrcTy->isRealFloatingType() && DestTy->isIntegralType(Ctx)); - return CK_FloatingToIntegral; -} - -QualType SemaHLSL::handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, - QualType LHSType, - QualType RHSType, - bool IsCompAssign) { - const auto *LVecTy = LHSType->getAs(); - const auto *RVecTy = RHSType->getAs(); - auto &Ctx = getASTContext(); - - // If the LHS is not a vector and this is a compound assignment, we truncate - // the argument to a scalar then convert it to the LHS's type. - if (!LVecTy && IsCompAssign) { - QualType RElTy = RHSType->castAs()->getElementType(); - RHS = SemaRef.ImpCastExprToType(RHS.get(), RElTy, CK_HLSLVectorTruncation); - RHSType = RHS.get()->getType(); - if (Ctx.hasSameUnqualifiedType(LHSType, RHSType)) - return LHSType; - RHS = SemaRef.ImpCastExprToType(RHS.get(), LHSType, - getScalarCastKind(Ctx, LHSType, RHSType)); - return LHSType; - } - - unsigned EndSz = std::numeric_limits::max(); - unsigned LSz = 0; - if (LVecTy) - LSz = EndSz = LVecTy->getNumElements(); - if (RVecTy) - EndSz = std::min(RVecTy->getNumElements(), EndSz); - assert(EndSz != std::numeric_limits::max() && - "one of the above should have had a value"); - - // In a compound assignment, the left operand does not change type, the right - // operand is converted to the type of the left operand. - if (IsCompAssign && LSz != EndSz) { - Diag(LHS.get()->getBeginLoc(), - diag::err_hlsl_vector_compound_assignment_truncation) - << LHSType << RHSType; - return QualType(); - } - - if (RVecTy && RVecTy->getNumElements() > EndSz) - castVector(SemaRef, RHS, RHSType, EndSz); - if (!IsCompAssign && LVecTy && LVecTy->getNumElements() > EndSz) - castVector(SemaRef, LHS, LHSType, EndSz); - - if (!RVecTy) - castVector(SemaRef, RHS, RHSType, EndSz); - if (!IsCompAssign && !LVecTy) - castVector(SemaRef, LHS, LHSType, EndSz); - - // If we're at the same type after resizing we can stop here. - if (Ctx.hasSameUnqualifiedType(LHSType, RHSType)) - return Ctx.getCommonSugaredType(LHSType, RHSType); - - QualType LElTy = LHSType->castAs()->getElementType(); - QualType RElTy = RHSType->castAs()->getElementType(); - - // Handle conversion for floating point vectors. - if (LElTy->isRealFloatingType() || RElTy->isRealFloatingType()) - return handleFloatVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType, - LElTy, RElTy, IsCompAssign); - - assert(LElTy->isIntegralType(Ctx) && RElTy->isIntegralType(Ctx) && - "HLSL Vectors can only contain integer or floating point types"); - return handleIntegerVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType, - LElTy, RElTy, IsCompAssign); -} - -void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, - BinaryOperatorKind Opc) { - assert((Opc == BO_LOr || Opc == BO_LAnd) && - "Called with non-logical operator"); - llvm::SmallVector Buff; - llvm::raw_svector_ostream OS(Buff); - PrintingPolicy PP(SemaRef.getLangOpts()); - StringRef NewFnName = Opc == BO_LOr ? "or" : "and"; - OS << NewFnName << "("; - LHS->printPretty(OS, nullptr, PP); - OS << ", "; - RHS->printPretty(OS, nullptr, PP); - OS << ")"; - SourceRange FullRange = SourceRange(LHS->getBeginLoc(), RHS->getEndLoc()); - SemaRef.Diag(LHS->getBeginLoc(), diag::note_function_suggestion) - << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str()); -} - void SemaHLSL::handleNumThreadsAttr(Decl *D, const ParsedAttr &AL) { llvm::VersionTuple SMVersion = getASTContext().getTargetInfo().getTriple().getOSVersion(); diff --git a/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl b/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl deleted file mode 100644 index 6138169e299fd7..00000000000000 --- a/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl +++ /dev/null @@ -1,379 +0,0 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -fnative-half-type %s -DERRORS -Wconversion -Wdouble-promotion -verify -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -std=hlsl2018 -finclude-default-header -fnative-half-type %s -DERRORS -Wconversion -Wdouble-promotion -verify -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -fnative-half-type %s -ast-dump | FileCheck %s - -//----------------------------------------------------------------------------// -// Case 1: float4 * int4 and inverse. -// -// In both cases here the int is converted to a float and the computation -// produces a float value. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f4f4i4 'float4 (float4, int4)' -// CHECK: BinaryOperator {{.*}} 'float4':'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export float4 f4f4i4(float4 A, int4 B) { - return A * B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} -} - -// CHECK-LABEL: FunctionDecl {{.*}} used f4i4f4 'float4 (float4, int4)' -// CHECK: BinaryOperator {{.*}} 'float4':'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -export float4 f4i4f4(float4 A, int4 B) { - return B * A; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} -} - -//----------------------------------------------------------------------------// -// Case 2: float4 * int2 and inverse. -// -// In both cases the float vector is trunctated to a float2 and the integer -// vector is converted to a float2. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f2f4i2 'float2 (float4, int2)' -// CHECK: BinaryOperator {{.*}} 'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}}'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector' lvalue ParmVar {{.*}} 'B' 'int2':'vector' -export float2 f2f4i2(float4 A, int2 B) { - // expected-warning@#f2f4i2 {{implicit conversion from 'int2' (aka 'vector') to 'vector' (vector of 2 'float' values) may lose precision}} - // expected-warning@#f2f4i2 {{implicit conversion truncates vector: 'float4' (aka 'vector') to 'vector' (vector of 2 'float' values)}} - return A * B; // #f2f4i2 -} - -// CHECK-LABEL: FunctionDecl {{.*}} used f2i2f4 'float2 (float4, int2)' -// CHECK: BinaryOperator {{.*}} 'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector' lvalue ParmVar {{.*}} 'B' 'int2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}}'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -export float2 f2i2f4(float4 A, int2 B) { - // expected-warning@#f2i2f4 {{implicit conversion from 'int2' (aka 'vector') to 'vector' (vector of 2 'float' values) may lose precision}} - // expected-warning@#f2i2f4 {{implicit conversion truncates vector: 'float4' (aka 'vector') to 'vector' (vector of 2 'float' values)}} - return B * A; // #f2i2f4 -} - -//----------------------------------------------------------------------------// -// Case 3: Integers of mismatched sign, equivalent size, but the unsigned type -// has lower conversion rank. -// -// This is the odd-ball case for HLSL that isn't really in spec, but we should -// handle gracefully. The lower-ranked unsigned type is converted to the -// equivalent unsigned type of higher rank, and the signed type is also -// converted to that unsigned type (meaning `unsigned long` becomes `unsinged -// long long`, and `long long` becomes `unsigned long long`). -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used wierdo 'int4 (vector, vector)' -// CHECK: BinaryOperator {{.*}} 'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: DeclRefExpr{{.*}} 'vector' lvalue ParmVar {{.*}} 'A' 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr{{.*}}> 'vector' -// CHECK-NEXT: DeclRefExpr {{.*}}'vector' lvalue ParmVar {{.*}} 'B' 'vector' -export int4 wierdo(vector A, vector B) { - // expected-warning@#wierdo {{implicit conversion loses integer precision: 'vector' (vector of 4 'unsigned long long' values) to 'vector' (vector of 4 'int' values)}} - // expected-warning@#wierdo {{implicit conversion changes signedness: 'vector' (vector of 4 'long long' values) to 'vector' (vector of 4 'unsigned long long' values)}} - return A * B; // #wierdo -} - -//----------------------------------------------------------------------------// -// Case 4: Compound assignment of float4 with an int4. -// -// In compound assignment the RHS is converted to match the LHS. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f4f4i4compound 'float4 (float4, int4)' -// CHECK: CompoundAssignOperator {{.*}} 'float4':'vector' lvalue '+=' ComputeLHSTy='float4':'vector' ComputeResultTy='float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export float4 f4f4i4compound(float4 A, int4 B) { - A += B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} - return A; -} - - -//----------------------------------------------------------------------------// -// Case 5: Compound assignment of float2 with an int4. -// -// In compound assignment the RHS is converted to match the LHS. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f4f2i4compound 'float4 (float2, int4)' -// CHECK: CompoundAssignOperator {{.*}} 'float2':'vector' lvalue '+=' ComputeLHSTy='float2':'vector' ComputeResultTy='float2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'A' 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export float4 f4f2i4compound(float2 A, int4 B) { - // expected-warning@#f4f2i4compound{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} - // expected-warning@#f4f2i4compound{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} - A += B; // #f4f2i4compound - return A.xyxy; -} - -//----------------------------------------------------------------------------// -// Case 6: float2 * int4 -// -// The int4 vector is trunctated to int2 then converted to float2. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f4f2i4 'float2 (float2, int4)' -// CHECK: BinaryOperator {{.*}} 'float2':'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'A' 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export float2 f4f2i4(float2 A, int4 B) { - // expected-warning@#f4f2i4{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} - // expected-warning@#f4f2i4{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} - return A * B; // #f4f2i4 -} - -//----------------------------------------------------------------------------// -// Case 7: Compound assignment of half4 with float4, and inverse. -// -// In compound assignment the RHS is converted to match the LHS. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f4h4f4compound 'float4 (half4, float4)' -// CHECK: CompoundAssignOperator {{.*}} 'half4':'vector' lvalue '+=' ComputeLHSTy='half4':'vector' ComputeResultTy='half4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'half4':'vector' lvalue ParmVar {{.*}} 'A' 'half4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'B' 'float4':'vector' -export float4 f4h4f4compound(half4 A, float4 B) { - A += B; // expected-warning{{implicit conversion loses floating-point precision: 'float4' (aka 'vector') to 'half4' (aka 'vector')}} - return B; -} - -// CHECK-LABEL: FunctionDecl {{.*}} used f4f4h4compound 'float4 (float4, half4)' -// CHECK: CompoundAssignOperator {{.*}} 'float4':'vector' lvalue '+=' ComputeLHSTy='float4':'vector' ComputeResultTy='float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'half4':'vector' lvalue ParmVar {{.*}} 'B' 'half4':'vector' -export float4 f4f4h4compound(float4 A, half4 B) { - A += B; // expected-warning{{implicit conversion increases floating-point precision: 'half4' (aka 'vector') to 'float4' (aka 'vector')}} - return A; -} - -//----------------------------------------------------------------------------// -// Case 8: int64_t4 * uint4 -// -// The unsigned argument is promoted to the higher ranked signed type since it -// can express all values of the unsgined argument. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used l4l4i4 'int64_t4 (int64_t4, uint4)' -// CHECK: BinaryOperator {{.*}} 'int64_t4':'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int64_t4':'vector' lvalue ParmVar {{.*}} 'A' 'int64_t4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'uint4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'uint4':'vector' lvalue ParmVar {{.*}} 'B' 'uint4':'vector' -export int64_t4 l4l4i4(int64_t4 A, uint4 B) { - return A * B; -} - -//----------------------------------------------------------------------------// -// Case 9: Compound assignment of int4 from int64_t4 -// -// In compound assignment the RHS is converted to match the LHS. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used i4i4l4compound 'int4 (int4, int64_t4)' -// CHECK: CompoundAssignOperator {{.*}} 'int4':'vector' lvalue '+=' ComputeLHSTy='int4':'vector' ComputeResultTy='int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'A' 'int4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int64_t4':'vector' lvalue ParmVar {{.*}} 'B' 'int64_t4':'vector' -export int4 i4i4l4compound(int4 A, int64_t4 B) { - A += B; // expected-warning{{implicit conversion loses integer precision: 'int64_t4' (aka 'vector') to 'int4' (aka 'vector')}} - return A; -} - -//----------------------------------------------------------------------------// -// Case 10: Compound assignment of vector with argument of -// vector -// -// In compound assignment the RHS is converted to match the LHS. This one is -// also the weird case because it is out of spec, but we should handle it -// gracefully. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used wierdocompound 'vector (vector, vector)' -// CHECK: CompoundAssignOperator {{.*}} 'vector' lvalue '+=' ComputeLHSTy='vector' ComputeResultTy='vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'vector' lvalue ParmVar {{.*}} 'A' 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'vector' lvalue ParmVar {{.*}} 'B' 'vector' -export vector wierdocompound(vector A, vector B) { - // expected-warning@#wierdocompound{{implicit conversion changes signedness: 'vector' (vector of 4 'long long' values) to 'vector' (vector of 4 'unsigned long' values)}} - A += B; // #wierdocompound - return A; -} - -//----------------------------------------------------------------------------// -// Case 11: Compound assignment of scalar with vector argument. -// -// Because the LHS of a compound assignment cannot change type, the RHS must be -// implicitly convertable to the LHS type. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used ffi2compound 'float (float, int2)' -// CHECK: CompoundAssignOperator {{.*}} 'float' lvalue '+=' ComputeLHSTy='float' ComputeResultTy='float' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'A' 'float' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector' lvalue ParmVar {{.*}} 'B' 'int2':'vector' -export float ffi2compound(float A, int2 B) { - A += B; // expected-warning {{implicit conversion turns vector to scalar: 'int2' (aka 'vector') to 'float'}} - return A; -} - -// CHECK-LABEL: FunctionDecl {{.*}} used iif2compound 'int (int, float2)' -// CHECK: CompoundAssignOperator {{.*}} 'int' lvalue '+=' ComputeLHSTy='int' ComputeResultTy='int' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'A' 'int' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' -// CHECK-NEXT: mplicitCastExpr {{.*}} 'float' -// CHECK-NEXT: ImplicitCastExpr{{.*}} 'float2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'B' 'float2':'vector' -export int iif2compound(int A, float2 B) { - A += B; // expected-warning{{implicit conversion turns vector to scalar: 'float2' (aka 'vector') to 'int'}} - return A; -} - - -//----------------------------------------------------------------------------// -// Case 12: Compound assignment of vector of larger size than the argument. -// -// Because the LHS of a compound assignment cannot change type, the RHS must be -// implicitly convertable to the LHS type. This fails since the RHS type can't -// be vector-extended implicitly. -//----------------------------------------------------------------------------// - -#ifdef ERRORS -// The only cases that are really illegal here are when the RHS is a vector that -// is larger than the LHS or when the LHS is a scalar. - -export float2 f2f4i2compound(float4 A, int2 B) { - A += B; // expected-error{{left hand operand of type 'float4' (aka 'vector') to compound assignment cannot be truncated when used with right hand operand of type 'int2' (aka 'vector')}} - return A.xy; -} - -#endif - -//----------------------------------------------------------------------------// -// Case 13: Comparison operators for mismatched arguments follow the same rules. -// -// Compare operators convert each argument following the usual arithmetic -// conversions. -//----------------------------------------------------------------------------// - -// Note: these cases work and generate correct code, but the way they get there -// may change with https://github.com/llvm/llvm-project/issues/91639, because -// representing boolean vectors as 32-bit integer vectors will allow more -// efficient code generation. - -// CHECK-LABEL: FunctionDecl {{.*}} used b4f4i4Compare 'bool4 (float4, int4)' -// CHECK: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: BinaryOperator {{.*}} 'vector' '<' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export bool4 b4f4i4Compare(float4 A, int4 B) { - return A < B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} -} - - -// CHECK-LABEL: FunctionDecl {{.*}} used b2f2i4Compare 'bool2 (float2, int4)' -// CHECK: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: BinaryOperator {{.*}} 'vector' '<=' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'A' 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' - -export bool2 b2f2i4Compare(float2 A, int4 B) { - // expected-warning@#b2f2i4Compare{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} - // expected-warning@#b2f2i4Compare{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} - return A <= B; // #b2f2i4Compare -} - -// CHECK-LABEL: FunctionDecl {{.*}} used b4fi4Compare 'bool4 (float, int4)' -// CHECK: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: BinaryOperator {{.*}} 'vector' '>' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'A' 'float' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export bool4 b4fi4Compare(float A, int4 B) { - return A > B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'vector' (vector of 4 'float' values) may lose precision}} -} - -//----------------------------------------------------------------------------// -// Case 14: Logical operators on vectors are disallowed in HLSL 2021+ -//----------------------------------------------------------------------------// - -#ifdef ERRORS - -#if __HLSL_VERSION >= 2021 -// expected-error@#b4f4i4Logical{{invalid operands to binary expression ('float4' (aka 'vector') and 'int4' (aka 'vector'))}} -// expected-note@#b4f4i4Logical{{did you mean or?}} -#else -// expected-warning@#b4f4i4Logical{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} -#endif - -export bool4 b4f4i4Logical(float4 A, int4 B) { - return A || B; // #b4f4i4Logical -} - -#if __HLSL_VERSION >= 2021 -// expected-error@#b2f2i4Logical{{invalid operands to binary expression ('float2' (aka 'vector') and 'int4' (aka 'vector'))}} -// expected-note@#b2f2i4Logical{{did you mean and?}} -#else -// expected-warning@#b2f2i4Logical{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} -// expected-warning@#b2f2i4Logical{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} -#endif - -export bool2 b2f2i4Logical(float2 A, int4 B) { - return A && B; // #b2f2i4Logical -} - -#if __HLSL_VERSION >= 2021 -// expected-error@#b2b2b2Logical{{invalid operands to binary expression ('bool2' (aka 'vector') and 'bool2')}} -// expected-note@#b2b2b2Logical{{did you mean and?}} -#endif - -export bool2 b2b2b2Logical(bool2 A, bool2 B) { - return A && B; // #b2b2b2Logical -} - -#endif