moving ocloc to shared folder

Change-Id: Ic739cf747f7e6fae2c0cd57f0bc1aa0899d3aa53
This commit is contained in:
chmielew
2020-02-27 16:17:08 +01:00
committed by sys_ocldev
parent 47021dcc69
commit e28419fc91
60 changed files with 105 additions and 103 deletions

View 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)

View 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()

View 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);
}
}

View 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 &sectionHeader : 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;
}

View 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);
};

View 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;
}

View 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);
};

View 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;
}

View 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;
};

View 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;
}

View 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;
}

View 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;
};

View File

@@ -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);
}

View File

@@ -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);

View 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

View 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);
}

View 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

View 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

View 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;
}
}

View 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);
}

View 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();
}
}

View 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);
};

View 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

View 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

View 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();
}

View 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;
};

View 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

View 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

View 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

View 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

View 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})

View File

@@ -0,0 +1,10 @@
/*
* Copyright (C) 2019-2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
extern std::string getCurrentDirectoryOwn(std::string outDirForBuilds);

View File

@@ -0,0 +1,10 @@
/*
* Copyright (C) 2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
extern std::string getPath();

View File

@@ -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 + "/";
}

View 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("");
}
}

View File

@@ -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);
}

View File

@@ -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;
};

View 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);

View File

@@ -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 + "\\";
}

View File

@@ -0,0 +1,12 @@
/*
* Copyright (C) 2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include <string>
std::string getPath() {
return std::string("");
}

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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";
}

View File

@@ -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);
};