Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions llvm/include/llvm/Support/PropertySetIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ class PropertySetRegistry {
"SYCL/specialization constants";
static constexpr char SYCL_COMPOSITE_SPECIALIZATION_CONSTANTS[] =
"SYCL/composite specialization constants";
static constexpr char SYCL_SPEC_CONSTANTS_DEFAULT_VALUES[] =
"SYCL/specialization constants default values";
static constexpr char SYCL_DEVICELIB_REQ_MASK[] = "SYCL/devicelib req mask";
static constexpr char SYCL_KERNEL_PARAM_OPT_INFO[] = "SYCL/kernel param opt";
static constexpr char SYCL_MISC_PROP[] = "SYCL/misc properties";
Expand All @@ -201,6 +203,13 @@ class PropertySetRegistry {
PropSet.insert(std::make_pair(Prop.first, PropertyValue(Prop.second)));
}

// Function to add a property to a given category (property set name).
template <typename T>
void add(StringRef Category, StringRef PropName, T &PropVal) {
auto &PropSet = PropSetMap[Category];
PropSet.insert(std::make_pair(PropName, PropertyValue(PropVal)));
}

// Parses and creates a property set registry.
static Expected<std::unique_ptr<PropertySetRegistry>>
read(const MemoryBuffer *Buf);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Support/PropertySetIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ void PropertyValue::copy(const PropertyValue &P) {

constexpr char PropertySetRegistry::SYCL_SPECIALIZATION_CONSTANTS[];
constexpr char PropertySetRegistry::SYCL_DEVICELIB_REQ_MASK[];
constexpr char PropertySetRegistry::SYCL_SPEC_CONSTANTS_DEFAULT_VALUES[];
constexpr char PropertySetRegistry::SYCL_KERNEL_PARAM_OPT_INFO[];
constexpr char PropertySetRegistry::SYCL_COMPOSITE_SPECIALIZATION_CONSTANTS[];
constexpr char PropertySetRegistry::SYCL_MISC_PROP[];
Expand Down
8 changes: 8 additions & 0 deletions llvm/test/tools/sycl-post-link/spec-constants/SYCL-2020.ll
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ attributes #3 = { nounwind }

; CHECK: !sycl.specialization-constants = !{![[#ID0:]], ![[#ID1:]], ![[#ID2:]], ![[#ID3:]]}
;
; CHECK-DEF: !sycl.specialization-constants-default-values = !{![[#ID4:]], ![[#ID5:]], ![[#ID6:]], ![[#ID7:]]}
; CHECK-RT-NOT: !sycl.specialization-constants-default-values
;
; CHECK: ![[#ID0]] = !{!"_ZTS14name_generatorIL_Z9id_doubleEE", i32 0, i32 0, i32 8}
; CHECK: ![[#ID1]] = !{!"_ZTS14name_generatorIL_Z6id_intEE", i32 1, i32 0, i32 4}
;
Expand All @@ -148,3 +151,8 @@ attributes #3 = { nounwind }
; CHECK-RT-SAME: i32 [[#SCID7]], i32 4, i32 4,
; CHECK-RT-SAME: i32 [[#SCID8]], i32 8, i32 4,
; CHECK-RT-SAME: i32 [[#SCID9]], i32 16, i32 8}
;
; CHECK-DEF: ![[#ID4]] = !{double 3.140000e+00}
; CHECK-DEF: ![[#ID5]] = !{i32 42}
; CHECK-DEF: ![[#ID6]] = !{%struct.ComposConst { i32 1, double 2.000000e+00, %struct.myConst { i32 13, float 0x4020666660000000 } }}
; CHECK-DEF: ![[#ID7]] = !{%struct.ComposConst2 { i8 1, %struct.myConst { i32 52, float 0x40479999A0000000 }, double 2.000000e+00 }}
145 changes: 124 additions & 21 deletions llvm/tools/sycl-post-link/SpecConstants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ constexpr char SPIRV_GET_SPEC_CONST_COMPOSITE[] =
// Name of the metadata which holds a list of all specialization constants (with
// associated information) encountered in the module
constexpr char SPEC_CONST_MD_STRING[] = "sycl.specialization-constants";
// Name of the metadata which holds a default value list of all specialization
// constants encountered in the module
constexpr char SPEC_CONST_DEFAULT_VAL_MD_STRING[] =
"sycl.specialization-constants-default-values";

void AssertRelease(bool Cond, const char *Msg) {
if (!Cond)
Expand Down Expand Up @@ -215,6 +219,12 @@ std::string mangleFuncItanium(StringRef BaseName, const FunctionType *FT) {
return Res;
}

MDNode *generateSpecConstDefaultValueMetadata(Instruction *I, StringRef SymID,
Value *Default) {
LLVMContext &Ctx = I->getContext();
return MDNode::get(Ctx, ConstantAsMetadata::get(cast<Constant>(Default)));
}

/// Recursively iterates over a composite type in order to collect information
/// about its scalar elements.
void collectCompositeElementsInfoRecursive(
Expand Down Expand Up @@ -265,6 +275,69 @@ void collectCompositeElementsInfoRecursive(
}
}

/// Recursively iterates over a composite type in order to collect information
/// about default values of its scalar elements.
void collectCompositeElementsDefaultValuesRecursive(
const Module &M, Constant *C, unsigned &Offset,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: processing of composite spec constants is similar in this function, emitSpecConstantRecursiveImpl and generateSpecConstDefaultValueMetadata. Could be factored out using e.g. the visitor pattern. At least a TODO for now would be good.

std::vector<char> &DefaultValues) {
Type *Ty = C->getType();
if (auto *ArrTy = dyn_cast<ArrayType>(Ty)) {
for (size_t I = 0; I < ArrTy->getNumElements(); ++I) {
Constant *El = cast<Constant>(C->getOperand(I));
collectCompositeElementsDefaultValuesRecursive(M, El, Offset,
DefaultValues);
}
} else if (auto *StructTy = dyn_cast<StructType>(Ty)) {
const StructLayout *SL = M.getDataLayout().getStructLayout(StructTy);
for (size_t I = 0, E = StructTy->getNumElements(); I < E; ++I) {
Constant *El = cast<Constant>(C->getOperand(I));
// When handling elements of a structure, we do not use manually
// calculated offsets (which are sum of sizes of all previously
// encountered elements), but instead rely on data provided for us by
// DataLayout, because the structure can be unpacked, i.e. padded in
// order to ensure particular alignment of its elements.
unsigned LocalOffset = Offset + SL->getElementOffset(I);

// If there was some alignment, fill the data between values with zeros.
while (LocalOffset != DefaultValues.size())
DefaultValues.push_back(0);

collectCompositeElementsDefaultValuesRecursive(M, El, LocalOffset,
DefaultValues);
}
// Update "global" offset according to the total size of a handled struct
// type.
Offset += SL->getSizeInBytes();
} else if (auto *VecTy = dyn_cast<FixedVectorType>(Ty)) {
for (size_t I = 0; I < VecTy->getNumElements(); ++I) {
Constant *El = cast<Constant>(C->getOperand(I));
collectCompositeElementsDefaultValuesRecursive(M, El, Offset,
DefaultValues);
}
} else { // Assume that we encountered some scalar element
int NumBytes = Ty->getScalarSizeInBits() / CHAR_BIT +
(Ty->getScalarSizeInBits() % 8 != 0);
char *CharPtr;

if (auto IntConst = dyn_cast<ConstantInt>(C)) {
auto Val = IntConst->getValue().getZExtValue();
CharPtr = reinterpret_cast<char *>(&Val);
} else if (auto FPConst = dyn_cast<ConstantFP>(C)) {
auto Val = FPConst->getValue();

if (NumBytes == 4) {
float v = Val.convertToFloat();
CharPtr = reinterpret_cast<char *>(&v);
} else if (NumBytes == 8) {
double v = Val.convertToDouble();
CharPtr = reinterpret_cast<char *>(&v);
}
}
std::copy_n(CharPtr, NumBytes, std::back_inserter(DefaultValues));
Offset += NumBytes;
}
}

MDNode *generateSpecConstantMetadata(const Module &M, StringRef SymbolicID,
Type *SCTy, ArrayRef<unsigned> IDs,
bool IsNativeSpecConstant) {
Expand Down Expand Up @@ -435,6 +508,7 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
StringMap<SmallVector<unsigned, 1>> IDMap;
StringMap<unsigned> OffsetMap;
MapVector<StringRef, MDNode *> SCMetadata;
SmallVector<MDNode *, 1> DefaultsMetadata;

// Iterate through all declarations of instances of function template
// template <typename T> T __sycl_get*SpecConstantValue(const char *ID)
Expand Down Expand Up @@ -486,6 +560,25 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
StringRef SymID = getStringLiteralArg(CI, NameArgNo, DelInsts);
Value *Replacement = nullptr;

Constant *DefaultValue = nullptr;
if (Is2020Intrinsic) {
// For SYCL 2020, there is a mechanism to specify the default value.
// It is stored as an initializer of a global variable referenced by
// the second argument of the intrinsic.
auto *GV = dyn_cast<GlobalVariable>(
CI->getArgOperand(NameArgNo + 1)->stripPointerCasts());
if (GV) {
assert(GV->hasInitializer() && "expected initializer");
auto *Initializer = GV->getInitializer();
assert((isa<ConstantAggregate>(Initializer) ||
Initializer->isZeroValue()) &&
"expected specialization_id instance");
// specialization_id structure contains a single field which is the
// default value of corresponding specialization constant.
DefaultValue = Initializer->getAggregateElement(0u);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what GV == 0 means? please add a comment or handle

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably we should just use cast instead of dyn_cast and always expect to see a value there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can meet nullptr instead of value here - this check is still needed. I left a comment above the if-.


if (SetValAtRT) {
// 2. Spec constant value will be set at run time - then add the literal
// to a "spec const string literal ID" -> "vector of integer IDs" map,
Expand All @@ -500,25 +593,6 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
IDs.push_back(NextID);
}

Constant *DefaultValue = nullptr;
if (Is2020Intrinsic) {
// For SYCL 2020, there is a mechanism to specify the default value.
// It is stored as an initializer of a global variable referenced by
// the second argument of the intrinsic.
auto *GV = dyn_cast<GlobalVariable>(
CI->getArgOperand(NameArgNo + 1)->stripPointerCasts());
if (GV) {
assert(GV->hasInitializer() && "expected initializer");
auto *Initializer = GV->getInitializer();
assert((isa<ConstantAggregate>(Initializer) ||
Initializer->isZeroValue()) &&
"expected specialization_id instance");
// specialization_id structure contains a single field which is the
// default value of corresponding specialization constant.
DefaultValue = Initializer->getAggregateElement(0u);
}
}

// 3. Transform to spirv intrinsic _Z*__spirv_SpecConstant* or
// _Z*__spirv_SpecConstantComposite
Replacement = emitSpecConstantRecursive(SCTy, CI, IDs, DefaultValue);
Expand Down Expand Up @@ -584,7 +658,12 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
BitCastInst *BitCast = new BitCastInst(
GEP, PointerType::get(SCTy, GEP->getAddressSpace()), "bc", CI);

Replacement = new LoadInst(SCTy, BitCast, "load", CI);
Instruction *Inst = new LoadInst(SCTy, BitCast, "load", CI);
Replacement = Inst;

if (IsNewSpecConstant && DefaultValue)
DefaultsMetadata.push_back(generateSpecConstDefaultValueMetadata(
Inst, SymID, DefaultValue));
} else {
// Replace the intrinsic with default C++ value for the spec constant
// type.
Expand Down Expand Up @@ -622,12 +701,20 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
for (const auto &P : SCMetadata)
MD->addOperand(P.second);

// Emit default values metadata only in native (default) spec constants mode.
if (!SetValAtRT) {
NamedMDNode *MDDefaults =
M.getOrInsertNamedMetadata(SPEC_CONST_DEFAULT_VAL_MD_STRING);
for (const auto &P : DefaultsMetadata)
MDDefaults->addOperand(P);
}

return IRModified ? PreservedAnalyses::none() : PreservedAnalyses::all();
}

bool SpecConstantsPass::collectSpecConstantMetadata(Module &M,
SpecIDMapTy &IDMap) {
NamedMDNode *MD = M.getOrInsertNamedMetadata(SPEC_CONST_MD_STRING);
NamedMDNode *MD = M.getNamedMetadata(SPEC_CONST_MD_STRING);
if (!MD)
return false;

Expand All @@ -654,3 +741,19 @@ bool SpecConstantsPass::collectSpecConstantMetadata(Module &M,

return true;
}

bool SpecConstantsPass::collectSpecConstantDefaultValuesMetadata(
Module &M, std::vector<char> &DefaultValues) {
NamedMDNode *N = M.getNamedMetadata(SPEC_CONST_DEFAULT_VAL_MD_STRING);
if (!N)
return false;

unsigned Offset = 0;
for (const auto *Node : N->operands()) {
auto *Constant = cast<ConstantAsMetadata>(Node->getOperand(0))->getValue();
collectCompositeElementsDefaultValuesRecursive(M, Constant, Offset,
DefaultValues);
}

return true;
}
5 changes: 5 additions & 0 deletions llvm/tools/sycl-post-link/SpecConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ class SpecConstantsPass : public llvm::PassInfoMixin<SpecConstantsPass> {
// metadata and builds "spec constant name" -> vector<"spec constant int ID">
// map
static bool collectSpecConstantMetadata(llvm::Module &M, SpecIDMapTy &IDMap);
// Searches given module for occurrences of specialization constant-specific
// metadata and builds vector of default values for every spec constant.
static bool
collectSpecConstantDefaultValuesMetadata(llvm::Module &M,
std::vector<char> &DefaultValues);

private:
bool SetValAtRT;
Expand Down
11 changes: 11 additions & 0 deletions llvm/tools/sycl-post-link/sycl-post-link.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,17 @@ static string_vector saveDeviceImageProperty(
PropSet.add(
llvm::util::PropertySetRegistry::SYCL_SPECIALIZATION_CONSTANTS,
TmpSpecIDMap);

// Add property with the default values of spec constants only in native
// (default) mode.
if (!ImgPSInfo.SetSpecConstAtRT) {
std::vector<char> DefaultValues;
SpecConstantsPass::collectSpecConstantDefaultValuesMetadata(
*ResultModules[I].get(), DefaultValues);
PropSet.add(llvm::util::PropertySetRegistry::
SYCL_SPEC_CONSTANTS_DEFAULT_VALUES,
"all", DefaultValues);
}
}
}
if (ImgPSInfo.EmitKernelParamInfo) {
Expand Down
2 changes: 2 additions & 0 deletions sycl/include/CL/sycl/detail/pi.h
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,8 @@ static const uint8_t PI_DEVICE_BINARY_OFFLOAD_KIND_SYCL = 4;
/// PropertySetRegistry::SYCL_SPECIALIZATION_CONSTANTS defined in
/// PropertySetIO.h
#define __SYCL_PI_PROPERTY_SET_SPEC_CONST_MAP "SYCL/specialization constants"
#define __SYCL_PI_PROPERTY_SET_SPEC_CONST_DEFAULT_VALUES_MAP \
"SYCL/specialization constants default values"
/// PropertySetRegistry::SYCL_DEVICELIB_REQ_MASK defined in PropertySetIO.h
#define __SYCL_PI_PROPERTY_SET_DEVICELIB_REQ_MASK "SYCL/devicelib req mask"
/// PropertySetRegistry::SYCL_KERNEL_PARAM_OPT_INFO defined in PropertySetIO.h
Expand Down
8 changes: 6 additions & 2 deletions sycl/test/basic_tests/SYCL-2020-spec-constants.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// RUN: %clangxx -fsycl -fsycl-device-only -c -o %t.bc %s
// RUN: sycl-post-link %t.bc -spec-const=rt -o %t-split1.txt
// RUN: cat %t-split1_0.prop | FileCheck %s
// RUN: cat %t-split1_0.prop | FileCheck %s -check-prefixes=CHECK,CHECK-RT
// RUN: sycl-post-link %t.bc -spec-const=default -o %t-split2.txt
// RUN: cat %t-split2_0.prop | FileCheck %s
// RUN: cat %t-split2_0.prop | FileCheck %s -check-prefixes=CHECK,CHECK-DEF
// RUN: llvm-spirv -o %t-split1_0.spv -spirv-max-version=1.1 -spirv-ext=+all %t-split1_0.bc
// RUN: llvm-spirv -o %t-split2_0.spv -spirv-max-version=1.1 -spirv-ext=+all %t-split2_0.bc
//
Expand Down Expand Up @@ -100,3 +100,7 @@ int main() {
// CHECK-DAG: _ZTSN2cl4sycl6detail32specialization_id_name_generatorIL_ZL9uint32_idEEE=2|
// CHECK-DAG: _ZTSN2cl4sycl6detail32specialization_id_name_generatorIL_ZL9uint64_idEEE=2|
// FIXME: check line for half constant

// CHECK-RT-NOT: [SYCL/specialization constants default values]
// CHECK-DEF: [SYCL/specialization constants default values]
// CHECK-DEF: all=2|