1010#include " CGHLSLRuntime.h"
1111#include " CodeGenModule.h"
1212#include " clang/AST/Type.h"
13+ #include < climits>
1314
1415// ===----------------------------------------------------------------------===//
1516// Implementation of constant buffer layout common between DirectX and
1819
1920using namespace clang ;
2021using namespace clang ::CodeGen;
22+ using llvm::hlsl::CBufferRowSizeInBytes;
2123
2224namespace {
2325
@@ -51,16 +53,22 @@ namespace clang {
5153namespace CodeGen {
5254
5355// Creates a layout type for given struct with HLSL constant buffer layout
54- // taking into account Packoffsets , if provided.
56+ // taking into account PackOffsets , if provided.
5557// Previously created layout types are cached by CGHLSLRuntime.
5658//
5759// The function iterates over all fields of the StructType (including base
5860// classes) and calls layoutField to converts each field to its corresponding
5961// LLVM type and to calculate its HLSL constant buffer layout. Any embedded
6062// structs (or arrays of structs) are converted to target layout types as well.
63+ //
64+ // When PackOffsets are specified the elements will be placed based on the
65+ // user-specified offsets. Not all elements must have a packoffset/register(c#)
66+ // annotation though. For those that don't, the PackOffsets array will contain
67+ // -1 value instead. These elements must be placed at the end of the layout
68+ // after all of the elements with specific offset.
6169llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType (
6270 const RecordType *StructType,
63- const llvm::SmallVector<unsigned > *Packoffsets ) {
71+ const llvm::SmallVector<int32_t > *PackOffsets ) {
6472
6573 // check if we already have the layout type for this struct
6674 if (llvm::TargetExtType *Ty =
@@ -72,6 +80,8 @@ llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType(
7280 unsigned Index = 0 ; // packoffset index
7381 unsigned EndOffset = 0 ;
7482
83+ SmallVector<std::pair<const FieldDecl *, unsigned >> DelayLayoutFields;
84+
7585 // reserve first spot in the layout vector for buffer size
7686 Layout.push_back (0 );
7787
@@ -84,22 +94,55 @@ llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType(
8494 " HLSL doesn't support multiple inheritance" );
8595 RecordTypes.push_back (D->bases_begin ()->getType ()->getAs <RecordType>());
8696 }
97+
98+ unsigned FieldOffset;
99+ llvm::Type *FieldType;
100+
87101 while (!RecordTypes.empty ()) {
88102 const RecordType *RT = RecordTypes.back ();
89103 RecordTypes.pop_back ();
90104
91105 for (const auto *FD : RT->getDecl ()->fields ()) {
92- assert ((!Packoffsets || Index < Packoffsets->size ()) &&
93- " number of elements in layout struct does not "
94- " match number of packoffset annotations" );
95-
96- if (!layoutField (FD, EndOffset, Layout, LayoutElements,
97- Packoffsets ? (*Packoffsets)[Index] : -1 ))
98- return nullptr ;
99- Index++;
106+ assert ((!PackOffsets || Index < PackOffsets->size ()) &&
107+ " number of elements in layout struct does not match number of "
108+ " packoffset annotations" );
109+
110+ // No PackOffset info at all, or have a valid packoffset/register(c#)
111+ // annotations value -> layout the field.
112+ const int PO = PackOffsets ? (*PackOffsets)[Index++] : -1 ;
113+ if (!PackOffsets || PO != -1 ) {
114+ if (!layoutField (FD, EndOffset, FieldOffset, FieldType, PO))
115+ return nullptr ;
116+ Layout.push_back (FieldOffset);
117+ LayoutElements.push_back (FieldType);
118+ continue ;
119+ }
120+ // Have PackOffset info, but there is no packoffset/register(cX)
121+ // annotation on this field. Delay the layout until after all of the
122+ // other elements with packoffsets/register(cX) are processed.
123+ DelayLayoutFields.emplace_back (FD, LayoutElements.size ());
124+ // reserve space for this field in the layout vector and elements list
125+ Layout.push_back (UINT_MAX);
126+ LayoutElements.push_back (nullptr );
100127 }
101128 }
102129
130+ // process delayed layouts
131+ for (auto I : DelayLayoutFields) {
132+ const FieldDecl *FD = I.first ;
133+ const unsigned IndexInLayoutElements = I.second ;
134+ // the first item in layout vector is size, so we need to offset the index
135+ // by 1
136+ const unsigned IndexInLayout = IndexInLayoutElements + 1 ;
137+ assert (Layout[IndexInLayout] == UINT_MAX &&
138+ LayoutElements[IndexInLayoutElements] == nullptr );
139+
140+ if (!layoutField (FD, EndOffset, FieldOffset, FieldType))
141+ return nullptr ;
142+ Layout[IndexInLayout] = FieldOffset;
143+ LayoutElements[IndexInLayoutElements] = FieldType;
144+ }
145+
103146 // set the size of the buffer
104147 Layout[0 ] = EndOffset;
105148
@@ -122,16 +165,19 @@ llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType(
122165// The function converts a single field of HLSL Buffer to its corresponding
123166// LLVM type and calculates it's layout. Any embedded structs (or
124167// arrays of structs) are converted to target layout types as well.
125- // The converted type is appended to the LayoutElements list, the element
126- // offset is added to the Layout list and the EndOffset updated to the offset
127- // just after the lay-ed out element (which is basically the size of the
128- // buffer).
168+ // The converted type is set to the FieldType parameter, the element
169+ // offset is set to the FieldOffset parameter. The EndOffset (=size of the
170+ // buffer) is also updated accordingly to the offset just after the placed
171+ // element, unless the incoming EndOffset already larger (may happen in case
172+ // of unsorted packoffset annotations).
129173// Returns true if the conversion was successful.
130174// The packoffset parameter contains the field's layout offset provided by the
131175// user or -1 if there was no packoffset (or register(cX)) annotation.
132- bool HLSLBufferLayoutBuilder::layoutField (
133- const FieldDecl *FD, unsigned &EndOffset, SmallVector<unsigned > &Layout,
134- SmallVector<llvm::Type *> &LayoutElements, int Packoffset) {
176+ bool HLSLBufferLayoutBuilder::layoutField (const FieldDecl *FD,
177+ unsigned &EndOffset,
178+ unsigned &FieldOffset,
179+ llvm::Type *&FieldType,
180+ int Packoffset) {
135181
136182 // Size of element; for arrays this is a size of a single element in the
137183 // array. Total array size of calculated as (ArrayCount-1) * ArrayStride +
@@ -141,8 +187,7 @@ bool HLSLBufferLayoutBuilder::layoutField(
141187 unsigned ArrayCount = 1 ;
142188 unsigned ArrayStride = 0 ;
143189
144- const unsigned BufferRowAlign = 16U ;
145- unsigned NextRowOffset = llvm::alignTo (EndOffset, BufferRowAlign);
190+ unsigned NextRowOffset = llvm::alignTo (EndOffset, CBufferRowSizeInBytes);
146191
147192 llvm::Type *ElemLayoutTy = nullptr ;
148193 QualType FieldTy = FD->getType ();
@@ -172,7 +217,7 @@ bool HLSLBufferLayoutBuilder::layoutField(
172217 getScalarOrVectorSizeInBytes (CGM.getTypes ().ConvertTypeForMem (Ty));
173218 ElemLayoutTy = CGM.getTypes ().ConvertTypeForMem (FieldTy);
174219 }
175- ArrayStride = llvm::alignTo (ElemSize, BufferRowAlign );
220+ ArrayStride = llvm::alignTo (ElemSize, CBufferRowSizeInBytes );
176221 ElemOffset = (Packoffset != -1 ) ? Packoffset : NextRowOffset;
177222
178223 } else if (FieldTy->isStructureType ()) {
@@ -220,8 +265,8 @@ bool HLSLBufferLayoutBuilder::layoutField(
220265 EndOffset = std::max<unsigned >(EndOffset, NewEndOffset);
221266
222267 // add the layout element and offset to the lists
223- Layout. push_back ( ElemOffset) ;
224- LayoutElements. push_back ( ElemLayoutTy) ;
268+ FieldOffset = ElemOffset;
269+ FieldType = ElemLayoutTy;
225270 return true ;
226271}
227272
0 commit comments