Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions macros/build.rs
Original file line number Diff line number Diff line change
@@ -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::<u32>().ok()?;
let minor = parts.next()?.parse::<u32>().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)");
}
37 changes: 34 additions & 3 deletions macros/src/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!({
Expand Down
Loading