Skip to content

Commit af1062d

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 03cf911 commit af1062d

File tree

11 files changed

+104
-72
lines changed

11 files changed

+104
-72
lines changed

src/librustc_const_math/int.rs

Lines changed: 34 additions & 2 deletions
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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,8 @@ extern {
654654
-> ValueRef;
655655
pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong;
656656
pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong;
657+
pub fn LLVMRustConstInt128Get(ConstantVal: ValueRef, SExt: bool,
658+
high: *mut u64, low: *mut u64) -> bool;
657659

658660

659661
/* Operations on composite constants */

src/librustc_trans/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) ->
727727
{
728728
let _icx = push_ctxt("with_cond");
729729

730-
if bcx.unreachable.get() || common::const_to_opt_uint(val) == Some(0) {
730+
if bcx.unreachable.get() || common::const_to_opt_u128(val, false) == Some(0) {
731731
return bcx;
732732
}
733733

src/librustc_trans/common.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -899,20 +899,34 @@ fn is_const_integral(v: ValueRef) -> bool {
899899
}
900900
}
901901

902-
pub fn const_to_opt_int(v: ValueRef) -> Option<i64> {
902+
903+
#[cfg(stage0)]
904+
pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option<u128> {
903905
unsafe {
904906
if is_const_integral(v) {
905-
Some(llvm::LLVMConstIntGetSExtValue(v))
907+
if !sign_ext {
908+
Some(llvm::LLVMConstIntGetZExtValue(v))
909+
} else {
910+
Some(llvm::LLVMConstIntGetSExtValue(v) as u64)
911+
}
906912
} else {
907913
None
908914
}
909915
}
910916
}
911917

912-
pub fn const_to_opt_uint(v: ValueRef) -> Option<u64> {
918+
#[cfg(not(stage0))]
919+
pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option<u128> {
913920
unsafe {
914921
if is_const_integral(v) {
915-
Some(llvm::LLVMConstIntGetZExtValue(v))
922+
let (mut lo, mut hi) = (0u64, 0u64);
923+
let success = llvm::LLVMRustConstInt128Get(v, sign_ext,
924+
&mut hi as *mut u64, &mut lo as *mut u64);
925+
if success {
926+
Some(((hi as u128) << 64) | (lo as u128))
927+
} else {
928+
None
929+
}
916930
} else {
917931
None
918932
}

src/librustc_trans/consts.rs

Lines changed: 0 additions & 1 deletion
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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,11 +378,12 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
378378

379379
// Choose max of two known alignments (combined value must
380380
// be aligned according to more restrictive of the two).
381-
let align = match (const_to_opt_uint(sized_align), const_to_opt_uint(unsized_align)) {
381+
let align = match (const_to_opt_u128(sized_align, false),
382+
const_to_opt_u128(unsized_align, false)) {
382383
(Some(sized_align), Some(unsized_align)) => {
383384
// If both alignments are constant, (the sized_align should always be), then
384385
// pick the correct alignment statically.
385-
C_uint(ccx, std::cmp::max(sized_align, unsized_align))
386+
C_uint(ccx, std::cmp::max(sized_align, unsized_align) as u64)
386387
}
387388
_ => bcx.select(bcx.icmp(llvm::IntUGT, sized_align, unsized_align),
388389
sized_align,

src/librustc_trans/intrinsic.rs

Lines changed: 4 additions & 2 deletions
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> {
@@ -1170,15 +1172,15 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
11701172
in_elem, in_ty,
11711173
ret_ty, ret_ty.simd_type(tcx));
11721174

1173-
let total_len = in_len as u64 * 2;
1175+
let total_len = in_len as u128 * 2;
11741176

11751177
let vector = llargs[2];
11761178

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

src/librustc_trans/mir/block.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
278278

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

283283
// This case can currently arise only from functions marked
284284
// with #[rustc_inherit_overflow_checks] and inlined from
@@ -331,14 +331,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
331331
let len = self.trans_operand(&mut bcx, len).immediate();
332332
let index = self.trans_operand(&mut bcx, index).immediate();
333333

334-
let const_err = common::const_to_opt_uint(len).and_then(|len| {
335-
common::const_to_opt_uint(index).map(|index| {
336-
ErrKind::IndexOutOfBounds {
337-
len: len,
338-
index: index
339-
}
340-
})
341-
});
334+
let const_err = common::const_to_opt_u128(len, false)
335+
.and_then(|len| common::const_to_opt_u128(index, false)
336+
.map(|index| ErrKind::IndexOutOfBounds {
337+
len: len as u64,
338+
index: index as u64
339+
}));
342340

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

src/librustc_trans/mir/constant.rs

Lines changed: 14 additions & 48 deletions
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, type_is_sized};
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

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

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

459-
let iv = if let Some(iv) = common::const_to_opt_uint(llindex) {
460+
let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
460461
iv
461462
} else {
462463
span_bug!(span, "index is not an integer-constant expression")
463464
};
464465

465466
// Produce an undef instead of a LLVM assertion on OOB.
466467
let len = common::const_to_uint(tr_base.len(self.ccx));
467-
let llelem = if iv < len {
468+
let llelem = if iv < len as u128 {
468469
const_get_elt(base.llval, &[iv as u32])
469470
} else {
470471
C_undef(type_of::type_of(self.ccx, projected_ty))
@@ -830,49 +831,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
830831

831832
fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
832833
match t.sty {
833-
ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type {
834-
ast::IntTy::I8 => {
835-
assert_eq!(input as i8 as i64, input);
836-
Some(ConstInt::I8(input as i8))
837-
},
838-
ast::IntTy::I16 => {
839-
assert_eq!(input as i16 as i64, input);
840-
Some(ConstInt::I16(input as i16))
841-
},
842-
ast::IntTy::I32 => {
843-
assert_eq!(input as i32 as i64, input);
844-
Some(ConstInt::I32(input as i32))
845-
},
846-
ast::IntTy::I64 => {
847-
Some(ConstInt::I64(input))
848-
},
849-
ast::IntTy::Is => {
850-
ConstIsize::new(input, tcx.sess.target.int_type)
851-
.ok().map(ConstInt::Isize)
852-
},
853-
}),
854-
ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type {
855-
ast::UintTy::U8 => {
856-
assert_eq!(input as u8 as u64, input);
857-
Some(ConstInt::U8(input as u8))
858-
},
859-
ast::UintTy::U16 => {
860-
assert_eq!(input as u16 as u64, input);
861-
Some(ConstInt::U16(input as u16))
862-
},
863-
ast::UintTy::U32 => {
864-
assert_eq!(input as u32 as u64, input);
865-
Some(ConstInt::U32(input as u32))
866-
},
867-
ast::UintTy::U64 => {
868-
Some(ConstInt::U64(input))
869-
},
870-
ast::UintTy::Us => {
871-
ConstUsize::new(input, tcx.sess.target.uint_type)
872-
.ok().map(ConstInt::Usize)
873-
},
874-
}),
875-
_ => None,
834+
ty::TyInt(int_type) => const_to_opt_u128(value, true)
835+
.and_then(|input| ConstInt::new_signed(input as i128, int_type,
836+
tcx.sess.target.int_type)),
837+
ty::TyUint(uint_type) => const_to_opt_u128(value, false)
838+
.and_then(|input| ConstInt::new_unsigned(input, uint_type,
839+
tcx.sess.target.uint_type)),
840+
_ => None
841+
876842
}
877843
}
878844

src/librustdoc/clean/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,7 +1568,7 @@ impl PrimitiveType {
15681568
}
15691569

15701570
pub fn to_string(&self) -> &'static str {
1571-
use PrimitiveType::*;
1571+
use self::PrimitiveType::*;
15721572
match *self {
15731573
Isize => "isize",
15741574
I8 => "i8",
@@ -1615,6 +1615,7 @@ impl From<ast::IntTy> for PrimitiveType {
16151615
ast::IntTy::I16 => PrimitiveType::I16,
16161616
ast::IntTy::I32 => PrimitiveType::I32,
16171617
ast::IntTy::I64 => PrimitiveType::I64,
1618+
ast::IntTy::I128 => PrimitiveType::I128,
16181619
}
16191620
}
16201621
}
@@ -1627,6 +1628,7 @@ impl From<ast::UintTy> for PrimitiveType {
16271628
ast::UintTy::U16 => PrimitiveType::U16,
16281629
ast::UintTy::U32 => PrimitiveType::U32,
16291630
ast::UintTy::U64 => PrimitiveType::U64,
1631+
ast::UintTy::U128 => PrimitiveType::U128,
16301632
}
16311633
}
16321634
}
@@ -2420,7 +2422,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
24202422
fn build_deref_target_impls(cx: &DocContext,
24212423
items: &[Item],
24222424
ret: &mut Vec<Item>) {
2423-
use PrimitiveType::*;
2425+
use self::PrimitiveType::*;
24242426
let tcx = match cx.tcx_opt() {
24252427
Some(t) => t,
24262428
None => return,

src/rustllvm/RustWrapper.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,7 @@ static LLVMLinkage from_rust(LLVMRustLinkage linkage) {
13021302
return LLVMCommonLinkage;
13031303
default:
13041304
llvm_unreachable("Invalid LLVMRustLinkage value!");
1305-
}
1305+
}
13061306
}
13071307

13081308
extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) {
@@ -1311,4 +1311,20 @@ extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) {
13111311

13121312
extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) {
13131313
LLVMSetLinkage(V, from_rust(RustLinkage));
1314+
1315+
// Returns true if both high and low were successfully set. Fails in case constant wasn’t any of
1316+
// the common sizes (1, 8, 16, 32, 64, 128 bits)
1317+
extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low)
1318+
{
1319+
auto C = unwrap<llvm::ConstantInt>(CV);
1320+
if (C->getBitWidth() > 128) { return false; }
1321+
APInt AP;
1322+
if (sext) {
1323+
AP = C->getValue().sextOrSelf(128);
1324+
} else {
1325+
AP = C->getValue().zextOrSelf(128);
1326+
}
1327+
*low = AP.getLoBits(64).getZExtValue();
1328+
*high = AP.getHiBits(64).getZExtValue();
1329+
return true;
13141330
}

0 commit comments

Comments
 (0)