aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c168
1 files changed, 83 insertions, 85 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index f4ff9b2d743..1b2a4e66d97 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -30,8 +30,6 @@ Boston, MA 02111-1307, USA. */
#include "hard-reg-set.h"
#include "except.h"
#include "function.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
#include "insn-config.h"
/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
#include "expr.h"
@@ -44,19 +42,6 @@ Boston, MA 02111-1307, USA. */
#include "intl.h"
#include "tm_p.h"
-#ifndef ACCUMULATE_OUTGOING_ARGS
-#define ACCUMULATE_OUTGOING_ARGS 0
-#endif
-
-/* Supply a default definition for PUSH_ARGS. */
-#ifndef PUSH_ARGS
-#ifdef PUSH_ROUNDING
-#define PUSH_ARGS !ACCUMULATE_OUTGOING_ARGS
-#else
-#define PUSH_ARGS 0
-#endif
-#endif
-
/* Decide whether a function's arguments should be processed
from first to last or from last to first.
@@ -410,6 +395,9 @@ protect_from_queue (x, modify)
QUEUED_INSN (y));
return temp;
}
+ /* Copy the address into a pseudo, so that the returned value
+ remains correct across calls to emit_queue. */
+ XEXP (new, 0) = copy_to_reg (XEXP (new, 0));
return new;
}
/* Otherwise, recursively protect the subexpressions of all
@@ -436,9 +424,11 @@ protect_from_queue (x, modify)
}
return x;
}
- /* If the increment has not happened, use the variable itself. */
+ /* If the increment has not happened, use the variable itself. Copy it
+ into a new pseudo so that the value remains correct across calls to
+ emit_queue. */
if (QUEUED_INSN (x) == 0)
- return QUEUED_VAR (x);
+ return copy_to_reg (QUEUED_VAR (x));
/* If the increment has happened and a pre-increment copy exists,
use that copy. */
if (QUEUED_COPY (x) != 0)
@@ -1506,7 +1496,7 @@ move_by_pieces (to, from, len, align)
}
/* Return number of insns required to move L bytes by pieces.
- ALIGN (in bytes) is maximum alignment we can assume. */
+ ALIGN (in bits) is maximum alignment we can assume. */
static unsigned HOST_WIDE_INT
move_by_pieces_ninsns (l, align)
@@ -1757,6 +1747,7 @@ emit_block_move (x, y, size, align)
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
+ TREE_NOTHROW (fn) = 1;
make_decl_rtl (fn, NULL_PTR);
assemble_external (fn);
}
@@ -1948,18 +1939,6 @@ emit_group_load (dst, orig_src, ssize, align)
tmps = (rtx *) alloca (sizeof (rtx) * XVECLEN (dst, 0));
- /* If we won't be loading directly from memory, protect the real source
- from strange tricks we might play. */
- src = orig_src;
- if (GET_CODE (src) != MEM && ! CONSTANT_P (src))
- {
- if (GET_MODE (src) == VOIDmode)
- src = gen_reg_rtx (GET_MODE (dst));
- else
- src = gen_reg_rtx (GET_MODE (orig_src));
- emit_move_insn (src, orig_src);
- }
-
/* Process the pieces. */
for (i = start; i < XVECLEN (dst, 0); i++)
{
@@ -1977,6 +1956,22 @@ emit_group_load (dst, orig_src, ssize, align)
abort ();
}
+ /* If we won't be loading directly from memory, protect the real source
+ from strange tricks we might play; but make sure that the source can
+ be loaded directly into the destination. */
+ src = orig_src;
+ if (GET_CODE (orig_src) != MEM
+ && (!CONSTANT_P (orig_src)
+ || (GET_MODE (orig_src) != mode
+ && GET_MODE (orig_src) != VOIDmode)))
+ {
+ if (GET_MODE (orig_src) == VOIDmode)
+ src = gen_reg_rtx (mode);
+ else
+ src = gen_reg_rtx (GET_MODE (orig_src));
+ emit_move_insn (src, orig_src);
+ }
+
/* Optimize the access just a bit. */
if (GET_CODE (src) == MEM
&& align >= GET_MODE_ALIGNMENT (mode)
@@ -2000,8 +1995,7 @@ emit_group_load (dst, orig_src, ssize, align)
else
abort ();
}
- else if ((CONSTANT_P (src)
- && (GET_MODE (src) == VOIDmode || GET_MODE (src) == mode))
+ else if (CONSTANT_P (src)
|| (GET_CODE (src) == REG && GET_MODE (src) == mode))
tmps[i] = src;
else
@@ -2639,7 +2633,7 @@ clear_storage (object, size, align)
For targets where libcalls and normal calls have different
conventions for returning pointers, we could end up generating
- incorrect code.
+ incorrect code.
So instead of using a libcall sequence we build up a suitable
CALL_EXPR and expand the call in the normal fashion. */
@@ -2657,6 +2651,7 @@ clear_storage (object, size, align)
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
+ TREE_NOTHROW (fn) = 1;
make_decl_rtl (fn, NULL_PTR);
assemble_external (fn);
}
@@ -2766,7 +2761,7 @@ emit_move_insn_1 (x, y)
enum mode_class class = GET_MODE_CLASS (mode);
unsigned int i;
- if (mode >= MAX_MACHINE_MODE)
+ if ((unsigned int) mode >= (unsigned int) MAX_MACHINE_MODE)
abort ();
if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
@@ -3077,7 +3072,7 @@ get_push_address (size)
SIZE is an rtx for the size of data to be copied (in bytes),
needed only if X is BLKmode.
- ALIGN is maximum alignment we can assume.
+ 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.
@@ -3180,7 +3175,8 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
and such small pushes do rounding that causes trouble. */
&& ((! SLOW_UNALIGNED_ACCESS (word_mode, align))
|| align >= BIGGEST_ALIGNMENT
- || PUSH_ROUNDING (align) == align)
+ || (PUSH_ROUNDING (align / BITS_PER_UNIT)
+ == (align / BITS_PER_UNIT)))
&& PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
{
/* Push padding now if padding above and stack grows down,
@@ -3843,7 +3839,7 @@ expand_assignment (to, from, want_value, suggest_reg)
TYPE_MODE (sizetype));
#ifdef TARGET_MEM_FUNCTIONS
- emit_library_call (memcpy_libfunc, LCT_NORMAL,
+ emit_library_call (memmove_libfunc, LCT_NORMAL,
VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
XEXP (from_rtx, 0), Pmode,
convert_to_mode (TYPE_MODE (sizetype),
@@ -4435,7 +4431,7 @@ store_constructor (exp, target, align, cleared, size)
/* If the constructor has fewer fields than the structure
or if we are initializing the structure to mostly zeros,
- clear the whole structure first. Don't do this is TARGET is
+ 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 (size > 0
@@ -4721,10 +4717,10 @@ store_constructor (exp, target, align, cleared, size)
index = build_decl (VAR_DECL, NULL_TREE, domain);
- DECL_RTL (index) = index_r
+ index_r
= gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
&unsignedp, 0));
-
+ SET_DECL_RTL (index, index_r);
if (TREE_CODE (value) == SAVE_EXPR
&& SAVE_EXPR_RTL (value) == 0)
{
@@ -5029,6 +5025,11 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
if (TREE_CODE (exp) == ERROR_MARK)
return const0_rtx;
+ /* If we have nothing to store, do nothing unless the expression has
+ side-effects. */
+ if (bitsize == 0)
+ return expand_expr (exp, const0_rtx, VOIDmode, 0);
+
if (bitsize < HOST_BITS_PER_WIDE_INT)
width_mask = ((HOST_WIDE_INT) 1 << bitsize) - 1;
@@ -5204,7 +5205,16 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
(bitpos
/ BITS_PER_UNIT))));
MEM_SET_IN_STRUCT_P (to_rtx, 1);
- MEM_ALIAS_SET (to_rtx) = alias_set;
+ /* If the address of the structure varies, then it might be on
+ the stack. And, stack slots may be shared across scopes.
+ So, two different structures, of different types, can end up
+ at the same location. We will give the structures alias set
+ zero; here we must be careful not to give non-zero alias sets
+ to their fields. */
+ if (!rtx_varies_p (addr, /*for_alias=*/0))
+ MEM_ALIAS_SET (to_rtx) = alias_set;
+ else
+ MEM_ALIAS_SET (to_rtx) = 0;
return store_expr (exp, to_rtx, value_mode != VOIDmode);
}
@@ -5649,7 +5659,7 @@ safe_from_p (x, exp, top_p)
switch (TREE_CODE_CLASS (TREE_CODE (exp)))
{
case 'd':
- exp_rtl = DECL_RTL (exp);
+ exp_rtl = DECL_RTL_SET_P (exp) ? DECL_RTL (exp) : NULL_RTX;
break;
case 'c':
@@ -5766,7 +5776,8 @@ safe_from_p (x, exp, top_p)
/* If this is a language-specific tree code, it may require
special handling. */
- if (TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE
+ if ((unsigned int) TREE_CODE (exp)
+ >= (unsigned int) LAST_AND_UNUSED_TREE_CODE
&& lang_safe_from_p
&& !(*lang_safe_from_p) (x, exp))
return 0;
@@ -6221,7 +6232,7 @@ expand_expr (exp, target, tmode, modifier)
copy_rtx (XEXP (DECL_RTL (exp), 0)));
/* If we got something, return it. But first, set the alignment
- the address is a register. */
+ if the address is a register. */
if (temp != 0)
{
if (GET_CODE (temp) == MEM && GET_CODE (XEXP (temp, 0)) == REG)
@@ -6494,6 +6505,8 @@ expand_expr (exp, target, tmode, modifier)
case LABELED_BLOCK_EXPR:
if (LABELED_BLOCK_BODY (exp))
expand_expr_stmt (LABELED_BLOCK_BODY (exp));
+ /* Should perhaps use expand_label, but this is simpler and safer. */
+ do_pending_stack_adjust ();
emit_label (label_rtx (LABELED_BLOCK_LABEL (exp)));
return const0_rtx;
@@ -6529,7 +6542,7 @@ expand_expr (exp, target, tmode, modifier)
/* If VARS have not yet been expanded, expand them now. */
while (vars)
{
- if (DECL_RTL (vars) == 0)
+ if (!DECL_RTL_SET_P (vars))
{
vars_need_expansion = 1;
expand_decl (vars);
@@ -6753,7 +6766,7 @@ expand_expr (exp, target, tmode, modifier)
elem = TREE_CHAIN (elem))
;
- if (elem)
+ if (elem && !TREE_SIDE_EFFECTS (TREE_VALUE (elem)))
return expand_expr (fold (TREE_VALUE (elem)), target,
tmode, ro_modifier);
}
@@ -7956,21 +7969,21 @@ expand_expr (exp, target, tmode, modifier)
&& (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))
== TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 2), 0))))
{
- tree true = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
- tree false = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
-
- if ((TREE_CODE_CLASS (TREE_CODE (true)) == '2'
- && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
- || (TREE_CODE_CLASS (TREE_CODE (false)) == '2'
- && operand_equal_p (true, TREE_OPERAND (false, 0), 0))
- || (TREE_CODE_CLASS (TREE_CODE (true)) == '1'
- && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
- || (TREE_CODE_CLASS (TREE_CODE (false)) == '1'
- && operand_equal_p (true, TREE_OPERAND (false, 0), 0)))
+ tree iftrue = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
+ tree iffalse = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
+
+ if ((TREE_CODE_CLASS (TREE_CODE (iftrue)) == '2'
+ && operand_equal_p (iffalse, TREE_OPERAND (iftrue, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (iffalse)) == '2'
+ && operand_equal_p (iftrue, TREE_OPERAND (iffalse, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (iftrue)) == '1'
+ && operand_equal_p (iffalse, TREE_OPERAND (iftrue, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (iffalse)) == '1'
+ && operand_equal_p (iftrue, TREE_OPERAND (iffalse, 0), 0)))
return expand_expr (build1 (NOP_EXPR, type,
- build (COND_EXPR, TREE_TYPE (true),
+ build (COND_EXPR, TREE_TYPE (iftrue),
TREE_OPERAND (exp, 0),
- true, false)),
+ iftrue, iffalse)),
target, tmode, modifier);
}
@@ -8268,7 +8281,7 @@ expand_expr (exp, target, tmode, modifier)
if (target == 0)
{
- if (DECL_RTL (slot) != 0)
+ if (DECL_RTL_SET_P (slot))
{
target = DECL_RTL (slot);
/* If we have already expanded the slot, so don't do
@@ -8281,7 +8294,7 @@ expand_expr (exp, target, tmode, modifier)
target = assign_temp (type, 2, 0, 1);
/* All temp slots at this level must not conflict. */
preserve_temp_slots (target);
- DECL_RTL (slot) = target;
+ SET_DECL_RTL (slot, target);
if (TREE_ADDRESSABLE (slot))
put_var_into_stack (slot);
@@ -8307,7 +8320,7 @@ expand_expr (exp, target, tmode, modifier)
/* If we have already assigned it space, use that space,
not target that we were passed in, as our target
parameter is only a hint. */
- if (DECL_RTL (slot) != 0)
+ if (DECL_RTL_SET_P (slot))
{
target = DECL_RTL (slot);
/* If we have already expanded the slot, so don't do
@@ -8317,7 +8330,7 @@ expand_expr (exp, target, tmode, modifier)
}
else
{
- DECL_RTL (slot) = target;
+ SET_DECL_RTL (slot, target);
/* 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))
@@ -8372,12 +8385,6 @@ expand_expr (exp, target, tmode, modifier)
temp = 0;
- if (TREE_CODE (lhs) != VAR_DECL
- && TREE_CODE (lhs) != RESULT_DECL
- && TREE_CODE (lhs) != PARM_DECL
- && ! (TREE_CODE (lhs) == INDIRECT_REF
- && TYPE_READONLY (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
-
/* Check for |= or &= of a bitfield of size one into another bitfield
of size 1. In this case, (unless we need the result of the
assignment) we can do this more efficiently with a
@@ -8474,7 +8481,9 @@ expand_expr (exp, target, tmode, modifier)
if (ignore)
return op0;
- op0 = protect_from_queue (op0, 0);
+ /* Pass 1 for MODIFY, so that protect_from_queue doesn't get
+ clever and returns a REG when given a MEM. */
+ op0 = protect_from_queue (op0, 1);
/* We would like the object in memory. If it is a constant, we can
have it be statically allocated into memory. For a non-constant,
@@ -8644,7 +8653,7 @@ expand_expr (exp, target, tmode, modifier)
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
- expand_eh_region_end (handler);
+ expand_eh_region_end_cleanup (handler);
return op0;
}
@@ -8691,23 +8700,12 @@ expand_expr (exp, target, tmode, modifier)
return const0_rtx;
}
- case POPDCC_EXPR:
- {
- rtx dcc = get_dynamic_cleanup_chain ();
- emit_move_insn (dcc, validize_mem (gen_rtx_MEM (Pmode, dcc)));
- return const0_rtx;
- }
-
- case POPDHC_EXPR:
- {
- rtx dhc = get_dynamic_handler_chain ();
- emit_move_insn (dhc, validize_mem (gen_rtx_MEM (Pmode, dhc)));
- return const0_rtx;
- }
-
case VA_ARG_EXPR:
return expand_builtin_va_arg (TREE_OPERAND (exp, 0), type);
+ case EXC_PTR_EXPR:
+ return get_exception_pointer (cfun);
+
default:
return (*lang_expand_expr) (exp, original_target, tmode, modifier);
}