Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine instruction_set MIR inline rules #104121

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion compiler/rustc_mir_transform/src/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,12 @@ impl<'tcx> Inliner<'tcx> {
return Err("incompatible sanitizer set");
}

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

Expand Down Expand Up @@ -453,6 +458,15 @@ impl<'tcx> Inliner<'tcx> {
if ty.needs_drop(tcx, self.param_env) && let Some(unwind) = unwind {
work_list.push(unwind);
}
} else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set
&& matches!(term.kind, TerminatorKind::InlineAsm { .. })
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
{
// During the attribute checking stage we allow a callee with no
// instruction_set assigned to count as compatible with a function that does
// assign one. However, during this stage we require an exact match when any
// inline-asm is detected. LLVM will still possibly do an inline later on
// if the no-attribute function ends up with the same instruction set anyway.
return Err("Cannot move inline-asm across instruction sets");
} else {
work_list.extend(term.successors())
}
Expand Down
28 changes: 22 additions & 6 deletions src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@
let _1: (); // in scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
let _2: (); // in scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
let _3: (); // in scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
+ scope 1 (inlined instruction_set_default) { // at $DIR/inline_instruction_set.rs:53:5: 53:30
let _4: (); // in scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
+ scope 1 (inlined instruction_set_default) { // at $DIR/inline_instruction_set.rs:59:5: 59:30
+ }
+ scope 2 (inlined inline_always_and_using_inline_asm) { // at $DIR/inline_instruction_set.rs:60:5: 60:41
+ scope 3 {
+ }
+ }

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

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

Expand All @@ -31,14 +36,25 @@
StorageLive(_3); // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
- // mir::Constant
- // + span: $DIR/inline_instruction_set.rs:53:5: 53:28
- // + span: $DIR/inline_instruction_set.rs:59:5: 59:28
- // + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) }
- }
-
- bb3: {
StorageDead(_3); // scope 0 at $DIR/inline_instruction_set.rs:+3:30: +3:31
_0 = const (); // scope 0 at $DIR/inline_instruction_set.rs:+0:18: +4:2
return; // scope 0 at $DIR/inline_instruction_set.rs:+4:2: +4:2
StorageLive(_4); // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
- _4 = inline_always_and_using_inline_asm() -> bb4; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
- // mir::Constant
- // + span: $DIR/inline_instruction_set.rs:60:5: 60:39
- // + literal: Const { ty: fn() {inline_always_and_using_inline_asm}, val: Value(<ZST>) }
+ asm!("/* do nothing */", options((empty))) -> bb3; // scope 3 at $DIR/inline_instruction_set.rs:43:14: 43:38
}

- bb4: {
+ bb3: {
StorageDead(_4); // scope 0 at $DIR/inline_instruction_set.rs:+4:41: +4:42
_0 = const (); // scope 0 at $DIR/inline_instruction_set.rs:+0:18: +5:2
return; // scope 0 at $DIR/inline_instruction_set.rs:+5:2: +5:2
}
}

11 changes: 9 additions & 2 deletions src/test/mir-opt/inline/inline_instruction_set.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Checks that only functions with the compatible instruction_set attributes are inlined.
//
// A function is "compatible" when the *callee* has the same attribute or no attribute.
//
// compile-flags: --target thumbv4t-none-eabi
// needs-llvm-components: arm

Expand Down Expand Up @@ -36,19 +38,24 @@ fn instruction_set_t32() {}
#[inline]
fn instruction_set_default() {}

#[inline(always)]
fn inline_always_and_using_inline_asm() {
unsafe { asm!("/* do nothing */") };
}

// EMIT_MIR inline_instruction_set.t32.Inline.diff
#[instruction_set(arm::t32)]
pub fn t32() {
instruction_set_a32();
instruction_set_t32();
// The default instruction set is currently
// conservatively assumed to be incompatible.
instruction_set_default();
tmiasko marked this conversation as resolved.
Show resolved Hide resolved
inline_always_and_using_inline_asm();
}

// EMIT_MIR inline_instruction_set.default.Inline.diff
pub fn default() {
instruction_set_a32();
instruction_set_t32();
instruction_set_default();
inline_always_and_using_inline_asm();
}
38 changes: 25 additions & 13 deletions src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@
let mut _0: (); // return place in scope 0 at $DIR/inline_instruction_set.rs:+0:14: +0:14
let _1: (); // in scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
let _2: (); // in scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
let _3: (); // in scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
+ scope 1 (inlined instruction_set_t32) { // at $DIR/inline_instruction_set.rs:43:5: 43:26
let _3: (); // in scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
let _4: (); // in scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
+ scope 1 (inlined instruction_set_t32) { // at $DIR/inline_instruction_set.rs:50:5: 50:26
+ }
+ scope 2 (inlined instruction_set_default) { // at $DIR/inline_instruction_set.rs:51:5: 51:30
+ }

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

Expand All @@ -22,25 +25,34 @@
StorageLive(_2); // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
- _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
- // mir::Constant
- // + span: $DIR/inline_instruction_set.rs:43:5: 43:24
- // + span: $DIR/inline_instruction_set.rs:50:5: 50:24
- // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(<ZST>) }
- }
-
- bb2: {
StorageDead(_2); // scope 0 at $DIR/inline_instruction_set.rs:+2:26: +2:27
StorageLive(_3); // scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
+ _3 = instruction_set_default() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
StorageLive(_3); // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
- // mir::Constant
- // + span: $DIR/inline_instruction_set.rs:51:5: 51:28
- // + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) }
- }
-
- bb3: {
StorageDead(_3); // scope 0 at $DIR/inline_instruction_set.rs:+3:30: +3:31
StorageLive(_4); // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
- _4 = inline_always_and_using_inline_asm() -> bb4; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
+ _4 = inline_always_and_using_inline_asm() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
// mir::Constant
// + span: $DIR/inline_instruction_set.rs:46:5: 46:28
// + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) }
// + span: $DIR/inline_instruction_set.rs:52:5: 52:39
// + literal: Const { ty: fn() {inline_always_and_using_inline_asm}, val: Value(<ZST>) }
}

- bb3: {
- bb4: {
+ bb2: {
StorageDead(_3); // scope 0 at $DIR/inline_instruction_set.rs:+5:30: +5:31
_0 = const (); // scope 0 at $DIR/inline_instruction_set.rs:+0:14: +6:2
return; // scope 0 at $DIR/inline_instruction_set.rs:+6:2: +6:2
StorageDead(_4); // scope 0 at $DIR/inline_instruction_set.rs:+4:41: +4:42
_0 = const (); // scope 0 at $DIR/inline_instruction_set.rs:+0:14: +5:2
return; // scope 0 at $DIR/inline_instruction_set.rs:+5:2: +5:2
}
}