[clang] [HLSL] Codegen for `cbuffer` declarations without embedded arrays or structs (PR #119755)

Chris B via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 20 07:55:29 PST 2024


================
@@ -54,78 +54,108 @@ void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
   auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
   DXILValMD->addOperand(Val);
 }
+
 void addDisableOptimizations(llvm::Module &M) {
   StringRef Key = "dx.disable_optimizations";
   M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
 }
-// cbuffer will be translated into global variable in special address space.
-// If translate into C,
-// cbuffer A {
-//   float a;
-//   float b;
-// }
-// float foo() { return a + b; }
+
+// Creates resource handle representing the constant buffer.
+// For cbuffer declaration:
 //
-// will be translated into
+//   cbuffer MyConstants {
+//     float a;
+//   }
 //
-// struct A {
-//   float a;
-//   float b;
-// } cbuffer_A __attribute__((address_space(4)));
-// float foo() { return cbuffer_A.a + cbuffer_A.b; }
+// creates a structure type MyConstants and then returns the resource handle
+// that would be spelled as:
 //
-// layoutBuffer will create the struct A type.
-// replaceBuffer will replace use of global variable a and b with cbuffer_A.a
-// and cbuffer_A.b.
+//   __hlsl_resource_t [[hlsl::resource_class(CBuffer)]]
+//   [[contained_type(MyConstants)]]
 //
-void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
-  if (Buf.Constants.empty())
-    return;
-
-  std::vector<llvm::Type *> EltTys;
-  for (auto &Const : Buf.Constants) {
-    GlobalVariable *GV = Const.first;
-    Const.second = EltTys.size();
-    llvm::Type *Ty = GV->getValueType();
-    EltTys.emplace_back(Ty);
+static const clang::Type *getBufferHandleType(CGHLSLRuntime::Buffer &Buf) {
+  HLSLBufferDecl *BD = Buf.Decl;
+  ASTContext &AST = BD->getASTContext();
+
+  // create struct type for the constant buffer; filter out any declarations
+  // that are not a VarDecls or that are static
+  CXXRecordDecl *StructDecl = CXXRecordDecl::Create(
+      BD->getASTContext(), TagDecl::TagKind::Class, BD->getDeclContext(),
+      BD->getLocation(), BD->getLocation(), BD->getIdentifier());
+  StructDecl->startDefinition();
+  for (Decl *it : Buf.Decl->decls()) {
+    const VarDecl *VD = dyn_cast<VarDecl>(it);
+    if (!VD || VD->getStorageClass() == SC_Static)
+      continue;
+    auto *Field = FieldDecl::Create(
+        AST, StructDecl, VD->getLocation(), VD->getLocation(),
+        VD->getIdentifier(), VD->getType(), VD->getTypeSourceInfo(), nullptr,
+        false, InClassInitStyle::ICIS_NoInit);
+    Field->setAccess(AccessSpecifier::AS_private);
+    StructDecl->addDecl(Field);
   }
-  Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
+  StructDecl->completeDefinition();
+  assert(!StructDecl->fields().empty() && "empty cbuffer should not get here");
+
+  // create the resource handle type
+  HLSLAttributedResourceType::Attributes ResAttrs(dxil::ResourceClass::CBuffer,
+                                                  false, false);
+  QualType ContainedTy = QualType(StructDecl->getTypeForDecl(), 0);
+  return AST
+      .getHLSLAttributedResourceType(AST.HLSLResourceTy, ContainedTy, ResAttrs)
+      .getTypePtr();
 }
 
-GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) {
-  // Create global variable for CB.
-  GlobalVariable *CBGV = new GlobalVariable(
-      Buf.LayoutStruct, /*isConstant*/ true,
-      GlobalValue::LinkageTypes::ExternalLinkage, nullptr,
-      llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb." : ".tb."),
-      GlobalValue::NotThreadLocal);
-
-  IRBuilder<> B(CBGV->getContext());
-  Value *ZeroIdx = B.getInt32(0);
-  // Replace Const use with CB use.
-  for (auto &[GV, Offset] : Buf.Constants) {
-    Value *GEP =
-        B.CreateGEP(Buf.LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
-
-    assert(Buf.LayoutStruct->getElementType(Offset) == GV->getValueType() &&
-           "constant type mismatch");
-
-    // Replace.
-    GV->replaceAllUsesWith(GEP);
-    // Erase GV.
-    GV->removeDeadConstantUsers();
-    GV->eraseFromParent();
+// Replaces all uses of the temporary constant buffer global variables with
+// buffer access intrinsic resource.getpointer and GEP.
+static void replaceBufferGlobals(CodeGenModule &CGM,
----------------
llvm-beanz wrote:

This is a big no. This is falling into the mess that was CGHLSLMSFinishCodeGen in DXC.

We should not be manipulating IR in Clang CodeGen. We should be able to inspect and dump the post-codegen IR, and test every IR transformation independently.

https://github.com/llvm/llvm-project/pull/119755


More information about the cfe-commits mailing list