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}; 28bdd1243dSDimitry 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: 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; 48bdd1243dSDimitry Andric static TypeSize alignTo4Dwords(TypeSize Offset) { 49bdd1243dSDimitry Andric return alignTo(Offset, RowAlign); 50bdd1243dSDimitry Andric } 51bdd1243dSDimitry Andric }; 52bdd1243dSDimitry Andric 53bdd1243dSDimitry Andric TypeSize LegacyCBufferLayout::getTypeAllocSizeInBytes(Type *Ty) { 54bdd1243dSDimitry Andric return getTypeAllocSize(Ty); 55bdd1243dSDimitry Andric } 56bdd1243dSDimitry Andric 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 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 & 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 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 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