/* * Copyright (C) 2017-2018 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "runtime/compiler_interface/compiler_interface.h" #include "runtime/compiler_interface/compiler_interface.inl" #include "runtime/context/context.h" #include "runtime/gen_common/hw_cmds.h" #include "runtime/helpers/file_io.h" #include "runtime/helpers/hw_info.h" #include "runtime/os_interface/debug_settings_manager.h" #include "runtime/platform/platform.h" #include "unit_tests/fixtures/device_fixture.h" #include "unit_tests/global_environment.h" #include "unit_tests/helpers/test_files.h" #include "unit_tests/helpers/debug_manager_state_restore.h" #include "unit_tests/helpers/memory_management.h" #include "unit_tests/mocks/mock_cif.h" #include "unit_tests/mocks/mock_compilers.h" #include "unit_tests/mocks/mock_context.h" #include "unit_tests/mocks/mock_program.h" #include "gmock/gmock.h" using namespace OCLRT; #if defined(_WIN32) const char *gBadDompilerDllName = "bad_compiler.dll"; #elif defined(__linux__) const char *gCBadDompilerDllName = "libbad_compiler.so"; #else #error "Unknown OS!" #endif class CompilerInterfaceTest : public DeviceFixture, public ::testing::Test { public: void SetUp() override { DeviceFixture::SetUp(); retVal = CL_SUCCESS; // create the compiler interface this->pCompilerInterface = new MockCompilerInterface(); bool initRet = pCompilerInterface->initialize(); ASSERT_TRUE(initRet); pDevice->getExecutionEnvironment()->compilerInterface.reset(pCompilerInterface); std::string testFile; testFile.append(clFiles); testFile.append("CopyBuffer_simd8.cl"); sourceSize = loadDataFromFile( testFile.c_str(), pSource); ASSERT_NE(0u, sourceSize); ASSERT_NE(nullptr, pSource); cl_device_id clDevice = pDevice; pContext = Context::create(nullptr, DeviceVector(&clDevice, 1), nullptr, nullptr, retVal); pProgram = new Program(*pDevice->getExecutionEnvironment(), pContext, false); inputArgs.pInput = (char *)pSource; inputArgs.InputSize = (uint32_t)sourceSize; inputArgs.pOptions = nullptr; inputArgs.OptionsSize = 0; inputArgs.pInternalOptions = nullptr; inputArgs.InternalOptionsSize = 0; inputArgs.pTracingOptions = nullptr; inputArgs.TracingOptionsCount = 0; } void TearDown() override { delete pProgram; delete pContext; deleteDataReadFromFile(pSource); DeviceFixture::TearDown(); } MockCompilerInterface *pCompilerInterface; TranslationArgs inputArgs; Program *pProgram = nullptr; MockContext *pContext = nullptr; void *pSource = nullptr; size_t sourceSize = 0; cl_int retVal = CL_SUCCESS; }; TEST_F(CompilerInterfaceTest, BuildWithDebugData) { class MyCompilerInterface : public CompilerInterface { public: static MyCompilerInterface *allocate() { auto compilerInterface = new MyCompilerInterface(); if (!compilerInterface->initializePub()) { delete compilerInterface; compilerInterface = nullptr; } for (size_t n = 0; n < sizeof(compilerInterface->mockDebugData); n++) { compilerInterface->mockDebugData[n] = (char)n; } auto vars = OCLRT::getIgcDebugVars(); vars.debugDataToReturn = compilerInterface->mockDebugData; vars.debugDataToReturnSize = sizeof(compilerInterface->mockDebugData); OCLRT::setIgcDebugVars(vars); return compilerInterface; } ~MyCompilerInterface() override { auto vars = OCLRT::getIgcDebugVars(); vars.debugDataToReturn = nullptr; vars.debugDataToReturnSize = 0; OCLRT::setIgcDebugVars(vars); } bool initializePub() { return initialize(); } char mockDebugData[32]; }; // Build a regular program cl_device_id device = pDevice; char *kernel = (char *)"__kernel void\nCB(\n__global unsigned int* src, __global unsigned int* dst)\n{\nint id = (int)get_global_id(0);\ndst[id] = src[id];\n}\n"; pProgram->setSource(kernel); retVal = pProgram->build(1, &device, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); // Inject DebugData during this build class MyCompilerInterface *cip = MyCompilerInterface::allocate(); EXPECT_NE(nullptr, cip); retVal = cip->build(*pProgram, inputArgs, false); EXPECT_EQ(CL_SUCCESS, retVal); // Verify size_t debugDataSize = 0; retVal = pProgram->getInfo(CL_PROGRAM_DEBUG_INFO_SIZES_INTEL, sizeof(debugDataSize), &debugDataSize, nullptr); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(debugDataSize, sizeof(cip->mockDebugData)); char *debugData = new char[debugDataSize]; for (size_t n = 0; n < sizeof(debugData); n++) { debugData[n] = 0; } char *pDebugData = &debugData[0]; size_t retData = 0; bool isOK = true; retVal = pProgram->getInfo(CL_PROGRAM_DEBUG_INFO_INTEL, 1, &pDebugData, &retData); EXPECT_EQ(CL_INVALID_VALUE, retVal); retVal = pProgram->getInfo(CL_PROGRAM_DEBUG_INFO_INTEL, debugDataSize, &pDebugData, &retData); EXPECT_EQ(CL_SUCCESS, retVal); cl_uint numDevices; retVal = clGetProgramInfo(pProgram, CL_PROGRAM_NUM_DEVICES, sizeof(numDevices), &numDevices, nullptr); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(numDevices * sizeof(debugData), retData); // Check integrity of returned debug data for (size_t n = 0; n < debugDataSize; n++) { if (debugData[n] != (char)n) { isOK = false; break; } } EXPECT_TRUE(isOK); for (size_t n = debugDataSize; n < sizeof(debugData); n++) { if (debugData[n] != (char)0) { isOK = false; break; } } EXPECT_TRUE(isOK); retData = 0; retVal = pProgram->getInfo(CL_PROGRAM_DEBUG_INFO_INTEL, debugDataSize, nullptr, &retData); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(numDevices * sizeof(debugData), retData); delete[] debugData; delete cip; } TEST_F(CompilerInterfaceTest, CompileClToIsa) { // build from .cl to gen ISA retVal = pCompilerInterface->build(*pProgram, inputArgs, false); EXPECT_EQ(CL_SUCCESS, retVal); } TEST_F(CompilerInterfaceTest, WhenBuildIsInvokedThenFclReceivesListOfExtensionsInInternalOptions) { std::string receivedInternalOptions; auto debugVars = OCLRT::getFclDebugVars(); debugVars.receivedInternalOptionsOutput = &receivedInternalOptions; gEnvironment->fclPushDebugVars(debugVars); retVal = pCompilerInterface->build(*pProgram, inputArgs, false); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_THAT(receivedInternalOptions, testing::HasSubstr(platform()->peekCompilerExtensions())); gEnvironment->fclPopDebugVars(); } TEST_F(CompilerInterfaceTest, whenCompilerIsNotAvailableThenBuildFailsGracefully) { pCompilerInterface->GetIgcMain()->Release(); pCompilerInterface->SetIgcMain(nullptr); retVal = pCompilerInterface->build(*pProgram, inputArgs, false); EXPECT_EQ(CL_COMPILER_NOT_AVAILABLE, retVal); } TEST_F(CompilerInterfaceTest, whenFclTranslatorReturnsNullptrThenBuildFailsGracefully) { pCompilerInterface->failCreateFclTranslationCtx = true; retVal = pCompilerInterface->build(*pProgram, inputArgs, false); pCompilerInterface->failCreateFclTranslationCtx = false; EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); } TEST_F(CompilerInterfaceTest, whenIgcTranslatorReturnsNullptrThenBuildFailsGracefully) { pCompilerInterface->failCreateIgcTranslationCtx = true; retVal = pCompilerInterface->build(*pProgram, inputArgs, false); pCompilerInterface->failCreateIgcTranslationCtx = true; EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); } TEST_F(CompilerInterfaceTest, CompileClToIsaWithOptions) { // build from .cl to gen ISA std::string internalOptions = "SOME_OPTION"; MockCompilerDebugVars fclDebugVars; fclDebugVars.fileName = gEnvironment->fclGetMockFile(); fclDebugVars.internalOptionsExpected = true; gEnvironment->fclPushDebugVars(fclDebugVars); MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = gEnvironment->igcGetMockFile(); igcDebugVars.internalOptionsExpected = true; gEnvironment->igcPushDebugVars(igcDebugVars); inputArgs.pInternalOptions = internalOptions.c_str(); inputArgs.InternalOptionsSize = static_cast(internalOptions.length()); retVal = pCompilerInterface->build(*pProgram, inputArgs, false); EXPECT_EQ(CL_SUCCESS, retVal); gEnvironment->fclPopDebugVars(); gEnvironment->igcPopDebugVars(); } TEST_F(CompilerInterfaceTest, CompileClToIr) { // compile only from .cl to IR MockCompilerDebugVars fclDebugVars; fclDebugVars.fileName = clFiles + "copybuffer.elf"; gEnvironment->fclPushDebugVars(fclDebugVars); retVal = pCompilerInterface->compile(*pProgram, inputArgs); EXPECT_EQ(CL_SUCCESS, retVal); gEnvironment->fclPopDebugVars(); } TEST_F(CompilerInterfaceTest, GivenProgramCreatedFromIrWhenCompileIsCalledThenIrFormatIsPreserved) { MockProgram prog(*pDevice->getExecutionEnvironment(), pContext, false); prog.programBinaryType = CL_PROGRAM_BINARY_TYPE_INTERMEDIATE; prog.isSpirV = true; retVal = pCompilerInterface->compile(prog, inputArgs); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(prog.isSpirV); prog.isSpirV = false; retVal = pCompilerInterface->compile(prog, inputArgs); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_FALSE(prog.isSpirV); } TEST_F(CompilerInterfaceTest, WhenCompileIsInvokedThenFclReceivesListOfExtensionsInInternalOptions) { std::string receivedInternalOptions; MockCompilerDebugVars fclDebugVars; fclDebugVars.fileName = clFiles + "copybuffer.elf"; fclDebugVars.receivedInternalOptionsOutput = &receivedInternalOptions; gEnvironment->fclPushDebugVars(fclDebugVars); retVal = pCompilerInterface->compile(*pProgram, inputArgs); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_THAT(receivedInternalOptions, testing::HasSubstr(platform()->peekCompilerExtensions())); gEnvironment->fclPopDebugVars(); } TEST_F(CompilerInterfaceTest, whenCompilerIsNotAvailableThenCompileFailsGracefully) { MockCompilerDebugVars fclDebugVars; fclDebugVars.fileName = clFiles + "copybuffer.elf"; gEnvironment->fclPushDebugVars(fclDebugVars); pCompilerInterface->GetIgcMain()->Release(); pCompilerInterface->SetIgcMain(nullptr); retVal = pCompilerInterface->compile(*pProgram, inputArgs); EXPECT_EQ(CL_COMPILER_NOT_AVAILABLE, retVal); gEnvironment->fclPopDebugVars(); } TEST_F(CompilerInterfaceTest, whenFclTranslatorReturnsNullptrThenCompileFailsGracefully) { MockCompilerDebugVars fclDebugVars; fclDebugVars.fileName = clFiles + "copybuffer.elf"; gEnvironment->fclPushDebugVars(fclDebugVars); pCompilerInterface->failCreateFclTranslationCtx = true; retVal = pCompilerInterface->compile(*pProgram, inputArgs); pCompilerInterface->failCreateFclTranslationCtx = false; EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); gEnvironment->fclPopDebugVars(); } TEST_F(CompilerInterfaceTest, CompileClToIrCompileFailure) { // compile only from .cl to IR MockCompilerDebugVars fclDebugVars; fclDebugVars.fileName = "../copybuffer.elf"; fclDebugVars.forceBuildFailure = true; gEnvironment->fclPushDebugVars(fclDebugVars); retVal = pCompilerInterface->compile(*pProgram, inputArgs); EXPECT_EQ(CL_COMPILE_PROGRAM_FAILURE, retVal); gEnvironment->fclPopDebugVars(); } TEST_F(CompilerInterfaceTest, LinkIrLinkFailure) { // link only .ll to gen ISA MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = "../copybuffer.ll"; igcDebugVars.forceBuildFailure = true; gEnvironment->igcPushDebugVars(igcDebugVars); retVal = pCompilerInterface->link(*pProgram, inputArgs); EXPECT_EQ(CL_BUILD_PROGRAM_FAILURE, retVal); gEnvironment->igcPopDebugVars(); } TEST_F(CompilerInterfaceTest, WhenLinkIsCalledThenLlvmBcIsUsedAsIntermediateRepresentation) { // link only from .ll to gen ISA MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = clFiles + "copybuffer.ll"; gEnvironment->igcPushDebugVars(igcDebugVars); retVal = pCompilerInterface->link(*pProgram, inputArgs); gEnvironment->igcPopDebugVars(); ASSERT_EQ(CL_SUCCESS, retVal); ASSERT_EQ(2U, pCompilerInterface->requestedTranslationCtxs.size()); MockCompilerInterface::TranslationOpT firstTranslation = {IGC::CodeType::elf, IGC::CodeType::llvmBc}, secondTranslation = {IGC::CodeType::llvmBc, IGC::CodeType::oclGenBin}; EXPECT_EQ(firstTranslation, pCompilerInterface->requestedTranslationCtxs[0]); EXPECT_EQ(secondTranslation, pCompilerInterface->requestedTranslationCtxs[1]); } TEST_F(CompilerInterfaceTest, whenCompilerIsNotAvailableThenLinkFailsGracefully) { MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = clFiles + "copybuffer.ll"; gEnvironment->igcPushDebugVars(igcDebugVars); pCompilerInterface->GetIgcMain()->Release(); pCompilerInterface->SetIgcMain(nullptr); retVal = pCompilerInterface->link(*pProgram, inputArgs); EXPECT_EQ(CL_COMPILER_NOT_AVAILABLE, retVal); gEnvironment->igcPopDebugVars(); } TEST_F(CompilerInterfaceTest, whenSrcAllocationFailsThenLinkFailsGracefully) { MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = clFiles + "copybuffer.ll"; gEnvironment->igcPushDebugVars(igcDebugVars); MockCIFBuffer::failAllocations = true; retVal = pCompilerInterface->link(*pProgram, inputArgs); MockCIFBuffer::failAllocations = false; EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); gEnvironment->igcPopDebugVars(); } TEST_F(CompilerInterfaceTest, whenTranslateReturnsNullptrThenLinkFailsGracefully) { MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = clFiles + "copybuffer.ll"; gEnvironment->igcPushDebugVars(igcDebugVars); pCompilerInterface->failCreateIgcTranslationCtx = true; retVal = pCompilerInterface->link(*pProgram, inputArgs); pCompilerInterface->failCreateIgcTranslationCtx = false; EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); gEnvironment->igcPopDebugVars(); } TEST_F(CompilerInterfaceTest, CreateLibFailure) { // create library from .ll to IR MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = "../copybuffer.ll"; igcDebugVars.forceBuildFailure = true; gEnvironment->igcPushDebugVars(igcDebugVars); retVal = pCompilerInterface->createLibrary(*pProgram, inputArgs); EXPECT_EQ(CL_BUILD_PROGRAM_FAILURE, retVal); gEnvironment->igcPopDebugVars(); } TEST_F(CompilerInterfaceTest, WhenCreateLibraryIsCalledThenLlvmBcIsUsedAsIntermediateRepresentation) { // create library from .ll to IR MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = clFiles + "copybuffer.ll"; gEnvironment->igcPushDebugVars(igcDebugVars); retVal = pCompilerInterface->createLibrary(*pProgram, inputArgs); gEnvironment->igcPopDebugVars(); EXPECT_EQ(CL_SUCCESS, retVal); ASSERT_EQ(1U, pCompilerInterface->requestedTranslationCtxs.size()); EXPECT_EQ(IGC::CodeType::llvmBc, pCompilerInterface->requestedTranslationCtxs[0].second); } TEST_F(CompilerInterfaceTest, whenCompilerIsNotAvailableThenCreateLibraryFailsGracefully) { MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = clFiles + "copybuffer.ll"; gEnvironment->igcPushDebugVars(igcDebugVars); pCompilerInterface->GetIgcMain()->Release(); pCompilerInterface->SetIgcMain(nullptr); retVal = pCompilerInterface->createLibrary(*pProgram, inputArgs); EXPECT_EQ(CL_COMPILER_NOT_AVAILABLE, retVal); gEnvironment->igcPopDebugVars(); } TEST_F(CompilerInterfaceTest, whenIgcTranslatorReturnsNullptrThenCreateLibraryFailsGracefully) { MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = clFiles + "copybuffer.ll"; gEnvironment->igcPushDebugVars(igcDebugVars); pCompilerInterface->failCreateIgcTranslationCtx = true; retVal = pCompilerInterface->createLibrary(*pProgram, inputArgs); pCompilerInterface->failCreateIgcTranslationCtx = false; EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); gEnvironment->igcPopDebugVars(); } TEST_F(CompilerInterfaceTest, fclBuildFailure) { MockCompilerDebugVars fclDebugVars; fclDebugVars.forceCreateFailure = false; fclDebugVars.forceBuildFailure = true; fclDebugVars.forceRegisterFail = false; fclDebugVars.fileName = "copybuffer_skl.bc"; gEnvironment->fclPushDebugVars(fclDebugVars); // build from .cl to gen ISA retVal = pCompilerInterface->build(*pProgram, inputArgs, false); EXPECT_EQ(CL_BUILD_PROGRAM_FAILURE, retVal); gEnvironment->fclPopDebugVars(); } TEST_F(CompilerInterfaceTest, igcBuildFailure) { MockCompilerDebugVars igcDebugVars; igcDebugVars.forceCreateFailure = false; igcDebugVars.forceBuildFailure = true; igcDebugVars.forceRegisterFail = false; igcDebugVars.fileName = "copybuffer_skl.gen"; gEnvironment->igcPushDebugVars(igcDebugVars); // build from .cl to gen ISA retVal = pCompilerInterface->build(*pProgram, inputArgs, false); EXPECT_EQ(CL_BUILD_PROGRAM_FAILURE, retVal); gEnvironment->igcPopDebugVars(); } TEST_F(CompilerInterfaceTest, CompileAndLinkSpirToIsa) { // compile and link from SPIR binary to gen ISA MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); char binary[] = "BC\xc0\xde "; auto retVal = program.createProgramFromBinary(binary, sizeof(binary)); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pCompilerInterface->compile(program, inputArgs); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pCompilerInterface->link(program, inputArgs); EXPECT_EQ(CL_SUCCESS, retVal); } TEST_F(CompilerInterfaceTest, BuildSpirToIsa) { // build from SPIR binary to gen ISA MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); char binary[] = "BC\xc0\xde "; auto retVal = program.createProgramFromBinary(binary, sizeof(binary)); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pCompilerInterface->build(program, inputArgs, false); EXPECT_EQ(CL_SUCCESS, retVal); } TEST_F(CompilerInterfaceTest, BuildSpirvToIsa) { // build from SPIR binary to gen ISA MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); uint64_t spirv[16] = {0x03022307}; auto retVal = program.createProgramFromBinary(spirv, sizeof(spirv)); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pCompilerInterface->build(program, inputArgs, false); EXPECT_EQ(CL_SUCCESS, retVal); } struct TranslationCtxMock { bool returnNullptr = false; bool returnNullptrOutput = false; bool returnNullptrLog = false; bool returnNullptrDebugData = false; CIF::Builtins::BufferSimple *receivedSrc = nullptr; CIF::Builtins::BufferSimple *receivedOpt = nullptr; CIF::Builtins::BufferSimple *receivedIntOpt = nullptr; CIF::Builtins::BufferSimple *receivedTracingOpt = nullptr; CIF::RAII::UPtr_t Translate(CIF::Builtins::BufferSimple *src, CIF::Builtins::BufferSimple *options, CIF::Builtins::BufferSimple *internalOptions, CIF::Builtins::BufferSimple *tracingOptions, uint32_t tracingOptionsCount) { this->receivedSrc = src; this->receivedOpt = options; this->receivedIntOpt = internalOptions; this->receivedTracingOpt = tracingOptions; if (returnNullptr) { return CIF::RAII::UPtr_t(nullptr); } auto ret = new MockOclTranslationOutput(); if (returnNullptrOutput) { ret->output->Release(); ret->output = nullptr; } if (returnNullptrLog) { ret->log->Release(); ret->log = nullptr; } if (returnNullptrDebugData) { ret->debugData->Release(); ret->debugData = nullptr; } return CIF::RAII::UPtr_t(ret); } CIF::RAII::UPtr_t Translate(CIF::Builtins::BufferSimple *src, CIF::Builtins::BufferSimple *options, CIF::Builtins::BufferSimple *internalOptions, CIF::Builtins::BufferSimple *tracingOptions, uint32_t tracingOptionsCount, void *gtpinInit) { return this->Translate(src, options, internalOptions, tracingOptions, tracingOptionsCount); } }; TEST(TranslateTest, whenArgsAreValidAndTranslatorReturnsValidOutputThenValidOutputIsReturned) { TranslationCtxMock mockTranslationCtx; auto mockSrc = CIF::RAII::UPtr_t(new MockCIFBuffer()); auto mockOpt = CIF::RAII::UPtr_t(new MockCIFBuffer()); auto mockIntOpt = CIF::RAII::UPtr_t(new MockCIFBuffer()); auto ret = OCLRT::translate(&mockTranslationCtx, mockSrc.get(), mockOpt.get(), mockIntOpt.get()); EXPECT_NE(nullptr, ret); EXPECT_EQ(mockSrc.get(), mockTranslationCtx.receivedSrc); EXPECT_EQ(mockOpt.get(), mockTranslationCtx.receivedOpt); EXPECT_EQ(mockIntOpt.get(), mockTranslationCtx.receivedIntOpt); } TEST(TranslateTest, whenTranslatorReturnsNullptrThenNullptrIsReturned) { TranslationCtxMock mockTranslationCtx; mockTranslationCtx.returnNullptr = true; auto mockCifBuffer = CIF::RAII::UPtr_t(new MockCIFBuffer()); auto ret = OCLRT::translate(&mockTranslationCtx, mockCifBuffer.get(), mockCifBuffer.get(), mockCifBuffer.get()); EXPECT_EQ(nullptr, ret); } TEST(TranslateTest, givenNullPtrAsGtPinInputWhenTranslatorReturnsNullptrThenNullptrIsReturned) { TranslationCtxMock mockTranslationCtx; mockTranslationCtx.returnNullptr = true; auto mockCifBuffer = std::make_unique(); auto ret = OCLRT::translate(&mockTranslationCtx, mockCifBuffer.get(), mockCifBuffer.get(), mockCifBuffer.get(), nullptr); EXPECT_EQ(nullptr, ret); } TEST(TranslateTest, whenTranslatorReturnsInvalidOutputThenNullptrIsReturned) { TranslationCtxMock mockTranslationCtx; auto mockCifBuffer = CIF::RAII::UPtr_t(new MockCIFBuffer()); for (uint32_t i = 1; i <= (1 << 3) - 1; ++i) { mockTranslationCtx.returnNullptrDebugData = (i & 1) != 0; mockTranslationCtx.returnNullptrLog = (i & (1 << 1)) != 0; mockTranslationCtx.returnNullptrOutput = (i & (1 << 2)) != 0; auto ret = OCLRT::translate(&mockTranslationCtx, mockCifBuffer.get(), mockCifBuffer.get(), mockCifBuffer.get()); EXPECT_EQ(nullptr, ret); } } TEST(TranslateTest, givenNullPtrAsGtPinInputWhenTranslatorReturnsInvalidOutputThenNullptrIsReturned) { TranslationCtxMock mockTranslationCtx; auto mockCifBuffer = CIF::RAII::UPtr_t(new MockCIFBuffer()); for (uint32_t i = 1; i <= (1 << 3) - 1; ++i) { mockTranslationCtx.returnNullptrDebugData = (i & 1) != 0; mockTranslationCtx.returnNullptrLog = (i & (1 << 1)) != 0; mockTranslationCtx.returnNullptrOutput = (i & (1 << 2)) != 0; auto ret = OCLRT::translate(&mockTranslationCtx, mockCifBuffer.get(), mockCifBuffer.get(), mockCifBuffer.get(), nullptr); EXPECT_EQ(nullptr, ret); } } TEST(TranslateTest, whenAnyArgIsNullThenNullptrIsReturnedAndTranslatorIsNotInvoked) { TranslationCtxMock mockTranslationCtx; auto mockCifBuffer = CIF::RAII::UPtr_t(new MockCIFBuffer()); for (uint32_t i = 0; i < (1 << 3) - 1; ++i) { auto src = (i & 1) ? mockCifBuffer.get() : nullptr; auto opts = (i & (1 << 1)) ? mockCifBuffer.get() : nullptr; auto intOpts = (i & (1 << 2)) ? mockCifBuffer.get() : nullptr; auto ret = OCLRT::translate(&mockTranslationCtx, src, opts, intOpts); EXPECT_EQ(nullptr, ret); } EXPECT_EQ(nullptr, mockTranslationCtx.receivedSrc); EXPECT_EQ(nullptr, mockTranslationCtx.receivedOpt); EXPECT_EQ(nullptr, mockTranslationCtx.receivedIntOpt); EXPECT_EQ(nullptr, mockTranslationCtx.receivedTracingOpt); } TEST(LoadCompilerTest, whenEverythingIsOkThenReturnsTrueAndValidOutputs) { MockCompilerEnableGuard mock; std::unique_ptr retLib; CIF::RAII::UPtr_t retMain; bool retVal = loadCompiler("", retLib, retMain); EXPECT_TRUE(retVal); EXPECT_NE(nullptr, retLib.get()); EXPECT_NE(nullptr, retMain.get()); } TEST(LoadCompilerTest, whenCouldNotLoadLibraryThenReturnFalseAndNullOutputs) { MockCompilerEnableGuard mock; std::unique_ptr retLib; CIF::RAII::UPtr_t retMain; bool retVal = loadCompiler("falseName.notRealLib", retLib, retMain); EXPECT_FALSE(retVal); EXPECT_EQ(nullptr, retLib.get()); EXPECT_EQ(nullptr, retMain.get()); } TEST(LoadCompilerTest, whenCreateMainFailsThenReturnFalseAndNullOutputs) { OCLRT::failCreateCifMain = true; MockCompilerEnableGuard mock; std::unique_ptr retLib; CIF::RAII::UPtr_t retMain; bool retVal = loadCompiler("", retLib, retMain); EXPECT_FALSE(retVal); EXPECT_EQ(nullptr, retLib.get()); EXPECT_EQ(nullptr, retMain.get()); OCLRT::failCreateCifMain = false; } TEST(LoadCompilerTest, whenEntrypointInterfaceIsNotCompatibleThenReturnFalseAndNullOutputs) { MockCompilerEnableGuard mock; std::unique_ptr retLib; CIF::RAII::UPtr_t retMain; bool retVal = loadCompiler("", retLib, retMain); EXPECT_FALSE(retVal); EXPECT_EQ(nullptr, retLib.get()); EXPECT_EQ(nullptr, retMain.get()); } template struct MockCompilerDeviceCtx : DeviceCtxBase { TranslationCtx *CreateTranslationCtxImpl(CIF::Version_t ver, IGC::CodeType::CodeType_t inType, IGC::CodeType::CodeType_t outType) override { returned = new TranslationCtx; return returned; } TranslationCtx *returned = nullptr; }; template struct LockListener { LockListener(OCLRT::Device *device) : device(device) { } static void Listener(MockCompilerInterface &compInt) { auto data = (LockListener *)compInt.lockListenerData; auto deviceCtx = CIF::RAII::UPtr(new MockDeviceCtx); EXPECT_TRUE(compInt.getDeviceContexts().empty()); compInt.setDeviceCtx(*data->device, deviceCtx.get()); data->createdDeviceCtx = deviceCtx.get(); } OCLRT::Device *device = nullptr; MockDeviceCtx *createdDeviceCtx = nullptr; }; TEST_F(CompilerInterfaceTest, GivenRequestForNewFclTranslationCtxWhenDeviceCtxIsNotAvailableThenCreateNewDeviceCtxAndUseItToReturnValidTranslationCtx) { auto device = this->pContext->getDevice(0); auto ret = this->pCompilerInterface->createFclTranslationCtx(*device, IGC::CodeType::oclC, IGC::CodeType::spirV); EXPECT_NE(nullptr, ret.get()); auto firstBaseCtx = this->pCompilerInterface->getFclBaseTranslationCtx(); EXPECT_NE(nullptr, firstBaseCtx); MockDevice md{device->getHardwareInfo()}; auto ret2 = this->pCompilerInterface->createFclTranslationCtx(md, IGC::CodeType::oclC, IGC::CodeType::spirV); EXPECT_NE(nullptr, ret2.get()); EXPECT_EQ(firstBaseCtx, this->pCompilerInterface->getFclBaseTranslationCtx()); } TEST_F(CompilerInterfaceTest, GivenRequestForNewFclTranslationCtxWhenDeviceCtxIsAlreadyAvailableThenUseItToReturnValidTranslationCtx) { auto device = this->pContext->getDevice(0); auto deviceCtx = CIF::RAII::UPtr(new MockCompilerDeviceCtx); this->pCompilerInterface->setFclDeviceCtx(*device, deviceCtx.get()); auto ret = this->pCompilerInterface->createFclTranslationCtx(*device, IGC::CodeType::oclC, IGC::CodeType::spirV); EXPECT_NE(nullptr, ret.get()); EXPECT_EQ(deviceCtx->returned, ret.get()); } TEST_F(CompilerInterfaceTest, GivenSimultaneousRequestForNewFclTranslationContextsWhenDeviceCtxIsNotAlreadyAvailableThenSynchronizeToCreateOnlyOneNewDeviceCtx) { auto device = this->pContext->getDevice(0); using ListenerT = LockListener; ListenerT listenerData(device); this->pCompilerInterface->lockListenerData = &listenerData; this->pCompilerInterface->lockListener = ListenerT::Listener; auto ret = this->pCompilerInterface->createFclTranslationCtx(*device, IGC::CodeType::oclC, IGC::CodeType::spirV); EXPECT_NE(nullptr, ret.get()); ASSERT_EQ(1U, this->pCompilerInterface->getFclDeviceContexts().size()); ASSERT_NE(this->pCompilerInterface->getFclDeviceContexts().end(), this->pCompilerInterface->getFclDeviceContexts().find(device)); EXPECT_NE(nullptr, listenerData.createdDeviceCtx); EXPECT_EQ(listenerData.createdDeviceCtx, this->pCompilerInterface->getFclDeviceContexts()[device].get()); } TEST_F(CompilerInterfaceTest, GivenRequestForNewTranslationCtxWhenFclMainIsNotAvailableThenReturnNullptr) { OCLRT::failCreateCifMain = true; auto device = this->pContext->getDevice(0); MockCompilerInterface tempCompilerInterface; auto retFcl = tempCompilerInterface.createFclTranslationCtx(*device, IGC::CodeType::oclC, IGC::CodeType::spirV); EXPECT_EQ(nullptr, retFcl); auto retIgc = tempCompilerInterface.createIgcTranslationCtx(*device, IGC::CodeType::oclC, IGC::CodeType::spirV); EXPECT_EQ(nullptr, retIgc); OCLRT::failCreateCifMain = false; } TEST_F(CompilerInterfaceTest, GivenRequestForNewTranslationCtxWhenCouldNotCreateDeviceCtxThenReturnNullptr) { auto device = this->pContext->getDevice(0); auto befFclMock = OCLRT::MockCIFMain::getGlobalCreatorFunc(); auto befIgcMock = OCLRT::MockCIFMain::getGlobalCreatorFunc(); OCLRT::MockCIFMain::setGlobalCreatorFunc(nullptr); OCLRT::MockCIFMain::setGlobalCreatorFunc(nullptr); auto retFcl = pCompilerInterface->createFclTranslationCtx(*device, IGC::CodeType::oclC, IGC::CodeType::spirV); EXPECT_EQ(nullptr, retFcl); auto retIgc = pCompilerInterface->createIgcTranslationCtx(*device, IGC::CodeType::oclC, IGC::CodeType::spirV); EXPECT_EQ(nullptr, retIgc); OCLRT::MockCIFMain::setGlobalCreatorFunc(befFclMock); OCLRT::MockCIFMain::setGlobalCreatorFunc(befIgcMock); } TEST_F(CompilerInterfaceTest, GivenRequestForNewIgcTranslationCtxWhenDeviceCtxIsAlreadyAvailableThenUseItToReturnValidTranslationCtx) { auto device = this->pContext->getDevice(0); auto deviceCtx = CIF::RAII::UPtr(new MockCompilerDeviceCtx); this->pCompilerInterface->setIgcDeviceCtx(*device, deviceCtx.get()); auto ret = this->pCompilerInterface->createIgcTranslationCtx(*device, IGC::CodeType::spirV, IGC::CodeType::oclGenBin); EXPECT_NE(nullptr, ret.get()); EXPECT_EQ(deviceCtx->returned, ret.get()); } TEST_F(CompilerInterfaceTest, GivenSimultaneousRequestForNewIgcTranslationContextsWhenDeviceCtxIsNotAlreadyAvailableThenSynchronizeToCreateOnlyOneNewDeviceCtx) { auto device = this->pContext->getDevice(0); using ListenerT = LockListener; ListenerT listenerData{device}; this->pCompilerInterface->lockListenerData = &listenerData; this->pCompilerInterface->lockListener = ListenerT::Listener; auto ret = this->pCompilerInterface->createIgcTranslationCtx(*device, IGC::CodeType::spirV, IGC::CodeType::oclGenBin); EXPECT_NE(nullptr, ret.get()); ASSERT_EQ(1U, this->pCompilerInterface->getIgcDeviceContexts().size()); ASSERT_NE(this->pCompilerInterface->getIgcDeviceContexts().end(), this->pCompilerInterface->getIgcDeviceContexts().find(device)); EXPECT_NE(nullptr, listenerData.createdDeviceCtx); EXPECT_EQ(listenerData.createdDeviceCtx, this->pCompilerInterface->getIgcDeviceContexts()[device].get()); } TEST_F(CompilerInterfaceTest, GivenRequestForNewIgcTranslationCtxWhenCouldNotPopulatePlatformInfoThenReturnNullptr) { auto device = this->pContext->getDevice(0); auto prevDebugVars = getIgcDebugVars(); for (uint32_t i = 1; i < (1 << 3); ++i) { this->pCompilerInterface->getIgcDeviceContexts().clear(); auto debugVars = prevDebugVars; debugVars.failCreatePlatformInterface = (i & 1) != 0; debugVars.failCreateIgcFeWaInterface = (i & (1 << 2)) != 0; debugVars.failCreateGtSystemInfoInterface = (i & (1 << 1)) != 0; setIgcDebugVars(debugVars); auto ret = pCompilerInterface->createIgcTranslationCtx(*device, IGC::CodeType::spirV, IGC::CodeType::oclGenBin); EXPECT_EQ(nullptr, ret); } setIgcDebugVars(prevDebugVars); } TEST_F(CompilerInterfaceTest, givenNoDbgKeyForceUseDifferentPlatformWhenRequestForNewTranslationCtxThenUseDefaultPlatform) { auto device = this->pContext->getDevice(0); auto retIgc = pCompilerInterface->createIgcTranslationCtx(*device, IGC::CodeType::spirV, IGC::CodeType::oclGenBin); EXPECT_NE(nullptr, retIgc); IGC::IgcOclDeviceCtxTagOCL *devCtx = pCompilerInterface->peekIgcDeviceCtx(device); auto igcPlatform = devCtx->GetPlatformHandle(); auto igcSysInfo = devCtx->GetGTSystemInfoHandle(); EXPECT_EQ(device->getHardwareInfo().pPlatform->eProductFamily, igcPlatform->GetProductFamily()); EXPECT_EQ(device->getHardwareInfo().pPlatform->eRenderCoreFamily, igcPlatform->GetRenderCoreFamily()); EXPECT_EQ(device->getHardwareInfo().pSysInfo->SliceCount, igcSysInfo->GetSliceCount()); EXPECT_EQ(device->getHardwareInfo().pSysInfo->SubSliceCount, igcSysInfo->GetSubSliceCount()); EXPECT_EQ(device->getHardwareInfo().pSysInfo->EUCount, igcSysInfo->GetEUCount()); EXPECT_EQ(device->getHardwareInfo().pSysInfo->ThreadCount, igcSysInfo->GetThreadCount()); } TEST_F(CompilerInterfaceTest, givenDbgKeyForceUseDifferentPlatformWhenRequestForNewTranslationCtxThenUseDbgKeyPlatform) { DebugManagerStateRestore dbgRestore; auto dbgProdFamily = DEFAULT_TEST_PLATFORM::hwInfo.pPlatform->eProductFamily; std::string dbgPlatformString(hardwarePrefix[dbgProdFamily]); const PLATFORM dbgPlatform = *hardwareInfoTable[dbgProdFamily]->pPlatform; const GT_SYSTEM_INFO dbgSystemInfo = *hardwareInfoTable[dbgProdFamily]->pSysInfo; DebugManager.flags.ForceCompilerUsePlatform.set(dbgPlatformString); auto device = this->pContext->getDevice(0); auto retIgc = pCompilerInterface->createIgcTranslationCtx(*device, IGC::CodeType::spirV, IGC::CodeType::oclGenBin); EXPECT_NE(nullptr, retIgc); IGC::IgcOclDeviceCtxTagOCL *devCtx = pCompilerInterface->peekIgcDeviceCtx(device); auto igcPlatform = devCtx->GetPlatformHandle(); auto igcSysInfo = devCtx->GetGTSystemInfoHandle(); EXPECT_EQ(dbgPlatform.eProductFamily, igcPlatform->GetProductFamily()); EXPECT_EQ(dbgPlatform.eRenderCoreFamily, igcPlatform->GetRenderCoreFamily()); EXPECT_EQ(dbgSystemInfo.SliceCount, igcSysInfo->GetSliceCount()); EXPECT_EQ(dbgSystemInfo.SubSliceCount, igcSysInfo->GetSubSliceCount()); EXPECT_EQ(dbgSystemInfo.EUCount, igcSysInfo->GetEUCount()); EXPECT_EQ(dbgSystemInfo.ThreadCount, igcSysInfo->GetThreadCount()); } TEST_F(CompilerInterfaceTest, IsCompilerAvailable) { ASSERT_TRUE(this->pCompilerInterface->GetIgcMain() && this->pCompilerInterface->GetFclMain()); EXPECT_TRUE(this->pCompilerInterface->isCompilerAvailable()); auto befIgcImain = this->pCompilerInterface->GetIgcMain(); this->pCompilerInterface->SetIgcMain(nullptr); EXPECT_FALSE(this->pCompilerInterface->isCompilerAvailable()); this->pCompilerInterface->SetIgcMain(befIgcImain); auto befFclImain = this->pCompilerInterface->GetFclMain(); this->pCompilerInterface->SetFclMain(nullptr); EXPECT_FALSE(this->pCompilerInterface->isCompilerAvailable()); this->pCompilerInterface->SetFclMain(befIgcImain); this->pCompilerInterface->SetIgcMain(nullptr); this->pCompilerInterface->SetFclMain(nullptr); EXPECT_FALSE(this->pCompilerInterface->isCompilerAvailable()); this->pCompilerInterface->SetIgcMain(befIgcImain); this->pCompilerInterface->SetFclMain(befFclImain); } TEST_F(CompilerInterfaceTest, whenCompilerIsNotAvailableThenGetSipKernelBinaryFailsGracefully) { pCompilerInterface->GetIgcMain()->Release(); pCompilerInterface->SetIgcMain(nullptr); std::vector sipBinary; retVal = pCompilerInterface->getSipKernelBinary(SipKernelType::Csr, *this->pDevice, sipBinary); EXPECT_EQ(CL_COMPILER_NOT_AVAILABLE, retVal); EXPECT_EQ(0U, sipBinary.size()); } TEST_F(CompilerInterfaceTest, whenIgcTranslatorReturnsNullptrThenGetSipKernelBinaryFailsGracefully) { pCompilerInterface->failCreateIgcTranslationCtx = true; std::vector sipBinary; retVal = pCompilerInterface->getSipKernelBinary(SipKernelType::Csr, *this->pDevice, sipBinary); EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); EXPECT_EQ(0U, sipBinary.size()); } TEST_F(CompilerInterfaceTest, whenIgcTranslatorReturnsBuildErrorThenGetSipKernelBinaryFailsGracefully) { MockCompilerDebugVars igcDebugVars; igcDebugVars.forceBuildFailure = true; gEnvironment->igcPushDebugVars(igcDebugVars); std::vector sipBinary; retVal = pCompilerInterface->getSipKernelBinary(SipKernelType::Csr, *this->pDevice, sipBinary); EXPECT_EQ(CL_BUILD_PROGRAM_FAILURE, retVal); EXPECT_EQ(0U, sipBinary.size()); gEnvironment->igcPopDebugVars(); } TEST_F(CompilerInterfaceTest, whenEverythingIsOkThenGetSipKernelReturnsIgcsOutputAsSipBinary) { MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = clFiles + "copybuffer.ll"; gEnvironment->igcPushDebugVars(igcDebugVars); std::vector sipBinary; retVal = pCompilerInterface->getSipKernelBinary(SipKernelType::Csr, *this->pDevice, sipBinary); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(0U, sipBinary.size()); gEnvironment->igcPopDebugVars(); } TEST_F(CompilerInterfaceTest, whenRequestingSipKernelBinaryThenProperInternalOptionsAndSrcAreUsed) { std::string receivedInternalOptions; std::string receivedInput; MockCompilerDebugVars igcDebugVars; igcDebugVars.fileName = clFiles + "copybuffer.ll"; igcDebugVars.receivedInternalOptionsOutput = &receivedInternalOptions; igcDebugVars.receivedInput = &receivedInput; gEnvironment->igcPushDebugVars(igcDebugVars); std::vector sipBinary; retVal = pCompilerInterface->getSipKernelBinary(SipKernelType::Csr, *this->pDevice, sipBinary); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(0U, sipBinary.size()); EXPECT_EQ(0, strcmp(getSipKernelCompilerInternalOptions(SipKernelType::Csr), receivedInternalOptions.c_str())); std::string expectedInut = getSipLlSrc(*this->pDevice); EXPECT_EQ(0, strcmp(expectedInut.c_str(), receivedInput.c_str())); gEnvironment->igcPopDebugVars(); }