clang 22.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
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 array
115 // 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
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 CodeGen
143} // namespace clang
static const CharUnits CBufferRowSize
C Language Family Type Representation.
QualType getElementType() const
Definition TypeBase.h:3734
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.
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 * layOutType(QualType Type)
Lays out a type following HLSL buffer rules.
Represents the canonical version of C arrays with a specified constant size.
Definition TypeBase.h:3760
uint64_t getZExtSize() const
Return the size zero-extended as a uint64_t.
Definition TypeBase.h:3836
A (possibly-)qualified type.
Definition TypeBase.h:937
CXXRecordDecl * castAsCXXRecordDecl() const
Definition Type.h:36
bool isStructureOrClassType() const
Definition Type.cpp:706
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition TypeBase.h:2921
@ 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.