diff --git a/Jenkinsfile b/Jenkinsfile index cfef97680a..b4507b6d1b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,5 @@ #!groovy dependenciesRevision='b44862a6724fe290b73ef3b4db9e02076384abef-1368' strategy='EQUAL' -allowedCD=253 +allowedCD=219 allowedF=11 diff --git a/core/compiler_interface/CMakeLists.txt b/core/compiler_interface/CMakeLists.txt index 9683554e95..70a8b60c92 100644 --- a/core/compiler_interface/CMakeLists.txt +++ b/core/compiler_interface/CMakeLists.txt @@ -13,6 +13,7 @@ set(NEO_COMPILER_INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/compiler_interface.inl ${CMAKE_CURRENT_SOURCE_DIR}/create_main.cpp ${CMAKE_CURRENT_SOURCE_DIR}/default_cache_config.h + ${CMAKE_CURRENT_SOURCE_DIR}/intermediate_representations.h ${CMAKE_CURRENT_SOURCE_DIR}/linker.h ${CMAKE_CURRENT_SOURCE_DIR}/linker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/compiler_options/compiler_options_base.h diff --git a/core/compiler_interface/compiler_interface.h b/core/compiler_interface/compiler_interface.h index afab9cc7e0..4529a1839a 100644 --- a/core/compiler_interface/compiler_interface.h +++ b/core/compiler_interface/compiler_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 Intel Corporation + * Copyright (C) 2017-2020 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -106,8 +106,9 @@ class CompilerInterface { CompilerInterface &operator=(CompilerInterface &&) = delete; virtual ~CompilerInterface(); - static CompilerInterface *createInstance(std::unique_ptr cache, bool requireFcl) { - auto instance = new CompilerInterface(); + template + static CompilerInterfaceT *createInstance(std::unique_ptr cache, bool requireFcl) { + auto instance = new CompilerInterfaceT(); if (!instance->initialize(std::move(cache), requireFcl)) { delete instance; instance = nullptr; @@ -137,7 +138,7 @@ class CompilerInterface { MOCKABLE_VIRTUAL TranslationOutput::ErrorCode getSipKernelBinary(NEO::Device &device, SipKernelType type, std::vector &retBinary); protected: - bool initialize(std::unique_ptr cache, bool requireFcl); + MOCKABLE_VIRTUAL bool initialize(std::unique_ptr cache, bool requireFcl); MOCKABLE_VIRTUAL bool loadFcl(); MOCKABLE_VIRTUAL bool loadIgc(); diff --git a/core/compiler_interface/intermediate_representations.h b/core/compiler_interface/intermediate_representations.h new file mode 100644 index 0000000000..30ab50ba37 --- /dev/null +++ b/core/compiler_interface/intermediate_representations.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019-2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "core/utilities/arrayref.h" +#include "core/utilities/const_stringref.h" + +#include +#include + +namespace NEO { + +static constexpr ConstStringRef llvmBcMagic = "BC\xc0\xde"; +static constexpr ConstStringRef spirvMagic = "\x07\x23\x02\x03"; +static constexpr ConstStringRef spirvMagicInv = "\x03\x02\x23\x07"; + +inline bool hasSameMagic(ConstStringRef expectedMagic, ArrayRef binary) { + auto binaryMagicLen = std::min(expectedMagic.size(), binary.size()); + ConstStringRef binaryMagic(reinterpret_cast(binary.begin()), binaryMagicLen); + return expectedMagic == binaryMagic; +} + +inline bool isLlvmBitcode(ArrayRef binary) { + return hasSameMagic(llvmBcMagic, binary); +} + +inline bool isSpirVBitcode(ArrayRef binary) { + return hasSameMagic(spirvMagic, binary) || hasSameMagic(spirvMagicInv, binary); +} + +} // namespace NEO diff --git a/core/device_binary_format/CMakeLists.txt b/core/device_binary_format/CMakeLists.txt index 0a78547bdf..9dffdc20ee 100644 --- a/core/device_binary_format/CMakeLists.txt +++ b/core/device_binary_format/CMakeLists.txt @@ -6,11 +6,22 @@ set(NEO_DEVICE_BINARY_FORMAT ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${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_formats.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/device_binary_formats.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.inl + ${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_validator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_validator.h + ${CMAKE_CURRENT_SOURCE_DIR}/elf/elf.h + ${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_decoder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_decoder.h + ${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_encoder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_encoder.h + ${CMAKE_CURRENT_SOURCE_DIR}/elf/ocl_elf.h ) set_property(GLOBAL PROPERTY NEO_DEVICE_BINARY_FORMAT ${NEO_DEVICE_BINARY_FORMAT}) diff --git a/core/device_binary_format/device_binary_format_ocl_elf.cpp b/core/device_binary_format/device_binary_format_ocl_elf.cpp new file mode 100644 index 0000000000..15c8297d65 --- /dev/null +++ b/core/device_binary_format/device_binary_format_ocl_elf.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "common/compiler_support.h" +#include "core/compiler_interface/intermediate_representations.h" +#include "core/device_binary_format/device_binary_formats.h" +#include "core/device_binary_format/elf/elf_decoder.h" +#include "core/device_binary_format/elf/elf_encoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" + +#include + +namespace NEO { + +template <> +bool isDeviceBinaryFormat(const ArrayRef binary) { + auto header = Elf::decodeElfFileHeader(binary); + if (nullptr == header) { + return false; + } + + switch (header->type) { + default: + return false; + case Elf::ET_OPENCL_EXECUTABLE: + CPP_ATTRIBUTE_FALLTHROUGH; + case Elf::ET_OPENCL_LIBRARY: + CPP_ATTRIBUTE_FALLTHROUGH; + case Elf::ET_OPENCL_OBJECTS: + return true; + } +} + +template <> +SingleDeviceBinary unpackSingleDeviceBinary(const ArrayRef archive, const ConstStringRef requestedProductAbbreviation, const TargetDevice requestedTargetDevice, + std::string &outErrReason, std::string &outWarning) { + auto elf = Elf::decodeElf(archive, outErrReason, outWarning); + if (nullptr == elf.elfFileHeader) { + return {}; + } + + SingleDeviceBinary ret; + switch (elf.elfFileHeader->type) { + default: + outErrReason = "Not OCL ELF file type"; + return {}; + + case Elf::ET_OPENCL_EXECUTABLE: + ret.format = NEO::DeviceBinaryFormat::Patchtokens; + break; + + case Elf::ET_OPENCL_LIBRARY: + ret.format = NEO::DeviceBinaryFormat::OclLibrary; + break; + + case Elf::ET_OPENCL_OBJECTS: + ret.format = NEO::DeviceBinaryFormat::OclCompiledObject; + break; + } + + for (auto &elfSectionHeader : elf.sectionHeaders) { + auto sectionData = elfSectionHeader.data; + switch (elfSectionHeader.header->type) { + case Elf::SHT_OPENCL_SPIRV: + CPP_ATTRIBUTE_FALLTHROUGH; + case Elf::SHT_OPENCL_LLVM_BINARY: + ret.intermediateRepresentation = sectionData; + break; + + case Elf::SHT_OPENCL_DEV_BINARY: + ret.deviceBinary = sectionData; + break; + + case Elf::SHT_OPENCL_OPTIONS: + ret.buildOptions = ConstStringRef(reinterpret_cast(sectionData.begin()), sectionData.size()); + break; + + case Elf::SHT_OPENCL_DEV_DEBUG: + ret.debugData = sectionData; + break; + + case Elf::SHT_STRTAB: + // ignoring intentionally - identifying sections by types + continue; + + case Elf::SHT_NULL: + // ignoring intentionally, inactive section, probably UNDEF + continue; + + default: + outErrReason = "Unhandled ELF section"; + return {}; + } + } + + if (NEO::DeviceBinaryFormat::Patchtokens != ret.format) { + ret.deviceBinary.clear(); + return ret; + } + + if (false == ret.deviceBinary.empty()) { + auto unpackedOclDevBin = unpackSingleDeviceBinary(ret.deviceBinary, requestedProductAbbreviation, requestedTargetDevice, + outErrReason, outWarning); + if (unpackedOclDevBin.deviceBinary.empty()) { + ret.deviceBinary.clear(); + ret.debugData.clear(); + } else { + ret.targetDevice = unpackedOclDevBin.targetDevice; + } + } + + return ret; +} + +template <> +DecodeError decodeSingleDeviceBinary(ProgramInfo &dst, const SingleDeviceBinary &src, std::string &outErrReason, std::string &outWarning) { + // packed binary format + outErrReason = "Device binary format is packed"; + return DecodeError::InvalidBinary; +} + +template <> +std::vector packDeviceBinary(const SingleDeviceBinary binary, std::string &outErrReason, std::string &outWarning) { + using namespace NEO::Elf; + NEO::Elf::ElfEncoder elfEncoder; + elfEncoder.getElfFileHeader().type = ET_OPENCL_EXECUTABLE; + if (binary.buildOptions.empty() == false) { + elfEncoder.appendSection(SHT_OPENCL_OPTIONS, SectionNamesOpenCl::buildOptions, + ArrayRef(reinterpret_cast(binary.buildOptions.data()), binary.buildOptions.size())); + } + + if (binary.intermediateRepresentation.empty() == false) { + if (NEO::isSpirVBitcode(binary.intermediateRepresentation)) { + elfEncoder.appendSection(SHT_OPENCL_SPIRV, SectionNamesOpenCl::spirvObject, binary.intermediateRepresentation); + } else if (NEO::isLlvmBitcode(binary.intermediateRepresentation)) { + elfEncoder.appendSection(SHT_OPENCL_LLVM_BINARY, SectionNamesOpenCl::llvmObject, binary.intermediateRepresentation); + } else { + outErrReason = "Unknown intermediate representation format"; + return {}; + } + } + + if (binary.debugData.empty() == false) { + elfEncoder.appendSection(SHT_OPENCL_DEV_DEBUG, SectionNamesOpenCl::deviceDebug, binary.debugData); + } + + if (binary.deviceBinary.empty() == false) { + elfEncoder.appendSection(SHT_OPENCL_DEV_BINARY, SectionNamesOpenCl::deviceBinary, binary.deviceBinary); + } + + return elfEncoder.encode(); +} + +} // namespace NEO diff --git a/core/device_binary_format/device_binary_format_patchtokens.cpp b/core/device_binary_format/device_binary_format_patchtokens.cpp new file mode 100644 index 0000000000..549c56f3f1 --- /dev/null +++ b/core/device_binary_format/device_binary_format_patchtokens.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "core/device_binary_format/device_binary_formats.h" +#include "core/device_binary_format/patchtokens_decoder.h" +#include "core/device_binary_format/patchtokens_dumper.h" +#include "core/device_binary_format/patchtokens_validator.h" +#include "core/helpers/debug_helpers.h" +#include "core/program/program_info_from_patchtokens.h" +#include "runtime/utilities/logger.h" + +namespace NEO { + +template <> +bool isDeviceBinaryFormat(const ArrayRef binary) { + return NEO::PatchTokenBinary::isValidPatchTokenBinary(binary); +} + +template <> +SingleDeviceBinary unpackSingleDeviceBinary(const ArrayRef archive, const ConstStringRef requestedProductAbbreviation, const TargetDevice requestedTargetDevice, + std::string &outErrReason, std::string &outWarning) { + auto programHeader = NEO::PatchTokenBinary::decodeProgramHeader(archive); + if (nullptr == programHeader) { + outErrReason = "Invalid program header"; + return {}; + } + bool validForTarget = (requestedTargetDevice.coreFamily == static_cast(programHeader->Device)); + validForTarget &= (requestedTargetDevice.maxPointerSizeInBytes >= programHeader->GPUPointerSizeInBytes); + validForTarget &= (iOpenCL::CURRENT_ICBE_VERSION == programHeader->Version); + if (false == validForTarget) { + outErrReason = "Unhandled target device"; + return {}; + } + SingleDeviceBinary ret = {}; + ret.targetDevice = requestedTargetDevice; + ret.format = NEO::DeviceBinaryFormat::Patchtokens; + ret.deviceBinary = archive; + return ret; +} + +template <> +DecodeError decodeSingleDeviceBinary(ProgramInfo &dst, const SingleDeviceBinary &src, std::string &outErrReason, std::string &outWarning) { + NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram = {}; + NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(src.deviceBinary, decodedProgram); + DBG_LOG(LogPatchTokens, NEO::PatchTokenBinary::asString(decodedProgram).c_str()); + + std::string validatorWarnings; + std::string validatorErrMessage; + auto validatorErr = PatchTokenBinary::validate(decodedProgram, outErrReason, outWarning); + if (DecodeError::Success != validatorErr) { + return validatorErr; + } + + NEO::populateProgramInfo(dst, decodedProgram); + + return DecodeError::Success; +} + +} // namespace NEO diff --git a/core/device_binary_format/device_binary_formats.cpp b/core/device_binary_format/device_binary_formats.cpp new file mode 100644 index 0000000000..5916a4f881 --- /dev/null +++ b/core/device_binary_format/device_binary_formats.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "core/device_binary_format/device_binary_formats.h" + +namespace NEO { + +std::vector packDeviceBinary(const SingleDeviceBinary binary, std::string &outErrReason, std::string &outWarning) { + return packDeviceBinary(binary, outErrReason, outWarning); +} + +} // namespace NEO diff --git a/core/device_binary_format/device_binary_formats.h b/core/device_binary_format/device_binary_formats.h new file mode 100644 index 0000000000..fc686c8dae --- /dev/null +++ b/core/device_binary_format/device_binary_formats.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "core/utilities/arrayref.h" +#include "core/utilities/const_stringref.h" + +#include +#include +#include +#include +#include + +namespace NEO { +struct ProgramInfo; + +enum class DeviceBinaryFormat : uint8_t { + Unknown, + OclElf, + OclLibrary, + OclCompiledObject, + Patchtokens +}; + +enum class DecodeError : uint8_t { + Success, + Undefined, + InvalidBinary, + UnhandledBinary +}; + +inline const char *asString(DecodeError err) { + switch (err) { + default: + return "with invalid binary"; + break; + case DecodeError::UnhandledBinary: + return "with unhandled binary"; + break; + case DecodeError::Success: + return "decoded successfully"; + break; + case DecodeError::Undefined: + return "in undefined status"; + break; + } +} + +struct TargetDevice { + GFXCORE_FAMILY coreFamily = IGFX_UNKNOWN_CORE; + uint32_t stepping = 0U; + uint32_t maxPointerSizeInBytes = 4U; +}; + +struct SingleDeviceBinary { + DeviceBinaryFormat format = DeviceBinaryFormat::Unknown; + ArrayRef deviceBinary; + ArrayRef debugData; + ArrayRef intermediateRepresentation; + ConstStringRef buildOptions; + TargetDevice targetDevice; +}; + +template +bool isDeviceBinaryFormat(const ArrayRef binary); + +template <> +bool isDeviceBinaryFormat(const ArrayRef); +template <> +bool isDeviceBinaryFormat(const ArrayRef); + +inline bool isAnyDeviceBinaryFormat(const ArrayRef binary) { + if (isDeviceBinaryFormat(binary)) { + return true; + } + if (isDeviceBinaryFormat(binary)) { + return true; + } + return false; +} + +template +SingleDeviceBinary unpackSingleDeviceBinary(const ArrayRef archive, const ConstStringRef requestedProductAbbreviation, const TargetDevice requestedTargetDevice, + std::string &outErrReason, std::string &outWarning); + +template <> +SingleDeviceBinary unpackSingleDeviceBinary(const ArrayRef, const ConstStringRef, const TargetDevice, std::string &, std::string &); +template <> +SingleDeviceBinary unpackSingleDeviceBinary(const ArrayRef, const ConstStringRef, const TargetDevice, std::string &, std::string &); + +inline SingleDeviceBinary unpackSingleDeviceBinary(const ArrayRef archive, const ConstStringRef requestedProductAbbreviation, const TargetDevice requestedTargetDevice, + std::string &outErrReason, std::string &outWarning) { + SingleDeviceBinary ret = {}; + ret.format = DeviceBinaryFormat::Unknown; + if (isDeviceBinaryFormat(archive)) { + return unpackSingleDeviceBinary(archive, requestedProductAbbreviation, requestedTargetDevice, outErrReason, outWarning); + } else if (isDeviceBinaryFormat(archive)) { + return unpackSingleDeviceBinary(archive, requestedProductAbbreviation, requestedTargetDevice, outErrReason, outWarning); + } else { + outErrReason = "Unknown format"; + } + return ret; +} + +template +std::vector packDeviceBinary(const SingleDeviceBinary binary, std::string &outErrReason, std::string &outWarning); + +template <> +std::vector packDeviceBinary(const SingleDeviceBinary, std::string &, std::string &); + +std::vector packDeviceBinary(const SingleDeviceBinary binary, std::string &outErrReason, std::string &outWarning); + +inline bool isAnyPackedDeviceBinaryFormat(const ArrayRef binary) { + if (isDeviceBinaryFormat(binary)) { + return true; + } + return false; +} + +inline bool isAnySingleDeviceBinaryFormat(const ArrayRef binary) { + return (false == isAnyPackedDeviceBinaryFormat(binary)) && isAnyDeviceBinaryFormat(binary); +} + +template +DecodeError decodeSingleDeviceBinary(ProgramInfo &dst, const SingleDeviceBinary &src, std::string &outErrReason, std::string &outWarning); + +template <> +DecodeError decodeSingleDeviceBinary(ProgramInfo &, const SingleDeviceBinary &, std::string &, std::string &); +template <> +DecodeError decodeSingleDeviceBinary(ProgramInfo &, const SingleDeviceBinary &, std::string &, std::string &); + +inline std::pair decodeSingleDeviceBinary(ProgramInfo &dst, const SingleDeviceBinary &src, std::string &outErrReason, std::string &outWarning) { + std::pair ret; + ret.first = DecodeError::InvalidBinary; + ret.second = DeviceBinaryFormat::Unknown; + if (isDeviceBinaryFormat(src.deviceBinary)) { + ret.second = DeviceBinaryFormat::OclElf; + ret.first = decodeSingleDeviceBinary(dst, src, outErrReason, outWarning); + } else if (isDeviceBinaryFormat(src.deviceBinary)) { + ret.second = DeviceBinaryFormat::Patchtokens; + ret.first = decodeSingleDeviceBinary(dst, src, outErrReason, outWarning); + } else { + outErrReason = "Unknown format"; + } + return ret; +} + +} // namespace NEO diff --git a/core/device_binary_format/elf/elf.h b/core/device_binary_format/elf/elf.h new file mode 100644 index 0000000000..91b77b0faa --- /dev/null +++ b/core/device_binary_format/elf/elf.h @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2017-2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +// Abstract: Defines the types used for ELF headers/sections. +#pragma once + +#include "core/utilities/const_stringref.h" + +#include +#include + +namespace NEO { + +namespace Elf { + +// Elf identifier class +enum ELF_IDENTIFIER_CLASS : uint8_t { + EI_CLASS_NONE = 0, // undefined + EI_CLASS_32 = 1, // 32-bit elf file + EI_CLASS_64 = 2, // 64-bit elf file +}; + +// Elf identifier data +enum ELF_IDENTIFIER_DATA : uint8_t { + EI_DATA_NONE = 0, // undefined + EI_DATA_LITTLE_ENDIAN = 1, // little-endian + EI_DATA_BIG_ENDIAN = 2, // big-endian +}; + +// Target machine +enum ELF_MACHINE : uint16_t { + EM_NONE = 0, // No specific instrution set +}; + +// Elf version +enum ELF_VERSION_ : uint8_t { + EV_INVALID = 0, // undefined + EV_CURRENT = 1, // current +}; + +// Elf type +enum ELF_TYPE : uint16_t { + ET_NONE = 0, // undefined + ET_REL = 1, // relocatable + ET_EXEC = 2, // executable + ET_DYN = 3, // shared object + ET_CORE = 4, // core file + ET_LOPROC = 0xff00, // start of processor-specific type + ET_OPENCL_RESERVED_START = 0xff01, // start of Intel OCL ELF_TYPES + ET_OPENCL_RESERVED_END = 0xff05, // end of Intel OCL ELF_TYPES + ET_HIPROC = 0xffff // end of processor-specific types +}; + +// Section header type +enum SECTION_HEADER_TYPE : uint32_t { + SHT_NULL = 0, // inactive section header + SHT_PROGBITS = 1, // program data + SHT_SYMTAB = 2, // symbol table + SHT_STRTAB = 3, // string table + SHT_RELA = 4, // relocation entries with add + SHT_HASH = 5, // symbol hash table + SHT_DYNAMIC = 6, // dynamic linking info + SHT_NOTE = 7, // notes + SHT_NOBITS = 8, // program "no data" space (bss) + SHT_REL = 9, // relocation entries (without add) + SHT_SHLIB = 10, // reserved + SHT_DYNSYM = 11, // dynamic linker symbol table + SHT_INIT_ARRAY = 14, // array of constructors + SHT_FINI_ARRAY = 15, // array of destructors + SHT_PREINIT_ARRAY = 16, // aaray of pre-constructors + SHT_GROUP = 17, // section group + SHT_SYMTAB_SHNDX = 18, // extended section indices + SHT_NUM = 19, // number of defined types + SHT_LOOS = 0x60000000, // start of os-specifc + SHT_OPENCL_RESERVED_START = 0xff000000, // start of Intel OCL SHT_TYPES + SHT_OPENCL_RESERVED_END = 0xff00000a // end of Intel OCL SHT_TYPES +}; + +enum SPECIAL_SECTION_HEADER_NUMBER : uint16_t { + SHN_UNDEF = 0U, // undef section +}; + +enum SECTION_HEADER_FLAGS : uint32_t { + SHF_NONE = 0x0, // no flags + SHF_WRITE = 0x1, // writeable data + SHF_ALLOC = 0x2, // occupies memory during execution + SHF_EXECINSTR = 0x4, // executable machine instructions + SHF_MERGE = 0x10, // data of section can be merged + SHF_STRINGS = 0x20, // data of section is null-terminated strings + SHF_INFO_LINK = 0x40, // section's sh_info is valid index + SHF_LINK_ORDER = 0x80, // has ordering requirements + SHF_OS_NONCONFORM = 0x100, // requires os-specific processing + SHF_GROUP = 0x200, // section is part of section group + SHF_TLS = 0x400, // thread-local storage + SHF_MASKOS = 0x0ff00000, // operating-system-specific flags + SHF_MASKPROC = 0xf0000000, // processor-specific flags +}; + +enum PROGRAM_HEADER_TYPE { + PT_NULL = 0x0, // unused segment + PT_LOAD = 0x1, // loadable segment + PT_DYNAMIC = 0x2, // dynamic linking information + PT_INTERP = 0x3, // path name to invoke as an interpreter + PT_NOTE = 0x4, // auxiliary information + PT_SHLIB = 0x5, // reserved + PT_PHDR = 0x6, // location and of programe header table + PT_TLS = 0x7, // thread-local storage template + PT_LOOS = 0x60000000, // start os-specifc segments + PT_HIOS = 0x6FFFFFFF, // end of os-specific segments + PT_LOPROC = 0x70000000, // start processor-specific segments + PT_HIPROC = 0x7FFFFFFF // end processor-specific segments +}; + +enum PROGRAM_HEADER_FLAGS : uint32_t { + PF_NONE = 0x0, // all access denied + PF_X = 0x1, // execute + PF_W = 0x2, // write + PF_R = 0x4, // read + PF_MASKOS = 0x0ff00000, // operating-system-specific flags + PF_MASKPROC = 0xf0000000 // processor-specific flags + +}; + +constexpr const char elfMagic[4] = {0x7f, 'E', 'L', 'F'}; + +struct ElfFileHeaderIdentity { + ElfFileHeaderIdentity(ELF_IDENTIFIER_CLASS classBits) + : eClass(classBits) { + } + char magic[4] = {elfMagic[0], elfMagic[1], elfMagic[2], elfMagic[3]}; // should match elfMagic + uint8_t eClass = EI_CLASS_NONE; // 32- or 64-bit format + uint8_t data = EI_DATA_LITTLE_ENDIAN; // endianness + uint8_t version = EV_CURRENT; // elf file version + uint8_t osAbi = 0U; // target system + uint8_t abiVersion = 0U; // abi + char padding[7] = {}; // pad to 16 bytes +}; +static_assert(sizeof(ElfFileHeaderIdentity) == 16, ""); + +template +struct ElfProgramHeaderTypes; + +template <> +struct ElfProgramHeaderTypes { + using Type = uint32_t; + using Flags = uint32_t; + using Offset = uint32_t; + using VAddr = uint32_t; + using PAddr = uint32_t; + using FileSz = uint32_t; + using MemSz = uint32_t; + using Align = uint32_t; +}; + +template <> +struct ElfProgramHeaderTypes { + using Type = uint32_t; + using Flags = uint32_t; + using Offset = uint64_t; + using VAddr = uint64_t; + using PAddr = uint64_t; + using FileSz = uint64_t; + using MemSz = uint64_t; + using Align = uint64_t; +}; + +template +struct ElfProgramHeader; + +template <> +struct ElfProgramHeader { + ElfProgramHeaderTypes::Type type = PT_NULL; // type of segment + ElfProgramHeaderTypes::Offset offset = 0U; // absolute offset of segment data in file + ElfProgramHeaderTypes::VAddr vAddr = 0U; // VA of segment in memory + ElfProgramHeaderTypes::PAddr pAddr = 0U; // PA of segment in memory + ElfProgramHeaderTypes::FileSz fileSz = 0U; // size of segment in file + ElfProgramHeaderTypes::MemSz memSz = 0U; // size of segment in memory + ElfProgramHeaderTypes::Flags flags = PF_NONE; // segment-dependent flags + ElfProgramHeaderTypes::Align align = 1U; // alignment +}; + +template <> +struct ElfProgramHeader { + ElfProgramHeaderTypes::Type type = PT_NULL; // type of segment + ElfProgramHeaderTypes::Flags flags = PF_NONE; // segment-dependent flags + ElfProgramHeaderTypes::Offset offset = 0U; // absolute offset of segment data in file + ElfProgramHeaderTypes::VAddr vAddr = 0U; // VA of segment in memory + ElfProgramHeaderTypes::PAddr pAddr = 0U; // PA of segment in memory + ElfProgramHeaderTypes::FileSz fileSz = 0U; // size of segment in file + ElfProgramHeaderTypes::MemSz memSz = 0U; // size of segment in memory + ElfProgramHeaderTypes::Align align = 1U; // alignment +}; + +static_assert(sizeof(ElfProgramHeader) == 0x20, ""); +static_assert(sizeof(ElfProgramHeader) == 0x38, ""); + +template +struct ElfSectionHeaderTypes; + +template <> +struct ElfSectionHeaderTypes { + using Name = uint32_t; + using Type = uint32_t; + using Flags = uint32_t; + using Addr = uint32_t; + using Offset = uint32_t; + using Size = uint32_t; + using Link = uint32_t; + using Info = uint32_t; + using AddrAlign = uint32_t; + using EntSize = uint32_t; +}; + +template <> +struct ElfSectionHeaderTypes { + using Name = uint32_t; + using Type = uint32_t; + using Flags = uint64_t; + using Addr = uint64_t; + using Offset = uint64_t; + using Size = uint64_t; + using Link = uint32_t; + using Info = uint32_t; + using AddrAlign = uint64_t; + using EntSize = uint64_t; +}; + +template +struct ElfSectionHeader { + typename ElfSectionHeaderTypes::Name name = 0U; // offset to string in string section names + typename ElfSectionHeaderTypes::Type type = SHT_NULL; // section type + typename ElfSectionHeaderTypes::Flags flags = SHF_NONE; // section flags + typename ElfSectionHeaderTypes::Addr addr = 0U; // VA of section in memory + typename ElfSectionHeaderTypes::Offset offset = 0U; // absolute offset of section data in file + typename ElfSectionHeaderTypes::Size size = 0U; // size of section's data + typename ElfSectionHeaderTypes::Link link = SHN_UNDEF; // index of associated section + typename ElfSectionHeaderTypes::Info info = 0U; // extra information + typename ElfSectionHeaderTypes::AddrAlign addralign = 0U; // section alignment + typename ElfSectionHeaderTypes::EntSize entsize = 0U; // section's entries size +}; + +static_assert(sizeof(ElfSectionHeader) == 0x28, ""); +static_assert(sizeof(ElfSectionHeader) == 0x40, ""); + +template +struct ElfFileHeaderTypes; + +template <> +struct ElfFileHeaderTypes { + using Type = uint16_t; + using Machine = uint16_t; + using Version = uint32_t; + using Entry = uint32_t; + using PhOff = uint32_t; + using ShOff = uint32_t; + using Flags = uint32_t; + using EhSize = uint16_t; + using PhEntSize = uint16_t; + using PhNum = uint16_t; + using ShEntSize = uint16_t; + using ShNum = uint16_t; + using ShStrNdx = uint16_t; +}; + +template <> +struct ElfFileHeaderTypes { + using Type = uint16_t; + using Machine = uint16_t; + using Version = uint32_t; + using Entry = uint64_t; + using PhOff = uint64_t; + using ShOff = uint64_t; + using Flags = uint32_t; + using EhSize = uint16_t; + using PhEntSize = uint16_t; + using PhNum = uint16_t; + using ShEntSize = uint16_t; + using ShNum = uint16_t; + using ShStrNdx = uint16_t; +}; + +template +struct ElfFileHeader { + ElfFileHeaderIdentity identity = ElfFileHeaderIdentity(NumBits); // elf file identity + typename ElfFileHeaderTypes::Type type = ET_NONE; // elf file type + typename ElfFileHeaderTypes::Machine machine = EM_NONE; // target machine + typename ElfFileHeaderTypes::Version version = 1U; // elf file version + typename ElfFileHeaderTypes::Entry entry = 0U; // entry point (start address) + typename ElfFileHeaderTypes::PhOff phOff = 0U; // absolute offset to program header table in file + typename ElfFileHeaderTypes::ShOff shOff = 0U; // absolute offset to section header table in file + typename ElfFileHeaderTypes::Flags flags = 0U; // target-dependent flags + typename ElfFileHeaderTypes::EhSize ehSize = sizeof(ElfFileHeader); // header size + typename ElfFileHeaderTypes::PhEntSize phEntSize = sizeof(ElfProgramHeader); // size of entries in program header table + typename ElfFileHeaderTypes::PhNum phNum = 0U; // number of entries in pogram header table + typename ElfFileHeaderTypes::ShEntSize shEntSize = sizeof(ElfSectionHeader); // size of entries section header table + typename ElfFileHeaderTypes::ShNum shNum = 0U; // number of entries in section header table + typename ElfFileHeaderTypes::ShStrNdx shStrNdx = SHN_UNDEF; // index of section header table with section names +}; + +static_assert(sizeof(ElfFileHeader) == 0x34, ""); +static_assert(sizeof(ElfFileHeader) == 0x40, ""); + +namespace SpecialSectionNames { +static constexpr ConstStringRef bss = ".bss"; // uninitialized memory +static constexpr ConstStringRef comment = ".comment"; // version control information +static constexpr ConstStringRef data = ".data"; // initialized memory +static constexpr ConstStringRef data1 = ".data1"; // initialized memory +static constexpr ConstStringRef debug = ".debug"; // debug symbols +static constexpr ConstStringRef dynamic = ".dynamic"; // dynamic linking information +static constexpr ConstStringRef dynstr = ".dynstr"; // strings for dynamic linking +static constexpr ConstStringRef dynsym = ".dynsym"; // dynamic linking symbol table +static constexpr ConstStringRef fini = ".fini"; // executable instructions of program termination +static constexpr ConstStringRef finiArray = ".fini_array"; // function pointers of termination array +static constexpr ConstStringRef got = ".got"; // global offset table +static constexpr ConstStringRef hash = ".hash"; // symnol hash table +static constexpr ConstStringRef init = ".init"; // executable instructions of program initializaion +static constexpr ConstStringRef initArray = ".init_array"; // function pointers of initialization array +static constexpr ConstStringRef interp = ".interp"; // path name of program interpreter +static constexpr ConstStringRef line = ".line"; // line number info for symbolic debugging +static constexpr ConstStringRef note = ".note"; // note section +static constexpr ConstStringRef plt = ".plt"; // procedure linkage table +static constexpr ConstStringRef preinitArray = ".preinit_array"; // function pointers of pre-initialization array +static constexpr ConstStringRef relPrefix = ".rel"; // prefix of .relNAME - relocations for NAME section +static constexpr ConstStringRef relaPrefix = ".rela"; // prefix of .relaNAME - rela relocations for NAME section +static constexpr ConstStringRef rodata = ".rodata"; // read-only data +static constexpr ConstStringRef rodata1 = ".rodata1"; // read-only data +static constexpr ConstStringRef shStrTab = ".shstrtab"; // section names (strings) +static constexpr ConstStringRef strtab = ".strtab"; // strings +static constexpr ConstStringRef symtab = ".symtab"; // symbol table +static constexpr ConstStringRef symtabShndx = ".symtab_shndx"; // special symbol table section index array +static constexpr ConstStringRef tbss = ".tbss"; // uninitialized thread-local data +static constexpr ConstStringRef tadata = ".tdata"; // initialided thread-local data +static constexpr ConstStringRef tdata1 = ".tdata1"; // initialided thread-local data +static constexpr ConstStringRef text = ".text"; // executable instructions +} // namespace SpecialSectionNames + +} // namespace Elf + +} // namespace NEO diff --git a/core/device_binary_format/elf/elf_decoder.cpp b/core/device_binary_format/elf/elf_decoder.cpp new file mode 100644 index 0000000000..71e9542f23 --- /dev/null +++ b/core/device_binary_format/elf/elf_decoder.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "core/device_binary_format/elf/elf_decoder.h" + +#include "core/helpers/ptr_math.h" + +#include + +namespace NEO { + +namespace Elf { + +template +const ElfFileHeader *decodeElfFileHeader(const ArrayRef binary) { + if (binary.size() < sizeof(ElfFileHeader)) { + return nullptr; + } + + const ElfFileHeader *header = reinterpret_cast *>(binary.begin()); + bool validHeader = (header->identity.magic[0] == elfMagic[0]); + validHeader &= (header->identity.magic[1] == elfMagic[1]); + validHeader &= (header->identity.magic[2] == elfMagic[2]); + validHeader &= (header->identity.magic[3] == elfMagic[3]); + validHeader &= (header->identity.eClass == NumBits); + + return validHeader ? header : nullptr; +} + +template const ElfFileHeader *decodeElfFileHeader(const ArrayRef); +template const ElfFileHeader *decodeElfFileHeader(const ArrayRef); + +template +Elf decodeElf(const ArrayRef binary, std::string &outErrReason, std::string &outWarning) { + Elf ret = {}; + ret.elfFileHeader = decodeElfFileHeader(binary); + if (nullptr == ret.elfFileHeader) { + outErrReason = "Invalid or missing ELF header"; + return {}; + } + + if (ret.elfFileHeader->phOff + ret.elfFileHeader->phNum * ret.elfFileHeader->phEntSize > binary.size()) { + outErrReason = "Out of bounds program headers table"; + return {}; + } + + if (ret.elfFileHeader->shOff + ret.elfFileHeader->shNum * ret.elfFileHeader->shEntSize > binary.size()) { + outErrReason = "Out of bounds section headers table"; + return {}; + } + + const ElfProgramHeader *programHeader = reinterpret_cast *>(binary.begin() + ret.elfFileHeader->phOff); + for (decltype(ret.elfFileHeader->phNum) i = 0; i < ret.elfFileHeader->phNum; ++i) { + if (programHeader->offset + programHeader->fileSz > binary.size()) { + outErrReason = "Out of bounds program header offset/filesz, program header idx : " + std::to_string(i); + return {}; + } + ArrayRef data(binary.begin() + programHeader->offset, static_cast(programHeader->fileSz)); + ret.programHeaders.push_back({programHeader, data}); + programHeader = ptrOffset(programHeader, ret.elfFileHeader->phEntSize); + } + + const ElfSectionHeader *sectionHeader = reinterpret_cast *>(binary.begin() + ret.elfFileHeader->shOff); + for (decltype(ret.elfFileHeader->shNum) i = 0; i < ret.elfFileHeader->shNum; ++i) { + ArrayRef data; + if (SHT_NOBITS != sectionHeader->type) { + if (sectionHeader->offset + sectionHeader->size > binary.size()) { + outErrReason = "Out of bounds section header offset/size, section header idx : " + std::to_string(i); + return {}; + } + data = ArrayRef(binary.begin() + sectionHeader->offset, static_cast(sectionHeader->size)); + } + ret.sectionHeaders.push_back({sectionHeader, data}); + sectionHeader = ptrOffset(sectionHeader, ret.elfFileHeader->shEntSize); + } + + return ret; +} + +template Elf decodeElf(const ArrayRef, std::string &, std::string &); +template Elf decodeElf(const ArrayRef, std::string &, std::string &); + +} // namespace Elf + +} // namespace NEO diff --git a/core/device_binary_format/elf/elf_decoder.h b/core/device_binary_format/elf/elf_decoder.h new file mode 100644 index 0000000000..b517cd1d04 --- /dev/null +++ b/core/device_binary_format/elf/elf_decoder.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "core/device_binary_format/elf/elf.h" +#include "core/utilities/arrayref.h" +#include "core/utilities/const_stringref.h" +#include "core/utilities/stackvec.h" + +#include + +namespace NEO { + +namespace Elf { + +template +struct Elf { + struct ProgramHeaderAndData { + const ElfProgramHeader *header = nullptr; + ArrayRef data; + }; + + struct SectionHeaderAndData { + const ElfSectionHeader *header; + ArrayRef data; + }; + + const ElfFileHeader *elfFileHeader = nullptr; + StackVec programHeaders; + StackVec sectionHeaders; +}; + +template +const ElfFileHeader *decodeElfFileHeader(const ArrayRef binary); +extern template const ElfFileHeader *decodeElfFileHeader(const ArrayRef); +extern template const ElfFileHeader *decodeElfFileHeader(const ArrayRef); + +template +Elf decodeElf(const ArrayRef binary, std::string &outErrReason, std::string &outWarning); +extern template Elf decodeElf(const ArrayRef, std::string &, std::string &); +extern template Elf decodeElf(const ArrayRef, std::string &, std::string &); + +template +inline bool isElf(const ArrayRef binary) { + return (nullptr != decodeElfFileHeader(binary)); +} + +inline bool isElf(const ArrayRef binary) { + return isElf(binary) || isElf(binary); +} + +inline ELF_IDENTIFIER_CLASS getElfNumBits(const ArrayRef binary) { + if (isElf(binary)) { + return EI_CLASS_32; + } else if (isElf(binary)) { + return EI_CLASS_64; + } + return EI_CLASS_NONE; +} + +} // namespace Elf + +} // namespace NEO diff --git a/core/device_binary_format/elf/elf_encoder.cpp b/core/device_binary_format/elf/elf_encoder.cpp new file mode 100644 index 0000000000..391851d008 --- /dev/null +++ b/core/device_binary_format/elf/elf_encoder.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "core/device_binary_format/elf/elf_encoder.h" + +#include "core/utilities/range.h" + +#include + +namespace NEO { + +namespace Elf { + +template +ElfEncoder::ElfEncoder(bool addUndefSectionHeader, bool addHeaderSectionNamesSection, uint64_t defaultDataAlignemnt) + : addUndefSectionHeader(addUndefSectionHeader), addHeaderSectionNamesSection(addHeaderSectionNamesSection), defaultDataAlignment(defaultDataAlignemnt) { + // add special strings + UNRECOVERABLE_IF(defaultDataAlignment == 0); + stringTable.push_back('\0'); + specialStringsOffsets.undef = 0U; + specialStringsOffsets.shStrTab = this->appendSectionName(SpecialSectionNames::shStrTab); + + if (addUndefSectionHeader) { + ElfSectionHeader undefSection; + sectionHeaders.push_back(undefSection); + } +} + +template +void ElfEncoder::appendSection(const ElfSectionHeader §ionHeader, const ArrayRef sectionData) { + sectionHeaders.push_back(sectionHeader); + if ((SHT_NOBITS != sectionHeader.type) && (false == sectionData.empty())) { + auto sectionDataAlignment = std::min(defaultDataAlignment, 8U); + auto alignedOffset = alignUp(this->data.size(), static_cast(sectionDataAlignment)); + auto alignedSize = alignUp(sectionData.size(), static_cast(sectionDataAlignment)); + this->data.reserve(alignedOffset + alignedSize); + this->data.resize(alignedOffset, 0U); + this->data.insert(this->data.end(), sectionData.begin(), sectionData.end()); + this->data.resize(alignedOffset + alignedSize, 0U); + sectionHeaders.rbegin()->offset = static_castoffset)>(alignedOffset); + sectionHeaders.rbegin()->size = static_castsize)>(sectionData.size()); + } +} + +template +void ElfEncoder::appendSegment(const ElfProgramHeader &programHeader, const ArrayRef segmentData) { + maxDataAlignmentNeeded = std::max(maxDataAlignmentNeeded, static_cast(programHeader.align)); + programHeaders.push_back(programHeader); + if (false == segmentData.empty()) { + UNRECOVERABLE_IF(programHeader.align == 0); + auto alignedOffset = alignUp(this->data.size(), static_cast(programHeader.align)); + auto alignedSize = alignUp(segmentData.size(), static_cast(programHeader.align)); + this->data.reserve(alignedOffset + alignedSize); + this->data.resize(alignedOffset, 0U); + this->data.insert(this->data.end(), segmentData.begin(), segmentData.end()); + this->data.resize(alignedOffset + alignedSize, 0U); + programHeaders.rbegin()->offset = static_castoffset)>(alignedOffset); + programHeaders.rbegin()->fileSz = static_castfileSz)>(segmentData.size()); + } +} + +template +ElfSectionHeader &ElfEncoder::appendSection(SECTION_HEADER_TYPE sectionType, ConstStringRef sectionLabel, const ArrayRef sectionData) { + ElfSectionHeader section = {}; + section.type = static_cast(sectionType); + section.flags = static_cast(SHF_NONE); + section.offset = 0U; + section.name = appendSectionName(sectionLabel); + section.addralign = 8U; + appendSection(section, sectionData); + return *sectionHeaders.rbegin(); +} + +template +ElfProgramHeader &ElfEncoder::appendSegment(PROGRAM_HEADER_TYPE segmentType, const ArrayRef segmentData) { + ElfProgramHeader segment = {}; + segment.type = static_cast(segmentType); + segment.flags = static_cast(PF_NONE); + segment.offset = 0U; + segment.align = static_cast(defaultDataAlignment); + appendSegment(segment, segmentData); + return *programHeaders.rbegin(); +} + +template +uint32_t ElfEncoder::appendSectionName(ConstStringRef str) { + if (str.empty() || (false == addHeaderSectionNamesSection)) { + return specialStringsOffsets.undef; + } + uint32_t offset = static_cast(stringTable.size()); + stringTable.insert(stringTable.end(), str.begin(), str.end()); + if (str[str.size() - 1] != '\0') { + stringTable.push_back('\0'); + } + return offset; +} + +template +std::vector ElfEncoder::encode() const { + ElfFileHeader elfFileHeader = this->elfFileHeader; + StackVec, 32> programHeaders = this->programHeaders; + StackVec, 32> sectionHeaders = this->sectionHeaders; + + if (addUndefSectionHeader && (1U == sectionHeaders.size())) { + sectionHeaders.clear(); + } + + ElfSectionHeader sectionHeaderNamesSection; + size_t alignedSectionNamesDataSize = 0U; + size_t dataPaddingBeforeSectionNames = 0U; + if ((false == sectionHeaders.empty()) && addHeaderSectionNamesSection) { + auto alignedDataSize = alignUp(data.size(), static_cast(defaultDataAlignment)); + dataPaddingBeforeSectionNames = alignedDataSize - data.size(); + sectionHeaderNamesSection.type = SHT_STRTAB; + sectionHeaderNamesSection.name = specialStringsOffsets.shStrTab; + sectionHeaderNamesSection.offset = static_cast(alignedDataSize); + sectionHeaderNamesSection.size = static_cast(stringTable.size()); + sectionHeaderNamesSection.addralign = static_cast(defaultDataAlignment); + elfFileHeader.shStrNdx = static_cast(sectionHeaders.size()); + sectionHeaders.push_back(sectionHeaderNamesSection); + alignedSectionNamesDataSize = alignUp(stringTable.size(), static_cast(sectionHeaderNamesSection.addralign)); + } + + elfFileHeader.phNum = static_cast(programHeaders.size()); + elfFileHeader.shNum = static_cast(sectionHeaders.size()); + + auto programHeadersOffset = elfFileHeader.ehSize; + auto sectionHeadersOffset = programHeadersOffset + elfFileHeader.phEntSize * elfFileHeader.phNum; + + if (false == programHeaders.empty()) { + elfFileHeader.phOff = static_cast(programHeadersOffset); + } + if (false == sectionHeaders.empty()) { + elfFileHeader.shOff = static_cast(sectionHeadersOffset); + } + + auto dataOffset = alignUp(sectionHeadersOffset + elfFileHeader.shEntSize * elfFileHeader.shNum, static_cast(maxDataAlignmentNeeded)); + auto stringTabOffset = dataOffset + data.size(); + + std::vector ret; + ret.reserve(stringTabOffset + alignedSectionNamesDataSize); + ret.insert(ret.end(), reinterpret_cast(&elfFileHeader), reinterpret_cast(&elfFileHeader + 1)); + ret.resize(programHeadersOffset, 0U); + + for (auto &programHeader : programHeaders) { + if (0 != programHeader.fileSz) { + programHeader.offset = static_cast(programHeader.offset + dataOffset); + } + ret.insert(ret.end(), reinterpret_cast(&programHeader), reinterpret_cast(&programHeader + 1)); + ret.resize(ret.size() + elfFileHeader.phEntSize - sizeof(programHeader), 0U); + } + + for (auto §ionHeader : sectionHeaders) { + if ((SHT_NOBITS != sectionHeader.type) && (0 != sectionHeader.size)) { + sectionHeader.offset = static_cast(sectionHeader.offset + dataOffset); + } + ret.insert(ret.end(), reinterpret_cast(§ionHeader), reinterpret_cast(§ionHeader + 1)); + ret.resize(ret.size() + elfFileHeader.shEntSize - sizeof(sectionHeader), 0U); + } + + ret.resize(dataOffset, 0U); + ret.insert(ret.end(), data.begin(), data.end()); + ret.resize(ret.size() + dataPaddingBeforeSectionNames, 0U); + ret.insert(ret.end(), reinterpret_cast(stringTable.data()), reinterpret_cast(stringTable.data() + static_cast(sectionHeaderNamesSection.size))); + ret.resize(ret.size() + alignedSectionNamesDataSize - static_cast(sectionHeaderNamesSection.size), 0U); + return ret; +} + +template struct ElfEncoder; +template struct ElfEncoder; + +} // namespace Elf + +} // namespace NEO diff --git a/core/device_binary_format/elf/elf_encoder.h b/core/device_binary_format/elf/elf_encoder.h new file mode 100644 index 0000000000..7aaf7f1ed5 --- /dev/null +++ b/core/device_binary_format/elf/elf_encoder.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "core/device_binary_format/elf/elf.h" +#include "core/helpers/aligned_memory.h" +#include "core/utilities/arrayref.h" +#include "core/utilities/const_stringref.h" +#include "core/utilities/stackvec.h" + +#include +#include + +namespace NEO { + +namespace Elf { + +template +struct ElfEncoder { + ElfEncoder(bool addUndefSectionHeader = true, bool addHeaderSectionNamesSection = true, uint64_t defaultDataAlignment = 8U); + + void appendSection(const ElfSectionHeader §ionHeader, const ArrayRef sectionData); + void appendSegment(const ElfProgramHeader &programHeader, const ArrayRef segmentData); + + ElfSectionHeader &appendSection(SECTION_HEADER_TYPE sectionType, ConstStringRef sectionLabel, const ArrayRef sectionData); + ElfProgramHeader &appendSegment(PROGRAM_HEADER_TYPE segmentType, const ArrayRef segmentData); + + template + ElfSectionHeader &appendSection(SectionHeaderEnumT sectionType, ConstStringRef sectionLabel, const ArrayRef sectionData) { + return appendSection(static_cast(sectionType), sectionLabel, sectionData); + } + + template + ElfSectionHeader &appendSection(SectionHeaderEnumT sectionType, ConstStringRef sectionLabel, const std::string §ionData) { + return appendSection(static_cast(sectionType), sectionLabel, + ArrayRef(reinterpret_cast(sectionData.c_str()), sectionData.size() + 1)); + } + + uint32_t appendSectionName(ConstStringRef str); + + std::vector encode() const; + + ElfFileHeader &getElfFileHeader() { + return elfFileHeader; + } + + protected: + bool addUndefSectionHeader = false; + bool addHeaderSectionNamesSection = false; + uint64_t defaultDataAlignment = 8U; + uint64_t maxDataAlignmentNeeded = 1U; + ElfFileHeader elfFileHeader; + StackVec, 32> programHeaders; + StackVec, 32> sectionHeaders; + std::vector data; + std::vector stringTable; + struct { + uint32_t shStrTab = 0; + uint32_t undef = 0; + } specialStringsOffsets; +}; + +extern template struct ElfEncoder; +extern template struct ElfEncoder; + +} // namespace Elf + +} // namespace NEO diff --git a/core/device_binary_format/elf/ocl_elf.h b/core/device_binary_format/elf/ocl_elf.h new file mode 100644 index 0000000000..03ecbb7858 --- /dev/null +++ b/core/device_binary_format/elf/ocl_elf.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019-2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +// Abstract: Defines the types used for ELF headers/sections. +#pragma once + +#include "core/device_binary_format/elf/elf.h" +#include "core/utilities/const_stringref.h" + +#include +#include + +namespace NEO { + +namespace Elf { + +enum ELF_TYPE_OPENCL : uint16_t { + ET_OPENCL_SOURCE = 0xff01, // format used to pass CL text sections to FE + ET_OPENCL_OBJECTS = 0xff02, // format used to pass LLVM objects / store LLVM binary output + ET_OPENCL_LIBRARY = 0xff03, // format used to store LLVM archive output + ET_OPENCL_EXECUTABLE = 0xff04, // format used to store executable output + ET_OPENCL_DEBUG = 0xff05, // format used to store debug output +}; +static_assert(sizeof(ELF_TYPE_OPENCL) == sizeof(ELF_TYPE), ""); +static_assert(static_cast(ET_OPENCL_SOURCE) == static_cast(ET_OPENCL_RESERVED_START), ""); +static_assert(static_cast(ET_OPENCL_DEBUG) == static_cast(ET_OPENCL_RESERVED_END), ""); + +enum SHT_OPENCL : uint32_t { + SHT_OPENCL_SOURCE = 0xff000000, // CL source to link into LLVM binary + SHT_OPENCL_HEADER = 0xff000001, // CL header to link into LLVM binary + SHT_OPENCL_LLVM_TEXT = 0xff000002, // LLVM text + SHT_OPENCL_LLVM_BINARY = 0xff000003, // LLVM byte code + SHT_OPENCL_LLVM_ARCHIVE = 0xff000004, // LLVM archives(s) + SHT_OPENCL_DEV_BINARY = 0xff000005, // Device binary (coherent by default) + SHT_OPENCL_OPTIONS = 0xff000006, // CL Options + SHT_OPENCL_PCH = 0xff000007, // PCH (pre-compiled headers) + SHT_OPENCL_DEV_DEBUG = 0xff000008, // Device debug + SHT_OPENCL_SPIRV = 0xff000009, // SPIRV + SHT_NON_COHERENT_DEV_BINARY = 0xff00000a, // Non-coherent Device binary +}; +static_assert(sizeof(SHT_OPENCL) == sizeof(SECTION_HEADER_TYPE), ""); +static_assert(static_cast(SHT_OPENCL_SOURCE) == static_cast(SHT_OPENCL_RESERVED_START), ""); +static_assert(static_cast(SHT_NON_COHERENT_DEV_BINARY) == static_cast(SHT_OPENCL_RESERVED_END), ""); + +namespace SectionNamesOpenCl { +static constexpr ConstStringRef buildOptions = "BuildOptions"; +static constexpr ConstStringRef spirvObject = "SPIRV Object"; +static constexpr ConstStringRef llvmObject = "Intel(R) OpenCL LLVM Object"; +static constexpr ConstStringRef deviceDebug = "Intel(R) OpenCL Device Debug"; +static constexpr ConstStringRef deviceBinary = "Intel(R) OpenCL Device Binary"; +} // namespace SectionNamesOpenCl + +} // namespace Elf + +} // namespace NEO diff --git a/core/device_binary_format/patchtokens_decoder.cpp b/core/device_binary_format/patchtokens_decoder.cpp index 6130348d9a..a46ca7e5f1 100644 --- a/core/device_binary_format/patchtokens_decoder.cpp +++ b/core/device_binary_format/patchtokens_decoder.cpp @@ -63,7 +63,7 @@ inline KernelArgFromPatchtokens &getKernelArg(KernelFromPatchtokens &kernel, siz if (arg.objectType == ArgObjectType::None) { arg.objectType = type; } else if ((arg.objectType != type) && (type != ArgObjectType::None)) { - kernel.decodeStatus = DecoderError::InvalidBinary; + kernel.decodeStatus = DecodeError::InvalidBinary; DBG_LOG(LogPatchTokens, "\n Mismatched metadata for kernel arg :", argNum); DEBUG_BREAK_IF(true); } @@ -425,7 +425,7 @@ inline bool decodeToken(const SPatchItemHeader *token, KernelFromPatchtokens &ou } break; } - return out.decodeStatus != DecoderError::InvalidBinary; + return out.decodeStatus != DecodeError::InvalidBinary; } inline bool decodeToken(const SPatchItemHeader *token, ProgramFromPatchtokens &out) { @@ -475,7 +475,7 @@ inline size_t getPatchTokenTotalSize(PatchTokensStreamRe ? tokSize + reinterpret_cast(token)->InlineDataSize : std::numeric_limits::max(); case PATCH_TOKEN_ALLOCATE_GLOBAL_MEMORY_SURFACE_PROGRAM_BINARY_INFO: - return stream.enoughDataLeft(token) + return stream.enoughDataLeft(token) ? tokSize + reinterpret_cast(token)->InlineDataSize : std::numeric_limits::max(); } @@ -499,12 +499,12 @@ inline bool decodePatchList(PatchTokensStreamReader patchListStream, OutT &out) return decodeSuccess; } -bool decodeKernelFromPatchtokensBlob(ArrayRef data, KernelFromPatchtokens &out) { - PatchTokensStreamReader stream{data}; +bool decodeKernelFromPatchtokensBlob(ArrayRef kernelBlob, KernelFromPatchtokens &out) { + PatchTokensStreamReader stream{kernelBlob}; auto decodePos = stream.data.begin(); - out.decodeStatus = DecoderError::Undefined; + out.decodeStatus = DecodeError::Undefined; if (stream.notEnoughDataLeft(decodePos)) { - out.decodeStatus = DecoderError::InvalidBinary; + out.decodeStatus = DecodeError::InvalidBinary; return false; } @@ -513,7 +513,7 @@ bool decodeKernelFromPatchtokensBlob(ArrayRef data, KernelFromPat auto kernelInfoBlobSize = sizeof(SKernelBinaryHeaderCommon) + out.header->KernelNameSize + out.header->KernelHeapSize + out.header->GeneralStateHeapSize + out.header->DynamicStateHeapSize + out.header->SurfaceStateHeapSize + out.header->PatchListSize; if (stream.notEnoughDataLeft(decodePos, kernelInfoBlobSize)) { - out.decodeStatus = DecoderError::InvalidBinary; + out.decodeStatus = DecodeError::InvalidBinary; return false; } @@ -539,11 +539,11 @@ bool decodeKernelFromPatchtokensBlob(ArrayRef data, KernelFromPat out.blobs.patchList = ArrayRef(decodePos, out.header->PatchListSize); if (false == decodePatchList(out.blobs.patchList, out)) { - out.decodeStatus = DecoderError::InvalidBinary; + out.decodeStatus = DecodeError::InvalidBinary; return false; } - out.decodeStatus = DecoderError::Success; + out.decodeStatus = DecodeError::Success; return true; } @@ -586,12 +586,12 @@ inline bool decodeKernels(ProgramFromPatchtokens &decodedProgram) { return decodeSuccess; } -bool decodeProgramFromPatchtokensBlob(ArrayRef blob, ProgramFromPatchtokens &out) { - out.blobs.programInfo = blob; +bool decodeProgramFromPatchtokensBlob(ArrayRef programBlob, ProgramFromPatchtokens &out) { + out.blobs.programInfo = programBlob; bool decodeSuccess = decodeProgramHeader(out); decodeSuccess = decodeSuccess && decodeKernels(out); decodeSuccess = decodeSuccess && decodePatchList(out.blobs.patchList, out); - out.decodeStatus = decodeSuccess ? DecoderError::Success : DecoderError::InvalidBinary; + out.decodeStatus = decodeSuccess ? DecodeError::Success : DecodeError::InvalidBinary; return decodeSuccess; } @@ -631,6 +631,15 @@ const KernelArgAttributesFromPatchtokens getInlineData(const SPatchKernelArgumen return ret; } +const iOpenCL::SProgramBinaryHeader *decodeProgramHeader(const ArrayRef programBlob) { + ProgramFromPatchtokens program; + program.blobs.programInfo = programBlob; + if (false == decodeProgramHeader(program)) { + return nullptr; + } + return program.header; +} + } // namespace PatchTokenBinary } // namespace NEO diff --git a/core/device_binary_format/patchtokens_decoder.h b/core/device_binary_format/patchtokens_decoder.h index 5ee0256a6f..1fa9ac1ac9 100644 --- a/core/device_binary_format/patchtokens_decoder.h +++ b/core/device_binary_format/patchtokens_decoder.h @@ -7,10 +7,12 @@ #pragma once +#include "core/device_binary_format/device_binary_formats.h" #include "core/helpers/ptr_math.h" #include "core/utilities/arrayref.h" #include "core/utilities/stackvec.h" +#include "igfxfmid.h" #include "patch_g7.h" #include "patch_list.h" #include "patch_shared.h" @@ -19,6 +21,7 @@ #include #include #include +#include namespace NEO { @@ -26,12 +29,6 @@ namespace PatchTokenBinary { using namespace iOpenCL; -enum class DecoderError { - Success = 0, - Undefined = 1, - InvalidBinary = 2, -}; - enum class ArgObjectType : uint32_t { None = 0, Buffer, @@ -100,7 +97,7 @@ struct KernelArgFromPatchtokens { using StackVecKernelArgs = StackVec; struct KernelFromPatchtokens { - DecoderError decodeStatus = DecoderError::Undefined; + DecodeError decodeStatus = DecodeError::Undefined; const SKernelBinaryHeaderCommon *header = nullptr; ArrayRef name; @@ -167,7 +164,7 @@ struct KernelFromPatchtokens { }; struct ProgramFromPatchtokens { - DecoderError decodeStatus = DecoderError::Undefined; + DecodeError decodeStatus = DecodeError::Undefined; const SProgramBinaryHeader *header = nullptr; struct { @@ -195,8 +192,8 @@ struct KernelArgAttributesFromPatchtokens { ArrayRef typeQualifiers; }; -bool decodeKernelFromPatchtokensBlob(ArrayRef blob, KernelFromPatchtokens &out); -bool decodeProgramFromPatchtokensBlob(ArrayRef blob, ProgramFromPatchtokens &out); +bool decodeKernelFromPatchtokensBlob(ArrayRef kernelBlob, KernelFromPatchtokens &out); +bool decodeProgramFromPatchtokensBlob(ArrayRef programBlob, ProgramFromPatchtokens &out); uint32_t calcKernelChecksum(const ArrayRef kernelBlob); bool hasInvalidChecksum(const KernelFromPatchtokens &decodedKernel); @@ -214,6 +211,12 @@ inline const uint8_t *getInlineData(const SPatchString *ptr) { const KernelArgAttributesFromPatchtokens getInlineData(const SPatchKernelArgumentInfo *ptr); +const iOpenCL::SProgramBinaryHeader *decodeProgramHeader(const ArrayRef programBlob); + +inline bool isValidPatchTokenBinary(const ArrayRef programBlob) { + return nullptr != decodeProgramHeader(programBlob); +} + } // namespace PatchTokenBinary } // namespace NEO diff --git a/core/device_binary_format/patchtokens_dumper.cpp b/core/device_binary_format/patchtokens_dumper.cpp index 14d941d97d..fd77813e29 100644 --- a/core/device_binary_format/patchtokens_dumper.cpp +++ b/core/device_binary_format/patchtokens_dumper.cpp @@ -710,21 +710,6 @@ void dumpVecIfNotEmpty(const T &vector, const std::string &vectorName, std::stri } } -const char *asString(DecoderError err) { - switch (err) { - default: - DEBUG_BREAK_IF(err != DecoderError::InvalidBinary); - return "with invalid binary"; - break; - case DecoderError::Success: - return "decoded successfully"; - break; - case DecoderError::Undefined: - return "in undefined status"; - break; - } -} - std::string asString(const ProgramFromPatchtokens &prog) { std::stringstream stream; stream << "Program of size : " << prog.blobs.programInfo.size() diff --git a/core/device_binary_format/patchtokens_validator.inl b/core/device_binary_format/patchtokens_validator.cpp similarity index 70% rename from core/device_binary_format/patchtokens_validator.inl rename to core/device_binary_format/patchtokens_validator.cpp index 9e8e151946..0025fa7d42 100644 --- a/core/device_binary_format/patchtokens_validator.inl +++ b/core/device_binary_format/patchtokens_validator.cpp @@ -1,11 +1,11 @@ /* - * Copyright (C) 2019-2020 Intel Corporation + * Copyright (C) 2020 Intel Corporation * * SPDX-License-Identifier: MIT * */ -#pragma once +#include "core/device_binary_format/patchtokens_validator.h" #include "core/device_binary_format/patchtokens_decoder.h" #include "core/helpers/hw_info.h" @@ -19,35 +19,23 @@ namespace NEO { namespace PatchTokenBinary { -enum class ValidatorError { - Success = 0, - Undefined = 1, - InvalidBinary = 2, - NotEnoughSlm = 3, -}; +bool allowUnhandledTokens = true; -constexpr bool isDeviceSupported(GFXCORE_FAMILY device) { - return (device < (sizeof(familyEnabled) / sizeof(familyEnabled[0]))) && familyEnabled[device]; -} - -template -inline ValidatorError validate(const ProgramFromPatchtokens &decodedProgram, - size_t sharedLocalMemorySize, - const UknownTokenValidatorT &tokenValidator, - std::string &outErrReason, std::string &outWarnings) { - if (decodedProgram.decodeStatus != PatchTokenBinary::DecoderError::Success) { +DecodeError validate(const ProgramFromPatchtokens &decodedProgram, + std::string &outErrReason, std::string &outWarnings) { + if (decodedProgram.decodeStatus != DecodeError::Success) { outErrReason = "ProgramFromPatchtokens wasn't successfully decoded"; - return ValidatorError::InvalidBinary; + return DecodeError::InvalidBinary; } if (decodedProgram.programScopeTokens.allocateConstantMemorySurface.size() > 1) { outErrReason = "Unhandled number of global constants surfaces > 1"; - return ValidatorError::InvalidBinary; + return DecodeError::UnhandledBinary; } if (decodedProgram.programScopeTokens.allocateGlobalMemorySurface.size() > 1) { outErrReason = "Unhandled number of global variables surfaces > 1"; - return ValidatorError::InvalidBinary; + return DecodeError::UnhandledBinary; } for (const auto &globalConstantPointerToken : decodedProgram.programScopeTokens.constantPointer) { @@ -59,7 +47,7 @@ inline ValidatorError validate(const ProgramFromPatchtokens &decodedProgram, if (isUnhandled) { outErrReason = "Unhandled SPatchConstantPointerProgramBinaryInfo"; - return ValidatorError::InvalidBinary; + return DecodeError::UnhandledBinary; } } @@ -72,50 +60,45 @@ inline ValidatorError validate(const ProgramFromPatchtokens &decodedProgram, if (isUnhandled) { outErrReason = "Unhandled SPatchGlobalPointerProgramBinaryInfo"; - return ValidatorError::InvalidBinary; + return DecodeError::UnhandledBinary; } } for (const auto &unhandledToken : decodedProgram.unhandledTokens) { - if (false == tokenValidator.isSafeToSkipUnhandledToken(unhandledToken->Token)) { - outErrReason = "Unhandled required program-scope Patch Token : " + std::to_string(unhandledToken->Token); - return ValidatorError::InvalidBinary; - } else { + if (allowUnhandledTokens) { outWarnings = "Unknown program-scope Patch Token : " + std::to_string(unhandledToken->Token); + } else { + outErrReason = "Unhandled required program-scope Patch Token : " + std::to_string(unhandledToken->Token); + return DecodeError::UnhandledBinary; } } UNRECOVERABLE_IF(nullptr == decodedProgram.header); if (decodedProgram.header->Version != CURRENT_ICBE_VERSION) { outErrReason = "Unhandled Version of Patchtokens: expected: " + std::to_string(CURRENT_ICBE_VERSION) + ", got: " + std::to_string(decodedProgram.header->Version); - return ValidatorError::InvalidBinary; + return DecodeError::UnhandledBinary; } if ((decodedProgram.header->GPUPointerSizeInBytes != 4U) && (decodedProgram.header->GPUPointerSizeInBytes != 8U)) { outErrReason = "Invalid pointer size"; - return ValidatorError::InvalidBinary; - } - - if (false == isDeviceSupported(static_cast(decodedProgram.header->Device))) { - outErrReason = "Unsupported device binary, device GFXCORE_FAMILY : " + std::to_string(decodedProgram.header->Device); - return ValidatorError::InvalidBinary; + return DecodeError::UnhandledBinary; } for (const auto &decodedKernel : decodedProgram.kernels) { - if (decodedKernel.decodeStatus != PatchTokenBinary::DecoderError::Success) { + if (decodedKernel.decodeStatus != DecodeError::Success) { outErrReason = "KernelFromPatchtokens wasn't successfully decoded"; - return ValidatorError::InvalidBinary; + return DecodeError::UnhandledBinary; } UNRECOVERABLE_IF(nullptr == decodedKernel.header); if (hasInvalidChecksum(decodedKernel)) { outErrReason = "KernelFromPatchtokens has invalid checksum"; - return ValidatorError::InvalidBinary; + return DecodeError::UnhandledBinary; } if (nullptr == decodedKernel.tokens.executionEnvironment) { outErrReason = "Missing execution environment"; - return ValidatorError::InvalidBinary; + return DecodeError::UnhandledBinary; } else { switch (decodedKernel.tokens.executionEnvironment->LargestCompiledSIMDSize) { case 1: @@ -128,14 +111,7 @@ inline ValidatorError validate(const ProgramFromPatchtokens &decodedProgram, break; default: outErrReason = "Invalid LargestCompiledSIMDSize"; - return ValidatorError::InvalidBinary; - } - } - - if (decodedKernel.tokens.allocateLocalSurface) { - if (sharedLocalMemorySize < decodedKernel.tokens.allocateLocalSurface->TotalInlineLocalMemorySize) { - outErrReason = "KernelFromPatchtokens requires too much SLM"; - return ValidatorError::NotEnoughSlm; + return DecodeError::UnhandledBinary; } } @@ -147,26 +123,26 @@ inline ValidatorError validate(const ProgramFromPatchtokens &decodedProgram, auto accessQualifier = KernelArgMetadata::parseAccessQualifier(parseLimitedString(argInfoInlineData.accessQualifier.begin(), argInfoInlineData.accessQualifier.size())); if (KernelArgMetadata::AccessQualifier::Unknown == accessQualifier) { outErrReason = "Unhandled access qualifier"; - return ValidatorError::InvalidBinary; + return DecodeError::UnhandledBinary; } auto addressQualifier = KernelArgMetadata::parseAddressSpace(parseLimitedString(argInfoInlineData.addressQualifier.begin(), argInfoInlineData.addressQualifier.size())); if (KernelArgMetadata::AddressSpaceQualifier::Unknown == addressQualifier) { outErrReason = "Unhandled address qualifier"; - return ValidatorError::InvalidBinary; + return DecodeError::UnhandledBinary; } } for (const auto &unhandledToken : decodedKernel.unhandledTokens) { - if (false == tokenValidator.isSafeToSkipUnhandledToken(unhandledToken->Token)) { - outErrReason = "Unhandled required kernel-scope Patch Token : " + std::to_string(unhandledToken->Token); - return ValidatorError::InvalidBinary; - } else { + if (allowUnhandledTokens) { outWarnings = "Unknown kernel-scope Patch Token : " + std::to_string(unhandledToken->Token); + } else { + outErrReason = "Unhandled required kernel-scope Patch Token : " + std::to_string(unhandledToken->Token); + return DecodeError::UnhandledBinary; } } } - return ValidatorError::Success; + return DecodeError::Success; } } // namespace PatchTokenBinary diff --git a/core/device_binary_format/patchtokens_validator.h b/core/device_binary_format/patchtokens_validator.h new file mode 100644 index 0000000000..3bef60be12 --- /dev/null +++ b/core/device_binary_format/patchtokens_validator.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019-2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "core/device_binary_format/device_binary_formats.h" + +#include + +namespace NEO { + +namespace PatchTokenBinary { +extern bool allowUnhandledTokens; + +struct ProgramFromPatchtokens; + +DecodeError validate(const ProgramFromPatchtokens &decodedProgram, + std::string &outErrReason, std::string &outWarnings); + +} // namespace PatchTokenBinary + +} // namespace NEO diff --git a/core/elf/CMakeLists.txt b/core/elf/CMakeLists.txt deleted file mode 100644 index 97e60746ba..0000000000 --- a/core/elf/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (C) 2017-2019 Intel Corporation -# -# SPDX-License-Identifier: MIT -# - -add_library(elflib STATIC EXCLUDE_FROM_ALL - ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt - ${CMAKE_CURRENT_SOURCE_DIR}/reader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/reader.h - ${CMAKE_CURRENT_SOURCE_DIR}/types.h - ${CMAKE_CURRENT_SOURCE_DIR}/writer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/writer.h -) - -create_project_source_tree(elflib) - -target_include_directories(elflib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_include_directories(elflib PRIVATE ${NEO_SOURCE_DIR}) - -set_target_properties(elflib PROPERTIES FOLDER "elflib") - -set_target_properties(elflib PROPERTIES POSITION_INDEPENDENT_CODE ON) diff --git a/core/elf/reader.cpp b/core/elf/reader.cpp deleted file mode 100644 index a2291012dc..0000000000 --- a/core/elf/reader.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2017-2019 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#include "reader.h" - -#include - -namespace CLElfLib { -CElfReader::CElfReader(ElfBinaryStorage &elfBinary) { - validateElfBinary(elfBinary); -} - -void CElfReader::validateElfBinary(ElfBinaryStorage &elfBinary) { - const char *nameTable = nullptr; - const char *end = nullptr; - size_t ourSize = 0u; - size_t entrySize = 0u; - size_t indexedSectionHeaderOffset = 0u; - beginBinary = elfBinary.data(); - - if (elfBinary.size() >= sizeof(SElf64Header)) { - // calculate a pointer to the end - end = beginBinary + elfBinary.size(); - elf64Header = reinterpret_cast(elfBinary.data()); - - if (!((elf64Header->Identity[ELFConstants::idIdxMagic0] == ELFConstants::elfMag0) && - (elf64Header->Identity[ELFConstants::idIdxMagic1] == ELFConstants::elfMag1) && - (elf64Header->Identity[ELFConstants::idIdxMagic2] == ELFConstants::elfMag2) && - (elf64Header->Identity[ELFConstants::idIdxMagic3] == ELFConstants::elfMag3) && - (elf64Header->Identity[ELFConstants::idIdxClass] == static_cast(E_EH_CLASS::EH_CLASS_64)))) { - throw ElfException(); - } - ourSize += elf64Header->ElfHeaderSize; - } else { - throw ElfException(); - } - - entrySize = elf64Header->SectionHeaderEntrySize; - - if (elf64Header->SectionNameTableIndex < elf64Header->NumSectionHeaderEntries) { - indexedSectionHeaderOffset = static_cast(elf64Header->SectionHeadersOffset) + (elf64Header->SectionNameTableIndex * entrySize); - - if ((beginBinary + indexedSectionHeaderOffset) <= end) { - nameTable = beginBinary + indexedSectionHeaderOffset; - } - } - - for (uint16_t i = 0u; i < elf64Header->NumSectionHeaderEntries; ++i) { - indexedSectionHeaderOffset = static_cast(elf64Header->SectionHeadersOffset) + (i * entrySize); - - // check section header offset - if ((beginBinary + indexedSectionHeaderOffset) > end) { - throw ElfException(); - } - - const SElf64SectionHeader *sectionHeader = nullptr; - - sectionHeader = reinterpret_cast(beginBinary + indexedSectionHeaderOffset); - - // check section data - if ((beginBinary + sectionHeader->DataOffset + sectionHeader->DataSize) > end) { - throw ElfException(); - } - - // check section name index - if ((nameTable + sectionHeader->Name) > end) { - throw ElfException(); - } - - SElf64SectionHeader stringSectionHeader = {0}; - stringSectionHeader.Type = sectionHeader->Type; - stringSectionHeader.Flags = sectionHeader->Flags; - stringSectionHeader.DataOffset = sectionHeader->DataOffset; - stringSectionHeader.DataSize = sectionHeader->DataSize; - stringSectionHeader.Name = sectionHeader->Name; - sectionHeaders.push_back(std::move(stringSectionHeader)); - - // tally up the sizes - ourSize += static_cast(sectionHeader->DataSize); - ourSize += static_cast(entrySize); - } - - if (ourSize != elfBinary.size()) { - throw ElfException(); - } -} - -char *CElfReader::getSectionData(Elf64_Off dataOffset) { - return beginBinary + dataOffset; -} - -const SElf64Header *CElfReader::getElfHeader() { - return elf64Header; -} - -} // namespace CLElfLib diff --git a/core/elf/reader.h b/core/elf/reader.h deleted file mode 100644 index f53a5a293d..0000000000 --- a/core/elf/reader.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2017-2019 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#pragma once -#include "types.h" - -namespace CLElfLib { -using ElfSectionHeaderStorage = std::vector; -/******************************************************************************\ - - Class: CElfReader - - Description: Class to provide simpler interaction with the ELF standard - binary object. SElf64Header defines the ELF header type and - SElf64SectionHeader defines the section header type. - -\******************************************************************************/ -class CElfReader { - public: - CElfReader(ElfBinaryStorage &elfBinary); - ElfSectionHeaderStorage &getSectionHeaders() { - return sectionHeaders; - } - - const SElf64Header *getElfHeader(); - char *getSectionData(Elf64_Off dataOffset); - - protected: - void validateElfBinary(ElfBinaryStorage &elfBinary); - - ElfSectionHeaderStorage sectionHeaders; - char *beginBinary; - const SElf64Header *elf64Header; -}; -} // namespace CLElfLib diff --git a/core/elf/types.h b/core/elf/types.h deleted file mode 100644 index dc3ea8dc1c..0000000000 --- a/core/elf/types.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2017-2019 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -// Abstract: Defines the types used for ELF headers/sections. -#pragma once - -#include -#include -#include - -namespace CLElfLib { -struct ElfException : std::exception { -}; - -using ElfBinaryStorage = std::vector; -/******************************************************************************\ - ELF Enumerates -\******************************************************************************/ - -// E_ID_IDX - Defines a file as being ELF -enum class E_ID_IDX : uint32_t { - ID_IDX_MAGIC0 = 0, - ID_IDX_MAGIC1 = 1, - ID_IDX_MAGIC2 = 2, - ID_IDX_MAGIC3 = 3, - ID_IDX_CLASS = 4, - ID_IDX_VERSION = 5, - ID_IDX_OSABI = 6, - ID_IDX_ABI_VERSION = 7, - ID_IDX_PADDING = 8, - ID_IDX_NUM_BYTES = 16, -}; - -// E_EHT_CLASS - Describes what data types the ELF structures will use. -enum class E_EH_CLASS : uint32_t { - EH_CLASS_NONE = 0, - EH_CLASS_32 = 1, // Use Elf32 data types - EH_CLASS_64 = 2, // Use Elf64 data types -}; - -// E_EHT_TYPE - List of pre-defined types header types. -// OS-specific codes start at 0xfe00 and run to 0xfeff. -// Processor-specific codes start at 0xff00 and end at 0xffff. -enum class E_EH_TYPE : uint16_t { - EH_TYPE_NONE = 0, - EH_TYPE_RELOCATABLE = 1, - EH_TYPE_EXECUTABLE = 2, - EH_TYPE_DYNAMIC = 3, - EH_TYPE_CORE = 4, - EH_TYPE_OPENCL_SOURCE = 0xff01, // format used to pass CL text sections to FE - EH_TYPE_OPENCL_OBJECTS = 0xff02, // format used to pass LLVM objects / store LLVM binary output - EH_TYPE_OPENCL_LIBRARY = 0xff03, // format used to store LLVM archive output - EH_TYPE_OPENCL_EXECUTABLE = 0xff04, // format used to store executable output - EH_TYPE_OPENCL_DEBUG = 0xff05, // format used to store debug output -}; - -// E_EH_MACHINE - List of pre-defined machine types. -// For OpenCL, currently, we do not need this information, so this is not -// fully defined. -enum class E_EH_MACHINE : uint16_t { - EH_MACHINE_NONE = 0, - //EHT_MACHINE_LO_RSVD = 1, // Beginning of range of reserved types. - //EHT_MACHINE_HI_RSVD = 200, // End of range of reserved types. -}; - -// E_EHT_VERSION - ELF header version options. -enum class E_EHT_VERSION : uint32_t { - EH_VERSION_INVALID = 0, - EH_VERSION_CURRENT = 1, -}; - -// E_SH_TYPE - List of pre-defined section header types. -// Processor-specific codes start at 0xff00 and end at 0xffff. -enum class E_SH_TYPE : uint32_t { - SH_TYPE_NULL = 0, - SH_TYPE_PROG_BITS = 1, - SH_TYPE_SYM_TBL = 2, - SH_TYPE_STR_TBL = 3, - SH_TYPE_RELO_ADDS = 4, - SH_TYPE_HASH = 5, - SH_TYPE_DYN = 6, - SH_TYPE_NOTE = 7, - SH_TYPE_NOBITS = 8, - SH_TYPE_RELO_NO_ADDS = 9, - SH_TYPE_SHLIB = 10, - SH_TYPE_DYN_SYM_TBL = 11, - SH_TYPE_INIT = 14, - SH_TYPE_FINI = 15, - SH_TYPE_PRE_INIT = 16, - SH_TYPE_GROUP = 17, - SH_TYPE_SYMTBL_SHNDX = 18, - SH_TYPE_OPENCL_SOURCE = 0xff000000, // CL source to link into LLVM binary - SH_TYPE_OPENCL_HEADER = 0xff000001, // CL header to link into LLVM binary - SH_TYPE_OPENCL_LLVM_TEXT = 0xff000002, // LLVM text - SH_TYPE_OPENCL_LLVM_BINARY = 0xff000003, // LLVM byte code - SH_TYPE_OPENCL_LLVM_ARCHIVE = 0xff000004, // LLVM archives(s) - SH_TYPE_OPENCL_DEV_BINARY = 0xff000005, // Device binary (coherent by default) - SH_TYPE_OPENCL_OPTIONS = 0xff000006, // CL Options - SH_TYPE_OPENCL_PCH = 0xff000007, // PCH (pre-compiled headers) - SH_TYPE_OPENCL_DEV_DEBUG = 0xff000008, // Device debug - SH_TYPE_SPIRV = 0xff000009, // SPIRV - SH_TYPE_NON_COHERENT_DEV_BINARY = 0xff00000a, // Non-coherent Device binary -}; - -// E_SH_FLAG - List of section header flags. -enum class E_SH_FLAG : uint64_t { - SH_FLAG_NONE = 0x0, - SH_FLAG_WRITE = 0x1, - SH_FLAG_ALLOC = 0x2, - SH_FLAG_EXEC_INSTR = 0x4, - SH_FLAG_MERGE = 0x8, - SH_FLAG_STRINGS = 0x10, - SH_FLAG_INFO_LINK = 0x20, - SH_FLAG_LINK_ORDER = 0x40, - SH_FLAG_OS_NONCONFORM = 0x100, - SH_FLAG_GROUP = 0x200, - SH_FLAG_TLS = 0x400, - SH_FLAG_MASK_OS = 0x0ff00000, - SH_FLAG_MASK_PROC = 0xf0000000, -}; - -/******************************************************************************\ - ELF-64 Data Types -\******************************************************************************/ -#if !defined(_UAPI_LINUX_ELF_H) -typedef uint64_t Elf64_Addr; -typedef uint64_t Elf64_Off; -typedef uint32_t Elf64_Word; -typedef int32_t Elf64_Sword; -typedef uint64_t Elf64_Xword; -typedef uint16_t Elf64_Short; // Renaming Elf64_Half to Elf64_Short to avoid a conflict with Android -#endif - -/******************************************************************************\ - ELF Constants -\******************************************************************************/ -namespace ELFConstants { -static const unsigned char elfMag0 = 0x7f; // ELFHeader.Identity[ELF_ID_MAGIC0] -static const unsigned char elfMag1 = 'E'; // ELFHeader.Identity[ELF_ID_MAGIC1] -static const unsigned char elfMag2 = 'L'; // ELFHeader.Identity[ELF_ID_MAGIC2] -static const unsigned char elfMag3 = 'F'; // ELFHeader.Identity[ELF_ID_MAGIC3] -static const unsigned int elfAlignBytes = 16; // Alignment set to 16-bytes - -static const uint32_t idIdxMagic0 = 0; -static const uint32_t idIdxMagic1 = 1; -static const uint32_t idIdxMagic2 = 2; -static const uint32_t idIdxMagic3 = 3; -static const uint32_t idIdxClass = 4; -static const uint32_t idIdxVersion = 5; -static const uint32_t idIdxOsabi = 6; -static const uint32_t idIdxAbiVersion = 7; -static const uint32_t idIdxPadding = 8; -static const uint32_t idIdxNumBytes = 16; -} // namespace ELFConstants - -/******************************************************************************\ - ELF-64 Header -\******************************************************************************/ -struct SElf64Header { - unsigned char Identity[ELFConstants::idIdxNumBytes]; - E_EH_TYPE Type; - E_EH_MACHINE Machine; - Elf64_Word Version; - Elf64_Addr EntryAddress; - Elf64_Off ProgramHeadersOffset; - Elf64_Off SectionHeadersOffset; - Elf64_Word Flags; - Elf64_Short ElfHeaderSize; - Elf64_Short ProgramHeaderEntrySize; - Elf64_Short NumProgramHeaderEntries; - Elf64_Short SectionHeaderEntrySize; - Elf64_Short NumSectionHeaderEntries; - Elf64_Short SectionNameTableIndex; -}; - -/******************************************************************************\ - ELF-64 Section Header -\******************************************************************************/ -struct SElf64SectionHeader { - Elf64_Word Name; - E_SH_TYPE Type; - E_SH_FLAG Flags; - Elf64_Addr Address; - Elf64_Off DataOffset; - Elf64_Xword DataSize; - Elf64_Word Link; - Elf64_Word Info; - Elf64_Xword Alignment; - Elf64_Xword EntrySize; -}; - -} // namespace CLElfLib diff --git a/core/elf/writer.cpp b/core/elf/writer.cpp deleted file mode 100644 index 8b667cd202..0000000000 --- a/core/elf/writer.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2017-2019 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#include "writer.h" - -#include - -// Need for linux compatibility with memcpy_s -#include "core/helpers/string.h" - -namespace CLElfLib { -void CElfWriter::resolveBinary(ElfBinaryStorage &binary) { - SElf64SectionHeader *curSectionHeader = nullptr; - char *data = nullptr; - char *stringTable = nullptr; - char *curString = nullptr; - - if (binary.size() < getTotalBinarySize()) { - binary.resize(getTotalBinarySize()); - } - - // get a pointer to the first section header - curSectionHeader = reinterpret_cast(binary.data() + sizeof(SElf64Header)); - - // get a pointer to the data - data = binary.data() + - sizeof(SElf64Header) + - ((numSections + 1) * sizeof(SElf64SectionHeader)); // +1 to account for string table entry - - // get a pointer to the string table - stringTable = binary.data() + sizeof(SElf64Header) + - ((numSections + 1) * sizeof(SElf64SectionHeader)) + // +1 to account for string table entry - dataSize; - - curString = stringTable; - - // Walk through the section nodes - while (nodeQueue.empty() == false) { - // Copy data into the section header - const auto &queueFront = nodeQueue.front(); - - curSectionHeader->Type = queueFront.type; - curSectionHeader->Flags = queueFront.flag; - curSectionHeader->DataSize = queueFront.dataSize; - curSectionHeader->DataOffset = data - binary.data(); - curSectionHeader->Name = static_cast(curString - stringTable); - curSectionHeader = reinterpret_cast(reinterpret_cast(curSectionHeader) + sizeof(SElf64SectionHeader)); - - // copy the data, move the data pointer - memcpy_s(data, queueFront.dataSize, queueFront.data.c_str(), queueFront.dataSize); - data += queueFront.dataSize; - - // copy the name into the string table, move the string pointer - if (queueFront.name.size() > 0) { - memcpy_s(curString, queueFront.name.size(), queueFront.name.c_str(), queueFront.name.size()); - curString += queueFront.name.size(); - } - *(curString++) = '\0'; // NOLINT - - nodeQueue.pop(); - } - - // add the string table section header - SElf64SectionHeader stringSectionHeader = {0}; - stringSectionHeader.Type = E_SH_TYPE::SH_TYPE_STR_TBL; - stringSectionHeader.Flags = E_SH_FLAG::SH_FLAG_NONE; - stringSectionHeader.DataOffset = stringTable - &binary[0]; - stringSectionHeader.DataSize = stringTableSize; - stringSectionHeader.Name = 0; - - // Copy into the last section header - memcpy_s(curSectionHeader, sizeof(SElf64SectionHeader), - &stringSectionHeader, sizeof(SElf64SectionHeader)); - - // Add to our section number - numSections++; - - // patch up the ELF header - patchElfHeader(*reinterpret_cast(binary.data())); -} - -void CElfWriter::patchElfHeader(SElf64Header &binary) { - // Setup the identity - binary.Identity[ELFConstants::idIdxMagic0] = ELFConstants::elfMag0; - binary.Identity[ELFConstants::idIdxMagic1] = ELFConstants::elfMag1; - binary.Identity[ELFConstants::idIdxMagic2] = ELFConstants::elfMag2; - binary.Identity[ELFConstants::idIdxMagic3] = ELFConstants::elfMag3; - binary.Identity[ELFConstants::idIdxClass] = static_cast(E_EH_CLASS::EH_CLASS_64); - binary.Identity[ELFConstants::idIdxVersion] = static_cast(E_EHT_VERSION::EH_VERSION_CURRENT); - - // Add other non-zero info - binary.Type = type; - binary.Machine = machine; - binary.Flags = static_cast(flag); - binary.ElfHeaderSize = static_cast(sizeof(SElf64Header)); - binary.SectionHeaderEntrySize = static_cast(sizeof(SElf64SectionHeader)); - binary.NumSectionHeaderEntries = numSections; - binary.SectionHeadersOffset = static_cast(sizeof(SElf64Header)); - binary.SectionNameTableIndex = numSections - 1; // last index -} -} // namespace CLElfLib diff --git a/core/elf/writer.h b/core/elf/writer.h deleted file mode 100644 index a0cbcfad72..0000000000 --- a/core/elf/writer.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2017-2019 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#pragma once -#include "types.h" - -#include -#include - -namespace CLElfLib { -struct SSectionNode { - E_SH_TYPE type = E_SH_TYPE::SH_TYPE_NULL; - E_SH_FLAG flag = E_SH_FLAG::SH_FLAG_NONE; - std::string name; - std::string data; - uint32_t dataSize = 0u; - - SSectionNode() = default; - - template - SSectionNode(E_SH_TYPE type, E_SH_FLAG flag, T1 &&name, T2 &&data, uint32_t dataSize) - : type(type), flag(flag), name(std::forward(name)), data(std::forward(data)), dataSize(dataSize) {} - - ~SSectionNode() = default; -}; - -/******************************************************************************\ - - Class: CElfWriter - - Description: Class to provide simpler interaction with the ELF standard - binary object. SElf64Header defines the ELF header type and - SElf64SectionHeader defines the section header type. - -\******************************************************************************/ -class CElfWriter { - public: - CElfWriter( - E_EH_TYPE type, - E_EH_MACHINE machine, - Elf64_Xword flag) : type(type), machine(machine), flag(flag) { - addSection(SSectionNode()); - } - - ~CElfWriter() {} - - template - void addSection(T &§ionNode) { - size_t nameSize = 0; - uint32_t dataSize = 0; - - nameSize = sectionNode.name.size() + 1u; - dataSize = sectionNode.dataSize; - - // push the node onto the queue - nodeQueue.push(std::forward(sectionNode)); - - // increment the sizes for each section - this->dataSize += dataSize; - stringTableSize += nameSize; - numSections++; - } - - void resolveBinary(ElfBinaryStorage &binary); - - size_t getTotalBinarySize() { - return sizeof(SElf64Header) + - ((numSections + 1) * sizeof(SElf64SectionHeader)) + // +1 to account for string table entry - dataSize + stringTableSize; - } - - protected: - E_EH_TYPE type = E_EH_TYPE::EH_TYPE_NONE; - E_EH_MACHINE machine = E_EH_MACHINE::EH_MACHINE_NONE; - Elf64_Xword flag = 0U; - - std::queue nodeQueue; - - uint32_t dataSize = 0U; - uint32_t numSections = 0U; - size_t stringTableSize = 0U; - - void patchElfHeader(SElf64Header &pBinary); -}; -} // namespace CLElfLib diff --git a/core/helpers/string.h b/core/helpers/string.h index ad15b0e095..a1be3710b0 100644 --- a/core/helpers/string.h +++ b/core/helpers/string.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 Intel Corporation + * Copyright (C) 2017-2020 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -94,13 +94,13 @@ inline int memmove_s(void *dst, size_t numberOfElements, const void *src, size_t #endif -template -inline std::unique_ptr makeCopy(const void *src, size_t size) { +template +inline std::unique_ptr makeCopy(const void *src, size_t size) { if (size == 0) { return nullptr; } using ElT = typename std::remove_all_extents::type; - std::unique_ptr copiedData(reinterpret_cast(new char[size])); + std::unique_ptr copiedData(new ElT[size]); memcpy_s(copiedData.get(), size, src, size); return copiedData; } diff --git a/core/program/program_info.cpp b/core/program/program_info.cpp index b73351c962..9ab2b1c182 100644 --- a/core/program/program_info.cpp +++ b/core/program/program_info.cpp @@ -18,4 +18,24 @@ ProgramInfo::~ProgramInfo() { kernelInfos.clear(); } +size_t getMaxInlineSlmNeeded(const ProgramInfo &programInfo) { + uint32_t ret = 0U; + for (const auto &kernelInfo : programInfo.kernelInfos) { + if (nullptr == kernelInfo->patchInfo.localsurface) { + continue; + } + ret = std::max(ret, kernelInfo->patchInfo.localsurface->TotalInlineLocalMemorySize); + } + return ret; +} + +bool requiresLocalMemoryWindowVA(const ProgramInfo &programInfo) { + for (const auto &kernelInfo : programInfo.kernelInfos) { + if (WorkloadInfo::undefinedOffset != kernelInfo->workloadInfo.localMemoryStatelessWindowStartAddressOffset) { + return true; + } + } + return false; +} + } // namespace NEO diff --git a/core/program/program_info.h b/core/program/program_info.h index 226c611128..51ef36e2d7 100644 --- a/core/program/program_info.h +++ b/core/program/program_info.h @@ -8,8 +8,8 @@ #pragma once #include "core/compiler_interface/linker.h" -#include "core/utilities/stackvec.h" +#include #include #include @@ -42,4 +42,7 @@ struct ProgramInfo { std::vector kernelInfos; }; +size_t getMaxInlineSlmNeeded(const ProgramInfo &programInfo); +bool requiresLocalMemoryWindowVA(const ProgramInfo &programInfo); + } // namespace NEO diff --git a/core/program/program_info_from_patchtokens.cpp b/core/program/program_info_from_patchtokens.cpp index 99cc56f6c9..57b28a95e5 100644 --- a/core/program/program_info_from_patchtokens.cpp +++ b/core/program/program_info_from_patchtokens.cpp @@ -25,11 +25,11 @@ bool requiresLocalMemoryWindowVA(const PatchTokenBinary::ProgramFromPatchtokens return false; } -void populateSingleKernelInfo(ProgramInfo &dst, const PatchTokenBinary::ProgramFromPatchtokens &decodedProgram, const DeviceInfoKernelPayloadConstants &constants, uint32_t kernelNum) { +void populateSingleKernelInfo(ProgramInfo &dst, const PatchTokenBinary::ProgramFromPatchtokens &decodedProgram, uint32_t kernelNum) { auto kernelInfo = std::make_unique(); const PatchTokenBinary::KernelFromPatchtokens &decodedKernel = decodedProgram.kernels[kernelNum]; - NEO::populateKernelInfo(*kernelInfo, decodedKernel, decodedProgram.header->GPUPointerSizeInBytes, constants); + NEO::populateKernelInfo(*kernelInfo, decodedKernel, decodedProgram.header->GPUPointerSizeInBytes); if (decodedKernel.tokens.programSymbolTable) { dst.prepareLinkerInputStorage(); @@ -44,9 +44,9 @@ void populateSingleKernelInfo(ProgramInfo &dst, const PatchTokenBinary::ProgramF dst.kernelInfos.push_back(kernelInfo.release()); } -void populateProgramInfo(ProgramInfo &dst, const PatchTokenBinary::ProgramFromPatchtokens &src, const DeviceInfoKernelPayloadConstants &constants) { +void populateProgramInfo(ProgramInfo &dst, const PatchTokenBinary::ProgramFromPatchtokens &src) { for (uint32_t i = 0; i < src.kernels.size(); ++i) { - populateSingleKernelInfo(dst, src, constants, i); + populateSingleKernelInfo(dst, src, i); } if (src.programScopeTokens.allocateConstantMemorySurface.empty() == false) { diff --git a/core/program/program_info_from_patchtokens.h b/core/program/program_info_from_patchtokens.h index 9b5754a9ad..99b118182b 100644 --- a/core/program/program_info_from_patchtokens.h +++ b/core/program/program_info_from_patchtokens.h @@ -12,7 +12,6 @@ namespace NEO { struct ProgramInfo; -struct DeviceInfoKernelPayloadConstants; namespace PatchTokenBinary { struct ProgramFromPatchtokens; @@ -25,6 +24,6 @@ inline uint64_t readMisalignedUint64(const uint64_t *address) { bool requiresLocalMemoryWindowVA(const PatchTokenBinary::ProgramFromPatchtokens &src); -void populateProgramInfo(ProgramInfo &dst, const PatchTokenBinary::ProgramFromPatchtokens &src, const DeviceInfoKernelPayloadConstants &constants); +void populateProgramInfo(ProgramInfo &dst, const PatchTokenBinary::ProgramFromPatchtokens &src); } // namespace NEO diff --git a/core/unit_tests/compiler_interface/CMakeLists.txt b/core/unit_tests/compiler_interface/CMakeLists.txt index c7e79c437c..ce0489ad5a 100644 --- a/core/unit_tests/compiler_interface/CMakeLists.txt +++ b/core/unit_tests/compiler_interface/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2019 Intel Corporation +# Copyright (C) 2019-2020 Intel Corporation # # SPDX-License-Identifier: MIT # @@ -9,6 +9,7 @@ set(NEO_CORE_COMPILER_INTERFACE_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/compiler_cache_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/compiler_options_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/compiler_interface_tests.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/intermediate_representations_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/linker_mock.h ${CMAKE_CURRENT_SOURCE_DIR}/linker_tests.cpp ) diff --git a/core/unit_tests/compiler_interface/compiler_interface_tests.cpp b/core/unit_tests/compiler_interface/compiler_interface_tests.cpp index b8ef795524..f83d17d64f 100644 --- a/core/unit_tests/compiler_interface/compiler_interface_tests.cpp +++ b/core/unit_tests/compiler_interface/compiler_interface_tests.cpp @@ -133,6 +133,15 @@ TEST(CompilerInterface, WhenInitializeIsCalledThenFailIfOneOfRequiredCompilersIs EXPECT_FALSE(initSuccess); } +TEST(CompilerInterfaceCreateInstance, WhenInitializeFailedThenReturnNull) { + struct FailInitializeCompilerInterface : CompilerInterface { + bool initialize(std::unique_ptr cache, bool requireFcl) override { + return false; + } + }; + EXPECT_EQ(nullptr, CompilerInterface::createInstance(std::make_unique(CompilerCacheConfig{}), false)); +} + TEST_F(CompilerInterfaceTest, WhenCompilingToIsaThenSuccessIsReturned) { TranslationOutput translationOutput; auto err = pCompilerInterface->build(*pDevice, inputArgs, translationOutput); diff --git a/core/unit_tests/compiler_interface/intermediate_representations_tests.cpp b/core/unit_tests/compiler_interface/intermediate_representations_tests.cpp new file mode 100644 index 0000000000..4d663e7b47 --- /dev/null +++ b/core/unit_tests/compiler_interface/intermediate_representations_tests.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "core/compiler_interface/intermediate_representations.h" +#include "test.h" + +TEST(HasSameMagic, WhenMagicIsMatchedThenReturnTrue) { + EXPECT_TRUE(NEO::hasSameMagic("abcd", ArrayRef("abcdefg").toArrayRef())); +} + +TEST(HasSameMagic, WhenBinaryIsNullptrThenReturnFalse) { + EXPECT_FALSE(NEO::hasSameMagic("abcd", {})); +} + +TEST(HasSameMagic, WhenBinaryIsShorterThanExpectedMagicThenReturnFalse) { + EXPECT_FALSE(NEO::hasSameMagic("abcd", ArrayRef("ab").toArrayRef())); +} + +TEST(HasSameMagic, WhenMagicIsNotMatchedThenReturnFalse) { + EXPECT_FALSE(NEO::hasSameMagic("abcd", ArrayRef("abcefg").toArrayRef())); +} + +static constexpr uint8_t llvmBinary[] = "BC\xc0\xde "; + +TEST(IsLlvmBitcode, WhenLlvmMagicWasFoundThenBinaryIsValidLLvm) { + EXPECT_TRUE(NEO::isLlvmBitcode(llvmBinary)); +} + +TEST(IsLlvmBitcode, WhenBinaryIsNullptrThenBinaryIsNotValidLLvm) { + EXPECT_FALSE(NEO::isLlvmBitcode(ArrayRef())); +} + +TEST(IsLlvmBitcode, WhenBinaryIsShorterThanLllvMagicThenBinaryIsNotValidLLvm) { + EXPECT_FALSE(NEO::isLlvmBitcode(ArrayRef(llvmBinary, 2))); +} + +TEST(IsLlvmBitcode, WhenBinaryDoesNotContainLllvMagicThenBinaryIsNotValidLLvm) { + const uint8_t notLlvmBinary[] = "ABCDEFGHIJKLMNO"; + EXPECT_FALSE(NEO::isLlvmBitcode(notLlvmBinary)); +} + +static constexpr uint32_t spirv[16] = {0x03022307}; +static constexpr uint32_t spirvInvEndianes[16] = {0x07230203}; + +TEST(IsSpirVBitcode, WhenSpirvMagicWasFoundThenBinaryIsValidSpirv) { + EXPECT_TRUE(NEO::isSpirVBitcode(ArrayRef(reinterpret_cast(&spirv), sizeof(spirv)))); + EXPECT_TRUE(NEO::isSpirVBitcode(ArrayRef(reinterpret_cast(&spirvInvEndianes), sizeof(spirvInvEndianes)))); +} + +TEST(IsSpirVBitcode, WhenBinaryIsNullptrThenBinaryIsNotValidSpirv) { + EXPECT_FALSE(NEO::isSpirVBitcode(ArrayRef())); +} + +TEST(IsSpirVBitcode, WhenBinaryIsShorterThanLllvMagicThenBinaryIsNotValidSpirv) { + EXPECT_FALSE(NEO::isSpirVBitcode(ArrayRef(reinterpret_cast(&spirvInvEndianes), 2))); +} + +TEST(IsSpirVBitcode, WhenBinaryDoesNotContainLllvMagicThenBinaryIsNotValidSpirv) { + const uint8_t notSpirvBinary[] = "ABCDEFGHIJKLMNO"; + EXPECT_FALSE(NEO::isSpirVBitcode(notSpirvBinary)); +} diff --git a/core/unit_tests/device_binary_format/CMakeLists.txt b/core/unit_tests/device_binary_format/CMakeLists.txt index 9b5c7f428d..5051f7cb87 100644 --- a/core/unit_tests/device_binary_format/CMakeLists.txt +++ b/core/unit_tests/device_binary_format/CMakeLists.txt @@ -6,6 +6,11 @@ set(NEO_DEVICE_BINARY_FORMAT_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_decoder_tests.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_encoder_tests.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/device_binary_format_ocl_elf_tests.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/device_binary_format_patchtokens_tests.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/device_binary_formats_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_decoder_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_dumper_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_tests.h diff --git a/core/unit_tests/device_binary_format/device_binary_format_ocl_elf_tests.cpp b/core/unit_tests/device_binary_format/device_binary_format_ocl_elf_tests.cpp new file mode 100644 index 0000000000..76fa75b07d --- /dev/null +++ b/core/unit_tests/device_binary_format/device_binary_format_ocl_elf_tests.cpp @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "core/compiler_interface/intermediate_representations.h" +#include "core/device_binary_format/device_binary_formats.h" +#include "core/device_binary_format/elf/elf_decoder.h" +#include "core/device_binary_format/elf/elf_encoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" +#include "core/program/program_info.h" +#include "core/unit_tests/device_binary_format/patchtokens_tests.h" +#include "test.h" + +#include +#include + +TEST(IsDeviceBinaryFormatOclElf, GivenElfThenReturnsTrueIfProperElfFileTypeDetected) { + NEO::Elf::ElfEncoder elfEnc64; + + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + EXPECT_TRUE(NEO::isDeviceBinaryFormat(elfEnc64.encode())); + + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_OBJECTS; + EXPECT_TRUE(NEO::isDeviceBinaryFormat(elfEnc64.encode())); + + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_LIBRARY; + EXPECT_TRUE(NEO::isDeviceBinaryFormat(elfEnc64.encode())); + + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_DEBUG; + EXPECT_FALSE(NEO::isDeviceBinaryFormat(elfEnc64.encode())); + + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_SOURCE; + EXPECT_FALSE(NEO::isDeviceBinaryFormat(elfEnc64.encode())); + + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_NONE; + EXPECT_FALSE(NEO::isDeviceBinaryFormat(elfEnc64.encode())); + + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_EXEC; + EXPECT_FALSE(NEO::isDeviceBinaryFormat(elfEnc64.encode())); + + NEO::Elf::ElfEncoder elfEnc32; + elfEnc32.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + EXPECT_FALSE(NEO::isDeviceBinaryFormat(elfEnc32.encode())); +} + +TEST(UnpackSingleDeviceBinaryOclElf, WhenFailedToDecodeElfThenUnpackingFails) { + std::string unpackErrors; + std::string unpackWarnings; + auto unpackResult = NEO::unpackSingleDeviceBinary({}, "", {}, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::Unknown, unpackResult.format); + EXPECT_TRUE(unpackResult.deviceBinary.empty()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_STREQ("Invalid or missing ELF header", unpackErrors.c_str()); +} + +TEST(UnpackSingleDeviceBinaryOclElf, GivenNotOclElfThenUnpackingFails) { + NEO::Elf::ElfEncoder elfEnc64; + std::string unpackErrors; + std::string unpackWarnings; + auto unpackResult = NEO::unpackSingleDeviceBinary(elfEnc64.encode(), "", {}, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::Unknown, unpackResult.format); + EXPECT_TRUE(unpackResult.deviceBinary.empty()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_STREQ("Not OCL ELF file type", unpackErrors.c_str()); +} + +TEST(UnpackSingleDeviceBinaryOclElf, GivenOclElfThenSetsProperOutputFormat) { + NEO::Elf::ElfEncoder elfEnc64; + std::string unpackErrors; + std::string unpackWarnings; + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + auto unpackResult = NEO::unpackSingleDeviceBinary(elfEnc64.encode(), "", {}, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::Patchtokens, unpackResult.format); + EXPECT_TRUE(unpackResult.deviceBinary.empty()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_TRUE(unpackErrors.empty()); + + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_LIBRARY; + elfEnc64.appendSection(NEO::Elf::SHT_OPENCL_SPIRV, NEO::Elf::SectionNamesOpenCl::spirvObject, ArrayRef::fromAny(NEO::spirvMagic.begin(), NEO::spirvMagic.size())); + auto elfData = elfEnc64.encode(); + unpackResult = NEO::unpackSingleDeviceBinary(elfData, "", {}, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::OclLibrary, unpackResult.format); + EXPECT_TRUE(unpackResult.deviceBinary.empty()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_TRUE(unpackErrors.empty()); + EXPECT_FALSE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(NEO::isSpirVBitcode(unpackResult.intermediateRepresentation)); + EXPECT_EQ(NEO::spirvMagic.size(), unpackResult.intermediateRepresentation.size()); + + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_OBJECTS; + elfEnc64.appendSection(NEO::Elf::SHT_OPENCL_LLVM_BINARY, NEO::Elf::SectionNamesOpenCl::llvmObject, ArrayRef::fromAny(NEO::llvmBcMagic.begin(), NEO::llvmBcMagic.size())); + elfData = elfEnc64.encode(); + unpackResult = NEO::unpackSingleDeviceBinary(elfData, "", {}, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::OclCompiledObject, unpackResult.format); + EXPECT_TRUE(unpackResult.deviceBinary.empty()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_TRUE(unpackErrors.empty()); + EXPECT_FALSE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(NEO::isLlvmBitcode(unpackResult.intermediateRepresentation)); + EXPECT_EQ(NEO::llvmBcMagic.size(), unpackResult.intermediateRepresentation.size()); +} + +TEST(UnpackSingleDeviceBinaryOclElf, GivenValidOclElfExecutableThenReadsAllSectionProperly) { + PatchTokensTestData::ValidEmptyProgram patchtokensProgram; + NEO::TargetDevice targetDevice; + targetDevice.coreFamily = static_cast(patchtokensProgram.header->Device); + targetDevice.stepping = patchtokensProgram.header->SteppingId; + targetDevice.maxPointerSizeInBytes = patchtokensProgram.header->GPUPointerSizeInBytes; + + const uint8_t intermediateRepresentation[] = "235711"; + const uint8_t debugData[] = "313739"; + std::string buildOptions = "buildOpts"; + NEO::Elf::ElfEncoder elfEnc64; + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + std::string unpackErrors; + std::string unpackWarnings; + elfEnc64.appendSection(NEO::Elf::SHT_OPENCL_DEV_BINARY, NEO::Elf::SectionNamesOpenCl::deviceBinary, patchtokensProgram.storage); + elfEnc64.appendSection(NEO::Elf::SHT_OPENCL_OPTIONS, NEO::Elf::SectionNamesOpenCl::buildOptions, buildOptions); + elfEnc64.appendSection(NEO::Elf::SHT_OPENCL_DEV_DEBUG, NEO::Elf::SectionNamesOpenCl::buildOptions, debugData); + { + auto encWithLlvm = elfEnc64; + encWithLlvm.appendSection(NEO::Elf::SHT_OPENCL_LLVM_BINARY, NEO::Elf::SectionNamesOpenCl::llvmObject, intermediateRepresentation); + auto elfData = encWithLlvm.encode(); + auto unpackResult = NEO::unpackSingleDeviceBinary(elfData, "", targetDevice, unpackErrors, unpackWarnings); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_TRUE(unpackErrors.empty()); + EXPECT_EQ(NEO::DeviceBinaryFormat::Patchtokens, unpackResult.format); + ASSERT_EQ(patchtokensProgram.storage.size(), unpackResult.deviceBinary.size()); + ASSERT_EQ(sizeof(debugData), unpackResult.debugData.size()); + ASSERT_EQ(buildOptions.size() + 1, unpackResult.buildOptions.size()); + ASSERT_EQ(sizeof(intermediateRepresentation), unpackResult.intermediateRepresentation.size()); + + EXPECT_EQ(0, memcmp(patchtokensProgram.storage.data(), unpackResult.deviceBinary.begin(), unpackResult.deviceBinary.size())); + EXPECT_STREQ(buildOptions.c_str(), unpackResult.buildOptions.begin()); + EXPECT_EQ(0, memcmp(debugData, unpackResult.debugData.begin(), unpackResult.debugData.size())); + EXPECT_EQ(0, memcmp(intermediateRepresentation, unpackResult.intermediateRepresentation.begin(), unpackResult.intermediateRepresentation.size())); + } + { + auto encWithSpirV = elfEnc64; + encWithSpirV.appendSection(NEO::Elf::SHT_OPENCL_SPIRV, NEO::Elf::SectionNamesOpenCl::spirvObject, intermediateRepresentation); + auto elfData = encWithSpirV.encode(); + auto unpackResult = NEO::unpackSingleDeviceBinary(elfData, "", targetDevice, unpackErrors, unpackWarnings); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_TRUE(unpackErrors.empty()); + EXPECT_EQ(NEO::DeviceBinaryFormat::Patchtokens, unpackResult.format); + ASSERT_EQ(patchtokensProgram.storage.size(), unpackResult.deviceBinary.size()); + ASSERT_EQ(sizeof(debugData), unpackResult.debugData.size()); + ASSERT_EQ(buildOptions.size() + 1, unpackResult.buildOptions.size()); + ASSERT_EQ(sizeof(intermediateRepresentation), unpackResult.intermediateRepresentation.size()); + + EXPECT_EQ(0, memcmp(patchtokensProgram.storage.data(), unpackResult.deviceBinary.begin(), unpackResult.deviceBinary.size())); + EXPECT_STREQ(buildOptions.c_str(), unpackResult.buildOptions.begin()); + EXPECT_EQ(0, memcmp(debugData, unpackResult.debugData.begin(), unpackResult.debugData.size())); + EXPECT_EQ(0, memcmp(intermediateRepresentation, unpackResult.intermediateRepresentation.begin(), unpackResult.intermediateRepresentation.size())); + } +} + +TEST(UnpackSingleDeviceBinaryOclElf, GivenOclElfExecutableWithUnhandledSectionThenUnpackingFails) { + NEO::Elf::ElfEncoder elfEnc64; + std::string unpackErrors; + std::string unpackWarnings; + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + elfEnc64.appendSection(NEO::Elf::SHT_NOBITS, "my_data", {}); + auto unpackResult = NEO::unpackSingleDeviceBinary(elfEnc64.encode(), "", {}, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::Unknown, unpackResult.format); + EXPECT_TRUE(unpackResult.deviceBinary.empty()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_STREQ("Unhandled ELF section", unpackErrors.c_str()); +} + +TEST(UnpackSingleDeviceBinaryOclElf, GivenOclElfExecutableWhenPatchtokensBinaryIsBrokenThenReadsAllSectionProperly) { + const uint8_t intermediateRepresentation[] = "235711"; + const uint8_t debugData[] = "313739"; + const uint8_t deviceBinary[] = "not_patchtokens"; + std::string buildOptions = "buildOpts"; + NEO::Elf::ElfEncoder elfEnc64; + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + std::string unpackErrors; + std::string unpackWarnings; + elfEnc64.appendSection(NEO::Elf::SHT_OPENCL_DEV_BINARY, NEO::Elf::SectionNamesOpenCl::deviceBinary, deviceBinary); + elfEnc64.appendSection(NEO::Elf::SHT_OPENCL_OPTIONS, NEO::Elf::SectionNamesOpenCl::buildOptions, buildOptions); + elfEnc64.appendSection(NEO::Elf::SHT_OPENCL_DEV_DEBUG, NEO::Elf::SectionNamesOpenCl::buildOptions, debugData); + elfEnc64.appendSection(NEO::Elf::SHT_OPENCL_SPIRV, NEO::Elf::SectionNamesOpenCl::spirvObject, intermediateRepresentation); + + auto unpackResult = NEO::unpackSingleDeviceBinary(elfEnc64.encode(), "", {}, unpackErrors, unpackWarnings); + EXPECT_FALSE(unpackErrors.empty()); + EXPECT_STREQ("Invalid program header", unpackErrors.c_str()); + EXPECT_EQ(NEO::DeviceBinaryFormat::Patchtokens, unpackResult.format); + EXPECT_TRUE(unpackResult.deviceBinary.empty()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_FALSE(unpackResult.intermediateRepresentation.empty()); + EXPECT_FALSE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); +} + +TEST(DecodeSingleDeviceBinaryOclElf, WhenUsedAsSingleDeviceBinaryThenDecodingFails) { + PatchTokensTestData::ValidEmptyProgram patchtokensProgram; + ; + + NEO::Elf::ElfEncoder elfEnc64; + elfEnc64.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + elfEnc64.appendSection(NEO::Elf::SHT_OPENCL_DEV_BINARY, NEO::Elf::SectionNamesOpenCl::deviceBinary, patchtokensProgram.storage); + auto elfData = elfEnc64.encode(); + + NEO::TargetDevice targetDevice; + targetDevice.coreFamily = static_cast(patchtokensProgram.header->Device); + targetDevice.stepping = patchtokensProgram.header->SteppingId; + targetDevice.maxPointerSizeInBytes = patchtokensProgram.header->GPUPointerSizeInBytes; + + NEO::SingleDeviceBinary deviceBinary; + deviceBinary.targetDevice = targetDevice; + deviceBinary.deviceBinary = elfData; + + std::string unpackErrors; + std::string unpackWarnings; + NEO::ProgramInfo programInfo; + NEO::DecodeError error = NEO::decodeSingleDeviceBinary(programInfo, deviceBinary, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, error); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_FALSE(unpackErrors.empty()); + EXPECT_STREQ("Device binary format is packed", unpackErrors.c_str()); +} + +TEST(PackDeviceBinaryOclElf, WhenPackingEmptyDataThenEmptyOclElfIsEmitted) { + NEO::SingleDeviceBinary singleBinary; + + std::string packErrors; + std::string packWarnings; + auto packedData = NEO::packDeviceBinary(singleBinary, packErrors, packWarnings); + EXPECT_TRUE(packWarnings.empty()); + EXPECT_TRUE(packErrors.empty()); + + ASSERT_TRUE(NEO::isDeviceBinaryFormat(packedData)); + + std::string decodeElfErrors; + std::string decodeElfWarnings; + auto elf = NEO::Elf::decodeElf(packedData, decodeElfErrors, decodeElfWarnings); + EXPECT_TRUE(decodeElfErrors.empty()); + EXPECT_TRUE(decodeElfWarnings.empty()); + ASSERT_NE(nullptr, elf.elfFileHeader); + + EXPECT_EQ(NEO::Elf::ET_OPENCL_EXECUTABLE, elf.elfFileHeader->type); + EXPECT_EQ(0U, elf.elfFileHeader->shNum); +} + +TEST(PackDeviceBinaryOclElf, WhenPackingBinaryWithUnknownIntermediateRepresentationThenFail) { + const uint8_t intermediateRepresentation[] = "not_llvm_and_not_spirv"; + NEO::SingleDeviceBinary singleBinary; + singleBinary.intermediateRepresentation = intermediateRepresentation; + + std::string packErrors; + std::string packWarnings; + auto packedData = NEO::packDeviceBinary(singleBinary, packErrors, packWarnings); + EXPECT_TRUE(packedData.empty()); + EXPECT_TRUE(packWarnings.empty()); + EXPECT_FALSE(packErrors.empty()); + EXPECT_STREQ("Unknown intermediate representation format", packErrors.c_str()); +} + +TEST(PackDeviceBinaryOclElf, WhenPackingBinaryWitIntermediateRepresentationThenChoosesProperSectionBasedOnMagic) { + using namespace NEO::Elf; + auto spirV = NEO::spirvMagic; + auto llvmBc = NEO::llvmBcMagic; + NEO::SingleDeviceBinary singleBinary; + + { + singleBinary.intermediateRepresentation = ArrayRef::fromAny(spirV.begin(), spirV.size()); + + std::string packErrors; + std::string packWarnings; + auto packedData = NEO::packDeviceBinary(singleBinary, packErrors, packWarnings); + EXPECT_FALSE(packedData.empty()); + EXPECT_TRUE(packWarnings.empty()); + EXPECT_TRUE(packErrors.empty()); + + ASSERT_TRUE(NEO::isDeviceBinaryFormat(packedData)); + + std::string decodeElfErrors; + std::string decodeElfWarnings; + auto elf = NEO::Elf::decodeElf(packedData, decodeElfErrors, decodeElfWarnings); + EXPECT_TRUE(decodeElfErrors.empty()); + EXPECT_TRUE(decodeElfWarnings.empty()); + ASSERT_NE(nullptr, elf.elfFileHeader); + + EXPECT_EQ(NEO::Elf::ET_OPENCL_EXECUTABLE, elf.elfFileHeader->type); + EXPECT_EQ(3U, elf.elfFileHeader->shNum); + + auto spirVSection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(), + [](const Elf<>::SectionHeaderAndData §ion) { return section.header->type == NEO::Elf::SHT_OPENCL_SPIRV; }); + ASSERT_NE(nullptr, spirVSection); + ASSERT_EQ(spirV.size(), spirVSection->data.size()); + EXPECT_EQ(0, memcmp(spirV.begin(), spirVSection->data.begin(), spirV.size())); + } + + { + singleBinary.intermediateRepresentation = ArrayRef::fromAny(llvmBc.begin(), llvmBc.size()); + + std::string packErrors; + std::string packWarnings; + auto packedData = NEO::packDeviceBinary(singleBinary, packErrors, packWarnings); + EXPECT_FALSE(packedData.empty()); + EXPECT_TRUE(packWarnings.empty()); + EXPECT_TRUE(packErrors.empty()); + + ASSERT_TRUE(NEO::isDeviceBinaryFormat(packedData)); + + std::string decodeElfErrors; + std::string decodeElfWarnings; + auto elf = NEO::Elf::decodeElf(packedData, decodeElfErrors, decodeElfWarnings); + EXPECT_TRUE(decodeElfErrors.empty()); + EXPECT_TRUE(decodeElfWarnings.empty()); + ASSERT_NE(nullptr, elf.elfFileHeader); + + EXPECT_EQ(NEO::Elf::ET_OPENCL_EXECUTABLE, elf.elfFileHeader->type); + EXPECT_EQ(3U, elf.elfFileHeader->shNum); + + auto llvmSection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(), + [](const Elf<>::SectionHeaderAndData §ion) { return section.header->type == NEO::Elf::SHT_OPENCL_LLVM_BINARY; }); + ASSERT_NE(nullptr, llvmSection); + ASSERT_EQ(llvmBc.size(), llvmSection->data.size()); + EXPECT_EQ(0, memcmp(llvmBc.begin(), llvmSection->data.begin(), llvmBc.size())); + } +} + +TEST(PackDeviceBinaryOclElf, WhenPackingBinaryThenSectionsAreProperlyPopulated) { + using namespace NEO::Elf; + NEO::SingleDeviceBinary singleBinary; + + auto spirV = NEO::spirvMagic; + const uint8_t debugData[] = "313739"; + const uint8_t deviceBinary[] = "23571113"; + std::string buildOptions = "buildOpts"; + singleBinary.intermediateRepresentation = ArrayRef::fromAny(spirV.begin(), spirV.size()); + singleBinary.debugData = debugData; + singleBinary.deviceBinary = deviceBinary; + singleBinary.buildOptions = buildOptions; + + std::string packErrors; + std::string packWarnings; + auto packedData = NEO::packDeviceBinary(singleBinary, packErrors, packWarnings); + EXPECT_TRUE(packErrors.empty()); + EXPECT_TRUE(packWarnings.empty()); + + std::string decodeElfErrors; + std::string decodeElfWarnings; + auto elf = NEO::Elf::decodeElf(packedData, decodeElfErrors, decodeElfWarnings); + EXPECT_TRUE(decodeElfErrors.empty()); + EXPECT_TRUE(decodeElfWarnings.empty()); + ASSERT_NE(nullptr, elf.elfFileHeader); + + auto spirvSection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(), + [](const Elf<>::SectionHeaderAndData §ion) { return section.header->type == NEO::Elf::SHT_OPENCL_SPIRV; }); + + auto deviceBinarySection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(), + [](const Elf<>::SectionHeaderAndData §ion) { return section.header->type == NEO::Elf::SHT_OPENCL_DEV_BINARY; }); + + auto deviceDebugSection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(), + [](const Elf<>::SectionHeaderAndData §ion) { return section.header->type == NEO::Elf::SHT_OPENCL_DEV_DEBUG; }); + + auto buildOptionsSection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(), + [](const Elf<>::SectionHeaderAndData §ion) { return section.header->type == NEO::Elf::SHT_OPENCL_OPTIONS; }); + + ASSERT_NE(nullptr, spirvSection); + ASSERT_EQ(spirV.size(), spirvSection->data.size()); + EXPECT_EQ(0, memcmp(spirV.begin(), spirvSection->data.begin(), spirV.size())); + + ASSERT_NE(nullptr, deviceBinarySection); + ASSERT_EQ(sizeof(deviceBinary), deviceBinarySection->data.size()); + EXPECT_EQ(0, memcmp(deviceBinary, deviceBinarySection->data.begin(), sizeof(deviceBinary))); + + ASSERT_NE(nullptr, deviceDebugSection); + ASSERT_EQ(sizeof(debugData), deviceDebugSection->data.size()); + EXPECT_EQ(0, memcmp(debugData, deviceDebugSection->data.begin(), sizeof(debugData))); + + ASSERT_NE(nullptr, buildOptionsSection); + ASSERT_EQ(buildOptions.size(), buildOptionsSection->data.size()); + EXPECT_EQ(0, memcmp(buildOptions.c_str(), buildOptionsSection->data.begin(), buildOptions.size())); +} diff --git a/core/unit_tests/device_binary_format/device_binary_format_patchtokens_tests.cpp b/core/unit_tests/device_binary_format/device_binary_format_patchtokens_tests.cpp new file mode 100644 index 0000000000..c50fc9b815 --- /dev/null +++ b/core/unit_tests/device_binary_format/device_binary_format_patchtokens_tests.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "core/device_binary_format/device_binary_formats.h" +#include "core/program/program_info.h" +#include "core/unit_tests/device_binary_format/patchtokens_tests.h" +#include "test.h" + +TEST(IsDeviceBinaryFormatPatchtokens, GiveValidBinaryReturnTrue) { + PatchTokensTestData::ValidProgramWithKernel programTokens; + EXPECT_TRUE(NEO::isDeviceBinaryFormat(programTokens.storage)); +} + +TEST(IsDeviceBinaryFormatPatchtokens, GiveInvalidBinaryReturnTrue) { + const uint8_t binary[] = "not_patchtokens"; + EXPECT_FALSE(NEO::isDeviceBinaryFormat(binary)); +} + +TEST(UnpackSingleDeviceBinaryPatchtokens, WhenFailedToDecodeHeaderThenUnpackingFails) { + std::string unpackErrors; + std::string unpackWarnings; + auto unpackResult = NEO::unpackSingleDeviceBinary({}, "", {}, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::Unknown, unpackResult.format); + EXPECT_TRUE(unpackResult.deviceBinary.empty()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_STREQ("Invalid program header", unpackErrors.c_str()); +} + +TEST(UnpackSingleDeviceBinaryPatchtokens, WhenValidBinaryAndMatchedWithRequestedTargetDeviceThenReturnSelf) { + PatchTokensTestData::ValidProgramWithKernel programTokens; + NEO::TargetDevice targetDevice; + targetDevice.coreFamily = static_cast(programTokens.header->Device); + targetDevice.stepping = programTokens.header->SteppingId; + targetDevice.maxPointerSizeInBytes = programTokens.header->GPUPointerSizeInBytes; + + std::string unpackErrors; + std::string unpackWarnings; + auto unpackResult = NEO::unpackSingleDeviceBinary(programTokens.storage, "", targetDevice, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::Patchtokens, unpackResult.format); + EXPECT_EQ(targetDevice.coreFamily, unpackResult.targetDevice.coreFamily); + EXPECT_EQ(targetDevice.stepping, unpackResult.targetDevice.stepping); + EXPECT_EQ(targetDevice.maxPointerSizeInBytes, unpackResult.targetDevice.maxPointerSizeInBytes); + EXPECT_FALSE(unpackResult.deviceBinary.empty()); + EXPECT_EQ(programTokens.storage.data(), unpackResult.deviceBinary.begin()); + EXPECT_EQ(programTokens.storage.size(), unpackResult.deviceBinary.size()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_TRUE(unpackErrors.empty()); +} + +TEST(UnpackSingleDeviceBinaryPatchtokens, WhenValidBinaryForDifferentCoreFamilyDeviceThenUnpackingFails) { + PatchTokensTestData::ValidProgramWithKernel programTokens; + NEO::TargetDevice targetDevice; + targetDevice.coreFamily = static_cast(programTokens.header->Device + 1); + targetDevice.stepping = programTokens.header->SteppingId; + targetDevice.maxPointerSizeInBytes = programTokens.header->GPUPointerSizeInBytes; + + std::string unpackErrors; + std::string unpackWarnings; + auto unpackResult = NEO::unpackSingleDeviceBinary(programTokens.storage, "", targetDevice, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::Unknown, unpackResult.format); + EXPECT_EQ(IGFX_UNKNOWN_CORE, unpackResult.targetDevice.coreFamily); + EXPECT_EQ(0U, unpackResult.targetDevice.stepping); + EXPECT_EQ(4U, unpackResult.targetDevice.maxPointerSizeInBytes); + EXPECT_TRUE(unpackResult.deviceBinary.empty()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_FALSE(unpackErrors.empty()); + EXPECT_STREQ("Unhandled target device", unpackErrors.c_str()); +} + +TEST(UnpackSingleDeviceBinaryPatchtokens, WhenValidBinaryWithUnsupportedPatchTokensVerionThenUnpackingFails) { + PatchTokensTestData::ValidProgramWithKernel programTokens; + programTokens.headerMutable->Version += 1; + NEO::TargetDevice targetDevice; + targetDevice.coreFamily = static_cast(programTokens.header->Device); + targetDevice.stepping = programTokens.header->SteppingId; + targetDevice.maxPointerSizeInBytes = programTokens.header->GPUPointerSizeInBytes; + + std::string unpackErrors; + std::string unpackWarnings; + auto unpackResult = NEO::unpackSingleDeviceBinary(programTokens.storage, "", targetDevice, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::Unknown, unpackResult.format); + EXPECT_EQ(IGFX_UNKNOWN_CORE, unpackResult.targetDevice.coreFamily); + EXPECT_EQ(0U, unpackResult.targetDevice.stepping); + EXPECT_EQ(4U, unpackResult.targetDevice.maxPointerSizeInBytes); + EXPECT_TRUE(unpackResult.deviceBinary.empty()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_FALSE(unpackErrors.empty()); + EXPECT_STREQ("Unhandled target device", unpackErrors.c_str()); +} + +TEST(UnpackSingleDeviceBinaryPatchtokens, WhenValidBinaryWithUnsupportedPointerSizeThenUnpackingFails) { + PatchTokensTestData::ValidProgramWithKernel programTokens; + programTokens.headerMutable->GPUPointerSizeInBytes = 8U; + NEO::TargetDevice targetDevice; + targetDevice.coreFamily = static_cast(programTokens.header->Device); + targetDevice.stepping = programTokens.header->SteppingId; + targetDevice.maxPointerSizeInBytes = 4U; + + std::string unpackErrors; + std::string unpackWarnings; + auto unpackResult = NEO::unpackSingleDeviceBinary(programTokens.storage, "", targetDevice, unpackErrors, unpackWarnings); + EXPECT_EQ(NEO::DeviceBinaryFormat::Unknown, unpackResult.format); + EXPECT_EQ(IGFX_UNKNOWN_CORE, unpackResult.targetDevice.coreFamily); + EXPECT_EQ(0U, unpackResult.targetDevice.stepping); + EXPECT_EQ(4U, unpackResult.targetDevice.maxPointerSizeInBytes); + EXPECT_TRUE(unpackResult.deviceBinary.empty()); + EXPECT_TRUE(unpackResult.debugData.empty()); + EXPECT_TRUE(unpackResult.intermediateRepresentation.empty()); + EXPECT_TRUE(unpackResult.buildOptions.empty()); + EXPECT_TRUE(unpackWarnings.empty()); + EXPECT_FALSE(unpackErrors.empty()); + EXPECT_STREQ("Unhandled target device", unpackErrors.c_str()); +} + +TEST(DecodeSingleDeviceBinaryPatchtokens, GivenInvalidBinaryThenReturnError) { + NEO::ProgramInfo programInfo; + NEO::SingleDeviceBinary singleBinary; + std::string decodeErrors; + std::string decodeWarnings; + auto error = NEO::decodeSingleDeviceBinary(programInfo, singleBinary, decodeErrors, decodeWarnings); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, error); + EXPECT_TRUE(decodeWarnings.empty()); + EXPECT_FALSE(decodeErrors.empty()); + EXPECT_STREQ("ProgramFromPatchtokens wasn't successfully decoded", decodeErrors.c_str()); +} + +TEST(DecodeSingleDeviceBinaryPatchtokens, GivenValidBinaryThenOutputIsProperlyPopulated) { + PatchTokensTestData::ValidProgramWithKernel programTokens; + NEO::ProgramInfo programInfo; + NEO::SingleDeviceBinary singleBinary; + singleBinary.deviceBinary = programTokens.storage; + std::string decodeErrors; + std::string decodeWarnings; + auto error = NEO::decodeSingleDeviceBinary(programInfo, singleBinary, decodeErrors, decodeWarnings); + EXPECT_EQ(NEO::DecodeError::Success, error); + EXPECT_TRUE(decodeWarnings.empty()); + EXPECT_TRUE(decodeErrors.empty()); + ASSERT_EQ(1U, programInfo.kernelInfos.size()); +} diff --git a/core/unit_tests/device_binary_format/device_binary_formats_tests.cpp b/core/unit_tests/device_binary_format/device_binary_formats_tests.cpp new file mode 100644 index 0000000000..8dcc95b039 --- /dev/null +++ b/core/unit_tests/device_binary_format/device_binary_formats_tests.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "core/device_binary_format/device_binary_formats.h" +#include "core/device_binary_format/elf/elf_encoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" +#include "core/program/program_info.h" +#include "core/unit_tests/device_binary_format/patchtokens_tests.h" +#include "test.h" + +TEST(DecodeError, WhenStringRepresentationIsNeededThenAsStringEncodesProperly) { + EXPECT_STREQ("decoded successfully", NEO::asString(NEO::DecodeError::Success)); + EXPECT_STREQ("in undefined status", NEO::asString(NEO::DecodeError::Undefined)); + EXPECT_STREQ("with invalid binary", NEO::asString(NEO::DecodeError::InvalidBinary)); + EXPECT_STREQ("with unhandled binary", NEO::asString(NEO::DecodeError::UnhandledBinary)); +} + +TEST(IsAnyDeviceBinaryFormat, GivenNoneOfKnownFormatsThenReturnsFalse) { + const uint8_t data[] = "none of known formats"; + EXPECT_FALSE(NEO::isAnyDeviceBinaryFormat(data)); +} + +TEST(IsAnyDeviceBinaryFormat, GivenPatchTokensFormatThenReturnsTrue) { + PatchTokensTestData::ValidEmptyProgram patchtokensProgram; + EXPECT_TRUE(NEO::isAnyDeviceBinaryFormat(patchtokensProgram.storage)); +} + +TEST(IsAnyDeviceBinaryFormat, GivenOclElfFormatThenReturnsTrue) { + NEO::Elf::ElfEncoder elfEnc; + elfEnc.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + EXPECT_TRUE(NEO::isAnyDeviceBinaryFormat(elfEnc.encode())); +} + +TEST(UnpackSingleDeviceBinary, GivenUnknownBinaryThenReturnError) { + const uint8_t data[] = "none of known formats"; + ConstStringRef requestedProductAbbreviation = "unk"; + NEO::TargetDevice requestedTargetDevice; + std::string outErrors; + std::string outWarnings; + auto unpacked = NEO::unpackSingleDeviceBinary(data, requestedProductAbbreviation, requestedTargetDevice, outErrors, outWarnings); + EXPECT_TRUE(unpacked.buildOptions.empty()); + EXPECT_TRUE(unpacked.debugData.empty()); + EXPECT_TRUE(unpacked.deviceBinary.empty()); + EXPECT_TRUE(unpacked.intermediateRepresentation.empty()); + EXPECT_EQ(NEO::DeviceBinaryFormat::Unknown, unpacked.format); + EXPECT_EQ(0U, unpacked.targetDevice.coreFamily); + EXPECT_EQ(0U, unpacked.targetDevice.stepping); + EXPECT_EQ(4U, unpacked.targetDevice.maxPointerSizeInBytes); + EXPECT_TRUE(outWarnings.empty()); + EXPECT_STREQ("Unknown format", outErrors.c_str()); +} + +TEST(UnpackSingleDeviceBinary, GivenPatchtoknsBinaryThenReturnSelf) { + PatchTokensTestData::ValidEmptyProgram patchtokensProgram; + ConstStringRef requestedProductAbbreviation = "unk"; + NEO::TargetDevice requestedTargetDevice; + requestedTargetDevice.coreFamily = static_cast(patchtokensProgram.header->Device); + requestedTargetDevice.stepping = patchtokensProgram.header->Device; + requestedTargetDevice.maxPointerSizeInBytes = patchtokensProgram.header->GPUPointerSizeInBytes; + std::string outErrors; + std::string outWarnings; + auto unpacked = NEO::unpackSingleDeviceBinary(patchtokensProgram.storage, requestedProductAbbreviation, requestedTargetDevice, outErrors, outWarnings); + EXPECT_TRUE(unpacked.buildOptions.empty()); + EXPECT_TRUE(unpacked.debugData.empty()); + EXPECT_FALSE(unpacked.deviceBinary.empty()); + EXPECT_EQ(patchtokensProgram.storage.data(), unpacked.deviceBinary.begin()); + EXPECT_EQ(patchtokensProgram.storage.size(), unpacked.deviceBinary.size()); + EXPECT_TRUE(unpacked.intermediateRepresentation.empty()); + EXPECT_EQ(NEO::DeviceBinaryFormat::Patchtokens, unpacked.format); + EXPECT_EQ(requestedTargetDevice.coreFamily, unpacked.targetDevice.coreFamily); + EXPECT_EQ(requestedTargetDevice.stepping, unpacked.targetDevice.stepping); + EXPECT_EQ(patchtokensProgram.header->GPUPointerSizeInBytes, unpacked.targetDevice.maxPointerSizeInBytes); + EXPECT_TRUE(outWarnings.empty()); + EXPECT_TRUE(outErrors.empty()); +} + +TEST(UnpackSingleDeviceBinary, GivenOclElfBinaryThenReturnPatchtokensBinary) { + PatchTokensTestData::ValidEmptyProgram patchtokensProgram; + + NEO::Elf::ElfEncoder elfEnc; + elfEnc.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + elfEnc.appendSection(NEO::Elf::SHT_OPENCL_DEV_BINARY, NEO::Elf::SectionNamesOpenCl::deviceBinary, patchtokensProgram.storage); + + ConstStringRef requestedProductAbbreviation = "unk"; + NEO::TargetDevice requestedTargetDevice; + requestedTargetDevice.coreFamily = static_cast(patchtokensProgram.header->Device); + requestedTargetDevice.stepping = patchtokensProgram.header->Device; + requestedTargetDevice.maxPointerSizeInBytes = patchtokensProgram.header->GPUPointerSizeInBytes; + std::string outErrors; + std::string outWarnings; + auto elfData = elfEnc.encode(); + auto unpacked = NEO::unpackSingleDeviceBinary(elfData, requestedProductAbbreviation, requestedTargetDevice, outErrors, outWarnings); + EXPECT_TRUE(unpacked.buildOptions.empty()); + EXPECT_TRUE(unpacked.debugData.empty()); + EXPECT_TRUE(unpacked.intermediateRepresentation.empty()); + EXPECT_EQ(NEO::DeviceBinaryFormat::Patchtokens, unpacked.format); + EXPECT_EQ(requestedTargetDevice.coreFamily, unpacked.targetDevice.coreFamily); + EXPECT_EQ(requestedTargetDevice.stepping, unpacked.targetDevice.stepping); + EXPECT_EQ(patchtokensProgram.header->GPUPointerSizeInBytes, unpacked.targetDevice.maxPointerSizeInBytes); + EXPECT_TRUE(outWarnings.empty()); + EXPECT_TRUE(outErrors.empty()); + + EXPECT_FALSE(unpacked.deviceBinary.empty()); + ASSERT_EQ(patchtokensProgram.storage.size(), unpacked.deviceBinary.size()); + EXPECT_EQ(0, memcmp(patchtokensProgram.storage.data(), unpacked.deviceBinary.begin(), unpacked.deviceBinary.size())); +} + +TEST(IsAnyPackedDeviceBinaryFormat, GivenUnknownFormatThenReturnFalse) { + const uint8_t data[] = "none of known formats"; + EXPECT_FALSE(NEO::isAnyPackedDeviceBinaryFormat(data)); +} + +TEST(IsAnyPackedDeviceBinaryFormat, GivenPatchTokensFormatThenReturnsFalse) { + PatchTokensTestData::ValidEmptyProgram patchtokensProgram; + EXPECT_FALSE(NEO::isAnyPackedDeviceBinaryFormat(patchtokensProgram.storage)); +} + +TEST(IsAnyPackedDeviceBinaryFormat, GivenOclElfFormatThenReturnsTrue) { + NEO::Elf::ElfEncoder elfEnc; + elfEnc.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + EXPECT_TRUE(NEO::isAnyPackedDeviceBinaryFormat(elfEnc.encode())); +} + +TEST(IsAnySingleDeviceBinaryFormat, GivenUnknownFormatThenReturnFalse) { + const uint8_t data[] = "none of known formats"; + EXPECT_FALSE(NEO::isAnySingleDeviceBinaryFormat(data)); +} + +TEST(IsAnySingleDeviceBinaryFormat, GivenPatchTokensFormatThenReturnsTrue) { + PatchTokensTestData::ValidEmptyProgram patchtokensProgram; + EXPECT_TRUE(NEO::isAnySingleDeviceBinaryFormat(patchtokensProgram.storage)); +} + +TEST(IsAnySingleDeviceBinaryFormat, GivenOclElfFormatThenReturnsFalse) { + NEO::Elf::ElfEncoder elfEnc; + elfEnc.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + EXPECT_FALSE(NEO::isAnySingleDeviceBinaryFormat(elfEnc.encode())); +} + +TEST(DecodeSingleDeviceBinary, GivenUnknownFormatThenReturnFalse) { + const uint8_t data[] = "none of known formats"; + NEO::ProgramInfo programInfo; + std::string decodeErrors; + std::string decodeWarnings; + NEO::SingleDeviceBinary bin; + bin.deviceBinary = data; + NEO::DecodeError status; + NEO::DeviceBinaryFormat format; + std::tie(status, format) = NEO::decodeSingleDeviceBinary(programInfo, bin, decodeErrors, decodeWarnings); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, status); + EXPECT_EQ(NEO::DeviceBinaryFormat::Unknown, format); + EXPECT_TRUE(decodeWarnings.empty()); + EXPECT_STREQ("Unknown format", decodeErrors.c_str()); +} + +TEST(DecodeSingleDeviceBinary, GivenPatchTokensFormatThenDecodingSucceeds) { + PatchTokensTestData::ValidEmptyProgram patchtokensProgram; + NEO::ProgramInfo programInfo; + std::string decodeErrors; + std::string decodeWarnings; + NEO::SingleDeviceBinary bin; + bin.deviceBinary = patchtokensProgram.storage; + NEO::DecodeError status; + NEO::DeviceBinaryFormat format; + std::tie(status, format) = NEO::decodeSingleDeviceBinary(programInfo, bin, decodeErrors, decodeWarnings); + EXPECT_EQ(NEO::DecodeError::Success, status); + EXPECT_EQ(NEO::DeviceBinaryFormat::Patchtokens, format); + EXPECT_TRUE(decodeWarnings.empty()); + EXPECT_TRUE(decodeErrors.empty()); +} + +TEST(DecodeSingleDeviceBinary, GivenOclElfFormatThenDecodingFails) { + PatchTokensTestData::ValidEmptyProgram patchtokensProgram; + + NEO::Elf::ElfEncoder elfEnc; + elfEnc.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + elfEnc.appendSection(NEO::Elf::SHT_OPENCL_DEV_BINARY, NEO::Elf::SectionNamesOpenCl::deviceBinary, patchtokensProgram.storage); + + auto elfData = elfEnc.encode(); + NEO::ProgramInfo programInfo; + std::string decodeErrors; + std::string decodeWarnings; + NEO::SingleDeviceBinary bin; + bin.deviceBinary = elfData; + NEO::DecodeError status; + NEO::DeviceBinaryFormat format; + std::tie(status, format) = NEO::decodeSingleDeviceBinary(programInfo, bin, decodeErrors, decodeWarnings); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, status); + EXPECT_EQ(NEO::DeviceBinaryFormat::OclElf, format); + EXPECT_TRUE(decodeWarnings.empty()); + EXPECT_STREQ("Device binary format is packed", decodeErrors.c_str()); +} + +TEST(PackDeviceBinary, GivenRequestToPackThenUsesOclElfFormat) { + NEO::SingleDeviceBinary deviceBinary; + + std::string packErrors; + std::string packWarnings; + auto packed = NEO::packDeviceBinary(deviceBinary, packErrors, packWarnings); + EXPECT_TRUE(packErrors.empty()); + EXPECT_TRUE(packWarnings.empty()); + EXPECT_TRUE(NEO::isDeviceBinaryFormat(packed)); +} diff --git a/core/unit_tests/device_binary_format/elf/elf_decoder_tests.cpp b/core/unit_tests/device_binary_format/elf/elf_decoder_tests.cpp new file mode 100644 index 0000000000..db5ce1d797 --- /dev/null +++ b/core/unit_tests/device_binary_format/elf/elf_decoder_tests.cpp @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "core/device_binary_format/elf/elf_decoder.h" +#include "test.h" + +using namespace NEO::Elf; + +TEST(ElfDecoder, WhenEmptyDataThenElfHeaderDecodingFails) { + ArrayRef empty; + EXPECT_EQ(nullptr, decodeElfFileHeader(empty)); + EXPECT_EQ(nullptr, decodeElfFileHeader(empty)); +} + +TEST(ElfDecoder, WhenValidHaderThenElfHeaderDecodingSucceeds) { + ElfFileHeader header64; + EXPECT_EQ(&header64, decodeElfFileHeader(ArrayRef::fromAny(&header64, 1U))); + + ElfFileHeader header32; + EXPECT_EQ(&header32, decodeElfFileHeader(ArrayRef::fromAny(&header32, 1U))); +} + +TEST(ElfDecoder, WhenNotEngoughDataThenElfHeaderDecodingFails) { + ElfFileHeader header64; + auto header64Data = ArrayRef::fromAny(&header64, 1U); + EXPECT_EQ(nullptr, decodeElfFileHeader(ArrayRef(header64Data.begin(), header64Data.begin() + header64Data.size() - 1))); + + ElfFileHeader header32; + auto header32Data = ArrayRef::fromAny(&header32, 1U); + EXPECT_EQ(nullptr, decodeElfFileHeader(ArrayRef(header32Data.begin(), header32Data.begin() + header32Data.size() - 1))); +} + +TEST(ElfDecoder, WhenInvalidElfMagicThenElfHeaderDecodingFails) { + ElfFileHeader header; + header.identity.magic[0] = 5; + EXPECT_EQ(nullptr, decodeElfFileHeader(ArrayRef::fromAny(&header, 1U))); + + header = ElfFileHeader{}; + header.identity.magic[1] = 5; + EXPECT_EQ(nullptr, decodeElfFileHeader(ArrayRef::fromAny(&header, 1U))); + + header = ElfFileHeader{}; + header.identity.magic[2] = 5; + EXPECT_EQ(nullptr, decodeElfFileHeader(ArrayRef::fromAny(&header, 1U))); + + header = ElfFileHeader{}; + header.identity.magic[3] = 5; + EXPECT_EQ(nullptr, decodeElfFileHeader(ArrayRef::fromAny(&header, 1U))); + + header = ElfFileHeader{}; + EXPECT_EQ(&header, decodeElfFileHeader(ArrayRef::fromAny(&header, 1U))); +} + +TEST(ElfDecoder, WhenMismatchedClassThenElfHeaderDecodingFails) { + ElfFileHeader header64; + EXPECT_EQ(nullptr, decodeElfFileHeader(ArrayRef::fromAny(&header64, 1U))); + + ElfFileHeader header32; + EXPECT_EQ(nullptr, decodeElfFileHeader(ArrayRef::fromAny(&header32, 1U))); +} + +TEST(ElfDecoder, WhenNotElfThenCheckNumBitsReturnsClassNone) { + ArrayRef empty; + EXPECT_EQ(EI_CLASS_NONE, getElfNumBits(empty)); +} + +TEST(ElfDecoder, WhenValidElfThenCheckNumBitsReturnsProperClass) { + ElfFileHeader header64; + EXPECT_EQ(EI_CLASS_64, getElfNumBits(ArrayRef::fromAny(&header64, 1U))); + + ElfFileHeader header32; + EXPECT_EQ(EI_CLASS_32, getElfNumBits(ArrayRef::fromAny(&header32, 1U))); +} + +TEST(ElfDecoder, WhenNotElfThenIsElfReturnsFalse) { + ArrayRef empty; + EXPECT_FALSE(isElf(empty)); +} + +TEST(ElfDecoder, WhenValidElfThenIsElfReturnsTrue) { + ElfFileHeader header64; + EXPECT_TRUE(isElf(ArrayRef::fromAny(&header64, 1U))); + + ElfFileHeader header32; + EXPECT_TRUE(isElf(ArrayRef::fromAny(&header32, 1U))); +} + +TEST(ElfDecoder, WhenValidEmptyElfThenHeaderIsProperlyDecodedAndNoWarningsOrErrorsEmitted) { + ElfFileHeader header64; + std::string decodeWarnings; + std::string decodeErrors; + auto elf64 = decodeElf(ArrayRef::fromAny(&header64, 1U), decodeErrors, decodeWarnings); + EXPECT_EQ(&header64, elf64.elfFileHeader); + EXPECT_TRUE(elf64.programHeaders.empty()); + EXPECT_TRUE(elf64.sectionHeaders.empty()); + EXPECT_TRUE(decodeErrors.empty()); + EXPECT_TRUE(decodeWarnings.empty()); + + decodeWarnings.clear(); + decodeErrors.clear(); + ElfFileHeader header32; + auto elf32 = decodeElf(ArrayRef::fromAny(&header32, 1U), decodeErrors, decodeWarnings); + EXPECT_EQ(&header32, elf32.elfFileHeader); + EXPECT_TRUE(elf32.programHeaders.empty()); + EXPECT_TRUE(elf32.sectionHeaders.empty()); + EXPECT_TRUE(decodeErrors.empty()); + EXPECT_TRUE(decodeWarnings.empty()); +} + +TEST(ElfDecoder, WhenInvalidElfHeaderThenDecodingFails) { + ElfFileHeader header; + header.identity.magic[0] = 5; + + std::string decodeWarnings; + std::string decodeErrors; + auto elf64 = decodeElf(ArrayRef::fromAny(&header, 1U), decodeErrors, decodeWarnings); + EXPECT_EQ(nullptr, elf64.elfFileHeader); + EXPECT_TRUE(elf64.programHeaders.empty()); + EXPECT_TRUE(elf64.sectionHeaders.empty()); + EXPECT_FALSE(decodeErrors.empty()); + EXPECT_STREQ("Invalid or missing ELF header", decodeErrors.c_str()); + EXPECT_TRUE(decodeWarnings.empty()); +} + +TEST(ElfDecoder, WhenOutOfBoundsProgramHeaderTableOffsetThenDecodingFails) { + ElfFileHeader header; + header.phOff = sizeof(header) + 1; + + std::string decodeWarnings; + std::string decodeErrors; + auto elf64 = decodeElf(ArrayRef::fromAny(&header, 1U), decodeErrors, decodeWarnings); + EXPECT_EQ(nullptr, elf64.elfFileHeader); + EXPECT_TRUE(elf64.programHeaders.empty()); + EXPECT_TRUE(elf64.sectionHeaders.empty()); + EXPECT_FALSE(decodeErrors.empty()); + EXPECT_STREQ("Out of bounds program headers table", decodeErrors.c_str()); + EXPECT_TRUE(decodeWarnings.empty()); +} + +TEST(ElfDecoder, WhenOutOfBoundsSectionHeaderTableOffsetThenDecodingFails) { + ElfFileHeader header; + header.shOff = sizeof(header) + 1; + + std::string decodeWarnings; + std::string decodeErrors; + auto elf64 = decodeElf(ArrayRef::fromAny(&header, 1U), decodeErrors, decodeWarnings); + EXPECT_EQ(nullptr, elf64.elfFileHeader); + EXPECT_TRUE(elf64.programHeaders.empty()); + EXPECT_TRUE(elf64.sectionHeaders.empty()); + ASSERT_FALSE(decodeErrors.empty()); + EXPECT_STREQ("Out of bounds section headers table", decodeErrors.c_str()); + EXPECT_TRUE(decodeWarnings.empty()); +} + +TEST(ElfDecoder, WhenValidProgramHeaderTableEntriesThenDecodingSucceedsAndNoWarningsOrErrorsEmitted) { + std::vector storage; + ElfFileHeader header; + header.phOff = header.ehSize; + header.phNum = 2; + storage.insert(storage.end(), reinterpret_cast(&header), reinterpret_cast(&header + 1)); + ElfProgramHeader programHeader0; + programHeader0.fileSz = sizeof(programHeader0) * 2; + programHeader0.offset = header.phOff; + ElfProgramHeader programHeader1; + storage.insert(storage.end(), reinterpret_cast(&programHeader0), reinterpret_cast(&programHeader0 + 1)); + storage.insert(storage.end(), reinterpret_cast(&programHeader1), reinterpret_cast(&programHeader1 + 1)); + + std::string decodeWarnings; + std::string decodeErrors; + auto elf64 = decodeElf(storage, decodeErrors, decodeWarnings); + EXPECT_EQ(reinterpret_cast(storage.data()), elf64.elfFileHeader); + EXPECT_TRUE(elf64.sectionHeaders.empty()); + EXPECT_TRUE(decodeErrors.empty()); + EXPECT_TRUE(decodeWarnings.empty()); + ASSERT_EQ(2U, elf64.programHeaders.size()); + EXPECT_EQ(reinterpret_cast(storage.data() + header.phOff), elf64.programHeaders[0].header); + EXPECT_EQ(reinterpret_cast(storage.data() + header.phOff + header.phEntSize), elf64.programHeaders[1].header); + EXPECT_TRUE(elf64.programHeaders[1].data.empty()); + EXPECT_FALSE(elf64.programHeaders[0].data.empty()); + EXPECT_EQ(storage.data() + programHeader0.offset, elf64.programHeaders[0].data.begin()); + EXPECT_EQ(programHeader0.fileSz, elf64.programHeaders[0].data.size()); +} + +TEST(ElfDecoder, WhenOutOfBoundsProgramHeaderTableEntriesThenDecodingFails) { + std::vector storage; + ElfFileHeader header; + header.phOff = header.ehSize; + header.phNum = 3; + storage.insert(storage.end(), reinterpret_cast(&header), reinterpret_cast(&header + 1)); + ElfProgramHeader programHeader0; + ElfProgramHeader programHeader1; + storage.insert(storage.end(), reinterpret_cast(&programHeader0), reinterpret_cast(&programHeader0 + 1)); + storage.insert(storage.end(), reinterpret_cast(&programHeader1), reinterpret_cast(&programHeader1 + 1)); + + std::string decodeWarnings; + std::string decodeErrors; + auto elf64 = decodeElf(storage, decodeErrors, decodeWarnings); + EXPECT_EQ(nullptr, elf64.elfFileHeader); + EXPECT_TRUE(elf64.programHeaders.empty()); + EXPECT_TRUE(elf64.sectionHeaders.empty()); + ASSERT_FALSE(decodeErrors.empty()); + EXPECT_STREQ("Out of bounds program headers table", decodeErrors.c_str()); + EXPECT_TRUE(decodeWarnings.empty()); +} + +TEST(ElfDecoder, WhenOutOfBoundsProgramHeaderDataThenDecodingFails) { + std::vector storage; + ElfFileHeader header; + header.phOff = header.ehSize; + header.phNum = 2; + storage.insert(storage.end(), reinterpret_cast(&header), reinterpret_cast(&header + 1)); + ElfProgramHeader programHeader0; + programHeader0.fileSz = sizeof(programHeader0) * 2; + programHeader0.offset = header.phOff; + ElfProgramHeader programHeader1; + programHeader1.fileSz = sizeof(programHeader0) * 3; + programHeader1.offset = header.phOff; + storage.insert(storage.end(), reinterpret_cast(&programHeader0), reinterpret_cast(&programHeader0 + 1)); + storage.insert(storage.end(), reinterpret_cast(&programHeader1), reinterpret_cast(&programHeader1 + 1)); + + std::string decodeWarnings; + std::string decodeErrors; + auto elf64 = decodeElf(storage, decodeErrors, decodeWarnings); + EXPECT_EQ(nullptr, elf64.elfFileHeader); + EXPECT_TRUE(elf64.programHeaders.empty()); + EXPECT_TRUE(elf64.sectionHeaders.empty()); + ASSERT_FALSE(decodeErrors.empty()); + EXPECT_STREQ("Out of bounds program header offset/filesz, program header idx : 1", decodeErrors.c_str()); + EXPECT_TRUE(decodeWarnings.empty()); +} + +TEST(ElfDecoder, WhenValidSectionHeaderTableEntriesThenDecodingSucceedsAndNoWarningsOrErrorsEmitted) { + std::vector storage; + ElfFileHeader header; + header.shOff = header.ehSize; + header.shNum = 2; + storage.insert(storage.end(), reinterpret_cast(&header), reinterpret_cast(&header + 1)); + ElfSectionHeader sectionHeader0; + sectionHeader0.size = sizeof(sectionHeader0) * 2; + sectionHeader0.offset = header.shOff; + ElfSectionHeader sectionHeader1; + storage.insert(storage.end(), reinterpret_cast(§ionHeader0), reinterpret_cast(§ionHeader0 + 1)); + storage.insert(storage.end(), reinterpret_cast(§ionHeader1), reinterpret_cast(§ionHeader1 + 1)); + + std::string decodeWarnings; + std::string decodeErrors; + auto elf64 = decodeElf(storage, decodeErrors, decodeWarnings); + EXPECT_EQ(reinterpret_cast(storage.data()), elf64.elfFileHeader); + EXPECT_TRUE(elf64.programHeaders.empty()); + EXPECT_TRUE(decodeErrors.empty()); + EXPECT_TRUE(decodeWarnings.empty()); + ASSERT_EQ(2U, elf64.sectionHeaders.size()); + EXPECT_EQ(reinterpret_cast(storage.data() + header.shOff), elf64.sectionHeaders[0].header); + EXPECT_EQ(reinterpret_cast(storage.data() + header.shOff + header.shEntSize), elf64.sectionHeaders[1].header); + EXPECT_TRUE(elf64.sectionHeaders[1].data.empty()); + EXPECT_FALSE(elf64.sectionHeaders[0].data.empty()); + EXPECT_EQ(storage.data() + sectionHeader0.offset, elf64.sectionHeaders[0].data.begin()); + EXPECT_EQ(sectionHeader0.size, elf64.sectionHeaders[0].data.size()); +} + +TEST(ElfDecoder, WhenOutOfBoundsSectionHeaderTableEntriesThenDecodingFails) { + std::vector storage; + ElfFileHeader header; + header.shOff = header.ehSize; + header.shNum = 3; + storage.insert(storage.end(), reinterpret_cast(&header), reinterpret_cast(&header + 1)); + ElfSectionHeader sectionHeader0; + ElfSectionHeader sectionHeader1; + storage.insert(storage.end(), reinterpret_cast(§ionHeader0), reinterpret_cast(§ionHeader0 + 1)); + storage.insert(storage.end(), reinterpret_cast(§ionHeader1), reinterpret_cast(§ionHeader1 + 1)); + + std::string decodeWarnings; + std::string decodeErrors; + auto elf64 = decodeElf(storage, decodeErrors, decodeWarnings); + EXPECT_EQ(nullptr, elf64.elfFileHeader); + EXPECT_TRUE(elf64.programHeaders.empty()); + EXPECT_TRUE(elf64.sectionHeaders.empty()); + ASSERT_FALSE(decodeErrors.empty()); + EXPECT_STREQ("Out of bounds section headers table", decodeErrors.c_str()); + EXPECT_TRUE(decodeWarnings.empty()); +} + +TEST(ElfDecoder, WhenOutOfBoundsSectionHeaderDataThenDecodingFails) { + std::vector storage; + ElfFileHeader header; + header.shOff = header.ehSize; + header.shNum = 2; + storage.insert(storage.end(), reinterpret_cast(&header), reinterpret_cast(&header + 1)); + ElfSectionHeader sectionHeader0; + sectionHeader0.size = sizeof(sectionHeader0) * 2; + sectionHeader0.offset = header.shOff; + ElfSectionHeader sectionHeader1; + sectionHeader1.size = sizeof(sectionHeader0) * 3; + sectionHeader1.offset = header.shOff; + storage.insert(storage.end(), reinterpret_cast(§ionHeader0), reinterpret_cast(§ionHeader0 + 1)); + storage.insert(storage.end(), reinterpret_cast(§ionHeader1), reinterpret_cast(§ionHeader1 + 1)); + + std::string decodeWarnings; + std::string decodeErrors; + auto elf64 = decodeElf(storage, decodeErrors, decodeWarnings); + EXPECT_EQ(nullptr, elf64.elfFileHeader); + EXPECT_TRUE(elf64.programHeaders.empty()); + EXPECT_TRUE(elf64.sectionHeaders.empty()); + ASSERT_FALSE(decodeErrors.empty()); + EXPECT_STREQ("Out of bounds section header offset/size, section header idx : 1", decodeErrors.c_str()); + EXPECT_TRUE(decodeWarnings.empty()); +} + +TEST(ElfDecoder, WhenSectionDoesNotHaveDataInFileThenDataIsSetAsEmpty) { + std::vector storage; + ElfFileHeader header; + header.shOff = header.ehSize; + header.shNum = 2; + storage.insert(storage.end(), reinterpret_cast(&header), reinterpret_cast(&header + 1)); + ElfSectionHeader sectionHeader0; + sectionHeader0.size = sizeof(sectionHeader0) * 2; + sectionHeader0.offset = header.shOff; + ElfSectionHeader sectionHeader1; + sectionHeader1.size = sizeof(sectionHeader0) * 3; + sectionHeader1.offset = header.shOff; + sectionHeader1.type = SHT_NOBITS; + storage.insert(storage.end(), reinterpret_cast(§ionHeader0), reinterpret_cast(§ionHeader0 + 1)); + storage.insert(storage.end(), reinterpret_cast(§ionHeader1), reinterpret_cast(§ionHeader1 + 1)); + + std::string decodeWarnings; + std::string decodeErrors; + auto elf64 = decodeElf(storage, decodeErrors, decodeWarnings); + EXPECT_EQ(reinterpret_cast(storage.data()), elf64.elfFileHeader); + EXPECT_TRUE(elf64.programHeaders.empty()); + EXPECT_TRUE(decodeErrors.empty()); + EXPECT_TRUE(decodeWarnings.empty()); + ASSERT_EQ(2U, elf64.sectionHeaders.size()); + EXPECT_EQ(reinterpret_cast(storage.data() + header.shOff), elf64.sectionHeaders[0].header); + EXPECT_EQ(reinterpret_cast(storage.data() + header.shOff + header.shEntSize), elf64.sectionHeaders[1].header); + EXPECT_TRUE(elf64.sectionHeaders[1].data.empty()); + EXPECT_FALSE(elf64.sectionHeaders[0].data.empty()); + EXPECT_EQ(storage.data() + sectionHeader0.offset, elf64.sectionHeaders[0].data.begin()); + EXPECT_EQ(sectionHeader0.size, elf64.sectionHeaders[0].data.size()); +} diff --git a/core/unit_tests/device_binary_format/elf/elf_encoder_tests.cpp b/core/unit_tests/device_binary_format/elf/elf_encoder_tests.cpp new file mode 100644 index 0000000000..b0e7f93397 --- /dev/null +++ b/core/unit_tests/device_binary_format/elf/elf_encoder_tests.cpp @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "core/device_binary_format/elf/elf_encoder.h" +#include "core/utilities/range.h" +#include "test.h" + +using namespace NEO::Elf; + +TEST(ElfEncoder, WhenEmptyDataThenEncodedElfContainsOnlyHeader) { + ElfEncoder elfEncoder64(false, false); + auto elfData64 = elfEncoder64.encode(); + ASSERT_EQ(sizeof(ElfFileHeader), elfData64.size()); + auto &header64 = *reinterpret_cast *>(elfData64.data()); + auto &identity64 = header64.identity; + EXPECT_EQ(elfMagic[0], identity64.magic[0]); + EXPECT_EQ(elfMagic[1], identity64.magic[1]); + EXPECT_EQ(elfMagic[2], identity64.magic[2]); + EXPECT_EQ(elfMagic[3], identity64.magic[3]); + EXPECT_EQ(EI_CLASS_64, identity64.eClass); + EXPECT_EQ(EI_DATA_LITTLE_ENDIAN, identity64.data); + EXPECT_EQ(EV_CURRENT, identity64.version); + EXPECT_EQ(0U, identity64.osAbi); + EXPECT_EQ(0U, identity64.abiVersion); + EXPECT_EQ(ET_NONE, header64.type); + EXPECT_EQ(EM_NONE, header64.machine); + EXPECT_EQ(1U, header64.version); + EXPECT_EQ(0U, header64.entry); + EXPECT_EQ(0U, header64.phOff); + EXPECT_EQ(0U, header64.shOff); + EXPECT_EQ(0U, header64.flags); + EXPECT_EQ(sizeof(ElfFileHeader), header64.ehSize); + EXPECT_EQ(sizeof(ElfProgramHeader), header64.phEntSize); + EXPECT_EQ(0U, header64.phNum); + EXPECT_EQ(sizeof(ElfSectionHeader), header64.shEntSize); + EXPECT_EQ(0U, header64.shNum); + EXPECT_EQ(SHN_UNDEF, header64.shStrNdx); + + ElfEncoder elfEncoder32(false, false); + auto elfData32 = elfEncoder32.encode(); + ASSERT_EQ(sizeof(ElfFileHeader), elfData32.size()); + auto &header32 = *reinterpret_cast *>(elfData32.data()); + auto &identity32 = header32.identity; + EXPECT_EQ(elfMagic[0], identity32.magic[0]); + EXPECT_EQ(elfMagic[1], identity32.magic[1]); + EXPECT_EQ(elfMagic[2], identity32.magic[2]); + EXPECT_EQ(elfMagic[3], identity32.magic[3]); + EXPECT_EQ(EI_CLASS_32, identity32.eClass); + EXPECT_EQ(EI_DATA_LITTLE_ENDIAN, identity32.data); + EXPECT_EQ(EV_CURRENT, identity32.version); + EXPECT_EQ(0U, identity32.osAbi); + EXPECT_EQ(0U, identity32.abiVersion); + EXPECT_EQ(ET_NONE, header32.type); + EXPECT_EQ(EM_NONE, header32.machine); + EXPECT_EQ(1U, header32.version); + EXPECT_EQ(0U, header32.entry); + EXPECT_EQ(0U, header32.phOff); + EXPECT_EQ(0U, header32.shOff); + EXPECT_EQ(0U, header32.flags); + EXPECT_EQ(sizeof(ElfFileHeader), header32.ehSize); + EXPECT_EQ(sizeof(ElfProgramHeader), header32.phEntSize); + EXPECT_EQ(0U, header32.phNum); + EXPECT_EQ(sizeof(ElfSectionHeader), header32.shEntSize); + EXPECT_EQ(0U, header32.shNum); + EXPECT_EQ(SHN_UNDEF, header32.shStrNdx); +} + +TEST(ElfEncoder, GivenRequestForUndefAndSectionHeaderNamesSectionsWhenNotNeededThenNotEmitted) { + ElfEncoder elfEncoder64(true, true); + auto elfData64 = elfEncoder64.encode(); + ASSERT_EQ(sizeof(ElfFileHeader), elfData64.size()); + auto &header64 = *reinterpret_cast *>(elfData64.data()); + EXPECT_EQ(0U, header64.shOff); + EXPECT_EQ(0U, header64.shNum); + EXPECT_EQ(SHN_UNDEF, header64.shStrNdx); +} + +TEST(ElfEncoder, GivenRequestForUndefAndSectionHeaderNamesSectionsWhenNeededThenEmitted) { + ElfEncoder elfEncoder64(true, true); + elfEncoder64.appendSection(SHT_NULL, ".my_name_is_important", {}); + auto elfData64 = elfEncoder64.encode(); + char expectedSectionNamesData[] = "\0.shstrtab\0.my_name_is_important"; + ASSERT_EQ(sizeof(ElfFileHeader) + 3 * sizeof(ElfSectionHeader) + alignUp(sizeof(expectedSectionNamesData), 8), elfData64.size()); + auto &header64 = *reinterpret_cast *>(elfData64.data()); + EXPECT_EQ(0U, header64.phOff); + EXPECT_EQ(header64.ehSize, header64.shOff); + EXPECT_EQ(0U, header64.flags); + EXPECT_EQ(sizeof(ElfFileHeader), header64.ehSize); + EXPECT_EQ(sizeof(ElfProgramHeader), header64.phEntSize); + EXPECT_EQ(0U, header64.phNum); + EXPECT_EQ(sizeof(ElfSectionHeader), header64.shEntSize); + EXPECT_EQ(3U, header64.shNum); + EXPECT_EQ(2U, header64.shStrNdx); + auto §Undef64 = *reinterpret_cast *>(elfData64.data() + sizeof(ElfFileHeader)); + auto §SkipMe64 = *reinterpret_cast *>(elfData64.data() + sizeof(ElfFileHeader) + sizeof(ElfSectionHeader)); + auto §SectionNames64 = *reinterpret_cast *>(elfData64.data() + sizeof(ElfFileHeader) + 2 * sizeof(ElfSectionHeader)); + const char *sectionNames64Data = reinterpret_cast(elfData64.data() + sizeof(ElfFileHeader) + 3 * sizeof(ElfSectionHeader)); + + EXPECT_EQ(0U, sectUndef64.name); + EXPECT_EQ(SHT_NULL, sectUndef64.type); + EXPECT_EQ(SHF_NONE, sectUndef64.flags); + EXPECT_EQ(0U, sectUndef64.addr); + EXPECT_EQ(0U, sectUndef64.offset); + EXPECT_EQ(0U, sectUndef64.size); + EXPECT_EQ(SHN_UNDEF, sectUndef64.link); + EXPECT_EQ(0U, sectUndef64.info); + EXPECT_EQ(0U, sectUndef64.addralign); + EXPECT_EQ(0U, sectUndef64.entsize); + + EXPECT_EQ(11U, sectSkipMe64.name); + EXPECT_EQ(SHT_NULL, sectSkipMe64.type); + EXPECT_EQ(SHF_NONE, sectSkipMe64.flags); + EXPECT_EQ(0U, sectSkipMe64.addr); + EXPECT_EQ(0U, sectSkipMe64.offset); + EXPECT_EQ(0U, sectSkipMe64.size); + EXPECT_EQ(SHN_UNDEF, sectSkipMe64.link); + EXPECT_EQ(0U, sectSkipMe64.info); + EXPECT_EQ(8U, sectSkipMe64.addralign); + EXPECT_EQ(0U, sectSkipMe64.entsize); + + EXPECT_EQ(1U, sectSectionNames64.name); + EXPECT_EQ(SHT_STRTAB, sectSectionNames64.type); + EXPECT_EQ(SHF_NONE, sectSectionNames64.flags); + EXPECT_EQ(0U, sectSectionNames64.addr); + EXPECT_EQ(sizeof(ElfFileHeader) + 3 * sizeof(ElfSectionHeader), sectSectionNames64.offset); + EXPECT_EQ(sizeof(expectedSectionNamesData), sectSectionNames64.size); + EXPECT_EQ(SHN_UNDEF, sectSectionNames64.link); + EXPECT_EQ(0U, sectSectionNames64.info); + EXPECT_EQ(8U, sectSectionNames64.addralign); + EXPECT_EQ(0U, sectSectionNames64.entsize); + EXPECT_EQ(0, memcmp(expectedSectionNamesData, sectionNames64Data, sizeof(expectedSectionNamesData))); + + ElfEncoder elfEncoder32(true, true); + elfEncoder32.appendSection(SHT_NULL, ".my_name_is_important", {}); + auto elfData32 = elfEncoder32.encode(); + ASSERT_EQ(sizeof(ElfFileHeader) + 3 * sizeof(ElfSectionHeader) + alignUp(sizeof(expectedSectionNamesData), 8), elfData32.size()); + auto &header32 = *reinterpret_cast *>(elfData32.data()); + EXPECT_EQ(header32.ehSize, header32.shOff); + auto §SectionNames32 = *reinterpret_cast *>(elfData32.data() + sizeof(ElfFileHeader) + 2 * sizeof(ElfSectionHeader)); + const char *sectionNames32Data = reinterpret_cast(elfData32.data() + sizeof(ElfFileHeader) + 3 * sizeof(ElfSectionHeader)); + EXPECT_EQ(sizeof(ElfFileHeader) + 3 * sizeof(ElfSectionHeader), sectSectionNames32.offset); + EXPECT_EQ(sizeof(expectedSectionNamesData), sectSectionNames32.size); + EXPECT_EQ(0, memcmp(expectedSectionNamesData, sectionNames32Data, sizeof(expectedSectionNamesData))); +} + +TEST(ElfEncoder, WhenAppendingSectionWithDataThenOffsetsAreProperlyUpdated) { + ElfEncoder elfEncoder64(false, false); + const uint8_t data[] = "235711131719"; + elfEncoder64.appendSection(SHT_PROGBITS, ".my_name_is_not_important", data); + + auto elfData64 = elfEncoder64.encode(); + ASSERT_EQ(sizeof(ElfFileHeader) + 1 * sizeof(ElfSectionHeader) + alignUp(sizeof(data), 8), elfData64.size()); + auto &header64 = *reinterpret_cast *>(elfData64.data()); + EXPECT_EQ(0U, header64.phOff); + EXPECT_EQ(header64.ehSize, header64.shOff); + EXPECT_EQ(1U, header64.shNum); + EXPECT_EQ(SHN_UNDEF, header64.shStrNdx); + + auto §ProgBits = *reinterpret_cast *>(elfData64.data() + sizeof(ElfFileHeader)); + auto sectProgBitsData = elfData64.data() + sizeof(ElfFileHeader) + sizeof(ElfSectionHeader); + EXPECT_EQ(0U, sectProgBits.name); + EXPECT_EQ(SHT_PROGBITS, sectProgBits.type); + EXPECT_EQ(SHF_NONE, sectProgBits.flags); + EXPECT_EQ(0U, sectProgBits.addr); + EXPECT_EQ(sizeof(ElfFileHeader) + sizeof(ElfSectionHeader), sectProgBits.offset); + EXPECT_EQ(sizeof(data), sectProgBits.size); + EXPECT_EQ(SHN_UNDEF, sectProgBits.link); + EXPECT_EQ(0U, sectProgBits.info); + EXPECT_EQ(8U, sectProgBits.addralign); + EXPECT_EQ(0U, sectProgBits.entsize); + EXPECT_EQ(0, memcmp(data, sectProgBitsData, sizeof(data))); +} + +TEST(ElfEncoder, WhenAppendingSectionWithoutDataThenOffsetsAreLeftIntact) { + ElfEncoder elfEncoder64(false, false); + elfEncoder64.appendSection(SHT_PROGBITS, ".my_name_is_not_important", {}); + + auto elfData64 = elfEncoder64.encode(); + ASSERT_EQ(sizeof(ElfFileHeader) + 1 * sizeof(ElfSectionHeader), elfData64.size()); + auto &header64 = *reinterpret_cast *>(elfData64.data()); + EXPECT_EQ(0U, header64.phOff); + EXPECT_EQ(header64.ehSize, header64.shOff); + EXPECT_EQ(1U, header64.shNum); + EXPECT_EQ(SHN_UNDEF, header64.shStrNdx); + + auto §ProgBits = *reinterpret_cast *>(elfData64.data() + sizeof(ElfFileHeader)); + EXPECT_EQ(0U, sectProgBits.name); + EXPECT_EQ(SHT_PROGBITS, sectProgBits.type); + EXPECT_EQ(SHF_NONE, sectProgBits.flags); + EXPECT_EQ(0U, sectProgBits.addr); + EXPECT_EQ(0U, sectProgBits.offset); + EXPECT_EQ(0U, sectProgBits.size); + EXPECT_EQ(SHN_UNDEF, sectProgBits.link); + EXPECT_EQ(0U, sectProgBits.info); + EXPECT_EQ(8U, sectProgBits.addralign); + EXPECT_EQ(0U, sectProgBits.entsize); +} + +TEST(ElfEncoder, WhenAppendingSectionWithNoBitsTypeThenDataIsIgnored) { + { + ElfEncoder elfEncoder64(false, false); + const uint8_t data[] = "235711131719"; + elfEncoder64.appendSection(SHT_NOBITS, ".my_name_is_not_important", data); + + auto elfData64 = elfEncoder64.encode(); + ASSERT_EQ(sizeof(ElfFileHeader) + 1 * sizeof(ElfSectionHeader), elfData64.size()); + auto &header64 = *reinterpret_cast *>(elfData64.data()); + EXPECT_EQ(0U, header64.phOff); + EXPECT_EQ(header64.ehSize, header64.shOff); + EXPECT_EQ(1U, header64.shNum); + EXPECT_EQ(SHN_UNDEF, header64.shStrNdx); + + auto §NoBits = *reinterpret_cast *>(elfData64.data() + sizeof(ElfFileHeader)); + EXPECT_EQ(0U, sectNoBits.name); + EXPECT_EQ(SHT_NOBITS, sectNoBits.type); + EXPECT_EQ(SHF_NONE, sectNoBits.flags); + EXPECT_EQ(0U, sectNoBits.addr); + EXPECT_EQ(0U, sectNoBits.offset); + EXPECT_EQ(0U, sectNoBits.size); + EXPECT_EQ(SHN_UNDEF, sectNoBits.link); + EXPECT_EQ(0U, sectNoBits.info); + EXPECT_EQ(8U, sectNoBits.addralign); + EXPECT_EQ(0U, sectNoBits.entsize); + } + + { + ElfEncoder elfEncoder64(false, false); + const uint8_t data[] = "235711131719"; + elfEncoder64.appendSection(static_cast(SHT_NOBITS), ".my_name_is_not_important", data).size = sizeof(data); + + auto elfData64 = elfEncoder64.encode(); + ASSERT_EQ(sizeof(ElfFileHeader) + 1 * sizeof(ElfSectionHeader), elfData64.size()); + + auto §NoBits = *reinterpret_cast *>(elfData64.data() + sizeof(ElfFileHeader)); + EXPECT_EQ(0U, sectNoBits.offset); + EXPECT_EQ(sizeof(data), sectNoBits.size); + } +} + +TEST(ElfEncoder, WhenAppendingSegmentWithDataThenOffsetsAreProperlyUpdated) { + ElfEncoder elfEncoder64(false, false); + const uint8_t data[] = "235711131719"; + elfEncoder64.appendSegment(PT_LOAD, data); + + auto elfData64 = elfEncoder64.encode(); + ASSERT_EQ(sizeof(ElfFileHeader) + 1 * sizeof(ElfProgramHeader) + alignUp(sizeof(data), 8), elfData64.size()); + auto &header64 = *reinterpret_cast *>(elfData64.data()); + EXPECT_EQ(0U, header64.shOff); + EXPECT_EQ(header64.ehSize, header64.phOff); + EXPECT_EQ(1U, header64.phNum); + EXPECT_EQ(SHN_UNDEF, header64.shStrNdx); + + auto &segLoad = *reinterpret_cast *>(elfData64.data() + sizeof(ElfFileHeader)); + auto segLoadBitsData = elfData64.data() + sizeof(ElfFileHeader) + sizeof(ElfProgramHeader); + EXPECT_EQ(PT_LOAD, segLoad.type); + EXPECT_EQ(PF_NONE, segLoad.flags); + EXPECT_EQ(sizeof(ElfFileHeader) + sizeof(ElfProgramHeader), segLoad.offset); + EXPECT_EQ(0U, segLoad.vAddr); + EXPECT_EQ(0U, segLoad.pAddr); + EXPECT_EQ(sizeof(data), segLoad.fileSz); + EXPECT_EQ(0U, segLoad.memSz); + EXPECT_EQ(8U, segLoad.align); + EXPECT_EQ(0, memcmp(data, segLoadBitsData, sizeof(data))); +} + +TEST(ElfEncoder, WhenAppendingSegmentWithoutDataThenOffsetsAreLeftIntact) { + ElfEncoder elfEncoder64(false, false); + elfEncoder64.appendSegment(PT_LOAD, {}); + + auto elfData64 = elfEncoder64.encode(); + ASSERT_EQ(sizeof(ElfFileHeader) + 1 * sizeof(ElfProgramHeader), elfData64.size()); + auto &header64 = *reinterpret_cast *>(elfData64.data()); + EXPECT_EQ(0U, header64.shOff); + EXPECT_EQ(header64.ehSize, header64.phOff); + EXPECT_EQ(1U, header64.phNum); + EXPECT_EQ(SHN_UNDEF, header64.shStrNdx); + + auto &segLoad = *reinterpret_cast *>(elfData64.data() + sizeof(ElfFileHeader)); + EXPECT_EQ(PT_LOAD, segLoad.type); + EXPECT_EQ(PF_NONE, segLoad.flags); + EXPECT_EQ(0U, segLoad.offset); + EXPECT_EQ(0U, segLoad.vAddr); + EXPECT_EQ(0U, segLoad.pAddr); + EXPECT_EQ(0U, segLoad.fileSz); + EXPECT_EQ(0U, segLoad.memSz); + EXPECT_EQ(8U, segLoad.align); +} + +TEST(ElfEncoder, WhenAppendingBothSectionAndSegmentThenProperElfIsEmited) { + const uint8_t segmentData[] = "235711131719"; + const uint8_t sectionData[] = "232931374143"; + const uint8_t sectionNamesData[] = "\0.shstrtab\0.my_name_is_important"; + + ElfFileHeader header; + header.type = ET_EXEC; + header.entry = 16U; + header.phOff = static_cast(sizeof(header)); + header.shOff = static_cast(sizeof(header) + sizeof(ElfProgramHeader)); + header.flags = 4U; + header.phNum = 1U; + header.shNum = 3U; + header.shStrNdx = 2U; + + ElfProgramHeader segment; + segment.type = PT_LOAD; + segment.flags = PF_R | PF_X; + segment.offset = static_cast(header.shOff + sizeof(ElfSectionHeader) * 3); + segment.vAddr = 4096U; + segment.pAddr = 4096U * 16; + segment.fileSz = static_cast(sizeof(segmentData)); + segment.memSz = 8192U; + segment.align = 8U; + + ElfSectionHeader sectionUndef; + ElfSectionHeader sectionProgBits; + sectionProgBits.name = 11U; + sectionProgBits.type = SHT_PROGBITS; + sectionProgBits.flags = SHF_ALLOC; + sectionProgBits.addr = 16U; + sectionProgBits.offset = static_cast(segment.offset + alignUp(static_cast(segment.fileSz), static_cast(segment.align))); + sectionProgBits.size = static_cast(sizeof(sectionData)); + sectionProgBits.link = SHN_UNDEF; + sectionProgBits.info = 0U; + sectionProgBits.addralign = 16U; + sectionProgBits.entsize = 0U; + ElfSectionHeader sectionSectionNames; + sectionSectionNames.name = 1U; + sectionSectionNames.type = SHT_STRTAB; + sectionSectionNames.flags = SHF_NONE; + sectionSectionNames.addr = 0U; + sectionSectionNames.offset = static_cast(sectionProgBits.offset + alignUp(static_cast(sectionProgBits.size), static_cast(sectionProgBits.addralign))); + sectionSectionNames.size = static_cast(sizeof(sectionNamesData)); + sectionSectionNames.link = SHN_UNDEF; + sectionSectionNames.info = 0U; + sectionSectionNames.addralign = 8U; + sectionSectionNames.entsize = 0U; + + std::vector handMade; + handMade.insert(handMade.end(), reinterpret_cast(&header), reinterpret_cast(&header + 1)); + handMade.insert(handMade.end(), reinterpret_cast(&segment), reinterpret_cast(&segment + 1)); + handMade.insert(handMade.end(), reinterpret_cast(§ionUndef), reinterpret_cast(§ionUndef + 1)); + handMade.insert(handMade.end(), reinterpret_cast(§ionProgBits), reinterpret_cast(§ionProgBits + 1)); + handMade.insert(handMade.end(), reinterpret_cast(§ionSectionNames), reinterpret_cast(§ionSectionNames + 1)); + handMade.insert(handMade.end(), segmentData, segmentData + sizeof(segmentData)); + handMade.resize(static_cast(sectionProgBits.offset), 0U); + handMade.insert(handMade.end(), sectionData, sectionData + sizeof(sectionData)); + handMade.resize(static_cast(sectionSectionNames.offset), 0U); + handMade.insert(handMade.end(), sectionNamesData, sectionNamesData + sizeof(sectionNamesData)); + handMade.resize(static_cast(sectionSectionNames.offset + alignUp(sizeof(sectionNamesData), 8U)), 0U); + + ElfEncoder elfEncoder64; + { + auto &encodedHeader = elfEncoder64.getElfFileHeader(); + encodedHeader.type = ET_EXEC; + encodedHeader.entry = 16U; + encodedHeader.flags = 4U; + + auto &encodedSegment = elfEncoder64.appendSegment(PT_LOAD, segmentData); + encodedSegment.type = PT_LOAD; + encodedSegment.flags = PF_R | PF_X; + encodedSegment.vAddr = 4096U; + encodedSegment.pAddr = 4096U * 16; + encodedSegment.memSz = 8192U; + encodedSegment.align = 8U; + + ElfSectionHeader encodedSectionProgBits; + encodedSectionProgBits.name = elfEncoder64.appendSectionName(".my_name_is_important"); + encodedSectionProgBits.type = SHT_PROGBITS; + encodedSectionProgBits.flags = SHF_ALLOC; + encodedSectionProgBits.addr = 16U; + encodedSectionProgBits.link = SHN_UNDEF; + encodedSectionProgBits.info = 0U; + encodedSectionProgBits.addralign = 16U; + encodedSectionProgBits.entsize = 0U; + + elfEncoder64.appendSection(encodedSectionProgBits, sectionData); + } + + auto generated = elfEncoder64.encode(); + + EXPECT_EQ(handMade, generated); +} + +TEST(ElfEncoder, WhenDefaultAlignmentIsRaisedThenSegmentDataAbideByIt) { + const uint8_t segmentData[] = "235711131719"; + const uint8_t sectionData[] = "232931374143475"; + + static constexpr size_t alignment = 128U; + + ElfEncoder elfEncoder64(true, true, alignment); + elfEncoder64.appendSegment(PT_LOAD, segmentData); + + elfEncoder64.appendSection(NEO::Elf::SHT_PROGBITS, "my_name_is_important", sectionData); + auto elfData64 = elfEncoder64.encode(); + + auto &header64 = *reinterpret_cast *>(elfData64.data()); + auto sectionHeaders = reinterpret_cast *>(elfData64.data() + static_cast(header64.shOff)); + auto programHeaders = reinterpret_cast *>(elfData64.data() + static_cast(header64.phOff)); + for (const auto §ion : NEO::CreateRange(sectionHeaders, header64.shNum)) { + EXPECT_EQ(0U, section.offset % 8U); + } + for (const auto &segment : NEO::CreateRange(programHeaders, header64.phNum)) { + EXPECT_EQ(0U, segment.offset % alignment); + EXPECT_LE(alignment, segment.align); + } +} + +TEST(ElfEncoder, WhenDefaultAlignmentIsLoweredThenSectionAndSegmentDataAbideByIt) { + const uint8_t segmentData[] = "235711131719"; + const uint8_t sectionData[] = "232931374143475"; + + static constexpr size_t alignment = 1U; + + ElfEncoder elfEncoder64(true, true, alignment); + elfEncoder64.appendSegment(PT_LOAD, segmentData); + + elfEncoder64.appendSection(NEO::Elf::SHT_PROGBITS, "my_name_is_important", sectionData); + auto elfData64 = elfEncoder64.encode(); + + auto &header64 = *reinterpret_cast *>(elfData64.data()); + auto sectionHeaders = reinterpret_cast *>(elfData64.data() + static_cast(header64.shOff)); + NEO::Elf::ElfSectionHeader *sectionNamesSection = sectionHeaders + header64.shStrNdx; + size_t unpaddedSize = sizeof(ElfFileHeader) + 3 * sizeof(NEO::Elf::ElfSectionHeader) + sizeof(NEO::Elf::ElfProgramHeader); + unpaddedSize += sizeof(segmentData) + sizeof(sectionData) + static_cast(sectionNamesSection->size); + EXPECT_EQ(unpaddedSize, elfData64.size()); +} + +TEST(ElfEncoder, WhenAppendingEmptySectionNameThenAlwaysReturn0AsOffset) { + ElfEncoder elfEncoder64(false, true); + auto offset0 = elfEncoder64.appendSectionName({}); + auto offset1 = elfEncoder64.appendSectionName({}); + auto offset2 = elfEncoder64.appendSectionName({}); + EXPECT_EQ(0U, offset0); + EXPECT_EQ(0U, offset1); + EXPECT_EQ(0U, offset2); +} + +TEST(ElfEncoder, WhenAppendingSectionNameThenEmplacedStringIsAlwaysNullterminated) { + ElfEncoder elfEncoder64(true, true); + auto strOffset = elfEncoder64.appendSectionName(ConstStringRef("abc", 2)); + auto strOffset2 = elfEncoder64.appendSectionName(ConstStringRef("de", 3)); + auto strOffset3 = elfEncoder64.appendSectionName(ConstStringRef("g")); + elfEncoder64.appendSection(SHT_NOBITS, "my_name_is_important", {}); + EXPECT_EQ(strOffset + 3, strOffset2); + EXPECT_EQ(strOffset2 + 3, strOffset3); + auto elfData = elfEncoder64.encode(); + auto header = reinterpret_cast *>(elfData.data()); + + auto sectionNamesSection = reinterpret_cast *>(elfData.data() + static_cast(header->shOff + header->shStrNdx * header->shEntSize)); + EXPECT_STREQ("ab", reinterpret_cast(elfData.data() + sectionNamesSection->offset + strOffset)); + EXPECT_STREQ("de", reinterpret_cast(elfData.data() + sectionNamesSection->offset + strOffset2)); + EXPECT_STREQ("g", reinterpret_cast(elfData.data() + sectionNamesSection->offset + strOffset3)); +} diff --git a/core/unit_tests/device_binary_format/patchtokens_decoder_tests.cpp b/core/unit_tests/device_binary_format/patchtokens_decoder_tests.cpp index 9c9f17964d..7d8861bbd5 100644 --- a/core/unit_tests/device_binary_format/patchtokens_decoder_tests.cpp +++ b/core/unit_tests/device_binary_format/patchtokens_decoder_tests.cpp @@ -191,7 +191,7 @@ TEST(KernelDecoder, GivenValidEmptyKernelThenDecodingOfHeaderSucceeds) { NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(kernelToEncode.blobs.kernelInfo, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); ASSERT_NE(nullptr, decodedKernel.header); EXPECT_EQ(kernelToEncode.header, decodedKernel.header); EXPECT_EQ(kernelToEncode.name, decodedKernel.name); @@ -211,7 +211,7 @@ TEST(KernelDecoder, GivenEmptyKernelWhenBlobSmallerThanKernelHeaderThenDecodingF kernelToEncode.blobs.kernelInfo.begin() + sizeof(iOpenCL::SKernelBinaryHeader) - 1); bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(brokenBlob, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); } TEST(KernelDecoder, GivenValidKernelWithHeapsThenDecodingSucceedsAndHeapsAreProperlySet) { @@ -246,7 +246,7 @@ TEST(KernelDecoder, GivenValidKernelWithHeapsThenDecodingSucceedsAndHeapsAreProp NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); EXPECT_EQ(kernelToEncode.header, decodedKernel.header); EXPECT_EQ(0U, decodedKernel.unhandledTokens.size()); @@ -274,37 +274,37 @@ TEST(KernelDecoder, GivenEmptyKernelWhenBlobDoesntHaveEnoughSpaceForHeaderDataTh kernelHeader->KernelNameSize = outOfBoundsSize; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(kernelToEncode.blobs.kernelInfo, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); kernelHeader->KernelNameSize = originalHeader.KernelNameSize; kernelHeader->KernelHeapSize = outOfBoundsSize; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(kernelToEncode.blobs.kernelInfo, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); kernelHeader->KernelHeapSize = originalHeader.KernelHeapSize; kernelHeader->GeneralStateHeapSize = outOfBoundsSize; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(kernelToEncode.blobs.kernelInfo, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); kernelHeader->GeneralStateHeapSize = originalHeader.GeneralStateHeapSize; kernelHeader->DynamicStateHeapSize = outOfBoundsSize; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(kernelToEncode.blobs.kernelInfo, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); kernelHeader->DynamicStateHeapSize = originalHeader.DynamicStateHeapSize; kernelHeader->SurfaceStateHeapSize = outOfBoundsSize; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(kernelToEncode.blobs.kernelInfo, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); kernelHeader->SurfaceStateHeapSize = originalHeader.SurfaceStateHeapSize; kernelHeader->PatchListSize = outOfBoundsSize; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(kernelToEncode.blobs.kernelInfo, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); kernelHeader->PatchListSize = originalHeader.PatchListSize; } @@ -347,7 +347,7 @@ TEST(KernelDecoder, GivenKernelWithValidKernelPatchtokensThenDecodingSucceedsAnd NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); EXPECT_TRUE(decodedKernel.unhandledTokens.empty()); EXPECT_EQ(ptrOffset(storage.data(), patchListOffset), decodedKernel.blobs.patchList.begin()); EXPECT_EQ(ptrOffset(storage.data(), storage.size()), decodedKernel.blobs.patchList.end()); @@ -398,7 +398,7 @@ TEST(KernelDecoder, GivenKernelWithValidStringPatchtokensThenDecodingSucceedsAnd NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); EXPECT_TRUE(decodedKernel.unhandledTokens.empty()); auto base = storage.data(); @@ -446,7 +446,7 @@ TEST(KernelDecoder, GivenKernelWithValidArgInfoPatchtokensThenDecodingSucceedsAn NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); EXPECT_TRUE(decodedKernel.unhandledTokens.empty()); auto base = storage.data(); @@ -507,7 +507,7 @@ TEST(KernelDecoder, GivenKernelWithValidObjectArgPatchtokensThenDecodingSucceeds NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); EXPECT_TRUE(decodedKernel.unhandledTokens.empty()); auto base = storage.data(); @@ -589,7 +589,7 @@ TEST(KernelDecoder, GivenKernelWithValidNonArgCrossThreadDataPatchtokensThenDeco NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); EXPECT_TRUE(decodedKernel.unhandledTokens.empty()); auto base = storage.data(); @@ -644,7 +644,7 @@ TEST(KernelDecoder, GivenKernelWithArgCrossThreadDataPatchtokensWhenSourceIndexI NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); ASSERT_EQ(5U, decodedKernel.unhandledTokens.size()); auto base = storage.data(); @@ -670,7 +670,7 @@ TEST(KernelDecoder, GivenKernelWithUnkownPatchtokensThenDecodingSucceedsButToken NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); ASSERT_EQ(2U, decodedKernel.unhandledTokens.size()); auto base = storage.data(); @@ -716,7 +716,7 @@ TEST(KernelDecoder, GivenKernelWithValidObjectArgMetadataPatchtokensThenDecoding NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); EXPECT_TRUE(decodedKernel.unhandledTokens.empty()); ASSERT_EQ(4U, decodedKernel.tokens.kernelArgs.size()); @@ -776,14 +776,14 @@ TEST(KernelDecoder, GivenKernelWithMismatchedArgMetadataPatchtokensThenDecodingF NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); decodedKernel = {}; arg0Metadata0->Type = iOpenCL::DATA_PARAMETER_BUFFER_STATEFUL; arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_IMAGE_WIDTH; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); EXPECT_TRUE(decodedKernel.unhandledTokens.empty()); decodedKernel = {}; @@ -791,77 +791,77 @@ TEST(KernelDecoder, GivenKernelWithMismatchedArgMetadataPatchtokensThenDecodingF arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_SAMPLER_ADDRESS_MODE; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); decodedKernel = {}; arg0Metadata0->Type = iOpenCL::DATA_PARAMETER_BUFFER_STATEFUL; arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_SUM_OF_LOCAL_MEMORY_OBJECT_ARGUMENT_SIZES; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); decodedKernel = {}; arg0Metadata0->Type = iOpenCL::DATA_PARAMETER_IMAGE_WIDTH; arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_BUFFER_STATEFUL; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); decodedKernel = {}; arg0Metadata0->Type = iOpenCL::DATA_PARAMETER_IMAGE_WIDTH; arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_SAMPLER_ADDRESS_MODE; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); decodedKernel = {}; arg0Metadata0->Type = iOpenCL::DATA_PARAMETER_IMAGE_WIDTH; arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_SUM_OF_LOCAL_MEMORY_OBJECT_ARGUMENT_SIZES; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); decodedKernel = {}; arg0Metadata0->Type = iOpenCL::DATA_PARAMETER_SAMPLER_ADDRESS_MODE; arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_BUFFER_STATEFUL; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); decodedKernel = {}; arg0Metadata0->Type = iOpenCL::DATA_PARAMETER_SAMPLER_ADDRESS_MODE; arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_IMAGE_WIDTH; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); decodedKernel = {}; arg0Metadata0->Type = iOpenCL::DATA_PARAMETER_SAMPLER_ADDRESS_MODE; arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_SUM_OF_LOCAL_MEMORY_OBJECT_ARGUMENT_SIZES; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); decodedKernel = {}; arg0Metadata0->Type = iOpenCL::DATA_PARAMETER_SUM_OF_LOCAL_MEMORY_OBJECT_ARGUMENT_SIZES; arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_IMAGE_WIDTH; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); decodedKernel = {}; arg0Metadata0->Type = iOpenCL::DATA_PARAMETER_SUM_OF_LOCAL_MEMORY_OBJECT_ARGUMENT_SIZES; arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_SAMPLER_ADDRESS_MODE; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); decodedKernel = {}; arg0Metadata0->Type = iOpenCL::DATA_PARAMETER_SUM_OF_LOCAL_MEMORY_OBJECT_ARGUMENT_SIZES; arg0Metadata1->Type = iOpenCL::DATA_PARAMETER_BUFFER_STATEFUL; decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); } TEST(KernelDecoder, GivenKernelWithMismatchedArgMetadataPatchtokensThenDecodingFailsAndStops) { @@ -883,7 +883,7 @@ TEST(KernelDecoder, GivenKernelWithMismatchedArgMetadataPatchtokensThenDecodingF NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); EXPECT_TRUE(decodedKernel.unhandledTokens.empty()); } @@ -905,7 +905,7 @@ TEST(KernelDecoder, GivenKernelWithByValArgMetadataPatchtokensThenDecodingSuccee NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); EXPECT_TRUE(decodedKernel.unhandledTokens.empty()); ASSERT_EQ(2U, decodedKernel.tokens.kernelArgs.size()); @@ -940,7 +940,7 @@ TEST(KernelDecoder, GivenKernelWithVmeMetadataPatchtokensThenDecodingSucceedsAnd NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); EXPECT_TRUE(decodedKernel.unhandledTokens.empty()); ASSERT_EQ(1U, decodedKernel.tokens.kernelArgs.size()); @@ -971,7 +971,7 @@ TEST(KernelDecoder, GivenKernelWithOutOfBoundsTokenThenDecodingFails) { NEO::PatchTokenBinary::KernelFromPatchtokens decodedKernel; bool decodeSuccess = NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(storage, decodedKernel); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedKernel.decodeStatus); } TEST(ProgramDecoder, GivenValidEmptyProgramThenDecodingOfHeaderSucceeds) { @@ -980,7 +980,7 @@ TEST(ProgramDecoder, GivenValidEmptyProgramThenDecodingOfHeaderSucceeds) { NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram; bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedProgram.decodeStatus); EXPECT_TRUE(decodedProgram.unhandledTokens.empty()); ASSERT_NE(nullptr, decodedProgram.header); EXPECT_EQ(programToEncode.header, decodedProgram.header); @@ -998,7 +998,7 @@ TEST(ProgramDecoder, GivenProgramWhenBlobSmallerThanProgramHeaderThenDecodingFai programToEncode.blobs.programInfo.begin() + sizeof(iOpenCL::SProgramBinaryHeader) - 1); bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(brokenBlob, decodedProgram); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedProgram.decodeStatus); } TEST(ProgramDecoder, GivenProgramWithInvaidProgramMagicThenDecodingFails) { @@ -1007,7 +1007,7 @@ TEST(ProgramDecoder, GivenProgramWithInvaidProgramMagicThenDecodingFails) { programToEncode.headerMutable->Magic += 1; bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedProgram.decodeStatus); } TEST(ProgramDecoder, GivenProgramWhenBlobDoesntHaveEnoughSpaceForPatchListThenDecodingFails) { @@ -1016,7 +1016,7 @@ TEST(ProgramDecoder, GivenProgramWhenBlobDoesntHaveEnoughSpaceForPatchListThenDe programToEncode.headerMutable->PatchListSize = static_cast(programToEncode.blobs.patchList.size() + 1); bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedProgram.decodeStatus); } TEST(ProgramDecoder, GivenValidProgramWithConstantSurfacesThenDecodingSucceedsAndTokensAreProperlyAssigned) { @@ -1024,7 +1024,7 @@ TEST(ProgramDecoder, GivenValidProgramWithConstantSurfacesThenDecodingSucceedsAn NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram; bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedProgram.decodeStatus); EXPECT_TRUE(decodedProgram.unhandledTokens.empty()); ASSERT_EQ(1U, decodedProgram.programScopeTokens.allocateConstantMemorySurface.size()); EXPECT_EQ(programToEncode.programScopeTokens.allocateConstantMemorySurface[0], decodedProgram.programScopeTokens.allocateConstantMemorySurface[0]); @@ -1038,7 +1038,7 @@ TEST(ProgramDecoder, GivenValidProgramWithConstantSurfacesThenDecodingSucceedsAn programToEncode.recalcTokPtr(); decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedProgram.decodeStatus); EXPECT_TRUE(decodedProgram.unhandledTokens.empty()); auto base = programToEncode.storage.data(); @@ -1047,13 +1047,22 @@ TEST(ProgramDecoder, GivenValidProgramWithConstantSurfacesThenDecodingSucceedsAn EXPECT_TRUE(tokenOffsetMatched(base, secondConstantSurfaceOff, decodedProgram.programScopeTokens.allocateConstantMemorySurface[1])); } +TEST(ProgramDecoder, GivenProgramWithConstantSurfaceWhenBlobSmallerThanNeededForPatchTokenThenDecodingFails) { + PatchTokensTestData::ValidProgramWithConstantSurface programToEncode; + NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram; + programToEncode.headerMutable->PatchListSize -= programToEncode.constSurfMutable->InlineDataSize + 1; + bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); + EXPECT_FALSE(decodeSuccess); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedProgram.decodeStatus); +} + TEST(ProgramDecoder, GivenProgramWithConstantSurfaceWhenBlobSmallerThanNeededForInlineDataThenDecodingFails) { PatchTokensTestData::ValidProgramWithConstantSurface programToEncode; NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram; programToEncode.headerMutable->PatchListSize -= 1; bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedProgram.decodeStatus); } TEST(ProgramDecoder, GivenValidProgramWithGlobalSurfacesThenDecodingSucceedsAndTokensAreProperlyAssigned) { @@ -1061,7 +1070,7 @@ TEST(ProgramDecoder, GivenValidProgramWithGlobalSurfacesThenDecodingSucceedsAndT NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram; bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedProgram.decodeStatus); EXPECT_TRUE(decodedProgram.unhandledTokens.empty()); ASSERT_EQ(1U, decodedProgram.programScopeTokens.allocateGlobalMemorySurface.size()); EXPECT_EQ(programToEncode.programScopeTokens.allocateGlobalMemorySurface[0], decodedProgram.programScopeTokens.allocateGlobalMemorySurface[0]); @@ -1075,7 +1084,7 @@ TEST(ProgramDecoder, GivenValidProgramWithGlobalSurfacesThenDecodingSucceedsAndT programToEncode.recalcTokPtr(); decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedProgram.decodeStatus); EXPECT_TRUE(decodedProgram.unhandledTokens.empty()); auto base = programToEncode.storage.data(); @@ -1084,13 +1093,22 @@ TEST(ProgramDecoder, GivenValidProgramWithGlobalSurfacesThenDecodingSucceedsAndT EXPECT_TRUE(tokenOffsetMatched(base, secondGlobalSurfaceOff, decodedProgram.programScopeTokens.allocateGlobalMemorySurface[1])); } +TEST(ProgramDecoder, GivenProgramWithGlobalSurfaceWhenBlobSmallerThanNeededForPatchTokenThenDecodingFails) { + PatchTokensTestData::ValidProgramWithGlobalSurface programToEncode; + NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram; + programToEncode.headerMutable->PatchListSize -= programToEncode.globalSurfMutable->InlineDataSize + 1; + bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); + EXPECT_FALSE(decodeSuccess); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedProgram.decodeStatus); +} + TEST(ProgramDecoder, GivenProgramWithGlobalSurfaceWhenBlobSmallerThanNeededForInlineDataThenDecodingFails) { PatchTokensTestData::ValidProgramWithGlobalSurface programToEncode; NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram; programToEncode.headerMutable->PatchListSize -= 1; bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedProgram.decodeStatus); } TEST(ProgramDecoder, GivenValidProgramWithPatchtokensThenDecodingSucceedsAndTokensAreProperlyAssinged) { @@ -1106,7 +1124,7 @@ TEST(ProgramDecoder, GivenValidProgramWithPatchtokensThenDecodingSucceedsAndToke programToEncode.recalcTokPtr(); bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedProgram.decodeStatus); EXPECT_TRUE(decodedProgram.unhandledTokens.empty()); auto base = programToEncode.storage.data(); @@ -1128,7 +1146,7 @@ TEST(ProgramDecoder, GivenProgramWithUnkownPatchtokensThenDecodingSucceedsButTok programToEncode.constSurfMutable->Size += programToEncode.constSurfMutable->InlineDataSize; bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedProgram.decodeStatus); ASSERT_EQ(1U, decodedProgram.unhandledTokens.size()); EXPECT_EQ(programToEncode.constSurfMutable, decodedProgram.unhandledTokens[0]); } @@ -1138,12 +1156,12 @@ TEST(ProgramDecoder, GivenValidProgramWithKernelThenDecodingSucceedsAndTokensAre NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram; bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.blobs.programInfo, decodedProgram); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedProgram.decodeStatus); EXPECT_TRUE(decodedProgram.unhandledTokens.empty()); ASSERT_EQ(1U, decodedProgram.header->NumberOfKernels); ASSERT_EQ(1U, decodedProgram.kernels.size()); auto decodedKernel = decodedProgram.kernels[0]; - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); EXPECT_TRUE(decodedKernel.unhandledTokens.empty()); EXPECT_NE(nullptr, decodedKernel.tokens.allocateLocalSurface); } @@ -1155,18 +1173,18 @@ TEST(ProgramDecoder, GivenValidProgramWithTwoKernelsWhenThenDecodingSucceeds) { NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram; bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.storage, decodedProgram); EXPECT_TRUE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedProgram.decodeStatus); EXPECT_TRUE(decodedProgram.unhandledTokens.empty()); EXPECT_EQ(2U, decodedProgram.header->NumberOfKernels); ASSERT_EQ(2U, decodedProgram.kernels.size()); auto decodedKernel0 = decodedProgram.kernels[0]; - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel0.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel0.decodeStatus); EXPECT_TRUE(decodedKernel0.unhandledTokens.empty()); EXPECT_NE(nullptr, decodedKernel0.tokens.allocateLocalSurface); auto decodedKernel1 = decodedProgram.kernels[0]; - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel1.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel1.decodeStatus); EXPECT_TRUE(decodedKernel1.unhandledTokens.empty()); EXPECT_NE(nullptr, decodedKernel1.tokens.allocateLocalSurface); } @@ -1177,7 +1195,7 @@ TEST(ProgramDecoder, GivenPatchTokenWithZeroSizeThenDecodingFailsAndStops) { NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram; bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.storage, decodedProgram); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedProgram.decodeStatus); } TEST(ProgramDecoder, GivenProgramWithMultipleKernelsWhenFailsToDecodeKernelThenDecodingFailsAndStops) { @@ -1188,7 +1206,7 @@ TEST(ProgramDecoder, GivenProgramWithMultipleKernelsWhenFailsToDecodeKernelThenD NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram; bool decodeSuccess = NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToEncode.storage, decodedProgram); EXPECT_FALSE(decodeSuccess); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::InvalidBinary, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, decodedProgram.decodeStatus); EXPECT_TRUE(decodedProgram.unhandledTokens.empty()); EXPECT_EQ(2U, decodedProgram.header->NumberOfKernels); EXPECT_EQ(1U, decodedProgram.kernels.size()); diff --git a/core/unit_tests/device_binary_format/patchtokens_dumper_tests.cpp b/core/unit_tests/device_binary_format/patchtokens_dumper_tests.cpp index 22d8456ff8..5b5deb58d7 100644 --- a/core/unit_tests/device_binary_format/patchtokens_dumper_tests.cpp +++ b/core/unit_tests/device_binary_format/patchtokens_dumper_tests.cpp @@ -14,7 +14,7 @@ TEST(ProgramDumper, GivenEmptyProgramThenProperlyCreatesDumpStringWithWarnig) { NEO::PatchTokenBinary::ProgramFromPatchtokens emptyProgram = {}; - emptyProgram.decodeStatus = NEO::PatchTokenBinary::DecoderError::Undefined; + emptyProgram.decodeStatus = NEO::DecodeError::Undefined; std::string generated = NEO::PatchTokenBinary::asString(emptyProgram); const char *expected = R"===(Program of size : 0 in undefined status @@ -24,7 +24,7 @@ Kernels section size : 0 )==="; EXPECT_STREQ(expected, generated.c_str()); - emptyProgram.decodeStatus = NEO::PatchTokenBinary::DecoderError::InvalidBinary; + emptyProgram.decodeStatus = NEO::DecodeError::InvalidBinary; generated = NEO::PatchTokenBinary::asString(emptyProgram); expected = R"===(Program of size : 0 with invalid binary @@ -34,7 +34,7 @@ Kernels section size : 0 )==="; EXPECT_STREQ(expected, generated.c_str()); - emptyProgram.decodeStatus = NEO::PatchTokenBinary::DecoderError::Success; + emptyProgram.decodeStatus = NEO::DecodeError::Success; generated = NEO::PatchTokenBinary::asString(emptyProgram); expected = R"===(Program of size : 0 decoded successfully @@ -47,7 +47,7 @@ Kernels section size : 0 TEST(KernelDumper, GivenEmptyKernelThenProperlyCreatesDumpStringWithWarnig) { NEO::PatchTokenBinary::KernelFromPatchtokens emptyKernel = {}; - emptyKernel.decodeStatus = NEO::PatchTokenBinary::DecoderError::Undefined; + emptyKernel.decodeStatus = NEO::DecodeError::Undefined; std::string generated = NEO::PatchTokenBinary::asString(emptyKernel); const char *expected = R"===(Kernel of size : 0 in undefined status @@ -56,7 +56,7 @@ Kernel-scope tokens section size : 0 )==="; EXPECT_STREQ(expected, generated.c_str()); - emptyKernel.decodeStatus = NEO::PatchTokenBinary::DecoderError::InvalidBinary; + emptyKernel.decodeStatus = NEO::DecodeError::InvalidBinary; generated = NEO::PatchTokenBinary::asString(emptyKernel); expected = R"===(Kernel of size : 0 with invalid binary @@ -65,7 +65,7 @@ Kernel-scope tokens section size : 0 )==="; EXPECT_STREQ(expected, generated.c_str()); - emptyKernel.decodeStatus = NEO::PatchTokenBinary::DecoderError::Success; + emptyKernel.decodeStatus = NEO::DecodeError::Success; generated = NEO::PatchTokenBinary::asString(emptyKernel); expected = R"===(Kernel of size : 0 decoded successfully @@ -2084,7 +2084,7 @@ TEST(PatchTokenDumper, GivenAnyTokenThenDumpingIsHandled) { kernelToken->Token = i; decodedKernel = {}; NEO::PatchTokenBinary::decodeKernelFromPatchtokensBlob(kernelToDecode.blobs.kernelInfo, decodedKernel); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedKernel.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedKernel.decodeStatus); if (decodedKernel.unhandledTokens.empty()) { auto dump = NEO::PatchTokenBinary::asString(decodedKernel); EXPECT_EQ(std::string::npos, dump.find("struct SPatchItemHeader")) << "Update patchtokens_dumper.cpp with definition of new patchtoken : " << i; @@ -2095,7 +2095,7 @@ TEST(PatchTokenDumper, GivenAnyTokenThenDumpingIsHandled) { programToken->Token = i; decodedProgram = {}; NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(programToDecode.blobs.programInfo, decodedProgram); - EXPECT_EQ(NEO::PatchTokenBinary::DecoderError::Success, decodedProgram.decodeStatus); + EXPECT_EQ(NEO::DecodeError::Success, decodedProgram.decodeStatus); if (decodedProgram.unhandledTokens.empty()) { auto dump = NEO::PatchTokenBinary::asString(decodedProgram); EXPECT_EQ(std::string::npos, dump.find("struct SPatchItemHeader")) << "Update patchtokens_dumper.cpp with definition of new patchtoken : " << i; diff --git a/core/unit_tests/device_binary_format/patchtokens_tests.h b/core/unit_tests/device_binary_format/patchtokens_tests.h index a31927c807..47798cc2cc 100644 --- a/core/unit_tests/device_binary_format/patchtokens_tests.h +++ b/core/unit_tests/device_binary_format/patchtokens_tests.h @@ -83,7 +83,7 @@ struct ValidEmptyProgram : NEO::PatchTokenBinary::ProgramFromPatchtokens { headerTok.Version = iOpenCL::CURRENT_ICBE_VERSION; headerTok.Device = renderCoreFamily; headerTok.GPUPointerSizeInBytes = sizeof(uintptr_t); - this->decodeStatus = NEO::PatchTokenBinary::DecoderError::Success; + this->decodeStatus = NEO::DecodeError::Success; storage.insert(storage.end(), reinterpret_cast(&headerTok), reinterpret_cast((&headerTok) + 1)); recalcTokPtr(); @@ -228,7 +228,7 @@ struct ValidEmptyKernel { execEnvTokInl.LargestCompiledSIMDSize = 32U; execEnvTokInl.CompiledSIMD32 = 1U; headerTokInl.PatchListSize = sizeof(execEnvTokInl); - ret.decodeStatus = NEO::PatchTokenBinary::DecoderError::Success; + ret.decodeStatus = NEO::DecodeError::Success; ret.name = "test_kernel"; headerTokInl.KernelNameSize = static_cast(ret.name.size()); @@ -253,7 +253,7 @@ struct ValidProgramWithKernel : ValidEmptyProgram { this->headerMutable->NumberOfKernels = 1; kernOffset = storage.size(); this->kernels.push_back(ValidEmptyKernel::create(storage)); - this->kernels[0].decodeStatus = NEO::PatchTokenBinary::DecoderError::Success; + this->kernels[0].decodeStatus = NEO::DecodeError::Success; kernExecEnvOffset = ptrDiff(this->kernels[0].blobs.patchList.begin(), storage.data()); recalcTokPtr(); } diff --git a/core/unit_tests/device_binary_format/patchtokens_validator_tests.cpp b/core/unit_tests/device_binary_format/patchtokens_validator_tests.cpp index 39b36175a4..5a1eeb3d9a 100644 --- a/core/unit_tests/device_binary_format/patchtokens_validator_tests.cpp +++ b/core/unit_tests/device_binary_format/patchtokens_validator_tests.cpp @@ -6,26 +6,17 @@ */ #include "core/device_binary_format/patchtokens_decoder.h" -#include "core/device_binary_format/patchtokens_validator.inl" +#include "core/device_binary_format/patchtokens_validator.h" #include "core/unit_tests/device_binary_format/patchtokens_tests.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -struct UknownTokenValidator { - UknownTokenValidator(bool isSafeToSkip = true) : isSafeToSkip(isSafeToSkip) { - } - bool isSafeToSkipUnhandledToken(uint32_t token) const { - return isSafeToSkip; - } - bool isSafeToSkip = true; -}; - TEST(PatchtokensValidator, GivenValidProgramThenValidationSucceeds) { PatchTokensTestData::ValidEmptyProgram prog; std::string error, warning; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); } @@ -34,16 +25,16 @@ TEST(PatchtokensValidator, GivenProgramWithInvalidOrUnknownStatusThenValidationF PatchTokensTestData::ValidEmptyProgram prog; std::string error, warning; - prog.decodeStatus = NEO::PatchTokenBinary::DecoderError::Undefined; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + prog.decodeStatus = NEO::DecodeError::Undefined; + EXPECT_EQ(NEO::DecodeError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("ProgramFromPatchtokens wasn't successfully decoded", error.c_str()); EXPECT_TRUE(warning.empty()); error.clear(); warning.clear(); - prog.decodeStatus = NEO::PatchTokenBinary::DecoderError::InvalidBinary; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + prog.decodeStatus = NEO::DecodeError::InvalidBinary; + EXPECT_EQ(NEO::DecodeError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("ProgramFromPatchtokens wasn't successfully decoded", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -52,7 +43,7 @@ TEST(PatchtokensValidator, GivenValidProgramWithASingleConstantSurfaceThenValida PatchTokensTestData::ValidProgramWithConstantSurface prog; std::string error, warning; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); } @@ -63,7 +54,7 @@ TEST(PatchtokensValidator, GivenProgramWithMultipleConstantSurfacesThenValidatio iOpenCL::SPatchAllocateConstantMemorySurfaceProgramBinaryInfo constSurface2 = *prog.programScopeTokens.allocateConstantMemorySurface[0]; prog.programScopeTokens.allocateConstantMemorySurface.push_back(&constSurface2); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled number of global constants surfaces > 1", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -72,7 +63,7 @@ TEST(PatchtokensValidator, GivenValidProgramWithASingleGlobalSurfaceThenValidati PatchTokensTestData::ValidProgramWithGlobalSurface prog; std::string error, warning; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); } @@ -83,7 +74,7 @@ TEST(PatchtokensValidator, GivenProgramWithMultipleGlobalSurfacesThenValidationF iOpenCL::SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo globSurface2 = *prog.programScopeTokens.allocateGlobalMemorySurface[0]; prog.programScopeTokens.allocateGlobalMemorySurface.push_back(&globSurface2); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled number of global variables surfaces > 1", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -92,7 +83,7 @@ TEST(PatchtokensValidator, GivenValidProgramWithValidConstantPointerThenValidati PatchTokensTestData::ValidProgramWithConstantSurfaceAndPointer prog; std::string error, warning; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); } @@ -102,7 +93,7 @@ TEST(PatchtokensValidator, GivenProgramWithInvalidConstantPointerBufferIndexThen std::string error, warning; prog.constantPointerMutable->BufferIndex = 1; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled SPatchConstantPointerProgramBinaryInfo", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -112,36 +103,36 @@ TEST(PatchtokensValidator, GivenProgramWithInvalidGpuPointerSizeThenValidationFa std::string error, warning; prog.headerMutable->GPUPointerSizeInBytes = 0U; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Invalid pointer size", error.c_str()); EXPECT_TRUE(warning.empty()); prog.headerMutable->GPUPointerSizeInBytes = 1U; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); prog.headerMutable->GPUPointerSizeInBytes = 2U; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); prog.headerMutable->GPUPointerSizeInBytes = 3U; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); prog.headerMutable->GPUPointerSizeInBytes = 4U; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); prog.headerMutable->GPUPointerSizeInBytes = 5U; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); prog.headerMutable->GPUPointerSizeInBytes = 6U; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); prog.headerMutable->GPUPointerSizeInBytes = 7U; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); prog.headerMutable->GPUPointerSizeInBytes = 8U; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); prog.headerMutable->GPUPointerSizeInBytes = 9U; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); } TEST(PatchtokensValidator, GivenProgramWithInvalidConstantPointerConstantBufferIndexThenValidationFails) { @@ -149,7 +140,7 @@ TEST(PatchtokensValidator, GivenProgramWithInvalidConstantPointerConstantBufferI std::string error, warning; prog.constantPointerMutable->ConstantBufferIndex = 1; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled SPatchConstantPointerProgramBinaryInfo", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -159,7 +150,7 @@ TEST(PatchtokensValidator, GivenProgramWithInvalidConstantPointerBufferTypeThenV std::string error, warning; prog.constantPointerMutable->BufferType = iOpenCL::NUM_PROGRAM_SCOPE_BUFFER_TYPE; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled SPatchConstantPointerProgramBinaryInfo", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -169,7 +160,7 @@ TEST(PatchtokensValidator, GivenProgramWithInvalidConstantPointerOffsetThenValid std::string error, warning; prog.constantPointerMutable->ConstantPointerOffset = prog.constSurfMutable->InlineDataSize; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled SPatchConstantPointerProgramBinaryInfo", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -179,7 +170,7 @@ TEST(PatchtokensValidator, GivenProgramWithoutConstantSurfaceButWithConstantPoin std::string error, warning; prog.programScopeTokens.allocateConstantMemorySurface.clear(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled SPatchConstantPointerProgramBinaryInfo", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -188,7 +179,7 @@ TEST(PatchtokensValidator, GivenValidProgramWithValidGlobalPointerThenValidation PatchTokensTestData::ValidProgramWithGlobalSurfaceAndPointer prog; std::string error, warning; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); } @@ -197,7 +188,7 @@ TEST(PatchtokensValidator, GivenValidProgramWithMixedGlobalVarAndConstSurfacesAn PatchTokensTestData::ValidProgramWithMixedGlobalVarAndConstSurfacesAndPointers prog; std::string error, warning; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); } @@ -207,13 +198,13 @@ TEST(PatchtokensValidator, GivenInvalidProgramWithMixedGlobalVarAndConstSurfaces PatchTokensTestData::ValidProgramWithGlobalSurfaceAndPointer progGlobalVar; progGlobalVar.globalPointerMutable->BufferType = iOpenCL::PROGRAM_SCOPE_CONSTANT_BUFFER; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(progGlobalVar, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(progGlobalVar, error, warning)); EXPECT_FALSE(error.empty()); EXPECT_TRUE(warning.empty()); PatchTokensTestData::ValidProgramWithConstantSurfaceAndPointer progConstVar; progConstVar.constantPointerMutable->BufferType = iOpenCL::PROGRAM_SCOPE_GLOBAL_BUFFER; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(progConstVar, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(progConstVar, error, warning)); EXPECT_FALSE(error.empty()); EXPECT_TRUE(warning.empty()); } @@ -223,7 +214,7 @@ TEST(PatchtokensValidator, GivenProgramWithInvalidGlobalPointerBufferIndexThenVa std::string error, warning; prog.globalPointerMutable->BufferIndex = 1; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled SPatchGlobalPointerProgramBinaryInfo", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -233,7 +224,7 @@ TEST(PatchtokensValidator, GivenProgramWithInvalidGlobalPointerGlobalBufferIndex std::string error, warning; prog.globalPointerMutable->GlobalBufferIndex = 1; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled SPatchGlobalPointerProgramBinaryInfo", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -243,7 +234,7 @@ TEST(PatchtokensValidator, GivenProgramWithInvalidGlobalPointerBufferTypeThenVal std::string error, warning; prog.globalPointerMutable->BufferType = iOpenCL::NUM_PROGRAM_SCOPE_BUFFER_TYPE; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled SPatchGlobalPointerProgramBinaryInfo", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -253,7 +244,7 @@ TEST(PatchtokensValidator, GivenProgramWithInvalidGlobalPointerOffsetThenValidat std::string error, warning; prog.globalPointerMutable->GlobalPointerOffset = prog.globalSurfMutable->InlineDataSize; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled SPatchGlobalPointerProgramBinaryInfo", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -263,7 +254,7 @@ TEST(PatchtokensValidator, GivenProgramWithoutGlobalSurfaceButWithGlobalPointerT std::string error, warning; prog.programScopeTokens.allocateGlobalMemorySurface.clear(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("Unhandled SPatchGlobalPointerProgramBinaryInfo", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -275,7 +266,10 @@ TEST(PatchtokensValidator, GivenValidProgramWithUnknownPatchTokenWhenUknownToken iOpenCL::SPatchItemHeader unknownToken = {}; unknownToken.Token = iOpenCL::NUM_PATCH_TOKENS + 1; prog.unhandledTokens.push_back(&unknownToken); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(false), error, warning)); + auto prevValue = NEO::PatchTokenBinary::allowUnhandledTokens; + NEO::PatchTokenBinary::allowUnhandledTokens = false; + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); + NEO::PatchTokenBinary::allowUnhandledTokens = prevValue; auto expectedError = "Unhandled required program-scope Patch Token : " + std::to_string(unknownToken.Token); EXPECT_STREQ(expectedError.c_str(), error.c_str()); EXPECT_TRUE(warning.empty()); @@ -288,7 +282,10 @@ TEST(PatchtokensValidator, GivenValidProgramWithUnknownPatchTokenWhenUknownToken iOpenCL::SPatchItemHeader unknownToken = {}; unknownToken.Token = iOpenCL::NUM_PATCH_TOKENS + 1; prog.unhandledTokens.push_back(&unknownToken); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + auto prevValue = NEO::PatchTokenBinary::allowUnhandledTokens; + NEO::PatchTokenBinary::allowUnhandledTokens = true; + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); + NEO::PatchTokenBinary::allowUnhandledTokens = prevValue; auto expectedWarning = "Unknown program-scope Patch Token : " + std::to_string(unknownToken.Token); EXPECT_TRUE(error.empty()); EXPECT_STREQ(expectedWarning.c_str(), warning.c_str()); @@ -299,28 +296,17 @@ TEST(PatchtokensValidator, GivenProgramWithUnsupportedPatchTokenVersionThenValid std::string error, warning; prog.headerMutable->Version = std::numeric_limits::max(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); auto expectedError = "Unhandled Version of Patchtokens: expected: " + std::to_string(iOpenCL::CURRENT_ICBE_VERSION) + ", got: " + std::to_string(prog.header->Version); EXPECT_STREQ(expectedError.c_str(), error.c_str()); EXPECT_TRUE(warning.empty()); } -TEST(PatchtokensValidator, GivenProgramWithUnsupportedPlatformThenValidationFails) { - PatchTokensTestData::ValidEmptyProgram prog; - std::string error, warning; - - prog.headerMutable->Device = IGFX_MAX_CORE; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); - auto expectedError = "Unsupported device binary, device GFXCORE_FAMILY : " + std::to_string(prog.header->Device); - EXPECT_STREQ(expectedError.c_str(), error.c_str()); - EXPECT_EQ(0U, warning.size()); -} - TEST(PatchtokensValidator, GivenValidProgramWithKernelThenValidationSucceeds) { PatchTokensTestData::ValidProgramWithKernel prog; std::string error, warning; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); } @@ -329,16 +315,16 @@ TEST(PatchtokensValidator, GivenProgramWithKernelWhenKernelHasInvalidOrUnknownSt PatchTokensTestData::ValidProgramWithKernel prog; std::string error, warning; - prog.kernels[0].decodeStatus = NEO::PatchTokenBinary::DecoderError::Undefined; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + prog.kernels[0].decodeStatus = NEO::DecodeError::Undefined; + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("KernelFromPatchtokens wasn't successfully decoded", error.c_str()); EXPECT_TRUE(warning.empty()); error.clear(); warning.clear(); - prog.kernels[0].decodeStatus = NEO::PatchTokenBinary::DecoderError::InvalidBinary; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + prog.kernels[0].decodeStatus = NEO::DecodeError::InvalidBinary; + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("KernelFromPatchtokens wasn't successfully decoded", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -348,7 +334,7 @@ TEST(PatchtokensValidator, GivenProgramWithKernelWhenKernelHasInvalidChecksumThe std::string error, warning; prog.kernelHeaderMutable->CheckSum += 1; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ("KernelFromPatchtokens has invalid checksum", error.c_str()); EXPECT_TRUE(warning.empty()); } @@ -357,22 +343,12 @@ TEST(PatchtokensValidator, GivenValidProgramWithKernelUsingSlmThenValidationSucc PatchTokensTestData::ValidProgramWithKernelUsingSlm prog; std::string error, warning; - size_t slmSizeAvailable = 1 + prog.kernels[0].tokens.allocateLocalSurface->TotalInlineLocalMemorySize; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, slmSizeAvailable, UknownTokenValidator(), error, warning)); + //size_t slmSizeAvailable = 1 + prog.kernels[0].tokens.allocateLocalSurface->TotalInlineLocalMemorySize; + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); } -TEST(PatchtokensValidator, GivenProgramWithKernelUsingSlmWhenKernelRequiresTooMuchSlmThenValidationFails) { - PatchTokensTestData::ValidProgramWithKernelUsingSlm prog; - std::string error, warning; - - size_t slmSizeAvailable = -1 + prog.kernels[0].tokens.allocateLocalSurface->TotalInlineLocalMemorySize; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::NotEnoughSlm, NEO::PatchTokenBinary::validate(prog, slmSizeAvailable, UknownTokenValidator(), error, warning)); - EXPECT_STREQ("KernelFromPatchtokens requires too much SLM", error.c_str()); - EXPECT_TRUE(warning.empty()); -} - TEST(PatchtokensValidator, GivenValidProgramWithKernelContainingUnknownPatchTokenWhenUknownTokenCantBeSkippedThenValidationFails) { PatchTokensTestData::ValidProgramWithKernel prog; std::string error, warning; @@ -380,7 +356,10 @@ TEST(PatchtokensValidator, GivenValidProgramWithKernelContainingUnknownPatchToke iOpenCL::SPatchItemHeader unknownToken = {}; unknownToken.Token = iOpenCL::NUM_PATCH_TOKENS + 1; prog.kernels[0].unhandledTokens.push_back(&unknownToken); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(false), error, warning)); + auto prevValue = NEO::PatchTokenBinary::allowUnhandledTokens; + NEO::PatchTokenBinary::allowUnhandledTokens = false; + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); + NEO::PatchTokenBinary::allowUnhandledTokens = prevValue; auto expectedError = "Unhandled required kernel-scope Patch Token : " + std::to_string(unknownToken.Token); EXPECT_STREQ(expectedError.c_str(), error.c_str()); EXPECT_TRUE(warning.empty()); @@ -393,7 +372,10 @@ TEST(PatchtokensValidator, GivenValidProgramWithKernelContainingUnknownPatchToke iOpenCL::SPatchItemHeader unknownToken = {}; unknownToken.Token = iOpenCL::NUM_PATCH_TOKENS + 1; prog.kernels[0].unhandledTokens.push_back(&unknownToken); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + auto prevValue = NEO::PatchTokenBinary::allowUnhandledTokens; + NEO::PatchTokenBinary::allowUnhandledTokens = true; + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); + NEO::PatchTokenBinary::allowUnhandledTokens = prevValue; auto expectedWarning = "Unknown kernel-scope Patch Token : " + std::to_string(unknownToken.Token); EXPECT_TRUE(error.empty()); EXPECT_STREQ(expectedWarning.c_str(), warning.c_str()); @@ -403,7 +385,7 @@ TEST(PatchtokensValidator, GivenProgramWithKernelWhenKernelArgsHasProperQualifie PatchTokensTestData::ValidProgramWithKernelAndArg prog; std::string error, warning; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); } @@ -412,7 +394,7 @@ TEST(PatchtokensValidator, GivenProgramWithKernelAndArgThenKernelArgInfoIsOption PatchTokensTestData::ValidProgramWithKernelAndArg prog; std::string error, warning; prog.kernels[0].tokens.kernelArgs[0].argInfo = nullptr; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); } @@ -422,7 +404,7 @@ TEST(PatchtokensValidator, GivenProgramWithKernelWhenKernelsArgHasUnknownAddress std::string error, warning; prog.arg0InfoAddressQualifierMutable[2] = '\0'; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); auto expectedError = "Unhandled address qualifier"; EXPECT_STREQ(expectedError, error.c_str()); EXPECT_TRUE(warning.empty()); @@ -433,7 +415,7 @@ TEST(PatchtokensValidator, GivenProgramWithKernelWhenKernelsArgHasUnknownAccessQ std::string error, warning; prog.arg0InfoAccessQualifierMutable[2] = '\0'; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); auto expectedError = "Unhandled access qualifier"; EXPECT_STREQ(expectedError, error.c_str()); EXPECT_TRUE(warning.empty()); @@ -443,7 +425,7 @@ TEST(PatchtokensValidator, GivenKernelWhenExecutionEnvironmentIsMissingThenValid PatchTokensTestData::ValidProgramWithKernel prog; std::string error, warning; prog.kernels[0].tokens.executionEnvironment = nullptr; - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); auto expectedError = "Missing execution environment"; EXPECT_STREQ(expectedError, error.c_str()); EXPECT_TRUE(warning.empty()); @@ -454,7 +436,7 @@ TEST(PatchtokensValidator, GivenKernelWhenExecutionEnvironmentHasInvalidSimdSize std::string error, warning; prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 0U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); auto expectedError = "Invalid LargestCompiledSIMDSize"; EXPECT_STREQ(expectedError, error.c_str()); EXPECT_TRUE(warning.empty()); @@ -462,77 +444,81 @@ TEST(PatchtokensValidator, GivenKernelWhenExecutionEnvironmentHasInvalidSimdSize error.clear(); prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 1U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); error.clear(); prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 2U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ(expectedError, error.c_str()); EXPECT_TRUE(warning.empty()); error.clear(); prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 3U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ(expectedError, error.c_str()); EXPECT_TRUE(warning.empty()); error.clear(); prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 4U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ(expectedError, error.c_str()); EXPECT_TRUE(warning.empty()); error.clear(); prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 5U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ(expectedError, error.c_str()); EXPECT_TRUE(warning.empty()); error.clear(); prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 6U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ(expectedError, error.c_str()); EXPECT_TRUE(warning.empty()); error.clear(); prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 7U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ(expectedError, error.c_str()); EXPECT_TRUE(warning.empty()); error.clear(); prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 8U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); error.clear(); prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 9U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::InvalidBinary, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::UnhandledBinary, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_STREQ(expectedError, error.c_str()); EXPECT_TRUE(warning.empty()); error.clear(); prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 16U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); error.clear(); prog.kernelExecEnvMutable->LargestCompiledSIMDSize = 32U; prog.recalcTokPtr(); - EXPECT_EQ(NEO::PatchTokenBinary::ValidatorError::Success, NEO::PatchTokenBinary::validate(prog, 0U, UknownTokenValidator(true), error, warning)); + EXPECT_EQ(NEO::DecodeError::Success, NEO::PatchTokenBinary::validate(prog, error, warning)); EXPECT_TRUE(error.empty()); EXPECT_TRUE(warning.empty()); } + +TEST(PatchtokensValidator, GivenDefaultStateThenUnhandledPatchtokensAreAllowed) { + EXPECT_TRUE(NEO::PatchTokenBinary::allowUnhandledTokens); +} diff --git a/core/unit_tests/program/program_info_from_patchtokens_tests.cpp b/core/unit_tests/program/program_info_from_patchtokens_tests.cpp index 801d4bca6b..bfffeb27fe 100644 --- a/core/unit_tests/program/program_info_from_patchtokens_tests.cpp +++ b/core/unit_tests/program/program_info_from_patchtokens_tests.cpp @@ -46,7 +46,7 @@ TEST(PopulateProgramInfoFromPatchtokensTests, WhenRequiresLocalMemoryWindowVAIsC TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresGlobalConstantsSurfaceThenGlobalConstantsSectionIsPopulated) { PatchTokensTestData::ValidProgramWithConstantSurface programTokens; NEO::ProgramInfo programInfo; - NEO::populateProgramInfo(programInfo, programTokens, {}); + NEO::populateProgramInfo(programInfo, programTokens); EXPECT_EQ(programInfo.globalConstants.size, programTokens.programScopeTokens.allocateConstantMemorySurface[0]->InlineDataSize); EXPECT_EQ(programInfo.globalConstants.initData, NEO::PatchTokenBinary::getInlineData(programTokens.programScopeTokens.allocateConstantMemorySurface[0])); EXPECT_TRUE(programInfo.kernelInfos.empty()); @@ -56,7 +56,7 @@ TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresGlobalConstants TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresGlobalVariablesSurfaceThenGlobalConstantsSectionIsPopulated) { PatchTokensTestData::ValidProgramWithGlobalSurface programTokens; NEO::ProgramInfo programInfo; - NEO::populateProgramInfo(programInfo, programTokens, {}); + NEO::populateProgramInfo(programInfo, programTokens); EXPECT_EQ(programInfo.globalVariables.size, programTokens.programScopeTokens.allocateGlobalMemorySurface[0]->InlineDataSize); EXPECT_EQ(programInfo.globalVariables.initData, NEO::PatchTokenBinary::getInlineData(programTokens.programScopeTokens.allocateGlobalMemorySurface[0])); EXPECT_TRUE(programInfo.kernelInfos.empty()); @@ -66,7 +66,7 @@ TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresGlobalVariables TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresGlobalConstantsPointersThenLinkerInputContainsProperRelocations) { PatchTokensTestData::ValidProgramWithConstantSurfaceAndPointer programFromTokens; NEO::ProgramInfo programInfo; - NEO::populateProgramInfo(programInfo, programFromTokens, {}); + NEO::populateProgramInfo(programInfo, programFromTokens); EXPECT_TRUE(programInfo.kernelInfos.empty()); ASSERT_NE(nullptr, programInfo.linkerInput); ASSERT_EQ(1U, programInfo.linkerInput->getDataRelocations().size()); @@ -81,7 +81,7 @@ TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresGlobalConstants TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresGlobalVariablesPointersThenLinkerInputContainsProperRelocations) { PatchTokensTestData::ValidProgramWithGlobalSurfaceAndPointer programFromTokens; NEO::ProgramInfo programInfo; - NEO::populateProgramInfo(programInfo, programFromTokens, {}); + NEO::populateProgramInfo(programInfo, programFromTokens); EXPECT_TRUE(programInfo.kernelInfos.empty()); ASSERT_NE(nullptr, programInfo.linkerInput); ASSERT_EQ(1U, programInfo.linkerInput->getDataRelocations().size()); @@ -96,7 +96,7 @@ TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresGlobalVariables TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresMixedGlobalVarAndConstPointersThenLinkerInputContainsProperRelocations) { PatchTokensTestData::ValidProgramWithMixedGlobalVarAndConstSurfacesAndPointers programFromTokens; NEO::ProgramInfo programInfo; - NEO::populateProgramInfo(programInfo, programFromTokens, {}); + NEO::populateProgramInfo(programInfo, programFromTokens); EXPECT_TRUE(programInfo.kernelInfos.empty()); ASSERT_NE(nullptr, programInfo.linkerInput); @@ -135,7 +135,7 @@ TEST(PopulateProgramInfoFromPatchtokensTests, GivenProgramWithSpecificPointerSiz { programFromTokens.headerMutable->GPUPointerSizeInBytes = 8; NEO::ProgramInfo programInfo; - NEO::populateProgramInfo(programInfo, programFromTokens, {}); + NEO::populateProgramInfo(programInfo, programFromTokens); ASSERT_NE(nullptr, programInfo.linkerInput); EXPECT_EQ(NEO::LinkerInput::Traits::Ptr64bit, programInfo.linkerInput->getTraits().pointerSize); } @@ -143,7 +143,7 @@ TEST(PopulateProgramInfoFromPatchtokensTests, GivenProgramWithSpecificPointerSiz { programFromTokens.headerMutable->GPUPointerSizeInBytes = 4; NEO::ProgramInfo programInfo; - NEO::populateProgramInfo(programInfo, programFromTokens, {}); + NEO::populateProgramInfo(programInfo, programFromTokens); ASSERT_NE(nullptr, programInfo.linkerInput); EXPECT_EQ(NEO::LinkerInput::Traits::Ptr32bit, programInfo.linkerInput->getTraits().pointerSize); } @@ -173,7 +173,7 @@ TEST(PopulateProgramInfoFromPatchtokensTests, GivenProgramWithProgramSymbolTable receivedNumEntries = numEntries; return true; }; - NEO::populateProgramInfo(programInfo, programFromTokens, {}); + NEO::populateProgramInfo(programInfo, programFromTokens); ASSERT_EQ(mockLinkerInput, programInfo.linkerInput.get()); EXPECT_EQ(1U, mockLinkerInput->decodeGlobalVariablesSymbolTableMockConfig.timesCalled); @@ -186,7 +186,7 @@ TEST(PopulateProgramInfoFromPatchtokensTests, GivenProgramWithKernelsThenKernelI programFromTokens.kernels.push_back(programFromTokens.kernels[0]); programFromTokens.kernels.push_back(programFromTokens.kernels[0]); NEO::ProgramInfo programInfo = {}; - NEO::populateProgramInfo(programInfo, programFromTokens, {}); + NEO::populateProgramInfo(programInfo, programFromTokens); ASSERT_EQ(3U, programInfo.kernelInfos.size()); EXPECT_EQ(programFromTokens.header->GPUPointerSizeInBytes, programInfo.kernelInfos[0]->gpuPointerSize); EXPECT_EQ(programFromTokens.header->GPUPointerSizeInBytes, programInfo.kernelInfos[1]->gpuPointerSize); @@ -232,7 +232,7 @@ TEST(PopulateProgramInfoFromPatchtokensTests, GivenProgramWithKernelsWhenKernelH receivedSegmentIds.push_back(instructionsSegmentId); return true; }; - NEO::populateProgramInfo(programInfo, programFromTokens, {}); + NEO::populateProgramInfo(programInfo, programFromTokens); ASSERT_EQ(2U, mockLinkerInput->decodeExportedFunctionsSymbolTableMockConfig.timesCalled); ASSERT_EQ(2U, receivedData.size()); @@ -283,7 +283,7 @@ TEST(PopulateProgramInfoFromPatchtokensTests, GivenProgramWithKernelsWhenKernelH receivedSegmentIds.push_back(instructionsSegmentId); return true; }; - NEO::populateProgramInfo(programInfo, programFromTokens, {}); + NEO::populateProgramInfo(programInfo, programFromTokens); ASSERT_EQ(2U, mockLinkerInput->decodeRelocationTableMockConfig.timesCalled); ASSERT_EQ(2U, receivedData.size()); diff --git a/core/unit_tests/program/program_info_tests.cpp b/core/unit_tests/program/program_info_tests.cpp index f58b9a72f0..25184f6022 100644 --- a/core/unit_tests/program/program_info_tests.cpp +++ b/core/unit_tests/program/program_info_tests.cpp @@ -6,11 +6,12 @@ */ #include "core/program/program_info.h" +#include "runtime/program/kernel_info.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -TEST(ProgramInfoTests, whenPrepareLinkerInputStorageGetsCalledTwiceThenLinkerInputStorageIsReused) { +TEST(ProgramInfoTests, WhenPrepareLinkerInputStorageGetsCalledTwiceThenLinkerInputStorageIsReused) { NEO::ProgramInfo programInfo; EXPECT_EQ(nullptr, programInfo.linkerInput); programInfo.prepareLinkerInputStorage(); @@ -19,3 +20,45 @@ TEST(ProgramInfoTests, whenPrepareLinkerInputStorageGetsCalledTwiceThenLinkerInp programInfo.prepareLinkerInputStorage(); EXPECT_EQ(prevLinkerInput, programInfo.linkerInput.get()); } + +TEST(GetMaxInlineSlmNeeded, GivenProgramWithoutKernelsThenReturn0) { + NEO::ProgramInfo programInfo; + EXPECT_EQ(0U, NEO::getMaxInlineSlmNeeded(programInfo)); +} + +TEST(GetMaxInlineSlmNeeded, GivenProgramWithKernelsNotRequirignSlmThenReturn0) { + NEO::ProgramInfo programInfo; + programInfo.kernelInfos = {new NEO::KernelInfo(), new NEO::KernelInfo(), new NEO::KernelInfo()}; + EXPECT_EQ(0U, NEO::getMaxInlineSlmNeeded(programInfo)); +} + +TEST(GetMaxInlineSlmNeeded, GivenProgramWithKernelsThenReturnMaxOfInlineSlmNeededByKernels) { + iOpenCL::SPatchAllocateLocalSurface slmTokens[3] = {}; + slmTokens[0].TotalInlineLocalMemorySize = 16; + slmTokens[1].TotalInlineLocalMemorySize = 64; + slmTokens[2].TotalInlineLocalMemorySize = 32; + NEO::ProgramInfo programInfo; + programInfo.kernelInfos = {new NEO::KernelInfo(), new NEO::KernelInfo(), new NEO::KernelInfo()}; + programInfo.kernelInfos[0]->patchInfo.localsurface = &slmTokens[0]; + programInfo.kernelInfos[1]->patchInfo.localsurface = &slmTokens[1]; + programInfo.kernelInfos[2]->patchInfo.localsurface = &slmTokens[2]; + EXPECT_EQ(64U, NEO::getMaxInlineSlmNeeded(programInfo)); +} + +TEST(RequiresLocalMemoryWindowVA, GivenProgramWithoutKernelsThenReturnFalse) { + NEO::ProgramInfo programInfo; + EXPECT_FALSE(NEO::requiresLocalMemoryWindowVA(programInfo)); +} + +TEST(RequiresLocalMemoryWindowVA, GivenProgramWithKernelsNotLocalMemoryWindowVAThenReturnFalse) { + NEO::ProgramInfo programInfo; + programInfo.kernelInfos = {new NEO::KernelInfo(), new NEO::KernelInfo(), new NEO::KernelInfo()}; + EXPECT_FALSE(NEO::requiresLocalMemoryWindowVA(programInfo)); +} + +TEST(RequiresLocalMemoryWindowVA, GivenProgramWithKernelsWhenSomeOfKernelRequireLocalMemoryWidnowVAThenReturnTrue) { + NEO::ProgramInfo programInfo; + programInfo.kernelInfos = {new NEO::KernelInfo(), new NEO::KernelInfo(), new NEO::KernelInfo()}; + programInfo.kernelInfos[1]->workloadInfo.localMemoryStatelessWindowStartAddressOffset = 0U; + EXPECT_TRUE(NEO::requiresLocalMemoryWindowVA(programInfo)); +} \ No newline at end of file diff --git a/core/unit_tests/utilities/const_stringref_tests.cpp b/core/unit_tests/utilities/const_stringref_tests.cpp index a07e7ef722..a403bf8ac7 100644 --- a/core/unit_tests/utilities/const_stringref_tests.cpp +++ b/core/unit_tests/utilities/const_stringref_tests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 Intel Corporation + * Copyright (C) 2017-2020 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -73,3 +73,28 @@ TEST(ConstStringRef, WhenComparingAgainstContainersThenUsesLexicographicOrdering EXPECT_TRUE(strTex != constStrText); EXPECT_TRUE(constStrText != strTex); } + +TEST(ConstStringRef, WhenStrIsCalledThenEmitsProperString) { + static constexpr ConstStringRef constStrText("Text"); + std::string str = constStrText.str(); + EXPECT_EQ(4U, str.size()); + EXPECT_STREQ("Text", str.c_str()); +} + +TEST(ConstStringRef, WhenDefaultInitializedThenEmpty) { + ConstStringRef str; + EXPECT_TRUE(str.empty()); +} + +TEST(ConstStringRef, WhenCopyConstructedThenIdenticalAsOrigin) { + static constexpr ConstStringRef a("Text"); + static constexpr ConstStringRef b(a); + EXPECT_EQ(a, b); +} + +TEST(ConstStringRef, WhenCopyAsignedThenIdenticalAsOrigin) { + static constexpr ConstStringRef a("Text"); + ConstStringRef b("OtherText"); + b = a; + EXPECT_EQ(a, b); +} diff --git a/core/unit_tests/utilities/containers_tests.cpp b/core/unit_tests/utilities/containers_tests.cpp index 59001c20a7..3cba2481c7 100644 --- a/core/unit_tests/utilities/containers_tests.cpp +++ b/core/unit_tests/utilities/containers_tests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Intel Corporation + * Copyright (C) 2018-2020 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -1598,6 +1598,16 @@ TEST(ArrayRef, WrapContainers) { ASSERT_EQ(35, sum(ar3)); } +TEST(ArrayRef, GivenEmptyContainerThenArrayRefIsEmpty) { + StackVec stackVec; + ArrayRef arrayRef(stackVec); + EXPECT_TRUE(arrayRef.empty()); + + const StackVec &constStackVec = stackVec; + ArrayRef constArrayRef(constStackVec); + EXPECT_TRUE(constArrayRef.empty()); +} + TEST(ArrayRef, ImplicitCoversionToArrayrefOfConst) { int carray[] = {5, 6, 7, 8, 9}; ArrayRef arrayRef(carray); @@ -1698,3 +1708,25 @@ TEST(Range, GivenRangeThenValidStandardIteratorsAreAvailable) { EXPECT_EQ(&*vec.begin(), &*rangeFromVec.begin()); EXPECT_EQ(&*vec.rbegin(), &*rangeFromVec.rbegin()); } + +TEST(ArrayRef, WhenFromAnyIsCalledThenPointerIsReinterpretedAndSizeIsAdjusted) { + uint32_t x[2] = {}; + auto arrayRefU8 = ArrayRef::fromAny(x, 2); + EXPECT_EQ(8U, arrayRefU8.size()); + EXPECT_EQ(reinterpret_cast(x), arrayRefU8.begin()); +} + +TEST(ArrayRef, WhenToArrayRefIsCalledThenPointerIsReinterpretedAndSizeIsAdjusted) { + uint32_t x[2] = {}; + auto arrayRefU32 = ArrayRef::fromAny(x, 2); + auto arrayRefU8 = arrayRefU32.toArrayRef(); + EXPECT_EQ(8U, arrayRefU8.size()); + EXPECT_EQ(reinterpret_cast(x), arrayRefU8.begin()); +} + +TEST(ArrayRef, WhenClearedThenEmpty) { + uint32_t x[2] = {}; + auto arrayRefU32 = ArrayRef::fromAny(x, 2); + arrayRefU32.clear(); + EXPECT_TRUE(arrayRefU32.empty()); +} diff --git a/core/utilities/arrayref.h b/core/utilities/arrayref.h index 707ad6bf4e..df20db707c 100644 --- a/core/utilities/arrayref.h +++ b/core/utilities/arrayref.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Intel Corporation + * Copyright (C) 2018-2020 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -38,6 +38,11 @@ class ArrayRef { : begIt((ctr.size() > 0) ? &*ctr.begin() : nullptr), endIt((ctr.size() > 0) ? (&*(ctr.end() - 1) + 1) : nullptr) { } + template + ArrayRef(const SequentialContainerType &ctr) + : begIt((ctr.size() > 0) ? &*ctr.begin() : nullptr), endIt((ctr.size() > 0) ? (&*(ctr.end() - 1) + 1) : nullptr) { + } + template ArrayRef(DataType (&array)[Size]) : begIt(&array[0]), endIt(&array[Size]) { @@ -55,6 +60,10 @@ class ArrayRef { return *this; } + void clear() { + endIt = begIt; + } + size_t size() const { return endIt - begIt; } @@ -96,6 +105,18 @@ class ArrayRef { return ArrayRef(begIt, endIt); } + template + static ArrayRef fromAny(AnyT *any, size_t anyCount) { + static_assert((sizeof(AnyT) == sizeof(DataType)) || ((sizeof(AnyT) % sizeof(DataType)) == 0), "Unhandled type conversion"); + return ArrayRef(reinterpret_cast(any), (anyCount * sizeof(AnyT)) / sizeof(DataType)); + } + + template + ArrayRef toArrayRef() { + static_assert((sizeof(AnyT) == sizeof(DataType)) || ((sizeof(DataType) % sizeof(AnyT)) == 0), "Unhandled type conversion"); + return ArrayRef(reinterpret_cast::iterator>(begIt), (this->size() * sizeof(DataType)) / sizeof(AnyT)); + } + private: DataType *begIt = nullptr; DataType *endIt = nullptr; diff --git a/core/utilities/const_stringref.h b/core/utilities/const_stringref.h index 1880cd70d7..0c26b1c4e8 100644 --- a/core/utilities/const_stringref.h +++ b/core/utilities/const_stringref.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Intel Corporation + * Copyright (C) 2019-2020 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -22,6 +22,18 @@ constexpr size_t constLength(const char *string) { class ConstStringRef { public: + constexpr ConstStringRef() { + } + + constexpr ConstStringRef(const ConstStringRef &rhs) : ptr(rhs.ptr), len(rhs.len) { + } + + ConstStringRef &operator=(const ConstStringRef &rhs) { + this->ptr = rhs.ptr; + this->len = rhs.len; + return *this; + } + template constexpr ConstStringRef(const char (&array)[Length]) noexcept : ptr(array), len(((Length > 0) && (array[Length - 1] == '\0')) ? (Length - 1) : Length) { @@ -43,6 +55,10 @@ class ConstStringRef { return ptr; } + std::string str() const { + return std::string(ptr, len); + } + constexpr size_t size() const noexcept { return len; } @@ -64,8 +80,8 @@ class ConstStringRef { } protected: - const char *const ptr; - const size_t len; + const char *ptr = nullptr; + size_t len = 0U; }; constexpr bool equals(const ConstStringRef &lhs, const ConstStringRef &rhs) { diff --git a/offline_compiler/CMakeLists.txt b/offline_compiler/CMakeLists.txt index d157b0ac30..772d0a452e 100644 --- a/offline_compiler/CMakeLists.txt +++ b/offline_compiler/CMakeLists.txt @@ -7,6 +7,12 @@ project(ocloc) set(CLOC_SRCS_LIB + ${NEO_SOURCE_DIR}/core/device_binary_format/elf/elf.h + ${NEO_SOURCE_DIR}/core/device_binary_format/elf/elf_decoder.h + ${NEO_SOURCE_DIR}/core/device_binary_format/elf/elf_decoder.cpp + ${NEO_SOURCE_DIR}/core/device_binary_format/elf/elf_encoder.h + ${NEO_SOURCE_DIR}/core/device_binary_format/elf/elf_encoder.cpp + ${NEO_SOURCE_DIR}/core/device_binary_format/elf/ocl_elf.h ${NEO_SOURCE_DIR}/core/helpers/abort.cpp ${NEO_SOURCE_DIR}/core/helpers/debug_helpers.cpp ${NEO_SOURCE_DIR}/core/helpers/file_io.cpp @@ -126,8 +132,6 @@ if(UNIX) target_link_libraries(ocloc dl pthread) endif() -target_link_libraries(ocloc elflib) - set_target_properties(ocloc PROPERTIES FOLDER "offline_compiler") add_custom_target(copy_compiler_files DEPENDS ${NEO__IGC_TARGETS}) diff --git a/offline_compiler/decoder/binary_decoder.cpp b/offline_compiler/decoder/binary_decoder.cpp index 754d539d88..cf815e0909 100644 --- a/offline_compiler/decoder/binary_decoder.cpp +++ b/offline_compiler/decoder/binary_decoder.cpp @@ -7,7 +7,8 @@ #include "binary_decoder.h" -#include "core/elf/reader.h" +#include "core/device_binary_format/elf/elf_decoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" #include "core/helpers/file_io.h" #include "core/helpers/ptr_math.h" #include "offline_compiler/offline_compiler.h" @@ -31,9 +32,9 @@ void BinaryDecoder::setMessagePrinter(const MessagePrinter &messagePrinter) { } template -T readUnaligned(void *ptr) { +T readUnaligned(const void *ptr) { T retVal = 0; - uint8_t *tmp1 = reinterpret_cast(ptr); + const uint8_t *tmp1 = reinterpret_cast(ptr); uint8_t *tmp2 = reinterpret_cast(&retVal); for (uint8_t i = 0; i < sizeof(T); ++i) { *(tmp2++) = *(tmp1++); @@ -52,7 +53,7 @@ int BinaryDecoder::decode() { return processBinary(devBinPtr, ptmFile); } -void BinaryDecoder::dumpField(void *&binaryPtr, const PTField &field, std::ostream &ptmFile) { +void BinaryDecoder::dumpField(const void *&binaryPtr, const PTField &field, std::ostream &ptmFile) { ptmFile << '\t' << static_cast(field.size) << ' '; switch (field.size) { case 1: { @@ -82,29 +83,33 @@ void BinaryDecoder::dumpField(void *&binaryPtr, const PTField &field, std::ostre binaryPtr = ptrOffset(binaryPtr, field.size); } -void *BinaryDecoder::getDevBinary() { +const void *BinaryDecoder::getDevBinary() { binary = readBinaryFile(binaryFile); - char *data = nullptr; - CLElfLib::CElfReader elfReader(binary); - for (const auto §ionHeader : elfReader.getSectionHeaders()) { //Finding right section - switch (sectionHeader.Type) { - case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_LLVM_BINARY: { + const void *data = nullptr; + std::string decoderErrors; + std::string decoderWarnings; + auto input = ArrayRef(reinterpret_cast(binary.data()), binary.size()); + auto elf = NEO::Elf::decodeElf(input, decoderErrors, decoderWarnings); + for (const auto §ionHeader : elf.sectionHeaders) { //Finding right section + auto sectionData = ArrayRef(reinterpret_cast(sectionHeader.data.begin()), sectionHeader.data.size()); + switch (sectionHeader.header->type) { + case NEO::Elf::SHT_OPENCL_LLVM_BINARY: { std::ofstream ofs(pathToDump + "llvm.bin", std::ios::binary); - ofs.write(elfReader.getSectionData(sectionHeader.DataOffset), sectionHeader.DataSize); + ofs.write(sectionData.begin(), sectionData.size()); break; } - case CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV: { + case NEO::Elf::SHT_OPENCL_SPIRV: { std::ofstream ofs(pathToDump + "spirv.bin", std::ios::binary); - ofs.write(elfReader.getSectionData(sectionHeader.DataOffset), sectionHeader.DataSize); + ofs.write(sectionData.begin(), sectionData.size()); break; } - case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_OPTIONS: { + case NEO::Elf::SHT_OPENCL_OPTIONS: { std::ofstream ofs(pathToDump + "build.bin", std::ios::binary); - ofs.write(elfReader.getSectionData(sectionHeader.DataOffset), sectionHeader.DataSize); + ofs.write(sectionData.begin(), sectionData.size()); break; } - case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY: { - data = elfReader.getSectionData(sectionHeader.DataOffset); + case NEO::Elf::SHT_OPENCL_DEV_BINARY: { + data = sectionData.begin(); break; } default: @@ -323,7 +328,7 @@ Examples: NEO::getDevicesTypes().c_str()); } -int BinaryDecoder::processBinary(void *&ptr, std::ostream &ptmFile) { +int BinaryDecoder::processBinary(const void *&ptr, std::ostream &ptmFile) { ptmFile << "ProgramBinaryHeader:\n"; uint32_t numberOfKernels = 0, patchListSize = 0, device = 0; for (const auto &v : programHeader.fields) { @@ -351,7 +356,7 @@ int BinaryDecoder::processBinary(void *&ptr, std::ostream &ptmFile) { return 0; } -void BinaryDecoder::processKernel(void *&ptr, std::ostream &ptmFile) { +void BinaryDecoder::processKernel(const void *&ptr, std::ostream &ptmFile) { uint32_t KernelNameSize = 0, KernelPatchListSize = 0, KernelHeapSize = 0, KernelHeapUnpaddedSize = 0, GeneralStateHeapSize = 0, DynamicStateHeapSize = 0, SurfaceStateHeapSize = 0; ptmFile << "KernelBinaryHeader:\n"; @@ -419,7 +424,7 @@ void BinaryDecoder::processKernel(void *&ptr, std::ostream &ptmFile) { readPatchTokens(ptr, KernelPatchListSize, ptmFile); } -void BinaryDecoder::readPatchTokens(void *&patchListPtr, uint32_t patchListSize, std::ostream &ptmFile) { +void BinaryDecoder::readPatchTokens(const void *&patchListPtr, uint32_t patchListSize, std::ostream &ptmFile) { auto endPatchListPtr = ptrOffset(patchListPtr, patchListSize); while (patchListPtr != endPatchListPtr) { auto patchTokenPtr = patchListPtr; @@ -456,7 +461,7 @@ void BinaryDecoder::readPatchTokens(void *&patchListPtr, uint32_t patchListSize, if (patchListPtr > patchTokenPtr) { ptmFile << "\tHex"; - uint8_t *byte = reinterpret_cast(patchTokenPtr); + const uint8_t *byte = reinterpret_cast(patchTokenPtr); while (ptrDiff(patchListPtr, patchTokenPtr) != 0) { ptmFile << ' ' << std::hex << +*(byte++); patchTokenPtr = ptrOffset(patchTokenPtr, sizeof(uint8_t)); diff --git a/offline_compiler/decoder/binary_decoder.h b/offline_compiler/decoder/binary_decoder.h index cc1fd6ab2c..6866cb0085 100644 --- a/offline_compiler/decoder/binary_decoder.h +++ b/offline_compiler/decoder/binary_decoder.h @@ -6,10 +6,8 @@ */ #pragma once -#include "core/elf/types.h" - -#include "helper.h" -#include "iga_wrapper.h" +#include "offline_compiler/decoder/helper.h" +#include "offline_compiler/decoder/iga_wrapper.h" #include #include @@ -46,20 +44,20 @@ class BinaryDecoder { protected: bool ignoreIsaPadding = false; BinaryHeader programHeader, kernelHeader; - CLElfLib::ElfBinaryStorage binary; + std::vector binary; std::unique_ptr iga; PTMap patchTokens; std::string binaryFile, pathToPatch, pathToDump; MessagePrinter messagePrinter; - void dumpField(void *&binaryPtr, const PTField &field, std::ostream &ptmFile); + void dumpField(const void *&binaryPtr, const PTField &field, std::ostream &ptmFile); uint8_t getSize(const std::string &typeStr); - void *getDevBinary(); + const void *getDevBinary(); void parseTokens(); void printHelp(); - int processBinary(void *&ptr, std::ostream &ptmFile); - void processKernel(void *&ptr, std::ostream &ptmFile); - void readPatchTokens(void *&patchListPtr, uint32_t patchListSize, std::ostream &ptmFile); + int processBinary(const void *&ptr, std::ostream &ptmFile); + void processKernel(const void *&ptr, std::ostream &ptmFile); + void readPatchTokens(const void *&patchListPtr, uint32_t patchListSize, std::ostream &ptmFile); uint32_t readStructFields(const std::vector &patchList, const size_t &structPos, std::vector &fields); }; diff --git a/offline_compiler/decoder/binary_encoder.cpp b/offline_compiler/decoder/binary_encoder.cpp index 6369285cb6..fe0d5edeaf 100644 --- a/offline_compiler/decoder/binary_encoder.cpp +++ b/offline_compiler/decoder/binary_encoder.cpp @@ -7,7 +7,8 @@ #include "binary_encoder.h" -#include "core/elf/writer.h" +#include "core/device_binary_format/elf/elf_encoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" #include "core/helpers/aligned_memory.h" #include "core/helpers/file_io.h" #include "core/helpers/hash.h" @@ -74,17 +75,14 @@ bool BinaryEncoder::copyBinaryToBinary(const std::string &srcFileName, std::ostr } int BinaryEncoder::createElf() { - CLElfLib::CElfWriter elfWriter(CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_EXECUTABLE, CLElfLib::E_EH_MACHINE::EH_MACHINE_NONE, 0); + NEO::Elf::ElfEncoder ElfEncoder; + ElfEncoder.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; //Build Options if (fileExists(pathToDump + "build.bin")) { auto binary = readBinaryFile(pathToDump + "build.bin"); - std::string data(binary.begin(), binary.end()); - elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_OPTIONS, - CLElfLib::E_SH_FLAG::SH_FLAG_NONE, - "BuildOptions", - data, - static_cast(data.size()))); + ElfEncoder.appendSection(NEO::Elf::SHT_OPENCL_OPTIONS, "BuildOptions", + ArrayRef(reinterpret_cast(binary.data()), binary.size())); } else { messagePrinter.printf("Warning! Missing build section.\n"); } @@ -92,20 +90,13 @@ int BinaryEncoder::createElf() { //LLVM or SPIRV if (fileExists(pathToDump + "llvm.bin")) { auto binary = readBinaryFile(pathToDump + "llvm.bin"); - std::string data(binary.begin(), binary.end()); - elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_LLVM_BINARY, - CLElfLib::E_SH_FLAG::SH_FLAG_NONE, - "Intel(R) OpenCL LLVM Object", - data, - static_cast(data.size()))); + ElfEncoder.appendSection(NEO::Elf::SHT_OPENCL_LLVM_BINARY, "Intel(R) OpenCL LLVM Object", + ArrayRef(reinterpret_cast(binary.data()), binary.size())); } else if (fileExists(pathToDump + "spirv.bin")) { auto binary = readBinaryFile(pathToDump + "spirv.bin"); std::string data(binary.begin(), binary.end()); - elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV, - CLElfLib::E_SH_FLAG::SH_FLAG_NONE, - "SPIRV Object", - data, - static_cast(data.size()))); + ElfEncoder.appendSection(NEO::Elf::SHT_OPENCL_SPIRV, "SPIRV Object", + ArrayRef(reinterpret_cast(binary.data()), binary.size())); } else { messagePrinter.printf("Warning! Missing llvm/spirv section.\n"); } @@ -113,20 +104,15 @@ int BinaryEncoder::createElf() { //Device Binary if (fileExists(pathToDump + "device_binary.bin")) { auto binary = readBinaryFile(pathToDump + "device_binary.bin"); - std::string data(binary.begin(), binary.end()); - elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY, - CLElfLib::E_SH_FLAG::SH_FLAG_NONE, - "Intel(R) OpenCL Device Binary", - data, - static_cast(data.size()))); + ElfEncoder.appendSection(NEO::Elf::SHT_OPENCL_DEV_BINARY, "Intel(R) OpenCL Device Binary", + ArrayRef(reinterpret_cast(binary.data()), binary.size())); } else { messagePrinter.printf("Missing device_binary.bin\n"); return -1; } //Resolve Elf Binary - std::vector elfBinary; - elfWriter.resolveBinary(elfBinary); + auto elfBinary = ElfEncoder.encode(); std::ofstream elfFile(elfName, std::ios::binary); if (!elfFile.good()) { @@ -134,7 +120,7 @@ int BinaryEncoder::createElf() { return -1; } - elfFile.write(elfBinary.data(), elfBinary.size()); + elfFile.write(reinterpret_cast(elfBinary.data()), elfBinary.size()); return 0; } diff --git a/offline_compiler/offline_compiler.cpp b/offline_compiler/offline_compiler.cpp index 9c8f9fbe8f..e3706860ab 100644 --- a/offline_compiler/offline_compiler.cpp +++ b/offline_compiler/offline_compiler.cpp @@ -8,7 +8,9 @@ #include "offline_compiler.h" #include "core/debug_settings/debug_settings_manager.h" -#include "core/elf/writer.h" +#include "core/device_binary_format/device_binary_formats.h" +#include "core/device_binary_format/elf/elf_encoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" #include "core/helpers/debug_helpers.h" #include "core/helpers/file_io.h" #include "core/helpers/hw_info.h" @@ -726,31 +728,45 @@ void OfflineCompiler::storeBinary( } bool OfflineCompiler::generateElfBinary() { - bool retVal = true; - if (!genBinary || !genBinarySize) { - retVal = false; + return false; } - if (retVal) { - CLElfLib::CElfWriter elfWriter(CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_EXECUTABLE, CLElfLib::E_EH_MACHINE::EH_MACHINE_NONE, 0); + SingleDeviceBinary binary = {}; + binary.buildOptions = this->options; + binary.intermediateRepresentation = ArrayRef(reinterpret_cast(this->irBinary), this->irBinarySize); + binary.deviceBinary = ArrayRef(reinterpret_cast(this->genBinary), this->genBinarySize); + binary.debugData = ArrayRef(reinterpret_cast(this->debugDataBinary), this->debugDataBinarySize); + std::string packErrors; + std::string packWarnings; - elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_OPTIONS, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "BuildOptions", options, static_cast(strlen(options.c_str()) + 1u))); - std::string irBinaryTemp = irBinary ? std::string(irBinary, irBinarySize) : ""; - elfWriter.addSection(CLElfLib::SSectionNode(isSpirV ? CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV : CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_LLVM_BINARY, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "Intel(R) OpenCL LLVM Object", std::move(irBinaryTemp), static_cast(irBinarySize))); + using namespace NEO::Elf; + ElfEncoder ElfEncoder; + ElfEncoder.getElfFileHeader().type = ET_OPENCL_EXECUTABLE; + if (binary.buildOptions.empty() == false) { + ElfEncoder.appendSection(SHT_OPENCL_OPTIONS, SectionNamesOpenCl::buildOptions, + ArrayRef(reinterpret_cast(binary.buildOptions.data()), binary.buildOptions.size())); + } - // Add the device binary if it exists - if (genBinary) { - std::string genBinaryTemp = genBinary ? std::string(genBinary, genBinarySize) : ""; - elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "Intel(R) OpenCL Device Binary", std::move(genBinaryTemp), static_cast(genBinarySize))); + if (binary.intermediateRepresentation.empty() == false) { + if (isSpirV) { + ElfEncoder.appendSection(SHT_OPENCL_SPIRV, SectionNamesOpenCl::spirvObject, binary.intermediateRepresentation); + } else { + ElfEncoder.appendSection(SHT_OPENCL_LLVM_BINARY, SectionNamesOpenCl::llvmObject, binary.intermediateRepresentation); } - - elfBinarySize = elfWriter.getTotalBinarySize(); - elfBinary.resize(elfBinarySize); - elfWriter.resolveBinary(elfBinary); } - return retVal; + if (binary.debugData.empty() == false) { + ElfEncoder.appendSection(SHT_OPENCL_DEV_DEBUG, SectionNamesOpenCl::deviceDebug, binary.debugData); + } + + if (binary.deviceBinary.empty() == false) { + ElfEncoder.appendSection(SHT_OPENCL_DEV_BINARY, SectionNamesOpenCl::deviceBinary, binary.deviceBinary); + } + + this->elfBinary = ElfEncoder.encode(); + + return true; } void OfflineCompiler::writeOutAllFiles() { @@ -821,7 +837,7 @@ void OfflineCompiler::writeOutAllFiles() { writeDataToFile( elfOutputFile.c_str(), elfBinary.data(), - elfBinarySize); + elfBinary.size()); } if (debugDataBinary) { diff --git a/offline_compiler/offline_compiler.h b/offline_compiler/offline_compiler.h index eb5396666e..f4f32055b2 100644 --- a/offline_compiler/offline_compiler.h +++ b/offline_compiler/offline_compiler.h @@ -6,8 +6,6 @@ */ #pragma once -#include "core/elf/writer.h" - #include "cif/common/cif_main.h" #include "ocl_igc_interface/fcl_ocl_device_ctx.h" #include "ocl_igc_interface/igc_ocl_device_ctx.h" @@ -98,8 +96,7 @@ class OfflineCompiler { bool outputNoSuffix = false; bool forceStatelessToStatefulOptimization = false; - CLElfLib::ElfBinaryStorage elfBinary; - size_t elfBinarySize = 0; + std::vector elfBinary; char *genBinary = nullptr; size_t genBinarySize = 0; char *irBinary = nullptr; diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 00571a26a5..3b22d9cce6 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -48,7 +48,6 @@ if(WIN32) endif() endif() -target_link_libraries(${NEO_STATIC_LIB_NAME} elflib) if(DEFINED AUB_STREAM_DIR) target_link_libraries(${NEO_STATIC_LIB_NAME} ${AUB_STREAM_PROJECT_NAME}) endif() diff --git a/runtime/dll/CMakeLists.txt b/runtime/dll/CMakeLists.txt index 8a4364991b..e733307fc8 100644 --- a/runtime/dll/CMakeLists.txt +++ b/runtime/dll/CMakeLists.txt @@ -30,7 +30,6 @@ set(RUNTIME_SRCS_DLL_BASE ${NEO_SOURCE_DIR}/runtime/api/api.cpp ${NEO_SOURCE_DIR}/runtime/compiler_interface/default_cache_config.cpp ${NEO_SOURCE_DIR}/runtime/helpers/built_ins_helper.cpp - ${NEO_SOURCE_DIR}/runtime/program/evaluate_unhandled_token.cpp ${GTPIN_INIT_FILE} ${HW_SRC_LINK} diff --git a/runtime/program/CMakeLists.txt b/runtime/program/CMakeLists.txt index ed0ec043dc..2d9235e30c 100644 --- a/runtime/program/CMakeLists.txt +++ b/runtime/program/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2018-2019 Intel Corporation +# Copyright (C) 2018-2020 Intel Corporation # # SPDX-License-Identifier: MIT # @@ -25,9 +25,8 @@ set(RUNTIME_SRCS_PROGRAM ${CMAKE_CURRENT_SOURCE_DIR}/patch_info.h ${CMAKE_CURRENT_SOURCE_DIR}/printf_handler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/printf_handler.h - ${CMAKE_CURRENT_SOURCE_DIR}/process_elf_binary.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/process_gen_binary.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/process_spir_binary.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/process_device_binary.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/process_intermediate_binary.cpp ${CMAKE_CURRENT_SOURCE_DIR}/program.cpp ${CMAKE_CURRENT_SOURCE_DIR}/program.h ) diff --git a/runtime/program/build.cpp b/runtime/program/build.cpp index e432c979f7..15040408b1 100644 --- a/runtime/program/build.cpp +++ b/runtime/program/build.cpp @@ -7,6 +7,7 @@ #include "core/compiler_interface/compiler_interface.h" #include "core/device/device.h" +#include "core/device_binary_format/device_binary_formats.h" #include "core/execution_environment/execution_environment.h" #include "core/utilities/time_measure_wrapper.h" #include "runtime/device/cl_device.h" @@ -125,8 +126,7 @@ cl_int Program::build( this->irBinarySize = compilerOuput.intermediateRepresentation.size; this->isSpirV = compilerOuput.intermediateCodeType == IGC::CodeType::spirV; } - this->genBinary = std::move(compilerOuput.deviceBinary.mem); - this->genBinarySize = compilerOuput.deviceBinary.size; + this->replaceDeviceBinary(std::move(compilerOuput.deviceBinary.mem), compilerOuput.deviceBinary.size); this->debugData = std::move(compilerOuput.debugData.mem); this->debugDataSize = compilerOuput.debugData.size; } diff --git a/runtime/program/compile.cpp b/runtime/program/compile.cpp index dc581bc544..297fa0926b 100644 --- a/runtime/program/compile.cpp +++ b/runtime/program/compile.cpp @@ -6,7 +6,10 @@ */ #include "core/compiler_interface/compiler_interface.h" -#include "core/elf/writer.h" +#include "core/device/device.h" +#include "core/device_binary_format/elf/elf.h" +#include "core/device_binary_format/elf/elf_encoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" #include "core/execution_environment/execution_environment.h" #include "runtime/device/cl_device.h" #include "runtime/helpers/validators.h" @@ -30,9 +33,6 @@ cl_int Program::compile( void(CL_CALLBACK *funcNotify)(cl_program program, void *userData), void *userData) { cl_int retVal = CL_SUCCESS; - cl_program program; - Program *pHeaderProgObj; - size_t compileDataSize; do { if (((deviceList == nullptr) && (numDevices != 0)) || @@ -89,43 +89,35 @@ cl_int Program::compile( } // create ELF writer to process all sources to be compiled - CLElfLib::CElfWriter elfWriter(CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_SOURCE, CLElfLib::E_EH_MACHINE::EH_MACHINE_NONE, 0); - - CLElfLib::SSectionNode sectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_SOURCE, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "CLMain", sourceCode, static_cast(sourceCode.size() + 1u)); - - // add main program's source - elfWriter.addSection(sectionNode); + NEO::Elf::ElfEncoder<> elfEncoder(true, true, 1U); + elfEncoder.getElfFileHeader().type = NEO::Elf::ET_OPENCL_SOURCE; + elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_SOURCE, "CLMain", sourceCode); for (cl_uint i = 0; i < numInputHeaders; i++) { - program = inputHeaders[i]; + auto program = inputHeaders[i]; if (program == nullptr) { retVal = CL_INVALID_PROGRAM; break; } - pHeaderProgObj = castToObject(program); + auto pHeaderProgObj = castToObject(program); if (pHeaderProgObj == nullptr) { retVal = CL_INVALID_PROGRAM; break; } - sectionNode.name = headerIncludeNames[i]; - sectionNode.type = CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_HEADER; - sectionNode.flag = CLElfLib::E_SH_FLAG::SH_FLAG_NONE; - // collect required data from the header - retVal = pHeaderProgObj->getSource(sectionNode.data); + + std::string includeHeaderSource; + retVal = pHeaderProgObj->getSource(includeHeaderSource); if (retVal != CL_SUCCESS) { break; } - sectionNode.dataSize = static_cast(sectionNode.data.size()); - elfWriter.addSection(sectionNode); + elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_HEADER, ConstStringRef(headerIncludeNames[i], strlen(headerIncludeNames[i])), includeHeaderSource); } if (retVal != CL_SUCCESS) { break; } - compileDataSize = elfWriter.getTotalBinarySize(); - CLElfLib::ElfBinaryStorage compileData(compileDataSize); - elfWriter.resolveBinary(compileData); + std::vector compileData = elfEncoder.encode(); CompilerInterface *pCompilerInterface = this->executionEnvironment.getCompilerInterface(); if (!pCompilerInterface) { @@ -148,7 +140,7 @@ cl_int Program::compile( } } - inputArgs.src = ArrayRef(compileData.data(), compileDataSize); + inputArgs.src = ArrayRef(reinterpret_cast(compileData.data()), compileData.size()); inputArgs.apiOptions = ArrayRef(options.c_str(), options.length()); inputArgs.internalOptions = ArrayRef(internalOptions.c_str(), internalOptions.length()); diff --git a/runtime/program/create.inl b/runtime/program/create.inl index 9017dee95d..127a30a074 100644 --- a/runtime/program/create.inl +++ b/runtime/program/create.inl @@ -144,11 +144,9 @@ T *Program::createFromGenBinary( if (CL_SUCCESS == retVal) { program = new T(executionEnvironment, context, isBuiltIn); program->numDevices = 1; - program->genBinary = makeCopy(binary, size); - program->genBinarySize = size; + program->replaceDeviceBinary(makeCopy(binary, size), size); program->isCreatedFromBinary = true; program->programBinaryType = CL_PROGRAM_BINARY_TYPE_EXECUTABLE; - program->isProgramBinaryResolved = true; program->buildStatus = CL_BUILD_SUCCESS; program->createdFrom = CreatedFrom::BINARY; } diff --git a/runtime/program/evaluate_unhandled_token.cpp b/runtime/program/evaluate_unhandled_token.cpp deleted file mode 100644 index 5f671981a7..0000000000 --- a/runtime/program/evaluate_unhandled_token.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2017-2019 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#include "runtime/program/program.h" - -namespace NEO { - -bool Program::isSafeToSkipUnhandledToken(unsigned int token) const { - return false; -} - -} // namespace NEO diff --git a/runtime/program/get_info.cpp b/runtime/program/get_info.cpp index 7888544ee7..83154b13b9 100644 --- a/runtime/program/get_info.cpp +++ b/runtime/program/get_info.cpp @@ -36,10 +36,10 @@ cl_int Program::getInfo(cl_program_info paramName, size_t paramValueSize, break; case CL_PROGRAM_BINARIES: - resolveProgramBinary(); - pSrc = elfBinary.data(); + packDeviceBinary(); + pSrc = packedDeviceBinary.get(); retSize = sizeof(void **); - srcSize = elfBinarySize; + srcSize = packedDeviceBinarySize; if (paramValue != nullptr) { if (paramValueSize < retSize) { retVal = CL_INVALID_VALUE; @@ -51,8 +51,8 @@ cl_int Program::getInfo(cl_program_info paramName, size_t paramValueSize, break; case CL_PROGRAM_BINARY_SIZES: - resolveProgramBinary(); - pSrc = &elfBinarySize; + packDeviceBinary(); + pSrc = &packedDeviceBinarySize; retSize = srcSize = sizeof(size_t *); break; @@ -116,13 +116,11 @@ cl_int Program::getInfo(cl_program_info paramName, size_t paramValueSize, break; case CL_PROGRAM_DEBUG_INFO_SIZES_INTEL: - resolveProgramBinary(); retSize = srcSize = sizeof(debugDataSize); pSrc = &debugDataSize; break; case CL_PROGRAM_DEBUG_INFO_INTEL: - resolveProgramBinary(); pSrc = debugData.get(); retSize = numDevices * sizeof(void **); srcSize = debugDataSize; diff --git a/runtime/program/kernel_info.cpp b/runtime/program/kernel_info.cpp index ac6abbd3fc..ecb45236c3 100644 --- a/runtime/program/kernel_info.cpp +++ b/runtime/program/kernel_info.cpp @@ -425,6 +425,37 @@ bool KernelInfo::createKernelAllocation(uint32_t rootDeviceIndex, MemoryManager return memoryManager->copyMemoryToAllocation(kernelAllocation, heapInfo.pKernelHeap, kernelIsaSize); } +void KernelInfo::apply(const DeviceInfoKernelPayloadConstants &constants) { + if (nullptr == this->crossThreadData) { + return; + } + + uint32_t privateMemoryStatelessSizeOffset = this->workloadInfo.privateMemoryStatelessSizeOffset; + uint32_t localMemoryStatelessWindowSizeOffset = this->workloadInfo.localMemoryStatelessWindowSizeOffset; + uint32_t localMemoryStatelessWindowStartAddressOffset = this->workloadInfo.localMemoryStatelessWindowStartAddressOffset; + + if (localMemoryStatelessWindowStartAddressOffset != WorkloadInfo::undefinedOffset) { + *(uintptr_t *)&(this->crossThreadData[localMemoryStatelessWindowStartAddressOffset]) = reinterpret_cast(constants.slmWindow); + } + + if (localMemoryStatelessWindowSizeOffset != WorkloadInfo::undefinedOffset) { + *(uint32_t *)&(this->crossThreadData[localMemoryStatelessWindowSizeOffset]) = constants.slmWindowSize; + } + + uint32_t privateMemorySize = 0U; + if (this->patchInfo.pAllocateStatelessPrivateSurface) { + privateMemorySize = this->patchInfo.pAllocateStatelessPrivateSurface->PerThreadPrivateMemorySize * constants.computeUnitsUsedForScratch * this->getMaxSimdSize(); + } + + if (privateMemoryStatelessSizeOffset != WorkloadInfo::undefinedOffset) { + *(uint32_t *)&(this->crossThreadData[privateMemoryStatelessSizeOffset]) = privateMemorySize; + } + + if (this->workloadInfo.maxWorkGroupSizeOffset != WorkloadInfo::undefinedOffset) { + *(uint32_t *)&(this->crossThreadData[this->workloadInfo.maxWorkGroupSizeOffset]) = constants.maxWorkGroupSize; + } +} + std::string concatenateKernelNames(ArrayRef kernelInfos) { std::string semiColonDelimitedKernelNameStr; diff --git a/runtime/program/kernel_info.h b/runtime/program/kernel_info.h index 6af94899bf..1bd6b7346f 100644 --- a/runtime/program/kernel_info.h +++ b/runtime/program/kernel_info.h @@ -188,6 +188,7 @@ struct KernelInfo { } bool createKernelAllocation(uint32_t rootDeviceIndex, MemoryManager *memoryManager); + void apply(const DeviceInfoKernelPayloadConstants &constants); std::string name; std::string attributes; diff --git a/runtime/program/kernel_info_from_patchtokens.cpp b/runtime/program/kernel_info_from_patchtokens.cpp index a14703e7e6..f7bda96f3f 100644 --- a/runtime/program/kernel_info_from_patchtokens.cpp +++ b/runtime/program/kernel_info_from_patchtokens.cpp @@ -141,8 +141,7 @@ void populateKernelInfoArg(KernelInfo &dstKernelInfo, KernelArgInfo &dstKernelIn dstKernelInfoArg.offsetObjectId = getOffset(src.objectId); } -void populateKernelInfo(KernelInfo &dst, const PatchTokenBinary::KernelFromPatchtokens &src, uint32_t gpuPointerSizeInBytes, - const DeviceInfoKernelPayloadConstants &constants) { +void populateKernelInfo(KernelInfo &dst, const PatchTokenBinary::KernelFromPatchtokens &src, uint32_t gpuPointerSizeInBytes) { UNRECOVERABLE_IF(nullptr == src.header); dst.heapInfo.pKernelHeader = src.header; dst.name = std::string(src.name.begin(), src.name.end()).c_str(); @@ -220,31 +219,6 @@ void populateKernelInfo(KernelInfo &dst, const PatchTokenBinary::KernelFromPatch uint32_t crossThreadDataSize = dst.patchInfo.dataParameterStream->DataParameterStreamSize; dst.crossThreadData = new char[crossThreadDataSize]; memset(dst.crossThreadData, 0x00, crossThreadDataSize); - - uint32_t privateMemoryStatelessSizeOffset = dst.workloadInfo.privateMemoryStatelessSizeOffset; - uint32_t localMemoryStatelessWindowSizeOffset = dst.workloadInfo.localMemoryStatelessWindowSizeOffset; - uint32_t localMemoryStatelessWindowStartAddressOffset = dst.workloadInfo.localMemoryStatelessWindowStartAddressOffset; - - if (localMemoryStatelessWindowStartAddressOffset != WorkloadInfo::undefinedOffset) { - *(uintptr_t *)&(dst.crossThreadData[localMemoryStatelessWindowStartAddressOffset]) = reinterpret_cast(constants.slmWindow); - } - - if (localMemoryStatelessWindowSizeOffset != WorkloadInfo::undefinedOffset) { - *(uint32_t *)&(dst.crossThreadData[localMemoryStatelessWindowSizeOffset]) = constants.slmWindowSize; - } - - uint32_t privateMemorySize = 0U; - if (dst.patchInfo.pAllocateStatelessPrivateSurface) { - privateMemorySize = dst.patchInfo.pAllocateStatelessPrivateSurface->PerThreadPrivateMemorySize * constants.computeUnitsUsedForScratch * dst.getMaxSimdSize(); - } - - if (privateMemoryStatelessSizeOffset != WorkloadInfo::undefinedOffset) { - *(uint32_t *)&(dst.crossThreadData[privateMemoryStatelessSizeOffset]) = privateMemorySize; - } - - if (dst.workloadInfo.maxWorkGroupSizeOffset != WorkloadInfo::undefinedOffset) { - *(uint32_t *)&(dst.crossThreadData[dst.workloadInfo.maxWorkGroupSizeOffset]) = constants.maxWorkGroupSize; - } } } diff --git a/runtime/program/kernel_info_from_patchtokens.h b/runtime/program/kernel_info_from_patchtokens.h index c4a2f3e76c..c4da0c2a01 100644 --- a/runtime/program/kernel_info_from_patchtokens.h +++ b/runtime/program/kernel_info_from_patchtokens.h @@ -11,14 +11,12 @@ namespace NEO { -struct DeviceInfoKernelPayloadConstants; struct KernelInfo; namespace PatchTokenBinary { struct KernelFromPatchtokens; } -void populateKernelInfo(KernelInfo &dst, const PatchTokenBinary::KernelFromPatchtokens &src, uint32_t gpuPointerSizeInBytes, - const DeviceInfoKernelPayloadConstants &constant); +void populateKernelInfo(KernelInfo &dst, const PatchTokenBinary::KernelFromPatchtokens &src, uint32_t gpuPointerSizeInBytes); } // namespace NEO diff --git a/runtime/program/link.cpp b/runtime/program/link.cpp index 770eec105a..f0f28c9a60 100644 --- a/runtime/program/link.cpp +++ b/runtime/program/link.cpp @@ -6,7 +6,9 @@ */ #include "core/compiler_interface/compiler_interface.h" -#include "core/elf/writer.h" +#include "core/device_binary_format/elf/elf.h" +#include "core/device_binary_format/elf/elf_encoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" #include "core/execution_environment/execution_environment.h" #include "core/utilities/stackvec.h" #include "runtime/device/cl_device.h" @@ -30,9 +32,6 @@ cl_int Program::link( void(CL_CALLBACK *funcNotify)(cl_program program, void *userData), void *userData) { cl_int retVal = CL_SUCCESS; - cl_program program; - Program *pInputProgObj; - size_t dataSize; bool isCreateLibrary; do { @@ -73,16 +72,17 @@ cl_int Program::link( buildStatus = CL_BUILD_IN_PROGRESS; - CLElfLib::CElfWriter elfWriter(CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_OBJECTS, CLElfLib::E_EH_MACHINE::EH_MACHINE_NONE, 0); + NEO::Elf::ElfEncoder<> elfEncoder(true, false, 1U); + elfEncoder.getElfFileHeader().type = NEO::Elf::ET_OPENCL_OBJECTS; StackVec inputProgramsInternal; for (cl_uint i = 0; i < numInputPrograms; i++) { - program = inputPrograms[i]; + auto program = inputPrograms[i]; if (program == nullptr) { retVal = CL_INVALID_PROGRAM; break; } - pInputProgObj = castToObject(program); + auto pInputProgObj = castToObject(program); if (pInputProgObj == nullptr) { retVal = CL_INVALID_PROGRAM; break; @@ -93,16 +93,15 @@ cl_int Program::link( break; } - elfWriter.addSection(CLElfLib::SSectionNode(pInputProgObj->getIsSpirV() ? CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV : CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_LLVM_BINARY, - CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "", std::string(pInputProgObj->irBinary.get(), pInputProgObj->irBinarySize), static_cast(pInputProgObj->irBinarySize))); + auto sectionType = pInputProgObj->getIsSpirV() ? NEO::Elf::SHT_OPENCL_SPIRV : NEO::Elf::SHT_OPENCL_LLVM_BINARY; + ConstStringRef sectionName = pInputProgObj->getIsSpirV() ? NEO::Elf::SectionNamesOpenCl::spirvObject : NEO::Elf::SectionNamesOpenCl::llvmObject; + elfEncoder.appendSection(sectionType, sectionName, ArrayRef(reinterpret_cast(pInputProgObj->irBinary.get()), pInputProgObj->irBinarySize)); } if (retVal != CL_SUCCESS) { break; } - dataSize = elfWriter.getTotalBinarySize(); - CLElfLib::ElfBinaryStorage data(dataSize); - elfWriter.resolveBinary(data); + auto clLinkInput = elfEncoder.encode(); CompilerInterface *pCompilerInterface = this->executionEnvironment.getCompilerInterface(); if (!pCompilerInterface) { @@ -112,7 +111,7 @@ cl_int Program::link( TranslationInput inputArgs = {IGC::CodeType::elf, IGC::CodeType::undefined}; - inputArgs.src = ArrayRef(data.data(), dataSize); + inputArgs.src = ArrayRef(reinterpret_cast(clLinkInput.data()), clLinkInput.size()); inputArgs.apiOptions = ArrayRef(options.c_str(), options.length()); inputArgs.internalOptions = ArrayRef(internalOptions.c_str(), internalOptions.length()); @@ -127,8 +126,7 @@ cl_int Program::link( break; } - this->genBinary = std::move(compilerOuput.deviceBinary.mem); - this->genBinarySize = compilerOuput.deviceBinary.size; + this->replaceDeviceBinary(std::move(compilerOuput.deviceBinary.mem), compilerOuput.deviceBinary.size); this->debugData = std::move(compilerOuput.debugData.mem); this->debugDataSize = compilerOuput.debugData.size; diff --git a/runtime/program/process_gen_binary.cpp b/runtime/program/process_device_binary.cpp similarity index 80% rename from runtime/program/process_gen_binary.cpp rename to runtime/program/process_device_binary.cpp index 28b817430a..6bf32e7111 100644 --- a/runtime/program/process_gen_binary.cpp +++ b/runtime/program/process_device_binary.cpp @@ -5,27 +5,21 @@ * */ -#include "core/device_binary_format/patchtokens_decoder.h" -#include "core/device_binary_format/patchtokens_dumper.h" -#include "core/device_binary_format/patchtokens_validator.inl" +#include "core/device_binary_format/device_binary_formats.h" #include "core/helpers/aligned_memory.h" #include "core/helpers/debug_helpers.h" #include "core/helpers/ptr_math.h" #include "core/helpers/string.h" #include "core/memory_manager/unified_memory_manager.h" #include "core/program/program_info.h" -#include "core/program/program_info_from_patchtokens.h" #include "core/program/program_initialization.h" #include "runtime/context/context.h" #include "runtime/device/cl_device.h" #include "runtime/gtpin/gtpin_notify.h" #include "runtime/memory_manager/memory_manager.h" #include "runtime/program/kernel_info.h" -#include "runtime/program/kernel_info_from_patchtokens.h" #include "runtime/program/program.h" -#include "patch_list.h" -#include "patch_shared.h" #include "program_debug_data.h" #include @@ -56,26 +50,6 @@ const KernelInfo *Program::getKernelInfo(size_t ordinal) const { return kernelInfoArray[ordinal]; } -cl_int Program::isHandled(const PatchTokenBinary::ProgramFromPatchtokens &decodedProgram) const { - std::string validatorErrMessage; - std::string validatorWarnings; - auto availableSlm = this->pDevice ? static_cast(this->pDevice->getDeviceInfo().localMemSize) : 0U; - auto validatorErr = PatchTokenBinary::validate(decodedProgram, availableSlm, *this, validatorErrMessage, validatorWarnings); - if (validatorWarnings.empty() == false) { - printDebugString(DebugManager.flags.PrintDebugMessages.get(), stderr, "%s\n", validatorWarnings.c_str()); - } - if (validatorErr != PatchTokenBinary::ValidatorError::Success) { - printDebugString(DebugManager.flags.PrintDebugMessages.get(), stderr, "%s\n", validatorErrMessage.c_str()); - switch (validatorErr) { - default: - return CL_INVALID_BINARY; - case PatchTokenBinary::ValidatorError::NotEnoughSlm: - return CL_OUT_OF_RESOURCES; - } - } - return CL_SUCCESS; -} - cl_int Program::linkBinary() { if (linkerInput == nullptr) { return CL_SUCCESS; @@ -146,6 +120,10 @@ cl_int Program::linkBinary() { } cl_int Program::processGenBinary() { + if (nullptr == this->unpackedDeviceBinary) { + return CL_INVALID_BINARY; + } + cleanCurrentKernelInfo(); if (this->constantSurface || this->globalSurface) { pDevice->getMemoryManager()->freeGraphicsMemory(this->constantSurface); @@ -154,41 +132,45 @@ cl_int Program::processGenBinary() { this->globalSurface = nullptr; } - auto blob = ArrayRef(reinterpret_cast(genBinary.get()), genBinarySize); ProgramInfo programInfo; - auto ret = this->processPatchTokensBinary(blob, programInfo); - if (CL_SUCCESS != ret) { - return ret; + auto blob = ArrayRef(reinterpret_cast(this->unpackedDeviceBinary.get()), this->unpackedDeviceBinarySize); + SingleDeviceBinary binary = {}; + binary.deviceBinary = blob; + std::string decodeErrors; + std::string decodeWarnings; + + DecodeError decodeError; + DeviceBinaryFormat singleDeviceBinaryFormat; + std::tie(decodeError, singleDeviceBinaryFormat) = NEO::decodeSingleDeviceBinary(programInfo, binary, decodeErrors, decodeWarnings); + if (decodeWarnings.empty() == false) { + printDebugString(DebugManager.flags.PrintDebugMessages.get(), stderr, "%s\n", decodeWarnings.c_str()); + } + + if (DecodeError::Success != decodeError) { + printDebugString(DebugManager.flags.PrintDebugMessages.get(), stderr, "%s\n", decodeErrors.c_str()); + return CL_INVALID_BINARY; } return this->processProgramInfo(programInfo); } -cl_int Program::processPatchTokensBinary(ArrayRef src, ProgramInfo &dst) { - NEO::PatchTokenBinary::ProgramFromPatchtokens decodedProgram = {}; - NEO::PatchTokenBinary::decodeProgramFromPatchtokensBlob(src, decodedProgram); - DBG_LOG(LogPatchTokens, NEO::PatchTokenBinary::asString(decodedProgram).c_str()); - cl_int retVal = this->isHandled(decodedProgram); - if (CL_SUCCESS != retVal) { - return retVal; - } - +cl_int Program::processProgramInfo(ProgramInfo &src) { + size_t slmNeeded = getMaxInlineSlmNeeded(src); + size_t slmAvailable = 0U; NEO::DeviceInfoKernelPayloadConstants deviceInfoConstants; if (this->pDevice) { + slmAvailable = static_cast(this->pDevice->getDeviceInfo().localMemSize); deviceInfoConstants.maxWorkGroupSize = (uint32_t)this->pDevice->getDeviceInfo().maxWorkGroupSize; deviceInfoConstants.computeUnitsUsedForScratch = this->pDevice->getDeviceInfo().computeUnitsUsedForScratch; deviceInfoConstants.slmWindowSize = (uint32_t)this->pDevice->getDeviceInfo().localMemSize; - if (requiresLocalMemoryWindowVA(decodedProgram)) { + if (requiresLocalMemoryWindowVA(src)) { deviceInfoConstants.slmWindow = this->executionEnvironment.memoryManager->getReservedMemory(MemoryConstants::slmWindowSize, MemoryConstants::slmWindowAlignment); } } + if (slmNeeded > slmAvailable) { + return CL_OUT_OF_RESOURCES; + } - NEO::populateProgramInfo(dst, decodedProgram, deviceInfoConstants); - - return CL_SUCCESS; -} - -cl_int Program::processProgramInfo(ProgramInfo &src) { this->linkerInput = std::move(src.linkerInput); this->kernelInfoArray = std::move(src.kernelInfos); auto svmAllocsManager = context ? context->getSVMAllocsManager() : nullptr; @@ -221,23 +203,13 @@ cl_int Program::processProgramInfo(ProgramInfo &src) { if (kernelInfo->requiresSubgroupIndependentForwardProgress()) { subgroupKernelInfoArray.push_back(kernelInfo); } + + kernelInfo->apply(deviceInfoConstants); } return linkBinary(); } -bool Program::validateGenBinaryDevice(GFXCORE_FAMILY device) const { - bool isValid = familyEnabled[device]; - - return isValid; -} - -bool Program::validateGenBinaryHeader(const iOpenCL::SProgramBinaryHeader *pGenBinaryHeader) const { - return pGenBinaryHeader->Magic == MAGIC_CL && - pGenBinaryHeader->Version == CURRENT_ICBE_VERSION && - validateGenBinaryDevice(static_cast(pGenBinaryHeader->Device)); -} - void Program::processDebugData() { if (debugData != nullptr) { SProgramDebugDataHeaderIGC *programDebugHeader = reinterpret_cast(debugData.get()); diff --git a/runtime/program/process_elf_binary.cpp b/runtime/program/process_elf_binary.cpp deleted file mode 100644 index 6d33f94d9e..0000000000 --- a/runtime/program/process_elf_binary.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2017-2020 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#include "common/compiler_support.h" -#include "core/device_binary_format/patchtokens_decoder.h" -#include "core/elf/reader.h" -#include "core/elf/writer.h" -#include "core/helpers/string.h" - -#include "program.h" - -namespace NEO { - -cl_int Program::processElfBinary( - const void *pBinary, - size_t binarySize, - uint32_t &binaryVersion) { - const CLElfLib::SElf64Header *pElfHeader = nullptr; - - binaryVersion = iOpenCL::CURRENT_ICBE_VERSION; - - elfBinarySize = binarySize; - elfBinary = CLElfLib::ElfBinaryStorage(reinterpret_cast(pBinary), reinterpret_cast(reinterpret_cast(pBinary) + binarySize)); - - try { - CLElfLib::CElfReader elfReader(elfBinary); - - pElfHeader = elfReader.getElfHeader(); - - switch (pElfHeader->Type) { - case CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_EXECUTABLE: - programBinaryType = CL_PROGRAM_BINARY_TYPE_EXECUTABLE; - break; - - case CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_LIBRARY: - programBinaryType = CL_PROGRAM_BINARY_TYPE_LIBRARY; - break; - - case CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_OBJECTS: - programBinaryType = CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT; - break; - - default: - return CL_INVALID_BINARY; - } - // section 0 is always null - for (size_t i = 1u; i < elfReader.getSectionHeaders().size(); ++i) { - const auto §ionHeader = elfReader.getSectionHeaders()[i]; - switch (sectionHeader.Type) { - case CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV: - this->isSpirV = true; - CPP_ATTRIBUTE_FALLTHROUGH; - case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_LLVM_BINARY: - if (sectionHeader.DataSize > 0) { - this->irBinary = makeCopy(elfReader.getSectionData(sectionHeader.DataOffset), static_cast(sectionHeader.DataSize)); - this->irBinarySize = static_cast(sectionHeader.DataSize); - } - break; - - case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY: - if (sectionHeader.DataSize > 0 && validateGenBinaryHeader(reinterpret_cast(elfReader.getSectionData(sectionHeader.DataOffset)))) { - this->genBinary = makeCopy(elfReader.getSectionData(sectionHeader.DataOffset), static_cast(sectionHeader.DataSize)); - this->genBinarySize = static_cast(sectionHeader.DataSize); - isCreatedFromBinary = true; - } else { - binaryVersion = reinterpret_cast(elfReader.getSectionData(sectionHeader.DataOffset))->Version; - return CL_INVALID_BINARY; - } - break; - - case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_OPTIONS: - if (sectionHeader.DataSize > 0) { - options = std::string(elfReader.getSectionData(sectionHeader.DataOffset), static_cast(sectionHeader.DataSize)); - } - break; - - case CLElfLib::E_SH_TYPE::SH_TYPE_STR_TBL: - // We can skip the string table - break; - - default: - return CL_INVALID_BINARY; - } - } - - isProgramBinaryResolved = true; - - // Create an empty build log since program is effectively built - updateBuildLog(pDevice, "", 1); - } catch (const CLElfLib::ElfException &) { - return CL_INVALID_BINARY; - } - - return CL_SUCCESS; -} - -cl_int Program::resolveProgramBinary() { - CLElfLib::E_EH_TYPE headerType; - - if (isProgramBinaryResolved == false) { - elfBinary.clear(); - elfBinarySize = 0; - - switch (programBinaryType) { - case CL_PROGRAM_BINARY_TYPE_EXECUTABLE: - headerType = CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_EXECUTABLE; - - if (!genBinary || !genBinarySize) { - return CL_INVALID_BINARY; - } - break; - - case CL_PROGRAM_BINARY_TYPE_LIBRARY: - headerType = CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_LIBRARY; - - if (!irBinary || !irBinarySize) { - return CL_INVALID_BINARY; - } - break; - - case CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT: - headerType = CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_OBJECTS; - - if (!irBinary || !irBinarySize) { - return CL_INVALID_BINARY; - } - break; - - default: - return CL_INVALID_BINARY; - } - - CLElfLib::CElfWriter elfWriter(headerType, CLElfLib::E_EH_MACHINE::EH_MACHINE_NONE, 0); - - elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_OPTIONS, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "BuildOptions", options, static_cast(strlen(options.c_str()) + 1u))); - std::string irBinaryTemp = irBinary ? std::string(irBinary.get(), irBinarySize) : ""; - // Add the LLVM component if available - elfWriter.addSection(CLElfLib::SSectionNode(getIsSpirV() ? CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV : CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_LLVM_BINARY, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, - headerType == CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_LIBRARY ? "Intel(R) OpenCL LLVM Archive" : "Intel(R) OpenCL LLVM Object", std::move(irBinaryTemp), static_cast(irBinarySize))); - // Add the device binary if it exists - if (genBinary) { - std::string genBinaryTemp = genBinary ? std::string(genBinary.get(), genBinarySize) : ""; - elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "Intel(R) OpenCL Device Binary", std::move(genBinaryTemp), static_cast(genBinarySize))); - } - - // Add the device debug data if it exists - if (debugData != nullptr) { - std::string debugDataTemp = debugData ? std::string(debugData.get(), debugDataSize) : ""; - elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_DEBUG, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "Intel(R) OpenCL Device Debug", std::move(debugDataTemp), static_cast(debugDataSize))); - } - - elfBinarySize = elfWriter.getTotalBinarySize(); - elfBinary = CLElfLib::ElfBinaryStorage(elfBinarySize); - elfWriter.resolveBinary(elfBinary); - isProgramBinaryResolved = true; - } else { - return CL_OUT_OF_HOST_MEMORY; - } - return CL_SUCCESS; -} -} // namespace NEO diff --git a/runtime/program/process_intermediate_binary.cpp b/runtime/program/process_intermediate_binary.cpp new file mode 100644 index 0000000000..46acc68eb1 --- /dev/null +++ b/runtime/program/process_intermediate_binary.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2017-2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "program.h" + +namespace NEO { +cl_int Program::processSpirBinary( + const void *pBinary, + size_t binarySize, + bool isSpirV) { + programBinaryType = CL_PROGRAM_BINARY_TYPE_INTERMEDIATE; + + this->irBinary = makeCopy(pBinary, binarySize); + this->irBinarySize = binarySize; + + buildStatus = CL_BUILD_NONE; + this->isSpirV = isSpirV; + + return CL_SUCCESS; +} +} // namespace NEO diff --git a/runtime/program/process_spir_binary.cpp b/runtime/program/process_spir_binary.cpp deleted file mode 100644 index 0912c1cf7b..0000000000 --- a/runtime/program/process_spir_binary.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2017-2019 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#include "program.h" - -namespace NEO { - -bool Program::isValidSpirvBinary( - const void *pBinary, - size_t binarySize) { - - const uint32_t magicWord[2] = {0x03022307, 0x07230203}; - bool retVal = false; - - if (pBinary && (binarySize > sizeof(uint32_t))) { - if ((memcmp(pBinary, &magicWord[0], sizeof(uint32_t)) == 0) || - (memcmp(pBinary, &magicWord[1], sizeof(uint32_t)) == 0)) { - retVal = true; - } - } - return retVal; -} - -cl_int Program::processSpirBinary( - const void *pBinary, - size_t binarySize, - bool isSpirV) { - programBinaryType = CL_PROGRAM_BINARY_TYPE_INTERMEDIATE; - - this->irBinary = makeCopy(pBinary, binarySize); - this->irBinarySize = binarySize; - - buildStatus = CL_BUILD_NONE; - this->isSpirV = isSpirV; - - return CL_SUCCESS; -} -} // namespace NEO diff --git a/runtime/program/program.cpp b/runtime/program/program.cpp index 54d6a1d4cd..d864098e86 100644 --- a/runtime/program/program.cpp +++ b/runtime/program/program.cpp @@ -8,7 +8,10 @@ #include "program.h" #include "core/compiler_interface/compiler_interface.h" -#include "core/elf/writer.h" +#include "core/compiler_interface/intermediate_representations.h" +#include "core/device_binary_format/device_binary_formats.h" +#include "core/device_binary_format/elf/elf_encoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" #include "core/helpers/debug_helpers.h" #include "core/helpers/hw_helper.h" #include "core/helpers/string.h" @@ -43,22 +46,6 @@ Program::Program(ExecutionEnvironment &executionEnvironment, Context *context, b blockKernelManager = new BlockKernelManager(); pDevice = context ? context->getDevice(0) : nullptr; numDevices = 1; - elfBinarySize = 0; - genBinary = nullptr; - genBinarySize = 0; - irBinary = nullptr; - irBinarySize = 0; - debugData = nullptr; - debugDataSize = 0; - buildStatus = CL_BUILD_NONE; - programBinaryType = CL_PROGRAM_BINARY_TYPE_NONE; - isCreatedFromBinary = false; - isProgramBinaryResolved = false; - constantSurface = nullptr; - globalSurface = nullptr; - globalVarTotalSize = 0; - programOptionVersion = 12u; - allowNonUniform = false; char paramValue[32] = {}; bool force32BitAddressess = false; @@ -111,8 +98,6 @@ Program::Program(ExecutionEnvironment &executionEnvironment, Context *context, b } Program::~Program() { - elfBinarySize = 0; - cleanCurrentKernelInfo(); freeBlockResources(); @@ -146,28 +131,68 @@ cl_int Program::createProgramFromBinary( const void *pBinary, size_t binarySize) { - cl_int retVal = CL_INVALID_PROGRAM; - uint32_t binaryVersion = iOpenCL::CURRENT_ICBE_VERSION; + cl_int retVal = CL_INVALID_BINARY; - if (Program::isValidLlvmBinary(pBinary, binarySize)) { - retVal = processSpirBinary(pBinary, binarySize, false); - } else if (Program::isValidSpirvBinary(pBinary, binarySize)) { - retVal = processSpirBinary(pBinary, binarySize, true); - } else { - bool rebuildRequired = DebugManager.flags.RebuildPrecompiledKernels.get(); - retVal = processElfBinary(pBinary, binarySize, binaryVersion); - if (retVal == CL_SUCCESS) { - isCreatedFromBinary = true; - } else if (binaryVersion != iOpenCL::CURRENT_ICBE_VERSION) { - // Version of compiler used to create program binary is invalid, - // needs to recompile program binary from its IR (if available). - // if recompile fails propagate error retVal from previous function - rebuildRequired = true; + this->irBinary.reset(); + this->irBinarySize = 0U; + this->isSpirV = false; + this->unpackedDeviceBinary.reset(); + this->unpackedDeviceBinarySize = 0U; + this->packedDeviceBinary.reset(); + this->packedDeviceBinarySize = 0U; + + ArrayRef archive(reinterpret_cast(pBinary), binarySize); + bool isSpirV = NEO::isSpirVBitcode(archive); + + if (isSpirV || NEO::isLlvmBitcode(archive)) { + this->programBinaryType = CL_PROGRAM_BINARY_TYPE_INTERMEDIATE; + retVal = processSpirBinary(archive.begin(), archive.size(), isSpirV); + } else if (isAnyDeviceBinaryFormat(archive)) { + this->programBinaryType = CL_PROGRAM_BINARY_TYPE_EXECUTABLE; + this->isCreatedFromBinary = true; + + auto productAbbreviation = hardwarePrefix[pDevice->getHardwareInfo().platform.eProductFamily]; + + TargetDevice targetDevice = {}; + targetDevice.coreFamily = pDevice->getHardwareInfo().platform.eRenderCoreFamily; + targetDevice.stepping = pDevice->getHardwareInfo().platform.usRevId; + targetDevice.maxPointerSizeInBytes = sizeof(uintptr_t); + std::string decodeErrors; + std::string decodeWarnings; + auto singleDeviceBinary = unpackSingleDeviceBinary(archive, ConstStringRef(productAbbreviation, strlen(productAbbreviation)), targetDevice, + decodeErrors, decodeWarnings); + if (decodeWarnings.empty() == false) { + printDebugString(DebugManager.flags.PrintDebugMessages.get(), stderr, "%s\n", decodeWarnings.c_str()); } - if (rebuildRequired) { - if (rebuildProgramFromIr() == CL_SUCCESS) { - retVal = CL_SUCCESS; + if (singleDeviceBinary.intermediateRepresentation.empty() && singleDeviceBinary.deviceBinary.empty()) { + retVal = CL_INVALID_BINARY; + printDebugString(DebugManager.flags.PrintDebugMessages.get(), stderr, "%s\n", decodeErrors.c_str()); + } else { + retVal = CL_SUCCESS; + this->irBinary = makeCopy(reinterpret_cast(singleDeviceBinary.intermediateRepresentation.begin()), singleDeviceBinary.intermediateRepresentation.size()); + this->irBinarySize = singleDeviceBinary.intermediateRepresentation.size(); + this->isSpirV = NEO::isSpirVBitcode(ArrayRef(reinterpret_cast(this->irBinary.get()), this->irBinarySize)); + this->options = singleDeviceBinary.buildOptions.str(); + + if ((false == singleDeviceBinary.deviceBinary.empty()) && (false == DebugManager.flags.RebuildPrecompiledKernels.get())) { + this->unpackedDeviceBinary = makeCopy(reinterpret_cast(singleDeviceBinary.deviceBinary.begin()), singleDeviceBinary.deviceBinary.size()); + this->unpackedDeviceBinarySize = singleDeviceBinary.deviceBinary.size(); + this->packedDeviceBinary = makeCopy(reinterpret_cast(archive.begin()), archive.size()); + this->packedDeviceBinarySize = archive.size(); + } else { + this->isCreatedFromBinary = false; + } + + switch (singleDeviceBinary.format) { + default: + break; + case DeviceBinaryFormat::OclLibrary: + this->programBinaryType = CL_PROGRAM_BINARY_TYPE_LIBRARY; + break; + case DeviceBinaryFormat::OclCompiledObject: + this->programBinaryType = CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT; + break; } } } @@ -175,60 +200,6 @@ cl_int Program::createProgramFromBinary( return retVal; } -cl_int Program::rebuildProgramFromIr() { - size_t dataSize; - - isSpirV = false; - if (Program::isValidSpirvBinary(irBinary.get(), irBinarySize)) { - isSpirV = true; - } else if (false == Program::isValidLlvmBinary(irBinary.get(), irBinarySize)) { - return CL_INVALID_PROGRAM; - } - - CLElfLib::CElfWriter elfWriter(CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_OBJECTS, CLElfLib::E_EH_MACHINE::EH_MACHINE_NONE, 0); - - elfWriter.addSection(CLElfLib::SSectionNode(isSpirV ? CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV : CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_LLVM_BINARY, - CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "", std::string(irBinary.get(), irBinarySize), static_cast(irBinarySize))); - - dataSize = elfWriter.getTotalBinarySize(); - CLElfLib::ElfBinaryStorage data(dataSize); - elfWriter.resolveBinary(data); - - CompilerInterface *pCompilerInterface = this->executionEnvironment.getCompilerInterface(); - if (nullptr == pCompilerInterface) { - return CL_OUT_OF_HOST_MEMORY; - } - - TranslationInput inputArgs = {IGC::CodeType::elf, IGC::CodeType::oclGenBin}; - inputArgs.src = ArrayRef(data); - inputArgs.apiOptions = ArrayRef(options); - inputArgs.internalOptions = ArrayRef(internalOptions); - - TranslationOutput compilerOuput = {}; - auto err = pCompilerInterface->link(this->pDevice->getDevice(), inputArgs, compilerOuput); - this->updateBuildLog(this->pDevice, compilerOuput.frontendCompilerLog.c_str(), compilerOuput.frontendCompilerLog.size()); - this->updateBuildLog(this->pDevice, compilerOuput.backendCompilerLog.c_str(), compilerOuput.backendCompilerLog.size()); - if (TranslationOutput::ErrorCode::Success != err) { - return asClError(err); - } - - this->genBinary = std::move(compilerOuput.deviceBinary.mem); - this->genBinarySize = compilerOuput.deviceBinary.size; - this->debugData = std::move(compilerOuput.debugData.mem); - this->debugDataSize = compilerOuput.debugData.size; - - auto retVal = processGenBinary(); - if (retVal != CL_SUCCESS) { - return retVal; - } - - programBinaryType = CL_PROGRAM_BINARY_TYPE_EXECUTABLE; - isCreatedFromBinary = true; - isProgramBinaryResolved = true; - - return CL_SUCCESS; -} - cl_int Program::setProgramSpecializationConstant(cl_uint specId, size_t specSize, const void *specValue) { if (!isSpirV) { return CL_INVALID_PROGRAM; @@ -270,22 +241,6 @@ cl_int Program::updateSpecializationConstant(cl_uint specId, size_t specSize, co return CL_INVALID_SPEC_ID; } -bool Program::isValidLlvmBinary( - const void *pBinary, - size_t binarySize) { - - const char *pLlvmMagic = "BC\xc0\xde"; - bool retVal = false; - - if (pBinary && (binarySize > (strlen(pLlvmMagic) + 1))) { - if (strstr((char *)pBinary, pLlvmMagic) != nullptr) { - retVal = true; - } - } - - return retVal; -} - void Program::setDevice(Device *device) { this->pDevice = device->getSpecializedDevice(); } @@ -456,4 +411,61 @@ void Program::updateNonUniformFlag(const Program **inputPrograms, size_t numInpu this->allowNonUniform = allowNonUniform; } +void Program::replaceDeviceBinary(std::unique_ptr newBinary, size_t newBinarySize) { + if (isAnyPackedDeviceBinaryFormat(ArrayRef(reinterpret_cast(newBinary.get()), newBinarySize))) { + this->packedDeviceBinary = std::move(newBinary); + this->packedDeviceBinarySize = newBinarySize; + this->unpackedDeviceBinary.reset(); + this->unpackedDeviceBinarySize = 0U; + } else { + this->packedDeviceBinary.reset(); + this->packedDeviceBinarySize = 0U; + this->unpackedDeviceBinary = std::move(newBinary); + this->unpackedDeviceBinarySize = newBinarySize; + } +} + +cl_int Program::packDeviceBinary() { + if (nullptr != packedDeviceBinary) { + return CL_SUCCESS; + } + + auto gfxCore = pDevice->getHardwareInfo().platform.eRenderCoreFamily; + auto stepping = pDevice->getHardwareInfo().platform.usRevId; + + if (nullptr != this->unpackedDeviceBinary.get()) { + SingleDeviceBinary singleDeviceBinary; + singleDeviceBinary.buildOptions = this->options; + singleDeviceBinary.targetDevice.coreFamily = gfxCore; + singleDeviceBinary.targetDevice.stepping = stepping; + singleDeviceBinary.deviceBinary = ArrayRef(reinterpret_cast(this->unpackedDeviceBinary.get()), this->unpackedDeviceBinarySize); + singleDeviceBinary.intermediateRepresentation = ArrayRef(reinterpret_cast(this->irBinary.get()), this->irBinarySize); + std::string packWarnings; + std::string packErrors; + auto packedDeviceBinary = NEO::packDeviceBinary(singleDeviceBinary, packErrors, packWarnings); + if (packedDeviceBinary.empty()) { + DEBUG_BREAK_IF(true); + return CL_OUT_OF_HOST_MEMORY; + } + this->packedDeviceBinary = makeCopy(packedDeviceBinary.data(), packedDeviceBinary.size()); + this->packedDeviceBinarySize = packedDeviceBinary.size(); + } else if (nullptr != this->irBinary.get()) { + NEO::Elf::ElfEncoder<> elfEncoder(true, true, 1U); + if (this->programBinaryType == CL_PROGRAM_BINARY_TYPE_LIBRARY) { + elfEncoder.getElfFileHeader().type = NEO::Elf::ET_OPENCL_LIBRARY; + } else { + elfEncoder.getElfFileHeader().type = NEO::Elf::ET_OPENCL_OBJECTS; + } + elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_SPIRV, NEO::Elf::SectionNamesOpenCl::spirvObject, ArrayRef::fromAny(this->irBinary.get(), this->irBinarySize)); + elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_OPTIONS, NEO::Elf::SectionNamesOpenCl::buildOptions, this->options); + auto elfData = elfEncoder.encode(); + this->packedDeviceBinary = makeCopy(elfData.data(), elfData.size()); + this->packedDeviceBinarySize = elfData.size(); + } else { + return CL_INVALID_PROGRAM; + } + + return CL_SUCCESS; +} + } // namespace NEO diff --git a/runtime/program/program.h b/runtime/program/program.h index a9f213e81c..d85bd2a065 100644 --- a/runtime/program/program.h +++ b/runtime/program/program.h @@ -8,7 +8,7 @@ #pragma once #include "core/compiler_interface/compiler_interface.h" #include "core/compiler_interface/linker.h" -#include "core/elf/writer.h" +#include "core/device_binary_format/elf/elf_encoder.h" #include "core/program/program_info.h" #include "core/utilities/const_stringref.h" #include "runtime/api/cl_types.h" @@ -132,7 +132,6 @@ class Program : public BaseObject<_cl_program> { std::unordered_map &builtinsMap); MOCKABLE_VIRTUAL cl_int processGenBinary(); - MOCKABLE_VIRTUAL cl_int processPatchTokensBinary(ArrayRef src, ProgramInfo &dst); MOCKABLE_VIRTUAL cl_int processProgramInfo(ProgramInfo &dst); cl_int compile(cl_uint numDevices, const cl_device_id *deviceList, const char *buildOptions, @@ -181,7 +180,6 @@ class Program : public BaseObject<_cl_program> { void setDevice(Device *device); - MOCKABLE_VIRTUAL cl_int processElfBinary(const void *pBinary, size_t binarySize, uint32_t &binaryVersion); cl_int processSpirBinary(const void *pBinary, size_t binarySize, bool isSpirV); cl_int getSource(std::string &binary) const; @@ -238,8 +236,6 @@ class Program : public BaseObject<_cl_program> { kernelDebugEnabled = true; } - static bool isValidLlvmBinary(const void *pBinary, size_t binarySize); - static bool isValidSpirvBinary(const void *pBinary, size_t binarySize); bool isKernelDebugEnabled() { return kernelDebugEnabled; } @@ -260,24 +256,17 @@ class Program : public BaseObject<_cl_program> { return this->linkerInput.get(); } - MOCKABLE_VIRTUAL bool isSafeToSkipUnhandledToken(unsigned int token) const; + MOCKABLE_VIRTUAL void replaceDeviceBinary(std::unique_ptr newBinary, size_t newBinarySize); protected: Program(ExecutionEnvironment &executionEnvironment); MOCKABLE_VIRTUAL cl_int createProgramFromBinary(const void *pBinary, size_t binarySize); - cl_int resolveProgramBinary(); + cl_int packDeviceBinary(); MOCKABLE_VIRTUAL cl_int linkBinary(); - MOCKABLE_VIRTUAL cl_int isHandled(const PatchTokenBinary::ProgramFromPatchtokens &decodedProgram) const; - - MOCKABLE_VIRTUAL cl_int rebuildProgramFromIr(); - - bool validateGenBinaryDevice(GFXCORE_FAMILY device) const; - bool validateGenBinaryHeader(const iOpenCL::SProgramBinaryHeader *pGenBinaryHeader) const; - void separateBlockKernels(); void updateNonUniformFlag(); @@ -293,19 +282,20 @@ class Program : public BaseObject<_cl_program> { static const std::string clOptNameClVer; - cl_program_binary_type programBinaryType; + cl_program_binary_type programBinaryType = CL_PROGRAM_BINARY_TYPE_NONE; bool isSpirV = false; - CLElfLib::ElfBinaryStorage elfBinary; - size_t elfBinarySize; - - std::unique_ptr genBinary; - size_t genBinarySize; std::unique_ptr irBinary; - size_t irBinarySize; + size_t irBinarySize = 0U; + + std::unique_ptr unpackedDeviceBinary; + size_t unpackedDeviceBinarySize = 0U; + + std::unique_ptr packedDeviceBinary; + size_t packedDeviceBinarySize = 0U; std::unique_ptr debugData; - size_t debugDataSize; + size_t debugDataSize = 0U; CreatedFrom createdFrom = CreatedFrom::UNKNOWN; @@ -313,23 +303,22 @@ class Program : public BaseObject<_cl_program> { std::vector parentKernelInfoArray; std::vector subgroupKernelInfoArray; - GraphicsAllocation *constantSurface; - GraphicsAllocation *globalSurface; + GraphicsAllocation *constantSurface = nullptr; + GraphicsAllocation *globalSurface = nullptr; GraphicsAllocation *exportedFunctionsSurface = nullptr; - size_t globalVarTotalSize; + size_t globalVarTotalSize = 0U; - cl_build_status buildStatus; - bool isCreatedFromBinary; - bool isProgramBinaryResolved; + cl_build_status buildStatus = CL_BUILD_NONE; + bool isCreatedFromBinary = false; std::string sourceCode; std::string options; std::string internalOptions; static const std::vector internalOptionsToExtract; - uint32_t programOptionVersion; - bool allowNonUniform; + uint32_t programOptionVersion = 12U; + bool allowNonUniform = false; std::unique_ptr linkerInput; Linker::RelocatedSymbolsMap symbols; @@ -341,13 +330,13 @@ class Program : public BaseObject<_cl_program> { CIF::RAII::UPtr_t specConstantsSizes; CIF::RAII::UPtr_t specConstantsValues; - BlockKernelManager *blockKernelManager; + BlockKernelManager *blockKernelManager = nullptr; ExecutionEnvironment &executionEnvironment; - Context *context; - ClDevice *pDevice; - cl_uint numDevices; + Context *context = nullptr; + ClDevice *pDevice = nullptr; + cl_uint numDevices = 0U; - bool isBuiltIn; + bool isBuiltIn = false; bool kernelDebugEnabled = false; }; diff --git a/runtime/utilities/logger.h b/runtime/utilities/logger.h index 99d6254bdc..65311b08a4 100644 --- a/runtime/utilities/logger.h +++ b/runtime/utilities/logger.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Intel Corporation + * Copyright (C) 2019-2020 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -8,7 +8,18 @@ #pragma once #include "core/debug_settings/debug_settings_manager.h" +#include +#include +#include +#include +#include +#include +#include + namespace NEO { +class Kernel; +struct MultiDispatchInfo; + template class FileLogger { public: diff --git a/unit_tests/api/cl_get_program_build_info_tests.inl b/unit_tests/api/cl_get_program_build_info_tests.inl index bfba69a48c..22bd2347e1 100644 --- a/unit_tests/api/cl_get_program_build_info_tests.inl +++ b/unit_tests/api/cl_get_program_build_info_tests.inl @@ -6,10 +6,13 @@ */ #include "core/compiler_interface/compiler_interface.h" +#include "core/compiler_interface/intermediate_representations.h" #include "core/device/device.h" +#include "core/device_binary_format/elf/elf.h" +#include "core/device_binary_format/elf/elf_encoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" #include "core/helpers/file_io.h" #include "runtime/context/context.h" -#include "unit_tests/elflib/elf_binary_simulator.h" #include "unit_tests/helpers/kernel_binary_helper.h" #include "unit_tests/helpers/test_files.h" @@ -98,8 +101,12 @@ TEST_F(clGetProgramBuildInfoTests, givenElfBinaryWhenclGetProgramBuildInfoIsCall cl_program pProgram = nullptr; cl_int binaryStatus = CL_INVALID_VALUE; - CLElfLib::ElfBinaryStorage elfBinary; - MockElfBinary(elfBinary); + NEO::Elf::ElfEncoder elfEncoder; + elfEncoder.getElfFileHeader().type = NEO::Elf::ET_OPENCL_LIBRARY; + const uint8_t data[4] = {}; + elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_OPTIONS, NEO::Elf::SectionNamesOpenCl::buildOptions, data); + elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_SPIRV, NEO::Elf::SectionNamesOpenCl::spirvObject, ArrayRef::fromAny(NEO::spirvMagic.begin(), NEO::spirvMagic.size())); + auto elfBinary = elfEncoder.encode(); const size_t binarySize = elfBinary.size(); const unsigned char *elfBinaryTemp = reinterpret_cast(elfBinary.data()); diff --git a/unit_tests/elflib/CMakeLists.txt b/unit_tests/elflib/CMakeLists.txt deleted file mode 100644 index 11c87d124f..0000000000 --- a/unit_tests/elflib/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (C) 2017-2019 Intel Corporation -# -# SPDX-License-Identifier: MIT -# - -project(elflib_tests) - -set(CLELFLIB_UNIT_TESTS_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/elflib_tests.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp - ${NEO_SOURCE_DIR}/unit_tests/fixtures/memory_management_fixture.cpp - ${NEO_SOURCE_DIR}/unit_tests/fixtures/memory_management_fixture.h - ${NEO_SOURCE_DIR}/core/unit_tests/helpers/memory_management.cpp - ${NEO_SOURCE_DIR}/core/unit_tests/helpers/memory_management.h -) - -add_executable(elflib_tests ${CLELFLIB_UNIT_TESTS_SRCS}) -target_link_libraries(elflib_tests gmock-gtest elflib) -set_property(TARGET elflib_tests APPEND_STRING PROPERTY COMPILE_FLAGS ${ASAN_FLAGS}) - -if(UNIX) - target_link_libraries(elflib_tests ${IGDRCL_EXTRA_LIBS}) -endif() - -add_custom_target(run_elflib_tests ALL DEPENDS unit_tests elflib_tests) -add_custom_command( - TARGET run_elflib_tests - POST_BUILD - COMMAND elflib_tests ${IGDRCL_TESTS_LISTENER_OPTION} -) -add_dependencies(run_unit_tests run_elflib_tests) - -set_target_properties(elflib_tests PROPERTIES FOLDER "elflib") -set_target_properties(run_elflib_tests PROPERTIES FOLDER "elflib") -create_project_source_tree(elflib_tests ${NEO_SOURCE_DIR}/unit_tests) diff --git a/unit_tests/elflib/elf_binary_simulator.h b/unit_tests/elflib/elf_binary_simulator.h deleted file mode 100644 index e11d6c6570..0000000000 --- a/unit_tests/elflib/elf_binary_simulator.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2018-2019 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#pragma once -#include "core/elf/types.h" -#include "core/elf/writer.h" - -namespace NEO { - -void MockElfBinary(CLElfLib::ElfBinaryStorage &elfBinary) { - CLElfLib::CElfWriter elfWriter(CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_LIBRARY, CLElfLib::E_EH_MACHINE::EH_MACHINE_NONE, 0); - elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_OPTIONS, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "BuildOptions", "\0", 1u)); - - elfBinary.resize(elfWriter.getTotalBinarySize()); - - elfWriter.resolveBinary(elfBinary); -} -} // namespace NEO diff --git a/unit_tests/elflib/elflib_tests.cpp b/unit_tests/elflib/elflib_tests.cpp deleted file mode 100644 index 6ef1431140..0000000000 --- a/unit_tests/elflib/elflib_tests.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2017-2019 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#include "core/elf/reader.h" -#include "core/elf/writer.h" -#include "unit_tests/fixtures/memory_management_fixture.h" - -#include "gtest/gtest.h" - -using namespace CLElfLib; - -struct ElfTests : public MemoryManagementFixture, - public ::testing::Test { - public: - void SetUp() override { - MemoryManagementFixture::SetUp(); - } - - void TearDown() override { - MemoryManagementFixture::TearDown(); - } -}; - -TEST_F(ElfTests, givenSectionDataWhenWriteToBinaryThenSectionIsAdded) { - class MockElfWriter : public CElfWriter { - public: - MockElfWriter() : CElfWriter(E_EH_TYPE::EH_TYPE_EXECUTABLE, E_EH_MACHINE::EH_MACHINE_NONE, 0) {} - using CElfWriter::nodeQueue; - }; - - MockElfWriter writer; - std::string data{"data pattern"}; - - writer.addSection(SSectionNode(E_SH_TYPE::SH_TYPE_OPENCL_SOURCE, E_SH_FLAG::SH_FLAG_WRITE, "Steve", data, static_cast(data.size()))); - - ASSERT_EQ(2u, writer.nodeQueue.size()); - // remove first (default) section - writer.nodeQueue.pop(); - EXPECT_EQ(E_SH_TYPE::SH_TYPE_OPENCL_SOURCE, writer.nodeQueue.front().type); - EXPECT_EQ(E_SH_FLAG::SH_FLAG_WRITE, writer.nodeQueue.front().flag); - EXPECT_EQ("Steve", writer.nodeQueue.front().name); - EXPECT_EQ(data, writer.nodeQueue.front().data); - EXPECT_EQ(static_cast(data.size()), writer.nodeQueue.front().dataSize); -} - -TEST_F(ElfTests, givenCElfWriterWhenPatchElfHeaderThenDefaultAreSet) { - class MockElfWriter : public CElfWriter { - public: - MockElfWriter() : CElfWriter(E_EH_TYPE::EH_TYPE_EXECUTABLE, E_EH_MACHINE::EH_MACHINE_NONE, 0) {} - using CElfWriter::patchElfHeader; - }; - - MockElfWriter writer; - - SElf64Header elfHeader; - - writer.patchElfHeader(elfHeader); - - EXPECT_TRUE(elfHeader.Identity[ELFConstants::idIdxMagic0] == ELFConstants::elfMag0); - EXPECT_TRUE(elfHeader.Identity[ELFConstants::idIdxMagic1] == ELFConstants::elfMag1); - EXPECT_TRUE(elfHeader.Identity[ELFConstants::idIdxMagic2] == ELFConstants::elfMag2); - EXPECT_TRUE(elfHeader.Identity[ELFConstants::idIdxMagic3] == ELFConstants::elfMag3); - EXPECT_TRUE(elfHeader.Identity[ELFConstants::idIdxClass] == static_cast(E_EH_CLASS::EH_CLASS_64)); - EXPECT_TRUE(elfHeader.Identity[ELFConstants::idIdxVersion] == static_cast(E_EHT_VERSION::EH_VERSION_CURRENT)); - - EXPECT_TRUE(elfHeader.Type == E_EH_TYPE::EH_TYPE_EXECUTABLE); - EXPECT_TRUE(elfHeader.Machine == E_EH_MACHINE::EH_MACHINE_NONE); - EXPECT_TRUE(elfHeader.Flags == static_cast(0)); - EXPECT_TRUE(elfHeader.ElfHeaderSize == static_cast(sizeof(SElf64Header))); - EXPECT_TRUE(elfHeader.SectionHeaderEntrySize == static_cast(sizeof(SElf64SectionHeader))); - EXPECT_TRUE(elfHeader.NumSectionHeaderEntries == 1); - EXPECT_TRUE(elfHeader.SectionHeadersOffset == static_cast(sizeof(SElf64Header))); - EXPECT_TRUE(elfHeader.SectionNameTableIndex == 0); -} - -TEST_F(ElfTests, givenSectionDataWhenWriteToBinaryThenSectionCanBeReadByID) { - CElfWriter writer(E_EH_TYPE::EH_TYPE_EXECUTABLE, E_EH_MACHINE::EH_MACHINE_NONE, 0); - - char sectionData[16]; - memset(sectionData, 0xdeadbeef, 4); - - writer.addSection(SSectionNode(E_SH_TYPE::SH_TYPE_OPENCL_SOURCE, E_SH_FLAG::SH_FLAG_WRITE, "", std::string(sectionData, 16u), 16u)); - - size_t binarySize = writer.getTotalBinarySize(); - - ElfBinaryStorage binary(binarySize); - writer.resolveBinary(binary); - - CElfReader elfReader(binary); - - char *pData = elfReader.getSectionData(elfReader.getSectionHeaders()[1].DataOffset); - - EXPECT_EQ(16u, elfReader.getSectionHeaders()[1].DataSize); - for (unsigned int i = 0; i < elfReader.getSectionHeaders()[1].DataSize; i++) { - EXPECT_EQ(sectionData[i], pData[i]); - } -} - -TEST_F(ElfTests, givenInvalidBinaryStorageThenExceptionIsThrown) { - ElfBinaryStorage binary; - - EXPECT_THROW(CElfReader elfReader(binary), ElfException); -} diff --git a/unit_tests/elflib/main.cpp b/unit_tests/elflib/main.cpp deleted file mode 100644 index d1ed84627f..0000000000 --- a/unit_tests/elflib/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2017-2019 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#include "unit_tests/custom_event_listener.h" - -#include "gtest/gtest.h" - -int main(int argc, char **argv) { - int retVal = 0; - - ::testing::InitGoogleTest(&argc, argv); - - ::testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners(); - ::testing::TestEventListener *default_listner = listeners.default_result_printer(); - - CCustomEventListener *customEventListener = new CCustomEventListener(default_listner); - - listeners.Release(listeners.default_result_printer()); - listeners.Append(customEventListener); - - retVal = RUN_ALL_TESTS(); - - return retVal; -} diff --git a/unit_tests/fixtures/kernel_data_fixture.cpp b/unit_tests/fixtures/kernel_data_fixture.cpp index 9f7b010f71..4eb37fd146 100644 --- a/unit_tests/fixtures/kernel_data_fixture.cpp +++ b/unit_tests/fixtures/kernel_data_fixture.cpp @@ -81,7 +81,7 @@ void KernelDataTest::buildAndDecode() { // now build a program with this kernel data iOpenCL::SProgramBinaryHeader header = {}; NEO::PatchTokenBinary::ProgramFromPatchtokens programFromPatchtokens; - programFromPatchtokens.decodeStatus = PatchTokenBinary::DecoderError::Success; + programFromPatchtokens.decodeStatus = DecodeError::Success; programFromPatchtokens.header = &header; programFromPatchtokens.kernels.resize(1); auto &kernelFromPatchtokens = *programFromPatchtokens.kernels.rbegin(); @@ -90,7 +90,7 @@ void KernelDataTest::buildAndDecode() { EXPECT_TRUE(decodeSuccess); ProgramInfo programInfo; - NEO::populateProgramInfo(programInfo, programFromPatchtokens, DeviceInfoKernelPayloadConstants()); + NEO::populateProgramInfo(programInfo, programFromPatchtokens); error = program->processProgramInfo(programInfo); EXPECT_EQ(CL_SUCCESS, error); diff --git a/unit_tests/gtpin/gtpin_tests.cpp b/unit_tests/gtpin/gtpin_tests.cpp index fbcfffc9f1..3700315f7c 100644 --- a/unit_tests/gtpin/gtpin_tests.cpp +++ b/unit_tests/gtpin/gtpin_tests.cpp @@ -987,8 +987,8 @@ TEST_F(GTPinTests, givenInitializedGTPinInterfaceWhenKernelWithoutSSHIsUsedThenK PatchTokensTestData::ValidProgramWithKernel programTokens; - pProgram->genBinary = makeCopy(reinterpret_cast(programTokens.storage.data()), programTokens.storage.size()); - pProgram->genBinarySize = programTokens.storage.size(); + pProgram->unpackedDeviceBinary = makeCopy(reinterpret_cast(programTokens.storage.data()), programTokens.storage.size()); + pProgram->unpackedDeviceBinarySize = programTokens.storage.size(); retVal = pProgram->processGenBinary(); EXPECT_EQ(CL_SUCCESS, retVal); @@ -1112,8 +1112,8 @@ TEST_F(GTPinTests, givenInitializedGTPinInterfaceWhenKernelWithExecEnvIsUsedThen uint64_t hashValue = Hash::hash(reinterpret_cast(pKernelBin), kernelBinSize); pKHdr->CheckSum = static_cast(hashValue & 0xFFFFFFFF); - pProgram->genBinary = makeCopy(&binary[0], binSize); - pProgram->genBinarySize = binSize; + pProgram->unpackedDeviceBinary = makeCopy(&binary[0], binSize); + pProgram->unpackedDeviceBinarySize = binSize; retVal = pProgram->processGenBinary(); EXPECT_EQ(CL_SUCCESS, retVal); @@ -2039,8 +2039,8 @@ TEST_F(GTPinTests, givenInitializedGTPinInterfaceWhenLowMemoryConditionOccursThe PatchTokensTestData::ValidProgramWithKernel programTokens; - pProgram->genBinary = makeCopy(programTokens.storage.data(), programTokens.storage.size()); - pProgram->genBinarySize = programTokens.storage.size(); + pProgram->unpackedDeviceBinary = makeCopy(programTokens.storage.data(), programTokens.storage.size()); + pProgram->unpackedDeviceBinarySize = programTokens.storage.size(); retVal = pProgram->processGenBinary(); if (retVal == CL_OUT_OF_HOST_MEMORY) { auto nonFailingAlloc = MemoryManagement::nonfailingAllocation; diff --git a/unit_tests/libult/CMakeLists.txt b/unit_tests/libult/CMakeLists.txt index 04f3a74f14..5ca113d476 100644 --- a/unit_tests/libult/CMakeLists.txt +++ b/unit_tests/libult/CMakeLists.txt @@ -40,7 +40,6 @@ set(IGDRCL_SRCS_LIB_ULT ${NEO_SOURCE_DIR}/unit_tests/libult/source_level_debugger_library.h ${NEO_SOURCE_DIR}/unit_tests/libult/ult_aub_command_stream_receiver.h ${NEO_SOURCE_DIR}/unit_tests/libult/ult_command_stream_receiver.h - ${NEO_SOURCE_DIR}/unit_tests/program/evaluate_unhandled_token_ult.cpp ${NEO_SOURCE_DIR}/unit_tests/utilities/debug_settings_reader_creator.cpp ${NEO_CORE_DIRECTORY}/unit_tests/helpers/memory_leak_listener.cpp ${NEO_CORE_DIRECTORY}/unit_tests/helpers/memory_leak_listener.h diff --git a/unit_tests/mocks/mock_program.cpp b/unit_tests/mocks/mock_program.cpp index 69eff515ee..b7a2db003f 100644 --- a/unit_tests/mocks/mock_program.cpp +++ b/unit_tests/mocks/mock_program.cpp @@ -104,7 +104,7 @@ Program *GlobalMockSipProgram::getSipProgramWithCustomBinary() { programTokens.kernels[0].name = name; NEO::ProgramInfo programInfo; - NEO::populateProgramInfo(programInfo, programTokens, {}); + NEO::populateProgramInfo(programInfo, programTokens); Program *ret = new Program(executionEnvironment, nullptr, false); ret->processProgramInfo(programInfo); diff --git a/unit_tests/mocks/mock_program.h b/unit_tests/mocks/mock_program.h index 3808bcef60..e41053ad49 100644 --- a/unit_tests/mocks/mock_program.h +++ b/unit_tests/mocks/mock_program.h @@ -6,8 +6,10 @@ */ #pragma once +#include "core/device/device.h" #include "core/helpers/hash.h" #include "core/helpers/string.h" +#include "runtime/device/cl_device.h" #include "runtime/program/kernel_info.h" #include "runtime/program/program.h" @@ -28,8 +30,6 @@ class MockProgram : public Program { using Program::internalOptionsToExtract; using Program::isKernelDebugEnabled; using Program::linkBinary; - using Program::rebuildProgramFromIr; - using Program::resolveProgramBinary; using Program::separateBlockKernels; using Program::updateNonUniformFlag; @@ -40,19 +40,18 @@ class MockProgram : public Program { using Program::context; using Program::debugData; using Program::debugDataSize; - using Program::elfBinary; - using Program::elfBinarySize; using Program::exportedFunctionsSurface; using Program::extractInternalOptions; - using Program::genBinary; - using Program::genBinarySize; using Program::getKernelInfo; using Program::globalSurface; using Program::irBinary; using Program::irBinarySize; - using Program::isProgramBinaryResolved; using Program::isSpirV; using Program::linkerInput; + using Program::options; + using Program::packDeviceBinary; + using Program::packedDeviceBinary; + using Program::packedDeviceBinarySize; using Program::pDevice; using Program::programBinaryType; using Program::sourceCode; @@ -60,6 +59,8 @@ class MockProgram : public Program { using Program::specConstantsSizes; using Program::specConstantsValues; using Program::symbols; + using Program::unpackedDeviceBinary; + using Program::unpackedDeviceBinarySize; template MockProgram(T &&... args) : Program(std::forward(args)...) { @@ -138,15 +139,16 @@ class MockProgram : public Program { return Program::isOptionValueValid(option, value); } - cl_int isHandled(const PatchTokenBinary::ProgramFromPatchtokens &decodedProgram) const override { - if (skipValidationOfBinary) { - return CL_SUCCESS; - } - return Program::isHandled(decodedProgram); + cl_int rebuildProgramFromIr() { + this->isCreatedFromBinary = false; + this->buildStatus = CL_BUILD_NONE; + this->programBinaryType = CL_PROGRAM_BINARY_TYPE_INTERMEDIATE; + std::unordered_map builtins; + auto &device = this->pDevice->getDevice(); + return this->build(&device, this->options.c_str(), false, builtins); } bool contextSet = false; - bool skipValidationOfBinary = false; int isFlagOptionOverride = -1; int isOptionValueValidOverride = -1; }; diff --git a/unit_tests/offline_compiler/CMakeLists.txt b/unit_tests/offline_compiler/CMakeLists.txt index c4cf63e9fb..ea838d8946 100644 --- a/unit_tests/offline_compiler/CMakeLists.txt +++ b/unit_tests/offline_compiler/CMakeLists.txt @@ -83,7 +83,7 @@ target_include_directories(ocloc_tests PRIVATE ) target_compile_definitions(ocloc_tests PUBLIC MOCKABLE_VIRTUAL=virtual $) -target_link_libraries(ocloc_tests gmock-gtest elflib) +target_link_libraries(ocloc_tests gmock-gtest) if(WIN32) target_link_libraries(ocloc_tests dbghelp) diff --git a/unit_tests/offline_compiler/decoder/decoder_tests.cpp b/unit_tests/offline_compiler/decoder/decoder_tests.cpp index 902408a214..1f2e7e7011 100644 --- a/unit_tests/offline_compiler/decoder/decoder_tests.cpp +++ b/unit_tests/offline_compiler/decoder/decoder_tests.cpp @@ -217,7 +217,7 @@ TEST(DecoderTests, GivenValidBinaryWhenReadingPatchTokensFromBinaryThenBinaryIsR PTptr->fields.push_back(PTField{4, "First"}); PTptr->fields.push_back(PTField{4, "Second"}); decoder.patchTokens.insert(std::pair>(4, std::move(PTptr))); - void *ptr = reinterpret_cast(binary.data()); + const void *ptr = reinterpret_cast(binary.data()); decoder.readPatchTokens(ptr, 28, out); std::string s = "Example patchtoken:\n\t4 Token 4\n\t4 Size 16\n\t4 First 1234\n\t4 Second 5678\nUnidentified PatchToken:\n\t4 Token 2\n\t4 Size 12\n\tHex ff ff ff ff\n"; EXPECT_EQ(s, out.str()); @@ -242,7 +242,7 @@ TEST(DecoderTests, GivenValidBinaryWithoutPatchTokensWhenProcessingBinaryThenBin std::string binaryString = binarySS.str(); std::vector binary(binaryString.begin(), binaryString.end()); - auto ptr = reinterpret_cast(binary.data()); + const void *ptr = reinterpret_cast(binary.data()); int retVal = decoder.processBinary(ptr, ptmFile); EXPECT_EQ(0, retVal); @@ -291,7 +291,7 @@ TEST(DecoderTests, GivenValidBinaryWhenProcessingBinaryThenProgramAndKernelAndPa decoder.pathToDump = "non_existing_folder/"; decoder.parseTokens(); - auto ptr = reinterpret_cast(binary.data()); + const void *ptr = reinterpret_cast(binary.data()); int retVal = decoder.processBinary(ptr, ptmFile); EXPECT_EQ(0, retVal); diff --git a/unit_tests/offline_compiler/mock/mock_offline_compiler.h b/unit_tests/offline_compiler/mock/mock_offline_compiler.h index 0ac15c92f1..210cd27814 100644 --- a/unit_tests/offline_compiler/mock/mock_offline_compiler.h +++ b/unit_tests/offline_compiler/mock/mock_offline_compiler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 Intel Corporation + * Copyright (C) 2017-2020 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -15,6 +15,7 @@ namespace NEO { class MockOfflineCompiler : public OfflineCompiler { public: using OfflineCompiler::deviceName; + using OfflineCompiler::elfBinary; using OfflineCompiler::fclDeviceCtx; using OfflineCompiler::generateFilePathForIr; using OfflineCompiler::generateOptsSuffix; @@ -80,14 +81,6 @@ class MockOfflineCompiler : public OfflineCompiler { return OfflineCompiler::generateElfBinary(); } - char *getElfBinary() { - return elfBinary.data(); - } - - size_t getElfBinarySize() { - return elfBinarySize; - } - char *getGenBinary() { return genBinary; } diff --git a/unit_tests/offline_compiler/offline_compiler_tests.cpp b/unit_tests/offline_compiler/offline_compiler_tests.cpp index f74af713be..224a39a142 100644 --- a/unit_tests/offline_compiler/offline_compiler_tests.cpp +++ b/unit_tests/offline_compiler/offline_compiler_tests.cpp @@ -768,14 +768,12 @@ TEST(OfflineCompilerTest, generateElfBinary) { mockOfflineCompiler->storeGenBinary(&binHeader, binSize); - EXPECT_EQ(nullptr, mockOfflineCompiler->getElfBinary()); - EXPECT_EQ(0u, mockOfflineCompiler->getElfBinarySize()); + EXPECT_TRUE(mockOfflineCompiler->elfBinary.empty()); retVal = mockOfflineCompiler->generateElfBinary(); EXPECT_TRUE(retVal); - EXPECT_NE(nullptr, mockOfflineCompiler->getElfBinary()); - EXPECT_NE(0u, mockOfflineCompiler->getElfBinarySize()); + EXPECT_FALSE(mockOfflineCompiler->elfBinary.empty()); } TEST(OfflineCompilerTest, givenLlvmInputOptionPassedWhenCmdLineParsedThenInputFileLlvmIsSetTrue) { diff --git a/unit_tests/program/CMakeLists.txt b/unit_tests/program/CMakeLists.txt index 40f8c90cf1..198487d343 100644 --- a/unit_tests/program/CMakeLists.txt +++ b/unit_tests/program/CMakeLists.txt @@ -7,7 +7,6 @@ set(IGDRCL_SRCS_tests_program ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt ${CMAKE_CURRENT_SOURCE_DIR}/block_kernel_manager_tests.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/evaluate_unhandled_token_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/kernel_data.cpp ${CMAKE_CURRENT_SOURCE_DIR}/kernel_data_OCL2_0.cpp ${CMAKE_CURRENT_SOURCE_DIR}/kernel_info_tests.cpp diff --git a/unit_tests/program/evaluate_unhandled_token_ult.cpp b/unit_tests/program/evaluate_unhandled_token_ult.cpp deleted file mode 100644 index ac8dbb63ba..0000000000 --- a/unit_tests/program/evaluate_unhandled_token_ult.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2017-2019 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#include "runtime/program/program.h" - -namespace NEO { - -bool Program::isSafeToSkipUnhandledToken(unsigned int token) const { - return true; -} - -} // namespace NEO diff --git a/unit_tests/program/kernel_info_from_patchtokens_tests.cpp b/unit_tests/program/kernel_info_from_patchtokens_tests.cpp index 65ded7d0b9..f368463f93 100644 --- a/unit_tests/program/kernel_info_from_patchtokens_tests.cpp +++ b/unit_tests/program/kernel_info_from_patchtokens_tests.cpp @@ -16,7 +16,7 @@ TEST(KernelInfoFromPatchTokens, GivenValidEmptyKernelFromPatchtokensThenReturnEm std::vector storage; auto src = PatchTokensTestData::ValidEmptyKernel::create(storage); NEO::KernelInfo dst = {}; - NEO::populateKernelInfo(dst, src, 4, {}); + NEO::populateKernelInfo(dst, src, 4); NEO::KernelInfo expectedKernelInfo = {}; expectedKernelInfo.name = std::string(src.name.begin()).c_str(); @@ -29,7 +29,7 @@ TEST(KernelInfoFromPatchTokens, GivenValidEmptyKernelFromPatchtokensThenReturnEm TEST(KernelInfoFromPatchTokens, GivenValidKernelWithArgThenMetadataIsProperlyPopulated) { PatchTokensTestData::ValidProgramWithKernelAndArg src; NEO::KernelInfo dst = {}; - NEO::populateKernelInfo(dst, src.kernels[0], 4, {}); + NEO::populateKernelInfo(dst, src.kernels[0], 4); ASSERT_EQ(1U, dst.kernelArgInfo.size()); EXPECT_EQ(NEO::KernelArgMetadata::AccessQualifier::ReadWrite, dst.kernelArgInfo[0].metadata.accessQualifier); EXPECT_EQ(NEO::KernelArgMetadata::AddressSpaceQualifier::Global, dst.kernelArgInfo[0].metadata.addressQualifier); @@ -52,7 +52,7 @@ TEST(KernelInfoFromPatchTokens, GivenValidKernelWithImageArgThenArgAccessQualifi imageArg.Writeable = false; src.kernels[0].tokens.kernelArgs[0].objectArg = &imageArg; NEO::KernelInfo dst = {}; - NEO::populateKernelInfo(dst, src.kernels[0], 4, {}); + NEO::populateKernelInfo(dst, src.kernels[0], 4); ASSERT_EQ(1U, dst.kernelArgInfo.size()); EXPECT_EQ(NEO::KernelArgMetadata::AccessQualifier::ReadWrite, dst.kernelArgInfo[0].metadata.accessQualifier); } @@ -66,7 +66,7 @@ TEST(KernelInfoFromPatchTokens, GivenValidKernelWithImageArgWhenArgInfoIsMissing { imageArg.Writeable = false; NEO::KernelInfo dst = {}; - NEO::populateKernelInfo(dst, src.kernels[0], 4, {}); + NEO::populateKernelInfo(dst, src.kernels[0], 4); ASSERT_EQ(1U, dst.kernelArgInfo.size()); EXPECT_EQ(NEO::KernelArgMetadata::AccessQualifier::ReadOnly, dst.kernelArgInfo[0].metadata.accessQualifier); } @@ -74,7 +74,7 @@ TEST(KernelInfoFromPatchTokens, GivenValidKernelWithImageArgWhenArgInfoIsMissing { imageArg.Writeable = true; NEO::KernelInfo dst = {}; - NEO::populateKernelInfo(dst, src.kernels[0], 4, {}); + NEO::populateKernelInfo(dst, src.kernels[0], 4); ASSERT_EQ(1U, dst.kernelArgInfo.size()); EXPECT_EQ(NEO::KernelArgMetadata::AccessQualifier::ReadWrite, dst.kernelArgInfo[0].metadata.accessQualifier); } @@ -84,7 +84,7 @@ TEST(KernelInfoFromPatchTokens, GivenValidKernelWithNonDelimitedArgTypeThenUsesA PatchTokensTestData::ValidProgramWithKernelAndArg src; src.arg0TypeMutable[4] = '*'; NEO::KernelInfo dst = {}; - NEO::populateKernelInfo(dst, src.kernels[0], 4, {}); + NEO::populateKernelInfo(dst, src.kernels[0], 4); ASSERT_EQ(1U, dst.kernelArgInfo.size()); EXPECT_STREQ("int**", dst.kernelArgInfo[0].metadataExtended->type.c_str()); } @@ -96,7 +96,7 @@ TEST(KernelInfoFromPatchTokens, GivenDataParameterStreamWithEmptySizeThenTokenIs src.tokens.dataParameterStream = &dataParameterStream; dataParameterStream.DataParameterStreamSize = 0U; NEO::KernelInfo dst; - NEO::populateKernelInfo(dst, src, 4, {}); + NEO::populateKernelInfo(dst, src, 4); EXPECT_EQ(nullptr, dst.crossThreadData); } @@ -107,7 +107,7 @@ TEST(KernelInfoFromPatchTokens, GivenDataParameterStreamWithNonEmptySizeThenCros src.tokens.dataParameterStream = &dataParameterStream; dataParameterStream.DataParameterStreamSize = 256U; NEO::KernelInfo dst; - NEO::populateKernelInfo(dst, src, 4, {}); + NEO::populateKernelInfo(dst, src, 4); EXPECT_NE(nullptr, dst.crossThreadData); } @@ -147,8 +147,9 @@ TEST(KernelInfoFromPatchTokens, GivenDataParameterStreamWhenTokensRequiringDevic src.tokens.crossThreadPayloadArgs.maxWorkGroupSize = &maxWorkgroupSize; NEO::KernelInfo dst; - NEO::populateKernelInfo(dst, src, 4, deviceInfoConstants); + NEO::populateKernelInfo(dst, src, 4); ASSERT_NE(nullptr, dst.crossThreadData); + dst.apply(deviceInfoConstants); uint32_t expectedPrivateMemorySize = privateSurface.PerThreadPrivateMemorySize * deviceInfoConstants.computeUnitsUsedForScratch * src.tokens.executionEnvironment->LargestCompiledSIMDSize; EXPECT_EQ(expectedPrivateMemorySize, *reinterpret_cast(dst.crossThreadData + privateMemorySize.Offset)); EXPECT_EQ(deviceInfoConstants.slmWindowSize, *reinterpret_cast(dst.crossThreadData + localMemoryWindowsSize.Offset)); @@ -176,8 +177,9 @@ TEST(KernelInfoFromPatchTokens, GivenDataParameterStreamWhenPrivateSurfaceIsNotA src.tokens.crossThreadPayloadArgs.privateMemoryStatelessSize = &privateMemorySize; NEO::KernelInfo dst; - NEO::populateKernelInfo(dst, src, 4, deviceInfoConstants); + NEO::populateKernelInfo(dst, src, 4); ASSERT_NE(nullptr, dst.crossThreadData); + dst.apply(deviceInfoConstants); uint32_t expectedPrivateMemorySize = 0U; EXPECT_EQ(expectedPrivateMemorySize, *reinterpret_cast(dst.crossThreadData + privateMemorySize.Offset)); } @@ -191,7 +193,7 @@ TEST(KernelInfoFromPatchTokens, GivenKernelWithGtpinInfoTokenThenKernelInfoIsPro kernelTokens.tokens.gtpinInfo = >pinInfo; NEO::KernelInfo kernelInfo = {}; - NEO::populateKernelInfo(kernelInfo, kernelTokens, sizeof(uintptr_t), {}); + NEO::populateKernelInfo(kernelInfo, kernelTokens, sizeof(void *)); EXPECT_NE(nullptr, kernelInfo.igcInfoForGtpin); } @@ -208,7 +210,7 @@ TEST(KernelInfoFromPatchTokens, GivenKernelWithGlobalObjectArgThenKernelInfoIsPr kernelTokens.tokens.kernelArgs.resize(2); kernelTokens.tokens.kernelArgs[1].objectArg = &globalMemArg; NEO::KernelInfo kernelInfo = {}; - NEO::populateKernelInfo(kernelInfo, kernelTokens, sizeof(uintptr_t), {}); + NEO::populateKernelInfo(kernelInfo, kernelTokens, sizeof(void *)); EXPECT_TRUE(kernelInfo.usesSsh); EXPECT_EQ(1U, kernelInfo.argumentsToPatchNum); ASSERT_EQ(2U, kernelInfo.kernelArgInfo.size()); diff --git a/unit_tests/program/process_elf_binary_tests.cpp b/unit_tests/program/process_elf_binary_tests.cpp index ca0c71b169..40d782248b 100644 --- a/unit_tests/program/process_elf_binary_tests.cpp +++ b/unit_tests/program/process_elf_binary_tests.cpp @@ -6,10 +6,14 @@ */ #include "core/device/device.h" -#include "core/elf/reader.h" +#include "core/device_binary_format/elf/elf.h" +#include "core/device_binary_format/elf/elf_decoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" #include "core/helpers/file_io.h" #include "core/helpers/string.h" +#include "core/unit_tests/device_binary_format/patchtokens_tests.h" #include "unit_tests/helpers/test_files.h" +#include "unit_tests/mocks/mock_device.h" #include "unit_tests/mocks/mock_program.h" #include "compiler_options.h" @@ -22,52 +26,44 @@ using namespace NEO; class ProcessElfBinaryTests : public ::testing::Test { public: void SetUp() override { - executionEnvironment = std::make_unique(); - program = std::make_unique(*executionEnvironment); + device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(nullptr)); + program = std::make_unique(*device->getExecutionEnvironment()); + program->pDevice = device.get(); } - std::unique_ptr executionEnvironment; std::unique_ptr program; + std::unique_ptr device; }; TEST_F(ProcessElfBinaryTests, NullBinary) { - uint32_t binaryVersion; - cl_int retVal = program->processElfBinary(nullptr, 0, binaryVersion); - + cl_int retVal = program->createProgramFromBinary(nullptr, 0); EXPECT_EQ(CL_INVALID_BINARY, retVal); - EXPECT_NE(0u, binaryVersion); } TEST_F(ProcessElfBinaryTests, InvalidBinary) { - uint32_t binaryVersion; char pBinary[] = "thisistotallyinvalid\0"; size_t binarySize = strnlen_s(pBinary, 21); - cl_int retVal = program->processElfBinary(pBinary, binarySize, binaryVersion); + cl_int retVal = program->createProgramFromBinary(pBinary, binarySize); EXPECT_EQ(CL_INVALID_BINARY, retVal); - EXPECT_NE(0u, binaryVersion); } TEST_F(ProcessElfBinaryTests, ValidBinary) { - uint32_t binaryVersion; std::string filePath; retrieveBinaryKernelFilename(filePath, "CopyBuffer_simd8_", ".bin"); size_t binarySize = 0; auto pBinary = loadDataFromFile(filePath.c_str(), binarySize); - cl_int retVal = program->processElfBinary(pBinary.get(), binarySize, binaryVersion); + cl_int retVal = program->createProgramFromBinary(pBinary.get(), binarySize); EXPECT_EQ(CL_SUCCESS, retVal); - EXPECT_EQ(0, memcmp(pBinary.get(), program->elfBinary.data(), binarySize)); - EXPECT_NE(0u, binaryVersion); + EXPECT_EQ(0, memcmp(pBinary.get(), program->packedDeviceBinary.get(), binarySize)); } TEST_F(ProcessElfBinaryTests, ValidSpirvBinary) { //clCreateProgramWithIL => SPIR-V stored as source code const uint32_t spirvBinary[2] = {0x03022307, 0x07230203}; size_t spirvBinarySize = sizeof(spirvBinary); - auto isSpirV = Program::isValidSpirvBinary(spirvBinary, spirvBinarySize); - EXPECT_TRUE(isSpirV); //clCompileProgram => SPIR-V stored as IR binary program->isSpirV = true; @@ -79,21 +75,22 @@ TEST_F(ProcessElfBinaryTests, ValidSpirvBinary) { EXPECT_TRUE(program->getIsSpirV()); //clGetProgramInfo => SPIR-V stored as ELF binary - cl_int retVal = program->resolveProgramBinary(); + cl_int retVal = program->packDeviceBinary(); EXPECT_EQ(CL_SUCCESS, retVal); - EXPECT_FALSE(program->elfBinary.empty()); - EXPECT_NE(0u, program->elfBinarySize); + EXPECT_NE(nullptr, program->packedDeviceBinary); + EXPECT_NE(0u, program->packedDeviceBinarySize); //use ELF reader to parse and validate ELF binary - CLElfLib::CElfReader elfReader(program->elfBinary); - const CLElfLib::SElf64Header *elf64Header = elfReader.getElfHeader(); - ASSERT_NE(nullptr, elf64Header); - EXPECT_EQ(elf64Header->Type, CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_LIBRARY); + std::string decodeErrors; + std::string decodeWarnings; + auto elf = NEO::Elf::decodeElf(ArrayRef(reinterpret_cast(program->packedDeviceBinary.get()), program->packedDeviceBinarySize), decodeErrors, decodeWarnings); + auto header = elf.elfFileHeader; + ASSERT_NE(nullptr, header); - //check if ELF binary contains section SH_TYPE_SPIRV + //check if ELF binary contains section SECTION_HEADER_TYPE_SPIRV bool hasSpirvSection = false; - for (const auto &elfSectionHeader : elfReader.getSectionHeaders()) { - if (elfSectionHeader.Type == CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV) { + for (const auto &elfSectionHeader : elf.sectionHeaders) { + if (elfSectionHeader.header->type == NEO::Elf::SHT_OPENCL_SPIRV) { hasSpirvSection = true; break; } @@ -102,10 +99,8 @@ TEST_F(ProcessElfBinaryTests, ValidSpirvBinary) { //clCreateProgramWithBinary => new program should recognize SPIR-V binary program->isSpirV = false; - uint32_t elfBinaryVersion; - auto pElfBinary = std::unique_ptr(new char[program->elfBinarySize]); - memcpy_s(pElfBinary.get(), program->elfBinarySize, program->elfBinary.data(), program->elfBinarySize); - retVal = program->processElfBinary(pElfBinary.get(), program->elfBinarySize, elfBinaryVersion); + auto elfBinary = makeCopy(program->packedDeviceBinary.get(), program->packedDeviceBinarySize); + retVal = program->createProgramFromBinary(elfBinary.get(), program->packedDeviceBinarySize); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(program->getIsSpirV()); } @@ -118,49 +113,71 @@ unsigned int BinaryTypeValues[] = { class ProcessElfBinaryTestsWithBinaryType : public ::testing::TestWithParam { public: void SetUp() override { - executionEnvironment = std::make_unique(); - program = std::make_unique(*executionEnvironment); + device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(nullptr)); + program = std::make_unique(*device->getExecutionEnvironment()); + program->pDevice = device.get(); } - std::unique_ptr executionEnvironment; std::unique_ptr program; + std::unique_ptr device; }; TEST_P(ProcessElfBinaryTestsWithBinaryType, GivenBinaryTypeWhenResolveProgramThenProgramIsProperlyResolved) { - uint32_t binaryVersion; std::string filePath; retrieveBinaryKernelFilename(filePath, "CopyBuffer_simd8_", ".bin"); size_t binarySize = 0; auto pBinary = loadDataFromFile(filePath.c_str(), binarySize); - cl_int retVal = program->processElfBinary(pBinary.get(), binarySize, binaryVersion); - - const auto &options = program->getOptions(); - size_t optionsSize = strlen(options.c_str()) + 1; - auto pTmpGenBinary = new char[program->genBinarySize]; - auto pTmpIrBinary = new char[program->irBinarySize]; - auto pTmpOptions = new char[optionsSize]; - - memcpy_s(pTmpGenBinary, program->genBinarySize, program->genBinary.get(), program->genBinarySize); - memcpy_s(pTmpIrBinary, program->irBinarySize, program->irBinary.get(), program->irBinarySize); - memcpy_s(pTmpOptions, optionsSize, options.c_str(), optionsSize); + cl_int retVal = program->createProgramFromBinary(pBinary.get(), binarySize); + auto options = program->options; + auto genBinary = makeCopy(program->unpackedDeviceBinary.get(), program->unpackedDeviceBinarySize); + auto genBinarySize = program->unpackedDeviceBinarySize; + auto irBinary = makeCopy(program->irBinary.get(), program->irBinarySize); + auto irBinarySize = program->irBinarySize; EXPECT_EQ(CL_SUCCESS, retVal); - EXPECT_EQ(0, memcmp(pBinary.get(), program->elfBinary.data(), binarySize)); - EXPECT_NE(0u, binaryVersion); + ASSERT_EQ(binarySize, program->packedDeviceBinarySize); + EXPECT_EQ(0, memcmp(pBinary.get(), program->packedDeviceBinary.get(), binarySize)); // delete program's elf reference to force a resolve - program->isProgramBinaryResolved = false; + program->packedDeviceBinary.reset(); + program->packedDeviceBinarySize = 0U; program->programBinaryType = GetParam(); - retVal = program->resolveProgramBinary(); + retVal = program->packDeviceBinary(); EXPECT_EQ(CL_SUCCESS, retVal); - EXPECT_EQ(0, memcmp(pTmpGenBinary, program->genBinary.get(), program->genBinarySize)); - EXPECT_EQ(0, memcmp(pTmpIrBinary, program->irBinary.get(), program->irBinarySize)); - EXPECT_EQ(0, memcmp(pTmpOptions, options.c_str(), optionsSize)); + ASSERT_NE(nullptr, program->packedDeviceBinary); - delete[] pTmpGenBinary; - delete[] pTmpIrBinary; - delete[] pTmpOptions; + std::string decodeErrors; + std::string decodeWarnings; + auto elf = NEO::Elf::decodeElf(ArrayRef(reinterpret_cast(program->packedDeviceBinary.get()), program->packedDeviceBinarySize), decodeErrors, decodeWarnings); + ASSERT_NE(nullptr, elf.elfFileHeader); + ArrayRef decodedIr; + ArrayRef decodedDeviceBinary; + ArrayRef decodedOptions; + for (auto §ion : elf.sectionHeaders) { + switch (section.header->type) { + default: + break; + case NEO::Elf::SHT_OPENCL_LLVM_BINARY: + decodedIr = section.data; + break; + case NEO::Elf::SHT_OPENCL_SPIRV: + decodedIr = section.data; + break; + case NEO::Elf::SHT_OPENCL_DEV_BINARY: + decodedDeviceBinary = section.data; + break; + case NEO::Elf::SHT_OPENCL_OPTIONS: + decodedDeviceBinary = section.data; + break; + } + } + ASSERT_EQ(options.size(), decodedOptions.size()); + ASSERT_EQ(genBinarySize, decodedDeviceBinary.size()); + ASSERT_EQ(irBinarySize, decodedIr.size()); + + EXPECT_EQ(0, memcmp(genBinary.get(), decodedDeviceBinary.begin(), genBinarySize)); + EXPECT_EQ(0, memcmp(irBinary.get(), decodedIr.begin(), irBinarySize)); } INSTANTIATE_TEST_CASE_P(ResolveBinaryTests, @@ -168,85 +185,72 @@ INSTANTIATE_TEST_CASE_P(ResolveBinaryTests, ::testing::ValuesIn(BinaryTypeValues)); TEST_F(ProcessElfBinaryTests, BackToBack) { - uint32_t binaryVersion; std::string filePath; retrieveBinaryKernelFilename(filePath, "CopyBuffer_simd8_", ".bin"); size_t binarySize = 0; auto pBinary = loadDataFromFile(filePath.c_str(), binarySize); - cl_int retVal = program->processElfBinary(pBinary.get(), binarySize, binaryVersion); + cl_int retVal = program->createProgramFromBinary(pBinary.get(), binarySize); EXPECT_EQ(CL_SUCCESS, retVal); - EXPECT_EQ(0, memcmp(pBinary.get(), program->elfBinary.data(), binarySize)); - EXPECT_NE(0u, binaryVersion); + EXPECT_EQ(0, memcmp(pBinary.get(), program->packedDeviceBinary.get(), binarySize)); std::string filePath2; retrieveBinaryKernelFilename(filePath2, "simple_arg_int_", ".bin"); pBinary = loadDataFromFile(filePath2.c_str(), binarySize); - retVal = program->processElfBinary(pBinary.get(), binarySize, binaryVersion); + retVal = program->createProgramFromBinary(pBinary.get(), binarySize); EXPECT_EQ(CL_SUCCESS, retVal); - EXPECT_EQ(0, memcmp(pBinary.get(), program->elfBinary.data(), binarySize)); - EXPECT_NE(0u, binaryVersion); + EXPECT_EQ(0, memcmp(pBinary.get(), program->packedDeviceBinary.get(), binarySize)); } TEST_F(ProcessElfBinaryTests, BuildOptionsEmpty) { - uint32_t binaryVersion; std::string filePath; retrieveBinaryKernelFilename(filePath, "simple_kernels_", ".bin"); size_t binarySize = 0; auto pBinary = loadDataFromFile(filePath.c_str(), binarySize); - cl_int retVal = program->processElfBinary(pBinary.get(), binarySize, binaryVersion); + cl_int retVal = program->createProgramFromBinary(pBinary.get(), binarySize); EXPECT_EQ(CL_SUCCESS, retVal); const auto &options = program->getOptions(); size_t optionsSize = strlen(options.c_str()) + 1; EXPECT_EQ(0, memcmp("", options.c_str(), optionsSize)); - EXPECT_NE(0u, binaryVersion); } TEST_F(ProcessElfBinaryTests, BuildOptionsNotEmpty) { - uint32_t binaryVersion; std::string filePath; retrieveBinaryKernelFilename(filePath, "simple_kernels_opts_", ".bin"); size_t binarySize = 0; auto pBinary = loadDataFromFile(filePath.c_str(), binarySize); - cl_int retVal = program->processElfBinary(pBinary.get(), binarySize, binaryVersion); + cl_int retVal = program->createProgramFromBinary(pBinary.get(), binarySize); EXPECT_EQ(CL_SUCCESS, retVal); const auto &options = program->getOptions(); - size_t optionsSize = strlen(options.c_str()) + 1; std::string buildOptionsNotEmpty = CompilerOptions::concatenate(CompilerOptions::optDisable, "-DDEF_WAS_SPECIFIED=1"); - EXPECT_EQ(0, memcmp(buildOptionsNotEmpty.c_str(), options.c_str(), optionsSize)); - EXPECT_NE(0u, binaryVersion); + EXPECT_STREQ(buildOptionsNotEmpty.c_str(), options.c_str()); } -TEST_F(ProcessElfBinaryTests, GivenBinaryWhenInvalidCURRENT_ICBE_VERSIONThenInvalidCURRENT_ICBE_VERSIONTIsReturned) { - uint32_t binaryVersion; - CLElfLib::ElfBinaryStorage elfBinary; - - CLElfLib::CElfWriter elfWriter(CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_EXECUTABLE, CLElfLib::E_EH_MACHINE::EH_MACHINE_NONE, 0); - - char *genBinary; - size_t genBinarySize = sizeof(SProgramBinaryHeader); - SProgramBinaryHeader genBinaryHeader = {0}; - genBinaryHeader.Magic = iOpenCL::MAGIC_CL; - genBinaryHeader.Version = iOpenCL::CURRENT_ICBE_VERSION - 3u; - genBinary = reinterpret_cast(&genBinaryHeader); - - if (genBinary) { - std::string genBinaryTemp = genBinary ? std::string(genBinary, genBinarySize) : ""; - elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "Intel(R) OpenCL Device Binary", std::move(genBinaryTemp), static_cast(genBinarySize))); +TEST_F(ProcessElfBinaryTests, GivenBinaryWhenIncompatiblePatchtokenVerionThenProramCreationFails) { + PatchTokensTestData::ValidEmptyProgram programTokens; + { + NEO::Elf::ElfEncoder<> elfEncoder; + elfEncoder.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_DEV_BINARY, NEO::Elf::SectionNamesOpenCl::deviceBinary, programTokens.storage); + auto elfBinary = elfEncoder.encode(); + cl_int retVal = program->createProgramFromBinary(elfBinary.data(), elfBinary.size()); + EXPECT_EQ(CL_SUCCESS, retVal); } - elfBinary.resize(elfWriter.getTotalBinarySize()); - elfWriter.resolveBinary(elfBinary); - - cl_int retVal = program->processElfBinary(elfBinary.data(), elfBinary.size(), binaryVersion); - - EXPECT_EQ(CL_INVALID_BINARY, retVal); - EXPECT_EQ(binaryVersion, iOpenCL::CURRENT_ICBE_VERSION - 3u); + { + programTokens.headerMutable->Version -= 1; + NEO::Elf::ElfEncoder<> elfEncoder; + elfEncoder.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_DEV_BINARY, NEO::Elf::SectionNamesOpenCl::deviceBinary, programTokens.storage); + auto elfBinary = elfEncoder.encode(); + cl_int retVal = program->createProgramFromBinary(elfBinary.data(), elfBinary.size()); + EXPECT_EQ(CL_INVALID_BINARY, retVal); + } } diff --git a/unit_tests/program/program_data_tests.cpp b/unit_tests/program/program_data_tests.cpp index 19f34c752e..35f66215d2 100644 --- a/unit_tests/program/program_data_tests.cpp +++ b/unit_tests/program/program_data_tests.cpp @@ -153,8 +153,8 @@ void ProgramDataTestBase::buildAndDecodeProgramPatchList() { pCurPtr += programPatchListSize; //as we use mock compiler in unit test, replace the genBinary here. - pProgram->genBinary = makeCopy(pProgramData, headerSize + programBinaryHeader.PatchListSize); - pProgram->genBinarySize = headerSize + programBinaryHeader.PatchListSize; + pProgram->unpackedDeviceBinary = makeCopy(pProgramData, headerSize + programBinaryHeader.PatchListSize); + pProgram->unpackedDeviceBinarySize = headerSize + programBinaryHeader.PatchListSize; error = pProgram->processGenBinary(); patchlistDecodeErrorCode = error; @@ -401,7 +401,7 @@ TEST(ProgramScopeMetadataTest, WhenPatchingGlobalSurfaceThenPickProperSourceBuff ProgramInfo programInfo; MockProgram program(execEnv); program.pDevice = &device; - NEO::populateProgramInfo(programInfo, decodedProgram, DeviceInfoKernelPayloadConstants{}); + NEO::populateProgramInfo(programInfo, decodedProgram); program.processProgramInfo(programInfo); ASSERT_NE(nullptr, program.globalSurface); ASSERT_NE(nullptr, program.constantSurface); @@ -476,7 +476,6 @@ TEST_F(ProgramDataTest, GivenProgramWith32bitPointerOptWhenProgramScopeGlobalPoi uint32_t sentinel = 0x17192329U; globalSurfaceStorage[0] = 0U; globalSurfaceStorage[1] = sentinel; - this->pProgram->skipValidationOfBinary = true; pProgram->linkerInput = std::move(programInfo.linkerInput); pProgram->linkBinary(); diff --git a/unit_tests/program/program_tests.cpp b/unit_tests/program/program_tests.cpp index 21841e9c70..4659a80a08 100644 --- a/unit_tests/program/program_tests.cpp +++ b/unit_tests/program/program_tests.cpp @@ -7,8 +7,10 @@ #include "unit_tests/program/program_tests.h" +#include "core/compiler_interface/intermediate_representations.h" +#include "core/device_binary_format/elf/elf_decoder.h" +#include "core/device_binary_format/elf/ocl_elf.h" #include "core/device_binary_format/patchtokens_decoder.h" -#include "core/elf/reader.h" #include "core/gmm_helper/gmm_helper.h" #include "core/helpers/aligned_memory.h" #include "core/helpers/hash.h" @@ -1509,61 +1511,7 @@ TEST(ProgramFromBinaryTests, givenBinaryWithInvalidICBEThenErrorIsReturned) { } } -class FailProgram : public Program { - public: - FailProgram(ExecutionEnvironment &executionEnvironment, Context *context, bool isBuiltIn = false) : Program(executionEnvironment, context, isBuiltIn) {} - cl_int rebuildProgramFromIr() override { - return CL_INVALID_PROGRAM; - } - // make method visible - cl_int createProgramFromBinary(const void *pBinary, size_t binarySize) override { - return Program::createProgramFromBinary(pBinary, binarySize); - } - cl_int processElfBinary(const void *pBinary, size_t binarySize, uint32_t &binaryVersion) override { - binaryVersion--; - // we should return anything but not CL_SUCCESS - return CL_INVALID_BINARY; - } -}; - -TEST(ProgramFromBinaryTests, CreateWithBinary_FailRecompile) { - cl_int retVal = CL_INVALID_BINARY; - - SProgramBinaryHeader binHeader; - memset(&binHeader, 0, sizeof(binHeader)); - binHeader.Magic = iOpenCL::MAGIC_CL; - binHeader.Version = iOpenCL::CURRENT_ICBE_VERSION; - binHeader.Device = platformDevices[0]->platform.eRenderCoreFamily; - binHeader.GPUPointerSizeInBytes = 8; - binHeader.NumberOfKernels = 0; - binHeader.SteppingId = 0; - binHeader.PatchListSize = 0; - size_t binSize = sizeof(SProgramBinaryHeader); - - ExecutionEnvironment executionEnvironment; - std::unique_ptr pProgram(FailProgram::createFromGenBinary(executionEnvironment, nullptr, &binHeader, binSize, false, &retVal)); - ASSERT_NE(nullptr, pProgram.get()); - EXPECT_EQ(CL_SUCCESS, retVal); - - binHeader.Version = iOpenCL::CURRENT_ICBE_VERSION - 1; - retVal = pProgram->createProgramFromBinary(&binHeader, binSize); - EXPECT_EQ(CL_INVALID_BINARY, retVal); -} - TEST(ProgramFromBinaryTests, givenEmptyProgramThenErrorIsReturned) { - class TestedProgram : public Program { - public: - TestedProgram(ExecutionEnvironment &executionEnvironment, Context *context, bool isBuiltIn) : Program(executionEnvironment, context, isBuiltIn) {} - char *setGenBinary(char *binary) { - auto res = genBinary.get(); - genBinary.release(); - genBinary.reset(binary); - return res; - } - void setGenBinarySize(size_t size) { - genBinarySize = size; - } - }; cl_int retVal = CL_INVALID_BINARY; SProgramBinaryHeader binHeader; @@ -1578,14 +1526,13 @@ TEST(ProgramFromBinaryTests, givenEmptyProgramThenErrorIsReturned) { size_t binSize = sizeof(SProgramBinaryHeader); ExecutionEnvironment executionEnvironment; - std::unique_ptr pProgram(TestedProgram::createFromGenBinary(executionEnvironment, nullptr, &binHeader, binSize, false, &retVal)); + std::unique_ptr pProgram(MockProgram::createFromGenBinary(executionEnvironment, nullptr, &binHeader, binSize, false, &retVal)); ASSERT_NE(nullptr, pProgram.get()); EXPECT_EQ(CL_SUCCESS, retVal); - auto originalPtr = pProgram->setGenBinary(nullptr); + pProgram->unpackedDeviceBinary.reset(nullptr); retVal = pProgram->processGenBinary(); EXPECT_EQ(CL_INVALID_BINARY, retVal); - pProgram->setGenBinary(originalPtr); } INSTANTIATE_TEST_CASE_P(ProgramFromBinaryTests, @@ -1942,64 +1889,13 @@ TEST_F(ProgramTests, givenProgramFromGenBinaryWhenSLMSizeIsBiggerThenDeviceLimit patchtokensProgram.slmMutable->TotalInlineLocalMemorySize = static_cast(pDevice->getDeviceInfo().localMemSize * 2); patchtokensProgram.recalcTokPtr(); auto program = std::make_unique(*pDevice->getExecutionEnvironment(), nullptr, false); - program->genBinary = makeCopy(patchtokensProgram.storage.data(), patchtokensProgram.storage.size()); - program->genBinarySize = patchtokensProgram.storage.size(); + program->unpackedDeviceBinary = makeCopy(patchtokensProgram.storage.data(), patchtokensProgram.storage.size()); + program->unpackedDeviceBinarySize = patchtokensProgram.storage.size(); auto retVal = program->processGenBinary(); EXPECT_EQ(CL_OUT_OF_RESOURCES, retVal); } -TEST_F(ProgramTests, ValidBinaryWithIGCVersionEqual0) { - cl_int retVal; - - auto program = std::make_unique(*pDevice->getExecutionEnvironment()); - EXPECT_NE(nullptr, program); - cl_device_id deviceId = pContext->getDevice(0); - ClDevice *pDevice = castToObject(deviceId); - program->setDevice(pDevice); - - // Load a binary program file - size_t binarySize = 0; - std::string filePath; - retrieveBinaryKernelFilename(filePath, "CopyBuffer_simd8_", ".bin"); - auto pBinary = loadDataFromFile(filePath.c_str(), binarySize); - EXPECT_NE(0u, binarySize); - program->elfBinary = CLElfLib::ElfBinaryStorage(pBinary.get(), pBinary.get() + binarySize); - - // Find its OpenCL program data and mark that the data were created with unknown compiler version, - // which means that the program has to be rebuild from its IR binary - CLElfLib::CElfReader elfReader(program->elfBinary); - const CLElfLib::SElf64Header *elf64Header = elfReader.getElfHeader(); - char *pSectionData = nullptr; - SProgramBinaryHeader *pBHdr = nullptr; - EXPECT_NE(nullptr, elf64Header); - EXPECT_EQ(elf64Header->Type, CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_EXECUTABLE); - - for (const auto &elfHeaderSection : elfReader.getSectionHeaders()) { - if (elfHeaderSection.Type != CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY) { - continue; - } - pSectionData = elfReader.getSectionData(elfHeaderSection.DataOffset); - EXPECT_NE(nullptr, pSectionData); - EXPECT_NE(0u, elfHeaderSection.DataSize); - pBHdr = (SProgramBinaryHeader *)pSectionData; - pBHdr->Version = 0; // Simulate compiler Version = 0 - break; - } - EXPECT_NE(nullptr, pBHdr); - - // Create program from modified binary, is should be successfully rebuilt - retVal = program->createProgramFromBinary(pBinary.get(), binarySize); - EXPECT_EQ(CL_SUCCESS, retVal); - - // Get IR binary and modify its header magic, - // then ask to rebuild program from its IR binary - it should fail - char *pIrBinary = program->irBinary.get(); - (*pIrBinary)--; - retVal = program->rebuildProgramFromIr(); - EXPECT_EQ(CL_INVALID_PROGRAM, retVal); -} - TEST_F(ProgramTests, RebuildBinaryButNoCompilerInterface) { auto noCompilerInterfaceExecutionEnvironment = std::make_unique(nullptr); auto program = std::make_unique(*noCompilerInterfaceExecutionEnvironment); @@ -2021,42 +1917,9 @@ TEST_F(ProgramTests, RebuildBinaryButNoCompilerInterface) { // Ask to rebuild program from its IR binary - it should fail (no Compiler Interface) retVal = program->rebuildProgramFromIr(); - EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); + EXPECT_NE(CL_SUCCESS, retVal); } -TEST_F(ProgramTests, RebuildBinaryWithRebuildError) { - class MyCompilerInterface : public CompilerInterface { - public: - MyCompilerInterface(){}; - ~MyCompilerInterface() override{}; - - TranslationOutput::ErrorCode link(const NEO::Device &device, const TranslationInput &input, TranslationOutput &output) override { - return TranslationOutput::ErrorCode::LinkFailure; - } - }; - - auto cip = std::make_unique(); - MockCompIfaceExecutionEnvironment executionEnvironment(cip.get()); - auto program = std::make_unique(executionEnvironment); - cl_device_id deviceId = pContext->getDevice(0); - ClDevice *pDevice = castToObject(deviceId); - program->setDevice(pDevice); - - // Load a binary program file - std::string filePath; - retrieveBinaryKernelFilename(filePath, "CopyBuffer_simd8_", ".bin"); - size_t binarySize = 0; - auto pBinary = loadDataFromFile(filePath.c_str(), binarySize); - EXPECT_NE(0u, binarySize); - - // Create program from loaded binary - cl_int retVal = program->createProgramFromBinary(pBinary.get(), binarySize); - EXPECT_EQ(CL_SUCCESS, retVal); - - // Ask to rebuild program from its IR binary - it should fail (linking error) - retVal = program->rebuildProgramFromIr(); - EXPECT_EQ(CL_LINK_PROGRAM_FAILURE, retVal); -} TEST_F(ProgramTests, BuildProgramWithReraFlag) { auto cip = std::make_unique(); @@ -2373,44 +2236,44 @@ TEST_F(ProgramTests, createFromILWhenCreatingProgramFromBinaryThenProperFlagIsSi prog->release(); } -static const char llvmBinary[] = "BC\xc0\xde "; +static const uint8_t llvmBinary[] = "BC\xc0\xde "; TEST(isValidLlvmBinary, whenLlvmMagicWasFoundThenBinaryIsValidLLvm) { - EXPECT_TRUE(Program::isValidLlvmBinary(llvmBinary, sizeof(llvmBinary))); + EXPECT_TRUE(NEO::isLlvmBitcode(llvmBinary)); } TEST(isValidLlvmBinary, whenBinaryIsNullptrThenBinaryIsNotValidLLvm) { - EXPECT_FALSE(Program::isValidLlvmBinary(nullptr, sizeof(llvmBinary))); + EXPECT_FALSE(NEO::isLlvmBitcode(ArrayRef())); } TEST(isValidLlvmBinary, whenBinaryIsShorterThanLllvMagicThenBinaryIsNotValidLLvm) { - EXPECT_FALSE(Program::isValidLlvmBinary(llvmBinary, 2)); + EXPECT_FALSE(NEO::isLlvmBitcode(ArrayRef(llvmBinary, 2))); } TEST(isValidLlvmBinary, whenBinaryDoesNotContainLllvMagicThenBinaryIsNotValidLLvm) { - char notLlvmBinary[] = "ABCDEFGHIJKLMNO"; - EXPECT_FALSE(Program::isValidLlvmBinary(notLlvmBinary, sizeof(notLlvmBinary))); + const uint8_t notLlvmBinary[] = "ABCDEFGHIJKLMNO"; + EXPECT_FALSE(NEO::isLlvmBitcode(notLlvmBinary)); } const uint32_t spirv[16] = {0x03022307}; const uint32_t spirvInvEndianes[16] = {0x07230203}; TEST(isValidSpirvBinary, whenSpirvMagicWasFoundThenBinaryIsValidSpirv) { - EXPECT_TRUE(Program::isValidSpirvBinary(spirv, sizeof(spirv))); - EXPECT_TRUE(Program::isValidSpirvBinary(spirvInvEndianes, sizeof(spirvInvEndianes))); + EXPECT_TRUE(NEO::isSpirVBitcode(ArrayRef(reinterpret_cast(&spirv), sizeof(spirv)))); + EXPECT_TRUE(NEO::isSpirVBitcode(ArrayRef(reinterpret_cast(&spirvInvEndianes), sizeof(spirvInvEndianes)))); } TEST(isValidSpirvBinary, whenBinaryIsNullptrThenBinaryIsNotValidLLvm) { - EXPECT_FALSE(Program::isValidSpirvBinary(nullptr, sizeof(spirv))); + EXPECT_FALSE(NEO::isSpirVBitcode(ArrayRef())); } TEST(isValidSpirvBinary, whenBinaryIsShorterThanLllvMagicThenBinaryIsNotValidLLvm) { - EXPECT_FALSE(Program::isValidSpirvBinary(spirv, 2)); + EXPECT_FALSE(NEO::isSpirVBitcode(ArrayRef(reinterpret_cast(&spirvInvEndianes), 2))); } TEST(isValidSpirvBinary, whenBinaryDoesNotContainLllvMagicThenBinaryIsNotValidLLvm) { - char notSpirvBinary[] = "ABCDEFGHIJKLMNO"; - EXPECT_FALSE(Program::isValidSpirvBinary(notSpirvBinary, sizeof(notSpirvBinary))); + const uint8_t notSpirvBinary[] = "ABCDEFGHIJKLMNO"; + EXPECT_FALSE(NEO::isSpirVBitcode(notSpirvBinary)); } TEST_F(ProgramTests, linkingTwoValidSpirvProgramsReturnsValidProgram) { @@ -2622,20 +2485,11 @@ TEST_F(ProgramTests, givenProgramWithSpirvWhenRebuildProgramIsCalledThenSpirvPat program->isSpirV = true; auto buildRet = program->rebuildProgramFromIr(); EXPECT_NE(CL_SUCCESS, buildRet); - - CLElfLib::ElfBinaryStorage elfBin(receivedInput.begin(), receivedInput.end()); - CLElfLib::CElfReader elfReader(elfBin); - - char *spvSectionData = nullptr; - size_t spvSectionDataSize = 0; - for (const auto &elfSectionHeader : elfReader.getSectionHeaders()) { - if (elfSectionHeader.Type == CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV) { - spvSectionData = elfReader.getSectionData(elfSectionHeader.DataOffset); - spvSectionDataSize = static_cast(elfSectionHeader.DataSize); - } - } - EXPECT_EQ(sizeof(spirv), spvSectionDataSize); - EXPECT_EQ(0, memcmp(spirv, spvSectionData, spvSectionDataSize)); + ASSERT_EQ(sizeof(spirv), receivedInput.size()); + EXPECT_EQ(0, memcmp(spirv, receivedInput.c_str(), receivedInput.size())); + ASSERT_EQ(1U, compilerInterface->requestedTranslationCtxs.size()); + EXPECT_EQ(IGC::CodeType::spirV, compilerInterface->requestedTranslationCtxs[0].first); + EXPECT_EQ(IGC::CodeType::oclGenBin, compilerInterface->requestedTranslationCtxs[0].second); } TEST_F(ProgramTests, whenRebuildingProgramThenStoreDeviceBinaryProperly) { @@ -2659,12 +2513,12 @@ TEST_F(ProgramTests, whenRebuildingProgramThenStoreDeviceBinaryProperly) { uint32_t ir[16] = {0x03022307, 0x23471113, 0x17192329}; program->irBinary = makeCopy(ir, sizeof(ir)); program->irBinarySize = sizeof(ir); - EXPECT_EQ(nullptr, program->genBinary); - EXPECT_EQ(0U, program->genBinarySize); + EXPECT_EQ(nullptr, program->unpackedDeviceBinary); + EXPECT_EQ(0U, program->unpackedDeviceBinarySize); program->rebuildProgramFromIr(); - ASSERT_NE(nullptr, program->genBinary); - ASSERT_EQ(sizeof(binaryToReturn), program->genBinarySize); - EXPECT_EQ(0, memcmp(binaryToReturn, program->genBinary.get(), program->genBinarySize)); + ASSERT_NE(nullptr, program->unpackedDeviceBinary); + ASSERT_EQ(sizeof(binaryToReturn), program->unpackedDeviceBinarySize); + EXPECT_EQ(0, memcmp(binaryToReturn, program->unpackedDeviceBinary.get(), program->unpackedDeviceBinarySize)); } TEST_F(ProgramTests, givenProgramWhenInternalOptionsArePassedThenTheyAreAddedToProgramInternalOptions) { @@ -2672,7 +2526,7 @@ TEST_F(ProgramTests, givenProgramWhenInternalOptionsArePassedThenTheyAreAddedToP MockProgram program(executionEnvironment); program.getInternalOptions().erase(); EXPECT_EQ(nullptr, program.getDevicePtr()); - std::string buildOptions(NEO::CompilerOptions::gtpinRera); + std::string buildOptions = NEO::CompilerOptions::gtpinRera.str(); program.extractInternalOptions(buildOptions); EXPECT_STREQ(program.getInternalOptions().c_str(), NEO::CompilerOptions::gtpinRera.data()); } @@ -2756,73 +2610,44 @@ TEST_F(ProgramTests, givenProgramWhenBuiltThenAdditionalOptionsAreApplied) { EXPECT_EQ(1u, program.applyAdditionalOptionsCalled); } -struct RebuildProgram : public Program { - using Program::createProgramFromBinary; - RebuildProgram(ExecutionEnvironment &executionEnvironment, Context *context, bool isBuiltIn = false) : Program(executionEnvironment, context, isBuiltIn) {} - cl_int rebuildProgramFromIr() override { - rebuildProgramFromIrCalled = true; - return CL_SUCCESS; - } - cl_int processElfBinary(const void *pBinary, size_t binarySize, uint32_t &binaryVersion) override { - processElfBinaryCalled = true; - return CL_SUCCESS; - } - bool rebuildProgramFromIrCalled = false; - bool processElfBinaryCalled = false; -}; - -TEST(RebuildProgramFromIrTests, givenBinaryProgramWhenKernelRebulildIsForcedThenRebuildProgramFromIrCalled) { +TEST(CreateProgramFromBinaryTests, givenBinaryProgramWhenKernelRebulildIsForcedThenDeviceBinaryIsNotUsed) { DebugManagerStateRestore dbgRestorer; DebugManager.flags.RebuildPrecompiledKernels.set(true); cl_int retVal = CL_INVALID_BINARY; - SProgramBinaryHeader binHeader; - memset(&binHeader, 0, sizeof(binHeader)); - binHeader.Magic = iOpenCL::MAGIC_CL; - binHeader.Version = iOpenCL::CURRENT_ICBE_VERSION; - binHeader.Device = platformDevices[0]->platform.eRenderCoreFamily; - binHeader.GPUPointerSizeInBytes = 8; - binHeader.NumberOfKernels = 0; - binHeader.SteppingId = 0; - binHeader.PatchListSize = 0; - size_t binSize = sizeof(SProgramBinaryHeader); + PatchTokensTestData::ValidEmptyProgram programTokens; - ExecutionEnvironment executionEnvironment; - std::unique_ptr pProgram(RebuildProgram::createFromGenBinary(executionEnvironment, nullptr, &binHeader, binSize, false, &retVal)); + auto clDevice = std::make_unique(MockDevice::createWithNewExecutionEnvironment(nullptr)); + std::unique_ptr pProgram(Program::createFromGenBinary(*clDevice->getExecutionEnvironment(), nullptr, programTokens.storage.data(), programTokens.storage.size(), false, &retVal)); + pProgram->pDevice = clDevice.get(); ASSERT_NE(nullptr, pProgram.get()); EXPECT_EQ(CL_SUCCESS, retVal); - binHeader.Version = iOpenCL::CURRENT_ICBE_VERSION; - retVal = pProgram->createProgramFromBinary(&binHeader, binSize); + retVal = pProgram->createProgramFromBinary(programTokens.storage.data(), programTokens.storage.size()); EXPECT_EQ(CL_SUCCESS, retVal); - EXPECT_TRUE(pProgram->processElfBinaryCalled); - EXPECT_TRUE(pProgram->rebuildProgramFromIrCalled); + EXPECT_EQ(nullptr, pProgram->unpackedDeviceBinary.get()); + EXPECT_EQ(0U, pProgram->unpackedDeviceBinarySize); + EXPECT_EQ(nullptr, pProgram->packedDeviceBinary); + EXPECT_EQ(0U, pProgram->packedDeviceBinarySize); } -TEST(RebuildProgramFromIrTests, givenBinaryProgramWhenKernelRebulildIsNotForcedThenRebuildProgramFromIrNotCalled) { +TEST(CreateProgramFromBinaryTests, givenBinaryProgramWhenKernelRebulildIsNotForcedThenDeviceBinaryIsUsed) { cl_int retVal = CL_INVALID_BINARY; - SProgramBinaryHeader binHeader; - memset(&binHeader, 0, sizeof(binHeader)); - binHeader.Magic = iOpenCL::MAGIC_CL; - binHeader.Version = iOpenCL::CURRENT_ICBE_VERSION; - binHeader.Device = platformDevices[0]->platform.eRenderCoreFamily; - binHeader.GPUPointerSizeInBytes = 8; - binHeader.NumberOfKernels = 0; - binHeader.SteppingId = 0; - binHeader.PatchListSize = 0; - size_t binSize = sizeof(SProgramBinaryHeader); + PatchTokensTestData::ValidEmptyProgram programTokens; - ExecutionEnvironment executionEnvironment; - std::unique_ptr pProgram(RebuildProgram::createFromGenBinary(executionEnvironment, nullptr, &binHeader, binSize, false, &retVal)); + auto clDevice = std::make_unique(MockDevice::createWithNewExecutionEnvironment(nullptr)); + std::unique_ptr pProgram(Program::createFromGenBinary(*clDevice->getExecutionEnvironment(), nullptr, programTokens.storage.data(), programTokens.storage.size(), false, &retVal)); + pProgram->pDevice = clDevice.get(); ASSERT_NE(nullptr, pProgram.get()); EXPECT_EQ(CL_SUCCESS, retVal); - binHeader.Version = iOpenCL::CURRENT_ICBE_VERSION; - retVal = pProgram->createProgramFromBinary(&binHeader, binSize); + retVal = pProgram->createProgramFromBinary(programTokens.storage.data(), programTokens.storage.size()); EXPECT_EQ(CL_SUCCESS, retVal); - EXPECT_TRUE(pProgram->processElfBinaryCalled); - EXPECT_FALSE(pProgram->rebuildProgramFromIrCalled); + EXPECT_NE(nullptr, reinterpret_cast(pProgram->unpackedDeviceBinary.get())); + EXPECT_EQ(programTokens.storage.size(), pProgram->unpackedDeviceBinarySize); + EXPECT_NE(nullptr, reinterpret_cast(pProgram->packedDeviceBinary.get())); + EXPECT_EQ(programTokens.storage.size(), pProgram->packedDeviceBinarySize); } struct SpecializationConstantProgramMock : public MockProgram {