From dbcdc871eff0bab8fb391ff7ffcb6649db48d82d Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 23 Aug 2016 03:56:52 +0300 Subject: [PATCH 01/15] 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). --- 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/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 | 47 ++-- src/librustc_llvm/ffi.rs | 3 + src/librustc_macro/Cargo.toml | 1 + src/librustc_metadata/Cargo.toml | 1 + src/librustc_metadata/decoder.rs | 3 + 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 | 90 ++++--- src/libserialize/lib.rs | 2 + src/libserialize/opaque.rs | 22 +- 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, 953 insertions(+), 362 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 0b800cacfc19a..195f3bdffa517 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -160,12 +160,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 f990a27e52b31..d794d4b3f3bfa 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -604,6 +604,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)*) => ($( @@ -613,6 +615,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)*) => ($( @@ -702,6 +706,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", 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 081f0c14ec30c..888337108dd07 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -177,6 +177,13 @@ pub trait Hasher { fn write_u64(&mut self, i: u64) { self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) }) } + #[cfg(not(stage0))] + /// Write 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) }) + } /// Write a single `usize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] @@ -211,6 +218,13 @@ pub trait Hasher { fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) } + #[cfg(not(stage0))] + /// Write 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) + } /// Write a single `isize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] @@ -319,6 +333,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 1ae4cf8e5ef5f..b95d619d93498 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -118,12 +118,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 7b797631dfd57..c79222e74336a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -144,6 +144,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)*) => ($( @@ -190,7 +192,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. @@ -1305,6 +1307,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 { @@ -2337,6 +2349,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 { @@ -2550,6 +2576,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")] @@ -2574,7 +2602,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),*) => {$( #[stable(feature = "rust1", since = "1.0.0")] impl TryFrom<$source> for $target { @@ -2593,16 +2621,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),*) => {$( @@ -2636,12 +2678,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; @@ -2669,6 +2729,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 { @@ -2801,27 +2863,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 85a52da332db5..7430c5ed11671 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -316,6 +316,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 `-`. /// @@ -389,6 +391,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 `*`. /// @@ -511,6 +515,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 `/`. /// @@ -640,6 +646,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)*) => ($( @@ -719,6 +727,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)*) => ($( @@ -814,6 +825,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 `!`. /// @@ -872,6 +885,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 `&`. /// @@ -955,6 +970,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 `|`. /// @@ -1038,6 +1055,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 `^`. /// @@ -1124,6 +1143,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 `<<`. /// @@ -1214,17 +1235,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 `>>`. /// @@ -1315,17 +1342,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 `+=`. /// @@ -1382,6 +1415,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 `-=`. /// @@ -1438,6 +1473,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 `*=`. /// @@ -1483,6 +1520,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 `/=`. /// @@ -1527,6 +1566,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 `%=`. /// @@ -1571,6 +1612,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 `&=`. /// @@ -1657,6 +1700,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 `|=`. /// @@ -1701,6 +1746,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 `^=`. /// @@ -1745,6 +1792,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 `<<=`. /// @@ -1797,17 +1846,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 `>>=`. /// @@ -1860,17 +1915,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 `arr[idx]` when used in an immutable context. 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 c34286f0195bf..0ab5abfcaa080 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -64,6 +64,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 078cce9c49ff4..306872fbd812d 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -279,11 +279,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 0c7c387b67ea3..0711fe192220e 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -184,11 +184,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>, @@ -265,11 +267,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)), } @@ -1235,6 +1239,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, } } @@ -1245,6 +1250,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 ed945534e1e5f..0d19985ebc10b 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; @@ -34,6 +35,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, @@ -54,6 +56,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), @@ -116,6 +120,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. @@ -324,7 +329,8 @@ pub enum Integer { I8, I16, I32, - I64 + I64, + I128, } impl Integer { @@ -367,22 +373,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, } } @@ -405,6 +413,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() } @@ -478,6 +487,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 } } @@ -489,6 +499,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 @@ -1013,17 +1024,21 @@ 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) = (i64::MAX, i64::MIN); + let (mut min, mut max) = (i128::max_value(), i128::min_value()); 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 < min { min = x; } if x > max { max = x; } } - let (discr, signed) = Integer::repr_discr(tcx, ty, hint, min, max); + // FIXME: should take i128? + let (discr, signed) = Integer::repr_discr(tcx, ty, hint, + min as i64, + max as i64); return success(CEnum { discr: discr, signed: signed, + // FIXME: should be u128? min: min as u64, max: max as u64 }); @@ -1054,7 +1069,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 c8fd27f066cac..32959af0575f0 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -46,11 +46,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, } } @@ -61,6 +63,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)), @@ -71,6 +74,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)), @@ -86,11 +90,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 8967672548b10..468aafbadc093 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -17,4 +17,5 @@ rustc_const_math = { path = "../librustc_const_math" } 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 4ae3c7d37db8d..feaa33d4d48d0 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -47,6 +47,8 @@ use std::collections::hash_map::Entry::Vacant; use rustc_const_math::*; use rustc_errors::DiagnosticBuilder; +use rustc_i128::{i128, u128}; + macro_rules! math { ($e:expr, $op:expr) => { match $op { @@ -619,38 +621,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!(), } @@ -999,26 +1006,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))) }, @@ -1026,7 +1037,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))) }, @@ -1105,21 +1117,23 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } 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)))) }, @@ -1149,13 +1163,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) { @@ -1179,9 +1193,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(_) => { @@ -1219,28 +1233,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(ref n, fty) => { diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index f926fef065ea6..8b7e6da4662bd 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -30,6 +30,7 @@ #![feature(question_mark)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(const_fn)] #[macro_use] extern crate syntax; #[macro_use] extern crate log; @@ -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 741dd4107e001..5ba5f8bd075d8 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -26,10 +26,14 @@ #![feature(rustc_private)] #![feature(staged_api)] #![feature(question_mark)] +#![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 bc2979c806f65..90027e8cc20d3 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -48,6 +48,8 @@ extern crate rustc_back; extern crate rustc_const_eval; extern crate syntax_pos; +extern crate rustc_i128; + pub use rustc::lint as lint; pub use rustc::middle as middle; pub use rustc::session as session; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 1209ced8dd3d7..5d08a62243ba5 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. @@ -145,7 +147,7 @@ impl LateLintPass 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 } + if let ast::LitKind::Int(shift, _) = lit.node { shift as u64 >= bits } else { false } } else { match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) { @@ -176,12 +178,13 @@ impl LateLintPass 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)); return; @@ -197,7 +200,7 @@ impl LateLintPass 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, @@ -255,23 +258,25 @@ impl LateLintPass 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::I8 => (i8::min_value() as i128, i8::max_value() as i128), + ast::IntTy::I16 => (i16::min_value() as i128, i16::max_value() as i128), + ast::IntTy::I32 => (i32::min_value() 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() as i128), + ast::IntTy::Is => (i64::min_value() as i128, i64::max_value() as i128), } } - 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::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() as u128, u128::max_value() as u128), + ast::UintTy::Us => (u64::min_value() as u128, u64::max_value() as u128), } } @@ -289,6 +294,7 @@ impl LateLintPass for TypeLimits { ast::IntTy::I16 => 16 as u64, ast::IntTy::I32 => 32, ast::IntTy::I64 => 64, + ast::IntTy::I128 => 128, } } @@ -299,6 +305,7 @@ impl LateLintPass for TypeLimits { ast::UintTy::U16 => 16, ast::UintTy::U32 => 32, ast::UintTy::U64 => 64, + ast::UintTy::U128 => 128, } } @@ -321,10 +328,10 @@ impl LateLintPass for TypeLimits { match tcx.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, + ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i128, _ => return true }, _ => bug!() @@ -332,8 +339,8 @@ impl LateLintPass for TypeLimits { 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) = 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 diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 50c68d5e75eef..b1909e0e91b6b 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -533,6 +533,7 @@ extern { 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; @@ -636,6 +637,8 @@ extern { /* 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 LLVMConstIntOfString(IntTy: TypeRef, Text: *const c_char, Radix: u8) -> ValueRef; pub fn LLVMConstIntOfStringAndSize(IntTy: TypeRef, diff --git a/src/librustc_macro/Cargo.toml b/src/librustc_macro/Cargo.toml index 6b3ee21d9aceb..37467cc81647a 100644 --- a/src/librustc_macro/Cargo.toml +++ b/src/librustc_macro/Cargo.toml @@ -10,3 +10,4 @@ crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 680d55955bb96..256a82c1e7e67 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -18,6 +18,7 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_llvm = { path = "../librustc_llvm" } rustc_macro = { path = "../librustc_macro" } +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 3e4a2542b270b..06c3f4cb1936e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -44,6 +44,7 @@ use syntax::attr; use syntax::ast::{self, NodeId}; use syntax::codemap; use syntax_pos::{self, Span, BytePos, Pos}; +use rustc_i128::u128; pub struct DecodeContext<'a, 'tcx: 'a> { opaque: opaque::Decoder<'a>, @@ -186,12 +187,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 4fc5a46762d12..a9b748e7b6442 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -45,9 +45,15 @@ extern crate rustc_back; extern crate rustc_llvm; extern crate rustc_macro; extern crate rustc_const_math; +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 a40571c5d8597..fcc326585df14 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::fnv::FnvHashMap; use rustc_data_structures::indexed_vec::Idx; +use rustc_i128::i128; use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::{Category, RvalueFunc}; @@ -343,6 +344,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(); @@ -365,10 +367,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 79a4cf73041d7..a7debfe82ab85 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 12f1eb8535a3e..272823d6e09c5 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -43,6 +43,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 fb9819b72ab3e..0f5f910589d0f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -964,13 +964,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 38f9e7ab0c51c..abca78c1fb5df 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -22,7 +22,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 5b1f691af8df7..d8fe57dacdd55 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -53,6 +53,8 @@ use syntax::parse::token::InternedString; use syntax::parse::token; use syntax_pos::{DUMMY_SP, Span}; +use rustc_i128::u128; + pub use context::{CrateContext, SharedCrateContext}; /// Is the type's representation size known at compile time? @@ -730,6 +732,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 15f7132e52d2f..bf14d75b12efe 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 1b67516a9e6d0..e75d357622bbf 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -1070,6 +1070,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); @@ -1136,50 +1137,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 a441800795b96..bf62b448be802 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1650,7 +1650,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 4cacbc0f35eff..788b25f1785fb 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -1318,6 +1318,8 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> // 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}; @@ -1335,6 +1337,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 => { @@ -1349,6 +1352,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 41c8d565d418c..3eb438f38b442 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -54,6 +54,7 @@ extern crate rustc_platform_intrinsics as intrinsics; extern crate serialize; extern crate rustc_const_math; extern crate rustc_const_eval; +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 b74d56ce368a9..d401e9d082821 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -26,7 +26,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, type_is_sized}; -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; @@ -37,6 +37,7 @@ use value::Value; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; +use rustc_i128::u128; use std::fmt; use std::ptr; @@ -76,6 +77,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) @@ -84,6 +86,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 b643dcd9871b0..5133b5ab96523 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -660,11 +660,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!(), }, @@ -673,11 +675,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!(), }, @@ -686,11 +690,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 5c7cbbbd88d46..66246d17daedf 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -396,11 +396,13 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, '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 03a71827b473b..0e6d66c415aa0 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -96,6 +96,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)) @@ -136,7 +140,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), } } @@ -146,7 +151,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 93d8b3e1563d9..ed30048cae0e2 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -437,7 +437,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 9fba9bcb757b6..5c6d531221e7b 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -339,6 +339,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); @@ -359,6 +363,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 70342a0cd258e..b14b8290fa4d6 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -149,6 +149,13 @@ impl<'cx, 'tcx> 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(), @@ -184,6 +191,13 @@ impl<'cx, 'tcx> 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 e5d4d4a9dae2c..a38cd4f6eac71 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1119,11 +1119,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 0ae059509bd10..1fe6ed64bd4f3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1461,8 +1461,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, @@ -1568,26 +1568,29 @@ impl PrimitiveType { } pub fn to_string(&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", } } @@ -2417,6 +2420,7 @@ impl Clean> for doctree::Impl { fn build_deref_target_impls(cx: &DocContext, items: &[Item], ret: &mut Vec) { + use PrimitiveType::*; let tcx = match cx.tcx_opt() { Some(t) => t, None => return, @@ -2439,25 +2443,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 6ccc0be41bc0f..1847a3361a5df 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -210,6 +210,8 @@ use std::string; use std::{char, f64, fmt, str}; use std; +use rustc_i128::{i128, u128}; + use Encodable; /// Represents a json value @@ -495,12 +497,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) } @@ -743,12 +747,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) } @@ -2141,11 +2147,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 0c5356c022235..4d704b6242c41 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] pub fn write_to_vec(vec: &mut Vec, position: &mut usize, byte: u8) { if *position == vec.len() { @@ -19,7 +21,7 @@ pub fn write_to_vec(vec: &mut Vec, position: &mut usize, byte: u8) { *position += 1; } -pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, mut value: u64) -> usize { +pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, mut value: u128) -> usize { let mut position = start_position; loop { let mut byte = (value & 0x7F) as u8; @@ -38,14 +40,14 @@ pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, mut value return position - start_position; } -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; } @@ -56,51 +58,53 @@ pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize) } -pub fn write_signed_leb128(out: &mut Vec, start_position: usize, mut value: i64) -> usize { - let mut position = start_position; +pub fn write_signed_leb128(out: &mut Vec, start_position: usize, value: i128) -> usize { + write_unsigned_leb128(out, start_position, value as u128) + // let mut position = start_position; + // loop { + // let mut byte = (value & 0x7f) as u8; + // 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. + // } - loop { - let mut byte = (value as u8) & 0x7f; - 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_to_vec(out, &mut position, byte); + // write_to_vec(out, &mut position, byte); - if !more { - break; - } - } + // if !more { + // break; + // } + // } - return position - start_position; + // return position - start_position; } -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 7cb02e2412c65..67cba3eb4e9de 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -45,6 +45,8 @@ Core encoding and decoding interfaces. extern crate rustc_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 e97834f63cee4..17f1a112dbd0a 100644 --- a/src/libserialize/opaque.rs +++ b/src/libserialize/opaque.rs @@ -12,6 +12,8 @@ use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, writ use std::io::{self, Write}; use serialize; +use rustc_i128::{i128, u128}; + // ----------------------------------------------------------------------------- // Encoder // ----------------------------------------------------------------------------- @@ -32,7 +34,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(()) }} @@ -41,7 +43,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(()) }} @@ -58,6 +60,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) } @@ -79,6 +85,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) } @@ -182,6 +192,10 @@ impl<'a> serialize::Decoder for Decoder<'a> { Ok(()) } + fn read_u128(&mut self) -> Result { + read_uleb128!(self, u128) + } + fn read_u64(&mut self) -> Result { read_uleb128!(self, u64) } @@ -204,6 +218,10 @@ impl<'a> serialize::Decoder for Decoder<'a> { read_uleb128!(self, usize) } + fn read_i128(&mut self) -> Result { + read_sleb128!(self, i128) + } + fn read_i64(&mut self) -> Result { read_sleb128!(self, i64) } diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 6650a981884d8..3f2b8b13a6da9 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -19,6 +19,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; @@ -26,11 +27,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>; @@ -143,11 +146,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; @@ -327,6 +332,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) @@ -387,6 +406,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 912045453e086..c7a7be577c3e2 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -282,6 +282,7 @@ #![feature(unwind_attributes)] #![feature(vec_push_all)] #![feature(zero_one)] +#![feature(i128)] #![cfg_attr(test, feature(update_panic_count))] // Issue# 30592: Systematically use alloc_system during stage0 since jemalloc @@ -415,6 +416,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; @@ -426,6 +430,9 @@ pub use core::u16; pub use core::u32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::u64; +#[unstable(feature = "i128", issue = "35118")] +#[cfg(not(stage0))] +pub use core::u128; #[path = "num/f32.rs"] pub mod f32; #[path = "num/f64.rs"] pub mod f64; diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 8b61e1b0d3a38..a2b269371a85a 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -14,3 +14,4 @@ log = { path = "../liblog" } rustc_bitflags = { path = "../librustc_bitflags" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c18b36161dfcf..14b14efd96faa 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -31,6 +31,8 @@ use std::u32; use serialize::{self, Encodable, Decodable, Encoder, Decoder}; +use rustc_i128::{u128, i128}; + /// A name is a part of an identifier, representing a string or gensym. It's /// the result of interning. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -1147,7 +1149,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(InternedString, FloatTy), /// A float literal without a suffix (`1.0 or 1.0E10`) @@ -1256,6 +1258,7 @@ pub enum IntTy { I16, I32, I64, + I128, } impl fmt::Debug for IntTy { @@ -1277,15 +1280,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 { @@ -1293,7 +1297,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, } } @@ -1304,6 +1310,7 @@ impl IntTy { IntTy::I16 => 16, IntTy::I32 => 32, IntTy::I64 => 64, + IntTy::I128 => 128, }) } } @@ -1315,6 +1322,7 @@ pub enum UintTy { U16, U32, U64, + U128, } impl UintTy { @@ -1324,11 +1332,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()) } @@ -1337,7 +1346,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, } } @@ -1348,6 +1359,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 dc02c26039c15..87a72cc4bd462 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -930,6 +930,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 @@ -976,7 +978,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 b81d95a6998c3..f8400a96c1459 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 parse::token::{self, keywords, InternedString}; use ptr::P; +use rustc_i128::u128; // Transitional reexports so qquote can find the paths it is looking for mod syntax { @@ -721,23 +722,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 b70e270df54d2..7ff4c9e095183 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! @@ -39,6 +40,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; @@ -278,7 +280,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))), @@ -300,7 +302,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 118ceb17ab4a4..09946c4f2cad3 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -44,8 +44,9 @@ extern crate rustc_unicode; pub extern crate rustc_errors as errors; extern crate syntax_pos; -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 1e286c143de9b..9cd8c85df46bf 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -27,6 +27,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] @@ -608,18 +610,20 @@ pub fn integer_lit(s: &str, "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), _ => { // 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)) @@ -636,7 +640,7 @@ pub fn integer_lit(s: &str, 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 d5ed1d157e47a..e27dc1a64a016 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, @@ -2081,7 +2083,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 8563d27908db6..32750bb9b761e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -29,6 +29,8 @@ use ptr::P; use std_inject; use tokenstream::{self, TokenTree}; +use rustc_i128::i128; + use std::ascii; use std::io::{self, Write, Read}; use std::iter; @@ -649,8 +651,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 e307925a6ed83..4fc687da4291d 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -785,12 +785,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 6e11e2ec64c3439f2e1279c3d3438af144fb85b9 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 00:59:16 +0300 Subject: [PATCH 02/15] 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 bdbc696014225f140a297eb517e7d750a7899d24 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 02:15:15 +0300 Subject: [PATCH 03/15] Feature gate the 128 bit types Dangling a carrot in front of a donkey. --- src/libcore/lib.rs | 1 + src/librustc_i128/lib.rs | 1 + src/librustc_resolve/lib.rs | 20 +++++++++++++++----- 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, 78 insertions(+), 5 deletions(-) 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 b95d619d93498..18d39a9d848b6 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -91,6 +91,7 @@ #![feature(unboxed_closures)] #![feature(question_mark)] #![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 0f5f910589d0f..9f338500863c0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -59,6 +59,7 @@ use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy}; use syntax::parse::token::{self, keywords}; use syntax::util::lev_distance::find_best_match_for_name; +use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax::visit::{self, FnKind, Visitor}; use syntax::attr; @@ -2492,11 +2493,20 @@ impl<'a> Resolver<'a> { let resolve_identifier_with_fallback = |this: &mut Self, record_used| { let def = this.resolve_identifier(last_ident, namespace, record_used); match def { - None | Some(LocalDef{def: Def::Mod(..), ..}) if namespace == TypeNS => - this.primitive_type_table - .primitive_types - .get(&last_ident.name) - .map_or(def, |prim_ty| Some(LocalDef::from_def(Def::PrimTy(*prim_ty)))), + None | Some(LocalDef{def: Def::Mod(..), ..}) if namespace == TypeNS => { + let prim = this.primitive_type_table.primitive_types.get(&last_ident.name); + match prim { + Some(&TyUint(UintTy::U128)) | Some(&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"); + } + } + _ => {} + } + prim.map_or(def, |prim_ty| Some(LocalDef::from_def(Def::PrimTy(*prim_ty)))) + } _ => def } }; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ee00cb2f5a3e4..17e097049733c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1244,6 +1244,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(ref e) = v.node.disr_expr { check_const_with_type(ccx, e, repr_type_ty, e.id); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index b687e4f92be73..9e755f5046be4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -303,6 +303,9 @@ declare_features! ( // Used to identify the `compiler_builtins` crate // rustc internal (active, compiler_builtins, "1.13.0", None), + + // The `i128` type + (active, i128_type, "1.14.0", Some(35118)) ); declare_features! ( @@ -1075,6 +1078,18 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { ast::ExprKind::InPlace(..) => { gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN); } + 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 ff94eb299c9d776b694c07bc345512bc02db31a2 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 02:37:19 +0300 Subject: [PATCH 04/15] 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 fcc326585df14..8b4a3655c368a 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -371,7 +371,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 14b14efd96faa..254ce2c9022d2 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1292,17 +1292,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, @@ -1341,17 +1330,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 77c9d7b77ab90c5e8b29451f942d89751ced9609 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 15:58:40 +0300 Subject: [PATCH 05/15] 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 | 85 ++++++++++++++++++-------------------- src/libsyntax/ast.rs | 4 +- 3 files changed, 44 insertions(+), 47 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 4d704b6242c41..89365bba0324c 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -58,53 +58,50 @@ pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u128, usize) } -pub fn write_signed_leb128(out: &mut Vec, start_position: usize, value: i128) -> usize { - write_unsigned_leb128(out, start_position, value as u128) - // let mut position = start_position; - // loop { - // let mut byte = (value & 0x7f) as u8; - // 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_to_vec(out, &mut position, byte); - - // if !more { - // break; - // } - // } - - // return position - start_position; +pub fn write_signed_leb128(out: &mut Vec, start_position: usize, mut value: i128) -> usize { + let mut position = start_position; + loop { + let mut byte = (value & 0x7f) as u8; + value >>= 7; + let more = !((((value == 0) && ((byte & 0x40) == 0)) || + ((value == !0) && ((byte & 0x40) != 0)))); + if more { + byte |= 0x80; // Mark this byte to show that more bytes will follow. + } + + write_to_vec(out, &mut position, byte); + + if !more { + break; + } + } + + return 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) + 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 254ce2c9022d2..665980a24ce87 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1286,8 +1286,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 32ba792149da5b8a2896d2724b54a0c171d8e34c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 16:10:38 +0300 Subject: [PATCH 06/15] Tidy --- src/librustc_i128/lib.rs | 9 +++++++++ src/rustc/Cargo.lock | 13 +++++++++++++ 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 +++++++++ src/tools/compiletest/Cargo.lock | 5 +++++ 7 files changed, 63 insertions(+) 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/rustc/Cargo.lock b/src/rustc/Cargo.lock index 69e3eab22e912..0218be179ea9d 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -64,6 +64,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", @@ -107,6 +108,7 @@ dependencies = [ "rustc_back 0.0.0", "rustc_const_math 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", @@ -117,6 +119,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", ] @@ -170,6 +173,10 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc_i128" +version = "0.0.0" + [[package]] name = "rustc_incremental" version = "0.0.0" @@ -191,6 +198,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", ] @@ -222,6 +230,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", "rustc_macro 0.0.0", "serialize 0.0.0", @@ -242,6 +251,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", ] @@ -323,6 +333,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", @@ -377,6 +388,7 @@ name = "serialize" version = "0.0.0" dependencies = [ "log 0.0.0", + "rustc_i128 0.0.0", ] [[package]] @@ -386,6 +398,7 @@ dependencies = [ "log 0.0.0", "rustc_bitflags 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/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() { diff --git a/src/tools/compiletest/Cargo.lock b/src/tools/compiletest/Cargo.lock index 755697806a00e..61dc07dc299ff 100644 --- a/src/tools/compiletest/Cargo.lock +++ b/src/tools/compiletest/Cargo.lock @@ -68,11 +68,16 @@ name = "regex-syntax" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc_i128" +version = "0.0.0" + [[package]] name = "serialize" version = "0.0.0" dependencies = [ "log 0.0.0", + "rustc_i128 0.0.0", ] [[package]] From f13c8654bd58685e356f6d8f456bff1e2aec58a7 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 16:48:35 +0300 Subject: [PATCH 07/15] Makefiles support for rustc_i128 crate --- mk/crates.mk | 24 ++++++++++++++---------- src/librustc_i128/lib.rs | 2 ++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/mk/crates.mk b/mk/crates.mk index 86bb3a8ca0ccc..57df102317f30 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 rustc_macro + rustc_const_eval rustc_const_math rustc_incremental rustc_macro rustc_i128 HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \ flate arena graphviz log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator @@ -96,22 +96,24 @@ 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 rustc_unicode rustc_errors syntax_pos +DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors \ + syntax_pos rustc_i128 DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros rustc_macro DEPS_proc_macro := syntax syntax_pos rustc_plugin log DEPS_syntax_pos := serialize -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 @@ -122,19 +124,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 rustc_macro 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_rustc_macro := std syntax DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rustc_const_math \ - rustc_macro syntax_ext + rustc_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 @@ -162,6 +165,7 @@ ONLY_RLIB_alloc := 1 ONLY_RLIB_rand := 1 ONLY_RLIB_collections := 1 ONLY_RLIB_rustc_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 67295ff766daadf63a29d07cd600f4fe0c40b258 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 19:29:15 +0300 Subject: [PATCH 08/15] Wrapping and attempt at LLVM 3.7 compat --- 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 4857817e84e4f..aaa93ea9f9922 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -288,6 +288,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 b1909e0e91b6b..dfbddc6db3a0c 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -533,7 +533,6 @@ extern { 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; diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index 0e6d66c415aa0..4eba2dd95c586 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -97,7 +97,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 112c1276ac6e7bb7d04a9d94f3395835a54d0e4d Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Aug 2016 22:38:14 +0300 Subject: [PATCH 09/15] 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 03cf911adb47d182248b224b38eda9a393791a75 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 25 Aug 2016 02:16:21 +0300 Subject: [PATCH 10/15] 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 66d05d81d80cd..53f31d0ff3cc4 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 89365bba0324c..627e9b369737f 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -126,22 +126,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 af1062d5593fba9a70446f577821df7d019e3709 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 26 Aug 2016 01:32:46 +0300 Subject: [PATCH 11/15] Add a way to retrieve constant value in 128 bits Fixes rebase fallout, makes code correct in presence of 128-bit constants. --- src/librustc_const_math/int.rs | 36 ++++++++++++++++- src/librustc_llvm/ffi.rs | 2 + src/librustc_trans/base.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 | 62 +++++++----------------------- src/librustdoc/clean/mod.rs | 6 ++- src/rustllvm/RustWrapper.cpp | 18 ++++++++- 11 files changed, 104 insertions(+), 72 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 dfbddc6db3a0c..2a0981d7ec017 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -654,6 +654,8 @@ extern { -> 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/base.rs b/src/librustc_trans/base.rs index 446042b839ad3..b29b40e6e71e7 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -727,7 +727,7 @@ pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) -> { let _icx = push_ctxt("with_cond"); - if bcx.unreachable.get() || common::const_to_opt_uint(val) == Some(0) { + if bcx.unreachable.get() || common::const_to_opt_u128(val, false) == Some(0) { return bcx; } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index d8fe57dacdd55..893bcdf94a8e9 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -899,20 +899,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 bf14d75b12efe..15f7132e52d2f 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 fe76ec05f6ead..b10a6e59ebb50 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -378,11 +378,12 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, '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 788b25f1785fb..bbec27fa1c674 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -35,6 +35,8 @@ use syntax::parse::token; use rustc::session::Session; use syntax_pos::{Span, DUMMY_SP}; +use rustc_i128::u128; + use std::cmp::Ordering; fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option { @@ -1170,7 +1172,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> 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]; @@ -1178,7 +1180,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> .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 003830123ff3b..b8a2ad550fcba 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -278,7 +278,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, '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 @@ -331,14 +331,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, '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 d401e9d082821..1d728709d4d29 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::repr as mir; @@ -28,14 +28,13 @@ use callee::Callee; use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty, type_is_sized}; 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, DUMMY_SP}; use rustc_i128::u128; @@ -45,6 +44,8 @@ use std::ptr; use super::operand::{OperandRef, OperandValue}; use super::MirContext; +use rustc_i128::{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. @@ -456,7 +457,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") @@ -464,7 +465,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)) @@ -830,49 +831,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 1fe6ed64bd4f3..c1ed80402a50e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1568,7 +1568,7 @@ impl PrimitiveType { } pub fn to_string(&self) -> &'static str { - use PrimitiveType::*; + use self::PrimitiveType::*; match *self { Isize => "isize", I8 => "i8", @@ -1615,6 +1615,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, } } } @@ -1627,6 +1628,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, } } } @@ -2420,7 +2422,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 = match cx.tcx_opt() { Some(t) => t, None => return, diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 672ab117f15f3..94e62bc69214c 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1302,7 +1302,7 @@ static LLVMLinkage from_rust(LLVMRustLinkage linkage) { return LLVMCommonLinkage; default: llvm_unreachable("Invalid LLVMRustLinkage value!"); - } + } } extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) { @@ -1311,4 +1311,20 @@ 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; } From b4ab3ec38196f62e6b0801b7f7a72d2fe68ccf39 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 28 Aug 2016 00:59:14 +0300 Subject: [PATCH 12/15] 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 1847a3361a5df..0f3651db67dc1 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -497,14 +497,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) } @@ -747,14 +747,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 90c65e4b33f66ed6ddb3af6e17ce7d913133bc6e Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 27 Sep 2016 16:22:02 +0300 Subject: [PATCH 13/15] 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 0d19985ebc10b..7ba75a709aae1 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -56,8 +56,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), @@ -102,6 +101,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, @@ -114,20 +114,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 7ce5468f27fd4fd05ef21949579ab6e95a74ead9 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 27 Sep 2016 19:06:44 +0300 Subject: [PATCH 14/15] Fix rebase fallout --- src/librustc/ty/layout.rs | 4 ++++ src/librustc_macro/Cargo.toml | 1 - 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 | 2 +- src/librustc_trans/type_.rs | 1 + src/librustc_typeck/check/mod.rs | 2 +- src/libsyntax/feature_gate.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 +++ 14 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 7ba75a709aae1..1f2702a2f9207 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -349,6 +349,7 @@ impl Integer { I16 => Size::from_bytes(2), I32 => Size::from_bytes(4), I64 => Size::from_bytes(8), + I128 => Size::from_bytes(16), } } @@ -359,6 +360,7 @@ impl Integer { I16 => dl.i16_align, I32 => dl.i32_align, I64 => dl.i64_align, + I128 => dl.i128_align, } } @@ -370,11 +372,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_macro/Cargo.toml b/src/librustc_macro/Cargo.toml index 37467cc81647a..6b3ee21d9aceb 100644 --- a/src/librustc_macro/Cargo.toml +++ b/src/librustc_macro/Cargo.toml @@ -10,4 +10,3 @@ crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } -rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 06c3f4cb1936e..600291855da93 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -44,7 +44,7 @@ use syntax::attr; use syntax::ast::{self, NodeId}; use syntax::codemap; 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 0f067270b80f5..82d6cdf89c6f4 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -42,6 +42,8 @@ use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::Visitor; 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 { kind: variant.kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: None }; @@ -410,7 +414,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = VariantData { kind: variant.kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: Some(def_id.index) }; @@ -672,7 +676,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; EntryKind::Struct(self.lazy(&VariantData { kind: variant.kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: struct_ctor })) } @@ -681,7 +685,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { EntryKind::Union(self.lazy(&VariantData { kind: variant.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 a9b748e7b6442..036a0262e19b9 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 f4d1e8e17f842..0ed9b534b39c8 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -26,6 +26,8 @@ use syntax_pos::{self, Span}; use std::marker::PhantomData; +use rustc_i128::u128; + #[cfg(not(test))] pub const RUSTC_VERSION: &'static str = concat!("rustc ", env!("CFG_VERSION")); @@ -264,7 +266,7 @@ pub struct FnData { #[derive(RustcEncodable, RustcDecodable)] pub struct VariantData { pub kind: ty::VariantKind, - 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 9f338500863c0..2cb0577bfa979 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2498,7 +2498,7 @@ impl<'a> Resolver<'a> { match prim { Some(&TyUint(UintTy::U128)) | Some(&TyInt(IntTy::I128)) => { if !this.session.features.borrow().i128_type { - emit_feature_err(&this.session.parse_sess.span_diagnostic, + emit_feature_err(&this.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 4eba2dd95c586..724e96884f223 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -315,6 +315,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 17e097049733c..369a9f44ccbbc 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1246,7 +1246,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/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9e755f5046be4..c471f6f38da54 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -305,7 +305,7 @@ declare_features! ( (active, compiler_builtins, "1.13.0", None), // The `i128` type - (active, i128_type, "1.14.0", Some(35118)) + (active, i128_type, "1.14.0", Some(35118)), ); declare_features! ( diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 4fc687da4291d..d0c898bcfeaa5 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -791,6 +791,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 94e62bc69214c..50d259b272098 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1311,6 +1311,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 b2df420ad9b82d8a145b9cb78c243e4183b438a0 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 2 Oct 2016 23:01:57 +0300 Subject: [PATCH 15/15] 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 fbcf5204d2537..3f23c9e414a88 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)) + } + } +}