Skip to content

Commit b62863b

Browse files
committed
Rework cbuffer codegen to use the target("dx.Layout", ...) type
1 parent a8cdd45 commit b62863b

16 files changed

+482
-286
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5034,7 +5034,7 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
50345034
bool IsCBuffer;
50355035
/// HasValidPackoffset - Whether the buffer has valid packoffset annotations
50365036
// on all declarations
5037-
bool HasPackoffset;
5037+
bool HasValidPackoffset;
50385038
// LayoutStruct - Layout struct for the buffer
50395039
CXXRecordDecl *LayoutStruct;
50405040

@@ -5057,8 +5057,8 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
50575057
SourceLocation getRBraceLoc() const { return RBraceLoc; }
50585058
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
50595059
bool isCBuffer() const { return IsCBuffer; }
5060-
void setHasPackoffset(bool PO) { HasPackoffset = PO; }
5061-
bool hasPackoffset() const { return HasPackoffset; }
5060+
void setHasValidPackoffset(bool PO) { HasValidPackoffset = PO; }
5061+
bool hasValidPackoffset() const { return HasValidPackoffset; }
50625062
const CXXRecordDecl *getLayoutStruct() const { return LayoutStruct; }
50635063
void addLayoutStruct(CXXRecordDecl *LS);
50645064

clang/lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5717,7 +5717,7 @@ HLSLBufferDecl::HLSLBufferDecl(DeclContext *DC, bool CBuffer,
57175717
SourceLocation IDLoc, SourceLocation LBrace)
57185718
: NamedDecl(Decl::Kind::HLSLBuffer, DC, IDLoc, DeclarationName(ID)),
57195719
DeclContext(Decl::Kind::HLSLBuffer), LBraceLoc(LBrace), KwLoc(KwLoc),
5720-
IsCBuffer(CBuffer), HasPackoffset(false), LayoutStruct(nullptr) {}
5720+
IsCBuffer(CBuffer), HasValidPackoffset(false), LayoutStruct(nullptr) {}
57215721

57225722
HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
57235723
DeclContext *LexicalParent, bool CBuffer,

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 59 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "clang/AST/Decl.h"
2121
#include "clang/AST/Type.h"
2222
#include "clang/Basic/TargetOptions.h"
23+
#include "llvm/ADT/SmallVector.h"
2324
#include "llvm/IR/DerivedTypes.h"
2425
#include "llvm/IR/GlobalVariable.h"
2526
#include "llvm/IR/LLVMContext.h"
@@ -70,11 +71,14 @@ void addDisableOptimizations(llvm::Module &M) {
7071

7172
} // namespace
7273

73-
llvm::Type *CGHLSLRuntime::convertHLSLSpecificType(const Type *T) {
74+
llvm::Type *
75+
CGHLSLRuntime::convertHLSLSpecificType(const Type *T,
76+
SmallVector<unsigned> *Packoffsets) {
7477
assert(T->isHLSLSpecificType() && "Not an HLSL specific type!");
7578

7679
// Check if the target has a specific translation for this type first.
77-
if (llvm::Type *TargetTy = CGM.getTargetCodeGenInfo().getHLSLType(CGM, T))
80+
if (llvm::Type *TargetTy =
81+
CGM.getTargetCodeGenInfo().getHLSLType(CGM, T, Packoffsets))
7882
return TargetTy;
7983

8084
llvm_unreachable("Generic handling of HLSL types is not supported.");
@@ -96,153 +100,28 @@ static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) {
96100
return isResourceRecordType(Ty);
97101
}
98102

99-
static ConstantAsMetadata *getConstIntMetadata(LLVMContext &Ctx, uint32_t value,
100-
bool isSigned = false) {
101-
return ConstantAsMetadata::get(
102-
ConstantInt::get(Ctx, llvm::APInt(32, value, isSigned)));
103-
}
104-
105-
static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
106-
assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
107-
if (Ty->isVectorTy()) {
108-
llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
109-
return FVT->getNumElements() *
110-
(FVT->getElementType()->getScalarSizeInBits() / 8);
111-
}
112-
return Ty->getScalarSizeInBits() / 8;
113-
}
114-
115-
// Returns size of a struct in constant buffer layout. The sizes are cached
116-
// in StructSizesForBuffer map. The map is also an indicator if a layout
117-
// metadata for this struct has been added to the module.
118-
// If the struct type is not in the map, this method will calculate the struct
119-
// layout, add a metadata node describing it to the module, and add the struct
120-
// size to the map.
121-
size_t
122-
CGHLSLRuntime::getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy) {
123-
// check if we already have a side for this struct
124-
auto SizeIt = StructSizesForBuffer.find(StructTy);
125-
if (SizeIt != StructSizesForBuffer.end())
126-
return SizeIt->getSecond();
127-
128-
// if not, calculate the struct layout and create a metadata node
129-
LLVMContext &Ctx = CGM.getLLVMContext();
130-
SmallVector<llvm::Metadata *> LayoutItems;
131-
132-
// start metadata list with a struct name and reserve one slot for its size
133-
LayoutItems.push_back(MDString::get(Ctx, StructTy->getName()));
134-
LayoutItems.push_back(nullptr);
135-
136-
// add element offsets
137-
size_t StructSize = 0;
138-
for (llvm::Type *ElTy : StructTy->elements()) {
139-
size_t Offset = calculateBufferElementOffset(ElTy, &StructSize);
140-
LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), Offset));
141-
}
142-
// set the size of the buffer to the reserved slot
143-
LayoutItems[1] = getConstIntMetadata(Ctx, StructSize);
144-
145-
// add the struct layout to metadata
146-
CGM.getModule()
147-
.getOrInsertNamedMetadata("hlsl.cblayouts")
148-
->addOperand(MDNode::get(CGM.getLLVMContext(), LayoutItems));
149-
150-
// add struct size to list and return it
151-
StructSizesForBuffer[StructTy] = StructSize;
152-
return StructSize;
153-
}
154-
155-
// Calculates offset of a single element in constant buffer layout.
156-
// The provided LayoutEndOffset marks the end of the layout so far (end offset
157-
// of the buffer or struct). After the element offset calculations are done it
158-
// will be updated the new end of layout value.
159-
// If the PackoffsetAttrs is not nullptr the offset will be based on the
160-
// packoffset annotation.
161-
size_t CGHLSLRuntime::calculateBufferElementOffset(
162-
llvm::Type *LayoutTy, size_t *LayoutEndOffset,
163-
HLSLPackOffsetAttr *PackoffsetAttr) {
164-
165-
size_t ElemOffset = 0;
166-
size_t ElemSize = 0;
167-
size_t ArrayCount = 1;
168-
size_t ArrayStride = 0;
169-
size_t EndOffset = *LayoutEndOffset;
170-
size_t NextRowOffset = llvm::alignTo(EndOffset, 16U);
171-
172-
if (LayoutTy->isArrayTy()) {
173-
llvm::Type *Ty = LayoutTy;
174-
while (Ty->isArrayTy()) {
175-
ArrayCount *= Ty->getArrayNumElements();
176-
Ty = Ty->getArrayElementType();
177-
}
178-
ElemSize =
179-
Ty->isStructTy()
180-
? getOrCalculateStructSizeForBuffer(cast<llvm::StructType>(Ty))
181-
: getScalarOrVectorSize(Ty);
182-
ArrayStride = llvm::alignTo(ElemSize, 16U);
183-
ElemOffset =
184-
PackoffsetAttr ? PackoffsetAttr->getOffsetInBytes() : NextRowOffset;
185-
186-
} else if (LayoutTy->isStructTy()) {
187-
ElemOffset =
188-
PackoffsetAttr ? PackoffsetAttr->getOffsetInBytes() : NextRowOffset;
189-
ElemSize =
190-
getOrCalculateStructSizeForBuffer(cast<llvm::StructType>(LayoutTy));
191-
192-
} else {
193-
size_t Align = 0;
194-
if (LayoutTy->isVectorTy()) {
195-
llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(LayoutTy);
196-
size_t SubElemSize = FVT->getElementType()->getScalarSizeInBits() / 8;
197-
ElemSize = FVT->getNumElements() * SubElemSize;
198-
Align = SubElemSize;
199-
} else {
200-
assert(LayoutTy->isIntegerTy() || LayoutTy->isFloatingPointTy());
201-
ElemSize = LayoutTy->getScalarSizeInBits() / 8;
202-
Align = ElemSize;
203-
}
204-
if (PackoffsetAttr) {
205-
ElemOffset = PackoffsetAttr->getOffsetInBytes();
206-
} else {
207-
ElemOffset = llvm::alignTo(EndOffset, Align);
208-
// if the element does not fit, move it to the next row
209-
if (ElemOffset + ElemSize > NextRowOffset)
210-
ElemOffset = NextRowOffset;
211-
}
212-
}
213-
214-
// Update end offset of the buffer/struct layout; do not update it if
215-
// the provided EndOffset is already bigger than the new one value
216-
// (which may happen with packoffset annotations)
217-
unsigned NewEndOffset =
218-
ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
219-
*LayoutEndOffset = std::max<size_t>(EndOffset, NewEndOffset);
220-
221-
return ElemOffset;
222-
}
223-
224-
// Emits constant global variables for buffer declarations, creates metadata
225-
// linking the constant globals with the buffer. Also calculates the buffer
226-
// layout and creates metadata node describing it.
103+
// Emits constant global variables for buffer constants declarations
104+
// and creates metadata linking the constant globals with the buffer global.
227105
void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
228106
llvm::GlobalVariable *BufGV) {
229107
LLVMContext &Ctx = CGM.getLLVMContext();
108+
109+
// get the layout struct from constant buffer target type
110+
llvm::Type *BufType = BufGV->getValueType();
111+
assert(isa<llvm::TargetExtType>(BufType) &&
112+
"expected target type for HLSL buffer resource");
113+
llvm::Type *BufLayoutType =
114+
cast<llvm::TargetExtType>(BufType)->getTypeParameter(0);
115+
assert(isa<llvm::TargetExtType>(BufLayoutType) &&
116+
"expected target type for buffer layout struct");
230117
llvm::StructType *LayoutStruct = cast<llvm::StructType>(
231-
cast<llvm::TargetExtType>(BufGV->getValueType())->getTypeParameter(0));
118+
cast<llvm::TargetExtType>(BufLayoutType)->getTypeParameter(0));
232119

233120
// Start metadata list associating the buffer global variable with its
234121
// constatns
235122
SmallVector<llvm::Metadata *> BufGlobals;
236123
BufGlobals.push_back(ValueAsMetadata::get(BufGV));
237124

238-
// Start layout metadata list with a struct name and reserve one slot for
239-
// the buffer size
240-
SmallVector<llvm::Metadata *> LayoutItems;
241-
LayoutItems.push_back(MDString::get(Ctx, LayoutStruct->getName()));
242-
LayoutItems.push_back(nullptr);
243-
244-
size_t BufferSize = 0;
245-
bool UsePackoffset = BufDecl->hasPackoffset();
246125
const auto *ElemIt = LayoutStruct->element_begin();
247126
for (Decl *D : BufDecl->decls()) {
248127
if (isa<CXXRecordDecl, EmptyDecl>(D))
@@ -275,17 +154,6 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
275154
"number of elements in layout struct does not match");
276155
llvm::Type *LayoutType = *ElemIt++;
277156

278-
// Make sure the type of the VarDecl type matches the type of the layout
279-
// struct element, or that it is a layout struct with the same name
280-
assert((CGM.getTypes().ConvertTypeForMem(VDTy) == LayoutType ||
281-
(LayoutType->isStructTy() &&
282-
cast<llvm::StructType>(LayoutType)
283-
->getName()
284-
.starts_with(("struct.__cblayout_" +
285-
VDTy->getAsCXXRecordDecl()->getName())
286-
.str()))) &&
287-
"layout type does not match the converted element type");
288-
289157
// there might be resources inside the used defined structs
290158
if (VDTy->isStructureType() && VDTy->isHLSLIntangibleType())
291159
// FIXME: handle resources in cbuffer structs
@@ -295,29 +163,15 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
295163
GlobalVariable *ElemGV =
296164
cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
297165
BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
298-
299-
// get offset of the global and and to metadata list
300-
assert(((UsePackoffset && VD->hasAttr<HLSLPackOffsetAttr>()) ||
301-
!UsePackoffset) &&
302-
"expected packoffset attribute on every declaration");
303-
size_t Offset = calculateBufferElementOffset(
304-
LayoutType, &BufferSize,
305-
UsePackoffset ? VD->getAttr<HLSLPackOffsetAttr>() : nullptr);
306-
LayoutItems.push_back(getConstIntMetadata(Ctx, Offset));
307166
}
308167
assert(ElemIt == LayoutStruct->element_end() &&
309168
"number of elements in layout struct does not match");
310169
// set the size of the buffer
311-
LayoutItems[1] = getConstIntMetadata(Ctx, BufferSize);
312170

313171
// add buffer metadata to the module
314172
CGM.getModule()
315173
.getOrInsertNamedMetadata("hlsl.cbs")
316174
->addOperand(MDNode::get(Ctx, BufGlobals));
317-
318-
CGM.getModule()
319-
.getOrInsertNamedMetadata("hlsl.cblayouts")
320-
->addOperand(MDNode::get(Ctx, LayoutItems));
321175
}
322176

323177
// Creates resource handle type for the HLSL buffer declaration
@@ -331,6 +185,25 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
331185
return cast<HLSLAttributedResourceType>(QT.getTypePtr());
332186
}
333187

188+
static void fillPackoffsetLayout(const HLSLBufferDecl *BufDecl,
189+
SmallVector<unsigned> &Layout) {
190+
assert(Layout.empty() && "expected empty vector for layout");
191+
assert(BufDecl->hasValidPackoffset());
192+
193+
for (Decl *D : BufDecl->decls()) {
194+
if (isa<CXXRecordDecl, EmptyDecl>(D) || isa<FunctionDecl>(D)) {
195+
continue;
196+
}
197+
VarDecl *VD = dyn_cast<VarDecl>(D);
198+
if (!VD || VD->getType().getAddressSpace() != LangAS::hlsl_constant)
199+
continue;
200+
assert(VD->hasAttr<HLSLPackOffsetAttr>() &&
201+
"expected packoffset attribute on every declaration");
202+
size_t Offset = VD->getAttr<HLSLPackOffsetAttr>()->getOffsetInBytes();
203+
Layout.push_back(Offset);
204+
}
205+
}
206+
334207
// Codegen for HLSLBufferDecl
335208
void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
336209

@@ -345,16 +218,20 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
345218
return;
346219

347220
// create global variable for the constant buffer
348-
llvm::Module &M = CGM.getModule();
221+
SmallVector<unsigned> Layout;
222+
if (BufDecl->hasValidPackoffset())
223+
fillPackoffsetLayout(BufDecl, Layout);
224+
349225
llvm::TargetExtType *TargetTy =
350-
cast<llvm::TargetExtType>(convertHLSLSpecificType(ResHandleTy));
226+
cast<llvm::TargetExtType>(convertHLSLSpecificType(
227+
ResHandleTy, BufDecl->hasValidPackoffset() ? &Layout : nullptr));
351228
llvm::GlobalVariable *BufGV =
352229
new GlobalVariable(TargetTy, /*isConstant*/ true,
353230
GlobalValue::LinkageTypes::ExternalLinkage, nullptr,
354231
llvm::formatv("{0}{1}", BufDecl->getName(),
355232
BufDecl->isCBuffer() ? ".cb" : ".tb"),
356233
GlobalValue::NotThreadLocal);
357-
M.insertGlobalVariable(BufGV);
234+
CGM.getModule().insertGlobalVariable(BufGV);
358235

359236
// Add globals for constant buffer elements and create metadata nodes
360237
emitBufferGlobalsAndMetadata(BufDecl, BufGV);
@@ -368,6 +245,21 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
368245
RBA->getSpaceNumber());
369246
}
370247

248+
llvm::Type *
249+
CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
250+
const auto Entry = LayoutTypes.find(StructType);
251+
if (Entry != LayoutTypes.end())
252+
return Entry->getSecond();
253+
return nullptr;
254+
}
255+
256+
void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
257+
llvm::Type *LayoutTy) {
258+
assert(getHLSLBufferLayoutType(StructType) == nullptr &&
259+
"layout type for this struct already exist");
260+
LayoutTypes[StructType] = LayoutTy;
261+
}
262+
371263
void CGHLSLRuntime::finishCodeGen() {
372264
auto &TargetOpts = CGM.getTarget().getTargetOpts();
373265
llvm::Module &M = CGM.getModule();

clang/lib/CodeGen/CGHLSLRuntime.h

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class ParmVarDecl;
6363
class HLSLBufferDecl;
6464
class HLSLResourceBindingAttr;
6565
class Type;
66+
class RecordType;
6667
class DeclContext;
6768
class HLSLPackOffsetAttr;
6869

@@ -141,7 +142,9 @@ class CGHLSLRuntime {
141142
CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
142143
virtual ~CGHLSLRuntime() {}
143144

144-
llvm::Type *convertHLSLSpecificType(const Type *T);
145+
llvm::Type *
146+
convertHLSLSpecificType(const Type *T,
147+
SmallVector<unsigned> *Packoffsets = nullptr);
145148

146149
void annotateHLSLResource(const VarDecl *D, llvm::GlobalVariable *GV);
147150
void generateGlobalCtorDtorCalls();
@@ -157,6 +160,10 @@ class CGHLSLRuntime {
157160

158161
llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);
159162

163+
llvm::Type *getHLSLBufferLayoutType(const RecordType *LayoutStructTy);
164+
void addHLSLBufferLayoutType(const RecordType *LayoutStructTy,
165+
llvm::Type *LayoutTy);
166+
160167
private:
161168
void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
162169
llvm::hlsl::ResourceClass RC,
@@ -165,18 +172,9 @@ class CGHLSLRuntime {
165172
BufferResBinding &Binding);
166173
void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
167174
llvm::GlobalVariable *BufGV);
168-
169-
size_t
170-
calculateBufferElementOffset(llvm::Type *LayoutTy, size_t *LayoutEndOffset,
171-
HLSLPackOffsetAttr *PackoffsetAttr = nullptr);
172-
173-
size_t getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy);
174-
175175
llvm::Triple::ArchType getArch();
176176

177-
// Sizes of structs in constant buffer layout. Structs in the map
178-
// had their layout calculated and added to the module as metadata.
179-
llvm::DenseMap<llvm::StructType *, size_t> StructSizesForBuffer;
177+
llvm::DenseMap<const clang::RecordType *, llvm::Type *> LayoutTypes;
180178
};
181179

182180
} // namespace CodeGen

clang/lib/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ add_clang_library(clangCodeGen
124124
Targets/CSKY.cpp
125125
Targets/DirectX.cpp
126126
Targets/Hexagon.cpp
127+
Targets/HLSLTargetInfo.cpp
127128
Targets/Lanai.cpp
128129
Targets/LoongArch.cpp
129130
Targets/M68k.cpp

0 commit comments

Comments
 (0)