[clang] [HLSL] Implement default constant buffer `$Globals` (PR #125807)

Helena Kotas via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 20 10:52:11 PST 2025


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

>From 63c465b40512ad4c5fff84c0b2b022b49d46eaa7 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 28 Jan 2025 13:20:30 -0800
Subject: [PATCH 01/19] [HLSL] Constant buffer layout struct update

- create structs with public fields instead of classes with private fields
- add Packed attribute to prevent struct padding
- use __cblayout_ prefix in name
- filter out arrays of resources (bug fix)
- don't create implicit initializer for constant buffer decls
- update tests
---
 clang/lib/Sema/SemaDecl.cpp                   |   7 +
 clang/lib/Sema/SemaHLSL.cpp                   |  29 ++--
 .../AST/HLSL/ast-dump-comment-cbuffer.hlsl    |   3 -
 clang/test/AST/HLSL/cbuffer.hlsl              | 144 ++++++++++--------
 .../test/AST/HLSL/cbuffer_and_namespaces.hlsl |  30 ++--
 clang/test/AST/HLSL/pch_hlsl_buffer.hlsl      |   4 +-
 6 files changed, 121 insertions(+), 96 deletions(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fe68eadc951b5..ba424567b23e0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14183,6 +14183,13 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
     if (getLangOpts().OpenCL &&
         Var->getType().getAddressSpace() == LangAS::opencl_local)
       return;
+
+    // In HLSL, objects in the hlsl_constat address space are initialized
+    // externaly, so don't synthesize an implicit initializer.
+    if (getLangOpts().HLSL &&
+        Var->getType().getAddressSpace() == LangAS::hlsl_constant)
+      return;
+
     // C++03 [dcl.init]p9:
     //   If no initializer is specified for an object, and the
     //   object is of (possibly cv-qualified) non-POD class type (or
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index aa99b44958eaf..97df01a5dd307 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -269,8 +269,11 @@ static bool isZeroSizedArray(const ConstantArrayType *CAT) {
   return CAT != nullptr;
 }
 
-// Returns true if the record type is an HLSL resource class
-static bool isResourceRecordType(const Type *Ty) {
+// Returns true if the record type is an HLSL resource class or an array of
+// HLSL resource classes
+static bool isResourceRecordTypeOrArrayOf(const Type *Ty) {
+  while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
+    Ty = CAT->getArrayElementTypeNoTypeQual();
   return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
 }
 
@@ -279,11 +282,10 @@ static bool isResourceRecordType(const Type *Ty) {
 // array, or a builtin intangible type. Returns false it is a valid leaf element
 // type or if it is a record type that needs to be inspected further.
 static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
-  if (Ty->isRecordType()) {
-    if (isResourceRecordType(Ty) || Ty->getAsCXXRecordDecl()->isEmpty())
-      return true;
-    return false;
-  }
+  if (isResourceRecordTypeOrArrayOf(Ty))
+    return true;
+  if (Ty->isRecordType())
+    return Ty->getAsCXXRecordDecl()->isEmpty();
   if (Ty->isConstantArrayType() &&
       isZeroSizedArray(cast<ConstantArrayType>(Ty)))
     return true;
@@ -339,7 +341,7 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S, NamedDecl *BaseDecl,
   ASTContext &AST = S.getASTContext();
 
   IdentifierInfo *NameBaseII = BaseDecl->getIdentifier();
-  llvm::SmallString<64> Name("__layout_");
+  llvm::SmallString<64> Name("__cblayout_");
   if (NameBaseII) {
     Name.append(NameBaseII->getName());
   } else {
@@ -393,7 +395,7 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty,
   auto *Field = FieldDecl::Create(AST, LayoutStruct, SourceLocation(),
                                   SourceLocation(), II, QT, TSI, nullptr, false,
                                   InClassInitStyle::ICIS_NoInit);
-  Field->setAccess(AccessSpecifier::AS_private);
+  Field->setAccess(AccessSpecifier::AS_public);
   return Field;
 }
 
@@ -417,9 +419,11 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S,
   if (CXXRecordDecl *RD = findRecordDeclInContext(II, DC))
     return RD;
 
-  CXXRecordDecl *LS = CXXRecordDecl::Create(
-      AST, TagDecl::TagKind::Class, DC, SourceLocation(), SourceLocation(), II);
+  CXXRecordDecl *LS =
+      CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, DC, SourceLocation(),
+                            SourceLocation(), II);
   LS->setImplicit(true);
+  LS->addAttr(PackedAttr::CreateImplicit(AST));
   LS->startDefinition();
 
   // copy base struct, create HLSL Buffer compatible version if needed
@@ -472,8 +476,9 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
   IdentifierInfo *II = getHostLayoutStructName(S, BufDecl, true);
 
   CXXRecordDecl *LS =
-      CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, BufDecl,
+      CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, BufDecl,
                             SourceLocation(), SourceLocation(), II);
+  LS->addAttr(PackedAttr::CreateImplicit(AST));
   LS->setImplicit(true);
   LS->startDefinition();
 
diff --git a/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl b/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl
index b2b3e13308da3..eca2ed0211d1b 100644
--- a/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl
+++ b/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl
@@ -27,6 +27,3 @@ cbuffer A {
 // AST-NEXT: TextComment {{.*}} Text=" CBuffer decl."
 // AST-NEXT: VarDecl {{.*}} a 'hlsl_constant float'
 // AST-NEXT: VarDecl {{.*}} b 'hlsl_constant int'
-// AST-NEXT: CXXRecordDecl {{.*}} implicit class __layout_A definition
-// AST: FieldDecl {{.*}} a 'float'
-// AST-NEXT: FieldDecl {{.*}} b 'int'
diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl
index f516cf5099e82..8254f0ee00b14 100644
--- a/clang/test/AST/HLSL/cbuffer.hlsl
+++ b/clang/test/AST/HLSL/cbuffer.hlsl
@@ -48,75 +48,83 @@ struct TwoFloats {
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
-  // CHECK: VarDecl {{.*}} col:9 used a1 'hlsl_constant float'
+  // CHECK: VarDecl {{.*}} used a1 'hlsl_constant float'
   float a1;
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB definition
-  // CHECK: FieldDecl {{.*}} a1 'float'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB definition
+  // CHECK: PackedAttr
+  // CHECK-NEXT: FieldDecl {{.*}} a1 'float'
 }
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_CB), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_CB), "");
 
 // Check that buffer layout struct does not include resources or empty types 
-// CHECK: HLSLBufferDecl {{.*}} line:62:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
-  // CHECK: VarDecl {{.*}} col:9 used a2 'hlsl_constant float'
+  // CHECK: VarDecl {{.*}} used a2 'hlsl_constant float'
   float a2;
-  // CHECK: VarDecl {{.*}} col:19 b2 'RWBuffer<float>':'hlsl::RWBuffer<float>'
+  // CHECK: VarDecl {{.*}} b2 'RWBuffer<float>':'hlsl::RWBuffer<float>'
   RWBuffer<float> b2; 
-  // CHECK: VarDecl {{.*}} col:15 c2 'EmptyStruct'
+  // CHECK: VarDecl {{.*}} c2 'EmptyStruct'
   EmptyStruct c2;
-  // CHECK: VarDecl {{.*}} col:9 d2 'float[0]'
+  // CHECK: VarDecl {{.*}} d2 'float[0]'
   float d2[0];
-  // CHECK: VarDecl {{.*}} col:9 e2 'hlsl_constant float'
+  // CHECK: VarDecl {{.*}} f2 'RWBuffer<float>[2]'
+  RWBuffer<float> f2[2];
+  // CHECK: VarDecl {{.*}} e2 'hlsl_constant float'
   float e2;
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_1 definition
-  // CHECK: FieldDecl {{.*}} a2 'float'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_1 definition
+  // CHECK: PackedAttr
+  // CHECK-NEXT: FieldDecl {{.*}} a2 'float'
   // CHECK-NEXT: FieldDecl {{.*}} e2 'float'
 }
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_1), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_1), "");
 
 // Check that layout struct is created for B and the empty struct C is removed
-// CHECK: HLSLBufferDecl {{.*}} line:83:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
-  // CHECK: VarDecl {{.*}} col:5 used s1 'hlsl_constant A'
+  // CHECK: VarDecl {{.*}} used s1 'hlsl_constant A'
   A s1;
-  // CHECK: VarDecl {{.*}} col:5 s2 'hlsl_constant B'
+  // CHECK: VarDecl {{.*}} s2 'hlsl_constant B'
   B s2;
-  // CHECK: VarDecl {{.*}} col:12 s3 'CTypedef':'C'
+  // CHECK: VarDecl {{.*}} s3 'CTypedef':'C'
   CTypedef s3;
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_2 definition
-  // CHECK: FieldDecl {{.*}} s1 'A'
-  // CHECK: FieldDecl {{.*}} s2 '__layout_B'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_2 definition
+  // CHECK: PackedAttr
+  // CHECK-NEXT: FieldDecl {{.*}} s1 'A'
+  // CHECK-NEXT: FieldDecl {{.*}} s2 '__cblayout_B'
 }
-// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_B definition
-// CHECK: FieldDecl {{.*}} a 'float'
+// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_B definition
+// CHECK: PackedAttr
+// CHECK-NEXT: FieldDecl {{.*}} a 'float'
 
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_B), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_2), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_B), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_2), "");
 
 // check that layout struct is created for D because of its base struct
-// CHECK: HLSLBufferDecl {{.*}} line:104:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
   // CHECK: VarDecl {{.*}} s4 'hlsl_constant D'
   D s4;
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_3 definition
-  // CHECK: FieldDecl {{.*}} s4 '__layout_D'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_3 definition
+  // CHECK: PackedAttr
+  // CHECK-NEXT: FieldDecl {{.*}} s4 '__cblayout_D'
 }
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_D definition
-  // CHECK: public '__layout_B'
-  // CHECK: FieldDecl {{.*}} b 'float'
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_D), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_3), "");
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_D definition
+  // CHECK: public '__cblayout_B'
+  // CHECK: PackedAttr
+  // CHECK-NEXT: FieldDecl {{.*}} b 'float'
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_D), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_3), "");
 
 // check that layout struct is created for E because because its base struct
 // is empty and should be eliminated, and BTypedef should reuse the previously
-// defined '__layout_B' 
-// CHECK: HLSLBufferDecl {{.*}} line:122:9 cbuffer CB
+// defined '__cblayout_B' 
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -124,18 +132,20 @@ cbuffer CB {
   E s5;
   // CHECK: VarDecl {{.*}} s6 'hlsl_constant BTypedef':'hlsl_constant B'
   BTypedef s6;
-  // CHECK: CXXRecordDecl {{.*}}  implicit referenced class __layout_CB_4 definition
-  // CHECK: FieldDecl {{.*}} s5 '__layout_E'
-  // CHECK: FieldDecl {{.*}} s6 '__layout_B'
+  // CHECK: CXXRecordDecl {{.*}}  implicit referenced struct __cblayout_CB_4 definition
+  // CHECK: PackedAttr
+  // CHECK-NEXT: FieldDecl {{.*}} s5 '__cblayout_E'
+  // CHECK-NEXT: FieldDecl {{.*}} s6 '__cblayout_B'
 }
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_E definition
-  // CHECK: FieldDecl {{.*}} c 'float'
-  // CHECK-NOT: CXXRecordDecl {{.*}} class __layout_B definition
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_E), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_4), "");
+// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_E definition
+// CHECK: PackedAttr
+// CHECK-NEXT: FieldDecl {{.*}} c 'float'
+// CHECK-NOT: CXXRecordDecl {{.*}} struct __cblayout_B definition
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_E), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_4), "");
 
 // check that this produces empty layout struct
-// CHECK: HLSLBufferDecl {{.*}} line:141:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -149,27 +159,30 @@ cbuffer CB {
   RWBuffer<float> Buf;
   // CHECK: VarDecl {{.*}} ea 'EmptyArrayTypedef':'float[10][0]'
   EmptyArrayTypedef ea;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout_CB_5 definition
+  // CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_CB_5 definition
+  // CHECK: PackedAttr
   // CHECK-NOT: FieldDecl
 }
 
 // check host layout struct with compatible base struct
-// CHECK: HLSLBufferDecl {{.*}} line:160:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
   // CHECK: VarDecl {{.*}} s8 'hlsl_constant F'
   F s8;
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_6 definition
-  // CHECK: FieldDecl {{.*}} s8 '__layout_F'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_6 definition
+  // CHECK: PackedAttr
+  // CHECK-NEXT: FieldDecl {{.*}} s8 '__cblayout_F'
 }
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_F definition
-  // CHECK: public 'A'
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_F), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_CB_6), "");
+// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_F definition
+// CHECK: public 'A'
+// CHECK: PackedAttr
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_F), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_CB_6), "");
 
 // anonymous structs
-// CHECK: HLSLBufferDecl {{.*}} line:175:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -182,7 +195,7 @@ cbuffer CB {
     // CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
     RWBuffer<float> f;
   } s9;
-  // CHECK: VarDecl {{.*}} s9 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:177:3
+  // CHECK: VarDecl {{.*}} s9 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:[[# @LINE - 8]]:3
   // CHECK: CXXRecordDecl {{.*}} struct definition
   struct {
     // CHECK: FieldDecl {{.*}} g 'float'
@@ -190,18 +203,21 @@ cbuffer CB {
     // CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
     RWBuffer<float> f;
   } s10;
-  // CHECK: VarDecl {{.*}} s10 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:187:3
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon definition
-  // CHECK: FieldDecl {{.*}} e 'float'
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon_1 definition
-  // CHECK: FieldDecl {{.*}} g 'float'
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_7 definition
-  // CHECK: FieldDecl {{.*}} s9 '__layout_anon'
-  // CHECK: FieldDecl {{.*}} s10 '__layout_anon_1'
+  // CHECK: VarDecl {{.*}} s10 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:[[# @LINE - 6]]:3
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_anon definition
+  // CHECK: PackedAttr
+  // CHECK-NEXT: FieldDecl {{.*}} e 'float'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_anon_1 definition
+  // CHECK: PackedAttr
+  // CHECK-NEXT: FieldDecl {{.*}} g 'float'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_7 definition
+  // CHECK: PackedAttr
+  // CHECK-NEXT: FieldDecl {{.*}} s9 '__cblayout_anon'
+  // CHECK-NEXT: FieldDecl {{.*}} s10 '__cblayout_anon_1'
 }
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_anon), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_anon_1), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_7), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_anon), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_anon_1), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_7), "");
 
 // Add uses for the constant buffer declarations so they are not optimized away
 export float foo() {
diff --git a/clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl b/clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl
index 12ce327d8be02..09596eda90b6a 100644
--- a/clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl
+++ b/clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl
@@ -19,10 +19,10 @@ namespace NS1 {
       int b;
       EmptyStruct es;
     };
-    // CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+    // CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_Foo definition
     // CHECK: FieldDecl {{.*}} b 'int'
   };
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+  // CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_Foo definition
   // CHECK: FieldDecl {{.*}} a 'float'
 }
 
@@ -41,12 +41,12 @@ cbuffer CB1 {
   NS1::Foo foo2;
   // CHECK: VarDecl {{.*}} foo3 'hlsl_constant NS1::Bar::Foo'
   NS1::Bar::Foo foo3;
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB1 definition
-  // CHECK: FieldDecl {{.*}} foo1 '__layout_Foo'
-  // CHECK: FieldDecl {{.*}} foo2 'NS1::__layout_Foo'
-  // CHECK: FieldDecl {{.*}} foo3 'NS1::Bar::__layout_Foo'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB1 definition
+  // CHECK: FieldDecl {{.*}} foo1 '__cblayout_Foo'
+  // CHECK: FieldDecl {{.*}} foo2 'NS1::__cblayout_Foo'
+  // CHECK: FieldDecl {{.*}} foo3 'NS1::Bar::__cblayout_Foo'
 }
-// CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+// CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_Foo definition
 // CHECK: FieldDecl {{.*}} c 'double'
 
 struct CB1ExpectedShape {
@@ -54,7 +54,7 @@ struct CB1ExpectedShape {
     float a2;
     int a;
 };
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(CB1ExpectedShape, __layout_CB1), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(CB1ExpectedShape, __cblayout_CB1), "");
 
 namespace NS2 {
   struct Foo { 
@@ -73,13 +73,13 @@ namespace NS2 {
     NS1::Foo foo2;
     // CHECK: VarDecl {{.*}} foo3 'hlsl_constant NS1::Bar::Foo'
     NS1::Bar::Foo foo3;
-    // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB2 definition
-    // CHECK: FieldDecl {{.*}} foo0 '__layout_Foo'
-    // CHECK: FieldDecl {{.*}} foo1 'NS2::__layout_Foo'
-    // CHECK: FieldDecl {{.*}} foo2 'NS1::__layout_Foo'
-    // CHECK: FieldDecl {{.*}} foo3 'NS1::Bar::__layout_Foo'
+    // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB2 definition
+    // CHECK: FieldDecl {{.*}} foo0 '__cblayout_Foo'
+    // CHECK: FieldDecl {{.*}} foo1 'NS2::__cblayout_Foo'
+    // CHECK: FieldDecl {{.*}} foo2 'NS1::__cblayout_Foo'
+    // CHECK: FieldDecl {{.*}} foo3 'NS1::Bar::__cblayout_Foo'
   }
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+  // CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_Foo definition
   // CHECK: FieldDecl {{.*}} d 'float[4]'
 }
 
@@ -89,7 +89,7 @@ struct CB2ExpectedShape {
     float a2;
     int a;
 };
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(CB2ExpectedShape, NS2::__layout_CB2), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(CB2ExpectedShape, NS2::__cblayout_CB2), "");
 
 // Add uses for the constant buffer declarations so they are not optimized away
 // CHECK: ExportDecl
diff --git a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
index 98d7aba397852..754948931ee53 100644
--- a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
+++ b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
@@ -21,14 +21,14 @@ float foo() {
 // CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK-NEXT: HLSLResourceAttr {{.*}} Implicit CBuffer
 // CHECK-NEXT: VarDecl 0x[[A:[0-9a-f]+]] {{.*}} imported used a 'hlsl_constant float'
-// CHECK-NEXT: CXXRecordDecl {{.*}} imported implicit <undeserialized declarations> class __layout_A definition
+// CHECK-NEXT: CXXRecordDecl {{.*}} imported implicit <undeserialized declarations> struct __cblayout_A definition
 // CHECK: FieldDecl {{.*}} imported a 'float'
 
 // CHECK: HLSLBufferDecl {{.*}} line:11:9 imported <undeserialized declarations> tbuffer B
 // CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit SRV
 // CHECK-NEXT: HLSLResourceAttr {{.*}} Implicit TBuffer
 // CHECK-NEXT: VarDecl 0x[[B:[0-9a-f]+]] {{.*}} imported used b 'hlsl_constant float'
-// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit <undeserialized declarations> class __layout_B definition
+// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit <undeserialized declarations> struct __cblayout_B definition
 // CHECK: FieldDecl 0x{{[0-9a-f]+}} {{.*}} imported b 'float'
 
 // CHECK-NEXT: FunctionDecl {{.*}} line:15:7 imported foo 'float ()'

>From c80415a22bf9b1e06928e84d8d0efa646fbaa5f9 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 28 Jan 2025 16:52:45 -0800
Subject: [PATCH 02/19] filter groupshared var decls

---
 clang/lib/Sema/SemaHLSL.cpp      | 3 ++-
 clang/test/AST/HLSL/cbuffer.hlsl | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 97df01a5dd307..b71dd2b273a1c 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -484,7 +484,8 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
 
   for (Decl *D : BufDecl->decls()) {
     VarDecl *VD = dyn_cast<VarDecl>(D);
-    if (!VD || VD->getStorageClass() == SC_Static)
+    if (!VD || VD->getStorageClass() == SC_Static ||
+        VD->getType().getAddressSpace() == LangAS::hlsl_groupshared)
       continue;
     const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
     if (FieldDecl *FD =
diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl
index 8254f0ee00b14..865db1201baa5 100644
--- a/clang/test/AST/HLSL/cbuffer.hlsl
+++ b/clang/test/AST/HLSL/cbuffer.hlsl
@@ -71,6 +71,8 @@ cbuffer CB {
   float d2[0];
   // CHECK: VarDecl {{.*}} f2 'RWBuffer<float>[2]'
   RWBuffer<float> f2[2];
+  // CHECK: VarDecl {{.*}} g2 'groupshared float'
+  groupshared float g2;
   // CHECK: VarDecl {{.*}} e2 'hlsl_constant float'
   float e2;
   // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_1 definition

>From cf08adb6b9e181613e81d2cfbadbbb68e645fe33 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 28 Jan 2025 14:46:26 -0800
Subject: [PATCH 03/19] [HLSL] Translate cbuffer declarations to target type
 dx.CBuffer - initial commit

---
 clang/include/clang/AST/Decl.h                |   6 +
 clang/include/clang/AST/Type.h                |   4 +-
 clang/lib/AST/Decl.cpp                        |  17 +-
 clang/lib/CodeGen/CGHLSLRuntime.cpp           | 409 ++++++++++++------
 clang/lib/CodeGen/CGHLSLRuntime.h             |  31 +-
 clang/lib/CodeGen/Targets/DirectX.cpp         |  11 +-
 clang/lib/Sema/SemaHLSL.cpp                   |   3 +
 clang/test/CodeGenHLSL/cbuf.hlsl              |  33 --
 clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl |  29 --
 clang/test/CodeGenHLSL/cbuffer.hlsl           | 200 +++++++++
 .../CodeGenHLSL/cbuffer_and_namespaces.hlsl   |  63 +++
 .../CodeGenHLSL/cbuffer_with_packoffset.hlsl  |  40 ++
 ...uffer_with_static_global_and_function.hlsl |  32 ++
 clang/test/CodeGenHLSL/resource-bindings.hlsl |   4 +
 .../static_global_and_function_in_cb.hlsl     |  22 -
 15 files changed, 679 insertions(+), 225 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/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 16403774e72b3..e1c7e3817699c 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -5032,6 +5032,9 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
   SourceLocation KwLoc;
   /// IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer).
   bool IsCBuffer;
+  /// HasValidPackoffset - Whether the buffer has valid packoffset annotations
+  //                       on all declarations
+  bool HasPackoffset;
 
   HLSLBufferDecl(DeclContext *DC, bool CBuffer, SourceLocation KwLoc,
                  IdentifierInfo *ID, SourceLocation IDLoc,
@@ -5052,6 +5055,9 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
   SourceLocation getRBraceLoc() const { return RBraceLoc; }
   void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
   bool isCBuffer() const { return IsCBuffer; }
+  void setHasPackoffset(bool PO) { HasPackoffset = PO; }
+  bool hasPackoffset() const { return HasPackoffset; }
+  const CXXRecordDecl *getLayoutStruct() const;
 
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 1d9743520654e..c3ff7ebd88516 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -6266,8 +6266,8 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
     LLVM_PREFERRED_TYPE(bool)
     uint8_t RawBuffer : 1;
 
-    Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV,
-               bool RawBuffer)
+    Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV = false,
+               bool RawBuffer = false)
         : ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {}
 
     Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {}
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index beb5fcaefac53..fa7d03354a993 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1747,6 +1747,10 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
       }
     }
 
+    // Suppress transparent contexts like export or HLSLBufferDecl context
+    if (Ctx->isTransparentContext())
+      continue;
+
     // Skip non-named contexts such as linkage specifications and ExportDecls.
     const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx);
     if (!ND)
@@ -5713,7 +5717,7 @@ HLSLBufferDecl::HLSLBufferDecl(DeclContext *DC, bool CBuffer,
                                SourceLocation IDLoc, SourceLocation LBrace)
     : NamedDecl(Decl::Kind::HLSLBuffer, DC, IDLoc, DeclarationName(ID)),
       DeclContext(Decl::Kind::HLSLBuffer), LBraceLoc(LBrace), KwLoc(KwLoc),
-      IsCBuffer(CBuffer) {}
+      IsCBuffer(CBuffer), HasPackoffset(false) {}
 
 HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
                                        DeclContext *LexicalParent, bool CBuffer,
@@ -5743,6 +5747,17 @@ HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C,
                                     SourceLocation(), SourceLocation());
 }
 
+const CXXRecordDecl *HLSLBufferDecl::getLayoutStruct() const {
+  // Layout struct is the last decl in the HLSLBufferDecl.
+  if (CXXRecordDecl *RD = llvm::dyn_cast_or_null<CXXRecordDecl>(LastDecl)) {
+    assert(RD->getName().starts_with(
+               ("__cblayout_" + getIdentifier()->getName()).str()) &&
+           "expected buffer layout struct");
+    return RD;
+  }
+  llvm_unreachable("HLSL buffer is missing a layout struct");
+}
+
 //===----------------------------------------------------------------------===//
 // ImportDecl Implementation
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 2ce54cc3c52ef..d3d9d42664359 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -16,15 +16,20 @@
 #include "CGDebugInfo.h"
 #include "CodeGenModule.h"
 #include "TargetInfo.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/Type.h"
 #include "clang/Basic/TargetOptions.h"
+#include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
 #include "llvm/IR/Value.h"
 #include "llvm/Support/Alignment.h"
 
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormatVariadic.h"
 
 using namespace clang;
@@ -32,6 +37,9 @@ using namespace CodeGen;
 using namespace clang::hlsl;
 using namespace llvm;
 
+static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
+                                 unsigned Slot, unsigned Space);
+
 namespace {
 
 void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
@@ -54,54 +62,11 @@ 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;
-
-  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);
-  }
-  Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
-}
-
-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);
-
-  return CBGV;
-}
 
 } // namespace
 
@@ -119,48 +84,280 @@ 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;
+}
+
+// Returns true if the type is an HLSL resource class or an array of
+// HLSL resource classes
+static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) {
+  while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
+    Ty = CAT->getArrayElementTypeNoTypeQual();
+  return isResourceRecordType(Ty);
+}
+
+static ConstantAsMetadata *getConstIntMetadata(LLVMContext &Ctx, uint32_t value,
+                                               bool isSigned = false) {
+  return ConstantAsMetadata::get(
+      ConstantInt::get(Ctx, llvm::APInt(32, value, isSigned)));
+}
+
+static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
+  assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
+  if (Ty->isVectorTy()) {
+    llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
+    return FVT->getNumElements() *
+           (FVT->getElementType()->getScalarSizeInBits() / 8);
+  }
+  return Ty->getScalarSizeInBits() / 8;
+}
+
+size_t
+CGHLSLRuntime::getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy) {
+  assert(StructTy->isStructTy());
+
+  // check if we already have a side for this struct
+  auto SizeIt = StructSizesForBuffer.find(StructTy);
+  if (SizeIt != StructSizesForBuffer.end())
+    return SizeIt->getSecond();
+
+  // if not, calculate the struct layout and add it to metadata
+  LLVMContext &Ctx = CGM.getLLVMContext();
+  SmallVector<llvm::Metadata *> LayoutItems;
+  LayoutItems.push_back(MDString::get(Ctx, StructTy->getName()));
+
+  size_t StructSize = 0;
+  LayoutItems.push_back(nullptr); // reserve one slot for the buffer size
+
+  for (llvm::Type *ElTy : StructTy->elements())
+    addLayoutInfoForBufferElement(StructSize, LayoutItems, ElTy);
+
+  // set the size of the buffer
+  LayoutItems[1] = getConstIntMetadata(Ctx, StructSize);
+
+  // add the struct layout info to metadata
+  MDNode *LayoutMDNode = MDNode::get(CGM.getLLVMContext(), LayoutItems);
+  CGM.getModule()
+      .getOrInsertNamedMetadata("hlsl.cblayouts")
+      ->addOperand(LayoutMDNode);
+
+  // add struct size to list and return it
+  StructSizesForBuffer[StructTy] = StructSize;
+  return StructSize;
+}
+
+void CGHLSLRuntime::addLayoutInfoForBufferElement(
+    size_t &EndOffset, SmallVector<llvm::Metadata *> &LayoutItems,
+    llvm::Type *LayoutTy, HLSLPackOffsetAttr *PackoffsetAttr) {
+
+  // calculate element offset and size; for arrays also calculate array
+  // element count and stride
+  size_t ElemOffset = 0;
+  size_t ElemSize = 0;
+  size_t ArrayCount = 1;
+  size_t ArrayStride = 0;
+  size_t NextRowOffset = llvm::alignTo(EndOffset, 16U);
+
+  if (LayoutTy->isArrayTy()) {
+    llvm::Type *Ty = LayoutTy;
+    while (Ty->isArrayTy()) {
+      ArrayCount *= Ty->getArrayNumElements();
+      Ty = Ty->getArrayElementType();
+    }
+    ElemSize =
+        Ty->isStructTy()
+            ? getOrCalculateStructSizeForBuffer(cast<llvm::StructType>(Ty))
+            : getScalarOrVectorSize(Ty);
+    ArrayStride = llvm::alignTo(ElemSize, 16U);
+    ElemOffset =
+        PackoffsetAttr ? PackoffsetAttr->getOffsetInBytes() : NextRowOffset;
+
+  } else if (LayoutTy->isStructTy()) {
+    ElemOffset =
+        PackoffsetAttr ? PackoffsetAttr->getOffsetInBytes() : NextRowOffset;
+    ElemSize =
+        getOrCalculateStructSizeForBuffer(cast<llvm::StructType>(LayoutTy));
+
+  } else {
+    size_t Align = 0;
+    if (LayoutTy->isVectorTy()) {
+      llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(LayoutTy);
+      size_t SubElemSize = FVT->getElementType()->getScalarSizeInBits() / 8;
+      ElemSize = FVT->getNumElements() * SubElemSize;
+      Align = SubElemSize;
+    } else {
+      assert(LayoutTy->isIntegerTy() || LayoutTy->isFloatingPointTy());
+      ElemSize = LayoutTy->getScalarSizeInBits() / 8;
+      Align = ElemSize;
+    }
+    if (PackoffsetAttr) {
+      ElemOffset = PackoffsetAttr->getOffsetInBytes();
+    } else {
+      ElemOffset = llvm::alignTo(EndOffset, Align);
+      if (ElemOffset + ElemSize > NextRowOffset)
+        ElemOffset = NextRowOffset;
+    }
   }
 
-  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));
+  // Update end offset of the buffer/struct layout; do not update it if
+  // the provided EndOffset is already bigger than the new one (which may happen
+  // with packoffset annotations)
+  unsigned NewEndOffset =
+      ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
+  EndOffset = std::max<size_t>(EndOffset, NewEndOffset);
+
+  // create metadata constan with the offset and stride and add to list
+  LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), ElemOffset));
+  if (ArrayStride)
+    LayoutItems.push_back(
+        getConstIntMetadata(CGM.getLLVMContext(), ArrayStride));
 }
 
-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)) {
+void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
+                                                 llvm::GlobalVariable *BufGV) {
+  llvm::StructType *LayoutStruct = cast<llvm::StructType>(
+      cast<llvm::TargetExtType>(BufGV->getValueType())->getTypeParameter(0));
+
+  LLVMContext &Ctx = CGM.getLLVMContext();
+
+  SmallVector<llvm::Metadata *> BufGlobals;
+  BufGlobals.push_back(ValueAsMetadata::get(BufGV));
+
+  SmallVector<llvm::Metadata *> LayoutItems;
+  LayoutItems.push_back(MDString::get(Ctx, LayoutStruct->getName()));
+
+  size_t BufferSize = 0;
+  size_t BufferSizeIndex = LayoutItems.size();
+  LayoutItems.push_back(nullptr); // reserve one slot for the buffer size
+
+  bool UsePackoffset = BufDecl->hasPackoffset();
+
+  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)) {
+      continue;
+    if (isa<FunctionDecl>(D)) {
       // A function within an cbuffer is effectively a top-level function,
       // as it only refers to globally scoped declarations.
-      CGM.EmitTopLevelDecl(it);
+      CGM.EmitTopLevelDecl(D);
+      continue;
+    }
+    if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+      QualType VDTy = VD->getType();
+      if (VDTy.getAddressSpace() != LangAS::hlsl_constant) {
+        if (VD->getStorageClass() == SC_Static ||
+            isResourceRecordTypeOrArrayOf(VDTy.getTypePtr())) {
+          // Emit static 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++;
+
+      assert((CGM.getTypes().ConvertTypeForMem(VDTy) == LayoutType ||
+              (LayoutType->isStructTy() &&
+               cast<llvm::StructType>(LayoutType)
+                   ->getName()
+                   .starts_with(("struct.__cblayout_" +
+                                 VDTy->getAsCXXRecordDecl()->getName())
+                                    .str()))) &&
+             "layout type does not match the converted element type");
+
+      // handle any resources declarations inside the struct
+      if (VDTy->isStructureType() && VDTy->isHLSLIntangibleType())
+        // FIXME: handle resources in cbuffer structs
+        llvm_unreachable("resources in cbuffer are not supported yet");
+
+      GlobalVariable *ElemGV =
+          cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
+      BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
+
+      assert(((UsePackoffset && VD->hasAttr<HLSLPackOffsetAttr>()) ||
+              !UsePackoffset) &&
+             "expected packoffset attribute on every declaration");
+
+      addLayoutInfoForBufferElement(
+          BufferSize, LayoutItems, LayoutType,
+          UsePackoffset ? VD->getAttr<HLSLPackOffsetAttr>() : nullptr);
     }
   }
+  assert(ElemIt == LayoutStruct->element_end() &&
+         "number of elements in layout struct does not match");
+
+  // add buffer global and a list of its constants to metadata
+  MDNode *BufMDNode = MDNode::get(CGM.getLLVMContext(), BufGlobals);
+  CGM.getModule().getOrInsertNamedMetadata("hlsl.cbs")->addOperand(BufMDNode);
+
+  // set the size of the buffer
+  LayoutItems[BufferSizeIndex] = getConstIntMetadata(Ctx, BufferSize);
+
+  // add buffer layout to metadata
+  MDNode *LayoutMDNode = MDNode::get(CGM.getLLVMContext(), LayoutItems);
+  CGM.getModule()
+      .getOrInsertNamedMetadata("hlsl.cblayouts")
+      ->addOperand(LayoutMDNode);
 }
 
-void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *D) {
-  Buffers.emplace_back(Buffer(D));
-  addBufferDecls(D, Buffers.back());
+// Creates resource handle type for the HLSL buffer
+static const clang::HLSLAttributedResourceType *
+createBufferHandleType(const HLSLBufferDecl *BufDecl) {
+  ASTContext &AST = BufDecl->getASTContext();
+  QualType QT = AST.getHLSLAttributedResourceType(
+      AST.HLSLResourceTy,
+      QualType(BufDecl->getLayoutStruct()->getTypeForDecl(), 0),
+      HLSLAttributedResourceType::Attributes(ResourceClass::CBuffer));
+  return cast<HLSLAttributedResourceType>(QT.getTypePtr());
+}
+
+// Creates temporary global variables for all declarations within the constant
+// 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 *BufDecl) {
+
+  assert(BufDecl->isCBuffer() && "tbuffer codegen is not supported yet");
+
+  // Create resource handle type for the buffer
+  const clang::HLSLAttributedResourceType *ResHandleTy =
+      createBufferHandleType(BufDecl);
+
+  // ignore empty constant buffer
+  if (ResHandleTy->getContainedType()->getAsCXXRecordDecl()->isEmpty())
+    return;
+
+  // Create global variable for the buffer
+  llvm::Module &M = CGM.getModule();
+  llvm::TargetExtType *TargetTy =
+      cast<llvm::TargetExtType>(convertHLSLSpecificType(ResHandleTy));
+  llvm::GlobalVariable *BufGV =
+      new GlobalVariable(TargetTy, /*isConstant*/ true,
+                         GlobalValue::LinkageTypes::ExternalLinkage, nullptr,
+                         llvm::formatv("{0}{1}", BufDecl->getName(),
+                                       BufDecl->isCBuffer() ? ".cb" : ".tb"),
+                         GlobalValue::NotThreadLocal);
+  M.insertGlobalVariable(BufGV);
+
+  // Add globals for buffer elements and create metadata node for the buffer
+  emitBufferGlobalsAndMetadata(BufDecl, BufGV);
+
+  // Add cbuffer resource initialization
+  const HLSLResourceBindingAttr *RBA =
+      BufDecl->getAttr<HLSLResourceBindingAttr>();
+  // FIXME: handle implicit binding if no binding attribute is found
+  if (RBA)
+    createResourceInitFn(CGM, BufGV, RBA->getSlotNumber(),
+                         RBA->getSpaceNumber());
 }
 
 void CGHLSLRuntime::finishCodeGen() {
@@ -173,28 +370,8 @@ void CGHLSLRuntime::finishCodeGen() {
   generateGlobalCtorDtorCalls();
   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);
-  }
 }
 
-CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D)
-    : Name(D->getName()), IsCBuffer(D->isCBuffer()),
-      Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
-
 void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
                                                 llvm::hlsl::ResourceClass RC,
                                                 llvm::hlsl::ResourceKind RK,
@@ -521,21 +698,15 @@ void CGHLSLRuntime::generateGlobalCtorDtorCalls() {
   }
 }
 
-// Returns true if the type is an HLSL resource class
-static bool isResourceRecordType(const clang::Type *Ty) {
-  return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
-}
-
-static void createResourceInitFn(CodeGenModule &CGM, const VarDecl *VD,
-                                 llvm::GlobalVariable *GV, unsigned Slot,
-                                 unsigned Space) {
+static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
+                                 unsigned Slot, unsigned Space) {
   LLVMContext &Ctx = CGM.getLLVMContext();
   llvm::Type *Int1Ty = llvm::Type::getInt1Ty(Ctx);
 
   llvm::Function *InitResFunc = llvm::Function::Create(
       llvm::FunctionType::get(CGM.VoidTy, false),
       llvm::GlobalValue::InternalLinkage,
-      ("_init_resource_" + VD->getName()).str(), CGM.getModule());
+      ("_init_resource_" + GV->getName()).str(), CGM.getModule());
   InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
 
   llvm::BasicBlock *EntryBB =
@@ -544,20 +715,15 @@ static void createResourceInitFn(CodeGenModule &CGM, const VarDecl *VD,
   const DataLayout &DL = CGM.getModule().getDataLayout();
   Builder.SetInsertPoint(EntryBB);
 
-  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);
-  assert(TargetTy != nullptr &&
-         "Failed to convert resource handle to target type");
+  // Make sure the global variable is resource handle (cbuffer) or
+  // resource class (=class where the first element is a resource handle).
+  llvm::Type *HandleTy = GV->getValueType();
+  assert((HandleTy->isTargetExtTy() ||
+          (HandleTy->isStructTy() &&
+           HandleTy->getStructElementType(0)->isTargetExtTy())) &&
+         "unexpected type of the global");
+  if (!HandleTy->isTargetExtTy())
+    HandleTy = HandleTy->getStructElementType(0);
 
   llvm::Value *Args[] = {
       llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */
@@ -569,9 +735,9 @@ static void createResourceInitFn(CodeGenModule &CGM, const VarDecl *VD,
       llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */
   };
   llvm::Value *CreateHandle = Builder.CreateIntrinsic(
-      /*ReturnType=*/TargetTy,
+      /*ReturnType=*/HandleTy,
       CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(), Args, nullptr,
-      Twine(VD->getName()).concat("_h"));
+      Twine(GV->getName()).concat("_h"));
 
   llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0);
   Builder.CreateAlignedStore(CreateHandle, HandleRef,
@@ -598,8 +764,7 @@ void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
     // not implemented yet.
     return;
 
-  createResourceInitFn(CGM, VD, GV, RBA->getSlotNumber(),
-                       RBA->getSpaceNumber());
+  createResourceInitFn(CGM, GV, RBA->getSlotNumber(), RBA->getSpaceNumber());
 }
 
 llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 032b2dee82f21..a6e3c78f52285 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/ADT/DenseMap.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicsDirectX.h"
@@ -46,25 +47,31 @@
     }                                                                          \
   }
 
+using ResourceClass = llvm::dxil::ResourceClass;
+
 namespace llvm {
 class GlobalVariable;
 class Function;
 class StructType;
+class Metadata;
 } // namespace llvm
 
 namespace clang {
+class NamedDecl;
 class VarDecl;
 class ParmVarDecl;
 class HLSLBufferDecl;
 class HLSLResourceBindingAttr;
 class Type;
 class DeclContext;
+class HLSLPackOffsetAttr;
 
 class FunctionDecl;
 
 namespace CodeGen {
 
 class CodeGenModule;
+class CGBuilderTy;
 
 class CGHLSLRuntime {
 public:
@@ -124,16 +131,6 @@ class CGHLSLRuntime {
     unsigned Space;
     BufferResBinding(HLSLResourceBindingAttr *Attr);
   };
-  struct Buffer {
-    Buffer(const HLSLBufferDecl *D);
-    llvm::StringRef Name;
-    // IsCBuffer - 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;
-  };
 
 protected:
   CodeGenModule &CGM;
@@ -167,10 +164,18 @@ class CGHLSLRuntime {
                                    llvm::hlsl::ResourceKind RK, bool IsROV,
                                    llvm::hlsl::ElementType ET,
                                    BufferResBinding &Binding);
-  void addConstant(VarDecl *D, Buffer &CB);
-  void addBufferDecls(const DeclContext *DC, Buffer &CB);
+  void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
+                                    llvm::GlobalVariable *BufGV);
+  void addLayoutInfoForBufferElement(
+      size_t &EndOffset, SmallVector<llvm::Metadata *> &LayoutItems,
+      llvm::Type *LayoutTy, HLSLPackOffsetAttr *PackoffsetAttr = nullptr);
+
+  size_t getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy);
+
   llvm::Triple::ArchType getArch();
-  llvm::SmallVector<Buffer> Buffers;
+
+  // sizes of structs that in constant buffer layout
+  llvm::DenseMap<llvm::StructType *, size_t> StructSizesForBuffer;
 };
 
 } // namespace CodeGen
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 7935f7ae37004..33bddc56d83f2 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -44,6 +44,7 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
       return nullptr;
 
     // convert element type
+    // llvm::Type *ElemType = CGM.getTypes().ConvertTypeForMem(ContainedTy);
     llvm::Type *ElemType = CGM.getTypes().ConvertType(ContainedTy);
 
     llvm::StringRef TypeName =
@@ -56,9 +57,13 @@ 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);
+    return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {Ty});
+  }
   case llvm::dxil::ResourceClass::Sampler:
     llvm_unreachable("dx.Sampler handles are not implemented yet");
     break;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index b71dd2b273a1c..2807cc773320b 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -239,6 +239,7 @@ static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
 
   // Make sure there is no overlap in packoffset - sort PackOffsetVec by offset
   // and compare adjacent values.
+  bool IsValid = true;
   ASTContext &Context = S.getASTContext();
   std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
             [](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
@@ -257,8 +258,10 @@ static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
       VarDecl *NextVar = PackOffsetVec[i + 1].first;
       S.Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
           << NextVar << Var;
+      IsValid = false;
     }
   }
+  BufDecl->setHasPackoffset(IsValid);
 }
 
 // Returns true if the array has a zero size = if any of the dimensions is 0
diff --git a/clang/test/CodeGenHLSL/cbuf.hlsl b/clang/test/CodeGenHLSL/cbuf.hlsl
deleted file mode 100644
index 825e7b8161a60..0000000000000
--- a/clang/test/CodeGenHLSL/cbuf.hlsl
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan-library %s \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// CHECK: @a = external addrspace(2) externally_initialized global float, align 4
-// CHECK: @b = external addrspace(2) externally_initialized global double, align 8
-// CHECK: @c = external addrspace(2) externally_initialized global float, align 4
-// CHECK: @d = external addrspace(2) externally_initialized global double, align 8
-
-// 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 addrspace(2) @a, align 4
-// CHECK: load double, ptr addrspace(2) @b, align 8
-// CHECK: load float, ptr addrspace(2) @c, align 4
-// CHECK: load double, ptr addrspace(2) @d, 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 13c401d428331..0000000000000
--- a/clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
+++ /dev/null
@@ -1,29 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan-library %s \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// Make sure cbuffer inside namespace works.
-
-// CHECK: @_ZN2n02n11aE = external addrspace(2) externally_initialized global float, align 4
-// CHECK: @_ZN2n01bE = external addrspace(2) externally_initialized global float, align 4
-
-// 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 addrspace(2) @_ZN2n02n11aE, align 4
-// CHECK: load float, ptr addrspace(2) @_ZN2n01bE, 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 0000000000000..99f16ea62cdcb
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -0,0 +1,200 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute \
+// RUN:   -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// CHECK: %struct.__cblayout_CBScalars = type <{ float, double, half, i64, i32, i16, i32, i64 }>
+// CHECK: %struct.__cblayout_CBVectors = type <{ <3 x float>, <3 x double>, <2 x half>, <3 x i64>, <4 x i32>, <3 x i16>, <3 x i64> }>
+// CHECK: %struct.__cblayout_CBArrays = type <{ [3 x float], [2 x <3 x double>], [2 x [2 x half]], [3 x i64], [2 x [3 x [4 x <4 x i32>]]], [1 x i16], [2 x i64], [4 x i32] }>
+// CHECK: %struct.__cblayout_CBStructs = type { %struct.A, %struct.B, %struct.C, [5 x %struct.A], %struct.__cblayout_D, half, %struct.B, <3 x i16> }
+// CHECK: %struct.A = type { <2 x float> }
+// CHECK: %struct.C = type { i32, %struct.A }
+// CHECK: %struct.__cblayout_D = type { [2 x [3 x %struct.B]] }
+// CHECK: %struct.B = type { %struct.A, <3 x i16> }
+
+cbuffer CBScalars : register(b1, space5) {
+  float a1;
+  double a2;
+  float16_t a3;
+  uint64_t a4;
+  int a5;
+  uint16_t a6;
+  bool a7;
+  int64_t a8;
+}
+
+// CHECK: @CBScalars.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBScalars)
+// CHECK: @a1 = external addrspace(2) global float, align 4
+// CHECK: @a2 = external addrspace(2) global double, align 8
+// CHECK: @a3 = external addrspace(2) global half, align 2
+// CHECK: @a4 = external addrspace(2) global i64, align 8
+// CHECK: @a5 = external addrspace(2) global i32, align 4
+// CHECK: @a6 = external addrspace(2) global i16, align 2
+// CHECK: @a7 = external addrspace(2) global i32, align 4
+// CHECK: @a8 = external addrspace(2) global i64, align 8
+
+cbuffer CBVectors {
+  float3 b1;
+  double3 b2;
+  float16_t2 b3;
+  uint64_t3 b4;
+  int4 b5;
+  uint16_t3 b6;
+  int64_t3 b7;
+  // FIXME: add s bool vectors after llvm-project/llvm#91639 is added
+}
+
+// CHECK: @CBVectors.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBVectors)
+// CHECK: @b1 = external addrspace(2) global <3 x float>, align 16
+// CHECK: @b2 = external addrspace(2) global <3 x double>, align 32
+// CHECK: @b3 = external addrspace(2) global <2 x half>, align 4
+// CHECK: @b4 = external addrspace(2) global <3 x i64>, align 32
+// CHECK: @b5 = external addrspace(2) global <4 x i32>, align 16
+// CHECK: @b6 = external addrspace(2) global <3 x i16>, align 8
+// CHECK: @b7 = external addrspace(2) global <3 x i64>, align 32
+
+cbuffer CBArrays : register(b2) {
+  float c1[3];
+  double3 c2[2];
+  float16_t c3[2][2];
+  uint64_t c4[3];
+  int4 c5[2][3][4];
+  uint16_t c6[1];
+  int64_t c7[2];
+  bool c8[4];
+}
+
+// CHECK: @CBArrays.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBArrays)
+// CHECK: @c1 = external addrspace(2) global [3 x float], align 4
+// CHECK: @c2 = external addrspace(2) global [2 x <3 x double>], align 32
+// CHECK: @c3 = external addrspace(2) global [2 x [2 x half]], align 2
+// CHECK: @c4 = external addrspace(2) global [3 x i64], align 8
+// CHECK: @c5 = external addrspace(2) global [2 x [3 x [4 x <4 x i32>]]], align 16
+// CHECK: @c6 = external addrspace(2) global [1 x i16], align 2
+// CHECK: @c7 = external addrspace(2) global [2 x i64], align 8
+// CHECK: @c8 = external addrspace(2) global [4 x i32], align 4
+
+struct Empty {};
+
+struct A {
+  float2 f1;
+};
+
+struct B : A {
+  uint16_t3 f2;
+};
+
+struct C {
+  int i;
+  A f3;
+};
+
+struct D {
+  B array_of_B[2][3];
+  Empty es;
+};
+
+// CHECK: @CBStructs.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBStructs)
+// CHECK: @a = external addrspace(2) global %struct.A, align 8
+// CHECK: @b = external addrspace(2) global %struct.B, align 8
+// CHECK: @c = external addrspace(2) global %struct.C, align 8
+// CHECK: @array_of_A = external addrspace(2) global [5 x %struct.A], align 8
+// CHECK: @d = external addrspace(2) global %struct.__cblayout_D, align 8
+// CHECK: @e = external addrspace(2) global half, align 2
+
+cbuffer CBStructs {
+  A a;
+  B b;
+  C c;
+  A array_of_A[5];
+  D d;
+  half e;
+  B f;
+  uint16_t3 g;
+};
+
+struct Test {
+    float a, b;
+};
+
+// CHECK: @CBMix.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBMix)
+// CHECK: @test = external addrspace(2) global [2 x %struct.Test], align 4
+// CHECK: @f1 = external addrspace(2) global float, align 4
+// CHECK: @f2 = external addrspace(2) global [3 x [2 x <2 x float>]], align 8
+// CHECK: @f3 = external addrspace(2) global float, align 4
+// CHECK: @s = external addrspace(2) global %struct.anon, align 4
+// CHECK: @dd = external addrspace(2) global double, align 8
+// CHECK: @f4 = external addrspace(2) global float, align 4
+// CHECK: @dv = external addrspace(2) global <1 x double>, align 8
+// CHECK: @uv = external addrspace(2) global i16, align 2
+
+cbuffer CBMix {
+    Test test[2];
+    float f1;
+    float2 f2[3][2];
+    float f3;
+    struct { float c; } s;
+    double dd;
+    float f4;
+    vector<double,1> dv;
+    uint16_t uv;
+};  
+
+// CHECK: efine internal void @_init_resource_CBScalars.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %[[HANDLE1:.*]] = call target("dx.CBuffer", %struct.__cblayout_CBScalars)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBScalarsst(i32 5, i32 1, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", %struct.__cblayout_CBScalars) %[[HANDLE1]], ptr @CBScalars.cb, align 4
+
+// CHECK: define internal void @_init_resource_CBArrays.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %[[HANDLE2:.*]] = call target("dx.CBuffer", %struct.__cblayout_CBArrays)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBArraysst(i32 0, i32 2, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", %struct.__cblayout_CBArrays) %[[HANDLE2]], ptr @CBArrays.cb, align 4
+
+RWBuffer<float> Buf;
+
+[numthreads(4,1,1)]
+void main() {
+  //Buf[0] = a1 + b1.z + c1[2] + a.f1.y;
+  Buf[0] = a.f1.y;
+}
+
+// CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_init_resource_CBScalars.cb()
+// CHECK-NEXT: call void @_init_resource_CBArrays.cb()
+
+// CHECK: !hlsl.cbs = !{![[CBSCALARS:[0-9]+]], ![[CBVECTORS:[0-9]+]], ![[CBARRAYS:[0-9]+]], ![[CBSTRUCTS:[0-9]+]], ![[CBMIX:[0-9]+]]}
+// CHECK: !hlsl.cblayouts = !{![[CBSCALARS_LAYOUT:[0-9]+]], ![[CBVECTORS_LAYOUT:[0-9]+]], ![[CBARRAYS_LAYOUT:[0-9]+]], ![[A_LAYOUT:[0-9]+]],
+// CHECK-SAME: ![[B_LAYOUT:[0-9]+]], ![[C_LAYOUT:[0-9]+]], ![[D_LAYOUT:[0-9]+]], ![[CBSTRUCTS_LAYOUT:[0-9]+]], ![[TEST_LAYOUT:[0-9]+]],
+// CHECK-SAME: ![[ANON_LAYOUT:[0-9]+]], ![[CBMIX_LAYOUT:[0-9]+]]}
+
+// CHECK: ![[CBSCALARS]] = !{ptr @CBScalars.cb, ptr addrspace(2) @a1, ptr addrspace(2) @a2, ptr addrspace(2) @a3, ptr addrspace(2) @a4,
+// CHECK-SAME: ptr addrspace(2) @a5, ptr addrspace(2) @a6, ptr addrspace(2) @a7, ptr addrspace(2) @a8}
+
+// CHECK: ![[CBVECTORS]] = !{ptr @CBVectors.cb, ptr addrspace(2) @b1, ptr addrspace(2) @b2, ptr addrspace(2) @b3, ptr addrspace(2) @b4,
+// CHECK-SAME: ptr addrspace(2) @b5, ptr addrspace(2) @b6, ptr addrspace(2) @b7}
+
+// CHECK: ![[CBARRAYS]] = !{ptr @CBArrays.cb, ptr addrspace(2) @c1, ptr addrspace(2) @c2, ptr addrspace(2) @c3, ptr addrspace(2) @c4, 
+// CHECK-SAME: ptr addrspace(2) @c5, ptr addrspace(2) @c6, ptr addrspace(2) @c7, ptr addrspace(2) @c8}
+
+// CHECK: ![[CBSTRUCTS]] = !{ptr @CBStructs.cb, ptr addrspace(2) @a, ptr addrspace(2) @b, ptr addrspace(2) @c, ptr addrspace(2) @array_of_A, 
+// CHECK-SAME: ptr addrspace(2) @d, ptr addrspace(2) @e, ptr addrspace(2) @f, ptr addrspace(2) @g}
+
+// CHECK: ![[CBMIX]] = !{ptr @CBMix.cb, ptr addrspace(2) @test, ptr addrspace(2) @f1, ptr addrspace(2) @f2, ptr addrspace(2) @f3,
+// CHECK-SAME: ptr addrspace(2) @s, ptr addrspace(2) @dd, ptr addrspace(2) @f4, ptr addrspace(2) @dv, ptr addrspace(2) @uv}
+
+// CHECK: ![[CBSCALARS_LAYOUT]] = !{!"struct.__cblayout_CBScalars", i32 56, i32 0, i32 8, i32 16, i32 24, i32 32, i32 36, i32 40, i32 48}
+// CHECK: ![[CBVECTORS_LAYOUT]] = !{!"struct.__cblayout_CBVectors", i32 136, i32 0, i32 16, i32 40, i32 48, i32 80, i32 96, i32 112}
+                                  
+// CHECK: ![[CBARRAYS_LAYOUT]] = !{!"struct.__cblayout_CBArrays", i32 708, i32 0, i32 16, i32 48, i32 32, i32 112, i32 16, i32 176, i32 16,
+// CHECK-SAME: i32 224, i32 16, i32 608, i32 16, i32 624, i32 16, i32 656, i32 16}
+
+// CHECK: ![[A_LAYOUT]] = !{!"struct.A", i32 8, i32 0}
+// CHECK: ![[B_LAYOUT]] = !{!"struct.B", i32 14, i32 0, i32 8}
+// CHECK: ![[C_LAYOUT]] = !{!"struct.C", i32 24, i32 0, i32 16}
+// CHECK: ![[D_LAYOUT]] = !{!"struct.__cblayout_D", i32 94, i32 0, i32 16}
+// CHECK: ![[CBSTRUCTS_LAYOUT]] = !{!"struct.__cblayout_CBStructs", i32 262, i32 0, i32 16, i32 32, i32 64, i32 16, i32 144, i32 238, i32 240, i32 256}
+
+// CHECK: ![[TEST_LAYOUT]] = !{!"struct.Test", i32 8, i32 0, i32 4}
+// CHECK: ![[ANON_LAYOUT]] = !{!"struct.anon", i32 4, i32 0}
+// CHECK: ![[CBMIX_LAYOUT]] = !{!"struct.__cblayout_CBMix", i32 162, i32 0, i32 16, i32 24, i32 32, i32 16, i32 120, i32 128, i32 136, i32 144, i32 152, i32 160}
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
new file mode 100644
index 0000000000000..aa5659af414ef
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
@@ -0,0 +1,63 @@
+// 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: %"struct.n0::n1::__cblayout_A" = type { float }
+// CHECK: %"struct.n0::__cblayout_B" = type { float }
+// CHECK: %"struct.n0::n2::__cblayout_C" = type { float, %"struct.n0::Foo" }
+// CHECK: %"struct.n0::Foo" = type { float }
+
+// CHECK: @A.cb = external constant target("dx.CBuffer", %"struct.n0::n1::__cblayout_A")
+// CHECK: @_ZN2n02n11aE = external addrspace(2) global float, align 4
+
+// CHECK: @B.cb = external constant target("dx.CBuffer", %"struct.n0::__cblayout_B")
+// CHECK: @_ZN2n01aE = external addrspace(2) global float, align 4
+
+// CHECK: @C.cb = external constant target("dx.CBuffer", %"struct.n0::n2::__cblayout_C")
+// CHECK: @_ZN2n02n21aE = external addrspace(2) global float, align 4
+// CHECK: @_ZN2n02n21bE = external addrspace(2) global %"struct.n0::Foo", align 4
+
+namespace n0 {
+  struct Foo {
+    float f;
+  };
+
+  namespace n1 {
+    cbuffer A {
+      float a;
+    }
+  }
+  cbuffer B {
+    float a;
+  }
+  namespace n2 {
+    cbuffer C {
+      float a;
+      Foo b;
+    }
+  }
+}
+
+float foo() {
+  // CHECK: load float, ptr addrspace(2) @_ZN2n02n11aE, align 4
+  // CHECK: load float, ptr addrspace(2) @_ZN2n01aE, align 4
+  // CHECK: load float, ptr addrspace(2) @_ZN2n02n21aE, align 4
+  return n0::n1::a + n0::a + n0::n2::a;
+}
+
+[numthreads(4,1,1)]
+void main() {}
+
+// CHECK: !hlsl.cbs = !{![[A:[0-9]+]], ![[B:[0-9]+]], ![[C:[0-9]+]]}
+// CHECK: !hlsl.cblayouts = !{![[A_LAYOUT:[0-9]+]], ![[B_LAYOUT:[0-9]+]], ![[FOO_LAYOUT:[0-9]+]], ![[C_LAYOUT:[0-9]+]]}
+
+// CHECK: [[A]] = !{ptr @A.cb, ptr addrspace(2) @_ZN2n02n11aE}
+// CHECK: [[B]] = !{ptr @B.cb, ptr addrspace(2) @_ZN2n01aE}
+// CHECK: [[C]] = !{ptr @C.cb, ptr addrspace(2) @_ZN2n02n21aE, ptr addrspace(2) @_ZN2n02n21bE}
+
+// CHECK: ![[A_LAYOUT]] = !{!"struct.n0::n1::__cblayout_A", i32 4, i32 0}
+// CHECK: ![[B_LAYOUT]] = !{!"struct.n0::__cblayout_B", i32 4, i32 0}
+// CHECK: ![[FOO_LAYOUT]] = !{!"struct.n0::Foo", i32 4, i32 0}
+// CHECK: ![[C_LAYOUT]] = !{!"struct.n0::n2::__cblayout_C", i32 20, i32 0, i32 16}
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
new file mode 100644
index 0000000000000..f5b5cba6197b3
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
@@ -0,0 +1,40 @@
+// 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: %struct.__cblayout_CB = type <{ float, double, <2 x i32> }>
+
+// CHECK: @CB.cb = external constant target("dx.CBuffer", %struct.__cblayout_CB)
+// CHECK: @a = external addrspace(2) global float, align 4
+// CHECK: @b = external addrspace(2) global double, align 8
+// CHECK: @c = external addrspace(2) global <2 x i32>, align 8
+
+cbuffer CB : register(b1, space3) {
+  float a : packoffset(c1.x);
+  double b : packoffset(c10.z);
+  int2 c : packoffset(c5.z);
+}
+
+// CHECK: define internal void @_init_resource_CB.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CB.cb_h = call target("dx.CBuffer", %struct.__cblayout_CB) @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBst(i32 3, i32 1, i32 1, i32 0, i1 false)
+
+float foo() {
+  // CHECK: load float, ptr addrspace(2) @a, align 4
+  // CHECK: load double, ptr addrspace(2) @b, align 8
+  return a + b;
+}
+// CHECK: define internal void @_GLOBAL__sub_I_cbuffer_with_packoffset.hlsl()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_init_resource_CB.cb()
+
+[numthreads(4,1,1)]
+void main() {
+  foo();
+}
+
+// CHECK: !hlsl.cbs = !{![[CB:[0-9]+]]}
+// CHECK: !hlsl.cblayouts = !{![[CB_LAYOUT:[0-9]+]]}
+
+// CHECK: ![[CB]] = !{ptr @CB.cb, ptr addrspace(2) @a, ptr addrspace(2) @b, ptr addrspace(2) @c}
+// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_CB", i32 176, i32 16, i32 168, i32 88}
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 0000000000000..8994640d5b311
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK: %struct.__cblayout_A = type { float }
+
+// CHECK: @A.cb = external constant target("dx.CBuffer", %struct.__cblayout_A)
+// CHECK: @a = external addrspace(2) global float, align 4
+// CHECK-DAG: @_ZL1b = internal global float 3.000000e+00, align 4
+// CHECK-NOT: @B.cb
+
+cbuffer A {
+  float a;
+  static float b = 3;
+  float foo() { return a + b; }
+}
+
+cbuffer B {
+  // intentionally empty
+}
+
+// CHECK: define {{.*}} float @_Z3foov() #0 {
+// CHECK: load float, ptr addrspace(2) @a, align 4
+
+extern float bar() {
+  return foo();
+}
+
+// CHECK: !hlsl.cbs = !{![[CB:[0-9]+]]}
+// CHECK: !hlsl.cblayouts = !{![[CB_LAYOUT:[0-9]+]]}
+
+// CHECK: ![[CB]] = !{ptr @A.cb, ptr addrspace(2) @a}
+// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_A", i32 4, i32 0}
diff --git a/clang/test/CodeGenHLSL/resource-bindings.hlsl b/clang/test/CodeGenHLSL/resource-bindings.hlsl
index bfa7896bd9811..57e8cc29572b1 100644
--- a/clang/test/CodeGenHLSL/resource-bindings.hlsl
+++ b/clang/test/CodeGenHLSL/resource-bindings.hlsl
@@ -2,14 +2,17 @@
 
 // CHECK: define internal void @_init_resource_U0S0()
 // CHECK: %U0S0_h = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false)
+// CHECK: store target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %U0S0_h, ptr @U0S0, align 4
 RWBuffer<float4> U0S0 : register(u0);
 
 // CHECK: define internal void @_init_resource_U5S3()
 // CHECK: %U5S3_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
+// CHECK: store target("dx.TypedBuffer", float, 1, 0, 0) %U5S3_h, ptr @U5S3, align 4
 RWBuffer<float> U5S3 : register(u5, space3);
 
 // CHECK: define internal void @_init_resource_T2S2()
 // CHECK: %T2S2_h = call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_0_0t(i32 2, i32 2, i32 1, i32 0, i1 false)
+// CHECK: store target("dx.RawBuffer", i32, 0, 0) %T2S2_h, ptr @T2S2, align 4
 StructuredBuffer<int> T2S2 : register(t2, space2);
 struct S {
   float4 f;
@@ -18,6 +21,7 @@ struct S {
 
 // CHECK: define internal void @_init_resource_T3S0()
 // CHECK: %T3S0_h = call target("dx.RawBuffer", %struct.S, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_s_struct.Ss_0_0t(i32 0, i32 3, i32 1, i32 0, i1 false)
+// CHECK: store target("dx.RawBuffer", %struct.S, 0, 0) %T3S0_h, ptr @T3S0, align 4
 StructuredBuffer<S> T3S0 : register(t3);
 
 // CHECK: define void @main()
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 25f51cce2017d..0000000000000
--- a/clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan-library %s \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-cbuffer A {
-  // CHECK: @a = external addrspace(2) externally_initialized global float, align 4
-  float a;
-  // CHECK: @_ZL1b = internal global float 3.000000e+00, align 4
-  static float b = 3;
-  float foo() { return a + b; }
-}
-// CHECK: @[[CB:.+]] = external constant { float }
-
-// CHECK:define {{.*}} float @_Z3foov()
-// CHECK:load float, ptr addrspace(2) @a, align 4
-// CHECK:load float, ptr @_ZL1b, align 4
-
-float bar() {
-  return foo();
-}

>From 56beb45a133be18b7e6649cc0a4af852bbed3db7 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 28 Jan 2025 16:06:03 -0800
Subject: [PATCH 04/19] remove stride

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 32 +++++++++++++++--------------
 clang/lib/CodeGen/CGHLSLRuntime.h   |  7 ++++---
 clang/test/CodeGenHLSL/cbuffer.hlsl |  9 ++++----
 3 files changed, 25 insertions(+), 23 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index d3d9d42664359..128ca86f66b5a 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -130,8 +130,11 @@ CGHLSLRuntime::getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy) {
   size_t StructSize = 0;
   LayoutItems.push_back(nullptr); // reserve one slot for the buffer size
 
-  for (llvm::Type *ElTy : StructTy->elements())
-    addLayoutInfoForBufferElement(StructSize, LayoutItems, ElTy);
+  for (llvm::Type *ElTy : StructTy->elements()) {
+    size_t Offset = calculateBufferElementOffset(ElTy, &StructSize);
+    // create metadata constant with the element start offset
+    LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), Offset));
+  }
 
   // set the size of the buffer
   LayoutItems[1] = getConstIntMetadata(Ctx, StructSize);
@@ -147,16 +150,16 @@ CGHLSLRuntime::getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy) {
   return StructSize;
 }
 
-void CGHLSLRuntime::addLayoutInfoForBufferElement(
-    size_t &EndOffset, SmallVector<llvm::Metadata *> &LayoutItems,
-    llvm::Type *LayoutTy, HLSLPackOffsetAttr *PackoffsetAttr) {
+size_t CGHLSLRuntime::calculateBufferElementOffset(
+    llvm::Type *LayoutTy, size_t *LayoutEndOffset,
+    HLSLPackOffsetAttr *PackoffsetAttr) {
 
-  // calculate element offset and size; for arrays also calculate array
-  // element count and stride
+  // calculate element offset and size
   size_t ElemOffset = 0;
   size_t ElemSize = 0;
   size_t ArrayCount = 1;
   size_t ArrayStride = 0;
+  size_t EndOffset = *LayoutEndOffset;
   size_t NextRowOffset = llvm::alignTo(EndOffset, 16U);
 
   if (LayoutTy->isArrayTy()) {
@@ -205,13 +208,9 @@ void CGHLSLRuntime::addLayoutInfoForBufferElement(
   // with packoffset annotations)
   unsigned NewEndOffset =
       ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
-  EndOffset = std::max<size_t>(EndOffset, NewEndOffset);
+  *LayoutEndOffset = std::max<size_t>(EndOffset, NewEndOffset);
 
-  // create metadata constan with the offset and stride and add to list
-  LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), ElemOffset));
-  if (ArrayStride)
-    LayoutItems.push_back(
-        getConstIntMetadata(CGM.getLLVMContext(), ArrayStride));
+  return ElemOffset;
 }
 
 void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
@@ -284,9 +283,12 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
               !UsePackoffset) &&
              "expected packoffset attribute on every declaration");
 
-      addLayoutInfoForBufferElement(
-          BufferSize, LayoutItems, LayoutType,
+      size_t Offset = calculateBufferElementOffset(
+          LayoutType, &BufferSize,
           UsePackoffset ? VD->getAttr<HLSLPackOffsetAttr>() : nullptr);
+
+      // create metadata constant with the element start offset
+      LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), Offset));
     }
   }
   assert(ElemIt == LayoutStruct->element_end() &&
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index a6e3c78f52285..d1f678863d4fb 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -166,9 +166,10 @@ class CGHLSLRuntime {
                                    BufferResBinding &Binding);
   void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
                                     llvm::GlobalVariable *BufGV);
-  void addLayoutInfoForBufferElement(
-      size_t &EndOffset, SmallVector<llvm::Metadata *> &LayoutItems,
-      llvm::Type *LayoutTy, HLSLPackOffsetAttr *PackoffsetAttr = nullptr);
+
+  size_t
+  calculateBufferElementOffset(llvm::Type *LayoutTy, size_t *LayoutEndOffset,
+                               HLSLPackOffsetAttr *PackoffsetAttr = nullptr);
 
   size_t getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy);
 
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index 99f16ea62cdcb..e600d25c4e19c 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -186,15 +186,14 @@ void main() {
 // CHECK: ![[CBSCALARS_LAYOUT]] = !{!"struct.__cblayout_CBScalars", i32 56, i32 0, i32 8, i32 16, i32 24, i32 32, i32 36, i32 40, i32 48}
 // CHECK: ![[CBVECTORS_LAYOUT]] = !{!"struct.__cblayout_CBVectors", i32 136, i32 0, i32 16, i32 40, i32 48, i32 80, i32 96, i32 112}
                                   
-// CHECK: ![[CBARRAYS_LAYOUT]] = !{!"struct.__cblayout_CBArrays", i32 708, i32 0, i32 16, i32 48, i32 32, i32 112, i32 16, i32 176, i32 16,
-// CHECK-SAME: i32 224, i32 16, i32 608, i32 16, i32 624, i32 16, i32 656, i32 16}
+// CHECK: ![[CBARRAYS_LAYOUT]] = !{!"struct.__cblayout_CBArrays", i32 708, i32 0, i32 48, i32 112, i32 176, i32 224, i32 608, i32 624, i32 656}
 
 // CHECK: ![[A_LAYOUT]] = !{!"struct.A", i32 8, i32 0}
 // CHECK: ![[B_LAYOUT]] = !{!"struct.B", i32 14, i32 0, i32 8}
 // CHECK: ![[C_LAYOUT]] = !{!"struct.C", i32 24, i32 0, i32 16}
-// CHECK: ![[D_LAYOUT]] = !{!"struct.__cblayout_D", i32 94, i32 0, i32 16}
-// CHECK: ![[CBSTRUCTS_LAYOUT]] = !{!"struct.__cblayout_CBStructs", i32 262, i32 0, i32 16, i32 32, i32 64, i32 16, i32 144, i32 238, i32 240, i32 256}
+// CHECK: ![[D_LAYOUT]] = !{!"struct.__cblayout_D", i32 94, i32 0}
+// CHECK: ![[CBSTRUCTS_LAYOUT]] = !{!"struct.__cblayout_CBStructs", i32 262, i32 0, i32 16, i32 32, i32 64, i32 144, i32 238, i32 240, i32 256}
 
 // CHECK: ![[TEST_LAYOUT]] = !{!"struct.Test", i32 8, i32 0, i32 4}
 // CHECK: ![[ANON_LAYOUT]] = !{!"struct.anon", i32 4, i32 0}
-// CHECK: ![[CBMIX_LAYOUT]] = !{!"struct.__cblayout_CBMix", i32 162, i32 0, i32 16, i32 24, i32 32, i32 16, i32 120, i32 128, i32 136, i32 144, i32 152, i32 160}
+// CHECK: ![[CBMIX_LAYOUT]] = !{!"struct.__cblayout_CBMix", i32 162, i32 0, i32 24, i32 32, i32 120, i32 128, i32 136, i32 144, i32 152, i32 160}

>From 749e88e87f36b8b4f2a8b5a4ddf02230a4be9600 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 28 Jan 2025 22:02:24 -0800
Subject: [PATCH 05/19] cleanup, update comments

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp   | 188 +++++++++++++-------------
 clang/lib/CodeGen/CGHLSLRuntime.h     |   4 +-
 clang/lib/CodeGen/Targets/DirectX.cpp |   1 -
 clang/test/CodeGenHLSL/cbuffer.hlsl   |   2 +-
 4 files changed, 100 insertions(+), 95 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 128ca86f66b5a..52247173b6990 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -89,8 +89,7 @@ static bool isResourceRecordType(const clang::Type *Ty) {
   return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
 }
 
-// Returns true if the type is an HLSL resource class or an array of
-// HLSL resource classes
+// 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();
@@ -113,48 +112,56 @@ static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
   return Ty->getScalarSizeInBits() / 8;
 }
 
+// Returns size of a struct in constant buffer layout. The sizes are cached
+// in StructSizesForBuffer map. The map is also an indicator if a layout
+// metadata for this struct has been added to the module.
+// If the struct type is not in the map, this method will calculate the struct
+// layout, add a metadata node describing it to the module, and add the struct
+// size to the map.
 size_t
 CGHLSLRuntime::getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy) {
-  assert(StructTy->isStructTy());
-
   // check if we already have a side for this struct
   auto SizeIt = StructSizesForBuffer.find(StructTy);
   if (SizeIt != StructSizesForBuffer.end())
     return SizeIt->getSecond();
 
-  // if not, calculate the struct layout and add it to metadata
+  // if not, calculate the struct layout and create a metadata node
   LLVMContext &Ctx = CGM.getLLVMContext();
   SmallVector<llvm::Metadata *> LayoutItems;
+
+  // start metadata list with a struct name and reserve one slot for its size
   LayoutItems.push_back(MDString::get(Ctx, StructTy->getName()));
+  LayoutItems.push_back(nullptr);
 
+  // add element offsets
   size_t StructSize = 0;
-  LayoutItems.push_back(nullptr); // reserve one slot for the buffer size
-
   for (llvm::Type *ElTy : StructTy->elements()) {
     size_t Offset = calculateBufferElementOffset(ElTy, &StructSize);
-    // create metadata constant with the element start offset
     LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), Offset));
   }
-
-  // set the size of the buffer
+  // set the size of the buffer to the reserved slot
   LayoutItems[1] = getConstIntMetadata(Ctx, StructSize);
 
-  // add the struct layout info to metadata
-  MDNode *LayoutMDNode = MDNode::get(CGM.getLLVMContext(), LayoutItems);
+  // add the struct layout to metadata
   CGM.getModule()
       .getOrInsertNamedMetadata("hlsl.cblayouts")
-      ->addOperand(LayoutMDNode);
+      ->addOperand(MDNode::get(CGM.getLLVMContext(), LayoutItems));
 
   // add struct size to list and return it
   StructSizesForBuffer[StructTy] = StructSize;
   return StructSize;
 }
 
+// Calculates offset of a single element in constant buffer layout.
+// The provided LayoutEndOffset marks the end of the layout so far (end offset
+// of the buffer or struct). After the element offset calculations are done it
+// will be updated the new end of layout value.
+// If the PackoffsetAttrs is not nullptr the offset will be based on the
+// packoffset annotation.
 size_t CGHLSLRuntime::calculateBufferElementOffset(
     llvm::Type *LayoutTy, size_t *LayoutEndOffset,
     HLSLPackOffsetAttr *PackoffsetAttr) {
 
-  // calculate element offset and size
   size_t ElemOffset = 0;
   size_t ElemSize = 0;
   size_t ArrayCount = 1;
@@ -198,14 +205,15 @@ size_t CGHLSLRuntime::calculateBufferElementOffset(
       ElemOffset = PackoffsetAttr->getOffsetInBytes();
     } else {
       ElemOffset = llvm::alignTo(EndOffset, Align);
+      // if the element does not fit, move it to the next row
       if (ElemOffset + ElemSize > NextRowOffset)
         ElemOffset = NextRowOffset;
     }
   }
 
   // Update end offset of the buffer/struct layout; do not update it if
-  // the provided EndOffset is already bigger than the new one (which may happen
-  // with packoffset annotations)
+  // the provided EndOffset is already bigger than the new one value
+  // (which may happen with packoffset annotations)
   unsigned NewEndOffset =
       ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
   *LayoutEndOffset = std::max<size_t>(EndOffset, NewEndOffset);
@@ -213,102 +221,106 @@ size_t CGHLSLRuntime::calculateBufferElementOffset(
   return ElemOffset;
 }
 
+// Emits constant global variables for buffer declarations, creates metadata
+// linking the constant globals with the buffer. Also calculates the buffer
+// layout and creates metadata node describing it.
 void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
                                                  llvm::GlobalVariable *BufGV) {
+  LLVMContext &Ctx = CGM.getLLVMContext();
   llvm::StructType *LayoutStruct = cast<llvm::StructType>(
       cast<llvm::TargetExtType>(BufGV->getValueType())->getTypeParameter(0));
 
-  LLVMContext &Ctx = CGM.getLLVMContext();
-
+  // Start metadata list associating the buffer global variable with its
+  // constatns
   SmallVector<llvm::Metadata *> BufGlobals;
   BufGlobals.push_back(ValueAsMetadata::get(BufGV));
 
+  // Start layout metadata list with a struct name and reserve one slot for
+  // the buffer size
   SmallVector<llvm::Metadata *> LayoutItems;
   LayoutItems.push_back(MDString::get(Ctx, LayoutStruct->getName()));
+  LayoutItems.push_back(nullptr);
 
   size_t BufferSize = 0;
-  size_t BufferSizeIndex = LayoutItems.size();
-  LayoutItems.push_back(nullptr); // reserve one slot for the buffer size
-
   bool UsePackoffset = BufDecl->hasPackoffset();
-
   const auto *ElemIt = LayoutStruct->element_begin();
   for (Decl *D : BufDecl->decls()) {
     if (isa<CXXRecordDecl, EmptyDecl>(D))
       // Nothing to do for this declaration.
       continue;
     if (isa<FunctionDecl>(D)) {
-      // A function within an cbuffer is effectively a top-level function,
-      // as it only refers to globally scoped declarations.
+      // A function within an cbuffer is effectively a top-level function.
       CGM.EmitTopLevelDecl(D);
       continue;
     }
-    if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
-      QualType VDTy = VD->getType();
-      if (VDTy.getAddressSpace() != LangAS::hlsl_constant) {
-        if (VD->getStorageClass() == SC_Static ||
-            isResourceRecordTypeOrArrayOf(VDTy.getTypePtr())) {
-          // Emit static 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;
-      }
+    VarDecl *VD = dyn_cast<VarDecl>(D);
+    if (!VD)
+      continue;
 
-      assert(ElemIt != LayoutStruct->element_end() &&
-             "number of elements in layout struct does not match");
-      llvm::Type *LayoutType = *ElemIt++;
-
-      assert((CGM.getTypes().ConvertTypeForMem(VDTy) == LayoutType ||
-              (LayoutType->isStructTy() &&
-               cast<llvm::StructType>(LayoutType)
-                   ->getName()
-                   .starts_with(("struct.__cblayout_" +
-                                 VDTy->getAsCXXRecordDecl()->getName())
-                                    .str()))) &&
-             "layout type does not match the converted element type");
-
-      // handle any resources declarations inside the struct
-      if (VDTy->isStructureType() && VDTy->isHLSLIntangibleType())
-        // FIXME: handle resources in cbuffer structs
-        llvm_unreachable("resources in cbuffer are not supported yet");
-
-      GlobalVariable *ElemGV =
-          cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
-      BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
-
-      assert(((UsePackoffset && VD->hasAttr<HLSLPackOffsetAttr>()) ||
-              !UsePackoffset) &&
-             "expected packoffset attribute on every declaration");
-
-      size_t Offset = calculateBufferElementOffset(
-          LayoutType, &BufferSize,
-          UsePackoffset ? VD->getAttr<HLSLPackOffsetAttr>() : nullptr);
-
-      // create metadata constant with the element start offset
-      LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), Offset));
+    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++;
+
+    // Make sure the type of the VarDecl type matches the type of the layout
+    // struct element, or that it is a layout struct with the same name
+    assert((CGM.getTypes().ConvertTypeForMem(VDTy) == LayoutType ||
+            (LayoutType->isStructTy() &&
+             cast<llvm::StructType>(LayoutType)
+                 ->getName()
+                 .starts_with(("struct.__cblayout_" +
+                               VDTy->getAsCXXRecordDecl()->getName())
+                                  .str()))) &&
+           "layout type does not match the converted element type");
+
+    // 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");
+
+    // create global variable for the constant and to metadata list
+    GlobalVariable *ElemGV =
+        cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
+    BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
+
+    // get offset of the global and and to metadata list
+    assert(((UsePackoffset && VD->hasAttr<HLSLPackOffsetAttr>()) ||
+            !UsePackoffset) &&
+           "expected packoffset attribute on every declaration");
+    size_t Offset = calculateBufferElementOffset(
+        LayoutType, &BufferSize,
+        UsePackoffset ? VD->getAttr<HLSLPackOffsetAttr>() : nullptr);
+    LayoutItems.push_back(getConstIntMetadata(Ctx, Offset));
   }
   assert(ElemIt == LayoutStruct->element_end() &&
          "number of elements in layout struct does not match");
-
-  // add buffer global and a list of its constants to metadata
-  MDNode *BufMDNode = MDNode::get(CGM.getLLVMContext(), BufGlobals);
-  CGM.getModule().getOrInsertNamedMetadata("hlsl.cbs")->addOperand(BufMDNode);
-
   // set the size of the buffer
-  LayoutItems[BufferSizeIndex] = getConstIntMetadata(Ctx, BufferSize);
+  LayoutItems[1] = getConstIntMetadata(Ctx, BufferSize);
+
+  // add buffer metadata to the module
+  CGM.getModule()
+      .getOrInsertNamedMetadata("hlsl.cbs")
+      ->addOperand(MDNode::get(Ctx, BufGlobals));
 
-  // add buffer layout to metadata
-  MDNode *LayoutMDNode = MDNode::get(CGM.getLLVMContext(), LayoutItems);
   CGM.getModule()
       .getOrInsertNamedMetadata("hlsl.cblayouts")
-      ->addOperand(LayoutMDNode);
+      ->addOperand(MDNode::get(Ctx, LayoutItems));
 }
 
-// Creates resource handle type for the HLSL buffer
+// Creates resource handle type for the HLSL buffer declaration
 static const clang::HLSLAttributedResourceType *
 createBufferHandleType(const HLSLBufferDecl *BufDecl) {
   ASTContext &AST = BufDecl->getASTContext();
@@ -319,26 +331,20 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
   return cast<HLSLAttributedResourceType>(QT.getTypePtr());
 }
 
-// Creates temporary global variables for all declarations within the constant
-// 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.
+// Codegen for HLSLBufferDecl
 void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
 
   assert(BufDecl->isCBuffer() && "tbuffer codegen is not supported yet");
 
-  // Create resource handle type for the buffer
+  // create resource handle type for the buffer
   const clang::HLSLAttributedResourceType *ResHandleTy =
       createBufferHandleType(BufDecl);
 
-  // ignore empty constant buffer
+  // empty constant buffer is ignored
   if (ResHandleTy->getContainedType()->getAsCXXRecordDecl()->isEmpty())
     return;
 
-  // Create global variable for the buffer
+  // create global variable for the constant buffer
   llvm::Module &M = CGM.getModule();
   llvm::TargetExtType *TargetTy =
       cast<llvm::TargetExtType>(convertHLSLSpecificType(ResHandleTy));
@@ -350,10 +356,10 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
                          GlobalValue::NotThreadLocal);
   M.insertGlobalVariable(BufGV);
 
-  // Add globals for buffer elements and create metadata node for the buffer
+  // Add globals for constant buffer elements and create metadata nodes
   emitBufferGlobalsAndMetadata(BufDecl, BufGV);
 
-  // Add cbuffer resource initialization
+  // Resource initialization
   const HLSLResourceBindingAttr *RBA =
       BufDecl->getAttr<HLSLResourceBindingAttr>();
   // FIXME: handle implicit binding if no binding attribute is found
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index d1f678863d4fb..8658cb8653fb4 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -71,7 +71,6 @@ class FunctionDecl;
 namespace CodeGen {
 
 class CodeGenModule;
-class CGBuilderTy;
 
 class CGHLSLRuntime {
 public:
@@ -175,7 +174,8 @@ class CGHLSLRuntime {
 
   llvm::Triple::ArchType getArch();
 
-  // sizes of structs that in constant buffer layout
+  // Sizes of structs in constant buffer layout. Structs in the map
+  // had their layout calculated and added to the module as metadata.
   llvm::DenseMap<llvm::StructType *, size_t> StructSizesForBuffer;
 };
 
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 33bddc56d83f2..ec7fa342d5846 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -44,7 +44,6 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
       return nullptr;
 
     // convert element type
-    // llvm::Type *ElemType = CGM.getTypes().ConvertTypeForMem(ContainedTy);
     llvm::Type *ElemType = CGM.getTypes().ConvertType(ContainedTy);
 
     llvm::StringRef TypeName =
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index e600d25c4e19c..9a3f632e859c7 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -164,6 +164,7 @@ void main() {
 // CHECK-NEXT: call void @_init_resource_CBArrays.cb()
 
 // CHECK: !hlsl.cbs = !{![[CBSCALARS:[0-9]+]], ![[CBVECTORS:[0-9]+]], ![[CBARRAYS:[0-9]+]], ![[CBSTRUCTS:[0-9]+]], ![[CBMIX:[0-9]+]]}
+
 // CHECK: !hlsl.cblayouts = !{![[CBSCALARS_LAYOUT:[0-9]+]], ![[CBVECTORS_LAYOUT:[0-9]+]], ![[CBARRAYS_LAYOUT:[0-9]+]], ![[A_LAYOUT:[0-9]+]],
 // CHECK-SAME: ![[B_LAYOUT:[0-9]+]], ![[C_LAYOUT:[0-9]+]], ![[D_LAYOUT:[0-9]+]], ![[CBSTRUCTS_LAYOUT:[0-9]+]], ![[TEST_LAYOUT:[0-9]+]],
 // CHECK-SAME: ![[ANON_LAYOUT:[0-9]+]], ![[CBMIX_LAYOUT:[0-9]+]]}
@@ -193,7 +194,6 @@ void main() {
 // CHECK: ![[C_LAYOUT]] = !{!"struct.C", i32 24, i32 0, i32 16}
 // CHECK: ![[D_LAYOUT]] = !{!"struct.__cblayout_D", i32 94, i32 0}
 // CHECK: ![[CBSTRUCTS_LAYOUT]] = !{!"struct.__cblayout_CBStructs", i32 262, i32 0, i32 16, i32 32, i32 64, i32 144, i32 238, i32 240, i32 256}
-
 // CHECK: ![[TEST_LAYOUT]] = !{!"struct.Test", i32 8, i32 0, i32 4}
 // CHECK: ![[ANON_LAYOUT]] = !{!"struct.anon", i32 4, i32 0}
 // CHECK: ![[CBMIX_LAYOUT]] = !{!"struct.__cblayout_CBMix", i32 162, i32 0, i32 24, i32 32, i32 120, i32 128, i32 136, i32 144, i32 152, i32 160}

>From a12bcbc287d706c2c7fa56005badb40d4a0fa6fc Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 4 Feb 2025 12:59:13 -0800
Subject: [PATCH 06/19] Move skipping of implicit initializer of hlsl_constant
 decls to a different PR.

---
 clang/lib/Sema/SemaDecl.cpp | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index ba424567b23e0..7c70150871da9 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14184,12 +14184,6 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
         Var->getType().getAddressSpace() == LangAS::opencl_local)
       return;
 
-    // In HLSL, objects in the hlsl_constat address space are initialized
-    // externaly, so don't synthesize an implicit initializer.
-    if (getLangOpts().HLSL &&
-        Var->getType().getAddressSpace() == LangAS::hlsl_constant)
-      return;
-
     // C++03 [dcl.init]p9:
     //   If no initializer is specified for an object, and the
     //   object is of (possibly cv-qualified) non-POD class type (or

>From 66ae78472080bb2b9de4b99ff63b5219f14c75c8 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 4 Feb 2025 17:58:43 -0800
Subject: [PATCH 07/19] Add LayoutStruct to HLSLBufferDecl; add skipping of
 implicit initializers

---
 clang/include/clang/AST/Decl.h |  5 ++++-
 clang/lib/AST/Decl.cpp         | 15 +++++----------
 clang/lib/Sema/SemaDecl.cpp    |  6 ++++++
 clang/lib/Sema/SemaHLSL.cpp    |  2 +-
 4 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index e1c7e3817699c..05e56978977f2 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -5035,6 +5035,8 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
   /// HasValidPackoffset - Whether the buffer has valid packoffset annotations
   //                       on all declarations
   bool HasPackoffset;
+  // LayoutStruct - Layout struct for the buffer
+  CXXRecordDecl *LayoutStruct;
 
   HLSLBufferDecl(DeclContext *DC, bool CBuffer, SourceLocation KwLoc,
                  IdentifierInfo *ID, SourceLocation IDLoc,
@@ -5057,7 +5059,8 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
   bool isCBuffer() const { return IsCBuffer; }
   void setHasPackoffset(bool PO) { HasPackoffset = PO; }
   bool hasPackoffset() const { return HasPackoffset; }
-  const CXXRecordDecl *getLayoutStruct() const;
+  const CXXRecordDecl *getLayoutStruct() const { return LayoutStruct; }
+  void addLayoutStruct(CXXRecordDecl *LS);
 
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index fa7d03354a993..4c5201d0ba2ee 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5717,7 +5717,7 @@ HLSLBufferDecl::HLSLBufferDecl(DeclContext *DC, bool CBuffer,
                                SourceLocation IDLoc, SourceLocation LBrace)
     : NamedDecl(Decl::Kind::HLSLBuffer, DC, IDLoc, DeclarationName(ID)),
       DeclContext(Decl::Kind::HLSLBuffer), LBraceLoc(LBrace), KwLoc(KwLoc),
-      IsCBuffer(CBuffer), HasPackoffset(false) {}
+      IsCBuffer(CBuffer), HasPackoffset(false), LayoutStruct(nullptr) {}
 
 HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
                                        DeclContext *LexicalParent, bool CBuffer,
@@ -5747,15 +5747,10 @@ HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C,
                                     SourceLocation(), SourceLocation());
 }
 
-const CXXRecordDecl *HLSLBufferDecl::getLayoutStruct() const {
-  // Layout struct is the last decl in the HLSLBufferDecl.
-  if (CXXRecordDecl *RD = llvm::dyn_cast_or_null<CXXRecordDecl>(LastDecl)) {
-    assert(RD->getName().starts_with(
-               ("__cblayout_" + getIdentifier()->getName()).str()) &&
-           "expected buffer layout struct");
-    return RD;
-  }
-  llvm_unreachable("HLSL buffer is missing a layout struct");
+void HLSLBufferDecl::addLayoutStruct(CXXRecordDecl *LS) {
+  assert(LayoutStruct == nullptr && "layout struct has already been set");
+  LayoutStruct = LS;
+  addDecl(LS);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7c70150871da9..5497c30ed09ff 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14184,6 +14184,12 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
         Var->getType().getAddressSpace() == LangAS::opencl_local)
       return;
 
+    // In HLSL, objects in the hlsl_constant address space are initialized
+    // externally, so don't synthesize an implicit initializer.
+    if (getLangOpts().HLSL &&
+        Var->getType().getAddressSpace() == LangAS::hlsl_constant)
+      return;
+
     // C++03 [dcl.init]p9:
     //   If no initializer is specified for an object, and the
     //   object is of (possibly cv-qualified) non-POD class type (or
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 2807cc773320b..d80e605055ad7 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -502,7 +502,7 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
     }
   }
   LS->completeDefinition();
-  BufDecl->addDecl(LS);
+  BufDecl->addLayoutStruct(LS);
 }
 
 // Handle end of cbuffer/tbuffer declaration

>From e042f72eee72ffb58d27dfd5e6011bd2e510ab84 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 4 Feb 2025 20:52:25 -0800
Subject: [PATCH 08/19] desugar types and check for resource builtin type

---
 clang/lib/Sema/SemaHLSL.cpp      | 3 ++-
 clang/test/AST/HLSL/cbuffer.hlsl | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index b71dd2b273a1c..a4d5b89794af4 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -282,6 +282,7 @@ static bool isResourceRecordTypeOrArrayOf(const Type *Ty) {
 // array, or a builtin intangible type. Returns false it is a valid leaf element
 // type or if it is a record type that needs to be inspected further.
 static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
+  Ty = Ty->getUnqualifiedDesugaredType();
   if (isResourceRecordTypeOrArrayOf(Ty))
     return true;
   if (Ty->isRecordType())
@@ -289,7 +290,7 @@ static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
   if (Ty->isConstantArrayType() &&
       isZeroSizedArray(cast<ConstantArrayType>(Ty)))
     return true;
-  if (Ty->isHLSLBuiltinIntangibleType())
+  if (Ty->isHLSLBuiltinIntangibleType() || Ty->isHLSLAttributedResourceType())
     return true;
   return false;
 }
diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl
index 865db1201baa5..87202d7998bdb 100644
--- a/clang/test/AST/HLSL/cbuffer.hlsl
+++ b/clang/test/AST/HLSL/cbuffer.hlsl
@@ -75,6 +75,8 @@ cbuffer CB {
   groupshared float g2;
   // CHECK: VarDecl {{.*}} e2 'hlsl_constant float'
   float e2;
+  // CHECK: VarDecl {{.*}} h2 '__hlsl_resource_t'
+  __hlsl_resource_t h2;
   // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_1 definition
   // CHECK: PackedAttr
   // CHECK-NEXT: FieldDecl {{.*}} a2 'float'

>From 42bb34f66f0030f55e1055c4ee0b362511b7f45b Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 4 Feb 2025 22:01:49 -0800
Subject: [PATCH 09/19] [HLSL] Implement default constant buffer `$Globals`

All variable declarations in the global scope that are not resources, static or empty are implicitly added to implicit constant buffer `$Globals`.

Fixes #123801
---
 clang/include/clang/AST/Decl.h              | 22 +++++++
 clang/include/clang/Sema/SemaHLSL.h         |  7 ++-
 clang/lib/AST/Decl.cpp                      | 41 ++++++++++++-
 clang/lib/CodeGen/CGHLSLRuntime.cpp         |  7 +--
 clang/lib/CodeGen/CodeGenModule.cpp         |  5 ++
 clang/lib/Sema/Sema.cpp                     |  3 +-
 clang/lib/Sema/SemaHLSL.cpp                 | 47 +++++++++++++--
 clang/test/AST/HLSL/default_cbuffer.hlsl    | 50 ++++++++++++++++
 clang/test/CodeGenHLSL/basic_types.hlsl     | 64 ++++++++++-----------
 clang/test/CodeGenHLSL/default_cbuffer.hlsl | 43 ++++++++++++++
 10 files changed, 242 insertions(+), 47 deletions(-)
 create mode 100644 clang/test/AST/HLSL/default_cbuffer.hlsl
 create mode 100644 clang/test/CodeGenHLSL/default_cbuffer.hlsl

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 05e56978977f2..f86ddaf89bd9c 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -5038,6 +5038,11 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
   // LayoutStruct - Layout struct for the buffer
   CXXRecordDecl *LayoutStruct;
 
+  // For default (implicit) constant buffer, a lisf of references of global
+  // decls that belong to the buffer. The decls are already parented by the
+  // translation unit context.
+  SmallVector<Decl *> DefaultBufferDecls;
+
   HLSLBufferDecl(DeclContext *DC, bool CBuffer, SourceLocation KwLoc,
                  IdentifierInfo *ID, SourceLocation IDLoc,
                  SourceLocation LBrace);
@@ -5047,6 +5052,8 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
                                 bool CBuffer, SourceLocation KwLoc,
                                 IdentifierInfo *ID, SourceLocation IDLoc,
                                 SourceLocation LBrace);
+  static HLSLBufferDecl *CreateDefaultCBuffer(ASTContext &C,
+                                              DeclContext *LexicalParent);
   static HLSLBufferDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
 
   SourceRange getSourceRange() const override LLVM_READONLY {
@@ -5061,6 +5068,7 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
   bool hasPackoffset() const { return HasPackoffset; }
   const CXXRecordDecl *getLayoutStruct() const { return LayoutStruct; }
   void addLayoutStruct(CXXRecordDecl *LS);
+  void addDefaultBufferDecl(Decl *D);
 
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -5072,6 +5080,20 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
     return static_cast<HLSLBufferDecl *>(const_cast<DeclContext *>(DC));
   }
 
+  // Iterator for the buffer decls. Concatenates the list of decls parented
+  // by this HLSLBufferDecl with the list of default buffer decls.
+  using buffer_decl_iterator =
+      llvm::concat_iterator<Decl *const, SmallVector<Decl *>::const_iterator,
+                            decl_iterator>;
+  using buffer_decl_range = llvm::iterator_range<buffer_decl_iterator>;
+
+  buffer_decl_range buffer_decls() const {
+    return buffer_decl_range(buffer_decls_begin(), buffer_decls_end());
+  }
+  buffer_decl_iterator buffer_decls_begin() const;
+  buffer_decl_iterator buffer_decls_end() const;
+  bool buffer_decls_empty();
+
   friend class ASTDeclReader;
   friend class ASTDeclWriter;
 };
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index f4cd11f423a84..b1cc856975532 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -103,13 +103,13 @@ class SemaHLSL : public SemaBase {
                          HLSLParamModifierAttr::Spelling Spelling);
   void ActOnTopLevelFunction(FunctionDecl *FD);
   void ActOnVariableDeclarator(VarDecl *VD);
+  void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU);
   void CheckEntryPoint(FunctionDecl *FD);
   void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
                                const HLSLAnnotationAttr *AnnotationAttr);
   void DiagnoseAttrStageMismatch(
       const Attr *A, llvm::Triple::EnvironmentType Stage,
       std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages);
-  void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU);
 
   QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS,
                                        QualType LHSType, QualType RHSType,
@@ -159,11 +159,16 @@ class SemaHLSL : public SemaBase {
   // List of all resource bindings
   ResourceBindings Bindings;
 
+  // default constant buffer $Globals
+  HLSLBufferDecl *DefaultCBuffer;
+
 private:
   void collectResourcesOnVarDecl(VarDecl *D);
   void collectResourcesOnUserRecordDecl(const VarDecl *VD,
                                         const RecordType *RT);
   void processExplicitBindingsOnDecl(VarDecl *D);
+
+  void diagnoseAvailabilityViolations(TranslationUnitDecl *TU);
 };
 
 } // namespace clang
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 4c5201d0ba2ee..eede936577f09 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -57,6 +57,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
@@ -5741,10 +5742,22 @@ HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
   return Result;
 }
 
+HLSLBufferDecl *
+HLSLBufferDecl::CreateDefaultCBuffer(ASTContext &C,
+                                     DeclContext *LexicalParent) {
+  DeclContext *DC = LexicalParent;
+  IdentifierInfo *II = &C.Idents.get("$Globals", tok::TokenKind::identifier);
+  HLSLBufferDecl *Result = new (C, DC) HLSLBufferDecl(
+      DC, true, SourceLocation(), II, SourceLocation(), SourceLocation());
+  Result->setImplicit(true);
+  return Result;
+}
+
 HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C,
                                                    GlobalDeclID ID) {
-  return new (C, ID) HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr,
-                                    SourceLocation(), SourceLocation());
+  return new (C, ID)
+      HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr,
+                     SourceLocation(), SourceLocation());
 }
 
 void HLSLBufferDecl::addLayoutStruct(CXXRecordDecl *LS) {
@@ -5753,6 +5766,30 @@ void HLSLBufferDecl::addLayoutStruct(CXXRecordDecl *LS) {
   addDecl(LS);
 }
 
+void HLSLBufferDecl::addDefaultBufferDecl(Decl *D) {
+  assert(isImplicit() &&
+         "default decls can only be added to the implicit/default constant "
+         "buffer $Globals");
+  DefaultBufferDecls.push_back(D);
+}
+
+HLSLBufferDecl::buffer_decl_iterator
+HLSLBufferDecl::buffer_decls_begin() const {
+  return buffer_decl_iterator(llvm::iterator_range(DefaultBufferDecls.begin(),
+                                                   DefaultBufferDecls.end()),
+                              decl_range(decls_begin(), decls_end()));
+}
+
+HLSLBufferDecl::buffer_decl_iterator HLSLBufferDecl::buffer_decls_end() const {
+  return buffer_decl_iterator(
+      llvm::iterator_range(DefaultBufferDecls.end(), DefaultBufferDecls.end()),
+      decl_range(decls_end(), decls_end()));
+}
+
+bool HLSLBufferDecl::buffer_decls_empty() {
+  return DefaultBufferDecls.empty() && decls_empty();
+}
+
 //===----------------------------------------------------------------------===//
 // ImportDecl Implementation
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 52247173b6990..a24f5ac878667 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -244,7 +244,7 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
   size_t BufferSize = 0;
   bool UsePackoffset = BufDecl->hasPackoffset();
   const auto *ElemIt = LayoutStruct->element_begin();
-  for (Decl *D : BufDecl->decls()) {
+  for (Decl *D : BufDecl->buffer_decls()) {
     if (isa<CXXRecordDecl, EmptyDecl>(D))
       // Nothing to do for this declaration.
       continue;
@@ -286,10 +286,7 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
                                   .str()))) &&
            "layout type does not match the converted element type");
 
-    // 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");
+    // FIXME: handle resources in cbuffer user-defined structs
 
     // create global variable for the constant and to metadata list
     GlobalVariable *ElemGV =
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index eb8d3ceeeba4c..65ec9c06b9ee5 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -5503,6 +5503,11 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
   if (getLangOpts().OpenCL && ASTTy->isSamplerT())
     return;
 
+  // HLSL default buffer constants will be emitted during HLSLBufferDecl codegen
+  if (getLangOpts().HLSL &&
+      D->getType().getAddressSpace() == LangAS::hlsl_constant)
+    return;
+
   // If this is OpenMP device, check if it is legal to emit this global
   // normally.
   if (LangOpts.OpenMPIsTargetDevice && OpenMPRuntime &&
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index abb46d3a84e74..d3c350b58da1a 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1416,8 +1416,7 @@ void Sema::ActOnEndOfTranslationUnit() {
   }
 
   if (LangOpts.HLSL)
-    HLSL().DiagnoseAvailabilityViolations(
-        getASTContext().getTranslationUnitDecl());
+    HLSL().ActOnEndOfTranslationUnit(getASTContext().getTranslationUnitDecl());
 
   // If there were errors, disable 'unused' warnings since they will mostly be
   // noise. Don't warn for a use from a module: either we should warn on all
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 1537a88731892..977185fcf9997 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -9,6 +9,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Sema/SemaHLSL.h"
+#include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/Attrs.inc"
@@ -147,7 +148,7 @@ bool ResourceBindings::hasBindingInfoForDecl(const VarDecl *VD) const {
   return DeclToBindingListIndex.contains(VD);
 }
 
-SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S) {}
+SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S), DefaultCBuffer(nullptr) {}
 
 Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
                                  SourceLocation KwLoc, IdentifierInfo *Ident,
@@ -219,7 +220,7 @@ static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
   // or on none.
   bool HasPackOffset = false;
   bool HasNonPackOffset = false;
-  for (auto *Field : BufDecl->decls()) {
+  for (auto *Field : BufDecl->buffer_decls()) {
     VarDecl *Var = dyn_cast<VarDecl>(Field);
     if (!Var)
       continue;
@@ -486,7 +487,7 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
   LS->setImplicit(true);
   LS->startDefinition();
 
-  for (Decl *D : BufDecl->decls()) {
+  for (Decl *D : BufDecl->buffer_decls()) {
     VarDecl *VD = dyn_cast<VarDecl>(D);
     if (!VD || VD->getStorageClass() == SC_Static ||
         VD->getType().getAddressSpace() == LangAS::hlsl_groupshared)
@@ -1922,7 +1923,21 @@ void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
 
 } // namespace
 
-void SemaHLSL::DiagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
+void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
+
+  // process default CBuffer - create buffer layout struct and invoke codegenCGH
+  if (DefaultCBuffer) {
+    SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
+    createHostLayoutStructForBuffer(SemaRef, DefaultCBuffer);
+
+    DeclGroupRef DG(DefaultCBuffer);
+    SemaRef.Consumer.HandleTopLevelDecl(DG);
+  }
+
+  diagnoseAvailabilityViolations(TU);
+}
+
+void SemaHLSL::diagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
   // Skip running the diagnostics scan if the diagnostic mode is
   // strict (-fhlsl-strict-availability) and the target shader stage is known
   // because all relevant diagnostics were already emitted in the
@@ -2784,6 +2799,14 @@ QualType SemaHLSL::getInoutParameterType(QualType Ty) {
   return Ty;
 }
 
+static bool IsDefaultBufferConstantDecl(VarDecl *VD) {
+  QualType QT = VD->getType();
+  return VD->getDeclContext()->isTranslationUnit() &&
+         QT.getAddressSpace() == LangAS::Default &&
+         VD->getStorageClass() != SC_Static &&
+         !isInvalidConstantBufferLeafElementType(QT.getTypePtr());
+}
+
 void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
   if (VD->hasGlobalStorage()) {
     // make sure the declaration has a complete type
@@ -2795,7 +2818,21 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
       return;
     }
 
-    // find all resources on decl
+    // Global variables outside a cbuffer block that are not a resource, static,
+    // groupshared, or an empty array or struct belong to the default constant
+    // buffer $Globals
+    if (IsDefaultBufferConstantDecl(VD)) {
+      if (DefaultCBuffer == nullptr)
+        DefaultCBuffer = HLSLBufferDecl::CreateDefaultCBuffer(
+            SemaRef.getASTContext(), SemaRef.getCurLexicalContext());
+      // update address space to hlsl_constant
+      QualType NewTy = getASTContext().getAddrSpaceQualType(
+          VD->getType(), LangAS::hlsl_constant);
+      VD->setType(NewTy);
+      DefaultCBuffer->addDefaultBufferDecl(VD);
+    }
+
+    // find all resources bindings on decl
     if (VD->getType()->isHLSLIntangibleType())
       collectResourcesOnVarDecl(VD);
 
diff --git a/clang/test/AST/HLSL/default_cbuffer.hlsl b/clang/test/AST/HLSL/default_cbuffer.hlsl
new file mode 100644
index 0000000000000..9e0fce7cc53cf
--- /dev/null
+++ b/clang/test/AST/HLSL/default_cbuffer.hlsl
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -ast-dump -o - %s | FileCheck %s
+
+struct EmptyStruct {
+};
+
+struct S {
+  RWBuffer<float> buf;
+  EmptyStruct es;
+  float ea[0];
+  float b;
+};
+
+// CHECK: VarDecl {{.*}} used a 'hlsl_constant float'
+float a;
+
+// CHECK: VarDecl {{.*}} b 'RWBuffer<float>':'hlsl::RWBuffer<float>'
+RWBuffer<float> b; 
+
+// CHECK: VarDecl {{.*}} c 'EmptyStruct'
+EmptyStruct c;
+
+// CHECK: VarDecl {{.*}} d 'float[0]'
+float d[0];
+
+// CHECK: VarDecl {{.*}} e 'RWBuffer<float>[2]'
+RWBuffer<float> e[2];
+
+// CHECK: VarDecl {{.*}} f 'groupshared float'
+groupshared float f;
+
+// CHECK: VarDecl {{.*}} g 'hlsl_constant float'
+float g;
+
+// CHECK: VarDecl {{.*}} h 'hlsl_constant S'
+S h;
+
+// CHECK: HLSLBufferDecl {{.*}} implicit cbuffer $Globals
+// CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_$Globals definition
+// CHECK: PackedAttr
+// CHECK-NEXT: FieldDecl {{.*}} a 'float'
+// CHECK-NEXT: FieldDecl {{.*}} g 'float'
+// CHECK-NEXT: FieldDecl {{.*}} h '__cblayout_S'
+
+// CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_S definition
+// CHECK: PackedAttr {{.*}} Implicit
+// CHECK-NEXT: FieldDecl {{.*}} b 'float'
+
+export float foo() {
+  return a;
+}
diff --git a/clang/test/CodeGenHLSL/basic_types.hlsl b/clang/test/CodeGenHLSL/basic_types.hlsl
index d987af45a649f..362042654ea8c 100644
--- a/clang/test/CodeGenHLSL/basic_types.hlsl
+++ b/clang/test/CodeGenHLSL/basic_types.hlsl
@@ -6,38 +6,38 @@
 // RUN:   -emit-llvm -disable-llvm-passes -o - -DNAMESPACED| FileCheck %s
 
 
-// CHECK: @uint16_t_Val = global i16 0, align 2
-// CHECK: @int16_t_Val = global i16 0, align 2
-// CHECK: @uint_Val = global i32 0, align 4
-// CHECK: @uint64_t_Val = global i64 0, align 8
-// CHECK: @int64_t_Val = global i64 0, align 8
-// CHECK: @int16_t2_Val = global <2 x i16> zeroinitializer, align 4
-// CHECK: @int16_t3_Val = global <3 x i16> zeroinitializer, align 8
-// CHECK: @int16_t4_Val = global <4 x i16> zeroinitializer, align 8
-// CHECK: @uint16_t2_Val = global <2 x i16> zeroinitializer, align 4
-// CHECK: @uint16_t3_Val = global <3 x i16> zeroinitializer, align 8
-// CHECK: @uint16_t4_Val = global <4 x i16> zeroinitializer, align 8
-// CHECK: @int2_Val = global <2 x i32> zeroinitializer, align 8
-// CHECK: @int3_Val = global <3 x i32> zeroinitializer, align 16
-// CHECK: @int4_Val = global <4 x i32> zeroinitializer, align 16
-// CHECK: @uint2_Val = global <2 x i32> zeroinitializer, align 8
-// CHECK: @uint3_Val = global <3 x i32> zeroinitializer, align 16
-// CHECK: @uint4_Val = global <4 x i32> zeroinitializer, align 16
-// CHECK: @int64_t2_Val = global <2 x i64> zeroinitializer, align 16
-// CHECK: @int64_t3_Val = global <3 x i64> zeroinitializer, align 32
-// CHECK: @int64_t4_Val = global <4 x i64> zeroinitializer, align 32
-// CHECK: @uint64_t2_Val = global <2 x i64> zeroinitializer, align 16
-// CHECK: @uint64_t3_Val = global <3 x i64> zeroinitializer, align 32
-// CHECK: @uint64_t4_Val = global <4 x i64> zeroinitializer, align 32
-// CHECK: @half2_Val = global <2 x half> zeroinitializer, align 4
-// CHECK: @half3_Val = global <3 x half> zeroinitializer, align 8
-// CHECK: @half4_Val = global <4 x half> zeroinitializer, align 8
-// CHECK: @float2_Val = global <2 x float> zeroinitializer, align 8
-// CHECK: @float3_Val = global <3 x float> zeroinitializer, align 16
-// CHECK: @float4_Val = global <4 x float> zeroinitializer, align 16
-// CHECK: @double2_Val = global <2 x double> zeroinitializer, align 16
-// CHECK: @double3_Val = global <3 x double> zeroinitializer, align 32
-// CHECK: @double4_Val = global <4 x double> zeroinitializer, align 32
+// CHECK: @uint16_t_Val = external addrspace(2) global i16, align 2
+// CHECK: @int16_t_Val = external addrspace(2) global i16, align 2
+// CHECK: @uint_Val = external addrspace(2) global i32, align 4
+// CHECK: @uint64_t_Val = external addrspace(2) global i64, align 8
+// CHECK: @int64_t_Val = external addrspace(2) global i64, align 8
+// CHECK: @int16_t2_Val = external addrspace(2) global <2 x i16>, align 4
+// CHECK: @int16_t3_Val = external addrspace(2) global <3 x i16>, align 8
+// CHECK: @int16_t4_Val = external addrspace(2) global <4 x i16>, align 8
+// CHECK: @uint16_t2_Val = external addrspace(2) global <2 x i16>, align 4
+// CHECK: @uint16_t3_Val = external addrspace(2) global <3 x i16>, align 8
+// CHECK: @uint16_t4_Val = external addrspace(2) global <4 x i16>, align 8
+// CHECK: @int2_Val = external addrspace(2) global <2 x i32>, align 8
+// CHECK: @int3_Val = external addrspace(2) global <3 x i32>, align 16
+// CHECK: @int4_Val = external addrspace(2) global <4 x i32>, align 16
+// CHECK: @uint2_Val = external addrspace(2) global <2 x i32>, align 8
+// CHECK: @uint3_Val = external addrspace(2) global <3 x i32>, align 16
+// CHECK: @uint4_Val = external addrspace(2) global <4 x i32>, align 16
+// CHECK: @int64_t2_Val = external addrspace(2) global <2 x i64>, align 16
+// CHECK: @int64_t3_Val = external addrspace(2) global <3 x i64>, align 32
+// CHECK: @int64_t4_Val = external addrspace(2) global <4 x i64>, align 32
+// CHECK: @uint64_t2_Val = external addrspace(2) global <2 x i64>, align 16
+// CHECK: @uint64_t3_Val = external addrspace(2) global <3 x i64>, align 32
+// CHECK: @uint64_t4_Val = external addrspace(2) global <4 x i64>, align 32
+// CHECK: @half2_Val = external addrspace(2) global <2 x half>, align 4
+// CHECK: @half3_Val = external addrspace(2) global <3 x half>, align 8
+// CHECK: @half4_Val = external addrspace(2) global <4 x half>, align 8
+// CHECK: @float2_Val = external addrspace(2) global <2 x float>, align 8
+// CHECK: @float3_Val = external addrspace(2) global <3 x float>, align 16
+// CHECK: @float4_Val = external addrspace(2) global <4 x float>, align 16
+// CHECK: @double2_Val = external addrspace(2) global <2 x double>, align 16
+// CHECK: @double3_Val = external addrspace(2) global <3 x double>, align 32
+// CHECK: @double4_Val = external addrspace(2) global <4 x double>, align 32
 
 #ifdef NAMESPACED
 #define TYPE_DECL(T)  hlsl::T T##_Val
diff --git a/clang/test/CodeGenHLSL/default_cbuffer.hlsl b/clang/test/CodeGenHLSL/default_cbuffer.hlsl
new file mode 100644
index 0000000000000..7368997b51ac9
--- /dev/null
+++ b/clang/test/CodeGenHLSL/default_cbuffer.hlsl
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute \
+// RUN:   -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// CHECK: %"struct.__cblayout_$Globals" = type { float, float, %struct.__cblayout_S }
+// CHECK: %struct.__cblayout_S = type { float }
+
+// CHECK-DAG: @"$Globals.cb" = external constant target("dx.CBuffer", %"struct.__cblayout_$Globals")
+// CHECK-DAG: @a = external addrspace(2) global float
+// CHECK-DAG: @g = external addrspace(2) global float
+// CHECK-DAG: @h = external addrspace(2) global %struct.__cblayout_S
+
+struct EmptyStruct {
+};
+
+struct S {
+  RWBuffer<float> buf;
+  EmptyStruct es;
+  float ea[0];
+  float b;
+};
+
+float a;
+RWBuffer<float> b; 
+EmptyStruct c;
+float d[0];
+RWBuffer<float> e[2];
+groupshared float f;
+float g;
+S h;
+
+RWBuffer<float> Buf;
+
+[numthreads(4,1,1)]
+void main() {
+  Buf[0] = a;
+}
+
+// CHECK: !hlsl.cblayouts = !{![[S_LAYOUT:.*]], ![[CB_LAYOUT:.*]]}
+// CHECK: !hlsl.cbs = !{![[CB:.*]]}
+
+// CHECK: ![[S_LAYOUT]] = !{!"struct.__cblayout_S", i32 4, i32 0}
+// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_$Globals", i32 20, i32 0, i32 4, i32 16}
+// CHECK: ![[CB]] = !{ptr @"$Globals.cb", ptr addrspace(2) @a, ptr addrspace(2) @g, ptr addrspace(2) @h}
\ No newline at end of file

>From 648548220abd23fe716fdc9a6b87257f82234ff5 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 4 Feb 2025 22:21:11 -0800
Subject: [PATCH 10/19] clang-format

---
 clang/lib/AST/Decl.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index eede936577f09..4eb648ce95f25 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5755,9 +5755,8 @@ HLSLBufferDecl::CreateDefaultCBuffer(ASTContext &C,
 
 HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C,
                                                    GlobalDeclID ID) {
-  return new (C, ID)
-      HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr,
-                     SourceLocation(), SourceLocation());
+  return new (C, ID) HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr,
+                                    SourceLocation(), SourceLocation());
 }
 
 void HLSLBufferDecl::addLayoutStruct(CXXRecordDecl *LS) {

>From 991ba1d81364fe21da9678d0db94c551abfe853a Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 5 Feb 2025 10:21:04 -0800
Subject: [PATCH 11/19] whitespace change so I can force-push the branch to
 unblock stuck PR

---
 clang/lib/Sema/SemaHLSL.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 977185fcf9997..72485322fc288 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1924,7 +1924,6 @@ void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
 } // namespace
 
 void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
-
   // process default CBuffer - create buffer layout struct and invoke codegenCGH
   if (DefaultCBuffer) {
     SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
@@ -1933,7 +1932,6 @@ void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
     DeclGroupRef DG(DefaultCBuffer);
     SemaRef.Consumer.HandleTopLevelDecl(DG);
   }
-
   diagnoseAvailabilityViolations(TU);
 }
 

>From b62863b900dd63eb1c8e3ffe656bbcbb6770dbdd Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 11 Feb 2025 20:32:51 -0800
Subject: [PATCH 12/19] Rework cbuffer codegen to use the target("dx.Layout",
 ...) type

---
 clang/include/clang/AST/Decl.h                |   6 +-
 clang/lib/AST/Decl.cpp                        |   2 +-
 clang/lib/CodeGen/CGHLSLRuntime.cpp           | 226 +++++-------------
 clang/lib/CodeGen/CGHLSLRuntime.h             |  20 +-
 clang/lib/CodeGen/CMakeLists.txt              |   1 +
 clang/lib/CodeGen/TargetInfo.h                |   4 +-
 clang/lib/CodeGen/Targets/DirectX.cpp         |  42 +++-
 clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp  | 201 ++++++++++++++++
 clang/lib/CodeGen/Targets/HLSLTargetInfo.h    |  39 +++
 clang/lib/CodeGen/Targets/SPIR.cpp            |  16 +-
 clang/lib/Sema/SemaHLSL.cpp                   |   2 +-
 clang/test/CodeGenHLSL/cbuffer.hlsl           | 120 +++++-----
 .../CodeGenHLSL/cbuffer_and_namespaces.hlsl   |  23 +-
 .../CodeGenHLSL/cbuffer_and_namespaces.ll     |  49 ++++
 .../CodeGenHLSL/cbuffer_with_packoffset.hlsl  |  10 +-
 ...uffer_with_static_global_and_function.hlsl |   7 +-
 16 files changed, 482 insertions(+), 286 deletions(-)
 create mode 100644 clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
 create mode 100644 clang/lib/CodeGen/Targets/HLSLTargetInfo.h
 create mode 100644 clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 05e56978977f2..85cef38bc03db 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -5034,7 +5034,7 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
   bool IsCBuffer;
   /// HasValidPackoffset - Whether the buffer has valid packoffset annotations
   //                       on all declarations
-  bool HasPackoffset;
+  bool HasValidPackoffset;
   // LayoutStruct - Layout struct for the buffer
   CXXRecordDecl *LayoutStruct;
 
@@ -5057,8 +5057,8 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
   SourceLocation getRBraceLoc() const { return RBraceLoc; }
   void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
   bool isCBuffer() const { return IsCBuffer; }
-  void setHasPackoffset(bool PO) { HasPackoffset = PO; }
-  bool hasPackoffset() const { return HasPackoffset; }
+  void setHasValidPackoffset(bool PO) { HasValidPackoffset = PO; }
+  bool hasValidPackoffset() const { return HasValidPackoffset; }
   const CXXRecordDecl *getLayoutStruct() const { return LayoutStruct; }
   void addLayoutStruct(CXXRecordDecl *LS);
 
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 4c5201d0ba2ee..95b25164d63dc 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5717,7 +5717,7 @@ HLSLBufferDecl::HLSLBufferDecl(DeclContext *DC, bool CBuffer,
                                SourceLocation IDLoc, SourceLocation LBrace)
     : NamedDecl(Decl::Kind::HLSLBuffer, DC, IDLoc, DeclarationName(ID)),
       DeclContext(Decl::Kind::HLSLBuffer), LBraceLoc(LBrace), KwLoc(KwLoc),
-      IsCBuffer(CBuffer), HasPackoffset(false), LayoutStruct(nullptr) {}
+      IsCBuffer(CBuffer), HasValidPackoffset(false), LayoutStruct(nullptr) {}
 
 HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
                                        DeclContext *LexicalParent, bool CBuffer,
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 52247173b6990..fde801dd1a8a4 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -20,6 +20,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/LLVMContext.h"
@@ -70,11 +71,14 @@ void addDisableOptimizations(llvm::Module &M) {
 
 } // namespace
 
-llvm::Type *CGHLSLRuntime::convertHLSLSpecificType(const Type *T) {
+llvm::Type *
+CGHLSLRuntime::convertHLSLSpecificType(const Type *T,
+                                       SmallVector<unsigned> *Packoffsets) {
   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, Packoffsets))
     return TargetTy;
 
   llvm_unreachable("Generic handling of HLSL types is not supported.");
@@ -96,153 +100,28 @@ static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) {
   return isResourceRecordType(Ty);
 }
 
-static ConstantAsMetadata *getConstIntMetadata(LLVMContext &Ctx, uint32_t value,
-                                               bool isSigned = false) {
-  return ConstantAsMetadata::get(
-      ConstantInt::get(Ctx, llvm::APInt(32, value, isSigned)));
-}
-
-static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
-  assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
-  if (Ty->isVectorTy()) {
-    llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
-    return FVT->getNumElements() *
-           (FVT->getElementType()->getScalarSizeInBits() / 8);
-  }
-  return Ty->getScalarSizeInBits() / 8;
-}
-
-// Returns size of a struct in constant buffer layout. The sizes are cached
-// in StructSizesForBuffer map. The map is also an indicator if a layout
-// metadata for this struct has been added to the module.
-// If the struct type is not in the map, this method will calculate the struct
-// layout, add a metadata node describing it to the module, and add the struct
-// size to the map.
-size_t
-CGHLSLRuntime::getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy) {
-  // check if we already have a side for this struct
-  auto SizeIt = StructSizesForBuffer.find(StructTy);
-  if (SizeIt != StructSizesForBuffer.end())
-    return SizeIt->getSecond();
-
-  // if not, calculate the struct layout and create a metadata node
-  LLVMContext &Ctx = CGM.getLLVMContext();
-  SmallVector<llvm::Metadata *> LayoutItems;
-
-  // start metadata list with a struct name and reserve one slot for its size
-  LayoutItems.push_back(MDString::get(Ctx, StructTy->getName()));
-  LayoutItems.push_back(nullptr);
-
-  // add element offsets
-  size_t StructSize = 0;
-  for (llvm::Type *ElTy : StructTy->elements()) {
-    size_t Offset = calculateBufferElementOffset(ElTy, &StructSize);
-    LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), Offset));
-  }
-  // set the size of the buffer to the reserved slot
-  LayoutItems[1] = getConstIntMetadata(Ctx, StructSize);
-
-  // add the struct layout to metadata
-  CGM.getModule()
-      .getOrInsertNamedMetadata("hlsl.cblayouts")
-      ->addOperand(MDNode::get(CGM.getLLVMContext(), LayoutItems));
-
-  // add struct size to list and return it
-  StructSizesForBuffer[StructTy] = StructSize;
-  return StructSize;
-}
-
-// Calculates offset of a single element in constant buffer layout.
-// The provided LayoutEndOffset marks the end of the layout so far (end offset
-// of the buffer or struct). After the element offset calculations are done it
-// will be updated the new end of layout value.
-// If the PackoffsetAttrs is not nullptr the offset will be based on the
-// packoffset annotation.
-size_t CGHLSLRuntime::calculateBufferElementOffset(
-    llvm::Type *LayoutTy, size_t *LayoutEndOffset,
-    HLSLPackOffsetAttr *PackoffsetAttr) {
-
-  size_t ElemOffset = 0;
-  size_t ElemSize = 0;
-  size_t ArrayCount = 1;
-  size_t ArrayStride = 0;
-  size_t EndOffset = *LayoutEndOffset;
-  size_t NextRowOffset = llvm::alignTo(EndOffset, 16U);
-
-  if (LayoutTy->isArrayTy()) {
-    llvm::Type *Ty = LayoutTy;
-    while (Ty->isArrayTy()) {
-      ArrayCount *= Ty->getArrayNumElements();
-      Ty = Ty->getArrayElementType();
-    }
-    ElemSize =
-        Ty->isStructTy()
-            ? getOrCalculateStructSizeForBuffer(cast<llvm::StructType>(Ty))
-            : getScalarOrVectorSize(Ty);
-    ArrayStride = llvm::alignTo(ElemSize, 16U);
-    ElemOffset =
-        PackoffsetAttr ? PackoffsetAttr->getOffsetInBytes() : NextRowOffset;
-
-  } else if (LayoutTy->isStructTy()) {
-    ElemOffset =
-        PackoffsetAttr ? PackoffsetAttr->getOffsetInBytes() : NextRowOffset;
-    ElemSize =
-        getOrCalculateStructSizeForBuffer(cast<llvm::StructType>(LayoutTy));
-
-  } else {
-    size_t Align = 0;
-    if (LayoutTy->isVectorTy()) {
-      llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(LayoutTy);
-      size_t SubElemSize = FVT->getElementType()->getScalarSizeInBits() / 8;
-      ElemSize = FVT->getNumElements() * SubElemSize;
-      Align = SubElemSize;
-    } else {
-      assert(LayoutTy->isIntegerTy() || LayoutTy->isFloatingPointTy());
-      ElemSize = LayoutTy->getScalarSizeInBits() / 8;
-      Align = ElemSize;
-    }
-    if (PackoffsetAttr) {
-      ElemOffset = PackoffsetAttr->getOffsetInBytes();
-    } else {
-      ElemOffset = llvm::alignTo(EndOffset, Align);
-      // if the element does not fit, move it to the next row
-      if (ElemOffset + ElemSize > NextRowOffset)
-        ElemOffset = NextRowOffset;
-    }
-  }
-
-  // Update end offset of the buffer/struct layout; do not update it if
-  // the provided EndOffset is already bigger than the new one value
-  // (which may happen with packoffset annotations)
-  unsigned NewEndOffset =
-      ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
-  *LayoutEndOffset = std::max<size_t>(EndOffset, NewEndOffset);
-
-  return ElemOffset;
-}
-
-// Emits constant global variables for buffer declarations, creates metadata
-// linking the constant globals with the buffer. Also calculates the buffer
-// layout and creates metadata node describing 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>(BufGV->getValueType())->getTypeParameter(0));
+      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));
 
-  // Start layout metadata list with a struct name and reserve one slot for
-  // the buffer size
-  SmallVector<llvm::Metadata *> LayoutItems;
-  LayoutItems.push_back(MDString::get(Ctx, LayoutStruct->getName()));
-  LayoutItems.push_back(nullptr);
-
-  size_t BufferSize = 0;
-  bool UsePackoffset = BufDecl->hasPackoffset();
   const auto *ElemIt = LayoutStruct->element_begin();
   for (Decl *D : BufDecl->decls()) {
     if (isa<CXXRecordDecl, EmptyDecl>(D))
@@ -275,17 +154,6 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
            "number of elements in layout struct does not match");
     llvm::Type *LayoutType = *ElemIt++;
 
-    // Make sure the type of the VarDecl type matches the type of the layout
-    // struct element, or that it is a layout struct with the same name
-    assert((CGM.getTypes().ConvertTypeForMem(VDTy) == LayoutType ||
-            (LayoutType->isStructTy() &&
-             cast<llvm::StructType>(LayoutType)
-                 ->getName()
-                 .starts_with(("struct.__cblayout_" +
-                               VDTy->getAsCXXRecordDecl()->getName())
-                                  .str()))) &&
-           "layout type does not match the converted element type");
-
     // there might be resources inside the used defined structs
     if (VDTy->isStructureType() && VDTy->isHLSLIntangibleType())
       // FIXME: handle resources in cbuffer structs
@@ -295,29 +163,15 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
     GlobalVariable *ElemGV =
         cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
     BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
-
-    // get offset of the global and and to metadata list
-    assert(((UsePackoffset && VD->hasAttr<HLSLPackOffsetAttr>()) ||
-            !UsePackoffset) &&
-           "expected packoffset attribute on every declaration");
-    size_t Offset = calculateBufferElementOffset(
-        LayoutType, &BufferSize,
-        UsePackoffset ? VD->getAttr<HLSLPackOffsetAttr>() : nullptr);
-    LayoutItems.push_back(getConstIntMetadata(Ctx, Offset));
   }
   assert(ElemIt == LayoutStruct->element_end() &&
          "number of elements in layout struct does not match");
   // set the size of the buffer
-  LayoutItems[1] = getConstIntMetadata(Ctx, BufferSize);
 
   // add buffer metadata to the module
   CGM.getModule()
       .getOrInsertNamedMetadata("hlsl.cbs")
       ->addOperand(MDNode::get(Ctx, BufGlobals));
-
-  CGM.getModule()
-      .getOrInsertNamedMetadata("hlsl.cblayouts")
-      ->addOperand(MDNode::get(Ctx, LayoutItems));
 }
 
 // Creates resource handle type for the HLSL buffer declaration
@@ -331,6 +185,25 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
   return cast<HLSLAttributedResourceType>(QT.getTypePtr());
 }
 
+static void fillPackoffsetLayout(const HLSLBufferDecl *BufDecl,
+                                 SmallVector<unsigned> &Layout) {
+  assert(Layout.empty() && "expected empty vector for layout");
+  assert(BufDecl->hasValidPackoffset());
+
+  for (Decl *D : BufDecl->decls()) {
+    if (isa<CXXRecordDecl, EmptyDecl>(D) || isa<FunctionDecl>(D)) {
+      continue;
+    }
+    VarDecl *VD = dyn_cast<VarDecl>(D);
+    if (!VD || VD->getType().getAddressSpace() != LangAS::hlsl_constant)
+      continue;
+    assert(VD->hasAttr<HLSLPackOffsetAttr>() &&
+           "expected packoffset attribute on every declaration");
+    size_t Offset = VD->getAttr<HLSLPackOffsetAttr>()->getOffsetInBytes();
+    Layout.push_back(Offset);
+  }
+}
+
 // Codegen for HLSLBufferDecl
 void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
 
@@ -345,16 +218,20 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
     return;
 
   // create global variable for the constant buffer
-  llvm::Module &M = CGM.getModule();
+  SmallVector<unsigned> Layout;
+  if (BufDecl->hasValidPackoffset())
+    fillPackoffsetLayout(BufDecl, Layout);
+
   llvm::TargetExtType *TargetTy =
-      cast<llvm::TargetExtType>(convertHLSLSpecificType(ResHandleTy));
+      cast<llvm::TargetExtType>(convertHLSLSpecificType(
+          ResHandleTy, BufDecl->hasValidPackoffset() ? &Layout : nullptr));
   llvm::GlobalVariable *BufGV =
       new GlobalVariable(TargetTy, /*isConstant*/ true,
                          GlobalValue::LinkageTypes::ExternalLinkage, nullptr,
                          llvm::formatv("{0}{1}", BufDecl->getName(),
                                        BufDecl->isCBuffer() ? ".cb" : ".tb"),
                          GlobalValue::NotThreadLocal);
-  M.insertGlobalVariable(BufGV);
+  CGM.getModule().insertGlobalVariable(BufGV);
 
   // Add globals for constant buffer elements and create metadata nodes
   emitBufferGlobalsAndMetadata(BufDecl, BufGV);
@@ -368,6 +245,21 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
                          RBA->getSpaceNumber());
 }
 
+llvm::Type *
+CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
+  const auto Entry = LayoutTypes.find(StructType);
+  if (Entry != LayoutTypes.end())
+    return Entry->getSecond();
+  return nullptr;
+}
+
+void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
+                                            llvm::Type *LayoutTy) {
+  assert(getHLSLBufferLayoutType(StructType) == nullptr &&
+         "layout type for this struct already exist");
+  LayoutTypes[StructType] = LayoutTy;
+}
+
 void CGHLSLRuntime::finishCodeGen() {
   auto &TargetOpts = CGM.getTarget().getTargetOpts();
   llvm::Module &M = CGM.getModule();
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 8658cb8653fb4..6d2054e9efd50 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -63,6 +63,7 @@ class ParmVarDecl;
 class HLSLBufferDecl;
 class HLSLResourceBindingAttr;
 class Type;
+class RecordType;
 class DeclContext;
 class HLSLPackOffsetAttr;
 
@@ -141,7 +142,9 @@ class CGHLSLRuntime {
   CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
   virtual ~CGHLSLRuntime() {}
 
-  llvm::Type *convertHLSLSpecificType(const Type *T);
+  llvm::Type *
+  convertHLSLSpecificType(const Type *T,
+                          SmallVector<unsigned> *Packoffsets = nullptr);
 
   void annotateHLSLResource(const VarDecl *D, llvm::GlobalVariable *GV);
   void generateGlobalCtorDtorCalls();
@@ -157,6 +160,10 @@ class CGHLSLRuntime {
 
   llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);
 
+  llvm::Type *getHLSLBufferLayoutType(const RecordType *LayoutStructTy);
+  void addHLSLBufferLayoutType(const RecordType *LayoutStructTy,
+                               llvm::Type *LayoutTy);
+
 private:
   void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
                                    llvm::hlsl::ResourceClass RC,
@@ -165,18 +172,9 @@ class CGHLSLRuntime {
                                    BufferResBinding &Binding);
   void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
                                     llvm::GlobalVariable *BufGV);
-
-  size_t
-  calculateBufferElementOffset(llvm::Type *LayoutTy, size_t *LayoutEndOffset,
-                               HLSLPackOffsetAttr *PackoffsetAttr = nullptr);
-
-  size_t getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy);
-
   llvm::Triple::ArchType getArch();
 
-  // Sizes of structs in constant buffer layout. Structs in the map
-  // had their layout calculated and added to the module as metadata.
-  llvm::DenseMap<llvm::StructType *, size_t> StructSizesForBuffer;
+  llvm::DenseMap<const clang::RecordType *, llvm::Type *> LayoutTypes;
 };
 
 } // namespace CodeGen
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index 868ec847b9634..1a6b25883d9c8 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -124,6 +124,7 @@ add_clang_library(clangCodeGen
   Targets/CSKY.cpp
   Targets/DirectX.cpp
   Targets/Hexagon.cpp
+  Targets/HLSLTargetInfo.cpp
   Targets/Lanai.cpp
   Targets/LoongArch.cpp
   Targets/M68k.cpp
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index 4a66683a3b91f..86057c14a549e 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -439,7 +439,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 SmallVector<unsigned> *Packoffsets = nullptr) const {
     return nullptr;
   }
 
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index ec7fa342d5846..3d4b65aec0a3a 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -7,8 +7,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "ABIInfoImpl.h"
+#include "CodeGenModule.h"
+#include "HLSLTargetInfo.h"
 #include "TargetInfo.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Type.h"
 
 using namespace clang;
 using namespace clang::CodeGen;
@@ -19,16 +24,30 @@ using namespace clang::CodeGen;
 
 namespace {
 
-class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {
+class DirectXTargetCodeGenInfo : public CommonHLSLTargetCodeGenInfo {
 public:
   DirectXTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
-      : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
+      : CommonHLSLTargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
 
-  llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *T) const override;
+  llvm::Type *getHLSLType(
+      CodeGenModule &CGM, const Type *T,
+      const SmallVector<unsigned> *Packoffsets = nullptr) const override;
+
+  llvm::Type *getHLSLLayoutType(CodeGenModule &CGM,
+                                llvm::StructType *LayoutStructTy,
+                                SmallVector<unsigned> Layout) const override;
 };
 
-llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
-                                                  const Type *Ty) const {
+llvm::Type *DirectXTargetCodeGenInfo::getHLSLLayoutType(
+    CodeGenModule &CGM, llvm::StructType *LayoutStructTy,
+    SmallVector<unsigned> Layout) const {
+  return llvm::TargetExtType::get(CGM.getLLVMContext(), "dx.Layout",
+                                  {LayoutStructTy}, Layout);
+}
+
+llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
+    CodeGenModule &CGM, const Type *Ty,
+    const SmallVector<unsigned> *Packoffsets) const {
   auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
   if (!ResType)
     return nullptr;
@@ -57,11 +76,16 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
     return llvm::TargetExtType::get(Ctx, TypeName, {ElemType}, Ints);
   }
   case llvm::dxil::ResourceClass::CBuffer: {
-    QualType StructTy = ResType->getContainedType();
-    if (StructTy.isNull())
+    QualType ContainedTy = ResType->getContainedType();
+    if (ContainedTy.isNull() || !ContainedTy->isStructureType())
       return nullptr;
-    llvm::Type *Ty = CGM.getTypes().ConvertType(StructTy);
-    return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {Ty});
+
+    llvm::Type *BufferLayoutTy = this->createHLSLBufferLayoutType(
+        CGM, ContainedTy->getAsStructureType(), Packoffsets);
+    if (!BufferLayoutTy)
+      return nullptr;
+
+    return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {BufferLayoutTy});
   }
   case llvm::dxil::ResourceClass::Sampler:
     llvm_unreachable("dx.Sampler handles are not implemented yet");
diff --git a/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp b/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
new file mode 100644
index 0000000000000..e0e7f6daddcfa
--- /dev/null
+++ b/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
@@ -0,0 +1,201 @@
+//===- HLSLTargetInto.cpp--------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "HLSLTargetInfo.h"
+#include "CGHLSLRuntime.h"
+#include "TargetInfo.h"
+#include "clang/AST/DeclCXX.h"
+
+//===----------------------------------------------------------------------===//
+// Target codegen info implementation common between DirectX and SPIR/SPIR-V.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+// Creates a new array type with the same dimentions
+// but with the new element type.
+static llvm::Type *
+createArrayWithNewElementType(CodeGenModule &CGM,
+                              const ConstantArrayType *ArrayType,
+                              llvm::Type *NewElemType) {
+  const clang::Type *ArrayElemType = ArrayType->getArrayElementTypeNoTypeQual();
+  if (ArrayElemType->isConstantArrayType())
+    NewElemType = createArrayWithNewElementType(
+        CGM, cast<const ConstantArrayType>(ArrayElemType), NewElemType);
+  return llvm::ArrayType::get(NewElemType, ArrayType->getSExtSize());
+}
+
+// Returns the size of a scalar or vector in bytes/
+static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
+  assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
+  if (Ty->isVectorTy()) {
+    llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
+    return FVT->getNumElements() *
+           (FVT->getElementType()->getScalarSizeInBits() / 8);
+  }
+  return Ty->getScalarSizeInBits() / 8;
+}
+
+} // namespace
+
+// Creates a layout type for given struct with HLSL constant buffer layout
+// taking into account Packoffsets, if provided.
+// Previously created layout types are cached in CGHLSLRuntime because
+// TargetCodeGenInto info is cannot store any data
+// (CGM.getTargetCodeGenInfo() returns a const reference to TargetCondegenInfo).
+//
+// The function iterates over all fields of the StructType (including base
+// classes), converts each field to its corresponding LLVM type and calculated
+// it's HLSL constant bufffer layout (offset and size). Any embedded struct (or
+// arrays of structs) are converted to target layout types as well.
+llvm::Type *CommonHLSLTargetCodeGenInfo::createHLSLBufferLayoutType(
+    CodeGenModule &CGM, const RecordType *StructType,
+    const SmallVector<unsigned> *Packoffsets) const {
+
+  // check if we already have the layout type for this struct
+  if (llvm::Type *Ty = CGM.getHLSLRuntime().getHLSLBufferLayoutType(StructType))
+    return Ty;
+
+  SmallVector<unsigned> Layout;
+  SmallVector<llvm::Type *> LayoutElements;
+  unsigned Index = 0; // packoffset index
+  unsigned EndOffset = 0;
+
+  // reserve first spot in the layout vector for buffer size
+  Layout.push_back(0);
+
+  // iterate over all fields of the record, including fields on base classes
+  llvm::SmallVector<const RecordType *> RecordTypes;
+  RecordTypes.push_back(StructType);
+  while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
+    CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
+    assert(D->getNumBases() == 1 &&
+           "HLSL doesn't support multiple inheritance");
+    RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
+  }
+  while (!RecordTypes.empty()) {
+    const RecordType *RT = RecordTypes.back();
+    RecordTypes.pop_back();
+
+    for (const auto *FD : RT->getDecl()->fields()) {
+      assert(!Packoffsets || Index < Packoffsets->size() &&
+                                 "number of elements in layout struct does not "
+                                 "match number of packoffset annotations");
+      // Size of element; for arrays this is a size of a single element in the
+      // array. Total array size of calculated as (ArrayCount-1) * ArrayStride +
+      // ElemSize.
+      unsigned ElemSize = 0;
+
+      unsigned ElemOffset = 0;
+      unsigned ArrayCount = 1;
+      unsigned ArrayStride = 0;
+      unsigned NextRowOffset = llvm::alignTo(EndOffset, 16U);
+      llvm::Type *ElemLayoutTy = nullptr;
+
+      QualType FieldTy = FD->getType();
+
+      if (FieldTy->isConstantArrayType()) {
+        // Unwrap array to find the element type and get combined array size.
+        QualType Ty = FieldTy;
+        while (Ty->isConstantArrayType()) {
+          const ConstantArrayType *ArrayTy = cast<ConstantArrayType>(Ty);
+          ArrayCount *= ArrayTy->getSExtSize();
+          Ty = ArrayTy->getElementType();
+        }
+        // For array of structures, create a new array with a layout type
+        // instead of the structure type.
+        if (Ty->isStructureType()) {
+          llvm::Type *NewTy = cast<llvm::TargetExtType>(
+              createHLSLBufferLayoutType(CGM, Ty->getAsStructureType()));
+          if (!NewTy)
+            return nullptr;
+          assert(isa<llvm::TargetExtType>(NewTy) && "expected target type");
+          ElemSize = cast<llvm::TargetExtType>(NewTy)->getIntParameter(0);
+          ElemLayoutTy = createArrayWithNewElementType(
+              CGM, cast<ConstantArrayType>(FieldTy.getTypePtr()), NewTy);
+        } else {
+          // Array of vectors or scalars
+          ElemSize =
+              getScalarOrVectorSize(CGM.getTypes().ConvertTypeForMem(Ty));
+          ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
+        }
+        ArrayStride = llvm::alignTo(ElemSize, 16U);
+        ElemOffset =
+            Packoffsets != nullptr ? (*Packoffsets)[Index] : NextRowOffset;
+
+      } else if (FieldTy->isStructureType()) {
+        // Create a layout type for the structure
+        ElemLayoutTy =
+            createHLSLBufferLayoutType(CGM, FieldTy->getAsStructureType());
+        if (!ElemLayoutTy)
+          return nullptr;
+        assert(isa<llvm::TargetExtType>(ElemLayoutTy) &&
+               "expected target type");
+        ElemSize = cast<llvm::TargetExtType>(ElemLayoutTy)->getIntParameter(0);
+        ElemOffset =
+            Packoffsets != nullptr ? (*Packoffsets)[Index] : NextRowOffset;
+      } else {
+        // scalar or vector - find element size and alignment
+        unsigned Align = 0;
+        ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
+        if (ElemLayoutTy->isVectorTy()) {
+          // align vectors by sub element size
+          const llvm::FixedVectorType *FVT =
+              cast<llvm::FixedVectorType>(ElemLayoutTy);
+          unsigned SubElemSize =
+              FVT->getElementType()->getScalarSizeInBits() / 8;
+          ElemSize = FVT->getNumElements() * SubElemSize;
+          Align = SubElemSize;
+        } else {
+          assert(ElemLayoutTy->isIntegerTy() ||
+                 ElemLayoutTy->isFloatingPointTy());
+          ElemSize = ElemLayoutTy->getScalarSizeInBits() / 8;
+          Align = ElemSize;
+        }
+        // calculate or get element offset for the vector or scalar
+        if (Packoffsets != nullptr) {
+          ElemOffset = (*Packoffsets)[Index];
+        } else {
+          ElemOffset = llvm::alignTo(EndOffset, Align);
+          // if the element does not fit, move it to the next row
+          if (ElemOffset + ElemSize > NextRowOffset)
+            ElemOffset = NextRowOffset;
+        }
+      }
+
+      // Update end offset of the layout; do not update it if the EndOffset
+      // is already bigger than the new value (which may happen with unordered
+      // packoffset annotations)
+      unsigned NewEndOffset =
+          ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
+      EndOffset = std::max<unsigned>(EndOffset, NewEndOffset);
+
+      // add the layout element and offset to the lists
+      Layout.push_back(ElemOffset);
+      LayoutElements.push_back(ElemLayoutTy);
+      Index++;
+    }
+  }
+
+  // set the size of the buffer
+  Layout[0] = EndOffset;
+
+  // create the layout struct type; anonymous struct have empty name but
+  // non-empty qualified name
+  const CXXRecordDecl *Decl = StructType->getAsCXXRecordDecl();
+  std::string Name =
+      Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString();
+  llvm::StructType *StructTy =
+      llvm::StructType::create(LayoutElements, Name, true);
+
+  // create target layout type
+  llvm::Type *NewLayoutTy = this->getHLSLLayoutType(CGM, StructTy, Layout);
+  if (NewLayoutTy)
+    CGM.getHLSLRuntime().addHLSLBufferLayoutType(StructType, NewLayoutTy);
+  return NewLayoutTy;
+}
diff --git a/clang/lib/CodeGen/Targets/HLSLTargetInfo.h b/clang/lib/CodeGen/Targets/HLSLTargetInfo.h
new file mode 100644
index 0000000000000..279ce4fba3dad
--- /dev/null
+++ b/clang/lib/CodeGen/Targets/HLSLTargetInfo.h
@@ -0,0 +1,39 @@
+//===- HLSLTargetInfo.h ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABIInfoImpl.h"
+#include "TargetInfo.h"
+
+using namespace clang;
+using namespace clang::CodeGen;
+
+//===----------------------------------------------------------------------===//
+// Target codegen info implementation common between DirectX and SPIR/SPIR-V.
+//===----------------------------------------------------------------------===//
+
+class CommonHLSLTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+  CommonHLSLTargetCodeGenInfo(std::unique_ptr<ABIInfo> Info)
+      : TargetCodeGenInfo(std::move(Info)) {}
+
+  // Returns LLVM target extension type "dx.Layout" or "spv.Layout"
+  // for given structure type and layout data. The first number in
+  // the Layout is the size followed by offsets for each struct element.
+  virtual llvm::Type *getHLSLLayoutType(CodeGenModule &CGM,
+                                        llvm::StructType *LayoutStructTy,
+                                        SmallVector<unsigned> Layout) const {
+    return nullptr;
+  };
+
+protected:
+  // Creates a layout type for given struct with HLSL constant buffer layout
+  // taking into account Packoffsets, if provided.
+  virtual llvm::Type *createHLSLBufferLayoutType(
+      CodeGenModule &CGM, const clang::RecordType *StructType,
+      const SmallVector<unsigned> *Packoffsets = nullptr) const;
+};
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index 5c75e985e953d..a1d8ffbf73284 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ABIInfoImpl.h"
+#include "HLSLTargetInfo.h"
 #include "TargetInfo.h"
 
 using namespace clang;
@@ -38,12 +39,12 @@ class SPIRVABIInfo : public CommonSPIRABIInfo {
 };
 } // end anonymous namespace
 namespace {
-class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo {
+class CommonSPIRTargetCodeGenInfo : public CommonHLSLTargetCodeGenInfo {
 public:
   CommonSPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
-      : TargetCodeGenInfo(std::make_unique<CommonSPIRABIInfo>(CGT)) {}
+      : CommonHLSLTargetCodeGenInfo(std::make_unique<CommonSPIRABIInfo>(CGT)) {}
   CommonSPIRTargetCodeGenInfo(std::unique_ptr<ABIInfo> ABIInfo)
-      : TargetCodeGenInfo(std::move(ABIInfo)) {}
+      : CommonHLSLTargetCodeGenInfo(std::move(ABIInfo)) {}
 
   LangAS getASTAllocaAddressSpace() const override {
     return getLangASFromTargetAS(
@@ -52,7 +53,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 *Ty,
+      const SmallVector<unsigned> *Packoffsets = nullptr) const override;
   llvm::Type *getSPIRVImageTypeFromHLSLResource(
       const HLSLAttributedResourceType::Attributes &attributes,
       llvm::Type *ElementType, llvm::LLVMContext &Ctx) const;
@@ -364,8 +367,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 SmallVector<unsigned> *Packoffsets) const {
   auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
   if (!ResType)
     return nullptr;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 1537a88731892..c011b46d11ac1 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -261,7 +261,7 @@ static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
       IsValid = false;
     }
   }
-  BufDecl->setHasPackoffset(IsValid);
+  BufDecl->setHasValidPackoffset(IsValid);
 }
 
 // Returns true if the array has a zero size = if any of the dimensions is 0
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index 9a3f632e859c7..38093c6dfacd7 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -1,14 +1,24 @@
 // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute \
 // RUN:   -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
 
-// CHECK: %struct.__cblayout_CBScalars = type <{ float, double, half, i64, i32, i16, i32, i64 }>
-// CHECK: %struct.__cblayout_CBVectors = type <{ <3 x float>, <3 x double>, <2 x half>, <3 x i64>, <4 x i32>, <3 x i16>, <3 x i64> }>
-// CHECK: %struct.__cblayout_CBArrays = type <{ [3 x float], [2 x <3 x double>], [2 x [2 x half]], [3 x i64], [2 x [3 x [4 x <4 x i32>]]], [1 x i16], [2 x i64], [4 x i32] }>
-// CHECK: %struct.__cblayout_CBStructs = type { %struct.A, %struct.B, %struct.C, [5 x %struct.A], %struct.__cblayout_D, half, %struct.B, <3 x i16> }
-// CHECK: %struct.A = type { <2 x float> }
-// CHECK: %struct.C = type { i32, %struct.A }
-// CHECK: %struct.__cblayout_D = type { [2 x [3 x %struct.B]] }
-// CHECK: %struct.B = type { %struct.A, <3 x i16> }
+// CHECK: %__cblayout_CBScalars = type <{ float, double, half, i64, i32, i16, i32, i64 }>
+// CHECK: %__cblayout_CBVectors = type <{ <3 x float>, <3 x double>, <2 x half>, <3 x i64>, <4 x i32>, <3 x i16>, <3 x i64> }>
+// CHECK: %__cblayout_CBArrays = type <{ [3 x float], [2 x <3 x double>], [2 x [2 x half]], [3 x i64], [2 x [3 x [4 x <4 x i32>]]], [1 x i16], [2 x i64], [4 x i32] }>
+// CHECK: %__cblayout_CBStructs = type <{ target("dx.Layout", %A, 8, 0), target("dx.Layout", %B, 14, 0, 8), 
+// CHECK-SAME: target("dx.Layout", %C, 24, 0, 16), [5 x target("dx.Layout", %A, 8, 0)], 
+// CHECK-SAME: target("dx.Layout", %__cblayout_D, 94, 0), half, <3 x i16> }>
+
+// CHECK: %A = type <{ <2 x float> }>
+// CHECK: %B = type <{ <2 x float>, <3 x i16> }>
+// CHECK: %C = type <{ i32, target("dx.Layout", %A, 8, 0) }>
+// CHECK: %__cblayout_D = type <{ [2 x [3 x target("dx.Layout", %B, 14, 0, 8)]] }>
+
+// CHECK: %__cblayout_CBMix = type <{ [2 x target("dx.Layout", %Test, 8, 0, 4)], float, [3 x [2 x <2 x float>]], float,
+// CHECK-SAME: target("dx.Layout", %anon, 4, 0), double, target("dx.Layout", %anon.0, 8, 0), float, <1 x double>, i16 }>
+
+// CHECK: %Test = type <{ float, float }>
+// CHECK: %anon = type <{ float }>
+// CHECK: %anon.0 = type <{ <2 x i32> }>
 
 cbuffer CBScalars : register(b1, space5) {
   float a1;
@@ -21,7 +31,8 @@ cbuffer CBScalars : register(b1, space5) {
   int64_t a8;
 }
 
-// CHECK: @CBScalars.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBScalars)
+// CHECK: @CBScalars.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 
+// CHECK-SAME: 56, 0, 8, 16, 24, 32, 36, 40, 48))
 // CHECK: @a1 = external addrspace(2) global float, align 4
 // CHECK: @a2 = external addrspace(2) global double, align 8
 // CHECK: @a3 = external addrspace(2) global half, align 2
@@ -39,10 +50,11 @@ cbuffer CBVectors {
   int4 b5;
   uint16_t3 b6;
   int64_t3 b7;
-  // FIXME: add s bool vectors after llvm-project/llvm#91639 is added
+  // FIXME: add a bool vectors after llvm-project/llvm#91639 is added
 }
 
-// CHECK: @CBVectors.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBVectors)
+// CHECK: @CBVectors.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors, 
+// CHECK-SAME: 136, 0, 16, 40, 48, 80, 96, 112))
 // CHECK: @b1 = external addrspace(2) global <3 x float>, align 16
 // CHECK: @b2 = external addrspace(2) global <3 x double>, align 32
 // CHECK: @b3 = external addrspace(2) global <2 x half>, align 4
@@ -62,7 +74,8 @@ cbuffer CBArrays : register(b2) {
   bool c8[4];
 }
 
-// CHECK: @CBArrays.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBArrays)
+// CHECK: @CBArrays.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 
+// CHECK-SAME: 708, 0, 48, 112, 176, 224, 608, 624, 656))
 // CHECK: @c1 = external addrspace(2) global [3 x float], align 4
 // CHECK: @c2 = external addrspace(2) global [2 x <3 x double>], align 32
 // CHECK: @c3 = external addrspace(2) global [2 x [2 x half]], align 2
@@ -92,13 +105,15 @@ struct D {
   Empty es;
 };
 
-// CHECK: @CBStructs.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBStructs)
-// CHECK: @a = external addrspace(2) global %struct.A, align 8
-// CHECK: @b = external addrspace(2) global %struct.B, align 8
-// CHECK: @c = external addrspace(2) global %struct.C, align 8
-// CHECK: @array_of_A = external addrspace(2) global [5 x %struct.A], align 8
-// CHECK: @d = external addrspace(2) global %struct.__cblayout_D, align 8
+// CHECK: @CBStructs.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs, 
+// CHECK-SAME: 246, 0, 16, 32, 64, 144, 238, 240))
+// CHECK: @a = external addrspace(2) global target("dx.Layout", %A, 8, 0), align 8
+// CHECK: @b = external addrspace(2) global target("dx.Layout", %B, 14, 0, 8), align 8
+// CHECK: @c = external addrspace(2) global target("dx.Layout", %C, 24, 0, 16), align 8
+// CHECK: @array_of_A = external addrspace(2) global [5 x target("dx.Layout", %A, 8, 0)], align 8
+// CHECK: @d = external addrspace(2) global target("dx.Layout", %__cblayout_D, 94, 0), align 8
 // CHECK: @e = external addrspace(2) global half, align 2
+// CHECK: @f = external addrspace(2) global <3 x i16>, align 8
 
 cbuffer CBStructs {
   A a;
@@ -107,55 +122,56 @@ cbuffer CBStructs {
   A array_of_A[5];
   D d;
   half e;
-  B f;
-  uint16_t3 g;
+  uint16_t3 f;
 };
 
 struct Test {
     float a, b;
 };
 
-// CHECK: @CBMix.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBMix)
-// CHECK: @test = external addrspace(2) global [2 x %struct.Test], align 4
+// CHECK: @CBMix.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CBMix,
+// CHECK-SAME: 170, 0, 24, 32, 120, 128, 136, 144, 152, 160, 168))
+// CHECK: @test = external addrspace(2) global [2 x target("dx.Layout", %Test, 8, 0, 4)], align 4
 // CHECK: @f1 = external addrspace(2) global float, align 4
 // CHECK: @f2 = external addrspace(2) global [3 x [2 x <2 x float>]], align 8
 // CHECK: @f3 = external addrspace(2) global float, align 4
-// CHECK: @s = external addrspace(2) global %struct.anon, align 4
-// CHECK: @dd = external addrspace(2) global double, align 8
-// CHECK: @f4 = external addrspace(2) global float, align 4
-// CHECK: @dv = external addrspace(2) global <1 x double>, align 8
-// CHECK: @uv = external addrspace(2) global i16, align 2
+// CHECK: @f4 = external addrspace(2) global target("dx.Layout", %anon, 4, 0), align 4
+// CHECK: @f5 = external addrspace(2) global double, align 8
+// CHECK: @f6 = external addrspace(2) global target("dx.Layout", %anon.0, 8, 0), align 8
+// CHECK: @f7 = external addrspace(2) global float, align 4
+// CHECK: @f8 = external addrspace(2) global <1 x double>, align 8
+// CHECK: @f9 = external addrspace(2) global i16, align 2
 
 cbuffer CBMix {
     Test test[2];
     float f1;
     float2 f2[3][2];
     float f3;
-    struct { float c; } s;
-    double dd;
-    float f4;
-    vector<double,1> dv;
-    uint16_t uv;
+    struct { float c; } f4;
+    double f5;
+    struct { int2 i; } f6;
+    float f7;
+    vector<double,1> f8;
+    uint16_t f9;
 };  
 
-// CHECK: efine internal void @_init_resource_CBScalars.cb()
+// CHECK: define internal void @_init_resource_CBScalars.cb()
 // CHECK-NEXT: entry:
-// CHECK-NEXT: %[[HANDLE1:.*]] = call target("dx.CBuffer", %struct.__cblayout_CBScalars)
-// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBScalarsst(i32 5, i32 1, i32 1, i32 0, i1 false)
-// CHECK-NEXT: store target("dx.CBuffer", %struct.__cblayout_CBScalars) %[[HANDLE1]], ptr @CBScalars.cb, align 4
+// CHECK-NEXT: %[[HANDLE1:.*]] = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48))
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBScalarss_56_0_8_16_24_32_36_40_48tt(i32 5, i32 1, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48)) %CBScalars.cb_h, ptr @CBScalars.cb, align 4
 
 // CHECK: define internal void @_init_resource_CBArrays.cb()
 // CHECK-NEXT: entry:
-// CHECK-NEXT: %[[HANDLE2:.*]] = call target("dx.CBuffer", %struct.__cblayout_CBArrays)
-// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBArraysst(i32 0, i32 2, i32 1, i32 0, i1 false)
-// CHECK-NEXT: store target("dx.CBuffer", %struct.__cblayout_CBArrays) %[[HANDLE2]], ptr @CBArrays.cb, align 4
+// CHECK-NEXT: %[[HANDLE2:.*]] = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656))
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBArrayss_708_0_48_112_176_224_608_624_656tt(i32 0, i32 2, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656)) %CBArrays.cb_h, ptr @CBArrays.cb, align 4
 
 RWBuffer<float> Buf;
 
 [numthreads(4,1,1)]
 void main() {
-  //Buf[0] = a1 + b1.z + c1[2] + a.f1.y;
-  Buf[0] = a.f1.y;
+  Buf[0] = a1 + b1.z + c1[2] + a.f1.y + f1;
 }
 
 // CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
@@ -165,10 +181,6 @@ void main() {
 
 // CHECK: !hlsl.cbs = !{![[CBSCALARS:[0-9]+]], ![[CBVECTORS:[0-9]+]], ![[CBARRAYS:[0-9]+]], ![[CBSTRUCTS:[0-9]+]], ![[CBMIX:[0-9]+]]}
 
-// CHECK: !hlsl.cblayouts = !{![[CBSCALARS_LAYOUT:[0-9]+]], ![[CBVECTORS_LAYOUT:[0-9]+]], ![[CBARRAYS_LAYOUT:[0-9]+]], ![[A_LAYOUT:[0-9]+]],
-// CHECK-SAME: ![[B_LAYOUT:[0-9]+]], ![[C_LAYOUT:[0-9]+]], ![[D_LAYOUT:[0-9]+]], ![[CBSTRUCTS_LAYOUT:[0-9]+]], ![[TEST_LAYOUT:[0-9]+]],
-// CHECK-SAME: ![[ANON_LAYOUT:[0-9]+]], ![[CBMIX_LAYOUT:[0-9]+]]}
-
 // CHECK: ![[CBSCALARS]] = !{ptr @CBScalars.cb, ptr addrspace(2) @a1, ptr addrspace(2) @a2, ptr addrspace(2) @a3, ptr addrspace(2) @a4,
 // CHECK-SAME: ptr addrspace(2) @a5, ptr addrspace(2) @a6, ptr addrspace(2) @a7, ptr addrspace(2) @a8}
 
@@ -179,21 +191,7 @@ void main() {
 // CHECK-SAME: ptr addrspace(2) @c5, ptr addrspace(2) @c6, ptr addrspace(2) @c7, ptr addrspace(2) @c8}
 
 // CHECK: ![[CBSTRUCTS]] = !{ptr @CBStructs.cb, ptr addrspace(2) @a, ptr addrspace(2) @b, ptr addrspace(2) @c, ptr addrspace(2) @array_of_A, 
-// CHECK-SAME: ptr addrspace(2) @d, ptr addrspace(2) @e, ptr addrspace(2) @f, ptr addrspace(2) @g}
+// CHECK-SAME: ptr addrspace(2) @d, ptr addrspace(2) @e, ptr addrspace(2) @f}
 
 // CHECK: ![[CBMIX]] = !{ptr @CBMix.cb, ptr addrspace(2) @test, ptr addrspace(2) @f1, ptr addrspace(2) @f2, ptr addrspace(2) @f3,
-// CHECK-SAME: ptr addrspace(2) @s, ptr addrspace(2) @dd, ptr addrspace(2) @f4, ptr addrspace(2) @dv, ptr addrspace(2) @uv}
-
-// CHECK: ![[CBSCALARS_LAYOUT]] = !{!"struct.__cblayout_CBScalars", i32 56, i32 0, i32 8, i32 16, i32 24, i32 32, i32 36, i32 40, i32 48}
-// CHECK: ![[CBVECTORS_LAYOUT]] = !{!"struct.__cblayout_CBVectors", i32 136, i32 0, i32 16, i32 40, i32 48, i32 80, i32 96, i32 112}
-                                  
-// CHECK: ![[CBARRAYS_LAYOUT]] = !{!"struct.__cblayout_CBArrays", i32 708, i32 0, i32 48, i32 112, i32 176, i32 224, i32 608, i32 624, i32 656}
-
-// CHECK: ![[A_LAYOUT]] = !{!"struct.A", i32 8, i32 0}
-// CHECK: ![[B_LAYOUT]] = !{!"struct.B", i32 14, i32 0, i32 8}
-// CHECK: ![[C_LAYOUT]] = !{!"struct.C", i32 24, i32 0, i32 16}
-// CHECK: ![[D_LAYOUT]] = !{!"struct.__cblayout_D", i32 94, i32 0}
-// CHECK: ![[CBSTRUCTS_LAYOUT]] = !{!"struct.__cblayout_CBStructs", i32 262, i32 0, i32 16, i32 32, i32 64, i32 144, i32 238, i32 240, i32 256}
-// CHECK: ![[TEST_LAYOUT]] = !{!"struct.Test", i32 8, i32 0, i32 4}
-// CHECK: ![[ANON_LAYOUT]] = !{!"struct.anon", i32 4, i32 0}
-// CHECK: ![[CBMIX_LAYOUT]] = !{!"struct.__cblayout_CBMix", i32 162, i32 0, i32 24, i32 32, i32 120, i32 128, i32 136, i32 144, i32 152, i32 160}
+// CHECK-SAME: ptr addrspace(2) @f4, ptr addrspace(2) @f5, ptr addrspace(2) @f6, ptr addrspace(2) @f7, ptr addrspace(2) @f8, ptr addrspace(2) @f9}
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
index aa5659af414ef..393ca3825c638 100644
--- a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
@@ -4,20 +4,20 @@
 
 // Make sure cbuffer inside namespace works.
 
-// CHECK: %"struct.n0::n1::__cblayout_A" = type { float }
-// CHECK: %"struct.n0::__cblayout_B" = type { float }
-// CHECK: %"struct.n0::n2::__cblayout_C" = type { float, %"struct.n0::Foo" }
-// CHECK: %"struct.n0::Foo" = type { float }
+// CHECK: %"n0::n1::__cblayout_A" = type <{ float }>
+// CHECK: %"n0::__cblayout_B" = type <{ float }>
+// CHECK: %"n0::n2::__cblayout_C" = type <{ float, target("dx.Layout", %"n0::Foo", 4, 0) }>
+// CHECK: %"n0::Foo" = type <{ float }>
 
-// CHECK: @A.cb = external constant target("dx.CBuffer", %"struct.n0::n1::__cblayout_A")
+// CHECK: @A.cb = external constant target("dx.CBuffer", target("dx.Layout", %"n0::n1::__cblayout_A", 4, 0))
 // CHECK: @_ZN2n02n11aE = external addrspace(2) global float, align 4
 
-// CHECK: @B.cb = external constant target("dx.CBuffer", %"struct.n0::__cblayout_B")
+// CHECK: @B.cb = external constant target("dx.CBuffer", target("dx.Layout", %"n0::__cblayout_B", 4, 0))
 // CHECK: @_ZN2n01aE = external addrspace(2) global float, align 4
 
-// CHECK: @C.cb = external constant target("dx.CBuffer", %"struct.n0::n2::__cblayout_C")
+// CHECK: @C.cb = external constant target("dx.CBuffer", target("dx.Layout", %"n0::n2::__cblayout_C", 20, 0, 16))
 // CHECK: @_ZN2n02n21aE = external addrspace(2) global float, align 4
-// CHECK: @_ZN2n02n21bE = external addrspace(2) global %"struct.n0::Foo", align 4
+// CHECK: external addrspace(2) global target("dx.Layout", %"n0::Foo", 4, 0), align 4
 
 namespace n0 {
   struct Foo {
@@ -51,13 +51,6 @@ float foo() {
 void main() {}
 
 // CHECK: !hlsl.cbs = !{![[A:[0-9]+]], ![[B:[0-9]+]], ![[C:[0-9]+]]}
-// CHECK: !hlsl.cblayouts = !{![[A_LAYOUT:[0-9]+]], ![[B_LAYOUT:[0-9]+]], ![[FOO_LAYOUT:[0-9]+]], ![[C_LAYOUT:[0-9]+]]}
-
 // CHECK: [[A]] = !{ptr @A.cb, ptr addrspace(2) @_ZN2n02n11aE}
 // CHECK: [[B]] = !{ptr @B.cb, ptr addrspace(2) @_ZN2n01aE}
 // CHECK: [[C]] = !{ptr @C.cb, ptr addrspace(2) @_ZN2n02n21aE, ptr addrspace(2) @_ZN2n02n21bE}
-
-// CHECK: ![[A_LAYOUT]] = !{!"struct.n0::n1::__cblayout_A", i32 4, i32 0}
-// CHECK: ![[B_LAYOUT]] = !{!"struct.n0::__cblayout_B", i32 4, i32 0}
-// CHECK: ![[FOO_LAYOUT]] = !{!"struct.n0::Foo", i32 4, i32 0}
-// CHECK: ![[C_LAYOUT]] = !{!"struct.n0::n2::__cblayout_C", i32 20, i32 0, i32 16}
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll
new file mode 100644
index 0000000000000..faa1931222ade
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll
@@ -0,0 +1,49 @@
+; ModuleID = 'C:\llvm-project\clang\test\CodeGenHLSL\cbuffer_and_namespaces.hlsl'
+source_filename = "C:\\llvm-project\\clang\\test\\CodeGenHLSL\\cbuffer_and_namespaces.hlsl"
+target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64"
+target triple = "dxilv1.3-pc-shadermodel6.3-library"
+
+%__cblayout_A = type <{ float }>
+%__cblayout_B = type <{ float }>
+%__cblayout_C = type <{ float, target("dx.Layout", %Foo, 4, 0) }>
+%Foo = type <{ float }>
+
+ at A.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_A, 4, 0))
+ at _ZN2n02n11aE = external addrspace(2) global float, align 4
+ at B.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_B, 4, 0))
+ at _ZN2n01aE = external addrspace(2) global float, align 4
+ at C.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_C, 20, 0, 16))
+ at _ZN2n02n21aE = external addrspace(2) global float, align 4
+ at _ZN2n02n21bE = external addrspace(2) global target("dx.Layout", %Foo, 4, 0), align 4
+
+; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind
+define noundef nofpclass(nan inf) float @_Z3foov() #0 {
+entry:
+  %0 = load float, ptr addrspace(2) @_ZN2n02n11aE, align 4
+  %1 = load float, ptr addrspace(2) @_ZN2n01aE, align 4
+  %add = fadd reassoc nnan ninf nsz arcp afn float %0, %1
+  %2 = load float, ptr addrspace(2) @_ZN2n02n21aE, align 4
+  %add1 = fadd reassoc nnan ninf nsz arcp afn float %add, %2
+  ret float %add1
+}
+
+; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind
+define void @_Z4mainv() #0 {
+entry:
+  ret void
+}
+
+attributes #0 = { alwaysinline convergent mustprogress norecurse nounwind "approx-func-fp-math"="true" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+
+!hlsl.cbs = !{!0, !1, !2}
+!llvm.module.flags = !{!3, !4}
+!dx.valver = !{!5}
+!llvm.ident = !{!6}
+
+!0 = !{ptr @A.cb, ptr addrspace(2) @_ZN2n02n11aE}
+!1 = !{ptr @B.cb, ptr addrspace(2) @_ZN2n01aE}
+!2 = !{ptr @C.cb, ptr addrspace(2) @_ZN2n02n21aE, ptr addrspace(2) @_ZN2n02n21bE}
+!3 = !{i32 1, !"wchar_size", i32 4}
+!4 = !{i32 4, !"dx.disable_optimizations", i32 1}
+!5 = !{i32 1, i32 8}
+!6 = !{!"clang version 20.0.0git (C:/llvm-project/clang a8cdd4536867465e3d6e2b4ad8c49b27ee94dec8)"}
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
index f5b5cba6197b3..870593986a976 100644
--- a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
@@ -2,9 +2,9 @@
 // RUN:   dxil-pc-shadermodel6.3-compute %s \
 // RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
 
-// CHECK: %struct.__cblayout_CB = type <{ float, double, <2 x i32> }>
+// CHECK: %__cblayout_CB = type <{ float, double, <2 x i32> }>
 
-// CHECK: @CB.cb = external constant target("dx.CBuffer", %struct.__cblayout_CB)
+// CHECK: @CB.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 176, 16, 168, 88))
 // CHECK: @a = external addrspace(2) global float, align 4
 // CHECK: @b = external addrspace(2) global double, align 8
 // CHECK: @c = external addrspace(2) global <2 x i32>, align 8
@@ -17,7 +17,8 @@ cbuffer CB : register(b1, space3) {
 
 // CHECK: define internal void @_init_resource_CB.cb()
 // CHECK-NEXT: entry:
-// CHECK-NEXT: %CB.cb_h = call target("dx.CBuffer", %struct.__cblayout_CB) @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBst(i32 3, i32 1, i32 1, i32 0, i1 false)
+// CHECK-NEXT: %CB.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 176, 16, 168, 88))
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBs_176_16_168_88tt(i32 3, i32 1, i32 1, i32 0, i1 false)
 
 float foo() {
   // CHECK: load float, ptr addrspace(2) @a, align 4
@@ -34,7 +35,4 @@ void main() {
 }
 
 // CHECK: !hlsl.cbs = !{![[CB:[0-9]+]]}
-// CHECK: !hlsl.cblayouts = !{![[CB_LAYOUT:[0-9]+]]}
-
 // CHECK: ![[CB]] = !{ptr @CB.cb, ptr addrspace(2) @a, ptr addrspace(2) @b, ptr addrspace(2) @c}
-// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_CB", i32 176, i32 16, i32 168, i32 88}
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 8994640d5b311..99f40d8fc93d7 100644
--- a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
@@ -1,9 +1,9 @@
 // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
 // RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
 
-// CHECK: %struct.__cblayout_A = type { float }
+// CHECK: %__cblayout_A = type <{ float }>
 
-// CHECK: @A.cb = external constant target("dx.CBuffer", %struct.__cblayout_A)
+// CHECK: @A.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_A, 4, 0))
 // CHECK: @a = external addrspace(2) global float, align 4
 // CHECK-DAG: @_ZL1b = internal global float 3.000000e+00, align 4
 // CHECK-NOT: @B.cb
@@ -26,7 +26,4 @@ extern float bar() {
 }
 
 // CHECK: !hlsl.cbs = !{![[CB:[0-9]+]]}
-// CHECK: !hlsl.cblayouts = !{![[CB_LAYOUT:[0-9]+]]}
-
 // CHECK: ![[CB]] = !{ptr @A.cb, ptr addrspace(2) @a}
-// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_A", i32 4, i32 0}

>From 62094b2c5c754d4d077cbd2925950914e7c1c4af Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Fri, 14 Feb 2025 18:31:31 -0800
Subject: [PATCH 13/19] code review feedback - add named constant, rename
 function, remove file

---
 clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp  | 11 +++--
 .../CodeGenHLSL/cbuffer_and_namespaces.ll     | 49 -------------------
 2 files changed, 6 insertions(+), 54 deletions(-)
 delete mode 100644 clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll

diff --git a/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp b/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
index e0e7f6daddcfa..e634e47853d35 100644
--- a/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
+++ b/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
@@ -31,7 +31,7 @@ createArrayWithNewElementType(CodeGenModule &CGM,
 }
 
 // Returns the size of a scalar or vector in bytes/
-static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
+static unsigned getScalarOrVectorSizeInBytes(llvm::Type *Ty) {
   assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
   if (Ty->isVectorTy()) {
     llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
@@ -65,6 +65,7 @@ llvm::Type *CommonHLSLTargetCodeGenInfo::createHLSLBufferLayoutType(
   SmallVector<llvm::Type *> LayoutElements;
   unsigned Index = 0; // packoffset index
   unsigned EndOffset = 0;
+  const unsigned BufferRowAlign = 16U;
 
   // reserve first spot in the layout vector for buffer size
   Layout.push_back(0);
@@ -94,7 +95,7 @@ llvm::Type *CommonHLSLTargetCodeGenInfo::createHLSLBufferLayoutType(
       unsigned ElemOffset = 0;
       unsigned ArrayCount = 1;
       unsigned ArrayStride = 0;
-      unsigned NextRowOffset = llvm::alignTo(EndOffset, 16U);
+      unsigned NextRowOffset = llvm::alignTo(EndOffset, BufferRowAlign);
       llvm::Type *ElemLayoutTy = nullptr;
 
       QualType FieldTy = FD->getType();
@@ -120,11 +121,11 @@ llvm::Type *CommonHLSLTargetCodeGenInfo::createHLSLBufferLayoutType(
               CGM, cast<ConstantArrayType>(FieldTy.getTypePtr()), NewTy);
         } else {
           // Array of vectors or scalars
-          ElemSize =
-              getScalarOrVectorSize(CGM.getTypes().ConvertTypeForMem(Ty));
+          ElemSize = getScalarOrVectorSizeInBytes(
+              CGM.getTypes().ConvertTypeForMem(Ty));
           ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
         }
-        ArrayStride = llvm::alignTo(ElemSize, 16U);
+        ArrayStride = llvm::alignTo(ElemSize, BufferRowAlign);
         ElemOffset =
             Packoffsets != nullptr ? (*Packoffsets)[Index] : NextRowOffset;
 
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll
deleted file mode 100644
index faa1931222ade..0000000000000
--- a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll
+++ /dev/null
@@ -1,49 +0,0 @@
-; ModuleID = 'C:\llvm-project\clang\test\CodeGenHLSL\cbuffer_and_namespaces.hlsl'
-source_filename = "C:\\llvm-project\\clang\\test\\CodeGenHLSL\\cbuffer_and_namespaces.hlsl"
-target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64"
-target triple = "dxilv1.3-pc-shadermodel6.3-library"
-
-%__cblayout_A = type <{ float }>
-%__cblayout_B = type <{ float }>
-%__cblayout_C = type <{ float, target("dx.Layout", %Foo, 4, 0) }>
-%Foo = type <{ float }>
-
- at A.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_A, 4, 0))
- at _ZN2n02n11aE = external addrspace(2) global float, align 4
- at B.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_B, 4, 0))
- at _ZN2n01aE = external addrspace(2) global float, align 4
- at C.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_C, 20, 0, 16))
- at _ZN2n02n21aE = external addrspace(2) global float, align 4
- at _ZN2n02n21bE = external addrspace(2) global target("dx.Layout", %Foo, 4, 0), align 4
-
-; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind
-define noundef nofpclass(nan inf) float @_Z3foov() #0 {
-entry:
-  %0 = load float, ptr addrspace(2) @_ZN2n02n11aE, align 4
-  %1 = load float, ptr addrspace(2) @_ZN2n01aE, align 4
-  %add = fadd reassoc nnan ninf nsz arcp afn float %0, %1
-  %2 = load float, ptr addrspace(2) @_ZN2n02n21aE, align 4
-  %add1 = fadd reassoc nnan ninf nsz arcp afn float %add, %2
-  ret float %add1
-}
-
-; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind
-define void @_Z4mainv() #0 {
-entry:
-  ret void
-}
-
-attributes #0 = { alwaysinline convergent mustprogress norecurse nounwind "approx-func-fp-math"="true" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
-
-!hlsl.cbs = !{!0, !1, !2}
-!llvm.module.flags = !{!3, !4}
-!dx.valver = !{!5}
-!llvm.ident = !{!6}
-
-!0 = !{ptr @A.cb, ptr addrspace(2) @_ZN2n02n11aE}
-!1 = !{ptr @B.cb, ptr addrspace(2) @_ZN2n01aE}
-!2 = !{ptr @C.cb, ptr addrspace(2) @_ZN2n02n21aE, ptr addrspace(2) @_ZN2n02n21bE}
-!3 = !{i32 1, !"wchar_size", i32 4}
-!4 = !{i32 4, !"dx.disable_optimizations", i32 1}
-!5 = !{i32 1, i32 8}
-!6 = !{!"clang version 20.0.0git (C:/llvm-project/clang a8cdd4536867465e3d6e2b4ad8c49b27ee94dec8)"}

>From 43aedd4ac16a5cd9782ebc63f7e56bc739f81df8 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Fri, 14 Feb 2025 19:12:40 -0800
Subject: [PATCH 14/19] fix test after merge

---
 clang/test/CodeGenHLSL/default_cbuffer.hlsl | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/clang/test/CodeGenHLSL/default_cbuffer.hlsl b/clang/test/CodeGenHLSL/default_cbuffer.hlsl
index 7368997b51ac9..8f89606fdd04f 100644
--- a/clang/test/CodeGenHLSL/default_cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/default_cbuffer.hlsl
@@ -1,13 +1,13 @@
 // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute \
 // RUN:   -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
 
-// CHECK: %"struct.__cblayout_$Globals" = type { float, float, %struct.__cblayout_S }
-// CHECK: %struct.__cblayout_S = type { float }
+// CHECK: %"__cblayout_$Globals" = type <{ float, float, target("dx.Layout", %__cblayout_S, 4, 0) }>
+// CHECK: %__cblayout_S = type <{ float }>
 
-// CHECK-DAG: @"$Globals.cb" = external constant target("dx.CBuffer", %"struct.__cblayout_$Globals")
+// CHECK-DAG: @"$Globals.cb" = external constant target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 20, 0, 4, 16))
 // CHECK-DAG: @a = external addrspace(2) global float
 // CHECK-DAG: @g = external addrspace(2) global float
-// CHECK-DAG: @h = external addrspace(2) global %struct.__cblayout_S
+// CHECK-DAG: @h = external addrspace(2) global target("dx.Layout", %__cblayout_S, 4, 0), align 4
 
 struct EmptyStruct {
 };
@@ -35,9 +35,5 @@ void main() {
   Buf[0] = a;
 }
 
-// CHECK: !hlsl.cblayouts = !{![[S_LAYOUT:.*]], ![[CB_LAYOUT:.*]]}
 // CHECK: !hlsl.cbs = !{![[CB:.*]]}
-
-// CHECK: ![[S_LAYOUT]] = !{!"struct.__cblayout_S", i32 4, i32 0}
-// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_$Globals", i32 20, i32 0, i32 4, i32 16}
 // CHECK: ![[CB]] = !{ptr @"$Globals.cb", ptr addrspace(2) @a, ptr addrspace(2) @g, ptr addrspace(2) @h}
\ No newline at end of file

>From a90b3a1166eb58395a3dd799d6ee078709bc5c69 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 18 Feb 2025 12:45:48 -0800
Subject: [PATCH 15/19] code review feedback - update comment, add new line

---
 clang/include/clang/AST/Decl.h              | 12 ++++++++++--
 clang/lib/CodeGen/CGHLSLRuntime.cpp         |  1 +
 clang/test/CodeGenHLSL/default_cbuffer.hlsl |  2 +-
 3 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 0dd4ca8cfd38b..86e6d1417ae79 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -5087,8 +5087,16 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
     return static_cast<HLSLBufferDecl *>(const_cast<DeclContext *>(DC));
   }
 
-  // Iterator for the buffer decls. Concatenates the list of decls parented
-  // by this HLSLBufferDecl with the list of default buffer decls.
+  // Iterator for the buffer decls. For constant buffers explicitly declared
+  // with `cbuffer` keyword this will the list of decls parented by this
+  // HLSLBufferDecl (equal to `decls()`).
+  // For implicit $Globals buffer this will be the list of default buffer
+  // declarations stored in DefaultBufferDecls plus the implicit layout
+  // struct (the only child of HLSLBufferDecl in this case).
+  //
+  // The iterator uses llvm::concat_iterator to concatenate the lists
+  // `decls()` and `DefaultBufferDecls`. For non-default buffers
+  // `DefaultBufferDecls` is always empty.
   using buffer_decl_iterator =
       llvm::concat_iterator<Decl *const, SmallVector<Decl *>::const_iterator,
                             decl_iterator>;
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 80ef24d54f128..32cdcbb705ee6 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -150,6 +150,7 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
     llvm::Type *LayoutType = *ElemIt++;
 
     // FIXME: handle resources in cbuffer user-defined structs
+    // Issue llvm/wg-hlsl#175
 
     // create global variable for the constant and to metadata list
     GlobalVariable *ElemGV =
diff --git a/clang/test/CodeGenHLSL/default_cbuffer.hlsl b/clang/test/CodeGenHLSL/default_cbuffer.hlsl
index 8f89606fdd04f..c5176aa8466e4 100644
--- a/clang/test/CodeGenHLSL/default_cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/default_cbuffer.hlsl
@@ -36,4 +36,4 @@ void main() {
 }
 
 // CHECK: !hlsl.cbs = !{![[CB:.*]]}
-// CHECK: ![[CB]] = !{ptr @"$Globals.cb", ptr addrspace(2) @a, ptr addrspace(2) @g, ptr addrspace(2) @h}
\ No newline at end of file
+// CHECK: ![[CB]] = !{ptr @"$Globals.cb", ptr addrspace(2) @a, ptr addrspace(2) @g, ptr addrspace(2) @h}

>From eaeaf2a76d78a1070a733e0692654d059c41a4ea Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 19 Feb 2025 11:13:08 -0800
Subject: [PATCH 16/19] code review feedback - minor changes

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 31da7432b3145..3f1ccce9c6271 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -103,12 +103,8 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
 
   // 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));
 
@@ -139,9 +135,13 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
         // Emit static and groupshared variables and resource classes inside
         // cbuffer as regular globals
         CGM.EmitGlobal(VD);
+      } else {
+        // 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
+        assert(BufDecl->getASTContext().getTypeSize(VDTy) == 0 &&
+               "constant buffer decl with non-zero sized type outside of "
+               "hlsl_constant address space");
       }
-      // 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;
     }
 
@@ -149,10 +149,8 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
            "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");
+    // FIXME: handle resources inside user defined structs
+    // (llvm/wg-hlsl#175)
 
     // create global variable for the constant and to metadata list
     GlobalVariable *ElemGV =
@@ -161,7 +159,6 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
   }
   assert(ElemIt == LayoutStruct->element_end() &&
          "number of elements in layout struct does not match");
-  // set the size of the buffer
 
   // add buffer metadata to the module
   CGM.getModule()
@@ -235,6 +232,7 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
   const HLSLResourceBindingAttr *RBA =
       BufDecl->getAttr<HLSLResourceBindingAttr>();
   // FIXME: handle implicit binding if no binding attribute is found
+  // (llvm/llvm-project#110722)
   if (RBA)
     createResourceInitFn(CGM, BufGV, RBA->getSlotNumber(),
                          RBA->getSpaceNumber());

>From d3c887280943d8d3ac5184088bcc39f8a5e42dce Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 19 Feb 2025 14:14:13 -0800
Subject: [PATCH 17/19] code review feedback - move layout calculations into a
 separate builder class instead of target info

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp           |   4 +-
 clang/lib/CodeGen/CGHLSLRuntime.h             |   7 +-
 clang/lib/CodeGen/CMakeLists.txt              |  20 +-
 clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp | 229 ++++++++++++++++++
 clang/lib/CodeGen/HLSLBufferLayoutBuilder.h   |  48 ++++
 clang/lib/CodeGen/Targets/DirectX.cpp         |  22 +-
 clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp  | 202 ---------------
 clang/lib/CodeGen/Targets/HLSLTargetInfo.h    |  39 ---
 clang/lib/CodeGen/Targets/SPIR.cpp            |   7 +-
 9 files changed, 303 insertions(+), 275 deletions(-)
 create mode 100644 clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
 create mode 100644 clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
 delete mode 100644 clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
 delete mode 100644 clang/lib/CodeGen/Targets/HLSLTargetInfo.h

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index b9ded3d3700db..4aa5a7ead14a2 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -240,7 +240,7 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
                          RBA->getSpaceNumber());
 }
 
-llvm::Type *
+llvm::TargetExtType *
 CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
   const auto Entry = LayoutTypes.find(StructType);
   if (Entry != LayoutTypes.end())
@@ -249,7 +249,7 @@ CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
 }
 
 void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
-                                            llvm::Type *LayoutTy) {
+                                            llvm::TargetExtType *LayoutTy) {
   assert(getHLSLBufferLayoutType(StructType) == nullptr &&
          "layout type for this struct already exist");
   LayoutTypes[StructType] = LayoutTy;
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 0f346410eccd4..a9da42324a038 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -162,9 +162,10 @@ class CGHLSLRuntime {
 
   llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);
 
-  llvm::Type *getHLSLBufferLayoutType(const RecordType *LayoutStructTy);
+  llvm::TargetExtType *
+  getHLSLBufferLayoutType(const RecordType *LayoutStructTy);
   void addHLSLBufferLayoutType(const RecordType *LayoutStructTy,
-                               llvm::Type *LayoutTy);
+                               llvm::TargetExtType *LayoutTy);
   void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E);
 
 private:
@@ -177,7 +178,7 @@ class CGHLSLRuntime {
                                     llvm::GlobalVariable *BufGV);
   llvm::Triple::ArchType getArch();
 
-  llvm::DenseMap<const clang::RecordType *, llvm::Type *> LayoutTypes;
+  llvm::DenseMap<const clang::RecordType *, llvm::TargetExtType *> LayoutTypes;
 };
 
 } // namespace CodeGen
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index 1a6b25883d9c8..0f3a106cea1b9 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -31,25 +31,26 @@ set(LLVM_LINK_COMPONENTS
   Target
   TargetParser
   TransformUtils
-  )
+)
 
 # Workaround for MSVC ARM64 performance regression:
 # https://developercommunity.visualstudio.com/t/Compiling-a-specific-code-for-ARM64-with/10444970
 # Since /O1 and /O2 represent a set of optimizations,
 # our goal is to disable the /Og flag while retaining the other optimizations from the /O1|/O2 set
 if(MSVC AND NOT CMAKE_CXX_COMPILER_ID MATCHES Clang
-    AND MSVC_VERSION VERSION_GREATER_EQUAL 1932
-    AND MSVC_VERSION VERSION_LESS 1939
-    AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
-
+  AND MSVC_VERSION VERSION_GREATER_EQUAL 1932
+  AND MSVC_VERSION VERSION_LESS 1939
+  AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
   string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
   string(REGEX MATCHALL "/[Oo][12]" opt_flags "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}")
-  if (opt_flags)
+
+  if(opt_flags)
     if(opt_flags MATCHES "1$")
       set(opt_flags "/Od;/Os;/Oy;/Ob2;/GF;/Gy")
-    elseif (opt_flags MATCHES "2$")
+    elseif(opt_flags MATCHES "2$")
       set(opt_flags "/Od;/Oi;/Ot;/Oy;/Ob2;/GF;/Gy")
     endif()
+
     set_source_files_properties(CGBuiltin.cpp PROPERTIES COMPILE_OPTIONS "${opt_flags}")
   endif()
 endif()
@@ -106,6 +107,7 @@ add_clang_library(clangCodeGen
   ConstantInitBuilder.cpp
   CoverageMappingGen.cpp
   ItaniumCXXABI.cpp
+  HLSLBufferLayoutBuilder.cpp
   LinkInModulesPass.cpp
   MacroPPCallbacks.cpp
   MicrosoftCXXABI.cpp
@@ -124,7 +126,6 @@ add_clang_library(clangCodeGen
   Targets/CSKY.cpp
   Targets/DirectX.cpp
   Targets/Hexagon.cpp
-  Targets/HLSLTargetInfo.cpp
   Targets/Lanai.cpp
   Targets/LoongArch.cpp
   Targets/M68k.cpp
@@ -148,6 +149,7 @@ add_clang_library(clangCodeGen
   vt_gen
   intrinsics_gen
   ClangDriverOptions
+
   # These generated headers are included transitively.
   ARMTargetParserTableGen
   AArch64TargetParserTableGen
@@ -159,4 +161,4 @@ add_clang_library(clangCodeGen
   clangFrontend
   clangLex
   clangSerialization
-  )
+)
diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
new file mode 100644
index 0000000000000..1ae00023ab2bc
--- /dev/null
+++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
@@ -0,0 +1,229 @@
+//===- HLSLBufferLayoutBuilder.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "HLSLBufferLayoutBuilder.h"
+#include "CGHLSLRuntime.h"
+#include "CodeGenModule.h"
+#include "clang/AST/Type.h"
+
+//===----------------------------------------------------------------------===//
+// Implementation of constant buffer layout common between DirectX and
+// SPIR/SPIR-V.
+//===----------------------------------------------------------------------===//
+
+using namespace clang;
+using namespace clang::CodeGen;
+
+namespace {
+
+// Creates a new array type with the same dimentions but with the new
+// element type.
+static llvm::Type *
+createArrayWithNewElementType(CodeGenModule &CGM,
+                              const ConstantArrayType *ArrayType,
+                              llvm::Type *NewElemType) {
+  const clang::Type *ArrayElemType = ArrayType->getArrayElementTypeNoTypeQual();
+  if (ArrayElemType->isConstantArrayType())
+    NewElemType = createArrayWithNewElementType(
+        CGM, cast<const ConstantArrayType>(ArrayElemType), NewElemType);
+  return llvm::ArrayType::get(NewElemType, ArrayType->getSExtSize());
+}
+
+// Returns the size of a scalar or vector in bytes
+static unsigned getScalarOrVectorSizeInBytes(llvm::Type *Ty) {
+  assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
+  if (Ty->isVectorTy()) {
+    llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
+    return FVT->getNumElements() *
+           (FVT->getElementType()->getScalarSizeInBits() / 8);
+  }
+  return Ty->getScalarSizeInBits() / 8;
+}
+
+} // namespace
+
+namespace clang {
+namespace CodeGen {
+
+// Creates a layout type for given struct with HLSL constant buffer layout
+// taking into account Packoffsets, if provided.
+// Previously created layout types are cached by CGHLSLRuntime.
+//
+// The function iterates over all fields of the StructType (including base
+// classes) and calls layoutField to converts each field to its corresponding
+// LLVM type and to calculate its HLSL constant buffer layout. Any embedded
+// structs (or arrays of structs) are converted to target layout types as well.
+llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType(
+    const RecordType *StructType,
+    const llvm::SmallVector<unsigned> *Packoffsets) {
+
+  // check if we already have the layout type for this struct
+  if (llvm::TargetExtType *Ty =
+          CGM.getHLSLRuntime().getHLSLBufferLayoutType(StructType))
+    return Ty;
+
+  SmallVector<unsigned> Layout;
+  SmallVector<llvm::Type *> LayoutElements;
+  unsigned Index = 0; // packoffset index
+  unsigned EndOffset = 0;
+
+  // reserve first spot in the layout vector for buffer size
+  Layout.push_back(0);
+
+  // iterate over all fields of the record, including fields on base classes
+  llvm::SmallVector<const RecordType *> RecordTypes;
+  RecordTypes.push_back(StructType);
+  while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
+    CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
+    assert(D->getNumBases() == 1 &&
+           "HLSL doesn't support multiple inheritance");
+    RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
+  }
+  while (!RecordTypes.empty()) {
+    const RecordType *RT = RecordTypes.back();
+    RecordTypes.pop_back();
+
+    for (const auto *FD : RT->getDecl()->fields()) {
+      assert(!Packoffsets || Index < Packoffsets->size() &&
+                                 "number of elements in layout struct does not "
+                                 "match number of packoffset annotations");
+
+      if (!layoutField(FD, EndOffset, Layout, LayoutElements,
+                       Packoffsets ? (*Packoffsets)[Index] : -1))
+        return nullptr;
+      Index++;
+    }
+  }
+
+  // set the size of the buffer
+  Layout[0] = EndOffset;
+
+  // create the layout struct type; anonymous struct have empty name but
+  // non-empty qualified name
+  const CXXRecordDecl *Decl = StructType->getAsCXXRecordDecl();
+  std::string Name =
+      Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString();
+  llvm::StructType *StructTy =
+      llvm::StructType::create(LayoutElements, Name, true);
+
+  // create target layout type
+  llvm::TargetExtType *NewLayoutTy = llvm::TargetExtType::get(
+      CGM.getLLVMContext(), LayoutTypeName, {StructTy}, Layout);
+  if (NewLayoutTy)
+    CGM.getHLSLRuntime().addHLSLBufferLayoutType(StructType, NewLayoutTy);
+  return NewLayoutTy;
+}
+
+// The function converts a single field of HLSL Buffer to its corresponding
+// LLVM type and calculates it's layout. Any embedded structs (or
+// arrays of structs) are converted to target layout types as well.
+// The converted type is appended to the LayoutElements list, the element
+// offset is added to the Layout list and the EndOffset updated to the offset
+// just after the lay-ed out element (which is basically the size of the
+// buffer).
+// Returns true if the conversion was successful.
+// The packoffset parameter contains the field's layout offset provided by the
+// user or -1 if there was no packoffset (or register(cX)) annotation.
+bool HLSLBufferLayoutBuilder::layoutField(
+    const FieldDecl *FD, unsigned &EndOffset, SmallVector<unsigned> &Layout,
+    SmallVector<llvm::Type *> &LayoutElements, int Packoffset) {
+
+  // Size of element; for arrays this is a size of a single element in the
+  // array. Total array size of calculated as (ArrayCount-1) * ArrayStride +
+  // ElemSize.
+  unsigned ElemSize = 0;
+  unsigned ElemOffset = 0;
+  unsigned ArrayCount = 1;
+  unsigned ArrayStride = 0;
+
+  const unsigned BufferRowAlign = 16U;
+  unsigned NextRowOffset = llvm::alignTo(EndOffset, BufferRowAlign);
+
+  llvm::Type *ElemLayoutTy = nullptr;
+  QualType FieldTy = FD->getType();
+
+  if (FieldTy->isConstantArrayType()) {
+    // Unwrap array to find the element type and get combined array size.
+    QualType Ty = FieldTy;
+    while (Ty->isConstantArrayType()) {
+      const ConstantArrayType *ArrayTy = cast<ConstantArrayType>(Ty);
+      ArrayCount *= ArrayTy->getSExtSize();
+      Ty = ArrayTy->getElementType();
+    }
+    // For array of structures, create a new array with a layout type
+    // instead of the structure type.
+    if (Ty->isStructureType()) {
+      llvm::Type *NewTy =
+          cast<llvm::TargetExtType>(createLayoutType(Ty->getAsStructureType()));
+      if (!NewTy)
+        return false;
+      assert(isa<llvm::TargetExtType>(NewTy) && "expected target type");
+      ElemSize = cast<llvm::TargetExtType>(NewTy)->getIntParameter(0);
+      ElemLayoutTy = createArrayWithNewElementType(
+          CGM, cast<ConstantArrayType>(FieldTy.getTypePtr()), NewTy);
+    } else {
+      // Array of vectors or scalars
+      ElemSize =
+          getScalarOrVectorSizeInBytes(CGM.getTypes().ConvertTypeForMem(Ty));
+      ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
+    }
+    ArrayStride = llvm::alignTo(ElemSize, BufferRowAlign);
+    ElemOffset = (Packoffset != -1) ? Packoffset : NextRowOffset;
+
+  } else if (FieldTy->isStructureType()) {
+    // Create a layout type for the structure
+    ElemLayoutTy = createLayoutType(FieldTy->getAsStructureType());
+    if (!ElemLayoutTy)
+      return false;
+    assert(isa<llvm::TargetExtType>(ElemLayoutTy) && "expected target type");
+    ElemSize = cast<llvm::TargetExtType>(ElemLayoutTy)->getIntParameter(0);
+    ElemOffset = (Packoffset != -1) ? Packoffset : NextRowOffset;
+
+  } else {
+    // scalar or vector - find element size and alignment
+    unsigned Align = 0;
+    ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
+    if (ElemLayoutTy->isVectorTy()) {
+      // align vectors by sub element size
+      const llvm::FixedVectorType *FVT =
+          cast<llvm::FixedVectorType>(ElemLayoutTy);
+      unsigned SubElemSize = FVT->getElementType()->getScalarSizeInBits() / 8;
+      ElemSize = FVT->getNumElements() * SubElemSize;
+      Align = SubElemSize;
+    } else {
+      assert(ElemLayoutTy->isIntegerTy() || ElemLayoutTy->isFloatingPointTy());
+      ElemSize = ElemLayoutTy->getScalarSizeInBits() / 8;
+      Align = ElemSize;
+    }
+
+    // calculate or get element offset for the vector or scalar
+    if (Packoffset != -1) {
+      ElemOffset = Packoffset;
+    } else {
+      ElemOffset = llvm::alignTo(EndOffset, Align);
+      // if the element does not fit, move it to the next row
+      if (ElemOffset + ElemSize > NextRowOffset)
+        ElemOffset = NextRowOffset;
+    }
+  }
+
+  // Update end offset of the layout; do not update it if the EndOffset
+  // is already bigger than the new value (which may happen with unordered
+  // packoffset annotations)
+  unsigned NewEndOffset =
+      ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
+  EndOffset = std::max<unsigned>(EndOffset, NewEndOffset);
+
+  // add the layout element and offset to the lists
+  Layout.push_back(ElemOffset);
+  LayoutElements.push_back(ElemLayoutTy);
+  return true;
+}
+
+} // namespace CodeGen
+} // namespace clang
diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
new file mode 100644
index 0000000000000..57bb17c557b9c
--- /dev/null
+++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
@@ -0,0 +1,48 @@
+//===- HLSLBufferLayoutBuilder.h ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/DerivedTypes.h"
+
+namespace clang {
+class RecordType;
+class FieldDecl;
+
+namespace CodeGen {
+class CodeGenModule;
+
+//===----------------------------------------------------------------------===//
+// Implementation of constant buffer layout common between DirectX and
+// SPIR/SPIR-V.
+//===----------------------------------------------------------------------===//
+
+class HLSLBufferLayoutBuilder {
+private:
+  CodeGenModule &CGM;
+  llvm::StringRef LayoutTypeName;
+
+public:
+  HLSLBufferLayoutBuilder(CodeGenModule &CGM, llvm::StringRef LayoutTypeName)
+      : CGM(CGM), LayoutTypeName(LayoutTypeName) {}
+
+  // Returns LLVM target extension type with the name LayoutTypeName
+  // for given structure type and layout data. The first number in
+  // the Layout is the size followed by offsets for each struct element.
+  llvm::TargetExtType *
+  createLayoutType(const RecordType *StructType,
+                   const llvm::SmallVector<unsigned> *Packoffsets = nullptr);
+
+private:
+  bool layoutField(const clang::FieldDecl *FD, unsigned &EndOffset,
+                   llvm::SmallVector<unsigned> &Layout,
+                   llvm::SmallVector<llvm::Type *> &LayoutElements,
+                   int Packoffset);
+};
+
+} // namespace CodeGen
+} // namespace clang
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 3d4b65aec0a3a..77091eb45f5cf 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -8,7 +8,7 @@
 
 #include "ABIInfoImpl.h"
 #include "CodeGenModule.h"
-#include "HLSLTargetInfo.h"
+#include "HLSLBufferLayoutBuilder.h"
 #include "TargetInfo.h"
 #include "clang/AST/Type.h"
 #include "llvm/ADT/SmallVector.h"
@@ -24,27 +24,16 @@ using namespace clang::CodeGen;
 
 namespace {
 
-class DirectXTargetCodeGenInfo : public CommonHLSLTargetCodeGenInfo {
+class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {
 public:
   DirectXTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
-      : CommonHLSLTargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
+      : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
 
   llvm::Type *getHLSLType(
       CodeGenModule &CGM, const Type *T,
       const SmallVector<unsigned> *Packoffsets = nullptr) const override;
-
-  llvm::Type *getHLSLLayoutType(CodeGenModule &CGM,
-                                llvm::StructType *LayoutStructTy,
-                                SmallVector<unsigned> Layout) const override;
 };
 
-llvm::Type *DirectXTargetCodeGenInfo::getHLSLLayoutType(
-    CodeGenModule &CGM, llvm::StructType *LayoutStructTy,
-    SmallVector<unsigned> Layout) const {
-  return llvm::TargetExtType::get(CGM.getLLVMContext(), "dx.Layout",
-                                  {LayoutStructTy}, Layout);
-}
-
 llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
     CodeGenModule &CGM, const Type *Ty,
     const SmallVector<unsigned> *Packoffsets) const {
@@ -80,8 +69,9 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
     if (ContainedTy.isNull() || !ContainedTy->isStructureType())
       return nullptr;
 
-    llvm::Type *BufferLayoutTy = this->createHLSLBufferLayoutType(
-        CGM, ContainedTy->getAsStructureType(), Packoffsets);
+    llvm::Type *BufferLayoutTy =
+        HLSLBufferLayoutBuilder(CGM, "dx.Layout")
+            .createLayoutType(ContainedTy->getAsStructureType(), Packoffsets);
     if (!BufferLayoutTy)
       return nullptr;
 
diff --git a/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp b/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
deleted file mode 100644
index e634e47853d35..0000000000000
--- a/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-//===- HLSLTargetInto.cpp--------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "HLSLTargetInfo.h"
-#include "CGHLSLRuntime.h"
-#include "TargetInfo.h"
-#include "clang/AST/DeclCXX.h"
-
-//===----------------------------------------------------------------------===//
-// Target codegen info implementation common between DirectX and SPIR/SPIR-V.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-// Creates a new array type with the same dimentions
-// but with the new element type.
-static llvm::Type *
-createArrayWithNewElementType(CodeGenModule &CGM,
-                              const ConstantArrayType *ArrayType,
-                              llvm::Type *NewElemType) {
-  const clang::Type *ArrayElemType = ArrayType->getArrayElementTypeNoTypeQual();
-  if (ArrayElemType->isConstantArrayType())
-    NewElemType = createArrayWithNewElementType(
-        CGM, cast<const ConstantArrayType>(ArrayElemType), NewElemType);
-  return llvm::ArrayType::get(NewElemType, ArrayType->getSExtSize());
-}
-
-// Returns the size of a scalar or vector in bytes/
-static unsigned getScalarOrVectorSizeInBytes(llvm::Type *Ty) {
-  assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
-  if (Ty->isVectorTy()) {
-    llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
-    return FVT->getNumElements() *
-           (FVT->getElementType()->getScalarSizeInBits() / 8);
-  }
-  return Ty->getScalarSizeInBits() / 8;
-}
-
-} // namespace
-
-// Creates a layout type for given struct with HLSL constant buffer layout
-// taking into account Packoffsets, if provided.
-// Previously created layout types are cached in CGHLSLRuntime because
-// TargetCodeGenInto info is cannot store any data
-// (CGM.getTargetCodeGenInfo() returns a const reference to TargetCondegenInfo).
-//
-// The function iterates over all fields of the StructType (including base
-// classes), converts each field to its corresponding LLVM type and calculated
-// it's HLSL constant bufffer layout (offset and size). Any embedded struct (or
-// arrays of structs) are converted to target layout types as well.
-llvm::Type *CommonHLSLTargetCodeGenInfo::createHLSLBufferLayoutType(
-    CodeGenModule &CGM, const RecordType *StructType,
-    const SmallVector<unsigned> *Packoffsets) const {
-
-  // check if we already have the layout type for this struct
-  if (llvm::Type *Ty = CGM.getHLSLRuntime().getHLSLBufferLayoutType(StructType))
-    return Ty;
-
-  SmallVector<unsigned> Layout;
-  SmallVector<llvm::Type *> LayoutElements;
-  unsigned Index = 0; // packoffset index
-  unsigned EndOffset = 0;
-  const unsigned BufferRowAlign = 16U;
-
-  // reserve first spot in the layout vector for buffer size
-  Layout.push_back(0);
-
-  // iterate over all fields of the record, including fields on base classes
-  llvm::SmallVector<const RecordType *> RecordTypes;
-  RecordTypes.push_back(StructType);
-  while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
-    CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
-    assert(D->getNumBases() == 1 &&
-           "HLSL doesn't support multiple inheritance");
-    RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
-  }
-  while (!RecordTypes.empty()) {
-    const RecordType *RT = RecordTypes.back();
-    RecordTypes.pop_back();
-
-    for (const auto *FD : RT->getDecl()->fields()) {
-      assert(!Packoffsets || Index < Packoffsets->size() &&
-                                 "number of elements in layout struct does not "
-                                 "match number of packoffset annotations");
-      // Size of element; for arrays this is a size of a single element in the
-      // array. Total array size of calculated as (ArrayCount-1) * ArrayStride +
-      // ElemSize.
-      unsigned ElemSize = 0;
-
-      unsigned ElemOffset = 0;
-      unsigned ArrayCount = 1;
-      unsigned ArrayStride = 0;
-      unsigned NextRowOffset = llvm::alignTo(EndOffset, BufferRowAlign);
-      llvm::Type *ElemLayoutTy = nullptr;
-
-      QualType FieldTy = FD->getType();
-
-      if (FieldTy->isConstantArrayType()) {
-        // Unwrap array to find the element type and get combined array size.
-        QualType Ty = FieldTy;
-        while (Ty->isConstantArrayType()) {
-          const ConstantArrayType *ArrayTy = cast<ConstantArrayType>(Ty);
-          ArrayCount *= ArrayTy->getSExtSize();
-          Ty = ArrayTy->getElementType();
-        }
-        // For array of structures, create a new array with a layout type
-        // instead of the structure type.
-        if (Ty->isStructureType()) {
-          llvm::Type *NewTy = cast<llvm::TargetExtType>(
-              createHLSLBufferLayoutType(CGM, Ty->getAsStructureType()));
-          if (!NewTy)
-            return nullptr;
-          assert(isa<llvm::TargetExtType>(NewTy) && "expected target type");
-          ElemSize = cast<llvm::TargetExtType>(NewTy)->getIntParameter(0);
-          ElemLayoutTy = createArrayWithNewElementType(
-              CGM, cast<ConstantArrayType>(FieldTy.getTypePtr()), NewTy);
-        } else {
-          // Array of vectors or scalars
-          ElemSize = getScalarOrVectorSizeInBytes(
-              CGM.getTypes().ConvertTypeForMem(Ty));
-          ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
-        }
-        ArrayStride = llvm::alignTo(ElemSize, BufferRowAlign);
-        ElemOffset =
-            Packoffsets != nullptr ? (*Packoffsets)[Index] : NextRowOffset;
-
-      } else if (FieldTy->isStructureType()) {
-        // Create a layout type for the structure
-        ElemLayoutTy =
-            createHLSLBufferLayoutType(CGM, FieldTy->getAsStructureType());
-        if (!ElemLayoutTy)
-          return nullptr;
-        assert(isa<llvm::TargetExtType>(ElemLayoutTy) &&
-               "expected target type");
-        ElemSize = cast<llvm::TargetExtType>(ElemLayoutTy)->getIntParameter(0);
-        ElemOffset =
-            Packoffsets != nullptr ? (*Packoffsets)[Index] : NextRowOffset;
-      } else {
-        // scalar or vector - find element size and alignment
-        unsigned Align = 0;
-        ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
-        if (ElemLayoutTy->isVectorTy()) {
-          // align vectors by sub element size
-          const llvm::FixedVectorType *FVT =
-              cast<llvm::FixedVectorType>(ElemLayoutTy);
-          unsigned SubElemSize =
-              FVT->getElementType()->getScalarSizeInBits() / 8;
-          ElemSize = FVT->getNumElements() * SubElemSize;
-          Align = SubElemSize;
-        } else {
-          assert(ElemLayoutTy->isIntegerTy() ||
-                 ElemLayoutTy->isFloatingPointTy());
-          ElemSize = ElemLayoutTy->getScalarSizeInBits() / 8;
-          Align = ElemSize;
-        }
-        // calculate or get element offset for the vector or scalar
-        if (Packoffsets != nullptr) {
-          ElemOffset = (*Packoffsets)[Index];
-        } else {
-          ElemOffset = llvm::alignTo(EndOffset, Align);
-          // if the element does not fit, move it to the next row
-          if (ElemOffset + ElemSize > NextRowOffset)
-            ElemOffset = NextRowOffset;
-        }
-      }
-
-      // Update end offset of the layout; do not update it if the EndOffset
-      // is already bigger than the new value (which may happen with unordered
-      // packoffset annotations)
-      unsigned NewEndOffset =
-          ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
-      EndOffset = std::max<unsigned>(EndOffset, NewEndOffset);
-
-      // add the layout element and offset to the lists
-      Layout.push_back(ElemOffset);
-      LayoutElements.push_back(ElemLayoutTy);
-      Index++;
-    }
-  }
-
-  // set the size of the buffer
-  Layout[0] = EndOffset;
-
-  // create the layout struct type; anonymous struct have empty name but
-  // non-empty qualified name
-  const CXXRecordDecl *Decl = StructType->getAsCXXRecordDecl();
-  std::string Name =
-      Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString();
-  llvm::StructType *StructTy =
-      llvm::StructType::create(LayoutElements, Name, true);
-
-  // create target layout type
-  llvm::Type *NewLayoutTy = this->getHLSLLayoutType(CGM, StructTy, Layout);
-  if (NewLayoutTy)
-    CGM.getHLSLRuntime().addHLSLBufferLayoutType(StructType, NewLayoutTy);
-  return NewLayoutTy;
-}
diff --git a/clang/lib/CodeGen/Targets/HLSLTargetInfo.h b/clang/lib/CodeGen/Targets/HLSLTargetInfo.h
deleted file mode 100644
index 279ce4fba3dad..0000000000000
--- a/clang/lib/CodeGen/Targets/HLSLTargetInfo.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//===- HLSLTargetInfo.h ---------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "ABIInfoImpl.h"
-#include "TargetInfo.h"
-
-using namespace clang;
-using namespace clang::CodeGen;
-
-//===----------------------------------------------------------------------===//
-// Target codegen info implementation common between DirectX and SPIR/SPIR-V.
-//===----------------------------------------------------------------------===//
-
-class CommonHLSLTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
-  CommonHLSLTargetCodeGenInfo(std::unique_ptr<ABIInfo> Info)
-      : TargetCodeGenInfo(std::move(Info)) {}
-
-  // Returns LLVM target extension type "dx.Layout" or "spv.Layout"
-  // for given structure type and layout data. The first number in
-  // the Layout is the size followed by offsets for each struct element.
-  virtual llvm::Type *getHLSLLayoutType(CodeGenModule &CGM,
-                                        llvm::StructType *LayoutStructTy,
-                                        SmallVector<unsigned> Layout) const {
-    return nullptr;
-  };
-
-protected:
-  // Creates a layout type for given struct with HLSL constant buffer layout
-  // taking into account Packoffsets, if provided.
-  virtual llvm::Type *createHLSLBufferLayoutType(
-      CodeGenModule &CGM, const clang::RecordType *StructType,
-      const SmallVector<unsigned> *Packoffsets = nullptr) const;
-};
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index 3cf95483dc4fa..c94db31ae1a89 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -7,7 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "ABIInfoImpl.h"
-#include "HLSLTargetInfo.h"
 #include "TargetInfo.h"
 
 using namespace clang;
@@ -39,12 +38,12 @@ class SPIRVABIInfo : public CommonSPIRABIInfo {
 };
 } // end anonymous namespace
 namespace {
-class CommonSPIRTargetCodeGenInfo : public CommonHLSLTargetCodeGenInfo {
+class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo {
 public:
   CommonSPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
-      : CommonHLSLTargetCodeGenInfo(std::make_unique<CommonSPIRABIInfo>(CGT)) {}
+      : TargetCodeGenInfo(std::make_unique<CommonSPIRABIInfo>(CGT)) {}
   CommonSPIRTargetCodeGenInfo(std::unique_ptr<ABIInfo> ABIInfo)
-      : CommonHLSLTargetCodeGenInfo(std::move(ABIInfo)) {}
+      : TargetCodeGenInfo(std::move(ABIInfo)) {}
 
   LangAS getASTAllocaAddressSpace() const override {
     return getLangASFromTargetAS(

>From 77987bd26cc81c2b08e52a3b2cdf6ac2c18ae0e0 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 19 Feb 2025 14:20:15 -0800
Subject: [PATCH 18/19] revert clang/lib/CodeGen/CMakeLists.txt whitespace
 changes

---
 clang/lib/CodeGen/CMakeLists.txt | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index 0f3a106cea1b9..05ab6671453f8 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -31,26 +31,25 @@ set(LLVM_LINK_COMPONENTS
   Target
   TargetParser
   TransformUtils
-)
+  )
 
 # Workaround for MSVC ARM64 performance regression:
 # https://developercommunity.visualstudio.com/t/Compiling-a-specific-code-for-ARM64-with/10444970
 # Since /O1 and /O2 represent a set of optimizations,
 # our goal is to disable the /Og flag while retaining the other optimizations from the /O1|/O2 set
 if(MSVC AND NOT CMAKE_CXX_COMPILER_ID MATCHES Clang
-  AND MSVC_VERSION VERSION_GREATER_EQUAL 1932
-  AND MSVC_VERSION VERSION_LESS 1939
-  AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
+    AND MSVC_VERSION VERSION_GREATER_EQUAL 1932
+    AND MSVC_VERSION VERSION_LESS 1939
+    AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
+
   string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
   string(REGEX MATCHALL "/[Oo][12]" opt_flags "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}")
-
-  if(opt_flags)
+  if (opt_flags)
     if(opt_flags MATCHES "1$")
       set(opt_flags "/Od;/Os;/Oy;/Ob2;/GF;/Gy")
-    elseif(opt_flags MATCHES "2$")
+    elseif (opt_flags MATCHES "2$")
       set(opt_flags "/Od;/Oi;/Ot;/Oy;/Ob2;/GF;/Gy")
     endif()
-
     set_source_files_properties(CGBuiltin.cpp PROPERTIES COMPILE_OPTIONS "${opt_flags}")
   endif()
 endif()
@@ -149,7 +148,6 @@ add_clang_library(clangCodeGen
   vt_gen
   intrinsics_gen
   ClangDriverOptions
-
   # These generated headers are included transitively.
   ARMTargetParserTableGen
   AArch64TargetParserTableGen
@@ -161,4 +159,4 @@ add_clang_library(clangCodeGen
   clangFrontend
   clangLex
   clangSerialization
-)
+  )

>From b93407368d9b65e2e07f82e342e6fec9a1bc8263 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 19 Feb 2025 14:27:45 -0800
Subject: [PATCH 19/19] clang-format

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 4aa5a7ead14a2..547220fb1f1e1 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -19,8 +19,8 @@
 #include "TargetInfo.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
-#include "clang/AST/Type.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/Type.h"
 #include "clang/Basic/TargetOptions.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/IR/DerivedTypes.h"



More information about the cfe-commits mailing list