aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorChris B <chris.bieneman@me.com>2024-02-15 14:58:06 -0600
committerGitHub <noreply@github.com>2024-02-15 14:58:06 -0600
commit5c57fd717d5d6a285efeb8402c6fe0c8f70592f3 (patch)
treecd4b71c05decd37f40090f06456570ad485e044e /clang/lib
parentedfc859af89e44207bf499b5d702aa26a7357da4 (diff)
downloadllvm-5c57fd717d5d6a285efeb8402c6fe0c8f70592f3.zip
llvm-5c57fd717d5d6a285efeb8402c6fe0c8f70592f3.tar.gz
llvm-5c57fd717d5d6a285efeb8402c6fe0c8f70592f3.tar.bz2
[HLSL] Vector standard conversions (#71098)
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) --------- Co-authored-by: Aaron Ballman <aaron@aaronballman.com>
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/Expr.cpp1
-rw-r--r--clang/lib/AST/ExprConstant.cpp2
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp2
-rw-r--r--clang/lib/CodeGen/CGExprComplex.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp64
-rw-r--r--clang/lib/Edit/RewriteObjCFoundationAPI.cpp4
-rw-r--r--clang/lib/Sema/SemaChecking.cpp11
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp86
-rw-r--r--clang/lib/Sema/SemaInit.cpp2
-rw-r--r--clang/lib/Sema/SemaOverload.cpp153
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp3
13 files changed, 289 insertions, 42 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 8b10e28..cc04071 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1897,6 +1897,7 @@ bool CastExpr::CastConsistency() const {
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
case CK_MatrixCast:
+ case CK_HLSLVectorTruncation:
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
goto CheckNoBasePath;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 0100101..fcf8f65 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13980,6 +13980,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_FixedPointCast:
case CK_IntegralToFixedPoint:
case CK_MatrixCast:
+ case CK_HLSLVectorTruncation:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -14818,6 +14819,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
case CK_MatrixCast:
+ case CK_HLSLVectorTruncation:
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 4a2f3ca..59a7fe8 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -5180,6 +5180,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
case CK_MatrixCast:
+ case CK_HLSLVectorTruncation:
return EmitUnsupportedLValue(E, "unexpected cast lvalue");
case CK_Dependent:
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 22f55fe..d0d6202 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -933,6 +933,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLOpaqueType:
case CK_MatrixCast:
+ case CK_HLSLVectorTruncation:
case CK_IntToOCLSampler:
case CK_FloatingToFixedPoint:
@@ -1457,6 +1458,7 @@ static bool castPreservesZero(const CastExpr *CE) {
case CK_MatrixCast:
case CK_NonAtomicToAtomic:
case CK_AtomicToNonAtomic:
+ case CK_HLSLVectorTruncation:
return true;
case CK_BaseToDerivedMemberPointer:
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 9ddf0e7..176a7e0 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -564,6 +564,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
case CK_MatrixCast:
+ case CK_HLSLVectorTruncation:
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 a054f38..75286dc 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1225,6 +1225,7 @@ public:
case CK_IntegralToFixedPoint:
case CK_ZeroToOCLOpaqueType:
case CK_MatrixCast:
+ case CK_HLSLVectorTruncation:
return nullptr;
}
llvm_unreachable("Invalid CastKind");
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index aa805f29..13526de 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2408,6 +2408,12 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
CE->getExprLoc());
case CK_IntegralCast: {
+ if (E->getType()->isExtVectorType() && DestTy->isExtVectorType()) {
+ QualType SrcElTy = E->getType()->castAs<VectorType>()->getElementType();
+ return Builder.CreateIntCast(Visit(E), ConvertType(DestTy),
+ SrcElTy->isSignedIntegerOrEnumerationType(),
+ "conv");
+ }
ScalarConversionOpts Opts;
if (auto *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
if (!ICE->isPartOfExplicitCast())
@@ -2416,9 +2422,50 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return EmitScalarConversion(Visit(E), E->getType(), DestTy,
CE->getExprLoc(), Opts);
}
- case CK_IntegralToFloating:
- case CK_FloatingToIntegral:
- case CK_FloatingCast:
+ case CK_IntegralToFloating: {
+ if (E->getType()->isVectorType() && DestTy->isVectorType()) {
+ // TODO: Support constrained FP intrinsics.
+ assert(!Builder.getIsFPConstrained() &&
+ "FP Constrained vector casts not supported yet.");
+ QualType SrcElTy = E->getType()->castAs<VectorType>()->getElementType();
+ if (SrcElTy->isSignedIntegerOrEnumerationType())
+ return Builder.CreateSIToFP(Visit(E), ConvertType(DestTy), "conv");
+ return Builder.CreateUIToFP(Visit(E), ConvertType(DestTy), "conv");
+ }
+ CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, CE);
+ return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+ CE->getExprLoc());
+ }
+ case CK_FloatingToIntegral: {
+ if (E->getType()->isVectorType() && DestTy->isVectorType()) {
+ // TODO: Support constrained FP intrinsics.
+ assert(!Builder.getIsFPConstrained() &&
+ "FP Constrained vector casts not supported yet.");
+ QualType DstElTy = DestTy->castAs<VectorType>()->getElementType();
+ if (DstElTy->isSignedIntegerOrEnumerationType())
+ return Builder.CreateFPToSI(Visit(E), ConvertType(DestTy), "conv");
+ return Builder.CreateFPToUI(Visit(E), ConvertType(DestTy), "conv");
+ }
+ CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, CE);
+ return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+ CE->getExprLoc());
+ }
+ case CK_FloatingCast: {
+ if (E->getType()->isVectorType() && DestTy->isVectorType()) {
+ // TODO: Support constrained FP intrinsics.
+ assert(!Builder.getIsFPConstrained() &&
+ "FP Constrained vector casts not supported yet.");
+ QualType SrcElTy = E->getType()->castAs<VectorType>()->getElementType();
+ QualType DstElTy = DestTy->castAs<VectorType>()->getElementType();
+ if (DstElTy->castAs<BuiltinType>()->getKind() <
+ SrcElTy->castAs<BuiltinType>()->getKind())
+ return Builder.CreateFPTrunc(Visit(E), ConvertType(DestTy), "conv");
+ return Builder.CreateFPExt(Visit(E), ConvertType(DestTy), "conv");
+ }
+ CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, CE);
+ return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+ CE->getExprLoc());
+ }
case CK_FixedPointToFloating:
case CK_FloatingToFixedPoint: {
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, CE);
@@ -2468,6 +2515,17 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_IntToOCLSampler:
return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
+ case CK_HLSLVectorTruncation: {
+ assert(DestTy->isVectorType() && "Expected dest type to be vector type");
+ Value *Vec = Visit(const_cast<Expr *>(E));
+ SmallVector<int, 16> Mask;
+ unsigned NumElts = DestTy->castAs<VectorType>()->getNumElements();
+ for (unsigned I = 0; I != NumElts; ++I)
+ Mask.push_back(I);
+
+ return Builder.CreateShuffleVector(Vec, Mask, "trunc");
+ }
+
} // end of switch
llvm_unreachable("unknown scalar cast");
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 2e123e8..22f2c47e 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1083,6 +1083,10 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_BooleanToSignedIntegral:
llvm_unreachable("OpenCL-specific cast in Objective-C?");
+ case CK_HLSLVectorTruncation:
+ llvm_unreachable("HLSL-specific cast in Objective-C?");
+ break;
+
case CK_FloatingToFixedPoint:
case CK_FixedPointToFloating:
case CK_FixedPointCast:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index afe2673..8e76338 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -15676,11 +15676,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->castAs<VectorType>()->getNumElements() <
+ Source->castAs<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 f2b8913..801ce7b 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4762,6 +4762,22 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
CK_ZeroToOCLOpaqueType,
From->getValueKind()).get();
break;
+ case ICK_HLSL_Vector_Truncation: {
+ // Note: HLSL built-in vectors are ExtVectors. Since this truncates a vector
+ // to a smaller vector, this can only operate on arguments where the source
+ // and destination types are ExtVectors.
+ assert(From->getType()->isExtVectorType() && ToType->isExtVectorType() &&
+ "HLSL vector truncation should only apply to ExtVectors");
+ auto *FromVec = From->getType()->castAs<VectorType>();
+ auto *ToVec = ToType->castAs<VectorType>();
+ QualType ElType = FromVec->getElementType();
+ QualType TruncTy =
+ Context.getExtVectorType(ElType, ToVec->getNumElements());
+ From = ImpCastExprToType(From, TruncTy, CK_HLSLVectorTruncation,
+ From->getValueKind())
+ .get();
+ break;
+ }
case ICK_Lvalue_To_Rvalue:
case ICK_Array_To_Pointer:
@@ -4774,6 +4790,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.
+
+ // TODO: Support HLSL matrices.
+ assert((!From->getType()->isMatrixType() && !ToType->isMatrixType()) &&
+ "Element conversion for matrix types is not implemented yet.");
+ assert(From->getType()->isVectorType() && ToType->isVectorType() &&
+ "Element conversion is only supported for vector types.");
+ assert(From->getType()->getAs<VectorType>()->getNumElements() ==
+ ToType->getAs<VectorType>()->getNumElements() &&
+ "Element conversion is only supported for vectors with the same "
+ "element counts.");
+ QualType FromElTy = From->getType()->getAs<VectorType>()->getElementType();
+ unsigned NumElts = ToType->getAs<VectorType>()->getNumElements();
+ switch (SCS.Element) {
+ case ICK_Boolean_Conversion:
+ // Perform half-to-boolean conversion via float.
+ if (FromElTy->isHalfType()) {
+ QualType FPExtType = Context.getExtVectorType(FromElTy, NumElts);
+ From = ImpCastExprToType(From, FPExtType, CK_FloatingCast).get();
+ FromType = FPExtType;
+ }
+
+ From =
+ ImpCastExprToType(From, ToType, ScalarTypeToBooleanCastKind(FromElTy),
+ VK_PRValue,
+ /*BasePath=*/nullptr, CCK)
+ .get();
+ break;
+ case ICK_Integral_Promotion:
+ case ICK_Integral_Conversion:
+ if (ToType->isBooleanType()) {
+ assert(FromType->castAs<EnumType>()->getDecl()->isFixed() &&
+ SCS.Second == ICK_Integral_Promotion &&
+ "only enums with fixed underlying type can promote to bool");
+ From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, VK_PRValue,
+ /*BasePath=*/nullptr, CCK)
+ .get();
+ } else {
+ From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_PRValue,
+ /*BasePath=*/nullptr, CCK)
+ .get();
+ }
+ break;
+
+ case ICK_Floating_Promotion:
+ case ICK_Floating_Conversion:
+ From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_PRValue,
+ /*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;
+ case ICK_Identity:
+ 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 b6de064..0fd4588 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6432,7 +6432,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 5c6d463..f764542 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -159,6 +159,7 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
ICR_C_Conversion,
ICR_C_Conversion_Extension,
ICR_Conversion,
+ ICR_Conversion,
};
static_assert(std::size(Rank) == (int)ICK_Num_Conversion_Kinds);
return Rank[(int)Kind];
@@ -199,6 +200,7 @@ static const char *GetImplicitConversionName(ImplicitConversionKind Kind) {
"C specific type conversion",
"Incompatible pointer conversion",
"Fixed point conversion",
+ "HLSL vector truncation",
};
static_assert(std::size(Name) == (int)ICK_Num_Conversion_Kinds);
return Name[Kind];
@@ -209,6 +211,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;
@@ -227,11 +230,13 @@ void StandardConversionSequence::setAsIdentityConversion() {
/// implicit conversions.
ImplicitConversionRank StandardConversionSequence::getRank() const {
ImplicitConversionRank Rank = ICR_Exact_Match;
- if (GetConversionRank(First) > Rank)
+ if (GetConversionRank(First) > Rank)
Rank = GetConversionRank(First);
- if (GetConversionRank(Second) > Rank)
+ if (GetConversionRank(Second) > Rank)
Rank = GetConversionRank(Second);
- if (GetConversionRank(Third) > Rank)
+ if (GetConversionRank(Element) > Rank)
+ Rank = GetConversionRank(Element);
+ if (GetConversionRank(Third) > Rank)
Rank = GetConversionRank(Third);
return Rank;
}
@@ -1829,12 +1834,85 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
}
/// 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 (S.IsFloatingPointPromotion(FromType, ToType)) {
+ ICK = ICK_Floating_Promotion;
+ return true;
+ }
+
+ if (IsFloatingPointConversion(S, FromType, ToType)) {
+ ICK = ICK_Floating_Conversion;
+ return true;
+ }
+
+ if (ToType->isBooleanType() && FromType->isArithmeticType()) {
+ ICK = ICK_Boolean_Conversion;
+ return true;
+ }
+
+ if (S.IsIntegralPromotion(From, FromType, ToType)) {
+ ICK = ICK_Integral_Promotion;
+ return true;
+ }
+
+ if (FromType->isIntegralOrUnscopedEnumerationType() &&
+ ToType->isIntegralType(S.Context)) {
+ ICK = ICK_Integral_Conversion;
+ 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 least one of these types to be a vector type to have a vector
// conversion.
@@ -1847,10 +1925,28 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
// There are no conversions between extended vector types, only identity.
if (ToType->isExtVectorType()) {
- // There are no conversions between extended vector types other than the
- // identity conversion.
- if (FromType->isExtVectorType())
+ if (FromType->isExtVectorType()) {
+ // HLSL allows implicit truncation of vector types.
+ if (S.getLangOpts().HLSL) {
+ unsigned FromElts = FromType->getAs<VectorType>()->getNumElements();
+ unsigned ToElts = ToType->getAs<VectorType>()->getNumElements();
+ if (FromElts < ToElts)
+ return false;
+ if (FromElts == ToElts)
+ ICK = ICK_Identity;
+ else
+ ICK = ICK_HLSL_Vector_Truncation;
+
+ QualType FromElTy = FromType->getAs<VectorType>()->getElementType();
+ QualType ToElTy = ToType->getAs<VectorType>()->getElementType();
+ if (S.Context.hasSameUnqualifiedType(FromElTy, ToElTy))
+ return true;
+ return IsVectorElementConversion(S, FromElTy, ToElTy, ElConv, From);
+ }
+ // There are no conversions between extended vector types other than the
+ // identity conversion.
return false;
+ }
// Vector splat from any arithmetic type to a vector.
if (FromType->isArithmeticType()) {
@@ -2056,6 +2152,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// conversion.
bool IncompatibleObjC = false;
ImplicitConversionKind SecondICK = ICK_Identity;
+ ImplicitConversionKind ElementICK = ICK_Identity;
if (S.Context.hasSameUnqualifiedType(FromType, ToType)) {
// The unqualified versions of the types are the same: there's no
// conversion to do.
@@ -2094,29 +2191,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// Complex-real conversions (C99 6.3.1.7)
SCS.Second = ICK_Complex_Real;
FromType = ToType.getUnqualifiedType();
- } else if (FromType->isRealFloatingType() && ToType->isRealFloatingType()) {
- // 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;
-
+ } else if (IsFloatingPointConversion(S, FromType, ToType)) {
// Floating point conversions (C++ 4.8).
SCS.Second = ICK_Floating_Conversion;
FromType = ToType.getUnqualifiedType();
@@ -2143,18 +2218,18 @@ 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, From,
- InOverloadResolution, CStyle)) {
+ } else if (IsVectorConversion(S, FromType, ToType, SecondICK, ElementICK,
+ From, InOverloadResolution, CStyle)) {
SCS.Second = SecondICK;
+ SCS.Element = ElementICK;
FromType = ToType.getUnqualifiedType();
} else if (!S.getLangOpts().CPlusPlus &&
S.Context.typesAreCompatible(ToType, FromType)) {
// Compatible conversions (Clang extension for C function overloading)
SCS.Second = ICK_Compatible_Conversion;
FromType = ToType.getUnqualifiedType();
- } else if (IsTransparentUnionStandardConversion(S, From, ToType,
- InOverloadResolution,
- SCS, CStyle)) {
+ } else if (IsTransparentUnionStandardConversion(
+ S, From, ToType, InOverloadResolution, SCS, CStyle)) {
SCS.Second = ICK_TransparentUnionConversion;
FromType = ToType;
} else if (tryAtomicConversion(S, From, ToType, InOverloadResolution, SCS,
@@ -2449,6 +2524,11 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
return true;
}
+ // In HLSL an rvalue of integral type can be promoted to an rvalue of a larger
+ // integral type.
+ if (Context.getLangOpts().HLSL)
+ return Context.getTypeSize(FromType) < Context.getTypeSize(ToType);
+
return false;
}
@@ -5042,6 +5122,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
: (RefConv & Sema::ReferenceConversions::ObjC)
? ICK_Compatible_Conversion
: ICK_Identity;
+ ICS.Standard.Element = 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.
@@ -5968,6 +6049,7 @@ static bool CheckConvertedConstantConversions(Sema &S,
case ICK_C_Only_Conversion:
case ICK_Incompatible_Pointer_Conversion:
case ICK_Fixed_Point_Conversion:
+ case ICK_HLSL_Vector_Truncation:
return false;
case ICK_Lvalue_To_Rvalue:
@@ -6245,6 +6327,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.Third = ICK_Identity;
SCS.ToTypePtrs[2] = SCS.ToTypePtrs[1] = SCS.ToTypePtrs[0];
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 7e431f7..c3fc56a 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -520,7 +520,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
// Various C++ casts that are not handled yet.
case CK_ToUnion:
case CK_MatrixCast:
- case CK_VectorSplat: {
+ case CK_VectorSplat:
+ case CK_HLSLVectorTruncation: {
QualType resultType = CastE->getType();
if (CastE->isGLValue())
resultType = getContext().getPointerType(resultType);