mirror of
https://github.com/intel/compute-runtime.git
synced 2026-01-04 07:14:10 +08:00
moving ocloc to shared folder
Change-Id: Ic739cf747f7e6fae2c0cd57f0bc1aa0899d3aa53
This commit is contained in:
8
shared/offline_compiler/CMakeLists.txt
Normal file
8
shared/offline_compiler/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright (C) 2017-2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
|
||||
add_subdirectory(source)
|
||||
set(CLOC_LIB_SRCS_LIB ${CLOC_LIB_SRCS_LIB} PARENT_SCOPE)
|
||||
220
shared/offline_compiler/source/CMakeLists.txt
Normal file
220
shared/offline_compiler/source/CMakeLists.txt
Normal file
@@ -0,0 +1,220 @@
|
||||
#
|
||||
# Copyright (C) 2018-2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
|
||||
project(ocloc_lib)
|
||||
|
||||
set(CLOC_LIB_SRCS_LIB
|
||||
${NEO_CORE_DIRECTORY}/device_binary_format/ar/ar.h
|
||||
${NEO_CORE_DIRECTORY}/device_binary_format/ar/ar_decoder.h
|
||||
${NEO_CORE_DIRECTORY}/device_binary_format/ar/ar_decoder.cpp
|
||||
${NEO_CORE_DIRECTORY}/device_binary_format/ar/ar_encoder.h
|
||||
${NEO_CORE_DIRECTORY}/device_binary_format/ar/ar_encoder.cpp
|
||||
${NEO_CORE_DIRECTORY}/device_binary_format/elf/elf.h
|
||||
${NEO_CORE_DIRECTORY}/device_binary_format/elf/elf_decoder.h
|
||||
${NEO_CORE_DIRECTORY}/device_binary_format/elf/elf_decoder.cpp
|
||||
${NEO_CORE_DIRECTORY}/device_binary_format/elf/elf_encoder.h
|
||||
${NEO_CORE_DIRECTORY}/device_binary_format/elf/elf_encoder.cpp
|
||||
${NEO_CORE_DIRECTORY}/device_binary_format/elf/ocl_elf.h
|
||||
${NEO_CORE_DIRECTORY}/helpers/abort.cpp
|
||||
${NEO_CORE_DIRECTORY}/helpers/debug_helpers.cpp
|
||||
${NEO_CORE_DIRECTORY}/helpers/file_io.cpp
|
||||
${NEO_CORE_DIRECTORY}/os_interface/os_library.h
|
||||
${OCLOC_DIRECTORY}/source/decoder/binary_decoder.cpp
|
||||
${OCLOC_DIRECTORY}/source/decoder/binary_decoder.h
|
||||
${OCLOC_DIRECTORY}/source/decoder/binary_encoder.cpp
|
||||
${OCLOC_DIRECTORY}/source/decoder/binary_encoder.h
|
||||
${OCLOC_DIRECTORY}/source/decoder/helper.cpp
|
||||
${OCLOC_DIRECTORY}/source/decoder/helper.h
|
||||
${OCLOC_DIRECTORY}/source/decoder/iga_wrapper.h
|
||||
${OCLOC_DIRECTORY}/source/decoder/translate_platform_base.h
|
||||
${OCLOC_DIRECTORY}/source/ocloc_api.cpp
|
||||
${OCLOC_DIRECTORY}/source/ocloc_api.h
|
||||
${OCLOC_DIRECTORY}/source/ocloc_arg_helper.h
|
||||
${OCLOC_DIRECTORY}/source/ocloc_arg_helper.cpp
|
||||
${OCLOC_DIRECTORY}/source/ocloc_fatbinary.cpp
|
||||
${OCLOC_DIRECTORY}/source/ocloc_fatbinary.h
|
||||
${OCLOC_DIRECTORY}/source/offline_compiler_helper.cpp
|
||||
${OCLOC_DIRECTORY}/source/offline_compiler.cpp
|
||||
${OCLOC_DIRECTORY}/source/offline_compiler.h
|
||||
${OCLOC_DIRECTORY}/source/multi_command.cpp
|
||||
${OCLOC_DIRECTORY}/source/multi_command.h
|
||||
${OCLOC_DIRECTORY}/source/offline_compiler_options.cpp
|
||||
${OCLOC_DIRECTORY}/source/${BRANCH_DIR_SUFFIX}/extra_settings.cpp
|
||||
${NEO_CORE_DIRECTORY}/compiler_interface/compiler_options/compiler_options_base.cpp
|
||||
${NEO_CORE_DIRECTORY}/compiler_interface/create_main.cpp
|
||||
${NEO_CORE_DIRECTORY}/helpers/hw_info.cpp
|
||||
${NEO_SOURCE_DIR}/opencl/source/platform/extensions.cpp
|
||||
${NEO_SOURCE_DIR}/opencl/source/platform/extensions.h
|
||||
)
|
||||
|
||||
if(${IGA_HEADERS_AVAILABLE})
|
||||
set(CLOC_LIB_SRCS_LIB ${CLOC_LIB_SRCS_LIB}
|
||||
${OCLOC_DIRECTORY}/source/decoder/iga_wrapper.cpp
|
||||
${OCLOC_DIRECTORY}/source/decoder${BRANCH_DIR_SUFFIX}/translate_platform.cpp
|
||||
)
|
||||
else()
|
||||
set(CLOC_LIB_SRCS_LIB ${CLOC_LIB_SRCS_LIB}
|
||||
${OCLOC_DIRECTORY}/source/decoder/iga_stubs.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND CLOC_LIB_SRCS_LIB
|
||||
${NEO_CORE_DIRECTORY}/os_interface/windows/os_library_win.cpp
|
||||
${NEO_CORE_DIRECTORY}/os_interface/windows/os_library_win.h
|
||||
${NEO_SOURCE_DIR}/opencl/source/dll/windows/options_windows.cpp
|
||||
)
|
||||
else()
|
||||
list(APPEND CLOC_LIB_SRCS_LIB
|
||||
${NEO_CORE_DIRECTORY}/os_interface/linux/os_library_linux.cpp
|
||||
${NEO_CORE_DIRECTORY}/os_interface/linux/os_library_linux.h
|
||||
${NEO_SOURCE_DIR}/opencl/source/dll/linux/options_linux.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
string(REPLACE ";" "," ALL_SUPPORTED_PRODUCT_FAMILIES "${ALL_SUPPORTED_PRODUCT_FAMILY}")
|
||||
|
||||
set(CLOC_LIB_LIB_FLAGS_DEFINITIONS
|
||||
-DCIF_HEADERS_ONLY_BUILD
|
||||
-DALL_SUPPORTED_PRODUCT_FAMILIES=${ALL_SUPPORTED_PRODUCT_FAMILIES}
|
||||
)
|
||||
|
||||
set(RUNTIME_GENX_CPP_FILES
|
||||
hw_info
|
||||
)
|
||||
|
||||
macro(macro_for_each_platform)
|
||||
list(APPEND CLOC_LIB_SRCS_LIB ${NEO_SOURCE_DIR}/opencl/source/${GEN_TYPE_LOWER}/hw_info_${PLATFORM_IT_LOWER}.inl)
|
||||
endmacro()
|
||||
|
||||
macro(macro_for_each_gen)
|
||||
foreach(SRC_IT ${RUNTIME_GENX_CPP_FILES})
|
||||
set(SRC_FILE ${NEO_SOURCE_DIR}/opencl/source/${GEN_TYPE_LOWER}/${SRC_IT})
|
||||
if(EXISTS ${SRC_FILE}_${GEN_TYPE_LOWER}.cpp)
|
||||
list(APPEND CLOC_LIB_SRCS_LIB ${SRC_FILE}_${GEN_TYPE_LOWER}.cpp)
|
||||
endif()
|
||||
endforeach()
|
||||
apply_macro_for_each_platform()
|
||||
|
||||
list(APPEND CLOC_LIB_SRCS_LIB ${NEO_CORE_DIRECTORY}/${GEN_TYPE_LOWER}/enable_${GEN_TYPE_LOWER}.cpp)
|
||||
endmacro()
|
||||
|
||||
apply_macro_for_each_gen("SUPPORTED")
|
||||
|
||||
set(CLOC_LIB_SRCS
|
||||
${CLOC_LIB_SRCS_LIB}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
|
||||
)
|
||||
add_library(ocloc_lib SHARED ${CLOC_LIB_SRCS})
|
||||
|
||||
set(CLOC_SRCS
|
||||
${NEO_CORE_DIRECTORY}/os_interface/os_library.h
|
||||
${OCLOC_DIRECTORY}/source/ocloc_wrapper.h
|
||||
${OCLOC_DIRECTORY}/source/ocloc_wrapper.cpp
|
||||
${OCLOC_DIRECTORY}/source/utilities/get_path.h
|
||||
)
|
||||
if(WIN32)
|
||||
list(APPEND CLOC_SRCS
|
||||
${NEO_CORE_DIRECTORY}/os_interface/windows/os_library_win.cpp
|
||||
${NEO_CORE_DIRECTORY}/os_interface/windows/os_library_win.h
|
||||
${OCLOC_DIRECTORY}/source/utilities/windows/get_path.cpp
|
||||
|
||||
)
|
||||
else()
|
||||
list(APPEND CLOC_SRCS
|
||||
${NEO_CORE_DIRECTORY}/os_interface/linux/os_library_linux.cpp
|
||||
${NEO_CORE_DIRECTORY}/os_interface/linux/os_library_linux.h
|
||||
${OCLOC_DIRECTORY}/source/utilities/linux/get_path.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable(ocloc ${CLOC_SRCS} ${OCLOC_DIRECTORY}/source/main.cpp ${CLOC_LIB_SRCS})
|
||||
|
||||
add_subdirectories()
|
||||
|
||||
create_project_source_tree(ocloc_lib)
|
||||
|
||||
set(CLOC_LIB_INCLUDES
|
||||
${ENGINE_NODE_DIR}
|
||||
${IGC_OCL_ADAPTOR_DIR}
|
||||
${CIF_BASE_DIR}
|
||||
${NEO__GMM_INCLUDE_DIR}
|
||||
${KHRONOS_HEADERS_DIR}
|
||||
${NEO__IGC_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_include_directories(ocloc_lib BEFORE PRIVATE ${CLOC_LIB_INCLUDES})
|
||||
target_include_directories(ocloc_lib BEFORE PRIVATE ${IGA_INCLUDE_DIR})
|
||||
|
||||
target_compile_definitions(ocloc_lib PUBLIC ${CLOC_LIB_LIB_FLAGS_DEFINITIONS} ${SUPPORTED_GEN_FLAGS_DEFINITONS} DEFAULT_PLATFORM=${DEFAULT_SUPPORTED_PLATFORM}
|
||||
IGA_LIBRARY_NAME=${CMAKE_SHARED_LIBRARY_PREFIX}${IGA_LIBRARY_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
target_compile_definitions(ocloc_lib PRIVATE ${NEO__IGC_COMPILE_DEFINITIONS})
|
||||
|
||||
if(MSVC)
|
||||
target_link_libraries(ocloc_lib dbghelp)
|
||||
target_link_libraries(ocloc dbghelp)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
target_link_libraries(ocloc_lib dl pthread)
|
||||
target_link_libraries(ocloc dl pthread)
|
||||
endif()
|
||||
|
||||
set(CLOC_LIB_SRCS_LIB ${CLOC_LIB_SRCS_LIB} PARENT_SCOPE)
|
||||
|
||||
add_dependencies(ocloc ocloc_lib)
|
||||
|
||||
target_include_directories(ocloc BEFORE PRIVATE ${CLOC_LIB_INCLUDES})
|
||||
target_include_directories(ocloc BEFORE PRIVATE ${IGA_INCLUDE_DIR})
|
||||
|
||||
target_compile_definitions(ocloc PUBLIC ${CLOC_LIB_LIB_FLAGS_DEFINITIONS} ${SUPPORTED_GEN_FLAGS_DEFINITONS} DEFAULT_PLATFORM=${DEFAULT_SUPPORTED_PLATFORM}
|
||||
IGA_LIBRARY_NAME=${CMAKE_SHARED_LIBRARY_PREFIX}${IGA_LIBRARY_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX} MOCKABLE_VIRTUAL=)
|
||||
target_compile_definitions(ocloc PRIVATE ${NEO__IGC_COMPILE_DEFINITIONS})
|
||||
|
||||
set(OCLOC_LIB_NAME "ocloc")
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
set(OCLOC_BITNESS_SUFFIX 32)
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(OCLOC_BITNESS_SUFFIX 64)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
install(FILES $<TARGET_FILE:ocloc_lib>
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/intel-opencl
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
|
||||
install(FILES $<TARGET_FILE:ocloc>
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||
COMPONENT ocloc)
|
||||
set_property(GLOBAL APPEND PROPERTY NEO_COMPONENTS_LIST "ocloc")
|
||||
set_target_properties(ocloc_lib PROPERTIES OUTPUT_NAME ${OCLOC_LIB_NAME})
|
||||
add_definitions(-DOCLOC_LIB_NAME="lib${OCLOC_LIB_NAME}.so")
|
||||
else()
|
||||
set_target_properties(ocloc_lib PROPERTIES OUTPUT_NAME "${OCLOC_LIB_NAME}${OCLOC_BITNESS_SUFFIX}")
|
||||
add_definitions(-DOCLOC_LIB_NAME="${OCLOC_LIB_NAME}${OCLOC_BITNESS_SUFFIX}.dll")
|
||||
endif()
|
||||
|
||||
create_project_source_tree(ocloc)
|
||||
set_target_properties(ocloc PROPERTIES FOLDER "offline_compiler")
|
||||
set_target_properties(ocloc_lib PROPERTIES FOLDER "offline_compiler")
|
||||
|
||||
|
||||
add_custom_target(copy_compiler_files DEPENDS ${NEO__IGC_TARGETS})
|
||||
set_target_properties(copy_compiler_files PROPERTIES FOLDER "opencl runtime")
|
||||
|
||||
if(WIN32)
|
||||
foreach(TARGET_tmp ${NEO__IGC_TARGETS})
|
||||
add_custom_command(
|
||||
TARGET copy_compiler_files
|
||||
PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:ocloc_lib>
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${TARGET_tmp}> $<TARGET_FILE_DIR:ocloc_lib>
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:ocloc>
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${TARGET_tmp}> $<TARGET_FILE_DIR:ocloc>
|
||||
)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
128
shared/offline_compiler/source/api.cpp
Normal file
128
shared/offline_compiler/source/api.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ocloc_api.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void printHelp() {
|
||||
printf(R"===(ocloc is a tool for managing Intel OpenCL GPU device binary format.
|
||||
It can be used for generation (as part of 'compile' command) as well as
|
||||
manipulation (decoding/modifying - as part of 'disasm'/'asm' commands) of such
|
||||
binary files.
|
||||
Intel OpenCL GPU device binary is a format used by Intel OpenCL GPU runtime
|
||||
(aka NEO). Intel OpenCL GPU runtime will return this binary format when queried
|
||||
using clGetProgramInfo(..., CL_PROGRAM_BINARIES, ...). It will also honor
|
||||
this format as input to clCreateProgramWithBinary function call.
|
||||
ocloc does not require Intel GPU device to be present in the system nor does it
|
||||
depend on Intel OpenCL GPU runtime driver to be installed. It does however rely
|
||||
on the same set of compilers (IGC, common_clang) as the runtime driver.
|
||||
|
||||
Usage: ocloc [--help] <command> [<command_args>]
|
||||
Available commands are listed below.
|
||||
Use 'ocloc <command> --help' to get help about specific command.
|
||||
|
||||
Commands:
|
||||
compile Compiles input to Intel OpenCL GPU device binary.
|
||||
disasm Disassembles Intel OpenCL GPU device binary.
|
||||
asm Assembles Intel OpenCL GPU device binary.
|
||||
multi Compiles multiple files using a config file.
|
||||
|
||||
Default command (when none provided) is 'compile'.
|
||||
|
||||
Examples:
|
||||
Compile file to Intel OpenCL GPU device binary (out = source_file_Gen9core.bin)
|
||||
ocloc -file source_file.cl -device skl
|
||||
|
||||
Disassemble Intel OpenCL GPU device binary
|
||||
ocloc disasm -file source_file_Gen9core.bin
|
||||
|
||||
Assemble to Intel OpenCL GPU device binary (after above disasm)
|
||||
ocloc asm -out reassembled.bin
|
||||
)===");
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int oclocInvoke(unsigned int numArgs, const char *argv[],
|
||||
const uint32_t numSources, const uint8_t **dataSources, const uint64_t *lenSources, const char **nameSources,
|
||||
const uint32_t numInputHeaders, const uint8_t **dataInputHeaders, const uint64_t *lenInputHeaders, const char **nameInputHeaders,
|
||||
uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs) {
|
||||
auto helper = std::make_unique<OclocArgHelper>(
|
||||
numSources, dataSources, lenSources, nameSources,
|
||||
numInputHeaders, dataInputHeaders, lenInputHeaders, nameInputHeaders,
|
||||
numOutputs, dataOutputs, lenOutputs, nameOutputs);
|
||||
std::vector<std::string> allArgs;
|
||||
if (numArgs > 1) {
|
||||
allArgs.assign(argv, argv + numArgs);
|
||||
}
|
||||
|
||||
try {
|
||||
if (numArgs == 1 || (numArgs > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))) {
|
||||
printHelp();
|
||||
} else if (numArgs > 1 && !strcmp(argv[1], "disasm")) {
|
||||
BinaryDecoder disasm(std::move(helper));
|
||||
int retVal = disasm.validateInput(allArgs);
|
||||
if (retVal == 0) {
|
||||
return disasm.decode();
|
||||
} else {
|
||||
return retVal;
|
||||
}
|
||||
} else if (numArgs > 1 && !strcmp(argv[1], "asm")) {
|
||||
BinaryEncoder assembler(std::move(helper));
|
||||
int retVal = assembler.validateInput(allArgs);
|
||||
if (retVal == 0) {
|
||||
return assembler.encode();
|
||||
} else {
|
||||
return retVal;
|
||||
}
|
||||
} else if (numArgs > 1 && (!strcmp(argv[1], "multi") || !strcmp(argv[1], "-multi"))) {
|
||||
int retValue = CL_SUCCESS;
|
||||
auto pMulti = std::unique_ptr<MultiCommand>(MultiCommand::create(allArgs, retValue));
|
||||
return retValue;
|
||||
} else {
|
||||
int retVal = CL_SUCCESS;
|
||||
std::vector<std::string> allArgs;
|
||||
if (numArgs > 1) {
|
||||
allArgs.assign(argv, argv + numArgs);
|
||||
}
|
||||
|
||||
OfflineCompiler *pCompiler = OfflineCompiler::create(numArgs, allArgs, true, retVal, std::move(helper));
|
||||
|
||||
if (retVal == CL_SUCCESS) {
|
||||
retVal = buildWithSafetyGuard(pCompiler);
|
||||
|
||||
std::string buildLog = pCompiler->getBuildLog();
|
||||
if (buildLog.empty() == false) {
|
||||
printf("%s\n", buildLog.c_str());
|
||||
}
|
||||
|
||||
if (retVal == CL_SUCCESS) {
|
||||
if (!pCompiler->isQuiet())
|
||||
printf("Build succeeded.\n");
|
||||
} else {
|
||||
printf("Build failed with error code: %d\n", retVal);
|
||||
}
|
||||
}
|
||||
delete pCompiler;
|
||||
return retVal;
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
printf("%s\n", e.what());
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
void oclocFreeOutput(uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs) {
|
||||
for (uint32_t i = 0; i < *numOutputs; i++) {
|
||||
delete[](*dataOutputs)[i];
|
||||
delete[](*nameOutputs)[i];
|
||||
}
|
||||
delete[](*dataOutputs);
|
||||
delete[](*lenOutputs);
|
||||
delete[](*nameOutputs);
|
||||
}
|
||||
}
|
||||
555
shared/offline_compiler/source/decoder/binary_decoder.cpp
Normal file
555
shared/offline_compiler/source/decoder/binary_decoder.cpp
Normal file
@@ -0,0 +1,555 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/decoder/binary_decoder.h"
|
||||
|
||||
#include "shared/offline_compiler/source/decoder/helper.h"
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
#include "shared/source/device_binary_format/elf/elf_decoder.h"
|
||||
#include "shared/source/device_binary_format/elf/ocl_elf.h"
|
||||
#include "shared/source/helpers/file_io.h"
|
||||
#include "shared/source/helpers/ptr_math.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#define MakeDirectory _mkdir
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#define MakeDirectory(dir) mkdir(dir, 0777)
|
||||
#endif
|
||||
|
||||
void BinaryDecoder::setMessagePrinter(const MessagePrinter &messagePrinter) {
|
||||
this->messagePrinter = messagePrinter;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T readUnaligned(const void *ptr) {
|
||||
T retVal = 0;
|
||||
const uint8_t *tmp1 = reinterpret_cast<const uint8_t *>(ptr);
|
||||
uint8_t *tmp2 = reinterpret_cast<uint8_t *>(&retVal);
|
||||
for (uint8_t i = 0; i < sizeof(T); ++i) {
|
||||
*(tmp2++) = *(tmp1++);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int BinaryDecoder::decode() {
|
||||
parseTokens();
|
||||
std::stringstream ptmFile;
|
||||
auto devBinPtr = getDevBinary();
|
||||
if (devBinPtr == nullptr) {
|
||||
messagePrinter.printf("Error! Device Binary section was not found.\n");
|
||||
exit(1);
|
||||
}
|
||||
return processBinary(devBinPtr, ptmFile);
|
||||
}
|
||||
|
||||
void BinaryDecoder::dumpField(const void *&binaryPtr, const PTField &field, std::ostream &ptmFile) {
|
||||
ptmFile << '\t' << static_cast<int>(field.size) << ' ';
|
||||
switch (field.size) {
|
||||
case 1: {
|
||||
auto val = readUnaligned<uint8_t>(binaryPtr);
|
||||
ptmFile << field.name << " " << +val << '\n';
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
auto val = readUnaligned<uint16_t>(binaryPtr);
|
||||
ptmFile << field.name << " " << val << '\n';
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
auto val = readUnaligned<uint32_t>(binaryPtr);
|
||||
ptmFile << field.name << " " << val << '\n';
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
auto val = readUnaligned<uint64_t>(binaryPtr);
|
||||
ptmFile << field.name << " " << val << '\n';
|
||||
break;
|
||||
}
|
||||
default:
|
||||
messagePrinter.printf("Error! Unknown size.\n");
|
||||
exit(1);
|
||||
}
|
||||
binaryPtr = ptrOffset(binaryPtr, field.size);
|
||||
}
|
||||
|
||||
const void *BinaryDecoder::getDevBinary() {
|
||||
binary = argHelper->readBinaryFile(binaryFile);
|
||||
const void *data = nullptr;
|
||||
std::string decoderErrors;
|
||||
std::string decoderWarnings;
|
||||
auto input = ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(binary.data()), binary.size());
|
||||
auto elf = NEO::Elf::decodeElf<NEO::Elf::EI_CLASS_64>(input, decoderErrors, decoderWarnings);
|
||||
for (const auto §ionHeader : elf.sectionHeaders) { //Finding right section
|
||||
auto sectionData = ArrayRef<const char>(reinterpret_cast<const char *>(sectionHeader.data.begin()), sectionHeader.data.size());
|
||||
switch (sectionHeader.header->type) {
|
||||
case NEO::Elf::SHT_OPENCL_LLVM_BINARY: {
|
||||
argHelper->saveOutput(pathToDump + "llvm.bin", sectionData.begin(), sectionData.size());
|
||||
break;
|
||||
}
|
||||
case NEO::Elf::SHT_OPENCL_SPIRV: {
|
||||
argHelper->saveOutput(pathToDump + "spirv.bin", sectionData.begin(), sectionData.size());
|
||||
break;
|
||||
}
|
||||
case NEO::Elf::SHT_OPENCL_OPTIONS: {
|
||||
argHelper->saveOutput(pathToDump + "build.bin", sectionData.begin(), sectionData.size());
|
||||
break;
|
||||
}
|
||||
case NEO::Elf::SHT_OPENCL_DEV_BINARY: {
|
||||
data = sectionData.begin();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t BinaryDecoder::getSize(const std::string &typeStr) {
|
||||
if (typeStr == "uint8_t") {
|
||||
return 1;
|
||||
} else if (typeStr == "uint16_t") {
|
||||
return 2;
|
||||
} else if (typeStr == "uint32_t") {
|
||||
return 4;
|
||||
} else if (typeStr == "uint64_t") {
|
||||
return 8;
|
||||
} else {
|
||||
messagePrinter.printf("Unhandled type : %s\n", typeStr.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> BinaryDecoder::loadPatchList() {
|
||||
if (argHelper->hasHeaders()) {
|
||||
return argHelper->headersToVectorOfStrings();
|
||||
} else {
|
||||
std::vector<std::string> patchList;
|
||||
if (pathToPatch.empty()) {
|
||||
messagePrinter.printf("Path to patch list not provided - using defaults, skipping patchokens as undefined.\n");
|
||||
patchList = {
|
||||
"struct SProgramBinaryHeader",
|
||||
"{",
|
||||
" uint32_t Magic;",
|
||||
" uint32_t Version;",
|
||||
" uint32_t Device;",
|
||||
" uint32_t GPUPointerSizeInBytes;",
|
||||
" uint32_t NumberOfKernels;",
|
||||
" uint32_t SteppingId;",
|
||||
" uint32_t PatchListSize;",
|
||||
"};",
|
||||
"",
|
||||
"struct SKernelBinaryHeader",
|
||||
"{",
|
||||
" uint32_t CheckSum;",
|
||||
" uint64_t ShaderHashCode;",
|
||||
" uint32_t KernelNameSize;",
|
||||
" uint32_t PatchListSize;",
|
||||
"};",
|
||||
"",
|
||||
"struct SKernelBinaryHeaderCommon :",
|
||||
" SKernelBinaryHeader",
|
||||
"{",
|
||||
" uint32_t KernelHeapSize;",
|
||||
" uint32_t GeneralStateHeapSize;",
|
||||
" uint32_t DynamicStateHeapSize;",
|
||||
" uint32_t SurfaceStateHeapSize;",
|
||||
" uint32_t KernelUnpaddedSize;",
|
||||
"};",
|
||||
"",
|
||||
"enum PATCH_TOKEN",
|
||||
"{",
|
||||
" PATCH_TOKEN_ALLOCATE_GLOBAL_MEMORY_SURFACE_PROGRAM_BINARY_INFO, // 41 @SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo@",
|
||||
" PATCH_TOKEN_ALLOCATE_CONSTANT_MEMORY_SURFACE_PROGRAM_BINARY_INFO, // 42 @SPatchAllocateConstantMemorySurfaceProgramBinaryInfo@",
|
||||
"};",
|
||||
"struct SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo :",
|
||||
" SPatchItemHeader",
|
||||
"{",
|
||||
" uint32_t Type;",
|
||||
" uint32_t GlobalBufferIndex;",
|
||||
" uint32_t InlineDataSize;",
|
||||
"};",
|
||||
"struct SPatchAllocateConstantMemorySurfaceProgramBinaryInfo :",
|
||||
" SPatchItemHeader",
|
||||
"{",
|
||||
" uint32_t ConstantBufferIndex;",
|
||||
" uint32_t InlineDataSize;",
|
||||
"};",
|
||||
|
||||
};
|
||||
} else {
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_list.h", true);
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_shared.h", true);
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_g7.h", true);
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_g8.h", true);
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_g9.h", true);
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_g10.h", true);
|
||||
}
|
||||
return patchList;
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryDecoder::parseTokens() {
|
||||
//Creating patchlist definitions
|
||||
auto patchList = loadPatchList();
|
||||
|
||||
size_t pos = findPos(patchList, "struct SProgramBinaryHeader");
|
||||
if (pos == patchList.size()) {
|
||||
messagePrinter.printf("While parsing patchtoken definitions: couldn't find SProgramBinaryHeader.");
|
||||
exit(1);
|
||||
}
|
||||
pos = findPos(patchList, "enum PATCH_TOKEN");
|
||||
if (pos == patchList.size()) {
|
||||
messagePrinter.printf("While parsing patchtoken definitions: couldn't find enum PATCH_TOKEN.");
|
||||
exit(1);
|
||||
}
|
||||
pos = findPos(patchList, "struct SKernelBinaryHeader");
|
||||
if (pos == patchList.size()) {
|
||||
messagePrinter.printf("While parsing patchtoken definitions: couldn't find SKernelBinaryHeader.");
|
||||
exit(1);
|
||||
}
|
||||
pos = findPos(patchList, "struct SKernelBinaryHeaderCommon :");
|
||||
if (pos == patchList.size()) {
|
||||
messagePrinter.printf("While parsing patchtoken definitions: couldn't find SKernelBinaryHeaderCommon.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Reading all Patch Tokens and according structs
|
||||
size_t patchTokenEnumPos = findPos(patchList, "enum PATCH_TOKEN");
|
||||
if (patchTokenEnumPos == patchList.size()) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (auto i = patchTokenEnumPos + 1; i < patchList.size(); ++i) {
|
||||
if (patchList[i].find("};") != std::string::npos) {
|
||||
break;
|
||||
} else if (patchList[i].find("PATCH_TOKEN") == std::string::npos) {
|
||||
continue;
|
||||
} else if (patchList[i].find("@") == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t patchTokenNoStartPos, patchTokenNoEndPos;
|
||||
patchTokenNoStartPos = patchList[i].find('/') + 3;
|
||||
patchTokenNoEndPos = patchList[i].find(' ', patchTokenNoStartPos);
|
||||
std::stringstream patchTokenNoStream(patchList[i].substr(patchTokenNoStartPos, patchTokenNoEndPos - patchTokenNoStartPos));
|
||||
int patchNo;
|
||||
patchTokenNoStream >> patchNo;
|
||||
|
||||
auto patchTokenPtr = std::make_unique<PatchToken>();
|
||||
size_t nameStartPos, nameEndPos;
|
||||
nameStartPos = patchList[i].find("PATCH_TOKEN");
|
||||
nameEndPos = patchList[i].find(',', nameStartPos);
|
||||
patchTokenPtr->name = patchList[i].substr(nameStartPos, nameEndPos - nameStartPos);
|
||||
|
||||
nameStartPos = patchList[i].find("@");
|
||||
nameEndPos = patchList[i].find('@', nameStartPos + 1);
|
||||
if (nameEndPos == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
std::string structName = "struct " + patchList[i].substr(nameStartPos + 1, nameEndPos - nameStartPos - 1) + " :";
|
||||
|
||||
size_t structPos = findPos(patchList, structName);
|
||||
if (structPos == patchList.size()) {
|
||||
continue;
|
||||
}
|
||||
patchTokenPtr->size = readStructFields(patchList, structPos + 1, patchTokenPtr->fields);
|
||||
patchTokens[static_cast<uint8_t>(patchNo)] = std::move(patchTokenPtr);
|
||||
}
|
||||
|
||||
//Finding and reading Program Binary Header
|
||||
size_t structPos = findPos(patchList, "struct SProgramBinaryHeader") + 1;
|
||||
programHeader.size = readStructFields(patchList, structPos, programHeader.fields);
|
||||
|
||||
//Finding and reading Kernel Binary Header
|
||||
structPos = findPos(patchList, "struct SKernelBinaryHeader") + 1;
|
||||
kernelHeader.size = readStructFields(patchList, structPos, kernelHeader.fields);
|
||||
|
||||
structPos = findPos(patchList, "struct SKernelBinaryHeaderCommon :") + 1;
|
||||
kernelHeader.size += readStructFields(patchList, structPos, kernelHeader.fields);
|
||||
}
|
||||
|
||||
void BinaryDecoder::printHelp() {
|
||||
messagePrinter.printf(R"===(Disassembles Intel OpenCL GPU device binary files.
|
||||
Output of such operation is a set of files that can be later used to
|
||||
reassemble back a valid Intel OpenCL GPU device binary (using ocloc 'asm'
|
||||
command). This set of files contains:
|
||||
Program-scope data :
|
||||
- spirv.bin (optional) - spirV representation of the program from which
|
||||
the input binary was generated
|
||||
- build.bin - build options that were used when generating the
|
||||
input binary
|
||||
- PTM.txt - 'patch tokens' describing program-scope and
|
||||
kernel-scope metadata about the input binary
|
||||
|
||||
Kernel-scope data (<kname> is replaced by corresponding kernel's name):
|
||||
- <kname>_DynamicStateHeap.bin - initial DynamicStateHeap (binary file)
|
||||
- <kname>_SurfaceStateHeap.bin - initial SurfaceStateHeap (binary file)
|
||||
- <kname>_KernelHeap.asm - list of instructions describing
|
||||
the kernel function (text file)
|
||||
|
||||
Usage: ocloc disasm -file <file> [-patch <patchtokens_dir>] [-dump <dump_dir>] [-device <device_type>] [-ignore_isa_padding]
|
||||
-file <file> Input file to be disassembled.
|
||||
This file should be an Intel OpenCL GPU device binary.
|
||||
|
||||
-patch <patchtokens_dir> Optional path to the directory containing
|
||||
patchtoken definitions (patchlist.h, etc.)
|
||||
as defined in intel-graphics-compiler (IGC) repo,
|
||||
IGC subdirectory :
|
||||
IGC/AdaptorOCL/ocl_igc_shared/executable_format
|
||||
By default (when patchtokens_dir is not provided)
|
||||
patchtokens won't be decoded.
|
||||
|
||||
-dump <dump_dir> Optional path for files representing decoded binary.
|
||||
Default is './dump'.
|
||||
|
||||
-device <device_type> Optional target device of input binary
|
||||
<device_type> can be: %s
|
||||
By default ocloc will pick base device within
|
||||
a generation - i.e. both skl and kbl will
|
||||
fallback to skl. If specific product (e.g. kbl)
|
||||
is needed, provide it as device_type.
|
||||
|
||||
-ignore_isa_padding Ignores Kernel Heap padding - Kernel Heap binary
|
||||
will be saved without padding.
|
||||
|
||||
--help Print this usage message.
|
||||
|
||||
Examples:
|
||||
Disassemble Intel OpenCL GPU device binary
|
||||
ocloc disasm -file source_file_Gen9core.bin
|
||||
)===",
|
||||
NEO::getDevicesTypes().c_str());
|
||||
}
|
||||
|
||||
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) {
|
||||
if (v.name == "NumberOfKernels") {
|
||||
numberOfKernels = readUnaligned<uint32_t>(ptr);
|
||||
} else if (v.name == "PatchListSize") {
|
||||
patchListSize = readUnaligned<uint32_t>(ptr);
|
||||
} else if (v.name == "Device") {
|
||||
device = readUnaligned<uint32_t>(ptr);
|
||||
}
|
||||
dumpField(ptr, v, ptmFile);
|
||||
}
|
||||
if (numberOfKernels == 0) {
|
||||
messagePrinter.printf("Warning! Number of Kernels is 0.\n");
|
||||
}
|
||||
|
||||
readPatchTokens(ptr, patchListSize, ptmFile);
|
||||
iga->setGfxCore(static_cast<GFXCORE_FAMILY>(device));
|
||||
|
||||
//Reading Kernels
|
||||
for (uint32_t i = 0; i < numberOfKernels; ++i) {
|
||||
ptmFile << "Kernel #" << i << '\n';
|
||||
processKernel(ptr, ptmFile);
|
||||
}
|
||||
|
||||
argHelper->saveOutput(pathToDump + "PTM.txt", ptmFile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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";
|
||||
for (const auto &v : kernelHeader.fields) {
|
||||
if (v.name == "PatchListSize")
|
||||
KernelPatchListSize = readUnaligned<uint32_t>(ptr);
|
||||
else if (v.name == "KernelNameSize")
|
||||
KernelNameSize = readUnaligned<uint32_t>(ptr);
|
||||
else if (v.name == "KernelHeapSize")
|
||||
KernelHeapSize = readUnaligned<uint32_t>(ptr);
|
||||
else if (v.name == "KernelUnpaddedSize")
|
||||
KernelHeapUnpaddedSize = readUnaligned<uint32_t>(ptr);
|
||||
else if (v.name == "GeneralStateHeapSize")
|
||||
GeneralStateHeapSize = readUnaligned<uint32_t>(ptr);
|
||||
else if (v.name == "DynamicStateHeapSize")
|
||||
DynamicStateHeapSize = readUnaligned<uint32_t>(ptr);
|
||||
else if (v.name == "SurfaceStateHeapSize")
|
||||
SurfaceStateHeapSize = readUnaligned<uint32_t>(ptr);
|
||||
|
||||
dumpField(ptr, v, ptmFile);
|
||||
}
|
||||
|
||||
if (KernelNameSize == 0) {
|
||||
messagePrinter.printf("Error! KernelNameSize was 0.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ptmFile << "\tKernelName ";
|
||||
std::string kernelName(static_cast<const char *>(ptr), 0, KernelNameSize);
|
||||
ptmFile << kernelName << '\n';
|
||||
ptr = ptrOffset(ptr, KernelNameSize);
|
||||
|
||||
std::string fileName = pathToDump + kernelName + "_KernelHeap";
|
||||
messagePrinter.printf("Trying to disassemble %s.krn\n", kernelName.c_str());
|
||||
std::string disassembledKernel;
|
||||
if (iga->tryDisassembleGenISA(ptr, KernelHeapUnpaddedSize, disassembledKernel)) {
|
||||
argHelper->saveOutput(fileName + ".asm", disassembledKernel.data(), disassembledKernel.size());
|
||||
} else {
|
||||
if (ignoreIsaPadding) {
|
||||
argHelper->saveOutput(fileName + ".dat", ptr, KernelHeapUnpaddedSize);
|
||||
} else {
|
||||
argHelper->saveOutput(fileName + ".dat", ptr, KernelHeapSize);
|
||||
}
|
||||
}
|
||||
ptr = ptrOffset(ptr, KernelHeapSize);
|
||||
|
||||
if (GeneralStateHeapSize != 0) {
|
||||
messagePrinter.printf("Warning! GeneralStateHeapSize wasn't 0.\n");
|
||||
fileName = pathToDump + kernelName + "_GeneralStateHeap.bin";
|
||||
argHelper->saveOutput(fileName, ptr, DynamicStateHeapSize);
|
||||
ptr = ptrOffset(ptr, GeneralStateHeapSize);
|
||||
}
|
||||
|
||||
fileName = pathToDump + kernelName + "_DynamicStateHeap.bin";
|
||||
argHelper->saveOutput(fileName, ptr, DynamicStateHeapSize);
|
||||
ptr = ptrOffset(ptr, DynamicStateHeapSize);
|
||||
|
||||
fileName = pathToDump + kernelName + "_SurfaceStateHeap.bin";
|
||||
argHelper->saveOutput(fileName, ptr, SurfaceStateHeapSize);
|
||||
ptr = ptrOffset(ptr, SurfaceStateHeapSize);
|
||||
|
||||
if (KernelPatchListSize == 0) {
|
||||
messagePrinter.printf("Warning! Kernel's patch list size was 0.\n");
|
||||
}
|
||||
readPatchTokens(ptr, KernelPatchListSize, ptmFile);
|
||||
}
|
||||
|
||||
void BinaryDecoder::readPatchTokens(const void *&patchListPtr, uint32_t patchListSize, std::ostream &ptmFile) {
|
||||
auto endPatchListPtr = ptrOffset(patchListPtr, patchListSize);
|
||||
while (patchListPtr != endPatchListPtr) {
|
||||
auto patchTokenPtr = patchListPtr;
|
||||
|
||||
auto token = readUnaligned<uint32_t>(patchTokenPtr);
|
||||
patchTokenPtr = ptrOffset(patchTokenPtr, sizeof(uint32_t));
|
||||
|
||||
auto Size = readUnaligned<uint32_t>(patchTokenPtr);
|
||||
patchTokenPtr = ptrOffset(patchTokenPtr, sizeof(uint32_t));
|
||||
|
||||
if (patchTokens.count(token) > 0) {
|
||||
ptmFile << patchTokens[(token)]->name << ":\n";
|
||||
} else {
|
||||
ptmFile << "Unidentified PatchToken:\n";
|
||||
}
|
||||
|
||||
ptmFile << '\t' << "4 Token " << token << '\n';
|
||||
ptmFile << '\t' << "4 Size " << Size << '\n';
|
||||
|
||||
if (patchTokens.count(token) > 0) {
|
||||
uint32_t fieldsSize = 0;
|
||||
for (const auto &v : patchTokens[(token)]->fields) {
|
||||
if ((fieldsSize += static_cast<uint32_t>(v.size)) > (Size - sizeof(uint32_t) * 2)) {
|
||||
break;
|
||||
}
|
||||
if (v.name == "InlineDataSize") { // Because InlineData field value is not added to PT size
|
||||
auto inlineDataSize = readUnaligned<uint32_t>(patchTokenPtr);
|
||||
patchListPtr = ptrOffset(patchListPtr, inlineDataSize);
|
||||
}
|
||||
dumpField(patchTokenPtr, v, ptmFile);
|
||||
}
|
||||
}
|
||||
patchListPtr = ptrOffset(patchListPtr, Size);
|
||||
|
||||
if (patchListPtr > patchTokenPtr) {
|
||||
ptmFile << "\tHex";
|
||||
const uint8_t *byte = reinterpret_cast<const uint8_t *>(patchTokenPtr);
|
||||
while (ptrDiff(patchListPtr, patchTokenPtr) != 0) {
|
||||
ptmFile << ' ' << std::hex << +*(byte++);
|
||||
patchTokenPtr = ptrOffset(patchTokenPtr, sizeof(uint8_t));
|
||||
}
|
||||
ptmFile << std::dec << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t BinaryDecoder::readStructFields(const std::vector<std::string> &patchList,
|
||||
const size_t &structPos, std::vector<PTField> &fields) {
|
||||
std::string typeStr, fieldName;
|
||||
uint8_t size;
|
||||
uint32_t fullSize = 0;
|
||||
size_t f1, f2;
|
||||
|
||||
for (auto i = structPos; i < patchList.size(); ++i) {
|
||||
if (patchList[i].find("};") != std::string::npos) {
|
||||
break;
|
||||
} else if (patchList[i].find("int") == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
f1 = patchList[i].find_first_not_of(' ');
|
||||
f2 = patchList[i].find(' ', f1 + 1);
|
||||
|
||||
typeStr = patchList[i].substr(f1, f2 - f1);
|
||||
size = getSize(typeStr);
|
||||
|
||||
f1 = patchList[i].find_first_not_of(' ', f2);
|
||||
f2 = patchList[i].find(';');
|
||||
fieldName = patchList[i].substr(f1, f2 - f1);
|
||||
fields.push_back(PTField{size, fieldName});
|
||||
fullSize += size;
|
||||
}
|
||||
return fullSize;
|
||||
}
|
||||
|
||||
int BinaryDecoder::validateInput(const std::vector<std::string> &args) {
|
||||
if (args[args.size() - 1] == "-help") {
|
||||
printHelp();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t argIndex = 2; argIndex < args.size(); ++argIndex) {
|
||||
const auto &currArg = args[argIndex];
|
||||
const bool hasMoreArgs = (argIndex + 1 < args.size());
|
||||
if ("-file" == currArg && hasMoreArgs) {
|
||||
binaryFile = args[++argIndex];
|
||||
} else if ("-device" == currArg && hasMoreArgs) {
|
||||
iga->setProductFamily(getProductFamilyFromDeviceName(args[++argIndex]));
|
||||
} else if ("-patch" == currArg && hasMoreArgs) {
|
||||
pathToPatch = args[++argIndex];
|
||||
addSlash(pathToPatch);
|
||||
} else if ("-dump" == currArg && hasMoreArgs) {
|
||||
pathToDump = args[++argIndex];
|
||||
addSlash(pathToDump);
|
||||
} else if ("-ignore_isa_padding" == currArg) {
|
||||
ignoreIsaPadding = true;
|
||||
} else if ("-q" == currArg) {
|
||||
this->messagePrinter = MessagePrinter{true};
|
||||
iga->setMessagePrinter(this->messagePrinter);
|
||||
} else {
|
||||
messagePrinter.printf("Unknown argument %s\n", currArg.c_str());
|
||||
printHelp();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (binaryFile.find(".bin") == std::string::npos) {
|
||||
messagePrinter.printf(".bin extension is expected for binary file.\n");
|
||||
printHelp();
|
||||
return -1;
|
||||
}
|
||||
if (false == iga->isKnownPlatform()) {
|
||||
messagePrinter.printf("Warning : missing or invalid -device parameter - results may be inacurate\n");
|
||||
}
|
||||
if (!argHelper->outputEnabled()) {
|
||||
if (pathToDump.empty()) {
|
||||
messagePrinter.printf("Warning : Path to dump folder not specificed - using ./dump as default.\n");
|
||||
pathToDump = std::string("dump/");
|
||||
}
|
||||
MakeDirectory(pathToDump.c_str());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
71
shared/offline_compiler/source/decoder/binary_decoder.h
Normal file
71
shared/offline_compiler/source/decoder/binary_decoder.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "shared/offline_compiler/source/decoder/helper.h"
|
||||
#include "shared/offline_compiler/source/decoder/iga_wrapper.h"
|
||||
#include "shared/offline_compiler/source/ocloc_arg_helper.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct PTField {
|
||||
uint8_t size = 0U;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct BinaryHeader {
|
||||
std::vector<PTField> fields;
|
||||
uint32_t size = 0U;
|
||||
};
|
||||
struct PatchToken : BinaryHeader {
|
||||
std::string name;
|
||||
};
|
||||
|
||||
using PTMap = std::unordered_map<uint8_t, std::unique_ptr<PatchToken>>;
|
||||
|
||||
class BinaryDecoder {
|
||||
public:
|
||||
BinaryDecoder() : iga(new IgaWrapper) {
|
||||
iga->setMessagePrinter(messagePrinter);
|
||||
if (nullptr == argHelper) {
|
||||
argHelper = std::make_unique<OclocArgHelper>();
|
||||
}
|
||||
}
|
||||
BinaryDecoder(const std::string &file, const std::string &patch, const std::string &dump)
|
||||
: binaryFile(file), pathToPatch(patch), pathToDump(dump){};
|
||||
BinaryDecoder(std::unique_ptr<OclocArgHelper> helper) : argHelper(std::move(helper)), iga(new IgaWrapper) {
|
||||
iga->setMessagePrinter(messagePrinter);
|
||||
};
|
||||
int decode();
|
||||
int validateInput(const std::vector<std::string> &args);
|
||||
void setMessagePrinter(const MessagePrinter &messagePrinter);
|
||||
|
||||
protected:
|
||||
std::unique_ptr<OclocArgHelper> argHelper = nullptr;
|
||||
bool ignoreIsaPadding = false;
|
||||
BinaryHeader programHeader, kernelHeader;
|
||||
std::vector<char> binary;
|
||||
std::unique_ptr<IgaWrapper> iga;
|
||||
PTMap patchTokens;
|
||||
std::string binaryFile, pathToPatch, pathToDump;
|
||||
MessagePrinter messagePrinter;
|
||||
|
||||
void dumpField(const void *&binaryPtr, const PTField &field, std::ostream &ptmFile);
|
||||
uint8_t getSize(const std::string &typeStr);
|
||||
const void *getDevBinary();
|
||||
std::vector<std::string> loadPatchList();
|
||||
void parseTokens();
|
||||
void printHelp();
|
||||
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<std::string> &patchList,
|
||||
const size_t &structPos, std::vector<PTField> &fields);
|
||||
};
|
||||
409
shared/offline_compiler/source/decoder/binary_encoder.cpp
Normal file
409
shared/offline_compiler/source/decoder/binary_encoder.cpp
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "binary_encoder.h"
|
||||
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
#include "shared/source/device_binary_format/elf/elf_encoder.h"
|
||||
#include "shared/source/device_binary_format/elf/ocl_elf.h"
|
||||
#include "shared/source/helpers/aligned_memory.h"
|
||||
#include "shared/source/helpers/file_io.h"
|
||||
#include "shared/source/helpers/hash.h"
|
||||
|
||||
#include "CL/cl.h"
|
||||
#include "helper.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
void BinaryEncoder::setMessagePrinter(const MessagePrinter &messagePrinter) {
|
||||
this->messagePrinter = messagePrinter;
|
||||
}
|
||||
|
||||
void BinaryEncoder::calculatePatchListSizes(std::vector<std::string> &ptmFile) {
|
||||
size_t patchListPos = 0;
|
||||
for (size_t i = 0; i < ptmFile.size(); ++i) {
|
||||
if (ptmFile[i].find("PatchListSize") != std::string::npos) {
|
||||
patchListPos = i;
|
||||
} else if (ptmFile[i].find("PATCH_TOKEN") != std::string::npos) {
|
||||
uint32_t calcSize = 0;
|
||||
i++;
|
||||
while (i < ptmFile.size() && ptmFile[i].find("Kernel #") == std::string::npos) {
|
||||
if (ptmFile[i].find(':') == std::string::npos) {
|
||||
if (ptmFile[i].find("Hex") != std::string::npos) {
|
||||
calcSize += static_cast<uint32_t>(std::count(ptmFile[i].begin(), ptmFile[i].end(), ' '));
|
||||
} else {
|
||||
calcSize += std::atoi(&ptmFile[i][1]);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
uint32_t size = static_cast<uint32_t>(std::stoul(ptmFile[patchListPos].substr(ptmFile[patchListPos].find_last_of(' ') + 1)));
|
||||
if (size != calcSize) {
|
||||
messagePrinter.printf("Warning! Calculated PatchListSize ( %u ) differs from file ( %u ) - changing it. Line %d\n", calcSize, size, static_cast<int>(patchListPos + 1));
|
||||
ptmFile[patchListPos] = ptmFile[patchListPos].substr(0, ptmFile[patchListPos].find_last_of(' ') + 1);
|
||||
ptmFile[patchListPos] += std::to_string(calcSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BinaryEncoder::copyBinaryToBinary(const std::string &srcFileName, std::ostream &outBinary, uint32_t *binaryLength) {
|
||||
auto binary = argHelper->readBinaryFile(srcFileName);
|
||||
auto length = binary.size();
|
||||
outBinary.write(binary.data(), length);
|
||||
|
||||
if (binaryLength) {
|
||||
*binaryLength = static_cast<uint32_t>(length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int BinaryEncoder::createElf(std::stringstream &deviceBinary) {
|
||||
NEO::Elf::ElfEncoder<NEO::Elf::EI_CLASS_64> ElfEncoder;
|
||||
ElfEncoder.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE;
|
||||
//Build Options
|
||||
if (argHelper->fileExists(pathToDump + "build.bin")) {
|
||||
auto binary = argHelper->readBinaryFile(pathToDump + "build.bin");
|
||||
ElfEncoder.appendSection(NEO::Elf::SHT_OPENCL_OPTIONS, "BuildOptions",
|
||||
ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(binary.data()), binary.size()));
|
||||
} else {
|
||||
messagePrinter.printf("Warning! Missing build section.\n");
|
||||
}
|
||||
//LLVM or SPIRV
|
||||
if (argHelper->fileExists(pathToDump + "llvm.bin")) {
|
||||
auto binary = argHelper->readBinaryFile(pathToDump + "llvm.bin");
|
||||
ElfEncoder.appendSection(NEO::Elf::SHT_OPENCL_LLVM_BINARY, "Intel(R) OpenCL LLVM Object",
|
||||
ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(binary.data()), binary.size()));
|
||||
} else if (argHelper->fileExists(pathToDump + "spirv.bin")) {
|
||||
auto binary = argHelper->readBinaryFile(pathToDump + "spirv.bin");
|
||||
ElfEncoder.appendSection(NEO::Elf::SHT_OPENCL_SPIRV, "SPIRV Object",
|
||||
ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(binary.data()), binary.size()));
|
||||
} else {
|
||||
messagePrinter.printf("Warning! Missing llvm/spirv section.\n");
|
||||
}
|
||||
|
||||
//Device Binary
|
||||
auto deviceBinaryStr = deviceBinary.str();
|
||||
std::vector<char> binary(deviceBinaryStr.begin(), deviceBinaryStr.end());
|
||||
ElfEncoder.appendSection(NEO::Elf::SHT_OPENCL_DEV_BINARY, "Intel(R) OpenCL Device Binary",
|
||||
ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(binary.data()), binary.size()));
|
||||
|
||||
//Resolve Elf Binary
|
||||
auto elfBinary = ElfEncoder.encode();
|
||||
argHelper->saveOutput(elfName, elfBinary.data(), elfBinary.size());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BinaryEncoder::printHelp() {
|
||||
messagePrinter.printf(R"===(Assembles Intel OpenCL GPU device binary from input files.
|
||||
It's expected that input files were previously generated by 'ocloc disasm'
|
||||
command or are compatible with 'ocloc disasm' output (especially in terms of
|
||||
file naming scheme). See 'ocloc disasm --help' for additional info.
|
||||
|
||||
Usage: ocloc asm -out <out_file> [-dump <dump_dir>] [-device <device_type>] [-ignore_isa_padding]
|
||||
-out <out_file> Filename for newly assembled binary.
|
||||
|
||||
-dump <dumping_dir> Path to the input directory containing
|
||||
disassembled binary (as disassembled
|
||||
by ocloc's disasm command).
|
||||
Default is './dump'.
|
||||
|
||||
-device <device_type> Optional target device of output binary
|
||||
<device_type> can be: %s
|
||||
By default ocloc will pick base device within
|
||||
a generation - i.e. both skl and kbl will
|
||||
fallback to skl. If specific product (e.g. kbl)
|
||||
is needed, provide it as device_type.
|
||||
|
||||
-ignore_isa_padding Ignores Kernel Heap padding - padding will not
|
||||
be added to Kernel Heap binary.
|
||||
|
||||
--help Print this usage message.
|
||||
|
||||
Examples:
|
||||
Assemble to Intel OpenCL GPU device binary
|
||||
ocloc asm -out reassembled.bin
|
||||
)===",
|
||||
NEO::getDevicesTypes().c_str());
|
||||
}
|
||||
|
||||
int BinaryEncoder::encode() {
|
||||
std::vector<std::string> ptmFile;
|
||||
if (!argHelper->fileExists(pathToDump + "PTM.txt")) {
|
||||
messagePrinter.printf("Error! Couldn't find PTM.txt");
|
||||
return -1;
|
||||
}
|
||||
argHelper->readFileToVectorOfStrings(pathToDump + "PTM.txt", ptmFile);
|
||||
|
||||
calculatePatchListSizes(ptmFile);
|
||||
|
||||
std::stringstream deviceBinary; //(pathToDump + "device_binary.bin", std::ios::binary);
|
||||
int retVal = processBinary(ptmFile, deviceBinary);
|
||||
argHelper->saveOutput(pathToDump + "device_binary.bin", deviceBinary.str().c_str(), deviceBinary.str().length());
|
||||
if (retVal != CL_SUCCESS) {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
retVal = createElf(deviceBinary);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int BinaryEncoder::processBinary(const std::vector<std::string> &ptmFileLines, std::ostream &deviceBinary) {
|
||||
if (false == iga->isKnownPlatform()) {
|
||||
auto deviceMarker = findPos(ptmFileLines, "Device");
|
||||
if (deviceMarker != ptmFileLines.size()) {
|
||||
std::stringstream ss(ptmFileLines[deviceMarker]);
|
||||
ss.ignore(32, ' ');
|
||||
ss.ignore(32, ' ');
|
||||
uint32_t gfxCore = 0;
|
||||
ss >> gfxCore;
|
||||
iga->setGfxCore(static_cast<GFXCORE_FAMILY>(gfxCore));
|
||||
}
|
||||
}
|
||||
size_t i = 0;
|
||||
while (i < ptmFileLines.size()) {
|
||||
if (ptmFileLines[i].find("Kernel #") != std::string::npos) {
|
||||
if (processKernel(++i, ptmFileLines, deviceBinary)) {
|
||||
messagePrinter.printf("Warning while processing kernel!\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (writeDeviceBinary(ptmFileLines[i++], deviceBinary)) {
|
||||
messagePrinter.printf("Error while writing to binary!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BinaryEncoder::addPadding(std::ostream &out, size_t numBytes) {
|
||||
for (size_t i = 0; i < numBytes; ++i) {
|
||||
const char nullByte = 0;
|
||||
out.write(&nullByte, 1U);
|
||||
}
|
||||
}
|
||||
|
||||
int BinaryEncoder::processKernel(size_t &line, const std::vector<std::string> &ptmFileLines, std::ostream &deviceBinary) {
|
||||
auto kernelInfoBeginMarker = line;
|
||||
auto kernelInfoEndMarker = ptmFileLines.size();
|
||||
auto kernelNameMarker = ptmFileLines.size();
|
||||
auto kernelPatchtokensMarker = ptmFileLines.size();
|
||||
std::stringstream kernelBlob;
|
||||
|
||||
// Normally these are added by the compiler, need to take or of them when reassembling
|
||||
constexpr size_t isaPaddingSizeInBytes = 128;
|
||||
constexpr uint32_t kernelHeapAlignmentInBytes = 64;
|
||||
|
||||
uint32_t kernelNameSizeInBinary = 0;
|
||||
std::string kernelName;
|
||||
|
||||
// Scan PTM lines for kernel info
|
||||
while (line < ptmFileLines.size()) {
|
||||
if (ptmFileLines[line].find("KernelName ") != std::string::npos) {
|
||||
kernelName = std::string(ptmFileLines[line], ptmFileLines[line].find(' ') + 1);
|
||||
kernelNameMarker = line;
|
||||
kernelPatchtokensMarker = kernelNameMarker + 1; // patchtokens come after name
|
||||
} else if (ptmFileLines[line].find("KernelNameSize") != std::string::npos) {
|
||||
std::stringstream ss(ptmFileLines[line]);
|
||||
ss.ignore(32, ' ');
|
||||
ss.ignore(32, ' ');
|
||||
ss >> kernelNameSizeInBinary;
|
||||
} else if (ptmFileLines[line].find("Kernel #") != std::string::npos) {
|
||||
kernelInfoEndMarker = line;
|
||||
break;
|
||||
}
|
||||
++line;
|
||||
}
|
||||
|
||||
// Write KernelName and padding
|
||||
kernelBlob.write(kernelName.c_str(), kernelName.size());
|
||||
addPadding(kernelBlob, kernelNameSizeInBinary - kernelName.size());
|
||||
|
||||
// Write KernelHeap and padding
|
||||
uint32_t kernelHeapSizeUnpadded = 0U;
|
||||
bool heapsCopiedSuccesfully = true;
|
||||
|
||||
// Use .asm if available, fallback to .dat
|
||||
if (argHelper->fileExists(pathToDump + kernelName + "_KernelHeap.asm")) {
|
||||
auto kernelAsAsm = argHelper->readBinaryFile(pathToDump + kernelName + "_KernelHeap.asm");
|
||||
std::string kernelAsBinary;
|
||||
messagePrinter.printf("Trying to assemble %s.asm\n", kernelName.c_str());
|
||||
if (false == iga->tryAssembleGenISA(std::string(kernelAsAsm.begin(), kernelAsAsm.end()), kernelAsBinary)) {
|
||||
messagePrinter.printf("Error : Could not assemble : %s\n", kernelName.c_str());
|
||||
return -1;
|
||||
}
|
||||
kernelHeapSizeUnpadded = static_cast<uint32_t>(kernelAsBinary.size());
|
||||
kernelBlob.write(kernelAsBinary.data(), kernelAsBinary.size());
|
||||
} else {
|
||||
heapsCopiedSuccesfully = copyBinaryToBinary(pathToDump + kernelName + "_KernelHeap.dat", kernelBlob, &kernelHeapSizeUnpadded);
|
||||
}
|
||||
|
||||
uint32_t kernelHeapSize = 0U;
|
||||
// Adding padding and alignment
|
||||
if (ignoreIsaPadding) {
|
||||
kernelHeapSize = kernelHeapSizeUnpadded;
|
||||
} else {
|
||||
addPadding(kernelBlob, isaPaddingSizeInBytes);
|
||||
const uint32_t kernelHeapPaddedSize = kernelHeapSizeUnpadded + isaPaddingSizeInBytes;
|
||||
kernelHeapSize = alignUp(kernelHeapPaddedSize, kernelHeapAlignmentInBytes);
|
||||
addPadding(kernelBlob, kernelHeapSize - kernelHeapPaddedSize);
|
||||
}
|
||||
|
||||
// Write GeneralStateHeap, DynamicStateHeap, SurfaceStateHeap
|
||||
if (argHelper->fileExists(pathToDump + kernelName + "_GeneralStateHeap.bin")) {
|
||||
heapsCopiedSuccesfully = heapsCopiedSuccesfully && copyBinaryToBinary(pathToDump + kernelName + "_GeneralStateHeap.bin", kernelBlob);
|
||||
}
|
||||
heapsCopiedSuccesfully = heapsCopiedSuccesfully && copyBinaryToBinary(pathToDump + kernelName + "_DynamicStateHeap.bin", kernelBlob);
|
||||
heapsCopiedSuccesfully = heapsCopiedSuccesfully && copyBinaryToBinary(pathToDump + kernelName + "_SurfaceStateHeap.bin", kernelBlob);
|
||||
if (false == heapsCopiedSuccesfully) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Write kernel patchtokens
|
||||
for (size_t i = kernelPatchtokensMarker; i < kernelInfoEndMarker; ++i) {
|
||||
if (writeDeviceBinary(ptmFileLines[i], kernelBlob)) {
|
||||
messagePrinter.printf("Error while writing to binary.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
auto kernelBlobData = kernelBlob.str();
|
||||
uint64_t hashValue = NEO::Hash::hash(reinterpret_cast<const char *>(kernelBlobData.data()), kernelBlobData.size());
|
||||
uint32_t calcCheckSum = hashValue & 0xFFFFFFFF;
|
||||
|
||||
// Add kernel header
|
||||
for (size_t i = kernelInfoBeginMarker; i < kernelNameMarker; ++i) {
|
||||
if (ptmFileLines[i].find("CheckSum") != std::string::npos) {
|
||||
static_assert(std::is_same<decltype(calcCheckSum), uint32_t>::value, "");
|
||||
deviceBinary.write(reinterpret_cast<char *>(&calcCheckSum), sizeof(uint32_t));
|
||||
} else if (ptmFileLines[i].find("KernelHeapSize") != std::string::npos) {
|
||||
static_assert(sizeof(kernelHeapSize) == sizeof(uint32_t), "");
|
||||
deviceBinary.write(reinterpret_cast<const char *>(&kernelHeapSize), sizeof(uint32_t));
|
||||
} else if (ptmFileLines[i].find("KernelUnpaddedSize") != std::string::npos) {
|
||||
static_assert(sizeof(kernelHeapSizeUnpadded) == sizeof(uint32_t), "");
|
||||
deviceBinary.write(reinterpret_cast<char *>(&kernelHeapSizeUnpadded), sizeof(uint32_t));
|
||||
} else {
|
||||
if (writeDeviceBinary(ptmFileLines[i], deviceBinary)) {
|
||||
messagePrinter.printf("Error while writing to binary.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add kernel blob after the header
|
||||
deviceBinary.write(kernelBlobData.c_str(), kernelBlobData.size());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BinaryEncoder::validateInput(const std::vector<std::string> &args) {
|
||||
if ("-help" == args[args.size() - 1]) {
|
||||
printHelp();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t argIndex = 2; argIndex < args.size(); ++argIndex) {
|
||||
const auto &currArg = args[argIndex];
|
||||
const bool hasMoreArgs = (argIndex + 1 < args.size());
|
||||
if ("-dump" == currArg && hasMoreArgs) {
|
||||
pathToDump = args[++argIndex];
|
||||
addSlash(pathToDump);
|
||||
} else if ("-device" == currArg && hasMoreArgs) {
|
||||
iga->setProductFamily(getProductFamilyFromDeviceName(args[++argIndex]));
|
||||
} else if ("-out" == currArg && hasMoreArgs) {
|
||||
elfName = args[++argIndex];
|
||||
} else if ("-ignore_isa_padding" == currArg) {
|
||||
ignoreIsaPadding = true;
|
||||
} else if ("-q" == currArg) {
|
||||
this->messagePrinter = MessagePrinter{true};
|
||||
iga->setMessagePrinter(this->messagePrinter);
|
||||
} else {
|
||||
messagePrinter.printf("Unknown argument %s\n", currArg.c_str());
|
||||
printHelp();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (pathToDump.empty()) {
|
||||
if (!argHelper->outputEnabled()) {
|
||||
messagePrinter.printf("Warning : Path to dump folder not specificed - using ./dump as default.\n");
|
||||
pathToDump = "dump";
|
||||
addSlash(pathToDump);
|
||||
}
|
||||
}
|
||||
if (elfName.find(".bin") == std::string::npos) {
|
||||
messagePrinter.printf(".bin extension is expected for binary file.\n");
|
||||
printHelp();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (false == iga->isKnownPlatform()) {
|
||||
messagePrinter.printf("Warning : missing or invalid -device parameter - results may be inacurate\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void BinaryEncoder::write(std::stringstream &in, std::ostream &deviceBinary) {
|
||||
T val;
|
||||
in >> val;
|
||||
deviceBinary.write(reinterpret_cast<const char *>(&val), sizeof(T));
|
||||
}
|
||||
template <>
|
||||
void BinaryEncoder::write<uint8_t>(std::stringstream &in, std::ostream &deviceBinary) {
|
||||
uint8_t val;
|
||||
uint16_t help;
|
||||
in >> help;
|
||||
val = static_cast<uint8_t>(help);
|
||||
deviceBinary.write(reinterpret_cast<const char *>(&val), sizeof(uint8_t));
|
||||
}
|
||||
template void BinaryEncoder::write<uint16_t>(std::stringstream &in, std::ostream &deviceBinary);
|
||||
template void BinaryEncoder::write<uint32_t>(std::stringstream &in, std::ostream &deviceBinary);
|
||||
template void BinaryEncoder::write<uint64_t>(std::stringstream &in, std::ostream &deviceBinary);
|
||||
|
||||
int BinaryEncoder::writeDeviceBinary(const std::string &line, std::ostream &deviceBinary) {
|
||||
if (line.find(':') != std::string::npos) {
|
||||
return 0;
|
||||
} else if (line.find("Hex") != std::string::npos) {
|
||||
std::stringstream ss(line);
|
||||
ss.ignore(32, ' ');
|
||||
uint16_t tmp;
|
||||
uint8_t byte;
|
||||
while (!ss.eof()) {
|
||||
ss >> std::hex >> tmp;
|
||||
byte = static_cast<uint8_t>(tmp);
|
||||
deviceBinary.write(reinterpret_cast<const char *>(&byte), sizeof(uint8_t));
|
||||
}
|
||||
} else {
|
||||
std::stringstream ss(line);
|
||||
uint16_t size;
|
||||
std::string name;
|
||||
ss >> size;
|
||||
ss >> name;
|
||||
switch (size) {
|
||||
case 1:
|
||||
write<uint8_t>(ss, deviceBinary);
|
||||
break;
|
||||
case 2:
|
||||
write<uint16_t>(ss, deviceBinary);
|
||||
break;
|
||||
case 4:
|
||||
write<uint32_t>(ss, deviceBinary);
|
||||
break;
|
||||
case 8:
|
||||
write<uint64_t>(ss, deviceBinary);
|
||||
break;
|
||||
default:
|
||||
messagePrinter.printf("Unknown size in line: %s\n", line.c_str());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
53
shared/offline_compiler/source/decoder/binary_encoder.h
Normal file
53
shared/offline_compiler/source/decoder/binary_encoder.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "shared/offline_compiler/source/ocloc_arg_helper.h"
|
||||
|
||||
#include "helper.h"
|
||||
#include "iga_wrapper.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class BinaryEncoder {
|
||||
public:
|
||||
BinaryEncoder() : iga(new IgaWrapper) {
|
||||
iga->setMessagePrinter(messagePrinter);
|
||||
argHelper = std::make_unique<OclocArgHelper>();
|
||||
}
|
||||
BinaryEncoder(const std::string &dump, const std::string &elf)
|
||||
: pathToDump(dump), elfName(elf){};
|
||||
BinaryEncoder(std::unique_ptr<OclocArgHelper> helper) : argHelper(std::move(helper)), iga(new IgaWrapper) {
|
||||
iga->setMessagePrinter(messagePrinter);
|
||||
}
|
||||
int encode();
|
||||
int validateInput(const std::vector<std::string> &args);
|
||||
|
||||
void setMessagePrinter(const MessagePrinter &messagePrinter);
|
||||
|
||||
protected:
|
||||
std::unique_ptr<OclocArgHelper> argHelper = nullptr;
|
||||
bool ignoreIsaPadding = false;
|
||||
std::string pathToDump, elfName;
|
||||
MessagePrinter messagePrinter;
|
||||
std::unique_ptr<IgaWrapper> iga;
|
||||
void calculatePatchListSizes(std::vector<std::string> &ptmFile);
|
||||
MOCKABLE_VIRTUAL bool copyBinaryToBinary(const std::string &srcFileName, std::ostream &outBinary, uint32_t *binaryLength);
|
||||
bool copyBinaryToBinary(const std::string &srcFileName, std::ostream &outBinary) {
|
||||
return copyBinaryToBinary(srcFileName, outBinary, nullptr);
|
||||
}
|
||||
int createElf(std::stringstream &deviceBinary);
|
||||
void printHelp();
|
||||
int processBinary(const std::vector<std::string> &ptmFile, std::ostream &deviceBinary);
|
||||
int processKernel(size_t &i, const std::vector<std::string> &ptmFileLines, std::ostream &deviceBinary);
|
||||
template <typename T>
|
||||
void write(std::stringstream &in, std::ostream &deviceBinary);
|
||||
int writeDeviceBinary(const std::string &line, std::ostream &deviceBinary);
|
||||
void addPadding(std::ostream &out, size_t numBytes);
|
||||
};
|
||||
86
shared/offline_compiler/source/decoder/helper.cpp
Normal file
86
shared/offline_compiler/source/decoder/helper.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "helper.h"
|
||||
|
||||
#include "shared/source/helpers/hw_info.h"
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
|
||||
#include "opencl/source/os_interface/os_inc_base.h"
|
||||
|
||||
#include "igfxfmid.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
void addSlash(std::string &path) {
|
||||
if (!path.empty()) {
|
||||
auto lastChar = *path.rbegin();
|
||||
if ((lastChar != '/') && (lastChar != '\\')) {
|
||||
path.append("/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<char> readBinaryFile(const std::string &fileName) {
|
||||
std::ifstream file(fileName, std::ios_base::binary);
|
||||
if (file.good()) {
|
||||
size_t length;
|
||||
file.seekg(0, file.end);
|
||||
length = static_cast<size_t>(file.tellg());
|
||||
file.seekg(0, file.beg);
|
||||
std::vector<char> binary(length);
|
||||
file.read(binary.data(), length);
|
||||
return binary;
|
||||
} else {
|
||||
printf("Error! Couldn't open %s\n", fileName.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void readFileToVectorOfStrings(std::vector<std::string> &lines, const std::string &fileName, bool replaceTabs) {
|
||||
std::ifstream file(fileName);
|
||||
if (file.good()) {
|
||||
if (replaceTabs) {
|
||||
for (std::string line; std::getline(file, line);) {
|
||||
std::replace_if(
|
||||
line.begin(), line.end(), [](auto c) { return c == '\t'; }, ' ');
|
||||
lines.push_back(std::move(line));
|
||||
}
|
||||
} else {
|
||||
for (std::string line; std::getline(file, line);) {
|
||||
lines.push_back(std::move(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t findPos(const std::vector<std::string> &lines, const std::string &whatToFind) {
|
||||
for (size_t i = 0; i < lines.size(); ++i) {
|
||||
auto it = lines[i].find(whatToFind);
|
||||
if (it != std::string::npos) {
|
||||
if (it + whatToFind.size() == lines[i].size()) {
|
||||
return i;
|
||||
}
|
||||
char delimiter = lines[i][it + whatToFind.size()];
|
||||
if ((delimiter == ' ') || (delimiter = '\t') || (delimiter = '\n') || (delimiter = '\r')) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lines.size();
|
||||
}
|
||||
|
||||
PRODUCT_FAMILY getProductFamilyFromDeviceName(const std::string &deviceName) {
|
||||
for (unsigned int productId = 0; productId < IGFX_MAX_PRODUCT; ++productId) {
|
||||
if (NEO::hardwarePrefix[productId] != nullptr &&
|
||||
deviceName == NEO::hardwarePrefix[productId]) {
|
||||
return static_cast<PRODUCT_FAMILY>(productId);
|
||||
}
|
||||
}
|
||||
return IGFX_UNKNOWN;
|
||||
}
|
||||
48
shared/offline_compiler/source/decoder/helper.h
Normal file
48
shared/offline_compiler/source/decoder/helper.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
|
||||
#include "igfxfmid.h"
|
||||
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
void addSlash(std::string &path);
|
||||
|
||||
std::vector<char> readBinaryFile(const std::string &fileName);
|
||||
|
||||
void readFileToVectorOfStrings(std::vector<std::string> &lines, const std::string &fileName, bool replaceTabs = false);
|
||||
|
||||
size_t findPos(const std::vector<std::string> &lines, const std::string &whatToFind);
|
||||
|
||||
PRODUCT_FAMILY getProductFamilyFromDeviceName(const std::string &deviceName);
|
||||
|
||||
class MessagePrinter {
|
||||
public:
|
||||
MessagePrinter() = default;
|
||||
MessagePrinter(bool suppressMessages) : suppressMessages(suppressMessages) {}
|
||||
|
||||
void printf(const char *message) {
|
||||
if (!suppressMessages) {
|
||||
::printf("%s", message);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void printf(const char *format, Args... args) {
|
||||
if (!suppressMessages) {
|
||||
::printf(format, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool suppressMessages = false;
|
||||
};
|
||||
39
shared/offline_compiler/source/decoder/iga_stubs.cpp
Normal file
39
shared/offline_compiler/source/decoder/iga_stubs.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "helper.h"
|
||||
#include "iga_wrapper.h"
|
||||
|
||||
struct IgaWrapper::Impl {
|
||||
};
|
||||
|
||||
IgaWrapper::IgaWrapper() = default;
|
||||
IgaWrapper::~IgaWrapper() = default;
|
||||
|
||||
bool IgaWrapper::tryDisassembleGenISA(const void *kernelPtr, uint32_t kernelSize, std::string &out) {
|
||||
messagePrinter->printf("Warning: ocloc built without support for IGA - kernel binaries won't be disassembled.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IgaWrapper::tryAssembleGenISA(const std::string &inAsm, std::string &outBinary) {
|
||||
messagePrinter->printf("Warning: ocloc built without support for IGA - kernel binaries won't be assembled.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IgaWrapper::tryLoadIga() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void IgaWrapper::setGfxCore(GFXCORE_FAMILY core) {
|
||||
}
|
||||
|
||||
void IgaWrapper::setProductFamily(PRODUCT_FAMILY product) {
|
||||
}
|
||||
|
||||
bool IgaWrapper::isKnownPlatform() const {
|
||||
return false;
|
||||
}
|
||||
193
shared/offline_compiler/source/decoder/iga_wrapper.cpp
Normal file
193
shared/offline_compiler/source/decoder/iga_wrapper.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "iga_wrapper.h"
|
||||
|
||||
#include "shared/source/helpers/hw_info.h"
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
|
||||
#include "opencl/source/os_interface/os_inc_base.h"
|
||||
|
||||
#include "helper.h"
|
||||
#include "igfxfmid.h"
|
||||
#include "translate_platform_base.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct IgaLibrary {
|
||||
pIGAAssemble assemble = nullptr;
|
||||
pIGAContextCreate contextCreate = nullptr;
|
||||
pIGAContextGetErrors contextGetErrors = nullptr;
|
||||
pIGAContextGetWarnings contextGetWarnings = nullptr;
|
||||
pIGAContextRelease contextRelease = nullptr;
|
||||
pIGADisassemble disassemble = nullptr;
|
||||
pIGAStatusToString statusToString = nullptr;
|
||||
iga_context_options_t OptsContext = {};
|
||||
|
||||
std::unique_ptr<NEO::OsLibrary> library;
|
||||
|
||||
bool isLoaded() {
|
||||
return library != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
struct IgaWrapper::Impl {
|
||||
iga_gen_t igaGen = IGA_GEN_INVALID;
|
||||
IgaLibrary igaLib;
|
||||
|
||||
void loadIga() {
|
||||
IgaLibrary iga;
|
||||
iga.OptsContext.cb = sizeof(igaLib.OptsContext);
|
||||
iga.OptsContext.gen = igaGen;
|
||||
|
||||
#define STR2(X) #X
|
||||
#define STR(X) STR2(X)
|
||||
iga.library.reset(NEO::OsLibrary::load(STR(IGA_LIBRARY_NAME)));
|
||||
if (iga.library == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
#define LOAD_OR_ERROR(MEMBER, FUNC_NAME) \
|
||||
if (nullptr == (iga.MEMBER = reinterpret_cast<decltype(iga.MEMBER)>(iga.library->getProcAddress(FUNC_NAME)))) { \
|
||||
printf("Warning : Couldn't find %s in %s\n", FUNC_NAME, STR(IGA_LIBRARY_NAME)); \
|
||||
return; \
|
||||
}
|
||||
|
||||
LOAD_OR_ERROR(assemble, IGA_ASSEMBLE_STR);
|
||||
LOAD_OR_ERROR(contextCreate, IGA_CONTEXT_CREATE_STR);
|
||||
LOAD_OR_ERROR(contextGetErrors, IGA_CONTEXT_GET_ERRORS_STR);
|
||||
LOAD_OR_ERROR(contextGetWarnings, IGA_CONTEXT_GET_WARNINGS_STR);
|
||||
LOAD_OR_ERROR(contextRelease, IGA_CONTEXT_RELEASE_STR);
|
||||
LOAD_OR_ERROR(disassemble, IGA_DISASSEMBLE_STR);
|
||||
LOAD_OR_ERROR(statusToString, IGA_STATUS_TO_STRING_STR);
|
||||
|
||||
#undef LOAD_OR_ERROR
|
||||
#undef STR
|
||||
#undef STR2
|
||||
|
||||
this->igaLib = std::move(iga);
|
||||
}
|
||||
};
|
||||
|
||||
IgaWrapper::IgaWrapper()
|
||||
: pimpl(std::make_unique<Impl>()) {
|
||||
}
|
||||
|
||||
IgaWrapper::~IgaWrapper() = default;
|
||||
|
||||
bool IgaWrapper::tryDisassembleGenISA(const void *kernelPtr, uint32_t kernelSize, std::string &out) {
|
||||
if (false == tryLoadIga()) {
|
||||
messagePrinter->printf("Warning: couldn't load iga - kernel binaries won't be disassembled.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
iga_context_t context;
|
||||
iga_disassemble_options_t disassembleOptions = IGA_DISASSEMBLE_OPTIONS_INIT();
|
||||
iga_status_t stat;
|
||||
|
||||
stat = pimpl->igaLib.contextCreate(&pimpl->igaLib.OptsContext, &context);
|
||||
if (stat != 0) {
|
||||
messagePrinter->printf("Error while creating IGA Context! Error msg: %s", pimpl->igaLib.statusToString(stat));
|
||||
return false;
|
||||
}
|
||||
|
||||
char kernelText = '\0';
|
||||
char *pKernelText = &kernelText;
|
||||
|
||||
stat = pimpl->igaLib.disassemble(context, &disassembleOptions, kernelPtr, kernelSize, nullptr, nullptr, &pKernelText);
|
||||
if (stat != 0) {
|
||||
messagePrinter->printf("Error while disassembling with IGA!\nStatus msg: %s\n", pimpl->igaLib.statusToString(stat));
|
||||
const iga_diagnostic_t *errors;
|
||||
uint32_t size = 100;
|
||||
pimpl->igaLib.contextGetErrors(context, &errors, &size);
|
||||
if (errors != nullptr) {
|
||||
messagePrinter->printf("Errors: %s\n", errors->message);
|
||||
}
|
||||
pimpl->igaLib.contextRelease(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
const iga_diagnostic_t *warnings;
|
||||
uint32_t warningsSize = 100;
|
||||
pimpl->igaLib.contextGetWarnings(context, &warnings, &warningsSize);
|
||||
if (warningsSize > 0 && warnings != nullptr) {
|
||||
messagePrinter->printf("Warnings: %s\n", warnings->message);
|
||||
}
|
||||
|
||||
out = pKernelText;
|
||||
pimpl->igaLib.contextRelease(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IgaWrapper::tryAssembleGenISA(const std::string &inAsm, std::string &outBinary) {
|
||||
if (false == tryLoadIga()) {
|
||||
messagePrinter->printf("Warning: couldn't load iga - kernel binaries won't be assembled.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
iga_context_t context;
|
||||
iga_status_t stat;
|
||||
iga_assemble_options_t assembleOptions = IGA_ASSEMBLE_OPTIONS_INIT();
|
||||
|
||||
stat = pimpl->igaLib.contextCreate(&pimpl->igaLib.OptsContext, &context);
|
||||
if (stat != 0) {
|
||||
messagePrinter->printf("Error while creating IGA Context! Error msg: %s", pimpl->igaLib.statusToString(stat));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t size = 0;
|
||||
void *pOutput = nullptr;
|
||||
stat = pimpl->igaLib.assemble(context, &assembleOptions, inAsm.c_str(), &pOutput, &size);
|
||||
if (stat != 0) {
|
||||
messagePrinter->printf("Error while assembling with IGA!\nStatus msg: %s\n", pimpl->igaLib.statusToString(stat));
|
||||
|
||||
const iga_diagnostic_t *errors;
|
||||
uint32_t size = 100;
|
||||
pimpl->igaLib.contextGetErrors(context, &errors, &size);
|
||||
if (errors != nullptr) {
|
||||
messagePrinter->printf("Errors: %s\n", errors->message);
|
||||
}
|
||||
|
||||
pimpl->igaLib.contextRelease(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
const iga_diagnostic_t *warnings;
|
||||
uint32_t context_size;
|
||||
pimpl->igaLib.contextGetWarnings(context, &warnings, &context_size);
|
||||
if (context_size > 0 && warnings != nullptr) {
|
||||
messagePrinter->printf("Warnings: %s\n", warnings->message);
|
||||
}
|
||||
|
||||
outBinary.assign(reinterpret_cast<char *>(pOutput), reinterpret_cast<char *>(pOutput) + size);
|
||||
|
||||
pimpl->igaLib.contextRelease(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IgaWrapper::tryLoadIga() {
|
||||
if (false == pimpl->igaLib.isLoaded()) {
|
||||
pimpl->loadIga();
|
||||
}
|
||||
return pimpl->igaLib.isLoaded();
|
||||
}
|
||||
|
||||
void IgaWrapper::setGfxCore(GFXCORE_FAMILY core) {
|
||||
if (pimpl->igaGen == IGA_GEN_INVALID) {
|
||||
pimpl->igaGen = translateToIgaGen(core);
|
||||
}
|
||||
}
|
||||
|
||||
void IgaWrapper::setProductFamily(PRODUCT_FAMILY product) {
|
||||
if (pimpl->igaGen == IGA_GEN_INVALID) {
|
||||
pimpl->igaGen = translateToIgaGen(product);
|
||||
}
|
||||
}
|
||||
|
||||
bool IgaWrapper::isKnownPlatform() const {
|
||||
return pimpl->igaGen != IGA_GEN_INVALID;
|
||||
}
|
||||
43
shared/offline_compiler/source/decoder/iga_wrapper.h
Normal file
43
shared/offline_compiler/source/decoder/iga_wrapper.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "igfxfmid.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class MessagePrinter;
|
||||
|
||||
struct IgaWrapper {
|
||||
IgaWrapper();
|
||||
MOCKABLE_VIRTUAL ~IgaWrapper();
|
||||
|
||||
IgaWrapper(IgaWrapper &) = delete;
|
||||
IgaWrapper(const IgaWrapper &&) = delete;
|
||||
IgaWrapper &operator=(const IgaWrapper &) = delete;
|
||||
IgaWrapper &operator=(IgaWrapper &&) = delete;
|
||||
|
||||
MOCKABLE_VIRTUAL bool tryDisassembleGenISA(const void *kernelPtr, uint32_t kernelSize, std::string &out);
|
||||
MOCKABLE_VIRTUAL bool tryAssembleGenISA(const std::string &inAsm, std::string &outBinary);
|
||||
|
||||
MOCKABLE_VIRTUAL void setGfxCore(GFXCORE_FAMILY core);
|
||||
MOCKABLE_VIRTUAL void setProductFamily(PRODUCT_FAMILY product);
|
||||
MOCKABLE_VIRTUAL bool isKnownPlatform() const;
|
||||
void setMessagePrinter(MessagePrinter &messagePrinter) {
|
||||
this->messagePrinter = &messagePrinter;
|
||||
}
|
||||
|
||||
protected:
|
||||
MOCKABLE_VIRTUAL bool tryLoadIga();
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
|
||||
MessagePrinter *messagePrinter = nullptr;
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/decoder/translate_platform_base.h"
|
||||
|
||||
iga_gen_t translateToIgaGen(PRODUCT_FAMILY productFamily) {
|
||||
return translateToIgaGenBase(productFamily);
|
||||
}
|
||||
|
||||
iga_gen_t translateToIgaGen(GFXCORE_FAMILY coreFamily) {
|
||||
return translateToIgaGenBase(coreFamily);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "igad.h"
|
||||
#include "igfxfmid.h"
|
||||
|
||||
inline iga_gen_t translateToIgaGenBase(PRODUCT_FAMILY productFamily) {
|
||||
switch (productFamily) {
|
||||
default:
|
||||
return IGA_GEN_INVALID;
|
||||
case IGFX_BROADWELL:
|
||||
return IGA_GEN8;
|
||||
case IGFX_CHERRYVIEW:
|
||||
return IGA_GEN8lp;
|
||||
case IGFX_SKYLAKE:
|
||||
return IGA_GEN9;
|
||||
case IGFX_BROXTON:
|
||||
return IGA_GEN9lp;
|
||||
case IGFX_KABYLAKE:
|
||||
return IGA_GEN9p5;
|
||||
case IGFX_COFFEELAKE:
|
||||
return IGA_GEN9p5;
|
||||
case IGFX_ICELAKE:
|
||||
return IGA_GEN11;
|
||||
case IGFX_ICELAKE_LP:
|
||||
return IGA_GEN11;
|
||||
}
|
||||
}
|
||||
|
||||
inline iga_gen_t translateToIgaGenBase(GFXCORE_FAMILY coreFamily) {
|
||||
switch (coreFamily) {
|
||||
default:
|
||||
return IGA_GEN_INVALID;
|
||||
case IGFX_GEN8_CORE:
|
||||
return IGA_GEN8;
|
||||
case IGFX_GEN9_CORE:
|
||||
return IGA_GEN9;
|
||||
case IGFX_GEN11_CORE:
|
||||
return IGA_GEN11;
|
||||
case IGFX_GEN11LP_CORE:
|
||||
return IGA_GEN11;
|
||||
}
|
||||
}
|
||||
|
||||
iga_gen_t translateToIgaGen(PRODUCT_FAMILY productFamily);
|
||||
iga_gen_t translateToIgaGen(GFXCORE_FAMILY coreFamily);
|
||||
19
shared/offline_compiler/source/extra_settings.cpp
Normal file
19
shared/offline_compiler/source/extra_settings.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
|
||||
#include "compiler_options.h"
|
||||
|
||||
namespace NEO {
|
||||
void OfflineCompiler::resolveExtraSettings() {
|
||||
if (deviceName == "tgllp") {
|
||||
CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::forceEmuInt32DivRemSP);
|
||||
}
|
||||
}
|
||||
} // namespace NEO
|
||||
13
shared/offline_compiler/source/main.cpp
Normal file
13
shared/offline_compiler/source/main.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ocloc_wrapper.h"
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
OclocWrapper oclocWrapper;
|
||||
return oclocWrapper.invokeOcloc(argc, argv);
|
||||
}
|
||||
279
shared/offline_compiler/source/multi_command.cpp
Normal file
279
shared/offline_compiler/source/multi_command.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/multi_command.h"
|
||||
|
||||
namespace NEO {
|
||||
int MultiCommand::singleBuild(size_t numArgs, const std::vector<std::string> &allArgs) {
|
||||
int retVal = CL_SUCCESS;
|
||||
std::string buildLog;
|
||||
OfflineCompiler *pCompiler = OfflineCompiler::create(numArgs, allArgs, true, retVal);
|
||||
if (retVal == CL_SUCCESS) {
|
||||
retVal = buildWithSafetyGuard(pCompiler);
|
||||
|
||||
buildLog = pCompiler->getBuildLog();
|
||||
if (buildLog.empty() == false) {
|
||||
printf("%s\n", buildLog.c_str());
|
||||
}
|
||||
|
||||
if (retVal == CL_SUCCESS) {
|
||||
if (!pCompiler->isQuiet())
|
||||
printf("Build succeeded.\n");
|
||||
} else {
|
||||
printf("Build failed with error code: %d\n", retVal);
|
||||
}
|
||||
}
|
||||
if (buildLog.empty() == false) {
|
||||
singleBuilds.push_back(pCompiler);
|
||||
} else {
|
||||
delete pCompiler;
|
||||
}
|
||||
|
||||
if (outputFileList != "") {
|
||||
std::ofstream myfile(outputFileList, std::fstream::app);
|
||||
if (myfile.is_open()) {
|
||||
if (retVal == CL_SUCCESS)
|
||||
myfile << getCurrentDirectoryOwn(outDirForBuilds) + OutFileName + ".bin";
|
||||
else
|
||||
myfile << "Unsuccesful build";
|
||||
myfile << std::endl;
|
||||
myfile.close();
|
||||
} else
|
||||
printf("Unable to open outputFileList\n");
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
MultiCommand::MultiCommand() = default;
|
||||
|
||||
MultiCommand::~MultiCommand() {
|
||||
deleteBuildsWithWarnigs();
|
||||
}
|
||||
|
||||
void MultiCommand::deleteBuildsWithWarnigs() {
|
||||
for (OfflineCompiler *pSingle : singleBuilds)
|
||||
delete pSingle;
|
||||
singleBuilds.clear();
|
||||
}
|
||||
|
||||
MultiCommand *MultiCommand::create(const std::vector<std::string> &argv, int &retVal) {
|
||||
retVal = CL_SUCCESS;
|
||||
auto pMultiCommand = new MultiCommand();
|
||||
|
||||
if (pMultiCommand) {
|
||||
retVal = pMultiCommand->initialize(argv);
|
||||
}
|
||||
|
||||
if (retVal != CL_SUCCESS) {
|
||||
delete pMultiCommand;
|
||||
pMultiCommand = nullptr;
|
||||
}
|
||||
|
||||
return pMultiCommand;
|
||||
}
|
||||
|
||||
std::string MultiCommand::eraseExtensionFromPath(std::string &filePath) {
|
||||
size_t extPos = filePath.find_last_of(".", filePath.size());
|
||||
if (extPos == std::string::npos) {
|
||||
extPos = filePath.size();
|
||||
}
|
||||
std::string fileName;
|
||||
std::string fileTrunk = filePath.substr(0, extPos);
|
||||
|
||||
return fileTrunk;
|
||||
}
|
||||
|
||||
void MultiCommand::addAdditionalOptionsToSingleCommandLine(std::vector<std::string> &singleLineWithArguments, int buildId) {
|
||||
bool hasOutDir = false;
|
||||
bool hasSpecificName = false;
|
||||
for (auto arg : singleLineWithArguments) {
|
||||
if (arg == "-out_dir") {
|
||||
hasOutDir = true;
|
||||
}
|
||||
if (arg == "-output") {
|
||||
hasSpecificName = true;
|
||||
}
|
||||
}
|
||||
if (!hasOutDir) {
|
||||
singleLineWithArguments.push_back("-out_dir");
|
||||
outDirForBuilds = eraseExtensionFromPath(pathToCMD);
|
||||
singleLineWithArguments.push_back(outDirForBuilds);
|
||||
}
|
||||
if (!hasSpecificName) {
|
||||
singleLineWithArguments.push_back("-output");
|
||||
OutFileName = "build_no_" + std::to_string(buildId + 1);
|
||||
singleLineWithArguments.push_back(OutFileName);
|
||||
}
|
||||
if (quiet)
|
||||
singleLineWithArguments.push_back("-q");
|
||||
}
|
||||
|
||||
int MultiCommand::initialize(const std::vector<std::string> &allArgs) {
|
||||
int retVal = CL_SUCCESS;
|
||||
size_t numArgs = allArgs.size();
|
||||
|
||||
for (uint32_t argIndex = 1; argIndex < numArgs; argIndex++) {
|
||||
if (allArgs[argIndex] == "-multi") {
|
||||
if (numArgs > argIndex + 1)
|
||||
pathToCMD = allArgs[argIndex + 1];
|
||||
else {
|
||||
printHelp();
|
||||
return INVALID_COMMAND_LINE;
|
||||
}
|
||||
argIndex++;
|
||||
} else if (allArgs[argIndex] == "-q") {
|
||||
quiet = true;
|
||||
} else if (allArgs[argIndex] == "-output_file_list") {
|
||||
if (numArgs > argIndex + 1)
|
||||
outputFileList = allArgs[argIndex + 1];
|
||||
else {
|
||||
printHelp();
|
||||
return INVALID_COMMAND_LINE;
|
||||
}
|
||||
argIndex++;
|
||||
} else if (allArgs[argIndex] == "--help") {
|
||||
printHelp();
|
||||
return PRINT_USAGE;
|
||||
} else {
|
||||
printf("Invalid option (arg %d): %s\n", argIndex, allArgs[argIndex].c_str());
|
||||
return INVALID_COMMAND_LINE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//save file with builds arguments to vector of strings, line by line
|
||||
openFileWithBuildsArguments();
|
||||
if (!lines.empty()) {
|
||||
for (unsigned int i = 0; i < lines.size(); i++) {
|
||||
std::vector<std::string> singleLineWithArguments;
|
||||
unsigned int numberOfArg;
|
||||
|
||||
singleLineWithArguments.push_back(allArgs[0]);
|
||||
retVal = splitLineInSeparateArgs(singleLineWithArguments, lines[i], i);
|
||||
if (retVal != CL_SUCCESS) {
|
||||
retValues.push_back(retVal);
|
||||
continue;
|
||||
}
|
||||
|
||||
addAdditionalOptionsToSingleCommandLine(singleLineWithArguments, i);
|
||||
|
||||
numberOfArg = static_cast<unsigned int>(singleLineWithArguments.size());
|
||||
|
||||
if (!quiet)
|
||||
printf("\nCommand number %d: ", i + 1);
|
||||
retVal = singleBuild(numberOfArg, singleLineWithArguments);
|
||||
retValues.push_back(retVal);
|
||||
}
|
||||
|
||||
return showResults();
|
||||
} else {
|
||||
printHelp();
|
||||
return INVALID_COMMAND_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiCommand::printHelp() {
|
||||
printf(R"===(Compiles multiple files using a config file.
|
||||
|
||||
Usage: ocloc multi <file_name>
|
||||
<file_name> Input file containing a list of arguments for subsequent
|
||||
ocloc invocations.
|
||||
Expected format of each line inside such file is:
|
||||
'-file <filename> -device <device_type> [compile_options].
|
||||
See 'ocloc compile --help' for available compile_options.
|
||||
Results of subsequent compilations will be dumped into
|
||||
a directory with name indentical file_name's base name.
|
||||
|
||||
-output_file_list Name of optional file containing
|
||||
paths to outputs .bin files
|
||||
|
||||
)===");
|
||||
}
|
||||
|
||||
int MultiCommand::splitLineInSeparateArgs(std::vector<std::string> &qargs, const std::string &command, int numberOfBuild) {
|
||||
unsigned int len = static_cast<unsigned int>(command.length());
|
||||
|
||||
bool qot = false, sqot = false;
|
||||
int arglen;
|
||||
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
int start = i;
|
||||
if (command[i] == '\"') {
|
||||
qot = true;
|
||||
} else if (command[i] == '\'')
|
||||
sqot = true;
|
||||
|
||||
if (qot) {
|
||||
i++;
|
||||
start++;
|
||||
while (i < len && command[i] != '\"')
|
||||
i++;
|
||||
if (i < len)
|
||||
qot = false;
|
||||
arglen = i - start;
|
||||
i++;
|
||||
} else if (sqot) {
|
||||
i++;
|
||||
while (i < len && command[i] != '\'')
|
||||
i++;
|
||||
if (i < len)
|
||||
sqot = false;
|
||||
arglen = i - start;
|
||||
i++;
|
||||
} else {
|
||||
while (i < len && command[i] != ' ')
|
||||
i++;
|
||||
arglen = i - start;
|
||||
}
|
||||
qargs.push_back(command.substr(start, arglen));
|
||||
}
|
||||
if (qot || sqot) {
|
||||
printf("One of the quotes is open in build number %d\n", numberOfBuild + 1);
|
||||
return INVALID_COMMAND_LINE;
|
||||
}
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
void MultiCommand::openFileWithBuildsArguments() {
|
||||
std::fstream multiCmdFile;
|
||||
std::stringstream fileContent;
|
||||
multiCmdFile.open(pathToCMD, std::fstream::in);
|
||||
|
||||
if (multiCmdFile.is_open()) {
|
||||
std::string param;
|
||||
fileContent << multiCmdFile.rdbuf();
|
||||
multiCmdFile.close();
|
||||
while (std::getline(fileContent, param, '\n')) {
|
||||
param.erase(param.find_last_not_of(" \r\t") + 1);
|
||||
param.erase(0, param.find_first_not_of(" \r\t"));
|
||||
if (!param.empty()) {
|
||||
lines.push_back(param);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("Can not open file with builds arguments\n");
|
||||
}
|
||||
}
|
||||
|
||||
int MultiCommand::showResults() {
|
||||
int retValue = CL_SUCCESS;
|
||||
int indexRetVal = 0;
|
||||
for (int retVal : retValues) {
|
||||
if (retVal != CL_SUCCESS) {
|
||||
if (retValue == CL_SUCCESS)
|
||||
retValue = retVal;
|
||||
if (!quiet)
|
||||
printf("Build %d: failed. Error code: %d\n", indexRetVal, retVal);
|
||||
} else {
|
||||
if (!quiet)
|
||||
printf("Build %d: successful\n", indexRetVal);
|
||||
}
|
||||
indexRetVal++;
|
||||
}
|
||||
return retValue;
|
||||
}
|
||||
} // namespace NEO
|
||||
54
shared/offline_compiler/source/multi_command.h
Normal file
54
shared/offline_compiler/source/multi_command.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/decoder/binary_decoder.h"
|
||||
#include "shared/offline_compiler/source/decoder/binary_encoder.h"
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
#include "shared/offline_compiler/source/utilities/get_current_dir.h"
|
||||
#include "shared/offline_compiler/source/utilities/safety_caller.h"
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
|
||||
#include <CL/cl.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace NEO {
|
||||
|
||||
class MultiCommand {
|
||||
public:
|
||||
static MultiCommand *create(const std::vector<std::string> &argv, int &retVal);
|
||||
void deleteBuildsWithWarnigs();
|
||||
|
||||
std::vector<OfflineCompiler *> singleBuilds;
|
||||
|
||||
MultiCommand &operator=(const MultiCommand &) = delete;
|
||||
MultiCommand(const MultiCommand &) = delete;
|
||||
~MultiCommand();
|
||||
|
||||
std::string outDirForBuilds;
|
||||
std::string outputFileList = "";
|
||||
|
||||
protected:
|
||||
int splitLineInSeparateArgs(std::vector<std::string> &qargs, const std::string &command, int numberOfBuild);
|
||||
void openFileWithBuildsArguments();
|
||||
void addAdditionalOptionsToSingleCommandLine(std::vector<std::string> &, int);
|
||||
void printHelp();
|
||||
int initialize(const std::vector<std::string> &allArgs);
|
||||
int showResults();
|
||||
int singleBuild(size_t numArgs, const std::vector<std::string> &allArgs);
|
||||
std::string eraseExtensionFromPath(std::string &filePath);
|
||||
std::string OutFileName;
|
||||
|
||||
std::vector<int> retValues;
|
||||
std::string pathToCMD;
|
||||
std::vector<std::string> lines;
|
||||
bool quiet = false;
|
||||
|
||||
MultiCommand();
|
||||
};
|
||||
} // namespace NEO
|
||||
129
shared/offline_compiler/source/ocloc_api.cpp
Normal file
129
shared/offline_compiler/source/ocloc_api.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ocloc_api.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void printHelp() {
|
||||
printf(R"===(ocloc is a tool for managing Intel OpenCL GPU device binary format.
|
||||
It can be used for generation (as part of 'compile' command) as well as
|
||||
manipulation (decoding/modifying - as part of 'disasm'/'asm' commands) of such
|
||||
binary files.
|
||||
Intel OpenCL GPU device binary is a format used by Intel OpenCL GPU runtime
|
||||
(aka NEO). Intel OpenCL GPU runtime will return this binary format when queried
|
||||
using clGetProgramInfo(..., CL_PROGRAM_BINARIES, ...). It will also honor
|
||||
this format as input to clCreateProgramWithBinary function call.
|
||||
ocloc does not require Intel GPU device to be present in the system nor does it
|
||||
depend on Intel OpenCL GPU runtime driver to be installed. It does however rely
|
||||
on the same set of compilers (IGC, common_clang) as the runtime driver.
|
||||
|
||||
Usage: ocloc [--help] <command> [<command_args>]
|
||||
Available commands are listed below.
|
||||
Use 'ocloc <command> --help' to get help about specific command.
|
||||
|
||||
Commands:
|
||||
compile Compiles input to Intel OpenCL GPU device binary.
|
||||
disasm Disassembles Intel OpenCL GPU device binary.
|
||||
asm Assembles Intel OpenCL GPU device binary.
|
||||
multi Compiles multiple files using a config file.
|
||||
|
||||
Default command (when none provided) is 'compile'.
|
||||
|
||||
Examples:
|
||||
Compile file to Intel OpenCL GPU device binary (out = source_file_Gen9core.bin)
|
||||
ocloc -file source_file.cl -device skl
|
||||
|
||||
Disassemble Intel OpenCL GPU device binary
|
||||
ocloc disasm -file source_file_Gen9core.bin
|
||||
|
||||
Assemble to Intel OpenCL GPU device binary (after above disasm)
|
||||
ocloc asm -out reassembled.bin
|
||||
)===");
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int oclocInvoke(unsigned int numArgs, const char *argv[],
|
||||
const uint32_t numSources, const uint8_t **dataSources, const uint64_t *lenSources, const char **nameSources,
|
||||
const uint32_t numInputHeaders, const uint8_t **dataInputHeaders, const uint64_t *lenInputHeaders, const char **nameInputHeaders,
|
||||
uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs) {
|
||||
auto helper = std::make_unique<OclocArgHelper>(
|
||||
numSources, dataSources, lenSources, nameSources,
|
||||
numInputHeaders, dataInputHeaders, lenInputHeaders, nameInputHeaders,
|
||||
numOutputs, dataOutputs, lenOutputs, nameOutputs);
|
||||
std::vector<std::string> allArgs;
|
||||
if (numArgs > 1) {
|
||||
allArgs.assign(argv, argv + numArgs);
|
||||
}
|
||||
|
||||
try {
|
||||
if (numArgs == 1 || (numArgs > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))) {
|
||||
printHelp();
|
||||
} else if (numArgs > 1 && !strcmp(argv[1], "disasm")) {
|
||||
BinaryDecoder disasm(std::move(helper));
|
||||
int retVal = disasm.validateInput(allArgs);
|
||||
if (retVal == 0) {
|
||||
return disasm.decode();
|
||||
} else {
|
||||
return retVal;
|
||||
}
|
||||
} else if (numArgs > 1 && !strcmp(argv[1], "asm")) {
|
||||
BinaryEncoder assembler(std::move(helper));
|
||||
int retVal = assembler.validateInput(allArgs);
|
||||
if (retVal == 0) {
|
||||
return assembler.encode();
|
||||
} else {
|
||||
return retVal;
|
||||
}
|
||||
} else if (numArgs > 1 && (!strcmp(argv[1], "multi") || !strcmp(argv[1], "-multi"))) {
|
||||
int retValue = CL_SUCCESS;
|
||||
auto pMulti = std::unique_ptr<MultiCommand>(MultiCommand::create(allArgs, retValue));
|
||||
return retValue;
|
||||
} else {
|
||||
int retVal = CL_SUCCESS;
|
||||
std::vector<std::string> allArgs;
|
||||
if (numArgs > 1) {
|
||||
allArgs.assign(argv, argv + numArgs);
|
||||
}
|
||||
|
||||
OfflineCompiler *pCompiler = OfflineCompiler::create(numArgs, allArgs, true, retVal, std::move(helper));
|
||||
|
||||
if (retVal == CL_SUCCESS) {
|
||||
retVal = buildWithSafetyGuard(pCompiler);
|
||||
|
||||
std::string buildLog = pCompiler->getBuildLog();
|
||||
if (buildLog.empty() == false) {
|
||||
printf("%s\n", buildLog.c_str());
|
||||
}
|
||||
|
||||
if (retVal == CL_SUCCESS) {
|
||||
if (!pCompiler->isQuiet())
|
||||
printf("Build succeeded.\n");
|
||||
} else {
|
||||
printf("Build failed with error code: %d\n", retVal);
|
||||
}
|
||||
}
|
||||
delete pCompiler;
|
||||
return retVal;
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
printf("%s\n", e.what());
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int oclocFreeOutput(uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs) {
|
||||
for (uint32_t i = 0; i < *numOutputs; i++) {
|
||||
delete[](*dataOutputs)[i];
|
||||
delete[](*nameOutputs)[i];
|
||||
}
|
||||
delete[](*dataOutputs);
|
||||
delete[](*lenOutputs);
|
||||
delete[](*nameOutputs);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
27
shared/offline_compiler/source/ocloc_api.h
Normal file
27
shared/offline_compiler/source/ocloc_api.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/decoder/binary_decoder.h"
|
||||
#include "shared/offline_compiler/source/decoder/binary_encoder.h"
|
||||
#include "shared/offline_compiler/source/multi_command.h"
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
|
||||
using namespace NEO;
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SIGNATURE __declspec(dllexport) int __cdecl
|
||||
#else
|
||||
#define SIGNATURE int
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
SIGNATURE oclocInvoke(unsigned int numArgs, const char *argv[],
|
||||
const uint32_t numSources, const uint8_t **dataSources, const uint64_t *lenSources, const char **nameSources,
|
||||
const uint32_t numInputHeaders, const uint8_t **dataInputHeaders, const uint64_t *lenInputHeaders, const char **nameInputHeaders,
|
||||
uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs);
|
||||
SIGNATURE oclocFreeOutput(uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs);
|
||||
}
|
||||
150
shared/offline_compiler/source/ocloc_arg_helper.cpp
Normal file
150
shared/offline_compiler/source/ocloc_arg_helper.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ocloc_arg_helper.h"
|
||||
|
||||
#include "shared/source/helpers/file_io.h"
|
||||
#include "shared/source/helpers/string.h"
|
||||
|
||||
#include "decoder/helper.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
void Source::toVectorOfStrings(std::vector<std::string> &lines, bool replaceTabs) {
|
||||
std::string line;
|
||||
const char *file = reinterpret_cast<const char *>(data);
|
||||
|
||||
while (*file != '\0') {
|
||||
if (replaceTabs && *file == '\t') {
|
||||
line += ' ';
|
||||
} else if (*file == '\n') {
|
||||
lines.push_back(line);
|
||||
line = "";
|
||||
} else {
|
||||
line += *file;
|
||||
}
|
||||
file++;
|
||||
}
|
||||
}
|
||||
|
||||
Output::Output(const std::string &name, const void *data, const size_t &size)
|
||||
: name(name), size(size) {
|
||||
this->data = new uint8_t[size];
|
||||
memcpy_s(reinterpret_cast<void *>(this->data), this->size, data, size);
|
||||
};
|
||||
|
||||
OclocArgHelper::OclocArgHelper(const uint32_t numSources, const uint8_t **dataSources,
|
||||
const uint64_t *lenSources, const char **nameSources,
|
||||
const uint32_t numInputHeaders,
|
||||
const uint8_t **dataInputHeaders,
|
||||
const uint64_t *lenInputHeaders, const char **nameInputHeaders,
|
||||
uint32_t *numOutputs, uint8_t ***dataOutputs,
|
||||
uint64_t **lenOutputs, char ***nameOutputs)
|
||||
: numOutputs(numOutputs), nameOutputs(nameOutputs),
|
||||
dataOutputs(dataOutputs), lenOutputs(lenOutputs), hasOutput(numOutputs != nullptr) {
|
||||
for (uint32_t i = 0; i < numSources; ++i) {
|
||||
inputs.push_back(Source(dataSources[i], lenSources[i], nameSources[i]));
|
||||
}
|
||||
for (uint32_t i = 0; i < numInputHeaders; ++i) {
|
||||
headers.push_back(Source(dataInputHeaders[i], lenInputHeaders[i], nameInputHeaders[i]));
|
||||
}
|
||||
}
|
||||
|
||||
OclocArgHelper::~OclocArgHelper() {
|
||||
if (outputEnabled()) {
|
||||
moveOutputs();
|
||||
}
|
||||
}
|
||||
|
||||
bool OclocArgHelper::fileExists(const std::string &filename) const {
|
||||
return sourceFileExists(filename) || ::fileExists(filename);
|
||||
}
|
||||
|
||||
void OclocArgHelper::moveOutputs() {
|
||||
*numOutputs = static_cast<uint32_t>(outputs.size());
|
||||
*nameOutputs = new char *[outputs.size()];
|
||||
*dataOutputs = new uint8_t *[outputs.size()];
|
||||
*lenOutputs = new uint64_t[outputs.size()];
|
||||
for (size_t i = 0; i < outputs.size(); ++i) {
|
||||
(*nameOutputs)[i] = new char[outputs[i]->name.length() + 1];
|
||||
strncpy((*nameOutputs)[i], outputs[i]->name.c_str(), outputs[i]->name.length() + 1);
|
||||
(*dataOutputs)[i] = outputs[i]->data;
|
||||
(*lenOutputs)[i] = outputs[i]->size;
|
||||
}
|
||||
}
|
||||
|
||||
Source *OclocArgHelper::findSourceFile(const std::string &filename) {
|
||||
for (auto &source : inputs) {
|
||||
if (filename == source.name) {
|
||||
return &source;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool OclocArgHelper::sourceFileExists(const std::string &filename) const {
|
||||
for (auto &input : inputs) {
|
||||
if (filename == input.name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> OclocArgHelper::headersToVectorOfStrings() {
|
||||
std::vector<std::string> lines;
|
||||
for (auto &header : headers) {
|
||||
header.toVectorOfStrings(lines, true);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
void OclocArgHelper::readFileToVectorOfStrings(const std::string &filename, std::vector<std::string> &lines) {
|
||||
if (Source *s = findSourceFile(filename)) {
|
||||
s->toVectorOfStrings(lines);
|
||||
} else {
|
||||
::readFileToVectorOfStrings(lines, filename);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<char> OclocArgHelper::readBinaryFile(const std::string &filename) {
|
||||
if (Source *s = findSourceFile(filename)) {
|
||||
return s->toBinaryVector();
|
||||
} else {
|
||||
return ::readBinaryFile(filename);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> OclocArgHelper::loadDataFromFile(const std::string &filename, size_t &retSize) {
|
||||
if (Source *s = findSourceFile(filename)) {
|
||||
std::unique_ptr<char[]> ret(new char[static_cast<unsigned int>(s->length)]());
|
||||
memcpy(ret.get(), s->data, static_cast<size_t>(s->length));
|
||||
retSize = static_cast<size_t>(s->length);
|
||||
return ret;
|
||||
} else {
|
||||
return ::loadDataFromFile(filename.c_str(), retSize);
|
||||
}
|
||||
}
|
||||
|
||||
void OclocArgHelper::saveOutput(const std::string &filename, const void *pData, const size_t &dataSize) {
|
||||
if (outputEnabled()) {
|
||||
addOutput(filename, pData, dataSize);
|
||||
} else {
|
||||
writeDataToFile(filename.c_str(), pData, dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
void OclocArgHelper::saveOutput(const std::string &filename, std::ostream &stream) {
|
||||
std::stringstream ss;
|
||||
ss << stream.rdbuf();
|
||||
if (outputEnabled()) {
|
||||
addOutput(filename, ss.str().c_str(), ss.str().length());
|
||||
} else {
|
||||
std::ofstream file(filename);
|
||||
file << ss.str();
|
||||
}
|
||||
}
|
||||
77
shared/offline_compiler/source/ocloc_arg_helper.h
Normal file
77
shared/offline_compiler/source/ocloc_arg_helper.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#pragma once
|
||||
|
||||
struct Source {
|
||||
const uint8_t *data;
|
||||
const uint64_t length;
|
||||
const char *name;
|
||||
Source(const uint8_t *data, const uint64_t length, const char *name)
|
||||
: data(data), length(length), name(name){};
|
||||
void toVectorOfStrings(std::vector<std::string> &lines, bool replaceTabs = false);
|
||||
inline std::vector<char> toBinaryVector() {
|
||||
return std::vector<char>(data, data + length);
|
||||
};
|
||||
};
|
||||
|
||||
struct Output {
|
||||
std::string name;
|
||||
uint8_t *data;
|
||||
const size_t size;
|
||||
Output(const std::string &name, const void *data, const size_t &size);
|
||||
};
|
||||
|
||||
class OclocArgHelper {
|
||||
protected:
|
||||
std::vector<Source> inputs, headers;
|
||||
std::vector<Output *> outputs;
|
||||
uint32_t *numOutputs = nullptr;
|
||||
char ***nameOutputs = nullptr;
|
||||
uint8_t ***dataOutputs = nullptr;
|
||||
uint64_t **lenOutputs = nullptr;
|
||||
bool hasOutput = false;
|
||||
void moveOutputs();
|
||||
|
||||
Source *findSourceFile(const std::string &filename);
|
||||
bool sourceFileExists(const std::string &filename) const;
|
||||
|
||||
inline void addOutput(const std::string &filename, const void *data, const size_t &size) {
|
||||
outputs.push_back(new Output(filename, data, size));
|
||||
}
|
||||
|
||||
public:
|
||||
OclocArgHelper() = default;
|
||||
OclocArgHelper(const uint32_t numSources, const uint8_t **dataSources,
|
||||
const uint64_t *lenSources, const char **nameSources,
|
||||
const uint32_t numInputHeaders,
|
||||
const uint8_t **dataInputHeaders,
|
||||
const uint64_t *lenInputHeaders, const char **nameInputHeaders,
|
||||
uint32_t *numOutputs, uint8_t ***dataOutputs,
|
||||
uint64_t **lenOutputs, char ***nameOutputs);
|
||||
virtual ~OclocArgHelper();
|
||||
|
||||
MOCKABLE_VIRTUAL bool fileExists(const std::string &filename) const;
|
||||
|
||||
std::vector<std::string> headersToVectorOfStrings();
|
||||
void readFileToVectorOfStrings(const std::string &filename, std::vector<std::string> &lines);
|
||||
MOCKABLE_VIRTUAL std::vector<char> readBinaryFile(const std::string &filename);
|
||||
std::unique_ptr<char[]> loadDataFromFile(const std::string &filename, size_t &retSize);
|
||||
|
||||
inline bool outputEnabled() { return hasOutput; }
|
||||
inline bool hasHeaders() { return headers.size() > 0; }
|
||||
void saveOutput(const std::string &filename, const void *pData, const size_t &dataSize);
|
||||
void saveOutput(const std::string &filename, std::ostream &stream);
|
||||
|
||||
void addInput(const std::string &filename, std::stringstream &stream);
|
||||
};
|
||||
293
shared/offline_compiler/source/ocloc_fatbinary.cpp
Normal file
293
shared/offline_compiler/source/ocloc_fatbinary.cpp
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/ocloc_fatbinary.h"
|
||||
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
#include "shared/offline_compiler/source/utilities/safety_caller.h"
|
||||
#include "shared/source/device_binary_format/ar/ar_encoder.h"
|
||||
#include "shared/source/helpers/file_io.h"
|
||||
#include "shared/source/helpers/hw_info.h"
|
||||
|
||||
#include "compiler_options.h"
|
||||
#include "igfxfmid.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
namespace NEO {
|
||||
|
||||
bool requestedFatBinary(int argc, const char *argv[]) {
|
||||
for (int argIndex = 1; argIndex < argc; argIndex++) {
|
||||
const auto &currArg = argv[argIndex];
|
||||
const bool hasMoreArgs = (argIndex + 1 < argc);
|
||||
if ((ConstStringRef("-device") == currArg) && hasMoreArgs) {
|
||||
ConstStringRef deviceArg(argv[argIndex + 1], strlen(argv[argIndex + 1]));
|
||||
return deviceArg.contains("*") || deviceArg.contains("-") || deviceArg.contains(",") || deviceArg.contains("gen");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<PRODUCT_FAMILY> getAllSupportedTargetPlatforms() {
|
||||
return std::vector<PRODUCT_FAMILY>{ALL_SUPPORTED_PRODUCT_FAMILIES};
|
||||
}
|
||||
|
||||
std::vector<ConstStringRef> toProductNames(const std::vector<PRODUCT_FAMILY> &productIds) {
|
||||
std::vector<ConstStringRef> ret;
|
||||
for (auto prodId : productIds) {
|
||||
ret.push_back(ConstStringRef(hardwarePrefix[prodId], strlen(hardwarePrefix[prodId])));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
PRODUCT_FAMILY asProductId(ConstStringRef product, const std::vector<PRODUCT_FAMILY> &allSupportedPlatforms) {
|
||||
for (auto family : allSupportedPlatforms) {
|
||||
if (product == hardwarePrefix[family]) {
|
||||
return family;
|
||||
}
|
||||
}
|
||||
return IGFX_UNKNOWN;
|
||||
}
|
||||
|
||||
GFXCORE_FAMILY asGfxCoreId(ConstStringRef core) {
|
||||
ConstStringRef coreIgnoreG(core.begin() + 1, core.size() - 1);
|
||||
for (unsigned int coreId = 0; coreId < IGFX_MAX_CORE; ++coreId) {
|
||||
if (nullptr == familyName[coreId]) {
|
||||
continue;
|
||||
}
|
||||
if (ConstStringRef(familyName[coreId] + 1, strlen(familyName[coreId]) - 1) == coreIgnoreG) {
|
||||
return static_cast<GFXCORE_FAMILY>(coreId);
|
||||
}
|
||||
}
|
||||
|
||||
return IGFX_UNKNOWN_CORE;
|
||||
}
|
||||
|
||||
void appendPlatformsForGfxCore(GFXCORE_FAMILY core, const std::vector<PRODUCT_FAMILY> &allSupportedPlatforms, std::vector<PRODUCT_FAMILY> &out) {
|
||||
for (auto family : allSupportedPlatforms) {
|
||||
if (core == hardwareInfoTable[family]->platform.eRenderCoreFamily) {
|
||||
out.push_back(family);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ConstStringRef> getTargetPlatformsForFatbinary(ConstStringRef deviceArg) {
|
||||
std::vector<PRODUCT_FAMILY> allSupportedPlatforms = getAllSupportedTargetPlatforms();
|
||||
if (deviceArg == "*") {
|
||||
return toProductNames(allSupportedPlatforms);
|
||||
}
|
||||
|
||||
auto genArg = ConstStringRef("gen");
|
||||
|
||||
std::vector<PRODUCT_FAMILY> requestedPlatforms;
|
||||
auto sets = CompilerOptions::tokenize(deviceArg, ',');
|
||||
for (auto set : sets) {
|
||||
if (set.contains("-")) {
|
||||
auto range = CompilerOptions::tokenize(deviceArg, '-');
|
||||
if (range.size() > 2) {
|
||||
printf("Invalid range : %s - should be from-to or -to or from-\n", set.str().c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
if (range.size() == 1) {
|
||||
// open range , from-max or min-to
|
||||
if (range[0].contains("gen")) {
|
||||
auto coreId = asGfxCoreId(range[0]);
|
||||
if (IGFX_UNKNOWN_CORE == coreId) {
|
||||
printf("Unknown device : %s\n", set.str().c_str());
|
||||
return {};
|
||||
}
|
||||
if ('-' == set[0]) {
|
||||
// to
|
||||
unsigned int coreIt = IGFX_UNKNOWN_CORE;
|
||||
++coreIt;
|
||||
while (coreIt <= static_cast<unsigned int>(coreId)) {
|
||||
appendPlatformsForGfxCore(static_cast<GFXCORE_FAMILY>(coreIt), allSupportedPlatforms, requestedPlatforms);
|
||||
++coreIt;
|
||||
}
|
||||
} else {
|
||||
// from
|
||||
unsigned int coreIt = coreId;
|
||||
while (coreIt < static_cast<unsigned int>(IGFX_MAX_CORE)) {
|
||||
appendPlatformsForGfxCore(static_cast<GFXCORE_FAMILY>(coreIt), allSupportedPlatforms, requestedPlatforms);
|
||||
++coreIt;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto prodId = asProductId(range[0], allSupportedPlatforms);
|
||||
if (IGFX_UNKNOWN == prodId) {
|
||||
printf("Unknown device : %s\n", range[0].str().c_str());
|
||||
return {};
|
||||
}
|
||||
auto prodIt = std::find(allSupportedPlatforms.begin(), allSupportedPlatforms.end(), prodId);
|
||||
assert(prodIt != allSupportedPlatforms.end());
|
||||
if ('-' == set[0]) {
|
||||
// to
|
||||
requestedPlatforms.insert(requestedPlatforms.end(), allSupportedPlatforms.begin(), prodIt + 1);
|
||||
} else {
|
||||
// from
|
||||
requestedPlatforms.insert(requestedPlatforms.end(), prodIt, allSupportedPlatforms.end());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (range[0].contains("gen")) {
|
||||
if (false == range[1].contains("gen")) {
|
||||
printf("Ranges mixing platforms and gfxCores is not supported : %s - should be genFrom-genTo or platformFrom-platformTo\n", set.str().c_str());
|
||||
return {};
|
||||
}
|
||||
auto coreFrom = asGfxCoreId(range[0]);
|
||||
auto coreTo = asGfxCoreId(range[1]);
|
||||
if (IGFX_UNKNOWN_CORE == coreFrom) {
|
||||
printf("Unknown device : %s\n", set.str().c_str());
|
||||
return {};
|
||||
}
|
||||
if (IGFX_UNKNOWN_CORE == coreTo) {
|
||||
printf("Unknown device : %s\n", set.str().c_str());
|
||||
return {};
|
||||
}
|
||||
if (coreFrom > coreTo) {
|
||||
std::swap(coreFrom, coreTo);
|
||||
}
|
||||
while (coreFrom <= coreTo) {
|
||||
appendPlatformsForGfxCore(static_cast<GFXCORE_FAMILY>(coreFrom), allSupportedPlatforms, requestedPlatforms);
|
||||
coreFrom = static_cast<GFXCORE_FAMILY>(static_cast<unsigned int>(coreFrom) + 1);
|
||||
}
|
||||
} else {
|
||||
auto platformFrom = asProductId(range[0], allSupportedPlatforms);
|
||||
auto platformTo = asProductId(range[1], allSupportedPlatforms);
|
||||
if (IGFX_UNKNOWN == platformFrom) {
|
||||
printf("Unknown device : %s\n", set.str().c_str());
|
||||
return {};
|
||||
}
|
||||
if (IGFX_UNKNOWN == platformTo) {
|
||||
printf("Unknown device : %s\n", set.str().c_str());
|
||||
return {};
|
||||
}
|
||||
if (platformFrom > platformTo) {
|
||||
std::swap(platformFrom, platformTo);
|
||||
}
|
||||
|
||||
auto from = std::find(allSupportedPlatforms.begin(), allSupportedPlatforms.end(), platformFrom);
|
||||
auto to = std::find(allSupportedPlatforms.begin(), allSupportedPlatforms.end(), platformTo) + 1;
|
||||
requestedPlatforms.insert(requestedPlatforms.end(), from, to);
|
||||
}
|
||||
}
|
||||
} else if (set.contains("gen")) {
|
||||
if (set.size() == genArg.size()) {
|
||||
printf("Invalid gen-based device : %s - gen should be followed by a number\n", set.str().c_str());
|
||||
} else {
|
||||
auto coreId = asGfxCoreId(set);
|
||||
if (IGFX_UNKNOWN_CORE == coreId) {
|
||||
printf("Unknown device : %s\n", set.str().c_str());
|
||||
return {};
|
||||
}
|
||||
appendPlatformsForGfxCore(coreId, allSupportedPlatforms, requestedPlatforms);
|
||||
}
|
||||
} else {
|
||||
auto prodId = asProductId(set, allSupportedPlatforms);
|
||||
if (IGFX_UNKNOWN == prodId) {
|
||||
printf("Unknown device : %s\n", set.str().c_str());
|
||||
return {};
|
||||
}
|
||||
requestedPlatforms.push_back(prodId);
|
||||
}
|
||||
}
|
||||
return toProductNames(requestedPlatforms);
|
||||
}
|
||||
|
||||
int buildFatbinary(int argc, const char *argv[]) {
|
||||
std::string pointerSizeInBits = (sizeof(void *) == 4) ? "32" : "64";
|
||||
int deviceArgIndex = -1;
|
||||
std::string inputFileName = "";
|
||||
std::string outputFileName = "";
|
||||
std::string outputDirectory = "";
|
||||
|
||||
std::vector<std::string> argsCopy;
|
||||
if (argc > 1) {
|
||||
argsCopy.assign(argv, argv + argc);
|
||||
}
|
||||
|
||||
for (int argIndex = 1; argIndex < argc; argIndex++) {
|
||||
const auto &currArg = argv[argIndex];
|
||||
const bool hasMoreArgs = (argIndex + 1 < argc);
|
||||
if ((ConstStringRef("-device") == currArg) && hasMoreArgs) {
|
||||
deviceArgIndex = argIndex + 1;
|
||||
++argIndex;
|
||||
} else if ((CompilerOptions::arch32bit == currArg) || (ConstStringRef("-32") == currArg)) {
|
||||
pointerSizeInBits = "32";
|
||||
} else if ((CompilerOptions::arch64bit == currArg) || (ConstStringRef("-64") == currArg)) {
|
||||
pointerSizeInBits = "64";
|
||||
} else if ((ConstStringRef("-file") == currArg) && hasMoreArgs) {
|
||||
inputFileName = argv[argIndex + 1];
|
||||
++argIndex;
|
||||
} else if ((ConstStringRef("-output") == currArg) && hasMoreArgs) {
|
||||
outputFileName = argv[argIndex + 1];
|
||||
++argIndex;
|
||||
} else if ((ConstStringRef("-out_dir") == currArg) && hasMoreArgs) {
|
||||
outputDirectory = argv[argIndex + 1];
|
||||
++argIndex;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ConstStringRef> targetPlatforms;
|
||||
targetPlatforms = getTargetPlatformsForFatbinary(ConstStringRef(argv[deviceArgIndex], strlen(argv[deviceArgIndex])));
|
||||
if (targetPlatforms.empty()) {
|
||||
printf("Failed to parse target devices from : %s\n", argv[deviceArgIndex]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NEO::Ar::ArEncoder fatbinary(true);
|
||||
|
||||
for (auto targetPlatform : targetPlatforms) {
|
||||
int retVal = 0;
|
||||
argsCopy[deviceArgIndex] = targetPlatform.str();
|
||||
std::unique_ptr<OfflineCompiler> pCompiler{OfflineCompiler::create(argc, argsCopy, false, retVal)};
|
||||
auto stepping = pCompiler->getHardwareInfo().platform.usRevId;
|
||||
if (retVal == 0) {
|
||||
retVal = buildWithSafetyGuard(pCompiler.get());
|
||||
|
||||
std::string buildLog = pCompiler->getBuildLog();
|
||||
if (buildLog.empty() == false) {
|
||||
printf("%s\n", buildLog.c_str());
|
||||
}
|
||||
|
||||
if (retVal == 0) {
|
||||
if (!pCompiler->isQuiet())
|
||||
printf("Build succeeded for : %s.\n", (targetPlatform.str() + "." + std::to_string(stepping)).c_str());
|
||||
} else {
|
||||
printf("Build failed for : %s with error code: %d\n", (targetPlatform.str() + "." + std::to_string(stepping)).c_str(), retVal);
|
||||
printf("Command was:");
|
||||
for (auto i = 0; i < argc; ++i)
|
||||
printf(" %s", argv[i]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != retVal) {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
fatbinary.appendFileEntry(pointerSizeInBits + "." + targetPlatform.str() + "." + std::to_string(stepping), pCompiler->getPackedDeviceBinaryOutput());
|
||||
}
|
||||
|
||||
auto fatbinaryData = fatbinary.encode();
|
||||
std::string fatbinaryFileName = outputFileName;
|
||||
if (outputFileName.empty() && (false == inputFileName.empty())) {
|
||||
fatbinaryFileName = OfflineCompiler::getFileNameTrunk(inputFileName) + ".ar";
|
||||
}
|
||||
if (false == outputDirectory.empty()) {
|
||||
fatbinaryFileName = outputDirectory + "/" + outputFileName;
|
||||
}
|
||||
writeDataToFile(fatbinaryFileName.c_str(), fatbinaryData.data(), fatbinaryData.size());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace NEO
|
||||
29
shared/offline_compiler/source/ocloc_fatbinary.h
Normal file
29
shared/offline_compiler/source/ocloc_fatbinary.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared/source/utilities/const_stringref.h"
|
||||
|
||||
#include "igfxfmid.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace NEO {
|
||||
|
||||
bool requestedFatBinary(int argc, const char *argv[]);
|
||||
|
||||
int buildFatbinary(int argc, const char *argv[]);
|
||||
|
||||
std::vector<PRODUCT_FAMILY> getAllSupportedTargetPlatforms();
|
||||
std::vector<ConstStringRef> toProductNames(const std::vector<PRODUCT_FAMILY> &productIds);
|
||||
PRODUCT_FAMILY asProductId(ConstStringRef product, const std::vector<PRODUCT_FAMILY> &allSupportedPlatforms);
|
||||
GFXCORE_FAMILY asGfxCoreId(ConstStringRef core);
|
||||
void appendPlatformsForGfxCore(GFXCORE_FAMILY core, const std::vector<PRODUCT_FAMILY> &allSupportedPlatforms, std::vector<PRODUCT_FAMILY> &out);
|
||||
std::vector<ConstStringRef> getTargetPlatformsForFatbinary(ConstStringRef deviceArg);
|
||||
|
||||
} // namespace NEO
|
||||
90
shared/offline_compiler/source/ocloc_wrapper.cpp
Normal file
90
shared/offline_compiler/source/ocloc_wrapper.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ocloc_wrapper.h"
|
||||
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
|
||||
#include "utilities/get_path.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
typedef int (*pOclocInvoke)(
|
||||
unsigned int numArgs, const char *argv[],
|
||||
const uint32_t numSources, const uint8_t **dataSources, const uint64_t *lenSources, const char **nameSources,
|
||||
const uint32_t numInputHeaders, const uint8_t **dataInputHeaders, const uint64_t *lenInputHeaders, const char **nameInputHeaders,
|
||||
uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs);
|
||||
|
||||
typedef int (*pOclocFreeOutput)(
|
||||
uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs);
|
||||
|
||||
struct OclocLibrary {
|
||||
pOclocInvoke invoke = nullptr;
|
||||
pOclocFreeOutput freeOutput = nullptr;
|
||||
|
||||
std::unique_ptr<NEO::OsLibrary> library;
|
||||
bool isLoaded() {
|
||||
return library != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
OclocWrapper::OclocWrapper() : pImpl(std::make_unique<Impl>()){};
|
||||
OclocWrapper::~OclocWrapper() = default;
|
||||
|
||||
struct OclocWrapper::Impl {
|
||||
OclocLibrary oclocLib;
|
||||
|
||||
void loadOcloc() {
|
||||
OclocLibrary ocloc;
|
||||
std::string oclocLibName = "";
|
||||
ocloc.library.reset(NEO::OsLibrary::load(oclocLibName));
|
||||
if (nullptr == (ocloc.invoke = reinterpret_cast<pOclocInvoke>(ocloc.library->getProcAddress("oclocInvoke")))) {
|
||||
std::cout << "Error! Couldn't find OclocInvoke function.\n";
|
||||
return;
|
||||
}
|
||||
if (nullptr == (ocloc.freeOutput = reinterpret_cast<pOclocFreeOutput>(ocloc.library->getProcAddress("oclocFreeOutput")))) {
|
||||
std::cout << "Error! Couldn't find OclocFreeOutput function.\n";
|
||||
return;
|
||||
}
|
||||
this->oclocLib = std::move(ocloc);
|
||||
}
|
||||
};
|
||||
|
||||
int OclocWrapper::invokeOcloc(unsigned int numArgs, const char *argv[]) {
|
||||
return invokeOcloc(numArgs, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
int OclocWrapper::invokeOcloc(unsigned int numArgs, const char *argv[],
|
||||
const uint32_t numSources, const uint8_t **dataSources, const uint64_t *lenSources, const char **nameSources,
|
||||
const uint32_t numInputHeaders, const uint8_t **dataInputHeaders, const uint64_t *lenInputHeaders, const char **nameInputHeaders,
|
||||
uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs) {
|
||||
if (false == tryLoadOcloc()) {
|
||||
std::cout << "Error! Ocloc Library couldn't be loaded.\n";
|
||||
return -1;
|
||||
}
|
||||
return pImpl->oclocLib.invoke(numArgs, argv,
|
||||
numSources, dataSources, lenSources, nameSources,
|
||||
numInputHeaders, dataInputHeaders, lenInputHeaders, nameInputHeaders,
|
||||
numOutputs, dataOutputs, lenOutputs, nameOutputs);
|
||||
}
|
||||
|
||||
int OclocWrapper::freeOutput(uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs) {
|
||||
if (false == tryLoadOcloc()) {
|
||||
std::cout << "Error! Ocloc Library couldn't be loaded.\n";
|
||||
return -1;
|
||||
}
|
||||
return pImpl->oclocLib.freeOutput(numOutputs, dataOutputs, lenOutputs, nameOutputs);
|
||||
}
|
||||
|
||||
bool OclocWrapper::tryLoadOcloc() {
|
||||
if (false == pImpl->oclocLib.isLoaded()) {
|
||||
pImpl->loadOcloc();
|
||||
}
|
||||
return pImpl->oclocLib.isLoaded();
|
||||
}
|
||||
33
shared/offline_compiler/source/ocloc_wrapper.h
Normal file
33
shared/offline_compiler/source/ocloc_wrapper.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
struct OclocWrapper {
|
||||
public:
|
||||
OclocWrapper();
|
||||
~OclocWrapper();
|
||||
|
||||
OclocWrapper(OclocWrapper &) = delete;
|
||||
OclocWrapper(const OclocWrapper &&) = delete;
|
||||
OclocWrapper &operator=(const OclocWrapper &) = delete;
|
||||
OclocWrapper &operator=(OclocWrapper &&) = delete;
|
||||
|
||||
int invokeOcloc(unsigned int numArgs, const char *argv[]);
|
||||
int invokeOcloc(unsigned int numArgs, const char *argv[],
|
||||
const uint32_t numSources, const uint8_t **dataSources, const uint64_t *lenSources, const char **nameSources,
|
||||
const uint32_t numInputHeaders, const uint8_t **dataInputHeaders, const uint64_t *lenInputHeaders, const char **nameInputHeaders,
|
||||
uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs);
|
||||
int freeOutput(uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs);
|
||||
|
||||
protected:
|
||||
bool tryLoadOcloc();
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
};
|
||||
931
shared/offline_compiler/source/offline_compiler.cpp
Normal file
931
shared/offline_compiler/source/offline_compiler.cpp
Normal file
@@ -0,0 +1,931 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "offline_compiler.h"
|
||||
|
||||
#include "shared/source/debug_settings/debug_settings_manager.h"
|
||||
#include "shared/source/device_binary_format/device_binary_formats.h"
|
||||
#include "shared/source/device_binary_format/elf/elf_encoder.h"
|
||||
#include "shared/source/device_binary_format/elf/ocl_elf.h"
|
||||
#include "shared/source/helpers/debug_helpers.h"
|
||||
#include "shared/source/helpers/file_io.h"
|
||||
#include "shared/source/helpers/hw_info.h"
|
||||
#include "shared/source/helpers/string.h"
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
|
||||
#include "opencl/source/helpers/validators.h"
|
||||
#include "opencl/source/os_interface/os_inc_base.h"
|
||||
#include "opencl/source/platform/extensions.h"
|
||||
|
||||
#include "cif/common/cif_main.h"
|
||||
#include "cif/helpers/error.h"
|
||||
#include "cif/import/library_api.h"
|
||||
#include "compiler_options.h"
|
||||
#include "igfxfmid.h"
|
||||
#include "ocl_igc_interface/code_type.h"
|
||||
#include "ocl_igc_interface/fcl_ocl_device_ctx.h"
|
||||
#include "ocl_igc_interface/igc_ocl_device_ctx.h"
|
||||
#include "ocl_igc_interface/platform_helper.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#define MakeDirectory _mkdir
|
||||
#define GetCurrentWorkingDirectory _getcwd
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#define MakeDirectory(dir) mkdir(dir, 0777)
|
||||
#define GetCurrentWorkingDirectory getcwd
|
||||
#endif
|
||||
|
||||
namespace NEO {
|
||||
|
||||
CIF::CIFMain *createMainNoSanitize(CIF::CreateCIFMainFunc_t createFunc);
|
||||
|
||||
std::string convertToPascalCase(const std::string &inString) {
|
||||
std::string outString;
|
||||
bool capitalize = true;
|
||||
|
||||
for (unsigned int i = 0; i < inString.length(); i++) {
|
||||
if (isalpha(inString[i]) && capitalize == true) {
|
||||
outString += toupper(inString[i]);
|
||||
capitalize = false;
|
||||
} else if (inString[i] == '_') {
|
||||
capitalize = true;
|
||||
} else {
|
||||
outString += inString[i];
|
||||
}
|
||||
}
|
||||
return outString;
|
||||
}
|
||||
|
||||
OfflineCompiler::OfflineCompiler() = default;
|
||||
OfflineCompiler::~OfflineCompiler() {
|
||||
delete[] irBinary;
|
||||
delete[] genBinary;
|
||||
}
|
||||
|
||||
OfflineCompiler *OfflineCompiler::create(size_t numArgs, const std::vector<std::string> &allArgs, bool dumpFiles, int &retVal) {
|
||||
retVal = CL_SUCCESS;
|
||||
auto pOffCompiler = new OfflineCompiler();
|
||||
|
||||
if (pOffCompiler) {
|
||||
pOffCompiler->argHelper = std::make_unique<OclocArgHelper>();
|
||||
retVal = pOffCompiler->initialize(numArgs, allArgs, dumpFiles);
|
||||
}
|
||||
|
||||
if (retVal != CL_SUCCESS) {
|
||||
delete pOffCompiler;
|
||||
pOffCompiler = nullptr;
|
||||
}
|
||||
|
||||
return pOffCompiler;
|
||||
}
|
||||
|
||||
OfflineCompiler *OfflineCompiler::create(size_t numArgs, const std::vector<std::string> &allArgs, bool dumpFiles, int &retVal, std::unique_ptr<OclocArgHelper> helper) {
|
||||
retVal = CL_SUCCESS;
|
||||
auto pOffCompiler = new OfflineCompiler();
|
||||
|
||||
if (pOffCompiler) {
|
||||
pOffCompiler->argHelper = std::move(helper);
|
||||
retVal = pOffCompiler->initialize(numArgs, allArgs, dumpFiles);
|
||||
}
|
||||
|
||||
if (retVal != CL_SUCCESS) {
|
||||
delete pOffCompiler;
|
||||
pOffCompiler = nullptr;
|
||||
}
|
||||
|
||||
return pOffCompiler;
|
||||
}
|
||||
|
||||
int OfflineCompiler::buildSourceCode() {
|
||||
int retVal = CL_SUCCESS;
|
||||
|
||||
do {
|
||||
if (strcmp(sourceCode.c_str(), "") == 0) {
|
||||
retVal = CL_INVALID_PROGRAM;
|
||||
break;
|
||||
}
|
||||
UNRECOVERABLE_IF(igcDeviceCtx == nullptr);
|
||||
|
||||
CIF::RAII::UPtr_t<IGC::OclTranslationOutputTagOCL> igcOutput;
|
||||
bool inputIsIntermediateRepresentation = inputFileLlvm || inputFileSpirV;
|
||||
if (false == inputIsIntermediateRepresentation) {
|
||||
UNRECOVERABLE_IF(fclDeviceCtx == nullptr);
|
||||
IGC::CodeType::CodeType_t intermediateRepresentation = useLlvmText ? IGC::CodeType::llvmLl
|
||||
: (useLlvmBc ? IGC::CodeType::llvmBc : preferredIntermediateRepresentation);
|
||||
// sourceCode.size() returns the number of characters without null terminated char
|
||||
auto fclSrc = CIF::Builtins::CreateConstBuffer(fclMain.get(), sourceCode.c_str(), sourceCode.size() + 1);
|
||||
auto fclOptions = CIF::Builtins::CreateConstBuffer(fclMain.get(), options.c_str(), options.size());
|
||||
auto fclInternalOptions = CIF::Builtins::CreateConstBuffer(fclMain.get(), internalOptions.c_str(), internalOptions.size());
|
||||
|
||||
auto fclTranslationCtx = fclDeviceCtx->CreateTranslationCtx(IGC::CodeType::oclC, intermediateRepresentation);
|
||||
auto igcTranslationCtx = igcDeviceCtx->CreateTranslationCtx(intermediateRepresentation, IGC::CodeType::oclGenBin);
|
||||
|
||||
if (false == NEO::areNotNullptr(fclSrc.get(), fclOptions.get(), fclInternalOptions.get(),
|
||||
fclTranslationCtx.get(), igcTranslationCtx.get())) {
|
||||
retVal = CL_OUT_OF_HOST_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
auto fclOutput = fclTranslationCtx->Translate(fclSrc.get(), fclOptions.get(),
|
||||
fclInternalOptions.get(), nullptr, 0);
|
||||
|
||||
if (fclOutput == nullptr) {
|
||||
retVal = CL_OUT_OF_HOST_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
UNRECOVERABLE_IF(fclOutput->GetBuildLog() == nullptr);
|
||||
UNRECOVERABLE_IF(fclOutput->GetOutput() == nullptr);
|
||||
|
||||
if (fclOutput->Successful() == false) {
|
||||
updateBuildLog(fclOutput->GetBuildLog()->GetMemory<char>(), fclOutput->GetBuildLog()->GetSizeRaw());
|
||||
retVal = CL_BUILD_PROGRAM_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
storeBinary(irBinary, irBinarySize, fclOutput->GetOutput()->GetMemory<char>(), fclOutput->GetOutput()->GetSizeRaw());
|
||||
isSpirV = intermediateRepresentation == IGC::CodeType::spirV;
|
||||
updateBuildLog(fclOutput->GetBuildLog()->GetMemory<char>(), fclOutput->GetBuildLog()->GetSizeRaw());
|
||||
|
||||
igcOutput = igcTranslationCtx->Translate(fclOutput->GetOutput(), fclOptions.get(),
|
||||
fclInternalOptions.get(),
|
||||
nullptr, 0);
|
||||
|
||||
} else {
|
||||
auto igcSrc = CIF::Builtins::CreateConstBuffer(igcMain.get(), sourceCode.c_str(), sourceCode.size());
|
||||
auto igcOptions = CIF::Builtins::CreateConstBuffer(igcMain.get(), options.c_str(), options.size());
|
||||
auto igcInternalOptions = CIF::Builtins::CreateConstBuffer(igcMain.get(), internalOptions.c_str(), internalOptions.size());
|
||||
auto igcTranslationCtx = igcDeviceCtx->CreateTranslationCtx(inputFileSpirV ? IGC::CodeType::spirV : IGC::CodeType::llvmBc, IGC::CodeType::oclGenBin);
|
||||
igcOutput = igcTranslationCtx->Translate(igcSrc.get(), igcOptions.get(), igcInternalOptions.get(), nullptr, 0);
|
||||
}
|
||||
if (igcOutput == nullptr) {
|
||||
retVal = CL_OUT_OF_HOST_MEMORY;
|
||||
break;
|
||||
}
|
||||
UNRECOVERABLE_IF(igcOutput->GetBuildLog() == nullptr);
|
||||
UNRECOVERABLE_IF(igcOutput->GetOutput() == nullptr);
|
||||
updateBuildLog(igcOutput->GetBuildLog()->GetMemory<char>(), igcOutput->GetBuildLog()->GetSizeRaw());
|
||||
|
||||
if (igcOutput->GetOutput()->GetSizeRaw() != 0) {
|
||||
storeBinary(genBinary, genBinarySize, igcOutput->GetOutput()->GetMemory<char>(), igcOutput->GetOutput()->GetSizeRaw());
|
||||
}
|
||||
if (igcOutput->GetDebugData()->GetSizeRaw() != 0) {
|
||||
storeBinary(debugDataBinary, debugDataBinarySize, igcOutput->GetDebugData()->GetMemory<char>(), igcOutput->GetDebugData()->GetSizeRaw());
|
||||
}
|
||||
retVal = igcOutput->Successful() ? CL_SUCCESS : CL_BUILD_PROGRAM_FAILURE;
|
||||
} while (0);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int OfflineCompiler::build() {
|
||||
int retVal = CL_SUCCESS;
|
||||
|
||||
retVal = buildSourceCode();
|
||||
|
||||
if (retVal == CL_SUCCESS) {
|
||||
generateElfBinary();
|
||||
if (dumpFiles) {
|
||||
writeOutAllFiles();
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void OfflineCompiler::updateBuildLog(const char *pErrorString, const size_t errorStringSize) {
|
||||
std::string errorString = (errorStringSize && pErrorString) ? std::string(pErrorString, pErrorString + errorStringSize) : "";
|
||||
if (errorString[0] != '\0') {
|
||||
if (buildLog.empty()) {
|
||||
buildLog.assign(errorString);
|
||||
} else {
|
||||
buildLog.append("\n" + errorString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string &OfflineCompiler::getBuildLog() {
|
||||
return buildLog;
|
||||
}
|
||||
|
||||
int OfflineCompiler::getHardwareInfo(const char *pDeviceName) {
|
||||
int retVal = CL_INVALID_DEVICE;
|
||||
|
||||
for (unsigned int productId = 0; productId < IGFX_MAX_PRODUCT; ++productId) {
|
||||
if (hardwarePrefix[productId] && (0 == strcmp(pDeviceName, hardwarePrefix[productId]))) {
|
||||
if (hardwareInfoTable[productId]) {
|
||||
hwInfo = hardwareInfoTable[productId];
|
||||
familyNameWithType.clear();
|
||||
familyNameWithType.append(familyName[hwInfo->platform.eRenderCoreFamily]);
|
||||
familyNameWithType.append(hwInfo->capabilityTable.platformType);
|
||||
retVal = CL_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
std::string OfflineCompiler::getStringWithinDelimiters(const std::string &src) {
|
||||
size_t start = src.find("R\"===(");
|
||||
size_t stop = src.find(")===\"");
|
||||
|
||||
DEBUG_BREAK_IF(std::string::npos == start);
|
||||
DEBUG_BREAK_IF(std::string::npos == stop);
|
||||
|
||||
start += strlen("R\"===(");
|
||||
size_t size = stop - start;
|
||||
|
||||
std::string dst(src, start, size + 1);
|
||||
dst[size] = '\0'; // put null char at the end
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
int OfflineCompiler::initialize(size_t numArgs, const std::vector<std::string> &allArgs, bool dumpFiles) {
|
||||
this->dumpFiles = dumpFiles;
|
||||
int retVal = CL_SUCCESS;
|
||||
const char *source = nullptr;
|
||||
std::unique_ptr<char[]> sourceFromFile;
|
||||
size_t sourceFromFileSize = 0;
|
||||
|
||||
retVal = parseCommandLine(numArgs, allArgs);
|
||||
if (retVal != CL_SUCCESS) {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
if (options.empty()) {
|
||||
// try to read options from file if not provided by commandline
|
||||
size_t ext_start = inputFile.find(".cl");
|
||||
if (ext_start != std::string::npos) {
|
||||
std::string oclocOptionsFileName = inputFile.substr(0, ext_start);
|
||||
oclocOptionsFileName.append("_ocloc_options.txt");
|
||||
|
||||
std::string oclocOptionsFromFile;
|
||||
bool oclocOptionsRead = readOptionsFromFile(oclocOptionsFromFile, oclocOptionsFileName, argHelper);
|
||||
if (oclocOptionsRead && !isQuiet()) {
|
||||
printf("Building with ocloc options:\n%s\n", oclocOptionsFromFile.c_str());
|
||||
}
|
||||
|
||||
if (oclocOptionsRead) {
|
||||
std::istringstream iss(allArgs[0] + " " + oclocOptionsFromFile);
|
||||
std::vector<std::string> tokens{
|
||||
std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};
|
||||
|
||||
retVal = parseCommandLine(tokens.size(), tokens);
|
||||
if (retVal != CL_SUCCESS) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
std::string optionsFileName = inputFile.substr(0, ext_start);
|
||||
optionsFileName.append("_options.txt");
|
||||
|
||||
bool optionsRead = readOptionsFromFile(options, optionsFileName, argHelper);
|
||||
if (optionsRead && !isQuiet()) {
|
||||
printf("Building with options:\n%s\n", options.c_str());
|
||||
}
|
||||
|
||||
std::string internalOptionsFileName = inputFile.substr(0, ext_start);
|
||||
internalOptionsFileName.append("_internal_options.txt");
|
||||
|
||||
std::string internalOptionsFromFile;
|
||||
bool internalOptionsRead = readOptionsFromFile(internalOptionsFromFile, internalOptionsFileName, argHelper);
|
||||
if (internalOptionsRead && !isQuiet()) {
|
||||
printf("Building with internal options:\n%s\n", internalOptionsFromFile.c_str());
|
||||
}
|
||||
CompilerOptions::concatenateAppend(internalOptions, internalOptionsFromFile);
|
||||
}
|
||||
}
|
||||
|
||||
parseDebugSettings();
|
||||
|
||||
// set up the device inside the program
|
||||
sourceFromFile = argHelper->loadDataFromFile(inputFile, sourceFromFileSize);
|
||||
if (sourceFromFileSize == 0) {
|
||||
retVal = INVALID_FILE;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
if (inputFileLlvm || inputFileSpirV) {
|
||||
// use the binary input "as is"
|
||||
sourceCode.assign(sourceFromFile.get(), sourceFromFileSize);
|
||||
} else {
|
||||
// for text input, we also accept files used as runtime builtins
|
||||
source = strstr((const char *)sourceFromFile.get(), "R\"===(");
|
||||
sourceCode = (source != nullptr) ? getStringWithinDelimiters(sourceFromFile.get()) : sourceFromFile.get();
|
||||
}
|
||||
|
||||
if ((inputFileSpirV == false) && (inputFileLlvm == false)) {
|
||||
auto fclLibFile = OsLibrary::load(Os::frontEndDllName);
|
||||
if (fclLibFile == nullptr) {
|
||||
printf("Error: Failed to load %s\n", Os::frontEndDllName);
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
this->fclLib.reset(fclLibFile);
|
||||
if (this->fclLib == nullptr) {
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
auto fclCreateMain = reinterpret_cast<CIF::CreateCIFMainFunc_t>(this->fclLib->getProcAddress(CIF::CreateCIFMainFuncName));
|
||||
if (fclCreateMain == nullptr) {
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
this->fclMain = CIF::RAII::UPtr(createMainNoSanitize(fclCreateMain));
|
||||
if (this->fclMain == nullptr) {
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
if (false == this->fclMain->IsCompatible<IGC::FclOclDeviceCtx>()) {
|
||||
printf("Incompatible interface in FCL : %s\n", CIF::InterfaceIdCoder::Dec(this->fclMain->FindIncompatible<IGC::FclOclDeviceCtx>()).c_str());
|
||||
DEBUG_BREAK_IF(true);
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
this->fclDeviceCtx = this->fclMain->CreateInterface<IGC::FclOclDeviceCtxTagOCL>();
|
||||
if (this->fclDeviceCtx == nullptr) {
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
fclDeviceCtx->SetOclApiVersion(hwInfo->capabilityTable.clVersionSupport * 10);
|
||||
preferredIntermediateRepresentation = fclDeviceCtx->GetPreferredIntermediateRepresentation();
|
||||
} else {
|
||||
if (!isQuiet()) {
|
||||
printf("Compilation from IR - skipping loading of FCL\n");
|
||||
}
|
||||
preferredIntermediateRepresentation = IGC::CodeType::spirV;
|
||||
}
|
||||
|
||||
this->igcLib.reset(OsLibrary::load(Os::igcDllName));
|
||||
if (this->igcLib == nullptr) {
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
auto igcCreateMain = reinterpret_cast<CIF::CreateCIFMainFunc_t>(this->igcLib->getProcAddress(CIF::CreateCIFMainFuncName));
|
||||
if (igcCreateMain == nullptr) {
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
this->igcMain = CIF::RAII::UPtr(createMainNoSanitize(igcCreateMain));
|
||||
if (this->igcMain == nullptr) {
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
std::vector<CIF::InterfaceId_t> interfacesToIgnore = {IGC::OclGenBinaryBase::GetInterfaceId()};
|
||||
if (false == this->igcMain->IsCompatible<IGC::IgcOclDeviceCtx>(&interfacesToIgnore)) {
|
||||
printf("Incompatible interface in IGC : %s\n", CIF::InterfaceIdCoder::Dec(this->igcMain->FindIncompatible<IGC::IgcOclDeviceCtx>(&interfacesToIgnore)).c_str());
|
||||
DEBUG_BREAK_IF(true);
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
CIF::Version_t verMin = 0, verMax = 0;
|
||||
if (false == this->igcMain->FindSupportedVersions<IGC::IgcOclDeviceCtx>(IGC::OclGenBinaryBase::GetInterfaceId(), verMin, verMax)) {
|
||||
printf("Patchtoken interface is missing");
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
this->igcDeviceCtx = this->igcMain->CreateInterface<IGC::IgcOclDeviceCtxTagOCL>();
|
||||
if (this->igcDeviceCtx == nullptr) {
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
this->igcDeviceCtx->SetProfilingTimerResolution(static_cast<float>(hwInfo->capabilityTable.defaultProfilingTimerResolution));
|
||||
auto igcPlatform = this->igcDeviceCtx->GetPlatformHandle();
|
||||
auto igcGtSystemInfo = this->igcDeviceCtx->GetGTSystemInfoHandle();
|
||||
auto igcFeWa = this->igcDeviceCtx->GetIgcFeaturesAndWorkaroundsHandle();
|
||||
if ((igcPlatform == nullptr) || (igcGtSystemInfo == nullptr) || (igcFeWa == nullptr)) {
|
||||
return CL_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
IGC::PlatformHelper::PopulateInterfaceWith(*igcPlatform.get(), hwInfo->platform);
|
||||
IGC::GtSysInfoHelper::PopulateInterfaceWith(*igcGtSystemInfo.get(), hwInfo->gtSystemInfo);
|
||||
// populate with features
|
||||
igcFeWa.get()->SetFtrDesktop(hwInfo->featureTable.ftrDesktop);
|
||||
igcFeWa.get()->SetFtrChannelSwizzlingXOREnabled(hwInfo->featureTable.ftrChannelSwizzlingXOREnabled);
|
||||
|
||||
igcFeWa.get()->SetFtrGtBigDie(hwInfo->featureTable.ftrGtBigDie);
|
||||
igcFeWa.get()->SetFtrGtMediumDie(hwInfo->featureTable.ftrGtMediumDie);
|
||||
igcFeWa.get()->SetFtrGtSmallDie(hwInfo->featureTable.ftrGtSmallDie);
|
||||
|
||||
igcFeWa.get()->SetFtrGT1(hwInfo->featureTable.ftrGT1);
|
||||
igcFeWa.get()->SetFtrGT1_5(hwInfo->featureTable.ftrGT1_5);
|
||||
igcFeWa.get()->SetFtrGT2(hwInfo->featureTable.ftrGT2);
|
||||
igcFeWa.get()->SetFtrGT3(hwInfo->featureTable.ftrGT3);
|
||||
igcFeWa.get()->SetFtrGT4(hwInfo->featureTable.ftrGT4);
|
||||
|
||||
igcFeWa.get()->SetFtrIVBM0M1Platform(hwInfo->featureTable.ftrIVBM0M1Platform);
|
||||
igcFeWa.get()->SetFtrGTL(hwInfo->featureTable.ftrGT1);
|
||||
igcFeWa.get()->SetFtrGTM(hwInfo->featureTable.ftrGT2);
|
||||
igcFeWa.get()->SetFtrGTH(hwInfo->featureTable.ftrGT3);
|
||||
|
||||
igcFeWa.get()->SetFtrSGTPVSKUStrapPresent(hwInfo->featureTable.ftrSGTPVSKUStrapPresent);
|
||||
igcFeWa.get()->SetFtrGTA(hwInfo->featureTable.ftrGTA);
|
||||
igcFeWa.get()->SetFtrGTC(hwInfo->featureTable.ftrGTC);
|
||||
igcFeWa.get()->SetFtrGTX(hwInfo->featureTable.ftrGTX);
|
||||
igcFeWa.get()->SetFtr5Slice(hwInfo->featureTable.ftr5Slice);
|
||||
|
||||
igcFeWa.get()->SetFtrGpGpuMidThreadLevelPreempt(hwInfo->featureTable.ftrGpGpuMidThreadLevelPreempt);
|
||||
igcFeWa.get()->SetFtrIoMmuPageFaulting(hwInfo->featureTable.ftrIoMmuPageFaulting);
|
||||
igcFeWa.get()->SetFtrWddm2Svm(hwInfo->featureTable.ftrWddm2Svm);
|
||||
igcFeWa.get()->SetFtrPooledEuEnabled(hwInfo->featureTable.ftrPooledEuEnabled);
|
||||
|
||||
igcFeWa.get()->SetFtrResourceStreamer(hwInfo->featureTable.ftrResourceStreamer);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int OfflineCompiler::parseCommandLine(size_t numArgs, const std::vector<std::string> &argv) {
|
||||
int retVal = CL_SUCCESS;
|
||||
bool compile32 = false;
|
||||
bool compile64 = false;
|
||||
|
||||
if (numArgs < 2) {
|
||||
printUsage();
|
||||
retVal = PRINT_USAGE;
|
||||
}
|
||||
|
||||
for (uint32_t argIndex = 1; argIndex < numArgs; argIndex++) {
|
||||
const auto &currArg = argv[argIndex];
|
||||
const bool hasMoreArgs = (argIndex + 1 < numArgs);
|
||||
if ("compile" == currArg) {
|
||||
//skip it
|
||||
} else if (("-file" == currArg) && hasMoreArgs) {
|
||||
inputFile = argv[argIndex + 1];
|
||||
argIndex++;
|
||||
} else if (("-output" == currArg) && hasMoreArgs) {
|
||||
outputFile = argv[argIndex + 1];
|
||||
argIndex++;
|
||||
} else if ((CompilerOptions::arch32bit == currArg) || ("-32" == currArg)) {
|
||||
compile32 = true;
|
||||
CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::arch32bit);
|
||||
} else if ((CompilerOptions::arch64bit == currArg) || ("-64" == currArg)) {
|
||||
compile64 = true;
|
||||
CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::arch64bit);
|
||||
} else if (CompilerOptions::greaterThan4gbBuffersRequired == currArg) {
|
||||
CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::greaterThan4gbBuffersRequired);
|
||||
} else if (("-device" == currArg) && hasMoreArgs) {
|
||||
deviceName = argv[argIndex + 1];
|
||||
argIndex++;
|
||||
} else if ("-llvm_text" == currArg) {
|
||||
useLlvmText = true;
|
||||
} else if ("-llvm_bc" == currArg) {
|
||||
useLlvmBc = true;
|
||||
} else if ("-llvm_input" == currArg) {
|
||||
inputFileLlvm = true;
|
||||
} else if ("-spirv_input" == currArg) {
|
||||
inputFileSpirV = true;
|
||||
} else if ("-cpp_file" == currArg) {
|
||||
useCppFile = true;
|
||||
} else if (("-options" == currArg) && hasMoreArgs) {
|
||||
options = argv[argIndex + 1];
|
||||
argIndex++;
|
||||
} else if (("-internal_options" == currArg) && hasMoreArgs) {
|
||||
CompilerOptions::concatenateAppend(internalOptions, argv[argIndex + 1]);
|
||||
argIndex++;
|
||||
} else if ("-options_name" == currArg) {
|
||||
useOptionsSuffix = true;
|
||||
} else if ("-force_stos_opt" == currArg) {
|
||||
forceStatelessToStatefulOptimization = true;
|
||||
} else if (("-out_dir" == currArg) && hasMoreArgs) {
|
||||
outputDirectory = argv[argIndex + 1];
|
||||
argIndex++;
|
||||
} else if ("-q" == currArg) {
|
||||
quiet = true;
|
||||
} else if ("-output_no_suffix" == currArg) {
|
||||
outputNoSuffix = true;
|
||||
} else if ("--help" == currArg) {
|
||||
printUsage();
|
||||
retVal = PRINT_USAGE;
|
||||
} else {
|
||||
printf("Invalid option (arg %d): %s\n", argIndex, argv[argIndex].c_str());
|
||||
retVal = INVALID_COMMAND_LINE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (retVal == CL_SUCCESS) {
|
||||
if (compile32 && compile64) {
|
||||
printf("Error: Cannot compile for 32-bit and 64-bit, please choose one.\n");
|
||||
retVal = INVALID_COMMAND_LINE;
|
||||
} else if (inputFile.empty()) {
|
||||
printf("Error: Input file name missing.\n");
|
||||
retVal = INVALID_COMMAND_LINE;
|
||||
} else if (deviceName.empty()) {
|
||||
printf("Error: Device name missing.\n");
|
||||
retVal = INVALID_COMMAND_LINE;
|
||||
} else if (!argHelper->fileExists(inputFile)) {
|
||||
printf("Error: Input file %s missing.\n", inputFile.c_str());
|
||||
retVal = INVALID_FILE;
|
||||
} else {
|
||||
retVal = getHardwareInfo(deviceName.c_str());
|
||||
if (retVal != CL_SUCCESS) {
|
||||
printf("Error: Cannot get HW Info for device %s.\n", deviceName.c_str());
|
||||
} else {
|
||||
std::string extensionsList = getExtensionsList(*hwInfo);
|
||||
CompilerOptions::concatenateAppend(internalOptions, convertEnabledExtensionsToCompilerInternalOptions(extensionsList.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void OfflineCompiler::setStatelessToStatefullBufferOffsetFlag() {
|
||||
bool isStatelessToStatefulBufferOffsetSupported = true;
|
||||
if (deviceName == "bdw") {
|
||||
isStatelessToStatefulBufferOffsetSupported = false;
|
||||
}
|
||||
if (DebugManager.flags.EnableStatelessToStatefulBufferOffsetOpt.get() != -1) {
|
||||
isStatelessToStatefulBufferOffsetSupported = DebugManager.flags.EnableStatelessToStatefulBufferOffsetOpt.get() != 0;
|
||||
}
|
||||
if (isStatelessToStatefulBufferOffsetSupported) {
|
||||
CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::hasBufferOffsetArg);
|
||||
}
|
||||
}
|
||||
|
||||
void OfflineCompiler::parseDebugSettings() {
|
||||
setStatelessToStatefullBufferOffsetFlag();
|
||||
resolveExtraSettings();
|
||||
}
|
||||
|
||||
std::string OfflineCompiler::parseBinAsCharArray(uint8_t *binary, size_t size, std::string &fileName) {
|
||||
std::string builtinName = convertToPascalCase(fileName);
|
||||
std::ostringstream out;
|
||||
|
||||
// Convert binary to cpp
|
||||
out << "#include <cstddef>\n";
|
||||
out << "#include <cstdint>\n\n";
|
||||
out << "size_t " << builtinName << "BinarySize_" << familyNameWithType << " = " << size << ";\n";
|
||||
out << "uint32_t " << builtinName << "Binary_" << familyNameWithType << "[" << (size + 3) / 4 << "] = {"
|
||||
<< std::endl
|
||||
<< " ";
|
||||
|
||||
uint32_t *binaryUint = (uint32_t *)binary;
|
||||
for (size_t i = 0; i < (size + 3) / 4; i++) {
|
||||
if (i != 0) {
|
||||
out << ", ";
|
||||
if (i % 8 == 0) {
|
||||
out << std::endl
|
||||
<< " ";
|
||||
}
|
||||
}
|
||||
if (i < size / 4) {
|
||||
out << "0x" << std::hex << std::setw(8) << std::setfill('0') << binaryUint[i];
|
||||
} else {
|
||||
uint32_t lastBytes = size & 0x3;
|
||||
uint32_t lastUint = 0;
|
||||
uint8_t *pLastUint = (uint8_t *)&lastUint;
|
||||
for (uint32_t j = 0; j < lastBytes; j++) {
|
||||
pLastUint[sizeof(uint32_t) - 1 - j] = binary[i * 4 + j];
|
||||
}
|
||||
out << "0x" << std::hex << std::setw(8) << std::setfill('0') << lastUint;
|
||||
}
|
||||
}
|
||||
out << "};" << std::endl;
|
||||
|
||||
out << std::endl
|
||||
<< "#include \"shared/source/built_ins/registry/built_ins_registry.h\"\n"
|
||||
<< std::endl;
|
||||
out << "namespace NEO {" << std::endl;
|
||||
out << "static RegisterEmbeddedResource register" << builtinName << "Bin(" << std::endl;
|
||||
out << " \"" << familyNameWithType << "_0_" << fileName.c_str() << ".builtin_kernel.bin\"," << std::endl;
|
||||
out << " (const char *)" << builtinName << "Binary_" << familyNameWithType << "," << std::endl;
|
||||
out << " " << builtinName << "BinarySize_" << familyNameWithType << ");" << std::endl;
|
||||
out << "}" << std::endl;
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string OfflineCompiler::getFileNameTrunk(std::string &filePath) {
|
||||
size_t slashPos = filePath.find_last_of("\\/", filePath.size()) + 1;
|
||||
size_t extPos = filePath.find_last_of(".", filePath.size());
|
||||
if (extPos == std::string::npos) {
|
||||
extPos = filePath.size();
|
||||
}
|
||||
|
||||
std::string fileTrunk = filePath.substr(slashPos, (extPos - slashPos));
|
||||
|
||||
return fileTrunk;
|
||||
}
|
||||
//
|
||||
std::string getDevicesTypes() {
|
||||
std::list<std::string> prefixes;
|
||||
for (int j = 0; j < IGFX_MAX_PRODUCT; j++) {
|
||||
if (hardwarePrefix[j] == nullptr)
|
||||
continue;
|
||||
prefixes.push_back(hardwarePrefix[j]);
|
||||
}
|
||||
|
||||
std::ostringstream os;
|
||||
for (auto it = prefixes.begin(); it != prefixes.end(); it++) {
|
||||
if (it != prefixes.begin())
|
||||
os << ",";
|
||||
os << *it;
|
||||
}
|
||||
|
||||
return os.str();
|
||||
}
|
||||
|
||||
void OfflineCompiler::printUsage() {
|
||||
printf(R"===(Compiles input file to Intel OpenCL GPU device binary (*.bin).
|
||||
Additionally, outputs intermediate representation (e.g. spirV).
|
||||
Different input and intermediate file formats are available.
|
||||
|
||||
Usage: ocloc [compile] -file <filename> -device <device_type> [-output <filename>] [-out_dir <output_dir>] [-options <options>] [-32|-64] [-internal_options <options>] [-llvm_text|-llvm_input|-spirv_input] [-options_name] [-q] [-cpp_file] [-output_no_suffix] [--help]
|
||||
|
||||
-file <filename> The input file to be compiled
|
||||
(by default input source format is
|
||||
OpenCL C kernel language).
|
||||
|
||||
-device <device_type> Target device.
|
||||
<device_type> can be: %s
|
||||
If multiple target devices are provided, ocloc
|
||||
will compile for each of these targets and will
|
||||
create a fatbinary archive that contains all of
|
||||
device binaries produced this way.
|
||||
Supported -device patterns examples :
|
||||
-device skl ; will compile 1 target
|
||||
-device skl,icllp ; will compile 2 targets
|
||||
-device skl-icllp ; will compile all targets
|
||||
in range (inclusive)
|
||||
-device skl- ; will compile all targets
|
||||
newer/same as provided
|
||||
-device -skl ; will compile all targets
|
||||
older/same as provided
|
||||
-device gen9 ; will compile all targets
|
||||
matching the same gen
|
||||
-device gen9-gen11 ; will compile all targets
|
||||
in range (inclusive)
|
||||
-device gen9- ; will compile all targets
|
||||
newer/same as provided
|
||||
-device -gen9 ; will compile all targets
|
||||
older/same as provided
|
||||
-device * ; will compile all targets
|
||||
known to ocloc
|
||||
|
||||
-output <filename> Optional output file base name.
|
||||
Default is input file's base name.
|
||||
This base name will be used for all output
|
||||
files. Proper sufixes (describing file formats)
|
||||
will be added automatically.
|
||||
|
||||
-out_dir <output_dir> Optional output directory.
|
||||
Default is current working directory.
|
||||
|
||||
-options <options> Optional OpenCL C compilation options
|
||||
as defined by OpenCL specification.
|
||||
|
||||
-32 Forces target architecture to 32-bit pointers.
|
||||
Default pointer size is inherited from
|
||||
ocloc's pointer size.
|
||||
This option is exclusive with -64.
|
||||
|
||||
-64 Forces target architecture to 64-bit pointers.
|
||||
Default pointer size is inherited from
|
||||
ocloc's pointer size.
|
||||
This option is exclusive with -32.
|
||||
|
||||
-internal_options <options> Optional compiler internal options
|
||||
as defined by compilers used underneath.
|
||||
Check intel-graphics-compiler (IGC) project
|
||||
for details on available internal options.
|
||||
|
||||
-llvm_text Forces intermediate representation (IR) format
|
||||
to human-readable LLVM IR (.ll).
|
||||
This option affects only output files
|
||||
and should not be used in combination with
|
||||
'-llvm_input' option.
|
||||
Default IR is spirV.
|
||||
This option is exclusive with -spirv_input.
|
||||
This option is exclusive with -llvm_input.
|
||||
|
||||
-llvm_input Indicates that input file is an llvm binary.
|
||||
Default is OpenCL C kernel language.
|
||||
This option is exclusive with -spirv_input.
|
||||
This option is exclusive with -llvm_text.
|
||||
|
||||
-spirv_input Indicates that input file is a spirV binary.
|
||||
Default is OpenCL C kernel language format.
|
||||
This option is exclusive with -llvm_input.
|
||||
This option is exclusive with -llvm_text.
|
||||
|
||||
-options_name Will add suffix to output files.
|
||||
This suffix will be generated based on input
|
||||
options (useful when rebuilding with different
|
||||
set of options so that results won't get
|
||||
overwritten).
|
||||
This suffix is added always as the last part
|
||||
of the filename (even after file's extension).
|
||||
It does not affect '--output' parameter and can
|
||||
be used along with it ('--output' parameter
|
||||
defines the base name - i.e. prefix).
|
||||
|
||||
-force_stos_opt Will forcibly enable stateless to stateful optimization,
|
||||
i.e. skip "-cl-intel-greater-than-4GB-buffer-required".
|
||||
|
||||
-q Will silence most of output messages.
|
||||
|
||||
-cpp_file Will generate c++ file with C-array
|
||||
containing Intel OpenCL device binary.
|
||||
|
||||
-output_no_suffix Prevents ocloc from adding family name suffix.
|
||||
|
||||
--help Print this usage message.
|
||||
|
||||
Examples :
|
||||
Compile file to Intel OpenCL GPU device binary (out = source_file_Gen9core.bin)
|
||||
ocloc -file source_file.cl -device skl
|
||||
)===",
|
||||
NEO::getDevicesTypes().c_str());
|
||||
}
|
||||
|
||||
void OfflineCompiler::storeBinary(
|
||||
char *&pDst,
|
||||
size_t &dstSize,
|
||||
const void *pSrc,
|
||||
const size_t srcSize) {
|
||||
dstSize = 0;
|
||||
|
||||
DEBUG_BREAK_IF(!(pSrc && srcSize > 0));
|
||||
|
||||
delete[] pDst;
|
||||
pDst = new char[srcSize];
|
||||
|
||||
dstSize = (cl_uint)srcSize;
|
||||
memcpy_s(pDst, dstSize, pSrc, srcSize);
|
||||
}
|
||||
|
||||
bool OfflineCompiler::generateElfBinary() {
|
||||
if (!genBinary || !genBinarySize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SingleDeviceBinary binary = {};
|
||||
binary.buildOptions = this->options;
|
||||
binary.intermediateRepresentation = ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(this->irBinary), this->irBinarySize);
|
||||
binary.deviceBinary = ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(this->genBinary), this->genBinarySize);
|
||||
binary.debugData = ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(this->debugDataBinary), this->debugDataBinarySize);
|
||||
std::string packErrors;
|
||||
std::string packWarnings;
|
||||
|
||||
using namespace NEO::Elf;
|
||||
ElfEncoder<EI_CLASS_64> ElfEncoder;
|
||||
ElfEncoder.getElfFileHeader().type = ET_OPENCL_EXECUTABLE;
|
||||
if (binary.buildOptions.empty() == false) {
|
||||
ElfEncoder.appendSection(SHT_OPENCL_OPTIONS, SectionNamesOpenCl::buildOptions,
|
||||
ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(binary.buildOptions.data()), binary.buildOptions.size()));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
std::string fileBase;
|
||||
std::string fileTrunk = getFileNameTrunk(inputFile);
|
||||
if (outputNoSuffix) {
|
||||
if (outputFile.empty()) {
|
||||
fileBase = fileTrunk;
|
||||
} else {
|
||||
fileBase = outputFile;
|
||||
}
|
||||
} else {
|
||||
if (outputFile.empty()) {
|
||||
fileBase = fileTrunk + "_" + familyNameWithType;
|
||||
} else {
|
||||
fileBase = outputFile + "_" + familyNameWithType;
|
||||
}
|
||||
}
|
||||
|
||||
if (outputDirectory != "") {
|
||||
std::list<std::string> dirList;
|
||||
std::string tmp = outputDirectory;
|
||||
size_t pos = outputDirectory.size() + 1;
|
||||
|
||||
do {
|
||||
dirList.push_back(tmp);
|
||||
pos = tmp.find_last_of("/\\", pos);
|
||||
tmp = tmp.substr(0, pos);
|
||||
} while (pos != std::string::npos);
|
||||
|
||||
while (!dirList.empty()) {
|
||||
MakeDirectory(dirList.back().c_str());
|
||||
dirList.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
if (irBinary) {
|
||||
std::string irOutputFileName = generateFilePathForIr(fileBase) + generateOptsSuffix();
|
||||
|
||||
argHelper->saveOutput(irOutputFileName, irBinary, irBinarySize);
|
||||
}
|
||||
|
||||
if (genBinary) {
|
||||
std::string genOutputFile = generateFilePath(outputDirectory, fileBase, ".gen") + generateOptsSuffix();
|
||||
|
||||
argHelper->saveOutput(genOutputFile, genBinary, genBinarySize);
|
||||
|
||||
if (useCppFile) {
|
||||
std::string cppOutputFile = generateFilePath(outputDirectory, fileBase, ".cpp");
|
||||
std::string cpp = parseBinAsCharArray((uint8_t *)genBinary, genBinarySize, fileTrunk);
|
||||
argHelper->saveOutput(cppOutputFile, cpp.c_str(), cpp.size());
|
||||
}
|
||||
}
|
||||
|
||||
if (!elfBinary.empty()) {
|
||||
std::string elfOutputFile;
|
||||
if (outputNoSuffix) {
|
||||
elfOutputFile = generateFilePath(outputDirectory, fileBase, "");
|
||||
} else {
|
||||
elfOutputFile = generateFilePath(outputDirectory, fileBase, ".bin") + generateOptsSuffix();
|
||||
}
|
||||
argHelper->saveOutput(
|
||||
elfOutputFile,
|
||||
elfBinary.data(),
|
||||
elfBinary.size());
|
||||
}
|
||||
|
||||
if (debugDataBinary) {
|
||||
std::string debugOutputFile = generateFilePath(outputDirectory, fileBase, ".dbg") + generateOptsSuffix();
|
||||
|
||||
argHelper->saveOutput(
|
||||
debugOutputFile,
|
||||
debugDataBinary,
|
||||
debugDataBinarySize);
|
||||
}
|
||||
}
|
||||
|
||||
bool OfflineCompiler::readOptionsFromFile(std::string &options, const std::string &file, std::unique_ptr<OclocArgHelper> &helper) {
|
||||
if (!helper->fileExists(file)) {
|
||||
return false;
|
||||
}
|
||||
size_t optionsSize = 0U;
|
||||
auto optionsFromFile = helper->loadDataFromFile(file, optionsSize);
|
||||
if (optionsSize > 0) {
|
||||
// Remove comment containing copyright header
|
||||
options = optionsFromFile.get();
|
||||
size_t commentBegin = options.find_first_of("/*");
|
||||
size_t commentEnd = options.find_last_of("*/");
|
||||
if (commentBegin != std::string::npos && commentEnd != std::string::npos) {
|
||||
options = options.replace(commentBegin, commentEnd - commentBegin + 1, "");
|
||||
size_t optionsBegin = options.find_first_not_of(" \t\n\r");
|
||||
if (optionsBegin != std::string::npos) {
|
||||
options = options.substr(optionsBegin, options.length());
|
||||
}
|
||||
}
|
||||
auto trimPos = options.find_last_not_of(" \n\r");
|
||||
options = options.substr(0, trimPos + 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string generateFilePath(const std::string &directory, const std::string &fileNameBase, const char *extension) {
|
||||
UNRECOVERABLE_IF(extension == nullptr);
|
||||
|
||||
if (directory.empty()) {
|
||||
return fileNameBase + extension;
|
||||
}
|
||||
|
||||
bool hasTrailingSlash = (*directory.rbegin() == '/');
|
||||
std::string ret;
|
||||
ret.reserve(directory.size() + (hasTrailingSlash ? 0 : 1) + fileNameBase.size() + strlen(extension) + 1);
|
||||
ret.append(directory);
|
||||
if (false == hasTrailingSlash) {
|
||||
ret.append("/", 1);
|
||||
}
|
||||
ret.append(fileNameBase);
|
||||
ret.append(extension);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace NEO
|
||||
136
shared/offline_compiler/source/offline_compiler.h
Normal file
136
shared/offline_compiler/source/offline_compiler.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2017-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared/offline_compiler/source/ocloc_arg_helper.h"
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
#include "shared/source/utilities/arrayref.h"
|
||||
#include "shared/source/utilities/const_stringref.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"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace NEO {
|
||||
|
||||
struct HardwareInfo;
|
||||
class OsLibrary;
|
||||
|
||||
std::string convertToPascalCase(const std::string &inString);
|
||||
|
||||
enum ErrorCode {
|
||||
INVALID_COMMAND_LINE = -5150,
|
||||
INVALID_FILE = -5151,
|
||||
PRINT_USAGE = -5152,
|
||||
};
|
||||
|
||||
std::string generateFilePath(const std::string &directory, const std::string &fileNameBase, const char *extension);
|
||||
std::string getDevicesTypes();
|
||||
|
||||
class OfflineCompiler {
|
||||
public:
|
||||
static OfflineCompiler *create(size_t numArgs, const std::vector<std::string> &allArgs, bool dumpFiles, int &retVal);
|
||||
static OfflineCompiler *create(size_t numArgs, const std::vector<std::string> &allArgs, bool dumpFiles, int &retVal, std::unique_ptr<OclocArgHelper> helper);
|
||||
int build();
|
||||
std::string &getBuildLog();
|
||||
void printUsage();
|
||||
|
||||
OfflineCompiler &operator=(const OfflineCompiler &) = delete;
|
||||
OfflineCompiler(const OfflineCompiler &) = delete;
|
||||
~OfflineCompiler();
|
||||
|
||||
bool isQuiet() const {
|
||||
return quiet;
|
||||
}
|
||||
|
||||
std::string parseBinAsCharArray(uint8_t *binary, size_t size, std::string &fileName);
|
||||
|
||||
static bool readOptionsFromFile(std::string &optionsOut, const std::string &file, std::unique_ptr<OclocArgHelper> &helper);
|
||||
|
||||
ArrayRef<const uint8_t> getPackedDeviceBinaryOutput() {
|
||||
return this->elfBinary;
|
||||
}
|
||||
|
||||
static std::string getFileNameTrunk(std::string &filePath);
|
||||
const HardwareInfo &getHardwareInfo() const {
|
||||
return *hwInfo;
|
||||
}
|
||||
|
||||
protected:
|
||||
OfflineCompiler();
|
||||
|
||||
int getHardwareInfo(const char *pDeviceName);
|
||||
std::string getStringWithinDelimiters(const std::string &src);
|
||||
int initialize(size_t numArgs, const std::vector<std::string> &allArgs, bool dumpFiles);
|
||||
int parseCommandLine(size_t numArgs, const std::vector<std::string> &allArgs);
|
||||
void setStatelessToStatefullBufferOffsetFlag();
|
||||
void resolveExtraSettings();
|
||||
void parseDebugSettings();
|
||||
void storeBinary(char *&pDst, size_t &dstSize, const void *pSrc, const size_t srcSize);
|
||||
int buildSourceCode();
|
||||
void updateBuildLog(const char *pErrorString, const size_t errorStringSize);
|
||||
bool generateElfBinary();
|
||||
std::string generateFilePathForIr(const std::string &fileNameBase) {
|
||||
const char *ext = (isSpirV) ? ".spv" : ".bc";
|
||||
return generateFilePath(outputDirectory, fileNameBase, useLlvmText ? ".ll" : ext);
|
||||
}
|
||||
|
||||
std::string generateOptsSuffix() {
|
||||
std::string suffix{useOptionsSuffix ? options : ""};
|
||||
std::replace(suffix.begin(), suffix.end(), ' ', '_');
|
||||
return suffix;
|
||||
}
|
||||
void writeOutAllFiles();
|
||||
const HardwareInfo *hwInfo = nullptr;
|
||||
|
||||
std::string deviceName;
|
||||
std::string familyNameWithType;
|
||||
std::string inputFile;
|
||||
std::string outputFile;
|
||||
std::string outputDirectory;
|
||||
std::string options;
|
||||
std::string internalOptions;
|
||||
std::string sourceCode;
|
||||
std::string buildLog;
|
||||
bool dumpFiles = true;
|
||||
|
||||
bool useLlvmText = false;
|
||||
bool useLlvmBc = false;
|
||||
bool useCppFile = false;
|
||||
bool useOptionsSuffix = false;
|
||||
bool quiet = false;
|
||||
bool inputFileLlvm = false;
|
||||
bool inputFileSpirV = false;
|
||||
bool outputNoSuffix = false;
|
||||
bool forceStatelessToStatefulOptimization = false;
|
||||
|
||||
std::vector<uint8_t> elfBinary;
|
||||
char *genBinary = nullptr;
|
||||
size_t genBinarySize = 0;
|
||||
char *irBinary = nullptr;
|
||||
size_t irBinarySize = 0;
|
||||
bool isSpirV = false;
|
||||
char *debugDataBinary = nullptr;
|
||||
size_t debugDataBinarySize = 0;
|
||||
|
||||
std::unique_ptr<OsLibrary> igcLib = nullptr;
|
||||
CIF::RAII::UPtr_t<CIF::CIFMain> igcMain = nullptr;
|
||||
CIF::RAII::UPtr_t<IGC::IgcOclDeviceCtxTagOCL> igcDeviceCtx = nullptr;
|
||||
|
||||
std::unique_ptr<OsLibrary> fclLib = nullptr;
|
||||
CIF::RAII::UPtr_t<CIF::CIFMain> fclMain = nullptr;
|
||||
CIF::RAII::UPtr_t<IGC::FclOclDeviceCtxTagOCL> fclDeviceCtx = nullptr;
|
||||
IGC::CodeType::CodeType_t preferredIntermediateRepresentation;
|
||||
|
||||
std::unique_ptr<OclocArgHelper> argHelper = nullptr;
|
||||
};
|
||||
} // namespace NEO
|
||||
23
shared/offline_compiler/source/offline_compiler_helper.cpp
Normal file
23
shared/offline_compiler/source/offline_compiler_helper.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2017-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/source/debug_settings/debug_settings_manager.h"
|
||||
#include "shared/source/helpers/hw_info.h"
|
||||
#include "shared/source/utilities/debug_settings_reader_creator.h"
|
||||
|
||||
namespace NEO {
|
||||
|
||||
template <DebugFunctionalityLevel DebugLevel>
|
||||
DebugSettingsManager<DebugLevel>::DebugSettingsManager(const char *registryPath) {
|
||||
}
|
||||
|
||||
template <DebugFunctionalityLevel DebugLevel>
|
||||
DebugSettingsManager<DebugLevel>::~DebugSettingsManager() = default;
|
||||
|
||||
// Global Debug Settings Manager
|
||||
DebugSettingsManager<globalDebugFunctionalityLevel> DebugManager("");
|
||||
} // namespace NEO
|
||||
17
shared/offline_compiler/source/offline_compiler_options.cpp
Normal file
17
shared/offline_compiler/source/offline_compiler_options.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2017-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace NEO {
|
||||
// AUB file folder location
|
||||
const char *folderAUB = "aub_out";
|
||||
|
||||
// Initial value for HW tag
|
||||
uint32_t initialHardwareTag = std::numeric_limits<uint32_t>::max();
|
||||
} // namespace NEO
|
||||
31
shared/offline_compiler/source/utilities/CMakeLists.txt
Normal file
31
shared/offline_compiler/source/utilities/CMakeLists.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# Copyright (C) 2018-2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
|
||||
set(CLOC_LIB_SRCS_UTILITIES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/safety_caller.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/get_current_dir.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/get_path.h
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND CLOC_LIB_SRCS_UTILITIES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/windows/safety_caller_windows.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/windows/safety_guard_windows.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/windows/seh_exception.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/windows/seh_exception.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/windows/get_current_dir_windows.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/windows/get_path.cpp
|
||||
)
|
||||
else()
|
||||
list(APPEND CLOC_LIB_SRCS_UTILITIES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/linux/safety_caller_linux.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/linux/get_current_dir_linux.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/linux/get_path.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(ocloc_lib PRIVATE ${CLOC_LIB_SRCS_UTILITIES})
|
||||
target_sources(ocloc PRIVATE ${CLOC_LIB_SRCS_UTILITIES})
|
||||
10
shared/offline_compiler/source/utilities/get_current_dir.h
Normal file
10
shared/offline_compiler/source/utilities/get_current_dir.h
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern std::string getCurrentDirectoryOwn(std::string outDirForBuilds);
|
||||
10
shared/offline_compiler/source/utilities/get_path.h
Normal file
10
shared/offline_compiler/source/utilities/get_path.h
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern std::string getPath();
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
std::string getCurrentDirectoryOwn(std::string outDirForBuilds) {
|
||||
char buf[256];
|
||||
if (getcwd(buf, sizeof(buf)) != NULL)
|
||||
return std::string(buf) + "/" + outDirForBuilds + "/";
|
||||
else
|
||||
return std::string("./") + outDirForBuilds + "/";
|
||||
}
|
||||
24
shared/offline_compiler/source/utilities/linux/get_path.cpp
Normal file
24
shared/offline_compiler/source/utilities/linux/get_path.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
std::string getPath() {
|
||||
char exepath[128] = {0};
|
||||
std::stringstream ss;
|
||||
ss << "/proc/" << getpid() << "/exe";
|
||||
if (readlink(ss.str().c_str(), exepath, 128) != -1) {
|
||||
std::string path = std::string(exepath);
|
||||
path = path.substr(0, path.find_last_of('/') + 1);
|
||||
return path;
|
||||
} else {
|
||||
return std::string("");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
#include "shared/offline_compiler/source/utilities/linux/safety_guard_linux.h"
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
|
||||
using namespace NEO;
|
||||
|
||||
int buildWithSafetyGuard(OfflineCompiler *compiler) {
|
||||
SafetyGuardLinux safetyGuard;
|
||||
int retVal = 0;
|
||||
|
||||
return safetyGuard.call<int, OfflineCompiler, decltype(&OfflineCompiler::build)>(compiler, &OfflineCompiler::build, retVal);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "shared/source/helpers/abort.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <execinfo.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
|
||||
static jmp_buf jmpbuf;
|
||||
|
||||
class SafetyGuardLinux {
|
||||
public:
|
||||
SafetyGuardLinux() {
|
||||
struct sigaction sigact;
|
||||
|
||||
sigact.sa_sigaction = sigAction;
|
||||
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);
|
||||
sigaction(SIGILL, &sigact, (struct sigaction *)NULL);
|
||||
}
|
||||
|
||||
static void sigAction(int sigNum, siginfo_t *info, void *ucontext) {
|
||||
const int callstackDepth = 30;
|
||||
void *addresses[callstackDepth];
|
||||
char **callstack;
|
||||
int backtraceSize = 0;
|
||||
|
||||
backtraceSize = backtrace(addresses, callstackDepth);
|
||||
callstack = backtrace_symbols(addresses, backtraceSize);
|
||||
|
||||
for (int i = 0; i < backtraceSize; ++i) {
|
||||
printf("[%d]: %s\n", i, callstack[i]);
|
||||
}
|
||||
|
||||
free(callstack);
|
||||
longjmp(jmpbuf, 1);
|
||||
}
|
||||
|
||||
template <typename T, typename Object, typename Method>
|
||||
T call(Object *object, Method method, T retValueOnCrash) {
|
||||
int jump = 0;
|
||||
jump = setjmp(jmpbuf);
|
||||
|
||||
if (jump == 0) {
|
||||
return (object->*method)();
|
||||
} else {
|
||||
if (onSigSegv) {
|
||||
onSigSegv();
|
||||
} else {
|
||||
NEO::abortExecution();
|
||||
}
|
||||
}
|
||||
return retValueOnCrash;
|
||||
}
|
||||
|
||||
typedef void (*callbackFunction)();
|
||||
callbackFunction onSigSegv = nullptr;
|
||||
};
|
||||
13
shared/offline_compiler/source/utilities/safety_caller.h
Normal file
13
shared/offline_compiler/source/utilities/safety_caller.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
namespace NEO {
|
||||
class OfflineCompiler;
|
||||
}
|
||||
|
||||
extern int buildWithSafetyGuard(NEO::OfflineCompiler *compiler);
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Windows.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string getCurrentDirectoryOwn(std::string outDirForBuilds) {
|
||||
char buf[256];
|
||||
GetCurrentDirectoryA(256, buf);
|
||||
return std::string(buf) + "\\" + outDirForBuilds + "\\";
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string getPath() {
|
||||
return std::string("");
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
#include "shared/offline_compiler/source/utilities/windows/safety_guard_windows.h"
|
||||
|
||||
using namespace NEO;
|
||||
|
||||
int buildWithSafetyGuard(OfflineCompiler *compiler) {
|
||||
SafetyGuardWindows safetyGuard;
|
||||
int retVal = 0;
|
||||
return safetyGuard.call<int, OfflineCompiler, decltype(&OfflineCompiler::build)>(compiler, &OfflineCompiler::build, retVal);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "shared/offline_compiler/source/utilities/windows/seh_exception.h"
|
||||
#include "shared/source/helpers/abort.h"
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
static jmp_buf jmpbuf;
|
||||
|
||||
class SafetyGuardWindows {
|
||||
public:
|
||||
template <typename T, typename Object, typename Method>
|
||||
T call(Object *object, Method method, T retValueOnCrash) {
|
||||
int jump = 0;
|
||||
jump = setjmp(jmpbuf);
|
||||
|
||||
if (jump == 0) {
|
||||
__try {
|
||||
return (object->*method)();
|
||||
} __except (SehException::filter(GetExceptionCode(), GetExceptionInformation())) {
|
||||
if (onExcept) {
|
||||
onExcept();
|
||||
} else {
|
||||
NEO::abortExecution();
|
||||
}
|
||||
longjmp(jmpbuf, 1);
|
||||
}
|
||||
}
|
||||
return retValueOnCrash;
|
||||
}
|
||||
|
||||
typedef void (*callbackFunction)();
|
||||
callbackFunction onExcept = nullptr;
|
||||
};
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "seh_exception.h"
|
||||
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4091)
|
||||
#include <dbghelp.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <excpt.h>
|
||||
#include <psapi.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
string SehException::getExceptionDescription(unsigned int code) {
|
||||
switch (code) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
return "Access violation";
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
return "Datatype misalignement";
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
return "Divide by zero";
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
return "Stack overflow";
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
int SehException::filter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
|
||||
|
||||
printf("EXCEPTION: %s\n", SehException::getExceptionDescription(code).c_str());
|
||||
|
||||
if (code != EXCEPTION_STACK_OVERFLOW) {
|
||||
string callstack;
|
||||
|
||||
SehException::getCallStack(code, ep, callstack);
|
||||
printf("Callstack:\n\n%s", callstack.c_str());
|
||||
}
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
void SehException::getCallStack(unsigned int code, struct _EXCEPTION_POINTERS *ep, string &stack) {
|
||||
DWORD machine = 0;
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
HANDLE hThread = GetCurrentThread();
|
||||
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetSystemInfo(&systemInfo);
|
||||
|
||||
if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
|
||||
machine = IMAGE_FILE_MACHINE_I386;
|
||||
} else if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
|
||||
machine = IMAGE_FILE_MACHINE_AMD64;
|
||||
} else {
|
||||
stack = "invalid processor arch";
|
||||
return;
|
||||
}
|
||||
|
||||
stack.clear();
|
||||
|
||||
BOOL result = SymInitialize(hProcess, NULL, TRUE);
|
||||
if (result == FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
STACKFRAME64 stackFrame;
|
||||
memset(&stackFrame, 0, sizeof(STACKFRAME64));
|
||||
const int nameSize = 255;
|
||||
char buffer[sizeof(IMAGEHLP_SYMBOL64) + (nameSize + 1) * sizeof(char)];
|
||||
IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer);
|
||||
symbol->MaxNameLength = nameSize;
|
||||
|
||||
DWORD displacement = 0;
|
||||
DWORD64 displacement64 = 0;
|
||||
|
||||
unique_ptr<NEO::OsLibrary> psApiLib(NEO::OsLibrary::load("psapi.dll"));
|
||||
auto getMappedFileName = reinterpret_cast<getMappedFileNameFunction>(psApiLib->getProcAddress("GetMappedFileNameA"));
|
||||
|
||||
size_t callstackCounter = 0;
|
||||
const size_t maxCallstackDepth = 1000;
|
||||
|
||||
#ifdef _WIN64
|
||||
stackFrame.AddrPC.Offset = ep->ContextRecord->Rip;
|
||||
stackFrame.AddrPC.Mode = AddrModeFlat;
|
||||
stackFrame.AddrStack.Offset = ep->ContextRecord->Rsp;
|
||||
stackFrame.AddrStack.Mode = AddrModeFlat;
|
||||
stackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp;
|
||||
stackFrame.AddrFrame.Mode = AddrModeFlat;
|
||||
#else
|
||||
stackFrame.AddrPC.Offset = ep->ContextRecord->Eip;
|
||||
stackFrame.AddrPC.Mode = AddrModeFlat;
|
||||
stackFrame.AddrStack.Offset = ep->ContextRecord->Esp;
|
||||
stackFrame.AddrStack.Mode = AddrModeFlat;
|
||||
stackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp;
|
||||
stackFrame.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
#endif
|
||||
|
||||
while (callstackCounter < maxCallstackDepth) {
|
||||
symbol->Name[255] = '\0';
|
||||
|
||||
if (!StackWalk64(machine, hProcess, hThread, &stackFrame, ep->ContextRecord, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, 0)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (stackFrame.AddrFrame.Offset == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
string lineInCode;
|
||||
string module;
|
||||
string symbolName;
|
||||
|
||||
DWORD64 address = stackFrame.AddrPC.Offset;
|
||||
IMAGEHLP_LINE64 imageLine;
|
||||
imageLine.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
if (SymGetLineFromAddr64(hProcess, address, &displacement, &imageLine)) {
|
||||
lineInCode = imageLine.FileName;
|
||||
char filename[MAX_PATH + 1];
|
||||
filename[MAX_PATH] = '\0';
|
||||
|
||||
if (getMappedFileName(hProcess, reinterpret_cast<LPVOID>(imageLine.Address), filename, MAX_PATH)) {
|
||||
module = filename;
|
||||
}
|
||||
}
|
||||
|
||||
if (SymGetSymFromAddr64(hProcess, address, &displacement64, symbol)) {
|
||||
|
||||
symbolName = symbol->Name;
|
||||
}
|
||||
addLineToCallstack(stack, callstackCounter, module, lineInCode, symbolName);
|
||||
callstackCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
void SehException::addLineToCallstack(std::string &callstack, size_t counter, std::string &module, std::string &line, std::string &symbol) {
|
||||
callstack += "[";
|
||||
callstack += to_string(counter);
|
||||
callstack += "]: ";
|
||||
|
||||
if (module.size()) {
|
||||
callstack += "Module:";
|
||||
callstack += module + "\n\t";
|
||||
}
|
||||
if (line.size()) {
|
||||
callstack += line + ":";
|
||||
}
|
||||
callstack += symbol + "\n";
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "excpt.h"
|
||||
#include "windows.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class SehException {
|
||||
public:
|
||||
static std::string getExceptionDescription(unsigned int code);
|
||||
static void getCallStack(unsigned int code, struct _EXCEPTION_POINTERS *ep, std::string &stack);
|
||||
static int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep);
|
||||
|
||||
protected:
|
||||
static void addLineToCallstack(std::string &callstack, size_t counter, std::string &module, std::string &line, std::string &symbol);
|
||||
typedef DWORD(WINAPI *getMappedFileNameFunction)(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename, DWORD nSize);
|
||||
};
|
||||
Reference in New Issue
Block a user