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