Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/packages/openvino.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ versions:
- filename: openvino-2026.3.1-1-cp314-cp314t-manylinux_2_39_riscv64.whl
sha256: 98aef13ec9747ac540f29b6177d0ba9dea117aac8b5deead6a935d1723f722db
requires-python: '>=3.10'
- version: 2026.4.0
- version: 2026.4.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
From 9c0ff41dfe1be9aaeb6080e01fed7d4fb38777da Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Thu, 24 Sep 2026 11:43:42 +0000
Subject: [PATCH] cpu: riscv64: never probe for RVV 1.0 support

can_compile_rvv100()/can_compile_zvfh() try to detect RVV 1.0 by executing a
v1.0 vsetivli under a SIGILL handler and recovering via sigsetjmp/siglongjmp
if it traps. On RVV 0.7.1 hardware (T-Head Xuantie C906/C910/C920: TH1520,
SG2042) that recovery does not hold -- the illegal instruction brings the
whole process down (SIGILL, exit 132) instead of returning false, observed
as a crash inside ov.Core()/device enumeration the moment the CPU plugin is
loaded, well before any model is compiled.

Hardcode both probes to report RVV as unsupported. Every mayiuse(gv)/
mayiuse(gv_zvfh) caller in this plugin already treats a false result as
'fall back to the scalar/generic executor', and Transformations::MainSnippets()
already turns Snippets/Subgraph tokenization off entirely when
is_supported_isa() (== mayiuse(gv)) is false -- both existing, already-
exercised code paths for riscv64 targets without RVV. This just makes this
target take them unconditionally, instead of taking the branch that crashes.

We do not have a kernel/toolchain-level root cause or a backtrace from the
affected hardware for why the SIGILL recovery itself fails here (it would
need re-running just the test leg against an existing wheel under gdb); until
that exists to accompany a report, this is carried as a local workaround.

Upstream-Status: To upstream [no root-cause backtrace yet to accompany a report]
---
.../nodes/kernels/riscv64/cpu_isa_traits.cpp | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
index 567d627..cc2293d 100644
--- a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
+++ b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
@@ -74,13 +74,23 @@ bool can_execute_generated_code() {
}

bool can_compile_rvv100() {
- static const bool status = can_execute_generated_code<RVVGenerator>();
- return status;
+ // Deliberately never probe: can_execute_generated_code<RVVGenerator>() is supposed to
+ // detect RVV 1.0 support by executing a v1.0 vsetivli under a SIGILL handler and
+ // recovering if it traps, but on RVV 0.7.1 hardware (e.g. T-Head Xuantie C906/C910/C920)
+ // the illegal instruction does not recover cleanly through sigsetjmp/siglongjmp -- it
+ // brings the whole process down instead of returning false, which is exactly the crash
+ // this patch works around. Hardcoding "unsupported" routes every mayiuse(gv) caller
+ // through OpenVINO's existing non-RVV fallback (scalar/generic node executors, and
+ // Snippets/Subgraph tokenization already turns itself off via is_supported_isa() when
+ // mayiuse(gv) is false) instead of ever attempting to execute or JIT-compile RVV 1.0
+ // code on this target.
+ return false;
}

bool can_compile_zvfh() {
- static const bool status = can_execute_generated_code<ZvfhGenerator>();
- return status;
+ // See can_compile_rvv100() above: RVV support is unconditionally disabled for this
+ // target, so the (narrower, RVV-1.0-dependent) Zvfh probe must never run either.
+ return false;
}

} // namespace
--
2.43.0

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Fri, 25 Sep 2026 14:30:00 +0000
Subject: [PATCH] cpu: riscv64: do not read vlenb unless RVV 1.0 is usable

mayiuse() constructs the Xbyak_riscv::CPU singleton on every call, for
every ISA. That constructor JIT-compiles and runs `csrr a0, vlenb` whenever
AT_HWCAP advertises V -- with no SIGILL handler around it, unlike the RVV 1.0
probe in can_compile_rvv100(). On cores whose kernel sets the V hwcap but
whose vector unit is not RVV 1.0 (T-Head Xuantie C906/C910/C920, RVV 0.7.1),
a vector-CSR access is exactly the kind of instruction that can trap, and
nothing would catch it. The only callers outside this file ask for gv or
gv_zvfh, reached from compile_model() (transformation pipeline, eltwise
executor), so this sits on every model compilation.

Evaluate the RVV 1.0 probe first in the gv case, and build the CPU object
only for the g case. With can_compile_rvv100() hardcoded to false by the
previous patch, mayiuse(gv)/mayiuse(gv_zvfh) now return false without
executing any vector instruction. Behaviour on RVV 1.0 hardware with the
probe restored is unchanged: the probe runs under its own SIGILL handler
before the HWCAP/vlenb query instead of after it.

This one is defensive: the SIGILL observed on the CI hardware comes from
oneDNN being compiled with -march=rv64gcv (a static initializer at plugin
dlopen time), which is handled at configure time, not here. It has not been
seen crashing on hardware by itself, so there is no backtrace to report yet.

Upstream-Status: To upstream [defensive fix, no hardware crash observed from this path yet to accompany a report]
---
.../intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
index cc2293de..d3e15af7 100644
--- a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
+++ b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
@@ -96,19 +96,23 @@ bool can_compile_zvfh() {
} // namespace

bool mayiuse(const cpu_isa_t cpu_isa) {
- const auto cpu = CPU::getInstance();
+ // Xbyak_riscv::CPU's constructor JIT-executes `csrr a0, vlenb` with no SIGILL handler whenever
+ // AT_HWCAP advertises V. Build it only for `g` (which nothing outside this file queries), and have
+ // `gv` consult the RVV 1.0 probe first so that it never gets that far on this target.
switch (cpu_isa) {
- case g:
+ case g: {
+ const auto& cpu = CPU::getInstance();
return cpu.hasExtension(RISCVExtension::I) && cpu.hasExtension(RISCVExtension::M) &&
cpu.hasExtension(RISCVExtension::A) && cpu.hasExtension(RISCVExtension::F) &&
cpu.hasExtension(RISCVExtension::D);
+ }
// cpu.hasExtension(RISCVExtension::V) checks only RVV support on the device.
// To figure out RVV version, we try to execute code with RVV1.0 instructions.
// If there is no `SEGILL`, the device supports RVV1.0.
// Otherwise we consider that there is no RVV support
// [TODO] If needed, support other RVV versions
case gv:
- return mayiuse(g) && cpu.hasExtension(RISCVExtension::V) && can_compile_rvv100();
+ return can_compile_rvv100() && mayiuse(g) && CPU::getInstance().hasExtension(RISCVExtension::V);
case gv_zvfh:
return mayiuse(gv) && can_compile_zvfh();
case isa_all:
--
2.43.0

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
From 9c0ff41dfe1be9aaeb6080e01fed7d4fb38777da Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Thu, 24 Sep 2026 11:43:42 +0000
Subject: [PATCH] cpu: riscv64: never probe for RVV 1.0 support

can_compile_rvv100()/can_compile_zvfh() try to detect RVV 1.0 by executing a
v1.0 vsetivli under a SIGILL handler and recovering via sigsetjmp/siglongjmp
if it traps. On RVV 0.7.1 hardware (T-Head Xuantie C906/C910/C920: TH1520,
SG2042) that recovery does not hold -- the illegal instruction brings the
whole process down (SIGILL, exit 132) instead of returning false, observed
as a crash inside ov.Core()/device enumeration the moment the CPU plugin is
loaded, well before any model is compiled.

Hardcode both probes to report RVV as unsupported. Every mayiuse(gv)/
mayiuse(gv_zvfh) caller in this plugin already treats a false result as
'fall back to the scalar/generic executor', and Transformations::MainSnippets()
already turns Snippets/Subgraph tokenization off entirely when
is_supported_isa() (== mayiuse(gv)) is false -- both existing, already-
exercised code paths for riscv64 targets without RVV. This just makes this
target take them unconditionally, instead of taking the branch that crashes.

We do not have a kernel/toolchain-level root cause or a backtrace from the
affected hardware for why the SIGILL recovery itself fails here (it would
need re-running just the test leg against an existing wheel under gdb); until
that exists to accompany a report, this is carried as a local workaround.

Upstream-Status: To upstream [no root-cause backtrace yet to accompany a report]
---
.../nodes/kernels/riscv64/cpu_isa_traits.cpp | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
index 567d627..cc2293d 100644
--- a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
+++ b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
@@ -74,13 +74,23 @@ bool can_execute_generated_code() {
}

bool can_compile_rvv100() {
- static const bool status = can_execute_generated_code<RVVGenerator>();
- return status;
+ // Deliberately never probe: can_execute_generated_code<RVVGenerator>() is supposed to
+ // detect RVV 1.0 support by executing a v1.0 vsetivli under a SIGILL handler and
+ // recovering if it traps, but on RVV 0.7.1 hardware (e.g. T-Head Xuantie C906/C910/C920)
+ // the illegal instruction does not recover cleanly through sigsetjmp/siglongjmp -- it
+ // brings the whole process down instead of returning false, which is exactly the crash
+ // this patch works around. Hardcoding "unsupported" routes every mayiuse(gv) caller
+ // through OpenVINO's existing non-RVV fallback (scalar/generic node executors, and
+ // Snippets/Subgraph tokenization already turns itself off via is_supported_isa() when
+ // mayiuse(gv) is false) instead of ever attempting to execute or JIT-compile RVV 1.0
+ // code on this target.
+ return false;
}

bool can_compile_zvfh() {
- static const bool status = can_execute_generated_code<ZvfhGenerator>();
- return status;
+ // See can_compile_rvv100() above: RVV support is unconditionally disabled for this
+ // target, so the (narrower, RVV-1.0-dependent) Zvfh probe must never run either.
+ return false;
}

} // namespace
--
2.43.0

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Fri, 25 Sep 2026 14:30:00 +0000
Subject: [PATCH] cpu: riscv64: do not read vlenb unless RVV 1.0 is usable

mayiuse() constructs the Xbyak_riscv::CPU singleton on every call, for
every ISA. That constructor JIT-compiles and runs `csrr a0, vlenb` whenever
AT_HWCAP advertises V -- with no SIGILL handler around it, unlike the RVV 1.0
probe in can_compile_rvv100(). On cores whose kernel sets the V hwcap but
whose vector unit is not RVV 1.0 (T-Head Xuantie C906/C910/C920, RVV 0.7.1),
a vector-CSR access is exactly the kind of instruction that can trap, and
nothing would catch it. The only callers outside this file ask for gv or
gv_zvfh, reached from compile_model() (transformation pipeline, eltwise
executor), so this sits on every model compilation.

Evaluate the RVV 1.0 probe first in the gv case, and build the CPU object
only for the g case. With can_compile_rvv100() hardcoded to false by the
previous patch, mayiuse(gv)/mayiuse(gv_zvfh) now return false without
executing any vector instruction. Behaviour on RVV 1.0 hardware with the
probe restored is unchanged: the probe runs under its own SIGILL handler
before the HWCAP/vlenb query instead of after it.

This one is defensive: the SIGILL observed on the CI hardware comes from
oneDNN being compiled with -march=rv64gcv (a static initializer at plugin
dlopen time), which is handled at configure time, not here. It has not been
seen crashing on hardware by itself, so there is no backtrace to report yet.

Upstream-Status: To upstream [defensive fix, no hardware crash observed from this path yet to accompany a report]
---
.../intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
index cc2293de..d3e15af7 100644
--- a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
+++ b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp
@@ -96,19 +96,23 @@ bool can_compile_zvfh() {
} // namespace

bool mayiuse(const cpu_isa_t cpu_isa) {
- const auto cpu = CPU::getInstance();
+ // Xbyak_riscv::CPU's constructor JIT-executes `csrr a0, vlenb` with no SIGILL handler whenever
+ // AT_HWCAP advertises V. Build it only for `g` (which nothing outside this file queries), and have
+ // `gv` consult the RVV 1.0 probe first so that it never gets that far on this target.
switch (cpu_isa) {
- case g:
+ case g: {
+ const auto& cpu = CPU::getInstance();
return cpu.hasExtension(RISCVExtension::I) && cpu.hasExtension(RISCVExtension::M) &&
cpu.hasExtension(RISCVExtension::A) && cpu.hasExtension(RISCVExtension::F) &&
cpu.hasExtension(RISCVExtension::D);
+ }
// cpu.hasExtension(RISCVExtension::V) checks only RVV support on the device.
// To figure out RVV version, we try to execute code with RVV1.0 instructions.
// If there is no `SEGILL`, the device supports RVV1.0.
// Otherwise we consider that there is no RVV support
// [TODO] If needed, support other RVV versions
case gv:
- return mayiuse(g) && cpu.hasExtension(RISCVExtension::V) && can_compile_rvv100();
+ return can_compile_rvv100() && mayiuse(g) && CPU::getInstance().hasExtension(RISCVExtension::V);
case gv_zvfh:
return mayiuse(gv) && can_compile_zvfh();
case isa_all:
--
2.43.0

Loading