blob: 21637cb9a8a56d735fcad4bc3c2513bd4f2168fa [file] [log] [blame]
// { dg-options "-w" }
#![feature(intrinsics, lang_items)]
pub use option::Option::{self, None, Some};
pub use result::Result::{self, Err, Ok};
mod option {
pub enum Option<T> {
None,
Some(T),
}
}
mod result {
pub enum Result<T, E> {
Ok(T),
Err(E),
}
}
#[lang = "sized"]
pub trait Sized {}
#[lang = "clone"]
pub trait Clone: Sized {
fn clone(&self) -> Self;
fn clone_from(&mut self, source: &Self) {
*self = source.clone()
}
}
mod impls {
use super::Clone;
macro_rules! impl_clone {
($($t:ty)*) => {
$(
impl Clone for $t {
fn clone(&self) -> Self {
*self
}
}
)*
}
}
impl_clone! {
usize u8 u16 u32 u64 // u128
isize i8 i16 i32 i64 // i128
f32 f64
bool char
}
}
#[lang = "copy"]
pub trait Copy: Clone {
// Empty.
}
mod copy_impls {
use super::Copy;
macro_rules! impl_copy {
($($t:ty)*) => {
$(
impl Copy for $t {}
)*
}
}
impl_copy! {
usize u8 u16 u32 u64 // u128
isize i8 i16 i32 i64 // i128
f32 f64
bool char
}
}
mod intrinsics {
extern "rust-intrinsic" {
pub fn add_with_overflow<T>(x: T, y: T) -> (T, bool);
pub fn wrapping_add<T>(a: T, b: T) -> T;
pub fn wrapping_sub<T>(a: T, b: T) -> T;
pub fn rotate_left<T>(a: T, b: T) -> T;
pub fn rotate_right<T>(a: T, b: T) -> T;
pub fn offset<T>(ptr: *const T, count: isize) -> *const T;
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
pub fn move_val_init<T>(dst: *mut T, src: T);
pub fn uninit<T>() -> T;
}
}
mod ptr {
#[lang = "const_ptr"]
impl<T> *const T {
pub unsafe fn offset(self, count: isize) -> *const T {
crate::intrinsics::offset(self, count)
}
}
#[lang = "mut_ptr"]
impl<T> *mut T {
pub unsafe fn offset(self, count: isize) -> *mut T {
crate::intrinsics::offset(self, count) as *mut T
}
}
pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
let x = x as *mut u8;
let y = y as *mut u8;
let len = crate::mem::size_of::<T>() * count;
swap_nonoverlapping_bytes(x, y, len)
}
pub unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
// For types smaller than the block optimization below,
// just swap directly to avoid pessimizing codegen.
if crate::mem::size_of::<T>() < 32 {
let z = read(x);
crate::intrinsics::copy_nonoverlapping(y, x, 1);
write(y, z);
} else {
swap_nonoverlapping(x, y, 1);
}
}
pub unsafe fn write<T>(dst: *mut T, src: T) {
crate::intrinsics::move_val_init(&mut *dst, src)
}
pub unsafe fn read<T>(src: *const T) -> T {
let mut tmp: T = crate::mem::uninitialized();
crate::intrinsics::copy_nonoverlapping(src, &mut tmp, 1);
tmp
}
unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
struct Block(u64, u64, u64, u64);
struct UnalignedBlock(u64, u64, u64, u64);
let block_size = crate::mem::size_of::<Block>();
// Loop through x & y, copying them `Block` at a time
// The optimizer should unroll the loop fully for most types
// N.B. We can't use a for loop as the `range` impl calls `mem::swap` recursively
let mut i: usize = 0;
while i + block_size <= len {
// Create some uninitialized memory as scratch space
// Declaring `t` here avoids aligning the stack when this loop is unused
let mut t: Block = crate::mem::uninitialized();
let t = &mut t as *mut _ as *mut u8;
let x = x.offset(i as isize);
let y = y.offset(i as isize);
// Swap a block of bytes of x & y, using t as a temporary buffer
// This should be optimized into efficient SIMD operations where available
crate::intrinsics::copy_nonoverlapping(x, t, block_size);
crate::intrinsics::copy_nonoverlapping(y, x, block_size);
crate::intrinsics::copy_nonoverlapping(t, y, block_size);
i += block_size;
}
if i < len {
// Swap any remaining bytes
let mut t: UnalignedBlock = crate::mem::uninitialized();
let rem = len - i;
let t = &mut t as *mut _ as *mut u8;
let x = x.offset(i as isize);
let y = y.offset(i as isize);
crate::intrinsics::copy_nonoverlapping(x, t, rem);
crate::intrinsics::copy_nonoverlapping(y, x, rem);
crate::intrinsics::copy_nonoverlapping(t, y, rem);
}
}
}
mod mem {
extern "rust-intrinsic" {
pub fn transmute<T, U>(_: T) -> U;
pub fn size_of<T>() -> usize;
}
pub fn swap<T>(x: &mut T, y: &mut T) {
unsafe {
crate::ptr::swap_nonoverlapping_one(x, y);
}
}
pub fn test(dest: &mut i32, mut src: i32) -> i32 {
swap(dest, &mut src);
src
}
pub unsafe fn uninitialized<T>() -> T {
crate::intrinsics::uninit()
}
}