Skip to content

Commit 7ac0966

Browse files
author
Pavel Samolysov
committed
[sycl-post-link] Add undefined value handling
1 parent b1d7f1d commit 7ac0966

File tree

1 file changed

+63
-30
lines changed

1 file changed

+63
-30
lines changed

llvm/tools/sycl-post-link/SpecConstants.cpp

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ constexpr char SPEC_CONST_MD_STRING[] = "sycl.specialization-constants";
5151
constexpr char SPEC_CONST_DEFAULT_VAL_MD_STRING[] =
5252
"sycl.specialization-constants-default-values";
5353

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+
5462
StringRef getStringLiteralArg(const CallInst *CI, unsigned ArgNo,
5563
SmallVectorImpl<Instruction *> &DelInsts) {
5664
Value *V = CI->getArgOperand(ArgNo)->stripPointerCasts();
@@ -236,8 +244,13 @@ MDNode *generateSpecConstDefaultValueMetadata(StringRef SymID, Value *Default) {
236244
/// Recursively iterates over a composite type in order to collect information
237245
/// about its scalar elements.
238246
void collectCompositeElementsInfoRecursive(
239-
const Module &M, Type *Ty, const unsigned *&IDIter, unsigned &Offset,
247+
const Module &M, Type *Ty, const ID *&IDIter, unsigned &Offset,
240248
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+
}
241254
if (auto *ArrTy = dyn_cast<ArrayType>(Ty)) {
242255
for (size_t I = 0; I < ArrTy->getNumElements(); ++I) {
243256
// TODO: this is a spot for potential optimization: for arrays we could
@@ -246,7 +259,9 @@ void collectCompositeElementsInfoRecursive(
246259
collectCompositeElementsInfoRecursive(M, ArrTy->getElementType(), IDIter,
247260
Offset, Result);
248261
}
249-
} else if (auto *StructTy = dyn_cast<StructType>(Ty)) {
262+
return;
263+
}
264+
if (auto *StructTy = dyn_cast<StructType>(Ty)) {
250265
const StructLayout *SL = M.getDataLayout().getStructLayout(StructTy);
251266
const unsigned BaseOffset = Offset;
252267
unsigned LocalOffset = Offset;
@@ -267,7 +282,12 @@ void collectCompositeElementsInfoRecursive(
267282
BaseOffset + SL->getSizeInBytes() - LocalOffset;
268283
if (PostStructPadding > 0) {
269284
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.
271291
Desc.ID = std::numeric_limits<unsigned>::max();
272292
Desc.Offset = LocalOffset;
273293
Desc.Size = PostStructPadding;
@@ -277,25 +297,29 @@ void collectCompositeElementsInfoRecursive(
277297
// Update "global" offset according to the total size of a handled struct
278298
// type.
279299
Offset += SL->getSizeInBytes();
280-
} else if (auto *VecTy = dyn_cast<FixedVectorType>(Ty)) {
300+
return;
301+
}
302+
if (auto *VecTy = dyn_cast<FixedVectorType>(Ty)) {
281303
for (size_t I = 0; I < VecTy->getNumElements(); ++I) {
282304
// TODO: this is a spot for potential optimization: for vectors we could
283305
// just make a single recursive call here and use it to populate Result
284306
// in a loop.
285307
collectCompositeElementsInfoRecursive(M, VecTy->getElementType(), IDIter,
286308
Offset, Result);
287309
}
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;
298311
}
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;
299323
}
300324

301325
/// Recursively iterates over a composite type in order to collect information
@@ -400,7 +424,7 @@ void collectCompositeElementsDefaultValuesRecursive(
400424
}
401425

402426
MDNode *generateSpecConstantMetadata(const Module &M, StringRef SymbolicID,
403-
Type *SCTy, ArrayRef<unsigned> IDs,
427+
Type *SCTy, ArrayRef<ID> IDs,
404428
bool IsNativeSpecConstant) {
405429
SmallVector<Metadata *, 16> MDOps;
406430
LLVMContext &Ctx = M.getContext();
@@ -413,7 +437,7 @@ MDNode *generateSpecConstantMetadata(const Module &M, StringRef SymbolicID,
413437
std::vector<SpecConstantDescriptor> Result;
414438
Result.reserve(IDs.size());
415439
unsigned Offset = 0;
416-
const unsigned *IDPtr = IDs.data();
440+
const ID *IDPtr = IDs.data();
417441
collectCompositeElementsInfoRecursive(M, SCTy, IDPtr, Offset, Result);
418442

419443
// 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,
432456
assert(IDs.size() == 1 &&
433457
"There must be a single ID for emulated spec constant");
434458
MDOps.push_back(ConstantAsMetadata::get(
435-
Constant::getIntegerValue(Int32Ty, APInt(32, IDs[0]))));
459+
Constant::getIntegerValue(Int32Ty, APInt(32, IDs[0].ID))));
436460
// Second element is always zero here
437461
MDOps.push_back(ConstantAsMetadata::get(
438462
Constant::getIntegerValue(Int32Ty, APInt(32, 0))));
@@ -548,25 +572,35 @@ Instruction *emitSpecConstantComposite(Type *Ty, ArrayRef<Value *> Elements,
548572
/// composite (plus for the top-level composite). Also enumerates all
549573
/// encountered scalars and assigns them IDs (or re-uses existing ones).
550574
Instruction *emitSpecConstantRecursiveImpl(Type *Ty, Instruction *InsertBefore,
551-
SmallVectorImpl<unsigned> &IDs,
575+
SmallVectorImpl<ID> &IDs,
552576
unsigned &Index,
553577
Constant *DefaultValue) {
554578
if (!Ty->isArrayTy() && !Ty->isStructTy() && !Ty->isVectorTy()) { // Scalar
555579
if (Index >= IDs.size()) {
556580
// If it is a new specialization constant, we need to generate IDs for
557581
// 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});
559585
}
560-
return emitSpecConstant(IDs[Index++], Ty, InsertBefore, DefaultValue);
586+
return emitSpecConstant(IDs[Index++].ID, Ty, InsertBefore, DefaultValue);
561587
}
562588

563589
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+
};
564598
auto LoopIteration = [&](Type *Ty, unsigned LocalIndex) {
565599
// Select corresponding element of the default value if it was provided
566600
Constant *Def =
567601
DefaultValue ? DefaultValue->getAggregateElement(LocalIndex) : nullptr;
568602
if (isa_and_nonnull<UndefValue>(Def))
569-
Elements.push_back(Def);
603+
HandleUndef(Def);
570604
else
571605
Elements.push_back(
572606
emitSpecConstantRecursiveImpl(Ty, InsertBefore, IDs, Index, Def));
@@ -576,7 +610,7 @@ Instruction *emitSpecConstantRecursiveImpl(Type *Ty, Instruction *InsertBefore,
576610
// If the default value is a composite and has the value 'undef', we should
577611
// not generate a bunch of __spirv_SpecConstant for its elements but
578612
// pass it into __spirv_SpecConstantComposite as is.
579-
Elements.push_back(DefaultValue);
613+
HandleUndef(DefaultValue);
580614
} else if (auto *ArrTy = dyn_cast<ArrayType>(Ty)) {
581615
for (size_t I = 0; I < ArrTy->getNumElements(); ++I) {
582616
LoopIteration(ArrTy->getElementType(), I);
@@ -599,7 +633,7 @@ Instruction *emitSpecConstantRecursiveImpl(Type *Ty, Instruction *InsertBefore,
599633

600634
/// Wrapper intended to hide IsFirstElement argument from the caller
601635
Instruction *emitSpecConstantRecursive(Type *Ty, Instruction *InsertBefore,
602-
SmallVectorImpl<unsigned> &IDs,
636+
SmallVectorImpl<ID> &IDs,
603637
Constant *DefaultValue) {
604638
unsigned Index = 0;
605639
return emitSpecConstantRecursiveImpl(Ty, InsertBefore, IDs, Index,
@@ -610,9 +644,9 @@ Instruction *emitSpecConstantRecursive(Type *Ty, Instruction *InsertBefore,
610644

611645
PreservedAnalyses SpecConstantsPass::run(Module &M,
612646
ModuleAnalysisManager &MAM) {
613-
unsigned NextID = 0;
647+
ID NextID = {0, false};
614648
unsigned NextOffset = 0;
615-
StringMap<SmallVector<unsigned, 1>> IDMap;
649+
StringMap<SmallVector<ID, 1>> IDMap;
616650
StringMap<unsigned> OffsetMap;
617651
MapVector<StringRef, MDNode *> SCMetadata;
618652
SmallVector<MDNode *, 4> DefaultsMetadata;
@@ -693,9 +727,8 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
693727
if (SetValAtRT) {
694728
// 2. Spec constant value will be set at run time - then add the literal
695729
// 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>{}));
699732
IsNewSpecConstant = Ins.second;
700733
auto &IDs = Ins.first->second;
701734
if (IsNewSpecConstant) {
@@ -711,7 +744,7 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
711744
// emitSpecConstantRecursive might emit more than one spec constant
712745
// (because of composite types) and therefore, we need to adjust
713746
// NextID according to the actual amount of emitted spec constants.
714-
NextID += IDs.size();
747+
NextID.ID += IDs.size();
715748

716749
// Generate necessary metadata which later will be pulled by
717750
// sycl-post-link and transformed into device image properties
@@ -743,7 +776,7 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
743776
SCMetadata[SymID] = generateSpecConstantMetadata(
744777
M, SymID, SCTy, NextID, /* is native spec constant */ false);
745778

746-
++NextID;
779+
++NextID.ID;
747780
NextOffset += Size;
748781
}
749782

0 commit comments

Comments
 (0)