From 39e37792828c44641b6816ed7b8098b881627a72 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Nov 2023 12:15:51 +0100 Subject: [PATCH] riscv: remove intrinsics that cannot be used from Rust --- crates/core_arch/src/riscv_shared/mod.rs | 114 +++++------------------ 1 file changed, 25 insertions(+), 89 deletions(-) diff --git a/crates/core_arch/src/riscv_shared/mod.rs b/crates/core_arch/src/riscv_shared/mod.rs index e75eaee1fe..3ce24324de 100644 --- a/crates/core_arch/src/riscv_shared/mod.rs +++ b/crates/core_arch/src/riscv_shared/mod.rs @@ -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; @@ -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, @@ -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 -}