Index: fold-const.c =================================================================== --- fold-const.c (revision 119398) +++ fold-const.c (working copy) @@ -2017,6 +2017,21 @@ return t; } +/* A subroutine of fold_convert_const handling conversions a FIXED_CST + to another fixed-point type. */ + +static tree +fold_convert_const_fixed_from_fixed (tree type, tree arg1) +{ + FIXED_VALUE_TYPE value; + tree t; + + fixed_convert (&value, TYPE_MODE (type), &TREE_FIXED_CST (arg1)); + t = build_fixed (type, value); + + return t; +} + /* Attempt to fold type conversion operation CODE of expression ARG1 to type TYPE. If no simplification can be done return NULL_TREE. */ @@ -2040,6 +2055,11 @@ if (TREE_CODE (arg1) == REAL_CST) return fold_convert_const_real_from_real (type, arg1); } + else if (TREE_CODE (type) == FIXED_POINT_TYPE) + { + if (TREE_CODE (arg1) == FIXED_CST) + return fold_convert_const_fixed_from_fixed (type, arg1); + } return NULL_TREE; } @@ -2137,6 +2157,15 @@ gcc_unreachable (); } + case FIXED_POINT_TYPE: + if (TREE_CODE (orig) == FIXED_CST) + { + tem = fold_convert_const (CONVERT_EXPR, type, arg); + if (tem != NULL_TREE) + return tem; + } + gcc_unreachable (); + case COMPLEX_TYPE: switch (TREE_CODE (orig)) { Index: c-typeck.c =================================================================== --- c-typeck.c (revision 119398) +++ c-typeck.c (working copy) @@ -605,9 +605,11 @@ code2 = TREE_CODE (t2); gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE - || code1 == REAL_TYPE || code1 == INTEGER_TYPE); + || code1 == FIXED_POINT_TYPE || code1 == REAL_TYPE + || code1 == INTEGER_TYPE); gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE - || code2 == REAL_TYPE || code2 == INTEGER_TYPE); + || code2 == FIXED_POINT_TYPE || code2 == REAL_TYPE + || code2 == INTEGER_TYPE); /* When one operand is a decimal float type, the other operand cannot be a generic float type or a complex type. We also disallow vector types @@ -682,6 +684,82 @@ return dfloat32_type_node; } + /* Deal with fixed-point types. */ + if (code1 == FIXED_POINT_TYPE || code2 == FIXED_POINT_TYPE) + { + unsigned int unsignedp = 0, satp = 0; + enum machine_mode m1, m2; + unsigned int fbit1, ibit1, fbit2, ibit2, max_fbit, max_ibit; + + m1 = TYPE_MODE (t1); + m2 = TYPE_MODE (t2); + + /* If one input type is saturating, the result type is saturating. */ + if (TYPE_SATURATING (t1) || TYPE_SATURATING (t2)) + satp = 1; + + /* If both types are unsigned, the result type is unsigned. + Otherwise, the result type is signed. */ + if (TYPE_UNSIGNED (t1) && TYPE_UNSIGNED (t2)) + unsignedp = 1; + + /* The result type is signed. */ + if (unsignedp == 0) + { + /* If the input type is unsigned, we need to convert to the + signed type. */ + if (code1 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t1)) + { + unsigned char mclass; + if (GET_MODE_CLASS (m1) == MODE_UFRACT) + mclass = MODE_FRACT; + else if (GET_MODE_CLASS (m1) == MODE_UACCUM) + mclass = MODE_ACCUM; + else + error ("machine mode is wrong"); + m1 = mode_for_size (GET_MODE_PRECISION (m1), mclass, 0); + } + if (code2 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t2)) + { + unsigned char mclass; + if (GET_MODE_CLASS (m2) == MODE_UFRACT) + mclass = MODE_FRACT; + else if (GET_MODE_CLASS (m2) == MODE_UACCUM) + mclass = MODE_ACCUM; + else + error ("machine mode is wrong"); + m2 = mode_for_size (GET_MODE_PRECISION (m2), mclass, 0); + } + } + + if (code1 == FIXED_POINT_TYPE) + { + fbit1 = GET_MODE_FBIT (m1); + ibit1 = GET_MODE_IBIT (m1); + } + else + { + fbit1 = 0; + ibit1 = TYPE_PRECISION (t1);; + } + + if (code2 == FIXED_POINT_TYPE) + { + fbit2 = GET_MODE_FBIT (m2); + ibit2 = GET_MODE_IBIT (m2); + } + else + { + fbit2 = 0; + ibit2 = TYPE_PRECISION (t2);; + } + + max_ibit = ibit1 >= ibit2 ? ibit1 : ibit2; + max_fbit = fbit1 >= fbit2 ? fbit1 : fbit2; + return c_common_fixed_point_type_for_size (max_ibit, max_fbit, unsignedp, + satp); + } + /* Both real or both integers; use the one with greater precision. */ if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) @@ -828,6 +906,14 @@ if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) return 0; + /* Allow saturating and not-saturating types be compatible. */ + if (ALL_FIXED_POINT_MODE_P (TYPE_MODE (t1)) + && ALL_FIXED_POINT_MODE_P (TYPE_MODE (t2)) + && TYPE_MODE (t1) == TYPE_MODE (t2) + && TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2) + && TYPE_SATURATING (t1) != TYPE_SATURATING (t2)) + return 1; + /* Allow for two different type nodes which have essentially the same definition. Note that we already checked for equality of the type qualifiers (just above). */ @@ -2954,7 +3040,7 @@ /* Report invalid types. */ - if (typecode != POINTER_TYPE + if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE && typecode != INTEGER_TYPE && typecode != REAL_TYPE) { if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) @@ -3000,7 +3086,9 @@ else inc = integer_one_node; - inc = convert (argtype, inc); + /* Don't convert integer_one_node to a fixed-point type. */ + if (TREE_CODE (argtype) != FIXED_POINT_TYPE) + inc = convert (argtype, inc); /* Complain about anything else that is not a true lvalue. */ if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR @@ -3940,9 +4028,11 @@ return convert (type, rhs); /* Arithmetic types all interconvert, and enum is treated like int. */ else if ((codel == INTEGER_TYPE || codel == REAL_TYPE + || codel == FIXED_POINT_TYPE || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE || codel == BOOLEAN_TYPE) && (coder == INTEGER_TYPE || coder == REAL_TYPE + || coder == FIXED_POINT_TYPE || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE || coder == BOOLEAN_TYPE)) return convert_and_check (type, rhs); @@ -4785,9 +4875,9 @@ /* Handle scalar types, including conversions. */ - if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE - || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE || code == COMPLEX_TYPE - || code == VECTOR_TYPE) + if (code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE + || code == POINTER_TYPE || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE + || code == COMPLEX_TYPE || code == VECTOR_TYPE) { if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE && (TREE_CODE (init) == STRING_CST Index: c-convert.c =================================================================== --- c-convert.c (revision 119382) +++ c-convert.c (working copy) @@ -106,6 +106,8 @@ return fold (convert_to_pointer (type, e)); if (code == REAL_TYPE) return fold (convert_to_real (type, e)); + if (code == FIXED_POINT_TYPE) + return fold (convert_to_fixed (type, e)); if (code == COMPLEX_TYPE) return fold (convert_to_complex (type, e)); if (code == VECTOR_TYPE) Index: fixed-value.h =================================================================== --- fixed-value.h (revision 119382) +++ fixed-value.h (working copy) @@ -45,6 +45,10 @@ /* In tree.c: wrap up a FIXED_VALUE_TYPE in a tree node. */ extern tree build_fixed (tree, FIXED_VALUE_TYPE); +/* Extend or truncate to a new mode. */ +extern void fixed_convert (FIXED_VALUE_TYPE *, enum machine_mode, + const FIXED_VALUE_TYPE *); + /* Compare two fixed-point objects for bitwise identity. */ extern bool fixed_identical (const FIXED_VALUE_TYPE *, const FIXED_VALUE_TYPE *); Index: fixed-value.c =================================================================== --- fixed-value.c (revision 119382) +++ fixed-value.c (working copy) @@ -122,7 +122,7 @@ lshift_double (f->data.low, f->data.high, (-GET_MODE_FBIT (f->mode)), 2 * HOST_BITS_PER_WIDE_INT, - &f->data.low, & f->data.high, + &f->data.low, &f->data.high, SIGNED_FIXED_POINT_MODE_P (f->mode)); f->data = double_int_ext (f->data, SIGNED_FIXED_POINT_MODE_P (f->mode) @@ -286,3 +286,31 @@ gcc_unreachable (); } } + +/* Extend or truncate to a new mode. */ + +void +fixed_convert (FIXED_VALUE_TYPE *f, enum machine_mode mode, + const FIXED_VALUE_TYPE *a) +{ + if (mode == a->mode) + *f = *a; + else + { + f->mode = mode; + /* If fbit is not the same, we need to left or right shift data. */ + if (GET_MODE_FBIT (f->mode) != GET_MODE_FBIT (a->mode)) + lshift_double (a->data.low, a->data.high, + GET_MODE_FBIT (f->mode) - GET_MODE_FBIT (a->mode), + 2 * HOST_BITS_PER_WIDE_INT, + &f->data.low, &f->data.high, + SIGNED_FIXED_POINT_MODE_P (f->mode)); + else + f->data = a->data; + f->data = double_int_ext (f->data, + SIGNED_FIXED_POINT_MODE_P (f->mode) + + GET_MODE_FBIT (f->mode) + + GET_MODE_IBIT (f->mode), + UNSIGNED_FIXED_POINT_MODE_P (f->mode)); + } +} Index: c-common.h =================================================================== --- c-common.h (revision 119398) +++ c-common.h (working copy) @@ -649,6 +649,8 @@ extern bool c_common_missing_argument (const char *opt, size_t code); extern tree c_common_type_for_mode (enum machine_mode, int); extern tree c_common_type_for_size (unsigned int, int); +extern tree c_common_fixed_point_type_for_size (unsigned int, unsigned int, + int, int); extern tree c_common_unsigned_type (tree); extern tree c_common_signed_type (tree); extern tree c_common_signed_or_unsigned_type (int, tree); Index: c-common.c =================================================================== --- c-common.c (revision 119428) +++ c-common.c (working copy) @@ -1795,6 +1795,33 @@ return 0; } +/* Return a fixed-point type that has at least IBIT ibits and FBIT fbits + that is unsigned if UNSIGNEDP is nonzero, otherwise signed; + and saturating if SATP is nonzero, otherwise not saturating. */ + +tree +c_common_fixed_point_type_for_size (unsigned int ibit, unsigned int fbit, + int unsignedp, int satp) +{ + enum machine_mode mode; + if (ibit == 0) + mode = unsignedp ? UQQmode : QQmode; + else + mode = unsignedp ? UHAmode : HAmode; + + for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) + if (GET_MODE_IBIT (mode) >= ibit && GET_MODE_FBIT (mode) >= fbit) + break; + + if (mode == VOIDmode) + { + error ("cannot find a common fixed-point mode to operate."); + return 0; + } + + return c_common_type_for_mode (mode, satp); +} + /* Used for communication between c_common_type_for_mode and c_register_builtin_type. */ static GTY(()) tree registered_builtin_types; Index: convert.h =================================================================== --- convert.h (revision 119382) +++ convert.h (working copy) @@ -24,6 +24,7 @@ extern tree convert_to_integer (tree, tree); extern tree convert_to_pointer (tree, tree); extern tree convert_to_real (tree, tree); +extern tree convert_to_fixed (tree, tree); extern tree convert_to_complex (tree, tree); extern tree convert_to_vector (tree, tree); Index: convert.c =================================================================== --- convert.c (revision 119382) +++ convert.c (working copy) @@ -821,3 +821,26 @@ return error_mark_node; } } + +/* Convert EXPR to some fixed-point type TYPE. + + EXPR must be fixed-point, float, integer, or enumeral; + in other cases error is called. */ + +tree +convert_to_fixed (tree type, tree expr) +{ + switch (TREE_CODE (TREE_TYPE (expr))) + { + case FIXED_POINT_TYPE: + { + enum tree_code code; + code = CONVERT_EXPR; + return fold_build1 (code, type, expr); + } + + default: + error ("aggregate value used where a fixed-point was expected"); + return error_mark_node; + } +}