[clang] [HLSL] Constant buffers codegen (PR #124886)
Justin Bogner via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 18 15:48:17 PST 2025
================
@@ -115,48 +83,176 @@ llvm::Triple::ArchType CGHLSLRuntime::getArch() {
return CGM.getTarget().getTriple().getArch();
}
-void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
- if (D->getStorageClass() == SC_Static) {
- // For static inside cbuffer, take as global static.
- // Don't add to cbuffer.
- CGM.EmitGlobal(D);
- return;
- }
+// Returns true if the type is an HLSL resource class
+static bool isResourceRecordType(const clang::Type *Ty) {
+ return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
+}
- auto *GV = cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(D));
- GV->setExternallyInitialized(true);
- // Add debug info for constVal.
- if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
- if (CGM.getCodeGenOpts().getDebugInfo() >=
- codegenoptions::DebugInfoKind::LimitedDebugInfo)
- DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
-
- // FIXME: support packoffset.
- // See https://github.com/llvm/llvm-project/issues/57914.
- uint32_t Offset = 0;
- bool HasUserOffset = false;
-
- unsigned LowerBound = HasUserOffset ? Offset : UINT_MAX;
- CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
+// Returns true if the type is an HLSL resource class or an array of them
+static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) {
+ while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
+ Ty = CAT->getArrayElementTypeNoTypeQual();
+ return isResourceRecordType(Ty);
}
-void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
- for (Decl *it : DC->decls()) {
- if (auto *ConstDecl = dyn_cast<VarDecl>(it)) {
- addConstant(ConstDecl, CB);
- } else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
+// Emits constant global variables for buffer constants declarations
+// and creates metadata linking the constant globals with the buffer global.
+void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
+ llvm::GlobalVariable *BufGV) {
+ LLVMContext &Ctx = CGM.getLLVMContext();
+
+ // get the layout struct from constant buffer target type
+ llvm::Type *BufType = BufGV->getValueType();
+ assert(isa<llvm::TargetExtType>(BufType) &&
+ "expected target type for HLSL buffer resource");
+ llvm::Type *BufLayoutType =
+ cast<llvm::TargetExtType>(BufType)->getTypeParameter(0);
+ assert(isa<llvm::TargetExtType>(BufLayoutType) &&
+ "expected target type for buffer layout struct");
+ llvm::StructType *LayoutStruct = cast<llvm::StructType>(
+ cast<llvm::TargetExtType>(BufLayoutType)->getTypeParameter(0));
+
+ // Start metadata list associating the buffer global variable with its
+ // constatns
+ SmallVector<llvm::Metadata *> BufGlobals;
+ BufGlobals.push_back(ValueAsMetadata::get(BufGV));
+
+ const auto *ElemIt = LayoutStruct->element_begin();
+ for (Decl *D : BufDecl->decls()) {
+ if (isa<CXXRecordDecl, EmptyDecl>(D))
// Nothing to do for this declaration.
- } else if (isa<FunctionDecl>(it)) {
- // A function within an cbuffer is effectively a top-level function,
- // as it only refers to globally scoped declarations.
- CGM.EmitTopLevelDecl(it);
+ continue;
+ if (isa<FunctionDecl>(D)) {
+ // A function within an cbuffer is effectively a top-level function.
+ CGM.EmitTopLevelDecl(D);
+ continue;
+ }
+ VarDecl *VD = dyn_cast<VarDecl>(D);
+ if (!VD)
+ continue;
+
+ QualType VDTy = VD->getType();
+ if (VDTy.getAddressSpace() != LangAS::hlsl_constant) {
+ if (VD->getStorageClass() == SC_Static ||
+ VDTy.getAddressSpace() == LangAS::hlsl_groupshared ||
+ isResourceRecordTypeOrArrayOf(VDTy.getTypePtr())) {
+ // Emit static and groupshared variables and resource classes inside
+ // cbuffer as regular globals
+ CGM.EmitGlobal(VD);
+ }
+ // Anything else that is not in the hlsl_constant address space must be
+ // an empty struct or a zero-sized array and can be ignored
+ continue;
+ }
+
+ assert(ElemIt != LayoutStruct->element_end() &&
+ "number of elements in layout struct does not match");
+ llvm::Type *LayoutType = *ElemIt++;
+
+ // there might be resources inside the used defined structs
+ if (VDTy->isStructureType() && VDTy->isHLSLIntangibleType())
+ // FIXME: handle resources in cbuffer structs
+ llvm_unreachable("resources in cbuffer are not supported yet");
----------------
bogner wrote:
`report_fatal_error` might be better here - I imagine something will crash later anyway if we get here.
https://github.com/llvm/llvm-project/pull/124886
More information about the cfe-commits
mailing list