Skip to content

Commit 5a69ade

Browse files
authored
Rollup merge of rust-lang#104121 - Lokathor:mir-opt-when-instruction-set-missing-on-callee, r=tmiasko
Refine `instruction_set` MIR inline rules Previously an exact match of the `instruction_set` attribute was required for an MIR inline to be considered. This change checks for an exact match *only* if the callee sets an `instruction_set` in the first place. When the callee does not declare an instruction set then it is considered to be platform agnostic code and it's allowed to be inline'd into the caller. cc `@oli-obk` [Edit] Zulip Context: https://rust-lang.zulipchat.com/#narrow/stream/189540-t-compiler.2Fwg-mir-opt/topic/What.20exactly.20does.20the.20MIR.20optimizer.20do.3F
2 parents 5fa44b5 + ea47943 commit 5a69ade

File tree

4 files changed

+71
-22
lines changed

4 files changed

+71
-22
lines changed

compiler/rustc_mir_transform/src/inline.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,12 @@ impl<'tcx> Inliner<'tcx> {
375375
return Err("incompatible sanitizer set");
376376
}
377377

378-
if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set {
378+
// Two functions are compatible if the callee has no attribute (meaning
379+
// that it's codegen agnostic), or sets an attribute that is identical
380+
// to this function's attribute.
381+
if callee_attrs.instruction_set.is_some()
382+
&& callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set
383+
{
379384
return Err("incompatible instruction set");
380385
}
381386

@@ -453,6 +458,15 @@ impl<'tcx> Inliner<'tcx> {
453458
if ty.needs_drop(tcx, self.param_env) && let Some(unwind) = unwind {
454459
work_list.push(unwind);
455460
}
461+
} else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set
462+
&& matches!(term.kind, TerminatorKind::InlineAsm { .. })
463+
{
464+
// During the attribute checking stage we allow a callee with no
465+
// instruction_set assigned to count as compatible with a function that does
466+
// assign one. However, during this stage we require an exact match when any
467+
// inline-asm is detected. LLVM will still possibly do an inline later on
468+
// if the no-attribute function ends up with the same instruction set anyway.
469+
return Err("Cannot move inline-asm across instruction sets");
456470
} else {
457471
work_list.extend(term.successors())
458472
}

src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff

+22-6
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@
66
let _1: (); // in scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
77
let _2: (); // in scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
88
let _3: (); // in scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
9-
+ scope 1 (inlined instruction_set_default) { // at $DIR/inline_instruction_set.rs:53:5: 53:30
9+
let _4: (); // in scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
10+
+ scope 1 (inlined instruction_set_default) { // at $DIR/inline_instruction_set.rs:59:5: 59:30
11+
+ }
12+
+ scope 2 (inlined inline_always_and_using_inline_asm) { // at $DIR/inline_instruction_set.rs:60:5: 60:41
13+
+ scope 3 {
14+
+ }
1015
+ }
1116

1217
bb0: {
1318
StorageLive(_1); // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
1419
_1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
1520
// mir::Constant
16-
// + span: $DIR/inline_instruction_set.rs:51:5: 51:24
21+
// + span: $DIR/inline_instruction_set.rs:57:5: 57:24
1722
// + literal: Const { ty: fn() {instruction_set_a32}, val: Value(<ZST>) }
1823
}
1924

@@ -22,7 +27,7 @@
2227
StorageLive(_2); // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
2328
_2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
2429
// mir::Constant
25-
// + span: $DIR/inline_instruction_set.rs:52:5: 52:24
30+
// + span: $DIR/inline_instruction_set.rs:58:5: 58:24
2631
// + literal: Const { ty: fn() {instruction_set_t32}, val: Value(<ZST>) }
2732
}
2833

@@ -31,14 +36,25 @@
3136
StorageLive(_3); // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
3237
- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
3338
- // mir::Constant
34-
- // + span: $DIR/inline_instruction_set.rs:53:5: 53:28
39+
- // + span: $DIR/inline_instruction_set.rs:59:5: 59:28
3540
- // + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) }
3641
- }
3742
-
3843
- bb3: {
3944
StorageDead(_3); // scope 0 at $DIR/inline_instruction_set.rs:+3:30: +3:31
40-
_0 = const (); // scope 0 at $DIR/inline_instruction_set.rs:+0:18: +4:2
41-
return; // scope 0 at $DIR/inline_instruction_set.rs:+4:2: +4:2
45+
StorageLive(_4); // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
46+
- _4 = inline_always_and_using_inline_asm() -> bb4; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
47+
- // mir::Constant
48+
- // + span: $DIR/inline_instruction_set.rs:60:5: 60:39
49+
- // + literal: Const { ty: fn() {inline_always_and_using_inline_asm}, val: Value(<ZST>) }
50+
+ asm!("/* do nothing */", options((empty))) -> bb3; // scope 3 at $DIR/inline_instruction_set.rs:43:14: 43:38
51+
}
52+
53+
- bb4: {
54+
+ bb3: {
55+
StorageDead(_4); // scope 0 at $DIR/inline_instruction_set.rs:+4:41: +4:42
56+
_0 = const (); // scope 0 at $DIR/inline_instruction_set.rs:+0:18: +5:2
57+
return; // scope 0 at $DIR/inline_instruction_set.rs:+5:2: +5:2
4258
}
4359
}
4460

src/test/mir-opt/inline/inline_instruction_set.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// Checks that only functions with the compatible instruction_set attributes are inlined.
22
//
3+
// A function is "compatible" when the *callee* has the same attribute or no attribute.
4+
//
35
// compile-flags: --target thumbv4t-none-eabi
46
// needs-llvm-components: arm
57

@@ -36,19 +38,24 @@ fn instruction_set_t32() {}
3638
#[inline]
3739
fn instruction_set_default() {}
3840

41+
#[inline(always)]
42+
fn inline_always_and_using_inline_asm() {
43+
unsafe { asm!("/* do nothing */") };
44+
}
45+
3946
// EMIT_MIR inline_instruction_set.t32.Inline.diff
4047
#[instruction_set(arm::t32)]
4148
pub fn t32() {
4249
instruction_set_a32();
4350
instruction_set_t32();
44-
// The default instruction set is currently
45-
// conservatively assumed to be incompatible.
4651
instruction_set_default();
52+
inline_always_and_using_inline_asm();
4753
}
4854

4955
// EMIT_MIR inline_instruction_set.default.Inline.diff
5056
pub fn default() {
5157
instruction_set_a32();
5258
instruction_set_t32();
5359
instruction_set_default();
60+
inline_always_and_using_inline_asm();
5461
}

src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff

+25-13
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
let mut _0: (); // return place in scope 0 at $DIR/inline_instruction_set.rs:+0:14: +0:14
66
let _1: (); // in scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
77
let _2: (); // in scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
8-
let _3: (); // in scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
9-
+ scope 1 (inlined instruction_set_t32) { // at $DIR/inline_instruction_set.rs:43:5: 43:26
8+
let _3: (); // in scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
9+
let _4: (); // in scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
10+
+ scope 1 (inlined instruction_set_t32) { // at $DIR/inline_instruction_set.rs:50:5: 50:26
11+
+ }
12+
+ scope 2 (inlined instruction_set_default) { // at $DIR/inline_instruction_set.rs:51:5: 51:30
1013
+ }
1114

1215
bb0: {
1316
StorageLive(_1); // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
1417
_1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
1518
// mir::Constant
16-
// + span: $DIR/inline_instruction_set.rs:42:5: 42:24
19+
// + span: $DIR/inline_instruction_set.rs:49:5: 49:24
1720
// + literal: Const { ty: fn() {instruction_set_a32}, val: Value(<ZST>) }
1821
}
1922

@@ -22,25 +25,34 @@
2225
StorageLive(_2); // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
2326
- _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
2427
- // mir::Constant
25-
- // + span: $DIR/inline_instruction_set.rs:43:5: 43:24
28+
- // + span: $DIR/inline_instruction_set.rs:50:5: 50:24
2629
- // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(<ZST>) }
2730
- }
2831
-
2932
- bb2: {
3033
StorageDead(_2); // scope 0 at $DIR/inline_instruction_set.rs:+2:26: +2:27
31-
StorageLive(_3); // scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
32-
- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
33-
+ _3 = instruction_set_default() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
34+
StorageLive(_3); // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
35+
- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
36+
- // mir::Constant
37+
- // + span: $DIR/inline_instruction_set.rs:51:5: 51:28
38+
- // + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) }
39+
- }
40+
-
41+
- bb3: {
42+
StorageDead(_3); // scope 0 at $DIR/inline_instruction_set.rs:+3:30: +3:31
43+
StorageLive(_4); // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
44+
- _4 = inline_always_and_using_inline_asm() -> bb4; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
45+
+ _4 = inline_always_and_using_inline_asm() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
3446
// mir::Constant
35-
// + span: $DIR/inline_instruction_set.rs:46:5: 46:28
36-
// + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) }
47+
// + span: $DIR/inline_instruction_set.rs:52:5: 52:39
48+
// + literal: Const { ty: fn() {inline_always_and_using_inline_asm}, val: Value(<ZST>) }
3749
}
3850

39-
- bb3: {
51+
- bb4: {
4052
+ bb2: {
41-
StorageDead(_3); // scope 0 at $DIR/inline_instruction_set.rs:+5:30: +5:31
42-
_0 = const (); // scope 0 at $DIR/inline_instruction_set.rs:+0:14: +6:2
43-
return; // scope 0 at $DIR/inline_instruction_set.rs:+6:2: +6:2
53+
StorageDead(_4); // scope 0 at $DIR/inline_instruction_set.rs:+4:41: +4:42
54+
_0 = const (); // scope 0 at $DIR/inline_instruction_set.rs:+0:14: +5:2
55+
return; // scope 0 at $DIR/inline_instruction_set.rs:+5:2: +5:2
4456
}
4557
}
4658

0 commit comments

Comments
 (0)