@@ -89,8 +89,7 @@ static bool isResourceRecordType(const clang::Type *Ty) {
8989 return HLSLAttributedResourceType::findHandleTypeOnResource (Ty) != nullptr ;
9090}
9191
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
9493static bool isResourceRecordTypeOrArrayOf (const clang::Type *Ty) {
9594 while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
9695 Ty = CAT->getArrayElementTypeNoTypeQual ();
@@ -113,48 +112,56 @@ static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
113112 return Ty->getScalarSizeInBits () / 8 ;
114113}
115114
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.
116121size_t
117122CGHLSLRuntime::getOrCalculateStructSizeForBuffer (llvm::StructType *StructTy) {
118- assert (StructTy->isStructTy ());
119-
120123 // check if we already have a side for this struct
121124 auto SizeIt = StructSizesForBuffer.find (StructTy);
122125 if (SizeIt != StructSizesForBuffer.end ())
123126 return SizeIt->getSecond ();
124127
125- // if not, calculate the struct layout and add it to metadata
128+ // if not, calculate the struct layout and create a metadata node
126129 LLVMContext &Ctx = CGM.getLLVMContext ();
127130 SmallVector<llvm::Metadata *> LayoutItems;
131+
132+ // start metadata list with a struct name and reserve one slot for its size
128133 LayoutItems.push_back (MDString::get (Ctx, StructTy->getName ()));
134+ LayoutItems.push_back (nullptr );
129135
136+ // add element offsets
130137 size_t StructSize = 0 ;
131- LayoutItems.push_back (nullptr ); // reserve one slot for the buffer size
132-
133138 for (llvm::Type *ElTy : StructTy->elements ()) {
134139 size_t Offset = calculateBufferElementOffset (ElTy, &StructSize);
135- // create metadata constant with the element start offset
136140 LayoutItems.push_back (getConstIntMetadata (CGM.getLLVMContext (), Offset));
137141 }
138-
139- // set the size of the buffer
142+ // set the size of the buffer to the reserved slot
140143 LayoutItems[1 ] = getConstIntMetadata (Ctx, StructSize);
141144
142- // add the struct layout info to metadata
143- MDNode *LayoutMDNode = MDNode::get (CGM.getLLVMContext (), LayoutItems);
145+ // add the struct layout to metadata
144146 CGM.getModule ()
145147 .getOrInsertNamedMetadata (" hlsl.cblayouts" )
146- ->addOperand (LayoutMDNode );
148+ ->addOperand (MDNode::get (CGM. getLLVMContext (), LayoutItems) );
147149
148150 // add struct size to list and return it
149151 StructSizesForBuffer[StructTy] = StructSize;
150152 return StructSize;
151153}
152154
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.
153161size_t CGHLSLRuntime::calculateBufferElementOffset (
154162 llvm::Type *LayoutTy, size_t *LayoutEndOffset,
155163 HLSLPackOffsetAttr *PackoffsetAttr) {
156164
157- // calculate element offset and size
158165 size_t ElemOffset = 0 ;
159166 size_t ElemSize = 0 ;
160167 size_t ArrayCount = 1 ;
@@ -198,117 +205,122 @@ size_t CGHLSLRuntime::calculateBufferElementOffset(
198205 ElemOffset = PackoffsetAttr->getOffsetInBytes ();
199206 } else {
200207 ElemOffset = llvm::alignTo (EndOffset, Align);
208+ // if the element does not fit, move it to the next row
201209 if (ElemOffset + ElemSize > NextRowOffset)
202210 ElemOffset = NextRowOffset;
203211 }
204212 }
205213
206214 // 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)
209217 unsigned NewEndOffset =
210218 ElemOffset + (ArrayCount - 1 ) * ArrayStride + ElemSize;
211219 *LayoutEndOffset = std::max<size_t >(EndOffset, NewEndOffset);
212220
213221 return ElemOffset;
214222}
215223
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.
216227void CGHLSLRuntime::emitBufferGlobalsAndMetadata (const HLSLBufferDecl *BufDecl,
217228 llvm::GlobalVariable *BufGV) {
229+ LLVMContext &Ctx = CGM.getLLVMContext ();
218230 llvm::StructType *LayoutStruct = cast<llvm::StructType>(
219231 cast<llvm::TargetExtType>(BufGV->getValueType ())->getTypeParameter (0 ));
220232
221- LLVMContext &Ctx = CGM. getLLVMContext ();
222-
233+ // Start metadata list associating the buffer global variable with its
234+ // constatns
223235 SmallVector<llvm::Metadata *> BufGlobals;
224236 BufGlobals.push_back (ValueAsMetadata::get (BufGV));
225237
238+ // Start layout metadata list with a struct name and reserve one slot for
239+ // the buffer size
226240 SmallVector<llvm::Metadata *> LayoutItems;
227241 LayoutItems.push_back (MDString::get (Ctx, LayoutStruct->getName ()));
242+ LayoutItems.push_back (nullptr );
228243
229244 size_t BufferSize = 0 ;
230- size_t BufferSizeIndex = LayoutItems.size ();
231- LayoutItems.push_back (nullptr ); // reserve one slot for the buffer size
232-
233245 bool UsePackoffset = BufDecl->hasPackoffset ();
234-
235246 const auto *ElemIt = LayoutStruct->element_begin ();
236247 for (Decl *D : BufDecl->decls ()) {
237248 if (isa<CXXRecordDecl, EmptyDecl>(D))
238249 // Nothing to do for this declaration.
239250 continue ;
240251 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.
243253 CGM.EmitTopLevelDecl (D);
244254 continue ;
245255 }
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 ;
259259
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 ;
292272 }
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));
293307 }
294308 assert (ElemIt == LayoutStruct->element_end () &&
295309 " 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-
301310 // 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));
303317
304- // add buffer layout to metadata
305- MDNode *LayoutMDNode = MDNode::get (CGM.getLLVMContext (), LayoutItems);
306318 CGM.getModule ()
307319 .getOrInsertNamedMetadata (" hlsl.cblayouts" )
308- ->addOperand (LayoutMDNode );
320+ ->addOperand (MDNode::get (Ctx, LayoutItems) );
309321}
310322
311- // Creates resource handle type for the HLSL buffer
323+ // Creates resource handle type for the HLSL buffer declaration
312324static const clang::HLSLAttributedResourceType *
313325createBufferHandleType (const HLSLBufferDecl *BufDecl) {
314326 ASTContext &AST = BufDecl->getASTContext ();
@@ -319,26 +331,20 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
319331 return cast<HLSLAttributedResourceType>(QT.getTypePtr ());
320332}
321333
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
329335void CGHLSLRuntime::addBuffer (const HLSLBufferDecl *BufDecl) {
330336
331337 assert (BufDecl->isCBuffer () && " tbuffer codegen is not supported yet" );
332338
333- // Create resource handle type for the buffer
339+ // create resource handle type for the buffer
334340 const clang::HLSLAttributedResourceType *ResHandleTy =
335341 createBufferHandleType (BufDecl);
336342
337- // ignore empty constant buffer
343+ // empty constant buffer is ignored
338344 if (ResHandleTy->getContainedType ()->getAsCXXRecordDecl ()->isEmpty ())
339345 return ;
340346
341- // Create global variable for the buffer
347+ // create global variable for the constant buffer
342348 llvm::Module &M = CGM.getModule ();
343349 llvm::TargetExtType *TargetTy =
344350 cast<llvm::TargetExtType>(convertHLSLSpecificType (ResHandleTy));
@@ -350,10 +356,10 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
350356 GlobalValue::NotThreadLocal);
351357 M.insertGlobalVariable (BufGV);
352358
353- // Add globals for buffer elements and create metadata node for the buffer
359+ // Add globals for constant buffer elements and create metadata nodes
354360 emitBufferGlobalsAndMetadata (BufDecl, BufGV);
355361
356- // Add cbuffer resource initialization
362+ // Resource initialization
357363 const HLSLResourceBindingAttr *RBA =
358364 BufDecl->getAttr <HLSLResourceBindingAttr>();
359365 // FIXME: handle implicit binding if no binding attribute is found
0 commit comments