Skip to content

Commit 16fc9d9

Browse files
sunyuechistweil
andcommitted
Add RISC-V V support (tesseract-ocr#4346)
Convert riscv-v-spec-1.0.pdf into 111 PNG images, then perform OCR on each one in sequence, and measure the testing time on banana_f3: old: 31m16.267s new: 16m51.155s Co-authored-by: sunyuechi <[email protected]> Co-authored-by: Stefan Weil <[email protected]>
1 parent d7c0a05 commit 16fc9d9

File tree

7 files changed

+149
-0
lines changed

7 files changed

+149
-0
lines changed

Makefile.am

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ libtesseract_la_LIBADD += libtesseract_neon.la
199199
noinst_LTLIBRARIES += libtesseract_neon.la
200200
endif
201201

202+
if HAVE_RVV
203+
libtesseract_rvv_la_CXXFLAGS = $(RVV_CXXFLAGS)
204+
libtesseract_rvv_la_CXXFLAGS += -O3
205+
libtesseract_rvv_la_CXXFLAGS += -I$(top_srcdir)/src/ccutil
206+
libtesseract_rvv_la_SOURCES = src/arch/intsimdmatrixrvv.cpp
207+
libtesseract_la_LIBADD += libtesseract_rvv.la
208+
noinst_LTLIBRARIES += libtesseract_rvv.la
209+
endif
210+
202211
libtesseract_la_SOURCES += src/arch/intsimdmatrix.cpp
203212
libtesseract_la_SOURCES += src/arch/simddetect.cpp
204213

configure.ac

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ AM_CONDITIONAL([HAVE_AVX512F], false)
131131
AM_CONDITIONAL([HAVE_FMA], false)
132132
AM_CONDITIONAL([HAVE_SSE4_1], false)
133133
AM_CONDITIONAL([HAVE_NEON], false)
134+
AM_CONDITIONAL([HAVE_RVV], false)
134135

135136
case "${host_cpu}" in
136137

@@ -188,6 +189,16 @@ case "${host_cpu}" in
188189

189190
;;
190191

192+
riscv*)
193+
194+
AX_CHECK_COMPILE_FLAG([-march=rv64gcv], [rvv=true], [rvv=false], [$WERROR])
195+
AM_CONDITIONAL([HAVE_RVV], [$rvv])
196+
if $rvv; then
197+
AC_DEFINE([HAVE_RVV], [1], [Enable RVV instructions])
198+
check_for_rvv=1
199+
fi
200+
;;
201+
191202
*)
192203

193204
AC_MSG_WARN([No compiler options for $host_cpu])
@@ -207,6 +218,16 @@ if test x$check_for_neon = x1; then
207218
fi
208219
fi
209220
221+
# additional checks for RVV targets
222+
if test x$check_for_rvv = x1; then
223+
AC_MSG_NOTICE([checking how to detect RVV availability])
224+
AC_CHECK_FUNCS([getauxval])
225+
226+
if test $ac_cv_func_getauxval = no; then
227+
AC_MSG_WARN([RVV is available, but we don't know how to check for it. Will not be able to use RVV.])
228+
fi
229+
fi
230+
210231
AX_CHECK_COMPILE_FLAG([-fopenmp-simd], [openmp_simd=true], [openmp_simd=false], [$WERROR])
211232
AM_CONDITIONAL([OPENMP_SIMD], $openmp_simd)
212233

src/arch/intsimdmatrix.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ struct TESS_API IntSimdMatrix {
115115
static const IntSimdMatrix *intSimdMatrix;
116116
// Only available with NEON.
117117
static const IntSimdMatrix intSimdMatrixNEON;
118+
// Only available with RVV.
119+
static const IntSimdMatrix intSimdMatrixRVV;
118120
// Only available with AVX2 / AVX / FMA / SSE.
119121
static const IntSimdMatrix intSimdMatrixAVX2;
120122
static const IntSimdMatrix intSimdMatrixSSE;

src/arch/intsimdmatrixrvv.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
///////////////////////////////////////////////////////////////////////
2+
// File: intsimdmatrixrvv.cpp
3+
// Description: matrix-vector product for 8-bit data on rvv.
4+
// Author: sunyuechi
5+
//
6+
// Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS).
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
///////////////////////////////////////////////////////////////////////
17+
18+
#ifdef HAVE_CONFIG_H
19+
# include "config_auto.h" // for HAVE_RVV, ...
20+
#endif
21+
22+
#if HAVE_RVV
23+
# include "intsimdmatrix.h"
24+
# include "tesstypes.h"
25+
26+
namespace tesseract {
27+
28+
static int DotProduct(const int8_t *u, const int8_t *v, int num) {
29+
int total = 0;
30+
31+
asm __volatile__ (
32+
" .option arch, +v \n\t"
33+
" vsetvli t0,zero,e32,m8,ta,ma \n\t"
34+
" vmv.v.i v0,0 \n\t"
35+
"1: \n\t"
36+
" vsetvli t0,%[num],e8,m2,ta,ma \n\t"
37+
" vle8.v v16,0(%[u]) \n\t"
38+
" vle8.v v24,0(%[v]) \n\t"
39+
" sub %[num],%[num],t0 \n\t"
40+
" vwmul.vv v8,v24,v16 \n\t"
41+
" add %[u],%[u],t0 \n\t"
42+
" add %[v],%[v],t0 \n\t"
43+
" vsetvli zero,zero,e16,m4,tu,ma \n\t"
44+
" vwadd.wv v0,v0,v8 \n\t"
45+
" bnez %[num],1b \n\t"
46+
" vsetvli t0,zero,e32,m8,ta,ma \n\t"
47+
" vmv.s.x v8,zero \n\t"
48+
" vredsum.vs v0,v0,v8 \n\t"
49+
" vmv.x.s %[total],v0 \n\t"
50+
: [u] "+r" (u),
51+
[v] "+r" (v),
52+
[num] "+r" (num),
53+
[total] "+r" (total)
54+
:
55+
: "cc", "memory"
56+
);
57+
58+
return total;
59+
}
60+
61+
static void matrixDotVector(int dim1, int dim2, const int8_t *wi, const TFloat *scales,
62+
const int8_t *u, TFloat *v) {
63+
int num_out = dim1;
64+
int num_in = dim2 - 1;
65+
for (int i = 0; i < num_out; ++i) {
66+
const int8_t *wi_start = wi + i * dim2;
67+
int total = DotProduct(wi_start, u, num_in);
68+
// Add in the bias and apply scaling.
69+
v[i] = (total + wi_start[num_in] * INT8_MAX) * scales[i];
70+
}
71+
}
72+
73+
const IntSimdMatrix IntSimdMatrix::intSimdMatrixRVV = {
74+
// Function.
75+
matrixDotVector,
76+
// Number of 32 bit outputs held in each register.
77+
1,
78+
// Maximum number of registers that we will use to hold outputs.
79+
1,
80+
// Number of 8 bit inputs in the inputs register.
81+
1,
82+
// Number of inputs in each weight group.
83+
1
84+
};
85+
86+
} // namespace tesseract.
87+
88+
#endif /* HAVE_RVV */

src/arch/simddetect.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@
6565
# endif
6666
#endif
6767

68+
#if defined(HAVE_RVV)
69+
# if defined(HAVE_GETAUXVAL)
70+
# include <sys/auxv.h>
71+
# define HWCAP_RV(letter) (1ul << ((letter) - 'A'))
72+
# endif
73+
#endif
74+
6875
namespace tesseract {
6976

7077
// Computes and returns the dot product of the two n-vectors u and v.
@@ -89,6 +96,8 @@ bool SIMDDetect::neon_available_ = true;
8996
#elif defined(HAVE_NEON)
9097
// If true, then Neon has been detected.
9198
bool SIMDDetect::neon_available_;
99+
#elif defined(HAVE_RVV)
100+
bool SIMDDetect::rvv_available_;
92101
#else
93102
// If true, then AVX has been detected.
94103
bool SIMDDetect::avx_available_;
@@ -229,6 +238,13 @@ SIMDDetect::SIMDDetect() {
229238
elf_aux_info(AT_HWCAP, &hwcap, sizeof hwcap);
230239
neon_available_ = hwcap & HWCAP_NEON;
231240
# endif
241+
#endif
242+
243+
#if defined(HAVE_RVV)
244+
# if defined(HAVE_GETAUXVAL)
245+
const unsigned long hwcap = getauxval(AT_HWCAP);
246+
rvv_available_ = hwcap & HWCAP_RV('V');
247+
# endif
232248
#endif
233249

234250
// Select code for calculation of dot product based on autodetection.
@@ -258,6 +274,10 @@ SIMDDetect::SIMDDetect() {
258274
} else if (neon_available_) {
259275
// NEON detected.
260276
SetDotProduct(DotProductNEON, &IntSimdMatrix::intSimdMatrixNEON);
277+
#endif
278+
#if defined(HAVE_RVV)
279+
} else if (rvv_available_) {
280+
SetDotProduct(DotProductGeneric, &IntSimdMatrix::intSimdMatrixRVV);
261281
#endif
262282
}
263283

src/arch/simddetect.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ class SIMDDetect {
6363
static inline bool IsNEONAvailable() {
6464
return detector.neon_available_;
6565
}
66+
// Returns true if RVV is available on this system.
67+
static inline bool IsRVVAvailable() {
68+
return detector.rvv_available_;
69+
}
6670

6771
// Update settings after config variable was set.
6872
static TESS_API void Update();
@@ -86,6 +90,8 @@ class SIMDDetect {
8690
static TESS_API bool sse_available_;
8791
// If true, then NEON has been detected.
8892
static TESS_API bool neon_available_;
93+
// If true, then RVV has been detected.
94+
static TESS_API bool rvv_available_;
8995
};
9096

9197
} // namespace tesseract

src/tesseract.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ static void PrintVersionInfo() {
112112
#if defined(HAVE_NEON) || defined(__aarch64__)
113113
if (tesseract::SIMDDetect::IsNEONAvailable())
114114
printf(" Found NEON\n");
115+
#elif defined(HAVE_RVV)
116+
if (tesseract::SIMDDetect::IsRVVAvailable())
117+
printf(" Found RVV\n");
115118
#else
116119
if (tesseract::SIMDDetect::IsAVX512BWAvailable()) {
117120
printf(" Found AVX512BW\n");

0 commit comments

Comments
 (0)