brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · 07cc738 Raw
144 lines · cpp
1//===- HLSLBufferLayoutBuilder.cpp ----------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "HLSLBufferLayoutBuilder.h"10#include "CGHLSLRuntime.h"11#include "CodeGenModule.h"12#include "TargetInfo.h"13#include "clang/AST/Type.h"14#include <climits>15 16//===----------------------------------------------------------------------===//17// Implementation of constant buffer layout common between DirectX and18// SPIR/SPIR-V.19//===----------------------------------------------------------------------===//20 21using namespace clang;22using namespace clang::CodeGen;23 24static const CharUnits CBufferRowSize =25    CharUnits::fromQuantity(llvm::hlsl::CBufferRowSizeInBytes);26 27namespace clang {28namespace CodeGen {29 30llvm::StructType *31HLSLBufferLayoutBuilder::layOutStruct(const RecordType *RT,32                                      const CGHLSLOffsetInfo &OffsetInfo) {33 34  // check if we already have the layout type for this struct35  // TODO: Do we need to check for matching OffsetInfo?36  if (llvm::StructType *Ty = CGM.getHLSLRuntime().getHLSLBufferLayoutType(RT))37    return Ty;38 39  // iterate over all fields of the record, including fields on base classes40  llvm::SmallVector<CXXRecordDecl *> RecordDecls;41  RecordDecls.push_back(RT->castAsCXXRecordDecl());42  while (RecordDecls.back()->getNumBases()) {43    CXXRecordDecl *D = RecordDecls.back();44    assert(D->getNumBases() == 1 &&45           "HLSL doesn't support multiple inheritance");46    RecordDecls.push_back(D->bases_begin()->getType()->castAsCXXRecordDecl());47  }48 49  SmallVector<std::pair<const FieldDecl *, uint32_t>> FieldsWithOffset;50  unsigned OffsetIdx = 0;51  for (const CXXRecordDecl *RD : llvm::reverse(RecordDecls))52    for (const auto *FD : RD->fields())53      FieldsWithOffset.emplace_back(FD, OffsetInfo[OffsetIdx++]);54 55  if (!OffsetInfo.empty())56    llvm::stable_sort(FieldsWithOffset, [](const auto &LHS, const auto &RHS) {57      return CGHLSLOffsetInfo::compareOffsets(LHS.second, RHS.second);58    });59 60  SmallVector<llvm::Type *> Layout;61  CharUnits CurrentOffset = CharUnits::Zero();62  for (auto &[FD, Offset] : FieldsWithOffset) {63    llvm::Type *LayoutType = layOutType(FD->getType());64 65    const llvm::DataLayout &DL = CGM.getDataLayout();66    CharUnits Size =67        CharUnits::fromQuantity(DL.getTypeSizeInBits(LayoutType) / 8);68    CharUnits Align = CharUnits::fromQuantity(DL.getABITypeAlign(LayoutType));69 70    if (LayoutType->isAggregateType() ||71        (CurrentOffset % CBufferRowSize) + Size > CBufferRowSize)72      Align = Align.alignTo(CBufferRowSize);73 74    CharUnits NextOffset = CurrentOffset.alignTo(Align);75 76    if (Offset != CGHLSLOffsetInfo::Unspecified) {77      CharUnits PackOffset = CharUnits::fromQuantity(Offset);78      assert(PackOffset >= NextOffset &&79             "Offset is invalid - would overlap with previous object");80      NextOffset = PackOffset;81    }82 83    if (NextOffset > CurrentOffset) {84      llvm::Type *Padding = CGM.getTargetCodeGenInfo().getHLSLPadding(85          CGM, NextOffset - CurrentOffset);86      assert(Padding && "No padding type for target?");87      Layout.emplace_back(Padding);88      CurrentOffset = NextOffset;89    }90    Layout.emplace_back(LayoutType);91    CurrentOffset += Size;92  }93 94  // Create the layout struct type; anonymous structs have empty name but95  // non-empty qualified name96  const auto *Decl = RT->castAsCXXRecordDecl();97  std::string Name =98      Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString();99 100  llvm::StructType *NewTy = llvm::StructType::create(Layout, Name,101                                                     /*isPacked=*/true);102  CGM.getHLSLRuntime().addHLSLBufferLayoutType(RT, NewTy);103  return NewTy;104}105 106llvm::Type *HLSLBufferLayoutBuilder::layOutArray(const ConstantArrayType *AT) {107  llvm::Type *EltTy = layOutType(AT->getElementType());108  uint64_t Count = AT->getZExtSize();109 110  CharUnits EltSize =111      CharUnits::fromQuantity(CGM.getDataLayout().getTypeSizeInBits(EltTy) / 8);112  CharUnits Padding = EltSize.alignTo(CBufferRowSize) - EltSize;113 114  // If we don't have any padding between elements then we just need the array115  // itself.116  if (Count < 2 || Padding.isZero())117    return llvm::ArrayType::get(EltTy, Count);118 119  llvm::LLVMContext &Context = CGM.getLLVMContext();120  llvm::Type *PaddingTy =121      CGM.getTargetCodeGenInfo().getHLSLPadding(CGM, Padding);122  assert(PaddingTy && "No padding type for target?");123  auto *PaddedEltTy =124      llvm::StructType::get(Context, {EltTy, PaddingTy}, /*isPacked=*/true);125  return llvm::StructType::get(126      Context, {llvm::ArrayType::get(PaddedEltTy, Count - 1), EltTy},127      /*IsPacked=*/true);128}129 130llvm::Type *HLSLBufferLayoutBuilder::layOutType(QualType Ty) {131  if (const auto *AT = CGM.getContext().getAsConstantArrayType(Ty))132    return layOutArray(AT);133 134  if (Ty->isStructureOrClassType()) {135    CGHLSLOffsetInfo EmptyOffsets;136    return layOutStruct(Ty->getAsCanonical<RecordType>(), EmptyOffsets);137  }138 139  return CGM.getTypes().ConvertTypeForMem(Ty);140}141 142} // namespace CodeGen143} // namespace clang144