diff --git a/level_zero/core/source/module/module_imp.cpp b/level_zero/core/source/module/module_imp.cpp index fbd08b1f39..bbe58aebcc 100644 --- a/level_zero/core/source/module/module_imp.cpp +++ b/level_zero/core/source/module/module_imp.cpp @@ -51,6 +51,8 @@ NEO::ConstStringRef greaterThan4GbRequired = "-ze-opt-greater-than-4GB-buffer-re NEO::ConstStringRef hasBufferOffsetArg = "-ze-intel-has-buffer-offset-arg"; NEO::ConstStringRef debugKernelEnable = "-ze-kernel-debug-enable"; NEO::ConstStringRef profileFlags = "-zet-profile-flags"; +NEO::ConstStringRef enableLibraryCompile = "-library-compilation"; +NEO::ConstStringRef enableGlobalVariableSymbols = "-ze-take-global-address"; } // namespace BuildOptions ModuleTranslationUnit::ModuleTranslationUnit(L0::Device *device) @@ -172,6 +174,70 @@ bool ModuleTranslationUnit::processSpecConstantInfo(NEO::CompilerInterface *comp return true; } +bool ModuleTranslationUnit::attemptGenBinaryCompile(NEO::TranslationInput inputArgs, bool staticLink, bool libraryExportRequired, bool globalExportRequired) { + auto result = this->compileGenBinary(inputArgs, staticLink); + std::string enableGlobalFlag(BuildOptions::enableGlobalVariableSymbols.str().c_str()); + std::string enableLibraryFlag(BuildOptions::enableLibraryCompile.str().c_str()); + bool completedGlobalFlagRemovalCheck = false; + bool completedLibraryFlagRemovalCheck = false; + if (result == false) { + if (!globalExportRequired || !libraryExportRequired) { + // If the build failed, attempt to remove the implicit flags for Global Variables and/or Library Compile + std::string reducedOptions(options); + // Attempt build with only removing the Global Variable Flag + if (!globalExportRequired) { + std::string globalFlagRemoved(options); + size_t optionPos = std::string::npos; + optionPos = reducedOptions.find(enableGlobalFlag.c_str()); + if (optionPos != std::string::npos) { + reducedOptions.erase(optionPos, BuildOptions::enableGlobalVariableSymbols.length()); + } + optionPos = globalFlagRemoved.find(enableGlobalFlag.c_str()); + if (optionPos != std::string::npos) { + globalFlagRemoved.erase(optionPos, BuildOptions::enableGlobalVariableSymbols.length()); + inputArgs.apiOptions = ArrayRef(globalFlagRemoved.c_str(), globalFlagRemoved.length()); + result = this->compileGenBinary(inputArgs, staticLink); + if (result == true) { + options.assign(globalFlagRemoved); + return result; + } + } + completedGlobalFlagRemovalCheck = true; + } + // Attempt build with only removing the Library Export Symbol Flag + if (!libraryExportRequired) { + std::string libraryFlagRemoved(options); + size_t optionPos = std::string::npos; + optionPos = reducedOptions.find(enableLibraryFlag.c_str()); + if (optionPos != std::string::npos) { + reducedOptions.erase(optionPos, BuildOptions::enableLibraryCompile.length()); + } + optionPos = libraryFlagRemoved.find(enableLibraryFlag.c_str()); + if (optionPos != std::string::npos) { + libraryFlagRemoved.erase(optionPos, BuildOptions::enableLibraryCompile.length()); + inputArgs.apiOptions = ArrayRef(libraryFlagRemoved.c_str(), libraryFlagRemoved.length()); + result = this->compileGenBinary(inputArgs, staticLink); + if (result == true) { + options.assign(libraryFlagRemoved); + return result; + } + } + completedLibraryFlagRemovalCheck = true; + } + // Attempt build with the removal of both library and Global Variable flags + if (completedGlobalFlagRemovalCheck && completedLibraryFlagRemovalCheck) { + inputArgs.apiOptions = ArrayRef(reducedOptions.c_str(), reducedOptions.length()); + result = this->compileGenBinary(inputArgs, staticLink); + if (result == true) { + options.assign(reducedOptions); + return result; + } + } + } + } + return result; +} + bool ModuleTranslationUnit::compileGenBinary(NEO::TranslationInput inputArgs, bool staticLink) { auto compilerInterface = device->getNEODevice()->getCompilerInterface(); UNRECOVERABLE_IF(nullptr == compilerInterface); @@ -205,7 +271,7 @@ bool ModuleTranslationUnit::compileGenBinary(NEO::TranslationInput inputArgs, bo } bool ModuleTranslationUnit::staticLinkSpirV(std::vector inputSpirVs, std::vector inputModuleSizes, const char *buildOptions, const char *internalBuildOptions, - std::vector specConstants) { + std::vector specConstants, bool libraryExportRequired, bool globalExportRequired) { auto compilerInterface = device->getNEODevice()->getCompilerInterface(); UNRECOVERABLE_IF(nullptr == compilerInterface); @@ -225,11 +291,11 @@ bool ModuleTranslationUnit::staticLinkSpirV(std::vector inputSpirV linkInputArgs.src = ArrayRef(reinterpret_cast(spirvElfSource.data()), spirvElfSource.size()); linkInputArgs.apiOptions = ArrayRef(options.c_str(), options.length()); linkInputArgs.internalOptions = ArrayRef(internalOptions.c_str(), internalOptions.length()); - return this->compileGenBinary(linkInputArgs, true); + return this->attemptGenBinaryCompile(linkInputArgs, true, libraryExportRequired, globalExportRequired); } bool ModuleTranslationUnit::buildFromSpirV(const char *input, uint32_t inputSize, const char *buildOptions, const char *internalBuildOptions, - const ze_module_constants_t *pConstants) { + const ze_module_constants_t *pConstants, bool libraryExportRequired, bool globalExportRequired) { auto compilerInterface = device->getNEODevice()->getCompilerInterface(); UNRECOVERABLE_IF(nullptr == compilerInterface); @@ -244,10 +310,10 @@ bool ModuleTranslationUnit::buildFromSpirV(const char *input, uint32_t inputSize inputArgs.src = ArrayRef(input, inputSize); inputArgs.apiOptions = ArrayRef(options.c_str(), options.length()); inputArgs.internalOptions = ArrayRef(internalOptions.c_str(), internalOptions.length()); - return this->compileGenBinary(inputArgs, false); + return this->attemptGenBinaryCompile(inputArgs, false, libraryExportRequired, globalExportRequired); } -bool ModuleTranslationUnit::createFromNativeBinary(const char *input, size_t inputSize) { +bool ModuleTranslationUnit::createFromNativeBinary(const char *input, size_t inputSize, bool libraryExportRequired, bool globalExportRequired) { UNRECOVERABLE_IF((nullptr == device) || (nullptr == device->getNEODevice())); auto productAbbreviation = NEO::hardwarePrefix[device->getNEODevice()->getHardwareInfo().platform.eProductFamily]; @@ -300,7 +366,7 @@ bool ModuleTranslationUnit::createFromNativeBinary(const char *input, size_t inp updateBuildLog(NEO::CompilerWarnings::recompiledFromIr.str()); } - return buildFromSpirV(this->irBinary.get(), static_cast(this->irBinarySize), this->options.c_str(), "", nullptr); + return buildFromSpirV(this->irBinary.get(), static_cast(this->irBinarySize), this->options.c_str(), "", nullptr, libraryExportRequired, globalExportRequired); } else { return processUnpackedBinary(); } @@ -508,13 +574,17 @@ bool ModuleImp::initialize(const ze_module_desc_t *desc, NEO::Device *neoDevice) inputModuleSizes, buildOptions.c_str(), internalBuildOptions.c_str(), - specConstants); + specConstants, + this->libraryExportRequired, + this->globalExportRequired); } else { success = this->translationUnit->buildFromSpirV(reinterpret_cast(programExpDesc->pInputModules[0]), inputModuleSizes[0], buildOptions.c_str(), internalBuildOptions.c_str(), - firstSpecConstants); + firstSpecConstants, + this->libraryExportRequired, + this->globalExportRequired); } } else { return false; @@ -530,14 +600,16 @@ bool ModuleImp::initialize(const ze_module_desc_t *desc, NEO::Device *neoDevice) if (desc->format == ZE_MODULE_FORMAT_NATIVE) { success = this->translationUnit->createFromNativeBinary( - reinterpret_cast(desc->pInputModule), desc->inputSize); + reinterpret_cast(desc->pInputModule), desc->inputSize, this->libraryExportRequired, this->globalExportRequired); } else if (desc->format == ZE_MODULE_FORMAT_IL_SPIRV) { this->builtFromSPIRv = true; success = this->translationUnit->buildFromSpirV(reinterpret_cast(desc->pInputModule), static_cast(desc->inputSize), buildOptions.c_str(), internalBuildOptions.c_str(), - desc->pConstants); + desc->pConstants, + this->libraryExportRequired, + this->globalExportRequired); } else { return false; } @@ -680,14 +752,21 @@ void ModuleImp::createBuildOptions(const char *pBuildFlags, std::string &apiOpti moveBuildOption(apiOptions, apiOptions, NEO::CompilerOptions::optDisable, BuildOptions::optDisable); moveBuildOption(internalBuildOptions, apiOptions, NEO::CompilerOptions::greaterThan4gbBuffersRequired, BuildOptions::greaterThan4GbRequired); moveBuildOption(internalBuildOptions, apiOptions, NEO::CompilerOptions::allowZebin, NEO::CompilerOptions::allowZebin); - moveOptLevelOption(apiOptions, apiOptions); moveProfileFlagsOption(apiOptions, apiOptions); + this->libraryExportRequired = moveBuildOption(apiOptions, apiOptions, BuildOptions::enableLibraryCompile, BuildOptions::enableLibraryCompile); + this->globalExportRequired = moveBuildOption(apiOptions, apiOptions, BuildOptions::enableGlobalVariableSymbols, BuildOptions::enableGlobalVariableSymbols); createBuildExtraOptions(apiOptions, internalBuildOptions); } if (NEO::ApiSpecificConfig::getBindlessConfiguration()) { NEO::CompilerOptions::concatenateAppend(internalBuildOptions, NEO::CompilerOptions::bindlessMode.str()); } + if (!this->libraryExportRequired && NEO::DebugManager.flags.EnableProgramSymbolTableGeneration.get()) { + NEO::CompilerOptions::concatenateAppend(apiOptions, BuildOptions::enableLibraryCompile.str()); + } + if (!this->globalExportRequired && NEO::DebugManager.flags.EnableGlobalSymbolGeneration.get()) { + NEO::CompilerOptions::concatenateAppend(apiOptions, BuildOptions::enableGlobalVariableSymbols.str()); + } } bool ModuleImp::moveOptLevelOption(std::string &dstOptionsSet, std::string &srcOptionSet) { diff --git a/level_zero/core/source/module/module_imp.h b/level_zero/core/source/module/module_imp.h index 1d9229a23e..3f230111bd 100644 --- a/level_zero/core/source/module/module_imp.h +++ b/level_zero/core/source/module/module_imp.h @@ -33,21 +33,24 @@ extern NEO::ConstStringRef greaterThan4GbRequired; extern NEO::ConstStringRef hasBufferOffsetArg; extern NEO::ConstStringRef debugKernelEnable; extern NEO::ConstStringRef profileFlags; +extern NEO::ConstStringRef enableLibraryCompile; +extern NEO::ConstStringRef enableGlobalVariableSymbols; } // namespace BuildOptions struct ModuleTranslationUnit { ModuleTranslationUnit(L0::Device *device); virtual ~ModuleTranslationUnit(); MOCKABLE_VIRTUAL bool buildFromSpirV(const char *input, uint32_t inputSize, const char *buildOptions, const char *internalBuildOptions, - const ze_module_constants_t *pConstants); + const ze_module_constants_t *pConstants, bool libraryExportRequired, bool globalExportRequired); MOCKABLE_VIRTUAL bool staticLinkSpirV(std::vector inputSpirVs, std::vector inputModuleSizes, const char *buildOptions, const char *internalBuildOptions, - std::vector specConstants); - MOCKABLE_VIRTUAL bool createFromNativeBinary(const char *input, size_t inputSize); + std::vector specConstants, bool libraryExportRequired, bool globalExportRequired); + MOCKABLE_VIRTUAL bool createFromNativeBinary(const char *input, size_t inputSize, bool libraryExportRequired, bool globalExportRequired); MOCKABLE_VIRTUAL bool processUnpackedBinary(); std::vector generateElfFromSpirV(std::vector inputSpirVs, std::vector inputModuleSizes); bool processSpecConstantInfo(NEO::CompilerInterface *compilerInterface, const ze_module_constants_t *pConstants, const char *input, uint32_t inputSize); std::string generateCompilerOptions(const char *buildOptions, const char *internalBuildOptions); MOCKABLE_VIRTUAL bool compileGenBinary(NEO::TranslationInput inputArgs, bool staticLink); + MOCKABLE_VIRTUAL bool attemptGenBinaryCompile(NEO::TranslationInput inputArgs, bool staticLink, bool libraryExportRequired, bool globalExportRequired); void updateBuildLog(const std::string &newLogEntry); void processDebugData(); L0::Device *device = nullptr; @@ -171,6 +174,8 @@ struct ModuleImp : public Module { bool isFullyLinked = false; bool allocatePrivateMemoryPerDispatch = true; bool isZebinBinary = false; + bool libraryExportRequired = false; + bool globalExportRequired = false; ModuleType type; NEO::Linker::UnresolvedExternals unresolvedExternalsInfo{}; std::set importedSymbolAllocations{}; diff --git a/level_zero/core/test/unit_tests/mocks/mock_module.h b/level_zero/core/test/unit_tests/mocks/mock_module.h index af3f3832d6..39d9862796 100644 --- a/level_zero/core/test/unit_tests/mocks/mock_module.h +++ b/level_zero/core/test/unit_tests/mocks/mock_module.h @@ -66,12 +66,36 @@ struct MockModuleTranslationUnit : public L0::ModuleTranslationUnit { } bool compileGenBinary(NEO::TranslationInput inputArgs, bool staticLink) override { + if (failGenCompile || failGenCompileCounter > 0) { + failGenCompileCounter = failGenCompileCounter - 1; + return false; + } if (unpackedDeviceBinarySize && unpackedDeviceBinary) { return true; } else { return ModuleTranslationUnit::compileGenBinary(inputArgs, staticLink); } } + + bool attemptGenBinaryCompile(NEO::TranslationInput inputArgs, bool staticLink, bool libraryExportRequired, bool globalExportRequired) override { + bool libraryExport = libraryExportRequired; + bool globalExport = globalExportRequired; + if (requireGlobalExport) { + globalExport = true; + } + if (requireLibraryExport) { + libraryExport = true; + } + if (unpackedDeviceBinarySize && unpackedDeviceBinary) { + return true; + } else { + return ModuleTranslationUnit::attemptGenBinaryCompile(inputArgs, staticLink, libraryExport, globalExport); + } + } + bool failGenCompile = false; + bool requireGlobalExport = false; + bool requireLibraryExport = false; + int failGenCompileCounter = 0; }; struct MockModule : public L0::ModuleImp { diff --git a/level_zero/core/test/unit_tests/sources/module/test_module.cpp b/level_zero/core/test/unit_tests/sources/module/test_module.cpp index 0e8e9dc606..863a9a0f23 100644 --- a/level_zero/core/test/unit_tests/sources/module/test_module.cpp +++ b/level_zero/core/test/unit_tests/sources/module/test_module.cpp @@ -1006,6 +1006,244 @@ TEST_F(ModuleStaticLinkTests, givenSingleModuleProvidedForSpirVStaticLinkAndBuil runSprivLinkBuildWithOneModule(); } +using ModuleOptionsTests = Test; + +HWTEST_F(ModuleOptionsTests, givenFailureDuringGenCompileThenAttemptCompileFails) { + auto mockCompiler = new MockCompilerInterface(); + auto rootDeviceEnvironment = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get(); + rootDeviceEnvironment->compilerInterface.reset(mockCompiler); + + auto mockTranslationUnit = new MockModuleTranslationUnit(device); + mockTranslationUnit->failGenCompile = true; + + uint8_t spirvData{}; + + ze_module_desc_t moduleDesc = {}; + moduleDesc.format = ZE_MODULE_FORMAT_IL_SPIRV; + moduleDesc.pInputModule = &spirvData; + moduleDesc.inputSize = sizeof(spirvData); + + Module module(device, nullptr, ModuleType::User); + module.translationUnit.reset(mockTranslationUnit); + + bool success = module.initialize(&moduleDesc, neoDevice); + EXPECT_FALSE(success); +} + +HWTEST_F(ModuleOptionsTests, givenValidModuleWithGlobalSymbolFlagThenGenCompileAttemptSucceeds) { + auto mockCompiler = new MockCompilerInterface(); + auto rootDeviceEnvironment = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get(); + rootDeviceEnvironment->compilerInterface.reset(mockCompiler); + + auto mockTranslationUnit = new MockModuleTranslationUnit(device); + mockTranslationUnit->options.append(BuildOptions::enableGlobalVariableSymbols.str()); + mockTranslationUnit->requireGlobalExport = true; + uint8_t spirvData{}; + + ze_module_desc_t moduleDesc = {}; + moduleDesc.format = ZE_MODULE_FORMAT_IL_SPIRV; + moduleDesc.pInputModule = &spirvData; + moduleDesc.inputSize = sizeof(spirvData); + + Module module(device, nullptr, ModuleType::User); + module.translationUnit.reset(mockTranslationUnit); + + bool success = module.initialize(&moduleDesc, neoDevice); + EXPECT_TRUE(success); +} + +HWTEST_F(ModuleOptionsTests, givenModuleWithGlobalSymbolFlagThenGenCompileAttemptSucceedsAfterGlobalFlagRemoved) { + auto mockCompiler = new MockCompilerInterface(); + auto rootDeviceEnvironment = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get(); + rootDeviceEnvironment->compilerInterface.reset(mockCompiler); + + auto mockTranslationUnit = new MockModuleTranslationUnit(device); + mockTranslationUnit->options.append(BuildOptions::enableGlobalVariableSymbols.str()); + mockTranslationUnit->requireGlobalExport = false; + mockTranslationUnit->failGenCompileCounter = 1; + uint8_t spirvData{}; + + ze_module_desc_t moduleDesc = {}; + moduleDesc.format = ZE_MODULE_FORMAT_IL_SPIRV; + moduleDesc.pInputModule = &spirvData; + moduleDesc.inputSize = sizeof(spirvData); + + Module module(device, nullptr, ModuleType::User); + module.translationUnit.reset(mockTranslationUnit); + + bool success = module.initialize(&moduleDesc, neoDevice); + EXPECT_TRUE(success); + + size_t optionPos = std::string::npos; + optionPos = mockTranslationUnit->options.find(BuildOptions::enableGlobalVariableSymbols.str().c_str()); + EXPECT_EQ(optionPos, std::string::npos); +} + +HWTEST_F(ModuleOptionsTests, givenModuleWithGlobalSymbolFlagRequiredThenGenCompileAttemptFails) { + auto mockCompiler = new MockCompilerInterface(); + auto rootDeviceEnvironment = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get(); + rootDeviceEnvironment->compilerInterface.reset(mockCompiler); + + auto mockTranslationUnit = new MockModuleTranslationUnit(device); + mockTranslationUnit->options.append(BuildOptions::enableGlobalVariableSymbols.str()); + mockTranslationUnit->requireGlobalExport = true; + mockTranslationUnit->failGenCompile = true; + uint8_t spirvData{}; + + ze_module_desc_t moduleDesc = {}; + moduleDesc.format = ZE_MODULE_FORMAT_IL_SPIRV; + moduleDesc.pInputModule = &spirvData; + moduleDesc.inputSize = sizeof(spirvData); + + Module module(device, nullptr, ModuleType::User); + module.translationUnit.reset(mockTranslationUnit); + + bool success = module.initialize(&moduleDesc, neoDevice); + EXPECT_FALSE(success); + + size_t optionPos = std::string::npos; + optionPos = mockTranslationUnit->options.find(BuildOptions::enableGlobalVariableSymbols.str().c_str()); + EXPECT_NE(optionPos, std::string::npos); +} + +HWTEST_F(ModuleOptionsTests, givenValidModuleWithLibrarySymbolFlagThenGenCompileAttemptSucceeds) { + auto mockCompiler = new MockCompilerInterface(); + auto rootDeviceEnvironment = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get(); + rootDeviceEnvironment->compilerInterface.reset(mockCompiler); + + auto mockTranslationUnit = new MockModuleTranslationUnit(device); + mockTranslationUnit->options.append(BuildOptions::enableLibraryCompile.str()); + mockTranslationUnit->requireLibraryExport = true; + uint8_t spirvData{}; + + ze_module_desc_t moduleDesc = {}; + moduleDesc.format = ZE_MODULE_FORMAT_IL_SPIRV; + moduleDesc.pInputModule = &spirvData; + moduleDesc.inputSize = sizeof(spirvData); + + Module module(device, nullptr, ModuleType::User); + module.translationUnit.reset(mockTranslationUnit); + + bool success = module.initialize(&moduleDesc, neoDevice); + EXPECT_TRUE(success); +} + +HWTEST_F(ModuleOptionsTests, givenModuleWithLibrarySymbolFlagThenGenCompileAttemptSucceedsAfterLibraryFlagRemoved) { + auto mockCompiler = new MockCompilerInterface(); + auto rootDeviceEnvironment = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get(); + rootDeviceEnvironment->compilerInterface.reset(mockCompiler); + + auto mockTranslationUnit = new MockModuleTranslationUnit(device); + mockTranslationUnit->options.append(BuildOptions::enableLibraryCompile.str().c_str()); + mockTranslationUnit->requireLibraryExport = false; + mockTranslationUnit->failGenCompileCounter = 2; + uint8_t spirvData{}; + + ze_module_desc_t moduleDesc = {}; + moduleDesc.format = ZE_MODULE_FORMAT_IL_SPIRV; + moduleDesc.pInputModule = &spirvData; + moduleDesc.inputSize = sizeof(spirvData); + + Module module(device, nullptr, ModuleType::User); + module.translationUnit.reset(mockTranslationUnit); + + bool success = module.initialize(&moduleDesc, neoDevice); + EXPECT_TRUE(success); + + size_t optionPos = std::string::npos; + optionPos = mockTranslationUnit->options.find(BuildOptions::enableLibraryCompile.str().c_str()); + EXPECT_EQ(optionPos, std::string::npos); +} + +HWTEST_F(ModuleOptionsTests, givenModuleWithLibrarySymbolFlagRequiredThenGenCompileAttemptFailsInRetry) { + auto mockCompiler = new MockCompilerInterface(); + auto rootDeviceEnvironment = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get(); + rootDeviceEnvironment->compilerInterface.reset(mockCompiler); + + auto mockTranslationUnit = new MockModuleTranslationUnit(device); + mockTranslationUnit->options.append(BuildOptions::enableLibraryCompile.str()); + mockTranslationUnit->requireLibraryExport = true; + mockTranslationUnit->failGenCompileCounter = 3; + uint8_t spirvData{}; + + ze_module_desc_t moduleDesc = {}; + moduleDesc.format = ZE_MODULE_FORMAT_IL_SPIRV; + moduleDesc.pInputModule = &spirvData; + moduleDesc.inputSize = sizeof(spirvData); + + Module module(device, nullptr, ModuleType::User); + module.translationUnit.reset(mockTranslationUnit); + + bool success = module.initialize(&moduleDesc, neoDevice); + EXPECT_FALSE(success); + + size_t optionPos = std::string::npos; + optionPos = mockTranslationUnit->options.find(BuildOptions::enableLibraryCompile.str().c_str()); + EXPECT_NE(optionPos, std::string::npos); +} + +HWTEST_F(ModuleOptionsTests, givenModuleWithLibraryAndGlobalSymbolFlagsRequiredThenGenCompileAttemptFailsInRetry) { + auto mockCompiler = new MockCompilerInterface(); + auto rootDeviceEnvironment = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get(); + rootDeviceEnvironment->compilerInterface.reset(mockCompiler); + + auto mockTranslationUnit = new MockModuleTranslationUnit(device); + mockTranslationUnit->options.append(BuildOptions::enableLibraryCompile.str()); + mockTranslationUnit->options.append(BuildOptions::enableGlobalVariableSymbols.str()); + mockTranslationUnit->requireGlobalExport = true; + mockTranslationUnit->requireLibraryExport = true; + mockTranslationUnit->failGenCompile = true; + uint8_t spirvData{}; + + ze_module_desc_t moduleDesc = {}; + moduleDesc.format = ZE_MODULE_FORMAT_IL_SPIRV; + moduleDesc.pInputModule = &spirvData; + moduleDesc.inputSize = sizeof(spirvData); + + Module module(device, nullptr, ModuleType::User); + module.translationUnit.reset(mockTranslationUnit); + + bool success = module.initialize(&moduleDesc, neoDevice); + EXPECT_FALSE(success); + + size_t optionPos = std::string::npos; + optionPos = mockTranslationUnit->options.find(BuildOptions::enableLibraryCompile.str().c_str()); + EXPECT_NE(optionPos, std::string::npos); + optionPos = mockTranslationUnit->options.find(BuildOptions::enableGlobalVariableSymbols.str().c_str()); + EXPECT_NE(optionPos, std::string::npos); +} + +HWTEST_F(ModuleOptionsTests, givenModuleWithLibraryAndGlobalSymbolFlagsAndGenCompileFailsInAllSingleRemovalThenGenCompileAttemptSuccedsInRetry) { + auto mockCompiler = new MockCompilerInterface(); + auto rootDeviceEnvironment = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get(); + rootDeviceEnvironment->compilerInterface.reset(mockCompiler); + + auto mockTranslationUnit = new MockModuleTranslationUnit(device); + mockTranslationUnit->options.append(BuildOptions::enableLibraryCompile.str()); + mockTranslationUnit->options.append(BuildOptions::enableGlobalVariableSymbols.str()); + mockTranslationUnit->requireGlobalExport = false; + mockTranslationUnit->requireLibraryExport = false; + mockTranslationUnit->failGenCompileCounter = 3; + uint8_t spirvData{}; + + ze_module_desc_t moduleDesc = {}; + moduleDesc.format = ZE_MODULE_FORMAT_IL_SPIRV; + moduleDesc.pInputModule = &spirvData; + moduleDesc.inputSize = sizeof(spirvData); + + Module module(device, nullptr, ModuleType::User); + module.translationUnit.reset(mockTranslationUnit); + + bool success = module.initialize(&moduleDesc, neoDevice); + EXPECT_TRUE(success); + + size_t optionPos = std::string::npos; + optionPos = mockTranslationUnit->options.find(BuildOptions::enableLibraryCompile.str().c_str()); + EXPECT_EQ(optionPos, std::string::npos); + optionPos = mockTranslationUnit->options.find(BuildOptions::enableGlobalVariableSymbols.str().c_str()); + EXPECT_EQ(optionPos, std::string::npos); +} + using ModuleLinkingTest = Test; HWTEST_F(ModuleLinkingTest, whenExternFunctionsAllocationIsPresentThenItsBeingAddedToResidencyContainer) { @@ -1959,14 +2197,14 @@ struct MockModuleTU : public L0::ModuleTranslationUnit { MockModuleTU(L0::Device *device) : L0::ModuleTranslationUnit(device) {} bool buildFromSpirV(const char *input, uint32_t inputSize, const char *buildOptions, const char *internalBuildOptions, - const ze_module_constants_t *pConstants) override { + const ze_module_constants_t *pConstants, bool libraryExportRequired, bool globalExportRequired) override { wasBuildFromSpirVCalled = true; return true; } - bool createFromNativeBinary(const char *input, size_t inputSize) override { + bool createFromNativeBinary(const char *input, size_t inputSize, bool libraryExportRequired, bool globalExportRequired) override { wasCreateFromNativeBinaryCalled = true; - return L0::ModuleTranslationUnit::createFromNativeBinary(input, inputSize); + return L0::ModuleTranslationUnit::createFromNativeBinary(input, inputSize, libraryExportRequired, globalExportRequired); } bool wasBuildFromSpirVCalled = false; @@ -2094,13 +2332,13 @@ HWTEST_F(ModuleTranslationUnitTest, WhenCreatingFromNativeBinaryThenSetsUpRequir emptyProgram.elfHeader->machine = copyHwInfo.platform.eProductFamily; L0::ModuleTranslationUnit moduleTuValid(this->device); - bool success = moduleTuValid.createFromNativeBinary(reinterpret_cast(emptyProgram.storage.data()), emptyProgram.storage.size()); + bool success = moduleTuValid.createFromNativeBinary(reinterpret_cast(emptyProgram.storage.data()), emptyProgram.storage.size(), false, false); EXPECT_TRUE(success); emptyProgram.elfHeader->machine = copyHwInfo.platform.eProductFamily; ++emptyProgram.elfHeader->machine; L0::ModuleTranslationUnit moduleTuInvalid(this->device); - success = moduleTuInvalid.createFromNativeBinary(reinterpret_cast(emptyProgram.storage.data()), emptyProgram.storage.size()); + success = moduleTuInvalid.createFromNativeBinary(reinterpret_cast(emptyProgram.storage.data()), emptyProgram.storage.size(), false, false); EXPECT_FALSE(success); } @@ -2130,7 +2368,7 @@ HWTEST_F(ModuleTranslationUnitTest, WhenCreatingFromNativeBinaryThenSetsUpPacked auto arData = encoder.encode(); L0::ModuleTranslationUnit moduleTuValid(this->device); - bool success = moduleTuValid.createFromNativeBinary(reinterpret_cast(arData.data()), arData.size()); + bool success = moduleTuValid.createFromNativeBinary(reinterpret_cast(arData.data()), arData.size(), false, false); EXPECT_TRUE(success); EXPECT_NE(moduleTuValid.packedDeviceBinarySize, arData.size()); } @@ -2143,7 +2381,7 @@ HWTEST_F(ModuleTranslationUnitTest, WhenCreatingFromZebinThenAppendAllowZebinFla zebin.elfHeader->machine = copyHwInfo.platform.eProductFamily; L0::ModuleTranslationUnit moduleTu(this->device); - bool success = moduleTu.createFromNativeBinary(reinterpret_cast(zebin.storage.data()), zebin.storage.size()); + bool success = moduleTu.createFromNativeBinary(reinterpret_cast(zebin.storage.data()), zebin.storage.size(), false, false); EXPECT_TRUE(success); auto expectedOptions = " " + NEO::CompilerOptions::allowZebin.str(); @@ -2172,7 +2410,7 @@ kernels: zebin.elfHeader->machine = copyHwInfo.platform.eProductFamily; L0::ModuleTranslationUnit moduleTuValid(this->device); - bool success = moduleTuValid.createFromNativeBinary(reinterpret_cast(zebin.storage.data()), zebin.storage.size()); + bool success = moduleTuValid.createFromNativeBinary(reinterpret_cast(zebin.storage.data()), zebin.storage.size(), false, false); EXPECT_TRUE(success); EXPECT_NE(nullptr, moduleTuValid.programInfo.linkerInput.get()); @@ -2231,7 +2469,7 @@ HWTEST_F(ModuleTranslationUnitTest, WhenBuildOptionsAreNullThenReuseExistingOpti moduleTu.options = "abcd"; pMockCompilerInterface->failBuild = true; - auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr); + auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr, false, false); EXPECT_FALSE(ret); EXPECT_STREQ("abcd", moduleTu.options.c_str()); EXPECT_STREQ("abcd", pMockCompilerInterface->receivedApiOptions.c_str()); @@ -2246,7 +2484,7 @@ HWTEST_F(ModuleTranslationUnitTest, WhenBuildOptionsAreNullThenReuseExistingOpti DebugManager.flags.DisableStatelessToStatefulOptimization.set(1); MockModuleTranslationUnit moduleTu(this->device); - auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr); + auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr, false, false); EXPECT_TRUE(ret); EXPECT_NE(pMockCompilerInterface->inputInternalOptions.find("cl-intel-greater-than-4GB-buffer-required"), std::string::npos); } @@ -2256,7 +2494,7 @@ HWTEST_F(ModuleTranslationUnitTest, givenInternalOptionsThenLSCCachePolicyIsSet) auto &rootDeviceEnvironment = this->neoDevice->executionEnvironment->rootDeviceEnvironments[this->neoDevice->getRootDeviceIndex()]; rootDeviceEnvironment->compilerInterface.reset(pMockCompilerInterface); MockModuleTranslationUnit moduleTu(this->device); - auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr); + auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr, false, false); const auto &compilerHwInfoConfig = *CompilerHwInfoConfig::get(defaultHwInfo->platform.eProductFamily); EXPECT_TRUE(ret); auto expectedPolicy = compilerHwInfoConfig.getCachingPolicyOptions(false); @@ -2275,7 +2513,7 @@ HWTEST2_F(ModuleTranslationUnitTest, givenDebugFlagSetToWbWhenGetInternalOptions auto &rootDeviceEnvironment = this->neoDevice->executionEnvironment->rootDeviceEnvironments[this->neoDevice->getRootDeviceIndex()]; rootDeviceEnvironment->compilerInterface.reset(pMockCompilerInterface); MockModuleTranslationUnit moduleTu(this->device); - auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr); + auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr, false, false); EXPECT_TRUE(ret); EXPECT_NE(pMockCompilerInterface->inputInternalOptions.find("-cl-store-cache-default=7 -cl-load-cache-default=4"), std::string::npos); } @@ -2288,7 +2526,7 @@ HWTEST2_F(ModuleTranslationUnitTest, givenDebugFlagSetForceAllResourcesUncachedW auto &rootDeviceEnvironment = this->neoDevice->executionEnvironment->rootDeviceEnvironments[this->neoDevice->getRootDeviceIndex()]; rootDeviceEnvironment->compilerInterface.reset(pMockCompilerInterface); MockModuleTranslationUnit moduleTu(this->device); - auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr); + auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr, false, false); EXPECT_TRUE(ret); EXPECT_NE(pMockCompilerInterface->inputInternalOptions.find("-cl-store-cache-default=1 -cl-load-cache-default=1"), std::string::npos); } @@ -2298,7 +2536,7 @@ HWTEST2_F(ModuleTranslationUnitTest, givenAtLeastXeHpgCoreWhenGetInternalOptions auto &rootDeviceEnvironment = this->neoDevice->executionEnvironment->rootDeviceEnvironments[this->neoDevice->getRootDeviceIndex()]; rootDeviceEnvironment->compilerInterface.reset(pMockCompilerInterface); MockModuleTranslationUnit moduleTu(this->device); - auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr); + auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr, false, false); EXPECT_TRUE(ret); EXPECT_NE(pMockCompilerInterface->inputInternalOptions.find("-cl-store-cache-default=2 -cl-load-cache-default=4"), std::string::npos); } @@ -2309,7 +2547,7 @@ HWTEST_F(ModuleTranslationUnitTest, givenForceToStatelessRequiredWhenBuildingMod rootDeviceEnvironment->compilerInterface.reset(mockCompilerInterface); MockModuleTranslationUnit moduleTu(device); - auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr); + auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr, false, false); EXPECT_TRUE(ret); const auto &compilerHwInfoConfig = *CompilerHwInfoConfig::get(defaultHwInfo->platform.eProductFamily); @@ -2408,6 +2646,117 @@ TEST(BuildOptions, givenSrcOptionNameInSrcNamesWhenMovingBuildOptionsThenOptionI EXPECT_EQ(std::string::npos, srcNames.find(NEO::CompilerOptions::optDisable.str())); } +TEST_F(ModuleTest, givenBuildOptionsWhenEnableProgramSymbolTableGenerationIsEnabledThenEnableLibraryCompileIsSet) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableProgramSymbolTableGeneration.set(1); + auto module = std::make_unique(device, nullptr, ModuleType::User); + ASSERT_NE(nullptr, module); + + std::string buildOptions; + std::string internalBuildOptions; + + module->createBuildOptions("", buildOptions, internalBuildOptions); + + EXPECT_TRUE(NEO::CompilerOptions::contains(buildOptions, BuildOptions::enableLibraryCompile)); +} + +TEST_F(ModuleTest, givenBuildOptionsWhenEnableProgramSymbolTableGenerationIsDisabledThenEnableLibraryCompileIsNotSet) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableProgramSymbolTableGeneration.set(0); + auto module = std::make_unique(device, nullptr, ModuleType::User); + ASSERT_NE(nullptr, module); + + std::string buildOptions; + std::string internalBuildOptions; + + module->createBuildOptions("", buildOptions, internalBuildOptions); + + EXPECT_FALSE(NEO::CompilerOptions::contains(buildOptions, BuildOptions::enableLibraryCompile)); +} + +TEST_F(ModuleTest, givenBuildOptionsWithEnableLibraryCompileWhenEnableProgramSymbolTableGenerationIsDisabledThenEnableLibraryCompileIsSet) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableProgramSymbolTableGeneration.set(0); + auto module = std::make_unique(device, nullptr, ModuleType::User); + ASSERT_NE(nullptr, module); + + std::string buildOptions; + std::string internalBuildOptions; + + module->createBuildOptions(BuildOptions::enableLibraryCompile.str().c_str(), buildOptions, internalBuildOptions); + + EXPECT_TRUE(NEO::CompilerOptions::contains(buildOptions, BuildOptions::enableLibraryCompile)); +} + +TEST_F(ModuleTest, givenBuildOptionsWithEnableLibraryCompileWhenEnableProgramSymbolTableGenerationIsEnabledThenEnableLibraryCompileIsSet) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableProgramSymbolTableGeneration.set(1); + auto module = std::make_unique(device, nullptr, ModuleType::User); + ASSERT_NE(nullptr, module); + + std::string buildOptions; + std::string internalBuildOptions; + + module->createBuildOptions(BuildOptions::enableLibraryCompile.str().c_str(), buildOptions, internalBuildOptions); + + EXPECT_TRUE(NEO::CompilerOptions::contains(buildOptions, BuildOptions::enableLibraryCompile)); +} + +TEST_F(ModuleTest, givenBuildOptionsWhenEnableGlobalSymbolGenerationIsEnabledThenEnableGlobalVariableSymbolsIsSet) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableGlobalSymbolGeneration.set(1); + auto module = std::make_unique(device, nullptr, ModuleType::User); + ASSERT_NE(nullptr, module); + + std::string buildOptions; + std::string internalBuildOptions; + + module->createBuildOptions("", buildOptions, internalBuildOptions); + + EXPECT_TRUE(NEO::CompilerOptions::contains(buildOptions, BuildOptions::enableGlobalVariableSymbols)); +} + +TEST_F(ModuleTest, givenBuildOptionsWhenEnableGlobalSymbolGenerationIsDisabledThenEnableGlobalVariableSymbolsIsNotSet) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableGlobalSymbolGeneration.set(0); + auto module = std::make_unique(device, nullptr, ModuleType::User); + ASSERT_NE(nullptr, module); + + std::string buildOptions; + std::string internalBuildOptions; + + module->createBuildOptions("", buildOptions, internalBuildOptions); + + EXPECT_FALSE(NEO::CompilerOptions::contains(buildOptions, BuildOptions::enableGlobalVariableSymbols)); +} + +TEST_F(ModuleTest, givenBuildOptionsWithEnableGlobalVariableSymbolsWhenEnableGlobalSymbolGenerationIsDisabledThenEnableGlobalVariableSymbolsIsSet) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableGlobalSymbolGeneration.set(0); + auto module = std::make_unique(device, nullptr, ModuleType::User); + ASSERT_NE(nullptr, module); + + std::string buildOptions; + std::string internalBuildOptions; + + module->createBuildOptions(BuildOptions::enableGlobalVariableSymbols.str().c_str(), buildOptions, internalBuildOptions); + + EXPECT_TRUE(NEO::CompilerOptions::contains(buildOptions, BuildOptions::enableGlobalVariableSymbols)); +} + +TEST_F(ModuleTest, givenBuildOptionsWithEnableGlobalVariableSymbolsWhenEnableGlobalSymbolGenerationIsEnabledThenEnableGlobalVariableSymbolsIsSet) { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableGlobalSymbolGeneration.set(1); + auto module = std::make_unique(device, nullptr, ModuleType::User); + ASSERT_NE(nullptr, module); + + std::string buildOptions; + std::string internalBuildOptions; + + module->createBuildOptions(BuildOptions::enableGlobalVariableSymbols.str().c_str(), buildOptions, internalBuildOptions); + + EXPECT_TRUE(NEO::CompilerOptions::contains(buildOptions, BuildOptions::enableGlobalVariableSymbols)); +} TEST_F(ModuleTest, givenInternalOptionsWhenBindlessEnabledThenBindlesOptionsPassed) { DebugManagerStateRestore restorer; DebugManager.flags.UseBindlessMode.set(1); @@ -2623,7 +2972,7 @@ TEST_F(ModuleInitializeTest, whenModuleInitializeIsCalledThenCorrectResultIsRetu class MyMockModuleTU : public MockModuleTU { public: using MockModuleTU::MockModuleTU; - bool createFromNativeBinary(const char *input, size_t inputSize) override { return true; } + bool createFromNativeBinary(const char *input, size_t inputSize, bool libraryExportRequired, bool globalExportRequired) override { return true; } }; const auto &compilerHwInfoConfig = *CompilerHwInfoConfig::get(defaultHwInfo->platform.eProductFamily); diff --git a/level_zero/core/test/unit_tests/xe_hpg_core/test_module_xe_hpg_core.cpp b/level_zero/core/test/unit_tests/xe_hpg_core/test_module_xe_hpg_core.cpp index 57417fa9fa..d98c30e19a 100644 --- a/level_zero/core/test/unit_tests/xe_hpg_core/test_module_xe_hpg_core.cpp +++ b/level_zero/core/test/unit_tests/xe_hpg_core/test_module_xe_hpg_core.cpp @@ -51,7 +51,7 @@ HWTEST2_F(KernelPropertyTest, givenDG2WhenGetInternalOptionsThenWriteByPassBuild auto &rootDeviceEnvironment = this->neoDevice->executionEnvironment->rootDeviceEnvironments[this->neoDevice->getRootDeviceIndex()]; rootDeviceEnvironment->compilerInterface.reset(pMockCompilerInterface); MockModuleTranslationUnit moduleTu(this->device); - auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr); + auto ret = moduleTu.buildFromSpirV("", 0U, nullptr, "", nullptr, false, false); EXPECT_TRUE(ret); EXPECT_NE(pMockCompilerInterface->inputInternalOptions.find("-cl-store-cache-default=2 -cl-load-cache-default=4"), std::string::npos); } diff --git a/shared/source/debug_settings/debug_variables_base.inl b/shared/source/debug_settings/debug_variables_base.inl index ceb8b93f0c..0cabc028f6 100644 --- a/shared/source/debug_settings/debug_variables_base.inl +++ b/shared/source/debug_settings/debug_variables_base.inl @@ -338,6 +338,8 @@ DECLARE_DEBUG_VARIABLE(bool, ForceSamplerLowFilteringPrecision, false, "Force Lo DECLARE_DEBUG_VARIABLE(bool, EngineInstancedSubDevices, false, "Create subdevices assigned to specific engine") DECLARE_DEBUG_VARIABLE(bool, AllowSingleTileEngineInstancedSubDevices, false, "Create subdevices assigned to specific engine on single tile config") DECLARE_DEBUG_VARIABLE(bool, EnablePrivateBO, false, "Enable PRELIM_I915_GEM_CREATE_EXT_VM_PRIVATE extension creating VM_PRIVATE BOs") +DECLARE_DEBUG_VARIABLE(bool, EnableProgramSymbolTableGeneration, true, "Enforce IGC to always generate the Program Symbol Table for Exported Functions for all Modules used by Level Zero.") +DECLARE_DEBUG_VARIABLE(bool, EnableGlobalSymbolGeneration, true, "Enforce IGC to always generate the Symbol Table Entry for Global Variables for all Modules used by Level Zero") DECLARE_DEBUG_VARIABLE(int32_t, ReturnSubDevicesAsApiDevices, -1, "Expose each subdevice as a separate device during clGetDeviceIDs or zeDeviceGet API call") DECLARE_DEBUG_VARIABLE(int32_t, ForceRunAloneContext, -1, "Control creation of run-alone HW context, -1:default, 0:disable, 1:enable") DECLARE_DEBUG_VARIABLE(int32_t, AddClGlSharing, -1, "Add cl-gl extension") diff --git a/shared/test/common/test_files/igdrcl.config b/shared/test/common/test_files/igdrcl.config index 0445d659e9..d96d460596 100644 --- a/shared/test/common/test_files/igdrcl.config +++ b/shared/test/common/test_files/igdrcl.config @@ -353,7 +353,9 @@ AllowPatchingVfeStateInCommandLists = 0 PrintMemoryRegionSizes = 0 OverrideDrmRegion = -1 AllowSingleTileEngineInstancedSubDevices = 0 +EnableProgramSymbolTableGeneration = 1 BinaryCacheTrace = false +EnableGlobalSymbolGeneration = 1 OverrideL1CacheControlInSurfaceState = -1 OverrideL1CacheControlInSurfaceStateForScratchSpace = -1 OverridePreferredSlmAllocationSizePerDss = -1