From 3a9a835692944fb9721e1d0638640f0851be4d68 Mon Sep 17 00:00:00 2001 From: Maciej Plewka Date: Tue, 11 Jul 2023 12:21:32 +0000 Subject: [PATCH] fix: encode options in elf file Resolves: NEO-8035 Signed-off-by: Maciej Plewka --- .../ocloc_fatbinary_tests.cpp | 69 ++++++++++++++++++- .../source/ocloc_fatbinary.cpp | 15 ++-- .../offline_compiler/source/ocloc_fatbinary.h | 4 +- .../source/offline_compiler.h | 4 ++ 4 files changed, 83 insertions(+), 9 deletions(-) diff --git a/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp b/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp index 6d6484d730..ec73ea9d78 100644 --- a/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp +++ b/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp @@ -1442,6 +1442,69 @@ TEST_F(OclocFatBinaryProductAcronymsTests, givenOpenRangeToFamilyWhenFatBinaryBu } } +TEST_F(OclocFatBinaryTest, givenSpirvInputWhenFatBinaryIsRequestedThenArchiveContainsOptions) { + const auto devices = prepareTwoDevices(&mockArgHelper); + if (devices.empty()) { + GTEST_SKIP(); + } + + char data[] = {1, 2, 3, 4, 5, 6, 7, 8}; + MockCompilerDebugVars igcDebugVars(gEnvironment->igcDebugVars); + igcDebugVars.binaryToReturn = data; + igcDebugVars.binaryToReturnSize = sizeof(data); + NEO::setIgcDebugVars(igcDebugVars); + + std::string dummyOptions = "-dummy-option "; + const std::vector args = { + "ocloc", + "-output", + outputArchiveName, + "-file", + spirvFilename, + "-output_no_suffix", + "-spirv_input", + "-options", + dummyOptions, + "-device", + devices}; + + mockArgHelper.getPrinterRef().setSuppressMessages(true); + const auto buildResult = buildFatBinary(args, &mockArgHelper); + ASSERT_EQ(OclocErrorCode::SUCCESS, buildResult); + ASSERT_EQ(1u, mockArgHelper.interceptedFiles.count(outputArchiveName)); + + const auto &rawArchive = mockArgHelper.interceptedFiles[outputArchiveName]; + const auto archiveBytes = ArrayRef::fromAny(rawArchive.data(), rawArchive.size()); + + std::string outErrReason{}; + std::string outWarning{}; + const auto decodedArchive = NEO::Ar::decodeAr(archiveBytes, outErrReason, outWarning); + + ASSERT_NE(nullptr, decodedArchive.magic); + ASSERT_TRUE(outErrReason.empty()); + ASSERT_TRUE(outWarning.empty()); + + const auto spirvFileIt = searchInArchiveByFilename(decodedArchive, archiveGenericIrName); + ASSERT_NE(decodedArchive.files.end(), spirvFileIt); + + const auto elf = Elf::decodeElf(spirvFileIt->fileData, outErrReason, outWarning); + ASSERT_NE(nullptr, elf.elfFileHeader); + ASSERT_TRUE(outErrReason.empty()); + ASSERT_TRUE(outWarning.empty()); + + const auto isOptionSection = [](const auto §ion) { + return section.header && section.header->type == Elf::SHT_OPENCL_OPTIONS; + }; + + const auto optionSectionIt = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(), isOptionSection); + ASSERT_NE(elf.sectionHeaders.end(), optionSectionIt); + + ASSERT_EQ(dummyOptions.size(), optionSectionIt->header->size); + const auto isSpirvDataEqualsInputFileData = std::memcmp(dummyOptions.data(), optionSectionIt->data.begin(), dummyOptions.size()) == 0; + EXPECT_TRUE(isSpirvDataEqualsInputFileData); + NEO::setIgcDebugVars(gEnvironment->igcDebugVars); +} + TEST_F(OclocFatBinaryTest, givenSpirvInputWhenFatBinaryIsRequestedThenArchiveContainsGenericIrFileWithSpirvContent) { const auto devices = prepareTwoDevices(&mockArgHelper); if (devices.empty()) { @@ -1688,11 +1751,12 @@ TEST_F(OclocFatBinaryTest, givenClInputFileWhenFatBinaryIsRequestedThenArchiveDo TEST_F(OclocFatBinaryTest, givenEmptyFileWhenAppendingGenericIrThenInvalidFileIsReturned) { Ar::ArEncoder ar; std::string emptyFile{"empty_file.spv"}; + std::string dummyOptions{"-cl-opt-disable "}; mockArgHelperFilesMap[emptyFile] = ""; mockArgHelper.shouldLoadDataFromFileReturnZeroSize = true; ::testing::internal::CaptureStdout(); - const auto errorCode{appendGenericIr(ar, emptyFile, &mockArgHelper)}; + const auto errorCode{appendGenericIr(ar, emptyFile, &mockArgHelper, dummyOptions)}; const auto output{::testing::internal::GetCapturedStdout()}; EXPECT_EQ(OclocErrorCode::INVALID_FILE, errorCode); @@ -1702,10 +1766,11 @@ TEST_F(OclocFatBinaryTest, givenEmptyFileWhenAppendingGenericIrThenInvalidFileIs TEST_F(OclocFatBinaryTest, givenInvalidIrFileWhenAppendingGenericIrThenInvalidFileIsReturned) { Ar::ArEncoder ar; std::string dummyFile{"dummy_file.spv"}; + std::string dummyOptions{"-cl-opt-disable "}; mockArgHelperFilesMap[dummyFile] = "This is not IR!"; ::testing::internal::CaptureStdout(); - const auto errorCode{appendGenericIr(ar, dummyFile, &mockArgHelper)}; + const auto errorCode{appendGenericIr(ar, dummyFile, &mockArgHelper, dummyOptions)}; const auto output{::testing::internal::GetCapturedStdout()}; EXPECT_EQ(OclocErrorCode::INVALID_FILE, errorCode); diff --git a/shared/offline_compiler/source/ocloc_fatbinary.cpp b/shared/offline_compiler/source/ocloc_fatbinary.cpp index 9b409d5bd5..98a1c0e60d 100644 --- a/shared/offline_compiler/source/ocloc_fatbinary.cpp +++ b/shared/offline_compiler/source/ocloc_fatbinary.cpp @@ -357,7 +357,7 @@ int buildFatBinary(const std::vector &args, OclocArgHelper *argHelp argHelper->printf("Warning! -device_options set for non-compiled device: %s\n", deviceAcronym.c_str()); } } - + std::string optionsForIr; for (const auto &product : targetProducts) { int retVal = 0; argsCopy[deviceArgIndex] = product.str(); @@ -372,10 +372,13 @@ int buildFatBinary(const std::vector &args, OclocArgHelper *argHelp if (retVal) { return retVal; } + if (optionsForIr.empty()) { + optionsForIr = pCompiler->getOptions(); + } } if (shouldPreserveGenericIr) { - const auto errorCode = appendGenericIr(fatbinary, inputFileName, argHelper); + const auto errorCode = appendGenericIr(fatbinary, inputFileName, argHelper, optionsForIr); if (errorCode != OclocErrorCode::SUCCESS) { argHelper->printf("Error! Couldn't append generic IR file!\n"); return errorCode; @@ -395,7 +398,7 @@ int buildFatBinary(const std::vector &args, OclocArgHelper *argHelp return 0; } -int appendGenericIr(Ar::ArEncoder &fatbinary, const std::string &inputFile, OclocArgHelper *argHelper) { +int appendGenericIr(Ar::ArEncoder &fatbinary, const std::string &inputFile, OclocArgHelper *argHelper, std::string options) { std::size_t fileSize = 0; std::unique_ptr fileContents = argHelper->loadDataFromFile(inputFile, fileSize); if (fileSize == 0) { @@ -404,24 +407,26 @@ int appendGenericIr(Ar::ArEncoder &fatbinary, const std::string &inputFile, Oclo } const auto ir = ArrayRef::fromAny(fileContents.get(), fileSize); + const auto opt = ArrayRef::fromAny(options.data(), options.size()); if (!isSpirVBitcode(ir)) { argHelper->printf("Error! Input file is not in supported generic IR format! " "Currently supported format is SPIR-V.\n"); return OclocErrorCode::INVALID_FILE; } - const auto encodedElf = createEncodedElfWithSpirv(ir); + const auto encodedElf = createEncodedElfWithSpirv(ir, opt); ArrayRef genericIrFile{encodedElf.data(), encodedElf.size()}; fatbinary.appendFileEntry("generic_ir", genericIrFile); return OclocErrorCode::SUCCESS; } -std::vector createEncodedElfWithSpirv(const ArrayRef &spirv) { +std::vector createEncodedElfWithSpirv(const ArrayRef &spirv, const ArrayRef &options) { using namespace NEO::Elf; ElfEncoder elfEncoder; elfEncoder.getElfFileHeader().type = ET_OPENCL_OBJECTS; elfEncoder.appendSection(SHT_OPENCL_SPIRV, SectionNamesOpenCl::spirvObject, spirv); + elfEncoder.appendSection(SHT_OPENCL_OPTIONS, SectionNamesOpenCl::buildOptions, options); return elfEncoder.encode(); } diff --git a/shared/offline_compiler/source/ocloc_fatbinary.h b/shared/offline_compiler/source/ocloc_fatbinary.h index 21941a0ff6..05a153e941 100644 --- a/shared/offline_compiler/source/ocloc_fatbinary.h +++ b/shared/offline_compiler/source/ocloc_fatbinary.h @@ -37,7 +37,7 @@ std::vector getProductsForRange(unsigned int productFrom, u std::vector getTargetProductsForFatbinary(ConstStringRef deviceArg, OclocArgHelper *argHelper); int buildFatBinaryForTarget(int retVal, const std::vector &argsCopy, std::string pointerSize, Ar::ArEncoder &fatbinary, OfflineCompiler *pCompiler, OclocArgHelper *argHelper, const std::string &deviceConfig); -int appendGenericIr(Ar::ArEncoder &fatbinary, const std::string &inputFile, OclocArgHelper *argHelper); -std::vector createEncodedElfWithSpirv(const ArrayRef &spirv); +int appendGenericIr(Ar::ArEncoder &fatbinary, const std::string &inputFile, OclocArgHelper *argHelper, std::string options); +std::vector createEncodedElfWithSpirv(const ArrayRef &spirv, const ArrayRef &options); } // namespace NEO diff --git a/shared/offline_compiler/source/offline_compiler.h b/shared/offline_compiler/source/offline_compiler.h index c0a9ab28a2..57f6baf4f2 100644 --- a/shared/offline_compiler/source/offline_compiler.h +++ b/shared/offline_compiler/source/offline_compiler.h @@ -97,6 +97,10 @@ All supported acronyms: %s. } bool showHelpOnly() const { return showHelp; } + std::string getOptions() { + return options; + } + protected: OfflineCompiler();