diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index b5ddca0fe2ca5..4df330ed87120 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -260,11 +260,6 @@ class SemaHLSL : public SemaBase { bool initGlobalResourceDecl(VarDecl *VD); bool initGlobalResourceArrayDecl(VarDecl *VD); - void createResourceRecordCtorArgs(const Type *ResourceTy, StringRef VarName, - HLSLResourceBindingAttr *RBA, - HLSLVkBindingAttr *VkBinding, - uint32_t ArrayIndex, - llvm::SmallVectorImpl &Args); }; } // namespace clang diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index afee1198e0988..49bc408a1b305 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "CGHLSLRuntime.h" +#include "Address.h" #include "CGDebugInfo.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" @@ -39,6 +40,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" #include +#include using namespace clang; using namespace CodeGen; @@ -111,37 +113,6 @@ static int getTotalArraySize(ASTContext &AST, const clang::Type *Ty) { return AST.getConstantArrayElementCount(cast(Ty)); } -// Find constructor decl for a specific resource record type and binding -// (implicit vs. explicit). The constructor has 5 parameters. -// For explicit binding the signature is: -// void(unsigned, unsigned, int, unsigned, const char *). -// For implicit binding the signature is: -// void(unsigned, int, unsigned, unsigned, const char *). -static CXXConstructorDecl *findResourceConstructorDecl(ASTContext &AST, - QualType ResTy, - bool ExplicitBinding) { - std::array ExpParmTypes = { - AST.UnsignedIntTy, AST.UnsignedIntTy, AST.UnsignedIntTy, - AST.UnsignedIntTy, AST.getPointerType(AST.CharTy.withConst())}; - ExpParmTypes[ExplicitBinding ? 2 : 1] = AST.IntTy; - - CXXRecordDecl *ResDecl = ResTy->getAsCXXRecordDecl(); - for (auto *Ctor : ResDecl->ctors()) { - if (Ctor->getNumParams() != ExpParmTypes.size()) - continue; - auto *ParmIt = Ctor->param_begin(); - auto ExpTyIt = ExpParmTypes.begin(); - for (; ParmIt != Ctor->param_end() && ExpTyIt != ExpParmTypes.end(); - ++ParmIt, ++ExpTyIt) { - if ((*ParmIt)->getType() != *ExpTyIt) - break; - } - if (ParmIt == Ctor->param_end()) - return Ctor; - } - llvm_unreachable("did not find constructor for resource class"); -} - static Value *buildNameForResource(llvm::StringRef BaseName, CodeGenModule &CGM) { llvm::SmallString<64> GlobalName = {BaseName, ".str"}; @@ -149,14 +120,22 @@ static Value *buildNameForResource(llvm::StringRef BaseName, .getPointer(); } -static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD, - llvm::Value *ThisPtr, llvm::Value *Range, - llvm::Value *Index, StringRef Name, - HLSLResourceBindingAttr *RBA, - HLSLVkBindingAttr *VkBinding, - CallArgList &Args) { +static CXXMethodDecl *lookupMethod(CXXRecordDecl *Record, StringRef Name, + StorageClass SC = SC_None) { + for (auto *Method : Record->methods()) { + if (Method->getStorageClass() == SC && Method->getName() == Name) + return Method; + } + return nullptr; +} + +static CXXMethodDecl *lookupResourceInitMethodAndSetupArgs( + CodeGenModule &CGM, CXXRecordDecl *ResourceDecl, llvm::Value *Range, + llvm::Value *Index, StringRef Name, HLSLResourceBindingAttr *RBA, + HLSLVkBindingAttr *VkBinding, CallArgList &Args) { assert((VkBinding || RBA) && "at least one a binding attribute expected"); + ASTContext &AST = CGM.getContext(); std::optional RegisterSlot; uint32_t SpaceNo = 0; if (VkBinding) { @@ -168,44 +147,57 @@ static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD, SpaceNo = RBA->getSpaceNumber(); } - ASTContext &AST = CD->getASTContext(); + CXXMethodDecl *CreateMethod = nullptr; Value *NameStr = buildNameForResource(Name, CGM); Value *Space = llvm::ConstantInt::get(CGM.IntTy, SpaceNo); - Args.add(RValue::get(ThisPtr), CD->getThisType()); if (RegisterSlot.has_value()) { // explicit binding auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RegisterSlot.value()); Args.add(RValue::get(RegSlot), AST.UnsignedIntTy); - Args.add(RValue::get(Space), AST.UnsignedIntTy); - Args.add(RValue::get(Range), AST.IntTy); - Args.add(RValue::get(Index), AST.UnsignedIntTy); - + CreateMethod = lookupMethod(ResourceDecl, "__createFromBinding", SC_Static); } else { // implicit binding - assert(RBA && "missing implicit binding attribute"); auto *OrderID = llvm::ConstantInt::get(CGM.IntTy, RBA->getImplicitBindingOrderID()); - Args.add(RValue::get(Space), AST.UnsignedIntTy); - Args.add(RValue::get(Range), AST.IntTy); - Args.add(RValue::get(Index), AST.UnsignedIntTy); Args.add(RValue::get(OrderID), AST.UnsignedIntTy); + CreateMethod = + lookupMethod(ResourceDecl, "__createFromImplicitBinding", SC_Static); } + Args.add(RValue::get(Space), AST.UnsignedIntTy); + Args.add(RValue::get(Range), AST.IntTy); + Args.add(RValue::get(Index), AST.UnsignedIntTy); Args.add(RValue::get(NameStr), AST.getPointerType(AST.CharTy.withConst())); + + return CreateMethod; +} + +static void callResourceInitMethod(CodeGenFunction &CGF, + CXXMethodDecl *CreateMethod, + CallArgList &Args, Address ReturnAddress) { + llvm::Constant *CalleeFn = CGF.CGM.GetAddrOfFunction(CreateMethod); + const FunctionProtoType *Proto = + CreateMethod->getType()->getAs(); + const CGFunctionInfo &FnInfo = + CGF.CGM.getTypes().arrangeFreeFunctionCall(Args, Proto, false); + ReturnValueSlot ReturnValue(ReturnAddress, false); + CGCallee Callee(CGCalleeInfo(Proto), CalleeFn); + CGF.EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr); } // Initializes local resource array variable. For multi-dimensional arrays it // calls itself recursively to initialize its sub-arrays. The Index used in the // resource constructor calls will begin at StartIndex and will be incremented // for each array element. The last used resource Index is returned to the -// caller. -static Value *initializeLocalResourceArray( - CodeGenFunction &CGF, AggValueSlot &ValueSlot, - const ConstantArrayType *ArrayTy, CXXConstructorDecl *CD, +// caller. If the function returns std::nullopt, it indicates an error. +static std::optional initializeLocalResourceArray( + CodeGenFunction &CGF, CXXRecordDecl *ResourceDecl, + const ConstantArrayType *ArrayTy, AggValueSlot &ValueSlot, llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName, HLSLResourceBindingAttr *RBA, HLSLVkBindingAttr *VkBinding, ArrayRef PrevGEPIndices, SourceLocation ArraySubsExprLoc) { + ASTContext &AST = CGF.getContext(); llvm::IntegerType *IntTy = CGF.CGM.IntTy; llvm::Value *Index = StartIndex; llvm::Value *One = llvm::ConstantInt::get(IntTy, 1); @@ -226,16 +218,19 @@ static Value *initializeLocalResourceArray( Index = CGF.Builder.CreateAdd(Index, One); GEPIndices.back() = llvm::ConstantInt::get(IntTy, I); } - Index = initializeLocalResourceArray( - CGF, ValueSlot, SubArrayTy, CD, Range, Index, ResourceName, RBA, - VkBinding, GEPIndices, ArraySubsExprLoc); + std::optional MaybeIndex = initializeLocalResourceArray( + CGF, ResourceDecl, SubArrayTy, ValueSlot, Range, Index, ResourceName, + RBA, VkBinding, GEPIndices, ArraySubsExprLoc); + if (!MaybeIndex) + return std::nullopt; + Index = *MaybeIndex; } return Index; } // For array of resources, initialize each resource in the array. llvm::Type *Ty = CGF.ConvertTypeForMem(ElemType); - CharUnits ElemSize = CD->getASTContext().getTypeSizeInChars(ElemType); + CharUnits ElemSize = AST.getTypeSizeInChars(ElemType); CharUnits Align = TmpArrayAddr.getAlignment().alignmentOfArrayElement(ElemSize); @@ -244,16 +239,21 @@ static Value *initializeLocalResourceArray( Index = CGF.Builder.CreateAdd(Index, One); GEPIndices.back() = llvm::ConstantInt::get(IntTy, I); } - Address ThisAddress = + Address ReturnAddress = CGF.Builder.CreateGEP(TmpArrayAddr, GEPIndices, Ty, Align); - llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo(ThisAddress, ElemType); CallArgList Args; - createResourceCtorArgs(CGF.CGM, CD, ThisPtr, Range, Index, ResourceName, - RBA, VkBinding, Args); - CGF.EmitCXXConstructorCall(CD, Ctor_Complete, false, false, ThisAddress, - Args, ValueSlot.mayOverlap(), ArraySubsExprLoc, - ValueSlot.isSanitizerChecked()); + CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs( + CGF.CGM, ResourceDecl, Range, Index, ResourceName, RBA, VkBinding, + Args); + + if (!CreateMethod) + // This can happen if someone creates an array of structs that looks like + // an HLSL resource record array but it does not have the required static + // create method. No binding will be generated for it. + return std::nullopt; + + callResourceInitMethod(CGF, CreateMethod, Args, ReturnAddress); } return Index; } @@ -969,11 +969,6 @@ std::optional CGHLSLRuntime::emitResourceArraySubscriptExpr( QualType ResourceTy = ResultTy->isArrayType() ? AST.getBaseElementType(ResultTy) : ResultTy; - // Lookup the resource class constructor based on the resource type and - // binding. - CXXConstructorDecl *CD = findResourceConstructorDecl( - AST, ResourceTy, VkBinding || RBA->hasRegisterSlot()); - // Create a temporary variable for the result, which is either going // to be a single resource instance or a local array of resources (we need to // return an LValue). @@ -986,7 +981,6 @@ std::optional CGHLSLRuntime::emitResourceArraySubscriptExpr( TmpVar, Qualifiers(), AggValueSlot::IsDestructed_t(true), AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t(false), AggValueSlot::DoesNotOverlap); - Address TmpVarAddress = ValueSlot.getAddress(); // Calculate total array size (= range size). llvm::Value *Range = @@ -995,27 +989,30 @@ std::optional CGHLSLRuntime::emitResourceArraySubscriptExpr( // If the result of the subscript operation is a single resource, call the // constructor. if (ResultTy == ResourceTy) { - QualType ThisType = CD->getThisType()->getPointeeType(); - llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo(TmpVarAddress, ThisType); - - // Assemble the constructor parameters. CallArgList Args; - createResourceCtorArgs(CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName(), - RBA, VkBinding, Args); - // Call the constructor. - CGF.EmitCXXConstructorCall(CD, Ctor_Complete, false, false, TmpVarAddress, - Args, ValueSlot.mayOverlap(), - ArraySubsExpr->getExprLoc(), - ValueSlot.isSanitizerChecked()); + CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs( + CGF.CGM, ResourceTy->getAsCXXRecordDecl(), Range, Index, + ArrayDecl->getName(), RBA, VkBinding, Args); + + if (!CreateMethod) + // This can happen if someone creates an array of structs that looks like + // an HLSL resource record array but it does not have the required static + // create method. No binding will be generated for it. + return std::nullopt; + + callResourceInitMethod(CGF, CreateMethod, Args, ValueSlot.getAddress()); + } else { // The result of the subscript operation is a local resource array which // needs to be initialized. const ConstantArrayType *ArrayTy = cast(ResultTy.getTypePtr()); - initializeLocalResourceArray(CGF, ValueSlot, ArrayTy, CD, Range, Index, - ArrayDecl->getName(), RBA, VkBinding, - {llvm::ConstantInt::get(CGM.IntTy, 0)}, - ArraySubsExpr->getExprLoc()); + std::optional EndIndex = initializeLocalResourceArray( + CGF, ResourceTy->getAsCXXRecordDecl(), ArrayTy, ValueSlot, Range, Index, + ArrayDecl->getName(), RBA, VkBinding, + {llvm::ConstantInt::get(CGM.IntTy, 0)}, ArraySubsExpr->getExprLoc()); + if (!EndIndex) + return std::nullopt; } return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl); } diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 983efaf798b87..55be036207eec 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3793,55 +3793,6 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { deduceAddressSpace(VD); } -void SemaHLSL::createResourceRecordCtorArgs( - const Type *ResourceTy, StringRef VarName, HLSLResourceBindingAttr *RBA, - HLSLVkBindingAttr *VkBinding, uint32_t ArrayIndex, - llvm::SmallVectorImpl &Args) { - std::optional RegisterSlot; - uint32_t SpaceNo = 0; - if (VkBinding) { - RegisterSlot = VkBinding->getBinding(); - SpaceNo = VkBinding->getSet(); - } else if (RBA) { - if (RBA->hasRegisterSlot()) - RegisterSlot = RBA->getSlotNumber(); - SpaceNo = RBA->getSpaceNumber(); - } - - ASTContext &AST = SemaRef.getASTContext(); - uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy); - uint64_t IntTySize = AST.getTypeSize(AST.IntTy); - IntegerLiteral *RangeSize = IntegerLiteral::Create( - AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation()); - IntegerLiteral *Index = - IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, ArrayIndex), - AST.UnsignedIntTy, SourceLocation()); - IntegerLiteral *Space = - IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, SpaceNo), - AST.UnsignedIntTy, SourceLocation()); - StringLiteral *Name = StringLiteral::Create( - AST, VarName, StringLiteralKind::Ordinary, false, - AST.getStringLiteralArrayType(AST.CharTy.withConst(), VarName.size()), - SourceLocation()); - - // resource with explicit binding - if (RegisterSlot.has_value()) { - IntegerLiteral *RegSlot = IntegerLiteral::Create( - AST, llvm::APInt(UIntTySize, RegisterSlot.value()), AST.UnsignedIntTy, - SourceLocation()); - Args.append({RegSlot, Space, RangeSize, Index, Name}); - } else { - // resource with implicit binding - uint32_t OrderID = (RBA && RBA->hasImplicitBindingOrderID()) - ? RBA->getImplicitBindingOrderID() - : getNextImplicitBindingOrderID(); - IntegerLiteral *OrderId = - IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, OrderID), - AST.UnsignedIntTy, SourceLocation()); - Args.append({Space, RangeSize, Index, OrderId, Name}); - } -} - bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) { assert(VD->getType()->isHLSLResourceRecord() && "expected resource record type"); @@ -3951,28 +3902,39 @@ bool SemaHLSL::initGlobalResourceArrayDecl(VarDecl *VD) { // Individual resources in a resource array are not initialized here. They // are initialized later on during codegen when the individual resources are - // accessed. Codegen will emit a call to the resource constructor with the - // specified array index. We need to make sure though that the constructor + // accessed. Codegen will emit a call to the resource initialization method + // with the specified array index. We need to make sure though that the method // for the specific resource type is instantiated, so codegen can emit a call // to it when the array element is accessed. - SmallVector Args; - QualType ResElementTy = VD->getASTContext().getBaseElementType(VD->getType()); - createResourceRecordCtorArgs(ResElementTy.getTypePtr(), VD->getName(), - VD->getAttr(), - VD->getAttr(), 0, Args); - SourceLocation Loc = VD->getLocation(); - InitializedEntity Entity = - InitializedEntity::InitializeTemporary(ResElementTy); - InitializationKind Kind = InitializationKind::CreateDirect(Loc, Loc, Loc); - InitializationSequence InitSeq(SemaRef, Entity, Kind, Args); - if (InitSeq.Failed()) + // Find correct initialization method based on the resource binding + // information. + ASTContext &AST = SemaRef.getASTContext(); + QualType ResElementTy = AST.getBaseElementType(VD->getType()); + CXXRecordDecl *ResourceDecl = ResElementTy->getAsCXXRecordDecl(); + + HLSLResourceBindingAttr *RBA = VD->getAttr(); + HLSLVkBindingAttr *VkBinding = VD->getAttr(); + CXXMethodDecl *CreateMethod = nullptr; + + if (VkBinding || (RBA && RBA->hasRegisterSlot())) + // Resource has explicit binding. + CreateMethod = lookupMethod(SemaRef, ResourceDecl, "__createFromBinding", + VD->getLocation()); + else + // Resource has implicit binding. + CreateMethod = + lookupMethod(SemaRef, ResourceDecl, "__createFromImplicitBinding", + VD->getLocation()); + + if (!CreateMethod) return false; - // This takes care of instantiating and emitting of the constructor that will - // be called from codegen when the array is accessed. - ExprResult OneResInit = InitSeq.Perform(SemaRef, Entity, Kind, Args); - return !OneResInit.isInvalid(); + // Make sure the create method template is instantiated and emitted. + if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation()) + SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod, + true); + return true; } // Returns true if the initialization has been handled. diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl b/clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl index bbd162e3aad20..f17cf12945e4a 100644 --- a/clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl +++ b/clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl @@ -1,17 +1,15 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \ -// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s +// RUN: -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s // CHECK: @[[BufA:.*]] = private unnamed_addr constant [2 x i8] c"A\00", align 1 RWBuffer A[4][3] : register(u2); RWStructuredBuffer Out; -// Make sure A[GI.x][GI.y] is translated to a RWBuffer constructor call with range 12 and dynamically calculated index +// Make sure A[GI.x][GI.y] is translated to a RWBuffer::__createFromBinding call +// with range 12 and dynamically calculated index -// NOTE: -// Constructor call for explicit binding has "jjij" in the mangled name and the arguments are (register, space, range_size, index, name). - -// CHECK: define internal void @_Z4mainDv3_j(<3 x i32> noundef %GI) +// CHECK: define internal void @main(unsigned int vector[3])(<3 x i32> noundef %GI) // CHECK: %[[GI_alloca:.*]] = alloca <3 x i32>, align 16 // CHECK: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer // CHECK: store <3 x i32> %GI, ptr %[[GI_alloca]] @@ -22,7 +20,9 @@ RWStructuredBuffer Out; // CHECK: %[[GI_x:.*]] = extractelement <3 x i32> %[[GI]], i32 0 // CHECK: %[[Tmp1:.*]] = mul i32 %[[GI_x]], 3 // CHECK: %[[Index:.*]] = add i32 %[[GI_y]], %[[Tmp1]] -// CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 2, i32 noundef 0, i32 noundef 12, i32 noundef %[[Index]], ptr noundef @A.str) +// CHECK: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Tmp0]], +// CHECK-SAME: i32 noundef 2, i32 noundef 0, i32 noundef 12, i32 noundef %[[Index]], ptr noundef @A.str) [numthreads(4,1,1)] void main(uint3 GI : SV_GroupThreadID) { Out[0] = A[GI.x][GI.y][0]; diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl b/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl index 36871f9a63b3f..1a05897b9e70b 100644 --- a/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl +++ b/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \ -// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s +// RUN: -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s // RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute \ -// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s +// RUN: -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s // CHECK: @[[BufB:.*]] = private unnamed_addr constant [2 x i8] c"B\00", align 1 // CHECK: @[[BufC:.*]] = private unnamed_addr constant [2 x i8] c"C\00", align 1 @@ -17,30 +17,30 @@ RWStructuredBuffer Out; [numthreads(4,1,1)] void main() { - // CHECK: define internal{{.*}} void @_Z4mainv() + // CHECK: define internal{{.*}} void @main() // CHECK: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer // CHECK: %[[Tmp1:.*]] = alloca %"class.hlsl::RWBuffer // CHECK: %[[Tmp2:.*]] = alloca %"class.hlsl::RWBuffer // CHECK: %[[Tmp3:.*]] = alloca %"class.hlsl::RWBuffer - // NOTE: - // Constructor call for explicit binding has "jjij" in the mangled name and the arguments are (register, space, range_size, index, name). - // For implicit binding the constructor has "jijj" in the mangled name and the arguments are (space, range_size, index, order_id, name). - // The range_size can be -1 for unbounded arrays, and that is the only signed int in the signature. - // The order_id argument is a sequential number that is assigned to resources with implicit binding and corresponds to the order in which - // the resources were declared. It is needed because implicit bindings are assigned later on in an LLVM pass that needs to know the order - // of the resource declarations. - - // Make sure that B[3][2] is translated to a RWBuffer constructor call for explicit binding (u2, space0) with range 16 and index 14 - // CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 2, i32 noundef 0, i32 noundef 16, i32 noundef 14, ptr noundef @[[BufB]]) - - // Make sure that C[1][0][3] is translated to a RWBuffer constructor call for explicit binding (u10, space1) with range 20 and index 13 - // CHECK: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp1]], i32 noundef 10, i32 noundef 1, i32 noundef 20, i32 noundef 13, ptr noundef @[[BufC]]) - - // Make sure that D[9][2] is translated to a RWBuffer constructor call for implicit binding (u18, space0) with range 50 and index 47 - // CHECK: call void @_ZN4hlsl8RWBufferIjEC1EjijjPKc(ptr {{.*}} %[[Tmp2]], i32 noundef 0, i32 noundef 50, i32 noundef 47, i32 noundef 0, ptr noundef @[[BufD]]) - - // Make sure that the second B[3][2] is translated to the same a RWBuffer constructor call as the first B[3][2] subscript - // CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp3]], i32 noundef 2, i32 noundef 0, i32 noundef 16, i32 noundef 14, ptr noundef @[[BufB]]) + // Make sure that B[3][2] is translated to a RWBuffer::__createFromBinding call (u2, space0) with range 16 and index 14 + // CHECK: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Tmp0]], + // CHECK-SAME: i32 noundef 2, i32 noundef 0, i32 noundef 16, i32 noundef 14, ptr noundef @[[BufB]]) + + // Make sure that C[1][0][3] is translated to a RWBuffer::__createFromBinding call (u10, space1) with range 20 and index 13 + // CHECK: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.0") align {{(4|8)}} %[[Tmp1]], + // CHECK-SAME: i32 noundef 10, i32 noundef 1, i32 noundef 20, i32 noundef 13, ptr noundef @[[BufC]]) + + // Make sure that D[9][2] is translated to a RWBuffer::__createFromImplicitBinding call with range 50 and index 47 + // CHECK: call void @hlsl::RWBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.1") align {{(4|8)}} %[[Tmp2]], + // CHECK-SAME: i32 noundef 0, i32 noundef 0, i32 noundef 50, i32 noundef 47, ptr noundef @[[BufD]]) + + // Make sure that the second B[3][2] is translated to the same RWBuffer::__createFromBinding call as the first B[3][2] subscript + // CHECK: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // CHECK-SAME: (ptr {{.*}} writable sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Tmp3]], + // CHECK-SAME: i32 noundef 2, i32 noundef 0, i32 noundef 16, i32 noundef 14, ptr noundef @[[BufB]]) Out[0] = B[3][2][0] + (float)C[1][0][3][0] + (float)D[9][2][0] + B[3][2][1]; } diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-subarray-many.hlsl b/clang/test/CodeGenHLSL/resources/res-array-global-subarray-many.hlsl index 7c52c7116f3d9..036feec39f1dd 100644 --- a/clang/test/CodeGenHLSL/resources/res-array-global-subarray-many.hlsl +++ b/clang/test/CodeGenHLSL/resources/res-array-global-subarray-many.hlsl @@ -1,28 +1,24 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \ -// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s +// RUN: -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s // CHECK: @[[BufA:.*]] = private unnamed_addr constant [2 x i8] c"A\00", align 1 RWBuffer A[5][4][3][2] : register(u10, space2); RWStructuredBuffer Out; -// CHECK: define {{.*}} float @_Z3fooA3_A2_N4hlsl8RWBufferIfEE(ptr noundef byval([3 x [2 x %"class.hlsl::RWBuffer"]]) align 4 %Arr) +// CHECK: define {{.*}} float @foo(hlsl::RWBuffer [3][2]) +// CHECK-SAME: (ptr noundef byval([3 x [2 x %"class.hlsl::RWBuffer"]]) align 4 %Arr) // CHECK-NEXT: entry: float foo(RWBuffer Arr[3][2]) { // CHECK-NEXT: %[[Arr_1_Ptr:.*]] = getelementptr inbounds [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %Arr, i32 0, i32 1 // CHECK-NEXT: %[[Arr_1_0_Ptr:.*]] = getelementptr inbounds [2 x %"class.hlsl::RWBuffer"], ptr %[[Arr_1_Ptr]], i32 0, i32 0 -// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr {{.*}} %[[Arr_1_0_Ptr]], i32 noundef 0) +// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @hlsl::RWBuffer::operator[](unsigned int)(ptr {{.*}} %[[Arr_1_0_Ptr]], i32 noundef 0) // CHECK-NEXT: %[[Value:.*]] = load float, ptr %[[BufPtr]], align 4 // CHECK-NEXT: ret float %[[Value]] return Arr[1][0][0]; } -// NOTE: -// - _ZN4hlsl8RWBufferIfEC1EjjijPKc is the constructor call for explicit binding -// (has "jjij" in the mangled name) and the arguments are (register, space, range_size, index, name). -// - _ZN4hlsl8RWBufferIfEixEj is the subscript operator for RWBuffer - -// CHECK: define internal void @_Z4mainj(i32 noundef %GI) +// CHECK: define internal void @main(unsigned int)(i32 noundef %GI) // CHECK-NEXT: entry: // CHECK-NEXT: %[[GI_alloca:.*]] = alloca i32, align 4 // CHECK-NEXT: %Sub = alloca [3 x [2 x %"class.hlsl::RWBuffer"]], align 4 @@ -35,35 +31,53 @@ float foo(RWBuffer Arr[3][2]) { [numthreads(4,1,1)] void main(uint GI : SV_GroupThreadID) { // Codegen for "A[4][1]" - create local array [[Tmp0]] of size 3 x 2 and initialize -// each element by a call to the resource constructor +// each element by a call to RWBuffer::__createFromBinding // The resource index for A[4][1][0][0] is 102 = 4 * (4 * 3 * 2) + 1 * (3 * 2) // (index in the resource array as if it was flattened) // CHECK-NEXT: %[[Ptr_Tmp0_0_0:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %tmp, i32 0, i32 0, i32 0 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp0_0_0]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 102, ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp0_0_0]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 102, ptr noundef @[[BufA]]) + // CHECK-NEXT: %[[Ptr_Tmp0_0_1:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %tmp, i32 0, i32 0, i32 1 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp0_0_1]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 103, ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp0_0_1]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 103, ptr noundef @[[BufA]]) + // CHECK-NEXT: %[[Ptr_Tmp0_1_0:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %tmp, i32 0, i32 1, i32 0 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp0_1_0]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 104, ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp0_1_0]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 104, ptr noundef @[[BufA]]) + // CHECK-NEXT: %[[Ptr_Tmp0_1_1:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %tmp, i32 0, i32 1, i32 1 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp0_1_1]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 105, ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp0_1_1]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 105, ptr noundef @[[BufA]]) + // CHECK-NEXT: %[[Ptr_Tmp0_2_0:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %tmp, i32 0, i32 2, i32 0 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp0_2_0]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 106, ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp0_2_0]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 106, ptr noundef @[[BufA]]) + // CHECK-NEXT: %[[Ptr_Tmp0_2_1:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %tmp, i32 0, i32 2, i32 1 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp0_2_1]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 107, ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp0_2_1]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef 107, ptr noundef @[[BufA]]) + // After this Tmp0 values are copied to %Sub using the standard array loop initializaion // (generated from ArrayInitLoopExpr AST node) RWBuffer Sub[3][2] = A[4][1]; // CHECK: %[[Ptr_Sub_2:.*]] = getelementptr inbounds [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %Sub, i32 0, i32 2 // CHECK: %[[Ptr_Sub_2_1:.*]] = getelementptr inbounds [2 x %"class.hlsl::RWBuffer"], ptr %[[Ptr_Sub_2]], i32 0, i32 1 -// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr {{.*}} %[[Ptr_Sub_2_1]], i32 noundef 0) +// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @hlsl::RWBuffer::operator[](unsigned int)(ptr {{.*}} %[[Ptr_Sub_2_1]], i32 noundef 0) // CHECK-NEXT: %[[Sub_2_1_0_Value:.*]] = load float, ptr %[[BufPtr]], align 4 // CHECK-NEXT: store float %[[Sub_2_1_0_Value]], ptr %a, align 4 float a = Sub[2][1][0]; // Codegen for "foo(A[2][GI])" - create local array [[Tmp2]] of size 3 x 2 and initialize -// each element by a call to the resource constructor with dynamic index, and then -// copy-in the array as an argument of "foo" +// each element by a call to the RWBuffer::__createFromBinding with dynamic index, +// and then copy-in the array as an argument of "foo" // Calculate the resource index for A[2][GI][0][0] (index in the resource array as if it was flattened) // The index is 2 * (4 * 3 * 2) + GI * (3 * 2) = 48 + GI * 6 @@ -73,35 +87,48 @@ void main(uint GI : SV_GroupThreadID) { // A[2][GI][0][0] // CHECK-NEXT: %[[Ptr_Tmp2_0_0:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %[[Tmp2]], i32 0, i32 0, i32 0 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp2_0_0]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_0_0]], ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp2_0_0]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_0_0]], ptr noundef @[[BufA]]) // A[2][GI][0][1] // CHECK-NEXT: %[[Index_A_2_GI_0_1:.*]] = add i32 %[[Index_A_2_GI_0_0]], 1 // CHECK-NEXT: %[[Ptr_Tmp2_0_1:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %[[Tmp2]], i32 0, i32 0, i32 1 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp2_0_1]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_0_1]], ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp2_0_1]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_0_1]], ptr noundef @[[BufA]]) // A[2][GI][1][0] // CHECK-NEXT: %[[Index_A_2_GI_1_0:.*]] = add i32 %[[Index_A_2_GI_0_1]], 1 // CHECK-NEXT: %[[Ptr_Tmp2_1_0:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %[[Tmp2]], i32 0, i32 1, i32 0 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp2_1_0]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_1_0]], ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp2_1_0]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_1_0]], ptr noundef @[[BufA]]) // A[2][GI][1][1] // CHECK-NEXT: %[[Index_A_2_GI_1_1:.*]] = add i32 %[[Index_A_2_GI_1_0]], 1 // CHECK-NEXT: %[[Ptr_Tmp2_1_1:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %[[Tmp2]], i32 0, i32 1, i32 1 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp2_1_1]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_1_1]], ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp2_1_1]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_1_1]], ptr noundef @[[BufA]]) // A[2][GI][2][0] // CHECK-NEXT: %[[Index_A_2_GI_2_0:.*]] = add i32 %[[Index_A_2_GI_1_1]], 1 // CHECK-NEXT: %[[Ptr_Tmp2_2_0:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %[[Tmp2]], i32 0, i32 2, i32 0 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp2_2_0]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_2_0]], ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp2_2_0]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_2_0]], ptr noundef @[[BufA]]) // A[2][GI][2][1] // CHECK-NEXT: %[[Index_A_2_GI_2_1:.*]] = add i32 %[[Index_A_2_GI_2_0]], 1 // CHECK-NEXT: %[[Ptr_Tmp2_2_1:.*]] = getelementptr [3 x [2 x %"class.hlsl::RWBuffer"]], ptr %[[Tmp2]], i32 0, i32 2, i32 1 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp2_2_1]], i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_2_1]], ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp2_2_1]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 120, i32 noundef %[[Index_A_2_GI_2_1]], ptr noundef @[[BufA]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Tmp1]], ptr align 4 %[[Tmp2]], i32 24, i1 false) -// CHECK-NEXT: %[[FooReturned:.*]] = call {{.*}} float @_Z3fooA3_A2_N4hlsl8RWBufferIfEE(ptr noundef byval([3 x [2 x %"class.hlsl::RWBuffer"]]) align 4 %[[Tmp1]]) +// CHECK-NEXT: %[[FooReturned:.*]] = call {{.*}} float @foo(hlsl::RWBuffer [3][2]) +// CHECK-SAME: (ptr noundef byval([3 x [2 x %"class.hlsl::RWBuffer"]]) align 4 %[[Tmp1]]) // CHECK-NEXT: store float %[[FooReturned]], ptr %b, align 4 float b = foo(A[2][GI]); diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-subarray-one.hlsl b/clang/test/CodeGenHLSL/resources/res-array-global-subarray-one.hlsl index 5caf2b6db4c8e..bbd48b7ddea52 100644 --- a/clang/test/CodeGenHLSL/resources/res-array-global-subarray-one.hlsl +++ b/clang/test/CodeGenHLSL/resources/res-array-global-subarray-one.hlsl @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \ -// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s +// RUN: -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s // CHECK: @[[BufA:.*]] = private unnamed_addr constant [2 x i8] c"A\00", align 1 @@ -10,12 +10,7 @@ float foo(RWBuffer Arr[2]) { return Arr[1][0]; } -// NOTE: -// - _ZN4hlsl8RWBufferIfEC1EjjijPKc is the constructor call for explicit binding -// (has "jjij" in the mangled name) and the arguments are (register, space, range_size, index, name). -// - _ZN4hlsl8RWBufferIfEixEj is the subscript operator for RWBuffer - -// CHECK: define internal void @_Z4mainj(i32 noundef %GI) +// CHECK: define internal void @main(unsigned int)(i32 noundef %GI) // CHECK-NEXT: entry: // CHECK-NEXT: %[[GI_alloca:.*]] = alloca i32, align 4 // CHECK-NEXT: %Sub = alloca [2 x %"class.hlsl::RWBuffer"], align 4 @@ -28,33 +23,41 @@ float foo(RWBuffer Arr[2]) { [numthreads(4,1,1)] void main(uint GI : SV_GroupThreadID) { // Codegen for "A[2]" - create local array [[Tmp0]] of size 2 and initialize -// each element by a call to the resource constructor +// each element by a call to RWBuffer::__createFromBinding method // CHECK-NEXT: %[[Ptr_Tmp0_0:.*]] = getelementptr [2 x %"class.hlsl::RWBuffer"], ptr %[[Tmp0]], i32 0, i32 0 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp0_0]], i32 noundef 10, i32 noundef 2, i32 noundef 8, i32 noundef 6, ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp0_0]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 8, i32 noundef 6, ptr noundef @[[BufA]]) // CHECK-NEXT: %[[Ptr_Tmp0_1:.*]] = getelementptr [2 x %"class.hlsl::RWBuffer"], ptr %[[Tmp0]], i32 0, i32 1 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp0_1]], i32 noundef 10, i32 noundef 2, i32 noundef 8, i32 noundef 7, ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp0_1]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 8, i32 noundef 7, ptr noundef @[[BufA]]) // After this Tmp0 values are copied to %Sub using the standard array loop initializaion // (generated from ArrayInitLoopExpr AST node) RWBuffer Sub[2] = A[3]; // CHECK: %[[Ptr_Sub_1:.*]] = getelementptr inbounds [2 x %"class.hlsl::RWBuffer"], ptr %Sub, i32 0, i32 1 -// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr {{.*}} %[[Ptr_Sub_1]], i32 noundef 0) +// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @hlsl::RWBuffer::operator[](unsigned int)(ptr {{.*}} %[[Ptr_Sub_1]], i32 noundef 0) // CHECK-NEXT: %[[Sub_1_0_Value:.*]] = load float, ptr %[[BufPtr]], align 4 // CHECK-NEXT: store float %[[Sub_1_0_Value]], ptr %a, align 4 float a = Sub[1][0]; // Codegen for "foo(A[GI])" - create local array [[Tmp2]] of size 2 and initialize -// each element by a call to the resource constructor with dynamic index, and then -// copy-in the array as an argument of "foo" +// each element by a call to the RWBuffer::__createFromBinding method +// with dynamic index, and then copy-in the array as an argument of "foo" // CHECK: %[[GI:.*]] = load i32, ptr %[[GI_alloca]], align 4 // CHECK-NEXT: %[[Index_A_GI_0:.*]] = mul i32 %[[GI]], 2 // CHECK-NEXT: %[[Ptr_Tmp2_GI_0:.*]] = getelementptr [2 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 0 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp2_GI_0]], i32 noundef 10, i32 noundef 2, i32 noundef 8, i32 noundef %[[Index_A_GI_0]], ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp2_GI_0]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 8, i32 noundef %[[Index_A_GI_0]], ptr noundef @[[BufA]]) // CHECK-NEXT: %[[Index_A_GI_1:.*]] = add i32 %[[Index_A_GI_0]], 1 // CHECK-NEXT: %[[Ptr_Tmp2_GI_1:.*]] = getelementptr [2 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 1 -// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Ptr_Tmp2_GI_1]], i32 noundef 10, i32 noundef 2, i32 noundef 8, i32 noundef %[[Index_A_GI_1]], ptr noundef @[[BufA]]) +// CHECK-NEXT: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) +// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Ptr_Tmp2_GI_1]], +// CHECK-SAME: i32 noundef 10, i32 noundef 2, i32 noundef 8, i32 noundef %[[Index_A_GI_1]], ptr noundef @[[BufA]]) // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Tmp1]], ptr align 4 %[[Tmp2]], i32 8, i1 false) -// CHECK-NEXT: %[[FooReturned:.*]] = call {{.*}} float @_Z3fooA2_N4hlsl8RWBufferIfEE(ptr noundef byval([2 x %"class.hlsl::RWBuffer"]) align 4 %[[Tmp1]]) +// CHECK-NEXT: %[[FooReturned:.*]] = call {{.*}} float @foo(hlsl::RWBuffer [2])(ptr noundef byval([2 x %"class.hlsl::RWBuffer"]) align 4 %[[Tmp1]]) // CHECK-NEXT: store float %[[FooReturned]], ptr %b, align 4 float b = foo(A[GI]); diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-unbounded.hlsl b/clang/test/CodeGenHLSL/resources/res-array-global-unbounded.hlsl index edf9ce01f72a6..6756a26bfc124 100644 --- a/clang/test/CodeGenHLSL/resources/res-array-global-unbounded.hlsl +++ b/clang/test/CodeGenHLSL/resources/res-array-global-unbounded.hlsl @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \ -// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -check-prefixes=CHECK,DXIL +// RUN: -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s -check-prefixes=CHECK,DXIL // RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute \ -// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -check-prefixes=CHECK,SPV +// RUN: -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s -check-prefixes=CHECK,SPV // CHECK: @[[BufA:.*]] = private unnamed_addr constant [2 x i8] c"A\00", align 1 // CHECK: @[[BufB:.*]] = private unnamed_addr constant [2 x i8] c"B\00", align 1 @@ -15,16 +15,9 @@ float foo(RWBuffer Arr[4], uint Index) { return (float)Arr[Index][0]; } -// NOTE: -// - _ZN4hlsl8RWBufferIfEC1EjjijPKc is the constructor call for explicit binding for RWBuffer -// (has "jjij" in the mangled name) and the arguments are (register, space, range_size, index, name). -// - _ZN4hlsl8RWBufferIiEC1EjijjPKc is the constructor call for implicit binding for RWBuffer -// (has "jijj" in the mangled name) and the arguments are (space, range_size, index, order_id, name). -// - _ZN4hlsl8RWBufferIfEixEj is the subscript operator on RWBuffer - [numthreads(4,1,1)] void main(uint GI : SV_GroupIndex) { - // CHECK: define internal {{.*}}void @_Z4mainj(i32 noundef %GI) + // CHECK: define internal{{.*}} void @main(unsigned int)(i32 noundef %GI) // CHECK: %[[GI_alloca:.*]] = alloca i32, align 4 // CHECK-NEXT: %a = alloca float, align 4 // CHECK-NEXT: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer @@ -35,8 +28,10 @@ void main(uint GI : SV_GroupIndex) { // Make sure A[100] is translated to a RWBuffer constructor call with range -1 and index 100 // and explicit binding (u10, space1) - // CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 10, i32 noundef 1, i32 noundef -1, i32 noundef 100, ptr noundef @A.str) - // CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr{{.*}} @_ZN4hlsl8RWBufferIfEixEj(ptr {{.*}} %[[Tmp0]], i32 noundef 0) + // CHECK: @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.0") align {{(4|8)}} %[[Tmp0]], + // CHECK-SAME: i32 noundef 10, i32 noundef 1, i32 noundef -1, i32 noundef 100, ptr noundef @A.str) + // CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr{{.*}} @hlsl::RWBuffer::operator[](unsigned int)(ptr {{.*}} %[[Tmp0]], i32 noundef 0) // CHECK-NEXT: %[[Value1:.*]] = load float, ptr{{.*}} %[[BufPtr]], align 4 // CHECK-NEXT: store float %[[Value1]], ptr %a, align 4 float a = A[100][0]; @@ -46,19 +41,34 @@ void main(uint GI : SV_GroupIndex) { // (space 0, order_id 0) // The first index is calculated from the array dimensions (unbounded x 5 x 4) and indices (2, 3) // as 2 * 5 * 4 + 3 * 4 = 52 and the following indices are sequential. + // CHECK-NEXT: %[[Ptr_Tmp2_0:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 0 - // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Ptr_Tmp2_0]], i32 noundef 0, i32 noundef -1, i32 noundef 52, i32 noundef 0, ptr noundef @B.str) + // CHECK-NEXT: call void @hlsl::RWBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Ptr_Tmp2_0]], + // CHECK-SAME: i32 noundef 0, i32 noundef 0, i32 noundef -1, i32 noundef 52, ptr noundef @[[BufB]]) + // CHECK-NEXT: %[[Ptr_Tmp2_1:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 1 - // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Ptr_Tmp2_1]], i32 noundef 0, i32 noundef -1, i32 noundef 53, i32 noundef 0, ptr noundef @B.str) + // CHECK-NEXT: call void @hlsl::RWBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Ptr_Tmp2_1]], + // CHECK-SAME: i32 noundef 0, i32 noundef 0, i32 noundef -1, i32 noundef 53, ptr noundef @[[BufB]]) + // CHECK-NEXT: %[[Ptr_Tmp2_2:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 2 - // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Ptr_Tmp2_2]], i32 noundef 0, i32 noundef -1, i32 noundef 54, i32 noundef 0, ptr noundef @B.str) + // CHECK-NEXT: call void @hlsl::RWBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Ptr_Tmp2_2]], + // CHECK-SAME: i32 noundef 0, i32 noundef 0, i32 noundef -1, i32 noundef 54, ptr noundef @[[BufB]]) + // CHECK-NEXT: %[[Ptr_Tmp2_3:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 3 - // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Ptr_Tmp2_3]], i32 noundef 0, i32 noundef -1, i32 noundef 55, i32 noundef 0, ptr noundef @B.str) + // CHECK-NEXT: call void @hlsl::RWBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Ptr_Tmp2_3]], + // CHECK-SAME: i32 noundef 0, i32 noundef 0, i32 noundef -1, i32 noundef 55, ptr noundef @[[BufB]]) + // DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Tmp1]], ptr align 4 %[[Tmp2]], i32 16, i1 false) // SPV-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[Tmp1]], ptr align 8 %[[Tmp2]], i64 32, i1 false) + // CHECK-NEXT: %[[GI:.*]] = load i32, ptr %[[GI_alloca]], align 4 - // DXIL-NEXT: %[[Value2:.*]] = call {{.*}} float @_Z3fooA4_N4hlsl8RWBufferIiEEj(ptr noundef byval([4 x %"class.hlsl::RWBuffer"]) align 4 %[[Tmp1]], i32 noundef %[[GI]]) - // SPV-NEXT: %[[Value2:.*]] = call {{.*}} float @_Z3fooA4_N4hlsl8RWBufferIiEEj(ptr noundef byval([4 x %"class.hlsl::RWBuffer"]) align 8 %[[Tmp1]], i32 noundef %[[GI]]) + // CHECK-NEXT: %[[Value2:.*]] = call {{.*}} float @foo(hlsl::RWBuffer [4], unsigned int) + // CHECK-SAME: (ptr noundef byval([4 x %"class.hlsl::RWBuffer"]) align {{(4|8)}} %[[Tmp1]], i32 noundef %[[GI]]) + // CHECK-NEXT: store float %[[Value2]], ptr %b, align 4 float b = foo(B[2][3], GI); diff --git a/clang/test/CodeGenHLSL/resources/res-array-global.hlsl b/clang/test/CodeGenHLSL/resources/res-array-global.hlsl index 0abdf5f88cf6e..f728c6b627b68 100644 --- a/clang/test/CodeGenHLSL/resources/res-array-global.hlsl +++ b/clang/test/CodeGenHLSL/resources/res-array-global.hlsl @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \ -// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -check-prefixes=CHECK,DXIL +// RUN: -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s -check-prefixes=CHECK,DXIL // RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute \ -// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -check-prefixes=CHECK,SPV +// RUN: -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s -check-prefixes=CHECK,SPV // CHECK: @[[BufA:.*]] = private unnamed_addr constant [2 x i8] c"A\00", align 1 // CHECK: @[[BufB:.*]] = private unnamed_addr constant [2 x i8] c"B\00", align 1 @@ -30,46 +30,59 @@ RWStructuredBuffer Out; [numthreads(4,1,1)] void main() { - // CHECK: define internal{{.*}} void @_Z4mainv() + // CHECK: define internal{{.*}} void @main() // CHECK: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer // CHECK: %[[Tmp1:.*]] = alloca %"class.hlsl::RWBuffer // CHECK: %[[Tmp2:.*]] = alloca %"class.hlsl::RWBuffer // CHECK: %[[Tmp3:.*]] = alloca %"class.hlsl::RWBuffer // CHECK: %[[Tmp4:.*]] = alloca %"class.hlsl::RWBuffer - // NOTE: - // Constructor call for explicit binding has "jjij" in the mangled name and the arguments are (register, space, range_size, index, name). - // For implicit binding the constructor has "jijj" in the mangled name and the arguments are (space, range_size, index, order_id, name). - // The range_size can be -1 for unbounded arrays, and that is the only signed int in the signature. - // The order_id argument is a sequential number that is assigned to resources with implicit binding and corresponds to the order in which - // the resources were declared. It is needed because implicit bindings are assigned later on in an LLVM pass that needs to know the order - // of the resource declarations. - - // Make sure A[2] is translated to a RWBuffer constructor call with range 4 and index 2 + // Make sure A[2] is translated to a RWBuffer::__createFromBinding call with range 4 and index 2 // and DXIL explicit binding (u10, space1) // and SPIR-V explicit binding (binding 12, set 2) - // DXIL: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 10, i32 noundef 1, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]]) - // SPV: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 12, i32 noundef 2, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]]) + // DXIL: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Tmp0]], + // DXIL-SAME: i32 noundef 10, i32 noundef 1, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]]) + // SPV: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 8 %[[Tmp0]], + // SPV-SAME: i32 noundef 12, i32 noundef 2, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]]) - // Make sure B[3] is translated to a RWBuffer constructor call with range 5 and index 3 + // Make sure B[3] is translated to a RWBuffer::__createFromImplicitBinding call with range 5 and index 3 // and DXIL for implicit binding in space0, order id 0 // and SPIR-V explicit binding (binding 13, set 0) - // DXIL: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Tmp1]], i32 noundef 0, i32 noundef 5, i32 noundef 3, i32 noundef 0, ptr noundef @[[BufB]]) - // SPV: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp1]], i32 noundef 13, i32 noundef 0, i32 noundef 5, i32 noundef 3, ptr noundef @[[BufB]]) + // DXIL: call void @hlsl::RWBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.0") align 4 %[[Tmp1]], + // DXIL-SAME: i32 noundef 0, i32 noundef 0, i32 noundef 5, i32 noundef 3, ptr noundef @[[BufB]]) + // SPV: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.0") align 8 %[[Tmp1]], + // SPV-SAME: i32 noundef 13, i32 noundef 0, i32 noundef 5, i32 noundef 3, ptr noundef @[[BufB]]) - // Make sure C[1] is translated to a RWBuffer constructor call with range 3 and index 1 - // and DXIL explicit binding (u2, space0) + // Make sure C[1] is translated to a RWBuffer::__createFromBinding call with range 3 and index 1 + // and DXIL explicit binding (u2, space0) // and SPIR-V explicit binding (binding 2, set 0) - // DXIL: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp2]], i32 noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]]) - // SPV: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp2]], i32 noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]]) + // DXIL: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.0") align 4 %[[Tmp2]], + // DXIL-SAME: i32 noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]]) + // SPV: call void @hlsl::RWBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.0") align 8 %[[Tmp2]], + // SPV-SAME: i32 noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]]) - // Make sure D[7] is translated to a RWBuffer constructor call with implicit binding + // Make sure D[7] is translated to a RWBuffer::__createFromImplicitBinding call // for both DXIL and SPIR-V - // DXIL: call void @_ZN4hlsl8RWBufferIdEC1EjijjPKc(ptr {{.*}} %[[Tmp3]], i32 noundef 0, i32 noundef 10, i32 noundef 7, i32 noundef 1, ptr noundef @[[BufD]]) - // SPV: call void @_ZN4hlsl8RWBufferIdEC1EjijjPKc(ptr {{.*}} %[[Tmp3]], i32 noundef 0, i32 noundef 10, i32 noundef 7, i32 noundef 0, ptr noundef @[[BufD]]) + // DXIL: call void @hlsl::RWBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.1") align 4 %[[Tmp3]], + // DXIL-SAME: i32 noundef 1, i32 noundef 0, i32 noundef 10, i32 noundef 7, ptr noundef @D.str) + // SPV: call void @hlsl::RWBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.1") align 8 %[[Tmp3]], + // SPV-SAME: i32 noundef 0, i32 noundef 0, i32 noundef 10, i32 noundef 7, ptr noundef @[[BufD]]) - // Make sure E[5][0] is translated to RWBuffer constructor call with implicit binding and specified space/set 2 - // DXIL: call void @_ZN4hlsl8RWBufferIjEC1EjijjPKc(ptr {{.*}} %[[Tmp4]], i32 noundef 2, i32 noundef 15, i32 noundef 5, i32 noundef 2, ptr noundef @[[BufE]]) - // SPV: call void @_ZN4hlsl8RWBufferIjEC1EjijjPKc(ptr {{.*}} %[[Tmp4]], i32 noundef 2, i32 noundef 15, i32 noundef 5, i32 noundef 1, ptr noundef @[[BufE]]) + // Make sure E[5][0] is translated to RWBuffer::__createFromImplicitBinding call + // for both DXIL and SPIR-V with specified space/set 2 + // DXIL: call void @hlsl::RWBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.2") align 4 %[[Tmp4]], + // DXIL-SAME: i32 noundef 2, i32 noundef 2, i32 noundef 15, i32 noundef 5, ptr noundef @[[BufE]]) + // SPV: call void @hlsl::RWBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*) + // SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.2") align 8 %[[Tmp4]], + // SPV-SAME: i32 noundef 1, i32 noundef 2, i32 noundef 15, i32 noundef 5, ptr noundef @[[BufE]]) Out[0] = A[2][0] + (float)B[3][0] + (float)C[1][0] + (float)D[7][0] + (float)E[5][0]; } diff --git a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl index 36430d4e2b628..e1ceec93407a0 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 referenced __handle '__hlsl_resource_t +// CHECK: FieldDecl {{.*}} implicit{{.*}} __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 referenced __handle '__hlsl_resource_t +// CHECK: FieldDecl {{.*}} implicit{{.*}} __handle '__hlsl_resource_t // CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)] // CHECK-SAME{LITERAL}: [[hlsl::is_rov]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector)]]