X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fsched-deps.c;h=7baad1b669e814e4ba29223f6dc71db2a137cbf8;hb=d431b2cae597afbe272e95bcd7ac60d7d9368cf7;hp=abb02c439abddda8be52a4a7a83ef96cbac174fd;hpb=b7fefcbf1f74784d60db9f87ed0ebf75abb2967e;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/sched-deps.c b/gcc/sched-deps.c index abb02c439ab..7baad1b669e 100644 --- a/gcc/sched-deps.c +++ b/gcc/sched-deps.c @@ -1,7 +1,7 @@ /* Instruction scheduling pass. This file computes dependencies between instructions. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by, and currently maintained by, Jim Wilson (wilson@cygnus.com) @@ -19,16 +19,17 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #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 "basic-block.h" #include "regs.h" #include "function.h" #include "flags.h" @@ -40,16 +41,24 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "sched-int.h" #include "params.h" #include "cselib.h" +#include "df.h" -extern char *reg_known_equiv_p; -extern rtx *reg_known_value; - -static regset_head reg_pending_sets_head; -static regset_head reg_pending_clobbers_head; static regset reg_pending_sets; static regset reg_pending_clobbers; -static int reg_pending_sets_all; +static regset reg_pending_uses; + +/* The following enumeration values tell us what dependencies we + should use to implement the barrier. We use true-dependencies for + TRUE_BARRIER and anti-dependencies for MOVE_BARRIER. */ +enum reg_pending_barrier_mode +{ + NOT_A_BARRIER = 0, + MOVE_BARRIER, + TRUE_BARRIER +}; + +static enum reg_pending_barrier_mode reg_pending_barrier; /* To speed up the test for duplicate dependency links we keep a record of dependencies created by add_dependence when the average @@ -64,53 +73,54 @@ static int reg_pending_sets_all; has enough entries to represent a dependency on any other insn in the insn chain. All bitmap for true dependencies cache is allocated then the rest two ones are also allocated. */ -static sbitmap *true_dependency_cache; -static sbitmap *anti_dependency_cache; -static sbitmap *output_dependency_cache; +static bitmap_head *true_dependency_cache; +static bitmap_head *anti_dependency_cache; +static bitmap_head *output_dependency_cache; +static int cache_size; /* To speed up checking consistency of formed forward insn dependencies we use the following cache. Another possible solution could be switching off checking duplication of insns in forward dependencies. */ #ifdef ENABLE_CHECKING -static sbitmap *forward_dependency_cache; +static bitmap_head *forward_dependency_cache; #endif -static int deps_may_trap_p PARAMS ((rtx)); -static void remove_dependence PARAMS ((rtx, rtx)); -static void set_sched_group_p PARAMS ((rtx)); +static int deps_may_trap_p (rtx); +static void add_dependence_list (rtx, rtx, enum reg_note); +static void add_dependence_list_and_free (rtx, rtx *, enum reg_note); +static void delete_all_dependences (rtx); +static void fixup_sched_groups (rtx); -static void flush_pending_lists PARAMS ((struct deps *, rtx, int)); -static void sched_analyze_1 PARAMS ((struct deps *, rtx, rtx)); -static void sched_analyze_2 PARAMS ((struct deps *, rtx, rtx)); -static void sched_analyze_insn PARAMS ((struct deps *, rtx, rtx, rtx)); -static rtx group_leader PARAMS ((rtx)); +static void flush_pending_lists (struct deps *, rtx, int, int); +static void sched_analyze_1 (struct deps *, rtx, rtx); +static void sched_analyze_2 (struct deps *, rtx, rtx); +static void sched_analyze_insn (struct deps *, rtx, rtx, rtx); -static rtx get_condition PARAMS ((rtx)); -static int conditions_mutex_p PARAMS ((rtx, rtx)); +static rtx sched_get_condition (rtx); +static int conditions_mutex_p (rtx, rtx); /* Return nonzero if a load of the memory reference MEM can cause a trap. */ static int -deps_may_trap_p (mem) - rtx mem; +deps_may_trap_p (rtx mem) { rtx addr = XEXP (mem, 0); - if (REG_P (addr) - && REGNO (addr) >= FIRST_PSEUDO_REGISTER - && reg_known_value[REGNO (addr)]) - addr = reg_known_value[REGNO (addr)]; + if (REG_P (addr) && REGNO (addr) >= FIRST_PSEUDO_REGISTER) + { + rtx t = get_reg_known_value (REGNO (addr)); + if (t) + addr = t; + } return rtx_addr_can_trap_p (addr); } /* Return the INSN_LIST containing INSN in LIST, or NULL if LIST does not contain INSN. */ -HAIFA_INLINE rtx -find_insn_list (insn, list) - rtx insn; - rtx list; +rtx +find_insn_list (rtx insn, rtx list) { while (list) { @@ -120,148 +130,103 @@ find_insn_list (insn, list) } return 0; } - -/* Return 1 if the pair (insn, x) is found in (LIST, LIST1), or 0 - otherwise. */ - -HAIFA_INLINE int -find_insn_mem_list (insn, x, list, list1) - rtx insn, x; - rtx list, list1; -{ - while (list) - { - if (XEXP (list, 0) == insn - && XEXP (list1, 0) == x) - return 1; - list = XEXP (list, 1); - list1 = XEXP (list1, 1); - } - return 0; -} /* Find the condition under which INSN is executed. */ static rtx -get_condition (insn) - rtx insn; +sched_get_condition (rtx insn) { rtx pat = PATTERN (insn); - rtx cond; + rtx src; if (pat == 0) return 0; + if (GET_CODE (pat) == COND_EXEC) return COND_EXEC_TEST (pat); - if (GET_CODE (insn) != JUMP_INSN) - return 0; - if (GET_CODE (pat) != SET || SET_SRC (pat) != pc_rtx) - return 0; - if (GET_CODE (SET_DEST (pat)) != IF_THEN_ELSE) - return 0; - pat = SET_DEST (pat); - cond = XEXP (pat, 0); - if (GET_CODE (XEXP (cond, 1)) == LABEL_REF - && XEXP (cond, 2) == pc_rtx) - return cond; - else if (GET_CODE (XEXP (cond, 2)) == LABEL_REF - && XEXP (cond, 1) == pc_rtx) - return gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)), GET_MODE (cond), - XEXP (cond, 0), XEXP (cond, 1)); - else + + if (!any_condjump_p (insn) || !onlyjump_p (insn)) return 0; + + src = SET_SRC (pc_set (insn)); + + if (XEXP (src, 2) == pc_rtx) + return XEXP (src, 0); + else if (XEXP (src, 1) == pc_rtx) + { + rtx cond = XEXP (src, 0); + enum rtx_code revcode = reversed_comparison_code (cond, insn); + + if (revcode == UNKNOWN) + return 0; + return gen_rtx_fmt_ee (revcode, GET_MODE (cond), XEXP (cond, 0), + XEXP (cond, 1)); + } + + return 0; } + /* Return nonzero if conditions COND1 and COND2 can never be both true. */ static int -conditions_mutex_p (cond1, cond2) - rtx cond1, cond2; +conditions_mutex_p (rtx cond1, rtx cond2) { - if (GET_RTX_CLASS (GET_CODE (cond1)) == '<' - && GET_RTX_CLASS (GET_CODE (cond2)) == '<' - && GET_CODE (cond1) == reverse_condition (GET_CODE (cond2)) + if (COMPARISON_P (cond1) + && COMPARISON_P (cond2) + && GET_CODE (cond1) == reversed_comparison_code (cond2, NULL) && XEXP (cond1, 0) == XEXP (cond2, 0) && XEXP (cond1, 1) == XEXP (cond2, 1)) return 1; return 0; } - -/* Add ELEM wrapped in an INSN_LIST with reg note kind DEP_TYPE to the - LOG_LINKS of INSN, if not already there. DEP_TYPE indicates the type - of dependence that this link represents. */ -void -add_dependence (insn, elem, dep_type) - rtx insn; - rtx elem; - enum reg_note dep_type; +/* Return true if insn1 and insn2 can never depend on one another because + the conditions under which they are executed are mutually exclusive. */ +bool +sched_insns_conditions_mutex_p (rtx insn1, rtx insn2) { - rtx link, next; - int present_p; rtx cond1, cond2; - /* Don't depend an insn on itself. */ - if (insn == elem) - return; - - /* We can get a dependency on deleted insns due to optimizations in - the register allocation and reloading or due to splitting. Any - such dependency is useless and can be ignored. */ - if (GET_CODE (elem) == NOTE) - return; - /* flow.c doesn't handle conditional lifetimes entirely correctly; calls mess up the conditional lifetimes. */ - /* ??? add_dependence is the wrong place to be eliding dependencies, - as that forgets that the condition expressions themselves may - be dependent. */ - if (GET_CODE (insn) != CALL_INSN && GET_CODE (elem) != CALL_INSN) + if (!CALL_P (insn1) && !CALL_P (insn2)) { - cond1 = get_condition (insn); - cond2 = get_condition (elem); + cond1 = sched_get_condition (insn1); + cond2 = sched_get_condition (insn2); if (cond1 && cond2 && conditions_mutex_p (cond1, cond2) /* Make sure first instruction doesn't affect condition of second instruction if switched. */ - && !modified_in_p (cond1, elem) + && !modified_in_p (cond1, insn2) /* Make sure second instruction doesn't affect condition of first instruction if switched. */ - && !modified_in_p (cond2, insn)) - return; + && !modified_in_p (cond2, insn1)) + return true; } + return false; +} + +/* Add ELEM wrapped in an INSN_LIST with reg note kind DEP_TYPE to the + LOG_LINKS of INSN, if not already there. DEP_TYPE indicates the + type of dependence that this link represents. The function returns + nonzero if a new entry has been added to insn's LOG_LINK. */ - /* If elem is part of a sequence that must be scheduled together, then - make the dependence point to the last insn of the sequence. - When HAVE_cc0, it is possible for NOTEs to exist between users and - setters of the condition codes, so we must skip past notes here. - Otherwise, NOTEs are impossible here. */ - next = next_nonnote_insn (elem); - if (next && SCHED_GROUP_P (next) - && GET_CODE (next) != CODE_LABEL) - { - /* Notes will never intervene here though, so don't bother checking - for them. */ - /* Hah! Wrong. */ - /* We must reject CODE_LABELs, so that we don't get confused by one - that has LABEL_PRESERVE_P set, which is represented by the same - bit in the rtl as SCHED_GROUP_P. A CODE_LABEL can never be - SCHED_GROUP_P. */ - - rtx nnext; - while ((nnext = next_nonnote_insn (next)) != NULL - && SCHED_GROUP_P (nnext) - && GET_CODE (nnext) != CODE_LABEL) - next = nnext; - - /* Again, don't depend an insn on itself. */ - if (insn == next) - return; +int +add_dependence (rtx insn, rtx elem, enum reg_note dep_type) +{ + rtx link; + int present_p; - /* Make the dependence to NEXT, the last insn of the group, instead - of the original ELEM. */ - elem = next; - } + /* Don't depend an insn on itself. */ + if (insn == elem) + return 0; + + /* We can get a dependency on deleted insns due to optimizations in + the register allocation and reloading or due to splitting. Any + such dependency is useless and can be ignored. */ + if (NOTE_P (elem)) + return 0; present_p = 1; #ifdef INSN_SCHEDULING @@ -272,9 +237,9 @@ add_dependence (insn, elem, dep_type) No need for interblock dependences with calls, since calls are not moved between blocks. Note: the edge where elem is a CALL is still required. */ - if (GET_CODE (insn) == CALL_INSN + if (CALL_P (insn) && (INSN_BB (elem) != INSN_BB (insn))) - return; + return 0; #endif /* If we already have a dependency for ELEM, then we do not need to @@ -284,21 +249,22 @@ add_dependence (insn, elem, dep_type) { enum reg_note present_dep_type = 0; - if (anti_dependency_cache == NULL || output_dependency_cache == NULL) - abort (); - if (TEST_BIT (true_dependency_cache[INSN_LUID (insn)], INSN_LUID (elem))) + gcc_assert (anti_dependency_cache); + gcc_assert (output_dependency_cache); + if (bitmap_bit_p (&true_dependency_cache[INSN_LUID (insn)], + INSN_LUID (elem))) /* Do nothing (present_set_type is already 0). */ ; - else if (TEST_BIT (anti_dependency_cache[INSN_LUID (insn)], + else if (bitmap_bit_p (&anti_dependency_cache[INSN_LUID (insn)], INSN_LUID (elem))) present_dep_type = REG_DEP_ANTI; - else if (TEST_BIT (output_dependency_cache[INSN_LUID (insn)], + else if (bitmap_bit_p (&output_dependency_cache[INSN_LUID (insn)], INSN_LUID (elem))) present_dep_type = REG_DEP_OUTPUT; - else + else present_p = 0; if (present_p && (int) dep_type >= (int) present_dep_type) - return; + return 0; } #endif @@ -312,15 +278,21 @@ add_dependence (insn, elem, dep_type) may be changed. */ if (true_dependency_cache != NULL) { - if (REG_NOTE_KIND (link) == REG_DEP_ANTI) - RESET_BIT (anti_dependency_cache[INSN_LUID (insn)], - INSN_LUID (elem)); - else if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT - && output_dependency_cache) - RESET_BIT (output_dependency_cache[INSN_LUID (insn)], - INSN_LUID (elem)); - else - abort (); + enum reg_note kind = REG_NOTE_KIND (link); + switch (kind) + { + case REG_DEP_ANTI: + bitmap_clear_bit (&anti_dependency_cache[INSN_LUID (insn)], + INSN_LUID (elem)); + break; + case REG_DEP_OUTPUT: + gcc_assert (output_dependency_cache); + bitmap_clear_bit (&output_dependency_cache[INSN_LUID (insn)], + INSN_LUID (elem)); + break; + default: + gcc_unreachable (); + } } #endif @@ -328,25 +300,25 @@ add_dependence (insn, elem, dep_type) one, then change the existing dependence to this type. */ if ((int) dep_type < (int) REG_NOTE_KIND (link)) PUT_REG_NOTE_KIND (link, dep_type); - + #ifdef INSN_SCHEDULING /* If we are adding a dependency to INSN's LOG_LINKs, then note that in the bitmap caches of dependency information. */ if (true_dependency_cache != NULL) { - if ((int)REG_NOTE_KIND (link) == 0) - SET_BIT (true_dependency_cache[INSN_LUID (insn)], - INSN_LUID (elem)); + if ((int) REG_NOTE_KIND (link) == 0) + bitmap_set_bit (&true_dependency_cache[INSN_LUID (insn)], + INSN_LUID (elem)); else if (REG_NOTE_KIND (link) == REG_DEP_ANTI) - SET_BIT (anti_dependency_cache[INSN_LUID (insn)], - INSN_LUID (elem)); + bitmap_set_bit (&anti_dependency_cache[INSN_LUID (insn)], + INSN_LUID (elem)); else if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT) - SET_BIT (output_dependency_cache[INSN_LUID (insn)], - INSN_LUID (elem)); + bitmap_set_bit (&output_dependency_cache[INSN_LUID (insn)], + INSN_LUID (elem)); } #endif - return; - } + return 0; + } /* Might want to check one level of transitivity to save conses. */ link = alloc_INSN_LIST (elem, LOG_LINKS (insn)); @@ -360,112 +332,95 @@ add_dependence (insn, elem, dep_type) in the bitmap caches of dependency information. */ if (true_dependency_cache != NULL) { - if ((int)dep_type == 0) - SET_BIT (true_dependency_cache[INSN_LUID (insn)], INSN_LUID (elem)); + if ((int) dep_type == 0) + bitmap_set_bit (&true_dependency_cache[INSN_LUID (insn)], INSN_LUID (elem)); else if (dep_type == REG_DEP_ANTI) - SET_BIT (anti_dependency_cache[INSN_LUID (insn)], INSN_LUID (elem)); + bitmap_set_bit (&anti_dependency_cache[INSN_LUID (insn)], INSN_LUID (elem)); else if (dep_type == REG_DEP_OUTPUT) - SET_BIT (output_dependency_cache[INSN_LUID (insn)], INSN_LUID (elem)); + bitmap_set_bit (&output_dependency_cache[INSN_LUID (insn)], INSN_LUID (elem)); } #endif + return 1; } -/* Remove ELEM wrapped in an INSN_LIST from the LOG_LINKS - of INSN. Abort if not found. */ +/* A convenience wrapper to operate on an entire list. */ static void -remove_dependence (insn, elem) - rtx insn; - rtx elem; +add_dependence_list (rtx insn, rtx list, enum reg_note dep_type) { - rtx prev, link, next; - int found = 0; - - for (prev = 0, link = LOG_LINKS (insn); link; link = next) + for (; list; list = XEXP (list, 1)) { - next = XEXP (link, 1); - if (XEXP (link, 0) == elem) - { - if (prev) - XEXP (prev, 1) = next; - else - LOG_LINKS (insn) = next; - -#ifdef INSN_SCHEDULING - /* If we are removing a dependency from the LOG_LINKS list, - make sure to remove it from the cache too. */ - if (true_dependency_cache != NULL) - { - if (REG_NOTE_KIND (link) == 0) - RESET_BIT (true_dependency_cache[INSN_LUID (insn)], - INSN_LUID (elem)); - else if (REG_NOTE_KIND (link) == REG_DEP_ANTI) - RESET_BIT (anti_dependency_cache[INSN_LUID (insn)], - INSN_LUID (elem)); - else if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT) - RESET_BIT (output_dependency_cache[INSN_LUID (insn)], - INSN_LUID (elem)); - } -#endif + if (! sched_insns_conditions_mutex_p (insn, XEXP (list, 0))) + add_dependence (insn, XEXP (list, 0), dep_type); + } +} - free_INSN_LIST_node (link); +/* Similar, but free *LISTP at the same time. */ - found = 1; - } - else - prev = link; +static void +add_dependence_list_and_free (rtx insn, rtx *listp, enum reg_note dep_type) +{ + rtx list, next; + for (list = *listp, *listp = NULL; list ; list = next) + { + next = XEXP (list, 1); + if (! sched_insns_conditions_mutex_p (insn, XEXP (list, 0))) + add_dependence (insn, XEXP (list, 0), dep_type); + free_INSN_LIST_node (list); } - - if (!found) - abort (); - return; } -/* Return an insn which represents a SCHED_GROUP, which is - the last insn in the group. */ +/* Clear all dependencies for an insn. */ -static rtx -group_leader (insn) - rtx insn; +static void +delete_all_dependences (rtx insn) { - rtx prev; + /* Clear caches, if they exist, as well as free the dependence. */ - do +#ifdef INSN_SCHEDULING + if (true_dependency_cache != NULL) { - prev = insn; - insn = next_nonnote_insn (insn); + bitmap_clear (&true_dependency_cache[INSN_LUID (insn)]); + bitmap_clear (&anti_dependency_cache[INSN_LUID (insn)]); + bitmap_clear (&output_dependency_cache[INSN_LUID (insn)]); } - while (insn && SCHED_GROUP_P (insn) && (GET_CODE (insn) != CODE_LABEL)); +#endif - return prev; + free_INSN_LIST_list (&LOG_LINKS (insn)); } -/* Set SCHED_GROUP_P and care for the rest of the bookkeeping that - goes along with that. */ +/* All insns in a scheduling group except the first should only have + dependencies on the previous insn in the group. So we find the + first instruction in the scheduling group by walking the dependence + chains backwards. Then we add the dependencies for the group to + the previous nonnote insn. */ static void -set_sched_group_p (insn) - rtx insn; +fixup_sched_groups (rtx insn) { - rtx link, prev; - - SCHED_GROUP_P (insn) = 1; + rtx link, prev_nonnote; - /* There may be a note before this insn now, but all notes will - be removed before we actually try to schedule the insns, so - it won't cause a problem later. We must avoid it here though. */ - prev = prev_nonnote_insn (insn); - - /* Make a copy of all dependencies on the immediately previous insn, - and add to this insn. This is so that all the dependencies will - apply to the group. Remove an explicit dependence on this insn - as SCHED_GROUP_P now represents it. */ + for (link = LOG_LINKS (insn); link ; link = XEXP (link, 1)) + { + rtx i = insn; + do + { + i = prev_nonnote_insn (i); + + if (XEXP (link, 0) == i) + goto next_link; + } while (SCHED_GROUP_P (i)); + if (! sched_insns_conditions_mutex_p (i, XEXP (link, 0))) + add_dependence (i, XEXP (link, 0), REG_NOTE_KIND (link)); + next_link:; + } - if (find_insn_list (prev, LOG_LINKS (insn))) - remove_dependence (insn, prev); + delete_all_dependences (insn); - for (link = LOG_LINKS (prev); link; link = XEXP (link, 1)) - add_dependence (insn, XEXP (link, 0), REG_NOTE_KIND (link)); + prev_nonnote = prev_nonnote_insn (insn); + if (BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (prev_nonnote) + && ! sched_insns_conditions_mutex_p (insn, prev_nonnote)) + add_dependence (insn, prev_nonnote, REG_DEP_ANTI); } /* Process an insn's memory dependencies. There are four kinds of @@ -483,12 +438,11 @@ set_sched_group_p (insn) The MEM is a memory reference contained within INSN, which we are saving so that we can do memory aliasing on it. */ -void -add_insn_mem_dependence (deps, insn_list, mem_list, insn, mem) - struct deps *deps; - rtx *insn_list, *mem_list, insn, mem; +static void +add_insn_mem_dependence (struct deps *deps, rtx *insn_list, rtx *mem_list, + rtx insn, rtx mem) { - register rtx link; + rtx link; link = alloc_INSN_LIST (insn, *insn_list); *insn_list = link; @@ -498,58 +452,34 @@ add_insn_mem_dependence (deps, insn_list, mem_list, insn, mem) mem = shallow_copy_rtx (mem); XEXP (mem, 0) = cselib_subst_to_values (XEXP (mem, 0)); } - link = alloc_EXPR_LIST (VOIDmode, mem, *mem_list); + link = alloc_EXPR_LIST (VOIDmode, canon_rtx (mem), *mem_list); *mem_list = link; deps->pending_lists_length++; } /* Make a dependency between every memory reference on the pending lists - and INSN, thus flushing the pending lists. If ONLY_WRITE, don't flush - the read list. */ + and INSN, thus flushing the pending lists. FOR_READ is true if emitting + dependencies for a read operation, similarly with FOR_WRITE. */ static void -flush_pending_lists (deps, insn, only_write) - struct deps *deps; - rtx insn; - int only_write; +flush_pending_lists (struct deps *deps, rtx insn, int for_read, + int for_write) { - rtx u; - rtx link; - - while (deps->pending_read_insns && ! only_write) + if (for_write) { - add_dependence (insn, XEXP (deps->pending_read_insns, 0), - REG_DEP_ANTI); - - link = deps->pending_read_insns; - deps->pending_read_insns = XEXP (deps->pending_read_insns, 1); - free_INSN_LIST_node (link); - - link = deps->pending_read_mems; - deps->pending_read_mems = XEXP (deps->pending_read_mems, 1); - free_EXPR_LIST_node (link); + add_dependence_list_and_free (insn, &deps->pending_read_insns, + REG_DEP_ANTI); + free_EXPR_LIST_list (&deps->pending_read_mems); } - while (deps->pending_write_insns) - { - add_dependence (insn, XEXP (deps->pending_write_insns, 0), - REG_DEP_ANTI); - - link = deps->pending_write_insns; - deps->pending_write_insns = XEXP (deps->pending_write_insns, 1); - free_INSN_LIST_node (link); - link = deps->pending_write_mems; - deps->pending_write_mems = XEXP (deps->pending_write_mems, 1); - free_EXPR_LIST_node (link); - } + add_dependence_list_and_free (insn, &deps->pending_write_insns, + for_read ? REG_DEP_ANTI : REG_DEP_OUTPUT); + free_EXPR_LIST_list (&deps->pending_write_mems); deps->pending_lists_length = 0; - /* last_pending_memory_flush is now a list of insns. */ - for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); - - free_INSN_LIST_list (&deps->last_pending_memory_flush); + add_dependence_list_and_free (insn, &deps->last_pending_memory_flush, + for_read ? REG_DEP_ANTI : REG_DEP_OUTPUT); deps->last_pending_memory_flush = alloc_INSN_LIST (insn, NULL_RTX); deps->pending_flush_length = 1; } @@ -559,13 +489,10 @@ flush_pending_lists (deps, insn, only_write) destination of X, and reads of everything mentioned. */ static void -sched_analyze_1 (deps, x, insn) - struct deps *deps; - rtx x; - rtx insn; +sched_analyze_1 (struct deps *deps, rtx x, rtx insn) { - register int regno; - register rtx dest = XEXP (x, 0); + int regno; + rtx dest = XEXP (x, 0); enum rtx_code code = GET_CODE (x); if (dest == 0) @@ -573,7 +500,7 @@ sched_analyze_1 (deps, x, insn) if (GET_CODE (dest) == PARALLEL) { - register int i; + int i; for (i = XVECLEN (dest, 0) - 1; i >= 0; i--) if (XEXP (XVECEXP (dest, 0, i), 0) != 0) @@ -588,9 +515,21 @@ sched_analyze_1 (deps, x, insn) } while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG - || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT) + || GET_CODE (dest) == ZERO_EXTRACT) { - if (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT) + if (GET_CODE (dest) == STRICT_LOW_PART + || GET_CODE (dest) == ZERO_EXTRACT + || read_modify_subreg_p (dest)) + { + /* These both read and modify the result. We must handle + them as writes to get proper dependencies for following + instructions. We must handle them as reads to get proper + dependencies from this to previous instructions. + Thus we need to call sched_analyze_2. */ + + sched_analyze_2 (deps, XEXP (dest, 0), insn); + } + if (GET_CODE (dest) == ZERO_EXTRACT) { /* The second and third arguments are values read by this insn. */ sched_analyze_2 (deps, XEXP (dest, 1), insn); @@ -599,48 +538,33 @@ sched_analyze_1 (deps, x, insn) dest = XEXP (dest, 0); } - if (GET_CODE (dest) == REG) + if (REG_P (dest)) { - register int i; - regno = REGNO (dest); +#ifdef STACK_REGS + /* Treat all writes to a stack register as modifying the TOS. */ + if (regno >= FIRST_STACK_REG && regno <= LAST_STACK_REG) + { + SET_REGNO_REG_SET (reg_pending_uses, FIRST_STACK_REG); + regno = FIRST_STACK_REG; + } +#endif + /* A hard reg in a wide mode may really be multiple registers. If so, mark all of them just like the first. */ if (regno < FIRST_PSEUDO_REGISTER) { - i = HARD_REGNO_NREGS (regno, GET_MODE (dest)); - while (--i >= 0) + int i = hard_regno_nregs[regno][GET_MODE (dest)]; + if (code == SET) { - int r = regno + i; - rtx u; - - for (u = deps->reg_last[r].uses; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); - - for (u = deps->reg_last[r].sets; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_OUTPUT); - - /* Clobbers need not be ordered with respect to one - another, but sets must be ordered with respect to a - pending clobber. */ - if (code == SET) - { - if (GET_CODE (PATTERN (insn)) != COND_EXEC) - free_INSN_LIST_list (&deps->reg_last[r].uses); - for (u = deps->reg_last[r].clobbers; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_OUTPUT); - SET_REGNO_REG_SET (reg_pending_sets, r); - } - else - SET_REGNO_REG_SET (reg_pending_clobbers, r); - - /* Function calls clobber all call_used regs. */ - if (global_regs[r] - || (code == SET - && TEST_HARD_REG_BIT (regs_invalidated_by_call, r))) - for (u = deps->last_function_call; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); + while (--i >= 0) + SET_REGNO_REG_SET (reg_pending_sets, regno + i); + } + else + { + while (--i >= 0) + SET_REGNO_REG_SET (reg_pending_clobbers, regno + i); } } /* ??? Reload sometimes emits USEs and CLOBBERs of pseudos that @@ -648,48 +572,33 @@ sched_analyze_1 (deps, x, insn) purpose already. */ else if (regno >= deps->max_reg) { - if (GET_CODE (PATTERN (insn)) != USE - && GET_CODE (PATTERN (insn)) != CLOBBER) - abort (); + gcc_assert (GET_CODE (PATTERN (insn)) == USE + || GET_CODE (PATTERN (insn)) == CLOBBER); } else { - rtx u; - - for (u = deps->reg_last[regno].uses; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); - - for (u = deps->reg_last[regno].sets; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_OUTPUT); - if (code == SET) - { - if (GET_CODE (PATTERN (insn)) != COND_EXEC) - free_INSN_LIST_list (&deps->reg_last[regno].uses); - for (u = deps->reg_last[regno].clobbers; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_OUTPUT); - SET_REGNO_REG_SET (reg_pending_sets, regno); - } + SET_REGNO_REG_SET (reg_pending_sets, regno); else SET_REGNO_REG_SET (reg_pending_clobbers, regno); /* Pseudos that are REG_EQUIV to something may be replaced by that during reloading. We need only add dependencies for the address in the REG_EQUIV note. */ - if (!reload_completed - && reg_known_equiv_p[regno] - && GET_CODE (reg_known_value[regno]) == MEM) - sched_analyze_2 (deps, XEXP (reg_known_value[regno], 0), insn); + if (!reload_completed && get_reg_known_equiv_p (regno)) + { + rtx t = get_reg_known_value (regno); + if (MEM_P (t)) + sched_analyze_2 (deps, XEXP (t, 0), insn); + } /* Don't let it cross a call after scheduling if it doesn't already cross one. */ - if (REG_N_CALLS_CROSSED (regno) == 0) - for (u = deps->last_function_call; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); + add_dependence_list (insn, deps->last_function_call, REG_DEP_ANTI); } } - else if (GET_CODE (dest) == MEM) + else if (MEM_P (dest)) { /* Writing memory. */ rtx t = dest; @@ -700,6 +609,7 @@ sched_analyze_1 (deps, x, insn) cselib_lookup (XEXP (t, 0), Pmode, 1); XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0)); } + t = canon_rtx (t); if (deps->pending_lists_length > MAX_PENDING_LIST_LENGTH) { @@ -708,18 +618,18 @@ sched_analyze_1 (deps, x, insn) these lists get long. When compiling GCC with itself, this flush occurs 8 times for sparc, and 10 times for m88k using the default value of 32. */ - flush_pending_lists (deps, insn, 0); + flush_pending_lists (deps, insn, false, true); } else { - rtx u; rtx pending, pending_mem; pending = deps->pending_read_insns; pending_mem = deps->pending_read_mems; while (pending) { - if (anti_dependence (XEXP (pending_mem, 0), t)) + if (anti_dependence (XEXP (pending_mem, 0), t) + && ! sched_insns_conditions_mutex_p (insn, XEXP (pending, 0))) add_dependence (insn, XEXP (pending, 0), REG_DEP_ANTI); pending = XEXP (pending, 1); @@ -730,15 +640,16 @@ sched_analyze_1 (deps, x, insn) pending_mem = deps->pending_write_mems; while (pending) { - if (output_dependence (XEXP (pending_mem, 0), t)) + if (output_dependence (XEXP (pending_mem, 0), t) + && ! sched_insns_conditions_mutex_p (insn, XEXP (pending, 0))) add_dependence (insn, XEXP (pending, 0), REG_DEP_OUTPUT); pending = XEXP (pending, 1); pending_mem = XEXP (pending_mem, 1); } - for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); + add_dependence_list (insn, deps->last_pending_memory_flush, + REG_DEP_ANTI); add_insn_mem_dependence (deps, &deps->pending_write_insns, &deps->pending_write_mems, insn, dest); @@ -754,15 +665,12 @@ sched_analyze_1 (deps, x, insn) /* Analyze the uses of memory and registers in rtx X in INSN. */ static void -sched_analyze_2 (deps, x, insn) - struct deps *deps; - rtx x; - rtx insn; +sched_analyze_2 (struct deps *deps, rtx x, rtx insn) { - register int i; - register int j; - register enum rtx_code code; - register const char *fmt; + int i; + int j; + enum rtx_code code; + const char *fmt; if (x == 0) return; @@ -773,6 +681,7 @@ sched_analyze_2 (deps, x, insn) { case CONST_INT: case CONST_DOUBLE: + case CONST_VECTOR: case SYMBOL_REF: case CONST: case LABEL_REF: @@ -784,75 +693,60 @@ sched_analyze_2 (deps, x, insn) #ifdef HAVE_cc0 case CC0: /* User of CC0 depends on immediately preceding insn. */ - set_sched_group_p (insn); + SCHED_GROUP_P (insn) = 1; + /* Don't move CC0 setter to another block (it can set up the + same flag for previous CC0 users which is safe). */ + CANT_MOVE (prev_nonnote_insn (insn)) = 1; return; #endif case REG: { - rtx u; int regno = REGNO (x); + +#ifdef STACK_REGS + /* Treat all reads of a stack register as modifying the TOS. */ + if (regno >= FIRST_STACK_REG && regno <= LAST_STACK_REG) + { + SET_REGNO_REG_SET (reg_pending_sets, FIRST_STACK_REG); + regno = FIRST_STACK_REG; + } +#endif + if (regno < FIRST_PSEUDO_REGISTER) { - int i; - - i = HARD_REGNO_NREGS (regno, GET_MODE (x)); + int i = hard_regno_nregs[regno][GET_MODE (x)]; while (--i >= 0) - { - int r = regno + i; - deps->reg_last[r].uses - = alloc_INSN_LIST (insn, deps->reg_last[r].uses); - SET_REGNO_REG_SET (&deps->reg_last_in_use, r); - - for (u = deps->reg_last[r].sets; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), 0); - - /* ??? This should never happen. */ - for (u = deps->reg_last[r].clobbers; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), 0); - - if (call_used_regs[r] || global_regs[r]) - /* Function calls clobber all call_used regs. */ - for (u = deps->last_function_call; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); - } + SET_REGNO_REG_SET (reg_pending_uses, regno + i); } /* ??? Reload sometimes emits USEs and CLOBBERs of pseudos that it does not reload. Ignore these as they have served their purpose already. */ else if (regno >= deps->max_reg) { - if (GET_CODE (PATTERN (insn)) != USE - && GET_CODE (PATTERN (insn)) != CLOBBER) - abort (); + gcc_assert (GET_CODE (PATTERN (insn)) == USE + || GET_CODE (PATTERN (insn)) == CLOBBER); } else { - deps->reg_last[regno].uses - = alloc_INSN_LIST (insn, deps->reg_last[regno].uses); - SET_REGNO_REG_SET (&deps->reg_last_in_use, regno); - - for (u = deps->reg_last[regno].sets; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), 0); - - /* ??? This should never happen. */ - for (u = deps->reg_last[regno].clobbers; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), 0); + SET_REGNO_REG_SET (reg_pending_uses, regno); /* Pseudos that are REG_EQUIV to something may be replaced by that during reloading. We need only add dependencies for the address in the REG_EQUIV note. */ - if (!reload_completed - && reg_known_equiv_p[regno] - && GET_CODE (reg_known_value[regno]) == MEM) - sched_analyze_2 (deps, XEXP (reg_known_value[regno], 0), insn); + if (!reload_completed && get_reg_known_equiv_p (regno)) + { + rtx t = get_reg_known_value (regno); + if (MEM_P (t)) + sched_analyze_2 (deps, XEXP (t, 0), insn); + } /* If the register does not already cross any calls, then add this insn to the sched_before_next_call list so that it will still not cross calls after scheduling. */ if (REG_N_CALLS_CROSSED (regno) == 0) - add_dependence (deps->sched_before_next_call, insn, - REG_DEP_ANTI); + deps->sched_before_next_call + = alloc_INSN_LIST (insn, deps->sched_before_next_call); } return; } @@ -870,11 +764,13 @@ sched_analyze_2 (deps, x, insn) cselib_lookup (XEXP (t, 0), Pmode, 1); XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0)); } + t = canon_rtx (t); pending = deps->pending_read_insns; pending_mem = deps->pending_read_mems; while (pending) { - if (read_dependence (XEXP (pending_mem, 0), t)) + if (read_dependence (XEXP (pending_mem, 0), t) + && ! sched_insns_conditions_mutex_p (insn, XEXP (pending, 0))) add_dependence (insn, XEXP (pending, 0), REG_DEP_ANTI); pending = XEXP (pending, 1); @@ -886,16 +782,17 @@ sched_analyze_2 (deps, x, insn) while (pending) { if (true_dependence (XEXP (pending_mem, 0), VOIDmode, - t, rtx_varies_p)) - add_dependence (insn, XEXP (pending, 0), 0); + t, rtx_varies_p) + && ! sched_insns_conditions_mutex_p (insn, XEXP (pending, 0))) + add_dependence (insn, XEXP (pending, 0), REG_DEP_TRUE); pending = XEXP (pending, 1); pending_mem = XEXP (pending_mem, 1); } for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1)) - if (GET_CODE (XEXP (u, 0)) != JUMP_INSN - || deps_may_trap_p (x)) + if ((! JUMP_P (XEXP (u, 0)) || deps_may_trap_p (x)) + && ! sched_insns_conditions_mutex_p (insn, XEXP (u, 0))) add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); /* Always add these dependencies to pending_reads, since @@ -910,15 +807,13 @@ sched_analyze_2 (deps, x, insn) /* Force pending stores to memory in case a trap handler needs them. */ case TRAP_IF: - flush_pending_lists (deps, insn, 1); + flush_pending_lists (deps, insn, true, false); break; case ASM_OPERANDS: case ASM_INPUT: case UNSPEC_VOLATILE: { - rtx u; - /* Traditional and volatile asm instructions must be considered to use and clobber all hard registers, all pseudo-registers and all of memory. So must TRAP_IF and UNSPEC_VOLATILE operations. @@ -927,25 +822,7 @@ sched_analyze_2 (deps, x, insn) mode. An insn should not be moved across this even if it only uses pseudo-regs because it might give an incorrectly rounded result. */ if (code != ASM_OPERANDS || MEM_VOLATILE_P (x)) - { - for (i = 0; i < deps->max_reg; i++) - { - struct deps_reg *reg_last = &deps->reg_last[i]; - - for (u = reg_last->uses; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); - for (u = reg_last->sets; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), 0); - for (u = reg_last->clobbers; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), 0); - - if (GET_CODE (PATTERN (insn)) != COND_EXEC) - free_INSN_LIST_list (®_last->uses); - } - reg_pending_sets_all = 1; - - flush_pending_lists (deps, insn, 0); - } + reg_pending_barrier = TRUE_BARRIER; /* 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 @@ -1002,31 +879,35 @@ sched_analyze_2 (deps, x, insn) /* Analyze an INSN with pattern X to find all dependencies. */ static void -sched_analyze_insn (deps, x, insn, loop_notes) - struct deps *deps; - rtx x, insn; - rtx loop_notes; +sched_analyze_insn (struct deps *deps, rtx x, rtx insn, rtx loop_notes) { - register RTX_CODE code = GET_CODE (x); - int schedule_barrier_found = 0; + RTX_CODE code = GET_CODE (x); rtx link; - int i; + unsigned i; + reg_set_iterator rsi; if (code == COND_EXEC) { sched_analyze_2 (deps, COND_EXEC_TEST (x), insn); /* ??? Should be recording conditions so we reduce the number of - false dependancies. */ + false dependencies. */ x = COND_EXEC_CODE (x); code = GET_CODE (x); } if (code == SET || code == CLOBBER) - sched_analyze_1 (deps, x, insn); + { + sched_analyze_1 (deps, x, insn); + + /* Bare clobber insns are used for letting life analysis, reg-stack + and others know that a value is dead. Depend on the last call + instruction so that reg-stack won't get confused. */ + if (code == CLOBBER) + add_dependence_list (insn, deps->last_function_call, REG_DEP_OUTPUT); + } else if (code == PARALLEL) { - register int i; - for (i = XVECLEN (x, 0) - 1; i >= 0; i--) + for (i = XVECLEN (x, 0); i--;) { rtx sub = XVECEXP (x, 0, i); code = GET_CODE (sub); @@ -1047,7 +928,7 @@ sched_analyze_insn (deps, x, insn, loop_notes) sched_analyze_2 (deps, x, insn); /* Mark registers CLOBBERED or used by called function. */ - if (GET_CODE (insn) == CALL_INSN) + if (CALL_P (insn)) { for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1)) { @@ -1057,32 +938,37 @@ sched_analyze_insn (deps, x, insn, loop_notes) sched_analyze_2 (deps, XEXP (link, 0), insn); } if (find_reg_note (insn, REG_SETJMP, NULL)) - schedule_barrier_found = 1; + reg_pending_barrier = MOVE_BARRIER; } - if (GET_CODE (insn) == JUMP_INSN) + if (JUMP_P (insn)) { rtx next; next = next_nonnote_insn (insn); - if (next && GET_CODE (next) == BARRIER) - schedule_barrier_found = 1; + if (next && BARRIER_P (next)) + reg_pending_barrier = TRUE_BARRIER; else { - rtx pending, pending_mem, u; - regset_head tmp; - INIT_REG_SET (&tmp); - - (*current_sched_info->compute_jump_reg_dependencies) (insn, &tmp); - EXECUTE_IF_SET_IN_REG_SET (&tmp, 0, i, + rtx pending, pending_mem; + regset_head tmp_uses, tmp_sets; + INIT_REG_SET (&tmp_uses); + INIT_REG_SET (&tmp_sets); + + (*current_sched_info->compute_jump_reg_dependencies) + (insn, &deps->reg_conditional_sets, &tmp_uses, &tmp_sets); + /* Make latency of jump equal to 0 by using anti-dependence. */ + EXECUTE_IF_SET_IN_REG_SET (&tmp_uses, 0, i, rsi) { struct deps_reg *reg_last = &deps->reg_last[i]; - for (u = reg_last->sets; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); + add_dependence_list (insn, reg_last->sets, REG_DEP_ANTI); + add_dependence_list (insn, reg_last->clobbers, REG_DEP_ANTI); + reg_last->uses_length++; reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses); - SET_REGNO_REG_SET (&deps->reg_last_in_use, i); - }); + } + IOR_REG_SET (reg_pending_sets, &tmp_sets); - CLEAR_REG_SET (&tmp); + CLEAR_REG_SET (&tmp_uses); + CLEAR_REG_SET (&tmp_sets); /* All memory writes and volatile reads must happen before the jump. Non-volatile reads must happen before the jump iff @@ -1092,7 +978,8 @@ sched_analyze_insn (deps, x, insn, loop_notes) pending_mem = deps->pending_write_mems; while (pending) { - add_dependence (insn, XEXP (pending, 0), REG_DEP_OUTPUT); + if (! sched_insns_conditions_mutex_p (insn, XEXP (pending, 0))) + add_dependence (insn, XEXP (pending, 0), REG_DEP_OUTPUT); pending = XEXP (pending, 1); pending_mem = XEXP (pending_mem, 1); } @@ -1101,14 +988,15 @@ sched_analyze_insn (deps, x, insn, loop_notes) pending_mem = deps->pending_read_mems; while (pending) { - if (MEM_VOLATILE_P (XEXP (pending_mem, 0))) + if (MEM_VOLATILE_P (XEXP (pending_mem, 0)) + && ! sched_insns_conditions_mutex_p (insn, XEXP (pending, 0))) add_dependence (insn, XEXP (pending, 0), REG_DEP_OUTPUT); pending = XEXP (pending, 1); pending_mem = XEXP (pending_mem, 1); } - for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); + add_dependence_list (insn, deps->last_pending_memory_flush, + REG_DEP_ANTI); } } @@ -1120,18 +1008,14 @@ sched_analyze_insn (deps, x, insn, loop_notes) { rtx link; - /* Update loop_notes with any notes from this insn. Also determine - if any of the notes on the list correspond to instruction scheduling - barriers (loop, eh & setjmp notes, but not range notes). */ + /* Update loop_notes with any notes from this insn. */ link = loop_notes; while (XEXP (link, 1)) { - if (INTVAL (XEXP (link, 0)) == NOTE_INSN_LOOP_BEG - || INTVAL (XEXP (link, 0)) == NOTE_INSN_LOOP_END - || INTVAL (XEXP (link, 0)) == NOTE_INSN_EH_REGION_BEG - || INTVAL (XEXP (link, 0)) == NOTE_INSN_EH_REGION_END) - schedule_barrier_found = 1; + gcc_assert (INTVAL (XEXP (link, 0)) == NOTE_INSN_LOOP_BEG + || INTVAL (XEXP (link, 0)) == NOTE_INSN_LOOP_END); + reg_pending_barrier = MOVE_BARRIER; link = XEXP (link, 1); } XEXP (link, 1) = REG_NOTES (insn); @@ -1139,75 +1023,158 @@ sched_analyze_insn (deps, x, insn, loop_notes) } /* If this instruction can throw an exception, then moving it changes - where block boundaries fall. This is mighty confusing elsewhere. + where block boundaries fall. This is mighty confusing elsewhere. Therefore, prevent such an instruction from being moved. */ - if (flag_non_call_exceptions && can_throw_internal (insn)) - schedule_barrier_found = 1; + if (can_throw_internal (insn)) + reg_pending_barrier = MOVE_BARRIER; /* Add dependencies if a scheduling barrier was found. */ - if (schedule_barrier_found) + if (reg_pending_barrier) { - rtx u; - - for (i = 0; i < deps->max_reg; i++) + /* In the case of barrier the most added dependencies are not + real, so we use anti-dependence here. */ + if (sched_get_condition (insn)) { - struct deps_reg *reg_last = &deps->reg_last[i]; - - for (u = reg_last->uses; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); - for (u = reg_last->sets; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), 0); - for (u = reg_last->clobbers; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), 0); - - if (GET_CODE (PATTERN (insn)) != COND_EXEC) - free_INSN_LIST_list (®_last->uses); + EXECUTE_IF_SET_IN_REG_SET (&deps->reg_last_in_use, 0, i, rsi) + { + struct deps_reg *reg_last = &deps->reg_last[i]; + add_dependence_list (insn, reg_last->uses, REG_DEP_ANTI); + add_dependence_list + (insn, reg_last->sets, + reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI); + add_dependence_list + (insn, reg_last->clobbers, + reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI); + } } - flush_pending_lists (deps, insn, 0); - - reg_pending_sets_all = 1; - } - - /* Accumulate clobbers until the next set so that it will be output - dependent on all of them. At the next set we can clear the clobber - list, since subsequent sets will be output dependent on it. */ - if (reg_pending_sets_all) - { - reg_pending_sets_all = 0; - for (i = 0; i < deps->max_reg; i++) + else { - struct deps_reg *reg_last = &deps->reg_last[i]; - if (GET_CODE (PATTERN (insn)) != COND_EXEC) + EXECUTE_IF_SET_IN_REG_SET (&deps->reg_last_in_use, 0, i, rsi) { - free_INSN_LIST_list (®_last->sets); - free_INSN_LIST_list (®_last->clobbers); + struct deps_reg *reg_last = &deps->reg_last[i]; + add_dependence_list_and_free (insn, ®_last->uses, + REG_DEP_ANTI); + add_dependence_list_and_free + (insn, ®_last->sets, + reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI); + add_dependence_list_and_free + (insn, ®_last->clobbers, + reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI); + reg_last->uses_length = 0; + reg_last->clobbers_length = 0; } + } + + for (i = 0; i < (unsigned)deps->max_reg; i++) + { + struct deps_reg *reg_last = &deps->reg_last[i]; reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets); SET_REGNO_REG_SET (&deps->reg_last_in_use, i); } + + flush_pending_lists (deps, insn, true, true); + CLEAR_REG_SET (&deps->reg_conditional_sets); + reg_pending_barrier = NOT_A_BARRIER; } else { - EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, + /* If the current insn is conditional, we can't free any + of the lists. */ + if (sched_get_condition (insn)) { - struct deps_reg *reg_last = &deps->reg_last[i]; - if (GET_CODE (PATTERN (insn)) != COND_EXEC) + EXECUTE_IF_SET_IN_REG_SET (reg_pending_uses, 0, i, rsi) { - free_INSN_LIST_list (®_last->sets); - free_INSN_LIST_list (®_last->clobbers); + struct deps_reg *reg_last = &deps->reg_last[i]; + add_dependence_list (insn, reg_last->sets, REG_DEP_TRUE); + add_dependence_list (insn, reg_last->clobbers, REG_DEP_TRUE); + reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses); + reg_last->uses_length++; } - reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets); - SET_REGNO_REG_SET (&deps->reg_last_in_use, i); - }); - EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, + EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi) + { + struct deps_reg *reg_last = &deps->reg_last[i]; + add_dependence_list (insn, reg_last->sets, REG_DEP_OUTPUT); + add_dependence_list (insn, reg_last->uses, REG_DEP_ANTI); + reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers); + reg_last->clobbers_length++; + } + EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi) + { + struct deps_reg *reg_last = &deps->reg_last[i]; + add_dependence_list (insn, reg_last->sets, REG_DEP_OUTPUT); + add_dependence_list (insn, reg_last->clobbers, REG_DEP_OUTPUT); + add_dependence_list (insn, reg_last->uses, REG_DEP_ANTI); + reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets); + SET_REGNO_REG_SET (&deps->reg_conditional_sets, i); + } + } + else { - struct deps_reg *reg_last = &deps->reg_last[i]; - reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers); - SET_REGNO_REG_SET (&deps->reg_last_in_use, i); - }); + EXECUTE_IF_SET_IN_REG_SET (reg_pending_uses, 0, i, rsi) + { + struct deps_reg *reg_last = &deps->reg_last[i]; + add_dependence_list (insn, reg_last->sets, REG_DEP_TRUE); + add_dependence_list (insn, reg_last->clobbers, REG_DEP_TRUE); + reg_last->uses_length++; + reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses); + } + EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi) + { + struct deps_reg *reg_last = &deps->reg_last[i]; + if (reg_last->uses_length > MAX_PENDING_LIST_LENGTH + || reg_last->clobbers_length > MAX_PENDING_LIST_LENGTH) + { + add_dependence_list_and_free (insn, ®_last->sets, + REG_DEP_OUTPUT); + add_dependence_list_and_free (insn, ®_last->uses, + REG_DEP_ANTI); + add_dependence_list_and_free (insn, ®_last->clobbers, + REG_DEP_OUTPUT); + reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets); + reg_last->clobbers_length = 0; + reg_last->uses_length = 0; + } + else + { + add_dependence_list (insn, reg_last->sets, REG_DEP_OUTPUT); + add_dependence_list (insn, reg_last->uses, REG_DEP_ANTI); + } + reg_last->clobbers_length++; + reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers); + } + EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi) + { + struct deps_reg *reg_last = &deps->reg_last[i]; + add_dependence_list_and_free (insn, ®_last->sets, + REG_DEP_OUTPUT); + add_dependence_list_and_free (insn, ®_last->clobbers, + REG_DEP_OUTPUT); + add_dependence_list_and_free (insn, ®_last->uses, + REG_DEP_ANTI); + reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets); + reg_last->uses_length = 0; + reg_last->clobbers_length = 0; + CLEAR_REGNO_REG_SET (&deps->reg_conditional_sets, i); + } + } + + IOR_REG_SET (&deps->reg_last_in_use, reg_pending_uses); + IOR_REG_SET (&deps->reg_last_in_use, reg_pending_clobbers); + IOR_REG_SET (&deps->reg_last_in_use, reg_pending_sets); } - CLEAR_REG_SET (reg_pending_sets); + CLEAR_REG_SET (reg_pending_uses); CLEAR_REG_SET (reg_pending_clobbers); + CLEAR_REG_SET (reg_pending_sets); + + /* If we are currently in a libcall scheduling group, then mark the + current insn as being in a scheduling group and that it can not + be moved into a different basic block. */ + + if (deps->libcall_block_tail_insn) + { + SCHED_GROUP_P (insn) = 1; + CANT_MOVE (insn) = 1; + } /* If a post-call group is still open, see if it should remain so. This insn must be a simple move of a hard reg to a pseudo or @@ -1229,7 +1196,7 @@ sched_analyze_insn (deps, x, insn, loop_notes) tmp = SET_DEST (set); if (GET_CODE (tmp) == SUBREG) tmp = SUBREG_REG (tmp); - if (GET_CODE (tmp) == REG) + if (REG_P (tmp)) dest_regno = REGNO (tmp); else goto end_call_group; @@ -1237,7 +1204,13 @@ sched_analyze_insn (deps, x, insn, loop_notes) tmp = SET_SRC (set); if (GET_CODE (tmp) == SUBREG) tmp = SUBREG_REG (tmp); - if (GET_CODE (tmp) == REG) + if ((GET_CODE (tmp) == PLUS + || GET_CODE (tmp) == MINUS) + && REG_P (XEXP (tmp, 0)) + && REGNO (XEXP (tmp, 0)) == STACK_POINTER_REGNUM + && dest_regno == STACK_POINTER_REGNUM) + src_regno = STACK_POINTER_REGNUM; + else if (REG_P (tmp)) src_regno = REGNO (tmp); else goto end_call_group; @@ -1245,49 +1218,61 @@ sched_analyze_insn (deps, x, insn, loop_notes) if (src_regno < FIRST_PSEUDO_REGISTER || dest_regno < FIRST_PSEUDO_REGISTER) { - set_sched_group_p (insn); + if (deps->in_post_call_group_p == post_call_initial) + deps->in_post_call_group_p = post_call; + + SCHED_GROUP_P (insn) = 1; CANT_MOVE (insn) = 1; } else { end_call_group: - deps->in_post_call_group_p = 0; + deps->in_post_call_group_p = not_post_call; } } + + /* Fixup the dependencies in the sched group. */ + if (SCHED_GROUP_P (insn)) + fixup_sched_groups (insn); } /* Analyze every insn between HEAD and TAIL inclusive, creating LOG_LINKS for every dependency. */ void -sched_analyze (deps, head, tail) - struct deps *deps; - rtx head, tail; +sched_analyze (struct deps *deps, rtx head, rtx tail) { - register rtx insn; - register rtx u; + rtx insn; rtx loop_notes = 0; if (current_sched_info->use_cselib) - cselib_init (); + cselib_init (true); + /* Before reload, if the previous block ended in a call, show that + we are inside a post-call group, so as to keep the lifetimes of + hard registers correct. */ + if (! reload_completed && !LABEL_P (head)) + { + insn = prev_nonnote_insn (head); + if (insn && CALL_P (insn)) + deps->in_post_call_group_p = post_call_initial; + } for (insn = head;; insn = NEXT_INSN (insn)) { - if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN) + rtx link, end_seq, r0, set; + + if (NONJUMP_INSN_P (insn) || JUMP_P (insn)) { /* Clear out the stale LOG_LINKS from flow. */ free_INSN_LIST_list (&LOG_LINKS (insn)); - /* Clear out stale SCHED_GROUP_P. */ - SCHED_GROUP_P (insn) = 0; - /* Make each JUMP_INSN a scheduling barrier for memory references. */ - if (GET_CODE (insn) == JUMP_INSN) + if (JUMP_P (insn)) { /* Keep the list a reasonable size. */ if (deps->pending_flush_length++ > MAX_PENDING_LIST_LENGTH) - flush_pending_lists (deps, insn, 0); + flush_pending_lists (deps, insn, true, true); else deps->last_pending_memory_flush = alloc_INSN_LIST (insn, deps->last_pending_memory_flush); @@ -1295,72 +1280,57 @@ sched_analyze (deps, head, tail) sched_analyze_insn (deps, PATTERN (insn), insn, loop_notes); loop_notes = 0; } - else if (GET_CODE (insn) == CALL_INSN) + else if (CALL_P (insn)) { - rtx x; - register int i; - - /* Clear out stale SCHED_GROUP_P. */ - SCHED_GROUP_P (insn) = 0; + int i; CANT_MOVE (insn) = 1; /* Clear out the stale LOG_LINKS from flow. */ free_INSN_LIST_list (&LOG_LINKS (insn)); - /* Any instruction using a hard register which may get clobbered - by a call needs to be marked as dependent on this call. - This prevents a use of a hard return reg from being moved - past a void call (i.e. it does not explicitly set the hard - return reg). */ - - /* If this call has REG_SETJMP, then assume that - all registers, not just hard registers, may be clobbered by this - call. */ - - /* Insn, being a CALL_INSN, magically depends on - `last_function_call' already. */ - if (find_reg_note (insn, REG_SETJMP, NULL)) { - for (i = 0; i < deps->max_reg; i++) - { - struct deps_reg *reg_last = &deps->reg_last[i]; - - for (u = reg_last->uses; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); - for (u = reg_last->sets; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), 0); - for (u = reg_last->clobbers; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), 0); - - free_INSN_LIST_list (®_last->uses); - } - reg_pending_sets_all = 1; + /* This is setjmp. Assume that all registers, not just + hard registers, may be clobbered by this call. */ + reg_pending_barrier = MOVE_BARRIER; } else { for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (call_used_regs[i] || global_regs[i]) + /* A call may read and modify global register variables. */ + if (global_regs[i]) { - for (u = deps->reg_last[i].uses; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); - for (u = deps->reg_last[i].sets; u; u = XEXP (u, 1)) - add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); - - SET_REGNO_REG_SET (reg_pending_clobbers, i); + SET_REGNO_REG_SET (reg_pending_sets, i); + SET_REGNO_REG_SET (reg_pending_uses, i); } + /* Other call-clobbered hard regs may be clobbered. + Since we only have a choice between 'might be clobbered' + and 'definitely not clobbered', we must include all + partly call-clobbered registers here. */ + else if (HARD_REGNO_CALL_PART_CLOBBERED (i, reg_raw_mode[i]) + || TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) + SET_REGNO_REG_SET (reg_pending_clobbers, i); + /* We don't know what set of fixed registers might be used + by the function, but it is certain that the stack pointer + is among them, but be conservative. */ + else if (fixed_regs[i]) + SET_REGNO_REG_SET (reg_pending_uses, i); + /* The frame pointer is normally not used by the function + itself, but by the debugger. */ + /* ??? MIPS o32 is an exception. It uses the frame pointer + in the macro expansion of jal but does not represent this + fact in the call_insn rtl. */ + else if (i == FRAME_POINTER_REGNUM + || (i == HARD_FRAME_POINTER_REGNUM + && (! reload_completed || frame_pointer_needed))) + SET_REGNO_REG_SET (reg_pending_uses, i); } /* For each insn which shouldn't cross a call, add a dependence between that insn and this call insn. */ - x = LOG_LINKS (deps->sched_before_next_call); - while (x) - { - add_dependence (insn, XEXP (x, 0), REG_DEP_ANTI); - x = XEXP (x, 1); - } - free_INSN_LIST_list (&LOG_LINKS (deps->sched_before_next_call)); + add_dependence_list_and_free (insn, &deps->sched_before_next_call, + REG_DEP_ANTI); sched_analyze_insn (deps, PATTERN (insn), insn, loop_notes); loop_notes = 0; @@ -1369,51 +1339,31 @@ sched_analyze (deps, head, tail) all pending reads and writes, and start new dependencies starting from here. But only flush writes for constant calls (which may be passed a pointer to something we haven't written yet). */ - flush_pending_lists (deps, insn, CONST_OR_PURE_CALL_P (insn)); - - /* Depend this function call (actually, the user of this - function call) on all hard register clobberage. */ + flush_pending_lists (deps, insn, true, !CONST_OR_PURE_CALL_P (insn)); - /* last_function_call is now a list of insns. */ + /* Remember the last function call for limiting lifetimes. */ free_INSN_LIST_list (&deps->last_function_call); deps->last_function_call = alloc_INSN_LIST (insn, NULL_RTX); /* Before reload, begin a post-call group, so as to keep the lifetimes of hard registers correct. */ if (! reload_completed) - deps->in_post_call_group_p = 1; + deps->in_post_call_group_p = post_call; } + /* EH_REGION insn notes can not appear until well after we complete + scheduling. */ + if (NOTE_P (insn)) + gcc_assert (NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG + && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END); + /* See comments on reemit_notes as to why we do this. ??? Actually, the reemit_notes just say what is done, not why. */ - else if (GET_CODE (insn) == NOTE - && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_BEG - || NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_END)) - { - loop_notes = alloc_EXPR_LIST (REG_SAVE_NOTE, NOTE_RANGE_INFO (insn), - loop_notes); - loop_notes = alloc_EXPR_LIST (REG_SAVE_NOTE, - GEN_INT (NOTE_LINE_NUMBER (insn)), - loop_notes); - } - else if (GET_CODE (insn) == NOTE - && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG - || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END - || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG - || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)) + if (NOTE_P (insn) + && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG + || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)) { - rtx rtx_region; - - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG - || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END) - rtx_region = GEN_INT (NOTE_EH_HANDLER (insn)); - else - rtx_region = GEN_INT (0); - - loop_notes = alloc_EXPR_LIST (REG_SAVE_NOTE, - rtx_region, - loop_notes); loop_notes = alloc_EXPR_LIST (REG_SAVE_NOTE, GEN_INT (NOTE_LINE_NUMBER (insn)), loop_notes); @@ -1422,6 +1372,46 @@ sched_analyze (deps, head, tail) if (current_sched_info->use_cselib) cselib_process_insn (insn); + + /* Now that we have completed handling INSN, check and see if it is + a CLOBBER beginning a libcall block. If it is, record the + end of the libcall sequence. + + We want to schedule libcall blocks as a unit before reload. While + this restricts scheduling, it preserves the meaning of a libcall + block. + + As a side effect, we may get better code due to decreased register + pressure as well as less chance of a foreign insn appearing in + a libcall block. */ + if (!reload_completed + /* Note we may have nested libcall sequences. We only care about + the outermost libcall sequence. */ + && deps->libcall_block_tail_insn == 0 + /* The sequence must start with a clobber of a register. */ + && NONJUMP_INSN_P (insn) + && GET_CODE (PATTERN (insn)) == CLOBBER + && (r0 = XEXP (PATTERN (insn), 0), REG_P (r0)) + && REG_P (XEXP (PATTERN (insn), 0)) + /* The CLOBBER must also have a REG_LIBCALL note attached. */ + && (link = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0 + && (end_seq = XEXP (link, 0)) != 0 + /* The insn referenced by the REG_LIBCALL note must be a + simple nop copy with the same destination as the register + mentioned in the clobber. */ + && (set = single_set (end_seq)) != 0 + && SET_DEST (set) == r0 && SET_SRC (set) == r0 + /* And finally the insn referenced by the REG_LIBCALL must + also contain a REG_EQUAL note and a REG_RETVAL note. */ + && find_reg_note (end_seq, REG_EQUAL, NULL_RTX) != 0 + && find_reg_note (end_seq, REG_RETVAL, NULL_RTX) != 0) + deps->libcall_block_tail_insn = XEXP (link, 0); + + /* If we have reached the end of a libcall block, then close the + block. */ + if (deps->libcall_block_tail_insn == insn) + deps->libcall_block_tail_insn = 0; + if (insn == tail) { if (current_sched_info->use_cselib) @@ -1429,20 +1419,56 @@ sched_analyze (deps, head, tail) return; } } - abort (); + gcc_unreachable (); } + +/* The following function adds forward dependence (FROM, TO) with + given DEP_TYPE. The forward dependence should be not exist before. */ + +void +add_forward_dependence (rtx from, rtx to, enum reg_note dep_type) +{ + rtx new_link; + +#ifdef ENABLE_CHECKING + /* If add_dependence is working properly there should never + be notes, deleted insns or duplicates in the backward + links. Thus we need not check for them here. + + However, if we have enabled checking we might as well go + ahead and verify that add_dependence worked properly. */ + gcc_assert (!NOTE_P (from)); + gcc_assert (!INSN_DELETED_P (from)); + if (forward_dependency_cache) + gcc_assert (!bitmap_bit_p (&forward_dependency_cache[INSN_LUID (from)], + INSN_LUID (to))); + else + gcc_assert (!find_insn_list (to, INSN_DEPEND (from))); + + /* ??? If bitmap_bit_p is a predicate, what is this supposed to do? */ + if (forward_dependency_cache != NULL) + bitmap_bit_p (&forward_dependency_cache[INSN_LUID (from)], + INSN_LUID (to)); +#endif + + new_link = alloc_INSN_LIST (to, INSN_DEPEND (from)); + + PUT_REG_NOTE_KIND (new_link, dep_type); + + INSN_DEPEND (from) = new_link; + INSN_DEP_COUNT (to) += 1; +} + /* Examine insns in the range [ HEAD, TAIL ] and Use the backward dependences from LOG_LINKS to build forward dependences in INSN_DEPEND. */ void -compute_forward_dependences (head, tail) - rtx head, tail; +compute_forward_dependences (rtx head, rtx tail) { rtx insn, link; rtx next_tail; - enum reg_note dep_type; next_tail = NEXT_INSN (tail); for (insn = head; insn != next_tail; insn = NEXT_INSN (insn)) @@ -1450,44 +1476,8 @@ compute_forward_dependences (head, tail) if (! INSN_P (insn)) continue; - insn = group_leader (insn); - for (link = LOG_LINKS (insn); link; link = XEXP (link, 1)) - { - rtx x = group_leader (XEXP (link, 0)); - rtx new_link; - - if (x != XEXP (link, 0)) - continue; - -#ifdef ENABLE_CHECKING - /* If add_dependence is working properly there should never - be notes, deleted insns or duplicates in the backward - links. Thus we need not check for them here. - - However, if we have enabled checking we might as well go - ahead and verify that add_dependence worked properly. */ - if (GET_CODE (x) == NOTE - || INSN_DELETED_P (x) - || (forward_dependency_cache != NULL - && TEST_BIT (forward_dependency_cache[INSN_LUID (x)], - INSN_LUID (insn))) - || (forward_dependency_cache == NULL - && find_insn_list (insn, INSN_DEPEND (x)))) - abort (); - if (forward_dependency_cache != NULL) - SET_BIT (forward_dependency_cache[INSN_LUID (x)], - INSN_LUID (insn)); -#endif - - new_link = alloc_INSN_LIST (insn, INSN_DEPEND (x)); - - dep_type = REG_NOTE_KIND (link); - PUT_REG_NOTE_KIND (new_link, dep_type); - - INSN_DEPEND (x) = new_link; - INSN_DEP_COUNT (insn) += 1; - } + add_forward_dependence (XEXP (link, 0), insn, REG_NOTE_KIND (link)); } } @@ -1495,15 +1485,14 @@ compute_forward_dependences (head, tail) n_bbs is the number of region blocks. */ void -init_deps (deps) - struct deps *deps; +init_deps (struct deps *deps) { int max_reg = (reload_completed ? FIRST_PSEUDO_REGISTER : max_reg_num ()); deps->max_reg = max_reg; - deps->reg_last = (struct deps_reg *) - xcalloc (max_reg, sizeof (struct deps_reg)); + deps->reg_last = xcalloc (max_reg, sizeof (struct deps_reg)); INIT_REG_SET (&deps->reg_last_in_use); + INIT_REG_SET (&deps->reg_conditional_sets); deps->pending_read_insns = 0; deps->pending_read_mems = 0; @@ -1513,45 +1502,50 @@ init_deps (deps) deps->pending_flush_length = 0; deps->last_pending_memory_flush = 0; deps->last_function_call = 0; - deps->in_post_call_group_p = 0; - - deps->sched_before_next_call - = gen_rtx_INSN (VOIDmode, 0, NULL_RTX, NULL_RTX, - NULL_RTX, 0, NULL_RTX, NULL_RTX); - LOG_LINKS (deps->sched_before_next_call) = 0; + deps->sched_before_next_call = 0; + deps->in_post_call_group_p = not_post_call; + deps->libcall_block_tail_insn = 0; } /* Free insn lists found in DEPS. */ void -free_deps (deps) - struct deps *deps; +free_deps (struct deps *deps) { - int i; + unsigned i; + reg_set_iterator rsi; + + free_INSN_LIST_list (&deps->pending_read_insns); + free_EXPR_LIST_list (&deps->pending_read_mems); + free_INSN_LIST_list (&deps->pending_write_insns); + free_EXPR_LIST_list (&deps->pending_write_mems); + free_INSN_LIST_list (&deps->last_pending_memory_flush); /* Without the EXECUTE_IF_SET, this loop is executed max_reg * nr_regions - times. For a test case with 42000 regs and 8000 small basic blocks, + times. For a testcase with 42000 regs and 8000 small basic blocks, this loop accounted for nearly 60% (84 sec) of the total -O2 runtime. */ - EXECUTE_IF_SET_IN_REG_SET (&deps->reg_last_in_use, 0, i, + EXECUTE_IF_SET_IN_REG_SET (&deps->reg_last_in_use, 0, i, rsi) { struct deps_reg *reg_last = &deps->reg_last[i]; - free_INSN_LIST_list (®_last->uses); - free_INSN_LIST_list (®_last->sets); - free_INSN_LIST_list (®_last->clobbers); - }); + if (reg_last->uses) + free_INSN_LIST_list (®_last->uses); + if (reg_last->sets) + free_INSN_LIST_list (®_last->sets); + if (reg_last->clobbers) + free_INSN_LIST_list (®_last->clobbers); + } CLEAR_REG_SET (&deps->reg_last_in_use); + CLEAR_REG_SET (&deps->reg_conditional_sets); free (deps->reg_last); - deps->reg_last = NULL; } /* If it is profitable to use them, initialize caches for tracking - dependency informatino. LUID is the number of insns to be scheduled, + dependency information. LUID is the number of insns to be scheduled, it is used in the estimate of profitability. */ void -init_dependency_caches (luid) - int luid; +init_dependency_caches (int luid) { /* ?!? We could save some memory by computing a per-region luid mapping which could reduce both the number of vectors in the cache and the size @@ -1561,34 +1555,52 @@ init_dependency_caches (luid) what we consider "very high". */ if (luid / n_basic_blocks > 100 * 5) { - true_dependency_cache = sbitmap_vector_alloc (luid, luid); - sbitmap_vector_zero (true_dependency_cache, luid); - anti_dependency_cache = sbitmap_vector_alloc (luid, luid); - sbitmap_vector_zero (anti_dependency_cache, luid); - output_dependency_cache = sbitmap_vector_alloc (luid, luid); - sbitmap_vector_zero (output_dependency_cache, luid); + int i; + true_dependency_cache = xmalloc (luid * sizeof (bitmap_head)); + anti_dependency_cache = xmalloc (luid * sizeof (bitmap_head)); + output_dependency_cache = xmalloc (luid * sizeof (bitmap_head)); #ifdef ENABLE_CHECKING - forward_dependency_cache = sbitmap_vector_alloc (luid, luid); - sbitmap_vector_zero (forward_dependency_cache, luid); + forward_dependency_cache = xmalloc (luid * sizeof (bitmap_head)); #endif + for (i = 0; i < luid; i++) + { + bitmap_initialize (&true_dependency_cache[i], 0); + bitmap_initialize (&anti_dependency_cache[i], 0); + bitmap_initialize (&output_dependency_cache[i], 0); +#ifdef ENABLE_CHECKING + bitmap_initialize (&forward_dependency_cache[i], 0); +#endif + } + cache_size = luid; } } /* Free the caches allocated in init_dependency_caches. */ void -free_dependency_caches () +free_dependency_caches (void) { if (true_dependency_cache) { - sbitmap_vector_free (true_dependency_cache); + int i; + + for (i = 0; i < cache_size; i++) + { + bitmap_clear (&true_dependency_cache[i]); + bitmap_clear (&anti_dependency_cache[i]); + bitmap_clear (&output_dependency_cache[i]); +#ifdef ENABLE_CHECKING + bitmap_clear (&forward_dependency_cache[i]); +#endif + } + free (true_dependency_cache); true_dependency_cache = NULL; - sbitmap_vector_free (anti_dependency_cache); + free (anti_dependency_cache); anti_dependency_cache = NULL; - sbitmap_vector_free (output_dependency_cache); + free (output_dependency_cache); output_dependency_cache = NULL; #ifdef ENABLE_CHECKING - sbitmap_vector_free (forward_dependency_cache); + free (forward_dependency_cache); forward_dependency_cache = NULL; #endif } @@ -1598,18 +1610,20 @@ free_dependency_caches () code. */ void -init_deps_global () +init_deps_global (void) { - reg_pending_sets = INITIALIZE_REG_SET (reg_pending_sets_head); - reg_pending_clobbers = INITIALIZE_REG_SET (reg_pending_clobbers_head); - reg_pending_sets_all = 0; + reg_pending_sets = ALLOC_REG_SET (®_obstack); + reg_pending_clobbers = ALLOC_REG_SET (®_obstack); + reg_pending_uses = ALLOC_REG_SET (®_obstack); + reg_pending_barrier = NOT_A_BARRIER; } /* Free everything used by the dependency analysis code. */ void -finish_deps_global () +finish_deps_global (void) { FREE_REG_SET (reg_pending_sets); FREE_REG_SET (reg_pending_clobbers); + FREE_REG_SET (reg_pending_uses); }