CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
163 lines
5.9 KiB
C++
163 lines
5.9 KiB
C++
//===- HLSLBufferLayoutBuilder.cpp ----------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "HLSLBufferLayoutBuilder.h"
|
|
#include "CGHLSLRuntime.h"
|
|
#include "CodeGenModule.h"
|
|
#include "TargetInfo.h"
|
|
#include "clang/AST/Type.h"
|
|
#include <climits>
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Implementation of constant buffer layout common between DirectX and
|
|
// SPIR/SPIR-V.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
using namespace clang;
|
|
using namespace clang::CodeGen;
|
|
|
|
static const CharUnits CBufferRowSize =
|
|
CharUnits::fromQuantity(llvm::hlsl::CBufferRowSizeInBytes);
|
|
|
|
namespace clang {
|
|
namespace CodeGen {
|
|
|
|
llvm::StructType *
|
|
HLSLBufferLayoutBuilder::layOutStruct(const RecordType *RT,
|
|
const CGHLSLOffsetInfo &OffsetInfo) {
|
|
|
|
// check if we already have the layout type for this struct
|
|
// TODO: Do we need to check for matching OffsetInfo?
|
|
if (llvm::StructType *Ty = CGM.getHLSLRuntime().getHLSLBufferLayoutType(RT))
|
|
return Ty;
|
|
|
|
// iterate over all fields of the record, including fields on base classes
|
|
llvm::SmallVector<CXXRecordDecl *> RecordDecls;
|
|
RecordDecls.push_back(RT->castAsCXXRecordDecl());
|
|
while (RecordDecls.back()->getNumBases()) {
|
|
CXXRecordDecl *D = RecordDecls.back();
|
|
assert(D->getNumBases() == 1 &&
|
|
"HLSL doesn't support multiple inheritance");
|
|
RecordDecls.push_back(D->bases_begin()->getType()->castAsCXXRecordDecl());
|
|
}
|
|
|
|
SmallVector<std::pair<const FieldDecl *, uint32_t>> FieldsWithOffset;
|
|
unsigned OffsetIdx = 0;
|
|
for (const CXXRecordDecl *RD : llvm::reverse(RecordDecls))
|
|
for (const auto *FD : RD->fields())
|
|
FieldsWithOffset.emplace_back(FD, OffsetInfo[OffsetIdx++]);
|
|
|
|
if (!OffsetInfo.empty())
|
|
llvm::stable_sort(FieldsWithOffset, [](const auto &LHS, const auto &RHS) {
|
|
return CGHLSLOffsetInfo::compareOffsets(LHS.second, RHS.second);
|
|
});
|
|
|
|
SmallVector<llvm::Type *> Layout;
|
|
CharUnits CurrentOffset = CharUnits::Zero();
|
|
for (auto &[FD, Offset] : FieldsWithOffset) {
|
|
llvm::Type *LayoutType = layOutType(FD->getType());
|
|
|
|
const llvm::DataLayout &DL = CGM.getDataLayout();
|
|
CharUnits Size =
|
|
CharUnits::fromQuantity(DL.getTypeSizeInBits(LayoutType) / 8);
|
|
CharUnits Align = CharUnits::fromQuantity(DL.getABITypeAlign(LayoutType));
|
|
|
|
if (LayoutType->isAggregateType() ||
|
|
(CurrentOffset % CBufferRowSize) + Size > CBufferRowSize)
|
|
Align = Align.alignTo(CBufferRowSize);
|
|
|
|
CharUnits NextOffset = CurrentOffset.alignTo(Align);
|
|
|
|
if (Offset != CGHLSLOffsetInfo::Unspecified) {
|
|
CharUnits PackOffset = CharUnits::fromQuantity(Offset);
|
|
assert(PackOffset >= NextOffset &&
|
|
"Offset is invalid - would overlap with previous object");
|
|
NextOffset = PackOffset;
|
|
}
|
|
|
|
if (NextOffset > CurrentOffset) {
|
|
llvm::Type *Padding = CGM.getTargetCodeGenInfo().getHLSLPadding(
|
|
CGM, NextOffset - CurrentOffset);
|
|
assert(Padding && "No padding type for target?");
|
|
Layout.emplace_back(Padding);
|
|
CurrentOffset = NextOffset;
|
|
}
|
|
Layout.emplace_back(LayoutType);
|
|
CurrentOffset += Size;
|
|
}
|
|
|
|
// Create the layout struct type; anonymous structs have empty name but
|
|
// non-empty qualified name
|
|
const auto *Decl = RT->castAsCXXRecordDecl();
|
|
std::string Name =
|
|
Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString();
|
|
|
|
llvm::StructType *NewTy = llvm::StructType::create(Layout, Name,
|
|
/*isPacked=*/true);
|
|
CGM.getHLSLRuntime().addHLSLBufferLayoutType(RT, NewTy);
|
|
return NewTy;
|
|
}
|
|
|
|
llvm::Type *HLSLBufferLayoutBuilder::padArrayElements(llvm::Type *EltTy,
|
|
uint64_t Count) {
|
|
CharUnits EltSize =
|
|
CharUnits::fromQuantity(CGM.getDataLayout().getTypeSizeInBits(EltTy) / 8);
|
|
CharUnits Padding = EltSize.alignTo(CBufferRowSize) - EltSize;
|
|
|
|
// If we don't have any padding between elements then we just need the array
|
|
// itself.
|
|
if (Count < 2 || Padding.isZero())
|
|
return llvm::ArrayType::get(EltTy, Count);
|
|
|
|
llvm::LLVMContext &Context = CGM.getLLVMContext();
|
|
llvm::Type *PaddingTy =
|
|
CGM.getTargetCodeGenInfo().getHLSLPadding(CGM, Padding);
|
|
assert(PaddingTy && "No padding type for target?");
|
|
auto *PaddedEltTy =
|
|
llvm::StructType::get(Context, {EltTy, PaddingTy}, /*isPacked=*/true);
|
|
return llvm::StructType::get(
|
|
Context, {llvm::ArrayType::get(PaddedEltTy, Count - 1), EltTy},
|
|
/*IsPacked=*/true);
|
|
}
|
|
|
|
llvm::Type *HLSLBufferLayoutBuilder::layOutArray(const ConstantArrayType *AT) {
|
|
llvm::Type *EltTy = layOutType(AT->getElementType());
|
|
uint64_t Count = AT->getZExtSize();
|
|
return padArrayElements(EltTy, Count);
|
|
}
|
|
|
|
llvm::Type *
|
|
HLSLBufferLayoutBuilder::layOutMatrix(const ConstantMatrixType *MT) {
|
|
// ConvertTypeForMem already handles row/column-major layout and bool
|
|
// promotion, producing [Count x <VecLen x EltTy>]. We just need to add
|
|
// cbuffer padding between the array elements.
|
|
llvm::ArrayType *MemTy =
|
|
cast<llvm::ArrayType>(CGM.getTypes().ConvertTypeForMem(QualType(MT, 0)));
|
|
return padArrayElements(MemTy->getElementType(), MemTy->getNumElements());
|
|
}
|
|
|
|
llvm::Type *HLSLBufferLayoutBuilder::layOutType(QualType Ty) {
|
|
if (const auto *AT = CGM.getContext().getAsConstantArrayType(Ty))
|
|
return layOutArray(AT);
|
|
|
|
if (Ty->isStructureOrClassType()) {
|
|
CGHLSLOffsetInfo EmptyOffsets;
|
|
return layOutStruct(Ty->getAsCanonical<RecordType>(), EmptyOffsets);
|
|
}
|
|
|
|
if (Ty->isConstantMatrixType()) {
|
|
const auto *MT = Ty->castAs<ConstantMatrixType>();
|
|
return layOutMatrix(MT);
|
|
}
|
|
|
|
return CGM.getTypes().ConvertTypeForMem(Ty);
|
|
}
|
|
|
|
} // namespace CodeGen
|
|
} // namespace clang
|