summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/ssa.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2002-02-01 18:16:02 +0000
committerobrien <obrien@FreeBSD.org>2002-02-01 18:16:02 +0000
commitc9ab9ae440a8066b2c2b85b157b1fdadcf09916a (patch)
tree086d9d6c8fbd4fc8fe4495059332f66bc0f8d12b /contrib/gcc/ssa.c
parent2ecfd8bd04b63f335c1ec6295740a4bfd97a4fa6 (diff)
downloadFreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.zip
FreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.tar.gz
Enlist the FreeBSD-CURRENT users as testers of what is to become Gcc 3.1.0.
These bits are taken from the FSF anoncvs repo on 1-Feb-2002 08:20 PST.
Diffstat (limited to 'contrib/gcc/ssa.c')
-rw-r--r--contrib/gcc/ssa.c2306
1 files changed, 2306 insertions, 0 deletions
diff --git a/contrib/gcc/ssa.c b/contrib/gcc/ssa.c
new file mode 100644
index 0000000..c97b35c
--- /dev/null
+++ b/contrib/gcc/ssa.c
@@ -0,0 +1,2306 @@
+/* Static Single Assignment conversion routines for the GNU compiler.
+ Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 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. */
+
+/* References:
+
+ Building an Optimizing Compiler
+ Robert Morgan
+ Butterworth-Heinemann, 1998
+
+ Static Single Assignment Construction
+ Preston Briggs, Tim Harvey, Taylor Simpson
+ Technical Report, Rice University, 1995
+ ftp://ftp.cs.rice.edu/public/preston/optimizer/SSA.ps.gz. */
+
+#include "config.h"
+#include "system.h"
+
+#include "rtl.h"
+#include "expr.h"
+#include "varray.h"
+#include "partition.h"
+#include "sbitmap.h"
+#include "hashtab.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "flags.h"
+#include "function.h"
+#include "real.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "basic-block.h"
+#include "output.h"
+#include "ssa.h"
+
+/* TODO:
+
+ Handle subregs better, maybe. For now, if a reg that's set in a
+ subreg expression is duplicated going into SSA form, an extra copy
+ is inserted first that copies the entire reg into the duplicate, so
+ that the other bits are preserved. This isn't strictly SSA, since
+ at least part of the reg is assigned in more than one place (though
+ they are adjacent).
+
+ ??? What to do about strict_low_part. Probably I'll have to split
+ them out of their current instructions first thing.
+
+ Actually the best solution may be to have a kind of "mid-level rtl"
+ in which the RTL encodes exactly what we want, without exposing a
+ lot of niggling processor details. At some later point we lower
+ the representation, calling back into optabs to finish any necessary
+ expansion. */
+
+/* All pseudo-registers and select hard registers are converted to SSA
+ form. When converting out of SSA, these select hard registers are
+ guaranteed to be mapped to their original register number. Each
+ machine's .h file should define CONVERT_HARD_REGISTER_TO_SSA_P
+ indicating which hard registers should be converted.
+
+ When converting out of SSA, temporaries for all registers are
+ partitioned. The partition is checked to ensure that all uses of
+ the same hard register in the same machine mode are in the same
+ class. */
+
+/* If conservative_reg_partition is non-zero, use a conservative
+ register partitioning algorithm (which leaves more regs after
+ emerging from SSA) instead of the coalescing one. This is being
+ left in for a limited time only, as a debugging tool until the
+ coalescing algorithm is validated. */
+
+static int conservative_reg_partition;
+
+/* This flag is set when the CFG is in SSA form. */
+int in_ssa_form = 0;
+
+/* Element I is the single instruction that sets register I. */
+varray_type ssa_definition;
+
+/* Element I-PSEUDO is the normal register that originated the ssa
+ register in question. */
+varray_type ssa_rename_from;
+
+/* Element I is the normal register that originated the ssa
+ register in question.
+
+ A hash table stores the (register, rtl) pairs. These are each
+ xmalloc'ed and deleted when the hash table is destroyed. */
+htab_t ssa_rename_from_ht;
+
+/* The running target ssa register for a given pseudo register.
+ (Pseudo registers appear in only one mode.) */
+static rtx *ssa_rename_to_pseudo;
+/* Similar, but for hard registers. A hard register can appear in
+ many modes, so we store an equivalent pseudo for each of the
+ modes. */
+static rtx ssa_rename_to_hard[FIRST_PSEUDO_REGISTER][NUM_MACHINE_MODES];
+
+/* ssa_rename_from maps pseudo registers to the original corresponding
+ RTL. It is implemented as using a hash table. */
+
+typedef struct {
+ unsigned int reg;
+ rtx original;
+} ssa_rename_from_pair;
+
+struct ssa_rename_from_hash_table_data {
+ sbitmap canonical_elements;
+ partition reg_partition;
+};
+
+static void ssa_rename_from_initialize
+ PARAMS ((void));
+static rtx ssa_rename_from_lookup
+ PARAMS ((int reg));
+static unsigned int original_register
+ PARAMS ((unsigned int regno));
+static void ssa_rename_from_insert
+ PARAMS ((unsigned int reg, rtx r));
+static void ssa_rename_from_free
+ PARAMS ((void));
+typedef int (*srf_trav) PARAMS ((int regno, rtx r, sbitmap canonical_elements, partition reg_partition));
+static void ssa_rename_from_traverse
+ PARAMS ((htab_trav callback_function, sbitmap canonical_elements, partition reg_partition));
+/*static Avoid warnign message. */ void ssa_rename_from_print
+ PARAMS ((void));
+static int ssa_rename_from_print_1
+ PARAMS ((void **slot, void *data));
+static hashval_t ssa_rename_from_hash_function
+ PARAMS ((const void * srfp));
+static int ssa_rename_from_equal
+ PARAMS ((const void *srfp1, const void *srfp2));
+static void ssa_rename_from_delete
+ PARAMS ((void *srfp));
+
+static rtx ssa_rename_to_lookup
+ PARAMS ((rtx reg));
+static void ssa_rename_to_insert
+ PARAMS ((rtx reg, rtx r));
+
+/* The number of registers that were live on entry to the SSA routines. */
+static unsigned int ssa_max_reg_num;
+
+/* Local function prototypes. */
+
+struct rename_context;
+
+static inline rtx * phi_alternative
+ PARAMS ((rtx, int));
+static void compute_dominance_frontiers_1
+ PARAMS ((sbitmap *frontiers, int *idom, int bb, sbitmap done));
+static void find_evaluations_1
+ PARAMS ((rtx dest, rtx set, void *data));
+static void find_evaluations
+ PARAMS ((sbitmap *evals, int nregs));
+static void compute_iterated_dominance_frontiers
+ PARAMS ((sbitmap *idfs, sbitmap *frontiers, sbitmap *evals, int nregs));
+static void insert_phi_node
+ PARAMS ((int regno, int b));
+static void insert_phi_nodes
+ PARAMS ((sbitmap *idfs, sbitmap *evals, int nregs));
+static void create_delayed_rename
+ PARAMS ((struct rename_context *, rtx *));
+static void apply_delayed_renames
+ PARAMS ((struct rename_context *));
+static int rename_insn_1
+ PARAMS ((rtx *ptr, void *data));
+static void rename_block
+ PARAMS ((int b, int *idom));
+static void rename_registers
+ PARAMS ((int nregs, int *idom));
+
+static inline int ephi_add_node
+ PARAMS ((rtx reg, rtx *nodes, int *n_nodes));
+static int * ephi_forward
+ PARAMS ((int t, sbitmap visited, sbitmap *succ, int *tstack));
+static void ephi_backward
+ PARAMS ((int t, sbitmap visited, sbitmap *pred, rtx *nodes));
+static void ephi_create
+ PARAMS ((int t, sbitmap visited, sbitmap *pred, sbitmap *succ, rtx *nodes));
+static void eliminate_phi
+ PARAMS ((edge e, partition reg_partition));
+static int make_regs_equivalent_over_bad_edges
+ PARAMS ((int bb, partition reg_partition));
+
+/* These are used only in the conservative register partitioning
+ algorithms. */
+static int make_equivalent_phi_alternatives_equivalent
+ PARAMS ((int bb, partition reg_partition));
+static partition compute_conservative_reg_partition
+ PARAMS ((void));
+static int record_canonical_element_1
+ PARAMS ((void **srfp, void *data));
+static int check_hard_regs_in_partition
+ PARAMS ((partition reg_partition));
+static int rename_equivalent_regs_in_insn
+ PARAMS ((rtx *ptr, void *data));
+
+/* These are used in the register coalescing algorithm. */
+static int coalesce_if_unconflicting
+ PARAMS ((partition p, conflict_graph conflicts, int reg1, int reg2));
+static int coalesce_regs_in_copies
+ PARAMS ((basic_block bb, partition p, conflict_graph conflicts));
+static int coalesce_reg_in_phi
+ PARAMS ((rtx, int dest_regno, int src_regno, void *data));
+static int coalesce_regs_in_successor_phi_nodes
+ PARAMS ((basic_block bb, partition p, conflict_graph conflicts));
+static partition compute_coalesced_reg_partition
+ PARAMS ((void));
+static int mark_reg_in_phi
+ PARAMS ((rtx *ptr, void *data));
+static void mark_phi_and_copy_regs
+ PARAMS ((regset phi_set));
+
+static int rename_equivalent_regs_in_insn
+ PARAMS ((rtx *ptr, void *data));
+static void rename_equivalent_regs
+ PARAMS ((partition reg_partition));
+
+/* Deal with hard registers. */
+static int conflicting_hard_regs_p
+ PARAMS ((int reg1, int reg2));
+
+/* ssa_rename_to maps registers and machine modes to SSA pseudo registers. */
+
+/* Find the register associated with REG in the indicated mode. */
+
+static rtx
+ssa_rename_to_lookup (reg)
+ rtx reg;
+{
+ if (!HARD_REGISTER_P (reg))
+ return ssa_rename_to_pseudo[REGNO (reg) - FIRST_PSEUDO_REGISTER];
+ else
+ return ssa_rename_to_hard[REGNO (reg)][GET_MODE (reg)];
+}
+
+/* Store a new value mapping REG to R in ssa_rename_to. */
+
+static void
+ssa_rename_to_insert(reg, r)
+ rtx reg;
+ rtx r;
+{
+ if (!HARD_REGISTER_P (reg))
+ ssa_rename_to_pseudo[REGNO (reg) - FIRST_PSEUDO_REGISTER] = r;
+ else
+ ssa_rename_to_hard[REGNO (reg)][GET_MODE (reg)] = r;
+}
+
+/* Prepare ssa_rename_from for use. */
+
+static void
+ssa_rename_from_initialize ()
+{
+ /* We use an arbitrary initial hash table size of 64. */
+ ssa_rename_from_ht = htab_create (64,
+ &ssa_rename_from_hash_function,
+ &ssa_rename_from_equal,
+ &ssa_rename_from_delete);
+}
+
+/* Find the REG entry in ssa_rename_from. Return NULL_RTX if no entry is
+ found. */
+
+static rtx
+ssa_rename_from_lookup (reg)
+ int reg;
+{
+ ssa_rename_from_pair srfp;
+ ssa_rename_from_pair *answer;
+ srfp.reg = reg;
+ srfp.original = NULL_RTX;
+ answer = (ssa_rename_from_pair *)
+ htab_find_with_hash (ssa_rename_from_ht, (void *) &srfp, reg);
+ return (answer == 0 ? NULL_RTX : answer->original);
+}
+
+/* Find the number of the original register specified by REGNO. If
+ the register is a pseudo, return the original register's number.
+ Otherwise, return this register number REGNO. */
+
+static unsigned int
+original_register (regno)
+ unsigned int regno;
+{
+ rtx original_rtx = ssa_rename_from_lookup (regno);
+ return original_rtx != NULL_RTX ? REGNO (original_rtx) : regno;
+}
+
+/* Add mapping from R to REG to ssa_rename_from even if already present. */
+
+static void
+ssa_rename_from_insert (reg, r)
+ unsigned int reg;
+ rtx r;
+{
+ void **slot;
+ ssa_rename_from_pair *srfp = xmalloc (sizeof (ssa_rename_from_pair));
+ srfp->reg = reg;
+ srfp->original = r;
+ slot = htab_find_slot_with_hash (ssa_rename_from_ht, (const void *) srfp,
+ reg, INSERT);
+ if (*slot != 0)
+ free ((void *) *slot);
+ *slot = srfp;
+}
+
+/* Apply the CALLBACK_FUNCTION to each element in ssa_rename_from.
+ CANONICAL_ELEMENTS and REG_PARTITION pass data needed by the only
+ current use of this function. */
+
+static void
+ssa_rename_from_traverse (callback_function,
+ canonical_elements, reg_partition)
+ htab_trav callback_function;
+ sbitmap canonical_elements;
+ partition reg_partition;
+{
+ struct ssa_rename_from_hash_table_data srfhd;
+ srfhd.canonical_elements = canonical_elements;
+ srfhd.reg_partition = reg_partition;
+ htab_traverse (ssa_rename_from_ht, callback_function, (void *) &srfhd);
+}
+
+/* Destroy ssa_rename_from. */
+
+static void
+ssa_rename_from_free ()
+{
+ htab_delete (ssa_rename_from_ht);
+}
+
+/* Print the contents of ssa_rename_from. */
+
+/* static Avoid erroneous error message. */
+void
+ssa_rename_from_print ()
+{
+ printf ("ssa_rename_from's hash table contents:\n");
+ htab_traverse (ssa_rename_from_ht, &ssa_rename_from_print_1, NULL);
+}
+
+/* Print the contents of the hash table entry SLOT, passing the unused
+ sttribute DATA. Used as a callback function with htab_traverse (). */
+
+static int
+ssa_rename_from_print_1 (slot, data)
+ void **slot;
+ void *data ATTRIBUTE_UNUSED;
+{
+ ssa_rename_from_pair * p = *slot;
+ printf ("ssa_rename_from maps pseudo %i to original %i.\n",
+ p->reg, REGNO (p->original));
+ return 1;
+}
+
+/* Given a hash entry SRFP, yield a hash value. */
+
+static hashval_t
+ssa_rename_from_hash_function (srfp)
+ const void *srfp;
+{
+ return ((const ssa_rename_from_pair *) srfp)->reg;
+}
+
+/* Test whether two hash table entries SRFP1 and SRFP2 are equal. */
+
+static int
+ssa_rename_from_equal (srfp1, srfp2)
+ const void *srfp1;
+ const void *srfp2;
+{
+ return ssa_rename_from_hash_function (srfp1) ==
+ ssa_rename_from_hash_function (srfp2);
+}
+
+/* Delete the hash table entry SRFP. */
+
+static void
+ssa_rename_from_delete (srfp)
+ void *srfp;
+{
+ free (srfp);
+}
+
+/* Given the SET of a PHI node, return the address of the alternative
+ for predecessor block C. */
+
+static inline rtx *
+phi_alternative (set, c)
+ rtx set;
+ int c;
+{
+ rtvec phi_vec = XVEC (SET_SRC (set), 0);
+ int v;
+
+ for (v = GET_NUM_ELEM (phi_vec) - 2; v >= 0; v -= 2)
+ if (INTVAL (RTVEC_ELT (phi_vec, v + 1)) == c)
+ return &RTVEC_ELT (phi_vec, v);
+
+ return NULL;
+}
+
+/* Given the SET of a phi node, remove the alternative for predecessor
+ block C. Return non-zero on success, or zero if no alternative is
+ found for C. */
+
+int
+remove_phi_alternative (set, block)
+ rtx set;
+ basic_block block;
+{
+ rtvec phi_vec = XVEC (SET_SRC (set), 0);
+ int num_elem = GET_NUM_ELEM (phi_vec);
+ int v, c;
+
+ c = block->index;
+ for (v = num_elem - 2; v >= 0; v -= 2)
+ if (INTVAL (RTVEC_ELT (phi_vec, v + 1)) == c)
+ {
+ if (v < num_elem - 2)
+ {
+ RTVEC_ELT (phi_vec, v) = RTVEC_ELT (phi_vec, num_elem - 2);
+ RTVEC_ELT (phi_vec, v + 1) = RTVEC_ELT (phi_vec, num_elem - 1);
+ }
+ PUT_NUM_ELEM (phi_vec, num_elem - 2);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* For all registers, find all blocks in which they are set.
+
+ This is the transform of what would be local kill information that
+ we ought to be getting from flow. */
+
+static sbitmap *fe_evals;
+static int fe_current_bb;
+
+static void
+find_evaluations_1 (dest, set, data)
+ rtx dest;
+ rtx set ATTRIBUTE_UNUSED;
+ void *data ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (dest) == REG
+ && CONVERT_REGISTER_TO_SSA_P (REGNO (dest)))
+ SET_BIT (fe_evals[REGNO (dest)], fe_current_bb);
+}
+
+static void
+find_evaluations (evals, nregs)
+ sbitmap *evals;
+ int nregs;
+{
+ int bb;
+
+ sbitmap_vector_zero (evals, nregs);
+ fe_evals = evals;
+
+ for (bb = n_basic_blocks; --bb >= 0; )
+ {
+ rtx p, last;
+
+ fe_current_bb = bb;
+ p = BLOCK_HEAD (bb);
+ last = BLOCK_END (bb);
+ while (1)
+ {
+ if (INSN_P (p))
+ note_stores (PATTERN (p), find_evaluations_1, NULL);
+
+ if (p == last)
+ break;
+ p = NEXT_INSN (p);
+ }
+ }
+}
+
+/* Computing the Dominance Frontier:
+
+ As decribed in Morgan, section 3.5, this may be done simply by
+ walking the dominator tree bottom-up, computing the frontier for
+ the children before the parent. When considering a block B,
+ there are two cases:
+
+ (1) A flow graph edge leaving B that does not lead to a child
+ of B in the dominator tree must be a block that is either equal
+ to B or not dominated by B. Such blocks belong in the frontier
+ of B.
+
+ (2) Consider a block X in the frontier of one of the children C
+ of B. If X is not equal to B and is not dominated by B, it
+ is in the frontier of B.
+*/
+
+static void
+compute_dominance_frontiers_1 (frontiers, idom, bb, done)
+ sbitmap *frontiers;
+ int *idom;
+ int bb;
+ sbitmap done;
+{
+ basic_block b = BASIC_BLOCK (bb);
+ edge e;
+ int c;
+
+ SET_BIT (done, bb);
+ sbitmap_zero (frontiers[bb]);
+
+ /* Do the frontier of the children first. Not all children in the
+ dominator tree (blocks dominated by this one) are children in the
+ CFG, so check all blocks. */
+ for (c = 0; c < n_basic_blocks; ++c)
+ if (idom[c] == bb && ! TEST_BIT (done, c))
+ compute_dominance_frontiers_1 (frontiers, idom, c, done);
+
+ /* Find blocks conforming to rule (1) above. */
+ for (e = b->succ; e; e = e->succ_next)
+ {
+ if (e->dest == EXIT_BLOCK_PTR)
+ continue;
+ if (idom[e->dest->index] != bb)
+ SET_BIT (frontiers[bb], e->dest->index);
+ }
+
+ /* Find blocks conforming to rule (2). */
+ for (c = 0; c < n_basic_blocks; ++c)
+ if (idom[c] == bb)
+ {
+ int x;
+ EXECUTE_IF_SET_IN_SBITMAP (frontiers[c], 0, x,
+ {
+ if (idom[x] != bb)
+ SET_BIT (frontiers[bb], x);
+ });
+ }
+}
+
+void
+compute_dominance_frontiers (frontiers, idom)
+ sbitmap *frontiers;
+ int *idom;
+{
+ sbitmap done = sbitmap_alloc (n_basic_blocks);
+ sbitmap_zero (done);
+
+ compute_dominance_frontiers_1 (frontiers, idom, 0, done);
+
+ sbitmap_free (done);
+}
+
+/* Computing the Iterated Dominance Frontier:
+
+ This is the set of merge points for a given register.
+
+ This is not particularly intuitive. See section 7.1 of Morgan, in
+ particular figures 7.3 and 7.4 and the immediately surrounding text.
+*/
+
+static void
+compute_iterated_dominance_frontiers (idfs, frontiers, evals, nregs)
+ sbitmap *idfs;
+ sbitmap *frontiers;
+ sbitmap *evals;
+ int nregs;
+{
+ sbitmap worklist;
+ int reg, passes = 0;
+
+ worklist = sbitmap_alloc (n_basic_blocks);
+
+ for (reg = 0; reg < nregs; ++reg)
+ {
+ sbitmap idf = idfs[reg];
+ int b, changed;
+
+ /* Start the iterative process by considering those blocks that
+ evaluate REG. We'll add their dominance frontiers to the
+ IDF, and then consider the blocks we just added. */
+ sbitmap_copy (worklist, evals[reg]);
+
+ /* Morgan's algorithm is incorrect here. Blocks that evaluate
+ REG aren't necessarily in REG's IDF. Start with an empty IDF. */
+ sbitmap_zero (idf);
+
+ /* Iterate until the worklist is empty. */
+ do
+ {
+ changed = 0;
+ passes++;
+ EXECUTE_IF_SET_IN_SBITMAP (worklist, 0, b,
+ {
+ RESET_BIT (worklist, b);
+ /* For each block on the worklist, add to the IDF all
+ blocks on its dominance frontier that aren't already
+ on the IDF. Every block that's added is also added
+ to the worklist. */
+ sbitmap_union_of_diff (worklist, worklist, frontiers[b], idf);
+ sbitmap_a_or_b (idf, idf, frontiers[b]);
+ changed = 1;
+ });
+ }
+ while (changed);
+ }
+
+ sbitmap_free (worklist);
+
+ if (rtl_dump_file)
+ {
+ fprintf (rtl_dump_file,
+ "Iterated dominance frontier: %d passes on %d regs.\n",
+ passes, nregs);
+ }
+}
+
+/* Insert the phi nodes. */
+
+static void
+insert_phi_node (regno, bb)
+ int regno, bb;
+{
+ basic_block b = BASIC_BLOCK (bb);
+ edge e;
+ int npred, i;
+ rtvec vec;
+ rtx phi, reg;
+ rtx insn;
+ int end_p;
+
+ /* Find out how many predecessors there are. */
+ for (e = b->pred, npred = 0; e; e = e->pred_next)
+ if (e->src != ENTRY_BLOCK_PTR)
+ npred++;
+
+ /* If this block has no "interesting" preds, then there is nothing to
+ do. Consider a block that only has the entry block as a pred. */
+ if (npred == 0)
+ return;
+
+ /* This is the register to which the phi function will be assigned. */
+ reg = regno_reg_rtx[regno];
+
+ /* Construct the arguments to the PHI node. The use of pc_rtx is just
+ a placeholder; we'll insert the proper value in rename_registers. */
+ vec = rtvec_alloc (npred * 2);
+ for (e = b->pred, i = 0; e ; e = e->pred_next, i += 2)
+ if (e->src != ENTRY_BLOCK_PTR)
+ {
+ RTVEC_ELT (vec, i + 0) = pc_rtx;
+ RTVEC_ELT (vec, i + 1) = GEN_INT (e->src->index);
+ }
+
+ phi = gen_rtx_PHI (VOIDmode, vec);
+ phi = gen_rtx_SET (VOIDmode, reg, phi);
+
+ insn = first_insn_after_basic_block_note (b);
+ end_p = PREV_INSN (insn) == b->end;
+ emit_insn_before (phi, insn);
+ if (end_p)
+ b->end = PREV_INSN (insn);
+}
+
+static void
+insert_phi_nodes (idfs, evals, nregs)
+ sbitmap *idfs;
+ sbitmap *evals ATTRIBUTE_UNUSED;
+ int nregs;
+{
+ int reg;
+
+ for (reg = 0; reg < nregs; ++reg)
+ if (CONVERT_REGISTER_TO_SSA_P (reg))
+ {
+ int b;
+ EXECUTE_IF_SET_IN_SBITMAP (idfs[reg], 0, b,
+ {
+ if (REGNO_REG_SET_P (BASIC_BLOCK (b)->global_live_at_start, reg))
+ insert_phi_node (reg, b);
+ });
+ }
+}
+
+/* Rename the registers to conform to SSA.
+
+ This is essentially the algorithm presented in Figure 7.8 of Morgan,
+ with a few changes to reduce pattern search time in favour of a bit
+ more memory usage. */
+
+/* One of these is created for each set. It will live in a list local
+ to its basic block for the duration of that block's processing. */
+struct rename_set_data
+{
+ struct rename_set_data *next;
+ /* This is the SET_DEST of the (first) SET that sets the REG. */
+ rtx *reg_loc;
+ /* This is what used to be at *REG_LOC. */
+ rtx old_reg;
+ /* This is the REG that will replace OLD_REG. It's set only
+ when the rename data is moved onto the DONE_RENAMES queue. */
+ rtx new_reg;
+ /* This is what to restore ssa_rename_to_lookup (old_reg) to. It is
+ usually the previous contents of ssa_rename_to_lookup (old_reg). */
+ rtx prev_reg;
+ /* This is the insn that contains all the SETs of the REG. */
+ rtx set_insn;
+};
+
+/* This struct is used to pass information to callback functions while
+ renaming registers. */
+struct rename_context
+{
+ struct rename_set_data *new_renames;
+ struct rename_set_data *done_renames;
+ rtx current_insn;
+};
+
+/* Queue the rename of *REG_LOC. */
+static void
+create_delayed_rename (c, reg_loc)
+ struct rename_context *c;
+ rtx *reg_loc;
+{
+ struct rename_set_data *r;
+ r = (struct rename_set_data *) xmalloc (sizeof(*r));
+
+ if (GET_CODE (*reg_loc) != REG
+ || !CONVERT_REGISTER_TO_SSA_P (REGNO (*reg_loc)))
+ abort ();
+
+ r->reg_loc = reg_loc;
+ r->old_reg = *reg_loc;
+ r->prev_reg = ssa_rename_to_lookup(r->old_reg);
+ r->set_insn = c->current_insn;
+ r->next = c->new_renames;
+ c->new_renames = r;
+}
+
+/* This is part of a rather ugly hack to allow the pre-ssa regno to be
+ reused. If, during processing, a register has not yet been touched,
+ ssa_rename_to[regno][machno] will be NULL. Now, in the course of pushing
+ and popping values from ssa_rename_to, when we would ordinarily
+ pop NULL back in, we pop RENAME_NO_RTX. We treat this exactly the
+ same as NULL, except that it signals that the original regno has
+ already been reused. */
+#define RENAME_NO_RTX pc_rtx
+
+/* Move all the entries from NEW_RENAMES onto DONE_RENAMES by
+ applying all the renames on NEW_RENAMES. */
+
+static void
+apply_delayed_renames (c)
+ struct rename_context *c;
+{
+ struct rename_set_data *r;
+ struct rename_set_data *last_r = NULL;
+
+ for (r = c->new_renames; r != NULL; r = r->next)
+ {
+ int new_regno;
+
+ /* Failure here means that someone has a PARALLEL that sets
+ a register twice (bad!). */
+ if (ssa_rename_to_lookup (r->old_reg) != r->prev_reg)
+ abort ();
+ /* Failure here means we have changed REG_LOC before applying
+ the rename. */
+ /* For the first set we come across, reuse the original regno. */
+ if (r->prev_reg == NULL_RTX && !HARD_REGISTER_P (r->old_reg))
+ {
+ r->new_reg = r->old_reg;
+ /* We want to restore RENAME_NO_RTX rather than NULL_RTX. */
+ r->prev_reg = RENAME_NO_RTX;
+ }
+ else
+ r->new_reg = gen_reg_rtx (GET_MODE (r->old_reg));
+ new_regno = REGNO (r->new_reg);
+ ssa_rename_to_insert (r->old_reg, r->new_reg);
+
+ if (new_regno >= (int) ssa_definition->num_elements)
+ {
+ int new_limit = new_regno * 5 / 4;
+ VARRAY_GROW (ssa_definition, new_limit);
+ }
+
+ VARRAY_RTX (ssa_definition, new_regno) = r->set_insn;
+ ssa_rename_from_insert (new_regno, r->old_reg);
+ last_r = r;
+ }
+ if (last_r != NULL)
+ {
+ last_r->next = c->done_renames;
+ c->done_renames = c->new_renames;
+ c->new_renames = NULL;
+ }
+}
+
+/* Part one of the first step of rename_block, called through for_each_rtx.
+ Mark pseudos that are set for later update. Transform uses of pseudos. */
+
+static int
+rename_insn_1 (ptr, data)
+ rtx *ptr;
+ void *data;
+{
+ rtx x = *ptr;
+ struct rename_context *context = data;
+
+ if (x == NULL_RTX)
+ return 0;
+
+ switch (GET_CODE (x))
+ {
+ case SET:
+ {
+ rtx *destp = &SET_DEST (x);
+ rtx dest = SET_DEST (x);
+
+ /* An assignment to a paradoxical SUBREG does not read from
+ the destination operand, and thus does not need to be
+ wrapped into a SEQUENCE when translating into SSA form.
+ We merely strip off the SUBREG and proceed normally for
+ this case. */
+ if (GET_CODE (dest) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (dest))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
+ && GET_CODE (SUBREG_REG (dest)) == REG
+ && CONVERT_REGISTER_TO_SSA_P (REGNO (SUBREG_REG (dest))))
+ {
+ destp = &XEXP (dest, 0);
+ dest = XEXP (dest, 0);
+ }
+
+ /* Some SETs also use the REG specified in their LHS.
+ These can be detected by the presence of
+ STRICT_LOW_PART, SUBREG, SIGN_EXTRACT, and ZERO_EXTRACT
+ in the LHS. Handle these by changing
+ (set (subreg (reg foo)) ...)
+ into
+ (sequence [(set (reg foo_1) (reg foo))
+ (set (subreg (reg foo_1)) ...)])
+
+ FIXME: Much of the time this is too much. For some constructs
+ we know that the output register is strictly an output
+ (paradoxical SUBREGs and some libcalls for example).
+
+ For those cases we are better off not making the false
+ dependency. */
+ if (GET_CODE (dest) == STRICT_LOW_PART
+ || GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == SIGN_EXTRACT
+ || GET_CODE (dest) == ZERO_EXTRACT)
+ {
+ rtx i, reg;
+ reg = dest;
+
+ while (GET_CODE (reg) == STRICT_LOW_PART
+ || GET_CODE (reg) == SUBREG
+ || GET_CODE (reg) == SIGN_EXTRACT
+ || GET_CODE (reg) == ZERO_EXTRACT)
+ reg = XEXP (reg, 0);
+
+ if (GET_CODE (reg) == REG
+ && CONVERT_REGISTER_TO_SSA_P (REGNO (reg)))
+ {
+ /* Generate (set reg reg), and do renaming on it so
+ that it becomes (set reg_1 reg_0), and we will
+ replace reg with reg_1 in the SUBREG. */
+
+ struct rename_set_data *saved_new_renames;
+ saved_new_renames = context->new_renames;
+ context->new_renames = NULL;
+ i = emit_insn (gen_rtx_SET (VOIDmode, reg, reg));
+ for_each_rtx (&i, rename_insn_1, data);
+ apply_delayed_renames (context);
+ context->new_renames = saved_new_renames;
+ }
+ }
+ else if (GET_CODE (dest) == REG
+ && CONVERT_REGISTER_TO_SSA_P (REGNO (dest)))
+ {
+ /* We found a genuine set of an interesting register. Tag
+ it so that we can create a new name for it after we finish
+ processing this insn. */
+
+ create_delayed_rename (context, destp);
+
+ /* Since we do not wish to (directly) traverse the
+ SET_DEST, recurse through for_each_rtx for the SET_SRC
+ and return. */
+ if (GET_CODE (x) == SET)
+ for_each_rtx (&SET_SRC (x), rename_insn_1, data);
+ return -1;
+ }
+
+ /* Otherwise, this was not an interesting destination. Continue
+ on, marking uses as normal. */
+ return 0;
+ }
+
+ case REG:
+ if (CONVERT_REGISTER_TO_SSA_P (REGNO (x)) &&
+ REGNO (x) < ssa_max_reg_num)
+ {
+ rtx new_reg = ssa_rename_to_lookup (x);
+
+ if (new_reg != NULL_RTX && new_reg != RENAME_NO_RTX)
+ {
+ if (GET_MODE (x) != GET_MODE (new_reg))
+ abort ();
+ *ptr = new_reg;
+ }
+ /* Else this is a use before a set. Warn? */
+ }
+ return -1;
+
+ case CLOBBER:
+ /* There is considerable debate on how CLOBBERs ought to be
+ handled in SSA. For now, we're keeping the CLOBBERs, which
+ means that we don't really have SSA form. There are a couple
+ of proposals for how to fix this problem, but neither is
+ implemented yet. */
+ {
+ rtx dest = XCEXP (x, 0, CLOBBER);
+ if (REG_P (dest))
+ {
+ if (CONVERT_REGISTER_TO_SSA_P (REGNO (dest))
+ && REGNO (dest) < ssa_max_reg_num)
+ {
+ rtx new_reg = ssa_rename_to_lookup (dest);
+ if (new_reg != NULL_RTX && new_reg != RENAME_NO_RTX)
+ XCEXP (x, 0, CLOBBER) = new_reg;
+ }
+ /* Stop traversing. */
+ return -1;
+ }
+ else
+ /* Continue traversing. */
+ return 0;
+ }
+
+ case PHI:
+ /* Never muck with the phi. We do that elsewhere, special-like. */
+ return -1;
+
+ default:
+ /* Anything else, continue traversing. */
+ return 0;
+ }
+}
+
+static void
+rename_block (bb, idom)
+ int bb;
+ int *idom;
+{
+ basic_block b = BASIC_BLOCK (bb);
+ edge e;
+ rtx insn, next, last;
+ struct rename_set_data *set_data = NULL;
+ int c;
+
+ /* Step One: Walk the basic block, adding new names for sets and
+ replacing uses. */
+
+ next = b->head;
+ last = b->end;
+ do
+ {
+ insn = next;
+ if (INSN_P (insn))
+ {
+ struct rename_context context;
+ context.done_renames = set_data;
+ context.new_renames = NULL;
+ context.current_insn = insn;
+
+ start_sequence ();
+ for_each_rtx (&PATTERN (insn), rename_insn_1, &context);
+ for_each_rtx (&REG_NOTES (insn), rename_insn_1, &context);
+
+ /* Sometimes, we end up with a sequence of insns that
+ SSA needs to treat as a single insn. Wrap these in a
+ SEQUENCE. (Any notes now get attached to the SEQUENCE,
+ not to the old version inner insn.) */
+ if (get_insns () != NULL_RTX)
+ {
+ rtx seq;
+ int i;
+
+ emit (PATTERN (insn));
+ seq = gen_sequence ();
+ /* We really want a SEQUENCE of SETs, not a SEQUENCE
+ of INSNs. */
+ for (i = 0; i < XVECLEN (seq, 0); i++)
+ XVECEXP (seq, 0, i) = PATTERN (XVECEXP (seq, 0, i));
+ PATTERN (insn) = seq;
+ }
+ end_sequence ();
+
+ apply_delayed_renames (&context);
+ set_data = context.done_renames;
+ }
+
+ next = NEXT_INSN (insn);
+ }
+ while (insn != last);
+
+ /* Step Two: Update the phi nodes of this block's successors. */
+
+ for (e = b->succ; e; e = e->succ_next)
+ {
+ if (e->dest == EXIT_BLOCK_PTR)
+ continue;
+
+ insn = first_insn_after_basic_block_note (e->dest);
+
+ while (PHI_NODE_P (insn))
+ {
+ rtx phi = PATTERN (insn);
+ rtx reg;
+
+ /* Find out which of our outgoing registers this node is
+ intended to replace. Note that if this is not the first PHI
+ node to have been created for this register, we have to
+ jump through rename links to figure out which register
+ we're talking about. This can easily be recognized by
+ noting that the regno is new to this pass. */
+ reg = SET_DEST (phi);
+ if (REGNO (reg) >= ssa_max_reg_num)
+ reg = ssa_rename_from_lookup (REGNO (reg));
+ if (reg == NULL_RTX)
+ abort ();
+ reg = ssa_rename_to_lookup (reg);
+
+ /* It is possible for the variable to be uninitialized on
+ edges in. Reduce the arity of the PHI so that we don't
+ consider those edges. */
+ if (reg == NULL || reg == RENAME_NO_RTX)
+ {
+ if (! remove_phi_alternative (phi, b))
+ abort ();
+ }
+ else
+ {
+ /* When we created the PHI nodes, we did not know what mode
+ the register should be. Now that we've found an original,
+ we can fill that in. */
+ if (GET_MODE (SET_DEST (phi)) == VOIDmode)
+ PUT_MODE (SET_DEST (phi), GET_MODE (reg));
+ else if (GET_MODE (SET_DEST (phi)) != GET_MODE (reg))
+ abort ();
+
+ *phi_alternative (phi, bb) = reg;
+ }
+
+ insn = NEXT_INSN (insn);
+ }
+ }
+
+ /* Step Three: Do the same to the children of this block in
+ dominator order. */
+
+ for (c = 0; c < n_basic_blocks; ++c)
+ if (idom[c] == bb)
+ rename_block (c, idom);
+
+ /* Step Four: Update the sets to refer to their new register,
+ and restore ssa_rename_to to its previous state. */
+
+ while (set_data)
+ {
+ struct rename_set_data *next;
+ rtx old_reg = *set_data->reg_loc;
+
+ if (*set_data->reg_loc != set_data->old_reg)
+ abort ();
+ *set_data->reg_loc = set_data->new_reg;
+
+ ssa_rename_to_insert (old_reg, set_data->prev_reg);
+
+ next = set_data->next;
+ free (set_data);
+ set_data = next;
+ }
+}
+
+static void
+rename_registers (nregs, idom)
+ int nregs;
+ int *idom;
+{
+ VARRAY_RTX_INIT (ssa_definition, nregs * 3, "ssa_definition");
+ ssa_rename_from_initialize ();
+
+ ssa_rename_to_pseudo = (rtx *) alloca (nregs * sizeof(rtx));
+ memset ((char *) ssa_rename_to_pseudo, 0, nregs * sizeof(rtx));
+ memset ((char *) ssa_rename_to_hard, 0,
+ FIRST_PSEUDO_REGISTER * NUM_MACHINE_MODES * sizeof (rtx));
+
+ rename_block (0, idom);
+
+ /* ??? Update basic_block_live_at_start, and other flow info
+ as needed. */
+
+ ssa_rename_to_pseudo = NULL;
+}
+
+/* The main entry point for moving to SSA. */
+
+void
+convert_to_ssa ()
+{
+ /* Element I is the set of blocks that set register I. */
+ sbitmap *evals;
+
+ /* Dominator bitmaps. */
+ sbitmap *dfs;
+ sbitmap *idfs;
+
+ /* Element I is the immediate dominator of block I. */
+ int *idom;
+
+ int nregs;
+
+ /* Don't do it twice. */
+ if (in_ssa_form)
+ abort ();
+
+ /* Need global_live_at_{start,end} up to date. Do not remove any
+ dead code. We'll let the SSA optimizers do that. */
+ life_analysis (get_insns (), NULL, 0);
+
+ idom = (int *) alloca (n_basic_blocks * sizeof (int));
+ memset ((void *) idom, -1, (size_t) n_basic_blocks * sizeof (int));
+ calculate_dominance_info (idom, NULL, CDI_DOMINATORS);
+
+ if (rtl_dump_file)
+ {
+ int i;
+ fputs (";; Immediate Dominators:\n", rtl_dump_file);
+ for (i = 0; i < n_basic_blocks; ++i)
+ fprintf (rtl_dump_file, ";\t%3d = %3d\n", i, idom[i]);
+ fflush (rtl_dump_file);
+ }
+
+ /* Compute dominance frontiers. */
+
+ dfs = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
+ compute_dominance_frontiers (dfs, idom);
+
+ if (rtl_dump_file)
+ {
+ dump_sbitmap_vector (rtl_dump_file, ";; Dominance Frontiers:",
+ "; Basic Block", dfs, n_basic_blocks);
+ fflush (rtl_dump_file);
+ }
+
+ /* Compute register evaluations. */
+
+ ssa_max_reg_num = max_reg_num ();
+ nregs = ssa_max_reg_num;
+ evals = sbitmap_vector_alloc (nregs, n_basic_blocks);
+ find_evaluations (evals, nregs);
+
+ /* Compute the iterated dominance frontier for each register. */
+
+ idfs = sbitmap_vector_alloc (nregs, n_basic_blocks);
+ compute_iterated_dominance_frontiers (idfs, dfs, evals, nregs);
+
+ if (rtl_dump_file)
+ {
+ dump_sbitmap_vector (rtl_dump_file, ";; Iterated Dominance Frontiers:",
+ "; Register", idfs, nregs);
+ fflush (rtl_dump_file);
+ }
+
+ /* Insert the phi nodes. */
+
+ insert_phi_nodes (idfs, evals, nregs);
+
+ /* Rename the registers to satisfy SSA. */
+
+ rename_registers (nregs, idom);
+
+ /* All done! Clean up and go home. */
+
+ sbitmap_vector_free (dfs);
+ sbitmap_vector_free (evals);
+ sbitmap_vector_free (idfs);
+ in_ssa_form = 1;
+
+ reg_scan (get_insns (), max_reg_num (), 1);
+}
+
+/* REG is the representative temporary of its partition. Add it to the
+ set of nodes to be processed, if it hasn't been already. Return the
+ index of this register in the node set. */
+
+static inline int
+ephi_add_node (reg, nodes, n_nodes)
+ rtx reg, *nodes;
+ int *n_nodes;
+{
+ int i;
+ for (i = *n_nodes - 1; i >= 0; --i)
+ if (REGNO (reg) == REGNO (nodes[i]))
+ return i;
+
+ nodes[i = (*n_nodes)++] = reg;
+ return i;
+}
+
+/* Part one of the topological sort. This is a forward (downward) search
+ through the graph collecting a stack of nodes to process. Assuming no
+ cycles, the nodes at top of the stack when we are finished will have
+ no other dependencies. */
+
+static int *
+ephi_forward (t, visited, succ, tstack)
+ int t;
+ sbitmap visited;
+ sbitmap *succ;
+ int *tstack;
+{
+ int s;
+
+ SET_BIT (visited, t);
+
+ EXECUTE_IF_SET_IN_SBITMAP (succ[t], 0, s,
+ {
+ if (! TEST_BIT (visited, s))
+ tstack = ephi_forward (s, visited, succ, tstack);
+ });
+
+ *tstack++ = t;
+ return tstack;
+}
+
+/* Part two of the topological sort. The is a backward search through
+ a cycle in the graph, copying the data forward as we go. */
+
+static void
+ephi_backward (t, visited, pred, nodes)
+ int t;
+ sbitmap visited, *pred;
+ rtx *nodes;
+{
+ int p;
+
+ SET_BIT (visited, t);
+
+ EXECUTE_IF_SET_IN_SBITMAP (pred[t], 0, p,
+ {
+ if (! TEST_BIT (visited, p))
+ {
+ ephi_backward (p, visited, pred, nodes);
+ emit_move_insn (nodes[p], nodes[t]);
+ }
+ });
+}
+
+/* Part two of the topological sort. Create the copy for a register
+ and any cycle of which it is a member. */
+
+static void
+ephi_create (t, visited, pred, succ, nodes)
+ int t;
+ sbitmap visited, *pred, *succ;
+ rtx *nodes;
+{
+ rtx reg_u = NULL_RTX;
+ int unvisited_predecessors = 0;
+ int p;
+
+ /* Iterate through the predecessor list looking for unvisited nodes.
+ If there are any, we have a cycle, and must deal with that. At
+ the same time, look for a visited predecessor. If there is one,
+ we won't need to create a temporary. */
+
+ EXECUTE_IF_SET_IN_SBITMAP (pred[t], 0, p,
+ {
+ if (! TEST_BIT (visited, p))
+ unvisited_predecessors = 1;
+ else if (!reg_u)
+ reg_u = nodes[p];
+ });
+
+ if (unvisited_predecessors)
+ {
+ /* We found a cycle. Copy out one element of the ring (if necessary),
+ then traverse the ring copying as we go. */
+
+ if (!reg_u)
+ {
+ reg_u = gen_reg_rtx (GET_MODE (nodes[t]));
+ emit_move_insn (reg_u, nodes[t]);
+ }
+
+ EXECUTE_IF_SET_IN_SBITMAP (pred[t], 0, p,
+ {
+ if (! TEST_BIT (visited, p))
+ {
+ ephi_backward (p, visited, pred, nodes);
+ emit_move_insn (nodes[p], reg_u);
+ }
+ });
+ }
+ else
+ {
+ /* No cycle. Just copy the value from a successor. */
+
+ int s;
+ EXECUTE_IF_SET_IN_SBITMAP (succ[t], 0, s,
+ {
+ SET_BIT (visited, t);
+ emit_move_insn (nodes[t], nodes[s]);
+ return;
+ });
+ }
+}
+
+/* Convert the edge to normal form. */
+
+static void
+eliminate_phi (e, reg_partition)
+ edge e;
+ partition reg_partition;
+{
+ int n_nodes;
+ sbitmap *pred, *succ;
+ sbitmap visited;
+ rtx *nodes;
+ int *stack, *tstack;
+ rtx insn;
+ int i;
+
+ /* Collect an upper bound on the number of registers needing processing. */
+
+ insn = first_insn_after_basic_block_note (e->dest);
+
+ n_nodes = 0;
+ while (PHI_NODE_P (insn))
+ {
+ insn = next_nonnote_insn (insn);
+ n_nodes += 2;
+ }
+
+ if (n_nodes == 0)
+ return;
+
+ /* Build the auxiliary graph R(B).
+
+ The nodes of the graph are the members of the register partition
+ present in Phi(B). There is an edge from FIND(T0)->FIND(T1) for
+ each T0 = PHI(...,T1,...), where T1 is for the edge from block C. */
+
+ nodes = (rtx *) alloca (n_nodes * sizeof(rtx));
+ pred = sbitmap_vector_alloc (n_nodes, n_nodes);
+ succ = sbitmap_vector_alloc (n_nodes, n_nodes);
+ sbitmap_vector_zero (pred, n_nodes);
+ sbitmap_vector_zero (succ, n_nodes);
+
+ insn = first_insn_after_basic_block_note (e->dest);
+
+ n_nodes = 0;
+ for (; PHI_NODE_P (insn); insn = next_nonnote_insn (insn))
+ {
+ rtx* preg = phi_alternative (PATTERN (insn), e->src->index);
+ rtx tgt = SET_DEST (PATTERN (insn));
+ rtx reg;
+
+ /* There may be no phi alternative corresponding to this edge.
+ This indicates that the phi variable is undefined along this
+ edge. */
+ if (preg == NULL)
+ continue;
+ reg = *preg;
+
+ if (GET_CODE (reg) != REG || GET_CODE (tgt) != REG)
+ abort ();
+
+ reg = regno_reg_rtx[partition_find (reg_partition, REGNO (reg))];
+ tgt = regno_reg_rtx[partition_find (reg_partition, REGNO (tgt))];
+ /* If the two registers are already in the same partition,
+ nothing will need to be done. */
+ if (reg != tgt)
+ {
+ int ireg, itgt;
+
+ ireg = ephi_add_node (reg, nodes, &n_nodes);
+ itgt = ephi_add_node (tgt, nodes, &n_nodes);
+
+ SET_BIT (pred[ireg], itgt);
+ SET_BIT (succ[itgt], ireg);
+ }
+ }
+
+ if (n_nodes == 0)
+ goto out;
+
+ /* Begin a topological sort of the graph. */
+
+ visited = sbitmap_alloc (n_nodes);
+ sbitmap_zero (visited);
+
+ tstack = stack = (int *) alloca (n_nodes * sizeof (int));
+
+ for (i = 0; i < n_nodes; ++i)
+ if (! TEST_BIT (visited, i))
+ tstack = ephi_forward (i, visited, succ, tstack);
+
+ sbitmap_zero (visited);
+
+ /* As we find a solution to the tsort, collect the implementation
+ insns in a sequence. */
+ start_sequence ();
+
+ while (tstack != stack)
+ {
+ i = *--tstack;
+ if (! TEST_BIT (visited, i))
+ ephi_create (i, visited, pred, succ, nodes);
+ }
+
+ insn = gen_sequence ();
+ end_sequence ();
+ insert_insn_on_edge (insn, e);
+ if (rtl_dump_file)
+ fprintf (rtl_dump_file, "Emitting copy on edge (%d,%d)\n",
+ e->src->index, e->dest->index);
+
+ sbitmap_free (visited);
+out:
+ sbitmap_vector_free (pred);
+ sbitmap_vector_free (succ);
+}
+
+/* For basic block B, consider all phi insns which provide an
+ alternative corresponding to an incoming abnormal critical edge.
+ Place the phi alternative corresponding to that abnormal critical
+ edge in the same register class as the destination of the set.
+
+ From Morgan, p. 178:
+
+ For each abnormal critical edge (C, B),
+ if T0 = phi (T1, ..., Ti, ..., Tm) is a phi node in B,
+ and C is the ith predecessor of B,
+ then T0 and Ti must be equivalent.
+
+ Return non-zero iff any such cases were found for which the two
+ regs were not already in the same class. */
+
+static int
+make_regs_equivalent_over_bad_edges (bb, reg_partition)
+ int bb;
+ partition reg_partition;
+{
+ int changed = 0;
+ basic_block b = BASIC_BLOCK (bb);
+ rtx phi;
+
+ /* Advance to the first phi node. */
+ phi = first_insn_after_basic_block_note (b);
+
+ /* Scan all the phi nodes. */
+ for (;
+ PHI_NODE_P (phi);
+ phi = next_nonnote_insn (phi))
+ {
+ edge e;
+ int tgt_regno;
+ rtx set = PATTERN (phi);
+ rtx tgt = SET_DEST (set);
+
+ /* The set target is expected to be an SSA register. */
+ if (GET_CODE (tgt) != REG
+ || !CONVERT_REGISTER_TO_SSA_P (REGNO (tgt)))
+ abort ();
+ tgt_regno = REGNO (tgt);
+
+ /* Scan incoming abnormal critical edges. */
+ for (e = b->pred; e; e = e->pred_next)
+ if ((e->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (e))
+ {
+ rtx *alt = phi_alternative (set, e->src->index);
+ int alt_regno;
+
+ /* If there is no alternative corresponding to this edge,
+ the value is undefined along the edge, so just go on. */
+ if (alt == 0)
+ continue;
+
+ /* The phi alternative is expected to be an SSA register. */
+ if (GET_CODE (*alt) != REG
+ || !CONVERT_REGISTER_TO_SSA_P (REGNO (*alt)))
+ abort ();
+ alt_regno = REGNO (*alt);
+
+ /* If the set destination and the phi alternative aren't
+ already in the same class... */
+ if (partition_find (reg_partition, tgt_regno)
+ != partition_find (reg_partition, alt_regno))
+ {
+ /* ... make them such. */
+ if (conflicting_hard_regs_p (tgt_regno, alt_regno))
+ /* It is illegal to unify a hard register with a
+ different register. */
+ abort ();
+
+ partition_union (reg_partition,
+ tgt_regno, alt_regno);
+ ++changed;
+ }
+ }
+ }
+
+ return changed;
+}
+
+/* Consider phi insns in basic block BB pairwise. If the set target
+ of both isns are equivalent pseudos, make the corresponding phi
+ alternatives in each phi corresponding equivalent.
+
+ Return nonzero if any new register classes were unioned. */
+
+static int
+make_equivalent_phi_alternatives_equivalent (bb, reg_partition)
+ int bb;
+ partition reg_partition;
+{
+ int changed = 0;
+ basic_block b = BASIC_BLOCK (bb);
+ rtx phi;
+
+ /* Advance to the first phi node. */
+ phi = first_insn_after_basic_block_note (b);
+
+ /* Scan all the phi nodes. */
+ for (;
+ PHI_NODE_P (phi);
+ phi = next_nonnote_insn (phi))
+ {
+ rtx set = PATTERN (phi);
+ /* The regno of the destination of the set. */
+ int tgt_regno = REGNO (SET_DEST (PATTERN (phi)));
+
+ rtx phi2 = next_nonnote_insn (phi);
+
+ /* Scan all phi nodes following this one. */
+ for (;
+ PHI_NODE_P (phi2);
+ phi2 = next_nonnote_insn (phi2))
+ {
+ rtx set2 = PATTERN (phi2);
+ /* The regno of the destination of the set. */
+ int tgt2_regno = REGNO (SET_DEST (set2));
+
+ /* Are the set destinations equivalent regs? */
+ if (partition_find (reg_partition, tgt_regno) ==
+ partition_find (reg_partition, tgt2_regno))
+ {
+ edge e;
+ /* Scan over edges. */
+ for (e = b->pred; e; e = e->pred_next)
+ {
+ int pred_block = e->src->index;
+ /* Identify the phi alternatives from both phi
+ nodes corresponding to this edge. */
+ rtx *alt = phi_alternative (set, pred_block);
+ rtx *alt2 = phi_alternative (set2, pred_block);
+
+ /* If one of the phi nodes doesn't have a
+ corresponding alternative, just skip it. */
+ if (alt == 0 || alt2 == 0)
+ continue;
+
+ /* Both alternatives should be SSA registers. */
+ if (GET_CODE (*alt) != REG
+ || !CONVERT_REGISTER_TO_SSA_P (REGNO (*alt)))
+ abort ();
+ if (GET_CODE (*alt2) != REG
+ || !CONVERT_REGISTER_TO_SSA_P (REGNO (*alt2)))
+ abort ();
+
+ /* If the alternatives aren't already in the same
+ class ... */
+ if (partition_find (reg_partition, REGNO (*alt))
+ != partition_find (reg_partition, REGNO (*alt2)))
+ {
+ /* ... make them so. */
+ if (conflicting_hard_regs_p (REGNO (*alt), REGNO (*alt2)))
+ /* It is illegal to unify a hard register with
+ a different register. */
+ abort ();
+
+ partition_union (reg_partition,
+ REGNO (*alt), REGNO (*alt2));
+ ++changed;
+ }
+ }
+ }
+ }
+ }
+
+ return changed;
+}
+
+/* Compute a conservative partition of outstanding pseudo registers.
+ See Morgan 7.3.1. */
+
+static partition
+compute_conservative_reg_partition ()
+{
+ int bb;
+ int changed = 0;
+
+ /* We don't actually work with hard registers, but it's easier to
+ carry them around anyway rather than constantly doing register
+ number arithmetic. */
+ partition p =
+ partition_new (ssa_definition->num_elements);
+
+ /* The first priority is to make sure registers that might have to
+ be copied on abnormal critical edges are placed in the same
+ partition. This saves us from having to split abnormal critical
+ edges. */
+ for (bb = n_basic_blocks; --bb >= 0; )
+ changed += make_regs_equivalent_over_bad_edges (bb, p);
+
+ /* Now we have to insure that corresponding arguments of phi nodes
+ assigning to corresponding regs are equivalent. Iterate until
+ nothing changes. */
+ while (changed > 0)
+ {
+ changed = 0;
+ for (bb = n_basic_blocks; --bb >= 0; )
+ changed += make_equivalent_phi_alternatives_equivalent (bb, p);
+ }
+
+ return p;
+}
+
+/* The following functions compute a register partition that attempts
+ to eliminate as many reg copies and phi node copies as possible by
+ coalescing registers. This is the strategy:
+
+ 1. As in the conservative case, the top priority is to coalesce
+ registers that otherwise would cause copies to be placed on
+ abnormal critical edges (which isn't possible).
+
+ 2. Figure out which regs are involved (in the LHS or RHS) of
+ copies and phi nodes. Compute conflicts among these regs.
+
+ 3. Walk around the instruction stream, placing two regs in the
+ same class of the partition if one appears on the LHS and the
+ other on the RHS of a copy or phi node and the two regs don't
+ conflict. The conflict information of course needs to be
+ updated.
+
+ 4. If anything has changed, there may be new opportunities to
+ coalesce regs, so go back to 2.
+*/
+
+/* If REG1 and REG2 don't conflict in CONFLICTS, place them in the
+ same class of partition P, if they aren't already. Update
+ CONFLICTS appropriately.
+
+ Returns one if REG1 and REG2 were placed in the same class but were
+ not previously; zero otherwise.
+
+ See Morgan figure 11.15. */
+
+static int
+coalesce_if_unconflicting (p, conflicts, reg1, reg2)
+ partition p;
+ conflict_graph conflicts;
+ int reg1;
+ int reg2;
+{
+ int reg;
+
+ /* Work only on SSA registers. */
+ if (!CONVERT_REGISTER_TO_SSA_P (reg1) || !CONVERT_REGISTER_TO_SSA_P (reg2))
+ return 0;
+
+ /* Find the canonical regs for the classes containing REG1 and
+ REG2. */
+ reg1 = partition_find (p, reg1);
+ reg2 = partition_find (p, reg2);
+
+ /* If they're already in the same class, there's nothing to do. */
+ if (reg1 == reg2)
+ return 0;
+
+ /* If the regs conflict, our hands are tied. */
+ if (conflicting_hard_regs_p (reg1, reg2) ||
+ conflict_graph_conflict_p (conflicts, reg1, reg2))
+ return 0;
+
+ /* We're good to go. Put the regs in the same partition. */
+ partition_union (p, reg1, reg2);
+
+ /* Find the new canonical reg for the merged class. */
+ reg = partition_find (p, reg1);
+
+ /* Merge conflicts from the two previous classes. */
+ conflict_graph_merge_regs (conflicts, reg, reg1);
+ conflict_graph_merge_regs (conflicts, reg, reg2);
+
+ return 1;
+}
+
+/* For each register copy insn in basic block BB, place the LHS and
+ RHS regs in the same class in partition P if they do not conflict
+ according to CONFLICTS.
+
+ Returns the number of changes that were made to P.
+
+ See Morgan figure 11.14. */
+
+static int
+coalesce_regs_in_copies (bb, p, conflicts)
+ basic_block bb;
+ partition p;
+ conflict_graph conflicts;
+{
+ int changed = 0;
+ rtx insn;
+ rtx end = bb->end;
+
+ /* Scan the instruction stream of the block. */
+ for (insn = bb->head; insn != end; insn = NEXT_INSN (insn))
+ {
+ rtx pattern;
+ rtx src;
+ rtx dest;
+
+ /* If this isn't a set insn, go to the next insn. */
+ if (GET_CODE (insn) != INSN)
+ continue;
+ pattern = PATTERN (insn);
+ if (GET_CODE (pattern) != SET)
+ continue;
+
+ src = SET_SRC (pattern);
+ dest = SET_DEST (pattern);
+
+ /* We're only looking for copies. */
+ if (GET_CODE (src) != REG || GET_CODE (dest) != REG)
+ continue;
+
+ /* Coalesce only if the reg modes are the same. As long as
+ each reg's rtx is unique, it can have only one mode, so two
+ pseudos of different modes can't be coalesced into one.
+
+ FIXME: We can probably get around this by inserting SUBREGs
+ where appropriate, but for now we don't bother. */
+ if (GET_MODE (src) != GET_MODE (dest))
+ continue;
+
+ /* Found a copy; see if we can use the same reg for both the
+ source and destination (and thus eliminate the copy,
+ ultimately). */
+ changed += coalesce_if_unconflicting (p, conflicts,
+ REGNO (src), REGNO (dest));
+ }
+
+ return changed;
+}
+
+struct phi_coalesce_context
+{
+ partition p;
+ conflict_graph conflicts;
+ int changed;
+};
+
+/* Callback function for for_each_successor_phi. If the set
+ destination and the phi alternative regs do not conflict, place
+ them in the same paritition class. DATA is a pointer to a
+ phi_coalesce_context struct. */
+
+static int
+coalesce_reg_in_phi (insn, dest_regno, src_regno, data)
+ rtx insn ATTRIBUTE_UNUSED;
+ int dest_regno;
+ int src_regno;
+ void *data;
+{
+ struct phi_coalesce_context *context =
+ (struct phi_coalesce_context *) data;
+
+ /* Attempt to use the same reg, if they don't conflict. */
+ context->changed
+ += coalesce_if_unconflicting (context->p, context->conflicts,
+ dest_regno, src_regno);
+ return 0;
+}
+
+/* For each alternative in a phi function corresponding to basic block
+ BB (in phi nodes in successor block to BB), place the reg in the
+ phi alternative and the reg to which the phi value is set into the
+ same class in partition P, if allowed by CONFLICTS.
+
+ Return the number of changes that were made to P.
+
+ See Morgan figure 11.14. */
+
+static int
+coalesce_regs_in_successor_phi_nodes (bb, p, conflicts)
+ basic_block bb;
+ partition p;
+ conflict_graph conflicts;
+{
+ struct phi_coalesce_context context;
+ context.p = p;
+ context.conflicts = conflicts;
+ context.changed = 0;
+
+ for_each_successor_phi (bb, &coalesce_reg_in_phi, &context);
+
+ return context.changed;
+}
+
+/* Compute and return a partition of pseudos. Where possible,
+ non-conflicting pseudos are placed in the same class.
+
+ The caller is responsible for deallocating the returned partition. */
+
+static partition
+compute_coalesced_reg_partition ()
+{
+ int bb;
+ int changed = 0;
+ regset_head phi_set_head;
+ regset phi_set = &phi_set_head;
+
+ partition p =
+ partition_new (ssa_definition->num_elements);
+
+ /* The first priority is to make sure registers that might have to
+ be copied on abnormal critical edges are placed in the same
+ partition. This saves us from having to split abnormal critical
+ edges (which can't be done). */
+ for (bb = n_basic_blocks; --bb >= 0; )
+ make_regs_equivalent_over_bad_edges (bb, p);
+
+ INIT_REG_SET (phi_set);
+
+ do
+ {
+ conflict_graph conflicts;
+
+ changed = 0;
+
+ /* Build the set of registers involved in phi nodes, either as
+ arguments to the phi function or as the target of a set. */
+ CLEAR_REG_SET (phi_set);
+ mark_phi_and_copy_regs (phi_set);
+
+ /* Compute conflicts. */
+ conflicts = conflict_graph_compute (phi_set, p);
+
+ /* FIXME: Better would be to process most frequently executed
+ blocks first, so that most frequently executed copies would
+ be more likely to be removed by register coalescing. But any
+ order will generate correct, if non-optimal, results. */
+ for (bb = n_basic_blocks; --bb >= 0; )
+ {
+ basic_block block = BASIC_BLOCK (bb);
+ changed += coalesce_regs_in_copies (block, p, conflicts);
+ changed +=
+ coalesce_regs_in_successor_phi_nodes (block, p, conflicts);
+ }
+
+ conflict_graph_delete (conflicts);
+ }
+ while (changed > 0);
+
+ FREE_REG_SET (phi_set);
+
+ return p;
+}
+
+/* Mark the regs in a phi node. PTR is a phi expression or one of its
+ components (a REG or a CONST_INT). DATA is a reg set in which to
+ set all regs. Called from for_each_rtx. */
+
+static int
+mark_reg_in_phi (ptr, data)
+ rtx *ptr;
+ void *data;
+{
+ rtx expr = *ptr;
+ regset set = (regset) data;
+
+ switch (GET_CODE (expr))
+ {
+ case REG:
+ SET_REGNO_REG_SET (set, REGNO (expr));
+ /* Fall through. */
+ case CONST_INT:
+ case PHI:
+ return 0;
+ default:
+ abort ();
+ }
+}
+
+/* Mark in PHI_SET all pseudos that are used in a phi node -- either
+ set from a phi expression, or used as an argument in one. Also
+ mark regs that are the source or target of a reg copy. Uses
+ ssa_definition. */
+
+static void
+mark_phi_and_copy_regs (phi_set)
+ regset phi_set;
+{
+ unsigned int reg;
+
+ /* Scan the definitions of all regs. */
+ for (reg = 0; reg < VARRAY_SIZE (ssa_definition); ++reg)
+ if (CONVERT_REGISTER_TO_SSA_P (reg))
+ {
+ rtx insn = VARRAY_RTX (ssa_definition, reg);
+ rtx pattern;
+ rtx src;
+
+ if (insn == NULL
+ || (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED))
+ continue;
+ pattern = PATTERN (insn);
+ /* Sometimes we get PARALLEL insns. These aren't phi nodes or
+ copies. */
+ if (GET_CODE (pattern) != SET)
+ continue;
+ src = SET_SRC (pattern);
+
+ if (GET_CODE (src) == REG)
+ {
+ /* It's a reg copy. */
+ SET_REGNO_REG_SET (phi_set, reg);
+ SET_REGNO_REG_SET (phi_set, REGNO (src));
+ }
+ else if (GET_CODE (src) == PHI)
+ {
+ /* It's a phi node. Mark the reg being set. */
+ SET_REGNO_REG_SET (phi_set, reg);
+ /* Mark the regs used in the phi function. */
+ for_each_rtx (&src, mark_reg_in_phi, phi_set);
+ }
+ /* ... else nothing to do. */
+ }
+}
+
+/* Rename regs in insn PTR that are equivalent. DATA is the register
+ partition which specifies equivalences. */
+
+static int
+rename_equivalent_regs_in_insn (ptr, data)
+ rtx *ptr;
+ void* data;
+{
+ rtx x = *ptr;
+ partition reg_partition = (partition) data;
+
+ if (x == NULL_RTX)
+ return 0;
+
+ switch (GET_CODE (x))
+ {
+ case REG:
+ if (CONVERT_REGISTER_TO_SSA_P (REGNO (x)))
+ {
+ unsigned int regno = REGNO (x);
+ unsigned int new_regno = partition_find (reg_partition, regno);
+ rtx canonical_element_rtx = ssa_rename_from_lookup (new_regno);
+
+ if (canonical_element_rtx != NULL_RTX &&
+ HARD_REGISTER_P (canonical_element_rtx))
+ {
+ if (REGNO (canonical_element_rtx) != regno)
+ *ptr = canonical_element_rtx;
+ }
+ else if (regno != new_regno)
+ {
+ rtx new_reg = regno_reg_rtx[new_regno];
+ if (GET_MODE (x) != GET_MODE (new_reg))
+ abort ();
+ *ptr = new_reg;
+ }
+ }
+ return -1;
+
+ case PHI:
+ /* No need to rename the phi nodes. We'll check equivalence
+ when inserting copies. */
+ return -1;
+
+ default:
+ /* Anything else, continue traversing. */
+ return 0;
+ }
+}
+
+/* Record the register's canonical element stored in SRFP in the
+ canonical_elements sbitmap packaged in DATA. This function is used
+ as a callback function for traversing ssa_rename_from. */
+
+static int
+record_canonical_element_1 (srfp, data)
+ void **srfp;
+ void *data;
+{
+ unsigned int reg = ((ssa_rename_from_pair *) *srfp)->reg;
+ sbitmap canonical_elements =
+ ((struct ssa_rename_from_hash_table_data *) data)->canonical_elements;
+ partition reg_partition =
+ ((struct ssa_rename_from_hash_table_data *) data)->reg_partition;
+
+ SET_BIT (canonical_elements, partition_find (reg_partition, reg));
+ return 1;
+}
+
+/* For each class in the REG_PARTITION corresponding to a particular
+ hard register and machine mode, check that there are no other
+ classes with the same hard register and machine mode. Returns
+ nonzero if this is the case, i.e., the partition is acceptable. */
+
+static int
+check_hard_regs_in_partition (reg_partition)
+ partition reg_partition;
+{
+ /* CANONICAL_ELEMENTS has a nonzero bit if a class with the given register
+ number and machine mode has already been seen. This is a
+ problem with the partition. */
+ sbitmap canonical_elements;
+ int element_index;
+ int already_seen[FIRST_PSEUDO_REGISTER][NUM_MACHINE_MODES];
+ int reg;
+ int mach_mode;
+
+ /* Collect a list of canonical elements. */
+ canonical_elements = sbitmap_alloc (max_reg_num ());
+ sbitmap_zero (canonical_elements);
+ ssa_rename_from_traverse (&record_canonical_element_1,
+ canonical_elements, reg_partition);
+
+ /* We have not seen any hard register uses. */
+ for (reg = 0; reg < FIRST_PSEUDO_REGISTER; ++reg)
+ for (mach_mode = 0; mach_mode < NUM_MACHINE_MODES; ++mach_mode)
+ already_seen[reg][mach_mode] = 0;
+
+ /* Check for classes with the same hard register and machine mode. */
+ EXECUTE_IF_SET_IN_SBITMAP (canonical_elements, 0, element_index,
+ {
+ rtx hard_reg_rtx = ssa_rename_from_lookup (element_index);
+ if (hard_reg_rtx != NULL_RTX &&
+ HARD_REGISTER_P (hard_reg_rtx) &&
+ already_seen[REGNO (hard_reg_rtx)][GET_MODE (hard_reg_rtx)] != 0)
+ /* Two distinct partition classes should be mapped to the same
+ hard register. */
+ return 0;
+ });
+
+ sbitmap_free (canonical_elements);
+
+ return 1;
+}
+
+/* Rename regs that are equivalent in REG_PARTITION. Also collapse
+ any SEQUENCE insns. */
+
+static void
+rename_equivalent_regs (reg_partition)
+ partition reg_partition;
+{
+ int bb;
+
+ for (bb = n_basic_blocks; --bb >= 0; )
+ {
+ basic_block b = BASIC_BLOCK (bb);
+ rtx next = b->head;
+ rtx last = b->end;
+ rtx insn;
+
+ do
+ {
+ insn = next;
+ if (INSN_P (insn))
+ {
+ for_each_rtx (&PATTERN (insn),
+ rename_equivalent_regs_in_insn,
+ reg_partition);
+ for_each_rtx (&REG_NOTES (insn),
+ rename_equivalent_regs_in_insn,
+ reg_partition);
+
+ if (GET_CODE (PATTERN (insn)) == SEQUENCE)
+ {
+ rtx s = PATTERN (insn);
+ int slen = XVECLEN (s, 0);
+ int i;
+
+ if (slen <= 1)
+ abort ();
+
+ PATTERN (insn) = XVECEXP (s, 0, slen-1);
+ for (i = 0; i < slen - 1; i++)
+ emit_insn_before (XVECEXP (s, 0, i), insn);
+ }
+ }
+
+ next = NEXT_INSN (insn);
+ }
+ while (insn != last);
+ }
+}
+
+/* The main entry point for moving from SSA. */
+
+void
+convert_from_ssa ()
+{
+ int bb;
+ partition reg_partition;
+ rtx insns = get_insns ();
+
+ /* Need global_live_at_{start,end} up to date. There should not be
+ any significant dead code at this point, except perhaps dead
+ stores. So do not take the time to perform dead code elimination.
+
+ Register coalescing needs death notes, so generate them. */
+ life_analysis (insns, NULL, PROP_DEATH_NOTES);
+
+ /* Figure out which regs in copies and phi nodes don't conflict and
+ therefore can be coalesced. */
+ if (conservative_reg_partition)
+ reg_partition = compute_conservative_reg_partition ();
+ else
+ reg_partition = compute_coalesced_reg_partition ();
+
+ if (!check_hard_regs_in_partition (reg_partition))
+ /* Two separate partitions should correspond to the same hard
+ register but do not. */
+ abort ();
+
+ rename_equivalent_regs (reg_partition);
+
+ /* Eliminate the PHI nodes. */
+ for (bb = n_basic_blocks; --bb >= 0; )
+ {
+ basic_block b = BASIC_BLOCK (bb);
+ edge e;
+
+ for (e = b->pred; e; e = e->pred_next)
+ if (e->src != ENTRY_BLOCK_PTR)
+ eliminate_phi (e, reg_partition);
+ }
+
+ partition_delete (reg_partition);
+
+ /* Actually delete the PHI nodes. */
+ for (bb = n_basic_blocks; --bb >= 0; )
+ {
+ rtx insn = BLOCK_HEAD (bb);
+
+ while (1)
+ {
+ /* If this is a PHI node delete it. */
+ if (PHI_NODE_P (insn))
+ {
+ if (insn == BLOCK_END (bb))
+ BLOCK_END (bb) = PREV_INSN (insn);
+ insn = delete_insn (insn);
+ }
+ /* Since all the phi nodes come at the beginning of the
+ block, if we find an ordinary insn, we can stop looking
+ for more phi nodes. */
+ else if (INSN_P (insn))
+ break;
+ /* If we've reached the end of the block, stop. */
+ else if (insn == BLOCK_END (bb))
+ break;
+ else
+ insn = NEXT_INSN (insn);
+ }
+ }
+
+ /* Commit all the copy nodes needed to convert out of SSA form. */
+ commit_edge_insertions ();
+
+ in_ssa_form = 0;
+
+ count_or_remove_death_notes (NULL, 1);
+
+ /* Deallocate the data structures. */
+ VARRAY_FREE (ssa_definition);
+ ssa_rename_from_free ();
+}
+
+/* Scan phi nodes in successors to BB. For each such phi node that
+ has a phi alternative value corresponding to BB, invoke FN. FN
+ is passed the entire phi node insn, the regno of the set
+ destination, the regno of the phi argument corresponding to BB,
+ and DATA.
+
+ If FN ever returns non-zero, stops immediately and returns this
+ value. Otherwise, returns zero. */
+
+int
+for_each_successor_phi (bb, fn, data)
+ basic_block bb;
+ successor_phi_fn fn;
+ void *data;
+{
+ edge e;
+
+ if (bb == EXIT_BLOCK_PTR)
+ return 0;
+
+ /* Scan outgoing edges. */
+ for (e = bb->succ; e != NULL; e = e->succ_next)
+ {
+ rtx insn;
+
+ basic_block successor = e->dest;
+ if (successor == ENTRY_BLOCK_PTR
+ || successor == EXIT_BLOCK_PTR)
+ continue;
+
+ /* Advance to the first non-label insn of the successor block. */
+ insn = first_insn_after_basic_block_note (successor);
+
+ if (insn == NULL)
+ continue;
+
+ /* Scan phi nodes in the successor. */
+ for ( ; PHI_NODE_P (insn); insn = NEXT_INSN (insn))
+ {
+ int result;
+ rtx phi_set = PATTERN (insn);
+ rtx *alternative = phi_alternative (phi_set, bb->index);
+ rtx phi_src;
+
+ /* This phi function may not have an alternative
+ corresponding to the incoming edge, indicating the
+ assigned variable is not defined along the edge. */
+ if (alternative == NULL)
+ continue;
+ phi_src = *alternative;
+
+ /* Invoke the callback. */
+ result = (*fn) (insn, REGNO (SET_DEST (phi_set)),
+ REGNO (phi_src), data);
+
+ /* Terminate if requested. */
+ if (result != 0)
+ return result;
+ }
+ }
+
+ return 0;
+}
+
+/* Assuming the ssa_rename_from mapping has been established, yields
+ nonzero if 1) only one SSA register of REG1 and REG2 comes from a
+ hard register or 2) both SSA registers REG1 and REG2 come from
+ different hard registers. */
+
+static int
+conflicting_hard_regs_p (reg1, reg2)
+ int reg1;
+ int reg2;
+{
+ int orig_reg1 = original_register (reg1);
+ int orig_reg2 = original_register (reg2);
+ if (HARD_REGISTER_NUM_P (orig_reg1) && HARD_REGISTER_NUM_P (orig_reg2)
+ && orig_reg1 != orig_reg2)
+ return 1;
+ if (HARD_REGISTER_NUM_P (orig_reg1) && !HARD_REGISTER_NUM_P (orig_reg2))
+ return 1;
+ if (!HARD_REGISTER_NUM_P (orig_reg1) && HARD_REGISTER_NUM_P (orig_reg2))
+ return 1;
+
+ return 0;
+}
OpenPOWER on IntegriCloud