[HLSL] Add resource constructor with implicit binding for global resources (#138976)
Adds constructor for resources with implicit binding and applies it to all resources without binding at the global scope. Adds Clang builtin function `__builtin_hlsl_resource_handlefromimplicitbinding` that gets translated to `llvm.dx|spv.resource.handlefromimplicitbinding` intrinsic calls. Specific bindings are assigned in DXILResourceImplicitBinding pass. Design proposals: https://github.com/llvm/wg-hlsl/blob/main/proposals/0024-implicit-resource-binding.md https://github.com/llvm/wg-hlsl/blob/main/proposals/0025-resource-constructors.md One change from the proposals is that the `orderId` parameter is added onto the constructor. Originally it was supposed to be generated in codegen when the `llvm.dx|spv.resource.handlefromimplicitbinding` call is emitted, but that is not possible because the call is inside a constructor, and the constructor body is generated once per resource type and not resource instance. So the only way to inject instance-based data like `orderId` into the `llvm.dx|spv.resource.handlefromimplicitbinding` call is that it must come in via the constructor argument. Closes #136784
This commit is contained in:
@@ -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];
|
||||
|
||||
@@ -175,6 +175,8 @@ private:
|
||||
// buffer which will be created at the end of the translation unit.
|
||||
llvm::SmallVector<Decl *> DefaultCBufferDecls;
|
||||
|
||||
uint32_t ImplicitBindingNextOrderID = 0;
|
||||
|
||||
private:
|
||||
void collectResourceBindingsOnVarDecl(VarDecl *D);
|
||||
void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
|
||||
@@ -182,6 +184,11 @@ private:
|
||||
void processExplicitBindingsOnDecl(VarDecl *D);
|
||||
|
||||
void diagnoseAvailabilityViolations(TranslationUnitDecl *TU);
|
||||
|
||||
bool initGlobalResourceDecl(VarDecl *VD);
|
||||
uint32_t getNextImplicitBindingOrderID() {
|
||||
return ImplicitBindingNextOrderID++;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
||||
@@ -303,6 +303,21 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
|
||||
HandleTy, CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(),
|
||||
ArrayRef<Value *>{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<Value *>{OrderID, SpaceOp, RangeOp, IndexOp, NonUniform});
|
||||
}
|
||||
case Builtin::BI__builtin_hlsl_all: {
|
||||
Value *Op0 = EmitScalarExpr(E->getArg(0));
|
||||
return Builder.CreateIntrinsic(
|
||||
|
||||
@@ -119,6 +119,8 @@ public:
|
||||
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)
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -76,9 +76,10 @@ public:
|
||||
AccessSpecifier Access = AccessSpecifier::AS_private);
|
||||
BuiltinTypeDeclBuilder &addArraySubscriptOperators();
|
||||
|
||||
// Builtin types methods
|
||||
// Builtin types constructors
|
||||
BuiltinTypeDeclBuilder &addDefaultHandleConstructor();
|
||||
BuiltinTypeDeclBuilder &addHandleConstructorFromBinding();
|
||||
BuiltinTypeDeclBuilder &addHandleConstructorFromImplicitBinding();
|
||||
|
||||
// Builtin types methods
|
||||
BuiltinTypeDeclBuilder &addLoadMethods();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<uint32_t> RegisterSlot;
|
||||
uint32_t SpaceNo = 0;
|
||||
HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
|
||||
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())};
|
||||
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());
|
||||
|
||||
return initVarDeclWithCtor(S, VD, Args);
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -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 {{.*}} <BuiltinFnToFnPtr>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' 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)'
|
||||
|
||||
@@ -125,6 +125,28 @@ RESOURCE<float> Buffer;
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int'
|
||||
// CHECK-NEXT: AlwaysInlineAttr
|
||||
|
||||
// Constructor from implicit binding
|
||||
|
||||
// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]]<element_type> '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]]<element_type>' lvalue implicit this
|
||||
// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefromimplicitbinding'
|
||||
// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
|
||||
// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]<element_type>' 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'
|
||||
|
||||
@@ -92,6 +92,28 @@ RESOURCE<float> Buffer;
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int'
|
||||
// CHECK-NEXT: AlwaysInlineAttr
|
||||
|
||||
// Constructor from implicit binding
|
||||
|
||||
// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]]<element_type> '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]]<element_type>' lvalue implicit this
|
||||
// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefromimplicitbinding'
|
||||
// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
|
||||
// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]<element_type>' 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'
|
||||
|
||||
@@ -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]+]]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<double> C1 constructor
|
||||
// CHECK: define internal void @__cxx_global_var_init.1() #0 {
|
||||
// Buf2 initialization part 1 - global init function that calls RWBuffer<float> 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<float> 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<int> 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<float> 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<int> default C2 constructor that initializes handle to poison
|
||||
// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIiEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
|
||||
|
||||
@@ -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<double> C1 constructor
|
||||
// Buf2 initialization part 1 - global init function that calls RWStructuredBuffer<float> 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<float> 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<float> 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<float> 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<float> 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<float> default C2 constructor that
|
||||
// initializes handle to poison
|
||||
|
||||
@@ -21,7 +21,7 @@ void InitBuf(RWBuffer<int> 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
|
||||
|
||||
|
||||
@@ -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]>;
|
||||
|
||||
Reference in New Issue
Block a user