Repository: go
Issue: x/sys/unix, x/sys/cpu: use the RISC-V Hardware Probing Interface on Linux
Labels: OS-Linux,arch-riscv,FixPending

**Overview**

The RISC-V port of Go is currently restricted to the RV64G instruction set.  It does not take advantage of any other RISC-V extensions that could be used to boost performance or reduce code size, for example the [Vector](https://github.com/riscv/riscv-v-spec/releases/tag/v1.0) or [Bit manipulation](https://github.com/riscv/riscv-bitmanip/releases/tag/1.0.0) extensions.    This is in stark contrast to other architectures supported by Go where SIMD and bit manipulation instructions are used when they are available.  For example, amd64 builds of Go can use AVX2 optimised versions of certain critical functions, e.g., compare and memmove, to improve performance.  Until recently, one issue preventing the use of RISC-V extensions beyond RV64G in Go was the lack of a mechanism to detect these extensions.   This issue was resolved in Linux 6.4.

Version 6.4 of the Linux kernel introduces a new syscall, [sys_riscv_hwprobe](https://docs.kernel.org/arch/riscv/hwprobe.html) that can be used to determine interesting pieces of information about the underlying RISC-V CPUs on which a user space program runs.   In particular, it exposes the RISC-V extensions supported by the CPUs in addition to other performance information such as whether and how efficiently the CPUs support unaligned memory accesses.

**What about HWCAP?**

Where available sys_riscv_hwprobe is preferable to using HWCAP as:

1. It's extensible (there's enough bits for all future extensions).
2. It can be used to query for extensions with multi-letter names, e.g., Zba, Zbb, which are likely to be useful in Go going forward.
3. The hwprobe extension bits are versioned and their meaning is concretely defined.
4. It can be used to determine additional information about the CPU. One potentially interesting example is its ability to return information about how well the CPU handles unaligned accesses.  The current optimised RISC-V primitives for Go, e.g., memequal go out of their way to avoid unaligned accesses, i.e., they do 8 individual byte loads and stores instead of two unaligned 8 byte memory accesses. The current implementations might not be optimal on CPUs that support fast unaligned accesses. Hwprobe provides a way to detect fast unaligned accesses  and an opportunity to switch to implementations that use them.

sys_riscv_hwprobe should be sufficient by itself for detecting the presence of V, Zba, Zbb, Zbs in vanilla kernels.  However, there may be cases where extensions have been back ported to an earlier kernel but hw_probe has not.  Such situations could be handled by first trying sys_hw_probe and then falling back to HWCAP if hw_probe is not available.  This is the strategy used in [OpenJDK](https://github.com/openjdk/jdk/commit/31b6fd775f1c4f2841d9a52ad5f275ad446ee661#diff-72275ce9ef886742bb64b12343a47ac7c0b50eec5e81b0963c3c12e50e595799R102).

**Update 26/09/2023** However, it is probably not safe to use hwcap to detect the Vector extension as some RISC-V boards, e.g., the SiPeed LicheePi, indicate support for Vector 0.7 ( which is not compatible with Vector 1.0) through the hwcap 'V' bit.

Note that there's already a [patch](https://go-review.googlesource.com/c/sys/+/508676) pending review that detects some extensions using HWCAP.   Here we propose calling sys_riscv_hwprobe first and if that fails falling back to the code in this HWCAP [patch](https://go-review.googlesource.com/c/sys/+/508676).  We would not fall back for Vector.

**What extensions can sys_riscv_hwprobe detect?**

It can detect FD and C in Linux 6.4

Support for detecting V, Zba, Zbb and Zbs are merged and are available in Linux 6.5.

**What are we proposing?**

The proposal is then to

(**Updated on 26th of September 2023.**)

1. Add support for the sys_riscv_hwprobe to golang.org/x/sys/unix ([510795](https://go-review.googlesource.com/c/sys/+/510795)).  This would add a new syscall, a new type and some new constants to riscv64 builds.
2. Update golang.org/x/sys/unix when Linux 6.5 is released to add support for the new extensions it supports. ([530895](https://go-review.googlesource.com/c/sys/+/530895))
3. Update golang.org/x/sys/cpu to invoke the new syscall and record which extensions are supported.  We'd fall back to HWCAP where sys_riscv_hwprobe is not available.
4. Add support for the sys_riscv_hwprobe to ~~internal/syscall/unix~~ runtime ([522995](https://go-review.googlesource.com/c/go/+/522995)).
5. Update internal/cpu to invoke the new syscall in internal/syscall/unix and record which extensions are supported.  We'd fall back to HWCAP (not for Vector) where sys_riscv_hwprobe is not available ([522995](https://go-review.googlesource.com/c/go/+/522995)).

Proposal #62238 introduces the golang/x/sys/cpu.RISCV64 structure with one member, HasV.  Here we propose adding the following new members to this structure.

```
        IsMisalignedFast bool // Fast misaligned accesses 
        HasC bool              // The C extension
        HasZba bool            // The Zba address generation extension, version 1.0 or greater
        HasZbb bool            // The Zbb extension, version 1.0 or greater
        HasZbs bool            // The Zbs extension, version 1.0 or greater
```