about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduardo Sánchez Muñoz <eduardosm-dev@e64.io>2024-03-21 17:54:53 +0100
committerEduardo Sánchez Muñoz <eduardosm-dev@e64.io>2024-03-21 18:20:54 +0100
commit89bc81f0dfdd128a9c4b906efebf5070a70f39d2 (patch)
treed3a99e8f3fdfc48a0bf7c2efe6c5d70e2c2d78c1
parent6bcd9bce9e7d1d3943478da8b5f6b072948f3c6d (diff)
downloadrust-89bc81f0dfdd128a9c4b906efebf5070a70f39d2.tar.gz
rust-89bc81f0dfdd128a9c4b906efebf5070a70f39d2.zip
Allow `llvm.x86.sse2.pause` instrinsic to be called without SSE2
The instrinsic is compiled to a `pause` instruction, which behaves like a no-op when SSE2 is not available.

https://www.felixcloutier.com/x86/pause.html
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs13
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs6
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs25
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-sse2.rs5
4 files changed, 43 insertions, 6 deletions
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 7cd397625dc..7b7921219e6 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -88,6 +88,19 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                 this.write_immediate(*sub, &this.project_field(dest, 1)?)?;
             }
 
+            // Used to implement the `_mm_pause` function.
+            // The intrinsic is used to hint the processor that the code is in a spin-loop.
+            // It is compiled down to a `pause` instruction. When SSE2 is not available,
+            // the instruction behaves like a no-op, so it is always safe to call the
+            // intrinsic.
+            "sse2.pause" => {
+                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                // Only exhibit the spin-loop hint behavior when SSE2 is enabled.
+                if this.tcx.sess.unstable_target_features.contains(&Symbol::intern("sse2")) {
+                    this.yield_active_thread();
+                }
+            }
+
             name if name.starts_with("sse.") => {
                 return sse::EvalContextExt::emulate_x86_sse_intrinsic(
                     this, link_name, abi, args, dest,
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index 18ff5d809e3..eb2cc9d37c8 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -580,12 +580,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                     this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?;
                 }
             }
-            // Used to implement the `_mm_pause` function.
-            // The intrinsic is used to hint the processor that the code is in a spin-loop.
-            "pause" => {
-                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                this.yield_active_thread();
-            }
             _ => return Ok(EmulateForeignItemResult::NotSupported),
         }
         Ok(EmulateForeignItemResult::NeedsJumping)
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs b/src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs
new file mode 100644
index 00000000000..c8b92fd5458
--- /dev/null
+++ b/src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs
@@ -0,0 +1,25 @@
+// Ignore everything except x86 and x86_64
+// Any new targets that are added to CI should be ignored here.
+// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
+//@ignore-target-aarch64
+//@ignore-target-arm
+//@ignore-target-avr
+//@ignore-target-s390x
+//@ignore-target-thumbv7em
+//@ignore-target-wasm32
+//@compile-flags: -C target-feature=-sse2
+
+#[cfg(target_arch = "x86")]
+use std::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use std::arch::x86_64::*;
+
+fn main() {
+    assert!(!is_x86_feature_detected!("sse2"));
+
+    unsafe {
+        // This is a SSE2 intrinsic, but it behaves as a no-op when SSE2
+        // is not available, so it is always safe to call.
+        _mm_pause();
+    }
+}
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs b/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs
index e636d6c8aaf..e0088b9eb24 100644
--- a/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs
+++ b/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs
@@ -54,6 +54,11 @@ mod tests {
             }
         }
 
+        fn test_mm_pause() {
+            unsafe { _mm_pause() }
+        }
+        test_mm_pause();
+
         #[target_feature(enable = "sse2")]
         unsafe fn test_mm_avg_epu8() {
             let (a, b) = (_mm_set1_epi8(3), _mm_set1_epi8(9));