diff --git a/llvm/lib/Target/DirectX/CBufferDataLayout.h b/llvm/lib/Target/DirectX/CBufferDataLayout.h new file mode 100644 --- /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 +#include + +namespace llvm { +class DataLayout; +class Type; + +namespace dxil { + +class LegacyCBufferLayout; + +class CBufferDataLayout { + const DataLayout &DL; + const bool IsLegacyLayout; + std::unique_ptr 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/CBufferDataLayout.cpp b/llvm/lib/Target/DirectX/CBufferDataLayout.cpp new file mode 100644 --- /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 Offsets; + TypeSize Size = {0, false}; + std::pair 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 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(EltTy) || isa(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(Ty)) { + LegacyStructLayout &Layout = getStructLayout(ST); + return Layout.Size; + } else if (auto *AT = dyn_cast(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(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/CMakeLists.txt b/llvm/lib/Target/DirectX/CMakeLists.txt --- a/llvm/lib/Target/DirectX/CMakeLists.txt +++ b/llvm/lib/Target/DirectX/CMakeLists.txt @@ -12,6 +12,7 @@ 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.h b/llvm/lib/Target/DirectX/DXILResource.h --- a/llvm/lib/Target/DirectX/DXILResource.h +++ b/llvm/lib/Target/DirectX/DXILResource.h @@ -25,6 +25,7 @@ class GlobalVariable; namespace dxil { +class CBufferDataLayout; class ResourceBase { protected: @@ -107,14 +108,34 @@ 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 class ResourceTable { + StringRef MDName; + + llvm::SmallVector 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 UAVs; - - void collectUAVs(Module &M); + ResourceTable UAVs = {"hlsl.uavs"}; + ResourceTable CBuffers = {"hlsl.cbufs"}; public: void collect(Module &M); diff --git a/llvm/lib/Target/DirectX/DXILResource.cpp b/llvm/lib/Target/DirectX/DXILResource.cpp --- 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::dxil; using namespace llvm::hlsl; -void Resources::collectUAVs(Module &M) { - NamedMDNode *Entry = M.getNamedMetadata("hlsl.uavs"); +template void ResourceTable::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(UAV)))); + for (auto *Res : Entry->operands()) { + Data.push_back(T(Counter++, FrontendResource(cast(Res)))); } } -void Resources::collect(Module &M) { collectUAVs(M); } +template <> void ResourceTable::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(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(GV->getInitializer()->getType())) + if (auto *ArrTy = dyn_cast(GV->getValueType())) RangeSize = ArrTy->getNumElements(); } @@ -276,6 +297,30 @@ 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 void ResourceTable::print(raw_ostream &OS) const { + for (auto &Res : Data) + Res.print(OS); +} + MDNode *ResourceBase::ExtendedProperties::write(LLVMContext &Ctx) const { IRBuilder<> B(Ctx); SmallVector Entries; @@ -315,14 +360,36 @@ 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 MDNode *ResourceTable::write(Module &M) const { + if (Data.empty()) + return nullptr; + SmallVector 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 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 @@ << "; ------------------------------ ---------- ------- ----------- " "------- -------------- ------\n"; - for (auto &UAV : UAVs) - UAV.print(O); + CBuffers.print(O); + UAVs.print(O); } void Resources::dump() const { print(dbgs()); } diff --git a/llvm/test/CodeGen/DirectX/cbuf.ll b/llvm/test/CodeGen/DirectX/cbuf.ll new file mode 100644 --- /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 + +@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 --- /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} + +@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 --- /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} + +@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 --- /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} + +@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> } +@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 --- /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 }> + +@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 --- 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 --- /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 --- a/llvm/unittests/Target/DirectX/CMakeLists.txt +++ b/llvm/unittests/Target/DirectX/CMakeLists.txt @@ -11,5 +11,6 @@ ) add_llvm_target_unittest(DirectXTests + CBufferDataLayoutTests.cpp PointerTypeAnalysisTests.cpp )