diff options
Diffstat (limited to 'contrib/gcc/df.c')
-rw-r--r-- | contrib/gcc/df.c | 3697 |
1 files changed, 0 insertions, 3697 deletions
diff --git a/contrib/gcc/df.c b/contrib/gcc/df.c deleted file mode 100644 index d91f95e..0000000 --- a/contrib/gcc/df.c +++ /dev/null @@ -1,3697 +0,0 @@ -/* Dataflow support routines. - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 - Free Software Foundation, Inc. - Contributed by Michael P. Hayes (m.hayes@elec.canterbury.ac.nz, - mhayes@redhat.com) - -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 2, 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 COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. - - -OVERVIEW: - -This file provides some dataflow routines for computing reaching defs, -upward exposed uses, live variables, def-use chains, and use-def -chains. The global dataflow is performed using simple iterative -methods with a worklist and could be sped up by ordering the blocks -with a depth first search order. - -A `struct ref' data structure (ref) is allocated for every register -reference (def or use) and this records the insn and bb the ref is -found within. The refs are linked together in chains of uses and defs -for each insn and for each register. Each ref also has a chain field -that links all the use refs for a def or all the def refs for a use. -This is used to create use-def or def-use chains. - - -USAGE: - -Here's an example of using the dataflow routines. - - struct df *df; - - df = df_init (); - - df_analyse (df, 0, DF_ALL); - - df_dump (df, DF_ALL, stderr); - - df_finish (df); - - -df_init simply creates a poor man's object (df) that needs to be -passed to all the dataflow routines. df_finish destroys this -object and frees up any allocated memory. DF_ALL says to analyse -everything. - -df_analyse performs the following: - -1. Records defs and uses by scanning the insns in each basic block - or by scanning the insns queued by df_insn_modify. -2. Links defs and uses into insn-def and insn-use chains. -3. Links defs and uses into reg-def and reg-use chains. -4. Assigns LUIDs to each insn (for modified blocks). -5. Calculates local reaching definitions. -6. Calculates global reaching definitions. -7. Creates use-def chains. -8. Calculates local reaching uses (upwards exposed uses). -9. Calculates global reaching uses. -10. Creates def-use chains. -11. Calculates local live registers. -12. Calculates global live registers. -13. Calculates register lifetimes and determines local registers. - - -PHILOSOPHY: - -Note that the dataflow information is not updated for every newly -deleted or created insn. If the dataflow information requires -updating then all the changed, new, or deleted insns needs to be -marked with df_insn_modify (or df_insns_modify) either directly or -indirectly (say through calling df_insn_delete). df_insn_modify -marks all the modified insns to get processed the next time df_analyse - is called. - -Beware that tinkering with insns may invalidate the dataflow information. -The philosophy behind these routines is that once the dataflow -information has been gathered, the user should store what they require -before they tinker with any insn. Once a reg is replaced, for example, -then the reg-def/reg-use chains will point to the wrong place. Once a -whole lot of changes have been made, df_analyse can be called again -to update the dataflow information. Currently, this is not very smart -with regard to propagating changes to the dataflow so it should not -be called very often. - - -DATA STRUCTURES: - -The basic object is a REF (reference) and this may either be a DEF -(definition) or a USE of a register. - -These are linked into a variety of lists; namely reg-def, reg-use, - insn-def, insn-use, def-use, and use-def lists. For example, -the reg-def lists contain all the refs that define a given register -while the insn-use lists contain all the refs used by an insn. - -Note that the reg-def and reg-use chains are generally short (except for the -hard registers) and thus it is much faster to search these chains -rather than searching the def or use bitmaps. - -If the insns are in SSA form then the reg-def and use-def lists -should only contain the single defining ref. - - -TODO: - -1) Incremental dataflow analysis. - -Note that if a loop invariant insn is hoisted (or sunk), we do not -need to change the def-use or use-def chains. All we have to do is to -change the bb field for all the associated defs and uses and to -renumber the LUIDs for the original and new basic blocks of the insn. - -When shadowing loop mems we create new uses and defs for new pseudos -so we do not affect the existing dataflow information. - -My current strategy is to queue up all modified, created, or deleted -insns so when df_analyse is called we can easily determine all the new -or deleted refs. Currently the global dataflow information is -recomputed from scratch but this could be propagated more efficiently. - -2) Reduced memory requirements. - -We could operate a pool of ref structures. When a ref is deleted it -gets returned to the pool (say by linking on to a chain of free refs). -This will require a pair of bitmaps for defs and uses so that we can -tell which ones have been changed. Alternatively, we could -periodically squeeze the def and use tables and associated bitmaps and -renumber the def and use ids. - -3) Ordering of reg-def and reg-use lists. - -Should the first entry in the def list be the first def (within a BB)? -Similarly, should the first entry in the use list be the last use -(within a BB)? - -4) Working with a sub-CFG. - -Often the whole CFG does not need to be analyzed, for example, -when optimizing a loop, only certain registers are of interest. -Perhaps there should be a bitmap argument to df_analyse to specify -which registers should be analyzed? - - -NOTES: - -Embedded addressing side-effects, such as POST_INC or PRE_INC, generate -both a use and a def. These are both marked read/write to show that they -are dependent. For example, (set (reg 40) (mem (post_inc (reg 42)))) -will generate a use of reg 42 followed by a def of reg 42 (both marked -read/write). Similarly, (set (reg 40) (mem (pre_dec (reg 41)))) -generates a use of reg 41 then a def of reg 41 (both marked read/write), -even though reg 41 is decremented before it is used for the memory -address in this second example. - -A set to a REG inside a ZERO_EXTRACT, SIGN_EXTRACT, or SUBREG invokes -a read-modify write operation. We generate both a use and a def -and again mark them read/write. -*/ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "rtl.h" -#include "tm_p.h" -#include "insn-config.h" -#include "recog.h" -#include "function.h" -#include "regs.h" -#include "alloc-pool.h" -#include "hard-reg-set.h" -#include "basic-block.h" -#include "sbitmap.h" -#include "bitmap.h" -#include "df.h" -#include "fibheap.h" - -#define FOR_EACH_BB_IN_BITMAP(BITMAP, MIN, BB, CODE) \ - do \ - { \ - unsigned int node_; \ - EXECUTE_IF_SET_IN_BITMAP (BITMAP, MIN, node_, \ - {(BB) = BASIC_BLOCK (node_); CODE;}); \ - } \ - while (0) - -static alloc_pool df_ref_pool; -static alloc_pool df_link_pool; -static struct df *ddf; - -static void df_reg_table_realloc (struct df *, int); -static void df_insn_table_realloc (struct df *, unsigned int); -static void df_bitmaps_alloc (struct df *, int); -static void df_bitmaps_free (struct df *, int); -static void df_free (struct df *); -static void df_alloc (struct df *, int); - -static rtx df_reg_clobber_gen (unsigned int); -static rtx df_reg_use_gen (unsigned int); - -static inline struct df_link *df_link_create (struct ref *, struct df_link *); -static struct df_link *df_ref_unlink (struct df_link **, struct ref *); -static void df_def_unlink (struct df *, struct ref *); -static void df_use_unlink (struct df *, struct ref *); -static void df_insn_refs_unlink (struct df *, basic_block, rtx); -#if 0 -static void df_bb_refs_unlink (struct df *, basic_block); -static void df_refs_unlink (struct df *, bitmap); -#endif - -static struct ref *df_ref_create (struct df *, rtx, rtx *, rtx, - enum df_ref_type, enum df_ref_flags); -static void df_ref_record_1 (struct df *, rtx, rtx *, rtx, enum df_ref_type, - enum df_ref_flags); -static void df_ref_record (struct df *, rtx, rtx *, rtx, enum df_ref_type, - enum df_ref_flags); -static void df_def_record_1 (struct df *, rtx, basic_block, rtx); -static void df_defs_record (struct df *, rtx, basic_block, rtx); -static void df_uses_record (struct df *, rtx *, enum df_ref_type, - basic_block, rtx, enum df_ref_flags); -static void df_insn_refs_record (struct df *, basic_block, rtx); -static void df_bb_refs_record (struct df *, basic_block); -static void df_refs_record (struct df *, bitmap); - -static void df_bb_reg_def_chain_create (struct df *, basic_block); -static void df_reg_def_chain_create (struct df *, bitmap); -static void df_bb_reg_use_chain_create (struct df *, basic_block); -static void df_reg_use_chain_create (struct df *, bitmap); -static void df_bb_du_chain_create (struct df *, basic_block, bitmap); -static void df_du_chain_create (struct df *, bitmap); -static void df_bb_ud_chain_create (struct df *, basic_block); -static void df_ud_chain_create (struct df *, bitmap); -static void df_bb_rd_local_compute (struct df *, basic_block); -static void df_rd_local_compute (struct df *, bitmap); -static void df_bb_ru_local_compute (struct df *, basic_block); -static void df_ru_local_compute (struct df *, bitmap); -static void df_bb_lr_local_compute (struct df *, basic_block); -static void df_lr_local_compute (struct df *, bitmap); -static void df_bb_reg_info_compute (struct df *, basic_block, bitmap); -static void df_reg_info_compute (struct df *, bitmap); - -static int df_bb_luids_set (struct df *df, basic_block); -static int df_luids_set (struct df *df, bitmap); - -static int df_modified_p (struct df *, bitmap); -static int df_refs_queue (struct df *); -static int df_refs_process (struct df *); -static int df_bb_refs_update (struct df *, basic_block); -static int df_refs_update (struct df *); -static void df_analyse_1 (struct df *, bitmap, int, int); - -static void df_insns_modify (struct df *, basic_block, rtx, rtx); -static int df_rtx_mem_replace (rtx *, void *); -static int df_rtx_reg_replace (rtx *, void *); -void df_refs_reg_replace (struct df *, bitmap, struct df_link *, rtx, rtx); - -static int df_def_dominates_all_uses_p (struct df *, struct ref *def); -static int df_def_dominates_uses_p (struct df *, struct ref *def, bitmap); -static struct ref *df_bb_regno_last_use_find (struct df *, basic_block, - unsigned int); -static struct ref *df_bb_regno_first_def_find (struct df *, basic_block, - unsigned int); -static struct ref *df_bb_insn_regno_last_use_find (struct df *, basic_block, - rtx, unsigned int); -static struct ref *df_bb_insn_regno_first_def_find (struct df *, basic_block, - rtx, unsigned int); - -static void df_chain_dump (struct df_link *, FILE *file); -static void df_chain_dump_regno (struct df_link *, FILE *file); -static void df_regno_debug (struct df *, unsigned int, FILE *); -static void df_ref_debug (struct df *, struct ref *, FILE *); -static void df_rd_transfer_function (int, int *, bitmap, bitmap, bitmap, - bitmap, void *); -static void df_ru_transfer_function (int, int *, bitmap, bitmap, bitmap, - bitmap, void *); -static void df_lr_transfer_function (int, int *, bitmap, bitmap, bitmap, - bitmap, void *); -static void hybrid_search_bitmap (basic_block, bitmap *, bitmap *, - bitmap *, bitmap *, enum df_flow_dir, - enum df_confluence_op, - transfer_function_bitmap, - sbitmap, sbitmap, void *); -static void hybrid_search_sbitmap (basic_block, sbitmap *, sbitmap *, - sbitmap *, sbitmap *, enum df_flow_dir, - enum df_confluence_op, - transfer_function_sbitmap, - sbitmap, sbitmap, void *); - - -/* Local memory allocation/deallocation routines. */ - - -/* Increase the insn info table to have space for at least SIZE + 1 - elements. */ -static void -df_insn_table_realloc (struct df *df, unsigned int size) -{ - size++; - if (size <= df->insn_size) - return; - - /* Make the table a little larger than requested, so we do not need - to enlarge it so often. */ - size += df->insn_size / 4; - - df->insns = xrealloc (df->insns, size * sizeof (struct insn_info)); - - memset (df->insns + df->insn_size, 0, - (size - df->insn_size) * sizeof (struct insn_info)); - - df->insn_size = size; - - if (! df->insns_modified) - { - df->insns_modified = BITMAP_XMALLOC (); - bitmap_zero (df->insns_modified); - } -} - - -/* Increase the reg info table by SIZE more elements. */ -static void -df_reg_table_realloc (struct df *df, int size) -{ - /* Make table 25 percent larger by default. */ - if (! size) - size = df->reg_size / 4; - - size += df->reg_size; - if (size < max_reg_num ()) - size = max_reg_num (); - - df->regs = xrealloc (df->regs, size * sizeof (struct reg_info)); - - /* Zero the new entries. */ - memset (df->regs + df->reg_size, 0, - (size - df->reg_size) * sizeof (struct reg_info)); - - df->reg_size = size; -} - - -/* Allocate bitmaps for each basic block. */ -static void -df_bitmaps_alloc (struct df *df, int flags) -{ - int dflags = 0; - basic_block bb; - - /* Free the bitmaps if they need resizing. */ - if ((flags & DF_LR) && df->n_regs < (unsigned int) max_reg_num ()) - dflags |= DF_LR | DF_RU; - if ((flags & DF_RU) && df->n_uses < df->use_id) - dflags |= DF_RU; - if ((flags & DF_RD) && df->n_defs < df->def_id) - dflags |= DF_RD; - - if (dflags) - df_bitmaps_free (df, dflags); - - df->n_defs = df->def_id; - df->n_uses = df->use_id; - - FOR_EACH_BB (bb) - { - struct bb_info *bb_info = DF_BB_INFO (df, bb); - - if (flags & DF_RD && ! bb_info->rd_in) - { - /* Allocate bitmaps for reaching definitions. */ - bb_info->rd_kill = BITMAP_XMALLOC (); - bitmap_zero (bb_info->rd_kill); - bb_info->rd_gen = BITMAP_XMALLOC (); - bitmap_zero (bb_info->rd_gen); - bb_info->rd_in = BITMAP_XMALLOC (); - bb_info->rd_out = BITMAP_XMALLOC (); - bb_info->rd_valid = 0; - } - - if (flags & DF_RU && ! bb_info->ru_in) - { - /* Allocate bitmaps for upward exposed uses. */ - bb_info->ru_kill = BITMAP_XMALLOC (); - bitmap_zero (bb_info->ru_kill); - /* Note the lack of symmetry. */ - bb_info->ru_gen = BITMAP_XMALLOC (); - bitmap_zero (bb_info->ru_gen); - bb_info->ru_in = BITMAP_XMALLOC (); - bb_info->ru_out = BITMAP_XMALLOC (); - bb_info->ru_valid = 0; - } - - if (flags & DF_LR && ! bb_info->lr_in) - { - /* Allocate bitmaps for live variables. */ - bb_info->lr_def = BITMAP_XMALLOC (); - bitmap_zero (bb_info->lr_def); - bb_info->lr_use = BITMAP_XMALLOC (); - bitmap_zero (bb_info->lr_use); - bb_info->lr_in = BITMAP_XMALLOC (); - bb_info->lr_out = BITMAP_XMALLOC (); - bb_info->lr_valid = 0; - } - } -} - - -/* Free bitmaps for each basic block. */ -static void -df_bitmaps_free (struct df *df, int flags) -{ - basic_block bb; - - FOR_EACH_BB (bb) - { - struct bb_info *bb_info = DF_BB_INFO (df, bb); - - if (!bb_info) - continue; - - if ((flags & DF_RD) && bb_info->rd_in) - { - /* Free bitmaps for reaching definitions. */ - BITMAP_XFREE (bb_info->rd_kill); - bb_info->rd_kill = NULL; - BITMAP_XFREE (bb_info->rd_gen); - bb_info->rd_gen = NULL; - BITMAP_XFREE (bb_info->rd_in); - bb_info->rd_in = NULL; - BITMAP_XFREE (bb_info->rd_out); - bb_info->rd_out = NULL; - } - - if ((flags & DF_RU) && bb_info->ru_in) - { - /* Free bitmaps for upward exposed uses. */ - BITMAP_XFREE (bb_info->ru_kill); - bb_info->ru_kill = NULL; - BITMAP_XFREE (bb_info->ru_gen); - bb_info->ru_gen = NULL; - BITMAP_XFREE (bb_info->ru_in); - bb_info->ru_in = NULL; - BITMAP_XFREE (bb_info->ru_out); - bb_info->ru_out = NULL; - } - - if ((flags & DF_LR) && bb_info->lr_in) - { - /* Free bitmaps for live variables. */ - BITMAP_XFREE (bb_info->lr_def); - bb_info->lr_def = NULL; - BITMAP_XFREE (bb_info->lr_use); - bb_info->lr_use = NULL; - BITMAP_XFREE (bb_info->lr_in); - bb_info->lr_in = NULL; - BITMAP_XFREE (bb_info->lr_out); - bb_info->lr_out = NULL; - } - } - df->flags &= ~(flags & (DF_RD | DF_RU | DF_LR)); -} - - -/* Allocate and initialize dataflow memory. */ -static void -df_alloc (struct df *df, int n_regs) -{ - int n_insns; - basic_block bb; - - df_link_pool = create_alloc_pool ("df_link pool", sizeof (struct df_link), - 100); - df_ref_pool = create_alloc_pool ("df_ref pool", sizeof (struct ref), 100); - - /* Perhaps we should use LUIDs to save memory for the insn_refs - table. This is only a small saving; a few pointers. */ - n_insns = get_max_uid () + 1; - - df->def_id = 0; - df->n_defs = 0; - /* Approximate number of defs by number of insns. */ - df->def_size = n_insns; - df->defs = xmalloc (df->def_size * sizeof (*df->defs)); - - df->use_id = 0; - df->n_uses = 0; - /* Approximate number of uses by twice number of insns. */ - df->use_size = n_insns * 2; - df->uses = xmalloc (df->use_size * sizeof (*df->uses)); - - df->n_regs = n_regs; - df->n_bbs = last_basic_block; - - /* Allocate temporary working array used during local dataflow analysis. */ - df->reg_def_last = xmalloc (df->n_regs * sizeof (struct ref *)); - - df_insn_table_realloc (df, n_insns); - - df_reg_table_realloc (df, df->n_regs); - - df->bbs_modified = BITMAP_XMALLOC (); - bitmap_zero (df->bbs_modified); - - df->flags = 0; - - df->bbs = xcalloc (last_basic_block, sizeof (struct bb_info)); - - df->all_blocks = BITMAP_XMALLOC (); - FOR_EACH_BB (bb) - bitmap_set_bit (df->all_blocks, bb->index); -} - - -/* Free all the dataflow info. */ -static void -df_free (struct df *df) -{ - df_bitmaps_free (df, DF_ALL); - - if (df->bbs) - free (df->bbs); - df->bbs = 0; - - if (df->insns) - free (df->insns); - df->insns = 0; - df->insn_size = 0; - - if (df->defs) - free (df->defs); - df->defs = 0; - df->def_size = 0; - df->def_id = 0; - - if (df->uses) - free (df->uses); - df->uses = 0; - df->use_size = 0; - df->use_id = 0; - - if (df->regs) - free (df->regs); - df->regs = 0; - df->reg_size = 0; - - if (df->bbs_modified) - BITMAP_XFREE (df->bbs_modified); - df->bbs_modified = 0; - - if (df->insns_modified) - BITMAP_XFREE (df->insns_modified); - df->insns_modified = 0; - - BITMAP_XFREE (df->all_blocks); - df->all_blocks = 0; - - free_alloc_pool (df_ref_pool); - free_alloc_pool (df_link_pool); - -} - -/* Local miscellaneous routines. */ - -/* Return a USE for register REGNO. */ -static rtx df_reg_use_gen (unsigned int regno) -{ - rtx reg; - rtx use; - - reg = regno_reg_rtx[regno]; - - use = gen_rtx_USE (GET_MODE (reg), reg); - return use; -} - - -/* Return a CLOBBER for register REGNO. */ -static rtx df_reg_clobber_gen (unsigned int regno) -{ - rtx reg; - rtx use; - - reg = regno_reg_rtx[regno]; - - use = gen_rtx_CLOBBER (GET_MODE (reg), reg); - return use; -} - -/* Local chain manipulation routines. */ - -/* Create a link in a def-use or use-def chain. */ -static inline struct df_link * -df_link_create (struct ref *ref, struct df_link *next) -{ - struct df_link *link; - - link = pool_alloc (df_link_pool); - link->next = next; - link->ref = ref; - return link; -} - - -/* Add REF to chain head pointed to by PHEAD. */ -static struct df_link * -df_ref_unlink (struct df_link **phead, struct ref *ref) -{ - struct df_link *link = *phead; - - if (link) - { - if (! link->next) - { - /* Only a single ref. It must be the one we want. - If not, the def-use and use-def chains are likely to - be inconsistent. */ - if (link->ref != ref) - abort (); - /* Now have an empty chain. */ - *phead = NULL; - } - else - { - /* Multiple refs. One of them must be us. */ - if (link->ref == ref) - *phead = link->next; - else - { - /* Follow chain. */ - for (; link->next; link = link->next) - { - if (link->next->ref == ref) - { - /* Unlink from list. */ - link->next = link->next->next; - return link->next; - } - } - } - } - } - return link; -} - - -/* Unlink REF from all def-use/use-def chains, etc. */ -int -df_ref_remove (struct df *df, struct ref *ref) -{ - if (DF_REF_REG_DEF_P (ref)) - { - df_def_unlink (df, ref); - df_ref_unlink (&df->insns[DF_REF_INSN_UID (ref)].defs, ref); - } - else - { - df_use_unlink (df, ref); - df_ref_unlink (&df->insns[DF_REF_INSN_UID (ref)].uses, ref); - } - return 1; -} - - -/* Unlink DEF from use-def and reg-def chains. */ -static void -df_def_unlink (struct df *df ATTRIBUTE_UNUSED, struct ref *def) -{ - struct df_link *du_link; - unsigned int dregno = DF_REF_REGNO (def); - - /* Follow def-use chain to find all the uses of this def. */ - for (du_link = DF_REF_CHAIN (def); du_link; du_link = du_link->next) - { - struct ref *use = du_link->ref; - - /* Unlink this def from the use-def chain. */ - df_ref_unlink (&DF_REF_CHAIN (use), def); - } - DF_REF_CHAIN (def) = 0; - - /* Unlink def from reg-def chain. */ - df_ref_unlink (&df->regs[dregno].defs, def); - - df->defs[DF_REF_ID (def)] = 0; -} - - -/* Unlink use from def-use and reg-use chains. */ -static void -df_use_unlink (struct df *df ATTRIBUTE_UNUSED, struct ref *use) -{ - struct df_link *ud_link; - unsigned int uregno = DF_REF_REGNO (use); - - /* Follow use-def chain to find all the defs of this use. */ - for (ud_link = DF_REF_CHAIN (use); ud_link; ud_link = ud_link->next) - { - struct ref *def = ud_link->ref; - - /* Unlink this use from the def-use chain. */ - df_ref_unlink (&DF_REF_CHAIN (def), use); - } - DF_REF_CHAIN (use) = 0; - - /* Unlink use from reg-use chain. */ - df_ref_unlink (&df->regs[uregno].uses, use); - - df->uses[DF_REF_ID (use)] = 0; -} - -/* Local routines for recording refs. */ - - -/* Create a new ref of type DF_REF_TYPE for register REG at address - LOC within INSN of BB. */ -static struct ref * -df_ref_create (struct df *df, rtx reg, rtx *loc, rtx insn, - enum df_ref_type ref_type, enum df_ref_flags ref_flags) -{ - struct ref *this_ref; - - this_ref = pool_alloc (df_ref_pool); - DF_REF_REG (this_ref) = reg; - DF_REF_LOC (this_ref) = loc; - DF_REF_INSN (this_ref) = insn; - DF_REF_CHAIN (this_ref) = 0; - DF_REF_TYPE (this_ref) = ref_type; - DF_REF_FLAGS (this_ref) = ref_flags; - - if (ref_type == DF_REF_REG_DEF) - { - if (df->def_id >= df->def_size) - { - /* Make table 25 percent larger. */ - df->def_size += (df->def_size / 4); - df->defs = xrealloc (df->defs, - df->def_size * sizeof (*df->defs)); - } - DF_REF_ID (this_ref) = df->def_id; - df->defs[df->def_id++] = this_ref; - } - else - { - if (df->use_id >= df->use_size) - { - /* Make table 25 percent larger. */ - df->use_size += (df->use_size / 4); - df->uses = xrealloc (df->uses, - df->use_size * sizeof (*df->uses)); - } - DF_REF_ID (this_ref) = df->use_id; - df->uses[df->use_id++] = this_ref; - } - return this_ref; -} - - -/* Create a new reference of type DF_REF_TYPE for a single register REG, - used inside the LOC rtx of INSN. */ -static void -df_ref_record_1 (struct df *df, rtx reg, rtx *loc, rtx insn, - enum df_ref_type ref_type, enum df_ref_flags ref_flags) -{ - df_ref_create (df, reg, loc, insn, ref_type, ref_flags); -} - - -/* Create new references of type DF_REF_TYPE for each part of register REG - at address LOC within INSN of BB. */ -static void -df_ref_record (struct df *df, rtx reg, rtx *loc, rtx insn, - enum df_ref_type ref_type, enum df_ref_flags ref_flags) -{ - unsigned int regno; - - if (GET_CODE (reg) != REG && GET_CODE (reg) != SUBREG) - abort (); - - /* For the reg allocator we are interested in some SUBREG rtx's, but not - all. Notably only those representing a word extraction from a multi-word - reg. As written in the docu those should have the form - (subreg:SI (reg:M A) N), with size(SImode) > size(Mmode). - XXX Is that true? We could also use the global word_mode variable. */ - if (GET_CODE (reg) == SUBREG - && (GET_MODE_SIZE (GET_MODE (reg)) < GET_MODE_SIZE (word_mode) - || GET_MODE_SIZE (GET_MODE (reg)) - >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (reg))))) - { - loc = &SUBREG_REG (reg); - reg = *loc; - ref_flags |= DF_REF_STRIPPED; - } - - regno = REGNO (GET_CODE (reg) == SUBREG ? SUBREG_REG (reg) : reg); - if (regno < FIRST_PSEUDO_REGISTER) - { - int i; - int endregno; - - if (! (df->flags & DF_HARD_REGS)) - return; - - /* GET_MODE (reg) is correct here. We do not want to go into a SUBREG - for the mode, because we only want to add references to regs, which - are really referenced. E.g., a (subreg:SI (reg:DI 0) 0) does _not_ - reference the whole reg 0 in DI mode (which would also include - reg 1, at least, if 0 and 1 are SImode registers). */ - endregno = HARD_REGNO_NREGS (regno, GET_MODE (reg)); - if (GET_CODE (reg) == SUBREG) - regno += subreg_regno_offset (regno, GET_MODE (SUBREG_REG (reg)), - SUBREG_BYTE (reg), GET_MODE (reg)); - endregno += regno; - - for (i = regno; i < endregno; i++) - df_ref_record_1 (df, regno_reg_rtx[i], - loc, insn, ref_type, ref_flags); - } - else - { - df_ref_record_1 (df, reg, loc, insn, ref_type, ref_flags); - } -} - - -/* Return nonzero if writes to paradoxical SUBREGs, or SUBREGs which - are too narrow, are read-modify-write. */ -bool -read_modify_subreg_p (rtx x) -{ - unsigned int isize, osize; - if (GET_CODE (x) != SUBREG) - return false; - isize = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))); - osize = GET_MODE_SIZE (GET_MODE (x)); - /* Paradoxical subreg writes don't leave a trace of the old content. */ - return (isize > osize && isize > UNITS_PER_WORD); -} - - -/* Process all the registers defined in the rtx, X. */ -static void -df_def_record_1 (struct df *df, rtx x, basic_block bb, rtx insn) -{ - rtx *loc; - rtx dst; - enum df_ref_flags flags = 0; - - /* We may recursively call ourselves on EXPR_LIST when dealing with PARALLEL - construct. */ - if (GET_CODE (x) == EXPR_LIST || GET_CODE (x) == CLOBBER) - loc = &XEXP (x, 0); - else - loc = &SET_DEST (x); - dst = *loc; - - /* Some targets place small structures in registers for - return values of functions. */ - if (GET_CODE (dst) == PARALLEL && GET_MODE (dst) == BLKmode) - { - int i; - - for (i = XVECLEN (dst, 0) - 1; i >= 0; i--) - { - rtx temp = XVECEXP (dst, 0, i); - if (GET_CODE (temp) == EXPR_LIST || GET_CODE (temp) == CLOBBER - || GET_CODE (temp) == SET) - df_def_record_1 (df, temp, bb, insn); - } - return; - } - - /* Maybe, we should flag the use of STRICT_LOW_PART somehow. It might - be handy for the reg allocator. */ - while (GET_CODE (dst) == STRICT_LOW_PART - || GET_CODE (dst) == ZERO_EXTRACT - || GET_CODE (dst) == SIGN_EXTRACT - || ((df->flags & DF_FOR_REGALLOC) == 0 - && read_modify_subreg_p (dst))) - { - /* Strict low part always contains SUBREG, but we do not want to make - it appear outside, as whole register is always considered. */ - if (GET_CODE (dst) == STRICT_LOW_PART) - { - loc = &XEXP (dst, 0); - dst = *loc; - } - loc = &XEXP (dst, 0); - dst = *loc; - flags |= DF_REF_READ_WRITE; - } - - if (GET_CODE (dst) == REG - || (GET_CODE (dst) == SUBREG && GET_CODE (SUBREG_REG (dst)) == REG)) - df_ref_record (df, dst, loc, insn, DF_REF_REG_DEF, flags); -} - - -/* Process all the registers defined in the pattern rtx, X. */ -static void -df_defs_record (struct df *df, rtx x, basic_block bb, rtx insn) -{ - RTX_CODE code = GET_CODE (x); - - if (code == SET || code == CLOBBER) - { - /* Mark the single def within the pattern. */ - df_def_record_1 (df, x, bb, insn); - } - else if (code == PARALLEL) - { - int i; - - /* Mark the multiple defs within the pattern. */ - for (i = XVECLEN (x, 0) - 1; i >= 0; i--) - { - code = GET_CODE (XVECEXP (x, 0, i)); - if (code == SET || code == CLOBBER) - df_def_record_1 (df, XVECEXP (x, 0, i), bb, insn); - } - } -} - - -/* Process all the registers used in the rtx at address LOC. */ -static void -df_uses_record (struct df *df, rtx *loc, enum df_ref_type ref_type, - basic_block bb, rtx insn, enum df_ref_flags flags) -{ - RTX_CODE code; - rtx x; - retry: - x = *loc; - if (!x) - return; - code = GET_CODE (x); - switch (code) - { - case LABEL_REF: - case SYMBOL_REF: - case CONST_INT: - case CONST: - case CONST_DOUBLE: - case CONST_VECTOR: - case PC: - case CC0: - case ADDR_VEC: - case ADDR_DIFF_VEC: - return; - - case CLOBBER: - /* If we are clobbering a MEM, mark any registers inside the address - as being used. */ - if (GET_CODE (XEXP (x, 0)) == MEM) - df_uses_record (df, &XEXP (XEXP (x, 0), 0), - DF_REF_REG_MEM_STORE, bb, insn, flags); - - /* If we're clobbering a REG then we have a def so ignore. */ - return; - - case MEM: - df_uses_record (df, &XEXP (x, 0), DF_REF_REG_MEM_LOAD, bb, insn, 0); - return; - - case SUBREG: - /* While we're here, optimize this case. */ - - /* In case the SUBREG is not of a REG, do not optimize. */ - if (GET_CODE (SUBREG_REG (x)) != REG) - { - loc = &SUBREG_REG (x); - df_uses_record (df, loc, ref_type, bb, insn, flags); - return; - } - /* ... Fall through ... */ - - case REG: - df_ref_record (df, x, loc, insn, ref_type, flags); - return; - - case SET: - { - rtx dst = SET_DEST (x); - - df_uses_record (df, &SET_SRC (x), DF_REF_REG_USE, bb, insn, 0); - - switch (GET_CODE (dst)) - { - case SUBREG: - if ((df->flags & DF_FOR_REGALLOC) == 0 - && read_modify_subreg_p (dst)) - { - df_uses_record (df, &SUBREG_REG (dst), DF_REF_REG_USE, bb, - insn, DF_REF_READ_WRITE); - break; - } - /* Fall through. */ - case REG: - case PARALLEL: - case PC: - case CC0: - break; - case MEM: - df_uses_record (df, &XEXP (dst, 0), - DF_REF_REG_MEM_STORE, - bb, insn, 0); - break; - case STRICT_LOW_PART: - /* A strict_low_part uses the whole REG and not just the SUBREG. */ - dst = XEXP (dst, 0); - if (GET_CODE (dst) != SUBREG) - abort (); - df_uses_record (df, &SUBREG_REG (dst), DF_REF_REG_USE, bb, - insn, DF_REF_READ_WRITE); - break; - case ZERO_EXTRACT: - case SIGN_EXTRACT: - df_uses_record (df, &XEXP (dst, 0), DF_REF_REG_USE, bb, insn, - DF_REF_READ_WRITE); - df_uses_record (df, &XEXP (dst, 1), DF_REF_REG_USE, bb, insn, 0); - df_uses_record (df, &XEXP (dst, 2), DF_REF_REG_USE, bb, insn, 0); - dst = XEXP (dst, 0); - break; - default: - abort (); - } - return; - } - - case RETURN: - break; - - case ASM_OPERANDS: - case UNSPEC_VOLATILE: - case TRAP_IF: - case ASM_INPUT: - { - /* 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. - - Consider for instance a volatile asm that changes the fpu rounding - mode. An insn should not be moved across this even if it only uses - pseudo-regs because it might give an incorrectly rounded result. - - For now, just mark any regs we can find in ASM_OPERANDS as - used. */ - - /* 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. */ - if (code == ASM_OPERANDS) - { - int j; - - for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++) - df_uses_record (df, &ASM_OPERANDS_INPUT (x, j), - DF_REF_REG_USE, bb, insn, 0); - return; - } - break; - } - - case PRE_DEC: - case POST_DEC: - case PRE_INC: - case POST_INC: - case PRE_MODIFY: - case POST_MODIFY: - /* Catch the def of the register being modified. */ - df_ref_record (df, XEXP (x, 0), &XEXP (x, 0), insn, DF_REF_REG_DEF, DF_REF_READ_WRITE); - - /* ... Fall through to handle uses ... */ - - default: - break; - } - - /* Recursively scan the operands of this expression. */ - { - const char *fmt = GET_RTX_FORMAT (code); - int i; - - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - { - /* Tail recursive case: save a function call level. */ - if (i == 0) - { - loc = &XEXP (x, 0); - goto retry; - } - df_uses_record (df, &XEXP (x, i), ref_type, bb, insn, flags); - } - else if (fmt[i] == 'E') - { - int j; - for (j = 0; j < XVECLEN (x, i); j++) - df_uses_record (df, &XVECEXP (x, i, j), ref_type, - bb, insn, flags); - } - } - } -} - - -/* Record all the df within INSN of basic block BB. */ -static void -df_insn_refs_record (struct df *df, basic_block bb, rtx insn) -{ - int i; - - if (INSN_P (insn)) - { - rtx note; - - /* Record register defs. */ - df_defs_record (df, PATTERN (insn), bb, insn); - - if (df->flags & DF_EQUIV_NOTES) - for (note = REG_NOTES (insn); note; - note = XEXP (note, 1)) - { - switch (REG_NOTE_KIND (note)) - { - case REG_EQUIV: - case REG_EQUAL: - df_uses_record (df, &XEXP (note, 0), DF_REF_REG_USE, - bb, insn, 0); - default: - break; - } - } - - if (GET_CODE (insn) == CALL_INSN) - { - rtx note; - rtx x; - - /* Record the registers used to pass arguments. */ - for (note = CALL_INSN_FUNCTION_USAGE (insn); note; - note = XEXP (note, 1)) - { - if (GET_CODE (XEXP (note, 0)) == USE) - df_uses_record (df, &XEXP (XEXP (note, 0), 0), DF_REF_REG_USE, - bb, insn, 0); - } - - /* The stack ptr is used (honorarily) by a CALL insn. */ - x = df_reg_use_gen (STACK_POINTER_REGNUM); - df_uses_record (df, &XEXP (x, 0), DF_REF_REG_USE, bb, insn, 0); - - if (df->flags & DF_HARD_REGS) - { - /* Calls may also reference any of the global registers, - so they are recorded as used. */ - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (global_regs[i]) - { - x = df_reg_use_gen (i); - df_uses_record (df, &SET_DEST (x), - DF_REF_REG_USE, bb, insn, 0); - } - } - } - - /* Record the register uses. */ - df_uses_record (df, &PATTERN (insn), - DF_REF_REG_USE, bb, insn, 0); - - if (GET_CODE (insn) == CALL_INSN) - { - rtx note; - - if (df->flags & DF_HARD_REGS) - { - /* Kill all registers invalidated by a call. */ - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) - { - rtx reg_clob = df_reg_clobber_gen (i); - df_defs_record (df, reg_clob, bb, insn); - } - } - - /* There may be extra registers to be clobbered. */ - for (note = CALL_INSN_FUNCTION_USAGE (insn); - note; - note = XEXP (note, 1)) - if (GET_CODE (XEXP (note, 0)) == CLOBBER) - df_defs_record (df, XEXP (note, 0), bb, insn); - } - } -} - - -/* Record all the refs within the basic block BB. */ -static void -df_bb_refs_record (struct df *df, basic_block bb) -{ - rtx insn; - - /* Scan the block an insn at a time from beginning to end. */ - for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn)) - { - if (INSN_P (insn)) - { - /* Record defs within INSN. */ - df_insn_refs_record (df, bb, insn); - } - if (insn == BB_END (bb)) - break; - } -} - - -/* Record all the refs in the basic blocks specified by BLOCKS. */ -static void -df_refs_record (struct df *df, bitmap blocks) -{ - basic_block bb; - - FOR_EACH_BB_IN_BITMAP (blocks, 0, bb, - { - df_bb_refs_record (df, bb); - }); -} - -/* Dataflow analysis routines. */ - - -/* Create reg-def chains for basic block BB. These are a list of - definitions for each register. */ -static void -df_bb_reg_def_chain_create (struct df *df, basic_block bb) -{ - rtx insn; - - /* Perhaps the defs should be sorted using a depth first search - of the CFG (or possibly a breadth first search). We currently - scan the basic blocks in reverse order so that the first defs - appear at the start of the chain. */ - - for (insn = BB_END (bb); insn && insn != PREV_INSN (BB_HEAD (bb)); - insn = PREV_INSN (insn)) - { - struct df_link *link; - unsigned int uid = INSN_UID (insn); - - if (! INSN_P (insn)) - continue; - - for (link = df->insns[uid].defs; link; link = link->next) - { - struct ref *def = link->ref; - unsigned int dregno = DF_REF_REGNO (def); - - /* Do not add ref's to the chain twice, i.e., only add new - refs. XXX the same could be done by testing if the - current insn is a modified (or a new) one. This would be - faster. */ - if (DF_REF_ID (def) < df->def_id_save) - continue; - - df->regs[dregno].defs - = df_link_create (def, df->regs[dregno].defs); - } - } -} - - -/* Create reg-def chains for each basic block within BLOCKS. These - are a list of definitions for each register. */ -static void -df_reg_def_chain_create (struct df *df, bitmap blocks) -{ - basic_block bb; - - FOR_EACH_BB_IN_BITMAP/*_REV*/ (blocks, 0, bb, - { - df_bb_reg_def_chain_create (df, bb); - }); -} - - -/* Create reg-use chains for basic block BB. These are a list of uses - for each register. */ -static void -df_bb_reg_use_chain_create (struct df *df, basic_block bb) -{ - rtx insn; - - /* Scan in forward order so that the last uses appear at the start - of the chain. */ - - for (insn = BB_HEAD (bb); insn && insn != NEXT_INSN (BB_END (bb)); - insn = NEXT_INSN (insn)) - { - struct df_link *link; - unsigned int uid = INSN_UID (insn); - - if (! INSN_P (insn)) - continue; - - for (link = df->insns[uid].uses; link; link = link->next) - { - struct ref *use = link->ref; - unsigned int uregno = DF_REF_REGNO (use); - - /* Do not add ref's to the chain twice, i.e., only add new - refs. XXX the same could be done by testing if the - current insn is a modified (or a new) one. This would be - faster. */ - if (DF_REF_ID (use) < df->use_id_save) - continue; - - df->regs[uregno].uses - = df_link_create (use, df->regs[uregno].uses); - } - } -} - - -/* Create reg-use chains for each basic block within BLOCKS. These - are a list of uses for each register. */ -static void -df_reg_use_chain_create (struct df *df, bitmap blocks) -{ - basic_block bb; - - FOR_EACH_BB_IN_BITMAP (blocks, 0, bb, - { - df_bb_reg_use_chain_create (df, bb); - }); -} - - -/* Create def-use chains from reaching use bitmaps for basic block BB. */ -static void -df_bb_du_chain_create (struct df *df, basic_block bb, bitmap ru) -{ - struct bb_info *bb_info = DF_BB_INFO (df, bb); - rtx insn; - - bitmap_copy (ru, bb_info->ru_out); - - /* For each def in BB create a linked list (chain) of uses - reached from the def. */ - for (insn = BB_END (bb); insn && insn != PREV_INSN (BB_HEAD (bb)); - insn = PREV_INSN (insn)) - { - struct df_link *def_link; - struct df_link *use_link; - unsigned int uid = INSN_UID (insn); - - if (! INSN_P (insn)) - continue; - - /* For each def in insn... */ - for (def_link = df->insns[uid].defs; def_link; def_link = def_link->next) - { - struct ref *def = def_link->ref; - unsigned int dregno = DF_REF_REGNO (def); - - DF_REF_CHAIN (def) = 0; - - /* While the reg-use chains are not essential, it - is _much_ faster to search these short lists rather - than all the reaching uses, especially for large functions. */ - for (use_link = df->regs[dregno].uses; use_link; - use_link = use_link->next) - { - struct ref *use = use_link->ref; - - if (bitmap_bit_p (ru, DF_REF_ID (use))) - { - DF_REF_CHAIN (def) - = df_link_create (use, DF_REF_CHAIN (def)); - - bitmap_clear_bit (ru, DF_REF_ID (use)); - } - } - } - - /* For each use in insn... */ - for (use_link = df->insns[uid].uses; use_link; use_link = use_link->next) - { - struct ref *use = use_link->ref; - bitmap_set_bit (ru, DF_REF_ID (use)); - } - } -} - - -/* Create def-use chains from reaching use bitmaps for basic blocks - in BLOCKS. */ -static void -df_du_chain_create (struct df *df, bitmap blocks) -{ - bitmap ru; - basic_block bb; - - ru = BITMAP_XMALLOC (); - - FOR_EACH_BB_IN_BITMAP (blocks, 0, bb, - { - df_bb_du_chain_create (df, bb, ru); - }); - - BITMAP_XFREE (ru); -} - - -/* Create use-def chains from reaching def bitmaps for basic block BB. */ -static void -df_bb_ud_chain_create (struct df *df, basic_block bb) -{ - struct bb_info *bb_info = DF_BB_INFO (df, bb); - struct ref **reg_def_last = df->reg_def_last; - rtx insn; - - memset (reg_def_last, 0, df->n_regs * sizeof (struct ref *)); - - /* For each use in BB create a linked list (chain) of defs - that reach the use. */ - for (insn = BB_HEAD (bb); insn && insn != NEXT_INSN (BB_END (bb)); - insn = NEXT_INSN (insn)) - { - unsigned int uid = INSN_UID (insn); - struct df_link *use_link; - struct df_link *def_link; - - if (! INSN_P (insn)) - continue; - - /* For each use in insn... */ - for (use_link = df->insns[uid].uses; use_link; use_link = use_link->next) - { - struct ref *use = use_link->ref; - unsigned int regno = DF_REF_REGNO (use); - - DF_REF_CHAIN (use) = 0; - - /* Has regno been defined in this BB yet? If so, use - the last def as the single entry for the use-def - chain for this use. Otherwise, we need to add all - the defs using this regno that reach the start of - this BB. */ - if (reg_def_last[regno]) - { - DF_REF_CHAIN (use) - = df_link_create (reg_def_last[regno], 0); - } - else - { - /* While the reg-def chains are not essential, it is - _much_ faster to search these short lists rather than - all the reaching defs, especially for large - functions. */ - for (def_link = df->regs[regno].defs; def_link; - def_link = def_link->next) - { - struct ref *def = def_link->ref; - - if (bitmap_bit_p (bb_info->rd_in, DF_REF_ID (def))) - { - DF_REF_CHAIN (use) - = df_link_create (def, DF_REF_CHAIN (use)); - } - } - } - } - - - /* For each def in insn... record the last def of each reg. */ - for (def_link = df->insns[uid].defs; def_link; def_link = def_link->next) - { - struct ref *def = def_link->ref; - int dregno = DF_REF_REGNO (def); - - reg_def_last[dregno] = def; - } - } -} - - -/* Create use-def chains from reaching def bitmaps for basic blocks - within BLOCKS. */ -static void -df_ud_chain_create (struct df *df, bitmap blocks) -{ - basic_block bb; - - FOR_EACH_BB_IN_BITMAP (blocks, 0, bb, - { - df_bb_ud_chain_create (df, bb); - }); -} - - - -static void -df_rd_transfer_function (int bb ATTRIBUTE_UNUSED, int *changed, bitmap in, - bitmap out, bitmap gen, bitmap kill, - void *data ATTRIBUTE_UNUSED) -{ - *changed = bitmap_union_of_diff (out, gen, in, kill); -} - - -static void -df_ru_transfer_function (int bb ATTRIBUTE_UNUSED, int *changed, bitmap in, - bitmap out, bitmap gen, bitmap kill, - void *data ATTRIBUTE_UNUSED) -{ - *changed = bitmap_union_of_diff (in, gen, out, kill); -} - - -static void -df_lr_transfer_function (int bb ATTRIBUTE_UNUSED, int *changed, bitmap in, - bitmap out, bitmap use, bitmap def, - void *data ATTRIBUTE_UNUSED) -{ - *changed = bitmap_union_of_diff (in, use, out, def); -} - - -/* Compute local reaching def info for basic block BB. */ -static void -df_bb_rd_local_compute (struct df *df, basic_block bb) -{ - struct bb_info *bb_info = DF_BB_INFO (df, bb); - rtx insn; - - for (insn = BB_HEAD (bb); insn && insn != NEXT_INSN (BB_END (bb)); - insn = NEXT_INSN (insn)) - { - unsigned int uid = INSN_UID (insn); - struct df_link *def_link; - - if (! INSN_P (insn)) - continue; - - for (def_link = df->insns[uid].defs; def_link; def_link = def_link->next) - { - struct ref *def = def_link->ref; - unsigned int regno = DF_REF_REGNO (def); - struct df_link *def2_link; - - for (def2_link = df->regs[regno].defs; def2_link; - def2_link = def2_link->next) - { - struct ref *def2 = def2_link->ref; - - /* Add all defs of this reg to the set of kills. This - is greedy since many of these defs will not actually - be killed by this BB but it keeps things a lot - simpler. */ - bitmap_set_bit (bb_info->rd_kill, DF_REF_ID (def2)); - - /* Zap from the set of gens for this BB. */ - bitmap_clear_bit (bb_info->rd_gen, DF_REF_ID (def2)); - } - - bitmap_set_bit (bb_info->rd_gen, DF_REF_ID (def)); - } - } - - bb_info->rd_valid = 1; -} - - -/* Compute local reaching def info for each basic block within BLOCKS. */ -static void -df_rd_local_compute (struct df *df, bitmap blocks) -{ - basic_block bb; - - FOR_EACH_BB_IN_BITMAP (blocks, 0, bb, - { - df_bb_rd_local_compute (df, bb); - }); -} - - -/* Compute local reaching use (upward exposed use) info for basic - block BB. */ -static void -df_bb_ru_local_compute (struct df *df, basic_block bb) -{ - /* This is much more tricky than computing reaching defs. With - reaching defs, defs get killed by other defs. With upwards - exposed uses, these get killed by defs with the same regno. */ - - struct bb_info *bb_info = DF_BB_INFO (df, bb); - rtx insn; - - - for (insn = BB_END (bb); insn && insn != PREV_INSN (BB_HEAD (bb)); - insn = PREV_INSN (insn)) - { - unsigned int uid = INSN_UID (insn); - struct df_link *def_link; - struct df_link *use_link; - - if (! INSN_P (insn)) - continue; - - for (def_link = df->insns[uid].defs; def_link; def_link = def_link->next) - { - struct ref *def = def_link->ref; - unsigned int dregno = DF_REF_REGNO (def); - - for (use_link = df->regs[dregno].uses; use_link; - use_link = use_link->next) - { - struct ref *use = use_link->ref; - - /* Add all uses of this reg to the set of kills. This - is greedy since many of these uses will not actually - be killed by this BB but it keeps things a lot - simpler. */ - bitmap_set_bit (bb_info->ru_kill, DF_REF_ID (use)); - - /* Zap from the set of gens for this BB. */ - bitmap_clear_bit (bb_info->ru_gen, DF_REF_ID (use)); - } - } - - for (use_link = df->insns[uid].uses; use_link; use_link = use_link->next) - { - struct ref *use = use_link->ref; - /* Add use to set of gens in this BB. */ - bitmap_set_bit (bb_info->ru_gen, DF_REF_ID (use)); - } - } - bb_info->ru_valid = 1; -} - - -/* Compute local reaching use (upward exposed use) info for each basic - block within BLOCKS. */ -static void -df_ru_local_compute (struct df *df, bitmap blocks) -{ - basic_block bb; - - FOR_EACH_BB_IN_BITMAP (blocks, 0, bb, - { - df_bb_ru_local_compute (df, bb); - }); -} - - -/* Compute local live variable info for basic block BB. */ -static void -df_bb_lr_local_compute (struct df *df, basic_block bb) -{ - struct bb_info *bb_info = DF_BB_INFO (df, bb); - rtx insn; - - for (insn = BB_END (bb); insn && insn != PREV_INSN (BB_HEAD (bb)); - insn = PREV_INSN (insn)) - { - unsigned int uid = INSN_UID (insn); - struct df_link *link; - - if (! INSN_P (insn)) - continue; - - for (link = df->insns[uid].defs; link; link = link->next) - { - struct ref *def = link->ref; - unsigned int dregno = DF_REF_REGNO (def); - - /* Add def to set of defs in this BB. */ - bitmap_set_bit (bb_info->lr_def, dregno); - - bitmap_clear_bit (bb_info->lr_use, dregno); - } - - for (link = df->insns[uid].uses; link; link = link->next) - { - struct ref *use = link->ref; - /* Add use to set of uses in this BB. */ - bitmap_set_bit (bb_info->lr_use, DF_REF_REGNO (use)); - } - } - bb_info->lr_valid = 1; -} - - -/* Compute local live variable info for each basic block within BLOCKS. */ -static void -df_lr_local_compute (struct df *df, bitmap blocks) -{ - basic_block bb; - - FOR_EACH_BB_IN_BITMAP (blocks, 0, bb, - { - df_bb_lr_local_compute (df, bb); - }); -} - - -/* Compute register info: lifetime, bb, and number of defs and uses - for basic block BB. */ -static void -df_bb_reg_info_compute (struct df *df, basic_block bb, bitmap live) -{ - struct reg_info *reg_info = df->regs; - struct bb_info *bb_info = DF_BB_INFO (df, bb); - rtx insn; - - bitmap_copy (live, bb_info->lr_out); - - for (insn = BB_END (bb); insn && insn != PREV_INSN (BB_HEAD (bb)); - insn = PREV_INSN (insn)) - { - unsigned int uid = INSN_UID (insn); - unsigned int regno; - struct df_link *link; - - if (! INSN_P (insn)) - continue; - - for (link = df->insns[uid].defs; link; link = link->next) - { - struct ref *def = link->ref; - unsigned int dregno = DF_REF_REGNO (def); - - /* Kill this register. */ - bitmap_clear_bit (live, dregno); - reg_info[dregno].n_defs++; - } - - for (link = df->insns[uid].uses; link; link = link->next) - { - struct ref *use = link->ref; - unsigned int uregno = DF_REF_REGNO (use); - - /* This register is now live. */ - bitmap_set_bit (live, uregno); - reg_info[uregno].n_uses++; - } - - /* Increment lifetimes of all live registers. */ - EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, - { - reg_info[regno].lifetime++; - }); - } -} - - -/* Compute register info: lifetime, bb, and number of defs and uses. */ -static void -df_reg_info_compute (struct df *df, bitmap blocks) -{ - basic_block bb; - bitmap live; - - live = BITMAP_XMALLOC (); - - FOR_EACH_BB_IN_BITMAP (blocks, 0, bb, - { - df_bb_reg_info_compute (df, bb, live); - }); - - BITMAP_XFREE (live); -} - - -/* Assign LUIDs for BB. */ -static int -df_bb_luids_set (struct df *df, basic_block bb) -{ - rtx insn; - int luid = 0; - - /* The LUIDs are monotonically increasing for each basic block. */ - - for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn)) - { - if (INSN_P (insn)) - DF_INSN_LUID (df, insn) = luid++; - DF_INSN_LUID (df, insn) = luid; - - if (insn == BB_END (bb)) - break; - } - return luid; -} - - -/* Assign LUIDs for each basic block within BLOCKS. */ -static int -df_luids_set (struct df *df, bitmap blocks) -{ - basic_block bb; - int total = 0; - - FOR_EACH_BB_IN_BITMAP (blocks, 0, bb, - { - total += df_bb_luids_set (df, bb); - }); - return total; -} - - -/* Perform dataflow analysis using existing DF structure for blocks - within BLOCKS. If BLOCKS is zero, use all basic blocks in the CFG. */ -static void -df_analyse_1 (struct df *df, bitmap blocks, int flags, int update) -{ - int aflags; - int dflags; - int i; - basic_block bb; - - dflags = 0; - aflags = flags; - if (flags & DF_UD_CHAIN) - aflags |= DF_RD | DF_RD_CHAIN; - - if (flags & DF_DU_CHAIN) - aflags |= DF_RU; - - if (flags & DF_RU) - aflags |= DF_RU_CHAIN; - - if (flags & DF_REG_INFO) - aflags |= DF_LR; - - if (! blocks) - blocks = df->all_blocks; - - df->flags = flags; - if (update) - { - df_refs_update (df); - /* More fine grained incremental dataflow analysis would be - nice. For now recompute the whole shebang for the - modified blocks. */ -#if 0 - df_refs_unlink (df, blocks); -#endif - /* All the def-use, use-def chains can be potentially - modified by changes in one block. The size of the - bitmaps can also change. */ - } - else - { - /* Scan the function for all register defs and uses. */ - df_refs_queue (df); - df_refs_record (df, blocks); - - /* Link all the new defs and uses to the insns. */ - df_refs_process (df); - } - - /* Allocate the bitmaps now the total number of defs and uses are - known. If the number of defs or uses have changed, then - these bitmaps need to be reallocated. */ - df_bitmaps_alloc (df, aflags); - - /* Set the LUIDs for each specified basic block. */ - df_luids_set (df, blocks); - - /* Recreate reg-def and reg-use chains from scratch so that first - def is at the head of the reg-def chain and the last use is at - the head of the reg-use chain. This is only important for - regs local to a basic block as it speeds up searching. */ - if (aflags & DF_RD_CHAIN) - { - df_reg_def_chain_create (df, blocks); - } - - if (aflags & DF_RU_CHAIN) - { - df_reg_use_chain_create (df, blocks); - } - - df->dfs_order = xmalloc (sizeof (int) * n_basic_blocks); - df->rc_order = xmalloc (sizeof (int) * n_basic_blocks); - df->rts_order = xmalloc (sizeof (int) * n_basic_blocks); - df->inverse_dfs_map = xmalloc (sizeof (int) * last_basic_block); - df->inverse_rc_map = xmalloc (sizeof (int) * last_basic_block); - df->inverse_rts_map = xmalloc (sizeof (int) * last_basic_block); - - flow_depth_first_order_compute (df->dfs_order, df->rc_order); - flow_reverse_top_sort_order_compute (df->rts_order); - for (i = 0; i < n_basic_blocks; i++) - { - df->inverse_dfs_map[df->dfs_order[i]] = i; - df->inverse_rc_map[df->rc_order[i]] = i; - df->inverse_rts_map[df->rts_order[i]] = i; - } - if (aflags & DF_RD) - { - /* Compute the sets of gens and kills for the defs of each bb. */ - df_rd_local_compute (df, df->flags & DF_RD ? blocks : df->all_blocks); - { - bitmap *in = xmalloc (sizeof (bitmap) * last_basic_block); - bitmap *out = xmalloc (sizeof (bitmap) * last_basic_block); - bitmap *gen = xmalloc (sizeof (bitmap) * last_basic_block); - bitmap *kill = xmalloc (sizeof (bitmap) * last_basic_block); - FOR_EACH_BB (bb) - { - in[bb->index] = DF_BB_INFO (df, bb)->rd_in; - out[bb->index] = DF_BB_INFO (df, bb)->rd_out; - gen[bb->index] = DF_BB_INFO (df, bb)->rd_gen; - kill[bb->index] = DF_BB_INFO (df, bb)->rd_kill; - } - iterative_dataflow_bitmap (in, out, gen, kill, df->all_blocks, - DF_FORWARD, DF_UNION, df_rd_transfer_function, - df->inverse_rc_map, NULL); - free (in); - free (out); - free (gen); - free (kill); - } - } - - if (aflags & DF_UD_CHAIN) - { - /* Create use-def chains. */ - df_ud_chain_create (df, df->all_blocks); - - if (! (flags & DF_RD)) - dflags |= DF_RD; - } - - if (aflags & DF_RU) - { - /* Compute the sets of gens and kills for the upwards exposed - uses in each bb. */ - df_ru_local_compute (df, df->flags & DF_RU ? blocks : df->all_blocks); - { - bitmap *in = xmalloc (sizeof (bitmap) * last_basic_block); - bitmap *out = xmalloc (sizeof (bitmap) * last_basic_block); - bitmap *gen = xmalloc (sizeof (bitmap) * last_basic_block); - bitmap *kill = xmalloc (sizeof (bitmap) * last_basic_block); - FOR_EACH_BB (bb) - { - in[bb->index] = DF_BB_INFO (df, bb)->ru_in; - out[bb->index] = DF_BB_INFO (df, bb)->ru_out; - gen[bb->index] = DF_BB_INFO (df, bb)->ru_gen; - kill[bb->index] = DF_BB_INFO (df, bb)->ru_kill; - } - iterative_dataflow_bitmap (in, out, gen, kill, df->all_blocks, - DF_BACKWARD, DF_UNION, df_ru_transfer_function, - df->inverse_rts_map, NULL); - free (in); - free (out); - free (gen); - free (kill); - } - } - - if (aflags & DF_DU_CHAIN) - { - /* Create def-use chains. */ - df_du_chain_create (df, df->all_blocks); - - if (! (flags & DF_RU)) - dflags |= DF_RU; - } - - /* Free up bitmaps that are no longer required. */ - if (dflags) - df_bitmaps_free (df, dflags); - - if (aflags & DF_LR) - { - /* Compute the sets of defs and uses of live variables. */ - df_lr_local_compute (df, df->flags & DF_LR ? blocks : df->all_blocks); - { - bitmap *in = xmalloc (sizeof (bitmap) * last_basic_block); - bitmap *out = xmalloc (sizeof (bitmap) * last_basic_block); - bitmap *use = xmalloc (sizeof (bitmap) * last_basic_block); - bitmap *def = xmalloc (sizeof (bitmap) * last_basic_block); - FOR_EACH_BB (bb) - { - in[bb->index] = DF_BB_INFO (df, bb)->lr_in; - out[bb->index] = DF_BB_INFO (df, bb)->lr_out; - use[bb->index] = DF_BB_INFO (df, bb)->lr_use; - def[bb->index] = DF_BB_INFO (df, bb)->lr_def; - } - iterative_dataflow_bitmap (in, out, use, def, df->all_blocks, - DF_BACKWARD, DF_UNION, df_lr_transfer_function, - df->inverse_rts_map, NULL); - free (in); - free (out); - free (use); - free (def); - } - } - - if (aflags & DF_REG_INFO) - { - df_reg_info_compute (df, df->all_blocks); - } - - free (df->dfs_order); - free (df->rc_order); - free (df->rts_order); - free (df->inverse_rc_map); - free (df->inverse_dfs_map); - free (df->inverse_rts_map); -} - - -/* Initialize dataflow analysis. */ -struct df * -df_init (void) -{ - struct df *df; - - df = xcalloc (1, sizeof (struct df)); - - /* Squirrel away a global for debugging. */ - ddf = df; - - return df; -} - - -/* Start queuing refs. */ -static int -df_refs_queue (struct df *df) -{ - df->def_id_save = df->def_id; - df->use_id_save = df->use_id; - /* ???? Perhaps we should save current obstack state so that we can - unwind it. */ - return 0; -} - - -/* Process queued refs. */ -static int -df_refs_process (struct df *df) -{ - unsigned int i; - - /* Build new insn-def chains. */ - for (i = df->def_id_save; i != df->def_id; i++) - { - struct ref *def = df->defs[i]; - unsigned int uid = DF_REF_INSN_UID (def); - - /* Add def to head of def list for INSN. */ - df->insns[uid].defs - = df_link_create (def, df->insns[uid].defs); - } - - /* Build new insn-use chains. */ - for (i = df->use_id_save; i != df->use_id; i++) - { - struct ref *use = df->uses[i]; - unsigned int uid = DF_REF_INSN_UID (use); - - /* Add use to head of use list for INSN. */ - df->insns[uid].uses - = df_link_create (use, df->insns[uid].uses); - } - return 0; -} - - -/* Update refs for basic block BB. */ -static int -df_bb_refs_update (struct df *df, basic_block bb) -{ - rtx insn; - int count = 0; - - /* While we have to scan the chain of insns for this BB, we do not - need to allocate and queue a long chain of BB/INSN pairs. Using - a bitmap for insns_modified saves memory and avoids queuing - duplicates. */ - - for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn)) - { - unsigned int uid; - - uid = INSN_UID (insn); - - if (bitmap_bit_p (df->insns_modified, uid)) - { - /* Delete any allocated refs of this insn. MPH, FIXME. */ - df_insn_refs_unlink (df, bb, insn); - - /* Scan the insn for refs. */ - df_insn_refs_record (df, bb, insn); - - count++; - } - if (insn == BB_END (bb)) - break; - } - return count; -} - - -/* Process all the modified/deleted insns that were queued. */ -static int -df_refs_update (struct df *df) -{ - basic_block bb; - int count = 0; - - if ((unsigned int) max_reg_num () >= df->reg_size) - df_reg_table_realloc (df, 0); - - df_refs_queue (df); - - FOR_EACH_BB_IN_BITMAP (df->bbs_modified, 0, bb, - { - count += df_bb_refs_update (df, bb); - }); - - df_refs_process (df); - return count; -} - - -/* Return nonzero if any of the requested blocks in the bitmap - BLOCKS have been modified. */ -static int -df_modified_p (struct df *df, bitmap blocks) -{ - int update = 0; - basic_block bb; - - if (!df->n_bbs) - return 0; - - FOR_EACH_BB (bb) - if (bitmap_bit_p (df->bbs_modified, bb->index) - && (! blocks || (blocks == (bitmap) -1) || bitmap_bit_p (blocks, bb->index))) - { - update = 1; - break; - } - - return update; -} - - -/* Analyze dataflow info for the basic blocks specified by the bitmap - BLOCKS, or for the whole CFG if BLOCKS is zero, or just for the - modified blocks if BLOCKS is -1. */ -int -df_analyse (struct df *df, bitmap blocks, int flags) -{ - int update; - - /* We could deal with additional basic blocks being created by - rescanning everything again. */ - if (df->n_bbs && df->n_bbs != (unsigned int) last_basic_block) - abort (); - - update = df_modified_p (df, blocks); - if (update || (flags != df->flags)) - { - if (! blocks) - { - if (df->n_bbs) - { - /* Recompute everything from scratch. */ - df_free (df); - } - /* Allocate and initialize data structures. */ - df_alloc (df, max_reg_num ()); - df_analyse_1 (df, 0, flags, 0); - update = 1; - } - else - { - if (blocks == (bitmap) -1) - blocks = df->bbs_modified; - - if (! df->n_bbs) - abort (); - - df_analyse_1 (df, blocks, flags, 1); - bitmap_zero (df->bbs_modified); - bitmap_zero (df->insns_modified); - } - } - return update; -} - - -/* Free all the dataflow info and the DF structure. */ -void -df_finish (struct df *df) -{ - df_free (df); - free (df); -} - - -/* Unlink INSN from its reference information. */ -static void -df_insn_refs_unlink (struct df *df, basic_block bb ATTRIBUTE_UNUSED, rtx insn) -{ - struct df_link *link; - unsigned int uid; - - uid = INSN_UID (insn); - - /* Unlink all refs defined by this insn. */ - for (link = df->insns[uid].defs; link; link = link->next) - df_def_unlink (df, link->ref); - - /* Unlink all refs used by this insn. */ - for (link = df->insns[uid].uses; link; link = link->next) - df_use_unlink (df, link->ref); - - df->insns[uid].defs = 0; - df->insns[uid].uses = 0; -} - - -#if 0 -/* Unlink all the insns within BB from their reference information. */ -static void -df_bb_refs_unlink (struct df *df, basic_block bb) -{ - rtx insn; - - /* Scan the block an insn at a time from beginning to end. */ - for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn)) - { - if (INSN_P (insn)) - { - /* Unlink refs for INSN. */ - df_insn_refs_unlink (df, bb, insn); - } - if (insn == BB_END (bb)) - break; - } -} - - -/* Unlink all the refs in the basic blocks specified by BLOCKS. - Not currently used. */ -static void -df_refs_unlink (struct df *df, bitmap blocks) -{ - basic_block bb; - - if (blocks) - { - FOR_EACH_BB_IN_BITMAP (blocks, 0, bb, - { - df_bb_refs_unlink (df, bb); - }); - } - else - { - FOR_EACH_BB (bb) - df_bb_refs_unlink (df, bb); - } -} -#endif - -/* Functions to modify insns. */ - - -/* Delete INSN and all its reference information. */ -rtx -df_insn_delete (struct df *df, basic_block bb ATTRIBUTE_UNUSED, rtx insn) -{ - /* If the insn is a jump, we should perhaps call delete_insn to - handle the JUMP_LABEL? */ - - /* We should not be deleting the NOTE_INSN_BASIC_BLOCK or label. */ - if (insn == BB_HEAD (bb)) - abort (); - - /* Delete the insn. */ - delete_insn (insn); - - df_insn_modify (df, bb, insn); - - return NEXT_INSN (insn); -} - - -/* Mark that INSN within BB may have changed (created/modified/deleted). - This may be called multiple times for the same insn. There is no - harm calling this function if the insn wasn't changed; it will just - slow down the rescanning of refs. */ -void -df_insn_modify (struct df *df, basic_block bb, rtx insn) -{ - unsigned int uid; - - uid = INSN_UID (insn); - if (uid >= df->insn_size) - df_insn_table_realloc (df, uid); - - bitmap_set_bit (df->bbs_modified, bb->index); - bitmap_set_bit (df->insns_modified, uid); - - /* For incremental updating on the fly, perhaps we could make a copy - of all the refs of the original insn and turn them into - anti-refs. When df_refs_update finds these anti-refs, it annihilates - the original refs. If validate_change fails then these anti-refs - will just get ignored. */ -} - - -typedef struct replace_args -{ - rtx match; - rtx replacement; - rtx insn; - int modified; -} replace_args; - - -/* Replace mem pointed to by PX with its associated pseudo register. - DATA is actually a pointer to a structure describing the - instruction currently being scanned and the MEM we are currently - replacing. */ -static int -df_rtx_mem_replace (rtx *px, void *data) -{ - replace_args *args = (replace_args *) data; - rtx mem = *px; - - if (mem == NULL_RTX) - return 0; - - switch (GET_CODE (mem)) - { - case MEM: - break; - - case CONST_DOUBLE: - /* We're not interested in the MEM associated with a - CONST_DOUBLE, so there's no need to traverse into one. */ - return -1; - - default: - /* This is not a MEM. */ - return 0; - } - - if (!rtx_equal_p (args->match, mem)) - /* This is not the MEM we are currently replacing. */ - return 0; - - /* Actually replace the MEM. */ - validate_change (args->insn, px, args->replacement, 1); - args->modified++; - - return 0; -} - - -int -df_insn_mem_replace (struct df *df, basic_block bb, rtx insn, rtx mem, rtx reg) -{ - replace_args args; - - args.insn = insn; - args.match = mem; - args.replacement = reg; - args.modified = 0; - - /* Search and replace all matching mems within insn. */ - for_each_rtx (&insn, df_rtx_mem_replace, &args); - - if (args.modified) - df_insn_modify (df, bb, insn); - - /* ???? FIXME. We may have a new def or one or more new uses of REG - in INSN. REG should be a new pseudo so it won't affect the - dataflow information that we currently have. We should add - the new uses and defs to INSN and then recreate the chains - when df_analyse is called. */ - return args.modified; -} - - -/* Replace one register with another. Called through for_each_rtx; PX - points to the rtx being scanned. DATA is actually a pointer to a - structure of arguments. */ -static int -df_rtx_reg_replace (rtx *px, void *data) -{ - rtx x = *px; - replace_args *args = (replace_args *) data; - - if (x == NULL_RTX) - return 0; - - if (x == args->match) - { - validate_change (args->insn, px, args->replacement, 1); - args->modified++; - } - - return 0; -} - - -/* Replace the reg within every ref on CHAIN that is within the set - BLOCKS of basic blocks with NEWREG. Also update the regs within - REG_NOTES. */ -void -df_refs_reg_replace (struct df *df, bitmap blocks, struct df_link *chain, rtx oldreg, rtx newreg) -{ - struct df_link *link; - replace_args args; - - if (! blocks) - blocks = df->all_blocks; - - args.match = oldreg; - args.replacement = newreg; - args.modified = 0; - - for (link = chain; link; link = link->next) - { - struct ref *ref = link->ref; - rtx insn = DF_REF_INSN (ref); - - if (! INSN_P (insn)) - continue; - - if (bitmap_bit_p (blocks, DF_REF_BBNO (ref))) - { - df_ref_reg_replace (df, ref, oldreg, newreg); - - /* Replace occurrences of the reg within the REG_NOTES. */ - if ((! link->next || DF_REF_INSN (ref) - != DF_REF_INSN (link->next->ref)) - && REG_NOTES (insn)) - { - args.insn = insn; - for_each_rtx (®_NOTES (insn), df_rtx_reg_replace, &args); - } - } - else - { - /* Temporary check to ensure that we have a grip on which - regs should be replaced. */ - abort (); - } - } -} - - -/* Replace all occurrences of register OLDREG with register NEWREG in - blocks defined by bitmap BLOCKS. This also replaces occurrences of - OLDREG in the REG_NOTES but only for insns containing OLDREG. This - routine expects the reg-use and reg-def chains to be valid. */ -int -df_reg_replace (struct df *df, bitmap blocks, rtx oldreg, rtx newreg) -{ - unsigned int oldregno = REGNO (oldreg); - - df_refs_reg_replace (df, blocks, df->regs[oldregno].defs, oldreg, newreg); - df_refs_reg_replace (df, blocks, df->regs[oldregno].uses, oldreg, newreg); - return 1; -} - - -/* Try replacing the reg within REF with NEWREG. Do not modify - def-use/use-def chains. */ -int -df_ref_reg_replace (struct df *df, struct ref *ref, rtx oldreg, rtx newreg) -{ - /* Check that insn was deleted by being converted into a NOTE. If - so ignore this insn. */ - if (! INSN_P (DF_REF_INSN (ref))) - return 0; - - if (oldreg && oldreg != DF_REF_REG (ref)) - abort (); - - if (! validate_change (DF_REF_INSN (ref), DF_REF_LOC (ref), newreg, 1)) - return 0; - - df_insn_modify (df, DF_REF_BB (ref), DF_REF_INSN (ref)); - return 1; -} - - -struct ref* -df_bb_def_use_swap (struct df *df, basic_block bb, rtx def_insn, rtx use_insn, unsigned int regno) -{ - struct ref *def; - struct ref *use; - int def_uid; - int use_uid; - struct df_link *link; - - def = df_bb_insn_regno_first_def_find (df, bb, def_insn, regno); - if (! def) - return 0; - - use = df_bb_insn_regno_last_use_find (df, bb, use_insn, regno); - if (! use) - return 0; - - /* The USE no longer exists. */ - use_uid = INSN_UID (use_insn); - df_use_unlink (df, use); - df_ref_unlink (&df->insns[use_uid].uses, use); - - /* The DEF requires shifting so remove it from DEF_INSN - and add it to USE_INSN by reusing LINK. */ - def_uid = INSN_UID (def_insn); - link = df_ref_unlink (&df->insns[def_uid].defs, def); - link->ref = def; - link->next = df->insns[use_uid].defs; - df->insns[use_uid].defs = link; - -#if 0 - link = df_ref_unlink (&df->regs[regno].defs, def); - link->ref = def; - link->next = df->regs[regno].defs; - df->insns[regno].defs = link; -#endif - - DF_REF_INSN (def) = use_insn; - return def; -} - - -/* Record df between FIRST_INSN and LAST_INSN inclusive. All new - insns must be processed by this routine. */ -static void -df_insns_modify (struct df *df, basic_block bb, rtx first_insn, rtx last_insn) -{ - rtx insn; - - for (insn = first_insn; ; insn = NEXT_INSN (insn)) - { - unsigned int uid; - - /* A non-const call should not have slipped through the net. If - it does, we need to create a new basic block. Ouch. The - same applies for a label. */ - if ((GET_CODE (insn) == CALL_INSN - && ! CONST_OR_PURE_CALL_P (insn)) - || GET_CODE (insn) == CODE_LABEL) - abort (); - - uid = INSN_UID (insn); - - if (uid >= df->insn_size) - df_insn_table_realloc (df, uid); - - df_insn_modify (df, bb, insn); - - if (insn == last_insn) - break; - } -} - - -/* Emit PATTERN before INSN within BB. */ -rtx -df_pattern_emit_before (struct df *df, rtx pattern, basic_block bb, rtx insn) -{ - rtx ret_insn; - rtx prev_insn = PREV_INSN (insn); - - /* We should not be inserting before the start of the block. */ - if (insn == BB_HEAD (bb)) - abort (); - ret_insn = emit_insn_before (pattern, insn); - if (ret_insn == insn) - return ret_insn; - - df_insns_modify (df, bb, NEXT_INSN (prev_insn), ret_insn); - return ret_insn; -} - - -/* Emit PATTERN after INSN within BB. */ -rtx -df_pattern_emit_after (struct df *df, rtx pattern, basic_block bb, rtx insn) -{ - rtx ret_insn; - - ret_insn = emit_insn_after (pattern, insn); - if (ret_insn == insn) - return ret_insn; - - df_insns_modify (df, bb, NEXT_INSN (insn), ret_insn); - return ret_insn; -} - - -/* Emit jump PATTERN after INSN within BB. */ -rtx -df_jump_pattern_emit_after (struct df *df, rtx pattern, basic_block bb, rtx insn) -{ - rtx ret_insn; - - ret_insn = emit_jump_insn_after (pattern, insn); - if (ret_insn == insn) - return ret_insn; - - df_insns_modify (df, bb, NEXT_INSN (insn), ret_insn); - return ret_insn; -} - - -/* Move INSN within BB before BEFORE_INSN within BEFORE_BB. - - This function should only be used to move loop invariant insns - out of a loop where it has been proven that the def-use info - will still be valid. */ -rtx -df_insn_move_before (struct df *df, basic_block bb, rtx insn, basic_block before_bb, rtx before_insn) -{ - struct df_link *link; - unsigned int uid; - - if (! bb) - return df_pattern_emit_before (df, insn, before_bb, before_insn); - - uid = INSN_UID (insn); - - /* Change bb for all df defined and used by this insn. */ - for (link = df->insns[uid].defs; link; link = link->next) - DF_REF_BB (link->ref) = before_bb; - for (link = df->insns[uid].uses; link; link = link->next) - DF_REF_BB (link->ref) = before_bb; - - /* The lifetimes of the registers used in this insn will be reduced - while the lifetimes of the registers defined in this insn - are likely to be increased. */ - - /* ???? Perhaps all the insns moved should be stored on a list - which df_analyse removes when it recalculates data flow. */ - - return emit_insn_before (insn, before_insn); -} - -/* Functions to query dataflow information. */ - - -int -df_insn_regno_def_p (struct df *df, basic_block bb ATTRIBUTE_UNUSED, - rtx insn, unsigned int regno) -{ - unsigned int uid; - struct df_link *link; - - uid = INSN_UID (insn); - - for (link = df->insns[uid].defs; link; link = link->next) - { - struct ref *def = link->ref; - - if (DF_REF_REGNO (def) == regno) - return 1; - } - - return 0; -} - - -static int -df_def_dominates_all_uses_p (struct df *df ATTRIBUTE_UNUSED, struct ref *def) -{ - struct df_link *du_link; - - /* Follow def-use chain to find all the uses of this def. */ - for (du_link = DF_REF_CHAIN (def); du_link; du_link = du_link->next) - { - struct ref *use = du_link->ref; - struct df_link *ud_link; - - /* Follow use-def chain to check all the defs for this use. */ - for (ud_link = DF_REF_CHAIN (use); ud_link; ud_link = ud_link->next) - if (ud_link->ref != def) - return 0; - } - return 1; -} - - -int -df_insn_dominates_all_uses_p (struct df *df, basic_block bb ATTRIBUTE_UNUSED, - rtx insn) -{ - unsigned int uid; - struct df_link *link; - - uid = INSN_UID (insn); - - for (link = df->insns[uid].defs; link; link = link->next) - { - struct ref *def = link->ref; - - if (! df_def_dominates_all_uses_p (df, def)) - return 0; - } - - return 1; -} - - -/* Return nonzero if all DF dominates all the uses within the bitmap - BLOCKS. */ -static int -df_def_dominates_uses_p (struct df *df ATTRIBUTE_UNUSED, struct ref *def, - bitmap blocks) -{ - struct df_link *du_link; - - /* Follow def-use chain to find all the uses of this def. */ - for (du_link = DF_REF_CHAIN (def); du_link; du_link = du_link->next) - { - struct ref *use = du_link->ref; - struct df_link *ud_link; - - /* Only worry about the uses within BLOCKS. For example, - consider a register defined within a loop that is live at the - loop exits. */ - if (bitmap_bit_p (blocks, DF_REF_BBNO (use))) - { - /* Follow use-def chain to check all the defs for this use. */ - for (ud_link = DF_REF_CHAIN (use); ud_link; ud_link = ud_link->next) - if (ud_link->ref != def) - return 0; - } - } - return 1; -} - - -/* Return nonzero if all the defs of INSN within BB dominates - all the corresponding uses. */ -int -df_insn_dominates_uses_p (struct df *df, basic_block bb ATTRIBUTE_UNUSED, - rtx insn, bitmap blocks) -{ - unsigned int uid; - struct df_link *link; - - uid = INSN_UID (insn); - - for (link = df->insns[uid].defs; link; link = link->next) - { - struct ref *def = link->ref; - - /* Only consider the defs within BLOCKS. */ - if (bitmap_bit_p (blocks, DF_REF_BBNO (def)) - && ! df_def_dominates_uses_p (df, def, blocks)) - return 0; - } - return 1; -} - - -/* Return the basic block that REG referenced in or NULL if referenced - in multiple basic blocks. */ -basic_block -df_regno_bb (struct df *df, unsigned int regno) -{ - struct df_link *defs = df->regs[regno].defs; - struct df_link *uses = df->regs[regno].uses; - struct ref *def = defs ? defs->ref : 0; - struct ref *use = uses ? uses->ref : 0; - basic_block bb_def = def ? DF_REF_BB (def) : 0; - basic_block bb_use = use ? DF_REF_BB (use) : 0; - - /* Compare blocks of first def and last use. ???? FIXME. What if - the reg-def and reg-use lists are not correctly ordered. */ - return bb_def == bb_use ? bb_def : 0; -} - - -/* Return nonzero if REG used in multiple basic blocks. */ -int -df_reg_global_p (struct df *df, rtx reg) -{ - return df_regno_bb (df, REGNO (reg)) != 0; -} - - -/* Return total lifetime (in insns) of REG. */ -int -df_reg_lifetime (struct df *df, rtx reg) -{ - return df->regs[REGNO (reg)].lifetime; -} - - -/* Return nonzero if REG live at start of BB. */ -int -df_bb_reg_live_start_p (struct df *df, basic_block bb, rtx reg) -{ - struct bb_info *bb_info = DF_BB_INFO (df, bb); - -#ifdef ENABLE_CHECKING - if (! bb_info->lr_in) - abort (); -#endif - - return bitmap_bit_p (bb_info->lr_in, REGNO (reg)); -} - - -/* Return nonzero if REG live at end of BB. */ -int -df_bb_reg_live_end_p (struct df *df, basic_block bb, rtx reg) -{ - struct bb_info *bb_info = DF_BB_INFO (df, bb); - -#ifdef ENABLE_CHECKING - if (! bb_info->lr_in) - abort (); -#endif - - return bitmap_bit_p (bb_info->lr_out, REGNO (reg)); -} - - -/* Return -1 if life of REG1 before life of REG2, 1 if life of REG1 - after life of REG2, or 0, if the lives overlap. */ -int -df_bb_regs_lives_compare (struct df *df, basic_block bb, rtx reg1, rtx reg2) -{ - unsigned int regno1 = REGNO (reg1); - unsigned int regno2 = REGNO (reg2); - struct ref *def1; - struct ref *use1; - struct ref *def2; - struct ref *use2; - - - /* The regs must be local to BB. */ - if (df_regno_bb (df, regno1) != bb - || df_regno_bb (df, regno2) != bb) - abort (); - - def2 = df_bb_regno_first_def_find (df, bb, regno2); - use1 = df_bb_regno_last_use_find (df, bb, regno1); - - if (DF_INSN_LUID (df, DF_REF_INSN (def2)) - > DF_INSN_LUID (df, DF_REF_INSN (use1))) - return -1; - - def1 = df_bb_regno_first_def_find (df, bb, regno1); - use2 = df_bb_regno_last_use_find (df, bb, regno2); - - if (DF_INSN_LUID (df, DF_REF_INSN (def1)) - > DF_INSN_LUID (df, DF_REF_INSN (use2))) - return 1; - - return 0; -} - - -/* Return last use of REGNO within BB. */ -static struct ref * -df_bb_regno_last_use_find (struct df *df, basic_block bb, unsigned int regno) -{ - struct df_link *link; - - /* This assumes that the reg-use list is ordered such that for any - BB, the last use is found first. However, since the BBs are not - ordered, the first use in the chain is not necessarily the last - use in the function. */ - for (link = df->regs[regno].uses; link; link = link->next) - { - struct ref *use = link->ref; - - if (DF_REF_BB (use) == bb) - return use; - } - return 0; -} - - -/* Return first def of REGNO within BB. */ -static struct ref * -df_bb_regno_first_def_find (struct df *df, basic_block bb, unsigned int regno) -{ - struct df_link *link; - - /* This assumes that the reg-def list is ordered such that for any - BB, the first def is found first. However, since the BBs are not - ordered, the first def in the chain is not necessarily the first - def in the function. */ - for (link = df->regs[regno].defs; link; link = link->next) - { - struct ref *def = link->ref; - - if (DF_REF_BB (def) == bb) - return def; - } - return 0; -} - - -/* Return first use of REGNO inside INSN within BB. */ -static struct ref * -df_bb_insn_regno_last_use_find (struct df *df, - basic_block bb ATTRIBUTE_UNUSED, rtx insn, - unsigned int regno) -{ - unsigned int uid; - struct df_link *link; - - uid = INSN_UID (insn); - - for (link = df->insns[uid].uses; link; link = link->next) - { - struct ref *use = link->ref; - - if (DF_REF_REGNO (use) == regno) - return use; - } - - return 0; -} - - -/* Return first def of REGNO inside INSN within BB. */ -static struct ref * -df_bb_insn_regno_first_def_find (struct df *df, - basic_block bb ATTRIBUTE_UNUSED, rtx insn, - unsigned int regno) -{ - unsigned int uid; - struct df_link *link; - - uid = INSN_UID (insn); - - for (link = df->insns[uid].defs; link; link = link->next) - { - struct ref *def = link->ref; - - if (DF_REF_REGNO (def) == regno) - return def; - } - - return 0; -} - - -/* Return insn using REG if the BB contains only a single - use and def of REG. */ -rtx -df_bb_single_def_use_insn_find (struct df *df, basic_block bb, rtx insn, rtx reg) -{ - struct ref *def; - struct ref *use; - struct df_link *du_link; - - def = df_bb_insn_regno_first_def_find (df, bb, insn, REGNO (reg)); - - if (! def) - abort (); - - du_link = DF_REF_CHAIN (def); - - if (! du_link) - return NULL_RTX; - - use = du_link->ref; - - /* Check if def is dead. */ - if (! use) - return NULL_RTX; - - /* Check for multiple uses. */ - if (du_link->next) - return NULL_RTX; - - return DF_REF_INSN (use); -} - -/* Functions for debugging/dumping dataflow information. */ - - -/* Dump a def-use or use-def chain for REF to FILE. */ -static void -df_chain_dump (struct df_link *link, FILE *file) -{ - fprintf (file, "{ "); - for (; link; link = link->next) - { - fprintf (file, "%c%d ", - DF_REF_REG_DEF_P (link->ref) ? 'd' : 'u', - DF_REF_ID (link->ref)); - } - fprintf (file, "}"); -} - - -/* Dump a chain of refs with the associated regno. */ -static void -df_chain_dump_regno (struct df_link *link, FILE *file) -{ - fprintf (file, "{ "); - for (; link; link = link->next) - { - fprintf (file, "%c%d(%d) ", - DF_REF_REG_DEF_P (link->ref) ? 'd' : 'u', - DF_REF_ID (link->ref), - DF_REF_REGNO (link->ref)); - } - fprintf (file, "}"); -} - - -/* Dump dataflow info. */ -void -df_dump (struct df *df, int flags, FILE *file) -{ - unsigned int j; - basic_block bb; - - if (! df || ! file) - return; - - fprintf (file, "\nDataflow summary:\n"); - fprintf (file, "n_regs = %d, n_defs = %d, n_uses = %d, n_bbs = %d\n", - df->n_regs, df->n_defs, df->n_uses, df->n_bbs); - - if (flags & DF_RD) - { - basic_block bb; - - fprintf (file, "Reaching defs:\n"); - FOR_EACH_BB (bb) - { - struct bb_info *bb_info = DF_BB_INFO (df, bb); - - if (! bb_info->rd_in) - continue; - - fprintf (file, "bb %d in \t", bb->index); - dump_bitmap (file, bb_info->rd_in); - fprintf (file, "bb %d gen \t", bb->index); - dump_bitmap (file, bb_info->rd_gen); - fprintf (file, "bb %d kill\t", bb->index); - dump_bitmap (file, bb_info->rd_kill); - fprintf (file, "bb %d out \t", bb->index); - dump_bitmap (file, bb_info->rd_out); - } - } - - if (flags & DF_UD_CHAIN) - { - fprintf (file, "Use-def chains:\n"); - for (j = 0; j < df->n_defs; j++) - { - if (df->defs[j]) - { - fprintf (file, "d%d bb %d luid %d insn %d reg %d ", - j, DF_REF_BBNO (df->defs[j]), - DF_INSN_LUID (df, DF_REF_INSN (df->defs[j])), - DF_REF_INSN_UID (df->defs[j]), - DF_REF_REGNO (df->defs[j])); - if (df->defs[j]->flags & DF_REF_READ_WRITE) - fprintf (file, "read/write "); - df_chain_dump (DF_REF_CHAIN (df->defs[j]), file); - fprintf (file, "\n"); - } - } - } - - if (flags & DF_RU) - { - fprintf (file, "Reaching uses:\n"); - FOR_EACH_BB (bb) - { - struct bb_info *bb_info = DF_BB_INFO (df, bb); - - if (! bb_info->ru_in) - continue; - - fprintf (file, "bb %d in \t", bb->index); - dump_bitmap (file, bb_info->ru_in); - fprintf (file, "bb %d gen \t", bb->index); - dump_bitmap (file, bb_info->ru_gen); - fprintf (file, "bb %d kill\t", bb->index); - dump_bitmap (file, bb_info->ru_kill); - fprintf (file, "bb %d out \t", bb->index); - dump_bitmap (file, bb_info->ru_out); - } - } - - if (flags & DF_DU_CHAIN) - { - fprintf (file, "Def-use chains:\n"); - for (j = 0; j < df->n_uses; j++) - { - if (df->uses[j]) - { - fprintf (file, "u%d bb %d luid %d insn %d reg %d ", - j, DF_REF_BBNO (df->uses[j]), - DF_INSN_LUID (df, DF_REF_INSN (df->uses[j])), - DF_REF_INSN_UID (df->uses[j]), - DF_REF_REGNO (df->uses[j])); - if (df->uses[j]->flags & DF_REF_READ_WRITE) - fprintf (file, "read/write "); - df_chain_dump (DF_REF_CHAIN (df->uses[j]), file); - fprintf (file, "\n"); - } - } - } - - if (flags & DF_LR) - { - fprintf (file, "Live regs:\n"); - FOR_EACH_BB (bb) - { - struct bb_info *bb_info = DF_BB_INFO (df, bb); - - if (! bb_info->lr_in) - continue; - - fprintf (file, "bb %d in \t", bb->index); - dump_bitmap (file, bb_info->lr_in); - fprintf (file, "bb %d use \t", bb->index); - dump_bitmap (file, bb_info->lr_use); - fprintf (file, "bb %d def \t", bb->index); - dump_bitmap (file, bb_info->lr_def); - fprintf (file, "bb %d out \t", bb->index); - dump_bitmap (file, bb_info->lr_out); - } - } - - if (flags & (DF_REG_INFO | DF_RD_CHAIN | DF_RU_CHAIN)) - { - struct reg_info *reg_info = df->regs; - - fprintf (file, "Register info:\n"); - for (j = 0; j < df->n_regs; j++) - { - if (((flags & DF_REG_INFO) - && (reg_info[j].n_uses || reg_info[j].n_defs)) - || ((flags & DF_RD_CHAIN) && reg_info[j].defs) - || ((flags & DF_RU_CHAIN) && reg_info[j].uses)) - { - fprintf (file, "reg %d", j); - if ((flags & DF_RD_CHAIN) && (flags & DF_RU_CHAIN)) - { - basic_block bb = df_regno_bb (df, j); - - if (bb) - fprintf (file, " bb %d", bb->index); - else - fprintf (file, " bb ?"); - } - if (flags & DF_REG_INFO) - { - fprintf (file, " life %d", reg_info[j].lifetime); - } - - if ((flags & DF_REG_INFO) || (flags & DF_RD_CHAIN)) - { - fprintf (file, " defs "); - if (flags & DF_REG_INFO) - fprintf (file, "%d ", reg_info[j].n_defs); - if (flags & DF_RD_CHAIN) - df_chain_dump (reg_info[j].defs, file); - } - - if ((flags & DF_REG_INFO) || (flags & DF_RU_CHAIN)) - { - fprintf (file, " uses "); - if (flags & DF_REG_INFO) - fprintf (file, "%d ", reg_info[j].n_uses); - if (flags & DF_RU_CHAIN) - df_chain_dump (reg_info[j].uses, file); - } - - fprintf (file, "\n"); - } - } - } - fprintf (file, "\n"); -} - - -void -df_insn_debug (struct df *df, rtx insn, FILE *file) -{ - unsigned int uid; - int bbi; - - uid = INSN_UID (insn); - if (uid >= df->insn_size) - return; - - if (df->insns[uid].defs) - bbi = DF_REF_BBNO (df->insns[uid].defs->ref); - else if (df->insns[uid].uses) - bbi = DF_REF_BBNO (df->insns[uid].uses->ref); - else - bbi = -1; - - fprintf (file, "insn %d bb %d luid %d defs ", - uid, bbi, DF_INSN_LUID (df, insn)); - df_chain_dump (df->insns[uid].defs, file); - fprintf (file, " uses "); - df_chain_dump (df->insns[uid].uses, file); - fprintf (file, "\n"); -} - - -void -df_insn_debug_regno (struct df *df, rtx insn, FILE *file) -{ - unsigned int uid; - int bbi; - - uid = INSN_UID (insn); - if (uid >= df->insn_size) - return; - - if (df->insns[uid].defs) - bbi = DF_REF_BBNO (df->insns[uid].defs->ref); - else if (df->insns[uid].uses) - bbi = DF_REF_BBNO (df->insns[uid].uses->ref); - else - bbi = -1; - - fprintf (file, "insn %d bb %d luid %d defs ", - uid, bbi, DF_INSN_LUID (df, insn)); - df_chain_dump_regno (df->insns[uid].defs, file); - fprintf (file, " uses "); - df_chain_dump_regno (df->insns[uid].uses, file); - fprintf (file, "\n"); -} - - -static void -df_regno_debug (struct df *df, unsigned int regno, FILE *file) -{ - if (regno >= df->reg_size) - return; - - fprintf (file, "reg %d life %d defs ", - regno, df->regs[regno].lifetime); - df_chain_dump (df->regs[regno].defs, file); - fprintf (file, " uses "); - df_chain_dump (df->regs[regno].uses, file); - fprintf (file, "\n"); -} - - -static void -df_ref_debug (struct df *df, struct ref *ref, FILE *file) -{ - fprintf (file, "%c%d ", - DF_REF_REG_DEF_P (ref) ? 'd' : 'u', - DF_REF_ID (ref)); - fprintf (file, "reg %d bb %d luid %d insn %d chain ", - DF_REF_REGNO (ref), - DF_REF_BBNO (ref), - DF_INSN_LUID (df, DF_REF_INSN (ref)), - INSN_UID (DF_REF_INSN (ref))); - df_chain_dump (DF_REF_CHAIN (ref), file); - fprintf (file, "\n"); -} - -/* Functions for debugging from GDB. */ - -void -debug_df_insn (rtx insn) -{ - df_insn_debug (ddf, insn, stderr); - debug_rtx (insn); -} - - -void -debug_df_reg (rtx reg) -{ - df_regno_debug (ddf, REGNO (reg), stderr); -} - - -void -debug_df_regno (unsigned int regno) -{ - df_regno_debug (ddf, regno, stderr); -} - - -void -debug_df_ref (struct ref *ref) -{ - df_ref_debug (ddf, ref, stderr); -} - - -void -debug_df_defno (unsigned int defno) -{ - df_ref_debug (ddf, ddf->defs[defno], stderr); -} - - -void -debug_df_useno (unsigned int defno) -{ - df_ref_debug (ddf, ddf->uses[defno], stderr); -} - - -void -debug_df_chain (struct df_link *link) -{ - df_chain_dump (link, stderr); - fputc ('\n', stderr); -} - - -/* Hybrid search algorithm from "Implementation Techniques for - Efficient Data-Flow Analysis of Large Programs". */ -static void -hybrid_search_bitmap (basic_block block, bitmap *in, bitmap *out, bitmap *gen, - bitmap *kill, enum df_flow_dir dir, - enum df_confluence_op conf_op, - transfer_function_bitmap transfun, sbitmap visited, - sbitmap pending, void *data) -{ - int changed; - int i = block->index; - edge e; - basic_block bb = block; - - SET_BIT (visited, block->index); - if (TEST_BIT (pending, block->index)) - { - if (dir == DF_FORWARD) - { - /* Calculate <conf_op> of predecessor_outs. */ - bitmap_zero (in[i]); - for (e = bb->pred; e != 0; e = e->pred_next) - { - if (e->src == ENTRY_BLOCK_PTR) - continue; - switch (conf_op) - { - case DF_UNION: - bitmap_a_or_b (in[i], in[i], out[e->src->index]); - break; - case DF_INTERSECTION: - bitmap_a_and_b (in[i], in[i], out[e->src->index]); - break; - } - } - } - else - { - /* Calculate <conf_op> of successor ins. */ - bitmap_zero (out[i]); - for (e = bb->succ; e != 0; e = e->succ_next) - { - if (e->dest == EXIT_BLOCK_PTR) - continue; - switch (conf_op) - { - case DF_UNION: - bitmap_a_or_b (out[i], out[i], in[e->dest->index]); - break; - case DF_INTERSECTION: - bitmap_a_and_b (out[i], out[i], in[e->dest->index]); - break; - } - } - } - /* Common part */ - (*transfun)(i, &changed, in[i], out[i], gen[i], kill[i], data); - RESET_BIT (pending, i); - if (changed) - { - if (dir == DF_FORWARD) - { - for (e = bb->succ; e != 0; e = e->succ_next) - { - if (e->dest == EXIT_BLOCK_PTR || e->dest->index == i) - continue; - SET_BIT (pending, e->dest->index); - } - } - else - { - for (e = bb->pred; e != 0; e = e->pred_next) - { - if (e->src == ENTRY_BLOCK_PTR || e->dest->index == i) - continue; - SET_BIT (pending, e->src->index); - } - } - } - } - if (dir == DF_FORWARD) - { - for (e = bb->succ; e != 0; e = e->succ_next) - { - if (e->dest == EXIT_BLOCK_PTR || e->dest->index == i) - continue; - if (!TEST_BIT (visited, e->dest->index)) - hybrid_search_bitmap (e->dest, in, out, gen, kill, dir, - conf_op, transfun, visited, pending, - data); - } - } - else - { - for (e = bb->pred; e != 0; e = e->pred_next) - { - if (e->src == ENTRY_BLOCK_PTR || e->src->index == i) - continue; - if (!TEST_BIT (visited, e->src->index)) - hybrid_search_bitmap (e->src, in, out, gen, kill, dir, - conf_op, transfun, visited, pending, - data); - } - } -} - - -/* Hybrid search for sbitmaps, rather than bitmaps. */ -static void -hybrid_search_sbitmap (basic_block block, sbitmap *in, sbitmap *out, - sbitmap *gen, sbitmap *kill, enum df_flow_dir dir, - enum df_confluence_op conf_op, - transfer_function_sbitmap transfun, sbitmap visited, - sbitmap pending, void *data) -{ - int changed; - int i = block->index; - edge e; - basic_block bb = block; - - SET_BIT (visited, block->index); - if (TEST_BIT (pending, block->index)) - { - if (dir == DF_FORWARD) - { - /* Calculate <conf_op> of predecessor_outs. */ - sbitmap_zero (in[i]); - for (e = bb->pred; e != 0; e = e->pred_next) - { - if (e->src == ENTRY_BLOCK_PTR) - continue; - switch (conf_op) - { - case DF_UNION: - sbitmap_a_or_b (in[i], in[i], out[e->src->index]); - break; - case DF_INTERSECTION: - sbitmap_a_and_b (in[i], in[i], out[e->src->index]); - break; - } - } - } - else - { - /* Calculate <conf_op> of successor ins. */ - sbitmap_zero (out[i]); - for (e = bb->succ; e != 0; e = e->succ_next) - { - if (e->dest == EXIT_BLOCK_PTR) - continue; - switch (conf_op) - { - case DF_UNION: - sbitmap_a_or_b (out[i], out[i], in[e->dest->index]); - break; - case DF_INTERSECTION: - sbitmap_a_and_b (out[i], out[i], in[e->dest->index]); - break; - } - } - } - /* Common part. */ - (*transfun)(i, &changed, in[i], out[i], gen[i], kill[i], data); - RESET_BIT (pending, i); - if (changed) - { - if (dir == DF_FORWARD) - { - for (e = bb->succ; e != 0; e = e->succ_next) - { - if (e->dest == EXIT_BLOCK_PTR || e->dest->index == i) - continue; - SET_BIT (pending, e->dest->index); - } - } - else - { - for (e = bb->pred; e != 0; e = e->pred_next) - { - if (e->src == ENTRY_BLOCK_PTR || e->dest->index == i) - continue; - SET_BIT (pending, e->src->index); - } - } - } - } - if (dir == DF_FORWARD) - { - for (e = bb->succ; e != 0; e = e->succ_next) - { - if (e->dest == EXIT_BLOCK_PTR || e->dest->index == i) - continue; - if (!TEST_BIT (visited, e->dest->index)) - hybrid_search_sbitmap (e->dest, in, out, gen, kill, dir, - conf_op, transfun, visited, pending, - data); - } - } - else - { - for (e = bb->pred; e != 0; e = e->pred_next) - { - if (e->src == ENTRY_BLOCK_PTR || e->src->index == i) - continue; - if (!TEST_BIT (visited, e->src->index)) - hybrid_search_sbitmap (e->src, in, out, gen, kill, dir, - conf_op, transfun, visited, pending, - data); - } - } -} - - -/* gen = GEN set. - kill = KILL set. - in, out = Filled in by function. - blocks = Blocks to analyze. - dir = Dataflow direction. - conf_op = Confluence operation. - transfun = Transfer function. - order = Order to iterate in. (Should map block numbers -> order) - data = Whatever you want. It's passed to the transfer function. - - This function will perform iterative bitvector dataflow, producing - the in and out sets. Even if you only want to perform it for a - small number of blocks, the vectors for in and out must be large - enough for *all* blocks, because changing one block might affect - others. However, it'll only put what you say to analyze on the - initial worklist. - - For forward problems, you probably want to pass in a mapping of - block number to rc_order (like df->inverse_rc_map). -*/ -void -iterative_dataflow_sbitmap (sbitmap *in, sbitmap *out, sbitmap *gen, - sbitmap *kill, bitmap blocks, - enum df_flow_dir dir, - enum df_confluence_op conf_op, - transfer_function_sbitmap transfun, int *order, - void *data) -{ - int i; - fibheap_t worklist; - basic_block bb; - sbitmap visited, pending; - - pending = sbitmap_alloc (last_basic_block); - visited = sbitmap_alloc (last_basic_block); - sbitmap_zero (pending); - sbitmap_zero (visited); - worklist = fibheap_new (); - - EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, - { - fibheap_insert (worklist, order[i], (void *) (size_t) i); - SET_BIT (pending, i); - if (dir == DF_FORWARD) - sbitmap_copy (out[i], gen[i]); - else - sbitmap_copy (in[i], gen[i]); - }); - - while (sbitmap_first_set_bit (pending) != -1) - { - while (!fibheap_empty (worklist)) - { - i = (size_t) fibheap_extract_min (worklist); - bb = BASIC_BLOCK (i); - if (!TEST_BIT (visited, bb->index)) - hybrid_search_sbitmap (bb, in, out, gen, kill, dir, - conf_op, transfun, visited, pending, data); - } - - if (sbitmap_first_set_bit (pending) != -1) - { - EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, - { - fibheap_insert (worklist, order[i], (void *) (size_t) i); - }); - sbitmap_zero (visited); - } - else - { - break; - } - } - - sbitmap_free (pending); - sbitmap_free (visited); - fibheap_delete (worklist); -} - - -/* Exactly the same as iterative_dataflow_sbitmap, except it works on - bitmaps instead. */ -void -iterative_dataflow_bitmap (bitmap *in, bitmap *out, bitmap *gen, bitmap *kill, - bitmap blocks, enum df_flow_dir dir, - enum df_confluence_op conf_op, - transfer_function_bitmap transfun, int *order, - void *data) -{ - int i; - fibheap_t worklist; - basic_block bb; - sbitmap visited, pending; - - pending = sbitmap_alloc (last_basic_block); - visited = sbitmap_alloc (last_basic_block); - sbitmap_zero (pending); - sbitmap_zero (visited); - worklist = fibheap_new (); - - EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, - { - fibheap_insert (worklist, order[i], (void *) (size_t) i); - SET_BIT (pending, i); - if (dir == DF_FORWARD) - bitmap_copy (out[i], gen[i]); - else - bitmap_copy (in[i], gen[i]); - }); - - while (sbitmap_first_set_bit (pending) != -1) - { - while (!fibheap_empty (worklist)) - { - i = (size_t) fibheap_extract_min (worklist); - bb = BASIC_BLOCK (i); - if (!TEST_BIT (visited, bb->index)) - hybrid_search_bitmap (bb, in, out, gen, kill, dir, - conf_op, transfun, visited, pending, data); - } - - if (sbitmap_first_set_bit (pending) != -1) - { - EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, - { - fibheap_insert (worklist, order[i], (void *) (size_t) i); - }); - sbitmap_zero (visited); - } - else - { - break; - } - } - sbitmap_free (pending); - sbitmap_free (visited); - fibheap_delete (worklist); -} |