#include "config.h"
#include "system.h"
#include "tree.h"
#include "flags.h"
#include "convert.h"
#include "toplev.h"
tree
convert_to_pointer (type, expr)
tree type, expr;
{
if (integer_zerop (expr))
{
expr = build_int_2 (0, 0);
TREE_TYPE (expr) = type;
return expr;
}
switch (TREE_CODE (TREE_TYPE (expr)))
{
case POINTER_TYPE:
case REFERENCE_TYPE:
return build1 (NOP_EXPR, type, expr);
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
case CHAR_TYPE:
if (TYPE_PRECISION (TREE_TYPE (expr)) == POINTER_SIZE)
return build1 (CONVERT_EXPR, type, expr);
return
convert_to_pointer (type,
convert (type_for_size (POINTER_SIZE, 0), expr));
default:
error ("cannot convert to a pointer type");
return convert_to_pointer (type, integer_zero_node);
}
}
tree
convert_to_real (type, expr)
tree type, expr;
{
switch (TREE_CODE (TREE_TYPE (expr)))
{
case REAL_TYPE:
return build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
type, expr);
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
case CHAR_TYPE:
return build1 (FLOAT_EXPR, type, expr);
case COMPLEX_TYPE:
return convert (type,
fold (build1 (REALPART_EXPR,
TREE_TYPE (TREE_TYPE (expr)), expr)));
case POINTER_TYPE:
case REFERENCE_TYPE:
error ("pointer value used where a floating point value was expected");
return convert_to_real (type, integer_zero_node);
default:
error ("aggregate value used where a float was expected");
return convert_to_real (type, integer_zero_node);
}
}
tree
convert_to_integer (type, expr)
tree type, expr;
{
enum tree_code ex_form = TREE_CODE (expr);
tree intype = TREE_TYPE (expr);
unsigned int inprec = TYPE_PRECISION (intype);
unsigned int outprec = TYPE_PRECISION (type);
if (!COMPLETE_TYPE_P (type))
{
error ("conversion to incomplete type");
return error_mark_node;
}
switch (TREE_CODE (intype))
{
case POINTER_TYPE:
case REFERENCE_TYPE:
if (integer_zerop (expr))
expr = integer_zero_node;
else
expr = fold (build1 (CONVERT_EXPR,
type_for_size (POINTER_SIZE, 0), expr));
return convert_to_integer (type, expr);
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
case CHAR_TYPE:
if (TREE_CODE_CLASS (ex_form) == '<')
{
TREE_TYPE (expr) = type;
return expr;
}
else if (ex_form == TRUTH_AND_EXPR || ex_form == TRUTH_ANDIF_EXPR
|| ex_form == TRUTH_OR_EXPR || ex_form == TRUTH_ORIF_EXPR
|| ex_form == TRUTH_XOR_EXPR)
{
TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0));
TREE_OPERAND (expr, 1) = convert (type, TREE_OPERAND (expr, 1));
TREE_TYPE (expr) = type;
return expr;
}
else if (ex_form == TRUTH_NOT_EXPR)
{
TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0));
TREE_TYPE (expr) = type;
return expr;
}
else if (outprec >= inprec)
return build1 (NOP_EXPR, type, expr);
else if (TREE_CODE (type) == ENUMERAL_TYPE
|| outprec != GET_MODE_BITSIZE (TYPE_MODE (type)))
return build1 (NOP_EXPR, type,
convert (type_for_mode (TYPE_MODE (type),
TREE_UNSIGNED (type)),
expr));
switch (ex_form)
{
case RSHIFT_EXPR:
if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
&& tree_int_cst_lt (TREE_OPERAND (expr, 1),
convert (TREE_TYPE (TREE_OPERAND (expr, 1)),
integer_one_node)))
goto trunc1;
break;
case LSHIFT_EXPR:
if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
&& tree_int_cst_sgn (TREE_OPERAND (expr, 1)) >= 0
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
{
if (tree_int_cst_lt (TREE_OPERAND (expr, 1), TYPE_SIZE (type)))
goto trunc1;
else
{
tree t = convert_to_integer (type, integer_zero_node);
if (TREE_SIDE_EFFECTS (expr))
return build (COMPOUND_EXPR, type, expr, t);
else
return t;
}
}
break;
case MAX_EXPR:
case MIN_EXPR:
case MULT_EXPR:
{
tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type);
tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
if (outprec >= TYPE_PRECISION (TREE_TYPE (arg0))
&& outprec >= TYPE_PRECISION (TREE_TYPE (arg1))
&& (TREE_UNSIGNED (TREE_TYPE (arg0))
== TREE_UNSIGNED (TREE_TYPE (arg1))))
goto trunc1;
break;
}
case PLUS_EXPR:
case MINUS_EXPR:
case BIT_AND_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case BIT_ANDTC_EXPR:
trunc1:
{
tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type);
tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
if (outprec >= BITS_PER_WORD
|| TRULY_NOOP_TRUNCATION (outprec, inprec)
|| inprec > TYPE_PRECISION (TREE_TYPE (arg0))
|| inprec > TYPE_PRECISION (TREE_TYPE (arg1)))
{
tree typex = type;
if (TREE_CODE (typex) == ENUMERAL_TYPE)
typex = type_for_size (TYPE_PRECISION (typex),
TREE_UNSIGNED (typex));
if (TYPE_PRECISION (typex) != inprec)
{
typex = ((TREE_UNSIGNED (TREE_TYPE (expr))
|| (TREE_UNSIGNED (TREE_TYPE (arg0))
&& TREE_UNSIGNED (TREE_TYPE (arg1))))
? unsigned_type (typex) : signed_type (typex));
return convert (type,
fold (build (ex_form, typex,
convert (typex, arg0),
convert (typex, arg1),
0)));
}
}
}
break;
case NEGATE_EXPR:
case BIT_NOT_EXPR:
{
tree typex = type;
if (TREE_CODE (typex) == ENUMERAL_TYPE)
typex = type_for_size (TYPE_PRECISION (typex),
TREE_UNSIGNED (typex));
if (TYPE_PRECISION (typex) != inprec)
{
typex = (TREE_UNSIGNED (TREE_TYPE (expr))
? unsigned_type (typex) : signed_type (typex));
return convert (type,
fold (build1 (ex_form, typex,
convert (typex,
TREE_OPERAND (expr, 0)))));
}
}
case NOP_EXPR:
return convert (type, get_unwidened (TREE_OPERAND (expr, 0), type));
case COND_EXPR:
return fold (build (COND_EXPR, type, TREE_OPERAND (expr, 0),
convert (type, TREE_OPERAND (expr, 1)),
convert (type, TREE_OPERAND (expr, 2))));
default:
break;
}
return build1 (NOP_EXPR, type, expr);
case REAL_TYPE:
return build1 (FIX_TRUNC_EXPR, type, expr);
case COMPLEX_TYPE:
return convert (type,
fold (build1 (REALPART_EXPR,
TREE_TYPE (TREE_TYPE (expr)), expr)));
case VECTOR_TYPE:
if (GET_MODE_SIZE (TYPE_MODE (type))
!= GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))))
{
error ("can't convert between vector values of different size");
return error_mark_node;
}
return build1 (NOP_EXPR, type, expr);
default:
error ("aggregate value used where an integer was expected");
return convert (type, integer_zero_node);
}
}
tree
convert_to_complex (type, expr)
tree type, expr;
{
tree subtype = TREE_TYPE (type);
switch (TREE_CODE (TREE_TYPE (expr)))
{
case REAL_TYPE:
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
case CHAR_TYPE:
return build (COMPLEX_EXPR, type, convert (subtype, expr),
convert (subtype, integer_zero_node));
case COMPLEX_TYPE:
{
tree elt_type = TREE_TYPE (TREE_TYPE (expr));
if (TYPE_MAIN_VARIANT (elt_type) == TYPE_MAIN_VARIANT (subtype))
return expr;
else if (TREE_CODE (expr) == COMPLEX_EXPR)
return fold (build (COMPLEX_EXPR,
type,
convert (subtype, TREE_OPERAND (expr, 0)),
convert (subtype, TREE_OPERAND (expr, 1))));
else
{
expr = save_expr (expr);
return
fold (build (COMPLEX_EXPR,
type, convert (subtype,
fold (build1 (REALPART_EXPR,
TREE_TYPE (TREE_TYPE (expr)),
expr))),
convert (subtype,
fold (build1 (IMAGPART_EXPR,
TREE_TYPE (TREE_TYPE (expr)),
expr)))));
}
}
case POINTER_TYPE:
case REFERENCE_TYPE:
error ("pointer value used where a complex was expected");
return convert_to_complex (type, integer_zero_node);
default:
error ("aggregate value used where a complex was expected");
return convert_to_complex (type, integer_zero_node);
}
}
tree
convert_to_vector (type, expr)
tree type, expr;
{
switch (TREE_CODE (TREE_TYPE (expr)))
{
case INTEGER_TYPE:
case VECTOR_TYPE:
if (GET_MODE_SIZE (TYPE_MODE (type))
!= GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))))
{
error ("can't convert between vector values of different size");
return error_mark_node;
}
return build1 (NOP_EXPR, type, expr);
default:
error ("can't convert value to a vector");
return convert_to_vector (type, integer_zero_node);
}
}