Skip to content

Commit de30092

Browse files
authored
add RVV support (#1000)
1 parent 5c5caff commit de30092

File tree

6 files changed

+172
-5
lines changed

6 files changed

+172
-5
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Ubuntu RISC-V Vector Extension
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened, ready_for_review]
6+
paths-ignore:
7+
- '**.md'
8+
- 'docs/**'
9+
push:
10+
branches:
11+
- main
12+
paths-ignore:
13+
- '**.md'
14+
- 'docs/**'
15+
16+
permissions:
17+
contents: read
18+
19+
concurrency:
20+
group: ${{ github.workflow }}-${{ github.ref }}
21+
cancel-in-progress: true
22+
jobs:
23+
ubuntu-build:
24+
strategy:
25+
fail-fast: false
26+
runs-on: ubuntu-24.04
27+
steps:
28+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
29+
- name: Setup ENV
30+
run: |
31+
sudo apt-get update -y
32+
sudo apt-get install -y cmake curl ninja-build \
33+
g++-riscv64-linux-gnu \
34+
gcc-riscv64-linux-gnu \
35+
qemu-user-static qemu-user
36+
- name: Build
37+
run: |
38+
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
39+
export QEMU_CPU="rv64,vlen=128"
40+
cmake -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains-dev/riscv64-rvv.cmake \
41+
-DADA_TESTING=ON \
42+
-DADA_USE_SIMDUTF=ON \
43+
-DCMAKE_BUILD_TYPE=Release \
44+
-G Ninja -B build
45+
cmake --build build -j=4
46+
- name: Test
47+
run: |
48+
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
49+
export QEMU_CPU="rv64,v=on,vlen=128"
50+
ctest --output-on-failure --test-dir build

cmake/toolchains-dev/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,22 @@ $ ctest --output-on-failure --test-dir build
2727
or
2828
$ qemu-loongarch64 build/singleheader/cdemo
2929
```
30+
31+
# RISC-V Vector Extension
32+
33+
The RISC-V Vector optimizations are supported by GCC-13, CLANG-16 and above.
34+
35+
Native builds will use the RVV code, if the specified `-march` ISA string or default target ISA supports the V extension.
36+
37+
For cross compilation, you may need to adjust the cross compiler target prefix in the toolchain file from `riscv64-linux-gnu` to e.g. `riscv64-unknown-linux-gnu` when using https://github.com/riscv-collab/riscv-gnu-toolchain.
38+
39+
```
40+
# For Debian/Ubuntu
41+
$ sudo apt install g++-riscv64-linux-gnu qemu-system-riscv qemu-user
42+
$ mkdir build; cd build
43+
$ export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
44+
$ export QEMU_CPU="rv64,v=on"
45+
$ mkdir build && cd build
46+
$ cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains-dev/riscv64-rvv.cmake -DADA_TESTING=ON ..
47+
$ cmake --build -j $(nproc)
48+
```
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Usage:
2+
# $ cmake -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains-dev/riscv64-rvv.cmake
3+
set(CMAKE_SYSTEM_NAME Generic)
4+
5+
set(target riscv64-linux-gnu)
6+
set(c_compiler gcc)
7+
set(cxx_compiler g++)
8+
9+
set(CMAKE_C_COMPILER "${target}-${c_compiler}")
10+
set(CMAKE_CXX_COMPILER "${target}-${cxx_compiler}")
11+
12+
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
13+
14+
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
15+
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
16+
17+
set(CMAKE_CROSSCOMPILING_EMULATOR "qemu-riscv64")
18+
19+
set(CMAKE_CXX_FLAGS "-march=rv64gcv")

include/ada/common_defs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,11 @@ namespace ada {
247247
#define ADA_LSX 1
248248
#endif
249249

250+
#if defined(__riscv_v) && __riscv_v_intrinsic >= 11000
251+
// Support RVV intrinsics v0.11 and above
252+
#define ADA_RVV 1
253+
#endif
254+
250255
#ifndef __has_cpp_attribute
251256
#define ada_lifetime_bound
252257
#elif __has_cpp_attribute(msvc::lifetimebound)

src/helpers.cpp

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
#include <cstring>
2+
#include <sstream>
3+
14
#include "ada/checkers-inl.h"
25
#include "ada/common_defs.h"
36
#include "ada/scheme.h"
47

5-
#include <cstring>
6-
#include <sstream>
7-
88
namespace ada::helpers {
99

1010
template <typename out_iter>
@@ -355,6 +355,42 @@ ada_really_inline size_t find_next_host_delimiter_special(
355355
}
356356
return size_t(view.length());
357357
}
358+
#elif ADA_RVV
359+
ada_really_inline size_t find_next_host_delimiter_special(
360+
std::string_view view, size_t location) noexcept {
361+
// The LUT approach was a bit slower on the SpacemiT X60, but I could see it
362+
// beeing faster on future hardware.
363+
#if 0
364+
// LUT generated using: s=":/\\?["; list(zip([((ord(c)>>2)&0xF)for c in s],s))
365+
static const uint8_t tbl[16] = {
366+
0xF, 0, 0, 0, 0, 0, '[', '\\', 0, 0, 0, '/', 0, 0, ':', '?'
367+
};
368+
vuint8m1_t vtbl = __riscv_vle8_v_u8m1(tbl, 16);
369+
#endif
370+
uint8_t* src = (uint8_t*)view.data() + location;
371+
for (size_t vl, n = view.size() - location; n > 0;
372+
n -= vl, src += vl, location += vl) {
373+
vl = __riscv_vsetvl_e8m1(n);
374+
vuint8m1_t v = __riscv_vle8_v_u8m1(src, vl);
375+
#if 0
376+
vuint8m1_t vidx = __riscv_vand(__riscv_vsrl(v, 2, vl), 0xF, vl);
377+
vuint8m1_t vlut = __riscv_vrgather(vtbl, vidx, vl);
378+
vbool8_t m = __riscv_vmseq(v, vlut, vl);
379+
#else
380+
vbool8_t m1 = __riscv_vmseq(v, ':', vl);
381+
vbool8_t m2 = __riscv_vmseq(v, '/', vl);
382+
vbool8_t m3 = __riscv_vmseq(v, '?', vl);
383+
vbool8_t m4 = __riscv_vmseq(v, '[', vl);
384+
vbool8_t m5 = __riscv_vmseq(v, '\\', vl);
385+
vbool8_t m = __riscv_vmor(
386+
__riscv_vmor(__riscv_vmor(m1, m2, vl), __riscv_vmor(m3, m4, vl), vl),
387+
m5, vl);
388+
#endif
389+
long idx = __riscv_vfirst(m, vl);
390+
if (idx >= 0) return location + idx;
391+
}
392+
return size_t(view.size());
393+
}
358394
#else
359395
// : / [ \\ ?
360396
static constexpr std::array<uint8_t, 256> special_host_delimiters =
@@ -535,6 +571,25 @@ ada_really_inline size_t find_next_host_delimiter(std::string_view view,
535571
}
536572
return size_t(view.length());
537573
}
574+
#elif ADA_RVV
575+
ada_really_inline size_t find_next_host_delimiter(std::string_view view,
576+
size_t location) noexcept {
577+
uint8_t* src = (uint8_t*)view.data() + location;
578+
for (size_t vl, n = view.size() - location; n > 0;
579+
n -= vl, src += vl, location += vl) {
580+
vl = __riscv_vsetvl_e8m1(n);
581+
vuint8m1_t v = __riscv_vle8_v_u8m1(src, vl);
582+
vbool8_t m1 = __riscv_vmseq(v, ':', vl);
583+
vbool8_t m2 = __riscv_vmseq(v, '/', vl);
584+
vbool8_t m3 = __riscv_vmseq(v, '?', vl);
585+
vbool8_t m4 = __riscv_vmseq(v, '[', vl);
586+
vbool8_t m =
587+
__riscv_vmor(__riscv_vmor(m1, m2, vl), __riscv_vmor(m3, m4, vl), vl);
588+
long idx = __riscv_vfirst(m, vl);
589+
if (idx >= 0) return location + idx;
590+
}
591+
return size_t(view.size());
592+
}
538593
#else
539594
// : / [ ?
540595
static constexpr std::array<uint8_t, 256> host_delimiters = []() consteval {

src/unicode.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
#include "ada/common_defs.h"
1+
#include "ada/unicode.h"
2+
23
#include "ada/character_sets-inl.h"
34
#include "ada/character_sets.h"
4-
#include "ada/unicode.h"
5+
#include "ada/common_defs.h"
56
#include "ada/log.h"
67

78
ADA_PUSH_DISABLE_ALL_WARNINGS
@@ -15,6 +16,8 @@ ADA_POP_DISABLE_WARNINGS
1516
#include <emmintrin.h>
1617
#elif ADA_LSX
1718
#include <lsxintrin.h>
19+
#elif ADA_RVV
20+
#include <riscv_vector.h>
1821
#endif
1922

2023
#include <ranges>
@@ -155,6 +158,22 @@ ada_really_inline bool has_tabs_or_newline(
155158
if (__lsx_bz_v(running)) return false;
156159
return true;
157160
}
161+
#elif ADA_RVV
162+
ada_really_inline bool has_tabs_or_newline(
163+
std::string_view user_input) noexcept {
164+
uint8_t* src = (uint8_t*)user_input.data();
165+
for (size_t vl, n = user_input.size(); n > 0; n -= vl, src += vl) {
166+
vl = __riscv_vsetvl_e8m1(n);
167+
vuint8m1_t v = __riscv_vle8_v_u8m1(src, vl);
168+
vbool8_t m1 = __riscv_vmseq(v, '\r', vl);
169+
vbool8_t m2 = __riscv_vmseq(v, '\n', vl);
170+
vbool8_t m3 = __riscv_vmseq(v, '\t', vl);
171+
vbool8_t m = __riscv_vmor(__riscv_vmor(m1, m2, vl), m3, vl);
172+
long idx = __riscv_vfirst(m, vl);
173+
if (idx >= 0) return true;
174+
}
175+
return false;
176+
}
158177
#else
159178
ada_really_inline bool has_tabs_or_newline(
160179
std::string_view user_input) noexcept {

0 commit comments

Comments
 (0)