Change:
<ins> // Test that the `reserve-x18` target feature is (not) emitted when // the `-Zfixed-x18` flag is (not) set. //@ revisions: unset set //@ needs-llvm-components: aarch64 //@ compile-flags: --target aarch64-unknown-none //@ [set] compile-flags: -Zfixed-x18 #![crate_type = "lib"] #![feature(no_core, lang_items)] #![no_core] #[lang = "sized"] trait Sized {} #[no_mangle] pub fn foo() { // CHECK: @foo() unnamed_addr #0 // unset-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} } // set: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} } } </ins>

Discussion:
On the target, specifying the target feature using the flag results in the following warning: The desired effect of this flag is to reserve the x18 register so that LLVM does not use it during codegen. Note that despite the warning, the flag still works fine today since it is passed on to LLVM. This feature is necessary for Rust to work when using the Linux Kernel's dynamic shadow call stack feature on aarch64 (). The shadow call stack feature requires that the x18 register is reserved, since it is used to store the shadow stack. In C code, the dynamic version of shadow call stack requires you to pass but not (which is only used for non-dynamic SCS). Clang has a collection of flags for reserving other registers than x18 as well. I think it would make sense to add those as well, even if they are less useful than x18. Related to . Related to .
This affects the ABI, right? I think adding a target spec option makes the most sense (or actually you can already set it as target feature in the target spec without giving a warning). That way you can't enable or disable it for individual functions or crates, which would break the ABI.
Yeah, it would be nice to have a flag for this (or having something like "global target features", i.e. like , but that it ensures it is set the same way for all compilation units).
There could be ABI concerns with this in general. AAPCS64 defines x18 as a platform register if required, or temporary if a platform register isn't needed. For x18 it's probably unlikely for it to have ABI concerns as it's already reserved for use on some platforms, the ones where it's not already reserved, it's only supposed to be a temporary register so not using it should be OK as it is not used for any fixed purpose. That's obviously assuming a platform defines its ABI based on the Arm standards. LLVM does support reserve on other registers, most notably for ABI reasons, x1 through x7 which would have ABI problems. LLVM does have test cases to ensure that a function call doesn't occur if any of the argument registers have been reserved. I'm not sure what other codegen backends do in that case though, or if they even support reserving those registers.

The analysis that LLVM does, doesn't seem to care if it would need to use that register for ABI reasons, even a function such as can't be called in a quick test. Using target features for this feels strange to me though, I'm wondering if a codegen option to reserve certain registers would be a better approach here. While this issue is specifically about reserving a register on AArch64, LLVM does support this for multiple other architectures and multiple registers, which we should maybe consider for the future.