1e3b55780SDimitry Andric //===- Target/DirectX/CBufferDataLayout.cpp - Cbuffer layout helper -------===//
2e3b55780SDimitry Andric //
3e3b55780SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e3b55780SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e3b55780SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e3b55780SDimitry Andric //
7e3b55780SDimitry Andric //===----------------------------------------------------------------------===//
8e3b55780SDimitry Andric //
9e3b55780SDimitry Andric // Utils to help cbuffer layout.
10e3b55780SDimitry Andric //
11e3b55780SDimitry Andric //===----------------------------------------------------------------------===//
12e3b55780SDimitry Andric
13e3b55780SDimitry Andric #include "CBufferDataLayout.h"
14e3b55780SDimitry Andric
15e3b55780SDimitry Andric #include "llvm/IR/DerivedTypes.h"
16e3b55780SDimitry Andric #include "llvm/IR/IRBuilder.h"
17e3b55780SDimitry Andric
18e3b55780SDimitry Andric namespace llvm {
19e3b55780SDimitry Andric namespace dxil {
20e3b55780SDimitry Andric
21e3b55780SDimitry Andric // Implement cbuffer layout in
22e3b55780SDimitry Andric // https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
23e3b55780SDimitry Andric class LegacyCBufferLayout {
24e3b55780SDimitry Andric struct LegacyStructLayout {
25e3b55780SDimitry Andric StructType *ST;
26e3b55780SDimitry Andric SmallVector<uint32_t> Offsets;
27e3b55780SDimitry Andric TypeSize Size = {0, false};
getElementLegacyOffsetllvm::dxil::LegacyCBufferLayout::LegacyStructLayout28e3b55780SDimitry Andric std::pair<uint32_t, uint32_t> getElementLegacyOffset(unsigned Idx) const {
29e3b55780SDimitry Andric assert(Idx < Offsets.size() && "Invalid element idx!");
30e3b55780SDimitry Andric uint32_t Offset = Offsets[Idx];
31e3b55780SDimitry Andric uint32_t Ch = Offset & (RowAlign - 1);
32e3b55780SDimitry Andric return std::make_pair((Offset - Ch) / RowAlign, Ch);
33e3b55780SDimitry Andric }
34e3b55780SDimitry Andric };
35e3b55780SDimitry Andric
36e3b55780SDimitry Andric public:
LegacyCBufferLayout(const DataLayout & DL)37e3b55780SDimitry Andric LegacyCBufferLayout(const DataLayout &DL) : DL(DL) {}
38e3b55780SDimitry Andric TypeSize getTypeAllocSizeInBytes(Type *Ty);
39e3b55780SDimitry Andric
40e3b55780SDimitry Andric private:
41e3b55780SDimitry Andric TypeSize applyRowAlign(TypeSize Offset, Type *EltTy);
42e3b55780SDimitry Andric TypeSize getTypeAllocSize(Type *Ty);
43e3b55780SDimitry Andric LegacyStructLayout &getStructLayout(StructType *ST);
44e3b55780SDimitry Andric const DataLayout &DL;
45e3b55780SDimitry Andric SmallDenseMap<StructType *, LegacyStructLayout> StructLayouts;
46e3b55780SDimitry Andric // 4 Dwords align.
47e3b55780SDimitry Andric static const uint32_t RowAlign = 16;
alignTo4Dwords(TypeSize Offset)48e3b55780SDimitry Andric static TypeSize alignTo4Dwords(TypeSize Offset) {
49e3b55780SDimitry Andric return alignTo(Offset, RowAlign);
50e3b55780SDimitry Andric }
51e3b55780SDimitry Andric };
52e3b55780SDimitry Andric
getTypeAllocSizeInBytes(Type * Ty)53e3b55780SDimitry Andric TypeSize LegacyCBufferLayout::getTypeAllocSizeInBytes(Type *Ty) {
54e3b55780SDimitry Andric return getTypeAllocSize(Ty);
55e3b55780SDimitry Andric }
56e3b55780SDimitry Andric
applyRowAlign(TypeSize Offset,Type * EltTy)57e3b55780SDimitry Andric TypeSize LegacyCBufferLayout::applyRowAlign(TypeSize Offset, Type *EltTy) {
58e3b55780SDimitry Andric TypeSize AlignedOffset = alignTo4Dwords(Offset);
59e3b55780SDimitry Andric
60e3b55780SDimitry Andric if (AlignedOffset == Offset)
61e3b55780SDimitry Andric return Offset;
62e3b55780SDimitry Andric
63e3b55780SDimitry Andric if (isa<StructType>(EltTy) || isa<ArrayType>(EltTy))
64e3b55780SDimitry Andric return AlignedOffset;
65e3b55780SDimitry Andric TypeSize Size = DL.getTypeStoreSize(EltTy);
66e3b55780SDimitry Andric if ((Offset + Size) > AlignedOffset)
67e3b55780SDimitry Andric return AlignedOffset;
68e3b55780SDimitry Andric else
69e3b55780SDimitry Andric return Offset;
70e3b55780SDimitry Andric }
71e3b55780SDimitry Andric
getTypeAllocSize(Type * Ty)72e3b55780SDimitry Andric TypeSize LegacyCBufferLayout::getTypeAllocSize(Type *Ty) {
73e3b55780SDimitry Andric if (auto *ST = dyn_cast<StructType>(Ty)) {
74e3b55780SDimitry Andric LegacyStructLayout &Layout = getStructLayout(ST);
75e3b55780SDimitry Andric return Layout.Size;
76e3b55780SDimitry Andric } else if (auto *AT = dyn_cast<ArrayType>(Ty)) {
77e3b55780SDimitry Andric unsigned NumElts = AT->getNumElements();
78e3b55780SDimitry Andric if (NumElts == 0)
79e3b55780SDimitry Andric return TypeSize::getFixed(0);
80e3b55780SDimitry Andric
81e3b55780SDimitry Andric TypeSize EltSize = getTypeAllocSize(AT->getElementType());
82e3b55780SDimitry Andric TypeSize AlignedEltSize = alignTo4Dwords(EltSize);
83e3b55780SDimitry Andric // Each new element start 4 dwords aligned.
84e3b55780SDimitry Andric return TypeSize::getFixed(AlignedEltSize * (NumElts - 1) + EltSize);
85e3b55780SDimitry Andric } else {
86e3b55780SDimitry Andric // NOTE: Use type store size, not align to ABI on basic types for legacy
87e3b55780SDimitry Andric // layout.
88e3b55780SDimitry Andric return DL.getTypeStoreSize(Ty);
89e3b55780SDimitry Andric }
90e3b55780SDimitry Andric }
91e3b55780SDimitry Andric
92e3b55780SDimitry Andric LegacyCBufferLayout::LegacyStructLayout &
getStructLayout(StructType * ST)93e3b55780SDimitry Andric LegacyCBufferLayout::getStructLayout(StructType *ST) {
94e3b55780SDimitry Andric auto it = StructLayouts.find(ST);
95e3b55780SDimitry Andric if (it != StructLayouts.end())
96e3b55780SDimitry Andric return it->second;
97e3b55780SDimitry Andric
98b1c73532SDimitry Andric TypeSize Offset = TypeSize::getFixed(0);
99e3b55780SDimitry Andric LegacyStructLayout Layout;
100e3b55780SDimitry Andric Layout.ST = ST;
101e3b55780SDimitry Andric for (Type *EltTy : ST->elements()) {
102e3b55780SDimitry Andric TypeSize EltSize = getTypeAllocSize(EltTy);
103e3b55780SDimitry Andric if (TypeSize ScalarSize = EltTy->getScalarType()->getPrimitiveSizeInBits())
104e3b55780SDimitry Andric Offset = alignTo(Offset, ScalarSize >> 3);
105e3b55780SDimitry Andric Offset = applyRowAlign(Offset, EltTy);
106e3b55780SDimitry Andric Layout.Offsets.emplace_back(Offset);
107e3b55780SDimitry Andric Offset = Offset.getWithIncrement(EltSize);
108e3b55780SDimitry Andric }
109e3b55780SDimitry Andric Layout.Size = Offset;
110e3b55780SDimitry Andric StructLayouts[ST] = Layout;
111e3b55780SDimitry Andric return StructLayouts[ST];
112e3b55780SDimitry Andric }
113e3b55780SDimitry Andric
CBufferDataLayout(const DataLayout & DL,const bool IsLegacy)114e3b55780SDimitry Andric CBufferDataLayout::CBufferDataLayout(const DataLayout &DL, const bool IsLegacy)
115e3b55780SDimitry Andric : DL(DL), IsLegacyLayout(IsLegacy),
116e3b55780SDimitry Andric LegacyDL(IsLegacy ? std::make_unique<LegacyCBufferLayout>(DL) : nullptr) {
117e3b55780SDimitry Andric }
118e3b55780SDimitry Andric
119e3b55780SDimitry Andric CBufferDataLayout::~CBufferDataLayout() = default;
120e3b55780SDimitry Andric
getTypeAllocSizeInBytes(Type * Ty)121e3b55780SDimitry Andric llvm::TypeSize CBufferDataLayout::getTypeAllocSizeInBytes(Type *Ty) {
122e3b55780SDimitry Andric if (IsLegacyLayout)
123e3b55780SDimitry Andric return LegacyDL->getTypeAllocSizeInBytes(Ty);
124e3b55780SDimitry Andric else
125e3b55780SDimitry Andric return DL.getTypeAllocSize(Ty);
126e3b55780SDimitry Andric }
127e3b55780SDimitry Andric
128e3b55780SDimitry Andric } // namespace dxil
129e3b55780SDimitry Andric } // namespace llvm
130