ocloc as shared library, ocloc API

Change-Id: Ie866b9ad5ee6de8c8b10f83551e2a3cab9d64a02
This commit is contained in:
chmielew 2020-02-07 14:06:50 +01:00 committed by sys_ocldev
parent d4d5971d84
commit 697848f3d1
32 changed files with 1087 additions and 426 deletions

View File

@ -821,7 +821,7 @@ if(MSVC)
endif()
add_subdirectory_unique(offline_compiler ${NEO_BUILD_DIR}/offline_compiler)
target_compile_definitions(ocloc PRIVATE MOCKABLE_VIRTUAL=)
target_compile_definitions(ocloc_lib PRIVATE MOCKABLE_VIRTUAL=)
if(DONT_CARE_OF_VIRTUALS)
set(NEO_CORE_RELEASE_LIB_NAME "neo_core")

View File

@ -4,9 +4,9 @@
# SPDX-License-Identifier: MIT
#
project(ocloc)
project(ocloc_lib)
set(CLOC_SRCS_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
@ -30,6 +30,10 @@ set(CLOC_SRCS_LIB
${NEO_SOURCE_DIR}/offline_compiler/decoder/helper.h
${NEO_SOURCE_DIR}/offline_compiler/decoder/iga_wrapper.h
${NEO_SOURCE_DIR}/offline_compiler/decoder/translate_platform_base.h
${NEO_SOURCE_DIR}/offline_compiler/ocloc_api.cpp
${NEO_SOURCE_DIR}/offline_compiler/ocloc_api.h
${NEO_SOURCE_DIR}/offline_compiler/ocloc_arg_helper.h
${NEO_SOURCE_DIR}/offline_compiler/ocloc_arg_helper.cpp
${NEO_SOURCE_DIR}/offline_compiler/ocloc_fatbinary.cpp
${NEO_SOURCE_DIR}/offline_compiler/ocloc_fatbinary.h
${NEO_SOURCE_DIR}/offline_compiler/offline_compiler_helper.cpp
@ -47,24 +51,24 @@ set(CLOC_SRCS_LIB
)
if(${IGA_HEADERS_AVAILABLE})
set(CLOC_SRCS_LIB ${CLOC_SRCS_LIB}
set(CLOC_LIB_SRCS_LIB ${CLOC_LIB_SRCS_LIB}
${NEO_SOURCE_DIR}/offline_compiler/decoder/iga_wrapper.cpp
${NEO_SOURCE_DIR}/offline_compiler/decoder${BRANCH_DIR_SUFFIX}/translate_platform.cpp
)
else()
set(CLOC_SRCS_LIB ${CLOC_SRCS_LIB}
set(CLOC_LIB_SRCS_LIB ${CLOC_LIB_SRCS_LIB}
${NEO_SOURCE_DIR}/offline_compiler/decoder/iga_stubs.cpp
)
endif()
if(WIN32)
list(APPEND CLOC_SRCS_LIB
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_SRCS_LIB
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
@ -73,7 +77,7 @@ endif()
string(REPLACE ";" "," ALL_SUPPORTED_PRODUCT_FAMILIES "${ALL_SUPPORTED_PRODUCT_FAMILY}")
set(CLOC_LIB_FLAGS_DEFINITIONS
set(CLOC_LIB_LIB_FLAGS_DEFINITIONS
-DCIF_HEADERS_ONLY_BUILD
-DALL_SUPPORTED_PRODUCT_FAMILIES=${ALL_SUPPORTED_PRODUCT_FAMILIES}
)
@ -83,43 +87,34 @@ set(RUNTIME_GENX_CPP_FILES
)
macro(macro_for_each_platform)
list(APPEND CLOC_SRCS_LIB ${NEO_SOURCE_DIR}/opencl/source/${GEN_TYPE_LOWER}/hw_info_${PLATFORM_IT_LOWER}.inl)
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_SRCS_LIB ${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_SRCS_LIB ${NEO_CORE_DIRECTORY}/${GEN_TYPE_LOWER}/enable_${GEN_TYPE_LOWER}.cpp)
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_SRCS
${CLOC_SRCS_LIB}
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
set(CLOC_LIB_SRCS
${CLOC_LIB_SRCS_LIB}
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
)
add_executable(ocloc ${CLOC_SRCS})
if(UNIX)
install(FILES $<TARGET_FILE:ocloc>
DESTINATION ${CMAKE_INSTALL_BINDIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
COMPONENT ocloc)
set_property(GLOBAL APPEND PROPERTY NEO_COMPONENTS_LIST "ocloc")
endif()
add_library(ocloc_lib SHARED ${CLOC_LIB_SRCS})
add_subdirectories()
create_project_source_tree(ocloc)
create_project_source_tree(ocloc_lib)
set(CLOC_INCLUDES
set(CLOC_LIB_INCLUDES
${ENGINE_NODE_DIR}
${IGC_OCL_ADAPTOR_DIR}
${CIF_BASE_DIR}
@ -128,22 +123,75 @@ set(CLOC_INCLUDES
${NEO__IGC_INCLUDE_DIR}
)
target_include_directories(ocloc BEFORE PRIVATE ${CLOC_INCLUDES})
target_include_directories(ocloc BEFORE PRIVATE ${IGA_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 PUBLIC ${CLOC_LIB_FLAGS_DEFINITIONS} ${SUPPORTED_GEN_FLAGS_DEFINITONS} DEFAULT_PLATFORM=${DEFAULT_SUPPORTED_PLATFORM}
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 PRIVATE ${NEO__IGC_COMPILE_DEFINITIONS})
target_compile_definitions(ocloc_lib PRIVATE ${NEO__IGC_COMPILE_DEFINITIONS})
if(MSVC)
target_link_libraries(ocloc dbghelp)
target_link_libraries(ocloc_lib dbghelp)
endif()
if(UNIX)
target_link_libraries(ocloc dl pthread)
target_link_libraries(ocloc_lib dl pthread)
endif()
set(CLOC_LIB_SRCS_LIB ${CLOC_LIB_SRCS_LIB} PARENT_SCOPE)
set(CLOC_SRCS
${NEO_CORE_DIRECTORY}/os_interface/os_library.h
${NEO_SOURCE_DIR}/offline_compiler/ocloc_wrapper.h
${NEO_SOURCE_DIR}/offline_compiler/ocloc_wrapper.cpp
${NEO_SOURCE_DIR}/offline_compiler/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
${NEO_SOURCE_DIR}/offline_compiler/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
${NEO_SOURCE_DIR}/offline_compiler/utilities/linux/get_path.cpp
)
endif()
add_executable(ocloc ${CLOC_SRCS} ${NEO_SOURCE_DIR}/offline_compiler/main.cpp)
add_dependencies(ocloc ocloc_lib)
target_link_libraries(ocloc ocloc_lib)
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")
@ -153,10 +201,11 @@ if(WIN32)
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()
set(CLOC_SRCS_LIB ${CLOC_SRCS_LIB} PARENT_SCOPE)

128
offline_compiler/api.cpp Normal file
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

@ -45,7 +45,7 @@ T readUnaligned(const void *ptr) {
int BinaryDecoder::decode() {
parseTokens();
std::ofstream ptmFile(pathToDump + "PTM.txt");
std::stringstream ptmFile;
auto devBinPtr = getDevBinary();
if (devBinPtr == nullptr) {
messagePrinter.printf("Error! Device Binary section was not found.\n");
@ -85,7 +85,7 @@ void BinaryDecoder::dumpField(const void *&binaryPtr, const PTField &field, std:
}
const void *BinaryDecoder::getDevBinary() {
binary = readBinaryFile(binaryFile);
binary = argHelper->readBinaryFile(binaryFile);
const void *data = nullptr;
std::string decoderErrors;
std::string decoderWarnings;
@ -95,18 +95,15 @@ const void *BinaryDecoder::getDevBinary() {
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: {
std::ofstream ofs(pathToDump + "llvm.bin", std::ios::binary);
ofs.write(sectionData.begin(), sectionData.size());
argHelper->saveOutput(pathToDump + "llvm.bin", sectionData.begin(), sectionData.size());
break;
}
case NEO::Elf::SHT_OPENCL_SPIRV: {
std::ofstream ofs(pathToDump + "spirv.bin", std::ios::binary);
ofs.write(sectionData.begin(), sectionData.size());
argHelper->saveOutput(pathToDump + "spirv.bin", sectionData.begin(), sectionData.size());
break;
}
case NEO::Elf::SHT_OPENCL_OPTIONS: {
std::ofstream ofs(pathToDump + "build.bin", std::ios::binary);
ofs.write(sectionData.begin(), sectionData.size());
argHelper->saveOutput(pathToDump + "build.bin", sectionData.begin(), sectionData.size());
break;
}
case NEO::Elf::SHT_OPENCL_DEV_BINARY: {
@ -135,70 +132,78 @@ uint8_t BinaryDecoder::getSize(const std::string &typeStr) {
}
}
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
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);
}
auto patchList = loadPatchList();
size_t pos = findPos(patchList, "struct SProgramBinaryHeader");
if (pos == patchList.size()) {
@ -354,6 +359,8 @@ int BinaryDecoder::processBinary(const void *&ptr, std::ostream &ptmFile) {
ptmFile << "Kernel #" << i << '\n';
processKernel(ptr, ptmFile);
}
argHelper->saveOutput(pathToDump + "PTM.txt", ptmFile);
return 0;
}
@ -394,12 +401,12 @@ void BinaryDecoder::processKernel(const void *&ptr, std::ostream &ptmFile) {
messagePrinter.printf("Trying to disassemble %s.krn\n", kernelName.c_str());
std::string disassembledKernel;
if (iga->tryDisassembleGenISA(ptr, KernelHeapUnpaddedSize, disassembledKernel)) {
writeDataToFile((fileName + ".asm").c_str(), disassembledKernel.data(), disassembledKernel.size());
argHelper->saveOutput(fileName + ".asm", disassembledKernel.data(), disassembledKernel.size());
} else {
if (ignoreIsaPadding) {
writeDataToFile((fileName + ".dat").c_str(), ptr, KernelHeapUnpaddedSize);
argHelper->saveOutput(fileName + ".dat", ptr, KernelHeapUnpaddedSize);
} else {
writeDataToFile((fileName + ".dat").c_str(), ptr, KernelHeapSize);
argHelper->saveOutput(fileName + ".dat", ptr, KernelHeapSize);
}
}
ptr = ptrOffset(ptr, KernelHeapSize);
@ -407,16 +414,16 @@ void BinaryDecoder::processKernel(const void *&ptr, std::ostream &ptmFile) {
if (GeneralStateHeapSize != 0) {
messagePrinter.printf("Warning! GeneralStateHeapSize wasn't 0.\n");
fileName = pathToDump + kernelName + "_GeneralStateHeap.bin";
writeDataToFile(fileName.c_str(), ptr, DynamicStateHeapSize);
argHelper->saveOutput(fileName, ptr, DynamicStateHeapSize);
ptr = ptrOffset(ptr, GeneralStateHeapSize);
}
fileName = pathToDump + kernelName + "_DynamicStateHeap.bin";
writeDataToFile(fileName.c_str(), ptr, DynamicStateHeapSize);
argHelper->saveOutput(fileName, ptr, DynamicStateHeapSize);
ptr = ptrOffset(ptr, DynamicStateHeapSize);
fileName = pathToDump + kernelName + "_SurfaceStateHeap.bin";
writeDataToFile(fileName.c_str(), ptr, SurfaceStateHeapSize);
argHelper->saveOutput(fileName, ptr, SurfaceStateHeapSize);
ptr = ptrOffset(ptr, SurfaceStateHeapSize);
if (KernelPatchListSize == 0) {
@ -501,33 +508,34 @@ uint32_t BinaryDecoder::readStructFields(const std::vector<std::string> &patchLi
return fullSize;
}
int BinaryDecoder::validateInput(uint32_t argc, const char **argv) {
if (!strcmp(argv[argc - 1], "--help")) {
int BinaryDecoder::validateInput(const std::vector<std::string> &args) {
if (args[args.size() - 1] == "-help") {
printHelp();
return -1;
}
for (uint32_t i = 2; i < argc; ++i) {
if (i < argc - 1) {
if (!strcmp(argv[i], "-file")) {
binaryFile = std::string(argv[++i]);
} else if (!strcmp(argv[i], "-device")) {
iga->setProductFamily(getProductFamilyFromDeviceName(argv[++i]));
} else if (!strcmp(argv[i], "-patch")) {
pathToPatch = std::string(argv[++i]);
addSlash(pathToPatch);
} else if (!strcmp(argv[i], "-dump")) {
pathToDump = std::string(argv[++i]);
addSlash(pathToDump);
}
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 {
if (!strcmp(argv[i], "-ignore_isa_padding")) {
ignoreIsaPadding = true;
} else {
messagePrinter.printf("Unknown argument %s\n", argv[i]);
printHelp();
return -1;
}
messagePrinter.printf("Unknown argument %s\n", currArg.c_str());
printHelp();
return -1;
}
}
if (binaryFile.find(".bin") == std::string::npos) {
@ -535,15 +543,15 @@ int BinaryDecoder::validateInput(uint32_t argc, const char **argv) {
printHelp();
return -1;
}
if (pathToDump.empty()) {
messagePrinter.printf("Warning : Path to dump folder not specificed - using ./dump as default.\n");
pathToDump = std::string("dump/");
}
if (false == iga->isKnownPlatform()) {
messagePrinter.printf("Warning : missing or invalid -device parameter - results may be inacurate\n");
}
MakeDirectory(pathToDump.c_str());
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

@ -8,6 +8,7 @@
#pragma once
#include "offline_compiler/decoder/helper.h"
#include "offline_compiler/decoder/iga_wrapper.h"
#include "offline_compiler/ocloc_arg_helper.h"
#include <memory>
#include <string>
@ -33,15 +34,21 @@ 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(uint32_t argc, const char **argv);
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;
@ -53,6 +60,7 @@ class BinaryDecoder {
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);

View File

@ -56,16 +56,8 @@ void BinaryEncoder::calculatePatchListSizes(std::vector<std::string> &ptmFile) {
}
bool BinaryEncoder::copyBinaryToBinary(const std::string &srcFileName, std::ostream &outBinary, uint32_t *binaryLength) {
std::ifstream ifs(srcFileName, std::ios::binary);
if (!ifs.good()) {
messagePrinter.printf("Cannot open %s.\n", srcFileName.c_str());
return false;
}
ifs.seekg(0, ifs.end);
auto length = static_cast<size_t>(ifs.tellg());
ifs.seekg(0, ifs.beg);
std::vector<char> binary(length);
ifs.read(binary.data(), length);
auto binary = argHelper->readBinaryFile(srcFileName);
auto length = binary.size();
outBinary.write(binary.data(), length);
if (binaryLength) {
@ -75,27 +67,24 @@ bool BinaryEncoder::copyBinaryToBinary(const std::string &srcFileName, std::ostr
return true;
}
int BinaryEncoder::createElf() {
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 (fileExists(pathToDump + "build.bin")) {
auto binary = readBinaryFile(pathToDump + "build.bin");
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 (fileExists(pathToDump + "llvm.bin")) {
auto binary = readBinaryFile(pathToDump + "llvm.bin");
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 (fileExists(pathToDump + "spirv.bin")) {
auto binary = readBinaryFile(pathToDump + "spirv.bin");
std::string data(binary.begin(), binary.end());
} 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 {
@ -103,25 +92,15 @@ int BinaryEncoder::createElf() {
}
//Device Binary
if (fileExists(pathToDump + "device_binary.bin")) {
auto binary = readBinaryFile(pathToDump + "device_binary.bin");
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()));
} else {
messagePrinter.printf("Missing device_binary.bin\n");
return -1;
}
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());
std::ofstream elfFile(elfName, std::ios::binary);
if (!elfFile.good()) {
messagePrinter.printf("Couldn't create %s.\n", elfName.c_str());
return -1;
}
elfFile.write(reinterpret_cast<const char *>(elfBinary.data()), elfBinary.size());
return 0;
}
@ -160,21 +139,23 @@ Examples:
int BinaryEncoder::encode() {
std::vector<std::string> ptmFile;
readFileToVectorOfStrings(ptmFile, pathToDump + "PTM.txt");
calculatePatchListSizes(ptmFile);
std::ofstream deviceBinary(pathToDump + "device_binary.bin", std::ios::binary);
if (!deviceBinary.good()) {
messagePrinter.printf("Error! Couldn't create device_binary.bin.\n");
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);
deviceBinary.close();
argHelper->saveOutput(pathToDump + "device_binary.bin", deviceBinary.str().c_str(), deviceBinary.str().length());
if (retVal != CL_SUCCESS) {
return retVal;
}
return createElf();
retVal = createElf(deviceBinary);
return retVal;
}
int BinaryEncoder::processBinary(const std::vector<std::string> &ptmFileLines, std::ostream &deviceBinary) {
@ -252,8 +233,8 @@ int BinaryEncoder::processKernel(size_t &line, const std::vector<std::string> &p
bool heapsCopiedSuccesfully = true;
// Use .asm if available, fallback to .dat
if (fileExists(pathToDump + kernelName + "_KernelHeap.asm")) {
auto kernelAsAsm = readBinaryFile(pathToDump + kernelName + "_KernelHeap.asm");
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)) {
@ -278,7 +259,7 @@ int BinaryEncoder::processKernel(size_t &line, const std::vector<std::string> &p
}
// Write GeneralStateHeap, DynamicStateHeap, SurfaceStateHeap
if (fileExists(pathToDump + kernelName + "_GeneralStateHeap.bin")) {
if (argHelper->fileExists(pathToDump + kernelName + "_GeneralStateHeap.bin")) {
heapsCopiedSuccesfully = heapsCopiedSuccesfully && copyBinaryToBinary(pathToDump + kernelName + "_GeneralStateHeap.bin", kernelBlob);
}
heapsCopiedSuccesfully = heapsCopiedSuccesfully && copyBinaryToBinary(pathToDump + kernelName + "_DynamicStateHeap.bin", kernelBlob);
@ -324,40 +305,39 @@ int BinaryEncoder::processKernel(size_t &line, const std::vector<std::string> &p
return 0;
}
int BinaryEncoder::validateInput(uint32_t argc, const char **argv) {
if (!strcmp(argv[argc - 1], "--help")) {
int BinaryEncoder::validateInput(const std::vector<std::string> &args) {
if ("-help" == args[args.size() - 1]) {
printHelp();
return -1;
}
for (uint32_t i = 2; i < argc; ++i) {
if (i < argc - 1) {
if (!strcmp(argv[i], "-dump")) {
pathToDump = std::string(argv[++i]);
addSlash(pathToDump);
} else if (!strcmp(argv[i], "-device")) {
iga->setProductFamily(getProductFamilyFromDeviceName(argv[++i]));
} else if (!strcmp(argv[i], "-out")) {
elfName = std::string(argv[++i]);
} else {
messagePrinter.printf("Unknown argument %s\n", argv[i]);
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 {
if (!strcmp(argv[i], "-ignore_isa_padding")) {
ignoreIsaPadding = true;
} else {
messagePrinter.printf("Unknown argument %s\n", argv[i]);
printHelp();
return -1;
}
messagePrinter.printf("Unknown argument %s\n", currArg.c_str());
printHelp();
return -1;
}
}
if (pathToDump.empty()) {
messagePrinter.printf("Warning : Path to dump folder not specificed - using ./dump as default.\n");
pathToDump = "dump";
addSlash(pathToDump);
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");
@ -428,11 +408,3 @@ int BinaryEncoder::writeDeviceBinary(const std::string &line, std::ostream &devi
}
return 0;
}
bool BinaryEncoder::fileExists(const std::string &path) const {
return ::fileExists(path);
}
std::vector<char> BinaryEncoder::readBinaryFile(const std::string &path) const {
return ::readBinaryFile(path);
}

View File

@ -6,6 +6,8 @@
*/
#pragma once
#include "offline_compiler/ocloc_arg_helper.h"
#include "helper.h"
#include "iga_wrapper.h"
@ -17,15 +19,20 @@ 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(uint32_t argc, const char **argv);
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;
@ -35,7 +42,7 @@ class BinaryEncoder {
bool copyBinaryToBinary(const std::string &srcFileName, std::ostream &outBinary) {
return copyBinaryToBinary(srcFileName, outBinary, nullptr);
}
int createElf();
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);
@ -43,6 +50,4 @@ class BinaryEncoder {
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);
MOCKABLE_VIRTUAL bool fileExists(const std::string &path) const;
MOCKABLE_VIRTUAL std::vector<char> readBinaryFile(const std::string &path) const;
};

View File

@ -1,128 +1,13 @@
/*
* Copyright (C) 2017-2020 Intel Corporation
* Copyright (C) 2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/os_interface/os_library.h"
#include "ocloc_wrapper.h"
#include "offline_compiler/multi_command.h"
#include "offline_compiler/ocloc_fatbinary.h"
#include "offline_compiler/offline_compiler.h"
#include "decoder/binary_decoder.h"
#include "decoder/binary_encoder.h"
#include <CL/cl.h>
#include <fstream>
#include <iostream>
using namespace NEO;
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
)===");
}
int main(int numArgs, const char *argv[]) {
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;
int retVal = disasm.validateInput(numArgs, argv);
if (retVal == 0) {
return disasm.decode();
} else {
return retVal;
}
} else if (numArgs > 1 && !strcmp(argv[1], "asm")) {
BinaryEncoder assembler;
int retVal = assembler.validateInput(numArgs, argv);
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;
std::vector<std::string> allArgs;
if (numArgs > 1) {
allArgs.assign(argv, argv + numArgs);
}
auto pMulti = std::unique_ptr<MultiCommand>(MultiCommand::create(allArgs, retValue));
return retValue;
} else {
if (requestedFatBinary(numArgs, argv)) {
return buildFatbinary(numArgs, argv);
}
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);
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);
printf("Command was:");
for (auto i = 0; i < numArgs; ++i)
printf(" %s", argv[i]);
printf("\n");
}
}
delete pCompiler;
return retVal;
}
} catch (const std::exception &e) {
printf("%s\n", e.what());
return -1;
}
return -1;
int main(int argc, const char *argv[]) {
OclocWrapper oclocWrapper;
return oclocWrapper.invokeOcloc(argc, argv);
}

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,28 @@
/*
* Copyright (C) 2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "offline_compiler/multi_command.h"
#include "offline_compiler/offline_compiler.h"
#include "decoder/binary_decoder.h"
#include "decoder/binary_encoder.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,94 @@
/*
* 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 = getPath() + OCLOC_LIB_NAME;
ocloc.library.reset(NEO::OsLibrary::load(oclocLibName));
if (nullptr == ocloc.library) {
std::cout << "Error! Couldn't find " << OCLOC_LIB_NAME << ".\n";
return;
}
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

@ -78,6 +78,24 @@ OfflineCompiler *OfflineCompiler::create(size_t numArgs, const std::vector<std::
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);
}
@ -256,7 +274,7 @@ int OfflineCompiler::initialize(size_t numArgs, const std::vector<std::string> &
oclocOptionsFileName.append("_ocloc_options.txt");
std::string oclocOptionsFromFile;
bool oclocOptionsRead = readOptionsFromFile(oclocOptionsFromFile, oclocOptionsFileName);
bool oclocOptionsRead = readOptionsFromFile(oclocOptionsFromFile, oclocOptionsFileName, argHelper);
if (oclocOptionsRead && !isQuiet()) {
printf("Building with ocloc options:\n%s\n", oclocOptionsFromFile.c_str());
}
@ -275,7 +293,7 @@ int OfflineCompiler::initialize(size_t numArgs, const std::vector<std::string> &
std::string optionsFileName = inputFile.substr(0, ext_start);
optionsFileName.append("_options.txt");
bool optionsRead = readOptionsFromFile(options, optionsFileName);
bool optionsRead = readOptionsFromFile(options, optionsFileName, argHelper);
if (optionsRead && !isQuiet()) {
printf("Building with options:\n%s\n", options.c_str());
}
@ -284,7 +302,7 @@ int OfflineCompiler::initialize(size_t numArgs, const std::vector<std::string> &
internalOptionsFileName.append("_internal_options.txt");
std::string internalOptionsFromFile;
bool internalOptionsRead = readOptionsFromFile(internalOptionsFromFile, internalOptionsFileName);
bool internalOptionsRead = readOptionsFromFile(internalOptionsFromFile, internalOptionsFileName, argHelper);
if (internalOptionsRead && !isQuiet()) {
printf("Building with internal options:\n%s\n", internalOptionsFromFile.c_str());
}
@ -295,7 +313,7 @@ int OfflineCompiler::initialize(size_t numArgs, const std::vector<std::string> &
parseDebugSettings();
// set up the device inside the program
sourceFromFile = loadDataFromFile(inputFile.c_str(), sourceFromFileSize);
sourceFromFile = argHelper->loadDataFromFile(inputFile, sourceFromFileSize);
if (sourceFromFileSize == 0) {
retVal = INVALID_FILE;
return retVal;
@ -507,7 +525,7 @@ int OfflineCompiler::parseCommandLine(size_t numArgs, const std::vector<std::str
} else if (deviceName.empty()) {
printf("Error: Device name missing.\n");
retVal = INVALID_COMMAND_LINE;
} else if (!fileExists(inputFile)) {
} else if (!argHelper->fileExists(inputFile)) {
printf("Error: Input file %s missing.\n", inputFile.c_str());
retVal = INVALID_FILE;
} else {
@ -828,24 +846,18 @@ void OfflineCompiler::writeOutAllFiles() {
if (irBinary) {
std::string irOutputFileName = generateFilePathForIr(fileBase) + generateOptsSuffix();
writeDataToFile(
irOutputFileName.c_str(),
irBinary,
irBinarySize);
argHelper->saveOutput(irOutputFileName, irBinary, irBinarySize);
}
if (genBinary) {
std::string genOutputFile = generateFilePath(outputDirectory, fileBase, ".gen") + generateOptsSuffix();
writeDataToFile(
genOutputFile.c_str(),
genBinary,
genBinarySize);
argHelper->saveOutput(genOutputFile, genBinary, genBinarySize);
if (useCppFile) {
std::string cppOutputFile = generateFilePath(outputDirectory, fileBase, ".cpp");
std::string cpp = parseBinAsCharArray((uint8_t *)genBinary, genBinarySize, fileTrunk);
writeDataToFile(cppOutputFile.c_str(), cpp.c_str(), cpp.size());
argHelper->saveOutput(cppOutputFile, cpp.c_str(), cpp.size());
}
}
@ -856,8 +868,8 @@ void OfflineCompiler::writeOutAllFiles() {
} else {
elfOutputFile = generateFilePath(outputDirectory, fileBase, ".bin") + generateOptsSuffix();
}
writeDataToFile(
elfOutputFile.c_str(),
argHelper->saveOutput(
elfOutputFile,
elfBinary.data(),
elfBinary.size());
}
@ -865,19 +877,19 @@ void OfflineCompiler::writeOutAllFiles() {
if (debugDataBinary) {
std::string debugOutputFile = generateFilePath(outputDirectory, fileBase, ".dbg") + generateOptsSuffix();
writeDataToFile(
debugOutputFile.c_str(),
argHelper->saveOutput(
debugOutputFile,
debugDataBinary,
debugDataBinarySize);
}
}
bool OfflineCompiler::readOptionsFromFile(std::string &options, const std::string &file) {
if (!fileExists(file)) {
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 = loadDataFromFile(file.c_str(), optionsSize);
auto optionsFromFile = helper->loadDataFromFile(file, optionsSize);
if (optionsSize > 0) {
// Remove comment containing copyright header
options = optionsFromFile.get();

View File

@ -11,6 +11,8 @@
#include "shared/source/utilities/arrayref.h"
#include "shared/source/utilities/const_stringref.h"
#include "offline_compiler/ocloc_arg_helper.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"
@ -38,6 +40,7 @@ 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();
@ -51,7 +54,9 @@ class OfflineCompiler {
}
std::string parseBinAsCharArray(uint8_t *binary, size_t size, std::string &fileName);
static bool readOptionsFromFile(std::string &optionsOut, const std::string &file);
static bool readOptionsFromFile(std::string &optionsOut, const std::string &file, std::unique_ptr<OclocArgHelper> &helper);
ArrayRef<const uint8_t> getPackedDeviceBinaryOutput() {
return this->elfBinary;
}
@ -126,5 +131,7 @@ class OfflineCompiler {
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

@ -4,24 +4,27 @@
# SPDX-License-Identifier: MIT
#
set(CLOC_SRCS_UTILITIES
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_SRCS_UTILITIES
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_SRCS_UTILITIES
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 PRIVATE ${CLOC_SRCS_UTILITIES})
target_sources(ocloc_lib PRIVATE ${CLOC_LIB_SRCS_UTILITIES})

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,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,12 @@
/*
* Copyright (C) 2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include <string>
std::string getPath() {
return std::string("");
}

View File

@ -64,11 +64,12 @@ function(compile_builtin gen_type platform_type builtin bits builtin_options)
set(cloc_cmd_prefix ocloc)
else()
if(DEFINED NEO__IGC_LIBRARY_PATH)
set(cloc_cmd_prefix LD_LIBRARY_PATH=${NEO__IGC_LIBRARY_PATH} $<TARGET_FILE:ocloc>)
set(cloc_cmd_prefix LD_LIBRARY_PATH=${NEO__IGC_LIBRARY_PATH}:$<TARGET_FILE_DIR:ocloc_lib> $<TARGET_FILE:ocloc>)
else()
set(cloc_cmd_prefix LD_LIBRARY_PATH=$<TARGET_FILE_DIR:ocloc> $<TARGET_FILE:ocloc>)
set(cloc_cmd_prefix LD_LIBRARY_PATH=$<TARGET_FILE_DIR:ocloc_lib> $<TARGET_FILE:ocloc>)
endif()
endif()
list(APPEND __cloc__options__ "-cl-kernel-arg-info")
add_custom_command(
OUTPUT ${OUTPUT_FILES}

View File

@ -35,9 +35,9 @@ function(compile_kernel target gen_type platform_type kernel)
set(cloc_cmd_prefix ocloc)
else()
if(DEFINED NEO__IGC_LIBRARY_PATH)
set(cloc_cmd_prefix LD_LIBRARY_PATH=${NEO__IGC_LIBRARY_PATH} $<TARGET_FILE:ocloc>)
set(cloc_cmd_prefix LD_LIBRARY_PATH=${NEO__IGC_LIBRARY_PATH}:$<TARGET_FILE_DIR:ocloc_lib> $<TARGET_FILE:ocloc>)
else()
set(cloc_cmd_prefix LD_LIBRARY_PATH=$<TARGET_FILE_DIR:ocloc> $<TARGET_FILE:ocloc>)
set(cloc_cmd_prefix LD_LIBRARY_PATH=$<TARGET_FILE_DIR:ocloc_lib> $<TARGET_FILE:ocloc>)
endif()
endif()
list(APPEND __cloc__options__ "-cl-kernel-arg-info")

View File

@ -205,9 +205,9 @@ if(WIN32)
set(cloc_cmd_prefix ocloc)
else()
if(DEFINED NEO__IGC_LIBRARY_PATH)
set(cloc_cmd_prefix LD_LIBRARY_PATH=${NEO__IGC_LIBRARY_PATH} $<TARGET_FILE:ocloc>)
set(cloc_cmd_prefix LD_LIBRARY_PATH=${NEO__IGC_LIBRARY_PATH}:$<TARGET_FILE_DIR:ocloc_lib> $<TARGET_FILE:ocloc>)
else()
set(cloc_cmd_prefix LD_LIBRARY_PATH=$<TARGET_FILE_DIR:ocloc> $<TARGET_FILE:ocloc>)
set(cloc_cmd_prefix LD_LIBRARY_PATH=$<TARGET_FILE_DIR:ocloc_lib> $<TARGET_FILE:ocloc>)
endif()
endif()

View File

@ -20,15 +20,16 @@ ${CMAKE_CURRENT_SOURCE_DIR}/decoder/mock/mock_encoder.h
${CMAKE_CURRENT_SOURCE_DIR}/decoder/mock/mock_iga_wrapper.h
${CMAKE_CURRENT_SOURCE_DIR}/mock/mock_offline_compiler.h
${CMAKE_CURRENT_SOURCE_DIR}/mock/mock_sip_ocloc_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mock/mock_argument_helper.h
)
set(CLOC_SRCS_UTILITIES
set(CLOC_LIB_SRCS_UTILITIES
${NEO_SOURCE_DIR}/offline_compiler/utilities/safety_caller.h
${NEO_SOURCE_DIR}/offline_compiler/utilities//get_current_dir.h
)
if(WIN32)
list(APPEND CLOC_SRCS_UTILITIES
list(APPEND CLOC_LIB_SRCS_UTILITIES
${NEO_SOURCE_DIR}/offline_compiler/utilities/windows/safety_caller_windows.cpp
${NEO_SOURCE_DIR}/offline_compiler/utilities/windows/safety_guard_windows.h
${NEO_SOURCE_DIR}/offline_compiler/utilities/windows/seh_exception.cpp
@ -36,7 +37,7 @@ if(WIN32)
${NEO_SOURCE_DIR}/offline_compiler/utilities/windows/get_current_dir_windows.cpp
)
else()
list(APPEND CLOC_SRCS_UTILITIES
list(APPEND CLOC_LIB_SRCS_UTILITIES
${NEO_SOURCE_DIR}/offline_compiler/utilities/linux/safety_caller_linux.cpp
${NEO_SOURCE_DIR}/offline_compiler/utilities/linux/safety_guard_linux.h
${NEO_SOURCE_DIR}/offline_compiler/utilities/linux/get_current_dir_linux.cpp
@ -62,8 +63,8 @@ set(IGDRCL_SRCS_offline_compiler_tests
${IGDRCL_SRCS_cloc}
${IGDRCL_SRCS_offline_compiler_mock}
${IGDRCL_SRCS_tests_compiler_mocks}
${CLOC_SRCS_LIB}
${CLOC_SRCS_UTILITIES}
${CLOC_LIB_SRCS_LIB}
${CLOC_LIB_SRCS_UTILITIES}
)
if(WIN32)
@ -81,9 +82,9 @@ link_directories(${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
add_executable(ocloc_tests ${IGDRCL_SRCS_offline_compiler_tests})
target_include_directories(ocloc_tests PRIVATE
$<TARGET_PROPERTY:ocloc,INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:ocloc_lib,INCLUDE_DIRECTORIES>
)
target_compile_definitions(ocloc_tests PUBLIC MOCKABLE_VIRTUAL=virtual $<TARGET_PROPERTY:ocloc,INTERFACE_COMPILE_DEFINITIONS>)
target_compile_definitions(ocloc_tests PUBLIC MOCKABLE_VIRTUAL=virtual $<TARGET_PROPERTY:ocloc_lib,INTERFACE_COMPILE_DEFINITIONS>)
target_link_libraries(ocloc_tests gmock-gtest)
@ -95,25 +96,25 @@ if(UNIX)
target_link_libraries(ocloc_tests dl pthread)
endif()
get_property(CLOC_FOLDER TARGET ocloc PROPERTY FOLDER)
get_property(CLOC_COMPILE_FLAGS TARGET ocloc PROPERTY COMPILE_FLAGS)
set_property(TARGET ocloc_tests PROPERTY FOLDER ${CLOC_FOLDER})
set_property(TARGET ocloc_tests APPEND_STRING PROPERTY COMPILE_FLAGS ${CLOC_COMPILE_FLAGS})
get_property(CLOC_LIB_FOLDER TARGET ocloc_lib PROPERTY FOLDER)
get_property(CLOC_LIB_COMPILE_FLAGS TARGET ocloc_lib PROPERTY COMPILE_FLAGS)
set_property(TARGET ocloc_tests PROPERTY FOLDER ${CLOC_LIB_FOLDER})
set_property(TARGET ocloc_tests APPEND_STRING PROPERTY COMPILE_FLAGS ${CLOC_LIB_COMPILE_FLAGS})
string(TOLOWER ${DEFAULT_TESTED_PLATFORM} CLOC_DEFAULT_DEVICE)
string(TOLOWER ${DEFAULT_TESTED_PLATFORM} CLOC_LIB_DEFAULT_DEVICE)
add_custom_target(run_ocloc_tests ALL
DEPENDS ocloc_tests
)
macro(macro_for_each_platform)
if("${PLATFORM_IT_LOWER}" STREQUAL "${CLOC_DEFAULT_DEVICE}")
if("${PLATFORM_IT_LOWER}" STREQUAL "${CLOC_LIB_DEFAULT_DEVICE}")
foreach(PLATFORM_TYPE ${PLATFORM_TYPES})
if(${PLATFORM_IT}_IS_${PLATFORM_TYPE})
get_family_name_with_type(${GEN_TYPE} ${PLATFORM_TYPE})
add_dependencies(run_ocloc_tests prepare_test_kernels_${family_name_with_type})
neo_copy_test_files(copy_test_files_${family_name_with_type} ${family_name_with_type})
add_dependencies(run_ocloc_tests copy_test_files_${family_name_with_type})
set(run_tests_cmd ocloc_tests --device ${CLOC_DEFAULT_DEVICE} --family_type ${family_name_with_type})
set(run_tests_cmd ocloc_tests --device ${CLOC_LIB_DEFAULT_DEVICE} --family_type ${family_name_with_type})
endif()
endforeach()
endif()
@ -123,17 +124,17 @@ macro(macro_for_each_gen)
endmacro()
apply_macro_for_each_gen("TESTED")
set_property(TARGET run_ocloc_tests PROPERTY FOLDER ${CLOC_FOLDER})
set_property(TARGET run_ocloc_tests PROPERTY FOLDER ${CLOC_LIB_FOLDER})
if(WIN32)
add_custom_command(
TARGET run_ocloc_tests
POST_BUILD
COMMAND echo deleting offline compiler files and directories...
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_DEFAULT_DEVICE}/copybuffer_${CLOC_DEFAULT_DEVICE}.bc
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_DEFAULT_DEVICE}/copybuffer_${CLOC_DEFAULT_DEVICE}.gen
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_DEFAULT_DEVICE}/copybuffer_${CLOC_DEFAULT_DEVICE}.bin
COMMAND ${CMAKE_COMMAND} -E remove_directory ${TargetDir}/${CLOC_DEFAULT_DEVICE}/offline_compiler_test
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_LIB_DEFAULT_DEVICE}/copybuffer_${CLOC_LIB_DEFAULT_DEVICE}.bc
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_LIB_DEFAULT_DEVICE}/copybuffer_${CLOC_LIB_DEFAULT_DEVICE}.gen
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_LIB_DEFAULT_DEVICE}/copybuffer_${CLOC_LIB_DEFAULT_DEVICE}.bin
COMMAND ${CMAKE_COMMAND} -E remove_directory ${TargetDir}/${CLOC_LIB_DEFAULT_DEVICE}/offline_compiler_test
COMMAND ${run_tests_cmd}
WORKING_DIRECTORY ${TargetDir}
)
@ -142,10 +143,10 @@ else()
TARGET run_ocloc_tests
POST_BUILD
COMMAND echo deleting offline compiler files and directories...
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_DEFAULT_DEVICE}/*.bc
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_DEFAULT_DEVICE}/*.gen
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_DEFAULT_DEVICE}/*.ll
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_DEFAULT_DEVICE}/*.bin
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_LIB_DEFAULT_DEVICE}/*.bc
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_LIB_DEFAULT_DEVICE}/*.gen
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_LIB_DEFAULT_DEVICE}/*.ll
COMMAND ${CMAKE_COMMAND} -E remove ${TargetDir}/${CLOC_LIB_DEFAULT_DEVICE}/*.bin
COMMAND ${CMAKE_COMMAND} -E remove_directory "${TargetDir}/offline_compiler_test"
COMMAND ${run_tests_cmd}
WORKING_DIRECTORY ${TargetDir}

View File

@ -29,7 +29,7 @@ SKernelBinaryHeaderCommon createKernelBinaryHeaderCommon(const uint32_t kernelNa
namespace NEO {
TEST(DecoderTests, WhenParsingValidListOfParametersThenReturnValueIsZero) {
const char *argv[] = {
std::vector<std::string> args = {
"ocloc",
"decoder",
"-file",
@ -40,22 +40,22 @@ TEST(DecoderTests, WhenParsingValidListOfParametersThenReturnValueIsZero) {
"test_files/created"};
MockDecoder decoder;
EXPECT_EQ(0, decoder.validateInput(static_cast<uint32_t>(arrayCount<const char *>(argv)), argv));
EXPECT_EQ(0, decoder.validateInput(args));
}
TEST(DecoderTests, WhenMissingParametersThenValidateInputReturnsErrorCode) {
const char *argv[] = {
std::vector<std::string> args = {
"ocloc",
"decoder",
"-patch",
"test_files"};
MockDecoder decoder;
EXPECT_NE(0, decoder.validateInput(static_cast<uint32_t>(arrayCount<const char *>(argv)), argv));
EXPECT_NE(0, decoder.validateInput(args));
}
TEST(DecoderTests, GivenWrongParametersWhenParsingParametersThenValidateInputReturnsErrorCode) {
const char *argv[] = {
std::vector<std::string> args = {
"cloc",
"decoder",
"-file",
@ -66,7 +66,7 @@ TEST(DecoderTests, GivenWrongParametersWhenParsingParametersThenValidateInputRet
"test_files/created"};
MockDecoder decoder;
EXPECT_NE(0, decoder.validateInput(static_cast<uint32_t>(arrayCount<const char *>(argv)), argv));
EXPECT_NE(0, decoder.validateInput(args));
}
TEST(DecoderTests, GivenValidSizeStringWhenGettingSizeThenProperOutcomeIsExpectedAndExceptionIsNotThrown) {

View File

@ -17,7 +17,7 @@
namespace NEO {
TEST(EncoderTests, WhenParsingValidListOfParametersThenReturnValueIsZero) {
const char *argv[] = {
std::vector<std::string> args = {
"ocloc",
"asm",
"-dump",
@ -26,11 +26,11 @@ TEST(EncoderTests, WhenParsingValidListOfParametersThenReturnValueIsZero) {
"test_files/binary_gen.bin"};
MockEncoder encoder;
EXPECT_EQ(0, encoder.validateInput(static_cast<uint32_t>(arrayCount<const char *>(argv)), argv));
EXPECT_EQ(0, encoder.validateInput(args));
}
TEST(EncoderTests, WhenMissingParametersThenErrorCodeIsReturned) {
const char *argv[] = {
std::vector<std::string> args = {
"ocloc",
"asm",
"-dump",
@ -38,11 +38,11 @@ TEST(EncoderTests, WhenMissingParametersThenErrorCodeIsReturned) {
"-out"};
MockEncoder encoder;
EXPECT_NE(0, encoder.validateInput(static_cast<uint32_t>(arrayCount<const char *>(argv)), argv));
EXPECT_NE(0, encoder.validateInput(args));
}
TEST(EncoderTests, GivenWrongParametersWhenParsingParametersThenErrorCodeIsReturne) {
const char *argv[] = {
TEST(EncoderTests, GivenWrongParametersWhenParsingParametersThenErrorCodeIsReturned) {
std::vector<std::string> args = {
"ocloc",
"asm",
"-dump",
@ -51,7 +51,7 @@ TEST(EncoderTests, GivenWrongParametersWhenParsingParametersThenErrorCodeIsRetur
"rasputin"};
MockEncoder encoder;
EXPECT_NE(0, encoder.validateInput(static_cast<uint32_t>(arrayCount<const char *>(argv)), argv));
EXPECT_NE(0, encoder.validateInput(args));
}
TEST(EncoderTests, WhenTryingToCopyNonExistingFileThenErrorCodeIsReturned) {

View File

@ -17,6 +17,7 @@ struct MockDecoder : public BinaryDecoder {
: BinaryDecoder(file, patch, dump) {
this->iga.reset(new MockIgaWrapper);
setMessagePrinter(MessagePrinter{true});
argHelper = std::make_unique<OclocArgHelper>();
};
using BinaryDecoder::binaryFile;
using BinaryDecoder::decode;

View File

@ -9,6 +9,7 @@
#include "shared/source/helpers/hash.h"
#include "offline_compiler/decoder/binary_encoder.h"
#include "opencl/test/unit_test/offline_compiler/mock/mock_argument_helper.h"
#include "mock_iga_wrapper.h"
@ -21,8 +22,11 @@ struct MockEncoder : public BinaryEncoder {
: BinaryEncoder(dump, elf) {
this->iga.reset(new MockIgaWrapper);
setMessagePrinter(MessagePrinter{true});
this->argHelper.reset(new MockOclocArgHelper(filesMap));
};
std::map<std::string, std::string> filesMap;
bool copyBinaryToBinary(const std::string &srcFileName, std::ostream &outBinary, uint32_t *binaryLength) override {
auto it = filesMap.find(srcFileName);
if (it == filesMap.end()) {
@ -34,16 +38,6 @@ struct MockEncoder : public BinaryEncoder {
}
return true;
}
bool fileExists(const std::string &path) const override {
return filesMap.count(path) || BinaryEncoder::fileExists(path);
}
std::vector<char> readBinaryFile(const std::string &path) const override {
return filesMap.count(path) ? std::vector<char>(filesMap.at(path).c_str(), filesMap.at(path).c_str() + filesMap.at(path).size())
: BinaryEncoder::readBinaryFile(path);
}
using BinaryEncoder::addPadding;
using BinaryEncoder::calculatePatchListSizes;
using BinaryEncoder::copyBinaryToBinary;
@ -60,6 +54,4 @@ struct MockEncoder : public BinaryEncoder {
MockIgaWrapper *getMockIga() const {
return static_cast<MockIgaWrapper *>(iga.get());
}
std::map<std::string, std::string> filesMap;
};

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "offline_compiler/ocloc_arg_helper.h"
#include <map>
#include <string>
class MockOclocArgHelper : public OclocArgHelper {
public:
std::map<std::string, std::string> &filesMap;
MockOclocArgHelper(std::map<std::string, std::string> &filesMap) : OclocArgHelper(
0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr),
filesMap(filesMap){};
protected:
bool fileExists(const std::string &filename) const override {
return filesMap.find(filename) != filesMap.end();
}
std::vector<char> readBinaryFile(const std::string &filename) override {
auto file = filesMap[filename];
return std::vector<char>(file.begin(), file.end());
}
};

View File

@ -31,6 +31,8 @@ class MockOfflineCompiler : public OfflineCompiler {
using OfflineCompiler::useOptionsSuffix;
MockOfflineCompiler() : OfflineCompiler() {
argHelper.reset(new OclocArgHelper(
0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));
}
int initialize(size_t numArgs, const std::vector<std::string> &argv) {

View File

@ -1051,7 +1051,8 @@ TEST(OfflineCompilerTest, givenNonExistingFilenameWhenUsedToReadOptionsThenReadO
std::string file("non_existing_file");
ASSERT_FALSE(fileExists(file.c_str()));
bool result = OfflineCompiler::readOptionsFromFile(options, file);
auto helper = std::make_unique<OclocArgHelper>();
bool result = OfflineCompiler::readOptionsFromFile(options, file, helper);
EXPECT_FALSE(result);
}

View File

@ -64,9 +64,9 @@ function(compile_builtin gen_type platform_type builtin bits builtin_options)
set(cloc_cmd_prefix ocloc)
else()
if(DEFINED NEO__IGC_LIBRARY_PATH)
set(cloc_cmd_prefix LD_LIBRARY_PATH=${NEO__IGC_LIBRARY_PATH} $<TARGET_FILE:ocloc>)
set(cloc_cmd_prefix LD_LIBRARY_PATH=${NEO__IGC_LIBRARY_PATH}:$<TARGET_FILE_DIR:ocloc_lib> $<TARGET_FILE:ocloc>)
else()
set(cloc_cmd_prefix LD_LIBRARY_PATH=$<TARGET_FILE_DIR:ocloc> $<TARGET_FILE:ocloc>)
set(cloc_cmd_prefix LD_LIBRARY_PATH=$<TARGET_FILE_DIR:ocloc_lib> $<TARGET_FILE:ocloc>)
endif()
endif()
list(APPEND __cloc__options__ "-cl-kernel-arg-info")