about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorDaniel Micay <danielmicay@gmail.com>2013-08-06 18:05:43 -0400
committerDaniel Micay <danielmicay@gmail.com>2013-08-06 23:54:24 -0400
commit55f3d04101c214a13f7d47fbdb140c5c1126c41b (patch)
treeca17a95c009009c7420d7d19414de9a6267aa774 /src/libstd
parent7d115c94205dd4b937d29c77d1704aa3f801869e (diff)
downloadrust-55f3d04101c214a13f7d47fbdb140c5c1126c41b.tar.gz
rust-55f3d04101c214a13f7d47fbdb140c5c1126c41b.zip
vec: use `offset_inbounds` for iterators
This allows LLVM to optimize vector iterators to an `getelementptr` and
`icmp` pair, instead of `getelementptr` and *two* comparisons.

Code snippet:

~~~
fn foo(xs: &mut [f64]) {
    for x in xs.mut_iter() {
        *x += 10.0;
    }
}
~~~

LLVM IR at stage0:

~~~
; Function Attrs: noinline uwtable
define void @"_ZN3foo17_68e1b25bca131dba7_0$x2e0E"({ i64, %tydesc*, i8*, i8*, i8 }* nocapture, { double*, i64 }* nocapture) #1 {
"function top level":
  %2 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 0
  %3 = load double** %2, align 8
  %4 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 1
  %5 = load i64* %4, align 8
  %6 = ptrtoint double* %3 to i64
  %7 = and i64 %5, -8
  %8 = add i64 %7, %6
  %9 = inttoptr i64 %8 to double*
  %10 = icmp eq double* %3, %9
  %11 = icmp eq double* %3, null
  %or.cond6 = or i1 %10, %11
  br i1 %or.cond6, label %match_case, label %match_else

match_else:                                       ; preds = %"function top level", %match_else
  %12 = phi double* [ %13, %match_else ], [ %3, %"function top level" ]
  %13 = getelementptr double* %12, i64 1
  %14 = load double* %12, align 8
  %15 = fadd double %14, 1.000000e+01
  store double %15, double* %12, align 8
  %16 = icmp eq double* %13, %9
  %17 = icmp eq double* %13, null
  %or.cond = or i1 %16, %17
  br i1 %or.cond, label %match_case, label %match_else

match_case:                                       ; preds = %match_else, %"function top level"
  ret void
}
~~~

Optimized LLVM IR at stage1/stage2:

~~~
; Function Attrs: noinline uwtable
define void @"_ZN3foo17_68e1b25bca131dba7_0$x2e0E"({ i64, %tydesc*, i8*, i8*, i8 }* nocapture, { double*, i64 }* nocapture) #1 {
"function top level":
  %2 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 0
  %3 = load double** %2, align 8
  %4 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 1
  %5 = load i64* %4, align 8
  %6 = lshr i64 %5, 3
  %7 = getelementptr inbounds double* %3, i64 %6
  %8 = icmp eq i64 %6, 0
  %9 = icmp eq double* %3, null
  %or.cond6 = or i1 %8, %9
  br i1 %or.cond6, label %match_case, label %match_else

match_else:                                       ; preds = %"function top level", %match_else
  %.sroa.0.0.in7 = phi double* [ %10, %match_else ], [ %3, %"function top level" ]
  %10 = getelementptr inbounds double* %.sroa.0.0.in7, i64 1
  %11 = load double* %.sroa.0.0.in7, align 8
  %12 = fadd double %11, 1.000000e+01
  store double %12, double* %.sroa.0.0.in7, align 8
  %13 = icmp eq double* %10, %7
  br i1 %13, label %match_case, label %match_else

match_case:                                       ; preds = %match_else, %"function top level"
  ret void
}
~~~
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/ptr.rs21
-rw-r--r--src/libstd/vec.rs8
2 files changed, 24 insertions, 5 deletions
diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs
index 98fb132672c..5a2bd0c4de9 100644
--- a/src/libstd/ptr.rs
+++ b/src/libstd/ptr.rs
@@ -272,7 +272,6 @@ pub trait RawPtr<T> {
     fn is_not_null(&self) -> bool;
     unsafe fn to_option(&self) -> Option<&T>;
     fn offset(&self, count: int) -> Self;
-    #[cfg(not(stage0))]
     unsafe fn offset_inbounds(self, count: int) -> Self;
 }
 
@@ -310,6 +309,14 @@ impl<T> RawPtr<T> for *T {
     /// Calculates the offset from a pointer. The offset *must* be in-bounds of
     /// the object, or one-byte-past-the-end.
     #[inline]
+    #[cfg(stage0)]
+    unsafe fn offset_inbounds(self, count: int) -> *T {
+        intrinsics::offset(self, count)
+    }
+
+    /// Calculates the offset from a pointer. The offset *must* be in-bounds of
+    /// the object, or one-byte-past-the-end.
+    #[inline]
     #[cfg(not(stage0))]
     unsafe fn offset_inbounds(self, count: int) -> *T {
         intrinsics::offset_inbounds(self, count)
@@ -354,6 +361,18 @@ impl<T> RawPtr<T> for *mut T {
     /// This method should be preferred over `offset` when the guarantee can be
     /// satisfied, to enable better optimization.
     #[inline]
+    #[cfg(stage0)]
+    unsafe fn offset_inbounds(self, count: int) -> *mut T {
+        intrinsics::offset(self as *T, count) as *mut T
+    }
+
+    /// Calculates the offset from a pointer. The offset *must* be in-bounds of
+    /// the object, or one-byte-past-the-end. An arithmetic overflow is also
+    /// undefined behaviour.
+    ///
+    /// This method should be preferred over `offset` when the guarantee can be
+    /// satisfied, to enable better optimization.
+    #[inline]
     #[cfg(not(stage0))]
     unsafe fn offset_inbounds(self, count: int) -> *mut T {
         intrinsics::offset_inbounds(self as *T, count) as *mut T
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
index 8dbfb3ec543..36201dc5e82 100644
--- a/src/libstd/vec.rs
+++ b/src/libstd/vec.rs
@@ -855,7 +855,7 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
                             lifetime: cast::transmute(p)}
             } else {
                 VecIterator{ptr: p,
-                            end: p.offset(self.len() as int),
+                            end: p.offset_inbounds(self.len() as int),
                             lifetime: cast::transmute(p)}
             }
         }
@@ -1837,7 +1837,7 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] {
                                lifetime: cast::transmute(p)}
             } else {
                 VecMutIterator{ptr: p,
-                               end: p.offset(self.len() as int),
+                               end: p.offset_inbounds(self.len() as int),
                                lifetime: cast::transmute(p)}
             }
         }
@@ -2193,7 +2193,7 @@ macro_rules! iterator {
                             // same pointer.
                             cast::transmute(self.ptr as uint + 1)
                         } else {
-                            self.ptr.offset(1)
+                            self.ptr.offset_inbounds(1)
                         };
 
                         Some(cast::transmute(old))
@@ -2225,7 +2225,7 @@ macro_rules! double_ended_iterator {
                             // See above for why 'ptr.offset' isn't used
                             cast::transmute(self.end as uint - 1)
                         } else {
-                            self.end.offset(-1)
+                            self.end.offset_inbounds(-1)
                         };
                         Some(cast::transmute(self.end))
                     }