Skip to content

Commit 19fe9b4

Browse files
authored
[HLSL][TableGen] Add __hlsl_resource_t to known built-in function types (#163465)
This change adds resource handle type `__hlsl_resource_t` to the list of types recognized in the Clang's built-in functions prototype string. HLSL has built-in resource classes and some of them have many methods, such as [Texture2D](https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-object-texture2d). Most of these methods will be implemented by built-in functions that will take resource handle as an argument. This change enables us to move from generic `void(...)` prototype string for these methods and explicit argument checking in `SemaHLSL.cpp` to a prototype string with explicit argument types. Argument checking in `SemaHLSL.cpp` can be reduced to handle just the rules that cannot be expressed in the prototype string (for example verifying that the offset value in `__builtin_hlsl_buffer_update_counter` is `1` or `-1`). In order to make this work, we now allow conversions from attributed resource handle type such as `__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]]` to a plain non-attributed `__hlsl_resource_t` type.
1 parent 9b7fd00 commit 19fe9b4

File tree

9 files changed

+96
-120
lines changed

9 files changed

+96
-120
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4949,25 +4949,25 @@ def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
49494949
def HLSLResourceUninitializedHandle : LangBuiltin<"HLSL_LANG"> {
49504950
let Spellings = ["__builtin_hlsl_resource_uninitializedhandle"];
49514951
let Attributes = [NoThrow];
4952-
let Prototype = "void(...)";
4952+
let Prototype = "__hlsl_resource_t(__hlsl_resource_t)";
49534953
}
49544954

49554955
def HLSLResourceHandleFromBinding : LangBuiltin<"HLSL_LANG"> {
49564956
let Spellings = ["__builtin_hlsl_resource_handlefrombinding"];
49574957
let Attributes = [NoThrow];
4958-
let Prototype = "void(...)";
4958+
let Prototype = "__hlsl_resource_t(__hlsl_resource_t, uint32_t, uint32_t, int32_t, uint32_t, char const*)";
49594959
}
49604960

49614961
def HLSLResourceHandleFromImplicitBinding : LangBuiltin<"HLSL_LANG"> {
49624962
let Spellings = ["__builtin_hlsl_resource_handlefromimplicitbinding"];
49634963
let Attributes = [NoThrow];
4964-
let Prototype = "void(...)";
4964+
let Prototype = "__hlsl_resource_t(__hlsl_resource_t, uint32_t, uint32_t, int32_t, uint32_t, char const*)";
49654965
}
49664966

49674967
def HLSLResourceCounterHandleFromImplicitBinding : LangBuiltin<"HLSL_LANG"> {
49684968
let Spellings = ["__builtin_hlsl_resource_counterhandlefromimplicitbinding"];
4969-
let Attributes = [NoThrow, CustomTypeChecking];
4970-
let Prototype = "void(...)";
4969+
let Attributes = [NoThrow];
4970+
let Prototype = "__hlsl_resource_t(__hlsl_resource_t, uint32_t, uint32_t)";
49714971
}
49724972

49734973
def HLSLResourceNonUniformIndex : LangBuiltin<"HLSL_LANG"> {
@@ -4979,13 +4979,13 @@ def HLSLResourceNonUniformIndex : LangBuiltin<"HLSL_LANG"> {
49794979
def HLSLResourceGetDimensionsX : LangBuiltin<"HLSL_LANG"> {
49804980
let Spellings = ["__builtin_hlsl_resource_getdimensions_x"];
49814981
let Attributes = [NoThrow];
4982-
let Prototype = "void(...)";
4982+
let Prototype = "void(__hlsl_resource_t, uint32_t&)";
49834983
}
49844984

49854985
def HLSLResourceGetStride : LangBuiltin<"HLSL_LANG"> {
49864986
let Spellings = ["__builtin_hlsl_resource_getstride"];
49874987
let Attributes = [NoThrow];
4988-
let Prototype = "void(...)";
4988+
let Prototype = "void(__hlsl_resource_t, uint32_t&)";
49894989
}
49904990

49914991
def HLSLAll : LangBuiltin<"HLSL_LANG"> {
@@ -5213,7 +5213,7 @@ def HLSLRadians : LangBuiltin<"HLSL_LANG"> {
52135213
def HLSLBufferUpdateCounter : LangBuiltin<"HLSL_LANG"> {
52145214
let Spellings = ["__builtin_hlsl_buffer_update_counter"];
52155215
let Attributes = [NoThrow];
5216-
let Prototype = "uint32_t(...)";
5216+
let Prototype = "uint32_t(__hlsl_resource_t, int)";
52175217
}
52185218

52195219
def HLSLSplitDouble: LangBuiltin<"HLSL_LANG"> {

clang/lib/AST/ASTContext.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12540,6 +12540,10 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
1254012540
Type = Context.AMDGPUTextureTy;
1254112541
break;
1254212542
}
12543+
case 'r': {
12544+
Type = Context.HLSLResourceTy;
12545+
break;
12546+
}
1254312547
default:
1254412548
llvm_unreachable("Unexpected target builtin type");
1254512549
}

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 11 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3058,54 +3058,29 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
30583058
break;
30593059
}
30603060
case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
3061-
if (SemaRef.checkArgCount(TheCall, 1) ||
3062-
CheckResourceHandle(&SemaRef, TheCall, 0))
3063-
return true;
3064-
// use the type of the handle (arg0) as a return type
3061+
assert(TheCall->getNumArgs() == 1 && "expected 1 arg");
3062+
// Update return type to be the attributed resource type from arg0.
30653063
QualType ResourceTy = TheCall->getArg(0)->getType();
30663064
TheCall->setType(ResourceTy);
30673065
break;
30683066
}
30693067
case Builtin::BI__builtin_hlsl_resource_handlefrombinding: {
3070-
ASTContext &AST = SemaRef.getASTContext();
3071-
if (SemaRef.checkArgCount(TheCall, 6) ||
3072-
CheckResourceHandle(&SemaRef, TheCall, 0) ||
3073-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3074-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy) ||
3075-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.IntTy) ||
3076-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy) ||
3077-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(5),
3078-
AST.getPointerType(AST.CharTy.withConst())))
3079-
return true;
3080-
// use the type of the handle (arg0) as a return type
3068+
assert(TheCall->getNumArgs() == 6 && "expected 6 args");
3069+
// Update return type to be the attributed resource type from arg0.
30813070
QualType ResourceTy = TheCall->getArg(0)->getType();
30823071
TheCall->setType(ResourceTy);
30833072
break;
30843073
}
30853074
case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
3086-
ASTContext &AST = SemaRef.getASTContext();
3087-
if (SemaRef.checkArgCount(TheCall, 6) ||
3088-
CheckResourceHandle(&SemaRef, TheCall, 0) ||
3089-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3090-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy) ||
3091-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.IntTy) ||
3092-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy) ||
3093-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(5),
3094-
AST.getPointerType(AST.CharTy.withConst())))
3095-
return true;
3096-
// use the type of the handle (arg0) as a return type
3075+
assert(TheCall->getNumArgs() == 6 && "expected 6 args");
3076+
// Update return type to be the attributed resource type from arg0.
30973077
QualType ResourceTy = TheCall->getArg(0)->getType();
30983078
TheCall->setType(ResourceTy);
30993079
break;
31003080
}
31013081
case Builtin::BI__builtin_hlsl_resource_counterhandlefromimplicitbinding: {
3082+
assert(TheCall->getNumArgs() == 3 && "expected 3 args");
31023083
ASTContext &AST = SemaRef.getASTContext();
3103-
if (SemaRef.checkArgCount(TheCall, 3) ||
3104-
CheckResourceHandle(&SemaRef, TheCall, 0) ||
3105-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3106-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy))
3107-
return true;
3108-
31093084
QualType MainHandleTy = TheCall->getArg(0)->getType();
31103085
auto *MainResType = MainHandleTy->getAs<HLSLAttributedResourceType>();
31113086
auto MainAttrs = MainResType->getAttrs();
@@ -3114,27 +3089,11 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
31143089
QualType CounterHandleTy = AST.getHLSLAttributedResourceType(
31153090
MainResType->getWrappedType(), MainResType->getContainedType(),
31163091
MainAttrs);
3092+
// Update return type to be the attributed resource type from arg0
3093+
// with added IsCounter flag.
31173094
TheCall->setType(CounterHandleTy);
31183095
break;
31193096
}
3120-
case Builtin::BI__builtin_hlsl_resource_getdimensions_x: {
3121-
ASTContext &AST = SemaRef.getASTContext();
3122-
if (SemaRef.checkArgCount(TheCall, 2) ||
3123-
CheckResourceHandle(&SemaRef, TheCall, 0) ||
3124-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3125-
CheckModifiableLValue(&SemaRef, TheCall, 1))
3126-
return true;
3127-
break;
3128-
}
3129-
case Builtin::BI__builtin_hlsl_resource_getstride: {
3130-
ASTContext &AST = SemaRef.getASTContext();
3131-
if (SemaRef.checkArgCount(TheCall, 2) ||
3132-
CheckResourceHandle(&SemaRef, TheCall, 0) ||
3133-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3134-
CheckModifiableLValue(&SemaRef, TheCall, 1))
3135-
return true;
3136-
break;
3137-
}
31383097
case Builtin::BI__builtin_hlsl_and:
31393098
case Builtin::BI__builtin_hlsl_or: {
31403099
if (SemaRef.checkArgCount(TheCall, 2))
@@ -3434,14 +3393,12 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
34343393
break;
34353394
}
34363395
case Builtin::BI__builtin_hlsl_buffer_update_counter: {
3396+
assert(TheCall->getNumArgs() == 2 && "expected 2 args");
34373397
auto checkResTy = [](const HLSLAttributedResourceType *ResTy) -> bool {
34383398
return !(ResTy->getAttrs().ResourceClass == ResourceClass::UAV &&
34393399
ResTy->getAttrs().RawBuffer && ResTy->hasContainedType());
34403400
};
3441-
if (SemaRef.checkArgCount(TheCall, 2) ||
3442-
CheckResourceHandle(&SemaRef, TheCall, 0, checkResTy) ||
3443-
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
3444-
SemaRef.getASTContext().IntTy))
3401+
if (CheckResourceHandle(&SemaRef, TheCall, 0, checkResTy))
34453402
return true;
34463403
Expr *OffsetExpr = TheCall->getArg(1);
34473404
std::optional<llvm::APSInt> Offset =

clang/lib/Sema/SemaOverload.cpp

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,20 +1825,34 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
18251825
return ICS;
18261826
}
18271827

1828-
if (S.getLangOpts().HLSL && ToType->isHLSLAttributedResourceType() &&
1829-
FromType->isHLSLAttributedResourceType()) {
1830-
auto *ToResType = cast<HLSLAttributedResourceType>(ToType);
1831-
auto *FromResType = cast<HLSLAttributedResourceType>(FromType);
1832-
if (S.Context.hasSameUnqualifiedType(ToResType->getWrappedType(),
1833-
FromResType->getWrappedType()) &&
1834-
S.Context.hasSameUnqualifiedType(ToResType->getContainedType(),
1835-
FromResType->getContainedType()) &&
1836-
ToResType->getAttrs() == FromResType->getAttrs()) {
1837-
ICS.setStandard();
1838-
ICS.Standard.setAsIdentityConversion();
1839-
ICS.Standard.setFromType(FromType);
1840-
ICS.Standard.setAllToTypes(ToType);
1841-
return ICS;
1828+
if (S.getLangOpts().HLSL) {
1829+
// Handle conversion of the HLSL resource types.
1830+
const Type *FromTy = FromType->getUnqualifiedDesugaredType();
1831+
if (FromTy->isHLSLAttributedResourceType()) {
1832+
// Attributed resource types can convert to other attributed
1833+
// resource types with the same attributes and contained types,
1834+
// or to __hlsl_resource_t without any attributes.
1835+
bool CanConvert = false;
1836+
const Type *ToTy = ToType->getUnqualifiedDesugaredType();
1837+
if (ToTy->isHLSLAttributedResourceType()) {
1838+
auto *ToResType = cast<HLSLAttributedResourceType>(ToTy);
1839+
auto *FromResType = cast<HLSLAttributedResourceType>(FromTy);
1840+
if (S.Context.hasSameUnqualifiedType(ToResType->getWrappedType(),
1841+
FromResType->getWrappedType()) &&
1842+
S.Context.hasSameUnqualifiedType(ToResType->getContainedType(),
1843+
FromResType->getContainedType()) &&
1844+
ToResType->getAttrs() == FromResType->getAttrs())
1845+
CanConvert = true;
1846+
} else if (ToTy->isHLSLResourceType()) {
1847+
CanConvert = true;
1848+
}
1849+
if (CanConvert) {
1850+
ICS.setStandard();
1851+
ICS.Standard.setAsIdentityConversion();
1852+
ICS.Standard.setFromType(FromType);
1853+
ICS.Standard.setAllToTypes(ToType);
1854+
return ICS;
1855+
}
18421856
}
18431857
}
18441858

clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ RESOURCE Buffer;
5050
// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
5151
// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
5252
// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t
53-
// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
54-
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_uninitializedhandle'
53+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '__hlsl_resource_t (*)(__hlsl_resource_t) noexcept' <BuiltinFnToFnPtr>
54+
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_uninitializedhandle' '__hlsl_resource_t (__hlsl_resource_t) noexcept'
5555
// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
5656
// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
5757
// CHECK-NEXT: AlwaysInlineAttr
@@ -97,8 +97,8 @@ RESOURCE Buffer;
9797
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
9898
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
9999
// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t {{.*}}'
100-
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
101-
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefrombinding' 'void (...) noexcept'
100+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '__hlsl_resource_t (*)(__hlsl_resource_t, unsigned int, unsigned int, int, unsigned int, const char *) noexcept' <BuiltinFnToFnPtr>
101+
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefrombinding' '__hlsl_resource_t (__hlsl_resource_t, unsigned int, unsigned int, int, unsigned int, const char *) noexcept'
102102
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
103103
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
104104
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'registerNo' 'unsigned int'
@@ -127,8 +127,8 @@ RESOURCE Buffer;
127127
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
128128
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
129129
// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t {{.*}}'
130-
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
131-
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefromimplicitbinding' 'void (...) noexcept'
130+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '__hlsl_resource_t (*)(__hlsl_resource_t, unsigned int, unsigned int, int, unsigned int, const char *) noexcept' <BuiltinFnToFnPtr>
131+
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefromimplicitbinding' '__hlsl_resource_t (__hlsl_resource_t, unsigned int, unsigned int, int, unsigned int, const char *) noexcept'
132132
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
133133
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
134134
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'orderId' 'unsigned int'
@@ -149,8 +149,8 @@ RESOURCE Buffer;
149149
// CHECK-NEXT: HLSLParamModifierAttr {{.*}} out
150150
// CHECK-NEXT: CompoundStmt
151151
// CHECK-NEXT: CallExpr {{.*}} 'void'
152-
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
153-
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getdimensions_x' 'void (...) noexcept'
152+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(__hlsl_resource_t, unsigned int &) noexcept' <BuiltinFnToFnPtr>
153+
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getdimensions_x' 'void (__hlsl_resource_t, unsigned int &) noexcept'
154154
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle {{.*}}
155155
// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
156156
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'dim' 'unsigned int &__restrict'

0 commit comments

Comments
 (0)