20
20
#include " clang/AST/Decl.h"
21
21
#include " clang/AST/Type.h"
22
22
#include " clang/Basic/TargetOptions.h"
23
+ #include " llvm/ADT/SmallVector.h"
23
24
#include " llvm/IR/DerivedTypes.h"
24
25
#include " llvm/IR/GlobalVariable.h"
25
26
#include " llvm/IR/LLVMContext.h"
@@ -70,11 +71,14 @@ void addDisableOptimizations(llvm::Module &M) {
70
71
71
72
} // namespace
72
73
73
- llvm::Type *CGHLSLRuntime::convertHLSLSpecificType (const Type *T) {
74
+ llvm::Type *
75
+ CGHLSLRuntime::convertHLSLSpecificType (const Type *T,
76
+ SmallVector<unsigned > *Packoffsets) {
74
77
assert (T->isHLSLSpecificType () && " Not an HLSL specific type!" );
75
78
76
79
// 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))
78
82
return TargetTy;
79
83
80
84
llvm_unreachable (" Generic handling of HLSL types is not supported." );
@@ -96,153 +100,28 @@ static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) {
96
100
return isResourceRecordType (Ty);
97
101
}
98
102
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.
227
105
void CGHLSLRuntime::emitBufferGlobalsAndMetadata (const HLSLBufferDecl *BufDecl,
228
106
llvm::GlobalVariable *BufGV) {
229
107
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" );
230
117
llvm::StructType *LayoutStruct = cast<llvm::StructType>(
231
- cast<llvm::TargetExtType>(BufGV-> getValueType () )->getTypeParameter (0 ));
118
+ cast<llvm::TargetExtType>(BufLayoutType )->getTypeParameter (0 ));
232
119
233
120
// Start metadata list associating the buffer global variable with its
234
121
// constatns
235
122
SmallVector<llvm::Metadata *> BufGlobals;
236
123
BufGlobals.push_back (ValueAsMetadata::get (BufGV));
237
124
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 ();
246
125
const auto *ElemIt = LayoutStruct->element_begin ();
247
126
for (Decl *D : BufDecl->decls ()) {
248
127
if (isa<CXXRecordDecl, EmptyDecl>(D))
@@ -275,17 +154,6 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
275
154
" number of elements in layout struct does not match" );
276
155
llvm::Type *LayoutType = *ElemIt++;
277
156
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
157
// there might be resources inside the used defined structs
290
158
if (VDTy->isStructureType () && VDTy->isHLSLIntangibleType ())
291
159
// FIXME: handle resources in cbuffer structs
@@ -295,29 +163,15 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
295
163
GlobalVariable *ElemGV =
296
164
cast<GlobalVariable>(CGM.GetAddrOfGlobalVar (VD, LayoutType));
297
165
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));
307
166
}
308
167
assert (ElemIt == LayoutStruct->element_end () &&
309
168
" number of elements in layout struct does not match" );
310
169
// set the size of the buffer
311
- LayoutItems[1 ] = getConstIntMetadata (Ctx, BufferSize);
312
170
313
171
// add buffer metadata to the module
314
172
CGM.getModule ()
315
173
.getOrInsertNamedMetadata (" hlsl.cbs" )
316
174
->addOperand (MDNode::get (Ctx, BufGlobals));
317
-
318
- CGM.getModule ()
319
- .getOrInsertNamedMetadata (" hlsl.cblayouts" )
320
- ->addOperand (MDNode::get (Ctx, LayoutItems));
321
175
}
322
176
323
177
// Creates resource handle type for the HLSL buffer declaration
@@ -331,6 +185,25 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
331
185
return cast<HLSLAttributedResourceType>(QT.getTypePtr ());
332
186
}
333
187
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
+
334
207
// Codegen for HLSLBufferDecl
335
208
void CGHLSLRuntime::addBuffer (const HLSLBufferDecl *BufDecl) {
336
209
@@ -345,16 +218,20 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
345
218
return ;
346
219
347
220
// 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
+
349
225
llvm::TargetExtType *TargetTy =
350
- cast<llvm::TargetExtType>(convertHLSLSpecificType (ResHandleTy));
226
+ cast<llvm::TargetExtType>(convertHLSLSpecificType (
227
+ ResHandleTy, BufDecl->hasValidPackoffset () ? &Layout : nullptr ));
351
228
llvm::GlobalVariable *BufGV =
352
229
new GlobalVariable (TargetTy, /* isConstant*/ true ,
353
230
GlobalValue::LinkageTypes::ExternalLinkage, nullptr ,
354
231
llvm::formatv (" {0}{1}" , BufDecl->getName (),
355
232
BufDecl->isCBuffer () ? " .cb" : " .tb" ),
356
233
GlobalValue::NotThreadLocal);
357
- M .insertGlobalVariable (BufGV);
234
+ CGM. getModule () .insertGlobalVariable (BufGV);
358
235
359
236
// Add globals for constant buffer elements and create metadata nodes
360
237
emitBufferGlobalsAndMetadata (BufDecl, BufGV);
@@ -368,6 +245,21 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
368
245
RBA->getSpaceNumber ());
369
246
}
370
247
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
+
371
263
void CGHLSLRuntime::finishCodeGen () {
372
264
auto &TargetOpts = CGM.getTarget ().getTargetOpts ();
373
265
llvm::Module &M = CGM.getModule ();
0 commit comments