Skip to content

Commit 7d5ee05

Browse files
authored
[sycl-post-link] Add a property with the default values of specialization constants (#3666)
This patch introduces a new property which contains all the defaults for spec constants. It is done by setting of metadata with the default values: ; Compilation line: ; sycl-post-link -spec-const=default -S llvm/test/tools/sycl-post-link/spec-constants/SYCL-2020.ll -o property.table !5 = !{i32 42} !6 = !{%struct.ComposConst { i32 1, double 2.000000e+00, %struct.myConst { i32 13, float 0x4020666660000000 } }} Property set looks this way: [SYCL/specialization constants default values] all=2|gAAAAAAAAAgKAAAA
1 parent 8b90f85 commit 7d5ee05

File tree

7 files changed

+169
-34
lines changed

7 files changed

+169
-34
lines changed

llvm/include/llvm/Support/PropertySetIO.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <map>
4444
#include <memory>
4545
#include <string>
46+
#include <type_traits>
4647

4748
namespace llvm {
4849
namespace util {
@@ -183,32 +184,33 @@ class PropertySetRegistry {
183184
// Specific property category names used by tools.
184185
static constexpr char SYCL_SPECIALIZATION_CONSTANTS[] =
185186
"SYCL/specialization constants";
186-
static constexpr char SYCL_COMPOSITE_SPECIALIZATION_CONSTANTS[] =
187-
"SYCL/composite specialization constants";
187+
static constexpr char SYCL_SPEC_CONSTANTS_DEFAULT_VALUES[] =
188+
"SYCL/specialization constants default values";
188189
static constexpr char SYCL_DEVICELIB_REQ_MASK[] = "SYCL/devicelib req mask";
189190
static constexpr char SYCL_KERNEL_PARAM_OPT_INFO[] = "SYCL/kernel param opt";
190191
static constexpr char SYCL_MISC_PROP[] = "SYCL/misc properties";
191192

192193
// Function for bulk addition of an entire property set under given category
193194
// (property set name).
194-
template <typename T>
195-
void add(StringRef Category, const std::map<StringRef, T> &Props) {
195+
template <typename MapTy> void add(StringRef Category, const MapTy &Props) {
196+
using KeyTy = typename MapTy::value_type::first_type;
197+
static_assert(std::is_same<typename std::remove_const<KeyTy>::type,
198+
llvm::StringRef>::value,
199+
"wrong key type");
200+
196201
assert(PropSetMap.find(Category) == PropSetMap.end() &&
197202
"category already added");
198203
auto &PropSet = PropSetMap[Category];
199204

200205
for (const auto &Prop : Props)
201-
PropSet.insert(std::make_pair(Prop.first, PropertyValue(Prop.second)));
206+
PropSet.insert({Prop.first, PropertyValue(Prop.second)});
202207
}
203208

209+
// Function to add a property to a given category (property set name).
204210
template <typename T>
205-
void add(StringRef Category, const MapVector<StringRef, T> &Props) {
206-
assert(PropSetMap.find(Category) == PropSetMap.end() &&
207-
"category already added");
211+
void add(StringRef Category, StringRef PropName, const T &PropVal) {
208212
auto &PropSet = PropSetMap[Category];
209-
210-
for (const auto &Prop : Props)
211-
PropSet.insert({Prop.first, PropertyValue(Prop.second)});
213+
PropSet.insert({PropName, PropertyValue(PropVal)});
212214
}
213215

214216
// Parses and creates a property set registry.

llvm/lib/Support/PropertySetIO.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ void PropertyValue::copy(const PropertyValue &P) {
195195

196196
constexpr char PropertySetRegistry::SYCL_SPECIALIZATION_CONSTANTS[];
197197
constexpr char PropertySetRegistry::SYCL_DEVICELIB_REQ_MASK[];
198+
constexpr char PropertySetRegistry::SYCL_SPEC_CONSTANTS_DEFAULT_VALUES[];
198199
constexpr char PropertySetRegistry::SYCL_KERNEL_PARAM_OPT_INFO[];
199-
constexpr char PropertySetRegistry::SYCL_COMPOSITE_SPECIALIZATION_CONSTANTS[];
200200
constexpr char PropertySetRegistry::SYCL_MISC_PROP[];
201201

202202
} // namespace util

llvm/test/tools/sycl-post-link/spec-constants/SYCL-2020.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ attributes #3 = { nounwind }
132132

133133
; CHECK: !sycl.specialization-constants = !{![[#ID0:]], ![[#ID1:]], ![[#ID2:]], ![[#ID3:]]}
134134
;
135+
; CHECK-DEF: !sycl.specialization-constants-default-values = !{![[#ID4:]], ![[#ID5:]], ![[#ID6:]], ![[#ID7:]]}
136+
; CHECK-RT-NOT: !sycl.specialization-constants-default-values
137+
;
135138
; CHECK: ![[#ID0]] = !{!"_ZTS14name_generatorIL_Z9id_doubleEE", i32 0, i32 0, i32 8}
136139
; CHECK: ![[#ID1]] = !{!"_ZTS14name_generatorIL_Z6id_intEE", i32 1, i32 0, i32 4}
137140
;
@@ -148,3 +151,8 @@ attributes #3 = { nounwind }
148151
; CHECK-RT-SAME: i32 [[#SCID7]], i32 4, i32 4,
149152
; CHECK-RT-SAME: i32 [[#SCID8]], i32 8, i32 4,
150153
; CHECK-RT-SAME: i32 [[#SCID9]], i32 16, i32 8}
154+
;
155+
; CHECK-DEF: ![[#ID4]] = !{double 3.140000e+00}
156+
; CHECK-DEF: ![[#ID5]] = !{i32 42}
157+
; CHECK-DEF: ![[#ID6]] = !{%struct.ComposConst { i32 1, double 2.000000e+00, %struct.myConst { i32 13, float 0x4020666660000000 } }}
158+
; CHECK-DEF: ![[#ID7]] = !{%struct.ComposConst2 { i8 1, %struct.myConst { i32 52, float 0x40479999A0000000 }, double 2.000000e+00 }}

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

Lines changed: 125 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ constexpr char SPIRV_GET_SPEC_CONST_COMPOSITE[] =
4646
// Name of the metadata which holds a list of all specialization constants (with
4747
// associated information) encountered in the module
4848
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";
4953

5054
void AssertRelease(bool Cond, const char *Msg) {
5155
if (!Cond)
@@ -214,6 +218,11 @@ std::string mangleFuncItanium(StringRef BaseName, const FunctionType *FT) {
214218
return Res;
215219
}
216220

221+
MDNode *generateSpecConstDefaultValueMetadata(StringRef SymID, Value *Default) {
222+
LLVMContext &Ctx = Default->getContext();
223+
return MDNode::get(Ctx, ConstantAsMetadata::get(cast<Constant>(Default)));
224+
}
225+
217226
/// Recursively iterates over a composite type in order to collect information
218227
/// about its scalar elements.
219228
void collectCompositeElementsInfoRecursive(
@@ -264,6 +273,72 @@ void collectCompositeElementsInfoRecursive(
264273
}
265274
}
266275

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+
267342
MDNode *generateSpecConstantMetadata(const Module &M, StringRef SymbolicID,
268343
Type *SCTy, ArrayRef<unsigned> IDs,
269344
bool IsNativeSpecConstant) {
@@ -476,6 +551,7 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
476551
StringMap<SmallVector<unsigned, 1>> IDMap;
477552
StringMap<unsigned> OffsetMap;
478553
MapVector<StringRef, MDNode *> SCMetadata;
554+
SmallVector<MDNode *, 4> DefaultsMetadata;
479555

480556
// Iterate through all declarations of instances of function template
481557
// template <typename T> T __sycl_get*SpecConstantValue(const char *ID)
@@ -531,6 +607,26 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
531607
StringRef SymID = getStringLiteralArg(CI, NameArgNo, DelInsts);
532608
Value *Replacement = nullptr;
533609

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+
534630
if (SetValAtRT) {
535631
// 2. Spec constant value will be set at run time - then add the literal
536632
// to a "spec const string literal ID" -> "vector of integer IDs" map,
@@ -545,25 +641,6 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
545641
IDs.push_back(NextID);
546642
}
547643

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-
567644
// 3. Transform to spirv intrinsic _Z*__spirv_SpecConstant* or
568645
// _Z*__spirv_SpecConstantComposite
569646
Replacement = emitSpecConstantRecursive(SCTy, CI, IDs, DefaultValue);
@@ -630,6 +707,10 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
630707
GEP, PointerType::get(SCTy, GEP->getAddressSpace()), "bc", CI);
631708

632709
Replacement = new LoadInst(SCTy, BitCast, "load", CI);
710+
711+
if (IsNewSpecConstant && DefaultValue)
712+
DefaultsMetadata.push_back(
713+
generateSpecConstDefaultValueMetadata(SymID, DefaultValue));
633714
} else {
634715
// Replace the intrinsic with default C++ value for the spec constant
635716
// type.
@@ -667,12 +748,20 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
667748
for (const auto &P : SCMetadata)
668749
MD->addOperand(P.second);
669750

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+
670759
return IRModified ? PreservedAnalyses::none() : PreservedAnalyses::all();
671760
}
672761

673762
bool SpecConstantsPass::collectSpecConstantMetadata(Module &M,
674763
SpecIDMapTy &IDMap) {
675-
NamedMDNode *MD = M.getOrInsertNamedMetadata(SPEC_CONST_MD_STRING);
764+
NamedMDNode *MD = M.getNamedMetadata(SPEC_CONST_MD_STRING);
676765
if (!MD)
677766
return false;
678767

@@ -699,3 +788,19 @@ bool SpecConstantsPass::collectSpecConstantMetadata(Module &M,
699788

700789
return true;
701790
}
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+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ class SpecConstantsPass : public llvm::PassInfoMixin<SpecConstantsPass> {
6262
// metadata and builds "spec constant name" -> vector<"spec constant int ID">
6363
// map
6464
static bool collectSpecConstantMetadata(llvm::Module &M, SpecIDMapTy &IDMap);
65+
// Searches given module for occurrences of specialization constant-specific
66+
// metadata and builds vector of default values for every spec constant.
67+
static bool
68+
collectSpecConstantDefaultValuesMetadata(llvm::Module &M,
69+
std::vector<char> &DefaultValues);
6570

6671
private:
6772
bool SetValAtRT;

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,17 @@ static string_vector saveDeviceImageProperty(
420420
PropSet.add(
421421
llvm::util::PropertySetRegistry::SYCL_SPECIALIZATION_CONSTANTS,
422422
TmpSpecIDMap);
423+
424+
// Add property with the default values of spec constants only in native
425+
// (default) mode.
426+
if (!ImgPSInfo.SetSpecConstAtRT) {
427+
std::vector<char> DefaultValues;
428+
SpecConstantsPass::collectSpecConstantDefaultValuesMetadata(
429+
*ResultModules[I].get(), DefaultValues);
430+
PropSet.add(llvm::util::PropertySetRegistry::
431+
SYCL_SPEC_CONSTANTS_DEFAULT_VALUES,
432+
"all", DefaultValues);
433+
}
423434
}
424435
}
425436
if (ImgPSInfo.EmitKernelParamInfo) {

sycl/test/basic_tests/SYCL-2020-spec-constants.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// RUN: %clangxx -fsycl -fsycl-device-only -c -o %t.bc %s
22
// RUN: sycl-post-link %t.bc -spec-const=rt -o %t-split1.txt
3-
// RUN: cat %t-split1_0.prop | FileCheck %s
3+
// RUN: cat %t-split1_0.prop | FileCheck %s -check-prefixes=CHECK,CHECK-RT
44
// RUN: sycl-post-link %t.bc -spec-const=default -o %t-split2.txt
5-
// RUN: cat %t-split2_0.prop | FileCheck %s
5+
// RUN: cat %t-split2_0.prop | FileCheck %s -check-prefixes=CHECK,CHECK-DEF
66
// RUN: llvm-spirv -o %t-split1_0.spv -spirv-max-version=1.1 -spirv-ext=+all %t-split1_0.bc
77
// RUN: llvm-spirv -o %t-split2_0.spv -spirv-max-version=1.1 -spirv-ext=+all %t-split2_0.bc
88
//
@@ -100,3 +100,7 @@ int main() {
100100
// CHECK-DAG: _ZTSN2cl4sycl6detail32specialization_id_name_generatorIL_ZL9uint32_idEEE=2|
101101
// CHECK-DAG: _ZTSN2cl4sycl6detail32specialization_id_name_generatorIL_ZL9uint64_idEEE=2|
102102
// FIXME: check line for half constant
103+
104+
// CHECK-RT-NOT: [SYCL/specialization constants default values]
105+
// CHECK-DEF: [SYCL/specialization constants default values]
106+
// CHECK-DEF: all=2|

0 commit comments

Comments
 (0)