Add a way to retrieve constant value in 128 bits
Fixes rebase fallout, makes code correct in presence of 128-bit constants. This commit includes manual merge conflict resolution changes from a rebase by @est31.
This commit is contained in:
parent
508fef5dff
commit
9aad2d551e
@ -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<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> {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ use monomorphize::{Instance};
|
||||
use type_::Type;
|
||||
use type_of;
|
||||
use rustc::ty;
|
||||
use rustc_i128::{i128, u128};
|
||||
|
||||
use rustc::hir;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -32,6 +32,8 @@ use syntax::symbol::Symbol;
|
||||
use rustc::session::Session;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use rustc_i128::u128;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::iter;
|
||||
|
||||
@ -1019,7 +1021,7 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
||||
in_elem, in_ty,
|
||||
ret_ty, ret_ty.simd_type(tcx));
|
||||
|
||||
let total_len = in_len as u64 * 2;
|
||||
let total_len = in_len as u128 * 2;
|
||||
|
||||
let vector = llargs[2];
|
||||
|
||||
@ -1027,7 +1029,7 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
||||
.map(|i| {
|
||||
let arg_idx = i;
|
||||
let val = const_get_elt(vector, &[i as libc::c_uint]);
|
||||
match const_to_opt_uint(val) {
|
||||
match const_to_opt_u128(val, true) {
|
||||
None => {
|
||||
emit_error!("shuffle index #{} is not a constant", arg_idx);
|
||||
None
|
||||
|
@ -269,7 +269,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
|
||||
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => {
|
||||
let cond = self.trans_operand(&bcx, cond).immediate();
|
||||
let mut const_cond = common::const_to_opt_uint(cond).map(|c| c == 1);
|
||||
let mut const_cond = common::const_to_opt_u128(cond, false).map(|c| c == 1);
|
||||
|
||||
// This case can currently arise only from functions marked
|
||||
// with #[rustc_inherit_overflow_checks] and inlined from
|
||||
@ -322,14 +322,12 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
let len = self.trans_operand(&mut bcx, len).immediate();
|
||||
let index = self.trans_operand(&mut bcx, index).immediate();
|
||||
|
||||
let const_err = common::const_to_opt_uint(len).and_then(|len| {
|
||||
common::const_to_opt_uint(index).map(|index| {
|
||||
ErrKind::IndexOutOfBounds {
|
||||
len: len,
|
||||
index: index
|
||||
}
|
||||
})
|
||||
});
|
||||
let const_err = common::const_to_opt_u128(len, false)
|
||||
.and_then(|len| common::const_to_opt_u128(index, false)
|
||||
.map(|index| ErrKind::IndexOutOfBounds {
|
||||
len: len as u64,
|
||||
index: index as u64
|
||||
}));
|
||||
|
||||
let file_line = C_struct(bcx.ccx, &[filename, line], false);
|
||||
let align = llalign_of_min(bcx.ccx, common::val_ty(file_line));
|
||||
|
@ -13,7 +13,7 @@ use rustc::middle::const_val::ConstVal;
|
||||
use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err};
|
||||
use rustc_const_math::ConstInt::*;
|
||||
use rustc_const_math::ConstFloat::*;
|
||||
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize, ConstMathErr};
|
||||
use rustc_const_math::{ConstInt, ConstMathErr};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::TransNormalize;
|
||||
use rustc::mir;
|
||||
@ -27,16 +27,14 @@ use callee::Callee;
|
||||
use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty};
|
||||
use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral};
|
||||
use common::{C_null, C_struct, C_str_slice, C_undef, C_uint};
|
||||
use common::{const_to_opt_int, const_to_opt_uint};
|
||||
use common::{const_to_opt_u128};
|
||||
use consts;
|
||||
use monomorphize::{self, Instance};
|
||||
use type_of;
|
||||
use type_::Type;
|
||||
use value::Value;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use rustc_i128::u128;
|
||||
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
@ -44,6 +42,8 @@ use std::ptr;
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
use super::MirContext;
|
||||
|
||||
use rustc_i128::{u128, i128};
|
||||
|
||||
/// A sized constant rvalue.
|
||||
/// The LLVM type might not be the same for a single Rust type,
|
||||
/// e.g. each enum variant would have its own LLVM struct type.
|
||||
@ -431,7 +431,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
mir::ProjectionElem::Index(ref index) => {
|
||||
let llindex = self.const_operand(index, span)?.llval;
|
||||
|
||||
let iv = if let Some(iv) = common::const_to_opt_uint(llindex) {
|
||||
let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
|
||||
iv
|
||||
} else {
|
||||
span_bug!(span, "index is not an integer-constant expression")
|
||||
@ -439,7 +439,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
|
||||
// Produce an undef instead of a LLVM assertion on OOB.
|
||||
let len = common::const_to_uint(tr_base.len(self.ccx));
|
||||
let llelem = if iv < len {
|
||||
let llelem = if iv < len as u128 {
|
||||
const_get_elt(base.llval, &[iv as u32])
|
||||
} else {
|
||||
C_undef(type_of::type_of(self.ccx, projected_ty))
|
||||
@ -797,49 +797,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
|
||||
fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user