https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/221103
>From 3e70d41f6223c89dd318cdcf57be14c250eb3557 Mon Sep 17 00:00:00 2001 From: Helena Kotas <[email protected]> Date: Thu, 3 Sep 2026 13:02:10 -0700 Subject: [PATCH 1/2] [HLSL] Add support for dynamic resources --- clang/include/clang/Basic/Builtins.td | 12 ++ .../clang/Sema/HLSLExternalSemaSource.h | 2 + clang/lib/CodeGen/CGHLSLBuiltins.cpp | 22 +++ clang/lib/CodeGen/CGHLSLRuntime.h | 2 + clang/lib/Headers/CMakeLists.txt | 1 + clang/lib/Headers/hlsl.h | 1 + clang/lib/Headers/hlsl/hlsl_resources.h | 36 +++++ clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 68 +++++++++ clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 3 + clang/lib/Sema/HLSLExternalSemaSource.cpp | 27 ++++ clang/lib/Sema/SemaHLSL.cpp | 26 ++++ .../test/AST/HLSL/ByteAddressBuffers-AST.hlsl | 18 +++ clang/test/AST/HLSL/DynamicResources-AST.hlsl | 132 ++++++++++++++++++ .../test/AST/HLSL/StructuredBuffers-AST.hlsl | 27 ++++ clang/test/AST/HLSL/TypedBuffers-AST.hlsl | 17 +++ .../resources/dynamic-resources.hlsl | 109 +++++++++++++++ clang/test/SemaHLSL/Language/InitLists.hlsl | 1 + .../Textures-SampleCmpLevelZero.hlsl | 5 +- .../dynamic-resources-availability.hlsl | 13 ++ .../SemaHLSL/Resources/dynamic-resources.hlsl | 50 +++++++ llvm/include/llvm/IR/IntrinsicsSPIRV.td | 9 ++ 21 files changed, 579 insertions(+), 2 deletions(-) create mode 100644 clang/lib/Headers/hlsl/hlsl_resources.h create mode 100644 clang/test/AST/HLSL/DynamicResources-AST.hlsl create mode 100644 clang/test/CodeGenHLSL/resources/dynamic-resources.hlsl create mode 100644 clang/test/SemaHLSL/Resources/dynamic-resources-availability.hlsl create mode 100644 clang/test/SemaHLSL/Resources/dynamic-resources.hlsl diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 49fe879c6add1..2b33b4a8541b3 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5431,6 +5431,18 @@ def HLSLResourceCounterHandleFromImplicitBinding : LangBuiltin<"HLSL_LANG"> { let Prototype = "__hlsl_resource_t(__hlsl_resource_t, uint32_t, uint32_t)"; } +def HLSLResourceHandleFromHeap : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_resource_handlefromheap"]; + let Attributes = [NoThrow]; + let Prototype = "__hlsl_resource_t(__hlsl_resource_t, uint32_t)"; +} + +def HLSLResourceCounterHandleFromHeap : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_resource_counterhandlefromheap"]; + let Attributes = [NoThrow]; + let Prototype = "__hlsl_resource_t(__hlsl_resource_t, uint32_t)"; +} + def HLSLResourceNonUniformIndex : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_resource_nonuniformindex"]; let Attributes = [NoThrow]; diff --git a/clang/include/clang/Sema/HLSLExternalSemaSource.h b/clang/include/clang/Sema/HLSLExternalSemaSource.h index 77fd3fafc6d77..840cd3e0a082a 100644 --- a/clang/include/clang/Sema/HLSLExternalSemaSource.h +++ b/clang/include/clang/Sema/HLSLExternalSemaSource.h @@ -43,8 +43,10 @@ class HLSLExternalSemaSource : public ExternalSemaSource { private: void defineTrivialHLSLTypes(); + void defineInternalHLSLTypes(); void defineHLSLVectorAlias(); void defineHLSLMatrixAlias(); + void defineHeapResourceInfoTypes(); void defineHLSLTypesWithForwardDeclarations(); void defineHLSLAtomicIntrinsics(); void onCompletion(CXXRecordDecl *Record, CompletionFunction Fn); diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 062faadcdcab2..42c107405dff3 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -1063,6 +1063,28 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, return EmitIntrinsicCall(IntrinsicID, {HandleTy, MainHandle->getType()}, Args); } + case Builtin::BI__builtin_hlsl_resource_handlefromheap: { + llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType()); + Value *IndexOp = EmitScalarExpr(E->getArg(1)); + llvm::Intrinsic::ID IntrinsicID = + CGM.getHLSLRuntime().getCreateHandleFromHeapIntrinsic(); + SmallVector<Value *> Args{IndexOp}; + return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args); + } + case Builtin::BI__builtin_hlsl_resource_counterhandlefromheap: { + Value *MainHandle = EmitScalarExpr(E->getArg(0)); + if (!CGM.getTriple().isSPIRV()) + return MainHandle; + + llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType()); + Value *IndexOp = EmitScalarExpr(E->getArg(1)); + llvm::Intrinsic::ID IntrinsicID = + llvm::Intrinsic::spv_resource_counterhandlefromheap; + SmallVector<Value *> Args{MainHandle, IndexOp}; + return EmitIntrinsicCall(IntrinsicID, {HandleTy, MainHandle->getType()}, + Args); + } + case Builtin::BI__builtin_hlsl_resource_nonuniformindex: { Value *IndexOp = EmitScalarExpr(E->getArg(0)); llvm::Type *RetTy = ConvertType(E->getType()); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index 381653e8f8345..2ceafcc94a0b8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -186,6 +186,8 @@ class CGHLSLRuntime { resource_handlefrombinding) GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromImplicitBinding, resource_handlefromimplicitbinding) + GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromHeap, + resource_handlefromheap) GENERATE_HLSL_INTRINSIC_FUNCTION(NonUniformResourceIndex, resource_nonuniformindex) GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, resource_updatecounter) diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index 3d845423759ac..9befd7b192af7 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -98,6 +98,7 @@ set(hlsl_subdir_files hlsl/hlsl_intrinsic_helpers.h hlsl/hlsl_intrinsics.h hlsl/hlsl_detail.h + hlsl/hlsl_resources.h hlsl/hlsl_spirv.h ) set(hlsl_files diff --git a/clang/lib/Headers/hlsl.h b/clang/lib/Headers/hlsl.h index 8a144191c4695..ff50c9f9b7ac2 100644 --- a/clang/lib/Headers/hlsl.h +++ b/clang/lib/Headers/hlsl.h @@ -26,6 +26,7 @@ #if __HLSL_VERSION <= __HLSL_202x #include "hlsl/hlsl_compat_overloads.h" #endif +#include "hlsl/hlsl_resources.h" #ifdef __spirv__ #include "hlsl/hlsl_spirv.h" diff --git a/clang/lib/Headers/hlsl/hlsl_resources.h b/clang/lib/Headers/hlsl/hlsl_resources.h new file mode 100644 index 0000000000000..d43c94dbff572 --- /dev/null +++ b/clang/lib/Headers/hlsl/hlsl_resources.h @@ -0,0 +1,36 @@ +//===----- hlsl_resources.h - HLSL definitions for resources ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _HLSL_HLSL_RESOURCES_H_ +#define _HLSL_HLSL_RESOURCES_H_ + +namespace hlsl { + +#define _HLSL_AVAILABILITY(platform, version) \ + __attribute__((availability(platform, introduced = version))) + +struct __hlsl_resource_descriptor_heap_struct { + __hlsl_heap_resource_info operator[](uint32_t Index) { + return __hlsl_heap_resource_info{Index}; + } +}; + +struct __hlsl_sampler_descriptor_heap_struct { + __hlsl_heap_sampler_info operator[](uint32_t Index) { + return __hlsl_heap_sampler_info{Index}; + } +}; + +_HLSL_AVAILABILITY(shadermodel, 6.6) +static __hlsl_resource_descriptor_heap_struct ResourceDescriptorHeap; + +_HLSL_AVAILABILITY(shadermodel, 6.6) +static __hlsl_sampler_descriptor_heap_struct SamplerDescriptorHeap; + +} // namespace hlsl +#endif //_HLSL_HLSL_RESOURCES_H_ diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 34e883264b5b3..15f78eadad4e2 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -1216,6 +1216,74 @@ BuiltinTypeDeclBuilder::addDefaultHandleConstructor(AccessSpecifier Access) { .finalize(Access); } +// Adds constructor that takes __hlsl_heap_resource_info: +// Resource::Resource(__hlsl_heap_resource_info info) { +// __handle = __builtin_hlsl_resource_handlefromheap(__handle, info.Index); +// } +BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addHeapResourceInfoConstructor(bool HasCounter) { + assert(!Record->isCompleteDefinition() && "record is already complete"); + + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + + ASTContext &AST = SemaRef.getASTContext(); + QualType HandleType = getResourceHandleField()->getType(); + + QualType HeapResInfoType = lookupBuiltinType( + SemaRef, "__hlsl_heap_resource_info", Record->getDeclContext()); + CXXRecordDecl *HeapResInfoDecl = HeapResInfoType->getAsCXXRecordDecl(); + + FieldDecl *IndexField = *HeapResInfoDecl->field_begin(); + assert(IndexField && IndexField->getType() == AST.UnsignedIntTy && + "Index field not as expected"); + + auto MB = BuiltinTypeMethodBuilder(*this, "", AST.VoidTy, false, true); + MB.addParam("HeapResInfo", HeapResInfoType) + .callBuiltin("__builtin_hlsl_resource_handlefromheap", HandleType, + PH::Handle, MB.createMemberExpr(PH::_0, IndexField)) + .assign(PH::Handle, PH::LastStmt); + + if (HasCounter) { + QualType CounterHandleType = getResourceCounterHandleField()->getType(); + MB.callBuiltin("__builtin_hlsl_resource_counterhandlefromheap", + CounterHandleType, PH::Handle, + MB.createMemberExpr(PH::_0, IndexField)) + .assign(PH::CounterHandle, PH::LastStmt); + } + + return MB.finalize(); +} + +// Adds constructor that takes __hlsl_heap_sampler_info: +// Resource::Resource(__hlsl_heap_sampler_info info) { +// __handle = __builtin_hlsl_resource_handlefromheap(__handle, info.Index); +// } +BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addHeapSamplerInfoConstructor() { + assert(!Record->isCompleteDefinition() && "record is already complete"); + + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + + ASTContext &AST = SemaRef.getASTContext(); + QualType HandleType = getResourceHandleField()->getType(); + + QualType HeapResInfoType = lookupBuiltinType( + SemaRef, "__hlsl_heap_sampler_info", Record->getDeclContext()); + CXXRecordDecl *HeapResInfoDecl = HeapResInfoType->getAsCXXRecordDecl(); + + FieldDecl *IndexField = *HeapResInfoDecl->field_begin(); + assert(IndexField && IndexField->getType() == AST.UnsignedIntTy && + "Index field not as expected"); + + auto MB = BuiltinTypeMethodBuilder(*this, "", AST.VoidTy, false, true); + MB.addParam("HeapResInfo", HeapResInfoType); + MB.callBuiltin("__builtin_hlsl_resource_handlefromheap", HandleType, + PH::Handle, MB.createMemberExpr(PH::_0, IndexField)) + .assign(PH::Handle, PH::LastStmt); + + return MB.finalize(); +} + BuiltinTypeDeclBuilder & BuiltinTypeDeclBuilder::addStaticInitializationFunctions(bool HasCounter) { if (HasCounter) { diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h index 62dea7fab8064..226f1026876ca 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h @@ -99,6 +99,9 @@ class BuiltinTypeDeclBuilder { BuiltinTypeDeclBuilder &addDefaultHandleConstructor( AccessSpecifier Access = AccessSpecifier::AS_public); BuiltinTypeDeclBuilder & + addHeapResourceInfoConstructor(bool HasCounter = false); + BuiltinTypeDeclBuilder &addHeapSamplerInfoConstructor(); + BuiltinTypeDeclBuilder & addCopyConstructor(AccessSpecifier Access = AccessSpecifier::AS_public); BuiltinTypeDeclBuilder &addCopyAssignmentOperator( AccessSpecifier Access = AccessSpecifier::AS_public); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index d2d9c97b98a57..75932dc8a136e 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -55,6 +55,7 @@ void HLSLExternalSemaSource::InitializeSema(Sema &S) { // Force external decls in the HLSL namespace to load from the PCH. (void)HLSLNamespace->getCanonicalDecl()->decls_begin(); defineTrivialHLSLTypes(); + defineInternalHLSLTypes(); defineHLSLTypesWithForwardDeclarations(); defineHLSLAtomicIntrinsics(); @@ -233,6 +234,29 @@ void HLSLExternalSemaSource::defineTrivialHLSLTypes() { defineHLSLMatrixAlias(); } +void HLSLExternalSemaSource::defineHeapResourceInfoTypes() { + ASTContext &AST = SemaPtr->getASTContext(); + CXXRecordDecl *ResDecl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, + "__hlsl_heap_resource_info") + .finalizeForwardDeclaration(); + if (!ResDecl->isCompleteDefinition()) + BuiltinTypeDeclBuilder(*SemaPtr, ResDecl) + .addMemberVariable("Index", AST.UnsignedIntTy, {}) + .completeDefinition(); + + CXXRecordDecl *SampDecl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, + "__hlsl_heap_sampler_info") + .finalizeForwardDeclaration(); + if (!SampDecl->isCompleteDefinition()) + BuiltinTypeDeclBuilder(*SemaPtr, SampDecl) + .addMemberVariable("Index", AST.UnsignedIntTy, {}) + .completeDefinition(); +} + +void HLSLExternalSemaSource::defineInternalHLSLTypes() { + defineHeapResourceInfoTypes(); +} + /// Set up common members and attributes for buffer types static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, ResourceClass RC, bool IsROV, @@ -242,6 +266,7 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, .addDefaultHandleConstructor() .addCopyConstructor() .addCopyAssignmentOperator() + .addHeapResourceInfoConstructor(HasCounter) .addStaticInitializationFunctions(HasCounter); } @@ -252,6 +277,7 @@ static BuiltinTypeDeclBuilder setupSamplerType(CXXRecordDecl *Decl, Sema &S) { .addDefaultHandleConstructor() .addCopyConstructor() .addCopyAssignmentOperator() + .addHeapSamplerInfoConstructor() .addStaticInitializationFunctions(false); } @@ -361,6 +387,7 @@ static BuiltinTypeDeclBuilder setupTextureType(CXXRecordDecl *Decl, Sema &S, B.addDefaultHandleConstructor() .addCopyConstructor() .addCopyAssignmentOperator() + .addHeapResourceInfoConstructor() .addStaticInitializationFunctions(false); if (T.has(TexCap::Load)) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 06828b9ec7fc0..7c64266d855de 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -4397,9 +4397,35 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { } case Builtin::BI__builtin_hlsl_resource_counterhandlefromimplicitbinding: { assert(TheCall->getNumArgs() == 3 && "expected 3 args"); + // Update return type to be the attributed resource type from arg0 + // with added IsCounter flag. QualType MainHandleTy = TheCall->getArg(0)->getType(); + QualType CounterHandleTy = + createCounterHandleType(SemaRef.getASTContext(), MainHandleTy); + TheCall->setType(CounterHandleTy); + break; + } + case Builtin::BI__builtin_hlsl_resource_handlefromheap: { + if (SemaRef.checkArgCount(TheCall, 2) || + CheckResourceHandle(&SemaRef, TheCall, 0) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), + SemaRef.getASTContext().UnsignedIntTy)) + return true; + + // Update return type to be the attributed resource type from arg0. + QualType ResourceTy = TheCall->getArg(0)->getType(); + TheCall->setType(ResourceTy); + break; + } + case Builtin::BI__builtin_hlsl_resource_counterhandlefromheap: { + if (SemaRef.checkArgCount(TheCall, 2) || + CheckResourceHandle(&SemaRef, TheCall, 0) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), + SemaRef.getASTContext().UnsignedIntTy)) + return true; // Update return type to be the attributed resource type from arg0 // with added IsCounter flag. + QualType MainHandleTy = TheCall->getArg(0)->getType(); QualType CounterHandleTy = createCounterHandleType(SemaRef.getASTContext(), MainHandleTy); TheCall->setType(CounterHandleTy); diff --git a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl index d6d2aa0819e7b..3312045cf4def 100644 --- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl @@ -82,6 +82,24 @@ RESOURCE Buffer; // CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this // CHECK-NEXT: AlwaysInlineAttr +// Heap info constructor + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (hlsl::__hlsl_heap_resource_info)' inline +// CHECK-NEXT: ParmVarDecl {{.*}} HeapResInfo 'hlsl::__hlsl_heap_resource_info' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: BinaryOperator {{.*}} '=' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t +// CHECK-NEXT: ImplicitCastExpr {{.*}} '__hlsl_resource_t (*)(__hlsl_resource_t, unsigned int) noexcept' <BuiltinFnToFnPtr> +// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefromheap' '__hlsl_resource_t (__hlsl_resource_t, unsigned int) noexcept' +// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <LValueToRValue> +// CHECK-NEXT: MemberExpr {{.*}} 'unsigned int' lvalue .Index +// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::__hlsl_heap_resource_info' lvalue ParmVar {{.*}} 'HeapResInfo' 'hlsl::__hlsl_heap_resource_info' +// CHECK-NEXT: AlwaysInlineAttr + // Static __createFromBinding method // CHECK: CXXMethodDecl {{.*}} __createFromBinding 'hlsl::[[RESOURCE]] (unsigned int, unsigned int, int, unsigned int, const char *)' static diff --git a/clang/test/AST/HLSL/DynamicResources-AST.hlsl b/clang/test/AST/HLSL/DynamicResources-AST.hlsl new file mode 100644 index 0000000000000..00d181388a977 --- /dev/null +++ b/clang/test/AST/HLSL/DynamicResources-AST.hlsl @@ -0,0 +1,132 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library -ast-dump %s | FileCheck %s + +// Global variables for ResourceDescriptorHeap and SamplerDescriptorHeap +// CHECK: VarDecl {{.*}} used ResourceDescriptorHeap 'hlsl_private __hlsl_resource_descriptor_heap_struct' static internal-linkage +// CHECK-NEXT: AvailabilityAttr {{.*}} shadermodel 6.6 0 0 "" "" 0 + +// CHECK: VarDecl {{.*}} used SamplerDescriptorHeap 'hlsl_private __hlsl_sampler_descriptor_heap_struct' static internal-linkage +// CHECK-NEXT: AvailabilityAttr {{.*}} shadermodel 6.6 0 0 "" "" 0 + +void useBuffer(RWBuffer<int> Buffer) {} + +// CHECK-LABEL: FunctionDecl {{.*}} testInvocations +export void testInvocations(unsigned Index) { + +// Buf1 declaration with direct initialization +// CHECK: VarDecl {{.*}} Buf1 'RWBuffer<int>':'hlsl::RWBuffer<int>' cinit +// CHECK-NEXT: ExprWithCleanups{{.*}} 'RWBuffer<int>':'hlsl::RWBuffer<int>' + +// RWBuffer copy constructor +// CHECK-NEXT: CXXConstructExpr {{.*}} 'RWBuffer<int>':'hlsl::RWBuffer<int>' 'void (const hlsl::RWBuffer<int> &)' +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'const RWBuffer<int>':'const hlsl::RWBuffer<int>' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const RWBuffer<int>':'const hlsl::RWBuffer<int>' <NoOp> +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'RWBuffer<int>':'hlsl::RWBuffer<int>' <ConstructorConversion> + +// RWBuffer heap info constructor +// CHECK-NEXT: CXXConstructExpr {{.*}} 'RWBuffer<int>':'hlsl::RWBuffer<int>' 'void (hlsl::__hlsl_heap_resource_info)' + +// __hlsl_heap_resource_info copy constructor +// CHECK-NEXT: CXXConstructExpr {{.*}} 'hlsl::__hlsl_heap_resource_info' 'void (__hlsl_heap_resource_info &&) noexcept' elidable + +// Indexing into ResourceDescriptorHeap +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} '__hlsl_heap_resource_info' xvalue +// CHECK-NEXT: CXXOperatorCallExpr {{.*}} '__hlsl_heap_resource_info' '[]' +// CHECK-NEXT: ImplicitCastExpr {{.*}} '__hlsl_heap_resource_info (*)(uint32_t)' <FunctionToPointerDecay> +// CHECK-NEXT: DeclRefExpr {{.*}} '__hlsl_heap_resource_info (uint32_t)' lvalue CXXMethod {{.*}} 'operator[]' '__hlsl_heap_resource_info (uint32_t)' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::__hlsl_resource_descriptor_heap_struct' lvalue <AddressSpaceConversion> +// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl_private __hlsl_resource_descriptor_heap_struct' lvalue Var {{.*}} 'ResourceDescriptorHeap' 'hlsl_private __hlsl_resource_descriptor_heap_struct' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' lvalue ParmVar {{.*}} 'Index' 'unsigned int' + + RWBuffer<int> Buf1 = ResourceDescriptorHeap[Index]; + +// Buf2 declaration initialized with default constructor (handle is poison) +// CHECK: VarDecl {{.*}} Buf2 'RWBuffer<int>':'hlsl::RWBuffer<int>' callinit +// CHECK-NEXT: CXXConstructExpr {{.*}} 'RWBuffer<int>':'hlsl::RWBuffer<int>' 'void ()' + +// Buf2 assignment operator +// CHECK-NEXT: ExprWithCleanups +// CHECK-NEXT: CXXOperatorCallExpr {{.*}} 'hlsl::RWBuffer<int>' lvalue '=' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::RWBuffer<int> &(*)(const hlsl::RWBuffer<int> &)' <FunctionToPointerDecay> +// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::RWBuffer<int> &(const hlsl::RWBuffer<int> &)' lvalue CXXMethod {{.*}} 'operator=' 'hlsl::RWBuffer<int> &(const hlsl::RWBuffer<int> &)' +// CHECK-NEXT: DeclRefExpr {{.*}} 'RWBuffer<int>':'hlsl::RWBuffer<int>' lvalue Var {{.*}} 'Buf2' 'RWBuffer<int>':'hlsl::RWBuffer<int>' + +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'const hlsl::RWBuffer<int>' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const hlsl::RWBuffer<int>' <NoOp> +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::RWBuffer<int>' <ConstructorConversion> + +// RWBuffer heap info constructor +// CHECK-NEXT: CXXConstructExpr {{.*}} 'hlsl::RWBuffer<int>' 'void (hlsl::__hlsl_heap_resource_info)' + +// __hlsl_heap_resource_info copy constructor +// CHECK-NEXT: CXXConstructExpr {{.*}} 'hlsl::__hlsl_heap_resource_info' 'void (__hlsl_heap_resource_info &&) noexcept' elidable + +// Indexing into ResourceDescriptorHeap +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} '__hlsl_heap_resource_info' xvalue +// CHECK-NEXT: CXXOperatorCallExpr {{.*}} '__hlsl_heap_resource_info' '[]' +// CHECK-NEXT: ImplicitCastExpr {{.*}} '__hlsl_heap_resource_info (*)(uint32_t)' <FunctionToPointerDecay> +// CHECK-NEXT: DeclRefExpr {{.*}} '__hlsl_heap_resource_info (uint32_t)' lvalue CXXMethod {{.*}} 'operator[]' '__hlsl_heap_resource_info (uint32_t)' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::__hlsl_resource_descriptor_heap_struct' lvalue <AddressSpaceConversion> +// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl_private __hlsl_resource_descriptor_heap_struct' lvalue Var {{.*}} 'ResourceDescriptorHeap' 'hlsl_private __hlsl_resource_descriptor_heap_struct' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' lvalue ParmVar {{.*}} 'Index' 'unsigned int' + + RWBuffer<int> Buf2; + Buf2 = ResourceDescriptorHeap[Index]; + +// Call to useBuffer with a temporary RWBuffer constructed from ResourceDescriptorHeap[Index] +// CHECK: CallExpr {{.*}} 'void' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(RWBuffer<int>)' <FunctionToPointerDecay> +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (RWBuffer<int>)' lvalue Function {{.*}} 'useBuffer' 'void (RWBuffer<int>)' + +// RWBuffer copy constructor +// CHECK-NEXT: CXXConstructExpr {{.*}} 'RWBuffer<int>':'hlsl::RWBuffer<int>' 'void (const hlsl::RWBuffer<int> &)' +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'const RWBuffer<int>':'const hlsl::RWBuffer<int>' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const RWBuffer<int>':'const hlsl::RWBuffer<int>' <NoOp> +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'RWBuffer<int>':'hlsl::RWBuffer<int>' <ConstructorConversion> + +// RWBuffer heap info constructor +// CHECK-NEXT: CXXConstructExpr {{.*}} 'RWBuffer<int>':'hlsl::RWBuffer<int>' 'void (hlsl::__hlsl_heap_resource_info)' + +// __hlsl_heap_resource_info copy constructor +// CHECK-NEXT: CXXConstructExpr {{.*}} 'hlsl::__hlsl_heap_resource_info' 'void (__hlsl_heap_resource_info &&) noexcept' elidable + +// Indexing into ResourceDescriptorHeap +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} '__hlsl_heap_resource_info' xvalue +// CHECK-NEXT: CXXOperatorCallExpr {{.*}} '__hlsl_heap_resource_info' '[]' +// CHECK-NEXT: ImplicitCastExpr {{.*}} '__hlsl_heap_resource_info (*)(uint32_t)' <FunctionToPointerDecay> +// CHECK-NEXT: DeclRefExpr {{.*}} '__hlsl_heap_resource_info (uint32_t)' lvalue CXXMethod {{.*}} 'operator[]' '__hlsl_heap_resource_info (uint32_t)' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::__hlsl_resource_descriptor_heap_struct' lvalue <AddressSpaceConversion> +// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl_private __hlsl_resource_descriptor_heap_struct' lvalue Var {{.*}} 'ResourceDescriptorHeap' 'hlsl_private __hlsl_resource_descriptor_heap_struct' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' lvalue ParmVar {{.*}} 'Index' 'unsigned int' + + useBuffer(ResourceDescriptorHeap[Index]); + +// CHECK: VarDecl {{.*}} Sampler 'SamplerState' cinit +// CHECK-NEXT: ExprWithCleanups {{.*}} 'SamplerState' + +// SamplerState copy constructor +// CHECK-NEXT: CXXConstructExpr {{.*}} <col:16, col:53> 'SamplerState' 'void (const hlsl::SamplerState &)' elidable +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} <col:26, col:53> 'const SamplerState' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} <col:26, col:53> 'const SamplerState' <NoOp> +// CHECK-NEXT: ImplicitCastExpr {{.*}} <col:26, col:53> 'SamplerState' <ConstructorConversion> + +// SamplerState heap info constructor +// CHECK-NEXT: CXXConstructExpr {{.*}} <col:26, col:53> 'SamplerState' 'void (hlsl::__hlsl_heap_sampler_info)' + +// __hlsl_heap_resource_info copy constructor +// CHECK-NEXT: CXXConstructExpr {{.*}} <col:26, col:53> 'hlsl::__hlsl_heap_sampler_info' 'void (__hlsl_heap_sampler_info &&) noexcept' elidable + +// Indexing into SamplerDescriptorHeap +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} <col:26, col:53> '__hlsl_heap_sampler_info' xvalue +// CHECK-NEXT: CXXOperatorCallExpr {{.*}} <col:26, col:53> '__hlsl_heap_sampler_info' '[]' +// CHECK-NEXT: ImplicitCastExpr {{.*}} <col:47, col:53> '__hlsl_heap_sampler_info (*)(uint32_t)' <FunctionToPointerDecay> +// CHECK-NEXT: DeclRefExpr {{.*}} <col:47, col:53> '__hlsl_heap_sampler_info (uint32_t)' lvalue CXXMethod {{.*}} 'operator[]' '__hlsl_heap_sampler_info (uint32_t)' +// CHECK-NEXT: ImplicitCastExpr {{.*}} <col:26> 'hlsl::__hlsl_sampler_descriptor_heap_struct' lvalue <AddressSpaceConversion> +// CHECK-NEXT: DeclRefExpr {{.*}} <col:26> 'hlsl_private __hlsl_sampler_descriptor_heap_struct' lvalue Var {{.*}} 'SamplerDescriptorHeap' 'hlsl_private __hlsl_sampler_descriptor_heap_struct' +// CHECK-NEXT: ImplicitCastExpr {{.*}} <col:48> 'unsigned int' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} <col:48> 'unsigned int' lvalue ParmVar {{.*}} 'Index' 'unsigned int' + + SamplerState Sampler = SamplerDescriptorHeap[Index]; +} diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl index 6b38b73d82321..eb858cd51cdb6 100644 --- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl @@ -139,6 +139,33 @@ RESOURCE<float> Buffer; // CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this // CHECK-NEXT: AlwaysInlineAttr +// Heap info constructor + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]]<element_type> 'void (hlsl::__hlsl_heap_resource_info)' inline +// CHECK-NEXT: ParmVarDecl {{.*}} HeapResInfo 'hlsl::__hlsl_heap_resource_info' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: BinaryOperator {{.*}} '=' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this +// CHECK-NEXT: CStyleCastExpr {{.*}} '__hlsl_resource_t +// CHECK-NEXT: CallExpr {{.*}} '<dependent type>' +// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefromheap' '__hlsl_resource_t (__hlsl_resource_t, unsigned int) noexcept' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this +// CHECK-NEXT: MemberExpr {{.*}} 'unsigned int' lvalue .Index +// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::__hlsl_heap_resource_info' lvalue ParmVar {{.*}} 'HeapResInfo' 'hlsl::__hlsl_heap_resource_info' +// CHECK-COUNTER-HANDLE-NEXT: BinaryOperator {{.*}} '=' +// CHECK-COUNTER-HANDLE-NEXT: MemberExpr {{.*}} lvalue .__counter_handle +// CHECK-COUNTER-HANDLE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this +// CHECK-COUNTER-HANDLE-NEXT: CStyleCastExpr {{.*}} '__hlsl_resource_t +// CHECK-COUNTER-HANDLE-NEXT: CallExpr {{.*}} '<dependent type>' +// CHECK-COUNTER-HANDLE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_counterhandlefromheap' '__hlsl_resource_t (__hlsl_resource_t, unsigned int) noexcept' +// CHECK-COUNTER-HANDLE-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-COUNTER-HANDLE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this +// CHECK-COUNTER-HANDLE-NEXT: MemberExpr {{.*}} 'unsigned int' lvalue .Index +// CHECK-COUNTER-HANDLE-NEXT: DeclRefExpr {{.*}} 'hlsl::__hlsl_heap_resource_info' lvalue ParmVar {{.*}} 'HeapResInfo' 'hlsl::__hlsl_heap_resource_info' +// CHECK-NEXT: AlwaysInlineAttr + // Static __createFromBinding method // CHECK-BINDING: CXXMethodDecl {{.*}} __createFromBinding 'hlsl::[[RESOURCE]]<element_type> (unsigned int, unsigned int, int, unsigned int, const char *)' static diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl index a2708e0782bef..667486b34e84f 100644 --- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl @@ -104,6 +104,23 @@ RESOURCE<float> Buffer; // CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this // CHECK-NEXT: AlwaysInlineAttr +// Heap info constructor + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]]<element_type> 'void (hlsl::__hlsl_heap_resource_info)' inline +// CHECK-NEXT: ParmVarDecl {{.*}} HeapResInfo 'hlsl::__hlsl_heap_resource_info' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: BinaryOperator {{.*}} '=' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this +// CHECK-NEXT: CStyleCastExpr {{.*}} '__hlsl_resource_t +// CHECK-NEXT: CallExpr {{.*}} '<dependent type>' +// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefromheap' '__hlsl_resource_t (__hlsl_resource_t, unsigned int) noexcept' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this +// CHECK-NEXT: MemberExpr {{.*}} 'unsigned int' lvalue .Index +// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::__hlsl_heap_resource_info' lvalue ParmVar {{.*}} 'HeapResInfo' 'hlsl::__hlsl_heap_resource_info' +// CHECK-NEXT: AlwaysInlineAttr + // Static __createFromBinding method // CHECK: CXXMethodDecl {{.*}} __createFromBinding 'hlsl::[[RESOURCE]]<element_type> (unsigned int, unsigned int, int, unsigned int, const char *)' static diff --git a/clang/test/CodeGenHLSL/resources/dynamic-resources.hlsl b/clang/test/CodeGenHLSL/resources/dynamic-resources.hlsl new file mode 100644 index 0000000000000..02d641fdeef5f --- /dev/null +++ b/clang/test/CodeGenHLSL/resources/dynamic-resources.hlsl @@ -0,0 +1,109 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library \ +// RUN: -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,DXIL +// RUN: %clang_cc1 -finclude-default-header -triple spirv-vulkan-library \ +// RUN: -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,SPV + +// CHECK: %S = type <{ i32 }> + +// CHECK: @hlsl::ResourceDescriptorHeap = internal {{.*}}global %"struct.hlsl::__hlsl_resource_descriptor_heap_struct" zeroinitializer, align 1 +// CHECK: @hlsl::SamplerDescriptorHeap = internal {{.*}}global %"struct.hlsl::__hlsl_sampler_descriptor_heap_struct" zeroinitializer, align 1 + +// CHECK-LABEL: testTypedBuffer +export void testTypedBuffer(unsigned Index) { +// CHECK: [[TMP0:%.*]] = alloca %"class.hlsl::__hlsl_heap_resource_info" + +// DXIL: call void @hlsl::__hlsl_resource_descriptor_heap_struct::operator[](unsigned int) +// DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::__hlsl_heap_resource_info") align 4 [[TMP0]], +// DXIL-SAME: ptr {{.*}} @hlsl::ResourceDescriptorHeap, i32 noundef %{{[0-9]+}}) + +// SPV: call spir_func void @hlsl::__hlsl_resource_descriptor_heap_struct::operator[](unsigned int) +// SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::__hlsl_heap_resource_info") align 4 [[TMP0]], +// SPV-SAME: ptr {{.*}} addrspacecast ({{.*}} @hlsl::ResourceDescriptorHeap to ptr), i32 noundef %{{[0-9]+}}) + +// CHECK: call {{(spir_func )*}}void @hlsl::RWBuffer<int>::RWBuffer(hlsl::__hlsl_heap_resource_info) +// CHECK-SAME: (ptr {{.*}} %Buffer, ptr noundef byval(%"class.hlsl::__hlsl_heap_resource_info") align 4 [[TMP0]]) + RWBuffer<int> Buffer = ResourceDescriptorHeap[Index]; +} + +struct S { + int Value; +}; + +// CHECK-LABEL: testConstantBuffer +export void testConstantBuffer(unsigned Index) { + +// CHECK: %CBS = alloca %"class.hlsl::ConstantBuffer" +// CHECK: [[TMP1:%.*]] = alloca %"class.hlsl::ConstantBuffer" +// CHECK: [[TMP2:%.*]] = alloca %"class.hlsl::__hlsl_heap_resource_info" +// CHECK: call {{(spir_func )*}}void @hlsl::ConstantBuffer<S>::ConstantBuffer()(ptr {{.*}} %CBS) + +// DXIL: call void @hlsl::__hlsl_resource_descriptor_heap_struct::operator[](unsigned int) +// DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::__hlsl_heap_resource_info") align 4 [[TMP2]], +// DXIL-SAME: ptr {{.*}} @hlsl::ResourceDescriptorHeap, i32 noundef %{{[0-9]+}}) + +// SPV: call spir_func void @hlsl::__hlsl_resource_descriptor_heap_struct::operator[](unsigned int) +// SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::__hlsl_heap_resource_info") align 4 [[TMP2]], +// SPV-SAME: ptr {{.*}} addrspacecast ({{.*}} @hlsl::ResourceDescriptorHeap to ptr), i32 noundef %{{[0-9]+}}) + +// CHECK: call {{(spir_func )*}}void @hlsl::ConstantBuffer<S>::ConstantBuffer(hlsl::__hlsl_heap_resource_info) +// CHECK-SAME: (ptr {{.*}} [[TMP1]], ptr noundef byval(%"class.hlsl::__hlsl_heap_resource_info") align 4 %{{.*}}) + +// CHECK: call {{.*}} ptr @hlsl::ConstantBuffer<S>::operator=(hlsl::ConstantBuffer<S> const&) +// CHECK-SAME: (ptr {{.*}} %CBS, ptr {{.*}} [[TMP1]]) + ConstantBuffer<S> CBS; + CBS = ResourceDescriptorHeap[Index]; +} + +// CHECK: define {{(spir_func )*}}void @testSampler(unsigned int)(ptr {{.*}} sret(%"class.hlsl::SamplerState") align {{(4|8)}} [[RESULT:%.*]], i32 noundef %Index) +// CHECK: [[TMP3:%.*]] = alloca %"class.hlsl::__hlsl_heap_sampler_info" +export SamplerState testSampler(unsigned Index) { + +// DXIL: call void @hlsl::__hlsl_sampler_descriptor_heap_struct::operator[](unsigned int) +// DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::__hlsl_heap_sampler_info") align 4 [[TMP3]], +// DXIL-SAME: ptr {{.*}} @hlsl::SamplerDescriptorHeap, i32 noundef %{{[0-9]+}}) + +// SPV: call spir_func void @hlsl::__hlsl_sampler_descriptor_heap_struct::operator[](unsigned int) +// SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::__hlsl_heap_sampler_info") align 4 [[TMP3]], +// SPV-SAME: ptr {{.*}} addrspacecast ({{.*}} @hlsl::SamplerDescriptorHeap to ptr), i32 noundef %{{[0-9]+}}) + +// CHECK: call {{(spir_func )*}}void @hlsl::SamplerState::SamplerState(hlsl::__hlsl_heap_sampler_info) +// CHECK-SAME: (ptr {{.*}} [[RESULT]], ptr noundef byval(%"class.hlsl::__hlsl_heap_sampler_info") align 4 [[TMP3]]) + return SamplerDescriptorHeap[Index]; +} + +void useAppendBuffer(AppendStructuredBuffer<int> Buffer, int Value) { + Buffer.Append(1); +} + +// CHECK-LABEL: testCounterBuffer +export void testCounterBuffer(unsigned Index) { +// CHECK: [[TMP_BUFFER:%.*]] = alloca %"class.hlsl::AppendStructuredBuffer" +// CHECK: [[TMP4:%.*]] = alloca %"class.hlsl::__hlsl_heap_resource_info" + +// DXIL: call void @hlsl::__hlsl_resource_descriptor_heap_struct::operator[](unsigned int) +// DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::__hlsl_heap_resource_info") align 4 [[TMP4]], +// DXIL-SAME: ptr {{.*}} @hlsl::ResourceDescriptorHeap, i32 noundef %{{[0-9]+}}) + +// SPV: call spir_func void @hlsl::__hlsl_resource_descriptor_heap_struct::operator[](unsigned int) +// SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::__hlsl_heap_resource_info") align 4 [[TMP4]], +// SPV-SAME: ptr {{.*}} addrspacecast ({{.*}} @hlsl::ResourceDescriptorHeap to ptr), i32 noundef %{{[0-9]+}}) + +// CHECK: call {{(spir_func )*}}void @hlsl::AppendStructuredBuffer<int>::AppendStructuredBuffer(hlsl::__hlsl_heap_resource_info) +// CHECK-SAME: (ptr {{.*}} [[TMP_BUFFER]], ptr noundef byval(%"class.hlsl::__hlsl_heap_resource_info") align 4 [[TMP4]]) + +// CHECK: call {{(spir_func )*}}void @useAppendBuffer(hlsl::AppendStructuredBuffer<int>, int) +// CHECK-SAME: (ptr {{.*}} [[TMP_BUFFER]], i32 noundef 10) + useAppendBuffer(ResourceDescriptorHeap[Index], 10); +} + +// DXIL-DAG: call target("dx.TypedBuffer", i32, 1, 0, 1) @llvm.dx.resource.handlefromheap{{.*}}(i32 %{{.*}}) +// DXIL-DAG: call target("dx.CBuffer", %S) @llvm.dx.resource.handlefromheap{{.*}}(i32 %{{.*}}) +// DXIL-DAG: call target("dx.Sampler", 0) @llvm.dx.resource.handlefromheap{{.*}}(i32 %{{.*}}) +// DXIL-DAG: call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefromheap{{.*}}(i32 %{{.*}}) +// DXIL-NOT: counterhandlefromheap + +// SPV-DAG: call target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24) @llvm.spv.resource.handlefromheap{{.*}}(i32 %{{.*}}) +// SPV-DAG: call target("spirv.VulkanBuffer", %S, 2, 0) @llvm.spv.resource.handlefromheap{{.*}}(i32 %{{.*}}) +// SPV-DAG: call target("spirv.Sampler") @llvm.spv.resource.handlefromheap{{.*}}(i32 %{{.*}}) +// SPV-DAG: call target("spirv.VulkanBuffer", [0 x i32], 12, 1) @llvm.spv.resource.handlefromheap{{.*}}(i32 %{{.*}}) +// SPV-DAG: call target("spirv.VulkanBuffer", i32, 12, 1) @llvm.spv.resource.counterhandlefromheap{{.*}}(target("spirv.VulkanBuffer", [0 x i32], 12, 1) %{{.*}}, i32 %{{.*}}) [ "convergencectrl"(token %{{.*}}) ] diff --git a/clang/test/SemaHLSL/Language/InitLists.hlsl b/clang/test/SemaHLSL/Language/InitLists.hlsl index 33c5700544449..f86b029713515 100644 --- a/clang/test/SemaHLSL/Language/InitLists.hlsl +++ b/clang/test/SemaHLSL/Language/InitLists.hlsl @@ -117,3 +117,4 @@ void Err2(RWBuffer<float4> B) { // This note refers to the RWBuffer copy constructor that do not have a source locations // expected-note@*{{candidate constructor not viable}} +// expected-note@*{{candidate constructor not viable}} diff --git a/clang/test/SemaHLSL/Resources/Textures-SampleCmpLevelZero.hlsl b/clang/test/SemaHLSL/Resources/Textures-SampleCmpLevelZero.hlsl index c3d7b41fba2ea..5dbcc3dd5fc05 100644 --- a/clang/test/SemaHLSL/Resources/Textures-SampleCmpLevelZero.hlsl +++ b/clang/test/SemaHLSL/Resources/Textures-SampleCmpLevelZero.hlsl @@ -74,8 +74,9 @@ void main(COORD_TYPE loc, float cmp) { // offset-note@*:* {{candidate function not viable: no known conversion from 'SamplerState' to 'hlsl::SamplerComparisonState' for 1st argument}} // offset-note@*:* {{candidate function not viable: requires 4 arguments, but 3 were provided}} // nooffset-note@*:* {{candidate constructor not viable: no known conversion from 'SamplerState' to 'const hlsl::SamplerComparisonState &' for 1st argument}} - // offset-error@+2 {{no matching member function for call to 'SampleCmpLevelZero'}} - // nooffset-error@+1 {{no viable conversion from 'SamplerState' to 'hlsl::SamplerComparisonState'}} + // offset-error@+3 {{no matching member function for call to 'SampleCmpLevelZero'}} + // nooffset-error@+2 {{no viable conversion from 'SamplerState' to 'hlsl::SamplerComparisonState'}} + // nooffset-note@*:* {{candidate constructor not viable: no known conversion from 'SamplerState' to 'hlsl::__hlsl_heap_sampler_info' for 1st argument}} t.SampleCmpLevelZero(s2, loc, cmp); #ifdef HAS_OFFSET diff --git a/clang/test/SemaHLSL/Resources/dynamic-resources-availability.hlsl b/clang/test/SemaHLSL/Resources/dynamic-resources-availability.hlsl new file mode 100644 index 0000000000000..dc9f0332da9c9 --- /dev/null +++ b/clang/test/SemaHLSL/Resources/dynamic-resources-availability.hlsl @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -finclude-default-header -fhlsl-strict-availability \ +// RUN: -triple dxil-pc-shadermodel6.5-library -verify %s + +export void testUnavailable(unsigned Index) { + + // expected-error@+2 {{'ResourceDescriptorHeap' is only available on Shader Model 6.6 or newer}} + // expected-note@hlsl/hlsl_resources.h:* {{'ResourceDescriptorHeap' has been marked as being introduced in Shader Model 6.6 here, but the deployment target is Shader Model 6.5}} + RWBuffer<int> Buffer = ResourceDescriptorHeap[Index]; + + // expected-error@+2 {{'SamplerDescriptorHeap' is only available on Shader Model 6.6 or newer}} + // expected-note@hlsl/hlsl_resources.h:* {{'SamplerDescriptorHeap' has been marked as being introduced in Shader Model 6.6 here, but the deployment target is Shader Model 6.5}} + SamplerState Sampler = SamplerDescriptorHeap[Index]; +} diff --git a/clang/test/SemaHLSL/Resources/dynamic-resources.hlsl b/clang/test/SemaHLSL/Resources/dynamic-resources.hlsl new file mode 100644 index 0000000000000..f3300de0f7ce5 --- /dev/null +++ b/clang/test/SemaHLSL/Resources/dynamic-resources.hlsl @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library -verify %s + +void useBuffer(RWBuffer<int> Buffer) {} +void useSampler(SamplerState Sampler) {} + +export void test(unsigned Index) { + + // valid + RWBuffer<int> Buf1 = ResourceDescriptorHeap[Index]; + Buf1 = ResourceDescriptorHeap[Index + 1]; + useBuffer(ResourceDescriptorHeap[Index + 2]); + + // valid + SamplerState Sampler = SamplerDescriptorHeap[Index]; + Sampler = SamplerDescriptorHeap[Index + 1]; + useSampler(SamplerDescriptorHeap[Index + 2]); + + // expected-error@+3 {{no viable conversion from '__hlsl_heap_sampler_info' to 'RWBuffer<int>'}} + // expected-note@*:* {{candidate constructor not viable: no known conversion from '__hlsl_heap_sampler_info' to 'const hlsl::RWBuffer<int> &' for 1st argument}} + // expected-note@*:* {{candidate constructor not viable: no known conversion from '__hlsl_heap_sampler_info' to 'hlsl::__hlsl_heap_resource_info' for 1st argument}} + RWBuffer<int> Buf2 = SamplerDescriptorHeap[Index]; + + // expected-error@+3 {{no viable conversion from '__hlsl_heap_resource_info' to 'SamplerState'}} + // expected-note@*:* {{candidate constructor not viable: no known conversion from '__hlsl_heap_resource_info' to 'const hlsl::SamplerState &' for 1st argument}} + // expected-note@*:* {{candidate constructor not viable: no known conversion from '__hlsl_heap_resource_info' to 'hlsl::__hlsl_heap_sampler_info' for 1st argument}} + SamplerState Sampler2 = ResourceDescriptorHeap[Index]; + + // expected-error@+2 {{no viable overloaded '='}} + // expected-note@*:* {{candidate function not viable: no known conversion from '__hlsl_heap_sampler_info' to 'RWBuffer<int>' for 1st argument}} + Buf2 = SamplerDescriptorHeap[Index]; + + // expected-error@+2 {{no viable overloaded '='}} + // expected-note@*:* {{candidate function not viable: no known conversion from '__hlsl_heap_resource_info' to 'SamplerState' for 1st argument}} + Sampler2 = ResourceDescriptorHeap[Index]; + + // expected-error@+2 {{no matching function for call to 'useBuffer'}} + // expected-note@*:* {{candidate function not viable: no known conversion from '__hlsl_heap_sampler_info' to 'const hlsl::RWBuffer<int>' for 1st argument}} + useBuffer(SamplerDescriptorHeap[Index]); + + // expected-error@+2 {{no matching function for call to 'useSampler'}} + // expected-note@*:* {{candidate function not viable: no known conversion from '__hlsl_heap_resource_info' to 'const hlsl::SamplerState' for 1st argument}} + useSampler(ResourceDescriptorHeap[Index]); + + // expected-error@+1 {{no member named 'Load'}} + ResourceDescriptorHeap[Index].Load(0); + + // expected-error@+1 {{no member named 'Sample'}} + SamplerDescriptorHeap[Index].Sample(0); + +} diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index 86b49a8ee446a..28b75badee306 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -207,6 +207,15 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty] [llvm_any_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrConvergent]>; + def int_spv_resource_handlefromheap + : DefaultAttrsIntrinsic<[llvm_any_ty], + [llvm_i32_ty], + [IntrNoMem]>; + def int_spv_resource_counterhandlefromheap + : DefaultAttrsIntrinsic<[llvm_any_ty], + [llvm_any_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent]>; + def int_spv_firstbituhigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>; def int_spv_firstbitshigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>; def int_spv_firstbitlow : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>; >From 3d582681329f0d11b669470533f92e5e1875cf14 Mon Sep 17 00:00:00 2001 From: Helena Kotas <[email protected]> Date: Thu, 10 Sep 2026 22:56:41 -0700 Subject: [PATCH 2/2] Remove heap index argument from llvm.spv.resource.counterhandlefromheap The index is not needed - it is copied from the main handle initialization call. --- clang/include/clang/Basic/Builtins.td | 2 +- clang/lib/CodeGen/CGHLSLBuiltins.cpp | 3 +-- clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 3 +-- clang/lib/Sema/SemaHLSL.cpp | 6 ++---- clang/test/AST/HLSL/StructuredBuffers-AST.hlsl | 4 +--- clang/test/CodeGenHLSL/resources/dynamic-resources.hlsl | 2 +- llvm/include/llvm/IR/IntrinsicsSPIRV.td | 2 +- 7 files changed, 8 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 2b33b4a8541b3..8b15aecbfde92 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5440,7 +5440,7 @@ def HLSLResourceHandleFromHeap : LangBuiltin<"HLSL_LANG"> { def HLSLResourceCounterHandleFromHeap : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_resource_counterhandlefromheap"]; let Attributes = [NoThrow]; - let Prototype = "__hlsl_resource_t(__hlsl_resource_t, uint32_t)"; + let Prototype = "__hlsl_resource_t(__hlsl_resource_t)"; } def HLSLResourceNonUniformIndex : LangBuiltin<"HLSL_LANG"> { diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 42c107405dff3..e4f5ada9a0aef 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -1077,10 +1077,9 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, return MainHandle; llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType()); - Value *IndexOp = EmitScalarExpr(E->getArg(1)); llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::spv_resource_counterhandlefromheap; - SmallVector<Value *> Args{MainHandle, IndexOp}; + SmallVector<Value *> Args{MainHandle}; return EmitIntrinsicCall(IntrinsicID, {HandleTy, MainHandle->getType()}, Args); } diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 15f78eadad4e2..a5e56154984eb 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -1246,8 +1246,7 @@ BuiltinTypeDeclBuilder::addHeapResourceInfoConstructor(bool HasCounter) { if (HasCounter) { QualType CounterHandleType = getResourceCounterHandleField()->getType(); MB.callBuiltin("__builtin_hlsl_resource_counterhandlefromheap", - CounterHandleType, PH::Handle, - MB.createMemberExpr(PH::_0, IndexField)) + CounterHandleType, PH::Handle) .assign(PH::CounterHandle, PH::LastStmt); } diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 7c64266d855de..2d03487e99db6 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -4418,10 +4418,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { break; } case Builtin::BI__builtin_hlsl_resource_counterhandlefromheap: { - if (SemaRef.checkArgCount(TheCall, 2) || - CheckResourceHandle(&SemaRef, TheCall, 0) || - CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), - SemaRef.getASTContext().UnsignedIntTy)) + if (SemaRef.checkArgCount(TheCall, 1) || + CheckResourceHandle(&SemaRef, TheCall, 0)) return true; // Update return type to be the attributed resource type from arg0 // with added IsCounter flag. diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl index eb858cd51cdb6..c86a4115f412c 100644 --- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl @@ -159,11 +159,9 @@ RESOURCE<float> Buffer; // CHECK-COUNTER-HANDLE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this // CHECK-COUNTER-HANDLE-NEXT: CStyleCastExpr {{.*}} '__hlsl_resource_t // CHECK-COUNTER-HANDLE-NEXT: CallExpr {{.*}} '<dependent type>' -// CHECK-COUNTER-HANDLE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_counterhandlefromheap' '__hlsl_resource_t (__hlsl_resource_t, unsigned int) noexcept' +// CHECK-COUNTER-HANDLE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_counterhandlefromheap' '__hlsl_resource_t (__hlsl_resource_t) noexcept' // CHECK-COUNTER-HANDLE-NEXT: MemberExpr {{.*}} lvalue .__handle // CHECK-COUNTER-HANDLE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this -// CHECK-COUNTER-HANDLE-NEXT: MemberExpr {{.*}} 'unsigned int' lvalue .Index -// CHECK-COUNTER-HANDLE-NEXT: DeclRefExpr {{.*}} 'hlsl::__hlsl_heap_resource_info' lvalue ParmVar {{.*}} 'HeapResInfo' 'hlsl::__hlsl_heap_resource_info' // CHECK-NEXT: AlwaysInlineAttr // Static __createFromBinding method diff --git a/clang/test/CodeGenHLSL/resources/dynamic-resources.hlsl b/clang/test/CodeGenHLSL/resources/dynamic-resources.hlsl index 02d641fdeef5f..39cf212cee889 100644 --- a/clang/test/CodeGenHLSL/resources/dynamic-resources.hlsl +++ b/clang/test/CodeGenHLSL/resources/dynamic-resources.hlsl @@ -106,4 +106,4 @@ export void testCounterBuffer(unsigned Index) { // SPV-DAG: call target("spirv.VulkanBuffer", %S, 2, 0) @llvm.spv.resource.handlefromheap{{.*}}(i32 %{{.*}}) // SPV-DAG: call target("spirv.Sampler") @llvm.spv.resource.handlefromheap{{.*}}(i32 %{{.*}}) // SPV-DAG: call target("spirv.VulkanBuffer", [0 x i32], 12, 1) @llvm.spv.resource.handlefromheap{{.*}}(i32 %{{.*}}) -// SPV-DAG: call target("spirv.VulkanBuffer", i32, 12, 1) @llvm.spv.resource.counterhandlefromheap{{.*}}(target("spirv.VulkanBuffer", [0 x i32], 12, 1) %{{.*}}, i32 %{{.*}}) [ "convergencectrl"(token %{{.*}}) ] +// SPV-DAG: call target("spirv.VulkanBuffer", i32, 12, 1) @llvm.spv.resource.counterhandlefromheap{{.*}}(target("spirv.VulkanBuffer", [0 x i32], 12, 1) %{{.*}}) [ "convergencectrl"(token %{{.*}}) ] diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index 28b75badee306..3f6eba6082152 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -213,7 +213,7 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty] [IntrNoMem]>; def int_spv_resource_counterhandlefromheap : DefaultAttrsIntrinsic<[llvm_any_ty], - [llvm_any_ty, llvm_i32_ty], + [llvm_any_ty], [IntrNoMem, IntrConvergent]>; def int_spv_firstbituhigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
