Skip to content

Commit

Permalink
Add a way to retrieve constant value in 128 bits
Browse files Browse the repository at this point in the history
Fixes rebase fallout, makes code correct in presence of 128-bit constants.

This commit includes manual merge conflict resolution changes from a rebase by @est31.
  • Loading branch information
nagisa authored and est31 committed Dec 30, 2016
1 parent 508fef5 commit 9aad2d5
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 70 deletions.
36 changes: 34 additions & 2 deletions src/librustc_const_math/int.rs
Expand Up @@ -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
}
}

Expand All @@ -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<ConstInt> {
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<ConstInt> {
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> {
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_llvm/ffi.rs
Expand Up @@ -582,6 +582,8 @@ extern "C" {
pub fn LLVMConstReal(RealTy: TypeRef, N: f64) -> ValueRef;
pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong;
pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong;
pub fn LLVMRustConstInt128Get(ConstantVal: ValueRef, SExt: bool,
high: *mut u64, low: *mut u64) -> bool;


// Operations on composite constants
Expand Down
22 changes: 18 additions & 4 deletions src/librustc_trans/common.rs
Expand Up @@ -592,20 +592,34 @@ fn is_const_integral(v: ValueRef) -> bool {
}
}

pub fn const_to_opt_int(v: ValueRef) -> Option<i64> {

#[cfg(stage0)]
pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option<u128> {
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<u64> {
#[cfg(not(stage0))]
pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option<u128> {
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
}
Expand Down
1 change: 0 additions & 1 deletion src/librustc_trans/consts.rs
Expand Up @@ -24,7 +24,6 @@ use monomorphize::{Instance};
use type_::Type;
use type_of;
use rustc::ty;
use rustc_i128::{i128, u128};

use rustc::hir;

Expand Down
5 changes: 3 additions & 2 deletions src/librustc_trans/glue.rs
Expand Up @@ -346,11 +346,12 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,

// Choose max of two known alignments (combined value must
// be aligned according to more restrictive of the two).
let align = match (const_to_opt_uint(sized_align), const_to_opt_uint(unsized_align)) {
let align = match (const_to_opt_u128(sized_align, false),
const_to_opt_u128(unsized_align, false)) {
(Some(sized_align), Some(unsized_align)) => {
// If both alignments are constant, (the sized_align should always be), then
// pick the correct alignment statically.
C_uint(ccx, std::cmp::max(sized_align, unsized_align))
C_uint(ccx, std::cmp::max(sized_align, unsized_align) as u64)
}
_ => bcx.select(bcx.icmp(llvm::IntUGT, sized_align, unsized_align),
sized_align,
Expand Down
6 changes: 4 additions & 2 deletions src/librustc_trans/intrinsic.rs
Expand Up @@ -32,6 +32,8 @@ use syntax::symbol::Symbol;
use rustc::session::Session;
use syntax_pos::Span;

use rustc_i128::u128;

use std::cmp::Ordering;
use std::iter;

Expand Down Expand Up @@ -1019,15 +1021,15 @@ fn generic_simd_intrinsic<'a, 'tcx>(
in_elem, in_ty,
ret_ty, ret_ty.simd_type(tcx));

let total_len = in_len as u64 * 2;
let total_len = in_len as u128 * 2;

let vector = llargs[2];

let indices: Option<Vec<_>> = (0..n)
.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
Expand Down
16 changes: 7 additions & 9 deletions src/librustc_trans/mir/block.rs
Expand Up @@ -269,7 +269,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {

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

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

let const_err = common::const_to_opt_uint(len).and_then(|len| {
common::const_to_opt_uint(index).map(|index| {
ErrKind::IndexOutOfBounds {
len: len,
index: index
}
})
});
let const_err = common::const_to_opt_u128(len, false)
.and_then(|len| common::const_to_opt_u128(index, false)
.map(|index| ErrKind::IndexOutOfBounds {
len: len as u64,
index: index as u64
}));

let file_line = C_struct(bcx.ccx, &[filename, line], false);
let align = llalign_of_min(bcx.ccx, common::val_ty(file_line));
Expand Down
63 changes: 14 additions & 49 deletions src/librustc_trans/mir/constant.rs
Expand Up @@ -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;
Expand All @@ -27,23 +27,23 @@ use callee::Callee;
use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty};
use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral};
use common::{C_null, C_struct, C_str_slice, C_undef, C_uint};
use common::{const_to_opt_int, const_to_opt_uint};
use common::{const_to_opt_u128};
use consts;
use monomorphize::{self, Instance};
use type_of;
use type_::Type;
use value::Value;

use syntax::ast;
use syntax_pos::Span;
use rustc_i128::u128;

use std::fmt;
use std::ptr;

use super::operand::{OperandRef, OperandValue};
use super::MirContext;

use rustc_i128::{u128, i128};

/// A sized constant rvalue.
/// The LLVM type might not be the same for a single Rust type,
/// e.g. each enum variant would have its own LLVM struct type.
Expand Down Expand Up @@ -431,15 +431,15 @@ 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")
};

// 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))
Expand Down Expand Up @@ -797,49 +797,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {

fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
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

}
}

Expand Down
4 changes: 3 additions & 1 deletion src/librustdoc/clean/mod.rs
Expand Up @@ -1653,6 +1653,7 @@ impl From<ast::IntTy> for PrimitiveType {
ast::IntTy::I16 => PrimitiveType::I16,
ast::IntTy::I32 => PrimitiveType::I32,
ast::IntTy::I64 => PrimitiveType::I64,
ast::IntTy::I128 => PrimitiveType::I128,
}
}
}
Expand All @@ -1665,6 +1666,7 @@ impl From<ast::UintTy> for PrimitiveType {
ast::UintTy::U16 => PrimitiveType::U16,
ast::UintTy::U32 => PrimitiveType::U32,
ast::UintTy::U64 => PrimitiveType::U64,
ast::UintTy::U128 => PrimitiveType::U128,
}
}
}
Expand Down Expand Up @@ -2489,7 +2491,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
fn build_deref_target_impls(cx: &DocContext,
items: &[Item],
ret: &mut Vec<Item>) {
use PrimitiveType::*;
use self::PrimitiveType::*;
let tcx = cx.tcx;

for item in items {
Expand Down
16 changes: 16 additions & 0 deletions src/rustllvm/RustWrapper.cpp
Expand Up @@ -1456,6 +1456,22 @@ extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) {

extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) {
LLVMSetLinkage(V, from_rust(RustLinkage));

// Returns true if both high and low were successfully set. Fails in case constant wasn’t any of
// the common sizes (1, 8, 16, 32, 64, 128 bits)
extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low)
{
auto C = unwrap<llvm::ConstantInt>(CV);
if (C->getBitWidth() > 128) { return false; }
APInt AP;
if (sext) {
AP = C->getValue().sextOrSelf(128);
} else {
AP = C->getValue().zextOrSelf(128);
}
*low = AP.getLoBits(64).getZExtValue();
*high = AP.getHiBits(64).getZExtValue();
return true;
}

extern "C" LLVMContextRef LLVMRustGetValueContext(LLVMValueRef V) {
Expand Down

0 comments on commit 9aad2d5

Please sign in to comment.