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