diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -22,6 +22,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Frontend/HLSL/HLSLResource.h" #include @@ -35,6 +36,7 @@ class VarDecl; class ParmVarDecl; class HLSLBufferDecl; +class HLSLResourceBindingAttr; class CallExpr; class Type; class DeclContext; @@ -47,13 +49,20 @@ class CGHLSLRuntime { public: + struct BufferResBinding { + // The ID like 2 in register(b2, space1). + llvm::Optional Reg; + // The Space like 1 is register(b2, space1). + // Default value is 0. + unsigned Space; + BufferResBinding(HLSLResourceBindingAttr *Attr); + }; struct Buffer { Buffer(const HLSLBufferDecl *D); llvm::StringRef Name; // IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer). bool IsCBuffer; - llvm::Optional Reg; - unsigned Space; + BufferResBinding Binding; // Global variable and offset for each constant. std::vector> Constants; llvm::StructType *LayoutStruct = nullptr; @@ -82,6 +91,11 @@ void setHLSLFunctionAttributes(llvm::Function *, const FunctionDecl *); private: + void addBufferResourceAnnotation(llvm::GlobalVariable *GV, + llvm::StringRef TyName, + hlsl::ResourceClass RC, + llvm::hlsl::ResourceKind RK, + BufferResBinding &Binding); void addConstant(VarDecl *D, Buffer &CB); void addBufferDecls(const DeclContext *DC, Buffer &CB); llvm::SmallVector Buffers; diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -17,7 +17,6 @@ #include "CodeGenModule.h" #include "clang/AST/Decl.h" #include "clang/Basic/TargetOptions.h" -#include "llvm/Frontend/HLSL/HLSLResource.h" #include "llvm/IR/IntrinsicsDirectX.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" @@ -90,16 +89,16 @@ GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) { // Create global variable for CB. - GlobalVariable *CBGV = - new GlobalVariable(Buf.LayoutStruct, /*isConstant*/ true, - GlobalValue::LinkageTypes::ExternalLinkage, nullptr, - Buf.Name + (Buf.IsCBuffer ? ".cb." : ".tb."), - GlobalValue::NotThreadLocal); + GlobalVariable *CBGV = new GlobalVariable( + Buf.LayoutStruct, /*isConstant*/ true, + GlobalValue::LinkageTypes::ExternalLinkage, nullptr, + llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb." : ".tb."), + GlobalValue::NotThreadLocal); IRBuilder<> B(CBGV->getContext()); Value *ZeroIdx = B.getInt32(0); // Replace Const use with CB use. - for (auto &[GV, Offset]: Buf.Constants) { + for (auto &[GV, Offset] : Buf.Constants) { Value *GEP = B.CreateGEP(Buf.LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)}); @@ -177,25 +176,100 @@ layoutBuffer(Buf, DL); GlobalVariable *GV = replaceBuffer(Buf); M.getGlobalList().push_back(GV); - // FIXME: generate resource binding. - // See https://github.com/llvm/llvm-project/issues/57915. + hlsl::ResourceClass RC = + Buf.IsCBuffer ? hlsl::ResourceClass::CBuffer : hlsl::ResourceClass::SRV; + llvm::hlsl::ResourceKind RK = Buf.IsCBuffer + ? llvm::hlsl::ResourceKind::CBuffer + : llvm::hlsl::ResourceKind::TBuffer; + std::string TyName = + Buf.Name.str() + (Buf.IsCBuffer ? ".cb." : ".tb.") + "ty"; + addBufferResourceAnnotation(GV, TyName, RC, RK, Buf.Binding); } } -CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D) { - Name = D->getName(); - IsCBuffer = D->isCBuffer(); - if (auto *Binding = D->getAttr()) { - llvm::APInt RegInt(64, 0); - Binding->getSlot().substr(1).getAsInteger(10, RegInt); - Reg = RegInt.getLimitedValue(); +CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D) + : Name(D->getName()), IsCBuffer(D->isCBuffer()), + Binding(D->getAttr()) {} - llvm::APInt SpaceInt(64, 0); - Binding->getSpace().substr(5).getAsInteger(10, RegInt); - Space = SpaceInt.getLimitedValue(); - } else { - Space = 0; +void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV, + llvm::StringRef TyName, + hlsl::ResourceClass RC, + llvm::hlsl::ResourceKind RK, + BufferResBinding &Binding) { + uint32_t Counter = ResourceCounters[static_cast(RC)]++; + llvm::Module &M = CGM.getModule(); + + NamedMDNode *ResourceMD = nullptr; + switch (RC) { + case hlsl::ResourceClass::UAV: + ResourceMD = M.getOrInsertNamedMetadata("hlsl.uavs"); + break; + case hlsl::ResourceClass::SRV: + ResourceMD = M.getOrInsertNamedMetadata("hlsl.srvs"); + break; + case hlsl::ResourceClass::CBuffer: + ResourceMD = M.getOrInsertNamedMetadata("hlsl.cbufs"); + break; + default: + assert(false && "Unsupported buffer type!"); + return; } + + assert(ResourceMD != nullptr && + "ResourceMD must have been set by the switch above."); + + llvm::hlsl::FrontendResource Res( + GV, TyName, Counter, RK, Binding.Reg.value_or(UINT_MAX), Binding.Space); + ResourceMD->addOperand(Res.getMetadata()); +} + +static llvm::hlsl::ResourceKind +castResourceShapeToResourceKind(HLSLResourceAttr::ResourceKind RK) { + switch (RK) { + case HLSLResourceAttr::ResourceKind::Texture1D: + return llvm::hlsl::ResourceKind::Texture1D; + case HLSLResourceAttr::ResourceKind::Texture2D: + return llvm::hlsl::ResourceKind::Texture2D; + case HLSLResourceAttr::ResourceKind::Texture2DMS: + return llvm::hlsl::ResourceKind::Texture2DMS; + case HLSLResourceAttr::ResourceKind::Texture3D: + return llvm::hlsl::ResourceKind::Texture3D; + case HLSLResourceAttr::ResourceKind::TextureCube: + return llvm::hlsl::ResourceKind::TextureCube; + case HLSLResourceAttr::ResourceKind::Texture1DArray: + return llvm::hlsl::ResourceKind::Texture1DArray; + case HLSLResourceAttr::ResourceKind::Texture2DArray: + return llvm::hlsl::ResourceKind::Texture2DArray; + case HLSLResourceAttr::ResourceKind::Texture2DMSArray: + return llvm::hlsl::ResourceKind::Texture2DMSArray; + case HLSLResourceAttr::ResourceKind::TextureCubeArray: + return llvm::hlsl::ResourceKind::TextureCubeArray; + case HLSLResourceAttr::ResourceKind::TypedBuffer: + return llvm::hlsl::ResourceKind::TypedBuffer; + case HLSLResourceAttr::ResourceKind::RawBuffer: + return llvm::hlsl::ResourceKind::RawBuffer; + case HLSLResourceAttr::ResourceKind::StructuredBuffer: + return llvm::hlsl::ResourceKind::StructuredBuffer; + case HLSLResourceAttr::ResourceKind::CBufferKind: + return llvm::hlsl::ResourceKind::CBuffer; + case HLSLResourceAttr::ResourceKind::SamplerKind: + return llvm::hlsl::ResourceKind::Sampler; + case HLSLResourceAttr::ResourceKind::TBuffer: + return llvm::hlsl::ResourceKind::TBuffer; + case HLSLResourceAttr::ResourceKind::RTAccelerationStructure: + return llvm::hlsl::ResourceKind::RTAccelerationStructure; + case HLSLResourceAttr::ResourceKind::FeedbackTexture2D: + return llvm::hlsl::ResourceKind::FeedbackTexture2D; + case HLSLResourceAttr::ResourceKind::FeedbackTexture2DArray: + return llvm::hlsl::ResourceKind::FeedbackTexture2DArray; + } + // Make sure to update HLSLResourceAttr::ResourceKind when add new Kind to + // hlsl::ResourceKind. Assume FeedbackTexture2DArray is the last enum for + // HLSLResourceAttr::ResourceKind. + static_assert( + static_cast( + HLSLResourceAttr::ResourceKind::FeedbackTexture2DArray) == + (static_cast(llvm::hlsl::ResourceKind::NumEntries) - 2)); } void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) { @@ -210,26 +284,27 @@ return; HLSLResourceAttr::ResourceClass RC = Attr->getResourceType(); - uint32_t Counter = ResourceCounters[static_cast(RC)]++; - - NamedMDNode *ResourceMD = nullptr; - switch (RC) { - case HLSLResourceAttr::ResourceClass::UAV: - ResourceMD = CGM.getModule().getOrInsertNamedMetadata("hlsl.uavs"); - break; - default: - assert(false && "Unsupported buffer type!"); - return; - } - - assert(ResourceMD != nullptr && - "ResourceMD must have been set by the switch above."); + llvm::hlsl::ResourceKind RK = + castResourceShapeToResourceKind(Attr->getResourceShape()); - auto &Ctx = CGM.getModule().getContext(); - IRBuilder<> B(Ctx); QualType QT(Ty, 0); - llvm::hlsl::FrontendResource Res(GV, QT.getAsString(), Counter); - ResourceMD->addOperand(Res.getMetadata()); + BufferResBinding Binding(D->getAttr()); + addBufferResourceAnnotation( + GV, QT.getAsString(), static_cast(RC), RK, Binding); +} + +CGHLSLRuntime::BufferResBinding::BufferResBinding( + HLSLResourceBindingAttr *Binding) { + if (Binding) { + llvm::APInt RegInt(64, 0); + Binding->getSlot().substr(1).getAsInteger(10, RegInt); + Reg = RegInt.getLimitedValue(); + llvm::APInt SpaceInt(64, 0); + Binding->getSpace().substr(5).getAsInteger(10, SpaceInt); + Space = SpaceInt.getLimitedValue(); + } else { + Space = 0; + } } void clang::CodeGen::CGHLSLRuntime::setHLSLEntryAttributes( diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-annotations.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-annotations.hlsl --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-annotations.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-annotations.hlsl @@ -3,10 +3,22 @@ RWBuffer Buffer1; RWBuffer > BufferArray[4]; +RWBuffer Buffer2 : register(u3); +RWBuffer > BufferArray2[4] : register(u4); + +RWBuffer Buffer3 : register(u3, space1); +RWBuffer > BufferArray3[4] : register(u4, space1); + + + [numthreads(1,1,1)] void main() { } -// CHECK: !hlsl.uavs = !{![[Single:[0-9]+]], ![[Array:[0-9]+]]} -// CHECK-DAG: ![[Single]] = !{ptr @"?Buffer1@@3V?$RWBuffer@M@hlsl@@A", !"RWBuffer", i32 0} -// CHECK-DAG: ![[Array]] = !{ptr @"?BufferArray@@3PAV?$RWBuffer@T?$__vector@M$03@__clang@@@hlsl@@A", !"RWBuffer >", i32 1} +// CHECK: !hlsl.uavs = !{![[Single:[0-9]+]], ![[Array:[0-9]+]], ![[SingleAllocated:[0-9]+]], ![[ArrayAllocated:[0-9]+]], ![[SingleSpace:[0-9]+]], ![[ArraySpace:[0-9]+]]} +// CHECK-DAG: ![[Single]] = !{ptr @"?Buffer1@@3V?$RWBuffer@M@hlsl@@A", !"RWBuffer", i32 0, i32 10, i32 -1, i32 0} +// CHECK-DAG: ![[Array]] = !{ptr @"?BufferArray@@3PAV?$RWBuffer@T?$__vector@M$03@__clang@@@hlsl@@A", !"RWBuffer >", i32 1, i32 10, i32 -1, i32 0} +// CHECK-DAG: ![[SingleAllocated]] = !{ptr @"?Buffer2@@3V?$RWBuffer@M@hlsl@@A", !"RWBuffer", i32 2, i32 10, i32 3, i32 0} +// CHECK-DAG: ![[ArrayAllocated]] = !{ptr @"?BufferArray2@@3PAV?$RWBuffer@T?$__vector@M$03@__clang@@@hlsl@@A", !"RWBuffer >", i32 3, i32 10, i32 4, i32 0} +// CHECK-DAG: ![[SingleSpace]] = !{ptr @"?Buffer3@@3V?$RWBuffer@M@hlsl@@A", !"RWBuffer", i32 4, i32 10, i32 3, i32 1} +// CHECK-DAG: ![[ArraySpace]] = !{ptr @"?BufferArray3@@3PAV?$RWBuffer@T?$__vector@M$03@__clang@@@hlsl@@A", !"RWBuffer >", i32 5, i32 10, i32 4, i32 1} diff --git a/clang/test/CodeGenHLSL/cbuf.hlsl b/clang/test/CodeGenHLSL/cbuf.hlsl --- a/clang/test/CodeGenHLSL/cbuf.hlsl +++ b/clang/test/CodeGenHLSL/cbuf.hlsl @@ -3,7 +3,7 @@ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s // CHECK: @[[CB:.+]] = external constant { float, double } -cbuffer A : register(b0, space1) { +cbuffer A : register(b0, space2) { float a; double b; } @@ -21,3 +21,8 @@ // CHECK: load double, ptr getelementptr inbounds ({ float, double }, ptr @[[TB]], i32 0, i32 1), align 8 return a + b + c*d; } + +// CHECK: !hlsl.cbufs = !{![[CBMD:[0-9]+]]} +// CHECK: !hlsl.srvs = !{![[TBMD:[0-9]+]]} +// CHECK: ![[CBMD]] = !{ptr @[[CB]], !"A.cb.ty", i32 0, i32 13, i32 0, i32 2} +// CHECK: ![[TBMD]] = !{ptr @[[TB]], !"A.tb.ty", i32 0, i32 15, i32 2, i32 1} diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLResource.h b/llvm/include/llvm/Frontend/HLSL/HLSLResource.h --- a/llvm/include/llvm/Frontend/HLSL/HLSLResource.h +++ b/llvm/include/llvm/Frontend/HLSL/HLSLResource.h @@ -21,20 +21,48 @@ namespace hlsl { +// The value ordering of this enumeration is part of the DXIL ABI. Elements +// can only be added to the end, and not removed. +enum class ResourceKind : uint32_t { + Invalid = 0, + Texture1D, + Texture2D, + Texture2DMS, + Texture3D, + TextureCube, + Texture1DArray, + Texture2DArray, + Texture2DMSArray, + TextureCubeArray, + TypedBuffer, + RawBuffer, + StructuredBuffer, + CBuffer, + Sampler, + TBuffer, + RTAccelerationStructure, + FeedbackTexture2D, + FeedbackTexture2DArray, + NumEntries, +}; + class FrontendResource { MDNode *Entry; public: FrontendResource(MDNode *E) : Entry(E) { - assert(Entry->getNumOperands() == 3 && "Unexpected metadata shape"); + assert(Entry->getNumOperands() == 6 && "Unexpected metadata shape"); } - FrontendResource(GlobalVariable *GV, StringRef TypeStr, uint32_t Counter); + FrontendResource(GlobalVariable *GV, StringRef TypeStr, uint32_t Counter, + ResourceKind RK, uint32_t ResIndex, uint32_t Space); GlobalVariable *getGlobalVariable(); StringRef getSourceType(); Constant *getID(); - + uint32_t getResourceKind(); + uint32_t getResourceIndex(); + uint32_t getSpace(); MDNode *getMetadata() { return Entry; } }; } // namespace hlsl diff --git a/llvm/lib/Frontend/HLSL/HLSLResource.cpp b/llvm/lib/Frontend/HLSL/HLSLResource.cpp --- a/llvm/lib/Frontend/HLSL/HLSLResource.cpp +++ b/llvm/lib/Frontend/HLSL/HLSLResource.cpp @@ -31,11 +31,31 @@ return cast(Entry->getOperand(2))->getValue(); } +uint32_t FrontendResource::FrontendResource::getResourceKind() { + return cast( + cast(Entry->getOperand(3))->getValue()) + ->getLimitedValue(); +} +uint32_t FrontendResource::getResourceIndex() { + return cast( + cast(Entry->getOperand(4))->getValue()) + ->getLimitedValue(); +} +uint32_t FrontendResource::getSpace() { + return cast( + cast(Entry->getOperand(5))->getValue()) + ->getLimitedValue(); +} + FrontendResource::FrontendResource(GlobalVariable *GV, StringRef TypeStr, - uint32_t Counter) { + uint32_t Counter, ResourceKind RK, + uint32_t ResIndex, uint32_t Space) { auto &Ctx = GV->getContext(); IRBuilder<> B(Ctx); - Entry = - MDNode::get(Ctx, {ValueAsMetadata::get(GV), MDString::get(Ctx, TypeStr), - ConstantAsMetadata::get(B.getInt32(Counter))}); + Entry = MDNode::get( + Ctx, {ValueAsMetadata::get(GV), MDString::get(Ctx, TypeStr), + ConstantAsMetadata::get(B.getInt32(Counter)), + ConstantAsMetadata::get(B.getInt32(static_cast(RK))), + ConstantAsMetadata::get(B.getInt32(ResIndex)), + ConstantAsMetadata::get(B.getInt32(Space))}); } 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,41 @@ +//===- 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 +#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(); + uint32_t 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,132 @@ +//===- 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; + uint32_t Size; + std::pair getElementLegacyOffset(unsigned Idx) const { + assert(Idx < Offsets.size() && "Invalid element idx!"); + unsigned Offset = Offsets[Idx]; + unsigned Ch = Offset & (RowAlign - 1); + return std::make_pair((Offset - Ch) / RowAlign, Ch); + } + }; + +public: + LegacyCBufferLayout(const DataLayout &DL) : DL(DL) {} + uint32_t getTypeAllocSizeInBytes(Type *Ty); + +private: + unsigned applyRowAlign(unsigned Offset, Type *EltTy); + unsigned getTypeAllocSize(Type *Ty); + LegacyStructLayout &getStructLayout(StructType *ST); + const DataLayout &DL; + SmallDenseMap StructLayouts; + // 4 Dwords align. + static const unsigned RowAlign = 16; + static unsigned align(unsigned Offset, unsigned Alignment) { + return (Offset + Alignment - 1) / Alignment * Alignment; + } + static unsigned alignTo4Dwords(unsigned Offset) { + return align(Offset, RowAlign); + } +}; + +uint32_t LegacyCBufferLayout::getTypeAllocSizeInBytes(Type *Ty) { + return getTypeAllocSize(Ty); +} + +unsigned LegacyCBufferLayout::applyRowAlign(unsigned Offset, Type *EltTy) { + unsigned AlignedOffset = alignTo4Dwords(Offset); + + if (AlignedOffset == Offset) + return Offset; + + if (isa(EltTy) || isa(EltTy)) + return AlignedOffset; + unsigned Size = DL.getTypeStoreSize(EltTy); + if ((Offset + Size) > AlignedOffset) + return AlignedOffset; + else + return Offset; +} + +unsigned 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 0; + + unsigned EltSize = getTypeAllocSize(AT->getElementType()); + unsigned AlignedEltSize = alignTo4Dwords(EltSize); + // Each new element start 4 dwords aligned. + return 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; + + unsigned Offset = 0; + LegacyStructLayout Layout; + Layout.ST = ST; + for (Type *EltTy : ST->elements()) { + unsigned EltSize = getTypeAllocSize(EltTy); + if (unsigned ScalarSize = EltTy->getScalarSizeInBits()) + Offset = align(Offset, ScalarSize >> 3); + Offset = applyRowAlign(Offset, EltTy); + Layout.Offsets.emplace_back(Offset); + Offset += 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; + +uint32_t 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 @@ -26,6 +26,7 @@ class GlobalVariable; namespace dxil { +class CBufferDataLayout; class ResourceBase { protected: @@ -40,32 +41,7 @@ void write(LLVMContext &Ctx, MutableArrayRef Entries) const; void print(raw_ostream &O, StringRef IDPrefix, StringRef BindingPrefix) const; - - // The value ordering of this enumeration is part of the DXIL ABI. Elements - // can only be added to the end, and not removed. - enum class Kinds : uint32_t { - Invalid = 0, - Texture1D, - Texture2D, - Texture2DMS, - Texture3D, - TextureCube, - Texture1DArray, - Texture2DArray, - Texture2DMSArray, - TextureCubeArray, - TypedBuffer, - RawBuffer, - StructuredBuffer, - CBuffer, - Sampler, - TBuffer, - RTAccelerationStructure, - FeedbackTexture2D, - FeedbackTexture2DArray, - NumEntries, - }; - + using Kinds = hlsl::ResourceKind; static StringRef getKindName(Kinds Kind); static void printKind(Kinds Kind, unsigned Alignment, raw_ostream &OS, bool SRV = false, bool HasCounter = false, @@ -133,14 +109,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(0), LowerBound(0), - RangeSize(1) { - if (auto *ArrTy = dyn_cast(GV->getInitializer()->getType())) + : ID(I), GV(R.getGlobalVariable()), Name(""), Space(R.getSpace()), + LowerBound(R.getResourceIndex()), RangeSize(1) { + if (auto *ArrTy = dyn_cast(GV->getValueType())) RangeSize = ArrTy->getNumElements(); } @@ -210,8 +231,9 @@ } UAVResource::UAVResource(uint32_t I, FrontendResource R) - : ResourceBase(I, R), Shape(Kinds::Invalid), GloballyCoherent(false), - HasCounter(false), IsROV(false), ExtProps() { + : ResourceBase(I, R), + Shape(static_cast(R.getResourceKind())), + GloballyCoherent(false), HasCounter(false), IsROV(false), ExtProps() { parseSourceType(R.getSourceType()); } @@ -275,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; @@ -314,21 +360,39 @@ 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); NamedMDNode *DXResMD = M.getOrInsertNamedMetadata("dx.resources"); DXResMD->addOperand(MDNode::get(M.getContext(), ResourceMDs)); - - NamedMDNode *Entry = M.getNamedMetadata("hlsl.uavs"); - if (Entry) - Entry->eraseFromParent(); } void Resources::print(raw_ostream &O) const { @@ -340,8 +404,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/UAVMetadata.ll b/llvm/test/CodeGen/DirectX/UAVMetadata.ll --- a/llvm/test/CodeGen/DirectX/UAVMetadata.ll +++ b/llvm/test/CodeGen/DirectX/UAVMetadata.ll @@ -13,15 +13,15 @@ ; PRINT-NEXT:; Name Type Format Dim ID HLSL Bind Count ; PRINT-NEXT:; ------------------------------ ---------- ------- ----------- ------- -------------- ------ ; PRINT-NEXT:; UAV f16 buf U0 u0 1 -; PRINT-NEXT:; UAV f32 buf U1 u0 1 -; PRINT-NEXT:; UAV f64 buf U2 u0 1 -; PRINT-NEXT:; UAV i1 buf U3 u0 2 -; PRINT-NEXT:; UAV byte r/w U4 u0 1 -; PRINT-NEXT:; UAV struct r/w U5 u0 1 -; PRINT-NEXT:; UAV i32 buf U6 u0 1 -; PRINT-NEXT:; UAV struct r/w U7 u0 1 -; PRINT-NEXT:; UAV byte r/w U8 u0 1 -; PRINT-NEXT:; UAV u64 buf U9 u0 1 +; PRINT-NEXT:; UAV f32 buf U1 u1 1 +; PRINT-NEXT:; UAV f64 buf U2 u2 1 +; PRINT-NEXT:; UAV i1 buf U3 u3 2 +; PRINT-NEXT:; UAV byte r/w U4 u5 1 +; PRINT-NEXT:; UAV struct r/w U5 u6 1 +; PRINT-NEXT:; UAV i32 buf U6 u7 1 +; PRINT-NEXT:; UAV struct r/w U7 u8 1 +; PRINT-NEXT:; UAV byte r/w U8 u9 1 +; PRINT-NEXT:; UAV u64 buf U9 u10,space2 1 @Zero = local_unnamed_addr global %"class.hlsl::RWBuffer" zeroinitializer, align 4 @One = local_unnamed_addr global %"class.hlsl::RWBuffer" zeroinitializer, align 4 @@ -37,16 +37,16 @@ !hlsl.uavs = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9} -!0 = !{ptr @Zero, !"RWBuffer", i32 0} -!1 = !{ptr @One, !"Buffer>", i32 1} -!2 = !{ptr @Two, !"Buffer", i32 2} -!3 = !{ptr @Three, !"Buffer", i32 3} -!4 = !{ptr @Four, !"ByteAddressBuffer", i32 4} -!5 = !{ptr @Five, !"StructuredBuffer", i32 5} -!6 = !{ptr @Six, !"RasterizerOrderedBuffer", i32 6} -!7 = !{ptr @Seven, !"RasterizerOrderedStructuredBuffer", i32 7} -!8 = !{ptr @Eight, !"RasterizerOrderedByteAddressBuffer", i32 8} -!9 = !{ptr @Nine, !"RWBuffer", i32 9} +!0 = !{ptr @Zero, !"RWBuffer", i32 0, i32 10, i32 0, i32 0} +!1 = !{ptr @One, !"Buffer>", i32 1, i32 10, i32 1, i32 0} +!2 = !{ptr @Two, !"Buffer", i32 2, i32 10, i32 2, i32 0} +!3 = !{ptr @Three, !"Buffer", i32 3, i32 10, i32 3, i32 0} +!4 = !{ptr @Four, !"ByteAddressBuffer", i32 4, i32 11, i32 5, i32 0} +!5 = !{ptr @Five, !"StructuredBuffer", i32 5, i32 12, i32 6, i32 0} +!6 = !{ptr @Six, !"RasterizerOrderedBuffer", i32 6, i32 10, i32 7, i32 0} +!7 = !{ptr @Seven, !"RasterizerOrderedStructuredBuffer", i32 7, i32 12, i32 8, i32 0} +!8 = !{ptr @Eight, !"RasterizerOrderedByteAddressBuffer", i32 8, i32 11, i32 9, i32 0} +!9 = !{ptr @Nine, !"RWBuffer", i32 9, i32 10, i32 10, i32 2} ; CHECK: !dx.resources = !{[[ResList:[!][0-9]+]]} @@ -57,21 +57,21 @@ ; CHECK-SAME: [[Eight:[!][0-9]+]], [[Nine:[!][0-9]+]]} ; CHECK: [[Zero]] = !{i32 0, ptr @Zero, !"", i32 0, i32 0, i32 1, i32 10, i1 false, i1 false, i1 false, [[Half:[!][0-9]+]]} ; CHECK: [[Half]] = !{i32 0, i32 8} -; CHECK: [[One]] = !{i32 1, ptr @One, !"", i32 0, i32 0, i32 1, i32 10, i1 false, i1 false, i1 false, [[Float:[!][0-9]+]]} +; CHECK: [[One]] = !{i32 1, ptr @One, !"", i32 0, i32 1, i32 1, i32 10, i1 false, i1 false, i1 false, [[Float:[!][0-9]+]]} ; CHECK: [[Float]] = !{i32 0, i32 9} -; CHECK: [[Two]] = !{i32 2, ptr @Two, !"", i32 0, i32 0, i32 1, i32 10, i1 false, i1 false, i1 false, [[Double:[!][0-9]+]]} +; CHECK: [[Two]] = !{i32 2, ptr @Two, !"", i32 0, i32 2, i32 1, i32 10, i1 false, i1 false, i1 false, [[Double:[!][0-9]+]]} ; CHECK: [[Double]] = !{i32 0, i32 10} -; CHECK: [[Three]] = !{i32 3, ptr @Three, !"", i32 0, i32 0, i32 2, i32 10, i1 false, i1 false, i1 false, [[Bool:[!][0-9]+]]} +; CHECK: [[Three]] = !{i32 3, ptr @Three, !"", i32 0, i32 3, i32 2, i32 10, i1 false, i1 false, i1 false, [[Bool:[!][0-9]+]]} ; CHECK: [[Bool]] = !{i32 0, i32 1} -; CHECK: [[Four]] = !{i32 4, ptr @Four, !"", i32 0, i32 0, i32 1, i32 11, i1 false, i1 false, i1 false, [[I16:[!][0-9]+]]} +; CHECK: [[Four]] = !{i32 4, ptr @Four, !"", i32 0, i32 5, i32 1, i32 11, i1 false, i1 false, i1 false, [[I16:[!][0-9]+]]} ; CHECK: [[I16]] = !{i32 0, i32 2} -; CHECK: [[Five]] = !{i32 5, ptr @Five, !"", i32 0, i32 0, i32 1, i32 12, i1 false, i1 false, i1 false, [[U16:[!][0-9]+]]} +; CHECK: [[Five]] = !{i32 5, ptr @Five, !"", i32 0, i32 6, i32 1, i32 12, i1 false, i1 false, i1 false, [[U16:[!][0-9]+]]} ; CHECK: [[U16]] = !{i32 0, i32 3} -; CHECK: [[Six]] = !{i32 6, ptr @Six, !"", i32 0, i32 0, i32 1, i32 10, i1 false, i1 false, i1 true, [[I32:[!][0-9]+]]} +; CHECK: [[Six]] = !{i32 6, ptr @Six, !"", i32 0, i32 7, i32 1, i32 10, i1 false, i1 false, i1 true, [[I32:[!][0-9]+]]} ; CHECK: [[I32]] = !{i32 0, i32 4} -; CHECK: [[Seven]] = !{i32 7, ptr @Seven, !"", i32 0, i32 0, i32 1, i32 12, i1 false, i1 false, i1 true, [[U32:[!][0-9]+]]} +; CHECK: [[Seven]] = !{i32 7, ptr @Seven, !"", i32 0, i32 8, i32 1, i32 12, i1 false, i1 false, i1 true, [[U32:[!][0-9]+]]} ; CHECK: [[U32]] = !{i32 0, i32 5} -; CHECK: [[Eight]] = !{i32 8, ptr @Eight, !"", i32 0, i32 0, i32 1, i32 11, i1 false, i1 false, i1 true, [[I64:[!][0-9]+]]} +; CHECK: [[Eight]] = !{i32 8, ptr @Eight, !"", i32 0, i32 9, i32 1, i32 11, i1 false, i1 false, i1 true, [[I64:[!][0-9]+]]} ; CHECK: [[I64]] = !{i32 0, i32 6} -; CHECK: [[Nine]] = !{i32 9, ptr @Nine, !"", i32 0, i32 0, i32 1, i32 10, i1 false, i1 false, i1 false, [[U64:[!][0-9]+]]} +; CHECK: [[Nine]] = !{i32 9, ptr @Nine, !"", i32 2, i32 10, i32 1, i32 10, i1 false, i1 false, i1 false, [[U64:[!][0-9]+]]} ; CHECK: [[U64]] = !{i32 0, i32 7} 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 0, 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 0, 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 0, 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 0, i32 13, i32 1, i32 0} +!1 = !{ptr @B.cb..1, !"B.cb.ty", i32 1, 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 0, i32 13, i32 1, i32 0}