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

Helena Kotas via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 19 16:56:30 PST 2024


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

>From 8cebb59304a1f893d94f2a758bc47a62f27c1b8b Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 12 Dec 2024 11:37:46 -0800
Subject: [PATCH 1/4] [HLSL] Codegen for simple `cbuffer` blocks without
 embedded arrays or structs

---
 clang/include/clang/Basic/Attr.td             |   6 +-
 clang/lib/CodeGen/CGDeclCXX.cpp               |  12 +-
 clang/lib/CodeGen/CGHLSLRuntime.cpp           | 249 +++++++++++-------
 clang/lib/CodeGen/CGHLSLRuntime.h             |  45 +++-
 clang/lib/Sema/SemaHLSL.cpp                   |  15 +-
 .../ByteAddressBuffers-constructors.hlsl      |   8 +-
 .../builtins/RWBuffer-constructor.hlsl        |  10 +-
 .../StructuredBuffers-constructors.hlsl       |   8 +-
 clang/test/CodeGenHLSL/cbuf.hlsl              |  26 --
 clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl |  23 --
 clang/test/CodeGenHLSL/cbuffer.hlsl           |  67 +++++
 .../CodeGenHLSL/cbuffer_and_namespaces.hlsl   |  47 ++++
 .../CodeGenHLSL/cbuffer_with_packoffset.hlsl  |  33 +++
 ...uffer_with_static_global_and_function.hlsl |  28 ++
 .../static_global_and_function_in_cb.hlsl     |  17 --
 15 files changed, 392 insertions(+), 202 deletions(-)
 delete mode 100644 clang/test/CodeGenHLSL/cbuf.hlsl
 delete mode 100644 clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
 create mode 100644 clang/test/CodeGenHLSL/cbuffer.hlsl
 create mode 100644 clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
 create mode 100644 clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
 create mode 100644 clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
 delete mode 100644 clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 90d2a2056fe1ba..f615f45a9524d8 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4711,9 +4711,9 @@ def HLSLPackOffset: HLSLAnnotationAttr {
   let Args = [IntArgument<"Subcomponent">, IntArgument<"Component">];
   let Documentation = [HLSLPackOffsetDocs];
   let AdditionalMembers = [{
-      unsigned getOffset() {
-        return subcomponent * 4 + component;
-      }
+  unsigned getOffsetInBytes() {
+    return subcomponent * 16 + component * 4;
+  }
   }];
 }
 
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index 2c3054605ee754..2869150a5e6648 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -886,6 +886,10 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
       ModuleInits.push_back(Fn);
     }
 
+  if (getLangOpts().HLSL && getHLSLRuntime().needsResourceBindingInitFn()) {
+    CXXGlobalInits.push_back(getHLSLRuntime().createResourceBindingInitFn());
+  }
+
   if (ModuleInits.empty() && CXXGlobalInits.empty() &&
       PrioritizedCXXGlobalInits.empty())
     return;
@@ -1127,14 +1131,6 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
       if (Decls[i])
         EmitRuntimeCall(Decls[i]);
 
-    if (getLangOpts().HLSL) {
-      CGHLSLRuntime &CGHLSL = CGM.getHLSLRuntime();
-      if (CGHLSL.needsResourceBindingInitFn()) {
-        llvm::Function *ResInitFn = CGHLSL.createResourceBindingInitFn();
-        Builder.CreateCall(llvm::FunctionCallee(ResInitFn), {});
-      }
-    }
-
     Scope.ForceCleanup();
 
     if (ExitBlock) {
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index fb15b1993e74ad..82fae11bc7bc37 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -54,69 +54,110 @@ 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; }
-//
-// will be translated into
-//
-// struct A {
-//   float a;
-//   float b;
-// } cbuffer_A __attribute__((address_space(4)));
-// float foo() { return cbuffer_A.a + cbuffer_A.b; }
-//
-// 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.
-//
-void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
-  if (Buf.Constants.empty())
-    return;
+
+// Creates the LLVM struct type representing the shape of the constant buffer
+// which will be included in the LLVM target type and calculates the memory
+// layout and constant buffer layout offsets of each constant.
+static void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
+  assert(!Buf.Constants.empty() &&
+         "empty constant buffer should not be created");
 
   std::vector<llvm::Type *> EltTys;
-  for (auto &Const : Buf.Constants) {
-    GlobalVariable *GV = Const.first;
-    Const.second = EltTys.size();
+  unsigned MemOffset = 0, CBufOffset = 0, Size = 0;
+
+  for (auto &C : Buf.Constants) {
+    GlobalVariable *GV = C.GlobalVar;
     llvm::Type *Ty = GV->getValueType();
+
+    assert(!Ty->isArrayTy() && !Ty->isStructTy() &&
+           "arrays and structs in cbuffer are not yet implemened");
+
+    // scalar type, vector or matrix
     EltTys.emplace_back(Ty);
+    unsigned FieldSize = Ty->getScalarSizeInBits() / 8;
+    if (Ty->isVectorTy())
+      FieldSize *= cast<FixedVectorType>(Ty)->getNumElements();
+    assert(FieldSize <= 16 && "field side larger than constant buffer row");
+
+    // set memory layout offset (no padding)
+    C.MemOffset = MemOffset;
+    MemOffset += FieldSize;
+
+    // calculate cbuffer layout offset or update total cbuffer size from
+    // packoffset annotations
+    if (Buf.HasPackoffset) {
+      assert(C.CBufferOffset != UINT_MAX &&
+             "cbuffer offset should have been set from packoffset attribute");
+      unsigned OffsetAfterField = C.CBufferOffset + FieldSize;
+      if (Size < OffsetAfterField)
+        Size = OffsetAfterField;
+    } else {
+      // allign to the size of the field
+      CBufOffset = llvm::alignTo(CBufOffset, FieldSize);
+      C.CBufferOffset = CBufOffset;
+      CBufOffset += FieldSize;
+      Size = CBufOffset;
+    }
   }
   Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
+  Buf.Size = Size;
 }
 
-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);
+// Creates LLVM target type target("dx.CBuffer",..) for the constant buffer.
+// The target type includes the LLVM struct type representing the shape
+// of the constant buffer, size, and a list of offsets for each fields
+// in cbuffer layout.
+static llvm::Type *getBufferTargetType(LLVMContext &Ctx,
+                                       CGHLSLRuntime::Buffer &Buf) {
+  assert(Buf.LayoutStruct != nullptr && Buf.Size != UINT_MAX &&
+         "the buffer layout has not been calculated yet");
+  llvm::SmallVector<unsigned> SizeAndOffsets;
+  SizeAndOffsets.reserve(Buf.Constants.size() + 1);
+  SizeAndOffsets.push_back(Buf.Size);
+  for (CGHLSLRuntime::BufferConstant &C : Buf.Constants) {
+    SizeAndOffsets.push_back(C.CBufferOffset);
+  }
+  return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {Buf.LayoutStruct},
+                                  SizeAndOffsets);
+}
 
-  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.
+static void replaceBufferGlobals(CodeGenModule &CGM,
+                                 CGHLSLRuntime::Buffer &Buf) {
+  assert(Buf.IsCBuffer && "tbuffer codegen is not yet supported");
+
+  GlobalVariable *BufGV = Buf.GlobalVar;
+  for (auto &Constant : Buf.Constants) {
+    GlobalVariable *ConstGV = Constant.GlobalVar;
+
+    // TODO: Map to an hlsl_device address space.
+    llvm::Type *RetTy = ConstGV->getType();
+    llvm::Type *TargetTy = BufGV->getValueType();
+
+    // Replace all uses of GV with CBuffer access
+    while (ConstGV->use_begin() != ConstGV->use_end()) {
+      Use &U = *ConstGV->use_begin();
+      if (Instruction *UserInstr = dyn_cast<Instruction>(U.getUser())) {
+        IRBuilder<> Builder(UserInstr);
+        Value *Handle = Builder.CreateLoad(TargetTy, BufGV);
+        Value *ResGetPointer = Builder.CreateIntrinsic(
+            RetTy, Intrinsic::dx_resource_getpointer,
+            ArrayRef<llvm::Value *>{Handle,
+                                    Builder.getInt32(Constant.MemOffset)});
+        U.set(ResGetPointer);
+      } else {
+        llvm_unreachable("unexpected use of constant value");
+      }
+    }
+    ConstGV->removeDeadConstantUsers();
+    ConstGV->eraseFromParent();
   }
-  return CBGV;
 }
 
 } // namespace
@@ -143,6 +184,9 @@ void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
     return;
   }
 
+  assert(!D->getType()->isArrayType() && !D->getType()->isStructureType() &&
+         "codegen for arrays and structs in cbuffer is not yet supported");
+
   auto *GV = cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(D));
   // Add debug info for constVal.
   if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
@@ -150,13 +194,12 @@ void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
         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;
+  CB.Constants.emplace_back(GV);
 
-  unsigned LowerBound = HasUserOffset ? Offset : UINT_MAX;
-  CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
+  if (HLSLPackOffsetAttr *PO = D->getAttr<HLSLPackOffsetAttr>()) {
+    CB.HasPackoffset = true;
+    CB.Constants.back().CBufferOffset = PO->getOffsetInBytes();
+  }
 }
 
 void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
@@ -173,9 +216,37 @@ void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
   }
 }
 
+// Creates temporary global variables for all declarations within the constant
+// buffer context, calculates the buffer layouts, and then creates a global
+// variable for the constant buffer and adds it to the module.
+// All uses of the temporary constant globals will be replaced with buffer
+// access intrinsic resource.getpointer in CGHLSLRuntime::finishCodeGen.
+// Later on in DXILResourceAccess pass these will be transtaled
+// to dx.op.cbufferLoadLegacy instructions.
 void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *D) {
-  Buffers.emplace_back(Buffer(D));
-  addBufferDecls(D, Buffers.back());
+  llvm::Module &M = CGM.getModule();
+  const DataLayout &DL = M.getDataLayout();
+
+  assert(D->isCBuffer() && "tbuffer codegen is not supported yet");
+
+  Buffer &Buf = Buffers.emplace_back(D);
+  addBufferDecls(D, Buf);
+  if (Buf.Constants.empty()) {
+    // empty constant buffer - do not add to globals
+    Buffers.pop_back();
+    return;
+  }
+  layoutBuffer(Buf, DL);
+
+  // Create global variable for CB.
+  llvm::Type *TargetTy = getBufferTargetType(CGM.getLLVMContext(), Buf);
+  Buf.GlobalVar = new GlobalVariable(
+      TargetTy, /*isConstant*/ true, GlobalValue::LinkageTypes::ExternalLinkage,
+      nullptr, llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb" : ".tb"),
+      GlobalValue::NotThreadLocal);
+
+  M.insertGlobalVariable(Buf.GlobalVar);
+  ResourcesToBind.emplace_back(Buf.Decl, Buf.GlobalVar);
 }
 
 void CGHLSLRuntime::finishCodeGen() {
@@ -189,26 +260,14 @@ void CGHLSLRuntime::finishCodeGen() {
   if (CGM.getCodeGenOpts().OptimizationLevel == 0)
     addDisableOptimizations(M);
 
-  const DataLayout &DL = M.getDataLayout();
-
   for (auto &Buf : Buffers) {
-    layoutBuffer(Buf, DL);
-    GlobalVariable *GV = replaceBuffer(Buf);
-    M.insertGlobalVariable(GV);
-    llvm::hlsl::ResourceClass RC = Buf.IsCBuffer
-                                       ? llvm::hlsl::ResourceClass::CBuffer
-                                       : llvm::hlsl::ResourceClass::SRV;
-    llvm::hlsl::ResourceKind RK = Buf.IsCBuffer
-                                      ? llvm::hlsl::ResourceKind::CBuffer
-                                      : llvm::hlsl::ResourceKind::TBuffer;
-    addBufferResourceAnnotation(GV, RC, RK, /*IsROV=*/false,
-                                llvm::hlsl::ElementType::Invalid, Buf.Binding);
+    replaceBufferGlobals(CGM, Buf);
   }
 }
 
 CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D)
-    : Name(D->getName()), IsCBuffer(D->isCBuffer()),
-      Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
+    : Name(D->getName()), IsCBuffer(D->isCBuffer()), HasPackoffset(false),
+      LayoutStruct(nullptr), Decl(D), GlobalVar(nullptr) {}
 
 void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
                                                 llvm::hlsl::ResourceClass RC,
@@ -237,7 +296,7 @@ void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
          "ResourceMD must have been set by the switch above.");
 
   llvm::hlsl::FrontendResource Res(
-      GV, RK, ET, IsROV, Binding.Reg.value_or(UINT_MAX), Binding.Space);
+      GV, RK, ET, IsROV, Binding.Slot.value_or(UINT_MAX), Binding.Space);
   ResourceMD->addOperand(Res.getMetadata());
 }
 
@@ -328,12 +387,8 @@ void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
 CGHLSLRuntime::BufferResBinding::BufferResBinding(
     HLSLResourceBindingAttr *Binding) {
   if (Binding) {
-    llvm::APInt RegInt(64, 0);
-    Binding->getSlot().substr(1).getAsInteger(10, RegInt);
-    Reg = RegInt.getLimitedValue();
-    llvm::APInt SpaceInt(64, 0);
-    Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
-    Space = SpaceInt.getLimitedValue();
+    Slot = Binding->getSlotNumber();
+    Space = Binding->getSpaceNumber();
   } else {
     Space = 0;
   }
@@ -572,24 +627,30 @@ llvm::Function *CGHLSLRuntime::createResourceBindingInitFn() {
   const DataLayout &DL = CGM.getModule().getDataLayout();
   Builder.SetInsertPoint(EntryBB);
 
-  for (const auto &[VD, GV] : ResourcesToBind) {
-    for (Attr *A : VD->getAttrs()) {
+  for (const auto &[Decl, GV] : ResourcesToBind) {
+    for (Attr *A : Decl->getAttrs()) {
       HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
       if (!RBA)
         continue;
 
-      const HLSLAttributedResourceType *AttrResType =
-          HLSLAttributedResourceType::findHandleTypeOnResource(
-              VD->getType().getTypePtr());
-
-      // FIXME: Only simple declarations of resources are supported for now.
-      // Arrays of resources or resources in user defined classes are
-      // not implemented yet.
-      assert(AttrResType != nullptr &&
-             "Resource class must have a handle of HLSLAttributedResourceType");
-
-      llvm::Type *TargetTy =
-          CGM.getTargetCodeGenInfo().getHLSLType(CGM, AttrResType);
+      llvm::Type *TargetTy = nullptr;
+      if (const VarDecl *VD = dyn_cast<VarDecl>(Decl)) {
+        const HLSLAttributedResourceType *AttrResType =
+            HLSLAttributedResourceType::findHandleTypeOnResource(
+                VD->getType().getTypePtr());
+
+        // FIXME: Only simple declarations of resources are supported for now.
+        // Arrays of resources or resources in user defined classes are
+        // not implemented yet.
+        assert(
+            AttrResType != nullptr &&
+            "Resource class must have a handle of HLSLAttributedResourceType");
+
+        TargetTy = CGM.getTargetCodeGenInfo().getHLSLType(CGM, AttrResType);
+      } else {
+        assert(isa<HLSLBufferDecl>(Decl));
+        TargetTy = GV->getValueType();
+      }
       assert(TargetTy != nullptr &&
              "Failed to convert resource handle to target type");
 
@@ -604,7 +665,7 @@ llvm::Function *CGHLSLRuntime::createResourceBindingInitFn() {
 
       llvm::Value *CreateHandle = Builder.CreateIntrinsic(
           /*ReturnType=*/TargetTy, getCreateHandleFromBindingIntrinsic(), Args,
-          nullptr, Twine(VD->getName()).concat("_h"));
+          nullptr, Twine(Decl->getName()).concat("_h"));
 
       llvm::Value *HandleRef =
           Builder.CreateStructGEP(GV->getValueType(), GV, 0);
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index f9efb1bc996412..9c3bbf5bbfe190 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -15,6 +15,7 @@
 #ifndef LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H
 #define LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H
 
+#include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicsDirectX.h"
@@ -53,6 +54,7 @@ class StructType;
 } // namespace llvm
 
 namespace clang {
+class NamedDecl;
 class VarDecl;
 class ParmVarDecl;
 class HLSLBufferDecl;
@@ -112,22 +114,43 @@ class CGHLSLRuntime {
   //===----------------------------------------------------------------------===//
 
   struct BufferResBinding {
-    // The ID like 2 in register(b2, space1).
-    std::optional<unsigned> Reg;
-    // The Space like 1 is register(b2, space1).
-    // Default value is 0.
+    // Register slot
+    std::optional<unsigned> Slot;
+    // Register space; default value is 0.
     unsigned Space;
+
     BufferResBinding(HLSLResourceBindingAttr *Attr);
   };
+
+  struct BufferConstant {
+    llvm::GlobalVariable *GlobalVar;
+    // offset in memory layout (in bytes)
+    unsigned MemOffset;
+    // offset in cbuffer layout (in bytes)
+    unsigned CBufferOffset;
+
+    BufferConstant(llvm::GlobalVariable *GV)
+        : GlobalVar(GV), MemOffset(UINT_MAX), CBufferOffset(UINT_MAX) {}
+  };
+
   struct Buffer {
-    Buffer(const HLSLBufferDecl *D);
     llvm::StringRef Name;
-    // IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer).
+    // Whether the buffer is a cbuffer (and not a tbuffer).
     bool IsCBuffer;
-    BufferResBinding Binding;
-    // Global variable and offset for each constant.
-    std::vector<std::pair<llvm::GlobalVariable *, unsigned>> Constants;
-    llvm::StructType *LayoutStruct = nullptr;
+    // Whether the buffer has packoffset annotations
+    bool HasPackoffset;
+    // List of global constants with memory and cbuffer layout ofsets
+    std::vector<BufferConstant> Constants;
+    // LLVM layout type
+    llvm::StructType *LayoutStruct;
+    // size of the buffer in cbuffer layout
+    unsigned Size;
+    // reference to the AST Decl node with resource binding attribute
+    const HLSLBufferDecl *Decl;
+    // global variable for the constant buffer
+    llvm::GlobalVariable *GlobalVar;
+
+    Buffer(const HLSLBufferDecl *D);
   };
 
 protected:
@@ -169,7 +192,7 @@ class CGHLSLRuntime {
   llvm::Triple::ArchType getArch();
   llvm::SmallVector<Buffer> Buffers;
 
-  llvm::SmallVector<std::pair<const VarDecl *, llvm::GlobalVariable *>>
+  llvm::SmallVector<std::pair<const NamedDecl *, llvm::GlobalVariable *>>
       ResourcesToBind;
 };
 
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 600c800029fd05..9b96806c35f3da 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -164,18 +164,18 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
   return Result;
 }
 
-// Calculate the size of a legacy cbuffer type based on
+// Calculate the size of a legacy cbuffer type in bytes based on
 // https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
 static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
                                            QualType T) {
   unsigned Size = 0;
-  constexpr unsigned CBufferAlign = 128;
+  constexpr unsigned CBufferAlign = 16;
   if (const RecordType *RT = T->getAs<RecordType>()) {
     const RecordDecl *RD = RT->getDecl();
     for (const FieldDecl *Field : RD->fields()) {
       QualType Ty = Field->getType();
       unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
-      unsigned FieldAlign = 32;
+      unsigned FieldAlign = 4;
       if (Ty->isAggregateType())
         FieldAlign = CBufferAlign;
       Size = llvm::alignTo(Size, FieldAlign);
@@ -194,7 +194,7 @@ static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
         calculateLegacyCbufferSize(Context, VT->getElementType());
     Size = ElementSize * ElementCount;
   } else {
-    Size = Context.getTypeSize(T);
+    Size = Context.getTypeSize(T) / 8;
   }
   return Size;
 }
@@ -229,16 +229,17 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
     std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
               [](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
                  const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
-                return LHS.second->getOffset() < RHS.second->getOffset();
+                return LHS.second->getOffsetInBytes() <
+                       RHS.second->getOffsetInBytes();
               });
 
     for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
       VarDecl *Var = PackOffsetVec[i].first;
       HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
       unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
-      unsigned Begin = Attr->getOffset() * 32;
+      unsigned Begin = Attr->getOffsetInBytes();
       unsigned End = Begin + Size;
-      unsigned NextBegin = PackOffsetVec[i + 1].second->getOffset() * 32;
+      unsigned NextBegin = PackOffsetVec[i + 1].second->getOffsetInBytes();
       if (End > NextBegin) {
         VarDecl *NextVar = PackOffsetVec[i + 1].first;
         Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
diff --git a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl
index 45e135427ba9c3..f1e949ab652cce 100644
--- a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl
@@ -15,10 +15,6 @@ RasterizerOrderedByteAddressBuffer Buffer2: register(u3, space4);
 // CHECK: @Buffer1 = global %"class.hlsl::RWByteAddressBuffer" zeroinitializer, align 4
 // CHECK: @Buffer2 = global %"class.hlsl::RasterizerOrderedByteAddressBuffer" zeroinitializer, align 4
 
-// CHECK: define internal void @_GLOBAL__sub_I_ByteAddressBuffers_constructors.hlsl()
-// CHECK: entry:
-// CHECK: call void @_init_resource_bindings()
-
 // CHECK: define internal void @_init_resource_bindings() {
 // CHECK-NEXT: entry:
 // CHECK-DXIL-NEXT: %Buffer0_h = call target("dx.RawBuffer", i8, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_i8_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false)
@@ -27,3 +23,7 @@ RasterizerOrderedByteAddressBuffer Buffer2: register(u3, space4);
 // CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 1, 0) %Buffer1_h, ptr @Buffer1, align 4
 // CHECK-DXIL-NEXT: %Buffer2_h = call target("dx.RawBuffer", i8, 1, 1) @llvm.dx.handle.fromBinding.tdx.RawBuffer_i8_1_1t(i32 4, i32 3, i32 1, i32 0, i1 false)
 // CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 1, 1) %Buffer2_h, ptr @Buffer2, align 4
+
+// CHECK: define internal void @_GLOBAL__sub_I_ByteAddressBuffers_constructors.hlsl()
+// CHECK: entry:
+// CHECK: call void @_init_resource_bindings()
diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
index c2db56e2b2bddf..8f252ea357459a 100644
--- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
@@ -12,14 +12,14 @@ RWBuffer<float> Buf : register(u5, space3);
 // CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
 // CHECK-NEXT: entry:
 
-// CHECK: define internal void @_GLOBAL__sub_I_RWBuffer_constructor.hlsl()
-// CHECK-NEXT: entry:
-// CHECK-NEXT: call void @__cxx_global_var_init()
-// CHECK-NEXT: call void @_init_resource_bindings()
-
 // CHECK: define internal void @_init_resource_bindings() {
 // CHECK-NEXT: entry:
 // CHECK-DXIL-NEXT: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
 // CHECK-DXIL-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %Buf_h, ptr @Buf, align 4
 // CHECK-SPIRV-NEXT: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.spv.handle.fromBinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
 // CHECK-SPIRV-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %Buf_h, ptr @Buf, align 4
+
+// CHECK: define internal void @_GLOBAL__sub_I_RWBuffer_constructor.hlsl()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @__cxx_global_var_init()
+// CHECK-NEXT: call void @_init_resource_bindings()
diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
index d84e92242ffb4d..17cba38cc8283f 100644
--- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
@@ -31,10 +31,6 @@ RasterizerOrderedStructuredBuffer<float> Buf5 : register(u1, space2);
 // CHECK: define linkonce_odr void @_ZN4hlsl33RasterizerOrderedStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
 // CHECK-NEXT: entry:
 
-// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl()
-// CHECK: entry:
-// CHECK: call void @_init_resource_bindings()
-
 // CHECK: define internal void @_init_resource_bindings() {
 // CHECK-NEXT: entry:
 // CHECK-DXIL-NEXT: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false)
@@ -58,3 +54,7 @@ RasterizerOrderedStructuredBuffer<float> Buf5 : register(u1, space2);
 // CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf4_h, ptr @Buf4, align 4
 // CHECK-SPIRV-NEXT: %Buf5_h = call target("dx.RawBuffer", float, 1, 1) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, i32 0, i1 false)
 // CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 1) %Buf5_h, ptr @Buf5, align 4
+
+// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl()
+// CHECK: entry:
+// CHECK: call void @_init_resource_bindings()
diff --git a/clang/test/CodeGenHLSL/cbuf.hlsl b/clang/test/CodeGenHLSL/cbuf.hlsl
deleted file mode 100644
index 3f9d4514967dd2..00000000000000
--- a/clang/test/CodeGenHLSL/cbuf.hlsl
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
-// RUN:   dxil-pc-shadermodel6.3-library %s \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// CHECK: @[[CB:.+]] = external constant { float, double }
-cbuffer A : register(b0, space2) {
-  float a;
-  double b;
-}
-
-// CHECK: @[[TB:.+]] = external constant { float, double }
-tbuffer A : register(t2, space1) {
-  float c;
-  double d;
-}
-
-float foo() {
-// CHECK: load float, ptr @[[CB]], align 4
-// CHECK: load double, ptr getelementptr ({ float, double }, ptr @[[CB]], i32 0, i32 1), align 8
-// CHECK: load float, ptr @[[TB]], align 4
-// CHECK: load double, ptr getelementptr ({ float, double }, ptr @[[TB]], i32 0, i32 1), align 8
-  return a + b + c*d;
-}
-
-// CHECK: !hlsl.cbufs = !{![[CBMD:[0-9]+]]}
-// CHECK: ![[CBMD]] = !{ptr @[[CB]], i32 13, i32 0, i1 false, i32 0, i32 2}
diff --git a/clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl b/clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
deleted file mode 100644
index 73dc376942dfb7..00000000000000
--- a/clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
-// RUN:   dxil-pc-shadermodel6.3-library %s \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// Make sure cbuffer inside namespace works.
-// CHECK: @[[CB:.+]] = external constant { float }
-// CHECK: @[[TB:.+]] = external constant { float }
-namespace n0 {
-namespace n1 {
-  cbuffer A {
-    float a;
-  }
-}
-  tbuffer B {
-    float b;
-  }
-}
-
-float foo() {
-// CHECK: load float, ptr @[[CB]], align 4
-// CHECK: load float, ptr @[[TB]], align 4
-  return n0::n1::a + n0::b;
-}
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
new file mode 100644
index 00000000000000..4d6b55157f30a5
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-compute %s \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK: @CB1.cb = external constant target("dx.CBuffer", { float, double }, 16, 0, 8)
+cbuffer CB1 : register(b0, space2) {
+  float a;
+  double b;
+}
+
+// CHECK: @ParticleLifeCB.cb = external constant target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20)
+cbuffer ParticleLifeCB : register(b2, space1) {
+  uint ParticleTypeMax;
+  uint NumParticles;
+  float2 WorldSize;
+  float Friction;
+  float ForceMultipler;
+}
+
+float foo() {
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float, double }, 16, 0, 8), ptr @CB1.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_16_0_8t(target("dx.CBuffer", { float, double }, 16, 0, 8) %[[HANDLE1]], i32 0)
+// CHECK: load float, ptr %[[PTR1]], align 4
+
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float, double }, 16, 0, 8), ptr @CB1.cb, align 4  
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_16_0_8t(target("dx.CBuffer", { float, double }, 16, 0, 8) %[[HANDLE2]], i32 4)
+// CHECK: load double, ptr %[[PTR2]], align 8
+  
+// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
+// CHECK: %[[PTR3:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
+// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE3]], i32 0)
+// CHECK: load i32, ptr %[[PTR3]], align 4
+
+// CHECK: %[[HANDLE4:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
+// CHECK: %[[PTR4:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
+// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE4]], i32 8)
+// CHECK: load <2 x float>, ptr %[[PTR4]], align 8
+
+// CHECK: %[[HANDLE5:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
+// CHECK: %[[PTR5:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
+// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE5]], i32 20)
+// CHECK: load float, ptr %[[PTR5]], align 4
+  return a + b + ParticleTypeMax + WorldSize.y * ForceMultipler;
+}
+
+// CHECK: define void @main()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_GLOBAL__sub_I_cbuffer.hlsl()
+// CHECK-NEXT: call void @_Z4mainv()
+// CHECK-NEXT: ret void
+
+// CHECK: define internal void @_init_resource_bindings() {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CB1_h = call target("dx.CBuffer", { float, double }, 16, 0, 8)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_f32f64s_16_0_8t(i32 2, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", { float, double }, 16, 0, 8) %CB1_h, ptr @CB1.cb, align 4
+// CHECK-NEXT: %ParticleLifeCB_h = call target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(i32 1, i32 2, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %ParticleLifeCB_h, ptr @ParticleLifeCB.cb, align 4
+
+// CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_init_resource_bindings()
+// CHECK-NEXT: ret void
+
+[numthreads(4,1,1)]
+void main() {}
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
new file mode 100644
index 00000000000000..860716ad3e582a
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// Make sure cbuffer inside namespace works.
+// CHECK: @A.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+// CHECK: @B.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+// CHECK: @C.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+
+namespace n0 {
+  namespace n1 {
+    cbuffer A {
+      float a;
+    }
+  }
+  cbuffer B {
+    float a;
+  }
+  namespace n2 {
+    cbuffer C {
+      float a;
+    }
+  }
+}
+
+float foo() {
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @A.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE1]], i32 0)
+// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %[[PTR1]], align 4
+
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @B.cb, align 4
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE2]], i32 0)
+// CHECK: %[[VAL2:[0-9]+]] = load float, ptr %[[PTR2]], align 4
+
+// CHECK: %add = fadd float %[[VAL1]], %[[VAL2]]
+
+// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @C.cb, align 4
+// CHECK: %[[PTR3:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE3]], i32 0)
+// CHECK: %[[VAL3:[0-9]+]] = load float, ptr %[[PTR3]], align 4
+
+// CHECK: %add1 = fadd float %add, %[[VAL3]]
+
+  return n0::n1::a + n0::a + n0::n2::a;
+}
+
+[numthreads(4,1,1)]
+void main() {}
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
new file mode 100644
index 00000000000000..58891659179aed
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-compute %s \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK: @CB.cb = external constant target("dx.CBuffer", { float, double }, 176, 16, 168)
+cbuffer CB : register(b1, space3) {
+  float a : packoffset(c1.x);
+  double b : packoffset(c10.z);
+}
+
+float foo() {
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float, double }, 176, 16, 168), ptr @CB.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_176_16_168t(
+// CHECK-SAME: target("dx.CBuffer", { float, double }, 176, 16, 168) %[[HANDLE1]], i32 0)
+// CHECK: load float, ptr %[[PTR1]], align 4
+
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float, double }, 176, 16, 168), ptr @CB.cb, align 4
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_176_16_168t(
+// CHECK-SAME: target("dx.CBuffer", { float, double }, 176, 16, 168) %[[HANDLE2]], i32 4)
+// CHECK: load double, ptr %[[PTR2]], align 8
+  return a + b;
+}
+
+// CHECK: define internal void @_init_resource_bindings() {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CB_h = call target("dx.CBuffer", { float, double }, 176, 16, 168)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_f32f64s_176_16_168t(i32 3, i32 1, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", { float, double }, 176, 16, 168) %CB_h, ptr @CB.cb, align 4
+
+[numthreads(4,1,1)]
+void main() {
+  foo();
+}
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
new file mode 100644
index 00000000000000..c72eac85ca675e
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK-DAG: @_ZL1b = internal global float 3.000000e+00, align 4
+// CHECK-DAG: @A.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+// CHECK-NOT: @B.cb
+
+cbuffer A {
+  float a;
+  static float b = 3;
+  float foo() { return a + b; }
+}
+
+cbuffer B {
+  // intentionally empty
+}
+
+
+// CHECK: define noundef float @_Z3foov() #0 {
+// CHECK: %[[HANDLE:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @A.cb, align 4
+// CHECK: %[[PTR:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE]], i32 0)
+// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %[[PTR]], align 4
+// CHECK: %[[VAL2:[0-9]+]] = load float, ptr @_ZL1b, align 4
+// CHECK: %add = fadd float %[[VAL1]], %[[VAL2]]
+
+extern float bar() {
+  return foo();
+}
diff --git a/clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl b/clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl
deleted file mode 100644
index f85bab2113170b..00000000000000
--- a/clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// CHECK-DAG: @[[CB:.+]] = external constant { float }
-
-cbuffer A {
-    float a;
-  // CHECK-DAG:@_ZL1b = internal global float 3.000000e+00, align 4
-  static float b = 3;
-  // CHECK:load float, ptr @[[CB]], align 4
-  // CHECK:load float, ptr @_ZL1b, align 4
-  float foo() { return a + b; }
-}
-
-float bar() {
-  return foo();
-}

>From dee03ca52a009b3e71fe2c976aa59473a8d970cf Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 12 Dec 2024 12:35:48 -0800
Subject: [PATCH 2/4] couple of commas to improve readability

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 82fae11bc7bc37..cfa77ccd1054d6 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -60,8 +60,8 @@ void addDisableOptimizations(llvm::Module &M) {
   M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
 }
 
-// Creates the LLVM struct type representing the shape of the constant buffer
-// which will be included in the LLVM target type and calculates the memory
+// Creates the LLVM struct type representing the shape of the constant buffer,
+// which will be included in the LLVM target type, and calculates the memory
 // layout and constant buffer layout offsets of each constant.
 static void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
   assert(!Buf.Constants.empty() &&

>From 7274d067aa82e178558521576df21041686b97c1 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 19 Dec 2024 14:29:53 -0800
Subject: [PATCH 3/4] Move target type and cbuffer layout calculations to
 DirectXTargetInfo

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp           | 159 ++++++++----------
 clang/lib/CodeGen/CGHLSLRuntime.h             |  37 ++--
 clang/lib/CodeGen/TargetInfo.h                |   5 +-
 clang/lib/CodeGen/Targets/DirectX.cpp         | 127 +++++++++++++-
 clang/lib/CodeGen/Targets/SPIR.cpp            |   9 +-
 clang/test/CodeGenHLSL/cbuffer.hlsl           |  64 +++----
 .../CodeGenHLSL/cbuffer_and_namespaces.hlsl   |  32 ++--
 .../CodeGenHLSL/cbuffer_with_packoffset.hlsl  |  25 +--
 ...uffer_with_static_global_and_function.hlsl |  11 +-
 9 files changed, 289 insertions(+), 180 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index cfa77ccd1054d6..0c8a11c6885815 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -16,6 +16,7 @@
 #include "CGDebugInfo.h"
 #include "CodeGenModule.h"
 #include "TargetInfo.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/Basic/TargetOptions.h"
 #include "llvm/IR/GlobalVariable.h"
@@ -29,7 +30,6 @@
 
 using namespace clang;
 using namespace CodeGen;
-using namespace clang::hlsl;
 using namespace llvm;
 
 namespace {
@@ -60,97 +60,83 @@ void addDisableOptimizations(llvm::Module &M) {
   M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
 }
 
-// Creates the LLVM struct type representing the shape of the constant buffer,
-// which will be included in the LLVM target type, and calculates the memory
-// layout and constant buffer layout offsets of each constant.
-static void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
-  assert(!Buf.Constants.empty() &&
-         "empty constant buffer should not be created");
-
-  std::vector<llvm::Type *> EltTys;
-  unsigned MemOffset = 0, CBufOffset = 0, Size = 0;
-
-  for (auto &C : Buf.Constants) {
-    GlobalVariable *GV = C.GlobalVar;
-    llvm::Type *Ty = GV->getValueType();
-
-    assert(!Ty->isArrayTy() && !Ty->isStructTy() &&
-           "arrays and structs in cbuffer are not yet implemened");
-
-    // scalar type, vector or matrix
-    EltTys.emplace_back(Ty);
-    unsigned FieldSize = Ty->getScalarSizeInBits() / 8;
-    if (Ty->isVectorTy())
-      FieldSize *= cast<FixedVectorType>(Ty)->getNumElements();
-    assert(FieldSize <= 16 && "field side larger than constant buffer row");
-
-    // set memory layout offset (no padding)
-    C.MemOffset = MemOffset;
-    MemOffset += FieldSize;
-
-    // calculate cbuffer layout offset or update total cbuffer size from
-    // packoffset annotations
-    if (Buf.HasPackoffset) {
-      assert(C.CBufferOffset != UINT_MAX &&
-             "cbuffer offset should have been set from packoffset attribute");
-      unsigned OffsetAfterField = C.CBufferOffset + FieldSize;
-      if (Size < OffsetAfterField)
-        Size = OffsetAfterField;
-    } else {
-      // allign to the size of the field
-      CBufOffset = llvm::alignTo(CBufOffset, FieldSize);
-      C.CBufferOffset = CBufOffset;
-      CBufOffset += FieldSize;
-      Size = CBufOffset;
-    }
-  }
-  Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
-  Buf.Size = Size;
-}
-
-// Creates LLVM target type target("dx.CBuffer",..) for the constant buffer.
-// The target type includes the LLVM struct type representing the shape
-// of the constant buffer, size, and a list of offsets for each fields
-// in cbuffer layout.
-static llvm::Type *getBufferTargetType(LLVMContext &Ctx,
-                                       CGHLSLRuntime::Buffer &Buf) {
-  assert(Buf.LayoutStruct != nullptr && Buf.Size != UINT_MAX &&
-         "the buffer layout has not been calculated yet");
-  llvm::SmallVector<unsigned> SizeAndOffsets;
-  SizeAndOffsets.reserve(Buf.Constants.size() + 1);
-  SizeAndOffsets.push_back(Buf.Size);
-  for (CGHLSLRuntime::BufferConstant &C : Buf.Constants) {
-    SizeAndOffsets.push_back(C.CBufferOffset);
+// Creates resource handle representing the constant buffer.
+// For cbuffer declaration:
+//
+//   cbuffer MyConstants {
+//     float a;
+//   }
+//
+// creates a structure type MyConstants and then returns the resource handle
+// that would be spelled as:
+//
+//   __hlsl_resource_t [[hlsl::resource_class(CBuffer)]]
+//   [[contained_type(MyConstants)]]
+//
+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);
   }
-  return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {Buf.LayoutStruct},
-                                  SizeAndOffsets);
+  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();
 }
 
 // Replaces all uses of the temporary constant buffer global variables with
-// buffer access intrinsic resource.getpointer.
+// 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;
-  for (auto &Constant : Buf.Constants) {
-    GlobalVariable *ConstGV = Constant.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::Type *RetTy = ConstGV->getType();
-    llvm::Type *TargetTy = BufGV->getValueType();
 
     // Replace all uses of GV with CBuffer access
     while (ConstGV->use_begin() != ConstGV->use_end()) {
       Use &U = *ConstGV->use_begin();
       if (Instruction *UserInstr = dyn_cast<Instruction>(U.getUser())) {
         IRBuilder<> Builder(UserInstr);
+        Value *Zero = Builder.getInt32(0);
         Value *Handle = Builder.CreateLoad(TargetTy, BufGV);
-        Value *ResGetPointer = Builder.CreateIntrinsic(
-            RetTy, Intrinsic::dx_resource_getpointer,
-            ArrayRef<llvm::Value *>{Handle,
-                                    Builder.getInt32(Constant.MemOffset)});
-        U.set(ResGetPointer);
+        Value *ResGetPointer =
+            Builder.CreateIntrinsic(RetTy, Intrinsic::dx_resource_getpointer,
+                                    ArrayRef<llvm::Value *>{Handle, Zero});
+        Value *GEP = Builder.CreateGEP(BufStructTy, ResGetPointer,
+                                       {Zero, Builder.getInt32(Index)},
+                                       ConstGV->getName());
+        U.set(GEP);
       } else {
         llvm_unreachable("unexpected use of constant value");
       }
@@ -162,11 +148,14 @@ static void replaceBufferGlobals(CodeGenModule &CGM,
 
 } // namespace
 
-llvm::Type *CGHLSLRuntime::convertHLSLSpecificType(const Type *T) {
+llvm::Type *
+CGHLSLRuntime::convertHLSLSpecificType(const Type *T,
+                                       const HLSLBufferDecl *BufferDecl) {
   assert(T->isHLSLSpecificType() && "Not an HLSL specific type!");
 
   // Check if the target has a specific translation for this type first.
-  if (llvm::Type *TargetTy = CGM.getTargetCodeGenInfo().getHLSLType(CGM, T))
+  if (llvm::Type *TargetTy =
+          CGM.getTargetCodeGenInfo().getHLSLType(CGM, T, BufferDecl))
     return TargetTy;
 
   llvm_unreachable("Generic handling of HLSL types is not supported.");
@@ -196,10 +185,8 @@ void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
 
   CB.Constants.emplace_back(GV);
 
-  if (HLSLPackOffsetAttr *PO = D->getAttr<HLSLPackOffsetAttr>()) {
+  if (HLSLPackOffsetAttr *PO = D->getAttr<HLSLPackOffsetAttr>())
     CB.HasPackoffset = true;
-    CB.Constants.back().CBufferOffset = PO->getOffsetInBytes();
-  }
 }
 
 void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
@@ -217,15 +204,14 @@ void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
 }
 
 // Creates temporary global variables for all declarations within the constant
-// buffer context, calculates the buffer layouts, and then creates a global
-// variable for the constant buffer and adds it to the module.
+// buffer context, creates a global variable for the constant buffer and adds
+// it to the module.
 // All uses of the temporary constant globals will be replaced with buffer
 // access intrinsic resource.getpointer in CGHLSLRuntime::finishCodeGen.
 // Later on in DXILResourceAccess pass these will be transtaled
 // to dx.op.cbufferLoadLegacy instructions.
-void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *D) {
+void CGHLSLRuntime::addBuffer(HLSLBufferDecl *D) {
   llvm::Module &M = CGM.getModule();
-  const DataLayout &DL = M.getDataLayout();
 
   assert(D->isCBuffer() && "tbuffer codegen is not supported yet");
 
@@ -236,10 +222,9 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *D) {
     Buffers.pop_back();
     return;
   }
-  layoutBuffer(Buf, DL);
-
   // Create global variable for CB.
-  llvm::Type *TargetTy = getBufferTargetType(CGM.getLLVMContext(), Buf);
+  llvm::Type *TargetTy = convertHLSLSpecificType(
+      getBufferHandleType(Buf), Buf.HasPackoffset ? Buf.Decl : nullptr);
   Buf.GlobalVar = new GlobalVariable(
       TargetTy, /*isConstant*/ true, GlobalValue::LinkageTypes::ExternalLinkage,
       nullptr, llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb" : ".tb"),
@@ -265,9 +250,9 @@ void CGHLSLRuntime::finishCodeGen() {
   }
 }
 
-CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D)
+CGHLSLRuntime::Buffer::Buffer(HLSLBufferDecl *D)
     : Name(D->getName()), IsCBuffer(D->isCBuffer()), HasPackoffset(false),
-      LayoutStruct(nullptr), Decl(D), GlobalVar(nullptr) {}
+      Decl(D), GlobalVar(nullptr) {}
 
 void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
                                                 llvm::hlsl::ResourceClass RC,
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 9c3bbf5bbfe190..6e5d26a93b253b 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -18,15 +18,13 @@
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/IntrinsicsDirectX.h"
-#include "llvm/IR/IntrinsicsSPIRV.h"
-
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/HLSLRuntime.h"
 
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Frontend/HLSL/HLSLResource.h"
+#include "llvm/IR/IntrinsicsDirectX.h"
+#include "llvm/IR/IntrinsicsSPIRV.h"
+#include "llvm/TargetParser/Triple.h"
 
 #include <optional>
 #include <vector>
@@ -122,35 +120,20 @@ class CGHLSLRuntime {
     BufferResBinding(HLSLResourceBindingAttr *Attr);
   };
 
-  struct BufferConstant {
-    llvm::GlobalVariable *GlobalVar;
-    // offset in memory layout (in bytes)
-    unsigned MemOffset;
-    // offset in cbuffer layout (in bytes)
-    unsigned CBufferOffset;
-
-    BufferConstant(llvm::GlobalVariable *GV)
-        : GlobalVar(GV), MemOffset(UINT_MAX), CBufferOffset(UINT_MAX) {}
-  };
-
   struct Buffer {
     llvm::StringRef Name;
     // Whether the buffer is a cbuffer (and not a tbuffer).
     bool IsCBuffer;
     // Whether the buffer has packoffset annotations
     bool HasPackoffset;
-    // List of global constants with memory and cbuffer layout ofsets
-    std::vector<BufferConstant> Constants;
-    // LLVM layout type
-    llvm::StructType *LayoutStruct;
-    // size of the buffer in cbuffer layout
-    unsigned Size;
+    // List of global constants
+    std::vector<llvm::GlobalVariable *> Constants;
     // reference to the AST Decl node with resource binding attribute
-    const HLSLBufferDecl *Decl;
+    HLSLBufferDecl *Decl;
     // global variable for the constant buffer
     llvm::GlobalVariable *GlobalVar;
 
-    Buffer(const HLSLBufferDecl *D);
+    Buffer(HLSLBufferDecl *D);
   };
 
 protected:
@@ -163,12 +146,14 @@ class CGHLSLRuntime {
   CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
   virtual ~CGHLSLRuntime() {}
 
-  llvm::Type *convertHLSLSpecificType(const Type *T);
+  llvm::Type *
+  convertHLSLSpecificType(const Type *T,
+                          const HLSLBufferDecl *BufferDecl = nullptr);
 
   void annotateHLSLResource(const VarDecl *D, llvm::GlobalVariable *GV);
   void generateGlobalCtorDtorCalls();
 
-  void addBuffer(const HLSLBufferDecl *D);
+  void addBuffer(HLSLBufferDecl *D);
   void finishCodeGen();
 
   void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn);
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index ab3142bdea684e..28c511249c1630 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -33,6 +33,7 @@ class Value;
 
 namespace clang {
 class Decl;
+class HLSLBufferDecl;
 
 namespace CodeGen {
 class ABIInfo;
@@ -439,7 +440,9 @@ class TargetCodeGenInfo {
   }
 
   /// Return an LLVM type that corresponds to a HLSL type
-  virtual llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *T) const {
+  virtual llvm::Type *
+  getHLSLType(CodeGenModule &CGM, const Type *T,
+              const HLSLBufferDecl *BufDecl = nullptr) const {
     return nullptr;
   }
 
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 7935f7ae370047..e5d36cd0ba3478 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -8,6 +8,8 @@
 
 #include "ABIInfoImpl.h"
 #include "TargetInfo.h"
+#include "clang/AST/Attrs.inc"
+#include "clang/AST/Decl.h"
 #include "llvm/IR/DerivedTypes.h"
 
 using namespace clang;
@@ -24,11 +26,116 @@ class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {
   DirectXTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
       : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
 
-  llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *T) const override;
+  llvm::Type *
+  getHLSLType(CodeGenModule &CGM, const Type *T,
+              const HLSLBufferDecl *BufDecl = nullptr) const override;
 };
 
-llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
-                                                  const Type *Ty) const {
+static bool hasPackoffset(const HLSLBufferDecl *BufferDecl) {
+  // If one valid constant buffer declaration has a packoffset annotation
+  // then they all need to have them.
+  for (auto *D : BufferDecl->decls())
+    if (VarDecl *VD = dyn_cast<VarDecl>(D))
+      if (VD->getStorageClass() != SC_Static)
+        return VD->hasAttr<HLSLPackOffsetAttr>();
+  return false;
+}
+
+// Fills in the Layout based on the constant buffer packoffset annotations
+// found in the HLSLBufferDecl instance.
+// The first item in the Layout vector will be set to the size of the buffer,
+// which is the highest packoffset value + size of its field.
+// After the size there will be a list of offsets (in bytes) for each field.
+// This layout encoding will be used in the LLVM target type
+// for constant buffers target("dx.CBuffer",..).
+static void createConstantBufferLayoutFromPackoffset(
+    CodeGenModule &CGM, llvm::Type *BufferTy, SmallVector<unsigned> &Layout,
+    const HLSLBufferDecl *BufferDecl) {
+  assert(BufferDecl && hasPackoffset(BufferDecl) &&
+         "expected non-null buffer declaration with packoffset attributes on "
+         "its fields");
+  assert(isa<llvm::StructType>(BufferTy) && "expected struct");
+
+  // total buffer size - equals to the highest packoffset value plus the size of
+  // its element
+  unsigned Size = 0;
+  // reserve the first spot in the layout vector for the buffer size
+  Layout.push_back(UINT_MAX);
+
+  auto DeclIt = BufferDecl->decls_begin();
+  for (llvm::Type *Ty : cast<llvm::StructType>(BufferTy)->elements()) {
+    assert(!Ty->isArrayTy() && !Ty->isStructTy() &&
+           "arrays and structs in cbuffer are not yet implemened");
+
+    VarDecl *VD = nullptr;
+    // ignore any declaration that is not var decls or that is static
+    while (DeclIt != BufferDecl->decls_end()) {
+      VD = llvm::dyn_cast<VarDecl>(*DeclIt);
+      DeclIt++;
+      if (VD && VD->getStorageClass() != SC_Static)
+        break;
+    }
+    assert(VD && "number of declaration in constant buffer does not match "
+                 "number of element in buffer struct");
+    assert(CGM.getTypes().ConvertType(VD->getType()) == Ty &&
+           "constant types do not match");
+
+    HLSLPackOffsetAttr *POAttr = VD->getAttr<HLSLPackOffsetAttr>();
+    assert(POAttr && "expected packoffset attribute on every declaration");
+
+    unsigned Offset = POAttr->getOffsetInBytes();
+    Layout.push_back(Offset);
+
+    unsigned FieldSize = Ty->getScalarSizeInBits() / 8;
+    if (Offset + FieldSize > Size)
+      Size = Offset + FieldSize;
+  }
+  Layout[0] = Size;
+}
+
+// Calculated constant buffer layout. The first item in the Layout
+// vector will be set to the size of the buffer followed by the offsets
+// (in bytes) for each field.
+// This layout encoding will be used in the LLVM target type
+// for constant buffers target("dx.CBuffer",..).
+static void
+calculateConstantBufferLayout(CodeGenModule &CGM, llvm::Type *BufferTy,
+                              SmallVector<unsigned> &Layout,
+                              const HLSLBufferDecl *BufferDecl = nullptr) {
+  assert(isa<llvm::StructType>(BufferTy) && "expected struct");
+  assert(BufferTy->getStructNumElements() != 0 &&
+         "empty constant buffer should not be created");
+
+  if (BufferDecl && hasPackoffset(BufferDecl)) {
+    createConstantBufferLayoutFromPackoffset(CGM, BufferTy, Layout, BufferDecl);
+    return;
+  }
+
+  unsigned CBufOffset = 0, Size = 0;
+  Layout.push_back(UINT_MAX); // reserve first spot for the buffer size
+
+  for (const llvm::Type *ElTy : cast<llvm::StructType>(BufferTy)->elements()) {
+    assert(!ElTy->isArrayTy() && !ElTy->isStructTy() &&
+           "arrays and structs in cbuffer are not yet implemened");
+
+    // scalar type, vector or matrix
+    unsigned FieldSize = ElTy->getScalarSizeInBits() / 8;
+    if (ElTy->isVectorTy())
+      FieldSize *= cast<llvm::FixedVectorType>(ElTy)->getNumElements();
+    assert(FieldSize <= 16 && "field side larger than constant buffer row");
+
+    // align to the size of the field
+    CBufOffset = llvm::alignTo(CBufOffset, FieldSize);
+    Layout.push_back(CBufOffset);
+    CBufOffset += FieldSize;
+    Size = CBufOffset;
+  }
+  Layout[0] = Size;
+}
+
+llvm::Type *
+DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM, const Type *Ty,
+                                      const HLSLBufferDecl *BufDecl) const {
   auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
   if (!ResType)
     return nullptr;
@@ -56,9 +163,17 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
 
     return llvm::TargetExtType::get(Ctx, TypeName, {ElemType}, Ints);
   }
-  case llvm::dxil::ResourceClass::CBuffer:
-    llvm_unreachable("dx.CBuffer handles are not implemented yet");
-    break;
+  case llvm::dxil::ResourceClass::CBuffer: {
+    QualType StructTy = ResType->getContainedType();
+    if (StructTy.isNull())
+      return nullptr;
+
+    llvm::Type *Ty = CGM.getTypes().ConvertType(StructTy);
+
+    SmallVector<unsigned> BufferLayout;
+    calculateConstantBufferLayout(CGM, Ty, BufferLayout, BufDecl);
+    return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {Ty}, BufferLayout);
+  }
   case llvm::dxil::ResourceClass::Sampler:
     llvm_unreachable("dx.Sampler handles are not implemented yet");
     break;
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index a48fe9d5f1ee9c..d3b0e8874b56ad 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -52,7 +52,9 @@ class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo {
 
   unsigned getOpenCLKernelCallingConv() const override;
   llvm::Type *getOpenCLType(CodeGenModule &CGM, const Type *T) const override;
-  llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *Ty) const override;
+  llvm::Type *
+  getHLSLType(CodeGenModule &CGM, const Type *T,
+              const HLSLBufferDecl *BufDecl = nullptr) const override;
   llvm::Type *getSPIRVImageTypeFromHLSLResource(
       const HLSLAttributedResourceType::Attributes &attributes,
       llvm::Type *ElementType, llvm::LLVMContext &Ctx) const;
@@ -327,8 +329,9 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getOpenCLType(CodeGenModule &CGM,
   return nullptr;
 }
 
-llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
-                                                     const Type *Ty) const {
+llvm::Type *
+CommonSPIRTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM, const Type *Ty,
+                                         const HLSLBufferDecl *BufDecl) const {
   auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
   if (!ResType)
     return nullptr;
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index 4d6b55157f30a5..77d408c9251cc3 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -2,14 +2,17 @@
 // RUN:   dxil-pc-shadermodel6.3-compute %s \
 // RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
 
-// CHECK: @CB1.cb = external constant target("dx.CBuffer", { float, double }, 16, 0, 8)
-cbuffer CB1 : register(b0, space2) {
+// CHECK: %class.CB = type { float, double }
+// CHECK: %class.ParticleLife = type { i32, i32, <2 x float>, float, float }
+
+// CHECK: @CB.cb = external constant target("dx.CBuffer", %class.CB, 16, 0, 8)
+cbuffer CB : register(b0, space2) {
   float a;
   double b;
 }
 
-// CHECK: @ParticleLifeCB.cb = external constant target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20)
-cbuffer ParticleLifeCB : register(b2, space1) {
+// CHECK: @ParticleLife.cb = external constant target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20)
+cbuffer ParticleLife : register(b2, space1) {
   uint ParticleTypeMax;
   uint NumParticles;
   float2 WorldSize;
@@ -18,28 +21,31 @@ cbuffer ParticleLifeCB : register(b2, space1) {
 }
 
 float foo() {
-// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float, double }, 16, 0, 8), ptr @CB1.cb, align 4
-// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_16_0_8t(target("dx.CBuffer", { float, double }, 16, 0, 8) %[[HANDLE1]], i32 0)
-// CHECK: load float, ptr %[[PTR1]], align 4
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", %class.CB, 16, 0, 8), ptr @CB.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.CBs_16_0_8t(target("dx.CBuffer", %class.CB, 16, 0, 8) %[[HANDLE1]], i32 0)
+// CHECK: %a = getelementptr %class.CB, ptr %[[PTR1]], i32 0, i32 0
+// CHECK: load float, ptr %a, align 4
 
-// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float, double }, 16, 0, 8), ptr @CB1.cb, align 4  
-// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_16_0_8t(target("dx.CBuffer", { float, double }, 16, 0, 8) %[[HANDLE2]], i32 4)
-// CHECK: load double, ptr %[[PTR2]], align 8
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", %class.CB, 16, 0, 8), ptr @CB.cb, align 4  
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.CBs_16_0_8t(target("dx.CBuffer", %class.CB, 16, 0, 8) %[[HANDLE2]], i32 0)
+// CHECK: %b = getelementptr %class.CB, ptr %[[PTR2]], i32 0, i32 1
+// CHECK: load double, ptr %b, align 8
   
-// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
-// CHECK: %[[PTR3:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
-// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE3]], i32 0)
-// CHECK: load i32, ptr %[[PTR3]], align 4
-
-// CHECK: %[[HANDLE4:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
-// CHECK: %[[PTR4:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
-// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE4]], i32 8)
-// CHECK: load <2 x float>, ptr %[[PTR4]], align 8
+// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20), ptr @ParticleLife.cb, align 4
+// CHECK: %[[PTR3:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20) %[[HANDLE3]], i32 0)
+// CHECK: %ParticleTypeMax = getelementptr %class.ParticleLife, ptr %[[PTR3]], i32 0, i32 0
+// CHECK: load i32, ptr %ParticleTypeMax, align 4
 
-// CHECK: %[[HANDLE5:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
-// CHECK: %[[PTR5:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
-// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE5]], i32 20)
-// CHECK: load float, ptr %[[PTR5]], align 4
+// CHECK: %[[HANDLE4:[0-9]+]] = load target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20), ptr @ParticleLife.cb, align 4
+// CHECK: %[[PTR4:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20) %[[HANDLE4]], i32 0)
+// CHECK: %WorldSize = getelementptr %class.ParticleLife, ptr %[[PTR4]], i32 0, i32 2
+// CHECK: %[[VEC:[0-9]+]] = load <2 x float>, ptr %WorldSize, align 8
+// CHECK: extractelement <2 x float> %[[VEC]], i32 1
+  
+// CHECK: %[[HANDLE5:[0-9]+]] = load target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20), ptr @ParticleLife.cb, align 4
+// CHECK: %[[PTR5:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20) %[[HANDLE5]], i32 0)
+// CHECK: %ForceMultipler = getelementptr %class.ParticleLife, ptr %[[PTR5]], i32 0, i32 4
+// CHECK: %15 = load float, ptr %ForceMultipler, align 4
   return a + b + ParticleTypeMax + WorldSize.y * ForceMultipler;
 }
 
@@ -51,12 +57,12 @@ float foo() {
 
 // CHECK: define internal void @_init_resource_bindings() {
 // CHECK-NEXT: entry:
-// CHECK-NEXT: %CB1_h = call target("dx.CBuffer", { float, double }, 16, 0, 8)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_f32f64s_16_0_8t(i32 2, i32 0, i32 1, i32 0, i1 false)
-// CHECK-NEXT: store target("dx.CBuffer", { float, double }, 16, 0, 8) %CB1_h, ptr @CB1.cb, align 4
-// CHECK-NEXT: %ParticleLifeCB_h = call target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(i32 1, i32 2, i32 1, i32 0, i1 false)
-// CHECK-NEXT: store target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %ParticleLifeCB_h, ptr @ParticleLifeCB.cb, align 4
+// CHECK-NEXT: %CB_h = call target("dx.CBuffer", %class.CB, 16, 0, 8)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.CBs_16_0_8t(i32 2, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", %class.CB, 16, 0, 8) %CB_h, ptr @CB.cb, align 4
+// CHECK-NEXT: %ParticleLife_h = call target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(i32 1, i32 2, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20) %ParticleLife_h, ptr @ParticleLife.cb, align 4
 
 // CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
 // CHECK-NEXT: entry:
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
index 860716ad3e582a..0c2592e32df51d 100644
--- a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
@@ -3,9 +3,14 @@
 // RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
 
 // Make sure cbuffer inside namespace works.
-// CHECK: @A.cb = external constant target("dx.CBuffer", { float }, 4, 0)
-// CHECK: @B.cb = external constant target("dx.CBuffer", { float }, 4, 0)
-// CHECK: @C.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+
+// CHECK: %"class.n0::n1::A" = type { float }
+// CHECK: %"class.n0::B" = type { float }
+// CHECK: %"class.n0::n2::C" = type { float }
+
+// CHECK: @A.cb = external constant target("dx.CBuffer", %"class.n0::n1::A", 4, 0)
+// CHECK: @B.cb = external constant target("dx.CBuffer", %"class.n0::B", 4, 0)
+// CHECK: @C.cb = external constant target("dx.CBuffer", %"class.n0::n2::C", 4, 0)
 
 namespace n0 {
   namespace n1 {
@@ -24,19 +29,22 @@ namespace n0 {
 }
 
 float foo() {
-// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @A.cb, align 4
-// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE1]], i32 0)
-// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %[[PTR1]], align 4
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", %"class.n0::n1::A", 4, 0), ptr @A.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @"llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.n0::n1::As_4_0t"(target("dx.CBuffer", %"class.n0::n1::A", 4, 0) %[[HANDLE1]], i32 0)
+// CHECK: %_ZN2n02n11aE = getelementptr %"class.n0::n1::A", ptr %[[PTR1]], i32 0, i32 0
+// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %_ZN2n02n11aE, align 4
 
-// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @B.cb, align 4
-// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE2]], i32 0)
-// CHECK: %[[VAL2:[0-9]+]] = load float, ptr %[[PTR2]], align 4
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", %"class.n0::B", 4, 0), ptr @B.cb, align 4
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @"llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.n0::Bs_4_0t"(target("dx.CBuffer", %"class.n0::B", 4, 0) %[[HANDLE2]], i32 0)
+// CHECK: %_ZN2n01aE = getelementptr %"class.n0::B", ptr %[[PTR2]], i32 0, i32 0
+// CHECK: %[[VAL2:[0-9]+]] = load float, ptr %_ZN2n01aE, align 4
 
 // CHECK: %add = fadd float %[[VAL1]], %[[VAL2]]
 
-// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @C.cb, align 4
-// CHECK: %[[PTR3:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE3]], i32 0)
-// CHECK: %[[VAL3:[0-9]+]] = load float, ptr %[[PTR3]], align 4
+// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", %"class.n0::n2::C", 4, 0), ptr @C.cb, align 4
+// CHECK: %[[PTR3:[0-9]+]] = call ptr @"llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.n0::n2::Cs_4_0t"(target("dx.CBuffer", %"class.n0::n2::C", 4, 0) %[[HANDLE3]], i32 0)
+// CHECK: %_ZN2n02n21aE = getelementptr %"class.n0::n2::C", ptr %[[PTR3]], i32 0, i32 0
+// CHECK: %[[VAL3:[0-9]+]] = load float, ptr %_ZN2n02n21aE, align 4
 
 // CHECK: %add1 = fadd float %add, %[[VAL3]]
 
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
index 58891659179aed..b05c8c044ca4b5 100644
--- a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
@@ -2,30 +2,31 @@
 // RUN:   dxil-pc-shadermodel6.3-compute %s \
 // RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
 
-// CHECK: @CB.cb = external constant target("dx.CBuffer", { float, double }, 176, 16, 168)
+// CHCEK: %class.CB = type { float, double }
+// CHECK: @CB.cb = external constant target("dx.CBuffer", %class.CB, 176, 16, 168)
 cbuffer CB : register(b1, space3) {
   float a : packoffset(c1.x);
   double b : packoffset(c10.z);
 }
 
 float foo() {
-// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float, double }, 176, 16, 168), ptr @CB.cb, align 4
-// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_176_16_168t(
-// CHECK-SAME: target("dx.CBuffer", { float, double }, 176, 16, 168) %[[HANDLE1]], i32 0)
-// CHECK: load float, ptr %[[PTR1]], align 4
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", %class.CB, 176, 16, 168), ptr @CB.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.CBs_176_16_168t(target("dx.CBuffer", %class.CB, 176, 16, 168) %[[HANDLE1]], i32 0)
+// CHECK: %a = getelementptr %class.CB, ptr %[[PTR1]], i32 0, i32 0
+// CHECK: load float, ptr %a, align 4
 
-// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float, double }, 176, 16, 168), ptr @CB.cb, align 4
-// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_176_16_168t(
-// CHECK-SAME: target("dx.CBuffer", { float, double }, 176, 16, 168) %[[HANDLE2]], i32 4)
-// CHECK: load double, ptr %[[PTR2]], align 8
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", %class.CB, 176, 16, 168), ptr @CB.cb, align 4
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.CBs_176_16_168t(target("dx.CBuffer", %class.CB, 176, 16, 168) %[[HANDLE2]], i32 0)
+// CHECK: %b = getelementptr %class.CB, ptr %[[PTR2]], i32 0, i32 1
+// CHECK: load double, ptr %b, align 8
   return a + b;
 }
 
 // CHECK: define internal void @_init_resource_bindings() {
 // CHECK-NEXT: entry:
-// CHECK-NEXT: %CB_h = call target("dx.CBuffer", { float, double }, 176, 16, 168)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_f32f64s_176_16_168t(i32 3, i32 1, i32 1, i32 0, i1 false)
-// CHECK-NEXT: store target("dx.CBuffer", { float, double }, 176, 16, 168) %CB_h, ptr @CB.cb, align 4
+// CHECK-NEXT: %CB_h = call target("dx.CBuffer", %class.CB, 176, 16, 168)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.CBs_176_16_168t(i32 3, i32 1, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", %class.CB, 176, 16, 168) %CB_h, ptr @CB.cb, align 4
 
 [numthreads(4,1,1)]
 void main() {
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
index c72eac85ca675e..e205f48015977c 100644
--- a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
@@ -1,8 +1,10 @@
 // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
 // RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
 
+// CHECK: %class.A = type { float }
+
 // CHECK-DAG: @_ZL1b = internal global float 3.000000e+00, align 4
-// CHECK-DAG: @A.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+// CHECK-DAG: @A.cb = external constant target("dx.CBuffer", %class.A, 4, 0)
 // CHECK-NOT: @B.cb
 
 cbuffer A {
@@ -17,9 +19,10 @@ cbuffer B {
 
 
 // CHECK: define noundef float @_Z3foov() #0 {
-// CHECK: %[[HANDLE:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @A.cb, align 4
-// CHECK: %[[PTR:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE]], i32 0)
-// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %[[PTR]], align 4
+// CHECK: %[[HANDLE:[0-9]+]] = load target("dx.CBuffer", %class.A, 4, 0), ptr @A.cb, align 4
+// CHECK: %[[PTR:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.As_4_0t(target("dx.CBuffer", %class.A, 4, 0) %[[HANDLE]], i32 0)
+// CHECK: %a = getelementptr %class.A, ptr %[[PTR]], i32 0, i32 0
+// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %a, align 4
 // CHECK: %[[VAL2:[0-9]+]] = load float, ptr @_ZL1b, align 4
 // CHECK: %add = fadd float %[[VAL1]], %[[VAL2]]
 

>From a150b1e000e2ecceb504b3fda4690f24bbfd8ecd Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 19 Dec 2024 16:56:10 -0800
Subject: [PATCH 4/4] update tests after merge

---
 clang/test/CodeGenHLSL/cbuffer.hlsl                 | 4 ++--
 clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index 77d408c9251cc3..b5be856d994f5b 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -58,10 +58,10 @@ float foo() {
 // CHECK: define internal void @_init_resource_bindings() {
 // CHECK-NEXT: entry:
 // CHECK-NEXT: %CB_h = call target("dx.CBuffer", %class.CB, 16, 0, 8)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.CBs_16_0_8t(i32 2, i32 0, i32 1, i32 0, i1 false)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_class.CBs_16_0_8t(i32 2, i32 0, i32 1, i32 0, i1 false)
 // CHECK-NEXT: store target("dx.CBuffer", %class.CB, 16, 0, 8) %CB_h, ptr @CB.cb, align 4
 // CHECK-NEXT: %ParticleLife_h = call target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(i32 1, i32 2, i32 1, i32 0, i1 false)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(i32 1, i32 2, i32 1, i32 0, i1 false)
 // CHECK-NEXT: store target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20) %ParticleLife_h, ptr @ParticleLife.cb, align 4
 
 // CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
index b05c8c044ca4b5..b6bb8e0428c9c4 100644
--- a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
@@ -25,7 +25,7 @@ float foo() {
 // CHECK: define internal void @_init_resource_bindings() {
 // CHECK-NEXT: entry:
 // CHECK-NEXT: %CB_h = call target("dx.CBuffer", %class.CB, 176, 16, 168)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.CBs_176_16_168t(i32 3, i32 1, i32 1, i32 0, i1 false)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_class.CBs_176_16_168t(i32 3, i32 1, i32 1, i32 0, i1 false)
 // CHECK-NEXT: store target("dx.CBuffer", %class.CB, 176, 16, 168) %CB_h, ptr @CB.cb, align 4
 
 [numthreads(4,1,1)]



More information about the cfe-commits mailing list