internal static void EmitNumericConversion(ILGenerator ilg, NativeType fromType, NativeType toType, bool @checked) { bool fromUnsigned = fromType.IsUnsigned(); switch (toType) { case NativeType.SByte: switch (fromType) { case NativeType.SByte: break; // NOP default: if (@checked) { ilg.Emit(fromUnsigned ? OpCodes.Conv_Ovf_I1_Un : OpCodes.Conv_Ovf_I1); } else { ilg.Emit(OpCodes.Conv_I1); } break; } break; case NativeType.Byte: switch (fromType) { case NativeType.Byte: break; // NOP default: if (@checked) { ilg.Emit(fromUnsigned ? OpCodes.Conv_Ovf_U1_Un : OpCodes.Conv_Ovf_U1); } else { ilg.Emit(OpCodes.Conv_U1); } break; } break; case NativeType.Int16: switch (fromType) { case NativeType.SByte: case NativeType.Byte: case NativeType.Int16: break; // NOP default: if (@checked) { ilg.Emit(fromUnsigned ? OpCodes.Conv_Ovf_I2_Un : OpCodes.Conv_Ovf_I2); } else { ilg.Emit(OpCodes.Conv_I2); } break; } break; case NativeType.Char: case NativeType.UInt16: switch (fromType) { case NativeType.Byte: case NativeType.UInt16: case NativeType.Char: break; // NOP default: if (@checked) { ilg.Emit(fromUnsigned ? OpCodes.Conv_Ovf_U2_Un : OpCodes.Conv_Ovf_U2); } else { ilg.Emit(OpCodes.Conv_U2); } break; } break; case NativeType.Int32: switch (fromType) { case NativeType.SByte: case NativeType.Byte: case NativeType.Int16: case NativeType.UInt16: case NativeType.Int32: case NativeType.Char: break; // NOP case NativeType.UInt32: if (@checked) { ilg.Emit(OpCodes.Conv_Ovf_I4_Un); } break; // NOP in unchecked default: if (@checked) { ilg.Emit(fromUnsigned ? OpCodes.Conv_Ovf_I4_Un : OpCodes.Conv_Ovf_I4); } else { ilg.Emit(OpCodes.Conv_I4); } break; } break; case NativeType.UInt32: switch (fromType) { case NativeType.Byte: case NativeType.UInt16: case NativeType.UInt32: case NativeType.Char: break; // NOP case NativeType.SByte: case NativeType.Int16: case NativeType.Int32: if (@checked) { ilg.Emit(OpCodes.Conv_Ovf_U4); } break; // NOP in unchecked default: if (@checked) { ilg.Emit(fromUnsigned ? OpCodes.Conv_Ovf_U4_Un : OpCodes.Conv_Ovf_U4); } else { ilg.Emit(OpCodes.Conv_U4); } break; } break; case NativeType.IntPtr: switch (fromType) { case NativeType.IntPtr: break; // NOP case NativeType.SByte: case NativeType.Int16: case NativeType.Int32: ilg.Emit(OpCodes.Conv_I); // potentially widening, so not NOP break; case NativeType.Byte: case NativeType.UInt16: case NativeType.Char: // Doesn't actually matter whether we sign extend, because // bit 32 can't be set in any of these types. ilg.Emit(OpCodes.Conv_U); // potentially widening, so not NOP break; case NativeType.UInt32: if (@checked) { ilg.Emit(OpCodes.Conv_Ovf_I_Un); } else { // Don't want to sign extend if this is a widening conversion. ilg.Emit(OpCodes.Conv_U); // potentially widening, so not NOP } break; default: if (@checked) { ilg.Emit(fromUnsigned ? OpCodes.Conv_Ovf_I_Un : OpCodes.Conv_Ovf_I); } else { ilg.Emit(OpCodes.Conv_I); } break; } break; case NativeType.UIntPtr: switch (fromType) { case NativeType.UIntPtr: break; // NOP case NativeType.Byte: case NativeType.UInt16: case NativeType.UInt32: case NativeType.Char: ilg.Emit(OpCodes.Conv_U); // potentially widening, so not NOP break; case NativeType.SByte: case NativeType.Int16: case NativeType.Int32: if (@checked) { ilg.Emit(OpCodes.Conv_Ovf_U); } else { ilg.Emit(OpCodes.Conv_I); // potentially widening, so not NOP } break; default: if (@checked) { ilg.Emit(fromUnsigned ? OpCodes.Conv_Ovf_U_Un : OpCodes.Conv_Ovf_U); } else { ilg.Emit(OpCodes.Conv_U); } break; } break; case NativeType.Int64: switch (fromType) { case NativeType.Int64: break; //NOP case NativeType.SByte: case NativeType.Int16: case NativeType.Int32: case NativeType.IntPtr: ilg.Emit(OpCodes.Conv_I8); // sign extend break; case NativeType.Byte: case NativeType.UInt16: case NativeType.UInt32: case NativeType.Char: ilg.Emit(OpCodes.Conv_U8); // 0 extend break; //case NativeType.Pointer: case NativeType.UIntPtr: if (@checked) { ilg.Emit(OpCodes.Conv_Ovf_I8_Un); } else { ilg.Emit(OpCodes.Conv_U8); // 0 extend if unchecked } break; case NativeType.UInt64: if (@checked) { ilg.Emit(OpCodes.Conv_Ovf_I8_Un); } break; // NOP in unchecked default: Debug.Assert(fromType.IsFloatingPoint()); if (@checked) { ilg.Emit(OpCodes.Conv_Ovf_I8); } else { ilg.Emit(OpCodes.Conv_I8); } break; } break; case NativeType.UInt64: switch (fromType) { case NativeType.UInt64: break; //NOP case NativeType.Byte: case NativeType.UInt16: case NativeType.UInt32: //case NativeType.Pointer: case NativeType.UIntPtr: case NativeType.Char: ilg.Emit(OpCodes.Conv_U8); // 0 extend break; case NativeType.SByte: case NativeType.Int16: case NativeType.Int32: case NativeType.IntPtr: if (@checked) { ilg.Emit(OpCodes.Conv_Ovf_U8); } else { ilg.Emit(OpCodes.Conv_I8); // sign extend if unchecked } break; case NativeType.Int64: if (@checked) { ilg.Emit(OpCodes.Conv_Ovf_U8); } break; // NOP in unchecked default: Debug.Assert(fromType.IsFloatingPoint()); if (@checked) { ilg.Emit(OpCodes.Conv_Ovf_U8); } else { ilg.Emit(OpCodes.Conv_U8); } break; } break; case NativeType.Single: switch (fromType) { case NativeType.UInt32: case NativeType.UInt64: ilg.Emit(OpCodes.Conv_R_Un); break; } ilg.Emit(OpCodes.Conv_R4); break; case NativeType.Double: switch (fromType) { case NativeType.UInt32: case NativeType.UInt64: ilg.Emit(OpCodes.Conv_R_Un); break; } ilg.Emit(OpCodes.Conv_R8); break; /* case NativeType.Pointer: * if (@checked) * { * switch (fromPredefTypeKind) * { * case NativeType.Byte: * case NativeType.UInt16: * case NativeType.UInt32: * ilg.Emit(OpCodes.Conv_U); * break; * case NativeType.UInt64: * ilg.Emit(OpCodes.Conv_Ovf_U_Un); * break; * case NativeType.SByte: * case NativeType.Int16: * case NativeType.Int32: * case NativeType.Int64: * ilg.Emit(OpCodes.Conv_Ovf_U); * break; * default: * throw ExceptionUtilities.UnexpectedValue(fromPredefTypeKind); * } * } * else * { * switch (fromPredefTypeKind) * { * case NativeType.Byte: * case NativeType.UInt16: * case NativeType.UInt32: * case NativeType.UInt64: * case NativeType.Int64: * ilg.Emit(OpCodes.Conv_U); * break; * case NativeType.SByte: * case NativeType.Int16: * case NativeType.Int32: * // This matches dev10. Presumably, we're using conv_i, * // rather than conv_u, to sign-extend the value. * ilg.Emit(OpCodes.Conv_I); * break; * default: * throw ExceptionUtilities.UnexpectedValue(fromPredefTypeKind); * } * } * break;*/ default: throw new InternalError(); } }