Skip to content

Commit 2c09c2f

Browse files
author
Clar Charr
committed
Add safe volatile functions.
1 parent 616b66d commit 2c09c2f

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

src/libcore/mem.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,93 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
832832
ptr::read(src as *const T as *const U)
833833
}
834834

835+
/// Copies a value while making no assumptions about the result.
836+
///
837+
/// This essentially tells the compiler that the value may have changed since it
838+
/// was last read, and that it should not make any assumptions or or perform
839+
/// optimisations on the returned value based upon previous computations
840+
/// involving `x`.
841+
///
842+
/// Usually, this is done when `x` is located in memory that may be modified by
843+
/// something other than the running program, like an I/O device or the
844+
/// operating system.
845+
///
846+
/// However, this function can also be used to force the compiler to determine
847+
/// the value of `x` before the copy can be used, preventing optimisations
848+
/// across the boundaries of this function. This is very useful in benchmarking
849+
/// when you want to ensure that a specific part of a computation is run
850+
/// completely and not optimised out.
851+
///
852+
/// Note that this does not always guarantee that the value of `x` is computed,
853+
/// or that a copy is made; if the final computation involving the copy is
854+
/// unused, this function call may still be optimised out.
855+
#[inline]
856+
#[unstable(feature = "safe_volatile", issue = "0")]
857+
pub fn copy_opaque<T: Copy>(x: &T) -> T {
858+
// this is okay because `T` is `Copy` and doesn't implement `Drop`
859+
unsafe { ptr::read_volatile(x as *const T) }
860+
}
861+
862+
/// Moves a value while making no assumptions about the result.
863+
///
864+
/// This is a version of `copy_opaque` that moves the value instead of copying
865+
/// it. This can also be used to force the compiler to determine the value of
866+
/// `x` before continuing, preventing optimisations across the boundaries of
867+
/// this function. This is very useful in benchmarking when you want to ensure
868+
/// that a specific part of a computation is run completely and not optimised
869+
/// out.
870+
///
871+
/// Note that this does not always guarantee that the value of `x` is computed;
872+
/// if the final computation involving the value is unused, this function call
873+
/// may still be optimised out.
874+
#[inline]
875+
#[unstable(feature = "safe_volatile", issue = "0")]
876+
pub fn move_opaque<T>(x: T) -> T {
877+
let y = unsafe { ptr::read_volatile(&x as *const T) };
878+
879+
// if we don't do this, `x` will be dropped twice
880+
forget(x);
881+
882+
// return the volatile version of the value
883+
y
884+
}
885+
886+
/// Replaces a value while guaranteeing that it is written.
887+
///
888+
/// This essentially tells the compiler that the value in `dest` may have been
889+
/// changed and be read in the future, and that it must compute the value of
890+
/// `dest` and `src`, and write `src` into `dest`.
891+
///
892+
/// Usually, this is done when `dest` is located in memory that may be read by
893+
/// something other than the running program, like an I/O device or the
894+
/// operating system.
895+
///
896+
/// However, this function can also be used to force the compiler to determine
897+
/// the value of `dest` and `src` before the original value of `dest` can be
898+
/// used, preventing optimisations across the boundaries of this function. This
899+
/// is very useful in benchmarking when you want to ensure that a specific part
900+
/// of a computation is run completely and not optimised out.
901+
#[inline]
902+
#[unstable(feature = "safe_volatile", issue = "0")]
903+
pub fn replace_opaque<T>(dest: &mut T, src: T) -> T {
904+
let temp = unsafe { ptr::read_volatile(dest) };
905+
unsafe { ptr::write_volatile(dest, src); }
906+
temp
907+
}
908+
909+
/// Drops a value while guaranteeing that it was computed.
910+
///
911+
/// This is very useful in benchmarking when you want to ensure that a specific
912+
/// computation is run completely and not optimised out.
913+
#[inline]
914+
#[unstable(feature = "safe_volatile", issue = "0")]
915+
pub fn drop_opaque<T>(x: T) {
916+
// move `x` into `y`, which will be dropped
917+
let mut y = unsafe { uninitialized() };
918+
unsafe { ptr::write_volatile(&mut y, x); }
919+
}
920+
921+
835922
/// Opaque type representing the discriminant of an enum.
836923
///
837924
/// See the `discriminant` function in this module for more information.

0 commit comments

Comments
 (0)