[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