Merge pull request #567 from libretro/perf/560-rpi-soc-tuning

perf(build): per-SoC -mcpu and -O3 for every Raspberry Pi target
This commit is contained in:
Joe Mattiello authored and GitHub committed 2026-08-22 03:56:25 -04:00
commit 5f898dacee
5 files changed
+342 -26

No files matched your search

+105 -3
View File
@@ -96,6 +96,85 @@ jobs:
cxx: 'g++ -m32'
multilib: true
# Raspberry Pi -- per-SoC tuned (issue #560).
#
# Cross-compiled on x86_64: -mcpu names a core to generate code FOR,
# it does not require running on one, so no Pi hardware is needed to
# produce these. The per-SoC flags live in the Makefile's rpi*
# platform blocks -- do not duplicate them here.
#
# rpi0 is deliberately absent: it is the same BCM2835/ARM1176 part
# as rpi1 and resolves to identical flags, so the rpi1 artifact
# serves both. Every other row is a genuinely distinct target.
#
# 32- and 64-bit rows for the same chip are BOTH needed: they are
# different userlands (Raspberry Pi OS ships both), and the 32-bit
# ones additionally carry -mfpu/-mfloat-abi, which aarch64 gcc
# rejects outright.
- platform: linux-rpi1-armv6
artifact: virtualjaguar_libretro.so
os: ubuntu-latest
cc: arm-linux-gnueabihf-gcc
cxx: arm-linux-gnueabihf-g++
make_extra: platform=rpi1
cross_arm: armhf
- platform: linux-rpi2-cortex-a7
artifact: virtualjaguar_libretro.so
os: ubuntu-latest
cc: arm-linux-gnueabihf-gcc
cxx: arm-linux-gnueabihf-g++
make_extra: platform=rpi2
cross_arm: armhf
- platform: linux-rpi3-cortex-a53
artifact: virtualjaguar_libretro.so
os: ubuntu-latest
cc: arm-linux-gnueabihf-gcc
cxx: arm-linux-gnueabihf-g++
make_extra: platform=rpi3
cross_arm: armhf
- platform: linux-rpi3_64-cortex-a53
artifact: virtualjaguar_libretro.so
os: ubuntu-latest
cc: aarch64-linux-gnu-gcc
cxx: aarch64-linux-gnu-g++
make_extra: platform=rpi3_64
cross_arm: arm64
- platform: linux-rpi4-cortex-a72
artifact: virtualjaguar_libretro.so
os: ubuntu-latest
cc: arm-linux-gnueabihf-gcc
cxx: arm-linux-gnueabihf-g++
make_extra: platform=rpi4
cross_arm: armhf
- platform: linux-rpi4_64-cortex-a72
artifact: virtualjaguar_libretro.so
os: ubuntu-latest
cc: aarch64-linux-gnu-gcc
cxx: aarch64-linux-gnu-g++
make_extra: platform=rpi4_64
cross_arm: arm64
- platform: linux-rpi5-cortex-a76
artifact: virtualjaguar_libretro.so
os: ubuntu-latest
cc: arm-linux-gnueabihf-gcc
cxx: arm-linux-gnueabihf-g++
make_extra: platform=rpi5
cross_arm: armhf
- platform: linux-rpi5_64-cortex-a76
artifact: virtualjaguar_libretro.so
os: ubuntu-latest
cc: aarch64-linux-gnu-gcc
cxx: aarch64-linux-gnu-g++
make_extra: platform=rpi5_64
cross_arm: arm64
# macOS
- platform: macos-arm64
artifact: virtualjaguar_libretro.dylib
@@ -193,6 +272,21 @@ jobs:
sudo apt-get update
sudo apt-get install -y gcc-multilib g++-multilib
# Cross toolchain for the Raspberry Pi rows. Also provides the matching
# objcopy: the host x86_64 objcopy in the packaging step below cannot
# read an ARM ELF (Ubuntu's binutils is single-target), so the strip /
# split-debug step needs the prefixed one.
- name: Install ARM cross toolchain
if: matrix.config.cross_arm
run: |
set -e
sudo apt-get update
if [ "${{ matrix.config.cross_arm }}" = armhf ]; then
sudo apt-get install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
else
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
fi
- name: Set up MSYS2
if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2
@@ -259,9 +353,17 @@ jobs:
OUT="virtualjaguar_libretro-${{ matrix.config.platform }}${EXT}"
DBG="${OUT}.debug"
cp "$SRC" "dist/${OUT}"
objcopy --only-keep-debug "dist/${OUT}" "dist/${DBG}"
objcopy --strip-debug --strip-unneeded "dist/${OUT}"
( cd dist && objcopy --add-gnu-debuglink="${DBG}" "${OUT}" )
# A cross-built ARM core needs the cross objcopy -- Ubuntu's
# binutils is single-target, so the host one cannot read an ARM ELF
# and the split-debug step would fail (or, worse, be skipped).
case "${{ matrix.config.cross_arm }}" in
armhf) OBJCOPY=arm-linux-gnueabihf-objcopy ;;
arm64) OBJCOPY=aarch64-linux-gnu-objcopy ;;
*) OBJCOPY=objcopy ;;
esac
"$OBJCOPY" --only-keep-debug "dist/${OUT}" "dist/${DBG}"
"$OBJCOPY" --strip-debug --strip-unneeded "dist/${OUT}"
( cd dist && "$OBJCOPY" --add-gnu-debuglink="${DBG}" "${OUT}" )
tar -C dist -czf "dist/virtualjaguar_libretro-${{ matrix.config.platform }}-debug.tar.gz" "${DBG}"
rm "dist/${DBG}"
+73 -5
View File
@@ -48,8 +48,27 @@ endif
# compilers again, and the Vita has real memory limits, so neither result
# above says anything about them. Measure before adding one.
#
# The rpi* targets are here by maintainer decision rather than by the
# measurement protocol above: the Pi platform names identify the silicon
# exactly, and every one of them is a small in-order or narrow out-of-order
# core with no headroom to spare, which is the case -O3 helps most. The
# closest evidence we have is the +5.5% measured on macOS arm64 (#515) --
# same ISA family, different compiler. Re-measure on real hardware when a
# Pi is available; test/tools/rpi_perf.sh exists for exactly that.
#
# -Ofast was considered and REJECTED for these. Its headline implication is
# -ffast-math, which #517 measured at ~0% here (the hot loops are integer;
# the only floating point is a SAVESTATED I2S resampler and event
# scheduling) and then removed globally as a latent determinism hazard.
# Determinism is load-bearing in this tree -- run-ahead (#400), netplay, and
# savestate compatibility all depend on it -- so -Ofast would reintroduce
# exactly what #517 took out, for a measured-zero gain, on a platform people
# run netplay on. `make OPT_LEVEL=-Ofast platform=rpi4` still works if you
# want to measure it.
#
# Override on the command line to test: `make OPT_LEVEL=-O2`.
OPT_O3_PLATFORMS := unix osx win ios-arm64 ios9 tvos-arm64
OPT_O3_PLATFORMS := unix osx win ios-arm64 ios9 tvos-arm64 \
rpi0 rpi1 rpi2 rpi3 rpi3_64 rpi4 rpi4_64 rpi5 rpi5_64
# classic_armv7_a7 asks for -Ofast in its own platform block and always has.
# It never took effect: the shared release branch appended -O2 afterwards and
# the last -O wins, so the target silently built at -O2 (issue #516). The
@@ -329,22 +348,71 @@ else ifneq (,$(filter arm64 aarch64,$(platform)))
# NEON-capable running a 32-bit OS, but rpi1 and rpi0 are ARMv6 (ARM1176) with
# no NEON at all, so they are deliberately absent from the NEON list.
#
# No -mcpu/-mtune and no -O level here. Both are unmeasured on this hardware
# and the standing rule from #515/#516/#517 is to measure first -- #516 is
# precisely the case of an optimisation flag that looked applied and was not.
# PER-SOC TUNING. Unlike a generic ARM target, a Raspberry Pi platform name
# identifies the silicon exactly, so -mcpu is a statement of fact rather than
# a guess -- which is why these get it and `unix`/`armv7-*` do not.
#
# rpi0 rpi1 BCM2835 ARM1176JZF-S ARMv6 + VFPv2, NO NEON
# rpi2 BCM2836 Cortex-A7 ARMv7-A + NEON-VFPv4
# rpi3 BCM2837 Cortex-A53 ARMv8-A, 32-bit userland
# rpi4 BCM2711 Cortex-A72 ARMv8-A, 32-bit userland
# rpi5 BCM2712 Cortex-A76 ARMv8.2-A, 32-bit userland
# *_64 same parts, aarch64 userland
#
# -mcpu implies -mtune, so both are never passed. -mfpu/-mfloat-abi are
# 32-bit-ARM-only options -- aarch64 gcc ERRORS on them -- so they are gated
# on the same 64-bit split as ARCH below, not appended blindly.
#
# rpi2 is the ambiguous one: board revision 1.2 shipped a BCM2837 (A53), but
# the libretro `rpi2` name conventionally means the original A7 part, and A7
# code runs on an A53 while the reverse is not true. Kept at A7 on purpose.
#
# -O3 comes from OPT_O3_PLATFORMS at the top of this file, NOT from here --
# see the #516 note there. Appending an -O to CFLAGS in a platform block is
# exactly the bug that made classic_armv7_a7 silently build at -O2 for years.
else ifneq (,$(filter rpi0 rpi1 rpi2 rpi3 rpi3_64 rpi4 rpi4_64 rpi5 rpi5_64,$(platform)))
TARGET := $(TARGET_NAME)_libretro.so
fpic := -fPIC
SHARED := -shared -Wl,--no-undefined -Wl,--version-script=$(LINK_SCRIPT)
GC_STYLE := gnu
ifneq (,$(filter rpi0 rpi1,$(platform)))
RPI_MCPU := arm1176jzf-s
else ifeq ($(platform),rpi2)
RPI_MCPU := cortex-a7
else ifneq (,$(filter rpi3 rpi3_64,$(platform)))
RPI_MCPU := cortex-a53
else ifneq (,$(filter rpi4 rpi4_64,$(platform)))
RPI_MCPU := cortex-a72
else
RPI_MCPU := cortex-a76
endif
CFLAGS += -mcpu=$(RPI_MCPU)
ifneq (,$(filter rpi3_64 rpi4_64 rpi5_64,$(platform)))
ARCH = aarch64
else
ARCH = arm
ifneq (,$(filter rpi2 rpi3 rpi4 rpi5,$(platform)))
# 32-bit only. ARMv6 parts get plain VFP; everything else NEON, in
# the encoding its ISA level actually provides.
ifneq (,$(filter rpi0 rpi1,$(platform)))
# -marm is REQUIRED here, not a tuning choice. Debian's armhf
# cross toolchain is --with-arch=armv7-a+fp and defaults to
# Thumb; ARMv6 has only Thumb-1, and GCC cannot pair Thumb-1
# with the hard-float VFP ABI:
# sorry, unimplemented: Thumb-1 'hard-float' VFP ABI
# A native Pi 1 compiler defaults to ARM mode and never shows
# this, so it only bites cross-builds -- i.e. CI. Verified in
# an arm-linux-gnueabihf container; A7/A53/A72/A76 build fine
# either way and are left on the Thumb-2 default.
CFLAGS += -marm -mfpu=vfp -mfloat-abi=hard
else ifeq ($(platform),rpi2)
CFLAGS += -mfpu=neon-vfpv4 -mfloat-abi=hard
HAVE_NEON = 1
else
CFLAGS += -mfpu=neon-fp-armv8 -mfloat-abi=hard
HAVE_NEON = 1
endif
endif
CXXFLAGS += $(CFLAGS)
else ifneq (,$(findstring armv,$(platform)))
TARGET := $(TARGET_NAME)_libretro.so
+13 -9
View File
@@ -126,15 +126,19 @@ else
# Derive ARCH from the toolchain triple when the platform block did not set
# it. Issue #560.
#
# This is the case that reaches actual users. The rules below key on
# $(ARCH); the native `uname -m` fallback further down is deliberately
# skipped for cross-compilers (BLITTER_CROSS_CC); and no platform block
# sets ARCH for a generic `platform=unix` cross-build. So the shipped
# "Linux 64-bit (ARM)" buildbot binary -- .gitlab-ci.yml:44, built as
# platform=unix with an aarch64- prefixed CC -- matched nothing and fell
# through to the SCALAR blitter on hardware where NEON is architecturally
# mandatory. The guard written to prevent false detection was, by itself,
# forcing the slow path.
# The rules below key on $(ARCH); the native `uname -m` fallback further
# down is deliberately skipped for cross-compilers (BLITTER_CROSS_CC); and
# no platform block sets ARCH for a generic `platform=unix` cross-build. So
# a cross-compiled aarch64 build matched nothing and fell through to the
# SCALAR blitter on hardware where NEON is architecturally mandatory. The
# guard written to prevent false detection was, by itself, forcing the slow
# path.
#
# NOT the official Linux ARM64 cores, to be clear: both the GitLab buildbot
# (ci-templates linux-aarch64.yml, `tags: aarch64`) and the GitHub
# release/nightly matrix row build NATIVELY with plain `gcc`, so `uname -m`
# fired and they always had NEON. This hits cross-builds -- distro
# packagers, container cross-compiles, anyone following a cross recipe.
#
# Only aarch64 is inferred. A 32-bit arm-*-gnueabihf triple says nothing
# about NEON (the armhf baseline is VFP; ARMv6 parts such as the Pi 1 and
+41
View File
@@ -16,6 +16,47 @@ Output: `virtualjaguar_libretro.{dylib,so,dll}`. CI: `make -j4` on Ubuntu (GCC)
or `platform=`; `Makefile.common` lists sources. Flags: `-D__LIBRETRO__`, `-DMSB_FIRST`
(big-endian).
## ARM / Raspberry Pi targets
The `rpi*` platform names identify the silicon exactly, so they carry real per-SoC
tuning (issue #560). Everything is resolved in the Makefile's `rpi*` platform block —
**never re-specify these on the command line**, and never append an `-O` in a platform
block (that is the #516 bug: the last `-O` wins and a later `-O2` silently beat
`-Ofast` for years).
| platform | SoC | core | blitter | flags on top of `-O3` |
| --- | --- | --- | --- | --- |
| `rpi0` `rpi1` | BCM2835 | ARM1176JZF-S (ARMv6) | **scalar** | `-marm -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard` |
| `rpi2` | BCM2836 | Cortex-A7 | neon | `-mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard` |
| `rpi3` / `rpi3_64` | BCM2837 | Cortex-A53 | neon | `-mcpu=cortex-a53` (+`-mfpu=neon-fp-armv8 -mfloat-abi=hard` on 32-bit) |
| `rpi4` / `rpi4_64` | BCM2711 | Cortex-A72 | neon | `-mcpu=cortex-a72` (same 32-bit addition) |
| `rpi5` / `rpi5_64` | BCM2712 | Cortex-A76 | neon | `-mcpu=cortex-a76` (same 32-bit addition) |
Three traps, all verified in an `arm-linux-gnueabihf` container:
- **`-mfpu` / `-mfloat-abi` are 32-bit-ARM only.** `aarch64-linux-gnu-gcc` hard-errors
(`unrecognized command-line option '-mfpu=neon-fp-armv8'`), so a `*_64` row that
acquires one does not build at all.
- **`rpi0`/`rpi1` need `-marm`.** Debian's armhf cross toolchain is
`--with-arch=armv7-a+fp` and defaults to Thumb; ARMv6 only has Thumb-1, and GCC
cannot pair Thumb-1 with hard-float (`sorry, unimplemented: Thumb-1 'hard-float' VFP
ABI`). A native Pi 1 compiler defaults to ARM mode, so this bites cross-builds only.
- **`rpi1` is scalar on purpose.** ARM1176 has no NEON. Do not "fix" it.
`-Ofast` is deliberately **not** used: it implies `-ffast-math`, which #517 measured at
~0% here and removed globally as a determinism hazard (run-ahead #400, netplay,
savestate compat all depend on determinism). `make OPT_LEVEL=-Ofast platform=rpi4`
still works if you want to measure it.
`test/tools/simd_matrix_check.sh` (in `make test`) asserts all of the above — blitter,
the *last* `-O`, the expected `-mcpu`, and that 32-bit-only flags stay off 64-bit rows.
Release/nightly build all eight via `release.yml`'s matrix, cross-compiled on x86_64
(`-mcpu` names a core to generate code *for*; it does not require running on one).
> The libretro GitLab buildbot cannot do this: `libretro-infrastructure/ci-templates`
> has no `rpi*` template (only `linux-aarch64.yml` for ARM Linux), so per-chipset Pi
> cores would need a template added upstream.
**Host builds: prefix `DEVELOPER_DIR=/Library/Developer/CommandLineTools`.** `xcode-select`
points at Xcode.app, so bare `make`/`cc` resolve inside an app bundle → macOS raises an App
Management prompt on every invocation (dozens per multi-agent run). Same Apple clang, no
+110 -9
View File
@@ -9,9 +9,11 @@
# notice. This script is the thing that notices.
#
# What it caught when it was written:
# * platform=unix with an aarch64- cross CC -- the shipped "Linux 64-bit
# (ARM)" buildbot binary -- selected SCALAR on hardware where NEON is
# architecturally mandatory.
# * platform=unix with an aarch64- CROSS CC selected SCALAR on hardware
# where NEON is architecturally mandatory. (Not the official ARM64
# Linux cores -- both build natively with plain gcc, so `uname -m`
# fired and they always had NEON. This hit cross-builds: distro
# packagers, container cross-compiles.)
# * armv7-neon-hardfloat, a platform named after NEON, selected SCALAR.
# * every rpi* name fell through to the Windows branch and built a .dll.
#
@@ -47,7 +49,7 @@ trap 'rm -f "$PROBE"' EXIT
# quotes keep make's $(...) out of the shell's hands.
{
printf 'vjsimd:\n'
printf '\t@echo "SIMD=$(notdir $(BLITTER_SIMD_SRC)) TARGET=$(notdir $(TARGET))"\n'
printf '\t@echo "SIMD=$(notdir $(BLITTER_SIMD_SRC)) TARGET=$(notdir $(TARGET)) CFLAGS=$(CFLAGS)"\n'
} > "$PROBE"
fail=0
@@ -63,8 +65,26 @@ dump() {
# -n prints the *unexecuted* `echo "SIMD=... TARGET=..."` line, quotes and
# all, so strip the quotes before matching or the first token anchors to a
# `"` and silently never matches.
make -n -f Makefile -f "$PROBE" vjsimd platform="$plat" "$@" 2>/dev/null \
| tr -d '"' | tr ' ' '\n' | grep -E '^(SIMD|TARGET)=' | tr '\n' ' '
# `env -u MAKEFLAGS` is load-bearing, not tidiness. GNU make passes
# command-line variables to sub-makes through MAKEFLAGS, and this script
# runs from inside `make test` -- so under `make coverage`, which invokes
# `$(MAKE) COVERAGE=1 TEST_EXPORTS=1 test`, the probe below would inherit
# COVERAGE=1 and see `FLAGS += --coverage -O0 -g` appended after the
# resolved level. Every rpi row then reports "last -O is -O0", which is
# the Makefile behaving CORRECTLY for a coverage build and this check
# asking the wrong question.
#
# The question these assertions exist to answer is what a RELEASE build
# resolves to, so the probe must be independent of whatever axes the
# calling make happens to carry. The explicit empty assignments pin the
# rest of BUILD_AXES for the same reason -- a future `make test` variant
# that sets DEBUG=1 would otherwise silently move the answer again.
env -u MAKEFLAGS -u MFLAGS -u MAKELEVEL \
make -n -f Makefile -f "$PROBE" vjsimd platform="$plat" \
COVERAGE= DEBUG= TEST_EXPORTS= BENCH_PROFILE= BLITTER_TRACE= \
RELEASE_DEBUG_INFO= DEBUG_PRESENTATION= STATIC_LINKING= \
"$@" 2>/dev/null \
| tr -d '"' | sed -n 's/.*\(SIMD=.*\)/\1/p' | head -1
}
# expect <expected-simd> <platform> [CC=...] -- '*' to skip the SIMD check
@@ -110,11 +130,71 @@ expect() {
return 0
}
# expect_tune <platform> <expected-last-O> <expected-mcpu|-> <expect-32bit-fp:yes|no>
#
# Guards issue #516, which is a DIFFERENT failure from the SIMD one above and
# needs its own assertion: classic_armv7_a7 asked for -Ofast in its platform
# block for years and silently built at -O2, because the shared release branch
# appended -O2 afterwards and the LAST -O wins. Nothing noticed, because a
# wrong -O level -- exactly like a wrong blitter -- compiles, links and passes
# every functional test.
#
# So this asserts the resolved level is the last -O in CFLAGS, not merely
# present, and that exactly one -O appears at all.
#
# It also asserts -mfpu/-mfloat-abi appear ONLY on 32-bit ARM: aarch64 gcc
# hard-errors on them ("unrecognized command-line option '-mfpu=neon-fp-armv8'"),
# so leaking one onto a *_64 row breaks that build outright.
expect_tune() {
local plat="$1" want_o="$2" want_mcpu="$3" want_fp="$4"
local got cflags last_o n_o mcpu has_fp
checked=$((checked + 1))
got="$(dump "$plat")"
cflags="$(printf '%s' "$got" | sed -n 's/.*CFLAGS=//p')"
if [ -z "$cflags" ]; then
printf 'FAIL %-42s could not read CFLAGS\n' "$plat"; fail=$((fail + 1)); return
fi
last_o="$(printf '%s' "$cflags" | tr ' ' '\n' | grep -E '^-O' | tail -1)"
n_o="$( printf '%s' "$cflags" | tr ' ' '\n' | grep -cE '^-O')"
mcpu="$( printf '%s' "$cflags" | tr ' ' '\n' | grep -E '^-mcpu=' | tail -1)"
has_fp="$(printf '%s' "$cflags" | tr ' ' '\n' | grep -cE '^-(mfpu=|mfloat-abi=)')"
if [ "$last_o" != "$want_o" ]; then
printf 'FAIL %-42s last -O is %s, expected %s (issue #516)\n' "$plat" "${last_o:-none}" "$want_o"
fail=$((fail + 1)); return
fi
if [ "$n_o" -ne 1 ]; then
printf 'FAIL %-42s %s -O flags in CFLAGS; expected exactly 1 (issue #516)\n' "$plat" "$n_o"
fail=$((fail + 1)); return
fi
if [ "$want_mcpu" = "-" ]; then
if [ -n "$mcpu" ]; then
printf 'FAIL %-42s unexpected %s\n' "$plat" "$mcpu"; fail=$((fail + 1)); return
fi
elif [ "$mcpu" != "-mcpu=$want_mcpu" ]; then
printf 'FAIL %-42s -mcpu is %s, expected -mcpu=%s\n' "$plat" "${mcpu:-none}" "$want_mcpu"
fail=$((fail + 1)); return
fi
if [ "$want_fp" = yes ] && [ "$has_fp" -eq 0 ]; then
printf 'FAIL %-42s 32-bit ARM row is missing -mfpu/-mfloat-abi\n' "$plat"; fail=$((fail + 1)); return
fi
if [ "$want_fp" = no ] && [ "$has_fp" -ne 0 ]; then
printf 'FAIL %-42s 64-bit row carries -mfpu/-mfloat-abi; aarch64 gcc rejects those\n' "$plat"
fail=$((fail + 1)); return
fi
[ "$VERBOSE" = 1 ] && printf 'ok %-42s %s %s\n' "$plat" "$last_o" "${mcpu:-(no -mcpu)}"
return 0
}
echo "simd_matrix_check: blitter selection per platform (issue #560)"
# --- the regression that shipped: cross-compiled ARM64 Linux ---------------
# platform=unix + an aarch64 cross CC is .gitlab-ci.yml:44, "Linux 64-bit
# (ARM)" -- the binary an actual Raspberry Pi user installs.
# --- cross-compiled ARM64 Linux --------------------------------------------
# Not what the official runners do (they are native), but what a distro
# packager or a container cross-build does.
expect neon unix CC=aarch64-linux-gnu-gcc
expect neon unix CC=aarch64-none-linux-gnu-gcc
# 32-bit armhf says nothing about NEON (VFP baseline, and ARMv6 parts exist),
@@ -161,6 +241,27 @@ case "$(uname -m 2>/dev/null)" in
*) expect '*' unix ;;
esac
# --- per-SoC tuning and optimisation level (issues #560, #516) --------------
# The Pi platform names identify the silicon exactly, so -mcpu is a fact here
# rather than a guess. rpi0/rpi1 are ARMv6 (ARM1176, no NEON); the rest are
# A7/A53/A72/A76.
echo
echo "simd_matrix_check: -O level and per-SoC tuning (issues #516, #560)"
expect_tune rpi0 -O3 arm1176jzf-s yes
expect_tune rpi1 -O3 arm1176jzf-s yes
expect_tune rpi2 -O3 cortex-a7 yes
expect_tune rpi3 -O3 cortex-a53 yes
expect_tune rpi3_64 -O3 cortex-a53 no
expect_tune rpi4 -O3 cortex-a72 yes
expect_tune rpi4_64 -O3 cortex-a72 no
expect_tune rpi5 -O3 cortex-a76 yes
expect_tune rpi5_64 -O3 cortex-a76 no
# The target #516 was actually about: -Ofast must survive to the end.
expect_tune classic_armv7_a7 -Ofast - yes
# Non-Pi ARM must NOT acquire -mcpu -- we do not know their silicon.
expect_tune tvos-arm64 -O3 - no
expect_tune vita -O2 - no
echo
if [ "$fail" -ne 0 ]; then
echo "simd_matrix_check: FAILED ($fail of $checked rows)"