From eb5e2d08c7e500c5612c6468036df7058fcc5a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 5 Feb 2021 00:00:00 +0000 Subject: [PATCH] Never MIR inline functions with a different instruction set --- compiler/rustc_attr/src/builtin.rs | 2 +- compiler/rustc_mir/src/transform/inline.rs | 5 ++ .../mir-opt/inline/inline-instruction-set.rs | 54 +++++++++++++++++++ ...inline_instruction_set.default.Inline.diff | 45 ++++++++++++++++ .../inline_instruction_set.t32.Inline.diff | 47 ++++++++++++++++ 5 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 src/test/mir-opt/inline/inline-instruction-set.rs create mode 100644 src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff create mode 100644 src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 696d5fdd6cd..aca3fbbca13 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -74,7 +74,7 @@ pub enum InlineAttr { Never, } -#[derive(Clone, Encodable, Decodable, Debug)] +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum InstructionSetAttr { ArmA32, ArmT32, diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index dd9a514466d..1635a95f46e 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -281,6 +281,11 @@ impl Inliner<'tcx> { return false; } + if self.codegen_fn_attrs.instruction_set != codegen_fn_attrs.instruction_set { + debug!("`callee has incompatible instruction set - not inlining"); + return false; + } + let hinted = match codegen_fn_attrs.inline { // Just treat inline(always) as a hint for now, // there are cases that prevent inlining that we diff --git a/src/test/mir-opt/inline/inline-instruction-set.rs b/src/test/mir-opt/inline/inline-instruction-set.rs new file mode 100644 index 00000000000..be36ff50c7e --- /dev/null +++ b/src/test/mir-opt/inline/inline-instruction-set.rs @@ -0,0 +1,54 @@ +// Checks that only functions with the compatible instruction_set attributes are inlined. +// +// compile-flags: --target thumbv4t-none-eabi +// needs-llvm-components: arm + +#![crate_type = "lib"] +#![feature(rustc_attrs)] +#![feature(no_core, lang_items)] +#![feature(isa_attribute)] +#![no_core] + +#[rustc_builtin_macro] +#[macro_export] +macro_rules! asm { + ("assembly template", + $(operands,)* + $(options($(option),*))? + ) => { + /* compiler built-in */ + }; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[instruction_set(arm::a32)] +#[inline] +fn instruction_set_a32() {} + +#[instruction_set(arm::t32)] +#[inline] +fn instruction_set_t32() {} + +#[inline] +fn instruction_set_default() {} + +// 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(); +} + +// EMIT_MIR inline_instruction_set.default.Inline.diff +pub fn default() { + instruction_set_a32(); + instruction_set_t32(); + instruction_set_default(); +} diff --git a/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff b/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff new file mode 100644 index 00000000000..334cf5a08e2 --- /dev/null +++ b/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff @@ -0,0 +1,45 @@ +- // MIR for `default` before Inline ++ // MIR for `default` after Inline + + fn default() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-instruction-set.rs:50:18: 50:18 + let _1: (); // in scope 0 at $DIR/inline-instruction-set.rs:51:5: 51:26 + let _2: (); // in scope 0 at $DIR/inline-instruction-set.rs:52:5: 52:26 + let _3: (); // in scope 0 at $DIR/inline-instruction-set.rs:53:5: 53:30 ++ scope 1 (inlined instruction_set_default) { // at $DIR/inline-instruction-set.rs:53:5: 53:30 ++ } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-instruction-set.rs:51:5: 51:26 + _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:51:5: 51:26 + // mir::Constant + // + span: $DIR/inline-instruction-set.rs:51:5: 51:24 + // + literal: Const { ty: fn() {instruction_set_a32}, val: Value(Scalar()) } + } + + bb1: { + StorageDead(_1); // scope 0 at $DIR/inline-instruction-set.rs:51:26: 51:27 + StorageLive(_2); // scope 0 at $DIR/inline-instruction-set.rs:52:5: 52:26 + _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:52:5: 52:26 + // mir::Constant + // + span: $DIR/inline-instruction-set.rs:52:5: 52:24 + // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(Scalar()) } + } + + bb2: { + StorageDead(_2); // scope 0 at $DIR/inline-instruction-set.rs:52:26: 52:27 + StorageLive(_3); // scope 0 at $DIR/inline-instruction-set.rs:53:5: 53:30 +- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline-instruction-set.rs:53:5: 53:30 +- // mir::Constant +- // + span: $DIR/inline-instruction-set.rs:53:5: 53:28 +- // + literal: Const { ty: fn() {instruction_set_default}, val: Value(Scalar()) } +- } +- +- bb3: { ++ _3 = const (); // scope 1 at $DIR/inline-instruction-set.rs:53:5: 53:30 + StorageDead(_3); // scope 0 at $DIR/inline-instruction-set.rs:53:30: 53:31 + _0 = const (); // scope 0 at $DIR/inline-instruction-set.rs:50:18: 54:2 + return; // scope 0 at $DIR/inline-instruction-set.rs:54:2: 54:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff b/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff new file mode 100644 index 00000000000..920b68c9daa --- /dev/null +++ b/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff @@ -0,0 +1,47 @@ +- // MIR for `t32` before Inline ++ // MIR for `t32` after Inline + + fn t32() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-instruction-set.rs:41:14: 41:14 + let _1: (); // in scope 0 at $DIR/inline-instruction-set.rs:42:5: 42:26 + let _2: (); // in scope 0 at $DIR/inline-instruction-set.rs:43:5: 43:26 + let _3: (); // in scope 0 at $DIR/inline-instruction-set.rs:46:5: 46:30 ++ scope 1 (inlined instruction_set_t32) { // at $DIR/inline-instruction-set.rs:43:5: 43:26 ++ } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-instruction-set.rs:42:5: 42:26 + _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:42:5: 42:26 + // mir::Constant + // + span: $DIR/inline-instruction-set.rs:42:5: 42:24 + // + literal: Const { ty: fn() {instruction_set_a32}, val: Value(Scalar()) } + } + + bb1: { + StorageDead(_1); // scope 0 at $DIR/inline-instruction-set.rs:42:26: 42:27 + StorageLive(_2); // scope 0 at $DIR/inline-instruction-set.rs:43:5: 43:26 +- _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:43:5: 43:26 +- // mir::Constant +- // + span: $DIR/inline-instruction-set.rs:43:5: 43:24 +- // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(Scalar()) } +- } +- +- bb2: { ++ _2 = const (); // scope 1 at $DIR/inline-instruction-set.rs:43:5: 43:26 + StorageDead(_2); // scope 0 at $DIR/inline-instruction-set.rs:43:26: 43:27 + StorageLive(_3); // scope 0 at $DIR/inline-instruction-set.rs:46:5: 46:30 +- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline-instruction-set.rs:46:5: 46:30 ++ _3 = instruction_set_default() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:46:5: 46:30 + // mir::Constant + // + span: $DIR/inline-instruction-set.rs:46:5: 46:28 + // + literal: Const { ty: fn() {instruction_set_default}, val: Value(Scalar()) } + } + +- bb3: { ++ bb2: { + StorageDead(_3); // scope 0 at $DIR/inline-instruction-set.rs:46:30: 46:31 + _0 = const (); // scope 0 at $DIR/inline-instruction-set.rs:41:14: 47:2 + return; // scope 0 at $DIR/inline-instruction-set.rs:47:2: 47:2 + } + } +