Skip to content

Allow llvm.x86.sse2.pause instrinsic to be called without SSE2 #3393

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

Merged
merged 1 commit into from
Mar 21, 2024
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
13 changes: 13 additions & 0 deletions src/shims/x86/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 0 additions & 6 deletions src/shims/x86/sse2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
25 changes: 25 additions & 0 deletions tests/pass/intrinsics-x86-pause-without-sse2.rs
Original file line number Diff line number Diff line change
@@ -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();
}
}
5 changes: 5 additions & 0 deletions tests/pass/intrinsics-x86-sse2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down