/* * Copyright (C) 2020-2021 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "shared/offline_compiler/source/ocloc_api.h" #include "shared/offline_compiler/source/offline_compiler.h" #include "shared/source/device_binary_format/elf/elf_decoder.h" #include "shared/source/device_binary_format/elf/ocl_elf.h" #include "environment.h" #include "gtest/gtest.h" #include "hw_cmds.h" #include extern Environment *gEnvironment; using namespace std::string_literals; TEST(OclocApiTests, WhenOclocVersionIsCalledThenCurrentOclocVersionIsReturned) { EXPECT_EQ(ocloc_version_t::OCLOC_VERSION_CURRENT, oclocVersion()); } TEST(OclocApiTests, WhenGoodArgsAreGivenThenSuccessIsReturned) { const char *argv[] = { "ocloc", "-file", "test_files/copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); 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(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS); EXPECT_EQ(std::string::npos, output.find("Command was: ocloc -file test_files/copybuffer.cl -device "s + argv[4])); } TEST(OclocApiTests, WhenGoodFamilyNameIsProvidedThenSuccessIsReturned) { const char *argv[] = { "ocloc", "-file", "test_files/copybuffer.cl", "-device", NEO::familyName[NEO::DEFAULT_PLATFORM::hwInfo.platform.eRenderCoreFamily]}; unsigned int argc = sizeof(argv) / sizeof(const char *); 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(retVal, NEO::OfflineCompiler::ErrorCode::SUCCESS); EXPECT_EQ(std::string::npos, output.find("Command was: ocloc -file test_files/copybuffer.cl -device "s + argv[4])); } TEST(OclocApiTests, WhenArgsWithMissingFileAreGivenThenErrorMessageIsProduced) { const char *argv[] = { "ocloc", "-q", "-file", "test_files/IDoNotExist.cl", "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); 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(retVal, NEO::OfflineCompiler::ErrorCode::INVALID_FILE); EXPECT_NE(std::string::npos, output.find("Command was: ocloc -q -file test_files/IDoNotExist.cl -device "s + argv[5])); } TEST(OclocApiTests, GivenIncludeHeadersWhenCompilingThenPassesToFclHeadersPackedAsElf) { auto prevFclDebugVars = NEO::getFclDebugVars(); auto debugVars = prevFclDebugVars; std::string receivedInput; debugVars.receivedInput = &receivedInput; setFclDebugVars(debugVars); const char *argv[] = { "ocloc", "-file", "main.cl", "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); const char *headerA = R"===( void foo() {} )==="; const char *headerB = R"===( void bar() {} )==="; const char *main = R"===( #include "includeA.h" #include "includeB.h" __kernel void k(){ foo(); bar(); } )==="; const char *sourcesNames[] = {"main.cl"}; const uint8_t *sources[] = {reinterpret_cast(main)}; const uint64_t sourcesLen[] = {strlen(main) + 1}; const char *headersNames[] = {"includeA.h", "includeB.h"}; const uint8_t *headers[] = {reinterpret_cast(headerA), reinterpret_cast(headerB)}; const uint64_t headersLen[] = {strlen(headerA) + 1, strlen(headerB) + 1}; uint32_t numOutputs = 0U; uint8_t **outputs = nullptr; uint64_t *outputsLen = nullptr; char **ouputsNames = nullptr; oclocInvoke(argc, argv, 1, sources, sourcesLen, sourcesNames, 2, headers, headersLen, headersNames, &numOutputs, &outputs, &outputsLen, &ouputsNames); NEO::setFclDebugVars(prevFclDebugVars); std::string decodeErr, decodeWarn; ArrayRef rawElf(reinterpret_cast(receivedInput.data()), receivedInput.size()); auto elf = NEO::Elf::decodeElf(rawElf, decodeErr, decodeWarn); ASSERT_NE(nullptr, elf.elfFileHeader) << decodeWarn << " " << decodeErr; EXPECT_EQ(NEO::Elf::ET_OPENCL_SOURCE, elf.elfFileHeader->type); using SectionT = std::remove_reference_t; const SectionT *sourceSection, *headerASection, *headerBSection; ASSERT_NE(NEO::Elf::SHN_UNDEF, elf.elfFileHeader->shStrNdx); auto sectionNamesSection = elf.sectionHeaders.begin() + elf.elfFileHeader->shStrNdx; auto elfStrings = sectionNamesSection->data.toArrayRef(); for (const auto §ion : elf.sectionHeaders) { if (NEO::Elf::SHT_OPENCL_SOURCE == section.header->type) { sourceSection = §ion; } else if (NEO::Elf::SHT_OPENCL_HEADER == section.header->type) { auto sectionName = elfStrings.begin() + section.header->name; if (0 == strcmp("includeA.h", sectionName)) { headerASection = §ion; } else if (0 == strcmp("includeB.h", sectionName)) { headerBSection = §ion; } else { EXPECT_FALSE(true) << sectionName; } } } ASSERT_NE(nullptr, sourceSection); EXPECT_EQ(sourcesLen[0], sourceSection->data.size()); EXPECT_STREQ(main, reinterpret_cast(sourceSection->data.begin())); ASSERT_NE(nullptr, headerASection); EXPECT_EQ(sourcesLen[0], sourceSection->data.size()); EXPECT_STREQ(headerA, reinterpret_cast(headerASection->data.begin())); ASSERT_NE(nullptr, headerBSection); EXPECT_EQ(sourcesLen[0], sourceSection->data.size()); EXPECT_STREQ(headerB, reinterpret_cast(headerBSection->data.begin())); }