Skip to content

Commit 7675856

Browse files
committed
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.
2 parents ce9c022 + 414970c commit 7675856

File tree

9 files changed

+215
-6
lines changed

9 files changed

+215
-6
lines changed

src/libcore/cast.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@ pub mod rusti {
2424
}
2525

2626
/// Casts the value at `src` to U. The two types must have the same length.
27+
#[cfg(not(stage0))]
28+
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
29+
let mut dest: U = unstable::intrinsics::uninit();
30+
{
31+
let dest_ptr: *mut u8 = rusti::transmute(&mut dest);
32+
let src_ptr: *u8 = rusti::transmute(src);
33+
unstable::intrinsics::memmove64(dest_ptr,
34+
src_ptr,
35+
sys::size_of::<U>() as u64);
36+
}
37+
dest
38+
}
39+
40+
#[cfg(stage0)]
2741
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
2842
let mut dest: U = unstable::intrinsics::init();
2943
{

src/libcore/unstable/intrinsics.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ pub extern "rust-intrinsic" {
4444

4545
pub fn init<T>() -> T;
4646

47+
#[cfg(not(stage0))]
48+
pub unsafe fn uninit<T>() -> T;
49+
4750
pub fn forget<T>(_: T) -> ();
4851

4952
pub fn needs_drop<T>() -> bool;

src/libcore/vec.rs

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -584,14 +584,29 @@ pub fn consume_reverse<T>(mut v: ~[T], f: &fn(uint, v: T)) {
584584
}
585585
586586
/// Remove the last element from a vector and return it
587+
#[cfg(not(stage0))]
588+
pub fn pop<T>(v: &mut ~[T]) -> T {
589+
let ln = v.len();
590+
if ln == 0 {
591+
fail!(~"sorry, cannot vec::pop an empty vector")
592+
}
593+
let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]);
594+
unsafe {
595+
let mut val = intrinsics::uninit();
596+
val <-> *valptr;
597+
raw::set_len(v, ln - 1u);
598+
val
599+
}
600+
}
601+
602+
#[cfg(stage0)]
587603
pub fn pop<T>(v: &mut ~[T]) -> T {
588604
let ln = v.len();
589605
if ln == 0 {
590606
fail!(~"sorry, cannot vec::pop an empty vector")
591607
}
592608
let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]);
593609
unsafe {
594-
// FIXME #4204: Should be uninit() - we don't need this zeroed
595610
let mut val = intrinsics::init();
596611
val <-> *valptr;
597612
raw::set_len(v, ln - 1u);
@@ -660,13 +675,30 @@ pub fn push_all<T:Copy>(v: &mut ~[T], rhs: &const [T]) {
660675
}
661676
662677
#[inline(always)]
678+
#[cfg(not(stage0))]
679+
pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) {
680+
let new_len = v.len() + rhs.len();
681+
reserve(&mut *v, new_len);
682+
unsafe {
683+
do as_mut_buf(rhs) |p, len| {
684+
for uint::range(0, len) |i| {
685+
let mut x = intrinsics::uninit();
686+
x <-> *ptr::mut_offset(p, i);
687+
push(&mut *v, x);
688+
}
689+
}
690+
raw::set_len(&mut rhs, 0);
691+
}
692+
}
693+
694+
#[inline(always)]
695+
#[cfg(stage0)]
663696
pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) {
664697
let new_len = v.len() + rhs.len();
665698
reserve(&mut *v, new_len);
666699
unsafe {
667700
do as_mut_buf(rhs) |p, len| {
668701
for uint::range(0, len) |i| {
669-
// FIXME #4204 Should be uninit() - don't need to zero
670702
let mut x = intrinsics::init();
671703
x <-> *ptr::mut_offset(p, i);
672704
push(&mut *v, x);
@@ -677,13 +709,29 @@ pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) {
677709
}
678710
679711
/// Shorten a vector, dropping excess elements.
712+
#[cfg(not(stage0))]
713+
pub fn truncate<T>(v: &mut ~[T], newlen: uint) {
714+
do as_mut_buf(*v) |p, oldlen| {
715+
assert!(newlen <= oldlen);
716+
unsafe {
717+
// This loop is optimized out for non-drop types.
718+
for uint::range(newlen, oldlen) |i| {
719+
let mut dropped = intrinsics::uninit();
720+
dropped <-> *ptr::mut_offset(p, i);
721+
}
722+
}
723+
}
724+
unsafe { raw::set_len(&mut *v, newlen); }
725+
}
726+
727+
/// Shorten a vector, dropping excess elements.
728+
#[cfg(stage0)]
680729
pub fn truncate<T>(v: &mut ~[T], newlen: uint) {
681730
do as_mut_buf(*v) |p, oldlen| {
682731
assert!(newlen <= oldlen);
683732
unsafe {
684733
// This loop is optimized out for non-drop types.
685734
for uint::range(newlen, oldlen) |i| {
686-
// FIXME #4204 Should be uninit() - don't need to zero
687735
let mut dropped = intrinsics::init();
688736
dropped <-> *ptr::mut_offset(p, i);
689737
}
@@ -696,6 +744,45 @@ pub fn truncate<T>(v: &mut ~[T], newlen: uint) {
696744
* Remove consecutive repeated elements from a vector; if the vector is
697745
* sorted, this removes all duplicates.
698746
*/
747+
#[cfg(not(stage0))]
748+
pub fn dedup<T:Eq>(v: &mut ~[T]) {
749+
unsafe {
750+
if v.len() < 1 { return; }
751+
let mut last_written = 0, next_to_read = 1;
752+
do as_const_buf(*v) |p, ln| {
753+
// We have a mutable reference to v, so we can make arbitrary
754+
// changes. (cf. push and pop)
755+
let p = p as *mut T;
756+
// last_written < next_to_read <= ln
757+
while next_to_read < ln {
758+
// last_written < next_to_read < ln
759+
if *ptr::mut_offset(p, next_to_read) ==
760+
*ptr::mut_offset(p, last_written) {
761+
let mut dropped = intrinsics::uninit();
762+
dropped <-> *ptr::mut_offset(p, next_to_read);
763+
} else {
764+
last_written += 1;
765+
// last_written <= next_to_read < ln
766+
if next_to_read != last_written {
767+
*ptr::mut_offset(p, last_written) <->
768+
*ptr::mut_offset(p, next_to_read);
769+
}
770+
}
771+
// last_written <= next_to_read < ln
772+
next_to_read += 1;
773+
// last_written < next_to_read <= ln
774+
}
775+
}
776+
// last_written < next_to_read == ln
777+
raw::set_len(v, last_written + 1);
778+
}
779+
}
780+
781+
/**
782+
* Remove consecutive repeated elements from a vector; if the vector is
783+
* sorted, this removes all duplicates.
784+
*/
785+
#[cfg(stage0)]
699786
pub fn dedup<T:Eq>(v: &mut ~[T]) {
700787
unsafe {
701788
if v.len() < 1 { return; }
@@ -709,8 +796,6 @@ pub fn dedup<T:Eq>(v: &mut ~[T]) {
709796
// last_written < next_to_read < ln
710797
if *ptr::mut_offset(p, next_to_read) ==
711798
*ptr::mut_offset(p, last_written) {
712-
// FIXME #4204 Should be uninit() - don't need to
713-
// zero
714799
let mut dropped = intrinsics::init();
715800
dropped <-> *ptr::mut_offset(p, next_to_read);
716801
} else {

src/librustc/middle/trans/foreign.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,9 @@ pub fn trans_intrinsic(ccx: @CrateContext,
715715
Store(bcx, C_null(lltp_ty), fcx.llretptr.get());
716716
}
717717
}
718+
~"uninit" => {
719+
// Do nothing, this is effectively a no-op
720+
}
718721
~"forget" => {}
719722
~"transmute" => {
720723
let (in_type, out_type) = (substs.tys[0], substs.tys[1]);

src/librustc/middle/trans/type_use.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint)
118118
if abi.is_intrinsic() {
119119
let flags = match *cx.ccx.sess.str_of(i.ident) {
120120
~"size_of" | ~"pref_align_of" | ~"min_align_of" |
121-
~"init" | ~"transmute" | ~"move_val" |
121+
~"uninit" | ~"init" | ~"transmute" | ~"move_val" |
122122
~"move_val_init" => use_repr,
123123

124124
~"get_tydesc" | ~"needs_drop" => use_tydesc,

src/librustc/middle/typeck/check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3447,6 +3447,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
34473447
~"size_of" |
34483448
~"pref_align_of" | ~"min_align_of" => (1u, ~[], ty::mk_uint()),
34493449
~"init" => (1u, ~[], param(ccx, 0u)),
3450+
~"uninit" => (1u, ~[], param(ccx, 0u)),
34503451
~"forget" => (1u, ~[arg(param(ccx, 0u))], ty::mk_nil()),
34513452
~"transmute" => (2, ~[ arg(param(ccx, 0)) ], param(ccx, 1)),
34523453
~"move_val" | ~"move_val_init" => {

src/libstd/priority_queue.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use core::old_iter::BaseIter;
1616
extern "rust-intrinsic" mod rusti {
1717
fn move_val_init<T>(dst: &mut T, src: T);
1818
fn init<T>() -> T;
19+
#[cfg(not(stage0))]
20+
fn uninit<T>() -> T;
1921
}
2022

2123
pub struct PriorityQueue<T> {
@@ -132,6 +134,27 @@ pub impl <T:Ord> PriorityQueue<T> {
132134
// vector over the junk element. This reduces the constant factor
133135
// compared to using swaps, which involves twice as many moves.
134136

137+
#[cfg(not(stage0))]
138+
priv fn siftup(&mut self, start: uint, mut pos: uint) {
139+
unsafe {
140+
let new = *ptr::to_unsafe_ptr(&self.data[pos]);
141+
142+
while pos > start {
143+
let parent = (pos - 1) >> 1;
144+
if new > self.data[parent] {
145+
let mut x = rusti::uninit();
146+
x <-> self.data[parent];
147+
rusti::move_val_init(&mut self.data[pos], x);
148+
pos = parent;
149+
loop
150+
}
151+
break
152+
}
153+
rusti::move_val_init(&mut self.data[pos], new);
154+
}
155+
}
156+
157+
#[cfg(stage0)]
135158
priv fn siftup(&mut self, start: uint, mut pos: uint) {
136159
unsafe {
137160
let new = *ptr::to_unsafe_ptr(&self.data[pos]);
@@ -151,6 +174,32 @@ pub impl <T:Ord> PriorityQueue<T> {
151174
}
152175
}
153176

177+
178+
#[cfg(not(stage0))]
179+
priv fn siftdown_range(&mut self, mut pos: uint, end: uint) {
180+
unsafe {
181+
let start = pos;
182+
let new = *ptr::to_unsafe_ptr(&self.data[pos]);
183+
184+
let mut child = 2 * pos + 1;
185+
while child < end {
186+
let right = child + 1;
187+
if right < end && !(self.data[child] > self.data[right]) {
188+
child = right;
189+
}
190+
let mut x = rusti::uninit();
191+
x <-> self.data[child];
192+
rusti::move_val_init(&mut self.data[pos], x);
193+
pos = child;
194+
child = 2 * pos + 1;
195+
}
196+
197+
rusti::move_val_init(&mut self.data[pos], new);
198+
self.siftup(start, pos);
199+
}
200+
}
201+
202+
#[cfg(stage0)]
154203
priv fn siftdown_range(&mut self, mut pos: uint, end: uint) {
155204
unsafe {
156205
let start = pos;

src/libstd/rc.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@ pub impl<T: Owned> Rc<T> {
4646
}
4747

4848
#[unsafe_destructor]
49+
#[cfg(not(stage0))]
50+
impl<T: Owned> Drop for Rc<T> {
51+
fn finalize(&self) {
52+
unsafe {
53+
(*self.ptr).count -= 1;
54+
if (*self.ptr).count == 0 {
55+
let mut x = intrinsics::uninit();
56+
x <-> *self.ptr;
57+
free(self.ptr as *c_void)
58+
}
59+
}
60+
}
61+
}
62+
63+
#[unsafe_destructor]
64+
#[cfg(stage0)]
4965
impl<T: Owned> Drop for Rc<T> {
5066
fn finalize(&self) {
5167
unsafe {
@@ -59,6 +75,7 @@ impl<T: Owned> Drop for Rc<T> {
5975
}
6076
}
6177

78+
6279
impl<T: Owned> Clone for Rc<T> {
6380
#[inline]
6481
fn clone(&self) -> Rc<T> {
@@ -97,6 +114,8 @@ mod test_rc {
97114
#[abi = "rust-intrinsic"]
98115
extern "rust-intrinsic" mod rusti {
99116
fn init<T>() -> T;
117+
#[cfg(not(stage0))]
118+
fn uninit<T>() -> T;
100119
}
101120

102121
#[deriving(Eq)]
@@ -154,6 +173,22 @@ pub impl<T: Owned> RcMut<T> {
154173
}
155174

156175
#[unsafe_destructor]
176+
#[cfg(not(stage0))]
177+
impl<T: Owned> Drop for RcMut<T> {
178+
fn finalize(&self) {
179+
unsafe {
180+
(*self.ptr).count -= 1;
181+
if (*self.ptr).count == 0 {
182+
let mut x = rusti::uninit();
183+
x <-> *self.ptr;
184+
free(self.ptr as *c_void)
185+
}
186+
}
187+
}
188+
}
189+
190+
#[unsafe_destructor]
191+
#[cfg(stage0)]
157192
impl<T: Owned> Drop for RcMut<T> {
158193
fn finalize(&self) {
159194
unsafe {

src/test/run-pass/intrinsic-uninit.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
mod rusti {
12+
#[abi = "rust-intrinsic"]
13+
pub extern "rust-intrinsic" {
14+
fn uninit<T>() -> T;
15+
}
16+
}
17+
pub fn main() {
18+
let _a : int = unsafe {rusti::uninit()};
19+
}

0 commit comments

Comments
 (0)