From b2a51146a5208cc7b913a3e4019801d5f1b686cd Mon Sep 17 00:00:00 2001 From: Krystian Chmielewski Date: Wed, 14 Dec 2022 09:46:25 +0000 Subject: [PATCH] feat(zebin): support data const/global buffer arg Add support for kernel payload arguments describing data const and data global buffers in zeInfo. Argument contains: * Offset in cross thread data where buffer's address should be written to. To be removed later. Relocations should be used instead. * Index in binding table where corresponding Surface State should be present. Required for bindful access to data buffers. Signed-off-by: Krystian Chmielewski --- .../device_binary_format/elf/zebin_elf.h | 15 +++- .../elf/zeinfo_enum_lookup.h | 6 +- .../device_binary_format/zebin_decoder.cpp | 37 ++++++++- .../zebin_decoder_tests.cpp | 82 ++++++++++++++++++- 4 files changed, 133 insertions(+), 7 deletions(-) diff --git a/shared/source/device_binary_format/elf/zebin_elf.h b/shared/source/device_binary_format/elf/zebin_elf.h index 4f92a3f120..0671095933 100644 --- a/shared/source/device_binary_format/elf/zebin_elf.h +++ b/shared/source/device_binary_format/elf/zebin_elf.h @@ -201,6 +201,7 @@ inline constexpr ConstStringRef filterMode("sampler_desc_filtermode"); inline constexpr ConstStringRef normalized("sampler_desc_normalized"); inline constexpr ConstStringRef isPipe("is_pipe"); inline constexpr ConstStringRef isPtr("is_ptr"); +inline constexpr ConstStringRef btiValue("bti_value"); namespace ArgType { inline constexpr ConstStringRef localSize("local_size"); @@ -218,6 +219,8 @@ inline constexpr ConstStringRef workDimensions("work_dimensions"); inline constexpr ConstStringRef implicitArgBuffer("implicit_arg_buffer"); inline constexpr ConstStringRef syncBuffer("sync_buffer"); inline constexpr ConstStringRef rtGlobalBuffer("rt_global_buffer"); +inline constexpr ConstStringRef dataConstBuffer("const_base"); +inline constexpr ConstStringRef dataGlobalBuffer("global_base"); namespace Image { inline constexpr ConstStringRef width("image_width"); @@ -579,6 +582,8 @@ enum ArgType : uint8_t { ArgTypeVmeSearchPathType, ArgTypeSyncBuffer, ArgTypeRtGlobalBuffer, + ArgTypeDataConstBuffer, + ArgTypeDataGlobalBuffer, ArgTypeMax }; @@ -667,7 +672,7 @@ enum SamplerType : uint8_t { }; using ArgTypeT = ArgType; -using OffseT = int32_t; +using OffsetT = int32_t; using SourceOffseT = int32_t; using SizeT = int32_t; using ArgIndexT = int32_t; @@ -676,28 +681,32 @@ using AddrspaceT = AddressSpace; using AccessTypeT = AccessType; using SlmAlignmentT = uint8_t; using SamplerIndexT = int32_t; +using BtiValueT = int32_t; namespace Defaults { inline constexpr ArgIndexT argIndex = -1; inline constexpr SlmAlignmentT slmArgAlignment = 16U; inline constexpr SamplerIndexT samplerIndex = -1; inline constexpr SourceOffseT sourceOffset = -1; +inline constexpr OffsetT offset = -1; +inline constexpr BtiValueT btiValue = -1; } // namespace Defaults struct PayloadArgumentBaseT { ArgTypeT argType = ArgTypeUnknown; - OffseT offset = 0; + OffsetT offset = Defaults::offset; SourceOffseT sourceOffset = Defaults::sourceOffset; SizeT size = 0; ArgIndexT argIndex = Defaults::argIndex; + BtiValueT btiValue = Defaults::btiValue; AddrmodeT addrmode = MemoryAddressingModeUnknown; AddrspaceT addrspace = AddressSpaceUnknown; AccessTypeT accessType = AccessTypeUnknown; SamplerIndexT samplerIndex = Defaults::samplerIndex; SlmAlignmentT slmArgAlignment = Defaults::slmArgAlignment; ImageType imageType = ImageTypeUnknown; - bool imageTransformable = false; SamplerType samplerType = SamplerTypeUnknown; + bool imageTransformable = false; bool isPipe = false; bool isPtr = false; }; diff --git a/shared/source/device_binary_format/elf/zeinfo_enum_lookup.h b/shared/source/device_binary_format/elf/zeinfo_enum_lookup.h index e0f7b64314..9c1af3b03d 100644 --- a/shared/source/device_binary_format/elf/zeinfo_enum_lookup.h +++ b/shared/source/device_binary_format/elf/zeinfo_enum_lookup.h @@ -22,7 +22,7 @@ using namespace Tags::Kernel::PayloadArgument::ArgType::Sampler::Vme; using ArgType = Types::Kernel::ArgType; inline constexpr ConstStringRef name = "argument type"; -inline constexpr LookupArray lookup({{{packedLocalIds, ArgType::ArgTypePackedLocalIds}, +inline constexpr LookupArray lookup({{{packedLocalIds, ArgType::ArgTypePackedLocalIds}, {localId, ArgType::ArgTypeLocalId}, {localSize, ArgType::ArgTypeLocalSize}, {groupCount, ArgType::ArgTypeGroupCount}, @@ -57,7 +57,9 @@ inline constexpr LookupArray lookup({{{packedLocalI {sadAdjustMode, ArgType::ArgTypeVmeSadAdjustMode}, {searchPathType, ArgType::ArgTypeVmeSearchPathType}, {syncBuffer, ArgType::ArgTypeSyncBuffer}, - {rtGlobalBuffer, ArgType::ArgTypeRtGlobalBuffer}}}); + {rtGlobalBuffer, ArgType::ArgTypeRtGlobalBuffer}, + {dataConstBuffer, ArgType::ArgTypeDataConstBuffer}, + {dataGlobalBuffer, ArgType::ArgTypeDataGlobalBuffer}}}); static_assert(lookup.size() == ArgType::ArgTypeMax - 1, "Every enum field must be present"); } // namespace ArgType diff --git a/shared/source/device_binary_format/zebin_decoder.cpp b/shared/source/device_binary_format/zebin_decoder.cpp index 39b2e39cb7..daacf99eeb 100644 --- a/shared/source/device_binary_format/zebin_decoder.cpp +++ b/shared/source/device_binary_format/zebin_decoder.cpp @@ -593,6 +593,8 @@ DecodeError readZeInfoPayloadArguments(const NEO::Yaml::YamlParser &parser, cons validPayload &= readZeInfoValueChecked(parser, payloadArgumentMemberNd, payloadArgMetadata.isPipe, context, outErrReason); } else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::isPtr == key) { validPayload &= readZeInfoValueChecked(parser, payloadArgumentMemberNd, payloadArgMetadata.isPtr, context, outErrReason); + } else if (NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::btiValue == key) { + validPayload &= readZeInfoValueChecked(parser, payloadArgumentMemberNd, payloadArgMetadata.btiValue, context, outErrReason); } else { outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + key.str() + "\" for payload argument in context of " + context.str() + "\n"); } @@ -720,6 +722,15 @@ bool setVecArgIndicesBasedOnSize(CrossThreadDataOffset (&vec)[Len], size_t vecSi return true; } +bool setSSHOffsetBasedOnBti(SurfaceStateHeapOffset &offset, Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::BtiValueT bti) { + if (bti < 0) { + return false; + } + constexpr auto surfaceStateSize = 64U; + offset = surfaceStateSize * bti; + return true; +} + NEO::DecodeError populateArgDescriptor(const NEO::Elf::ZebinKernelMetadata::Types::Kernel::PerThreadPayloadArgument::PerThreadPayloadArgumentBaseT &src, NEO::KernelDescriptor &dst, uint32_t grfSize, std::string &outErrReason, std::string &outWarning) { switch (src.argType) { @@ -791,7 +802,9 @@ NEO::DecodeError populateArgDescriptor(const NEO::Elf::ZebinKernelMetadata::Type NEO::DecodeError populateArgDescriptor(const NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::PayloadArgumentBaseT &src, NEO::KernelDescriptor &dst, uint32_t &crossThreadDataSize, std::string &outErrReason, std::string &outWarning) { - crossThreadDataSize = std::max(crossThreadDataSize, src.offset + src.size); + if (src.offset != Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::Defaults::offset) { + crossThreadDataSize = std::max(crossThreadDataSize, src.offset + src.size); + } auto &explicitArgs = dst.payloadMappings.explicitArgs; auto getVmeDescriptor = [&src, &dst]() { @@ -1104,6 +1117,28 @@ NEO::DecodeError populateArgDescriptor(const NEO::Elf::ZebinKernelMetadata::Type dst.payloadMappings.implicitArgs.rtDispatchGlobals.stateless = src.offset; dst.kernelAttributes.flags.hasRTCalls = true; break; + + case NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeDataConstBuffer: { + if (src.offset != Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::Defaults::offset) { + dst.payloadMappings.implicitArgs.globalConstantsSurfaceAddress.stateless = src.offset; + dst.payloadMappings.implicitArgs.globalConstantsSurfaceAddress.pointerSize = src.size; + } + if (false == setSSHOffsetBasedOnBti(dst.payloadMappings.implicitArgs.globalConstantsSurfaceAddress.bindful, src.btiValue)) { + outErrReason.append("DeviceBinaryFormat::Zebin : Invalid bti for argument of type " + NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::ArgType::dataConstBuffer.str() + " in context of : " + dst.kernelMetadata.kernelName + "\n"); + return DecodeError::InvalidBinary; + } + } break; + + case NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeDataGlobalBuffer: { + if (src.offset != Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::Defaults::offset) { + dst.payloadMappings.implicitArgs.globalVariablesSurfaceAddress.stateless = src.offset; + dst.payloadMappings.implicitArgs.globalVariablesSurfaceAddress.pointerSize = src.size; + } + if (false == setSSHOffsetBasedOnBti(dst.payloadMappings.implicitArgs.globalVariablesSurfaceAddress.bindful, src.btiValue)) { + outErrReason.append("DeviceBinaryFormat::Zebin : Invalid bti for argument of type " + NEO::Elf::ZebinKernelMetadata::Tags::Kernel::PayloadArgument::ArgType::dataGlobalBuffer.str() + " in context of : " + dst.kernelMetadata.kernelName + "\n"); + return DecodeError::InvalidBinary; + } + } break; } return DecodeError::Success; diff --git a/shared/test/unit_test/device_binary_format/zebin_decoder_tests.cpp b/shared/test/unit_test/device_binary_format/zebin_decoder_tests.cpp index 02024ce376..6467051eaa 100644 --- a/shared/test/unit_test/device_binary_format/zebin_decoder_tests.cpp +++ b/shared/test/unit_test/device_binary_format/zebin_decoder_tests.cpp @@ -2181,6 +2181,10 @@ kernels: size : 4 arg_index : 2 is_ptr : true + - arg_type : const_base + offset : 32 + size : 8 + bti_value : 1 ... )==="; @@ -2200,7 +2204,7 @@ kernels: EXPECT_EQ(NEO::DecodeError::Success, err); EXPECT_TRUE(errors.empty()) << errors; EXPECT_TRUE(warnings.empty()) << warnings; - ASSERT_EQ(2U, args.size()); + ASSERT_EQ(3U, args.size()); EXPECT_EQ(NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeArgBypointer, args[0].argType); EXPECT_EQ(16, args[0].offset); @@ -2213,7 +2217,13 @@ kernels: EXPECT_EQ(NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeArgByvalue, args[1].argType); EXPECT_EQ(24, args[1].offset); EXPECT_EQ(4, args[1].size); + EXPECT_EQ(2, args[1].argIndex); EXPECT_TRUE(args[1].isPtr); + + EXPECT_EQ(NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeDataConstBuffer, args[2].argType); + EXPECT_EQ(32, args[2].offset); + EXPECT_EQ(8, args[2].size); + EXPECT_EQ(1, args[2].btiValue); } TEST(ReadZeInfoPayloadArguments, GivenUnknownEntryThenEmmitsWarning) { @@ -5648,6 +5658,76 @@ TEST(PopulateArgDescriptor, GivenValidArgOfTypeRTGlobalBufferThenRtGlobalBufferI EXPECT_TRUE(kernelDescriptor.kernelAttributes.flags.hasRTCalls); } +TEST(PopulateArgDescriptor, GivenValidConstDataBufferArgThenItIsPopulatedCorrectly) { + NEO::KernelDescriptor kernelDescriptor; + NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::PayloadArgumentBaseT dataConstBuffer; + dataConstBuffer.argType = NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeDataConstBuffer; + dataConstBuffer.size = 8; + dataConstBuffer.offset = 32; + dataConstBuffer.btiValue = 1; + + uint32_t crossThreadDataSize = 0U; + std::string errors, warnings; + auto err = NEO::populateArgDescriptor(dataConstBuffer, kernelDescriptor, crossThreadDataSize, errors, warnings); + EXPECT_EQ(NEO::DecodeError::Success, err); + EXPECT_TRUE(errors.empty()); + EXPECT_TRUE(warnings.empty()); + EXPECT_EQ(40U, crossThreadDataSize); + EXPECT_EQ(8U, kernelDescriptor.payloadMappings.implicitArgs.globalConstantsSurfaceAddress.pointerSize); + EXPECT_EQ(32U, kernelDescriptor.payloadMappings.implicitArgs.globalConstantsSurfaceAddress.stateless); + EXPECT_EQ(64U, kernelDescriptor.payloadMappings.implicitArgs.globalConstantsSurfaceAddress.bindful); +} + +TEST(PopulateArgDescriptor, GivenInvalidConstDataBufferArgThenErrorIsReturned) { + NEO::KernelDescriptor kernelDescriptor; + kernelDescriptor.kernelMetadata.kernelName = "kernel"; + NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::PayloadArgumentBaseT dataConstBuffer; + dataConstBuffer.argType = NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeDataConstBuffer; + dataConstBuffer.btiValue = -1; + + uint32_t crossThreadDataSize = 0U; + std::string errors, warnings; + auto err = NEO::populateArgDescriptor(dataConstBuffer, kernelDescriptor, crossThreadDataSize, errors, warnings); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, err); + EXPECT_TRUE(warnings.empty()); + EXPECT_STREQ("DeviceBinaryFormat::Zebin : Invalid bti for argument of type const_base in context of : kernel\n", errors.c_str()); +} + +TEST(PopulateArgDescriptor, GivenValidGlobalDataBufferArgThenItIsPopulatedCorrectly) { + NEO::KernelDescriptor kernelDescriptor; + NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::PayloadArgumentBaseT dataGlobalBuffer; + dataGlobalBuffer.argType = NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeDataGlobalBuffer; + dataGlobalBuffer.size = 8; + dataGlobalBuffer.offset = 32; + dataGlobalBuffer.btiValue = 1; + + uint32_t crossThreadDataSize = 0U; + std::string errors, warnings; + auto err = NEO::populateArgDescriptor(dataGlobalBuffer, kernelDescriptor, crossThreadDataSize, errors, warnings); + EXPECT_EQ(NEO::DecodeError::Success, err); + EXPECT_TRUE(errors.empty()); + EXPECT_TRUE(warnings.empty()); + EXPECT_EQ(40U, crossThreadDataSize); + EXPECT_EQ(8U, kernelDescriptor.payloadMappings.implicitArgs.globalVariablesSurfaceAddress.pointerSize); + EXPECT_EQ(32U, kernelDescriptor.payloadMappings.implicitArgs.globalVariablesSurfaceAddress.stateless); + EXPECT_EQ(64U, kernelDescriptor.payloadMappings.implicitArgs.globalVariablesSurfaceAddress.bindful); +} + +TEST(PopulateArgDescriptor, GivenInvalidGlobalDataBufferArgThenErrorIsReturned) { + NEO::KernelDescriptor kernelDescriptor; + kernelDescriptor.kernelMetadata.kernelName = "kernel"; + NEO::Elf::ZebinKernelMetadata::Types::Kernel::PayloadArgument::PayloadArgumentBaseT dataGlobalBuffer; + dataGlobalBuffer.argType = NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypeDataGlobalBuffer; + dataGlobalBuffer.btiValue = -1; + + uint32_t crossThreadDataSize = 0U; + std::string errors, warnings; + auto err = NEO::populateArgDescriptor(dataGlobalBuffer, kernelDescriptor, crossThreadDataSize, errors, warnings); + EXPECT_EQ(NEO::DecodeError::InvalidBinary, err); + EXPECT_TRUE(warnings.empty()); + EXPECT_STREQ("DeviceBinaryFormat::Zebin : Invalid bti for argument of type global_base in context of : kernel\n", errors.c_str()); +} + TEST(PopulateArgDescriptorCrossthreadPayload, GivenArgTypePrintfBufferWhenOffsetAndSizeIsValidThenPopulatesKernelDescriptor) { NEO::ConstStringRef zeinfo = R"===( kernels: