Fix intcast, use it where appropriate
This commit is contained in:
parent
7d1f36a482
commit
f3bd723101
@ -1310,7 +1310,6 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
let discr_max = (variants.len() - 1) as i64;
|
||||
assert!(discr_max >= 0);
|
||||
let (min_ity, _) = Integer::repr_discr(tcx, ty, &hints[..], 0, discr_max);
|
||||
|
||||
let mut align = dl.aggregate_align;
|
||||
let mut size = Size::from_bytes(0);
|
||||
|
||||
@ -1351,6 +1350,23 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
return Err(LayoutError::SizeOverflow(ty));
|
||||
}
|
||||
|
||||
let typeck_ity = Integer::from_attr(dl, def.discr_ty);
|
||||
if typeck_ity < min_ity {
|
||||
// It is a bug if Layout decided on a greater discriminant size than typeck for
|
||||
// some reason at this point (based on values discriminant can take on). Mostly
|
||||
// because this discriminant will be loaded, and then stored into variable of
|
||||
// type calculated by typeck. Consider such case (a bug): typeck decided on
|
||||
// byte-sized discriminant, but layout thinks we need a 16-bit to store all
|
||||
// discriminant values. That would be a bug, because then, in trans, in order
|
||||
// to store this 16-bit discriminant into 8-bit sized temporary some of the
|
||||
// space necessary to represent would have to be discarded (or layout is wrong
|
||||
// on thinking it needs 16 bits)
|
||||
bug!("layout decided on a larger discriminant type ({:?}) than typeck ({:?})",
|
||||
min_ity, typeck_ity);
|
||||
// However, it is fine to make discr type however large (as an optimisation)
|
||||
// after this point – we’ll just truncate the value we load in trans.
|
||||
}
|
||||
|
||||
// Check to see if we should use a different type for the
|
||||
// discriminant. We can safely use a type with the same size
|
||||
// as the alignment of the first field of each variant.
|
||||
|
@ -1084,11 +1084,11 @@ extern "C" {
|
||||
DestTy: TypeRef,
|
||||
Name: *const c_char)
|
||||
-> ValueRef;
|
||||
pub fn LLVMBuildIntCast(B: BuilderRef,
|
||||
Val: ValueRef,
|
||||
DestTy: TypeRef,
|
||||
Name: *const c_char)
|
||||
-> ValueRef;
|
||||
pub fn LLVMRustBuildIntCast(B: BuilderRef,
|
||||
Val: ValueRef,
|
||||
DestTy: TypeRef,
|
||||
IsSized: bool)
|
||||
-> ValueRef;
|
||||
pub fn LLVMBuildFPCast(B: BuilderRef,
|
||||
Val: ValueRef,
|
||||
DestTy: TypeRef,
|
||||
|
@ -318,7 +318,7 @@ pub fn trans_get_discr<'a, 'tcx>(
|
||||
};
|
||||
match cast_to {
|
||||
None => val,
|
||||
Some(llty) => if is_discr_signed(&l) { bcx.sext(val, llty) } else { bcx.zext(val, llty) }
|
||||
Some(llty) => bcx.intcast(val, llty, is_discr_signed(&l))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -536,7 +536,7 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>,
|
||||
let memcpy = ccx.get_intrinsic(&key);
|
||||
let src_ptr = b.pointercast(src, Type::i8p(ccx));
|
||||
let dst_ptr = b.pointercast(dst, Type::i8p(ccx));
|
||||
let size = b.intcast(n_bytes, ccx.int_type());
|
||||
let size = b.intcast(n_bytes, ccx.int_type(), false);
|
||||
let align = C_i32(ccx, align as i32);
|
||||
let volatile = C_bool(ccx, false);
|
||||
b.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
|
||||
|
@ -780,10 +780,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
pub fn intcast(&self, val: ValueRef, dest_ty: Type, is_signed: bool) -> ValueRef {
|
||||
self.count_insn("intcast");
|
||||
unsafe {
|
||||
llvm::LLVMBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), is_signed)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,17 +286,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
|
||||
let newval = match (r_t_in, r_t_out) {
|
||||
(CastTy::Int(_), CastTy::Int(_)) => {
|
||||
let srcsz = ll_t_in.int_width();
|
||||
let dstsz = ll_t_out.int_width();
|
||||
if srcsz == dstsz {
|
||||
bcx.bitcast(llval, ll_t_out)
|
||||
} else if srcsz > dstsz {
|
||||
bcx.trunc(llval, ll_t_out)
|
||||
} else if signed {
|
||||
bcx.sext(llval, ll_t_out)
|
||||
} else {
|
||||
bcx.zext(llval, ll_t_out)
|
||||
}
|
||||
bcx.intcast(llval, ll_t_out, signed)
|
||||
}
|
||||
(CastTy::Float, CastTy::Float) => {
|
||||
let srcsz = ll_t_in.float_width();
|
||||
@ -439,7 +429,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
let discr_ty = rvalue.ty(&*self.mir, bcx.tcx()).unwrap();
|
||||
let discr_type = type_of::immediate_type_of(bcx.ccx, discr_ty);
|
||||
let discr = adt::trans_get_discr(&bcx, enum_ty, discr_lvalue.llval,
|
||||
Some(discr_type), true);
|
||||
discr_lvalue.alignment, Some(discr_type), true);
|
||||
(bcx, OperandRef {
|
||||
val: OperandValue::Immediate(discr),
|
||||
ty: discr_ty
|
||||
|
@ -1308,6 +1308,12 @@ extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) {
|
||||
return toRust(LLVMGetVisibility(V));
|
||||
}
|
||||
|
||||
// Oh hey, a binding that makes sense for once? (because LLVM’s own do not)
|
||||
extern "C" LLVMValueRef LLVMRustBuildIntCast(LLVMBuilderRef B, LLVMValueRef Val,
|
||||
LLVMTypeRef DestTy, bool isSigned) {
|
||||
return wrap(unwrap(B)->CreateIntCast(unwrap(Val), unwrap(DestTy), isSigned, ""));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustSetVisibility(LLVMValueRef V,
|
||||
LLVMRustVisibility RustVisibility) {
|
||||
LLVMSetVisibility(V, fromRust(RustVisibility));
|
||||
|
Loading…
Reference in New Issue
Block a user