From 9c35129966f4bfbdf4e81858dd2654b260d93940 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Fri, 11 Sep 2026 18:32:53 +0000 Subject: [PATCH 1/4] raspberry_pi_pico, raspberry_pi_pico_w: enable picogame Neither fits at -O3: pico has 48 KB free of its 1020 KB partition and pico_w 2 KB of its 1536 KB, while the engine needs 50 KB. At -O2 with the loop passes both keep around 140 KB free, within 1% of -O3 on this M0+. --- .../raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk | 7 +++++++ .../boards/raspberry_pi_pico_w/mpconfigboard.mk | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk index 20607d50e41..27cbde43257 100644 --- a/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk +++ b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk @@ -9,4 +9,11 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY__EVE = 1 + +CIRCUITPY_PICOGAME = 1 +CIRCUITPY_PICOGAME_FAST_DISPLAY = 1 CIRCUITPY_PICODVI = 1 + +# The default is -O3. picogame does not fit at -O3; these loop passes keep the render +# kernels within 1% of it. +OPTIMIZATION_FLAGS = -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-partial-pre -fsplit-paths diff --git a/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk b/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk index e658db65f4d..f8bb881730b 100644 --- a/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk @@ -12,6 +12,9 @@ CIRCUITPY_USB_HOST = 0 CIRCUITPY__EVE = 1 +CIRCUITPY_PICOGAME = 1 +CIRCUITPY_PICOGAME_FAST_DISPLAY = 1 + CIRCUITPY_CYW43 = 1 CIRCUITPY_SSL = 1 CIRCUITPY_HASHLIB = 1 @@ -34,3 +37,7 @@ CFLAGS += \ # Must be accompanied by a linker script change CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' + +# The default is -O3. picogame does not fit at -O3; these loop passes keep the render +# kernels within 1% of it. +OPTIMIZATION_FLAGS = -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-partial-pre -fsplit-paths From 91ba8469d4195943bd539ab39bfc3bc8143f74e7 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Sun, 13 Sep 2026 20:38:43 +0000 Subject: [PATCH 2/4] raspberrypi: move the RP2040 optimization flags into the port They were set per board. Every RP2040 build has the same reason to use them, so they belong next to the other RP2040 defaults, with a note on what each pass does and why RP2350 keeps -O3. --- .../boards/raspberry_pi_pico/mpconfigboard.mk | 4 ---- .../boards/raspberry_pi_pico_w/mpconfigboard.mk | 4 ---- ports/raspberrypi/mpconfigport.mk | 15 +++++++++++++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk index 27cbde43257..2026a9727d9 100644 --- a/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk +++ b/ports/raspberrypi/boards/raspberry_pi_pico/mpconfigboard.mk @@ -13,7 +13,3 @@ CIRCUITPY__EVE = 1 CIRCUITPY_PICOGAME = 1 CIRCUITPY_PICOGAME_FAST_DISPLAY = 1 CIRCUITPY_PICODVI = 1 - -# The default is -O3. picogame does not fit at -O3; these loop passes keep the render -# kernels within 1% of it. -OPTIMIZATION_FLAGS = -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-partial-pre -fsplit-paths diff --git a/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk b/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk index f8bb881730b..bb7a9208899 100644 --- a/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk @@ -37,7 +37,3 @@ CFLAGS += \ # Must be accompanied by a linker script change CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' - -# The default is -O3. picogame does not fit at -O3; these loop passes keep the render -# kernels within 1% of it. -OPTIMIZATION_FLAGS = -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-partial-pre -fsplit-paths diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 551ab00ab47..91007cf4c70 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -63,6 +63,21 @@ CIRCUITPY_TOUCHIO ?= 1 # delay in ms before calling cyw43_arch_init_with_country CIRCUITPY_CYW43_INIT_DELAY ?= 1000 + +# -O2 plus the five -O3 loop passes that help here, leaving out the eight that make loops +# faster by duplicating them: function cloning, peeling, unroll-and-jam, splitting, +# interchange and versioning for strides. The vectorizer stays on - it is already on at -O2 - +# but without those passes it rarely finds a loop to work on, and on this core it was not +# winning anything anyway. Measured on a full build: benchmarks within 1 % of -O3 and about +# 150 KB less flash, which is what lets a board fit. +# -funswitch-loops moves a test that cannot change inside the loop out of it +# -fpredictive-commoning reuses what the previous iteration already loaded +# -fgcse-after-reload drops loads still redundant once registers are assigned +# -ftree-partial-pre computes a value once when only some paths need it +# -fsplit-paths duplicates a small piece of a loop so the passes above see through it +# RP2350 keeps plain -O3: there the duplicating passes are what lets the vectorizer pair +# 16-bit writes, and fill loops run 24-41 % slower without them. +OPTIMIZATION_FLAGS ?= -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-partial-pre -fsplit-paths endif ifeq ($(CHIP_VARIANT),RP2350) From f27ba69fc29a8a1ee921b4dda1255169d683076c Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Mon, 14 Sep 2026 15:26:48 +0000 Subject: [PATCH 3/4] raspberrypi: cut the RP2040 flag set to the two that measure The five-pass set was 16-37 % behind -O3 on rectangle fills, memory copies and aesio, because what recovers those is the vectorizer cost model, not the loop passes. Adding -fvect-cost-model=dynamic closes that gap. Four of the five passes then turn out to emit the same code as plain -O2 for the loops that matter here, so drop them. The result matches -O3 on every benchmark for 130 KB less flash, and is 2.5 KB smaller than the five-pass set it replaces. --- ports/raspberrypi/mpconfigport.mk | 40 ++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 91007cf4c70..c62df7a5692 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -64,20 +64,32 @@ CIRCUITPY_TOUCHIO ?= 1 # delay in ms before calling cyw43_arch_init_with_country CIRCUITPY_CYW43_INIT_DELAY ?= 1000 -# -O2 plus the five -O3 loop passes that help here, leaving out the eight that make loops -# faster by duplicating them: function cloning, peeling, unroll-and-jam, splitting, -# interchange and versioning for strides. The vectorizer stays on - it is already on at -O2 - -# but without those passes it rarely finds a loop to work on, and on this core it was not -# winning anything anyway. Measured on a full build: benchmarks within 1 % of -O3 and about -# 150 KB less flash, which is what lets a board fit. -# -funswitch-loops moves a test that cannot change inside the loop out of it -# -fpredictive-commoning reuses what the previous iteration already loaded -# -fgcse-after-reload drops loads still redundant once registers are assigned -# -ftree-partial-pre computes a value once when only some paths need it -# -fsplit-paths duplicates a small piece of a loop so the passes above see through it -# RP2350 keeps plain -O3: there the duplicating passes are what lets the vectorizer pair -# 16-bit writes, and fill loops run 24-41 % slower without them. -OPTIMIZATION_FLAGS ?= -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-partial-pre -fsplit-paths +# -O2 plus the two flags that carry -O3 here, which is 130 KB less flash than -O3 for the same +# speed on everything measured. That headroom is what lets a board fit. +# +# -funswitch-loops Hoists a test that cannot change inside a loop out of it and keeps +# one copy of the body per value. Costs 16 KB, because it duplicates +# loop bodies in 94 functions. Buys 24 % on a flipped sprite blit, +# 9 % on a textured floor, and 1-2 % on bitmaptools.alphablend and +# the ulab reductions. +# +# -fvect-cost-model=dynamic -O2 sets very-cheap, which turns nearly every loop down. dynamic +# accepts them, which here means memset, memcpy and a 16-bit row +# fill get unrolled with an alignment prologue. Costs 4 KB. Buys +# 37 % on rectangle fills and bytearray copies and 16 % on aesio. +# Runs shorter than the prologue lose: a four-pixel span fill is +# 7 % slower. +# +# The four other -O3 loop passes we measured (-fpredictive-commoning, -fgcse-after-reload, +# -ftree-partial-pre, -fsplit-paths) emit the same code as -O2 for the loops that matter here, +# so they are left out. So is the rest of -O3: its inline parameters alone are 92 KB, and they +# also take the 60-factorial loop 56 % slower. +# +# Neither flag reaches the bytecode dispatch loop: py/py.mk builds gc.o and vm.o at -O3 whatever +# this is set to, so pure interpreter work measures the same under all of them. +# +# RP2350 keeps plain -O3. There an -O2 set runs 24-41 % slower on fill loops. +OPTIMIZATION_FLAGS ?= -O2 -funswitch-loops -fvect-cost-model=dynamic endif ifeq ($(CHIP_VARIANT),RP2350) From 54dfb120bd853c92e5ddeb6f4fb663c9a5db66b6 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Mon, 14 Sep 2026 15:27:13 +0000 Subject: [PATCH 4/4] pajenicko_picopad: drop the board optimization flags The port now sets the same flags for every RP2040, and this board's copy assigned with = rather than ?=, so it would pin the old five-pass set and be the one board that misses the port default. --- ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk index b5df0e6ecb5..03a203dc2de 100644 --- a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk @@ -50,8 +50,3 @@ CFLAGS += \ # Must be accompanied by a linker script change CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' - -# The rp2 port default is -O3; on this Cortex-M0+ (no SIMD/FPU, 16 KB XIP cache) -O2 plus -# these five loop passes measures within +-1% of -O3 across the picogame render kernels -# while using ~150 KB less flash (gc.o/vm.o stay -O3 via SUPEROPT regardless). -OPTIMIZATION_FLAGS = -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-partial-pre -fsplit-paths