Changelog
Source:NEWS.md
Rggml 0.1.0 (unreleased)
Added
rggml_mul_mat(A, B, backend), a public GEMM (crossprod(A, B)) on the"cpu","blas", or"vulkan"backend via GGML’s device-buffer residency path - the supported entry point for a dense single-precision matrix multiply on the GPU, promoted from the internal test routine.New opt-in
GGML_VK_ALLOW_128_PUSH=1(off by default, so default behaviour is upstream GGML’s): accepts a Vulkan device that exposes only 128-byte push constants for matrix multiply and<=4Dops. Upstream refuses any device below 256 bytes, but in this build only the 5-D non-contiguous copy actually needs 256 (and still errors at its own dispatch); matmul’s push struct is 68 bytes. This makes a real GPU reached through the Mesa dzn D3D12 translation layer under WSL usable for GEMM - verified on an RTX 5050 via dzn at 2-2.6x OpenBLAS through 4096^3 (single precision).Added
rggml_cpu_info(), reporting whatconfigureactually compiled:arch_kernels("arm"for GGML’s native NEON kernels,"generic"for the portable ones),simd_dispatch,sgemm,vulkan. Every branchconfigurecan take is numerically correct, so no numerical test can tell them apart: a build that silently fell back from the NEON kernels, or fromsgemm_to thedgemm_promotion, passes the whole suite.test_cpu_info.Rnow asserts on this, including the invariant thatarch_kernels == "arm"andsimd_dispatchare mutually exclusive (both define the canonicalggml_vec_dot_q4_K_q8_K, and the linker would silently pick one), and that real aarch64 CI runners land on"arm".On aarch64, GGML’s own hand-tuned NEON kernels are compiled in instead of the portable scalar reference: 23
vec_dots covering every quantized type, not just the oneq4_Kvariant the SIMD dispatcher stages. NEON is a mandatory baseline of the architecture, soggml-cpu/arch/arm/quants.cneeds no ISA flag and cannot produce a binary that will not run on the machine that built it;configuretherefore drops-DGGML_CPU_GENERICand skips the dispatcher there (arch/armdefines the canonical symbols it would duplicate). x86 keeps the dispatcher on purpose:arch/x86’s kernels are selected by compile-time#if defined(__AVX2__), so a-mavx2build of them would require AVX2 at runtime - which is why GGML upstream needsGGML_CPU_ALL_VARIANTSplusdlopenand we do not.Fixed a BLAS link failure on Windows that was really a portability bug. R guarantees only the double-precision BLAS:
<R_ext/BLAS.h>declares no single-precision routine andRblas.dllexports nosgemm_. Most Linux reference BLAS builds happen to export it, which is why thecblas_sgemmshim linked here but not there.configurenow link-probessgemm_against R’s ownBLAS_LIBS/FLIBS; where it is missing, the shim promotes its operands to double, callsdgemm_(still an optimized BLAS), and demotes the result - correct to float precision, with a naive triple loop only if the temporaries cannot be allocated. SetRGGML_NO_SGEMM=1to force the promoted path anywhere.Rggml now builds on Windows (Rtools/MinGW);
OS_type: unixis gone. R runsconfigure.win, which re-execs the singleconfigurewithRGGML_WINDOWS=1rather than duplicating the SIMD probe, the Vulkan shader pipeline and thelibggml.abuild. The Windows branch writessrc/Makevars.winwithout-ldl(Windows has no libdl) and locates the Vulkan SDK under its Windows layout ($VULKAN_SDK/Bin/glslc.exe,-lvulkan-1). Awindows-latestCI job verifies it. The vendored GGML was already Windows-hardened: the by-pointerggml_backend_buffer_iand never-destroyed-teardown-singleton patches exist precisely because passing that POD by value, and running those destructors at exit, crashed on Windows/MinGW.-
Added the Vulkan GPU backend (API version 7), vendored from the same pinned ggmlR tarball as the CPU core (so it version-matches it) through
tools/vendor-ggml. It is opt-in at build time, never auto-detected:install.packages("Rggml", configure.args = "--with-vulkan") R CMD INSTALL --configure-args=--with-vulkan .Auto-detection would be hostile: GGML embeds 156 compiled SPIR-V shaders as C++ translation units, and the largest (
mul_mm, a 141 MB array literal) needs ~5 GB of RAM to compile - independent of-Olevel, since the cost is parsing the literal.configureprobesglslc’s optional shader features (coopmat, coopmat2, integer_dot, bfloat16), builds the shader generator, and compiles the shader set those features imply; it errors out clearly if--with-vulkanis given withoutglslc/Vulkan headers. Without the flag, nothing about the build changes. New C-callables:Rggml_backend_vulkan_init,Rggml_backend_vulkan_device_count, andRggml_backend_vulkan_device_description; they report zero devices instead of failing when the backend was not built, so callers can probe and fall back. R-level:rggml_vulkan_info(),rggml_has_vulkan(). Added the device-buffer residency C-callables (API version 7):
Rggml_backend_alloc_ctx_tensors,Rggml_backend_buffer_free,Rggml_backend_tensor_set,Rggml_backend_tensor_get. The CPU and BLAS backends compute on host memory, so pointing a tensor at an R buffer works; a GPU backend’s tensors must live in device memory. These wrap GGML’s backend-agnostic path - allocate a no_alloc context’s tensors into one backend buffer, upload, compute, download - which is identical for CPU, BLAS and Vulkan, and is whattest_vulkan.Ruses to assert the GPU backend computes the same product as the CPU one.Added view and copy C-callables (API version 6):
Rggml_view_1d/_2d/_3d(byte offsets/strides, as in ggml) andRggml_cpy- the building blocks of a KV cache: cpy nodes write new keys/values into views of a persistent cache tensor, expanded into the graph ahead of the attention nodes that read other views of the same cache (see Rllm’s incremental decoding).Added the transformer graph-op C-callables (API version 5): the ops a forward pass composes -
Rggml_get_rows,Rggml_rms_norm,Rggml_mul,Rggml_add,Rggml_silu,Rggml_scale,Rggml_soft_max,Rggml_diag_mask_inf,Rggml_rope(wrappingggml_rope_extwith YaRN off), and the shape opsRggml_reshape_2d/_3d,Rggml_permute,Rggml_cont,Rggml_transpose. Downstream packages can now assemble and compute full transformer graphs (see Rllm’s llama forward pass) without linking GGML.Added quantization C-callables (API version 4):
Rggml_quantizewrapsggml_quantize_chunk()so downstream packages can encode f32 rows into any GGUF block format (the output is byte-compatible with GGUF tensor payloads), andRggml_dequantizewraps GGML’s type-traitsto_float- the authoritative reference dequantizer, used by the Rfmalloc ecosystem to cross-validate its codec decoders (this cross-validation caught and pinned a Q4_K decode bug in Rgguf’s vendored gguflib; see that package’s NEWS).Verified the full quantized-weight compute path over an external payload: a
Q4_Ktensor pointed zero-copy at a heap buffer standing in for an mmap’d GGUF payload, multiplied by dense F32 activations viaggml_mul_mat()on the CPU backend, routes each weight row through the runtime-SIMD-dispatchedvec_dot(activations quantized toQ8_Kon the fly, as at llama.cpp inference) and tracks the true product to q4_K accuracy (test_mul_mat_q4k.R).Initial release. Rggml is a carrier package: it vendors a CPU-only, architecture-generic build of the ‘GGML’ tensor library as a static library (
inst/ggml/libggml.a), installs its headers, and exposes GGML’s tensor-context/matrix-multiply compute path throughR_RegisterCCallableC-callable entry points, declared for downstream use ininst/include/Rggml.h.Registered C-callables: context lifecycle (
Rggml_context_create,Rggml_context_free, plusRggml_used_mem/Rggml_tensor_overhead/Rggml_graph_overheadfor sizing), tensor creation with an optional zero-copy external data pointer (Rggml_new_tensor,Rggml_tensor_data,Rggml_tensor_set_data,Rggml_tensor_ne,Rggml_tensor_nb), the CPU backend (Rggml_backend_cpu_init,Rggml_backend_free,Rggml_backend_graph_compute), graph building (Rggml_new_graph,Rggml_build_forward_expand), matrix multiply (Rggml_mul_mat, and the canned single-opRggml_compute_mul_matthat also copies the F32 result into a caller-providedfloat*/double*buffer), and type/size introspection (Rggml_type_size,Rggml_row_size,Rggml_blck_size,Rggml_nbytes,Rggml_nelements,Rggml_type_name).Added runtime SIMD dispatch for GGML’s hot quantized vec-dot kernels, starting with
q4_K x q8_K.configurecompiles the kernel into ISA-specific variants (-mavx2 -mfma -O3on x86 incl. Intel macOS;-O3NEON on aarch64 incl. Apple Silicon) staged undertools/simd/, and a CPUID dispatcher (tools/simd/rggml_simd_dispatch.c, using a vendored copy of RsimdDispatch’scpu_features) selects the best at runtime, falling back to GGML’s scalar reference. The ISA flags live inconfigure, not in R’s recorded package flags, so R CMD check raises no non-portable-flags NOTE; a variant is only called after its ISA is confirmed at runtime (single.so, nodlopen, unlike GGML’s ownGGML_CPU_ALL_VARIANTS). The AVX2 q4_K dot measures ~6-7x faster than the scalar reference on x86.Enabled GGML’s BLAS backend (
Rggml_backend_blas_init,Rggml_backend_blas_set_n_threads): dense F32mul_matoffloads to whatever BLAS the R build links against, since BLAS is universal in R. GGML’s backend calls the Ccblas_sgemm, which R does not provide, so Rggml bridges it with a small portable shim (inst/ggml/cblas.h+rggml_cblas.c) forwarding to the Fortran BLAS viaF77_NAME(), linking$(BLAS_LIBS) $(FLIBS). The BLAS backend is a drop-inbackendfor the existingRggml_compute_mul_mat/Rggml_backend_graph_computepath.Added
ggml_version(), returning the vendored GGML library’s own runtime version string.Verified and documented the
ggml_mul_mat()convention: loading two R matrices directly into GGML tensors withne = dim(matrix)(the raw column-major bytes, no copy or transpose),ggml_mul_mat(ctx, A, B)produces a result tensor of dim(ncol(A), ncol(B))equal tocrossprod(A, B)(t(A) %*% B). Covered by the tinytest suite with both hand-checkable small cases and larger random matrices, through both the ggml-managed and the zero-copy (externally-owned buffer) tensor creation paths, exercised via the registered C-callables (not the internal implementation functions directly).CPU kernels are architecture-generic (no
-marchSIMD flags, no OpenMP, no hand-written x86 SIMD kernel files) for CRAN-facing build portability, plus the BLAS backend above for dense products. No Vulkan/CUDA/Metal GPU backends. Runtime-SIMD-dispatched quantized kernels (GGML_CPU_ALL_VARIANTS) and a Vulkan backend are planned; see README.md.