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
|
Reference in New Issue
Block a user