提交 9aad2d55 编写于 作者: S Simonas Kazlauskas 提交者: est31

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.
上级 508fef5d
......@@ -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 @@ pub fn LLVMStructTypeInContext(C: ContextRef,
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 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 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 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
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 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
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_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 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 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 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
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 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
// 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 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'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 @@ fn from(int_ty: ast::IntTy) -> 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 @@ fn from(uint_ty: ast::UintTy) -> 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 @@ fn clean(&self, cx: &DocContext) -> Vec<Item> {
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) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册