|
22 | 22 | #include "clang/AST/RecursiveASTVisitor.h"
|
23 | 23 | #include "clang/AST/Type.h"
|
24 | 24 | #include "clang/Basic/TargetOptions.h"
|
| 25 | +#include "llvm/ADT/SmallString.h" |
25 | 26 | #include "llvm/ADT/SmallVector.h"
|
26 | 27 | #include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
|
27 | 28 | #include "llvm/IR/Constants.h"
|
@@ -84,6 +85,111 @@ void addRootSignature(llvm::dxbc::RootSignatureVersion RootSigVer,
|
84 | 85 | RootSignatureValMD->addOperand(MDVals);
|
85 | 86 | }
|
86 | 87 |
|
| 88 | +// Find array variable declaration from nested array subscript AST nodes |
| 89 | +static const ValueDecl *getArrayDecl(const ArraySubscriptExpr *ASE) { |
| 90 | + const Expr *E = nullptr; |
| 91 | + while (ASE != nullptr) { |
| 92 | + E = ASE->getBase()->IgnoreImpCasts(); |
| 93 | + if (!E) |
| 94 | + return nullptr; |
| 95 | + ASE = dyn_cast<ArraySubscriptExpr>(E); |
| 96 | + } |
| 97 | + if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E)) |
| 98 | + return DRE->getDecl(); |
| 99 | + return nullptr; |
| 100 | +} |
| 101 | + |
| 102 | +// Get the total size of the array, or -1 if the array is unbounded. |
| 103 | +static int getTotalArraySize(ASTContext &AST, const clang::Type *Ty) { |
| 104 | + Ty = Ty->getUnqualifiedDesugaredType(); |
| 105 | + assert(Ty->isArrayType() && "expected array type"); |
| 106 | + if (Ty->isIncompleteArrayType()) |
| 107 | + return -1; |
| 108 | + return AST.getConstantArrayElementCount(cast<ConstantArrayType>(Ty)); |
| 109 | +} |
| 110 | + |
| 111 | +// Find constructor decl for a specific resource record type and binding |
| 112 | +// (implicit vs. explicit). The constructor has 5 parameters. |
| 113 | +// For explicit binding the signature is: |
| 114 | +// void(unsigned, unsigned, int, unsigned, const char *). |
| 115 | +// For implicit binding the signature is: |
| 116 | +// void(unsigned, int, unsigned, unsigned, const char *). |
| 117 | +static CXXConstructorDecl *findResourceConstructorDecl(ASTContext &AST, |
| 118 | + QualType ResTy, |
| 119 | + bool ExplicitBinding) { |
| 120 | + std::array<QualType, 5> ExpParmTypes = { |
| 121 | + AST.UnsignedIntTy, AST.UnsignedIntTy, AST.UnsignedIntTy, |
| 122 | + AST.UnsignedIntTy, AST.getPointerType(AST.CharTy.withConst())}; |
| 123 | + ExpParmTypes[ExplicitBinding ? 2 : 1] = AST.IntTy; |
| 124 | + |
| 125 | + CXXRecordDecl *ResDecl = ResTy->getAsCXXRecordDecl(); |
| 126 | + for (auto *Ctor : ResDecl->ctors()) { |
| 127 | + if (Ctor->getNumParams() != ExpParmTypes.size()) |
| 128 | + continue; |
| 129 | + auto *ParmIt = Ctor->param_begin(); |
| 130 | + auto ExpTyIt = ExpParmTypes.begin(); |
| 131 | + for (; ParmIt != Ctor->param_end() && ExpTyIt != ExpParmTypes.end(); |
| 132 | + ++ParmIt, ++ExpTyIt) { |
| 133 | + if ((*ParmIt)->getType() != *ExpTyIt) |
| 134 | + break; |
| 135 | + } |
| 136 | + if (ParmIt == Ctor->param_end()) |
| 137 | + return Ctor; |
| 138 | + } |
| 139 | + llvm_unreachable("did not find constructor for resource class"); |
| 140 | +} |
| 141 | + |
| 142 | +static Value *buildNameForResource(llvm::StringRef BaseName, |
| 143 | + CodeGenModule &CGM) { |
| 144 | + llvm::SmallString<64> GlobalName = {BaseName, ".str"}; |
| 145 | + return CGM.GetAddrOfConstantCString(BaseName.str(), GlobalName.c_str()) |
| 146 | + .getPointer(); |
| 147 | +} |
| 148 | + |
| 149 | +static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD, |
| 150 | + llvm::Value *ThisPtr, llvm::Value *Range, |
| 151 | + llvm::Value *Index, StringRef Name, |
| 152 | + HLSLResourceBindingAttr *RBA, |
| 153 | + HLSLVkBindingAttr *VkBinding, |
| 154 | + CallArgList &Args) { |
| 155 | + assert((VkBinding || RBA) && "at least one a binding attribute expected"); |
| 156 | + |
| 157 | + std::optional<uint32_t> RegisterSlot; |
| 158 | + uint32_t SpaceNo = 0; |
| 159 | + if (VkBinding) { |
| 160 | + RegisterSlot = VkBinding->getBinding(); |
| 161 | + SpaceNo = VkBinding->getSet(); |
| 162 | + } else { |
| 163 | + if (RBA->hasRegisterSlot()) |
| 164 | + RegisterSlot = RBA->getSlotNumber(); |
| 165 | + SpaceNo = RBA->getSpaceNumber(); |
| 166 | + } |
| 167 | + |
| 168 | + ASTContext &AST = CD->getASTContext(); |
| 169 | + Value *NameStr = buildNameForResource(Name, CGM); |
| 170 | + Value *Space = llvm::ConstantInt::get(CGM.IntTy, SpaceNo); |
| 171 | + |
| 172 | + Args.add(RValue::get(ThisPtr), CD->getThisType()); |
| 173 | + if (RegisterSlot.has_value()) { |
| 174 | + // explicit binding |
| 175 | + auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RegisterSlot.value()); |
| 176 | + Args.add(RValue::get(RegSlot), AST.UnsignedIntTy); |
| 177 | + Args.add(RValue::get(Space), AST.UnsignedIntTy); |
| 178 | + Args.add(RValue::get(Range), AST.IntTy); |
| 179 | + Args.add(RValue::get(Index), AST.UnsignedIntTy); |
| 180 | + |
| 181 | + } else { |
| 182 | + // implicit binding |
| 183 | + auto *OrderID = |
| 184 | + llvm::ConstantInt::get(CGM.IntTy, RBA->getImplicitBindingOrderID()); |
| 185 | + Args.add(RValue::get(Space), AST.UnsignedIntTy); |
| 186 | + Args.add(RValue::get(Range), AST.IntTy); |
| 187 | + Args.add(RValue::get(Index), AST.UnsignedIntTy); |
| 188 | + Args.add(RValue::get(OrderID), AST.UnsignedIntTy); |
| 189 | + } |
| 190 | + Args.add(RValue::get(NameStr), AST.getPointerType(AST.CharTy.withConst())); |
| 191 | +} |
| 192 | + |
87 | 193 | } // namespace
|
88 | 194 |
|
89 | 195 | llvm::Type *
|
@@ -589,13 +695,6 @@ static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
|
589 | 695 | CGM.AddCXXGlobalInit(InitResFunc);
|
590 | 696 | }
|
591 | 697 |
|
592 |
| -static Value *buildNameForResource(llvm::StringRef BaseName, |
593 |
| - CodeGenModule &CGM) { |
594 |
| - std::string Str(BaseName); |
595 |
| - std::string GlobalName(Str + ".str"); |
596 |
| - return CGM.GetAddrOfConstantCString(Str, GlobalName.c_str()).getPointer(); |
597 |
| -} |
598 |
| - |
599 | 698 | void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
|
600 | 699 | llvm::GlobalVariable *GV,
|
601 | 700 | HLSLVkBindingAttr *VkBinding) {
|
@@ -623,17 +722,13 @@ void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
|
623 | 722 | auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
|
624 | 723 | auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
|
625 | 724 | auto *Space = llvm::ConstantInt::get(CGM.IntTy, RBA->getSpaceNumber());
|
626 |
| - Value *Name = nullptr; |
| 725 | + Value *Name = buildNameForResource(BufDecl->getName(), CGM); |
627 | 726 |
|
628 | 727 | llvm::Intrinsic::ID IntrinsicID =
|
629 | 728 | RBA->hasRegisterSlot()
|
630 | 729 | ? CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic()
|
631 | 730 | : CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
|
632 | 731 |
|
633 |
| - std::string Str(BufDecl->getName()); |
634 |
| - std::string GlobalName(Str + ".str"); |
635 |
| - Name = CGM.GetAddrOfConstantCString(Str, GlobalName.c_str()).getPointer(); |
636 |
| - |
637 | 732 | // buffer with explicit binding
|
638 | 733 | if (RBA->hasRegisterSlot()) {
|
639 | 734 | auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber());
|
@@ -700,3 +795,91 @@ void CGHLSLRuntime::emitInitListOpaqueValues(CodeGenFunction &CGF,
|
700 | 795 | }
|
701 | 796 | }
|
702 | 797 | }
|
| 798 | + |
| 799 | +std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr( |
| 800 | + const ArraySubscriptExpr *ArraySubsExpr, CodeGenFunction &CGF) { |
| 801 | + assert(ArraySubsExpr->getType()->isHLSLResourceRecord() || |
| 802 | + ArraySubsExpr->getType()->isHLSLResourceRecordArray() && |
| 803 | + "expected resource array subscript expression"); |
| 804 | + |
| 805 | + // let clang codegen handle local resource array subscripts |
| 806 | + const VarDecl *ArrayDecl = dyn_cast<VarDecl>(getArrayDecl(ArraySubsExpr)); |
| 807 | + if (!ArrayDecl || !ArrayDecl->hasGlobalStorage()) |
| 808 | + return std::nullopt; |
| 809 | + |
| 810 | + if (ArraySubsExpr->getType()->isArrayType()) |
| 811 | + // FIXME: this is not yet implemented (llvm/llvm-project#145426) |
| 812 | + llvm_unreachable( |
| 813 | + "indexing of sub-arrays of multidimensional arrays not supported yet"); |
| 814 | + |
| 815 | + // get the resource array type |
| 816 | + ASTContext &AST = ArrayDecl->getASTContext(); |
| 817 | + const Type *ResArrayTy = ArrayDecl->getType().getTypePtr(); |
| 818 | + assert(ResArrayTy->isHLSLResourceRecordArray() && |
| 819 | + "expected array of resource classes"); |
| 820 | + |
| 821 | + // Iterate through all nested array subscript expressions to calculate |
| 822 | + // the index in the flattened resource array (if this is a multi- |
| 823 | + // dimensional array). The index is calculated as a sum of all indices |
| 824 | + // multiplied by the total size of the array at that level. |
| 825 | + Value *Index = nullptr; |
| 826 | + const ArraySubscriptExpr *ASE = ArraySubsExpr; |
| 827 | + while (ASE != nullptr) { |
| 828 | + Value *SubIndex = CGF.EmitScalarExpr(ASE->getIdx()); |
| 829 | + if (const auto *ArrayTy = |
| 830 | + dyn_cast<ConstantArrayType>(ASE->getType().getTypePtr())) { |
| 831 | + Value *Multiplier = llvm::ConstantInt::get( |
| 832 | + CGM.IntTy, AST.getConstantArrayElementCount(ArrayTy)); |
| 833 | + SubIndex = CGF.Builder.CreateMul(SubIndex, Multiplier); |
| 834 | + } |
| 835 | + |
| 836 | + Index = Index ? CGF.Builder.CreateAdd(Index, SubIndex) : SubIndex; |
| 837 | + ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase()->IgnoreParenImpCasts()); |
| 838 | + } |
| 839 | + |
| 840 | + // find binding info for the resource array (for implicit binding |
| 841 | + // an HLSLResourceBindingAttr should have been added by SemaHLSL) |
| 842 | + QualType ResourceTy = ArraySubsExpr->getType(); |
| 843 | + HLSLVkBindingAttr *VkBinding = ArrayDecl->getAttr<HLSLVkBindingAttr>(); |
| 844 | + HLSLResourceBindingAttr *RBA = ArrayDecl->getAttr<HLSLResourceBindingAttr>(); |
| 845 | + assert((VkBinding || RBA) && "resource array must have a binding attribute"); |
| 846 | + |
| 847 | + // lookup the resource class constructor based on the resource type and |
| 848 | + // binding |
| 849 | + CXXConstructorDecl *CD = findResourceConstructorDecl( |
| 850 | + AST, ResourceTy, VkBinding || RBA->hasRegisterSlot()); |
| 851 | + |
| 852 | + // create a temporary variable for the resource class instance (we need to |
| 853 | + // return an LValue) |
| 854 | + RawAddress TmpVar = CGF.CreateMemTemp(ResourceTy); |
| 855 | + if (CGF.EmitLifetimeStart(TmpVar.getPointer())) |
| 856 | + CGF.pushFullExprCleanup<CodeGenFunction::CallLifetimeEnd>( |
| 857 | + NormalEHLifetimeMarker, TmpVar); |
| 858 | + |
| 859 | + AggValueSlot ValueSlot = AggValueSlot::forAddr( |
| 860 | + TmpVar, Qualifiers(), AggValueSlot::IsDestructed_t(true), |
| 861 | + AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t(false), |
| 862 | + AggValueSlot::DoesNotOverlap); |
| 863 | + |
| 864 | + Address ThisAddress = ValueSlot.getAddress(); |
| 865 | + llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo( |
| 866 | + ThisAddress, CD->getThisType()->getPointeeType()); |
| 867 | + |
| 868 | + // get total array size (= range size) |
| 869 | + llvm::Value *Range = |
| 870 | + llvm::ConstantInt::get(CGM.IntTy, getTotalArraySize(AST, ResArrayTy)); |
| 871 | + |
| 872 | + // assemble the constructor parameters |
| 873 | + CallArgList Args; |
| 874 | + createResourceCtorArgs(CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName(), |
| 875 | + RBA, VkBinding, Args); |
| 876 | + |
| 877 | + // call the constructor |
| 878 | + CGF.EmitCXXConstructorCall(CD, Ctor_Complete, false, false, ThisAddress, Args, |
| 879 | + ValueSlot.mayOverlap(), |
| 880 | + ArraySubsExpr->getExprLoc(), |
| 881 | + ValueSlot.isSanitizerChecked()); |
| 882 | + |
| 883 | + return CGF.MakeAddrLValue(TmpVar, ArraySubsExpr->getType(), |
| 884 | + AlignmentSource::Decl); |
| 885 | +} |
0 commit comments