diff options
Diffstat (limited to 'vendor/crunchy')
-rw-r--r-- | vendor/crunchy/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/crunchy/Cargo.toml | 31 | ||||
-rw-r--r-- | vendor/crunchy/README.md | 38 | ||||
-rw-r--r-- | vendor/crunchy/build.rs | 253 | ||||
-rw-r--r-- | vendor/crunchy/src/lib.rs | 36 |
5 files changed, 359 insertions, 0 deletions
diff --git a/vendor/crunchy/.cargo-checksum.json b/vendor/crunchy/.cargo-checksum.json new file mode 100644 index 0000000..225b779 --- /dev/null +++ b/vendor/crunchy/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"5238a96db3efb623481ac00afca51748372d99e472bc4943f2d1762ad4cc6cf0","README.md":"6d402ec0e7baa639139f550f501b26f0fcd7e33d4b5b1184e027c5836cd6ec06","build.rs":"1fae5664addf11f9e703430663950a6f48aa9d48bfe1b80281e0b25999da3814","src/lib.rs":"e9696c988b07c250de57b4b65254869cfd75e24f5acaa0a7dd54d80facfc3fd9"},"package":"7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"}
\ No newline at end of file diff --git a/vendor/crunchy/Cargo.toml b/vendor/crunchy/Cargo.toml new file mode 100644 index 0000000..b05c686 --- /dev/null +++ b/vendor/crunchy/Cargo.toml @@ -0,0 +1,31 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "crunchy" +version = "0.2.2" +authors = ["Vurich <jackefransham@hotmail.co.uk>"] +build = "build.rs" +description = "Crunchy unroller: deterministically unroll constant loops" +license = "MIT" + +[dependencies] + +[features] +default = ["limit_128"] +limit_1024 = [] +limit_128 = [] +limit_2048 = [] +limit_256 = [] +limit_512 = [] +limit_64 = [] +std = [] diff --git a/vendor/crunchy/README.md b/vendor/crunchy/README.md new file mode 100644 index 0000000..9036450 --- /dev/null +++ b/vendor/crunchy/README.md @@ -0,0 +1,38 @@ +# Crunchy + +The crunchy unroller - deterministically unroll constant loops. For number +"crunching". + +The Rust optimizer will unroll constant loops that don't use the loop variable, +like this: + +```rust +for _ in 0..100 { + println!("Hello!"); +} +``` + +However, using the loop variable will cause it to never unroll the loop. This is +unfortunate because it means that you can't constant-fold the loop variable, and +if you end up stomping on the registers it will have to do a load for each +iteration. This crate ensures that your code is unrolled and const-folded. It +only works on literals, unfortunately, but there's a work-around: + +```rust +debug_assert_eq!(MY_CONSTANT, 100); +unroll! { + for i in 0..100 { + println!("Iteration {}", i); + } +} +``` + +This means that your tests will catch if you redefine the constant. + +To default maximum number of loops to unroll is `64`, but that can be easily increased using the cargo features: + +* `limit_128` +* `limit_256` +* `limit_512` +* `limit_1024` +* `limit_2048`
\ No newline at end of file diff --git a/vendor/crunchy/build.rs b/vendor/crunchy/build.rs new file mode 100644 index 0000000..b9c69ae --- /dev/null +++ b/vendor/crunchy/build.rs @@ -0,0 +1,253 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::Path; + +const LOWER_LIMIT: usize = 16; + +fn main() { + let limit = if cfg!(feature="limit_2048") { + 2048 + } else if cfg!(feature="limit_1024") { + 1024 + } else if cfg!(feature="limit_512") { + 512 + } else if cfg!(feature="limit_256") { + 256 + } else if cfg!(feature="limit_128") { + 128 + } else { + 64 + }; + + let out_dir = env::var("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("lib.rs"); + let mut f = File::create(&dest_path).unwrap(); + + let mut output = String::new(); + + output.push_str(r#" +/// Unroll the given for loop +/// +/// Example: +/// +/// ```ignore +/// unroll! { +/// for i in 0..5 { +/// println!("Iteration {}", i); +/// } +/// } +/// ``` +/// +/// will expand into: +/// +/// ```ignore +/// { println!("Iteration {}", 0); } +/// { println!("Iteration {}", 1); } +/// { println!("Iteration {}", 2); } +/// { println!("Iteration {}", 3); } +/// { println!("Iteration {}", 4); } +/// ``` +#[macro_export] +macro_rules! unroll { + (for $v:ident in 0..0 $c:block) => {}; + + (for $v:ident < $max:tt in ($start:tt..$end:tt).step_by($val:expr) {$($c:tt)*}) => { + { + let step = $val; + let start = $start; + let end = start + ($end - start) / step; + unroll! { + for val < $max in start..end { + let $v: usize = ((val - start) * step) + start; + + $($c)* + } + } + } + }; + + (for $v:ident in ($start:tt..$end:tt).step_by($val:expr) {$($c:tt)*}) => { + unroll! { + for $v < $end in ($start..$end).step_by($val) {$($c)*} + } + }; + + (for $v:ident in ($start:tt..$end:tt) {$($c:tt)*}) => { + unroll!{ + for $v in $start..$end {$($c)*} + } + }; + + (for $v:ident in $start:tt..$end:tt {$($c:tt)*}) => { + #[allow(non_upper_case_globals)] + #[allow(unused_comparisons)] + { + unroll!(@$v, 0, $end, { + if $v >= $start {$($c)*} + } + ); + } + }; + + (for $v:ident < $max:tt in $start:tt..$end:tt $c:block) => { + #[allow(non_upper_case_globals)] + { + let range = $start..$end; + assert!( + $max >= range.end, + "`{}` out of range `{:?}`", + stringify!($max), + range, + ); + unroll!( + @$v, + 0, + $max, + { + if $v >= range.start && $v < range.end { + $c + } + } + ); + } + }; + + (for $v:ident in 0..$end:tt {$($statement:tt)*}) => { + #[allow(non_upper_case_globals)] + { unroll!(@$v, 0, $end, {$($statement)*}); } + }; + +"#); + + for i in 0..limit + 1 { + output.push_str(format!(" (@$v:ident, $a:expr, {}, $c:block) => {{\n", i).as_str()); + + if i <= LOWER_LIMIT { + output.push_str(format!(" {{ const $v: usize = $a; $c }}\n").as_str()); + + for a in 1..i { + output.push_str(format!(" {{ const $v: usize = $a + {}; $c }}\n", a).as_str()); + } + } else { + let half = i / 2; + + if i % 2 == 0 { + output.push_str(format!(" unroll!(@$v, $a, {0}, $c);\n", half).as_str()); + output.push_str(format!(" unroll!(@$v, $a + {0}, {0}, $c);\n", half).as_str()); + } else { + if half > 1 { + output.push_str(format!(" unroll!(@$v, $a, {}, $c);\n", i - 1).as_str()) + } + + output.push_str(format!(" {{ const $v: usize = $a + {}; $c }}\n", i - 1).as_str()); + } + } + + output.push_str(" };\n\n"); + } + + output.push_str("}\n\n"); + + output.push_str(format!(r#" +#[cfg(all(test, feature = "std"))] +mod tests {{ + #[test] + fn invalid_range() {{ + let mut a: Vec<usize> = vec![]; + unroll! {{ + for i in (5..4) {{ + a.push(i); + }} + }} + assert_eq!(a, vec![]); + }} + + #[test] + fn start_at_one_with_step() {{ + let mut a: Vec<usize> = vec![]; + unroll! {{ + for i in (2..4).step_by(1) {{ + a.push(i); + }} + }} + assert_eq!(a, vec![2, 3]); + }} + + #[test] + fn start_at_one() {{ + let mut a: Vec<usize> = vec![]; + unroll! {{ + for i in 1..4 {{ + a.push(i); + }} + }} + assert_eq!(a, vec![1, 2, 3]); + }} + + #[test] + fn test_all() {{ + {{ + let a: Vec<usize> = vec![]; + unroll! {{ + for i in 0..0 {{ + a.push(i); + }} + }} + assert_eq!(a, (0..0).collect::<Vec<usize>>()); + }} + {{ + let mut a: Vec<usize> = vec![]; + unroll! {{ + for i in 0..1 {{ + a.push(i); + }} + }} + assert_eq!(a, (0..1).collect::<Vec<usize>>()); + }} + {{ + let mut a: Vec<usize> = vec![]; + unroll! {{ + for i in 0..{0} {{ + a.push(i); + }} + }} + assert_eq!(a, (0..{0}).collect::<Vec<usize>>()); + }} + {{ + let mut a: Vec<usize> = vec![]; + let start = {0} / 4; + let end = start * 3; + unroll! {{ + for i < {0} in start..end {{ + a.push(i); + }} + }} + assert_eq!(a, (start..end).collect::<Vec<usize>>()); + }} + {{ + let mut a: Vec<usize> = vec![]; + unroll! {{ + for i in (0..{0}).step_by(2) {{ + a.push(i); + }} + }} + assert_eq!(a, (0..{0} / 2).map(|x| x * 2).collect::<Vec<usize>>()); + }} + {{ + let mut a: Vec<usize> = vec![]; + let start = {0} / 4; + let end = start * 3; + unroll! {{ + for i < {0} in (start..end).step_by(2) {{ + a.push(i); + }} + }} + assert_eq!(a, (start..end).filter(|x| x % 2 == 0).collect::<Vec<usize>>()); + }} + }} +}} +"#, limit).as_str()); + + f.write_all(output.as_bytes()).unwrap(); +} diff --git a/vendor/crunchy/src/lib.rs b/vendor/crunchy/src/lib.rs new file mode 100644 index 0000000..6de39e2 --- /dev/null +++ b/vendor/crunchy/src/lib.rs @@ -0,0 +1,36 @@ +//! The crunchy unroller - deterministically unroll constant loops. For number "crunching". +//! +//! The Rust optimizer will unroll constant loops that don't use the loop variable, like this: +//! +//! ```ignore +//! for _ in 0..100 { +//! println!("Hello!"); +//! } +//! ``` +//! +//! However, using the loop variable will cause it to never unroll the loop. This is unfortunate because it means that you can't +//! constant-fold the loop variable, and if you end up stomping on the registers it will have to do a load for each iteration. +//! This crate ensures that your code is unrolled and const-folded. It only works on literals, +//! unfortunately, but there's a work-around: +//! +//! ```ignore +//! debug_assert_eq!(MY_CONSTANT, 100); +//! unroll! { +//! for i in 0..100 { +//! println!("Iteration {}", i); +//! } +//! } +//! ``` +//! This means that your tests will catch if you redefine the constant. +//! +//! To default maximum number of loops to unroll is `64`, but that can be easily increased using the cargo features: +//! +//! * `limit_128` +//! * `limit_256` +//! * `limit_512` +//! * `limit_1024` +//! * `limit_2048` + +#![cfg_attr(not(feature = "std"), no_std)] + +include!(concat!(env!("OUT_DIR"), "/lib.rs")); |