clang 23.0.0git
HLSLBufferLayoutBuilder.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8
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 and
18// SPIR/SPIR-V.
19//===----------------------------------------------------------------------===//
20
21using namespace clang;
22using namespace clang::CodeGen;
23
25 CharUnits::fromQuantity(llvm::hlsl::CBufferRowSizeInBytes);
26
27namespace clang {
28namespace CodeGen {
29
30llvm::StructType *
32 const CGHLSLOffsetInfo &OffsetInfo) {
33
34 // check if we already have the layout type for this struct
35 // 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 classes
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
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
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 but
95 // non-empty qualified name
96 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::padArrayElements(llvm::Type *EltTy,
107 uint64_t Count) {
108 CharUnits EltSize =
109 CharUnits::fromQuantity(CGM.getDataLayout().getTypeSizeInBits(EltTy) / 8);
110 CharUnits Padding = EltSize.alignTo(CBufferRowSize) - EltSize;
111
112 // If we don't have any padding between elements then we just need the array
113 // itself.
114 if (Count < 2 || Padding.isZero())
115 return llvm::ArrayType::get(EltTy, Count);
116
117 llvm::LLVMContext &Context = CGM.getLLVMContext();
118 llvm::Type *PaddingTy =
119 CGM.getTargetCodeGenInfo().getHLSLPadding(CGM, Padding);
120 assert(PaddingTy && "No padding type for target?");
121 auto *PaddedEltTy =
122 llvm::StructType::get(Context, {EltTy, PaddingTy}, /*isPacked=*/true);
123 return llvm::StructType::get(
124 Context, {llvm::ArrayType::get(PaddedEltTy, Count - 1), EltTy},
125 /*IsPacked=*/true);
126}
127
129 llvm::Type *EltTy = layOutType(AT->getElementType());
130 uint64_t Count = AT->getZExtSize();
131 return padArrayElements(EltTy, Count);
132}
133
134llvm::Type *
136 // ConvertTypeForMem already handles row/column-major layout and bool
137 // promotion, producing [Count x <VecLen x EltTy>]. We just need to add
138 // cbuffer padding between the array elements.
139 llvm::ArrayType *MemTy =
140 cast<llvm::ArrayType>(CGM.getTypes().ConvertTypeForMem(QualType(MT, 0)));
141 return padArrayElements(MemTy->getElementType(), MemTy->getNumElements());
142}
143
145 if (const auto *AT = CGM.getContext().getAsConstantArrayType(Ty))
146 return layOutArray(AT);
147
148 if (Ty->isStructureOrClassType()) {
149 CGHLSLOffsetInfo EmptyOffsets;
150 return layOutStruct(Ty->getAsCanonical<RecordType>(), EmptyOffsets);
151 }
152
153 if (Ty->isConstantMatrixType()) {
154 const auto *MT = Ty->castAs<ConstantMatrixType>();
155 return layOutMatrix(MT);
156 }
157
158 return CGM.getTypes().ConvertTypeForMem(Ty);
159}
160
161} // namespace CodeGen
162} // namespace clang
static const CharUnits CBufferRowSize
C Language Family Type Representation.
QualType getElementType() const
Definition TypeBase.h:3742
QualType getType() const
Retrieves the type of the base class.
Definition DeclCXX.h:249
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
unsigned getNumBases() const
Retrieves the number of base classes of this class.
Definition DeclCXX.h:602
base_class_iterator bases_begin()
Definition DeclCXX.h:615
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
bool isZero() const
isZero - Test whether the quantity equals zero.
Definition CharUnits.h:122
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
CharUnits alignTo(const CharUnits &Align) const
alignTo - Returns the next integer (mod 2**64) that is greater than or equal to this quantity and is ...
Definition CharUnits.h:201
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition CharUnits.h:53
static const uint32_t Unspecified
static bool compareOffsets(uint32_t LHS, uint32_t RHS)
Comparison function for offsets received from operator[] suitable for use in a stable_sort.
const llvm::DataLayout & getDataLayout() const
const TargetCodeGenInfo & getTargetCodeGenInfo()
llvm::LLVMContext & getLLVMContext()
llvm::StructType * layOutStruct(const RecordType *StructType, const CGHLSLOffsetInfo &OffsetInfo)
Lays out a struct type following HLSL buffer rules and considering any explicit offset information.
llvm::Type * layOutArray(const ConstantArrayType *AT)
Lays out an array type following HLSL buffer rules.
llvm::Type * layOutMatrix(const ConstantMatrixType *MT)
Lays out a matrix type following HLSL buffer rules.
llvm::Type * layOutType(QualType Type)
Lays out a type following HLSL buffer rules.
virtual llvm::Type * getHLSLPadding(CodeGenModule &CGM, CharUnits NumBytes) const
Return an LLVM type that corresponds to padding in HLSL types.
Definition TargetInfo.h:433
Represents the canonical version of C arrays with a specified constant size.
Definition TypeBase.h:3768
uint64_t getZExtSize() const
Return the size zero-extended as a uint64_t.
Definition TypeBase.h:3844
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4395
A (possibly-)qualified type.
Definition TypeBase.h:937
CXXRecordDecl * castAsCXXRecordDecl() const
Definition Type.h:36
bool isConstantMatrixType() const
Definition TypeBase.h:8792
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9285
bool isStructureOrClassType() const
Definition Type.cpp:707
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition TypeBase.h:2929
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
Definition CGValue.h:146
The JSON file list parser is used to communicate input to InstallAPI.
U cast(CodeGen::Address addr)
Definition Address.h:327