feat(zebin): add support for build options section

This change:
* Adds support for build options section in zebinary - using
build options in binary when rebuilding.
* Appends "-cl-intel-allow-zebin" flag to build options when zebin is
used.

Resolves: NEO-6916

Signed-off-by: Krystian Chmielewski <krystian.chmielewski@intel.com>
This commit is contained in:
Krystian Chmielewski
2022-04-25 12:12:15 +00:00
committed by Compute-Runtime-Automation
parent 0d82216f43
commit e007ba499f
10 changed files with 159 additions and 15 deletions

View File

@@ -8,6 +8,7 @@
#include "shared/source/device_binary_format/device_binary_formats.h"
#include "shared/source/device_binary_format/elf/elf.h"
#include "shared/source/device_binary_format/elf/zebin_elf.h"
#include "shared/source/helpers/ptr_math.h"
#include "shared/source/helpers/string.h"
#include "shared/source/program/program_info.h"
#include "shared/test/common/test_macros/test.h"
@@ -54,7 +55,7 @@ TEST(UnpackSingleDeviceBinaryZebin, WhenUnhandledElfTypeThenUnpackingFails) {
EXPECT_TRUE(unpackResult.intermediateRepresentation.empty());
EXPECT_TRUE(unpackResult.buildOptions.empty());
EXPECT_TRUE(unpackWarnings.empty());
EXPECT_STREQ("Unhandled elf type", unpackErrors.c_str());
EXPECT_STREQ("Unhandled elf type\n", unpackErrors.c_str());
}
TEST(UnpackSingleDeviceBinaryZebin, WhenValidBinaryAndMatchedWithRequestedTargetDeviceThenReturnSelf) {
@@ -125,7 +126,8 @@ TEST(UnpackSingleDeviceBinaryZebin, WhenValidBinaryForDifferentDeviceThenUnpacki
EXPECT_TRUE(unpackResult.buildOptions.empty());
EXPECT_TRUE(unpackWarnings.empty());
EXPECT_FALSE(unpackErrors.empty());
EXPECT_STREQ("Unhandled target device", unpackErrors.c_str());
EXPECT_STREQ("Unhandled target device\n", unpackErrors.c_str());
unpackErrors.clear();
zebin.machine = static_cast<decltype(zebin.machine)>(IGFX_GEN9_CORE);
NEO::Elf::ZebinTargetFlags targetFlags;
@@ -144,7 +146,7 @@ TEST(UnpackSingleDeviceBinaryZebin, WhenValidBinaryForDifferentDeviceThenUnpacki
EXPECT_TRUE(unpackResult.buildOptions.empty());
EXPECT_TRUE(unpackWarnings.empty());
EXPECT_FALSE(unpackErrors.empty());
EXPECT_STREQ("Unhandled target device", unpackErrors.c_str());
EXPECT_STREQ("Unhandled target device\n", unpackErrors.c_str());
}
TEST(UnpackSingleDeviceBinaryZebin, WhenValidBinaryWithUnsupportedPointerSizeThenUnpackingFails) {
@@ -169,7 +171,7 @@ TEST(UnpackSingleDeviceBinaryZebin, WhenValidBinaryWithUnsupportedPointerSizeThe
EXPECT_TRUE(unpackResult.buildOptions.empty());
EXPECT_TRUE(unpackWarnings.empty());
EXPECT_FALSE(unpackErrors.empty());
EXPECT_STREQ("Unhandled target device", unpackErrors.c_str());
EXPECT_STREQ("Unhandled target device\n", unpackErrors.c_str());
}
TEST(UnpackSingleDeviceBinaryZebin, WhenNotRequestedThenDontValidateDeviceRevision) {
@@ -245,7 +247,8 @@ TEST(UnpackSingleDeviceBinaryZebin, WhenRequestedThenValidateRevision) {
EXPECT_TRUE(unpackResult.buildOptions.empty());
EXPECT_TRUE(unpackWarnings.empty());
EXPECT_FALSE(unpackErrors.empty());
EXPECT_STREQ("Unhandled target device", unpackErrors.c_str());
EXPECT_STREQ("Unhandled target device\n", unpackErrors.c_str());
unpackErrors.clear();
targetDevice.stepping = 8U;
unpackResult = NEO::unpackSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ArrayRef<const uint8_t>::fromAny(&zebin, 1U), "", targetDevice, unpackErrors, unpackWarnings);
@@ -259,9 +262,9 @@ TEST(UnpackSingleDeviceBinaryZebin, WhenRequestedThenValidateRevision) {
EXPECT_TRUE(unpackResult.buildOptions.empty());
EXPECT_TRUE(unpackWarnings.empty());
EXPECT_FALSE(unpackErrors.empty());
EXPECT_STREQ("Unhandled target device", unpackErrors.c_str());
EXPECT_STREQ("Unhandled target device\n", unpackErrors.c_str());
unpackErrors.clear();
targetDevice.stepping = 5U;
unpackResult = NEO::unpackSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ArrayRef<const uint8_t>::fromAny(&zebin, 1U), "", targetDevice, unpackErrors, unpackWarnings);
EXPECT_EQ(NEO::DeviceBinaryFormat::Zebin, unpackResult.format);
@@ -359,11 +362,52 @@ TEST(UnpackSingleDeviceBinaryZebin, WhenMachineIsIntelGTAndIntelGTNoteSectionIsV
EXPECT_TRUE(unpackErrors.empty());
}
TEST(UnpackSingleDeviceBinaryZebin, WhenZebinIsNotValidForTargetAndHasSPIRVThenSetIRAndBuildOptions) {
TEST(UnpackSingleDeviceBinaryZebin, GivenZebinWithSpirvAndBuildOptionsThenUnpackThemProperly) {
ZebinTestData::ValidEmptyProgram zebin;
const uint8_t spirvData[30] = {0xd};
zebin.appendSection(NEO::Elf::SHT_ZEBIN_SPIRV, NEO::Elf::SectionsNamesZebin::spv, spirvData);
NEO::ConstStringRef buildOptions = "-cl-kernel-arg-info -cl-fast-relaxed-math";
zebin.appendSection(NEO::Elf::SHT_ZEBIN_MISC, NEO::Elf::SectionsNamesZebin::buildOptions,
{reinterpret_cast<const uint8_t *>(buildOptions.data()), buildOptions.size()});
auto elfHdrs = reinterpret_cast<NEO::Elf::ElfSectionHeader<NEO::Elf::EI_CLASS_64> *>(
ptrOffset(zebin.storage.data(), static_cast<size_t>(zebin.elfHeader->shOff)));
auto spirvHdr = elfHdrs[3];
auto buildOptionsHdr = elfHdrs[4];
ASSERT_EQ(NEO::Elf::SHT_ZEBIN_SPIRV, spirvHdr.type);
ASSERT_EQ(NEO::Elf::SHT_ZEBIN_MISC, buildOptionsHdr.type);
zebin.elfHeader->type = NEO::Elf::ET_ZEBIN_EXE;
zebin.elfHeader->machine = IGFX_SKYLAKE;
NEO::TargetDevice targetDevice = {};
targetDevice.productFamily = static_cast<PRODUCT_FAMILY>(zebin.elfHeader->machine);
targetDevice.maxPointerSizeInBytes = 8;
std::string unpackErrors;
std::string unpackWarnings;
auto unpackResult = NEO::unpackSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(zebin.storage, "", targetDevice, unpackErrors, unpackWarnings);
EXPECT_EQ(NEO::DeviceBinaryFormat::Zebin, unpackResult.format);
EXPECT_TRUE(unpackErrors.empty()) << unpackErrors;
EXPECT_TRUE(unpackWarnings.empty()) << unpackWarnings;
EXPECT_FALSE(unpackResult.deviceBinary.empty());
EXPECT_EQ(zebin.storage.data(), unpackResult.deviceBinary.begin());
EXPECT_FALSE(unpackResult.buildOptions.empty());
auto buildOptionsPtr = reinterpret_cast<const char *>(ptrOffset(zebin.storage.data(), static_cast<size_t>(buildOptionsHdr.offset)));
EXPECT_EQ(buildOptionsPtr, unpackResult.buildOptions.begin());
EXPECT_FALSE(unpackResult.intermediateRepresentation.empty());
auto spirvPtr = ptrOffset(zebin.storage.data(), static_cast<size_t>(spirvHdr.offset));
EXPECT_EQ(spirvPtr, unpackResult.intermediateRepresentation.begin());
}
TEST(UnpackSingleDeviceBinaryZebin, GivenZebinForDifferentTargetDeviceWithIntermediateRepresentationThenDeviceBinaryIsEmptyIrIsSetAndWarningAboutRebuildIsReturned) {
ZebinTestData::ValidEmptyProgram zebin;
const uint8_t spirvData[30] = {0xd};
auto spirvHdr = zebin.appendSection(NEO::Elf::SHT_ZEBIN_SPIRV, NEO::Elf::SectionsNamesZebin::spv, spirvData);
zebin.elfHeader->type = NEO::Elf::ET_ZEBIN_EXE;
zebin.elfHeader->machine = IGFX_UNKNOWN;
@@ -375,9 +419,34 @@ TEST(UnpackSingleDeviceBinaryZebin, WhenZebinIsNotValidForTargetAndHasSPIRVThenS
std::string unpackWarnings;
auto unpackResult = NEO::unpackSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(zebin.storage, "", targetDevice, unpackErrors, unpackWarnings);
EXPECT_EQ(NEO::DeviceBinaryFormat::Zebin, unpackResult.format);
EXPECT_TRUE(unpackErrors.empty()) << unpackErrors;
EXPECT_STREQ("Invalid target device. Rebuilding from intermediate representation.\n", unpackWarnings.c_str());
EXPECT_TRUE(unpackResult.deviceBinary.empty());
EXPECT_FALSE(unpackResult.intermediateRepresentation.empty());
EXPECT_EQ(0, memcmp(spirvData, unpackResult.intermediateRepresentation.begin(), sizeof(spirvData)));
EXPECT_STREQ(NEO::CompilerOptions::allowZebin.begin(), unpackResult.buildOptions.begin());
auto spirvPtr = ptrOffset(zebin.storage.data(), static_cast<size_t>(spirvHdr.offset));
EXPECT_EQ(spirvPtr, unpackResult.intermediateRepresentation.begin());
}
TEST(UnpackSingleDeviceBinaryZebin, GivenMiscZebinSectionWithNameDifferentThanBuildOptionsThenItIsIgnored) {
ZebinTestData::ValidEmptyProgram zebin;
uint8_t secData;
zebin.appendSection(NEO::Elf::SHT_ZEBIN_MISC, "not_build_options", ArrayRef<uint8_t>{&secData, 1U});
zebin.elfHeader->type = NEO::Elf::ET_ZEBIN_EXE;
zebin.elfHeader->machine = IGFX_SKYLAKE;
NEO::TargetDevice targetDevice = {};
targetDevice.productFamily = static_cast<PRODUCT_FAMILY>(zebin.elfHeader->machine);
targetDevice.maxPointerSizeInBytes = 8;
std::string unpackErrors;
std::string unpackWarnings;
auto unpackResult = NEO::unpackSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(zebin.storage, "", targetDevice, unpackErrors, unpackWarnings);
EXPECT_EQ(NEO::DeviceBinaryFormat::Zebin, unpackResult.format);
EXPECT_TRUE(unpackErrors.empty()) << unpackErrors;
EXPECT_TRUE(unpackWarnings.empty()) << unpackWarnings;
EXPECT_FALSE(unpackResult.deviceBinary.empty());
EXPECT_EQ(zebin.storage.data(), unpackResult.deviceBinary.begin());
}

View File

@@ -93,6 +93,7 @@ TEST(ExtractZebinSections, GivenKnownSectionsThenCapturesThemProperly) {
elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_SPIRV, NEO::Elf::SectionsNamesZebin::spv, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_GTPIN_INFO, NEO::Elf::SectionsNamesZebin::gtpinInfo, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_VISA_ASM, NEO::Elf::SectionsNamesZebin::vIsaAsmPrefix.str() + "someKernel", std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_MISC, NEO::Elf::SectionsNamesZebin::buildOptions, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_REL, NEO::Elf::SpecialSectionNames::relPrefix.str() + "someKernel", std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_RELA, NEO::Elf::SpecialSectionNames::relaPrefix.str() + "someKernel", std::string{});
@@ -117,6 +118,7 @@ TEST(ExtractZebinSections, GivenKnownSectionsThenCapturesThemProperly) {
ASSERT_EQ(1U, sections.zeInfoSections.size());
ASSERT_EQ(1U, sections.symtabSections.size());
ASSERT_EQ(1U, sections.spirvSections.size());
ASSERT_EQ(1U, sections.buildOptionsSection.size());
auto stringSection = decodedElf.sectionHeaders[decodedElf.elfFileHeader->shStrNdx];
const char *strings = stringSection.data.toArrayRef<const char>().begin();
@@ -153,6 +155,29 @@ TEST(ExtractZebinSections, GivenMispelledConstDataSectionThenAllowItButEmitError
EXPECT_STREQ(".data.global_const", strings + sections.constDataSections[0]->header->name);
}
TEST(ExtractZebinSections, GivenUnknownMiscSectionThenEmitWarning) {
NEO::Elf::ElfEncoder<> elfEncoder;
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::textPrefix.str() + "someKernel", std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_SYMTAB, NEO::Elf::SectionsNamesZebin::symtab, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo, std::string{});
ConstStringRef unknownMiscSectionName = "unknown_misc_section";
elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_MISC, unknownMiscSectionName, std::string{});
auto encodedElf = elfEncoder.encode();
std::string elfDecodeErrors;
std::string elfDecodeWarnings;
auto decodedElf = NEO::Elf::decodeElf(encodedElf, elfDecodeErrors, elfDecodeWarnings);
NEO::ZebinSections sections;
std::string errors;
std::string warnings;
auto decodeError = NEO::extractZebinSections(decodedElf, sections, errors, warnings);
EXPECT_EQ(NEO::DecodeError::Success, decodeError);
EXPECT_TRUE(errors.empty()) << errors;
const auto expectedWarning = "DeviceBinaryFormat::Zebin : unhandled SHT_ZEBIN_MISC section : " + unknownMiscSectionName.str() + " currently supports only : " + NEO::Elf::SectionsNamesZebin::buildOptions.str() + ".\n";
EXPECT_STREQ(expectedWarning.c_str(), warnings.c_str());
}
TEST(ValidateZebinSectionsCount, GivenEmptyZebinThenReturnSuccess) {
NEO::ZebinSections sections;
std::string errors;