use crate::prelude::*;
pub(crate) fn codegen_set_discriminant<'tcx>(
- fx: &mut FunctionCx<'_, 'tcx, impl Module>,
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
place: CPlace<'tcx>,
variant_index: VariantIdx,
) {
variants: _,
} => {
let ptr = place.place_field(fx, mir::Field::new(tag_field));
- let to = ty::ScalarInt::try_from_uint(
- layout
- .ty
- .discriminant_for_variant(fx.tcx, variant_index)
- .unwrap()
- .val,
- ptr.layout().size,
- )
- .unwrap();
+ let to = layout.ty.discriminant_for_variant(fx.tcx, variant_index).unwrap().val;
+ let to = if ptr.layout().abi.is_signed() {
+ ty::ScalarInt::try_from_int(
+ ptr.layout().size.sign_extend(to) as i128,
+ ptr.layout().size,
+ )
+ .unwrap()
+ } else {
+ ty::ScalarInt::try_from_uint(to, ptr.layout().size).unwrap()
+ };
let discr = CValue::const_val(fx, ptr.layout(), to);
ptr.write_cvalue(fx, discr);
}
Variants::Multiple {
tag: _,
tag_field,
- tag_encoding:
- TagEncoding::Niche {
- dataful_variant,
- ref niche_variants,
- niche_start,
- },
+ tag_encoding: TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
variants: _,
} => {
if variant_index != dataful_variant {
let niche = place.place_field(fx, mir::Field::new(tag_field));
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
- let niche_value = u128::from(niche_value).wrapping_add(niche_start);
- let niche_llval = CValue::const_val(fx, niche.layout(), niche_value.into());
+ let niche_value = ty::ScalarInt::try_from_uint(
+ u128::from(niche_value).wrapping_add(niche_start),
+ niche.layout().size,
+ )
+ .unwrap();
+ let niche_llval = CValue::const_val(fx, niche.layout(), niche_value);
niche.write_cvalue(fx, niche_llval);
}
}
}
pub(crate) fn codegen_get_discriminant<'tcx>(
- fx: &mut FunctionCx<'_, 'tcx, impl Module>,
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
value: CValue<'tcx>,
dest_layout: TyAndLayout<'tcx>,
) -> CValue<'tcx> {
let layout = value.layout();
if layout.abi == Abi::Uninhabited {
- return trap_unreachable_ret_value(
- fx,
- dest_layout,
- "[panic] Tried to get discriminant for uninhabited type.",
- );
+ let true_ = fx.bcx.ins().iconst(types::I32, 1);
+ fx.bcx.ins().trapnz(true_, TrapCode::UnreachableCodeReached);
+ // Return a dummy value
+ return CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout);
}
let (tag_scalar, tag_field, tag_encoding) = match &layout.variants {
.ty
.discriminant_for_variant(fx.tcx, *index)
.map_or(u128::from(index.as_u32()), |discr| discr.val);
- return CValue::const_val(fx, dest_layout, discr_val.into());
+ let discr_val = if dest_layout.abi.is_signed() {
+ ty::ScalarInt::try_from_int(
+ dest_layout.size.sign_extend(discr_val) as i128,
+ dest_layout.size,
+ )
+ .unwrap()
+ } else {
+ ty::ScalarInt::try_from_uint(discr_val, dest_layout.size).unwrap()
+ };
+ return CValue::const_val(fx, dest_layout, discr_val);
+ }
+ Variants::Multiple { tag, tag_field, tag_encoding, variants: _ } => {
+ (tag, *tag_field, tag_encoding)
}
- Variants::Multiple {
- tag,
- tag_field,
- tag_encoding,
- variants: _,
- } => (tag, *tag_field, tag_encoding),
};
let cast_to = fx.clif_type(dest_layout.ty).unwrap();
// Decode the discriminant (specifically if it's niche-encoded).
match *tag_encoding {
TagEncoding::Direct => {
- let signed = match tag_scalar.value {
+ let signed = match tag_scalar.primitive() {
Int(_, signed) => signed,
_ => false,
};
let val = clif_intcast(fx, tag, cast_to, signed);
CValue::by_val(val, dest_layout)
}
- TagEncoding::Niche {
- dataful_variant,
- ref niche_variants,
- niche_start,
- } => {
+ TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
// Rebase from niche values to discriminants, and check
// whether the result is in range for the niche variants.
let relative_discr = if niche_start == 0 {
tag
} else {
- // FIXME handle niche_start > i64::MAX
- fx.bcx
- .ins()
- .iadd_imm(tag, -i64::try_from(niche_start).unwrap())
+ let niche_start = match fx.bcx.func.dfg.value_type(tag) {
+ types::I128 => {
+ let lsb = fx.bcx.ins().iconst(types::I64, niche_start as u64 as i64);
+ let msb =
+ fx.bcx.ins().iconst(types::I64, (niche_start >> 64) as u64 as i64);
+ fx.bcx.ins().iconcat(lsb, msb)
+ }
+ ty => fx.bcx.ins().iconst(ty, niche_start as i64),
+ };
+ fx.bcx.ins().isub(tag, niche_start)
};
let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
let is_niche = {
} else {
clif_intcast(fx, relative_discr, cast_to, false)
};
- fx.bcx
- .ins()
- .iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
+ fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
};
- let dataful_variant = fx
- .bcx
- .ins()
- .iconst(cast_to, i64::from(dataful_variant.as_u32()));
+ let dataful_variant = fx.bcx.ins().iconst(cast_to, i64::from(dataful_variant.as_u32()));
let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant);
CValue::by_val(discr, dest_layout)
}