Zebin support

Change-Id: I1e426ee2c5174fd0a4c51c1644cda467c2b88881
This commit is contained in:
Jaroslaw Chodor
2020-07-30 13:18:54 +02:00
parent 855c474aaf
commit 321f649854
27 changed files with 4763 additions and 18 deletions

View File

@@ -14,6 +14,7 @@ set(NEO_DEVICE_BINARY_FORMAT
${CMAKE_CURRENT_SOURCE_DIR}/device_binary_format_ar.cpp
${CMAKE_CURRENT_SOURCE_DIR}/device_binary_format_ocl_elf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/device_binary_format_patchtokens.cpp
${CMAKE_CURRENT_SOURCE_DIR}/device_binary_format_zebin.cpp
${CMAKE_CURRENT_SOURCE_DIR}/device_binary_formats.cpp
${CMAKE_CURRENT_SOURCE_DIR}/device_binary_formats.h
${CMAKE_CURRENT_SOURCE_DIR}/elf/elf.h
@@ -22,12 +23,15 @@ set(NEO_DEVICE_BINARY_FORMAT
${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_encoder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_encoder.h
${CMAKE_CURRENT_SOURCE_DIR}/elf/ocl_elf.h
${CMAKE_CURRENT_SOURCE_DIR}/elf/zebin_elf.h
${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_decoder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_decoder.h
${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_dumper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_dumper.h
${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_validator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_validator.h
${CMAKE_CURRENT_SOURCE_DIR}/zebin_decoder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/zebin_decoder.h
${CMAKE_CURRENT_SOURCE_DIR}/yaml/yaml_parser.cpp
${CMAKE_CURRENT_SOURCE_DIR}/yaml/yaml_parser.h
)

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/compiler_interface/intermediate_representations.h"
#include "shared/source/device_binary_format/device_binary_formats.h"
#include "shared/source/device_binary_format/elf/elf_decoder.h"
#include "shared/source/device_binary_format/elf/elf_encoder.h"
#include "shared/source/device_binary_format/elf/zebin_elf.h"
#include "shared/source/program/program_info.h"
#include <tuple>
namespace NEO {
template <>
bool isDeviceBinaryFormat<NEO::DeviceBinaryFormat::Zebin>(const ArrayRef<const uint8_t> binary) {
auto header = Elf::decodeElfFileHeader<Elf::EI_CLASS_64>(binary);
if (nullptr == header) {
return false;
}
return header->type == NEO::Elf::ET_ZEBIN_EXE;
}
template <>
SingleDeviceBinary unpackSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(const ArrayRef<const uint8_t> archive, const ConstStringRef requestedProductAbbreviation, const TargetDevice &requestedTargetDevice,
std::string &outErrReason, std::string &outWarning) {
auto elf = Elf::decodeElf<Elf::EI_CLASS_64>(archive, outErrReason, outWarning);
if (nullptr == elf.elfFileHeader) {
return {};
}
switch (elf.elfFileHeader->type) {
default:
outErrReason = "Unhandled elf type";
return {};
case NEO::Elf::ET_ZEBIN_EXE:
break;
}
const auto &flags = reinterpret_cast<const NEO::Elf::ZebinTargetFlags &>(elf.elfFileHeader->flags);
bool validForTarget = flags.machineEntryUsesGfxCoreInsteadOfProductFamily
? (requestedTargetDevice.coreFamily == static_cast<GFXCORE_FAMILY>(elf.elfFileHeader->machine))
: (requestedTargetDevice.productFamily == static_cast<PRODUCT_FAMILY>(elf.elfFileHeader->machine));
validForTarget &= (requestedTargetDevice.maxPointerSizeInBytes == 8U);
validForTarget &= (0 == flags.validateRevisionId) | ((requestedTargetDevice.stepping >= flags.minHwRevisionId) & (requestedTargetDevice.stepping <= flags.maxHwRevisionId));
if (false == validForTarget) {
outErrReason = "Unhandled target device";
return {};
}
SingleDeviceBinary ret;
ret.deviceBinary = archive;
ret.format = NEO::DeviceBinaryFormat::Zebin;
ret.targetDevice = requestedTargetDevice;
return ret;
}
} // namespace NEO

View File

@@ -10,6 +10,9 @@
namespace NEO {
std::vector<uint8_t> packDeviceBinary(const SingleDeviceBinary binary, std::string &outErrReason, std::string &outWarning) {
if (NEO::isAnyPackedDeviceBinaryFormat(binary.deviceBinary)) {
return std::vector<uint8_t>(binary.deviceBinary.begin(), binary.deviceBinary.end());
}
return packDeviceBinary<DeviceBinaryFormat::OclElf>(binary, outErrReason, outWarning);
}

View File

@@ -25,7 +25,8 @@ enum class DeviceBinaryFormat : uint8_t {
OclLibrary,
OclCompiledObject,
Patchtokens,
Archive
Archive,
Zebin
};
enum class DecodeError : uint8_t {
@@ -54,6 +55,7 @@ inline const char *asString(DecodeError err) {
struct TargetDevice {
GFXCORE_FAMILY coreFamily = IGFX_UNKNOWN_CORE;
PRODUCT_FAMILY productFamily = IGFX_UNKNOWN;
uint32_t stepping = 0U;
uint32_t maxPointerSizeInBytes = 4U;
};
@@ -76,6 +78,8 @@ template <>
bool isDeviceBinaryFormat<DeviceBinaryFormat::Patchtokens>(const ArrayRef<const uint8_t>);
template <>
bool isDeviceBinaryFormat<DeviceBinaryFormat::Archive>(const ArrayRef<const uint8_t>);
template <>
bool isDeviceBinaryFormat<DeviceBinaryFormat::Zebin>(const ArrayRef<const uint8_t>);
inline bool isAnyDeviceBinaryFormat(const ArrayRef<const uint8_t> binary) {
if (isDeviceBinaryFormat<DeviceBinaryFormat::OclElf>(binary)) {
@@ -87,6 +91,9 @@ inline bool isAnyDeviceBinaryFormat(const ArrayRef<const uint8_t> binary) {
if (isDeviceBinaryFormat<DeviceBinaryFormat::Archive>(binary)) {
return true;
}
if (isDeviceBinaryFormat<DeviceBinaryFormat::Zebin>(binary)) {
return true;
}
return false;
}
@@ -100,6 +107,8 @@ template <>
SingleDeviceBinary unpackSingleDeviceBinary<DeviceBinaryFormat::Patchtokens>(const ArrayRef<const uint8_t>, const ConstStringRef, const TargetDevice &, std::string &, std::string &);
template <>
SingleDeviceBinary unpackSingleDeviceBinary<DeviceBinaryFormat::Archive>(const ArrayRef<const uint8_t>, const ConstStringRef, const TargetDevice &, std::string &, std::string &);
template <>
SingleDeviceBinary unpackSingleDeviceBinary<DeviceBinaryFormat::Zebin>(const ArrayRef<const uint8_t>, const ConstStringRef, const TargetDevice &, std::string &, std::string &);
inline SingleDeviceBinary unpackSingleDeviceBinary(const ArrayRef<const uint8_t> archive, const ConstStringRef requestedProductAbbreviation, const TargetDevice &requestedTargetDevice,
std::string &outErrReason, std::string &outWarning) {
@@ -111,6 +120,8 @@ inline SingleDeviceBinary unpackSingleDeviceBinary(const ArrayRef<const uint8_t>
return unpackSingleDeviceBinary<DeviceBinaryFormat::Patchtokens>(archive, requestedProductAbbreviation, requestedTargetDevice, outErrReason, outWarning);
} else if (isDeviceBinaryFormat<DeviceBinaryFormat::Archive>(archive)) {
return unpackSingleDeviceBinary<DeviceBinaryFormat::Archive>(archive, requestedProductAbbreviation, requestedTargetDevice, outErrReason, outWarning);
} else if (isDeviceBinaryFormat<DeviceBinaryFormat::Zebin>(archive)) {
return unpackSingleDeviceBinary<DeviceBinaryFormat::Zebin>(archive, requestedProductAbbreviation, requestedTargetDevice, outErrReason, outWarning);
} else {
outErrReason = "Unknown format";
}
@@ -132,11 +143,14 @@ inline bool isAnyPackedDeviceBinaryFormat(const ArrayRef<const uint8_t> binary)
if (isDeviceBinaryFormat<DeviceBinaryFormat::Archive>(binary)) {
return true;
}
if (isDeviceBinaryFormat<DeviceBinaryFormat::Zebin>(binary)) {
return true;
}
return false;
}
inline bool isAnySingleDeviceBinaryFormat(const ArrayRef<const uint8_t> binary) {
return (false == isAnyPackedDeviceBinaryFormat(binary)) && isAnyDeviceBinaryFormat(binary);
return ((false == isAnyPackedDeviceBinaryFormat(binary)) && isAnyDeviceBinaryFormat(binary)) || isDeviceBinaryFormat<DeviceBinaryFormat::Zebin>(binary);
}
template <DeviceBinaryFormat Format>
@@ -148,6 +162,8 @@ template <>
DecodeError decodeSingleDeviceBinary<DeviceBinaryFormat::Patchtokens>(ProgramInfo &, const SingleDeviceBinary &, std::string &, std::string &);
template <>
DecodeError decodeSingleDeviceBinary<DeviceBinaryFormat::Archive>(ProgramInfo &, const SingleDeviceBinary &, std::string &, std::string &);
template <>
DecodeError decodeSingleDeviceBinary<DeviceBinaryFormat::Zebin>(ProgramInfo &, const SingleDeviceBinary &, std::string &, std::string &);
inline std::pair<DecodeError, DeviceBinaryFormat> decodeSingleDeviceBinary(ProgramInfo &dst, const SingleDeviceBinary &src, std::string &outErrReason, std::string &outWarning) {
std::pair<DecodeError, DeviceBinaryFormat> ret;
@@ -162,6 +178,9 @@ inline std::pair<DecodeError, DeviceBinaryFormat> decodeSingleDeviceBinary(Progr
} else if (isDeviceBinaryFormat<DeviceBinaryFormat::Archive>(src.deviceBinary)) {
ret.second = DeviceBinaryFormat::Archive;
ret.first = decodeSingleDeviceBinary<DeviceBinaryFormat::Archive>(dst, src, outErrReason, outWarning);
} else if (isDeviceBinaryFormat<DeviceBinaryFormat::Zebin>(src.deviceBinary)) {
ret.second = DeviceBinaryFormat::Zebin;
ret.first = decodeSingleDeviceBinary<DeviceBinaryFormat::Zebin>(dst, src, outErrReason, outWarning);
} else {
outErrReason = "Unknown format";
}

View File

@@ -303,6 +303,55 @@ struct ElfFileHeader {
static_assert(sizeof(ElfFileHeader<EI_CLASS_32>) == 0x34, "");
static_assert(sizeof(ElfFileHeader<EI_CLASS_64>) == 0x40, "");
template <int NumBits>
struct ElfSymbolEntryTypes;
template <>
struct ElfSymbolEntryTypes<EI_CLASS_32> {
using Name = uint32_t;
using Info = uint8_t;
using Other = uint8_t;
using Shndx = uint16_t;
using Value = uint32_t;
using Size = uint32_t;
};
template <>
struct ElfSymbolEntryTypes<EI_CLASS_64> {
using Name = uint32_t;
using Info = uint8_t;
using Other = uint8_t;
using Shndx = uint16_t;
using Value = uint64_t;
using Size = uint64_t;
};
template <ELF_IDENTIFIER_CLASS NumBits>
struct ElfSymbolEntry;
template <>
struct ElfSymbolEntry<EI_CLASS_32> {
ElfSymbolEntryTypes<EI_CLASS_32>::Name name;
ElfSymbolEntryTypes<EI_CLASS_32>::Value value;
ElfSymbolEntryTypes<EI_CLASS_32>::Size size;
ElfSymbolEntryTypes<EI_CLASS_32>::Info info;
ElfSymbolEntryTypes<EI_CLASS_32>::Other other;
ElfSymbolEntryTypes<EI_CLASS_32>::Shndx shndx;
};
template <>
struct ElfSymbolEntry<EI_CLASS_64> {
ElfSymbolEntryTypes<EI_CLASS_64>::Name name;
ElfSymbolEntryTypes<EI_CLASS_64>::Info info;
ElfSymbolEntryTypes<EI_CLASS_64>::Other other;
ElfSymbolEntryTypes<EI_CLASS_64>::Shndx shndx;
ElfSymbolEntryTypes<EI_CLASS_64>::Value value;
ElfSymbolEntryTypes<EI_CLASS_64>::Size size;
};
static_assert(sizeof(ElfSymbolEntry<EI_CLASS_32>) == 0x10, "");
static_assert(sizeof(ElfSymbolEntry<EI_CLASS_64>) == 0x18, "");
namespace SpecialSectionNames {
static constexpr ConstStringRef bss = ".bss"; // uninitialized memory
static constexpr ConstStringRef comment = ".comment"; // version control information

View File

@@ -0,0 +1,336 @@
/*
* Copyright (C) 2019-2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
// Abstract: Defines the types used for ELF headers/sections.
#pragma once
#include "shared/source/device_binary_format/elf/elf.h"
#include "shared/source/utilities/const_stringref.h"
#include <inttypes.h>
#include <stddef.h>
namespace NEO {
namespace Elf {
enum ELF_TYPE_ZEBIN : uint16_t {
ET_ZEBIN_REL = 0xff11, // A relocatable ZE binary file
ET_ZEBIN_EXE = 0xff12, // An executable ZE binary file
ET_ZEBIN_DYN = 0xff13, // A shared object ZE binary file
};
enum SHT_ZEBIN : uint32_t {
SHT_ZEBIN_SPIRV = 0xff000009, // .spv.kernel section, value the same as SHT_OPENCL_SPIRV
SHT_ZEBIN_ZEINFO = 0xff000011 // .ze_info section
};
namespace SectionsNamesZebin {
static constexpr ConstStringRef textPrefix = ".text.";
static constexpr ConstStringRef dataConst = ".data.const";
static constexpr ConstStringRef dataGlobal = ".data.global";
static constexpr ConstStringRef symtab = ".symtab";
static constexpr ConstStringRef relTablePrefix = ".rel.";
static constexpr ConstStringRef spv = ".spv";
static constexpr ConstStringRef debugInfo = ".debug_info";
static constexpr ConstStringRef zeInfo = ".ze_info";
} // namespace SectionsNamesZebin
struct ZebinTargetFlags {
union {
struct {
// bit[7:0]: dedicated for specific generator (meaning based on generatorId)
uint8_t generatorSpecificFlags : 8;
// bit[12:8]: values [0-31], min compatbile device revision Id (stepping)
uint8_t minHwRevisionId : 5;
// bit[13:13]:
// 0 - full validation during decoding (safer decoding)
// 1 - no validation (faster decoding - recommended for known generators)
bool validateRevisionId : 1;
// bit[14:14]:
// 0 - ignore minHwRevisionId and maxHwRevisionId
// 1 - underlying device must match specified revisionId info
bool disableExtendedValidation : 1;
// bit[15:15]:
// 0 - elfFileHeader::machine is PRODUCT_FAMILY
// 1 - elfFileHeader::machine is GFXCORE_FAMILY
bool machineEntryUsesGfxCoreInsteadOfProductFamily : 1;
// bit[20:16]: max compatbile device revision Id (stepping)
uint8_t maxHwRevisionId : 5;
// bit[23:21]: generator of this device binary
// 0 - Unregistered
// 1 - IGC
uint8_t generatorId : 3;
// bit[31:24]: MBZ, reserved for future use
uint8_t reserved : 8;
};
uint32_t packed = 0U;
};
};
static_assert(sizeof(ZebinTargetFlags) == sizeof(uint32_t), "");
namespace ZebinKernelMetadata {
namespace Tags {
static constexpr ConstStringRef kernels("kernels");
namespace Kernel {
static constexpr ConstStringRef name("name");
static constexpr ConstStringRef executionEnv("execution_env");
static constexpr ConstStringRef payloadArguments("payload_arguments");
static constexpr ConstStringRef bindingTableIndices("binding_table_indices");
static constexpr ConstStringRef perThreadPayloadArguments("per_thread_payload_arguments");
namespace ExecutionEnv {
static constexpr ConstStringRef actualKernelStartOffset("actual_kernel_start_offset");
static constexpr ConstStringRef barrierCount("barrier_count");
static constexpr ConstStringRef disableMidThreadPreemption("disable_mid_thread_preemption");
static constexpr ConstStringRef grfCount("grf_count");
static constexpr ConstStringRef has4gbBuffers("has_4gb_buffers");
static constexpr ConstStringRef hasDeviceEnqueue("has_device_enqueue");
static constexpr ConstStringRef hasFenceForImageAccess("has_fence_for_image_access");
static constexpr ConstStringRef hasGlobalAtomics("has_global_atomics");
static constexpr ConstStringRef hasMultiScratchSpaces("has_multi_scratch_spaces");
static constexpr ConstStringRef hasNoStatelessWrite("has_no_stateless_write");
static constexpr ConstStringRef hwPreemptionMode("hw_preemption_mode");
static constexpr ConstStringRef offsetToSkipPerThreadDataLoad("offset_to_skip_per_thread_data_load");
static constexpr ConstStringRef offsetToSkipSetFfidGp("offset_to_skip_set_ffid_gp");
static constexpr ConstStringRef requiredSubGroupSize("required_sub_group_size");
static constexpr ConstStringRef requiredWorkGroupSize("required_work_group_size");
static constexpr ConstStringRef simdSize("simd_size");
static constexpr ConstStringRef slmSize("slm_size");
static constexpr ConstStringRef subgroupIndependentForwardProgress("subgroup_independent_forward_progress");
static constexpr ConstStringRef workGroupWalkOrderDimensions("work_group_walk_order_dimensions");
} // namespace ExecutionEnv
namespace PayloadArgument {
static constexpr ConstStringRef argType("arg_type");
static constexpr ConstStringRef argIndex("arg_index");
static constexpr ConstStringRef offset("offset");
static constexpr ConstStringRef size("size");
static constexpr ConstStringRef addrmode("addrmode");
static constexpr ConstStringRef addrspace("addrspace");
static constexpr ConstStringRef accessType("access_type");
namespace ArgType {
static constexpr ConstStringRef localSize("local_size");
static constexpr ConstStringRef groupSize("group_size");
static constexpr ConstStringRef globalIdOffset("global_id_offset");
static constexpr ConstStringRef privateBaseStateless("private_base_stateless");
static constexpr ConstStringRef argByvalue("arg_byvalue");
static constexpr ConstStringRef argBypointer("arg_bypointer");
} // namespace ArgType
namespace MemoryAddressingMode {
static constexpr ConstStringRef stateless("stateless");
static constexpr ConstStringRef stateful("stateful");
static constexpr ConstStringRef bindless("bindless");
static constexpr ConstStringRef sharedLocalMemory("shared_local_memory");
} // namespace MemoryAddressingMode
namespace AddrSpace {
static constexpr ConstStringRef global("global");
static constexpr ConstStringRef local("local");
static constexpr ConstStringRef constant("constant");
static constexpr ConstStringRef image("image");
static constexpr ConstStringRef sampler("sampler");
} // namespace AddrSpace
namespace AccessType {
static constexpr ConstStringRef readonly("readonly");
static constexpr ConstStringRef writeonly("writeonly");
static constexpr ConstStringRef readwrite("readwrite");
} // namespace AccessType
} // namespace PayloadArgument
namespace BindingTableIndex {
static constexpr ConstStringRef btiValue("bti_value");
static constexpr ConstStringRef argIndex("arg_index");
} // namespace BindingTableIndex
namespace PerThreadPayloadArgument {
static constexpr ConstStringRef argType("arg_type");
static constexpr ConstStringRef offset("offset");
static constexpr ConstStringRef size("size");
namespace ArgType {
static constexpr ConstStringRef packedLocalIds("packed_local_ids");
static constexpr ConstStringRef localId("local_id");
} // namespace ArgType
} // namespace PerThreadPayloadArgument
} // namespace Kernel
} // namespace Tags
namespace Types {
namespace Kernel {
namespace ExecutionEnv {
using ActualKernelStartOffsetT = int32_t;
using BarrierCountT = int32_t;
using DisableMidThreadPreemptionT = bool;
using GrfCountT = int32_t;
using Has4GBBuffersT = bool;
using HasDeviceEnqueueT = bool;
using HasFenceForImageAccessT = bool;
using HasGlobalAtomicsT = bool;
using HasMultiScratchSpacesT = bool;
using HasNoStatelessWriteT = bool;
using HwPreemptionModeT = int32_t;
using OffsetToSkipPerThreadDataLoadT = int32_t;
using OffsetToSkipSetFfidGpT = int32_t;
using RequiredSubGroupSizeT = int32_t;
using RequiredWorkGroupSizeT = int32_t[3];
using SimdSizeT = int32_t;
using SlmSizeT = int32_t;
using SubgroupIndependentForwardProgressT = bool;
using WorkgroupWalkOrderDimensionsT = int32_t[3];
namespace Defaults {
static constexpr BarrierCountT barrierCount = 0;
static constexpr DisableMidThreadPreemptionT disableMidThreadPreemption = false;
static constexpr Has4GBBuffersT has4GBBuffers = false;
static constexpr HasDeviceEnqueueT hasDeviceEnqueue = false;
static constexpr HasFenceForImageAccessT hasFenceForImageAccess = false;
static constexpr HasGlobalAtomicsT hasGlobalAtomics = false;
static constexpr HasMultiScratchSpacesT hasMultiScratchSpaces = false;
static constexpr HasNoStatelessWriteT hasNoStatelessWrite = false;
static constexpr HwPreemptionModeT hwPreemptionMode = -1;
static constexpr OffsetToSkipPerThreadDataLoadT offsetToSkipPerThreadDataLoad = 0;
static constexpr OffsetToSkipSetFfidGpT offsetToSkipSetFfidGp = 0;
static constexpr RequiredSubGroupSizeT requiredSubGroupSize = 0;
static constexpr RequiredWorkGroupSizeT requiredWorkGroupSize = {0, 0, 0};
static constexpr SlmSizeT slmSize = 0;
static constexpr SubgroupIndependentForwardProgressT subgroupIndependentForwardProgress = false;
static constexpr WorkgroupWalkOrderDimensionsT workgroupWalkOrderDimensions = {0, 1, 2};
} // namespace Defaults
static constexpr ConstStringRef required[] = {
Tags::Kernel::ExecutionEnv::actualKernelStartOffset,
Tags::Kernel::ExecutionEnv::grfCount,
Tags::Kernel::ExecutionEnv::simdSize};
struct ExecutionEnvBaseT {
ActualKernelStartOffsetT actualKernelStartOffset = -1;
BarrierCountT barrierCount = Defaults::barrierCount;
DisableMidThreadPreemptionT disableMidThreadPreemption = Defaults::disableMidThreadPreemption;
GrfCountT grfCount = -1;
Has4GBBuffersT has4GBBuffers = Defaults::has4GBBuffers;
HasDeviceEnqueueT hasDeviceEnqueue = Defaults::hasDeviceEnqueue;
HasFenceForImageAccessT hasFenceForImageAccess = Defaults::hasFenceForImageAccess;
HasGlobalAtomicsT hasGlobalAtomics = Defaults::hasGlobalAtomics;
HasMultiScratchSpacesT hasMultiScratchSpaces = Defaults::hasMultiScratchSpaces;
HasNoStatelessWriteT hasNoStatelessWrite = Defaults::hasNoStatelessWrite;
HwPreemptionModeT hwPreemptionMode = Defaults::hwPreemptionMode;
OffsetToSkipPerThreadDataLoadT offsetToSkipPerThreadDataLoad = Defaults::offsetToSkipPerThreadDataLoad;
OffsetToSkipSetFfidGpT offsetToSkipSetFfidGp = Defaults::offsetToSkipSetFfidGp;
RequiredSubGroupSizeT requiredSubGroupSize = Defaults::requiredSubGroupSize;
RequiredWorkGroupSizeT requiredWorkGroupSize = {Defaults::requiredWorkGroupSize[0], Defaults::requiredWorkGroupSize[1], Defaults::requiredWorkGroupSize[2]};
SimdSizeT simdSize = -1;
SlmSizeT slmSize = Defaults::slmSize;
SubgroupIndependentForwardProgressT subgroupIndependentForwardProgress = Defaults::subgroupIndependentForwardProgress;
WorkgroupWalkOrderDimensionsT workgroupWalkOrderDimensions{Defaults::workgroupWalkOrderDimensions[0], Defaults::workgroupWalkOrderDimensions[1], Defaults::workgroupWalkOrderDimensions[2]};
};
} // namespace ExecutionEnv
enum ArgType : uint8_t {
ArgTypeUnknown = 0,
ArgTypePackedLocalIds = 1,
ArgTypeLocalId,
ArgTypeLocalSize,
ArgTypeGroupSize,
ArgTypeGlobalIdOffset,
ArgTypePrivateBaseStateless,
ArgTypeArgByvalue,
ArgTypeArgBypointer,
};
namespace PerThreadPayloadArgument {
using OffsetT = int32_t;
using SizeT = int32_t;
using ArgTypeT = ArgType;
namespace Defaults {
}
struct PerThreadPayloadArgumentBaseT {
ArgTypeT argType = ArgTypeUnknown;
OffsetT offset = -1;
SizeT size = -1;
};
} // namespace PerThreadPayloadArgument
namespace PayloadArgument {
enum MemoryAddressingMode : uint8_t {
MemoryAddressingModeUnknown = 0,
MemoryAddressingModeStateful = 1,
MemoryAddressingModeStateless,
MemoryAddressingModeBindless,
MemoryAddressingModeSharedLocalMemory,
};
enum AddressSpace : uint8_t {
AddressSpaceUnknown = 0,
AddressSpaceGlobal = 1,
AddressSpaceLocal,
AddressSpaceConstant,
AddressSpaceImage,
AddressSpaceSampler,
};
enum AccessType : uint8_t {
AccessTypeUnknown = 0,
AccessTypeReadonly = 1,
AccessTypeWriteonly,
AccessTypeReadwrite,
};
using ArgTypeT = ArgType;
using OffseT = int32_t;
using SizeT = int32_t;
using ArgIndexT = int32_t;
using AddrmodeT = MemoryAddressingMode;
using AddrspaceT = AddressSpace;
using AccessTypeT = AccessType;
namespace Defaults {
static constexpr ArgIndexT argIndex = -1;
}
struct PayloadArgumentBaseT {
ArgTypeT argType = ArgTypeUnknown;
OffseT offset = 0;
SizeT size = 0;
ArgIndexT argIndex = Defaults::argIndex;
AddrmodeT addrmode = MemoryAddressingModeUnknown;
AddrspaceT addrspace = AddressSpaceUnknown;
AccessTypeT accessType = AccessTypeUnknown;
};
} // namespace PayloadArgument
namespace BindingTableEntry {
using BtiValueT = int32_t;
using ArgIndexT = int32_t;
struct BindingTableEntryBaseT {
BtiValueT btiValue = 0U;
ArgIndexT argIndex = 0U;
};
} // namespace BindingTableEntry
} // namespace Kernel
} // namespace Types
} // namespace ZebinKernelMetadata
} // namespace Elf
} // namespace NEO

View File

@@ -452,6 +452,9 @@ struct YamlParser {
}
ConstChildrenRange createChildrenRange(const Node &parent) const {
if (0 == parent.numChildren) {
return ConstChildrenRange(invalidNodeID, nodes);
}
return ConstChildrenRange(nodes[parent.firstChildId], nodes);
}
@@ -478,7 +481,7 @@ struct YamlParser {
};
template <>
inline bool YamlParser::readValueChecked<uint64_t>(const Node &node, uint64_t &outValue) const {
inline bool YamlParser::readValueChecked<int64_t>(const Node &node, int64_t &outValue) const {
if (invalidTokenId == node.value) {
return false;
}
@@ -492,6 +495,45 @@ inline bool YamlParser::readValueChecked<uint64_t>(const Node &node, uint64_t &o
return true;
}
template <>
inline bool YamlParser::readValueChecked<int32_t>(const Node &node, int32_t &outValue) const {
int64_t int64V = 0U;
bool validValue = readValueChecked<int64_t>(node, int64V);
validValue &= int64V <= std::numeric_limits<int32_t>::max();
validValue &= int64V >= std::numeric_limits<int32_t>::min();
outValue = static_cast<int32_t>(int64V);
return validValue;
}
template <>
inline bool YamlParser::readValueChecked<int16_t>(const Node &node, int16_t &outValue) const {
int64_t int64V = 0U;
bool validValue = readValueChecked<int64_t>(node, int64V);
validValue &= int64V <= std::numeric_limits<int16_t>::max();
validValue &= int64V >= std::numeric_limits<int16_t>::min();
outValue = static_cast<int16_t>(int64V);
return validValue;
}
template <>
inline bool YamlParser::readValueChecked<int8_t>(const Node &node, int8_t &outValue) const {
int64_t int64V = 0U;
bool validValue = readValueChecked<int64_t>(node, int64V);
validValue &= int64V <= std::numeric_limits<int8_t>::max();
validValue &= int64V >= std::numeric_limits<int8_t>::min();
outValue = static_cast<int8_t>(int64V);
return validValue;
}
template <>
inline bool YamlParser::readValueChecked<uint64_t>(const Node &node, uint64_t &outValue) const {
int64_t int64V = 0U;
bool validValue = readValueChecked<int64_t>(node, int64V);
validValue &= int64V >= 0;
outValue = static_cast<uint64_t>(int64V);
return validValue;
}
template <>
inline bool YamlParser::readValueChecked<uint32_t>(const Node &node, uint32_t &outValue) const {
uint64_t uint64V = 0U;

View File

@@ -0,0 +1,834 @@
/*
* Copyright (C) 2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/device_binary_format/zebin_decoder.h"
#include "shared/source/compiler_interface/intermediate_representations.h"
#include "shared/source/debug_settings/debug_settings_manager.h"
#include "shared/source/device_binary_format/device_binary_formats.h"
#include "shared/source/device_binary_format/elf/elf_decoder.h"
#include "shared/source/device_binary_format/elf/elf_encoder.h"
#include "shared/source/device_binary_format/elf/zebin_elf.h"
#include "shared/source/device_binary_format/yaml/yaml_parser.h"
#include "shared/source/program/program_info.h"
#include "shared/source/utilities/compiler_support.h"
#include "shared/source/utilities/stackvec.h"
#include "opencl/source/program/kernel_info.h"
#include <tuple>
namespace NEO {
DecodeError extractZebinSections(NEO::Elf::Elf<Elf::EI_CLASS_64> &elf, ZebinSections &out, std::string &outErrReason, std::string &outWarning) {
if ((elf.elfFileHeader->shStrNdx >= elf.sectionHeaders.size()) || (NEO::Elf::SHN_UNDEF == elf.elfFileHeader->shStrNdx)) {
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid or missing shStrNdx in elf header\n");
return DecodeError::InvalidBinary;
}
auto sectionHeaderNamesData = elf.sectionHeaders[elf.elfFileHeader->shStrNdx].data;
ConstStringRef sectionHeaderNamesString(reinterpret_cast<const char *>(sectionHeaderNamesData.begin()), sectionHeaderNamesData.size());
for (auto &elfSectionHeader : elf.sectionHeaders) {
ConstStringRef sectionName = ConstStringRef(sectionHeaderNamesString.begin() + elfSectionHeader.header->name);
switch (elfSectionHeader.header->type) {
default:
outErrReason.append("DeviceBinaryFormat::Zebin : Unhandled ELF section header type : " + std::to_string(elfSectionHeader.header->type) + "\n");
return DecodeError::InvalidBinary;
case Elf::SHT_PROGBITS:
if (sectionName.startsWith(NEO::Elf::SectionsNamesZebin::textPrefix.data())) {
out.textKernelSections.push_back(&elfSectionHeader);
} else if (sectionName == NEO::Elf::SectionsNamesZebin::dataConst) {
out.constDataSections.push_back(&elfSectionHeader);
} else if (sectionName == ".data.global_const") {
outWarning.append("Misspelled section name : " + sectionName.str() + ", should be : " + NEO::Elf::SectionsNamesZebin::dataConst.str() + "\n");
out.constDataSections.push_back(&elfSectionHeader);
} else if (sectionName == NEO::Elf::SectionsNamesZebin::dataGlobal) {
out.globalDataSections.push_back(&elfSectionHeader);
} else {
outErrReason.append("DeviceBinaryFormat::Zebin : Unhandled SHT_PROGBITS section : " + sectionName.str() + " currently supports only : " + NEO::Elf::SectionsNamesZebin::textPrefix.str() + "KERNEL_NAME, " + NEO::Elf::SectionsNamesZebin::dataConst.str() + " and " + NEO::Elf::SectionsNamesZebin::dataGlobal.str() + ".\n");
return DecodeError::InvalidBinary;
}
break;
case NEO::Elf::SHT_ZEBIN_ZEINFO:
out.zeInfoSections.push_back(&elfSectionHeader);
break;
case NEO::Elf::SHT_SYMTAB:
out.symtabSections.push_back(&elfSectionHeader);
break;
case NEO::Elf::SHT_ZEBIN_SPIRV:
out.spirvSections.push_back(&elfSectionHeader);
break;
case NEO::Elf::SHT_STRTAB:
// ignoring intentionally - section header names
continue;
case NEO::Elf::SHT_NULL:
// ignoring intentionally, inactive section, probably UNDEF
continue;
}
}
return DecodeError::Success;
}
template <typename ContainerT>
bool validateZebinSectionsCountAtMost(const ContainerT &sectionsContainer, ConstStringRef sectionName, uint32_t max, std::string &outErrReason, std::string &outWarning) {
if (sectionsContainer.size() <= max) {
return true;
}
outErrReason.append("DeviceBinaryFormat::Zebin : Expected at most " + std::to_string(max) + " of " + sectionName.str() + " section, got : " + std::to_string(sectionsContainer.size()) + "\n");
return false;
}
template <typename ContainerT>
bool validateZebinSectionsCountExactly(const ContainerT &sectionsContainer, ConstStringRef sectionName, uint32_t num, std::string &outErrReason, std::string &outWarning) {
if (sectionsContainer.size() == num) {
return true;
}
outErrReason.append("DeviceBinaryFormat::Zebin : Expected exactly " + std::to_string(num) + " of " + sectionName.str() + " section, got : " + std::to_string(sectionsContainer.size()) + "\n");
return false;
}
DecodeError validateZebinSectionsCount(const ZebinSections &sections, std::string &outErrReason, std::string &outWarning) {
bool valid = validateZebinSectionsCountAtMost(sections.zeInfoSections, NEO::Elf::SectionsNamesZebin::zeInfo, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(sections.globalDataSections, NEO::Elf::SectionsNamesZebin::dataGlobal, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(sections.constDataSections, NEO::Elf::SectionsNamesZebin::dataConst, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(sections.symtabSections, NEO::Elf::SectionsNamesZebin::symtab, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(sections.spirvSections, NEO::Elf::SectionsNamesZebin::spv, 1U, outErrReason, outWarning);
return valid ? DecodeError::Success : DecodeError::InvalidBinary;
}
void extractZeInfoKernelSections(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &kernelNd, ZeInfoKernelSections &outZeInfoKernelSections, ConstStringRef context, std::string &outWarning) {
for (const auto &kernelMetadataNd : parser.createChildrenRange(kernelNd)) {
auto key = parser.readKey(kernelMetadataNd);
if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::name == key) {
outZeInfoKernelSections.nameNd.push_back(&kernelMetadataNd);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::executionEnv == key) {
outZeInfoKernelSections.executionEnvNd.push_back(&kernelMetadataNd);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::payloadArguments == key) {
outZeInfoKernelSections.payloadArgumentsNd.push_back(&kernelMetadataNd);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::perThreadPayloadArguments == key) {
outZeInfoKernelSections.perThreadPayloadArgumentsNd.push_back(&kernelMetadataNd);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::bindingTableIndices == key) {
outZeInfoKernelSections.bindingTableIndicesNd.push_back(&kernelMetadataNd);
} else {
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + parser.readKey(kernelMetadataNd).str() + "\" in context of : " + context.str() + "\n");
}
}
}
DecodeError validateZeInfoKernelSectionsCount(const ZeInfoKernelSections &outZeInfoKernelSections, std::string &outErrReason, std::string &outWarning) {
bool valid = validateZebinSectionsCountExactly(outZeInfoKernelSections.nameNd, NEO::Elf::ZebinKernelMetadata::Tags::Kernel::name, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountExactly(outZeInfoKernelSections.executionEnvNd, NEO::Elf::ZebinKernelMetadata::Tags::Kernel::executionEnv, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(outZeInfoKernelSections.payloadArgumentsNd, NEO::Elf::ZebinKernelMetadata::Tags::Kernel::payloadArguments, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(outZeInfoKernelSections.perThreadPayloadArgumentsNd, NEO::Elf::ZebinKernelMetadata::Tags::Kernel::perThreadPayloadArguments, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(outZeInfoKernelSections.bindingTableIndicesNd, NEO::Elf::ZebinKernelMetadata::Tags::Kernel::bindingTableIndices, 1U, outErrReason, outWarning);
return valid ? DecodeError::Success : DecodeError::InvalidBinary;
}
template <typename T>
bool readZeInfoValueChecked(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &node, T &outValue, ConstStringRef context, std::string &outErrReason) {
if (parser.readValueChecked(node, outValue)) {
return true;
}
outErrReason.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : could not read " + parser.readKey(node).str() + " from : [" + parser.readValue(node).str() + "] in context of : " + context.str() + "\n");
return false;
}
DecodeError readZeInfoExecutionEnvironment(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &node,
NEO::Elf::ZebinKernelMetadata::Types::Kernel::ExecutionEnv::ExecutionEnvBaseT &outExecEnv,
ConstStringRef context,
std::string &outErrReason, std::string &outWarning) {
bool validExecEnv = true;
for (const auto &execEnvMetadataNd : parser.createChildrenRange(node)) {
auto key = parser.readKey(execEnvMetadataNd);
if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::actualKernelStartOffset == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.actualKernelStartOffset, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::barrierCount == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.barrierCount, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::disableMidThreadPreemption == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.disableMidThreadPreemption, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::grfCount == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.grfCount, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::has4gbBuffers == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.has4GBBuffers, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::hasDeviceEnqueue == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.hasDeviceEnqueue, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::hasFenceForImageAccess == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.hasFenceForImageAccess, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::hasGlobalAtomics == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.hasGlobalAtomics, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::hasMultiScratchSpaces == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.hasMultiScratchSpaces, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::hasNoStatelessWrite == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.hasNoStatelessWrite, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::hwPreemptionMode == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.hwPreemptionMode, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::offsetToSkipPerThreadDataLoad == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.offsetToSkipPerThreadDataLoad, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::offsetToSkipSetFfidGp == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.offsetToSkipSetFfidGp, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::requiredSubGroupSize == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.requiredSubGroupSize, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::simdSize == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.simdSize, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::slmSize == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.slmSize, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::ExecutionEnv::subgroupIndependentForwardProgress == key) {
validExecEnv = validExecEnv & readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.subgroupIndependentForwardProgress, context, outErrReason);
} else {
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + key.str() + "\" in context of " + context.str() + "\n");
}
}
return validExecEnv ? DecodeError::Success : DecodeError::InvalidBinary;
}
bool readEnumChecked(const Yaml::Token *token, NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgType &out, ConstStringRef context, std::string &outErrReason) {
if (nullptr == token) {
return false;
}
using namespace NEO::Elf::ZebinKernelMetadata::Tags::Kernel;
using ArgTypeT = NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgType;
auto tokenValue = token->cstrref();
if (tokenValue == PerThreadPayloadArgument::ArgType::packedLocalIds) {
out = ArgTypeT::ArgTypePackedLocalIds;
} else if (tokenValue == PerThreadPayloadArgument::ArgType::localId) {
out = ArgTypeT::ArgTypeLocalId;
} else if (tokenValue == PayloadArgument::ArgType::localSize) {
out = ArgTypeT::ArgTypeLocalSize;
} else if (tokenValue == PayloadArgument::ArgType::groupSize) {
out = ArgTypeT::ArgTypeGroupSize;
} else if (tokenValue == PayloadArgument::ArgType::globalIdOffset) {
out = ArgTypeT::ArgTypeGlobalIdOffset;
} else if (tokenValue == PayloadArgument::ArgType::privateBaseStateless) {
out = ArgTypeT::ArgTypePrivateBaseStateless;
} else if (tokenValue == PayloadArgument::ArgType::argByvalue) {
out = ArgTypeT::ArgTypeArgByvalue;
} else if (tokenValue == PayloadArgument::ArgType::argBypointer) {
out = ArgTypeT::ArgTypeArgBypointer;
} else {
outErrReason.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unhandled \"" + tokenValue.str() + "\" argument type in context of " + context.str() + "\n");
return false;
}
return true;
}
bool readEnumChecked(const Yaml::Token *token, NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::MemoryAddressingMode &out,
ConstStringRef context, std::string &outErrReason) {
if (nullptr == token) {
return false;
}
using namespace NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::MemoryAddressingMode;
using AddrMode = NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::MemoryAddressingMode;
auto tokenValue = token->cstrref();
if (stateless == tokenValue) {
out = AddrMode::MemoryAddressingModeStateless;
} else if (stateful == tokenValue) {
out = AddrMode::MemoryAddressingModeStateful;
} else if (bindless == tokenValue) {
out = AddrMode::MemoryAddressingModeBindless;
} else if (sharedLocalMemory == tokenValue) {
out = AddrMode::MemoryAddressingModeSharedLocalMemory;
} else {
outErrReason.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unhandled \"" + tokenValue.str() + "\" memory addressing mode in context of " + context.str() + "\n");
return false;
}
return true;
}
bool readEnumChecked(const Yaml::Token *token, NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AddressSpace &out,
ConstStringRef context, std::string &outErrReason) {
if (nullptr == token) {
return false;
}
using namespace NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::AddrSpace;
using AddrSpace = NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AddressSpace;
auto tokenValue = token->cstrref();
if (global == tokenValue) {
out = AddrSpace::AddressSpaceGlobal;
} else if (local == tokenValue) {
out = AddrSpace::AddressSpaceLocal;
} else if (constant == tokenValue) {
out = AddrSpace::AddressSpaceConstant;
} else if (image == tokenValue) {
out = AddrSpace::AddressSpaceImage;
} else if (sampler == tokenValue) {
out = AddrSpace::AddressSpaceSampler;
} else {
outErrReason.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unhandled \"" + tokenValue.str() + "\" address space in context of " + context.str() + "\n");
return false;
}
return true;
}
bool readEnumChecked(const Yaml::Token *token, NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AccessType &out,
ConstStringRef context, std::string &outErrReason) {
if (nullptr == token) {
return false;
}
using namespace NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::AccessType;
using AccessType = NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AccessType;
auto tokenValue = token->cstrref();
static constexpr ConstStringRef readonly("readonly");
static constexpr ConstStringRef writeonly("writeonly");
static constexpr ConstStringRef readwrite("readwrite");
if (readonly == tokenValue) {
out = AccessType::AccessTypeReadonly;
} else if (writeonly == tokenValue) {
out = AccessType::AccessTypeWriteonly;
} else if (readwrite == tokenValue) {
out = AccessType::AccessTypeReadwrite;
} else {
outErrReason.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unhandled \"" + tokenValue.str() + "\" access type in context of " + context.str() + "\n");
return false;
}
return true;
}
DecodeError readZeInfoPerThreadPayloadArguments(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &node,
ZeInfoPerThreadPayloadArguments &outPerThreadPayloadArguments,
ConstStringRef context,
std::string &outErrReason, std::string &outWarning) {
bool validPerThreadPayload = true;
for (const auto &perThredPayloadArgumentNd : parser.createChildrenRange(node)) {
outPerThreadPayloadArguments.resize(outPerThreadPayloadArguments.size() + 1);
auto &perThreadPayloadArgMetadata = *outPerThreadPayloadArguments.rbegin();
ConstStringRef argTypeStr;
for (const auto &perThreadPayloadArgumentMemberNd : parser.createChildrenRange(perThredPayloadArgumentNd)) {
auto key = parser.readKey(perThreadPayloadArgumentMemberNd);
if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PerThreadPayloadArgument::argType == key) {
auto argTypeToken = parser.getValueToken(perThreadPayloadArgumentMemberNd);
argTypeStr = parser.readValue(perThreadPayloadArgumentMemberNd);
validPerThreadPayload &= readEnumChecked(argTypeToken, perThreadPayloadArgMetadata.argType, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PerThreadPayloadArgument::size == key) {
validPerThreadPayload &= readZeInfoValueChecked(parser, perThreadPayloadArgumentMemberNd, perThreadPayloadArgMetadata.size, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PerThreadPayloadArgument::offset == key) {
validPerThreadPayload &= readZeInfoValueChecked(parser, perThreadPayloadArgumentMemberNd, perThreadPayloadArgMetadata.offset, context, outErrReason);
} else {
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + key.str() + "\" for per-thread payload argument in context of " + context.str() + "\n");
}
}
if (0 == perThreadPayloadArgMetadata.size) {
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Skippinig 0-size per-thread argument of type : " + argTypeStr.str() + " in context of " + context.str() + "\n");
outPerThreadPayloadArguments.pop_back();
}
}
return validPerThreadPayload ? DecodeError::Success : DecodeError::InvalidBinary;
}
DecodeError readZeInfoPayloadArguments(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &node,
ZeInfoPayloadArguments &ouPayloadArguments,
uint32_t &outMaxPayloadArgumentIndex,
ConstStringRef context,
std::string &outErrReason, std::string &outWarning) {
bool validPayload = true;
for (const auto &payloadArgumentNd : parser.createChildrenRange(node)) {
ouPayloadArguments.resize(ouPayloadArguments.size() + 1);
auto &payloadArgMetadata = *ouPayloadArguments.rbegin();
for (const auto &payloadArgumentMemberNd : parser.createChildrenRange(payloadArgumentNd)) {
auto key = parser.readKey(payloadArgumentMemberNd);
if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::argType == key) {
auto argTypeToken = parser.getValueToken(payloadArgumentMemberNd);
validPayload &= readEnumChecked(argTypeToken, payloadArgMetadata.argType, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::argIndex == key) {
validPayload &= parser.readValueChecked(payloadArgumentMemberNd, payloadArgMetadata.argIndex);
outMaxPayloadArgumentIndex = std::max<uint32_t>(outMaxPayloadArgumentIndex, payloadArgMetadata.argIndex);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::offset == key) {
validPayload &= readZeInfoValueChecked(parser, payloadArgumentMemberNd, payloadArgMetadata.offset, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::size == key) {
validPayload &= readZeInfoValueChecked(parser, payloadArgumentMemberNd, payloadArgMetadata.size, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::addrmode == key) {
auto memTypeToken = parser.getValueToken(payloadArgumentMemberNd);
validPayload &= readEnumChecked(memTypeToken, payloadArgMetadata.addrmode, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::addrspace == key) {
auto addrSpaceToken = parser.getValueToken(payloadArgumentMemberNd);
validPayload &= readEnumChecked(addrSpaceToken, payloadArgMetadata.addrspace, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::accessType == key) {
auto accessTypeToken = parser.getValueToken(payloadArgumentMemberNd);
validPayload &= readEnumChecked(accessTypeToken, payloadArgMetadata.accessType, context, outErrReason);
} else {
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + key.str() + "\" for payload argument in context of " + context.str() + "\n");
}
}
}
return validPayload ? DecodeError::Success : DecodeError::InvalidBinary;
}
DecodeError readZeInfoBindingTableIndices(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &node,
ZeInfoBindingTableIndices &outBindingTableIndices, ZeInfoBindingTableIndices::value_type &outMaxBindingTableIndex,
ConstStringRef context,
std::string &outErrReason, std::string &outWarning) {
bool validBindingTableEntries = true;
for (const auto &bindingTableIndexNd : parser.createChildrenRange(node)) {
outBindingTableIndices.resize(outBindingTableIndices.size() + 1);
auto &bindingTableIndexMetadata = *outBindingTableIndices.rbegin();
for (const auto &bindingTableIndexMemberNd : parser.createChildrenRange(bindingTableIndexNd)) {
auto key = parser.readKey(bindingTableIndexMemberNd);
if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::BindingTableIndex::argIndex == key) {
validBindingTableEntries &= readZeInfoValueChecked(parser, bindingTableIndexMemberNd, bindingTableIndexMetadata.argIndex, context, outErrReason);
outMaxBindingTableIndex.argIndex = std::max<uint32_t>(outMaxBindingTableIndex.argIndex, bindingTableIndexMetadata.argIndex);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::BindingTableIndex::btiValue == key) {
validBindingTableEntries &= readZeInfoValueChecked(parser, bindingTableIndexMemberNd, bindingTableIndexMetadata.btiValue, context, outErrReason);
outMaxBindingTableIndex.btiValue = std::max<uint32_t>(outMaxBindingTableIndex.btiValue, bindingTableIndexMetadata.btiValue);
} else {
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + key.str() + "\" for binding table index in context of " + context.str() + "\n");
}
}
}
return validBindingTableEntries ? DecodeError::Success : DecodeError::InvalidBinary;
}
template <typename ElSize, size_t Len>
bool setVecArgIndicesBasedOnSize(CrossThreadDataOffset (&vec)[Len], size_t vecSize, CrossThreadDataOffset baseOffset) {
switch (vecSize) {
default:
return false;
case sizeof(ElSize) * 3:
vec[2] = static_cast<CrossThreadDataOffset>(baseOffset + 2 * sizeof(ElSize));
CPP_ATTRIBUTE_FALLTHROUGH;
case sizeof(ElSize) * 2:
vec[1] = static_cast<CrossThreadDataOffset>(baseOffset + 1 * sizeof(ElSize));
CPP_ATTRIBUTE_FALLTHROUGH;
case sizeof(ElSize) * 1:
vec[0] = static_cast<CrossThreadDataOffset>(baseOffset + 0 * sizeof(ElSize));
break;
}
return true;
}
NEO::DecodeError populateArgDescriptor(const NEO::Elf::ZebinKernelMetadata::Types::Kernel::PerThreadPayloadArgument::PerThreadPayloadArgumentBaseT &src, NEO::KernelDescriptor &dst,
std::string &outErrReason, std::string &outWarning) {
switch (src.argType) {
default:
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid arg type in per thread data section in context of : " + dst.kernelMetadata.kernelName + ".\n");
return DecodeError::InvalidBinary;
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeLocalId: {
if (src.offset != 0) {
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid offset for argument of type " + NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PerThreadPayloadArgument::ArgType::localId.str() + " in context of : " + dst.kernelMetadata.kernelName + ". Expected 0.\n");
return DecodeError::InvalidBinary;
}
using LocalIdT = uint16_t;
uint32_t singleChannelIndicesCount = (dst.kernelAttributes.simdSize == 32 ? 32 : 16);
uint32_t singleChannelBytes = singleChannelIndicesCount * sizeof(LocalIdT);
auto tupleSize = (src.size / singleChannelBytes);
switch (tupleSize) {
default:
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid size for argument of type " + NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PerThreadPayloadArgument::ArgType::localId.str() + " in context of : " + dst.kernelMetadata.kernelName + ". For simd=" + std::to_string(dst.kernelAttributes.simdSize) + " expected : " + std::to_string(singleChannelBytes) + " or " + std::to_string(singleChannelBytes * 2) + " or " + std::to_string(singleChannelBytes * 3) + ". Got : " + std::to_string(src.size) + " \n");
return DecodeError::InvalidBinary;
case 1:
CPP_ATTRIBUTE_FALLTHROUGH;
case 2:
CPP_ATTRIBUTE_FALLTHROUGH;
case 3:
dst.kernelAttributes.numLocalIdChannels = static_cast<uint8_t>(tupleSize);
break;
}
dst.kernelAttributes.perThreadDataSize = dst.kernelAttributes.simdSize;
dst.kernelAttributes.perThreadDataSize *= dst.kernelAttributes.numLocalIdChannels;
dst.kernelAttributes.perThreadDataSize *= sizeof(LocalIdT);
break;
}
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypePackedLocalIds: {
if (src.offset != 0) {
outErrReason.append("DeviceBinaryFormat::Zebin : Unhandled offset for argument of type " + NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PerThreadPayloadArgument::ArgType::packedLocalIds.str() + " in context of : " + dst.kernelMetadata.kernelName + ". Expected 0.\n");
return DecodeError::InvalidBinary;
}
using LocalIdT = uint16_t;
auto tupleSize = src.size / sizeof(LocalIdT);
switch (tupleSize) {
default:
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid size for argument of type " + NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PerThreadPayloadArgument::ArgType::packedLocalIds.str() + " in context of : " + dst.kernelMetadata.kernelName + ". Expected : " + std::to_string(sizeof(LocalIdT)) + " or " + std::to_string(sizeof(LocalIdT) * 2) + " or " + std::to_string(sizeof(LocalIdT) * 3) + ". Got : " + std::to_string(src.size) + " \n");
return DecodeError::InvalidBinary;
case 1:
CPP_ATTRIBUTE_FALLTHROUGH;
case 2:
CPP_ATTRIBUTE_FALLTHROUGH;
case 3:
dst.kernelAttributes.numLocalIdChannels = static_cast<uint8_t>(tupleSize);
break;
}
dst.kernelAttributes.simdSize = 1;
dst.kernelAttributes.perThreadDataSize = dst.kernelAttributes.simdSize;
dst.kernelAttributes.perThreadDataSize *= dst.kernelAttributes.numLocalIdChannels;
dst.kernelAttributes.perThreadDataSize *= sizeof(LocalIdT);
break;
}
}
return DecodeError::Success;
}
NEO::DecodeError populateArgDescriptor(const NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::PayloadArgumentBaseT &src, NEO::KernelDescriptor &dst, uint32_t &crossThreadDataSize,
std::string &outErrReason, std::string &outWarning) {
crossThreadDataSize = std::max<uint32_t>(crossThreadDataSize, src.offset + src.size);
switch (src.argType) {
default:
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid arg type in cross thread data section in context of : " + dst.kernelMetadata.kernelName + ".\n");
return DecodeError::InvalidBinary; // unsupported
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeArgBypointer: {
auto &argTraits = dst.payloadMappings.explicitArgs[src.argIndex].getTraits();
auto &argAsPointer = dst.payloadMappings.explicitArgs[src.argIndex].as<ArgDescPointer>(true);
switch (src.addrspace) {
default:
UNRECOVERABLE_IF(NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AddressSpaceUnknown != src.addrspace);
argTraits.addressQualifier = KernelArgMetadata::AddrUnknown;
break;
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AddressSpaceGlobal:
argTraits.addressQualifier = KernelArgMetadata::AddrGlobal;
break;
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AddressSpaceLocal:
argTraits.addressQualifier = KernelArgMetadata::AddrLocal;
break;
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AddressSpaceConstant:
argTraits.addressQualifier = KernelArgMetadata::AddrConstant;
break;
}
switch (src.accessType) {
default:
UNRECOVERABLE_IF(argTraits.accessQualifier != NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AccessTypeUnknown);
argTraits.accessQualifier = KernelArgMetadata::AccessUnknown;
break;
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AccessTypeReadonly:
argTraits.accessQualifier = KernelArgMetadata::AccessReadOnly;
break;
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AccessTypeReadwrite:
argTraits.accessQualifier = KernelArgMetadata::AccessReadWrite;
break;
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AccessTypeWriteonly:
argTraits.accessQualifier = KernelArgMetadata::AccessWriteOnly;
break;
}
argTraits.argByValSize = sizeof(void *);
switch (src.addrmode) {
default:
outErrReason.append("Invalid or missing memory addressing mode for arg idx : " + std::to_string(src.argIndex) + " in context of : " + dst.kernelMetadata.kernelName + ".\n");
return DecodeError::InvalidBinary;
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::MemoryAddressingModeStateful:
break;
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::MemoryAddressingModeStateless:
argAsPointer.stateless = src.offset;
argAsPointer.pointerSize = src.size;
break;
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::MemoryAddressingModeBindless:
argAsPointer.bindless = src.offset;
break;
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::MemoryAddressingModeSharedLocalMemory:
argAsPointer.slmOffset = src.offset; // what about SLM alignment ?
break;
}
break;
}
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeArgByvalue: {
auto &argAsValue = dst.payloadMappings.explicitArgs[src.argIndex].as<ArgDescValue>(true);
ArgDescValue::Element valueElement;
valueElement.offset = src.offset;
valueElement.sourceOffset = 0U;
valueElement.size = src.size;
argAsValue.elements.push_back(valueElement);
break;
}
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeLocalSize: {
using LocalSizeT = uint32_t;
if (false == setVecArgIndicesBasedOnSize<LocalSizeT>(dst.payloadMappings.dispatchTraits.localWorkSize, src.size, src.offset)) {
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid size for argument of type " + NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::ArgType::localSize.str() + " in context of : " + dst.kernelMetadata.kernelName + ". Expected 4 or 8 or 12. Got : " + std::to_string(src.size) + "\n");
return DecodeError::InvalidBinary;
}
break;
}
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeGlobalIdOffset: {
using GlovaIdOffsetT = uint32_t;
if (false == setVecArgIndicesBasedOnSize<GlovaIdOffsetT>(dst.payloadMappings.dispatchTraits.globalWorkOffset, src.size, src.offset)) {
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid size for argument of type " + NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::ArgType::globalIdOffset.str() + " in context of : " + dst.kernelMetadata.kernelName + ". Expected 4 or 8 or 12. Got : " + std::to_string(src.size) + "\n");
return DecodeError::InvalidBinary;
}
break;
}
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeGroupSize: {
using GroupSizeT = uint32_t;
if (false == setVecArgIndicesBasedOnSize<GroupSizeT>(dst.payloadMappings.dispatchTraits.numWorkGroups, src.size, src.offset)) {
{
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid size for argument of type " + NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::ArgType::groupSize.str() + " in context of : " + dst.kernelMetadata.kernelName + ". Expected 4 or 8 or 12. Got : " + std::to_string(src.size) + "\n");
return DecodeError::InvalidBinary;
}
}
break;
}
}
return DecodeError::Success;
}
NEO::DecodeError populateKernelDescriptor(NEO::ProgramInfo &dst, NEO::Elf::Elf<NEO::Elf::EI_CLASS_64> &elf, NEO::ZebinSections &zebinSections,
NEO::Yaml::YamlParser &yamlParser, const NEO::Yaml::Node &kernelNd, std::string &outErrReason, std::string &outWarning) {
auto kernelInfo = std::make_unique<NEO::KernelInfo>();
auto &kernelDescriptor = kernelInfo->kernelDescriptor;
ZeInfoKernelSections zeInfokernelSections;
extractZeInfoKernelSections(yamlParser, kernelNd, zeInfokernelSections, NEO::Elf::SectionsNamesZebin::zeInfo, outWarning);
auto extractError = validateZeInfoKernelSectionsCount(zeInfokernelSections, outErrReason, outWarning);
if (DecodeError::Success != extractError) {
return extractError;
}
kernelDescriptor.kernelMetadata.kernelName = yamlParser.readValue(*zeInfokernelSections.nameNd[0]).str();
NEO::Elf::ZebinKernelMetadata::Types::Kernel::ExecutionEnv::ExecutionEnvBaseT execEnv;
auto execEnvErr = readZeInfoExecutionEnvironment(yamlParser, *zeInfokernelSections.executionEnvNd[0], execEnv, kernelInfo->kernelDescriptor.kernelMetadata.kernelName, outErrReason, outWarning);
if (DecodeError::Success != execEnvErr) {
return execEnvErr;
}
ZeInfoPerThreadPayloadArguments perThreadPayloadArguments;
if (false == zeInfokernelSections.perThreadPayloadArgumentsNd.empty()) {
auto perThreadPayloadArgsErr = readZeInfoPerThreadPayloadArguments(yamlParser, *zeInfokernelSections.perThreadPayloadArgumentsNd[0], perThreadPayloadArguments,
kernelDescriptor.kernelMetadata.kernelName, outErrReason, outWarning);
if (DecodeError::Success != perThreadPayloadArgsErr) {
return perThreadPayloadArgsErr;
}
}
uint32_t maxArgumentIndex = 0U;
ZeInfoPayloadArguments payloadArguments;
if (false == zeInfokernelSections.payloadArgumentsNd.empty()) {
auto payloadArgsErr = readZeInfoPayloadArguments(yamlParser, *zeInfokernelSections.payloadArgumentsNd[0], payloadArguments, maxArgumentIndex,
kernelDescriptor.kernelMetadata.kernelName, outErrReason, outWarning);
if (DecodeError::Success != payloadArgsErr) {
return payloadArgsErr;
}
}
kernelDescriptor.kernelAttributes.hasBarriers = execEnv.barrierCount;
kernelDescriptor.kernelAttributes.flags.usesBarriers = (kernelDescriptor.kernelAttributes.hasBarriers > 0U);
kernelDescriptor.kernelAttributes.flags.requiresDisabledMidThreadPreemption = execEnv.disableMidThreadPreemption;
kernelDescriptor.kernelAttributes.numGrfRequired = execEnv.grfCount;
if (execEnv.has4GBBuffers) {
kernelDescriptor.kernelAttributes.bufferAddressingMode = KernelDescriptor::Stateless;
}
kernelDescriptor.kernelAttributes.flags.usesDeviceSideEnqueue = execEnv.hasDeviceEnqueue;
kernelDescriptor.kernelAttributes.flags.usesFencesForReadWriteImages = execEnv.hasFenceForImageAccess;
kernelDescriptor.kernelAttributes.flags.useGlobalAtomics = execEnv.hasGlobalAtomics;
kernelDescriptor.kernelAttributes.flags.usesStatelessWrites = (false == execEnv.hasNoStatelessWrite);
kernelDescriptor.entryPoints.skipPerThreadDataLoad = execEnv.offsetToSkipPerThreadDataLoad;
kernelDescriptor.entryPoints.skipSetFFIDGP = execEnv.offsetToSkipSetFfidGp;
kernelDescriptor.kernelMetadata.requiredSubGroupSize = execEnv.requiredSubGroupSize;
kernelDescriptor.kernelAttributes.simdSize = execEnv.simdSize;
kernelDescriptor.kernelAttributes.slmInlineSize = execEnv.slmSize;
kernelDescriptor.kernelAttributes.flags.requiresSubgroupIndependentForwardProgress = execEnv.subgroupIndependentForwardProgress;
if ((kernelDescriptor.kernelAttributes.simdSize != 1) && (kernelDescriptor.kernelAttributes.simdSize != 8) && (kernelDescriptor.kernelAttributes.simdSize != 16) && (kernelDescriptor.kernelAttributes.simdSize != 32)) {
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid simd size : " + std::to_string(kernelDescriptor.kernelAttributes.simdSize) + " in context of : " + kernelDescriptor.kernelMetadata.kernelName + ". Expected 1, 8, 16 or 32. Got : " + std::to_string(kernelDescriptor.kernelAttributes.simdSize) + "\n");
return DecodeError::InvalidBinary;
}
for (const auto &arg : perThreadPayloadArguments) {
auto decodeErr = populateArgDescriptor(arg, kernelDescriptor, outErrReason, outWarning);
if (DecodeError::Success != decodeErr) {
return decodeErr;
}
}
kernelDescriptor.payloadMappings.explicitArgs.resize(maxArgumentIndex + 1);
kernelDescriptor.explicitArgsExtendedMetadata.resize(maxArgumentIndex + 1);
kernelDescriptor.kernelAttributes.numArgsToPatch = maxArgumentIndex + 1;
uint32_t crossThreadDataSize = 0;
for (const auto &arg : payloadArguments) {
auto decodeErr = populateArgDescriptor(arg, kernelDescriptor, crossThreadDataSize, outErrReason, outWarning);
if (DecodeError::Success != decodeErr) {
return decodeErr;
}
}
if (NEO::DebugManager.flags.ZebinAppendElws.get()) {
kernelDescriptor.payloadMappings.dispatchTraits.enqueuedLocalWorkSize[0] = alignDown(crossThreadDataSize + 12, 32);
kernelDescriptor.payloadMappings.dispatchTraits.enqueuedLocalWorkSize[1] = kernelDescriptor.payloadMappings.dispatchTraits.enqueuedLocalWorkSize[0] + 4;
kernelDescriptor.payloadMappings.dispatchTraits.enqueuedLocalWorkSize[2] = kernelDescriptor.payloadMappings.dispatchTraits.enqueuedLocalWorkSize[1] + 4;
crossThreadDataSize = kernelDescriptor.payloadMappings.dispatchTraits.enqueuedLocalWorkSize[2] + 4;
}
kernelDescriptor.kernelAttributes.crossThreadDataSize = static_cast<uint16_t>(alignUp(crossThreadDataSize, 32));
ZeInfoBindingTableIndices bindingTableIndices;
ZeInfoBindingTableIndices::value_type maximumBindingTableEntry;
if (false == zeInfokernelSections.bindingTableIndicesNd.empty()) {
auto btisErr = readZeInfoBindingTableIndices(yamlParser, *zeInfokernelSections.bindingTableIndicesNd[0], bindingTableIndices, maximumBindingTableEntry,
kernelDescriptor.kernelMetadata.kernelName, outErrReason, outWarning);
if (DecodeError::Success != btisErr) {
return btisErr;
}
}
auto generatedSshPos = kernelDescriptor.generatedHeaps.size();
uint32_t generatedSshSize = 0U;
if (bindingTableIndices.empty() == false) {
static constexpr auto maxSurfaceStateSize = 64U;
static constexpr auto btiSize = sizeof(int);
auto numEntries = maximumBindingTableEntry.btiValue + 1;
kernelDescriptor.generatedHeaps.resize(alignUp(generatedSshPos, maxSurfaceStateSize), 0U);
generatedSshPos = kernelInfo->kernelDescriptor.generatedHeaps.size();
// make room for surface states
kernelDescriptor.generatedHeaps.resize(generatedSshPos + numEntries * maxSurfaceStateSize, 0U);
auto generatedBindingTablePos = kernelDescriptor.generatedHeaps.size();
kernelDescriptor.generatedHeaps.resize(generatedBindingTablePos + numEntries * btiSize, 0U);
auto bindingTableIt = reinterpret_cast<int *>(kernelDescriptor.generatedHeaps.data() + generatedBindingTablePos);
for (auto &bti : bindingTableIndices) {
*bindingTableIt = bti.btiValue * 64U;
++bindingTableIt;
auto &explicitArg = kernelDescriptor.payloadMappings.explicitArgs[bti.argIndex];
switch (explicitArg.type) {
default:
outErrReason.append("DeviceBinaryFormat::Zebin::.ze_info : Invalid binding table entry for non-pointer and non-image argument idx : " + std::to_string(bti.argIndex) + ".\n");
return DecodeError::InvalidBinary;
case ArgDescriptor::ArgTPointer: {
explicitArg.as<ArgDescPointer>().bindful = bti.btiValue * maxSurfaceStateSize;
break;
}
}
}
kernelDescriptor.generatedHeaps.resize(alignUp(kernelDescriptor.generatedHeaps.size(), maxSurfaceStateSize), 0U);
generatedSshSize = static_cast<uint32_t>(kernelDescriptor.generatedHeaps.size() - generatedSshPos);
kernelDescriptor.payloadMappings.bindingTable.numEntries = numEntries;
kernelDescriptor.payloadMappings.bindingTable.tableOffset = static_cast<SurfaceStateHeapOffset>(generatedBindingTablePos - generatedSshPos);
}
ZebinSections::SectionHeaderData *correspondingTextSegment = nullptr;
auto sectionHeaderNamesData = elf.sectionHeaders[elf.elfFileHeader->shStrNdx].data;
ConstStringRef sectionHeaderNamesString(reinterpret_cast<const char *>(sectionHeaderNamesData.begin()), sectionHeaderNamesData.size());
for (auto *textSection : zebinSections.textKernelSections) {
ConstStringRef sectionName = ConstStringRef(sectionHeaderNamesString.begin() + textSection->header->name);
auto sufix = sectionName.substr(static_cast<int>(NEO::Elf::SectionsNamesZebin::textPrefix.length()));
if (sufix == kernelDescriptor.kernelMetadata.kernelName) {
correspondingTextSegment = textSection;
}
}
if (nullptr == correspondingTextSegment) {
outErrReason.append("Could not find text section for kernel " + kernelDescriptor.kernelMetadata.kernelName + "\n");
return DecodeError::InvalidBinary;
}
kernelInfo->heapInfo.pKernelHeap = correspondingTextSegment->data.begin();
kernelInfo->heapInfo.KernelHeapSize = static_cast<uint32_t>(correspondingTextSegment->data.size());
kernelInfo->heapInfo.KernelUnpaddedSize = static_cast<uint32_t>(correspondingTextSegment->data.size());
kernelInfo->heapInfo.pSsh = kernelDescriptor.generatedHeaps.data() + generatedSshPos;
kernelInfo->heapInfo.SurfaceStateHeapSize = generatedSshSize;
dst.kernelInfos.push_back(kernelInfo.release());
return DecodeError::Success;
}
template <>
DecodeError decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ProgramInfo &dst, const SingleDeviceBinary &src, std::string &outErrReason, std::string &outWarning) {
auto elf = Elf::decodeElf<Elf::EI_CLASS_64>(src.deviceBinary, outErrReason, outWarning);
if (nullptr == elf.elfFileHeader) {
return DecodeError::InvalidBinary;
}
ZebinSections zebinSections;
auto extractError = extractZebinSections(elf, zebinSections, outErrReason, outWarning);
if (DecodeError::Success != extractError) {
return extractError;
}
extractError = validateZebinSectionsCount(zebinSections, outErrReason, outWarning);
if (DecodeError::Success != extractError) {
return extractError;
}
if (false == zebinSections.globalDataSections.empty()) {
dst.globalVariables.initData = zebinSections.globalDataSections[0]->data.begin();
dst.globalVariables.size = zebinSections.globalDataSections[0]->data.size();
}
if (false == zebinSections.constDataSections.empty()) {
dst.globalConstants.initData = zebinSections.constDataSections[0]->data.begin();
dst.globalConstants.size = zebinSections.constDataSections[0]->data.size();
}
if (false == zebinSections.symtabSections.empty()) {
dst.prepareLinkerInputStorage();
auto expectedSymSize = sizeof(NEO::Elf::ElfSymbolEntry<Elf::EI_CLASS_64>);
auto gotSymSize = zebinSections.symtabSections[0]->header->entsize;
if (expectedSymSize != gotSymSize) {
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid symbol table entries size - expected : " + std::to_string(expectedSymSize) + ", got : " + std::to_string(gotSymSize) + "\n");
return DecodeError::InvalidBinary;
}
outWarning.append("DeviceBinaryFormat::Zebin : Ignoring symbol table\n");
}
if (zebinSections.zeInfoSections.empty()) {
outWarning.append("DeviceBinaryFormat::Zebin : Expected at least one " + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " section, got 0\n");
return DecodeError::Success;
}
auto metadataSectionData = zebinSections.zeInfoSections[0]->data;
ConstStringRef metadataString(reinterpret_cast<const char *>(metadataSectionData.begin()), metadataSectionData.size());
NEO::Yaml::YamlParser yamlParser;
bool parseSuccess = yamlParser.parse(metadataString, outErrReason, outWarning);
if (false == parseSuccess) {
return DecodeError::InvalidBinary;
}
if (yamlParser.empty()) {
outWarning.append("DeviceBinaryFormat::Zebin : Empty kernels metadata section (" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + ")\n");
return DecodeError::Success;
}
UniqueNode kernelsSectionNodes;
for (const auto &globalScopeNd : yamlParser.createChildrenRange(*yamlParser.getRoot())) {
auto key = yamlParser.readKey(globalScopeNd);
if (NEO::Elf::ZebinKernelMetadata::Tags::kernels == key) {
kernelsSectionNodes.push_back(&globalScopeNd);
continue;
}
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + yamlParser.readKey(globalScopeNd).str() + "\" in global scope of " + NEO::Elf::SectionsNamesZebin::zeInfo.str() + "\n");
}
if (kernelsSectionNodes.size() > 1U) {
outErrReason.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Expected at most one " + NEO::Elf::ZebinKernelMetadata::Tags::kernels.str() + " entry in global scope of " + NEO::Elf::SectionsNamesZebin::zeInfo.str() + ", got : " + std::to_string(kernelsSectionNodes.size()) + "\n");
return DecodeError::InvalidBinary;
}
if (kernelsSectionNodes.empty()) {
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Expected one " + NEO::Elf::ZebinKernelMetadata::Tags::kernels.str() + " entry in global scope of " + NEO::Elf::SectionsNamesZebin::zeInfo.str() + ", got : " + std::to_string(kernelsSectionNodes.size()) + "\n");
return DecodeError::Success;
}
for (const auto &kernelNd : yamlParser.createChildrenRange(*kernelsSectionNodes[0])) {
auto zeInfoErr = populateKernelDescriptor(dst, elf, zebinSections, yamlParser, kernelNd, outErrReason, outWarning);
if (DecodeError::Success != zeInfoErr) {
return zeInfoErr;
}
}
return DecodeError::Success;
}
} // namespace NEO

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/device_binary_format/device_binary_formats.h"
#include "shared/source/device_binary_format/elf/elf_decoder.h"
#include "shared/source/device_binary_format/elf/zebin_elf.h"
#include "shared/source/device_binary_format/yaml/yaml_parser.h"
#include "shared/source/kernel/kernel_descriptor.h"
#include "shared/source/utilities/stackvec.h"
#include <string>
namespace NEO {
struct ZebinSections {
using SectionHeaderData = NEO::Elf::Elf<Elf::EI_CLASS_64>::SectionHeaderAndData;
StackVec<SectionHeaderData *, 32> textKernelSections;
StackVec<SectionHeaderData *, 1> zeInfoSections;
StackVec<SectionHeaderData *, 1> globalDataSections;
StackVec<SectionHeaderData *, 1> constDataSections;
StackVec<SectionHeaderData *, 1> symtabSections;
StackVec<SectionHeaderData *, 1> spirvSections;
};
using UniqueNode = StackVec<const NEO::Yaml::Node *, 1>;
struct ZeInfoKernelSections {
UniqueNode nameNd;
UniqueNode executionEnvNd;
UniqueNode payloadArgumentsNd;
UniqueNode bindingTableIndicesNd;
UniqueNode perThreadPayloadArgumentsNd;
};
DecodeError extractZebinSections(NEO::Elf::Elf<Elf::EI_CLASS_64> &elf, ZebinSections &out, std::string &outErrReason, std::string &outWarning);
DecodeError validateZebinSectionsCount(const ZebinSections &sections, std::string &outErrReason, std::string &outWarning);
void extractZeInfoKernelSections(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &kernelNd, ZeInfoKernelSections &outZeInfoKernelSections, ConstStringRef context, std::string &outWarning);
DecodeError validateZeInfoKernelSectionsCount(const ZeInfoKernelSections &outZeInfoKernelSections, std::string &outErrReason, std::string &outWarning);
DecodeError readZeInfoExecutionEnvironment(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &node,
NEO::Elf::ZebinKernelMetadata::Types::Kernel::ExecutionEnv::ExecutionEnvBaseT &outExecEnv,
ConstStringRef context, std::string &outErrReason, std::string &outWarning);
bool readEnumChecked(const Yaml::Token *token, NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgType &out,
ConstStringRef context, std::string &outErrReason);
bool readEnumChecked(const Yaml::Token *token, NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::MemoryAddressingMode &out,
ConstStringRef context, std::string &outErrReason);
bool readEnumChecked(const Yaml::Token *token, NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AddressSpace &out,
ConstStringRef context, std::string &outErrReason);
bool readEnumChecked(const Yaml::Token *token, NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::AccessType &out,
ConstStringRef context, std::string &outErrReason);
using ZeInfoPerThreadPayloadArguments = StackVec<NEO::Elf::ZebinKernelMetadata::Types::Kernel::PerThreadPayloadArgument::PerThreadPayloadArgumentBaseT, 2>;
DecodeError readZeInfoPerThreadPayloadArguments(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &node,
ZeInfoPerThreadPayloadArguments &outPerThreadPayloadArguments,
ConstStringRef context,
std::string &outErrReason, std::string &outWarning);
using ZeInfoPayloadArguments = StackVec<NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::PayloadArgumentBaseT, 32>;
DecodeError readZeInfoPayloadArguments(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &node,
ZeInfoPayloadArguments &ouPayloadArguments,
uint32_t &outMaxPayloadArgumentIndex,
ConstStringRef context,
std::string &outErrReason, std::string &outWarning);
using ZeInfoBindingTableIndices = StackVec<NEO::Elf::ZebinKernelMetadata::Types::Kernel::BindingTableEntry::BindingTableEntryBaseT, 32>;
DecodeError readZeInfoBindingTableIndices(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &node,
ZeInfoBindingTableIndices &outBindingTableIndices, ZeInfoBindingTableIndices::value_type &outMaxBindingTableIndex,
ConstStringRef context,
std::string &outErrReason, std::string &outWarning);
NEO::DecodeError populateArgDescriptor(const NEO::Elf::ZebinKernelMetadata::Types::Kernel::PerThreadPayloadArgument::PerThreadPayloadArgumentBaseT &src, NEO::KernelDescriptor &dst,
std::string &outErrReason, std::string &outWarning);
NEO::DecodeError populateArgDescriptor(const NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::PayloadArgumentBaseT &src, NEO::KernelDescriptor &dst, uint32_t &crossThreadDataSize,
std::string &outErrReason, std::string &outWarning);
NEO::DecodeError populateKernelDescriptor(NEO::ProgramInfo &dst, NEO::Elf::Elf<NEO::Elf::EI_CLASS_64> &elf, NEO::ZebinSections &zebinSections,
NEO::Yaml::YamlParser &yamlParser, const NEO::Yaml::Node &kernelNd, std::string &outErrReason, std::string &outWarning);
} // namespace NEO