aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.4.0/gcc/resource.c
diff options
context:
space:
mode:
authorDan Albert <danalbert@google.com>2015-06-17 11:09:54 -0700
committerDan Albert <danalbert@google.com>2015-06-17 14:15:22 -0700
commitf378ebf14df0952eae870c9865bab8326aa8f137 (patch)
tree31794503eb2a8c64ea5f313b93100f1163afcffb /gcc-4.4.0/gcc/resource.c
parent2c58169824949d3a597d9fa81931e001ef9b1bd0 (diff)
downloadtoolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.tar.gz
toolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.tar.bz2
toolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.zip
Delete old versions of GCC.
Change-Id: I710f125d905290e1024cbd67f48299861790c66c
Diffstat (limited to 'gcc-4.4.0/gcc/resource.c')
-rw-r--r--gcc-4.4.0/gcc/resource.c1264
1 files changed, 0 insertions, 1264 deletions
diff --git a/gcc-4.4.0/gcc/resource.c b/gcc-4.4.0/gcc/resource.c
deleted file mode 100644
index 2f9a71bc6..000000000
--- a/gcc-4.4.0/gcc/resource.c
+++ /dev/null
@@ -1,1264 +0,0 @@
-/* Definitions for computing resource usage of specific insns.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
- Free Software Foundation, Inc.
-
-This file is part of GCC.
-
-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 3, or (at your option) any later
-version.
-
-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 GCC; see the file COPYING3. If not see
-<http://www.gnu.org/licenses/>. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "toplev.h"
-#include "rtl.h"
-#include "tm_p.h"
-#include "hard-reg-set.h"
-#include "function.h"
-#include "regs.h"
-#include "flags.h"
-#include "output.h"
-#include "resource.h"
-#include "except.h"
-#include "insn-attr.h"
-#include "params.h"
-#include "df.h"
-
-/* This structure is used to record liveness information at the targets or
- fallthrough insns of branches. We will most likely need the information
- at targets again, so save them in a hash table rather than recomputing them
- each time. */
-
-struct target_info
-{
- int uid; /* INSN_UID of target. */
- struct target_info *next; /* Next info for same hash bucket. */
- HARD_REG_SET live_regs; /* Registers live at target. */
- int block; /* Basic block number containing target. */
- int bb_tick; /* Generation count of basic block info. */
-};
-
-#define TARGET_HASH_PRIME 257
-
-/* Indicates what resources are required at the beginning of the epilogue. */
-static struct resources start_of_epilogue_needs;
-
-/* Indicates what resources are required at function end. */
-static struct resources end_of_function_needs;
-
-/* Define the hash table itself. */
-static struct target_info **target_hash_table = NULL;
-
-/* For each basic block, we maintain a generation number of its basic
- block info, which is updated each time we move an insn from the
- target of a jump. This is the generation number indexed by block
- number. */
-
-static int *bb_ticks;
-
-/* Marks registers possibly live at the current place being scanned by
- mark_target_live_regs. Also used by update_live_status. */
-
-static HARD_REG_SET current_live_regs;
-
-/* Marks registers for which we have seen a REG_DEAD note but no assignment.
- Also only used by the next two functions. */
-
-static HARD_REG_SET pending_dead_regs;
-
-static void update_live_status (rtx, const_rtx, void *);
-static int find_basic_block (rtx, int);
-static rtx next_insn_no_annul (rtx);
-static rtx find_dead_or_set_registers (rtx, struct resources*,
- rtx*, int, struct resources,
- struct resources);
-
-/* Utility function called from mark_target_live_regs via note_stores.
- It deadens any CLOBBERed registers and livens any SET registers. */
-
-static void
-update_live_status (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED)
-{
- int first_regno, last_regno;
- int i;
-
- if (!REG_P (dest)
- && (GET_CODE (dest) != SUBREG || !REG_P (SUBREG_REG (dest))))
- return;
-
- if (GET_CODE (dest) == SUBREG)
- {
- first_regno = subreg_regno (dest);
- last_regno = first_regno + subreg_nregs (dest);
-
- }
- else
- {
- first_regno = REGNO (dest);
- last_regno = END_HARD_REGNO (dest);
- }
-
- if (GET_CODE (x) == CLOBBER)
- for (i = first_regno; i < last_regno; i++)
- CLEAR_HARD_REG_BIT (current_live_regs, i);
- else
- for (i = first_regno; i < last_regno; i++)
- {
- SET_HARD_REG_BIT (current_live_regs, i);
- CLEAR_HARD_REG_BIT (pending_dead_regs, i);
- }
-}
-
-/* Find the number of the basic block with correct live register
- information that starts closest to INSN. Return -1 if we couldn't
- find such a basic block or the beginning is more than
- SEARCH_LIMIT instructions before INSN. Use SEARCH_LIMIT = -1 for
- an unlimited search.
-
- The delay slot filling code destroys the control-flow graph so,
- instead of finding the basic block containing INSN, we search
- backwards toward a BARRIER where the live register information is
- correct. */
-
-static int
-find_basic_block (rtx insn, int search_limit)
-{
- basic_block bb;
-
- /* Scan backwards to the previous BARRIER. Then see if we can find a
- label that starts a basic block. Return the basic block number. */
- for (insn = prev_nonnote_insn (insn);
- insn && !BARRIER_P (insn) && search_limit != 0;
- insn = prev_nonnote_insn (insn), --search_limit)
- ;
-
- /* The closest BARRIER is too far away. */
- if (search_limit == 0)
- return -1;
-
- /* The start of the function. */
- else if (insn == 0)
- return ENTRY_BLOCK_PTR->next_bb->index;
-
- /* See if any of the upcoming CODE_LABELs start a basic block. If we reach
- anything other than a CODE_LABEL or note, we can't find this code. */
- for (insn = next_nonnote_insn (insn);
- insn && LABEL_P (insn);
- insn = next_nonnote_insn (insn))
- {
- FOR_EACH_BB (bb)
- if (insn == BB_HEAD (bb))
- return bb->index;
- }
-
- return -1;
-}
-
-/* Similar to next_insn, but ignores insns in the delay slots of
- an annulled branch. */
-
-static rtx
-next_insn_no_annul (rtx insn)
-{
- if (insn)
- {
- /* If INSN is an annulled branch, skip any insns from the target
- of the branch. */
- if (INSN_P (insn)
- && INSN_ANNULLED_BRANCH_P (insn)
- && NEXT_INSN (PREV_INSN (insn)) != insn)
- {
- rtx next = NEXT_INSN (insn);
- enum rtx_code code = GET_CODE (next);
-
- while ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
- && INSN_FROM_TARGET_P (next))
- {
- insn = next;
- next = NEXT_INSN (insn);
- code = GET_CODE (next);
- }
- }
-
- insn = NEXT_INSN (insn);
- if (insn && NONJUMP_INSN_P (insn)
- && GET_CODE (PATTERN (insn)) == SEQUENCE)
- insn = XVECEXP (PATTERN (insn), 0, 0);
- }
-
- return insn;
-}
-
-/* Given X, some rtl, and RES, a pointer to a `struct resource', mark
- which resources are referenced by the insn. If INCLUDE_DELAYED_EFFECTS
- is TRUE, resources used by the called routine will be included for
- CALL_INSNs. */
-
-void
-mark_referenced_resources (rtx x, struct resources *res,
- int include_delayed_effects)
-{
- enum rtx_code code = GET_CODE (x);
- int i, j;
- unsigned int r;
- const char *format_ptr;
-
- /* Handle leaf items for which we set resource flags. Also, special-case
- CALL, SET and CLOBBER operators. */
- switch (code)
- {
- case CONST:
- case CONST_INT:
- case CONST_DOUBLE:
- case CONST_FIXED:
- case CONST_VECTOR:
- case PC:
- case SYMBOL_REF:
- case LABEL_REF:
- return;
-
- case SUBREG:
- if (!REG_P (SUBREG_REG (x)))
- mark_referenced_resources (SUBREG_REG (x), res, 0);
- else
- {
- unsigned int regno = subreg_regno (x);
- unsigned int last_regno = regno + subreg_nregs (x);
-
- gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER);
- for (r = regno; r < last_regno; r++)
- SET_HARD_REG_BIT (res->regs, r);
- }
- return;
-
- case REG:
- gcc_assert (HARD_REGISTER_P (x));
- add_to_hard_reg_set (&res->regs, GET_MODE (x), REGNO (x));
- return;
-
- case MEM:
- /* If this memory shouldn't change, it really isn't referencing
- memory. */
- if (MEM_READONLY_P (x))
- res->unch_memory = 1;
- else
- res->memory = 1;
- res->volatil |= MEM_VOLATILE_P (x);
-
- /* Mark registers used to access memory. */
- mark_referenced_resources (XEXP (x, 0), res, 0);
- return;
-
- case CC0:
- res->cc = 1;
- return;
-
- case UNSPEC_VOLATILE:
- case TRAP_IF:
- case ASM_INPUT:
- /* Traditional asm's are always volatile. */
- 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_referenced_resources (ASM_OPERANDS_INPUT (x, i), res, 0);
- return;
-
- case CALL:
- /* The first operand will be a (MEM (xxx)) but doesn't really reference
- memory. The second operand may be referenced, though. */
- mark_referenced_resources (XEXP (XEXP (x, 0), 0), res, 0);
- mark_referenced_resources (XEXP (x, 1), res, 0);
- return;
-
- case SET:
- /* Usually, the first operand of SET is set, not referenced. But
- registers used to access memory are referenced. SET_DEST is
- also referenced if it is a ZERO_EXTRACT. */
-
- mark_referenced_resources (SET_SRC (x), res, 0);
-
- x = SET_DEST (x);
- if (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);
- if (MEM_P (x))
- mark_referenced_resources (XEXP (x, 0), res, 0);
- return;
-
- case CLOBBER:
- return;
-
- case CALL_INSN:
- if (include_delayed_effects)
- {
- /* A CALL references memory, the frame pointer if it exists, the
- stack pointer, any global registers and any registers given in
- USE insns immediately in front of the CALL.
-
- However, we may have moved some of the parameter loading insns
- into the delay slot of this CALL. If so, the USE's for them
- don't count and should be skipped. */
- rtx insn = PREV_INSN (x);
- rtx sequence = 0;
- int seq_size = 0;
- int i;
-
- /* If we are part of a delay slot sequence, point at the SEQUENCE. */
- if (NEXT_INSN (insn) != x)
- {
- sequence = PATTERN (NEXT_INSN (insn));
- seq_size = XVECLEN (sequence, 0);
- gcc_assert (GET_CODE (sequence) == SEQUENCE);
- }
-
- res->memory = 1;
- SET_HARD_REG_BIT (res->regs, STACK_POINTER_REGNUM);
- if (frame_pointer_needed)
- {
- SET_HARD_REG_BIT (res->regs, FRAME_POINTER_REGNUM);
-#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
- SET_HARD_REG_BIT (res->regs, HARD_FRAME_POINTER_REGNUM);
-#endif
- }
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (global_regs[i])
- SET_HARD_REG_BIT (res->regs, i);
-
- /* Check for a REG_SETJMP. If it exists, then we must
- assume that this call can need any register.
-
- This is done to be more conservative about how we handle setjmp.
- We assume that they both use and set all registers. Using all
- registers ensures that a register will not be considered dead
- just because it crosses a setjmp call. A register should be
- considered dead only if the setjmp call returns nonzero. */
- if (find_reg_note (x, REG_SETJMP, NULL))
- SET_HARD_REG_SET (res->regs);
-
- {
- rtx link;
-
- for (link = CALL_INSN_FUNCTION_USAGE (x);
- link;
- link = XEXP (link, 1))
- if (GET_CODE (XEXP (link, 0)) == USE)
- {
- for (i = 1; i < seq_size; i++)
- {
- rtx slot_pat = PATTERN (XVECEXP (sequence, 0, i));
- if (GET_CODE (slot_pat) == SET
- && rtx_equal_p (SET_DEST (slot_pat),
- XEXP (XEXP (link, 0), 0)))
- break;
- }
- if (i >= seq_size)
- mark_referenced_resources (XEXP (XEXP (link, 0), 0),
- res, 0);
- }
- }
- }
-
- /* ... fall through to other INSN processing ... */
-
- case INSN:
- case JUMP_INSN:
-
-#ifdef INSN_REFERENCES_ARE_DELAYED
- if (! include_delayed_effects
- && INSN_REFERENCES_ARE_DELAYED (x))
- return;
-#endif
-
- /* No special processing, just speed up. */
- mark_referenced_resources (PATTERN (x), res, include_delayed_effects);
- return;
-
- default:
- break;
- }
-
- /* Process each sub-expression and flag what it needs. */
- format_ptr = GET_RTX_FORMAT (code);
- for (i = 0; i < GET_RTX_LENGTH (code); i++)
- switch (*format_ptr++)
- {
- case 'e':
- mark_referenced_resources (XEXP (x, i), res, include_delayed_effects);
- break;
-
- case 'E':
- for (j = 0; j < XVECLEN (x, i); j++)
- mark_referenced_resources (XVECEXP (x, i, j), res,
- include_delayed_effects);
- break;
- }
-}
-
-/* A subroutine of mark_target_live_regs. Search forward from TARGET
- looking for registers that are set before they are used. These are dead.
- Stop after passing a few conditional jumps, and/or a small
- number of unconditional branches. */
-
-static rtx
-find_dead_or_set_registers (rtx target, struct resources *res,
- rtx *jump_target, int jump_count,
- struct resources set, struct resources needed)
-{
- HARD_REG_SET scratch;
- rtx insn, next;
- rtx jump_insn = 0;
- int i;
-
- for (insn = target; insn; insn = next)
- {
- rtx this_jump_insn = insn;
-
- next = NEXT_INSN (insn);
-
- /* If this instruction can throw an exception, then we don't
- know where we might end up next. That means that we have to
- assume that whatever we have already marked as live really is
- live. */
- if (can_throw_internal (insn))
- break;
-
- switch (GET_CODE (insn))
- {
- case CODE_LABEL:
- /* After a label, any pending dead registers that weren't yet
- used can be made dead. */
- AND_COMPL_HARD_REG_SET (pending_dead_regs, needed.regs);
- AND_COMPL_HARD_REG_SET (res->regs, pending_dead_regs);
- CLEAR_HARD_REG_SET (pending_dead_regs);
-
- continue;
-
- case BARRIER:
- case NOTE:
- continue;
-
- case INSN:
- if (GET_CODE (PATTERN (insn)) == USE)
- {
- /* If INSN is a USE made by update_block, we care about the
- underlying insn. Any registers set by the underlying insn
- are live since the insn is being done somewhere else. */
- if (INSN_P (XEXP (PATTERN (insn), 0)))
- mark_set_resources (XEXP (PATTERN (insn), 0), res, 0,
- MARK_SRC_DEST_CALL);
-
- /* All other USE insns are to be ignored. */
- continue;
- }
- else if (GET_CODE (PATTERN (insn)) == CLOBBER)
- continue;
- else if (GET_CODE (PATTERN (insn)) == SEQUENCE)
- {
- /* An unconditional jump can be used to fill the delay slot
- of a call, so search for a JUMP_INSN in any position. */
- for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
- {
- this_jump_insn = XVECEXP (PATTERN (insn), 0, i);
- if (JUMP_P (this_jump_insn))
- break;
- }
- }
-
- default:
- break;
- }
-
- if (JUMP_P (this_jump_insn))
- {
- if (jump_count++ < 10)
- {
- if (any_uncondjump_p (this_jump_insn)
- || GET_CODE (PATTERN (this_jump_insn)) == RETURN)
- {
- next = JUMP_LABEL (this_jump_insn);
- if (jump_insn == 0)
- {
- jump_insn = insn;
- if (jump_target)
- *jump_target = JUMP_LABEL (this_jump_insn);
- }
- }
- else if (any_condjump_p (this_jump_insn))
- {
- struct resources target_set, target_res;
- struct resources fallthrough_res;
-
- /* We can handle conditional branches here by following
- both paths, and then IOR the results of the two paths
- together, which will give us registers that are dead
- on both paths. Since this is expensive, we give it
- a much higher cost than unconditional branches. The
- cost was chosen so that we will follow at most 1
- conditional branch. */
-
- jump_count += 4;
- if (jump_count >= 10)
- break;
-
- mark_referenced_resources (insn, &needed, 1);
-
- /* For an annulled branch, mark_set_resources ignores slots
- filled by instructions from the target. This is correct
- if the branch is not taken. Since we are following both
- paths from the branch, we must also compute correct info
- if the branch is taken. We do this by inverting all of
- the INSN_FROM_TARGET_P bits, calling mark_set_resources,
- and then inverting the INSN_FROM_TARGET_P bits again. */
-
- if (GET_CODE (PATTERN (insn)) == SEQUENCE
- && INSN_ANNULLED_BRANCH_P (this_jump_insn))
- {
- for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
- INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i))
- = ! INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i));
-
- target_set = set;
- mark_set_resources (insn, &target_set, 0,
- MARK_SRC_DEST_CALL);
-
- for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
- INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i))
- = ! INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i));
-
- mark_set_resources (insn, &set, 0, MARK_SRC_DEST_CALL);
- }
- else
- {
- mark_set_resources (insn, &set, 0, MARK_SRC_DEST_CALL);
- target_set = set;
- }
-
- target_res = *res;
- COPY_HARD_REG_SET (scratch, target_set.regs);
- AND_COMPL_HARD_REG_SET (scratch, needed.regs);
- AND_COMPL_HARD_REG_SET (target_res.regs, scratch);
-
- fallthrough_res = *res;
- COPY_HARD_REG_SET (scratch, set.regs);
- AND_COMPL_HARD_REG_SET (scratch, needed.regs);
- AND_COMPL_HARD_REG_SET (fallthrough_res.regs, scratch);
-
- find_dead_or_set_registers (JUMP_LABEL (this_jump_insn),
- &target_res, 0, jump_count,
- target_set, needed);
- find_dead_or_set_registers (next,
- &fallthrough_res, 0, jump_count,
- set, needed);
- IOR_HARD_REG_SET (fallthrough_res.regs, target_res.regs);
- AND_HARD_REG_SET (res->regs, fallthrough_res.regs);
- break;
- }
- else
- break;
- }
- else
- {
- /* Don't try this optimization if we expired our jump count
- above, since that would mean there may be an infinite loop
- in the function being compiled. */
- jump_insn = 0;
- break;
- }
- }
-
- mark_referenced_resources (insn, &needed, 1);
- mark_set_resources (insn, &set, 0, MARK_SRC_DEST_CALL);
-
- COPY_HARD_REG_SET (scratch, set.regs);
- AND_COMPL_HARD_REG_SET (scratch, needed.regs);
- AND_COMPL_HARD_REG_SET (res->regs, scratch);
- }
-
- return jump_insn;
-}
-
-/* Given X, a part of an insn, and a pointer to a `struct resource',
- RES, indicate which resources are modified by the insn. If
- MARK_TYPE is MARK_SRC_DEST_CALL, also mark resources potentially
- set by the called routine.
-
- If IN_DEST is nonzero, it means we are inside a SET. Otherwise,
- objects are being referenced instead of set.
-
- We never mark the insn as modifying the condition code unless it explicitly
- SETs CC0 even though this is not totally correct. The reason for this is
- that we require a SET of CC0 to immediately precede the reference to CC0.
- So if some other insn sets CC0 as a side-effect, we know it cannot affect
- our computation and thus may be placed in a delay slot. */
-
-void
-mark_set_resources (rtx x, struct resources *res, int in_dest,
- enum mark_resource_type mark_type)
-{
- enum rtx_code code;
- int i, j;
- unsigned int r;
- const char *format_ptr;
-
- restart:
-
- code = GET_CODE (x);
-
- switch (code)
- {
- case NOTE:
- case BARRIER:
- case CODE_LABEL:
- case USE:
- case CONST_INT:
- case CONST_DOUBLE:
- case CONST_FIXED:
- case CONST_VECTOR:
- case LABEL_REF:
- case SYMBOL_REF:
- case CONST:
- case PC:
- /* These don't set any resources. */
- return;
-
- case CC0:
- if (in_dest)
- res->cc = 1;
- return;
-
- case CALL_INSN:
- /* Called routine modifies the condition code, memory, any registers
- that aren't saved across calls, global registers and anything
- explicitly CLOBBERed immediately after the CALL_INSN. */
-
- if (mark_type == MARK_SRC_DEST_CALL)
- {
- rtx link;
-
- res->cc = res->memory = 1;
-
- IOR_HARD_REG_SET (res->regs, regs_invalidated_by_call);
-
- for (link = CALL_INSN_FUNCTION_USAGE (x);
- link; link = XEXP (link, 1))
- if (GET_CODE (XEXP (link, 0)) == CLOBBER)
- mark_set_resources (SET_DEST (XEXP (link, 0)), res, 1,
- MARK_SRC_DEST);
-
- /* Check for a REG_SETJMP. If it exists, then we must
- assume that this call can clobber any register. */
- if (find_reg_note (x, REG_SETJMP, NULL))
- SET_HARD_REG_SET (res->regs);
- }
-
- /* ... and also what its RTL says it modifies, if anything. */
-
- case JUMP_INSN:
- case INSN:
-
- /* An insn consisting of just a CLOBBER (or USE) is just for flow
- and doesn't actually do anything, so we ignore it. */
-
-#ifdef INSN_SETS_ARE_DELAYED
- if (mark_type != MARK_SRC_DEST_CALL
- && INSN_SETS_ARE_DELAYED (x))
- return;
-#endif
-
- x = PATTERN (x);
- if (GET_CODE (x) != USE && GET_CODE (x) != CLOBBER)
- goto restart;
- return;
-
- case SET:
- /* If the source of a SET is a CALL, this is actually done by
- the called routine. So only include it if we are to include the
- effects of the calling routine. */
-
- mark_set_resources (SET_DEST (x), res,
- (mark_type == MARK_SRC_DEST_CALL
- || GET_CODE (SET_SRC (x)) != CALL),
- mark_type);
-
- mark_set_resources (SET_SRC (x), res, 0, MARK_SRC_DEST);
- return;
-
- case CLOBBER:
- mark_set_resources (XEXP (x, 0), res, 1, MARK_SRC_DEST);
- return;
-
- case SEQUENCE:
- for (i = 0; i < XVECLEN (x, 0); i++)
- if (! (INSN_ANNULLED_BRANCH_P (XVECEXP (x, 0, 0))
- && INSN_FROM_TARGET_P (XVECEXP (x, 0, i))))
- mark_set_resources (XVECEXP (x, 0, i), res, 0, mark_type);
- return;
-
- case POST_INC:
- case PRE_INC:
- case POST_DEC:
- case PRE_DEC:
- mark_set_resources (XEXP (x, 0), res, 1, MARK_SRC_DEST);
- return;
-
- case PRE_MODIFY:
- case POST_MODIFY:
- mark_set_resources (XEXP (x, 0), res, 1, MARK_SRC_DEST);
- mark_set_resources (XEXP (XEXP (x, 1), 0), res, 0, MARK_SRC_DEST);
- mark_set_resources (XEXP (XEXP (x, 1), 1), res, 0, MARK_SRC_DEST);
- return;
-
- case SIGN_EXTRACT:
- case ZERO_EXTRACT:
- mark_set_resources (XEXP (x, 0), res, in_dest, MARK_SRC_DEST);
- mark_set_resources (XEXP (x, 1), res, 0, MARK_SRC_DEST);
- mark_set_resources (XEXP (x, 2), res, 0, MARK_SRC_DEST);
- return;
-
- case MEM:
- if (in_dest)
- {
- res->memory = 1;
- res->unch_memory |= MEM_READONLY_P (x);
- res->volatil |= MEM_VOLATILE_P (x);
- }
-
- mark_set_resources (XEXP (x, 0), res, 0, MARK_SRC_DEST);
- return;
-
- case SUBREG:
- if (in_dest)
- {
- if (!REG_P (SUBREG_REG (x)))
- mark_set_resources (SUBREG_REG (x), res, in_dest, mark_type);
- else
- {
- unsigned int regno = subreg_regno (x);
- unsigned int last_regno = regno + subreg_nregs (x);
-
- gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER);
- for (r = regno; r < last_regno; r++)
- SET_HARD_REG_BIT (res->regs, r);
- }
- }
- return;
-
- case REG:
- if (in_dest)
- {
- gcc_assert (HARD_REGISTER_P (x));
- add_to_hard_reg_set (&res->regs, GET_MODE (x), REGNO (x));
- }
- 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,
- MARK_SRC_DEST);
- return;
-
- default:
- break;
- }
-
- /* Process each sub-expression and flag what it needs. */
- format_ptr = GET_RTX_FORMAT (code);
- for (i = 0; i < GET_RTX_LENGTH (code); i++)
- switch (*format_ptr++)
- {
- case 'e':
- mark_set_resources (XEXP (x, i), res, in_dest, mark_type);
- break;
-
- case 'E':
- for (j = 0; j < XVECLEN (x, i); j++)
- mark_set_resources (XVECEXP (x, i, j), res, in_dest, mark_type);
- break;
- }
-}
-
-/* Return TRUE if INSN is a return, possibly with a filled delay slot. */
-
-static bool
-return_insn_p (const_rtx insn)
-{
- if (JUMP_P (insn) && GET_CODE (PATTERN (insn)) == RETURN)
- return true;
-
- if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
- return return_insn_p (XVECEXP (PATTERN (insn), 0, 0));
-
- return false;
-}
-
-/* Set the resources that are live at TARGET.
-
- If TARGET is zero, we refer to the end of the current function and can
- return our precomputed value.
-
- Otherwise, we try to find out what is live by consulting the basic block
- information. This is tricky, because we must consider the actions of
- reload and jump optimization, which occur after the basic block information
- has been computed.
-
- Accordingly, we proceed as follows::
-
- We find the previous BARRIER and look at all immediately following labels
- (with no intervening active insns) to see if any of them start a basic
- block. If we hit the start of the function first, we use block 0.
-
- Once we have found a basic block and a corresponding first insns, we can
- accurately compute the live status from basic_block_live_regs and
- reg_renumber. (By starting at a label following a BARRIER, we are immune
- to actions taken by reload and jump.) Then we scan all insns between
- that point and our target. For each CLOBBER (or for call-clobbered regs
- when we pass a CALL_INSN), mark the appropriate registers are dead. For
- a SET, mark them as live.
-
- We have to be careful when using REG_DEAD notes because they are not
- updated by such things as find_equiv_reg. So keep track of registers
- marked as dead that haven't been assigned to, and mark them dead at the
- next CODE_LABEL since reload and jump won't propagate values across labels.
-
- If we cannot find the start of a basic block (should be a very rare
- case, if it can happen at all), mark everything as potentially live.
-
- Next, scan forward from TARGET looking for things set or clobbered
- before they are used. These are not live.
-
- Because we can be called many times on the same target, save our results
- in a hash table indexed by INSN_UID. This is only done if the function
- init_resource_info () was invoked before we are called. */
-
-void
-mark_target_live_regs (rtx insns, rtx target, struct resources *res)
-{
- int b = -1;
- unsigned int i;
- struct target_info *tinfo = NULL;
- rtx insn;
- rtx jump_insn = 0;
- rtx jump_target;
- HARD_REG_SET scratch;
- struct resources set, needed;
-
- /* Handle end of function. */
- if (target == 0)
- {
- *res = end_of_function_needs;
- return;
- }
-
- /* Handle return insn. */
- else if (return_insn_p (target))
- {
- *res = end_of_function_needs;
- mark_referenced_resources (target, res, 0);
- return;
- }
-
- /* We have to assume memory is needed, but the CC isn't. */
- res->memory = 1;
- res->volatil = res->unch_memory = 0;
- res->cc = 0;
-
- /* See if we have computed this value already. */
- if (target_hash_table != NULL)
- {
- for (tinfo = target_hash_table[INSN_UID (target) % TARGET_HASH_PRIME];
- tinfo; tinfo = tinfo->next)
- if (tinfo->uid == INSN_UID (target))
- break;
-
- /* Start by getting the basic block number. If we have saved
- information, we can get it from there unless the insn at the
- start of the basic block has been deleted. */
- if (tinfo && tinfo->block != -1
- && ! INSN_DELETED_P (BB_HEAD (BASIC_BLOCK (tinfo->block))))
- b = tinfo->block;
- }
-
- if (b == -1)
- b = find_basic_block (target, MAX_DELAY_SLOT_LIVE_SEARCH);
-
- if (target_hash_table != NULL)
- {
- if (tinfo)
- {
- /* If the information is up-to-date, use it. Otherwise, we will
- update it below. */
- if (b == tinfo->block && b != -1 && tinfo->bb_tick == bb_ticks[b])
- {
- COPY_HARD_REG_SET (res->regs, tinfo->live_regs);
- return;
- }
- }
- else
- {
- /* Allocate a place to put our results and chain it into the
- hash table. */
- tinfo = XNEW (struct target_info);
- tinfo->uid = INSN_UID (target);
- tinfo->block = b;
- tinfo->next
- = target_hash_table[INSN_UID (target) % TARGET_HASH_PRIME];
- target_hash_table[INSN_UID (target) % TARGET_HASH_PRIME] = tinfo;
- }
- }
-
- CLEAR_HARD_REG_SET (pending_dead_regs);
-
- /* If we found a basic block, get the live registers from it and update
- them with anything set or killed between its start and the insn before
- TARGET. Otherwise, we must assume everything is live. */
- if (b != -1)
- {
- regset regs_live = DF_LR_IN (BASIC_BLOCK (b));
- rtx start_insn, stop_insn;
-
- /* Compute hard regs live at start of block -- this is the real hard regs
- marked live, plus live pseudo regs that have been renumbered to
- hard regs. */
-
- REG_SET_TO_HARD_REG_SET (current_live_regs, regs_live);
-
- /* Get starting and ending insn, handling the case where each might
- be a SEQUENCE. */
- start_insn = (b == ENTRY_BLOCK_PTR->next_bb->index ?
- insns : BB_HEAD (BASIC_BLOCK (b)));
- stop_insn = target;
-
- if (NONJUMP_INSN_P (start_insn)
- && GET_CODE (PATTERN (start_insn)) == SEQUENCE)
- start_insn = XVECEXP (PATTERN (start_insn), 0, 0);
-
- if (NONJUMP_INSN_P (stop_insn)
- && GET_CODE (PATTERN (stop_insn)) == SEQUENCE)
- stop_insn = next_insn (PREV_INSN (stop_insn));
-
- for (insn = start_insn; insn != stop_insn;
- insn = next_insn_no_annul (insn))
- {
- rtx link;
- rtx real_insn = insn;
- enum rtx_code code = GET_CODE (insn);
-
- /* If this insn is from the target of a branch, it isn't going to
- be used in the sequel. If it is used in both cases, this
- test will not be true. */
- if ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
- && INSN_FROM_TARGET_P (insn))
- continue;
-
- /* If this insn is a USE made by update_block, we care about the
- underlying insn. */
- if (code == INSN && GET_CODE (PATTERN (insn)) == USE
- && INSN_P (XEXP (PATTERN (insn), 0)))
- real_insn = XEXP (PATTERN (insn), 0);
-
- if (CALL_P (real_insn))
- {
- /* CALL clobbers all call-used regs that aren't fixed except
- sp, ap, and fp. Do this before setting the result of the
- call live. */
- AND_COMPL_HARD_REG_SET (current_live_regs,
- regs_invalidated_by_call);
-
- /* A CALL_INSN sets any global register live, since it may
- have been modified by the call. */
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (global_regs[i])
- SET_HARD_REG_BIT (current_live_regs, i);
- }
-
- /* Mark anything killed in an insn to be deadened at the next
- label. Ignore USE insns; the only REG_DEAD notes will be for
- parameters. But they might be early. A CALL_INSN will usually
- clobber registers used for parameters. It isn't worth bothering
- with the unlikely case when it won't. */
- if ((NONJUMP_INSN_P (real_insn)
- && GET_CODE (PATTERN (real_insn)) != USE
- && GET_CODE (PATTERN (real_insn)) != CLOBBER)
- || JUMP_P (real_insn)
- || CALL_P (real_insn))
- {
- for (link = REG_NOTES (real_insn); link; link = XEXP (link, 1))
- if (REG_NOTE_KIND (link) == REG_DEAD
- && REG_P (XEXP (link, 0))
- && REGNO (XEXP (link, 0)) < FIRST_PSEUDO_REGISTER)
- add_to_hard_reg_set (&pending_dead_regs,
- GET_MODE (XEXP (link, 0)),
- REGNO (XEXP (link, 0)));
-
- 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. */
- for (link = REG_NOTES (real_insn); link; link = XEXP (link, 1))
- if (REG_NOTE_KIND (link) == REG_UNUSED
- && REG_P (XEXP (link, 0))
- && REGNO (XEXP (link, 0)) < FIRST_PSEUDO_REGISTER)
- remove_from_hard_reg_set (&current_live_regs,
- GET_MODE (XEXP (link, 0)),
- REGNO (XEXP (link, 0)));
- }
-
- else if (LABEL_P (real_insn))
- {
- /* A label clobbers the pending dead registers since neither
- reload nor jump will propagate a value across a label. */
- AND_COMPL_HARD_REG_SET (current_live_regs, pending_dead_regs);
- CLEAR_HARD_REG_SET (pending_dead_regs);
- }
-
- /* The beginning of the epilogue corresponds to the end of the
- RTL chain when there are no epilogue insns. Certain resources
- are implicitly required at that point. */
- else if (NOTE_P (real_insn)
- && NOTE_KIND (real_insn) == NOTE_INSN_EPILOGUE_BEG)
- IOR_HARD_REG_SET (current_live_regs, start_of_epilogue_needs.regs);
- }
-
- COPY_HARD_REG_SET (res->regs, current_live_regs);
- if (tinfo != NULL)
- {
- tinfo->block = b;
- tinfo->bb_tick = bb_ticks[b];
- }
- }
- else
- /* We didn't find the start of a basic block. Assume everything
- in use. This should happen only extremely rarely. */
- SET_HARD_REG_SET (res->regs);
-
- CLEAR_RESOURCE (&set);
- CLEAR_RESOURCE (&needed);
-
- jump_insn = find_dead_or_set_registers (target, res, &jump_target, 0,
- set, needed);
-
- /* 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. We add the live
- resources found using the test below to those found until now. */
-
- if (jump_insn)
- {
- struct resources new_resources;
- rtx stop_insn = next_active_insn (jump_insn);
-
- mark_target_live_regs (insns, next_active_insn (jump_target),
- &new_resources);
- CLEAR_RESOURCE (&set);
- CLEAR_RESOURCE (&needed);
-
- /* Include JUMP_INSN in the needed registers. */
- for (insn = target; insn != stop_insn; insn = next_active_insn (insn))
- {
- mark_referenced_resources (insn, &needed, 1);
-
- COPY_HARD_REG_SET (scratch, needed.regs);
- AND_COMPL_HARD_REG_SET (scratch, set.regs);
- IOR_HARD_REG_SET (new_resources.regs, scratch);
-
- mark_set_resources (insn, &set, 0, MARK_SRC_DEST_CALL);
- }
-
- IOR_HARD_REG_SET (res->regs, new_resources.regs);
- }
-
- if (tinfo != NULL)
- {
- COPY_HARD_REG_SET (tinfo->live_regs, res->regs);
- }
-}
-
-/* Initialize the resources required by mark_target_live_regs ().
- This should be invoked before the first call to mark_target_live_regs. */
-
-void
-init_resource_info (rtx epilogue_insn)
-{
- int i;
-
- /* Indicate what resources are required to be valid at the end of the current
- function. The condition code never is and memory always is. If the
- frame pointer is needed, it is and so is the stack pointer unless
- EXIT_IGNORE_STACK is nonzero. If the frame pointer is not needed, the
- stack pointer is. Registers used to return the function value are
- needed. Registers holding global variables are needed. */
-
- end_of_function_needs.cc = 0;
- end_of_function_needs.memory = 1;
- end_of_function_needs.unch_memory = 0;
- CLEAR_HARD_REG_SET (end_of_function_needs.regs);
-
- if (frame_pointer_needed)
- {
- SET_HARD_REG_BIT (end_of_function_needs.regs, FRAME_POINTER_REGNUM);
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
- SET_HARD_REG_BIT (end_of_function_needs.regs, HARD_FRAME_POINTER_REGNUM);
-#endif
- if (! EXIT_IGNORE_STACK
- || current_function_sp_is_unchanging)
- SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM);
- }
- else
- SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM);
-
- if (crtl->return_rtx != 0)
- mark_referenced_resources (crtl->return_rtx,
- &end_of_function_needs, 1);
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (global_regs[i]
-#ifdef EPILOGUE_USES
- || EPILOGUE_USES (i)
-#endif
- )
- SET_HARD_REG_BIT (end_of_function_needs.regs, i);
-
- /* The registers required to be live at the end of the function are
- represented in the flow information as being dead just prior to
- reaching the end of the function. For example, the return of a value
- might be represented by a USE of the return register immediately
- followed by an unconditional jump to the return label where the
- return label is the end of the RTL chain. The end of the RTL chain
- is then taken to mean that the return register is live.
-
- This sequence is no longer maintained when epilogue instructions are
- added to the RTL chain. To reconstruct the original meaning, the
- start of the epilogue (NOTE_INSN_EPILOGUE_BEG) is regarded as the
- point where these registers become live (start_of_epilogue_needs).
- If epilogue instructions are present, the registers set by those
- instructions won't have been processed by flow. Thus, those
- registers are additionally required at the end of the RTL chain
- (end_of_function_needs). */
-
- start_of_epilogue_needs = end_of_function_needs;
-
- while ((epilogue_insn = next_nonnote_insn (epilogue_insn)))
- {
- mark_set_resources (epilogue_insn, &end_of_function_needs, 0,
- MARK_SRC_DEST_CALL);
- if (return_insn_p (epilogue_insn))
- break;
- }
-
- /* Allocate and initialize the tables used by mark_target_live_regs. */
- target_hash_table = XCNEWVEC (struct target_info *, TARGET_HASH_PRIME);
- bb_ticks = XCNEWVEC (int, last_basic_block);
-}
-
-/* Free up the resources allocated to mark_target_live_regs (). This
- should be invoked after the last call to mark_target_live_regs (). */
-
-void
-free_resource_info (void)
-{
- if (target_hash_table != NULL)
- {
- int i;
-
- for (i = 0; i < TARGET_HASH_PRIME; ++i)
- {
- struct target_info *ti = target_hash_table[i];
-
- while (ti)
- {
- struct target_info *next = ti->next;
- free (ti);
- ti = next;
- }
- }
-
- free (target_hash_table);
- target_hash_table = NULL;
- }
-
- if (bb_ticks != NULL)
- {
- free (bb_ticks);
- bb_ticks = NULL;
- }
-}
-
-/* Clear any hashed information that we have stored for INSN. */
-
-void
-clear_hashed_info_for_insn (rtx insn)
-{
- struct target_info *tinfo;
-
- if (target_hash_table != NULL)
- {
- for (tinfo = target_hash_table[INSN_UID (insn) % TARGET_HASH_PRIME];
- tinfo; tinfo = tinfo->next)
- if (tinfo->uid == INSN_UID (insn))
- break;
-
- if (tinfo)
- tinfo->block = -1;
- }
-}
-
-/* Increment the tick count for the basic block that contains INSN. */
-
-void
-incr_ticks_for_insn (rtx insn)
-{
- int b = find_basic_block (insn, MAX_DELAY_SLOT_LIVE_SEARCH);
-
- if (b != -1)
- bb_ticks[b]++;
-}
-
-/* Add TRIAL to the set of resources used at the end of the current
- function. */
-void
-mark_end_of_function_resources (rtx trial, int include_delayed_effects)
-{
- mark_referenced_resources (trial, &end_of_function_needs,
- include_delayed_effects);
-}