/* Definitions for computing resource usage of specific insns.
- Copyright (C) 1999 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
+#include "toplev.h"
#include "rtl.h"
+#include "tm_p.h"
#include "hard-reg-set.h"
-#include "system.h"
#include "basic-block.h"
+#include "function.h"
#include "regs.h"
#include "flags.h"
#include "output.h"
#include "resource.h"
+#include "insn-attr.h"
/* This structure is used to record liveness information at the targets or
fallthrough insns of branches. We will most likely need the information
static HARD_REG_SET pending_dead_regs;
\f
-static void update_live_status PROTO ((rtx, rtx));
-static int find_basic_block PROTO ((rtx));
-static rtx next_insn_no_annul PROTO ((rtx));
-static rtx find_dead_or_set_registers PROTO ((rtx, struct resources*,
+static void update_live_status PARAMS ((rtx, rtx, void *));
+static int find_basic_block PARAMS ((rtx));
+static rtx next_insn_no_annul PARAMS ((rtx));
+static rtx find_dead_or_set_registers PARAMS ((rtx, struct resources*,
rtx*, int, struct resources,
struct resources));
\f
It deadens any CLOBBERed registers and livens any SET registers. */
static void
-update_live_status (dest, x)
+update_live_status (dest, x, data)
rtx dest;
rtx x;
+ void *data ATTRIBUTE_UNUSED;
{
int first_regno, last_regno;
int i;
{
register enum rtx_code code = GET_CODE (x);
register int i, j;
- register char *format_ptr;
+ register const char *format_ptr;
/* Handle leaf items for which we set resource flags. Also, special-case
CALL, SET and CLOBBER operators. */
res->unch_memory = 1;
else
res->memory = 1;
- res->volatil = MEM_VOLATILE_P (x);
+ res->volatil |= MEM_VOLATILE_P (x);
/* Mark registers used to access memory. */
mark_referenced_resources (XEXP (x, 0), res, 0);
break;
case ASM_OPERANDS:
- res->volatil = MEM_VOLATILE_P (x);
+ res->volatil |= MEM_VOLATILE_P (x);
/* For all ASM_OPERANDS, we must traverse the vector of input operands.
We can not just fall through here since then we would be confused
mark_referenced_resources (SET_SRC (x), res, 0);
x = SET_DEST (x);
- if (GET_CODE (x) == SIGN_EXTRACT || GET_CODE (x) == ZERO_EXTRACT)
+ if (GET_CODE (x) == SIGN_EXTRACT
+ || GET_CODE (x) == ZERO_EXTRACT
+ || GET_CODE (x) == STRICT_LOW_PART)
mark_referenced_resources (x, res, 0);
else if (GET_CODE (x) == SUBREG)
x = SUBREG_REG (x);
{
register enum rtx_code code;
register int i, j;
- register char *format_ptr;
+ register const char *format_ptr;
restart:
if (in_dest)
{
res->memory = 1;
- res->unch_memory = RTX_UNCHANGING_P (x);
- res->volatil = MEM_VOLATILE_P (x);
+ res->unch_memory |= RTX_UNCHANGING_P (x);
+ res->volatil |= MEM_VOLATILE_P (x);
}
mark_set_resources (XEXP (x, 0), res, 0, 0);
SET_HARD_REG_BIT (res->regs, REGNO (x) + i);
return;
+ case UNSPEC_VOLATILE:
+ case ASM_INPUT:
+ /* Traditional asm's are always volatile. */
+ res->volatil = 1;
+ return;
+
+ case TRAP_IF:
+ res->volatil = 1;
+ break;
+
+ case ASM_OPERANDS:
+ res->volatil |= MEM_VOLATILE_P (x);
+
+ /* For all ASM_OPERANDS, we must traverse the vector of input operands.
+ We can not just fall through here since then we would be confused
+ by the ASM_INPUT rtx inside ASM_OPERANDS, which do not indicate
+ traditional asms unlike their normal usage. */
+
+ for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
+ mark_set_resources (ASM_OPERANDS_INPUT (x, i), res, in_dest, 0);
+ return;
+
default:
break;
}
TARGET. Otherwise, we must assume everything is live. */
if (b != -1)
{
- regset regs_live = basic_block_live_at_start[b];
+ regset regs_live = BASIC_BLOCK (b)->global_live_at_start;
int j;
int regno;
rtx start_insn, stop_insn;
#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& ! (i == ARG_POINTER_REGNUM && fixed_regs[i])
#endif
-#ifdef PIC_OFFSET_TABLE_REGNUM
+#if defined (PIC_OFFSET_TABLE_REGNUM) && !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
&& ! (i == PIC_OFFSET_TABLE_REGNUM && flag_pic)
#endif
)
SET_HARD_REG_BIT (pending_dead_regs, i);
}
- note_stores (PATTERN (real_insn), update_live_status);
+ note_stores (PATTERN (real_insn), update_live_status, NULL);
/* If any registers were unused after this insn, kill them.
These notes will always be accurate. */
/* If we hit an unconditional branch, we have another way of finding out
what is live: we can see what is live at the branch target and include
- anything used but not set before the branch. The only things that are
- live are those that are live using the above test and the test below. */
+ anything used but not set before the branch. We add the live
+ resources found using the test below to those found until now. */
if (jump_insn)
{
mark_set_resources (insn, &set, 0, 1);
}
- AND_HARD_REG_SET (res->regs, new_resources.regs);
+ IOR_HARD_REG_SET (res->regs, new_resources.regs);
}
if (tinfo != NULL)
mark_set_resources (epilogue_insn, &end_of_function_needs, 0, 1);
/* Allocate and initialize the tables used by mark_target_live_regs. */
- target_hash_table
- = (struct target_info **) xmalloc ((TARGET_HASH_PRIME
- * sizeof (struct target_info *)));
- bzero ((char *) target_hash_table,
- TARGET_HASH_PRIME * sizeof (struct target_info *));
-
- bb_ticks = (int *) xmalloc (n_basic_blocks * sizeof (int));
- bzero ((char *) bb_ticks, n_basic_blocks * sizeof (int));
+ target_hash_table = (struct target_info **)
+ xcalloc (TARGET_HASH_PRIME, sizeof (struct target_info *));
+ bb_ticks = (int *) xcalloc (n_basic_blocks, sizeof (int));
}
\f
/* Free up the resources allcated to mark_target_live_regs (). This
include_delayed_effects);
}
\f
-/* Try to find an available hard register of mode MODE at
- CURRENT_INSN, matching the register class in CLASS_STR. Registers
- that already have bits set in REG_SET will not be considered.
+/* Try to find a hard register of mode MODE, matching the register class in
+ CLASS_STR, which is available at the beginning of insn CURRENT_INSN and
+ remains available until the end of LAST_INSN. LAST_INSN may be NULL_RTX,
+ in which case the only condition is that the register must be available
+ before CURRENT_INSN.
+ Registers that already have bits set in REG_SET will not be considered.
If an appropriate register is available, it will be returned and the
corresponding bit(s) in REG_SET will be set; otherwise, NULL_RTX is
returned. */
rtx
-find_free_register (current_insn, class_str, mode, reg_set)
- rtx current_insn;
- char *class_str;
+find_free_register (current_insn, last_insn, class_str, mode, reg_set)
+ rtx current_insn, last_insn;
+ const char *class_str;
int mode;
HARD_REG_SET *reg_set;
{
= (clet == 'r' ? GENERAL_REGS : REG_CLASS_FROM_LETTER (clet));
mark_target_live_regs (get_insns (), current_insn, &used);
+ if (last_insn)
+ while (current_insn != last_insn)
+ {
+ /* Exclude anything set in this insn. */
+ mark_set_resources (PATTERN (current_insn), &used, 0, 1);
+ current_insn = next_nonnote_insn (current_insn);
+ }
+
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
- int success = 1;
+ int regno;
+ int success;
+
+#ifdef REG_ALLOC_ORDER
+ regno = reg_alloc_order [i];
+#else
+ regno = i;
+#endif
- if (! TEST_HARD_REG_BIT (reg_class_contents[class], i))
+ /* Don't allocate fixed registers. */
+ if (fixed_regs[regno])
continue;
- for (j = HARD_REGNO_NREGS (i, mode) - 1; j >= 0; j--)
+ /* Make sure the register is of the right class. */
+ if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno))
+ continue;
+ /* And can support the mode we need. */
+ if (! HARD_REGNO_MODE_OK (regno, mode))
+ continue;
+ /* And that we don't create an extra save/restore. */
+ if (! call_used_regs[regno] && ! regs_ever_live[regno])
+ continue;
+ /* And we don't clobber traceback for noreturn functions. */
+ if ((regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM)
+ && (! reload_completed || frame_pointer_needed))
+ continue;
+
+ success = 1;
+ for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
{
- if (TEST_HARD_REG_BIT (*reg_set, i + j)
- || TEST_HARD_REG_BIT (used.regs, i + j))
+ if (TEST_HARD_REG_BIT (*reg_set, regno + j)
+ || TEST_HARD_REG_BIT (used.regs, regno + j))
{
success = 0;
break;
}
if (success)
{
- for (j = HARD_REGNO_NREGS (i, mode) - 1; j >= 0; j--)
+ for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
{
- SET_HARD_REG_BIT (*reg_set, i + j);
+ SET_HARD_REG_BIT (*reg_set, regno + j);
}
- return gen_rtx_REG (mode, i);
+ return gen_rtx_REG (mode, regno);
}
}
return NULL_RTX;
}
+
+/* Return true if REG is dead at CURRENT_INSN. */
+
+int
+reg_dead_p (current_insn, reg)
+ rtx current_insn, reg;
+{
+ struct resources used;
+ int regno, j;
+
+ mark_target_live_regs (get_insns (), current_insn, &used);
+
+ regno = REGNO (reg);
+ for (j = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1; j >= 0; j--)
+ {
+ if (TEST_HARD_REG_BIT (used.regs, regno + j))
+ return 0;
+ }
+
+ return 1;
+}