Skip to content

Commit c5430b3

Browse files
committed
Updates based on review feedback
This addresses feedback from @rjmcall. The main updates are: * Added asserts and todos about handling constrained intrinsics. * Fixed sufflevector code generation (and updated tests) * Fixed shadowed promotion casts. Writing a test for this revealed another issue. * Added Element conversion to conversion rank checking, and added test to verify promotion is preferred over conversion. * Added HLSL integral promotion check. There are still at least two outstanding bugs that are exposed by this change which I've added an XFAIL'd test for (llvm#81047 & llvm#81049). HLSL's promotion rules are not well written down, but specifically in overload resolution integer and floating point values can implicitly cast to larger types and the smallest of the larger types is the best match.
1 parent 2b90d41 commit c5430b3

File tree

6 files changed

+101
-24
lines changed

6 files changed

+101
-24
lines changed

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2421,7 +2421,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
24212421
CE->getExprLoc(), Opts);
24222422
}
24232423
case CK_IntegralToFloating: {
2424-
if (E->getType()->isExtVectorType() && DestTy->isExtVectorType()) {
2424+
if (E->getType()->isVectorType() && DestTy->isVectorType()) {
2425+
// TODO: Support constrained FP intrinsics.
2426+
assert(!Builder.getIsFPConstrained() &&
2427+
"FP Constrained vector casts not supported yet.");
24252428
QualType SrcElTy = E->getType()->castAs<VectorType>()->getElementType();
24262429
if (SrcElTy->isSignedIntegerOrEnumerationType())
24272430
return Builder.CreateSIToFP(Visit(E), ConvertType(DestTy), "conv");
@@ -2432,7 +2435,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
24322435
CE->getExprLoc());
24332436
}
24342437
case CK_FloatingToIntegral: {
2435-
if (E->getType()->isExtVectorType() && DestTy->isExtVectorType()) {
2438+
if (E->getType()->isVectorType() && DestTy->isVectorType()) {
2439+
// TODO: Support constrained FP intrinsics.
2440+
assert(!Builder.getIsFPConstrained() &&
2441+
"FP Constrained vector casts not supported yet.");
24362442
QualType DstElTy = DestTy->castAs<VectorType>()->getElementType();
24372443
if (DstElTy->isSignedIntegerOrEnumerationType())
24382444
return Builder.CreateFPToSI(Visit(E), ConvertType(DestTy), "conv");
@@ -2443,7 +2449,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
24432449
CE->getExprLoc());
24442450
}
24452451
case CK_FloatingCast: {
2446-
if (E->getType()->isExtVectorType() && DestTy->isExtVectorType()) {
2452+
if (E->getType()->isVectorType() && DestTy->isVectorType()) {
2453+
// TODO: Support constrained FP intrinsics.
2454+
assert(!Builder.getIsFPConstrained() &&
2455+
"FP Constrained vector casts not supported yet.");
24472456
QualType SrcElTy = E->getType()->castAs<VectorType>()->getElementType();
24482457
QualType DstElTy = DestTy->castAs<VectorType>()->getElementType();
24492458
if (DstElTy->castAs<BuiltinType>()->getKind() <
@@ -2508,8 +2517,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
25082517
assert(DestTy->isVectorType() && "Expected dest type to be vector type");
25092518
Value *Vec = Visit(const_cast<Expr *>(E));
25102519
SmallVector<int, 16> Mask;
2511-
Mask.insert(Mask.begin(), DestTy->castAs<VectorType>()->getNumElements(),
2512-
0);
2520+
unsigned NumElts = DestTy->castAs<VectorType>()->getNumElements();
2521+
for (unsigned I = 0; I != NumElts; ++I)
2522+
Mask.push_back(I);
2523+
25132524
return Builder.CreateShuffleVector(Vec, Mask, "trunc");
25142525
}
25152526

clang/lib/Sema/SemaOverload.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ ImplicitConversionRank StandardConversionSequence::getRank() const {
232232
Rank = GetConversionRank(First);
233233
if (GetConversionRank(Second) > Rank)
234234
Rank = GetConversionRank(Second);
235+
if (GetConversionRank(Element) > Rank)
236+
Rank = GetConversionRank(Element);
235237
if (GetConversionRank(Third) > Rank)
236238
Rank = GetConversionRank(Third);
237239
return Rank;
@@ -1879,13 +1881,13 @@ static bool IsVectorElementConversion(Sema &S, QualType FromType,
18791881
if (S.Context.hasSameUnqualifiedType(FromType, ToType))
18801882
return true;
18811883

1882-
if (IsFloatingPointConversion(S, FromType, ToType)) {
1883-
ICK = ICK_Floating_Conversion;
1884+
if (S.IsFloatingPointPromotion(FromType, ToType)) {
1885+
ICK = ICK_Floating_Promotion;
18841886
return true;
18851887
}
18861888

1887-
if (S.IsFloatingPointPromotion(FromType, ToType)) {
1888-
ICK = ICK_Floating_Promotion;
1889+
if (IsFloatingPointConversion(S, FromType, ToType)) {
1890+
ICK = ICK_Floating_Conversion;
18891891
return true;
18901892
}
18911893

@@ -1894,14 +1896,14 @@ static bool IsVectorElementConversion(Sema &S, QualType FromType,
18941896
return true;
18951897
}
18961898

1897-
if (FromType->isIntegralOrUnscopedEnumerationType() &&
1898-
ToType->isIntegralType(S.Context)) {
1899-
ICK = ICK_Integral_Conversion;
1899+
if (S.IsIntegralPromotion(From, FromType, ToType)) {
1900+
ICK = ICK_Integral_Promotion;
19001901
return true;
19011902
}
19021903

1903-
if (S.IsIntegralPromotion(From, FromType, ToType)) {
1904-
ICK = ICK_Integral_Promotion;
1904+
if (FromType->isIntegralOrUnscopedEnumerationType() &&
1905+
ToType->isIntegralType(S.Context)) {
1906+
ICK = ICK_Integral_Conversion;
19051907
return true;
19061908
}
19071909

@@ -2531,6 +2533,12 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
25312533
return true;
25322534
}
25332535

2536+
// In HLSL an rvalue of integral type can be promoted to an rvalue of a larger
2537+
// integral type.
2538+
if (Context.getLangOpts().HLSL)
2539+
return Context.getTypeSize(FromType) < Context.getTypeSize(ToType);
2540+
2541+
25342542
return false;
25352543
}
25362544

clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ void f3_to_d4() {
1818
// CHECK: [[f2:%.*]] = alloca <2 x float>
1919
// CHECK: store <3 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00>, ptr [[f3]]
2020
// CHECK: [[vecf3:%.*]] = load <3 x float>, ptr [[f3]]
21-
// CHECK: [[vecf2:%.*]] = shufflevector <3 x float> [[vecf3]], <3 x float> poison, <2 x i32> zeroinitializer
21+
// CHECK: [[vecf2:%.*]] = shufflevector <3 x float> [[vecf3]], <3 x float> poison, <2 x i32> <i32 0, i32 1>
2222
// CHECK: store <2 x float> [[vecf2]], ptr [[f2]]
2323
void f3_to_f2() {
2424
vector<float,3> f3 = 2.0;
@@ -30,7 +30,7 @@ void f3_to_f2() {
3030
// CHECK: [[f2:%.*]] = alloca <2 x float>
3131
// CHECK: store <4 x double> <double 3.000000e+00, double 3.000000e+00, double 3.000000e+00, double 3.000000e+00>, ptr [[d4]]
3232
// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
33-
// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> zeroinitializer
33+
// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> <i32 0, i32 1>
3434
// CHECK: [[vecf2:%.*]] = fptrunc <2 x double> [[vecd2]] to <2 x float>
3535
// CHECK: store <2 x float> [[vecf2]], ptr [[f2]]
3636
void d4_to_f2() {
@@ -55,7 +55,7 @@ void f2_to_i2() {
5555
// CHECK: [[i2:%.*]] = alloca <2 x i32>
5656
// CHECK: store <4 x double> <double 5.000000e+00, double 5.000000e+00, double 5.000000e+00, double 5.000000e+00>, ptr [[d4]]
5757
// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
58-
// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> zeroinitializer
58+
// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> <i32 0, i32 1>
5959
// CHECK: [[veci2]] = fptosi <2 x double> [[vecd2]] to <2 x i32>
6060
// CHECK: store <2 x i32> [[veci2]], ptr [[i2]]
6161
void d4_to_i2() {
@@ -81,7 +81,7 @@ void d4_to_l4() {
8181
// CHECK: [[i2:%.*]] = alloca <2 x i32>
8282
// CHECK: store <4 x i64> <i64 7, i64 7, i64 7, i64 7>, ptr [[l4]]
8383
// CHECK: [[vecl4:%.*]] = load <4 x i64>, ptr [[l4]]
84-
// CHECK: [[vecl2:%.*]] = shufflevector <4 x i64> [[vecl4]], <4 x i64> poison, <2 x i32> zeroinitializer
84+
// CHECK: [[vecl2:%.*]] = shufflevector <4 x i64> [[vecl4]], <4 x i64> poison, <2 x i32> <i32 0, i32 1>
8585
// CHECK: [[veci2:%.*]] = trunc <2 x i64> [[vecl2]] to <2 x i32>
8686
// CHECK: store <2 x i32> [[veci2]], ptr [[i2]]
8787
void l4_to_i2() {
@@ -108,7 +108,7 @@ void i2_to_b2() {
108108
// CHECK: [[b2:%.*]] = alloca i8
109109
// CHECK: store <4 x double> <double 9.000000e+00, double 9.000000e+00, double 9.000000e+00, double 9.000000e+00>, ptr [[d4]]
110110
// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
111-
// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> zeroinitializer
111+
// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> <i32 0, i32 1>
112112
// CHECK: [[vecb2:%.*]] = fcmp une <2 x double> [[vecd2]], zeroinitializer
113113
// CHECK: [[vecb8:%.*]] = shufflevector <2 x i1> [[vecb2]], <2 x i1> poison, <8 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
114114
// CHECK: [[i8:%.*]] = bitcast <8 x i1> [[vecb8]] to i8

clang/test/CodeGenHLSL/builtins/sqrt.hlsl

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \
22
// RUN: dxil-pc-shadermodel6.2-library %s -fnative-half-type \
33
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
4-
// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \
5-
// RUN: dxil-pc-shadermodel6.2-library %s -emit-llvm -disable-llvm-passes \
6-
// RUN: -o - | FileCheck %s --check-prefix=NO_HALF
74

85
using hlsl::sqrt;
96

@@ -30,5 +27,3 @@ half sqrt_h(half x)
3027

3128
// CHECK: define noundef half @"?sqrt_h@@YA$f16@$f16@@Z"(
3229
// CHECK: call half @llvm.sqrt.f16(half %0)
33-
// NO_HALF: define noundef float @"?sqrt_h@@YA$halff@$halff@@Z"(
34-
// NO_HALF: call float @llvm.sqrt.f32(float %0)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -o - -fsyntax-only %s -verify
2+
// XFAIL: *
3+
4+
// https://github.com/llvm/llvm-project/issues/81047
5+
6+
// expected-no-diagnostics
7+
void Fn3(double2 D);
8+
void Fn3(float2 F);
9+
10+
void Call3(half2 H) {
11+
Fn3(H);
12+
}
13+
14+
void Fn4(int64_t2 L);
15+
void Fn4(int2 I);
16+
17+
void Call4(int16_t H) {
18+
Fn4(H);
19+
}
20+
21+
// https://github.com/llvm/llvm-project/issues/81049
22+
23+
// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \
24+
// RUN: dxil-pc-shadermodel6.2-library %s -emit-llvm -disable-llvm-passes \
25+
// RUN: -o - | FileCheck %s --check-prefix=NO_HALF
26+
27+
half sqrt_h(half x)
28+
{
29+
return sqrt(x);
30+
}
31+
32+
// NO_HALF: define noundef float @"?sqrt_h@@YA$halff@$halff@@Z"(
33+
// NO_HALF: call float @llvm.sqrt.f32(float %0)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %clang_cc1 -triple dxil-unknown-shadermodel6.6-library -S -fnative-half-type -finclude-default-header -o - -ast-dump %s | FileCheck %s
2+
void Fn(double2 D);
3+
void Fn(half2 H);
4+
5+
// CHECK: FunctionDecl {{.*}} Call 'void (float2)'
6+
// CHECK: CallExpr {{.*}}'void'
7+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' <FunctionToPointerDecay>
8+
// CHECK-NEXT: DeclRefExpr {{.*}}'void (double2)' lvalue Function {{.*}} 'Fn' 'void (double2)'
9+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double2':'double __attribute__((ext_vector_type(2)))' <FloatingCast>
10+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'float __attribute__((ext_vector_type(2)))' <LValueToRValue>
11+
// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'float __attribute__((ext_vector_type(2)))' lvalue ParmVar {{.*}} 'F' 'float2':'float __attribute__((ext_vector_type(2)))'
12+
13+
void Call(float2 F) {
14+
Fn(F);
15+
}
16+
17+
void Fn2(int64_t2 L);
18+
void Fn2(int16_t2 S);
19+
20+
// CHECK: FunctionDecl {{.*}} Call2 'void (int2)'
21+
// CHECK: CallExpr {{.*}} 'void'
22+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int64_t2)' <FunctionToPointerDecay>
23+
// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int64_t2)' lvalue Function {{.*}} 'Fn2' 'void (int64_t2)'
24+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t2':'long __attribute__((ext_vector_type(2)))' <IntegralCast>
25+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'int __attribute__((ext_vector_type(2)))' <LValueToRValue>
26+
// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'int __attribute__((ext_vector_type(2)))' lvalue ParmVar {{.*}} 'I' 'int2':'int __attribute__((ext_vector_type(2)))'
27+
28+
void Call2(int2 I) {
29+
Fn2(I);
30+
}

0 commit comments

Comments
 (0)