Skip to content

Commit 84c6a2c

Browse files
committed
[HLSL] Rework implicit conversion sequences
This PR reworks HLSL's implicit conversion sequences. Initially I was seeking to match DXC's behavior more closely, but that was leading to a pile of special case rules to tie-break ambiguous cases that should really be left as ambiguous. This change is a bit closer to C++'s overload resolution rules, but it does have a bit of nuance around how dimension adjustment conversions are ranked. Conversion sequence ranks for HLSL are: * Exact match * Scalar Widening (i.e. splat) * Promotion * Scalar Widening with Promotion * Conversion * Scalar Widening with Conversion * Dimension Reduction (i.e. truncation) * Dimension Reduction with Promotion * Dimension Reduction with Conversion In this implementation I've folded the disambiguation into the conversion sequence ranks which does add some complexity as compared to C++, however this avoids needing to add special casing in `CompareStandardConversionSequences`. I belive the added conversion rank values provide a simpler approach, but welcome feedback. ../clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hl sl ../clang/test/SemaHLSL/TruncationOverloadResolution.hlsl ../clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl ../clang/test/SemaHLSL/VectorElementOverloadResolution.hlsl ../clang/test/SemaHLSL/standard_conversion_sequences.hlsl
1 parent 2ad7b4a commit 84c6a2c

16 files changed

+447
-339
lines changed

clang/docs/HLSL/ExpectedDifferences.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,16 @@ behavior between Clang and DXC. Some examples include:
6767
void takesDoubles(double, double, double);
6868

6969
cbuffer CB {
70+
bool B;
7071
uint U;
7172
int I;
7273
float X, Y, Z;
7374
double3 A, B;
7475
}
7576

77+
void twoParams(int, int);
78+
void twoParams(float, float);
79+
7680
export void call() {
7781
halfOrInt16(U); // DXC: Fails with call ambiguous between int16_t and uint16_t overloads
7882
// Clang: Resolves to halfOrInt16(uint16_t).
@@ -98,6 +102,13 @@ behavior between Clang and DXC. Some examples include:
98102
// FXC: Expands to compute double dot product with fmul/fadd
99103
// Clang: Resolves to dot(float3, float3), emits conversion warnings.
100104

105+
#ifndef IGNORE_ERRORS
106+
tan(B); // DXC: resolves to tan(float).
107+
// Clang: Fails to resolve, ambiguous between integer types.
108+
109+
twoParams(I, X); // DXC: resolves twoParams(int, int).
110+
// Clang: Fails to resolve ambiguous conversions.
111+
#endif
101112
}
102113

103114
.. note::

clang/include/clang/Sema/Overload.h

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ class Sema;
201201
/// HLSL non-decaying array rvalue cast.
202202
ICK_HLSL_Array_RValue,
203203

204+
// HLSL vector splat from scalar or boolean type.
205+
ICK_HLSL_Vector_Splat,
206+
204207
/// The number of conversion kinds
205208
ICK_Num_Conversion_Kinds,
206209
};
@@ -213,15 +216,27 @@ class Sema;
213216
/// Exact Match
214217
ICR_Exact_Match = 0,
215218

219+
/// HLSL Scalar Widening
220+
ICR_HLSL_Scalar_Widening,
221+
216222
/// Promotion
217223
ICR_Promotion,
218224

225+
/// HLSL Scalar Widening with promotion
226+
ICR_HLSL_Scalar_Widening_Promotion,
227+
228+
/// HLSL Matching Dimension Reduction
229+
ICR_HLSL_Dimension_Reduction,
230+
219231
/// Conversion
220232
ICR_Conversion,
221233

222234
/// OpenCL Scalar Widening
223235
ICR_OCL_Scalar_Widening,
224236

237+
/// HLSL Scalar Widening with conversion
238+
ICR_HLSL_Scalar_Widening_Conversion,
239+
225240
/// Complex <-> Real conversion
226241
ICR_Complex_Real_Conversion,
227242

@@ -233,11 +248,21 @@ class Sema;
233248

234249
/// Conversion not allowed by the C standard, but that we accept as an
235250
/// extension anyway.
236-
ICR_C_Conversion_Extension
251+
ICR_C_Conversion_Extension,
252+
253+
/// HLSL Dimension reduction with promotion
254+
ICR_HLSL_Dimension_Reduction_Promotion,
255+
256+
/// HLSL Dimension reduction with conversion
257+
ICR_HLSL_Dimension_Reduction_Conversion,
237258
};
238259

239260
ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
240261

262+
ImplicitConversionRank
263+
GetDimensionConversionRank(ImplicitConversionRank Base,
264+
ImplicitConversionKind Dimension);
265+
241266
/// NarrowingKind - The kind of narrowing conversion being performed by a
242267
/// standard conversion sequence according to C++11 [dcl.init.list]p7.
243268
enum NarrowingKind {
@@ -277,11 +302,10 @@ class Sema;
277302
/// pointer-to-member conversion, or boolean conversion.
278303
ImplicitConversionKind Second : 8;
279304

280-
/// Element - Between the second and third conversion a vector or matrix
281-
/// element conversion may occur. If this is not ICK_Identity this
282-
/// conversion is applied element-wise to each element in the vector or
283-
/// matrix.
284-
ImplicitConversionKind Element : 8;
305+
/// Dimension - Between the second and third conversion a vector or matrix
306+
/// dimension conversion may occur. If this is not ICK_Identity this
307+
/// conversion truncates the vector or matrix, or extends a scalar.
308+
ImplicitConversionKind Dimension : 8;
285309

286310
/// Third - The third conversion can be a qualification conversion
287311
/// or a function conversion.
@@ -379,7 +403,7 @@ class Sema;
379403
void setAsIdentityConversion();
380404

381405
bool isIdentityConversion() const {
382-
return Second == ICK_Identity && Element == ICK_Identity &&
406+
return Second == ICK_Identity && Dimension == ICK_Identity &&
383407
Third == ICK_Identity;
384408
}
385409

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 77 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4294,6 +4294,21 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
42944294
return From;
42954295
}
42964296

4297+
// GetIntermediateVectorType - Compute the intermediate cast type casting
4298+
// elements of the from type to the elements of the to type without resizing the
4299+
// vector.
4300+
static QualType adjustVectorType(ASTContext &Context, QualType FromTy,
4301+
QualType ToType, QualType *ElTy = nullptr) {
4302+
auto *ToVec = ToType->castAs<VectorType>();
4303+
QualType ElType = ToVec->getElementType();
4304+
if (ElTy)
4305+
*ElTy = ElType;
4306+
if (!FromTy->isVectorType())
4307+
return ElType;
4308+
auto *FromVec = FromTy->castAs<VectorType>();
4309+
return Context.getExtVectorType(ElType, FromVec->getNumElements());
4310+
}
4311+
42974312
ExprResult
42984313
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
42994314
const StandardConversionSequence& SCS,
@@ -4443,27 +4458,36 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
44434458
break;
44444459

44454460
case ICK_Integral_Promotion:
4446-
case ICK_Integral_Conversion:
4447-
if (ToType->isBooleanType()) {
4461+
case ICK_Integral_Conversion: {
4462+
QualType ElTy = ToType;
4463+
QualType StepTy = ToType;
4464+
if (ToType->isVectorType())
4465+
StepTy = adjustVectorType(Context, FromType, ToType, &ElTy);
4466+
if (ElTy->isBooleanType()) {
44484467
assert(FromType->castAs<EnumType>()->getDecl()->isFixed() &&
44494468
SCS.Second == ICK_Integral_Promotion &&
44504469
"only enums with fixed underlying type can promote to bool");
4451-
From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, VK_PRValue,
4470+
From = ImpCastExprToType(From, StepTy, CK_IntegralToBoolean, VK_PRValue,
44524471
/*BasePath=*/nullptr, CCK)
44534472
.get();
44544473
} else {
4455-
From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_PRValue,
4474+
From = ImpCastExprToType(From, StepTy, CK_IntegralCast, VK_PRValue,
44564475
/*BasePath=*/nullptr, CCK)
44574476
.get();
44584477
}
44594478
break;
4479+
}
44604480

44614481
case ICK_Floating_Promotion:
4462-
case ICK_Floating_Conversion:
4463-
From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_PRValue,
4482+
case ICK_Floating_Conversion: {
4483+
QualType StepTy = ToType;
4484+
if (ToType->isVectorType())
4485+
StepTy = adjustVectorType(Context, FromType, ToType);
4486+
From = ImpCastExprToType(From, StepTy, CK_FloatingCast, VK_PRValue,
44644487
/*BasePath=*/nullptr, CCK)
44654488
.get();
44664489
break;
4490+
}
44674491

44684492
case ICK_Complex_Promotion:
44694493
case ICK_Complex_Conversion: {
@@ -4486,16 +4510,21 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
44864510
break;
44874511
}
44884512

4489-
case ICK_Floating_Integral:
4490-
if (ToType->isRealFloatingType())
4491-
From = ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_PRValue,
4513+
case ICK_Floating_Integral: {
4514+
QualType ElTy = ToType;
4515+
QualType StepTy = ToType;
4516+
if (ToType->isVectorType())
4517+
StepTy = adjustVectorType(Context, FromType, ToType, &ElTy);
4518+
if (ElTy->isRealFloatingType())
4519+
From = ImpCastExprToType(From, StepTy, CK_IntegralToFloating, VK_PRValue,
44924520
/*BasePath=*/nullptr, CCK)
44934521
.get();
44944522
else
4495-
From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_PRValue,
4523+
From = ImpCastExprToType(From, StepTy, CK_FloatingToIntegral, VK_PRValue,
44964524
/*BasePath=*/nullptr, CCK)
44974525
.get();
44984526
break;
4527+
}
44994528

45004529
case ICK_Fixed_Point_Conversion:
45014530
assert((FromType->isFixedPointType() || ToType->isFixedPointType()) &&
@@ -4617,18 +4646,26 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
46174646
break;
46184647
}
46194648

4620-
case ICK_Boolean_Conversion:
4649+
case ICK_Boolean_Conversion: {
46214650
// Perform half-to-boolean conversion via float.
46224651
if (From->getType()->isHalfType()) {
46234652
From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).get();
46244653
FromType = Context.FloatTy;
46254654
}
4655+
QualType ElTy = FromType;
4656+
QualType StepTy = ToType;
4657+
if (FromType->isVectorType()) {
4658+
if (getLangOpts().HLSL)
4659+
StepTy = adjustVectorType(Context, FromType, ToType);
4660+
ElTy = FromType->castAs<VectorType>()->getElementType();
4661+
}
46264662

4627-
From = ImpCastExprToType(From, Context.BoolTy,
4628-
ScalarTypeToBooleanCastKind(FromType), VK_PRValue,
4663+
From = ImpCastExprToType(From, StepTy,
4664+
ScalarTypeToBooleanCastKind(ElTy), VK_PRValue,
46294665
/*BasePath=*/nullptr, CCK)
46304666
.get();
46314667
break;
4668+
}
46324669

46334670
case ICK_Derived_To_Base: {
46344671
CXXCastPath BasePath;
@@ -4754,22 +4791,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
47544791
CK_ZeroToOCLOpaqueType,
47554792
From->getValueKind()).get();
47564793
break;
4757-
case ICK_HLSL_Vector_Truncation: {
4758-
// Note: HLSL built-in vectors are ExtVectors. Since this truncates a vector
4759-
// to a smaller vector, this can only operate on arguments where the source
4760-
// and destination types are ExtVectors.
4761-
assert(From->getType()->isExtVectorType() && ToType->isExtVectorType() &&
4762-
"HLSL vector truncation should only apply to ExtVectors");
4763-
auto *FromVec = From->getType()->castAs<VectorType>();
4764-
auto *ToVec = ToType->castAs<VectorType>();
4765-
QualType ElType = FromVec->getElementType();
4766-
QualType TruncTy =
4767-
Context.getExtVectorType(ElType, ToVec->getNumElements());
4768-
From = ImpCastExprToType(From, TruncTy, CK_HLSLVectorTruncation,
4769-
From->getValueKind())
4770-
.get();
4771-
break;
4772-
}
47734794

47744795
case ICK_Lvalue_To_Rvalue:
47754796
case ICK_Array_To_Pointer:
@@ -4780,73 +4801,45 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
47804801
case ICK_C_Only_Conversion:
47814802
case ICK_Incompatible_Pointer_Conversion:
47824803
case ICK_HLSL_Array_RValue:
4804+
case ICK_HLSL_Vector_Truncation:
4805+
case ICK_HLSL_Vector_Splat:
47834806
llvm_unreachable("Improper second standard conversion");
47844807
}
47854808

4786-
if (SCS.Element != ICK_Identity) {
4809+
if (SCS.Dimension != ICK_Identity) {
47874810
// If SCS.Element is not ICK_Identity the To and From types must be HLSL
47884811
// vectors or matrices.
47894812

47904813
// TODO: Support HLSL matrices.
47914814
assert((!From->getType()->isMatrixType() && !ToType->isMatrixType()) &&
4792-
"Element conversion for matrix types is not implemented yet.");
4793-
assert(From->getType()->isVectorType() && ToType->isVectorType() &&
4794-
"Element conversion is only supported for vector types.");
4795-
assert(From->getType()->getAs<VectorType>()->getNumElements() ==
4796-
ToType->getAs<VectorType>()->getNumElements() &&
4797-
"Element conversion is only supported for vectors with the same "
4798-
"element counts.");
4799-
QualType FromElTy = From->getType()->getAs<VectorType>()->getElementType();
4800-
unsigned NumElts = ToType->getAs<VectorType>()->getNumElements();
4801-
switch (SCS.Element) {
4802-
case ICK_Boolean_Conversion:
4803-
// Perform half-to-boolean conversion via float.
4804-
if (FromElTy->isHalfType()) {
4805-
QualType FPExtType = Context.getExtVectorType(FromElTy, NumElts);
4806-
From = ImpCastExprToType(From, FPExtType, CK_FloatingCast).get();
4807-
FromType = FPExtType;
4808-
}
4809-
4810-
From =
4811-
ImpCastExprToType(From, ToType, ScalarTypeToBooleanCastKind(FromElTy),
4812-
VK_PRValue,
4813-
/*BasePath=*/nullptr, CCK)
4814-
.get();
4815-
break;
4816-
case ICK_Integral_Promotion:
4817-
case ICK_Integral_Conversion:
4818-
if (ToType->isBooleanType()) {
4819-
assert(FromType->castAs<EnumType>()->getDecl()->isFixed() &&
4820-
SCS.Second == ICK_Integral_Promotion &&
4821-
"only enums with fixed underlying type can promote to bool");
4822-
From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, VK_PRValue,
4823-
/*BasePath=*/nullptr, CCK)
4824-
.get();
4825-
} else {
4826-
From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_PRValue,
4827-
/*BasePath=*/nullptr, CCK)
4828-
.get();
4829-
}
4830-
break;
4831-
4832-
case ICK_Floating_Promotion:
4833-
case ICK_Floating_Conversion:
4834-
From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_PRValue,
4815+
"Dimension conversion for matrix types is not implemented yet.");
4816+
assert(ToType->isVectorType() &&
4817+
"Dimension conversion is only supported for vector types.");
4818+
switch (SCS.Dimension) {
4819+
case ICK_HLSL_Vector_Splat: {
4820+
// Vector splat from any arithmetic type to a vector.
4821+
Expr *Elem = prepareVectorSplat(ToType, From).get();
4822+
From = ImpCastExprToType(Elem, ToType, CK_VectorSplat, VK_PRValue,
48354823
/*BasePath=*/nullptr, CCK)
48364824
.get();
48374825
break;
4838-
case ICK_Floating_Integral:
4839-
if (ToType->hasFloatingRepresentation())
4840-
From =
4841-
ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_PRValue,
4842-
/*BasePath=*/nullptr, CCK)
4843-
.get();
4844-
else
4845-
From =
4846-
ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_PRValue,
4847-
/*BasePath=*/nullptr, CCK)
4848-
.get();
4826+
}
4827+
case ICK_HLSL_Vector_Truncation: {
4828+
// Note: HLSL built-in vectors are ExtVectors. Since this truncates a
4829+
// vector to a smaller vector, this can only operate on arguments where
4830+
// the source and destination types are ExtVectors.
4831+
assert(From->getType()->isExtVectorType() && ToType->isExtVectorType() &&
4832+
"HLSL vector truncation should only apply to ExtVectors");
4833+
auto *FromVec = From->getType()->castAs<VectorType>();
4834+
auto *ToVec = ToType->castAs<VectorType>();
4835+
QualType ElType = FromVec->getElementType();
4836+
QualType TruncTy =
4837+
Context.getExtVectorType(ElType, ToVec->getNumElements());
4838+
From = ImpCastExprToType(From, TruncTy, CK_HLSLVectorTruncation,
4839+
From->getValueKind())
4840+
.get();
48494841
break;
4842+
}
48504843
case ICK_Identity:
48514844
default:
48524845
llvm_unreachable("Improper element standard conversion");

0 commit comments

Comments
 (0)