feature(zebin): add support for spill/private size in execution env
add fallback to previous logic based on zeinfo version Related-To: NEO-9944 Signed-off-by: Mateusz Jablonski <mateusz.jablonski@intel.com>
This commit is contained in:
parent
c0686da2d6
commit
dd7083d710
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2023 Intel Corporation
|
* Copyright (C) 2023-2024 Intel Corporation
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
@ -65,6 +65,8 @@ inline constexpr ConstStringRef roundRobin("round_robin");
|
||||||
inline constexpr ConstStringRef roundRobinStall("round_robin_stall");
|
inline constexpr ConstStringRef roundRobinStall("round_robin_stall");
|
||||||
} // namespace ThreadSchedulingMode
|
} // namespace ThreadSchedulingMode
|
||||||
inline constexpr ConstStringRef indirectStatelessCount("indirect_stateless_count");
|
inline constexpr ConstStringRef indirectStatelessCount("indirect_stateless_count");
|
||||||
|
inline constexpr ConstStringRef privateSize("private_size");
|
||||||
|
inline constexpr ConstStringRef spillSize("spill_size");
|
||||||
} // namespace ExecutionEnv
|
} // namespace ExecutionEnv
|
||||||
|
|
||||||
namespace Attributes {
|
namespace Attributes {
|
||||||
|
@ -342,6 +344,8 @@ using WorkgroupWalkOrderDimensionsT = int32_t[3];
|
||||||
using ThreadSchedulingModeT = ThreadSchedulingMode;
|
using ThreadSchedulingModeT = ThreadSchedulingMode;
|
||||||
using IndirectStatelessCountT = int32_t;
|
using IndirectStatelessCountT = int32_t;
|
||||||
using HasSampleT = bool;
|
using HasSampleT = bool;
|
||||||
|
using PrivateSizeT = int32_t;
|
||||||
|
using SpillSizeT = int32_t;
|
||||||
|
|
||||||
namespace Defaults {
|
namespace Defaults {
|
||||||
inline constexpr BarrierCountT barrierCount = 0;
|
inline constexpr BarrierCountT barrierCount = 0;
|
||||||
|
@ -371,6 +375,8 @@ inline constexpr WorkgroupWalkOrderDimensionsT workgroupWalkOrderDimensions = {0
|
||||||
inline constexpr ThreadSchedulingModeT threadSchedulingMode = ThreadSchedulingModeUnknown;
|
inline constexpr ThreadSchedulingModeT threadSchedulingMode = ThreadSchedulingModeUnknown;
|
||||||
inline constexpr IndirectStatelessCountT indirectStatelessCount = 0;
|
inline constexpr IndirectStatelessCountT indirectStatelessCount = 0;
|
||||||
inline constexpr HasSampleT hasSample = false;
|
inline constexpr HasSampleT hasSample = false;
|
||||||
|
inline constexpr PrivateSizeT privateSize = 0;
|
||||||
|
inline constexpr SpillSizeT spillSize = 0;
|
||||||
} // namespace Defaults
|
} // namespace Defaults
|
||||||
|
|
||||||
inline constexpr ConstStringRef required[] = {
|
inline constexpr ConstStringRef required[] = {
|
||||||
|
@ -404,6 +410,8 @@ struct ExecutionEnvBaseT {
|
||||||
ThreadSchedulingModeT threadSchedulingMode = Defaults::threadSchedulingMode;
|
ThreadSchedulingModeT threadSchedulingMode = Defaults::threadSchedulingMode;
|
||||||
IndirectStatelessCountT indirectStatelessCount = Defaults::indirectStatelessCount;
|
IndirectStatelessCountT indirectStatelessCount = Defaults::indirectStatelessCount;
|
||||||
HasSampleT hasSample = Defaults::hasSample;
|
HasSampleT hasSample = Defaults::hasSample;
|
||||||
|
PrivateSizeT privateSize = Defaults::privateSize;
|
||||||
|
SpillSizeT spillSize = Defaults::spillSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExperimentalPropertiesBaseT {
|
struct ExperimentalPropertiesBaseT {
|
||||||
|
|
|
@ -420,7 +420,8 @@ DecodeError decodeZeInfo(ProgramInfo &dst, ConstStringRef zeInfo, std::string &o
|
||||||
return DecodeError::invalidBinary;
|
return DecodeError::invalidBinary;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto zeInfoDecodeError = decodeZeInfoVersion(yamlParser, zeInfoSections, outErrReason, outWarning);
|
Types::Version zeInfoVersion{};
|
||||||
|
auto zeInfoDecodeError = decodeZeInfoVersion(yamlParser, zeInfoSections, outErrReason, outWarning, zeInfoVersion);
|
||||||
if (DecodeError::success != zeInfoDecodeError) {
|
if (DecodeError::success != zeInfoDecodeError) {
|
||||||
return zeInfoDecodeError;
|
return zeInfoDecodeError;
|
||||||
}
|
}
|
||||||
|
@ -435,7 +436,7 @@ DecodeError decodeZeInfo(ProgramInfo &dst, ConstStringRef zeInfo, std::string &o
|
||||||
return zeInfoDecodeError;
|
return zeInfoDecodeError;
|
||||||
}
|
}
|
||||||
|
|
||||||
zeInfoDecodeError = decodeZeInfoKernels(dst, yamlParser, zeInfoSections, outErrReason, outWarning);
|
zeInfoDecodeError = decodeZeInfoKernels(dst, yamlParser, zeInfoSections, outErrReason, outWarning, zeInfoVersion);
|
||||||
if (DecodeError::success != zeInfoDecodeError) {
|
if (DecodeError::success != zeInfoDecodeError) {
|
||||||
return zeInfoDecodeError;
|
return zeInfoDecodeError;
|
||||||
}
|
}
|
||||||
|
@ -443,18 +444,18 @@ DecodeError decodeZeInfo(ProgramInfo &dst, ConstStringRef zeInfo, std::string &o
|
||||||
return DecodeError::success;
|
return DecodeError::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodeError decodeZeInfoVersion(Yaml::YamlParser &parser, const ZeInfoSections &zeInfoSections, std::string &outErrReason, std::string &outWarning) {
|
DecodeError decodeZeInfoVersion(Yaml::YamlParser &parser, const ZeInfoSections &zeInfoSections, std::string &outErrReason, std::string &outWarning, Types::Version &srcZeInfoVersion) {
|
||||||
if (false == zeInfoSections.version.empty()) {
|
if (false == zeInfoSections.version.empty()) {
|
||||||
Types::Version zeInfoVersion;
|
auto err = readZeInfoVersionFromZeInfo(srcZeInfoVersion, parser, *zeInfoSections.version[0], outErrReason, outWarning);
|
||||||
auto err = readZeInfoVersionFromZeInfo(zeInfoVersion, parser, *zeInfoSections.version[0], outErrReason, outWarning);
|
|
||||||
if (DecodeError::success != err) {
|
if (DecodeError::success != err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
err = validateZeInfoVersion(zeInfoVersion, outErrReason, outWarning);
|
err = validateZeInfoVersion(srcZeInfoVersion, outErrReason, outWarning);
|
||||||
if (DecodeError::success != err) {
|
if (DecodeError::success != err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
srcZeInfoVersion = zeInfoDecoderVersion;
|
||||||
outWarning.append("DeviceBinaryFormat::zebin::.ze_info : No version info provided (i.e. no " + Tags::version.str() + " entry in global scope of DeviceBinaryFormat::zebin::.ze_info) - will use decoder's default : \'" + std::to_string(zeInfoDecoderVersion.major) + "." + std::to_string(zeInfoDecoderVersion.minor) + "\'\n");
|
outWarning.append("DeviceBinaryFormat::zebin::.ze_info : No version info provided (i.e. no " + Tags::version.str() + " entry in global scope of DeviceBinaryFormat::zebin::.ze_info) - will use decoder's default : \'" + std::to_string(zeInfoDecoderVersion.major) + "." + std::to_string(zeInfoDecoderVersion.minor) + "\'\n");
|
||||||
}
|
}
|
||||||
return DecodeError::success;
|
return DecodeError::success;
|
||||||
|
@ -487,11 +488,11 @@ DecodeError decodeZeInfoFunctions(ProgramInfo &dst, Yaml::YamlParser &parser, co
|
||||||
return DecodeError::success;
|
return DecodeError::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodeError decodeZeInfoKernels(ProgramInfo &dst, Yaml::YamlParser &parser, const ZeInfoSections &zeInfoSections, std::string &outErrReason, std::string &outWarning) {
|
DecodeError decodeZeInfoKernels(ProgramInfo &dst, Yaml::YamlParser &parser, const ZeInfoSections &zeInfoSections, std::string &outErrReason, std::string &outWarning, const Types::Version &srcZeInfoVersion) {
|
||||||
UNRECOVERABLE_IF(zeInfoSections.kernels.size() != 1U);
|
UNRECOVERABLE_IF(zeInfoSections.kernels.size() != 1U);
|
||||||
for (const auto &kernelNd : parser.createChildrenRange(*zeInfoSections.kernels[0])) {
|
for (const auto &kernelNd : parser.createChildrenRange(*zeInfoSections.kernels[0])) {
|
||||||
auto kernelInfo = std::make_unique<KernelInfo>();
|
auto kernelInfo = std::make_unique<KernelInfo>();
|
||||||
auto zeInfoErr = decodeZeInfoKernelEntry(kernelInfo->kernelDescriptor, parser, kernelNd, dst.grfSize, dst.minScratchSpaceSize, outErrReason, outWarning);
|
auto zeInfoErr = decodeZeInfoKernelEntry(kernelInfo->kernelDescriptor, parser, kernelNd, dst.grfSize, dst.minScratchSpaceSize, outErrReason, outWarning, srcZeInfoVersion);
|
||||||
if (DecodeError::success != zeInfoErr) {
|
if (DecodeError::success != zeInfoErr) {
|
||||||
return zeInfoErr;
|
return zeInfoErr;
|
||||||
}
|
}
|
||||||
|
@ -504,7 +505,7 @@ DecodeError decodeZeInfoKernels(ProgramInfo &dst, Yaml::YamlParser &parser, cons
|
||||||
return DecodeError::success;
|
return DecodeError::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodeError decodeZeInfoKernelEntry(NEO::KernelDescriptor &dst, NEO::Yaml::YamlParser &yamlParser, const NEO::Yaml::Node &kernelNd, uint32_t grfSize, uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning) {
|
DecodeError decodeZeInfoKernelEntry(NEO::KernelDescriptor &dst, NEO::Yaml::YamlParser &yamlParser, const NEO::Yaml::Node &kernelNd, uint32_t grfSize, uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning, const Types::Version &srcZeInfoVersion) {
|
||||||
ZeInfoKernelSections zeInfokernelSections;
|
ZeInfoKernelSections zeInfokernelSections;
|
||||||
extractZeInfoKernelSections(yamlParser, kernelNd, zeInfokernelSections, ".ze_info", outWarning);
|
extractZeInfoKernelSections(yamlParser, kernelNd, zeInfokernelSections, ".ze_info", outWarning);
|
||||||
auto extractError = validateZeInfoKernelSectionsCount(zeInfokernelSections, outErrReason, outWarning);
|
auto extractError = validateZeInfoKernelSectionsCount(zeInfokernelSections, outErrReason, outWarning);
|
||||||
|
@ -515,7 +516,7 @@ DecodeError decodeZeInfoKernelEntry(NEO::KernelDescriptor &dst, NEO::Yaml::YamlP
|
||||||
dst.kernelAttributes.binaryFormat = DeviceBinaryFormat::zebin;
|
dst.kernelAttributes.binaryFormat = DeviceBinaryFormat::zebin;
|
||||||
dst.kernelMetadata.kernelName = yamlParser.readValueNoQuotes(*zeInfokernelSections.nameNd[0]).str();
|
dst.kernelMetadata.kernelName = yamlParser.readValueNoQuotes(*zeInfokernelSections.nameNd[0]).str();
|
||||||
|
|
||||||
auto decodeError = decodeZeInfoKernelExecutionEnvironment(dst, yamlParser, zeInfokernelSections, outErrReason, outWarning);
|
auto decodeError = decodeZeInfoKernelExecutionEnvironment(dst, yamlParser, zeInfokernelSections, outErrReason, outWarning, srcZeInfoVersion);
|
||||||
if (DecodeError::success != decodeError) {
|
if (DecodeError::success != decodeError) {
|
||||||
return decodeError;
|
return decodeError;
|
||||||
}
|
}
|
||||||
|
@ -545,7 +546,7 @@ DecodeError decodeZeInfoKernelEntry(NEO::KernelDescriptor &dst, NEO::Yaml::YamlP
|
||||||
return decodeError;
|
return decodeError;
|
||||||
}
|
}
|
||||||
|
|
||||||
decodeError = decodeZeInfoKernelPerThreadMemoryBuffers(dst, yamlParser, zeInfokernelSections, minScratchSpaceSize, outErrReason, outWarning);
|
decodeError = decodeZeInfoKernelPerThreadMemoryBuffers(dst, yamlParser, zeInfokernelSections, minScratchSpaceSize, outErrReason, outWarning, srcZeInfoVersion);
|
||||||
if (DecodeError::success != decodeError) {
|
if (DecodeError::success != decodeError) {
|
||||||
return decodeError;
|
return decodeError;
|
||||||
}
|
}
|
||||||
|
@ -580,13 +581,13 @@ DecodeError decodeZeInfoKernelEntry(NEO::KernelDescriptor &dst, NEO::Yaml::YamlP
|
||||||
return DecodeError::success;
|
return DecodeError::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodeError decodeZeInfoKernelExecutionEnvironment(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, std::string &outErrReason, std::string &outWarning) {
|
DecodeError decodeZeInfoKernelExecutionEnvironment(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, std::string &outErrReason, std::string &outWarning, const Types::Version &srcZeInfoVersion) {
|
||||||
KernelExecutionEnvBaseT execEnv;
|
KernelExecutionEnvBaseT execEnv;
|
||||||
auto execEnvErr = readZeInfoExecutionEnvironment(parser, *kernelSections.executionEnvNd[0], execEnv, dst.kernelMetadata.kernelName, outErrReason, outWarning);
|
auto execEnvErr = readZeInfoExecutionEnvironment(parser, *kernelSections.executionEnvNd[0], execEnv, dst.kernelMetadata.kernelName, outErrReason, outWarning);
|
||||||
if (DecodeError::success != execEnvErr) {
|
if (DecodeError::success != execEnvErr) {
|
||||||
return execEnvErr;
|
return execEnvErr;
|
||||||
}
|
}
|
||||||
populateKernelExecutionEnvironment(dst, execEnv);
|
populateKernelExecutionEnvironment(dst, execEnv, srcZeInfoVersion);
|
||||||
return DecodeError::success;
|
return DecodeError::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,6 +648,10 @@ DecodeError readZeInfoExecutionEnvironment(const Yaml::YamlParser &parser, const
|
||||||
validExecEnv &= readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.indirectStatelessCount, context, outErrReason);
|
validExecEnv &= readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.indirectStatelessCount, context, outErrReason);
|
||||||
} else if (Tags::Kernel::ExecutionEnv::hasSample == key) {
|
} else if (Tags::Kernel::ExecutionEnv::hasSample == key) {
|
||||||
validExecEnv &= readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.hasSample, context, outErrReason);
|
validExecEnv &= readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.hasSample, context, outErrReason);
|
||||||
|
} else if (Tags::Kernel::ExecutionEnv::privateSize == key) {
|
||||||
|
validExecEnv &= readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.privateSize, context, outErrReason);
|
||||||
|
} else if (Tags::Kernel::ExecutionEnv::spillSize == key) {
|
||||||
|
validExecEnv &= readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.spillSize, context, outErrReason);
|
||||||
} else {
|
} else {
|
||||||
outWarning.append("DeviceBinaryFormat::zebin::.ze_info : Unknown entry \"" + key.str() + "\" in context of " + context.str() + "\n");
|
outWarning.append("DeviceBinaryFormat::zebin::.ze_info : Unknown entry \"" + key.str() + "\" in context of " + context.str() + "\n");
|
||||||
}
|
}
|
||||||
|
@ -664,7 +669,7 @@ DecodeError readZeInfoExecutionEnvironment(const Yaml::YamlParser &parser, const
|
||||||
return DecodeError::success;
|
return DecodeError::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void populateKernelExecutionEnvironment(KernelDescriptor &dst, const KernelExecutionEnvBaseT &execEnv) {
|
void populateKernelExecutionEnvironment(KernelDescriptor &dst, const KernelExecutionEnvBaseT &execEnv, const Types::Version &srcZeInfoVersion) {
|
||||||
dst.entryPoints.skipPerThreadDataLoad = execEnv.offsetToSkipPerThreadDataLoad;
|
dst.entryPoints.skipPerThreadDataLoad = execEnv.offsetToSkipPerThreadDataLoad;
|
||||||
dst.entryPoints.skipSetFFIDGP = execEnv.offsetToSkipSetFfidGp;
|
dst.entryPoints.skipSetFFIDGP = execEnv.offsetToSkipSetFfidGp;
|
||||||
dst.kernelAttributes.flags.passInlineData = (execEnv.inlineDataPayloadSize != 0);
|
dst.kernelAttributes.flags.passInlineData = (execEnv.inlineDataPayloadSize != 0);
|
||||||
|
@ -692,6 +697,10 @@ void populateKernelExecutionEnvironment(KernelDescriptor &dst, const KernelExecu
|
||||||
dst.kernelAttributes.workgroupWalkOrder[2] = static_cast<uint8_t>(execEnv.workgroupWalkOrderDimensions[2]);
|
dst.kernelAttributes.workgroupWalkOrder[2] = static_cast<uint8_t>(execEnv.workgroupWalkOrderDimensions[2]);
|
||||||
dst.kernelAttributes.hasIndirectStatelessAccess = (execEnv.indirectStatelessCount > 0);
|
dst.kernelAttributes.hasIndirectStatelessAccess = (execEnv.indirectStatelessCount > 0);
|
||||||
dst.kernelAttributes.numThreadsRequired = static_cast<uint32_t>(execEnv.euThreadCount);
|
dst.kernelAttributes.numThreadsRequired = static_cast<uint32_t>(execEnv.euThreadCount);
|
||||||
|
if (isScratchMemoryUsageDefinedInExecutionEnvironment(srcZeInfoVersion)) {
|
||||||
|
dst.kernelAttributes.privateScratchMemorySize = static_cast<uint32_t>(execEnv.privateSize);
|
||||||
|
dst.kernelAttributes.spillFillScratchMemorySize = static_cast<uint32_t>(execEnv.spillSize);
|
||||||
|
}
|
||||||
|
|
||||||
using ThreadSchedulingMode = Types::Kernel::ExecutionEnv::ThreadSchedulingMode;
|
using ThreadSchedulingMode = Types::Kernel::ExecutionEnv::ThreadSchedulingMode;
|
||||||
switch (execEnv.threadSchedulingMode) {
|
switch (execEnv.threadSchedulingMode) {
|
||||||
|
@ -1471,7 +1480,7 @@ DecodeError populateKernelInlineSampler(KernelDescriptor &dst, const KernelInlin
|
||||||
return DecodeError::success;
|
return DecodeError::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodeError decodeZeInfoKernelPerThreadMemoryBuffers(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, const uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning) {
|
DecodeError decodeZeInfoKernelPerThreadMemoryBuffers(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, const uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning, const Types::Version &srcZeInfoVersion) {
|
||||||
if (false == kernelSections.perThreadMemoryBuffersNd.empty()) {
|
if (false == kernelSections.perThreadMemoryBuffersNd.empty()) {
|
||||||
KernelPerThreadMemoryBuffers perThreadMemoryBuffers{};
|
KernelPerThreadMemoryBuffers perThreadMemoryBuffers{};
|
||||||
auto perThreadMemoryBuffersErr = readZeInfoPerThreadMemoryBuffers(parser, *kernelSections.perThreadMemoryBuffersNd[0], perThreadMemoryBuffers,
|
auto perThreadMemoryBuffersErr = readZeInfoPerThreadMemoryBuffers(parser, *kernelSections.perThreadMemoryBuffersNd[0], perThreadMemoryBuffers,
|
||||||
|
@ -1480,7 +1489,7 @@ DecodeError decodeZeInfoKernelPerThreadMemoryBuffers(KernelDescriptor &dst, Yaml
|
||||||
return perThreadMemoryBuffersErr;
|
return perThreadMemoryBuffersErr;
|
||||||
}
|
}
|
||||||
for (const auto &memBuff : perThreadMemoryBuffers) {
|
for (const auto &memBuff : perThreadMemoryBuffers) {
|
||||||
auto decodeErr = populateKernelPerThreadMemoryBuffer(dst, memBuff, minScratchSpaceSize, outErrReason, outWarning);
|
auto decodeErr = populateKernelPerThreadMemoryBuffer(dst, memBuff, minScratchSpaceSize, outErrReason, outWarning, srcZeInfoVersion);
|
||||||
if (DecodeError::success != decodeErr) {
|
if (DecodeError::success != decodeErr) {
|
||||||
return decodeErr;
|
return decodeErr;
|
||||||
}
|
}
|
||||||
|
@ -1514,7 +1523,7 @@ DecodeError readZeInfoPerThreadMemoryBuffers(const Yaml::YamlParser &parser, con
|
||||||
return validBuffer ? DecodeError::success : DecodeError::invalidBinary;
|
return validBuffer ? DecodeError::success : DecodeError::invalidBinary;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodeError populateKernelPerThreadMemoryBuffer(KernelDescriptor &dst, const KernelPerThreadMemoryBufferBaseT &src, const uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning) {
|
DecodeError populateKernelPerThreadMemoryBuffer(KernelDescriptor &dst, const KernelPerThreadMemoryBufferBaseT &src, const uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning, const Types::Version &srcZeInfoVersion) {
|
||||||
using namespace Types::Kernel::PerThreadMemoryBuffer;
|
using namespace Types::Kernel::PerThreadMemoryBuffer;
|
||||||
using namespace Tags::Kernel::PerThreadMemoryBuffer::AllocationType;
|
using namespace Tags::Kernel::PerThreadMemoryBuffer::AllocationType;
|
||||||
using namespace Tags::Kernel::PerThreadMemoryBuffer::MemoryUsage;
|
using namespace Tags::Kernel::PerThreadMemoryBuffer::MemoryUsage;
|
||||||
|
@ -1540,15 +1549,18 @@ DecodeError populateKernelPerThreadMemoryBuffer(KernelDescriptor &dst, const Ker
|
||||||
dst.kernelAttributes.perHwThreadPrivateMemorySize = size;
|
dst.kernelAttributes.perHwThreadPrivateMemorySize = size;
|
||||||
break;
|
break;
|
||||||
case AllocationTypeScratch:
|
case AllocationTypeScratch:
|
||||||
|
if (src.slot > 1) {
|
||||||
if (src.slot == 0) {
|
|
||||||
dst.kernelAttributes.spillFillScratchMemorySize = src.size;
|
|
||||||
} else if (src.slot == 1) {
|
|
||||||
dst.kernelAttributes.privateScratchMemorySize = src.size;
|
|
||||||
} else {
|
|
||||||
outErrReason.append("DeviceBinaryFormat::zebin : Invalid scratch buffer slot " + std::to_string(src.slot) + " in context of : " + dst.kernelMetadata.kernelName + ". Expected 0 or 1.\n");
|
outErrReason.append("DeviceBinaryFormat::zebin : Invalid scratch buffer slot " + std::to_string(src.slot) + " in context of : " + dst.kernelMetadata.kernelName + ". Expected 0 or 1.\n");
|
||||||
return DecodeError::invalidBinary;
|
return DecodeError::invalidBinary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isScratchMemoryUsageDefinedInExecutionEnvironment(srcZeInfoVersion)) {
|
||||||
|
if (src.slot == 0) {
|
||||||
|
dst.kernelAttributes.spillFillScratchMemorySize = src.size;
|
||||||
|
} else { // slot 1
|
||||||
|
dst.kernelAttributes.privateScratchMemorySize = src.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (0 != dst.kernelAttributes.perThreadScratchSize[src.slot]) {
|
if (0 != dst.kernelAttributes.perThreadScratchSize[src.slot]) {
|
||||||
outErrReason.append("DeviceBinaryFormat::zebin : Invalid duplicated scratch buffer entry " + std::to_string(src.slot) + " in context of : " + dst.kernelMetadata.kernelName + ".\n");
|
outErrReason.append("DeviceBinaryFormat::zebin : Invalid duplicated scratch buffer entry " + std::to_string(src.slot) + " in context of : " + dst.kernelMetadata.kernelName + ".\n");
|
||||||
return DecodeError::invalidBinary;
|
return DecodeError::invalidBinary;
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct KernelInfo;
|
||||||
struct ProgramInfo;
|
struct ProgramInfo;
|
||||||
|
|
||||||
namespace Zebin::ZeInfo {
|
namespace Zebin::ZeInfo {
|
||||||
inline constexpr NEO::Zebin::ZeInfo::Types::Version zeInfoDecoderVersion{1, 38};
|
inline constexpr NEO::Zebin::ZeInfo::Types::Version zeInfoDecoderVersion{1, 39};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool readEnumChecked(ConstStringRef enumString, T &outValue, ConstStringRef kernelName, std::string &outErrReason);
|
bool readEnumChecked(ConstStringRef enumString, T &outValue, ConstStringRef kernelName, std::string &outErrReason);
|
||||||
|
@ -63,7 +63,7 @@ DecodeError validateZeInfoVersion(const Types::Version &receivedZeInfoVersion, s
|
||||||
|
|
||||||
DecodeError populateExternalFunctionsMetadata(NEO::ProgramInfo &dst, NEO::Yaml::YamlParser &yamlParser, const NEO::Yaml::Node &functionNd, std::string &outErrReason, std::string &outWarning);
|
DecodeError populateExternalFunctionsMetadata(NEO::ProgramInfo &dst, NEO::Yaml::YamlParser &yamlParser, const NEO::Yaml::Node &functionNd, std::string &outErrReason, std::string &outWarning);
|
||||||
|
|
||||||
DecodeError decodeZeInfoVersion(Yaml::YamlParser &parser, const ZeInfoSections &zeInfoSections, std::string &outErrReason, std::string &outWarning);
|
DecodeError decodeZeInfoVersion(Yaml::YamlParser &parser, const ZeInfoSections &zeInfoSections, std::string &outErrReason, std::string &outWarning, Types::Version &srcZeInfoVersion);
|
||||||
DecodeError readZeInfoVersionFromZeInfo(Types::Version &dst,
|
DecodeError readZeInfoVersionFromZeInfo(Types::Version &dst,
|
||||||
NEO::Yaml::YamlParser &yamlParser, const NEO::Yaml::Node &versionNd, std::string &outErrReason, std::string &outWarning);
|
NEO::Yaml::YamlParser &yamlParser, const NEO::Yaml::Node &versionNd, std::string &outErrReason, std::string &outWarning);
|
||||||
|
|
||||||
|
@ -71,13 +71,13 @@ DecodeError decodeZeInfoGlobalHostAccessTable(ProgramInfo &dst, Yaml::YamlParser
|
||||||
|
|
||||||
DecodeError decodeZeInfoFunctions(ProgramInfo &dst, Yaml::YamlParser &parser, const ZeInfoSections &zeInfoSections, std::string &outErrReason, std::string &outWarning);
|
DecodeError decodeZeInfoFunctions(ProgramInfo &dst, Yaml::YamlParser &parser, const ZeInfoSections &zeInfoSections, std::string &outErrReason, std::string &outWarning);
|
||||||
|
|
||||||
DecodeError decodeZeInfoKernels(ProgramInfo &dst, Yaml::YamlParser &parser, const ZeInfoSections &zeInfoSections, std::string &outErrReason, std::string &outWarning);
|
DecodeError decodeZeInfoKernels(ProgramInfo &dst, Yaml::YamlParser &parser, const ZeInfoSections &zeInfoSections, std::string &outErrReason, std::string &outWarning, const Types::Version &srcZeInfoVersion);
|
||||||
DecodeError decodeZeInfoKernelEntry(KernelDescriptor &dst, Yaml::YamlParser &yamlParser, const Yaml::Node &kernelNd, uint32_t grfSize, uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning);
|
DecodeError decodeZeInfoKernelEntry(KernelDescriptor &dst, Yaml::YamlParser &yamlParser, const Yaml::Node &kernelNd, uint32_t grfSize, uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning, const Types::Version &srcZeInfoVersion);
|
||||||
|
|
||||||
using KernelExecutionEnvBaseT = Types::Kernel::ExecutionEnv::ExecutionEnvBaseT;
|
using KernelExecutionEnvBaseT = Types::Kernel::ExecutionEnv::ExecutionEnvBaseT;
|
||||||
DecodeError decodeZeInfoKernelExecutionEnvironment(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, std::string &outErrReason, std::string &outWarning);
|
DecodeError decodeZeInfoKernelExecutionEnvironment(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, std::string &outErrReason, std::string &outWarning, const Types::Version &srcZeInfoVersion);
|
||||||
DecodeError readZeInfoExecutionEnvironment(const Yaml::YamlParser &parser, const Yaml::Node &node, KernelExecutionEnvBaseT &outExecEnv, ConstStringRef context, std::string &outErrReason, std::string &outWarning);
|
DecodeError readZeInfoExecutionEnvironment(const Yaml::YamlParser &parser, const Yaml::Node &node, KernelExecutionEnvBaseT &outExecEnv, ConstStringRef context, std::string &outErrReason, std::string &outWarning);
|
||||||
void populateKernelExecutionEnvironment(KernelDescriptor &dst, const KernelExecutionEnvBaseT &execEnv);
|
void populateKernelExecutionEnvironment(KernelDescriptor &dst, const KernelExecutionEnvBaseT &execEnv, const Types::Version &srcZeInfoVersion);
|
||||||
|
|
||||||
using KernelAttributesBaseT = Types::Kernel::Attributes::AttributesBaseT;
|
using KernelAttributesBaseT = Types::Kernel::Attributes::AttributesBaseT;
|
||||||
DecodeError decodeZeInfoKernelUserAttributes(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, std::string &outErrReason, std::string &outWarning);
|
DecodeError decodeZeInfoKernelUserAttributes(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, std::string &outErrReason, std::string &outWarning);
|
||||||
|
@ -109,9 +109,9 @@ DecodeError populateKernelInlineSampler(KernelDescriptor &dst, const KernelInlin
|
||||||
|
|
||||||
using KernelPerThreadMemoryBufferBaseT = Types::Kernel::PerThreadMemoryBuffer::PerThreadMemoryBufferBaseT;
|
using KernelPerThreadMemoryBufferBaseT = Types::Kernel::PerThreadMemoryBuffer::PerThreadMemoryBufferBaseT;
|
||||||
using KernelPerThreadMemoryBuffers = StackVec<KernelPerThreadMemoryBufferBaseT, 8>;
|
using KernelPerThreadMemoryBuffers = StackVec<KernelPerThreadMemoryBufferBaseT, 8>;
|
||||||
DecodeError decodeZeInfoKernelPerThreadMemoryBuffers(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, const uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning);
|
DecodeError decodeZeInfoKernelPerThreadMemoryBuffers(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, const uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning, const Types::Version &srcZeInfoVersion);
|
||||||
DecodeError readZeInfoPerThreadMemoryBuffers(const Yaml::YamlParser &parser, const Yaml::Node &node, KernelPerThreadMemoryBuffers &outPerThreadMemoryBuffers, ConstStringRef context, std::string &outErrReason, std::string &outWarning);
|
DecodeError readZeInfoPerThreadMemoryBuffers(const Yaml::YamlParser &parser, const Yaml::Node &node, KernelPerThreadMemoryBuffers &outPerThreadMemoryBuffers, ConstStringRef context, std::string &outErrReason, std::string &outWarning);
|
||||||
DecodeError populateKernelPerThreadMemoryBuffer(KernelDescriptor &dst, const KernelPerThreadMemoryBufferBaseT &src, const uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning);
|
DecodeError populateKernelPerThreadMemoryBuffer(KernelDescriptor &dst, const KernelPerThreadMemoryBufferBaseT &src, const uint32_t minScratchSpaceSize, std::string &outErrReason, std::string &outWarning, const Types::Version &srcZeInfoVersion);
|
||||||
|
|
||||||
using KernelExperimentalPropertiesBaseT = Types::Kernel::ExecutionEnv::ExperimentalPropertiesBaseT;
|
using KernelExperimentalPropertiesBaseT = Types::Kernel::ExecutionEnv::ExperimentalPropertiesBaseT;
|
||||||
DecodeError decodeZeInfoKernelExperimentalProperties(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, std::string &outErrReason, std::string &outWarning);
|
DecodeError decodeZeInfoKernelExperimentalProperties(KernelDescriptor &dst, Yaml::YamlParser &parser, const ZeInfoKernelSections &kernelSections, std::string &outErrReason, std::string &outWarning);
|
||||||
|
@ -130,6 +130,13 @@ void populateKernelMiscInfo(KernelDescriptor &dst, KernelMiscArgInfos &kernelMis
|
||||||
|
|
||||||
void generateSSHWithBindingTable(KernelDescriptor &dst);
|
void generateSSHWithBindingTable(KernelDescriptor &dst);
|
||||||
void generateDSH(KernelDescriptor &dst);
|
void generateDSH(KernelDescriptor &dst);
|
||||||
|
|
||||||
|
inline bool isAtLeastZeInfoVersion(const Types::Version &srcVersion, const Types::Version &expectedVersion) {
|
||||||
|
return srcVersion.minor >= expectedVersion.minor;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isScratchMemoryUsageDefinedInExecutionEnvironment(const Types::Version &srcVersion) { return isAtLeastZeInfoVersion(srcVersion, {1, 39}); }
|
||||||
|
|
||||||
} // namespace Zebin::ZeInfo
|
} // namespace Zebin::ZeInfo
|
||||||
|
|
||||||
} // namespace NEO
|
} // namespace NEO
|
||||||
|
|
|
@ -38,6 +38,10 @@ class DecodeZeInfoKernelEntryFixture {
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodeError decodeZeInfoKernelEntry(ConstStringRef zeinfo) {
|
DecodeError decodeZeInfoKernelEntry(ConstStringRef zeinfo) {
|
||||||
|
return decodeZeInfoKernelEntryForSpecificVersion(zeinfo, NEO::Zebin::ZeInfo::zeInfoDecoderVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
DecodeError decodeZeInfoKernelEntryForSpecificVersion(ConstStringRef zeinfo, const NEO::Zebin::ZeInfo::Types::Version &zeInfoVersion) {
|
||||||
kernelDescriptor = std::make_unique<KernelDescriptor>();
|
kernelDescriptor = std::make_unique<KernelDescriptor>();
|
||||||
yamlParser = std::make_unique<NEO::Yaml::YamlParser>();
|
yamlParser = std::make_unique<NEO::Yaml::YamlParser>();
|
||||||
errors.clear();
|
errors.clear();
|
||||||
|
@ -50,7 +54,7 @@ class DecodeZeInfoKernelEntryFixture {
|
||||||
|
|
||||||
auto &kernelNode = *yamlParser->createChildrenRange(*yamlParser->findNodeWithKeyDfs("kernels")).begin();
|
auto &kernelNode = *yamlParser->createChildrenRange(*yamlParser->findNodeWithKeyDfs("kernels")).begin();
|
||||||
return NEO::Zebin::ZeInfo::decodeZeInfoKernelEntry(*kernelDescriptor, *yamlParser, kernelNode,
|
return NEO::Zebin::ZeInfo::decodeZeInfoKernelEntry(*kernelDescriptor, *yamlParser, kernelNode,
|
||||||
grfSize, minScratchSpaceSize, errors, warnings);
|
grfSize, minScratchSpaceSize, errors, warnings, zeInfoVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -66,6 +70,13 @@ class DecodeZeInfoKernelEntryFixture {
|
||||||
};
|
};
|
||||||
using namespace NEO::Zebin;
|
using namespace NEO::Zebin;
|
||||||
|
|
||||||
|
TEST(ZeInfoVersionSupportTest, whenCheckingSupportedZeInfoVersionThenProperValueIsReturned) {
|
||||||
|
ZeInfo::Types::Version srcZeInfoVersion{3, 14};
|
||||||
|
EXPECT_TRUE(ZeInfo::isAtLeastZeInfoVersion(srcZeInfoVersion, {3, 14}));
|
||||||
|
EXPECT_FALSE(ZeInfo::isAtLeastZeInfoVersion(srcZeInfoVersion, {3, 15}));
|
||||||
|
EXPECT_TRUE(ZeInfo::isAtLeastZeInfoVersion(srcZeInfoVersion, {3, 13}));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ZebinValidateTargetTest, givenTargetDeviceCreatedUsingHelperFunctionWhenValidatingAgainstAdjustedHwInfoForIgcThenSuccessIsReturned) {
|
TEST(ZebinValidateTargetTest, givenTargetDeviceCreatedUsingHelperFunctionWhenValidatingAgainstAdjustedHwInfoForIgcThenSuccessIsReturned) {
|
||||||
MockExecutionEnvironment executionEnvironment;
|
MockExecutionEnvironment executionEnvironment;
|
||||||
auto &rootDeviceEnvironment = *executionEnvironment.rootDeviceEnvironments[0];
|
auto &rootDeviceEnvironment = *executionEnvironment.rootDeviceEnvironments[0];
|
||||||
|
@ -3588,6 +3599,8 @@ TEST_F(decodeZeInfoKernelEntryTest, GivenMinimalExecutionEnvThenPopulateKernelDe
|
||||||
EXPECT_EQ(kernelDescriptor.kernelAttributes.workgroupWalkOrder[0], static_cast<uint8_t>(Defaults::workgroupWalkOrderDimensions[0]));
|
EXPECT_EQ(kernelDescriptor.kernelAttributes.workgroupWalkOrder[0], static_cast<uint8_t>(Defaults::workgroupWalkOrderDimensions[0]));
|
||||||
EXPECT_EQ(kernelDescriptor.kernelAttributes.workgroupWalkOrder[1], static_cast<uint8_t>(Defaults::workgroupWalkOrderDimensions[1]));
|
EXPECT_EQ(kernelDescriptor.kernelAttributes.workgroupWalkOrder[1], static_cast<uint8_t>(Defaults::workgroupWalkOrderDimensions[1]));
|
||||||
EXPECT_EQ(kernelDescriptor.kernelAttributes.workgroupWalkOrder[2], static_cast<uint8_t>(Defaults::workgroupWalkOrderDimensions[2]));
|
EXPECT_EQ(kernelDescriptor.kernelAttributes.workgroupWalkOrder[2], static_cast<uint8_t>(Defaults::workgroupWalkOrderDimensions[2]));
|
||||||
|
EXPECT_EQ(kernelDescriptor.kernelAttributes.privateScratchMemorySize, static_cast<uint32_t>(Defaults::privateSize));
|
||||||
|
EXPECT_EQ(kernelDescriptor.kernelAttributes.spillFillScratchMemorySize, static_cast<uint32_t>(Defaults::spillSize));
|
||||||
EXPECT_EQ(kernelDescriptor.kernelMetadata.requiredSubGroupSize, static_cast<uint8_t>(Defaults::requiredSubGroupSize));
|
EXPECT_EQ(kernelDescriptor.kernelMetadata.requiredSubGroupSize, static_cast<uint8_t>(Defaults::requiredSubGroupSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4039,6 +4052,7 @@ kernels:
|
||||||
- name : some_kernel
|
- name : some_kernel
|
||||||
execution_env:
|
execution_env:
|
||||||
simd_size: 8
|
simd_size: 8
|
||||||
|
spill_size: 2048
|
||||||
per_thread_memory_buffers:
|
per_thread_memory_buffers:
|
||||||
- type: scratch
|
- type: scratch
|
||||||
usage: spill_fill_space
|
usage: spill_fill_space
|
||||||
|
@ -4060,6 +4074,7 @@ kernels:
|
||||||
- name : some_kernel
|
- name : some_kernel
|
||||||
execution_env:
|
execution_env:
|
||||||
simd_size: 8
|
simd_size: 8
|
||||||
|
private_size: 2048
|
||||||
per_thread_memory_buffers:
|
per_thread_memory_buffers:
|
||||||
- type: scratch
|
- type: scratch
|
||||||
usage: private_space
|
usage: private_space
|
||||||
|
@ -4076,23 +4091,58 @@ kernels:
|
||||||
EXPECT_EQ(2048U, kernelDescriptor->kernelAttributes.privateScratchMemorySize);
|
EXPECT_EQ(2048U, kernelDescriptor->kernelAttributes.privateScratchMemorySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(decodeZeInfoKernelEntryTest, GivenPerThreadMemoryBufferOfSizeSmallerThanMinimalWhenTypeIsScratchThenSetsProperFieldsInDescriptor) {
|
TEST_F(decodeZeInfoKernelEntryTest, GivenPerThreadMemoryForSpillAndPrivateDefinedInSeparateFieldsThenProperFieldsInDescriptorAreSet) {
|
||||||
ConstStringRef zeinfo = R"===(
|
ConstStringRef zeinfo = R"===(
|
||||||
kernels:
|
kernels:
|
||||||
- name : some_kernel
|
- name : some_kernel
|
||||||
execution_env:
|
execution_env:
|
||||||
simd_size: 8
|
simd_size: 8
|
||||||
|
private_size: 256
|
||||||
|
spill_size: 512
|
||||||
per_thread_memory_buffers:
|
per_thread_memory_buffers:
|
||||||
- type: scratch
|
- type: scratch
|
||||||
usage: private_space
|
usage: single_space
|
||||||
size: 512
|
size: 1024
|
||||||
|
- type: scratch
|
||||||
|
usage: single_space
|
||||||
|
size: 2048
|
||||||
|
slot: 1
|
||||||
)===";
|
)===";
|
||||||
auto err = decodeZeInfoKernelEntry(zeinfo);
|
auto err = decodeZeInfoKernelEntry(zeinfo);
|
||||||
EXPECT_EQ(NEO::DecodeError::success, err);
|
EXPECT_EQ(NEO::DecodeError::success, err);
|
||||||
EXPECT_TRUE(errors.empty()) << errors;
|
EXPECT_TRUE(errors.empty()) << errors;
|
||||||
EXPECT_TRUE(warnings.empty()) << warnings;
|
EXPECT_TRUE(warnings.empty()) << warnings;
|
||||||
EXPECT_EQ(1024U, kernelDescriptor->kernelAttributes.perThreadScratchSize[0]);
|
EXPECT_EQ(1024U, kernelDescriptor->kernelAttributes.perThreadScratchSize[0]);
|
||||||
EXPECT_EQ(0U, kernelDescriptor->kernelAttributes.perThreadScratchSize[1]);
|
EXPECT_EQ(2048U, kernelDescriptor->kernelAttributes.perThreadScratchSize[1]);
|
||||||
|
EXPECT_EQ(256U, kernelDescriptor->kernelAttributes.privateScratchMemorySize);
|
||||||
|
EXPECT_EQ(512U, kernelDescriptor->kernelAttributes.spillFillScratchMemorySize);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(decodeZeInfoKernelEntryTest, GivenPerThreadMemoryForSpillAndPrivateDefinedInOlderZeInfoThenFallbackToLegacySlotMeaning) {
|
||||||
|
ConstStringRef zeinfo = R"===(
|
||||||
|
kernels:
|
||||||
|
- name : some_kernel
|
||||||
|
execution_env:
|
||||||
|
simd_size: 8
|
||||||
|
private_size: 256
|
||||||
|
spill_size: 512
|
||||||
|
per_thread_memory_buffers:
|
||||||
|
- type: scratch
|
||||||
|
usage: single_space
|
||||||
|
size: 1024
|
||||||
|
- type: scratch
|
||||||
|
usage: single_space
|
||||||
|
size: 2048
|
||||||
|
slot: 1
|
||||||
|
)===";
|
||||||
|
auto err = decodeZeInfoKernelEntryForSpecificVersion(zeinfo, {1, 38});
|
||||||
|
EXPECT_EQ(NEO::DecodeError::success, err);
|
||||||
|
EXPECT_TRUE(errors.empty()) << errors;
|
||||||
|
EXPECT_TRUE(warnings.empty()) << warnings;
|
||||||
|
EXPECT_EQ(1024U, kernelDescriptor->kernelAttributes.perThreadScratchSize[0]);
|
||||||
|
EXPECT_EQ(2048U, kernelDescriptor->kernelAttributes.perThreadScratchSize[1]);
|
||||||
|
EXPECT_EQ(2048U, kernelDescriptor->kernelAttributes.privateScratchMemorySize);
|
||||||
|
EXPECT_EQ(1024U, kernelDescriptor->kernelAttributes.spillFillScratchMemorySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(decodeZeInfoKernelEntryTest, GivenPerThreadMemoryBufferOfSizeBiggerThanMinimalWhenTypeIsScratchThenSetsProperFieldsInDescriptor) {
|
TEST_F(decodeZeInfoKernelEntryTest, GivenPerThreadMemoryBufferOfSizeBiggerThanMinimalWhenTypeIsScratchThenSetsProperFieldsInDescriptor) {
|
||||||
|
|
Loading…
Reference in New Issue