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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* This file handles the generation of rtl code from tree structure
int current_function_varargs;
+/* Nonzero if current function uses stdarg.h or equivalent.
+ Zero for functions that use varargs.h. */
+
+int current_function_stdarg;
+
/* Quantities of various kinds of registers
used for the current function's args. */
int level;
/* Non-zero if this should survive a call to free_temp_slots. */
int keep;
+ /* The offset of the slot from the frame_pointer, including extra space
+ for alignment. This info is for combine_temp_slots. */
+ int base_offset;
+ /* The size of the slot, including extra space for alignment. This
+ info is for combine_temp_slots. */
+ int full_size;
};
/* List of all temporaries allocated, both available and in use. */
static struct temp_slot *find_temp_slot_from_address PROTO((rtx));
static void put_reg_into_stack PROTO((struct function *, rtx, tree,
- enum machine_mode, enum machine_mode));
+ enum machine_mode, enum machine_mode,
+ int));
static void fixup_var_refs PROTO((rtx, enum machine_mode, int));
static struct fixup_replacement
*find_fixup_replacement PROTO((struct fixup_replacement **, rtx));
p->pretend_args_size = current_function_pretend_args_size;
p->arg_offset_rtx = current_function_arg_offset_rtx;
p->varargs = current_function_varargs;
+ p->stdarg = current_function_stdarg;
p->uses_const_pool = current_function_uses_const_pool;
p->uses_pic_offset_table = current_function_uses_pic_offset_table;
p->internal_arg_pointer = current_function_internal_arg_pointer;
current_function_pretend_args_size = p->pretend_args_size;
current_function_arg_offset_rtx = p->arg_offset_rtx;
current_function_varargs = p->varargs;
+ current_function_stdarg = p->stdarg;
current_function_uses_const_pool = p->uses_const_pool;
current_function_uses_pic_offset_table = p->uses_pic_offset_table;
current_function_internal_arg_pointer = p->internal_arg_pointer;
p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));
p->in_use = p->addr_taken = 0;
p->size = best_p->size - rounded_size;
+ p->base_offset = best_p->base_offset + rounded_size;
+ p->full_size = best_p->full_size - rounded_size;
p->slot = gen_rtx (MEM, BLKmode,
plus_constant (XEXP (best_p->slot, 0),
rounded_size));
stack_slot_list);
best_p->size = rounded_size;
+ best_p->full_size = rounded_size;
}
}
/* The following slot size computation is necessary because we don't
know the actual size of the temporary slot until assign_stack_local
has performed all the frame alignment and size rounding for the
- requested temporary. Otherwise combine_temp_slots won't think that
- adjacent slots really are adjacent. */
+ requested temporary. Note that extra space added for alignment
+ can be either above or below this stack slot depending on which
+ way the frame grows. We include the extra space if and only if it
+ is above this slot. */
#ifdef FRAME_GROWS_DOWNWARD
p->size = frame_offset_old - frame_offset;
#else
- p->size = frame_offset - frame_offset_old;
+ p->size = size;
+#endif
+ /* Now define the fields used by combine_temp_slots. */
+#ifdef FRAME_GROWS_DOWNWARD
+ p->base_offset = frame_offset;
+ p->full_size = frame_offset_old - frame_offset;
+#else
+ p->base_offset = frame_offset_old;
+ p->full_size = frame_offset - frame_offset_old;
#endif
p->address = 0;
p->next = temp_slots;
int delete_q = 0;
if (! q->in_use && GET_MODE (q->slot) == BLKmode)
{
- if (rtx_equal_p (plus_constant (XEXP (p->slot, 0), p->size),
- XEXP (q->slot, 0)))
+ if (p->base_offset + p->full_size == q->base_offset)
{
/* Q comes after P; combine Q into P. */
p->size += q->size;
+ p->full_size += q->full_size;
delete_q = 1;
}
- else if (rtx_equal_p (plus_constant (XEXP (q->slot, 0), q->size),
- XEXP (p->slot, 0)))
+ else if (q->base_offset + q->full_size == p->base_offset)
{
/* P comes after Q; combine P into Q. */
q->size += p->size;
+ q->full_size += p->full_size;
delete_p = 1;
break;
}
temp_slot_level--;
}
+
+/* Initialize temporary slots. */
+
+void
+init_temp_slots ()
+{
+ /* We have not allocated any temporaries yet. */
+ temp_slots = 0;
+ temp_slot_level = 0;
+ target_temp_slot_level = 0;
+}
\f
/* Retroactively move an auto variable from a register to a stack slot.
This is done when an address-reference to the variable is seen. */
if (GET_CODE (reg) == REG)
put_reg_into_stack (function, reg, TREE_TYPE (decl),
- promoted_mode, decl_mode);
+ promoted_mode, decl_mode, TREE_SIDE_EFFECTS (decl));
else if (GET_CODE (reg) == CONCAT)
{
/* A CONCAT contains two pseudos; put them both in the stack.
We do it so they end up consecutive. */
enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));
tree part_type = TREE_TYPE (TREE_TYPE (decl));
-#ifdef STACK_GROWS_DOWNWARD
+#ifdef FRAME_GROWS_DOWNWARD
/* Since part 0 should have a lower address, do it second. */
- put_reg_into_stack (function, XEXP (reg, 1),
- part_type, part_mode, part_mode);
- put_reg_into_stack (function, XEXP (reg, 0),
- part_type, part_mode, part_mode);
+ put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
+ part_mode, TREE_SIDE_EFFECTS (decl));
+ put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
+ part_mode, TREE_SIDE_EFFECTS (decl));
#else
- put_reg_into_stack (function, XEXP (reg, 0),
- part_type, part_mode, part_mode);
- put_reg_into_stack (function, XEXP (reg, 1),
- part_type, part_mode, part_mode);
+ put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
+ part_mode, TREE_SIDE_EFFECTS (decl));
+ put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
+ part_mode, TREE_SIDE_EFFECTS (decl));
#endif
/* Change the CONCAT into a combined MEM for both parts. */
PUT_CODE (reg, MEM);
+ MEM_VOLATILE_P (reg) = MEM_VOLATILE_P (XEXP (reg, 0));
+
/* The two parts are in memory order already.
Use the lower parts address as ours. */
XEXP (reg, 0) = XEXP (XEXP (reg, 0), 0);
/* Subroutine of put_var_into_stack. This puts a single pseudo reg REG
into the stack frame of FUNCTION (0 means the current function).
DECL_MODE is the machine mode of the user-level data type.
- PROMOTED_MODE is the machine mode of the register. */
+ PROMOTED_MODE is the machine mode of the register.
+ VOLATILE_P is nonzero if this is for a "volatile" decl. */
static void
-put_reg_into_stack (function, reg, type, promoted_mode, decl_mode)
+put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p)
struct function *function;
rtx reg;
tree type;
enum machine_mode promoted_mode, decl_mode;
+ int volatile_p;
{
rtx new = 0;
new = assign_stack_local (decl_mode, GET_MODE_SIZE (decl_mode), 0);
}
+ PUT_MODE (reg, decl_mode);
XEXP (reg, 0) = XEXP (new, 0);
/* `volatil' bit means one thing for MEMs, another entirely for REGs. */
- REG_USERVAR_P (reg) = 0;
+ MEM_VOLATILE_P (reg) = volatile_p;
PUT_CODE (reg, MEM);
- PUT_MODE (reg, decl_mode);
/* If this is a memory ref that contains aggregate components,
mark it as such for cse and loop optimize. */
If it has a REG_LIBCALL note, delete the REG_LIBCALL
and REG_RETVAL notes too. */
- if (GET_CODE (PATTERN (insn)) == CLOBBER
+ if (GET_CODE (PATTERN (insn)) == CLOBBER
&& XEXP (PATTERN (insn), 0) == var)
{
if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0)
&& (GET_CODE (SET_DEST (x)) == REG
|| (GET_CODE (SET_DEST (x)) == SUBREG
&& GET_CODE (SUBREG_REG (SET_DEST (x))) == REG))
- && x == single_set (PATTERN (insn)))
+ && GET_MODE (var) == promoted_mode
+ && x == single_set (insn))
{
rtx pat;
&& (GET_CODE (SET_SRC (x)) == REG
|| (GET_CODE (SET_SRC (x)) == SUBREG
&& GET_CODE (SUBREG_REG (SET_SRC (x))) == REG))
- && x == single_set (PATTERN (insn)))
+ && GET_MODE (var) == promoted_mode
+ && x == single_set (insn))
{
rtx pat;
fixeddest = XEXP (fixeddest, 0);
/* Convert (SUBREG (MEM)) to a MEM in a changed mode. */
if (GET_CODE (fixeddest) == SUBREG)
- fixeddest = fixup_memory_subreg (fixeddest, insn, 0);
+ {
+ fixeddest = fixup_memory_subreg (fixeddest, insn, 0);
+ promoted_mode = GET_MODE (fixeddest);
+ }
else
fixeddest = fixup_stack_1 (fixeddest, insn);
- temp = gen_reg_rtx (GET_MODE (SET_SRC (x)) == VOIDmode
- ? GET_MODE (fixeddest)
- : GET_MODE (SET_SRC (x)));
+ temp = gen_reg_rtx (promoted_mode);
emit_insn_after (gen_move_insn (fixeddest,
gen_lowpart (GET_MODE (fixeddest),
&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
!= void_type_node));
+ current_function_stdarg = stdarg;
+
/* If the reg that the virtual arg pointer will be translated into is
not a fixed reg or is the stack pointer, make a copy of the virtual
arg pointer, and address parms via the copy. The frame pointer is
??? When MAYBE_REG_PARM_STACK_SPACE is defined, we can't tell
whether this parameter already has a stack slot allocated,
because an arg block exists only if current_function_args_size
- is larger than some threshhold, and we haven't calculated that
+ is larger than some threshold, and we haven't calculated that
yet. So, for now, we just assume that stack slots never exist
in this case. */
|| REG_PARM_STACK_SPACE (fndecl) > 0
rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
emit_move_insn (tempreg, validize_mem (entry_parm));
- tempreg = gen_lowpart (nominal_mode, tempreg);
push_to_sequence (conversion_insns);
+ tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
+
expand_assignment (parm,
make_tree (nominal_type, tempreg), 0, 0);
conversion_insns = get_insns ();
&& FUNCTION_ARG_CALLEE_COPIES (args_so_far,
TYPE_MODE (DECL_ARG_TYPE (parm)),
DECL_ARG_TYPE (parm),
- ! last_named))
+ ! last_named)
+ && ! TREE_ADDRESSABLE (DECL_ARG_TYPE (parm)))
{
rtx copy;
tree type = DECL_ARG_TYPE (parm);
but for arguments instead of local variables. */
void
-setjmp_args_warning (block)
- tree block;
+setjmp_args_warning ()
{
register tree decl;
for (decl = DECL_ARGUMENTS (current_function_decl);
duplicate portions of the RTL code. Call identify_blocks before
changing the RTL, and call reorder_blocks after. */
-/* Put all this function's BLOCK nodes into a vector, and return it.
+/* Put all this function's BLOCK nodes including those that are chained
+ onto the first block into a vector, and return it.
Also store in each NOTE for the beginning or end of a block
the index of that block in the vector.
- The arguments are TOP_BLOCK, the top-level block of the function,
+ The arguments are BLOCK, the chain of top-level blocks of the function,
and INSNS, the insn chain of the function. */
tree *
-identify_blocks (top_block, insns)
- tree top_block;
+identify_blocks (block, insns)
+ tree block;
rtx insns;
{
int n_blocks;
tree *block_vector;
int *block_stack;
int depth = 0;
- int next_block_number = 0;
- int current_block_number = 0;
+ int next_block_number = 1;
+ int current_block_number = 1;
rtx insn;
- if (top_block == 0)
+ if (block == 0)
return 0;
- n_blocks = all_blocks (top_block, 0);
+ n_blocks = all_blocks (block, 0);
block_vector = (tree *) xmalloc (n_blocks * sizeof (tree));
block_stack = (int *) alloca (n_blocks * sizeof (int));
- all_blocks (top_block, block_vector);
+ all_blocks (block, block_vector);
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE)
}
}
+ if (n_blocks != next_block_number)
+ abort ();
+
return block_vector;
}
Returns the current top-level block. */
tree
-reorder_blocks (block_vector, top_block, insns)
+reorder_blocks (block_vector, block, insns)
tree *block_vector;
- tree top_block;
+ tree block;
rtx insns;
{
- tree current_block = top_block;
+ tree current_block = block;
rtx insn;
if (block_vector == 0)
- return top_block;
+ return block;
- /* Prune the old tree away, so that it doesn't get in the way. */
+ /* Prune the old trees away, so that it doesn't get in the way. */
BLOCK_SUBBLOCKS (current_block) = 0;
+ BLOCK_CHAIN (current_block) = 0;
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE)
}
}
+ BLOCK_SUBBLOCKS (current_block)
+ = blocks_nreverse (BLOCK_SUBBLOCKS (current_block));
return current_block;
}
return prev;
}
-/* Count the subblocks of BLOCK, and list them all into the vector VECTOR.
- Also clear TREE_ASM_WRITTEN in all blocks. */
+/* Count the subblocks of the list starting with BLOCK, and list them
+ all into the vector VECTOR. Also clear TREE_ASM_WRITTEN in all
+ blocks. */
static int
all_blocks (block, vector)
tree block;
tree *vector;
{
- int n_blocks = 1;
- tree subblocks;
+ int n_blocks = 0;
- TREE_ASM_WRITTEN (block) = 0;
- /* Record this block. */
- if (vector)
- vector[0] = block;
+ while (block)
+ {
+ TREE_ASM_WRITTEN (block) = 0;
- /* Record the subblocks, and their subblocks. */
- for (subblocks = BLOCK_SUBBLOCKS (block);
- subblocks; subblocks = BLOCK_CHAIN (subblocks))
- n_blocks += all_blocks (subblocks, vector ? vector + n_blocks : 0);
+ /* Record this block. */
+ if (vector)
+ vector[n_blocks] = block;
+
+ ++n_blocks;
+
+ /* Record the subblocks, and their subblocks... */
+ n_blocks += all_blocks (BLOCK_SUBBLOCKS (block),
+ vector ? vector + n_blocks : 0);
+ block = BLOCK_CHAIN (block);
+ }
return n_blocks;
}
/* No RTL_EXPRs in this function yet. */
rtl_expr_chain = 0;
- /* We have not allocated any temporaries yet. */
- temp_slots = 0;
- temp_slot_level = 0;
- target_temp_slot_level = 0;
+ /* Set up to allocate temporaries. */
+ init_temp_slots ();
/* Within function body, compute a type's size as soon it is laid out. */
immediate_size_expand++;
current_function_outgoing_args_size = 0;
- /* Initialize the insn lengths. */
- init_insn_lengths ();
-
/* Prevent ever trying to delete the first instruction of a function.
Also tell final how to output a linenum before the function prologue. */
emit_line_note (filename, line);
/* Indicate we have no need of a frame pointer yet. */
frame_pointer_needed = 0;
- /* By default assume not varargs. */
+ /* By default assume not varargs or stdarg. */
current_function_varargs = 0;
+ current_function_stdarg = 0;
}
/* Indicate that the current function uses extra args