diff options
Diffstat (limited to 'gcc/expr.cc')
-rw-r--r-- | gcc/expr.cc | 182 |
1 files changed, 118 insertions, 64 deletions
diff --git a/gcc/expr.cc b/gcc/expr.cc index 1eeefa1..ac4fdfa 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -7631,8 +7631,8 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, tree domain; tree elttype = TREE_TYPE (type); bool const_bounds_p; - HOST_WIDE_INT minelt = 0; - HOST_WIDE_INT maxelt = 0; + unsigned HOST_WIDE_INT minelt = 0; + unsigned HOST_WIDE_INT maxelt = 0; /* The storage order is specified for every aggregate type. */ reverse = TYPE_REVERSE_STORAGE_ORDER (type); @@ -7640,14 +7640,14 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, domain = TYPE_DOMAIN (type); const_bounds_p = (TYPE_MIN_VALUE (domain) && TYPE_MAX_VALUE (domain) - && tree_fits_shwi_p (TYPE_MIN_VALUE (domain)) - && tree_fits_shwi_p (TYPE_MAX_VALUE (domain))); + && tree_fits_uhwi_p (TYPE_MIN_VALUE (domain)) + && tree_fits_uhwi_p (TYPE_MAX_VALUE (domain))); /* If we have constant bounds for the range of the type, get them. */ if (const_bounds_p) { - minelt = tree_to_shwi (TYPE_MIN_VALUE (domain)); - maxelt = tree_to_shwi (TYPE_MAX_VALUE (domain)); + minelt = tree_to_uhwi (TYPE_MIN_VALUE (domain)); + maxelt = tree_to_uhwi (TYPE_MAX_VALUE (domain)); } /* If the constructor has fewer elements than the array, clear @@ -7660,7 +7660,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, else { unsigned HOST_WIDE_INT idx; - HOST_WIDE_INT count = 0, zero_count = 0; + unsigned HOST_WIDE_INT count = 0, zero_count = 0; need_to_clear = ! const_bounds_p; /* This loop is a more accurate version of the loop in @@ -7668,7 +7668,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, is also needed to check for missing elements. */ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, index, value) { - HOST_WIDE_INT this_node_count; + unsigned HOST_WIDE_INT this_node_count; if (need_to_clear) break; @@ -7742,16 +7742,16 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, { tree lo_index = TREE_OPERAND (index, 0); tree hi_index = TREE_OPERAND (index, 1); - rtx index_r, pos_rtx; - HOST_WIDE_INT lo, hi, count; - tree position; + rtx index_r; + unsigned HOST_WIDE_INT lo, hi, count; + tree offset; /* If the range is constant and "small", unroll the loop. */ if (const_bounds_p - && tree_fits_shwi_p (lo_index) - && tree_fits_shwi_p (hi_index) - && (lo = tree_to_shwi (lo_index), - hi = tree_to_shwi (hi_index), + && tree_fits_uhwi_p (lo_index) + && tree_fits_uhwi_p (hi_index) + && (lo = tree_to_uhwi (lo_index), + hi = tree_to_uhwi (hi_index), count = hi - lo + 1, (!MEM_P (target) || count <= 2 @@ -7762,7 +7762,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, lo -= minelt; hi -= minelt; for (; lo <= hi; lo++) { - bitpos = lo * tree_to_shwi (TYPE_SIZE (elttype)); + bitpos = lo * tree_to_uhwi (TYPE_SIZE (elttype)); if (MEM_P (target) && !MEM_KEEP_ALIAS_SET_P (target) @@ -7798,21 +7798,18 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, emit_label (loop_start); /* Assign value to element index. */ - position = - fold_convert (ssizetype, - fold_build2 (MINUS_EXPR, - TREE_TYPE (index), - index, - TYPE_MIN_VALUE (domain))); - - position = - size_binop (MULT_EXPR, position, - fold_convert (ssizetype, - TYPE_SIZE_UNIT (elttype))); - - pos_rtx = expand_normal (position); - xtarget = offset_address (target, pos_rtx, - highest_pow2_factor (position)); + offset = fold_build2 (MINUS_EXPR, + TREE_TYPE (index), + index, + TYPE_MIN_VALUE (domain)); + + offset = size_binop (MULT_EXPR, + fold_convert (sizetype, offset), + TYPE_SIZE_UNIT (elttype)); + + xtarget = offset_address (target, + expand_normal (offset), + highest_pow2_factor (offset)); xtarget = adjust_address (xtarget, mode, 0); if (TREE_CODE (value) == CONSTRUCTOR) store_constructor (value, xtarget, cleared, @@ -7840,35 +7837,32 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, emit_label (loop_end); } } - else if ((index != 0 && ! tree_fits_shwi_p (index)) - || ! tree_fits_uhwi_p (TYPE_SIZE (elttype))) + else if ((index && !tree_fits_uhwi_p (index)) + || !tree_fits_uhwi_p (TYPE_SIZE (elttype))) { - tree position; - - if (index == 0) - index = ssize_int (1); - - if (minelt) - index = fold_convert (ssizetype, - fold_build2 (MINUS_EXPR, - TREE_TYPE (index), - index, - TYPE_MIN_VALUE (domain))); - - position = - size_binop (MULT_EXPR, index, - fold_convert (ssizetype, - TYPE_SIZE_UNIT (elttype))); + tree offset; + + if (index) + offset = fold_build2 (MINUS_EXPR, + TREE_TYPE (index), + index, + TYPE_MIN_VALUE (domain)); + else + offset = size_int (i); + + offset = size_binop (MULT_EXPR, + fold_convert (sizetype, offset), + TYPE_SIZE_UNIT (elttype)); xtarget = offset_address (target, - expand_normal (position), - highest_pow2_factor (position)); + expand_normal (offset), + highest_pow2_factor (offset)); xtarget = adjust_address (xtarget, mode, 0); store_expr (value, xtarget, 0, false, reverse); } else { - if (index != 0) - bitpos = ((tree_to_shwi (index) - minelt) + if (index) + bitpos = ((tree_to_uhwi (index) - minelt) * tree_to_uhwi (TYPE_SIZE (elttype))); else bitpos = (i * tree_to_uhwi (TYPE_SIZE (elttype))); @@ -9687,8 +9681,8 @@ expand_expr_divmod (tree_code code, machine_mode mode, tree treeop0, || code == CEIL_MOD_EXPR || code == ROUND_MOD_EXPR); if (SCALAR_INT_MODE_P (mode) && optimize >= 2 - && get_range_pos_neg (treeop0) == 1 - && get_range_pos_neg (treeop1) == 1) + && get_range_pos_neg (treeop0, currently_expanding_gimple_stmt) == 1 + && get_range_pos_neg (treeop1, currently_expanding_gimple_stmt) == 1) { /* If both arguments are known to be positive when interpreted as signed, we can expand it as both signed and unsigned @@ -9885,14 +9879,68 @@ expand_expr_real_2 (const_sepops ops, rtx target, machine_mode tmode, op0 = gen_rtx_fmt_e (TYPE_UNSIGNED (TREE_TYPE (treeop0)) ? ZERO_EXTEND : SIGN_EXTEND, mode, op0); + else if (SCALAR_INT_MODE_P (GET_MODE (op0)) + && optimize >= 2 + && SCALAR_INT_MODE_P (mode) + && (GET_MODE_SIZE (as_a <scalar_int_mode> (mode)) + > GET_MODE_SIZE (as_a <scalar_int_mode> (GET_MODE (op0)))) + && get_range_pos_neg (treeop0, + currently_expanding_gimple_stmt) == 1) + { + /* If argument is known to be positive when interpreted + as signed, we can expand it as both sign and zero + extension. Choose the cheaper sequence in that case. */ + bool speed_p = optimize_insn_for_speed_p (); + rtx uns_ret = NULL_RTX, sgn_ret = NULL_RTX; + do_pending_stack_adjust (); + start_sequence (); + if (target == NULL_RTX) + uns_ret = convert_to_mode (mode, op0, 1); + else + convert_move (target, op0, 1); + rtx_insn *uns_insns = end_sequence (); + start_sequence (); + if (target == NULL_RTX) + sgn_ret = convert_to_mode (mode, op0, 0); + else + convert_move (target, op0, 0); + rtx_insn *sgn_insns = end_sequence (); + unsigned uns_cost = seq_cost (uns_insns, speed_p); + unsigned sgn_cost = seq_cost (sgn_insns, speed_p); + bool was_tie = false; + + /* If costs are the same then use as tie breaker the other other + factor. */ + if (uns_cost == sgn_cost) + { + uns_cost = seq_cost (uns_insns, !speed_p); + sgn_cost = seq_cost (sgn_insns, !speed_p); + was_tie = true; + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, ";; positive extension:%s unsigned cost: %u; " + "signed cost: %u\n", + was_tie ? " (needed tie breaker)" : "", + uns_cost, sgn_cost); + if (uns_cost < sgn_cost + || (uns_cost == sgn_cost && TYPE_UNSIGNED (TREE_TYPE (treeop0)))) + { + emit_insn (uns_insns); + sgn_ret = uns_ret; + } + else + emit_insn (sgn_insns); + if (target == NULL_RTX) + op0 = sgn_ret; + else + op0 = target; + } else if (target == 0) - op0 = convert_to_mode (mode, op0, - TYPE_UNSIGNED (TREE_TYPE - (treeop0))); + op0 = convert_to_mode (mode, op0, TYPE_UNSIGNED (TREE_TYPE (treeop0))); else { - convert_move (target, op0, - TYPE_UNSIGNED (TREE_TYPE (treeop0))); + convert_move (target, op0, TYPE_UNSIGNED (TREE_TYPE (treeop0))); op0 = target; } @@ -11372,11 +11420,16 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, /* ??? internal call expansion doesn't follow the usual API of returning the destination RTX and being passed a desired target. */ + if (modifier == EXPAND_WRITE) + return DECL_RTL (SSA_NAME_VAR (exp)); rtx dest = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp))); tree tmplhs = make_tree (TREE_TYPE (exp), dest); - gimple_call_set_lhs (g, tmplhs); + tree var_or_id = SSA_NAME_VAR (exp); + if (!var_or_id) + var_or_id = SSA_NAME_IDENTIFIER (exp); + SET_SSA_NAME_VAR_OR_IDENTIFIER (exp, tmplhs); expand_internal_call (as_a <gcall *> (g)); - gimple_call_set_lhs (g, exp); + SET_SSA_NAME_VAR_OR_IDENTIFIER (exp, var_or_id); return dest; } @@ -13223,7 +13276,7 @@ maybe_optimize_pow2p_mod_cmp (enum tree_code code, tree *arg0, tree *arg1) || integer_zerop (*arg1) /* If c is known to be non-negative, modulo will be expanded as unsigned modulo. */ - || get_range_pos_neg (treeop0) == 1) + || get_range_pos_neg (treeop0, currently_expanding_gimple_stmt) == 1) return code; /* x % c == d where d < 0 && d <= -c should be always false. */ @@ -13355,7 +13408,8 @@ maybe_optimize_mod_cmp (enum tree_code code, tree *arg0, tree *arg1) /* If both operands are known to have the sign bit clear, handle even the signed modulo case as unsigned. treeop1 is always positive >= 2, checked above. */ - if (!TYPE_UNSIGNED (type) && get_range_pos_neg (treeop0) != 1) + if (!TYPE_UNSIGNED (type) + && get_range_pos_neg (treeop0, currently_expanding_gimple_stmt) != 1) sgn = SIGNED; if (!TYPE_UNSIGNED (type)) |