X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fexpr.c;h=df86a57ee1813780c655a4115706d133e665423b;hb=f5734d36e9d0cf7d7f0186e40ad9915da244bc84;hp=8505d8f676f1d26d76187deb47444515431fcbc6;hpb=616ba5c3d0b0d1335bf1f164e8aef45bc453eab9;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/expr.c b/gcc/expr.c index 8505d8f676f..df86a57ee18 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -1,6 +1,6 @@ /* Convert tree expression to rtl instructions, for GNU compiler. Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #include "config.h" #include "system.h" @@ -126,7 +126,7 @@ static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode, struct move_by_pieces *); static bool block_move_libcall_safe_for_call_parm (void); static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned); -static rtx emit_block_move_via_libcall (rtx, rtx, rtx); +static rtx emit_block_move_via_libcall (rtx, rtx, rtx, bool); static tree emit_block_move_libcall_fn (int); static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned); static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode); @@ -134,8 +134,7 @@ static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int); static void store_by_pieces_1 (struct store_by_pieces *, unsigned int); static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode, struct store_by_pieces *); -static bool clear_storage_via_clrmem (rtx, rtx, unsigned); -static rtx clear_storage_via_libcall (rtx, rtx); +static rtx clear_storage_via_libcall (rtx, rtx, bool); static tree clear_storage_libcall_fn (int); static rtx compress_float_constant (rtx, rtx); static rtx get_subtarget (rtx); @@ -146,7 +145,6 @@ static void store_constructor (tree, rtx, int, HOST_WIDE_INT); static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode, tree, tree, int); -static unsigned HOST_WIDE_INT highest_pow2_factor (tree); static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (tree, tree); static int is_aligning_offset (tree, tree); @@ -159,6 +157,7 @@ static void emit_single_push_insn (enum machine_mode, rtx, tree); #endif static void do_tablejump (rtx, enum machine_mode, rtx, rtx, rtx); static rtx const_vector_from_tree (tree); +static void write_complex_part (rtx, rtx, bool); /* Record for each mode whether we can move a register directly to or from an object of that mode in memory. If we can't, we won't try @@ -199,14 +198,39 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES]; /* This array records the insn_code of insns to perform block moves. */ enum insn_code movmem_optab[NUM_MACHINE_MODES]; -/* This array records the insn_code of insns to perform block clears. */ -enum insn_code clrmem_optab[NUM_MACHINE_MODES]; +/* This array records the insn_code of insns to perform block sets. */ +enum insn_code setmem_optab[NUM_MACHINE_MODES]; -/* These arrays record the insn_code of two different kinds of insns +/* These arrays record the insn_code of three different kinds of insns to perform block compares. */ enum insn_code cmpstr_optab[NUM_MACHINE_MODES]; +enum insn_code cmpstrn_optab[NUM_MACHINE_MODES]; enum insn_code cmpmem_optab[NUM_MACHINE_MODES]; +/* Synchronization primitives. */ +enum insn_code sync_add_optab[NUM_MACHINE_MODES]; +enum insn_code sync_sub_optab[NUM_MACHINE_MODES]; +enum insn_code sync_ior_optab[NUM_MACHINE_MODES]; +enum insn_code sync_and_optab[NUM_MACHINE_MODES]; +enum insn_code sync_xor_optab[NUM_MACHINE_MODES]; +enum insn_code sync_nand_optab[NUM_MACHINE_MODES]; +enum insn_code sync_old_add_optab[NUM_MACHINE_MODES]; +enum insn_code sync_old_sub_optab[NUM_MACHINE_MODES]; +enum insn_code sync_old_ior_optab[NUM_MACHINE_MODES]; +enum insn_code sync_old_and_optab[NUM_MACHINE_MODES]; +enum insn_code sync_old_xor_optab[NUM_MACHINE_MODES]; +enum insn_code sync_old_nand_optab[NUM_MACHINE_MODES]; +enum insn_code sync_new_add_optab[NUM_MACHINE_MODES]; +enum insn_code sync_new_sub_optab[NUM_MACHINE_MODES]; +enum insn_code sync_new_ior_optab[NUM_MACHINE_MODES]; +enum insn_code sync_new_and_optab[NUM_MACHINE_MODES]; +enum insn_code sync_new_xor_optab[NUM_MACHINE_MODES]; +enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES]; +enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES]; +enum insn_code sync_compare_and_swap_cc[NUM_MACHINE_MODES]; +enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES]; +enum insn_code sync_lock_release[NUM_MACHINE_MODES]; + /* SLOW_UNALIGNED_ACCESS is nonzero if unaligned accesses are very slow. */ #ifndef SLOW_UNALIGNED_ACCESS @@ -325,8 +349,8 @@ convert_move (rtx to, rtx from, int unsignedp) { enum machine_mode to_mode = GET_MODE (to); enum machine_mode from_mode = GET_MODE (from); - int to_real = GET_MODE_CLASS (to_mode) == MODE_FLOAT; - int from_real = GET_MODE_CLASS (from_mode) == MODE_FLOAT; + int to_real = SCALAR_FLOAT_MODE_P (to_mode); + int from_real = SCALAR_FLOAT_MODE_P (from_mode); enum insn_code code; rtx libcall; @@ -441,19 +465,27 @@ convert_move (rtx to, rtx from, int unsignedp) } if (GET_MODE_CLASS (from_mode) == MODE_PARTIAL_INT) { + rtx new_from; enum machine_mode full_mode = smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT); gcc_assert (sext_optab->handlers[full_mode][from_mode].insn_code != CODE_FOR_nothing); - emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code, - to, from, UNKNOWN); if (to_mode == full_mode) - return; + { + emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code, + to, from, UNKNOWN); + return; + } + + new_from = gen_reg_rtx (full_mode); + emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code, + new_from, from, UNKNOWN); /* else proceed to integer conversions below. */ from_mode = full_mode; + from = new_from; } /* Now both modes are integers. */ @@ -610,9 +642,6 @@ convert_move (rtx to, rtx from, int unsignedp) if ((code = can_extend_p (to_mode, from_mode, unsignedp)) != CODE_FOR_nothing) { - if (flag_force_mem) - from = force_not_mem (from); - emit_unop_insn (code, to, from, equiv_code); return; } @@ -1123,6 +1152,7 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method) switch (method) { case BLOCK_OP_NORMAL: + case BLOCK_OP_TAILCALL: may_use_call = true; break; @@ -1171,7 +1201,8 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method) else if (emit_block_move_via_movmem (x, y, size, align)) ; else if (may_use_call) - retval = emit_block_move_via_libcall (x, y, size); + retval = emit_block_move_via_libcall (x, y, size, + method == BLOCK_OP_TAILCALL); else emit_block_move_via_loop (x, y, size, align); @@ -1219,8 +1250,7 @@ block_move_libcall_safe_for_call_parm (void) rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1); if (!tmp || !REG_P (tmp)) return false; - if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, - NULL_TREE, 1)) + if (targetm.calls.arg_partial_bytes (&args_so_far, mode, NULL, 1)) return false; FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1); } @@ -1301,7 +1331,7 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align) Return the return value from memcpy, 0 otherwise. */ static rtx -emit_block_move_via_libcall (rtx dst, rtx src, rtx size) +emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall) { rtx dst_addr, src_addr; tree call_expr, arg_list, fn, src_tree, dst_tree, size_tree; @@ -1343,6 +1373,7 @@ emit_block_move_via_libcall (rtx dst, rtx src, rtx size) call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn); call_expr = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), call_expr, arg_list, NULL_TREE); + CALL_EXPR_TAILCALL (call_expr) = tailcall; retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0); @@ -1650,6 +1681,11 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize) tmps[i] = gen_reg_rtx (mode); emit_move_insn (tmps[i], adjust_address (src, mode, bytepos)); } + else if (COMPLEX_MODE_P (mode) + && GET_MODE (src) == mode + && bytelen == GET_MODE_SIZE (mode)) + /* Let emit_move_complex do the bulk of the work. */ + tmps[i] = src; else if (GET_CODE (src) == CONCAT) { unsigned int slen = GET_MODE_SIZE (GET_MODE (src)); @@ -2398,95 +2434,60 @@ store_by_pieces_2 (rtx (*genfun) (rtx, ...), enum machine_mode mode, its length in bytes. */ rtx -clear_storage (rtx object, rtx size) +clear_storage (rtx object, rtx size, enum block_op_methods method) { - rtx retval = 0; - unsigned int align = (MEM_P (object) ? MEM_ALIGN (object) - : GET_MODE_ALIGNMENT (GET_MODE (object))); + enum machine_mode mode = GET_MODE (object); + unsigned int align; + + gcc_assert (method == BLOCK_OP_NORMAL || method == BLOCK_OP_TAILCALL); /* If OBJECT is not BLKmode and SIZE is the same size as its mode, just move a zero. Otherwise, do this a piece at a time. */ - if (GET_MODE (object) != BLKmode + if (mode != BLKmode && GET_CODE (size) == CONST_INT - && INTVAL (size) == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (object))) - emit_move_insn (object, CONST0_RTX (GET_MODE (object))); - else - { - if (size == const0_rtx) - ; - else if (GET_CODE (size) == CONST_INT - && CLEAR_BY_PIECES_P (INTVAL (size), align)) - clear_by_pieces (object, INTVAL (size), align); - else if (clear_storage_via_clrmem (object, size, align)) - ; - else - retval = clear_storage_via_libcall (object, size); - } - - return retval; -} - -/* A subroutine of clear_storage. Expand a clrmem pattern; - return true if successful. */ - -static bool -clear_storage_via_clrmem (rtx object, rtx size, unsigned int align) -{ - /* Try the most limited insn first, because there's no point - including more than one in the machine description unless - the more limited one has some advantage. */ - - rtx opalign = GEN_INT (align / BITS_PER_UNIT); - enum machine_mode mode; - - for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + && INTVAL (size) == (HOST_WIDE_INT) GET_MODE_SIZE (mode)) { - enum insn_code code = clrmem_optab[(int) mode]; - insn_operand_predicate_fn pred; - - if (code != CODE_FOR_nothing - /* We don't need MODE to be narrower than - BITS_PER_HOST_WIDE_INT here because if SIZE is less than - the mode mask, as it is returned by the macro, it will - definitely be less than the actual mode mask. */ - && ((GET_CODE (size) == CONST_INT - && ((unsigned HOST_WIDE_INT) INTVAL (size) - <= (GET_MODE_MASK (mode) >> 1))) - || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD) - && ((pred = insn_data[(int) code].operand[0].predicate) == 0 - || (*pred) (object, BLKmode)) - && ((pred = insn_data[(int) code].operand[2].predicate) == 0 - || (*pred) (opalign, VOIDmode))) + rtx zero = CONST0_RTX (mode); + if (zero != NULL) { - rtx op1; - rtx last = get_last_insn (); - rtx pat; - - op1 = convert_to_mode (mode, size, 1); - pred = insn_data[(int) code].operand[1].predicate; - if (pred != 0 && ! (*pred) (op1, mode)) - op1 = copy_to_mode_reg (mode, op1); + emit_move_insn (object, zero); + return NULL; + } - pat = GEN_FCN ((int) code) (object, op1, opalign); - if (pat) + if (COMPLEX_MODE_P (mode)) + { + zero = CONST0_RTX (GET_MODE_INNER (mode)); + if (zero != NULL) { - emit_insn (pat); - return true; + write_complex_part (object, zero, 0); + write_complex_part (object, zero, 1); + return NULL; } - else - delete_insns_since (last); } } - return false; + if (size == const0_rtx) + return NULL; + + align = MEM_ALIGN (object); + + if (GET_CODE (size) == CONST_INT + && CLEAR_BY_PIECES_P (INTVAL (size), align)) + clear_by_pieces (object, INTVAL (size), align); + else if (set_storage_via_setmem (object, size, const0_rtx, align)) + ; + else + return clear_storage_via_libcall (object, size, + method == BLOCK_OP_TAILCALL); + + return NULL; } /* A subroutine of clear_storage. Expand a call to memset. Return the return value of memset, 0 otherwise. */ static rtx -clear_storage_via_libcall (rtx object, rtx size) +clear_storage_via_libcall (rtx object, rtx size, bool tailcall) { tree call_expr, arg_list, fn, object_tree, size_tree; enum machine_mode size_mode; @@ -2519,6 +2520,7 @@ clear_storage_via_libcall (rtx object, rtx size) call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn); call_expr = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), call_expr, arg_list, NULL_TREE); + CALL_EXPR_TAILCALL (call_expr) = tailcall; retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0); @@ -2574,6 +2576,73 @@ clear_storage_libcall_fn (int for_call) return block_clear_fn; } +/* Expand a setmem pattern; return true if successful. */ + +bool +set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align) +{ + /* Try the most limited insn first, because there's no point + including more than one in the machine description unless + the more limited one has some advantage. */ + + rtx opalign = GEN_INT (align / BITS_PER_UNIT); + enum machine_mode mode; + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + enum insn_code code = setmem_optab[(int) mode]; + insn_operand_predicate_fn pred; + + if (code != CODE_FOR_nothing + /* We don't need MODE to be narrower than + BITS_PER_HOST_WIDE_INT here because if SIZE is less than + the mode mask, as it is returned by the macro, it will + definitely be less than the actual mode mask. */ + && ((GET_CODE (size) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (size) + <= (GET_MODE_MASK (mode) >> 1))) + || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD) + && ((pred = insn_data[(int) code].operand[0].predicate) == 0 + || (*pred) (object, BLKmode)) + && ((pred = insn_data[(int) code].operand[3].predicate) == 0 + || (*pred) (opalign, VOIDmode))) + { + rtx opsize, opchar; + enum machine_mode char_mode; + rtx last = get_last_insn (); + rtx pat; + + opsize = convert_to_mode (mode, size, 1); + pred = insn_data[(int) code].operand[1].predicate; + if (pred != 0 && ! (*pred) (opsize, mode)) + opsize = copy_to_mode_reg (mode, opsize); + + opchar = val; + char_mode = insn_data[(int) code].operand[2].mode; + if (char_mode != VOIDmode) + { + opchar = convert_to_mode (char_mode, opchar, 1); + pred = insn_data[(int) code].operand[2].predicate; + if (pred != 0 && ! (*pred) (opchar, char_mode)) + opchar = copy_to_mode_reg (char_mode, opchar); + } + + pat = GEN_FCN ((int) code) (object, opsize, opchar, opalign); + if (pat) + { + emit_insn (pat); + return true; + } + else + delete_insns_since (last); + } + } + + return false; +} + + /* Write to one of the components of the complex value CPLX. Write VAL to the real part if IMAG_P is false, and the imaginary part if its true. */ @@ -2594,18 +2663,45 @@ write_complex_part (rtx cplx, rtx val, bool imag_p) imode = GET_MODE_INNER (cmode); ibitsize = GET_MODE_BITSIZE (imode); + /* For MEMs simplify_gen_subreg may generate an invalid new address + because, e.g., the original address is considered mode-dependent + by the target, which restricts simplify_subreg from invoking + adjust_address_nv. Instead of preparing fallback support for an + invalid address, we call adjust_address_nv directly. */ + if (MEM_P (cplx)) + { + emit_move_insn (adjust_address_nv (cplx, imode, + imag_p ? GET_MODE_SIZE (imode) : 0), + val); + return; + } + /* If the sub-object is at least word sized, then we know that subregging will work. This special case is important, since store_bit_field wants to operate on integer modes, and there's rarely an OImode to correspond to TCmode. */ - if (ibitsize >= BITS_PER_WORD) + if (ibitsize >= BITS_PER_WORD + /* For hard regs we have exact predicates. Assume we can split + the original object if it spans an even number of hard regs. + This special case is important for SCmode on 64-bit platforms + where the natural size of floating-point regs is 32-bit. */ + || (REG_P (cplx) + && REGNO (cplx) < FIRST_PSEUDO_REGISTER + && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0)) { rtx part = simplify_gen_subreg (imode, cplx, cmode, imag_p ? GET_MODE_SIZE (imode) : 0); - emit_move_insn (part, val); + if (part) + { + emit_move_insn (part, val); + return; + } + else + /* simplify_gen_subreg may fail for sub-word MEMs. */ + gcc_assert (MEM_P (cplx) && ibitsize < BITS_PER_WORD); } - else - store_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0, imode, val); + + store_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0, imode, val); } /* Extract one of the components of the complex value CPLX. Extract the @@ -2636,63 +2732,79 @@ read_complex_part (rtx cplx, bool imag_p) } } + /* For MEMs simplify_gen_subreg may generate an invalid new address + because, e.g., the original address is considered mode-dependent + by the target, which restricts simplify_subreg from invoking + adjust_address_nv. Instead of preparing fallback support for an + invalid address, we call adjust_address_nv directly. */ + if (MEM_P (cplx)) + return adjust_address_nv (cplx, imode, + imag_p ? GET_MODE_SIZE (imode) : 0); + /* If the sub-object is at least word sized, then we know that subregging will work. This special case is important, since extract_bit_field wants to operate on integer modes, and there's rarely an OImode to correspond to TCmode. */ - if (ibitsize >= BITS_PER_WORD) + if (ibitsize >= BITS_PER_WORD + /* For hard regs we have exact predicates. Assume we can split + the original object if it spans an even number of hard regs. + This special case is important for SCmode on 64-bit platforms + where the natural size of floating-point regs is 32-bit. */ + || (REG_P (cplx) + && REGNO (cplx) < FIRST_PSEUDO_REGISTER + && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0)) { rtx ret = simplify_gen_subreg (imode, cplx, cmode, imag_p ? GET_MODE_SIZE (imode) : 0); - gcc_assert (ret != NULL); - return ret; + if (ret) + return ret; + else + /* simplify_gen_subreg may fail for sub-word MEMs. */ + gcc_assert (MEM_P (cplx) && ibitsize < BITS_PER_WORD); } return extract_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0, true, NULL_RTX, imode, imode); } -/* A subroutine of emit_move_insn_1. Generate a move from Y into X using - ALT_MODE instead of the operand's natural mode, MODE. CODE is the insn - code for the move in ALT_MODE, and is known to be valid. Returns the - instruction emitted. */ +/* A subroutine of emit_move_insn_1. Yet another lowpart generator. + NEW_MODE and OLD_MODE are the same size. Return NULL if X cannot be + represented in NEW_MODE. If FORCE is true, this will never happen, as + we'll force-create a SUBREG if needed. */ static rtx -emit_move_via_alt_mode (enum machine_mode alt_mode, enum machine_mode mode, - enum insn_code code, rtx x, rtx y) +emit_move_change_mode (enum machine_mode new_mode, + enum machine_mode old_mode, rtx x, bool force) { - /* Get X and Y in ALT_MODE. We can't use gen_lowpart here because it - may call change_address which is not appropriate if we were - called when a reload was in progress. We don't have to worry - about changing the address since the size in bytes is supposed to - be the same. Copy the MEM to change the mode and move any - substitutions from the old MEM to the new one. */ + rtx ret; - if (reload_in_progress) + if (reload_in_progress && MEM_P (x)) { - rtx x1 = x, y1 = y; + /* We can't use gen_lowpart here because it may call change_address + which is not appropriate if we were called when a reload was in + progress. We don't have to worry about changing the address since + the size in bytes is supposed to be the same. Copy the MEM to + change the mode and move any substitutions from the old MEM to + the new one. */ - x = gen_lowpart_common (alt_mode, x1); - if (x == 0 && MEM_P (x1)) - { - x = adjust_address_nv (x1, alt_mode, 0); - copy_replacements (x1, x); - } - - y = gen_lowpart_common (alt_mode, y1); - if (y == 0 && MEM_P (y1)) - { - y = adjust_address_nv (y1, alt_mode, 0); - copy_replacements (y1, y); - } + ret = adjust_address_nv (x, new_mode, 0); + copy_replacements (x, ret); } else { - x = simplify_gen_subreg (alt_mode, x, mode, 0); - y = simplify_gen_subreg (alt_mode, y, mode, 0); + /* Note that we do want simplify_subreg's behavior of validating + that the new mode is ok for a hard register. If we were to use + simplify_gen_subreg, we would create the subreg, but would + probably run into the target not being able to implement it. */ + /* Except, of course, when FORCE is true, when this is exactly what + we want. Which is needed for CCmodes on some targets. */ + if (force) + ret = simplify_gen_subreg (new_mode, x, old_mode, 0); + else + ret = simplify_subreg (new_mode, x, old_mode, 0); } - return emit_insn (GEN_FCN (code) (x, y)); + return ret; } /* A subroutine of emit_move_insn_1. Generate a move from Y into X using @@ -2700,7 +2812,7 @@ emit_move_via_alt_mode (enum machine_mode alt_mode, enum machine_mode mode, emitted, or NULL if such a move could not be generated. */ static rtx -emit_move_via_integer (enum machine_mode mode, rtx x, rtx y) +emit_move_via_integer (enum machine_mode mode, rtx x, rtx y, bool force) { enum machine_mode imode; enum insn_code code; @@ -2715,7 +2827,13 @@ emit_move_via_integer (enum machine_mode mode, rtx x, rtx y) if (code == CODE_FOR_nothing) return NULL_RTX; - return emit_move_via_alt_mode (imode, mode, code, x, y); + x = emit_move_change_mode (imode, mode, x, force); + if (x == NULL_RTX) + return NULL_RTX; + y = emit_move_change_mode (imode, mode, y, force); + if (y == NULL_RTX) + return NULL_RTX; + return emit_insn (GEN_FCN (code) (x, y)); } /* A subroutine of emit_move_insn_1. X is a push_operand in MODE. @@ -2734,6 +2852,19 @@ emit_move_resolve_push (enum machine_mode mode, rtx x) #endif if (code == PRE_DEC || code == POST_DEC) adjust = -adjust; + else if (code == PRE_MODIFY || code == POST_MODIFY) + { + rtx expr = XEXP (XEXP (x, 0), 1); + HOST_WIDE_INT val; + + gcc_assert (GET_CODE (expr) == PLUS || GET_CODE (expr) == MINUS); + gcc_assert (GET_CODE (XEXP (expr, 1)) == CONST_INT); + val = INTVAL (XEXP (expr, 1)); + if (GET_CODE (expr) == MINUS) + val = -val; + gcc_assert (adjust == val || adjust == -val); + adjust = val; + } /* Do not use anti_adjust_stack, since we don't want to update stack_pointer_delta. */ @@ -2747,13 +2878,13 @@ emit_move_resolve_push (enum machine_mode mode, rtx x) { case PRE_INC: case PRE_DEC: + case PRE_MODIFY: temp = stack_pointer_rtx; break; case POST_INC: - temp = plus_constant (stack_pointer_rtx, -GET_MODE_SIZE (mode)); - break; case POST_DEC: - temp = plus_constant (stack_pointer_rtx, GET_MODE_SIZE (mode)); + case POST_MODIFY: + temp = plus_constant (stack_pointer_rtx, -adjust); break; default: gcc_unreachable (); @@ -2819,19 +2950,14 @@ emit_move_complex (enum machine_mode mode, rtx x, rtx y) if (push_operand (x, mode)) return emit_move_complex_push (mode, x, y); - /* For memory to memory moves, optimial behaviour can be had with the - existing block move logic. */ - if (MEM_P (x) && MEM_P (y)) - { - emit_block_move (x, y, GEN_INT (GET_MODE_SIZE (mode)), - BLOCK_OP_NO_LIBCALL); - return get_last_insn (); - } - /* See if we can coerce the target into moving both values at once. */ + /* Move floating point as parts. */ + if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT + && mov_optab->handlers[GET_MODE_INNER (mode)].insn_code != CODE_FOR_nothing) + try_int = false; /* Not possible if the values are inherently not adjacent. */ - if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT) + else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT) try_int = false; /* Is possible if both are registers (or subregs of registers). */ else if (register_operand (x, mode) && register_operand (y, mode)) @@ -2849,7 +2975,18 @@ emit_move_complex (enum machine_mode mode, rtx x, rtx y) if (try_int) { - rtx ret = emit_move_via_integer (mode, x, y); + rtx ret; + + /* For memory to memory moves, optimal behavior can be had with the + existing block move logic. */ + if (MEM_P (x) && MEM_P (y)) + { + emit_block_move (x, y, GEN_INT (GET_MODE_SIZE (mode)), + BLOCK_OP_NO_LIBCALL); + return get_last_insn (); + } + + ret = emit_move_via_integer (mode, x, y, true); if (ret) return ret; } @@ -2879,11 +3016,15 @@ emit_move_ccmode (enum machine_mode mode, rtx x, rtx y) { enum insn_code code = mov_optab->handlers[CCmode].insn_code; if (code != CODE_FOR_nothing) - return emit_move_via_alt_mode (CCmode, mode, code, x, y); + { + x = emit_move_change_mode (CCmode, mode, x, true); + y = emit_move_change_mode (CCmode, mode, y, true); + return emit_insn (GEN_FCN (code) (x, y)); + } } /* Otherwise, find the MODE_INT mode of the same width. */ - ret = emit_move_via_integer (mode, x, y); + ret = emit_move_via_integer (mode, x, y, false); gcc_assert (ret != NULL); return ret; } @@ -2928,8 +3069,8 @@ emit_move_multi_word (enum machine_mode mode, rtx x, rtx y) rtx ypart = operand_subword (y, i, 1, mode); /* If we can't get a part of Y, put Y into memory if it is a - constant. Otherwise, force it into a register. If we still - can't get a part of Y, abort. */ + constant. Otherwise, force it into a register. Then we must + be able to get a part of Y. */ if (ypart == 0 && CONSTANT_P (y)) { y = force_const_mem (mode, y); @@ -2991,7 +3132,7 @@ emit_move_insn_1 (rtx x, rtx y) fits within a HOST_WIDE_INT. */ if (!CONSTANT_P (y) || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) { - rtx ret = emit_move_via_integer (mode, x, y); + rtx ret = emit_move_via_integer (mode, x, y, false); if (ret) return ret; } @@ -3076,9 +3217,15 @@ compress_float_constant (rtx x, rtx y) enum machine_mode orig_srcmode = GET_MODE (y); enum machine_mode srcmode; REAL_VALUE_TYPE r; + int oldcost, newcost; REAL_VALUE_FROM_CONST_DOUBLE (r, y); + if (LEGITIMATE_CONSTANT_P (y)) + oldcost = rtx_cost (y, SET); + else + oldcost = rtx_cost (force_const_mem (dstmode, y), SET); + for (srcmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_srcmode)); srcmode != orig_srcmode; srcmode = GET_MODE_WIDER_MODE (srcmode)) @@ -3103,12 +3250,23 @@ compress_float_constant (rtx x, rtx y) the extension. */ if (! (*insn_data[ic].operand[1].predicate) (trunc_y, srcmode)) continue; + /* This is valid, but may not be cheaper than the original. */ + newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET); + if (oldcost < newcost) + continue; } else if (float_extend_from_mem[dstmode][srcmode]) - trunc_y = validize_mem (force_const_mem (srcmode, trunc_y)); + { + trunc_y = force_const_mem (srcmode, trunc_y); + /* This is valid, but may not be cheaper than the original. */ + newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET); + if (oldcost < newcost) + continue; + trunc_y = validize_mem (trunc_y); + } else continue; - + emit_unop_insn (ic, x, trunc_y, UNKNOWN); last_insn = get_last_insn (); @@ -3278,9 +3436,8 @@ emit_single_push_insn (enum machine_mode mode, rtx x, tree type) ALIGN (in bits) is maximum alignment we can assume. If PARTIAL and REG are both nonzero, then copy that many of the first - words of X into registers starting with REG, and push the rest of X. - The amount of space pushed is decreased by PARTIAL words, - rounded *down* to a multiple of PARM_BOUNDARY. + bytes of X into registers starting with REG, and push the rest of X. + The amount of space pushed is decreased by PARTIAL bytes. REG must be a hard register in this case. If REG is zero but PARTIAL is not, take any all others actions for an argument partially in registers, but do not actually load any @@ -3332,24 +3489,15 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size, /* Copy a block into the stack, entirely or partially. */ rtx temp; - int used = partial * UNITS_PER_WORD; + int used; int offset; int skip; - if (reg && GET_CODE (reg) == PARALLEL) - { - /* Use the size of the elt to compute offset. */ - rtx elt = XEXP (XVECEXP (reg, 0, 0), 0); - used = partial * GET_MODE_SIZE (GET_MODE (elt)); - offset = used % (PARM_BOUNDARY / BITS_PER_UNIT); - } - else - offset = used % (PARM_BOUNDARY / BITS_PER_UNIT); + offset = partial % (PARM_BOUNDARY / BITS_PER_UNIT); + used = partial - offset; gcc_assert (size); - used -= offset; - /* USED is now the # of bytes we need not copy to the stack because registers will take care of them. */ @@ -3460,9 +3608,9 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size, int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD; int i; int not_stack; - /* # words of start of argument + /* # bytes of start of argument that we must make space for but need not store. */ - int offset = partial % (PARM_BOUNDARY / BITS_PER_WORD); + int offset = partial % (PARM_BOUNDARY / BITS_PER_UNIT); int args_offset = INTVAL (args_so_far); int skip; @@ -3480,8 +3628,9 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size, offset = 0; /* Now NOT_STACK gets the number of words that we don't need to - allocate on the stack. */ - not_stack = partial - offset; + allocate on the stack. Convert OFFSET to words too. */ + not_stack = (partial - offset) / UNITS_PER_WORD; + offset /= UNITS_PER_WORD; /* If the partial register-part of the arg counts in its stack size, skip the part of stack space corresponding to the registers. @@ -3565,7 +3714,10 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size, if (GET_CODE (reg) == PARALLEL) emit_group_load (reg, x, type, -1); else - move_block_to_reg (REGNO (reg), x, partial, mode); + { + gcc_assert (partial % UNITS_PER_WORD == 0); + move_block_to_reg (REGNO (reg), x, partial / UNITS_PER_WORD, mode); + } } if (extra && args_addr == 0 && where_pad == stack_direction) @@ -3700,6 +3852,41 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize, emit_move_insn (str_rtx, result); return true; + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + if (TREE_CODE (op1) != INTEGER_CST) + break; + value = expand_expr (op1, NULL_RTX, GET_MODE (str_rtx), 0); + value = convert_modes (GET_MODE (str_rtx), + TYPE_MODE (TREE_TYPE (op1)), value, + TYPE_UNSIGNED (TREE_TYPE (op1))); + + /* We may be accessing data outside the field, which means + we can alias adjacent data. */ + if (MEM_P (str_rtx)) + { + str_rtx = shallow_copy_rtx (str_rtx); + set_mem_alias_set (str_rtx, 0); + set_mem_expr (str_rtx, 0); + } + + binop = TREE_CODE (src) == BIT_IOR_EXPR ? ior_optab : xor_optab; + if (bitpos + bitsize != GET_MODE_BITSIZE (GET_MODE (str_rtx))) + { + rtx mask = GEN_INT (((unsigned HOST_WIDE_INT) 1 << bitsize) + - 1); + value = expand_and (GET_MODE (str_rtx), value, mask, + NULL_RTX); + } + value = expand_shift (LSHIFT_EXPR, GET_MODE (str_rtx), value, + build_int_cst (NULL_TREE, bitpos), + NULL_RTX, 1); + result = expand_binop (GET_MODE (str_rtx), binop, str_rtx, + value, str_rtx, 1, OPTAB_WIDEN); + if (result != str_rtx) + emit_move_insn (str_rtx, result); + return true; + default: break; } @@ -3734,7 +3921,6 @@ expand_assignment (tree to, tree from) { enum machine_mode mode1; HOST_WIDE_INT bitsize, bitpos; - rtx orig_to_rtx; tree offset; int unsignedp; int volatilep = 0; @@ -3742,19 +3928,27 @@ expand_assignment (tree to, tree from) push_temp_slots (); tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1, - &unsignedp, &volatilep); + &unsignedp, &volatilep, true); /* If we are going to use store_bit_field and extract_bit_field, make sure to_rtx will be safe for multiple use. */ - orig_to_rtx = to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0); + to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0); if (offset != 0) { - rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM); + rtx offset_rtx; - gcc_assert (MEM_P (to_rtx)); + if (!MEM_P (to_rtx)) + { + /* We can get constant negative offsets into arrays with broken + user code. Translate this to a trap instead of ICEing. */ + gcc_assert (TREE_CODE (offset) == INTEGER_CST); + expand_builtin_trap (); + to_rtx = gen_rtx_MEM (BLKmode, const0_rtx); + } + offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM); #ifdef POINTERS_EXTEND_UNSIGNED if (GET_MODE (offset_rtx) != Pmode) offset_rtx = convert_to_mode (Pmode, offset_rtx, 0); @@ -4102,10 +4296,10 @@ store_expr (tree exp, rtx target, int call_param_p) but TARGET is not valid memory reference, TEMP will differ from TARGET although it is really the same location. */ && !(alt_rtl && rtx_equal_p (alt_rtl, target)) - /* If there's nothing to copy, don't bother. Don't call expr_size - unless necessary, because some front-ends (C++) expr_size-hook - aborts on objects that are not supposed to be bit-copied or - bit-initialized. */ + /* If there's nothing to copy, don't bother. Don't call + expr_size unless necessary, because some front-ends (C++) + expr_size-hook must not be given objects that are not + supposed to be bit-copied or bit-initialized. */ && expr_size (exp) != const0_rtx) { if (GET_MODE (temp) != GET_MODE (target) @@ -4185,7 +4379,7 @@ store_expr (tree exp, rtx target, int call_param_p) } if (size != const0_rtx) - clear_storage (target, size); + clear_storage (target, size, BLOCK_OP_NORMAL); if (label) emit_label (label); @@ -4211,24 +4405,32 @@ store_expr (tree exp, rtx target, int call_param_p) return NULL_RTX; } -/* Examine CTOR. Discover how many scalar fields are set to nonzero - values and place it in *P_NZ_ELTS. Discover how many scalar fields - are set to non-constant values and place it in *P_NC_ELTS. */ +/* Examine CTOR to discover: + * how many scalar fields are set to nonzero values, + and place it in *P_NZ_ELTS; + * how many scalar fields are set to non-constant values, + and place it in *P_NC_ELTS; and + * how many scalar fields in total are in CTOR, + and place it in *P_ELT_COUNT. + * if a type is a union, and the initializer from the constructor + is not the largest element in the union, then set *p_must_clear. */ static void categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, - HOST_WIDE_INT *p_nc_elts) + HOST_WIDE_INT *p_nc_elts, + HOST_WIDE_INT *p_elt_count, + bool *p_must_clear) { - HOST_WIDE_INT nz_elts, nc_elts; - tree list; + unsigned HOST_WIDE_INT idx; + HOST_WIDE_INT nz_elts, nc_elts, elt_count; + tree value, purpose; nz_elts = 0; nc_elts = 0; + elt_count = 0; - for (list = CONSTRUCTOR_ELTS (ctor); list; list = TREE_CHAIN (list)) + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value) { - tree value = TREE_VALUE (list); - tree purpose = TREE_PURPOSE (list); HOST_WIDE_INT mult; mult = 1; @@ -4246,10 +4448,11 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, { case CONSTRUCTOR: { - HOST_WIDE_INT nz = 0, nc = 0; - categorize_ctor_elements_1 (value, &nz, &nc); + HOST_WIDE_INT nz = 0, nc = 0, ic = 0; + categorize_ctor_elements_1 (value, &nz, &nc, &ic, p_must_clear); nz_elts += mult * nz; nc_elts += mult * nc; + elt_count += mult * ic; } break; @@ -4257,10 +4460,12 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, case REAL_CST: if (!initializer_zerop (value)) nz_elts += mult; + elt_count += mult; break; case STRING_CST: nz_elts += mult * TREE_STRING_LENGTH (value); + elt_count += mult * TREE_STRING_LENGTH (value); break; case COMPLEX_CST: @@ -4268,43 +4473,91 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, nz_elts += mult; if (!initializer_zerop (TREE_IMAGPART (value))) nz_elts += mult; + elt_count += mult; break; case VECTOR_CST: { tree v; for (v = TREE_VECTOR_CST_ELTS (value); v; v = TREE_CHAIN (v)) - if (!initializer_zerop (TREE_VALUE (v))) - nz_elts += mult; + { + if (!initializer_zerop (TREE_VALUE (v))) + nz_elts += mult; + elt_count += mult; + } } break; default: nz_elts += mult; + elt_count += mult; if (!initializer_constant_valid_p (value, TREE_TYPE (value))) nc_elts += mult; break; } } + if (!*p_must_clear + && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (ctor)) == QUAL_UNION_TYPE)) + { + tree init_sub_type; + bool clear_this = true; + + if (!VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor))) + { + /* We don't expect more than one element of the union to be + initialized. Not sure what we should do otherwise... */ + gcc_assert (VEC_length (constructor_elt, CONSTRUCTOR_ELTS (ctor)) + == 1); + + init_sub_type = TREE_TYPE (VEC_index (constructor_elt, + CONSTRUCTOR_ELTS (ctor), + 0)->value); + + /* ??? We could look at each element of the union, and find the + largest element. Which would avoid comparing the size of the + initialized element against any tail padding in the union. + Doesn't seem worth the effort... */ + if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)), + TYPE_SIZE (init_sub_type)) == 1) + { + /* And now we have to find out if the element itself is fully + constructed. E.g. for union { struct { int a, b; } s; } u + = { .s = { .a = 1 } }. */ + if (elt_count == count_type_elements (init_sub_type, false)) + clear_this = false; + } + } + + *p_must_clear = clear_this; + } + *p_nz_elts += nz_elts; *p_nc_elts += nc_elts; + *p_elt_count += elt_count; } void categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts, - HOST_WIDE_INT *p_nc_elts) + HOST_WIDE_INT *p_nc_elts, + HOST_WIDE_INT *p_elt_count, + bool *p_must_clear) { *p_nz_elts = 0; *p_nc_elts = 0; - categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts); + *p_elt_count = 0; + *p_must_clear = false; + categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count, + p_must_clear); } /* Count the number of scalars in TYPE. Return -1 on overflow or - variable-sized. */ + variable-sized. If ALLOW_FLEXARR is true, don't count flexible + array member at the end of the structure. */ HOST_WIDE_INT -count_type_elements (tree type) +count_type_elements (tree type, bool allow_flexarr) { const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1)); switch (TREE_CODE (type)) @@ -4315,7 +4568,7 @@ count_type_elements (tree type) if (telts && host_integerp (telts, 1)) { HOST_WIDE_INT n = tree_low_cst (telts, 1) + 1; - HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type)); + HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type), false); if (n == 0) return 0; else if (max / n > m) @@ -4332,9 +4585,23 @@ count_type_elements (tree type) for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f)) if (TREE_CODE (f) == FIELD_DECL) { - t = count_type_elements (TREE_TYPE (f)); + t = count_type_elements (TREE_TYPE (f), false); if (t < 0) - return -1; + { + /* Check for structures with flexible array member. */ + tree tf = TREE_TYPE (f); + if (allow_flexarr + && TREE_CHAIN (f) == NULL + && TREE_CODE (tf) == ARRAY_TYPE + && TYPE_DOMAIN (tf) + && TYPE_MIN_VALUE (TYPE_DOMAIN (tf)) + && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (tf))) + && !TYPE_MAX_VALUE (TYPE_DOMAIN (tf)) + && int_size_in_bytes (type) >= 0) + break; + + return -1; + } n += t; } @@ -4370,7 +4637,6 @@ count_type_elements (tree type) case VOID_TYPE: case METHOD_TYPE: - case FILE_TYPE: case FUNCTION_TYPE: case LANG_TYPE: default: @@ -4386,16 +4652,38 @@ mostly_zeros_p (tree exp) if (TREE_CODE (exp) == CONSTRUCTOR) { - HOST_WIDE_INT nz_elts, nc_elts, elts; + HOST_WIDE_INT nz_elts, nc_elts, count, elts; + bool must_clear; + + categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear); + if (must_clear) + return 1; - categorize_ctor_elements (exp, &nz_elts, &nc_elts); - elts = count_type_elements (TREE_TYPE (exp)); + elts = count_type_elements (TREE_TYPE (exp), false); return nz_elts < elts / 4; } return initializer_zerop (exp); } + +/* Return 1 if EXP contains all zeros. */ + +static int +all_zeros_p (tree exp) +{ + if (TREE_CODE (exp) == CONSTRUCTOR) + + { + HOST_WIDE_INT nz_elts, nc_elts, count; + bool must_clear; + + categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear); + return nz_elts == 0; + } + + return initializer_zerop (exp); +} /* Helper function for store_constructor. TARGET, BITSIZE, BITPOS, MODE, EXP are as for store_field. @@ -4468,7 +4756,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) case UNION_TYPE: case QUAL_UNION_TYPE: { - tree elt; + unsigned HOST_WIDE_INT idx; + tree field, value; /* If size is zero or the target is already cleared, do nothing. */ if (size == 0 || cleared) @@ -4479,7 +4768,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) && ! CONSTRUCTOR_ELTS (exp)) /* If the constructor is empty, clear the union. */ { - clear_storage (target, expr_size (exp)); + clear_storage (target, expr_size (exp), BLOCK_OP_NORMAL); cleared = 1; } @@ -4500,14 +4789,14 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) register whose mode size isn't equal to SIZE since clear_storage can't handle this case. */ else if (size > 0 - && ((list_length (CONSTRUCTOR_ELTS (exp)) + && (((int)VEC_length (constructor_elt, CONSTRUCTOR_ELTS (exp)) != fields_length (type)) || mostly_zeros_p (exp)) && (!REG_P (target) || ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target)) == size))) { - clear_storage (target, GEN_INT (size)); + clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL); cleared = 1; } @@ -4516,11 +4805,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) /* Store each element of the constructor into the corresponding field of TARGET. */ - - for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt)) + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, field, value) { - tree field = TREE_PURPOSE (elt); - tree value = TREE_VALUE (elt); enum machine_mode mode; HOST_WIDE_INT bitsize; HOST_WIDE_INT bitpos = 0; @@ -4603,9 +4889,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) if (BYTES_BIG_ENDIAN) value - = fold (build2 (LSHIFT_EXPR, type, value, - build_int_cst (NULL_TREE, - BITS_PER_WORD - bitsize))); + = fold_build2 (LSHIFT_EXPR, type, value, + build_int_cst (NULL_TREE, + BITS_PER_WORD - bitsize)); bitsize = BITS_PER_WORD; mode = word_mode; } @@ -4626,8 +4912,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) } case ARRAY_TYPE: { - tree elt; - int i; + tree value, index; + unsigned HOST_WIDE_INT i; int need_to_clear; tree domain; tree elttype = TREE_TYPE (type); @@ -4657,18 +4943,20 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) need_to_clear = 1; else { + unsigned HOST_WIDE_INT idx; + tree index, value; 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 mostly_zeros_p (it handles RANGE_EXPR in an index). It is also needed to check for missing elements. */ - for (elt = CONSTRUCTOR_ELTS (exp); - elt != NULL_TREE && ! need_to_clear; - elt = TREE_CHAIN (elt)) + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, index, value) { - tree index = TREE_PURPOSE (elt); HOST_WIDE_INT this_node_count; + + if (need_to_clear) + break; if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR) { @@ -4689,7 +4977,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) this_node_count = 1; count += this_node_count; - if (mostly_zeros_p (TREE_VALUE (elt))) + if (mostly_zeros_p (value)) zero_count += this_node_count; } @@ -4707,7 +4995,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) if (REG_P (target)) emit_move_insn (target, CONST0_RTX (GET_MODE (target))); else - clear_storage (target, GEN_INT (size)); + clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL); cleared = 1; } @@ -4718,16 +5006,12 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) /* Store each element of the constructor into the corresponding element of TARGET, determined by counting the elements. */ - for (elt = CONSTRUCTOR_ELTS (exp), i = 0; - elt; - elt = TREE_CHAIN (elt), i++) + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), i, index, value) { enum machine_mode mode; HOST_WIDE_INT bitsize; HOST_WIDE_INT bitpos; int unsignedp; - tree value = TREE_VALUE (elt); - tree index = TREE_PURPOSE (elt); rtx xtarget = target; if (cleared && initializer_zerop (value)) @@ -4806,8 +5090,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) /* Assign value to element index. */ position = convert (ssizetype, - fold (build2 (MINUS_EXPR, TREE_TYPE (index), - index, TYPE_MIN_VALUE (domain)))); + fold_build2 (MINUS_EXPR, TREE_TYPE (index), + index, TYPE_MIN_VALUE (domain))); position = size_binop (MULT_EXPR, position, convert (ssizetype, TYPE_SIZE_UNIT (elttype))); @@ -4849,10 +5133,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) if (minelt) index = fold_convert (ssizetype, - fold (build2 (MINUS_EXPR, - TREE_TYPE (index), - index, - TYPE_MIN_VALUE (domain)))); + fold_build2 (MINUS_EXPR, + TREE_TYPE (index), + index, + TYPE_MIN_VALUE (domain))); position = size_binop (MULT_EXPR, index, convert (ssizetype, @@ -4887,7 +5171,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) case VECTOR_TYPE: { - tree elt; + unsigned HOST_WIDE_INT idx; + constructor_elt *ce; int i; int need_to_clear; int icode = 0; @@ -4896,7 +5181,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) enum machine_mode eltmode = TYPE_MODE (elttype); HOST_WIDE_INT bitsize; HOST_WIDE_INT bitpos; - rtx *vector = NULL; + rtvec vector = NULL; unsigned n_elts; gcc_assert (eltmode != BLKmode); @@ -4911,9 +5196,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) { unsigned int i; - vector = alloca (n_elts); + vector = rtvec_alloc (n_elts); for (i = 0; i < n_elts; i++) - vector [i] = CONST0_RTX (GET_MODE_INNER (mode)); + RTVEC_ELT (vector, i) = CONST0_RTX (GET_MODE_INNER (mode)); } } @@ -4927,18 +5212,17 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) else { unsigned HOST_WIDE_INT count = 0, zero_count = 0; + tree value; - for (elt = CONSTRUCTOR_ELTS (exp); - elt != NULL_TREE; - elt = TREE_CHAIN (elt)) + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value) { int n_elts_here = tree_low_cst (int_const_binop (TRUNC_DIV_EXPR, - TYPE_SIZE (TREE_TYPE (TREE_VALUE (elt))), + TYPE_SIZE (TREE_TYPE (value)), TYPE_SIZE (elttype), 0), 1); count += n_elts_here; - if (mostly_zeros_p (TREE_VALUE (elt))) + if (mostly_zeros_p (value)) zero_count += n_elts_here; } @@ -4952,30 +5236,29 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) if (REG_P (target)) emit_move_insn (target, CONST0_RTX (GET_MODE (target))); else - clear_storage (target, GEN_INT (size)); + clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL); cleared = 1; } + /* Inform later passes that the old value is dead. */ if (!cleared && REG_P (target)) - /* Inform later passes that the old value is dead. */ - emit_insn (gen_rtx_CLOBBER (VOIDmode, target)); + emit_move_insn (target, CONST0_RTX (GET_MODE (target))); /* Store each element of the constructor into the corresponding element of TARGET, determined by counting the elements. */ - for (elt = CONSTRUCTOR_ELTS (exp), i = 0; - elt; - elt = TREE_CHAIN (elt), i += bitsize / elt_size) + for (idx = 0, i = 0; + VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), idx, ce); + idx++, i += bitsize / elt_size) { - tree value = TREE_VALUE (elt); - tree index = TREE_PURPOSE (elt); HOST_WIDE_INT eltpos; + tree value = ce->value; bitsize = tree_low_cst (TYPE_SIZE (TREE_TYPE (value)), 1); if (cleared && initializer_zerop (value)) continue; - if (index != 0) - eltpos = tree_low_cst (index, 1); + if (ce->index) + eltpos = tree_low_cst (ce->index, 1); else eltpos = i; @@ -4984,7 +5267,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) /* Vector CONSTRUCTORs should only be built from smaller vectors in the case of BLKmode vectors. */ gcc_assert (TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE); - vector[eltpos] = expand_expr (value, NULL_RTX, VOIDmode, 0); + RTVEC_ELT (vector, eltpos) + = expand_expr (value, NULL_RTX, VOIDmode, 0); } else { @@ -5002,8 +5286,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) if (vector) emit_insn (GEN_FCN (icode) (target, - gen_rtx_PARALLEL (GET_MODE (target), - gen_rtvec_v (n_elts, vector)))); + gen_rtx_PARALLEL (GET_MODE (target), vector))); break; } @@ -5103,7 +5386,27 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0)) { - rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0); + rtx temp; + + /* If EXP is a NOP_EXPR of precision less than its mode, then that + implies a mask operation. If the precision is the same size as + the field we're storing into, that mask is redundant. This is + particularly common with bit field assignments generated by the + C front end. */ + if (TREE_CODE (exp) == NOP_EXPR) + { + tree type = TREE_TYPE (exp); + if (INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) < GET_MODE_BITSIZE (TYPE_MODE (type)) + && bitsize == TYPE_PRECISION (type)) + { + type = TREE_TYPE (TREE_OPERAND (exp, 0)); + if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) >= bitsize) + exp = TREE_OPERAND (exp, 0); + } + } + + temp = expand_expr (exp, NULL_RTX, VOIDmode, 0); /* If BITSIZE is narrower than the size of the type of EXP we will be narrowing TEMP. Normally, what's wanted are the @@ -5181,13 +5484,27 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, If the field describes a variable-sized object, *PMODE is set to VOIDmode and *PBITSIZE is set to -1. An access cannot be made in - this case, but the address of the object can be found. */ + this case, but the address of the object can be found. + + If KEEP_ALIGNING is true and the target is STRICT_ALIGNMENT, we don't + look through nodes that serve as markers of a greater alignment than + the one that can be deduced from the expression. These nodes make it + possible for front-ends to prevent temporaries from being created by + the middle-end on alignment considerations. For that purpose, the + normal operating mode at high-level is to always pass FALSE so that + the ultimate containing object is really returned; moreover, the + associated predicate handled_component_p will always return TRUE + on these nodes, thus indicating that they are essentially handled + by get_inner_reference. TRUE should only be passed when the caller + is scanning the expression in order to build another representation + and specifically knows how to handle these nodes; as such, this is + the normal operating mode in the RTL expanders. */ tree get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, HOST_WIDE_INT *pbitpos, tree *poffset, enum machine_mode *pmode, int *punsignedp, - int *pvolatilep) + int *pvolatilep, bool keep_aligning) { tree size_tree = 0; enum machine_mode mode = VOIDmode; @@ -5271,8 +5588,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, index, then convert to sizetype and multiply by the size of the array element. */ if (! integer_zerop (low_bound)) - index = fold (build2 (MINUS_EXPR, TREE_TYPE (index), - index, low_bound)); + index = fold_build2 (MINUS_EXPR, TREE_TYPE (index), + index, low_bound); offset = size_binop (PLUS_EXPR, offset, size_binop (MULT_EXPR, @@ -5289,14 +5606,10 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, bitsize_int (*pbitsize)); break; - /* We can go inside most conversions: all NON_VALUE_EXPRs, all normal - conversions that don't change the mode, and all view conversions - except those that need to "step up" the alignment. */ - case VIEW_CONVERT_EXPR: - if ((TYPE_ALIGN (TREE_TYPE (exp)) + if (keep_aligning && STRICT_ALIGNMENT + && (TYPE_ALIGN (TREE_TYPE (exp)) > TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))) - && STRICT_ALIGNMENT && (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0))) < BIGGEST_ALIGNMENT) && (TYPE_ALIGN_OK (TREE_TYPE (exp)) @@ -5567,8 +5880,20 @@ force_operand (rtx value, rtx target) } if (UNARY_P (value)) { + int unsignedp = 0; + op1 = force_operand (XEXP (value, 0), NULL_RTX); - return expand_simple_unop (GET_MODE (value), code, op1, target, 0); + switch (code) + { + case ZERO_EXTEND: case UNSIGNED_FIX: case UNSIGNED_FLOAT: + unsignedp = 1; + /* fall through. */ + case TRUNCATE: + case SIGN_EXTEND: case FIX: case FLOAT: + return convert_to_mode (GET_MODE (value), op1, unsignedp); + default: + return expand_simple_unop (GET_MODE (value), code, op1, target, 0); + } } #ifdef INSN_SCHEDULING @@ -5790,7 +6115,7 @@ safe_from_p (rtx x, tree exp, int top_p) /* Return the highest power of two that EXP is known to be a multiple of. This is used in updating alignment of MEMs in array references. */ -static unsigned HOST_WIDE_INT +unsigned HOST_WIDE_INT highest_pow2_factor (tree exp) { unsigned HOST_WIDE_INT c0, c1; @@ -5891,7 +6216,7 @@ expand_var (tree var) ? !TREE_ASM_WRITTEN (var) : !DECL_RTL_SET_P (var)) { - if (TREE_CODE (var) == VAR_DECL && DECL_VALUE_EXPR (var)) + if (TREE_CODE (var) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (var)) /* Should be ignored. */; else if (lang_hooks.expand_decl (var)) /* OK. */; @@ -6003,7 +6328,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, /* If the DECL isn't in memory, then the DECL wasn't properly marked TREE_ADDRESSABLE, which will be either a front-end or a tree optimizer bug. */ - gcc_assert (GET_CODE (result) == MEM); + gcc_assert (MEM_P (result)); result = XEXP (result, 0); /* ??? Is this needed anymore? */ @@ -6019,8 +6344,13 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, return result; } + /* Pass FALSE as the last argument to get_inner_reference although + we are expanding to RTL. The rationale is that we know how to + handle "aligning nodes" here: we can just bypass them because + they won't change the final object whose address will be returned + (they actually exist only for that purpose). */ inner = get_inner_reference (exp, &bitsize, &bitpos, &offset, - &mode1, &unsignedp, &volatilep); + &mode1, &unsignedp, &volatilep, false); break; } @@ -6041,7 +6371,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, result = convert_memory_address (tmode, result); tmp = convert_memory_address (tmode, tmp); - if (modifier == EXPAND_SUM) + if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER) result = gen_rtx_PLUS (tmode, result, tmp); else { @@ -6183,7 +6513,7 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, information. It would be better of the diagnostic routines used the file/line information embedded in the tree nodes rather than globals. */ - if (cfun && EXPR_HAS_LOCATION (exp)) + if (cfun && cfun->ib_boundaries_block && EXPR_HAS_LOCATION (exp)) { location_t saved_location = input_location; input_location = EXPR_LOCATION (exp); @@ -6238,7 +6568,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, optab this_optab; rtx subtarget, original_target; int ignore; - tree context; + tree context, subexp0, subexp1; bool reduce_bit_field = false; #define REDUCE_BIT_FIELD(expr) (reduce_bit_field && !ignore \ ? reduce_to_bit_field_precision ((expr), \ @@ -6317,18 +6647,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, target = 0; } - /* If will do cse, generate all results into pseudo registers - since 1) that allows cse to find more things - and 2) otherwise cse could produce an insn the machine - cannot support. An exception is a CONSTRUCTOR into a multi-word - MEM: that's much more likely to be most efficient into the MEM. - Another is a CALL_EXPR which must return in memory. */ - - if (! cse_not_expected && mode != BLKmode && target - && (!REG_P (target) || REGNO (target) < FIRST_PSEUDO_REGISTER) - && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD) - && ! (code == CALL_EXPR && aggregate_value_p (exp, exp))) - target = 0; switch (code) { @@ -6467,8 +6785,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_FLOAT) return const_vector_from_tree (exp); else - return expand_expr (build1 (CONSTRUCTOR, TREE_TYPE (exp), - TREE_VECTOR_CST_ELTS (exp)), + return expand_expr (build_constructor_from_list + (TREE_TYPE (exp), + TREE_VECTOR_CST_ELTS (exp)), ignore ? const0_rtx : target, tmode, modifier); case CONST_DECL: @@ -6566,14 +6885,28 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, subexpressions. */ if (ignore) { - tree elt; + unsigned HOST_WIDE_INT idx; + tree value; - for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt)) - expand_expr (TREE_VALUE (elt), const0_rtx, VOIDmode, 0); + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value) + expand_expr (value, const0_rtx, VOIDmode, 0); return const0_rtx; } + /* Try to avoid creating a temporary at all. This is possible + if all of the initializer is zero. + FIXME: try to handle all [0..255] initializers we can handle + with memset. */ + else if (TREE_STATIC (exp) + && !TREE_ADDRESSABLE (exp) + && target != 0 && mode == BLKmode + && all_zeros_p (exp)) + { + clear_storage (target, expr_size (exp), BLOCK_OP_NORMAL); + return target; + } + /* All elts simple constants => refer to a constant in memory. But if this is a non-BLKmode mode, let it store a field at a time since that should make a CONST_INT or CONST_DOUBLE when we @@ -6632,11 +6965,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, case INDIRECT_REF: { tree exp1 = TREE_OPERAND (exp, 0); - tree orig; - - if (code == MISALIGNED_INDIRECT_REF - && !targetm.vectorize.misaligned_mem_ok (mode)) - abort (); if (modifier != EXPAND_WRITE) { @@ -6659,14 +6987,51 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, temp = gen_rtx_MEM (mode, op0); - orig = REF_ORIGINAL (exp); - if (!orig) - orig = exp; - set_mem_attributes (temp, orig, 0); + set_mem_attributes (temp, exp, 0); + + /* Resolve the misalignment now, so that we don't have to remember + to resolve it later. Of course, this only works for reads. */ + /* ??? When we get around to supporting writes, we'll have to handle + this in store_expr directly. The vectorizer isn't generating + those yet, however. */ + if (code == MISALIGNED_INDIRECT_REF) + { + int icode; + rtx reg, insn; + + gcc_assert (modifier == EXPAND_NORMAL + || modifier == EXPAND_STACK_PARM); + + /* The vectorizer should have already checked the mode. */ + icode = movmisalign_optab->handlers[mode].insn_code; + gcc_assert (icode != CODE_FOR_nothing); + + /* We've already validated the memory, and we're creating a + new pseudo destination. The predicates really can't fail. */ + reg = gen_reg_rtx (mode); + + /* Nor can the insn generator. */ + insn = GEN_FCN (icode) (reg, temp); + emit_insn (insn); + + return reg; + } return temp; } + case TARGET_MEM_REF: + { + struct mem_address addr; + + get_address_description (exp, &addr); + op0 = addr_for_mem_ref (&addr, true); + op0 = memory_address (mode, op0); + temp = gen_rtx_MEM (mode, op0); + set_mem_attributes (temp, TMR_ORIGINAL (exp), 0); + } + return temp; + case ARRAY_REF: { @@ -6700,16 +7065,17 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, && ! TREE_SIDE_EFFECTS (array) && TREE_CODE (index) == INTEGER_CST) { - tree elem; + unsigned HOST_WIDE_INT ix; + tree field, value; - for (elem = CONSTRUCTOR_ELTS (array); - (elem && !tree_int_cst_equal (TREE_PURPOSE (elem), index)); - elem = TREE_CHAIN (elem)) - ; - - if (elem && !TREE_SIDE_EFFECTS (TREE_VALUE (elem))) - return expand_expr (fold (TREE_VALUE (elem)), target, tmode, - modifier); + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (array), ix, + field, value) + if (tree_int_cst_equal (field, index)) + { + if (!TREE_SIDE_EFFECTS (value)) + return expand_expr (fold (value), target, tmode, modifier); + break; + } } else if (optimize >= 1 @@ -6727,17 +7093,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, if (TREE_CODE (init) == CONSTRUCTOR) { - tree elem; - - for (elem = CONSTRUCTOR_ELTS (init); - (elem - && !tree_int_cst_equal (TREE_PURPOSE (elem), index)); - elem = TREE_CHAIN (elem)) - ; - - if (elem && !TREE_SIDE_EFFECTS (TREE_VALUE (elem))) - return expand_expr (fold (TREE_VALUE (elem)), target, - tmode, modifier); + unsigned HOST_WIDE_INT ix; + tree field, value; + + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix, + field, value) + if (tree_int_cst_equal (field, index)) + { + if (!TREE_SIDE_EFFECTS (value)) + return expand_expr (fold (value), target, tmode, + modifier); + break; + } } else if (TREE_CODE (init) == STRING_CST && 0 > compare_tree_int (index, @@ -6761,11 +7128,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, appropriate field if it is present. */ if (TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR) { - tree elt; + unsigned HOST_WIDE_INT idx; + tree field, value; - for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt; - elt = TREE_CHAIN (elt)) - if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1) + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)), + idx, field, value) + if (field == TREE_OPERAND (exp, 1) /* We can normally use the value of the field in the CONSTRUCTOR. However, if this is a bitfield in an integral mode that we can fit in a HOST_WIDE_INT, @@ -6773,24 +7141,21 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, since this is done implicitly by the constructor. If the bitfield does not meet either of those conditions, we can't do this optimization. */ - && (! DECL_BIT_FIELD (TREE_PURPOSE (elt)) - || ((GET_MODE_CLASS (DECL_MODE (TREE_PURPOSE (elt))) - == MODE_INT) - && (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt))) + && (! DECL_BIT_FIELD (field) + || ((GET_MODE_CLASS (DECL_MODE (field)) == MODE_INT) + && (GET_MODE_BITSIZE (DECL_MODE (field)) <= HOST_BITS_PER_WIDE_INT)))) { - if (DECL_BIT_FIELD (TREE_PURPOSE (elt)) + if (DECL_BIT_FIELD (field) && modifier == EXPAND_STACK_PARM) target = 0; - op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier); - if (DECL_BIT_FIELD (TREE_PURPOSE (elt))) + op0 = expand_expr (value, target, tmode, modifier); + if (DECL_BIT_FIELD (field)) { - HOST_WIDE_INT bitsize - = TREE_INT_CST_LOW (DECL_SIZE (TREE_PURPOSE (elt))); - enum machine_mode imode - = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt))); + HOST_WIDE_INT bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)); + enum machine_mode imode = TYPE_MODE (TREE_TYPE (field)); - if (TYPE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt)))) + if (TYPE_UNSIGNED (TREE_TYPE (field))) { op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1); op0 = expand_and (imode, op0, op1, target); @@ -6822,7 +7187,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, tree offset; int volatilep = 0; tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset, - &mode1, &unsignedp, &volatilep); + &mode1, &unsignedp, &volatilep, true); rtx orig_op0; /* If we got back the original object, something is wrong. Perhaps @@ -6847,25 +7212,30 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, || modifier == EXPAND_STACK_PARM) ? modifier : EXPAND_NORMAL); - /* If this is a constant, put it into a register if it is a - legitimate constant and OFFSET is 0 and memory if it isn't. */ + /* If this is a constant, put it into a register if it is a legitimate + constant, OFFSET is 0, and we won't try to extract outside the + register (in case we were passed a partially uninitialized object + or a view_conversion to a larger size). Force the constant to + memory otherwise. */ if (CONSTANT_P (op0)) { enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem)); if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0) - && offset == 0) + && offset == 0 + && bitpos + bitsize <= GET_MODE_BITSIZE (mode)) op0 = force_reg (mode, op0); else op0 = validize_mem (force_const_mem (mode, op0)); } - /* Otherwise, if this object not in memory and we either have an - offset or a BLKmode result, put it there. This case can't occur in - C, but can in Ada if we have unchecked conversion of an expression - from a scalar type to an array or record type or for an - ARRAY_RANGE_REF whose type is BLKmode. */ + /* Otherwise, if this object not in memory and we either have an + offset, a BLKmode result, or a reference outside the object, put it + there. Such cases can occur in Ada if we have unchecked conversion + of an expression from a scalar type to an array or record type or + for an ARRAY_RANGE_REF whose type is BLKmode. */ else if (!MEM_P (op0) && (offset != 0 + || (bitpos + bitsize > GET_MODE_BITSIZE (GET_MODE (op0))) || (code == ARRAY_RANGE_REF && mode == BLKmode))) { tree nt = build_qualified_type (TREE_TYPE (tem), @@ -7205,18 +7575,27 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, case VIEW_CONVERT_EXPR: op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier); - /* If the input and output modes are both the same, we are done. - Otherwise, if neither mode is BLKmode and both are integral and within - a word, we can use gen_lowpart. If neither is true, make sure the - operand is in memory and convert the MEM to the new mode. */ + /* If the input and output modes are both the same, we are done. */ if (TYPE_MODE (type) == GET_MODE (op0)) ; + /* If neither mode is BLKmode, and both modes are the same size + then we can use gen_lowpart. */ else if (TYPE_MODE (type) != BLKmode && GET_MODE (op0) != BLKmode - && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT - && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT - && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_WORD - && GET_MODE_SIZE (GET_MODE (op0)) <= UNITS_PER_WORD) - op0 = gen_lowpart (TYPE_MODE (type), op0); + && GET_MODE_SIZE (TYPE_MODE (type)) + == GET_MODE_SIZE (GET_MODE (op0))) + { + if (GET_CODE (op0) == SUBREG) + op0 = force_reg (GET_MODE (op0), op0); + op0 = gen_lowpart (TYPE_MODE (type), op0); + } + /* If both modes are integral, then we can convert from one to the + other. */ + else if (SCALAR_INT_MODE_P (GET_MODE (op0)) + && SCALAR_INT_MODE_P (TYPE_MODE (type))) + op0 = convert_modes (TYPE_MODE (type), GET_MODE (op0), op0, + TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)))); + /* As a last resort, spill op0 to memory, and reload it in a + different mode. */ else if (!MEM_P (op0)) { /* If the operand is not a MEM, force it into memory. Since we @@ -7337,7 +7716,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, } else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST - && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT && TREE_CONSTANT (TREE_OPERAND (exp, 0))) { rtx constant_part; @@ -7470,7 +7849,43 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, from a narrower type. If this machine supports multiplying in that narrower type with a result in the desired type, do it that way, and avoid the explicit type-conversion. */ - if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR + + subexp0 = TREE_OPERAND (exp, 0); + subexp1 = TREE_OPERAND (exp, 1); + /* First, check if we have a multiplication of one signed and one + unsigned operand. */ + if (TREE_CODE (subexp0) == NOP_EXPR + && TREE_CODE (subexp1) == NOP_EXPR + && TREE_CODE (type) == INTEGER_TYPE + && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0))) + < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))) + && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0))) + == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp1, 0)))) + && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0))) + != TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp1, 0))))) + { + enum machine_mode innermode + = TYPE_MODE (TREE_TYPE (TREE_OPERAND (subexp0, 0))); + this_optab = usmul_widen_optab; + if (mode == GET_MODE_WIDER_MODE (innermode)) + { + if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) + { + if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0)))) + expand_operands (TREE_OPERAND (subexp0, 0), + TREE_OPERAND (subexp1, 0), + NULL_RTX, &op0, &op1, 0); + else + expand_operands (TREE_OPERAND (subexp0, 0), + TREE_OPERAND (subexp1, 0), + NULL_RTX, &op1, &op0, 0); + + goto binop3; + } + } + } + /* Check for a multiplication with matching signedness. */ + else if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR && TREE_CODE (type) == INTEGER_TYPE && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))) < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))) @@ -7502,7 +7917,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab; this_optab = zextend_p ? umul_widen_optab : smul_widen_optab; - if (mode == GET_MODE_WIDER_MODE (innermode)) + if (mode == GET_MODE_2XWIDER_MODE (innermode)) { if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) { @@ -7561,18 +7976,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, return expand_divmod (0, code, mode, op0, op1, target, unsignedp); case RDIV_EXPR: - /* Emit a/b as a*(1/b). Later we may manage CSE the reciprocal saving - expensive divide. If not, combine will rebuild the original - computation. */ - if (flag_unsafe_math_optimizations && optimize && !optimize_size - && TREE_CODE (type) == REAL_TYPE - && !real_onep (TREE_OPERAND (exp, 0))) - return expand_expr (build2 (MULT_EXPR, type, TREE_OPERAND (exp, 0), - build2 (RDIV_EXPR, type, - build_real (type, dconst1), - TREE_OPERAND (exp, 1))), - target, tmode, modifier); - goto binop; case TRUNC_MOD_EXPR: @@ -7662,41 +8065,110 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, /* At this point, a MEM target is no longer useful; we will get better code without it. */ - if (MEM_P (target)) + if (! REG_P (target)) target = gen_reg_rtx (mode); /* If op1 was placed in target, swap op0 and op1. */ if (target != op0 && target == op1) { - rtx tem = op0; + temp = op0; op0 = op1; - op1 = tem; + op1 = temp; } - if (target != op0) - emit_move_insn (target, op0); + /* We generate better code and avoid problems with op1 mentioning + target by forcing op1 into a pseudo if it isn't a constant. */ + if (! CONSTANT_P (op1)) + op1 = force_reg (mode, op1); - op0 = gen_label_rtx (); + { + enum rtx_code comparison_code; + rtx cmpop1 = op1; - /* If this mode is an integer too wide to compare properly, - compare word by word. Rely on cse to optimize constant cases. */ - if (GET_MODE_CLASS (mode) == MODE_INT - && ! can_compare_p (GE, mode, ccp_jump)) - { - if (code == MAX_EXPR) - do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1, - NULL_RTX, op0); - else - do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target, - NULL_RTX, op0); - } - else - { - do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE, - unsignedp, mode, NULL_RTX, NULL_RTX, op0); - } + if (code == MAX_EXPR) + comparison_code = unsignedp ? GEU : GE; + else + comparison_code = unsignedp ? LEU : LE; + + /* Canonicalize to comparisons against 0. */ + if (op1 == const1_rtx) + { + /* Converting (a >= 1 ? a : 1) into (a > 0 ? a : 1) + or (a != 0 ? a : 1) for unsigned. + For MIN we are safe converting (a <= 1 ? a : 1) + into (a <= 0 ? a : 1) */ + cmpop1 = const0_rtx; + if (code == MAX_EXPR) + comparison_code = unsignedp ? NE : GT; + } + if (op1 == constm1_rtx && !unsignedp) + { + /* Converting (a >= -1 ? a : -1) into (a >= 0 ? a : -1) + and (a <= -1 ? a : -1) into (a < 0 ? a : -1) */ + cmpop1 = const0_rtx; + if (code == MIN_EXPR) + comparison_code = LT; + } +#ifdef HAVE_conditional_move + /* Use a conditional move if possible. */ + if (can_conditionally_move_p (mode)) + { + rtx insn; + + /* ??? Same problem as in expmed.c: emit_conditional_move + forces a stack adjustment via compare_from_rtx, and we + lose the stack adjustment if the sequence we are about + to create is discarded. */ + do_pending_stack_adjust (); + + start_sequence (); + + /* Try to emit the conditional move. */ + insn = emit_conditional_move (target, comparison_code, + op0, cmpop1, mode, + op0, op1, mode, + unsignedp); + + /* If we could do the conditional move, emit the sequence, + and return. */ + if (insn) + { + rtx seq = get_insns (); + end_sequence (); + emit_insn (seq); + return target; + } + + /* Otherwise discard the sequence and fall back to code with + branches. */ + end_sequence (); + } +#endif + if (target != op0) + emit_move_insn (target, op0); + + temp = gen_label_rtx (); + + /* If this mode is an integer too wide to compare properly, + compare word by word. Rely on cse to optimize constant cases. */ + if (GET_MODE_CLASS (mode) == MODE_INT + && ! can_compare_p (GE, mode, ccp_jump)) + { + if (code == MAX_EXPR) + do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1, + NULL_RTX, temp); + else + do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target, + NULL_RTX, temp); + } + else + { + do_compare_rtx_and_jump (target, cmpop1, comparison_code, + unsignedp, mode, NULL_RTX, NULL_RTX, temp); + } + } emit_move_insn (target, op1); - emit_label (op0); + emit_label (temp); return target; case BIT_NOT_EXPR: @@ -8057,11 +8529,27 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, op2 = expand_expr (oprnd2, NULL_RTX, VOIDmode, 0); temp = expand_ternary_op (mode, this_optab, op0, op1, op2, target, unsignedp); - if (temp == 0) - abort (); + gcc_assert (temp); + return temp; + } + + case REDUC_MAX_EXPR: + case REDUC_MIN_EXPR: + case REDUC_PLUS_EXPR: + { + op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0); + this_optab = optab_for_tree_code (code, type); + temp = expand_unop (mode, this_optab, op0, target, unsignedp); + gcc_assert (temp); return temp; } + case VEC_LSHIFT_EXPR: + case VEC_RSHIFT_EXPR: + { + target = expand_vec_shift_expr (exp, target); + return target; + } default: return lang_hooks.expand_expr (exp, original_target, tmode, @@ -8443,8 +8931,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap) if ((code == LT && integer_zerop (arg1)) || (! only_cheap && code == GE && integer_zerop (arg1))) ; - else if (BRANCH_COST >= 0 - && ! only_cheap && (code == NE || code == EQ) + else if (! only_cheap && (code == NE || code == EQ) && TREE_CODE (type) != REAL_TYPE && ((abs_optab->handlers[(int) operand_mode].insn_code != CODE_FOR_nothing) @@ -8688,9 +9175,9 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range, if (! HAVE_tablejump) return 0; - index_expr = fold (build2 (MINUS_EXPR, index_type, - convert (index_type, index_expr), - convert (index_type, minval))); + index_expr = fold_build2 (MINUS_EXPR, index_type, + convert (index_type, index_expr), + convert (index_type, minval)); index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0); do_pending_stack_adjust ();