Skip to content

Commit 47573bf

Browse files
committedJan 10, 2025
add -Zmin-function-alignment
1 parent a52085d commit 47573bf

File tree

8 files changed

+145
-3
lines changed

8 files changed

+145
-3
lines changed
 

‎compiler/rustc_codegen_llvm/src/attributes.rs

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

‎compiler/rustc_codegen_ssa/src/mir/naked_asm.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,13 @@ fn prefix_and_suffix<'tcx>(
132132

133133
let attrs = tcx.codegen_fn_attrs(instance.def_id());
134134
let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string());
135-
let align = attrs.alignment.map(|a| a.bytes()).unwrap_or(4);
136135

137-
// See https://sourceware.org/binutils/docs/as/ARM-Directives.html for info on these directives.
136+
// function alignment can be set globally with the `-Zmin-function-alignment=<n>` flag;
137+
// the alignment from a `#[repr(align(<n>))]` is used if it specifies a higher alignment.
138+
// if no alignment is specified, an alignment of 4 bytes is used.
139+
let min_function_alignment = tcx.sess.opts.unstable_opts.min_function_alignment;
140+
let align = Ord::max(min_function_alignment, attrs.alignment).map(|a| a.bytes()).unwrap_or(4);
141+
138142
// In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`.
139143
let (arch_prefix, arch_suffix) = if is_arm {
140144
(

‎compiler/rustc_interface/src/tests.rs

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

‎compiler/rustc_session/src/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2891,6 +2891,7 @@ pub(crate) mod dep_tracking {
28912891
use std::num::NonZero;
28922892
use std::path::PathBuf;
28932893

2894+
use rustc_abi::Align;
28942895
use rustc_data_structures::fx::FxIndexMap;
28952896
use rustc_data_structures::stable_hasher::Hash64;
28962897
use rustc_errors::LanguageIdentifier;
@@ -3011,6 +3012,7 @@ pub(crate) mod dep_tracking {
30113012
InliningThreshold,
30123013
FunctionReturn,
30133014
WasmCAbi,
3015+
Align,
30143016
);
30153017

30163018
impl<T1, T2> DepTrackingHash for (T1, T2)

‎compiler/rustc_session/src/options.rs

+19
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::num::{IntErrorKind, NonZero};
44
use std::path::PathBuf;
55
use std::str;
66

7+
use rustc_abi::Align;
78
use rustc_data_structures::fx::FxIndexMap;
89
use rustc_data_structures::profiling::TimePassesFormat;
910
use rustc_data_structures::stable_hasher::Hash64;
@@ -455,6 +456,7 @@ mod desc {
455456
pub(crate) const parse_wasm_c_abi: &str = "`legacy` or `spec`";
456457
pub(crate) const parse_mir_include_spans: &str =
457458
"either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)";
459+
pub(crate) const parse_align: &str = "a number that is a power of 2 between 1 and 2^29";
458460
}
459461

460462
pub mod parse {
@@ -1533,6 +1535,21 @@ pub mod parse {
15331535

15341536
true
15351537
}
1538+
1539+
pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
1540+
let mut bytes = 0u64;
1541+
if !parse_number(&mut bytes, v) {
1542+
return false;
1543+
}
1544+
1545+
let Ok(align) = Align::from_bytes(bytes) else {
1546+
return false;
1547+
};
1548+
1549+
*slot = Some(align);
1550+
1551+
true
1552+
}
15361553
}
15371554

15381555
options! {
@@ -1888,6 +1905,8 @@ options! {
18881905
"gather metadata statistics (default: no)"),
18891906
metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
18901907
"the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"),
1908+
min_function_alignment: Option<Align> = (None, parse_align, [TRACKED],
1909+
"align all functions to at least this many bytes. Must be a power of 2"),
18911910
mir_emit_retag: bool = (false, parse_bool, [TRACKED],
18921911
"emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
18931912
(default: no)"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# `min-function-alignment`
2+
3+
The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/82232.
4+
5+
------------------------
6+
7+
The `-Zmin-function-alignment=<align>` flag specifies the minimum alignment of functions for which code is generated.
8+
The `align` value must be a power of 2, other values are rejected.
9+
10+
Note that `-Zbuild-std` (or similar) is required to apply this minimum alignment to standard library functions.
11+
By default, these functions come precompiled and their alignments won't respect the `min-function-alignment` flag.
12+
13+
This flag is equivalent to:
14+
15+
- `-fmin-function-alignment` for [GCC](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-fmin-function-alignment_003dn)
16+
- `-falign-functions` for [Clang](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang1-falign-functions)
17+
18+
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`.
19+
20+
There are two additional edge cases for this flag:
21+
22+
- targets have a minimum alignment for functions (e.g. on x86_64 the lowest that LLVM generates is 16 bytes).
23+
A `min-function-alignment` value lower than the target's minimum has no effect.
24+
- the maximum alignment supported by rust (and LLVM) is `2^29`. Trying to set a higher value results in an error.
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//@ revisions: align16 align1024
2+
//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
3+
//@ [align16] compile-flags: -Zmin-function-alignment=16
4+
//@ [align1024] compile-flags: -Zmin-function-alignment=1024
5+
6+
#![crate_type = "lib"]
7+
#![feature(fn_align)]
8+
9+
// functions without explicit alignment use the global minimum
10+
//
11+
// CHECK-LABEL: @no_explicit_align
12+
// align16: align 16
13+
// align1024: align 1024
14+
#[no_mangle]
15+
pub fn no_explicit_align() {}
16+
17+
// CHECK-LABEL: @lower_align
18+
// align16: align 16
19+
// align1024: align 1024
20+
#[no_mangle]
21+
#[repr(align(8))]
22+
pub fn lower_align() {}
23+
24+
// the higher value of min-function-alignment and repr(align) wins out
25+
//
26+
// CHECK-LABEL: @higher_align
27+
// align16: align 32
28+
// align1024: align 1024
29+
#[no_mangle]
30+
#[repr(align(32))]
31+
pub fn higher_align() {}
32+
33+
// cold functions follow the same rules as other functions
34+
//
35+
// in GCC, the `-falign-functions` does not apply to cold functions, but
36+
// `-Zmin-function-alignment` applies to all functions.
37+
//
38+
// CHECK-LABEL: @no_explicit_align_cold
39+
// align16: align 16
40+
// align1024: align 1024
41+
#[no_mangle]
42+
#[cold]
43+
pub fn no_explicit_align_cold() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmin-function-alignment=16
2+
//@ needs-asm-support
3+
//@ ignore-arm no "ret" mnemonic
4+
5+
#![feature(naked_functions, fn_align)]
6+
#![crate_type = "lib"]
7+
8+
// functions without explicit alignment use the global minimum
9+
//
10+
// CHECK: .balign 16
11+
#[no_mangle]
12+
#[naked]
13+
pub unsafe extern "C" fn naked_no_explicit_align() {
14+
core::arch::naked_asm!("ret")
15+
}
16+
17+
// CHECK: .balign 16
18+
#[no_mangle]
19+
#[repr(align(8))]
20+
#[naked]
21+
pub unsafe extern "C" fn naked_lower_align() {
22+
core::arch::naked_asm!("ret")
23+
}
24+
25+
// CHECK: .balign 32
26+
#[no_mangle]
27+
#[repr(align(32))]
28+
#[naked]
29+
pub unsafe extern "C" fn naked_higher_align() {
30+
core::arch::naked_asm!("ret")
31+
}
32+
33+
// cold functions follow the same rules as other functions
34+
//
35+
// in GCC, the `-falign-functions` does not apply to cold functions, but
36+
// `-Zmin-function-alignment` applies to all functions.
37+
//
38+
// CHECK: .balign 16
39+
#[no_mangle]
40+
#[cold]
41+
#[naked]
42+
pub unsafe extern "C" fn no_explicit_align_cold() {
43+
core::arch::naked_asm!("ret")
44+
}

0 commit comments

Comments
 (0)