Using RsimdDispatch in Other Packages
Source:vignettes/using-in-other-packages.Rmd
using-in-other-packages.RmdDownstream packages use RsimdDispatch as a template and
header provider. The usual workflow is:
- call
use_simd_dispatch()from the package root; - replace the demo
count_nonzero()andconvolve1d()kernels with package-specific kernels; - let
configurestage the dispatch core, CPU feature detection, and kernel objects; - link everything into one shared library via the generated
src/Makevars.
use_simd_dispatch() updates DESCRIPTION,
adding RsimdDispatch to LinkingTo, and copies
package-specific scaffold files. It does not add a runtime dependency on
RsimdDispatch. The LinkingTo entry makes
bundled SIMDe headers available to C code:
Copy the scaffold
From the downstream package root:
RsimdDispatch::use_simd_dispatch(pkg = "MyPackage", prefix = "mypkg")If pkg is omitted, the package name is read from
DESCRIPTION. If prefix is omitted, a lowercase
C identifier prefix is derived from the package name. The helper
performs the important substitutions, including @useDynLib,
R_init_<Package>(), sd_,
SD_, and RC_ symbols.
The copied scaffold includes:
configure
configure.win
cleanup
tools/configure-simd-dispatch.sh
tools/simdDispatch/kernels/kernel_scalar.c
tools/simdDispatch/kernels/kernel_sse2.c
tools/simdDispatch/kernels/kernel_sse41.c
tools/simdDispatch/kernels/kernel_avx2.c
tools/simdDispatch/kernels/kernel_avx512.c
tools/simdDispatch/kernels/kernel_neon.c
tools/simdDispatch/kernels/kernel_wasm_simd128.c
tools/simdDispatch/kernels/kernel_common.h
src/Makevars.in
src/Makevars.win.in
Replace the demo kernels
The demo operations are registered by each backend file. For example, the AVX2 staged source registers both demo operations:
static const SdKernelDef sd_avx2_kernels[] = {
{SD_OP_COUNT_NONZERO, SD_SIG_RAW_COUNT, sd_count_nonzero_avx2_invoke},
{SD_OP_CONVOLVE1D, SD_SIG_F64_CONVOLVE, sd_convolve1d_avx2_invoke},
SD_KERNEL_DEF_END
};
void sd_register_avx2(SdDispatchBuilder *builder) {
sd_register_kernel_table(builder, sd_avx2_kernels);
}SSE2 and SSE4.1 currently register only count_nonzero(),
which demonstrates operation-level backend support. A backend
intentionally omits an operation by not registering that slot.
Explicitly selecting such a backend is allowed, but calling the
unsupported operation errors clearly; "auto" skips that
backend for the unsupported operation.
For a real package, replace the demo operation signatures with your
own and keep the same structure. Staged kernel files include
tools/simdDispatch/kernels/kernel_api.h, not private
headers from src/; the dispatch core implements that
kernel-facing registration ABI.
R API wrapper ordinary src/Makevars compilation
R registration ordinary src/Makevars compilation
dispatch core staged baseline object under src/rsd-lib/
CPU feature checks staged baseline object under src/rsd-lib/
scalar kernel staged by configure under src/rsd-kernels/
SSE/AVX/NEON/wasm staged by configure as optional objects under src/rsd-kernels/
Do not put -mavx2, -mavx512*,
-msimd128, or -march=native in global package
flags. The configure helper keeps ISA flags local to optional staged
kernel objects, and the dispatcher remains safe on baseline CPUs.
Extending the number of operations
The staged build model already scales across operations: if you add
another function to each existing
tools/simdDispatch/kernels/kernel_*.c file, the same staged
object for that backend contains the new implementation. For a small
number of operations, keep the dispatch code explicit and add:
- add a row to
tools/simdDispatch/kernels/operations.def(operation ID, lower name, signature ID, call-frame type); if the operation uses a new call-frame struct, also add the struct tokernel_api.hand a row tosignatures.def; - one implementation plus a small
void *call-frame thunk per backend file undertools/simdDispatch/kernels/, following the naming conventionsd_<operation>_<backend>(); - one
SdKernelDefrow in each backend file that implements the operation; - the
.Callwrapper insrc/r_api.c, which marshals R objects into the operation call frame and callssd_dispatch_invoke(); - the native registration entry in
src/registration.c; - the R wrapper, tests, and documentation.
Backend metadata and kernel availability are table-driven, similar in
spirit to R’s native routine registration tables. Operation
implementation ownership stays close to each backend source file, while
tools/simdDispatch/simd_dispatch.c consumes only opaque
operation IDs and generic kernel-definition rows.
For packages with many public operations, keep a single operation
catalog that can generate the repetitive dispatch metadata,
.Call registration, and R wrappers. Optimized backend
kernels can remain hand-written, but operation names, argument lists,
and exported wrapper metadata should not be duplicated by hand.