auto merge of #6354 : Aatch/rust/uninit-intrinsic, r=graydon
Adds an `uninit` intrinsic. It's just an empty function, so llvm optimizes it down to nothing. I changed all of the `init` intrinsic usages to `uninit` where it seemed appropriate to.
This commit is contained in:
commit
7675856253
@ -24,6 +24,20 @@ pub mod rusti {
|
||||
}
|
||||
|
||||
/// Casts the value at `src` to U. The two types must have the same length.
|
||||
#[cfg(not(stage0))]
|
||||
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
||||
let mut dest: U = unstable::intrinsics::uninit();
|
||||
{
|
||||
let dest_ptr: *mut u8 = rusti::transmute(&mut dest);
|
||||
let src_ptr: *u8 = rusti::transmute(src);
|
||||
unstable::intrinsics::memmove64(dest_ptr,
|
||||
src_ptr,
|
||||
sys::size_of::<U>() as u64);
|
||||
}
|
||||
dest
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
||||
let mut dest: U = unstable::intrinsics::init();
|
||||
{
|
||||
|
@ -44,6 +44,9 @@ pub extern "rust-intrinsic" {
|
||||
|
||||
pub fn init<T>() -> T;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub unsafe fn uninit<T>() -> T;
|
||||
|
||||
pub fn forget<T>(_: T) -> ();
|
||||
|
||||
pub fn needs_drop<T>() -> bool;
|
||||
|
@ -584,6 +584,22 @@ pub fn consume_reverse<T>(mut v: ~[T], f: &fn(uint, v: T)) {
|
||||
}
|
||||
|
||||
/// Remove the last element from a vector and return it
|
||||
#[cfg(not(stage0))]
|
||||
pub fn pop<T>(v: &mut ~[T]) -> T {
|
||||
let ln = v.len();
|
||||
if ln == 0 {
|
||||
fail!(~"sorry, cannot vec::pop an empty vector")
|
||||
}
|
||||
let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]);
|
||||
unsafe {
|
||||
let mut val = intrinsics::uninit();
|
||||
val <-> *valptr;
|
||||
raw::set_len(v, ln - 1u);
|
||||
val
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
pub fn pop<T>(v: &mut ~[T]) -> T {
|
||||
let ln = v.len();
|
||||
if ln == 0 {
|
||||
@ -591,7 +607,6 @@ pub fn pop<T>(v: &mut ~[T]) -> T {
|
||||
}
|
||||
let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]);
|
||||
unsafe {
|
||||
// FIXME #4204: Should be uninit() - we don't need this zeroed
|
||||
let mut val = intrinsics::init();
|
||||
val <-> *valptr;
|
||||
raw::set_len(v, ln - 1u);
|
||||
@ -660,13 +675,30 @@ pub fn push_all<T:Copy>(v: &mut ~[T], rhs: &const [T]) {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(not(stage0))]
|
||||
pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) {
|
||||
let new_len = v.len() + rhs.len();
|
||||
reserve(&mut *v, new_len);
|
||||
unsafe {
|
||||
do as_mut_buf(rhs) |p, len| {
|
||||
for uint::range(0, len) |i| {
|
||||
let mut x = intrinsics::uninit();
|
||||
x <-> *ptr::mut_offset(p, i);
|
||||
push(&mut *v, x);
|
||||
}
|
||||
}
|
||||
raw::set_len(&mut rhs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(stage0)]
|
||||
pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) {
|
||||
let new_len = v.len() + rhs.len();
|
||||
reserve(&mut *v, new_len);
|
||||
unsafe {
|
||||
do as_mut_buf(rhs) |p, len| {
|
||||
for uint::range(0, len) |i| {
|
||||
// FIXME #4204 Should be uninit() - don't need to zero
|
||||
let mut x = intrinsics::init();
|
||||
x <-> *ptr::mut_offset(p, i);
|
||||
push(&mut *v, x);
|
||||
@ -677,13 +709,29 @@ pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) {
|
||||
}
|
||||
|
||||
/// Shorten a vector, dropping excess elements.
|
||||
#[cfg(not(stage0))]
|
||||
pub fn truncate<T>(v: &mut ~[T], newlen: uint) {
|
||||
do as_mut_buf(*v) |p, oldlen| {
|
||||
assert!(newlen <= oldlen);
|
||||
unsafe {
|
||||
// This loop is optimized out for non-drop types.
|
||||
for uint::range(newlen, oldlen) |i| {
|
||||
let mut dropped = intrinsics::uninit();
|
||||
dropped <-> *ptr::mut_offset(p, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe { raw::set_len(&mut *v, newlen); }
|
||||
}
|
||||
|
||||
/// Shorten a vector, dropping excess elements.
|
||||
#[cfg(stage0)]
|
||||
pub fn truncate<T>(v: &mut ~[T], newlen: uint) {
|
||||
do as_mut_buf(*v) |p, oldlen| {
|
||||
assert!(newlen <= oldlen);
|
||||
unsafe {
|
||||
// This loop is optimized out for non-drop types.
|
||||
for uint::range(newlen, oldlen) |i| {
|
||||
// FIXME #4204 Should be uninit() - don't need to zero
|
||||
let mut dropped = intrinsics::init();
|
||||
dropped <-> *ptr::mut_offset(p, i);
|
||||
}
|
||||
@ -696,6 +744,45 @@ pub fn truncate<T>(v: &mut ~[T], newlen: uint) {
|
||||
* Remove consecutive repeated elements from a vector; if the vector is
|
||||
* sorted, this removes all duplicates.
|
||||
*/
|
||||
#[cfg(not(stage0))]
|
||||
pub fn dedup<T:Eq>(v: &mut ~[T]) {
|
||||
unsafe {
|
||||
if v.len() < 1 { return; }
|
||||
let mut last_written = 0, next_to_read = 1;
|
||||
do as_const_buf(*v) |p, ln| {
|
||||
// We have a mutable reference to v, so we can make arbitrary
|
||||
// changes. (cf. push and pop)
|
||||
let p = p as *mut T;
|
||||
// last_written < next_to_read <= ln
|
||||
while next_to_read < ln {
|
||||
// last_written < next_to_read < ln
|
||||
if *ptr::mut_offset(p, next_to_read) ==
|
||||
*ptr::mut_offset(p, last_written) {
|
||||
let mut dropped = intrinsics::uninit();
|
||||
dropped <-> *ptr::mut_offset(p, next_to_read);
|
||||
} else {
|
||||
last_written += 1;
|
||||
// last_written <= next_to_read < ln
|
||||
if next_to_read != last_written {
|
||||
*ptr::mut_offset(p, last_written) <->
|
||||
*ptr::mut_offset(p, next_to_read);
|
||||
}
|
||||
}
|
||||
// last_written <= next_to_read < ln
|
||||
next_to_read += 1;
|
||||
// last_written < next_to_read <= ln
|
||||
}
|
||||
}
|
||||
// last_written < next_to_read == ln
|
||||
raw::set_len(v, last_written + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove consecutive repeated elements from a vector; if the vector is
|
||||
* sorted, this removes all duplicates.
|
||||
*/
|
||||
#[cfg(stage0)]
|
||||
pub fn dedup<T:Eq>(v: &mut ~[T]) {
|
||||
unsafe {
|
||||
if v.len() < 1 { return; }
|
||||
@ -709,8 +796,6 @@ pub fn dedup<T:Eq>(v: &mut ~[T]) {
|
||||
// last_written < next_to_read < ln
|
||||
if *ptr::mut_offset(p, next_to_read) ==
|
||||
*ptr::mut_offset(p, last_written) {
|
||||
// FIXME #4204 Should be uninit() - don't need to
|
||||
// zero
|
||||
let mut dropped = intrinsics::init();
|
||||
dropped <-> *ptr::mut_offset(p, next_to_read);
|
||||
} else {
|
||||
|
@ -715,6 +715,9 @@ pub fn trans_intrinsic(ccx: @CrateContext,
|
||||
Store(bcx, C_null(lltp_ty), fcx.llretptr.get());
|
||||
}
|
||||
}
|
||||
~"uninit" => {
|
||||
// Do nothing, this is effectively a no-op
|
||||
}
|
||||
~"forget" => {}
|
||||
~"transmute" => {
|
||||
let (in_type, out_type) = (substs.tys[0], substs.tys[1]);
|
||||
|
@ -118,7 +118,7 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint)
|
||||
if abi.is_intrinsic() {
|
||||
let flags = match *cx.ccx.sess.str_of(i.ident) {
|
||||
~"size_of" | ~"pref_align_of" | ~"min_align_of" |
|
||||
~"init" | ~"transmute" | ~"move_val" |
|
||||
~"uninit" | ~"init" | ~"transmute" | ~"move_val" |
|
||||
~"move_val_init" => use_repr,
|
||||
|
||||
~"get_tydesc" | ~"needs_drop" => use_tydesc,
|
||||
|
@ -3447,6 +3447,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
|
||||
~"size_of" |
|
||||
~"pref_align_of" | ~"min_align_of" => (1u, ~[], ty::mk_uint()),
|
||||
~"init" => (1u, ~[], param(ccx, 0u)),
|
||||
~"uninit" => (1u, ~[], param(ccx, 0u)),
|
||||
~"forget" => (1u, ~[arg(param(ccx, 0u))], ty::mk_nil()),
|
||||
~"transmute" => (2, ~[ arg(param(ccx, 0)) ], param(ccx, 1)),
|
||||
~"move_val" | ~"move_val_init" => {
|
||||
|
@ -16,6 +16,8 @@ use core::old_iter::BaseIter;
|
||||
extern "rust-intrinsic" mod rusti {
|
||||
fn move_val_init<T>(dst: &mut T, src: T);
|
||||
fn init<T>() -> T;
|
||||
#[cfg(not(stage0))]
|
||||
fn uninit<T>() -> T;
|
||||
}
|
||||
|
||||
pub struct PriorityQueue<T> {
|
||||
@ -132,6 +134,27 @@ pub impl <T:Ord> PriorityQueue<T> {
|
||||
// vector over the junk element. This reduces the constant factor
|
||||
// compared to using swaps, which involves twice as many moves.
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
priv fn siftup(&mut self, start: uint, mut pos: uint) {
|
||||
unsafe {
|
||||
let new = *ptr::to_unsafe_ptr(&self.data[pos]);
|
||||
|
||||
while pos > start {
|
||||
let parent = (pos - 1) >> 1;
|
||||
if new > self.data[parent] {
|
||||
let mut x = rusti::uninit();
|
||||
x <-> self.data[parent];
|
||||
rusti::move_val_init(&mut self.data[pos], x);
|
||||
pos = parent;
|
||||
loop
|
||||
}
|
||||
break
|
||||
}
|
||||
rusti::move_val_init(&mut self.data[pos], new);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
priv fn siftup(&mut self, start: uint, mut pos: uint) {
|
||||
unsafe {
|
||||
let new = *ptr::to_unsafe_ptr(&self.data[pos]);
|
||||
@ -151,6 +174,32 @@ pub impl <T:Ord> PriorityQueue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
priv fn siftdown_range(&mut self, mut pos: uint, end: uint) {
|
||||
unsafe {
|
||||
let start = pos;
|
||||
let new = *ptr::to_unsafe_ptr(&self.data[pos]);
|
||||
|
||||
let mut child = 2 * pos + 1;
|
||||
while child < end {
|
||||
let right = child + 1;
|
||||
if right < end && !(self.data[child] > self.data[right]) {
|
||||
child = right;
|
||||
}
|
||||
let mut x = rusti::uninit();
|
||||
x <-> self.data[child];
|
||||
rusti::move_val_init(&mut self.data[pos], x);
|
||||
pos = child;
|
||||
child = 2 * pos + 1;
|
||||
}
|
||||
|
||||
rusti::move_val_init(&mut self.data[pos], new);
|
||||
self.siftup(start, pos);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
priv fn siftdown_range(&mut self, mut pos: uint, end: uint) {
|
||||
unsafe {
|
||||
let start = pos;
|
||||
|
@ -46,6 +46,22 @@ pub impl<T: Owned> Rc<T> {
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: Owned> Drop for Rc<T> {
|
||||
fn finalize(&self) {
|
||||
unsafe {
|
||||
(*self.ptr).count -= 1;
|
||||
if (*self.ptr).count == 0 {
|
||||
let mut x = intrinsics::uninit();
|
||||
x <-> *self.ptr;
|
||||
free(self.ptr as *c_void)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[cfg(stage0)]
|
||||
impl<T: Owned> Drop for Rc<T> {
|
||||
fn finalize(&self) {
|
||||
unsafe {
|
||||
@ -59,6 +75,7 @@ impl<T: Owned> Drop for Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: Owned> Clone for Rc<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Rc<T> {
|
||||
@ -97,6 +114,8 @@ mod test_rc {
|
||||
#[abi = "rust-intrinsic"]
|
||||
extern "rust-intrinsic" mod rusti {
|
||||
fn init<T>() -> T;
|
||||
#[cfg(not(stage0))]
|
||||
fn uninit<T>() -> T;
|
||||
}
|
||||
|
||||
#[deriving(Eq)]
|
||||
@ -154,6 +173,22 @@ pub impl<T: Owned> RcMut<T> {
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: Owned> Drop for RcMut<T> {
|
||||
fn finalize(&self) {
|
||||
unsafe {
|
||||
(*self.ptr).count -= 1;
|
||||
if (*self.ptr).count == 0 {
|
||||
let mut x = rusti::uninit();
|
||||
x <-> *self.ptr;
|
||||
free(self.ptr as *c_void)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[cfg(stage0)]
|
||||
impl<T: Owned> Drop for RcMut<T> {
|
||||
fn finalize(&self) {
|
||||
unsafe {
|
||||
|
19
src/test/run-pass/intrinsic-uninit.rs
Normal file
19
src/test/run-pass/intrinsic-uninit.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern "rust-intrinsic" {
|
||||
fn uninit<T>() -> T;
|
||||
}
|
||||
}
|
||||
pub fn main() {
|
||||
let _a : int = unsafe {rusti::uninit()};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user