diff options
author | Chao-ying Fu <fu@mips.com> | 2007-08-08 22:29:12 +0000 |
---|---|---|
committer | Chao-ying Fu <chaoyingfu@gcc.gnu.org> | 2007-08-08 22:29:12 +0000 |
commit | 325217edf0332af8e5e52a32eb9b3cd862646375 (patch) | |
tree | 844eff658d57c57ce2ecfa8982a6e96a0c7c3392 /gcc/fold-const.c | |
parent | ad10fdc2b781c481fe7793dc9eb735d0bb493921 (diff) | |
download | gcc-325217edf0332af8e5e52a32eb9b3cd862646375.zip gcc-325217edf0332af8e5e52a32eb9b3cd862646375.tar.gz gcc-325217edf0332af8e5e52a32eb9b3cd862646375.tar.bz2 |
tree.def (FIXED_POINT_TYPE): New type.
* tree.def (FIXED_POINT_TYPE): New type.
(FIXED_CST): New constant.
(FIXED_CONVERT_EXPR): New expr.
* doc/c-tree.texi (Types): Document FIXED_POINT_TYPE.
(Expressions): Document FIXED_CST and FIXED_CONVERT_EXPR.
* tree.h (struct tree_base): Add saturating_flag.
Remove one bit of spare for saturating_flag.
(NUMERICAL_TYPE_CHECK): Support FIXED_POINT_TYPE.
(NON_SAT_FIXED_POINT_TYPE_P, SAT_FIXED_POINT_TYPE_P,
FIXED_POINT_TYPE_P): Define.
(TYPE_SATURATING): Define.
(TREE_FIXED_CST_PTR, TREE_FIXED_CST): Define.
(struct tree_fixed_cst): New.
(TYPE_IBIT, TYPE_FBIT): Define.
(tree_node): Add fixed_cst.
(enum tree_index): Add new enumeration values of
TI_SAT_SFRACT_TYPE, TI_SAT_FRACT_TYPE, TI_SAT_LFRACT_TYPE,
TI_SAT_LLFRACT_TYPE, TI_SAT_USFRACT_TYPE, TI_SAT_UFRACT_TYPE,
TI_SAT_ULFRACT_TYPE, TI_SAT_ULLFRACT_TYPE, TI_SFRACT_TYPE,
TI_FRACT_TYPE, TI_LFRACT_TYPE, TI_LLFRACT_TYPE, TI_USFRACT_TYPE,
TI_UFRACT_TYPE, TI_ULFRACT_TYPE, TI_ULLFRACT_TYPE,
TI_SAT_SACCUM_TYPE, TI_SAT_ACCUM_TYPE, TI_SAT_LACCUM_TYPE,
TI_SAT_LLACCUM_TYPE, TI_SAT_USACCUM_TYPE, TI_SAT_UACCUM_TYPE,
TI_SAT_ULACCUM_TYPE, TI_SAT_ULLACCUM_TYPE, TI_SACCUM_TYPE,
TI_ACCUM_TYPE, TI_LACCUM_TYPE, TI_LLACCUM_TYPE, TI_USACCUM_TYPE,
TI_UACCUM_TYPE, TI_ULACCUM_TYPE, TI_ULLACCUM_TYPE,
TI_QQ_TYPE, TI_HQ_TYPE,_TYPE, TI_SQ_TYPE, TI_DQ_TYPE, TI_TQ_TYPE,
TI_UQQ_TYPE, TI_UHQ_TYPE, TI_USQ_TYPE, TI_UDQ_TYPE, TI_UTQ_TYPE,
TI_SAT_QQ_TYPE, TI_SAT_HQ_TYPE, TI_SAT_SQ_TYPE, TI_SAT_DQ_TYPE,
TI_SAT_TQ_TYPE, TI_SAT_UQQ_TYPE, TI_SAT_UHQ_TYPE, TI_SAT_USQ_TYPE,
TI_SAT_UDQ_TYPE, TI_SAT_UTQ_TYPE, TI_HA_TYPE, TI_SA_TYPE, TI_DA_TYPE,
TI_TA_TYPE, TI_UHA_TYPE, TI_USA_TYPE, TI_UDA_TYPE, TI_UTA_TYPE,
TI_SAT_HA_TYPE, TI_SAT_SA_TYPE, TI_SAT_DA_TYPE, TI_SAT_TA_TYPE,
TI_SAT_UHA_TYPE, TI_SAT_USA_TYPE, TI_SAT_UDA_TYPE, TI_SAT_UTA_TYPE.
(sat_short_fract_type_node, sat_fract_type_node,
sat_long_fract_type_node, sat_long_long_fract_type_node,
sat_unsigned_short_fract_type_node, sat_unsigned_fract_type_node,
sat_unsigned_long_fract_type_node,
sat_unsigned_long_long_fract_type_node, short_fract_type_node,
fract_type_node, long_fract_type_node, long_long_fract_type_node,
unsigned_short_fract_type_node, unsigned_fract_type_node,
unsigned_long_fract_type_node, unsigned_long_long_fract_type_node,
sat_short_accum_type_node, sat_accum_type_node,
sat_long_accum_type_node, sat_long_long_accum_type_node,
sat_unsigned_short_accum_type_node, sat_unsigned_accum_type_node,
sat_unsigned_long_accum_type_node,
sat_unsigned_long_long_accum_type_node, short_accum_type_node,
accum_type_node, long_accum_type_node, long_long_accum_type_node,
unsigned_short_accum_type_node, unsigned_accum_type_node,
unsigned_long_accum_type_node, unsigned_long_long_accum_type_node,
qq_type_node, hq_type_node, sq_type_node, dq_type_node, tq_type_node,
uqq_type_node, uhq_type_node, usq_type_node, udq_type_node,
utq_type_node, sat_qq_type_node, sat_hq_type_node, sat_sq_type_node,
sat_dq_type_node, sat_tq_type_node, sat_uqq_type_node,
sat_uhq_type_node, sat_usq_type_node, sat_udq_type_node,
sat_utq_type_node, ha_type_node, sa_type_node, da_type_node,
ta_type_node, uha_type_node, usa_type_node, uda_type_node,
uta_type_node, sat_ha_type_node, sat_sa_type_node, sat_da_type_node,
sat_ta_type_node, sat_uha_type_node, sat_usa_type_node,
sat_uda_type_node, sat_uta_type_node): New macro.
(make_fract_type, make_accum_type): Declare.
(make_signed_fract_type, make_unsigned_fract_type,
make_sat_signed_fract_type, make_sat_unsigned_fract_type,
make_signed_accum_type, make_unsigned_accum_type,
make_sat_signed_accum_type, make_sat_unsigned_accum_type,
make_or_reuse_signed_fract_type, make_or_reuse_unsigned_fract_type,
make_or_reuse_sat_signed_fract_type,
make_or_reuse_sat_unsigned_fract_type, make_or_reuse_signed_accum_type,
make_or_reuse_unsigned_accum_type, make_or_reuse_sat_signed_accum_type,
make_or_reuse_sat_unsigned_accum_type): New macro.
(fixed_zerop): Declare.
* defaults.h (SHORT_FRACT_TYPE_SIZE, FRACT_TYPE_SIZE,
LONG_FRACT_TYPE_SIZE, LONG_LONG_FRACT_TYPE_SIZE,
SHORT_ACCUM_TYPE_SIZE, ACCUM_TYPE_SIZE, LONG_ACCUM_TYPE_SIZE,
LONG_LONG_ACCUM_TYPE_SIZE): Define.
* treestruct.def: Add TS_FIXED_CST.
* Makefile.in (c-pretty-print.o): Add dependence on fixed-value.h.
(tree.o): Likewise.
(tree-dump.o): Likewise.
(print-tree.o): Likewise.
(tree-pretty-print.o): Likewise.
(fold-const.o): Likewise.
* tree-complex.c (some_nonzerop): Handle FIXED_CST.
* tree-gimple.c (is_gimple_formal_tmp_rhs): Handle FIXED_CST.
(is_gimple_min_invariant): Handle FIXED_CST.
* stor-layout.c (int_mode_for_mode): Handle MODE_FRACT, MODE_UFRACT,
MODE_ACCUM, MODE_UACCUM, MODE_VECTOR_FRACT, MODE_VECTOR_UFRACT,
MODE_VECTOR_ACCUM, MODE_VECTOR_UACCUM.
(layout_type): Handle FIXED_POINT_TYPE.
(make_fract_type, make_accum_type): New functions.
* tree-browser.c (browse_tree): Handle FIXED_POINT_TYPE.
* tree-dump.c (fixed-value.h): New include.
(dump_fixed): New function.
(dequeue_and_dump): Handle FIXED_POINT_TYPE and FIXED_CST.
* tree-inline.c (remap_type_1): Handle FIXED_POINT_TYPE.
(estimate_num_insns_1): Handle FIXED_CST and FIXED_CONVERT_EXPR.
* tree-pretty-print.c (fixed-value.h): New include.
(dump_generic_node): Handle FIXED_POINT_TYPE, FIXED_CST, and
FIXED_CONVERT_EXPR.
* tree-scalar-evolution.c (get_scalar_evolution): Handle FIXED_CST.
* tree-ssa-loop-im.c (for_each_index): Handle FIXED_CST.
* tree-ssa-pre.c (poolify_tree): Handle FIXED_CST.
* tree-ssa-reassoc.c (break_up_subtract_bb): We can do reassociation
for non-saturating fixed-point types.
(reassociate_bb): Likewise.
* emit-rtl.c (fixed-value.h): New include.
(fconst0, fconst1): New array.
(init_emit_once): Initialize fconst0 and fconst1 for fixed-point modes.
* tree-vect-generic.c expand_vector_operation): Support
MODE_VECTOR_FRACT, MODE_VECTOR_UFRACT, MODE_VECTOR_ACCUM, and
MODE_VECTOR_UACCUM.
(type_for_widest_vector_mode): Add one parameter for the
saturating flag.
Check scalar FRACT, UFRACT, ACCUM, and UACCUM mode to select their
vector mode.
Pass the satp parameter to type_for_mode for fixed-point types.
(expand_vector_operations_1): Pass the saturating flag to
type_for_widest_vector_mode.
Support MODE_VECTOR_FRACT, MODE_VECTOR_UFRACT, MODE_VECTOR_ACCUM,
and MODE_VECTOR_UACCUM.
* tree-vect-transform.c (vect_is_simple_cond): Support FIXED_CST.
(vectorizable_condition): Likewise.
* tree.c (fixed-value.h): New include.
(tree_code_size): Support FIXED_CST.
(build_fixed): New function.
(build_one_cst): Support FIXED_POINT_TYPE for accum types.
(fixed_zerop): New function.
(tree_node_structure): Support FIXED_CST.
(type_contains_placeholder_1): Support FIXED_POINT_TYPE.
(build_type_attribute_qual_variant): Handle FIXED_POINT_TYPE.
(type_hash_eq): Handle FIXED_POINT_TYPE.
(simple_cst_equal): Support FIXED_CST.
(iterative_hash_expr): Handle FIXED_CST.
(get_unwidened): Make sure type is not FIXED_POINT_TYPE.
(get_narrower): Likewise.
(variably_modified_type_p): Handle FIXED_POINT_TYPE.
(make_or_reuse_fract_type, make_or_reuse_accum_type): New functions.
(build_common_tree_nodes_2): Use MAKE_FIXED_TYPE_NODE_FAMILY and
MAKE_FIXED_MODE_NODE macros to initialize fixed-point type
nodes.
(build_vector_type_for_mode): Handle MODE_VECTOR_FRACT,
MODE_VECTOR_UFRACT, MODE_VECTOR_ACCUM, MODE_VECTOR_UACCUM.
(initializer_zerop): Support FIXED_CST.
(walk_tree): Handle FIXED_CST and FIXED_POINT_TYPE.
* dwarf2out.c (base_type_die): Use DW_ATE_signed_fixed or
DW_ATE_unsigned_fixed to describe FIXED_POINT_TYPE.
(is_base_type): Handle FIXED_POINT_TYPE.
(add_type_attribute): Handle FIXED_POINT_TYPE.
(gen_type_die_with_usage): Handle FIXED_POINT_TYPE.
* print-tree.c (fixed-value.h): New include.
(print_node_brief): Support FIXED_CST.
(print_node): Support FIXED_POINT_TYPE and FIXED_CST.
* c-pretty-print.c (fixed-value.h): New include.
(pp_c_type_specifier): Handle FIXED_POINT_TYPE. Need to pass
TYPE_SATURATING to c_common_type_for_mode for fixed-point modes.
(pp_c_direct_abstract_declarator): Handle FIXED_POINT_TYPE.
Support fixed-point types for inner items in VECTOR_TYPE.
(pp_c_direct_declarator): Likewise.
(pp_c_declarator): Likewise.
(pp_c_fixed_constant): New function.
(pp_c_constant): Handle FIXED_CST.
(pp_c_primary_expression): Likewise.
(pp_c_expression): Likewise.
* fold-const.c (fixed-value.h): New include.
(negate_expr_p): Return true for FIXED_CST.
(fold_negate_expr): Support FIXED_CST.
(split_tree): Support FIXED_CST.
(const_binop): Support FIXED_CST.
(fold_convert_const_int_from_fixed): New function to convert from
fixed to int.
(fold_convert_const_real_from_fixed): New function to convert from
fixed to real.
(fold_convert_const_fixed_from_fixed): New function to convert from
fixed to another fixed.
(fold_convert_const_fixed_from_int): New function to convert from
int to fixed.
(fold_convert_const_fixed_from_real): New function to convert from
real to fixed.
(fold_convert_const): Support conversions from fixed to int, from
fixed to real, from fixed to fixed, from int to fixed, and from real
to fixed.
(fold_convert): Support FIXED_CST and FIXED_POINT_TYPE.
(operand_equal_p): Support FIXED_CST.
(make_range): For fixed-point modes, we need to pass the
saturating flag as the 2nd parameter.
(tree_swap_operands_p): Handle FIXED_CST.
(fold_plusminus_mult_expr): For fract modes, we cannot generate
constant 1.
(fold_unary): Support FIXED_CONVERT_EXPR.
(fold_binary): Handle FIXED_CST.
Make sure the type is not saturating, before associating operations.
Ex: A + B + C, A * B * C, (A1 * C1) +/- (A2 * C2).
(tree_expr_nonnegative_warnv_p): Handle FIXED_CST.
(fold_negate_const): Support FIXED_CST.
(fold_relational_const): Support FIXED_CST.
* gimplify.c (omp_firstprivatize_type_sizes): Handle FIXED_POINT_TYPE.
(gimplify_expr): Handle FIXED_CST.
(gimplify_type_sizes): Handle FIXED_POINT_TYPE.
* ipa-prop.c (ipa_callsite_compute_param): Support FIXED_CST.
* ipa-type-escape.c (type_to_consider): Handle FIXED_POINT_TYPE.
* doc/tm.texi (Type Layout): Document SHORT_FRACT_TYPE_SIZE,
FRACT_TYPE_SIZE, LONG_FRACT_TYPE_SIZE, LONG_LONG_FRACT_TYPE_SIZE,
SHORT_ACCUM_TYPE_SIZE, ACCUM_TYPE_SIZE, LONG_ACCUM_TYPE_SIZE,
LONG_LONG_ACCUM_TYPE_SIZE.
* dbxout.c (dbxout_type): Handle FIXED_POINT_TYPE.
* c-aux-info.c (gen_type): Handle FIXED_POINT_TYPE.
* tree-sra.c (is_sra_scalar_type): Support FIXED_POINT_TYPE.
* expmed.c (extract_bit_field): Support MODE_FRACT, MODE_UFRACT,
MODE_ACCUM, and MODE_UACCUM.
* tree-vectorizer.c (vect_is_simple_reduction): Check for saturating
fixed-point types to disable reduction.
* explow.c (promote_mode): Support FIXED_POINT_TYPE.
From-SVN: r127306
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 346 |
1 files changed, 334 insertions, 12 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 154454a..eadcb97 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -54,6 +54,7 @@ along with GCC; see the file COPYING3. If not see #include "flags.h" #include "tree.h" #include "real.h" +#include "fixed-value.h" #include "rtl.h" #include "expr.h" #include "tm_p.h" @@ -1127,6 +1128,7 @@ negate_expr_p (tree t) return (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type)); + case FIXED_CST: case REAL_CST: case NEGATE_EXPR: return true; @@ -1257,6 +1259,10 @@ fold_negate_expr (tree t) return tem; break; + case FIXED_CST: + tem = fold_negate_const (t, type); + return tem; + case COMPLEX_CST: { tree rpart = negate_expr (TREE_REALPART (t)); @@ -1479,10 +1485,12 @@ split_tree (tree in, enum tree_code code, tree *conp, tree *litp, /* Strip any conversions that don't change the machine mode or signedness. */ STRIP_SIGN_NOPS (in); - if (TREE_CODE (in) == INTEGER_CST || TREE_CODE (in) == REAL_CST) + if (TREE_CODE (in) == INTEGER_CST || TREE_CODE (in) == REAL_CST + || TREE_CODE (in) == FIXED_CST) *litp = in; else if (TREE_CODE (in) == code || (! FLOAT_TYPE_P (TREE_TYPE (in)) + && ! SAT_FIXED_POINT_TYPE_P (TREE_TYPE (in)) /* We can associate addition and subtraction together (even though the C standard doesn't say so) for integers because the value is not affected. For reals, the value might be @@ -1496,9 +1504,11 @@ split_tree (tree in, enum tree_code code, tree *conp, tree *litp, int neg_litp_p = 0, neg_conp_p = 0, neg_var_p = 0; /* First see if either of the operands is a literal, then a constant. */ - if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST) + if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST + || TREE_CODE (op0) == FIXED_CST) *litp = op0, op0 = 0; - else if (TREE_CODE (op1) == INTEGER_CST || TREE_CODE (op1) == REAL_CST) + else if (TREE_CODE (op1) == INTEGER_CST || TREE_CODE (op1) == REAL_CST + || TREE_CODE (op1) == FIXED_CST) *litp = op1, neg_litp_p = neg1_p, op1 = 0; if (op0 != 0 && TREE_CONSTANT (op0)) @@ -1886,6 +1896,52 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc) return t; } + if (TREE_CODE (arg1) == FIXED_CST) + { + FIXED_VALUE_TYPE f1; + FIXED_VALUE_TYPE f2; + FIXED_VALUE_TYPE result; + tree t, type; + int sat_p; + bool overflow_p; + + /* 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); + sat_p = TYPE_SATURATING (type); + overflow_p = fixed_arithmetic (&result, code, &f1, &f2, sat_p); + t = build_fixed (type, result); + /* Propagate overflow flags. */ + if (overflow_p | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)) + { + TREE_OVERFLOW (t) = 1; + TREE_CONSTANT_OVERFLOW (t) = 1; + } + else if (TREE_CONSTANT_OVERFLOW (arg1) | TREE_CONSTANT_OVERFLOW (arg2)) + TREE_CONSTANT_OVERFLOW (t) = 1; + return t; + } + if (TREE_CODE (arg1) == COMPLEX_CST) { tree type = TREE_TYPE (arg1); @@ -2151,6 +2207,61 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, tree arg1) return t; } +/* A subroutine of fold_convert_const handling conversions of a + FIXED_CST to an integer type. */ + +static tree +fold_convert_const_int_from_fixed (tree type, tree arg1) +{ + tree t; + double_int temp, temp_trunc; + unsigned int mode; + + /* Right shift FIXED_CST to temp by fbit. */ + temp = TREE_FIXED_CST (arg1).data; + mode = TREE_FIXED_CST (arg1).mode; + if (GET_MODE_FBIT (mode) < 2 * HOST_BITS_PER_WIDE_INT) + { + lshift_double (temp.low, temp.high, + - GET_MODE_FBIT (mode), 2 * HOST_BITS_PER_WIDE_INT, + &temp.low, &temp.high, SIGNED_FIXED_POINT_MODE_P (mode)); + + /* Left shift temp to temp_trunc by fbit. */ + lshift_double (temp.low, temp.high, + GET_MODE_FBIT (mode), 2 * HOST_BITS_PER_WIDE_INT, + &temp_trunc.low, &temp_trunc.high, + SIGNED_FIXED_POINT_MODE_P (mode)); + } + else + { + temp.low = 0; + temp.high = 0; + temp_trunc.low = 0; + temp_trunc.high = 0; + } + + /* If FIXED_CST is negative, we need to round the value toward 0. + By checking if the fractional bits are not zero to add 1 to temp. */ + if (SIGNED_FIXED_POINT_MODE_P (mode) && temp_trunc.high < 0 + && !double_int_equal_p (TREE_FIXED_CST (arg1).data, temp_trunc)) + { + double_int one; + one.low = 1; + one.high = 0; + temp = double_int_add (temp, one); + } + + /* Given a fixed-point constant, make new constant with new type, + appropriately sign-extended or truncated. */ + t = force_fit_type_double (type, temp.low, temp.high, -1, + (temp.high < 0 + && (TYPE_UNSIGNED (type) + < TYPE_UNSIGNED (TREE_TYPE (arg1)))) + | TREE_OVERFLOW (arg1)); + + return t; +} + /* A subroutine of fold_convert_const handling conversions a REAL_CST to another floating point type. */ @@ -2167,6 +2278,102 @@ fold_convert_const_real_from_real (tree type, tree arg1) return t; } +/* A subroutine of fold_convert_const handling conversions a FIXED_CST + to a floating point type. */ + +static tree +fold_convert_const_real_from_fixed (tree type, tree arg1) +{ + REAL_VALUE_TYPE value; + tree t; + + real_convert_from_fixed (&value, TYPE_MODE (type), &TREE_FIXED_CST (arg1)); + t = build_real (type, value); + + TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1); + TREE_CONSTANT_OVERFLOW (t) + = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1); + 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; + bool overflow_p; + + overflow_p = fixed_convert (&value, TYPE_MODE (type), &TREE_FIXED_CST (arg1), + TYPE_SATURATING (type)); + t = build_fixed (type, value); + + /* Propagate overflow flags. */ + if (overflow_p | TREE_OVERFLOW (arg1)) + { + TREE_OVERFLOW (t) = 1; + TREE_CONSTANT_OVERFLOW (t) = 1; + } + else if (TREE_CONSTANT_OVERFLOW (arg1)) + TREE_CONSTANT_OVERFLOW (t) = 1; + return t; +} + +/* A subroutine of fold_convert_const handling conversions an INTEGER_CST + to a fixed-point type. */ + +static tree +fold_convert_const_fixed_from_int (tree type, tree arg1) +{ + FIXED_VALUE_TYPE value; + tree t; + bool overflow_p; + + overflow_p = fixed_convert_from_int (&value, TYPE_MODE (type), + TREE_INT_CST (arg1), + TYPE_UNSIGNED (TREE_TYPE (arg1)), + TYPE_SATURATING (type)); + t = build_fixed (type, value); + + /* Propagate overflow flags. */ + if (overflow_p | TREE_OVERFLOW (arg1)) + { + TREE_OVERFLOW (t) = 1; + TREE_CONSTANT_OVERFLOW (t) = 1; + } + else if (TREE_CONSTANT_OVERFLOW (arg1)) + TREE_CONSTANT_OVERFLOW (t) = 1; + return t; +} + +/* A subroutine of fold_convert_const handling conversions a REAL_CST + to a fixed-point type. */ + +static tree +fold_convert_const_fixed_from_real (tree type, tree arg1) +{ + FIXED_VALUE_TYPE value; + tree t; + bool overflow_p; + + overflow_p = fixed_convert_from_real (&value, TYPE_MODE (type), + &TREE_REAL_CST (arg1), + TYPE_SATURATING (type)); + t = build_fixed (type, value); + + /* Propagate overflow flags. */ + if (overflow_p | TREE_OVERFLOW (arg1)) + { + TREE_OVERFLOW (t) = 1; + TREE_CONSTANT_OVERFLOW (t) = 1; + } + else if (TREE_CONSTANT_OVERFLOW (arg1)) + TREE_CONSTANT_OVERFLOW (t) = 1; + return t; +} + /* Attempt to fold type conversion operation CODE of expression ARG1 to type TYPE. If no simplification can be done return NULL_TREE. */ @@ -2182,13 +2389,26 @@ fold_convert_const (enum tree_code code, tree type, tree arg1) return fold_convert_const_int_from_int (type, arg1); else if (TREE_CODE (arg1) == REAL_CST) return fold_convert_const_int_from_real (code, type, arg1); + else if (TREE_CODE (arg1) == FIXED_CST) + return fold_convert_const_int_from_fixed (type, arg1); } else if (TREE_CODE (type) == REAL_TYPE) { if (TREE_CODE (arg1) == INTEGER_CST) return build_real_from_int_cst (type, arg1); - if (TREE_CODE (arg1) == REAL_CST) + else if (TREE_CODE (arg1) == REAL_CST) return fold_convert_const_real_from_real (type, arg1); + else if (TREE_CODE (arg1) == FIXED_CST) + return fold_convert_const_real_from_fixed (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); + else if (TREE_CODE (arg1) == INTEGER_CST) + return fold_convert_const_fixed_from_int (type, arg1); + else if (TREE_CODE (arg1) == REAL_CST) + return fold_convert_const_fixed_from_real (type, arg1); } return NULL_TREE; } @@ -2300,6 +2520,12 @@ fold_convert (tree type, tree arg) if (tem != NULL_TREE) return tem; } + else if (TREE_CODE (arg) == FIXED_CST) + { + tem = fold_convert_const (FIXED_CONVERT_EXPR, type, arg); + if (tem != NULL_TREE) + return tem; + } switch (TREE_CODE (orig)) { @@ -2311,6 +2537,35 @@ fold_convert (tree type, tree arg) case REAL_TYPE: return fold_build1 (NOP_EXPR, type, arg); + case FIXED_POINT_TYPE: + return fold_build1 (FIXED_CONVERT_EXPR, type, arg); + + case COMPLEX_TYPE: + tem = fold_build1 (REALPART_EXPR, TREE_TYPE (orig), arg); + return fold_convert (type, tem); + + default: + gcc_unreachable (); + } + + case FIXED_POINT_TYPE: + if (TREE_CODE (arg) == FIXED_CST || TREE_CODE (arg) == INTEGER_CST + || TREE_CODE (arg) == REAL_CST) + { + tem = fold_convert_const (FIXED_CONVERT_EXPR, type, arg); + if (tem != NULL_TREE) + return tem; + } + + switch (TREE_CODE (orig)) + { + case FIXED_POINT_TYPE: + case INTEGER_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case REAL_TYPE: + return fold_build1 (FIXED_CONVERT_EXPR, type, arg); + case COMPLEX_TYPE: tem = fold_build1 (REALPART_EXPR, TREE_TYPE (orig), arg); return fold_convert (type, tem); @@ -2326,6 +2581,7 @@ fold_convert (tree type, tree arg) case BOOLEAN_TYPE: case ENUMERAL_TYPE: case POINTER_TYPE: case REFERENCE_TYPE: case REAL_TYPE: + case FIXED_POINT_TYPE: return build2 (COMPLEX_EXPR, type, fold_convert (TREE_TYPE (type), arg), fold_convert (TREE_TYPE (type), integer_zero_node)); @@ -2808,6 +3064,10 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) case INTEGER_CST: return tree_int_cst_equal (arg0, arg1); + case FIXED_CST: + return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (arg0), + TREE_FIXED_CST (arg1)); + case REAL_CST: if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (arg0), TREE_REAL_CST (arg1))) @@ -4265,8 +4525,16 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh, if (!TYPE_UNSIGNED (exp_type) && TYPE_UNSIGNED (arg0_type)) { tree high_positive; - tree equiv_type = lang_hooks.types.type_for_mode - (TYPE_MODE (arg0_type), 1); + tree equiv_type; + /* For fixed-point modes, we need to pass the saturating flag + as the 2nd parameter. */ + if (ALL_FIXED_POINT_MODE_P (TYPE_MODE (arg0_type))) + equiv_type = lang_hooks.types.type_for_mode + (TYPE_MODE (arg0_type), + TYPE_SATURATING (arg0_type)); + else + equiv_type = lang_hooks.types.type_for_mode + (TYPE_MODE (arg0_type), 1); /* A range without an upper bound is, naturally, unbounded. Since convert would have cropped a very large value, use @@ -6737,6 +7005,11 @@ tree_swap_operands_p (const_tree arg0, const_tree arg1, bool reorder) if (TREE_CODE (arg0) == REAL_CST) return 1; + if (TREE_CODE (arg1) == FIXED_CST) + return 0; + if (TREE_CODE (arg0) == FIXED_CST) + return 1; + if (TREE_CODE (arg1) == COMPLEX_CST) return 0; if (TREE_CODE (arg0) == COMPLEX_CST) @@ -7136,6 +7409,9 @@ fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1) } else { + /* We cannot generate constant 1 for fract. */ + if (ALL_FRACT_MODE_P (TYPE_MODE (type))) + return NULL_TREE; arg00 = arg0; arg01 = build_one_cst (type); } @@ -7151,6 +7427,9 @@ fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1) } else { + /* We cannot generate constant 1 for fract. */ + if (ALL_FRACT_MODE_P (TYPE_MODE (type))) + return NULL_TREE; arg10 = arg1; arg11 = build_one_cst (type); } @@ -8011,6 +8290,10 @@ fold_unary (enum tree_code code, tree type, tree op0) tem = fold_convert_const (code, type, op0); return tem ? tem : NULL_TREE; + case FIXED_CONVERT_EXPR: + tem = fold_convert_const (code, type, arg0); + return tem ? tem : NULL_TREE; + case VIEW_CONVERT_EXPR: if (TREE_TYPE (op0) == type) return op0; @@ -9114,11 +9397,18 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) 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)) { if (kind == tcc_binary) - tem = const_binop (code, arg0, arg1, 0); + { + /* Make sure type and arg0 have the same saturating flag. */ + gcc_assert (TYPE_SATURATING (type) + == TYPE_SATURATING (TREE_TYPE (arg0))); + tem = const_binop (code, arg0, arg1, 0); + } else if (kind == tcc_comparison) tem = fold_relational_const (code, type, arg0, arg1); else @@ -9323,9 +9613,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) } /* Handle (A1 * C1) + (A2 * C2) with A1, A2 or C1, C2 being the - same or one. */ + same or one. Make sure type is not saturating. */ if ((TREE_CODE (arg0) == MULT_EXPR || TREE_CODE (arg1) == MULT_EXPR) + && !TYPE_SATURATING (type) && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)) { tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1); @@ -9569,9 +9860,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) /* In most languages, can't associate operations on floats through parentheses. Rather than remember where the parentheses were, we don't associate floats at all, unless the user has specified - -funsafe-math-optimizations. */ + -funsafe-math-optimizations. + And, we need to make sure type is not saturating. */ - if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations) + if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations) + && !TYPE_SATURATING (type)) { tree var0, con0, lit0, minus_lit0; tree var1, con1, lit1, minus_lit1; @@ -9874,9 +10167,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) return tem; /* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the - same or one. */ + same or one. Make sure type is not saturating. */ if ((TREE_CODE (arg0) == MULT_EXPR || TREE_CODE (arg1) == MULT_EXPR) + && !TYPE_SATURATING (type) && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)) { tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1); @@ -13480,6 +13774,9 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p) case REAL_CST: return ! REAL_VALUE_NEGATIVE (TREE_REAL_CST (t)); + case FIXED_CST: + return ! FIXED_VALUE_NEGATIVE (TREE_FIXED_CST (t)); + case POINTER_PLUS_EXPR: case PLUS_EXPR: if (FLOAT_TYPE_P (TREE_TYPE (t))) @@ -14082,7 +14379,7 @@ fold_read_from_constant_string (tree exp) } /* Return the tree for neg (ARG0) when ARG0 is known to be either - an integer constant or real constant. + an integer constant, real, or fixed-point constant. TYPE is the type of the result. */ @@ -14110,6 +14407,24 @@ fold_negate_const (tree arg0, tree type) t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0))); break; + case FIXED_CST: + { + FIXED_VALUE_TYPE f; + bool overflow_p = fixed_arithmetic (&f, NEGATE_EXPR, + &(TREE_FIXED_CST (arg0)), NULL, + TYPE_SATURATING (type)); + t = build_fixed (type, f); + /* Propagate overflow flags. */ + if (overflow_p | TREE_OVERFLOW (arg0)) + { + TREE_OVERFLOW (t) = 1; + TREE_CONSTANT_OVERFLOW (t) = 1; + } + else if (TREE_CONSTANT_OVERFLOW (arg0)) + TREE_CONSTANT_OVERFLOW (t) = 1; + break; + } + default: gcc_unreachable (); } @@ -14240,6 +14555,13 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1) 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); + } + /* Handle equality/inequality of complex constants. */ if (TREE_CODE (op0) == COMPLEX_CST && TREE_CODE (op1) == COMPLEX_CST) { |