1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
// { dg-options "-w" }
#![feature(intrinsics)]
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 {
intrinsics::offset(self, count)
}
}
#[lang = "mut_ptr"]
impl<T> *mut T {
pub unsafe fn offset(self, count: isize) -> *mut T {
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 = 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 mem::size_of::<T>() < 32 {
let z = read(x);
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) {
intrinsics::move_val_init(&mut *dst, src)
}
pub unsafe fn read<T>(src: *const T) -> T {
let mut tmp: T = mem::uninitialized();
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 = 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 = 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
intrinsics::copy_nonoverlapping(x, t, block_size);
intrinsics::copy_nonoverlapping(y, x, block_size);
intrinsics::copy_nonoverlapping(t, y, block_size);
i += block_size;
}
if i < len {
// Swap any remaining bytes
let mut t: UnalignedBlock = 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);
intrinsics::copy_nonoverlapping(x, t, rem);
intrinsics::copy_nonoverlapping(y, x, rem);
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 {
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 {
intrinsics::uninit()
}
}
|