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