diff options
Diffstat (limited to 'clang/lib/CodeGen/CGHLSLRuntime.cpp')
| -rw-r--r-- | clang/lib/CodeGen/CGHLSLRuntime.cpp | 206 |
1 files changed, 154 insertions, 52 deletions
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 12ece217ba56..4c8ece972f75 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -18,6 +18,7 @@ #include "CodeGenModule.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attrs.inc" #include "clang/AST/Decl.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" @@ -36,6 +37,7 @@ #include "llvm/Support/Alignment.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" +#include <cstdint> using namespace clang; using namespace CodeGen; @@ -67,9 +69,9 @@ void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) { DXILValMD->addOperand(Val); } -void addRootSignature(llvm::dxbc::RootSignatureVersion RootSigVer, - ArrayRef<llvm::hlsl::rootsig::RootElement> Elements, - llvm::Function *Fn, llvm::Module &M) { +void addRootSignatureMD(llvm::dxbc::RootSignatureVersion RootSigVer, + ArrayRef<llvm::hlsl::rootsig::RootElement> Elements, + llvm::Function *Fn, llvm::Module &M) { auto &Ctx = M.getContext(); llvm::hlsl::rootsig::MetadataBuilder RSBuilder(Ctx, Elements); @@ -77,8 +79,8 @@ void addRootSignature(llvm::dxbc::RootSignatureVersion RootSigVer, ConstantAsMetadata *Version = ConstantAsMetadata::get(ConstantInt::get( llvm::Type::getInt32Ty(Ctx), llvm::to_underlying(RootSigVer))); - MDNode *MDVals = - MDNode::get(Ctx, {ValueAsMetadata::get(Fn), RootSignature, Version}); + ValueAsMetadata *EntryFunc = Fn ? ValueAsMetadata::get(Fn) : nullptr; + MDNode *MDVals = MDNode::get(Ctx, {EntryFunc, RootSignature, Version}); StringRef RootSignatureValKey = "dx.rootsignatures"; auto *RootSignatureValMD = M.getOrInsertNamedMetadata(RootSignatureValKey); @@ -180,6 +182,7 @@ static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD, } 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); @@ -190,6 +193,70 @@ static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD, Args.add(RValue::get(NameStr), AST.getPointerType(AST.CharTy.withConst())); } +// 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, + llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName, + HLSLResourceBindingAttr *RBA, HLSLVkBindingAttr *VkBinding, + ArrayRef<llvm::Value *> PrevGEPIndices, SourceLocation ArraySubsExprLoc) { + + llvm::IntegerType *IntTy = CGF.CGM.IntTy; + llvm::Value *Index = StartIndex; + llvm::Value *One = llvm::ConstantInt::get(IntTy, 1); + const uint64_t ArraySize = ArrayTy->getSExtSize(); + QualType ElemType = ArrayTy->getElementType(); + Address TmpArrayAddr = ValueSlot.getAddress(); + + // Add additional index to the getelementptr call indices. + // This index will be updated for each array element in the loops below. + SmallVector<llvm::Value *> GEPIndices(PrevGEPIndices); + GEPIndices.push_back(llvm::ConstantInt::get(IntTy, 0)); + + // For array of arrays, recursively initialize the sub-arrays. + if (ElemType->isArrayType()) { + const ConstantArrayType *SubArrayTy = cast<ConstantArrayType>(ElemType); + for (uint64_t I = 0; I < ArraySize; I++) { + if (I > 0) { + 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); + } + 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 Align = + TmpArrayAddr.getAlignment().alignmentOfArrayElement(ElemSize); + + for (uint64_t I = 0; I < ArraySize; I++) { + if (I > 0) { + Index = CGF.Builder.CreateAdd(Index, One); + GEPIndices.back() = llvm::ConstantInt::get(IntTy, I); + } + Address ThisAddress = + 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()); + } + return Index; +} + } // namespace llvm::Type * @@ -381,6 +448,19 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) { } } +void CGHLSLRuntime::addRootSignature( + const HLSLRootSignatureDecl *SignatureDecl) { + llvm::Module &M = CGM.getModule(); + Triple T(M.getTargetTriple()); + + // Generated later with the function decl if not targeting root signature + if (T.getEnvironment() != Triple::EnvironmentType::RootSignature) + return; + + addRootSignatureMD(SignatureDecl->getVersion(), + SignatureDecl->getRootElements(), nullptr, M); +} + llvm::TargetExtType * CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) { const auto Entry = LayoutTypes.find(StructType); @@ -584,8 +664,8 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, for (const Attr *Attr : FD->getAttrs()) { if (const auto *RSAttr = dyn_cast<RootSignatureAttr>(Attr)) { auto *RSDecl = RSAttr->getSignatureDecl(); - addRootSignature(RSDecl->getVersion(), RSDecl->getRootElements(), EntryFn, - M); + addRootSignatureMD(RSDecl->getVersion(), RSDecl->getRootElements(), + EntryFn, M); } } } @@ -699,8 +779,6 @@ void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, llvm::GlobalVariable *GV, HLSLVkBindingAttr *VkBinding) { assert(VkBinding && "expect a nonnull binding attribute"); - llvm::Type *Int1Ty = llvm::Type::getInt1Ty(CGM.getLLVMContext()); - auto *NonUniform = llvm::ConstantInt::get(Int1Ty, false); auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0); auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1); auto *Set = llvm::ConstantInt::get(CGM.IntTy, VkBinding->getSet()); @@ -709,7 +787,7 @@ void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, llvm::Intrinsic::ID IntrinsicID = CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(); - SmallVector<Value *> Args{Set, Binding, RangeSize, Index, NonUniform, Name}; + SmallVector<Value *> Args{Set, Binding, RangeSize, Index, Name}; initializeBuffer(CGM, GV, IntrinsicID, Args); } @@ -717,8 +795,6 @@ void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, llvm::GlobalVariable *GV, HLSLResourceBindingAttr *RBA) { assert(RBA && "expect a nonnull binding attribute"); - llvm::Type *Int1Ty = llvm::Type::getInt1Ty(CGM.getLLVMContext()); - auto *NonUniform = llvm::ConstantInt::get(Int1Ty, false); auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0); auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1); auto *Space = llvm::ConstantInt::get(CGM.IntTy, RBA->getSpaceNumber()); @@ -732,15 +808,13 @@ void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, // buffer with explicit binding if (RBA->hasRegisterSlot()) { auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber()); - SmallVector<Value *> Args{Space, RegSlot, RangeSize, - Index, NonUniform, Name}; + SmallVector<Value *> Args{Space, RegSlot, RangeSize, Index, Name}; initializeBuffer(CGM, GV, IntrinsicID, Args); } else { // buffer with implicit binding auto *OrderID = llvm::ConstantInt::get(CGM.IntTy, RBA->getImplicitBindingOrderID()); - SmallVector<Value *> Args{OrderID, Space, RangeSize, - Index, NonUniform, Name}; + SmallVector<Value *> Args{OrderID, Space, RangeSize, Index, Name}; initializeBuffer(CGM, GV, IntrinsicID, Args); } } @@ -768,11 +842,27 @@ llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) { class OpaqueValueVisitor : public RecursiveASTVisitor<OpaqueValueVisitor> { public: - llvm::SmallPtrSet<OpaqueValueExpr *, 8> OVEs; + llvm::SmallVector<OpaqueValueExpr *, 8> OVEs; + llvm::SmallPtrSet<OpaqueValueExpr *, 8> Visited; OpaqueValueVisitor() {} + bool VisitHLSLOutArgExpr(HLSLOutArgExpr *) { + // These need to be bound in CodeGenFunction::EmitHLSLOutArgLValues + // or CodeGenFunction::EmitHLSLOutArgExpr. If they are part of this + // traversal, the temporary containing the copy out will not have + // been created yet. + return false; + } + bool VisitOpaqueValueExpr(OpaqueValueExpr *E) { - OVEs.insert(E); + // Traverse the source expression first. + if (E->getSourceExpr()) + TraverseStmt(E->getSourceExpr()); + + // Then add this OVE if we haven't seen it before. + if (Visited.insert(E).second) + OVEs.push_back(E); + return true; } }; @@ -802,16 +892,14 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr( ArraySubsExpr->getType()->isHLSLResourceRecordArray() && "expected resource array subscript expression"); - // let clang codegen handle local resource array subscripts - const VarDecl *ArrayDecl = dyn_cast<VarDecl>(getArrayDecl(ArraySubsExpr)); + // Let clang codegen handle local resource array subscripts, + // or when the subscript references on opaque expression (as part of + // ArrayInitLoopExpr AST node). + const VarDecl *ArrayDecl = + dyn_cast_or_null<VarDecl>(getArrayDecl(ArraySubsExpr)); if (!ArrayDecl || !ArrayDecl->hasGlobalStorage()) return std::nullopt; - if (ArraySubsExpr->getType()->isArrayType()) - // FIXME: this is not yet implemented (llvm/llvm-project#145426) - llvm_unreachable( - "indexing of sub-arrays of multidimensional arrays not supported yet"); - // get the resource array type ASTContext &AST = ArrayDecl->getASTContext(); const Type *ResArrayTy = ArrayDecl->getType().getTypePtr(); @@ -832,26 +920,30 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr( CGM.IntTy, AST.getConstantArrayElementCount(ArrayTy)); SubIndex = CGF.Builder.CreateMul(SubIndex, Multiplier); } - Index = Index ? CGF.Builder.CreateAdd(Index, SubIndex) : SubIndex; ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase()->IgnoreParenImpCasts()); } - // find binding info for the resource array (for implicit binding - // an HLSLResourceBindingAttr should have been added by SemaHLSL) - QualType ResourceTy = ArraySubsExpr->getType(); + // Find binding info for the resource array. For implicit binding + // an HLSLResourceBindingAttr should have been added by SemaHLSL. HLSLVkBindingAttr *VkBinding = ArrayDecl->getAttr<HLSLVkBindingAttr>(); HLSLResourceBindingAttr *RBA = ArrayDecl->getAttr<HLSLResourceBindingAttr>(); assert((VkBinding || RBA) && "resource array must have a binding attribute"); - // lookup the resource class constructor based on the resource type and - // binding + // Find the individual resource type. + QualType ResultTy = ArraySubsExpr->getType(); + 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 resource class instance (we need to - // return an LValue) - RawAddress TmpVar = CGF.CreateMemTemp(ResourceTy); + // 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). + RawAddress TmpVar = CGF.CreateMemTemp(ResultTy); if (CGF.EmitLifetimeStart(TmpVar.getPointer())) CGF.pushFullExprCleanup<CodeGenFunction::CallLifetimeEnd>( NormalEHLifetimeMarker, TmpVar); @@ -860,26 +952,36 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr( TmpVar, Qualifiers(), AggValueSlot::IsDestructed_t(true), AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t(false), AggValueSlot::DoesNotOverlap); + Address TmpVarAddress = ValueSlot.getAddress(); - Address ThisAddress = ValueSlot.getAddress(); - llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo( - ThisAddress, CD->getThisType()->getPointeeType()); - - // get total array size (= range size) + // Calculate total array size (= range size). llvm::Value *Range = llvm::ConstantInt::get(CGM.IntTy, getTotalArraySize(AST, ResArrayTy)); - // 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, ThisAddress, Args, - ValueSlot.mayOverlap(), - ArraySubsExpr->getExprLoc(), - ValueSlot.isSanitizerChecked()); - - return CGF.MakeAddrLValue(TmpVar, ArraySubsExpr->getType(), - AlignmentSource::Decl); + // 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()); + } else { + // The result of the subscript operation is a local resource array which + // needs to be initialized. + const ConstantArrayType *ArrayTy = + cast<ConstantArrayType>(ResultTy.getTypePtr()); + initializeLocalResourceArray(CGF, ValueSlot, ArrayTy, CD, Range, Index, + ArrayDecl->getName(), RBA, VkBinding, + {llvm::ConstantInt::get(CGM.IntTy, 0)}, + ArraySubsExpr->getExprLoc()); + } + return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl); } |
