std1.0.0-beta-7 SafeC docs

Module simd::cortex_m

#include <std/simd/cortex_m.h> source

std::simd, ARM Cortex-M convenience layer

Unlike the other five per-ISA headers in std/simd/, Cortex-M support is partial and this header documents exactly where the line is, verified directly against this compiler's output (not assumed):

* Cortex-M55 / Cortex-M85 (Armv8.1-M, MVE/"Helium", target attribute
  '+mve'): vec<T,N> arithmetic lowers to real MVE vector instructions
  (q-register vadd.i32/vldrw.u32/vstrw.32, ...) — verified via
  `--target thumbv8.1m.main-none-eabi` + `llc -mattr=+mve`. The
  f32x4/i32x4/i16x8/i8x16 aliases below are meaningful and native
  (one 128-bit MVE q-register) on these cores.

* Cortex-M4 / Cortex-M7 (Armv7E-M, DSP extension, target attribute
  '+dsp'): the DSP extension's packed-SIMD instructions (SADD16,
  SMLAD, ...) operate on 2x16-bit or 4x8-bit lanes packed into a
  single 32-bit *scalar* register, not a real vector register file.
  LLVM does not auto-vectorize generic vec<T,N> IR into these
  instructions the way it does for MVE/NEON/SSE/RVV/SIMD128 — a
  `vec<short,2>` add on `thumbv7em` lowers to two independent 32-bit
  `add`s, not a single `sadd16` (confirmed by inspecting compiler
  output), so there is no vec<T,N>-based type alias for DSP below.
  Instead, the dsp_* functions declared below wrap compiler builtins
  (__arm_dsp_*, see CodeGen.cpp) that map 1:1 onto the real
  instructions — verified against real llc output on
  '-mtriple=thumbv7em-none-eabi -mcpu=cortex-m4' (qadd/sadd16/smlad/
  usad8/ssat all emit the single named instruction, not a libcall).

* Cortex-M0 / M0+ / M3 / M23 (no DSP, no MVE): vec<T,N> still compiles
  (verified: whole stdlib compiles clean for `thumbv6m-none-eabi
  --freestanding`) and is fully correct, but every lane operation is
  scalarized — there is no SIMD hardware to target at all on these
  cores, so vec<T,N> here is purely a portable-code convenience, not
  a performance feature.

Type aliases

mve_f32x4Cortex-M55/M85 (MVE, '+mve'): native 128-bit q-register operations.
mve_i32x4
mve_i16x8
mve_i8x16

Functions

dsp_qaddEach 'int'/'unsigned int' operand packs 2x16-bit or 4x8-bit lanes into one 32-bit word (lane 0 in the low bits); packing/unpacking individual lanes is the caller's job (shifts, or reading two adjacent short/char values as one int through a union or pointer cast). Requires an ARM target — using any of these while compiling for a non-ARM target is a compile error at the call site (enforced by the underlying _arm_dsp* builtin).
dsp_qsubsaturating 32-bit sub
dsp_qadd16saturating 2x16-bit add
dsp_qadd8saturating 4x8-bit add
dsp_qsub16saturating 2x16-bit sub
dsp_qsub8saturating 4x8-bit sub
dsp_sadd16wrapping 2x16-bit add
dsp_sadd8wrapping 4x8-bit add
dsp_ssub16wrapping 2x16-bit sub
dsp_ssub8wrapping 4x8-bit sub
dsp_uqadd16
dsp_uqadd8
dsp_uqsub16
dsp_uqsub8
dsp_smladdual 16x16 multiply-accumulate
dsp_smladxexchanged (cross) lanes
dsp_smlsddual 16x16 multiply-subtract
dsp_smlsdx
dsp_smuaddual 16x16 multiply, summed
dsp_smuadx
dsp_smusddual 16x16 multiply, difference
dsp_smusdx
dsp_usad8sum of |byte diffs|, 4 lanes
dsp_usada8
dsp_sxtab16sign-extend b's two bytes, add to a's halfwords
dsp_uxtab16