Skip to content

Commit dbcd45a

Browse files
committed
Add a way to retrieve constant value in 128 bits
Fixes rebase fallout, makes code correct in presence of 128-bit constants.
1 parent 817f7d6 commit dbcd45a

File tree

11 files changed

+105
-71
lines changed

11 files changed

+105
-71
lines changed

src/librustc_const_math/int.rs

+34-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ mod ubounds {
5858
bounds!{u128: 0,
5959
i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX
6060
u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX u128 U128MIN U128MAX
61-
isize IMIN IMAX usize UMIN UMAX
61+
// do not add constants for isize/usize, because these are guaranteed to be wrong for
62+
// arbitrary host/target combinations
6263
}
6364
}
6465

@@ -78,11 +79,42 @@ mod ibounds {
7879
bounds!{i128,
7980
i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX
8081
u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX
81-
isize IMIN IMAX usize UMIN UMAX
82+
// do not add constants for isize/usize, because these are guaranteed to be wrong for
83+
// arbitrary host/target combinations
8284
}
8385
}
8486

8587
impl ConstInt {
88+
/// Creates a new unsigned ConstInt with matching type while also checking that overflow does
89+
/// not happen.
90+
pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {
91+
match ty {
92+
UintTy::U8 if val <= ubounds::U8MAX => Some(U8(val as u8)),
93+
UintTy::U16 if val <= ubounds::U16MAX => Some(U16(val as u16)),
94+
UintTy::U32 if val <= ubounds::U32MAX => Some(U32(val as u32)),
95+
UintTy::U64 if val <= ubounds::U64MAX => Some(U64(val as u64)),
96+
UintTy::Us if val <= ubounds::U64MAX => ConstUsize::new(val as u64, usize_ty).ok()
97+
.map(Usize),
98+
UintTy::U128 => Some(U128(val)),
99+
_ => None
100+
}
101+
}
102+
103+
/// Creates a new unsigned ConstInt with matching type while also checking that overflow does
104+
/// not happen.
105+
pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> {
106+
match ty {
107+
IntTy::I8 if val <= ibounds::I8MAX => Some(I8(val as i8)),
108+
IntTy::I16 if val <= ibounds::I16MAX => Some(I16(val as i16)),
109+
IntTy::I32 if val <= ibounds::I32MAX => Some(I32(val as i32)),
110+
IntTy::I64 if val <= ibounds::I64MAX => Some(I64(val as i64)),
111+
IntTy::Is if val <= ibounds::I64MAX => ConstIsize::new(val as i64, isize_ty).ok()
112+
.map(Isize),
113+
IntTy::I128 => Some(I128(val)),
114+
_ => None
115+
}
116+
}
117+
86118
/// If either value is `Infer` or `InferSigned`, try to turn the value into the type of
87119
/// the other value. If both values have no type, don't do anything
88120
pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> {

src/librustc_llvm/ffi.rs

+2
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,8 @@ extern {
659659
-> ValueRef;
660660
pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong;
661661
pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong;
662+
pub fn LLVMRustConstInt128Get(ConstantVal: ValueRef, SExt: bool,
663+
high: *mut u64, low: *mut u64) -> bool;
662664

663665

664666
/* Operations on composite constants */

src/librustc_trans/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) ->
735735
{
736736
let _icx = push_ctxt("with_cond");
737737

738-
if bcx.unreachable.get() || common::const_to_opt_uint(val) == Some(0) {
738+
if bcx.unreachable.get() || common::const_to_opt_u128(val, false) == Some(0) {
739739
return bcx;
740740
}
741741

src/librustc_trans/common.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -926,20 +926,34 @@ fn is_const_integral(v: ValueRef) -> bool {
926926
}
927927
}
928928

929-
pub fn const_to_opt_int(v: ValueRef) -> Option<i64> {
929+
930+
#[cfg(stage0)]
931+
pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option<u128> {
930932
unsafe {
931933
if is_const_integral(v) {
932-
Some(llvm::LLVMConstIntGetSExtValue(v))
934+
if !sign_ext {
935+
Some(llvm::LLVMConstIntGetZExtValue(v))
936+
} else {
937+
Some(llvm::LLVMConstIntGetSExtValue(v) as u64)
938+
}
933939
} else {
934940
None
935941
}
936942
}
937943
}
938944

939-
pub fn const_to_opt_uint(v: ValueRef) -> Option<u64> {
945+
#[cfg(not(stage0))]
946+
pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option<u128> {
940947
unsafe {
941948
if is_const_integral(v) {
942-
Some(llvm::LLVMConstIntGetZExtValue(v))
949+
let (mut lo, mut hi) = (0u64, 0u64);
950+
let success = llvm::LLVMRustConstInt128Get(v, sign_ext,
951+
&mut hi as *mut u64, &mut lo as *mut u64);
952+
if success {
953+
Some(((hi as u128) << 64) | (lo as u128))
954+
} else {
955+
None
956+
}
943957
} else {
944958
None
945959
}

src/librustc_trans/consts.rs

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ use monomorphize::{Instance};
2424
use type_::Type;
2525
use type_of;
2626
use rustc::ty;
27-
use rustc_i128::{i128, u128};
2827

2928
use rustc::hir;
3029

src/librustc_trans/glue.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -368,11 +368,12 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
368368

369369
// Choose max of two known alignments (combined value must
370370
// be aligned according to more restrictive of the two).
371-
let align = match (const_to_opt_uint(sized_align), const_to_opt_uint(unsized_align)) {
371+
let align = match (const_to_opt_u128(sized_align, false),
372+
const_to_opt_u128(unsized_align, false)) {
372373
(Some(sized_align), Some(unsized_align)) => {
373374
// If both alignments are constant, (the sized_align should always be), then
374375
// pick the correct alignment statically.
375-
C_uint(ccx, std::cmp::max(sized_align, unsized_align))
376+
C_uint(ccx, std::cmp::max(sized_align, unsized_align) as u64)
376377
}
377378
_ => bcx.select(bcx.icmp(llvm::IntUGT, sized_align, unsized_align),
378379
sized_align,

src/librustc_trans/intrinsic.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ use syntax::parse::token;
3535
use rustc::session::Session;
3636
use syntax_pos::{Span, DUMMY_SP};
3737

38+
use rustc_i128::u128;
39+
3840
use std::cmp::Ordering;
3941

4042
fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
@@ -1165,15 +1167,15 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
11651167
in_elem, in_ty,
11661168
ret_ty, ret_ty.simd_type(tcx));
11671169

1168-
let total_len = in_len as u64 * 2;
1170+
let total_len = in_len as u128 * 2;
11691171

11701172
let vector = llargs[2];
11711173

11721174
let indices: Option<Vec<_>> = (0..n)
11731175
.map(|i| {
11741176
let arg_idx = i;
11751177
let val = const_get_elt(vector, &[i as libc::c_uint]);
1176-
match const_to_opt_uint(val) {
1178+
match const_to_opt_u128(val, true) {
11771179
None => {
11781180
emit_error!("shuffle index #{} is not a constant", arg_idx);
11791181
None

src/librustc_trans/mir/block.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
261261

262262
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => {
263263
let cond = self.trans_operand(&bcx, cond).immediate();
264-
let mut const_cond = common::const_to_opt_uint(cond).map(|c| c == 1);
264+
let mut const_cond = common::const_to_opt_u128(cond, false).map(|c| c == 1);
265265

266266
// This case can currently arise only from functions marked
267267
// with #[rustc_inherit_overflow_checks] and inlined from
@@ -314,14 +314,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
314314
let len = self.trans_operand(&mut bcx, len).immediate();
315315
let index = self.trans_operand(&mut bcx, index).immediate();
316316

317-
let const_err = common::const_to_opt_uint(len).and_then(|len| {
318-
common::const_to_opt_uint(index).map(|index| {
319-
ErrKind::IndexOutOfBounds {
320-
len: len,
321-
index: index
322-
}
323-
})
324-
});
317+
let const_err = common::const_to_opt_u128(len, false)
318+
.and_then(|len| common::const_to_opt_u128(index, false)
319+
.map(|index| ErrKind::IndexOutOfBounds {
320+
len: len as u64,
321+
index: index as u64
322+
}));
325323

326324
let file_line = C_struct(bcx.ccx(), &[filename, line], false);
327325
let align = llalign_of_min(bcx.ccx(), common::val_ty(file_line));

src/librustc_trans/mir/constant.rs

+14-48
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc::middle::const_val::ConstVal;
1313
use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err};
1414
use rustc_const_math::ConstInt::*;
1515
use rustc_const_math::ConstFloat::*;
16-
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize, ConstMathErr};
16+
use rustc_const_math::{ConstInt, ConstMathErr};
1717
use rustc::hir::def_id::DefId;
1818
use rustc::infer::TransNormalize;
1919
use rustc::mir::repr as mir;
@@ -28,14 +28,13 @@ use callee::Callee;
2828
use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty};
2929
use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral};
3030
use common::{C_null, C_struct, C_str_slice, C_undef, C_uint};
31-
use common::{const_to_opt_int, const_to_opt_uint};
31+
use common::{const_to_opt_u128};
3232
use consts;
3333
use monomorphize::{self, Instance};
3434
use type_of;
3535
use type_::Type;
3636
use value::Value;
3737

38-
use syntax::ast;
3938
use syntax_pos::{Span, DUMMY_SP};
4039
use rustc_i128::u128;
4140

@@ -44,6 +43,8 @@ use std::ptr;
4443
use super::operand::{OperandRef, OperandValue};
4544
use super::MirContext;
4645

46+
use rustc_i128::{i128};
47+
4748
/// A sized constant rvalue.
4849
/// The LLVM type might not be the same for a single Rust type,
4950
/// e.g. each enum variant would have its own LLVM struct type.
@@ -445,15 +446,15 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
445446
mir::ProjectionElem::Index(ref index) => {
446447
let llindex = self.const_operand(index, span)?.llval;
447448

448-
let iv = if let Some(iv) = common::const_to_opt_uint(llindex) {
449+
let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
449450
iv
450451
} else {
451452
span_bug!(span, "index is not an integer-constant expression")
452453
};
453454

454455
// Produce an undef instead of a LLVM assertion on OOB.
455456
let len = common::const_to_uint(tr_base.len(self.ccx));
456-
let llelem = if iv < len {
457+
let llelem = if iv < len as u128 {
457458
const_get_elt(base.llval, &[iv as u32])
458459
} else {
459460
C_undef(type_of::type_of(self.ccx, projected_ty))
@@ -796,49 +797,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
796797

797798
fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
798799
match t.sty {
799-
ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type {
800-
ast::IntTy::I8 => {
801-
assert_eq!(input as i8 as i64, input);
802-
Some(ConstInt::I8(input as i8))
803-
},
804-
ast::IntTy::I16 => {
805-
assert_eq!(input as i16 as i64, input);
806-
Some(ConstInt::I16(input as i16))
807-
},
808-
ast::IntTy::I32 => {
809-
assert_eq!(input as i32 as i64, input);
810-
Some(ConstInt::I32(input as i32))
811-
},
812-
ast::IntTy::I64 => {
813-
Some(ConstInt::I64(input))
814-
},
815-
ast::IntTy::Is => {
816-
ConstIsize::new(input, tcx.sess.target.int_type)
817-
.ok().map(ConstInt::Isize)
818-
},
819-
}),
820-
ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type {
821-
ast::UintTy::U8 => {
822-
assert_eq!(input as u8 as u64, input);
823-
Some(ConstInt::U8(input as u8))
824-
},
825-
ast::UintTy::U16 => {
826-
assert_eq!(input as u16 as u64, input);
827-
Some(ConstInt::U16(input as u16))
828-
},
829-
ast::UintTy::U32 => {
830-
assert_eq!(input as u32 as u64, input);
831-
Some(ConstInt::U32(input as u32))
832-
},
833-
ast::UintTy::U64 => {
834-
Some(ConstInt::U64(input))
835-
},
836-
ast::UintTy::Us => {
837-
ConstUsize::new(input, tcx.sess.target.uint_type)
838-
.ok().map(ConstInt::Usize)
839-
},
840-
}),
841-
_ => None,
800+
ty::TyInt(int_type) => const_to_opt_u128(value, true)
801+
.and_then(|input| ConstInt::new_signed(input as i128, int_type,
802+
tcx.sess.target.int_type)),
803+
ty::TyUint(uint_type) => const_to_opt_u128(value, false)
804+
.and_then(|input| ConstInt::new_unsigned(input, uint_type,
805+
tcx.sess.target.uint_type)),
806+
_ => None
807+
842808
}
843809
}
844810

src/librustdoc/clean/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1583,7 +1583,7 @@ impl PrimitiveType {
15831583
}
15841584

15851585
pub fn to_string(&self) -> &'static str {
1586-
use PrimitiveType::*;
1586+
use self::PrimitiveType::*;
15871587
match *self {
15881588
Isize => "isize",
15891589
I8 => "i8",
@@ -1630,6 +1630,7 @@ impl From<ast::IntTy> for PrimitiveType {
16301630
ast::IntTy::I16 => PrimitiveType::I16,
16311631
ast::IntTy::I32 => PrimitiveType::I32,
16321632
ast::IntTy::I64 => PrimitiveType::I64,
1633+
ast::IntTy::I128 => PrimitiveType::I128,
16331634
}
16341635
}
16351636
}
@@ -1642,6 +1643,7 @@ impl From<ast::UintTy> for PrimitiveType {
16421643
ast::UintTy::U16 => PrimitiveType::U16,
16431644
ast::UintTy::U32 => PrimitiveType::U32,
16441645
ast::UintTy::U64 => PrimitiveType::U64,
1646+
ast::UintTy::U128 => PrimitiveType::U128,
16451647
}
16461648
}
16471649
}
@@ -2441,7 +2443,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
24412443
fn build_deref_target_impls(cx: &DocContext,
24422444
items: &[Item],
24432445
ret: &mut Vec<Item>) {
2444-
use PrimitiveType::*;
2446+
use self::PrimitiveType::*;
24452447
let tcx = match cx.tcx_opt() {
24462448
Some(t) => t,
24472449
None => return,

src/rustllvm/RustWrapper.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -1232,3 +1232,21 @@ extern "C" void LLVMRustUnsetComdat(LLVMValueRef V) {
12321232
GlobalObject *GV = unwrap<GlobalObject>(V);
12331233
GV->setComdat(nullptr);
12341234
}
1235+
1236+
1237+
// Returns true if both high and low were successfully set. Fails in case constant wasn’t any of
1238+
// the common sizes (1, 8, 16, 32, 64, 128 bits)
1239+
extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low)
1240+
{
1241+
auto C = unwrap<llvm::ConstantInt>(CV);
1242+
if (C->getBitWidth() > 128) { return false; }
1243+
APInt AP;
1244+
if (sext) {
1245+
AP = C->getValue().sextOrSelf(128);
1246+
} else {
1247+
AP = C->getValue().zextOrSelf(128);
1248+
}
1249+
*low = AP.getLoBits(64).getZExtValue();
1250+
*high = AP.getHiBits(64).getZExtValue();
1251+
return true;
1252+
}

0 commit comments

Comments
 (0)