From 435555e52bfb2d115a1b875c0cc65c920f894b27 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 19 Sep 2025 19:17:54 +0200 Subject: [PATCH 1/2] Load string indices with inline asm to save space. --- CHANGELOG.md | 1 + macros/build.rs | 24 ++++++++++++++++++++++++ macros/src/construct.rs | 37 ++++++++++++++++++++++++++++++++++--- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 596966827..82ae83b46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ We have several packages which live in this repository. Changes are tracked sepa ### [defmt-next] +- [#879]: Load string indices with inline asm to save space. * [#974]: Ensure typechecking is still performed on disabled log statement. * [#960]: Fix `Format` not accepting multiple helper attribute instances * [#937]: add support for `#[defmt(transparent)]` on `Format` derive diff --git a/macros/build.rs b/macros/build.rs index 772d48b4b..63953668f 100644 --- a/macros/build.rs +++ b/macros/build.rs @@ -1,3 +1,27 @@ fn main() { println!("cargo:rerun-if-env-changed=DEFMT_LOG"); + + // Check rustc version + let rustc = std::env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string()); + let output = std::process::Command::new(rustc) + .arg("--version") + .output() + .expect("failed to execute rustc"); + let version_str = String::from_utf8_lossy(&output.stdout); + // rustc 1.91.0-beta.1 (1bffa2300 2025-09-15) + let is_ge_1_91 = version_str + .split_whitespace() + .nth(1) + .and_then(|v| { + let mut parts = v.split('.'); + let major = parts.next()?.parse::().ok()?; + let minor = parts.next()?.parse::().ok()?; + Some((major, minor)) + }) + .map(|(major, minor)| major > 1 || (major == 1 && minor >= 91)) + .unwrap_or(false); + if is_ge_1_91 { + println!("cargo:rustc-cfg=rustc_ge_1_91"); + } + println!("cargo:rustc-check-cfg=cfg(rustc_ge_1_91)"); } diff --git a/macros/src/construct.rs b/macros/src/construct.rs index 3548338f3..8dc49ba81 100644 --- a/macros/src/construct.rs +++ b/macros/src/construct.rs @@ -46,10 +46,41 @@ pub(crate) fn interned_string( quote!({ #defmt_path::export::fetch_add_string_index() }) } else { let var_item = static_variable(&var_name, string, tag, prefix); - quote!({ - #var_item + + // defmt string indices are 16 bits, which can be loaded with a single `movw`. + // However, the compiler doesn't know that, so it generates `movw+movt` or `ldr rX, [pc, #offs]` + // because it sees we're loading an address of a symbol, which could be any 32bit value. + // This wastes space, so we load the value with asm manually to avoid this. + let val_arm_optimized = quote!( + let res: u16; + unsafe { ::core::arch::asm!( + "movw {res}, #:lower16:{y}", + res = lateout(reg) res, + y = sym #var_name, + options(pure, nomem, nostack, preserves_flags) + )}; + res + ); + let val_standard = quote!( &#var_name as *const u8 as u16 - }) + ); + + // using symbols with quotes in `asm!(sym)` only works in Rust 1.91+ + if cfg!(rustc_ge_1_91) { + quote!({ + #var_item + + #[cfg(target_arch = "arm")] + { #val_arm_optimized } + #[cfg(not(target_arch = "arm"))] + { #val_standard } + }) + } else { + quote!({ + #var_item + #val_standard + }) + } }; quote!({ From 732e0a079ea18503e9b2e87271c8ae34b7919d67 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 25 Sep 2025 12:45:01 +0200 Subject: [PATCH 2/2] ci: update nightly. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 789e46b3e..e5758c142 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -146,7 +146,7 @@ jobs: toolchain: - stable - "1.81" # host MSRV - - nightly-2025-08-05 # some tests use unstable features, but avoid LLVM21 due to https://github.com/rust-lang/rust/issues/146065 + - nightly runs-on: ubuntu-latest steps: - uses: actions/checkout@v4