alignment. */
#define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))
-/* NEED_SEPARATE_AP means that we cannot derive ap from the value of fp
- during rtl generation. If they are different register numbers, this is
- always true. It may also be true if
- FIRST_PARM_OFFSET - STARTING_FRAME_OFFSET is not a constant during rtl
- generation. See fix_lexical_addr for details. */
-
-#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
-#define NEED_SEPARATE_AP
-#endif
-
/* Nonzero if function being compiled doesn't contain any calls
(ignoring the prologue and epilogue). This is set prior to
local register allocation and is valid for the remaining
compiler passes. */
int current_function_is_leaf;
-/* Nonzero if function being compiled doesn't contain any instructions
- that can throw an exception. This is set prior to final. */
-
-int current_function_nothrow;
-
/* Nonzero if function being compiled doesn't modify the stack pointer
(ignoring the prologue and epilogue). This is only valid after
life_analysis has run. */
#ifdef HAVE_return
static void emit_return_into_block (basic_block, rtx);
#endif
-static void purge_single_hard_subreg_set (rtx);
#if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX)
static rtx keep_stack_depressed (rtx);
#endif
if (p->decl == decl)
return p;
- abort ();
+ gcc_unreachable ();
}
/* Save the current context for compilation of a nested function.
current_function_decl = p->decl;
reg_renumber = 0;
- restore_emit_status (p);
-
lang_hooks.function.leave_nested (p);
/* Reset variables that have known state during rtx generation. */
- rtx_equal_function_value_matters = 1;
virtuals_instantiated = 0;
generating_concat_p = 1;
}
/* f->eh->eh_return_stub_label is used by code generation. */
lang_hooks.function.final (f);
- f->stmt = NULL;
}
/* Clear out all parts of the state in F that can safely be discarded
{
rtx x, addr;
int bigend_correction = 0;
- int alignment;
+ unsigned int alignment;
int frame_off, frame_alignment, frame_phase;
if (align == 0)
use logical operations which are unambiguous. */
#ifdef FRAME_GROWS_DOWNWARD
function->x_frame_offset
- = (FLOOR_ROUND (function->x_frame_offset - frame_phase, alignment)
+ = (FLOOR_ROUND (function->x_frame_offset - frame_phase,
+ (unsigned HOST_WIDE_INT) alignment)
+ frame_phase);
#else
function->x_frame_offset
- = (CEIL_ROUND (function->x_frame_offset - frame_phase, alignment)
+ = (CEIL_ROUND (function->x_frame_offset - frame_phase,
+ (unsigned HOST_WIDE_INT) alignment)
+ frame_phase);
#endif
}
static struct temp_slot **
temp_slots_at_level (int level)
{
- level++;
if (!used_temp_slots)
VARRAY_GENERIC_PTR_INIT (used_temp_slots, 3, "used_temp_slots");
KEEP is 1 if this slot is to be retained after a call to
free_temp_slots. Automatic variables for a block are allocated
- with this flag. KEEP is 2 if we allocate a longer term temporary,
- whose lifetime is controlled by CLEANUP_POINT_EXPRs. KEEP is 3
- if we are to allocate something at an inner level to be treated as
- a variable in the block (e.g., a SAVE_EXPR).
+ with this flag. KEEP values of 2 or 3 were needed respectively
+ for variables whose lifetime is controlled by CLEANUP_POINT_EXPRs
+ or for SAVE_EXPRs, but they are now unused and will abort.
TYPE is the type that will be used for the stack slot. */
/* If SIZE is -1 it means that somebody tried to allocate a temporary
of a variable size. */
- if (size == -1)
- abort ();
+ gcc_assert (size != -1);
+
+ /* These are now unused. */
+ gcc_assert (keep <= 1);
if (mode == BLKmode)
align = BIGGEST_ALIGNMENT;
So for requests which depended on the rounding of SIZE, we go ahead
and round it now. We also make sure ALIGNMENT is at least
BIGGEST_ALIGNMENT. */
- if (mode == BLKmode && align < BIGGEST_ALIGNMENT)
- abort ();
+ gcc_assert (mode != BLKmode || align == BIGGEST_ALIGNMENT);
p->slot = assign_stack_local (mode,
(mode == BLKmode
? CEIL_ROUND (size, (int) align / BITS_PER_UNIT)
p->in_use = 1;
p->addr_taken = 0;
p->type = type;
-
- if (keep == 2)
- {
- p->level = target_temp_slot_level;
- p->keep = 1;
- }
- else if (keep == 3)
- {
- p->level = var_temp_slot_level;
- p->keep = 0;
- }
- else
- {
- p->level = temp_slot_level;
- p->keep = keep;
- }
+ p->level = temp_slot_level;
+ p->keep = keep;
pp = temp_slots_at_level (p->level);
insert_slot_to_list (p, pp);
/* If a type is specified, set the relevant flags. */
if (type != 0)
{
- RTX_UNCHANGING_P (slot) = (lang_hooks.honor_readonly
- && TYPE_READONLY (type));
MEM_VOLATILE_P (slot) = TYPE_VOLATILE (type);
MEM_SET_IN_STRUCT_P (slot, AGGREGATE_TYPE_P (type));
}
/* If we still haven't been able to get a size, see if the language
can compute a maximum size. */
if (size == -1
- && (size_tree = lang_hooks.type_max_size (type)) != 0
+ && (size_tree = lang_hooks.types.max_size (type)) != 0
&& host_integerp (size_tree, 1))
size = tree_low_cst (size_tree, 1);
if (decl && size == -1
&& TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST)
{
- error ("%Jsize of variable '%D' is too large", decl, decl);
+ error ("%Jsize of variable %qD is too large", decl, decl);
size = 1;
}
done for BLKmode slots because we can be sure that we won't have alignment
problems in this case. */
-void
+static void
combine_temp_slots (void)
{
struct temp_slot *p, *q, *next, *next_q;
avail_temp_slots = 0;
used_temp_slots = 0;
temp_slot_level = 0;
- var_temp_slot_level = 0;
- target_temp_slot_level = 0;
}
\f
/* These routines are responsible for converting virtual register references
#endif
\f
-/* Convert a SET of a hard subreg to a set of the appropriate hard
- register. A subroutine of purge_hard_subreg_sets. */
-
-static void
-purge_single_hard_subreg_set (rtx pattern)
-{
- rtx reg = SET_DEST (pattern);
- enum machine_mode mode = GET_MODE (SET_DEST (pattern));
- int offset = 0;
-
- if (GET_CODE (reg) == SUBREG && REG_P (SUBREG_REG (reg))
- && REGNO (SUBREG_REG (reg)) < FIRST_PSEUDO_REGISTER)
- {
- offset = subreg_regno_offset (REGNO (SUBREG_REG (reg)),
- GET_MODE (SUBREG_REG (reg)),
- SUBREG_BYTE (reg),
- GET_MODE (reg));
- reg = SUBREG_REG (reg);
- }
-
-
- if (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER)
- {
- reg = gen_rtx_REG (mode, REGNO (reg) + offset);
- SET_DEST (pattern) = reg;
- }
-}
-
-/* Eliminate all occurrences of SETs of hard subregs from INSNS. The
- only such SETs that we expect to see are those left in because
- integrate can't handle sets of parts of a return value register.
-
- We don't use alter_subreg because we only want to eliminate subregs
- of hard registers. */
-
-void
-purge_hard_subreg_sets (rtx insn)
-{
- for (; insn; insn = NEXT_INSN (insn))
- {
- if (INSN_P (insn))
- {
- rtx pattern = PATTERN (insn);
- switch (GET_CODE (pattern))
- {
- case SET:
- if (GET_CODE (SET_DEST (pattern)) == SUBREG)
- purge_single_hard_subreg_set (pattern);
- break;
- case PARALLEL:
- {
- int j;
- for (j = XVECLEN (pattern, 0) - 1; j >= 0; j--)
- {
- rtx inner_pattern = XVECEXP (pattern, 0, j);
- if (GET_CODE (inner_pattern) == SET
- && GET_CODE (SET_DEST (inner_pattern)) == SUBREG)
- purge_single_hard_subreg_set (inner_pattern);
- }
- }
- break;
- default:
- break;
- }
- }
- }
-}
-\f
/* Pass through the INSNS of function FNDECL and convert virtual register
references to hard register references. */
enum machine_mode mode;
rtx addr;
+ if (x == 0)
+ return;
+
+ /* If this is a CONCAT, recurse for the pieces. */
+ if (GET_CODE (x) == CONCAT)
+ {
+ instantiate_decl (XEXP (x, 0), size / 2, valid_only);
+ instantiate_decl (XEXP (x, 1), size / 2, valid_only);
+ return;
+ }
+
/* If this is not a MEM, no need to do anything. Similarly if the
address is a constant or a register that is not a virtual register. */
-
- if (x == 0 || !MEM_P (x))
+ if (!MEM_P (x))
return;
addr = XEXP (x, 0);
static void
instantiate_virtual_regs_lossage (rtx insn)
{
- if (asm_noperands (PATTERN (insn)) >= 0)
- {
- error_for_asm (insn, "impossible constraint in `asm'");
- delete_insn (insn);
- }
- else
- abort ();
+ gcc_assert (asm_noperands (PATTERN (insn)) >= 0);
+ error_for_asm (insn, "impossible constraint in %<asm%>");
+ delete_insn (insn);
}
/* Given a pointer to a piece of rtx and an optional pointer to the
containing object, instantiate any virtual registers present in it.
break;
default:
/* We don't expect other rtl types here. */
- abort();
+ gcc_unreachable ();
}
if (TREE_CODE (type) == VOID_TYPE)
return 0;
+ /* If the front end has decided that this needs to be passed by
+ reference, do so. */
+ if ((TREE_CODE (exp) == PARM_DECL || TREE_CODE (exp) == RESULT_DECL)
+ && DECL_BY_REFERENCE (exp))
+ return 1;
if (targetm.calls.return_in_memory (type, fntype))
return 1;
/* Types that are TREE_ADDRESSABLE must be constructed in memory,
return (optimize || DECL_REGISTER (decl));
}
+/* Return true if TYPE should be passed by invisible reference. */
+
+bool
+pass_by_reference (CUMULATIVE_ARGS *ca, enum machine_mode mode,
+ tree type, bool named_arg)
+{
+ if (type)
+ {
+ /* If this type contains non-trivial constructors, then it is
+ forbidden for the middle-end to create any new copies. */
+ if (TREE_ADDRESSABLE (type))
+ return true;
+
+ /* GCC post 3.4 passes *all* variable sized types by reference. */
+ if (!TYPE_SIZE (type) || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+ return true;
+ }
+
+ return targetm.calls.pass_by_reference (ca, mode, type, named_arg);
+}
+
+/* Return true if TYPE, which is passed by reference, should be callee
+ copied instead of caller copied. */
+
+bool
+reference_callee_copied (CUMULATIVE_ARGS *ca, enum machine_mode mode,
+ tree type, bool named_arg)
+{
+ if (type && TREE_ADDRESSABLE (type))
+ return false;
+ return targetm.calls.callee_copies (ca, mode, type, named_arg);
+}
+
/* Structures to communicate between the subroutines of assign_parms.
The first holds data persistent across all parameters, the second
is cleared out for each parameter. */
&& TYPE_TRANSPARENT_UNION (passed_type)))
passed_type = TREE_TYPE (TYPE_FIELDS (passed_type));
- /* See if this arg was passed by invisible reference. It is if it is an
- object whose size depends on the contents of the object itself or if
- the machine requires these objects be passed that way. */
- if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (passed_type))
- || TREE_ADDRESSABLE (passed_type)
- || FUNCTION_ARG_PASS_BY_REFERENCE (all->args_so_far, passed_mode,
- passed_type, data->named_arg))
+ /* See if this arg was passed by invisible reference. */
+ if (pass_by_reference (&all->args_so_far, passed_mode,
+ passed_type, data->named_arg))
{
passed_type = nominal_type = build_pointer_type (passed_type);
data->passed_pointer = true;
passed_mode = nominal_mode = Pmode;
}
- /* See if the frontend wants to pass this by invisible reference. */
- else if (passed_type != nominal_type
- && POINTER_TYPE_P (passed_type)
- && TREE_TYPE (passed_type) == nominal_type)
- {
- nominal_type = passed_type;
- data->passed_pointer = 1;
- passed_mode = nominal_mode = Pmode;
- }
/* Find mode as it is passed by the ABI. */
promoted_mode = passed_mode;
/* If this parameter was passed both in registers and in the stack, use
the copy on the stack. */
- if (MUST_PASS_IN_STACK (data->promoted_mode, data->passed_type))
+ if (targetm.calls.must_pass_in_stack (data->promoted_mode,
+ data->passed_type))
entry_parm = 0;
-#ifdef FUNCTION_ARG_PARTIAL_NREGS
if (entry_parm)
{
int partial;
/* We assume at most one partial arg, and it must be the first
argument on the stack. */
- if (all->extra_pretend_bytes || all->pretend_args_size)
- abort ();
+ gcc_assert (!all->extra_pretend_bytes && !all->pretend_args_size);
pretend_bytes = partial * UNITS_PER_WORD;
all->pretend_args_size = CEIL_ROUND (pretend_bytes, STACK_BYTES);
all->extra_pretend_bytes = all->pretend_args_size;
}
}
-#endif
locate_and_pad_parm (data->promoted_mode, data->passed_type, in_regs,
entry_parm ? data->partial : 0, current_function_decl,
assign_parm_is_stack_parm (struct assign_parm_data_all *all,
struct assign_parm_data_one *data)
{
- /* Trivially true if we've no incomming register. */
+ /* Trivially true if we've no incoming register. */
if (data->entry_parm == NULL)
;
/* Also true if we're partially in registers and partially not,
return true;
#ifdef BLOCK_REG_PADDING
- if (data->locate.where_pad == (BYTES_BIG_ENDIAN ? upward : downward)
- && GET_MODE_SIZE (data->promoted_mode) < UNITS_PER_WORD)
+ /* Only assign_parm_setup_block knows how to deal with register arguments
+ that are padded at the least significant end. */
+ if (REG_P (data->entry_parm)
+ && GET_MODE_SIZE (data->promoted_mode) < UNITS_PER_WORD
+ && (BLOCK_REG_PADDING (data->passed_mode, data->passed_type, 1)
+ == (BYTES_BIG_ENDIAN ? upward : downward)))
return true;
#endif
if (GET_CODE (entry_parm) == PARALLEL
&& data->nominal_mode != BLKmode
&& XVECLEN (entry_parm, 0) > 1
- && optimize)
+ && use_register_for_decl (parm))
{
rtx parmreg = gen_reg_rtx (data->nominal_mode);
- emit_group_store (parmreg, entry_parm, data->nominal_type,
- int_size_in_bytes (data->nominal_type));
+ /* For values returned in multiple registers, handle possible
+ incompatible calls to emit_group_store.
+
+ For example, the following would be invalid, and would have to
+ be fixed by the conditional below:
+
+ emit_group_store ((reg:SF), (parallel:DF))
+ emit_group_store ((reg:SI), (parallel:DI))
+
+ An example of this are doubles in e500 v2:
+ (parallel:DF (expr_list (reg:SI) (const_int 0))
+ (expr_list (reg:SI) (const_int 4))). */
+ if (data->nominal_mode != data->passed_mode)
+ {
+ rtx t = gen_reg_rtx (GET_MODE (entry_parm));
+ emit_group_store (t, entry_parm, NULL_TREE,
+ GET_MODE_SIZE (GET_MODE (entry_parm)));
+ convert_move (parmreg, t, 0);
+ }
+ else
+ emit_group_store (parmreg, entry_parm, data->nominal_type,
+ int_size_in_bytes (data->nominal_type));
SET_DECL_RTL (parm, parmreg);
return;
}
}
else if (GET_CODE (entry_parm) == PARALLEL)
;
- else if (size != 0 && PARM_BOUNDARY % BITS_PER_WORD != 0)
- abort ();
+ else
+ gcc_assert (!size || !(PARM_BOUNDARY % BITS_PER_WORD));
mem = validize_mem (stack_parm);
int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
rtx reg = gen_rtx_REG (word_mode, REGNO (data->entry_parm));
- x = expand_binop (word_mode, ashl_optab, reg,
- GEN_INT (by), 0, 1, OPTAB_WIDEN);
+ x = expand_shift (LSHIFT_EXPR, word_mode, reg,
+ build_int_cst (NULL_TREE, by),
+ NULL_RTX, 1);
tem = change_address (mem, word_mode, 0);
emit_move_insn (tem, x);
}
SET_DECL_RTL (parm, x);
}
else
- {
- SET_DECL_RTL (parm, parmreg);
- maybe_set_unchanging (DECL_RTL (parm), parm);
- }
+ SET_DECL_RTL (parm, parmreg);
/* Copy the value into the register. */
if (data->nominal_mode != data->passed_mode
/* TREE_USED gets set erroneously during expand_assignment. */
save_tree_used = TREE_USED (parm);
- expand_assignment (parm, make_tree (data->nominal_type, tempreg), 0);
+ expand_assignment (parm, make_tree (data->nominal_type, tempreg));
TREE_USED (parm) = save_tree_used;
all->conversion_insns = get_insns ();
end_sequence ();
data->stack_parm = NULL;
}
-#ifdef FUNCTION_ARG_CALLEE_COPIES
/* If we are passed an arg by reference and it is our responsibility
to make a copy, do it now.
PASSED_TYPE and PASSED mode now refer to the pointer, not the
/* ??? Later add code to handle the case that if the argument isn't
modified, don't do the copy. */
- else if (data->passed_pointer
- && FUNCTION_ARG_CALLEE_COPIES (all->args_so_far,
- TYPE_MODE (TREE_TYPE (passed_type)),
- TREE_TYPE (passed_type),
- data->named_arg)
- && ! TREE_ADDRESSABLE (TREE_TYPE (passed_type)))
+ else if (data->passed_pointer)
{
- rtx copy;
- tree type = TREE_TYPE (passed_type);
+ tree type = TREE_TYPE (data->passed_type);
+
+ if (reference_callee_copied (&all->args_so_far, TYPE_MODE (type),
+ type, data->named_arg))
+ {
+ rtx copy;
- /* This sequence may involve a library call perhaps clobbering
- registers that haven't been copied to pseudos yet. */
+ /* This sequence may involve a library call perhaps clobbering
+ registers that haven't been copied to pseudos yet. */
- push_to_sequence (all->conversion_insns);
+ push_to_sequence (all->conversion_insns);
- if (!COMPLETE_TYPE_P (type)
- || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
- {
- /* This is a variable sized object. */
- copy = allocate_dynamic_stack_space (expr_size (parm), NULL_RTX,
- TYPE_ALIGN (type));
- copy = gen_rtx_MEM (BLKmode, copy);
- }
- else
- copy = assign_stack_temp (TYPE_MODE (type),
- int_size_in_bytes (type), 1);
- set_mem_attributes (copy, parm, 1);
+ if (!COMPLETE_TYPE_P (type)
+ || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+ {
+ /* This is a variable sized object. */
+ copy = allocate_dynamic_stack_space (expr_size (parm), NULL_RTX,
+ TYPE_ALIGN (type));
+ copy = gen_rtx_MEM (BLKmode, copy);
+ }
+ else
+ copy = assign_stack_temp (TYPE_MODE (type),
+ int_size_in_bytes (type), 1);
+ set_mem_attributes (copy, parm, 1);
- store_expr (parm, copy, 0);
- emit_move_insn (parmreg, XEXP (copy, 0));
- all->conversion_insns = get_insns ();
- end_sequence ();
+ store_expr (parm, copy, 0);
+ emit_move_insn (parmreg, XEXP (copy, 0));
+ all->conversion_insns = get_insns ();
+ end_sequence ();
- did_conversion = true;
+ did_conversion = true;
+ }
}
-#endif /* FUNCTION_ARG_CALLEE_COPIES */
/* Mark the register as eliminable if we did no conversion and it was
copied from memory at a fixed offset, and the arg pointer was not
/* Assign RTL expressions to the function's parameters. This may involve
copying them into registers and using those registers as the DECL_RTL. */
-void
+static void
assign_parms (tree fndecl)
{
struct assign_parm_data_all all;
rtx addr = DECL_RTL (all.function_result_decl);
rtx x;
- addr = convert_memory_address (Pmode, addr);
- x = gen_rtx_MEM (DECL_MODE (result), addr);
- set_mem_attributes (x, result, 1);
+ if (DECL_BY_REFERENCE (result))
+ x = addr;
+ else
+ {
+ addr = convert_memory_address (Pmode, addr);
+ x = gen_rtx_MEM (DECL_MODE (result), addr);
+ set_mem_attributes (x, result, 1);
+ }
SET_DECL_RTL (result, x);
}
#ifdef ARGS_GROW_DOWNWARD
current_function_arg_offset_rtx
- = (stack_args_size.var == 0 ? GEN_INT (-all.stack_args_size.constant)
+ = (all.stack_args_size.var == 0 ? GEN_INT (-all.stack_args_size.constant)
: expand_expr (size_diffop (all.stack_args_size.var,
size_int (-all.stack_args_size.constant)),
NULL_RTX, VOIDmode, 0));
&& DECL_RTL_SET_P (decl)
&& REG_P (DECL_RTL (decl))
&& regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
- warning ("%Jvariable '%D' might be clobbered by `longjmp' or `vfork'",
+ warning ("%Jvariable %qD might be clobbered by %<longjmp%>"
+ " or %<vfork%>",
decl, decl);
}
if (DECL_RTL (decl) != 0
&& REG_P (DECL_RTL (decl))
&& regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
- warning ("%Jargument '%D' might be clobbered by `longjmp' or `vfork'",
+ warning ("%Jargument %qD might be clobbered by %<longjmp%> or %<vfork%>",
decl, decl);
}
\f
-/* Convert a stack slot address ADDR for variable VAR
- (from a containing function)
- into an address valid in this function (using a static chain). */
-
-rtx
-fix_lexical_addr (rtx addr, tree var)
-{
- rtx basereg;
- HOST_WIDE_INT displacement;
- tree context = decl_function_context (var);
- struct function *fp;
- rtx base = 0;
-
- /* If this is the present function, we need not do anything. */
- if (context == current_function_decl)
- return addr;
-
- fp = find_function_data (context);
-
- /* Decode given address as base reg plus displacement. */
- if (REG_P (addr))
- basereg = addr, displacement = 0;
- else if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 1)) == CONST_INT)
- basereg = XEXP (addr, 0), displacement = INTVAL (XEXP (addr, 1));
- else
- abort ();
-
- if (base == 0)
- abort ();
-
- /* Use same offset, relative to appropriate static chain or argument
- pointer. */
- return plus_constant (base, displacement);
-}
-\f
/* Identify BLOCKs referenced by more than one NOTE_INSN_BLOCK_{BEG,END},
and create duplicate blocks. */
/* ??? Need an option to either create block fragments or to create
for (insn = insns; insn; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == NOTE)
+ if (NOTE_P (insn))
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
{
cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
- init_stmt_for_function ();
init_eh_for_function ();
lang_hooks.function.init (cfun);
/* We haven't done register allocation yet. */
reg_renumber = 0;
- /* Indicate that we need to distinguish between the return value of the
- present function and the return value of a function being called. */
- rtx_equal_function_value_matters = 1;
-
/* Indicate that we have not instantiated virtual registers yet. */
virtuals_instantiated = 0;
for the current function. The PENDING_SIZES are a TREE_LIST. The
TREE_VALUE of each node is a SAVE_EXPR. */
-void
+static void
expand_pending_sizes (tree pending_sizes)
{
tree tem;
/* Evaluate now the sizes of any types declared among the arguments. */
for (tem = pending_sizes; tem; tem = TREE_CHAIN (tem))
- {
- expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0);
- /* Flush the queue in case this parameter declaration has
- side-effects. */
- emit_queue ();
- }
+ expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0);
}
/* Start the RTL for a new function, and set variables used for
}
if (value_address)
{
- rtx x = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
- set_mem_attributes (x, DECL_RESULT (subr), 1);
+ rtx x = value_address;
+ if (!DECL_BY_REFERENCE (DECL_RESULT (subr)))
+ {
+ x = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), x);
+ set_mem_attributes (x, DECL_RESULT (subr), 1);
+ }
SET_DECL_RTL (DECL_RESULT (subr), x);
}
}
so we may see a PARALLEL or a REG. */
if (REG_P (hard_reg))
SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
- else if (GET_CODE (hard_reg) == PARALLEL)
- SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
else
- abort ();
+ {
+ gcc_assert (GET_CODE (hard_reg) == PARALLEL);
+ SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
+ }
/* Set DECL_REGISTER flag so that expand_function_end will copy the
result to the real return register(s). */
set_decl_incoming_rtl (parm, static_chain_incoming_rtx);
SET_DECL_RTL (parm, local);
- maybe_set_unchanging (local, parm);
mark_reg_pointer (local, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm))));
emit_move_insn (local, static_chain_incoming_rtx);
before the frame variable gets declared. Help out... */
expand_var (TREE_OPERAND (cfun->nonlocal_goto_save_area, 0));
- t_save = build (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area,
- integer_zero_node, NULL_TREE, NULL_TREE);
+ t_save = build4 (ARRAY_REF, ptr_type_node,
+ cfun->nonlocal_goto_save_area,
+ integer_zero_node, NULL_TREE, NULL_TREE);
r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ r_save = convert_memory_address (Pmode, r_save);
emit_move_insn (r_save, virtual_stack_vars_rtx);
update_nonlocal_goto_save_area ();
as opposed to parm setup. */
emit_note (NOTE_INSN_FUNCTION_BEG);
- if (GET_CODE (get_last_insn ()) != NOTE)
+ if (!NOTE_P (get_last_insn ()))
emit_note (NOTE_INSN_DELETED);
parm_birth_insn = get_last_insn ();
decl; decl = TREE_CHAIN (decl))
if (!TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
&& DECL_NAME (decl) && !DECL_ARTIFICIAL (decl))
- warning ("%Junused parameter '%D'", decl, decl);
+ warning ("%Junused parameter %qD", decl, decl);
}
static GTY(()) rtx initial_trampoline;
{
rtx clobber_after;
- finish_expr_for_function ();
-
/* If arg_pointer_save_area was referenced only from a nested
function, we will not have initialized it yet. Do that now. */
if (arg_pointer_save_area && ! cfun->arg_pointer_save_area_init)
rtx insn, seq;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
start_sequence ();
probe_stack_range (STACK_CHECK_PROTECT,
is computed. */
clobber_after = get_last_insn ();
- /* Output the label for the actual return from the function,
- if one is expected. This happens either because a function epilogue
- is used instead of a return instruction, or because a return was done
- with a goto in order to run local cleanups, or because of pcc-style
- structure returning. */
- if (return_label)
- emit_label (return_label);
+ /* Output the label for the actual return from the function. */
+ emit_label (return_label);
/* Let except.c know where it should emit the call to unregister
the function context for sjlj exceptions. */
rtx real_decl_rtl = current_function_return_rtx;
/* This should be set in assign_parms. */
- if (! REG_FUNCTION_VALUE_P (real_decl_rtl))
- abort ();
+ gcc_assert (REG_FUNCTION_VALUE_P (real_decl_rtl));
/* If this is a BLKmode structure being returned in registers,
then use the mode computed in expand_return. Note that if
if (current_function_returns_struct
|| current_function_returns_pcc_struct)
{
- rtx value_address
- = XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
+ rtx value_address = DECL_RTL (DECL_RESULT (current_function_decl));
tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
+ rtx outgoing;
+
+ if (DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
+ type = TREE_TYPE (type);
+ else
+ value_address = XEXP (value_address, 0);
+
#ifdef FUNCTION_OUTGOING_VALUE
- rtx outgoing
- = FUNCTION_OUTGOING_VALUE (build_pointer_type (type),
- current_function_decl);
+ outgoing = FUNCTION_OUTGOING_VALUE (build_pointer_type (type),
+ current_function_decl);
#else
- rtx outgoing
- = FUNCTION_VALUE (build_pointer_type (type), current_function_decl);
-#endif
+ outgoing = FUNCTION_VALUE (build_pointer_type (type),
+ current_function_decl);
+#endif
/* Mark this as a function return value so integrate will delete the
assignment and USE below when inlining this function. */
/* Emit the actual code to clobber return register. */
{
- rtx seq, after;
+ rtx seq;
start_sequence ();
clobber_return_register ();
+ expand_naked_return ();
seq = get_insns ();
end_sequence ();
- after = emit_insn_after (seq, clobber_after);
+ emit_insn_after (seq, clobber_after);
}
- /* Output the label for the naked return from the function, if one is
- expected. This is currently used only by __builtin_return. */
- if (naked_return_label)
- emit_label (naked_return_label);
+ /* Output the label for the naked return from the function. */
+ emit_label (naked_return_label);
/* ??? This should no longer be necessary since stupid is no longer with
us, but there are some parts of the compiler (eg reload_combine, and
sh mach_dep_reorg) that still try and compute their own lifetime info
instead of using the general framework. */
use_return_register ();
-
- /* Fix up any gotos that jumped out to the outermost
- binding level of the function.
- Must follow emitting RETURN_LABEL. */
-
- /* If you have any cleanups to do at this point,
- and they need to create temporary variables,
- then you will lose. */
- expand_fixups (get_insns ());
}
rtx
{
int i, j;
- if (GET_CODE (insn) == INSN
+ if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
{
int count = 0;
insn = next;
continue;
}
- else if (MEM_P (retaddr)
- && REG_P (XEXP (retaddr, 0)))
- base = gen_rtx_REG (Pmode, REGNO (XEXP (retaddr, 0))), offset = 0;
- else if (MEM_P (retaddr)
- && GET_CODE (XEXP (retaddr, 0)) == PLUS
- && REG_P (XEXP (XEXP (retaddr, 0), 0))
- && GET_CODE (XEXP (XEXP (retaddr, 0), 1)) == CONST_INT)
+ else
{
- base = gen_rtx_REG (Pmode, REGNO (XEXP (XEXP (retaddr, 0), 0)));
- offset = INTVAL (XEXP (XEXP (retaddr, 0), 1));
+ rtx ret_ptr;
+ gcc_assert (MEM_P (retaddr));
+
+ ret_ptr = XEXP (retaddr, 0);
+
+ if (REG_P (ret_ptr))
+ {
+ base = gen_rtx_REG (Pmode, REGNO (ret_ptr));
+ offset = 0;
+ }
+ else
+ {
+ gcc_assert (GET_CODE (ret_ptr) == PLUS
+ && REG_P (XEXP (ret_ptr, 0))
+ && GET_CODE (XEXP (ret_ptr, 1)) == CONST_INT);
+ base = gen_rtx_REG (Pmode, REGNO (XEXP (ret_ptr, 0)));
+ offset = INTVAL (XEXP (ret_ptr, 1));
+ }
}
- else
- abort ();
/* If the base of the location containing the return pointer
is SP, we must update it with the replacement address. Otherwise,
&& info.const_equiv[regno] == 0)
break;
- if (regno == FIRST_PSEUDO_REGISTER)
- abort ();
+ gcc_assert (regno < FIRST_PSEUDO_REGISTER);
reg = gen_rtx_REG (Pmode, regno);
emit_move_insn (reg, retaddr);
/* Show the SET in the above insn is a RETURN. */
jump_set = single_set (jump_insn);
- if (jump_set == 0)
- abort ();
- else
- SET_IS_RETURN_P (jump_set) = 1;
+ gcc_assert (jump_set);
+ SET_IS_RETURN_P (jump_set) = 1;
}
/* If SP is not mentioned in the pattern and its equivalent register, if
&& (info.sp_equiv_reg == stack_pointer_rtx
|| !reg_set_p (info.sp_equiv_reg, insn)))
{
- if (! validate_replace_rtx (stack_pointer_rtx,
- plus_constant (info.sp_equiv_reg,
- info.sp_offset),
- insn))
- abort ();
+ int changed;
+
+ changed = validate_replace_rtx (stack_pointer_rtx,
+ plus_constant (info.sp_equiv_reg,
+ info.sp_offset),
+ insn);
+ gcc_assert (changed);
add_insn (insn);
}
set from. If unknown, abort. */
if (reg_set_p (stack_pointer_rtx, set))
{
- if (SET_DEST (set) != stack_pointer_rtx)
- abort ();
+ gcc_assert (SET_DEST (set) == stack_pointer_rtx);
if (GET_CODE (SET_SRC (set)) == PLUS)
{
p->new_sp_equiv_reg = XEXP (SET_SRC (set), 0);
if (GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
p->new_sp_offset = INTVAL (XEXP (SET_SRC (set), 1));
- else if (REG_P (XEXP (SET_SRC (set), 1))
- && REGNO (XEXP (SET_SRC (set), 1)) < FIRST_PSEUDO_REGISTER
- && p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))] != 0)
- p->new_sp_offset
- = INTVAL (p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]);
else
- abort ();
+ {
+ gcc_assert (REG_P (XEXP (SET_SRC (set), 1))
+ && (REGNO (XEXP (SET_SRC (set), 1))
+ < FIRST_PSEUDO_REGISTER)
+ && p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]);
+ p->new_sp_offset
+ = INTVAL (p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]);
+ }
}
else
p->new_sp_equiv_reg = SET_SRC (set), p->new_sp_offset = 0;
p->new_sp_offset += p->sp_offset;
}
- if (p->new_sp_equiv_reg == 0 || !REG_P (p->new_sp_equiv_reg))
- abort ();
+ gcc_assert (p->new_sp_equiv_reg && REG_P (p->new_sp_equiv_reg));
return;
}
Pmode). */
else if (p->new_sp_equiv_reg != 0 && reg_set_p (p->new_sp_equiv_reg, set))
{
- if (p->equiv_reg_src != 0
- || !REG_P (p->new_sp_equiv_reg)
- || !REG_P (SET_DEST (set))
- || GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) > BITS_PER_WORD
- || REGNO (p->new_sp_equiv_reg) != REGNO (SET_DEST (set)))
- abort ();
- else
- p->equiv_reg_src
- = simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx,
- plus_constant (p->sp_equiv_reg,
- p->sp_offset));
+ gcc_assert (!p->equiv_reg_src
+ && REG_P (p->new_sp_equiv_reg)
+ && REG_P (SET_DEST (set))
+ && (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set)))
+ <= BITS_PER_WORD)
+ && REGNO (p->new_sp_equiv_reg) == REGNO (SET_DEST (set)));
+ p->equiv_reg_src
+ = simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx,
+ plus_constant (p->sp_equiv_reg,
+ p->sp_offset));
}
/* Otherwise, replace any references to SP in the insn to its new value
#if defined (HAVE_epilogue) || defined(HAVE_return)
rtx epilogue_end = NULL_RTX;
#endif
+ edge_iterator ei;
#ifdef HAVE_prologue
if (HAVE_prologue)
/* Can't deal with multiple successors of the entry block
at the moment. Function should always have at least one
entry point. */
- if (!ENTRY_BLOCK_PTR->succ || ENTRY_BLOCK_PTR->succ->succ_next)
- abort ();
+ gcc_assert (EDGE_COUNT (ENTRY_BLOCK_PTR->succs) == 1);
- insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ);
+ insert_insn_on_edge (seq, EDGE_SUCC (ENTRY_BLOCK_PTR, 0));
inserted = 1;
}
#endif
/* If the exit block has no non-fake predecessors, we don't need
an epilogue. */
- for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
if ((e->flags & EDGE_FAKE) == 0)
break;
if (e == NULL)
emit (conditional) return instructions. */
basic_block last;
- edge e_next;
rtx label;
- for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
if (e->flags & EDGE_FALLTHRU)
break;
if (e == NULL)
/* Verify that there are no active instructions in the last block. */
label = BB_END (last);
- while (label && GET_CODE (label) != CODE_LABEL)
+ while (label && !LABEL_P (label))
{
if (active_insn_p (label))
break;
label = PREV_INSN (label);
}
- if (BB_HEAD (last) == label && GET_CODE (label) == CODE_LABEL)
+ if (BB_HEAD (last) == label && LABEL_P (label))
{
+ edge_iterator ei2;
rtx epilogue_line_note = NULL_RTX;
/* Locate the line number associated with the closing brace,
for (seq = get_last_insn ();
seq && ! active_insn_p (seq);
seq = PREV_INSN (seq))
- if (GET_CODE (seq) == NOTE && NOTE_LINE_NUMBER (seq) > 0)
+ if (NOTE_P (seq) && NOTE_LINE_NUMBER (seq) > 0)
{
epilogue_line_note = seq;
break;
}
- for (e = last->pred; e; e = e_next)
+ for (ei2 = ei_start (last->preds); (e = ei_safe_edge (ei2)); )
{
basic_block bb = e->src;
rtx jump;
- e_next = e->pred_next;
if (bb == ENTRY_BLOCK_PTR)
- continue;
+ {
+ ei_next (&ei2);
+ continue;
+ }
jump = BB_END (bb);
- if ((GET_CODE (jump) != JUMP_INSN) || JUMP_LABEL (jump) != label)
- continue;
+ if (!JUMP_P (jump) || JUMP_LABEL (jump) != label)
+ {
+ ei_next (&ei2);
+ continue;
+ }
/* If we have an unconditional jump, we can replace that
with a simple return instruction. */
else if (condjump_p (jump))
{
if (! redirect_jump (jump, 0, 0))
- continue;
+ {
+ ei_next (&ei2);
+ continue;
+ }
/* If this block has only one successor, it both jumps
and falls through to the fallthru block, so we can't
delete the edge. */
- if (bb->succ->succ_next == NULL)
- continue;
+ if (EDGE_COUNT (bb->succs) == 1)
+ {
+ ei_next (&ei2);
+ continue;
+ }
}
else
- continue;
+ {
+ ei_next (&ei2);
+ continue;
+ }
/* Fix up the CFG for the successful change we just made. */
redirect_edge_succ (e, EXIT_BLOCK_PTR);
emit_barrier_after (BB_END (last));
emit_return_into_block (last, epilogue_line_note);
epilogue_end = BB_END (last);
- last->succ->flags &= ~EDGE_FALLTHRU;
+ EDGE_SUCC (last, 0)->flags &= ~EDGE_FALLTHRU;
goto epilogue_done;
}
}
There really shouldn't be a mixture -- either all should have
been converted or none, however... */
- for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
if (e->flags & EDGE_FALLTHRU)
break;
if (e == NULL)
use return. Inserting a jump 'by hand' is extremely messy, so
we take advantage of cfg_layout_finalize using
fixup_fallthru_exit_predecessor. */
- cfg_layout_initialize ();
+ cfg_layout_initialize (0);
FOR_EACH_BB (cur_bb)
if (cur_bb->index >= 0 && cur_bb->next_bb->index >= 0)
cur_bb->rbi->next = cur_bb->next_bb;
#ifdef HAVE_sibcall_epilogue
/* Emit sibling epilogues before any sibling call sites. */
- for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+ for (ei = ei_start (EXIT_BLOCK_PTR->preds); (e = ei_safe_edge (ei)); )
{
basic_block bb = e->src;
rtx insn = BB_END (bb);
rtx i;
rtx newinsn;
- if (GET_CODE (insn) != CALL_INSN
+ if (!CALL_P (insn)
|| ! SIBLING_CALL_P (insn))
- continue;
+ {
+ ei_next (&ei);
+ continue;
+ }
start_sequence ();
emit_insn (gen_sibcall_epilogue ());
i = PREV_INSN (insn);
newinsn = emit_insn_before (seq, insn);
+ ei_next (&ei);
}
#endif
for (insn = prologue_end; insn; insn = prev)
{
prev = PREV_INSN (insn);
- if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+ if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0)
{
/* Note that we cannot reorder the first insn in the
chain, since rest_of_compilation relies on that
for (insn = BB_END (ENTRY_BLOCK_PTR->next_bb);
insn != prologue_end && insn;
insn = PREV_INSN (insn))
- if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+ if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0)
break;
/* If we didn't find one, make a copy of the first line number
for (insn = next_active_insn (prologue_end);
insn;
insn = PREV_INSN (insn))
- if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+ if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0)
{
emit_note_copy_after (insn, prologue_end);
break;
for (insn = epilogue_end; insn; insn = next)
{
next = NEXT_INSN (insn);
- if (GET_CODE (insn) == NOTE
+ if (NOTE_P (insn)
&& (NOTE_LINE_NUMBER (insn) > 0
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END))
reorg has run. */
for (insn = f; insn; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == NOTE)
+ if (NOTE_P (insn))
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
note = insn;
if (note == 0)
{
for (note = last; (note = NEXT_INSN (note));)
- if (GET_CODE (note) == NOTE
+ if (NOTE_P (note)
&& NOTE_LINE_NUMBER (note) == NOTE_INSN_PROLOGUE_END)
break;
}
/* Avoid placing note between CODE_LABEL and BASIC_BLOCK note. */
- if (GET_CODE (last) == CODE_LABEL)
+ if (LABEL_P (last))
last = NEXT_INSN (last);
reorder_insns (note, note, last);
}
reorg has run. */
for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
{
- if (GET_CODE (insn) == NOTE)
+ if (NOTE_P (insn))
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
note = insn;
if (note == 0)
{
for (note = insn; (note = PREV_INSN (note));)
- if (GET_CODE (note) == NOTE
+ if (NOTE_P (note)
&& NOTE_LINE_NUMBER (note) == NOTE_INSN_EPILOGUE_BEG)
break;
}