10
10
#include " CGHLSLRuntime.h"
11
11
#include " CodeGenModule.h"
12
12
#include " clang/AST/Type.h"
13
+ #include < climits>
13
14
14
15
// ===----------------------------------------------------------------------===//
15
16
// Implementation of constant buffer layout common between DirectX and
18
19
19
20
using namespace clang ;
20
21
using namespace clang ::CodeGen;
22
+ using llvm::hlsl::CBufferRowSizeInBytes;
21
23
22
24
namespace {
23
25
@@ -51,16 +53,22 @@ namespace clang {
51
53
namespace CodeGen {
52
54
53
55
// 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.
55
57
// Previously created layout types are cached by CGHLSLRuntime.
56
58
//
57
59
// The function iterates over all fields of the StructType (including base
58
60
// classes) and calls layoutField to converts each field to its corresponding
59
61
// LLVM type and to calculate its HLSL constant buffer layout. Any embedded
60
62
// 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.
61
69
llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType (
62
70
const RecordType *StructType,
63
- const llvm::SmallVector<unsigned > *Packoffsets ) {
71
+ const llvm::SmallVector<int32_t > *PackOffsets ) {
64
72
65
73
// check if we already have the layout type for this struct
66
74
if (llvm::TargetExtType *Ty =
@@ -72,6 +80,8 @@ llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType(
72
80
unsigned Index = 0 ; // packoffset index
73
81
unsigned EndOffset = 0 ;
74
82
83
+ SmallVector<std::pair<const FieldDecl *, unsigned >> DelayLayoutFields;
84
+
75
85
// reserve first spot in the layout vector for buffer size
76
86
Layout.push_back (0 );
77
87
@@ -84,22 +94,55 @@ llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType(
84
94
" HLSL doesn't support multiple inheritance" );
85
95
RecordTypes.push_back (D->bases_begin ()->getType ()->getAs <RecordType>());
86
96
}
97
+
98
+ unsigned FieldOffset;
99
+ llvm::Type *FieldType;
100
+
87
101
while (!RecordTypes.empty ()) {
88
102
const RecordType *RT = RecordTypes.back ();
89
103
RecordTypes.pop_back ();
90
104
91
105
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 );
100
127
}
101
128
}
102
129
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
+
103
146
// set the size of the buffer
104
147
Layout[0 ] = EndOffset;
105
148
@@ -122,16 +165,19 @@ llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType(
122
165
// The function converts a single field of HLSL Buffer to its corresponding
123
166
// LLVM type and calculates it's layout. Any embedded structs (or
124
167
// 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).
129
173
// Returns true if the conversion was successful.
130
174
// The packoffset parameter contains the field's layout offset provided by the
131
175
// 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) {
135
181
136
182
// Size of element; for arrays this is a size of a single element in the
137
183
// array. Total array size of calculated as (ArrayCount-1) * ArrayStride +
@@ -141,8 +187,7 @@ bool HLSLBufferLayoutBuilder::layoutField(
141
187
unsigned ArrayCount = 1 ;
142
188
unsigned ArrayStride = 0 ;
143
189
144
- const unsigned BufferRowAlign = 16U ;
145
- unsigned NextRowOffset = llvm::alignTo (EndOffset, BufferRowAlign);
190
+ unsigned NextRowOffset = llvm::alignTo (EndOffset, CBufferRowSizeInBytes);
146
191
147
192
llvm::Type *ElemLayoutTy = nullptr ;
148
193
QualType FieldTy = FD->getType ();
@@ -172,7 +217,7 @@ bool HLSLBufferLayoutBuilder::layoutField(
172
217
getScalarOrVectorSizeInBytes (CGM.getTypes ().ConvertTypeForMem (Ty));
173
218
ElemLayoutTy = CGM.getTypes ().ConvertTypeForMem (FieldTy);
174
219
}
175
- ArrayStride = llvm::alignTo (ElemSize, BufferRowAlign );
220
+ ArrayStride = llvm::alignTo (ElemSize, CBufferRowSizeInBytes );
176
221
ElemOffset = (Packoffset != -1 ) ? Packoffset : NextRowOffset;
177
222
178
223
} else if (FieldTy->isStructureType ()) {
@@ -220,8 +265,8 @@ bool HLSLBufferLayoutBuilder::layoutField(
220
265
EndOffset = std::max<unsigned >(EndOffset, NewEndOffset);
221
266
222
267
// 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;
225
270
return true ;
226
271
}
227
272
0 commit comments