by Ludovic Henry, Qualcomm
The latest torch 2.13.0 can now be installed on riscv64 from the RISE Python Package Index:
pip install torch --extra-index-url https://pypi.riseproject.dev/simple/ --prefer-binary
There are four wheels, for CPython 3.12, 3.13, 3.14 and 3.14t, tagged manylinux_2_39_riscv64. They are built on RISC-V hardware, nothing here is cross-compiled or built under QEMU.
PyPI has 49 releases of torch and not one of them contains a riscv64 file. Until now, running PyTorch on a RISC-V machine meant compiling it yourself, which in turn meant getting a few dozen native libraries and Python packages to compile first.
This post covers what went into that: the dependency work, what we have been doing with the PyTorch community, and the CI that produces these builds. It also covers what still does not work, which is a fair amount.
The Dependencies
Very little of this was PyTorch work. Most of it was in the layers below.
SLEEF, the vector math library PyTorch uses for transcendental functions, is the oldest piece for which we added support for RISC-V (shibatch/sleef#477, released in SLEEF 3.6). The GitHub Actions CI went in a week earlier, in #476, and that ordering was deliberate. Asking a maintainer to accept an architecture they have no way of testing is a much harder conversation than asking them to add one more job to a matrix that already exists.
NumPy mattered more than anything else, because almost everything else depends on it. Two things landed in May 2026. numpy#31488 added riscv64 wheel building and testing to NumPy’s CI. numpy#31522 added RISC-V to NEP 57, NumPy’s platform support policy, as a Tier 3 platform. The second one is the one that will still be doing work in two years, because it is what a maintainer can point at when the next person asks whether riscv64 is worth the CI minutes.
OpenBLAS does the matrix-multiply work in these wheels, since oneDNN is disabled (more on that below). RISC-V support there goes back to 2018 and the RVV kernels, the ZVL128B and ZVL256B targets and DYNAMIC_ARCH detection came in over 2024 and 2025, almost none of it ours. What we hit was narrower: a build failure with DYNAMIC_TARGET=1 and bfloat16 (OpenBLAS#5789), and then the discovery that OpenBLAS v0.3.33 does not compile on riscv64 at all: an undeclared coremsg variable in dynamic_riscv64.c. That is fixed in v0.3.34, and pytorch#190314 moves PyTorch’s pin forward to it.
GCC 13 versus GCC 14 came up three separate times in three unrelated projects. OpenBLAS’s ZVL targets need GCC 14. abseil’s subword-atomics static_assert fails on GCC 13, which breaks sentencepiece. libaom’s RVV intrinsics want finalised-spec rounding mode arguments that GCC 13 does not have, which breaks Pillow’s AVIF support.
Then there is the Python layer, which is most of the work by volume. The RISE Python Wheels project currently tracks 77 packages. We actively build 40 of them. The other 37 we have stopped building, because upstream now ships riscv64 wheels themselves. Getting a package into that second group is the ultimate goal of the exercise: build a wheel so people can actually install the thing, send the patch upstream, delete our workflow when it lands.
The packaging tooling had to catch up too, and it got there before CPython did. manylinux_2_39_riscv64 arrived in pypa/manylinux#1743 in July 2025, and pip has understood riscv64 manylinux wheels since 24.1. If you are on an older pip you will silently get much older wheels with a plain linux_riscv64 tag. For what it is worth, riscv64 still does not appear in PEP 11 at any tier. CPython builds and runs on it, but there is no support commitment from the core team.
Working with PyTorch upstream
RISC-V work in PyTorch started well before we got involved. The first RVV kernel, a depthwise convolution with a measured 31% improvement on MobileNet V2, was merged in July 2024 by zhangfeiv0 at ISCAS (pytorch#127867). A request for RISC-V CI was filed in November 2024 (#141550) and sat for a while. In January 2026 the XuanTie team at Alibaba DAMO filed RFC #171659 with a proper roadmap, and that became the tracking issue #180975, which is now the best overview of where RISC-V support in PyTorch is heading. Most of the items on it are not ours.
We have concentrated on build and CI infrastructure. What has landed:
- #187821 renamed the existing cross-compilation image to include
crossin the name, so that a native image could exist alongside it without confusion. - #188262 fixed OpenBLAS build on non-AArch64 platforms
- #189365 changed the sccache install to download from upstream releases.
- #190314 bumped OpenBLAS to v0.3.34, #187791 bumped lintrunner to v0.13.0, and #187792 bumped Numpy to 1.26.4, all versions that bring
riscv64support - #190887 added a native build image for linux-riscv64. This is what lets PyTorch be built on RISC-V hardware rather than cross-compiled.
- #191657 enabled the build of the wheel for RISC-V
Separately, PyTorch merged RFC-0050, which defines a cross-repository CI relay for out-of-tree backends, and #181739 and #181977 registered riseproject-dev/pytorch-ci as a consumer of it. Every push to pytorch/pytorch is now forwarded to RISE infrastructure, where it can trigger a native RISC-V build. We are at Level 1, which means events come to us but nothing goes back: no dashboard, no check on the pull request. Level 2 and Level 3 are what we are working towards.
Three patches are still carried in our tree rather than upstream, in patches/torch/2.13.0/. Two of them are build scripts for the manywheel image and one is a backport of something already merged. Emptying that directory is the concrete version of “get this upstream”. Some of these patches have already been merged into upstream’s main, others are being contributed. The goal is for upstream PyTorch to build on RISC-V out-of-the-box, without patches.
The CI
riseproject-dev/pytorch-ci builds and tests upstream PyTorch on RISC-V continuously. It has taken over 40,000 relay events since it was set up at the end of April, and run around 3,900 builds. Everything runs on ubuntu-24.04-riscv, the RISE RISC-V Runners label, on Scaleway EM-RV1 machines.
Two parts of this were more work than expected.
The first is compilation caching. A PyTorch build is about 2,300 ninja targets, and on our current RISE RISC-V Runners, a build with a cold-cache takes around 20 hours. A hot-cache build can reach 99+% cache-hit leading to build times of ~1h30 (linking can’t be cached and still takes a while). We even developed a custom sccache Redis-based coordinator to leverage the multiple machines which may rebuild PyTorch concurrently on a cold-cache.
The second is test sharding. PyTorch splits its test suite across shards using historical per-file timings that it downloads from test-infra, and those timings are measured on x86. The ratios between files are different enough on RISC-V that using them produces badly unbalanced shards, so we measure our own and substitute them into the build. The current file covers 550 test files and 121.9 hours of serial test time, refreshed weekly from real CI artifacts. inductor/test_torchinductor_opinfo on its own is 17.6 hours of that, which is more than a tenth of the total, so a balanced ten-way split does not exist without sub-sharding the multiple large test suites.
With that in place, here is where correctness stands. A full ten-shard run on 14 August executed 212,038 test cases: 165,591 passed, 191 failed, 46,256 skipped. That is 99.998% of the tests that passed!
99.998% of the enabled tests are passing out-of-the-box!
However, the 191 failures are more interesting than the percentage, because most of them are not RISC-V getting arithmetic wrong. They are places where something assumes x86:
- 69 failures, a third of the total, are the same assertion:
Expect L1_cache_size > 0 but got 0. cpuinfo does not fill in cache topology on RISC-V and the Inductor CPU autotuner asserts on it. - 15 are float-to-integer conversion of non-finite values. This one is a real difference in RISC-V semantics and is the most legitimate bug in the set.
- 9 are
NoQEngine. There is no quantization backend on riscv64, because neither FBGEMM nor QNNPACK supports it. - 6 are oneDNN not being available, 6 are an x86-only launcher test under
backends/xeon, and 3 are a hardcoded timing threshold that this hardware does not meet.
What does not work yet
The wheels install and run but they are not the fastest; yet!
There is no RVV vectorization in ATen. PyTorch’s CPUCapability dispatch has entries for AVX2, AVX512, NEON, SVE and VSX, and nothing for RVV, so most tensor operations in this wheel are scalar code. The patch to change that is #175746, open since February. It is stuck on a real design question rather than on missing kernels: Vectorized<> assumes the vector width is known at compile time, and both RVV and Arm SVE break that assumption. The same question is holding up SVE in #153471. Somebody has to decide what that abstraction should look like before either can land.
oneDNN is off. These builds use USE_MKLDNN=0 and OpenBLAS. There is a merged change enabling oneDNN on RISC-V with a reported 8.85x on elementwise multiply on SG2044, but PyTorch’s CI does not exercise it and neither do we yet, so treat that figure as something on the roadmap.
Test capacity is thin. A full run lands close to the 24-hour job limit, and most red runs are infrastructure rather than tests. RISE is working with ISCAS to increase build and test hardware capacity.
Next
Ship every release from here. 2.13.0 is parameterised by tag, so keeping up with upstream is now a matter of running the pipeline, and 2.14 is the first real test of whether we hold that.
Get RISC-V properly supported upstream. In practical terms: Level 1 to Level 3 on the CI relay so results show up on pull requests, a CODEOWNERS entry so RISC-V changes have a reviewer who is expected to look at them, and the patches directory emptied.
Bigger machines. A 121-hour test suite is a hardware problem first. We are working with Scaleway on EM-RV2, working with ISCAS on increasing building and testing capacity, and bringing up RVA23-class pools, and if you build RISC-V hardware and want a large, real, continuously running PyTorch workload on it, we would like to talk. It is a good way to find things wrong with a core.
More of PyTorch working. RVV in ATen first, since much of the rest waits on it, then oneDNN validated in CI, then quantization, then the Inductor and Triton items in phases 3 and 4 of the tracking issue.
Credits
Trevor Gamblin (BayLibre) and Julien Stephan (BayLibre) maintains python-wheels and wrote most of the build workflows and patches. Mark Ryan (Meta) started the original wheel_builder this project continues. Bruno Verachten has been landing riscv64 support directly in upstream projects, sentencepiece among them, and was one of the first heavy users of the runners. Ken Unger has done most of the RVV microkernel work in XNNPACK and cpuinfo thateverything above it relies on. zhangfeiv0 and colleagues at ISCAS contributed the first RVV kernel in PyTorch, the first CI attempt, and the oneDNN enablement. The XuanTie team at Alibaba DAMO wrote the roadmap the rest of us are working through. The PyTorch maintainers have reviewed a steady stream of infrastructure changes from us.
If you maintain something that depends on torch, the most useful thing you can do is add --extra-index-url https://pypi.riseproject.dev/simple/ to a riscv64 job and tell us what breaks. Issues on riseproject-dev/python-wheels get looked at fastest.
import torch works on RISC-V now. Making it fast is the next post.