Skip to content

Commit 3a5f146

Browse files
committed
libcore: Use LLVM intrinsics for floor; add a new Perlin noise benchmark
1 parent 2db3abd commit 3a5f146

File tree

3 files changed

+143
-3
lines changed

3 files changed

+143
-3
lines changed

src/libcore/f32.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@
1717
use cmp;
1818
use num;
1919

20-
pub use cmath::c_float_utils::*;
20+
pub use cmath::c_float_utils::{acos, asin, atan, atan2, cbrt, ceil};
21+
pub use cmath::c_float_utils::{copysign, cos, cosh, erf, erfc, exp, expm1};
22+
pub use cmath::c_float_utils::{exp2, abs, abs_sub, mul_add, fmax, fmin};
23+
pub use cmath::c_float_utils::{nextafter, frexp, hypot, ldexp, lgamma};
24+
pub use cmath::c_float_utils::{ln, log_radix, ln1p, log10, log2, ilog_radix};
25+
pub use cmath::c_float_utils::{modf, pow, round, sin, sinh, sqrt, tan};
26+
pub use cmath::c_float_utils::{tanh, tgamma, trunc};
2127
pub use cmath::c_float_targ_consts::*;
2228

2329
// These are not defined inside consts:: for consistency with
@@ -53,6 +59,10 @@ pub pure fn ge(x: f32, y: f32) -> bool { return x >= y; }
5359

5460
pub pure fn gt(x: f32, y: f32) -> bool { return x > y; }
5561

62+
/// Returns `x` rounded down
63+
#[inline(always)]
64+
pub pure fn floor(x: f32) -> f32 { unsafe { floorf32(x) } }
65+
5666
// FIXME (#1999): replace the predicates below with llvm intrinsics or
5767
// calls to the libmath macros in the rust runtime for performance.
5868

@@ -185,6 +195,11 @@ impl f32: num::One {
185195
static pure fn one() -> f32 { 1.0 }
186196
}
187197

198+
#[abi="rust-intrinsic"]
199+
pub extern {
200+
fn floorf32(val: f32) -> f32;
201+
}
202+
188203
//
189204
// Local Variables:
190205
// mode: rust

src/libcore/f64.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ use cmp;
1919
use libc;
2020
use num;
2121

22-
pub use cmath::c_double_utils::*;
22+
pub use cmath::c_double_utils::{acos, asin, atan, atan2, cbrt, ceil};
23+
pub use cmath::c_double_utils::{copysign, cos, cosh, erf, erfc, exp, expm1};
24+
pub use cmath::c_double_utils::{exp2, abs, abs_sub, mul_add, fmax, fmin};
25+
pub use cmath::c_double_utils::{nextafter, frexp, hypot, ldexp, lgamma};
26+
pub use cmath::c_double_utils::{ln, log_radix, ln1p, log10, log2, ilog_radix};
27+
pub use cmath::c_double_utils::{modf, pow, round, sin, sinh, sqrt, tan};
28+
pub use cmath::c_double_utils::{tanh, tgamma, trunc, j0, j1, jn, y0, y1, yn};
2329
pub use cmath::c_double_targ_consts::*;
2430

2531
// FIXME (#1433): obtain these in a different way
@@ -113,11 +119,15 @@ pub pure fn is_infinite(x: f64) -> bool {
113119
return x == infinity || x == neg_infinity;
114120
}
115121

116-
/// Returns true if `x`is a finite number
122+
/// Returns true if `x` is a finite number
117123
pub pure fn is_finite(x: f64) -> bool {
118124
return !(is_NaN(x) || is_infinite(x));
119125
}
120126

127+
/// Returns `x` rounded down
128+
#[inline(always)]
129+
pub pure fn floor(x: f64) -> f64 { unsafe { floorf64(x) } }
130+
121131
// FIXME (#1999): add is_normal, is_subnormal, and fpclassify
122132

123133
/* Module: consts */
@@ -206,6 +216,11 @@ impl f64: num::One {
206216
static pure fn one() -> f64 { 1.0 }
207217
}
208218

219+
#[abi="rust-intrinsic"]
220+
pub extern {
221+
fn floorf64(val: f64) -> f64;
222+
}
223+
209224
//
210225
// Local Variables:
211226
// mode: rust

src/test/bench/noise.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Perlin noise benchmark from https://gist.github.com/1170424
2+
3+
struct Vec2 {
4+
x: f32,
5+
y: f32,
6+
}
7+
8+
fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v }
9+
fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) }
10+
11+
fn random_gradient(r: rand::Rng) -> Vec2 {
12+
let v = r.gen_float() * float::consts::pi * 2.0;
13+
Vec2{
14+
x: float::cos(v) as f32,
15+
y: float::sin(v) as f32,
16+
}
17+
}
18+
19+
fn gradient(orig: Vec2, grad: Vec2, p: Vec2) -> f32 {
20+
let sp = Vec2{x: p.x - orig.x, y: p.y - orig.y};
21+
grad.x * sp.x + grad.y + sp.y
22+
}
23+
24+
struct Noise2DContext {
25+
rgradients: [Vec2 * 256],
26+
permutations: [int * 256],
27+
}
28+
29+
fn Noise2DContext() -> ~Noise2DContext {
30+
let r = rand::Rng();
31+
let mut rgradients = [ Vec2 { x: 0.0, y: 0.0 }, ..256 ];
32+
for int::range(0, 256) |i| { rgradients[i] = random_gradient(r); }
33+
let mut permutations = [ 0, ..256 ];
34+
for int::range(0, 256) |i| { permutations[i] = i; }
35+
r.shuffle_mut(permutations);
36+
37+
~Noise2DContext{
38+
rgradients: move rgradients,
39+
permutations: move permutations,
40+
}
41+
}
42+
43+
impl Noise2DContext {
44+
#[inline(always)]
45+
fn get_gradient(&self, x: int, y: int) -> Vec2 {
46+
let idx = self.permutations[x & 255] + self.permutations[y & 255];
47+
self.rgradients[idx & 255]
48+
}
49+
50+
#[inline(always)]
51+
fn get_gradients(&self, gradients: &mut [Vec2 * 4], origins: &mut [Vec2 * 4], x: f32, y: f32) {
52+
let x0f = f32::floor(x);
53+
let y0f = f32::floor(y);
54+
let x0 = x0f as int;
55+
let y0 = y0f as int;
56+
let x1 = x0 + 1;
57+
let y1 = y0 + 1;
58+
59+
gradients[0] = self.get_gradient(x0, y0);
60+
gradients[1] = self.get_gradient(x1, y0);
61+
gradients[2] = self.get_gradient(x0, y1);
62+
gradients[3] = self.get_gradient(x1, y1);
63+
64+
origins[0] = Vec2{x: x0f + 0.0, y: y0f + 0.0};
65+
origins[1] = Vec2{x: x0f + 1.0, y: y0f + 0.0};
66+
origins[2] = Vec2{x: x0f + 0.0, y: y0f + 1.0};
67+
origins[3] = Vec2{x: x0f + 1.0, y: y0f + 1.0};
68+
}
69+
70+
fn get(&self, x: f32, y: f32) -> f32 {
71+
let p = Vec2{x: x, y: y};
72+
let mut gradients = [ Vec2 { x: 0.0, y: 0.0 }, ..4 ];
73+
let mut origins = [ Vec2 { x: 0.0, y: 0.0 }, ..4 ];
74+
self.get_gradients(&mut gradients, &mut origins, x, y);
75+
let v0 = gradient(origins[0], gradients[0], p);
76+
let v1 = gradient(origins[1], gradients[1], p);
77+
let v2 = gradient(origins[2], gradients[2], p);
78+
let v3 = gradient(origins[3], gradients[3], p);
79+
let fx = smooth(x - origins[0].x);
80+
let vx0 = lerp(v0, v1, fx);
81+
let vx1 = lerp(v2, v3, fx);
82+
let fy = smooth(y - origins[0].y);
83+
lerp(vx0, vx1, fy)
84+
}
85+
}
86+
87+
fn main() {
88+
let symbols = [" ", "░", "▒", "▓", "█", "█"];
89+
let mut pixels = vec::from_elem(256*256, 0f32);
90+
let n2d = Noise2DContext();
91+
for int::range(0, 100) |_| {
92+
for int::range(0, 256) |y| {
93+
for int::range(0, 256) |x| {
94+
let v = n2d.get(
95+
x as f32 * 0.1f32,
96+
y as f32 * 0.1f32
97+
) * 0.5f32 + 0.5f32;
98+
pixels[y*256+x] = v;
99+
};
100+
};
101+
};
102+
103+
/*for int::range(0, 256) |y| {
104+
for int::range(0, 256) |x| {
105+
io::print(symbols[pixels[y*256+x] / 0.2f32 as int]);
106+
}
107+
io::println("");
108+
}*/
109+
}
110+

0 commit comments

Comments
 (0)