Skip to content

Commit e57670e

Browse files
allnesclaude
andcommitted
[CPU][ARM] Guard ARM SVE kernel entry points
Cause: - AArch64 GCC LTO (cross-compile, gcc-10) propagates -march=armv8-a+sve target attributes from runtime-dispatched SVE clones into generic ARMv8-A baseline code. - GCC auto-vectorizes generic helpers (e.g. std::vector resize in the SVE PagedAttention executor) with SVE (mov z0.b,#0 / whilelo / st1d). - On cores without SVE (e.g. Cortex-A72) these instructions are illegal -> SIGILL at runtime, reached on a TBB worker thread. - brgemm_kernel.cpp ISA selection unconditionally falls back to sve_128 without checking mayiuse(sve_128). Solution: - Add hasArmSVESupport() and hasArmASIMDSupport() to precision_support. - Guard make_pa_executor: throw when !hasArmSVESupport(). - brgemm_kernel.cpp: return isa_undef and throw instead of unconditional sve_128 fallback in getVlen()/init_brgemm()/init_brgemm_copy_*(). - Guard ACL conv/fullyconnected/lowp-fullyconnected and kleidiai_mm executor entry points via mayUseAclGemmBasedExecutor() (acl_isa_guard.hpp). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e267686 commit e57670e

10 files changed

Lines changed: 117 additions & 33 deletions

File tree

src/plugins/intel_cpu/src/nodes/executors/acl/acl_conv.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "memory_desc/cpu_memory_desc.h"
2525
#include "nodes/common/cpu_convert.h"
2626
#include "nodes/executors/acl/acl_common_executor.hpp"
27+
#include "nodes/executors/acl/acl_isa_guard.hpp"
2728
#include "nodes/executors/common/common_utils.hpp"
2829
#include "nodes/executors/convolution_config.hpp"
2930
#include "nodes/executors/debug_messages.hpp"
@@ -118,6 +119,7 @@ ACLConvolutionExecutor::ACLConvolutionExecutor(const ConvAttrs& attrs,
118119
}
119120

120121
bool ACLConvolutionExecutor::supports(const ConvConfig& config) {
122+
VERIFY(mayUseAclGemmBasedExecutor(), UNSUPPORTED_ISA);
121123
VERIFY(config.attrs.postOps.size() <= 1U, UNSUPPORTED_BY_EXECUTOR);
122124

123125
const auto& srcDesc = config.descs.at(ARG_SRC);
@@ -144,6 +146,9 @@ bool ACLConvolutionExecutor::supports(const ConvConfig& config) {
144146
}
145147

146148
arm_compute::Status ACLConvolutionExecutor::validateTensorsInfo(const ACLInfos& aclMemoryInfos) {
149+
if (!mayUseAclGemmBasedExecutor()) {
150+
return aclGemmBasedExecutorUnsupportedStatus();
151+
}
147152
// Note: LPT propagate dequantization scales from src and weights on conv output, and the result scale
148153
// is applied as weight scale. So quantization configuration forms in the following way:
149154
// - src quantization info is always trivial

src/plugins/intel_cpu/src/nodes/executors/acl/acl_fullyconnected.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "nodes/common/cpu_convert.h"
1818
#include "nodes/executors/acl/acl_common_executor.hpp"
1919
#include "nodes/executors/acl/acl_fullyconnected_utils.hpp"
20+
#include "nodes/executors/acl/acl_isa_guard.hpp"
2021
#include "nodes/executors/debug_messages.hpp"
2122
#include "nodes/executors/executor.hpp"
2223
#include "nodes/executors/fullyconnected_config.hpp"
@@ -76,6 +77,7 @@ ACLFullyConnectedExecutor::ACLFullyConnectedExecutor(const FCAttrs& attrs,
7677
}
7778

7879
bool ACLFullyConnectedExecutor::supports(const FCConfig& config) {
80+
VERIFY(mayUseAclGemmBasedExecutor(), UNSUPPORTED_ISA);
7981
VERIFY(any_of(srcType(config), ov::element::f16, ov::element::f32), UNSUPPORTED_SRC_PRECISIONS);
8082
VERIFY(any_of(weiType(config), ov::element::f16, ov::element::f32), UNSUPPORTED_WEI_PRECISIONS);
8183
VERIFY(postOpsNumbers(config) < 2, UNSUPPORTED_NUMBER_OF_POSTOPS);
@@ -91,6 +93,9 @@ void ACLFullyConnectedExecutor::updateTensorsShapes(ACLShapes& aclMemoryShapes)
9193
}
9294

9395
arm_compute::Status ACLFullyConnectedExecutor::validateTensorsInfo(const ACLInfos& aclMemoryInfos) {
96+
if (!mayUseAclGemmBasedExecutor()) {
97+
return aclGemmBasedExecutorUnsupportedStatus();
98+
}
9499
if (aclfcAttrs.isConvertedWeights) {
95100
aclMemoryInfos[ACLArgs::ACL_WEI]->set_data_type(aclMemoryInfos[ACLArgs::ACL_SRC_0]->data_type());
96101
}

src/plugins/intel_cpu/src/nodes/executors/acl/acl_fullyconnected_utils.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "nodes/common/reorder_prim.h"
4343
#include "nodes/convert.h"
4444
#include "nodes/executors/acl/acl_common_executor.hpp"
45+
#include "nodes/executors/acl/acl_isa_guard.hpp"
4546
#include "nodes/executors/executor.hpp"
4647
#include "nodes/executors/fullyconnected_config.hpp"
4748
#include "nodes/executors/memory_arguments.hpp"
@@ -377,6 +378,9 @@ void acl_fc_executor::ACLWeightFormatGenerator::updateTensorsShapes(ACLShapes& a
377378
}
378379

379380
arm_compute::Status acl_fc_executor::ACLWeightFormatGenerator::validateTensorsInfo(const ACLInfos& aclMemoryInfos) {
381+
if (!mayUseAclGemmBasedExecutor()) {
382+
return aclGemmBasedExecutorUnsupportedStatus();
383+
}
380384
if (aclfcAttrs.isConvertedWeights) {
381385
aclMemoryInfos[ACLArgs::ACL_WEI]->set_data_type(aclMemoryInfos[ACLArgs::ACL_SRC_0]->data_type());
382386
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (C) 2018-2026 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#pragma once
6+
7+
#include <arm_compute/core/Error.h>
8+
9+
#include "utils/precision_support.h"
10+
11+
namespace ov::intel_cpu {
12+
13+
inline bool mayUseAclGemmBasedExecutor() {
14+
#if defined(OPENVINO_ARCH_ARM64)
15+
return hasArmSVESupport();
16+
#else
17+
return true;
18+
#endif
19+
}
20+
21+
inline arm_compute::Status aclGemmBasedExecutorUnsupportedStatus() {
22+
return arm_compute::Status(arm_compute::ErrorCode::RUNTIME_ERROR,
23+
"ACL GEMM-based executor requires ARM SVE runtime support");
24+
}
25+
26+
} // namespace ov::intel_cpu

src/plugins/intel_cpu/src/nodes/executors/acl/acl_lowp_fullyconnected.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "memory_desc/cpu_memory_desc.h"
2020
#include "nodes/common/cpu_convert.h"
2121
#include "nodes/executors/acl/acl_common_executor.hpp"
22+
#include "nodes/executors/acl/acl_isa_guard.hpp"
2223
#include "nodes/executors/acl/acl_utils.hpp"
2324
#include "nodes/executors/common/common_utils.hpp"
2425
#include "nodes/executors/debug_messages.hpp"
@@ -79,6 +80,7 @@ ACLLowpFullyConnectedExecutor::ACLLowpFullyConnectedExecutor(const FCAttrs& attr
7980
}
8081

8182
bool ACLLowpFullyConnectedExecutor::supports(const FCConfig& config) {
83+
VERIFY(mayUseAclGemmBasedExecutor(), UNSUPPORTED_ISA);
8284
VERIFY(any_of(srcType(config), ov::element::u8, ov::element::i8), UNSUPPORTED_SRC_PRECISIONS);
8385
VERIFY(weiType(config) == ov::element::i8, UNSUPPORTED_WEI_PRECISIONS);
8486
VERIFY(dstType(config) == ov::element::f32, UNSUPPORTED_DST_PRECISIONS);
@@ -93,6 +95,9 @@ void ACLLowpFullyConnectedExecutor::updateTensorsShapes(ACLShapes& aclMemoryShap
9395
}
9496

9597
arm_compute::Status ACLLowpFullyConnectedExecutor::validateTensorsInfo(const ACLInfos& aclMemoryInfos) {
98+
if (!mayUseAclGemmBasedExecutor()) {
99+
return aclGemmBasedExecutorUnsupportedStatus();
100+
}
96101
const auto& tensor_info = aclMemoryInfos[ACLArgs::ACL_SRC_0];
97102
if (dequantizationScales.empty()) {
98103
tensor_info->set_quantization_info(arm_compute::QuantizationInfo(1.F));

src/plugins/intel_cpu/src/nodes/executors/kleidiai/kleidiai_mm.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "memory_desc/cpu_memory_desc.h"
2525
#include "memory_desc/cpu_memory_desc_utils.h"
2626
#include "nodes/executors/acl/acl_fullyconnected_utils.hpp"
27+
#include "nodes/executors/debug_messages.hpp"
2728
#include "nodes/executors/executor.hpp"
2829
#include "nodes/executors/fullyconnected_config.hpp"
2930
#include "nodes/executors/memory_arguments.hpp"
@@ -60,6 +61,7 @@ static bool useDynamicQuantizationImpl(const FCAttrs& attrs, const MemoryDescPtr
6061
}
6162

6263
bool MatMulKleidiAIExecutor::supports(const FCConfig& config) {
64+
VERIFY(hasArmASIMDSupport(), UNSUPPORTED_ISA);
6365
return config.descs.at(ARG_WEI)->getPrecision() == element::f32 ||
6466
useDynamicQuantizationImpl(config.attrs, config.descs.at(ARG_WEI));
6567
}

src/plugins/intel_cpu/src/nodes/kernels/aarch64/brgemm_kernel.cpp

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// Copyright (C) 2018-2026 Intel Corporation
2-
// Copyright (C) 2024 FUJITSU LIMITED
32
// SPDX-License-Identifier: Apache-2.0
43
//
54

@@ -35,14 +34,41 @@ using namespace dnnl::impl::cpu::aarch64::matmul;
3534

3635
namespace ov::intel_cpu {
3736

38-
static size_t getVlen() {
37+
static cpu_isa_t getSupportedSveIsa() {
3938
if (mayiuse(sve_512)) {
40-
return cpu_isa_traits<sve_512>::vlen;
39+
return cpu_isa_t::sve_512;
4140
}
4241
if (mayiuse(sve_256)) {
42+
return cpu_isa_t::sve_256;
43+
}
44+
if (mayiuse(sve_128)) {
45+
return cpu_isa_t::sve_128;
46+
}
47+
return cpu_isa_t::isa_undef;
48+
}
49+
50+
static cpu_isa_t getSupportedSve256Isa() {
51+
if (mayiuse(sve_512)) {
52+
return cpu_isa_t::sve_512;
53+
}
54+
if (mayiuse(sve_256)) {
55+
return cpu_isa_t::sve_256;
56+
}
57+
return cpu_isa_t::isa_undef;
58+
}
59+
60+
static size_t getVlen() {
61+
const auto isa = getSupportedSveIsa();
62+
if (isa == cpu_isa_t::sve_512) {
63+
return cpu_isa_traits<sve_512>::vlen;
64+
}
65+
if (isa == cpu_isa_t::sve_256) {
4366
return cpu_isa_traits<sve_256>::vlen;
4467
}
45-
return cpu_isa_traits<sve_128>::vlen;
68+
if (isa == cpu_isa_t::sve_128) {
69+
return cpu_isa_traits<sve_128>::vlen;
70+
}
71+
THROW_ERROR("requires ARM SVE support");
4672
}
4773

4874
BrgemmKernel::BrgemmKernel(size_t M,
@@ -152,15 +178,10 @@ size_t BrgemmKernel::get_scratch_b_size() const {
152178

153179
void BrgemmKernel::init_brgemm(brgemmCtx& ctx, std::unique_ptr<dnnl::impl::cpu::aarch64::brgemm_kernel_t>& brgKernel) {
154180
brgemm_t brgDesc;
155-
cpu_isa_t isa = [&]() {
156-
if (mayiuse(sve_512)) {
157-
return cpu_isa_t::sve_512;
158-
}
159-
if (mayiuse(sve_256)) {
160-
return cpu_isa_t::sve_256;
161-
}
162-
return cpu_isa_t::sve_128;
163-
}();
181+
const cpu_isa_t isa = getSupportedSveIsa();
182+
if (isa == cpu_isa_t::isa_undef) {
183+
THROW_ERROR("requires ARM SVE support");
184+
}
164185
auto status = brgemm_desc_init(&brgDesc,
165186
isa,
166187
brgemm_addr,
@@ -216,15 +237,10 @@ void BrgemmKernel::init_brgemm_copy_a(
216237
// copied A has the same precision of original
217238
brgCopyKernelConf.tr_a_dt_sz = DnnlExtensionUtils::sizeOfDataType(static_cast<dnnl::memory::data_type>(dt_in0));
218239
brgCopyKernelConf.transposed_A = transpose;
219-
brgCopyKernelConf.isa = [&]() {
220-
if (mayiuse(sve_512)) {
221-
return cpu_isa_t::sve_512;
222-
}
223-
if (mayiuse(sve_256)) {
224-
return cpu_isa_t::sve_256;
225-
}
226-
return cpu_isa_t::sve_128;
227-
}();
240+
brgCopyKernelConf.isa = getSupportedSve256Isa();
241+
if (brgCopyKernelConf.isa == cpu_isa_t::isa_undef) {
242+
THROW_ERROR("copy A kernel requires ARM SVE256 support");
243+
}
228244

229245
create_brgemm_matmul_copy_a(brgCopyKernel, &brgCopyKernelConf);
230246
}
@@ -261,15 +277,10 @@ void BrgemmKernel::init_brgemm_copy_b(
261277
brgCopyKernelConf.tr_b_dt_sz =
262278
DnnlExtensionUtils::sizeOfDataType(static_cast<dnnl::memory::data_type>(brgCopyKernelConf.src_dt));
263279
brgCopyKernelConf.req_wei_vnni_downconvert = false;
264-
brgCopyKernelConf.isa = []() {
265-
if (mayiuse(sve_512)) {
266-
return cpu_isa_t::sve_512;
267-
}
268-
if (mayiuse(sve_256)) {
269-
return cpu_isa_t::sve_256;
270-
}
271-
return cpu_isa_t::sve_128;
272-
}();
280+
brgCopyKernelConf.isa = getSupportedSve256Isa();
281+
if (brgCopyKernelConf.isa == cpu_isa_t::isa_undef) {
282+
THROW_ERROR("copy B kernel requires ARM SVE256 support");
283+
}
273284

274285
brgCopyKernelConf.has_zero_point_a = false;
275286
brgCopyKernelConf.has_zero_point_b = false;

src/plugins/intel_cpu/src/nodes/kernels/scaled_attn/executor_pa.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "transpose_kernel.hpp"
4141
#include "utils/general_utils.h"
4242
#include "utils/plain_tensor.hpp"
43+
#include "utils/precision_support.h"
4344
#include "xattention.hpp"
4445
#if defined(OPENVINO_ARCH_X86_64)
4546
# include "nodes/kernels/x64/brgemm_kernel.hpp"
@@ -2926,21 +2927,25 @@ std::shared_ptr<PagedAttentionExecutor> make_pa_executor(ov::element::Type data_
29262927
OPENVINO_THROW("make_pa_executor: unsupported precision: ", data_type);
29272928
}
29282929
#elif (defined(OPENVINO_ARCH_ARM64) && defined(HAVE_SVE))
2930+
if (!ov::intel_cpu::hasArmSVESupport()) {
2931+
OPENVINO_THROW("make_pa_executor: ARM implementation requires SVE support");
2932+
}
29292933
if (data_type == ov::element::f32) {
29302934
if (key_cache_type == ov::element::u8 && value_cache_type == ov::element::u8) {
29312935
executor =
29322936
std::make_shared<AttentionExecutor<float, ov::element::u8, ov::element::u8>>(params, cpu_parallel);
29332937
} else {
29342938
OPENVINO_THROW("make_pa_executor: key_cache_type and value_cache_type of u8 is only support");
29352939
}
2936-
}
2937-
if (data_type == ov::element::f16) {
2940+
} else if (data_type == ov::element::f16) {
29382941
if (key_cache_type == ov::element::u8 && value_cache_type == ov::element::u8) {
29392942
executor = std::make_shared<AttentionExecutor<ov::float16, ov::element::u8, ov::element::u8>>(params,
29402943
cpu_parallel);
29412944
} else {
29422945
OPENVINO_THROW("make_pa_executor: key_cache_type and value_cache_type of u8 is only support");
29432946
}
2947+
} else {
2948+
OPENVINO_THROW("make_pa_executor: unsupported precision: ", data_type);
29442949
}
29452950

29462951
#else

src/plugins/intel_cpu/src/utils/precision_support.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#if defined(OPENVINO_ARCH_X86_64)
88
# include "cpu/x64/cpu_isa_traits.hpp"
99
#endif
10+
#if defined(OPENVINO_ARCH_ARM64)
11+
# include "cpu/aarch64/cpu_isa_traits.hpp"
12+
#endif
1013
#include "openvino/core/type/element_type.hpp"
1114
#include "openvino/core/visibility.hpp"
1215
#include "openvino/runtime/system_conf.hpp"
@@ -54,6 +57,22 @@ ov::element::Type defaultFloatPrecision() {
5457
return ov::element::f32;
5558
}
5659

60+
bool hasArmASIMDSupport() {
61+
#if defined(OPENVINO_ARCH_ARM64)
62+
return dnnl::impl::cpu::aarch64::mayiuse(dnnl::impl::cpu::aarch64::asimd);
63+
#else
64+
return false;
65+
#endif
66+
}
67+
68+
bool hasArmSVESupport() {
69+
#if defined(OPENVINO_ARCH_ARM64)
70+
return with_cpu_sve() && dnnl::impl::cpu::aarch64::mayiuse(dnnl::impl::cpu::aarch64::sve_128);
71+
#else
72+
return false;
73+
#endif
74+
}
75+
5776
bool hasIntDotProductSupport() {
5877
return with_cpu_arm_dotprod();
5978
}

src/plugins/intel_cpu/src/utils/precision_support.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ namespace ov::intel_cpu {
1010

1111
bool hasHardwareSupport(const ov::element::Type& precision);
1212
ov::element::Type defaultFloatPrecision();
13+
bool hasArmASIMDSupport();
14+
bool hasArmSVESupport();
1315
bool hasIntDotProductSupport();
1416
bool hasInt8MMSupport();
1517

0 commit comments

Comments
 (0)