@@ -89,8 +89,7 @@ static bool isResourceRecordType(const clang::Type *Ty) {
89
89
return HLSLAttributedResourceType::findHandleTypeOnResource (Ty) != nullptr ;
90
90
}
91
91
92
- // Returns true if the type is an HLSL resource class or an array of
93
- // HLSL resource classes
92
+ // Returns true if the type is an HLSL resource class or an array of them
94
93
static bool isResourceRecordTypeOrArrayOf (const clang::Type *Ty) {
95
94
while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
96
95
Ty = CAT->getArrayElementTypeNoTypeQual ();
@@ -113,48 +112,56 @@ static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
113
112
return Ty->getScalarSizeInBits () / 8 ;
114
113
}
115
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.
116
121
size_t
117
122
CGHLSLRuntime::getOrCalculateStructSizeForBuffer (llvm::StructType *StructTy) {
118
- assert (StructTy->isStructTy ());
119
-
120
123
// check if we already have a side for this struct
121
124
auto SizeIt = StructSizesForBuffer.find (StructTy);
122
125
if (SizeIt != StructSizesForBuffer.end ())
123
126
return SizeIt->getSecond ();
124
127
125
- // if not, calculate the struct layout and add it to metadata
128
+ // if not, calculate the struct layout and create a metadata node
126
129
LLVMContext &Ctx = CGM.getLLVMContext ();
127
130
SmallVector<llvm::Metadata *> LayoutItems;
131
+
132
+ // start metadata list with a struct name and reserve one slot for its size
128
133
LayoutItems.push_back (MDString::get (Ctx, StructTy->getName ()));
134
+ LayoutItems.push_back (nullptr );
129
135
136
+ // add element offsets
130
137
size_t StructSize = 0 ;
131
- LayoutItems.push_back (nullptr ); // reserve one slot for the buffer size
132
-
133
138
for (llvm::Type *ElTy : StructTy->elements ()) {
134
139
size_t Offset = calculateBufferElementOffset (ElTy, &StructSize);
135
- // create metadata constant with the element start offset
136
140
LayoutItems.push_back (getConstIntMetadata (CGM.getLLVMContext (), Offset));
137
141
}
138
-
139
- // set the size of the buffer
142
+ // set the size of the buffer to the reserved slot
140
143
LayoutItems[1 ] = getConstIntMetadata (Ctx, StructSize);
141
144
142
- // add the struct layout info to metadata
143
- MDNode *LayoutMDNode = MDNode::get (CGM.getLLVMContext (), LayoutItems);
145
+ // add the struct layout to metadata
144
146
CGM.getModule ()
145
147
.getOrInsertNamedMetadata (" hlsl.cblayouts" )
146
- ->addOperand (LayoutMDNode );
148
+ ->addOperand (MDNode::get (CGM. getLLVMContext (), LayoutItems) );
147
149
148
150
// add struct size to list and return it
149
151
StructSizesForBuffer[StructTy] = StructSize;
150
152
return StructSize;
151
153
}
152
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.
153
161
size_t CGHLSLRuntime::calculateBufferElementOffset (
154
162
llvm::Type *LayoutTy, size_t *LayoutEndOffset,
155
163
HLSLPackOffsetAttr *PackoffsetAttr) {
156
164
157
- // calculate element offset and size
158
165
size_t ElemOffset = 0 ;
159
166
size_t ElemSize = 0 ;
160
167
size_t ArrayCount = 1 ;
@@ -198,117 +205,122 @@ size_t CGHLSLRuntime::calculateBufferElementOffset(
198
205
ElemOffset = PackoffsetAttr->getOffsetInBytes ();
199
206
} else {
200
207
ElemOffset = llvm::alignTo (EndOffset, Align);
208
+ // if the element does not fit, move it to the next row
201
209
if (ElemOffset + ElemSize > NextRowOffset)
202
210
ElemOffset = NextRowOffset;
203
211
}
204
212
}
205
213
206
214
// Update end offset of the buffer/struct layout; do not update it if
207
- // the provided EndOffset is already bigger than the new one (which may happen
208
- // with packoffset annotations)
215
+ // the provided EndOffset is already bigger than the new one value
216
+ // (which may happen with packoffset annotations)
209
217
unsigned NewEndOffset =
210
218
ElemOffset + (ArrayCount - 1 ) * ArrayStride + ElemSize;
211
219
*LayoutEndOffset = std::max<size_t >(EndOffset, NewEndOffset);
212
220
213
221
return ElemOffset;
214
222
}
215
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.
216
227
void CGHLSLRuntime::emitBufferGlobalsAndMetadata (const HLSLBufferDecl *BufDecl,
217
228
llvm::GlobalVariable *BufGV) {
229
+ LLVMContext &Ctx = CGM.getLLVMContext ();
218
230
llvm::StructType *LayoutStruct = cast<llvm::StructType>(
219
231
cast<llvm::TargetExtType>(BufGV->getValueType ())->getTypeParameter (0 ));
220
232
221
- LLVMContext &Ctx = CGM. getLLVMContext ();
222
-
233
+ // Start metadata list associating the buffer global variable with its
234
+ // constatns
223
235
SmallVector<llvm::Metadata *> BufGlobals;
224
236
BufGlobals.push_back (ValueAsMetadata::get (BufGV));
225
237
238
+ // Start layout metadata list with a struct name and reserve one slot for
239
+ // the buffer size
226
240
SmallVector<llvm::Metadata *> LayoutItems;
227
241
LayoutItems.push_back (MDString::get (Ctx, LayoutStruct->getName ()));
242
+ LayoutItems.push_back (nullptr );
228
243
229
244
size_t BufferSize = 0 ;
230
- size_t BufferSizeIndex = LayoutItems.size ();
231
- LayoutItems.push_back (nullptr ); // reserve one slot for the buffer size
232
-
233
245
bool UsePackoffset = BufDecl->hasPackoffset ();
234
-
235
246
const auto *ElemIt = LayoutStruct->element_begin ();
236
247
for (Decl *D : BufDecl->decls ()) {
237
248
if (isa<CXXRecordDecl, EmptyDecl>(D))
238
249
// Nothing to do for this declaration.
239
250
continue ;
240
251
if (isa<FunctionDecl>(D)) {
241
- // A function within an cbuffer is effectively a top-level function,
242
- // as it only refers to globally scoped declarations.
252
+ // A function within an cbuffer is effectively a top-level function.
243
253
CGM.EmitTopLevelDecl (D);
244
254
continue ;
245
255
}
246
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
247
- QualType VDTy = VD->getType ();
248
- if (VDTy.getAddressSpace () != LangAS::hlsl_constant) {
249
- if (VD->getStorageClass () == SC_Static ||
250
- isResourceRecordTypeOrArrayOf (VDTy.getTypePtr ())) {
251
- // Emit static variables and resource classes inside cbuffer as
252
- // regular globals
253
- CGM.EmitGlobal (VD);
254
- }
255
- // Anything else that is not in the hlsl_constant address space must be
256
- // an empty struct or a zero-sized array and can be ignored
257
- continue ;
258
- }
256
+ VarDecl *VD = dyn_cast<VarDecl>(D);
257
+ if (!VD)
258
+ continue ;
259
259
260
- assert (ElemIt != LayoutStruct->element_end () &&
261
- " number of elements in layout struct does not match" );
262
- llvm::Type *LayoutType = *ElemIt++;
263
-
264
- assert ((CGM.getTypes ().ConvertTypeForMem (VDTy) == LayoutType ||
265
- (LayoutType->isStructTy () &&
266
- cast<llvm::StructType>(LayoutType)
267
- ->getName ()
268
- .starts_with ((" struct.__cblayout_" +
269
- VDTy->getAsCXXRecordDecl ()->getName ())
270
- .str ()))) &&
271
- " layout type does not match the converted element type" );
272
-
273
- // handle any resources declarations inside the struct
274
- if (VDTy->isStructureType () && VDTy->isHLSLIntangibleType ())
275
- // FIXME: handle resources in cbuffer structs
276
- llvm_unreachable (" resources in cbuffer are not supported yet" );
277
-
278
- GlobalVariable *ElemGV =
279
- cast<GlobalVariable>(CGM.GetAddrOfGlobalVar (VD, LayoutType));
280
- BufGlobals.push_back (ValueAsMetadata::get (ElemGV));
281
-
282
- assert (((UsePackoffset && VD->hasAttr <HLSLPackOffsetAttr>()) ||
283
- !UsePackoffset) &&
284
- " expected packoffset attribute on every declaration" );
285
-
286
- size_t Offset = calculateBufferElementOffset (
287
- LayoutType, &BufferSize,
288
- UsePackoffset ? VD->getAttr <HLSLPackOffsetAttr>() : nullptr );
289
-
290
- // create metadata constant with the element start offset
291
- LayoutItems.push_back (getConstIntMetadata (CGM.getLLVMContext (), Offset));
260
+ QualType VDTy = VD->getType ();
261
+ if (VDTy.getAddressSpace () != LangAS::hlsl_constant) {
262
+ if (VD->getStorageClass () == SC_Static ||
263
+ VDTy.getAddressSpace () == LangAS::hlsl_groupshared ||
264
+ isResourceRecordTypeOrArrayOf (VDTy.getTypePtr ())) {
265
+ // Emit static and groupshared variables and resource classes inside
266
+ // cbuffer as regular globals
267
+ CGM.EmitGlobal (VD);
268
+ }
269
+ // Anything else that is not in the hlsl_constant address space must be
270
+ // an empty struct or a zero-sized array and can be ignored
271
+ continue ;
292
272
}
273
+
274
+ assert (ElemIt != LayoutStruct->element_end () &&
275
+ " number of elements in layout struct does not match" );
276
+ llvm::Type *LayoutType = *ElemIt++;
277
+
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
+
289
+ // there might be resources inside the used defined structs
290
+ if (VDTy->isStructureType () && VDTy->isHLSLIntangibleType ())
291
+ // FIXME: handle resources in cbuffer structs
292
+ llvm_unreachable (" resources in cbuffer are not supported yet" );
293
+
294
+ // create global variable for the constant and to metadata list
295
+ GlobalVariable *ElemGV =
296
+ cast<GlobalVariable>(CGM.GetAddrOfGlobalVar (VD, LayoutType));
297
+ 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));
293
307
}
294
308
assert (ElemIt == LayoutStruct->element_end () &&
295
309
" number of elements in layout struct does not match" );
296
-
297
- // add buffer global and a list of its constants to metadata
298
- MDNode *BufMDNode = MDNode::get (CGM.getLLVMContext (), BufGlobals);
299
- CGM.getModule ().getOrInsertNamedMetadata (" hlsl.cbs" )->addOperand (BufMDNode);
300
-
301
310
// set the size of the buffer
302
- LayoutItems[BufferSizeIndex] = getConstIntMetadata (Ctx, BufferSize);
311
+ LayoutItems[1 ] = getConstIntMetadata (Ctx, BufferSize);
312
+
313
+ // add buffer metadata to the module
314
+ CGM.getModule ()
315
+ .getOrInsertNamedMetadata (" hlsl.cbs" )
316
+ ->addOperand (MDNode::get (Ctx, BufGlobals));
303
317
304
- // add buffer layout to metadata
305
- MDNode *LayoutMDNode = MDNode::get (CGM.getLLVMContext (), LayoutItems);
306
318
CGM.getModule ()
307
319
.getOrInsertNamedMetadata (" hlsl.cblayouts" )
308
- ->addOperand (LayoutMDNode );
320
+ ->addOperand (MDNode::get (Ctx, LayoutItems) );
309
321
}
310
322
311
- // Creates resource handle type for the HLSL buffer
323
+ // Creates resource handle type for the HLSL buffer declaration
312
324
static const clang::HLSLAttributedResourceType *
313
325
createBufferHandleType (const HLSLBufferDecl *BufDecl) {
314
326
ASTContext &AST = BufDecl->getASTContext ();
@@ -319,26 +331,20 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
319
331
return cast<HLSLAttributedResourceType>(QT.getTypePtr ());
320
332
}
321
333
322
- // Creates temporary global variables for all declarations within the constant
323
- // buffer context, creates a global variable for the constant buffer and adds
324
- // it to the module.
325
- // All uses of the temporary constant globals will be replaced with buffer
326
- // access intrinsic resource.getpointer in CGHLSLRuntime::finishCodeGen.
327
- // Later on in DXILResourceAccess pass these will be transtaled
328
- // to dx.op.cbufferLoadLegacy instructions.
334
+ // Codegen for HLSLBufferDecl
329
335
void CGHLSLRuntime::addBuffer (const HLSLBufferDecl *BufDecl) {
330
336
331
337
assert (BufDecl->isCBuffer () && " tbuffer codegen is not supported yet" );
332
338
333
- // Create resource handle type for the buffer
339
+ // create resource handle type for the buffer
334
340
const clang::HLSLAttributedResourceType *ResHandleTy =
335
341
createBufferHandleType (BufDecl);
336
342
337
- // ignore empty constant buffer
343
+ // empty constant buffer is ignored
338
344
if (ResHandleTy->getContainedType ()->getAsCXXRecordDecl ()->isEmpty ())
339
345
return ;
340
346
341
- // Create global variable for the buffer
347
+ // create global variable for the constant buffer
342
348
llvm::Module &M = CGM.getModule ();
343
349
llvm::TargetExtType *TargetTy =
344
350
cast<llvm::TargetExtType>(convertHLSLSpecificType (ResHandleTy));
@@ -350,10 +356,10 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
350
356
GlobalValue::NotThreadLocal);
351
357
M.insertGlobalVariable (BufGV);
352
358
353
- // Add globals for buffer elements and create metadata node for the buffer
359
+ // Add globals for constant buffer elements and create metadata nodes
354
360
emitBufferGlobalsAndMetadata (BufDecl, BufGV);
355
361
356
- // Add cbuffer resource initialization
362
+ // Resource initialization
357
363
const HLSLResourceBindingAttr *RBA =
358
364
BufDecl->getAttr <HLSLResourceBindingAttr>();
359
365
// FIXME: handle implicit binding if no binding attribute is found
0 commit comments