mirror of
https://github.com/intel/compute-runtime.git
synced 2025-09-15 13:01:45 +08:00
Allow ocloc to link files
Added 'link' option to ocloc CLI, which allows linking of several IR files to single output file. Supported formats of output file are ELF and LLVM BC. Related-To: NEO-6163 Signed-off-by: Patryk Wrobel <patryk.wrobel@intel.com>
This commit is contained in:

committed by
Compute-Runtime-Automation

parent
504b49effa
commit
53482e6821
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# Copyright (C) 2018-2022 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
@ -10,6 +10,7 @@ set(IGDRCL_SRCS_cloc
|
||||
${OCLOC_DIRECTORY}/source/decoder/binary_decoder.cpp
|
||||
${OCLOC_DIRECTORY}/source/decoder/binary_encoder.cpp
|
||||
${OCLOC_DIRECTORY}/source/offline_compiler.cpp
|
||||
${OCLOC_DIRECTORY}/source/offline_linker.cpp
|
||||
${OCLOC_DIRECTORY}/source/ocloc_fatbinary.cpp
|
||||
)
|
||||
|
||||
@ -19,12 +20,13 @@ set(IGDRCL_SRCS_offline_compiler_mock
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/decoder/mock/mock_iga_wrapper.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mock/mock_argument_helper.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mock/mock_offline_compiler.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mock/mock_offline_linker.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mock/mock_sip_ocloc_tests.cpp
|
||||
)
|
||||
|
||||
set(CLOC_LIB_SRCS_UTILITIES
|
||||
${OCLOC_DIRECTORY}/source/utilities/safety_caller.h
|
||||
${OCLOC_DIRECTORY}/source/utilities//get_current_dir.h
|
||||
${OCLOC_DIRECTORY}/source/utilities/get_current_dir.h
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
@ -58,6 +60,8 @@ set(IGDRCL_SRCS_offline_compiler_tests
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ocloc_validator_tests.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/offline_compiler_tests.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/offline_compiler_tests.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/offline_linker_tests.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/offline_linker_tests.h
|
||||
${NEO_SHARED_DIRECTORY}/helpers/abort.cpp
|
||||
${NEO_SHARED_DIRECTORY}/helpers/file_io.cpp
|
||||
${NEO_SHARED_DIRECTORY}/memory_manager/deferred_deleter.cpp
|
||||
|
@ -1,12 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Intel Corporation
|
||||
* Copyright (C) 2020-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/ocloc_arg_helper.h"
|
||||
#include "shared/source/helpers/string.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
@ -17,6 +19,10 @@ class MockOclocArgHelper : public OclocArgHelper {
|
||||
using FilesMap = std::map<FileName, FileData>;
|
||||
using OclocArgHelper::deviceProductTable;
|
||||
FilesMap &filesMap;
|
||||
bool interceptOutput{false};
|
||||
bool shouldReturnReadingError{false};
|
||||
FilesMap interceptedFiles;
|
||||
|
||||
MockOclocArgHelper(FilesMap &filesMap) : OclocArgHelper(
|
||||
0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr),
|
||||
filesMap(filesMap){};
|
||||
@ -30,4 +36,33 @@ class MockOclocArgHelper : public OclocArgHelper {
|
||||
auto file = filesMap[filename];
|
||||
return std::vector<char>(file.begin(), file.end());
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> loadDataFromFile(const std::string &filename, size_t &retSize) override {
|
||||
if (shouldReturnReadingError) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!fileExists(filename)) {
|
||||
return OclocArgHelper::loadDataFromFile(filename, retSize);
|
||||
}
|
||||
|
||||
const auto &file = filesMap[filename];
|
||||
std::unique_ptr<char[]> result{new char[file.size()]};
|
||||
|
||||
std::copy(file.begin(), file.end(), result.get());
|
||||
retSize = file.size();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void saveOutput(const std::string &filename, const void *pData, const size_t &dataSize) override {
|
||||
if (interceptOutput) {
|
||||
auto &fileContent = interceptedFiles[filename];
|
||||
fileContent.resize(dataSize, '\0');
|
||||
|
||||
memcpy_s(fileContent.data(), fileContent.size(), pData, dataSize);
|
||||
} else {
|
||||
OclocArgHelper::saveOutput(filename, pData, dataSize);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared/offline_compiler/source/offline_linker.h"
|
||||
|
||||
namespace NEO {
|
||||
|
||||
class MockOfflineLinker : public OfflineLinker {
|
||||
public:
|
||||
using OfflineLinker::InputFileContent;
|
||||
using OfflineLinker::OperationMode;
|
||||
|
||||
using OfflineLinker::initHardwareInfo;
|
||||
using OfflineLinker::initialize;
|
||||
using OfflineLinker::loadInputFilesContent;
|
||||
using OfflineLinker::parseCommand;
|
||||
using OfflineLinker::prepareIgc;
|
||||
using OfflineLinker::tryToStoreBuildLog;
|
||||
using OfflineLinker::verifyLinkerCommand;
|
||||
|
||||
using OfflineLinker::hwInfo;
|
||||
using OfflineLinker::inputFilenames;
|
||||
using OfflineLinker::inputFilesContent;
|
||||
using OfflineLinker::internalOptions;
|
||||
using OfflineLinker::operationMode;
|
||||
using OfflineLinker::options;
|
||||
using OfflineLinker::outputFilename;
|
||||
using OfflineLinker::outputFormat;
|
||||
|
||||
bool shouldReturnEmptyHardwareInfoTable{false};
|
||||
bool shouldFailLoadingOfIgcLib{false};
|
||||
bool shouldFailLoadingOfIgcCreateMainFunction{false};
|
||||
bool shouldFailCreationOfIgcMain{false};
|
||||
bool shouldFailCreationOfIgcDeviceContext{false};
|
||||
bool shouldReturnInvalidIgcPlatformHandle{false};
|
||||
bool shouldReturnInvalidGTSystemInfoHandle{false};
|
||||
|
||||
MockOfflineLinker(OclocArgHelper *argHelper) : OfflineLinker{argHelper} {}
|
||||
|
||||
ArrayRef<const HardwareInfo *> getHardwareInfoTable() const override {
|
||||
if (shouldReturnEmptyHardwareInfoTable) {
|
||||
return {};
|
||||
} else {
|
||||
return OfflineLinker::getHardwareInfoTable();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<OsLibrary> loadIgcLibrary() const override {
|
||||
if (shouldFailLoadingOfIgcLib) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return OfflineLinker::loadIgcLibrary();
|
||||
}
|
||||
}
|
||||
|
||||
CIF::CreateCIFMainFunc_t loadCreateIgcMainFunction() const override {
|
||||
if (shouldFailLoadingOfIgcCreateMainFunction) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return OfflineLinker::loadCreateIgcMainFunction();
|
||||
}
|
||||
}
|
||||
|
||||
CIF::RAII::UPtr_t<CIF::CIFMain> createIgcMain(CIF::CreateCIFMainFunc_t createMainFunction) const override {
|
||||
if (shouldFailCreationOfIgcMain) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return OfflineLinker::createIgcMain(createMainFunction);
|
||||
}
|
||||
}
|
||||
|
||||
CIF::RAII::UPtr_t<IGC::IgcOclDeviceCtxTagOCL> createIgcDeviceContext() const override {
|
||||
if (shouldFailCreationOfIgcDeviceContext) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return OfflineLinker::createIgcDeviceContext();
|
||||
}
|
||||
}
|
||||
|
||||
CIF::RAII::UPtr_t<IGC::PlatformTagOCL> getIgcPlatformHandle() const override {
|
||||
if (shouldReturnInvalidIgcPlatformHandle) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return OfflineLinker::getIgcPlatformHandle();
|
||||
}
|
||||
}
|
||||
|
||||
CIF::RAII::UPtr_t<IGC::GTSystemInfoTagOCL> getGTSystemInfoHandle() const override {
|
||||
if (shouldReturnInvalidGTSystemInfoHandle) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return OfflineLinker::getGTSystemInfoHandle();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace NEO
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Intel Corporation
|
||||
* Copyright (C) 2020-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/ocloc_api.h"
|
||||
#include "shared/offline_compiler/source/ocloc_error_code.h"
|
||||
#include "shared/offline_compiler/source/queries.h"
|
||||
#include "shared/offline_compiler/source/utilities/get_git_version_info.h"
|
||||
#include "shared/source/device_binary_format/elf/elf_decoder.h"
|
||||
@ -43,7 +44,7 @@ TEST(OclocApiTests, WhenGoodArgsAreGivenThenSuccessIsReturned) {
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
EXPECT_EQ(std::string::npos, output.find("Command was: ocloc -file test_files/copybuffer.cl -device "s + argv[4]));
|
||||
}
|
||||
|
||||
@ -61,7 +62,7 @@ TEST(OclocApiTests, GivenNeoRevisionQueryWhenQueryingThenNeoRevisionIsReturned)
|
||||
0, nullptr, nullptr, nullptr,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
&numOutputs, &dataOutputs, &lenOutputs, &nameOutputs);
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
EXPECT_EQ(numOutputs, 2u);
|
||||
|
||||
int queryOutputIndex = -1;
|
||||
@ -92,7 +93,7 @@ TEST(OclocApiTests, GivenOclDriverVersionQueryWhenQueryingThenNeoRevisionIsRetur
|
||||
0, nullptr, nullptr, nullptr,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
&numOutputs, &dataOutputs, &lenOutputs, &nameOutputs);
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
EXPECT_EQ(numOutputs, 2u);
|
||||
|
||||
int queryOutputIndex = -1;
|
||||
@ -121,7 +122,7 @@ TEST(OclocApiTests, GivenNoQueryWhenQueryingThenErrorIsReturned) {
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::INVALID_COMMAND_LINE);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::INVALID_COMMAND_LINE);
|
||||
EXPECT_STREQ("Error: Invalid command line. Expected ocloc query <argument>", output.c_str());
|
||||
}
|
||||
|
||||
@ -138,7 +139,7 @@ TEST(OclocApiTests, GivenInvalidQueryWhenQueryingThenErrorIsReturned) {
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::INVALID_COMMAND_LINE);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::INVALID_COMMAND_LINE);
|
||||
EXPECT_STREQ("Error: Invalid command line. Uknown argument unknown_query.", output.c_str());
|
||||
}
|
||||
|
||||
@ -158,7 +159,7 @@ TEST(OclocApiTests, WhenGoodFamilyNameIsProvidedThenSuccessIsReturned) {
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
EXPECT_EQ(std::string::npos, output.find("Command was: ocloc -file test_files/copybuffer.cl -device "s + argv[4]));
|
||||
}
|
||||
|
||||
@ -179,7 +180,7 @@ TEST(OclocApiTests, WhenArgsWithMissingFileAreGivenThenErrorMessageIsProduced) {
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::INVALID_FILE);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::INVALID_FILE);
|
||||
EXPECT_NE(std::string::npos, output.find("Command was: ocloc -q -file test_files/IDoNotExist.cl -device "s + argv[5]));
|
||||
}
|
||||
|
||||
@ -200,7 +201,7 @@ TEST(OclocApiTests, givenInputOptionsAndInternalOptionsWhenCmdlineIsPrintedThenB
|
||||
0, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_NE(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_NE(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
EXPECT_TRUE(output.find("Command was: ocloc -q -file test_files/IDoNotExist.cl -device "s +
|
||||
gEnvironment->devicePrefix.c_str() +
|
||||
" -options \"-D DEBUG -cl-kernel-arg-info\" -internal_options \"-internalOption1 -internal-option-2\"") != std::string::npos);
|
||||
@ -226,7 +227,7 @@ TEST(OclocApiTests, givenInputOptionsCalledOptionsWhenCmdlineIsPrintedThenQuotes
|
||||
0, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_NE(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_NE(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
EXPECT_TRUE(output.find("Command was: ocloc -q -file test_files/IDoNotExist.cl -device "s +
|
||||
gEnvironment->devicePrefix.c_str() +
|
||||
" -options \"-options\" -internal_options \"-internalOption\"") != std::string::npos);
|
||||
@ -255,7 +256,7 @@ TEST(OclocApiTests, givenInvalidInputOptionsAndInternalOptionsFilesWhenCmdlineIs
|
||||
0, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_NE(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_NE(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
|
||||
EXPECT_TRUE(output.find("Compiling options read from file were:\n"
|
||||
"-shouldfailOptions") != std::string::npos);
|
||||
@ -283,7 +284,7 @@ TEST(OclocApiTests, givenInvalidOclocOptionsFileWhenCmdlineIsPrintedThenTheyAreP
|
||||
0, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_NE(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_NE(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
|
||||
EXPECT_TRUE(output.find("Failed with ocloc options from file:\n"
|
||||
"-invalid_ocloc_option") != std::string::npos);
|
||||
@ -396,7 +397,7 @@ TEST(OclocApiTests, GivenHelpParameterWhenDecodingThenHelpMsgIsPrintedAndSuccess
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_FALSE(output.empty());
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
}
|
||||
|
||||
TEST(OclocApiTests, GivenHelpParameterWhenEncodingThenHelpMsgIsPrintedAndSuccessIsReturned) {
|
||||
@ -413,5 +414,109 @@ TEST(OclocApiTests, GivenHelpParameterWhenEncodingThenHelpMsgIsPrintedAndSuccess
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_FALSE(output.empty());
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
}
|
||||
|
||||
TEST(OclocApiTests, GivenNonexistentFileWhenValidateIsInvokedThenErrorIsPrinted) {
|
||||
const char *argv[] = {
|
||||
"ocloc",
|
||||
"validate",
|
||||
"-file",
|
||||
"some_special_nonexistent_file.gen"};
|
||||
unsigned int argc = sizeof(argv) / sizeof(argv[0]);
|
||||
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = oclocInvoke(argc, argv,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
const auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(-1, retVal);
|
||||
|
||||
const std::string expectedErrorMessage{"Error : Input file missing : some_special_nonexistent_file.gen\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST(OclocApiTests, GivenZeroArgumentsWhenOclocIsInvokedThenHelpIsPrinted) {
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = oclocInvoke(0, nullptr,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
const auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(NEO::OclocErrorCode::INVALID_COMMAND_LINE, retVal);
|
||||
EXPECT_FALSE(output.empty());
|
||||
}
|
||||
|
||||
TEST(OclocApiTests, GivenCommandWithoutArgsWhenOclocIsInvokedThenHelpIsPrinted) {
|
||||
const char *argv[] = {
|
||||
"ocloc"};
|
||||
unsigned int argc = sizeof(argv) / sizeof(argv[0]);
|
||||
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = oclocInvoke(argc, argv,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
const auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(NEO::OclocErrorCode::SUCCESS, retVal);
|
||||
EXPECT_FALSE(output.empty());
|
||||
}
|
||||
|
||||
TEST(OclocApiTests, GivenLongHelpArgumentWhenOclocIsInvokedThenHelpIsPrinted) {
|
||||
const char *argv[] = {
|
||||
"ocloc",
|
||||
"--help"};
|
||||
unsigned int argc = sizeof(argv) / sizeof(argv[0]);
|
||||
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = oclocInvoke(argc, argv,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
const auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(NEO::OclocErrorCode::SUCCESS, retVal);
|
||||
EXPECT_FALSE(output.empty());
|
||||
}
|
||||
|
||||
TEST(OclocApiTests, GivenHelpParameterWhenLinkingThenHelpMsgIsPrintedAndSuccessIsReturned) {
|
||||
const char *argv[] = {
|
||||
"ocloc",
|
||||
"link",
|
||||
"--help"};
|
||||
unsigned int argc = sizeof(argv) / sizeof(argv[0]);
|
||||
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = oclocInvoke(argc, argv,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_FALSE(output.empty());
|
||||
EXPECT_EQ(NEO::OclocErrorCode::SUCCESS, retVal);
|
||||
}
|
||||
|
||||
TEST(OclocApiTests, GivenInvalidParameterWhenLinkingThenErrorIsReturned) {
|
||||
const char *argv[] = {
|
||||
"ocloc",
|
||||
"link",
|
||||
"--dummy_param"};
|
||||
unsigned int argc = sizeof(argv) / sizeof(argv[0]);
|
||||
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = oclocInvoke(argc, argv,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
0, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(NEO::OclocErrorCode::INVALID_COMMAND_LINE, retVal);
|
||||
|
||||
const std::string expectedInitError{"Invalid option (arg 2): --dummy_param\n"};
|
||||
const std::string expectedExecuteError{"Error: Linker cannot be executed due to unsuccessful initialization!\n"};
|
||||
const std::string expectedErrorMessage = expectedInitError + expectedExecuteError;
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Intel Corporation
|
||||
* Copyright (C) 2020-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@ -8,6 +8,7 @@
|
||||
#include "opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.h"
|
||||
|
||||
#include "shared/offline_compiler/source/ocloc_arg_helper.h"
|
||||
#include "shared/offline_compiler/source/ocloc_error_code.h"
|
||||
#include "shared/source/helpers/hw_helper.h"
|
||||
|
||||
#include <algorithm>
|
||||
@ -505,7 +506,7 @@ TEST_F(OclocFatBinaryGetTargetConfigsForFatbinary, GivenMutiplePlatformWhenSecon
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = buildFatBinary(argv, argHelper.get());
|
||||
auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_NE(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_NE(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
|
||||
resString << "Unknown device : unk\n";
|
||||
resString << "Failed to parse target devices from : " << platformTarget << "\n";
|
||||
@ -536,7 +537,7 @@ TEST_F(OclocFatBinaryGetTargetConfigsForFatbinary, GivenClosedRangeTooExtensiveW
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = buildFatBinary(argv, argHelper.get());
|
||||
auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_NE(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_NE(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
resString << "Invalid range : " << configString.str() << " - should be from-to or -to or from-"
|
||||
<< "\n";
|
||||
resString << "Failed to parse target devices from : " << configString.str() << "\n";
|
||||
@ -641,7 +642,7 @@ TEST_F(OclocFatBinaryGetTargetConfigsForFatbinary, GivenTwoPlatformsWhenFatBinar
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = buildFatBinary(argv, argHelper.get());
|
||||
auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
|
||||
for (uint32_t i = 0; i < got.size(); i++) {
|
||||
resString << "Build succeeded for : " << expected[i].str() + "." + platformsRevision[i] + ".\n";
|
||||
@ -695,7 +696,7 @@ TEST_F(OclocFatBinaryGetTargetConfigsForFatbinary, GivenPlatformsClosedRangeWhen
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = buildFatBinary(argv, argHelper.get());
|
||||
auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
|
||||
for (uint32_t i = 0; i < got.size(); i++) {
|
||||
resString << "Build succeeded for : " << expected[i].str() + "." + platformsRevisions[i] + ".\n";
|
||||
@ -744,7 +745,7 @@ TEST_F(OclocFatBinaryGetTargetConfigsForFatbinary, GivenPlatformsOpenRangeToWhen
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = buildFatBinary(argv, argHelper.get());
|
||||
auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
|
||||
for (uint32_t i = 0; i < got.size(); i++) {
|
||||
resString << "Build succeeded for : " << expected[i].str() + "." + platformsRevisions[i] + ".\n";
|
||||
@ -793,7 +794,7 @@ TEST_F(OclocFatBinaryGetTargetConfigsForFatbinary, GivenPlatformsOpenRangeFromWh
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = buildFatBinary(argv, argHelper.get());
|
||||
auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
|
||||
for (uint32_t i = 0; i < got.size(); i++) {
|
||||
resString << "Build succeeded for : " << expected[i].str() + "." + platformsRevisions[i] + ".\n";
|
||||
@ -847,7 +848,7 @@ TEST_F(OclocFatBinaryGetTargetConfigsForFatbinary, GivenTwoConfigsWhenFatBinaryB
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = buildFatBinary(argv, argHelper.get());
|
||||
auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
|
||||
for (auto deviceConfig : expected) {
|
||||
std::string platformName = hardwarePrefix[deviceConfig.hwInfo->platform.eProductFamily];
|
||||
@ -893,7 +894,7 @@ TEST_F(OclocFatBinaryGetTargetConfigsForFatbinary, GivenProductConfigOpenRangeFr
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = buildFatBinary(argv, argHelper.get());
|
||||
auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
|
||||
for (auto deviceConfig : expected) {
|
||||
std::string platformName = hardwarePrefix[deviceConfig.hwInfo->platform.eProductFamily];
|
||||
@ -939,7 +940,7 @@ TEST_F(OclocFatBinaryGetTargetConfigsForFatbinary, GivenProductConfigOpenRangeTo
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = buildFatBinary(argv, argHelper.get());
|
||||
auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
|
||||
for (auto deviceConfig : expected) {
|
||||
std::string platformName = hardwarePrefix[deviceConfig.hwInfo->platform.eProductFamily];
|
||||
@ -993,7 +994,7 @@ TEST_F(OclocFatBinaryGetTargetConfigsForFatbinary, GivenProductConfigClosedRange
|
||||
testing::internal::CaptureStdout();
|
||||
int retVal = buildFatBinary(argv, argHelper.get());
|
||||
auto output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS);
|
||||
EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS);
|
||||
|
||||
for (auto deviceConfig : expected) {
|
||||
std::string platformName = hardwarePrefix[deviceConfig.hwInfo->platform.eProductFamily];
|
||||
|
@ -238,7 +238,7 @@ TEST_F(MultiCommandTests, GivenMissingTextFileWithArgsWhenBuildingMultiCommandTh
|
||||
|
||||
EXPECT_STRNE(output.c_str(), "");
|
||||
EXPECT_EQ(nullptr, pMultiCommand);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::INVALID_FILE, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_FILE, retVal);
|
||||
DebugManager.flags.PrintDebugMessages.set(false);
|
||||
}
|
||||
TEST_F(MultiCommandTests, GivenLackOfClFileWhenBuildingMultiCommandThenInvalidFileErrorIsReturned) {
|
||||
@ -263,7 +263,7 @@ TEST_F(MultiCommandTests, GivenLackOfClFileWhenBuildingMultiCommandThenInvalidFi
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
|
||||
EXPECT_EQ(nullptr, pMultiCommand);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::INVALID_FILE, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_FILE, retVal);
|
||||
DebugManager.flags.PrintDebugMessages.set(false);
|
||||
|
||||
deleteFileWithArgs();
|
||||
@ -318,7 +318,7 @@ TEST_F(OfflineCompilerTests, GivenHelpOptionOnQueryThenSuccessIsReturned) {
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
|
||||
EXPECT_STREQ(OfflineCompiler::queryHelp.data(), output.c_str());
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::SUCCESS, retVal);
|
||||
}
|
||||
|
||||
TEST_F(OfflineCompilerTests, GivenArgsWhenQueryIsCalledThenSuccessIsReturned) {
|
||||
@ -329,7 +329,7 @@ TEST_F(OfflineCompilerTests, GivenArgsWhenQueryIsCalledThenSuccessIsReturned) {
|
||||
|
||||
int retVal = OfflineCompiler::query(argv.size(), argv, oclocArgHelperWithoutInput.get());
|
||||
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::SUCCESS, retVal);
|
||||
}
|
||||
|
||||
TEST_F(OfflineCompilerTests, GivenArgsWhenOfflineCompilerIsCreatedThenSuccessIsReturned) {
|
||||
@ -587,7 +587,7 @@ TEST_F(OfflineCompilerTests, givenExcludeIrArgumentWhenCompilingKernelThenIrShou
|
||||
mockOfflineCompiler.initialize(argv.size(), argv);
|
||||
|
||||
const auto buildResult{mockOfflineCompiler.build()};
|
||||
ASSERT_EQ(OfflineCompiler::SUCCESS, buildResult);
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, buildResult);
|
||||
|
||||
std::string errorReason{};
|
||||
std::string warning{};
|
||||
@ -611,7 +611,7 @@ TEST_F(OfflineCompilerTests, givenLackOfExcludeIrArgumentWhenCompilingKernelThen
|
||||
mockOfflineCompiler.initialize(argv.size(), argv);
|
||||
|
||||
const auto buildResult{mockOfflineCompiler.build()};
|
||||
ASSERT_EQ(OfflineCompiler::SUCCESS, buildResult);
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, buildResult);
|
||||
|
||||
std::string errorReason{};
|
||||
std::string warning{};
|
||||
@ -872,7 +872,7 @@ TEST_F(OfflineCompilerTests, GivenHelpOptionThenBuildDoesNotOccur) {
|
||||
pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get());
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_STRNE("", output.c_str());
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::SUCCESS, retVal);
|
||||
|
||||
delete pOfflineCompiler;
|
||||
}
|
||||
@ -890,7 +890,7 @@ TEST_F(OfflineCompilerTests, GivenInvalidFileWhenBuildingThenInvalidFileErrorIsR
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_STRNE(output.c_str(), "");
|
||||
EXPECT_EQ(nullptr, pOfflineCompiler);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::INVALID_FILE, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_FILE, retVal);
|
||||
DebugManager.flags.PrintDebugMessages.set(false);
|
||||
delete pOfflineCompiler;
|
||||
}
|
||||
@ -908,7 +908,7 @@ TEST_F(OfflineCompilerTests, GivenInvalidFlagWhenBuildingThenInvalidCommandLineE
|
||||
std::string output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_STRNE(output.c_str(), "");
|
||||
EXPECT_EQ(nullptr, pOfflineCompiler);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::INVALID_COMMAND_LINE, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, retVal);
|
||||
|
||||
delete pOfflineCompiler;
|
||||
}
|
||||
@ -925,7 +925,7 @@ TEST_F(OfflineCompilerTests, GivenInvalidOptionsWhenBuildingThenInvalidCommandLi
|
||||
EXPECT_STRNE(output.c_str(), "");
|
||||
|
||||
EXPECT_EQ(nullptr, pOfflineCompiler);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::INVALID_COMMAND_LINE, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, retVal);
|
||||
|
||||
delete pOfflineCompiler;
|
||||
|
||||
@ -939,7 +939,7 @@ TEST_F(OfflineCompilerTests, GivenInvalidOptionsWhenBuildingThenInvalidCommandLi
|
||||
output = testing::internal::GetCapturedStdout();
|
||||
EXPECT_STRNE(output.c_str(), "");
|
||||
EXPECT_EQ(nullptr, pOfflineCompiler);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::INVALID_COMMAND_LINE, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, retVal);
|
||||
|
||||
delete pOfflineCompiler;
|
||||
}
|
||||
@ -1724,7 +1724,7 @@ TEST(OfflineCompilerTest, givenCompilerWhenBuildSourceCodeFailsThenGenerateElfBi
|
||||
MockOfflineCompiler compiler;
|
||||
compiler.overrideBuildSourceCodeStatus = true;
|
||||
|
||||
auto expectedError = OfflineCompiler::ErrorCode::BUILD_PROGRAM_FAILURE;
|
||||
auto expectedError = OclocErrorCode::BUILD_PROGRAM_FAILURE;
|
||||
compiler.buildSourceCodeStatus = expectedError;
|
||||
|
||||
EXPECT_EQ(0u, compiler.generateElfBinaryCalled);
|
||||
@ -1755,7 +1755,7 @@ TEST(OfflineCompilerTest, givenDeviceSpecificKernelFileWhenCompilerIsInitialized
|
||||
gEnvironment->devicePrefix.c_str()};
|
||||
|
||||
int retVal = mockOfflineCompiler->initialize(argv.size(), argv);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::SUCCESS, retVal);
|
||||
EXPECT_STREQ("-cl-opt-disable", mockOfflineCompiler->options.c_str());
|
||||
}
|
||||
|
||||
@ -1774,7 +1774,7 @@ TEST(OfflineCompilerTest, givenHexadecimalRevisionIdWhenCompilerIsInitializedThe
|
||||
"0x11"};
|
||||
|
||||
int retVal = mockOfflineCompiler->initialize(argv.size(), argv);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(mockOfflineCompiler->hwInfo.platform.usRevId, 17);
|
||||
}
|
||||
|
||||
@ -1796,7 +1796,7 @@ TEST(OfflineCompilerTest, givenDebugVariableSetWhenInitializingThenOverrideRevis
|
||||
"0x11"};
|
||||
|
||||
int retVal = mockOfflineCompiler->initialize(argv.size(), argv);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(mockOfflineCompiler->hwInfo.platform.usRevId, 123);
|
||||
}
|
||||
|
||||
@ -1815,7 +1815,7 @@ TEST(OfflineCompilerTest, givenDecimalRevisionIdWhenCompilerIsInitializedThenPas
|
||||
"17"};
|
||||
|
||||
int retVal = mockOfflineCompiler->initialize(argv.size(), argv);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(mockOfflineCompiler->hwInfo.platform.usRevId, 17);
|
||||
}
|
||||
|
||||
@ -1834,7 +1834,7 @@ TEST(OfflineCompilerTest, givenNoRevisionIdWhenCompilerIsInitializedThenHwInfoHa
|
||||
mockOfflineCompiler->initHardwareInfo(gEnvironment->devicePrefix.c_str());
|
||||
auto revId = mockOfflineCompiler->hwInfo.platform.usRevId;
|
||||
int retVal = mockOfflineCompiler->initialize(argv.size(), argv);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(mockOfflineCompiler->hwInfo.platform.usRevId, revId);
|
||||
}
|
||||
|
||||
@ -1851,7 +1851,7 @@ TEST(OfflineCompilerTest, whenDeviceIsSpecifiedThenDefaultConfigFromTheDeviceIsU
|
||||
gEnvironment->devicePrefix.c_str()};
|
||||
|
||||
int retVal = mockOfflineCompiler->initialize(argv.size(), argv);
|
||||
EXPECT_EQ(OfflineCompiler::ErrorCode::SUCCESS, retVal);
|
||||
EXPECT_EQ(OclocErrorCode::SUCCESS, retVal);
|
||||
|
||||
HardwareInfo hwInfo = mockOfflineCompiler->hwInfo;
|
||||
|
||||
|
@ -1,12 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 Intel Corporation
|
||||
* Copyright (C) 2018-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared/offline_compiler/source/multi_command.h"
|
||||
#include "shared/offline_compiler/source/ocloc_error_code.h"
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
@ -19,7 +21,7 @@ namespace NEO {
|
||||
class OfflineCompilerTests : public ::testing::Test {
|
||||
public:
|
||||
OfflineCompiler *pOfflineCompiler = nullptr;
|
||||
int retVal = OfflineCompiler::ErrorCode::SUCCESS;
|
||||
int retVal = OclocErrorCode::SUCCESS;
|
||||
std::unique_ptr<OclocArgHelper> oclocArgHelperWithoutInput = std::make_unique<OclocArgHelper>();
|
||||
};
|
||||
|
||||
@ -31,7 +33,7 @@ class MultiCommandTests : public ::testing::Test {
|
||||
MultiCommand *pMultiCommand = nullptr;
|
||||
std::string nameOfFileWithArgs;
|
||||
std::string outFileList;
|
||||
int retVal = OfflineCompiler::ErrorCode::SUCCESS;
|
||||
int retVal = OclocErrorCode::SUCCESS;
|
||||
std::unique_ptr<OclocArgHelper> oclocArgHelperWithoutInput = std::make_unique<OclocArgHelper>();
|
||||
};
|
||||
} // namespace NEO
|
||||
|
793
opencl/test/unit_test/offline_compiler/offline_linker_tests.cpp
Normal file
793
opencl/test/unit_test/offline_compiler/offline_linker_tests.cpp
Normal file
@ -0,0 +1,793 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "offline_linker_tests.h"
|
||||
|
||||
#include "shared/offline_compiler/source/ocloc_error_code.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/string.h"
|
||||
#include "shared/source/os_interface/os_inc_base.h"
|
||||
#include "shared/test/common/mocks/mock_compilers.h"
|
||||
|
||||
#include "environment.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
extern Environment *gEnvironment;
|
||||
|
||||
namespace NEO {
|
||||
|
||||
using OperationMode = MockOfflineLinker::OperationMode;
|
||||
|
||||
void OfflineLinkerTest::SetUp() {
|
||||
MockCompilerDebugVars igcDebugVars{gEnvironment->igcDebugVars};
|
||||
igcDebugVars.binaryToReturn = binaryToReturn;
|
||||
igcDebugVars.binaryToReturnSize = sizeof(binaryToReturn);
|
||||
|
||||
setIgcDebugVars(igcDebugVars);
|
||||
}
|
||||
|
||||
void OfflineLinkerTest::TearDown() {
|
||||
setIgcDebugVars(gEnvironment->igcDebugVars);
|
||||
}
|
||||
|
||||
std::string OfflineLinkerTest::getEmptySpirvFile() const {
|
||||
std::string spirv{"\x07\x23\x02\x03"};
|
||||
spirv.resize(64, '\0');
|
||||
|
||||
return spirv;
|
||||
}
|
||||
|
||||
std::string OfflineLinkerTest::getEmptyLlvmBcFile() const {
|
||||
std::string llvmbc{"BC\xc0\xde"};
|
||||
llvmbc.resize(64, '\0');
|
||||
|
||||
return llvmbc;
|
||||
}
|
||||
|
||||
MockOfflineLinker::InputFileContent OfflineLinkerTest::createFileContent(const std::string &content, IGC::CodeType::CodeType_t codeType) const {
|
||||
std::unique_ptr<char[]> bytes{new char[content.size()]};
|
||||
std::copy(content.begin(), content.end(), bytes.get());
|
||||
|
||||
return {std::move(bytes), content.size(), codeType};
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenDefaultConstructedLinkerThenRequiredFieldsHaveDefaultValues) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
|
||||
EXPECT_EQ(OperationMode::SKIP_EXECUTION, mockOfflineLinker.operationMode);
|
||||
EXPECT_EQ("linker_output", mockOfflineLinker.outputFilename);
|
||||
EXPECT_EQ(IGC::CodeType::llvmBc, mockOfflineLinker.outputFormat);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenLessThanTwoArgumentsWhenParsingThenInvalidCommandIsReturned) {
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe"};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto result = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, result);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenInputFilesArgumentsWhenParsingThenListOfFilenamesIsPopulated) {
|
||||
const std::string firstFile{"sample_input_1.spv"};
|
||||
const std::string secondFile{"sample_input_2.spv"};
|
||||
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-file",
|
||||
firstFile,
|
||||
"-file",
|
||||
secondFile};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto result = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, result);
|
||||
ASSERT_EQ(2u, mockOfflineLinker.inputFilenames.size());
|
||||
|
||||
EXPECT_EQ(firstFile, mockOfflineLinker.inputFilenames[0]);
|
||||
EXPECT_EQ(secondFile, mockOfflineLinker.inputFilenames[1]);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenOutputFilenameArgumentWhenParsingThenOutputFilenameIsSetAccordingly) {
|
||||
const std::string outputFilename{"my_custom_output_filename"};
|
||||
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-out",
|
||||
outputFilename};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto result = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, result);
|
||||
EXPECT_EQ(outputFilename, mockOfflineLinker.outputFilename);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenValidOutputFileFormatWhenParsingThenOutputFormatIsSetAccordingly) {
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-out_format",
|
||||
"LLVM_BC"};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto result = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, result);
|
||||
EXPECT_EQ(IGC::CodeType::llvmBc, mockOfflineLinker.outputFormat);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenUnknownOutputFileFormatWhenParsingThenInvalidFormatIsSet) {
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-out_format",
|
||||
"StrangeFormat"};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto result = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, result);
|
||||
EXPECT_EQ(IGC::CodeType::invalid, mockOfflineLinker.outputFormat);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenOptionsArgumentWhenParsingThenOptionsAreSet) {
|
||||
const std::string options{"-g"};
|
||||
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-options",
|
||||
options};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto result = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, result);
|
||||
EXPECT_EQ(options, mockOfflineLinker.options);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenInternalOptionsArgumentWhenParsingThenInternalOptionsAreSet) {
|
||||
const std::string internalOptions{"-ze-allow-zebin"};
|
||||
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-internal_options",
|
||||
internalOptions};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto result = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, result);
|
||||
EXPECT_EQ(internalOptions, mockOfflineLinker.internalOptions);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenHelpArgumentWhenParsingThenShowHelpOperationIsSet) {
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"--help"};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto result = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, result);
|
||||
EXPECT_EQ(OperationMode::SHOW_HELP, mockOfflineLinker.operationMode);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenUnknownArgumentWhenParsingThenErrorIsReported) {
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-some_new_unknown_command"};
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto result = mockOfflineLinker.initialize(argv.size(), argv);
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, result);
|
||||
|
||||
const std::string expectedErrorMessage{"Invalid option (arg 2): -some_new_unknown_command\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenFlagsWhichRequireMoreArgsWithoutThemWhenParsingThenErrorIsReported) {
|
||||
const std::array<std::string, 5> flagsToTest = {
|
||||
"-file", "-out", "-out_format", "-options", "-internal_options"};
|
||||
|
||||
for (const auto &flag : flagsToTest) {
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
flag};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto result = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, result);
|
||||
|
||||
const std::string expectedErrorMessage{"Invalid option (arg 2): " + flag + "\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenCommandWithoutInputFilesWhenVerificationIsPerformedThenErrorIsReturned) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.inputFilenames = {};
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto verificationResult = mockOfflineLinker.verifyLinkerCommand();
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, verificationResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error: Input name is missing! At least one input file is required!\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenCommandWithEmptyFilenameWhenVerificationIsPerformedThenErrorIsReturned) {
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-file",
|
||||
""};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto verificationResult = mockOfflineLinker.initialize(argv.size(), argv);
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, verificationResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error: Empty filename cannot be used!\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenCommandWithNonexistentInputFileWhenVerificationIsPerformedThenErrorIsReturned) {
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-file",
|
||||
"some_file1.spv",
|
||||
"-file",
|
||||
"some_file2.spv"};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto parsingResult = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, parsingResult);
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto verificationResult = mockOfflineLinker.verifyLinkerCommand();
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_FILE, verificationResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error: Input file some_file1.spv missing.\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenCommandWithInvalidOutputFormatWhenVerificationIsPerformedThenErrorIsReturned) {
|
||||
mockArgHelperFilesMap["some_file.spv"] = getEmptySpirvFile();
|
||||
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-file",
|
||||
"some_file.spv",
|
||||
"-out_format",
|
||||
"SomeDummyUnknownFormat"};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto parsingResult = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, parsingResult);
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto verificationResult = mockOfflineLinker.verifyLinkerCommand();
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, verificationResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error: Invalid output type!\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenValidCommandWhenVerificationIsPerformedThenSuccessIsReturned) {
|
||||
mockArgHelperFilesMap["some_file1.spv"] = getEmptySpirvFile();
|
||||
mockArgHelperFilesMap["some_file2.spv"] = getEmptySpirvFile();
|
||||
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-file",
|
||||
"some_file1.spv",
|
||||
"-file",
|
||||
"some_file2.spv"};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
const auto parsingResult = mockOfflineLinker.parseCommand(argv.size(), argv);
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, parsingResult);
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto verificationResult = mockOfflineLinker.verifyLinkerCommand();
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::SUCCESS, verificationResult);
|
||||
EXPECT_TRUE(output.empty());
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenEmptyFileWhenLoadingInputFilesThenErrorIsReturned) {
|
||||
const std::string filename{"some_file.spv"};
|
||||
|
||||
// Empty file is treated as an error.
|
||||
mockArgHelperFilesMap[filename] = "";
|
||||
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-file",
|
||||
filename};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto readingResult = mockOfflineLinker.initialize(argv.size(), argv);
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::INVALID_FILE, readingResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error: Cannot read input file: some_file.spv\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenValidFileWithUnknownFormatWhenLoadingInputFilesThenErrorIsReturned) {
|
||||
const std::string filename{"some_file.unknown"};
|
||||
|
||||
// Spir-V or LLVM-BC magic constants are required. This should be treated as error.
|
||||
mockArgHelperFilesMap[filename] = "Some unknown format!";
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.inputFilenames.push_back(filename);
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto readingResult = mockOfflineLinker.loadInputFilesContent();
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::INVALID_PROGRAM, readingResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error: Unsupported format of input file: some_file.unknown\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenReadingErrorWhenLoadingInputFilesThenErrorIsReturned) {
|
||||
const std::string filename{"some_file1.spv"};
|
||||
mockArgHelperFilesMap[filename] = getEmptySpirvFile();
|
||||
|
||||
mockArgHelper.shouldReturnReadingError = true;
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.inputFilenames.push_back(filename);
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto readingResult = mockOfflineLinker.loadInputFilesContent();
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::INVALID_FILE, readingResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error: Cannot read input file: some_file1.spv\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenValidFilesWithValidFormatsWhenLoadingInputFilesThenFilesAreLoadedAndSuccessIsReturned) {
|
||||
const std::string firstFilename{"some_file1.spv"};
|
||||
const std::string secondFilename{"some_file2.llvmbc"};
|
||||
|
||||
mockArgHelperFilesMap[firstFilename] = getEmptySpirvFile();
|
||||
mockArgHelperFilesMap[secondFilename] = getEmptyLlvmBcFile();
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.inputFilenames.push_back(firstFilename);
|
||||
mockOfflineLinker.inputFilenames.push_back(secondFilename);
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto readingResult = mockOfflineLinker.loadInputFilesContent();
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, readingResult);
|
||||
EXPECT_TRUE(output.empty());
|
||||
|
||||
const auto &firstExpectedContent = mockArgHelperFilesMap[firstFilename];
|
||||
const auto &firstActualContent = mockOfflineLinker.inputFilesContent[0];
|
||||
|
||||
ASSERT_EQ(firstExpectedContent.size(), firstActualContent.size);
|
||||
const auto isFirstPairEqual = std::equal(firstExpectedContent.begin(), firstExpectedContent.end(), firstActualContent.bytes.get());
|
||||
EXPECT_TRUE(isFirstPairEqual);
|
||||
|
||||
const auto &secondExpectedContent = mockArgHelperFilesMap[secondFilename];
|
||||
const auto &secondActualContent = mockOfflineLinker.inputFilesContent[1];
|
||||
|
||||
ASSERT_EQ(secondExpectedContent.size(), secondActualContent.size);
|
||||
const auto isSecondPairEqual = std::equal(secondExpectedContent.begin(), secondExpectedContent.end(), secondActualContent.bytes.get());
|
||||
EXPECT_TRUE(isSecondPairEqual);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenValidFilesWhenInitializationIsSuccessfulThenLinkModeOfOperationIsSet) {
|
||||
const std::string firstFilename{"some_file1.spv"};
|
||||
const std::string secondFilename{"some_file2.llvmbc"};
|
||||
|
||||
mockArgHelperFilesMap[firstFilename] = getEmptySpirvFile();
|
||||
mockArgHelperFilesMap[secondFilename] = getEmptyLlvmBcFile();
|
||||
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-file",
|
||||
firstFilename,
|
||||
"-file",
|
||||
secondFilename};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto readingResult = mockOfflineLinker.initialize(argv.size(), argv);
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::SUCCESS, readingResult);
|
||||
EXPECT_TRUE(output.empty());
|
||||
|
||||
EXPECT_EQ(OperationMode::LINK_FILES, mockOfflineLinker.operationMode);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenSPIRVandLLVMBCFilesWhenElfOutputIsRequestedThenElfWithSPIRVAndLLVMSectionsIsCreated) {
|
||||
auto spirvFileContent = createFileContent(getEmptySpirvFile(), IGC::CodeType::spirV);
|
||||
auto llvmbcFileContent = createFileContent(getEmptyLlvmBcFile(), IGC::CodeType::llvmBc);
|
||||
|
||||
mockArgHelper.interceptOutput = true;
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.inputFilesContent.emplace_back(std::move(spirvFileContent.bytes), spirvFileContent.size, spirvFileContent.codeType);
|
||||
mockOfflineLinker.inputFilesContent.emplace_back(std::move(llvmbcFileContent.bytes), llvmbcFileContent.size, llvmbcFileContent.codeType);
|
||||
mockOfflineLinker.outputFormat = IGC::CodeType::elf;
|
||||
mockOfflineLinker.operationMode = OperationMode::LINK_FILES;
|
||||
|
||||
const auto linkingResult{mockOfflineLinker.execute()};
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, linkingResult);
|
||||
|
||||
ASSERT_EQ(1u, mockArgHelper.interceptedFiles.count("linker_output"));
|
||||
const auto &rawOutput{mockArgHelper.interceptedFiles.at("linker_output")};
|
||||
const auto encodedElf{ArrayRef<const uint8_t>::fromAny(rawOutput.data(), rawOutput.size())};
|
||||
|
||||
std::string errorReason{};
|
||||
std::string warning{};
|
||||
const auto elf{Elf::decodeElf(encodedElf, errorReason, warning)};
|
||||
|
||||
ASSERT_TRUE(errorReason.empty());
|
||||
EXPECT_TRUE(warning.empty());
|
||||
|
||||
// SPIR-V bitcode section.
|
||||
EXPECT_EQ(Elf::SHT_OPENCL_SPIRV, elf.sectionHeaders[1].header->type);
|
||||
|
||||
const auto &expectedFirstSection = mockOfflineLinker.inputFilesContent[0];
|
||||
const auto &actualFirstSection = elf.sectionHeaders[1];
|
||||
ASSERT_EQ(expectedFirstSection.size, actualFirstSection.header->size);
|
||||
|
||||
const auto isFirstSectionContentEqual = std::memcmp(actualFirstSection.data.begin(), expectedFirstSection.bytes.get(), expectedFirstSection.size) == 0;
|
||||
EXPECT_TRUE(isFirstSectionContentEqual);
|
||||
|
||||
// LLVM bitcode section.
|
||||
EXPECT_EQ(Elf::SHT_OPENCL_LLVM_BINARY, elf.sectionHeaders[2].header->type);
|
||||
|
||||
const auto &expectedSecondSection = mockOfflineLinker.inputFilesContent[1];
|
||||
const auto &actualSecondSection = elf.sectionHeaders[2];
|
||||
ASSERT_EQ(expectedSecondSection.size, actualSecondSection.header->size);
|
||||
|
||||
const auto isSecondSectionContentEqual = std::memcmp(actualSecondSection.data.begin(), expectedSecondSection.bytes.get(), expectedSecondSection.size) == 0;
|
||||
EXPECT_TRUE(isSecondSectionContentEqual);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenValidInputFileContentsWhenLlvmBcOutputIsRequestedThenSuccessIsReturnedAndFileIsWritten) {
|
||||
auto spirvFileContent = createFileContent(getEmptySpirvFile(), IGC::CodeType::spirV);
|
||||
auto llvmbcFileContent = createFileContent(getEmptyLlvmBcFile(), IGC::CodeType::llvmBc);
|
||||
|
||||
mockArgHelper.interceptOutput = true;
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.inputFilesContent.emplace_back(std::move(spirvFileContent.bytes), spirvFileContent.size, spirvFileContent.codeType);
|
||||
mockOfflineLinker.inputFilesContent.emplace_back(std::move(llvmbcFileContent.bytes), llvmbcFileContent.size, llvmbcFileContent.codeType);
|
||||
mockOfflineLinker.outputFormat = IGC::CodeType::llvmBc;
|
||||
mockOfflineLinker.operationMode = OperationMode::LINK_FILES;
|
||||
|
||||
const auto igcInitializationResult{mockOfflineLinker.prepareIgc()};
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, igcInitializationResult);
|
||||
|
||||
const auto linkingResult{mockOfflineLinker.execute()};
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, linkingResult);
|
||||
|
||||
ASSERT_EQ(1u, mockArgHelper.interceptedFiles.count("linker_output"));
|
||||
const auto &actualOutput{mockArgHelper.interceptedFiles.at("linker_output")};
|
||||
const auto &expectedOutput{binaryToReturn};
|
||||
|
||||
ASSERT_EQ(sizeof(expectedOutput), actualOutput.size());
|
||||
|
||||
const auto isActualOutputSameAsExpected{std::equal(std::begin(expectedOutput), std::end(expectedOutput), std::begin(actualOutput))};
|
||||
EXPECT_TRUE(isActualOutputSameAsExpected);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenValidInputFileContentsAndFailingIGCWhenLlvmBcOutputIsRequestedThenErrorIsReturned) {
|
||||
MockCompilerDebugVars igcDebugVars{gEnvironment->igcDebugVars};
|
||||
igcDebugVars.forceBuildFailure = true;
|
||||
setIgcDebugVars(igcDebugVars);
|
||||
|
||||
auto spirvFileContent = createFileContent(getEmptySpirvFile(), IGC::CodeType::spirV);
|
||||
auto llvmbcFileContent = createFileContent(getEmptyLlvmBcFile(), IGC::CodeType::llvmBc);
|
||||
|
||||
mockArgHelper.interceptOutput = true;
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.inputFilesContent.emplace_back(std::move(spirvFileContent.bytes), spirvFileContent.size, spirvFileContent.codeType);
|
||||
mockOfflineLinker.inputFilesContent.emplace_back(std::move(llvmbcFileContent.bytes), llvmbcFileContent.size, llvmbcFileContent.codeType);
|
||||
mockOfflineLinker.outputFormat = IGC::CodeType::llvmBc;
|
||||
mockOfflineLinker.operationMode = OperationMode::LINK_FILES;
|
||||
|
||||
const auto igcInitializationResult{mockOfflineLinker.prepareIgc()};
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, igcInitializationResult);
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto linkingResult{mockOfflineLinker.execute()};
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::BUILD_PROGRAM_FAILURE, linkingResult);
|
||||
EXPECT_EQ(0u, mockArgHelper.interceptedFiles.count("linker_output"));
|
||||
|
||||
const std::string expectedErrorMessage{"Error: Translation has failed! IGC returned empty output.\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenValidInputFileContentsAndInvalidTranslationOutputWhenLlvmBcOutputIsRequestedThenErrorIsReturned) {
|
||||
MockCompilerDebugVars igcDebugVars{gEnvironment->igcDebugVars};
|
||||
igcDebugVars.shouldReturnInvalidTranslationOutput = true;
|
||||
setIgcDebugVars(igcDebugVars);
|
||||
|
||||
auto spirvFileContent = createFileContent(getEmptySpirvFile(), IGC::CodeType::spirV);
|
||||
auto llvmbcFileContent = createFileContent(getEmptyLlvmBcFile(), IGC::CodeType::llvmBc);
|
||||
|
||||
mockArgHelper.interceptOutput = true;
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.inputFilesContent.emplace_back(std::move(spirvFileContent.bytes), spirvFileContent.size, spirvFileContent.codeType);
|
||||
mockOfflineLinker.inputFilesContent.emplace_back(std::move(llvmbcFileContent.bytes), llvmbcFileContent.size, llvmbcFileContent.codeType);
|
||||
mockOfflineLinker.outputFormat = IGC::CodeType::llvmBc;
|
||||
mockOfflineLinker.operationMode = OperationMode::LINK_FILES;
|
||||
|
||||
const auto igcInitializationResult{mockOfflineLinker.prepareIgc()};
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, igcInitializationResult);
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto linkingResult{mockOfflineLinker.execute()};
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::OUT_OF_HOST_MEMORY, linkingResult);
|
||||
EXPECT_EQ(0u, mockArgHelper.interceptedFiles.count("linker_output"));
|
||||
|
||||
const std::string expectedErrorMessage{"Error: Translation has failed! IGC output is nullptr!\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenUninitializedLinkerWhenExecuteIsInvokedThenErrorIsIssued) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto executionResult{mockOfflineLinker.execute()};
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, executionResult);
|
||||
ASSERT_FALSE(output.empty());
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenHelpRequestWhenExecuteIsInvokedThenHelpIsPrinted) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.operationMode = OperationMode::SHOW_HELP;
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto executionResult{mockOfflineLinker.execute()};
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, executionResult);
|
||||
ASSERT_FALSE(output.empty());
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenInvalidOperationModeWhenExecuteIsInvokedThenErrorIsIssued) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.operationMode = static_cast<OperationMode>(7);
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto executionResult{mockOfflineLinker.execute()};
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
ASSERT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, executionResult);
|
||||
ASSERT_FALSE(output.empty());
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenUninitializedHwInfoWhenInitIsCalledThenHwInfoIsInitialized) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
ASSERT_EQ(IGFX_UNKNOWN, mockOfflineLinker.hwInfo.platform.eProductFamily);
|
||||
|
||||
const auto hwInfoInitializationResult{mockOfflineLinker.initHardwareInfo()};
|
||||
ASSERT_EQ(OclocErrorCode::SUCCESS, hwInfoInitializationResult);
|
||||
EXPECT_NE(IGFX_UNKNOWN, mockOfflineLinker.hwInfo.platform.eProductFamily);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenEmptyHwInfoTableWhenInitializationIsPerformedThenItFailsOnHwInit) {
|
||||
const std::string firstFilename{"some_file1.spv"};
|
||||
const std::string secondFilename{"some_file2.llvmbc"};
|
||||
|
||||
mockArgHelperFilesMap[firstFilename] = getEmptySpirvFile();
|
||||
mockArgHelperFilesMap[secondFilename] = getEmptyLlvmBcFile();
|
||||
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-file",
|
||||
firstFilename,
|
||||
"-file",
|
||||
secondFilename};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.shouldReturnEmptyHardwareInfoTable = true;
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto readingResult = mockOfflineLinker.initialize(argv.size(), argv);
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::INVALID_DEVICE, readingResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error! Cannot retrieve any valid hardware information!\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenMissingIgcLibraryWhenInitializationIsPerformedThenItFailsOnIgcPreparation) {
|
||||
const std::string firstFilename{"some_file1.spv"};
|
||||
const std::string secondFilename{"some_file2.llvmbc"};
|
||||
|
||||
mockArgHelperFilesMap[firstFilename] = getEmptySpirvFile();
|
||||
mockArgHelperFilesMap[secondFilename] = getEmptyLlvmBcFile();
|
||||
|
||||
const std::vector<std::string> argv = {
|
||||
"ocloc.exe",
|
||||
"link",
|
||||
"-file",
|
||||
firstFilename,
|
||||
"-file",
|
||||
secondFilename};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.shouldFailLoadingOfIgcLib = true;
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto readingResult = mockOfflineLinker.initialize(argv.size(), argv);
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::OUT_OF_HOST_MEMORY, readingResult);
|
||||
|
||||
std::stringstream expectedErrorMessage;
|
||||
expectedErrorMessage << "Error! Loading of IGC library has failed! Filename: " << Os::igcDllName << "\n";
|
||||
|
||||
EXPECT_EQ(expectedErrorMessage.str(), output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenOfflineLinkerWhenStoringValidBuildLogThenItIsSaved) {
|
||||
const std::string someValidLog{"Warning: This is a build log!"};
|
||||
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.tryToStoreBuildLog(someValidLog.data(), someValidLog.size());
|
||||
|
||||
EXPECT_EQ(someValidLog, mockOfflineLinker.getBuildLog());
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenOfflineLinkerWhenStoringInvalidBuildLogThenItIsIgnored) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.tryToStoreBuildLog(nullptr, 0);
|
||||
|
||||
const auto buildLog{mockOfflineLinker.getBuildLog()};
|
||||
EXPECT_TRUE(buildLog.empty());
|
||||
|
||||
// Invalid size has been passed.
|
||||
const char *log{"Info: This is a log!"};
|
||||
mockOfflineLinker.tryToStoreBuildLog(log, 0);
|
||||
|
||||
const auto buildLog2{mockOfflineLinker.getBuildLog()};
|
||||
EXPECT_TRUE(buildLog2.empty());
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenFailingLoadingOfIgcSymbolsWhenPreparingIgcThenFailureIsReported) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.shouldFailLoadingOfIgcCreateMainFunction = true;
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto igcPreparationResult{mockOfflineLinker.prepareIgc()};
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::OUT_OF_HOST_MEMORY, igcPreparationResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error! Cannot load required functions from IGC library.\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenFailingCreationOfIgcMainWhenPreparingIgcThenFailureIsReported) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.shouldFailCreationOfIgcMain = true;
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto igcPreparationResult{mockOfflineLinker.prepareIgc()};
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::OUT_OF_HOST_MEMORY, igcPreparationResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error! Cannot create IGC main component!\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenFailingCreationOfIgcDeviceContextWhenPreparingIgcThenFailureIsReported) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.shouldFailCreationOfIgcDeviceContext = true;
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto igcPreparationResult{mockOfflineLinker.prepareIgc()};
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::OUT_OF_HOST_MEMORY, igcPreparationResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error! Cannot create IGC device context!\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenInvalidIgcPlatformHandleWhenPreparingIgcThenFailureIsReported) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.shouldReturnInvalidIgcPlatformHandle = true;
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto igcPreparationResult{mockOfflineLinker.prepareIgc()};
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::OUT_OF_HOST_MEMORY, igcPreparationResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error! IGC device context has not been properly created!\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
TEST_F(OfflineLinkerTest, GivenInvalidIgcGTSystemInfoHandleWhenPreparingIgcThenFailureIsReported) {
|
||||
MockOfflineLinker mockOfflineLinker{&mockArgHelper};
|
||||
mockOfflineLinker.shouldReturnInvalidGTSystemInfoHandle = true;
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
const auto igcPreparationResult{mockOfflineLinker.prepareIgc()};
|
||||
const auto output{::testing::internal::GetCapturedStdout()};
|
||||
|
||||
EXPECT_EQ(OclocErrorCode::OUT_OF_HOST_MEMORY, igcPreparationResult);
|
||||
|
||||
const std::string expectedErrorMessage{"Error! IGC device context has not been properly created!\n"};
|
||||
EXPECT_EQ(expectedErrorMessage, output);
|
||||
}
|
||||
|
||||
} // namespace NEO
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "mock/mock_argument_helper.h"
|
||||
#include "mock/mock_offline_linker.h"
|
||||
|
||||
namespace NEO {
|
||||
|
||||
class OfflineLinkerTest : public ::testing::Test {
|
||||
public:
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
|
||||
std::string getEmptySpirvFile() const;
|
||||
std::string getEmptyLlvmBcFile() const;
|
||||
MockOfflineLinker::InputFileContent createFileContent(const std::string &content, IGC::CodeType::CodeType_t codeType) const;
|
||||
|
||||
protected:
|
||||
MockOclocArgHelper::FilesMap mockArgHelperFilesMap{};
|
||||
MockOclocArgHelper mockArgHelper{mockArgHelperFilesMap};
|
||||
char binaryToReturn[8]{7, 7, 7, 7, 0, 1, 2, 3};
|
||||
};
|
||||
|
||||
} // namespace NEO
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2020-2021 Intel Corporation
|
||||
# Copyright (C) 2020-2022 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
@ -60,6 +60,7 @@ set(CLOC_LIB_SRCS_LIB
|
||||
${OCLOC_DIRECTORY}/source/ocloc_api.h
|
||||
${OCLOC_DIRECTORY}/source/ocloc_arg_helper.cpp
|
||||
${OCLOC_DIRECTORY}/source/ocloc_arg_helper.h
|
||||
${OCLOC_DIRECTORY}/source/ocloc_error_code.h
|
||||
${OCLOC_DIRECTORY}/source/ocloc_fatbinary.cpp
|
||||
${OCLOC_DIRECTORY}/source/ocloc_fatbinary.h
|
||||
${OCLOC_DIRECTORY}/source/ocloc_validator.cpp
|
||||
@ -68,6 +69,8 @@ set(CLOC_LIB_SRCS_LIB
|
||||
${OCLOC_DIRECTORY}/source/offline_compiler.h
|
||||
${OCLOC_DIRECTORY}/source/offline_compiler_helper.cpp
|
||||
${OCLOC_DIRECTORY}/source/offline_compiler_options.cpp
|
||||
${OCLOC_DIRECTORY}/source/offline_linker.cpp
|
||||
${OCLOC_DIRECTORY}/source/offline_linker.h
|
||||
${OCLOC_DIRECTORY}/source/queries.h
|
||||
${OCLOC_DIRECTORY}/source/utilities/get_git_version_info.h
|
||||
${OCLOC_DIRECTORY}/source/utilities/get_git_version_info.cpp
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2021 Intel Corporation
|
||||
* Copyright (C) 2019-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include "shared/offline_compiler/source/multi_command.h"
|
||||
|
||||
#include "shared/offline_compiler/source/ocloc_error_code.h"
|
||||
#include "shared/offline_compiler/source/ocloc_fatbinary.h"
|
||||
#include "shared/source/utilities/const_stringref.h"
|
||||
|
||||
@ -14,13 +15,13 @@
|
||||
|
||||
namespace NEO {
|
||||
int MultiCommand::singleBuild(const std::vector<std::string> &args) {
|
||||
int retVal = OfflineCompiler::ErrorCode::SUCCESS;
|
||||
int retVal = OclocErrorCode::SUCCESS;
|
||||
|
||||
if (requestedFatBinary(args, argHelper)) {
|
||||
retVal = buildFatBinary(args, argHelper);
|
||||
} else {
|
||||
std::unique_ptr<OfflineCompiler> pCompiler{OfflineCompiler::create(args.size(), args, true, retVal, argHelper)};
|
||||
if (retVal == OfflineCompiler::ErrorCode::SUCCESS) {
|
||||
if (retVal == OclocErrorCode::SUCCESS) {
|
||||
retVal = buildWithSafetyGuard(pCompiler.get());
|
||||
|
||||
std::string &buildLog = pCompiler->getBuildLog();
|
||||
@ -30,14 +31,14 @@ int MultiCommand::singleBuild(const std::vector<std::string> &args) {
|
||||
}
|
||||
outFileName += ".bin";
|
||||
}
|
||||
if (retVal == OfflineCompiler::ErrorCode::SUCCESS) {
|
||||
if (retVal == OclocErrorCode::SUCCESS) {
|
||||
if (!quiet)
|
||||
argHelper->printf("Build succeeded.\n");
|
||||
} else {
|
||||
argHelper->printf("Build failed with error code: %d\n", retVal);
|
||||
}
|
||||
|
||||
if (retVal == OfflineCompiler::ErrorCode::SUCCESS) {
|
||||
if (retVal == OclocErrorCode::SUCCESS) {
|
||||
outputFile << getCurrentDirectoryOwn(outDirForBuilds) + outFileName;
|
||||
} else {
|
||||
outputFile << "Unsuccesful build";
|
||||
@ -48,7 +49,7 @@ int MultiCommand::singleBuild(const std::vector<std::string> &args) {
|
||||
}
|
||||
|
||||
MultiCommand *MultiCommand::create(const std::vector<std::string> &args, int &retVal, OclocArgHelper *helper) {
|
||||
retVal = OfflineCompiler::ErrorCode::SUCCESS;
|
||||
retVal = OclocErrorCode::SUCCESS;
|
||||
auto pMultiCommand = new MultiCommand();
|
||||
|
||||
if (pMultiCommand) {
|
||||
@ -56,7 +57,7 @@ MultiCommand *MultiCommand::create(const std::vector<std::string> &args, int &re
|
||||
retVal = pMultiCommand->initialize(args);
|
||||
}
|
||||
|
||||
if (retVal != OfflineCompiler::ErrorCode::SUCCESS) {
|
||||
if (retVal != OclocErrorCode::SUCCESS) {
|
||||
delete pMultiCommand;
|
||||
pMultiCommand = nullptr;
|
||||
}
|
||||
@ -107,7 +108,7 @@ int MultiCommand::initialize(const std::vector<std::string> &args) {
|
||||
} else {
|
||||
argHelper->printf("Invalid option (arg %zu): %s\n", argIndex, currArg.c_str());
|
||||
printHelp();
|
||||
return OfflineCompiler::ErrorCode::INVALID_COMMAND_LINE;
|
||||
return OclocErrorCode::INVALID_COMMAND_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,11 +117,11 @@ int MultiCommand::initialize(const std::vector<std::string> &args) {
|
||||
argHelper->readFileToVectorOfStrings(pathToCommandFile, lines);
|
||||
if (lines.empty()) {
|
||||
argHelper->printf("Command file was empty.\n");
|
||||
return OfflineCompiler::ErrorCode::INVALID_FILE;
|
||||
return OclocErrorCode::INVALID_FILE;
|
||||
}
|
||||
} else {
|
||||
argHelper->printf("Could not find/open file with builds argument.s\n");
|
||||
return OfflineCompiler::ErrorCode::INVALID_FILE;
|
||||
return OclocErrorCode::INVALID_FILE;
|
||||
}
|
||||
|
||||
runBuilds(args[0]);
|
||||
@ -136,7 +137,7 @@ void MultiCommand::runBuilds(const std::string &argZero) {
|
||||
std::vector<std::string> args = {argZero};
|
||||
|
||||
int retVal = splitLineInSeparateArgs(args, lines[i], i);
|
||||
if (retVal != OfflineCompiler::ErrorCode::SUCCESS) {
|
||||
if (retVal != OclocErrorCode::SUCCESS) {
|
||||
retValues.push_back(retVal);
|
||||
continue;
|
||||
}
|
||||
@ -188,22 +189,22 @@ int MultiCommand::splitLineInSeparateArgs(std::vector<std::string> &qargs, const
|
||||
}
|
||||
if (end == std::string::npos) {
|
||||
argHelper->printf("One of the quotes is open in build number %zu\n", numberOfBuild + 1);
|
||||
return OfflineCompiler::ErrorCode::INVALID_FILE;
|
||||
return OclocErrorCode::INVALID_FILE;
|
||||
}
|
||||
argLen = end - start;
|
||||
i = end;
|
||||
qargs.push_back(commandsLine.substr(start, argLen));
|
||||
}
|
||||
return OfflineCompiler::ErrorCode::SUCCESS;
|
||||
return OclocErrorCode::SUCCESS;
|
||||
}
|
||||
|
||||
int MultiCommand::showResults() {
|
||||
int retValue = OfflineCompiler::ErrorCode::SUCCESS;
|
||||
int retValue = OclocErrorCode::SUCCESS;
|
||||
int indexRetVal = 0;
|
||||
for (int retVal : retValues) {
|
||||
retValue |= retVal;
|
||||
if (!quiet) {
|
||||
if (retVal != OfflineCompiler::ErrorCode::SUCCESS) {
|
||||
if (retVal != OclocErrorCode::SUCCESS) {
|
||||
argHelper->printf("Build command %d: failed. Error code: %d\n", indexRetVal, retVal);
|
||||
} else {
|
||||
argHelper->printf("Build command %d: successful\n", indexRetVal);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Intel Corporation
|
||||
* Copyright (C) 2020-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@ -10,9 +10,11 @@
|
||||
#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/ocloc_error_code.h"
|
||||
#include "shared/offline_compiler/source/ocloc_fatbinary.h"
|
||||
#include "shared/offline_compiler/source/ocloc_validator.h"
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
#include "shared/offline_compiler/source/offline_linker.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@ -36,6 +38,7 @@ Use 'ocloc <command> --help' to get help about specific command.
|
||||
|
||||
Commands:
|
||||
compile Compiles input to Intel Compute GPU device binary.
|
||||
link Links several IR files.
|
||||
disasm Disassembles Intel Compute GPU device binary.
|
||||
asm Assembles Intel Compute GPU device binary.
|
||||
multi Compiles multiple files using a config file.
|
||||
@ -48,6 +51,9 @@ Examples:
|
||||
Compile file to Intel Compute GPU device binary (out = source_file_Gen9core.bin)
|
||||
ocloc -file source_file.cl -device skl
|
||||
|
||||
Link two SPIR-V files.
|
||||
ocloc link -file sample1.spv -file sample2.spv -out_format LLVM_BC -out samples_merged.llvm_bc
|
||||
|
||||
Disassemble Intel Compute GPU device binary
|
||||
ocloc disasm -file source_file_Gen9core.bin
|
||||
|
||||
@ -108,7 +114,7 @@ int oclocInvoke(unsigned int numArgs, const char *argv[],
|
||||
try {
|
||||
if (numArgs == 1 || (numArgs > 1 && (ConstStringRef("-h") == allArgs[1] || ConstStringRef("--help") == allArgs[1]))) {
|
||||
helper->printf("%s", help);
|
||||
return OfflineCompiler::ErrorCode::SUCCESS;
|
||||
return OclocErrorCode::SUCCESS;
|
||||
} else if (numArgs > 1 && ConstStringRef("disasm") == allArgs[1]) {
|
||||
BinaryDecoder disasm(helper.get());
|
||||
int retVal = disasm.validateInput(allArgs);
|
||||
@ -138,7 +144,7 @@ int oclocInvoke(unsigned int numArgs, const char *argv[],
|
||||
return retVal;
|
||||
}
|
||||
} else if (numArgs > 1 && ConstStringRef("multi") == allArgs[1]) {
|
||||
int retValue = OfflineCompiler::ErrorCode::SUCCESS;
|
||||
int retValue = OclocErrorCode::SUCCESS;
|
||||
std::unique_ptr<MultiCommand> pMulti{(MultiCommand::create(allArgs, retValue, helper.get()))};
|
||||
return retValue;
|
||||
} else if (requestedFatBinary(allArgs, helper.get())) {
|
||||
@ -147,11 +153,26 @@ int oclocInvoke(unsigned int numArgs, const char *argv[],
|
||||
return NEO::Ocloc::validate(allArgs, helper.get());
|
||||
} else if (numArgs > 1 && ConstStringRef("query") == allArgs[1]) {
|
||||
return OfflineCompiler::query(numArgs, allArgs, helper.get());
|
||||
} else if (numArgs > 1 && ConstStringRef("link") == allArgs[1]) {
|
||||
int createResult{OclocErrorCode::SUCCESS};
|
||||
const auto linker{OfflineLinker::create(numArgs, allArgs, createResult, helper.get())};
|
||||
const auto linkingResult{linkWithSafetyGuard(linker.get())};
|
||||
|
||||
const auto buildLog = linker->getBuildLog();
|
||||
if (!buildLog.empty()) {
|
||||
helper->printf("%s\n", buildLog.c_str());
|
||||
}
|
||||
|
||||
if (createResult == OclocErrorCode::SUCCESS && linkingResult == OclocErrorCode::SUCCESS) {
|
||||
helper->printf("Linker execution has succeeded!\n");
|
||||
}
|
||||
|
||||
return createResult | linkingResult;
|
||||
} else {
|
||||
int retVal = OfflineCompiler::ErrorCode::SUCCESS;
|
||||
int retVal = OclocErrorCode::SUCCESS;
|
||||
|
||||
std::unique_ptr<OfflineCompiler> pCompiler{OfflineCompiler::create(numArgs, allArgs, true, retVal, helper.get())};
|
||||
if (retVal == OfflineCompiler::ErrorCode::SUCCESS) {
|
||||
if (retVal == OclocErrorCode::SUCCESS) {
|
||||
retVal = buildWithSafetyGuard(pCompiler.get());
|
||||
|
||||
std::string buildLog = pCompiler->getBuildLog();
|
||||
@ -159,7 +180,7 @@ int oclocInvoke(unsigned int numArgs, const char *argv[],
|
||||
helper->printf("%s\n", buildLog.c_str());
|
||||
}
|
||||
|
||||
if (retVal == OfflineCompiler::ErrorCode::SUCCESS) {
|
||||
if (retVal == OclocErrorCode::SUCCESS) {
|
||||
if (!pCompiler->isQuiet())
|
||||
helper->printf("Build succeeded.\n");
|
||||
} else {
|
||||
@ -167,7 +188,7 @@ int oclocInvoke(unsigned int numArgs, const char *argv[],
|
||||
}
|
||||
}
|
||||
|
||||
if (retVal != OfflineCompiler::ErrorCode::SUCCESS) {
|
||||
if (retVal != OclocErrorCode::SUCCESS) {
|
||||
printOclocOptionsReadFromFile(pCompiler.get());
|
||||
printOclocCmdLine(numArgs, argv, helper);
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ class OclocArgHelper {
|
||||
bool isFatbinary() {
|
||||
return fatBinary;
|
||||
}
|
||||
void saveOutput(const std::string &filename, const void *pData, const size_t &dataSize);
|
||||
MOCKABLE_VIRTUAL void saveOutput(const std::string &filename, const void *pData, const size_t &dataSize);
|
||||
void saveOutput(const std::string &filename, const std::ostream &stream);
|
||||
|
||||
MessagePrinter &getPrinterRef() { return messagePrinter; }
|
||||
|
22
shared/offline_compiler/source/ocloc_error_code.h
Normal file
22
shared/offline_compiler/source/ocloc_error_code.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace NEO::OclocErrorCode {
|
||||
|
||||
enum {
|
||||
SUCCESS = 0,
|
||||
OUT_OF_HOST_MEMORY = -6,
|
||||
BUILD_PROGRAM_FAILURE = -11,
|
||||
INVALID_DEVICE = -33,
|
||||
INVALID_PROGRAM = -44,
|
||||
INVALID_COMMAND_LINE = -5150,
|
||||
INVALID_FILE = -5151,
|
||||
};
|
||||
|
||||
} // namespace NEO::OclocErrorCode
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Intel Corporation
|
||||
* Copyright (C) 2020-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include "shared/offline_compiler/source/ocloc_fatbinary.h"
|
||||
|
||||
#include "shared/offline_compiler/source/ocloc_error_code.h"
|
||||
#include "shared/offline_compiler/source/utilities/safety_caller.h"
|
||||
#include "shared/source/helpers/file_io.h"
|
||||
#include "shared/source/helpers/hw_info.h"
|
||||
@ -378,7 +379,7 @@ int buildFatBinary(const std::vector<std::string> &args, OclocArgHelper *argHelp
|
||||
argsCopy[deviceArgIndex] = targetPlatform.str();
|
||||
|
||||
std::unique_ptr<OfflineCompiler> pCompiler{OfflineCompiler::create(argsCopy.size(), argsCopy, false, retVal, argHelper)};
|
||||
if (OfflineCompiler::ErrorCode::SUCCESS != retVal) {
|
||||
if (OclocErrorCode::SUCCESS != retVal) {
|
||||
argHelper->printf("Error! Couldn't create OfflineCompiler. Exiting.\n");
|
||||
return retVal;
|
||||
}
|
||||
@ -402,7 +403,7 @@ int buildFatBinary(const std::vector<std::string> &args, OclocArgHelper *argHelp
|
||||
argHelper->setFatbinary(true);
|
||||
argHelper->setDeviceInfoForFatbinaryTarget(targetConfig);
|
||||
std::unique_ptr<OfflineCompiler> pCompiler{OfflineCompiler::create(argsCopy.size(), argsCopy, false, retVal, argHelper)};
|
||||
if (OfflineCompiler::ErrorCode::SUCCESS != retVal) {
|
||||
if (OclocErrorCode::SUCCESS != retVal) {
|
||||
argHelper->printf("Error! Couldn't create OfflineCompiler. Exiting.\n");
|
||||
return retVal;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "offline_compiler.h"
|
||||
|
||||
#include "shared/offline_compiler/source/ocloc_error_code.h"
|
||||
#include "shared/offline_compiler/source/queries.h"
|
||||
#include "shared/offline_compiler/source/utilities/get_git_version_info.h"
|
||||
#include "shared/source/compiler_interface/intermediate_representations.h"
|
||||
@ -50,6 +51,8 @@
|
||||
#define GetCurrentWorkingDirectory getcwd
|
||||
#endif
|
||||
|
||||
using namespace NEO::OclocErrorCode;
|
||||
|
||||
namespace NEO {
|
||||
|
||||
CIF::CIFMain *createMainNoSanitize(CIF::CreateCIFMainFunc_t createFunc);
|
||||
|
@ -33,16 +33,6 @@ std::string getDevicesTypes();
|
||||
|
||||
class OfflineCompiler {
|
||||
public:
|
||||
enum ErrorCode {
|
||||
SUCCESS = 0,
|
||||
OUT_OF_HOST_MEMORY = -6,
|
||||
BUILD_PROGRAM_FAILURE = -11,
|
||||
INVALID_DEVICE = -33,
|
||||
INVALID_PROGRAM = -44,
|
||||
INVALID_COMMAND_LINE = -5150,
|
||||
INVALID_FILE = -5151,
|
||||
};
|
||||
|
||||
static int query(size_t numArgs, const std::vector<std::string> &allArgs, OclocArgHelper *helper);
|
||||
|
||||
static OfflineCompiler *create(size_t numArgs, const std::vector<std::string> &allArgs, bool dumpFiles, int &retVal, OclocArgHelper *helper);
|
||||
|
409
shared/offline_compiler/source/offline_linker.cpp
Normal file
409
shared/offline_compiler/source/offline_linker.cpp
Normal file
@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "offline_linker.h"
|
||||
|
||||
#include "shared/offline_compiler/source/ocloc_arg_helper.h"
|
||||
#include "shared/offline_compiler/source/ocloc_error_code.h"
|
||||
#include "shared/source/compiler_interface/intermediate_representations.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/compiler_hw_info_config.h"
|
||||
#include "shared/source/helpers/string.h"
|
||||
#include "shared/source/os_interface/os_inc_base.h"
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
|
||||
#include "cif/common/cif_main.h"
|
||||
#include "ocl_igc_interface/platform_helper.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
namespace NEO {
|
||||
|
||||
CIF::CIFMain *createMainNoSanitize(CIF::CreateCIFMainFunc_t createFunc);
|
||||
|
||||
std::unique_ptr<OfflineLinker> OfflineLinker::create(size_t argsCount, const std::vector<std::string> &args, int &errorCode, OclocArgHelper *argHelper) {
|
||||
std::unique_ptr<OfflineLinker> linker{new OfflineLinker{argHelper}};
|
||||
errorCode = linker->initialize(argsCount, args);
|
||||
|
||||
return linker;
|
||||
}
|
||||
|
||||
OfflineLinker::OfflineLinker(OclocArgHelper *argHelper)
|
||||
: argHelper{argHelper}, operationMode{OperationMode::SKIP_EXECUTION}, outputFilename{"linker_output"}, outputFormat{IGC::CodeType::llvmBc} {}
|
||||
|
||||
OfflineLinker::~OfflineLinker() = default;
|
||||
|
||||
int OfflineLinker::initialize(size_t argsCount, const std::vector<std::string> &args) {
|
||||
const auto parsingResult{parseCommand(argsCount, args)};
|
||||
if (parsingResult != OclocErrorCode::SUCCESS) {
|
||||
return parsingResult;
|
||||
}
|
||||
|
||||
// If a user requested help, then stop here.
|
||||
if (operationMode == OperationMode::SHOW_HELP) {
|
||||
return OclocErrorCode::SUCCESS;
|
||||
}
|
||||
|
||||
const auto verificationResult{verifyLinkerCommand()};
|
||||
if (verificationResult != OclocErrorCode::SUCCESS) {
|
||||
return verificationResult;
|
||||
}
|
||||
|
||||
const auto loadingResult{loadInputFilesContent()};
|
||||
if (loadingResult != OclocErrorCode::SUCCESS) {
|
||||
return loadingResult;
|
||||
}
|
||||
|
||||
const auto hwInfoInitializationResult{initHardwareInfo()};
|
||||
if (hwInfoInitializationResult != OclocErrorCode::SUCCESS) {
|
||||
return hwInfoInitializationResult;
|
||||
}
|
||||
|
||||
const auto igcPreparationResult{prepareIgc()};
|
||||
if (igcPreparationResult != OclocErrorCode::SUCCESS) {
|
||||
return igcPreparationResult;
|
||||
}
|
||||
|
||||
operationMode = OperationMode::LINK_FILES;
|
||||
return OclocErrorCode::SUCCESS;
|
||||
}
|
||||
|
||||
int OfflineLinker::parseCommand(size_t argsCount, const std::vector<std::string> &args) {
|
||||
if (argsCount < 2u) {
|
||||
operationMode = OperationMode::SHOW_HELP;
|
||||
return OclocErrorCode::INVALID_COMMAND_LINE;
|
||||
}
|
||||
|
||||
for (size_t argIndex = 1u; argIndex < argsCount; ++argIndex) {
|
||||
const auto ¤tArg{args[argIndex]};
|
||||
const auto hasMoreArgs{argIndex + 1 < argsCount};
|
||||
|
||||
if (currentArg == "link") {
|
||||
continue;
|
||||
} else if ((currentArg == "-file") && hasMoreArgs) {
|
||||
inputFilenames.push_back(args[argIndex + 1]);
|
||||
++argIndex;
|
||||
} else if (currentArg == "-out" && hasMoreArgs) {
|
||||
outputFilename = args[argIndex + 1];
|
||||
++argIndex;
|
||||
} else if ((currentArg == "-out_format") && hasMoreArgs) {
|
||||
outputFormat = parseOutputFormat(args[argIndex + 1]);
|
||||
++argIndex;
|
||||
} else if ((currentArg == "-options") && hasMoreArgs) {
|
||||
options = args[argIndex + 1];
|
||||
++argIndex;
|
||||
} else if ((currentArg == "-internal_options") && hasMoreArgs) {
|
||||
internalOptions = args[argIndex + 1];
|
||||
++argIndex;
|
||||
} else if (currentArg == "--help") {
|
||||
operationMode = OperationMode::SHOW_HELP;
|
||||
return OclocErrorCode::SUCCESS;
|
||||
} else {
|
||||
argHelper->printf("Invalid option (arg %zd): %s\n", argIndex, currentArg.c_str());
|
||||
return OclocErrorCode::INVALID_COMMAND_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
return OclocErrorCode::SUCCESS;
|
||||
}
|
||||
|
||||
IGC::CodeType::CodeType_t OfflineLinker::parseOutputFormat(const std::string &outputFormatName) {
|
||||
constexpr static std::array supportedFormatNames = {
|
||||
std::pair{"ELF", IGC::CodeType::elf},
|
||||
std::pair{"LLVM_BC", IGC::CodeType::llvmBc}};
|
||||
|
||||
for (const auto &[name, format] : supportedFormatNames) {
|
||||
if (name == outputFormatName) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
return IGC::CodeType::invalid;
|
||||
}
|
||||
|
||||
int OfflineLinker::verifyLinkerCommand() {
|
||||
if (inputFilenames.empty()) {
|
||||
argHelper->printf("Error: Input name is missing! At least one input file is required!\n");
|
||||
return OclocErrorCode::INVALID_COMMAND_LINE;
|
||||
}
|
||||
|
||||
for (const auto &filename : inputFilenames) {
|
||||
if (filename.empty()) {
|
||||
argHelper->printf("Error: Empty filename cannot be used!\n");
|
||||
return OclocErrorCode::INVALID_COMMAND_LINE;
|
||||
}
|
||||
|
||||
if (!argHelper->fileExists(filename)) {
|
||||
argHelper->printf("Error: Input file %s missing.\n", filename.c_str());
|
||||
return OclocErrorCode::INVALID_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
if (outputFormat == IGC::CodeType::invalid) {
|
||||
argHelper->printf("Error: Invalid output type!\n");
|
||||
return OclocErrorCode::INVALID_COMMAND_LINE;
|
||||
}
|
||||
|
||||
return OclocErrorCode::SUCCESS;
|
||||
}
|
||||
|
||||
int OfflineLinker::loadInputFilesContent() {
|
||||
std::unique_ptr<char[]> bytes{};
|
||||
size_t size{};
|
||||
IGC::CodeType::CodeType_t codeType{};
|
||||
|
||||
inputFilesContent.reserve(inputFilenames.size());
|
||||
|
||||
for (const auto &filename : inputFilenames) {
|
||||
size = 0;
|
||||
bytes = argHelper->loadDataFromFile(filename, size);
|
||||
if (bytes == nullptr || size == 0) {
|
||||
argHelper->printf("Error: Cannot read input file: %s\n", filename.c_str());
|
||||
return OclocErrorCode::INVALID_FILE;
|
||||
}
|
||||
|
||||
codeType = detectCodeType(bytes.get(), size);
|
||||
if (codeType == IGC::CodeType::invalid) {
|
||||
argHelper->printf("Error: Unsupported format of input file: %s\n", filename.c_str());
|
||||
return OclocErrorCode::INVALID_PROGRAM;
|
||||
}
|
||||
|
||||
inputFilesContent.emplace_back(std::move(bytes), size, codeType);
|
||||
}
|
||||
|
||||
return OclocErrorCode::SUCCESS;
|
||||
}
|
||||
|
||||
IGC::CodeType::CodeType_t OfflineLinker::detectCodeType(char *bytes, size_t size) const {
|
||||
const auto bytesArray = ArrayRef<const uint8_t>::fromAny(bytes, size);
|
||||
if (isSpirVBitcode(bytesArray)) {
|
||||
return IGC::CodeType::spirV;
|
||||
}
|
||||
|
||||
if (isLlvmBitcode(bytesArray)) {
|
||||
return IGC::CodeType::llvmBc;
|
||||
}
|
||||
|
||||
return IGC::CodeType::invalid;
|
||||
}
|
||||
|
||||
int OfflineLinker::initHardwareInfo() {
|
||||
// In spite of linking input files to intermediate representation instead of native binaries,
|
||||
// we have to initialize hardware info. Without that, initialization of IGC fails.
|
||||
// Therefore, we select the first valid hardware info entry and use it.
|
||||
const auto hwInfoTable{getHardwareInfoTable()};
|
||||
for (auto productId = 0u; productId < hwInfoTable.size(); ++productId) {
|
||||
if (hwInfoTable[productId]) {
|
||||
hwInfo = *hwInfoTable[productId];
|
||||
|
||||
const auto hwInfoConfig = defaultHardwareInfoConfigTable[hwInfo.platform.eProductFamily];
|
||||
setHwInfoValuesFromConfig(hwInfoConfig, hwInfo);
|
||||
hardwareInfoSetup[hwInfo.platform.eProductFamily](&hwInfo, true, hwInfoConfig);
|
||||
|
||||
return OclocErrorCode::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
argHelper->printf("Error! Cannot retrieve any valid hardware information!\n");
|
||||
return OclocErrorCode::INVALID_DEVICE;
|
||||
}
|
||||
|
||||
ArrayRef<const HardwareInfo *> OfflineLinker::getHardwareInfoTable() const {
|
||||
return {hardwareInfoTable};
|
||||
}
|
||||
|
||||
int OfflineLinker::prepareIgc() {
|
||||
igcLib = loadIgcLibrary();
|
||||
if (!igcLib) {
|
||||
argHelper->printf("Error! Loading of IGC library has failed! Filename: %s\n", Os::igcDllName);
|
||||
return OclocErrorCode::OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
const auto igcCreateMainFunction = loadCreateIgcMainFunction();
|
||||
if (!igcCreateMainFunction) {
|
||||
argHelper->printf("Error! Cannot load required functions from IGC library.\n");
|
||||
return OclocErrorCode::OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
igcMain = createIgcMain(igcCreateMainFunction);
|
||||
if (!igcMain) {
|
||||
argHelper->printf("Error! Cannot create IGC main component!\n");
|
||||
return OclocErrorCode::OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
igcDeviceCtx = createIgcDeviceContext();
|
||||
if (!igcDeviceCtx) {
|
||||
argHelper->printf("Error! Cannot create IGC device context!\n");
|
||||
return OclocErrorCode::OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
const auto igcPlatform = getIgcPlatformHandle();
|
||||
const auto igcGtSystemInfo = getGTSystemInfoHandle();
|
||||
if (!igcPlatform || !igcGtSystemInfo) {
|
||||
argHelper->printf("Error! IGC device context has not been properly created!\n");
|
||||
return OclocErrorCode::OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
IGC::PlatformHelper::PopulateInterfaceWith(*igcPlatform.get(), hwInfo.platform);
|
||||
IGC::GtSysInfoHelper::PopulateInterfaceWith(*igcGtSystemInfo.get(), hwInfo.gtSystemInfo);
|
||||
|
||||
return OclocErrorCode::SUCCESS;
|
||||
}
|
||||
|
||||
std::unique_ptr<OsLibrary> OfflineLinker::loadIgcLibrary() const {
|
||||
return std::unique_ptr<OsLibrary>{OsLibrary::load(Os::igcDllName)};
|
||||
}
|
||||
|
||||
CIF::CreateCIFMainFunc_t OfflineLinker::loadCreateIgcMainFunction() const {
|
||||
return reinterpret_cast<CIF::CreateCIFMainFunc_t>(igcLib->getProcAddress(CIF::CreateCIFMainFuncName));
|
||||
}
|
||||
|
||||
CIF::RAII::UPtr_t<CIF::CIFMain> OfflineLinker::createIgcMain(CIF::CreateCIFMainFunc_t createMainFunction) const {
|
||||
return CIF::RAII::UPtr(createMainNoSanitize(createMainFunction));
|
||||
}
|
||||
|
||||
CIF::RAII::UPtr_t<IGC::IgcOclDeviceCtxTagOCL> OfflineLinker::createIgcDeviceContext() const {
|
||||
return igcMain->CreateInterface<IGC::IgcOclDeviceCtxTagOCL>();
|
||||
}
|
||||
|
||||
CIF::RAII::UPtr_t<IGC::PlatformTagOCL> OfflineLinker::getIgcPlatformHandle() const {
|
||||
return igcDeviceCtx->GetPlatformHandle();
|
||||
}
|
||||
|
||||
CIF::RAII::UPtr_t<IGC::GTSystemInfoTagOCL> OfflineLinker::getGTSystemInfoHandle() const {
|
||||
return igcDeviceCtx->GetGTSystemInfoHandle();
|
||||
}
|
||||
|
||||
int OfflineLinker::execute() {
|
||||
switch (operationMode) {
|
||||
case OperationMode::SHOW_HELP:
|
||||
return showHelp();
|
||||
case OperationMode::LINK_FILES:
|
||||
return link();
|
||||
case OperationMode::SKIP_EXECUTION:
|
||||
[[fallthrough]];
|
||||
default:
|
||||
argHelper->printf("Error: Linker cannot be executed due to unsuccessful initialization!\n");
|
||||
return OclocErrorCode::INVALID_COMMAND_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
int OfflineLinker::showHelp() {
|
||||
constexpr auto help{R"===(Links several IR files to selected output format (LLVM BC, ELF).
|
||||
Input files can be given in SPIR-V or LLVM BC.
|
||||
|
||||
Usage: ocloc link [-file <filename>]... -out <filename> [-out_format <format>] [-options <options>] [-internal_options <options>] [--help]
|
||||
|
||||
-file <filename> The input file to be linked.
|
||||
Multiple files can be passed using repetition of this arguments.
|
||||
Please see examples below.
|
||||
|
||||
-out <filename> Output filename.
|
||||
|
||||
-out_format <format> Output file format. Supported ones are ELF and LLVM_BC.
|
||||
When not specified, LLVM_BC is used.
|
||||
|
||||
-options <options> Optional OpenCL C compilation options
|
||||
as defined by OpenCL specification.
|
||||
|
||||
-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.
|
||||
You also may provide explicit --help to inquire
|
||||
information about option, mentioned in -options.
|
||||
|
||||
--help Print this usage message.
|
||||
|
||||
Examples:
|
||||
Link two SPIR-V files to LLVM BC output
|
||||
ocloc link -file first_file.spv -file second_file.spv -out linker_output.llvmbc
|
||||
|
||||
Link two LLVM BC files to ELF output
|
||||
ocloc link -file first_file.llvmbc -file second_file.llvmbc -out_format ELF -out translated.elf
|
||||
)==="};
|
||||
|
||||
argHelper->printf(help);
|
||||
|
||||
return OclocErrorCode::SUCCESS;
|
||||
}
|
||||
|
||||
int OfflineLinker::link() {
|
||||
const auto encodedElfFile{createSingleInputFile()};
|
||||
if (outputFormat == IGC::CodeType::elf) {
|
||||
argHelper->saveOutput(outputFilename, encodedElfFile.data(), encodedElfFile.size());
|
||||
return OclocErrorCode::SUCCESS;
|
||||
}
|
||||
|
||||
const auto [translationResult, translatedBitcode] = translateToOutputFormat(encodedElfFile);
|
||||
if (translationResult == OclocErrorCode::SUCCESS) {
|
||||
argHelper->saveOutput(outputFilename, translatedBitcode.data(), translatedBitcode.size());
|
||||
}
|
||||
|
||||
return translationResult;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> OfflineLinker::createSingleInputFile() const {
|
||||
NEO::Elf::ElfEncoder<> elfEncoder{true, false, 1U};
|
||||
elfEncoder.getElfFileHeader().type = Elf::ET_OPENCL_OBJECTS;
|
||||
|
||||
for (const auto &[bytes, size, codeType] : inputFilesContent) {
|
||||
const auto isSpirv = codeType == IGC::CodeType::spirV;
|
||||
const auto sectionType = isSpirv ? Elf::SHT_OPENCL_SPIRV : Elf::SHT_OPENCL_LLVM_BINARY;
|
||||
const auto sectionName = isSpirv ? Elf::SectionNamesOpenCl::spirvObject : Elf::SectionNamesOpenCl::llvmObject;
|
||||
const auto bytesArray = ArrayRef<const uint8_t>::fromAny(bytes.get(), size);
|
||||
|
||||
elfEncoder.appendSection(sectionType, sectionName, bytesArray);
|
||||
}
|
||||
|
||||
return elfEncoder.encode();
|
||||
}
|
||||
|
||||
std::pair<int, std::vector<uint8_t>> OfflineLinker::translateToOutputFormat(const std::vector<uint8_t> &elfInput) {
|
||||
auto igcSrc = CIF::Builtins::CreateConstBuffer(igcMain.get(), elfInput.data(), elfInput.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(IGC::CodeType::elf, outputFormat);
|
||||
|
||||
const auto tracingOptions{nullptr};
|
||||
const auto tracingOptionsSize{0};
|
||||
const auto igcOutput = igcTranslationCtx->Translate(igcSrc.get(), igcOptions.get(), igcInternalOptions.get(), tracingOptions, tracingOptionsSize);
|
||||
|
||||
std::vector<uint8_t> outputFileContent{};
|
||||
if (!igcOutput) {
|
||||
argHelper->printf("Error: Translation has failed! IGC output is nullptr!\n");
|
||||
return {OclocErrorCode::OUT_OF_HOST_MEMORY, std::move(outputFileContent)};
|
||||
}
|
||||
|
||||
if (igcOutput->GetOutput()->GetSizeRaw() != 0) {
|
||||
outputFileContent.resize(igcOutput->GetOutput()->GetSizeRaw());
|
||||
memcpy_s(outputFileContent.data(), outputFileContent.size(), igcOutput->GetOutput()->GetMemory<char>(), igcOutput->GetOutput()->GetSizeRaw());
|
||||
}
|
||||
|
||||
tryToStoreBuildLog(igcOutput->GetBuildLog()->GetMemory<char>(), igcOutput->GetBuildLog()->GetSizeRaw());
|
||||
|
||||
const auto errorCode{igcOutput->Successful() ? OclocErrorCode::SUCCESS : OclocErrorCode::BUILD_PROGRAM_FAILURE};
|
||||
if (errorCode != OclocErrorCode::SUCCESS) {
|
||||
argHelper->printf("Error: Translation has failed! IGC returned empty output.\n");
|
||||
}
|
||||
|
||||
return {errorCode, std::move(outputFileContent)};
|
||||
}
|
||||
|
||||
std::string OfflineLinker::getBuildLog() const {
|
||||
return buildLog;
|
||||
}
|
||||
|
||||
void OfflineLinker::tryToStoreBuildLog(const char *buildLogRaw, size_t size) {
|
||||
if (buildLogRaw && size != 0) {
|
||||
buildLog = std::string{buildLogRaw, buildLogRaw + size};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace NEO
|
95
shared/offline_compiler/source/offline_linker.h
Normal file
95
shared/offline_compiler/source/offline_linker.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared/source/helpers/hw_info.h"
|
||||
#include "shared/source/utilities/arrayref.h"
|
||||
|
||||
#include "cif/common/cif_main.h"
|
||||
#include "cif/import/library_api.h"
|
||||
#include "ocl_igc_interface/code_type.h"
|
||||
#include "ocl_igc_interface/igc_ocl_device_ctx.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class OclocArgHelper;
|
||||
|
||||
namespace NEO {
|
||||
|
||||
class OsLibrary;
|
||||
|
||||
class OfflineLinker {
|
||||
protected:
|
||||
enum class OperationMode {
|
||||
SKIP_EXECUTION = 0,
|
||||
SHOW_HELP = 1,
|
||||
LINK_FILES = 2,
|
||||
};
|
||||
|
||||
struct InputFileContent {
|
||||
InputFileContent(std::unique_ptr<char[]> bytes, size_t size, IGC::CodeType::CodeType_t codeType)
|
||||
: bytes{std::move(bytes)}, size{size}, codeType{codeType} {}
|
||||
|
||||
std::unique_ptr<char[]> bytes{};
|
||||
size_t size{};
|
||||
IGC::CodeType::CodeType_t codeType{};
|
||||
};
|
||||
|
||||
public:
|
||||
static std::unique_ptr<OfflineLinker> create(size_t argsCount, const std::vector<std::string> &args, int &errorCode, OclocArgHelper *argHelper);
|
||||
MOCKABLE_VIRTUAL ~OfflineLinker();
|
||||
|
||||
int execute();
|
||||
std::string getBuildLog() const;
|
||||
|
||||
protected:
|
||||
explicit OfflineLinker(OclocArgHelper *argHelper);
|
||||
int initialize(size_t argsCount, const std::vector<std::string> &args);
|
||||
int parseCommand(size_t argsCount, const std::vector<std::string> &args);
|
||||
IGC::CodeType::CodeType_t parseOutputFormat(const std::string &outputFormatName);
|
||||
int verifyLinkerCommand();
|
||||
int loadInputFilesContent();
|
||||
IGC::CodeType::CodeType_t detectCodeType(char *bytes, size_t size) const;
|
||||
int initHardwareInfo();
|
||||
int prepareIgc();
|
||||
int link();
|
||||
int showHelp();
|
||||
std::vector<uint8_t> createSingleInputFile() const;
|
||||
std::pair<int, std::vector<uint8_t>> translateToOutputFormat(const std::vector<uint8_t> &elfInput);
|
||||
void tryToStoreBuildLog(const char *buildLogRaw, size_t size);
|
||||
|
||||
MOCKABLE_VIRTUAL ArrayRef<const HardwareInfo *> getHardwareInfoTable() const;
|
||||
MOCKABLE_VIRTUAL std::unique_ptr<OsLibrary> loadIgcLibrary() const;
|
||||
MOCKABLE_VIRTUAL CIF::CreateCIFMainFunc_t loadCreateIgcMainFunction() const;
|
||||
MOCKABLE_VIRTUAL CIF::RAII::UPtr_t<CIF::CIFMain> createIgcMain(CIF::CreateCIFMainFunc_t createMainFunction) const;
|
||||
MOCKABLE_VIRTUAL CIF::RAII::UPtr_t<IGC::IgcOclDeviceCtxTagOCL> createIgcDeviceContext() const;
|
||||
MOCKABLE_VIRTUAL CIF::RAII::UPtr_t<IGC::PlatformTagOCL> getIgcPlatformHandle() const;
|
||||
MOCKABLE_VIRTUAL CIF::RAII::UPtr_t<IGC::GTSystemInfoTagOCL> getGTSystemInfoHandle() const;
|
||||
|
||||
OclocArgHelper *argHelper{};
|
||||
OperationMode operationMode{};
|
||||
|
||||
std::vector<std::string> inputFilenames{};
|
||||
std::vector<InputFileContent> inputFilesContent{};
|
||||
std::string outputFilename{};
|
||||
IGC::CodeType::CodeType_t outputFormat{};
|
||||
std::string options{};
|
||||
std::string internalOptions{};
|
||||
|
||||
std::unique_ptr<OsLibrary> igcLib{};
|
||||
CIF::RAII::UPtr_t<CIF::CIFMain> igcMain{};
|
||||
CIF::RAII::UPtr_t<IGC::IgcOclDeviceCtxTagOCL> igcDeviceCtx{};
|
||||
HardwareInfo hwInfo{};
|
||||
std::string buildLog{};
|
||||
};
|
||||
|
||||
} // namespace NEO
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Intel Corporation
|
||||
* Copyright (C) 2020-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
#include "shared/offline_compiler/source/offline_linker.h"
|
||||
#include "shared/offline_compiler/source/utilities/linux/safety_guard_linux.h"
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
|
||||
@ -17,3 +18,10 @@ int buildWithSafetyGuard(OfflineCompiler *compiler) {
|
||||
|
||||
return safetyGuard.call<int, OfflineCompiler, decltype(&OfflineCompiler::build)>(compiler, &OfflineCompiler::build, retVal);
|
||||
}
|
||||
|
||||
int linkWithSafetyGuard(OfflineLinker *linker) {
|
||||
SafetyGuardLinux safetyGuard{};
|
||||
int returnValueOnCrash{-1};
|
||||
|
||||
return safetyGuard.call(linker, &OfflineLinker::execute, returnValueOnCrash);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
* Copyright (C) 2018-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@ -8,6 +8,8 @@
|
||||
#pragma once
|
||||
namespace NEO {
|
||||
class OfflineCompiler;
|
||||
}
|
||||
class OfflineLinker;
|
||||
} // namespace NEO
|
||||
|
||||
extern int buildWithSafetyGuard(NEO::OfflineCompiler *compiler);
|
||||
extern int linkWithSafetyGuard(NEO::OfflineLinker *linker);
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Intel Corporation
|
||||
* Copyright (C) 2020-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/offline_compiler/source/offline_compiler.h"
|
||||
#include "shared/offline_compiler/source/offline_linker.h"
|
||||
#include "shared/offline_compiler/source/utilities/windows/safety_guard_windows.h"
|
||||
|
||||
using namespace NEO;
|
||||
@ -15,3 +16,10 @@ int buildWithSafetyGuard(OfflineCompiler *compiler) {
|
||||
int retVal = 0;
|
||||
return safetyGuard.call<int, OfflineCompiler, decltype(&OfflineCompiler::build)>(compiler, &OfflineCompiler::build, retVal);
|
||||
}
|
||||
|
||||
int linkWithSafetyGuard(OfflineLinker *linker) {
|
||||
SafetyGuardWindows safetyGuard{};
|
||||
int returnValueOnCrash{-1};
|
||||
|
||||
return safetyGuard.call(linker, &OfflineLinker::execute, returnValueOnCrash);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 Intel Corporation
|
||||
* Copyright (C) 2018-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@ -521,6 +521,10 @@ IGC::OclTranslationOutputBase *MockIgcOclTranslationCtx::TranslateImpl(
|
||||
CIF::Builtins::BufferSimple *internalOptions,
|
||||
CIF::Builtins::BufferSimple *tracingOptions,
|
||||
uint32_t tracingOptionsCount) {
|
||||
if (igcDebugVars->shouldReturnInvalidTranslationOutput) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto out = new MockOclTranslationOutput();
|
||||
translate(true, src, options, internalOptions, out);
|
||||
return out;
|
||||
@ -534,6 +538,10 @@ IGC::OclTranslationOutputBase *MockIgcOclTranslationCtx::TranslateImpl(
|
||||
CIF::Builtins::BufferSimple *tracingOptions,
|
||||
uint32_t tracingOptionsCount,
|
||||
void *gtpinInput) {
|
||||
if (igcDebugVars->shouldReturnInvalidTranslationOutput) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto out = new MockOclTranslationOutput();
|
||||
translate(true, src, options, internalOptions, out);
|
||||
return out;
|
||||
@ -556,6 +564,10 @@ IGC::OclTranslationOutputBase *MockIgcOclTranslationCtx::TranslateImpl(
|
||||
CIF::Builtins::BufferSimple *tracingOptions,
|
||||
uint32_t tracingOptionsCount,
|
||||
void *gtPinInput) {
|
||||
if (igcDebugVars->shouldReturnInvalidTranslationOutput) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto out = new MockOclTranslationOutput();
|
||||
translate(true, src, options, internalOptions, out);
|
||||
return out;
|
||||
@ -618,6 +630,10 @@ IGC::OclTranslationOutputBase *MockFclOclTranslationCtx::TranslateImpl(
|
||||
CIF::Builtins::BufferSimple *internalOptions,
|
||||
CIF::Builtins::BufferSimple *tracingOptions,
|
||||
uint32_t tracingOptionsCount) {
|
||||
if (fclDebugVars->shouldReturnInvalidTranslationOutput) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto out = new MockOclTranslationOutput();
|
||||
translate(false, src, options, internalOptions, out);
|
||||
return out;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 Intel Corporation
|
||||
* Copyright (C) 2018-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@ -25,6 +25,7 @@ struct MockCompilerDebugVars {
|
||||
bindful,
|
||||
bindless
|
||||
};
|
||||
bool shouldReturnInvalidTranslationOutput = false;
|
||||
bool forceBuildFailure = false;
|
||||
bool forceCreateFailure = false;
|
||||
bool forceRegisterFail = false;
|
||||
|
Reference in New Issue
Block a user