Skip to content

Add Armv8.1-M targets for Cortex-M55 and Cortex-M85 based microcontrollers - #162519

Open
jonathanpallant wants to merge 4 commits into
rust-lang:mainfrom
ferrocene:add-thumbv81m
Open

jonathanpallant wants to merge 4 commits into
rust-lang:mainfrom
ferrocene:add-thumbv81m

Conversation

@jonathanpallant

@jonathanpallant jonathanpallant commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

View all comments

Here is a new target for Armv8.1-M processors, including the Cortex-M55 and Cortex-M85. There's a soft-float version (EABI) and a hard-float version (EABIHF), as is usual for Arm bare-metal targets.

These targets assume you have the DSP and Low-Overhead Branch (LOB) architecture extensions enabled, as the Cortex-M55 and Cortex-M85 do. The LOB extension allows for much tighter loops, and hence higher performance with less code space.

LOB isn't available in Armv8.0-M, and DSP is off by default because not all Cortex-M33 processors have it enabled. You also need to know you are on Armv8.1-M so you can enable the LOB bit in the Configuration Control Register to turn it on. The cortex-m-rt crate can look at the target name to do that automatically.

All that means I think that means it's worth having this target as distinct from the existing Armv8.0-M Mainline target (thumbv8m.main-none-eabi*).

Here's a sample function:

#![no_std]

#[unsafe(no_mangle)]
pub fn process(data: &[u8]) -> u32 {
    let mut result = 0;
    for item in data.iter() {
        if *item > 10 {
            result += 1;
        }
    }
    result
}

Here's the thumbv8m.main-none-eabi assembly, at opt-level=s:

process:
	cbz     r1, .LBB0_4
	push    {r7, lr}
	mov     r7, sp
	mov     r2, r0
	movs    r0, #0
.LBB0_2:
	ldrb    r3, [r2], #1
	cmp     r3, #10
	it      hi
	addhi   r0, #1
	subs    r1, #1
	bne     .LBB0_2
	pop     {r7, pc}
.LBB0_4:
	movs    r0, #0
	bx      lr

Here's the thumbv8.1m.main-none-eabi assembly at opt-level=s:

process:
	push    {r7, lr}
	mov     r7, sp
	movs    r2, #0
	wls     lr, r1, .LBB0_2    ; While Loop Start using `LR` to count up to `R1`
.LBB0_1:
	ldrb    r1, [r0], #1
	cmp     r1, #10
	cinc    r2, r2, hi         ; Conditional Increment (replaces 'it hi; addhi r2, #1')
	le      lr, .LBB0_1        ; Loop End, which takes zero cycles after the first loop
.LBB0_2:
	mov     r0, r2
	pop     {r7, pc}

At opt-level=3, LLVM seems to prefer to unroll the loop, which is possibly sub-optimal. But that's an LLVM issue, and you do still get the use of CINC, which reduces code size and increases performance over Armv8.0-M.

I'm proposing these targets at Tier 3 initially, with the hope we can get it up to Tier 2 with the rest of the Arm M-profile targets.

  • No LLMs were used in the creation of this PR.

Tier 3 Target Policy

  • A tier 3 target must have a designated developer or developers (the "target
    maintainers") on record to be CCed when issues arise regarding the target.
    (The mechanism to track and CC such developers may evolve over time.)

I'm offering the Rust Embedded Devices Working Group (who agreed in their last weekly meeting), and I'm proposing Arm also maintain this target as they do thumbv8m.main-none-eabi*. If they decline, or it takes time to get that agreement, I'm happy to take them out for now.

The target will get added to the rust-embedded/cortex-m repository for testing with the cortex-m and cortex-m-rt crates.

  • Targets must use naming consistent with any existing targets; for instance, a
    target for the same CPU or OS as an existing Rust target should use the same
    name for that CPU or OS. Targets should normally use the same names and
    naming conventions as used elsewhere in the broader ecosystem beyond Rust
    (such as in other toolchains), unless they have a very good reason to
    diverge. Changing the name of a target can be highly disruptive, especially
    once the target reaches a higher tier, so getting the name right is important
    even for a tier 3 target.
    • Target names should not introduce undue confusion or ambiguity unless
      absolutely necessary to maintain ecosystem compatibility. For example, if
      the name of the target makes people extremely likely to form incorrect
      beliefs about what it targets, the name should be changed or augmented to
      disambiguate it.
    • If possible, use only letters, numbers, dashes and underscores for the name.
      Periods (.) are known to cause issues in Cargo.

I believe this is our first target to use a point-release of an Arm Architecture. I picked the same target string that LLVM uses, even though I don't like it.

  • Tier 3 targets may have unusual requirements to build or use, but must not
    create legal issues or impose onerous legal terms for the Rust project or for
    Rust developers or users.

It's no different to the existing Arm M-profile targets.

  • Neither this policy nor any decisions made regarding targets shall create any
    binding agreement or estoppel by any party. If any member of an approving
    Rust team serves as one of the maintainers of a target, or has any legal or
    employment requirement (explicit or implicit) that might affect their
    decisions regarding a target, they must recuse themselves from any approval
    decisions regarding the target's tier status, though they may otherwise
    participate in discussions.
    • This requirement does not prevent part or all of this policy from being
      cited in an explicit contract or work agreement (e.g. to implement or
      maintain support for a target). This requirement exists to ensure that a
      developer or team responsible for reviewing and approving a target does not
      face any legal threats or obligations that would prevent them from freely
      exercising their judgment in such approval, even if such judgment involves
      subjective matters or goes beyond the letter of these requirements.

Noted

  • Tier 3 targets should attempt to implement as much of the standard libraries
    as possible and appropriate (core for most targets, alloc for targets
    that can support dynamic memory allocation, std for targets with an
    operating system or equivalent layer of system-provided functionality), but
    may leave some code unimplemented (either unavailable or stubbed out as
    appropriate), whether because the target makes it impossible to implement or
    challenging to implement. The authors of pull requests are not obligated to
    avoid calling any portions of the standard library on the basis of a tier 3
    target not implementing those portions.

The Arm bare-metal targets are naturally no_std.

  • The target must provide documentation for the Rust community explaining how
    to build for the target, using cross-compilation if possible. If the target
    supports running binaries, or running tests (even if they do not pass), the
    documentation must explain how to run such binaries or tests for the target,
    using emulation if possible or dedicated hardware if necessary.

Target docs updated, with the new page based on the existing Armv8-M target docs.

  • Tier 3 targets must not impose burden on the authors of pull requests, or
    other developers in the community, to maintain the target. In particular,
    do not post comments (automated or manual) on a PR that derail or suggest a
    block on the PR based on a tier 3 target. Do not send automated messages or
    notifications (via any medium, including via @) to a PR author or others
    involved with a PR regarding a tier 3 target, unless they have opted into
    such messages.
    • Backlinks such as those generated by the issue/PR tracker when linking to
      an issue or PR are not considered a violation of this policy, within
      reason. However, such messages (even on a separate repository) must not
      generate notifications to anyone involved with a PR who has not requested
      such notifications.

Noted

  • Patches adding or updating tier 3 targets must not break any existing tier 2
    or tier 1 target, and must not knowingly break another tier 3 target without
    approval of either the compiler team or the maintainers of the other tier 3
    target.
    • In particular, this may come up when working on closely related targets,
      such as variations of the same architecture with different features. Avoid
      introducing unconditional uses of features that another variation of the
      target may not have; use conditional compilation or runtime detection, as
      appropriate, to let each target run code supported by that target.

Noted. There is a "v8.1m.main" target feature in rustc already so code can do the right thing where that's required.

  • Tier 3 targets must be able to produce assembly using at least one of
    rustc's supported backends from any host target. (Having support in a fork
    of the backend is not sufficient, it must be upstream.)

Built locally to test it works - see examples above.

r? compiler

These targets assume you have the DSP and LOB extensions enabled,
as the Cortex-M55 and Cortex-M85 do. The LOB extension allows for much
tighter loops, and hence higher performance.
@rustbot

rustbot commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

These commits modify compiler targets.
(See the Target Tier Policy.)

Some changes occurred in src/doc/rustc/src/platform-support

cc @Noratrieb

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Sep 9, 2026
Comment thread src/doc/rustc/src/platform-support/thumbv8.1m.main-none-eabi.md Outdated
@rust-log-analyzer

This comment has been minimized.

@jonathanpallant

Copy link
Copy Markdown
Contributor Author

The error from CI is:

error: Target name thumbv8.1m.main-none-eabihf contains other characters than ASCII alphanumeric (a-z, A-Z, 0-9), dash (-) or underscore (_).

Yes, it does. But so does thumbv8m.main-none-eabihf?

@mkj

mkj commented Sep 9, 2026

Copy link
Copy Markdown

Yes, it does. But so does thumbv8m.main-none-eabihf?

There's a hardcoded ignore list.

let ignore_target_names = [
"thumbv8m.base-none-eabi",

@rustbot rustbot added the T-infra Relevant to the infrastructure team, which will review and decide on the PR/issue. label Sep 9, 2026
@jonathanpallant

Copy link
Copy Markdown
Contributor Author
  • I added the targets to the ignore list (why does this rule exist if we can so easily ignore it?)
  • Remove the DSP column from the docs

@jonathanpallant

Copy link
Copy Markdown
Contributor Author

@rustbot ping arm-maintainers

because I added you as a target maintainer here

@rustbot

rustbot commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Error: Only Rust team members can ping teams.

Please file an issue on GitHub at triagebot if there's a problem with this bot, or reach out on #triagebot on Zulip.

@oli-obk

oli-obk commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

@rustbot ping arm-maintainers

@rustbot

rustbot commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Dear ARM Maintainers, your feedback has been requested on this issue/PR.
Thanks! <3

cc @adamgemmell @davidtwco @Jamesbarford @lqd

@rustbot rustbot added the O-Arm Target: 32-bit Arm processors (armv6, armv7, thumb...), including 64-bit Arm in AArch32 state label Sep 10, 2026
@oli-obk

oli-obk commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

anyone from arm-maintainers wanna review this one? I can only check that it follows the formal criteria, not any details

@adamgemmell adamgemmell left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be up to @davidtwco if Arm is ok with maintaining this target. In practice I'd expect the maintenance to be low as it's just thumv8m-main-eabi*, which we already maintain, with extra features enabled.

You also need to know you are on Armv8.1-M so you can enable the LOB bit in the Configuration Control Register to turn it on. The cortex-m-rt crate can look at the target name to do that automatically.

Could it also just check if the lob feature is enabled globally?

It seems to me that the target is mainly useful once promoted to tier 2 (so we distribute std for it) for users that can't use -Zbuild-std and don't want to build core/alloc from source. My impression is that many embedded uses are forced to use nightly for a variety of reasons and so can often use -Zbuild-std, particularly to recompile with -Copt-level=s or -Ctarget-cpu. How useful is the target in practice?

View changes since this review

Comment thread compiler/rustc_target/src/spec/targets/thumbv81m_main_none_eabi.rs Outdated
Comment thread compiler/rustc_target/src/spec/targets/thumbv81m_main_none_eabihf.rs Outdated
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 10, 2026
@rustbot

rustbot commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@diondokter

Copy link
Copy Markdown
Member

My impression is that many embedded uses are forced to use nightly for a variety of reasons

FYI, to the credit of the project, there's fewer and fewer reasons to. If you're on a well supported platform and using e.g. embassy, you can do that with the stable compiler just fine. So much so that I think all my embedded projects in the last two years have been exclusively on the stable compiler. Companies also don't like using nightly, feels like a risk they can't oversee to them.

@jonathanpallant

Copy link
Copy Markdown
Contributor Author

Agreed - all my projects build on stable (at least where the target is Tier 2).

Ferrocene is also "not a nightly compiler" so people using that are only using stable features.

@jonathanpallant

Copy link
Copy Markdown
Contributor Author

Could it also just check if the lob feature is enabled globally?

Not in a stable way? I don't think any Arm target features are stable.

@adamgemmell

Copy link
Copy Markdown
Contributor

Could it also just check if the lob feature is enabled globally?

Not in a stable way? I don't think any Arm target features are stable.

That's true (checking for them on stable never resolves to true), but creating new targets isn't a sustainable workaround for that. But on the other hand clearly the target's useful for some people now while we're waiting for that and build-std.

@jonathanpallant

Copy link
Copy Markdown
Contributor Author

I look forward to deleting them all and replacing them with a single arm-none-eabi target :)

They are Tier 3, not Tier 2.
@jonathanpallant

Copy link
Copy Markdown
Contributor Author

Corrected both targets to Tier 3

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Sep 13, 2026
@oli-obk oli-obk assigned davidtwco and unassigned oli-obk Sep 14, 2026
@jonathanpallant

jonathanpallant commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

I did some benchmarks on an STM32N657. I was looking for ASCII capital letters in a 32K block of text:

#[unsafe(no_mangle)]
#[inline(never)]
pub fn benchmark(s: &str) -> usize {
    let mut count = 0;
    for b in s.bytes() {
        if b.is_ascii_uppercase() {
            count += 1;
        }

    }
    count
}

I used the cycle counter to measure the elapsed time for this function.

Target opt-level target-cpu Cycles
thumbv8m.main-none-eabihf 3 None 155,702
thumbv8.1m.main-none-eabihf 3 None 147,512
thumbv8m.main-none-eabihf 3 cortex-m55 47,174
thumbv8.1m.main-none-eabihf 3 cortex-m55 47,174
thumbv8m.main-none-eabihf s None 262,181
thumbv8.1m.main-none-eabihf s None 163,885
thumbv8m.main-none-eabihf s cortex-m55 163,885
thumbv8.1m.main-none-eabihf s cortex-m55 163,884

At opt-level=3 with target-cpu=cortex-m55 the M-Profile Vector Engine kicked in and SIMD'd the problem, giving the huge speed boost. Not all Cortex-M55 CPUs have MVE though, and there's still a nice boost at opt-level="s" using this target (likely thanks to the LOB feature that this target enables).

Given this data, you could make the argument that the target is irrelevant and people should be using -Ctarget-cpu instead. But, I would counter that if you have a Cortex-M55 without MVE it gets really messy (you have to use negative features like -Ctarget-cpu=cortex-m55 -Ctarget-feature=-mve). Plus, without this target there's also no stable way for cortex-m-rt to know when to turn on the Low-Overhead Branch cache (because the "lob" feature isn't stable so it cannnot check for it).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

O-Arm Target: 32-bit Arm processors (armv6, armv7, thumb...), including 64-bit Arm in AArch32 state S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-infra Relevant to the infrastructure team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants