mirror of
https://github.com/intel/compute-runtime.git
synced 2025-12-27 15:53:13 +08:00
Zebin support
Change-Id: I1e426ee2c5174fd0a4c51c1644cda467c2b88881
This commit is contained in:
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
336
shared/source/device_binary_format/elf/zebin_elf.h
Normal file
336
shared/source/device_binary_format/elf/zebin_elf.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
834
shared/source/device_binary_format/zebin_decoder.cpp
Normal file
834
shared/source/device_binary_format/zebin_decoder.cpp
Normal 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 §ionsContainer, 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 §ionsContainer, 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 §ions, 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
|
||||
81
shared/source/device_binary_format/zebin_decoder.h
Normal file
81
shared/source/device_binary_format/zebin_decoder.h
Normal 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 §ions, 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
|
||||
Reference in New Issue
Block a user