[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,
+                                 CGHLSLRuntime::Buffer &Buf) {
+  assert(Buf.IsCBuffer && "tbuffer codegen is not yet supported");
+
+  GlobalVariable *BufGV = Buf.GlobalVar;
+  llvm::Type *TargetTy = BufGV->getValueType();
+  llvm::Type *BufStructTy = cast<TargetExtType>(TargetTy)->getTypeParameter(0);
+  unsigned Index = 0;
+  for (auto ConstIt = Buf.Constants.begin(); ConstIt != Buf.Constants.end();
+       ++ConstIt, ++Index) {
+    GlobalVariable *ConstGV = *ConstIt;
+
+    // TODO: Map to an hlsl_device address space.
----------------
llvm-beanz wrote:

```suggestion
    // TODO: Map to an hlsl_device address space (#109877).
```

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


More information about the cfe-commits mailing list