Skip to main content

libarch/x86/
intrin.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use core::arch::asm;
6
7#[cfg(target_arch = "x86")]
8use core::arch::x86::{__cpuid, _rdtsc};
9#[cfg(target_arch = "x86_64")]
10use core::arch::x86_64::{__cpuid, _rdtsc};
11
12/// Yield the processor momentarily. This should be used in busy waits.
13#[inline(always)]
14pub fn r#yield() {
15    // SAFETY: The `pause` instruction provides a hint to improve spin-wait loop performance
16    // and does not modify register state or memory.
17    unsafe {
18        asm!("pause", options(nomem, nostack, preserves_flags));
19    }
20}
21
22/// Convenience alias for [`r#yield`].
23#[inline(always)]
24pub fn yield_processor() {
25    r#yield();
26}
27
28// TODO(https://fxbug.dev/42126965): Improve the docs on the barrier APIs, maybe rename/refine.
29
30/// Synchronize all memory accesses of all kinds.
31#[inline(always)]
32pub fn device_memory_barrier() {
33    // SAFETY: `mfence` serializes all memory load and store operations that precede the instruction.
34    unsafe {
35        asm!("mfence", options(nostack, preserves_flags));
36    }
37}
38
39/// Synchronize the ordering of all memory accesses wrt other CPUs.
40#[inline(always)]
41pub fn thread_memory_barrier() {
42    device_memory_barrier();
43}
44
45/// Ensure all stores that appear before this barrier (in program order) complete before any stores
46/// that appear after this barrier.
47#[inline(always)]
48pub fn store_memory_barrier() {
49    // No need to emit a fence instruction. Stores will not be re-ordered with other stores.
50    // [intel/vol3]: 8.2.2 Memory Ordering in P6 and More Recent Processor Families
51    // [amd/vol2]: 7.2 Multiprocessor Memory Access Ordering
52    // SAFETY: A compiler barrier prevents compiler reordering across this point without emitting
53    // machine instructions.
54    unsafe {
55        asm!("", options(nostack, preserves_flags));
56    }
57}
58
59/// Force the processor to complete all modifications to register state and
60/// memory by previous instructions (including draining any buffered writes)
61/// before the next instruction is fetched.
62///
63/// [intel/vol3]: 8.3  Serializing Instructions.
64/// [amd/vol2]: 7.6.4  Serializing Instructions.
65///
66/// `cpuid` is a serializing instruction.
67#[inline(always)]
68pub fn serialize_instructions() {
69    let _ = __cpuid(0);
70}
71
72/// Return the current CPU cycle count.
73#[inline(always)]
74pub fn cycles() -> u64 {
75    // SAFETY: `_rdtsc` reads the current CPU timestamp counter.
76    unsafe { _rdtsc() }
77}