Until I discovered this, I couldn’t build working ATmega4809 Rust code with anything other than optimisation level 1 - which means horribly large binaries (not great on an embedded processor with 48Kb of flash.)

But, after extensive banging of my head against the screen, I’ve discovered that the LLVM register allocator is broken at higher optimisation levels.

You can force LLVM to always use the basic register allocator by adding the following to .cargo/config.toml:

[build]
target = "avr-atmega4809.json"
rustc-wrapper = "./rustc-wrapper.sh"
rustflags = [
    "-C","llvm-args=--regalloc=basic"
]

And - hey presto! You can now use other optimisation levels, and of course the all import “small” optimisation level, like so in your Cargo.toml:

[profile.release]
panic = "abort"
codegen-units = 1
opt-level = "s"
debug = true
lto = true
overflow-checks = false