Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7a0d3ca
[HLSL] Reorder the arguments of handle initialization builtins
hekota Aug 28, 2025
dcbbda4
[HLSL] Add static methods for resource initialization and a construct…
hekota Aug 28, 2025
02342c9
[HLSL] Use static create methods to initialize individual resources
hekota Sep 2, 2025
b13a530
cleanup
hekota Sep 3, 2025
a0cfc72
Merge branch 'main' of https://github.com/llvm/llvm-project into res-…
hekota Sep 3, 2025
1e6f4de
Merge branch 'users/hekota/pr155861-res-create-0-reorder-builtin-args…
hekota Sep 3, 2025
dfc07bd
Remove handle constructor, update create methods body and expected AS…
hekota Sep 4, 2025
a41cf8a
Merge branch 'main' of https://github.com/llvm/llvm-project into res-…
hekota Sep 4, 2025
e7641e1
cleanup
hekota Sep 4, 2025
6028194
clang-format
hekota Sep 4, 2025
ea93f39
Merge branch 'users/hekota/pr155866-res-create-1-add-methods' into re…
hekota Sep 4, 2025
e7d6ee6
Update tests after create methods body change
hekota Sep 4, 2025
84883bc
Merge branch 'main' of https://github.com/llvm/llvm-project into res-…
hekota Sep 4, 2025
7782eea
Update tests to use llvm-cxxfilt to have unmangled names in the basel…
hekota Sep 4, 2025
f64525e
Merge branch 'users/hekota/pr155866-res-create-1-add-methods' of http…
hekota Sep 4, 2025
dfa4144
Merge branch 'main' of https://github.com/llvm/llvm-project into res-…
hekota Sep 10, 2025
c7b35b9
update PR after merge from main that introduced explicit copy constru…
hekota Sep 11, 2025
b487a54
more cleanup after merge
hekota Sep 12, 2025
cdc85ca
clang-format
hekota Sep 12, 2025
ce719b2
code review feedback - add arg comments, use Sema for name lookup
hekota Sep 16, 2025
b53d261
code review feedback - add comment
hekota Sep 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
Expand Down Expand Up @@ -48,6 +49,14 @@ static FunctionDecl *lookupBuiltinFunction(Sema &S, StringRef Name) {
"Since this is a builtin it should always resolve!");
return cast<FunctionDecl>(R.getFoundDecl());
}

CXXConstructorDecl *lookupCopyConstructor(QualType ResTy) {
assert(ResTy->isRecordType() && "not a CXXRecord type");
for (auto *CD : ResTy->getAsCXXRecordDecl()->ctors())
if (CD->isCopyConstructor())
return CD;
return nullptr;
}
} // namespace

// Builder for template arguments of builtin types. Used internally
Expand Down Expand Up @@ -580,6 +589,23 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnValue(T ReturnValue) {

Expr *ReturnValueExpr = convertPlaceholder(ReturnValue);
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();

QualType Ty = ReturnValueExpr->getType();
if (Ty->isRecordType()) {
// For record types, create a call to copy constructor to ensure proper copy
// semantics.
auto *ICE =
ImplicitCastExpr::Create(AST, Ty.withConst(), CK_NoOp, ReturnValueExpr,
nullptr, VK_XValue, FPOptionsOverride());
CXXConstructorDecl *CD = lookupCopyConstructor(Ty);
assert(CD && "no copy constructor found");
ReturnValueExpr = CXXConstructExpr::Create(
AST, Ty, SourceLocation(), CD, /*Elidable=*/false, {ICE},
/*HadMultipleCandidates=*/false, /*ListInitialization=*/false,
/*StdInitListInitialization=*/false,
/*ZeroInitListInitialization=*/false, CXXConstructionKind::Complete,
SourceRange());
}
StmtsList.push_back(
ReturnStmt::Create(AST, SourceLocation(), ReturnValueExpr, nullptr));
return *this;
Expand Down
134 changes: 109 additions & 25 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,15 @@ struct PerVisibilityBindingChecker {
}
};

static CXXMethodDecl *lookupMethod(Sema &S, CXXRecordDecl *RecordDecl,
StringRef Name, SourceLocation Loc) {
DeclarationName DeclName(&S.getASTContext().Idents.get(Name));
LookupResult Result(S, DeclName, Loc, Sema::LookupMemberName);
if (!S.LookupQualifiedName(Result, static_cast<DeclContext *>(RecordDecl)))
return nullptr;
return cast<CXXMethodDecl>(Result.getFoundDecl());
}

} // end anonymous namespace

bool SemaHLSL::handleRootSignatureElements(
Expand Down Expand Up @@ -3738,26 +3747,6 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
deduceAddressSpace(VD);
}

static bool initVarDeclWithCtor(Sema &S, VarDecl *VD,
MutableArrayRef<Expr *> Args) {
InitializedEntity Entity = InitializedEntity::InitializeVariable(VD);
InitializationKind Kind = InitializationKind::CreateDirect(
VD->getLocation(), SourceLocation(), SourceLocation());

InitializationSequence InitSeq(S, Entity, Kind, Args);
if (InitSeq.Failed())
return false;

ExprResult Init = InitSeq.Perform(S, Entity, Kind, Args);
if (!Init.get())
return false;

VD->setInit(S.MaybeCreateExprWithCleanups(Init.get()));
VD->setInitStyle(VarDecl::CallInit);
S.CheckCompleteVariableDeclaration(VD);
return true;
}

void SemaHLSL::createResourceRecordCtorArgs(
const Type *ResourceTy, StringRef VarName, HLSLResourceBindingAttr *RBA,
HLSLVkBindingAttr *VkBinding, uint32_t ArrayIndex,
Expand Down Expand Up @@ -3808,11 +3797,106 @@ void SemaHLSL::createResourceRecordCtorArgs(
}

bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
SmallVector<Expr *> Args;
createResourceRecordCtorArgs(VD->getType().getTypePtr(), VD->getName(),
VD->getAttr<HLSLResourceBindingAttr>(),
VD->getAttr<HLSLVkBindingAttr>(), 0, Args);
return initVarDeclWithCtor(SemaRef, VD, Args);
assert(VD->getType()->isHLSLResourceRecord() &&
"expected resource record type");

ASTContext &AST = SemaRef.getASTContext();
uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
uint64_t IntTySize = AST.getTypeSize(AST.IntTy);

// Gather resource binding information from attributes.
HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
HLSLVkBindingAttr *VkBinding = VD->getAttr<HLSLVkBindingAttr>();
std::optional<uint32_t> RegisterSlot;
uint32_t SpaceNo = 0;
if (VkBinding) {
RegisterSlot = VkBinding->getBinding();
SpaceNo = VkBinding->getSet();
} else if (RBA) {
if (RBA->hasRegisterSlot())
RegisterSlot = RBA->getSlotNumber();
SpaceNo = RBA->getSpaceNumber();
}

// Find correct initialization method and create its arguments.
QualType ResourceTy = VD->getType();
CXXRecordDecl *ResourceDecl = ResourceTy->getAsCXXRecordDecl();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did look up the call tree here to be sure, but it does seem like we're guaranteed that ResourceTy will be complete by the time we get here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, in ActOnVariableDeclarator we call Sema.RequireCompleteType for all declarations at global scope, and that happens before the initialization here that is invokend from ActOnUninitializedVarDecl.

CXXMethodDecl *CreateMethod = nullptr;
llvm::SmallVector<Expr *> Args;

if (RegisterSlot.has_value()) {
// The resource has explicit binding.
CreateMethod = lookupMethod(SemaRef, ResourceDecl, "__createFromBinding",
VD->getLocation());
IntegerLiteral *RegSlot = IntegerLiteral::Create(
AST, llvm::APInt(UIntTySize, RegisterSlot.value()), AST.UnsignedIntTy,
SourceLocation());
Args.push_back(RegSlot);
} else {
// The resource has implicit binding.
CreateMethod =
lookupMethod(SemaRef, ResourceDecl, "__createFromImplicitBinding",
VD->getLocation());
uint32_t OrderID = (RBA && RBA->hasImplicitBindingOrderID())
? RBA->getImplicitBindingOrderID()
: getNextImplicitBindingOrderID();
IntegerLiteral *OrderId =
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, OrderID),
AST.UnsignedIntTy, SourceLocation());
Args.push_back(OrderId);
}

if (!CreateMethod)
// This can happen if someone creates a struct that looks like an HLSL
// resource record but does not have the required static create method.
// No binding will be generated for it.
return false;

IntegerLiteral *Space =
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, SpaceNo),
AST.UnsignedIntTy, SourceLocation());
Args.push_back(Space);

IntegerLiteral *RangeSize = IntegerLiteral::Create(
AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation());
Args.push_back(RangeSize);

IntegerLiteral *Index = IntegerLiteral::Create(
AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation());
Args.push_back(Index);

StringRef VarName = VD->getName();
StringLiteral *Name = StringLiteral::Create(
AST, VarName, StringLiteralKind::Ordinary, false,
AST.getStringLiteralArrayType(AST.CharTy.withConst(), VarName.size()),
SourceLocation());
ImplicitCastExpr *NameCast = ImplicitCastExpr::Create(
AST, AST.getPointerType(AST.CharTy.withConst()), CK_ArrayToPointerDecay,
Name, nullptr, VK_PRValue, FPOptionsOverride());
Args.push_back(NameCast);

// Make sure the create method template is instantiated and emitted.
if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
true);

// Create CallExpr with a call to the static method and set it as the decl
// initialization.
DeclRefExpr *DRE = DeclRefExpr::Create(
AST, NestedNameSpecifierLoc(), SourceLocation(), CreateMethod, false,
CreateMethod->getNameInfo(), CreateMethod->getType(), VK_PRValue);

auto *ImpCast = ImplicitCastExpr::Create(
AST, AST.getPointerType(CreateMethod->getType()),
CK_FunctionToPointerDecay, DRE, nullptr, VK_PRValue, FPOptionsOverride());

CallExpr *InitExpr =
CallExpr::Create(AST, ImpCast, Args, ResourceTy, VK_PRValue,
SourceLocation(), FPOptionsOverride());
VD->setInit(InitExpr);
VD->setInitStyle(VarDecl::CallInit);
SemaRef.CheckCompleteVariableDeclaration(VD);
return true;
}

bool SemaHLSL::initGlobalResourceArrayDecl(VarDecl *VD) {
Expand Down
6 changes: 5 additions & 1 deletion clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ RESOURCE Buffer;

#endif

// CHECK: CXXRecordDecl {{.*}} implicit referenced <undeserialized declarations> class [[RESOURCE]] definition
// CHECK: CXXRecordDecl {{.*}} implicit referenced class [[RESOURCE]] definition
// CHECK: FinalAttr {{.*}} Implicit final
// CHECK-NEXT: FieldDecl {{.*}} implicit __handle '__hlsl_resource_t
// CHECK-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
Expand Down Expand Up @@ -107,6 +107,8 @@ RESOURCE Buffer;
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'const char *' ParmVar {{.*}} 'name' 'const char *'
// CHECK-NEXT: ReturnStmt
// CHECK-NEXT: CXXConstructExpr {{.*}} 'hlsl::[[RESOURCE]]' 'void (const hlsl::[[RESOURCE]] &)'
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const hlsl::[[RESOURCE]]' xvalue <NoOp>
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline

Expand Down Expand Up @@ -135,6 +137,8 @@ RESOURCE Buffer;
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'const char *' ParmVar {{.*}} 'name' 'const char *'
// CHECK-NEXT: ReturnStmt
// CHECK-NEXT: CXXConstructExpr {{.*}} 'hlsl::[[RESOURCE]]' 'void (const hlsl::[[RESOURCE]] &)'
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const hlsl::[[RESOURCE]]' xvalue <NoOp>
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline

Expand Down
48 changes: 37 additions & 11 deletions clang/test/AST/HLSL/vk_binding_attr.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-library -finclude-default-header -ast-dump -o - %s | FileCheck %s -check-prefixes=DXIL,CHECK

// CHECK: VarDecl {{.*}} Buf 'StructuredBuffer<float>':'hlsl::StructuredBuffer<float>'
// SPV-NEXT: CXXConstructExpr {{.*}} 'StructuredBuffer<float>':'hlsl::StructuredBuffer<float>' 'void (unsigned int, unsigned int, int, unsigned int, const char *)'
// CHECK-NEXT: CallExpr {{.*}} 'StructuredBuffer<float>':'hlsl::StructuredBuffer<float>'
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::StructuredBuffer<float> (*)(unsigned int, unsigned int, int, unsigned int, const char *)' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::StructuredBuffer<float> (unsigned int, unsigned int, int, unsigned int, const char *)'
// CHECK-NEXT-SAME: CXXMethod {{.*}} '__createFromBinding' 'hlsl::StructuredBuffer<float> (unsigned int, unsigned int, int, unsigned int, const char *)'
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 23
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 102
// DXIL-NEXT: CXXConstructExpr {{.*}} 'StructuredBuffer<float>':'hlsl::StructuredBuffer<float>' 'void (unsigned int, int, unsigned int, unsigned int, const char *)'
// DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
// DXIL-NEXT: IntegerLiteral {{.*}} 'int' 1
// DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
// SPV: HLSLVkBindingAttr {{.*}} 23 102
// DXIL-NOT: HLSLVkBindingAttr
[[vk::binding(23, 102)]] StructuredBuffer<float> Buf;

// CHECK: VarDecl {{.*}} Buf2 'StructuredBuffer<float>':'hlsl::StructuredBuffer<float>'
// CHECK-NEXT: CXXConstructExpr {{.*}} 'StructuredBuffer<float>':'hlsl::StructuredBuffer<float>' 'void (unsigned int, unsigned int, int, unsigned int, const char *)'
// CHECK-NEXT: CallExpr {{.*}} 'StructuredBuffer<float>':'hlsl::StructuredBuffer<float>'
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::StructuredBuffer<float> (*)(unsigned int, unsigned int, int, unsigned int, const char *)' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::StructuredBuffer<float> (unsigned int, unsigned int, int, unsigned int, const char *)'
// CHECK-NEXT-SAME: CXXMethod {{.*}} '__createFromBinding' 'hlsl::StructuredBuffer<float> (unsigned int, unsigned int, int, unsigned int, const char *)'
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 14
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1
// DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 23
Expand All @@ -24,7 +29,10 @@
[[vk::binding(14, 1)]] StructuredBuffer<float> Buf2 : register(t23, space102);

// CHECK: VarDecl {{.*}} Buf3 'StructuredBuffer<float>':'hlsl::StructuredBuffer<float>'
// CHECK-NEXT: CXXConstructExpr {{.*}} 'StructuredBuffer<float>':'hlsl::StructuredBuffer<float>' 'void (unsigned int, unsigned int, int, unsigned int, const char *)'
// CHECK-NEXT: CallExpr {{.*}} 'StructuredBuffer<float>':'hlsl::StructuredBuffer<float>'
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::StructuredBuffer<float> (*)(unsigned int, unsigned int, int, unsigned int, const char *)' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::StructuredBuffer<float> (unsigned int, unsigned int, int, unsigned int, const char *)'
// CHECK-NEXT-SAME: CXXMethod {{.*}} '__createFromBinding' 'hlsl::StructuredBuffer<float> (unsigned int, unsigned int, int, unsigned int, const char *)'
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 14
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
// DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 23
Expand All @@ -43,28 +51,46 @@
}

// CHECK: VarDecl {{.*}} Buf4 'Buffer<int>':'hlsl::Buffer<int>'
// SPV-NEXT: CXXConstructExpr {{.*}} 'Buffer<int>':'hlsl::Buffer<int>' 'void (unsigned int, unsigned int, int, unsigned int, const char *)'
// CHECK-NEXT: CallExpr {{.*}} 'Buffer<int>':'hlsl::Buffer<int>'
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::Buffer<int> (*)(unsigned int, unsigned int, int, unsigned int, const char *)' <FunctionToPointerDecay>
// SPV-NEXT: DeclRefExpr {{.*}} 'hlsl::Buffer<int> (unsigned int, unsigned int, int, unsigned int, const char *)'
// SPV-NEXT-SAME: CXXMethod {{.*}} '__createFromBinding' 'Buffer<int> (unsigned int, unsigned int, int, unsigned int, const char *)'
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 24
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 103
// DXL-NEXT: CXXConstructExpr {{.*}} 'Buffer<int>':'hlsl::Buffer<int>' 'void (unsigned int, int, unsigned int, unsigned int, const char *)'
// DXIL-NEXT: DeclRefExpr {{.*}} 'hlsl::Buffer<int> (unsigned int, unsigned int, int, unsigned int, const char *)'
// DXIL-NEXT-SAME: CXXMethod {{.*}} '__createFromImplicitBinding' 'Buffer<int> (unsigned int, unsigned int, int, unsigned int, const char *)'
// DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 2
// DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
// SPV: HLSLVkBindingAttr {{.*}} 24 103
// DXIL-NOT: HLSLVkBindingAttr
[[vk::binding(24, 103)]] Buffer<int> Buf4;

// CHECK: VarDecl {{.*}} Buf5 'RWBuffer<int2>':'hlsl::RWBuffer<vector<int, 2>>'
// SPV-NEXT: CXXConstructExpr {{.*}} 'RWBuffer<int2>':'hlsl::RWBuffer<vector<int, 2>>' 'void (unsigned int, unsigned int, int, unsigned int, const char *)'
// CHECK-NEXT: CallExpr {{.*}} 'RWBuffer<int2>':'hlsl::RWBuffer<vector<int, 2>>'
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::RWBuffer<vector<int, 2>> (*)(unsigned int, unsigned int, int, unsigned int, const char *)' <FunctionToPointerDecay>
// SPV-NEXT: DeclRefExpr {{.*}} 'hlsl::RWBuffer<vector<int, 2>> (unsigned int, unsigned int, int, unsigned int, const char *)'
// SPV-NEXT-SAME: CXXMethod {{.*}} '__createFromBinding' 'Buffer<int2> (unsigned int, unsigned int, int, unsigned int, const char *)'
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 25
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 104
// DXL-NEXT: CXXConstructExpr {{.*}} 'Buffer<int>':'hlsl::Buffer<int>' 'void (unsigned int, int, unsigned int, unsigned int, const char *)'
// DXIL-NEXT: DeclRefExpr {{.*}} 'hlsl::RWBuffer<vector<int, 2>> (unsigned int, unsigned int, int, unsigned int, const char *)'
// DXIL-NEXT-SAME: CXXMethod {{.*}} '__createFromImplicitBinding' 'Buffer<int2> (unsigned int, unsigned int, int, unsigned int, const char *)'
// DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 3
// DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
// SPV: HLSLVkBindingAttr {{.*}} 25 104
// DXIL-NOT: HLSLVkBindingAttr
[[vk::binding(25, 104)]] RWBuffer<int2> Buf5;

// CHECK: VarDecl {{.*}} Buf6 'RWStructuredBuffer<int>':'hlsl::RWStructuredBuffer<int>'
// SPV-NEXT: CXXConstructExpr {{.*}} 'RWStructuredBuffer<int>':'hlsl::RWStructuredBuffer<int>' 'void (unsigned int, unsigned int, int, unsigned int, const char *)'
// CHECK-NEXT: CallExpr {{.*}} 'RWStructuredBuffer<int>':'hlsl::RWStructuredBuffer<int>'
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::RWStructuredBuffer<int> (*)(unsigned int, unsigned int, int, unsigned int, const char *)' <FunctionToPointerDecay>
// SPV-NEXT: DeclRefExpr {{.*}} 'hlsl::RWStructuredBuffer<int> (unsigned int, unsigned int, int, unsigned int, const char *)'
// SPV-NEXT-SAME: CXXMethod {{.*}} '__createFromBinding' 'hlsl::RWStructuredBuffer<int> (unsigned int, unsigned int, int, unsigned int, const char *)'
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 26
// SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 105
// DXL-NEXT: CXXConstructExpr {{.*}} 'Buffer<int>':'hlsl::Buffer<int>' 'void (unsigned int, int, unsigned int, unsigned int, const char *)'
// DXIL-NEXT: DeclRefExpr {{.*}} 'hlsl::RWStructuredBuffer<int> (unsigned int, unsigned int, int, unsigned int, const char *)'
// DXIL-NEXT-SAME: CXXMethod {{.*}} '__createFromBinding' 'hlsl::RWStructuredBuffer<int> (unsigned int, unsigned int, int, unsigned int, const char *)'
// DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 4
// DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
// SPV: HLSLVkBindingAttr {{.*}} 26 105
// DXIL-NOT: HLSLVkBindingAttr
[[vk::binding(26, 105)]] RWStructuredBuffer<int> Buf6;
Loading