From 85001dcbc184491dfb24e9d2a39df46fd4c9a363 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Wed, 9 Apr 2025 18:17:26 -0700 Subject: [PATCH 01/13] Initialize resources by constructors - add resource record constructor with explicit binding - completes implementation of default resource constructor - removes resource initialization for Codegen for resource records - cbuffer still needs to be initialized in Codegen because it does not have a resource class type --- clang/include/clang/Basic/Builtins.td | 12 ++ clang/include/clang/Sema/SemaHLSL.h | 1 + clang/lib/CodeGen/CGHLSLBuiltins.cpp | 18 ++ clang/lib/CodeGen/CGHLSLRuntime.cpp | 78 ++++----- clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 36 +++- clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 1 + clang/lib/Sema/HLSLExternalSemaSource.cpp | 3 +- clang/lib/Sema/SemaDecl.cpp | 6 +- clang/lib/Sema/SemaHLSL.cpp | 89 ++++++++++ .../test/AST/HLSL/StructuredBuffers-AST.hlsl | 60 ++++++- clang/test/AST/HLSL/TypedBuffers-AST.hlsl | 5 +- .../ByteAddressBuffers-constructors.hlsl | 129 +++++++++++--- .../builtins/RWBuffer-constructor-opt.hlsl | 2 +- .../builtins/RWBuffer-constructor.hlsl | 117 ++++++++++++- .../StructuredBuffers-constructors.hlsl | 159 ++++++++++++------ clang/test/CodeGenHLSL/cbuffer.hlsl | 8 +- .../CodeGenHLSL/cbuffer_with_packoffset.hlsl | 4 +- clang/test/CodeGenHLSL/resource-bindings.hlsl | 52 +++--- .../hlsl_resource_handle_attrs.hlsl | 4 +- 19 files changed, 610 insertions(+), 174 deletions(-) diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 868e5b92acdc9b..5e92715f59e575 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4789,6 +4789,18 @@ def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLResourceCreatePoisonHandle : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_resource_createpoisonhandle"]; + let Attributes = [NoThrow]; + let Prototype = "void(...)"; +} + +def HLSLResourceCreateHandleFromBinding : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_resource_createhandlefrombinding"]; + let Attributes = [NoThrow]; + let Prototype = "void(...)"; +} + def HLSLAll : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_all"]; let Attributes = [NoThrow, Const]; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index f333fe30e8da02..a913d6cce62bd9 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -105,6 +105,7 @@ class SemaHLSL : public SemaBase { HLSLParamModifierAttr::Spelling Spelling); void ActOnTopLevelFunction(FunctionDecl *FD); void ActOnVariableDeclarator(VarDecl *VD); + bool ActOnUninitializedVarDecl(VarDecl *D); void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU); void CheckEntryPoint(FunctionDecl *FD); void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param, diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 99c62808c323d4..c652f435781f0a 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -287,6 +287,24 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(), ArrayRef{HandleOp, IndexOp}); } + case Builtin::BI__builtin_hlsl_resource_createpoisonhandle: { + llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType()); + return llvm::PoisonValue::get(HandleTy); + } + case Builtin::BI__builtin_hlsl_resource_createhandlefrombinding: { + llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType()); + Value *SpaceNoOp = EmitScalarExpr(E->getArg(1)); + Value *RegisterNoOp = EmitScalarExpr(E->getArg(2)); + Value *RangeOp = EmitScalarExpr(E->getArg(3)); + Value *IndexOp = EmitScalarExpr(E->getArg(4)); + // FIXME: NonUniformResourceIndex bit is not yet implemented + Value *NonUniform = + llvm::ConstantInt::get(llvm::Type::getInt1Ty(getLLVMContext()), false); + return Builder.CreateIntrinsic( + HandleTy, CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(), + ArrayRef{SpaceNoOp, RegisterNoOp, RangeOp, IndexOp, + NonUniform}); + } case Builtin::BI__builtin_hlsl_all: { Value *Op0 = EmitScalarExpr(E->getArg(0)); return Builder.CreateIntrinsic( diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 3b1810b62a2cd0..c7fb6b57c47dca 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -41,8 +41,9 @@ using namespace llvm; using llvm::hlsl::CBufferRowSizeInBytes; -static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV, - unsigned Slot, unsigned Space); +static void initializeBufferFromBinding(CodeGenModule &CGM, + llvm::GlobalVariable *GV, unsigned Slot, + unsigned Space); namespace { @@ -255,14 +256,14 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) { // Add globals for constant buffer elements and create metadata nodes emitBufferGlobalsAndMetadata(BufDecl, BufGV); - // Resource initialization + // Initialize cbuffer from binding (implicit or explicit) const HLSLResourceBindingAttr *RBA = BufDecl->getAttr(); // FIXME: handle implicit binding if no binding attribute is found // (llvm/llvm-project#110722) if (RBA) - createResourceInitFn(CGM, BufGV, RBA->getSlotNumber(), - RBA->getSpaceNumber()); + initializeBufferFromBinding(CGM, BufGV, RBA->getSlotNumber(), + RBA->getSpaceNumber()); } llvm::TargetExtType * @@ -494,15 +495,15 @@ void CGHLSLRuntime::generateGlobalCtorDtorCalls() { } } -static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV, - unsigned Slot, unsigned Space) { - LLVMContext &Ctx = CGM.getLLVMContext(); - llvm::Type *Int1Ty = llvm::Type::getInt1Ty(Ctx); +static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV, + Intrinsic::ID IntrID, + ArrayRef Args) { + LLVMContext &Ctx = CGM.getLLVMContext(); llvm::Function *InitResFunc = llvm::Function::Create( llvm::FunctionType::get(CGM.VoidTy, false), llvm::GlobalValue::InternalLinkage, - ("_init_resource_" + GV->getName()).str(), CGM.getModule()); + ("_init_buffer_" + GV->getName()).str(), CGM.getModule()); InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline); llvm::BasicBlock *EntryBB = @@ -511,28 +512,12 @@ static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV, const DataLayout &DL = CGM.getModule().getDataLayout(); Builder.SetInsertPoint(EntryBB); - // Make sure the global variable is resource handle (cbuffer) or - // resource class (=class where the first element is a resource handle). + // Make sure the global variable is buffer resource handle llvm::Type *HandleTy = GV->getValueType(); - assert((HandleTy->isTargetExtTy() || - (HandleTy->isStructTy() && - HandleTy->getStructElementType(0)->isTargetExtTy())) && - "unexpected type of the global"); - if (!HandleTy->isTargetExtTy()) - HandleTy = HandleTy->getStructElementType(0); + assert(HandleTy->isTargetExtTy() && "unexpected type of the buffer global"); - llvm::Value *Args[] = { - llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */ - llvm::ConstantInt::get(CGM.IntTy, Slot), /* lower_bound */ - // FIXME: resource arrays are not yet implemented - llvm::ConstantInt::get(CGM.IntTy, 1), /* range_size */ - llvm::ConstantInt::get(CGM.IntTy, 0), /* index */ - // FIXME: NonUniformResourceIndex bit is not yet implemented - llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */ - }; llvm::Value *CreateHandle = Builder.CreateIntrinsic( - /*ReturnType=*/HandleTy, - CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(), Args, nullptr, + /*ReturnType=*/HandleTy, IntrID, Args, nullptr, Twine(GV->getName()).concat("_h")); llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0); @@ -543,26 +528,25 @@ static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV, CGM.AddCXXGlobalInit(InitResFunc); } -void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD, - llvm::GlobalVariable *GV) { - - // If the global variable has resource binding, create an init function - // for the resource - const HLSLResourceBindingAttr *RBA = VD->getAttr(); - if (!RBA) - // FIXME: collect unbound resources for implicit binding resolution later - // on? - return; - - if (!VD->getType().getTypePtr()->isHLSLResourceRecord()) - // FIXME: Only simple declarations of resources are supported for now. - // Arrays of resources or resources in user defined classes are - // not implemented yet. - return; - - createResourceInitFn(CGM, GV, RBA->getSlotNumber(), RBA->getSpaceNumber()); +static void initializeBufferFromBinding(CodeGenModule &CGM, + llvm::GlobalVariable *GV, unsigned Slot, + unsigned Space) { + llvm::Type *Int1Ty = llvm::Type::getInt1Ty(CGM.getLLVMContext()); + llvm::Value *Args[] = { + llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */ + llvm::ConstantInt::get(CGM.IntTy, Slot), /* lower_bound */ + llvm::ConstantInt::get(CGM.IntTy, 1), /* range_size */ + llvm::ConstantInt::get(CGM.IntTy, 0), /* index */ + llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */ + }; + initializeBuffer(CGM, GV, + CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(), + Args); } +void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD, + llvm::GlobalVariable *GV) {} + llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) { if (!CGM.shouldEmitConvergenceTokens()) return nullptr; diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 2d3e1088557ab8..4fd01404b012e1 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -400,6 +400,7 @@ void BuiltinTypeMethodBuilder::createDecl() { // create params & set them to the function prototype SmallVector ParmDecls; + unsigned CurScopeDepth = DeclBuilder.SemaRef.getCurScope()->getDepth(); auto FnProtoLoc = Method->getTypeSourceInfo()->getTypeLoc().getAs(); for (int I = 0, E = Params.size(); I != E; I++) { @@ -414,6 +415,7 @@ void BuiltinTypeMethodBuilder::createDecl() { HLSLParamModifierAttr::Create(AST, SourceRange(), MP.Modifier); Parm->addAttr(Mod); } + Parm->setScopeInfo(CurScopeDepth, I); ParmDecls.push_back(Parm); FnProtoLoc.setParam(I, Parm); } @@ -447,10 +449,14 @@ BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName, AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false, FD->getNameInfo(), AST.BuiltinFnTy, VK_PRValue); + auto *ImpCast = ImplicitCastExpr::Create( + AST, AST.getPointerType(FD->getType()), CK_BuiltinFnToFnPtr, DRE, nullptr, + VK_PRValue, FPOptionsOverride()); + if (ReturnType.isNull()) ReturnType = FD->getReturnType(); - Expr *Call = CallExpr::Create(AST, DRE, Args, ReturnType, VK_PRValue, + Expr *Call = CallExpr::Create(AST, ImpCast, Args, ReturnType, VK_PRValue, SourceLocation(), FPOptionsOverride()); StmtsList.push_back(Call); return *this; @@ -632,11 +638,33 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() { if (Record->isCompleteDefinition()) return *this; - // FIXME: initialize handle to poison value; this can be added after - // resource constructor from binding is implemented, otherwise the handle - // value will get overwritten. + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + QualType HandleType = getResourceHandleField()->getType(); return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy, false, true) + .callBuiltin("__builtin_hlsl_resource_createpoisonhandle", HandleType, + PH::Handle) + .assign(PH::Handle, PH::LastStmt) + .finalize(); +} + +BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addHandleConstructorFromBinding() { + if (Record->isCompleteDefinition()) + return *this; + + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + ASTContext &AST = SemaRef.getASTContext(); + QualType HandleType = getResourceHandleField()->getType(); + + return BuiltinTypeMethodBuilder(*this, "", AST.VoidTy, false, true) + .addParam("spaceNo", AST.UnsignedIntTy) + .addParam("registerNo", AST.UnsignedIntTy) + .addParam("range", AST.IntTy) + .addParam("index", AST.UnsignedIntTy) + .callBuiltin("__builtin_hlsl_resource_createhandlefrombinding", + HandleType, PH::Handle, PH::_0, PH::_1, PH::_2, PH::_3) + .assign(PH::Handle, PH::LastStmt) .finalize(); } diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h index dbf54dfd9ecd93..db617dc53c8991 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h @@ -78,6 +78,7 @@ class BuiltinTypeDeclBuilder { // Builtin types methods BuiltinTypeDeclBuilder &addDefaultHandleConstructor(); + BuiltinTypeDeclBuilder &addHandleConstructorFromBinding(); // Builtin types methods BuiltinTypeDeclBuilder &addLoadMethods(); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index f5477ac912693f..f09232a9db4dab 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -131,7 +131,8 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, bool RawBuffer) { return BuiltinTypeDeclBuilder(S, Decl) .addHandleMember(RC, IsROV, RawBuffer) - .addDefaultHandleConstructor(); + .addDefaultHandleConstructor() + .addHandleConstructorFromBinding(); } // This function is responsible for constructing the constraint expression for diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 540f5f23fe89a0..22699644c0a1ae 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14345,10 +14345,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { Var->getType().getAddressSpace() == LangAS::opencl_local) return; - // In HLSL, objects in the hlsl_constant address space are initialized - // externally, so don't synthesize an implicit initializer. - if (getLangOpts().HLSL && - Var->getType().getAddressSpace() == LangAS::hlsl_constant) + // Handle HLSL uninitialized decls + if (getLangOpts().HLSL && HLSL().ActOnUninitializedVarDecl(Var)) return; // C++03 [dcl.init]p9: diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index fe600386e6fa9b..fb786e14290200 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -32,6 +32,7 @@ #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Template.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" @@ -305,6 +306,10 @@ static bool isResourceRecordTypeOrArrayOf(const Type *Ty) { return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr; } +static bool isResourceRecordTypeOrArrayOf(VarDecl *VD) { + return isResourceRecordTypeOrArrayOf(VD->getType().getTypePtr()); +} + // Returns true if the type is a leaf element type that is not valid to be // included in HLSL Buffer, such as a resource class, empty struct, zero-sized // array, or a builtin intangible type. Returns false it is a valid leaf element @@ -2385,6 +2390,29 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { break; } + case Builtin::BI__builtin_hlsl_resource_createpoisonhandle: { + if (SemaRef.checkArgCount(TheCall, 1) || + CheckResourceHandle(&SemaRef, TheCall, 0)) + return true; + // use the type of the handle (arg0) as a return type + QualType ResourceTy = TheCall->getArg(0)->getType(); + TheCall->setType(ResourceTy); + break; + } + case Builtin::BI__builtin_hlsl_resource_createhandlefrombinding: { + ASTContext &AST = SemaRef.getASTContext(); + if (SemaRef.checkArgCount(TheCall, 5) || + CheckResourceHandle(&SemaRef, TheCall, 0) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.IntTy) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy)) + return true; + // use the type of the handle (arg0) as a return type + QualType ResourceTy = TheCall->getArg(0)->getType(); + TheCall->setType(ResourceTy); + break; + } case Builtin::BI__builtin_hlsl_and: case Builtin::BI__builtin_hlsl_or: { if (SemaRef.checkArgCount(TheCall, 2)) @@ -3179,6 +3207,67 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { } } +static bool initVarDeclWithConstructor(Sema &S, VarDecl *VD, + MutableArrayRef Args) { + InitializedEntity Entity = InitializedEntity::InitializeVariable(VD); + InitializationKind Kind = InitializationKind::CreateDirect( + VD->getLocation(), SourceLocation(), SourceLocation()); + + InitializationSequence InitSeq(S, Entity, Kind, Args); + 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; +} + +static bool initGlobalResourceDecl(Sema &S, VarDecl *VD) { + HLSLResourceBindingAttr *RBA = VD->getAttr(); + if (!RBA) + // FIXME: add support for implicit binding (llvm/llvm-project#110722) + return false; + + ASTContext &AST = S.getASTContext(); + uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy); + uint64_t IntTySize = AST.getTypeSize(AST.IntTy); + Expr *Args[] = { + IntegerLiteral::Create(AST, + llvm::APInt(UIntTySize, RBA->getSpaceNumber()), + AST.UnsignedIntTy, SourceLocation()), + IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, RBA->getSlotNumber()), + AST.UnsignedIntTy, SourceLocation()), + IntegerLiteral::Create(AST, llvm::APInt(IntTySize, 1), AST.IntTy, + SourceLocation()), + IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, + SourceLocation())}; + + return initVarDeclWithConstructor(S, VD, Args); +} + +// Returns true in the initialization has been handled; +// Return false to let Clang handle the default initializaton. +bool SemaHLSL::ActOnUninitializedVarDecl(VarDecl *VD) { + // Objects in the hlsl_constant address space are initialized + // externally, so don't synthesize an implicit initializer. + if (VD->getType().getAddressSpace() == LangAS::hlsl_constant) + return true; + + // Initialize resources + if (!isResourceRecordTypeOrArrayOf(VD)) + return false; + + // FIXME: We currectly support only simple resources - no arrays of resources + // or resources in user defined structs). + if (VD->getType()->isHLSLResourceRecord()) + return initGlobalResourceDecl(SemaRef, VD); + + return false; +} + // Walks though the global variable declaration, collects all resource binding // requirements and adds them to Bindings void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) { diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl index dcead068f481ea..a07613ca2c7294 100644 --- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl @@ -89,12 +89,51 @@ RESOURCE Buffer; // CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] +// Default constructor + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void ()' inline +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: BinaryOperator {{.*}} '=' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t +// CHECK-NEXT: ImplicitCastExpr {{.*}} +// CHECK-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_createpoisonhandle' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: AlwaysInlineAttr + +// Constructor from binding + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (unsigned int, unsigned int, int, unsigned int)' inline +// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} registerNo 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} range 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} index 'unsigned int' +// CHECK-NEXT: CompoundStmt {{.*}} +// CHECK-NEXT: BinaryOperator {{.*}} '=' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t +// CHECK-NEXT: ImplicitCastExpr {{.*}} +// CHECK-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_createhandlefrombinding' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'spaceNo' 'unsigned int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'registerNo' 'unsigned int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} 'range' 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int' +// CHECK-NEXT: AlwaysInlineAttr + +// Subsctript operators + // CHECK-SUBSCRIPT: CXXMethodDecl {{.*}} operator[] 'const element_type &(unsigned int) const' // CHECK-SUBSCRIPT-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' // CHECK-SUBSCRIPT-NEXT: CompoundStmt // CHECK-SUBSCRIPT-NEXT: ReturnStmt // CHECK-SUBSCRIPT-NEXT: UnaryOperator {{.*}} 'element_type' prefix '*' cannot overflow // CHECK-SUBSCRIPT-NEXT: CallExpr {{.*}} 'element_type *' +// CHECK-SUBSCRIPT-NEXT: ImplicitCastExpr {{.*}} // CHECK-SUBSCRIPT-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' // CHECK-SUBSCRIPT-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::resource_class( @@ -111,6 +150,7 @@ RESOURCE Buffer; // CHECK-SUBSCRIPT-NEXT: ReturnStmt // CHECK-SUBSCRIPT-NEXT: UnaryOperator {{.*}} 'element_type' prefix '*' cannot overflow // CHECK-SUBSCRIPT-NEXT: CallExpr {{.*}} 'element_type *' +// CHECK-SUBSCRIPT-NEXT: ImplicitCastExpr {{.*}} // CHECK-SUBSCRIPT-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' // CHECK-SUBSCRIPT-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::resource_class( @@ -124,12 +164,15 @@ RESOURCE Buffer; // CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'const element_type &(unsigned int) const' // CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'element_type &(unsigned int)' +// Load method + // CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int)' // CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' // CHECK-LOAD-NEXT: CompoundStmt // CHECK-LOAD-NEXT: ReturnStmt // CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'element_type' prefix '*' cannot overflow // CHECK-LOAD-NEXT: CallExpr {{.*}} 'element_type *' +// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} // CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' // CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-LOAD-SAME{LITERAL}: [[hlsl::resource_class( @@ -139,10 +182,13 @@ RESOURCE Buffer; // CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' // CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline +// IncrementCounter method + // CHECK-COUNTER: CXXMethodDecl {{.*}} IncrementCounter 'unsigned int ()' // CHECK-COUNTER-NEXT: CompoundStmt // CHECK-COUNTER-NEXT: ReturnStmt // CHECK-COUNTER-NEXT: CallExpr {{.*}} 'unsigned int' +// CHECK-COUNTER-NEXT: ImplicitCastExpr {{.*}} // CHECK-COUNTER-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept' // CHECK-COUNTER-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-COUNTER-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] @@ -152,10 +198,13 @@ RESOURCE Buffer; // CHECK-COUNTER-NEXT: IntegerLiteral {{.*}} 'int' 1 // CHECK-COUNTER-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline +// DecrementCounter method + // CHECK-COUNTER-NEXT: CXXMethodDecl {{.*}} DecrementCounter 'unsigned int ()' // CHECK-COUNTER-NEXT: CompoundStmt // CHECK-COUNTER-NEXT: ReturnStmt // CHECK-COUNTER-NEXT: CallExpr {{.*}} 'unsigned int' +// CHECK-COUNTER-NEXT: ImplicitCastExpr {{.*}} // CHECK-COUNTER-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept' // CHECK-COUNTER-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-COUNTER-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] @@ -165,12 +214,15 @@ RESOURCE Buffer; // CHECK-COUNTER-NEXT: IntegerLiteral {{.*}} 'int' -1 // CHECK-COUNTER-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline +// Append method + // CHECK-APPEND: CXXMethodDecl {{.*}} Append 'void (element_type)' // CHECK-APPEND-NEXT: ParmVarDecl {{.*}} value 'element_type' // CHECK-APPEND-NEXT: CompoundStmt // CHECK-APPEND-NEXT: BinaryOperator {{.*}} 'element_type' '=' // CHECK-APPEND-NEXT: UnaryOperator {{.*}} 'element_type' prefix '*' cannot overflow // CHECK-APPEND-NEXT: CallExpr {{.*}} 'element_type *' +// CHECK-APPEND-NEXT: ImplicitCastExpr {{.*}} // CHECK-APPEND-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' // CHECK-APPEND-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-APPEND-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] @@ -178,6 +230,7 @@ RESOURCE Buffer; // CHECK-APPEND-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]' lvalue .__handle // CHECK-APPEND-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this // CHECK-APPEND-NEXT: CallExpr {{.*}} 'unsigned int' +// CHECK-APPEND-NEXT: ImplicitCastExpr {{.*}} // CHECK-APPEND-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept' // CHECK-APPEND-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-APPEND-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] @@ -187,11 +240,14 @@ RESOURCE Buffer; // CHECK-APPEND-NEXT: IntegerLiteral {{.*}} 'int' 1 // CHECK-APPEND-NEXT: DeclRefExpr {{.*}} 'element_type' ParmVar {{.*}} 'value' 'element_type' +// Consume method + // CHECK-CONSUME: CXXMethodDecl {{.*}} Consume 'element_type ()' // CHECK-CONSUME-NEXT: CompoundStmt // CHECK-CONSUME-NEXT: ReturnStmt // CHECK-CONSUME-NEXT: UnaryOperator {{.*}} 'element_type' prefix '*' cannot overflow // CHECK-CONSUME-NEXT: CallExpr {{.*}} 'element_type *' +// CHECK-CONSUME-NEXT: ImplicitCastExpr {{.*}} // CHECK-CONSUME-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' // CHECK-CONSUME-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-CONSUME-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] @@ -199,6 +255,7 @@ RESOURCE Buffer; // CHECK-CONSUME-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]' lvalue .__handle // CHECK-CONSUME-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this // CHECK-CONSUME-NEXT: CallExpr {{.*}} 'unsigned int' +// CHECK-CONSUME-NEXT: ImplicitCastExpr {{.*}} // CHECK-CONSUME-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept' // CHECK-CONSUME-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-CONSUME-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] @@ -208,11 +265,10 @@ RESOURCE Buffer; // CHECK-CONSUME-NEXT: IntegerLiteral {{.*}} 'int' -1 // CHECK: ClassTemplateSpecializationDecl {{.*}} class [[RESOURCE]] definition - // CHECK: TemplateArgument type 'float' // CHECK-NEXT: BuiltinType {{.*}} 'float' // CHECK-NEXT: FinalAttr {{.*}} Implicit final -// CHECK-NEXT: FieldDecl {{.*}} implicit __handle '__hlsl_resource_t +// CHECK-NEXT: FieldDecl {{.*}} implicit referenced __handle '__hlsl_resource_t // CHECK-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]] // CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] // CHECK-ROV-SAME{LITERAL}: [[hlsl::is_rov]] diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl index f665b06d691e88..41fd7d7d2ba2a0 100644 --- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl @@ -62,6 +62,7 @@ RESOURCE Buffer; // CHECK-NEXT: ReturnStmt // CHECK-NEXT: UnaryOperator {{.*}} 'element_type' prefix '*' cannot overflow // CHECK-NEXT: CallExpr {{.*}} 'element_type *' +// CHECK-NEXT: ImplicitCastExpr {{.*}} // CHECK-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' // CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] @@ -77,6 +78,7 @@ RESOURCE Buffer; // CHECK-NEXT: ReturnStmt // CHECK-NEXT: UnaryOperator {{.*}} 'element_type' prefix '*' cannot overflow // CHECK-NEXT: CallExpr {{.*}} 'element_type *' +// CHECK-NEXT: ImplicitCastExpr {{.*}} // CHECK-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' // CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] @@ -92,6 +94,7 @@ RESOURCE Buffer; // CHECK-NEXT: ReturnStmt // CHECK-NEXT: UnaryOperator {{.*}} 'element_type' prefix '*' cannot overflow // CHECK-NEXT: CallExpr {{.*}} 'element_type *' +// CHECK-NEXT: ImplicitCastExpr {{.*}} // CHECK-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' // CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] @@ -106,6 +109,6 @@ RESOURCE Buffer; // CHECK: TemplateArgument type 'float' // CHECK-NEXT: BuiltinType {{.*}} 'float' // CHECK-NEXT: FinalAttr {{.*}} Implicit final -// CHECK-NEXT: FieldDecl {{.*}} implicit __handle '__hlsl_resource_t +// CHECK-NEXT: FieldDecl {{.*}} implicit referenced __handle '__hlsl_resource_t // CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]] diff --git a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl index 926a37c6895171..8853c2948ae543 100644 --- a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl @@ -1,34 +1,117 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// FIXME: SPIR-V codegen of llvm.spv.resource.handlefrombinding and resource types is not yet implemented // RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -// NOTE: SPIRV codegen for resource types is not yet implemented +// NOTE: Itanium ABI for C++ requires Clang to generate 2 constructors types to support polymorphism: +// - C1 - Complete object constructor - constructs the complete object, including virtual base classes. +// - C2 - Base object constructor - creates the object itself and initializes data members and non-virtual base classes. +// The constructors are distinquished by C1/C2 designators in their mangled name. +// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor -ByteAddressBuffer Buffer0: register(t0); -RWByteAddressBuffer Buffer1: register(u1, space2); -RasterizerOrderedByteAddressBuffer Buffer2: register(u3, space4); +// Resource with explicit binding +ByteAddressBuffer Buf1: register(t1, space2); -// CHECK: "class.hlsl::ByteAddressBuffer" = type { target("dx.RawBuffer", i8, 0, 0) } -// CHECK: "class.hlsl::RWByteAddressBuffer" = type { target("dx.RawBuffer", i8, 1, 0) } -// CHECK: "class.hlsl::RasterizerOrderedByteAddressBuffer" = type { target("dx.RawBuffer", i8, 1, 1) } +// Resource with implicit binding +RWByteAddressBuffer Buf2; -// CHECK: @_ZL7Buffer0 = internal global %"class.hlsl::ByteAddressBuffer" poison, align 4 -// CHECK: @_ZL7Buffer1 = internal global %"class.hlsl::RWByteAddressBuffer" poison, align 4 -// CHECK: @_ZL7Buffer2 = internal global %"class.hlsl::RasterizerOrderedByteAddressBuffer" poison, align 4 +export void foo() { + // Local resource declaration + RasterizerOrderedByteAddressBuffer Buf3; +} -// CHECK; define internal void @_init_resource_Buffer0() -// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", i8, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", i8, 0, 0) [[H]], ptr @_ZL7Buffer0, align 4 +// CHECK: %"class.hlsl::ByteAddressBuffer" = type { target("dx.RawBuffer", i8, 0, 0) } +// CHECK: %"class.hlsl::RWByteAddressBuffer" = type { target("dx.RawBuffer", i8, 1, 0) } +// CHECK: %"class.hlsl::RasterizerOrderedByteAddressBuffer" = type { target("dx.RawBuffer", i8, 1, 1) } -// CHECK; define internal void @_init_resource_Buffer1() -// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_0t(i32 2, i32 1, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", i8, 1, 0) [[H]], ptr @_ZL7Buffer1, align 4 +// CHECK: @_ZL4Buf1 = internal global %"class.hlsl::ByteAddressBuffer" poison, align 4 +// CHECK: @_ZL4Buf2 = internal global %"class.hlsl::RWByteAddressBuffer" poison, align 4 -// CHECK; define internal void @_init_resource_Buffer2() -// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", i8, 1, 1) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_1t(i32 4, i32 3, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", i8, 1, 1) [[H]], ptr @_ZL7Buffer2, align 4 +// Buf1 initialization part 1 - global init function that calls ByteAddressBuffer C1 constructor with explicit binding +// CHECK: define internal void @__cxx_global_var_init() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @_ZN4hlsl17ByteAddressBufferC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf1, +// CHECK-SAME: i32 noundef 2, i32 noundef 1, i32 noundef 1, i32 noundef 0) +// Buf1 initialization part 2 - body of ByteAddressBuffer C1 constructor with explicit binding that calls the C2 constructor +// CHECK: define linkonce_odr void @_ZN4hlsl17ByteAddressBufferC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 +// CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %range.addr = alloca i32, align 4 +// CHECK-NEXT: %index.addr = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 +// CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 +// CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 +// CHECK: call void @_ZN4hlsl17ByteAddressBufferC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this1, +// CHECK-SAME: i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3) +// CHECK-NEXT: ret void + +// Buf2 initialization part 1 - FIXME: constructor with implicit binding does not exist yet; +// the global init function currently calls the default RWByteAddressBuffer C1 constructor +// CHECK: define internal void @__cxx_global_var_init.1() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @_ZN4hlsl19RWByteAddressBufferC1Ev(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf2) + +// Buf3 initialization part 1 - local variable declared in function foo() is initialized by +// RasterizerOrderedByteAddressBuffer C1 default constructor +// CHECK: define void @_Z3foov() #2 { +// CHECK-NEXT: entry: +// CHECK-NEXT: %Buf3 = alloca %"class.hlsl::RasterizerOrderedByteAddressBuffer", align 4 +// CHECK-NEXT: call void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %Buf3) + +// Buf3 initialization part 2 - body of RasterizerOrderedByteAddressBuffer default C1 constructor that +// calls the default C2 constructor +// CHECK: define linkonce_odr void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK: call void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this1) +// CHECK-NEXT: ret void + +// Buf1 initialization part 3 - ByteAddressBuffer C2 constructor with explicit binding that initializes +// handle with @llvm.dx.resource.handlefrombinding +// CHECK: define linkonce_odr void @_ZN4hlsl17ByteAddressBufferC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 +// CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %range.addr = alloca i32, align 4 +// CHECK-NEXT: %index.addr = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 +// CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 +// CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 +// CHECK-DXIL-NEXT: %4 = call target("dx.RawBuffer", i8, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t( +// CHECK-SAME: i32 %0, i32 %1, i32 %2, i32 %3, i1 false) +// CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::ByteAddressBuffer", ptr %this1, i32 0, i32 0 +// CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 0, 0) %4, ptr %__handle, align 4 +// CHECK-NEXT: ret void + +// Buf3 initialization part 3 - body of RasterizerOrderedByteAddressBuffer default C2 constructor that +// initializes handle to poison +// CHECK: define linkonce_odr void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedByteAddressBuffer", ptr %this1, i32 0, i32 0 +// CHECK: store target("dx.RawBuffer", i8, 1, 1) poison, ptr %__handle, align 4 + +// Module initialization // CHECK: define internal void @_GLOBAL__sub_I_ByteAddressBuffers_constructors.hlsl() -// CHECK: entry: -// CHECK: call void @_init_resource__ZL7Buffer0() -// CHECK: call void @_init_resource__ZL7Buffer1() -// CHECK: call void @_init_resource__ZL7Buffer2() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @__cxx_global_var_init() +// CHECK-NEXT: call void @__cxx_global_var_init.1() diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl index 56c523f6bc8cf0..8a08536ce133cb 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -O3 -o - %s | FileCheck %s // RUN: %clang_cc1 -triple spirv-vulkan-compute -x hlsl -emit-llvm -O3 -o - %s | FileCheck %s -// All referenced to an unused resource should be removed by optimizations. +// All references to unused resources should be removed by optimizations. RWBuffer Buf : register(u5, space3); [shader("compute")] diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl index 5324176a7b9bb7..c704a3b05b3b4d 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl @@ -1,20 +1,119 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -// FIXME: SPIR-V codegen of llvm.spv.resource.handlefrombinding is not yet implemented +// FIXME: SPIR-V codegen of llvm.spv.resource.handlefrombinding and resource types is not yet implemented // RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -// NOTE: SPIRV codegen for resource types is not yet implemented +// NOTE: Itanium ABI for C++ requires Clang to generate 2 constructors types to support polymorphism: +// - C1 - Complete object constructor - constructs the complete object, including virtual base classes. +// - C2 - Base object constructor - creates the object itself and initializes data members and non-virtual base classes. +// The constructors are distinquished by C1/C2 designators in their mangled name. +// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor -RWBuffer Buf : register(u5, space3); +// Resource with explicit binding +RWBuffer Buf1 : register(u5, space3); + +// Resource with implicit binding +RWBuffer Buf2; + +export void foo() { + // Local resource declaration + RWBuffer Buf3; +} // CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", float, 1, 0, 0) } -// CHECK: @_ZL3Buf = internal global %"class.hlsl::RWBuffer" poison, align 4 +// CHECK: %"class.hlsl::RWBuffer.0" = type { target("dx.TypedBuffer", double, 1, 0, 0) } +// CHECK: %"class.hlsl::RWBuffer.1" = type { target("dx.TypedBuffer", i32, 1, 0, 1) } + +// CHECK: @_ZL4Buf1 = internal global %"class.hlsl::RWBuffer" poison, align 4 +// CHECK: @_ZL4Buf2 = internal global %"class.hlsl::RWBuffer.0" poison, align 4 + +// Buf1 initialization part 1 - global init function that calls RWBuffer C1 constructor with explicit binding +// CHECK: define internal void @__cxx_global_var_init() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf1, +// CHECK-SAME: i32 noundef 3, i32 noundef 5, i32 noundef 1, i32 noundef 0) + +// Buf1 initialization part 2 - body of RWBuffer C1 constructor with explicit binding that calls the C2 constructor +// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 +// CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %range.addr = alloca i32, align 4 +// CHECK-NEXT: %index.addr = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 +// CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 +// CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 +// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this1, +// CHECK-SAME: i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3) +// CHECK-NEXT: ret void -// CHECK: define internal void @_init_resource__ZL3Buf() -// CHECK-DXIL: [[H:%.*]] = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.TypedBuffer", float, 1, 0, 0) [[H]], ptr @_ZL3Buf, align 4 +// Buf2 initialization part 1 - FIXME: constructor with implicit binding does not exist yet; +// the global init function currently calls the default RWBufer C1 constructor +// CHECK: define internal void @__cxx_global_var_init.1() #0 { +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIdEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf2) -// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// Buf3 initialization part 1 - local variable declared in function foo() is initialized by RWBuffer C1 default constructor +// CHECK: define void @_Z3foov() // CHECK-NEXT: entry: +// CHECK-NEXT: %Buf3 = alloca %"class.hlsl::RWBuffer.1", align 4 +// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %Buf3) +// Buf3 initialization part 2 - body of RWBuffer default C1 constructor that calls the default C2 constructor +// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this1) +// CHECK-NEXT: ret void + +// Buf1 initialization part 3 - body of RWBuffer C2 constructor with explicit binding that initializes +// handle with @llvm.dx.resource.handlefrombinding +// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 +// CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %range.addr = alloca i32, align 4 +// CHECK-NEXT: %index.addr = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 +// CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 +// CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 +// CHECK-DXIL-NEXT: %4 = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t( +// CHECK-DXIL-SAME: i32 %0, i32 %1, i32 %2, i32 %3, i1 false) +// CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer", ptr %this1, i32 0, i32 0 +// CHECK-DXIL-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %4, ptr %__handle, align 4 +// CHECK-NEXT: ret void + +// Buf3 initialization part 3 - body of RWBuffer default C2 constructor that initializes handle to poison +// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIiEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer.1", ptr %this1, i32 0, i32 0 +// CHECK-NEXT: store target("dx.TypedBuffer", i32, 1, 0, 1) poison, ptr %__handle, align 4 +// CHECK-NEXT: ret void + +// Module initialization // CHECK: define internal void @_GLOBAL__sub_I_RWBuffer_constructor.hlsl() -// CHECK: call void @_init_resource__ZL3Buf() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @__cxx_global_var_init() +// CHECK-NEXT: call void @__cxx_global_var_init.1() diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl index 8a1429fd1a6fc1..3c41f3583ac1a8 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl @@ -1,70 +1,121 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -// RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -DSPIRV -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV +// FIXME: SPIR-V codegen of llvm.spv.resource.handlefrombinding and resource types is not yet implemented +// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV +// NOTE: Itanium ABI for C++ requires Clang to generate 2 constructors types to support polymorphism: +// - C1 - Complete object constructor - constructs the complete object, including virtual base classes. +// - C2 - Base object constructor - creates the object itself and initializes data members and non-virtual base classes. +// The constructors are distinquished by C1/C2 designators in their mangled name. +// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor -StructuredBuffer Buf : register(t10); -RWStructuredBuffer Buf2 : register(u5, space1); +// Resource with explicit binding +StructuredBuffer Buf1 : register(t10, space2); -#ifndef SPIRV -// NOTE: SPIRV codegen for these resource types is not implemented yet. -AppendStructuredBuffer Buf3 : register(u3); -ConsumeStructuredBuffer Buf4 : register(u4); -RasterizerOrderedStructuredBuffer Buf5 : register(u1, space2); -#endif +// Resource with implicit binding +RWStructuredBuffer Buf2; -// CHECK-DXIL: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", float, 0, 0) } -// CHECK-DXIL: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) } -// CHECK-DXIL: %"class.hlsl::AppendStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) } -// CHECK-DXIL: %"class.hlsl::ConsumeStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) } -// CHECK-DXIL: %"class.hlsl::RasterizerOrderedStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 1) } +export void foo() { + AppendStructuredBuffer Buf3; +} -// CHECK-SPIRV: %"class.hlsl::StructuredBuffer" = type { target("spirv.VulkanBuffer", [0 x float], 12, 0) } -// CHECK-SPIRV: %"class.hlsl::RWStructuredBuffer" = type { target("spirv.VulkanBuffer", [0 x float], 12, 1) } +// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", float, 0, 0) } +// CHECK: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) } +// CHECK: %"class.hlsl::AppendStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) } +// CHECK: @_ZL4Buf1 = internal global %"class.hlsl::StructuredBuffer" poison, align 4 +// CHECK: @_ZL4Buf2 = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4 -// CHECK: @_ZL3Buf = internal global %"class.hlsl::StructuredBuffer" poison -// CHECK: @_ZL4Buf2 = internal global %"class.hlsl::RWStructuredBuffer" poison -// CHECK-DXIL: @_ZL4Buf3 = internal global %"class.hlsl::AppendStructuredBuffer" poison, align 4 -// CHECK-DXIL: @_ZL4Buf4 = internal global %"class.hlsl::ConsumeStructuredBuffer" poison, align 4 -// CHECK-DXIL: @_ZL4Buf5 = internal global %"class.hlsl::RasterizerOrderedStructuredBuffer" poison, align 4 +// Buf1 initialization part 1 - global init function that calls StructuredBuffer C1 constructor +// with explicit binding +// CHECK: define internal void @__cxx_global_var_init() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @_ZN4hlsl16StructuredBufferIfEC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf1, i32 noundef 2, i32 noundef 10, i32 noundef 1, i32 noundef 0) -// CHECK: define internal void @_init_resource__ZL3Buf() -// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", float, 0, 0) [[H]], ptr @_ZL3Buf, align 4 -// CHECK-SPIRV: [[H:%.*]] = call target("spirv.VulkanBuffer", [0 x float], 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0f32_12_0t(i32 0, i32 10, i32 1, i32 0, i1 false) -// CHECK-SPIRV: store target("spirv.VulkanBuffer", [0 x float], 12, 0) [[H]], ptr @_ZL3Buf, align 8 +// Buf1 initialization part 2 - body of StructuredBuffer C1 constructor with explicit binding +// that calls the C2 constructor +// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 +// CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %range.addr = alloca i32, align 4 +// CHECK-NEXT: %index.addr = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 +// CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 +// CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 +// CHECK: call void @_ZN4hlsl16StructuredBufferIfEC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this1, +// CHECK-SAME: i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3) +// CHECK-NEXT: ret void -// CHECK: define internal void @_init_resource__ZL4Buf2() -// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf2, align 4 -// CHECK-SPIRV: [[H:%.*]] = call target("spirv.VulkanBuffer", [0 x float], 12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0f32_12_1t(i32 1, i32 5, i32 1, i32 0, i1 false) -// CHECK-SPIRV: store target("spirv.VulkanBuffer", [0 x float], 12, 1) [[H]], ptr @_ZL4Buf2, align 8 +// Buf2 initialization part 1 - FIXME: constructor with implicit binding does not exist yet; +// the global init function currently calls the default RWStructuredBufer C1 constructor +// CHECK: define internal void @__cxx_global_var_init.1() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @_ZN4hlsl18RWStructuredBufferIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf2) -// CHECK-DXIL: define internal void @_init_resource__ZL4Buf3() -// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 3, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf3, align 4 +// Buf3 initialization part 1 - local variable declared in function foo() is initialized by +// AppendStructuredBuffer C1 default constructor +// CHECK: define void @_Z3foov() +// CHECK-NEXT: entry: +// CHECK-NEXT: %Buf3 = alloca %"class.hlsl::AppendStructuredBuffer", align 4 +// CHECK-NEXT: call void @_ZN4hlsl22AppendStructuredBufferIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %Buf3) -// CHECK-DXIL: define internal void @_init_resource__ZL4Buf4() -// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 4, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf4, align 4 +// Buf3 initialization part 2 - body of AppendStructuredBuffer default C1 constructor that calls +// the default C2 constructor +// CHECK: define linkonce_odr void @_ZN4hlsl22AppendStructuredBufferIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK: call void @_ZN4hlsl22AppendStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this1) +// CHECK-NEXT: ret void -// CHECK-DXIL: define internal void @_init_resource__ZL4Buf5() -// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 1) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 1) [[H]], ptr @_ZL4Buf5, align 4 +// Buf1 initialization part 3 - body of AppendStructuredBuffer C2 constructor with explicit binding +// that initializes handle with @llvm.dx.resource.handlefrombinding +// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 +// CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %range.addr = alloca i32, align 4 +// CHECK-NEXT: %index.addr = alloca i32, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 +// CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 +// CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 +// CHECK-DXIL-NEXT: %4 = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t( +// CHECK-DXIL-SAME: i32 %0, i32 %1, i32 %2, i32 %3, i1 false) +// CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %this1, i32 0, i32 0 +// CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 0, 0) %4, ptr %__handle, align 4 +// CHECK-NEXT: ret void -// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ev(ptr noundef nonnull align {{[48]}} dereferenceable({{[48]}}) %this) +// Buf3 initialization part 3 - body of AppendStructuredBuffer default C2 constructor that +// initializes handle to poison +// CHECK: define linkonce_odr void @_ZN4hlsl22AppendStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) // CHECK-NEXT: entry: -// CHECK-DXIL: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) -// CHECK-DXIL-NEXT: entry: -// CHECK-DXIL: define linkonce_odr void @_ZN4hlsl22AppendStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) -// CHECK-DXIL-NEXT: entry: -// CHECK-DXIL: define linkonce_odr void @_ZN4hlsl23ConsumeStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) -// CHECK-DXIL: define linkonce_odr void @_ZN4hlsl33RasterizerOrderedStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) -// CHECK-DXIL-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 4 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::AppendStructuredBuffer", ptr %this1, i32 0, i32 0 +// CHECK: store target("dx.RawBuffer", float, 1, 0) poison, ptr %__handle, align 4 -// CHECK: define {{.*}} void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl() -// CHECK: call {{.*}} @_init_resource__ZL3Buf() -// CHECK: call {{.*}} @_init_resource__ZL4Buf2() -// CHECK-DXIL: call void @_init_resource__ZL4Buf3() -// CHECK-DXIL: call void @_init_resource__ZL4Buf4() -// CHECK-DXIL: call void @_init_resource__ZL4Buf5() +// Module initialization +// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @__cxx_global_var_init() +// CHECK-NEXT: call void @__cxx_global_var_init.1() diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl index 0a0465cc44e912..0fb36d16fee0a4 100644 --- a/clang/test/CodeGenHLSL/cbuffer.hlsl +++ b/clang/test/CodeGenHLSL/cbuffer.hlsl @@ -267,13 +267,13 @@ cbuffer CB_C { double D4; } -// CHECK: define internal void @_init_resource_CBScalars.cb() +// CHECK: define internal void @_init_buffer_CBScalars.cb() // CHECK-NEXT: entry: // CHECK-NEXT: %[[HANDLE1:.*]] = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48)) // CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBScalarss_56_0_8_16_24_32_36_40_48tt(i32 5, i32 1, i32 1, i32 0, i1 false) // CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48)) %CBScalars.cb_h, ptr @CBScalars.cb, align 4 -// CHECK: define internal void @_init_resource_CBArrays.cb() +// CHECK: define internal void @_init_buffer_CBArrays.cb() // CHECK-NEXT: entry: // CHECK-NEXT: %[[HANDLE2:.*]] = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656)) // CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBArrayss_708_0_48_112_176_224_608_624_656tt(i32 0, i32 2, i32 1, i32 0, i1 false) @@ -288,8 +288,8 @@ void main() { // CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl() // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_init_resource_CBScalars.cb() -// CHECK-NEXT: call void @_init_resource_CBArrays.cb() +// CHECK-NEXT: call void @_init_buffer_CBScalars.cb() +// CHECK-NEXT: call void @_init_buffer_CBArrays.cb() // CHECK: !hlsl.cbs = !{![[CBSCALARS:[0-9]+]], ![[CBVECTORS:[0-9]+]], ![[CBARRAYS:[0-9]+]], ![[CBTYPEDEFARRAY:[0-9]+]], ![[CBSTRUCTS:[0-9]+]], ![[CBCLASSES:[0-9]+]], // CHECK-SAME: ![[CBMIX:[0-9]+]], ![[CB_A:[0-9]+]], ![[CB_B:[0-9]+]], ![[CB_C:[0-9]+]]} diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl index c0a77564b141ac..11ca7b6724ae46 100644 --- a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl +++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl @@ -27,7 +27,7 @@ cbuffer CB : register(b0) { float2 y : packoffset(c5); } -// CHECK: define internal void @_init_resource_CB.cb() +// CHECK: define internal void @_init_buffer_CB.cb() // CHECK-NEXT: entry: // CHECK-NEXT: %CB.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 176, 16, 168, 88)) // CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBs_176_16_168_88tt(i32 3, i32 1, i32 1, i32 0, i1 false) @@ -39,7 +39,7 @@ float foo() { } // CHECK: define internal void @_GLOBAL__sub_I_cbuffer_with_packoffset.hlsl() // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_init_resource_CB.cb() +// CHECK-NEXT: call void @_init_buffer_CB.cb() [numthreads(4,1,1)] void main() { diff --git a/clang/test/CodeGenHLSL/resource-bindings.hlsl b/clang/test/CodeGenHLSL/resource-bindings.hlsl index 3342fb55a59a46..d8e105ed7e98cf 100644 --- a/clang/test/CodeGenHLSL/resource-bindings.hlsl +++ b/clang/test/CodeGenHLSL/resource-bindings.hlsl @@ -1,34 +1,46 @@ // RUN: %clang_cc1 -triple dxil--shadermodel6.6-compute -x hlsl -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -// CHECK: define internal void @_init_resource__ZL4U0S0() -// CHECK: [[H:%.*]] = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false) -// CHECK: store target("dx.TypedBuffer", <4 x float>, 1, 0, 0) [[H]], ptr @_ZL4U0S0, align 4 +// CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", <4 x float>, 1, 0, 0) } +// CHECK: %"class.hlsl::RWBuffer.0" = type { target("dx.TypedBuffer", float, 1, 0, 0) } +// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", i32, 0, 0) } +// CHECK: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", %struct.S, 1, 0) } + +// CHECK: @_ZL4U0S0 = internal global %"class.hlsl::RWBuffer" poison, align 4 +// CHECK: @_ZL4U5S3 = internal global %"class.hlsl::RWBuffer.0" poison, align 4 +// CHECK: @_ZL4T2S2 = internal global %"class.hlsl::StructuredBuffer" poison, align 4 +// CHECK: @_ZL4T3S0 = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4 + +// CHECK: %[[HANDLE:.*]] = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) +// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_1_0_0t( +// CHECK-SAME: i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i1 false) +// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw %"class.hlsl::RWBuffer", ptr %this{{[0-9]*}}, i32 0, i32 0 +// CHECK: store target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %[[HANDLE]], ptr %[[HANDLE_PTR]], align 4 RWBuffer U0S0 : register(u0); -// CHECK: define internal void @_init_resource__ZL4U5S3() -// CHECK: [[H:%.*]] = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false) -// CHECK: store target("dx.TypedBuffer", float, 1, 0, 0) [[H]], ptr @_ZL4U5S3, align 4 +// CHECK: %[[HANDLE:.*]] = call target("dx.TypedBuffer", float, 1, 0, 0) +// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t( +// CHECK-SAME: i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i1 false) +// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw %"class.hlsl::RWBuffer.0", ptr %this{{[0-9]*}}, i32 0, i32 0 +// CHECK: store target("dx.TypedBuffer", float, 1, 0, 0) %[[HANDLE]], ptr %[[HANDLE_PTR]], align 4 RWBuffer U5S3 : register(u5, space3); -// CHECK: define internal void @_init_resource__ZL4T2S2() -// CHECK: [[H:%.*]] = call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_0_0t(i32 2, i32 2, i32 1, i32 0, i1 false) -// CHECK: store target("dx.RawBuffer", i32, 0, 0) [[H]], ptr @_ZL4T2S2, align 4 +// CHECK: %[[HANDLE:.*]] = call target("dx.RawBuffer", i32, 0, 0) +// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_0_0t( +// CHECK-SAME: i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i1 false) +// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %this{{[0-9]*}}, i32 0, i32 0 +// CHECK: store target("dx.RawBuffer", i32, 0, 0) %[[HANDLE]], ptr %[[HANDLE_PTR]], align 4 StructuredBuffer T2S2 : register(t2, space2); + +// CHECK: %[[HANDLE:.*]] = call target("dx.RawBuffer", %struct.S, 1, 0) +// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_s_struct.Ss_1_0t( +// CHECK-SAME: i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i1 false) +// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer", ptr %this{{[0-9]*}}, i32 0, i32 0 +// CHECK: store target("dx.RawBuffer", %struct.S, 1, 0) %[[HANDLE]], ptr %[[HANDLE_PTR]], align 4 struct S { float4 f; int i; }; - -// CHECK: define internal void @_init_resource__ZL4T3S0() -// CHECK: [[H:%.*]] = call target("dx.RawBuffer", %struct.S, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_s_struct.Ss_0_0t(i32 0, i32 3, i32 1, i32 0, i1 false) -// CHECK: store target("dx.RawBuffer", %struct.S, 0, 0) [[H]], ptr @_ZL4T3S0, align 4 -StructuredBuffer T3S0 : register(t3); - -// CHECK: define void @main() -// CHECK: call void @_init_resource__ZL4U0S0() -// CHECK: call void @_init_resource__ZL4U5S3() -// CHECK: call void @_init_resource__ZL4T2S2() -// CHECK: call void @_init_resource__ZL4T3S0() +RWStructuredBuffer T3S0 : register(u3); [numthreads(4,1,1)] void main() {} diff --git a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl index b5737f5dac8a9c..36e70bc686be8f 100644 --- a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl +++ b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl @@ -3,7 +3,7 @@ // CHECK: ClassTemplateSpecializationDecl {{.*}} class RWBuffer definition implicit_instantiation // CHECK: TemplateArgument type 'float' // CHECK: BuiltinType {{.*}} 'float' -// CHECK: FieldDecl {{.*}} implicit __handle '__hlsl_resource_t +// CHECK: FieldDecl {{.*}} implicit referenced __handle '__hlsl_resource_t // CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]] RWBuffer Buffer1; @@ -12,7 +12,7 @@ RWBuffer Buffer1; // CHECK: TemplateArgument type 'vector' // CHECK: ExtVectorType {{.*}} 'vector' 4 // CHECK: BuiltinType {{.*}} 'float' -// CHECK: FieldDecl {{.*}} implicit __handle '__hlsl_resource_t +// CHECK: FieldDecl {{.*}} implicit referenced __handle '__hlsl_resource_t // CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)] // CHECK-SAME{LITERAL}: [[hlsl::is_rov]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector)]] From 752ed77e6199810f8803699cfb6e2225a4bc09bf Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Wed, 9 Apr 2025 21:06:03 -0700 Subject: [PATCH 02/13] flip register & space, add more tests, cleanup empty function --- clang/lib/CodeGen/CGHLSLBuiltins.cpp | 4 +- clang/lib/CodeGen/CGHLSLRuntime.cpp | 3 -- clang/lib/CodeGen/CGHLSLRuntime.h | 1 - clang/lib/CodeGen/CodeGenModule.cpp | 3 -- clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 2 +- clang/lib/Sema/SemaHLSL.cpp | 8 ++-- .../test/AST/HLSL/ByteAddressBuffers-AST.hlsl | 36 +++++++++++++++++ .../test/AST/HLSL/StructuredBuffers-AST.hlsl | 4 +- clang/test/AST/HLSL/TypedBuffers-AST.hlsl | 40 +++++++++++++++++++ .../ByteAddressBuffers-constructors.hlsl | 24 +++++------ .../builtins/RWBuffer-constructor.hlsl | 24 +++++------ .../StructuredBuffers-constructors.hlsl | 25 ++++++------ 12 files changed, 122 insertions(+), 52 deletions(-) diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index c652f435781f0a..dfcade7a074ca2 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -293,8 +293,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, } case Builtin::BI__builtin_hlsl_resource_createhandlefrombinding: { llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType()); - Value *SpaceNoOp = EmitScalarExpr(E->getArg(1)); - Value *RegisterNoOp = EmitScalarExpr(E->getArg(2)); + Value *RegisterNoOp = EmitScalarExpr(E->getArg(1)); + Value *SpaceNoOp = EmitScalarExpr(E->getArg(2)); Value *RangeOp = EmitScalarExpr(E->getArg(3)); Value *IndexOp = EmitScalarExpr(E->getArg(4)); // FIXME: NonUniformResourceIndex bit is not yet implemented diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index c7fb6b57c47dca..450213fcec6762 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -544,9 +544,6 @@ static void initializeBufferFromBinding(CodeGenModule &CGM, Args); } -void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD, - llvm::GlobalVariable *GV) {} - llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) { if (!CGM.shouldEmitConvergenceTokens()) return nullptr; diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index 68151c0f0ea24b..4d6db3f5d9f3e5 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -150,7 +150,6 @@ class CGHLSLRuntime { void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn); void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn); - void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var); llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 8f9cf965af2b96..395b5c3ecc6952 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -5698,9 +5698,6 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, getCUDARuntime().handleVarRegistration(D, *GV); } - if (LangOpts.HLSL) - getHLSLRuntime().handleGlobalVarDefinition(D, GV); - GV->setInitializer(Init); if (emitter) emitter->finalize(GV); diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 4fd01404b012e1..a680d6efcd67d8 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -658,8 +658,8 @@ BuiltinTypeDeclBuilder::addHandleConstructorFromBinding() { QualType HandleType = getResourceHandleField()->getType(); return BuiltinTypeMethodBuilder(*this, "", AST.VoidTy, false, true) - .addParam("spaceNo", AST.UnsignedIntTy) .addParam("registerNo", AST.UnsignedIntTy) + .addParam("spaceNo", AST.UnsignedIntTy) .addParam("range", AST.IntTy) .addParam("index", AST.UnsignedIntTy) .callBuiltin("__builtin_hlsl_resource_createhandlefrombinding", diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index fb786e14290200..299733f8c107f1 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3207,7 +3207,7 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { } } -static bool initVarDeclWithConstructor(Sema &S, VarDecl *VD, +static bool initVarDeclWithCtor(Sema &S, VarDecl *VD, MutableArrayRef Args) { InitializedEntity Entity = InitializedEntity::InitializeVariable(VD); InitializationKind Kind = InitializationKind::CreateDirect( @@ -3235,17 +3235,17 @@ static bool initGlobalResourceDecl(Sema &S, VarDecl *VD) { uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy); uint64_t IntTySize = AST.getTypeSize(AST.IntTy); Expr *Args[] = { + IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, RBA->getSlotNumber()), + AST.UnsignedIntTy, SourceLocation()), IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, RBA->getSpaceNumber()), AST.UnsignedIntTy, SourceLocation()), - IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, RBA->getSlotNumber()), - AST.UnsignedIntTy, SourceLocation()), IntegerLiteral::Create(AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation()), IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation())}; - return initVarDeclWithConstructor(S, VD, Args); + return initVarDeclWithCtor(S, VD, Args); } // Returns true in the initialization has been handled; diff --git a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl index 38e5b6281c42ec..c8b584171f0071 100644 --- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl @@ -42,5 +42,41 @@ RESOURCE Buffer; // CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(char8_t)]] +// Default constructor + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void ()' inline +// 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 {{.*}} +// CHECK-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_createpoisonhandle' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: AlwaysInlineAttr + +// Constructor from binding + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (unsigned int, unsigned int, int, unsigned int)' inline +// CHECK-NEXT: ParmVarDecl {{.*}} registerNo 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} range 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} index 'unsigned int' +// 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 {{.*}} +// CHECK-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_createhandlefrombinding' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'registerNo' 'unsigned int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'spaceNo' 'unsigned int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} 'range' 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int' +// CHECK-NEXT: AlwaysInlineAttr + // CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'const element_type &(unsigned int) const' // CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'element_type &(unsigned int)' diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl index a07613ca2c7294..c02a064f7c8533 100644 --- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl @@ -106,8 +106,8 @@ RESOURCE Buffer; // Constructor from binding // CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (unsigned int, unsigned int, int, unsigned int)' inline -// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int' // CHECK-NEXT: ParmVarDecl {{.*}} registerNo 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int' // CHECK-NEXT: ParmVarDecl {{.*}} range 'int' // CHECK-NEXT: ParmVarDecl {{.*}} index 'unsigned int' // CHECK-NEXT: CompoundStmt {{.*}} @@ -119,8 +119,8 @@ RESOURCE Buffer; // CHECK-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_createhandlefrombinding' // CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle // CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this -// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'spaceNo' 'unsigned int' // CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'registerNo' 'unsigned int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'spaceNo' 'unsigned int' // CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} 'range' 'int' // CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl index 41fd7d7d2ba2a0..075bdbace2e017 100644 --- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl @@ -56,6 +56,44 @@ RESOURCE Buffer; // CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] +// Default constructor + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void ()' inline +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: BinaryOperator {{.*}} '=' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t +// CHECK-NEXT: ImplicitCastExpr {{.*}} +// CHECK-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_createpoisonhandle' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: AlwaysInlineAttr + +// Constructor from binding + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (unsigned int, unsigned int, int, unsigned int)' inline +// CHECK-NEXT: ParmVarDecl {{.*}} registerNo 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} range 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} index 'unsigned int' +// CHECK-NEXT: CompoundStmt {{.*}} +// CHECK-NEXT: BinaryOperator {{.*}} '=' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t +// CHECK-NEXT: ImplicitCastExpr {{.*}} +// CHECK-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_createhandlefrombinding' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'registerNo' 'unsigned int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'spaceNo' 'unsigned int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} 'range' 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int' +// CHECK-NEXT: AlwaysInlineAttr + +// Subsctript operators + // CHECK: CXXMethodDecl {{.*}} operator[] 'const element_type &(unsigned int) const' // CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' // CHECK-NEXT: CompoundStmt @@ -88,6 +126,8 @@ RESOURCE Buffer; // CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline +// Load method + // CHECK-NEXT: CXXMethodDecl {{.*}} Load 'element_type (unsigned int)' // CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' // CHECK-NEXT: CompoundStmt diff --git a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl index 8853c2948ae543..80bf907180af40 100644 --- a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl @@ -30,25 +30,25 @@ export void foo() { // CHECK: define internal void @__cxx_global_var_init() // CHECK-NEXT: entry: // CHECK-NEXT: call void @_ZN4hlsl17ByteAddressBufferC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf1, -// CHECK-SAME: i32 noundef 2, i32 noundef 1, i32 noundef 1, i32 noundef 0) +// CHECK-SAME: i32 noundef 1, i32 noundef 2, i32 noundef 1, i32 noundef 0) // Buf1 initialization part 2 - body of ByteAddressBuffer C1 constructor with explicit binding that calls the C2 constructor // CHECK: define linkonce_odr void @_ZN4hlsl17ByteAddressBufferC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, -// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index) // CHECK-NEXT: entry: // CHECK-NEXT: %this.addr = alloca ptr, align 4 -// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %range.addr = alloca i32, align 4 // CHECK-NEXT: %index.addr = alloca i32, align 4 // CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 -// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 // CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 // CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 -// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 -// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %spaceNo.addr, align 4 // CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 // CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 // CHECK: call void @_ZN4hlsl17ByteAddressBufferC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this1, @@ -81,25 +81,25 @@ export void foo() { // Buf1 initialization part 3 - ByteAddressBuffer C2 constructor with explicit binding that initializes // handle with @llvm.dx.resource.handlefrombinding // CHECK: define linkonce_odr void @_ZN4hlsl17ByteAddressBufferC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, -// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index) // CHECK-NEXT: entry: // CHECK-NEXT: %this.addr = alloca ptr, align 4 -// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %range.addr = alloca i32, align 4 // CHECK-NEXT: %index.addr = alloca i32, align 4 // CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 -// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 // CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 // CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 -// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 -// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %spaceNo.addr, align 4 // CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 // CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 // CHECK-DXIL-NEXT: %4 = call target("dx.RawBuffer", i8, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t( -// CHECK-SAME: i32 %0, i32 %1, i32 %2, i32 %3, i1 false) +// CHECK-DXIL-SAME: i32 %1, i32 %0, i32 %2, i32 %3, i1 false) // CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::ByteAddressBuffer", ptr %this1, i32 0, i32 0 // CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 0, 0) %4, ptr %__handle, align 4 // CHECK-NEXT: ret void diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl index c704a3b05b3b4d..8cf1337dcaf872 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl @@ -30,25 +30,25 @@ export void foo() { // CHECK: define internal void @__cxx_global_var_init() // CHECK-NEXT: entry: // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf1, -// CHECK-SAME: i32 noundef 3, i32 noundef 5, i32 noundef 1, i32 noundef 0) +// CHECK-SAME: i32 noundef 5, i32 noundef 3, i32 noundef 1, i32 noundef 0) // Buf1 initialization part 2 - body of RWBuffer C1 constructor with explicit binding that calls the C2 constructor // CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, -// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index) // CHECK-NEXT: entry: // CHECK-NEXT: %this.addr = alloca ptr, align 4 -// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %range.addr = alloca i32, align 4 // CHECK-NEXT: %index.addr = alloca i32, align 4 // CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 -// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 // CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 // CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 -// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 -// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %spaceNo.addr, align 4 // CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 // CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this1, @@ -79,25 +79,25 @@ export void foo() { // Buf1 initialization part 3 - body of RWBuffer C2 constructor with explicit binding that initializes // handle with @llvm.dx.resource.handlefrombinding // CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, -// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index) // CHECK-NEXT: entry: // CHECK-NEXT: %this.addr = alloca ptr, align 4 -// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %range.addr = alloca i32, align 4 // CHECK-NEXT: %index.addr = alloca i32, align 4 // CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 -// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 // CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 // CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 -// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 -// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %spaceNo.addr, align 4 // CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 // CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 // CHECK-DXIL-NEXT: %4 = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t( -// CHECK-DXIL-SAME: i32 %0, i32 %1, i32 %2, i32 %3, i1 false) +// CHECK-DXIL-SAME: i32 %1, i32 %0, i32 %2, i32 %3, i1 false) // CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer", ptr %this1, i32 0, i32 0 // CHECK-DXIL-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %4, ptr %__handle, align 4 // CHECK-NEXT: ret void diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl index 3c41f3583ac1a8..ec94991ea48016 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl @@ -29,26 +29,27 @@ export void foo() { // with explicit binding // CHECK: define internal void @__cxx_global_var_init() // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_ZN4hlsl16StructuredBufferIfEC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf1, i32 noundef 2, i32 noundef 10, i32 noundef 1, i32 noundef 0) +// CHECK-NEXT: call void @_ZN4hlsl16StructuredBufferIfEC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf1, +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 1, i32 noundef 0) // Buf1 initialization part 2 - body of StructuredBuffer C1 constructor with explicit binding // that calls the C2 constructor // CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC1Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, -// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index) // CHECK-NEXT: entry: // CHECK-NEXT: %this.addr = alloca ptr, align 4 -// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %range.addr = alloca i32, align 4 // CHECK-NEXT: %index.addr = alloca i32, align 4 // CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 -// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 // CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 // CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 -// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 -// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %spaceNo.addr, align 4 // CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 // CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 // CHECK: call void @_ZN4hlsl16StructuredBufferIfEC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this1, @@ -81,25 +82,25 @@ export void foo() { // Buf1 initialization part 3 - body of AppendStructuredBuffer C2 constructor with explicit binding // that initializes handle with @llvm.dx.resource.handlefrombinding // CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) %this, -// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef %range, i32 noundef %index) +// CHECK-SAME: i32 noundef %registerNo, i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index) // CHECK-NEXT: entry: // CHECK-NEXT: %this.addr = alloca ptr, align 4 -// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %registerNo.addr = alloca i32, align 4 +// CHECK-NEXT: %spaceNo.addr = alloca i32, align 4 // CHECK-NEXT: %range.addr = alloca i32, align 4 // CHECK-NEXT: %index.addr = alloca i32, align 4 // CHECK-NEXT: store ptr %this, ptr %this.addr, align 4 -// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %registerNo, ptr %registerNo.addr, align 4 +// CHECK-NEXT: store i32 %spaceNo, ptr %spaceNo.addr, align 4 // CHECK-NEXT: store i32 %range, ptr %range.addr, align 4 // CHECK-NEXT: store i32 %index, ptr %index.addr, align 4 // CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 4 -// CHECK-NEXT: %0 = load i32, ptr %spaceNo.addr, align 4 -// CHECK-NEXT: %1 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %0 = load i32, ptr %registerNo.addr, align 4 +// CHECK-NEXT: %1 = load i32, ptr %spaceNo.addr, align 4 // CHECK-NEXT: %2 = load i32, ptr %range.addr, align 4 // CHECK-NEXT: %3 = load i32, ptr %index.addr, align 4 // CHECK-DXIL-NEXT: %4 = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t( -// CHECK-DXIL-SAME: i32 %0, i32 %1, i32 %2, i32 %3, i1 false) +// CHECK-DXIL-SAME: i32 %1, i32 %0, i32 %2, i32 %3, i1 false) // CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %this1, i32 0, i32 0 // CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 0, 0) %4, ptr %__handle, align 4 // CHECK-NEXT: ret void From 4b25a5ff72b496a265e818fa51d5f0fb90af6b04 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Wed, 9 Apr 2025 21:11:41 -0700 Subject: [PATCH 03/13] clang-format --- clang/lib/Sema/SemaHLSL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 299733f8c107f1..27959f61f1dc31 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3208,7 +3208,7 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { } static bool initVarDeclWithCtor(Sema &S, VarDecl *VD, - MutableArrayRef Args) { + MutableArrayRef Args) { InitializedEntity Entity = InitializedEntity::InitializeVariable(VD); InitializationKind Kind = InitializationKind::CreateDirect( VD->getLocation(), SourceLocation(), SourceLocation()); From 6fb658a603f116f29e635e4802a8d77b896150ff Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 10 Apr 2025 17:31:57 -0700 Subject: [PATCH 04/13] [HLSL] Allow register annotations to specify only `space` Specifying only `space` in a `register` annotation means the compiler should implicitly assign a register slot to the resource from the provided virtual register space. --- clang/include/clang/Basic/Attr.td | 11 ++- clang/lib/CodeGen/CGHLSLRuntime.cpp | 2 +- clang/lib/Sema/SemaHLSL.cpp | 74 +++++++++++-------- .../test/AST/HLSL/resource_binding_attr.hlsl | 4 + .../SemaHLSL/resource_binding_attr_error.hlsl | 4 +- test.ll | 7 ++ 6 files changed, 64 insertions(+), 38 deletions(-) create mode 100644 test.ll diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index fd9e6864855520..1fe37ad4e2d4da 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4751,20 +4751,25 @@ def HLSLResourceBinding: InheritableAttr { private: RegisterType RegType; - unsigned SlotNumber; + int SlotNumber; // -1 if the register slot was not specified unsigned SpaceNumber; public: - void setBinding(RegisterType RT, unsigned SlotNum, unsigned SpaceNum) { + void setBinding(RegisterType RT, int SlotNum, unsigned SpaceNum) { RegType = RT; SlotNumber = SlotNum; SpaceNumber = SpaceNum; } + bool isImplicit() const { + return SlotNumber < 0; + } RegisterType getRegisterType() const { + assert(!isImplicit() && "binding does not have register slot"); return RegType; } unsigned getSlotNumber() const { - return SlotNumber; + assert(!isImplicit() && "binding does not have register slot"); + return (unsigned)SlotNumber; } unsigned getSpaceNumber() const { return SpaceNumber; diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 450213fcec6762..e42bb8e16e80b2 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -261,7 +261,7 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) { BufDecl->getAttr(); // FIXME: handle implicit binding if no binding attribute is found // (llvm/llvm-project#110722) - if (RBA) + if (RBA && !RBA->isImplicit()) initializeBufferFromBinding(CGM, BufGV, RBA->getSlotNumber(), RBA->getSpaceNumber()); } diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 27959f61f1dc31..73b8c198400261 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1529,72 +1529,82 @@ void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) { diag::err_incomplete_type)) return; } - StringRef Space = "space0"; + StringRef Slot = ""; + StringRef Space = ""; + SourceLocation SlotLoc, SpaceLoc; if (!AL.isArgIdent(0)) { Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL << AANT_ArgumentIdentifier; return; } - IdentifierLoc *Loc = AL.getArgAsIdent(0); - StringRef Str = Loc->Ident->getName(); - SourceLocation ArgLoc = Loc->Loc; - SourceLocation SpaceArgLoc; - bool SpecifiedSpace = false; if (AL.getNumArgs() == 2) { - SpecifiedSpace = true; - Slot = Str; + Slot = Loc->Ident->getName(); + SlotLoc = Loc->Loc; + if (!AL.isArgIdent(1)) { Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL << AANT_ArgumentIdentifier; return; } - IdentifierLoc *Loc = AL.getArgAsIdent(1); + Loc = AL.getArgAsIdent(1); Space = Loc->Ident->getName(); - SpaceArgLoc = Loc->Loc; + SpaceLoc = Loc->Loc; } else { - Slot = Str; + StringRef Str = Loc->Ident->getName(); + if (Str.starts_with("space")) { + Space = Str; + SpaceLoc = Loc->Loc; + } else { + Slot = Str; + SlotLoc = Loc->Loc; + Space = "space0"; + } } - RegisterType RegType; - unsigned SlotNum = 0; + RegisterType RegType = RegisterType::SRV; + int SlotNum = -1; unsigned SpaceNum = 0; - // Validate. + // Validate slot if (!Slot.empty()) { if (!convertToRegisterType(Slot, &RegType)) { - Diag(ArgLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1); + Diag(SlotLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1); return; } if (RegType == RegisterType::I) { - Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_i); + Diag(SlotLoc, diag::warn_hlsl_deprecated_register_type_i); return; } - StringRef SlotNumStr = Slot.substr(1); if (SlotNumStr.getAsInteger(10, SlotNum)) { - Diag(ArgLoc, diag::err_hlsl_unsupported_register_number); + Diag(SlotLoc, diag::err_hlsl_unsupported_register_number); return; } } - if (!Space.starts_with("space")) { - Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; - return; - } - StringRef SpaceNumStr = Space.substr(5); - if (SpaceNumStr.getAsInteger(10, SpaceNum)) { - Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; - return; + // Validate space + if (!Space.empty()) { + if (!Space.starts_with("space")) { + Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space; + return; + } + StringRef SpaceNumStr = Space.substr(5); + if (SpaceNumStr.getAsInteger(10, SpaceNum)) { + Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space; + return; + } } - if (!DiagnoseHLSLRegisterAttribute(SemaRef, ArgLoc, TheDecl, RegType, - SpecifiedSpace)) - return; + // If we have slot, diagnose it is the right register type for the decl + if (SlotNum >= 0) + if (!DiagnoseHLSLRegisterAttribute(SemaRef, SlotLoc, TheDecl, RegType, + !SpaceLoc.isInvalid())) + return; HLSLResourceBindingAttr *NewAttr = HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL); @@ -1967,7 +1977,7 @@ void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) { for (const Decl *VD : DefaultCBufferDecls) { const HLSLResourceBindingAttr *RBA = VD->getAttr(); - if (RBA && + if (RBA && !RBA->isImplicit() && RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) { DefaultCBuffer->setHasValidPackoffset(true); break; @@ -3227,7 +3237,7 @@ static bool initVarDeclWithCtor(Sema &S, VarDecl *VD, static bool initGlobalResourceDecl(Sema &S, VarDecl *VD) { HLSLResourceBindingAttr *RBA = VD->getAttr(); - if (!RBA) + if (!RBA || RBA->isImplicit()) // FIXME: add support for implicit binding (llvm/llvm-project#110722) return false; @@ -3310,7 +3320,7 @@ void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) { for (Attr *A : VD->attrs()) { HLSLResourceBindingAttr *RBA = dyn_cast(A); - if (!RBA) + if (!RBA || RBA->isImplicit()) continue; RegisterType RT = RBA->getRegisterType(); diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl b/clang/test/AST/HLSL/resource_binding_attr.hlsl index af43eddc45edd7..c073cd4dc1476a 100644 --- a/clang/test/AST/HLSL/resource_binding_attr.hlsl +++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl @@ -30,6 +30,10 @@ RWBuffer UAV : register(u3); // CHECK: HLSLResourceBindingAttr {{.*}} "u4" "space0" RWBuffer UAV1 : register(u2), UAV2 : register(u4); +// CHECK: VarDecl {{.*}} UAV3 'RWBuffer':'hlsl::RWBuffer' +// CHECK: HLSLResourceBindingAttr {{.*}} "" "space5" +RWBuffer UAV3 : register(space5); + // // Default constants ($Globals) layout annotations diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl index 74aff79f0e37fb..5f0ab660613157 100644 --- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl +++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl @@ -22,8 +22,8 @@ cbuffer c : register(bf, s2) { // expected-error@+1 {{expected identifier}} cbuffer A : register() {} -// expected-error@+1 {{register number should be an integer}} -cbuffer B : register(space1) {} +// expected-error@+1 {{invalid space specifier 'space' used; expected 'space' followed by an integer, like space1}} +cbuffer B : register(space) {} // expected-error@+1 {{wrong argument format for hlsl attribute, use b2 instead}} cbuffer C : register(b 2) {} diff --git a/test.ll b/test.ll new file mode 100644 index 00000000000000..dc674289e3e74e --- /dev/null +++ b/test.ll @@ -0,0 +1,7 @@ +ByteAddressBuffer Buffer0: register(t0); +RWBuffer Buf : register(u0); + +[numthreads(4,1,1)] +void main() { + Buf[0] = 10; +} From c5c7ab8ace5d82a3f84c5b00738b1d7fd3b3b311 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 10 Apr 2025 18:13:35 -0700 Subject: [PATCH 05/13] remove condition - Space is never empty --- clang/lib/Sema/SemaHLSL.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 73b8c198400261..786bfcb3acf7aa 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1588,16 +1588,14 @@ void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) { } // Validate space - if (!Space.empty()) { - if (!Space.starts_with("space")) { - Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space; - return; - } - StringRef SpaceNumStr = Space.substr(5); - if (SpaceNumStr.getAsInteger(10, SpaceNum)) { - Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space; - return; - } + if (!Space.starts_with("space")) { + Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space; + return; + } + StringRef SpaceNumStr = Space.substr(5); + if (SpaceNumStr.getAsInteger(10, SpaceNum)) { + Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space; + return; } // If we have slot, diagnose it is the right register type for the decl From 7084cf1978d01f1d4295e3facacf667b3f020fb1 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 10 Apr 2025 18:16:31 -0700 Subject: [PATCH 06/13] remove unintentionally added file --- test.ll | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 test.ll diff --git a/test.ll b/test.ll deleted file mode 100644 index dc674289e3e74e..00000000000000 --- a/test.ll +++ /dev/null @@ -1,7 +0,0 @@ -ByteAddressBuffer Buffer0: register(t0); -RWBuffer Buf : register(u0); - -[numthreads(4,1,1)] -void main() { - Buf[0] = 10; -} From 192a89df2d64bc5785fe4a8bff99e7f0f0f6199a Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Fri, 11 Apr 2025 10:58:19 -0700 Subject: [PATCH 07/13] fix typo --- clang/test/AST/HLSL/StructuredBuffers-AST.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl index c02a064f7c8533..1efa95942cd359 100644 --- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl @@ -125,7 +125,7 @@ RESOURCE Buffer; // CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr -// Subsctript operators +// Subscript operators // CHECK-SUBSCRIPT: CXXMethodDecl {{.*}} operator[] 'const element_type &(unsigned int) const' // CHECK-SUBSCRIPT-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' From b79e4ddae3485511dd75038a1e2be8210d041969 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Fri, 11 Apr 2025 12:21:09 -0700 Subject: [PATCH 08/13] Handle register(u-1); --- clang/lib/Parse/ParseHLSL.cpp | 11 ++++++++--- clang/test/SemaHLSL/resource_binding_attr_error.hlsl | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp index f4c109f9a81a23..6e8fd56fe5262a 100644 --- a/clang/lib/Parse/ParseHLSL.cpp +++ b/clang/lib/Parse/ParseHLSL.cpp @@ -163,11 +163,16 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, SourceLocation SlotLoc = Tok.getLocation(); ArgExprs.push_back(ParseIdentifierLoc()); - // Add numeric_constant for fix-it. - if (SlotStr.size() == 1 && Tok.is(tok::numeric_constant)) + if (SlotStr.size() == 1) { + if (!Tok.is(tok::numeric_constant)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::numeric_constant; + SkipUntil(tok::r_paren, StopAtSemi); // skip through ) + return; + } + // Add numeric_constant for fix-it. fixSeparateAttrArgAndNumber(SlotStr, SlotLoc, Tok, ArgExprs, *this, Actions.Context, PP); - + } if (Tok.is(tok::comma)) { ConsumeToken(); // consume comma if (!Tok.is(tok::identifier)) { diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl index 5f0ab660613157..d126d25bd94f00 100644 --- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl +++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl @@ -31,6 +31,9 @@ cbuffer C : register(b 2) {} // expected-error@+1 {{wrong argument format for hlsl attribute, use b2 instead}} cbuffer D : register(b 2, space3) {} +// expected-error@+1 {{expected }} +cbuffer E : register(u-1) {}; + // expected-error@+1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}} static MyTemplatedSRV U : register(u5); From ba660203a963aa03fcbd5987fc7956cdb2365438 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Fri, 11 Apr 2025 16:26:11 -0700 Subject: [PATCH 09/13] code review feedback --- clang/lib/CodeGen/CGHLSLBuiltins.cpp | 8 ++++---- clang/lib/Sema/SemaHLSL.cpp | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index dfcade7a074ca2..324e11e9f2051c 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -293,17 +293,17 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, } case Builtin::BI__builtin_hlsl_resource_createhandlefrombinding: { llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType()); - Value *RegisterNoOp = EmitScalarExpr(E->getArg(1)); - Value *SpaceNoOp = EmitScalarExpr(E->getArg(2)); + Value *RegisterOp = EmitScalarExpr(E->getArg(1)); + Value *SpaceOp = EmitScalarExpr(E->getArg(2)); Value *RangeOp = EmitScalarExpr(E->getArg(3)); Value *IndexOp = EmitScalarExpr(E->getArg(4)); // FIXME: NonUniformResourceIndex bit is not yet implemented + // (llvm/llvm-project#135452) Value *NonUniform = llvm::ConstantInt::get(llvm::Type::getInt1Ty(getLLVMContext()), false); return Builder.CreateIntrinsic( HandleTy, CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(), - ArrayRef{SpaceNoOp, RegisterNoOp, RangeOp, IndexOp, - NonUniform}); + ArrayRef{SpaceOp, RegisterOp, RangeOp, IndexOp, NonUniform}); } case Builtin::BI__builtin_hlsl_all: { Value *Op0 = EmitScalarExpr(E->getArg(0)); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 27959f61f1dc31..e65f1795f99050 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3248,8 +3248,8 @@ static bool initGlobalResourceDecl(Sema &S, VarDecl *VD) { return initVarDeclWithCtor(S, VD, Args); } -// Returns true in the initialization has been handled; -// Return false to let Clang handle the default initializaton. +// Returns true if the initialization has been handled. +// Returns false to use default initialization. bool SemaHLSL::ActOnUninitializedVarDecl(VarDecl *VD) { // Objects in the hlsl_constant address space are initialized // externally, so don't synthesize an implicit initializer. @@ -3261,7 +3261,8 @@ bool SemaHLSL::ActOnUninitializedVarDecl(VarDecl *VD) { return false; // FIXME: We currectly support only simple resources - no arrays of resources - // or resources in user defined structs). + // or resources in user defined structs. + // (llvm/llvm-project#133835, llvm/llvm-project#133837) if (VD->getType()->isHLSLResourceRecord()) return initGlobalResourceDecl(SemaRef, VD); From 9fe6d3883863cb2543fc345afd8877ac7cab1b01 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Mon, 21 Apr 2025 16:56:29 -0700 Subject: [PATCH 10/13] Add -Wno-hlsl-implicit-binding to tests --- .../CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl | 2 +- clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl | 2 +- .../CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl index 80bf907180af40..af8ab8a8ad96be 100644 --- a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN: %clang_cc1 -Wno-hlsl-implicit-binding -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL // FIXME: SPIR-V codegen of llvm.spv.resource.handlefrombinding and resource types is not yet implemented // RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl index 8cf1337dcaf872..adf231dedf4cbd 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN: %clang_cc1 -Wno-hlsl-implicit-binding -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL // FIXME: SPIR-V codegen of llvm.spv.resource.handlefrombinding and resource types is not yet implemented // RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl index ec94991ea48016..ea818a737cf74e 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN: %clang_cc1 -Wno-hlsl-implicit-binding -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL // FIXME: SPIR-V codegen of llvm.spv.resource.handlefrombinding and resource types is not yet implemented // RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV From 87f30307a61491b1c4f3a1b52c9d3d8bbb83baf1 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Tue, 22 Apr 2025 10:05:00 -0700 Subject: [PATCH 11/13] Update tests after latest merge from main - add -Wno-hlsl-implicit-binding - add test case with space-only annotation --- clang/lib/Sema/SemaHLSL.cpp | 2 -- clang/test/AST/HLSL/resource_binding_attr.hlsl | 2 +- clang/test/SemaHLSL/resource_binding_implicit.hlsl | 5 ++--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 55638ca0daa58b..cc81d0d104bf21 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1548,13 +1548,11 @@ void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) { if (AL.getNumArgs() == 2) { Slot = Loc->getIdentifierInfo()->getName(); SlotLoc = Loc->getLoc(); - if (!AL.isArgIdent(1)) { Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL << AANT_ArgumentIdentifier; return; } - Loc = AL.getArgAsIdent(1); Space = Loc->getIdentifierInfo()->getName(); SpaceLoc = Loc->getLoc(); diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl b/clang/test/AST/HLSL/resource_binding_attr.hlsl index c073cd4dc1476a..ef75919fc3daf7 100644 --- a/clang/test/AST/HLSL/resource_binding_attr.hlsl +++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -ast-dump -o - %s | FileCheck %s +// RUN: %clang_cc1 -Wno-hlsl-implicit-binding -triple dxil-pc-shadermodel6.3-library -finclude-default-header -ast-dump -o - %s | FileCheck %s // CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 4]]:9 cbuffer CB // CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer diff --git a/clang/test/SemaHLSL/resource_binding_implicit.hlsl b/clang/test/SemaHLSL/resource_binding_implicit.hlsl index 8f0e721c7153fa..ce9f0d1ac364f1 100644 --- a/clang/test/SemaHLSL/resource_binding_implicit.hlsl +++ b/clang/test/SemaHLSL/resource_binding_implicit.hlsl @@ -14,9 +14,8 @@ RWBuffer c; // No warning - explicit binding. RWBuffer d : register(u0); -// TODO: Add this test once #135287 lands -// TODO: ... @+1 {{resource has implicit register binding}} -// TODO: RWBuffer dd : register(space1); +// expected-warning@+1 {{resource has implicit register binding}} +RWBuffer dd : register(space1); // No warning - explicit binding. RWBuffer ddd : register(u3, space4); From 9e338e0349478b3f2e4ea3b05aea111f272e7c62 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Wed, 23 Apr 2025 14:43:38 -0700 Subject: [PATCH 12/13] Switch to std::optional type for the register slot number instead of using -1 --- clang/include/clang/Basic/Attr.td | 8 ++++---- clang/lib/Sema/SemaHLSL.cpp | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index e8b793ad47c694..ade794e0601d6e 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4723,17 +4723,17 @@ def HLSLResourceBinding: InheritableAttr { private: RegisterType RegType; - int SlotNumber; // -1 if the register slot was not specified + std::optional SlotNumber; unsigned SpaceNumber; public: - void setBinding(RegisterType RT, int SlotNum, unsigned SpaceNum) { + void setBinding(RegisterType RT, std::optional SlotNum, unsigned SpaceNum) { RegType = RT; SlotNumber = SlotNum; SpaceNumber = SpaceNum; } bool isImplicit() const { - return SlotNumber < 0; + return !SlotNumber.has_value(); } RegisterType getRegisterType() const { assert(!isImplicit() && "binding does not have register slot"); @@ -4741,7 +4741,7 @@ def HLSLResourceBinding: InheritableAttr { } unsigned getSlotNumber() const { assert(!isImplicit() && "binding does not have register slot"); - return (unsigned)SlotNumber; + return SlotNumber.value(); } unsigned getSpaceNumber() const { return SpaceNumber; diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index cc81d0d104bf21..2bb17f7da20f53 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1569,7 +1569,7 @@ void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) { } RegisterType RegType = RegisterType::SRV; - int SlotNum = -1; + std::optional SlotNum; unsigned SpaceNum = 0; // Validate slot @@ -1583,10 +1583,12 @@ void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) { return; } StringRef SlotNumStr = Slot.substr(1); - if (SlotNumStr.getAsInteger(10, SlotNum)) { + unsigned N; + if (SlotNumStr.getAsInteger(10, N)) { Diag(SlotLoc, diag::err_hlsl_unsupported_register_number); return; } + SlotNum = N; } // Validate space @@ -1601,7 +1603,7 @@ void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) { } // If we have slot, diagnose it is the right register type for the decl - if (SlotNum >= 0) + if (SlotNum.has_value()) if (!DiagnoseHLSLRegisterAttribute(SemaRef, SlotLoc, TheDecl, RegType, !SpaceLoc.isInvalid())) return; From ce5fcc2d72a19dc986adff6cc7f66d0c2edd1109 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Tue, 29 Apr 2025 19:47:14 -0700 Subject: [PATCH 13/13] fix merge & clang-format --- clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 4 ++-- clang/test/AST/HLSL/StructuredBuffers-AST.hlsl | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index bdf2e9ae9d4a4a..35364a4d6f2ac3 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -662,8 +662,8 @@ BuiltinTypeDeclBuilder::addHandleConstructorFromBinding() { .addParam("spaceNo", AST.UnsignedIntTy) .addParam("range", AST.IntTy) .addParam("index", AST.UnsignedIntTy) - .callBuiltin("__builtin_hlsl_resource_handlefrombinding", - HandleType, PH::Handle, PH::_0, PH::_1, PH::_2, PH::_3) + .callBuiltin("__builtin_hlsl_resource_handlefrombinding", HandleType, + PH::Handle, PH::_0, PH::_1, PH::_2, PH::_3) .assign(PH::Handle, PH::LastStmt) .finalize(); } diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl index d4491e8b8be590..63265a00035829 100644 --- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl @@ -166,8 +166,6 @@ RESOURCE Buffer; // Load method -// Load method - // CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int)' // CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' // CHECK-LOAD-NEXT: CompoundStmt