diff options
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 523 |
1 files changed, 386 insertions, 137 deletions
diff --git a/gcc/expr.c b/gcc/expr.c index e5f7ae51783..78b35db8c84 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 Free Software Foundation, Inc. + 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -129,6 +129,8 @@ struct store_by_pieces }; static rtx enqueue_insn PARAMS ((rtx, rtx)); +static rtx mark_queue PARAMS ((void)); +static void emit_insns_enqueued_after_mark PARAMS ((rtx)); static unsigned HOST_WIDE_INT move_by_pieces_ninsns PARAMS ((unsigned HOST_WIDE_INT, unsigned int)); @@ -153,7 +155,7 @@ static rtx clear_storage_via_libcall PARAMS ((rtx, rtx)); static tree clear_storage_libcall_fn PARAMS ((int)); static rtx compress_float_constant PARAMS ((rtx, rtx)); static rtx get_subtarget PARAMS ((rtx)); -static int is_zeros_p PARAMS ((tree)); +static int is_zeros_p PARAMS ((tree)); static int mostly_zeros_p PARAMS ((tree)); static void store_constructor_field PARAMS ((rtx, unsigned HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode, @@ -177,6 +179,7 @@ static rtx do_store_flag PARAMS ((tree, rtx, enum machine_mode, int)); static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, tree)); #endif static void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, rtx)); +static rtx const_vector_from_tree PARAMS ((tree)); /* 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 @@ -499,13 +502,31 @@ queued_subexp_p (x) } } -/* Perform all the pending incrementations. */ +/* Retrieve a mark on the queue. */ + +static rtx +mark_queue () +{ + return pending_chain; +} -void -emit_queue () +/* Perform all the pending incrementations that have been enqueued + after MARK was retrieved. If MARK is null, perform all the + pending incrementations. */ + +static void +emit_insns_enqueued_after_mark (mark) + rtx mark; { rtx p; - while ((p = pending_chain)) + + /* The marked incrementation may have been emitted in the meantime + through a call to emit_queue. In this case, the mark is not valid + anymore so do nothing. */ + if (mark && ! QUEUED_BODY (mark)) + return; + + while ((p = pending_chain) != mark) { rtx body = QUEUED_BODY (p); @@ -532,9 +553,18 @@ emit_queue () break; } + QUEUED_BODY (p) = 0; pending_chain = QUEUED_NEXT (p); } } + +/* Perform all the pending incrementations. */ + +void +emit_queue () +{ + emit_insns_enqueued_after_mark (NULL_RTX); +} /* Copy data from FROM to TO, where the machine modes are not the same. Both modes may be integer, or both may be floating. @@ -885,7 +915,11 @@ convert_move (to, from, unsignedp) != CODE_FOR_nothing)) { if (GET_CODE (to) == REG) - emit_insn (gen_rtx_CLOBBER (VOIDmode, to)); + { + if (reg_overlap_mentioned_p (to, from)) + from = force_reg (from_mode, from); + emit_insn (gen_rtx_CLOBBER (VOIDmode, to)); + } convert_move (gen_lowpart (word_mode, to), from, unsignedp); emit_unop_insn (code, to, gen_lowpart (word_mode, to), equiv_code); @@ -1397,6 +1431,8 @@ convert_modes (mode, oldmode, x, unsignedp) && ((GET_CODE (x) == MEM && ! MEM_VOLATILE_P (x) && direct_load[(int) mode]) || (GET_CODE (x) == REG + && (! HARD_REGISTER_P (x) + || HARD_REGNO_MODE_OK (REGNO (x), mode)) && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), GET_MODE_BITSIZE (GET_MODE (x))))))))) { @@ -1422,6 +1458,15 @@ convert_modes (mode, oldmode, x, unsignedp) return gen_lowpart (mode, x); } + /* Converting from integer constant into mode is always equivalent to an + subreg operation. */ + if (VECTOR_MODE_P (mode) && GET_MODE (x) == VOIDmode) + { + if (GET_MODE_BITSIZE (mode) != GET_MODE_BITSIZE (oldmode)) + abort (); + return simplify_gen_subreg (mode, x, oldmode, 0); + } + temp = gen_reg_rtx (mode); convert_move (temp, x, unsignedp); return temp; @@ -2436,7 +2481,7 @@ emit_group_store (orig_dst, src, ssize) { dst = gen_reg_rtx (GET_MODE (orig_dst)); /* Make life a bit easier for combine. */ - emit_move_insn (dst, const0_rtx); + emit_move_insn (dst, CONST0_RTX (GET_MODE (orig_dst))); } /* Process the pieces. */ @@ -2468,6 +2513,15 @@ emit_group_store (orig_dst, src, ssize) bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))); dest = XEXP (dst, 1); } + else if (bytepos == 0 && XVECLEN (src, 0)) + { + dest = assign_stack_temp (GET_MODE (dest), + GET_MODE_SIZE (GET_MODE (dest)), 0); + emit_move_insn (adjust_address (dest, GET_MODE (tmps[i]), bytepos), + tmps[i]); + dst = dest; + break; + } else abort (); } @@ -2486,7 +2540,7 @@ emit_group_store (orig_dst, src, ssize) emit_queue (); /* Copy from the pseudo into the (probable) hard reg. */ - if (GET_CODE (dst) == REG) + if (orig_dst != dst) emit_move_insn (orig_dst, dst); } @@ -2648,6 +2702,9 @@ can_store_by_pieces (len, constfun, constfundata, align) int reverse; rtx cst; + if (len == 0) + return 1; + if (! MOVE_BY_PIECES_P (len, align)) return 0; @@ -2723,6 +2780,9 @@ store_by_pieces (to, len, constfun, constfundata, align) { struct store_by_pieces data; + if (len == 0) + return; + if (! MOVE_BY_PIECES_P (len, align)) abort (); to = protect_from_queue (to, 1); @@ -2745,6 +2805,9 @@ clear_by_pieces (to, len, align) { struct store_by_pieces data; + if (len == 0) + return; + data.constfun = clear_by_pieces_1; data.constfundata = NULL; data.len = len; @@ -2915,7 +2978,9 @@ clear_storage (object, size) object = protect_from_queue (object, 1); size = protect_from_queue (size, 0); - if (GET_CODE (size) == CONST_INT + if (GET_CODE (size) == CONST_INT && INTVAL (size) == 0) + ; + 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_clrstr (object, size, align)) @@ -4020,7 +4085,8 @@ expand_assignment (to, from, want_value, suggest_reg) problem. */ if (TREE_CODE (to) == COMPONENT_REF || TREE_CODE (to) == BIT_FIELD_REF - || TREE_CODE (to) == ARRAY_REF || TREE_CODE (to) == ARRAY_RANGE_REF) + || TREE_CODE (to) == ARRAY_REF || TREE_CODE (to) == ARRAY_RANGE_REF + || TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE) { enum machine_mode mode1; HOST_WIDE_INT bitsize, bitpos; @@ -4051,7 +4117,7 @@ expand_assignment (to, from, want_value, suggest_reg) #ifdef POINTERS_EXTEND_UNSIGNED if (GET_MODE (offset_rtx) != Pmode) - offset_rtx = convert_memory_address (Pmode, offset_rtx); + offset_rtx = convert_to_mode (Pmode, offset_rtx, 0); #else if (GET_MODE (offset_rtx) != ptr_mode) offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0); @@ -4095,7 +4161,11 @@ expand_assignment (to, from, want_value, suggest_reg) } if (TREE_CODE (to) == COMPONENT_REF - && TREE_READONLY (TREE_OPERAND (to, 1))) + && TREE_READONLY (TREE_OPERAND (to, 1)) + /* We can't assert that a MEM won't be set more than once + if the component is not addressable because another + non-addressable component may be referenced by the same MEM. */ + && ! (GET_CODE (to_rtx) == MEM && ! can_address_p (to))) { if (to_rtx == orig_to_rtx) to_rtx = copy_rtx (to_rtx); @@ -4248,7 +4318,7 @@ expand_assignment (to, from, want_value, suggest_reg) and storing the value into TARGET. TARGET may contain a QUEUED rtx. - If WANT_VALUE is nonzero, return a copy of the value + If WANT_VALUE & 1 is nonzero, return a copy of the value not in TARGET, so that we can be sure to use the proper value in a containing expression even if TARGET has something else stored in it. If possible, we copy the value through a pseudo @@ -4263,9 +4333,12 @@ expand_assignment (to, from, want_value, suggest_reg) with no sequence point. Will other languages need this to be more thorough? - If WANT_VALUE is 0, we return NULL, to make sure + If WANT_VALUE & 1 is 0, we return NULL, to make sure to catch quickly any cases where the caller uses the value - and fails to set WANT_VALUE. */ + and fails to set WANT_VALUE. + + If WANT_VALUE & 2 is set, this is a store into a call param on the + stack, and block moves may need to be treated specially. */ rtx store_expr (exp, target, want_value) @@ -4274,14 +4347,26 @@ store_expr (exp, target, want_value) int want_value; { rtx temp; + rtx mark = mark_queue (); int dont_return_target = 0; int dont_store_target = 0; + if (VOID_TYPE_P (TREE_TYPE (exp))) + { + /* C++ can generate ?: expressions with a throw expression in one + branch and an rvalue in the other. Here, we resolve attempts to + store the throw expression's nonexistant result. */ + if (want_value) + abort (); + expand_expr (exp, const0_rtx, VOIDmode, 0); + return NULL_RTX; + } if (TREE_CODE (exp) == COMPOUND_EXPR) { /* Perform first part of compound expression, then assign from second part. */ - expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0); + expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, + want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL); emit_queue (); return store_expr (TREE_OPERAND (exp, 1), target, want_value); } @@ -4301,20 +4386,20 @@ store_expr (exp, target, want_value) NO_DEFER_POP; jumpifnot (TREE_OPERAND (exp, 0), lab1); start_cleanup_deferral (); - store_expr (TREE_OPERAND (exp, 1), target, 0); + store_expr (TREE_OPERAND (exp, 1), target, want_value & 2); end_cleanup_deferral (); emit_queue (); emit_jump_insn (gen_jump (lab2)); emit_barrier (); emit_label (lab1); start_cleanup_deferral (); - store_expr (TREE_OPERAND (exp, 2), target, 0); + store_expr (TREE_OPERAND (exp, 2), target, want_value & 2); end_cleanup_deferral (); emit_queue (); emit_label (lab2); OK_DEFER_POP; - return want_value ? target : NULL_RTX; + return want_value & 1 ? target : NULL_RTX; } else if (queued_subexp_p (target)) /* If target contains a postincrement, let's not risk @@ -4324,18 +4409,24 @@ store_expr (exp, target, want_value) { /* Expand EXP into a new pseudo. */ temp = gen_reg_rtx (GET_MODE (target)); - temp = expand_expr (exp, temp, GET_MODE (target), 0); + temp = expand_expr (exp, temp, GET_MODE (target), + (want_value & 2 + ? EXPAND_STACK_PARM : EXPAND_NORMAL)); } else - temp = expand_expr (exp, NULL_RTX, GET_MODE (target), 0); + temp = expand_expr (exp, NULL_RTX, GET_MODE (target), + (want_value & 2 + ? EXPAND_STACK_PARM : EXPAND_NORMAL)); /* If target is volatile, ANSI requires accessing the value *from* the target, if it is accessed. So make that happen. In no case return the target itself. */ - if (! MEM_VOLATILE_P (target) && want_value) + if (! MEM_VOLATILE_P (target) && (want_value & 1) != 0) dont_return_target = 1; } - else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target) + else if ((want_value & 1) != 0 + && GET_CODE (target) == MEM + && ! MEM_VOLATILE_P (target) && GET_MODE (target) != BLKmode) /* If target is in memory and caller wants value in a register instead, arrange that. Pass TARGET as target for expand_expr so that, @@ -4344,7 +4435,8 @@ store_expr (exp, target, want_value) Don't do this if TARGET is volatile because we are supposed to write it and then read it. */ { - temp = expand_expr (exp, target, GET_MODE (target), 0); + temp = expand_expr (exp, target, GET_MODE (target), + want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL); if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode) { /* If TEMP is already in the desired TARGET, only copy it from @@ -4371,7 +4463,8 @@ store_expr (exp, target, want_value) the extend. But don't do this if the type of EXP is a subtype of something else since then the conversion might involve more than just converting modes. */ - if (! want_value && INTEGRAL_TYPE_P (TREE_TYPE (exp)) + if ((want_value & 1) == 0 + && INTEGRAL_TYPE_P (TREE_TYPE (exp)) && TREE_TYPE (TREE_TYPE (exp)) == 0) { if (TREE_UNSIGNED (TREE_TYPE (exp)) @@ -4388,12 +4481,13 @@ store_expr (exp, target, want_value) inner_target = SUBREG_REG (target); } - temp = expand_expr (exp, inner_target, VOIDmode, 0); + temp = expand_expr (exp, inner_target, VOIDmode, + want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL); /* If TEMP is a volatile MEM and we want a result value, make the access now so it gets done only once. Likewise if it contains TARGET. */ - if (GET_CODE (temp) == MEM && want_value + if (GET_CODE (temp) == MEM && (want_value & 1) != 0 && (MEM_VOLATILE_P (temp) || reg_mentioned_p (SUBREG_REG (target), XEXP (temp, 0)))) temp = copy_to_reg (temp); @@ -4416,7 +4510,7 @@ store_expr (exp, target, want_value) target. Otherwise, the caller might get confused by a result whose mode is larger than expected. */ - if (want_value && GET_MODE (temp) != GET_MODE (target)) + if ((want_value & 1) != 0 && GET_MODE (temp) != GET_MODE (target)) { if (GET_MODE (temp) != VOIDmode) { @@ -4431,11 +4525,12 @@ store_expr (exp, target, want_value) temp, SUBREG_PROMOTED_UNSIGNED_P (target)); } - return want_value ? temp : NULL_RTX; + return want_value & 1 ? temp : NULL_RTX; } else { - temp = expand_expr (exp, target, GET_MODE (target), 0); + temp = expand_expr (exp, target, GET_MODE (target), + want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL); /* Return TARGET if it's a specified hardware register. If TARGET is a volatile mem ref, either return TARGET or return a reg copied *from* TARGET; ANSI requires this. @@ -4447,7 +4542,7 @@ store_expr (exp, target, want_value) && REGNO (target) < FIRST_PSEUDO_REGISTER) && !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target)) && ! rtx_equal_p (temp, target) - && (CONSTANT_P (temp) || want_value)) + && (CONSTANT_P (temp) || (want_value & 1) != 0)) dont_return_target = 1; } @@ -4462,7 +4557,11 @@ store_expr (exp, target, want_value) temp, TREE_UNSIGNED (TREE_TYPE (exp))); /* If value was not generated in the target, store it there. - Convert the value to TARGET's type first if necessary. + Convert the value to TARGET's type first if necessary and emit the + pending incrementations that have been queued when expanding EXP. + Note that we cannot emit the whole queue blindly because this will + effectively disable the POST_INC optimization later. + If TEMP and TARGET compare equal according to rtx_equal_p, but one or both of them are volatile memory refs, we have to distinguish two cases: @@ -4491,7 +4590,9 @@ store_expr (exp, target, want_value) bit-initialized. */ && expr_size (exp) != const0_rtx) { + emit_insns_enqueued_after_mark (mark); target = protect_from_queue (target, 1); + temp = protect_from_queue (temp, 0); if (GET_MODE (temp) != GET_MODE (target) && GET_MODE (temp) != VOIDmode) { @@ -4518,7 +4619,9 @@ store_expr (exp, target, want_value) if (GET_CODE (size) == CONST_INT && INTVAL (size) < TREE_STRING_LENGTH (exp)) - emit_block_move (target, temp, size, BLOCK_OP_NORMAL); + emit_block_move (target, temp, size, + (want_value & 2 + ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); else { /* Compute the size of the data to copy from the string. */ @@ -4526,13 +4629,18 @@ store_expr (exp, target, want_value) = size_binop (MIN_EXPR, make_tree (sizetype, size), size_int (TREE_STRING_LENGTH (exp))); - rtx copy_size_rtx = expand_expr (copy_size, NULL_RTX, - VOIDmode, 0); + rtx copy_size_rtx + = expand_expr (copy_size, NULL_RTX, VOIDmode, + (want_value & 2 + ? EXPAND_STACK_PARM : EXPAND_NORMAL)); rtx label = 0; /* Copy that much. */ - copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx, 0); - emit_block_move (target, temp, copy_size_rtx, BLOCK_OP_NORMAL); + copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx, + TREE_UNSIGNED (sizetype)); + emit_block_move (target, temp, copy_size_rtx, + (want_value & 2 + ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); /* Figure out how much is left in TARGET that we have to clear. Do all calculations in ptr_mode. */ @@ -4550,8 +4658,8 @@ store_expr (exp, target, want_value) #ifdef POINTERS_EXTEND_UNSIGNED if (GET_MODE (copy_size_rtx) != Pmode) - copy_size_rtx = convert_memory_address (Pmode, - copy_size_rtx); + copy_size_rtx = convert_to_mode (Pmode, copy_size_rtx, + TREE_UNSIGNED (sizetype)); #endif target = offset_address (target, copy_size_rtx, @@ -4573,13 +4681,15 @@ store_expr (exp, target, want_value) else if (GET_CODE (target) == PARALLEL) emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp))); else if (GET_MODE (temp) == BLKmode) - emit_block_move (target, temp, expr_size (exp), BLOCK_OP_NORMAL); + emit_block_move (target, temp, expr_size (exp), + (want_value & 2 + ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); else emit_move_insn (target, temp); } /* If we don't want a value, return NULL_RTX. */ - if (! want_value) + if ((want_value & 1) == 0) return NULL_RTX; /* If we are supposed to return TEMP, do so as long as it isn't a MEM. @@ -4588,7 +4698,8 @@ store_expr (exp, target, want_value) return temp; /* Return TARGET itself if it is a hard register. */ - else if (want_value && GET_MODE (target) != BLKmode + else if ((want_value & 1) != 0 + && GET_MODE (target) != BLKmode && ! (GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)) return copy_to_reg (target); @@ -4756,11 +4867,13 @@ store_constructor (exp, target, cleared, size) { tree elt; + /* If size is zero or the target is already cleared, do nothing. */ + if (size == 0 || cleared) + cleared = 1; /* We either clear the aggregate or indicate the value is dead. */ - if ((TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == QUAL_UNION_TYPE) - && ! cleared - && ! CONSTRUCTOR_ELTS (exp)) + else if ((TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + && ! CONSTRUCTOR_ELTS (exp)) /* If the constructor is empty, clear the union. */ { clear_storage (target, expr_size (exp)); @@ -4771,7 +4884,7 @@ store_constructor (exp, target, cleared, size) set the initial value as zero so we can fold the value into a constant. But if more than one register is involved, this probably loses. */ - else if (! cleared && GET_CODE (target) == REG && TREE_STATIC (exp) + else if (GET_CODE (target) == REG && TREE_STATIC (exp) && GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD) { emit_move_insn (target, CONST0_RTX (GET_MODE (target))); @@ -4783,10 +4896,8 @@ store_constructor (exp, target, cleared, size) clear the whole structure first. Don't do this if TARGET is a register whose mode size isn't equal to SIZE since clear_storage can't handle this case. */ - else if (! cleared && size > 0 - && ((list_length (CONSTRUCTOR_ELTS (exp)) - != fields_length (type)) - || mostly_zeros_p (exp)) + else if (((list_length (CONSTRUCTOR_ELTS (exp)) != fields_length (type)) + || mostly_zeros_p (exp)) && (GET_CODE (target) != REG || ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target)) == size))) @@ -4855,7 +4966,7 @@ store_constructor (exp, target, cleared, size) #ifdef POINTERS_EXTEND_UNSIGNED if (GET_MODE (offset_rtx) != Pmode) - offset_rtx = convert_memory_address (Pmode, offset_rtx); + offset_rtx = convert_to_mode (Pmode, offset_rtx, 0); #else if (GET_MODE (offset_rtx) != ptr_mode) offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0); @@ -4865,7 +4976,10 @@ store_constructor (exp, target, cleared, size) highest_pow2_factor (offset)); } - if (TREE_READONLY (field)) + /* If the constructor has been cleared, setting RTX_UNCHANGING_P + on the MEM might lead to scheduling the clearing after the + store. */ + if (TREE_READONLY (field) && !cleared) { if (GET_CODE (to_rtx) == MEM) to_rtx = copy_rtx (to_rtx); @@ -5248,7 +5362,7 @@ store_constructor (exp, target, cleared, size) { if (word != 0 || ! cleared) { - rtx datum = GEN_INT (word); + rtx datum = gen_int_mode (word, mode); rtx to_rtx; /* The assumption here is that it is safe to use @@ -5992,22 +6106,31 @@ safe_from_p (x, exp, top_p) case 'x': if (TREE_CODE (exp) == TREE_LIST) - return ((TREE_VALUE (exp) == 0 - || safe_from_p (x, TREE_VALUE (exp), 0)) - && (TREE_CHAIN (exp) == 0 - || safe_from_p (x, TREE_CHAIN (exp), 0))); + { + while (1) + { + if (TREE_VALUE (exp) && !safe_from_p (x, TREE_VALUE (exp), 0)) + return 0; + exp = TREE_CHAIN (exp); + if (!exp) + return 1; + if (TREE_CODE (exp) != TREE_LIST) + return safe_from_p (x, exp, 0); + } + } else if (TREE_CODE (exp) == ERROR_MARK) return 1; /* An already-visited SAVE_EXPR? */ else return 0; - case '1': - return safe_from_p (x, TREE_OPERAND (exp, 0), 0); - case '2': case '<': - return (safe_from_p (x, TREE_OPERAND (exp, 0), 0) - && safe_from_p (x, TREE_OPERAND (exp, 1), 0)); + if (!safe_from_p (x, TREE_OPERAND (exp, 1), 0)) + return 0; + /* FALLTHRU */ + + case '1': + return safe_from_p (x, TREE_OPERAND (exp, 0), 0); case 'e': case 'r': @@ -6405,7 +6528,14 @@ find_placeholder (exp, plist) EXPAND_CONST_ADDRESS says that it is okay to return a MEM with a constant address even if that address is not normally legitimate. - EXPAND_INITIALIZER and EXPAND_SUM also have this effect. */ + EXPAND_INITIALIZER and EXPAND_SUM also have this effect. + + EXPAND_STACK_PARM is used when expanding to a TARGET on the stack for + a call parameter. Such targets require special care as we haven't yet + marked TARGET so that it's safe from being trashed by libcalls. We + don't want to use TARGET for anything but the final result; + Intermediate values must go elsewhere. Additionally, calls to + emit_block_move will be flagged with BLOCK_OP_CALL_PARM. */ rtx expand_expr (exp, target, tmode, modifier) @@ -6548,7 +6678,7 @@ expand_expr (exp, target, tmode, modifier) if (! cse_not_expected && mode != BLKmode && target && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER) && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD)) - target = subtarget; + target = 0; switch (code) { @@ -6592,23 +6722,10 @@ expand_expr (exp, target, tmode, modifier) case VAR_DECL: /* If a static var's type was incomplete when the decl was written, but the type is complete now, lay out the decl now. */ - if (DECL_SIZE (exp) == 0 && COMPLETE_TYPE_P (TREE_TYPE (exp)) + if (DECL_SIZE (exp) == 0 + && COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (TREE_TYPE (exp)) && (TREE_STATIC (exp) || DECL_EXTERNAL (exp))) - { - rtx value = DECL_RTL_IF_SET (exp); - - layout_decl (exp, 0); - - /* If the RTL was already set, update its mode and memory - attributes. */ - if (value != 0) - { - PUT_MODE (value, DECL_MODE (exp)); - SET_DECL_RTL (exp, 0); - set_mem_attributes (value, exp, 1); - SET_DECL_RTL (exp, value); - } - } + layout_decl (exp, 0); /* ... fall through ... */ @@ -6733,8 +6850,11 @@ expand_expr (exp, target, tmode, modifier) return temp; + case VECTOR_CST: + return const_vector_from_tree (exp); + case CONST_DECL: - return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0); + return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier); case REAL_CST: /* If optimized, generate immediate CONST_DOUBLE @@ -6810,7 +6930,7 @@ expand_expr (exp, target, tmode, modifier) temp = SAVE_EXPR_RTL (exp); if (temp && GET_CODE (temp) == REG) { - put_var_into_stack (exp); + put_var_into_stack (exp, /*rescan=*/true); temp = SAVE_EXPR_RTL (exp); } if (temp == 0 || GET_CODE (temp) != MEM) @@ -6837,12 +6957,12 @@ expand_expr (exp, target, tmode, modifier) /* If the mode of TEMP does not match that of the expression, it must be a promoted value. We pass store_expr a SUBREG of the wanted mode but mark it so that we know that it was already - extended. Note that `unsignedp' was modified above in - this case. */ + extended. */ if (GET_CODE (temp) == REG && GET_MODE (temp) != mode) { temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp)); + promote_mode (type, mode, &unsignedp, 0); SUBREG_PROMOTED_VAR_P (temp) = 1; SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp); } @@ -6850,7 +6970,8 @@ expand_expr (exp, target, tmode, modifier) if (temp == const0_rtx) expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0); else - store_expr (TREE_OPERAND (exp, 0), temp, 0); + store_expr (TREE_OPERAND (exp, 0), temp, + modifier == EXPAND_STACK_PARM ? 2 : 0); TREE_USED (exp) = 1; } @@ -7039,7 +7160,8 @@ expand_expr (exp, target, tmode, modifier) /* Handle calls that pass values in multiple non-contiguous locations. The Irix 6 ABI has examples of this. */ if (target == 0 || ! safe_from_p (target, exp, 1) - || GET_CODE (target) == PARALLEL) + || GET_CODE (target) == PARALLEL + || modifier == EXPAND_STACK_PARM) target = assign_temp (build_qualified_type (type, (TYPE_QUALS (type) @@ -7109,7 +7231,9 @@ expand_expr (exp, target, tmode, modifier) Don't fold if this is for wide characters since it's too difficult to do correctly and this is a very rare case. */ - if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER + if (modifier != EXPAND_CONST_ADDRESS + && modifier != EXPAND_INITIALIZER + && modifier != EXPAND_MEMORY && TREE_CODE (array) == STRING_CST && TREE_CODE (index) == INTEGER_CST && compare_tree_int (index, TREE_STRING_LENGTH (array)) < 0 @@ -7123,8 +7247,11 @@ expand_expr (exp, target, tmode, modifier) we have an explicit constructor and when our operand is a variable that was declared const. */ - if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER - && TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array) + if (modifier != EXPAND_CONST_ADDRESS + && modifier != EXPAND_INITIALIZER + && modifier != EXPAND_MEMORY + && TREE_CODE (array) == CONSTRUCTOR + && ! TREE_SIDE_EFFECTS (array) && TREE_CODE (index) == INTEGER_CST && 0 > compare_tree_int (index, list_length (CONSTRUCTOR_ELTS @@ -7145,6 +7272,7 @@ expand_expr (exp, target, tmode, modifier) else if (optimize >= 1 && modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER + && modifier != EXPAND_MEMORY && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array) && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array) && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK) @@ -7213,6 +7341,9 @@ expand_expr (exp, target, tmode, modifier) && (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt))) <= HOST_BITS_PER_WIDE_INT)))) { + if (DECL_BIT_FIELD (TREE_PURPOSE (elt)) + && modifier == EXPAND_STACK_PARM) + target = 0; op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier); if (DECL_BIT_FIELD (TREE_PURPOSE (elt))) { @@ -7267,10 +7398,12 @@ expand_expr (exp, target, tmode, modifier) (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) != INTEGER_CST) + && modifier != EXPAND_STACK_PARM ? target : NULL_RTX), VOIDmode, (modifier == EXPAND_INITIALIZER - || modifier == EXPAND_CONST_ADDRESS) + || modifier == EXPAND_CONST_ADDRESS + || modifier == EXPAND_STACK_PARM) ? modifier : EXPAND_NORMAL); /* If this is a constant, put it into a register if it is a @@ -7287,7 +7420,8 @@ expand_expr (exp, target, tmode, modifier) if (offset != 0) { - rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM); + rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, + EXPAND_SUM); /* If this object is in a register, put it into memory. This case can't occur in C, but can in Ada if we have @@ -7300,7 +7434,8 @@ expand_expr (exp, target, tmode, modifier) forcing the SAVE_EXPR into memory. */ if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR) { - put_var_into_stack (TREE_OPERAND (exp, 0)); + put_var_into_stack (TREE_OPERAND (exp, 0), + /*rescan=*/true); op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0)); } else @@ -7321,7 +7456,7 @@ expand_expr (exp, target, tmode, modifier) #ifdef POINTERS_EXTEND_UNSIGNED if (GET_MODE (offset_rtx) != Pmode) - offset_rtx = convert_memory_address (Pmode, offset_rtx); + offset_rtx = convert_to_mode (Pmode, offset_rtx, 0); #else if (GET_MODE (offset_rtx) != ptr_mode) offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0); @@ -7423,7 +7558,8 @@ expand_expr (exp, target, tmode, modifier) emit_block_move (target, op0, GEN_INT ((bitsize + BITS_PER_UNIT - 1) / BITS_PER_UNIT), - BLOCK_OP_NORMAL); + (modifier == EXPAND_STACK_PARM + ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); return target; } @@ -7433,8 +7569,10 @@ expand_expr (exp, target, tmode, modifier) if (GET_CODE (op0) == MEM && GET_CODE (XEXP (op0, 0)) == REG) mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0)); - op0 = extract_bit_field (op0, bitsize, bitpos, - unsignedp, target, ext_mode, ext_mode, + op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp, + (modifier == EXPAND_STACK_PARM + ? NULL_RTX : target), + ext_mode, ext_mode, int_size_in_bytes (TREE_TYPE (tem))); /* If the result is a record type and BITSIZE is narrower than @@ -7678,8 +7816,8 @@ expand_expr (exp, target, tmode, modifier) { if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == BUILT_IN_FRONTEND) - return (*lang_hooks.expand_expr) - (exp, original_target, tmode, modifier); + return (*lang_hooks.expand_expr) (exp, original_target, + tmode, modifier); else return expand_builtin (exp, target, subtarget, tmode, ignore); } @@ -7715,7 +7853,8 @@ expand_expr (exp, target, tmode, modifier) if (GET_CODE (target) == MEM) /* Store data into beginning of memory target. */ store_expr (TREE_OPERAND (exp, 0), - adjust_address (target, TYPE_MODE (valtype), 0), 0); + adjust_address (target, TYPE_MODE (valtype), 0), + modifier == EXPAND_STACK_PARM ? 2 : 0); else if (GET_CODE (target) == REG) /* Store this field into a union of the proper type. */ @@ -7840,7 +7979,8 @@ expand_expr (exp, target, tmode, modifier) if (GET_MODE (op0) == BLKmode) emit_block_move (new_with_op0_mode, op0, GEN_INT (GET_MODE_SIZE (TYPE_MODE (type))), - BLOCK_OP_NORMAL); + (modifier == EXPAND_STACK_PARM + ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); else emit_move_insn (new_with_op0_mode, op0); @@ -7892,6 +8032,8 @@ expand_expr (exp, target, tmode, modifier) if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER || (mode == ptr_mode && (unsignedp || ! flag_trapv))) { + if (modifier == EXPAND_STACK_PARM) + target = 0; if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT && TREE_CONSTANT (TREE_OPERAND (exp, 1))) @@ -8086,6 +8228,8 @@ expand_expr (exp, target, tmode, modifier) if (modifier == EXPAND_SUM && mode == ptr_mode && host_integerp (TREE_OPERAND (exp, 1), 0)) { + tree exp1 = TREE_OPERAND (exp, 1); + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM); @@ -8104,14 +8248,17 @@ expand_expr (exp, target, tmode, modifier) if (GET_CODE (op0) != REG) op0 = copy_to_mode_reg (mode, op0); - return - gen_rtx_MULT (mode, op0, - GEN_INT (tree_low_cst (TREE_OPERAND (exp, 1), 0))); + return gen_rtx_MULT (mode, op0, + gen_int_mode (tree_low_cst (exp1, 0), + TYPE_MODE (TREE_TYPE (exp1)))); } if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1)) subtarget = 0; + if (modifier == EXPAND_STACK_PARM) + target = 0; + /* Check for multiplying things that have been extended from a narrower type. If this machine supports multiplying in that narrower type with a result in the desired type, @@ -8195,6 +8342,8 @@ expand_expr (exp, target, tmode, modifier) case EXACT_DIV_EXPR: if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1)) subtarget = 0; + if (modifier == EXPAND_STACK_PARM) + target = 0; /* Possible optimization: compute the dividend with EXPAND_SUM then if the divisor is constant can optimize the case where some terms of the dividend have coeffs divisible by it. */ @@ -8213,7 +8362,7 @@ expand_expr (exp, target, tmode, modifier) build (RDIV_EXPR, type, build_real (type, dconst1), TREE_OPERAND (exp, 1))), - target, tmode, unsignedp); + target, tmode, modifier); this_optab = sdiv_optab; goto binop; @@ -8223,6 +8372,8 @@ expand_expr (exp, target, tmode, modifier) case ROUND_MOD_EXPR: if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1)) subtarget = 0; + if (modifier == EXPAND_STACK_PARM) + target = 0; op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0); return expand_divmod (1, code, mode, op0, op1, target, unsignedp); @@ -8234,14 +8385,14 @@ expand_expr (exp, target, tmode, modifier) case FIX_TRUNC_EXPR: op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0); - if (target == 0) + if (target == 0 || modifier == EXPAND_STACK_PARM) target = gen_reg_rtx (mode); expand_fix (target, op0, unsignedp); return target; case FLOAT_EXPR: op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0); - if (target == 0) + if (target == 0 || modifier == EXPAND_STACK_PARM) target = gen_reg_rtx (mode); /* expand_float can't figure out what to do if FROM has VOIDmode. So give it the correct mode. With -O, cse will optimize this. */ @@ -8254,6 +8405,8 @@ expand_expr (exp, target, tmode, modifier) case NEGATE_EXPR: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + if (modifier == EXPAND_STACK_PARM) + target = 0; temp = expand_unop (mode, ! unsignedp && flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT) @@ -8264,6 +8417,8 @@ expand_expr (exp, target, tmode, modifier) case ABS_EXPR: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + if (modifier == EXPAND_STACK_PARM) + target = 0; /* Handle complex values specially. */ if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT @@ -8281,7 +8436,9 @@ expand_expr (exp, target, tmode, modifier) case MAX_EXPR: case MIN_EXPR: target = original_target; - if (target == 0 || ! safe_from_p (target, TREE_OPERAND (exp, 1), 1) + if (target == 0 + || modifier == EXPAND_STACK_PARM + || ! safe_from_p (target, TREE_OPERAND (exp, 1), 1) || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)) || GET_MODE (target) != mode || (GET_CODE (target) == REG @@ -8305,9 +8462,14 @@ expand_expr (exp, target, tmode, modifier) /* At this point, a MEM target is no longer useful; we will get better code without it. */ - if (GET_CODE (target) == MEM) + if (! REG_P (target)) target = gen_reg_rtx (mode); + /* 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); + if (target != op0) emit_move_insn (target, op0); @@ -8338,6 +8500,8 @@ expand_expr (exp, target, tmode, modifier) case BIT_NOT_EXPR: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + if (modifier == EXPAND_STACK_PARM) + target = 0; temp = expand_unop (mode, one_cmpl_optab, op0, target, 1); if (temp == 0) abort (); @@ -8345,6 +8509,8 @@ expand_expr (exp, target, tmode, modifier) case FFS_EXPR: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + if (modifier == EXPAND_STACK_PARM) + target = 0; temp = expand_unop (mode, ffs_optab, op0, target, 1); if (temp == 0) abort (); @@ -8384,6 +8550,8 @@ expand_expr (exp, target, tmode, modifier) case RROTATE_EXPR: if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1)) subtarget = 0; + if (modifier == EXPAND_STACK_PARM) + target = 0; op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target, unsignedp); @@ -8403,7 +8571,9 @@ expand_expr (exp, target, tmode, modifier) case UNGT_EXPR: case UNGE_EXPR: case UNEQ_EXPR: - temp = do_store_flag (exp, target, tmode != VOIDmode ? tmode : mode, 0); + temp = do_store_flag (exp, + modifier != EXPAND_STACK_PARM ? target : NULL_RTX, + tmode != VOIDmode ? tmode : mode, 0); if (temp != 0) return temp; @@ -8452,7 +8622,9 @@ expand_expr (exp, target, tmode, modifier) case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: if (! ignore - && (target == 0 || ! safe_from_p (target, exp, 1) + && (target == 0 + || modifier == EXPAND_STACK_PARM + || ! safe_from_p (target, exp, 1) /* Make sure we don't have a hard reg (such as function's return value) live across basic blocks, if not optimizing. */ || (!optimize && GET_CODE (target) == REG @@ -8472,6 +8644,8 @@ expand_expr (exp, target, tmode, modifier) return ignore ? const0_rtx : target; case TRUTH_NOT_EXPR: + if (modifier == EXPAND_STACK_PARM) + target = 0; op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0); /* The parser is careful to generate TRUTH_NOT_EXPR only with operands that are always zero or one. */ @@ -8486,7 +8660,7 @@ expand_expr (exp, target, tmode, modifier) emit_queue (); return expand_expr (TREE_OPERAND (exp, 1), (ignore ? const0_rtx : target), - VOIDmode, 0); + VOIDmode, modifier); case COND_EXPR: /* If we would have a "singleton" (see below) were it not for a @@ -8539,6 +8713,8 @@ expand_expr (exp, target, tmode, modifier) return const0_rtx; } + if (modifier == EXPAND_STACK_PARM) + target = 0; op0 = expand_expr (TREE_OPERAND (exp, 0), target, mode, modifier); if (GET_MODE (op0) == mode) return op0; @@ -8579,6 +8755,8 @@ expand_expr (exp, target, tmode, modifier) if (ignore) temp = 0; + else if (modifier == EXPAND_STACK_PARM) + temp = assign_temp (type, 0, 0, 1); else if (original_target && (safe_from_p (original_target, TREE_OPERAND (exp, 0), 1) || (singleton && GET_CODE (original_target) == REG @@ -8666,7 +8844,8 @@ expand_expr (exp, target, tmode, modifier) || (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)) temp = gen_reg_rtx (mode); - store_expr (singleton, temp, 0); + store_expr (singleton, temp, + modifier == EXPAND_STACK_PARM ? 2 : 0); } else expand_expr (singleton, @@ -8685,11 +8864,11 @@ expand_expr (exp, target, tmode, modifier) store_expr (build (TREE_CODE (binary_op), type, make_tree (type, temp), TREE_OPERAND (binary_op, 1)), - temp, 0); + temp, modifier == EXPAND_STACK_PARM ? 2 : 0); else store_expr (build1 (TREE_CODE (unary_op), type, make_tree (type, temp)), - temp, 0); + temp, modifier == EXPAND_STACK_PARM ? 2 : 0); op1 = op0; } /* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any @@ -8708,11 +8887,13 @@ expand_expr (exp, target, tmode, modifier) if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER) temp = gen_reg_rtx (mode); - store_expr (TREE_OPERAND (exp, 1), temp, 0); + store_expr (TREE_OPERAND (exp, 1), temp, + modifier == EXPAND_STACK_PARM ? 2 : 0); jumpif (TREE_OPERAND (exp, 0), op0); start_cleanup_deferral (); - store_expr (TREE_OPERAND (exp, 2), temp, 0); + store_expr (TREE_OPERAND (exp, 2), temp, + modifier == EXPAND_STACK_PARM ? 2 : 0); op1 = op0; } else if (temp @@ -8727,11 +8908,13 @@ expand_expr (exp, target, tmode, modifier) if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER) temp = gen_reg_rtx (mode); - store_expr (TREE_OPERAND (exp, 2), temp, 0); + store_expr (TREE_OPERAND (exp, 2), temp, + modifier == EXPAND_STACK_PARM ? 2 : 0); jumpifnot (TREE_OPERAND (exp, 0), op0); start_cleanup_deferral (); - store_expr (TREE_OPERAND (exp, 1), temp, 0); + store_expr (TREE_OPERAND (exp, 1), temp, + modifier == EXPAND_STACK_PARM ? 2 : 0); op1 = op0; } else @@ -8745,7 +8928,8 @@ expand_expr (exp, target, tmode, modifier) example A ? throw : E */ if (temp != 0 && TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node) - store_expr (TREE_OPERAND (exp, 1), temp, 0); + store_expr (TREE_OPERAND (exp, 1), temp, + modifier == EXPAND_STACK_PARM ? 2 : 0); else expand_expr (TREE_OPERAND (exp, 1), ignore ? const0_rtx : NULL_RTX, VOIDmode, 0); @@ -8757,7 +8941,8 @@ expand_expr (exp, target, tmode, modifier) start_cleanup_deferral (); if (temp != 0 && TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node) - store_expr (TREE_OPERAND (exp, 2), temp, 0); + store_expr (TREE_OPERAND (exp, 2), temp, + modifier == EXPAND_STACK_PARM ? 2 : 0); else expand_expr (TREE_OPERAND (exp, 2), ignore ? const0_rtx : NULL_RTX, VOIDmode, 0); @@ -8811,11 +8996,9 @@ expand_expr (exp, target, tmode, modifier) else { target = assign_temp (type, 2, 0, 1); - /* All temp slots at this level must not conflict. */ - preserve_temp_slots (target); SET_DECL_RTL (slot, target); if (TREE_ADDRESSABLE (slot)) - put_var_into_stack (slot); + put_var_into_stack (slot, /*rescan=*/false); /* Since SLOT is not known to the called function to belong to its stack frame, we must build an explicit @@ -8854,7 +9037,7 @@ expand_expr (exp, target, tmode, modifier) /* If we must have an addressable slot, then make sure that the RTL that we just stored in slot is OK. */ if (TREE_ADDRESSABLE (slot)) - put_var_into_stack (slot); + put_var_into_stack (slot, /*rescan=*/true); } } @@ -8862,7 +9045,7 @@ expand_expr (exp, target, tmode, modifier) /* Mark it as expanded. */ TREE_OPERAND (exp, 1) = NULL_TREE; - store_expr (exp1, target, 0); + store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0); expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp)); @@ -8947,6 +9130,8 @@ expand_expr (exp, target, tmode, modifier) return expand_increment (exp, ! ignore, ignore); case ADDR_EXPR: + if (modifier == EXPAND_STACK_PARM) + target = 0; /* Are we taking the address of a nested function? */ if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL && decl_function_context (TREE_OPERAND (exp, 0)) != 0 @@ -9002,7 +9187,8 @@ expand_expr (exp, target, tmode, modifier) forcing the SAVE_EXPR into memory. */ if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR) { - put_var_into_stack (TREE_OPERAND (exp, 0)); + put_var_into_stack (TREE_OPERAND (exp, 0), + /*rescan=*/true); op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0)); } else @@ -9055,20 +9241,30 @@ expand_expr (exp, target, tmode, modifier) && MEM_ALIGN (op0) < BIGGEST_ALIGNMENT) { tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0)); - rtx new - = assign_stack_temp_for_type - (TYPE_MODE (inner_type), - MEM_SIZE (op0) ? INTVAL (MEM_SIZE (op0)) - : int_size_in_bytes (inner_type), - 1, build_qualified_type (inner_type, - (TYPE_QUALS (inner_type) - | TYPE_QUAL_CONST))); + rtx new; if (TYPE_ALIGN_OK (inner_type)) abort (); + if (TREE_ADDRESSABLE (inner_type)) + { + /* We can't make a bitwise copy of this object, so fail. */ + error ("cannot take the address of an unaligned member"); + return const0_rtx; + } + + new = assign_stack_temp_for_type + (TYPE_MODE (inner_type), + MEM_SIZE (op0) ? INTVAL (MEM_SIZE (op0)) + : int_size_in_bytes (inner_type), + 1, build_qualified_type (inner_type, + (TYPE_QUALS (inner_type) + | TYPE_QUAL_CONST))); + emit_block_move (new, op0, expr_size (TREE_OPERAND (exp, 0)), - BLOCK_OP_NORMAL); + (modifier == EXPAND_STACK_PARM + ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); + op0 = new; } @@ -9284,6 +9480,8 @@ expand_expr (exp, target, tmode, modifier) op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0); binop2: + if (modifier == EXPAND_STACK_PARM) + target = 0; temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp, OPTAB_LIB_WIDEN); if (temp == 0) @@ -9696,6 +9894,9 @@ do_jump (exp, if_false_label, if_true_label) break; case INTEGER_CST: + /* ??? This should never happen - but it does, GCC PR opt/14749. */ + if (TREE_CONSTANT_OVERFLOW (exp)) + goto normal; temp = integer_zerop (exp) ? if_false_label : if_true_label; if (temp) emit_jump (temp); @@ -9710,6 +9911,12 @@ do_jump (exp, if_false_label, if_true_label) break; #endif + case UNSAVE_EXPR: + do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); + TREE_OPERAND (exp, 0) + = (*lang_hooks.unsave_expr_now) (TREE_OPERAND (exp, 0)); + break; + case NOP_EXPR: if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF || TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF @@ -11032,6 +11239,7 @@ do_tablejump (index, mode, range, table_label, default_label) temp = gen_reg_rtx (CASE_VECTOR_MODE); vector = gen_rtx_MEM (CASE_VECTOR_MODE, index); RTX_UNCHANGING_P (vector) = 1; + MEM_NOTRAP_P (vector) = 1; convert_move (temp, vector, 0); emit_jump_insn (gen_tablejump (temp, table_label)); @@ -11101,4 +11309,45 @@ vector_mode_valid_p (mode) return mov_optab->handlers[innermode].insn_code != CODE_FOR_nothing; } +/* Return a CONST_VECTOR rtx for a VECTOR_CST tree. */ +static rtx +const_vector_from_tree (exp) + tree exp; +{ + rtvec v; + int units, i; + tree link, elt; + enum machine_mode inner, mode; + + mode = TYPE_MODE (TREE_TYPE (exp)); + + if (is_zeros_p (exp)) + return CONST0_RTX (mode); + + units = GET_MODE_NUNITS (mode); + inner = GET_MODE_INNER (mode); + + v = rtvec_alloc (units); + + link = TREE_VECTOR_CST_ELTS (exp); + for (i = 0; link; link = TREE_CHAIN (link), ++i) + { + elt = TREE_VALUE (link); + + if (TREE_CODE (elt) == REAL_CST) + RTVEC_ELT (v, i) = CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (elt), + inner); + else + RTVEC_ELT (v, i) = immed_double_const (TREE_INT_CST_LOW (elt), + TREE_INT_CST_HIGH (elt), + inner); + } + + /* Initialize remaining elements to 0. */ + for (; i < units; ++i) + RTVEC_ELT (v, i) = CONST0_RTX (inner); + + return gen_rtx_raw_CONST_VECTOR (mode, v); +} + #include "gt-expr.h" |