llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-hlsl Author: Chris B (llvm-beanz) <details> <summary>Changes</summary> HLSL supports vector truncation and element conversions as part of standard conversion sequences. The vector truncation conversion is a C++ second conversion in the conversion sequence. If a vector truncation is in a conversion sequence an element conversion may occur after it before the standard C++ third conversion. Vector element conversions can be boolean conversions, floating point or integral conversions or promotions. [HLSL Draft Specification](https://microsoft.github.io/hlsl-specs/specs/hlsl.pdf) --- Patch is 41.58 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71098.diff 19 Files Affected: - (modified) clang/include/clang/AST/OperationKinds.def (+3) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3) - (modified) clang/include/clang/Sema/Overload.h (+11-1) - (modified) clang/lib/AST/Expr.cpp (+1) - (modified) clang/lib/AST/ExprConstant.cpp (+2) - (modified) clang/lib/CodeGen/CGExpr.cpp (+2) - (modified) clang/lib/CodeGen/CGExprAgg.cpp (+2) - (modified) clang/lib/CodeGen/CGExprComplex.cpp (+1) - (modified) clang/lib/CodeGen/CGExprConstant.cpp (+1) - (modified) clang/lib/CodeGen/CGExprScalar.cpp (+20-3) - (modified) clang/lib/Edit/RewriteObjCFoundationAPI.cpp (+4) - (modified) clang/lib/Sema/SemaChecking.cpp (+9-2) - (modified) clang/lib/Sema/SemaExprCXX.cpp (+83) - (modified) clang/lib/Sema/SemaInit.cpp (+1-1) - (modified) clang/lib/Sema/SemaOverload.cpp (+110-34) - (modified) clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp (+2-1) - (added) clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl (+119) - (modified) clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl (+1-1) - (added) clang/test/SemaHLSL/standard_conversion_sequences.hlsl (+92) ``````````diff diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def index 8dd98730dff7426..e497fe4d1f93ff4 100644 --- a/clang/include/clang/AST/OperationKinds.def +++ b/clang/include/clang/AST/OperationKinds.def @@ -361,6 +361,9 @@ CAST_OPERATION(AddressSpaceConversion) // Convert an integer initializer to an OpenCL sampler. CAST_OPERATION(IntToOCLSampler) +// Truncate a vector type (HLSL only). +CAST_OPERATION(VectorTruncation) + //===- Binary Operations -------------------------------------------------===// // Operators listed in order of precedence. // Note that additions to this should also update the StmtVisitor class, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 224c0df7f1fb71f..01ba3a24e0018ba 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12005,6 +12005,9 @@ def err_hlsl_pointers_unsupported : Error< def err_hlsl_operator_unsupported : Error< "the '%select{&|*|->}0' operator is unsupported in HLSL">; +def warn_hlsl_impcast_vector_truncation : Warning< + "implicit conversion truncates vector: %0 to %1">, InGroup<Conversion>; + // Layout randomization diagnostics. def err_non_designated_init_used : Error< "a randomized struct can only be initialized with a designated initializer">; diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index a97968dc7b20967..0d4aaa5ff7c766b 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -192,6 +192,9 @@ class Sema; /// C-only conversion between pointers with incompatible types ICK_Incompatible_Pointer_Conversion, + /// HLSL vector truncation. + ICK_HLSL_Vector_Truncation, + /// The number of conversion kinds ICK_Num_Conversion_Kinds, }; @@ -271,6 +274,12 @@ class Sema; /// pointer-to-member conversion, or boolean conversion. ImplicitConversionKind Second : 8; + /// Element - Between the second and third conversion a vector or matrix + /// element conversion may occur. If this is not ICK_Identity this + /// conversion is applied element-wise to each element in the vector or + /// matrix. + ImplicitConversionKind Element : 8; + /// Third - The third conversion can be a qualification conversion /// or a function conversion. ImplicitConversionKind Third : 8; @@ -357,7 +366,8 @@ class Sema; void setAsIdentityConversion(); bool isIdentityConversion() const { - return Second == ICK_Identity && Third == ICK_Identity; + return Second == ICK_Identity && Element == ICK_Identity && + Third == ICK_Identity; } ImplicitConversionRank getRank() const; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 5d3b510df1ef9b3..d18514949b1eb37 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1882,6 +1882,7 @@ bool CastExpr::CastConsistency() const { case CK_FixedPointToIntegral: case CK_IntegralToFixedPoint: case CK_MatrixCast: + case CK_VectorTruncation: assert(!getType()->isBooleanType() && "unheralded conversion to bool"); goto CheckNoBasePath; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index b6b1e6617dffaa9..f0e44ab0c85a3ea 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -13888,6 +13888,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_FixedPointCast: case CK_IntegralToFixedPoint: case CK_MatrixCast: + case CK_VectorTruncation: llvm_unreachable("invalid cast kind for integral value"); case CK_BitCast: @@ -14726,6 +14727,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_FixedPointToIntegral: case CK_IntegralToFixedPoint: case CK_MatrixCast: + case CK_VectorTruncation: llvm_unreachable("invalid cast kind for complex value"); case CK_LValueToRValue: diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 54a1d300a9ac738..0e0f7f205eae9f6 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -4858,6 +4858,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_FixedPointToIntegral: case CK_IntegralToFixedPoint: case CK_MatrixCast: + case CK_VectorTruncation: return EmitUnsupportedLValue(E, "unexpected cast lvalue"); case CK_Dependent: @@ -4985,6 +4986,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(), CGM.getTBAAInfoForSubobject(LV, E->getType())); } + case CK_ZeroToOCLOpaqueType: llvm_unreachable("NULL to OpenCL opaque type lvalue cast is not valid"); } diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 810b28f25fa18bf..f9278133e5ddc6b 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -930,6 +930,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLOpaqueType: case CK_MatrixCast: + case CK_VectorTruncation: case CK_IntToOCLSampler: case CK_FloatingToFixedPoint: @@ -1454,6 +1455,7 @@ static bool castPreservesZero(const CastExpr *CE) { case CK_MatrixCast: case CK_NonAtomicToAtomic: case CK_AtomicToNonAtomic: + case CK_VectorTruncation: return true; case CK_BaseToDerivedMemberPointer: diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index f3cbd1d0451ebe4..45862701d59bb4a 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -556,6 +556,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op, case CK_FixedPointToIntegral: case CK_IntegralToFixedPoint: case CK_MatrixCast: + case CK_VectorTruncation: llvm_unreachable("invalid cast kind for complex value"); case CK_FloatingRealToComplex: diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index cd91a698a9336f8..b43eb1891481237 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1225,6 +1225,7 @@ class ConstExprEmitter : case CK_IntegralToFixedPoint: case CK_ZeroToOCLOpaqueType: case CK_MatrixCast: + case CK_VectorTruncation: return nullptr; } llvm_unreachable("Invalid CastKind"); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 1a7a3f97bb779a0..61641c1131c39dd 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -610,6 +610,8 @@ class ScalarExprEmitter llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); + llvm::Value *EmitVectorElementConversion(QualType SrcType, QualType DstType, + llvm::Value *Src); Value *VisitUnaryAddrOf(const UnaryOperator *E) { if (isa<MemberPointerType>(E->getType())) // never sugared @@ -1422,6 +1424,9 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, return Builder.CreateVectorSplat(NumElements, Src, "splat"); } + if (SrcType->isExtVectorType() && DstType->isExtVectorType()) + return EmitVectorElementConversion(SrcType, DstType, Src); + if (SrcType->isMatrixType() && DstType->isMatrixType()) return EmitScalarCast(Src, SrcType, DstType, SrcTy, DstTy, Opts); @@ -1701,10 +1706,14 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { } Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) { - QualType SrcType = E->getSrcExpr()->getType(), - DstType = E->getType(); + QualType SrcType = E->getSrcExpr()->getType(), DstType = E->getType(); + Value *Src = CGF.EmitScalarExpr(E->getSrcExpr()); + return EmitVectorElementConversion(SrcType, DstType, Src); +} - Value *Src = CGF.EmitScalarExpr(E->getSrcExpr()); +llvm::Value *ScalarExprEmitter::EmitVectorElementConversion(QualType SrcType, + QualType DstType, + Value *Src) { SrcType = CGF.getContext().getCanonicalType(SrcType); DstType = CGF.getContext().getCanonicalType(DstType); @@ -2475,6 +2484,14 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { case CK_IntToOCLSampler: return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF); + + case CK_VectorTruncation: { + assert(DestTy->isVectorType() && "Expected dest type to be vector type"); + Value *Vec = Visit(const_cast<Expr *>(E)); + SmallVector<int, 16> Mask; + Mask.insert(Mask.begin(), DestTy->getAs<VectorType>()->getNumElements(), 0); + return Builder.CreateShuffleVector(Vec, Mask, "trunc"); + } } // end of switch diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp index 736e450574d9f80..5ff9e3ee39d2a35 100644 --- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1086,6 +1086,10 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, case CK_BooleanToSignedIntegral: llvm_unreachable("OpenCL-specific cast in Objective-C?"); + + case CK_VectorTruncation: + llvm_unreachable("HLSL-specific cast in Objective-C?"); + break; case CK_FloatingToFixedPoint: case CK_FixedPointToFloating: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 1842a783dc29aaa..0729d92d642aa57 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -15416,11 +15416,18 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (S.SourceMgr.isInSystemMacro(CC)) return; return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar); + } else if (S.getLangOpts().HLSL && + Target->getAs<VectorType>()->getNumElements() < + Source->getAs<VectorType>()->getNumElements()) { + // Diagnose vector truncation but don't return. We may also want to + // diagnose an element conversion. + DiagnoseImpCast(S, E, T, CC, diag::warn_hlsl_impcast_vector_truncation); } // If the vector cast is cast between two vectors of the same size, it is - // a bitcast, not a conversion. - if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target)) + // a bitcast, not a conversion, except under HLSL where it is a conversion. + if (!S.getLangOpts().HLSL && + S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target)) return; Source = cast<VectorType>(Source)->getElementType().getTypePtr(); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index ea286c9709c13ff..83dcb615ccc03f1 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4709,6 +4709,19 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, CK_ZeroToOCLOpaqueType, From->getValueKind()).get(); break; + case ICK_HLSL_Vector_Truncation: { + // Note: HLSL vectors are ExtVectors. Since this truncates a vector to a + // smaller vector, this can only operate on arguments where the source and + // destination types are ExtVectors. + auto *FromVec = From->getType()->castAs<ExtVectorType>(); + auto *ToVec = ToType->castAs<ExtVectorType>(); + QualType ElType = FromVec->getElementType(); + QualType TruncTy = Context.getExtVectorType(ElType, ToVec->getNumElements()); + From = ImpCastExprToType(From, TruncTy, CK_VectorTruncation, + From->getValueKind()) + .get(); + break; + } case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: @@ -4721,6 +4734,76 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, llvm_unreachable("Improper second standard conversion"); } + if (SCS.Element != ICK_Identity) { + // if SCS.Element is not ICK_Identity the To and From types must be HLSL + // vectors or matrices. HLSL matrices aren't yet supported so this code only + // handles vectors for now. + + assert(From->getType()->isVectorType() && ToType->isVectorType() && + "Element conversion is only supported for vector types."); + assert(From->getType()->getAs<VectorType>()->getNumElements() == + ToType->getAs<VectorType>()->getNumElements() && + "Element conversion is only supported for vectors with the same " + "element counts."); + QualType FromElTy = From->getType()->getAs<VectorType>()->getElementType(); + unsigned NumElts = ToType->getAs<VectorType>()->getNumElements(); + switch (SCS.Element) { + case ICK_Identity: + // Nothing to do. + break; + case ICK_Boolean_Conversion: + // Perform half-to-boolean conversion via float. + if (FromElTy->isHalfType()) { + QualType FPExtType = Context.getExtVectorType(FromElTy, NumElts); + From = ImpCastExprToType(From, FPExtType, CK_FloatingCast).get(); + FromType = FPExtType; + } + + From = + ImpCastExprToType(From, ToType, + ScalarTypeToBooleanCastKind(FromElTy), VK_PRValue, + /*BasePath=*/nullptr, CCK) + .get(); + break; + case ICK_Integral_Promotion: + case ICK_Integral_Conversion: + if (ToType->isBooleanType()) { + assert(FromType->castAs<EnumType>()->getDecl()->isFixed() && + SCS.Second == ICK_Integral_Promotion && + "only enums with fixed underlying type can promote to bool"); + From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, VK_PRValue, + /*BasePath=*/nullptr, CCK) + .get(); + } else { + From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_PRValue, + /*BasePath=*/nullptr, CCK) + .get(); + } + break; + + case ICK_Floating_Promotion: + case ICK_Floating_Conversion: + From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_PRValue, + /*BasePath=*/nullptr, CCK) + .get(); + break; + case ICK_Floating_Integral: + if (ToType->isRealFloatingType()) + From = + ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_PRValue, + /*BasePath=*/nullptr, CCK) + .get(); + else + From = + ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_PRValue, + /*BasePath=*/nullptr, CCK) + .get(); + break; + default: + llvm_unreachable("Improper element standard conversion"); + } + } + switch (SCS.Third) { case ICK_Identity: // Nothing to do. diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index ed02d3580f34f9a..e7d3348d9983793 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -6427,7 +6427,7 @@ void InitializationSequence::InitializeFrom(Sema &S, // For HLSL ext vector types we allow list initialization behavior for C++ // constructor syntax. This is accomplished by converting initialization // arguments an InitListExpr late. - if (S.getLangOpts().HLSL && DestType->isExtVectorType() && + if (S.getLangOpts().HLSL && Args.size() > 1 && DestType->isExtVectorType() && (SourceType.isNull() || !Context.hasSameUnqualifiedType(SourceType, DestType))) { diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index d3d2dfed2ce0cc2..98ddc49bfe2c912 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -158,7 +158,8 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) { // it was omitted by the patch that added // ICK_Zero_Queue_Conversion ICR_C_Conversion, - ICR_C_Conversion_Extension + ICR_C_Conversion_Extension, + ICR_C_Conversion }; static_assert(std::size(Rank) == (int)ICK_Num_Conversion_Kinds); return Rank[(int)Kind]; @@ -197,7 +198,8 @@ static const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "OpenCL Zero Event Conversion", "OpenCL Zero Queue Conversion", "C specific type conversion", - "Incompatible pointer conversion" + "Incompatible pointer conversion", + "HLSL vector truncation" }; static_assert(std::size(Name) == (int)ICK_Num_Conversion_Kinds); return Name[Kind]; @@ -208,6 +210,7 @@ static const char* GetImplicitConversionName(ImplicitConversionKind Kind) { void StandardConversionSequence::setAsIdentityConversion() { First = ICK_Identity; Second = ICK_Identity; + Element = ICK_Identity; Third = ICK_Identity; DeprecatedStringLiteralToCharPtr = false; QualificationIncludesObjCLifetime = false; @@ -1841,13 +1844,86 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType, return true; } +/// Determine whether the conversion from FromType to ToType is a valid +/// floating point conversion. +/// +static bool IsFloatingPointConversion(Sema &S, QualType FromType, + QualType ToType) { + if (!FromType->isRealFloatingType() || !ToType->isRealFloatingType()) + return false; + // FIXME: disable conversions between long double, __ibm128 and __float128 + // if their representation is different until there is back end support + // We of course allow this conversion if long double is really double. + + // Conversions between bfloat16 and float16 are currently not supported. + if ((FromType->isBFloat16Type() && + (ToType->isFloat16Type() || ToType->isHalfType())) || + (ToType->isBFloat16Type() && + (FromType->isFloat16Type() || FromType->isHalfType()))) + return false; + + // Conversions between IEEE-quad and IBM-extended semantics are not + // permitted. + const llvm::fltSemantics &FromSem = S.Context.getFloatTypeSemantics(FromType); + const llvm::fltSemantics &ToSem = S.Context.getFloatTypeSemantics(ToType); + if ((&FromSem == &llvm::APFloat::PPCDoubleDouble() && + &ToSem == &llvm::APFloat::IEEEquad()) || + (&FromSem == &llvm::APFloat::IEEEquad() && + &ToSem == &llvm::APFloat::PPCDoubleDouble())) + return false; + return true; +} + +static bool IsVectorElementConversion(Sema &S, QualType FromType, + QualType ToType, + ImplicitConversionKind &ICK, Expr *From) { + if (S.Context.hasSameUnqualifiedType(FromType, ToType)) + return true; + + if (IsFloatingPointConversion(S, FromType, ToType)) { + ICK = ICK_Floating_Conversion; + return true; + } + + if (S.IsFloatingPointPromotion(FromType, ToType)) { + ICK = ICK_Floating_Promotion; + return true; + } + + if (ToType->isBooleanType() && FromType->isArithmeticType()) { + ICK = ICK_Boolean_Conversion; + return true; + } + + if (FromType->isIntegralOrUnscopedEnumerationType() && + ToType->isIntegralType(S.Context)) { + ICK = ICK_Integral_Conversion; + return true; + } + + if (S.IsIntegralPromotion(From, FromType, ToType)) { + ICK = ICK_Integral_Promotion; + return true; + } + + if ((FromType->isRealFloatingType() && ToType->isIntegralType(S.Context)) || + (FromType->isIntegralOrUnscopedEnumerationType() && + ToType->isRealFloatingType())) { + ICK = ICK_Floating_Integral; + return true; + } + + return false; +} + /// Determine whether the conversion from FromType to ToType is a valid /// vector conversion. /// /// \param ICK Will be set to the vector conversion kind, if this is a vector /// conversion. static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType, - ImplicitConversionKind &ICK, Expr *From, + ImplicitConversionKind &ICK, + ImplicitConversionKind &ElConv, Expr *From, bool InOverloadResolution, bool CStyle) { // We need at... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/71098 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits