Skip to content

Commit 488f710

Browse files
committed
add -Zmin-function-alignment
1 parent dd436ae commit 488f710

File tree

7 files changed

+108
-3
lines changed

7 files changed

+108
-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
@@ -25,6 +25,7 @@ use rustc_span::edition::{DEFAULT_EDITION, Edition};
2525
use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
2626
use rustc_span::symbol::sym;
2727
use rustc_span::{FileName, SourceFileHashAlgorithm};
28+
use rustc_target::abi::Align;
2829
use rustc_target::spec::{
2930
CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
3031
RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, WasmCAbi,
@@ -803,6 +804,7 @@ fn test_unstable_options_tracking_hash() {
803804
tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
804805
tracked!(maximal_hir_to_mir_coverage, true);
805806
tracked!(merge_functions, Some(MergeFunctions::Disabled));
807+
tracked!(min_function_alignment, Some(Align::EIGHT));
806808
tracked!(mir_emit_retag, true);
807809
tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
808810
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)"),
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -Zmin-function-alignment=16
2+
3+
#![crate_type = "lib"]
4+
#![feature(fn_align)]
5+
6+
// functions without explicit alignment use the global minimum
7+
//
8+
// CHECK: align 16
9+
#[no_mangle]
10+
pub fn no_explicit_align() {}
11+
12+
// CHECK: align 16
13+
#[no_mangle]
14+
#[repr(align(8))]
15+
pub fn lower_align() {}
16+
17+
// CHECK: align 32
18+
#[no_mangle]
19+
#[repr(align(32))]
20+
pub fn higher_align() {}
21+
22+
// cold functions follow the same rules as other functions
23+
//
24+
// in GCC, the `-falign-functions` does not apply to cold functions, but
25+
// `-Zmin-function-alignment` applies to all functions.
26+
//
27+
// CHECK: align 16
28+
#[no_mangle]
29+
#[cold]
30+
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)