@@ -51,6 +51,14 @@ constexpr char SPEC_CONST_MD_STRING[] = "sycl.specialization-constants";
51
51
constexpr char SPEC_CONST_DEFAULT_VAL_MD_STRING[] =
52
52
" sycl.specialization-constants-default-values" ;
53
53
54
+ // / Spec. Constant ID is a pair of Id and a flag whether this Id belongs to an
55
+ // / undefined value. Undefined values ('undef' in the IR) are used to get the
56
+ // / required alignment and should be handled in a special manner as padding.
57
+ struct ID {
58
+ unsigned ID;
59
+ bool Undef;
60
+ };
61
+
54
62
StringRef getStringLiteralArg (const CallInst *CI, unsigned ArgNo,
55
63
SmallVectorImpl<Instruction *> &DelInsts) {
56
64
Value *V = CI->getArgOperand (ArgNo)->stripPointerCasts ();
@@ -236,8 +244,13 @@ MDNode *generateSpecConstDefaultValueMetadata(StringRef SymID, Value *Default) {
236
244
// / Recursively iterates over a composite type in order to collect information
237
245
// / about its scalar elements.
238
246
void collectCompositeElementsInfoRecursive (
239
- const Module &M, Type *Ty, const unsigned *&IDIter, unsigned &Offset,
247
+ const Module &M, Type *Ty, const ID *&IDIter, unsigned &Offset,
240
248
std::vector<SpecConstantDescriptor> &Result) {
249
+ if (IDIter->Undef ) {
250
+ // We can just skip undefined values because every such value is just a
251
+ // padding and will be handled in a different manner.
252
+ return ;
253
+ }
241
254
if (auto *ArrTy = dyn_cast<ArrayType>(Ty)) {
242
255
for (size_t I = 0 ; I < ArrTy->getNumElements (); ++I) {
243
256
// TODO: this is a spot for potential optimization: for arrays we could
@@ -246,7 +259,9 @@ void collectCompositeElementsInfoRecursive(
246
259
collectCompositeElementsInfoRecursive (M, ArrTy->getElementType (), IDIter,
247
260
Offset, Result);
248
261
}
249
- } else if (auto *StructTy = dyn_cast<StructType>(Ty)) {
262
+ return ;
263
+ }
264
+ if (auto *StructTy = dyn_cast<StructType>(Ty)) {
250
265
const StructLayout *SL = M.getDataLayout ().getStructLayout (StructTy);
251
266
const unsigned BaseOffset = Offset;
252
267
unsigned LocalOffset = Offset;
@@ -267,7 +282,12 @@ void collectCompositeElementsInfoRecursive(
267
282
BaseOffset + SL->getSizeInBytes () - LocalOffset;
268
283
if (PostStructPadding > 0 ) {
269
284
SpecConstantDescriptor Desc;
270
- // ID of padding descriptors is the max value possible.
285
+ // ID of padding descriptors is the max value possible. This value is a
286
+ // magic value for the runtime and will just be skipped. Even if there
287
+ // are many specialization constants and every constant has padding of
288
+ // a different length, everything will work regardless rewriting
289
+ // the descriptions with Desc.ID equals to the max value: they will just
290
+ // be ignored at all.
271
291
Desc.ID = std::numeric_limits<unsigned >::max ();
272
292
Desc.Offset = LocalOffset;
273
293
Desc.Size = PostStructPadding;
@@ -277,25 +297,29 @@ void collectCompositeElementsInfoRecursive(
277
297
// Update "global" offset according to the total size of a handled struct
278
298
// type.
279
299
Offset += SL->getSizeInBytes ();
280
- } else if (auto *VecTy = dyn_cast<FixedVectorType>(Ty)) {
300
+ return ;
301
+ }
302
+ if (auto *VecTy = dyn_cast<FixedVectorType>(Ty)) {
281
303
for (size_t I = 0 ; I < VecTy->getNumElements (); ++I) {
282
304
// TODO: this is a spot for potential optimization: for vectors we could
283
305
// just make a single recursive call here and use it to populate Result
284
306
// in a loop.
285
307
collectCompositeElementsInfoRecursive (M, VecTy->getElementType (), IDIter,
286
308
Offset, Result);
287
309
}
288
- } else { // Assume that we encountered some scalar element
289
- SpecConstantDescriptor Desc;
290
- Desc.ID = *IDIter;
291
- Desc.Offset = Offset;
292
- Desc.Size = M.getDataLayout ().getTypeStoreSize (Ty);
293
- Result.push_back (Desc);
294
-
295
- // Move current ID and offset
296
- ++IDIter;
297
- Offset += Desc.Size ;
310
+ return ;
298
311
}
312
+
313
+ // Assume that we encountered some scalar element
314
+ SpecConstantDescriptor Desc;
315
+ Desc.ID = IDIter->ID ;
316
+ Desc.Offset = Offset;
317
+ Desc.Size = M.getDataLayout ().getTypeStoreSize (Ty);
318
+ Result.push_back (Desc);
319
+
320
+ // Move current ID and offset
321
+ ++IDIter;
322
+ Offset += Desc.Size ;
299
323
}
300
324
301
325
// / Recursively iterates over a composite type in order to collect information
@@ -400,7 +424,7 @@ void collectCompositeElementsDefaultValuesRecursive(
400
424
}
401
425
402
426
MDNode *generateSpecConstantMetadata (const Module &M, StringRef SymbolicID,
403
- Type *SCTy, ArrayRef<unsigned > IDs,
427
+ Type *SCTy, ArrayRef<ID > IDs,
404
428
bool IsNativeSpecConstant) {
405
429
SmallVector<Metadata *, 16 > MDOps;
406
430
LLVMContext &Ctx = M.getContext ();
@@ -413,7 +437,7 @@ MDNode *generateSpecConstantMetadata(const Module &M, StringRef SymbolicID,
413
437
std::vector<SpecConstantDescriptor> Result;
414
438
Result.reserve (IDs.size ());
415
439
unsigned Offset = 0 ;
416
- const unsigned *IDPtr = IDs.data ();
440
+ const ID *IDPtr = IDs.data ();
417
441
collectCompositeElementsInfoRecursive (M, SCTy, IDPtr, Offset, Result);
418
442
419
443
// We may have padding elements so size should be at least the same size as
@@ -432,7 +456,7 @@ MDNode *generateSpecConstantMetadata(const Module &M, StringRef SymbolicID,
432
456
assert (IDs.size () == 1 &&
433
457
" There must be a single ID for emulated spec constant" );
434
458
MDOps.push_back (ConstantAsMetadata::get (
435
- Constant::getIntegerValue (Int32Ty, APInt (32 , IDs[0 ]))));
459
+ Constant::getIntegerValue (Int32Ty, APInt (32 , IDs[0 ]. ID ))));
436
460
// Second element is always zero here
437
461
MDOps.push_back (ConstantAsMetadata::get (
438
462
Constant::getIntegerValue (Int32Ty, APInt (32 , 0 ))));
@@ -548,25 +572,35 @@ Instruction *emitSpecConstantComposite(Type *Ty, ArrayRef<Value *> Elements,
548
572
// / composite (plus for the top-level composite). Also enumerates all
549
573
// / encountered scalars and assigns them IDs (or re-uses existing ones).
550
574
Instruction *emitSpecConstantRecursiveImpl (Type *Ty, Instruction *InsertBefore,
551
- SmallVectorImpl<unsigned > &IDs,
575
+ SmallVectorImpl<ID > &IDs,
552
576
unsigned &Index,
553
577
Constant *DefaultValue) {
554
578
if (!Ty->isArrayTy () && !Ty->isStructTy () && !Ty->isVectorTy ()) { // Scalar
555
579
if (Index >= IDs.size ()) {
556
580
// If it is a new specialization constant, we need to generate IDs for
557
581
// scalar elements, starting with the second one.
558
- IDs.push_back (IDs.back () + 1 );
582
+ assert (!isa_and_nonnull<UndefValue>(DefaultValue) &&
583
+ " All scalar values should be defined" );
584
+ IDs.push_back ({IDs.back ().ID + 1 , false });
559
585
}
560
- return emitSpecConstant (IDs[Index++], Ty, InsertBefore, DefaultValue);
586
+ return emitSpecConstant (IDs[Index++]. ID , Ty, InsertBefore, DefaultValue);
561
587
}
562
588
563
589
SmallVector<Value *, 8 > Elements;
590
+ auto HandleUndef = [&](Constant *Def) {
591
+ if (Index >= IDs.size ()) {
592
+ // If it is a new specialization constant, we need to generate IDs for
593
+ // the whole undef value.
594
+ IDs.push_back ({IDs.back ().ID + 1 , true });
595
+ }
596
+ Elements.push_back (Def);
597
+ };
564
598
auto LoopIteration = [&](Type *Ty, unsigned LocalIndex) {
565
599
// Select corresponding element of the default value if it was provided
566
600
Constant *Def =
567
601
DefaultValue ? DefaultValue->getAggregateElement (LocalIndex) : nullptr ;
568
602
if (isa_and_nonnull<UndefValue>(Def))
569
- Elements. push_back (Def);
603
+ HandleUndef (Def);
570
604
else
571
605
Elements.push_back (
572
606
emitSpecConstantRecursiveImpl (Ty, InsertBefore, IDs, Index, Def));
@@ -576,7 +610,7 @@ Instruction *emitSpecConstantRecursiveImpl(Type *Ty, Instruction *InsertBefore,
576
610
// If the default value is a composite and has the value 'undef', we should
577
611
// not generate a bunch of __spirv_SpecConstant for its elements but
578
612
// pass it into __spirv_SpecConstantComposite as is.
579
- Elements. push_back (DefaultValue);
613
+ HandleUndef (DefaultValue);
580
614
} else if (auto *ArrTy = dyn_cast<ArrayType>(Ty)) {
581
615
for (size_t I = 0 ; I < ArrTy->getNumElements (); ++I) {
582
616
LoopIteration (ArrTy->getElementType (), I);
@@ -599,7 +633,7 @@ Instruction *emitSpecConstantRecursiveImpl(Type *Ty, Instruction *InsertBefore,
599
633
600
634
// / Wrapper intended to hide IsFirstElement argument from the caller
601
635
Instruction *emitSpecConstantRecursive (Type *Ty, Instruction *InsertBefore,
602
- SmallVectorImpl<unsigned > &IDs,
636
+ SmallVectorImpl<ID > &IDs,
603
637
Constant *DefaultValue) {
604
638
unsigned Index = 0 ;
605
639
return emitSpecConstantRecursiveImpl (Ty, InsertBefore, IDs, Index,
@@ -610,9 +644,9 @@ Instruction *emitSpecConstantRecursive(Type *Ty, Instruction *InsertBefore,
610
644
611
645
PreservedAnalyses SpecConstantsPass::run (Module &M,
612
646
ModuleAnalysisManager &MAM) {
613
- unsigned NextID = 0 ;
647
+ ID NextID = { 0 , false } ;
614
648
unsigned NextOffset = 0 ;
615
- StringMap<SmallVector<unsigned , 1 >> IDMap;
649
+ StringMap<SmallVector<ID , 1 >> IDMap;
616
650
StringMap<unsigned > OffsetMap;
617
651
MapVector<StringRef, MDNode *> SCMetadata;
618
652
SmallVector<MDNode *, 4 > DefaultsMetadata;
@@ -693,9 +727,8 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
693
727
if (SetValAtRT) {
694
728
// 2. Spec constant value will be set at run time - then add the literal
695
729
// to a "spec const string literal ID" -> "vector of integer IDs" map,
696
- // uniquing the integer IDs if this is a new literal
697
- auto Ins =
698
- IDMap.insert (std::make_pair (SymID, SmallVector<unsigned , 1 >{}));
730
+ // making the integer IDs unique if this is a new literal
731
+ auto Ins = IDMap.insert (std::make_pair (SymID, SmallVector<ID, 1 >{}));
699
732
IsNewSpecConstant = Ins.second ;
700
733
auto &IDs = Ins.first ->second ;
701
734
if (IsNewSpecConstant) {
@@ -711,7 +744,7 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
711
744
// emitSpecConstantRecursive might emit more than one spec constant
712
745
// (because of composite types) and therefore, we need to adjust
713
746
// NextID according to the actual amount of emitted spec constants.
714
- NextID += IDs.size ();
747
+ NextID. ID += IDs.size ();
715
748
716
749
// Generate necessary metadata which later will be pulled by
717
750
// sycl-post-link and transformed into device image properties
@@ -743,7 +776,7 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
743
776
SCMetadata[SymID] = generateSpecConstantMetadata (
744
777
M, SymID, SCTy, NextID, /* is native spec constant */ false );
745
778
746
- ++NextID;
779
+ ++NextID. ID ;
747
780
NextOffset += Size;
748
781
}
749
782
0 commit comments