Skip to content

Commit b509eb7

Browse files
authored
[HLSL] add IsTypedResourceElementCompatible type trait (#114864)
This PR implements a new type trait as a builtin, __builtin_hlsl_is_typed_resource_element_compatible This type traits verifies that the given input type is suitable as a typed resource element type. It checks that the given input type is homogeneous, has no more than 4 sub elements, does not exceed 16 bytes, and does not contain any arrays, booleans, or enums. Fixes an issue in #113730 that needed to cause that PR to be reverted. Fixes #113223
1 parent dbb4858 commit b509eb7

File tree

6 files changed

+175
-0
lines changed

6 files changed

+175
-0
lines changed

clang/include/clang/Basic/TokenKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,7 @@ KEYWORD(out , KEYHLSL)
662662
// HLSL Type traits
663663
TYPE_TRAIT_2(__builtin_hlsl_is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
664664
TYPE_TRAIT_1(__builtin_hlsl_is_intangible, IsIntangibleType, KEYHLSL)
665+
TYPE_TRAIT_1(__builtin_hlsl_is_typed_resource_element_compatible, IsTypedResourceElementCompatible, KEYHLSL)
665666

666667
// OpenMP Type Traits
667668
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ class SemaHLSL : public SemaBase {
132132

133133
// HLSL Type trait implementations
134134
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
135+
bool IsTypedResourceElementCompatible(QualType T1);
135136

136137
bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);
137138

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5032,6 +5032,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
50325032
case UTT_IsScalar:
50335033
case UTT_IsCompound:
50345034
case UTT_IsMemberPointer:
5035+
case UTT_IsTypedResourceElementCompatible:
50355036
// Fall-through
50365037

50375038
// These traits are modeled on type predicates in C++0x [meta.unary.prop]
@@ -5714,6 +5715,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
57145715
tok::kw___builtin_hlsl_is_intangible))
57155716
return false;
57165717
return T->isHLSLIntangibleType();
5718+
5719+
case UTT_IsTypedResourceElementCompatible:
5720+
assert(Self.getLangOpts().HLSL &&
5721+
"typed resource element compatible types are an HLSL-only feature");
5722+
if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
5723+
diag::err_incomplete_type))
5724+
return false;
5725+
5726+
return Self.HLSL().IsTypedResourceElementCompatible(T);
57175727
}
57185728
}
57195729

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,6 +2199,50 @@ static void BuildFlattenedTypeList(QualType BaseTy,
21992199
}
22002200
}
22012201

2202+
bool SemaHLSL::IsTypedResourceElementCompatible(clang::QualType QT) {
2203+
if (QT.isNull())
2204+
return false;
2205+
2206+
// check if the outer type was an array type
2207+
if (QT->isArrayType())
2208+
return false;
2209+
2210+
llvm::SmallVector<QualType, 4> QTTypes;
2211+
BuildFlattenedTypeList(QT, QTTypes);
2212+
2213+
assert(QTTypes.size() > 0 &&
2214+
"expected at least one constituent type from non-null type");
2215+
QualType FirstQT = SemaRef.Context.getCanonicalType(QTTypes[0]);
2216+
2217+
// element count cannot exceed 4
2218+
if (QTTypes.size() > 4)
2219+
return false;
2220+
2221+
for (QualType TempQT : QTTypes) {
2222+
// ensure homogeneity
2223+
if (!getASTContext().hasSameUnqualifiedType(FirstQT, TempQT))
2224+
return false;
2225+
}
2226+
2227+
if (const BuiltinType *BT = FirstQT->getAs<BuiltinType>()) {
2228+
if (BT->isBooleanType() || BT->isEnumeralType())
2229+
return false;
2230+
2231+
// Check if it is an array type.
2232+
if (FirstQT->isArrayType())
2233+
return false;
2234+
}
2235+
2236+
// if the loop above completes without returning, then
2237+
// we've guaranteed homogeneity
2238+
int TotalSizeInBytes =
2239+
(SemaRef.Context.getTypeSize(FirstQT) / 8) * QTTypes.size();
2240+
if (TotalSizeInBytes > 16)
2241+
return false;
2242+
2243+
return true;
2244+
}
2245+
22022246
bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
22032247
if (T1.isNull() || T2.isNull())
22042248
return false;
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
2+
// expected-no-diagnostics
3+
4+
struct oneInt {
5+
int i;
6+
};
7+
8+
struct twoInt {
9+
int aa;
10+
int ab;
11+
};
12+
13+
struct threeInts {
14+
oneInt o;
15+
twoInt t;
16+
};
17+
18+
struct oneFloat {
19+
float f;
20+
};
21+
struct depthDiff {
22+
int i;
23+
oneInt o;
24+
oneFloat f;
25+
};
26+
27+
struct notHomogenous{
28+
int i;
29+
float f;
30+
};
31+
32+
struct EightElements {
33+
twoInt x[2];
34+
twoInt y[2];
35+
};
36+
37+
struct EightHalves {
38+
half x[8];
39+
};
40+
41+
struct intVec {
42+
int2 i;
43+
};
44+
45+
struct oneIntWithVec {
46+
int i;
47+
oneInt i2;
48+
int2 i3;
49+
};
50+
51+
struct weirdStruct {
52+
int i;
53+
intVec iv;
54+
};
55+
56+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(int), "");
57+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(float), "");
58+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(float4), "");
59+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(double2), "");
60+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneInt), "");
61+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneFloat), "");
62+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(twoInt), "");
63+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(threeInts), "");
64+
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(notHomogenous), "");
65+
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(depthDiff), "");
66+
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(EightElements), "");
67+
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(EightHalves), "");
68+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneIntWithVec), "");
69+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(weirdStruct), "");
70+
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(RWBuffer<int>), "");
71+
72+
73+
// arrays not allowed
74+
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(half[4]), "");
75+
76+
template<typename T> struct TemplatedBuffer {
77+
T a;
78+
__hlsl_resource_t h;
79+
};
80+
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(TemplatedBuffer<int>), "");
81+
82+
struct MyStruct1 : TemplatedBuffer<float> {
83+
float x;
84+
};
85+
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(MyStruct1), "");
86+
87+
struct MyStruct2 {
88+
const TemplatedBuffer<float> TB[10];
89+
};
90+
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(MyStruct2), "");
91+
92+
template<typename T> struct SimpleTemplate {
93+
T a;
94+
};
95+
96+
// though the element type is incomplete, the type trait should still technically return true
97+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(SimpleTemplate<__hlsl_resource_t>), "");
98+
99+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(SimpleTemplate<float>), "");
100+
101+
102+
typedef int myInt;
103+
104+
struct TypeDefTest {
105+
int x;
106+
myInt y;
107+
};
108+
109+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(TypeDefTest), "");
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
2+
3+
// types must be complete
4+
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(__hlsl_resource_t), "");
5+
6+
// expected-note@+1{{forward declaration of 'notComplete'}}
7+
struct notComplete;
8+
// expected-error@+1{{incomplete type 'notComplete' where a complete type is required}}
9+
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(notComplete), "");
10+

0 commit comments

Comments
 (0)