Skip to content

Commit 4672db6

Browse files
authored
Insert cast when types are identical to HLSL but not to clang (microsoft#4631)
It's possible to get a value of a type `unsigned long` in HLSL, such as the result of sizeof(), while the uint type is `unsigned int` instead. This leads to the situation where no cast is inserted because the types look identical when translated down to ArBasicKind, which can lead to an assert during codegen, such as when passing sizeof() result to a function call parameter. This change preserves the original canonical type ptr from clang and sets the conversion type when these differ, even when ArBasicKind is identical.
1 parent dfceabd commit 4672db6

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

tools/clang/lib/Sema/SemaHLSL.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ BITWISE_ENUM_OPS(TYPE_CONVERSION_REMARKS)
708708
struct ArTypeInfo {
709709
ArTypeObjectKind ShapeKind; // The shape of the type (basic, matrix, etc.)
710710
ArBasicKind EltKind; // The primitive type of elements in this type.
711+
const clang::Type *EltTy; // Canonical element type ptr
711712
ArBasicKind ObjKind; // The object type for this type (textures, buffers, etc.)
712713
UINT uRows;
713714
UINT uCols;
@@ -4308,6 +4309,22 @@ class HLSLExternalSource : public ExternalSemaSource {
43084309
return QualType(type->getCanonicalTypeUnqualified()->getTypePtr(), 0);
43094310
}
43104311

4312+
/// <summary>Given a Clang type, return the QualType for its element, drilling through any array/vector/matrix.</summary>
4313+
QualType GetTypeElementType(QualType type)
4314+
{
4315+
type = GetStructuralForm(type);
4316+
ArTypeObjectKind kind = GetTypeObjectKind(type);
4317+
if (kind == AR_TOBJ_MATRIX || kind == AR_TOBJ_VECTOR) {
4318+
type = GetMatrixOrVectorElementType(type);
4319+
} else if (kind == AR_TOBJ_STRING) {
4320+
// return original type even if it's an array (string literal)
4321+
} else if (type->isArrayType()) {
4322+
const ArrayType* arrayType = type->getAsArrayTypeUnsafe();
4323+
type = GetTypeElementType(arrayType->getElementType());
4324+
}
4325+
return type;
4326+
}
4327+
43114328
/// <summary>Given a Clang type, return the ArBasicKind classification for its contents.</summary>
43124329
ArBasicKind GetTypeElementKind(QualType type)
43134330
{
@@ -6779,6 +6796,7 @@ void HLSLExternalSource::CollectInfo(QualType type, ArTypeInfo* pTypeInfo)
67796796
// Try to inline that here, making it cheaper to use this function
67806797
// when retrieving multiple properties.
67816798
pTypeInfo->ObjKind = GetTypeElementKind(type);
6799+
pTypeInfo->EltTy = GetTypeElementType(type)->getCanonicalTypeUnqualified()->getTypePtr();
67826800
pTypeInfo->EltKind = pTypeInfo->ObjKind;
67836801
pTypeInfo->ShapeKind = GetTypeObjectKind(type);
67846802
GetRowsAndColsForAny(type, pTypeInfo->uRows, pTypeInfo->uCols);
@@ -8899,6 +8917,18 @@ static bool ConvertComponent(ArTypeInfo TargetInfo, ArTypeInfo SourceInfo,
88998917
ComponentConversion = ICK_Floating_Integral;
89008918
}
89018919
}
8920+
} else if (TargetInfo.EltTy != SourceInfo.EltTy) {
8921+
// Types are identical in HLSL, but not identical in clang,
8922+
// such as unsigned long vs. unsigned int.
8923+
// Add conversion based on the type.
8924+
if (IS_BASIC_AINT(TargetInfo.EltKind))
8925+
ComponentConversion = ICK_Integral_Conversion;
8926+
else if (IS_BASIC_FLOAT(TargetInfo.EltKind))
8927+
ComponentConversion = ICK_Floating_Conversion;
8928+
else {
8929+
DXASSERT(false, "unhandled case for conversion that's identical in HLSL, but not in clang");
8930+
return false;
8931+
}
89028932
}
89038933

89048934
return true;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %dxc -T vs_6_0 -ast-dump %s | FileCheck %s
2+
// RUN: %dxc -T vs_6_0 %s | FileCheck -check-prefix=CHECKIR %s
3+
4+
// sizeof() results in unsigned long, while various HLSL intrinsics take unsigned int.
5+
// These types are identical in HLSL (uint), but not in clang.
6+
// A conversion step is still necessary to prevent this case from causing
7+
// assert when checking function arguments during codegen.
8+
9+
// CHECK: CallExpr
10+
// CHECK-NEXT: ImplicitCastExpr
11+
// CHECK-NEXT: DeclRefExpr
12+
// CHECK-NEXT: ImplicitCastExpr
13+
// CHECK-SAME: IntegralCast
14+
// CHECK-NEXT: UnaryExprOrTypeTraitExpr
15+
16+
// CHECKIR: call void @dx.op.storeOutput.i32(i32 5, i32 0, i32 0, i8 0, i32 4)
17+
18+
uint main() : OUT {
19+
return abs(sizeof(float));
20+
}

0 commit comments

Comments
 (0)