@@ -46,6 +46,10 @@ constexpr char SPIRV_GET_SPEC_CONST_COMPOSITE[] =
46
46
// Name of the metadata which holds a list of all specialization constants (with
47
47
// associated information) encountered in the module
48
48
constexpr char SPEC_CONST_MD_STRING[] = " sycl.specialization-constants" ;
49
+ // Name of the metadata which holds a default value list of all specialization
50
+ // constants encountered in the module
51
+ constexpr char SPEC_CONST_DEFAULT_VAL_MD_STRING[] =
52
+ " sycl.specialization-constants-default-values" ;
49
53
50
54
void AssertRelease (bool Cond, const char *Msg) {
51
55
if (!Cond)
@@ -214,6 +218,11 @@ std::string mangleFuncItanium(StringRef BaseName, const FunctionType *FT) {
214
218
return Res;
215
219
}
216
220
221
+ MDNode *generateSpecConstDefaultValueMetadata (StringRef SymID, Value *Default) {
222
+ LLVMContext &Ctx = Default->getContext ();
223
+ return MDNode::get (Ctx, ConstantAsMetadata::get (cast<Constant>(Default)));
224
+ }
225
+
217
226
// / Recursively iterates over a composite type in order to collect information
218
227
// / about its scalar elements.
219
228
void collectCompositeElementsInfoRecursive (
@@ -264,6 +273,72 @@ void collectCompositeElementsInfoRecursive(
264
273
}
265
274
}
266
275
276
+ // / Recursively iterates over a composite type in order to collect information
277
+ // / about default values of its scalar elements.
278
+ // / TODO: processing of composite spec constants here is similar to
279
+ // / collectCompositeElementsInfoRecursive. Possible place for improvement -
280
+ // / factor out the common code, e.g. using visitor pattern.
281
+ void collectCompositeElementsDefaultValuesRecursive (
282
+ const Module &M, Constant *C, unsigned &Offset,
283
+ std::vector<char > &DefaultValues) {
284
+ Type *Ty = C->getType ();
285
+ if (auto *ArrTy = dyn_cast<ArrayType>(Ty)) {
286
+ for (size_t I = 0 ; I < ArrTy->getNumElements (); ++I) {
287
+ Constant *El = cast<Constant>(C->getOperand (I));
288
+ collectCompositeElementsDefaultValuesRecursive (M, El, Offset,
289
+ DefaultValues);
290
+ }
291
+ } else if (auto *StructTy = dyn_cast<StructType>(Ty)) {
292
+ const StructLayout *SL = M.getDataLayout ().getStructLayout (StructTy);
293
+ for (size_t I = 0 , E = StructTy->getNumElements (); I < E; ++I) {
294
+ Constant *El = cast<Constant>(C->getOperand (I));
295
+ // When handling elements of a structure, we do not use manually
296
+ // calculated offsets (which are sum of sizes of all previously
297
+ // encountered elements), but instead rely on data provided for us by
298
+ // DataLayout, because the structure can be unpacked, i.e. padded in
299
+ // order to ensure particular alignment of its elements.
300
+ unsigned LocalOffset = Offset + SL->getElementOffset (I);
301
+
302
+ // If there was some alignment, fill the data between values with zeros.
303
+ while (LocalOffset != DefaultValues.size ())
304
+ DefaultValues.push_back (0 );
305
+
306
+ collectCompositeElementsDefaultValuesRecursive (M, El, LocalOffset,
307
+ DefaultValues);
308
+ }
309
+ // Update "global" offset according to the total size of a handled struct
310
+ // type.
311
+ Offset += SL->getSizeInBytes ();
312
+ } else if (auto *VecTy = dyn_cast<FixedVectorType>(Ty)) {
313
+ for (size_t I = 0 ; I < VecTy->getNumElements (); ++I) {
314
+ Constant *El = cast<Constant>(C->getOperand (I));
315
+ collectCompositeElementsDefaultValuesRecursive (M, El, Offset,
316
+ DefaultValues);
317
+ }
318
+ } else { // Assume that we encountered some scalar element
319
+ int NumBytes = Ty->getScalarSizeInBits () / CHAR_BIT +
320
+ (Ty->getScalarSizeInBits () % 8 != 0 );
321
+ char *CharPtr;
322
+
323
+ if (auto IntConst = dyn_cast<ConstantInt>(C)) {
324
+ auto Val = IntConst->getValue ().getZExtValue ();
325
+ CharPtr = reinterpret_cast <char *>(&Val);
326
+ } else if (auto FPConst = dyn_cast<ConstantFP>(C)) {
327
+ auto Val = FPConst->getValue ();
328
+
329
+ if (NumBytes == 4 ) {
330
+ float v = Val.convertToFloat ();
331
+ CharPtr = reinterpret_cast <char *>(&v);
332
+ } else if (NumBytes == 8 ) {
333
+ double v = Val.convertToDouble ();
334
+ CharPtr = reinterpret_cast <char *>(&v);
335
+ }
336
+ }
337
+ std::copy_n (CharPtr, NumBytes, std::back_inserter (DefaultValues));
338
+ Offset += NumBytes;
339
+ }
340
+ }
341
+
267
342
MDNode *generateSpecConstantMetadata (const Module &M, StringRef SymbolicID,
268
343
Type *SCTy, ArrayRef<unsigned > IDs,
269
344
bool IsNativeSpecConstant) {
@@ -476,6 +551,7 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
476
551
StringMap<SmallVector<unsigned , 1 >> IDMap;
477
552
StringMap<unsigned > OffsetMap;
478
553
MapVector<StringRef, MDNode *> SCMetadata;
554
+ SmallVector<MDNode *, 4 > DefaultsMetadata;
479
555
480
556
// Iterate through all declarations of instances of function template
481
557
// template <typename T> T __sycl_get*SpecConstantValue(const char *ID)
@@ -531,6 +607,26 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
531
607
StringRef SymID = getStringLiteralArg (CI, NameArgNo, DelInsts);
532
608
Value *Replacement = nullptr ;
533
609
610
+ Constant *DefaultValue = nullptr ;
611
+ if (Is2020Intrinsic) {
612
+ // For SYCL 2020, there is a mechanism to specify the default value.
613
+ // It is stored as an initializer of a global variable referenced by
614
+ // the second argument of the intrinsic.
615
+ auto *GV = dyn_cast<GlobalVariable>(
616
+ CI->getArgOperand (NameArgNo + 1 )->stripPointerCasts ());
617
+ // Go through global variable if the second argument was not null.
618
+ if (GV) {
619
+ assert (GV->hasInitializer () && " expected initializer" );
620
+ auto *Initializer = GV->getInitializer ();
621
+ assert ((isa<ConstantAggregate>(Initializer) ||
622
+ Initializer->isZeroValue ()) &&
623
+ " expected specialization_id instance" );
624
+ // specialization_id structure contains a single field which is the
625
+ // default value of corresponding specialization constant.
626
+ DefaultValue = Initializer->getAggregateElement (0u );
627
+ }
628
+ }
629
+
534
630
if (SetValAtRT) {
535
631
// 2. Spec constant value will be set at run time - then add the literal
536
632
// to a "spec const string literal ID" -> "vector of integer IDs" map,
@@ -545,25 +641,6 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
545
641
IDs.push_back (NextID);
546
642
}
547
643
548
- Constant *DefaultValue = nullptr ;
549
- if (Is2020Intrinsic) {
550
- // For SYCL 2020, there is a mechanism to specify the default value.
551
- // It is stored as an initializer of a global variable referenced by
552
- // the second argument of the intrinsic.
553
- auto *GV = dyn_cast<GlobalVariable>(
554
- CI->getArgOperand (NameArgNo + 1 )->stripPointerCasts ());
555
- if (GV) {
556
- assert (GV->hasInitializer () && " expected initializer" );
557
- auto *Initializer = GV->getInitializer ();
558
- assert ((isa<ConstantAggregate>(Initializer) ||
559
- Initializer->isZeroValue ()) &&
560
- " expected specialization_id instance" );
561
- // specialization_id structure contains a single field which is the
562
- // default value of corresponding specialization constant.
563
- DefaultValue = Initializer->getAggregateElement (0u );
564
- }
565
- }
566
-
567
644
// 3. Transform to spirv intrinsic _Z*__spirv_SpecConstant* or
568
645
// _Z*__spirv_SpecConstantComposite
569
646
Replacement = emitSpecConstantRecursive (SCTy, CI, IDs, DefaultValue);
@@ -630,6 +707,10 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
630
707
GEP, PointerType::get (SCTy, GEP->getAddressSpace ()), " bc" , CI);
631
708
632
709
Replacement = new LoadInst (SCTy, BitCast, " load" , CI);
710
+
711
+ if (IsNewSpecConstant && DefaultValue)
712
+ DefaultsMetadata.push_back (
713
+ generateSpecConstDefaultValueMetadata (SymID, DefaultValue));
633
714
} else {
634
715
// Replace the intrinsic with default C++ value for the spec constant
635
716
// type.
@@ -667,12 +748,20 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
667
748
for (const auto &P : SCMetadata)
668
749
MD->addOperand (P.second );
669
750
751
+ // Emit default values metadata only in native (default) spec constants mode.
752
+ if (!SetValAtRT) {
753
+ NamedMDNode *MDDefaults =
754
+ M.getOrInsertNamedMetadata (SPEC_CONST_DEFAULT_VAL_MD_STRING);
755
+ for (const auto &P : DefaultsMetadata)
756
+ MDDefaults->addOperand (P);
757
+ }
758
+
670
759
return IRModified ? PreservedAnalyses::none () : PreservedAnalyses::all ();
671
760
}
672
761
673
762
bool SpecConstantsPass::collectSpecConstantMetadata (Module &M,
674
763
SpecIDMapTy &IDMap) {
675
- NamedMDNode *MD = M.getOrInsertNamedMetadata (SPEC_CONST_MD_STRING);
764
+ NamedMDNode *MD = M.getNamedMetadata (SPEC_CONST_MD_STRING);
676
765
if (!MD)
677
766
return false ;
678
767
@@ -699,3 +788,19 @@ bool SpecConstantsPass::collectSpecConstantMetadata(Module &M,
699
788
700
789
return true ;
701
790
}
791
+
792
+ bool SpecConstantsPass::collectSpecConstantDefaultValuesMetadata (
793
+ Module &M, std::vector<char > &DefaultValues) {
794
+ NamedMDNode *N = M.getNamedMetadata (SPEC_CONST_DEFAULT_VAL_MD_STRING);
795
+ if (!N)
796
+ return false ;
797
+
798
+ unsigned Offset = 0 ;
799
+ for (const auto *Node : N->operands ()) {
800
+ auto *Constant = cast<ConstantAsMetadata>(Node->getOperand (0 ))->getValue ();
801
+ collectCompositeElementsDefaultValuesRecursive (M, Constant, Offset,
802
+ DefaultValues);
803
+ }
804
+
805
+ return true ;
806
+ }
0 commit comments