]> git.lizzy.rs Git - rust.git/commitdiff
Refine instruction_set inline rules
authorLokathor <zefria@gmail.com>
Mon, 7 Nov 2022 19:07:07 +0000 (12:07 -0700)
committerLokathor <zefria@gmail.com>
Fri, 25 Nov 2022 22:19:16 +0000 (15:19 -0700)
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.

compiler/rustc_mir_transform/src/inline.rs
src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff
src/test/mir-opt/inline/inline_instruction_set.rs
src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff

index 780b91d9215d5e2c08c68d32c9a081efff1a66b6..b1b527b569a88a81f7d2c24f0edb014b076a0eae 100644 (file)
@@ -375,7 +375,12 @@ fn check_codegen_attributes(
             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");
         }
 
@@ -453,6 +458,15 @@ fn check_mir_body(
                 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 { .. })
+            {
+                // 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())
             }
index e421428dcdff59c114955d5d7038e949f07ab74a..f1988ea4bd678f785b4035b2bfb86f0089c0cc31 100644 (file)
@@ -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>) }
       }
   
@@ -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>) }
       }
   
           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
       }
   }
   
index be36ff50c7ef13316cf3a442fc3d70249a986911..5dfb04943e39f1051ccfb22533d39798c5c120c0 100644 (file)
@@ -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
 
@@ -36,14 +38,18 @@ 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();
+    inline_always_and_using_inline_asm();
 }
 
 // EMIT_MIR inline_instruction_set.default.Inline.diff
@@ -51,4 +57,5 @@ pub fn default() {
     instruction_set_a32();
     instruction_set_t32();
     instruction_set_default();
+    inline_always_and_using_inline_asm();
 }
index 1ea2b87e53acd7a2188313c352a51c8d9eb39625..e777b2cc29eb36ff4c8dbd791065517b53da703a 100644 (file)
@@ -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>) }
       }
   
           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
       }
   }