about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTomasz Miąsko <tomasz.miasko@gmail.com>2021-02-05 00:00:00 +0000
committerTomasz Miąsko <tomasz.miasko@gmail.com>2021-02-05 00:00:00 +0000
commiteb5e2d08c7e500c5612c6468036df7058fcc5a79 (patch)
treec6324890231c0fd6fa299396d343f966b68ab4eb
parent9e5d58fb420a487ae30f38141eccdc8d79fb8d58 (diff)
downloadrust-eb5e2d08c7e500c5612c6468036df7058fcc5a79.tar.gz
rust-eb5e2d08c7e500c5612c6468036df7058fcc5a79.zip
Never MIR inline functions with a different instruction set
-rw-r--r--compiler/rustc_attr/src/builtin.rs2
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs5
-rw-r--r--src/test/mir-opt/inline/inline-instruction-set.rs54
-rw-r--r--src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff45
-rw-r--r--src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff47
5 files changed, 152 insertions, 1 deletions
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(<ZST>)) }
+      }
+  
+      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(<ZST>)) }
+      }
+  
+      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(<ZST>)) }
+-     }
+- 
+-     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(<ZST>)) }
+      }
+  
+      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(<ZST>)) }
+-     }
+- 
+-     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(<ZST>)) }
+      }
+  
+-     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
+      }
+  }
+