[llvm] 944f4b2 - [DirectX backend] add support ConstantBuffer to DXILResource.h

Xiang Li via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 12 10:42:22 PST 2023


Author: Xiang Li
Date: 2023-01-12T13:42:11-05:00
New Revision: 944f4b2805852072022293678fddd65dc450e0f2

URL: https://github.com/llvm/llvm-project/commit/944f4b2805852072022293678fddd65dc450e0f2
DIFF: https://github.com/llvm/llvm-project/commit/944f4b2805852072022293678fddd65dc450e0f2.diff

LOG: [DirectX backend] add support ConstantBuffer to DXILResource.h

class ConstantBuffer is added to save information for cbuffer.
Also add CBufferDataLayout to calculate the size for cbuffer.

Now always use legacy cbuffer layout.
https://reviews.llvm.org/D134998 will add control to disable legacy cbuffer layout.

Reviewed By: beanz

Differential Revision: https://reviews.llvm.org/D136031

Added: 
    llvm/lib/Target/DirectX/CBufferDataLayout.cpp
    llvm/lib/Target/DirectX/CBufferDataLayout.h
    llvm/test/CodeGen/DirectX/cbuf.ll
    llvm/test/CodeGen/DirectX/legacy_cb_layout_0.ll
    llvm/test/CodeGen/DirectX/legacy_cb_layout_1.ll
    llvm/test/CodeGen/DirectX/legacy_cb_layout_2.ll
    llvm/test/CodeGen/DirectX/legacy_cb_layout_3.ll
    llvm/unittests/Target/DirectX/CBufferDataLayoutTests.cpp

Modified: 
    llvm/lib/Target/DirectX/CMakeLists.txt
    llvm/lib/Target/DirectX/DXILResource.cpp
    llvm/lib/Target/DirectX/DXILResource.h
    llvm/test/tools/dxil-dis/BasicIR.ll
    llvm/unittests/Target/DirectX/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/DirectX/CBufferDataLayout.cpp b/llvm/lib/Target/DirectX/CBufferDataLayout.cpp
new file mode 100644
index 000000000000..41bb69b3d79c
--- /dev/null
+++ b/llvm/lib/Target/DirectX/CBufferDataLayout.cpp
@@ -0,0 +1,129 @@
+//===- Target/DirectX/CBufferDataLayout.cpp - Cbuffer layout helper -------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Utils to help cbuffer layout.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CBufferDataLayout.h"
+
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/IRBuilder.h"
+
+namespace llvm {
+namespace dxil {
+
+// Implement cbuffer layout in
+// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
+class LegacyCBufferLayout {
+  struct LegacyStructLayout {
+    StructType *ST;
+    SmallVector<uint32_t> Offsets;
+    TypeSize Size = {0, false};
+    std::pair<uint32_t, uint32_t> getElementLegacyOffset(unsigned Idx) const {
+      assert(Idx < Offsets.size() && "Invalid element idx!");
+      uint32_t Offset = Offsets[Idx];
+      uint32_t Ch = Offset & (RowAlign - 1);
+      return std::make_pair((Offset - Ch) / RowAlign, Ch);
+    }
+  };
+
+public:
+  LegacyCBufferLayout(const DataLayout &DL) : DL(DL) {}
+  TypeSize getTypeAllocSizeInBytes(Type *Ty);
+
+private:
+  TypeSize applyRowAlign(TypeSize Offset, Type *EltTy);
+  TypeSize getTypeAllocSize(Type *Ty);
+  LegacyStructLayout &getStructLayout(StructType *ST);
+  const DataLayout &DL;
+  SmallDenseMap<StructType *, LegacyStructLayout> StructLayouts;
+  // 4 Dwords align.
+  static const uint32_t RowAlign = 16;
+  static TypeSize alignTo4Dwords(TypeSize Offset) {
+    return alignTo(Offset, RowAlign);
+  }
+};
+
+TypeSize LegacyCBufferLayout::getTypeAllocSizeInBytes(Type *Ty) {
+  return getTypeAllocSize(Ty);
+}
+
+TypeSize LegacyCBufferLayout::applyRowAlign(TypeSize Offset, Type *EltTy) {
+  TypeSize AlignedOffset = alignTo4Dwords(Offset);
+
+  if (AlignedOffset == Offset)
+    return Offset;
+
+  if (isa<StructType>(EltTy) || isa<ArrayType>(EltTy))
+    return AlignedOffset;
+  TypeSize Size = DL.getTypeStoreSize(EltTy);
+  if ((Offset + Size) > AlignedOffset)
+    return AlignedOffset;
+  else
+    return Offset;
+}
+
+TypeSize LegacyCBufferLayout::getTypeAllocSize(Type *Ty) {
+  if (auto *ST = dyn_cast<StructType>(Ty)) {
+    LegacyStructLayout &Layout = getStructLayout(ST);
+    return Layout.Size;
+  } else if (auto *AT = dyn_cast<ArrayType>(Ty)) {
+    unsigned NumElts = AT->getNumElements();
+    if (NumElts == 0)
+      return TypeSize::getFixed(0);
+
+    TypeSize EltSize = getTypeAllocSize(AT->getElementType());
+    TypeSize AlignedEltSize = alignTo4Dwords(EltSize);
+    // Each new element start 4 dwords aligned.
+    return TypeSize::getFixed(AlignedEltSize * (NumElts - 1) + EltSize);
+  } else {
+    // NOTE: Use type store size, not align to ABI on basic types for legacy
+    // layout.
+    return DL.getTypeStoreSize(Ty);
+  }
+}
+
+LegacyCBufferLayout::LegacyStructLayout &
+LegacyCBufferLayout::getStructLayout(StructType *ST) {
+  auto it = StructLayouts.find(ST);
+  if (it != StructLayouts.end())
+    return it->second;
+
+  TypeSize Offset = TypeSize::Fixed(0);
+  LegacyStructLayout Layout;
+  Layout.ST = ST;
+  for (Type *EltTy : ST->elements()) {
+    TypeSize EltSize = getTypeAllocSize(EltTy);
+    if (TypeSize ScalarSize = EltTy->getScalarType()->getPrimitiveSizeInBits())
+      Offset = alignTo(Offset, ScalarSize >> 3);
+    Offset = applyRowAlign(Offset, EltTy);
+    Layout.Offsets.emplace_back(Offset);
+    Offset = Offset.getWithIncrement(EltSize);
+  }
+  Layout.Size = Offset;
+  StructLayouts[ST] = Layout;
+  return StructLayouts[ST];
+}
+
+CBufferDataLayout::CBufferDataLayout(const DataLayout &DL, const bool IsLegacy)
+    : DL(DL), IsLegacyLayout(IsLegacy),
+      LegacyDL(IsLegacy ? std::make_unique<LegacyCBufferLayout>(DL) : nullptr) {
+}
+
+CBufferDataLayout::~CBufferDataLayout() = default;
+
+llvm::TypeSize CBufferDataLayout::getTypeAllocSizeInBytes(Type *Ty) {
+  if (IsLegacyLayout)
+    return LegacyDL->getTypeAllocSizeInBytes(Ty);
+  else
+    return DL.getTypeAllocSize(Ty);
+}
+
+} // namespace dxil
+} // namespace llvm

diff  --git a/llvm/lib/Target/DirectX/CBufferDataLayout.h b/llvm/lib/Target/DirectX/CBufferDataLayout.h
new file mode 100644
index 000000000000..65321512cb79
--- /dev/null
+++ b/llvm/lib/Target/DirectX/CBufferDataLayout.h
@@ -0,0 +1,43 @@
+//===- Target/DirectX/CBufferDataLayout.h - Cbuffer layout helper ---------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Utils to help cbuffer layout.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TARGET_DIRECTX_CBUFFERDATALAYOUT_H
+#define LLVM_TARGET_DIRECTX_CBUFFERDATALAYOUT_H
+
+#include "llvm/Support/TypeSize.h"
+
+#include <memory>
+#include <stdint.h>
+
+namespace llvm {
+class DataLayout;
+class Type;
+
+namespace dxil {
+
+class LegacyCBufferLayout;
+
+class CBufferDataLayout {
+  const DataLayout &DL;
+  const bool IsLegacyLayout;
+  std::unique_ptr<LegacyCBufferLayout> LegacyDL;
+
+public:
+  CBufferDataLayout(const DataLayout &DL, const bool IsLegacy);
+  ~CBufferDataLayout();
+  llvm::TypeSize getTypeAllocSizeInBytes(Type *Ty);
+};
+
+} // namespace dxil
+} // namespace llvm
+
+#endif

diff  --git a/llvm/lib/Target/DirectX/CMakeLists.txt b/llvm/lib/Target/DirectX/CMakeLists.txt
index 6485399a4caa..dbee3de2c59f 100644
--- a/llvm/lib/Target/DirectX/CMakeLists.txt
+++ b/llvm/lib/Target/DirectX/CMakeLists.txt
@@ -12,6 +12,7 @@ tablegen(LLVM DXILOperation.inc -gen-dxil-operation)
 add_public_tablegen_target(DirectXCommonTableGen)
 
 add_llvm_target(DirectXCodeGen
+  CBufferDataLayout.cpp
   DirectXAsmPrinter.cpp
   DirectXInstrInfo.cpp
   DirectXRegisterInfo.cpp

diff  --git a/llvm/lib/Target/DirectX/DXILResource.cpp b/llvm/lib/Target/DirectX/DXILResource.cpp
index 518f77ffcc1a..763432911dbf 100644
--- a/llvm/lib/Target/DirectX/DXILResource.cpp
+++ b/llvm/lib/Target/DirectX/DXILResource.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "DXILResource.h"
+#include "CBufferDataLayout.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Metadata.h"
@@ -22,23 +23,43 @@ using namespace llvm;
 using namespace llvm::dxil;
 using namespace llvm::hlsl;
 
-void Resources::collectUAVs(Module &M) {
-  NamedMDNode *Entry = M.getNamedMetadata("hlsl.uavs");
+template <typename T> void ResourceTable<T>::collect(Module &M) {
+  NamedMDNode *Entry = M.getNamedMetadata(MDName);
   if (!Entry || Entry->getNumOperands() == 0)
     return;
 
   uint32_t Counter = 0;
-  for (auto *UAV : Entry->operands()) {
-    UAVs.push_back(UAVResource(Counter++, FrontendResource(cast<MDNode>(UAV))));
+  for (auto *Res : Entry->operands()) {
+    Data.push_back(T(Counter++, FrontendResource(cast<MDNode>(Res))));
   }
 }
 
-void Resources::collect(Module &M) { collectUAVs(M); }
+template <> void ResourceTable<ConstantBuffer>::collect(Module &M) {
+  NamedMDNode *Entry = M.getNamedMetadata(MDName);
+  if (!Entry || Entry->getNumOperands() == 0)
+    return;
+
+  uint32_t Counter = 0;
+  for (auto *Res : Entry->operands()) {
+    Data.push_back(
+        ConstantBuffer(Counter++, FrontendResource(cast<MDNode>(Res))));
+  }
+  // FIXME: share CBufferDataLayout with CBuffer load lowering.
+  //   See https://github.com/llvm/llvm-project/issues/58381
+  CBufferDataLayout CBDL(M.getDataLayout(), /*IsLegacy*/ true);
+  for (auto &CB : Data)
+    CB.setSize(CBDL);
+}
+
+void Resources::collect(Module &M) {
+  UAVs.collect(M);
+  CBuffers.collect(M);
+}
 
 ResourceBase::ResourceBase(uint32_t I, FrontendResource R)
     : ID(I), GV(R.getGlobalVariable()), Name(""), Space(R.getSpace()),
       LowerBound(R.getResourceIndex()), RangeSize(1) {
-  if (auto *ArrTy = dyn_cast<ArrayType>(GV->getInitializer()->getType()))
+  if (auto *ArrTy = dyn_cast<ArrayType>(GV->getValueType()))
     RangeSize = ArrTy->getNumElements();
 }
 
@@ -276,6 +297,30 @@ void UAVResource::parseSourceType(StringRef S) {
     ExtProps.ElementType = ElTy;
 }
 
+ConstantBuffer::ConstantBuffer(uint32_t I, hlsl::FrontendResource R)
+    : ResourceBase(I, R) {}
+
+void ConstantBuffer::setSize(CBufferDataLayout &DL) {
+  CBufferSizeInBytes = DL.getTypeAllocSizeInBytes(GV->getValueType());
+}
+
+void ConstantBuffer::print(raw_ostream &OS) const {
+  OS << "; " << left_justify(Name, 31);
+
+  OS << right_justify("cbuffer", 10);
+
+  printComponentType(Kinds::CBuffer, ComponentType::Invalid, 8, OS);
+
+  printKind(Kinds::CBuffer, 12, OS, /*SRV*/ false, /*HasCounter*/ false);
+  // Print the binding part.
+  ResourceBase::print(OS, "CB", "cb");
+}
+
+template <typename T> void ResourceTable<T>::print(raw_ostream &OS) const {
+  for (auto &Res : Data)
+    Res.print(OS);
+}
+
 MDNode *ResourceBase::ExtendedProperties::write(LLVMContext &Ctx) const {
   IRBuilder<> B(Ctx);
   SmallVector<Metadata *> Entries;
@@ -315,14 +360,36 @@ MDNode *UAVResource::write() const {
   return MDNode::get(Ctx, Entries);
 }
 
+MDNode *ConstantBuffer::write() const {
+  auto &Ctx = GV->getContext();
+  IRBuilder<> B(Ctx);
+  Metadata *Entries[7];
+  ResourceBase::write(Ctx, Entries);
+
+  Entries[6] = ConstantAsMetadata::get(B.getInt32(CBufferSizeInBytes));
+  return MDNode::get(Ctx, Entries);
+}
+
+template <typename T> MDNode *ResourceTable<T>::write(Module &M) const {
+  if (Data.empty())
+    return nullptr;
+  SmallVector<Metadata *> MDs;
+  for (auto &Res : Data)
+    MDs.emplace_back(Res.write());
+
+  NamedMDNode *Entry = M.getNamedMetadata(MDName);
+  if (Entry)
+    Entry->eraseFromParent();
+
+  return MDNode::get(M.getContext(), MDs);
+}
+
 void Resources::write(Module &M) const {
   Metadata *ResourceMDs[4] = {nullptr, nullptr, nullptr, nullptr};
-  SmallVector<Metadata *> UAVMDs;
-  for (auto &UAV : UAVs)
-    UAVMDs.emplace_back(UAV.write());
 
-  if (!UAVMDs.empty())
-    ResourceMDs[1] = MDNode::get(M.getContext(), UAVMDs);
+  ResourceMDs[1] = UAVs.write(M);
+
+  ResourceMDs[2] = CBuffers.write(M);
 
   bool HasResource = ResourceMDs[0] != nullptr || ResourceMDs[1] != nullptr ||
                      ResourceMDs[2] != nullptr || ResourceMDs[3] != nullptr;
@@ -346,8 +413,8 @@ void Resources::print(raw_ostream &O) const {
     << "; ------------------------------ ---------- ------- ----------- "
        "------- -------------- ------\n";
 
-  for (auto &UAV : UAVs)
-    UAV.print(O);
+  CBuffers.print(O);
+  UAVs.print(O);
 }
 
 void Resources::dump() const { print(dbgs()); }

diff  --git a/llvm/lib/Target/DirectX/DXILResource.h b/llvm/lib/Target/DirectX/DXILResource.h
index 12fd9a9df83a..cb39020bc61e 100644
--- a/llvm/lib/Target/DirectX/DXILResource.h
+++ b/llvm/lib/Target/DirectX/DXILResource.h
@@ -25,6 +25,7 @@ class Module;
 class GlobalVariable;
 
 namespace dxil {
+class CBufferDataLayout;
 
 class ResourceBase {
 protected:
@@ -107,14 +108,34 @@ class UAVResource : public ResourceBase {
   void print(raw_ostream &O) const;
 };
 
+class ConstantBuffer : public ResourceBase {
+  uint32_t CBufferSizeInBytes = 0; // Cbuffer used size in bytes.
+public:
+  ConstantBuffer(uint32_t I, hlsl::FrontendResource R);
+  void setSize(CBufferDataLayout &DL);
+  MDNode *write() const;
+  void print(raw_ostream &O) const;
+};
+
+template <typename T> class ResourceTable {
+  StringRef MDName;
+
+  llvm::SmallVector<T> Data;
+
+public:
+  ResourceTable(StringRef Name) : MDName(Name) {}
+  void collect(Module &M);
+  MDNode *write(Module &M) const;
+  void print(raw_ostream &O) const;
+};
+
 // FIXME: Fully computing the resource structures requires analyzing the IR
 // because some flags are set based on what operations are performed on the
 // resource. This partial patch handles some of the leg work, but not all of it.
 // See issue https://github.com/llvm/llvm-project/issues/57936.
 class Resources {
-  llvm::SmallVector<UAVResource> UAVs;
-
-  void collectUAVs(Module &M);
+  ResourceTable<UAVResource> UAVs = {"hlsl.uavs"};
+  ResourceTable<ConstantBuffer> CBuffers = {"hlsl.cbufs"};
 
 public:
   void collect(Module &M);

diff  --git a/llvm/test/CodeGen/DirectX/cbuf.ll b/llvm/test/CodeGen/DirectX/cbuf.ll
new file mode 100644
index 000000000000..6640654f730e
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/cbuf.ll
@@ -0,0 +1,37 @@
+; RUN: opt -S -dxil-metadata-emit < %s | FileCheck %s --check-prefix=DXILMD
+; RUN: opt -S --passes="print-dxil-resource" < %s 2>&1 | FileCheck %s --check-prefix=PRINT
+
+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 = "dxil-unknown-shadermodel6.7-library"
+
+; Make sure the size is 24 = 16 + 8 (float,i32,double -> 16 and int2 -> 8)
+; DXILMD:!{i32 0, ptr @A.cb., !"", i32 1, i32 2, i32 1, i32 24}
+
+; Make sure match register(b2, space1) with ID 0.
+; PRINT:cbuffer      NA          NA     CB0     cb2,space1     1
+
+ at A.cb. = external constant { float, i32, double, <2 x i32> }
+
+; Function Attrs: noinline nounwind optnone
+define noundef float @"?foo@@YAMXZ"() #0 {
+entry:
+  %0 = load float, ptr @A.cb., align 4
+  %conv = fpext float %0 to double
+  %1 = load double, ptr getelementptr inbounds ({ float, i32, double, <2 x i32> }, ptr @A.cb., i32 0, i32 2), align 8
+  %2 = load <2 x i32>, ptr getelementptr inbounds ({ float, i32, double, <2 x i32> }, ptr @A.cb., i32 0, i32 3), align 8
+  %3 = extractelement <2 x i32> %2, i32 1
+  %conv1 = sitofp i32 %3 to double
+  %4 = call double @llvm.fmuladd.f64(double %1, double %conv1, double %conv)
+  %conv2 = fptrunc double %4 to float
+  ret float %conv2
+}
+
+; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
+declare double @llvm.fmuladd.f64(double, double, double) #1
+
+attributes #0 = { noinline nounwind }
+attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
+
+!hlsl.cbufs = !{!1}
+
+!1 = !{ptr @A.cb., !"A.cb.ty", i32 13, i32 2, i32 1}

diff  --git a/llvm/test/CodeGen/DirectX/legacy_cb_layout_0.ll b/llvm/test/CodeGen/DirectX/legacy_cb_layout_0.ll
new file mode 100644
index 000000000000..50821467d5dd
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/legacy_cb_layout_0.ll
@@ -0,0 +1,14 @@
+; RUN: opt -S -dxil-metadata-emit < %s | FileCheck %s --check-prefix=DXILMD
+
+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 = "dxil-unknown-shadermodel6.7-library"
+
+; Make sure the size is 36 = 16 + 16 + 4 (float, double -> 16, float, half, i16, i64 -> 16 and int -> 4)
+; DXILMD:!{i32 0, ptr @A.cb., !"", i32 0, i32 2, i32 1, i32 36}
+
+ at A.cb. = external local_unnamed_addr constant { float, double, float, half, i16, i64, i32 }
+
+
+!hlsl.cbufs = !{!1}
+
+!1 = !{ptr @A.cb., !"A.cb.ty", i32 13, i32 2, i32 0}

diff  --git a/llvm/test/CodeGen/DirectX/legacy_cb_layout_1.ll b/llvm/test/CodeGen/DirectX/legacy_cb_layout_1.ll
new file mode 100644
index 000000000000..8a38ccd8ef78
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/legacy_cb_layout_1.ll
@@ -0,0 +1,37 @@
+; RUN: opt -S -dxil-metadata-emit < %s | FileCheck %s --check-prefix=DXILMD
+
+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 = "dxil-unknown-shadermodel6.7-library"
+
+;
+; cbuffer B
+; {
+;
+;   struct B
+;   {
+;
+;       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
+;   
+;   } B;                                              ; Offset:    0 Size:    96
+;
+; }
+;
+
+
+; Make sure the size is 96
+; DXILMD:!{i32 0, ptr @B.cb., !"", i32 0, i32 1, i32 1, i32 96}
+
+ at B.cb. = external local_unnamed_addr constant { double, <3 x float>, float, <3 x double>, half, <2 x double>, float, <3 x half>, <3 x half> }
+
+
+!hlsl.cbufs = !{!0}
+
+!0 = !{ptr @B.cb., !"B.cb.ty", i32 13, i32 1, i32 0}

diff  --git a/llvm/test/CodeGen/DirectX/legacy_cb_layout_2.ll b/llvm/test/CodeGen/DirectX/legacy_cb_layout_2.ll
new file mode 100644
index 000000000000..b669538846ab
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/legacy_cb_layout_2.ll
@@ -0,0 +1,51 @@
+; RUN: opt -S -dxil-metadata-emit < %s | FileCheck %s --check-prefix=DXILMD
+
+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 = "dxil-unknown-shadermodel6.7-library"
+
+; cbuffer B
+; {
+;
+;   struct B
+;   {
+;
+;       double B0[2];                                 ; Offset:    0
+;       float3 B1[3];                                 ; Offset:   32
+;       float B2;                                     ; Offset:   76
+;       double B3[3];                                 ; Offset:   80
+;       half B4;                                      ; Offset:  120
+;       double2 B5[1];                                ; Offset:  128
+;       float B6;                                     ; Offset:  144
+;       half3 B7[2];                                  ; Offset:  160
+;       half3 B8;                                     ; Offset:  182
+;   
+;   } B;                                              ; Offset:    0 Size:   188
+;
+; }
+;
+; cbuffer B
+; {
+;
+;   struct B.0
+;   {
+;
+;       double3 B9[3];                                ; Offset:    0
+;       half3 B10;                                    ; Offset:   88
+;   
+;   } B;                                              ; Offset:    0 Size:    94
+;
+; }
+
+
+; Make sure the size is 188.
+; DXILMD:!{i32 0, ptr @B.cb., !"", i32 0, i32 1, i32 1, i32 188}
+; Make sure the size is 94.
+; DXILMD:!{i32 1, ptr @B.cb..1, !"", i32 0, i32 2, i32 1, i32 94}
+
+ at B.cb. = external local_unnamed_addr constant { [2 x double], [3 x <3 x float>], float, [3 x double], half, [1 x <2 x double>], float, [2 x <3 x half>], <3 x half> }
+ at B.cb..1 = external local_unnamed_addr constant { [3 x <3 x double>], <3 x half> }
+
+!hlsl.cbufs = !{!0, !1}
+
+!0 = !{ptr @B.cb., !"B.cb.ty", i32 13, i32 1, i32 0}
+!1 = !{ptr @B.cb..1, !"B.cb.ty", i32 13, i32 2, i32 0}

diff  --git a/llvm/test/CodeGen/DirectX/legacy_cb_layout_3.ll b/llvm/test/CodeGen/DirectX/legacy_cb_layout_3.ll
new file mode 100644
index 000000000000..afd46d08b5c7
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/legacy_cb_layout_3.ll
@@ -0,0 +1,81 @@
+; RUN: opt -S -dxil-metadata-emit < %s | FileCheck %s --check-prefix=DXILMD
+
+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 = "dxil-unknown-shadermodel6.7-library"
+
+; cbuffer D
+; {
+;
+;   struct D
+;   {
+;
+;       int D0;                                       ; Offset:    0
+;       struct struct.B
+;       {
+;
+;           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
+;       
+;       } D1;                                         ; Offset:   16
+;
+;       half D2;                                      ; Offset:  112
+;       struct struct.C
+;       {
+;
+;           struct struct.A
+;           {
+;
+;               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.B
+;           {
+;
+;               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
+;       
+;       } D3;                                         ; Offset:  128
+;
+;       double D4;                                    ; Offset:  392
+;   
+;   } D;                                              ; Offset:    0 Size:   400
+
+
+; Make sure the size is 400
+; DXILMD:!{i32 0, ptr @D.cb., !"", i32 0, i32 1, i32 1, i32 400}
+
+
+%struct.B = type <{ double, <3 x float>, float, <3 x double>, half, <2 x double>, float, <3 x half>, <3 x half> }>
+%struct.C = type <{ %struct.A, [1 x float], [2 x %struct.B], half }>
+%struct.A = type <{ float, double, float, half, i16, i64, i32 }>
+
+ at D.cb. = external local_unnamed_addr constant { i32, %struct.B, half, %struct.C, double }
+
+!hlsl.cbufs = !{!0}
+!0 = !{ptr @D.cb., !"D.cb.ty", i32 13, i32 1, i32 0}

diff  --git a/llvm/test/tools/dxil-dis/BasicIR.ll b/llvm/test/tools/dxil-dis/BasicIR.ll
index 8f961f095754..a79365a93802 100644
--- a/llvm/test/tools/dxil-dis/BasicIR.ll
+++ b/llvm/test/tools/dxil-dis/BasicIR.ll
@@ -1,6 +1,6 @@
 ; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
 
-; RUN: llc --filetype=obj %s --stop-after=dxil-write-bitcode -o %t | llvm-bcanalyzer --dump-blockinfo %t | FileCheck %s  --check-prefix=BLOCK_INFO
+; RUN: llc --filetype=obj %s --stop-after=dxil-write-bitcode -o %t && llvm-bcanalyzer --dump-blockinfo %t | FileCheck %s  --check-prefix=BLOCK_INFO
 
 ; CHECK: define i32 @foo(i32 %X, i32 %Y) {
 ; CHECK:   %Z = sub i32 %X, %Y

diff  --git a/llvm/unittests/Target/DirectX/CBufferDataLayoutTests.cpp b/llvm/unittests/Target/DirectX/CBufferDataLayoutTests.cpp
new file mode 100644
index 000000000000..c2cef65e42ed
--- /dev/null
+++ b/llvm/unittests/Target/DirectX/CBufferDataLayoutTests.cpp
@@ -0,0 +1,153 @@
+//===- llvm/unittests/Target/DirectX/CBufferDataLayoutTests.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 "CBufferDataLayout.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Type.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using ::testing::Contains;
+using ::testing::Pair;
+
+using namespace llvm;
+using namespace llvm::dxil;
+
+void checkLegacyLayout(CBufferDataLayout &CBDL, Type *T16, Type *T32,
+                       Type *T64) {
+  // Basic types.
+  EXPECT_EQ(2ULL, CBDL.getTypeAllocSizeInBytes(T16).getFixedSize());
+  EXPECT_EQ(4ULL, CBDL.getTypeAllocSizeInBytes(T32).getFixedSize());
+  EXPECT_EQ(8ULL, CBDL.getTypeAllocSizeInBytes(T64).getFixedSize());
+  // Vector types.
+  Type *T16V2 = FixedVectorType::get(T16, 2);
+  Type *T32V2 = FixedVectorType::get(T32, 2);
+  Type *T64V2 = FixedVectorType::get(T64, 2);
+  Type *T16V3 = FixedVectorType::get(T16, 3);
+  Type *T32V3 = FixedVectorType::get(T32, 3);
+  Type *T64V3 = FixedVectorType::get(T64, 3);
+  Type *T16V4 = FixedVectorType::get(T16, 4);
+  Type *T32V4 = FixedVectorType::get(T32, 4);
+  Type *T64V4 = FixedVectorType::get(T64, 4);
+  EXPECT_EQ(4ULL, CBDL.getTypeAllocSizeInBytes(T16V2).getFixedSize());
+  EXPECT_EQ(8ULL, CBDL.getTypeAllocSizeInBytes(T32V2).getFixedSize());
+  EXPECT_EQ(16ULL, CBDL.getTypeAllocSizeInBytes(T64V2).getFixedSize());
+  EXPECT_EQ(6ULL, CBDL.getTypeAllocSizeInBytes(T16V3).getFixedSize());
+  EXPECT_EQ(12ULL, CBDL.getTypeAllocSizeInBytes(T32V3).getFixedSize());
+  EXPECT_EQ(24ULL, CBDL.getTypeAllocSizeInBytes(T64V3).getFixedSize());
+  EXPECT_EQ(8ULL, CBDL.getTypeAllocSizeInBytes(T16V4).getFixedSize());
+  EXPECT_EQ(16ULL, CBDL.getTypeAllocSizeInBytes(T32V4).getFixedSize());
+  EXPECT_EQ(32ULL, CBDL.getTypeAllocSizeInBytes(T64V4).getFixedSize());
+
+  // Array types.
+
+  ArrayType *T16A3 = ArrayType::get(T16, 3);
+  ArrayType *T32A3 = ArrayType::get(T32, 3);
+  ArrayType *T64A3 = ArrayType::get(T64, 3);
+
+  EXPECT_EQ(34ULL, CBDL.getTypeAllocSizeInBytes(T16A3).getFixedSize());
+  EXPECT_EQ(36ULL, CBDL.getTypeAllocSizeInBytes(T32A3).getFixedSize());
+  EXPECT_EQ(40ULL, CBDL.getTypeAllocSizeInBytes(T64A3).getFixedSize());
+
+  ArrayType *T16V3A3 = ArrayType::get(T16V3, 3);
+  ArrayType *T32V3A3 = ArrayType::get(T32V3, 3);
+  ArrayType *T64V3A3 = ArrayType::get(T64V3, 3);
+
+  EXPECT_EQ(38ULL, CBDL.getTypeAllocSizeInBytes(T16V3A3).getFixedSize());
+  EXPECT_EQ(44ULL, CBDL.getTypeAllocSizeInBytes(T32V3A3).getFixedSize());
+  EXPECT_EQ(88ULL, CBDL.getTypeAllocSizeInBytes(T64V3A3).getFixedSize());
+
+  ArrayType *T16V3A3A3 = ArrayType::get(T16V3A3, 3);
+  ArrayType *T32V3A3A3 = ArrayType::get(T32V3A3, 3);
+  ArrayType *T64V3A3A3 = ArrayType::get(T64V3A3, 3);
+
+  EXPECT_EQ((48 * 2 + 38ULL),
+            CBDL.getTypeAllocSizeInBytes(T16V3A3A3).getFixedSize());
+  EXPECT_EQ((48 * 2 + 44ULL),
+            CBDL.getTypeAllocSizeInBytes(T32V3A3A3).getFixedSize());
+  EXPECT_EQ((96 * 2 + 88ULL),
+            CBDL.getTypeAllocSizeInBytes(T64V3A3A3).getFixedSize());
+
+  // Struct types.
+  StructType *BasicMix0 = StructType::get(T16, T32, T64);
+  StructType *BasicMix1 = StructType::get(T16, T64, T32);
+  StructType *BasicMix2 = StructType::get(T32, T64, T16);
+  StructType *BasicMix3 = StructType::get(T32, T16, T64);
+  StructType *BasicMix4 = StructType::get(T64, T16, T32);
+  StructType *BasicMix5 = StructType::get(T64, T32, T16);
+
+  EXPECT_EQ(16ULL, CBDL.getTypeAllocSizeInBytes(BasicMix0).getFixedSize());
+  EXPECT_EQ(20ULL, CBDL.getTypeAllocSizeInBytes(BasicMix1).getFixedSize());
+  EXPECT_EQ(18ULL, CBDL.getTypeAllocSizeInBytes(BasicMix2).getFixedSize());
+  EXPECT_EQ(16ULL, CBDL.getTypeAllocSizeInBytes(BasicMix3).getFixedSize());
+  EXPECT_EQ(16ULL, CBDL.getTypeAllocSizeInBytes(BasicMix4).getFixedSize());
+  EXPECT_EQ(14ULL, CBDL.getTypeAllocSizeInBytes(BasicMix5).getFixedSize());
+
+  StructType *VecMix0 = StructType::get(T16V3, T16, T32, T64V2);
+  StructType *VecMix1 = StructType::get(T16V3, T32, T64V2, T16);
+  StructType *VecMix2 = StructType::get(T16V3, T64, T32V2, T16);
+  StructType *VecMix3 = StructType::get(T32V3, T64, T16V2, T32);
+  StructType *VecMix4 = StructType::get(T32V3, T16, T16V2, T64);
+  StructType *VecMix5 = StructType::get(T32V3, T64V3, T16V2, T64);
+
+  EXPECT_EQ(32ULL, CBDL.getTypeAllocSizeInBytes(VecMix0).getFixedSize());
+  EXPECT_EQ(34ULL, CBDL.getTypeAllocSizeInBytes(VecMix1).getFixedSize());
+  EXPECT_EQ(26ULL, CBDL.getTypeAllocSizeInBytes(VecMix2).getFixedSize());
+  EXPECT_EQ(32ULL, CBDL.getTypeAllocSizeInBytes(VecMix3).getFixedSize());
+  EXPECT_EQ(32ULL, CBDL.getTypeAllocSizeInBytes(VecMix4).getFixedSize());
+  EXPECT_EQ(56ULL, CBDL.getTypeAllocSizeInBytes(VecMix5).getFixedSize());
+
+  StructType *ArrayMix0 = StructType::get(T16A3, T16, T32, T64A3);
+  StructType *ArrayMix1 = StructType::get(T32A3, T16, T32, T16A3);
+  StructType *ArrayMix2 = StructType::get(T16A3, T32, T64, T32A3);
+  StructType *ArrayMix3 = StructType::get(T32A3, T32, T64, T16A3);
+  StructType *ArrayMix4 = StructType::get(T16A3, T64, T16, T64A3);
+  StructType *ArrayMix5 = StructType::get(T32A3, T64, T16, T32A3);
+
+  EXPECT_EQ(88ULL, CBDL.getTypeAllocSizeInBytes(ArrayMix0).getFixedSize());
+  EXPECT_EQ(82ULL, CBDL.getTypeAllocSizeInBytes(ArrayMix1).getFixedSize());
+  EXPECT_EQ(84ULL, CBDL.getTypeAllocSizeInBytes(ArrayMix2).getFixedSize());
+  EXPECT_EQ(82ULL, CBDL.getTypeAllocSizeInBytes(ArrayMix3).getFixedSize());
+  EXPECT_EQ(104ULL, CBDL.getTypeAllocSizeInBytes(ArrayMix4).getFixedSize());
+  EXPECT_EQ(100ULL, CBDL.getTypeAllocSizeInBytes(ArrayMix5).getFixedSize());
+
+  StructType *StructMix0 = StructType::get(T16A3, T16, T32, ArrayMix0);
+  StructType *StructMix1 = StructType::get(StructMix0, T16, T32, ArrayMix1);
+  ArrayType *StructArray0 = ArrayType::get(StructMix1, 3);
+  StructType *StructMix2 = StructType::get(StructArray0, T64);
+  ArrayType *StructArray1 = ArrayType::get(StructMix2, 3);
+  StructType *StructMix3 = StructType::get(StructArray1, T32);
+  EXPECT_EQ(136ULL, CBDL.getTypeAllocSizeInBytes(StructMix0).getFixedSize());
+  EXPECT_EQ(226ULL, CBDL.getTypeAllocSizeInBytes(StructMix1).getFixedSize());
+  EXPECT_EQ(706ULL, CBDL.getTypeAllocSizeInBytes(StructArray0).getFixedSize());
+  EXPECT_EQ(720ULL, CBDL.getTypeAllocSizeInBytes(StructMix2).getFixedSize());
+  EXPECT_EQ(2160ULL, CBDL.getTypeAllocSizeInBytes(StructArray1).getFixedSize());
+  EXPECT_EQ(2164ULL, CBDL.getTypeAllocSizeInBytes(StructMix3).getFixedSize());
+}
+
+TEST(CBufferDataLayout, LegacyLayout) {
+  LLVMContext Context;
+  llvm::DataLayout DL("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");
+
+  CBufferDataLayout CBDL(DL, true);
+
+  Type *F16 = Type::getHalfTy(Context);
+  Type *F32 = Type::getFloatTy(Context);
+  Type *F64 = Type::getDoubleTy(Context);
+
+  Type *I16 = Type::getInt16Ty(Context);
+  Type *I32 = Type::getInt32Ty(Context);
+  Type *I64 = Type::getInt64Ty(Context);
+
+  checkLegacyLayout(CBDL, F16, F32, F64);
+  checkLegacyLayout(CBDL, I16, I32, I64);
+}

diff  --git a/llvm/unittests/Target/DirectX/CMakeLists.txt b/llvm/unittests/Target/DirectX/CMakeLists.txt
index 621b00ae65d3..dd3dc5c09255 100644
--- a/llvm/unittests/Target/DirectX/CMakeLists.txt
+++ b/llvm/unittests/Target/DirectX/CMakeLists.txt
@@ -11,5 +11,6 @@ set(LLVM_LINK_COMPONENTS
 )
 
 add_llvm_target_unittest(DirectXTests
+  CBufferDataLayoutTests.cpp
   PointerTypeAnalysisTests.cpp
   )


        


More information about the llvm-commits mailing list