1944f4b28SXiang Li //===- Target/DirectX/CBufferDataLayout.cpp - Cbuffer layout helper -------===//
2944f4b28SXiang Li //
3944f4b28SXiang Li // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4944f4b28SXiang Li // See https://llvm.org/LICENSE.txt for license information.
5944f4b28SXiang Li // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6944f4b28SXiang Li //
7944f4b28SXiang Li //===----------------------------------------------------------------------===//
8944f4b28SXiang Li //
9944f4b28SXiang Li // Utils to help cbuffer layout.
10944f4b28SXiang Li //
11944f4b28SXiang Li //===----------------------------------------------------------------------===//
12944f4b28SXiang Li
13944f4b28SXiang Li #include "CBufferDataLayout.h"
14944f4b28SXiang Li
15944f4b28SXiang Li #include "llvm/IR/DerivedTypes.h"
16944f4b28SXiang Li #include "llvm/IR/IRBuilder.h"
17944f4b28SXiang Li
18944f4b28SXiang Li namespace llvm {
19944f4b28SXiang Li namespace dxil {
20944f4b28SXiang Li
21944f4b28SXiang Li // Implement cbuffer layout in
22944f4b28SXiang Li // https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
23944f4b28SXiang Li class LegacyCBufferLayout {
24944f4b28SXiang Li struct LegacyStructLayout {
25944f4b28SXiang Li StructType *ST;
26944f4b28SXiang Li SmallVector<uint32_t> Offsets;
27944f4b28SXiang Li TypeSize Size = {0, false};
getElementLegacyOffsetllvm::dxil::LegacyCBufferLayout::LegacyStructLayout28944f4b28SXiang Li std::pair<uint32_t, uint32_t> getElementLegacyOffset(unsigned Idx) const {
29944f4b28SXiang Li assert(Idx < Offsets.size() && "Invalid element idx!");
30944f4b28SXiang Li uint32_t Offset = Offsets[Idx];
31944f4b28SXiang Li uint32_t Ch = Offset & (RowAlign - 1);
32944f4b28SXiang Li return std::make_pair((Offset - Ch) / RowAlign, Ch);
33944f4b28SXiang Li }
34944f4b28SXiang Li };
35944f4b28SXiang Li
36944f4b28SXiang Li public:
LegacyCBufferLayout(const DataLayout & DL)37944f4b28SXiang Li LegacyCBufferLayout(const DataLayout &DL) : DL(DL) {}
38944f4b28SXiang Li TypeSize getTypeAllocSizeInBytes(Type *Ty);
39944f4b28SXiang Li
40944f4b28SXiang Li private:
41944f4b28SXiang Li TypeSize applyRowAlign(TypeSize Offset, Type *EltTy);
42944f4b28SXiang Li TypeSize getTypeAllocSize(Type *Ty);
43944f4b28SXiang Li LegacyStructLayout &getStructLayout(StructType *ST);
44944f4b28SXiang Li const DataLayout &DL;
45944f4b28SXiang Li SmallDenseMap<StructType *, LegacyStructLayout> StructLayouts;
46944f4b28SXiang Li // 4 Dwords align.
47944f4b28SXiang Li static const uint32_t RowAlign = 16;
alignTo4Dwords(TypeSize Offset)48944f4b28SXiang Li static TypeSize alignTo4Dwords(TypeSize Offset) {
49944f4b28SXiang Li return alignTo(Offset, RowAlign);
50944f4b28SXiang Li }
51944f4b28SXiang Li };
52944f4b28SXiang Li
getTypeAllocSizeInBytes(Type * Ty)53944f4b28SXiang Li TypeSize LegacyCBufferLayout::getTypeAllocSizeInBytes(Type *Ty) {
54944f4b28SXiang Li return getTypeAllocSize(Ty);
55944f4b28SXiang Li }
56944f4b28SXiang Li
applyRowAlign(TypeSize Offset,Type * EltTy)57944f4b28SXiang Li TypeSize LegacyCBufferLayout::applyRowAlign(TypeSize Offset, Type *EltTy) {
58944f4b28SXiang Li TypeSize AlignedOffset = alignTo4Dwords(Offset);
59944f4b28SXiang Li
60944f4b28SXiang Li if (AlignedOffset == Offset)
61944f4b28SXiang Li return Offset;
62944f4b28SXiang Li
63944f4b28SXiang Li if (isa<StructType>(EltTy) || isa<ArrayType>(EltTy))
64944f4b28SXiang Li return AlignedOffset;
65944f4b28SXiang Li TypeSize Size = DL.getTypeStoreSize(EltTy);
66944f4b28SXiang Li if ((Offset + Size) > AlignedOffset)
67944f4b28SXiang Li return AlignedOffset;
68944f4b28SXiang Li else
69944f4b28SXiang Li return Offset;
70944f4b28SXiang Li }
71944f4b28SXiang Li
getTypeAllocSize(Type * Ty)72944f4b28SXiang Li TypeSize LegacyCBufferLayout::getTypeAllocSize(Type *Ty) {
73944f4b28SXiang Li if (auto *ST = dyn_cast<StructType>(Ty)) {
74944f4b28SXiang Li LegacyStructLayout &Layout = getStructLayout(ST);
75944f4b28SXiang Li return Layout.Size;
76944f4b28SXiang Li } else if (auto *AT = dyn_cast<ArrayType>(Ty)) {
77944f4b28SXiang Li unsigned NumElts = AT->getNumElements();
78944f4b28SXiang Li if (NumElts == 0)
79*81b7f115SSander de Smalen return TypeSize::getFixed(0);
80944f4b28SXiang Li
81944f4b28SXiang Li TypeSize EltSize = getTypeAllocSize(AT->getElementType());
82944f4b28SXiang Li TypeSize AlignedEltSize = alignTo4Dwords(EltSize);
83944f4b28SXiang Li // Each new element start 4 dwords aligned.
84*81b7f115SSander de Smalen return TypeSize::getFixed(AlignedEltSize * (NumElts - 1) + EltSize);
85944f4b28SXiang Li } else {
86944f4b28SXiang Li // NOTE: Use type store size, not align to ABI on basic types for legacy
87944f4b28SXiang Li // layout.
88944f4b28SXiang Li return DL.getTypeStoreSize(Ty);
89944f4b28SXiang Li }
90944f4b28SXiang Li }
91944f4b28SXiang Li
92944f4b28SXiang Li LegacyCBufferLayout::LegacyStructLayout &
getStructLayout(StructType * ST)93944f4b28SXiang Li LegacyCBufferLayout::getStructLayout(StructType *ST) {
94944f4b28SXiang Li auto it = StructLayouts.find(ST);
95944f4b28SXiang Li if (it != StructLayouts.end())
96944f4b28SXiang Li return it->second;
97944f4b28SXiang Li
98*81b7f115SSander de Smalen TypeSize Offset = TypeSize::getFixed(0);
99944f4b28SXiang Li LegacyStructLayout Layout;
100944f4b28SXiang Li Layout.ST = ST;
101944f4b28SXiang Li for (Type *EltTy : ST->elements()) {
102944f4b28SXiang Li TypeSize EltSize = getTypeAllocSize(EltTy);
103944f4b28SXiang Li if (TypeSize ScalarSize = EltTy->getScalarType()->getPrimitiveSizeInBits())
104944f4b28SXiang Li Offset = alignTo(Offset, ScalarSize >> 3);
105944f4b28SXiang Li Offset = applyRowAlign(Offset, EltTy);
106944f4b28SXiang Li Layout.Offsets.emplace_back(Offset);
107944f4b28SXiang Li Offset = Offset.getWithIncrement(EltSize);
108944f4b28SXiang Li }
109944f4b28SXiang Li Layout.Size = Offset;
110944f4b28SXiang Li StructLayouts[ST] = Layout;
111944f4b28SXiang Li return StructLayouts[ST];
112944f4b28SXiang Li }
113944f4b28SXiang Li
CBufferDataLayout(const DataLayout & DL,const bool IsLegacy)114944f4b28SXiang Li CBufferDataLayout::CBufferDataLayout(const DataLayout &DL, const bool IsLegacy)
115944f4b28SXiang Li : DL(DL), IsLegacyLayout(IsLegacy),
116944f4b28SXiang Li LegacyDL(IsLegacy ? std::make_unique<LegacyCBufferLayout>(DL) : nullptr) {
117944f4b28SXiang Li }
118944f4b28SXiang Li
119944f4b28SXiang Li CBufferDataLayout::~CBufferDataLayout() = default;
120944f4b28SXiang Li
getTypeAllocSizeInBytes(Type * Ty)121944f4b28SXiang Li llvm::TypeSize CBufferDataLayout::getTypeAllocSizeInBytes(Type *Ty) {
122944f4b28SXiang Li if (IsLegacyLayout)
123944f4b28SXiang Li return LegacyDL->getTypeAllocSizeInBytes(Ty);
124944f4b28SXiang Li else
125944f4b28SXiang Li return DL.getTypeAllocSize(Ty);
126944f4b28SXiang Li }
127944f4b28SXiang Li
128944f4b28SXiang Li } // namespace dxil
129944f4b28SXiang Li } // namespace llvm
130