Skip to content

[HLSL] Rework implicit conversion sequences #96011

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions clang/docs/HLSL/ExpectedDifferences.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -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::
Expand Down
38 changes: 31 additions & 7 deletions clang/include/clang/Sema/Overload.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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,

Expand All @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}

Expand Down
160 changes: 76 additions & 84 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you renamed this function after writing the doc comment.

In any case, we generally don't repeat the function name in the doc comment any more, and these should be /// comments for them to show up on the doxygen page

QualType ToType, QualType *ElTy = nullptr) {
auto *ToVec = ToType->castAs<VectorType>();
QualType ElType = ToVec->getElementType();
if (ElTy)
*ElTy = ElType;
if (!FromTy->isVectorType())
return ElType;
auto *FromVec = FromTy->castAs<VectorType>();
return Context.getExtVectorType(ElType, FromVec->getNumElements());
}

ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
const StandardConversionSequence& SCS,
Expand Down Expand Up @@ -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<EnumType>()->getDecl()->isFixed() &&
SCS.Second == ICK_Integral_Promotion &&
"only enums with fixed underlying type can promote to bool");
From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, VK_PRValue,
From = ImpCastExprToType(From, StepTy, CK_IntegralToBoolean, VK_PRValue,
/*BasePath=*/nullptr, CCK)
.get();
} else {
From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_PRValue,
From = ImpCastExprToType(From, StepTy, CK_IntegralCast, VK_PRValue,
/*BasePath=*/nullptr, CCK)
.get();
}
break;
}

case ICK_Floating_Promotion:
case ICK_Floating_Conversion:
From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_PRValue,
case ICK_Floating_Conversion: {
QualType StepTy = ToType;
if (ToType->isVectorType())
StepTy = adjustVectorType(Context, FromType, ToType);
From = ImpCastExprToType(From, StepTy, CK_FloatingCast, VK_PRValue,
/*BasePath=*/nullptr, CCK)
.get();
break;
}

case ICK_Complex_Promotion:
case ICK_Complex_Conversion: {
Expand All @@ -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()) &&
Expand Down Expand Up @@ -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<VectorType>()->getElementType();
}

From = ImpCastExprToType(From, Context.BoolTy,
ScalarTypeToBooleanCastKind(FromType), VK_PRValue,
From = ImpCastExprToType(From, StepTy, ScalarTypeToBooleanCastKind(ElTy),
VK_PRValue,
/*BasePath=*/nullptr, CCK)
.get();
break;
}

case ICK_Derived_To_Base: {
CXXCastPath BasePath;
Expand Down Expand Up @@ -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<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:
Expand All @@ -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<VectorType>()->getNumElements() ==
ToType->getAs<VectorType>()->getNumElements() &&
"Element conversion is only supported for vectors with the same "
"element counts.");
QualType FromElTy = From->getType()->getAs<VectorType>()->getElementType();
unsigned NumElts = ToType->getAs<VectorType>()->getNumElements();
switch (SCS.Element) {
case ICK_Boolean_Conversion:
// Perform half-to-boolean conversion via float.
if (FromElTy->isHalfType()) {
QualType FPExtType = Context.getExtVectorType(FromElTy, NumElts);
From = ImpCastExprToType(From, FPExtType, CK_FloatingCast).get();
FromType = FPExtType;
}

From =
ImpCastExprToType(From, ToType, ScalarTypeToBooleanCastKind(FromElTy),
VK_PRValue,
/*BasePath=*/nullptr, CCK)
.get();
break;
case ICK_Integral_Promotion:
case ICK_Integral_Conversion:
if (ToType->isBooleanType()) {
assert(FromType->castAs<EnumType>()->getDecl()->isFixed() &&
SCS.Second == ICK_Integral_Promotion &&
"only enums with fixed underlying type can promote to bool");
From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, VK_PRValue,
/*BasePath=*/nullptr, CCK)
.get();
} else {
From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_PRValue,
/*BasePath=*/nullptr, CCK)
.get();
}
break;

case ICK_Floating_Promotion:
case ICK_Floating_Conversion:
From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_PRValue,
"Dimension conversion for matrix types is not implemented yet.");
assert(ToType->isVectorType() &&
"Dimension conversion is only supported for vector types.");
switch (SCS.Dimension) {
case ICK_HLSL_Vector_Splat: {
// Vector splat from any arithmetic type to a vector.
Expr *Elem = prepareVectorSplat(ToType, From).get();
From = ImpCastExprToType(Elem, ToType, CK_VectorSplat, VK_PRValue,
/*BasePath=*/nullptr, CCK)
.get();
break;
case ICK_Floating_Integral:
if (ToType->hasFloatingRepresentation())
From =
ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_PRValue,
/*BasePath=*/nullptr, CCK)
.get();
else
From =
ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_PRValue,
/*BasePath=*/nullptr, CCK)
.get();
}
case ICK_HLSL_Vector_Truncation: {
// Note: HLSL built-in vectors are ExtVectors. Since this truncates a
// vector to a smaller vector, this can only operate on arguments where
// the source and destination types are ExtVectors.
assert(From->getType()->isExtVectorType() && ToType->isExtVectorType() &&
"HLSL vector truncation should only apply to ExtVectors");
auto *FromVec = From->getType()->castAs<VectorType>();
auto *ToVec = ToType->castAs<VectorType>();
QualType ElType = FromVec->getElementType();
QualType TruncTy =
Context.getExtVectorType(ElType, ToVec->getNumElements());
From = ImpCastExprToType(From, TruncTy, CK_HLSLVectorTruncation,
From->getValueKind())
.get();
break;
}
case ICK_Identity:
default:
llvm_unreachable("Improper element standard conversion");
Expand Down
Loading
Loading