From b0e55a83a82bae26851f442859acace2b94f5028 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 23 Aug 2016 03:56:52 +0300 Subject: [PATCH 01/47] Such large. Very 128. Much bits. This commit introduces 128-bit integers. Stage 2 builds and produces a working compiler which understands and supports 128-bit integers throughout. The general strategy used is to have rustc_i128 module which provides aliases for iu128, equal to iu64 in stage9 and iu128 later. Since nowhere in rustc we rely on large numbers being supported, this strategy is good enough to get past the first bootstrap stages to end up with a fully working 128-bit capable compiler. In order for this strategy to work, number of locations had to be changed to use associated max_value/min_value instead of MAX/MIN constants as well as the min_value (or was it max_value?) had to be changed to use xor instead of shift so both 64-bit and 128-bit based consteval works (former not necessarily producing the right results in stage1). This commit includes manual merge conflict resolution changes from a rebase by @est31. --- src/libcore/clone.rs | 4 + src/libcore/cmp.rs | 6 + src/libcore/default.rs | 4 + src/libcore/fmt/num.rs | 21 +- src/libcore/hash/mod.rs | 19 ++ src/libcore/lib.rs | 8 + src/libcore/nonzero.rs | 4 + src/libcore/num/i128.rs | 17 ++ src/libcore/num/i16.rs | 2 +- src/libcore/num/i32.rs | 2 +- src/libcore/num/i64.rs | 2 +- src/libcore/num/i8.rs | 2 +- src/libcore/num/int_macros.rs | 2 +- src/libcore/num/isize.rs | 7 +- src/libcore/num/mod.rs | 110 +++++++- src/libcore/num/u128.rs | 16 ++ src/libcore/num/u16.rs | 2 +- src/libcore/num/u32.rs | 2 +- src/libcore/num/u64.rs | 2 +- src/libcore/num/u8.rs | 2 +- src/libcore/num/uint_macros.rs | 2 +- src/libcore/num/usize.rs | 7 +- src/libcore/ops.rs | 61 +++++ src/libproc_macro/Cargo.toml | 1 + src/librustc/Cargo.toml | 1 + src/librustc/lib.rs | 3 + src/librustc/middle/lang_items.rs | 2 + src/librustc/ty/context.rs | 6 + src/librustc/ty/layout.rs | 45 ++-- src/librustc/ty/util.rs | 6 + src/librustc_const_eval/Cargo.toml | 3 +- src/librustc_const_eval/eval.rs | 89 +++--- src/librustc_const_eval/lib.rs | 3 + src/librustc_const_math/Cargo.toml | 1 + src/librustc_const_math/err.rs | 2 + src/librustc_const_math/int.rs | 312 +++++++++++++--------- src/librustc_const_math/is.rs | 5 +- src/librustc_const_math/lib.rs | 4 + src/librustc_const_math/us.rs | 5 +- src/librustc_i128/Cargo.toml | 9 + src/librustc_i128/lib.rs | 16 ++ src/librustc_lint/Cargo.toml | 1 + src/librustc_lint/lib.rs | 2 + src/librustc_lint/types.rs | 59 ++-- src/librustc_llvm/ffi.rs | 2 + src/librustc_metadata/Cargo.toml | 1 + src/librustc_metadata/decoder.rs | 4 + src/librustc_metadata/lib.rs | 6 + src/librustc_mir/Cargo.toml | 1 + src/librustc_mir/build/expr/as_rvalue.rs | 12 +- src/librustc_mir/build/misc.rs | 2 + src/librustc_mir/lib.rs | 2 + src/librustc_resolve/lib.rs | 3 +- src/librustc_trans/Cargo.toml | 3 +- src/librustc_trans/common.rs | 12 + src/librustc_trans/consts.rs | 1 + src/librustc_trans/context.rs | 11 + src/librustc_trans/debuginfo/metadata.rs | 3 +- src/librustc_trans/disr.rs | 3 +- src/librustc_trans/intrinsic.rs | 4 + src/librustc_trans/lib.rs | 1 + src/librustc_trans/mir/constant.rs | 5 +- src/librustc_trans/mir/rvalue.rs | 6 + src/librustc_trans/trans_item.rs | 2 + src/librustc_trans/type_.rs | 10 +- src/librustc_typeck/check/intrinsic.rs | 4 +- src/librustc_typeck/check/method/probe.rs | 8 + src/librustc_typeck/coherence/orphan.rs | 14 + src/librustc_typeck/collect.rs | 2 + src/librustdoc/clean/mod.rs | 86 +++--- src/libserialize/Cargo.toml | 1 + src/libserialize/json.rs | 8 + src/libserialize/leb128.rs | 61 ++--- src/libserialize/lib.rs | 2 + src/libserialize/opaque.rs | 24 +- src/libserialize/serialize.rs | 33 +++ src/libstd/lib.rs | 7 + src/libsyntax/Cargo.toml | 1 + src/libsyntax/ast.rs | 28 +- src/libsyntax/attr.rs | 5 +- src/libsyntax/ext/build.rs | 14 +- src/libsyntax/ext/quote.rs | 6 +- src/libsyntax/lib.rs | 3 +- src/libsyntax/parse/mod.rs | 8 +- src/libsyntax/parse/parser.rs | 4 +- src/libsyntax/print/pprust.rs | 5 +- src/libsyntax_ext/deriving/generic/mod.rs | 3 +- 87 files changed, 945 insertions(+), 355 deletions(-) create mode 100644 src/libcore/num/i128.rs create mode 100644 src/libcore/num/u128.rs create mode 100644 src/librustc_i128/Cargo.toml create mode 100644 src/librustc_i128/lib.rs diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index d72b18ae345ce..cd2e8f1018141 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -153,12 +153,16 @@ clone_impl! { i8 } clone_impl! { i16 } clone_impl! { i32 } clone_impl! { i64 } +#[cfg(not(stage0))] +clone_impl! { i128 } clone_impl! { usize } clone_impl! { u8 } clone_impl! { u16 } clone_impl! { u32 } clone_impl! { u64 } +#[cfg(not(stage0))] +clone_impl! { u128 } clone_impl! { f32 } clone_impl! { f64 } diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 54fb70278cac6..a78d27ea3afc1 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -681,6 +681,8 @@ mod impls { partial_eq_impl! { bool char usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } + #[cfg(not(stage0))] + partial_eq_impl! { u128 i128 } macro_rules! eq_impl { ($($t:ty)*) => ($( @@ -690,6 +692,8 @@ mod impls { } eq_impl! { () bool char usize u8 u16 u32 u64 isize i8 i16 i32 i64 } + #[cfg(not(stage0))] + eq_impl! { u128 i128 } macro_rules! partial_ord_impl { ($($t:ty)*) => ($( @@ -779,6 +783,8 @@ mod impls { } ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 } + #[cfg(not(stage0))] + ord_impl! { u128 i128 } #[unstable(feature = "never_type_impls", issue = "35121")] impl PartialEq for ! { diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 85e4b2a006769..ccd4343336f5e 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -144,12 +144,16 @@ default_impl! { u8, 0 } default_impl! { u16, 0 } default_impl! { u32, 0 } default_impl! { u64, 0 } +#[cfg(not(stage0))] +default_impl! { u128, 0 } default_impl! { isize, 0 } default_impl! { i8, 0 } default_impl! { i16, 0 } default_impl! { i32, 0 } default_impl! { i64, 0 } +#[cfg(not(stage0))] +default_impl! { i128, 0 } default_impl! { f32, 0.0f32 } default_impl! { f64, 0.0f64 } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 0145897d8f690..7b6c2d4888965 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -30,6 +30,8 @@ trait Int: Zero + PartialEq + PartialOrd + Div + Rem + fn to_u16(&self) -> u16; fn to_u32(&self) -> u32; fn to_u64(&self) -> u64; + #[cfg(not(stage0))] + fn to_u128(&self) -> u128; } macro_rules! doit { @@ -39,9 +41,13 @@ macro_rules! doit { fn to_u16(&self) -> u16 { *self as u16 } fn to_u32(&self) -> u32 { *self as u32 } fn to_u64(&self) -> u64 { *self as u64 } + #[cfg(not(stage0))] + fn to_u128(&self) -> u128 { *self as u128 } })*) } doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } +#[cfg(not(stage0))] +doit! { i128 u128 } /// A type that represents a specific radix #[doc(hidden)] @@ -59,11 +65,11 @@ trait GenericRadix { /// Format an integer using the radix using a formatter. fn fmt_int(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result { - // The radix can be as low as 2, so we need a buffer of at least 64 + // The radix can be as low as 2, so we need a buffer of at least 128 // characters for a base 2 number. let zero = T::zero(); let is_nonnegative = x >= zero; - let mut buf = [0; 64]; + let mut buf = [0; 128]; let mut curr = buf.len(); let base = T::from_u8(self.base()); if is_nonnegative { @@ -182,6 +188,8 @@ integer! { i8, u8 } integer! { i16, u16 } integer! { i32, u32 } integer! { i64, u64 } +#[cfg(not(stage0))] +integer! { i128, u128 } const DEC_DIGITS_LUT: &'static[u8] = b"0001020304050607080910111213141516171819\ @@ -203,14 +211,15 @@ macro_rules! impl_Display { // convert the negative num to positive by summing 1 to it's 2 complement (!self.$conv_fn()).wrapping_add(1) }; - let mut buf: [u8; 20] = unsafe { mem::uninitialized() }; + let mut buf: [u8; 40] = unsafe { mem::uninitialized() }; let mut curr = buf.len() as isize; let buf_ptr = buf.as_mut_ptr(); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); unsafe { - // eagerly decode 4 characters at a time - if <$t>::max_value() as u64 >= 10000 { + // need at least 16 bits for the 4-characters-at-a-time to work. + if ::mem::size_of::<$t>() >= 2 { + // eagerly decode 4 characters at a time while n >= 10000 { let rem = (n % 10000) as isize; n /= 10000; @@ -256,6 +265,8 @@ macro_rules! impl_Display { impl_Display!(i8, u8, i16, u16, i32, u32: to_u32); impl_Display!(i64, u64: to_u64); +#[cfg(not(stage0))] +impl_Display!(i128, u128: to_u128); #[cfg(target_pointer_width = "16")] impl_Display!(isize, usize: to_u16); #[cfg(target_pointer_width = "32")] diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 18b465d85a12f..92657a6d0b1ca 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -186,6 +186,13 @@ pub trait Hasher { fn write_u64(&mut self, i: u64) { self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) }) } + #[cfg(not(stage0))] + /// Writes a single `u128` into this hasher. + #[inline] + #[unstable(feature = "i128", issue = "35118")] + fn write_u128(&mut self, i: u128) { + self.write(&unsafe { mem::transmute::<_, [u8; 16]>(i) }) + } /// Writes a single `usize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] @@ -220,6 +227,13 @@ pub trait Hasher { fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) } + #[cfg(not(stage0))] + /// Writes a single `i128` into this hasher. + #[inline] + #[unstable(feature = "i128", issue = "35118")] + fn write_i128(&mut self, i: i128) { + self.write_u128(i as u128) + } /// Writes a single `isize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] @@ -362,6 +376,11 @@ mod impls { (i64, write_i64), (isize, write_isize), } + #[cfg(not(stage0))] + impl_write! { + (u128, write_u128), + (i128, write_i128), + } #[stable(feature = "rust1", since = "1.0.0")] impl Hash for bool { diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9834fca5fdc78..443f4b2ea8e42 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -120,12 +120,20 @@ mod uint_macros; #[path = "num/i32.rs"] pub mod i32; #[path = "num/i64.rs"] pub mod i64; +// SNAP +#[cfg(not(stage0))] +#[path = "num/i128.rs"] pub mod i128; + #[path = "num/usize.rs"] pub mod usize; #[path = "num/u8.rs"] pub mod u8; #[path = "num/u16.rs"] pub mod u16; #[path = "num/u32.rs"] pub mod u32; #[path = "num/u64.rs"] pub mod u64; +// SNAP +#[cfg(not(stage0))] +#[path = "num/u128.rs"] pub mod u128; + #[path = "num/f32.rs"] pub mod f32; #[path = "num/f64.rs"] pub mod f64; diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 47afaf77353ee..539ad00bd30e0 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -30,6 +30,10 @@ unsafe impl Zeroable for i32 {} unsafe impl Zeroable for u32 {} unsafe impl Zeroable for i64 {} unsafe impl Zeroable for u64 {} +#[cfg(not(stage0))] +unsafe impl Zeroable for i128 {} +#[cfg(not(stage0))] +unsafe impl Zeroable for u128 {} /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. diff --git a/src/libcore/num/i128.rs b/src/libcore/num/i128.rs new file mode 100644 index 0000000000000..6268271a1dcc5 --- /dev/null +++ b/src/libcore/num/i128.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The 128-bit signed integer type. +//! +//! *[See also the `i128` primitive type](../../std/primitive.i128.html).* + +#![unstable(feature = "i128", issue="35118")] + +int_module! { i128 } diff --git a/src/libcore/num/i16.rs b/src/libcore/num/i16.rs index 1dd820980f496..0f3a5baa2dd9e 100644 --- a/src/libcore/num/i16.rs +++ b/src/libcore/num/i16.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -int_module! { i16, 16 } +int_module! { i16 } diff --git a/src/libcore/num/i32.rs b/src/libcore/num/i32.rs index 8a2168933dc66..ea8b3a9145c6e 100644 --- a/src/libcore/num/i32.rs +++ b/src/libcore/num/i32.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -int_module! { i32, 32 } +int_module! { i32 } diff --git a/src/libcore/num/i64.rs b/src/libcore/num/i64.rs index 2ce9eb11936bc..aa21b1190aef5 100644 --- a/src/libcore/num/i64.rs +++ b/src/libcore/num/i64.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -int_module! { i64, 64 } +int_module! { i64 } diff --git a/src/libcore/num/i8.rs b/src/libcore/num/i8.rs index 8b5a7f1910e20..1bed4861594c9 100644 --- a/src/libcore/num/i8.rs +++ b/src/libcore/num/i8.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -int_module! { i8, 8 } +int_module! { i8 } diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index e74c30d5e5af8..630fac9d92f0f 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -10,7 +10,7 @@ #![doc(hidden)] -macro_rules! int_module { ($T:ident, $bits:expr) => ( +macro_rules! int_module { ($T:ident) => ( /// The smallest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/num/isize.rs b/src/libcore/num/isize.rs index 86bcef4011d02..e0917f79c43dc 100644 --- a/src/libcore/num/isize.rs +++ b/src/libcore/num/isize.rs @@ -14,9 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(target_pointer_width = "16")] -int_module! { isize, 16 } -#[cfg(target_pointer_width = "32")] -int_module! { isize, 32 } -#[cfg(target_pointer_width = "64")] -int_module! { isize, 64 } +int_module! { isize } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index a4529909e83ef..49e366a89760c 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -145,6 +145,8 @@ macro_rules! zero_one_impl { )*) } zero_one_impl! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +#[cfg(not(stage0))] +zero_one_impl! { u128 i128 } macro_rules! zero_one_impl_float { ($($t:ty)*) => ($( @@ -191,7 +193,7 @@ macro_rules! int_impl { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub const fn min_value() -> Self { - (-1 as Self) << ($BITS - 1) + !0 ^ ((!0 as $UnsignedT) >> 1) as Self } /// Returns the largest value that can be represented by this integer type. @@ -1298,6 +1300,16 @@ impl i64 { intrinsics::mul_with_overflow } } +// SNAP +#[cfg(not(stage0))] +#[lang = "i128"] +impl i128 { + int_impl! { i128, u128, 128, + intrinsics::add_with_overflow, + intrinsics::sub_with_overflow, + intrinsics::mul_with_overflow } +} + #[cfg(target_pointer_width = "16")] #[lang = "isize"] impl isize { @@ -2330,6 +2342,20 @@ impl u64 { intrinsics::mul_with_overflow } } +// SNAP +#[cfg(not(stage0))] +#[lang = "u128"] +impl u128 { + uint_impl! { u128, 128, + intrinsics::ctpop, + intrinsics::ctlz, + intrinsics::cttz, + intrinsics::bswap, + intrinsics::add_with_overflow, + intrinsics::sub_with_overflow, + intrinsics::mul_with_overflow } +} + #[cfg(target_pointer_width = "16")] #[lang = "usize"] impl usize { @@ -2543,6 +2569,8 @@ macro_rules! from_str_radix_int_impl { )*} } from_str_radix_int_impl! { isize i8 i16 i32 i64 usize u8 u16 u32 u64 } +#[cfg(not(stage0))] +from_str_radix_int_impl! { u128 i128 } /// The error type returned when a checked integral type conversion fails. #[unstable(feature = "try_from", issue = "33417")] @@ -2567,7 +2595,7 @@ impl fmt::Display for TryFromIntError { } } -macro_rules! same_sign_from_int_impl { +macro_rules! same_sign_try_from_int_impl { ($storage:ty, $target:ty, $($source:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { @@ -2586,16 +2614,30 @@ macro_rules! same_sign_from_int_impl { )*} } -same_sign_from_int_impl!(u64, u8, u8, u16, u32, u64, usize); -same_sign_from_int_impl!(i64, i8, i8, i16, i32, i64, isize); -same_sign_from_int_impl!(u64, u16, u8, u16, u32, u64, usize); -same_sign_from_int_impl!(i64, i16, i8, i16, i32, i64, isize); -same_sign_from_int_impl!(u64, u32, u8, u16, u32, u64, usize); -same_sign_from_int_impl!(i64, i32, i8, i16, i32, i64, isize); -same_sign_from_int_impl!(u64, u64, u8, u16, u32, u64, usize); -same_sign_from_int_impl!(i64, i64, i8, i16, i32, i64, isize); -same_sign_from_int_impl!(u64, usize, u8, u16, u32, u64, usize); -same_sign_from_int_impl!(i64, isize, i8, i16, i32, i64, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, u8, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, i8, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, u16, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, i16, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, u32, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, i32, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, u64, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, i64, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, u128, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, i128, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, usize, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, isize, i8, i16, i32, i64, i128, isize); macro_rules! cross_sign_from_int_impl { ($unsigned:ty, $($signed:ty),*) => {$( @@ -2629,12 +2671,30 @@ macro_rules! cross_sign_from_int_impl { )*} } +#[cfg(stage0)] cross_sign_from_int_impl!(u8, i8, i16, i32, i64, isize); +#[cfg(stage0)] cross_sign_from_int_impl!(u16, i8, i16, i32, i64, isize); +#[cfg(stage0)] cross_sign_from_int_impl!(u32, i8, i16, i32, i64, isize); +#[cfg(stage0)] cross_sign_from_int_impl!(u64, i8, i16, i32, i64, isize); +#[cfg(stage0)] cross_sign_from_int_impl!(usize, i8, i16, i32, i64, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(u8, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(u16, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(u32, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(u64, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(u128, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(usize, i8, i16, i32, i64, i128, isize); + #[doc(hidden)] trait FromStrRadixHelper: PartialOrd + Copy { fn min_value() -> Self; @@ -2662,6 +2722,8 @@ macro_rules! doit { })*) } doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } +#[cfg(not(stage0))] +doit! { i128 u128 } fn from_str_radix(src: &str, radix: u32) -> Result { use self::IntErrorKind::*; @@ -2795,27 +2857,51 @@ macro_rules! impl_from { impl_from! { u8, u16 } impl_from! { u8, u32 } impl_from! { u8, u64 } +#[cfg(not(stage0))] +impl_from! { u8, u128 } impl_from! { u8, usize } impl_from! { u16, u32 } impl_from! { u16, u64 } +#[cfg(not(stage0))] +impl_from! { u16, u128 } impl_from! { u32, u64 } +#[cfg(not(stage0))] +impl_from! { u32, u128 } +#[cfg(not(stage0))] +impl_from! { u64, u128 } // Signed -> Signed impl_from! { i8, i16 } impl_from! { i8, i32 } impl_from! { i8, i64 } +#[cfg(not(stage0))] +impl_from! { i8, i128 } impl_from! { i8, isize } impl_from! { i16, i32 } impl_from! { i16, i64 } +#[cfg(not(stage0))] +impl_from! { i16, i128 } impl_from! { i32, i64 } +#[cfg(not(stage0))] +impl_from! { i32, i128 } +#[cfg(not(stage0))] +impl_from! { i64, i128 } // Unsigned -> Signed impl_from! { u8, i16 } impl_from! { u8, i32 } impl_from! { u8, i64 } +#[cfg(not(stage0))] +impl_from! { u8, i128 } impl_from! { u16, i32 } impl_from! { u16, i64 } +#[cfg(not(stage0))] +impl_from! { u16, i128 } impl_from! { u32, i64 } +#[cfg(not(stage0))] +impl_from! { u32, i128 } +#[cfg(not(stage0))] +impl_from! { u64, i128 } // Note: integers can only be represented with full precision in a float if // they fit in the significand, which is 24 bits in f32 and 53 bits in f64. diff --git a/src/libcore/num/u128.rs b/src/libcore/num/u128.rs new file mode 100644 index 0000000000000..77291f687255e --- /dev/null +++ b/src/libcore/num/u128.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The 128-bit unsigned integer type. +//! +//! *[See also the `u128` primitive type](../../std/primitive.u128.html).* + +#![unstable(feature = "i128", issue="35118")] +uint_module! { u128 } diff --git a/src/libcore/num/u16.rs b/src/libcore/num/u16.rs index d34d87caa55fa..9c318216f1fba 100644 --- a/src/libcore/num/u16.rs +++ b/src/libcore/num/u16.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -uint_module! { u16, 16 } +uint_module! { u16 } diff --git a/src/libcore/num/u32.rs b/src/libcore/num/u32.rs index f9c9099e47f18..84367c2073833 100644 --- a/src/libcore/num/u32.rs +++ b/src/libcore/num/u32.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -uint_module! { u32, 32 } +uint_module! { u32 } diff --git a/src/libcore/num/u64.rs b/src/libcore/num/u64.rs index 8dfe4335a3d72..cc48a28b22f69 100644 --- a/src/libcore/num/u64.rs +++ b/src/libcore/num/u64.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -uint_module! { u64, 64 } +uint_module! { u64 } diff --git a/src/libcore/num/u8.rs b/src/libcore/num/u8.rs index 0106ee8e401c9..6c0daa7763ae1 100644 --- a/src/libcore/num/u8.rs +++ b/src/libcore/num/u8.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -uint_module! { u8, 8 } +uint_module! { u8 } diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index cc9256ab6bf4e..a3a2dc73e9c8e 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -10,7 +10,7 @@ #![doc(hidden)] -macro_rules! uint_module { ($T:ident, $bits:expr) => ( +macro_rules! uint_module { ($T:ident) => ( /// The smallest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/num/usize.rs b/src/libcore/num/usize.rs index 685c52e271ec0..0b6f1c73c5834 100644 --- a/src/libcore/num/usize.rs +++ b/src/libcore/num/usize.rs @@ -14,9 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(target_pointer_width = "16")] -uint_module! { usize, 16 } -#[cfg(target_pointer_width = "32")] -uint_module! { usize, 32 } -#[cfg(target_pointer_width = "64")] -uint_module! { usize, 64 } +uint_module! { usize } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 07ae5b920b27b..40d941a8b27e0 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -268,6 +268,8 @@ macro_rules! add_impl { } add_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +add_impl! { u128 i128 } /// The `Sub` trait is used to specify the functionality of `-`. /// @@ -341,6 +343,8 @@ macro_rules! sub_impl { } sub_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +sub_impl! { u128 i128 } /// The `Mul` trait is used to specify the functionality of `*`. /// @@ -463,6 +467,8 @@ macro_rules! mul_impl { } mul_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +mul_impl! { u128 i128 } /// The `Div` trait is used to specify the functionality of `/`. /// @@ -592,6 +598,8 @@ macro_rules! div_impl_integer { } div_impl_integer! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +div_impl_integer! { u128 i128 } macro_rules! div_impl_float { ($($t:ty)*) => ($( @@ -671,6 +679,9 @@ macro_rules! rem_impl_integer { } rem_impl_integer! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +rem_impl_integer! { u128 i128 } + macro_rules! rem_impl_float { ($($t:ty)*) => ($( @@ -766,6 +777,8 @@ macro_rules! neg_impl_unsigned { // neg_impl_unsigned! { usize u8 u16 u32 u64 } neg_impl_numeric! { isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +neg_impl_numeric! { i128 } /// The `Not` trait is used to specify the functionality of unary `!`. /// @@ -824,6 +837,8 @@ macro_rules! not_impl { } not_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +not_impl! { u128 i128 } /// The `BitAnd` trait is used to specify the functionality of `&`. /// @@ -907,6 +922,8 @@ macro_rules! bitand_impl { } bitand_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitand_impl! { u128 i128 } /// The `BitOr` trait is used to specify the functionality of `|`. /// @@ -990,6 +1007,8 @@ macro_rules! bitor_impl { } bitor_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitor_impl! { u128 i128 } /// The `BitXor` trait is used to specify the functionality of `^`. /// @@ -1076,6 +1095,8 @@ macro_rules! bitxor_impl { } bitxor_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitxor_impl! { u128 i128 } /// The `Shl` trait is used to specify the functionality of `<<`. /// @@ -1166,17 +1187,23 @@ macro_rules! shl_impl_all { shl_impl! { $t, u16 } shl_impl! { $t, u32 } shl_impl! { $t, u64 } + #[cfg(not(stage0))] + shl_impl! { $t, u128 } shl_impl! { $t, usize } shl_impl! { $t, i8 } shl_impl! { $t, i16 } shl_impl! { $t, i32 } shl_impl! { $t, i64 } + #[cfg(not(stage0))] + shl_impl! { $t, i128 } shl_impl! { $t, isize } )*) } shl_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +#[cfg(not(stage0))] +shl_impl_all! { u128 i128 } /// The `Shr` trait is used to specify the functionality of `>>`. /// @@ -1267,17 +1294,23 @@ macro_rules! shr_impl_all { shr_impl! { $t, u16 } shr_impl! { $t, u32 } shr_impl! { $t, u64 } + #[cfg(not(stage0))] + shr_impl! { $t, u128 } shr_impl! { $t, usize } shr_impl! { $t, i8 } shr_impl! { $t, i16 } shr_impl! { $t, i32 } shr_impl! { $t, i64 } + #[cfg(not(stage0))] + shr_impl! { $t, i128 } shr_impl! { $t, isize } )*) } shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +#[cfg(not(stage0))] +shr_impl_all! { u128 i128 } /// The `AddAssign` trait is used to specify the functionality of `+=`. /// @@ -1334,6 +1367,8 @@ macro_rules! add_assign_impl { } add_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +add_assign_impl! { u128 i128 } /// The `SubAssign` trait is used to specify the functionality of `-=`. /// @@ -1390,6 +1425,8 @@ macro_rules! sub_assign_impl { } sub_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +sub_assign_impl! { u128 i128 } /// The `MulAssign` trait is used to specify the functionality of `*=`. /// @@ -1435,6 +1472,8 @@ macro_rules! mul_assign_impl { } mul_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +mul_assign_impl! { u128 i128 } /// The `DivAssign` trait is used to specify the functionality of `/=`. /// @@ -1479,6 +1518,8 @@ macro_rules! div_assign_impl { } div_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +div_assign_impl! { u128 i128 } /// The `RemAssign` trait is used to specify the functionality of `%=`. /// @@ -1523,6 +1564,8 @@ macro_rules! rem_assign_impl { } rem_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +rem_assign_impl! { u128 i128 } /// The `BitAndAssign` trait is used to specify the functionality of `&=`. /// @@ -1609,6 +1652,8 @@ macro_rules! bitand_assign_impl { } bitand_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitand_assign_impl! { u128 i128 } /// The `BitOrAssign` trait is used to specify the functionality of `|=`. /// @@ -1653,6 +1698,8 @@ macro_rules! bitor_assign_impl { } bitor_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitor_assign_impl! { u128 i128 } /// The `BitXorAssign` trait is used to specify the functionality of `^=`. /// @@ -1697,6 +1744,8 @@ macro_rules! bitxor_assign_impl { } bitxor_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitxor_assign_impl! { u128 i128 } /// The `ShlAssign` trait is used to specify the functionality of `<<=`. /// @@ -1749,17 +1798,23 @@ macro_rules! shl_assign_impl_all { shl_assign_impl! { $t, u16 } shl_assign_impl! { $t, u32 } shl_assign_impl! { $t, u64 } + #[cfg(not(stage0))] + shl_assign_impl! { $t, u128 } shl_assign_impl! { $t, usize } shl_assign_impl! { $t, i8 } shl_assign_impl! { $t, i16 } shl_assign_impl! { $t, i32 } shl_assign_impl! { $t, i64 } + #[cfg(not(stage0))] + shl_assign_impl! { $t, i128 } shl_assign_impl! { $t, isize } )*) } shl_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +#[cfg(not(stage0))] +shl_assign_impl_all! { u128 i128 } /// The `ShrAssign` trait is used to specify the functionality of `>>=`. /// @@ -1812,17 +1867,23 @@ macro_rules! shr_assign_impl_all { shr_assign_impl! { $t, u16 } shr_assign_impl! { $t, u32 } shr_assign_impl! { $t, u64 } + #[cfg(not(stage0))] + shr_assign_impl! { $t, u128 } shr_assign_impl! { $t, usize } shr_assign_impl! { $t, i8 } shr_assign_impl! { $t, i16 } shr_assign_impl! { $t, i32 } shr_assign_impl! { $t, i64 } + #[cfg(not(stage0))] + shr_assign_impl! { $t, i128 } shr_assign_impl! { $t, isize } )*) } shr_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +#[cfg(not(stage0))] +shr_assign_impl_all! { u128 i128 } /// The `Index` trait is used to specify the functionality of indexing operations /// like `container[index]` when used in an immutable context. diff --git a/src/libproc_macro/Cargo.toml b/src/libproc_macro/Cargo.toml index 7ce65d0fe4dbc..ca26ddbe5a0ee 100644 --- a/src/libproc_macro/Cargo.toml +++ b/src/libproc_macro/Cargo.toml @@ -9,3 +9,4 @@ crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 578ef68b00386..51494885e7369 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -20,6 +20,7 @@ rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_llvm = { path = "../librustc_llvm" } +rustc_i128 = { path = "../librustc_i128" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index efe855f0a39e9..73ec9d8f8c880 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -62,6 +62,9 @@ extern crate rustc_errors as errors; extern crate serialize as rustc_serialize; // used by deriving +// SNAP: +extern crate rustc_i128; + #[cfg(test)] extern crate test; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 4cae5b370eb7e..cd7859af8ee7b 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -260,11 +260,13 @@ language_item_table! { I16ImplItem, "i16", i16_impl; I32ImplItem, "i32", i32_impl; I64ImplItem, "i64", i64_impl; + I128ImplItem, "i128", i128_impl; IsizeImplItem, "isize", isize_impl; U8ImplItem, "u8", u8_impl; U16ImplItem, "u16", u16_impl; U32ImplItem, "u32", u32_impl; U64ImplItem, "u64", u64_impl; + U128ImplItem, "u128", u128_impl; UsizeImplItem, "usize", usize_impl; F32ImplItem, "f32", f32_impl; F64ImplItem, "f64", f64_impl; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index cb1fc15c5f682..380c5b0eb6f3b 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -194,11 +194,13 @@ pub struct CommonTypes<'tcx> { pub i16: Ty<'tcx>, pub i32: Ty<'tcx>, pub i64: Ty<'tcx>, + pub i128: Ty<'tcx>, pub usize: Ty<'tcx>, pub u8: Ty<'tcx>, pub u16: Ty<'tcx>, pub u32: Ty<'tcx>, pub u64: Ty<'tcx>, + pub u128: Ty<'tcx>, pub f32: Ty<'tcx>, pub f64: Ty<'tcx>, pub never: Ty<'tcx>, @@ -359,11 +361,13 @@ impl<'tcx> CommonTypes<'tcx> { i16: mk(TyInt(ast::IntTy::I16)), i32: mk(TyInt(ast::IntTy::I32)), i64: mk(TyInt(ast::IntTy::I64)), + i128: mk(TyInt(ast::IntTy::I128)), usize: mk(TyUint(ast::UintTy::Us)), u8: mk(TyUint(ast::UintTy::U8)), u16: mk(TyUint(ast::UintTy::U16)), u32: mk(TyUint(ast::UintTy::U32)), u64: mk(TyUint(ast::UintTy::U64)), + u128: mk(TyUint(ast::UintTy::U128)), f32: mk(TyFloat(ast::FloatTy::F32)), f64: mk(TyFloat(ast::FloatTy::F64)), } @@ -1304,6 +1308,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ast::IntTy::I16 => self.types.i16, ast::IntTy::I32 => self.types.i32, ast::IntTy::I64 => self.types.i64, + ast::IntTy::I128 => self.types.i128, } } @@ -1314,6 +1319,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ast::UintTy::U16 => self.types.u16, ast::UintTy::U32 => self.types.u32, ast::UintTy::U64 => self.types.u64, + ast::UintTy::U128 => self.types.u128, } } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index ebac30c8e506e..67856cecad1ee 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -20,6 +20,7 @@ use ty::{self, Ty, TyCtxt, TypeFoldable}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; use syntax_pos::DUMMY_SP; +use rustc_i128::{i128, u128}; use std::cmp; use std::fmt; @@ -35,6 +36,7 @@ pub struct TargetDataLayout { pub i16_align: Align, pub i32_align: Align, pub i64_align: Align, + pub i128_align: Align, pub f32_align: Align, pub f64_align: Align, pub pointer_size: Size, @@ -55,6 +57,8 @@ impl Default for TargetDataLayout { i16_align: Align::from_bits(16, 16).unwrap(), i32_align: Align::from_bits(32, 32).unwrap(), i64_align: Align::from_bits(32, 64).unwrap(), + // FIXME: i128 is correct? + i128_align: Align::from_bits(64, 128).unwrap(), f32_align: Align::from_bits(32, 32).unwrap(), f64_align: Align::from_bits(64, 64).unwrap(), pointer_size: Size::from_bits(64), @@ -117,6 +121,7 @@ impl TargetDataLayout { Ok(16) => &mut dl.i16_align, Ok(32) => &mut dl.i32_align, Ok(64) => &mut dl.i64_align, + Ok(128) => &mut dl.i128_align, Ok(_) => continue, Err(_) => { size(&s[1..], "i"); // For the user error. @@ -325,7 +330,8 @@ pub enum Integer { I8, I16, I32, - I64 + I64, + I128, } impl Integer { @@ -368,22 +374,24 @@ impl Integer { /// Find the smallest Integer type which can represent the signed value. pub fn fit_signed(x: i64) -> Integer { match x { - -0x0000_0001...0x0000_0000 => I1, - -0x0000_0080...0x0000_007f => I8, - -0x0000_8000...0x0000_7fff => I16, - -0x8000_0000...0x7fff_ffff => I32, - _ => I64 + -0x0000_0000_0000_0001...0x0000_0000_0000_0000 => I1, + -0x0000_0000_0000_0080...0x0000_0000_0000_007f => I8, + -0x0000_0000_0000_8000...0x0000_0000_0000_7fff => I16, + -0x0000_0000_8000_0000...0x0000_0000_7fff_ffff => I32, + -0x8000_0000_0000_0000...0x7fff_ffff_ffff_ffff => I64, + _ => I128 } } /// Find the smallest Integer type which can represent the unsigned value. pub fn fit_unsigned(x: u64) -> Integer { match x { - 0...0x0000_0001 => I1, - 0...0x0000_00ff => I8, - 0...0x0000_ffff => I16, - 0...0xffff_ffff => I32, - _ => I64 + 0...0x0000_0000_0000_0001 => I1, + 0...0x0000_0000_0000_00ff => I8, + 0...0x0000_0000_0000_ffff => I16, + 0...0x0000_0000_ffff_ffff => I32, + 0...0xffff_ffff_ffff_ffff => I64, + _ => I128, } } @@ -406,6 +414,7 @@ impl Integer { attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16, attr::SignedInt(IntTy::I32) | attr::UnsignedInt(UintTy::U32) => I32, attr::SignedInt(IntTy::I64) | attr::UnsignedInt(UintTy::U64) => I64, + attr::SignedInt(IntTy::I128) | attr::UnsignedInt(UintTy::U128) => I128, attr::SignedInt(IntTy::Is) | attr::UnsignedInt(UintTy::Us) => { dl.ptr_sized_integer() } @@ -486,6 +495,7 @@ impl Primitive { Int(I16) => Size::from_bits(16), Int(I32) | F32 => Size::from_bits(32), Int(I64) | F64 => Size::from_bits(64), + Int(I128) => Size::from_bits(128), Pointer => dl.pointer_size } } @@ -497,6 +507,7 @@ impl Primitive { Int(I16) => dl.i16_align, Int(I32) => dl.i32_align, Int(I64) => dl.i64_align, + Int(I128) => dl.i128_align, F32 => dl.f32_align, F64 => dl.f64_align, Pointer => dl.pointer_align @@ -1175,19 +1186,23 @@ impl<'a, 'gcx, 'tcx> Layout { if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) { // All bodies empty -> intlike - let (mut min, mut max, mut non_zero) = (i64::MAX, i64::MIN, true); + let (mut min, mut max, mut non_zero) = (i128::max_value(), i128::min_value(), true); for v in &def.variants { - let x = v.disr_val.to_u64_unchecked() as i64; + let x = v.disr_val.to_u128_unchecked() as i128; if x == 0 { non_zero = false; } if x < min { min = x; } if x > max { max = x; } } - let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..], min, max); + // FIXME: should take i128? + let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..], + min as i64, + max as i64); return success(CEnum { discr: discr, signed: signed, non_zero: non_zero, + // FIXME: should be u128? min: min as u64, max: max as u64 }); @@ -1232,7 +1247,7 @@ impl<'a, 'gcx, 'tcx> Layout { // non-empty body, explicit discriminants should have // been rejected by a checker before this point. for (i, v) in def.variants.iter().enumerate() { - if i as u64 != v.disr_val.to_u64_unchecked() { + if i as u128 != v.disr_val.to_u128_unchecked() { bug!("non-C-like enum {} with specified discriminants", tcx.item_path_str(def.did)); } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index b4ac6b9d2502e..0b45ff94a9312 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -51,11 +51,13 @@ impl IntTypeExt for attr::IntType { SignedInt(ast::IntTy::I16) => tcx.types.i16, SignedInt(ast::IntTy::I32) => tcx.types.i32, SignedInt(ast::IntTy::I64) => tcx.types.i64, + SignedInt(ast::IntTy::I128) => tcx.types.i128, SignedInt(ast::IntTy::Is) => tcx.types.isize, UnsignedInt(ast::UintTy::U8) => tcx.types.u8, UnsignedInt(ast::UintTy::U16) => tcx.types.u16, UnsignedInt(ast::UintTy::U32) => tcx.types.u32, UnsignedInt(ast::UintTy::U64) => tcx.types.u64, + UnsignedInt(ast::UintTy::U128) => tcx.types.u128, UnsignedInt(ast::UintTy::Us) => tcx.types.usize, } } @@ -66,6 +68,7 @@ impl IntTypeExt for attr::IntType { SignedInt(ast::IntTy::I16) => ConstInt::I16(0), SignedInt(ast::IntTy::I32) => ConstInt::I32(0), SignedInt(ast::IntTy::I64) => ConstInt::I64(0), + SignedInt(ast::IntTy::I128) => ConstInt::I128(0), SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type { ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16(0)), ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)), @@ -76,6 +79,7 @@ impl IntTypeExt for attr::IntType { UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0), UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0), UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0), + UnsignedInt(ast::UintTy::U128) => ConstInt::U128(0), UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type { ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(0)), ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)), @@ -91,11 +95,13 @@ impl IntTypeExt for attr::IntType { (SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {}, (SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {}, (SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {}, + (SignedInt(ast::IntTy::I128), ConstInt::I128(_)) => {}, (SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {}, (UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {}, (UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {}, (UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {}, (UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {}, + (UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) => {}, (UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {}, _ => bug!("disr type mismatch: {:?} vs {:?}", self, val), } diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 0e5cbce8639be..7148e181bbd6d 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -19,4 +19,5 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } graphviz = { path = "../libgraphviz" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_pos = { path = "../libsyntax_pos" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index e8e7a2eb7ede0..c736b4865e738 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -43,6 +43,8 @@ use std::cmp::Ordering; use rustc_const_math::*; use rustc_errors::DiagnosticBuilder; +use rustc_i128::{i128, u128}; + macro_rules! math { ($e:expr, $op:expr) => { match $op { @@ -588,38 +590,43 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let hir::ExprLit(ref lit) = inner.node { use syntax::ast::*; use syntax::ast::LitIntType::*; - const I8_OVERFLOW: u64 = ::std::i8::MAX as u64 + 1; - const I16_OVERFLOW: u64 = ::std::i16::MAX as u64 + 1; - const I32_OVERFLOW: u64 = ::std::i32::MAX as u64 + 1; - const I64_OVERFLOW: u64 = ::std::i64::MAX as u64 + 1; + const I8_OVERFLOW: u128 = i8::max_value() as u128 + 1; + const I16_OVERFLOW: u128 = i16::max_value() as u128 + 1; + const I32_OVERFLOW: u128 = i32::max_value() as u128 + 1; + const I64_OVERFLOW: u128 = i64::max_value() as u128 + 1; + const I128_OVERFLOW: u128 = i128::max_value() as u128 + 1; match (&lit.node, ety.map(|t| &t.sty)) { (&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) | (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => { - return Ok(Integral(I8(::std::i8::MIN))) + return Ok(Integral(I8(i8::min_value()))) }, (&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) | (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => { - return Ok(Integral(I16(::std::i16::MIN))) + return Ok(Integral(I16(i16::min_value()))) }, (&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) | (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => { - return Ok(Integral(I32(::std::i32::MIN))) + return Ok(Integral(I32(i32::min_value()))) }, (&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) | (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => { - return Ok(Integral(I64(::std::i64::MIN))) + return Ok(Integral(I64(i64::min_value()))) + }, + (&LitKind::Int(I128_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I128))) | + (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => { + return Ok(Integral(I128(i128::min_value()))) }, (&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) | (&LitKind::Int(n, Signed(IntTy::Is)), _) => { match tcx.sess.target.int_type { IntTy::I16 => if n == I16_OVERFLOW { - return Ok(Integral(Isize(Is16(::std::i16::MIN)))); + return Ok(Integral(Isize(Is16(i16::min_value())))); }, IntTy::I32 => if n == I32_OVERFLOW { - return Ok(Integral(Isize(Is32(::std::i32::MIN)))); + return Ok(Integral(Isize(Is32(i32::min_value())))); }, IntTy::I64 => if n == I64_OVERFLOW { - return Ok(Integral(Isize(Is64(::std::i64::MIN)))); + return Ok(Integral(Isize(Is64(i64::min_value())))); }, _ => bug!(), } @@ -973,26 +980,30 @@ fn infer<'a, 'tcx>(i: ConstInt, (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result), (&ty::TyInt(IntTy::I32), result @ I32(_)) => Ok(result), (&ty::TyInt(IntTy::I64), result @ I64(_)) => Ok(result), + (&ty::TyInt(IntTy::I128), result @ I128(_)) => Ok(result), (&ty::TyInt(IntTy::Is), result @ Isize(_)) => Ok(result), (&ty::TyUint(UintTy::U8), result @ U8(_)) => Ok(result), (&ty::TyUint(UintTy::U16), result @ U16(_)) => Ok(result), (&ty::TyUint(UintTy::U32), result @ U32(_)) => Ok(result), (&ty::TyUint(UintTy::U64), result @ U64(_)) => Ok(result), + (&ty::TyUint(UintTy::U128), result @ U128(_)) => Ok(result), (&ty::TyUint(UintTy::Us), result @ Usize(_)) => Ok(result), - (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i64 as i8)), - (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i64 as i16)), - (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i64 as i32)), - (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i64)), + (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i128 as i8)), + (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i128 as i16)), + (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i128 as i32)), + (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i128 as i64)), + (&ty::TyInt(IntTy::I128), Infer(i)) => Ok(I128(i as i128)), (&ty::TyInt(IntTy::Is), Infer(i)) => { - Ok(Isize(ConstIsize::new_truncating(i as i64, tcx.sess.target.int_type))) + Ok(Isize(ConstIsize::new_truncating(i as i128, tcx.sess.target.int_type))) }, (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)), (&ty::TyInt(IntTy::I16), InferSigned(i)) => Ok(I16(i as i16)), (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)), - (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i)), + (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i as i64)), + (&ty::TyInt(IntTy::I128), InferSigned(i)) => Ok(I128(i)), (&ty::TyInt(IntTy::Is), InferSigned(i)) => { Ok(Isize(ConstIsize::new_truncating(i, tcx.sess.target.int_type))) }, @@ -1000,7 +1011,8 @@ fn infer<'a, 'tcx>(i: ConstInt, (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)), (&ty::TyUint(UintTy::U16), Infer(i)) => Ok(U16(i as u16)), (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)), - (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i)), + (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i as u64)), + (&ty::TyUint(UintTy::U128), Infer(i)) => Ok(U128(i)), (&ty::TyUint(UintTy::Us), Infer(i)) => { Ok(Usize(ConstUsize::new_truncating(i, tcx.sess.target.uint_type))) }, @@ -1071,21 +1083,23 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>( } fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult { - let v = val.to_u64_unchecked(); + let v = val.to_u128_unchecked(); match ty.sty { ty::TyBool if v == 0 => Ok(Bool(false)), ty::TyBool if v == 1 => Ok(Bool(true)), - ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i64 as i8))), - ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i64 as i16))), - ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i64 as i32))), - ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i64))), + ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))), + ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))), + ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))), + ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))), + ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))), ty::TyInt(ast::IntTy::Is) => { - Ok(Integral(Isize(ConstIsize::new_truncating(v as i64, tcx.sess.target.int_type)))) + Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.int_type)))) }, ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))), ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))), ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))), - ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v))), + ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))), + ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))), ty::TyUint(ast::UintTy::Us) => { Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type)))) }, @@ -1115,13 +1129,13 @@ fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match ty.sty { ty::TyInt(_) | ty::TyUint(_) => { let i = match val { - F32(f) if f >= 0.0 => Infer(f as u64), + F32(f) if f >= 0.0 => Infer(f as u128), FInfer { f64: f, .. } | - F64(f) if f >= 0.0 => Infer(f as u64), + F64(f) if f >= 0.0 => Infer(f as u128), - F32(f) => InferSigned(f as i64), + F32(f) => InferSigned(f as i128), FInfer { f64: f, .. } | - F64(f) => InferSigned(f as i64) + F64(f) => InferSigned(f as i128) }; if let (InferSigned(_), &ty::TyUint(_)) = (i, &ty.sty) { @@ -1145,9 +1159,9 @@ fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult { match val { Integral(i) => cast_const_int(tcx, i, ty), - Bool(b) => cast_const_int(tcx, Infer(b as u64), ty), + Bool(b) => cast_const_int(tcx, Infer(b as u128), ty), Float(f) => cast_const_float(tcx, f, ty), - Char(c) => cast_const_int(tcx, Infer(c as u64), ty), + Char(c) => cast_const_int(tcx, Infer(c as u128), ty), Function(_) => Err(UnimplementedConstVal("casting fn pointers")), ByteStr(b) => match ty.sty { ty::TyRawPtr(_) => { @@ -1185,28 +1199,29 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind, LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())), LitKind::Byte(n) => Ok(Integral(U8(n))), LitKind::Int(n, Signed(ity)) => { - infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral) + infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral) }, + // FIXME: this should become u128. LitKind::Int(n, Unsuffixed) => { match ty_hint.map(|t| &t.sty) { Some(&ty::TyInt(ity)) => { - infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral) + infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral) }, Some(&ty::TyUint(uty)) => { - infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral) + infer(Infer(n as u128), tcx, &ty::TyUint(uty)).map(Integral) }, - None => Ok(Integral(Infer(n))), + None => Ok(Integral(Infer(n as u128))), Some(&ty::TyAdt(adt, _)) => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); - infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral) + infer(Infer(n as u128), tcx, &int_ty.to_ty(tcx).sty).map(Integral) }, Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit), } }, LitKind::Int(n, Unsigned(ity)) => { - infer(Infer(n), tcx, &ty::TyUint(ity)).map(Integral) + infer(Infer(n as u128), tcx, &ty::TyUint(ity)).map(Integral) }, LitKind::Float(n, fty) => { diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 7a6cc4937232d..67b4efdbd1f44 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -28,6 +28,7 @@ #![feature(slice_patterns)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(const_fn)] extern crate arena; #[macro_use] extern crate syntax; @@ -41,6 +42,8 @@ extern crate graphviz; extern crate syntax_pos; extern crate serialize as rustc_serialize; // used by deriving +extern crate rustc_i128; + // NB: This module needs to be declared first so diagnostics are // registered before they are used. pub mod diagnostics; diff --git a/src/librustc_const_math/Cargo.toml b/src/librustc_const_math/Cargo.toml index 10aadabe22ed7..3d7a4865e45af 100644 --- a/src/librustc_const_math/Cargo.toml +++ b/src/librustc_const_math/Cargo.toml @@ -12,3 +12,4 @@ crate-type = ["dylib"] log = { path = "../liblog" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_const_math/err.rs b/src/librustc_const_math/err.rs index e2e30ef026c2f..1e9c2badd6860 100644 --- a/src/librustc_const_math/err.rs +++ b/src/librustc_const_math/err.rs @@ -74,11 +74,13 @@ impl ConstMathErr { ULitOutOfRange(ast::UintTy::U16) => "literal out of range for u16", ULitOutOfRange(ast::UintTy::U32) => "literal out of range for u32", ULitOutOfRange(ast::UintTy::U64) => "literal out of range for u64", + ULitOutOfRange(ast::UintTy::U128) => "literal out of range for u128", ULitOutOfRange(ast::UintTy::Us) => "literal out of range for usize", LitOutOfRange(ast::IntTy::I8) => "literal out of range for i8", LitOutOfRange(ast::IntTy::I16) => "literal out of range for i16", LitOutOfRange(ast::IntTy::I32) => "literal out of range for i32", LitOutOfRange(ast::IntTy::I64) => "literal out of range for i64", + LitOutOfRange(ast::IntTy::I128) => "literal out of range for i128", LitOutOfRange(ast::IntTy::Is) => "literal out of range for isize", } } diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs index 28a5887847252..a1b6ecf153a6e 100644 --- a/src/librustc_const_math/int.rs +++ b/src/librustc_const_math/int.rs @@ -11,6 +11,7 @@ use std::cmp::Ordering; use syntax::attr::IntType; use syntax::ast::{IntTy, UintTy}; +use rustc_i128::{i128, u128}; use super::is::*; use super::us::*; @@ -22,42 +23,65 @@ pub enum ConstInt { I16(i16), I32(i32), I64(i64), + I128(i128), Isize(ConstIsize), U8(u8), U16(u16), U32(u32), U64(u64), + U128(u128), Usize(ConstUsize), - Infer(u64), - InferSigned(i64), + // FIXME: i128 + Infer(u128), + InferSigned(i128), } pub use self::ConstInt::*; macro_rules! bounds { - ($($t:ident $min:ident $max:ident)*) => { - mod as_u64 { - $( - #[allow(dead_code)] - pub const $min: u64 = ::std::$t::MIN as u64; - #[allow(dead_code)] - pub const $max: u64 = ::std::$t::MAX as u64; - )* - } - mod as_i64 { - $( - #[allow(dead_code)] - pub const $min: i64 = ::std::$t::MIN as i64; - #[allow(dead_code)] - pub const $max: i64 = ::std::$t::MAX as i64; - )* - } + ($ct: ty, $($t:ident $min:ident $max:ident)*) => { + $( + pub const $min: $ct = $t::min_value() as $ct; + pub const $max: $ct = $t::max_value() as $ct; + )* + }; + ($ct: ty: $min_val: expr, $($t:ident $min:ident $max:ident)*) => { + $( + pub const $min: $ct = $min_val; + pub const $max: $ct = $t::max_value() as $ct; + )* + } +} + +mod ubounds { + #![allow(dead_code)] + use rustc_i128::{u128, i128}; + // FIXME: min are problably all wrong for signed here. + bounds!{u128: 0, + i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX + u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX u128 U128MIN U128MAX + isize IMIN IMAX usize UMIN UMAX } } -bounds!{ - i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX isize IMIN IMAX - u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX usize UMIN UMAX +mod ibounds { + #![allow(dead_code)] + use rustc_i128::i128; + #[cfg(stage0)] + pub const U64MIN: i128 = 0; + #[cfg(stage0)] + pub const U64MAX: i128 = i128::max_value(); + #[cfg(not(stage0))] + bounds!(i128, u64 U64MIN U64MAX); + + pub const U128MIN: i128 = 0; + pub const U128MAX: i128 = i128::max_value(); + + bounds!{i128, + i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX + u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX + isize IMIN IMAX usize UMIN UMAX + } } impl ConstInt { @@ -68,46 +92,54 @@ impl ConstInt { (InferSigned(_), InferSigned(_)) | (Infer(_), Infer(_)) => self, // no inference possible // kindof wrong, you could have had values > I64MAX during computation of a - (Infer(a @ 0...as_u64::I64MAX), InferSigned(_)) => InferSigned(a as i64), + (Infer(a @ 0...ubounds::I64MAX), InferSigned(_)) => InferSigned(a as i128), (Infer(_), InferSigned(_)) => return Err(ConstMathErr::NotInRange), (_, InferSigned(_)) | (_, Infer(_)) => return other.infer(self).map(|(b, a)| (a, b)), - (Infer(a @ 0...as_u64::I8MAX), I8(_)) => I8(a as i64 as i8), - (Infer(a @ 0...as_u64::I16MAX), I16(_)) => I16(a as i64 as i16), - (Infer(a @ 0...as_u64::I32MAX), I32(_)) => I32(a as i64 as i32), - (Infer(a @ 0...as_u64::I64MAX), I64(_)) => I64(a as i64), - (Infer(a @ 0...as_u64::I16MAX), Isize(Is16(_))) => Isize(Is16(a as i64 as i16)), - (Infer(a @ 0...as_u64::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)), - (Infer(a @ 0...as_u64::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)), - (Infer(a @ 0...as_u64::U8MAX), U8(_)) => U8(a as u8), - (Infer(a @ 0...as_u64::U16MAX), U16(_)) => U16(a as u16), - (Infer(a @ 0...as_u64::U32MAX), U32(_)) => U32(a as u32), - (Infer(a), U64(_)) => U64(a), - (Infer(a @ 0...as_u64::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)), - (Infer(a @ 0...as_u64::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)), - (Infer(a), Usize(Us64(_))) => Usize(Us64(a)), + (Infer(a @ 0...ubounds::I8MAX), I8(_)) => I8(a as i64 as i8), + (Infer(a @ 0...ubounds::I16MAX), I16(_)) => I16(a as i64 as i16), + (Infer(a @ 0...ubounds::I32MAX), I32(_)) => I32(a as i64 as i32), + (Infer(a @ 0...ubounds::I64MAX), I64(_)) => I64(a as i64), + (Infer(a @ 0...ubounds::I128MAX), I128(_)) => I128(a as i128), + (Infer(a @ 0...ubounds::I16MAX), Isize(Is16(_))) => Isize(Is16(a as i64 as i16)), + (Infer(a @ 0...ubounds::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)), + (Infer(a @ 0...ubounds::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)), + (Infer(a @ 0...ubounds::U8MAX), U8(_)) => U8(a as u8), + (Infer(a @ 0...ubounds::U16MAX), U16(_)) => U16(a as u16), + (Infer(a @ 0...ubounds::U32MAX), U32(_)) => U32(a as u32), + (Infer(a @ 0...ubounds::U64MAX), U64(_)) => U64(a as u64), + (Infer(a @ 0...ubounds::U128MAX), U128(_)) => U128(a as u128), + (Infer(a @ 0...ubounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)), + (Infer(a @ 0...ubounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)), + (Infer(a @ 0...ubounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)), (Infer(_), _) => return Err(ConstMathErr::NotInRange), - (InferSigned(a @ as_i64::I8MIN...as_i64::I8MAX), I8(_)) => I8(a as i8), - (InferSigned(a @ as_i64::I16MIN...as_i64::I16MAX), I16(_)) => I16(a as i16), - (InferSigned(a @ as_i64::I32MIN...as_i64::I32MAX), I32(_)) => I32(a as i32), - (InferSigned(a), I64(_)) => I64(a), - (InferSigned(a @ as_i64::I16MIN...as_i64::I16MAX), Isize(Is16(_))) => { + (InferSigned(a @ ibounds::I8MIN...ibounds::I8MAX), I8(_)) => I8(a as i8), + (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), I16(_)) => I16(a as i16), + (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), I32(_)) => I32(a as i32), + (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), I64(_)) => I64(a as i64), + (InferSigned(a @ ibounds::I128MIN...ibounds::I128MAX), I128(_)) => I128(a as i128), + (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), Isize(Is16(_))) => { Isize(Is16(a as i16)) }, - (InferSigned(a @ as_i64::I32MIN...as_i64::I32MAX), Isize(Is32(_))) => { + (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), Isize(Is32(_))) => { Isize(Is32(a as i32)) }, - (InferSigned(a), Isize(Is64(_))) => Isize(Is64(a)), - (InferSigned(a @ 0...as_i64::U8MAX), U8(_)) => U8(a as u8), - (InferSigned(a @ 0...as_i64::U16MAX), U16(_)) => U16(a as u16), - (InferSigned(a @ 0...as_i64::U32MAX), U32(_)) => U32(a as u32), - (InferSigned(a @ 0...as_i64::I64MAX), U64(_)) => U64(a as u64), - (InferSigned(a @ 0...as_i64::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)), - (InferSigned(a @ 0...as_i64::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)), - (InferSigned(a @ 0...as_i64::I64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)), + (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), Isize(Is64(_))) => { + Isize(Is64(a as i64)) + }, + (InferSigned(a @ 0...ibounds::U8MAX), U8(_)) => U8(a as u8), + (InferSigned(a @ 0...ibounds::U16MAX), U16(_)) => U16(a as u16), + (InferSigned(a @ 0...ibounds::U32MAX), U32(_)) => U32(a as u32), + // SNAP: replace with U64MAX + (InferSigned(a @ 0...ibounds::I64MAX), U64(_)) => U64(a as u64), + (InferSigned(a @ 0...ibounds::I128MAX), U128(_)) => U128(a as u128), + (InferSigned(a @ 0...ibounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)), + (InferSigned(a @ 0...ibounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)), + // SNAP: replace with U64MAX + (InferSigned(a @ 0...ibounds::I64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)), (InferSigned(_), _) => return Err(ConstMathErr::NotInRange), _ => self, // already known types }; @@ -119,28 +151,34 @@ impl ConstInt { match self { Infer(i) => Infer(i), InferSigned(i) if i < 0 => InferSigned(i), - I8(i) if i < 0 => InferSigned(i as i64), - I16(i) if i < 0 => InferSigned(i as i64), - I32(i) if i < 0 => InferSigned(i as i64), - I64(i) if i < 0 => InferSigned(i as i64), - Isize(Is16(i)) if i < 0 => InferSigned(i as i64), - Isize(Is32(i)) if i < 0 => InferSigned(i as i64), - Isize(Is64(i)) if i < 0 => InferSigned(i as i64), - InferSigned(i) => Infer(i as u64), - I8(i) => Infer(i as u64), - I16(i) => Infer(i as u64), - I32(i) => Infer(i as u64), - I64(i) => Infer(i as u64), - Isize(Is16(i)) => Infer(i as u64), - Isize(Is32(i)) => Infer(i as u64), - Isize(Is64(i)) => Infer(i as u64), - U8(i) => Infer(i as u64), - U16(i) => Infer(i as u64), - U32(i) => Infer(i as u64), - U64(i) => Infer(i as u64), - Usize(Us16(i)) => Infer(i as u64), - Usize(Us32(i)) => Infer(i as u64), - Usize(Us64(i)) => Infer(i), + I8(i) if i < 0 => InferSigned(i as i128), + I16(i) if i < 0 => InferSigned(i as i128), + I32(i) if i < 0 => InferSigned(i as i128), + I64(i) if i < 0 => InferSigned(i as i128), + // FIXME: 1128, compare with i128 + I128(i) if i < 0 => InferSigned(i as i128), + Isize(Is16(i)) if i < 0 => InferSigned(i as i128), + Isize(Is32(i)) if i < 0 => InferSigned(i as i128), + Isize(Is64(i)) if i < 0 => InferSigned(i as i128), + InferSigned(i) => Infer(i as u128), + I8(i) => Infer(i as u128), + I16(i) => Infer(i as u128), + I32(i) => Infer(i as u128), + I64(i) => Infer(i as u128), + // FIXME: i128 + I128(i) => Infer(i as u128), + Isize(Is16(i)) => Infer(i as u128), + Isize(Is32(i)) => Infer(i as u128), + Isize(Is64(i)) => Infer(i as u128), + U8(i) => Infer(i as u128), + U16(i) => Infer(i as u128), + U32(i) => Infer(i as u128), + U64(i) => Infer(i as u128), + // FIXME: i128 + U128(i) => Infer(i as u128), + Usize(Us16(i)) => Infer(i as u128), + Usize(Us32(i)) => Infer(i as u128), + Usize(Us64(i)) => Infer(i as u128), } } @@ -153,67 +191,66 @@ impl ConstInt { I16(_) => "i16", I32(_) => "i32", I64(_) => "i64", + I128(_) => "i128", Isize(_) => "isize", U8(_) => "u8", U16(_) => "u16", U32(_) => "u32", U64(_) => "u64", + U128(_) => "u128", Usize(_) => "usize", } } - /// Erases the type and returns a u64. - /// This is not the same as `-5i8 as u64` but as `-5i8 as i64 as u64` - pub fn to_u64_unchecked(self) -> u64 { + /// Erases the type and returns a u128. + /// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128` + pub fn to_u128_unchecked(self) -> u128 { match self.erase_type() { ConstInt::Infer(i) => i, - ConstInt::InferSigned(i) => i as u64, + ConstInt::InferSigned(i) => i as u128, _ => unreachable!(), } } /// Converts the value to a `u32` if it's in the range 0...std::u32::MAX pub fn to_u32(&self) -> Option { - match *self { - I8(v) if v >= 0 => Some(v as u32), - I16(v) if v >= 0 => Some(v as u32), - I32(v) if v >= 0 => Some(v as u32), - InferSigned(v) - | Isize(Is64(v)) - | I64(v) if v >= 0 && v <= ::std::u32::MAX as i64 => Some(v as u32), - Isize(Is32(v)) if v >= 0 => Some(v as u32), - Isize(Is16(v)) if v >= 0 => Some(v as u32), - U8(v) => Some(v as u32), - U16(v) => Some(v as u32), - U32(v) => Some(v), - Infer(v) - | Usize(Us64(v)) - | U64(v) if v <= ::std::u32::MAX as u64 => Some(v as u32), - Usize(Us32(v)) => Some(v), - Usize(Us16(v)) => Some(v as u32), - _ => None, - } + self.to_u128().and_then(|v| if v <= u32::max_value() as u128 { + Some(v as u32) + } else { + None + }) } - /// Converts the value to a `u64` if it's >= 0 + /// Converts the value to a `u64` if it's in the range 0...std::u64::MAX pub fn to_u64(&self) -> Option { + self.to_u128().and_then(|v| if v <= u64::max_value() as u128 { + Some(v as u64) + } else { + None + }) + } + + /// Converts the value to a `u128` if it's in the range 0...std::u128::MAX + pub fn to_u128(&self) -> Option { match *self { Infer(v) => Some(v), - InferSigned(v) if v >= 0 => Some(v as u64), - I8(v) if v >= 0 => Some(v as u64), - I16(v) if v >= 0 => Some(v as u64), - I32(v) if v >= 0 => Some(v as u64), - I64(v) if v >= 0 => Some(v as u64), - Isize(Is16(v)) if v >= 0 => Some(v as u64), - Isize(Is32(v)) if v >= 0 => Some(v as u64), - Isize(Is64(v)) if v >= 0 => Some(v as u64), - U8(v) => Some(v as u64), - U16(v) => Some(v as u64), - U32(v) => Some(v as u64), - U64(v) => Some(v), - Usize(Us16(v)) => Some(v as u64), - Usize(Us32(v)) => Some(v as u64), - Usize(Us64(v)) => Some(v), + InferSigned(v) if v >= 0 => Some(v as u128), + I8(v) if v >= 0 => Some(v as u128), + I16(v) if v >= 0 => Some(v as u128), + I32(v) if v >= 0 => Some(v as u128), + I64(v) if v >= 0 => Some(v as u128), + I128(v) if v >= 0 => Some(v as u128), + Isize(Is16(v)) if v >= 0 => Some(v as u128), + Isize(Is32(v)) if v >= 0 => Some(v as u128), + Isize(Is64(v)) if v >= 0 => Some(v as u128), + U8(v) => Some(v as u128), + U16(v) => Some(v as u128), + U32(v) => Some(v as u128), + U64(v) => Some(v as u128), + U128(v) => Some(v as u128), + Usize(Us16(v)) => Some(v as u128), + Usize(Us32(v)) => Some(v as u128), + Usize(Us64(v)) => Some(v as u128), _ => None, } } @@ -224,6 +261,7 @@ impl ConstInt { I16(v) => v < 0, I32(v) => v < 0, I64(v) => v < 0, + I128(v) => v < 0, Isize(Is16(v)) => v < 0, Isize(Is32(v)) => v < 0, Isize(Is64(v)) => v < 0, @@ -239,6 +277,7 @@ impl ConstInt { (I16(a), I16(b)) => Ok(a.cmp(&b)), (I32(a), I32(b)) => Ok(a.cmp(&b)), (I64(a), I64(b)) => Ok(a.cmp(&b)), + (I128(a), I128(b)) => Ok(a.cmp(&b)), (Isize(Is16(a)), Isize(Is16(b))) => Ok(a.cmp(&b)), (Isize(Is32(a)), Isize(Is32(b))) => Ok(a.cmp(&b)), (Isize(Is64(a)), Isize(Is64(b))) => Ok(a.cmp(&b)), @@ -246,6 +285,7 @@ impl ConstInt { (U16(a), U16(b)) => Ok(a.cmp(&b)), (U32(a), U32(b)) => Ok(a.cmp(&b)), (U64(a), U64(b)) => Ok(a.cmp(&b)), + (U128(a), U128(b)) => Ok(a.cmp(&b)), (Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)), (Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)), (Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)), @@ -265,6 +305,7 @@ impl ConstInt { ConstInt::I16(i) => ConstInt::I16(add1!(i)), ConstInt::I32(i) => ConstInt::I32(add1!(i)), ConstInt::I64(i) => ConstInt::I64(add1!(i)), + ConstInt::I128(i) => ConstInt::I128(add1!(i)), ConstInt::Isize(ConstIsize::Is16(i)) => ConstInt::Isize(ConstIsize::Is16(add1!(i))), ConstInt::Isize(ConstIsize::Is32(i)) => ConstInt::Isize(ConstIsize::Is32(add1!(i))), ConstInt::Isize(ConstIsize::Is64(i)) => ConstInt::Isize(ConstIsize::Is64(add1!(i))), @@ -272,6 +313,7 @@ impl ConstInt { ConstInt::U16(i) => ConstInt::U16(add1!(i)), ConstInt::U32(i) => ConstInt::U32(add1!(i)), ConstInt::U64(i) => ConstInt::U64(add1!(i)), + ConstInt::U128(i) => ConstInt::U128(add1!(i)), ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))), ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))), ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))), @@ -285,11 +327,13 @@ impl ConstInt { ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)), ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)), ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)), + ConstInt::I128(_) => Some(IntType::SignedInt(IntTy::I128)), ConstInt::Isize(_) => Some(IntType::SignedInt(IntTy::Is)), ConstInt::U8(_) => Some(IntType::UnsignedInt(UintTy::U8)), ConstInt::U16(_) => Some(IntType::UnsignedInt(UintTy::U16)), ConstInt::U32(_) => Some(IntType::UnsignedInt(UintTy::U32)), ConstInt::U64(_) => Some(IntType::UnsignedInt(UintTy::U64)), + ConstInt::U128(_) => Some(IntType::UnsignedInt(UintTy::U128)), ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)), _ => None, } @@ -317,6 +361,7 @@ impl ::std::fmt::Display for ConstInt { I16(i) => write!(fmt, "{}i16", i), I32(i) => write!(fmt, "{}i32", i), I64(i) => write!(fmt, "{}i64", i), + I128(i) => write!(fmt, "{}i128", i), Isize(ConstIsize::Is64(i)) => write!(fmt, "{}isize", i), Isize(ConstIsize::Is32(i)) => write!(fmt, "{}isize", i), Isize(ConstIsize::Is16(i)) => write!(fmt, "{}isize", i), @@ -324,6 +369,7 @@ impl ::std::fmt::Display for ConstInt { U16(i) => write!(fmt, "{}u16", i), U32(i) => write!(fmt, "{}u32", i), U64(i) => write!(fmt, "{}u64", i), + U128(i) => write!(fmt, "{}u128", i), Usize(ConstUsize::Us64(i)) => write!(fmt, "{}usize", i), Usize(ConstUsize::Us32(i)) => write!(fmt, "{}usize", i), Usize(ConstUsize::Us16(i)) => write!(fmt, "{}usize", i), @@ -351,6 +397,7 @@ macro_rules! impl_binop { (I16(a), I16(b)) => a.$checked_func(b).map(I16), (I32(a), I32(b)) => a.$checked_func(b).map(I32), (I64(a), I64(b)) => a.$checked_func(b).map(I64), + (I128(a), I128(b)) => a.$checked_func(b).map(I128), (Isize(Is16(a)), Isize(Is16(b))) => a.$checked_func(b).map(Is16).map(Isize), (Isize(Is32(a)), Isize(Is32(b))) => a.$checked_func(b).map(Is32).map(Isize), (Isize(Is64(a)), Isize(Is64(b))) => a.$checked_func(b).map(Is64).map(Isize), @@ -358,6 +405,7 @@ macro_rules! impl_binop { (U16(a), U16(b)) => a.$checked_func(b).map(U16), (U32(a), U32(b)) => a.$checked_func(b).map(U32), (U64(a), U64(b)) => a.$checked_func(b).map(U64), + (U128(a), U128(b)) => a.$checked_func(b).map(U128), (Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize), (Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize), (Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize), @@ -380,6 +428,7 @@ macro_rules! derive_binop { (I16(a), I16(b)) => Ok(I16(a.$func(b))), (I32(a), I32(b)) => Ok(I32(a.$func(b))), (I64(a), I64(b)) => Ok(I64(a.$func(b))), + (I128(a), I128(b)) => Ok(I128(a.$func(b))), (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a.$func(b)))), (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a.$func(b)))), (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a.$func(b)))), @@ -387,6 +436,7 @@ macro_rules! derive_binop { (U16(a), U16(b)) => Ok(U16(a.$func(b))), (U32(a), U32(b)) => Ok(U32(a.$func(b))), (U64(a), U64(b)) => Ok(U64(a.$func(b))), + (U128(a), U128(b)) => Ok(U128(a.$func(b))), (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))), (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))), (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))), @@ -406,6 +456,11 @@ derive_binop!(BitAnd, bitand); derive_binop!(BitOr, bitor); derive_binop!(BitXor, bitxor); +#[cfg(not(stage0))] +const I128_MIN: i128 = ::std::i128::MIN; +#[cfg(stage0)] +const I128_MIN: i128 = ::std::i64::MIN; + fn check_division( lhs: ConstInt, rhs: ConstInt, @@ -417,6 +472,7 @@ fn check_division( (I16(_), I16(0)) => Err(zerr), (I32(_), I32(0)) => Err(zerr), (I64(_), I64(0)) => Err(zerr), + (I128(_), I128(0)) => Err(zerr), (Isize(_), Isize(Is16(0))) => Err(zerr), (Isize(_), Isize(Is32(0))) => Err(zerr), (Isize(_), Isize(Is64(0))) => Err(zerr), @@ -426,6 +482,7 @@ fn check_division( (U16(_), U16(0)) => Err(zerr), (U32(_), U32(0)) => Err(zerr), (U64(_), U64(0)) => Err(zerr), + (U128(_), U128(0)) => Err(zerr), (Usize(_), Usize(Us16(0))) => Err(zerr), (Usize(_), Usize(Us32(0))) => Err(zerr), (Usize(_), Usize(Us64(0))) => Err(zerr), @@ -435,10 +492,11 @@ fn check_division( (I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)), (I32(::std::i32::MIN), I32(-1)) => Err(Overflow(op)), (I64(::std::i64::MIN), I64(-1)) => Err(Overflow(op)), + (I128(I128_MIN), I128(-1)) => Err(Overflow(op)), (Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)), (Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)), (Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)), - (InferSigned(::std::i64::MIN), InferSigned(-1)) => Err(Overflow(op)), + (InferSigned(I128_MIN), InferSigned(-1)) => Err(Overflow(op)), _ => Ok(()), } @@ -454,6 +512,7 @@ impl ::std::ops::Div for ConstInt { (I16(a), I16(b)) => Ok(I16(a/b)), (I32(a), I32(b)) => Ok(I32(a/b)), (I64(a), I64(b)) => Ok(I64(a/b)), + (I128(a), I128(b)) => Ok(I128(a/b)), (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))), (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))), (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))), @@ -463,6 +522,7 @@ impl ::std::ops::Div for ConstInt { (U16(a), U16(b)) => Ok(U16(a/b)), (U32(a), U32(b)) => Ok(U32(a/b)), (U64(a), U64(b)) => Ok(U64(a/b)), + (U128(a), U128(b)) => Ok(U128(a/b)), (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))), (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))), (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))), @@ -484,6 +544,7 @@ impl ::std::ops::Rem for ConstInt { (I16(a), I16(b)) => Ok(I16(a%b)), (I32(a), I32(b)) => Ok(I32(a%b)), (I64(a), I64(b)) => Ok(I64(a%b)), + (I128(a), I128(b)) => Ok(I128(a%b)), (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))), (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))), (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))), @@ -493,6 +554,7 @@ impl ::std::ops::Rem for ConstInt { (U16(a), U16(b)) => Ok(U16(a%b)), (U32(a), U32(b)) => Ok(U32(a%b)), (U64(a), U64(b)) => Ok(U64(a%b)), + (U128(a), U128(b)) => Ok(U128(a%b)), (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))), (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))), (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))), @@ -512,6 +574,7 @@ impl ::std::ops::Shl for ConstInt { I16(a) => Ok(I16(overflowing!(a.overflowing_shl(b), Op::Shl))), I32(a) => Ok(I32(overflowing!(a.overflowing_shl(b), Op::Shl))), I64(a) => Ok(I64(overflowing!(a.overflowing_shl(b), Op::Shl))), + I128(a) => Ok(I128(overflowing!(a.overflowing_shl(b), Op::Shl))), Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shl(b), Op::Shl)))), Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shl(b), Op::Shl)))), Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shl(b), Op::Shl)))), @@ -519,6 +582,7 @@ impl ::std::ops::Shl for ConstInt { U16(a) => Ok(U16(overflowing!(a.overflowing_shl(b), Op::Shl))), U32(a) => Ok(U32(overflowing!(a.overflowing_shl(b), Op::Shl))), U64(a) => Ok(U64(overflowing!(a.overflowing_shl(b), Op::Shl))), + U128(a) => Ok(U128(overflowing!(a.overflowing_shl(b), Op::Shl))), Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))), Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))), Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))), @@ -537,6 +601,7 @@ impl ::std::ops::Shr for ConstInt { I16(a) => Ok(I16(overflowing!(a.overflowing_shr(b), Op::Shr))), I32(a) => Ok(I32(overflowing!(a.overflowing_shr(b), Op::Shr))), I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shr))), + I128(a) => Ok(I128(overflowing!(a.overflowing_shr(b), Op::Shr))), Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shr(b), Op::Shr)))), Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shr(b), Op::Shr)))), Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shr(b), Op::Shr)))), @@ -544,6 +609,7 @@ impl ::std::ops::Shr for ConstInt { U16(a) => Ok(U16(overflowing!(a.overflowing_shr(b), Op::Shr))), U32(a) => Ok(U32(overflowing!(a.overflowing_shr(b), Op::Shr))), U64(a) => Ok(U64(overflowing!(a.overflowing_shr(b), Op::Shr))), + U128(a) => Ok(U128(overflowing!(a.overflowing_shr(b), Op::Shr))), Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))), Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))), Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))), @@ -561,22 +627,14 @@ impl ::std::ops::Neg for ConstInt { I16(a) => Ok(I16(overflowing!(a.overflowing_neg(), Op::Neg))), I32(a) => Ok(I32(overflowing!(a.overflowing_neg(), Op::Neg))), I64(a) => Ok(I64(overflowing!(a.overflowing_neg(), Op::Neg))), + I128(a) => Ok(I128(overflowing!(a.overflowing_neg(), Op::Neg))), Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_neg(), Op::Neg)))), Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_neg(), Op::Neg)))), Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_neg(), Op::Neg)))), - U8(0) => Ok(U8(0)), - U16(0) => Ok(U16(0)), - U32(0) => Ok(U32(0)), - U64(0) => Ok(U64(0)), - Usize(Us16(0)) => Ok(Usize(Us16(0))), - Usize(Us32(0)) => Ok(Usize(Us32(0))), - Usize(Us64(0)) => Ok(Usize(Us64(0))), - U8(_) => Err(UnsignedNegation), - U16(_) => Err(UnsignedNegation), - U32(_) => Err(UnsignedNegation), - U64(_) => Err(UnsignedNegation), - Usize(_) => Err(UnsignedNegation), - Infer(a @ 0...as_u64::I64MAX) => Ok(InferSigned(-(a as i64))), + a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) | + a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a), + U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation), + Infer(a @ 0...ubounds::I64MAX) => Ok(InferSigned(-(a as i128))), Infer(_) => Err(Overflow(Op::Neg)), InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))), } @@ -591,6 +649,7 @@ impl ::std::ops::Not for ConstInt { I16(a) => Ok(I16(!a)), I32(a) => Ok(I32(!a)), I64(a) => Ok(I64(!a)), + I128(a) => Ok(I128(!a)), Isize(Is16(a)) => Ok(Isize(Is16(!a))), Isize(Is32(a)) => Ok(Isize(Is32(!a))), Isize(Is64(a)) => Ok(Isize(Is64(!a))), @@ -598,6 +657,7 @@ impl ::std::ops::Not for ConstInt { U16(a) => Ok(U16(!a)), U32(a) => Ok(U32(!a)), U64(a) => Ok(U64(!a)), + U128(a) => Ok(U128(!a)), Usize(Us16(a)) => Ok(Usize(Us16(!a))), Usize(Us32(a)) => Ok(Usize(Us32(!a))), Usize(Us64(a)) => Ok(Usize(Us64(!a))), diff --git a/src/librustc_const_math/is.rs b/src/librustc_const_math/is.rs index ef92b628523e7..19ae0c91fc5f9 100644 --- a/src/librustc_const_math/is.rs +++ b/src/librustc_const_math/is.rs @@ -10,6 +10,7 @@ use syntax::ast; use super::err::*; +use rustc_i128::i128; /// Depending on the target only one variant is ever used in a compilation. /// Anything else is an error. This invariant is checked at several locations @@ -41,11 +42,11 @@ impl ConstIsize { _ => unreachable!(), } } - pub fn new_truncating(i: i64, target_int_ty: ast::IntTy) -> Self { + pub fn new_truncating(i: i128, target_int_ty: ast::IntTy) -> Self { match target_int_ty { ast::IntTy::I16 => Is16(i as i16), ast::IntTy::I32 => Is32(i as i32), - ast::IntTy::I64 => Is64(i), + ast::IntTy::I64 => Is64(i as i64), _ => unreachable!(), } } diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index f667ff23b27a6..597344a2c82d0 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -25,10 +25,14 @@ #![feature(rustc_private)] #![feature(staged_api)] +#![feature(const_fn)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; +// SNAP: remove use of this crate +extern crate rustc_i128; + extern crate serialize as rustc_serialize; // used by deriving mod float; diff --git a/src/librustc_const_math/us.rs b/src/librustc_const_math/us.rs index bf73ff03c9895..9ebf5cab6bb06 100644 --- a/src/librustc_const_math/us.rs +++ b/src/librustc_const_math/us.rs @@ -10,6 +10,7 @@ use syntax::ast; use super::err::*; +use rustc_i128::u128; /// Depending on the target only one variant is ever used in a compilation. /// Anything else is an error. This invariant is checked at several locations @@ -41,11 +42,11 @@ impl ConstUsize { _ => unreachable!(), } } - pub fn new_truncating(i: u64, target_uint_ty: ast::UintTy) -> Self { + pub fn new_truncating(i: u128, target_uint_ty: ast::UintTy) -> Self { match target_uint_ty { ast::UintTy::U16 => Us16(i as u16), ast::UintTy::U32 => Us32(i as u32), - ast::UintTy::U64 => Us64(i), + ast::UintTy::U64 => Us64(i as u64), _ => unreachable!(), } } diff --git a/src/librustc_i128/Cargo.toml b/src/librustc_i128/Cargo.toml new file mode 100644 index 0000000000000..79632394bf6b0 --- /dev/null +++ b/src/librustc_i128/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_i128" +version = "0.0.0" + +[lib] +name = "rustc_i128" +path = "lib.rs" +crate-type = ["dylib"] diff --git a/src/librustc_i128/lib.rs b/src/librustc_i128/lib.rs new file mode 100644 index 0000000000000..14604fc66ba86 --- /dev/null +++ b/src/librustc_i128/lib.rs @@ -0,0 +1,16 @@ +#![allow(non_camel_case_types)] + +#[cfg(stage0)] +pub type i128 = i64; +#[cfg(stage0)] +pub type u128 = u64; + +#[cfg(not(stage0))] +pub type i128 = int::_i128; +#[cfg(not(stage0))] +pub type u128 = int::_u128; +#[cfg(not(stage0))] +mod int { + pub type _i128 = i128; + pub type _u128 = u128; +} diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 4d5c0d7ba0ae1..272f8b4f64dbd 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -14,5 +14,6 @@ log = { path = "../liblog" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } +rustc_i128 = { path = "../librustc_i128" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index a53d43b2a257a..a24edfaaac1c2 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -47,6 +47,8 @@ extern crate rustc_back; extern crate rustc_const_eval; extern crate syntax_pos; +extern crate rustc_i128; + pub use rustc::lint; pub use rustc::middle; pub use rustc::session; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index a3aa4af493aaf..95e955bd6833e 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -33,6 +33,8 @@ use syntax::codemap; use rustc::hir; +use rustc_i128::{i128, u128}; + register_long_diagnostics! { E0519: r##" It is not allowed to negate an unsigned integer. @@ -147,7 +149,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { if let Some(bits) = opt_ty_bits { let exceeding = if let hir::ExprLit(ref lit) = r.node { if let ast::LitKind::Int(shift, _) = lit.node { - shift >= bits + shift as u64 >= bits } else { false } @@ -182,12 +184,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { t }; let (_, max) = int_ty_range(int_type); + let max = max as u128; let negative = self.negated_expr_id == e.id; // Detect literal value out of range [min, max] inclusive // avoiding use of -min to prevent overflow/panic - if (negative && v > max as u64 + 1) || - (!negative && v > max as u64) { + if (negative && v > max + 1) || + (!negative && v > max) { cx.span_lint(OVERFLOWING_LITERALS, e.span, &format!("literal out of range for {:?}", t)); @@ -204,7 +207,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { t }; let (min, max) = uint_ty_range(uint_type); - let lit_val: u64 = match lit.node { + let lit_val: u128 = match lit.node { // _v is u8, within range by definition ast::LitKind::Byte(_v) => return, ast::LitKind::Int(v, _) => v, @@ -264,23 +267,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { // for isize & usize, be conservative with the warnings, so that the // warnings are consistent between 32- and 64-bit platforms - fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) { + fn int_ty_range(int_ty: ast::IntTy) -> (i128, i128) { match int_ty { - ast::IntTy::Is => (i64::MIN, i64::MAX), - ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64), - ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64), - ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64), - ast::IntTy::I64 => (i64::MIN, i64::MAX), + ast::IntTy::Is => (i64::min_value() as i128, i64::max_value() as i128), + ast::IntTy::I8 => (i8::min_value() as i64 as i128, i8::max_value() as i128), + ast::IntTy::I16 => (i16::min_value() as i64 as i128, i16::max_value() as i128), + ast::IntTy::I32 => (i32::min_value() as i64 as i128, i32::max_value() as i128), + ast::IntTy::I64 => (i64::min_value() as i128, i64::max_value() as i128), + ast::IntTy::I128 =>(i128::min_value() as i128, i128::max_value()), } } - fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) { + fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) { match uint_ty { - ast::UintTy::Us => (u64::MIN, u64::MAX), - ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64), - ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64), - ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64), - ast::UintTy::U64 => (u64::MIN, u64::MAX), + ast::UintTy::Us => (u64::min_value() as u128, u64::max_value() as u128), + ast::UintTy::U8 => (u8::min_value() as u128, u8::max_value() as u128), + ast::UintTy::U16 => (u16::min_value() as u128, u16::max_value() as u128), + ast::UintTy::U32 => (u32::min_value() as u128, u32::max_value() as u128), + ast::UintTy::U64 => (u64::min_value() as u128, u64::max_value() as u128), + ast::UintTy::U128 => (u128::min_value(), u128::max_value()), } } @@ -298,6 +303,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { ast::IntTy::I16 => 16 as u64, ast::IntTy::I32 => 32, ast::IntTy::I64 => 64, + ast::IntTy::I128 => 128, } } @@ -308,6 +314,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { ast::UintTy::U16 => 16, ast::UintTy::U32 => 32, ast::UintTy::U64 => 64, + ast::UintTy::U128 => 128, } } @@ -327,28 +334,28 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { match tcx.tables().node_id_to_type(expr.id).sty { ty::TyInt(int_ty) => { let (min, max) = int_ty_range(int_ty); - let lit_val: i64 = match lit.node { + let lit_val: i128 = match lit.node { hir::ExprLit(ref li) => { match li.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | - ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64, - _ => return true, + ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i128, + _ => return true } - } - _ => bug!(), + }, + _ => bug!() }; is_valid(norm_binop, lit_val, min, max) } ty::TyUint(uint_ty) => { - let (min, max): (u64, u64) = uint_ty_range(uint_ty); - let lit_val: u64 = match lit.node { + let (min, max) :(u128, u128) = uint_ty_range(uint_ty); + let lit_val: u128 = match lit.node { hir::ExprLit(ref li) => { match li.node { ast::LitKind::Int(v, _) => v, - _ => return true, + _ => return true } - } - _ => bug!(), + }, + _ => bug!() }; is_valid(norm_binop, lit_val, min, max) } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index c170581516593..efb06bdb73e3a 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -508,6 +508,7 @@ extern "C" { pub fn LLVMInt16TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMInt32TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMInt64TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMInt128TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMIntTypeInContext(C: ContextRef, NumBits: c_uint) -> TypeRef; pub fn LLVMGetIntTypeWidth(IntegerTy: TypeRef) -> c_uint; @@ -578,6 +579,7 @@ extern "C" { // Operations on scalar constants pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) -> ValueRef; + pub fn LLVMConstIntOfArbitraryPrecision(IntTy: TypeRef, Wn: c_uint, Ws: *const u64) -> ValueRef; pub fn LLVMConstReal(RealTy: TypeRef, N: f64) -> ValueRef; pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong; pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong; diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 6f7f03ca216b9..4bd98c087f517 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -18,6 +18,7 @@ rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_llvm = { path = "../librustc_llvm" } +rustc_i128 = { path = "../librustc_i128" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index c27e06c50222b..3e3553dd1f229 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -43,6 +43,8 @@ use syntax::attr; use syntax::ast::{self, NodeId}; use syntax::codemap; use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP}; +use syntax_pos::{self, Span, BytePos, Pos}; +use rustc_i128::u128; pub struct DecodeContext<'a, 'tcx: 'a> { opaque: opaque::Decoder<'a>, @@ -211,12 +213,14 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> { decoder_methods! { read_nil -> (); + read_u128 -> u128; read_u64 -> u64; read_u32 -> u32; read_u16 -> u16; read_u8 -> u8; read_usize -> usize; + read_i128 -> i128; read_i64 -> i64; read_i32 -> i32; read_i16 -> i16; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 56f3cfc12c97f..8ba3e7d82f2e2 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -45,9 +45,15 @@ extern crate rustc_back; extern crate rustc_const_math; extern crate rustc_data_structures; extern crate rustc_llvm; +extern crate rustc_i128; mod diagnostics; +pub use rustc::middle; + +#[macro_use] +mod macros; + mod astencode; mod index_builder; mod index; diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 2a1a815330675..7e26aa9a57bf5 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -17,5 +17,6 @@ rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_bitflags = { path = "../librustc_bitflags" } +rustc_i128 = { path = "../librustc_i128" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index b75e52fd4b10d..0aad96d27cc06 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -15,6 +15,7 @@ use std; use rustc_const_math::{ConstMathErr, Op}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; +use rustc_i128::i128; use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::{Category, RvalueFunc}; @@ -347,6 +348,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast::IntTy::I16 => ConstInt::I16(-1), ast::IntTy::I32 => ConstInt::I32(-1), ast::IntTy::I64 => ConstInt::I64(-1), + ast::IntTy::I128 => ConstInt::I128(-1), ast::IntTy::Is => { let int_ty = self.hir.tcx().sess.target.int_type; let val = ConstIsize::new(-1, int_ty).unwrap(); @@ -369,10 +371,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let literal = match ty.sty { ty::TyInt(ity) => { let val = match ity { - ast::IntTy::I8 => ConstInt::I8(std::i8::MIN), - ast::IntTy::I16 => ConstInt::I16(std::i16::MIN), - ast::IntTy::I32 => ConstInt::I32(std::i32::MIN), - ast::IntTy::I64 => ConstInt::I64(std::i64::MIN), + ast::IntTy::I8 => ConstInt::I8(i8::min_value()), + ast::IntTy::I16 => ConstInt::I16(i16::min_value()), + ast::IntTy::I32 => ConstInt::I32(i32::min_value()), + ast::IntTy::I64 => ConstInt::I64(i64::min_value()), + // FIXME: i128 + ast::IntTy::I128 => ConstInt::I128(i128::min_value()), ast::IntTy::Is => { let int_ty = self.hir.tcx().sess.target.int_type; let min = match int_ty { diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index a5f51ef35b741..99aa5cb0fa86e 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -66,6 +66,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast::UintTy::U16 => ConstInt::U16(0), ast::UintTy::U32 => ConstInt::U32(0), ast::UintTy::U64 => ConstInt::U64(0), + ast::UintTy::U128 => ConstInt::U128(0), ast::UintTy::Us => { let uint_ty = self.hir.tcx().sess.target.uint_type; let val = ConstUsize::new(0, uint_ty).unwrap(); @@ -81,6 +82,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast::IntTy::I16 => ConstInt::I16(0), ast::IntTy::I32 => ConstInt::I32(0), ast::IntTy::I64 => ConstInt::I64(0), + ast::IntTy::I128 => ConstInt::I128(0), ast::IntTy::Is => { let int_ty = self.hir.tcx().sess.target.int_type; let val = ConstIsize::new(0, int_ty).unwrap(); diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 56dadd2d673e1..a608275cefa06 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -41,6 +41,8 @@ extern crate syntax_pos; extern crate rustc_const_math; extern crate rustc_const_eval; +extern crate rustc_i128; + pub mod diagnostics; pub mod build; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 865195d3db488..53fa87b52250d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1005,13 +1005,14 @@ impl PrimitiveTypeTable { table.intern("i16", TyInt(IntTy::I16)); table.intern("i32", TyInt(IntTy::I32)); table.intern("i64", TyInt(IntTy::I64)); + table.intern("i128", TyInt(IntTy::I128)); table.intern("str", TyStr); table.intern("usize", TyUint(UintTy::Us)); table.intern("u8", TyUint(UintTy::U8)); table.intern("u16", TyUint(UintTy::U16)); table.intern("u32", TyUint(UintTy::U32)); table.intern("u64", TyUint(UintTy::U64)); - + table.intern("u128", TyUint(UintTy::U128)); table } diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 796a80d080944..93e2e472b75f1 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -23,7 +23,8 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_incremental = { path = "../librustc_incremental" } rustc_llvm = { path = "../librustc_llvm" } +rustc_i128 = { path = "../librustc_i128" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 71e17f1ea7405..3e564a7c6ed4d 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -44,6 +44,8 @@ use syntax::ast; use syntax::symbol::{Symbol, InternedString}; use syntax_pos::Span; +use rustc_i128::u128; + pub use context::{CrateContext, SharedCrateContext}; pub fn type_is_fat_ptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { @@ -425,6 +427,16 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { } } +pub fn C_big_integral(t: Type, u: u128) -> ValueRef { + if ::std::mem::size_of::() == 16 { + unsafe { + llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, &u as *const u128 as *const u64) + } + } else { + C_integral(t, u as u64, false) + } +} + pub fn C_floating_f64(f: f64, t: Type) -> ValueRef { unsafe { llvm::LLVMConstReal(t.to_ref(), f) diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 2e2644d91bb6c..fd921b3c43290 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -24,6 +24,7 @@ use monomorphize::{Instance}; use type_::Type; use type_of; use rustc::ty; +use rustc_i128::{i128, u128}; use rustc::hir; diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index d9179d6a6fa73..413b643740861 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -1022,6 +1022,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option { let t_i16 = Type::i16(ccx); let t_i32 = Type::i32(ccx); let t_i64 = Type::i64(ccx); + let t_i128 = Type::i128(ccx); let t_f32 = Type::f32(ccx); let t_f64 = Type::f64(ccx); @@ -1088,50 +1089,60 @@ fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option { ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16); ifn!("llvm.ctpop.i32", fn(t_i32) -> t_i32); ifn!("llvm.ctpop.i64", fn(t_i64) -> t_i64); + ifn!("llvm.ctpop.i128", fn(t_i128) -> t_i128); ifn!("llvm.ctlz.i8", fn(t_i8 , i1) -> t_i8); ifn!("llvm.ctlz.i16", fn(t_i16, i1) -> t_i16); ifn!("llvm.ctlz.i32", fn(t_i32, i1) -> t_i32); ifn!("llvm.ctlz.i64", fn(t_i64, i1) -> t_i64); + ifn!("llvm.ctlz.i128", fn(t_i128, i1) -> t_i128); ifn!("llvm.cttz.i8", fn(t_i8 , i1) -> t_i8); ifn!("llvm.cttz.i16", fn(t_i16, i1) -> t_i16); ifn!("llvm.cttz.i32", fn(t_i32, i1) -> t_i32); ifn!("llvm.cttz.i64", fn(t_i64, i1) -> t_i64); + ifn!("llvm.cttz.i128", fn(t_i128, i1) -> t_i128); ifn!("llvm.bswap.i16", fn(t_i16) -> t_i16); ifn!("llvm.bswap.i32", fn(t_i32) -> t_i32); ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); + ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128); ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.sadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.sadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.uadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.uadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.uadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.uadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.uadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.ssub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.ssub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.ssub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.ssub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.ssub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.usub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.usub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.usub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.usub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.usub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.smul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.smul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.smul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.smul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.smul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.umul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.umul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.umul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.umul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.lifetime.start", fn(t_i64,i8p) -> void); ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void); diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 511c9d3c13f91..b2d12c7e7d0f2 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1460,7 +1460,8 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), name.as_ptr(), - v.disr_val.to_u64_unchecked()) + // FIXME: what if enumeration has i128 discriminant? + v.disr_val.to_u128_unchecked() as u64) } }) .collect(); diff --git a/src/librustc_trans/disr.rs b/src/librustc_trans/disr.rs index fc79fa813aa5a..c5737c6e5f12c 100644 --- a/src/librustc_trans/disr.rs +++ b/src/librustc_trans/disr.rs @@ -26,7 +26,8 @@ impl ::std::ops::BitAnd for Disr { impl From<::rustc::ty::Disr> for Disr { fn from(i: ::rustc::ty::Disr) -> Disr { - Disr(i.to_u64_unchecked()) + // FIXME: what if discr has 128 bit discr? + Disr(i.to_u128_unchecked() as u64) } } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index b7116ba1f338b..cc55a2b3e9a58 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -1167,6 +1167,8 @@ fn generic_simd_intrinsic<'a, 'tcx>( // Returns the width of an int TypeVariant, and if it's signed or not // Returns None if the type is not an integer +// FIXME: there’s multiple of this functions, investigate using some of the already existing +// stuffs. fn int_type_width_signed<'tcx>(sty: &ty::TypeVariants<'tcx>, ccx: &CrateContext) -> Option<(u64, bool)> { use rustc::ty::{TyInt, TyUint}; @@ -1184,6 +1186,7 @@ fn int_type_width_signed<'tcx>(sty: &ty::TypeVariants<'tcx>, ccx: &CrateContext) ast::IntTy::I16 => 16, ast::IntTy::I32 => 32, ast::IntTy::I64 => 64, + ast::IntTy::I128 => 128, }, true)), TyUint(t) => Some((match t { ast::UintTy::Us => { @@ -1198,6 +1201,7 @@ fn int_type_width_signed<'tcx>(sty: &ty::TypeVariants<'tcx>, ccx: &CrateContext) ast::UintTy::U16 => 16, ast::UintTy::U32 => 32, ast::UintTy::U64 => 64, + ast::UintTy::U128 => 128, }, false)), _ => None, } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 0d3e1853f011e..11bfa0d76c382 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -57,6 +57,7 @@ extern crate rustc_const_eval; #[macro_use] #[no_link] extern crate rustc_bitflags; +extern crate rustc_i128; #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1cedaa0a4e1a4..737ca634f0860 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -25,7 +25,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use {abi, adt, base, Disr, machine}; use callee::Callee; use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty}; -use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral}; +use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral}; use common::{C_null, C_struct, C_str_slice, C_undef, C_uint}; use common::{const_to_opt_int, const_to_opt_uint}; use consts; @@ -36,6 +36,7 @@ use value::Value; use syntax::ast; use syntax_pos::Span; +use rustc_i128::u128; use std::fmt; use std::ptr; @@ -75,6 +76,7 @@ impl<'tcx> Const<'tcx> { ConstVal::Integral(I16(v)) => C_integral(Type::i16(ccx), v as u64, true), ConstVal::Integral(I32(v)) => C_integral(Type::i32(ccx), v as u64, true), ConstVal::Integral(I64(v)) => C_integral(Type::i64(ccx), v as u64, true), + ConstVal::Integral(I128(v)) => C_big_integral(Type::i128(ccx), v as u128), ConstVal::Integral(Isize(v)) => { let i = v.as_i64(ccx.tcx().sess.target.int_type); C_integral(Type::int(ccx), i as u64, true) @@ -83,6 +85,7 @@ impl<'tcx> Const<'tcx> { ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false), ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false), ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false), + ConstVal::Integral(U128(v)) => C_big_integral(Type::i128(ccx), v), ConstVal::Integral(Usize(v)) => { let u = v.as_u64(ccx.tcx().sess.target.uint_type); C_integral(Type::int(ccx), u, false) diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index b17550087edf7..cca48737bb963 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -711,11 +711,13 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &BlockAndBuilder, ty: Ty) -> Val TyInt(I16) => "llvm.sadd.with.overflow.i16", TyInt(I32) => "llvm.sadd.with.overflow.i32", TyInt(I64) => "llvm.sadd.with.overflow.i64", + TyInt(I128) => "llvm.sadd.with.overflow.i128", TyUint(U8) => "llvm.uadd.with.overflow.i8", TyUint(U16) => "llvm.uadd.with.overflow.i16", TyUint(U32) => "llvm.uadd.with.overflow.i32", TyUint(U64) => "llvm.uadd.with.overflow.i64", + TyUint(U128) => "llvm.uadd.with.overflow.i128", _ => unreachable!(), }, @@ -724,11 +726,13 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &BlockAndBuilder, ty: Ty) -> Val TyInt(I16) => "llvm.ssub.with.overflow.i16", TyInt(I32) => "llvm.ssub.with.overflow.i32", TyInt(I64) => "llvm.ssub.with.overflow.i64", + TyInt(I128) => "llvm.ssub.with.overflow.i128", TyUint(U8) => "llvm.usub.with.overflow.i8", TyUint(U16) => "llvm.usub.with.overflow.i16", TyUint(U32) => "llvm.usub.with.overflow.i32", TyUint(U64) => "llvm.usub.with.overflow.i64", + TyUint(U128) => "llvm.usub.with.overflow.i128", _ => unreachable!(), }, @@ -737,11 +741,13 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &BlockAndBuilder, ty: Ty) -> Val TyInt(I16) => "llvm.smul.with.overflow.i16", TyInt(I32) => "llvm.smul.with.overflow.i32", TyInt(I64) => "llvm.smul.with.overflow.i64", + TyInt(I128) => "llvm.smul.with.overflow.i128", TyUint(U8) => "llvm.umul.with.overflow.i8", TyUint(U16) => "llvm.umul.with.overflow.i16", TyUint(U32) => "llvm.umul.with.overflow.i32", TyUint(U64) => "llvm.umul.with.overflow.i64", + TyUint(U128) => "llvm.umul.with.overflow.i128", _ => unreachable!(), }, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 6e0d8d08e7042..f6f91411225d9 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -397,11 +397,13 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { ty::TyInt(ast::IntTy::I16) => output.push_str("i16"), ty::TyInt(ast::IntTy::I32) => output.push_str("i32"), ty::TyInt(ast::IntTy::I64) => output.push_str("i64"), + ty::TyInt(ast::IntTy::I128) => output.push_str("i128"), ty::TyUint(ast::UintTy::Us) => output.push_str("usize"), ty::TyUint(ast::UintTy::U8) => output.push_str("u8"), ty::TyUint(ast::UintTy::U16) => output.push_str("u16"), ty::TyUint(ast::UintTy::U32) => output.push_str("u32"), ty::TyUint(ast::UintTy::U64) => output.push_str("u64"), + ty::TyUint(ast::UintTy::U128) => output.push_str("u128"), ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), ty::TyAdt(adt_def, substs) => { diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index 2b2776acab869..e8d8db2956b8a 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -94,6 +94,10 @@ impl Type { ty!(llvm::LLVMInt64TypeInContext(ccx.llcx())) } + pub fn i128(ccx: &CrateContext) -> Type { + ty!(llvm::LLVMInt128TypeInContext(ccx.llcx())) + } + // Creates an integer type with the given number of bits, e.g. i24 pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type { ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint)) @@ -134,7 +138,8 @@ impl Type { ast::IntTy::I8 => Type::i8(ccx), ast::IntTy::I16 => Type::i16(ccx), ast::IntTy::I32 => Type::i32(ccx), - ast::IntTy::I64 => Type::i64(ccx) + ast::IntTy::I64 => Type::i64(ccx), + ast::IntTy::I128 => Type::i128(ccx), } } @@ -144,7 +149,8 @@ impl Type { ast::UintTy::U8 => Type::i8(ccx), ast::UintTy::U16 => Type::i16(ccx), ast::UintTy::U32 => Type::i32(ccx), - ast::UintTy::U64 => Type::i64(ccx) + ast::UintTy::U64 => Type::i64(ccx), + ast::UintTy::U128 => Type::i128(ccx), } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index c733c0856c6da..4f41bbe9924b0 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -432,7 +432,9 @@ fn match_intrinsic_type_to_type<'tcx, 'a>( (true, 32, &ty::TyInt(ast::IntTy::I32)) | (false, 32, &ty::TyUint(ast::UintTy::U32)) | (true, 64, &ty::TyInt(ast::IntTy::I64)) | - (false, 64, &ty::TyUint(ast::UintTy::U64)) => {}, + (false, 64, &ty::TyUint(ast::UintTy::U64)) | + (true, 128, &ty::TyInt(ast::IntTy::I128)) | + (false, 128, &ty::TyUint(ast::UintTy::U128)) => {}, _ => simple_error(&format!("`{}`", t), &format!("`{}{n}`", if signed {"i"} else {"u"}, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 1962534c39716..5c3da4237bef2 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -435,6 +435,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let lang_def_id = self.tcx.lang_items.i64_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } + ty::TyInt(ast::IntTy::I128) => { + let lang_def_id = self.tcx.lang_items.i128_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } ty::TyInt(ast::IntTy::Is) => { let lang_def_id = self.tcx.lang_items.isize_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); @@ -455,6 +459,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let lang_def_id = self.tcx.lang_items.u64_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } + ty::TyUint(ast::UintTy::U128) => { + let lang_def_id = self.tcx.lang_items.u128_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } ty::TyUint(ast::UintTy::Us) => { let lang_def_id = self.tcx.lang_items.usize_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index bc1ead07c0ea7..2b5a4515cd0d8 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -160,6 +160,13 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { "i64", item.span); } + ty::TyInt(ast::IntTy::I128) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.i128_impl(), + "i128", + "i128", + item.span); + } ty::TyInt(ast::IntTy::Is) => { self.check_primitive_impl(def_id, self.tcx.lang_items.isize_impl(), @@ -195,6 +202,13 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { "u64", item.span); } + ty::TyUint(ast::UintTy::U128) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.u128_impl(), + "u128", + "u128", + item.span); + } ty::TyUint(ast::UintTy::Us) => { self.check_primitive_impl(def_id, self.tcx.lang_items.usize_impl(), diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fd51b38e1b557..7ddf10375bf23 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1060,11 +1060,13 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) | (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) | (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) | + (attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) | (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) | (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) | (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) | (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) | (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) | + (attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) | (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Some(i), (_, i) => { print_err(ConstVal::Integral(i)); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3b8281980696d..6e9b66d564555 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1513,8 +1513,8 @@ pub enum Type { #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)] pub enum PrimitiveType { - Isize, I8, I16, I32, I64, - Usize, U8, U16, U32, U64, + Isize, I8, I16, I32, I64, I128, + Usize, U8, U16, U32, U64, U128, F32, F64, Char, Bool, @@ -1614,26 +1614,29 @@ impl PrimitiveType { } pub fn as_str(&self) -> &'static str { + use PrimitiveType::*; match *self { - PrimitiveType::Isize => "isize", - PrimitiveType::I8 => "i8", - PrimitiveType::I16 => "i16", - PrimitiveType::I32 => "i32", - PrimitiveType::I64 => "i64", - PrimitiveType::Usize => "usize", - PrimitiveType::U8 => "u8", - PrimitiveType::U16 => "u16", - PrimitiveType::U32 => "u32", - PrimitiveType::U64 => "u64", - PrimitiveType::F32 => "f32", - PrimitiveType::F64 => "f64", - PrimitiveType::Str => "str", - PrimitiveType::Bool => "bool", - PrimitiveType::Char => "char", - PrimitiveType::Array => "array", - PrimitiveType::Slice => "slice", - PrimitiveType::Tuple => "tuple", - PrimitiveType::RawPointer => "pointer", + Isize => "isize", + I8 => "i8", + I16 => "i16", + I32 => "i32", + I64 => "i64", + I128 => "i128", + Usize => "usize", + U8 => "u8", + U16 => "u16", + U32 => "u32", + U64 => "u64", + U128 => "u128", + F32 => "f32", + F64 => "f64", + Str => "str", + Bool => "bool", + Char => "char", + Array => "array", + Slice => "slice", + Tuple => "tuple", + RawPointer => "pointer", } } @@ -2486,6 +2489,7 @@ impl Clean> for doctree::Impl { fn build_deref_target_impls(cx: &DocContext, items: &[Item], ret: &mut Vec) { + use PrimitiveType::*; let tcx = cx.tcx; for item in items { @@ -2505,25 +2509,27 @@ fn build_deref_target_impls(cx: &DocContext, } }; let did = match primitive { - PrimitiveType::Isize => tcx.lang_items.isize_impl(), - PrimitiveType::I8 => tcx.lang_items.i8_impl(), - PrimitiveType::I16 => tcx.lang_items.i16_impl(), - PrimitiveType::I32 => tcx.lang_items.i32_impl(), - PrimitiveType::I64 => tcx.lang_items.i64_impl(), - PrimitiveType::Usize => tcx.lang_items.usize_impl(), - PrimitiveType::U8 => tcx.lang_items.u8_impl(), - PrimitiveType::U16 => tcx.lang_items.u16_impl(), - PrimitiveType::U32 => tcx.lang_items.u32_impl(), - PrimitiveType::U64 => tcx.lang_items.u64_impl(), - PrimitiveType::F32 => tcx.lang_items.f32_impl(), - PrimitiveType::F64 => tcx.lang_items.f64_impl(), - PrimitiveType::Char => tcx.lang_items.char_impl(), - PrimitiveType::Bool => None, - PrimitiveType::Str => tcx.lang_items.str_impl(), - PrimitiveType::Slice => tcx.lang_items.slice_impl(), - PrimitiveType::Array => tcx.lang_items.slice_impl(), - PrimitiveType::Tuple => None, - PrimitiveType::RawPointer => tcx.lang_items.const_ptr_impl(), + Isize => tcx.lang_items.isize_impl(), + I8 => tcx.lang_items.i8_impl(), + I16 => tcx.lang_items.i16_impl(), + I32 => tcx.lang_items.i32_impl(), + I64 => tcx.lang_items.i64_impl(), + I128 => tcx.lang_items.i128_impl(), + Usize => tcx.lang_items.usize_impl(), + U8 => tcx.lang_items.u8_impl(), + U16 => tcx.lang_items.u16_impl(), + U32 => tcx.lang_items.u32_impl(), + U64 => tcx.lang_items.u64_impl(), + U128 => tcx.lang_items.u128_impl(), + F32 => tcx.lang_items.f32_impl(), + F64 => tcx.lang_items.f64_impl(), + Char => tcx.lang_items.char_impl(), + Bool => None, + Str => tcx.lang_items.str_impl(), + Slice => tcx.lang_items.slice_impl(), + Array => tcx.lang_items.slice_impl(), + Tuple => None, + RawPointer => tcx.lang_items.const_ptr_impl(), }; if let Some(did) = did { if !did.is_local() { diff --git a/src/libserialize/Cargo.toml b/src/libserialize/Cargo.toml index 919cda49c004c..3213b4e4208be 100644 --- a/src/libserialize/Cargo.toml +++ b/src/libserialize/Cargo.toml @@ -10,3 +10,4 @@ crate-type = ["dylib", "rlib"] [dependencies] log = { path = "../liblog" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 239d32c8fc8dd..80b0bfc7d3e32 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -211,6 +211,8 @@ use std::string; use std::{char, f64, fmt, str}; use std; +use rustc_i128::{i128, u128}; + use Encodable; /// Represents a json value @@ -494,12 +496,14 @@ impl<'a> ::Encoder for Encoder<'a> { } fn emit_usize(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u128(&mut self, _: u128) -> EncodeResult { unimplemented!() } fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_isize(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i128(&mut self, _: i128) -> EncodeResult { unimplemented!() } fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } @@ -742,12 +746,14 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { } fn emit_usize(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u128(&mut self, _: u128) -> EncodeResult { unimplemented!() } fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_isize(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i128(&mut self, _: i128) -> EncodeResult { unimplemented!() } fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } @@ -2138,11 +2144,13 @@ impl ::Decoder for Decoder { read_primitive! { read_u16, u16 } read_primitive! { read_u32, u32 } read_primitive! { read_u64, u64 } + read_primitive! { read_u128, u128 } read_primitive! { read_isize, isize } read_primitive! { read_i8, i8 } read_primitive! { read_i16, i16 } read_primitive! { read_i32, i32 } read_primitive! { read_i64, i64 } + read_primitive! { read_i128, i128 } fn read_f32(&mut self) -> DecodeResult { self.read_f64().map(|x| x as f32) } diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs index 5b72c6d46aceb..7a4d1c7a0e449 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc_i128::{i128, u128}; + #[inline] fn write_to_vec(vec: &mut Vec, position: usize, byte: u8) { if position == vec.len() { @@ -28,7 +30,6 @@ pub fn write_unsigned_leb128_to(mut value: u64, mut write: W) -> usize where W: FnMut(usize, u8) { let mut position = 0; - loop { let mut byte = (value & 0x7F) as u8; value >>= 7; @@ -52,14 +53,14 @@ pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, value: u6 } #[inline] -pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize) { +pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u128, usize) { let mut result = 0; let mut shift = 0; let mut position = start_position; loop { let byte = data[position]; position += 1; - result |= ((byte & 0x7F) as u64) << shift; + result |= ((byte & 0x7F) as u128) << shift; if (byte & 0x80) == 0 { break; } @@ -76,7 +77,7 @@ pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize) /// The callback `write` is called once for each position /// that is to be written to with the byte to be encoded /// at that position. -pub fn write_signed_leb128_to(mut value: i64, mut write: W) -> usize +pub fn write_signed_leb128_to(mut value: i128, mut write: W) -> usize where W: FnMut(usize, u8) { let mut position = 0; @@ -92,43 +93,43 @@ pub fn write_signed_leb128_to(mut value: i64, mut write: W) -> usize write(position, byte); position += 1; - if !more { break; } } - position } -pub fn write_signed_leb128(out: &mut Vec, start_position: usize, value: i64) -> usize { +pub fn write_signed_leb128(out: &mut Vec, start_position: usize, value: i128) -> usize { write_signed_leb128_to(value, |i, v| write_to_vec(out, start_position+i, v)) } #[inline] -pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i64, usize) { - let mut result = 0; - let mut shift = 0; - let mut position = start_position; - let mut byte; - - loop { - byte = data[position]; - position += 1; - result |= ((byte & 0x7F) as i64) << shift; - shift += 7; - - if (byte & 0x80) == 0 { - break; - } - } - - if (shift < 64) && ((byte & 0x40) != 0) { - // sign extend - result |= -(1i64 << shift); - } - - (result, position - start_position) +pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i128, usize) { + let (l, r) = read_unsigned_leb128(data, start_position); + (l as i128, r) + // let mut result = 0; + // let mut shift = 0; + // let mut position = start_position; + // let mut byte; + + // loop { + // byte = data[position]; + // position += 1; + // result |= ((byte & 0x7F) as i128) << shift; + // shift += 7; + + // if (byte & 0x80) == 0 { + // break; + // } + // } + + // if (shift < 64) && ((byte & 0x40) != 0) { + // // sign extend + // result |= -(1 << shift); + // } + + // (result, position - start_position) } #[test] diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index ad2304e1556a4..0979860189ca1 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -44,6 +44,8 @@ Core encoding and decoding interfaces. extern crate std_unicode; extern crate collections; +extern crate rustc_i128; + pub use self::serialize::{Decoder, Encoder, Decodable, Encodable}; pub use self::serialize::{SpecializationError, SpecializedEncoder, SpecializedDecoder}; diff --git a/src/libserialize/opaque.rs b/src/libserialize/opaque.rs index 87b6ed2ed403c..8a0648d5851a1 100644 --- a/src/libserialize/opaque.rs +++ b/src/libserialize/opaque.rs @@ -13,6 +13,8 @@ use std::borrow::Cow; use std::io::{self, Write}; use serialize; +use rustc_i128::{i128, u128}; + // ----------------------------------------------------------------------------- // Encoder // ----------------------------------------------------------------------------- @@ -33,7 +35,7 @@ impl<'a> Encoder<'a> { macro_rules! write_uleb128 { ($enc:expr, $value:expr) => {{ let pos = $enc.cursor.position() as usize; - let bytes_written = write_unsigned_leb128($enc.cursor.get_mut(), pos, $value as u64); + let bytes_written = write_unsigned_leb128($enc.cursor.get_mut(), pos, $value as u128); $enc.cursor.set_position((pos + bytes_written) as u64); Ok(()) }} @@ -42,7 +44,7 @@ macro_rules! write_uleb128 { macro_rules! write_sleb128 { ($enc:expr, $value:expr) => {{ let pos = $enc.cursor.position() as usize; - let bytes_written = write_signed_leb128($enc.cursor.get_mut(), pos, $value as i64); + let bytes_written = write_signed_leb128($enc.cursor.get_mut(), pos, $value as i128); $enc.cursor.set_position((pos + bytes_written) as u64); Ok(()) }} @@ -59,6 +61,10 @@ impl<'a> serialize::Encoder for Encoder<'a> { write_uleb128!(self, v) } + fn emit_u128(&mut self, v: u128) -> EncodeResult { + write_uleb128!(self, v) + } + fn emit_u64(&mut self, v: u64) -> EncodeResult { write_uleb128!(self, v) } @@ -80,6 +86,10 @@ impl<'a> serialize::Encoder for Encoder<'a> { write_sleb128!(self, v) } + fn emit_i128(&mut self, v: i128) -> EncodeResult { + write_sleb128!(self, v) + } + fn emit_i64(&mut self, v: i64) -> EncodeResult { write_sleb128!(self, v) } @@ -184,6 +194,11 @@ impl<'a> serialize::Decoder for Decoder<'a> { Ok(()) } + #[inline] + fn read_u128(&mut self) -> Result { + read_uleb128!(self, u128) + } + #[inline] fn read_u64(&mut self) -> Result { read_uleb128!(self, u64) @@ -211,6 +226,11 @@ impl<'a> serialize::Decoder for Decoder<'a> { read_uleb128!(self, usize) } + #[inline] + fn read_i128(&mut self) -> Result { + read_sleb128!(self, i128) + } + #[inline] fn read_i64(&mut self) -> Result { read_sleb128!(self, i64) diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index c4613c661a84b..395f2ccbe6d28 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -20,6 +20,7 @@ use std::path; use std::rc::Rc; use std::cell::{Cell, RefCell}; use std::sync::Arc; +use rustc_i128::{i128, u128}; pub trait Encoder { type Error; @@ -27,11 +28,13 @@ pub trait Encoder { // Primitive types: fn emit_nil(&mut self) -> Result<(), Self::Error>; fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error>; + fn emit_u128(&mut self, v: u128) -> Result<(), Self::Error>; fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>; fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error>; fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error>; fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error>; fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error>; + fn emit_i128(&mut self, v: i128) -> Result<(), Self::Error>; fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error>; fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error>; fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error>; @@ -144,11 +147,13 @@ pub trait Decoder { // Primitive types: fn read_nil(&mut self) -> Result<(), Self::Error>; fn read_usize(&mut self) -> Result; + fn read_u128(&mut self) -> Result; fn read_u64(&mut self) -> Result; fn read_u32(&mut self) -> Result; fn read_u16(&mut self) -> Result; fn read_u8(&mut self) -> Result; fn read_isize(&mut self) -> Result; + fn read_i128(&mut self) -> Result; fn read_i64(&mut self) -> Result; fn read_i32(&mut self) -> Result; fn read_i16(&mut self) -> Result; @@ -328,6 +333,20 @@ impl Decodable for u64 { } } +#[cfg(not(stage0))] +impl Encodable for u128 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_u128(*self) + } +} + +#[cfg(not(stage0))] +impl Decodable for u128 { + fn decode(d: &mut D) -> Result { + d.read_u128() + } +} + impl Encodable for isize { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_isize(*self) @@ -388,6 +407,20 @@ impl Decodable for i64 { } } +#[cfg(not(stage0))] +impl Encodable for i128 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_i128(*self) + } +} + +#[cfg(not(stage0))] +impl Decodable for i128 { + fn decode(d: &mut D) -> Result { + d.read_i128() + } +} + impl Encodable for str { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_str(self) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index fc5c6968544e8..f1e3996e825bf 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -301,6 +301,7 @@ #![feature(unwind_attributes)] #![feature(vec_push_all)] #![feature(zero_one)] +#![feature(i128)] #![cfg_attr(test, feature(update_panic_count))] // Explicitly import the prelude. The compiler uses this same unstable attribute @@ -395,6 +396,9 @@ pub use core::i16; pub use core::i32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::i64; +#[unstable(feature = "i128", issue = "35118")] +#[cfg(not(stage0))] +pub use core::i128; #[stable(feature = "rust1", since = "1.0.0")] pub use core::usize; #[stable(feature = "rust1", since = "1.0.0")] @@ -423,6 +427,9 @@ pub use core_collections::string; pub use core_collections::vec; #[stable(feature = "rust1", since = "1.0.0")] pub use std_unicode::char; +#[unstable(feature = "i128", issue = "35118")] +#[cfg(not(stage0))] +pub use core::u128; pub mod f32; pub mod f64; diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 0b38f5450b63f..a200da6c293ea 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -15,3 +15,4 @@ rustc_bitflags = { path = "../librustc_bitflags" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f72985fd91a3e..d1257a02a58f9 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -33,6 +33,8 @@ use std::u32; use serialize::{self, Encodable, Decodable, Encoder, Decoder}; +use rustc_i128::{u128, i128}; + /// An identifier contains a Name (index into the interner /// table) and a SyntaxContext to track renaming and /// macro expansion per Flatt et al., "Macros That Work Together" @@ -1062,7 +1064,7 @@ pub enum LitKind { /// A character literal (`'a'`) Char(char), /// An integer literal (`1`) - Int(u64, LitIntType), + Int(u128, LitIntType), /// A float literal (`1f64` or `1E10f64`) Float(Symbol, FloatTy), /// A float literal without a suffix (`1.0 or 1.0E10`) @@ -1171,6 +1173,7 @@ pub enum IntTy { I16, I32, I64, + I128, } impl fmt::Debug for IntTy { @@ -1192,15 +1195,16 @@ impl IntTy { IntTy::I8 => "i8", IntTy::I16 => "i16", IntTy::I32 => "i32", - IntTy::I64 => "i64" + IntTy::I64 => "i64", + IntTy::I128 => "i128", } } - pub fn val_to_string(&self, val: i64) -> String { + pub fn val_to_string(&self, val: i128) -> String { // cast to a u64 so we can correctly print INT64_MIN. All integral types // are parsed as u64, so we wouldn't want to print an extra negative // sign. - format!("{}{}", val as u64, self.ty_to_string()) + format!("{}{}", val as u128, self.ty_to_string()) } pub fn ty_max(&self) -> u64 { @@ -1208,7 +1212,9 @@ impl IntTy { IntTy::I8 => 0x80, IntTy::I16 => 0x8000, IntTy::Is | IntTy::I32 => 0x80000000, // FIXME: actually ni about Is - IntTy::I64 => 0x8000000000000000 + IntTy::I64 => 0x8000000000000000, + // FIXME: i128 + IntTy::I128 => !0u64, } } @@ -1219,6 +1225,7 @@ impl IntTy { IntTy::I16 => 16, IntTy::I32 => 32, IntTy::I64 => 64, + IntTy::I128 => 128, }) } } @@ -1230,6 +1237,7 @@ pub enum UintTy { U16, U32, U64, + U128, } impl UintTy { @@ -1239,11 +1247,12 @@ impl UintTy { UintTy::U8 => "u8", UintTy::U16 => "u16", UintTy::U32 => "u32", - UintTy::U64 => "u64" + UintTy::U64 => "u64", + UintTy::U128 => "u128", } } - pub fn val_to_string(&self, val: u64) -> String { + pub fn val_to_string(&self, val: u128) -> String { format!("{}{}", val, self.ty_to_string()) } @@ -1252,7 +1261,9 @@ impl UintTy { UintTy::U8 => 0xff, UintTy::U16 => 0xffff, UintTy::Us | UintTy::U32 => 0xffffffff, // FIXME: actually ni about Us - UintTy::U64 => 0xffffffffffffffff + UintTy::U64 => 0xffffffffffffffff, + // FIXME: i128 + UintTy::U128 => 0xffffffffffffffff, } } @@ -1263,6 +1274,7 @@ impl UintTy { UintTy::U16 => 16, UintTy::U32 => 32, UintTy::U64 => 64, + UintTy::U128 => 128, }) } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index c31bcfbd86992..ab8a49b41f25e 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -899,6 +899,8 @@ fn int_type_of_word(s: &str) -> Option { "u32" => Some(UnsignedInt(ast::UintTy::U32)), "i64" => Some(SignedInt(ast::IntTy::I64)), "u64" => Some(UnsignedInt(ast::UintTy::U64)), + "i128" => Some(SignedInt(ast::IntTy::I128)), + "u128" => Some(UnsignedInt(ast::UintTy::U128)), "isize" => Some(SignedInt(ast::IntTy::Is)), "usize" => Some(UnsignedInt(ast::UintTy::Us)), _ => None @@ -945,7 +947,8 @@ impl IntType { SignedInt(ast::IntTy::I8) | UnsignedInt(ast::UintTy::U8) | SignedInt(ast::IntTy::I16) | UnsignedInt(ast::UintTy::U16) | SignedInt(ast::IntTy::I32) | UnsignedInt(ast::UintTy::U32) | - SignedInt(ast::IntTy::I64) | UnsignedInt(ast::UintTy::U64) => true, + SignedInt(ast::IntTy::I64) | UnsignedInt(ast::UintTy::U64) | + SignedInt(ast::IntTy::I128) | UnsignedInt(ast::UintTy::U128) => true, SignedInt(ast::IntTy::Is) | UnsignedInt(ast::UintTy::Us) => false } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 7584fa3916de0..28f0c297303e3 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -16,6 +16,7 @@ use codemap::{dummy_spanned, respan, Spanned}; use ext::base::ExtCtxt; use ptr::P; use symbol::{Symbol, keywords}; +use rustc_i128::u128; // Transitional reexports so qquote can find the paths it is looking for mod syntax { @@ -712,23 +713,26 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr(sp, ast::ExprKind::Lit(P(respan(sp, lit)))) } fn expr_usize(&self, span: Span, i: usize) -> P { - self.expr_lit(span, ast::LitKind::Int(i as u64, ast::LitIntType::Unsigned(ast::UintTy::Us))) + self.expr_lit(span, ast::LitKind::Int(i as u128, + ast::LitIntType::Unsigned(ast::UintTy::Us))) } fn expr_isize(&self, sp: Span, i: isize) -> P { if i < 0 { - let i = (-i) as u64; + let i = (-i) as u128; let lit_ty = ast::LitIntType::Signed(ast::IntTy::Is); let lit = self.expr_lit(sp, ast::LitKind::Int(i, lit_ty)); self.expr_unary(sp, ast::UnOp::Neg, lit) } else { - self.expr_lit(sp, ast::LitKind::Int(i as u64, ast::LitIntType::Signed(ast::IntTy::Is))) + self.expr_lit(sp, ast::LitKind::Int(i as u128, + ast::LitIntType::Signed(ast::IntTy::Is))) } } fn expr_u32(&self, sp: Span, u: u32) -> P { - self.expr_lit(sp, ast::LitKind::Int(u as u64, ast::LitIntType::Unsigned(ast::UintTy::U32))) + self.expr_lit(sp, ast::LitKind::Int(u as u128, + ast::LitIntType::Unsigned(ast::UintTy::U32))) } fn expr_u8(&self, sp: Span, u: u8) -> P { - self.expr_lit(sp, ast::LitKind::Int(u as u64, ast::LitIntType::Unsigned(ast::UintTy::U8))) + self.expr_lit(sp, ast::LitKind::Int(u as u128, ast::LitIntType::Unsigned(ast::UintTy::U8))) } fn expr_bool(&self, sp: Span, value: bool) -> P { self.expr_lit(sp, ast::LitKind::Bool(value)) diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index aa777a19a9bcb..d2eb2636e6b31 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -19,6 +19,7 @@ use parse::token; use ptr::P; use tokenstream::{self, TokenTree}; + /// Quasiquoting works via token trees. /// /// This is registered as a set of expression syntax extension called quote! @@ -40,6 +41,7 @@ pub mod rt { pub use parse::new_parser_from_tts; pub use syntax_pos::{BytePos, Span, DUMMY_SP}; pub use codemap::{dummy_spanned}; + use rustc_i128::{u128}; pub trait ToTokens { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec; @@ -288,7 +290,7 @@ pub mod rt { } else { *self }; - let lit = ast::LitKind::Int(val as u64, ast::LitIntType::Signed($tag)); + let lit = ast::LitKind::Int(val as u128, ast::LitIntType::Signed($tag)); let lit = P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Lit(P(dummy_spanned(lit))), @@ -310,7 +312,7 @@ pub mod rt { (unsigned, $t:ty, $tag:expr) => ( impl ToTokens for $t { fn to_tokens(&self, cx: &ExtCtxt) -> Vec { - let lit = ast::LitKind::Int(*self as u64, ast::LitIntType::Unsigned($tag)); + let lit = ast::LitKind::Int(*self as u128, ast::LitIntType::Unsigned($tag)); dummy_spanned(lit).to_tokens(cx) } } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index b3b0ee6093ddf..5d6808284f67e 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -46,8 +46,9 @@ pub extern crate rustc_errors as errors; extern crate syntax_pos; extern crate rustc_data_structures; -extern crate serialize as rustc_serialize; // used by deriving +extern crate rustc_i128; +extern crate serialize as rustc_serialize; // used by deriving // A variant of 'try!' that panics on an Err. This is used as a crutch on the // way towards a non-panic!-prone parser. It should be used for fatal parsing diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 24178e1f675b5..32b61a88ac17f 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -28,6 +28,8 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::str; +use rustc_i128::u128; + pub type PResult<'a, T> = Result>; #[macro_use] @@ -557,18 +559,20 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a "i16" => ast::LitIntType::Signed(ast::IntTy::I16), "i32" => ast::LitIntType::Signed(ast::IntTy::I32), "i64" => ast::LitIntType::Signed(ast::IntTy::I64), + "i128" => ast::LitIntType::Signed(ast::IntTy::I128), "usize" => ast::LitIntType::Unsigned(ast::UintTy::Us), "u8" => ast::LitIntType::Unsigned(ast::UintTy::U8), "u16" => ast::LitIntType::Unsigned(ast::UintTy::U16), "u32" => ast::LitIntType::Unsigned(ast::UintTy::U32), "u64" => ast::LitIntType::Unsigned(ast::UintTy::U64), + "u128" => ast::LitIntType::Unsigned(ast::UintTy::U128), suf => { // i and u look like widths, so lets // give an error message along those lines if looks_like_width_suffix(&['i', 'u'], suf) { sd.struct_span_err(sp, &format!("invalid width `{}` for integer literal", &suf[1..])) - .help("valid widths are 8, 16, 32 and 64") + .help("valid widths are 8, 16, 32, 64 and 128") .emit(); } else { sd.struct_span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf)) @@ -585,7 +589,7 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \ string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix); - match u64::from_str_radix(s, base) { + match u128::from_str_radix(s, base) { Ok(r) => ast::LitKind::Int(r, ty), Err(_) => { // small bases are lexed as if they were base 10, e.g, the string diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a0ed50b33a46c..2bb38433a26ef 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -64,6 +64,8 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::slice; +use rustc_i128::u128; + bitflags! { flags Restrictions: u8 { const RESTRICTION_STMT_EXPR = 1 << 0, @@ -2044,7 +2046,7 @@ impl<'a> Parser<'a> { pub fn mk_lit_u32(&mut self, i: u32, attrs: ThinVec) -> P { let span = &self.span; let lv_lit = P(codemap::Spanned { - node: LitKind::Int(i as u64, ast::LitIntType::Unsigned(UintTy::U32)), + node: LitKind::Int(i as u128, ast::LitIntType::Unsigned(UintTy::U32)), span: *span }); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 7558f0256da18..60e1882fcf582 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -30,6 +30,8 @@ use std_inject; use symbol::{Symbol, keywords}; use tokenstream::{self, TokenTree}; +use rustc_i128::i128; + use std::ascii; use std::io::{self, Write, Read}; use std::iter; @@ -647,8 +649,7 @@ pub trait PrintState<'a> { ast::LitKind::Int(i, t) => { match t { ast::LitIntType::Signed(st) => { - word(self.writer(), - &st.val_to_string(i as i64)) + word(self.writer(), &st.val_to_string(i as i128)) } ast::LitIntType::Unsigned(ut) => { word(self.writer(), &ut.val_to_string(i)) diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 7f187d8d1c119..114bf437cfd3e 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -782,12 +782,13 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> & attr::ReprInt(attr::SignedInt(ast::IntTy::I16)) => "i16", attr::ReprInt(attr::SignedInt(ast::IntTy::I32)) => "i32", attr::ReprInt(attr::SignedInt(ast::IntTy::I64)) => "i64", + attr::ReprInt(attr::SignedInt(ast::IntTy::I128)) => "i128", attr::ReprInt(attr::UnsignedInt(ast::UintTy::Us)) => "usize", attr::ReprInt(attr::UnsignedInt(ast::UintTy::U8)) => "u8", attr::ReprInt(attr::UnsignedInt(ast::UintTy::U16)) => "u16", attr::ReprInt(attr::UnsignedInt(ast::UintTy::U32)) => "u32", - attr::ReprInt(attr::UnsignedInt(ast::UintTy::U64)) => "u64", + attr::ReprInt(attr::UnsignedInt(ast::UintTy::U128)) => "u128", } } } From b5260644af9cf556fe614d50e578f7c994013ae1 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 00:59:16 +0300 Subject: [PATCH 02/47] Tests for the 128 bit integers --- src/test/run-pass/i128.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/test/run-pass/u128.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 src/test/run-pass/i128.rs create mode 100644 src/test/run-pass/u128.rs diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs new file mode 100644 index 0000000000000..34a90aa4bc5de --- /dev/null +++ b/src/test/run-pass/i128.rs @@ -0,0 +1,38 @@ +fn main() { + let x: i128 = -1; + assert_eq!(0, !x); + let y: i128 = -2; + assert_eq!(!1, y); + let z: i128 = 0xABCD_EF; + assert_eq!(-z * -z * -z * -z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); + assert_eq!(-z + -z + -z + -z, -0x2AF3_7BC); + let k: i128 = -0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210; + assert_eq!(k + k, -0x2468_ACF1_3579_BDFF_DB97_530E_CA86_420); + assert_eq!(0, k - k); + assert_eq!(-0x1234_5678_9ABC_DEFF_EDCB_A987_5A86_421, k + z); + assert_eq!(-0x1000_0000_0000_0000_0000_0000_0000_000, + k + 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210); + assert_eq!(-0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42); + assert_eq!(-k, k / -1); + assert_eq!(-0x91A2_B3C4_D5E6_F8, k >> 65); + assert_eq!(-0xFDB9_7530_ECA8_6420_0000_0000_0000_0000, k << 65); + assert!(k < z); + assert!(y > k); + assert!(y < x); + assert_eq!(x as i64, -1); + assert_eq!(z as i64, 0xABCD_EF); + assert_eq!(k as i64, -0xFEDC_BA98_7654_3210); + assert_eq!(k as u128, 0xFEDC_BA98_7654_3210_0123_4567_89AB_CDF0); + assert_eq!(-k as u128, 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210); + // formatting + let j: i128 = -(1 << 67); + assert_eq!("-147573952589676412928", format!("{}", j)); + assert_eq!("fffffffffffffff80000000000000000", format!("{:x}", j)); + assert_eq!("3777777777777777777760000000000000000000000", format!("{:o}", j)); + assert_eq!("1111111111111111111111111111111111111111111111111111111111111\ + 0000000000000000000000000000000000000000000000000000000000000000000", + format!("{:b}", j)); + assert_eq!("-147573952589676412928", format!("{:?}", j)); + // common traits + x.clone(); +} diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs new file mode 100644 index 0000000000000..0debc57a8a089 --- /dev/null +++ b/src/test/run-pass/u128.rs @@ -0,0 +1,35 @@ +fn main() { + let x: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFF; + assert_eq!(0, !x); + let y: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFE; + assert_eq!(!1, y); + let z: u128 = 0xABCD_EF; + assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); + assert_eq!(z + z + z + z, 0x2AF3_7BC); + let k: u128 = 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210; + assert_eq!(k + k, 0x2468_ACF1_3579_BDFF_DB97_530E_CA86_420); + assert_eq!(0, k - k); + assert_eq!(0x1234_5678_9ABC_DEFF_EDCB_A987_5A86_421, k - z); + assert_eq!(0x1000_0000_0000_0000_0000_0000_0000_000, + k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210); + assert_eq!(0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42); + assert_eq!(0x91A2_B3C4_D5E6_F7, k >> 65); + assert_eq!(0xFDB9_7530_ECA8_6420_0000_0000_0000_0000, k << 65); + assert!(k > z); + assert!(y > k); + assert!(y < x); + assert_eq!(x as u64, !0); + assert_eq!(z as u64, 0xABCD_EF); + assert_eq!(k as u64, 0xFEDC_BA98_7654_3210); + assert_eq!(k as i128, 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210); + // formatting + let j: u128 = 1 << 67; + assert_eq!("147573952589676412928", format!("{}", j)); + assert_eq!("80000000000000000", format!("{:x}", j)); + assert_eq!("20000000000000000000000", format!("{:o}", j)); + assert_eq!("10000000000000000000000000000000000000000000000000000000000000000000", + format!("{:b}", j)); + assert_eq!("147573952589676412928", format!("{:?}", j)); + // common traits + x.clone(); +} From d4d5be18b702b5fd8b38b67d503860f788a14acd Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 02:15:15 +0300 Subject: [PATCH 03/47] Feature gate the 128 bit types Dangling a carrot in front of a donkey. This commit includes manual merge conflict resolution changes from a rebase by @est31. --- src/libcore/lib.rs | 1 + src/librustc_i128/lib.rs | 1 + src/librustc_resolve/lib.rs | 15 ++++++++++++++- src/librustc_typeck/check/mod.rs | 7 +++++++ src/libsyntax/feature_gate.rs | 15 +++++++++++++++ src/test/compile-fail/i128-feature-2.rs | 20 ++++++++++++++++++++ src/test/compile-fail/i128-feature.rs | 8 ++++++++ src/test/run-pass/i128.rs | 2 ++ src/test/run-pass/u128.rs | 9 +++++++++ 9 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/i128-feature-2.rs create mode 100644 src/test/compile-fail/i128-feature.rs diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 443f4b2ea8e42..2cb2f81fcffb5 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -90,6 +90,7 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(never_type)] +#![cfg_attr(not(stage0), feature(i128_type))] #![feature(prelude_import)] #[prelude_import] diff --git a/src/librustc_i128/lib.rs b/src/librustc_i128/lib.rs index 14604fc66ba86..5b50c2b493ab2 100644 --- a/src/librustc_i128/lib.rs +++ b/src/librustc_i128/lib.rs @@ -1,4 +1,5 @@ #![allow(non_camel_case_types)] +#![feature(i128_type)] #[cfg(stage0)] pub type i128 = i64; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 53fa87b52250d..f27a5c80b9c99 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -61,6 +61,7 @@ use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, Generics}; use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Local, Mutability, Pat, PatKind, Path}; use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind}; +use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use errors::DiagnosticBuilder; @@ -2309,8 +2310,20 @@ impl<'a> Resolver<'a> { PathResult::Module(..) | PathResult::Failed(..) if (ns == TypeNS || path.len() > 1) && self.primitive_type_table.primitive_types.contains_key(&path[0].name) => { + let prim = self.primitive_type_table.primitive_types[&path[0].name]; + match prim { + TyUint(UintTy::U128) | TyInt(IntTy::I128) => { + if !this.session.features.borrow().i128_type { + emit_feature_err(&this.session.parse_sess.span_diagnostic, + "i128_type", span, GateIssue::Language, + "128-bit type is unstable"); + + } + } + _ => {} + } PathResolution { - base_def: Def::PrimTy(self.primitive_type_table.primitive_types[&path[0].name]), + base_def: Def::PrimTy(prim), depth: path.len() - 1, } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7275fbd12036b..051a4200235ab 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1330,6 +1330,13 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx); + if repr_type_ty == ccx.tcx.types.i128 || repr_type_ty == ccx.tcx.types.u128 { + if !ccx.tcx.sess.features.borrow().i128_type { + emit_feature_err(&ccx.tcx.sess.parse_sess.span_diagnostic, + "i128_type", sp, GateIssue::Language, "128-bit type is unstable"); + } + } + for v in vs { if let Some(e) = v.node.disr_expr { check_const_with_type(ccx, e, repr_type_ty, e.node_id); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 625af803458b5..a3f2cd3a0cdb8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -321,6 +321,9 @@ declare_features! ( // `extern "ptx-*" fn()` (active, abi_ptx, "1.15.0", None), + + // The `i128` type + (active, i128_type, "1.15.0", Some(35118)), ); declare_features! ( @@ -1215,6 +1218,18 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, loop_break_value, e.span, "`break` with a value is experimental"); } + ast::ExprKind::Lit(ref lit) => { + if let ast::LitKind::Int(_, ref ty) = lit.node { + match *ty { + ast::LitIntType::Signed(ast::IntTy::I128) | + ast::LitIntType::Unsigned(ast::UintTy::U128) => { + gate_feature_post!(&self, i128_type, e.span, + "128-bit integers are not stable"); + } + _ => {} + } + } + } _ => {} } visit::walk_expr(self, e); diff --git a/src/test/compile-fail/i128-feature-2.rs b/src/test/compile-fail/i128-feature-2.rs new file mode 100644 index 0000000000000..b450ba33fdf82 --- /dev/null +++ b/src/test/compile-fail/i128-feature-2.rs @@ -0,0 +1,20 @@ +fn test1() -> i128 { //~ ERROR 128-bit type is unstable + 0 +} + +fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable + 0 +} + +fn test3() { + let x: i128 = 0; //~ ERROR 128-bit type is unstable +} + +fn test3_2() { + let x: u128 = 0; //~ ERROR 128-bit type is unstable +} + +#[repr(u128)] +enum A { //~ ERROR 128-bit type is unstable + A(u64) +} diff --git a/src/test/compile-fail/i128-feature.rs b/src/test/compile-fail/i128-feature.rs new file mode 100644 index 0000000000000..640cda1469d28 --- /dev/null +++ b/src/test/compile-fail/i128-feature.rs @@ -0,0 +1,8 @@ +fn test2() { + 0i128; //~ ERROR 128-bit integers are not stable +} + +fn test2_2() { + 0u128; //~ ERROR 128-bit integers are not stable +} + diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index 34a90aa4bc5de..85a3f00e946bf 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -1,3 +1,5 @@ +#![feature(i128_type)] + fn main() { let x: i128 = -1; assert_eq!(0, !x); diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs index 0debc57a8a089..57e1ea282e03c 100644 --- a/src/test/run-pass/u128.rs +++ b/src/test/run-pass/u128.rs @@ -1,8 +1,15 @@ +#![feature(i128_type)] + fn main() { let x: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFF; assert_eq!(0, !x); + assert_eq!(0, !x); let y: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFE; assert_eq!(!1, y); + assert_eq!(x, y | 1); + assert_eq!(0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFE, + y & + 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF); let z: u128 = 0xABCD_EF; assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); assert_eq!(z + z + z + z, 0x2AF3_7BC); @@ -13,6 +20,8 @@ fn main() { assert_eq!(0x1000_0000_0000_0000_0000_0000_0000_000, k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210); assert_eq!(0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42); + assert_eq!(0, k % 42); + assert_eq!(15, z % 42); assert_eq!(0x91A2_B3C4_D5E6_F7, k >> 65); assert_eq!(0xFDB9_7530_ECA8_6420_0000_0000_0000_0000, k << 65); assert!(k > z); From 4e2b946e6539b4866c672cda6958fc1a2fe80687 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 02:37:19 +0300 Subject: [PATCH 04/47] Cleanup FIXMEs --- src/librustc_const_math/int.rs | 5 ----- src/librustc_mir/build/expr/as_rvalue.rs | 1 - src/libsyntax/ast.rs | 22 ---------------------- 3 files changed, 28 deletions(-) diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs index a1b6ecf153a6e..7af61d6f27402 100644 --- a/src/librustc_const_math/int.rs +++ b/src/librustc_const_math/int.rs @@ -31,7 +31,6 @@ pub enum ConstInt { U64(u64), U128(u128), Usize(ConstUsize), - // FIXME: i128 Infer(u128), InferSigned(i128), } @@ -56,7 +55,6 @@ macro_rules! bounds { mod ubounds { #![allow(dead_code)] use rustc_i128::{u128, i128}; - // FIXME: min are problably all wrong for signed here. bounds!{u128: 0, i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX u128 U128MIN U128MAX @@ -155,7 +153,6 @@ impl ConstInt { I16(i) if i < 0 => InferSigned(i as i128), I32(i) if i < 0 => InferSigned(i as i128), I64(i) if i < 0 => InferSigned(i as i128), - // FIXME: 1128, compare with i128 I128(i) if i < 0 => InferSigned(i as i128), Isize(Is16(i)) if i < 0 => InferSigned(i as i128), Isize(Is32(i)) if i < 0 => InferSigned(i as i128), @@ -165,7 +162,6 @@ impl ConstInt { I16(i) => Infer(i as u128), I32(i) => Infer(i as u128), I64(i) => Infer(i as u128), - // FIXME: i128 I128(i) => Infer(i as u128), Isize(Is16(i)) => Infer(i as u128), Isize(Is32(i)) => Infer(i as u128), @@ -174,7 +170,6 @@ impl ConstInt { U16(i) => Infer(i as u128), U32(i) => Infer(i as u128), U64(i) => Infer(i as u128), - // FIXME: i128 U128(i) => Infer(i as u128), Usize(Us16(i)) => Infer(i as u128), Usize(Us32(i)) => Infer(i as u128), diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 0aad96d27cc06..8199a08c852de 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -375,7 +375,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast::IntTy::I16 => ConstInt::I16(i16::min_value()), ast::IntTy::I32 => ConstInt::I32(i32::min_value()), ast::IntTy::I64 => ConstInt::I64(i64::min_value()), - // FIXME: i128 ast::IntTy::I128 => ConstInt::I128(i128::min_value()), ast::IntTy::Is => { let int_ty = self.hir.tcx().sess.target.int_type; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d1257a02a58f9..60402fe1a6607 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1207,17 +1207,6 @@ impl IntTy { format!("{}{}", val as u128, self.ty_to_string()) } - pub fn ty_max(&self) -> u64 { - match *self { - IntTy::I8 => 0x80, - IntTy::I16 => 0x8000, - IntTy::Is | IntTy::I32 => 0x80000000, // FIXME: actually ni about Is - IntTy::I64 => 0x8000000000000000, - // FIXME: i128 - IntTy::I128 => !0u64, - } - } - pub fn bit_width(&self) -> Option { Some(match *self { IntTy::Is => return None, @@ -1256,17 +1245,6 @@ impl UintTy { format!("{}{}", val, self.ty_to_string()) } - pub fn ty_max(&self) -> u64 { - match *self { - UintTy::U8 => 0xff, - UintTy::U16 => 0xffff, - UintTy::Us | UintTy::U32 => 0xffffffff, // FIXME: actually ni about Us - UintTy::U64 => 0xffffffffffffffff, - // FIXME: i128 - UintTy::U128 => 0xffffffffffffffff, - } - } - pub fn bit_width(&self) -> Option { Some(match *self { UintTy::Us => return None, From 64de4e2731cff74e0c4b81d9389734dee7229db2 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 15:58:40 +0300 Subject: [PATCH 05/47] Fix LEB128 to work with the stage1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stage 1 can’t really handle negative 128-bit literals, but an equivalent bit-not is fine --- src/librustc_i128/lib.rs | 2 +- src/libserialize/leb128.rs | 48 +++++++++++++++++++------------------- src/libsyntax/ast.rs | 4 ++-- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/librustc_i128/lib.rs b/src/librustc_i128/lib.rs index 5b50c2b493ab2..65533b5011b82 100644 --- a/src/librustc_i128/lib.rs +++ b/src/librustc_i128/lib.rs @@ -1,5 +1,5 @@ #![allow(non_camel_case_types)] -#![feature(i128_type)] +#![cfg_attr(not(stage0), feature(i128_type))] #[cfg(stage0)] pub type i128 = i64; diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs index 7a4d1c7a0e449..04ebffd47f20d 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -87,12 +87,14 @@ pub fn write_signed_leb128_to(mut value: i128, mut write: W) -> usize value >>= 7; let more = !((((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && ((byte & 0x40) != 0)))); + if more { byte |= 0x80; // Mark this byte to show that more bytes will follow. } write(position, byte); position += 1; + if !more { break; } @@ -106,30 +108,28 @@ pub fn write_signed_leb128(out: &mut Vec, start_position: usize, value: i128 #[inline] pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i128, usize) { - let (l, r) = read_unsigned_leb128(data, start_position); - (l as i128, r) - // let mut result = 0; - // let mut shift = 0; - // let mut position = start_position; - // let mut byte; - - // loop { - // byte = data[position]; - // position += 1; - // result |= ((byte & 0x7F) as i128) << shift; - // shift += 7; - - // if (byte & 0x80) == 0 { - // break; - // } - // } - - // if (shift < 64) && ((byte & 0x40) != 0) { - // // sign extend - // result |= -(1 << shift); - // } - - // (result, position - start_position) + let mut result = 0; + let mut shift = 0; + let mut position = start_position; + let mut byte; + + loop { + byte = data[position]; + position += 1; + result |= ((byte & 0x7F) as i128) << shift; + shift += 7; + + if (byte & 0x80) == 0 { + break; + } + } + + if (shift < 64) && ((byte & 0x40) != 0) { + // sign extend + result |= -(1 << shift); + } + + (result, position - start_position) } #[test] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 60402fe1a6607..da4b787160fb2 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1201,8 +1201,8 @@ impl IntTy { } pub fn val_to_string(&self, val: i128) -> String { - // cast to a u64 so we can correctly print INT64_MIN. All integral types - // are parsed as u64, so we wouldn't want to print an extra negative + // cast to a u128 so we can correctly print INT128_MIN. All integral types + // are parsed as u128, so we wouldn't want to print an extra negative // sign. format!("{}{}", val as u128, self.ty_to_string()) } From 64fbce6826bd14594e645847fd11be290ca9fade Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 16:10:38 +0300 Subject: [PATCH 06/47] Tidy This commit includes manual merge conflict resolution changes from a rebase by @est31. --- src/Cargo.lock | 14 ++++++++++++++ src/librustc_i128/lib.rs | 9 +++++++++ src/test/compile-fail/i128-feature-2.rs | 9 +++++++++ src/test/compile-fail/i128-feature.rs | 9 +++++++++ src/test/run-pass/i128.rs | 9 +++++++++ src/test/run-pass/u128.rs | 9 +++++++++ 6 files changed, 59 insertions(+) diff --git a/src/Cargo.lock b/src/Cargo.lock index 9cd77e71b82dd..19e394f301b49 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -201,6 +201,7 @@ dependencies = [ name = "proc_macro" version = "0.0.0" dependencies = [ + "rustc_i128 0.0.0", "syntax 0.0.0", ] @@ -249,6 +250,7 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_i128 0.0.0", "rustc_llvm 0.0.0", "serialize 0.0.0", "syntax 0.0.0", @@ -308,6 +310,7 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_i128 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", @@ -318,6 +321,7 @@ name = "rustc_const_math" version = "0.0.0" dependencies = [ "log 0.0.0", + "rustc_i128 0.0.0", "serialize 0.0.0", "syntax 0.0.0", ] @@ -372,6 +376,10 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc_i128" +version = "0.0.0" + [[package]] name = "rustc_incremental" version = "0.0.0" @@ -393,6 +401,7 @@ dependencies = [ "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", + "rustc_i128 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -418,6 +427,7 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_i128 0.0.0", "rustc_llvm 0.0.0", "serialize 0.0.0", "syntax 0.0.0", @@ -437,6 +447,7 @@ dependencies = [ "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", + "rustc_i128 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -519,6 +530,7 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_i128 0.0.0", "rustc_incremental 0.0.0", "rustc_llvm 0.0.0", "rustc_platform_intrinsics 0.0.0", @@ -574,6 +586,7 @@ name = "serialize" version = "0.0.0" dependencies = [ "log 0.0.0", + "rustc_i128 0.0.0", ] [[package]] @@ -619,6 +632,7 @@ dependencies = [ "rustc_bitflags 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_i128 0.0.0", "serialize 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/librustc_i128/lib.rs b/src/librustc_i128/lib.rs index 65533b5011b82..c5b52148d1e8a 100644 --- a/src/librustc_i128/lib.rs +++ b/src/librustc_i128/lib.rs @@ -1,3 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. #![allow(non_camel_case_types)] #![cfg_attr(not(stage0), feature(i128_type))] diff --git a/src/test/compile-fail/i128-feature-2.rs b/src/test/compile-fail/i128-feature-2.rs index b450ba33fdf82..4a76d39921842 100644 --- a/src/test/compile-fail/i128-feature-2.rs +++ b/src/test/compile-fail/i128-feature-2.rs @@ -1,3 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. fn test1() -> i128 { //~ ERROR 128-bit type is unstable 0 } diff --git a/src/test/compile-fail/i128-feature.rs b/src/test/compile-fail/i128-feature.rs index 640cda1469d28..87dda469f9390 100644 --- a/src/test/compile-fail/i128-feature.rs +++ b/src/test/compile-fail/i128-feature.rs @@ -1,3 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. fn test2() { 0i128; //~ ERROR 128-bit integers are not stable } diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index 85a3f00e946bf..57ef6e55935c2 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -1,3 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. #![feature(i128_type)] fn main() { diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs index 57e1ea282e03c..4c6ae7b0e786e 100644 --- a/src/test/run-pass/u128.rs +++ b/src/test/run-pass/u128.rs @@ -1,3 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. #![feature(i128_type)] fn main() { From ec1fdfe1c392c61dffebf0db0f348de566ae0804 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 16:48:35 +0300 Subject: [PATCH 07/47] Makefiles support for rustc_i128 crate This commit includes manual merge conflict resolution changes from a rebase by @est31. --- mk/crates.mk | 25 +++++++++++++++---------- src/librustc_i128/lib.rs | 2 ++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/mk/crates.mk b/mk/crates.mk index 79df941aeb3ee..732db8022fcf5 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -59,7 +59,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_platform_intrinsics rustc_errors \ rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \ - rustc_const_eval rustc_const_math rustc_incremental proc_macro + rustc_const_eval rustc_const_math rustc_incremental proc_macro rustc_i128 HOST_CRATES := syntax syntax_ext proc_macro_tokens proc_macro_plugin syntax_pos $(RUSTC_CRATES) \ rustdoc fmt_macros flate arena graphviz log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator @@ -92,23 +92,26 @@ DEPS_getopts := std DEPS_graphviz := std DEPS_log := std DEPS_num := std -DEPS_serialize := std log +DEPS_serialize := std log rustc_i128 DEPS_term := std DEPS_test := std getopts term native:rust_test_helpers +DEPS_rustc_i128 = std -DEPS_syntax := std term serialize log arena libc rustc_bitflags std_unicode rustc_errors syntax_pos rustc_data_structures +DEPS_syntax := std term serialize log arena libc rustc_bitflags std_unicode rustc_errors \ + syntax_pos rustc_data_structures rustc_i128 DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros proc_macro +DEPS_proc_macro := syntax syntax_pos rustc_plugin log DEPS_syntax_pos := serialize DEPS_proc_macro_tokens := syntax syntax_pos log DEPS_proc_macro_plugin := syntax syntax_pos rustc_plugin log proc_macro_tokens -DEPS_rustc_const_math := std syntax log serialize +DEPS_rustc_const_math := std syntax log serialize rustc_i128 DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize \ - rustc_back graphviz syntax_pos + rustc_back graphviz syntax_pos rustc_i128 DEPS_rustc := syntax fmt_macros flate arena serialize getopts \ log graphviz rustc_llvm rustc_back rustc_data_structures\ - rustc_const_math syntax_pos rustc_errors + rustc_const_math syntax_pos rustc_errors rustc_i128 DEPS_rustc_back := std syntax flate log libc DEPS_rustc_borrowck := rustc log graphviz syntax syntax_pos rustc_errors rustc_mir DEPS_rustc_data_structures := std log serialize libc @@ -119,19 +122,20 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo rustc_passes rustc_save_analysis rustc_const_eval \ rustc_incremental syntax_pos rustc_errors proc_macro rustc_data_structures DEPS_rustc_errors := log libc serialize syntax_pos -DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval +DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval rustc_i128 DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags DEPS_proc_macro := std syntax DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rustc_const_math \ - proc_macro syntax_ext + proc_macro syntax_ext rustc_i128 DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors -DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags +DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags \ + rustc_i128 DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors DEPS_rustc_platform_intrinsics := std DEPS_rustc_plugin := rustc rustc_metadata syntax syntax_pos rustc_errors DEPS_rustc_privacy := rustc log syntax syntax_pos DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ - log syntax serialize rustc_llvm rustc_platform_intrinsics \ + log syntax serialize rustc_llvm rustc_platform_intrinsics rustc_i128 \ rustc_const_math rustc_const_eval rustc_incremental rustc_errors syntax_pos DEPS_rustc_incremental := rustc syntax_pos serialize rustc_data_structures DEPS_rustc_save_analysis := rustc log syntax syntax_pos serialize @@ -159,6 +163,7 @@ ONLY_RLIB_alloc := 1 ONLY_RLIB_rand := 1 ONLY_RLIB_collections := 1 ONLY_RLIB_std_unicode := 1 +ONLY_RLIB_rustc_i128 := 1 ONLY_RLIB_rustc_bitflags := 1 ONLY_RLIB_alloc_system := 1 ONLY_RLIB_alloc_jemalloc := 1 diff --git a/src/librustc_i128/lib.rs b/src/librustc_i128/lib.rs index c5b52148d1e8a..a9770396e7882 100644 --- a/src/librustc_i128/lib.rs +++ b/src/librustc_i128/lib.rs @@ -9,6 +9,8 @@ // except according to those terms. #![allow(non_camel_case_types)] #![cfg_attr(not(stage0), feature(i128_type))] +#![crate_type="rlib"] +#![crate_name="rustc_i128"] #[cfg(stage0)] pub type i128 = i64; From d9eb756cbfdd0f4388bb7bd203d8d43761ff7942 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 19:29:15 +0300 Subject: [PATCH 08/47] Wrapping and attempt at LLVM 3.7 compat This commit includes manual merge conflict resolution changes from a rebase by @est31. --- src/libcore/num/wrapping.rs | 2 ++ src/librustc_llvm/ffi.rs | 1 - src/librustc_trans/type_.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 50d64838a5c0b..b3c2c25551e0d 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -298,6 +298,8 @@ macro_rules! wrapping_impl { } wrapping_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +wrapping_impl! { u128 i128 } mod shift_max { #![allow(non_upper_case_globals)] diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index efb06bdb73e3a..acf2bd50847c3 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -508,7 +508,6 @@ extern "C" { pub fn LLVMInt16TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMInt32TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMInt64TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMInt128TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMIntTypeInContext(C: ContextRef, NumBits: c_uint) -> TypeRef; pub fn LLVMGetIntTypeWidth(IntegerTy: TypeRef) -> c_uint; diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index e8d8db2956b8a..5e4fe015d7678 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -95,7 +95,7 @@ impl Type { } pub fn i128(ccx: &CrateContext) -> Type { - ty!(llvm::LLVMInt128TypeInContext(ccx.llcx())) + ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), 128)) } // Creates an integer type with the given number of bits, e.g. i24 From db2527add3a9442266e7d31a218b91cda255bd4a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 22:38:14 +0300 Subject: [PATCH 09/47] Fix parse-fail and compile-fail tests --- src/test/compile-fail/const-tup-index-span.rs | 2 +- src/test/compile-fail/oversized-literal.rs | 13 ------------- src/test/parse-fail/int-literal-too-large-span.rs | 4 ++-- src/test/parse-fail/issue-5544-a.rs | 2 +- src/test/parse-fail/issue-5544-b.rs | 2 +- src/test/parse-fail/lex-bad-numeric-literals.rs | 4 ++-- 6 files changed, 7 insertions(+), 20 deletions(-) delete mode 100644 src/test/compile-fail/oversized-literal.rs diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs index 8f7ec9de58af2..f3fb92e2b2206 100644 --- a/src/test/compile-fail/const-tup-index-span.rs +++ b/src/test/compile-fail/const-tup-index-span.rs @@ -10,7 +10,7 @@ // Test spans of errors -const TUP: (usize,) = 5 << 64; +const TUP: (usize,) = 5usize << 64; //~^ ERROR E0080 //~| attempt to shift left with overflow const ARR: [i32; TUP.0] = []; diff --git a/src/test/compile-fail/oversized-literal.rs b/src/test/compile-fail/oversized-literal.rs deleted file mode 100644 index 5416bcacf3d59..0000000000000 --- a/src/test/compile-fail/oversized-literal.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn main() { - println!("{}", 18446744073709551616u64); //~ error: int literal is too large -} diff --git a/src/test/parse-fail/int-literal-too-large-span.rs b/src/test/parse-fail/int-literal-too-large-span.rs index c4b25d4357933..1af8df7d2f644 100644 --- a/src/test/parse-fail/int-literal-too-large-span.rs +++ b/src/test/parse-fail/int-literal-too-large-span.rs @@ -13,7 +13,7 @@ // issue #17123 fn main() { - 100000000000000000000000000000000 //~ ERROR int literal is too large - + 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + //~^ ERROR int literal is too large ; // the span shouldn't point to this. } diff --git a/src/test/parse-fail/issue-5544-a.rs b/src/test/parse-fail/issue-5544-a.rs index f406b2cc803fc..cf1500e34d874 100644 --- a/src/test/parse-fail/issue-5544-a.rs +++ b/src/test/parse-fail/issue-5544-a.rs @@ -11,6 +11,6 @@ // compile-flags: -Z parse-only fn main() { - let __isize = 18446744073709551616; // 2^64 + let __isize = 340282366920938463463374607431768211456; // 2^128 //~^ ERROR int literal is too large } diff --git a/src/test/parse-fail/issue-5544-b.rs b/src/test/parse-fail/issue-5544-b.rs index 898b092064518..8c0b6741cb804 100644 --- a/src/test/parse-fail/issue-5544-b.rs +++ b/src/test/parse-fail/issue-5544-b.rs @@ -11,6 +11,6 @@ // compile-flags: -Z parse-only fn main() { - let __isize = 0xff_ffff_ffff_ffff_ffff; + let __isize = 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ff; //~^ ERROR int literal is too large } diff --git a/src/test/parse-fail/lex-bad-numeric-literals.rs b/src/test/parse-fail/lex-bad-numeric-literals.rs index bb97b037a0028..d495a8edd09a4 100644 --- a/src/test/parse-fail/lex-bad-numeric-literals.rs +++ b/src/test/parse-fail/lex-bad-numeric-literals.rs @@ -23,8 +23,8 @@ fn main() { 0o; //~ ERROR: no valid digits 1e+; //~ ERROR: expected at least one digit in exponent 0x539.0; //~ ERROR: hexadecimal float literal is not supported - 99999999999999999999999999999999; //~ ERROR: int literal is too large - 99999999999999999999999999999999; //~ ERROR: int literal is too large + 9900000000000000000000000000999999999999999999999999999999; //~ ERROR: int literal is too large + 9900000000000000000000000000999999999999999999999999999999; //~ ERROR: int literal is too large 0x; //~ ERROR: no valid digits 0xu32; //~ ERROR: no valid digits 0ou32; //~ ERROR: no valid digits From 508fef5dffa5e0fad578f6faa13cfce86ead9463 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 25 Aug 2016 02:16:21 +0300 Subject: [PATCH 10/47] impl Step for iu128 Also fix the leb128 tests --- src/libcore/iter/range.rs | 2 ++ src/libserialize/leb128.rs | 11 +---------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index e6f21d6c17ae0..9d22037882f21 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -242,6 +242,8 @@ step_impl_signed!(i64); // assume here that it is less than 64-bits. #[cfg(not(target_pointer_width = "64"))] step_impl_no_between!(u64 i64); +#[cfg(not(stage0))] +step_impl_no_between!(u128 i128); /// An adapter for stepping range iterators by a custom amount. /// diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs index 04ebffd47f20d..55ae7ae10f4eb 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -154,22 +154,13 @@ fn test_unsigned_leb128() { #[test] fn test_signed_leb128() { - let mut values = Vec::new(); - - let mut i = -500; - while i < 500 { - values.push(i * 123457i64); - i += 1; - } - + let values: Vec<_> = (-500..500).map(|i| i * 0x12345789ABCDEF).collect(); let mut stream = Vec::new(); - for &x in &values { let pos = stream.len(); let bytes_written = write_signed_leb128(&mut stream, pos, x); assert_eq!(stream.len(), pos + bytes_written); } - let mut pos = 0; for &x in &values { let (value, bytes_read) = read_signed_leb128(&mut stream, pos); From 9aad2d551e76d80783e812be70de5f49fb038b5e Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 26 Aug 2016 01:32:46 +0300 Subject: [PATCH 11/47] Add a way to retrieve constant value in 128 bits Fixes rebase fallout, makes code correct in presence of 128-bit constants. This commit includes manual merge conflict resolution changes from a rebase by @est31. --- src/librustc_const_math/int.rs | 36 ++++++++++++++++- src/librustc_llvm/ffi.rs | 2 + src/librustc_trans/common.rs | 22 +++++++++-- src/librustc_trans/consts.rs | 1 - src/librustc_trans/glue.rs | 5 ++- src/librustc_trans/intrinsic.rs | 6 ++- src/librustc_trans/mir/block.rs | 16 ++++---- src/librustc_trans/mir/constant.rs | 63 +++++++----------------------- src/librustdoc/clean/mod.rs | 4 +- src/rustllvm/RustWrapper.cpp | 16 ++++++++ 10 files changed, 101 insertions(+), 70 deletions(-) diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs index 7af61d6f27402..59eb4b70aa8ff 100644 --- a/src/librustc_const_math/int.rs +++ b/src/librustc_const_math/int.rs @@ -58,7 +58,8 @@ mod ubounds { bounds!{u128: 0, i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX u128 U128MIN U128MAX - isize IMIN IMAX usize UMIN UMAX + // do not add constants for isize/usize, because these are guaranteed to be wrong for + // arbitrary host/target combinations } } @@ -78,11 +79,42 @@ mod ibounds { bounds!{i128, i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX - isize IMIN IMAX usize UMIN UMAX + // do not add constants for isize/usize, because these are guaranteed to be wrong for + // arbitrary host/target combinations } } impl ConstInt { + /// Creates a new unsigned ConstInt with matching type while also checking that overflow does + /// not happen. + pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option { + match ty { + UintTy::U8 if val <= ubounds::U8MAX => Some(U8(val as u8)), + UintTy::U16 if val <= ubounds::U16MAX => Some(U16(val as u16)), + UintTy::U32 if val <= ubounds::U32MAX => Some(U32(val as u32)), + UintTy::U64 if val <= ubounds::U64MAX => Some(U64(val as u64)), + UintTy::Us if val <= ubounds::U64MAX => ConstUsize::new(val as u64, usize_ty).ok() + .map(Usize), + UintTy::U128 => Some(U128(val)), + _ => None + } + } + + /// Creates a new unsigned ConstInt with matching type while also checking that overflow does + /// not happen. + pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option { + match ty { + IntTy::I8 if val <= ibounds::I8MAX => Some(I8(val as i8)), + IntTy::I16 if val <= ibounds::I16MAX => Some(I16(val as i16)), + IntTy::I32 if val <= ibounds::I32MAX => Some(I32(val as i32)), + IntTy::I64 if val <= ibounds::I64MAX => Some(I64(val as i64)), + IntTy::Is if val <= ibounds::I64MAX => ConstIsize::new(val as i64, isize_ty).ok() + .map(Isize), + IntTy::I128 => Some(I128(val)), + _ => None + } + } + /// If either value is `Infer` or `InferSigned`, try to turn the value into the type of /// the other value. If both values have no type, don't do anything pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> { diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index acf2bd50847c3..fb188252075e6 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -582,6 +582,8 @@ extern "C" { pub fn LLVMConstReal(RealTy: TypeRef, N: f64) -> ValueRef; pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong; pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong; + pub fn LLVMRustConstInt128Get(ConstantVal: ValueRef, SExt: bool, + high: *mut u64, low: *mut u64) -> bool; // Operations on composite constants diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 3e564a7c6ed4d..f4c7d2973bf66 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -592,20 +592,34 @@ fn is_const_integral(v: ValueRef) -> bool { } } -pub fn const_to_opt_int(v: ValueRef) -> Option { + +#[cfg(stage0)] +pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option { unsafe { if is_const_integral(v) { - Some(llvm::LLVMConstIntGetSExtValue(v)) + if !sign_ext { + Some(llvm::LLVMConstIntGetZExtValue(v)) + } else { + Some(llvm::LLVMConstIntGetSExtValue(v) as u64) + } } else { None } } } -pub fn const_to_opt_uint(v: ValueRef) -> Option { +#[cfg(not(stage0))] +pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option { unsafe { if is_const_integral(v) { - Some(llvm::LLVMConstIntGetZExtValue(v)) + let (mut lo, mut hi) = (0u64, 0u64); + let success = llvm::LLVMRustConstInt128Get(v, sign_ext, + &mut hi as *mut u64, &mut lo as *mut u64); + if success { + Some(((hi as u128) << 64) | (lo as u128)) + } else { + None + } } else { None } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index fd921b3c43290..2e2644d91bb6c 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -24,7 +24,6 @@ use monomorphize::{Instance}; use type_::Type; use type_of; use rustc::ty; -use rustc_i128::{i128, u128}; use rustc::hir; diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 3989dae553ffc..62141369caec1 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -346,11 +346,12 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, // Choose max of two known alignments (combined value must // be aligned according to more restrictive of the two). - let align = match (const_to_opt_uint(sized_align), const_to_opt_uint(unsized_align)) { + let align = match (const_to_opt_u128(sized_align, false), + const_to_opt_u128(unsized_align, false)) { (Some(sized_align), Some(unsized_align)) => { // If both alignments are constant, (the sized_align should always be), then // pick the correct alignment statically. - C_uint(ccx, std::cmp::max(sized_align, unsized_align)) + C_uint(ccx, std::cmp::max(sized_align, unsized_align) as u64) } _ => bcx.select(bcx.icmp(llvm::IntUGT, sized_align, unsized_align), sized_align, diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index cc55a2b3e9a58..c4129b346e409 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -32,6 +32,8 @@ use syntax::symbol::Symbol; use rustc::session::Session; use syntax_pos::Span; +use rustc_i128::u128; + use std::cmp::Ordering; use std::iter; @@ -1019,7 +1021,7 @@ fn generic_simd_intrinsic<'a, 'tcx>( in_elem, in_ty, ret_ty, ret_ty.simd_type(tcx)); - let total_len = in_len as u64 * 2; + let total_len = in_len as u128 * 2; let vector = llargs[2]; @@ -1027,7 +1029,7 @@ fn generic_simd_intrinsic<'a, 'tcx>( .map(|i| { let arg_idx = i; let val = const_get_elt(vector, &[i as libc::c_uint]); - match const_to_opt_uint(val) { + match const_to_opt_u128(val, true) { None => { emit_error!("shuffle index #{} is not a constant", arg_idx); None diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 71ac7c0d25204..ecedcd68382d1 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -269,7 +269,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => { let cond = self.trans_operand(&bcx, cond).immediate(); - let mut const_cond = common::const_to_opt_uint(cond).map(|c| c == 1); + let mut const_cond = common::const_to_opt_u128(cond, false).map(|c| c == 1); // This case can currently arise only from functions marked // with #[rustc_inherit_overflow_checks] and inlined from @@ -322,14 +322,12 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let len = self.trans_operand(&mut bcx, len).immediate(); let index = self.trans_operand(&mut bcx, index).immediate(); - let const_err = common::const_to_opt_uint(len).and_then(|len| { - common::const_to_opt_uint(index).map(|index| { - ErrKind::IndexOutOfBounds { - len: len, - index: index - } - }) - }); + let const_err = common::const_to_opt_u128(len, false) + .and_then(|len| common::const_to_opt_u128(index, false) + .map(|index| ErrKind::IndexOutOfBounds { + len: len as u64, + index: index as u64 + })); let file_line = C_struct(bcx.ccx, &[filename, line], false); let align = llalign_of_min(bcx.ccx, common::val_ty(file_line)); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 737ca634f0860..04f1e4fb8640e 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -13,7 +13,7 @@ use rustc::middle::const_val::ConstVal; use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err}; use rustc_const_math::ConstInt::*; use rustc_const_math::ConstFloat::*; -use rustc_const_math::{ConstInt, ConstIsize, ConstUsize, ConstMathErr}; +use rustc_const_math::{ConstInt, ConstMathErr}; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; use rustc::mir; @@ -27,16 +27,14 @@ use callee::Callee; use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty}; use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral}; use common::{C_null, C_struct, C_str_slice, C_undef, C_uint}; -use common::{const_to_opt_int, const_to_opt_uint}; +use common::{const_to_opt_u128}; use consts; use monomorphize::{self, Instance}; use type_of; use type_::Type; use value::Value; -use syntax::ast; use syntax_pos::Span; -use rustc_i128::u128; use std::fmt; use std::ptr; @@ -44,6 +42,8 @@ use std::ptr; use super::operand::{OperandRef, OperandValue}; use super::MirContext; +use rustc_i128::{u128, i128}; + /// A sized constant rvalue. /// The LLVM type might not be the same for a single Rust type, /// e.g. each enum variant would have its own LLVM struct type. @@ -431,7 +431,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::ProjectionElem::Index(ref index) => { let llindex = self.const_operand(index, span)?.llval; - let iv = if let Some(iv) = common::const_to_opt_uint(llindex) { + let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) { iv } else { span_bug!(span, "index is not an integer-constant expression") @@ -439,7 +439,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { // Produce an undef instead of a LLVM assertion on OOB. let len = common::const_to_uint(tr_base.len(self.ccx)); - let llelem = if iv < len { + let llelem = if iv < len as u128 { const_get_elt(base.llval, &[iv as u32]) } else { C_undef(type_of::type_of(self.ccx, projected_ty)) @@ -797,49 +797,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option { match t.sty { - ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type { - ast::IntTy::I8 => { - assert_eq!(input as i8 as i64, input); - Some(ConstInt::I8(input as i8)) - }, - ast::IntTy::I16 => { - assert_eq!(input as i16 as i64, input); - Some(ConstInt::I16(input as i16)) - }, - ast::IntTy::I32 => { - assert_eq!(input as i32 as i64, input); - Some(ConstInt::I32(input as i32)) - }, - ast::IntTy::I64 => { - Some(ConstInt::I64(input)) - }, - ast::IntTy::Is => { - ConstIsize::new(input, tcx.sess.target.int_type) - .ok().map(ConstInt::Isize) - }, - }), - ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type { - ast::UintTy::U8 => { - assert_eq!(input as u8 as u64, input); - Some(ConstInt::U8(input as u8)) - }, - ast::UintTy::U16 => { - assert_eq!(input as u16 as u64, input); - Some(ConstInt::U16(input as u16)) - }, - ast::UintTy::U32 => { - assert_eq!(input as u32 as u64, input); - Some(ConstInt::U32(input as u32)) - }, - ast::UintTy::U64 => { - Some(ConstInt::U64(input)) - }, - ast::UintTy::Us => { - ConstUsize::new(input, tcx.sess.target.uint_type) - .ok().map(ConstInt::Usize) - }, - }), - _ => None, + ty::TyInt(int_type) => const_to_opt_u128(value, true) + .and_then(|input| ConstInt::new_signed(input as i128, int_type, + tcx.sess.target.int_type)), + ty::TyUint(uint_type) => const_to_opt_u128(value, false) + .and_then(|input| ConstInt::new_unsigned(input, uint_type, + tcx.sess.target.uint_type)), + _ => None + } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6e9b66d564555..1c8c63a14459d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1653,6 +1653,7 @@ impl From for PrimitiveType { ast::IntTy::I16 => PrimitiveType::I16, ast::IntTy::I32 => PrimitiveType::I32, ast::IntTy::I64 => PrimitiveType::I64, + ast::IntTy::I128 => PrimitiveType::I128, } } } @@ -1665,6 +1666,7 @@ impl From for PrimitiveType { ast::UintTy::U16 => PrimitiveType::U16, ast::UintTy::U32 => PrimitiveType::U32, ast::UintTy::U64 => PrimitiveType::U64, + ast::UintTy::U128 => PrimitiveType::U128, } } } @@ -2489,7 +2491,7 @@ impl Clean> for doctree::Impl { fn build_deref_target_impls(cx: &DocContext, items: &[Item], ret: &mut Vec) { - use PrimitiveType::*; + use self::PrimitiveType::*; let tcx = cx.tcx; for item in items { diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 5d5845213e230..8109324931800 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1456,6 +1456,22 @@ extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) { extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) { LLVMSetLinkage(V, from_rust(RustLinkage)); + +// Returns true if both high and low were successfully set. Fails in case constant wasn’t any of +// the common sizes (1, 8, 16, 32, 64, 128 bits) +extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low) +{ + auto C = unwrap(CV); + if (C->getBitWidth() > 128) { return false; } + APInt AP; + if (sext) { + AP = C->getValue().sextOrSelf(128); + } else { + AP = C->getValue().zextOrSelf(128); + } + *low = AP.getLoBits(64).getZExtValue(); + *high = AP.getHiBits(64).getZExtValue(); + return true; } extern "C" LLVMContextRef LLVMRustGetValueContext(LLVMValueRef V) { From 4ff620e0edd4928468e59a09e83092742082838b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 28 Aug 2016 00:59:14 +0300 Subject: [PATCH 12/47] Implement emit_iu128 for json serialiser Causes ICEs otherwise while trying to dump AST --- src/libserialize/json.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 80b0bfc7d3e32..3e62026f51219 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -496,14 +496,14 @@ impl<'a> ::Encoder for Encoder<'a> { } fn emit_usize(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u128(&mut self, _: u128) -> EncodeResult { unimplemented!() } + fn emit_u128(&mut self, v: u128) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_isize(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i128(&mut self, _: i128) -> EncodeResult { unimplemented!() } + fn emit_i128(&mut self, v: i128) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } @@ -746,14 +746,14 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { } fn emit_usize(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u128(&mut self, _: u128) -> EncodeResult { unimplemented!() } + fn emit_u128(&mut self, v: u128) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_isize(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i128(&mut self, _: i128) -> EncodeResult { unimplemented!() } + fn emit_i128(&mut self, v: i128) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } From bfa53cfb76e6e23c8f0380132ceef5008add8ccb Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 27 Sep 2016 16:22:02 +0300 Subject: [PATCH 13/47] Fix i128 alignment calculation --- src/librustc/ty/layout.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 67856cecad1ee..d930d5d224601 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -57,8 +57,7 @@ impl Default for TargetDataLayout { i16_align: Align::from_bits(16, 16).unwrap(), i32_align: Align::from_bits(32, 32).unwrap(), i64_align: Align::from_bits(32, 64).unwrap(), - // FIXME: i128 is correct? - i128_align: Align::from_bits(64, 128).unwrap(), + i128_align: Align::from_bits(32, 64).unwrap(), f32_align: Align::from_bits(32, 32).unwrap(), f64_align: Align::from_bits(64, 64).unwrap(), pointer_size: Size::from_bits(64), @@ -103,6 +102,7 @@ impl TargetDataLayout { }; let mut dl = TargetDataLayout::default(); + let mut i128_align_src = 64; for spec in sess.target.target.data_layout.split("-") { match &spec.split(":").collect::>()[..] { &["e"] => dl.endian = Endian::Little, @@ -115,20 +115,28 @@ impl TargetDataLayout { dl.pointer_align = align(a, p); } &[s, ref a..] if s.starts_with("i") => { - let ty_align = match s[1..].parse::() { - Ok(1) => &mut dl.i8_align, - Ok(8) => &mut dl.i8_align, - Ok(16) => &mut dl.i16_align, - Ok(32) => &mut dl.i32_align, - Ok(64) => &mut dl.i64_align, - Ok(128) => &mut dl.i128_align, - Ok(_) => continue, + let bits = match s[1..].parse::() { + Ok(bits) => bits, Err(_) => { size(&s[1..], "i"); // For the user error. continue; } }; - *ty_align = align(a, s); + let a = align(a, s); + match bits { + 1 => dl.i1_align = a, + 8 => dl.i8_align = a, + 16 => dl.i16_align = a, + 32 => dl.i32_align = a, + 64 => dl.i64_align = a, + _ => {} + } + if bits >= i128_align_src && bits <= 128 { + // Default alignment for i128 is decided by taking the alignment of + // largest-sized i{64...128}. + i128_align_src = bits; + dl.i128_align = a; + } } &[s, ref a..] if s.starts_with("v") => { let v_size = size(&s[1..], "v"); From 7a3704c50044a0e9d611a264daeabbf47d398474 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 27 Sep 2016 19:06:44 +0300 Subject: [PATCH 14/47] Fix rebase fallout This commit includes manual merge conflict resolution changes from a rebase by @est31. --- src/libproc_macro/Cargo.toml | 1 - src/librustc/ty/layout.rs | 4 ++++ src/librustc_metadata/decoder.rs | 2 +- src/librustc_metadata/encoder.rs | 12 ++++++++---- src/librustc_metadata/lib.rs | 3 --- src/librustc_metadata/schema.rs | 4 +++- src/librustc_resolve/lib.rs | 4 ++-- src/librustc_trans/type_.rs | 1 + src/librustc_typeck/check/mod.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 1 + src/rustllvm/RustWrapper.cpp | 1 + src/test/run-pass/i128.rs | 3 +++ src/test/run-pass/u128.rs | 3 +++ 13 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/libproc_macro/Cargo.toml b/src/libproc_macro/Cargo.toml index ca26ddbe5a0ee..7ce65d0fe4dbc 100644 --- a/src/libproc_macro/Cargo.toml +++ b/src/libproc_macro/Cargo.toml @@ -9,4 +9,3 @@ crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } -rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index d930d5d224601..ed2aa5e51b905 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -350,6 +350,7 @@ impl Integer { I16 => Size::from_bytes(2), I32 => Size::from_bytes(4), I64 => Size::from_bytes(8), + I128 => Size::from_bytes(16), } } @@ -360,6 +361,7 @@ impl Integer { I16 => dl.i16_align, I32 => dl.i32_align, I64 => dl.i64_align, + I128 => dl.i128_align, } } @@ -371,11 +373,13 @@ impl Integer { (I16, false) => tcx.types.u16, (I32, false) => tcx.types.u32, (I64, false) => tcx.types.u64, + (I128, false) => tcx.types.u128, (I1, true) => tcx.types.i8, (I8, true) => tcx.types.i8, (I16, true) => tcx.types.i16, (I32, true) => tcx.types.i32, (I64, true) => tcx.types.i64, + (I128, true) => tcx.types.i128, } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3e3553dd1f229..cfc4dfb90753e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -44,7 +44,7 @@ use syntax::ast::{self, NodeId}; use syntax::codemap; use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP}; use syntax_pos::{self, Span, BytePos, Pos}; -use rustc_i128::u128; +use rustc_i128::{u128, i128}; pub struct DecodeContext<'a, 'tcx: 'a> { opaque: opaque::Decoder<'a>, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 72dcb4ba9a3a8..c3bcdf42d4ede 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -43,6 +43,8 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; use rustc::hir::intravisit; +use rustc_i128::{u128, i128}; + use super::index_builder::{FromId, IndexBuilder, Untracked}; pub struct EncodeContext<'a, 'tcx: 'a> { @@ -75,12 +77,14 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> { encoder_methods! { emit_usize(usize); + emit_u128(u128); emit_u64(u64); emit_u32(u32); emit_u16(u16); emit_u8(u8); emit_isize(isize); + emit_i128(i128); emit_i64(i64); emit_i32(i32); emit_i16(i16); @@ -259,7 +263,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: None, }; @@ -386,7 +390,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: Some(def_id.index), }; @@ -648,7 +652,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; EntryKind::Struct(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: struct_ctor, })) } @@ -657,7 +661,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { EntryKind::Union(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: None, })) } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 8ba3e7d82f2e2..f4ccc01544aa6 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -51,9 +51,6 @@ mod diagnostics; pub use rustc::middle; -#[macro_use] -mod macros; - mod astencode; mod index_builder; mod index; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 2bd5a9ea59d04..74825a5c6e3f6 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -27,6 +27,8 @@ use syntax_pos::{self, Span}; use std::marker::PhantomData; +use rustc_i128::u128; + pub fn rustc_version() -> String { format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version")) @@ -264,7 +266,7 @@ pub struct FnData { #[derive(RustcEncodable, RustcDecodable)] pub struct VariantData { pub ctor_kind: CtorKind, - pub disr: u64, + pub disr: u128, /// If this is a struct's only variant, this /// is the index of the "struct ctor" item. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f27a5c80b9c99..b7908f0c0edde 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2313,8 +2313,8 @@ impl<'a> Resolver<'a> { let prim = self.primitive_type_table.primitive_types[&path[0].name]; match prim { TyUint(UintTy::U128) | TyInt(IntTy::I128) => { - if !this.session.features.borrow().i128_type { - emit_feature_err(&this.session.parse_sess.span_diagnostic, + if !self.session.features.borrow().i128_type { + emit_feature_err(&self.session.parse_sess, "i128_type", span, GateIssue::Language, "128-bit type is unstable"); diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index 5e4fe015d7678..f68acab911317 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -313,6 +313,7 @@ impl Type { I16 => Type::i16(cx), I32 => Type::i32(cx), I64 => Type::i64(cx), + I128 => Type::i128(cx), } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 051a4200235ab..26dd53fecb243 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1332,7 +1332,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx); if repr_type_ty == ccx.tcx.types.i128 || repr_type_ty == ccx.tcx.types.u128 { if !ccx.tcx.sess.features.borrow().i128_type { - emit_feature_err(&ccx.tcx.sess.parse_sess.span_diagnostic, + emit_feature_err(&ccx.tcx.sess.parse_sess, "i128_type", sp, GateIssue::Language, "128-bit type is unstable"); } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 114bf437cfd3e..0d2f4eaaffda3 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -788,6 +788,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> & attr::ReprInt(attr::UnsignedInt(ast::UintTy::U8)) => "u8", attr::ReprInt(attr::UnsignedInt(ast::UintTy::U16)) => "u16", attr::ReprInt(attr::UnsignedInt(ast::UintTy::U32)) => "u32", + attr::ReprInt(attr::UnsignedInt(ast::UintTy::U64)) => "u64", attr::ReprInt(attr::UnsignedInt(ast::UintTy::U128)) => "u128", } } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 8109324931800..46ba68f072400 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1456,6 +1456,7 @@ extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) { extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) { LLVMSetLinkage(V, from_rust(RustLinkage)); +} // Returns true if both high and low were successfully set. Fails in case constant wasn’t any of // the common sizes (1, 8, 16, 32, 64, 128 bits) diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index 57ef6e55935c2..2279a84ca5cc5 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -7,6 +7,9 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// ignore-stage0 +// ignore-stage1 #![feature(i128_type)] fn main() { diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs index 4c6ae7b0e786e..9c87a5a8ee6fc 100644 --- a/src/test/run-pass/u128.rs +++ b/src/test/run-pass/u128.rs @@ -7,6 +7,9 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// ignore-stage0 +// ignore-stage1 #![feature(i128_type)] fn main() { From 5fd5d524b75d123eda841fbb86af1b5916b6081b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 2 Oct 2016 23:01:57 +0300 Subject: [PATCH 15/47] WIP intrinsics --- src/libcompiler_builtins/lib.rs | 623 ++++++++++++++++++++++++++++++++ 1 file changed, 623 insertions(+) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 4a703b3da68f6..a7345f169c55b 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -17,3 +17,626 @@ #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![feature(staged_api)] +#![feature(core_intrinsics)] +#![feature(core_float)] +#![feature(associated_consts)] +#![cfg_attr(not(stage0), feature(i128_type))] + +#![allow(non_camel_case_types, unused_variables)] + + +#[cfg(any(target_pointer_width="32", target_pointer_width="16"))] +pub mod reimpls { + #![allow(unused_comparisons)] + // C API is expected to tolerate some amount of size mismatch in ABI. Hopefully the amount of + // handling is sufficient for bootstrapping. + #[cfg(stage0)] + type u128_ = u64; + #[cfg(stage0)] + type i128_ = i64; + #[cfg(not(stage0))] + type u128_ = u128; + #[cfg(not(stage0))] + type i128_ = i128; + + fn unimplemented() -> ! { + unsafe { ::core::intrinsics::abort() } + } + + macro_rules! ashl { + ($a:expr, $b:expr, $ty:ty) => {{ + let (a, b) = ($a, $b); + let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; + let half_bits = bits / 2; + if b & half_bits != 0 { + <$ty>::from_parts(0, a.low() << (b - half_bits)) + } else if b == 0 { + a + } else { + <$ty>::from_parts(a.low() << b, (a.high() << b) | (a.low() >> (half_bits - b))) + } + }} + } + + #[export_name="__ashlti3"] + pub extern fn shl(a: u128_, b: u128_) -> u128_ { + ashl!(a, b, u128_) + } + + macro_rules! ashr { + ($a: expr, $b: expr, $ty:ty) => {{ + let (a, b) = ($a, $b); + let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; + let half_bits = bits / 2; + if b & half_bits != 0 { + <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, + a.high() >> (half_bits - 1)) + } else if b == 0 { + a + } else { + let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf; + <$ty>::from_parts((high_unsigned << (half_bits - b)) | (a.low() >> b), + a.high() >> b) + } + }} + } + + #[export_name="__ashrti3"] + pub extern fn shr(a: i128_, b: i128_) -> i128_ { + ashr!(a, b, i128_) + } + + macro_rules! lshr { + ($a: expr, $b: expr, $ty:ty) => {{ + let (a, b) = ($a, $b); + let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; + let half_bits = bits / 2; + if b & half_bits != 0 { + <$ty>::from_parts(a.high() >> (b - half_bits), 0) + } else if b == 0 { + a + } else { + <$ty>::from_parts((a.high() << (half_bits - b)) | (a.low() >> b), a.high() >> b) + } + }} + } + + + #[export_name="__lshrti3"] + pub extern fn lshr(a: u128_, b: u128_) -> u128_ { + lshr!(a, b, u128_) + } + + #[cfg(stage0)] + #[export_name="__udivmodti4"] + pub extern fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { + unsafe { + if !rem.is_null() { + *rem = n % d; + } + n / d + } + } + + #[cfg(not(stage0))] + #[export_name="__udivmodti4"] + pub extern fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { + unsafe { + // NOTE X is unknown, K != 0 + if n.high() == 0 { + if d.high() == 0 { + // 0 X + // --- + // 0 X + if !rem.is_null() { + *rem = u128::from(n.low() % d.low()); + } + return u128::from(n.low() / d.low()); + } else { + // 0 X + // --- + // K X + if !rem.is_null() { + *rem = n; + } + return 0; + }; + } + + let mut sr; + let mut q; + let mut r; + + if d.low() == 0 { + if d.high() == 0 { + // K X + // --- + // 0 0 + unimplemented() + } + + if n.low() == 0 { + // K 0 + // --- + // K 0 + if !rem.is_null() { + *rem = u128::from_parts(0, n.high() % d.high()); + } + return u128::from(n.high() / d.high()); + } + + // K K + // --- + // K 0 + + if d.high().is_power_of_two() { + if !rem.is_null() { + *rem = u128::from_parts(n.low(), n.high() & (d.high() - 1)); + } + return u128::from(n.high() >> d.high().trailing_zeros()); + } + + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > 64 - 2 { + if !rem.is_null() { + *rem = n; + } + return 0; + } + + sr += 1; + + // 1 <= sr <= u32::bits() - 1 + q = n << (128 - sr); + r = n >> sr; + } else { + if d.high() == 0 { + // K X + // --- + // 0 K + if d.low().is_power_of_two() { + if !rem.is_null() { + *rem = u128::from(n.low() & (d.low() - 1)); + } + + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return n >> sr; + }; + } + + sr = 1 + 64 + d.low().leading_zeros() - n.high().leading_zeros(); + + // 2 <= sr <= u64::bits() - 1 + q = n << (128 - sr); + r = n >> sr; + } else { + // K X + // --- + // K K + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > 64 - 1 { + if !rem.is_null() { + *rem = n; + } + return 0; + } + + sr += 1; + + // 1 <= sr <= u32::bits() + q = n << (128 - sr); + r = n >> sr; + } + } + + // Not a special case + // q and r are initialized with + // q = n << (u64::bits() - sr) + // r = n >> sr + // 1 <= sr <= u64::bits() - 1 + let mut carry = 0; + + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (128 - 1)); + q = (q << 1) | carry as u128; + + // carry = 0 + // if r >= d { + // r -= d; + // carry = 1; + // } + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i128 >> (128 - 1); + carry = (s & 1) as u64; + r -= d & s as u128; + } + + if !rem.is_null() { + *rem = r; + } + (q << 1) | carry as u128 + } + } + + #[export_name="__umodti3"] + pub extern fn u128_mod(a: u128_, b: u128_) -> u128_ { + unsafe { + let mut r = ::core::mem::zeroed(); + u128_div_mod(a, b, &mut r); + r + } + } + + #[export_name="__modti3"] + pub extern fn i128_mod(a: i128_, b: i128_) -> i128_ { + let b = b.abs(); + let sa = a.signum(); + let a = a.abs(); + unsafe { + let mut r = ::core::mem::zeroed(); + u128_div_mod(a as u128_, b as u128_, &mut r); + if sa == -1 { -(r as i128_) } else { r as i128_ } + } + } + + #[export_name="__divti3"] + pub extern fn i128_div(a: i128_, b: i128_) -> i128_ { + let sa = a.signum(); + let sb = b.signum(); + let a = a.abs(); + let b = b.abs(); + let sr = sa ^ sb; + unsafe { + let mut r = ::core::mem::zeroed(); + if sa == -1 { + -(u128_div_mod(a as u128_, b as u128_, &mut r) as i128_) + } else { + u128_div_mod(a as u128_, b as u128_, &mut r) as i128_ + } + } + } + + #[export_name="__udivti3"] + pub extern fn u128_div(a: u128_, b: u128_) -> u128_ { + unsafe { + let mut r = ::core::mem::zeroed(); + u128_div_mod(a, b, &mut r) + } + } + + macro_rules! mulo { + ($a:expr, $b:expr, $o: expr, $ty: ty) => {{ + let (a, b, overflow) = ($a, $b, $o); + *overflow = 0; + let result = a.wrapping_mul(b); + if a == <$ty>::min_value() { + if b != 0 && b != 1 { + *overflow = 1; + } + return result; + } + if b == <$ty>::min_value() { + if a != 0 && a != 1 { + *overflow = 1; + } + return result; + } + + let bits = ::core::mem::size_of::<$ty>() * 8; + let sa = a >> (bits - 1); + let abs_a = (a ^ sa) - sa; + let sb = b >> (bits - 1); + let abs_b = (b ^ sb) - sb; + if abs_a < 2 || abs_b < 2 { + return result; + } + if sa == sb { + if abs_a > <$ty>::max_value() / abs_b { + *overflow = 1; + } + } else { + if abs_a > <$ty>::min_value() / -abs_b { + *overflow = 1; + } + } + result + }} + } + + // FIXME: i32 here should be c_int. + #[export_name="__muloti4"] + pub extern fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128_ { + if let Some(v) = (a as i64).checked_mul(b as i64) { + *o = 0; + v as i128_ + } else { + *o = 1; + 0 + } + } + + pub trait LargeInt { + type LowHalf; + type HighHalf; + + fn low(self) -> Self::LowHalf; + fn high(self) -> Self::HighHalf; + fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; + } + impl LargeInt for u64 { + type LowHalf = u32; + type HighHalf = u32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> u32 { + (self >> 32) as u32 + } + fn from_parts(low: u32, high: u32) -> u64 { + low as u64 | ((high as u64) << 32) + } + } + impl LargeInt for i64 { + type LowHalf = u32; + type HighHalf = i32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> i32 { + (self >> 32) as i32 + } + fn from_parts(low: u32, high: i32) -> i64 { + low as i64 | ((high as i64) << 32) + } + } + #[cfg(not(stage0))] + impl LargeInt for u128 { + type LowHalf = u64; + type HighHalf = u64; + + fn low(self) -> u64 { + self as u64 + } + fn high(self) -> u64 { + unsafe { *(&self as *const u128 as *const u64) } + } + fn from_parts(low: u64, high: u64) -> u128 { + #[repr(C, packed)] struct Parts(u64, u64); + unsafe { ::core::mem::transmute(Parts(low, high)) } + } + } + #[cfg(not(stage0))] + impl LargeInt for i128 { + type LowHalf = u64; + type HighHalf = i64; + + fn low(self) -> u64 { + self as u64 + } + fn high(self) -> i64 { + unsafe { *(&self as *const i128 as *const i64) } + } + fn from_parts(low: u64, high: i64) -> i128 { + u128::from_parts(low, high as u64) as i128 + } + } + + macro_rules! mul { + ($a:expr, $b:expr, $ty: ty) => {{ + let (a, b) = ($a, $b); + let bits = ::core::mem::size_of::<$ty>() * 8; + let half_bits = bits / 4; + let lower_mask = !0 >> half_bits; + let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); + let mut t = low >> half_bits; + low &= lower_mask; + t += (a.low() >> half_bits) * (b.low() & lower_mask); + low += (t & lower_mask) << half_bits; + let mut high = t >> half_bits; + t = low >> half_bits; + low &= lower_mask; + t += (b.low() >> half_bits) * (a.low() & lower_mask); + low += (t & lower_mask) << half_bits; + high += t >> half_bits; + high += (a.low() >> half_bits) * (b.low() >> half_bits); + high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high()))); + <$ty>::from_parts(low, high) + }} + } + + + #[export_name="__multi3"] + pub extern fn u128_mul(a: u128_, b: u128_) -> u128_ { + (a as u64 * b as u64) as u128_ + // mul!(a, b, u128_) + } + + trait FloatStuff: Sized { + type ToBytes; + + const MANTISSA_BITS: u32; + const MAX_EXP: i32; + const EXP_MASK: Self::ToBytes; + const MANTISSA_MASK: Self::ToBytes; + + fn to_bytes(self) -> Self::ToBytes; + fn get_exponent(self) -> i32; + } + + impl FloatStuff for f32 { + type ToBytes = u32; + const MANTISSA_BITS: u32 = 23; + const MAX_EXP: i32 = 127; + const MANTISSA_MASK: u32 = 0x007F_FFFF; + const EXP_MASK: u32 = 0x7F80_0000; + + fn to_bytes(self) -> u32 { unsafe { ::core::mem::transmute(self) } } + fn get_exponent(self) -> i32 { + (((self.to_bytes() & Self::EXP_MASK) >> Self::MANTISSA_BITS) as i32) - Self::MAX_EXP + } + } + + impl FloatStuff for f64 { + type ToBytes = u64; + const MANTISSA_BITS: u32 = 52; + const MAX_EXP: i32 = 1023; + const EXP_MASK: u64 = 0x7FF0_0000_0000_0000; + const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF; + + fn to_bytes(self) -> u64 { unsafe { ::core::mem::transmute(self) } } + fn get_exponent(self) -> i32 { + (((self.to_bytes() & Self::EXP_MASK) >> Self::MANTISSA_BITS) as i32) - Self::MAX_EXP + } + } + + macro_rules! float_as_unsigned { + ($from: expr, $fromty: ty, $outty: ty) => { { + use core::num::Float; + let repr = $from.to_bytes(); + let sign = $from.signum(); + let exponent = $from.get_exponent(); + let mantissa = repr & <$fromty as FloatStuff>::MANTISSA_MASK; + if sign == -1.0 || exponent < 0 { return 0; } + if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { + return !0; + } + if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { + mantissa as $outty >> (<$fromty as FloatStuff>::MANTISSA_BITS as i32 - exponent) + } else { + mantissa as $outty << (exponent - <$fromty as FloatStuff>::MANTISSA_BITS as i32) + } + } } + } + + #[export_name="__fixunsdfti"] + pub extern fn f64_as_u128(a: f64) -> u128_ { + float_as_unsigned!(a, f64, u128_) + } + + #[export_name="__fixunssfti"] + pub extern fn f32_as_u128(a: f32) -> u128_ { + float_as_unsigned!(a, f32, u128_) + } + + macro_rules! float_as_signed { + ($from: expr, $fromty: ty, $outty: ty) => {{ + use core::num::Float; + let repr = $from.to_bytes(); + let sign = $from.signum(); + let exponent = $from.get_exponent(); + let mantissa = repr & <$fromty as FloatStuff>::MANTISSA_MASK; + + if exponent < 0 { return 0; } + if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { + return if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }; + } + let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { + mantissa as $outty >> (<$fromty as FloatStuff>::MANTISSA_BITS as i32 - exponent) + } else { + mantissa as $outty << (exponent - <$fromty as FloatStuff>::MANTISSA_BITS as i32) + }; + if sign >= 0.0 { r } else { -r } + }} + } + + #[export_name="__fixdfti"] + pub extern fn f64_as_i128(a: f64) -> i128_ { + float_as_signed!(a, f64, i128_) + } + + #[export_name="__fixsfti"] + pub extern fn f32_as_i128(a: f32) -> i128_ { + float_as_signed!(a, f32, i128_) + } + + #[export_name="__floattidf"] + pub extern fn i128_as_f64(a: i128_) -> f64 { + match a.signum() { + 1 => u128_as_f64(a.abs() as u128_), + 0 => 0.0, + -1 => -u128_as_f64(a.abs() as u128_), + _ => unimplemented() + } + } + + #[export_name="__floattisf"] + pub extern fn i128_as_f32(a: i128_) -> f32 { + match a.signum() { + 1 => u128_as_f32(a.abs() as u128_), + 0 => 0.0, + -1 => -u128_as_f32(a.abs() as u128_), + _ => unimplemented() + } + } + + #[export_name="__floatuntidf"] + pub extern fn u128_as_f64(mut a: u128_) -> f64 { + use ::core::f64::MANTISSA_DIGITS; + if a == 0 { return 0.0; } + let sd = 128 - a.leading_zeros(); + let mut e = sd - 1; + const MD1 : u32 = MANTISSA_DIGITS + 1; + const MD2 : u32 = MANTISSA_DIGITS + 2; + + if sd > MANTISSA_DIGITS { + a = match sd { + MD1 => a << 1, + MD2 => a, + _ => (a >> (sd - (MANTISSA_DIGITS + 2))) | + (if (a & (!0 >> (128 + MANTISSA_DIGITS + 2) - sd)) == 0 { 0 } else { 1 }) + }; + a |= if (a & 4) == 0 { 0 } else { 1 }; + a += 1; + a >>= 2; + if a & (1 << MANTISSA_DIGITS) != 0 { + a >>= 1; + e += 1; + } + } else { + a <<= MANTISSA_DIGITS - sd; + } + unsafe { + ::core::mem::transmute(((e as u64 + 1023) << 52) | (a as u64 & 0x000f_ffff_ffff_ffff)) + } + } + + #[export_name="__floatuntisf"] + pub extern fn u128_as_f32(mut a: u128_) -> f32 { + use ::core::f32::MANTISSA_DIGITS; + if a == 0 { return 0.0; } + let sd = 128 - a.leading_zeros(); + let mut e = sd - 1; + const MD1 : u32 = MANTISSA_DIGITS + 1; + const MD2 : u32 = MANTISSA_DIGITS + 2; + + if sd > MANTISSA_DIGITS { + a = match sd { + MD1 => a << 1, + MD2 => a, + _ => (a >> (sd - (MANTISSA_DIGITS + 2))) | + (if (a & (!0 >> (128 + MANTISSA_DIGITS + 2) - sd)) == 0 { 0 } else { 1 }) + }; + a |= if (a & 4) == 0 { 0 } else { 1 }; + a += 1; + a >>= 2; + if a & (1 << MANTISSA_DIGITS) != 0 { + a >>= 1; + e += 1; + } + } else { + a <<= MANTISSA_DIGITS - sd; + } + unsafe { + ::core::mem::transmute(((e + 127) << 23) | (a as u32 & 0x007f_ffff)) + } + } +} From 32d8d241599d8c72d23741db286e123a2f1cd7df Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 20 Nov 2016 01:26:51 +0100 Subject: [PATCH 16/47] Fix rebase fallout --- src/libcompiler_builtins/lib.rs | 6 +++++- src/libcore/num/mod.rs | 21 +++++++++++++++++++++ src/librustc/ty/layout.rs | 4 +++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index a7345f169c55b..ac22fa4bc95d8 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -448,7 +448,11 @@ pub mod reimpls { low += (t & lower_mask) << half_bits; high += t >> half_bits; high += (a.low() >> half_bits) * (b.low() >> half_bits); - high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high()))); + high = high + .wrapping_add(a.high() + .wrapping_mul(b.low()) + .wrapping_add(a.low() + .wrapping_mul(b.high()))); <$ty>::from_parts(low, high) }} } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 49e366a89760c..61c687313dcb6 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2614,6 +2614,27 @@ macro_rules! same_sign_try_from_int_impl { )*} } +#[cfg(stage0)] +same_sign_try_from_int_impl!(u64, u8, u8, u16, u32, u64, usize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(i64, i8, i8, i16, i32, i64, isize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(u64, u16, u8, u16, u32, u64, usize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(i64, i16, i8, i16, i32, i64, isize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(u64, u32, u8, u16, u32, u64, usize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(i64, i32, i8, i16, i32, i64, isize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(u64, u64, u8, u16, u32, u64, usize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(i64, i64, i8, i16, i32, i64, isize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(u64, usize, u8, u16, u32, u64, usize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(i64, isize, i8, i16, i32, i64, isize); + #[cfg(not(stage0))] same_sign_try_from_int_impl!(u128, u8, u8, u16, u32, u64, u128, usize); #[cfg(not(stage0))] diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index ed2aa5e51b905..75600ddaabdb5 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1198,7 +1198,9 @@ impl<'a, 'gcx, 'tcx> Layout { if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) { // All bodies empty -> intlike - let (mut min, mut max, mut non_zero) = (i128::max_value(), i128::min_value(), true); + let (mut min, mut max, mut non_zero) = (i128::max_value(), + i128::min_value(), + true); for v in &def.variants { let x = v.disr_val.to_u128_unchecked() as i128; if x == 0 { non_zero = false; } From 8bcb021991879b676769eb593c043abe4837369b Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 20 Nov 2016 05:06:53 +0100 Subject: [PATCH 17/47] Use LLVMRustConstInt128Get on stage1 too llvm::LLVMConstIntGetZExtValue doesn't accept values with more than 64 bits. This fixes an LLVM assertion error when compiling libcore with stage1: src/llvm/include/llvm/ADT/APInt.h:1336: uint64_t llvm::APInt::getZExtValue() const: Assertion `getActiveBits() <= 64 && "Too many bits for uint64_t"' failed. --- src/librustc_trans/common.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index f4c7d2973bf66..79aa566376582 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -592,23 +592,18 @@ fn is_const_integral(v: ValueRef) -> bool { } } - +#[inline] #[cfg(stage0)] -pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option { - unsafe { - if is_const_integral(v) { - if !sign_ext { - Some(llvm::LLVMConstIntGetZExtValue(v)) - } else { - Some(llvm::LLVMConstIntGetSExtValue(v) as u64) - } - } else { - None - } - } +fn hi_lo_to_u128(lo: u64, _: u64) -> u128 { + lo as u128 } +#[inline] #[cfg(not(stage0))] +fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 { + ((hi as u128) << 64) | (lo as u128) +} + pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option { unsafe { if is_const_integral(v) { @@ -616,7 +611,7 @@ pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option { let success = llvm::LLVMRustConstInt128Get(v, sign_ext, &mut hi as *mut u64, &mut lo as *mut u64); if success { - Some(((hi as u128) << 64) | (lo as u128)) + Some(hi_lo_to_u128(lo, hi)) } else { None } From 9e99213831a876bdb9b84dbf30462e4a845cf84f Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 20 Nov 2016 06:44:56 +0100 Subject: [PATCH 18/47] Compilation fixes --- src/Cargo.lock | 2 +- src/librustc_incremental/Cargo.toml | 1 + src/librustc_incremental/lib.rs | 2 ++ src/librustdoc/clean/mod.rs | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 19e394f301b49..b4455a34e4968 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -201,7 +201,6 @@ dependencies = [ name = "proc_macro" version = "0.0.0" dependencies = [ - "rustc_i128 0.0.0", "syntax 0.0.0", ] @@ -388,6 +387,7 @@ dependencies = [ "log 0.0.0", "rustc 0.0.0", "rustc_data_structures 0.0.0", + "rustc_i128 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index e3ee752754504..8a38f36a5d133 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -16,3 +16,4 @@ serialize = { path = "../libserialize" } log = { path = "../liblog" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index ce73b14ef2d02..d02e4f9b165d8 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -33,6 +33,8 @@ extern crate serialize as rustc_serialize; #[macro_use] extern crate syntax; extern crate syntax_pos; +extern crate rustc_i128; + const ATTR_DIRTY: &'static str = "rustc_dirty"; const ATTR_CLEAN: &'static str = "rustc_clean"; const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty"; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1c8c63a14459d..5978791fbc710 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1614,7 +1614,7 @@ impl PrimitiveType { } pub fn as_str(&self) -> &'static str { - use PrimitiveType::*; + use self::PrimitiveType::*; match *self { Isize => "isize", I8 => "i8", From 85ec09187c5d75a49659a82882a97cc93baff5af Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 21 Nov 2016 05:40:35 +0100 Subject: [PATCH 19/47] Make rustdoc aware of the primitive i128 type Many thanks to ollie27 for spotting all the places. --- src/librustdoc/clean/inline.rs | 2 ++ src/librustdoc/clean/mod.rs | 2 ++ src/libstd/primitive_docs.rs | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cba5e1ba6f318..93854193762fb 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -268,11 +268,13 @@ pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { tcx.lang_items.i16_impl(), tcx.lang_items.i32_impl(), tcx.lang_items.i64_impl(), + tcx.lang_items.i128_impl(), tcx.lang_items.usize_impl(), tcx.lang_items.u8_impl(), tcx.lang_items.u16_impl(), tcx.lang_items.u32_impl(), tcx.lang_items.u64_impl(), + tcx.lang_items.u128_impl(), tcx.lang_items.f32_impl(), tcx.lang_items.f64_impl(), tcx.lang_items.char_impl(), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5978791fbc710..e0a26ca318189 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1595,11 +1595,13 @@ impl PrimitiveType { "i16" => Some(PrimitiveType::I16), "i32" => Some(PrimitiveType::I32), "i64" => Some(PrimitiveType::I64), + "i128" => Some(PrimitiveType::I128), "usize" => Some(PrimitiveType::Usize), "u8" => Some(PrimitiveType::U8), "u16" => Some(PrimitiveType::U16), "u32" => Some(PrimitiveType::U32), "u64" => Some(PrimitiveType::U64), + "u128" => Some(PrimitiveType::U128), "bool" => Some(PrimitiveType::Bool), "char" => Some(PrimitiveType::Char), "str" => Some(PrimitiveType::Str), diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 54dde6681e188..5981b482a9728 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -597,6 +597,17 @@ mod prim_i32 { } /// mod prim_i64 { } +#[doc(primitive = "i128")] +// +/// The 128-bit signed integer type. +/// +/// *[See also the `std::i128` module](i128/index.html).* +/// +/// However, please note that examples are shared between primitive integer +/// types. So it's normal if you see usage of types like `i8` in there. +/// +mod prim_i128 { } + #[doc(primitive = "u8")] // /// The 8-bit unsigned integer type. @@ -641,6 +652,17 @@ mod prim_u32 { } /// mod prim_u64 { } +#[doc(primitive = "u128")] +// +/// The 128-bit unsigned integer type. +/// +/// *[See also the `std::u128` module](u128/index.html).* +/// +/// However, please note that examples are shared between primitive integer +/// types. So it's normal if you see usage of types like `u8` in there. +/// +mod prim_u128 { } + #[doc(primitive = "isize")] // /// The pointer-sized signed integer type. From dc14a108ae25fb135ea47fd683de87d1da5fc49e Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 25 Nov 2016 00:08:40 +0100 Subject: [PATCH 20/47] Fix intrinsics and expand tests --- src/libcompiler_builtins/lib.rs | 122 ++++++++++++++++++-------------- src/test/run-pass/i128.rs | 7 ++ src/test/run-pass/u128.rs | 9 +++ 3 files changed, 84 insertions(+), 54 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index ac22fa4bc95d8..274709f28ea89 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -24,10 +24,15 @@ #![allow(non_camel_case_types, unused_variables)] - #[cfg(any(target_pointer_width="32", target_pointer_width="16"))] pub mod reimpls { + #![allow(unused_comparisons)] + + use core::intrinsics::unchecked_div; + use core::intrinsics::unchecked_rem; + use core::ptr; + // C API is expected to tolerate some amount of size mismatch in ABI. Hopefully the amount of // handling is sufficient for bootstrapping. #[cfg(stage0)] @@ -112,26 +117,27 @@ pub mod reimpls { pub extern fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { unsafe { if !rem.is_null() { - *rem = n % d; + *rem = unchecked_rem(n, d); } - n / d + unchecked_div(n, d) } } #[cfg(not(stage0))] #[export_name="__udivmodti4"] pub extern fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { + // Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide unsafe { - // NOTE X is unknown, K != 0 + // special cases, X is unknown, K != 0 if n.high() == 0 { if d.high() == 0 { // 0 X // --- // 0 X if !rem.is_null() { - *rem = u128::from(n.low() % d.low()); + *rem = u128::from(unchecked_rem(n.low(), d.low())); } - return u128::from(n.low() / d.low()); + return u128::from(unchecked_div(n.low(), d.low())); } else { // 0 X // --- @@ -152,7 +158,10 @@ pub mod reimpls { // K X // --- // 0 0 - unimplemented() + if !rem.is_null() { + *rem = u128::from(unchecked_rem(n.high(), d.low())); + } + return u128::from(unchecked_div(n.high(), d.low())); } if n.low() == 0 { @@ -160,9 +169,9 @@ pub mod reimpls { // --- // K 0 if !rem.is_null() { - *rem = u128::from_parts(0, n.high() % d.high()); + *rem = u128::from_parts(0, unchecked_rem(n.high(), d.high())); } - return u128::from(n.high() / d.high()); + return u128::from(unchecked_div(n.high(), d.high())); } // K K @@ -176,6 +185,9 @@ pub mod reimpls { return u128::from(n.high() >> d.high().trailing_zeros()); } + // K K + // --- + // K 0 sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); // D > N @@ -188,8 +200,8 @@ pub mod reimpls { sr += 1; - // 1 <= sr <= u32::bits() - 1 - q = n << (128 - sr); + // 1 <= sr <= u64::bits() - 1 + q = n << (64 - sr); r = n >> sr; } else { if d.high() == 0 { @@ -214,6 +226,10 @@ pub mod reimpls { // 2 <= sr <= u64::bits() - 1 q = n << (128 - sr); r = n >> sr; + // FIXME the C compiler-rt implementation has something here + // that looks like a speed optimisation. + // It would be worth a try to port it to Rust too and + // compare the speed. } else { // K X // --- @@ -292,23 +308,17 @@ pub mod reimpls { let sb = b.signum(); let a = a.abs(); let b = b.abs(); - let sr = sa ^ sb; - unsafe { - let mut r = ::core::mem::zeroed(); - if sa == -1 { - -(u128_div_mod(a as u128_, b as u128_, &mut r) as i128_) - } else { - u128_div_mod(a as u128_, b as u128_, &mut r) as i128_ - } + let sr = sa * sb; // sign of quotient + if sr == -1 { + -(u128_div_mod(a as u128_, b as u128_, ptr::null_mut()) as i128_) + } else { + u128_div_mod(a as u128_, b as u128_, ptr::null_mut()) as i128_ } } #[export_name="__udivti3"] pub extern fn u128_div(a: u128_, b: u128_) -> u128_ { - unsafe { - let mut r = ::core::mem::zeroed(); - u128_div_mod(a, b, &mut r) - } + u128_div_mod(a, b, ptr::null_mut()) } macro_rules! mulo { @@ -329,23 +339,24 @@ pub mod reimpls { return result; } - let bits = ::core::mem::size_of::<$ty>() * 8; - let sa = a >> (bits - 1); - let abs_a = (a ^ sa) - sa; - let sb = b >> (bits - 1); - let abs_b = (b ^ sb) - sb; + let sa = a.signum(); + let abs_a = a.abs(); + let sb = b.signum(); + let abs_b = b.abs(); if abs_a < 2 || abs_b < 2 { return result; } + unsafe { if sa == sb { - if abs_a > <$ty>::max_value() / abs_b { + if abs_a > unchecked_div(<$ty>::max_value(), abs_b) { *overflow = 1; } } else { - if abs_a > <$ty>::min_value() / -abs_b { + if abs_a > unchecked_div(<$ty>::min_value(), -abs_b) { *overflow = 1; } } + } result }} } @@ -353,13 +364,7 @@ pub mod reimpls { // FIXME: i32 here should be c_int. #[export_name="__muloti4"] pub extern fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128_ { - if let Some(v) = (a as i64).checked_mul(b as i64) { - *o = 0; - v as i128_ - } else { - *o = 1; - 0 - } + mulo!(a, b, o, i128_) } pub trait LargeInt { @@ -407,7 +412,7 @@ pub mod reimpls { self as u64 } fn high(self) -> u64 { - unsafe { *(&self as *const u128 as *const u64) } + unsafe { *(&self as *const u128 as *const u64).offset(1) } } fn from_parts(low: u64, high: u64) -> u128 { #[repr(C, packed)] struct Parts(u64, u64); @@ -423,7 +428,7 @@ pub mod reimpls { self as u64 } fn high(self) -> i64 { - unsafe { *(&self as *const i128 as *const i64) } + unsafe { *(&self as *const i128 as *const i64).offset(1) } } fn from_parts(low: u64, high: i64) -> i128 { u128::from_parts(low, high as u64) as i128 @@ -431,37 +436,41 @@ pub mod reimpls { } macro_rules! mul { - ($a:expr, $b:expr, $ty: ty) => {{ + ($a:expr, $b:expr, $ty: ty, $tyh: ty) => {{ let (a, b) = ($a, $b); - let bits = ::core::mem::size_of::<$ty>() * 8; - let half_bits = bits / 4; + let half_bits = (::core::mem::size_of::<$tyh>() * 8) / 2; let lower_mask = !0 >> half_bits; let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); let mut t = low >> half_bits; low &= lower_mask; t += (a.low() >> half_bits) * (b.low() & lower_mask); low += (t & lower_mask) << half_bits; - let mut high = t >> half_bits; + let mut high = (t >> half_bits) as $tyh; t = low >> half_bits; low &= lower_mask; t += (b.low() >> half_bits) * (a.low() & lower_mask); low += (t & lower_mask) << half_bits; - high += t >> half_bits; - high += (a.low() >> half_bits) * (b.low() >> half_bits); + high += (t >> half_bits) as $tyh; + high += ((a.low() >> half_bits) * (b.low() >> half_bits)) as $tyh; high = high .wrapping_add(a.high() - .wrapping_mul(b.low()) - .wrapping_add(a.low() - .wrapping_mul(b.high()))); + .wrapping_mul(b.low() as $tyh)) + .wrapping_add((a.low() as $tyh) + .wrapping_mul(b.high())); <$ty>::from_parts(low, high) }} } + #[cfg(stage0)] + #[export_name="__multi3"] + pub extern fn u128_mul(a: i128_, b: i128_) -> i128_ { + (a as i64 * b as i64) as i128_ + } + #[cfg(not(stage0))] #[export_name="__multi3"] - pub extern fn u128_mul(a: u128_, b: u128_) -> u128_ { - (a as u64 * b as u64) as u128_ - // mul!(a, b, u128_) + pub extern fn u128_mul(a: i128_, b: i128_) -> i128_ { + mul!(a, b, i128_, i64) } trait FloatStuff: Sized { @@ -471,6 +480,7 @@ pub mod reimpls { const MAX_EXP: i32; const EXP_MASK: Self::ToBytes; const MANTISSA_MASK: Self::ToBytes; + const MANTISSA_LEAD_BIT: Self::ToBytes; fn to_bytes(self) -> Self::ToBytes; fn get_exponent(self) -> i32; @@ -480,8 +490,9 @@ pub mod reimpls { type ToBytes = u32; const MANTISSA_BITS: u32 = 23; const MAX_EXP: i32 = 127; - const MANTISSA_MASK: u32 = 0x007F_FFFF; const EXP_MASK: u32 = 0x7F80_0000; + const MANTISSA_MASK: u32 = 0x007F_FFFF; + const MANTISSA_LEAD_BIT: u32 = 0x0080_0000; fn to_bytes(self) -> u32 { unsafe { ::core::mem::transmute(self) } } fn get_exponent(self) -> i32 { @@ -495,6 +506,7 @@ pub mod reimpls { const MAX_EXP: i32 = 1023; const EXP_MASK: u64 = 0x7FF0_0000_0000_0000; const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF; + const MANTISSA_LEAD_BIT: u64 = 0x0010_0000_0000_0000; fn to_bytes(self) -> u64 { unsafe { ::core::mem::transmute(self) } } fn get_exponent(self) -> i32 { @@ -508,7 +520,8 @@ pub mod reimpls { let repr = $from.to_bytes(); let sign = $from.signum(); let exponent = $from.get_exponent(); - let mantissa = repr & <$fromty as FloatStuff>::MANTISSA_MASK; + let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK; + let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; if sign == -1.0 || exponent < 0 { return 0; } if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { return !0; @@ -537,7 +550,8 @@ pub mod reimpls { let repr = $from.to_bytes(); let sign = $from.signum(); let exponent = $from.get_exponent(); - let mantissa = repr & <$fromty as FloatStuff>::MANTISSA_MASK; + let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK; + let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; if exponent < 0 { return 0; } if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index 2279a84ca5cc5..4799f0d68bf2c 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -18,6 +18,9 @@ fn main() { let y: i128 = -2; assert_eq!(!1, y); let z: i128 = 0xABCD_EF; + assert_eq!(z * z, 0x734C_C2F2_A521); + assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); + assert_eq!(-z * -z, 0x734C_C2F2_A521); assert_eq!(-z * -z * -z * -z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); assert_eq!(-z + -z + -z + -z, -0x2AF3_7BC); let k: i128 = -0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210; @@ -38,6 +41,10 @@ fn main() { assert_eq!(k as i64, -0xFEDC_BA98_7654_3210); assert_eq!(k as u128, 0xFEDC_BA98_7654_3210_0123_4567_89AB_CDF0); assert_eq!(-k as u128, 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210); + assert_eq!((-z as f64) as i128, -z); + assert_eq!((-z as f32) as i128, -z); + assert_eq!((-z as f64 * 16.0) as i128, -z * 16); + assert_eq!((-z as f32 * 16.0) as i128, -z * 16); // formatting let j: i128 = -(1 << 67); assert_eq!("-147573952589676412928", format!("{}", j)); diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs index 9c87a5a8ee6fc..bd6ff46e8f478 100644 --- a/src/test/run-pass/u128.rs +++ b/src/test/run-pass/u128.rs @@ -23,6 +23,7 @@ fn main() { y & 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF); let z: u128 = 0xABCD_EF; + assert_eq!(z * z, 0x734C_C2F2_A521); assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); assert_eq!(z + z + z + z, 0x2AF3_7BC); let k: u128 = 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210; @@ -34,6 +35,7 @@ fn main() { assert_eq!(0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42); assert_eq!(0, k % 42); assert_eq!(15, z % 42); + assert_eq!(0x169D_A8020_CEC18, k % 0x3ACB_FE49_FF24_AC); assert_eq!(0x91A2_B3C4_D5E6_F7, k >> 65); assert_eq!(0xFDB9_7530_ECA8_6420_0000_0000_0000_0000, k << 65); assert!(k > z); @@ -43,6 +45,13 @@ fn main() { assert_eq!(z as u64, 0xABCD_EF); assert_eq!(k as u64, 0xFEDC_BA98_7654_3210); assert_eq!(k as i128, 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210); + assert_eq!((z as f64) as u128, z); + assert_eq!((z as f32) as u128, z); + assert_eq!((z as f64 * 16.0) as u128, z * 16); + assert_eq!((z as f32 * 16.0) as u128, z * 16); + let l :u128 = 432 << 100; + assert_eq!((l as f32) as u128, l); + assert_eq!((l as f64) as u128, l); // formatting let j: u128 = 1 << 67; assert_eq!("147573952589676412928", format!("{}", j)); From 2715367f080198fe836e6b239e28548ca9e65ed4 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 25 Nov 2016 02:33:35 +0100 Subject: [PATCH 21/47] intrinsics : uabs and iabs --- src/libcompiler_builtins/lib.rs | 39 ++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 274709f28ea89..3452370013ade 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -292,12 +292,12 @@ pub mod reimpls { #[export_name="__modti3"] pub extern fn i128_mod(a: i128_, b: i128_) -> i128_ { - let b = b.abs(); + let b = b.uabs(); let sa = a.signum(); - let a = a.abs(); + let a = a.uabs(); unsafe { let mut r = ::core::mem::zeroed(); - u128_div_mod(a as u128_, b as u128_, &mut r); + u128_div_mod(a, b, &mut r); if sa == -1 { -(r as i128_) } else { r as i128_ } } } @@ -306,13 +306,13 @@ pub mod reimpls { pub extern fn i128_div(a: i128_, b: i128_) -> i128_ { let sa = a.signum(); let sb = b.signum(); - let a = a.abs(); - let b = b.abs(); + let a = a.uabs(); + let b = b.uabs(); let sr = sa * sb; // sign of quotient if sr == -1 { - -(u128_div_mod(a as u128_, b as u128_, ptr::null_mut()) as i128_) + -(u128_div_mod(a, b, ptr::null_mut()) as i128_) } else { - u128_div_mod(a as u128_, b as u128_, ptr::null_mut()) as i128_ + u128_div_mod(a, b, ptr::null_mut()) as i128_ } } @@ -340,9 +340,9 @@ pub mod reimpls { } let sa = a.signum(); - let abs_a = a.abs(); + let abs_a = a.iabs(); let sb = b.signum(); - let abs_b = b.abs(); + let abs_b = b.iabs(); if abs_a < 2 || abs_b < 2 { return result; } @@ -473,6 +473,19 @@ pub mod reimpls { mul!(a, b, i128_, i64) } + trait AbsExt: Sized { + fn uabs(self) -> u128_ { + self.iabs() as u128_ + } + fn iabs(self) -> i128_; + } + + impl AbsExt for i128_ { + fn iabs(self) -> i128_ { + ((self ^ self).wrapping_sub(self)) + } + } + trait FloatStuff: Sized { type ToBytes; @@ -579,9 +592,9 @@ pub mod reimpls { #[export_name="__floattidf"] pub extern fn i128_as_f64(a: i128_) -> f64 { match a.signum() { - 1 => u128_as_f64(a.abs() as u128_), + 1 => u128_as_f64(a.uabs()), 0 => 0.0, - -1 => -u128_as_f64(a.abs() as u128_), + -1 => -u128_as_f64(a.uabs()), _ => unimplemented() } } @@ -589,9 +602,9 @@ pub mod reimpls { #[export_name="__floattisf"] pub extern fn i128_as_f32(a: i128_) -> f32 { match a.signum() { - 1 => u128_as_f32(a.abs() as u128_), + 1 => u128_as_f32(a.uabs()), 0 => 0.0, - -1 => -u128_as_f32(a.abs() as u128_), + -1 => -u128_as_f32(a.uabs()), _ => unimplemented() } } From 13d49f5299d28ae7a02b4118ddc5f2f98f8caf92 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 26 Nov 2016 18:30:14 +0100 Subject: [PATCH 22/47] Fix warning on 64 bit --- src/libcompiler_builtins/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 3452370013ade..f139a00e2a459 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -17,8 +17,8 @@ #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![feature(staged_api)] -#![feature(core_intrinsics)] -#![feature(core_float)] +#![cfg_attr(any(target_pointer_width="32", target_pointer_width="16"), + feature(core_intrinsics, core_float))] #![feature(associated_consts)] #![cfg_attr(not(stage0), feature(i128_type))] From 3b34f90bc1f230737516a799e59dbd3425aab04b Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 28 Nov 2016 00:57:25 +0100 Subject: [PATCH 23/47] Move from RUSTC_CRATES to TARGET_CRATES --- mk/crates.mk | 4 ++-- src/librustc_i128/Cargo.toml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mk/crates.mk b/mk/crates.mk index 732db8022fcf5..9624a51dda01b 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -54,12 +54,12 @@ TARGET_CRATES := libc std term \ compiler_builtins core alloc \ std_unicode rustc_bitflags \ alloc_system alloc_jemalloc \ - panic_abort panic_unwind unwind + panic_abort panic_unwind unwind rustc_i128 RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_platform_intrinsics rustc_errors \ rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \ - rustc_const_eval rustc_const_math rustc_incremental proc_macro rustc_i128 + rustc_const_eval rustc_const_math rustc_incremental proc_macro HOST_CRATES := syntax syntax_ext proc_macro_tokens proc_macro_plugin syntax_pos $(RUSTC_CRATES) \ rustdoc fmt_macros flate arena graphviz log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator diff --git a/src/librustc_i128/Cargo.toml b/src/librustc_i128/Cargo.toml index 79632394bf6b0..6fd67637db7e6 100644 --- a/src/librustc_i128/Cargo.toml +++ b/src/librustc_i128/Cargo.toml @@ -6,4 +6,3 @@ version = "0.0.0" [lib] name = "rustc_i128" path = "lib.rs" -crate-type = ["dylib"] From c79aba71d5a0573a6f9cd270dac60d92c611236c Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 28 Nov 2016 02:18:34 +0100 Subject: [PATCH 24/47] 40 -> 39, as ceil(log10(2^128)) == 39 just as ceil(log10(2^64)) == 20 --- src/libcore/fmt/num.rs | 2 +- src/test/run-pass/u128.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 7b6c2d4888965..cd725392b665f 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -211,7 +211,7 @@ macro_rules! impl_Display { // convert the negative num to positive by summing 1 to it's 2 complement (!self.$conv_fn()).wrapping_add(1) }; - let mut buf: [u8; 40] = unsafe { mem::uninitialized() }; + let mut buf: [u8; 39] = unsafe { mem::uninitialized() }; let mut curr = buf.len() as isize; let buf_ptr = buf.as_mut_ptr(); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs index bd6ff46e8f478..d138e09318bfe 100644 --- a/src/test/run-pass/u128.rs +++ b/src/test/run-pass/u128.rs @@ -59,6 +59,8 @@ fn main() { assert_eq!("20000000000000000000000", format!("{:o}", j)); assert_eq!("10000000000000000000000000000000000000000000000000000000000000000000", format!("{:b}", j)); + assert_eq!("340282366920938463463374607431768211455", + format!("{}", u128::max_value())); assert_eq!("147573952589676412928", format!("{:?}", j)); // common traits x.clone(); From 317810d4c4371b8fcaf884d4918b15a55701fc1d Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 4 Dec 2016 07:58:49 +0100 Subject: [PATCH 25/47] Always use Rust based intrinsics on Windows The check inside compiler-rt file int_types.h to #define CRT_HAS_128BIT looks like: #if (defined(__LP64__) || defined(__wasm__)) && \ !(defined(__mips__) && defined(__clang__)) #define CRT_HAS_128BIT #endif Windows uses LLP64 instead of LP64, so it doesn't ship with the C based intrinsics. Also, add libcompiler_builtins to the list of crates that may have platform specific checks (like the ones we just added). --- src/libcompiler_builtins/lib.rs | 6 ++++-- src/tools/tidy/src/pal.rs | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index f139a00e2a459..790de76cad69d 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -17,14 +17,16 @@ #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![feature(staged_api)] -#![cfg_attr(any(target_pointer_width="32", target_pointer_width="16"), +#![cfg_attr(any(target_pointer_width="32", target_pointer_width="16", target_os="windows", + target_arch="mips64"), feature(core_intrinsics, core_float))] #![feature(associated_consts)] #![cfg_attr(not(stage0), feature(i128_type))] #![allow(non_camel_case_types, unused_variables)] -#[cfg(any(target_pointer_width="32", target_pointer_width="16"))] +#[cfg(any(target_pointer_width="32", target_pointer_width="16", target_os="windows", + target_arch="mips64"))] pub mod reimpls { #![allow(unused_comparisons)] diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index a5e4e5a4c2672..3808c05c6b939 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -26,6 +26,7 @@ //! exceptions: //! //! - core may not have platform-specific code +//! - libcompiler_builtins may have platform-specific code //! - liballoc_system may have platform-specific code //! - liballoc_jemalloc may have platform-specific code //! - libpanic_abort may have platform-specific code @@ -53,6 +54,7 @@ const EXCEPTION_PATHS: &'static [&'static str] = &[ // std crates "src/liballoc_jemalloc", "src/liballoc_system", + "src/libcompiler_builtins", "src/liblibc", "src/libpanic_abort", "src/libpanic_unwind", From 3e2046214ca7054bb438259c0287568976323040 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 6 Dec 2016 00:48:54 +0100 Subject: [PATCH 26/47] Try to fix some things * shift so that no panics are generated (otherwise results in linker error) * no_std as insurance to not get into issues with errors like "cannot satisfy dependencies so `rustc_i128` only shows up once" (pure guessing here, but it doesn't hurt...) --- src/libcompiler_builtins/lib.rs | 4 ++-- src/librustc_i128/lib.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 790de76cad69d..d6b2c6d49bd33 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -74,7 +74,7 @@ pub mod reimpls { ($a: expr, $b: expr, $ty:ty) => {{ let (a, b) = ($a, $b); let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; - let half_bits = bits / 2; + let half_bits = bits >> 1; if b & half_bits != 0 { <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, a.high() >> (half_bits - 1)) @@ -97,7 +97,7 @@ pub mod reimpls { ($a: expr, $b: expr, $ty:ty) => {{ let (a, b) = ($a, $b); let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; - let half_bits = bits / 2; + let half_bits = bits >> 1; if b & half_bits != 0 { <$ty>::from_parts(a.high() >> (b - half_bits), 0) } else if b == 0 { diff --git a/src/librustc_i128/lib.rs b/src/librustc_i128/lib.rs index a9770396e7882..80f550c7f50e2 100644 --- a/src/librustc_i128/lib.rs +++ b/src/librustc_i128/lib.rs @@ -9,6 +9,7 @@ // except according to those terms. #![allow(non_camel_case_types)] #![cfg_attr(not(stage0), feature(i128_type))] +#![no_std] #![crate_type="rlib"] #![crate_name="rustc_i128"] From 92e6c53a2568417495db00fcfc9cb1677bbd105d Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 7 Dec 2016 16:28:45 +0100 Subject: [PATCH 27/47] libcompiler_builtins: don't codegen dead code call to eh_personality There was a linker error on 32 bit platforms with optimisations turned off, complaining that there was an undefined reference to "rust_eh_personality", when compiling the rustc_const_math as stage1 artifact. Apparently the compiler_builtins crate includes a call to "rust_eh_personality". If compiled for 64 bits, this call doesn't appear, which explains why the linker error only happens on 32 bit platforms, and optimisations will get it removed on 32 bit as well. There were two origins of the call: 1. A for loop where apparently the compiler wasn't sure whether next() could panic or not, and therefore generated a landing pad for the worst case. The minimal reproducible example is "for _ in 0..sr { }". 2. A default impl of uabs where the compiler apparently wasn't sure either whether iabs() could panic or not. Many thanks to nagisa for contributing the fix. This commit also puts extern "C" to the intrinsics, as this is generally a good thing to do. --- src/libcompiler_builtins/lib.rs | 55 +++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index d6b2c6d49bd33..677a6e9456807 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -66,7 +66,7 @@ pub mod reimpls { } #[export_name="__ashlti3"] - pub extern fn shl(a: u128_, b: u128_) -> u128_ { + pub extern "C" fn shl(a: u128_, b: u128_) -> u128_ { ashl!(a, b, u128_) } @@ -89,7 +89,7 @@ pub mod reimpls { } #[export_name="__ashrti3"] - pub extern fn shr(a: i128_, b: i128_) -> i128_ { + pub extern "C" fn shr(a: i128_, b: i128_) -> i128_ { ashr!(a, b, i128_) } @@ -110,13 +110,13 @@ pub mod reimpls { #[export_name="__lshrti3"] - pub extern fn lshr(a: u128_, b: u128_) -> u128_ { + pub extern "C" fn lshr(a: u128_, b: u128_) -> u128_ { lshr!(a, b, u128_) } #[cfg(stage0)] #[export_name="__udivmodti4"] - pub extern fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { + pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { unsafe { if !rem.is_null() { *rem = unchecked_rem(n, d); @@ -127,7 +127,7 @@ pub mod reimpls { #[cfg(not(stage0))] #[export_name="__udivmodti4"] - pub extern fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { + pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { // Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide unsafe { // special cases, X is unknown, K != 0 @@ -261,7 +261,12 @@ pub mod reimpls { // 1 <= sr <= u64::bits() - 1 let mut carry = 0; - for _ in 0..sr { + // FIXME: replace this with a for loop + // (atm not doable as this generates call to + // eh_personality when optimisations are turned off, + // which in turn gives a linker error in later + // compilation steps) + while sr > 0 { // r:q = ((r:q) << 1) | carry r = (r << 1) | (q >> (128 - 1)); q = (q << 1) | carry as u128; @@ -274,6 +279,7 @@ pub mod reimpls { let s = (d.wrapping_sub(r).wrapping_sub(1)) as i128 >> (128 - 1); carry = (s & 1) as u64; r -= d & s as u128; + sr -= 1; } if !rem.is_null() { @@ -284,7 +290,7 @@ pub mod reimpls { } #[export_name="__umodti3"] - pub extern fn u128_mod(a: u128_, b: u128_) -> u128_ { + pub extern "C" fn u128_mod(a: u128_, b: u128_) -> u128_ { unsafe { let mut r = ::core::mem::zeroed(); u128_div_mod(a, b, &mut r); @@ -293,7 +299,7 @@ pub mod reimpls { } #[export_name="__modti3"] - pub extern fn i128_mod(a: i128_, b: i128_) -> i128_ { + pub extern "C" fn i128_mod(a: i128_, b: i128_) -> i128_ { let b = b.uabs(); let sa = a.signum(); let a = a.uabs(); @@ -305,7 +311,7 @@ pub mod reimpls { } #[export_name="__divti3"] - pub extern fn i128_div(a: i128_, b: i128_) -> i128_ { + pub extern "C" fn i128_div(a: i128_, b: i128_) -> i128_ { let sa = a.signum(); let sb = b.signum(); let a = a.uabs(); @@ -319,7 +325,7 @@ pub mod reimpls { } #[export_name="__udivti3"] - pub extern fn u128_div(a: u128_, b: u128_) -> u128_ { + pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128_ { u128_div_mod(a, b, ptr::null_mut()) } @@ -365,7 +371,7 @@ pub mod reimpls { // FIXME: i32 here should be c_int. #[export_name="__muloti4"] - pub extern fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128_ { + pub extern "C" fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128_ { mulo!(a, b, o, i128_) } @@ -465,24 +471,25 @@ pub mod reimpls { #[cfg(stage0)] #[export_name="__multi3"] - pub extern fn u128_mul(a: i128_, b: i128_) -> i128_ { + pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128_ { (a as i64 * b as i64) as i128_ } #[cfg(not(stage0))] #[export_name="__multi3"] - pub extern fn u128_mul(a: i128_, b: i128_) -> i128_ { + pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128_ { mul!(a, b, i128_, i64) } trait AbsExt: Sized { - fn uabs(self) -> u128_ { - self.iabs() as u128_ - } + fn uabs(self) -> u128_; fn iabs(self) -> i128_; } impl AbsExt for i128_ { + fn uabs(self) -> u128_ { + self.iabs() as u128_ + } fn iabs(self) -> i128_ { ((self ^ self).wrapping_sub(self)) } @@ -550,12 +557,12 @@ pub mod reimpls { } #[export_name="__fixunsdfti"] - pub extern fn f64_as_u128(a: f64) -> u128_ { + pub extern "C" fn f64_as_u128(a: f64) -> u128_ { float_as_unsigned!(a, f64, u128_) } #[export_name="__fixunssfti"] - pub extern fn f32_as_u128(a: f32) -> u128_ { + pub extern "C" fn f32_as_u128(a: f32) -> u128_ { float_as_unsigned!(a, f32, u128_) } @@ -582,17 +589,17 @@ pub mod reimpls { } #[export_name="__fixdfti"] - pub extern fn f64_as_i128(a: f64) -> i128_ { + pub extern "C" fn f64_as_i128(a: f64) -> i128_ { float_as_signed!(a, f64, i128_) } #[export_name="__fixsfti"] - pub extern fn f32_as_i128(a: f32) -> i128_ { + pub extern "C" fn f32_as_i128(a: f32) -> i128_ { float_as_signed!(a, f32, i128_) } #[export_name="__floattidf"] - pub extern fn i128_as_f64(a: i128_) -> f64 { + pub extern "C" fn i128_as_f64(a: i128_) -> f64 { match a.signum() { 1 => u128_as_f64(a.uabs()), 0 => 0.0, @@ -602,7 +609,7 @@ pub mod reimpls { } #[export_name="__floattisf"] - pub extern fn i128_as_f32(a: i128_) -> f32 { + pub extern "C" fn i128_as_f32(a: i128_) -> f32 { match a.signum() { 1 => u128_as_f32(a.uabs()), 0 => 0.0, @@ -612,7 +619,7 @@ pub mod reimpls { } #[export_name="__floatuntidf"] - pub extern fn u128_as_f64(mut a: u128_) -> f64 { + pub extern "C" fn u128_as_f64(mut a: u128_) -> f64 { use ::core::f64::MANTISSA_DIGITS; if a == 0 { return 0.0; } let sd = 128 - a.leading_zeros(); @@ -643,7 +650,7 @@ pub mod reimpls { } #[export_name="__floatuntisf"] - pub extern fn u128_as_f32(mut a: u128_) -> f32 { + pub extern "C" fn u128_as_f32(mut a: u128_) -> f32 { use ::core::f32::MANTISSA_DIGITS; if a == 0 { return 0.0; } let sd = 128 - a.leading_zeros(); From 3be141f1b46be54607277444956a211ee56a359c Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 7 Dec 2016 16:56:26 +0100 Subject: [PATCH 28/47] Remove unimplemented() function --- src/libcompiler_builtins/lib.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 677a6e9456807..818d7fb86c0fd 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -46,10 +46,6 @@ pub mod reimpls { #[cfg(not(stage0))] type i128_ = i128; - fn unimplemented() -> ! { - unsafe { ::core::intrinsics::abort() } - } - macro_rules! ashl { ($a:expr, $b:expr, $ty:ty) => {{ let (a, b) = ($a, $b); @@ -603,8 +599,7 @@ pub mod reimpls { match a.signum() { 1 => u128_as_f64(a.uabs()), 0 => 0.0, - -1 => -u128_as_f64(a.uabs()), - _ => unimplemented() + _ => -u128_as_f64(a.uabs()), } } @@ -613,8 +608,7 @@ pub mod reimpls { match a.signum() { 1 => u128_as_f32(a.uabs()), 0 => 0.0, - -1 => -u128_as_f32(a.uabs()), - _ => unimplemented() + _ => -u128_as_f32(a.uabs()), } } From 53ff50a94f083ec44bd6f6cb56ded6c52fcc7b8a Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 8 Dec 2016 19:02:22 +0100 Subject: [PATCH 29/47] Port to wrapping_* and unchecked_* operations Otherwise, we codegen panic calls which create problems with debug assertions turned on. --- src/libcompiler_builtins/lib.rs | 196 +++++++++++++++++++------------- 1 file changed, 118 insertions(+), 78 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 818d7fb86c0fd..8d124b7e0aab8 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -50,13 +50,17 @@ pub mod reimpls { ($a:expr, $b:expr, $ty:ty) => {{ let (a, b) = ($a, $b); let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; - let half_bits = bits / 2; + let half_bits = bits >> 1; if b & half_bits != 0 { - <$ty>::from_parts(0, a.low() << (b - half_bits)) + <$ty>::from_parts(0, a.low().wrapping_shl( + b.wrapping_sub(half_bits) as u32)) } else if b == 0 { a } else { - <$ty>::from_parts(a.low() << b, (a.high() << b) | (a.low() >> (half_bits - b))) + <$ty>::from_parts(a.low().wrapping_shl(b as u32), + a.high().wrapping_shl(b as u32) + | a.low() + .wrapping_shr(half_bits.wrapping_sub(b) as u32)) } }} } @@ -72,14 +76,16 @@ pub mod reimpls { let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; let half_bits = bits >> 1; if b & half_bits != 0 { - <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, - a.high() >> (half_bits - 1)) + <$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32) + as <$ty as LargeInt>::LowHalf, + a.high().wrapping_shr(half_bits.wrapping_sub(1) as u32)) } else if b == 0 { a } else { let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf; - <$ty>::from_parts((high_unsigned << (half_bits - b)) | (a.low() >> b), - a.high() >> b) + <$ty>::from_parts(high_unsigned.wrapping_shl(half_bits.wrapping_sub(b) as u32) + | a.low().wrapping_shr(b as u32), + a.high().wrapping_shr(b as u32)) } }} } @@ -95,11 +101,13 @@ pub mod reimpls { let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; let half_bits = bits >> 1; if b & half_bits != 0 { - <$ty>::from_parts(a.high() >> (b - half_bits), 0) + <$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32), 0) } else if b == 0 { a } else { - <$ty>::from_parts((a.high() << (half_bits - b)) | (a.low() >> b), a.high() >> b) + <$ty>::from_parts(a.high().wrapping_shl(half_bits.wrapping_sub(b) as u32) + | a.low().wrapping_shr(b as u32), + a.high().wrapping_shr(b as u32)) } }} } @@ -178,9 +186,10 @@ pub mod reimpls { if d.high().is_power_of_two() { if !rem.is_null() { - *rem = u128::from_parts(n.low(), n.high() & (d.high() - 1)); + *rem = u128::from_parts(n.low(), + n.high() & (d.high().wrapping_sub(1))); } - return u128::from(n.high() >> d.high().trailing_zeros()); + return u128::from(n.high().wrapping_shr(d.high().trailing_zeros())); } // K K @@ -196,11 +205,11 @@ pub mod reimpls { return 0; } - sr += 1; + sr = sr.wrapping_add(1); // 1 <= sr <= u64::bits() - 1 - q = n << (64 - sr); - r = n >> sr; + q = n.wrapping_shl(64u32.wrapping_sub(sr)); + r = n.wrapping_shr(sr); } else { if d.high() == 0 { // K X @@ -208,22 +217,24 @@ pub mod reimpls { // 0 K if d.low().is_power_of_two() { if !rem.is_null() { - *rem = u128::from(n.low() & (d.low() - 1)); + *rem = u128::from(n.low() & (d.low().wrapping_sub(1))); } if d.low() == 1 { return n; } else { let sr = d.low().trailing_zeros(); - return n >> sr; + return n.wrapping_shr(sr); }; } - sr = 1 + 64 + d.low().leading_zeros() - n.high().leading_zeros(); + sr = (1 + 64u32) + .wrapping_add(d.low().leading_zeros()) + .wrapping_sub(n.high().leading_zeros()); // 2 <= sr <= u64::bits() - 1 - q = n << (128 - sr); - r = n >> sr; + q = n.wrapping_shl(128u32.wrapping_sub(sr)); + r = n.wrapping_shr(sr); // FIXME the C compiler-rt implementation has something here // that looks like a speed optimisation. // It would be worth a try to port it to Rust too and @@ -242,11 +253,11 @@ pub mod reimpls { return 0; } - sr += 1; + sr = sr.wrapping_add(1); // 1 <= sr <= u32::bits() - q = n << (128 - sr); - r = n >> sr; + q = n.wrapping_shl(128u32.wrapping_sub(sr)); + r = n.wrapping_shr(sr); } } @@ -264,24 +275,24 @@ pub mod reimpls { // compilation steps) while sr > 0 { // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (128 - 1)); - q = (q << 1) | carry as u128; + r = r.wrapping_shl(1) | q.wrapping_shr(128 - 1); + q = q.wrapping_shl(1) | carry as u128; // carry = 0 // if r >= d { // r -= d; // carry = 1; // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i128 >> (128 - 1); + let s = ((d.wrapping_sub(r).wrapping_sub(1)) as i128).wrapping_shr(128 - 1); carry = (s & 1) as u64; - r -= d & s as u128; - sr -= 1; + r = r.wrapping_sub(d & s as u128); + sr = sr.wrapping_sub(1); } if !rem.is_null() { *rem = r; } - (q << 1) | carry as u128 + (q.wrapping_shl(1)) | carry as u128 } } @@ -302,7 +313,7 @@ pub mod reimpls { unsafe { let mut r = ::core::mem::zeroed(); u128_div_mod(a, b, &mut r); - if sa == -1 { -(r as i128_) } else { r as i128_ } + if sa == -1 { (r as i128_).unchecked_neg() } else { r as i128_ } } } @@ -312,9 +323,9 @@ pub mod reimpls { let sb = b.signum(); let a = a.uabs(); let b = b.uabs(); - let sr = sa * sb; // sign of quotient + let sr = sa.wrapping_mul(sb); // sign of quotient if sr == -1 { - -(u128_div_mod(a, b, ptr::null_mut()) as i128_) + (u128_div_mod(a, b, ptr::null_mut()) as i128_).unchecked_neg() } else { u128_div_mod(a, b, ptr::null_mut()) as i128_ } @@ -356,7 +367,7 @@ pub mod reimpls { *overflow = 1; } } else { - if abs_a > unchecked_div(<$ty>::min_value(), -abs_b) { + if abs_a > unchecked_div(<$ty>::min_value(), abs_b.unchecked_neg()) { *overflow = 1; } } @@ -387,10 +398,10 @@ pub mod reimpls { self as u32 } fn high(self) -> u32 { - (self >> 32) as u32 + (self.wrapping_shr(32)) as u32 } fn from_parts(low: u32, high: u32) -> u64 { - low as u64 | ((high as u64) << 32) + low as u64 | (high as u64).wrapping_shl(32) } } impl LargeInt for i64 { @@ -401,10 +412,10 @@ pub mod reimpls { self as u32 } fn high(self) -> i32 { - (self >> 32) as i32 + self.wrapping_shr(32) as i32 } fn from_parts(low: u32, high: i32) -> i64 { - low as i64 | ((high as i64) << 32) + low as i64 | (high as i64).wrapping_shl(32) } } #[cfg(not(stage0))] @@ -442,20 +453,23 @@ pub mod reimpls { macro_rules! mul { ($a:expr, $b:expr, $ty: ty, $tyh: ty) => {{ let (a, b) = ($a, $b); - let half_bits = (::core::mem::size_of::<$tyh>() * 8) / 2; - let lower_mask = !0 >> half_bits; - let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); - let mut t = low >> half_bits; + let half_bits = ((::core::mem::size_of::<$tyh>() * 8) / 2) as u32; + let lower_mask = (!0u64).wrapping_shr(half_bits); + let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask); + let mut t = low.wrapping_shr(half_bits); low &= lower_mask; - t += (a.low() >> half_bits) * (b.low() & lower_mask); - low += (t & lower_mask) << half_bits; - let mut high = (t >> half_bits) as $tyh; - t = low >> half_bits; + t = t.wrapping_add(a.low().wrapping_shr(half_bits) + .wrapping_mul(b.low() & lower_mask)); + low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits)); + let mut high = t.wrapping_shr(half_bits) as $tyh; + t = low.wrapping_shr(half_bits); low &= lower_mask; - t += (b.low() >> half_bits) * (a.low() & lower_mask); - low += (t & lower_mask) << half_bits; - high += (t >> half_bits) as $tyh; - high += ((a.low() >> half_bits) * (b.low() >> half_bits)) as $tyh; + t = t.wrapping_add(b.low().wrapping_shr(half_bits) + .wrapping_mul(a.low() & lower_mask)); + low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits)); + high = high.wrapping_add(t.wrapping_shr(half_bits) as $tyh); + high = high.wrapping_add(a.low().wrapping_shr(half_bits) + .wrapping_mul(b.low().wrapping_shr(half_bits)) as $tyh); high = high .wrapping_add(a.high() .wrapping_mul(b.low() as $tyh)) @@ -468,7 +482,7 @@ pub mod reimpls { #[cfg(stage0)] #[export_name="__multi3"] pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128_ { - (a as i64 * b as i64) as i128_ + (a as i64).wrapping_mul(b as i64) as i128_ } #[cfg(not(stage0))] @@ -491,6 +505,16 @@ pub mod reimpls { } } + trait NegExt: Sized { + fn unchecked_neg(self) -> i128_; + } + + impl NegExt for i128_ { + fn unchecked_neg(self) -> i128_ { + (!self).wrapping_add(1) + } + } + trait FloatStuff: Sized { type ToBytes; @@ -514,7 +538,8 @@ pub mod reimpls { fn to_bytes(self) -> u32 { unsafe { ::core::mem::transmute(self) } } fn get_exponent(self) -> i32 { - (((self.to_bytes() & Self::EXP_MASK) >> Self::MANTISSA_BITS) as i32) - Self::MAX_EXP + ((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32) + .wrapping_sub(Self::MAX_EXP) } } @@ -528,7 +553,8 @@ pub mod reimpls { fn to_bytes(self) -> u64 { unsafe { ::core::mem::transmute(self) } } fn get_exponent(self) -> i32 { - (((self.to_bytes() & Self::EXP_MASK) >> Self::MANTISSA_BITS) as i32) - Self::MAX_EXP + ((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32) + .wrapping_sub(Self::MAX_EXP) } } @@ -545,9 +571,11 @@ pub mod reimpls { return !0; } if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { - mantissa as $outty >> (<$fromty as FloatStuff>::MANTISSA_BITS as i32 - exponent) + (mantissa as $outty) + .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32).wrapping_sub(exponent) as u32) } else { - mantissa as $outty << (exponent - <$fromty as FloatStuff>::MANTISSA_BITS as i32) + (mantissa as $outty) + .wrapping_shl(exponent.wrapping_sub(<$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) } } } } @@ -576,11 +604,13 @@ pub mod reimpls { return if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }; } let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { - mantissa as $outty >> (<$fromty as FloatStuff>::MANTISSA_BITS as i32 - exponent) + (mantissa as $outty) + .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32).wrapping_sub(exponent) as u32) } else { - mantissa as $outty << (exponent - <$fromty as FloatStuff>::MANTISSA_BITS as i32) + (mantissa as $outty) + .wrapping_shl(exponent.wrapping_sub(<$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) }; - if sign >= 0.0 { r } else { -r } + if sign >= 0.0 { r } else { r.unchecked_neg() } }} } @@ -616,30 +646,35 @@ pub mod reimpls { pub extern "C" fn u128_as_f64(mut a: u128_) -> f64 { use ::core::f64::MANTISSA_DIGITS; if a == 0 { return 0.0; } - let sd = 128 - a.leading_zeros(); - let mut e = sd - 1; + let sd = 128u32.wrapping_sub(a.leading_zeros()); + let mut e = sd.wrapping_sub(1); const MD1 : u32 = MANTISSA_DIGITS + 1; const MD2 : u32 = MANTISSA_DIGITS + 2; + // SNAP: replace this with !0u128 + let negn :u128_ = !0; + if sd > MANTISSA_DIGITS { a = match sd { - MD1 => a << 1, + MD1 => a.wrapping_shl(1), MD2 => a, - _ => (a >> (sd - (MANTISSA_DIGITS + 2))) | - (if (a & (!0 >> (128 + MANTISSA_DIGITS + 2) - sd)) == 0 { 0 } else { 1 }) + _ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) | + (if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2) + .wrapping_sub(sd as u128_))) == 0 { 0 } else { 1 }) }; a |= if (a & 4) == 0 { 0 } else { 1 }; - a += 1; - a >>= 2; + a = a.wrapping_add(1); + a = a.wrapping_shr(2); if a & (1 << MANTISSA_DIGITS) != 0 { - a >>= 1; - e += 1; + a = a.wrapping_shr(1); + e = e.wrapping_add(1); } } else { - a <<= MANTISSA_DIGITS - sd; + a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd)); } unsafe { - ::core::mem::transmute(((e as u64 + 1023) << 52) | (a as u64 & 0x000f_ffff_ffff_ffff)) + ::core::mem::transmute((e as u64).wrapping_add(1023).wrapping_shl(52) + | (a as u64 & 0x000f_ffff_ffff_ffff)) } } @@ -647,30 +682,35 @@ pub mod reimpls { pub extern "C" fn u128_as_f32(mut a: u128_) -> f32 { use ::core::f32::MANTISSA_DIGITS; if a == 0 { return 0.0; } - let sd = 128 - a.leading_zeros(); - let mut e = sd - 1; + let sd = 128u32.wrapping_sub(a.leading_zeros()); + let mut e = sd.wrapping_sub(1); const MD1 : u32 = MANTISSA_DIGITS + 1; const MD2 : u32 = MANTISSA_DIGITS + 2; + // SNAP: replace this with !0u128 + let negn :u128_ = !0; + if sd > MANTISSA_DIGITS { a = match sd { - MD1 => a << 1, + MD1 => a.wrapping_shl(1), MD2 => a, - _ => (a >> (sd - (MANTISSA_DIGITS + 2))) | - (if (a & (!0 >> (128 + MANTISSA_DIGITS + 2) - sd)) == 0 { 0 } else { 1 }) + _ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) | + (if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2) + .wrapping_sub(sd as u128_))) == 0 { 0 } else { 1 }) }; a |= if (a & 4) == 0 { 0 } else { 1 }; - a += 1; - a >>= 2; + a = a.wrapping_add(1); + a = a.wrapping_shr(2); if a & (1 << MANTISSA_DIGITS) != 0 { - a >>= 1; - e += 1; + a = a.wrapping_shr(1); + e = e.wrapping_add(1); } } else { - a <<= MANTISSA_DIGITS - sd; + a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd)); } unsafe { - ::core::mem::transmute(((e + 127) << 23) | (a as u32 & 0x007f_ffff)) + ::core::mem::transmute((e as u32).wrapping_add(127).wrapping_shl(23) + | (a as u32 & 0x007f_ffff)) } } } From ca73affe8d060eaea9ff44950e758ed17fb4034a Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 8 Dec 2016 20:02:20 +0100 Subject: [PATCH 30/47] Tidy --- src/libcompiler_builtins/lib.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 8d124b7e0aab8..bd62b342bfd4b 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -572,10 +572,12 @@ pub mod reimpls { } if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { (mantissa as $outty) - .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32).wrapping_sub(exponent) as u32) + .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32) + .wrapping_sub(exponent) as u32) } else { (mantissa as $outty) - .wrapping_shl(exponent.wrapping_sub(<$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) + .wrapping_shl(exponent.wrapping_sub( + <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) } } } } @@ -605,10 +607,12 @@ pub mod reimpls { } let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { (mantissa as $outty) - .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32).wrapping_sub(exponent) as u32) + .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32) + .wrapping_sub(exponent) as u32) } else { (mantissa as $outty) - .wrapping_shl(exponent.wrapping_sub(<$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) + .wrapping_shl(exponent.wrapping_sub( + <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) }; if sign >= 0.0 { r } else { r.unchecked_neg() } }} From 92163f1c5e73cd8430276ba738d2cc3bca116163 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 10 Dec 2016 22:18:01 +0100 Subject: [PATCH 31/47] Windows x64 ABI requires i128 params to be passed as reference --- src/librustc_trans/cabi_x86_win64.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librustc_trans/cabi_x86_win64.rs b/src/librustc_trans/cabi_x86_win64.rs index 71ecb6e9ca104..a849f38247380 100644 --- a/src/librustc_trans/cabi_x86_win64.rs +++ b/src/librustc_trans/cabi_x86_win64.rs @@ -18,16 +18,20 @@ use type_::Type; pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { let fixup = |a: &mut ArgType| { - if a.ty.kind() == Struct { - match llsize_of_alloc(ccx, a.ty) { - 1 => a.cast = Some(Type::i8(ccx)), - 2 => a.cast = Some(Type::i16(ccx)), - 4 => a.cast = Some(Type::i32(ccx)), - 8 => a.cast = Some(Type::i64(ccx)), - _ => a.make_indirect(ccx) - } - } else { - a.extend_integer_width_to(32); + match a.ty.kind() { + Struct => match llsize_of_alloc(ccx, a.ty) { + 1 => a.cast = Some(Type::i8(ccx)), + 2 => a.cast = Some(Type::i16(ccx)), + 4 => a.cast = Some(Type::i32(ccx)), + 8 => a.cast = Some(Type::i64(ccx)), + _ => a.make_indirect(ccx) + }, + Integer => match llsize_of_alloc(ccx, a.ty) { + 1 ... 8 => a.extend_integer_width_to(32), + 16 => a.make_indirect(ccx), + _ => bug!(), + }, + _ => (), } }; From d71223a6c54cd80392c7141b0f081fffb8dee628 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 12 Dec 2016 04:56:00 +0100 Subject: [PATCH 32/47] intrinsics: try to return everything via {u,i}128ret to match LLVM on suggestion by nagisa. --- src/libcompiler_builtins/lib.rs | 137 +++++++++++++++++++++++--------- 1 file changed, 99 insertions(+), 38 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index bd62b342bfd4b..6d1c604680678 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -19,7 +19,7 @@ #![feature(staged_api)] #![cfg_attr(any(target_pointer_width="32", target_pointer_width="16", target_os="windows", target_arch="mips64"), - feature(core_intrinsics, core_float))] + feature(core_intrinsics, core_float, repr_simd))] #![feature(associated_consts)] #![cfg_attr(not(stage0), feature(i128_type))] @@ -46,6 +46,29 @@ pub mod reimpls { #[cfg(not(stage0))] type i128_ = i128; + // Unfortunately, every tool on Windows expects different + // calling conventions to be met for int128. We need to + // match here what LLVM expects from us. This is only + // required for the return type! + #[cfg(not(stage0))] + #[cfg(windows)] + #[repr(simd)] + pub struct u64x2(u64, u64); + + #[cfg(not(stage0))] + #[cfg(windows)] + type u128ret = u64x2; + + #[cfg(any(not(windows),stage0))] + type u128ret = u128_; + + #[cfg(not(stage0))] + #[cfg(windows)] + type i128ret = u64x2; + + #[cfg(any(not(windows),stage0))] + type i128ret = i128_; + macro_rules! ashl { ($a:expr, $b:expr, $ty:ty) => {{ let (a, b) = ($a, $b); @@ -114,24 +137,27 @@ pub mod reimpls { #[export_name="__lshrti3"] - pub extern "C" fn lshr(a: u128_, b: u128_) -> u128_ { - lshr!(a, b, u128_) + pub extern "C" fn lshr(a: u128_, b: u128_) -> u128ret { + lshr!(a, b, u128_).to_ret() } - #[cfg(stage0)] #[export_name="__udivmodti4"] - pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { + pub extern "C" fn u128_div_mod_export(n: u128_, d: u128_, rem: *mut u128_) -> u128ret { + u128_div_mod(n, d, rem).to_ret() + } + + #[cfg(stage0)] + pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128ret { unsafe { if !rem.is_null() { *rem = unchecked_rem(n, d); } - unchecked_div(n, d) + unchecked_div(n, d).to_ret() } } #[cfg(not(stage0))] - #[export_name="__udivmodti4"] - pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { + pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128 { // Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide unsafe { // special cases, X is unknown, K != 0 @@ -297,43 +323,50 @@ pub mod reimpls { } #[export_name="__umodti3"] - pub extern "C" fn u128_mod(a: u128_, b: u128_) -> u128_ { + pub extern "C" fn u128_mod(a: u128_, b: u128_) -> u128ret { unsafe { let mut r = ::core::mem::zeroed(); u128_div_mod(a, b, &mut r); - r + r.to_ret() } } #[export_name="__modti3"] - pub extern "C" fn i128_mod(a: i128_, b: i128_) -> i128_ { + pub extern "C" fn i128_mod(a: i128_, b: i128_) -> i128ret { let b = b.uabs(); let sa = a.signum(); let a = a.uabs(); - unsafe { + (unsafe { let mut r = ::core::mem::zeroed(); u128_div_mod(a, b, &mut r); if sa == -1 { (r as i128_).unchecked_neg() } else { r as i128_ } - } + }).to_ret() } #[export_name="__divti3"] - pub extern "C" fn i128_div(a: i128_, b: i128_) -> i128_ { + pub extern "C" fn i128_div(a: i128_, b: i128_) -> i128ret { let sa = a.signum(); let sb = b.signum(); let a = a.uabs(); let b = b.uabs(); let sr = sa.wrapping_mul(sb); // sign of quotient - if sr == -1 { + (if sr == -1 { (u128_div_mod(a, b, ptr::null_mut()) as i128_).unchecked_neg() } else { u128_div_mod(a, b, ptr::null_mut()) as i128_ - } + }).to_ret() } + #[cfg(stage0)] + #[export_name="__udivti3"] + pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128ret { + (a / b).to_ret() + } + + #[cfg(not(stage0))] #[export_name="__udivti3"] - pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128_ { - u128_div_mod(a, b, ptr::null_mut()) + pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128ret { + u128_div_mod(a, b, ptr::null_mut()).to_ret() } macro_rules! mulo { @@ -345,13 +378,13 @@ pub mod reimpls { if b != 0 && b != 1 { *overflow = 1; } - return result; + return result.to_ret(); } if b == <$ty>::min_value() { if a != 0 && a != 1 { *overflow = 1; } - return result; + return result.to_ret(); } let sa = a.signum(); @@ -359,7 +392,7 @@ pub mod reimpls { let sb = b.signum(); let abs_b = b.iabs(); if abs_a < 2 || abs_b < 2 { - return result; + return result.to_ret(); } unsafe { if sa == sb { @@ -372,27 +405,30 @@ pub mod reimpls { } } } - result + result.to_ret() }} } // FIXME: i32 here should be c_int. #[export_name="__muloti4"] - pub extern "C" fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128_ { + pub extern "C" fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128ret { mulo!(a, b, o, i128_) } pub trait LargeInt { type LowHalf; type HighHalf; + type Ret; fn low(self) -> Self::LowHalf; fn high(self) -> Self::HighHalf; fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; + fn to_ret(self) -> Self::Ret; } impl LargeInt for u64 { type LowHalf = u32; type HighHalf = u32; + type Ret = u64; fn low(self) -> u32 { self as u32 @@ -403,10 +439,14 @@ pub mod reimpls { fn from_parts(low: u32, high: u32) -> u64 { low as u64 | (high as u64).wrapping_shl(32) } + fn to_ret(self) -> u64 { + self + } } impl LargeInt for i64 { type LowHalf = u32; type HighHalf = i32; + type Ret = i64; fn low(self) -> u32 { self as u32 @@ -417,11 +457,15 @@ pub mod reimpls { fn from_parts(low: u32, high: i32) -> i64 { low as i64 | (high as i64).wrapping_shl(32) } + fn to_ret(self) -> i64 { + self + } } #[cfg(not(stage0))] impl LargeInt for u128 { type LowHalf = u64; type HighHalf = u64; + type Ret = u128ret; fn low(self) -> u64 { self as u64 @@ -433,11 +477,20 @@ pub mod reimpls { #[repr(C, packed)] struct Parts(u64, u64); unsafe { ::core::mem::transmute(Parts(low, high)) } } + #[cfg(not(windows))] + fn to_ret(self) -> u128ret { + self + } + #[cfg(windows)] + fn to_ret(self) -> u128ret { + u64x2(self.low(), self.high()) + } } #[cfg(not(stage0))] impl LargeInt for i128 { type LowHalf = u64; type HighHalf = i64; + type Ret = i128ret; fn low(self) -> u64 { self as u64 @@ -448,6 +501,14 @@ pub mod reimpls { fn from_parts(low: u64, high: i64) -> i128 { u128::from_parts(low, high as u64) as i128 } + #[cfg(not(windows))] + fn to_ret(self) -> u128ret { + self + } + #[cfg(windows)] + fn to_ret(self) -> i128ret { + u64x2(self.low(), self.high() as u64) + } } macro_rules! mul { @@ -481,14 +542,14 @@ pub mod reimpls { #[cfg(stage0)] #[export_name="__multi3"] - pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128_ { - (a as i64).wrapping_mul(b as i64) as i128_ + pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128ret { + ((a as i64).wrapping_mul(b as i64) as i128_).to_ret() } #[cfg(not(stage0))] #[export_name="__multi3"] - pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128_ { - mul!(a, b, i128_, i64) + pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128ret { + mul!(a, b, i128_, i64).to_ret() } trait AbsExt: Sized { @@ -566,11 +627,11 @@ pub mod reimpls { let exponent = $from.get_exponent(); let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK; let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; - if sign == -1.0 || exponent < 0 { return 0; } + if sign == -1.0 || exponent < 0 { return (0 as u128_).to_ret(); } if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { - return !0; + return (!(0 as u128_)).to_ret(); } - if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { + (if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { (mantissa as $outty) .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32) .wrapping_sub(exponent) as u32) @@ -578,17 +639,17 @@ pub mod reimpls { (mantissa as $outty) .wrapping_shl(exponent.wrapping_sub( <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) - } + }).to_ret() } } } #[export_name="__fixunsdfti"] - pub extern "C" fn f64_as_u128(a: f64) -> u128_ { + pub extern "C" fn f64_as_u128(a: f64) -> u128ret { float_as_unsigned!(a, f64, u128_) } #[export_name="__fixunssfti"] - pub extern "C" fn f32_as_u128(a: f32) -> u128_ { + pub extern "C" fn f32_as_u128(a: f32) -> u128ret { float_as_unsigned!(a, f32, u128_) } @@ -601,9 +662,9 @@ pub mod reimpls { let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK; let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; - if exponent < 0 { return 0; } + if exponent < 0 { return (0 as i128_).to_ret(); } if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { - return if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }; + return (if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }).to_ret(); } let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { (mantissa as $outty) @@ -614,17 +675,17 @@ pub mod reimpls { .wrapping_shl(exponent.wrapping_sub( <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) }; - if sign >= 0.0 { r } else { r.unchecked_neg() } + (if sign >= 0.0 { r } else { r.unchecked_neg() }).to_ret() }} } #[export_name="__fixdfti"] - pub extern "C" fn f64_as_i128(a: f64) -> i128_ { + pub extern "C" fn f64_as_i128(a: f64) -> i128ret { float_as_signed!(a, f64, i128_) } #[export_name="__fixsfti"] - pub extern "C" fn f32_as_i128(a: f32) -> i128_ { + pub extern "C" fn f32_as_i128(a: f32) -> i128ret { float_as_signed!(a, f32, i128_) } From c3e3bc0058e35cc665608935a525caa736eacd19 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 14 Dec 2016 04:19:45 +0100 Subject: [PATCH 33/47] Fix another windows ABI mistake ...this time with the float intrinsics. --- src/libcompiler_builtins/lib.rs | 34 +++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 6d1c604680678..8a1f02d661e24 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -689,7 +689,33 @@ pub mod reimpls { float_as_signed!(a, f32, i128_) } - #[export_name="__floattidf"] + // LLVM expectations for ABI on windows are pure madness. + + #[cfg(not(stage0))] + #[cfg_attr(windows, export_name="__floattidf")] + pub extern "C" fn i128_as_f64_win(alow: u64, ahigh: i64) -> f64 { + i128_as_f64(i128_::from_parts(alow, ahigh)) + } + + #[cfg(not(stage0))] + #[cfg_attr(windows, export_name="__floattisf")] + pub extern "C" fn i128_as_f32_win(alow: u64, ahigh: i64) -> f32 { + i128_as_f32(i128_::from_parts(alow, ahigh)) + } + + #[cfg(not(stage0))] + #[cfg_attr(windows, export_name="__floatuntidf")] + pub extern "C" fn u128_as_f64_win(alow: u64, ahigh: u64) -> f64 { + u128_as_f64(u128_::from_parts(alow, ahigh)) + } + + #[cfg(not(stage0))] + #[cfg_attr(windows, export_name="__floatuntisf")] + pub extern "C" fn u128_as_f32_win(alow: u64, ahigh: u64) -> f32 { + u128_as_f32(u128_::from_parts(alow, ahigh)) + } + + #[cfg_attr(any(not(windows),stage0),export_name="__floattidf")] pub extern "C" fn i128_as_f64(a: i128_) -> f64 { match a.signum() { 1 => u128_as_f64(a.uabs()), @@ -698,7 +724,7 @@ pub mod reimpls { } } - #[export_name="__floattisf"] + #[cfg_attr(any(not(windows),stage0),export_name="__floattisf")] pub extern "C" fn i128_as_f32(a: i128_) -> f32 { match a.signum() { 1 => u128_as_f32(a.uabs()), @@ -707,7 +733,7 @@ pub mod reimpls { } } - #[export_name="__floatuntidf"] + #[cfg_attr(any(not(windows),stage0),export_name="__floatuntidf")] pub extern "C" fn u128_as_f64(mut a: u128_) -> f64 { use ::core::f64::MANTISSA_DIGITS; if a == 0 { return 0.0; } @@ -743,7 +769,7 @@ pub mod reimpls { } } - #[export_name="__floatuntisf"] + #[cfg_attr(any(not(windows),stage0),export_name="__floatuntisf")] pub extern "C" fn u128_as_f32(mut a: u128_) -> f32 { use ::core::f32::MANTISSA_DIGITS; if a == 0 { return 0.0; } From 01dcb7fe6c386b4dc529bb666ba70bc8f4cc18b2 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 14 Dec 2016 05:12:12 +0100 Subject: [PATCH 34/47] Tidy --- src/libcompiler_builtins/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 8a1f02d661e24..92c6f8dd72845 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -664,7 +664,8 @@ pub mod reimpls { if exponent < 0 { return (0 as i128_).to_ret(); } if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { - return (if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }).to_ret(); + let ret = if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }; + return ret.to_ret(); } let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { (mantissa as $outty) From 8cbe725d34d3f04a99d557c066e6191d0af74ed7 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 14 Dec 2016 12:57:38 +0100 Subject: [PATCH 35/47] Fix rebase fallout --- src/librustc_metadata/decoder.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index cfc4dfb90753e..dad956afb5e60 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -43,7 +43,6 @@ use syntax::attr; use syntax::ast::{self, NodeId}; use syntax::codemap; use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP}; -use syntax_pos::{self, Span, BytePos, Pos}; use rustc_i128::{u128, i128}; pub struct DecodeContext<'a, 'tcx: 'a> { From dd10c5a5033cd90af65e32a08c43ce5e34fc9168 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 15 Dec 2016 22:57:59 +0100 Subject: [PATCH 36/47] Feature gate: 1.16.0 instead of 1.15.0 --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a3f2cd3a0cdb8..a3ecdabbe1ce3 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -323,7 +323,7 @@ declare_features! ( (active, abi_ptx, "1.15.0", None), // The `i128` type - (active, i128_type, "1.15.0", Some(35118)), + (active, i128_type, "1.16.0", Some(35118)), ); declare_features! ( From 0a481fe5d2a028df806e68a1b91177924a0cda35 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 16 Dec 2016 18:01:32 +0100 Subject: [PATCH 37/47] Fix rebase fallout and compilation fixes --- src/Cargo.lock | 1 + src/librustc_data_structures/Cargo.toml | 1 + src/librustc_data_structures/lib.rs | 2 ++ src/librustc_data_structures/stable_hasher.rs | 5 +++-- src/libserialize/leb128.rs | 4 ++-- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index b4455a34e4968..6acdc8102a7d0 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -330,6 +330,7 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "log 0.0.0", + "rustc_i128 0.0.0", "serialize 0.0.0", ] diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index e2e16059d9871..bb6103748102d 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -11,3 +11,4 @@ crate-type = ["dylib"] [dependencies] log = { path = "../liblog" } serialize = { path = "../libserialize" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 86f244d65dd42..d3ec674daed4d 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -44,6 +44,8 @@ extern crate serialize as rustc_serialize; // used by deriving #[cfg(unix)] extern crate libc; +extern crate rustc_i128; + pub use rustc_serialize::hex::ToHex; pub mod array_vec; diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index ed97c3dde5eff..87048eff5b78b 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -13,13 +13,14 @@ use std::marker::PhantomData; use std::mem; use blake2b::Blake2bHasher; use rustc_serialize::leb128; +use rustc_i128::{u128,i128}; fn write_unsigned_leb128_to_buf(buf: &mut [u8; 16], value: u64) -> usize { - leb128::write_unsigned_leb128_to(value, |i, v| buf[i] = v) + leb128::write_unsigned_leb128_to(value as u128, |i, v| buf[i] = v) } fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize { - leb128::write_signed_leb128_to(value, |i, v| buf[i] = v) + leb128::write_signed_leb128_to(value as i128, |i, v| buf[i] = v) } /// When hashing something that ends up affecting properties like symbol names. We diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs index 55ae7ae10f4eb..392f332d508dd 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -26,7 +26,7 @@ fn write_to_vec(vec: &mut Vec, position: usize, byte: u8) { /// The callback `write` is called once for each position /// that is to be written to with the byte to be encoded /// at that position. -pub fn write_unsigned_leb128_to(mut value: u64, mut write: W) -> usize +pub fn write_unsigned_leb128_to(mut value: u128, mut write: W) -> usize where W: FnMut(usize, u8) { let mut position = 0; @@ -48,7 +48,7 @@ pub fn write_unsigned_leb128_to(mut value: u64, mut write: W) -> usize position } -pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, value: u64) -> usize { +pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, value: u128) -> usize { write_unsigned_leb128_to(value, |i, v| write_to_vec(out, start_position+i, v)) } From 208c8f58b20650dbfaad521f566ee433b742210a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 18 Dec 2016 01:47:38 +0200 Subject: [PATCH 38/47] Fix sign-extension in stage1 compiler --- src/librustc_trans/common.rs | 5 +++-- src/librustc_trans/mir/constant.rs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 79aa566376582..7e7bd15dc6e5a 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -427,13 +427,14 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { } } -pub fn C_big_integral(t: Type, u: u128) -> ValueRef { +pub fn C_big_integral(t: Type, u: u128, sign_extend: bool) -> ValueRef { if ::std::mem::size_of::() == 16 { unsafe { llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, &u as *const u128 as *const u64) } } else { - C_integral(t, u as u64, false) + // SNAP: remove after snapshot + C_integral(t, u as u64, sign_extend) } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 04f1e4fb8640e..700894c255da6 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -76,7 +76,7 @@ impl<'tcx> Const<'tcx> { ConstVal::Integral(I16(v)) => C_integral(Type::i16(ccx), v as u64, true), ConstVal::Integral(I32(v)) => C_integral(Type::i32(ccx), v as u64, true), ConstVal::Integral(I64(v)) => C_integral(Type::i64(ccx), v as u64, true), - ConstVal::Integral(I128(v)) => C_big_integral(Type::i128(ccx), v as u128), + ConstVal::Integral(I128(v)) => C_big_integral(Type::i128(ccx), v as u128, true), ConstVal::Integral(Isize(v)) => { let i = v.as_i64(ccx.tcx().sess.target.int_type); C_integral(Type::int(ccx), i as u64, true) @@ -85,7 +85,7 @@ impl<'tcx> Const<'tcx> { ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false), ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false), ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false), - ConstVal::Integral(U128(v)) => C_big_integral(Type::i128(ccx), v), + ConstVal::Integral(U128(v)) => C_big_integral(Type::i128(ccx), v, false), ConstVal::Integral(Usize(v)) => { let u = v.as_u64(ccx.tcx().sess.target.uint_type); C_integral(Type::int(ccx), u, false) From e0e53773e32ec516bcb68409fd60c5dc0b7bc381 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 21 Dec 2016 05:40:46 +0200 Subject: [PATCH 39/47] Fix a return type --- src/libcompiler_builtins/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 92c6f8dd72845..d9da9ef39d236 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -502,7 +502,7 @@ pub mod reimpls { u128::from_parts(low, high as u64) as i128 } #[cfg(not(windows))] - fn to_ret(self) -> u128ret { + fn to_ret(self) -> i128ret { self } #[cfg(windows)] From 5a853b042209e5ad58e642b23c7f70c135104228 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 21 Dec 2016 21:28:13 +0200 Subject: [PATCH 40/47] The windows special-cases only apply to x64 --- src/libcompiler_builtins/lib.rs | 70 ++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index d9da9ef39d236..8e3a3db6fcf9c 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -51,22 +51,22 @@ pub mod reimpls { // match here what LLVM expects from us. This is only // required for the return type! #[cfg(not(stage0))] - #[cfg(windows)] + #[cfg(all(windows, target_pointer_width="64"))] #[repr(simd)] pub struct u64x2(u64, u64); #[cfg(not(stage0))] - #[cfg(windows)] + #[cfg(all(windows, target_pointer_width="64")] type u128ret = u64x2; - #[cfg(any(not(windows),stage0))] + #[cfg(any(not(all(windows, target_pointer_width="64")),stage0))] type u128ret = u128_; #[cfg(not(stage0))] - #[cfg(windows)] + #[cfg(all(windows, target_pointer_width="64")] type i128ret = u64x2; - #[cfg(any(not(windows),stage0))] + #[cfg(any(not(all(windows, target_pointer_width="64")),stage0))] type i128ret = i128_; macro_rules! ashl { @@ -477,11 +477,11 @@ pub mod reimpls { #[repr(C, packed)] struct Parts(u64, u64); unsafe { ::core::mem::transmute(Parts(low, high)) } } - #[cfg(not(windows))] + #[cfg(not(all(windows, target_pointer_width="64")))] fn to_ret(self) -> u128ret { self } - #[cfg(windows)] + #[cfg(all(windows, target_pointer_width="64"))] fn to_ret(self) -> u128ret { u64x2(self.low(), self.high()) } @@ -501,11 +501,11 @@ pub mod reimpls { fn from_parts(low: u64, high: i64) -> i128 { u128::from_parts(low, high as u64) as i128 } - #[cfg(not(windows))] + #[cfg(not(all(windows, target_pointer_width="64")))] fn to_ret(self) -> i128ret { self } - #[cfg(windows)] + #[cfg(all(windows, target_pointer_width="64"))] fn to_ret(self) -> i128ret { u64x2(self.low(), self.high() as u64) } @@ -693,30 +693,35 @@ pub mod reimpls { // LLVM expectations for ABI on windows are pure madness. #[cfg(not(stage0))] - #[cfg_attr(windows, export_name="__floattidf")] - pub extern "C" fn i128_as_f64_win(alow: u64, ahigh: i64) -> f64 { - i128_as_f64(i128_::from_parts(alow, ahigh)) - } + #[cfg(all(windows, target_pointer_width="64"))] + mod windows_64_workarounds { + #[export_name="__floattidf"] + pub extern "C" fn i128_as_f64_win(alow: u64, ahigh: i64) -> f64 { + ::i128_as_f64(i128_::from_parts(alow, ahigh)) + } - #[cfg(not(stage0))] - #[cfg_attr(windows, export_name="__floattisf")] - pub extern "C" fn i128_as_f32_win(alow: u64, ahigh: i64) -> f32 { - i128_as_f32(i128_::from_parts(alow, ahigh)) - } + #[export_name="__floattisf"] + pub extern "C" fn i128_as_f32_win(alow: u64, ahigh: i64) -> f32 { + ::i128_as_f32(i128_::from_parts(alow, ahigh)) + } - #[cfg(not(stage0))] - #[cfg_attr(windows, export_name="__floatuntidf")] - pub extern "C" fn u128_as_f64_win(alow: u64, ahigh: u64) -> f64 { - u128_as_f64(u128_::from_parts(alow, ahigh)) - } + #[export_name="__floatuntidf"] + pub extern "C" fn u128_as_f64_win(alow: u64, ahigh: u64) -> f64 { + ::u128_as_f64(u128_::from_parts(alow, ahigh)) + } - #[cfg(not(stage0))] - #[cfg_attr(windows, export_name="__floatuntisf")] - pub extern "C" fn u128_as_f32_win(alow: u64, ahigh: u64) -> f32 { - u128_as_f32(u128_::from_parts(alow, ahigh)) + #[export_name="__floatuntisf"] + pub extern "C" fn u128_as_f32_win(alow: u64, ahigh: u64) -> f32 { + ::u128_as_f32(u128_::from_parts(alow, ahigh)) + } } + #[cfg(not(stage0))] + #[cfg(all(windows, target_pointer_width="64"))] + pub use windows_64_workarounds::*; + - #[cfg_attr(any(not(windows),stage0),export_name="__floattidf")] + #[cfg_attr(not(all(windows, target_pointer_width="64", not(stage0))), + export_name="__floattidf")] pub extern "C" fn i128_as_f64(a: i128_) -> f64 { match a.signum() { 1 => u128_as_f64(a.uabs()), @@ -725,7 +730,8 @@ pub mod reimpls { } } - #[cfg_attr(any(not(windows),stage0),export_name="__floattisf")] + #[cfg_attr(not(all(windows, target_pointer_width="64", not(stage0))), + export_name="__floattisf")] pub extern "C" fn i128_as_f32(a: i128_) -> f32 { match a.signum() { 1 => u128_as_f32(a.uabs()), @@ -734,7 +740,8 @@ pub mod reimpls { } } - #[cfg_attr(any(not(windows),stage0),export_name="__floatuntidf")] + #[cfg_attr(not(all(windows, target_pointer_width="64", not(stage0))), + export_name="__floatuntidf")] pub extern "C" fn u128_as_f64(mut a: u128_) -> f64 { use ::core::f64::MANTISSA_DIGITS; if a == 0 { return 0.0; } @@ -770,7 +777,8 @@ pub mod reimpls { } } - #[cfg_attr(any(not(windows),stage0),export_name="__floatuntisf")] + #[cfg_attr(not(all(windows, target_pointer_width="64", not(stage0))), + export_name="__floatuntisf")] pub extern "C" fn u128_as_f32(mut a: u128_) -> f32 { use ::core::f32::MANTISSA_DIGITS; if a == 0 { return 0.0; } From 9842d27e9cbb95fc3472cf17a2696d864acf0a8c Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 21 Dec 2016 21:09:52 +0100 Subject: [PATCH 41/47] Fix build --- src/libcompiler_builtins/lib.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 8e3a3db6fcf9c..40ac32875e677 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -56,14 +56,14 @@ pub mod reimpls { pub struct u64x2(u64, u64); #[cfg(not(stage0))] - #[cfg(all(windows, target_pointer_width="64")] + #[cfg(all(windows, target_pointer_width="64"))] type u128ret = u64x2; #[cfg(any(not(all(windows, target_pointer_width="64")),stage0))] type u128ret = u128_; #[cfg(not(stage0))] - #[cfg(all(windows, target_pointer_width="64")] + #[cfg(all(windows, target_pointer_width="64"))] type i128ret = u64x2; #[cfg(any(not(all(windows, target_pointer_width="64")),stage0))] @@ -695,29 +695,31 @@ pub mod reimpls { #[cfg(not(stage0))] #[cfg(all(windows, target_pointer_width="64"))] mod windows_64_workarounds { + use super::{i128_, u128_, LargeInt}; + use super::{i128_as_f64, i128_as_f32, u128_as_f64, u128_as_f32}; #[export_name="__floattidf"] pub extern "C" fn i128_as_f64_win(alow: u64, ahigh: i64) -> f64 { - ::i128_as_f64(i128_::from_parts(alow, ahigh)) + i128_as_f64(i128_::from_parts(alow, ahigh)) } #[export_name="__floattisf"] pub extern "C" fn i128_as_f32_win(alow: u64, ahigh: i64) -> f32 { - ::i128_as_f32(i128_::from_parts(alow, ahigh)) + i128_as_f32(i128_::from_parts(alow, ahigh)) } #[export_name="__floatuntidf"] pub extern "C" fn u128_as_f64_win(alow: u64, ahigh: u64) -> f64 { - ::u128_as_f64(u128_::from_parts(alow, ahigh)) + u128_as_f64(u128_::from_parts(alow, ahigh)) } #[export_name="__floatuntisf"] pub extern "C" fn u128_as_f32_win(alow: u64, ahigh: u64) -> f32 { - ::u128_as_f32(u128_::from_parts(alow, ahigh)) + u128_as_f32(u128_::from_parts(alow, ahigh)) } } #[cfg(not(stage0))] #[cfg(all(windows, target_pointer_width="64"))] - pub use windows_64_workarounds::*; + pub use self::windows_64_workarounds::*; #[cfg_attr(not(all(windows, target_pointer_width="64", not(stage0))), From ee6256b1ffd213d1e07390e4d66f57e6e463020f Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 22 Dec 2016 12:06:30 +0100 Subject: [PATCH 42/47] More windows fixes --- src/libcompiler_builtins/lib.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 40ac32875e677..1c625ea985599 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -378,13 +378,13 @@ pub mod reimpls { if b != 0 && b != 1 { *overflow = 1; } - return result.to_ret(); + return result; } if b == <$ty>::min_value() { if a != 0 && a != 1 { *overflow = 1; } - return result.to_ret(); + return result; } let sa = a.signum(); @@ -392,7 +392,7 @@ pub mod reimpls { let sb = b.signum(); let abs_b = b.iabs(); if abs_a < 2 || abs_b < 2 { - return result.to_ret(); + return result; } unsafe { if sa == sb { @@ -405,13 +405,14 @@ pub mod reimpls { } } } - result.to_ret() + result }} } // FIXME: i32 here should be c_int. - #[export_name="__muloti4"] - pub extern "C" fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128ret { + #[cfg_attr(not(all(windows, target_pointer_width="64", not(stage0))), + export_name="__muloti4")] + pub extern "C" fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128 { mulo!(a, b, o, i128_) } @@ -696,7 +697,14 @@ pub mod reimpls { #[cfg(all(windows, target_pointer_width="64"))] mod windows_64_workarounds { use super::{i128_, u128_, LargeInt}; - use super::{i128_as_f64, i128_as_f32, u128_as_f64, u128_as_f32}; + use super::{i128_as_f64, i128_as_f32, u128_as_f64, u128_as_f32, i128_mul_oflow}; + + #[export_name="__muloti4"] + pub extern "C" fn i128_mul_oflow_win(alow: u64, ahigh: i64, + blow: u64, bhigh: i64, o: &mut i32) -> i128 { + i128_mul_oflow(i128_::from_parts(alow, ahigh), i128_::from_parts(blow, bhigh), o) + } + #[export_name="__floattidf"] pub extern "C" fn i128_as_f64_win(alow: u64, ahigh: i64) -> f64 { i128_as_f64(i128_::from_parts(alow, ahigh)) From 86ce3a2f7c1b9bcd342f5a0212383e5b2711f5f6 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 23 Dec 2016 10:05:41 +0200 Subject: [PATCH 43/47] Further and hopefully final Windows fixes --- src/libcompiler_builtins/lib.rs | 325 +++++++++++------------ src/librustc_trans/abi.rs | 3 + src/libsyntax/abi.rs | 2 + src/libsyntax/feature_gate.rs | 9 +- src/test/run-pass/i128.rs | 38 ++- src/test/ui/codemap_tests/unicode.stderr | 2 +- 6 files changed, 199 insertions(+), 180 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 1c625ea985599..e9094a2ef32a1 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -19,11 +19,12 @@ #![feature(staged_api)] #![cfg_attr(any(target_pointer_width="32", target_pointer_width="16", target_os="windows", target_arch="mips64"), - feature(core_intrinsics, core_float, repr_simd))] + feature(core_intrinsics, repr_simd))] #![feature(associated_consts)] -#![cfg_attr(not(stage0), feature(i128_type))] +#![cfg_attr(not(stage0), feature(i128_type, core_float, abi_unadjusted))] -#![allow(non_camel_case_types, unused_variables)] +#![allow(non_camel_case_types, unused_variables, unused_imports)] +#![cfg_attr(stage0, allow(dead_code))] #[cfg(any(target_pointer_width="32", target_pointer_width="16", target_os="windows", target_arch="mips64"))] @@ -46,29 +47,6 @@ pub mod reimpls { #[cfg(not(stage0))] type i128_ = i128; - // Unfortunately, every tool on Windows expects different - // calling conventions to be met for int128. We need to - // match here what LLVM expects from us. This is only - // required for the return type! - #[cfg(not(stage0))] - #[cfg(all(windows, target_pointer_width="64"))] - #[repr(simd)] - pub struct u64x2(u64, u64); - - #[cfg(not(stage0))] - #[cfg(all(windows, target_pointer_width="64"))] - type u128ret = u64x2; - - #[cfg(any(not(all(windows, target_pointer_width="64")),stage0))] - type u128ret = u128_; - - #[cfg(not(stage0))] - #[cfg(all(windows, target_pointer_width="64"))] - type i128ret = u64x2; - - #[cfg(any(not(all(windows, target_pointer_width="64")),stage0))] - type i128ret = i128_; - macro_rules! ashl { ($a:expr, $b:expr, $ty:ty) => {{ let (a, b) = ($a, $b); @@ -137,27 +115,22 @@ pub mod reimpls { #[export_name="__lshrti3"] - pub extern "C" fn lshr(a: u128_, b: u128_) -> u128ret { - lshr!(a, b, u128_).to_ret() - } - - #[export_name="__udivmodti4"] - pub extern "C" fn u128_div_mod_export(n: u128_, d: u128_, rem: *mut u128_) -> u128ret { - u128_div_mod(n, d, rem).to_ret() + pub extern "C" fn lshr(a: u128_, b: u128_) -> u128_ { + lshr!(a, b, u128_) } #[cfg(stage0)] - pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128ret { + pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { unsafe { if !rem.is_null() { *rem = unchecked_rem(n, d); } - unchecked_div(n, d).to_ret() + unchecked_div(n, d) } } #[cfg(not(stage0))] - pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128 { + pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { // Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide unsafe { // special cases, X is unknown, K != 0 @@ -322,29 +295,18 @@ pub mod reimpls { } } - #[export_name="__umodti3"] - pub extern "C" fn u128_mod(a: u128_, b: u128_) -> u128ret { - unsafe { - let mut r = ::core::mem::zeroed(); - u128_div_mod(a, b, &mut r); - r.to_ret() - } - } - - #[export_name="__modti3"] - pub extern "C" fn i128_mod(a: i128_, b: i128_) -> i128ret { + fn i128_mod(a: i128_, b: i128_) -> i128_ { let b = b.uabs(); let sa = a.signum(); let a = a.uabs(); - (unsafe { + unsafe { let mut r = ::core::mem::zeroed(); u128_div_mod(a, b, &mut r); if sa == -1 { (r as i128_).unchecked_neg() } else { r as i128_ } - }).to_ret() + } } - #[export_name="__divti3"] - pub extern "C" fn i128_div(a: i128_, b: i128_) -> i128ret { + fn i128_div(a: i128_, b: i128_) -> i128_ { let sa = a.signum(); let sb = b.signum(); let a = a.uabs(); @@ -354,19 +316,13 @@ pub mod reimpls { (u128_div_mod(a, b, ptr::null_mut()) as i128_).unchecked_neg() } else { u128_div_mod(a, b, ptr::null_mut()) as i128_ - }).to_ret() + }) } #[cfg(stage0)] #[export_name="__udivti3"] - pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128ret { - (a / b).to_ret() - } - - #[cfg(not(stage0))] - #[export_name="__udivti3"] - pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128ret { - u128_div_mod(a, b, ptr::null_mut()).to_ret() + pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128_ { + (a / b) } macro_rules! mulo { @@ -394,7 +350,6 @@ pub mod reimpls { if abs_a < 2 || abs_b < 2 { return result; } - unsafe { if sa == sb { if abs_a > unchecked_div(<$ty>::max_value(), abs_b) { *overflow = 1; @@ -404,32 +359,21 @@ pub mod reimpls { *overflow = 1; } } - } result }} } - // FIXME: i32 here should be c_int. - #[cfg_attr(not(all(windows, target_pointer_width="64", not(stage0))), - export_name="__muloti4")] - pub extern "C" fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128 { - mulo!(a, b, o, i128_) - } - pub trait LargeInt { type LowHalf; type HighHalf; - type Ret; fn low(self) -> Self::LowHalf; fn high(self) -> Self::HighHalf; fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; - fn to_ret(self) -> Self::Ret; } impl LargeInt for u64 { type LowHalf = u32; type HighHalf = u32; - type Ret = u64; fn low(self) -> u32 { self as u32 @@ -440,14 +384,10 @@ pub mod reimpls { fn from_parts(low: u32, high: u32) -> u64 { low as u64 | (high as u64).wrapping_shl(32) } - fn to_ret(self) -> u64 { - self - } } impl LargeInt for i64 { type LowHalf = u32; type HighHalf = i32; - type Ret = i64; fn low(self) -> u32 { self as u32 @@ -458,15 +398,11 @@ pub mod reimpls { fn from_parts(low: u32, high: i32) -> i64 { low as i64 | (high as i64).wrapping_shl(32) } - fn to_ret(self) -> i64 { - self - } } #[cfg(not(stage0))] impl LargeInt for u128 { type LowHalf = u64; type HighHalf = u64; - type Ret = u128ret; fn low(self) -> u64 { self as u64 @@ -478,20 +414,11 @@ pub mod reimpls { #[repr(C, packed)] struct Parts(u64, u64); unsafe { ::core::mem::transmute(Parts(low, high)) } } - #[cfg(not(all(windows, target_pointer_width="64")))] - fn to_ret(self) -> u128ret { - self - } - #[cfg(all(windows, target_pointer_width="64"))] - fn to_ret(self) -> u128ret { - u64x2(self.low(), self.high()) - } } #[cfg(not(stage0))] impl LargeInt for i128 { type LowHalf = u64; type HighHalf = i64; - type Ret = i128ret; fn low(self) -> u64 { self as u64 @@ -502,14 +429,6 @@ pub mod reimpls { fn from_parts(low: u64, high: i64) -> i128 { u128::from_parts(low, high as u64) as i128 } - #[cfg(not(all(windows, target_pointer_width="64")))] - fn to_ret(self) -> i128ret { - self - } - #[cfg(all(windows, target_pointer_width="64"))] - fn to_ret(self) -> i128ret { - u64x2(self.low(), self.high() as u64) - } } macro_rules! mul { @@ -543,14 +462,14 @@ pub mod reimpls { #[cfg(stage0)] #[export_name="__multi3"] - pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128ret { - ((a as i64).wrapping_mul(b as i64) as i128_).to_ret() + pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128_ { + ((a as i64).wrapping_mul(b as i64) as i128_) } #[cfg(not(stage0))] #[export_name="__multi3"] - pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128ret { - mul!(a, b, i128_, i64).to_ret() + pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128_ { + mul!(a, b, i128_, i64) } trait AbsExt: Sized { @@ -628,9 +547,9 @@ pub mod reimpls { let exponent = $from.get_exponent(); let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK; let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; - if sign == -1.0 || exponent < 0 { return (0 as u128_).to_ret(); } + if sign == -1.0 || exponent < 0 { return 0 as u128_; } if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { - return (!(0 as u128_)).to_ret(); + return !(0 as u128_); } (if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { (mantissa as $outty) @@ -640,20 +559,10 @@ pub mod reimpls { (mantissa as $outty) .wrapping_shl(exponent.wrapping_sub( <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) - }).to_ret() + }) } } } - #[export_name="__fixunsdfti"] - pub extern "C" fn f64_as_u128(a: f64) -> u128ret { - float_as_unsigned!(a, f64, u128_) - } - - #[export_name="__fixunssfti"] - pub extern "C" fn f32_as_u128(a: f32) -> u128ret { - float_as_unsigned!(a, f32, u128_) - } - macro_rules! float_as_signed { ($from: expr, $fromty: ty, $outty: ty) => {{ use core::num::Float; @@ -663,10 +572,10 @@ pub mod reimpls { let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK; let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; - if exponent < 0 { return (0 as i128_).to_ret(); } + if exponent < 0 { return 0 as i128_; } if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { let ret = if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }; - return ret.to_ret(); + return ret } let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { (mantissa as $outty) @@ -677,62 +586,12 @@ pub mod reimpls { .wrapping_shl(exponent.wrapping_sub( <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) }; - (if sign >= 0.0 { r } else { r.unchecked_neg() }).to_ret() + (if sign >= 0.0 { r } else { r.unchecked_neg() }) }} } - #[export_name="__fixdfti"] - pub extern "C" fn f64_as_i128(a: f64) -> i128ret { - float_as_signed!(a, f64, i128_) - } - #[export_name="__fixsfti"] - pub extern "C" fn f32_as_i128(a: f32) -> i128ret { - float_as_signed!(a, f32, i128_) - } - - // LLVM expectations for ABI on windows are pure madness. - - #[cfg(not(stage0))] - #[cfg(all(windows, target_pointer_width="64"))] - mod windows_64_workarounds { - use super::{i128_, u128_, LargeInt}; - use super::{i128_as_f64, i128_as_f32, u128_as_f64, u128_as_f32, i128_mul_oflow}; - - #[export_name="__muloti4"] - pub extern "C" fn i128_mul_oflow_win(alow: u64, ahigh: i64, - blow: u64, bhigh: i64, o: &mut i32) -> i128 { - i128_mul_oflow(i128_::from_parts(alow, ahigh), i128_::from_parts(blow, bhigh), o) - } - - #[export_name="__floattidf"] - pub extern "C" fn i128_as_f64_win(alow: u64, ahigh: i64) -> f64 { - i128_as_f64(i128_::from_parts(alow, ahigh)) - } - - #[export_name="__floattisf"] - pub extern "C" fn i128_as_f32_win(alow: u64, ahigh: i64) -> f32 { - i128_as_f32(i128_::from_parts(alow, ahigh)) - } - - #[export_name="__floatuntidf"] - pub extern "C" fn u128_as_f64_win(alow: u64, ahigh: u64) -> f64 { - u128_as_f64(u128_::from_parts(alow, ahigh)) - } - - #[export_name="__floatuntisf"] - pub extern "C" fn u128_as_f32_win(alow: u64, ahigh: u64) -> f32 { - u128_as_f32(u128_::from_parts(alow, ahigh)) - } - } - #[cfg(not(stage0))] - #[cfg(all(windows, target_pointer_width="64"))] - pub use self::windows_64_workarounds::*; - - - #[cfg_attr(not(all(windows, target_pointer_width="64", not(stage0))), - export_name="__floattidf")] - pub extern "C" fn i128_as_f64(a: i128_) -> f64 { + fn i128_as_f64(a: i128_) -> f64 { match a.signum() { 1 => u128_as_f64(a.uabs()), 0 => 0.0, @@ -740,9 +599,7 @@ pub mod reimpls { } } - #[cfg_attr(not(all(windows, target_pointer_width="64", not(stage0))), - export_name="__floattisf")] - pub extern "C" fn i128_as_f32(a: i128_) -> f32 { + fn i128_as_f32(a: i128_) -> f32 { match a.signum() { 1 => u128_as_f32(a.uabs()), 0 => 0.0, @@ -750,9 +607,7 @@ pub mod reimpls { } } - #[cfg_attr(not(all(windows, target_pointer_width="64", not(stage0))), - export_name="__floatuntidf")] - pub extern "C" fn u128_as_f64(mut a: u128_) -> f64 { + fn u128_as_f64(mut a: u128_) -> f64 { use ::core::f64::MANTISSA_DIGITS; if a == 0 { return 0.0; } let sd = 128u32.wrapping_sub(a.leading_zeros()); @@ -787,9 +642,7 @@ pub mod reimpls { } } - #[cfg_attr(not(all(windows, target_pointer_width="64", not(stage0))), - export_name="__floatuntisf")] - pub extern "C" fn u128_as_f32(mut a: u128_) -> f32 { + fn u128_as_f32(mut a: u128_) -> f32 { use ::core::f32::MANTISSA_DIGITS; if a == 0 { return 0.0; } let sd = 128u32.wrapping_sub(a.leading_zeros()); @@ -823,4 +676,122 @@ pub mod reimpls { | (a as u32 & 0x007f_ffff)) } } + + + macro_rules! why_are_abi_strings_checked_by_parser { ($cret:ty, $conv:expr, $unadj:tt) => { + mod imp { + use super::{i128_, u128_, LargeInt, FloatStuff, NegExt, AbsExt}; + use super::{i128_as_f64, i128_as_f32, u128_as_f64, u128_as_f32, + i128_div, i128_mod, u128_div_mod, unchecked_div, ptr}; + // For x64 + // rdx:rcx, r9:r8, stack -> rdx:rax + // aka. + // define i128 @__muloti4(i128, i128, i32*) + #[export_name="__muloti4"] + pub unsafe extern $unadj fn i128_mul_oflow(a: i128_, b: i128_, o: *mut i32) -> i128_ { + mulo!(a, b, o, i128_) + } + + // For x64 + // rdx:rax -> xmm0 + // aka. + // define double @__muloti4(i128) + #[export_name="__floattidf"] + pub extern $unadj fn i128_as_f64_(a: i128_) -> f64 { + i128_as_f64(a) + } + #[export_name="__floattisf"] + pub extern $unadj fn i128_as_f32_(a: i128_) -> f32 { + i128_as_f32(a) + } + #[export_name="__floatuntidf"] + pub extern $unadj fn u128_as_f64_(a: u128_) -> f64 { + u128_as_f64(a) + } + #[export_name="__floatuntisf"] + pub extern $unadj fn u128_as_f32_(a: u128_) -> f32 { + u128_as_f32(a) + } + + // For x64 + // xmm0 -> rdx:rax + // aka. + // define i128 @stuff(double) + #[export_name="__fixunsdfti"] + pub extern $unadj fn f64_as_u128(a: f64) -> u128_ { + float_as_unsigned!(a, f64, u128_) + } + + #[export_name="__fixunssfti"] + pub extern "unadjusted" fn f32_as_u128(a: f32) -> u128_ { + float_as_unsigned!(a, f32, u128_) + } + + #[export_name="__fixdfti"] + pub extern "unadjusted" fn f64_as_i128(a: f64) -> i128_ { + float_as_signed!(a, f64, i128_) + } + + #[export_name="__fixsfti"] + pub extern "unadjusted" fn f32_as_i128(a: f32) -> i128_ { + float_as_signed!(a, f32, i128_) + } + + #[repr(simd)] + pub struct u64x2(u64, u64); + + // For x64 + // pointers -> xmm0 + // aka. + // define <2 x u64> @stuff(i128*, i128*, i128*) + // + // That almost matches the C ABI, so we simply use the C ABI + #[export_name="__udivmodti4"] + pub extern "C" fn u128_div_mod_(n: u128_, d: u128_, rem: *mut u128_) -> $cret { + let x = u128_div_mod(n, d, rem); + ($conv)(x) + } + + #[export_name="__udivti3"] + pub extern "C" fn u128_div_(a: u128_, b: u128_) -> $cret { + let x = u128_div_mod(a, b, ptr::null_mut()); + ($conv)(x) + } + + #[export_name="__umodti3"] + pub extern "C" fn u128_mod_(a: u128_, b: u128_) -> $cret { + unsafe { + let mut r = ::core::mem::zeroed(); + u128_div_mod(a, b, &mut r); + ($conv)(r) + } + } + + #[export_name="__divti3"] + pub extern "C" fn i128_div_(a: i128_, b: i128_) -> $cret { + let x = i128_div(a, b); + ($conv)(x as u128_) + } + + #[export_name="__modti3"] + pub extern "C" fn i128_mod_(a: i128_, b: i128_) -> $cret { + let x = i128_mod(a, b); + ($conv)(x as u128_) + } + } + } } + + // LLVM expectations for ABI on windows x64 are pure madness. + #[cfg(not(stage0))] + #[cfg(all(windows, target_pointer_width="64"))] + why_are_abi_strings_checked_by_parser!(u64x2, + |i: u128_| u64x2(i.low(), i.high()), + "unadjusted"); + + #[cfg(not(stage0))] + #[cfg(not(all(windows, target_pointer_width="64")))] + why_are_abi_strings_checked_by_parser!(u128_, |i|{ i }, "C"); + + #[cfg(not(stage0))] + pub use self::imp::*; } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 81e4b4d1f21c7..3fba75bc253cd 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -352,6 +352,7 @@ impl FnType { Fastcall => llvm::X86FastcallCallConv, Vectorcall => llvm::X86_VectorCall, C => llvm::CCallConv, + Unadjusted => llvm::CCallConv, Win64 => llvm::X86_64_Win64, SysV64 => llvm::X86_64_SysV, Aapcs => llvm::ArmAapcsCallConv, @@ -528,6 +529,8 @@ impl FnType { ccx: &CrateContext<'a, 'tcx>, abi: Abi, sig: &ty::FnSig<'tcx>) { + if abi == Abi::Unadjusted { return } + if abi == Abi::Rust || abi == Abi::RustCall || abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { let fixup = |arg: &mut ArgType| { diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 0cc62fb43a54d..75554f20effee 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -50,6 +50,7 @@ pub enum Abi { RustIntrinsic, RustCall, PlatformIntrinsic, + Unadjusted } #[allow(non_camel_case_types)] @@ -92,6 +93,7 @@ const AbiDatas: &'static [AbiData] = &[ AbiData {abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true }, AbiData {abi: Abi::RustCall, name: "rust-call", generic: true }, AbiData {abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true }, + AbiData {abi: Abi::Unadjusted, name: "unadjusted", generic: true }, ]; /// Returns the ABI with the given name (if any). diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a3ecdabbe1ce3..e7df454cf6a50 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -324,6 +324,9 @@ declare_features! ( // The `i128` type (active, i128_type, "1.16.0", Some(35118)), + + // The `unadjusted` ABI. Perma unstable. + (active, abi_unadjusted, "1.16.0", None), ); declare_features! ( @@ -995,7 +998,11 @@ impl<'a> PostExpansionVisitor<'a> { Abi::PtxKernel => { gate_feature_post!(&self, abi_ptx, span, "PTX ABIs are experimental and subject to change"); - } + }, + Abi::Unadjusted => { + gate_feature_post!(&self, abi_unadjusted, span, + "unadjusted ABI is an implementation detail and perma-unstable"); + }, // Stable Abi::Cdecl | Abi::Stdcall | diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index 4799f0d68bf2c..71d3e6491cbad 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -10,7 +10,10 @@ // ignore-stage0 // ignore-stage1 -#![feature(i128_type)] +#![feature(i128_type, test)] + +extern crate test; +use test::black_box as b; fn main() { let x: i128 = -1; @@ -45,6 +48,39 @@ fn main() { assert_eq!((-z as f32) as i128, -z); assert_eq!((-z as f64 * 16.0) as i128, -z * 16); assert_eq!((-z as f32 * 16.0) as i128, -z * 16); + // Same stuff as above, but blackboxed, to force use of intrinsics + let x: i128 = b(-1); + assert_eq!(0, !x); + let y: i128 = b(-2); + assert_eq!(!1, y); + let z: i128 = b(0xABCD_EF); + assert_eq!(z * z, 0x734C_C2F2_A521); + assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); + assert_eq!(-z * -z, 0x734C_C2F2_A521); + assert_eq!(-z * -z * -z * -z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); + assert_eq!(-z + -z + -z + -z, -0x2AF3_7BC); + let k: i128 = b(-0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210); + assert_eq!(k + k, -0x2468_ACF1_3579_BDFF_DB97_530E_CA86_420); + assert_eq!(0, k - k); + assert_eq!(-0x1234_5678_9ABC_DEFF_EDCB_A987_5A86_421, k + z); + assert_eq!(-0x1000_0000_0000_0000_0000_0000_0000_000, + k + 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210); + assert_eq!(-0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42); + assert_eq!(-k, k / -1); + assert_eq!(-0x91A2_B3C4_D5E6_F8, k >> 65); + assert_eq!(-0xFDB9_7530_ECA8_6420_0000_0000_0000_0000, k << 65); + assert!(k < z); + assert!(y > k); + assert!(y < x); + assert_eq!(x as i64, -1); + assert_eq!(z as i64, 0xABCD_EF); + assert_eq!(k as i64, -0xFEDC_BA98_7654_3210); + assert_eq!(k as u128, 0xFEDC_BA98_7654_3210_0123_4567_89AB_CDF0); + assert_eq!(-k as u128, 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210); + assert_eq!((-z as f64) as i128, -z); + assert_eq!((-z as f32) as i128, -z); + assert_eq!((-z as f64 * 16.0) as i128, -z * 16); + assert_eq!((-z as f32 * 16.0) as i128, -z * 16); // formatting let j: i128 = -(1 << 67); assert_eq!("-147573952589676412928", format!("{}", j)); diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index 70fe17888e84d..f71ef126b64d9 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -1,4 +1,4 @@ -error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, ptx-kernel, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` +error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, ptx-kernel, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted], found `路濫狼á́́` --> $DIR/unicode.rs:11:8 | 11 | extern "路濫狼á́́" fn foo() {} From d166ee96649bddf88f8496733562c49b986d4ef1 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 26 Dec 2016 17:20:33 +0100 Subject: [PATCH 44/47] Add test to ensure unadjusted stays unstable --- src/test/compile-fail/unadjusted-unstable.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/compile-fail/unadjusted-unstable.rs diff --git a/src/test/compile-fail/unadjusted-unstable.rs b/src/test/compile-fail/unadjusted-unstable.rs new file mode 100644 index 0000000000000..501f4451ed8d5 --- /dev/null +++ b/src/test/compile-fail/unadjusted-unstable.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern "unadjusted" fn foo() { +//~^ ERROR: unadjusted ABI is an implementation detail and perma-unstable +} + +fn main() { + foo(); +} From 6b359635ec56bfbf0f5a9f775443ca493b0a4919 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 26 Dec 2016 20:13:58 +0100 Subject: [PATCH 45/47] Fix warning when compiling on 64 bit Linux Code is much simpler now as well. --- src/libcompiler_builtins/lib.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index e9094a2ef32a1..1bb84c9fc0256 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -16,13 +16,9 @@ issue = "0")] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] -#![feature(staged_api)] -#![cfg_attr(any(target_pointer_width="32", target_pointer_width="16", target_os="windows", - target_arch="mips64"), - feature(core_intrinsics, repr_simd))] -#![feature(associated_consts)] -#![cfg_attr(not(stage0), feature(i128_type, core_float, abi_unadjusted))] - +#![allow(unused_features)] +#![feature(staged_api, core_intrinsics, repr_simd, + i128_type, core_float, abi_unadjusted, associated_consts)] #![allow(non_camel_case_types, unused_variables, unused_imports)] #![cfg_attr(stage0, allow(dead_code))] From ee69cd79255fbf98d755ff4556c4af4adda1befb Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 31 Dec 2016 04:55:29 +0200 Subject: [PATCH 46/47] Calculate discriminant bounds within 64 bits Since discriminants do not support i128 yet, lets just calculate the boundaries within the 64 bits that are supported. This also avoids an issue with bootstrapping on 32 bit systems due to #38727. --- src/librustc/ty/layout.rs | 20 +++++++++++++------- src/librustc_llvm/ffi.rs | 2 +- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/mir/mod.rs | 1 + src/librustc_trans/mir/operand.rs | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 75600ddaabdb5..ff95554dbbfcd 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -20,7 +20,8 @@ use ty::{self, Ty, TyCtxt, TypeFoldable}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; use syntax_pos::DUMMY_SP; -use rustc_i128::{i128, u128}; +use rustc_i128::u128; +use rustc_const_math::ConstInt; use std::cmp; use std::fmt; @@ -1198,20 +1199,25 @@ impl<'a, 'gcx, 'tcx> Layout { if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) { // All bodies empty -> intlike - let (mut min, mut max, mut non_zero) = (i128::max_value(), - i128::min_value(), + let (mut min, mut max, mut non_zero) = (i64::max_value(), + i64::min_value(), true); for v in &def.variants { - let x = v.disr_val.to_u128_unchecked() as i128; + let x = match v.disr_val.erase_type() { + ConstInt::InferSigned(i) => i as i64, + ConstInt::Infer(i) => i as u64 as i64, + _ => bug!() + }; if x == 0 { non_zero = false; } if x < min { min = x; } if x > max { max = x; } } - // FIXME: should take i128? + // FIXME: should handle i128? signed-value based impl is weird and hard to + // grok. let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..], - min as i64, - max as i64); + min, + max); return success(CEnum { discr: discr, signed: signed, diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index fb188252075e6..6815da4cc20fd 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -33,7 +33,7 @@ pub enum LLVMRustResult { // Consts for the LLVM CallConv type, pre-cast to usize. /// LLVM CallingConv::ID. Should we wrap this? -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] pub enum CallConv { CCallConv = 0, diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 3fba75bc253cd..65e752232f6ad 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -313,7 +313,7 @@ impl ArgType { /// /// I will do my best to describe this structure, but these /// comments are reverse-engineered and may be inaccurate. -NDM -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct FnType { /// The LLVM types of each argument. pub args: Vec, diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 7a50e5cbe8c79..a1373cb9482b7 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -205,6 +205,7 @@ pub fn trans_mir<'a, 'tcx: 'a>( sig: &ty::FnSig<'tcx>, abi: Abi, ) { + debug!("fn_ty: {:?}", fn_ty); let debug_context = debuginfo::create_function_debug_context(fcx.ccx, instance, sig, abi, fcx.llfn, mir); let bcx = fcx.get_entry_block(); diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index a15d51d9da64d..526155655af27 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> OperandRef<'tcx> { pub fn immediate(self) -> ValueRef { match self.val { OperandValue::Immediate(s) => s, - _ => bug!() + _ => bug!("not immediate: {:?}", self) } } From 29e01af6a68817a12c1fc5fa04c483d2200c3cbb Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 31 Dec 2016 18:16:55 +0100 Subject: [PATCH 47/47] Fix iabs and add some more tests --- src/libcompiler_builtins/lib.rs | 17 +++++++++++++---- src/test/run-pass/i128.rs | 6 +++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 1bb84c9fc0256..1bc9b66000124 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -469,16 +469,25 @@ pub mod reimpls { } trait AbsExt: Sized { - fn uabs(self) -> u128_; + fn uabs(self) -> u128_ { + self.iabs() as u128_ + } fn iabs(self) -> i128_; } + #[cfg(stage0)] impl AbsExt for i128_ { - fn uabs(self) -> u128_ { - self.iabs() as u128_ + fn iabs(self) -> i128_ { + let s = self >> 63; + ((self ^ s).wrapping_sub(s)) } + } + + #[cfg(not(stage0))] + impl AbsExt for i128_ { fn iabs(self) -> i128_ { - ((self ^ self).wrapping_sub(self)) + let s = self >> 127; + ((self ^ s).wrapping_sub(s)) } } diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index 71d3e6491cbad..b7aeb21229ccb 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -91,5 +91,9 @@ fn main() { format!("{:b}", j)); assert_eq!("-147573952589676412928", format!("{:?}", j)); // common traits - x.clone(); + assert_eq!(x, b(x.clone())); + // overflow checks + assert_eq!((-z).checked_mul(-z), Some(0x734C_C2F2_A521)); + assert_eq!((z).checked_mul(z), Some(0x734C_C2F2_A521)); + assert_eq!((k).checked_mul(k), None); }