Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
2000, 2001 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
#include "config.h"
#include "system.h"
unsigned int, HOST_WIDE_INT, int));
static enum memory_use_mode
get_memory_usage_from_modifier PARAMS ((enum expand_modifier));
-static tree save_noncopied_parts PARAMS ((tree, tree));
-static tree init_noncopied_parts PARAMS ((tree, tree));
-static int fixed_type_p PARAMS ((tree));
static rtx var_rtx PARAMS ((tree));
static rtx expand_expr_unaligned PARAMS ((tree, unsigned int *));
static rtx expand_increment PARAMS ((tree, int, int));
}
#ifndef STACK_GROWS_DOWNWARD
-#ifdef ARGS_GROW_DOWNWARD
- if (!ACCUMULATE_OUTGOING_ARGS)
-#else
if (0)
-#endif
#else
if (1)
#endif
{
- /* Return the lowest stack address when STACK or ARGS grow downward and
- we are not aaccumulating outgoing arguments (the c4x port uses such
- conventions). */
temp = virtual_outgoing_args_rtx;
if (extra != 0 && below)
temp = plus_constant (temp, extra);
Default is below for small data on big-endian machines; else above. */
enum direction where_pad = FUNCTION_ARG_PADDING (mode, type);
- /* Invert direction if stack is post-update. */
- if (STACK_PUSH_CODE == POST_INC || STACK_PUSH_CODE == POST_DEC)
+ /* Invert direction if stack is post-decrement.
+ FIXME: why? */
+ if (STACK_PUSH_CODE == POST_DEC)
if (where_pad != none)
where_pad = (where_pad == downward ? upward : downward);
int need_to_clear;
tree domain = TYPE_DOMAIN (type);
tree elttype = TREE_TYPE (type);
- int const_bounds_p = (host_integerp (TYPE_MIN_VALUE (domain), 0)
+ int const_bounds_p = (TYPE_MIN_VALUE (domain)
+ && TYPE_MAX_VALUE (domain)
+ && host_integerp (TYPE_MIN_VALUE (domain), 0)
&& host_integerp (TYPE_MAX_VALUE (domain), 0));
HOST_WIDE_INT minelt = 0;
HOST_WIDE_INT maxelt = 0;
return value;
}
\f
-/* Subroutine of expand_expr:
- save the non-copied parts (LIST) of an expr (LHS), and return a list
- which can restore these values to their previous values,
- should something modify their storage. */
-
-static tree
-save_noncopied_parts (lhs, list)
- tree lhs;
- tree list;
-{
- tree tail;
- tree parts = 0;
-
- for (tail = list; tail; tail = TREE_CHAIN (tail))
- if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
- parts = chainon (parts, save_noncopied_parts (lhs, TREE_VALUE (tail)));
- else
- {
- 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 (build_qualified_type (part_type,
- (TYPE_QUALS (part_type)
- | TYPE_QUAL_CONST)),
- 0, 1, 1);
-
- parts = tree_cons (to_be_saved,
- build (RTL_EXPR, part_type, NULL_TREE,
- (tree) validize_mem (target)),
- parts);
- store_expr (TREE_PURPOSE (parts),
- RTL_EXPR_RTL (TREE_VALUE (parts)), 0);
- }
- return parts;
-}
-
-/* Subroutine of expand_expr:
- record the non-copied parts (LIST) of an expr (LHS), and return a list
- which specifies the initial values of these parts. */
-
-static tree
-init_noncopied_parts (lhs, list)
- tree lhs;
- tree list;
-{
- tree tail;
- tree parts = 0;
-
- for (tail = list; tail; tail = TREE_CHAIN (tail))
- if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
- parts = chainon (parts, init_noncopied_parts (lhs, TREE_VALUE (tail)));
- else if (TREE_PURPOSE (tail))
- {
- tree part = TREE_VALUE (tail);
- tree part_type = TREE_TYPE (part);
- tree to_be_initialized = build (COMPONENT_REF, part_type, lhs, part);
- parts = tree_cons (TREE_PURPOSE (tail), to_be_initialized, parts);
- }
- return parts;
-}
-
/* Subroutine of expand_expr: return nonzero iff there is no way that
EXP can reference X, which is being modified. TOP_P is nonzero if this
call is going to be used to determine whether we need a temporary
return 1;
}
-/* Subroutine of expand_expr: return nonzero iff EXP is an
- expression whose type is statically determinable. */
-
-static int
-fixed_type_p (exp)
- tree exp;
-{
- if (TREE_CODE (exp) == PARM_DECL
- || TREE_CODE (exp) == VAR_DECL
- || TREE_CODE (exp) == CALL_EXPR || TREE_CODE (exp) == TARGET_EXPR
- || TREE_CODE (exp) == COMPONENT_REF
- || TREE_CODE (exp) == ARRAY_REF)
- return 1;
- return 0;
-}
-
/* Subroutine of expand_expr: return rtx if EXP is a
variable or parameter; else return 0. */
}
#endif
\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, abort. If PLIST is nonzero,
+ it is a location into which a pointer into the placeholder list at
+ which the object is found is placed. */
+
+tree
+find_placeholder (exp, plist)
+ tree exp;
+ tree *plist;
+{
+ tree type = TREE_TYPE (exp);
+ tree placeholder_expr;
+
+ for (placeholder_expr = placeholder_list; placeholder_expr != 0;
+ placeholder_expr = TREE_CHAIN (placeholder_expr))
+ {
+ tree need_type = TYPE_MAIN_VARIANT (type);
+ tree elt;
+
+ /* 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;
+ }
+
+ 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);
+ }
+ }
+
+ abort ();
+}
+\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.
case PLACEHOLDER_EXPR:
{
+ tree old_list = placeholder_list;
tree placeholder_expr;
- /* If there is an object on the head of the placeholder list,
- see if some object in it of type TYPE or a pointer to it. For
- further information, see tree.def. */
- for (placeholder_expr = placeholder_list;
- placeholder_expr != 0;
- placeholder_expr = TREE_CHAIN (placeholder_expr))
- {
- tree need_type = TYPE_MAIN_VARIANT (type);
- tree object = 0;
- tree old_list = placeholder_list;
- tree elt;
-
- /* 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 && object == 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)
- object = elt;
-
- for (elt = TREE_PURPOSE (placeholder_expr);
- elt != 0 && object == 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))
- object = build1 (INDIRECT_REF, need_type, elt);
-
- if (object != 0)
- {
- /* Expand this object skipping the list entries before
- it was found in case it is also a PLACEHOLDER_EXPR.
- In that case, we want to translate it using subsequent
- entries. */
- placeholder_list = TREE_CHAIN (placeholder_expr);
- temp = expand_expr (object, original_target, tmode,
- ro_modifier);
- placeholder_list = old_list;
- return temp;
- }
- }
+ exp = find_placeholder (exp, &placeholder_expr);
+ placeholder_list = TREE_CHAIN (placeholder_expr);
+ temp = expand_expr (exp, original_target, tmode, ro_modifier);
+ placeholder_list = old_list;
+ return temp;
}
/* We can't find the object or there was a missing WITH_RECORD_EXPR. */
tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
&mode1, &unsignedp, &volatilep,
&alignment);
+ rtx orig_op0;
/* If we got back the original object, something is wrong. Perhaps
we are evaluating an expression too early. In any event, don't
computation, since it will need a temporary and TARGET is known
to have to do. This occurs in unchecked conversion in Ada. */
- op0 = expand_expr (tem,
- (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
- && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
- != INTEGER_CST)
- ? target : NULL_RTX),
- VOIDmode,
- (modifier == EXPAND_INITIALIZER
- || modifier == EXPAND_CONST_ADDRESS)
- ? modifier : EXPAND_NORMAL);
+ orig_op0 = op0
+ = expand_expr (tem,
+ (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
+ && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
+ != INTEGER_CST)
+ ? target : NULL_RTX),
+ VOIDmode,
+ (modifier == EXPAND_INITIALIZER
+ || modifier == EXPAND_CONST_ADDRESS)
+ ? modifier : EXPAND_NORMAL);
/* If this is a constant, put it into a register if it is a
legitimate constant and OFFSET is 0 and memory if it isn't. */
/* Don't forget about volatility even if this is a bitfield. */
if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
{
- op0 = copy_rtx (op0);
+ if (op0 == orig_op0)
+ op0 = copy_rtx (op0);
+
MEM_VOLATILE_P (op0) = 1;
}
else
op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
+ if (op0 == orig_op0)
+ op0 = copy_rtx (op0);
+
set_mem_attributes (op0, exp, 0);
if (GET_CODE (XEXP (op0, 0)) == REG)
mark_reg_pointer (XEXP (op0, 0), alignment);
{
tree lhs = TREE_OPERAND (exp, 0);
tree rhs = TREE_OPERAND (exp, 1);
- tree noncopied_parts = 0;
- tree lhs_type = TREE_TYPE (lhs);
temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
- if (TYPE_NONCOPIED_PARTS (lhs_type) != 0 && !fixed_type_p (rhs))
- noncopied_parts
- = init_noncopied_parts (stabilize_reference (lhs),
- TYPE_NONCOPIED_PARTS (lhs_type));
-
- while (noncopied_parts != 0)
- {
- expand_assignment (TREE_VALUE (noncopied_parts),
- TREE_PURPOSE (noncopied_parts), 0, 0);
- noncopied_parts = TREE_CHAIN (noncopied_parts);
- }
return temp;
}
case MODIFY_EXPR:
{
/* If lhs is complex, expand calls in rhs before computing it.
- That's so we don't compute a pointer and save it over a call.
- If lhs is simple, compute it first so we can give it as a
- target if the rhs is just a call. This avoids an extra temp and copy
- and that prevents a partial-subsumption which makes bad code.
- Actually we could treat component_ref's of vars like vars. */
+ That's so we don't compute a pointer and save it over a
+ call. If lhs is simple, compute it first so we can give it
+ as a target if the rhs is just a call. This avoids an
+ extra temp and copy and that prevents a partial-subsumption
+ which makes bad code. Actually we could treat
+ component_ref's of vars like vars. */
tree lhs = TREE_OPERAND (exp, 0);
tree rhs = TREE_OPERAND (exp, 1);
- tree noncopied_parts = 0;
- tree lhs_type = TREE_TYPE (lhs);
temp = 0;
return const0_rtx;
}
- if (TYPE_NONCOPIED_PARTS (lhs_type) != 0
- && ! (fixed_type_p (lhs) && fixed_type_p (rhs)))
- noncopied_parts
- = save_noncopied_parts (stabilize_reference (lhs),
- TYPE_NONCOPIED_PARTS (lhs_type));
-
temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
- while (noncopied_parts != 0)
- {
- expand_assignment (TREE_PURPOSE (noncopied_parts),
- TREE_VALUE (noncopied_parts), 0, 0);
- noncopied_parts = TREE_CHAIN (noncopied_parts);
- }
+
return temp;
}
case EXC_PTR_EXPR:
return get_exception_pointer (cfun);
+ case FDESC_EXPR:
+ /* Function descriptors are not valid except for as
+ initialization constants, and should not be expanded. */
+ abort ();
+
default:
return (*lang_expand_expr) (exp, original_target, tmode, modifier);
}