summary refs log tree commit diff
path: root/src/libcore/num
AgeCommit message (Collapse)AuthorLines
2019-01-16allow unused warnings related to rustc_layout_scalar_valid_range_startPietro Albini-0/+4
2019-01-13Auto merge of #57568 - Centril:rollup, r=Centrilbors-4/+24
Rollup of 16 pull requests Successful merges: - #57351 (Don't actually create a full MIR stack frame when not needed) - #57353 (Optimise floating point `is_finite` (2x) and `is_infinite` (1.6x).) - #57412 (Improve the wording) - #57436 (save-analysis: use a fallback when access levels couldn't be computed) - #57453 (lldb_batchmode.py: try `import _thread` for Python 3) - #57454 (Some cleanups for core::fmt) - #57461 (Change `String` to `&'static str` in `ParseResult::Failure`.) - #57473 (std: Render large exit codes as hex on Windows) - #57474 (save-analysis: Get path def from parent in case there's no def for the path itself.) - #57494 (Speed up item_bodies for large match statements involving regions) - #57496 (re-do docs for core::cmp) - #57508 (rustdoc: Allow inlining of reexported crates and crate items) - #57547 (Use `ptr::eq` where applicable) - #57557 (resolve: Mark extern crate items as used in more cases) - #57560 (hygiene: Do not treat `Self` ctor as a local variable) - #57564 (Update the const fn tracking issue to the new metabug) Failed merges: r? @ghost
2019-01-13Rollup merge of #57353 - huonw:faster-finiteness-checks, r=KodrAusMazdak Farrokhzad-4/+24
Optimise floating point `is_finite` (2x) and `is_infinite` (1.6x). These can both rely on IEEE754 semantics to be made faster, by folding away the sign with an abs (left private for now), and then comparing to infinity, letting the NaN semantics of a direct float comparison handle NaN input properly. The `abs` bit-fiddling is simple (a single and), and so these new forms compile down to a few instructions, without branches, e.g. for f32: ```asm is_infinite: andps xmm0, xmmword ptr [rip + .LCPI2_0] ; 0x7FFF_FFFF ucomiss xmm0, dword ptr [rip + .LCPI2_1] ; 0x7F80_0000 setae al ret is_finite: andps xmm0, xmmword ptr [rip + .LCPI1_0] ; 0x7FFF_FFFF movss xmm1, dword ptr [rip + .LCPI1_1] ; 0x7F80_0000 ucomiss xmm1, xmm0 seta al ret ``` When used in loops/repeatedly, they get even better: the memory operations (loading the mask 0x7FFFFFFF for abs, and infinity 0x7F80_0000) are likely to be hoisted out of the individual calls, to be shared, and the `seta`/`setae` are likely to be collapsed into conditional jumps or moves (or similar). The old `is_infinite` did two comparisons, and the old `is_finite` did three (with a branch), and both of them had to check the flags after every one of those comparison. These functions have had that old implementation since they were added in https://github.com/rust-lang/rust/commit/6284190ef9918e05cb9147a2a81100ddcb06fea8 7 years ago. Benchmark (`abs` is the new form, `std` is the old): ``` test f32_is_finite_abs ... bench: 55 ns/iter (+/- 10) test f32_is_finite_std ... bench: 118 ns/iter (+/- 5) test f32_is_infinite_abs ... bench: 53 ns/iter (+/- 1) test f32_is_infinite_std ... bench: 84 ns/iter (+/- 6) test f64_is_finite_abs ... bench: 52 ns/iter (+/- 12) test f64_is_finite_std ... bench: 128 ns/iter (+/- 25) test f64_is_infinite_abs ... bench: 54 ns/iter (+/- 5) test f64_is_infinite_std ... bench: 93 ns/iter (+/- 23) ``` ```rust #![feature(test)] extern crate test; use std::{f32, f64}; use test::Bencher; const VALUES_F32: &[f32] = &[0.910, 0.135, 0.735, -0.874, 0.518, 0.150, -0.527, -0.418, 0.449, -0.158, -0.064, -0.144, -0.948, -0.103, 0.225, -0.104, -0.795, 0.435, 0.860, 0.027, 0.625, -0.848, -0.454, 0.359, -0.930, 0.067, 0.642, 0.976, -0.682, -0.035, 0.750, 0.005, -0.825, 0.731, -0.850, -0.740, -0.118, -0.972, 0.888, -0.958, 0.086, 0.237, -0.580, 0.488, 0.028, -0.552, 0.302, 0.058, -0.229, -0.166, -0.248, -0.430, 0.789, -0.122, 0.120, -0.934, -0.911, -0.976, 0.882, -0.410, 0.311, -0.611, -0.758, 0.786, -0.711, 0.378, 0.803, -0.068, 0.932, 0.483, 0.085, 0.247, -0.128, -0.839, -0.737, -0.605, 0.637, -0.230, -0.502, 0.231, -0.694, -0.400, -0.441, 0.142, 0.174, 0.681, -0.763, -0.608, 0.848, -0.550, 0.883, -0.212, 0.876, 0.186, -0.909, 0.401, -0.533, -0.961, 0.539, -0.298, -0.448, 0.223, -0.307, -0.594, 0.629, -0.534, 0.959, 0.349, -0.926, -0.523, -0.895, -0.157, -0.074, -0.060, 0.513, -0.647, -0.649, 0.428, 0.401, 0.391, 0.426, 0.700, 0.880, -0.101, 0.862, 0.493, 0.819, -0.597]; #[bench] fn f32_is_infinite_std(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F32).iter().any(|x| x.is_infinite())); } #[bench] fn f32_is_infinite_abs(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F32).iter().any(|x| x.abs()== f32::INFINITY)); } #[bench] fn f32_is_finite_std(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F32).iter().all(|x| x.is_finite())); } #[bench] fn f32_is_finite_abs(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F32).iter().all(|x| x.abs() < f32::INFINITY)); } const VALUES_F64: &[f64] = &[0.910, 0.135, 0.735, -0.874, 0.518, 0.150, -0.527, -0.418, 0.449, -0.158, -0.064, -0.144, -0.948, -0.103, 0.225, -0.104, -0.795, 0.435, 0.860, 0.027, 0.625, -0.848, -0.454, 0.359, -0.930, 0.067, 0.642, 0.976, -0.682, -0.035, 0.750, 0.005, -0.825, 0.731, -0.850, -0.740, -0.118, -0.972, 0.888, -0.958, 0.086, 0.237, -0.580, 0.488, 0.028, -0.552, 0.302, 0.058, -0.229, -0.166, -0.248, -0.430, 0.789, -0.122, 0.120, -0.934, -0.911, -0.976, 0.882, -0.410, 0.311, -0.611, -0.758, 0.786, -0.711, 0.378, 0.803, -0.068, 0.932, 0.483, 0.085, 0.247, -0.128, -0.839, -0.737, -0.605, 0.637, -0.230, -0.502, 0.231, -0.694, -0.400, -0.441, 0.142, 0.174, 0.681, -0.763, -0.608, 0.848, -0.550, 0.883, -0.212, 0.876, 0.186, -0.909, 0.401, -0.533, -0.961, 0.539, -0.298, -0.448, 0.223, -0.307, -0.594, 0.629, -0.534, 0.959, 0.349, -0.926, -0.523, -0.895, -0.157, -0.074, -0.060, 0.513, -0.647, -0.649, 0.428, 0.401, 0.391, 0.426, 0.700, 0.880, -0.101, 0.862, 0.493, 0.819, -0.597]; #[bench] fn f64_is_infinite_std(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F64).iter().any(|x| x.is_infinite())); } #[bench] fn f64_is_infinite_abs(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F64).iter().any(|x| x.abs() == f64::INFINITY)); } #[bench] fn f64_is_finite_std(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F64).iter().all(|x| x.is_finite())); } #[bench] fn f64_is_finite_abs(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F64).iter().all(|x| x.abs() < f64::INFINITY)); } ```
2019-01-13Minor cosmetic changesAlexander Regueiro-8/+12
2019-01-13const stabilize .Mazdak Farrokhzad-22/+43
2019-01-07Optimise floating point `is_finite` (2x) and `is_infinite` (1.6x).Huon Wilson-4/+24
These can both rely on IEEE754 semantics to be made faster, by folding away the sign with an abs (left private for now), and then comparing to infinity, letting the NaN semantics of a direct float comparison handle NaN input properly. The `abs` bit-fiddling is simple (a single and), and so these new forms compile down to a few instructions, without branches, e.g. for f32: ```asm is_infinite: andps xmm0, xmmword ptr [rip + .LCPI2_0] ; 0x7FFF_FFFF ucomiss xmm0, dword ptr [rip + .LCPI2_1] ; 0x7F80_0000 setae al ret is_finite: andps xmm0, xmmword ptr [rip + .LCPI1_0] ; 0x7FFF_FFFF movss xmm1, dword ptr [rip + .LCPI1_1] ; 0x7F80_0000 ucomiss xmm1, xmm0 seta al ret ``` When used in loops/repeatedly, they get even better: the memory operations (loading the mask 0x7FFFFFFF for abs, and infinity 0x7F80_0000) are likely to be hoisted out of the individual calls, to be shared, and the `seta`/`setae` are likely to be collapsed into conditional jumps or moves (or similar). The old `is_infinite` did two comparisons, and the old `is_finite` did three (with a branch), and both of them had to check the flags after every one of those comparison. These functions have had that old implementation since they were added in https://github.com/rust-lang/rust/commit/6284190ef9918e05cb9147a2a81100ddcb06fea8 7 years ago. Benchmark (`abs` is the new form, `std` is the old): ``` test f32_is_finite_abs ... bench: 55 ns/iter (+/- 10) test f32_is_finite_std ... bench: 118 ns/iter (+/- 5) test f32_is_infinite_abs ... bench: 53 ns/iter (+/- 1) test f32_is_infinite_std ... bench: 84 ns/iter (+/- 6) test f64_is_finite_abs ... bench: 52 ns/iter (+/- 12) test f64_is_finite_std ... bench: 128 ns/iter (+/- 25) test f64_is_infinite_abs ... bench: 54 ns/iter (+/- 5) test f64_is_infinite_std ... bench: 93 ns/iter (+/- 23) ``` ```rust #![feature(test)] extern crate test; use std::{f32, f64}; use test::Bencher; const VALUES_F32: &[f32] = &[0.910, 0.135, 0.735, -0.874, 0.518, 0.150, -0.527, -0.418, 0.449, -0.158, -0.064, -0.144, -0.948, -0.103, 0.225, -0.104, -0.795, 0.435, 0.860, 0.027, 0.625, -0.848, -0.454, 0.359, -0.930, 0.067, 0.642, 0.976, -0.682, -0.035, 0.750, 0.005, -0.825, 0.731, -0.850, -0.740, -0.118, -0.972, 0.888, -0.958, 0.086, 0.237, -0.580, 0.488, 0.028, -0.552, 0.302, 0.058, -0.229, -0.166, -0.248, -0.430, 0.789, -0.122, 0.120, -0.934, -0.911, -0.976, 0.882, -0.410, 0.311, -0.611, -0.758, 0.786, -0.711, 0.378, 0.803, -0.068, 0.932, 0.483, 0.085, 0.247, -0.128, -0.839, -0.737, -0.605, 0.637, -0.230, -0.502, 0.231, -0.694, -0.400, -0.441, 0.142, 0.174, 0.681, -0.763, -0.608, 0.848, -0.550, 0.883, -0.212, 0.876, 0.186, -0.909, 0.401, -0.533, -0.961, 0.539, -0.298, -0.448, 0.223, -0.307, -0.594, 0.629, -0.534, 0.959, 0.349, -0.926, -0.523, -0.895, -0.157, -0.074, -0.060, 0.513, -0.647, -0.649, 0.428, 0.401, 0.391, 0.426, 0.700, 0.880, -0.101, 0.862, 0.493, 0.819, -0.597]; #[bench] fn f32_is_infinite_std(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F32).iter().any(|x| x.is_infinite())); } #[bench] fn f32_is_infinite_abs(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F32).iter().any(|x| x.abs()== f32::INFINITY)); } #[bench] fn f32_is_finite_std(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F32).iter().all(|x| x.is_finite())); } #[bench] fn f32_is_finite_abs(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F32).iter().all(|x| x.abs() < f32::INFINITY)); } const VALUES_F64: &[f64] = &[0.910, 0.135, 0.735, -0.874, 0.518, 0.150, -0.527, -0.418, 0.449, -0.158, -0.064, -0.144, -0.948, -0.103, 0.225, -0.104, -0.795, 0.435, 0.860, 0.027, 0.625, -0.848, -0.454, 0.359, -0.930, 0.067, 0.642, 0.976, -0.682, -0.035, 0.750, 0.005, -0.825, 0.731, -0.850, -0.740, -0.118, -0.972, 0.888, -0.958, 0.086, 0.237, -0.580, 0.488, 0.028, -0.552, 0.302, 0.058, -0.229, -0.166, -0.248, -0.430, 0.789, -0.122, 0.120, -0.934, -0.911, -0.976, 0.882, -0.410, 0.311, -0.611, -0.758, 0.786, -0.711, 0.378, 0.803, -0.068, 0.932, 0.483, 0.085, 0.247, -0.128, -0.839, -0.737, -0.605, 0.637, -0.230, -0.502, 0.231, -0.694, -0.400, -0.441, 0.142, 0.174, 0.681, -0.763, -0.608, 0.848, -0.550, 0.883, -0.212, 0.876, 0.186, -0.909, 0.401, -0.533, -0.961, 0.539, -0.298, -0.448, 0.223, -0.307, -0.594, 0.629, -0.534, 0.959, 0.349, -0.926, -0.523, -0.895, -0.157, -0.074, -0.060, 0.513, -0.647, -0.649, 0.428, 0.401, 0.391, 0.426, 0.700, 0.880, -0.101, 0.862, 0.493, 0.819, -0.597]; #[bench] fn f64_is_infinite_std(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F64).iter().any(|x| x.is_infinite())); } #[bench] fn f64_is_infinite_abs(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F64).iter().any(|x| x.abs() == f64::INFINITY)); } #[bench] fn f64_is_finite_std(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F64).iter().all(|x| x.is_finite())); } #[bench] fn f64_is_finite_abs(b: &mut Bencher) { b.iter(|| test::black_box(VALUES_F64).iter().all(|x| x.abs() < f64::INFINITY)); } ```
2018-12-31const-stabilize const_int_ops + reverse_bitsMazdak Farrokhzad-21/+36
2018-12-31now that some intrisics are safe, use that fact.Mazdak Farrokhzad-0/+24
2018-12-31stabilize const_int_signMazdak Farrokhzad-2/+0
2018-12-31stabilize const_int_rotateMazdak Farrokhzad-4/+4
2018-12-31stabilize const_int_wrapping.Mazdak Farrokhzad-10/+10
2018-12-28Make the getter for NonZero types into a const fndylan_DPC-1/+1
2018-12-26Remove the private generic NonZero<T> wrapper type.Simon Sapin-6/+6
Instead, use `#[rustc_layout_scalar_valid_range_start(1)]` directly on relevant libcore types.
2018-12-25Remove licensesMark Rousskov-310/+0
2018-12-20fix nitsNicole Mazzuca-2/+4
2018-12-20Update src/libcore/num/mod.rsDavid Tolnay-1/+1
Co-Authored-By: ubsan <npmazzuca@gmail.com>
2018-12-17rename div_euc -> div_euclid, and mod_euc -> rem_euclidNicole Mazzuca-76/+96
logic is written up in https://github.com/rust-lang/rust/issues/49048 Also, update the documentation slightly
2018-12-16Rollup merge of #56855 - nikic:remove-cttz-hack, r=nagisaMazdak Farrokhzad-14/+1
Remove u8 cttz hack This issue has since been fixed in LLVM: https://github.com/llvm-mirror/llvm/commit/1886c8e29a9992d73c5e6ba0d52eb98ee036ab5d Furthermore this code doesn't actually work, because the 8 literal does not match the $BITS provided from the macro invocation, so effectively this was just dead code. Ref #43024. What LLVM does is still not ideal for CPUs that only have bsf but not tzcnt, will create a patch for that later. r? @nagisa
2018-12-16Rollup merge of #56706 - oli-obk:const_unsafe_fn, r=CentrilMazdak Farrokhzad-1/+1
Make `const unsafe fn` bodies `unsafe` r? @Centril Updated for tracking issue discussion https://github.com/rust-lang/rust/issues/55607#issuecomment-445882296
2018-12-15Remove u8 cttz hackNikita Popov-14/+1
This issue has since been fixed in LLVM: https://github.com/llvm-mirror/llvm/commit/1886c8e29a9992d73c5e6ba0d52eb98ee036ab5d Furthermore this doesn't actually work, because the "8" literal does not match the $BITS provided from the macro invocation, so effectively this code was not being used anyway...
2018-12-12Bump to 1.33.0Alex Crichton-12/+2
* Update bootstrap compiler * Update version to 1.33.0 * Remove some `#[cfg(stage0)]` annotations Actually updating the version number is blocked on updating Cargo
2018-12-11Make `const unsafe fn` bodies `unsafe`Oliver Scherer-1/+1
2018-12-07Various minor/cosmetic improvements to codeAlexander Regueiro-24/+24
2018-12-04Make sure the initialization of constrained int range newtypes is unsafeOliver Scherer-2/+2
2018-12-01Rollup merge of #56355 - Zoxc:inline-things, r=michaelwoeristerkennytm-0/+1
Add inline attributes and add unit to CommonTypes
2018-12-01Rollup merge of #56216 - SimonSapin:array-tryfrom-slice, r=withoutboatskennytm-0/+78
Add TryFrom<&[T]> for [T; $N] where T: Copy `TryFrom<&[T]> for &[T; $N]` (note *reference* to an array) already exists, but not needing to dereference makes type inference easier for example when using `u32::from_be_bytes`. Also add doc examples doing just that.
2018-11-29Add inline attributes and add unit to CommonTypesJohn Kåre Alsaker-0/+1
2018-11-26Auto merge of #55705 - ethanboxx:master, r=SimonSapinbors-1/+24
Make `ParseIntError` and `IntErrorKind` fully public Why would you write nice error types if I can't read them? # Why It can be useful to use `match` with errors produced when parsing strings to int. This would be useful for the `.err_match()` function in my [new crate](https://crates.io/crates/read_input). --- I could also do this for `ParseFloatError` if people think it is a good idea. I am new around hear so please tell me if I am getting anything wrong.
2018-11-25Add TryFrom<&[T]> for [T; $N] where T: CopySimon Sapin-0/+78
`TryFrom<&[T]> for &[T; $N]` (note *reference* to an array) already exists, but not needing to dereference makes type inference easier for example when using `u32::from_be_bytes`. Also add doc examples doing just that.
2018-11-25fix missing borrowEthan Brierley-1/+1
2018-11-25Use a reference rather than take ownershipEthan Brierley-1/+1
2018-11-25Stabilize the int_to_from_bytes featureSimon Sapin-36/+12
Fixes #52963
2018-11-15Rollup merge of #55901 - euclio:speling, r=petrochenkovPietro Albini-1/+1
fix various typos in doc comments
2018-11-13fix various typos in doc commentsAndy Russell-1/+1
2018-11-12Auto merge of #55278 - Centril:constification-1, r=alexcrichtonbors-17/+15
Minor standard library constification This PR makes some bits of the standard library into `const fn`s. I've tried to be as aggressive as I possibly could in the constification. The list is rather small due to how restrictive `const fn` is at the moment. r? @oli-obk cc @rust-lang/libs Stable public APIs affected: + [x] `Cell::as_ptr` + [x] `UnsafeCell::get` + [x] `char::is_ascii` + [x] `iter::empty` + [x] `ManuallyDrop::{new, into_inner}` + [x] `RangeInclusive::{start, end}` + [x] `NonNull::as_ptr` + [x] `{[T], str}::as_ptr` + [x] `Duration::{as_secs, subsec_millis, subsec_micros, subsec_nanos}` + [x] `CStr::as_ptr` + [x] `Ipv4Addr::is_unspecified` + [x] `Ipv6Addr::new` + [x] `Ipv6Addr::octets` Unstable public APIs affected: + [x] `Duration::{as_millis, as_micros, as_nanos, as_float_secs}` + [x] `Wrapping::{count_ones, count_zeros, trailing_zeros, rotate_left, rotate_right, swap_bytes, reverse_bits, from_be, from_le, to_be, to_le, leading_zeros, is_positive, is_negative, leading_zeros}` + [x] `core::convert::identity` -------------------------- ## Removed from list in first pass: Stable public APIs affected: + [ ] `BTree{Map, Set}::{len, is_empty}` + [ ] `VecDeque::is_empty` + [ ] `String::{is_empty, len}` + [ ] `FromUtf8Error::utf8_error` + [ ] `Vec<T>::{is_empty, len}` + [ ] `Layout::size` + [ ] `DecodeUtf16Error::unpaired_surrogate` + [ ] `core::fmt::{fill, width, precision, sign_plus, sign_minus, alternate, sign_aware_zero_pad}` + [ ] `panic::Location::{file, line, column}` + [ ] `{ChunksExact, RChunksExact}::remainder` + [ ] `Utf8Error::valid_up_to` + [ ] `VacantEntry::key` + [ ] `NulError::nul_position` + [ ] `IntoStringError::utf8_error` + [ ] `IntoInnerError::error` + [ ] `io::Chain::get_ref` + [ ] `io::Take::{limit, get_ref}` + [ ] `SocketAddrV6::{flowinfo, scope_id}` + [ ] `PrefixComponent::{kind, as_os_str}` + [ ] `Path::{ancestors, display}` + [ ] `WaitTimeoutResult::timed_out` + [ ] `Receiver::{iter, try_iter}` + [ ] `thread::JoinHandle::thread` + [ ] `SystemTimeError::duration` Unstable public APIs affected: + [ ] `core::fmt::Arguments::new_v1` + [ ] `core::fmt::Arguments::new_v1_formatted` + [ ] `Pin::{get_ref, into_ref}` + [ ] `Utf8Lossy::chunks` + [ ] `LocalWaker::as_waker` + [ ] `panic::PanicInfo::{internal_constructor, message, location}` + [ ] `panic::Location::{internal_constructor }` ## Removed from list in 2nd pass: Stable public APIs affected: + [ ] `LinkedList::{new, iter, is_empty, len}` + [ ] `mem::forget` + [ ] `Cursor::{new, get_ref, position}` + [ ] `io::{empty, repeat, sink}` + [ ] `PoisonError::new` + [ ] `thread::Builder::new` + [ ] `process::Stdio::{piped, inherit, null}` Unstable public APIs affected: + [ ] `io::Initializer::{zeroing, should_initialize}`
2018-11-11Rollup merge of #55828 - oli-obk:promotion_strikes_again, r=eddybPietro Albini-0/+2
Add missing `rustc_promotable` attribute to unsigned `min_value` and `max_value` cc @pnkfelix fixes #55806
2018-11-10revert making internal APIs const fn.Mazdak Farrokhzad-5/+5
2018-11-10constify parts of libcore.Mazdak Farrokhzad-22/+20
2018-11-09Add missing `rustc_promotable` attribute to unsigned `min_value` and `max_value`Oliver Scherer-0/+2
2018-11-07add unstable attributeEthan Brierley-0/+4
2018-11-07Fix incorrect documentationEthan Brierley-2/+2
2018-11-07Use method rather than public fieldEthan Brierley-2/+5
2018-11-06Document kind fieldEthan Brierley-0/+1
2018-11-06Fix mistake in my markdownEthan Brierley-0/+2
2018-11-06Add very useful documentationEthan Brierley-0/+8
2018-11-05Continue to try to make travis happy by adding a issue numberEthan Brierley-1/+2
2018-11-05break line to keep `travis_fold:start:tidy` happyEthan Brierley-1/+2
2018-11-05Add useful attributesEthan Brierley-0/+3
2018-11-05Make `ParseIntError` and `IntErrorKind` fully publicEthan Brierley-2/+2
2018-11-03Implement rotate using funnel shift on LLVM >= 7Nikita Popov-2/+12
Implement the rotate_left and rotate_right operations using llvm.fshl and llvm.fshr if they are available (LLVM >= 7). Originally I wanted to expose the funnel_shift_left and funnel_shift_right intrinsics and implement rotate_left and rotate_right on top of them. However, emulation of funnel shifts requires emitting a conditional to check for zero shift amount, which is not necessary for rotates. I was uncomfortable doing that here, as I don't want to rely on LLVM to optimize away that conditional (and for variable rotates, I'm not sure it can). We should revisit that question when we raise our minimum version requirement to LLVM 7 and don't need emulation code anymore.