public static Expr SignedIntegralToArith(Expr expr, ExprType type) {
ExprTypeKind from = expr.Type.Kind;
ExprTypeKind to = type.Kind;
Env env = expr.Env;
switch (from) {
case ExprTypeKind.CHAR:
switch (to) {
case ExprTypeKind.SHORT:
case ExprTypeKind.USHORT:
return new TypeCast(TypeCastType.INT8_TO_INT16, expr, type);
case ExprTypeKind.LONG:
case ExprTypeKind.ULONG:
return new TypeCast(TypeCastType.INT8_TO_INT32, expr, type);
case ExprTypeKind.UCHAR:
return new TypeCast(TypeCastType.NOP, expr, type);
case ExprTypeKind.FLOAT:
// char -> long -> float
return new TypeCast(TypeCastType.INT32_TO_FLOAT, new TypeCast(TypeCastType.INT8_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);
case ExprTypeKind.DOUBLE:
// char -> long -> double
return new TypeCast(TypeCastType.INT32_TO_DOUBLE, new TypeCast(TypeCastType.INT8_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);
case ExprTypeKind.VOID:
case ExprTypeKind.POINTER:
case ExprTypeKind.FUNCTION:
case ExprTypeKind.ARRAY:
case ExprTypeKind.INCOMPLETE_ARRAY:
case ExprTypeKind.STRUCT_OR_UNION:
case ExprTypeKind.CHAR:
default:
throw new InvalidProgramException($"Cannot cast from {from} to {to}");
}
case ExprTypeKind.SHORT:
switch (to) {
case ExprTypeKind.CHAR:
case ExprTypeKind.UCHAR:
return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type);
case ExprTypeKind.USHORT:
return new TypeCast(TypeCastType.NOP, expr, type);
case ExprTypeKind.LONG:
case ExprTypeKind.ULONG:
return new TypeCast(TypeCastType.INT16_TO_INT32, expr, type);
case ExprTypeKind.FLOAT:
// short -> long -> float
return new TypeCast(TypeCastType.INT32_TO_FLOAT, new TypeCast(TypeCastType.INT16_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);
case ExprTypeKind.DOUBLE:
// short -> long -> double
return new TypeCast(TypeCastType.INT32_TO_DOUBLE, new TypeCast(TypeCastType.INT16_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);
case ExprTypeKind.VOID:
case ExprTypeKind.SHORT:
case ExprTypeKind.POINTER:
case ExprTypeKind.FUNCTION:
case ExprTypeKind.ARRAY:
case ExprTypeKind.INCOMPLETE_ARRAY:
case ExprTypeKind.STRUCT_OR_UNION:
default:
throw new InvalidProgramException($"Cannot cast from {from} to {to}");
}
case ExprTypeKind.LONG:
switch (to) {
case ExprTypeKind.CHAR:
if (expr.IsConstExpr) {
return new ConstChar((SByte)((ConstLong)expr).Value, env);
}
return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type);
case ExprTypeKind.UCHAR:
if (expr.IsConstExpr) {
return new ConstUChar((Byte)((ConstLong)expr).Value, env);
}
return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type);
case ExprTypeKind.SHORT:
if (expr.IsConstExpr) {
return new ConstShort((Int16)((ConstLong)expr).Value, env);
}
return new TypeCast(TypeCastType.PRESERVE_INT16, expr, type);
case ExprTypeKind.USHORT:
if (expr.IsConstExpr) {
return new ConstUShort((UInt16)((ConstLong)expr).Value, env);
}
return new TypeCast(TypeCastType.PRESERVE_INT16, expr, type);
case ExprTypeKind.ULONG:
if (expr.IsConstExpr) {
return new ConstULong((UInt32)((ConstLong)expr).Value, env);
}
return new TypeCast(TypeCastType.NOP, expr, type);
case ExprTypeKind.FLOAT:
if (expr.IsConstExpr) {
return new ConstFloat(((ConstLong)expr).Value, env);
}
return new TypeCast(TypeCastType.INT32_TO_FLOAT, expr, type);
case ExprTypeKind.DOUBLE:
if (expr.IsConstExpr) {
return new ConstDouble(((ConstLong)expr).Value, env);
}
return new TypeCast(TypeCastType.INT32_TO_DOUBLE, expr, type);
case ExprTypeKind.VOID:
case ExprTypeKind.LONG:
case ExprTypeKind.POINTER:
case ExprTypeKind.FUNCTION:
case ExprTypeKind.ARRAY:
case ExprTypeKind.INCOMPLETE_ARRAY:
case ExprTypeKind.STRUCT_OR_UNION:
default:
throw new InvalidProgramException($"Cannot cast from {from} to {to}");
}
default:
throw new InvalidProgramException();
}
}