1
Fork 0

add -Zmin-function-alignment

This commit is contained in:
Folkert de Vries 2024-12-18 22:03:07 +01:00
parent a52085d9f6
commit 47573bf61e
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
8 changed files with 145 additions and 3 deletions

View file

@ -472,7 +472,11 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
} }
if let Some(align) = codegen_fn_attrs.alignment { // function alignment can be set globally with the `-Zmin-function-alignment=<n>` flag;
// the alignment from a `#[repr(align(<n>))]` is used if it specifies a higher alignment.
if let Some(align) =
Ord::max(cx.tcx.sess.opts.unstable_opts.min_function_alignment, codegen_fn_attrs.alignment)
{
llvm::set_alignment(llfn, align); llvm::set_alignment(llfn, align);
} }
if let Some(backchain) = backchain_attr(cx) { if let Some(backchain) = backchain_attr(cx) {

View file

@ -132,9 +132,13 @@ fn prefix_and_suffix<'tcx>(
let attrs = tcx.codegen_fn_attrs(instance.def_id()); let attrs = tcx.codegen_fn_attrs(instance.def_id());
let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string()); let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string());
let align = attrs.alignment.map(|a| a.bytes()).unwrap_or(4);
// See https://sourceware.org/binutils/docs/as/ARM-Directives.html for info on these directives. // function alignment can be set globally with the `-Zmin-function-alignment=<n>` flag;
// the alignment from a `#[repr(align(<n>))]` is used if it specifies a higher alignment.
// if no alignment is specified, an alignment of 4 bytes is used.
let min_function_alignment = tcx.sess.opts.unstable_opts.min_function_alignment;
let align = Ord::max(min_function_alignment, attrs.alignment).map(|a| a.bytes()).unwrap_or(4);
// In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`. // In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`.
let (arch_prefix, arch_suffix) = if is_arm { let (arch_prefix, arch_suffix) = if is_arm {
( (

View file

@ -24,6 +24,7 @@ use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, build_session, filesearc
use rustc_span::edition::{DEFAULT_EDITION, Edition}; use rustc_span::edition::{DEFAULT_EDITION, Edition};
use rustc_span::source_map::{RealFileLoader, SourceMapInputs}; use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
use rustc_span::{FileName, SourceFileHashAlgorithm, sym}; use rustc_span::{FileName, SourceFileHashAlgorithm, sym};
use rustc_target::abi::Align;
use rustc_target::spec::{ use rustc_target::spec::{
CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, WasmCAbi, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, WasmCAbi,
@ -802,6 +803,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(location_detail, LocationDetail { file: true, line: false, column: false }); tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
tracked!(maximal_hir_to_mir_coverage, true); tracked!(maximal_hir_to_mir_coverage, true);
tracked!(merge_functions, Some(MergeFunctions::Disabled)); tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(min_function_alignment, Some(Align::EIGHT));
tracked!(mir_emit_retag, true); tracked!(mir_emit_retag, true);
tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]); tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
tracked!(mir_keep_place_mention, true); tracked!(mir_keep_place_mention, true);

View file

@ -2891,6 +2891,7 @@ pub(crate) mod dep_tracking {
use std::num::NonZero; use std::num::NonZero;
use std::path::PathBuf; use std::path::PathBuf;
use rustc_abi::Align;
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::stable_hasher::Hash64; use rustc_data_structures::stable_hasher::Hash64;
use rustc_errors::LanguageIdentifier; use rustc_errors::LanguageIdentifier;
@ -3011,6 +3012,7 @@ pub(crate) mod dep_tracking {
InliningThreshold, InliningThreshold,
FunctionReturn, FunctionReturn,
WasmCAbi, WasmCAbi,
Align,
); );
impl<T1, T2> DepTrackingHash for (T1, T2) impl<T1, T2> DepTrackingHash for (T1, T2)

View file

@ -4,6 +4,7 @@ use std::num::{IntErrorKind, NonZero};
use std::path::PathBuf; use std::path::PathBuf;
use std::str; use std::str;
use rustc_abi::Align;
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::profiling::TimePassesFormat; use rustc_data_structures::profiling::TimePassesFormat;
use rustc_data_structures::stable_hasher::Hash64; use rustc_data_structures::stable_hasher::Hash64;
@ -455,6 +456,7 @@ mod desc {
pub(crate) const parse_wasm_c_abi: &str = "`legacy` or `spec`"; pub(crate) const parse_wasm_c_abi: &str = "`legacy` or `spec`";
pub(crate) const parse_mir_include_spans: &str = pub(crate) const parse_mir_include_spans: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)"; "either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)";
pub(crate) const parse_align: &str = "a number that is a power of 2 between 1 and 2^29";
} }
pub mod parse { pub mod parse {
@ -1533,6 +1535,21 @@ pub mod parse {
true true
} }
pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
let mut bytes = 0u64;
if !parse_number(&mut bytes, v) {
return false;
}
let Ok(align) = Align::from_bytes(bytes) else {
return false;
};
*slot = Some(align);
true
}
} }
options! { options! {
@ -1888,6 +1905,8 @@ options! {
"gather metadata statistics (default: no)"), "gather metadata statistics (default: no)"),
metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED], metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"), "the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"),
min_function_alignment: Option<Align> = (None, parse_align, [TRACKED],
"align all functions to at least this many bytes. Must be a power of 2"),
mir_emit_retag: bool = (false, parse_bool, [TRACKED], mir_emit_retag: bool = (false, parse_bool, [TRACKED],
"emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
(default: no)"), (default: no)"),

View file

@ -0,0 +1,24 @@
# `min-function-alignment`
The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/82232.
------------------------
The `-Zmin-function-alignment=<align>` flag specifies the minimum alignment of functions for which code is generated.
The `align` value must be a power of 2, other values are rejected.
Note that `-Zbuild-std` (or similar) is required to apply this minimum alignment to standard library functions.
By default, these functions come precompiled and their alignments won't respect the `min-function-alignment` flag.
This flag is equivalent to:
- `-fmin-function-alignment` for [GCC](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-fmin-function-alignment_003dn)
- `-falign-functions` for [Clang](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang1-falign-functions)
The specified alignment is a minimum. A higher alignment can be specified for specific functions by using the [`repr(align(...))`](https://github.com/rust-lang/rust/issues/82232) feature and annotating the function with a `#[repr(align(<align>))]` attribute. The attribute's value is ignored when it is lower than the value passed to `min-function-alignment`.
There are two additional edge cases for this flag:
- targets have a minimum alignment for functions (e.g. on x86_64 the lowest that LLVM generates is 16 bytes).
A `min-function-alignment` value lower than the target's minimum has no effect.
- the maximum alignment supported by rust (and LLVM) is `2^29`. Trying to set a higher value results in an error.

View file

@ -0,0 +1,43 @@
//@ revisions: align16 align1024
//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
//@ [align16] compile-flags: -Zmin-function-alignment=16
//@ [align1024] compile-flags: -Zmin-function-alignment=1024
#![crate_type = "lib"]
#![feature(fn_align)]
// functions without explicit alignment use the global minimum
//
// CHECK-LABEL: @no_explicit_align
// align16: align 16
// align1024: align 1024
#[no_mangle]
pub fn no_explicit_align() {}
// CHECK-LABEL: @lower_align
// align16: align 16
// align1024: align 1024
#[no_mangle]
#[repr(align(8))]
pub fn lower_align() {}
// the higher value of min-function-alignment and repr(align) wins out
//
// CHECK-LABEL: @higher_align
// align16: align 32
// align1024: align 1024
#[no_mangle]
#[repr(align(32))]
pub fn higher_align() {}
// cold functions follow the same rules as other functions
//
// in GCC, the `-falign-functions` does not apply to cold functions, but
// `-Zmin-function-alignment` applies to all functions.
//
// CHECK-LABEL: @no_explicit_align_cold
// align16: align 16
// align1024: align 1024
#[no_mangle]
#[cold]
pub fn no_explicit_align_cold() {}

View file

@ -0,0 +1,44 @@
//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmin-function-alignment=16
//@ needs-asm-support
//@ ignore-arm no "ret" mnemonic
#![feature(naked_functions, fn_align)]
#![crate_type = "lib"]
// functions without explicit alignment use the global minimum
//
// CHECK: .balign 16
#[no_mangle]
#[naked]
pub unsafe extern "C" fn naked_no_explicit_align() {
core::arch::naked_asm!("ret")
}
// CHECK: .balign 16
#[no_mangle]
#[repr(align(8))]
#[naked]
pub unsafe extern "C" fn naked_lower_align() {
core::arch::naked_asm!("ret")
}
// CHECK: .balign 32
#[no_mangle]
#[repr(align(32))]
#[naked]
pub unsafe extern "C" fn naked_higher_align() {
core::arch::naked_asm!("ret")
}
// cold functions follow the same rules as other functions
//
// in GCC, the `-falign-functions` does not apply to cold functions, but
// `-Zmin-function-alignment` applies to all functions.
//
// CHECK: .balign 16
#[no_mangle]
#[cold]
#[naked]
pub unsafe extern "C" fn no_explicit_align_cold() {
core::arch::naked_asm!("ret")
}