Skip to content

Commit 719343f

Browse files
committed
Auto merge of #162460 - Jamesbarford:feat/inline-always+target-feature-#2, r=nikic,traviscross
Feat - `#[inline(always)] + #[target_feature(enable = "....")]` #2 This is broadly a resurrection of `#[inline(always)] + #[target_feature(enable = "...")]`. - Applies the `alwaysinline` attribute to the function definition. - `version < LLVM23` downgrades to an `inline` hint. - Remove the check for using [target features + inline always](compiler/rustc_codegen_ssa/src/codegen_attrs.rs) This should now be sound thanks to * llvm/llvm-project#205113 * llvm/llvm-project#209345 Therefore, it should be okay to just allow this combination. But we can also have a period of unstable experimentation if t-lang prefers. Reference PR; rust-lang/reference#2391 r? @RalfJung
2 parents 6a58677 + 1cd5e32 commit 719343f

7 files changed

Lines changed: 85 additions & 55 deletions

File tree

‎compiler/rustc_codegen_llvm/src/attributes.rs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ pub(crate) fn inline_attr<'tcx, 'll>(
6868

6969
match inline {
7070
InlineAttr::Hint => Some(AttributeKind::InlineHint.create_attr(cx.llcx)),
71+
// LLVM 22 and older may inline a target-featured function into a caller
72+
// that lacks those features. Keep the function inlineable, but do not force it.
73+
InlineAttr::Always
74+
if !codegen_fn_attrs.target_features.is_empty()
75+
&& llvm_util::get_version() < (23, 0, 0) =>
76+
{
77+
Some(AttributeKind::InlineHint.create_attr(cx.llcx))
78+
}
7179
InlineAttr::Always | InlineAttr::Force { .. } => {
7280
Some(AttributeKind::AlwaysInline.create_attr(cx.llcx))
7381
}

‎compiler/rustc_codegen_ssa/src/codegen_attrs.rs‎

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -415,33 +415,6 @@ fn check_result(
415415
interesting_spans: InterestingAttributeDiagnosticSpans,
416416
codegen_fn_attrs: &CodegenFnAttrs,
417417
) {
418-
// If a function uses `#[target_feature]` it can't be inlined into general
419-
// purpose functions as they wouldn't have the right target features
420-
// enabled. For that reason we also forbid `#[inline(always)]` as it can't be
421-
// respected.
422-
//
423-
// `#[rustc_force_inline]` doesn't need to be prohibited here, only
424-
// `#[inline(always)]`, as forced inlining is implemented entirely within
425-
// rustc (and so the MIR inliner can do any necessary checks for compatible target
426-
// features).
427-
//
428-
// This sidesteps the LLVM blockers in enabling `target_features` +
429-
// `inline(always)` to be used together (see rust-lang/rust#116573 and
430-
// llvm/llvm-project#70563).
431-
if !codegen_fn_attrs.target_features.is_empty()
432-
&& matches!(codegen_fn_attrs.inline, InlineAttr::Always)
433-
&& let Some(span) = interesting_spans.inline
434-
{
435-
let mut diag = tcx
436-
.dcx()
437-
.struct_span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`");
438-
diag.note(
439-
"See this issue for full discussion: \
440-
https://github.com/rust-lang/rust/issues/145574",
441-
);
442-
diag.emit();
443-
}
444-
445418
// warn that inline has no effect when no_sanitize is present
446419
if codegen_fn_attrs.sanitizers != SanitizerFnAttrs::default()
447420
&& codegen_fn_attrs.inline.always()

‎compiler/rustc_lint/src/lib.rs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,9 @@ fn register_builtins(store: &mut LintStore) {
698698
store.register_removed("soft_unstable", "the general soft-unstable mechanism has been removed");
699699
store.register_removed(
700700
"inline_always_mismatching_target_features",
701-
"replaced by a hard error for `#[inline(always)]` with `#[target_feature]`",
701+
"replaced by a hard error for `#[inline(always)]` with `#[target_feature]`. \
702+
This was prior to LLVM23 where combining these could be unsound. See \
703+
<https://github.com/rust-lang/rust/issues/145574> for more information",
702704
);
703705
store.register_removed(
704706
"repr_transparent_external_private_fields",
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ only-x86_64
2+
//@ min-llvm-version: 23
3+
//@ compile-flags: -Copt-level=3
4+
5+
#![crate_type = "lib"]
6+
#![allow(unused_unsafe)]
7+
8+
use std::arch::x86_64::_bzhi_u64;
9+
10+
#[inline(always)]
11+
#[target_feature(enable = "bmi2")]
12+
#[unsafe(no_mangle)]
13+
pub unsafe fn callee_requires_bmi2() -> u64 {
14+
// black box this as `_bzhi_u64(1, 2)` can evaluate to `1` at compile time and LLVM is smart
15+
// enough to see that it then can ignore `bmi2` as this returns a constant. Which is safe to
16+
// do.
17+
std::hint::black_box(_bzhi_u64(1, 2))
18+
}
19+
20+
#[unsafe(no_mangle)]
21+
// CHECK-LABEL: define{{.*}} @caller_only()
22+
// CHECK: [[TMP:%.+]] = tail call noundef i64 @callee_requires_bmi2()
23+
pub unsafe fn caller_only() {
24+
let _x = callee_requires_bmi2();
25+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//@ add-minicore
2+
//@ compile-flags: --target aarch64-unknown-linux-gnu -Zinline-mir=no -C no-prepopulate-passes -Copt-level=3
3+
//@ needs-llvm-components: aarch64
4+
//@ min-llvm-version: 23
5+
6+
#![crate_type = "lib"]
7+
#![feature(no_core, lang_items)]
8+
#![no_core]
9+
10+
extern crate minicore;
11+
use minicore::*;
12+
13+
#[inline(always)]
14+
#[target_feature(enable = "neon")]
15+
#[no_mangle]
16+
pub fn single_target_feature() -> i32 {
17+
42
18+
}
19+
20+
#[inline(always)]
21+
#[target_feature(enable = "neon,i8mm")]
22+
#[no_mangle]
23+
// CHECK: define{{( noundef)?}} i32 @multiple_target_features() unnamed_addr #1{{( !guid ![0-9]+)?}} {
24+
pub fn multiple_target_features() -> i32 {
25+
// CHECK: %_0 = call{{( noundef)?}} i32 @single_target_feature() #3
26+
single_target_feature()
27+
}
28+
29+
#[no_mangle]
30+
// CHECK: define{{( noundef)?}} i32 @inherits_from_global() unnamed_addr #2{{( !guid ![0-9]+)?}} {
31+
pub fn inherits_from_global() -> i32 {
32+
unsafe {
33+
// CHECK: %_0 = call{{( noundef)?}} i32 @single_target_feature() #3
34+
single_target_feature()
35+
}
36+
}

‎tests/ui/target-feature/invalid-attribute.rs‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,6 @@ type Uwu = ();
6666
//~^ ERROR attribute cannot be used on
6767
trait Baz {}
6868

69-
#[inline(always)]
70-
//~^ ERROR: cannot use `#[inline(always)]`
71-
//~| NOTE: See this issue for full discussion: https://github.com/rust-lang/rust/issues/145574
72-
#[target_feature(enable = "sse2")]
73-
unsafe fn test() {}
74-
7569
#[target_feature(enable = "sse2")]
7670
//~^ ERROR attribute cannot be used on
7771
static A: () = ();

‎tests/ui/target-feature/invalid-attribute.stderr‎

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -121,39 +121,39 @@ LL | #[target_feature(enable = "sse2")]
121121
= help: the `target_feature` attribute can only be applied to functions
122122

123123
error: the `target_feature` attribute cannot be used on statics
124-
--> $DIR/invalid-attribute.rs:75:3
124+
--> $DIR/invalid-attribute.rs:69:3
125125
|
126126
LL | #[target_feature(enable = "sse2")]
127127
| ^^^^^^^^^^^^^^
128128
|
129129
= help: the `target_feature` attribute can only be applied to functions
130130

131131
error: the `target_feature` attribute cannot be used on trait impl blocks
132-
--> $DIR/invalid-attribute.rs:79:3
132+
--> $DIR/invalid-attribute.rs:73:3
133133
|
134134
LL | #[target_feature(enable = "sse2")]
135135
| ^^^^^^^^^^^^^^
136136
|
137137
= help: the `target_feature` attribute can only be applied to functions
138138

139139
error: the `target_feature` attribute cannot be used on inherent impl blocks
140-
--> $DIR/invalid-attribute.rs:85:3
140+
--> $DIR/invalid-attribute.rs:79:3
141141
|
142142
LL | #[target_feature(enable = "sse2")]
143143
| ^^^^^^^^^^^^^^
144144
|
145145
= help: the `target_feature` attribute can only be applied to functions
146146

147147
error: the `target_feature` attribute cannot be used on expressions
148-
--> $DIR/invalid-attribute.rs:106:7
148+
--> $DIR/invalid-attribute.rs:100:7
149149
|
150150
LL | #[target_feature(enable = "sse2")]
151151
| ^^^^^^^^^^^^^^
152152
|
153153
= help: the `target_feature` attribute can only be applied to functions
154154

155155
error: the `target_feature` attribute cannot be used on closures
156-
--> $DIR/invalid-attribute.rs:112:7
156+
--> $DIR/invalid-attribute.rs:106:7
157157
|
158158
LL | #[target_feature(enable = "sse2")]
159159
| ^^^^^^^^^^^^^^
@@ -168,16 +168,8 @@ LL | #[target_feature(enable = "foo")]
168168
|
169169
= help: valid names are: `fma`, `xop`, `adx`, `aes`, and `avx` and X more
170170

171-
error: cannot use `#[inline(always)]` with `#[target_feature]`
172-
--> $DIR/invalid-attribute.rs:69:1
173-
|
174-
LL | #[inline(always)]
175-
| ^^^^^^^^^^^^^^^^^
176-
|
177-
= note: See this issue for full discussion: https://github.com/rust-lang/rust/issues/145574
178-
179171
error[E0046]: not all trait items implemented, missing: `foo`
180-
--> $DIR/invalid-attribute.rs:81:1
172+
--> $DIR/invalid-attribute.rs:75:1
181173
|
182174
LL | impl Quux for u8 {}
183175
| ^^^^^^^^^^^^^^^^ missing `foo` in implementation
@@ -186,7 +178,7 @@ LL | fn foo();
186178
| --------- `foo` from trait
187179

188180
error: `#[target_feature(..)]` cannot be applied to safe trait method
189-
--> $DIR/invalid-attribute.rs:95:5
181+
--> $DIR/invalid-attribute.rs:89:5
190182
|
191183
LL | #[target_feature(enable = "sse2")]
192184
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
@@ -195,21 +187,21 @@ LL | fn foo() {}
195187
| -------- not an `unsafe` function
196188

197189
error[E0053]: method `foo` has an incompatible type for trait
198-
--> $DIR/invalid-attribute.rs:98:5
190+
--> $DIR/invalid-attribute.rs:92:5
199191
|
200192
LL | fn foo() {}
201193
| ^^^^^^^^ expected safe fn, found unsafe fn
202194
|
203195
note: type in trait
204-
--> $DIR/invalid-attribute.rs:90:5
196+
--> $DIR/invalid-attribute.rs:84:5
205197
|
206198
LL | fn foo();
207199
| ^^^^^^^^^
208200
= note: expected signature `fn()`
209201
found signature `#[target_feature(..)] fn()`
210202

211203
error: the feature named `+sse2` is not valid for this target
212-
--> $DIR/invalid-attribute.rs:117:18
204+
--> $DIR/invalid-attribute.rs:111:18
213205
|
214206
LL | #[target_feature(enable = "+sse2")]
215207
| ^^^^^^^^^^^^^^^^ `+sse2` is not valid for this target
@@ -221,22 +213,22 @@ LL + #[target_feature(enable = "sse2")]
221213
|
222214

223215
error: the feature named `sse5` is not valid for this target
224-
--> $DIR/invalid-attribute.rs:122:18
216+
--> $DIR/invalid-attribute.rs:116:18
225217
|
226218
LL | #[target_feature(enable = "sse5")]
227219
| ^^^^^^^^^^^^^^^ `sse5` is not valid for this target
228220
|
229221
= help: valid names are: `sse`, `sse2`, `sse3`, `sse4a`, and `ssse3` and X more
230222

231223
error: the feature named `avx512` is not valid for this target
232-
--> $DIR/invalid-attribute.rs:127:18
224+
--> $DIR/invalid-attribute.rs:121:18
233225
|
234226
LL | #[target_feature(enable = "avx512")]
235227
| ^^^^^^^^^^^^^^^^^ `avx512` is not valid for this target
236228
|
237229
= help: valid names are: `avx512f`, `avx2`, `avx512bw`, `avx512cd`, and `avx512dq` and X more
238230

239-
error: aborting due to 26 previous errors
231+
error: aborting due to 25 previous errors
240232

241233
Some errors have detailed explanations: E0046, E0053, E0539.
242234
For more information about an error, try `rustc --explain E0046`.

0 commit comments

Comments
 (0)