Index: tree.h =================================================================== --- tree.h (revision 118915) +++ tree.h (working copy) @@ -4188,6 +4188,11 @@ extern bool cst_and_fits_in_hwi (tree); extern tree num_ending_zeros (tree); +/* fixed_zerop (tree x) is nonzero if X is a fixed-point constant of + value 0. */ + +extern int fixed_zerop (tree); + /* staticp (tree x) is nonzero if X is a reference to data allocated at a fixed address in memory. Returns the outermost data. */ Index: tree.c =================================================================== --- tree.c (revision 118915) +++ tree.c (working copy) @@ -1413,6 +1413,15 @@ || integer_nonzerop (TREE_IMAGPART (expr))))); } +/* Return 1 if EXPR is the fixed-point constant zero. */ + +int +fixed_zerop (tree expr) +{ + return TREE_CODE (expr) == FIXED_CST + && double_int_zero_p (TREE_FIXED_CST (expr).data); +} + /* Return the power of two represented by a tree node known to be a power of two. */ Index: final.c =================================================================== --- final.c (revision 118838) +++ final.c (working copy) @@ -3252,13 +3252,7 @@ break; case CONST_FIXED: - if (CONST_FIXED_VALUE_HIGH (x)) - fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX, - CONST_FIXED_VALUE_HIGH (x), CONST_FIXED_VALUE_LOW (x)); - else if (CONST_FIXED_VALUE_LOW (x) < 0) - fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_FIXED_VALUE_LOW (x)); - else - fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_FIXED_VALUE_LOW (x)); + fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_FIXED_VALUE_LOW (x)); break; case PLUS: Index: fold-const.c =================================================================== --- fold-const.c (revision 118527) +++ fold-const.c (working copy) @@ -1077,6 +1077,10 @@ return tem; break; + case FIXED_CST: + tem = fold_negate_const (t, type); + return tem; + case COMPLEX_CST: { tree rpart = negate_expr (TREE_REALPART (t)); @@ -1656,6 +1660,41 @@ return t; } + if (TREE_CODE (arg1) == FIXED_CST) + { + FIXED_VALUE_TYPE f1; + FIXED_VALUE_TYPE f2; + FIXED_VALUE_TYPE result; + tree t, type; + + /* The following codes are handled by fixed_arithmetic. */ + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + f2 = TREE_FIXED_CST (arg2); + break; + + case LSHIFT_EXPR: + case RSHIFT_EXPR: + f2.data.high = TREE_INT_CST_HIGH (arg2); + f2.data.low = TREE_INT_CST_LOW (arg2); + f2.mode = SImode; + break; + + default: + return NULL_TREE; + } + + f1 = TREE_FIXED_CST (arg1); + type = TREE_TYPE (arg1); + fixed_arithmetic (&result, code, &f1, &f2); + t = build_fixed (type, result); + return t; + } + if (TREE_CODE (arg1) == COMPLEX_CST) { tree type = TREE_TYPE (arg1); @@ -8461,6 +8500,8 @@ constant but we can't do arithmetic on them. */ if ((TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) || (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST) + || (TREE_CODE (arg0) == FIXED_CST && TREE_CODE (arg1) == FIXED_CST) + || (TREE_CODE (arg0) == FIXED_CST && TREE_CODE (arg1) == INTEGER_CST) || (TREE_CODE (arg0) == COMPLEX_CST && TREE_CODE (arg1) == COMPLEX_CST) || (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)) { @@ -12608,6 +12649,10 @@ t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0))); break; + case FIXED_CST: + t = build_fixed (type, FIXED_VALUE_NEGATE (TREE_FIXED_CST (arg0))); + break; + default: gcc_unreachable (); } @@ -12741,6 +12786,13 @@ return constant_boolean_node (real_compare (code, c0, c1), type); } + if (TREE_CODE (op0) == FIXED_CST && TREE_CODE (op1) == FIXED_CST) + { + const FIXED_VALUE_TYPE *c0 = TREE_FIXED_CST_PTR (op0); + const FIXED_VALUE_TYPE *c1 = TREE_FIXED_CST_PTR (op1); + return constant_boolean_node (fixed_compare (code, c0, c1), type); + } + /* From here on we only handle LT, LE, GT, GE, EQ and NE. To compute GT, swap the arguments and do LT. Index: c-decl.c =================================================================== --- c-decl.c (revision 119029) +++ c-decl.c (working copy) @@ -7507,21 +7507,22 @@ { const char *str; if (i == RID_FRACT) - { - str = "_Fract"; + str = "_Fract"; + else + str = "_Accum"; + if (specs->complex_p) + error ("both % and %<%s%> in " + "declaration specifiers", str); + else if (i == RID_FRACT) specs->typespec_word = cts_fract; - } else - { - str = "_Accum"; specs->typespec_word = cts_accum; - } - if (!targetm.fixed_point_supported_p ()) - error ("fixed-point types not supported for this target"); - if (pedantic) - pedwarn ("ISO C does not support fixed-point types"); - return specs; } + if (!targetm.fixed_point_supported_p ()) + error ("fixed-point types not supported for this target"); + if (pedantic) + pedwarn ("ISO C does not support fixed-point types"); + return specs; default: /* ObjC reserved word "id", handled below. */ break; Index: c-typeck.c =================================================================== --- c-typeck.c (revision 118527) +++ c-typeck.c (working copy) @@ -2826,7 +2826,7 @@ is enough to prevent anybody from looking inside for associativity, but won't generate any code. */ if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE - || typecode == COMPLEX_TYPE + || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE || typecode == VECTOR_TYPE)) { error ("wrong type argument to unary plus"); @@ -2839,7 +2839,7 @@ case NEGATE_EXPR: if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE - || typecode == COMPLEX_TYPE + || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE || typecode == VECTOR_TYPE)) { error ("wrong type argument to unary minus"); @@ -2893,7 +2893,7 @@ break; case TRUTH_NOT_EXPR: - if (typecode != INTEGER_TYPE + if (typecode != INTEGER_TYPE && typecode != FIXED_POINT_TYPE && typecode != REAL_TYPE && typecode != POINTER_TYPE && typecode != COMPLEX_TYPE) { @@ -7887,12 +7887,14 @@ case EXACT_DIV_EXPR: /* Floating point division by zero is a legitimate way to obtain infinities and NaNs. */ - if (skip_evaluation == 0 && integer_zerop (op1)) + if (skip_evaluation == 0 && (integer_zerop (op1) || fixed_zerop (op1))) warning (OPT_Wdiv_by_zero, "division by zero"); if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE + || code0 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE) && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)) { enum tree_code tcode0 = code0, tcode1 = code1; @@ -7902,7 +7904,8 @@ if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE) tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1))); - if (!(tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE)) + if (!((tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE) + || (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE))) resultcode = RDIV_EXPR; else /* Although it would be tempting to shorten always here, that @@ -7969,7 +7972,8 @@ Also set SHORT_SHIFT if shifting rightward. */ case RSHIFT_EXPR: - if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE) + && code1 == INTEGER_TYPE) { if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0) { @@ -7997,7 +8001,8 @@ break; case LSHIFT_EXPR: - if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE) + && code1 == INTEGER_TYPE) { if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0) { @@ -8028,9 +8033,9 @@ but don't convert the args to int! */ build_type = integer_type_node; if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE - || code0 == COMPLEX_TYPE) + || code0 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE) && (code1 == INTEGER_TYPE || code1 == REAL_TYPE - || code1 == COMPLEX_TYPE)) + || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE)) short_compare = 1; else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) { @@ -8104,8 +8109,10 @@ case LT_EXPR: case GT_EXPR: build_type = integer_type_node; - if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) - && (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE + || code0 == FIXED_POINT_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == FIXED_POINT_TYPE)) short_compare = 1; else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) { @@ -8166,10 +8173,10 @@ } if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE - || code0 == VECTOR_TYPE) + || code0 == FIXED_POINT_TYPE || code0 == VECTOR_TYPE) && (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE - || code1 == VECTOR_TYPE)) + || code0 == FIXED_POINT_TYPE || code1 == VECTOR_TYPE)) { int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE); Index: emit-rtl.c =================================================================== --- emit-rtl.c (revision 118838) +++ emit-rtl.c (working copy) @@ -109,6 +109,9 @@ REAL_VALUE_TYPE dconstpi; REAL_VALUE_TYPE dconste; +/* Record fixed-point constant 0. */ +FIXED_VALUE_TYPE fconst0[(int) MAX_MACHINE_MODE]; + /* All references to the following fixed hard registers go through these unique rtl objects. On machines where the frame-pointer and arg-pointer are the same register, they use the same unique object. @@ -5320,6 +5323,50 @@ const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1); } + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FRACT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + fconst0[mode].data.high = 0; + fconst0[mode].data.low = 0; + fconst0[mode].mode = mode; + const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE ( + fconst0[mode], mode); + } + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_UFRACT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + fconst0[mode].data.high = 0; + fconst0[mode].data.low = 0; + fconst0[mode].mode = mode; + const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE ( + fconst0[mode], mode); + } + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_ACCUM); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + fconst0[mode].data.high = 0; + fconst0[mode].data.low = 0; + fconst0[mode].mode = mode; + const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE ( + fconst0[mode], mode); + } + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_UACCUM); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + fconst0[mode].data.high = 0; + fconst0[mode].data.low = 0; + fconst0[mode].mode = mode; + const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE ( + fconst0[mode], mode); + } + for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i) if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC) const_tiny_rtx[0][i] = const0_rtx; Index: fixed_value.h =================================================================== --- fixed_value.h (revision 119029) +++ fixed_value.h (working copy) @@ -31,6 +31,9 @@ #define FIXED_VALUE_TYPE struct fixed_value +/* Constant fixed-point values 0. */ +extern FIXED_VALUE_TYPE fconst0[]; + /* Return a CONST_FIXED with value R and mode M. */ #define CONST_FIXED_FROM_FIXED_VALUE(r, m) \ const_fixed_from_fixed_value (r, m) @@ -53,4 +56,18 @@ /* Render F as a decimal floating point constant. */ extern void fixed_to_decimal (char *str, const FIXED_VALUE_TYPE *, size_t); +/* Binary or unary arithmetic on tree_code. */ +extern void fixed_arithmetic (FIXED_VALUE_TYPE *, int, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *); + +/* Compare fixed-point values by tree_code. */ +extern bool fixed_compare (int, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *); + +extern FIXED_VALUE_TYPE fixed_arithmetic2 (int, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *); + +#define FIXED_VALUE_NEGATE(X) \ + fixed_arithmetic2 (NEGATE_EXPR, &(X), NULL) + #endif /* GCC_FIXED_VALUE_H */ Index: fixed_value.c =================================================================== --- fixed_value.c (revision 119029) +++ fixed_value.c (working copy) @@ -27,6 +27,15 @@ #include "fixed_value.h" #include "real.h" +static void do_fixed_add (FIXED_VALUE_TYPE *, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *, int); +static void do_fixed_multiply (FIXED_VALUE_TYPE *, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *); +static void do_fixed_divide (FIXED_VALUE_TYPE *, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *); +static void do_fixed_shift (FIXED_VALUE_TYPE *, const FIXED_VALUE_TYPE *, + const FIXED_VALUE_TYPE *, int); + /* Compare two fixed objects for bitwise identity. */ bool @@ -61,6 +70,11 @@ real_from_string (&base_value, base_string); real_arithmetic (&fixed_value, MULT_EXPR, &real_value, &base_value); real_to_integer2 (&f->data.low, &f->data.high, &fixed_value); + 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)); } /* Render F as a decimal floating point constant. */ @@ -78,3 +92,197 @@ real_arithmetic (&fixed_value, RDIV_EXPR, &real_value, &base_value); real_to_decimal (str, &fixed_value, buf_size, 0, 1); } + +/* Calculate F = A + (SUBTRACT_P ? -B : B). */ + +static void +do_fixed_add (FIXED_VALUE_TYPE *f, const FIXED_VALUE_TYPE *a, + const FIXED_VALUE_TYPE *b, int subtract_p) +{ + f->mode = a->mode; + f->data = double_int_add (a->data, + subtract_p ? double_int_neg (b->data) : b->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)); +} + +/* Calculate F = A * B. */ + +static void +do_fixed_multiply (FIXED_VALUE_TYPE *f, const FIXED_VALUE_TYPE *a, + const FIXED_VALUE_TYPE *b) +{ + f->mode = a->mode; + if (GET_MODE_PRECISION (f->mode) <= HOST_BITS_PER_WIDE_INT) + { + f->data = double_int_mul (a->data, b->data); + 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, + SIGNED_FIXED_POINT_MODE_P (f->mode)); + 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)); + } + else + { + /* FIXME */ + printf ("ERROR\n"); + } +} + +/* Calculate F = A / B. */ + +static void +do_fixed_divide (FIXED_VALUE_TYPE *f, const FIXED_VALUE_TYPE *a, + const FIXED_VALUE_TYPE *b) +{ + f->mode = a->mode; + if (GET_MODE_PRECISION (f->mode) <= HOST_BITS_PER_WIDE_INT) + { + lshift_double (a->data.low, a->data.high, + GET_MODE_FBIT (f->mode), + 2 * HOST_BITS_PER_WIDE_INT, + &f->data.low, & f->data.high, + SIGNED_FIXED_POINT_MODE_P (f->mode)); + f->data = double_int_div (f->data, b->data, + UNSIGNED_FIXED_POINT_MODE_P (f->mode), + TRUNC_DIV_EXPR); + 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)); + } + else + { + /* FIXME */ + printf ("ERROR\n"); + } +} + +/* Calculate F = A << B if LEFT_P. Otherwies, F = A >> B. */ + +static void +do_fixed_shift (FIXED_VALUE_TYPE *f, const FIXED_VALUE_TYPE *a, + const FIXED_VALUE_TYPE *b, int left_p) +{ + f->mode = a->mode; + lshift_double (a->data.low, a->data.high, + left_p ? b->data.low : (-b->data.low), + 2 * HOST_BITS_PER_WIDE_INT, + &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) + + GET_MODE_FBIT (f->mode) + + GET_MODE_IBIT (f->mode), + UNSIGNED_FIXED_POINT_MODE_P (f->mode)); +} + +/* Perform the binary or unary operation described by CODE. + For a unary operation, leave OP1 NULL. This function returns + true if the result may be inexact due to loss of precision. */ + +void +fixed_arithmetic (FIXED_VALUE_TYPE *f, int icode, const FIXED_VALUE_TYPE *op0, + const FIXED_VALUE_TYPE *op1) +{ + switch (icode) + { + case NEGATE_EXPR: + f->mode = op0->mode; + f->data = double_int_neg (op0->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)); + break; + + case PLUS_EXPR: + do_fixed_add (f, op0, op1, 0); + break; + + case MINUS_EXPR: + do_fixed_add (f, op0, op1, 1); + break; + + case MULT_EXPR: + do_fixed_multiply (f, op0, op1); + break; + + case TRUNC_DIV_EXPR: + do_fixed_divide (f, op0, op1); + break; + + case LSHIFT_EXPR: + do_fixed_shift (f, op0, op1, 1); + break; + + case RSHIFT_EXPR: + do_fixed_shift (f, op0, op1, 0); + break; + + default: + gcc_unreachable (); + } +} + +FIXED_VALUE_TYPE +fixed_arithmetic2 (int icode, const FIXED_VALUE_TYPE *op0, + const FIXED_VALUE_TYPE *op1) +{ + FIXED_VALUE_TYPE f; + fixed_arithmetic (&f, icode, op0, op1); + return f; +} + +/* Compare fixed-point values by tree_code. */ + +bool +fixed_compare (int icode, const FIXED_VALUE_TYPE *op0, + const FIXED_VALUE_TYPE *op1) +{ + enum tree_code code = icode; + + switch (code) + { + case NE_EXPR: + return op0->mode != op1->mode + || !double_int_equal_p (op0->data, op1->data); + + case EQ_EXPR: + return op0->mode == op1->mode + && double_int_equal_p (op0->data, op1->data); + + case LT_EXPR: + return op0->mode == op1->mode + && double_int_cmp (op0->data, op1->data, + UNSIGNED_FIXED_POINT_MODE_P (op0->mode)) == -1; + + case LE_EXPR: + return op0->mode == op1->mode + && double_int_cmp (op0->data, op1->data, + UNSIGNED_FIXED_POINT_MODE_P (op0->mode)) != 1; + + case GT_EXPR: + return op0->mode == op1->mode + && double_int_cmp (op0->data, op1->data, + UNSIGNED_FIXED_POINT_MODE_P (op0->mode)) == 1; + + case GE_EXPR: + return op0->mode == op1->mode + && double_int_cmp (op0->data, op1->data, + UNSIGNED_FIXED_POINT_MODE_P (op0->mode)) != -1; + + default: + gcc_unreachable (); + } +} Index: c-common.c =================================================================== --- c-common.c (revision 119029) +++ c-common.c (working copy) @@ -2194,7 +2194,8 @@ the second arg is 0. */ if (TREE_CONSTANT (primop0) - && !integer_zerop (primop1) && !real_zerop (primop1)) + && !integer_zerop (primop1) && !real_zerop (primop1) + && !fixed_zerop (primop1)) { tree tem = primop0; int temi = unsignedp0; @@ -2635,6 +2636,12 @@ ? truthvalue_true_node : truthvalue_false_node; + case FIXED_CST: + return fixed_compare (NE_EXPR, &TREE_FIXED_CST (expr), + &fconst0[TYPE_MODE (TREE_TYPE (expr))]) + ? truthvalue_true_node + : truthvalue_false_node; + case FUNCTION_DECL: expr = build_unary_op (ADDR_EXPR, expr, 0); /* Fall through. */