#include "langhooks.h"
#include "intl.h"
#include "tm_p.h"
+#include "tree-iterator.h"
+#include "tree-pass.h"
+#include "tree-flow.h"
#include "target.h"
+#include "timevar.h"
/* Decide whether a function's arguments should be processed
from first to last or from last to first.
#endif
#endif
-/* Convert defined/undefined to boolean. */
-#ifdef TARGET_MEM_FUNCTIONS
-#undef TARGET_MEM_FUNCTIONS
-#define TARGET_MEM_FUNCTIONS 1
-#else
-#define TARGET_MEM_FUNCTIONS 0
-#endif
-
/* If this is nonzero, we do not bother generating VOLATILE
around volatile memory references, and we are willing to
the same indirect address eventually. */
int cse_not_expected;
-/* Chain of pending expressions for PLACEHOLDER_EXPR to replace. */
-tree placeholder_list = 0;
-
/* This structure is used by move_by_pieces to describe the move to
be performed. */
struct move_by_pieces
static tree clear_storage_libcall_fn (int);
static rtx compress_float_constant (rtx, rtx);
static rtx get_subtarget (rtx);
-static int is_zeros_p (tree);
static void store_constructor_field (rtx, unsigned HOST_WIDE_INT,
HOST_WIDE_INT, enum machine_mode,
tree, tree, int, int);
static rtx var_rtx (tree);
static unsigned HOST_WIDE_INT highest_pow2_factor (tree);
-static unsigned HOST_WIDE_INT highest_pow2_factor_for_type (tree, tree);
+static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (tree, tree);
static int is_aligning_offset (tree, tree);
static rtx expand_increment (tree, int, int);
enum insn_code cmpstr_optab[NUM_MACHINE_MODES];
enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
-/* Stack of EXPR_WITH_FILE_LOCATION nested expressions. */
-struct file_stack *expr_wfl_stack;
-
/* SLOW_UNALIGNED_ACCESS is nonzero if unaligned accesses are very slow. */
#ifndef SLOW_UNALIGNED_ACCESS
}
}
-/* Perform all the pending incrementations. */
+/* Retrieve a mark on the queue. */
+
+static rtx
+mark_queue (void)
+{
+ return pending_chain;
+}
-void
-emit_queue (void)
+/* 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 (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);
break;
}
+ QUEUED_BODY (p) = 0;
pending_chain = QUEUED_NEXT (p);
}
}
+
+/* Perform all the pending incrementations. */
+
+void
+emit_queue (void)
+{
+ emit_insns_enqueued_after_mark (NULL_RTX);
+}
\f
/* Copy data from FROM to TO, where the machine modes are not the same.
Both modes may be integer, or both may be floating.
if (to_real != from_real)
abort ();
+ /* If the source and destination are already the same, then there's
+ nothing to do. */
+ if (to == from)
+ return;
+
/* If FROM is a SUBREG that indicates that we have already done at least
the required extension, strip it. We don't handle such SUBREGs as
TO here. */
&& ((code = can_extend_p (to_mode, word_mode, unsignedp))
!= CODE_FOR_nothing))
{
- if (GET_CODE (to) == REG)
- emit_insn (gen_rtx_CLOBBER (VOIDmode, to));
+ if (REG_P (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);
if (GET_MODE_BITSIZE (from_mode) > BITS_PER_WORD
&& GET_MODE_BITSIZE (to_mode) <= BITS_PER_WORD)
{
- if (!((GET_CODE (from) == MEM
+ if (!((MEM_P (from)
&& ! MEM_VOLATILE_P (from)
&& direct_load[(int) to_mode]
&& ! mode_dependent_address_p (XEXP (from, 0)))
- || GET_CODE (from) == REG
+ || REG_P (from)
|| GET_CODE (from) == SUBREG))
from = force_reg (from_mode, from);
convert_move (to, gen_lowpart (word_mode, from), 0);
&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),
GET_MODE_BITSIZE (from_mode)))
{
- if (!((GET_CODE (from) == MEM
+ if (!((MEM_P (from)
&& ! MEM_VOLATILE_P (from)
&& direct_load[(int) to_mode]
&& ! mode_dependent_address_p (XEXP (from, 0)))
- || GET_CODE (from) == REG
+ || REG_P (from)
|| GET_CODE (from) == SUBREG))
from = force_reg (from_mode, from);
- if (GET_CODE (from) == REG && REGNO (from) < FIRST_PSEUDO_REGISTER
+ if (REG_P (from) && REGNO (from) < FIRST_PSEUDO_REGISTER
&& ! HARD_REGNO_MODE_OK (REGNO (from), to_mode))
from = copy_to_reg (from);
emit_move_insn (to, gen_lowpart (to_mode, from));
&& GET_MODE_CLASS (oldmode) == MODE_INT
&& (GET_CODE (x) == CONST_DOUBLE
|| (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (oldmode)
- && ((GET_CODE (x) == MEM && ! MEM_VOLATILE_P (x)
+ && ((MEM_P (x) && ! MEM_VOLATILE_P (x)
&& direct_load[(int) mode])
- || (GET_CODE (x) == REG
+ || (REG_P (x)
&& (! HARD_REGISTER_P (x)
|| HARD_REGNO_MODE_OK (REGNO (x), mode))
&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
- if (GET_MODE (x) != BLKmode)
- abort ();
- if (GET_MODE (y) != BLKmode)
- abort ();
-
x = protect_from_queue (x, 1);
y = protect_from_queue (y, 0);
size = protect_from_queue (size, 0);
- if (GET_CODE (x) != MEM)
+ if (!MEM_P (x))
abort ();
- if (GET_CODE (y) != MEM)
+ if (!MEM_P (y))
abort ();
if (size == 0)
abort ();
+ /* Make sure we've got BLKmode addresses; store_one_arg can decide that
+ block copy is more efficient for other large modes, e.g. DCmode. */
+ x = adjust_address (x, BLKmode, 0);
+ y = adjust_address (y, BLKmode, 0);
+
/* Set MEM_SIZE as appropriate for this block copy. The main place this
can be incorrect is coming from __builtin_memcpy. */
if (GET_CODE (size) == CONST_INT)
return false;
}
-/* A subroutine of emit_block_move. Expand a call to memcpy or bcopy.
+/* A subroutine of emit_block_move. Expand a call to memcpy.
Return the return value from memcpy, 0 otherwise. */
static rtx
could get the wrong value for an argument.
To avoid this problem we go ahead and emit code to copy the addresses of
- DST and SRC and SIZE into new pseudos. We can then place those new
- pseudos into an RTL_EXPR and use them later, even after a call to
- emit_queue.
+ DST and SRC and SIZE into new pseudos.
Note this is not strictly needed for library calls since they do not call
emit_queue before loading their arguments. However, we may need to have
dst_tree = make_tree (ptr_type_node, dst_addr);
src_tree = make_tree (ptr_type_node, src_addr);
- if (TARGET_MEM_FUNCTIONS)
- size_mode = TYPE_MODE (sizetype);
- else
- size_mode = TYPE_MODE (unsigned_type_node);
+ size_mode = TYPE_MODE (sizetype);
size = convert_to_mode (size_mode, size, 1);
size = copy_to_mode_reg (size_mode, size);
memcpy in this context. This could be a user call to memcpy and
the user may wish to examine the return value from memcpy. For
targets where libcalls and normal calls have different conventions
- for returning pointers, we could end up generating incorrect code.
+ for returning pointers, we could end up generating incorrect code. */
- For convenience, we generate the call to bcopy this way as well. */
-
- if (TARGET_MEM_FUNCTIONS)
- size_tree = make_tree (sizetype, size);
- else
- size_tree = make_tree (unsigned_type_node, size);
+ size_tree = make_tree (sizetype, size);
fn = emit_block_move_libcall_fn (true);
arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE);
- if (TARGET_MEM_FUNCTIONS)
- {
- arg_list = tree_cons (NULL_TREE, src_tree, arg_list);
- arg_list = tree_cons (NULL_TREE, dst_tree, arg_list);
- }
- else
- {
- arg_list = tree_cons (NULL_TREE, dst_tree, arg_list);
- arg_list = tree_cons (NULL_TREE, src_tree, arg_list);
- }
+ arg_list = tree_cons (NULL_TREE, src_tree, arg_list);
+ arg_list = tree_cons (NULL_TREE, dst_tree, arg_list);
/* Now we have to build up the CALL_EXPR itself. */
call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
gen_rtx_CLOBBER (VOIDmode, dst),
NULL_RTX));
- return TARGET_MEM_FUNCTIONS ? retval : NULL_RTX;
+ return retval;
}
/* A subroutine of emit_block_move_via_libcall. Create the tree node
{
tree args, fn;
- if (TARGET_MEM_FUNCTIONS)
- {
- fn = get_identifier ("memcpy");
- args = build_function_type_list (ptr_type_node, ptr_type_node,
- const_ptr_type_node, sizetype,
- NULL_TREE);
- }
- else
- {
- fn = get_identifier ("bcopy");
- args = build_function_type_list (void_type_node, const_ptr_type_node,
- ptr_type_node, unsigned_type_node,
- NULL_TREE);
- }
+ fn = get_identifier ("memcpy");
+ args = build_function_type_list (ptr_type_node, ptr_type_node,
+ const_ptr_type_node, sizetype,
+ NULL_TREE);
fn = build_decl (FUNCTION_DECL, fn, args);
DECL_EXTERNAL (fn) = 1;
y_addr = force_operand (XEXP (y, 0), NULL_RTX);
do_pending_stack_adjust ();
- emit_note (NOTE_INSN_LOOP_BEG);
-
emit_jump (cmp_label);
emit_label (top_label);
if (tmp != iter)
emit_move_insn (iter, tmp);
- emit_note (NOTE_INSN_LOOP_CONT);
emit_label (cmp_label);
emit_cmp_and_jump_insns (iter, size, LT, NULL_RTX, iter_mode,
true, top_label);
-
- emit_note (NOTE_INSN_LOOP_END);
}
\f
/* Copy all or part of a value X into registers starting at REGNO.
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
+ if (!MEM_P (orig_src)
&& (!CONSTANT_P (orig_src)
|| (GET_MODE (orig_src) != mode
&& GET_MODE (orig_src) != VOIDmode)))
}
/* Optimize the access just a bit. */
- if (GET_CODE (src) == MEM
+ if (MEM_P (src)
&& (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (src))
|| MEM_ALIGN (src) >= GET_MODE_ALIGNMENT (mode))
&& bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
to be extracted. */
tmps[i] = XEXP (src, bytepos / slen0);
if (! CONSTANT_P (tmps[i])
- && (GET_CODE (tmps[i]) != REG || GET_MODE (tmps[i]) != mode))
+ && (!REG_P (tmps[i]) || GET_MODE (tmps[i]) != mode))
tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
(bytepos % slen0) * BITS_PER_UNIT,
1, NULL_RTX, mode, mode, ssize);
SIMD register, which is currently broken. While we get GCC
to emit proper RTL for these cases, let's dump to memory. */
else if (VECTOR_MODE_P (GET_MODE (dst))
- && GET_CODE (src) == REG)
+ && REG_P (src))
{
int slen = GET_MODE_SIZE (GET_MODE (src));
rtx mem;
&& XVECLEN (dst, 0) > 1)
tmps[i] = simplify_gen_subreg (mode, src, GET_MODE(dst), bytepos);
else if (CONSTANT_P (src)
- || (GET_CODE (src) == REG && GET_MODE (src) == mode))
+ || (REG_P (src) && GET_MODE (src) == mode))
tmps[i] = src;
else
tmps[i] = extract_bit_field (src, bytelen * BITS_PER_UNIT,
mode, mode, ssize);
if (shift)
- expand_binop (mode, ashl_optab, tmps[i], GEN_INT (shift),
- tmps[i], 0, OPTAB_WIDEN);
+ tmps[i] = expand_shift (LSHIFT_EXPR, mode, tmps[i],
+ build_int_2 (shift, 0), tmps[i], 0);
}
emit_queue ();
emit_group_load (dst, temp, type, ssize);
return;
}
- else if (GET_CODE (dst) != MEM && GET_CODE (dst) != CONCAT)
+ else if (!MEM_P (dst) && GET_CODE (dst) != CONCAT)
{
dst = gen_reg_rtx (GET_MODE (orig_dst));
/* Make life a bit easier for combine. */
)
{
int shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
- expand_binop (mode, ashr_optab, tmps[i], GEN_INT (shift),
- tmps[i], 0, OPTAB_WIDEN);
+ tmps[i] = expand_shift (RSHIFT_EXPR, mode, tmps[i],
+ build_int_2 (shift, 0), tmps[i], 0);
}
bytelen = ssize - bytepos;
}
}
/* Optimize the access just a bit. */
- if (GET_CODE (dest) == MEM
+ if (MEM_P (dest)
&& (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (dest))
|| MEM_ALIGN (dest) >= GET_MODE_ALIGNMENT (mode))
&& bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
if (GET_MODE (srcreg) != BLKmode
&& GET_MODE_SIZE (GET_MODE (srcreg)) < UNITS_PER_WORD)
- srcreg = convert_to_mode (word_mode, srcreg, TREE_UNSIGNED (type));
+ srcreg = convert_to_mode (word_mode, srcreg, TYPE_UNSIGNED (type));
/* If the structure doesn't take up a whole number of words, see whether
SRCREG is padded on the left or on the right. If it's on the left,
void
use_reg (rtx *call_fusage, rtx reg)
{
- if (GET_CODE (reg) != REG
+ if (!REG_P (reg)
|| REGNO (reg) >= FIRST_PSEUDO_REGISTER)
abort ();
/* A NULL entry means the parameter goes both on the stack and in
registers. This can also be a MEM for targets that pass values
partially on the stack and partially in registers. */
- if (reg != 0 && GET_CODE (reg) == REG)
+ if (reg != 0 && REG_P (reg))
use_reg (call_fusage, reg);
}
}
clear_storage (rtx object, rtx size)
{
rtx retval = 0;
- unsigned int align = (GET_CODE (object) == MEM ? MEM_ALIGN (object)
+ unsigned int align = (MEM_P (object) ? MEM_ALIGN (object)
: GET_MODE_ALIGNMENT (GET_MODE (object)));
/* If OBJECT is not BLKmode and SIZE is the same size as its mode,
return false;
}
-/* A subroutine of clear_storage. Expand a call to memset or bzero.
+/* A subroutine of clear_storage. Expand a call to memset.
Return the return value of memset, 0 otherwise. */
static rtx
not careful we could get the wrong value for an argument.
To avoid this problem we go ahead and emit code to copy OBJECT
- and SIZE into new pseudos. We can then place those new pseudos
- into an RTL_EXPR and use them later, even after a call to
- emit_queue.
+ and SIZE into new pseudos.
Note this is not strictly needed for library calls since they
do not call emit_queue before loading their arguments. However,
object = copy_to_mode_reg (Pmode, XEXP (object, 0));
- if (TARGET_MEM_FUNCTIONS)
- size_mode = TYPE_MODE (sizetype);
- else
- size_mode = TYPE_MODE (unsigned_type_node);
+ size_mode = TYPE_MODE (sizetype);
size = convert_to_mode (size_mode, size, 1);
size = copy_to_mode_reg (size_mode, size);
memset in this context. This could be a user call to memset and
the user may wish to examine the return value from memset. For
targets where libcalls and normal calls have different conventions
- for returning pointers, we could end up generating incorrect code.
-
- For convenience, we generate the call to bzero this way as well. */
+ for returning pointers, we could end up generating incorrect code. */
object_tree = make_tree (ptr_type_node, object);
- if (TARGET_MEM_FUNCTIONS)
- size_tree = make_tree (sizetype, size);
- else
- size_tree = make_tree (unsigned_type_node, size);
+ size_tree = make_tree (sizetype, size);
fn = clear_storage_libcall_fn (true);
arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE);
- if (TARGET_MEM_FUNCTIONS)
- arg_list = tree_cons (NULL_TREE, integer_zero_node, arg_list);
+ arg_list = tree_cons (NULL_TREE, integer_zero_node, arg_list);
arg_list = tree_cons (NULL_TREE, object_tree, arg_list);
/* Now we have to build up the CALL_EXPR itself. */
if (RTX_UNCHANGING_P (object))
emit_insn (gen_rtx_CLOBBER (VOIDmode, object));
- return (TARGET_MEM_FUNCTIONS ? retval : NULL_RTX);
+ return retval;
}
/* A subroutine of clear_storage_via_libcall. Create the tree node
{
tree fn, args;
- if (TARGET_MEM_FUNCTIONS)
- {
- fn = get_identifier ("memset");
- args = build_function_type_list (ptr_type_node, ptr_type_node,
- integer_type_node, sizetype,
- NULL_TREE);
- }
- else
- {
- fn = get_identifier ("bzero");
- args = build_function_type_list (void_type_node, ptr_type_node,
- unsigned_type_node, NULL_TREE);
- }
+ fn = get_identifier ("memset");
+ args = build_function_type_list (ptr_type_node, ptr_type_node,
+ integer_type_node, sizetype,
+ NULL_TREE);
fn = build_decl (FUNCTION_DECL, fn, args);
DECL_EXTERNAL (fn) = 1;
if (mode == BLKmode || (GET_MODE (y) != mode && GET_MODE (y) != VOIDmode))
abort ();
- /* Never force constant_p_rtx to memory. */
- if (GET_CODE (y) == CONSTANT_P_RTX)
- ;
- else if (CONSTANT_P (y))
+ if (CONSTANT_P (y))
{
if (optimize
&& SCALAR_FLOAT_MODE_P (GET_MODE (x))
/* If X or Y are memory references, verify that their addresses are valid
for the machine. */
- if (GET_CODE (x) == MEM
+ if (MEM_P (x)
&& ((! memory_address_p (GET_MODE (x), XEXP (x, 0))
&& ! push_operand (x, GET_MODE (x)))
|| (flag_force_addr
&& CONSTANT_ADDRESS_P (XEXP (x, 0)))))
x = validize_mem (x);
- if (GET_CODE (y) == MEM
+ if (MEM_P (y)
&& (! memory_address_p (GET_MODE (y), XEXP (y, 0))
|| (flag_force_addr
&& CONSTANT_ADDRESS_P (XEXP (y, 0)))))
last_insn = emit_move_insn_1 (x, y);
- if (y_cst && GET_CODE (x) == REG
+ if (y_cst && REG_P (x)
&& (set = single_set (last_insn)) != NULL_RTX
&& SET_DEST (set) == x
&& ! rtx_equal_p (y_cst, SET_SRC (set)))
GET_MODE_SIZE (mode), 0);
rtx cmem = adjust_address (mem, mode, 0);
- cfun->cannot_inline
- = N_("function using short complex types cannot be inline");
-
if (packed_dest_p)
{
rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
if (reload_in_progress)
{
x = gen_lowpart_common (tmode, x1);
- if (x == 0 && GET_CODE (x1) == MEM)
+ if (x == 0 && MEM_P (x1))
{
x = adjust_address_nv (x1, tmode, 0);
copy_replacements (x1, x);
}
y = gen_lowpart_common (tmode, y1);
- if (y == 0 && GET_CODE (y1) == MEM)
+ if (y == 0 && MEM_P (y1))
{
y = adjust_address_nv (y1, tmode, 0);
copy_replacements (y1, y);
/* If we are in reload, see if either operand is a MEM whose address
is scheduled for replacement. */
- if (reload_in_progress && GET_CODE (x) == MEM
+ if (reload_in_progress && MEM_P (x)
&& (inner = find_replacement (&XEXP (x, 0))) != XEXP (x, 0))
x = replace_equiv_address_nv (x, inner);
- if (reload_in_progress && GET_CODE (y) == MEM
+ if (reload_in_progress && MEM_P (y)
&& (inner = find_replacement (&XEXP (y, 0))) != XEXP (y, 0))
y = replace_equiv_address_nv (y, inner);
emit_unop_insn (ic, x, trunc_y, UNKNOWN);
last_insn = get_last_insn ();
- if (GET_CODE (x) == REG)
+ if (REG_P (x))
set_unique_reg_note (last_insn, REG_EQUAL, y);
return last_insn;
size = convert_modes (Pmode, ptr_mode, size, 1);
if (CONSTANT_P (size))
anti_adjust_stack (plus_constant (size, extra));
- else if (GET_CODE (size) == REG && extra == 0)
+ else if (REG_P (size) && extra == 0)
anti_adjust_stack (size);
else
{
/* If X is a hard register in a non-integer mode, copy it into a pseudo;
SUBREGs of such registers are not allowed. */
- if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER
+ if ((REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER
&& GET_MODE_CLASS (GET_MODE (x)) != MODE_INT))
x = copy_to_reg (x);
{
return ((x == 0
/* Only registers can be subtargets. */
- || GET_CODE (x) != REG
+ || !REG_P (x)
/* If the register is readonly, it can't be set more than once. */
|| RTX_UNCHANGING_P (x)
/* Don't use hard regs to avoid extending their life. */
{
rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
- if (GET_CODE (to_rtx) != MEM)
+ if (!MEM_P (to_rtx))
abort ();
#ifdef POINTERS_EXTEND_UNSIGNED
/* A constant address in TO_RTX can have VOIDmode, we must not try
to call force_reg for that case. Avoid that case. */
- if (GET_CODE (to_rtx) == MEM
+ if (MEM_P (to_rtx)
&& GET_MODE (to_rtx) == BLKmode
&& GET_MODE (XEXP (to_rtx, 0)) != VOIDmode
&& bitsize > 0
}
to_rtx = offset_address (to_rtx, offset_rtx,
- highest_pow2_factor_for_type (TREE_TYPE (to),
- offset));
+ highest_pow2_factor_for_target (to,
+ offset));
}
- if (GET_CODE (to_rtx) == MEM)
+ if (MEM_P (to_rtx))
{
/* If the field is at offset zero, we could have been given the
DECL_RTX of the parent struct. Don't munge it. */
/* Deal with volatile and readonly fields. The former is only done
for MEM. Also set MEM_KEEP_ALIAS_SET_P if needed. */
- if (volatilep && GET_CODE (to_rtx) == MEM)
+ if (volatilep && MEM_P (to_rtx))
{
if (to_rtx == orig_to_rtx)
to_rtx = copy_rtx (to_rtx);
/* 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)))
+ && ! (MEM_P (to_rtx) && ! can_address_p (to)))
{
if (to_rtx == orig_to_rtx)
to_rtx = copy_rtx (to_rtx);
RTX_UNCHANGING_P (to_rtx) = 1;
}
- if (GET_CODE (to_rtx) == MEM && ! can_address_p (to))
+ if (MEM_P (to_rtx) && ! can_address_p (to))
{
if (to_rtx == orig_to_rtx)
to_rtx = copy_rtx (to_rtx);
MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
}
+ /* Disabled temporarily. GET_MODE (to_rtx) is often not the right
+ mode. */
+ while (0 && mode1 == VOIDmode && !want_value
+ && bitpos + bitsize <= BITS_PER_WORD
+ && bitsize < BITS_PER_WORD
+ && GET_MODE_BITSIZE (GET_MODE (to_rtx)) <= BITS_PER_WORD
+ && !TREE_SIDE_EFFECTS (to)
+ && !TREE_THIS_VOLATILE (to))
+ {
+ tree src, op0, op1;
+ rtx value;
+ HOST_WIDE_INT count = bitpos;
+ optab binop;
+
+ src = from;
+ STRIP_NOPS (src);
+ if (TREE_CODE (TREE_TYPE (src)) != INTEGER_TYPE
+ || TREE_CODE_CLASS (TREE_CODE (src)) != '2')
+ break;
+
+ op0 = TREE_OPERAND (src, 0);
+ op1 = TREE_OPERAND (src, 1);
+ STRIP_NOPS (op0);
+
+ if (! operand_equal_p (to, op0, 0))
+ break;
+
+ if (BYTES_BIG_ENDIAN)
+ count = GET_MODE_BITSIZE (GET_MODE (to_rtx)) - bitpos - bitsize;
+
+ /* Special case some bitfield op= exp. */
+ switch (TREE_CODE (src))
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ if (count <= 0)
+ break;
+
+ /* For now, just optimize the case of the topmost bitfield
+ where we don't need to do any masking and also
+ 1 bit bitfields where xor can be used.
+ We might win by one instruction for the other bitfields
+ too if insv/extv instructions aren't used, so that
+ can be added later. */
+ if (count + bitsize != GET_MODE_BITSIZE (GET_MODE (to_rtx))
+ && (bitsize != 1 || TREE_CODE (op1) != INTEGER_CST))
+ break;
+ value = expand_expr (op1, NULL_RTX, VOIDmode, 0);
+ value = protect_from_queue (value, 0);
+ to_rtx = protect_from_queue (to_rtx, 1);
+ binop = TREE_CODE (src) == PLUS_EXPR ? add_optab : sub_optab;
+ if (bitsize == 1
+ && count + bitsize != GET_MODE_BITSIZE (GET_MODE (to_rtx)))
+ {
+ value = expand_and (GET_MODE (to_rtx), value, const1_rtx,
+ NULL_RTX);
+ binop = xor_optab;
+ }
+ value = expand_shift (LSHIFT_EXPR, GET_MODE (to_rtx),
+ value, build_int_2 (count, 0),
+ NULL_RTX, 1);
+ result = expand_binop (GET_MODE (to_rtx), binop, to_rtx,
+ value, to_rtx, 1, OPTAB_WIDEN);
+ if (result != to_rtx)
+ emit_move_insn (to_rtx, result);
+ free_temp_slots ();
+ pop_temp_slots ();
+ return NULL_RTX;
+ default:
+ break;
+ }
+
+ break;
+ }
+
result = store_field (to_rtx, bitsize, bitpos, mode1, from,
(want_value
/* Spurious cast for HPUX compiler. */
return (want_value ? convert_modes (TYPE_MODE (TREE_TYPE (to)),
TYPE_MODE (TREE_TYPE (from)),
result,
- TREE_UNSIGNED (TREE_TYPE (to)))
+ TYPE_UNSIGNED (TREE_TYPE (to)))
: NULL_RTX);
}
if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from, from)
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST
&& ! ((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
- && GET_CODE (DECL_RTL (to)) == REG))
+ && REG_P (DECL_RTL (to))))
{
rtx value;
/* Don't move directly into a return register. */
if (TREE_CODE (to) == RESULT_DECL
- && (GET_CODE (to_rtx) == REG || GET_CODE (to_rtx) == PARALLEL))
+ && (REG_P (to_rtx) || GET_CODE (to_rtx) == PARALLEL))
{
rtx temp;
size = expr_size (from);
from_rtx = expand_expr (from, NULL_RTX, VOIDmode, 0);
- if (TARGET_MEM_FUNCTIONS)
- 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),
- size, TREE_UNSIGNED (sizetype)),
- TYPE_MODE (sizetype));
- else
- emit_library_call (bcopy_libfunc, LCT_NORMAL,
- VOIDmode, 3, XEXP (from_rtx, 0), Pmode,
- XEXP (to_rtx, 0), Pmode,
- convert_to_mode (TYPE_MODE (integer_type_node),
- size,
- TREE_UNSIGNED (integer_type_node)),
- TYPE_MODE (integer_type_node));
+ 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),
+ size, TYPE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
preserve_temp_slots (to_rtx);
free_temp_slots ();
{
rtx temp;
rtx alt_rtl = NULL_RTX;
+ rtx mark = mark_queue ();
int dont_return_target = 0;
int dont_store_target = 0;
dont_return_target = 1;
}
else if ((want_value & 1) != 0
- && GET_CODE (target) == MEM
+ && MEM_P (target)
&& ! MEM_VOLATILE_P (target)
&& GET_MODE (target) != BLKmode)
/* If target is in memory and caller wants value in a register instead,
&& INTEGRAL_TYPE_P (TREE_TYPE (exp))
&& TREE_TYPE (TREE_TYPE (exp)) == 0)
{
- if (TREE_UNSIGNED (TREE_TYPE (exp))
+ if (TYPE_UNSIGNED (TREE_TYPE (exp))
!= SUBREG_PROMOTED_UNSIGNED_P (target))
exp = convert
- ((*lang_hooks.types.signed_or_unsigned_type)
+ (lang_hooks.types.signed_or_unsigned_type
(SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)), exp);
- exp = convert ((*lang_hooks.types.type_for_mode)
+ exp = convert (lang_hooks.types.type_for_mode
(GET_MODE (SUBREG_REG (target)),
SUBREG_PROMOTED_UNSIGNED_P (target)),
exp);
only necessary if the MEM is volatile, or if the address
overlaps TARGET. But not performing the load twice also
reduces the amount of rtl we generate and then have to CSE. */
- if (GET_CODE (temp) == MEM && (want_value & 1) != 0)
+ if (MEM_P (temp) && (want_value & 1) != 0)
temp = copy_to_reg (temp);
/* If TEMP is a VOIDmode constant, use convert_modes to make
Otherwise, if TEMP is not TARGET, return TEMP
if it is constant (for efficiency),
or if we really want the correct value. */
- if (!(target && GET_CODE (target) == REG
+ if (!(target && REG_P (target)
&& REGNO (target) < FIRST_PSEUDO_REGISTER)
- && !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
+ && !(MEM_P (target) && MEM_VOLATILE_P (target))
&& ! rtx_equal_p (temp, target)
&& (CONSTANT_P (temp) || (want_value & 1) != 0))
dont_return_target = 1;
&& TREE_CODE (exp) != ERROR_MARK
&& GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)),
- temp, TREE_UNSIGNED (TREE_TYPE (exp)));
+ temp, TYPE_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:
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)
{
- int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
+ int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
if (dont_return_target)
{
/* In this case, we will return TEMP,
/* Copy that much. */
copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx,
- TREE_UNSIGNED (sizetype));
+ TYPE_UNSIGNED (sizetype));
emit_block_move (target, temp, copy_size_rtx,
(want_value & 2
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (copy_size_rtx) != Pmode)
copy_size_rtx = convert_to_mode (Pmode, copy_size_rtx,
- TREE_UNSIGNED (sizetype));
+ TYPE_UNSIGNED (sizetype));
#endif
target = offset_address (target, copy_size_rtx,
/* If we are supposed to return TEMP, do so as long as it isn't a MEM.
??? The latter test doesn't seem to make sense. */
- else if (dont_return_target && GET_CODE (temp) != MEM)
+ else if (dont_return_target && !MEM_P (temp))
return temp;
/* Return TARGET itself if it is a hard register. */
else if ((want_value & 1) != 0
&& GET_MODE (target) != BLKmode
- && ! (GET_CODE (target) == REG
+ && ! (REG_P (target)
&& REGNO (target) < FIRST_PSEUDO_REGISTER))
return copy_to_reg (target);
return target;
}
\f
-/* Return 1 if EXP just contains zeros. FIXME merge with initializer_zerop. */
+/* 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. */
-static int
-is_zeros_p (tree exp)
+static void
+categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
+ HOST_WIDE_INT *p_nc_elts)
{
- tree elt;
+ HOST_WIDE_INT nz_elts, nc_elts;
+ tree list;
- switch (TREE_CODE (exp))
+ nz_elts = 0;
+ nc_elts = 0;
+
+ for (list = CONSTRUCTOR_ELTS (ctor); list; list = TREE_CHAIN (list))
{
- case CONVERT_EXPR:
- case NOP_EXPR:
- case NON_LVALUE_EXPR:
- case VIEW_CONVERT_EXPR:
- return is_zeros_p (TREE_OPERAND (exp, 0));
+ tree value = TREE_VALUE (list);
+ tree purpose = TREE_PURPOSE (list);
+ HOST_WIDE_INT mult;
- case INTEGER_CST:
- return integer_zerop (exp);
+ mult = 1;
+ if (TREE_CODE (purpose) == RANGE_EXPR)
+ {
+ tree lo_index = TREE_OPERAND (purpose, 0);
+ tree hi_index = TREE_OPERAND (purpose, 1);
- case COMPLEX_CST:
- return
- is_zeros_p (TREE_REALPART (exp)) && is_zeros_p (TREE_IMAGPART (exp));
+ if (host_integerp (lo_index, 1) && host_integerp (hi_index, 1))
+ mult = (tree_low_cst (hi_index, 1)
+ - tree_low_cst (lo_index, 1) + 1);
+ }
- case REAL_CST:
- return REAL_VALUES_IDENTICAL (TREE_REAL_CST (exp), dconst0);
+ switch (TREE_CODE (value))
+ {
+ case CONSTRUCTOR:
+ {
+ HOST_WIDE_INT nz = 0, nc = 0;
+ categorize_ctor_elements_1 (value, &nz, &nc);
+ nz_elts += mult * nz;
+ nc_elts += mult * nc;
+ }
+ break;
- case VECTOR_CST:
- for (elt = TREE_VECTOR_CST_ELTS (exp); elt;
- elt = TREE_CHAIN (elt))
- if (!is_zeros_p (TREE_VALUE (elt)))
- return 0;
+ case INTEGER_CST:
+ case REAL_CST:
+ if (!initializer_zerop (value))
+ nz_elts += mult;
+ break;
+ case COMPLEX_CST:
+ if (!initializer_zerop (TREE_REALPART (value)))
+ nz_elts += mult;
+ if (!initializer_zerop (TREE_IMAGPART (value)))
+ nz_elts += 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;
+ }
+ break;
- return 1;
+ default:
+ nz_elts += mult;
+ if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
+ nc_elts += mult;
+ break;
+ }
+ }
- case CONSTRUCTOR:
- if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
- return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
- for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
- if (! is_zeros_p (TREE_VALUE (elt)))
- return 0;
+ *p_nz_elts += nz_elts;
+ *p_nc_elts += nc_elts;
+}
+void
+categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
+ HOST_WIDE_INT *p_nc_elts)
+{
+ *p_nz_elts = 0;
+ *p_nc_elts = 0;
+ categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts);
+}
+
+/* Count the number of scalars in TYPE. Return -1 on overflow or
+ variable-sized. */
+
+HOST_WIDE_INT
+count_type_elements (tree type)
+{
+ const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1));
+ switch (TREE_CODE (type))
+ {
+ case ARRAY_TYPE:
+ {
+ tree telts = array_type_nelts (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));
+ if (n == 0)
+ return 0;
+ else if (max / n > m)
+ return n * m;
+ }
+ return -1;
+ }
+
+ case RECORD_TYPE:
+ {
+ HOST_WIDE_INT n = 0, t;
+ tree f;
+
+ for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
+ if (TREE_CODE (f) == FIELD_DECL)
+ {
+ t = count_type_elements (TREE_TYPE (f));
+ if (t < 0)
+ return -1;
+ n += t;
+ }
+
+ return n;
+ }
+
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ {
+ /* Ho hum. How in the world do we guess here? Clearly it isn't
+ right to count the fields. Guess based on the number of words. */
+ HOST_WIDE_INT n = int_size_in_bytes (type);
+ if (n < 0)
+ return -1;
+ return n / UNITS_PER_WORD;
+ }
+
+ case COMPLEX_TYPE:
+ return 2;
+
+ case VECTOR_TYPE:
+ /* ??? This is broke. We should encode the vector width in the tree. */
+ return GET_MODE_NUNITS (TYPE_MODE (type));
+
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ case POINTER_TYPE:
+ case OFFSET_TYPE:
+ case REFERENCE_TYPE:
return 1;
+ case VOID_TYPE:
+ case METHOD_TYPE:
+ case FILE_TYPE:
+ case SET_TYPE:
+ case FUNCTION_TYPE:
+ case LANG_TYPE:
default:
- return 0;
+ abort ();
}
}
mostly_zeros_p (tree exp)
{
if (TREE_CODE (exp) == CONSTRUCTOR)
+
{
- int elts = 0, zeros = 0;
- tree elt = CONSTRUCTOR_ELTS (exp);
+ HOST_WIDE_INT nz_elts, nc_elts, elts;
+
+ /* If there are no ranges of true bits, it is all zero. */
if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
- {
- /* If there are no ranges of true bits, it is all zero. */
- return elt == NULL_TREE;
- }
- for (; elt; elt = TREE_CHAIN (elt))
- {
- /* We do not handle the case where the index is a RANGE_EXPR,
- so the statistic will be somewhat inaccurate.
- We do make a more accurate count in store_constructor itself,
- so since this function is only used for nested array elements,
- this should be close enough. */
- if (mostly_zeros_p (TREE_VALUE (elt)))
- zeros++;
- elts++;
- }
+ return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
+
+ categorize_ctor_elements (exp, &nz_elts, &nc_elts);
+ elts = count_type_elements (TREE_TYPE (exp));
- return 4 * zeros >= 3 * elts;
+ return nz_elts < elts / 4;
}
- return is_zeros_p (exp);
+ return initializer_zerop (exp);
}
\f
/* Helper function for store_constructor.
tree exp, tree type, int cleared, int alias_set)
{
if (TREE_CODE (exp) == CONSTRUCTOR
+ /* We can only call store_constructor recursively if the size and
+ bit position are on a byte boundary. */
&& bitpos % BITS_PER_UNIT == 0
+ && (bitsize > 0 && bitsize % BITS_PER_UNIT == 0)
/* If we have a nonzero bitpos for a register target, then we just
let store_field do the bitfield handling. This is unlikely to
generate unnecessary clear instructions anyways. */
- && (bitpos == 0 || GET_CODE (target) == MEM))
+ && (bitpos == 0 || MEM_P (target)))
{
- if (GET_CODE (target) == MEM)
+ if (MEM_P (target))
target
= adjust_address (target,
GET_MODE (target) == BLKmode
/* Update the alias set, if required. */
- if (GET_CODE (target) == MEM && ! MEM_KEEP_ALIAS_SET_P (target)
+ if (MEM_P (target) && ! MEM_KEEP_ALIAS_SET_P (target)
&& MEM_ALIAS_SET (target) != 0)
{
target = copy_rtx (target);
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 (GET_CODE (target) == REG && TREE_STATIC (exp)
+ else if (REG_P (target) && TREE_STATIC (exp)
&& GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
{
emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
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 (((list_length (CONSTRUCTOR_ELTS (exp)) != fields_length (type))
- || mostly_zeros_p (exp))
- && (GET_CODE (target) != REG
+ else if (size > 0
+ && ((list_length (CONSTRUCTOR_ELTS (exp)) != fields_length (type))
+ || mostly_zeros_p (exp))
+ && (!REG_P (target)
|| ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target))
== size)))
{
if (field == 0)
continue;
- if (cleared && is_zeros_p (value))
+ if (cleared && initializer_zerop (value))
continue;
if (host_integerp (DECL_SIZE (field), 1))
{
rtx offset_rtx;
- if (CONTAINS_PLACEHOLDER_P (offset))
- offset = build (WITH_RECORD_EXPR, sizetype,
- offset, make_tree (TREE_TYPE (exp), target));
+ offset
+ = SUBSTITUTE_PLACEHOLDER_IN_EXPR (offset,
+ make_tree (TREE_TYPE (exp),
+ target));
offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
- if (GET_CODE (to_rtx) != MEM)
+ if (!MEM_P (to_rtx))
abort ();
#ifdef POINTERS_EXTEND_UNSIGNED
if (TREE_READONLY (field))
{
- if (GET_CODE (to_rtx) == MEM)
+ if (MEM_P (to_rtx))
to_rtx = copy_rtx (to_rtx);
RTX_UNCHANGING_P (to_rtx) = 1;
start of a word, try to widen it to a full word.
This special case allows us to output C++ member function
initializations in a form that the optimizers can understand. */
- if (GET_CODE (target) == REG
+ if (REG_P (target)
&& bitsize < BITS_PER_WORD
&& bitpos % BITS_PER_WORD == 0
&& GET_MODE_CLASS (mode) == MODE_INT
if (TYPE_PRECISION (type) < BITS_PER_WORD)
{
- type = (*lang_hooks.types.type_for_size)
- (BITS_PER_WORD, TREE_UNSIGNED (type));
+ type = lang_hooks.types.type_for_size
+ (BITS_PER_WORD, TYPE_UNSIGNED (type));
value = convert (type, value);
}
}
#endif
- if (GET_CODE (to_rtx) == MEM && !MEM_KEEP_ALIAS_SET_P (to_rtx)
+ if (MEM_P (to_rtx) && !MEM_KEEP_ALIAS_SET_P (to_rtx)
&& DECL_NONADDRESSABLE_P (field))
{
to_rtx = copy_rtx (to_rtx);
tree elt;
int i;
int need_to_clear;
- tree domain = TYPE_DOMAIN (type);
+ tree domain;
tree elttype = TREE_TYPE (type);
int const_bounds_p;
HOST_WIDE_INT minelt = 0;
int elt_size = 0;
unsigned n_elts = 0;
- /* Vectors are like arrays, but the domain is stored via an array
- type indirectly. */
- if (TREE_CODE (type) == VECTOR_TYPE)
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ domain = TYPE_DOMAIN (type);
+ else
+ /* Vectors do not have domains; look up the domain of
+ the array embedded in the debug representation type.
+ FIXME Would probably be more efficient to treat vectors
+ separately from arrays. */
{
- /* Note that although TYPE_DEBUG_REPRESENTATION_TYPE uses
- the same field as TYPE_DOMAIN, we are not guaranteed that
- it always will. */
domain = TYPE_DEBUG_REPRESENTATION_TYPE (type);
domain = TYPE_DOMAIN (TREE_TYPE (TYPE_FIELDS (domain)));
if (REG_P (target) && VECTOR_MODE_P (GET_MODE (target)))
/* If the constructor has fewer elements than the array,
clear the whole array first. Similarly if this is
static constructor of a non-BLKmode object. */
- if (cleared || (GET_CODE (target) == REG && TREE_STATIC (exp)))
+ if (cleared || (REG_P (target) && TREE_STATIC (exp)))
need_to_clear = 1;
else
{
tree index = TREE_PURPOSE (elt);
rtx xtarget = target;
- if (cleared && is_zeros_p (value))
+ if (cleared && initializer_zerop (value))
continue;
- unsignedp = TREE_UNSIGNED (elttype);
+ unsignedp = TYPE_UNSIGNED (elttype);
mode = TYPE_MODE (elttype);
if (mode == BLKmode)
bitsize = (host_integerp (TYPE_SIZE (elttype), 1)
{
tree lo_index = TREE_OPERAND (index, 0);
tree hi_index = TREE_OPERAND (index, 1);
- rtx index_r, pos_rtx, loop_end;
- struct nesting *loop;
+ rtx index_r, pos_rtx;
HOST_WIDE_INT lo, hi, count;
tree position;
&& (lo = tree_low_cst (lo_index, 0),
hi = tree_low_cst (hi_index, 0),
count = hi - lo + 1,
- (GET_CODE (target) != MEM
+ (!MEM_P (target)
|| count <= 2
|| (host_integerp (TYPE_SIZE (elttype), 1)
&& (tree_low_cst (TYPE_SIZE (elttype), 1) * count
{
bitpos = lo * tree_low_cst (TYPE_SIZE (elttype), 0);
- if (GET_CODE (target) == MEM
+ if (MEM_P (target)
&& !MEM_KEEP_ALIAS_SET_P (target)
&& TREE_CODE (type) == ARRAY_TYPE
&& TYPE_NONALIASED_COMPONENT (type))
}
else
{
- expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
- loop_end = gen_label_rtx ();
+ rtx loop_start = gen_label_rtx ();
+ rtx loop_end = gen_label_rtx ();
+ tree exit_cond;
- unsignedp = TREE_UNSIGNED (domain);
+ expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
+ unsignedp = TYPE_UNSIGNED (domain);
index = build_decl (VAR_DECL, NULL_TREE, domain);
= 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)
- {
- /* Make sure value gets expanded once before the
- loop. */
- expand_expr (value, const0_rtx, VOIDmode, 0);
- emit_queue ();
- }
store_expr (lo_index, index_r, 0);
- loop = expand_start_loop (0);
+
+ /* Build the head of the loop. */
+ do_pending_stack_adjust ();
+ emit_queue ();
+ emit_label (loop_start);
/* Assign value to element index. */
position
else
store_expr (value, xtarget, 0);
- expand_exit_loop_if_false (loop,
- build (LT_EXPR, integer_type_node,
- index, hi_index));
+ /* Generate a conditional jump to exit the loop. */
+ exit_cond = build (LT_EXPR, integer_type_node,
+ index, hi_index);
+ jumpif (exit_cond, loop_end);
+ /* Update the loop counter, and jump to the head of
+ the loop. */
expand_increment (build (PREINCREMENT_EXPR,
TREE_TYPE (index),
index, integer_one_node), 0, 0);
- expand_end_loop ();
+ emit_jump (loop_start);
+
+ /* Build the end of the loop. */
emit_label (loop_end);
}
}
else
bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
- if (GET_CODE (target) == MEM && !MEM_KEEP_ALIAS_SET_P (target)
+ if (MEM_P (target) && !MEM_KEEP_ALIAS_SET_P (target)
&& TREE_CODE (type) == ARRAY_TYPE
&& TYPE_NONALIASED_COMPONENT (type))
{
and then "or" in whatever non-constant ranges we need in addition.
If a large set is all zero or all ones, it is
- probably better to set it using memset (if available) or bzero.
+ probably better to set it using memset.
Also, if a large set has just a single range, it may also be
better to first clear all the first clear the set (using
- bzero/memset), and set the bits we want. */
+ memset), and set the bits we want. */
/* Check for all zeros. */
if (elt == NULL_TREE && size > 0)
{
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
XEXP if the set is multi-word, but not if
it's single-word. */
- if (GET_CODE (target) == MEM)
+ if (MEM_P (target))
to_rtx = adjust_address (target, mode, offset);
else if (offset == 0)
to_rtx = target;
{
targetx
= assign_temp
- ((build_qualified_type ((*lang_hooks.types.type_for_mode)
+ ((build_qualified_type (lang_hooks.types.type_for_mode
(GET_MODE (target), 0),
TYPE_QUAL_CONST)),
0, 1, 1);
emit_move_insn (targetx, target);
}
- else if (GET_CODE (target) == MEM)
+ else if (MEM_P (target))
targetx = target;
else
abort ();
/* Optimization: If startbit and endbit are constants divisible
by BITS_PER_UNIT, call memset instead. */
- if (TARGET_MEM_FUNCTIONS
- && TREE_CODE (startbit) == INTEGER_CST
+ if (TREE_CODE (startbit) == INTEGER_CST
&& TREE_CODE (endbit) == INTEGER_CST
&& (startb = TREE_INT_CST_LOW (startbit)) % BITS_PER_UNIT == 0
&& (endb = TREE_INT_CST_LOW (endbit) + 1) % BITS_PER_UNIT == 0)
twice, once with emit_move_insn and once via store_field. */
if (mode == BLKmode
- && (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
+ && (REG_P (target) || GET_CODE (target) == SUBREG))
{
rtx object = assign_temp (type, 0, 1, 1);
rtx blk_object = adjust_address (object, BLKmode, 0);
if (bitpos != 0)
abort ();
- return store_expr (exp, target, 0);
+ return store_expr (exp, target, value_mode != VOIDmode);
}
/* If the structure is in a register or if the component
|| (mode != BLKmode && ! direct_store[(int) mode]
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
- || GET_CODE (target) == REG
+ || REG_P (target)
|| GET_CODE (target) == SUBREG
/* If the field isn't aligned enough to store as an ordinary memref,
store it as a bit field. */
boundary. If so, we simply do a block copy. */
if (GET_MODE (target) == BLKmode && GET_MODE (temp) == BLKmode)
{
- if (GET_CODE (target) != MEM || GET_CODE (temp) != MEM
+ if (!MEM_P (target) || !MEM_P (temp)
|| bitpos % BITS_PER_UNIT != 0)
abort ();
/* The caller wants an rtx for the value.
If possible, avoid refetching from the bitfield itself. */
if (width_mask != 0
- && ! (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)))
+ && ! (MEM_P (target) && MEM_VOLATILE_P (target)))
{
tree count;
enum machine_mode tmode;
/* If a value is wanted, it must be the lhs;
so make the address stable for multiple use. */
- if (value_mode != VOIDmode && GET_CODE (addr) != REG
+ if (value_mode != VOIDmode && !REG_P (addr)
&& ! CONSTANT_ADDRESS_P (addr)
/* A frame-pointer reference is already stable. */
&& ! (GET_CODE (addr) == PLUS
enum machine_mode mode = VOIDmode;
tree offset = size_zero_node;
tree bit_offset = bitsize_zero_node;
- tree placeholder_ptr = 0;
tree tem;
/* First get the mode, signedness, and size. We do this from just the
if (! DECL_BIT_FIELD (TREE_OPERAND (exp, 1)))
mode = DECL_MODE (TREE_OPERAND (exp, 1));
- *punsignedp = TREE_UNSIGNED (TREE_OPERAND (exp, 1));
+ *punsignedp = DECL_UNSIGNED (TREE_OPERAND (exp, 1));
}
else if (TREE_CODE (exp) == BIT_FIELD_REF)
{
size_tree = TREE_OPERAND (exp, 1);
- *punsignedp = TREE_UNSIGNED (exp);
+ *punsignedp = BIT_FIELD_REF_UNSIGNED (exp);
}
else
{
mode = TYPE_MODE (TREE_TYPE (exp));
- *punsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
+ *punsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
if (mode == BLKmode)
size_tree = TYPE_SIZE (TREE_TYPE (exp));
else if (TREE_CODE (exp) == COMPONENT_REF)
{
tree field = TREE_OPERAND (exp, 1);
- tree this_offset = DECL_FIELD_OFFSET (field);
+ tree this_offset = component_ref_field_offset (exp);
/* If this field hasn't been filled in yet, don't go
past it. This should only happen when folding expressions
made during type construction. */
if (this_offset == 0)
break;
- else if (CONTAINS_PLACEHOLDER_P (this_offset))
- this_offset = build (WITH_RECORD_EXPR, sizetype, this_offset, exp);
offset = size_binop (PLUS_EXPR, offset, this_offset);
bit_offset = size_binop (PLUS_EXPR, bit_offset,
|| TREE_CODE (exp) == ARRAY_RANGE_REF)
{
tree index = TREE_OPERAND (exp, 1);
- tree array = TREE_OPERAND (exp, 0);
- tree domain = TYPE_DOMAIN (TREE_TYPE (array));
- tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);
- tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
+ tree low_bound = array_ref_low_bound (exp);
+ tree unit_size = array_ref_element_size (exp);
/* We assume all arrays have sizes that are a multiple of a byte.
First subtract the lower bound, if any, in the type of the
index, then convert to sizetype and multiply by the size of the
array element. */
- if (low_bound != 0 && ! integer_zerop (low_bound))
+ if (! integer_zerop (low_bound))
index = fold (build (MINUS_EXPR, TREE_TYPE (index),
index, low_bound));
- /* If the index has a self-referential type, pass it to a
- WITH_RECORD_EXPR; if the component size is, pass our
- component to one. */
- if (CONTAINS_PLACEHOLDER_P (index))
- index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, exp);
- if (CONTAINS_PLACEHOLDER_P (unit_size))
- unit_size = build (WITH_RECORD_EXPR, sizetype, unit_size, array);
-
offset = size_binop (PLUS_EXPR, offset,
size_binop (MULT_EXPR,
convert (sizetype, index),
unit_size));
}
- else if (TREE_CODE (exp) == PLACEHOLDER_EXPR)
- {
- tree new = find_placeholder (exp, &placeholder_ptr);
-
- /* If we couldn't find the replacement, return the PLACEHOLDER_EXPR.
- We might have been called from tree optimization where we
- haven't set up an object yet. */
- if (new == 0)
- break;
- else
- exp = new;
-
- continue;
- }
-
/* 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. */
return exp;
}
+/* Return a tree of sizetype representing the size, in bytes, of the element
+ of EXP, an ARRAY_REF. */
+
+tree
+array_ref_element_size (tree exp)
+{
+ tree aligned_size = TREE_OPERAND (exp, 3);
+ tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+ /* If a size was specified in the ARRAY_REF, it's the size measured
+ in alignment units of the element type. So multiply by that value. */
+ if (aligned_size)
+ return size_binop (MULT_EXPR, aligned_size,
+ size_int (TYPE_ALIGN (elmt_type) / BITS_PER_UNIT));
+
+ /* Otherwise, take the size from that of the element type. Substitute
+ any PLACEHOLDER_EXPR that we have. */
+ else
+ return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_SIZE_UNIT (elmt_type), exp);
+}
+
+/* Return a tree representing the lower bound of the array mentioned in
+ EXP, an ARRAY_REF. */
+
+tree
+array_ref_low_bound (tree exp)
+{
+ tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+ /* If a lower bound is specified in EXP, use it. */
+ if (TREE_OPERAND (exp, 2))
+ return TREE_OPERAND (exp, 2);
+
+ /* Otherwise, if there is a domain type and it has a lower bound, use it,
+ substituting for a PLACEHOLDER_EXPR as needed. */
+ if (domain_type && TYPE_MIN_VALUE (domain_type))
+ return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MIN_VALUE (domain_type), exp);
+
+ /* Otherwise, return a zero of the appropriate type. */
+ return fold_convert (TREE_TYPE (TREE_OPERAND (exp, 1)), integer_zero_node);
+}
+
+/* Return a tree representing the offset, in bytes, of the field referenced
+ by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */
+
+tree
+component_ref_field_offset (tree exp)
+{
+ tree aligned_offset = TREE_OPERAND (exp, 2);
+ tree field = TREE_OPERAND (exp, 1);
+
+ /* If an offset was specified in the COMPONENT_REF, it's the offset measured
+ in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT. So multiply by that
+ value. */
+ if (aligned_offset)
+ return size_binop (MULT_EXPR, aligned_offset,
+ size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT));
+
+ /* Otherwise, take the offset from that of the field. Substitute
+ any PLACEHOLDER_EXPR that we have. */
+ else
+ return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
+}
+
/* Return 1 if T is an expression that get_inner_reference handles. */
int
/* Check for subreg applied to an expression produced by loop optimizer. */
if (code == SUBREG
- && GET_CODE (SUBREG_REG (value)) != REG
- && GET_CODE (SUBREG_REG (value)) != MEM)
+ && !REG_P (SUBREG_REG (value))
+ && !MEM_P (SUBREG_REG (value)))
{
value = simplify_gen_subreg (GET_MODE (value),
force_reg (GET_MODE (SUBREG_REG (value)),
if (ARITHMETIC_P (value))
{
op2 = XEXP (value, 1);
- if (!CONSTANT_P (op2) && !(GET_CODE (op2) == REG && op2 != subtarget))
+ if (!CONSTANT_P (op2) && !(REG_P (op2) && op2 != subtarget))
subtarget = 0;
if (code == MINUS && GET_CODE (op2) == CONST_INT)
{
creating another one around this addition. */
if (code == PLUS && GET_CODE (op2) == CONST_INT
&& GET_CODE (XEXP (value, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (value, 0), 0)) == REG
+ && REG_P (XEXP (XEXP (value, 0), 0))
&& REGNO (XEXP (XEXP (value, 0), 0)) >= FIRST_VIRTUAL_REGISTER
&& REGNO (XEXP (XEXP (value, 0), 0)) <= LAST_VIRTUAL_REGISTER)
{
#ifdef INSN_SCHEDULING
/* On machines that have insn scheduling, we want all memory reference to be
explicit, so we need to deal with such paradoxical SUBREGs. */
- if (GET_CODE (value) == SUBREG && GET_CODE (SUBREG_REG (value)) == MEM
+ if (GET_CODE (value) == SUBREG && MEM_P (SUBREG_REG (value))
&& (GET_MODE_SIZE (GET_MODE (value))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (value)))))
value
{
rtx exp_rtl = 0;
int i, nops;
- static tree save_expr_list;
if (x == 0
/* If EXP has varying size, we MUST use a target since we currently
!= INTEGER_CST)
&& GET_MODE (x) == BLKmode)
/* If X is in the outgoing argument area, it is always safe. */
- || (GET_CODE (x) == MEM
+ || (MEM_P (x)
&& (XEXP (x, 0) == virtual_outgoing_args_rtx
|| (GET_CODE (XEXP (x, 0)) == PLUS
&& XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx))))
if (GET_CODE (x) == SUBREG)
{
x = SUBREG_REG (x);
- if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
return 0;
}
- /* A SAVE_EXPR might appear many times in the expression passed to the
- top-level safe_from_p call, and if it has a complex subexpression,
- examining it multiple times could result in a combinatorial explosion.
- E.g. on an Alpha running at least 200MHz, a Fortran testcase compiled
- with optimization took about 28 minutes to compile -- even though it was
- only a few lines long. So we mark each SAVE_EXPR we see with TREE_PRIVATE
- and turn that off when we are done. We keep a list of the SAVE_EXPRs
- we have processed. Note that the only test of top_p was above. */
-
- if (top_p)
- {
- int rtn;
- tree t;
-
- save_expr_list = 0;
-
- rtn = safe_from_p (x, exp, 0);
-
- for (t = save_expr_list; t != 0; t = TREE_CHAIN (t))
- TREE_PRIVATE (TREE_PURPOSE (t)) = 0;
-
- return rtn;
- }
-
/* Now look at our tree code and possibly recurse. */
switch (TREE_CODE_CLASS (TREE_CODE (exp)))
{
else
return 0;
+ case 's':
+ /* The only case we look at here is the DECL_INITIAL inside a
+ DECL_EXPR. */
+ return (TREE_CODE (exp) != DECL_EXPR
+ || TREE_CODE (DECL_EXPR_DECL (exp)) != VAR_DECL
+ || !DECL_INITIAL (DECL_EXPR_DECL (exp))
+ || safe_from_p (x, DECL_INITIAL (DECL_EXPR_DECL (exp)), 0));
+
case '2':
case '<':
if (!safe_from_p (x, TREE_OPERAND (exp, 1), 0))
if (DECL_P (exp))
{
if (!DECL_RTL_SET_P (exp)
- || GET_CODE (DECL_RTL (exp)) != MEM)
+ || !MEM_P (DECL_RTL (exp)))
return 0;
else
exp_rtl = XEXP (DECL_RTL (exp), 0);
break;
case INDIRECT_REF:
- if (GET_CODE (x) == MEM
+ if (MEM_P (x)
&& alias_sets_conflict_p (MEM_ALIAS_SET (x),
get_alias_set (exp)))
return 0;
case CALL_EXPR:
/* Assume that the call will clobber all hard registers and
all of memory. */
- if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
- || GET_CODE (x) == MEM)
+ if ((REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ || MEM_P (x))
return 0;
break;
- case RTL_EXPR:
- /* If a sequence exists, we would have to scan every instruction
- in the sequence to see if it was safe. This is probably not
- worthwhile. */
- if (RTL_EXPR_SEQUENCE (exp))
- return 0;
-
- exp_rtl = RTL_EXPR_RTL (exp);
- break;
-
case WITH_CLEANUP_EXPR:
exp_rtl = WITH_CLEANUP_EXPR_RTL (exp);
break;
case CLEANUP_POINT_EXPR:
- return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
-
case SAVE_EXPR:
- exp_rtl = SAVE_EXPR_RTL (exp);
- if (exp_rtl)
- break;
-
- /* If we've already scanned this, don't do it again. Otherwise,
- show we've scanned it and record for clearing the flag if we're
- going on. */
- if (TREE_PRIVATE (exp))
- return 1;
-
- TREE_PRIVATE (exp) = 1;
- if (! safe_from_p (x, TREE_OPERAND (exp, 0), 0))
- {
- TREE_PRIVATE (exp) = 0;
- return 0;
- }
-
- save_expr_list = tree_cons (exp, NULL_TREE, save_expr_list);
- return 1;
+ return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
case BIND_EXPR:
/* The only operand we look at is operand 1. The rest aren't
special handling. */
if ((unsigned int) TREE_CODE (exp)
>= (unsigned int) LAST_AND_UNUSED_TREE_CODE
- && !(*lang_hooks.safe_from_p) (x, exp))
+ && !lang_hooks.safe_from_p (x, exp))
return 0;
}
if (GET_CODE (exp_rtl) == SUBREG)
{
exp_rtl = SUBREG_REG (exp_rtl);
- if (GET_CODE (exp_rtl) == REG
+ if (REG_P (exp_rtl)
&& REGNO (exp_rtl) < FIRST_PSEUDO_REGISTER)
return 0;
}
/* If the rtl is X, then it is not safe. Otherwise, it is unless both
are memory and they conflict. */
return ! (rtx_equal_p (x, exp_rtl)
- || (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
+ || (MEM_P (x) && MEM_P (exp_rtl)
&& true_dependence (exp_rtl, VOIDmode, x,
rtx_addr_varies_p)));
}
break;
case NON_LVALUE_EXPR: case NOP_EXPR: case CONVERT_EXPR:
- case SAVE_EXPR: case WITH_RECORD_EXPR:
+ case SAVE_EXPR:
return highest_pow2_factor (TREE_OPERAND (exp, 0));
case COMPOUND_EXPR:
return 1;
}
-/* Similar, except that it is known that the expression must be a multiple
- of the alignment of TYPE. */
+/* Similar, except that the alignment requirements of TARGET are
+ taken into account. Assume it is at least as aligned as its
+ type, unless it is a COMPONENT_REF in which case the layout of
+ the structure gives the alignment. */
static unsigned HOST_WIDE_INT
-highest_pow2_factor_for_type (tree type, tree exp)
+highest_pow2_factor_for_target (tree target, tree exp)
{
- unsigned HOST_WIDE_INT type_align, factor;
+ unsigned HOST_WIDE_INT target_align, factor;
factor = highest_pow2_factor (exp);
- type_align = TYPE_ALIGN (type) / BITS_PER_UNIT;
- return MAX (factor, type_align);
+ if (TREE_CODE (target) == COMPONENT_REF)
+ target_align = DECL_ALIGN (TREE_OPERAND (target, 1)) / BITS_PER_UNIT;
+ else
+ target_align = TYPE_ALIGN (TREE_TYPE (target)) / BITS_PER_UNIT;
+ return MAX (factor, target_align);
}
\f
-/* Return an object on the placeholder list that matches EXP, a
- PLACEHOLDER_EXPR. An object "matches" if it is of the type of the
- PLACEHOLDER_EXPR or a pointer type to it. For further information, see
- tree.def. If no such object is found, return 0. If PLIST is nonzero, it
- is a location which initially points to a starting location in the
- placeholder list (zero means start of the list) and where a pointer into
- the placeholder list at which the object is found is placed. */
+/* Expands variable VAR. */
-tree
-find_placeholder (tree exp, tree *plist)
+void
+expand_var (tree var)
{
- tree type = TREE_TYPE (exp);
- tree placeholder_expr;
+ if (DECL_EXTERNAL (var))
+ return;
- for (placeholder_expr
- = plist && *plist ? TREE_CHAIN (*plist) : placeholder_list;
- placeholder_expr != 0;
- placeholder_expr = TREE_CHAIN (placeholder_expr))
- {
- tree need_type = TYPE_MAIN_VARIANT (type);
- tree elt;
+ if (TREE_STATIC (var))
+ /* If this is an inlined copy of a static local variable,
+ look up the original decl. */
+ var = DECL_ORIGIN (var);
- /* Find the outermost reference that is of the type we want. If none,
- see if any object has a type that is a pointer to the type we
- want. */
- for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
- elt = ((TREE_CODE (elt) == COMPOUND_EXPR
- || TREE_CODE (elt) == COND_EXPR)
- ? TREE_OPERAND (elt, 1)
- : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
- ? TREE_OPERAND (elt, 0) : 0))
- if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
- {
- if (plist)
- *plist = placeholder_expr;
- return elt;
- }
+ if (TREE_STATIC (var)
+ ? !TREE_ASM_WRITTEN (var)
+ : !DECL_RTL_SET_P (var))
+ {
+ if (TREE_CODE (var) == VAR_DECL && DECL_DEFER_OUTPUT (var))
+ {
+ /* Prepare a mem & address for the decl. */
+ rtx x;
+
+ if (TREE_STATIC (var))
+ abort ();
- for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
- elt
- = ((TREE_CODE (elt) == COMPOUND_EXPR
- || TREE_CODE (elt) == COND_EXPR)
- ? TREE_OPERAND (elt, 1)
- : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
- ? TREE_OPERAND (elt, 0) : 0))
- if (POINTER_TYPE_P (TREE_TYPE (elt))
- && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
- == need_type))
- {
- if (plist)
- *plist = placeholder_expr;
- return build1 (INDIRECT_REF, need_type, elt);
- }
+ x = gen_rtx_MEM (DECL_MODE (var),
+ gen_reg_rtx (Pmode));
+
+ set_mem_attributes (x, var, 1);
+ SET_DECL_RTL (var, x);
+ }
+ else if (lang_hooks.expand_decl (var))
+ /* OK. */;
+ else if (TREE_CODE (var) == VAR_DECL && !TREE_STATIC (var))
+ expand_decl (var);
+ else if (TREE_CODE (var) == VAR_DECL && TREE_STATIC (var))
+ rest_of_decl_compilation (var, NULL, 0, 0);
+ else if (TREE_CODE (var) == TYPE_DECL
+ || TREE_CODE (var) == CONST_DECL
+ || TREE_CODE (var) == FUNCTION_DECL
+ || TREE_CODE (var) == LABEL_DECL)
+ /* No expansion needed. */;
+ else
+ abort ();
}
+}
- return 0;
+/* Expands declarations of variables in list VARS. */
+
+static void
+expand_vars (tree vars)
+{
+ for (; vars; vars = TREE_CHAIN (vars))
+ {
+ tree var = vars;
+
+ if (DECL_EXTERNAL (var))
+ continue;
+
+ expand_var (var);
+ expand_decl_init (var);
+ }
}
/* Subroutine of expand_expr. Expand the two operands of a binary
COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on
recursively. */
+static rtx expand_expr_real_1 (tree, rtx, enum machine_mode,
+ enum expand_modifier, rtx *);
+
rtx
expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
enum expand_modifier modifier, rtx *alt_rtl)
{
+ int rn = -1;
+ rtx ret, last = NULL;
+
+ /* Handle ERROR_MARK before anybody tries to access its type. */
+ if (TREE_CODE (exp) == ERROR_MARK
+ || TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK)
+ {
+ ret = CONST0_RTX (tmode);
+ return ret ? ret : const0_rtx;
+ }
+
+ if (flag_non_call_exceptions)
+ {
+ rn = lookup_stmt_eh_region (exp);
+ /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't throw. */
+ if (rn >= 0)
+ last = get_last_insn ();
+ }
+
+ /* If this is an expression of some kind and it has an associated line
+ number, then emit the line number before expanding the expression.
+
+ We need to save and restore the file and line information so that
+ errors discovered during expansion are emitted with the right
+ 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))
+ {
+ location_t saved_location = input_location;
+ input_location = EXPR_LOCATION (exp);
+ emit_line_note (input_location);
+
+ /* Record where the insns produced belong. */
+ record_block_change (TREE_BLOCK (exp));
+
+ ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
+
+ input_location = saved_location;
+ }
+ else
+ {
+ ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
+ }
+
+ /* If using non-call exceptions, mark all insns that may trap.
+ expand_call() will mark CALL_INSNs before we get to this code,
+ but it doesn't handle libcalls, and these may trap. */
+ if (rn >= 0)
+ {
+ rtx insn;
+ for (insn = next_real_insn (last); insn;
+ insn = next_real_insn (insn))
+ {
+ if (! find_reg_note (insn, REG_EH_REGION, NULL_RTX)
+ /* If we want exceptions for non-call insns, any
+ may_trap_p instruction may throw. */
+ && GET_CODE (PATTERN (insn)) != CLOBBER
+ && GET_CODE (PATTERN (insn)) != USE
+ && (GET_CODE (insn) == CALL_INSN || may_trap_p (PATTERN (insn))))
+ {
+ REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (rn),
+ REG_NOTES (insn));
+ }
+ }
+ }
+
+ return ret;
+}
+
+static rtx
+expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
+ enum expand_modifier modifier, rtx *alt_rtl)
+{
rtx op0, op1, temp;
tree type = TREE_TYPE (exp);
- int unsignedp = TREE_UNSIGNED (type);
+ int unsignedp;
enum machine_mode mode;
enum tree_code code = TREE_CODE (exp);
optab this_optab;
int ignore;
tree context;
- /* Handle ERROR_MARK before anybody tries to access its type. */
- if (TREE_CODE (exp) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
- {
- op0 = CONST0_RTX (tmode);
- if (op0 != 0)
- return op0;
- return const0_rtx;
- }
-
mode = TYPE_MODE (type);
+ unsignedp = TYPE_UNSIGNED (type);
+
/* Use subtarget as the target for operand 0 of a binary operation. */
subtarget = get_subtarget (target);
original_target = target;
ignore = (target == const0_rtx
|| ((code == NON_LVALUE_EXPR || code == NOP_EXPR
- || code == CONVERT_EXPR || code == REFERENCE_EXPR
- || code == COND_EXPR || code == VIEW_CONVERT_EXPR)
+ || code == CONVERT_EXPR || code == COND_EXPR
+ || code == VIEW_CONVERT_EXPR)
&& TREE_CODE (type) == VOID_TYPE));
/* If we are going to ignore this result, we need only do something
&& modifier != EXPAND_CONST_ADDRESS)
{
temp = expand_expr (exp, NULL_RTX, VOIDmode, modifier);
- if (GET_CODE (temp) == MEM)
+ if (MEM_P (temp))
temp = copy_to_reg (temp);
return const0_rtx;
}
Another is a CALL_EXPR which must return in memory. */
if (! cse_not_expected && mode != BLKmode && target
- && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER)
+ && (!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;
case LABEL_DECL:
{
tree function = decl_function_context (exp);
- /* Labels in containing functions, or labels used from initializers,
- must be forced. */
- if (modifier == EXPAND_INITIALIZER
- || (function != current_function_decl
- && function != inline_function_decl
- && function != 0))
- temp = force_label_rtx (exp);
- else
- temp = label_rtx (exp);
- temp = gen_rtx_MEM (FUNCTION_MODE, gen_rtx_LABEL_REF (Pmode, temp));
+ temp = label_rtx (exp);
+ temp = gen_rtx_LABEL_REF (Pmode, temp);
+
if (function != current_function_decl
- && function != inline_function_decl && function != 0)
- LABEL_REF_NONLOCAL_P (XEXP (temp, 0)) = 1;
+ && function != 0)
+ LABEL_REF_NONLOCAL_P (temp) = 1;
+
+ temp = gen_rtx_MEM (FUNCTION_MODE, temp);
return temp;
}
/* Handle variables inherited from containing functions. */
context = decl_function_context (exp);
- /* We treat inline_function_decl as an alias for the current function
- because that is the inline function whose vars, types, etc.
- are being merged into the current function.
- See expand_inline_function. */
-
if (context != 0 && context != current_function_decl
- && context != inline_function_decl
/* If var is static, we don't need a static chain to access it. */
- && ! (GET_CODE (DECL_RTL (exp)) == MEM
+ && ! (MEM_P (DECL_RTL (exp))
&& CONSTANT_P (XEXP (DECL_RTL (exp), 0))))
{
rtx addr;
DECL_NONLOCAL (exp) = 1;
if (DECL_NO_STATIC_CHAIN (current_function_decl))
abort ();
- (*lang_hooks.mark_addressable) (exp);
- if (GET_CODE (DECL_RTL (exp)) != MEM)
+ lang_hooks.mark_addressable (exp);
+ if (!MEM_P (DECL_RTL (exp)))
abort ();
addr = XEXP (DECL_RTL (exp), 0);
- if (GET_CODE (addr) == MEM)
+ if (MEM_P (addr))
addr
= replace_equiv_address (addr,
fix_lexical_addr (XEXP (addr, 0), exp));
from its initializer, while the initializer is still being parsed.
See expand_decl. */
- else if (GET_CODE (DECL_RTL (exp)) == MEM
- && GET_CODE (XEXP (DECL_RTL (exp), 0)) == REG)
+ else if (MEM_P (DECL_RTL (exp))
+ && REG_P (XEXP (DECL_RTL (exp), 0)))
temp = validize_mem (DECL_RTL (exp));
/* If DECL_RTL is memory, we are in the normal case and either
the address is not valid or it is not a register and -fforce-addr
is specified, get the address into a register. */
- else if (GET_CODE (DECL_RTL (exp)) == MEM
+ else if (MEM_P (DECL_RTL (exp))
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_SUM
&& modifier != EXPAND_INITIALIZER
&& (! memory_address_p (DECL_MODE (exp),
XEXP (DECL_RTL (exp), 0))
|| (flag_force_addr
- && GET_CODE (XEXP (DECL_RTL (exp), 0)) != REG)))
+ && !REG_P (XEXP (DECL_RTL (exp), 0)))))
{
if (alt_rtl)
*alt_rtl = DECL_RTL (exp);
if the address is a register. */
if (temp != 0)
{
- if (GET_CODE (temp) == MEM && GET_CODE (XEXP (temp, 0)) == REG)
+ if (MEM_P (temp) && REG_P (XEXP (temp, 0)))
mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
return temp;
must be a promoted value. We return a SUBREG of the wanted mode,
but mark it so that we know that it was already extended. */
- if (GET_CODE (DECL_RTL (exp)) == REG
+ if (REG_P (DECL_RTL (exp))
&& GET_MODE (DECL_RTL (exp)) != DECL_MODE (exp))
{
/* Get the signedness used for this variable. Ensure we get the
copy_rtx (XEXP (temp, 0)));
return temp;
- case EXPR_WITH_FILE_LOCATION:
- {
- rtx to_return;
- struct file_stack fs;
-
- fs.location = input_location;
- fs.next = expr_wfl_stack;
- input_filename = EXPR_WFL_FILENAME (exp);
- input_line = EXPR_WFL_LINENO (exp);
- expr_wfl_stack = &fs;
- if (EXPR_WFL_EMIT_LINE_NOTE (exp))
- emit_line_note (input_location);
- /* Possibly avoid switching back and forth here. */
- to_return = expand_expr (EXPR_WFL_NODE (exp),
- (ignore ? const0_rtx : target),
- tmode, modifier);
- if (expr_wfl_stack != &fs)
- abort ();
- input_location = fs.location;
- expr_wfl_stack = fs.next;
- return to_return;
- }
-
case SAVE_EXPR:
- context = decl_function_context (exp);
-
- /* If this SAVE_EXPR was at global context, assume we are an
- initialization function and move it into our context. */
- if (context == 0)
- SAVE_EXPR_CONTEXT (exp) = current_function_decl;
-
- /* We treat inline_function_decl as an alias for the current function
- because that is the inline function whose vars, types, etc.
- are being merged into the current function.
- See expand_inline_function. */
- if (context == current_function_decl || context == inline_function_decl)
- context = 0;
-
- /* If this is non-local, handle it. */
- if (context)
- {
- /* The following call just exists to abort if the context is
- not of a containing function. */
- find_function_data (context);
-
- temp = SAVE_EXPR_RTL (exp);
- if (temp && GET_CODE (temp) == REG)
- {
- put_var_into_stack (exp, /*rescan=*/true);
- temp = SAVE_EXPR_RTL (exp);
- }
- if (temp == 0 || GET_CODE (temp) != MEM)
- abort ();
- return
- replace_equiv_address (temp,
- fix_lexical_addr (XEXP (temp, 0), exp));
- }
- if (SAVE_EXPR_RTL (exp) == 0)
- {
- if (mode == VOIDmode)
- temp = const0_rtx;
- else
- temp = assign_temp (build_qualified_type (type,
- (TYPE_QUALS (type)
- | TYPE_QUAL_CONST)),
- 3, 0, 0);
-
- SAVE_EXPR_RTL (exp) = temp;
- if (!optimize && GET_CODE (temp) == REG)
- save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, temp,
- save_expr_regs);
-
- /* 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. */
-
- 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);
- }
-
- if (temp == const0_rtx)
- expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
- else
- store_expr (TREE_OPERAND (exp, 0), temp,
- modifier == EXPAND_STACK_PARM ? 2 : 0);
+ {
+ tree val = TREE_OPERAND (exp, 0);
+ rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
- TREE_USED (exp) = 1;
- }
+ if (TREE_CODE (val) != VAR_DECL || !DECL_ARTIFICIAL (val))
+ {
+ /* We can indeed still hit this case, typically via builtin
+ expanders calling save_expr immediately before expanding
+ something. Assume this means that we only have to deal
+ with non-BLKmode values. */
+ if (GET_MODE (ret) == BLKmode)
+ abort ();
- /* If the mode of SAVE_EXPR_RTL does not match that of the expression, it
- must be a promoted value. We return a SUBREG of the wanted mode,
- but mark it so that we know that it was already extended. */
+ val = build_decl (VAR_DECL, NULL, TREE_TYPE (exp));
+ DECL_ARTIFICIAL (val) = 1;
+ TREE_OPERAND (exp, 0) = val;
- if (GET_CODE (SAVE_EXPR_RTL (exp)) == REG
- && GET_MODE (SAVE_EXPR_RTL (exp)) != mode)
- {
- /* Compute the signedness and make the proper SUBREG. */
- promote_mode (type, mode, &unsignedp, 0);
- temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
- SUBREG_PROMOTED_VAR_P (temp) = 1;
- SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
- return temp;
- }
+ if (!CONSTANT_P (ret))
+ ret = copy_to_reg (ret);
+ SET_DECL_RTL (val, ret);
+ }
- return SAVE_EXPR_RTL (exp);
+ return ret;
+ }
case UNSAVE_EXPR:
{
rtx temp;
temp = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
TREE_OPERAND (exp, 0)
- = (*lang_hooks.unsave_expr_now) (TREE_OPERAND (exp, 0));
- return temp;
- }
-
- case PLACEHOLDER_EXPR:
- {
- tree old_list = placeholder_list;
- tree placeholder_expr = 0;
-
- exp = find_placeholder (exp, &placeholder_expr);
- if (exp == 0)
- abort ();
-
- placeholder_list = TREE_CHAIN (placeholder_expr);
- temp = expand_expr (exp, original_target, tmode, modifier);
- placeholder_list = old_list;
+ = lang_hooks.unsave_expr_now (TREE_OPERAND (exp, 0));
return temp;
}
- case WITH_RECORD_EXPR:
- /* Put the object on the placeholder list, expand our first operand,
- and pop the list. */
- placeholder_list = tree_cons (TREE_OPERAND (exp, 1), NULL_TREE,
- placeholder_list);
- target = expand_expr (TREE_OPERAND (exp, 0), original_target, tmode,
- modifier);
- placeholder_list = TREE_CHAIN (placeholder_list);
- return target;
-
case GOTO_EXPR:
if (TREE_CODE (TREE_OPERAND (exp, 0)) == LABEL_DECL)
expand_goto (TREE_OPERAND (exp, 0));
expand_computed_goto (TREE_OPERAND (exp, 0));
return const0_rtx;
+ /* These are lowered during gimplification, so we should never ever
+ see them here. */
+ case LOOP_EXPR:
case EXIT_EXPR:
- expand_exit_loop_if_false (NULL,
- invert_truthvalue (TREE_OPERAND (exp, 0)));
- return const0_rtx;
+ abort ();
case LABELED_BLOCK_EXPR:
if (LABELED_BLOCK_BODY (exp))
- expand_expr_stmt_value (LABELED_BLOCK_BODY (exp), 0, 1);
+ 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)));
expand_goto (LABELED_BLOCK_LABEL (EXIT_BLOCK_LABELED_BLOCK (exp)));
return const0_rtx;
- case LOOP_EXPR:
- push_temp_slots ();
- expand_start_loop (1);
- expand_expr_stmt_value (TREE_OPERAND (exp, 0), 0, 1);
- expand_end_loop ();
- pop_temp_slots ();
-
- return const0_rtx;
-
case BIND_EXPR:
{
- tree vars = TREE_OPERAND (exp, 0);
-
- /* Need to open a binding contour here because
- if there are any cleanups they must be contained here. */
- expand_start_bindings (2);
+ tree block = BIND_EXPR_BLOCK (exp);
+ int mark_ends;
- /* Mark the corresponding BLOCK for output in its proper place. */
- if (TREE_OPERAND (exp, 2) != 0
- && ! TREE_USED (TREE_OPERAND (exp, 2)))
- (*lang_hooks.decls.insert_block) (TREE_OPERAND (exp, 2));
+ /* If we're in functions-as-trees mode, this BIND_EXPR represents
+ the block, so we need to emit NOTE_INSN_BLOCK_* notes. */
+ mark_ends = (block != NULL_TREE);
+ expand_start_bindings_and_block (mark_ends ? 0 : 2, block);
/* If VARS have not yet been expanded, expand them now. */
- while (vars)
- {
- if (!DECL_RTL_SET_P (vars))
- expand_decl (vars);
- expand_decl_init (vars);
- vars = TREE_CHAIN (vars);
- }
+ expand_vars (BIND_EXPR_VARS (exp));
- temp = expand_expr (TREE_OPERAND (exp, 1), target, tmode, modifier);
+ /* TARGET was clobbered early in this function. The correct
+ indicator or whether or not we need the value of this
+ expression is the IGNORE variable. */
+ temp = expand_expr (BIND_EXPR_BODY (exp),
+ ignore ? const0_rtx : target,
+ tmode, modifier);
- expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0);
+ expand_end_bindings (BIND_EXPR_VARS (exp), mark_ends, 0);
return temp;
}
- case RTL_EXPR:
- if (RTL_EXPR_SEQUENCE (exp))
- {
- if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
- abort ();
- emit_insn (RTL_EXPR_SEQUENCE (exp));
- RTL_EXPR_SEQUENCE (exp) = const0_rtx;
- }
- preserve_rtl_expr_result (RTL_EXPR_RTL (exp));
- free_temps_for_rtl_expr (exp);
- if (alt_rtl)
- *alt_rtl = RTL_EXPR_ALT_RTL (exp);
- return RTL_EXPR_RTL (exp);
-
case CONSTRUCTOR:
/* If we don't need the result, just ensure we evaluate any
subexpressions. */
&& (! MOVE_BY_PIECES_P
(tree_low_cst (TYPE_SIZE_UNIT (type), 1),
TYPE_ALIGN (type)))
- && ((TREE_CODE (type) == VECTOR_TYPE
- && !is_zeros_p (exp))
- || ! mostly_zeros_p (exp)))))
+ && ! mostly_zeros_p (exp))))
|| ((modifier == EXPAND_INITIALIZER
|| modifier == EXPAND_CONST_ADDRESS)
&& TREE_CONSTANT (exp)))
case INDIRECT_REF:
{
tree exp1 = TREE_OPERAND (exp, 0);
- tree index;
- tree string = string_constant (exp1, &index);
- /* Try to optimize reads from const strings. */
- if (string
- && TREE_CODE (string) == STRING_CST
- && TREE_CODE (index) == INTEGER_CST
- && compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0
- && GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) == 1
- && modifier != EXPAND_WRITE)
- return gen_int_mode (TREE_STRING_POINTER (string)
- [TREE_INT_CST_LOW (index)], mode);
+ if (modifier != EXPAND_WRITE)
+ {
+ tree t;
+
+ t = fold_read_from_constant_string (exp);
+ if (t)
+ return expand_expr (t, target, tmode, modifier);
+ }
op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
op0 = memory_address (mode, op0);
}
case ARRAY_REF:
+
+#ifdef ENABLE_CHECKING
if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != ARRAY_TYPE)
abort ();
+#endif
{
tree array = TREE_OPERAND (exp, 0);
- tree domain = TYPE_DOMAIN (TREE_TYPE (array));
- tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
+ tree low_bound = array_ref_low_bound (exp);
tree index = convert (sizetype, TREE_OPERAND (exp, 1));
HOST_WIDE_INT i;
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
- && GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) == 1)
- return gen_int_mode (TREE_STRING_POINTER (array)
- [TREE_INT_CST_LOW (index)], mode);
+ && modifier != EXPAND_MEMORY)
+ {
+ tree t = fold_read_from_constant_string (exp);
+
+ if (t)
+ return expand_expr (t, target, tmode, modifier);
+ }
/* If this is a constant index into a constant array,
just get the value from the array. Handle both the cases when
enum machine_mode imode
= TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
- if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
+ if (TYPE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
{
op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
op0 = expand_and (imode, op0, op1, target);
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. */
- else if (GET_CODE (op0) != MEM
+ else if (!MEM_P (op0)
&& (offset != 0
|| (code == ARRAY_RANGE_REF && mode == BLKmode)))
{
- /* If the operand is a SAVE_EXPR, we can deal with this by
- forcing the SAVE_EXPR into memory. */
- if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
- {
- put_var_into_stack (TREE_OPERAND (exp, 0),
- /*rescan=*/true);
- op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
- }
- else
- {
- tree nt
- = build_qualified_type (TREE_TYPE (tem),
- (TYPE_QUALS (TREE_TYPE (tem))
- | TYPE_QUAL_CONST));
- rtx memloc = assign_temp (nt, 1, 1, 1);
+ tree nt = build_qualified_type (TREE_TYPE (tem),
+ (TYPE_QUALS (TREE_TYPE (tem))
+ | TYPE_QUAL_CONST));
+ rtx memloc = assign_temp (nt, 1, 1, 1);
- emit_move_insn (memloc, op0);
- op0 = memloc;
- }
+ emit_move_insn (memloc, op0);
+ op0 = memloc;
}
if (offset != 0)
rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
EXPAND_SUM);
- if (GET_CODE (op0) != MEM)
+ if (!MEM_P (op0))
abort ();
#ifdef POINTERS_EXTEND_UNSIGNED
/* If OFFSET is making OP0 more aligned than BIGGEST_ALIGNMENT,
record its alignment as BIGGEST_ALIGNMENT. */
- if (GET_CODE (op0) == MEM && bitpos == 0 && offset != 0
+ if (MEM_P (op0) && bitpos == 0 && offset != 0
&& is_aligning_offset (offset, tem))
set_mem_align (op0, BIGGEST_ALIGNMENT);
/* Don't forget about volatility even if this is a bitfield. */
- if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
+ if (MEM_P (op0) && volatilep && ! MEM_VOLATILE_P (op0))
{
if (op0 == orig_op0)
op0 = copy_rtx (op0);
(which we know to be the width of a basic mode), then
storing into memory, and changing the mode to BLKmode. */
if (mode1 == VOIDmode
- || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
+ || REG_P (op0) || GET_CODE (op0) == SUBREG
|| (mode1 != BLKmode && ! direct_load[(int) mode1]
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT
|| (mode1 != BLKmode
&& (((TYPE_ALIGN (TREE_TYPE (tem)) < GET_MODE_ALIGNMENT (mode)
|| (bitpos % GET_MODE_ALIGNMENT (mode) != 0)
- || (GET_CODE (op0) == MEM
+ || (MEM_P (op0)
&& (MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode1)
|| (bitpos % GET_MODE_ALIGNMENT (mode1) != 0))))
&& ((modifier == EXPAND_CONST_ADDRESS
enum machine_mode ext_mode = mode;
if (ext_mode == BLKmode
- && ! (target != 0 && GET_CODE (op0) == MEM
- && GET_CODE (target) == MEM
+ && ! (target != 0 && MEM_P (op0)
+ && MEM_P (target)
&& bitpos % BITS_PER_UNIT == 0))
ext_mode = mode_for_size (bitsize, MODE_INT, 1);
/* In this case, BITPOS must start at a byte boundary and
TARGET, if specified, must be a MEM. */
- if (GET_CODE (op0) != MEM
- || (target != 0 && GET_CODE (target) != MEM)
+ if (!MEM_P (op0)
+ || (target != 0 && !MEM_P (target))
|| bitpos % BITS_PER_UNIT != 0)
abort ();
op0 = validize_mem (op0);
- if (GET_CODE (op0) == MEM && GET_CODE (XEXP (op0, 0)) == REG)
+ if (MEM_P (op0) && REG_P (XEXP (op0, 0)))
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
- bitsize),
op0, 1);
+ /* If the result type is BLKmode, store the data into a temporary
+ of the appropriate type, but with the mode corresponding to the
+ mode for the data we have (op0's mode). It's tempting to make
+ this a constant type, since we know it's only being stored once,
+ but that can cause problems if we are taking the address of this
+ COMPONENT_REF because the MEM of any reference via that address
+ will have flags corresponding to the type, which will not
+ necessarily be constant. */
if (mode == BLKmode)
{
- rtx new = assign_temp (build_qualified_type
- ((*lang_hooks.types.type_for_mode)
- (ext_mode, 0),
- TYPE_QUAL_CONST), 0, 1, 1);
+ rtx new
+ = assign_stack_temp_for_type
+ (ext_mode, GET_MODE_BITSIZE (ext_mode), 0, type);
emit_move_insn (new, op0);
op0 = copy_rtx (new);
op0 = copy_rtx (op0);
set_mem_attributes (op0, exp, 0);
- if (GET_CODE (XEXP (op0, 0)) == REG)
+ if (REG_P (XEXP (op0, 0)))
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
MEM_VOLATILE_P (op0) |= volatilep;
return target;
}
- case VTABLE_REF:
- {
- rtx insn, before = get_last_insn (), vtbl_ref;
-
- /* Evaluate the interior expression. */
- subtarget = expand_expr (TREE_OPERAND (exp, 0), target,
- tmode, modifier);
-
- /* Get or create an instruction off which to hang a note. */
- if (REG_P (subtarget))
- {
- target = subtarget;
- insn = get_last_insn ();
- if (insn == before)
- abort ();
- if (! INSN_P (insn))
- insn = prev_nonnote_insn (insn);
- }
- else
- {
- target = gen_reg_rtx (GET_MODE (subtarget));
- insn = emit_move_insn (target, subtarget);
- }
-
- /* Collect the data for the note. */
- vtbl_ref = XEXP (DECL_RTL (TREE_OPERAND (exp, 1)), 0);
- vtbl_ref = plus_constant (vtbl_ref,
- tree_low_cst (TREE_OPERAND (exp, 2), 0));
- /* Discard the initial CONST that was added. */
- vtbl_ref = XEXP (vtbl_ref, 0);
-
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_VTABLE_REF, vtbl_ref, REG_NOTES (insn));
-
- return target;
- }
+ case OBJ_TYPE_REF:
+ return expand_expr (OBJ_TYPE_REF_EXPR (exp), target, tmode, modifier);
/* Intended for a reference to a buffer of a file-object in Pascal.
But it's not certain that a special tree code will really be
tree set = TREE_OPERAND (exp, 0);
tree index = TREE_OPERAND (exp, 1);
- int iunsignedp = TREE_UNSIGNED (TREE_TYPE (index));
+ int iunsignedp = TYPE_UNSIGNED (TREE_TYPE (index));
tree set_type = TREE_TYPE (set);
tree set_low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (set_type));
tree set_high_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (set_type));
{
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,
- alt_rtl);
+ return lang_hooks.expand_expr (exp, original_target,
+ tmode, modifier,
+ alt_rtl);
else
return expand_builtin (exp, target, subtarget, tmode, ignore);
}
case NON_LVALUE_EXPR:
case NOP_EXPR:
case CONVERT_EXPR:
- case REFERENCE_EXPR:
if (TREE_OPERAND (exp, 0) == error_mark_node)
return const0_rtx;
target = assign_temp (type, 0, 1, 1);
}
- if (GET_CODE (target) == MEM)
+ if (MEM_P (target))
/* Store data into beginning of memory target. */
store_expr (TREE_OPERAND (exp, 0),
adjust_address (target, TYPE_MODE (valtype), 0),
modifier == EXPAND_STACK_PARM ? 2 : 0);
- else if (GET_CODE (target) == REG)
+ else if (REG_P (target))
/* Store this field into a union of the proper type. */
store_field (target,
MIN ((int_size_in_bytes (TREE_TYPE
/* If the signedness of the conversion differs and OP0 is
a promoted SUBREG, clear that indication since we now
have to do the proper extension. */
- if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))) != unsignedp
+ if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))) != unsignedp
&& GET_CODE (op0) == SUBREG)
SUBREG_PROMOTED_VAR_P (op0) = 0;
inner_mode));
else
return convert_modes (mode, inner_mode, op0,
- TREE_UNSIGNED (inner_type));
+ TYPE_UNSIGNED (inner_type));
}
if (modifier == EXPAND_INITIALIZER)
if (target == 0)
return
convert_to_mode (mode, op0,
- TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+ TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
else
convert_move (target, op0,
- TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+ TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
return target;
case VIEW_CONVERT_EXPR:
&& 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);
- else if (GET_CODE (op0) != MEM)
+ else if (!MEM_P (op0))
{
/* If the operand is not a MEM, force it into memory. Since we
are going to be be changing the mode of the MEM, don't call
that the operand is known to be aligned, indicate that it is.
Otherwise, we need only be concerned about alignment for non-BLKmode
results. */
- if (GET_CODE (op0) == MEM)
+ if (MEM_P (op0))
{
op0 = copy_rtx (op0);
&& (GET_MODE_CLASS (mode) == MODE_INT)
? addv_optab : add_optab;
- /* If we are adding a constant, an RTL_EXPR that is sp, fp, or ap, and
+ /* If we are adding a constant, a VAR_DECL that is sp, fp, or ap, and
something else, make sure we add the register to the constant and
then to the other thing. This case can occur during strength
reduction and doing it this way will produce better code if the
if (TREE_CODE (TREE_OPERAND (exp, 0)) == PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 1)) == INTEGER_CST
- && TREE_CODE (TREE_OPERAND (exp, 1)) == RTL_EXPR
- && (RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == frame_pointer_rtx
- || RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == stack_pointer_rtx
- || RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == arg_pointer_rtx))
+ && TREE_CODE (TREE_OPERAND (exp, 1)) == VAR_DECL
+ && (DECL_RTL (TREE_OPERAND (exp, 1)) == frame_pointer_rtx
+ || DECL_RTL (TREE_OPERAND (exp, 1)) == stack_pointer_rtx
+ || DECL_RTL (TREE_OPERAND (exp, 1)) == arg_pointer_rtx))
{
tree t = TREE_OPERAND (exp, 1);
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
EXPAND_SUM);
- if (GET_CODE (op0) != REG)
+ if (!REG_P (op0))
op0 = force_operand (op0, NULL_RTX);
- if (GET_CODE (op0) != REG)
+ if (!REG_P (op0))
op0 = copy_to_mode_reg (mode, op0);
return gen_rtx_MULT (mode, op0,
|| exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0))
||
(TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
- && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
- ==
- TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))
+ && (TYPE_PRECISION (TREE_TYPE
+ (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
+ == TYPE_PRECISION (TREE_TYPE
+ (TREE_OPERAND
+ (TREE_OPERAND (exp, 0), 0))))
/* If both operands are extended, they must either both
be zero-extended or both be sign-extended. */
- && (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
- ==
- TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))))))
+ && (TYPE_UNSIGNED (TREE_TYPE
+ (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
+ == TYPE_UNSIGNED (TREE_TYPE
+ (TREE_OPERAND
+ (TREE_OPERAND (exp, 0), 0)))))))
{
tree op0type = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
enum machine_mode innermode = TYPE_MODE (op0type);
- bool zextend_p = TREE_UNSIGNED (op0type);
+ bool zextend_p = TYPE_UNSIGNED (op0type);
optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
op0 = copy_to_mode_reg (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
op0);
expand_float (target, op0,
- TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+ TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
return target;
case NEGATE_EXPR:
/* Unsigned abs is simply the operand. Testing here means we don't
risk generating incorrect code below. */
- if (TREE_UNSIGNED (type))
+ if (TYPE_UNSIGNED (type))
return op0;
return expand_abs (mode, op0, target, unsignedp,
target = original_target;
if (target == 0
|| modifier == EXPAND_STACK_PARM
- || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
+ || (MEM_P (target) && MEM_VOLATILE_P (target))
|| GET_MODE (target) != mode
- || (GET_CODE (target) == REG
+ || (REG_P (target)
&& REGNO (target) < FIRST_PSEUDO_REGISTER))
target = gen_reg_rtx (mode);
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
/* At this point, a MEM target is no longer useful; we will get better
code without it. */
- if (GET_CODE (target) == MEM)
+ if (MEM_P (target))
target = gen_reg_rtx (mode);
/* If op1 was placed in target, swap op0 and op1. */
case UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
+ case LTGT_EXPR:
temp = do_store_flag (exp,
modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
tmode != VOIDmode ? tmode : mode, 0);
/* For foo != 0, load foo, and if it is nonzero load 1 instead. */
if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1))
&& original_target
- && GET_CODE (original_target) == REG
+ && REG_P (original_target)
&& (GET_MODE (original_target)
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
{
|| ! 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
+ || (!optimize && REG_P (target)
&& REGNO (target) < FIRST_PSEUDO_REGISTER)))
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
(ignore ? const0_rtx : target),
VOIDmode, modifier, alt_rtl);
+ case STATEMENT_LIST:
+ {
+ tree_stmt_iterator iter;
+
+ if (!ignore)
+ abort ();
+
+ for (iter = tsi_start (exp); !tsi_end_p (iter); tsi_next (&iter))
+ expand_expr (tsi_stmt (iter), const0_rtx, VOIDmode, modifier);
+ }
+ return const0_rtx;
+
case COND_EXPR:
+ /* If it's void, we don't need to worry about computing a value. */
+ if (VOID_TYPE_P (TREE_TYPE (exp)))
+ {
+ tree pred = TREE_OPERAND (exp, 0);
+ tree then_ = TREE_OPERAND (exp, 1);
+ tree else_ = TREE_OPERAND (exp, 2);
+
+ /* If we do not have any pending cleanups or stack_levels
+ to restore, and at least one arm of the COND_EXPR is a
+ GOTO_EXPR to a local label, then we can emit more efficient
+ code by using jumpif/jumpifnot instead of the 'if' machinery. */
+ if (! optimize
+ || containing_blocks_have_cleanups_or_stack_level ())
+ ;
+ else if (TREE_CODE (then_) == GOTO_EXPR
+ && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
+ {
+ jumpif (pred, label_rtx (GOTO_DESTINATION (then_)));
+ return expand_expr (else_, const0_rtx, VOIDmode, 0);
+ }
+ else if (TREE_CODE (else_) == GOTO_EXPR
+ && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
+ {
+ jumpifnot (pred, label_rtx (GOTO_DESTINATION (else_)));
+ return expand_expr (then_, const0_rtx, VOIDmode, 0);
+ }
+
+ /* Just use the 'if' machinery. */
+ expand_start_cond (pred, 0);
+ start_cleanup_deferral ();
+ expand_expr (then_, const0_rtx, VOIDmode, 0);
+
+ exp = else_;
+
+ /* Iterate over 'else if's instead of recursing. */
+ for (; TREE_CODE (exp) == COND_EXPR; exp = TREE_OPERAND (exp, 2))
+ {
+ expand_start_else ();
+ if (EXPR_HAS_LOCATION (exp))
+ {
+ emit_line_note (EXPR_LOCATION (exp));
+ record_block_change (TREE_BLOCK (exp));
+ }
+ expand_elseif (TREE_OPERAND (exp, 0));
+ expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, 0);
+ }
+ /* Don't emit the jump and label if there's no 'else' clause. */
+ if (TREE_SIDE_EFFECTS (exp))
+ {
+ expand_start_else ();
+ expand_expr (exp, const0_rtx, VOIDmode, 0);
+ }
+ end_cleanup_deferral ();
+ expand_end_cond ();
+ return const0_rtx;
+ }
+
/* If we would have a "singleton" (see below) were it not for a
conversion in each arm, bring that conversion back out. */
if (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
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
+ || (singleton && REG_P (original_target)
&& REGNO (original_target) >= FIRST_PSEUDO_REGISTER
&& original_target == var_rtx (singleton)))
&& GET_MODE (original_target) == mode
#ifdef HAVE_conditional_move
&& (! can_conditionally_move_p (mode)
- || GET_CODE (original_target) == REG
+ || REG_P (original_target)
|| TREE_ADDRESSABLE (type))
#endif
- && (GET_CODE (original_target) != MEM
+ && (!MEM_P (original_target)
|| TREE_ADDRESSABLE (type)))
temp = original_target;
else if (TREE_ADDRESSABLE (type))
might clobber it. */
if ((binary_op
&& ! safe_from_p (temp, TREE_OPERAND (binary_op, 1), 1))
- || (GET_CODE (temp) == REG
+ || (REG_P (temp)
&& REGNO (temp) < FIRST_PSEUDO_REGISTER))
temp = gen_reg_rtx (mode);
store_expr (singleton, temp,
|| TREE_CODE (TREE_OPERAND (exp, 1)) == SAVE_EXPR)
&& safe_from_p (temp, TREE_OPERAND (exp, 2), 1))
{
- if (GET_CODE (temp) == REG
+ if (REG_P (temp)
&& REGNO (temp) < FIRST_PSEUDO_REGISTER)
temp = gen_reg_rtx (mode);
store_expr (TREE_OPERAND (exp, 1), temp,
|| TREE_CODE (TREE_OPERAND (exp, 2)) == SAVE_EXPR)
&& safe_from_p (temp, TREE_OPERAND (exp, 1), 1))
{
- if (GET_CODE (temp) == REG
+ if (REG_P (temp)
&& REGNO (temp) < FIRST_PSEUDO_REGISTER)
temp = gen_reg_rtx (mode);
store_expr (TREE_OPERAND (exp, 2), temp,
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, /*rescan=*/false);
/* Since SLOT is not known to the called function
to belong to its stack frame, we must build an explicit
if (TREE_OPERAND (exp, 2) == 0)
TREE_OPERAND (exp, 2)
- = (*lang_hooks.maybe_build_cleanup) (slot);
+ = lang_hooks.maybe_build_cleanup (slot);
cleanups = TREE_OPERAND (exp, 2);
}
}
return target;
}
else
- {
- 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))
- put_var_into_stack (slot, /*rescan=*/true);
- }
+ SET_DECL_RTL (slot, target);
}
exp1 = TREE_OPERAND (exp, 3) = TREE_OPERAND (exp, 1);
/* Mark it as expanded. */
TREE_OPERAND (exp, 1) = NULL_TREE;
- store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
+ if (VOID_TYPE_P (TREE_TYPE (exp1)))
+ /* If the initializer is void, just expand it; it will initialize
+ the object directly. */
+ expand_expr (exp1, const0_rtx, VOIDmode, 0);
+ else
+ store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
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
- && ! DECL_NO_STATIC_CHAIN (TREE_OPERAND (exp, 0))
- && ! TREE_STATIC (exp))
- {
- op0 = trampoline_address (TREE_OPERAND (exp, 0));
- op0 = force_operand (op0, target);
- }
/* If we are taking the address of something erroneous, just
return a zero. */
- else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
+ if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
return const0_rtx;
/* If we are taking the address of a constant and are at the
top level, we have to use output_constant_def since we can't
if (CONSTANT_P (op0))
op0 = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
op0);
- else if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
- || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF
- || GET_CODE (op0) == PARALLEL || GET_CODE (op0) == LO_SUM)
+ else if (REG_P (op0) || GET_CODE (op0) == SUBREG
+ || GET_CODE (op0) == CONCAT || GET_CODE (op0) == PARALLEL
+ || GET_CODE (op0) == LO_SUM)
{
- /* If the operand is a SAVE_EXPR, we can deal with this by
- forcing the SAVE_EXPR into memory. */
- if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
- {
- put_var_into_stack (TREE_OPERAND (exp, 0),
- /*rescan=*/true);
- op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
- }
+ /* If this object is in a register, it can't be BLKmode. */
+ tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
+ rtx memloc = assign_temp (inner_type, 1, 1, 1);
+
+ if (GET_CODE (op0) == PARALLEL)
+ /* Handle calls that pass values in multiple
+ non-contiguous locations. The Irix 6 ABI has examples
+ of this. */
+ emit_group_store (memloc, op0, inner_type,
+ int_size_in_bytes (inner_type));
else
- {
- /* If this object is in a register, it can't be BLKmode. */
- tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
- rtx memloc = assign_temp (inner_type, 1, 1, 1);
-
- if (GET_CODE (op0) == PARALLEL)
- /* Handle calls that pass values in multiple
- non-contiguous locations. The Irix 6 ABI has examples
- of this. */
- emit_group_store (memloc, op0, inner_type,
- int_size_in_bytes (inner_type));
- else
- emit_move_insn (memloc, op0);
+ emit_move_insn (memloc, op0);
- op0 = memloc;
- }
+ op0 = memloc;
}
- if (GET_CODE (op0) != MEM)
+ if (!MEM_P (op0))
abort ();
mark_temp_addr_taken (op0);
}
if (flag_force_addr
- && GET_CODE (op0) != REG
+ && !REG_P (op0)
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER
&& modifier != EXPAND_SUM)
op0 = force_reg (Pmode, op0);
- if (GET_CODE (op0) == REG
+ if (REG_P (op0)
&& ! REG_USERVAR_P (op0))
mark_reg_pointer (op0, TYPE_ALIGN (TREE_TYPE (type)));
return target;
}
+ case RESX_EXPR:
+ expand_resx_expr (exp);
+ return const0_rtx;
+
case TRY_CATCH_EXPR:
{
tree handler = TREE_OPERAND (exp, 1);
expand_eh_region_start ();
-
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
-
- expand_eh_region_end_cleanup (handler);
+ expand_eh_handler (handler);
return op0;
}
+ case CATCH_EXPR:
+ expand_start_catch (CATCH_TYPES (exp));
+ expand_expr (CATCH_BODY (exp), const0_rtx, VOIDmode, 0);
+ expand_end_catch ();
+ return const0_rtx;
+
+ case EH_FILTER_EXPR:
+ /* Should have been handled in expand_eh_handler. */
+ abort ();
+
case TRY_FINALLY_EXPR:
{
tree try_block = TREE_OPERAND (exp, 0);
tree finally_block = TREE_OPERAND (exp, 1);
- if (!optimize || unsafe_for_reeval (finally_block) > 1)
+ if ((!optimize && lang_protect_cleanup_actions == NULL)
+ || unsafe_for_reeval (finally_block) > 1)
{
/* In this case, wrapping FINALLY_BLOCK in an UNSAVE_EXPR
is not sufficient, so we cannot expand the block twice.
case EXC_PTR_EXPR:
return get_exception_pointer (cfun);
+ case FILTER_EXPR:
+ return get_exception_filter (cfun);
+
case FDESC_EXPR:
/* Function descriptors are not valid except for as
initialization constants, and should not be expanded. */
abort ();
+ case SWITCH_EXPR:
+ expand_start_case (0, SWITCH_COND (exp), integer_type_node,
+ "switch");
+ if (SWITCH_BODY (exp))
+ expand_expr_stmt (SWITCH_BODY (exp));
+ if (SWITCH_LABELS (exp))
+ {
+ tree duplicate = 0;
+ tree vec = SWITCH_LABELS (exp);
+ size_t i, n = TREE_VEC_LENGTH (vec);
+
+ for (i = 0; i < n; ++i)
+ {
+ tree elt = TREE_VEC_ELT (vec, i);
+ tree controlling_expr_type = TREE_TYPE (SWITCH_COND (exp));
+ tree min_value = TYPE_MIN_VALUE (controlling_expr_type);
+ tree max_value = TYPE_MAX_VALUE (controlling_expr_type);
+
+ tree case_low = CASE_LOW (elt);
+ tree case_high = CASE_HIGH (elt) ? CASE_HIGH (elt) : case_low;
+ if (case_low && case_high)
+ {
+ /* Case label is less than minimum for type. */
+ if (TREE_CODE (min_value) == INTEGER_CST
+ && tree_int_cst_compare (case_low, min_value) < 0
+ && tree_int_cst_compare (case_high, min_value) < 0)
+ {
+ warning ("case label value %d is less than minimum value for type",
+ TREE_INT_CST (case_low));
+ continue;
+ }
+
+ /* Case value is greater than maximum for type. */
+ if (TREE_CODE (max_value) == INTEGER_CST
+ && tree_int_cst_compare (case_low, max_value) > 0
+ && tree_int_cst_compare (case_high, max_value) > 0)
+ {
+ warning ("case label value %d exceeds maximum value for type",
+ TREE_INT_CST (case_high));
+ continue;
+ }
+
+ /* Saturate lower case label value to minimum. */
+ if (TREE_CODE (min_value) == INTEGER_CST
+ && tree_int_cst_compare (case_high, min_value) >= 0
+ && tree_int_cst_compare (case_low, min_value) < 0)
+ {
+ warning ("lower value %d in case label range less than minimum value for type",
+ TREE_INT_CST (case_low));
+ case_low = min_value;
+ }
+
+ /* Saturate upper case label value to maximum. */
+ if (TREE_CODE (max_value) == INTEGER_CST
+ && tree_int_cst_compare (case_low, max_value) <= 0
+ && tree_int_cst_compare (case_high, max_value) > 0)
+ {
+ warning ("upper value %d in case label range exceeds maximum value for type",
+ TREE_INT_CST (case_high));
+ case_high = max_value;
+ }
+ }
+
+ add_case_node (case_low, case_high, CASE_LABEL (elt), &duplicate, true);
+ if (duplicate)
+ abort ();
+ }
+ }
+ expand_end_case_type (SWITCH_COND (exp), TREE_TYPE (exp));
+ return const0_rtx;
+
+ case LABEL_EXPR:
+ expand_label (TREE_OPERAND (exp, 0));
+ return const0_rtx;
+
+ case CASE_LABEL_EXPR:
+ {
+ tree duplicate = 0;
+ add_case_node (CASE_LOW (exp), CASE_HIGH (exp), CASE_LABEL (exp),
+ &duplicate, false);
+ if (duplicate)
+ abort ();
+ return const0_rtx;
+ }
+
+ case ASM_EXPR:
+ expand_asm_expr (exp);
+ return const0_rtx;
+
default:
- return (*lang_hooks.expand_expr) (exp, original_target, tmode, modifier,
- alt_rtl);
+ return lang_hooks.expand_expr (exp, original_target, tmode,
+ modifier, alt_rtl);
}
/* Here to do an ordinary binary operator, generating an instruction
static int
is_aligning_offset (tree offset, tree exp)
{
- /* Strip off any conversions and WITH_RECORD_EXPR nodes. */
+ /* Strip off any conversions. */
while (TREE_CODE (offset) == NON_LVALUE_EXPR
|| TREE_CODE (offset) == NOP_EXPR
- || TREE_CODE (offset) == CONVERT_EXPR
- || TREE_CODE (offset) == WITH_RECORD_EXPR)
+ || TREE_CODE (offset) == CONVERT_EXPR)
offset = TREE_OPERAND (offset, 0);
/* We must now have a BIT_AND_EXPR with a constant that is one less than
|| TREE_CODE (offset) == CONVERT_EXPR)
offset = TREE_OPERAND (offset, 0);
- /* This must now be the address either of EXP or of a PLACEHOLDER_EXPR
- whose type is the same as EXP. */
- return (TREE_CODE (offset) == ADDR_EXPR
- && (TREE_OPERAND (offset, 0) == exp
- || (TREE_CODE (TREE_OPERAND (offset, 0)) == PLACEHOLDER_EXPR
- && (TREE_TYPE (TREE_OPERAND (offset, 0))
- == TREE_TYPE (exp)))));
+ /* This must now be the address of EXP. */
+ return TREE_CODE (offset) == ADDR_EXPR && TREE_OPERAND (offset, 0) == exp;
}
\f
/* Return the tree node if an ARG corresponds to a string constant or zero
*ptr_offset = size_zero_node;
return TREE_OPERAND (arg, 0);
}
+ if (TREE_CODE (arg) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0)) == STRING_CST)
+ {
+ *ptr_offset = convert (sizetype, TREE_OPERAND (TREE_OPERAND (arg, 0), 1));
+ return TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+ }
else if (TREE_CODE (arg) == PLUS_EXPR)
{
tree arg0 = TREE_OPERAND (arg, 0);
bad_subreg = 1;
}
- op0_is_copy = ((GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG)
+ op0_is_copy = ((GET_CODE (op0) == SUBREG || REG_P (op0))
&& temp != get_last_insn ());
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1));
}
- if (icode != (int) CODE_FOR_nothing && GET_CODE (op0) == MEM)
+ if (icode != (int) CODE_FOR_nothing && MEM_P (op0))
{
rtx addr = (general_operand (XEXP (op0, 0), mode)
? force_reg (Pmode, XEXP (op0, 0))
/* Increment however we can. */
op1 = expand_binop (mode, this_optab, value, op1, op0,
- TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
+ TYPE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
/* Make sure the value is stored into OP0. */
if (op1 != op0)
type = TREE_TYPE (arg0);
operand_mode = TYPE_MODE (type);
- unsignedp = TREE_UNSIGNED (type);
+ unsignedp = TYPE_UNSIGNED (type);
/* We won't bother with BLKmode store-flag operations because it would mean
passing a lot of information to emit_store_flag. */
case UNEQ_EXPR:
code = UNEQ;
break;
+ case LTGT_EXPR:
+ code = LTGT;
+ break;
default:
abort ();
&& TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
&& integer_pow2p (TREE_OPERAND (arg0, 1)))
{
- tree type = (*lang_hooks.types.type_for_mode) (mode, unsignedp);
+ tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
return expand_expr (fold_single_bit_test (code == NE ? NE_EXPR : EQ_EXPR,
arg0, arg1, type),
target, VOIDmode, EXPAND_NORMAL);
}
/* If this failed, we have to do this with set/compare/jump/set code. */
- if (GET_CODE (target) != REG
+ if (!REG_P (target)
|| reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
target = gen_reg_rtx (GET_MODE (target));
{
if (TYPE_MODE (index_type) != index_mode)
{
- index_expr = convert ((*lang_hooks.types.type_for_size)
+ index_expr = convert (lang_hooks.types.type_for_size
(index_bits, 0), index_expr);
index_type = TREE_TYPE (index_expr);
}
op_mode = insn_data[(int) CODE_FOR_casesi].operand[1].mode;
op1 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (minval)),
- op1, TREE_UNSIGNED (TREE_TYPE (minval)));
+ op1, TYPE_UNSIGNED (TREE_TYPE (minval)));
if (! (*insn_data[(int) CODE_FOR_casesi].operand[1].predicate)
(op1, op_mode))
op1 = copy_to_mode_reg (op_mode, op1);
op_mode = insn_data[(int) CODE_FOR_casesi].operand[2].mode;
op2 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (range)),
- op2, TREE_UNSIGNED (TREE_TYPE (range)));
+ op2, TYPE_UNSIGNED (TREE_TYPE (range)));
if (! (*insn_data[(int) CODE_FOR_casesi].operand[2].predicate)
(op2, op_mode))
op2 = copy_to_mode_reg (op_mode, op2);
out of PIC_CASE_VECTOR_ADDRESS won't be a valid address,
and break_out_memory_refs will go to work on it and mess it up. */
#ifdef PIC_CASE_VECTOR_ADDRESS
- if (flag_pic && GET_CODE (index) != REG)
+ if (flag_pic && !REG_P (index))
index = copy_to_mode_reg (Pmode, index);
#endif
TYPE_MODE (TREE_TYPE (range)),
expand_expr (range, NULL_RTX,
VOIDmode, 0),
- TREE_UNSIGNED (TREE_TYPE (range))),
+ TYPE_UNSIGNED (TREE_TYPE (range))),
table_label, default_label);
return 1;
}
mode = TYPE_MODE (TREE_TYPE (exp));
- if (is_zeros_p (exp))
+ if (initializer_zerop (exp))
return CONST0_RTX (mode);
units = GET_MODE_NUNITS (mode);
return gen_rtx_raw_CONST_VECTOR (mode, v);
}
-
#include "gt-expr.h"