mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-14 21:16:50 +00:00
add -Zmin-function-alignment
This commit is contained in:
parent
a52085d9f6
commit
47573bf61e
@ -472,7 +472,11 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
|
||||
let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
|
||||
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);
|
||||
}
|
||||
if let Some(backchain) = backchain_attr(cx) {
|
||||
|
@ -132,9 +132,13 @@ fn prefix_and_suffix<'tcx>(
|
||||
|
||||
let attrs = tcx.codegen_fn_attrs(instance.def_id());
|
||||
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`.
|
||||
let (arch_prefix, arch_suffix) = if is_arm {
|
||||
(
|
||||
|
@ -24,6 +24,7 @@ use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, build_session, filesearc
|
||||
use rustc_span::edition::{DEFAULT_EDITION, Edition};
|
||||
use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
|
||||
use rustc_span::{FileName, SourceFileHashAlgorithm, sym};
|
||||
use rustc_target::abi::Align;
|
||||
use rustc_target::spec::{
|
||||
CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
|
||||
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!(maximal_hir_to_mir_coverage, true);
|
||||
tracked!(merge_functions, Some(MergeFunctions::Disabled));
|
||||
tracked!(min_function_alignment, Some(Align::EIGHT));
|
||||
tracked!(mir_emit_retag, true);
|
||||
tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
|
||||
tracked!(mir_keep_place_mention, true);
|
||||
|
@ -2891,6 +2891,7 @@ pub(crate) mod dep_tracking {
|
||||
use std::num::NonZero;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rustc_abi::Align;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::stable_hasher::Hash64;
|
||||
use rustc_errors::LanguageIdentifier;
|
||||
@ -3011,6 +3012,7 @@ pub(crate) mod dep_tracking {
|
||||
InliningThreshold,
|
||||
FunctionReturn,
|
||||
WasmCAbi,
|
||||
Align,
|
||||
);
|
||||
|
||||
impl<T1, T2> DepTrackingHash for (T1, T2)
|
||||
|
@ -4,6 +4,7 @@ use std::num::{IntErrorKind, NonZero};
|
||||
use std::path::PathBuf;
|
||||
use std::str;
|
||||
|
||||
use rustc_abi::Align;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::profiling::TimePassesFormat;
|
||||
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_mir_include_spans: &str =
|
||||
"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 {
|
||||
@ -1533,6 +1535,21 @@ pub mod parse {
|
||||
|
||||
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! {
|
||||
@ -1888,6 +1905,8 @@ options! {
|
||||
"gather metadata statistics (default: no)"),
|
||||
metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
|
||||
"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],
|
||||
"emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
|
||||
(default: no)"),
|
||||
|
@ -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.
|
43
tests/codegen/min-function-alignment.rs
Normal file
43
tests/codegen/min-function-alignment.rs
Normal 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() {}
|
44
tests/codegen/naked-fn/min-function-alignment.rs
Normal file
44
tests/codegen/naked-fn/min-function-alignment.rs
Normal 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")
|
||||
}
|
Loading…
Reference in New Issue
Block a user