Skip to content

Commit 8128e91

Browse files
committed
Auto merge of rust-lang#94127 - erikdesjardins:debugattr, r=nikic
At opt-level=0, apply only ABI-affecting attributes to functions This should provide a small perf improvement for debug builds, and should more than cancel out the perf regression from adding noundef (rust-lang#93670 (comment), rust-lang#94106). r? `@nikic`
2 parents d5a9bc9 + 945276c commit 8128e91

File tree

6 files changed

+127
-53
lines changed

6 files changed

+127
-53
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

+60-49
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,14 @@ use rustc_middle::bug;
1313
use rustc_middle::ty::layout::LayoutOf;
1414
pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
1515
use rustc_middle::ty::Ty;
16+
use rustc_session::config;
1617
use rustc_target::abi::call::ArgAbi;
1718
pub use rustc_target::abi::call::*;
1819
use rustc_target::abi::{self, HasDataLayout, Int};
1920
pub use rustc_target::spec::abi::Abi;
2021

2122
use libc::c_uint;
2223

23-
macro_rules! for_each_kind {
24-
($flags: ident, $f: ident, $($kind: ident),+) => ({
25-
$(if $flags.contains(ArgAttribute::$kind) { $f(llvm::Attribute::$kind) })+
26-
})
27-
}
28-
29-
trait ArgAttributeExt {
30-
fn for_each_kind<F>(&self, f: F)
31-
where
32-
F: FnMut(llvm::Attribute);
33-
}
34-
35-
impl ArgAttributeExt for ArgAttribute {
36-
fn for_each_kind<F>(&self, mut f: F)
37-
where
38-
F: FnMut(llvm::Attribute),
39-
{
40-
for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg, NoUndef)
41-
}
42-
}
43-
4424
pub trait ArgAttributesExt {
4525
fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value);
4626
fn apply_attrs_to_callsite(
@@ -58,10 +38,39 @@ fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
5838
cx.tcx.sess.opts.debugging_opts.mutable_noalias.unwrap_or(true)
5939
}
6040

41+
const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::Attribute); 1] =
42+
[(ArgAttribute::InReg, llvm::Attribute::InReg)];
43+
44+
const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::Attribute); 5] = [
45+
(ArgAttribute::NoAlias, llvm::Attribute::NoAlias),
46+
(ArgAttribute::NoCapture, llvm::Attribute::NoCapture),
47+
(ArgAttribute::NonNull, llvm::Attribute::NonNull),
48+
(ArgAttribute::ReadOnly, llvm::Attribute::ReadOnly),
49+
(ArgAttribute::NoUndef, llvm::Attribute::NoUndef),
50+
];
51+
6152
impl ArgAttributesExt for ArgAttributes {
6253
fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value) {
6354
let mut regular = self.regular;
6455
unsafe {
56+
// ABI-affecting attributes must always be applied
57+
for (attr, llattr) in ABI_AFFECTING_ATTRIBUTES {
58+
if regular.contains(attr) {
59+
llattr.apply_llfn(idx, llfn);
60+
}
61+
}
62+
if let Some(align) = self.pointee_align {
63+
llvm::LLVMRustAddAlignmentAttr(llfn, idx.as_uint(), align.bytes() as u32);
64+
}
65+
match self.arg_ext {
66+
ArgExtension::None => {}
67+
ArgExtension::Zext => llvm::Attribute::ZExt.apply_llfn(idx, llfn),
68+
ArgExtension::Sext => llvm::Attribute::SExt.apply_llfn(idx, llfn),
69+
}
70+
// Only apply remaining attributes when optimizing
71+
if cx.sess().opts.optimize == config::OptLevel::No {
72+
return;
73+
}
6574
let deref = self.pointee_size.bytes();
6675
if deref != 0 {
6776
if regular.contains(ArgAttribute::NonNull) {
@@ -71,22 +80,14 @@ impl ArgAttributesExt for ArgAttributes {
7180
}
7281
regular -= ArgAttribute::NonNull;
7382
}
74-
if let Some(align) = self.pointee_align {
75-
llvm::LLVMRustAddAlignmentAttr(llfn, idx.as_uint(), align.bytes() as u32);
83+
for (attr, llattr) in OPTIMIZATION_ATTRIBUTES {
84+
if regular.contains(attr) {
85+
llattr.apply_llfn(idx, llfn);
86+
}
7687
}
77-
regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
7888
if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
7989
llvm::Attribute::NoAlias.apply_llfn(idx, llfn);
8090
}
81-
match self.arg_ext {
82-
ArgExtension::None => {}
83-
ArgExtension::Zext => {
84-
llvm::Attribute::ZExt.apply_llfn(idx, llfn);
85-
}
86-
ArgExtension::Sext => {
87-
llvm::Attribute::SExt.apply_llfn(idx, llfn);
88-
}
89-
}
9091
}
9192
}
9293

@@ -98,6 +99,28 @@ impl ArgAttributesExt for ArgAttributes {
9899
) {
99100
let mut regular = self.regular;
100101
unsafe {
102+
// ABI-affecting attributes must always be applied
103+
for (attr, llattr) in ABI_AFFECTING_ATTRIBUTES {
104+
if regular.contains(attr) {
105+
llattr.apply_callsite(idx, callsite);
106+
}
107+
}
108+
if let Some(align) = self.pointee_align {
109+
llvm::LLVMRustAddAlignmentCallSiteAttr(
110+
callsite,
111+
idx.as_uint(),
112+
align.bytes() as u32,
113+
);
114+
}
115+
match self.arg_ext {
116+
ArgExtension::None => {}
117+
ArgExtension::Zext => llvm::Attribute::ZExt.apply_callsite(idx, callsite),
118+
ArgExtension::Sext => llvm::Attribute::SExt.apply_callsite(idx, callsite),
119+
}
120+
// Only apply remaining attributes when optimizing
121+
if cx.sess().opts.optimize == config::OptLevel::No {
122+
return;
123+
}
101124
let deref = self.pointee_size.bytes();
102125
if deref != 0 {
103126
if regular.contains(ArgAttribute::NonNull) {
@@ -111,26 +134,14 @@ impl ArgAttributesExt for ArgAttributes {
111134
}
112135
regular -= ArgAttribute::NonNull;
113136
}
114-
if let Some(align) = self.pointee_align {
115-
llvm::LLVMRustAddAlignmentCallSiteAttr(
116-
callsite,
117-
idx.as_uint(),
118-
align.bytes() as u32,
119-
);
137+
for (attr, llattr) in OPTIMIZATION_ATTRIBUTES {
138+
if regular.contains(attr) {
139+
llattr.apply_callsite(idx, callsite);
140+
}
120141
}
121-
regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
122142
if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
123143
llvm::Attribute::NoAlias.apply_callsite(idx, callsite);
124144
}
125-
match self.arg_ext {
126-
ArgExtension::None => {}
127-
ArgExtension::Zext => {
128-
llvm::Attribute::ZExt.apply_callsite(idx, callsite);
129-
}
130-
ArgExtension::Sext => {
131-
llvm::Attribute::SExt.apply_callsite(idx, callsite);
132-
}
133-
}
134145
}
135146
}
136147
}

src/test/codegen/fastcall-inreg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// as "inreg" like the C/C++ compilers for the platforms.
33
// x86 only.
44

5-
// compile-flags: --target i686-unknown-linux-gnu -C no-prepopulate-passes
5+
// compile-flags: --target i686-unknown-linux-gnu -O -C no-prepopulate-passes
66
// needs-llvm-components: x86
77

88
#![crate_type = "lib"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// compile-flags: -C opt-level=0 -C no-prepopulate-passes
2+
3+
// This test checks that arguments/returns in opt-level=0 builds,
4+
// while lacking attributes used for optimization, still have ABI-affecting attributes.
5+
6+
#![crate_type = "lib"]
7+
#![feature(rustc_attrs)]
8+
9+
pub struct S {
10+
_field: [i32; 8],
11+
}
12+
13+
// CHECK: zeroext i1 @boolean(i1 zeroext %x)
14+
#[no_mangle]
15+
pub fn boolean(x: bool) -> bool {
16+
x
17+
}
18+
19+
// CHECK-LABEL: @boolean_call
20+
#[no_mangle]
21+
pub fn boolean_call(x: bool, f: fn(bool) -> bool) -> bool {
22+
// CHECK: call zeroext i1 %f(i1 zeroext %x)
23+
f(x)
24+
}
25+
26+
// CHECK: align 4 i32* @borrow(i32* align 4 %x)
27+
#[no_mangle]
28+
pub fn borrow(x: &i32) -> &i32 {
29+
x
30+
}
31+
32+
// CHECK-LABEL: @borrow_call
33+
#[no_mangle]
34+
pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {
35+
// CHECK: call align 4 i32* %f(i32* align 4 %x)
36+
f(x)
37+
}
38+
39+
// CHECK: void @struct_(%S* sret(%S){{( %0)?}}, %S* %x)
40+
#[no_mangle]
41+
pub fn struct_(x: S) -> S {
42+
x
43+
}
44+
45+
// CHECK-LABEL: @struct_call
46+
#[no_mangle]
47+
pub fn struct_call(x: S, f: fn(S) -> S) -> S {
48+
// CHECK: call void %f(%S* sret(%S){{( %0)?}}, %S* %{{.+}})
49+
f(x)
50+
}
51+
52+
// CHECK: { i8, i8 } @enum_(i1 zeroext %x.0, i8 %x.1)
53+
#[no_mangle]
54+
pub fn enum_(x: Option<u8>) -> Option<u8> {
55+
x
56+
}
57+
58+
// CHECK-LABEL: @enum_call
59+
#[no_mangle]
60+
pub fn enum_call(x: Option<u8>, f: fn(Option<u8>) -> Option<u8>) -> Option<u8> {
61+
// CHECK: call { i8, i8 } %f(i1 zeroext %x.0, i8 %x.1)
62+
f(x)
63+
}

src/test/codegen/repr-transparent-aggregates-1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// compile-flags: -C no-prepopulate-passes
1+
// compile-flags: -O -C no-prepopulate-passes
22
//
33

44
// ignore-arm

src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// compile-flags: --target riscv64gc-unknown-linux-gnu -C no-prepopulate-passes
1+
// compile-flags: --target riscv64gc-unknown-linux-gnu -O -C no-prepopulate-passes
22
// needs-llvm-components: riscv
33

44
#![crate_type = "lib"]

src/test/codegen/union-abi.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// ignore-emscripten vectors passed directly
2-
// compile-flags: -C no-prepopulate-passes
2+
// compile-flags: -O -C no-prepopulate-passes
33

44
// This test that using union forward the abi of the inner type, as
55
// discussed in #54668

0 commit comments

Comments
 (0)