Skip to content

riscv: deprecate intrinsics that cannot be used from Rust #1478

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
Nov 5, 2023
Merged
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
114 changes: 25 additions & 89 deletions crates/core_arch/src/riscv_shared/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
//! Shared RISC-V intrinsics

//!
//! ## Missing floating-point register instructions
//!
//! We are deliberately *not* providing instructions that could change the floating-point rounding
//! mode or exception behavior or read the accrued exceptions flags: `frcsr`, `fscsr`, `fsrm`,
//! `frflags`, `fsflags`.
//!
//! Rust makes no guarantees whatsoever about the contents of the accrued exceptions register: Rust
//! floating-point operations may or may not result in this register getting updated with exception
//! state, and the register can change between two invocations of this function even when no
//! floating-point operations appear in the source code (since floating-point operations appearing
//! earlier or later can be reordered).
//!
//! Modifying the rounding mode leads to **immediate Undefined Behavior**: Rust assumes that the
//! default rounding mode is always set and will optimize accordingly. This even applies when the
//! rounding mode is altered and later reset to its original value without any floating-point
//! operations appearing in the source code between those operations (since floating-point
//! operations appearing earlier or later can be reordered).
//!
//! If you need to perform some floating-point operations and check whether they raised an
//! exception, use a single inline assembly block for the entire sequence of operations.
//!
//! If you need to perform some floating-point operations under a differen rounding mode, use a
//! single inline assembly block and make sure to restore the original rounding mode before the end
//! of the block.
mod p;
mod zb;
mod zk;
Expand Down Expand Up @@ -531,44 +555,6 @@ pub unsafe fn hinval_gvma_all() {
asm!(".insn r 0x73, 0, 0x33, x0, x0, x0", options(nostack))
}

/// Reads the floating-point control and status register `fcsr`
///
/// Register `fcsr` is a 32-bit read/write register that selects the dynamic rounding mode
/// for floating-point arithmetic operations and holds the accrued exception flag.
///
/// According to "F" Standard Extension for Single-Precision Floating-Point, Version 2.2,
/// register `fcsr` is defined as:
///
/// | Bit index | Meaning |
/// |:----------|:--------|
/// | 0..=4 | Accrued Exceptions (`fflags`) |
/// | 5..=7 | Rounding Mode (`frm`) |
/// | 8..=31 | _Reserved_ |
///
/// For definition of each field, visit [`frrm`] and [`frflags`].
///
/// [`frrm`]: fn.frrm.html
/// [`frflags`]: fn.frflags.html
#[inline]
#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
pub fn frcsr() -> u32 {
let value: u32;
unsafe { asm!("frcsr {}", out(reg) value, options(nomem, nostack)) };
value
}

/// Swaps the floating-point control and status register `fcsr`
///
/// This function swaps the value in `fcsr` by copying the original value to be returned,
/// and then writing a new value obtained from input variable `value` into `fcsr`.
#[inline]
#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
pub fn fscsr(value: u32) -> u32 {
let original: u32;
unsafe { asm!("fscsr {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
original
}

/// Reads the floating-point rounding mode register `frm`
///
/// According to "F" Standard Extension for Single-Precision Floating-Point, Version 2.2,
Expand All @@ -591,53 +577,3 @@ pub fn frrm() -> u32 {
unsafe { asm!("frrm {}", out(reg) value, options(nomem, nostack)) };
value
}

/// Swaps the floating-point rounding mode register `frm`
///
/// This function swaps the value in `frm` by copying the original value to be returned,
/// and then writing a new value obtained from the three least-significant bits of
/// input variable `value` into `frm`.
#[inline]
#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
pub fn fsrm(value: u32) -> u32 {
let original: u32;
unsafe { asm!("fsrm {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
original
}

/// Reads the floating-point accrued exception flags register `fflags`
///
/// The accrued exception flags indicate the exception conditions that have arisen
/// on any floating-point arithmetic instruction since the field was last reset by software.
///
/// According to "F" Standard Extension for Single-Precision Floating-Point, Version 2.2,
/// the accrued exception flags is defined as a bit vector of 5 bits.
/// The meaning of each binary bit is listed in the table below.
///
/// | Bit index | Mnemonic | Meaning |
/// |:--|:---|:-----------------|
/// | 4 | NV | Invalid Operation |
/// | 3 | DZ | Divide by Zero |
/// | 2 | OF | Overflow |
/// | 1 | UF | Underflow |
/// | 0 | NX | Inexact |
#[inline]
#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
pub fn frflags() -> u32 {
let value: u32;
unsafe { asm!("frflags {}", out(reg) value, options(nomem, nostack)) };
value
}

/// Swaps the floating-point accrued exception flags register `fflags`
///
/// This function swaps the value in `fflags` by copying the original value to be returned,
/// and then writing a new value obtained from the five least-significant bits of
/// input variable `value` into `fflags`.
#[inline]
#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
pub fn fsflags(value: u32) -> u32 {
let original: u32;
unsafe { asm!("fsflags {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
original
}