about summary refs log tree commit diff
path: root/src/libstd/ptr.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-05-27 15:56:08 -0700
committerbors <bors@rust-lang.org>2013-05-27 15:56:08 -0700
commitdbc57584bd4e87f0bd3eed6bced8bbd04d99edcf (patch)
tree834f7712e7345b319c0662b0488bc25ee53b8654 /src/libstd/ptr.rs
parent5d04ee805b96d34e7c5b316270a730fd9a0c537f (diff)
parente6c04dea0325af808198306e283c17f90d31fc26 (diff)
downloadrust-dbc57584bd4e87f0bd3eed6bced8bbd04d99edcf.tar.gz
rust-dbc57584bd4e87f0bd3eed6bced8bbd04d99edcf.zip
auto merge of #6724 : thestinger/rust/swap_fast, r=thestinger
Passing higher alignment values gives the optimization passes more freedom since it can copy in larger chunks. This change results in rustc outputting the same post-optimization IR as clang for swaps and most copies excluding the lack of information about padding.

Code snippet:

```rust
#[inline(never)]
fn swap<T>(x: &mut T, y: &mut T) {
    util::swap(x, y);
}
```

Original IR (for `int`):

```llvm
define internal fastcc void @_ZN9swap_283417_a71830ca3ed2d65d3_00E(i64*, i64*) #1 {
static_allocas:
  %2 = icmp eq i64* %0, %1
  br i1 %2, label %_ZN4util9swap_283717_a71830ca3ed2d65d3_00E.exit, label %3

; <label>:3                                       ; preds = %static_allocas
  %4 = load i64* %0, align 1
  %5 = load i64* %1, align 1
  store i64 %5, i64* %0, align 1
  store i64 %4, i64* %1, align 1
  br label %_ZN4util9swap_283717_a71830ca3ed2d65d3_00E.exit

_ZN4util9swap_283717_a71830ca3ed2d65d3_00E.exit:  ; preds = %3, %static_allocas
  ret void
}
```

After #6710:

```llvm
define internal fastcc void @_ZN9swap_283017_a71830ca3ed2d65d3_00E(i64* nocapture, i64* nocapture) #1 {
static_allocas:
  %2 = load i64* %0, align 1
  %3 = load i64* %1, align 1
  store i64 %3, i64* %0, align 1
  store i64 %2, i64* %1, align 1
  ret void
}
```

After this change:

```llvm
define internal fastcc void @_ZN9swap_283017_a71830ca3ed2d65d3_00E(i64* nocapture, i64* nocapture) #1 {
static_allocas:
  %2 = load i64* %0, align 8
  %3 = load i64* %1, align 8
  store i64 %3, i64* %0, align 8
  store i64 %2, i64* %1, align 8
  ret void
}
```

Another example:

```rust
#[inline(never)]
fn set<T>(x: &mut T, y: T) {
    *x = y;
}
```

Before, with `(int, int)` (align 1):

```llvm
define internal fastcc void @_ZN8set_282517_8fa972e3f9e451983_00E({ i64, i64 }* nocapture, { i64, i64 }* nocapture) #1 {
static_allocas:
  %2 = bitcast { i64, i64 }* %1 to i8*
  %3 = bitcast { i64, i64 }* %0 to i8*
  tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* %2, i64 16, i32 1, i1 false)
  ret void
}
```

After, with `(int, int)` (align 8):

```llvm
define internal fastcc void @_ZN8set_282617_8fa972e3f9e451983_00E({ i64, i64 }* nocapture, { i64, i64 }* nocapture) #1 {
static_allocas:
  %2 = bitcast { i64, i64 }* %1 to i8*
  %3 = bitcast { i64, i64 }* %0 to i8*
  tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* %2, i64 16, i32 8, i1 false)
  ret void
}
```
Diffstat (limited to 'src/libstd/ptr.rs')
-rw-r--r--src/libstd/ptr.rs84
1 files changed, 65 insertions, 19 deletions
diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs
index d1c0ffe7953..309129b7f13 100644
--- a/src/libstd/ptr.rs
+++ b/src/libstd/ptr.rs
@@ -19,6 +19,7 @@ use sys;
 #[cfg(not(test))] use cmp::{Eq, Ord};
 use uint;
 
+#[cfg(stage0)]
 pub mod libc_ {
     use libc::c_void;
     use libc;
@@ -27,12 +28,6 @@ pub mod libc_ {
     #[abi = "cdecl"]
     pub extern {
         #[rust_stack]
-        unsafe fn memmove(dest: *mut c_void,
-                          src: *const c_void,
-                          n: libc::size_t)
-                       -> *c_void;
-
-        #[rust_stack]
         unsafe fn memset(dest: *mut c_void,
                          c: libc::c_int,
                          len: libc::size_t)
@@ -97,15 +92,28 @@ pub fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }
  * and destination may overlap.
  */
 #[inline(always)]
-#[cfg(target_word_size = "32")]
+#[cfg(target_word_size = "32", stage0)]
 pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
     use unstable::intrinsics::memmove32;
     let n = count * sys::size_of::<T>();
     memmove32(dst as *mut u8, src as *u8, n as u32);
 }
 
+/**
+ * Copies data from one location to another
+ *
+ * Copies `count` elements (not bytes) from `src` to `dst`. The source
+ * and destination may overlap.
+ */
 #[inline(always)]
-#[cfg(target_word_size = "64")]
+#[cfg(target_word_size = "32", not(stage0))]
+pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
+    use unstable::intrinsics::memmove32;
+    memmove32(dst, src as *T, count as u32);
+}
+
+#[inline(always)]
+#[cfg(target_word_size = "64", stage0)]
 pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
     use unstable::intrinsics::memmove64;
     let n = count * sys::size_of::<T>();
@@ -113,33 +121,63 @@ pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
 }
 
 #[inline(always)]
-#[cfg(target_word_size = "32")]
+#[cfg(target_word_size = "64", not(stage0))]
+pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
+    use unstable::intrinsics::memmove64;
+    memmove64(dst, src as *T, count as u64);
+}
+
+#[inline(always)]
+#[cfg(target_word_size = "32", stage0)]
+pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
+    use unstable::intrinsics::memmove32;
+    let n = count * sys::size_of::<T>();
+    memmove32(dst as *mut u8, src as *u8, n as u32);
+}
+
+#[inline(always)]
+#[cfg(target_word_size = "32", not(stage0))]
 pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
-    #[cfg(stage0)]
-    use memcpy32 = unstable::intrinsics::memmove32;
-    #[cfg(not(stage0))]
     use unstable::intrinsics::memcpy32;
+    memcpy32(dst, src as *T, count as u32);
+}
+
+#[inline(always)]
+#[cfg(target_word_size = "64", stage0)]
+pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
+    use unstable::intrinsics::memmove64;
     let n = count * sys::size_of::<T>();
-    memcpy32(dst as *mut u8, src as *u8, n as u32);
+    memmove64(dst as *mut u8, src as *u8, n as u64);
 }
 
 #[inline(always)]
-#[cfg(target_word_size = "64")]
+#[cfg(target_word_size = "64", not(stage0))]
 pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
-    #[cfg(stage0)]
-    use memcpy64 = unstable::intrinsics::memmove64;
-    #[cfg(not(stage0))]
     use unstable::intrinsics::memcpy64;
-    let n = count * sys::size_of::<T>();
-    memcpy64(dst as *mut u8, src as *u8, n as u64);
+    memcpy64(dst, src as *T, count as u64);
 }
 
 #[inline(always)]
+#[cfg(stage0)]
 pub unsafe fn set_memory<T>(dst: *mut T, c: int, count: uint) {
     let n = count * sys::size_of::<T>();
     libc_::memset(dst as *mut c_void, c as libc::c_int, n as size_t);
 }
 
+#[inline(always)]
+#[cfg(target_word_size = "32", not(stage0))]
+pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
+    use unstable::intrinsics::memset32;
+    memset32(dst, c, count as u32);
+}
+
+#[inline(always)]
+#[cfg(target_word_size = "64", not(stage0))]
+pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
+    use unstable::intrinsics::memset64;
+    memset64(dst, c, count as u64);
+}
+
 /**
   Transform a region pointer - &T - to an unsafe pointer - *T.
   This is safe, but is implemented with an unsafe block due to
@@ -581,4 +619,12 @@ pub mod ptr_tests {
             });
         }
     }
+
+    #[test]
+    fn test_set_memory() {
+        let mut xs = [0u8, ..20];
+        let ptr = vec::raw::to_mut_ptr(xs);
+        unsafe { set_memory(ptr, 5u8, xs.len()); }
+        assert_eq!(xs, [5u8, ..20]);
+    }
 }