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:
bors 2013-05-09 12:37:00 -07:00
commit 7675856253
9 changed files with 215 additions and 6 deletions

View File

@ -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();
{

View File

@ -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;

View File

@ -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 {

View File

@ -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]);

View File

@ -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,

View File

@ -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" => {

View File

@ -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;

View File

@ -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 {

View 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()};
}