/* Convert tree expression to rtl instructions, for GNU compiler.
- Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
- Free Software Foundation, Inc.
+ Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "reload.h"
#include "output.h"
#include "typeclass.h"
-#include "defaults.h"
#include "toplev.h"
#include "ggc.h"
#include "intl.h"
static tree init_noncopied_parts PARAMS ((tree, tree));
static int fixed_type_p PARAMS ((tree));
static rtx var_rtx PARAMS ((tree));
-static int readonly_fields_p PARAMS ((tree));
static rtx expand_expr_unaligned PARAMS ((tree, unsigned int *));
static rtx expand_increment PARAMS ((tree, int, int));
static void do_jump_by_parts_greater PARAMS ((tree, int, rtx, rtx));
to perform a structure copy. */
#ifndef MOVE_BY_PIECES_P
#define MOVE_BY_PIECES_P(SIZE, ALIGN) \
- (move_by_pieces_ninsns (SIZE, ALIGN) < MOVE_RATIO)
+ (move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) MOVE_RATIO)
#endif
/* This array records the insn_code of insns to perform block moves. */
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
- make_decl_rtl (fn, NULL_PTR, 1);
+ make_decl_rtl (fn, NULL_PTR);
assemble_external (fn);
}
#endif
enum machine_mode mode;
+ if (nregs == 0)
+ return;
+
/* If SIZE is that of a mode no bigger than a word, just use that
mode's store operation. */
if (size <= UNITS_PER_WORD
int shift = 0;
/* Handle trailing fragments that run over the size of the struct. */
- if (ssize >= 0 && bytepos + bytelen > ssize)
+ if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
{
shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
bytelen = ssize - bytepos;
if (bytepos == 0
&& bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0))))
tmps[i] = XEXP (src, 0);
- else if (bytepos == GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
+ else if (bytepos == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
&& bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1))))
tmps[i] = XEXP (src, 1);
else
unsigned int bytelen = GET_MODE_SIZE (mode);
/* Handle trailing fragments that run over the size of the struct. */
- if (ssize >= 0 && bytepos + bytelen > ssize)
+ if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
{
if (BYTES_BIG_ENDIAN)
{
if (tgtblk == 0)
{
- tgtblk = assign_stack_temp (BLKmode, bytes, 0);
- MEM_SET_IN_STRUCT_P (tgtblk, AGGREGATE_TYPE_P (type));
+ tgtblk = assign_temp (build_qualified_type (type,
+ (TYPE_QUALS (type)
+ | TYPE_QUAL_CONST)),
+ 0, 1, 1);
preserve_temp_slots (tgtblk);
}
just move a zero. Otherwise, do this a piece at a time. */
if (GET_MODE (object) != BLKmode
&& GET_CODE (size) == CONST_INT
- && GET_MODE_SIZE (GET_MODE (object)) == INTVAL (size))
+ && GET_MODE_SIZE (GET_MODE (object)) == (unsigned int) INTVAL (size))
emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
else
{
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
- make_decl_rtl (fn, NULL_PTR, 1);
+ make_decl_rtl (fn, NULL_PTR);
assemble_external (fn);
}
rtx x, y;
{
enum machine_mode mode = GET_MODE (x);
+ rtx y_cst = NULL_RTX;
+ rtx last_insn;
x = protect_from_queue (x, 1);
y = protect_from_queue (y, 0);
if (GET_CODE (y) == CONSTANT_P_RTX)
;
else if (CONSTANT_P (y) && ! LEGITIMATE_CONSTANT_P (y))
- y = force_const_mem (mode, y);
+ {
+ y_cst = y;
+ y = force_const_mem (mode, y);
+ }
/* If X or Y are memory references, verify that their addresses are valid
for the machine. */
if (mode == BLKmode)
abort ();
- return emit_move_insn_1 (x, y);
+ last_insn = emit_move_insn_1 (x, y);
+
+ if (y_cst && GET_CODE (x) == REG)
+ REG_NOTES (last_insn)
+ = gen_rtx_EXPR_LIST (REG_EQUAL, y_cst, REG_NOTES (last_insn));
+
+ return last_insn;
}
/* Low level part of emit_move_insn.
enum mode_class reg_class = ((class == MODE_COMPLEX_FLOAT)
? MODE_FLOAT : MODE_INT);
- enum machine_mode reg_mode =
- mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
+ enum machine_mode reg_mode
+ = mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
if (reg_mode != BLKmode)
{
rtx mem = assign_stack_temp (reg_mode,
GET_MODE_SIZE (mode), 0);
-
rtx cmem = change_address (mem, mode, NULL_RTX);
- cfun->cannot_inline = N_("function using short complex types cannot be inline");
+ cfun->cannot_inline
+ = N_("function using short complex types cannot be inline");
if (packed_dest_p)
{
{
addr = plus_constant (addr, TREE_STRING_LENGTH (exp));
size = plus_constant (size, -TREE_STRING_LENGTH (exp));
- align = MIN (align, (BITS_PER_UNIT
- * (INTVAL (copy_size_rtx)
- & - INTVAL (copy_size_rtx))));
+ align = MIN (align,
+ (unsigned int) (BITS_PER_UNIT
+ * (INTVAL (copy_size_rtx)
+ & - INTVAL (copy_size_rtx))));
}
else
{
plus_constant (XEXP (target, 0),
bitpos / BITS_PER_UNIT));
+
+ /* Show the alignment may no longer be what it was and update the alias
+ set, if required. */
+ if (bitpos != 0)
+ align = MIN (align, (unsigned int) bitpos & - bitpos);
if (GET_CODE (target) == MEM)
MEM_ALIAS_SET (target) = alias_set;
+
store_constructor (exp, target, align, cleared, bitsize / BITS_PER_UNIT);
}
else
!= fields_length (type))
|| mostly_zeros_p (exp))
&& (GET_CODE (target) != REG
- || GET_MODE_SIZE (GET_MODE (target)) == size))
+ || (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target)) == size))
{
if (! cleared)
clear_storage (target, GEN_INT (size), align);
store_constructor_field (target, bitsize, bitpos, mode, value,
type, align, cleared,
TYPE_NONALIASED_COMPONENT (type)
+ && GET_CODE (target) == MEM
? MEM_ALIAS_SET (target) :
get_alias_set (elttype));
if (REG_P (target))
{
- targetx = assign_stack_temp (GET_MODE (target),
- GET_MODE_SIZE (GET_MODE (target)),
- 0);
+ targetx
+ = assign_temp
+ ((build_qualified_type (type_for_mode (GET_MODE (target), 0),
+ TYPE_QUAL_CONST)),
+ 0, 1, 1);
emit_move_insn (targetx, target);
}
if (mode == BLKmode
&& (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
{
- rtx object = assign_stack_temp (GET_MODE (target),
- GET_MODE_SIZE (GET_MODE (target)), 0);
+ rtx object
+ = assign_temp
+ (build_qualified_type (type_for_mode (GET_MODE (target), 0),
+ TYPE_QUAL_CONST),
+ 0, 1, 1);
rtx blk_object = copy_rtx (object);
- MEM_SET_IN_STRUCT_P (object, 1);
- MEM_SET_IN_STRUCT_P (blk_object, 1);
PUT_MODE (blk_object, BLKmode);
- if (bitsize != GET_MODE_BITSIZE (GET_MODE (target)))
+ if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
emit_move_insn (object, target);
store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0,
}
}
\f
-/* Given an rtx VALUE that may contain additions and multiplications,
- return an equivalent value that just refers to a register or memory.
- This is done by generating instructions to perform the arithmetic
- and returning a pseudo-register containing the value.
+/* Given an rtx VALUE that may contain additions and multiplications, return
+ an equivalent value that just refers to a register, memory, or constant.
+ This is done by generating instructions to perform the arithmetic and
+ returning a pseudo-register containing the value.
The returned value may be a REG, SUBREG, MEM or constant. */
tree part = TREE_VALUE (tail);
tree part_type = TREE_TYPE (part);
tree to_be_saved = build (COMPONENT_REF, part_type, lhs, part);
- rtx target = assign_temp (part_type, 0, 1, 1);
+ rtx target
+ = assign_temp (build_qualified_type (part_type,
+ (TYPE_QUALS (part_type)
+ | TYPE_QUAL_CONST)),
+ 0, 1, 1);
+
if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
target = change_address (target, TYPE_MODE (part_type), NULL_RTX);
parts = tree_cons (to_be_saved,
{
rtx exp_rtl = 0;
int i, nops;
- static int save_expr_count;
- static int save_expr_size = 0;
- static tree *save_expr_rewritten;
- static tree save_expr_trees[256];
+ static tree save_expr_list;
if (x == 0
/* If EXP has varying size, we MUST use a target since we currently
|| TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)) == NULL_TREE
|| TREE_CODE (TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)))
!= INTEGER_CST)
- && GET_MODE (x) == BLKmode))
+ && GET_MODE (x) == BLKmode)
+ /* If X is in the outgoing argument area, it is always safe. */
+ || (GET_CODE (x) == MEM
+ && (XEXP (x, 0) == virtual_outgoing_args_rtx
+ || (GET_CODE (XEXP (x, 0)) == PLUS
+ && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx))))
return 1;
- if (top_p && save_expr_size == 0)
- {
- int rtn;
-
- save_expr_count = 0;
- save_expr_size = ARRAY_SIZE (save_expr_trees);
- save_expr_rewritten = &save_expr_trees[0];
-
- rtn = safe_from_p (x, exp, 1);
-
- for (i = 0; i < save_expr_count; ++i)
- {
- if (TREE_CODE (save_expr_trees[i]) != ERROR_MARK)
- abort ();
- TREE_SET_CODE (save_expr_trees[i], SAVE_EXPR);
- }
-
- save_expr_size = 0;
-
- return rtn;
- }
-
/* If this is a subreg of a hard register, declare it unsafe, otherwise,
find the underlying pseudo. */
if (GET_CODE (x) == SUBREG)
return 0;
}
- /* If X is a location in the outgoing argument area, it is always safe. */
- if (GET_CODE (x) == MEM
- && (XEXP (x, 0) == virtual_outgoing_args_rtx
- || (GET_CODE (XEXP (x, 0)) == PLUS
- && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx)))
- return 1;
+ /* 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 test case 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)))
{
case 'd':
{
case ADDR_EXPR:
return (staticp (TREE_OPERAND (exp, 0))
- || safe_from_p (x, TREE_OPERAND (exp, 0), 0)
- || TREE_STATIC (exp));
+ || TREE_STATIC (exp)
+ || safe_from_p (x, TREE_OPERAND (exp, 0), 0));
case INDIRECT_REF:
- if (GET_CODE (x) == MEM)
+ if (GET_CODE (x) == MEM
+ && alias_sets_conflict_p (MEM_ALIAS_SET (x),
+ get_alias_set (exp)))
return 0;
break;
if (exp_rtl)
break;
- /* This SAVE_EXPR might appear many times in the top-level
- safe_from_p() expression, 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 test case compiled with
- optimization took about 28 minutes to compile -- even though
- it was only a few lines long, and the complicated line causing
- so much time to be spent in the earlier version of safe_from_p()
- had only 293 or so unique nodes.
-
- So, turn this SAVE_EXPR into an ERROR_MARK for now, but remember
- where it is so we can turn it back in the top-level safe_from_p()
- when we're done. */
-
- /* For now, don't bother re-sizing the array. */
- if (save_expr_count >= save_expr_size)
- return 0;
- save_expr_rewritten[save_expr_count++] = exp;
+ /* 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;
- nops = TREE_CODE_LENGTH (SAVE_EXPR);
- for (i = 0; i < nops; i++)
+ TREE_PRIVATE (exp) = 1;
+ if (! safe_from_p (x, TREE_OPERAND (exp, 0), 0))
{
- tree operand = TREE_OPERAND (exp, i);
- if (operand == NULL_TREE)
- continue;
- TREE_SET_CODE (exp, ERROR_MARK);
- if (!safe_from_p (x, operand, 0))
- return 0;
- TREE_SET_CODE (exp, SAVE_EXPR);
+ TREE_PRIVATE (exp) = 0;
+ return 0;
}
- TREE_SET_CODE (exp, ERROR_MARK);
+
+ save_expr_list = tree_cons (exp, NULL_TREE, save_expr_list);
return 1;
case BIND_EXPR:
}
/* If the rtl is X, then it is not safe. Otherwise, it is unless both
- are memory and EXP is not readonly. */
+ are memory and they conflict. */
return ! (rtx_equal_p (x, exp_rtl)
|| (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
- && ! TREE_READONLY (exp)));
+ && true_dependence (exp_rtl, GET_MODE (x), x,
+ rtx_addr_varies_p)));
}
/* If we reach here, it is safe. */
}
#ifdef MAX_INTEGER_COMPUTATION_MODE
+
void
check_max_integer_computation_mode (exp)
tree exp;
mode = TYPE_MODE (TREE_TYPE (exp));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
}
/* Check operand of a unary op. */
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
}
/* Check operands of a binary/comparison op. */
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
}
}
#endif
\f
-/* Utility function used by expand_expr to see if TYPE, a RECORD_TYPE,
- has any readonly fields. If any of the fields have types that
- contain readonly fields, return true as well. */
-
-static int
-readonly_fields_p (type)
- tree type;
-{
- tree field;
-
- for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field))
- if (TREE_CODE (field) == FIELD_DECL
- && (TREE_READONLY (field)
- || (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
- && readonly_fields_p (TREE_TYPE (field)))))
- return 1;
-
- return 0;
-}
-\f
/* expand_expr: generate code for computing expression EXP.
An rtx for the computed value is returned. The value is never null.
In the case of a void EXP, const0_rtx is returned.
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
}
if (tmode != mode
&& TREE_CODE (exp) != RTL_EXPR
&& GET_MODE_CLASS (tmode) == MODE_INT
&& tmode > MAX_INTEGER_COMPUTATION_MODE)
- fatal ("unsupported wide integer operation");
+ internal_error ("unsupported wide integer operation");
check_max_integer_computation_mode (exp);
#endif
if (mode == VOIDmode)
temp = const0_rtx;
else
- {
- temp = assign_temp (type, 3, 0, 0);
- if (GET_CODE (temp) == MEM)
- RTX_UNCHANGING_P (temp) = 1;
- }
+ 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)
XEXP (constructor, 0));
return constructor;
}
-
else
{
/* Handle calls that pass values in multiple non-contiguous
locations. The Irix 6 ABI has examples of this. */
if (target == 0 || ! safe_from_p (target, exp, 1)
|| GET_CODE (target) == PARALLEL)
- {
- if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
- target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
- else
- target = assign_temp (type, 0, 1, 1);
- }
-
- if (TREE_READONLY (exp))
- {
- if (GET_CODE (target) == MEM)
- target = copy_rtx (target);
-
- RTX_UNCHANGING_P (target) = 1;
- }
+ target
+ = assign_temp (build_qualified_type (type,
+ (TYPE_QUALS (type)
+ | (TREE_READONLY (exp)
+ * TYPE_QUAL_CONST))),
+ TREE_ADDRESSABLE (exp), 1, 1);
store_constructor (exp, target, TYPE_ALIGN (TREE_TYPE (exp)), 0,
int_size_in_bytes (TREE_TYPE (exp)));
/* If we are writing to this object and its type is a record with
readonly fields, we must mark it as readonly so it will
conflict with readonly references to those fields. */
- if (modifier == EXPAND_MEMORY_USE_WO
- && TREE_CODE (type) == RECORD_TYPE && readonly_fields_p (type))
+ if (modifier == EXPAND_MEMORY_USE_WO && readonly_fields_p (type))
RTX_UNCHANGING_P (temp) = 1;
return temp;
if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
{
- rtx memloc = assign_temp (TREE_TYPE (tem), 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);
mark_temp_addr_taken (memloc);
emit_move_insn (memloc, op0);
if (mode == BLKmode)
{
- rtx new = assign_stack_temp (ext_mode,
- bitsize / BITS_PER_UNIT, 0);
+ tree nt = build_qualified_type (type_for_mode (ext_mode, 0),
+ TYPE_QUAL_CONST);
+ rtx new = assign_temp (nt, 0, 1, 1);
emit_move_insn (new, op0);
op0 = copy_rtx (new);
PUT_MODE (op0, BLKmode);
- MEM_SET_IN_STRUCT_P (op0, 1);
}
return op0;
modifier);
if (target == 0)
- {
- if (mode != BLKmode)
- target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
- else
- target = assign_temp (type, 0, 1, 1);
- }
+ target = assign_temp (type, 0, 1, 1);
if (GET_CODE (target) == MEM)
/* Store data into beginning of memory target. */
MIN ((int_size_in_bytes (TREE_TYPE
(TREE_OPERAND (exp, 0)))
* BITS_PER_UNIT),
- GET_MODE_BITSIZE (mode)),
+ (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
VOIDmode, 0, BITS_PER_UNIT,
int_size_in_bytes (type), 0);
/* If this object is in a register, it must be not
be BLKmode. */
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
- rtx memloc = assign_temp (inner_type, 1, 1, 1);
+ tree nt = build_qualified_type (inner_type,
+ (TYPE_QUALS (inner_type)
+ | TYPE_QUAL_CONST));
+ rtx memloc = assign_temp (nt, 1, 1, 1);
mark_temp_addr_taken (memloc);
if (GET_CODE (op0) == PARALLEL)
if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
{
- rtx memloc = assign_temp (TREE_TYPE (tem), 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);
mark_temp_addr_taken (memloc);
emit_move_insn (memloc, op0);
}
else
{
- rtx new = assign_stack_temp (ext_mode,
- bitsize / BITS_PER_UNIT, 0);
+ tree nt = build_qualified_type (type_for_mode (ext_mode, 0),
+ TYPE_QUAL_CONST);
+ rtx new = assign_temp (nt, 0, 1, 1);
op0 = extract_bit_field (validize_mem (op0), bitsize, bitpos,
unsignedp, NULL_RTX, ext_mode,
/* Do any postincrements in the expression that was tested. */
emit_queue ();
- if (GET_CODE (temp) == CONST_INT || GET_CODE (temp) == LABEL_REF)
+ if (GET_CODE (temp) == CONST_INT
+ || (GET_CODE (temp) == CONST_DOUBLE && GET_MODE (temp) == VOIDmode)
+ || GET_CODE (temp) == LABEL_REF)
{
rtx target = temp == const0_rtx ? if_false_label : if_true_label;
if (target)