mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-30 20:44:34 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			156 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			156 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! Various number casting functions
 | |
| 
 | |
| use crate::prelude::*;
 | |
| 
 | |
| pub(crate) fn clif_intcast(
 | |
|     fx: &mut FunctionCx<'_, '_, '_>,
 | |
|     val: Value,
 | |
|     to: Type,
 | |
|     signed: bool,
 | |
| ) -> Value {
 | |
|     let from = fx.bcx.func.dfg.value_type(val);
 | |
|     match (from, to) {
 | |
|         // equal
 | |
|         (_, _) if from == to => val,
 | |
| 
 | |
|         // extend
 | |
|         (_, _) if to.wider_or_equal(from) => {
 | |
|             if signed {
 | |
|                 fx.bcx.ins().sextend(to, val)
 | |
|             } else {
 | |
|                 fx.bcx.ins().uextend(to, val)
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // reduce
 | |
|         (_, _) => fx.bcx.ins().ireduce(to, val),
 | |
|     }
 | |
| }
 | |
| 
 | |
| pub(crate) fn clif_int_or_float_cast(
 | |
|     fx: &mut FunctionCx<'_, '_, '_>,
 | |
|     from: Value,
 | |
|     from_signed: bool,
 | |
|     to_ty: Type,
 | |
|     to_signed: bool,
 | |
| ) -> Value {
 | |
|     let from_ty = fx.bcx.func.dfg.value_type(from);
 | |
| 
 | |
|     if from_ty.is_int() && to_ty.is_int() {
 | |
|         // int-like -> int-like
 | |
|         clif_intcast(
 | |
|             fx,
 | |
|             from,
 | |
|             to_ty,
 | |
|             // This is correct as either from_signed == to_signed (=> this is trivially correct)
 | |
|             // Or from_clif_ty == to_clif_ty, which means this is a no-op.
 | |
|             from_signed,
 | |
|         )
 | |
|     } else if from_ty.is_int() && to_ty.is_float() {
 | |
|         if from_ty == types::I128 {
 | |
|             // _______ss__f_
 | |
|             // __float  tisf: i128 -> f32
 | |
|             // __float  tidf: i128 -> f64
 | |
|             // __floatuntisf: u128 -> f32
 | |
|             // __floatuntidf: u128 -> f64
 | |
| 
 | |
|             let name = format!(
 | |
|                 "__float{sign}ti{flt}f",
 | |
|                 sign = if from_signed { "" } else { "un" },
 | |
|                 flt = match to_ty {
 | |
|                     types::F32 => "s",
 | |
|                     types::F64 => "d",
 | |
|                     _ => unreachable!("{:?}", to_ty),
 | |
|                 },
 | |
|             );
 | |
| 
 | |
|             return fx.lib_call(
 | |
|                 &name,
 | |
|                 vec![AbiParam::new(types::I128)],
 | |
|                 vec![AbiParam::new(to_ty)],
 | |
|                 &[from],
 | |
|             )[0];
 | |
|         }
 | |
| 
 | |
|         // int-like -> float
 | |
|         if from_signed {
 | |
|             fx.bcx.ins().fcvt_from_sint(to_ty, from)
 | |
|         } else {
 | |
|             fx.bcx.ins().fcvt_from_uint(to_ty, from)
 | |
|         }
 | |
|     } else if from_ty.is_float() && to_ty.is_int() {
 | |
|         let val = if to_ty == types::I128 {
 | |
|             // _____sssf___
 | |
|             // __fix   sfti: f32 -> i128
 | |
|             // __fix   dfti: f64 -> i128
 | |
|             // __fixunssfti: f32 -> u128
 | |
|             // __fixunsdfti: f64 -> u128
 | |
| 
 | |
|             let name = format!(
 | |
|                 "__fix{sign}{flt}fti",
 | |
|                 sign = if to_signed { "" } else { "uns" },
 | |
|                 flt = match from_ty {
 | |
|                     types::F32 => "s",
 | |
|                     types::F64 => "d",
 | |
|                     _ => unreachable!("{:?}", to_ty),
 | |
|                 },
 | |
|             );
 | |
| 
 | |
|             fx.lib_call(
 | |
|                 &name,
 | |
|                 vec![AbiParam::new(from_ty)],
 | |
|                 vec![AbiParam::new(types::I128)],
 | |
|                 &[from],
 | |
|             )[0]
 | |
|         } else if to_ty == types::I8 || to_ty == types::I16 {
 | |
|             // FIXME implement fcvt_to_*int_sat.i8/i16
 | |
|             let val = if to_signed {
 | |
|                 fx.bcx.ins().fcvt_to_sint_sat(types::I32, from)
 | |
|             } else {
 | |
|                 fx.bcx.ins().fcvt_to_uint_sat(types::I32, from)
 | |
|             };
 | |
|             let (min, max) = match (to_ty, to_signed) {
 | |
|                 (types::I8, false) => (0, i64::from(u8::MAX)),
 | |
|                 (types::I16, false) => (0, i64::from(u16::MAX)),
 | |
|                 (types::I8, true) => (i64::from(i8::MIN as u32), i64::from(i8::MAX as u32)),
 | |
|                 (types::I16, true) => (i64::from(i16::MIN as u32), i64::from(i16::MAX as u32)),
 | |
|                 _ => unreachable!(),
 | |
|             };
 | |
|             let min_val = fx.bcx.ins().iconst(types::I32, min);
 | |
|             let max_val = fx.bcx.ins().iconst(types::I32, max);
 | |
| 
 | |
|             let val = if to_signed {
 | |
|                 let has_underflow = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, val, min);
 | |
|                 let has_overflow = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, val, max);
 | |
|                 let bottom_capped = fx.bcx.ins().select(has_underflow, min_val, val);
 | |
|                 fx.bcx.ins().select(has_overflow, max_val, bottom_capped)
 | |
|             } else {
 | |
|                 let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, val, max);
 | |
|                 fx.bcx.ins().select(has_overflow, max_val, val)
 | |
|             };
 | |
|             fx.bcx.ins().ireduce(to_ty, val)
 | |
|         } else if to_signed {
 | |
|             fx.bcx.ins().fcvt_to_sint_sat(to_ty, from)
 | |
|         } else {
 | |
|             fx.bcx.ins().fcvt_to_uint_sat(to_ty, from)
 | |
|         };
 | |
| 
 | |
|         if let Some(false) = fx.tcx.sess.opts.unstable_opts.saturating_float_casts {
 | |
|             return val;
 | |
|         }
 | |
| 
 | |
|         let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from);
 | |
|         let zero = type_zero_value(&mut fx.bcx, to_ty);
 | |
|         fx.bcx.ins().select(is_not_nan, val, zero)
 | |
|     } else if from_ty.is_float() && to_ty.is_float() {
 | |
|         // float -> float
 | |
|         match (from_ty, to_ty) {
 | |
|             (types::F32, types::F64) => fx.bcx.ins().fpromote(types::F64, from),
 | |
|             (types::F64, types::F32) => fx.bcx.ins().fdemote(types::F32, from),
 | |
|             _ => from,
 | |
|         }
 | |
|     } else {
 | |
|         unreachable!("cast value from {:?} to {:?}", from_ty, to_ty);
 | |
|     }
 | |
| }
 | 
