diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 11b1e247237a7..187d3b5ed24a7 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4819,6 +4819,12 @@ def HLSLResourceHandleFromBinding : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLResourceHandleFromImplicitBinding : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_resource_handlefromimplicitbinding"]; + 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 e340547ff5f45..15182bb27bbdf 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -175,6 +175,8 @@ class SemaHLSL : public SemaBase { // buffer which will be created at the end of the translation unit. llvm::SmallVector DefaultCBufferDecls; + uint32_t ImplicitBindingNextOrderID = 0; + private: void collectResourceBindingsOnVarDecl(VarDecl *D); void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD, @@ -182,6 +184,11 @@ class SemaHLSL : public SemaBase { void processExplicitBindingsOnDecl(VarDecl *D); void diagnoseAvailabilityViolations(TranslationUnitDecl *TU); + + bool initGlobalResourceDecl(VarDecl *VD); + uint32_t getNextImplicitBindingOrderID() { + return ImplicitBindingNextOrderID++; + } }; } // namespace clang diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 5d93df34c66b2..d4a0714da07b3 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -303,6 +303,21 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, HandleTy, CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(), ArrayRef{SpaceOp, RegisterOp, RangeOp, IndexOp, NonUniform}); } + case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: { + llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType()); + Value *SpaceOp = EmitScalarExpr(E->getArg(1)); + Value *RangeOp = EmitScalarExpr(E->getArg(2)); + Value *IndexOp = EmitScalarExpr(E->getArg(3)); + Value *OrderID = 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().getCreateHandleFromImplicitBindingIntrinsic(), + ArrayRef{OrderID, SpaceOp, 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.h b/clang/lib/CodeGen/CGHLSLRuntime.h index 4d6db3f5d9f3e..e40864d8ed854 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -119,6 +119,8 @@ class CGHLSLRuntime { resource_getpointer) GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding, resource_handlefrombinding) + GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromImplicitBinding, + resource_handlefromimplicitbinding) GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, resource_updatecounter) GENERATE_HLSL_INTRINSIC_FUNCTION(GroupMemoryBarrierWithGroupSync, group_memory_barrier_with_group_sync) diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 35364a4d6f2ac..7a561638aebbc 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -668,6 +668,26 @@ BuiltinTypeDeclBuilder::addHandleConstructorFromBinding() { .finalize(); } +BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addHandleConstructorFromImplicitBinding() { + 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("range", AST.IntTy) + .addParam("index", AST.UnsignedIntTy) + .addParam("orderId", AST.UnsignedIntTy) + .callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding", + HandleType, PH::Handle, PH::_0, PH::_1, PH::_2, PH::_3) + .assign(PH::Handle, PH::LastStmt) + .finalize(); +} + BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() { ASTContext &AST = Record->getASTContext(); DeclarationName Subscript = diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h index db617dc53c899..a52e2938104c7 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h @@ -76,9 +76,10 @@ class BuiltinTypeDeclBuilder { AccessSpecifier Access = AccessSpecifier::AS_private); BuiltinTypeDeclBuilder &addArraySubscriptOperators(); - // Builtin types methods + // Builtin types constructors BuiltinTypeDeclBuilder &addDefaultHandleConstructor(); BuiltinTypeDeclBuilder &addHandleConstructorFromBinding(); + BuiltinTypeDeclBuilder &addHandleConstructorFromImplicitBinding(); // Builtin types methods BuiltinTypeDeclBuilder &addLoadMethods(); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index f09232a9db4da..38bde7c28e946 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -132,7 +132,8 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, return BuiltinTypeDeclBuilder(S, Decl) .addHandleMember(RC, IsROV, RawBuffer) .addDefaultHandleConstructor() - .addHandleConstructorFromBinding(); + .addHandleConstructorFromBinding() + .addHandleConstructorFromImplicitBinding(); } // This function is responsible for constructing the constraint expression for diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 744ec439b2393..16f3986179aea 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -2454,6 +2454,20 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { TheCall->setType(ResourceTy); break; } + case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: { + 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.IntTy) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.UnsignedIntTy) || + 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)) @@ -3285,8 +3299,10 @@ static bool initVarDeclWithCtor(Sema &S, VarDecl *VD, VD->getLocation(), SourceLocation(), SourceLocation()); InitializationSequence InitSeq(S, Entity, Kind, Args); - ExprResult Init = InitSeq.Perform(S, Entity, Kind, Args); + if (InitSeq.Failed()) + return false; + ExprResult Init = InitSeq.Perform(S, Entity, Kind, Args); if (!Init.get()) return false; @@ -3296,27 +3312,42 @@ static bool initVarDeclWithCtor(Sema &S, VarDecl *VD, return true; } -static bool initGlobalResourceDecl(Sema &S, VarDecl *VD) { +bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) { + std::optional RegisterSlot; + uint32_t SpaceNo = 0; HLSLResourceBindingAttr *RBA = VD->getAttr(); - if (!RBA || !RBA->hasRegisterSlot()) - // FIXME: add support for implicit binding (llvm/llvm-project#110722) - return false; + if (RBA) { + if (RBA->hasRegisterSlot()) + RegisterSlot = RBA->getSlotNumber(); + SpaceNo = RBA->getSpaceNumber(); + } - ASTContext &AST = S.getASTContext(); + ASTContext &AST = SemaRef.getASTContext(); 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(IntTySize, 1), AST.IntTy, - SourceLocation()), - IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, - SourceLocation())}; - - return initVarDeclWithCtor(S, VD, Args); + IntegerLiteral *RangeSize = IntegerLiteral::Create( + AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation()); + IntegerLiteral *Index = IntegerLiteral::Create( + AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation()); + IntegerLiteral *Space = + IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, SpaceNo), + AST.UnsignedIntTy, SourceLocation()); + + // resource with explicit binding + if (RegisterSlot.has_value()) { + IntegerLiteral *RegSlot = IntegerLiteral::Create( + AST, llvm::APInt(UIntTySize, RegisterSlot.value()), AST.UnsignedIntTy, + SourceLocation()); + Expr *Args[] = {RegSlot, Space, RangeSize, Index}; + return initVarDeclWithCtor(SemaRef, VD, Args); + } + + // resource with implicit binding + IntegerLiteral *OrderId = IntegerLiteral::Create( + AST, llvm::APInt(UIntTySize, getNextImplicitBindingOrderID()), + AST.UnsignedIntTy, SourceLocation()); + Expr *Args[] = {Space, RangeSize, Index, OrderId}; + return initVarDeclWithCtor(SemaRef, VD, Args); } // Returns true if the initialization has been handled. @@ -3334,8 +3365,9 @@ bool SemaHLSL::ActOnUninitializedVarDecl(VarDecl *VD) { // FIXME: We currectly support only simple resources - no arrays of resources // or resources in user defined structs. // (llvm/llvm-project#133835, llvm/llvm-project#133837) - if (VD->getType()->isHLSLResourceRecord()) - return initGlobalResourceDecl(SemaRef, VD); + // Initialize resources at the global scope + if (VD->hasGlobalStorage() && VD->getType()->isHLSLResourceRecord()) + return initGlobalResourceDecl(VD); return false; } diff --git a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl index 5fba939d29cfe..8b9aa99a5314e 100644 --- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl @@ -78,5 +78,27 @@ RESOURCE Buffer; // CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr +// Constructor from implicit binding + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (unsigned int, int, unsigned int, unsigned int)' inline +// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} range 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} index 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} orderId '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_handlefromimplicitbinding' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this +// 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: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'orderId' '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 63265a0003582..f8659313ff19c 100644 --- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl @@ -125,6 +125,28 @@ RESOURCE Buffer; // CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr +// Constructor from implicit binding + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (unsigned int, int, unsigned int, unsigned int)' inline +// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} range 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} index 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} orderId '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_handlefromimplicitbinding' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// 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: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'orderId' 'unsigned int' +// CHECK-NEXT: AlwaysInlineAttr + // Subscript operators // CHECK-SUBSCRIPT: CXXMethodDecl {{.*}} operator[] 'const hlsl_device element_type &(unsigned int) const' diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl index 6074c1e8bcdd2..dad1ef17a1f86 100644 --- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl @@ -92,6 +92,28 @@ RESOURCE Buffer; // CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr +// Constructor from implicit binding + +// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (unsigned int, int, unsigned int, unsigned int)' inline +// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} range 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} index 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} orderId '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_handlefromimplicitbinding' +// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle +// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// 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: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'orderId' 'unsigned int' +// CHECK-NEXT: AlwaysInlineAttr + // Subsctript operators // CHECK: CXXMethodDecl {{.*}} operator[] 'const hlsl_device element_type &(unsigned int) const' diff --git a/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl b/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl index b798c2a6d6c4b..1d451acfc6214 100644 --- a/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl +++ b/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl @@ -33,7 +33,7 @@ void SecondEntry() {} // Verify the constructor is alwaysinline // NOINLINE: ; Function Attrs: {{.*}}alwaysinline -// NOINLINE-NEXT: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ev({{.*}} [[CtorAttr:\#[0-9]+]] +// NOINLINE-NEXT: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ejijj({{.*}} [[CtorAttr:\#[0-9]+]] // NOINLINE: ; Function Attrs: {{.*}}alwaysinline // NOINLINE-NEXT: define internal void @_GLOBAL__sub_I_GlobalConstructorLib.hlsl() [[InitAttr:\#[0-9]+]] diff --git a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl index 40a2bcb1a7418..5f844fcfe4121 100644 --- a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl @@ -38,11 +38,16 @@ export void foo() { // CHECK: call void @_ZN4hlsl17ByteAddressBufferC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) // CHECK-SAME: %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) -// 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() +// Buf2 initialization part 1 - global init function that calls RWByteAddressBuffer C1 constructor with implicit binding +// CHECK: define internal void @__cxx_global_var_init.1() #0 { // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_ZN4hlsl19RWByteAddressBufferC1Ev(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf2) +// CHECK-NEXT: call void @_ZN4hlsl19RWByteAddressBufferC1Ejijj(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf2, +// CHECK-SAME: i32 noundef 0, i32 noundef 1, i32 noundef 0, i32 noundef 0) + +// Buf2 initialization part 2 - body of RWByteAddressBuffer C1 constructor with implicit binding that calls the C2 constructor +// CHECK: define linkonce_odr void @_ZN4hlsl19RWByteAddressBufferC1Ejijj(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId) +// CHECK: call void @_ZN4hlsl19RWByteAddressBufferC2Ejijj(ptr noundef nonnull align 4 dereferenceable(4) %this1, i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3) #4 // Buf3 initialization part 1 - local variable declared in function foo() is initialized by // RasterizerOrderedByteAddressBuffer C1 default constructor @@ -65,7 +70,14 @@ export void foo() { // CHECK-DXIL-SAME: i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false) // CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::ByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0 // CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 0, 0) %[[HANDLE]], ptr %__handle, align 4 -// CHECK-NEXT: ret void + +// Buf2 initialization part 3 - body of RWByteAddressBuffer C2 constructor with implicit binding that initializes +// handle with @llvm.dx.resource.handlefromimplicitbinding +// CHECK: define linkonce_odr void @_ZN4hlsl19RWByteAddressBufferC2Ejijj(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId) unnamed_addr #1 align 2 { +// CHECK: %[[HANDLE:.*]] = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_i8_1_0t(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false) +// CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::RWByteAddressBuffer", ptr %this1, i32 0, i32 0 +// CHECK-NEXT: store target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], ptr %__handle, align 4 // Buf3 initialization part 3 - body of RasterizerOrderedByteAddressBuffer default C2 constructor that // initializes handle to poison diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl index d80438120b2f0..ad8ebdf7d8c85 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl @@ -38,11 +38,16 @@ export void foo() { // CHECK: call void @_ZN4hlsl8RWBufferIfEC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) // CHECK-SAME: %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) -// 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 { +// Buf2 initialization part 1 - global init function that calls RWBuffer C1 constructor with implicit binding +// CHECK: define internal void @__cxx_global_var_init.1() // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIdEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf2) +// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIdEC1Ejijj(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf2, +// CHECK-SAME: i32 noundef 0, i32 noundef 1, i32 noundef 0, i32 noundef 0) + +// Buf2 initialization part 2 - body of RWBuffer C1 constructor with implicit binding that calls the C2 constructor +// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIdEC1Ejijj(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId) +// CHECK: call void @_ZN4hlsl8RWBufferIdEC2Ejijj(ptr noundef nonnull align 4 dereferenceable(4) %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) #4 // Buf3 initialization part 1 - local variable declared in function foo() is initialized by RWBuffer C1 default constructor // CHECK: define void @_Z3foov() @@ -62,7 +67,14 @@ export void foo() { // CHECK-DXIL-SAME: i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false) // CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer", ptr %{{.*}}, i32 0, i32 0 // CHECK-DXIL-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %[[HANDLE]], ptr %__handle, align 4 -// CHECK-NEXT: ret void + +// Buf2 initialization part 3 - body of RWBuffer C2 constructor with implicit binding that initializes +// handle with @llvm.dx.resource.handlefromimplicitbinding +// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIdEC2Ejijj(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId) unnamed_addr #1 align 2 { +// CHECK: %[[HANDLE:.*]] = call target("dx.TypedBuffer", double, 1, 0, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.TypedBuffer_f64_1_0_0t(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false) +// CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer.0", ptr %{{.*}}, i32 0, i32 0 +// CHECK-NEXT: store target("dx.TypedBuffer", double, 1, 0, 0) %[[HANDLE]], ptr %__handle, align 4 // 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) diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl index ffc7d8c64ff51..34ce676a02f83 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl @@ -39,11 +39,18 @@ export void foo() { // CHECK: call void @_ZN4hlsl16StructuredBufferIfEC2Ejjij(ptr noundef nonnull align 4 dereferenceable(4) // CHECK-SAME: %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) -// Buf2 initialization part 1 - FIXME: constructor with implicit binding does not exist yet; -// the global init function currently calls the default RWStructuredBufer C1 constructor +// Buf2 initialization part 1 - global init function that calls RWStructuredBuffer C1 constructor with +// implicit binding // 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-NEXT: call void @_ZN4hlsl18RWStructuredBufferIfEC1Ejijj(ptr noundef nonnull align 4 dereferenceable(4) @_ZL4Buf2, +// CHECK-SAME: i32 noundef 0, i32 noundef 1, i32 noundef 0, i32 noundef 0) + +// Buf2 initialization part 2 - body of RWStructuredBuffer C1 constructor with implicit binding that calls the C2 constructor +// CHECK: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC1Ejijj(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId) +// CHECK: call void @_ZN4hlsl18RWStructuredBufferIfEC2Ejijj(ptr noundef nonnull align 4 dereferenceable(4) +// CHECK-SAME; %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) #4 // Buf3 initialization part 1 - local variable declared in function foo() is initialized by // AppendStructuredBuffer C1 default constructor @@ -56,7 +63,6 @@ export void foo() { // the default C2 constructor // CHECK: define linkonce_odr void @_ZN4hlsl22AppendStructuredBufferIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) // CHECK: call void @_ZN4hlsl22AppendStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %{{.*}}) -// CHECK-NEXT: ret void // Buf1 initialization part 3 - body of AppendStructuredBuffer C2 constructor with explicit binding // that initializes handle with @llvm.dx.resource.handlefrombinding @@ -66,7 +72,14 @@ export void foo() { // CHECK-SAME: i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false) // CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %{{.*}}, i32 0, i32 0 // CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 0, 0) %[[HANDLE]], ptr %__handle, align 4 -// CHECK-NEXT: ret void + +// Buf2 initialization part 3 - body of RWStructuredBuffer C2 constructor with implicit binding that initializes +// handle with @llvm.dx.resource.handlefromimplicitbinding +// CHECK: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC2Ejijj(ptr noundef nonnull align 4 dereferenceable(4) %this, +// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, i32 noundef %orderId) unnamed_addr #1 align 2 { +// CHECK: %[[HANDLE:.*]] = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f32_1_0t(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i1 false) +// CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer", ptr %{{.*}}, i32 0, i32 0 +// CHECK-NEXT: store target("dx.RawBuffer", float, 1, 0) %[[HANDLE]], ptr %__handle, align 4 // Buf3 initialization part 3 - body of AppendStructuredBuffer default C2 constructor that // initializes handle to poison diff --git a/clang/test/CodeGenHLSL/static-local-ctor.hlsl b/clang/test/CodeGenHLSL/static-local-ctor.hlsl index 7aeb5e987d6b2..474bcf1aff6ac 100644 --- a/clang/test/CodeGenHLSL/static-local-ctor.hlsl +++ b/clang/test/CodeGenHLSL/static-local-ctor.hlsl @@ -21,7 +21,7 @@ void InitBuf(RWBuffer buf) { // CHECK-NEXT: br i1 [[Tmp3]] // CHECK-NOT: _Init_thread_header // CHECK: init.check: -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1Ev +// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1Ejijj // CHECK-NEXT: store i8 1, ptr @_ZGVZ4mainvE5mybuf // CHECK-NOT: _Init_thread_footer diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index 404467781b4d0..8d984d6ce58df 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -119,6 +119,11 @@ let TargetPrefix = "spv" in { [llvm_any_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i1_ty], [IntrNoMem]>; + def int_spv_resource_handlefromimplicitbinding + : DefaultAttrsIntrinsic< + [llvm_any_ty], + [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i1_ty], + [IntrNoMem]>; def int_spv_firstbituhigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>; def int_spv_firstbitshigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>;