https://github.com/python3kgae updated 
https://github.com/llvm/llvm-project/pull/91999

>From de2b6cab831ac07bf6adcfe563fd9d866e295071 Mon Sep 17 00:00:00 2001
From: Xiang Li <python3k...@outlook.com>
Date: Mon, 13 May 2024 12:59:48 -0400
Subject: [PATCH 1/2] [HLSL] support packoffset in clang codeGen

Implement packoffset as offset in the layouted struct for cbuffer.

cbuffer CB {
  float a : packoffset(c2);
  float b : packoffset(c4);
  float2 c : packoffset(c2.z);
}

will get layout struct like

struct CBLayout {
  uint8_t padding0[32]; // c0/c1
  float a;         // c2.x
  uint8_t padding1[4];  // c2.y
  float2 c;        // c2.zw
  uint8_t padding[8];  // c3
  float b;         // c4.x
}
---
 clang/include/clang/AST/Decl.h         |   5 ++
 clang/lib/AST/Decl.cpp                 |  48 +++++++++++
 clang/lib/CodeGen/CGHLSLRuntime.cpp    | 103 +++++++++++++++++++----
 clang/lib/CodeGen/CGHLSLRuntime.h      |   8 +-
 clang/lib/Sema/SemaHLSL.cpp            |  38 +--------
 clang/test/CodeGenHLSL/cbuf.hlsl       |   8 +-
 clang/test/CodeGenHLSL/packoffset.hlsl | 109 +++++++++++++++++++++++++
 7 files changed, 264 insertions(+), 55 deletions(-)
 create mode 100644 clang/test/CodeGenHLSL/packoffset.hlsl

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index de8b923645f8d..dfec2f3834e9d 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -4959,6 +4959,11 @@ class HLSLBufferDecl final : public NamedDecl, public 
DeclContext {
                                 SourceLocation LBrace);
   static HLSLBufferDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
 
+  // Calculate the size of a legacy cbuffer type based on
+  // 
https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
+  static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
+                                             QualType T);
+
   SourceRange getSourceRange() const override LLVM_READONLY {
     return SourceRange(getLocStart(), RBraceLoc);
   }
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index ec851c9371e10..ebfff00001087 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5671,6 +5671,54 @@ HLSLBufferDecl 
*HLSLBufferDecl::CreateDeserialized(ASTContext &C,
                                     SourceLocation(), SourceLocation());
 }
 
+static uint64_t calculateLegacyCbufferAlign(const ASTContext &Context,
+                                            QualType T) {
+  if (T->isAggregateType())
+    return 128;
+  else if (const VectorType *VT = T->getAs<VectorType>())
+    return Context.getTypeSize(VT->getElementType());
+  else
+    return Context.getTypeSize(T);
+}
+
+unsigned HLSLBufferDecl::calculateLegacyCbufferSize(const ASTContext &Context,
+                                                    QualType T) {
+  unsigned Size = 0;
+  constexpr unsigned CBufferAlign = 128;
+  constexpr unsigned CBufferAlignMask = CBufferAlign - 1;
+  if (const RecordType *RT = T->getAs<RecordType>()) {
+    const RecordDecl *RD = RT->getDecl();
+    for (const FieldDecl *Field : RD->fields()) {
+      QualType Ty = Field->getType().getCanonicalType();
+      unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
+      unsigned FieldAlign = calculateLegacyCbufferAlign(Context, Ty);
+      if (FieldAlign < CBufferAlign) {
+        // Cross 16-byte boundary.
+        unsigned Base = CBufferAlignMask & Size;
+        if ((Base + FieldSize) > CBufferAlign)
+          FieldAlign = CBufferAlign;
+      }
+      Size = llvm::alignTo(Size, FieldAlign);
+      Size += FieldSize;
+    }
+  } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
+    if (unsigned ElementCount = AT->getSize().getZExtValue()) {
+      unsigned ElementSize =
+          calculateLegacyCbufferSize(Context, AT->getElementType());
+      unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign);
+      Size = AlignedElementSize * (ElementCount - 1) + ElementSize;
+    }
+  } else if (const VectorType *VT = T->getAs<VectorType>()) {
+    unsigned ElementCount = VT->getNumElements();
+    unsigned ElementSize =
+        calculateLegacyCbufferSize(Context, VT->getElementType());
+    Size = ElementSize * ElementCount;
+  } else {
+    Size = Context.getTypeSize(T);
+  }
+  return Size;
+}
+
 
//===----------------------------------------------------------------------===//
 // ImportDecl Implementation
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 5e6a3dd4878f4..0014bfbc68095 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -52,6 +52,17 @@ void addDisableOptimizations(llvm::Module &M) {
   StringRef Key = "dx.disable_optimizations";
   M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
 }
+
+static uint64_t calculateLegacyCbufferAlign(const DataLayout &DL,
+                                            llvm::Type *T) {
+  if (T->isAggregateType())
+    return 16;
+  else if (const auto *VT = dyn_cast<FixedVectorType>(T))
+    return DL.getTypeAllocSize(VT->getElementType());
+  else
+    return DL.getTypeAllocSize(T);
+}
+
 // cbuffer will be translated into global variable in special address space.
 // If translate into C,
 // cbuffer A {
@@ -76,14 +87,71 @@ void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const 
DataLayout &DL) {
   if (Buf.Constants.empty())
     return;
 
+  // Sort Buffer.Constants based on offset.
+  std::stable_sort(Buf.Constants.begin(), Buf.Constants.end(),
+                   [](const CGHLSLRuntime::Buffer::Constant &LHS,
+                      const CGHLSLRuntime::Buffer::Constant &RHS) {
+                     return LHS.Offset < RHS.Offset;
+                   });
+
+  unsigned BufferSize = 0;
+  // Collect offset for allocated constants first.
+  for (auto &Const : Buf.Constants) {
+    unsigned Offset = Const.Offset;
+    if (Offset == UINT_MAX)
+      continue;
+    unsigned Size = Const.Size;
+    // No need to align, the packoffset is already aligned.
+    BufferSize = Offset + Size;
+  }
+
+  constexpr unsigned CBufferAlign = 16;
+  constexpr unsigned CBufferAlignMask = CBufferAlign - 1;
+  // Allocate Offset for constant not allocated yet.
+  for (auto &Const : Buf.Constants) {
+    unsigned Offset = Const.Offset;
+    if (Offset != UINT_MAX)
+      continue;
+
+    GlobalVariable *GV = Const.GV;
+    llvm::Type *Ty = GV->getValueType();
+    unsigned Align = calculateLegacyCbufferAlign(DL, Ty);
+    unsigned Size = Const.Size;
+    if (Align < CBufferAlign) {
+      // Cross 16-byte boundary.
+      unsigned Base = CBufferAlignMask & Size;
+      if ((Base + Size) > CBufferAlign)
+        Align = CBufferAlign;
+    }
+    Offset = llvm::alignTo(BufferSize, Align);
+    BufferSize = Offset + Size;
+    Const.Offset = Offset;
+  }
+
+  // Build struct type for cbuffer.
+  LLVMContext &Ctx = Buf.Constants[0].GV->getContext();
   std::vector<llvm::Type *> EltTys;
+  unsigned CurOffset = 0;
+  auto *I8Ty = llvm::Type::getInt8Ty(Ctx);
+
   for (auto &Const : Buf.Constants) {
-    GlobalVariable *GV = Const.first;
-    Const.second = EltTys.size();
+    // Byte offset.
+    unsigned ConstOffset = Const.Offset;
+    // Add padding if needed.
+    if (CurOffset < ConstOffset)
+      EltTys.emplace_back(
+          llvm::ArrayType::get(I8Ty, (ConstOffset - CurOffset)));
+    assert(CurOffset <= ConstOffset && "constant overlap");
+    GlobalVariable *GV = Const.GV;
+    // Change the offset to field index of the layout struct.
+    Const.ElementIndex = EltTys.size();
     llvm::Type *Ty = GV->getValueType();
     EltTys.emplace_back(Ty);
+    unsigned Size = Const.Size;
+    // No need to align, the ConstOffset is already aligned.
+    CurOffset = ConstOffset + Size;
   }
-  Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
+  Buf.LayoutStruct = llvm::StructType::get(Ctx, EltTys);
 }
 
 GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) {
@@ -97,11 +165,13 @@ GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) {
   IRBuilder<> B(CBGV->getContext());
   Value *ZeroIdx = B.getInt32(0);
   // Replace Const use with CB use.
-  for (auto &[GV, Offset] : Buf.Constants) {
-    Value *GEP =
-        B.CreateGEP(Buf.LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
+  for (auto &Constant : Buf.Constants) {
+    GlobalVariable *GV = Constant.GV;
+    Value *GEP = B.CreateGEP(Buf.LayoutStruct, CBGV,
+                             {ZeroIdx, B.getInt32(Constant.ElementIndex)});
 
-    assert(Buf.LayoutStruct->getElementType(Offset) == GV->getValueType() &&
+    assert(Buf.LayoutStruct->getElementType(Constant.ElementIndex) ==
+               GV->getValueType() &&
            "constant type mismatch");
 
     // Replace.
@@ -134,13 +204,18 @@ void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
         codegenoptions::DebugInfoKind::LimitedDebugInfo)
       DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
 
-  // FIXME: support packoffset.
-  // See https://github.com/llvm/llvm-project/issues/57914.
-  uint32_t Offset = 0;
-  bool HasUserOffset = false;
-
-  unsigned LowerBound = HasUserOffset ? Offset : UINT_MAX;
-  CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
+  unsigned LowerBound = UINT_MAX;
+  bool HasUserOffset = D->hasAttr<HLSLPackOffsetAttr>();
+  if (HasUserOffset) {
+    auto *Attr = D->getAttr<HLSLPackOffsetAttr>();
+    // Make the offset in bytes.
+    LowerBound = Attr->getOffset() * 4;
+  }
+  // Byte size.
+  unsigned Size = HLSLBufferDecl::calculateLegacyCbufferSize(CGM.getContext(),
+                                                             D->getType()) >>
+                  3;
+  CB.Constants.emplace_back(Buffer::Constant{GV, LowerBound, Size, 0});
 }
 
 void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h 
b/clang/lib/CodeGen/CGHLSLRuntime.h
index 0abe39dedcb96..e9f6ccad72ee8 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -95,8 +95,14 @@ class CGHLSLRuntime {
     // IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer).
     bool IsCBuffer;
     BufferResBinding Binding;
+    struct Constant {
+      llvm::GlobalVariable *GV;
+      unsigned Offset;
+      unsigned Size;
+      unsigned ElementIndex;
+    };
     // Global variable and offset for each constant.
-    std::vector<std::pair<llvm::GlobalVariable *, unsigned>> Constants;
+    std::vector<Constant> Constants;
     llvm::StructType *LayoutStruct = nullptr;
   };
 
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 6a12c417e2f3a..12496e6f01c7d 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -39,41 +39,6 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool 
CBuffer,
   return Result;
 }
 
-// Calculate the size of a legacy cbuffer type based on
-// 
https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
-static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
-                                           QualType T) {
-  unsigned Size = 0;
-  constexpr unsigned CBufferAlign = 128;
-  if (const RecordType *RT = T->getAs<RecordType>()) {
-    const RecordDecl *RD = RT->getDecl();
-    for (const FieldDecl *Field : RD->fields()) {
-      QualType Ty = Field->getType();
-      unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
-      unsigned FieldAlign = 32;
-      if (Ty->isAggregateType())
-        FieldAlign = CBufferAlign;
-      Size = llvm::alignTo(Size, FieldAlign);
-      Size += FieldSize;
-    }
-  } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
-    if (unsigned ElementCount = AT->getSize().getZExtValue()) {
-      unsigned ElementSize =
-          calculateLegacyCbufferSize(Context, AT->getElementType());
-      unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign);
-      Size = AlignedElementSize * (ElementCount - 1) + ElementSize;
-    }
-  } else if (const VectorType *VT = T->getAs<VectorType>()) {
-    unsigned ElementCount = VT->getNumElements();
-    unsigned ElementSize =
-        calculateLegacyCbufferSize(Context, VT->getElementType());
-    Size = ElementSize * ElementCount;
-  } else {
-    Size = Context.getTypeSize(T);
-  }
-  return Size;
-}
-
 void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
   auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
   BufDecl->setRBraceLoc(RBrace);
@@ -110,7 +75,8 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation 
RBrace) {
     for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
       VarDecl *Var = PackOffsetVec[i].first;
       HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
-      unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
+      unsigned Size =
+          HLSLBufferDecl::calculateLegacyCbufferSize(Context, Var->getType());
       unsigned Begin = Attr->getOffset() * 32;
       unsigned End = Begin + Size;
       unsigned NextBegin = PackOffsetVec[i + 1].second->getOffset() * 32;
diff --git a/clang/test/CodeGenHLSL/cbuf.hlsl b/clang/test/CodeGenHLSL/cbuf.hlsl
index dc2a6aaa8f433..2500562508274 100644
--- a/clang/test/CodeGenHLSL/cbuf.hlsl
+++ b/clang/test/CodeGenHLSL/cbuf.hlsl
@@ -2,13 +2,13 @@
 // RUN:   dxil-pc-shadermodel6.3-library %s \
 // RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
 
-// CHECK: @[[CB:.+]] = external constant { float, double }
+// CHECK: @[[CB:.+]] = external constant { float, [4 x i8], double }
 cbuffer A : register(b0, space2) {
   float a;
   double b;
 }
 
-// CHECK: @[[TB:.+]] = external constant { float, double }
+// CHECK: @[[TB:.+]] = external constant { float, [4 x i8], double }
 tbuffer A : register(t2, space1) {
   float c;
   double d;
@@ -16,9 +16,9 @@ tbuffer A : register(t2, space1) {
 
 float foo() {
 // CHECK: load float, ptr @[[CB]], align 4
-// CHECK: load double, ptr getelementptr inbounds ({ float, double }, ptr 
@[[CB]], i32 0, i32 1), align 8
+// CHECK: load double, ptr getelementptr inbounds ({ float, [4 x i8], double 
}, ptr @[[CB]], i32 0, i32 2), align 8
 // CHECK: load float, ptr @[[TB]], align 4
-// CHECK: load double, ptr getelementptr inbounds ({ float, double }, ptr 
@[[TB]], i32 0, i32 1), align 8
+// CHECK: load double, ptr getelementptr inbounds ({ float, [4 x i8], double 
}, ptr @[[TB]], i32 0, i32 2), align 8
   return a + b + c*d;
 }
 
diff --git a/clang/test/CodeGenHLSL/packoffset.hlsl 
b/clang/test/CodeGenHLSL/packoffset.hlsl
new file mode 100644
index 0000000000000..72cfc11c00aee
--- /dev/null
+++ b/clang/test/CodeGenHLSL/packoffset.hlsl
@@ -0,0 +1,109 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s -fnative-half-type \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK: @A.cb. = external constant { [8 x i8], double, [8 x i8], float, 
float, half, i16, [4 x i8], i64, i32 }
+cbuffer A {
+  float a : packoffset(c1.z);
+  double b : packoffset(c0.z);
+  float  c;
+  half   d;
+  int16_t e;
+  int64_t f;
+  int     g;
+}
+
+// CHECK: @B.cb. = external constant { [24 x i8], float, [4 x i8], double, [8 
x i8], <3 x float>, [4 x i8], <3 x double>, half, [6 x i8], <2 x double>, 
float, <3 x half>, <3 x half> }
+cbuffer B {
+  double  B0;
+  float3  B1;
+  float   B2 : packoffset(c1.z);
+  double3 B3;
+  half    B4;
+  double2 B5;
+  float   B6;
+  half3   B7;
+  half3   B8;
+}
+
+// CHECK: @C.cb. = external constant { [2 x double], [8 x i8], [3 x <3 x 
float>], float, [3 x double], half, [6 x i8], [1 x <2 x double>], float, [12 x 
i8], [2 x <3 x half>], <3 x half> }
+cbuffer C {
+  double C0[2] : packoffset(c0);
+  float3 C1[3];
+  float  C2;
+  double C3[3];
+  half   C4;
+  double2 C5[1];
+  float  C6;
+  half3  C7[2];
+  half3  C8;
+}
+
+// CHECK: @D.cb. = external constant { [3 x <3 x double>], <3 x half> }
+cbuffer D {
+  double3 D9[3] : packoffset(c);
+  half3 D10;
+}
+                                
+struct S0
+{
+    double B0;
+    float3 B1;
+    float B2;
+    double3 B3;
+    half B4;
+    double2 B5;
+    float B6;
+    half3 B7;
+    half3 B8;
+};
+
+struct S1
+{
+    float A0;
+    double A1;
+    float A2;
+    half A3;
+    int16_t A4;
+    int64_t A5;
+    int A6;
+};
+
+struct S2
+{
+    double B0;
+    float3 B1;
+    float B2;
+    double3 B3;
+    half B4;
+    double2 B5;
+    float B6;
+    half3 B7;
+    half3 B8;
+};
+
+struct S3
+{
+    S1 C0;
+    float C1[1];
+    S2 C2[2];
+    half C3;
+};           
+
+// CHECK: @E.cb. = external constant { [16 x i8], half, [2 x i8], i32, double, 
%struct.S3, [206 x i8], %struct.S0 }
+cbuffer E {
+  int E0 : packoffset(c1.y);
+  S0  E1 : packoffset(c31);
+  half E2 : packoffset(c1);
+  S3 E3 : packoffset(c2);
+  double E4 : packoffset(c1.z);
+}
+
+float foo() {
+// CHECK: %[[a:.+]] = load float, ptr getelementptr inbounds ({ [8 x i8], 
double, [8 x i8], float, float, half, i16, [4 x i8], i64, i32 }, ptr @A.cb., 
i32 0, i32 3), align 4
+// CHECK: %[[B2:.+]] = load float, ptr getelementptr inbounds ({ [24 x i8], 
float, [4 x i8], double, [8 x i8], <3 x float>, [4 x i8], <3 x double>, half, 
[6 x i8], <2 x double>, float, <3 x half>, <3 x half> }, ptr @B.cb., i32 0, i32 
1), align 4
+// CHECK: %[[C6:.+]] = load float, ptr getelementptr inbounds ({ [2 x double], 
[8 x i8], [3 x <3 x float>], float, [3 x double], half, [6 x i8], [1 x <2 x 
double>], float, [12 x i8], [2 x <3 x half>], <3 x half> }, ptr @C.cb., i32 0, 
i32 8), align 4
+// CHECK: %[[D10:.+]] = load <3 x half>, ptr getelementptr inbounds ({ [3 x <3 
x double>], <3 x half> }, ptr @D.cb., i32 0, i32 1), align 8
+// CHECK: %[[E0:.+]] = load i32, ptr getelementptr inbounds ({ [16 x i8], 
half, [2 x i8], i32, double, %struct.S3, [206 x i8], %struct.S0 }, ptr @E.cb., 
i32 0, i32 3), align 4
+  return a + B2 + C6*D10.z + E0;
+}

>From 87de4175301caa98387e7447111d6fda914e73d4 Mon Sep 17 00:00:00 2001
From: Xiang Li <python3k...@outlook.com>
Date: Thu, 16 May 2024 11:17:52 -0400
Subject: [PATCH 2/2] Add unit test.

---
 clang/unittests/AST/CMakeLists.txt            |   1 +
 .../AST/HLSLLegacyCbufferTypeSizeTest.cpp     | 576 ++++++++++++++++++
 2 files changed, 577 insertions(+)
 create mode 100644 clang/unittests/AST/HLSLLegacyCbufferTypeSizeTest.cpp

diff --git a/clang/unittests/AST/CMakeLists.txt 
b/clang/unittests/AST/CMakeLists.txt
index 54765e36db008..5ce8b7c44554e 100644
--- a/clang/unittests/AST/CMakeLists.txt
+++ b/clang/unittests/AST/CMakeLists.txt
@@ -29,6 +29,7 @@ add_clang_unittest(ASTTests
   DeclTest.cpp
   EvaluateAsRValueTest.cpp
   ExternalASTSourceTest.cpp
+  HLSLLegacyCbufferTypeSizeTest.cpp
   NamedDeclPrinterTest.cpp
   RandstructTest.cpp
   RecursiveASTVisitorTest.cpp
diff --git a/clang/unittests/AST/HLSLLegacyCbufferTypeSizeTest.cpp 
b/clang/unittests/AST/HLSLLegacyCbufferTypeSizeTest.cpp
new file mode 100644
index 0000000000000..abf494d8b3482
--- /dev/null
+++ b/clang/unittests/AST/HLSLLegacyCbufferTypeSizeTest.cpp
@@ -0,0 +1,576 @@
+//===- unittests/AST/HLSLLegacyCbufferTypeSizeTest.cpp -- cbuf size test 
--===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for HLSLBufferDecl::calculateLegacyCbufferSize.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace ast_matchers;
+using namespace tooling;
+
+// FIXME: Let buildASTFromCodeWithArgs find hlsl.h instead of using "nostdinc".
+
+TEST(HLSLLegacyCbufferTypeSize, BasicTypes) {
+  constexpr char Code[] = R"hlsl(
+    namespace hlsl {
+    // built-in scalar data types:
+
+    #ifdef __HLSL_ENABLE_16_BIT
+    // 16-bit integer.
+    typedef short int16_t;
+    #endif
+
+    // 64-bit integer.
+    typedef long int64_t;
+
+    } // namespace hlsl
+
+    struct A {
+      float a;
+      double b;
+      float  c;
+      half   d;
+      int16_t e;
+      int64_t f;
+      int     g;
+    };
+  )hlsl";
+  auto AST =
+      tooling::buildASTFromCodeWithArgs(Code,
+                                        /*Args=*/
+                                        {"--driver-mode=dxc", "-T", "lib_6_3",
+                                         "-enable-16bit-types", "-nostdinc"},
+                                        /* FileName*/ "input.hlsl");
+  ASTContext &Ctx = AST->getASTContext();
+
+  auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+
+  //  struct A
+  //  {
+
+  //      float a;                                      ; Offset:    0
+  //      double b;                                     ; Offset:    8
+  //      float c;                                      ; Offset:   16
+  //      half d;                                       ; Offset:   20
+  //      int16_t e;                                    ; Offset:   22
+  //      int64_t f;                                    ; Offset:   24
+  //      int g;                                        ; Offset:   32
+
+  //  } A;                                              ; Offset:    0 Size: 36
+  auto const *A = selectFirst<RecordDecl>("A", Results);
+  unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+      Ctx, QualType(A->getTypeForDecl(), 0));
+  ASSERT_EQ(SizeA, 36u * 8u);
+}
+
+TEST(HLSLLegacyCbufferTypeSize, VectorTypes) {
+  constexpr char Code[] = R"hlsl(
+    namespace hlsl {
+    // built-in scalar data types:
+
+    #ifdef __HLSL_ENABLE_16_BIT
+    // 16-bit integer.
+    typedef short int16_t;
+    #endif
+
+    // 64-bit integer.
+    typedef long int64_t;
+
+    // built-in vector data types:
+
+    typedef vector<half, 2> half2;
+    typedef vector<half, 3> half3;
+    typedef vector<half, 4> half4;
+
+    typedef vector<float, 2> float2;
+    typedef vector<float, 3> float3;
+    typedef vector<float, 4> float4;
+    typedef vector<double, 2> double2;
+    typedef vector<double, 3> double3;
+    typedef vector<double, 4> double4;
+
+    } // namespace hlsl
+
+    struct A {
+      double  B0;
+      float3  B1;
+      float   B2;
+      double3 B3;
+      half    B4;
+      double2 B5;
+      float   B6;
+      half3   B7;
+      half3   B8;
+    };
+  )hlsl";
+  auto AST =
+      tooling::buildASTFromCodeWithArgs(Code,
+                                        /*Args=*/
+                                        {"--driver-mode=dxc", "-T", "lib_6_3",
+                                         "-enable-16bit-types", "-nostdinc"},
+                                        /* FileName*/ "input.hlsl");
+  ASTContext &Ctx = AST->getASTContext();
+
+  auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+  //  struct A
+  //  {
+
+  //      double B0;                                    ; Offset:    0
+  //      float3 B1;                                    ; Offset:   16
+  //      float B2;                                     ; Offset:   28
+  //      double3 B3;                                   ; Offset:   32
+  //      half B4;                                      ; Offset:   56
+  //      double2 B5;                                   ; Offset:   64
+  //      float B6;                                     ; Offset:   80
+  //      half3 B7;                                     ; Offset:   84
+  //      half3 B8;                                     ; Offset:   90
+
+  //  } A;                                              ; Offset:    0 Size: 96
+  auto const *A = selectFirst<RecordDecl>("A", Results);
+  unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+      Ctx, QualType(A->getTypeForDecl(), 0));
+  ASSERT_EQ(SizeA, 96u * 8u);
+}
+
+TEST(HLSLLegacyCbufferTypeSize, ArrayTypes) {
+  constexpr char Code[] = R"hlsl(
+    namespace hlsl {
+    // built-in scalar data types:
+
+    #ifdef __HLSL_ENABLE_16_BIT
+    // 16-bit integer.
+    typedef short int16_t;
+    #endif
+
+    // 64-bit integer.
+    typedef long int64_t;
+
+    // built-in vector data types:
+
+    typedef vector<half, 2> half2;
+    typedef vector<half, 3> half3;
+    typedef vector<half, 4> half4;
+
+    typedef vector<float, 2> float2;
+    typedef vector<float, 3> float3;
+    typedef vector<float, 4> float4;
+    typedef vector<double, 2> double2;
+    typedef vector<double, 3> double3;
+    typedef vector<double, 4> double4;
+
+    } // namespace hlsl
+
+    struct A {
+      double C0[2];
+      float3 C1[3];
+      float  C2;
+      double C3[3];
+      half   C4;
+      double2 C5[1];
+      float  C6;
+      half3  C7[2];
+      half3  C8;
+    };
+  )hlsl";
+  auto AST =
+      tooling::buildASTFromCodeWithArgs(Code,
+                                        /*Args=*/
+                                        {"--driver-mode=dxc", "-T", "lib_6_3",
+                                         "-enable-16bit-types", "-nostdinc"},
+                                        /* FileName*/ "input.hlsl");
+  ASTContext &Ctx = AST->getASTContext();
+
+  auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+
+  //  struct A
+  //  {
+
+  //      double C0[2];                                 ; Offset:    0
+  //      float3 C1[3];                                 ; Offset:   32
+  //      float C2;                                     ; Offset:   76
+  //      double C3[3];                                 ; Offset:   80
+  //      half C4;                                      ; Offset:  120
+  //      double2 C5[1];                                ; Offset:  128
+  //      float C6;                                     ; Offset:  144
+  //      half3 C7[2];                                  ; Offset:  160
+  //      half3 C8;                                     ; Offset:  182
+
+  //  } A;                                              ; Offset:    0 Size: 
188
+  auto const *A = selectFirst<RecordDecl>("A", Results);
+  unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+      Ctx, QualType(A->getTypeForDecl(), 0));
+  ASSERT_EQ(SizeA, 188u * 8u);
+}
+
+TEST(HLSLLegacyCbufferTypeSize, Vec3) {
+  constexpr char Code[] = R"hlsl(
+    namespace hlsl {
+    // built-in scalar data types:
+
+    #ifdef __HLSL_ENABLE_16_BIT
+    // 16-bit integer.
+    typedef short int16_t;
+    #endif
+
+    // 64-bit integer.
+    typedef long int64_t;
+
+    // built-in vector data types:
+
+    typedef vector<half, 2> half2;
+    typedef vector<half, 3> half3;
+    typedef vector<half, 4> half4;
+
+    typedef vector<float, 2> float2;
+    typedef vector<float, 3> float3;
+    typedef vector<float, 4> float4;
+    typedef vector<double, 2> double2;
+    typedef vector<double, 3> double3;
+    typedef vector<double, 4> double4;
+
+    } // namespace hlsl
+
+    struct A {
+      double3 D9[3];
+      half3 D10;
+    };
+  )hlsl";
+  auto AST =
+      tooling::buildASTFromCodeWithArgs(Code,
+                                        /*Args=*/
+                                        {"--driver-mode=dxc", "-T", "lib_6_3",
+                                         "-enable-16bit-types", "-nostdinc"},
+                                        /* FileName*/ "input.hlsl");
+  ASTContext &Ctx = AST->getASTContext();
+
+  auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+
+  //  struct A
+  //  {
+  //
+  //      double3 D9[3];                                ; Offset:    0
+  //      half3 D10;                                    ; Offset:   88
+  //
+  //  } A;                                              ; Offset:    0 Size: 94
+  auto const *A = selectFirst<RecordDecl>("A", Results);
+  unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+      Ctx, QualType(A->getTypeForDecl(), 0));
+  ASSERT_EQ(SizeA, 94u * 8u);
+}
+
+TEST(HLSLLegacyCbufferTypeSize, NestedStruct) {
+  constexpr char Code[] = R"hlsl(
+    namespace hlsl {
+    // built-in scalar data types:
+
+    #ifdef __HLSL_ENABLE_16_BIT
+    // 16-bit integer.
+    typedef short int16_t;
+    #endif
+
+    // 64-bit integer.
+    typedef long int64_t;
+
+    // built-in vector data types:
+
+    typedef vector<half, 2> half2;
+    typedef vector<half, 3> half3;
+    typedef vector<half, 4> half4;
+
+    typedef vector<float, 2> float2;
+    typedef vector<float, 3> float3;
+    typedef vector<float, 4> float4;
+    typedef vector<double, 2> double2;
+    typedef vector<double, 3> double3;
+    typedef vector<double, 4> double4;
+
+    } // namespace hlsl
+
+    struct S0
+    {
+        double B0;
+        float3 B1;
+        float B2;
+        double3 B3;
+        half B4;
+        double2 B5;
+        float B6;
+        half3 B7;
+        half3 B8;
+    };
+
+    struct S1
+    {
+        float A0;
+        double A1;
+        float A2;
+        half A3;
+        int16_t A4;
+        int64_t A5;
+        int A6;
+    };
+
+    struct S2
+    {
+        double B0;
+        float3 B1;
+        float B2;
+        double3 B3;
+        half B4;
+        double2 B5;
+        float B6;
+        half3 B7;
+        half3 B8;
+    };
+
+    struct S3
+    {
+        S1 C0;
+        float C1[1];
+        S2 C2[2];
+        half C3;
+    };           
+
+    struct A {
+      int E0;
+      S0  E1;
+      half E2;
+      S3 E3;
+      double E4;
+    };
+  )hlsl";
+
+  auto AST =
+      tooling::buildASTFromCodeWithArgs(Code,
+                                        /*Args=*/
+                                        {"--driver-mode=dxc", "-T", "lib_6_3",
+                                         "-enable-16bit-types", "-nostdinc"},
+                                        /* FileName*/ "input.hlsl");
+  ASTContext &Ctx = AST->getASTContext();
+
+  auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+
+  //  struct E
+  //  {
+  //      int E0;                                       ; Offset:    0
+  //      struct struct.S0
+  //      {
+
+  //          double B0;                                ; Offset:   16
+  //          float3 B1;                                ; Offset:   32
+  //          float B2;                                 ; Offset:   44
+  //          double3 B3;                               ; Offset:   48
+  //          half B4;                                  ; Offset:   72
+  //          double2 B5;                               ; Offset:   80
+  //          float B6;                                 ; Offset:   96
+  //          half3 B7;                                 ; Offset:  100
+  //          half3 B8;                                 ; Offset:  106
+
+  //      } E1;                                         ; Offset:   16
+
+  //      half E2;                                      ; Offset:  112
+  //      struct struct.S3
+  //      {
+
+  //          struct struct.S1
+  //          {
+
+  //              float A0;                             ; Offset:  128
+  //              double A1;                            ; Offset:  136
+  //              float A2;                             ; Offset:  144
+  //              half A3;                              ; Offset:  148
+  //              int16_t A4;                           ; Offset:  150
+  //              int64_t A5;                           ; Offset:  152
+  //              int A6;                               ; Offset:  160
+
+  //          } C0;                                     ; Offset:  128
+
+  //          float C1[1];                              ; Offset:  176
+  //          struct struct.S2
+  //          {
+
+  //              double B0;                            ; Offset:  192
+  //              float3 B1;                            ; Offset:  208
+  //              float B2;                             ; Offset:  220
+  //              double3 B3;                           ; Offset:  224
+  //              half B4;                              ; Offset:  248
+  //              double2 B5;                           ; Offset:  256
+  //              float B6;                             ; Offset:  272
+  //              half3 B7;                             ; Offset:  276
+  //              half3 B8;                             ; Offset:  282
+
+  //          } C2[2];;                                 ; Offset:  192
+
+  //          half C3;                                  ; Offset:  384
+
+  //      } E3;                                         ; Offset:  128
+
+  //      double E4;                                    ; Offset:  392
+
+  //  } E;                                              ; Offset:    0 Size: 
400
+
+  auto const *A = selectFirst<RecordDecl>("A", Results);
+  unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+      Ctx, QualType(A->getTypeForDecl(), 0));
+  ASSERT_EQ(SizeA, 400u * 8u);
+}
+
+TEST(HLSLLegacyCbufferTypeSize, NestedStructDisable16bitTypes) {
+  constexpr char Code[] = R"hlsl(
+    namespace hlsl {
+
+    // built-in vector data types:
+
+    typedef vector<half, 2> half2;
+    typedef vector<half, 3> half3;
+    typedef vector<half, 4> half4;
+
+    typedef vector<float, 2> float2;
+    typedef vector<float, 3> float3;
+    typedef vector<float, 4> float4;
+    typedef vector<double, 2> double2;
+    typedef vector<double, 3> double3;
+    typedef vector<double, 4> double4;
+
+    } // namespace hlsl
+
+    struct S0
+    {
+        double B0;
+        float3 B1;
+        float B2;
+        double3 B3;
+        half B4;
+        double2 B5;
+        float B6;
+        half3 B7;
+        half3 B8;
+    };
+
+    struct S1
+    {
+        float A0;
+        double A1;
+        float A2;
+        half A3;
+        half A4;
+        double A5;
+        int A6;
+    };
+
+    struct S2
+    {
+        double B0;
+        float3 B1;
+        float B2;
+        double3 B3;
+        half B4;
+        double2 B5;
+        float B6;
+        half3 B7;
+        half3 B8;
+    };
+
+    struct S3
+    {
+        S1 C0;
+        float C1[1];
+        S2 C2[2];
+        half C3;
+    };           
+
+    struct A {
+      int E0;
+      S0  E1;
+      half E2;
+      S3 E3;
+      double E4;
+    };
+  )hlsl";
+
+  auto AST = tooling::buildASTFromCodeWithArgs(
+      Code,
+      /*Args=*/{"--driver-mode=dxc", "-T", "lib_6_3", "-nostdinc"},
+      /* FileName*/ "input.hlsl");
+  ASTContext &Ctx = AST->getASTContext();
+
+  auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+
+  //  struct E
+  //  {
+
+  //      int E0;                                       ; Offset:    0
+  //      struct struct.S0
+  //      {
+
+  //          double B0;                                ; Offset:   16
+  //          float3 B1;                                ; Offset:   32
+  //          float B2;                                 ; Offset:   44
+  //          double3 B3;                               ; Offset:   48
+  //          float B4;                                 ; Offset:   72
+  //          double2 B5;                               ; Offset:   80
+  //          float B6;                                 ; Offset:   96
+  //          float3 B7;                                ; Offset:  100
+  //          float3 B8;                                ; Offset:  112
+
+  //      } E1;                                         ; Offset:   16
+
+  //      float E2;                                     ; Offset:  124
+  //      struct struct.S3
+  //      {
+
+  //          struct struct.S1
+  //          {
+
+  //              float A0;                             ; Offset:  128
+  //              double A1;                            ; Offset:  136
+  //              float A2;                             ; Offset:  144
+  //              float A3;                             ; Offset:  148
+  //              float A4;                             ; Offset:  152
+  //              double A5;                            ; Offset:  160
+  //              int A6;                               ; Offset:  168
+
+  //          } C0;                                     ; Offset:  128
+
+  //          float C1[1];                              ; Offset:  176
+  //          struct struct.S2
+  //          {
+
+  //              double B0;                            ; Offset:  192
+  //              float3 B1;                            ; Offset:  208
+  //              float B2;                             ; Offset:  220
+  //              double3 B3;                           ; Offset:  224
+  //              float B4;                             ; Offset:  248
+  //              double2 B5;                           ; Offset:  256
+  //              float B6;                             ; Offset:  272
+  //              float3 B7;                            ; Offset:  276
+  //              float3 B8;                            ; Offset:  288
+
+  //          } C2[2];;                                 ; Offset:  192
+
+  //          float C3;                                 ; Offset:  412
+
+  //      } E3;                                         ; Offset:  128
+
+  //      double E4;                                    ; Offset:  416
+
+  //  } E;                                              ; Offset:    0 Size: 
424
+
+  auto const *A = selectFirst<RecordDecl>("A", Results);
+  unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+      Ctx, QualType(A->getTypeForDecl(), 0));
+  ASSERT_EQ(SizeA, 424u * 8u);
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to