From 2892e5a7f9023266772bf3c6a3af154613abb987 Mon Sep 17 00:00:00 2001 From: Mateusz Jablonski Date: Mon, 27 Oct 2025 11:30:50 +0000 Subject: [PATCH] feature: add support for require_assert_buffer and require_sync_buffer in zeinfo Related-To: NEO-16544, IGC-11358 Signed-off-by: Mateusz Jablonski --- .../compiler_interface/external_functions.cpp | 4 ++ .../compiler_interface/external_functions.h | 2 + .../device_binary_format/zebin/zeinfo.h | 8 +++ .../zebin/zeinfo_decoder.cpp | 8 +++ .../zebin/zeinfo_decoder.h | 2 +- .../external_functions_tests.cpp | 67 ++++++++++++++++++- .../zebin_decoder_tests.cpp | 40 +++++++++++ 7 files changed, 127 insertions(+), 4 deletions(-) diff --git a/shared/source/compiler_interface/external_functions.cpp b/shared/source/compiler_interface/external_functions.cpp index 7b38306a73..37528dc66d 100644 --- a/shared/source/compiler_interface/external_functions.cpp +++ b/shared/source/compiler_interface/external_functions.cpp @@ -70,6 +70,8 @@ uint32_t resolveExtFuncDependencies(const ExternalFunctionInfosT &externalFuncti caller->hasRTCalls |= callee->hasRTCalls; caller->hasPrintfCalls |= callee->hasPrintfCalls; caller->hasIndirectCalls |= callee->hasIndirectCalls; + caller->requireAssertBuffer |= callee->requireAssertBuffer; + caller->requireSyncBuffer |= callee->requireSyncBuffer; } } return RESOLVE_SUCCESS; @@ -91,6 +93,8 @@ uint32_t resolveKernelDependencies(const ExternalFunctionInfosT &externalFunctio kernelAttributes.flags.hasRTCalls |= externalFunctionInfo.hasRTCalls; kernelAttributes.flags.hasPrintfCalls |= externalFunctionInfo.hasPrintfCalls; kernelAttributes.flags.hasIndirectCalls |= externalFunctionInfo.hasIndirectCalls; + kernelAttributes.flags.usesAssert |= externalFunctionInfo.requireAssertBuffer; + kernelAttributes.flags.usesSyncBuffer |= externalFunctionInfo.requireSyncBuffer; } return RESOLVE_SUCCESS; } diff --git a/shared/source/compiler_interface/external_functions.h b/shared/source/compiler_interface/external_functions.h index bb217101e3..8e5c3afb4a 100644 --- a/shared/source/compiler_interface/external_functions.h +++ b/shared/source/compiler_interface/external_functions.h @@ -30,6 +30,8 @@ struct ExternalFunctionInfo { bool hasRTCalls = false; bool hasPrintfCalls = false; bool hasIndirectCalls = false; + bool requireAssertBuffer = false; + bool requireSyncBuffer = false; }; struct ExternalFunctionUsageKernel { diff --git a/shared/source/device_binary_format/zebin/zeinfo.h b/shared/source/device_binary_format/zebin/zeinfo.h index f82ac4ea2d..7b33797420 100644 --- a/shared/source/device_binary_format/zebin/zeinfo.h +++ b/shared/source/device_binary_format/zebin/zeinfo.h @@ -68,6 +68,8 @@ inline constexpr ConstStringRef requireImplicitArgBuffer("require_iab"); inline constexpr ConstStringRef hasLscStoresWithNonDefaultL1CacheControls("has_lsc_stores_with_non_default_l1_cache_controls"); inline constexpr ConstStringRef hasPrintfCalls("has_printf_calls"); inline constexpr ConstStringRef hasIndirectCalls("has_indirect_calls"); +inline constexpr ConstStringRef requireAssertBuffer("require_assert_buffer"); +inline constexpr ConstStringRef requireSyncBuffer("require_sync_buffer"); namespace ThreadSchedulingMode { inline constexpr ConstStringRef ageBased("age_based"); @@ -368,6 +370,8 @@ using RequireImplicitArgBufferT = bool; using HasLscStoresWithNonDefaultL1CacheControlsT = bool; using HasPrintfCallsT = bool; using HasIndirectCallsT = bool; +using RequireAssertBufferT = bool; +using RequireSyncBufferT = bool; namespace Defaults { inline constexpr BarrierCountT barrierCount = 0; @@ -406,6 +410,8 @@ inline constexpr RequireImplicitArgBufferT requireImplicitArgBuffer = false; inline constexpr HasLscStoresWithNonDefaultL1CacheControlsT hasLscStoresWithNonDefaultL1CacheControls = false; inline constexpr HasPrintfCallsT hasPrintfCalls = false; inline constexpr HasIndirectCallsT hasIndirectCalls = false; +inline constexpr RequireAssertBufferT requireAssertBuffer = false; +inline constexpr RequireSyncBufferT requireSyncBuffer = false; } // namespace Defaults inline constexpr ConstStringRef required[] = { @@ -452,6 +458,8 @@ struct ExecutionEnvBaseT final : NEO::NonCopyableAndNonMovableClass { HasLscStoresWithNonDefaultL1CacheControlsT hasLscStoresWithNonDefaultL1CacheControls = Defaults::hasLscStoresWithNonDefaultL1CacheControls; HasPrintfCallsT hasPrintfCalls = Defaults::hasPrintfCalls; HasIndirectCallsT hasIndirectCalls = Defaults::hasIndirectCalls; + RequireAssertBufferT requireAssertBuffer = Defaults::requireAssertBuffer; + RequireSyncBufferT requireSyncBuffer = Defaults::requireSyncBuffer; }; static_assert(NEO::NonCopyableAndNonMovable); diff --git a/shared/source/device_binary_format/zebin/zeinfo_decoder.cpp b/shared/source/device_binary_format/zebin/zeinfo_decoder.cpp index 08f26f8990..f03feed103 100644 --- a/shared/source/device_binary_format/zebin/zeinfo_decoder.cpp +++ b/shared/source/device_binary_format/zebin/zeinfo_decoder.cpp @@ -306,6 +306,8 @@ DecodeError populateExternalFunctionsMetadata(NEO::ProgramInfo &dst, NEO::Yaml:: extFunInfo.hasRTCalls = execEnv.hasRTCalls; extFunInfo.hasPrintfCalls = execEnv.hasPrintfCalls; extFunInfo.hasIndirectCalls = execEnv.hasIndirectCalls; + extFunInfo.requireAssertBuffer = execEnv.requireAssertBuffer; + extFunInfo.requireSyncBuffer = execEnv.requireSyncBuffer; dst.externalFunctions.push_back(extFunInfo); } @@ -706,6 +708,10 @@ DecodeError readZeInfoExecutionEnvironment(const Yaml::YamlParser &parser, const validExecEnv &= readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.hasPrintfCalls, context, outErrReason); } else if (Tags::Kernel::ExecutionEnv::hasIndirectCalls == key) { validExecEnv &= readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.hasIndirectCalls, context, outErrReason); + } else if (Tags::Kernel::ExecutionEnv::requireAssertBuffer == key) { + validExecEnv &= readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.requireAssertBuffer, context, outErrReason); + } else if (Tags::Kernel::ExecutionEnv::requireSyncBuffer == key) { + validExecEnv &= readZeInfoValueChecked(parser, execEnvMetadataNd, outExecEnv.requireSyncBuffer, context, outErrReason); } else { readZeInfoValueCheckedExtra(parser, execEnvMetadataNd, outExecEnv, context, key, outErrReason, outWarning, validExecEnv, err); } @@ -739,6 +745,8 @@ void populateKernelExecutionEnvironment(KernelDescriptor &dst, const KernelExecu dst.kernelAttributes.flags.requiresImplicitArgs = execEnv.requireImplicitArgBuffer; dst.kernelAttributes.flags.hasIndirectCalls = execEnv.hasIndirectCalls; dst.kernelAttributes.flags.hasPrintfCalls = execEnv.hasPrintfCalls; + dst.kernelAttributes.flags.usesAssert = execEnv.requireAssertBuffer; + dst.kernelAttributes.flags.usesSyncBuffer = execEnv.requireSyncBuffer; dst.kernelAttributes.barrierCount = execEnv.barrierCount; dst.kernelAttributes.bufferAddressingMode = (execEnv.has4GBBuffers) ? KernelDescriptor::Stateless : KernelDescriptor::BindfulAndStateless; dst.kernelAttributes.inlineDataPayloadSize = static_cast(execEnv.inlineDataPayloadSize); diff --git a/shared/source/device_binary_format/zebin/zeinfo_decoder.h b/shared/source/device_binary_format/zebin/zeinfo_decoder.h index 74ff381084..7658626368 100644 --- a/shared/source/device_binary_format/zebin/zeinfo_decoder.h +++ b/shared/source/device_binary_format/zebin/zeinfo_decoder.h @@ -19,7 +19,7 @@ struct KernelInfo; struct ProgramInfo; namespace Zebin::ZeInfo { -inline constexpr NEO::Zebin::ZeInfo::Types::Version zeInfoDecoderVersion{1, 60}; +inline constexpr NEO::Zebin::ZeInfo::Types::Version zeInfoDecoderVersion{1, 61}; using KernelExecutionEnvBaseT = Types::Kernel::ExecutionEnv::ExecutionEnvBaseT; diff --git a/shared/test/unit_test/compiler_interface/external_functions_tests.cpp b/shared/test/unit_test/compiler_interface/external_functions_tests.cpp index 0b63795548..592c05fad7 100644 --- a/shared/test/unit_test/compiler_interface/external_functions_tests.cpp +++ b/shared/test/unit_test/compiler_interface/external_functions_tests.cpp @@ -84,11 +84,22 @@ struct ExternalFunctionsTests : public ::testing::Test { bool hasRTCalls; bool hasPrintfCalls; bool hasIndirectCalls; + bool requireAssertBuffer; + bool requireSyncBuffer; }; void addExternalFunction(const std::string &functionName, FunctionInfo functionInfo) { funcNameToId[functionName] = extFuncInfoStorage.size(); - extFuncInfoStorage.push_back(ExternalFunctionInfo{functionName, functionInfo.barrierCount, 128U, 8U, functionInfo.hasRTCalls, functionInfo.hasPrintfCalls, functionInfo.hasIndirectCalls}); + extFuncInfoStorage.push_back(ExternalFunctionInfo{ + .functionName = functionName, + .barrierCount = functionInfo.barrierCount, + .numGrfRequired = 128U, + .simdSize = 8U, + .hasRTCalls = functionInfo.hasRTCalls, + .hasPrintfCalls = functionInfo.hasPrintfCalls, + .hasIndirectCalls = functionInfo.hasIndirectCalls, + .requireAssertBuffer = functionInfo.requireAssertBuffer, + .requireSyncBuffer = functionInfo.requireSyncBuffer}); } void addKernel(const std::string &kernelName) { kernelDescriptorStorage.push_back(std::make_unique()); @@ -304,7 +315,7 @@ TEST_F(ExternalFunctionsTests, GivenValidFunctionAndKernelDependenciesWhenResolv EXPECT_TRUE(nameToKernelDescriptor["kernel2"]->kernelAttributes.flags.hasPrintfCalls); } -TEST_F(ExternalFunctionsTests, GivenValidFunctionAndKernelDependenciesWhenResolvingDependenciesThenSetAppropriateHasIndirectfCallsAndReturnSuccess) { +TEST_F(ExternalFunctionsTests, GivenValidFunctionAndKernelDependenciesWhenResolvingDependenciesThenSetAppropriateHasIndirectCallsAndReturnSuccess) { addKernel("kernel0"); addKernel("kernel1"); addKernel("kernel2"); @@ -329,7 +340,7 @@ TEST_F(ExternalFunctionsTests, GivenValidFunctionAndKernelDependenciesWhenResolv EXPECT_TRUE(nameToKernelDescriptor["kernel2"]->kernelAttributes.flags.hasIndirectCalls); } -TEST_F(ExternalFunctionsTests, GivenValidFunctionAndKernelOptionalDependenciesWhenResolvingDependenciesThenSetAppropriateHasIndirectfCallsAndReturnSuccess) { +TEST_F(ExternalFunctionsTests, GivenValidFunctionAndKernelOptionalDependenciesWhenResolvingDependenciesThenSetAppropriateHasIndirectCallsAndReturnSuccess) { addKernel("kernel0"); addKernel("kernel1"); addKernel("kernel2"); @@ -353,3 +364,53 @@ TEST_F(ExternalFunctionsTests, GivenValidFunctionAndKernelOptionalDependenciesWh EXPECT_FALSE(nameToKernelDescriptor["kernel1"]->kernelAttributes.flags.hasIndirectCalls); EXPECT_TRUE(nameToKernelDescriptor["kernel2"]->kernelAttributes.flags.hasIndirectCalls); } + +TEST_F(ExternalFunctionsTests, GivenValidFunctionAndKernelDependenciesWhenResolvingDependenciesThenSetAppropriateUsesAssertAndReturnSuccess) { + addKernel("kernel0"); + addKernel("kernel1"); + addKernel("kernel2"); + addExternalFunction("fun0", {.requireAssertBuffer = false}); + addExternalFunction("fun1", {.requireAssertBuffer = true}); + addExternalFunction("fun2", {.requireAssertBuffer = false}); + + addFuncDependency("fun1", "fun0"); + addKernelDependency("fun0", "kernel0"); + addKernelDependency("fun2", "kernel1"); + addKernelDependency("fun2", "kernel2"); + set(); + + nameToKernelDescriptor["kernel2"]->kernelAttributes.flags.usesAssert = true; + auto error = resolveExternalDependencies(extFuncInfo, kernelDependencies, functionDependencies, nameToKernelDescriptor); + EXPECT_EQ(RESOLVE_SUCCESS, error); + EXPECT_TRUE(extFuncInfo[funcNameToId["fun0"]]->requireAssertBuffer); + EXPECT_TRUE(extFuncInfo[funcNameToId["fun1"]]->requireAssertBuffer); + EXPECT_FALSE(extFuncInfo[funcNameToId["fun2"]]->requireAssertBuffer); + EXPECT_TRUE(nameToKernelDescriptor["kernel0"]->kernelAttributes.flags.usesAssert); + EXPECT_FALSE(nameToKernelDescriptor["kernel1"]->kernelAttributes.flags.usesAssert); + EXPECT_TRUE(nameToKernelDescriptor["kernel2"]->kernelAttributes.flags.usesAssert); +} + +TEST_F(ExternalFunctionsTests, GivenValidFunctionAndKernelDependenciesWhenResolvingDependenciesThenSetAppropriateUsesSyncBufferAndReturnSuccess) { + addKernel("kernel0"); + addKernel("kernel1"); + addKernel("kernel2"); + addExternalFunction("fun0", {.requireSyncBuffer = false}); + addExternalFunction("fun1", {.requireSyncBuffer = true}); + addExternalFunction("fun2", {.requireSyncBuffer = false}); + + addFuncDependency("fun1", "fun0"); + addKernelDependency("fun0", "kernel0"); + addKernelDependency("fun2", "kernel1"); + addKernelDependency("fun2", "kernel2"); + set(); + + nameToKernelDescriptor["kernel2"]->kernelAttributes.flags.usesSyncBuffer = true; + auto error = resolveExternalDependencies(extFuncInfo, kernelDependencies, functionDependencies, nameToKernelDescriptor); + EXPECT_EQ(RESOLVE_SUCCESS, error); + EXPECT_TRUE(extFuncInfo[funcNameToId["fun0"]]->requireSyncBuffer); + EXPECT_TRUE(extFuncInfo[funcNameToId["fun1"]]->requireSyncBuffer); + EXPECT_FALSE(extFuncInfo[funcNameToId["fun2"]]->requireSyncBuffer); + EXPECT_TRUE(nameToKernelDescriptor["kernel0"]->kernelAttributes.flags.usesSyncBuffer); + EXPECT_FALSE(nameToKernelDescriptor["kernel1"]->kernelAttributes.flags.usesSyncBuffer); + EXPECT_TRUE(nameToKernelDescriptor["kernel2"]->kernelAttributes.flags.usesSyncBuffer); +} 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 881cda08c6..d3f0fff005 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 @@ -1979,6 +1979,8 @@ kernels: has_lsc_stores_with_non_default_l1_cache_controls: true has_printf_calls: true has_indirect_calls: true + require_assert_buffer: true + require_sync_buffer: true ... )==="; @@ -2029,6 +2031,8 @@ kernels: EXPECT_TRUE(execEnv.hasLscStoresWithNonDefaultL1CacheControls); EXPECT_TRUE(execEnv.hasPrintfCalls); EXPECT_TRUE(execEnv.hasIndirectCalls); + EXPECT_TRUE(execEnv.requireAssertBuffer); + EXPECT_TRUE(execEnv.requireSyncBuffer); } TEST(ReadZeInfoExecutionEnvironment, GivenMinimalExecutionEnvThenSetProperMembersToDefaults) { @@ -2089,6 +2093,8 @@ kernels: EXPECT_EQ(Defaults::hasLscStoresWithNonDefaultL1CacheControls, execEnv.hasLscStoresWithNonDefaultL1CacheControls); EXPECT_EQ(Defaults::hasPrintfCalls, execEnv.hasPrintfCalls); EXPECT_EQ(Defaults::hasIndirectCalls, execEnv.hasIndirectCalls); + EXPECT_EQ(Defaults::requireAssertBuffer, execEnv.requireAssertBuffer); + EXPECT_EQ(Defaults::requireSyncBuffer, execEnv.requireSyncBuffer); } TEST(ReadZeInfoExecutionEnvironment, GivenUnknownEntryThenEmitsError) { @@ -3678,6 +3684,8 @@ functions: has_rtcalls: true has_printf_calls: true has_indirect_calls: true + require_assert_buffer: true + require_sync_buffer: true )==="; uint8_t kernelIsa[8]{0U}; @@ -3705,6 +3713,8 @@ functions: EXPECT_EQ(true, funInfo.hasRTCalls); EXPECT_EQ(true, funInfo.hasIndirectCalls); EXPECT_EQ(true, funInfo.hasPrintfCalls); + EXPECT_EQ(true, funInfo.requireAssertBuffer); + EXPECT_EQ(true, funInfo.requireSyncBuffer); } TEST(DecodeSingleDeviceBinaryZebin, GivenValidZeInfoWithEmptyKernelsAndExternalFunctionsMetadataThenPopulatesExternalFunctionMetadataProperly) { @@ -7629,6 +7639,36 @@ kernels: EXPECT_TRUE(kernelDescriptor->kernelAttributes.flags.hasPrintfCalls); } +TEST_F(decodeZeInfoKernelEntryTest, GivenKernelRequiringAssertBufferWhenPopulatingKernelDescriptorThenUsesAssertFlagIsSet) { + ConstStringRef zeinfo = R"===( +kernels: + - name : some_kernel + execution_env: + simd_size: 8 + require_assert_buffer: true +... +)==="; + auto err = decodeZeInfoKernelEntry(zeinfo); + EXPECT_EQ(NEO::DecodeError::success, err); + + EXPECT_TRUE(kernelDescriptor->kernelAttributes.flags.usesAssert); +} + +TEST_F(decodeZeInfoKernelEntryTest, GivenKernelRequiringSyncBufferWhenPopulatingKernelDescriptorThenUsesSyncBufferFlagIsSet) { + ConstStringRef zeinfo = R"===( +kernels: + - name : some_kernel + execution_env: + simd_size: 8 + require_sync_buffer: true +... +)==="; + auto err = decodeZeInfoKernelEntry(zeinfo); + EXPECT_EQ(NEO::DecodeError::success, err); + + EXPECT_TRUE(kernelDescriptor->kernelAttributes.flags.usesSyncBuffer); +} + TEST(PopulateInlineSamplers, GivenInvalidSamplerIndexThenPopulateInlineSamplersFails) { NEO::KernelDescriptor kd; std::string errors, warnings;