summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/ssa-dce.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-dce.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-dce.c')
-rw-r--r--contrib/gcc/ssa-dce.c742
1 files changed, 742 insertions, 0 deletions
diff --git a/contrib/gcc/ssa-dce.c b/contrib/gcc/ssa-dce.c
new file mode 100644
index 0000000..83b4e44
--- /dev/null
+++ b/contrib/gcc/ssa-dce.c
@@ -0,0 +1,742 @@
+/* Dead-code elimination pass for the GNU compiler.
+ Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+ Written by Jeffrey D. Oldham <oldham@codesourcery.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. */
+
+/* Dead-code elimination is the removal of instructions which have no
+ impact on the program's output. "Dead instructions" have no impact
+ on the program's output, while "necessary instructions" may have
+ impact on the output.
+
+ The algorithm consists of three phases:
+ 1) marking as necessary all instructions known to be necessary,
+ e.g., writing a value to memory,
+ 2) propagating necessary instructions, e.g., the instructions
+ giving values to operands in necessary instructions, and
+ 3) removing dead instructions (except replacing dead conditionals
+ with unconditional jumps).
+
+ Side Effects:
+ The last step can require adding labels, deleting insns, and
+ modifying basic block structures. Some conditional jumps may be
+ converted to unconditional jumps so the control-flow graph may be
+ out-of-date.
+
+ Edges from some infinite loops to the exit block can be added to
+ the control-flow graph, but will be removed after this pass is
+ complete.
+
+ It Does Not Perform:
+ We decided to not simultaneously perform jump optimization and dead
+ loop removal during dead-code elimination. Thus, all jump
+ instructions originally present remain after dead-code elimination
+ but 1) unnecessary conditional jump instructions are changed to
+ unconditional jump instructions and 2) all unconditional jump
+ instructions remain.
+
+ Assumptions:
+ 1) SSA has been performed.
+ 2) The basic block and control-flow graph structures are accurate.
+ 3) The flow graph permits constructing an edge_list.
+ 4) note rtxes should be saved.
+
+ Unfinished:
+ When replacing unnecessary conditional jumps with unconditional
+ jumps, the control-flow graph is not updated. It should be.
+
+ References:
+ Building an Optimizing Compiler
+ Robert Morgan
+ Butterworth-Heinemann, 1998
+ Section 8.9
+*/
+
+#include "config.h"
+#include "system.h"
+
+#include "rtl.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "ssa.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "output.h"
+
+
+/* A map from blocks to the edges on which they are control dependent. */
+typedef struct {
+ /* An dynamically allocated array. The Nth element corresponds to
+ the block with index N + 2. The Ith bit in the bitmap is set if
+ that block is dependent on the Ith edge. */
+ bitmap *data;
+ /* The number of elements in the array. */
+ int length;
+} control_dependent_block_to_edge_map_s, *control_dependent_block_to_edge_map;
+
+/* Local function prototypes. */
+static control_dependent_block_to_edge_map control_dependent_block_to_edge_map_create
+ PARAMS((size_t num_basic_blocks));
+static void set_control_dependent_block_to_edge_map_bit
+ PARAMS ((control_dependent_block_to_edge_map c, basic_block bb,
+ int edge_index));
+static void control_dependent_block_to_edge_map_free
+ PARAMS ((control_dependent_block_to_edge_map c));
+static void find_all_control_dependences
+ PARAMS ((struct edge_list *el, int *pdom,
+ control_dependent_block_to_edge_map cdbte));
+static void find_control_dependence
+ PARAMS ((struct edge_list *el, int edge_index, int *pdom,
+ control_dependent_block_to_edge_map cdbte));
+static basic_block find_pdom
+ PARAMS ((int *pdom, basic_block block));
+static int inherently_necessary_register_1
+ PARAMS ((rtx *current_rtx, void *data));
+static int inherently_necessary_register
+ PARAMS ((rtx current_rtx));
+static int find_inherently_necessary
+ PARAMS ((rtx current_rtx));
+static int propagate_necessity_through_operand
+ PARAMS ((rtx *current_rtx, void *data));
+static void note_inherently_necessary_set
+ PARAMS ((rtx, rtx, void *));
+
+/* Unnecessary insns are indicated using insns' in_struct bit. */
+
+/* Indicate INSN is dead-code; returns nothing. */
+#define KILL_INSN(INSN) INSN_DEAD_CODE_P(INSN) = 1
+/* Indicate INSN is necessary, i.e., not dead-code; returns nothing. */
+#define RESURRECT_INSN(INSN) INSN_DEAD_CODE_P(INSN) = 0
+/* Return nonzero if INSN is unnecessary. */
+#define UNNECESSARY_P(INSN) INSN_DEAD_CODE_P(INSN)
+static void mark_all_insn_unnecessary
+ PARAMS ((void));
+/* Execute CODE with free variable INSN for all unnecessary insns in
+ an unspecified order, producing no output. */
+#define EXECUTE_IF_UNNECESSARY(INSN, CODE) \
+{ \
+ rtx INSN; \
+ \
+ for (INSN = get_insns (); INSN != NULL_RTX; INSN = NEXT_INSN (INSN)) \
+ if (INSN_DEAD_CODE_P (INSN)) { \
+ CODE; \
+ } \
+}
+/* Find the label beginning block BB. */
+static rtx find_block_label
+ PARAMS ((basic_block bb));
+/* Remove INSN, updating its basic block structure. */
+static void delete_insn_bb
+ PARAMS ((rtx insn));
+
+/* Recording which blocks are control dependent on which edges. We
+ expect each block to be control dependent on very few edges so we
+ use a bitmap for each block recording its edges. An array holds
+ the bitmap. Its position 0 entry holds the bitmap for block
+ INVALID_BLOCK+1 so that all blocks, including the entry and exit
+ blocks can participate in the data structure. */
+
+/* Create a control_dependent_block_to_edge_map, given the number
+ NUM_BASIC_BLOCKS of non-entry, non-exit basic blocks, e.g.,
+ n_basic_blocks. This memory must be released using
+ control_dependent_block_to_edge_map_free (). */
+
+static control_dependent_block_to_edge_map
+control_dependent_block_to_edge_map_create (num_basic_blocks)
+ size_t num_basic_blocks;
+{
+ int i;
+ control_dependent_block_to_edge_map c
+ = xmalloc (sizeof (control_dependent_block_to_edge_map_s));
+ c->length = num_basic_blocks - (INVALID_BLOCK+1);
+ c->data = xmalloc ((size_t) c->length*sizeof (bitmap));
+ for (i = 0; i < c->length; ++i)
+ c->data[i] = BITMAP_XMALLOC ();
+
+ return c;
+}
+
+/* Indicate block BB is control dependent on an edge with index
+ EDGE_INDEX in the mapping C of blocks to edges on which they are
+ control-dependent. */
+
+static void
+set_control_dependent_block_to_edge_map_bit (c, bb, edge_index)
+ control_dependent_block_to_edge_map c;
+ basic_block bb;
+ int edge_index;
+{
+ if (bb->index - (INVALID_BLOCK+1) >= c->length)
+ abort ();
+
+ bitmap_set_bit (c->data[bb->index - (INVALID_BLOCK+1)],
+ edge_index);
+}
+
+/* Execute CODE for each edge (given number EDGE_NUMBER within the
+ CODE) for which the block containing INSN is control dependent,
+ returning no output. CDBTE is the mapping of blocks to edges on
+ which they are control-dependent. */
+
+#define EXECUTE_IF_CONTROL_DEPENDENT(CDBTE, INSN, EDGE_NUMBER, CODE) \
+ EXECUTE_IF_SET_IN_BITMAP \
+ (CDBTE->data[BLOCK_NUM (INSN) - (INVALID_BLOCK+1)], 0, \
+ EDGE_NUMBER, CODE)
+
+/* Destroy a control_dependent_block_to_edge_map C. */
+
+static void
+control_dependent_block_to_edge_map_free (c)
+ control_dependent_block_to_edge_map c;
+{
+ int i;
+ for (i = 0; i < c->length; ++i)
+ BITMAP_XFREE (c->data[i]);
+ free ((PTR) c);
+}
+
+/* Record all blocks' control dependences on all edges in the edge
+ list EL, ala Morgan, Section 3.6. The mapping PDOM of blocks to
+ their postdominators are used, and results are stored in CDBTE,
+ which should be empty. */
+
+static void
+find_all_control_dependences (el, pdom, cdbte)
+ struct edge_list *el;
+ int *pdom;
+ control_dependent_block_to_edge_map cdbte;
+{
+ int i;
+
+ for (i = 0; i < NUM_EDGES (el); ++i)
+ find_control_dependence (el, i, pdom, cdbte);
+}
+
+/* Determine all blocks' control dependences on the given edge with
+ edge_list EL index EDGE_INDEX, ala Morgan, Section 3.6. The
+ mapping PDOM of blocks to their postdominators are used, and
+ results are stored in CDBTE, which is assumed to be initialized
+ with zeros in each (block b', edge) position. */
+
+static void
+find_control_dependence (el, edge_index, pdom, cdbte)
+ struct edge_list *el;
+ int edge_index;
+ int *pdom;
+ control_dependent_block_to_edge_map cdbte;
+{
+ basic_block current_block;
+ basic_block ending_block;
+
+ if (INDEX_EDGE_PRED_BB (el, edge_index) == EXIT_BLOCK_PTR)
+ abort ();
+ ending_block =
+ (INDEX_EDGE_PRED_BB (el, edge_index) == ENTRY_BLOCK_PTR)
+ ? BASIC_BLOCK (0)
+ : find_pdom (pdom, INDEX_EDGE_PRED_BB (el, edge_index));
+
+ for (current_block = INDEX_EDGE_SUCC_BB (el, edge_index);
+ current_block != ending_block && current_block != EXIT_BLOCK_PTR;
+ current_block = find_pdom (pdom, current_block))
+ {
+ set_control_dependent_block_to_edge_map_bit (cdbte,
+ current_block,
+ edge_index);
+ }
+}
+
+/* Find the immediate postdominator PDOM of the specified basic block
+ BLOCK. This function is necessary because some blocks have
+ negative numbers. */
+
+static basic_block
+find_pdom (pdom, block)
+ int *pdom;
+ basic_block block;
+{
+ if (!block)
+ abort ();
+ if (block->index == INVALID_BLOCK)
+ abort ();
+
+ if (block == ENTRY_BLOCK_PTR)
+ return BASIC_BLOCK (0);
+ else if (block == EXIT_BLOCK_PTR || pdom[block->index] == EXIT_BLOCK)
+ return EXIT_BLOCK_PTR;
+ else
+ return BASIC_BLOCK (pdom[block->index]);
+}
+
+/* Determine if the given CURRENT_RTX uses a hard register not
+ converted to SSA. Returns nonzero only if it uses such a hard
+ register. DATA is not used.
+
+ The program counter (PC) is not considered inherently necessary
+ since code should be position-independent and thus not depend on
+ particular PC values. */
+
+static int
+inherently_necessary_register_1 (current_rtx, data)
+ rtx *current_rtx;
+ void *data ATTRIBUTE_UNUSED;
+{
+ rtx x = *current_rtx;
+
+ if (x == NULL_RTX)
+ return 0;
+ switch (GET_CODE (x))
+ {
+ case CLOBBER:
+ /* Do not traverse the rest of the clobber. */
+ return -1;
+ break;
+ case PC:
+ return 0;
+ break;
+ case REG:
+ if (CONVERT_REGISTER_TO_SSA_P (REGNO (x)) || x == pc_rtx)
+ return 0;
+ else
+ return !0;
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
+
+/* Return nonzero if the insn CURRENT_RTX is inherently necessary. */
+
+static int
+inherently_necessary_register (current_rtx)
+ rtx current_rtx;
+{
+ return for_each_rtx (&current_rtx,
+ &inherently_necessary_register_1, NULL);
+}
+
+
+/* Called via note_stores for each store in an insn. Note whether
+ or not a particular store is inherently necessary. Store a
+ nonzero value in inherently_necessary_p if such a store is found. */
+
+static void
+note_inherently_necessary_set (dest, set, data)
+ rtx set ATTRIBUTE_UNUSED;
+ rtx dest;
+ void *data;
+{
+ int *inherently_necessary_set_p = (int *) data;
+
+ while (GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == STRICT_LOW_PART
+ || GET_CODE (dest) == ZERO_EXTRACT
+ || GET_CODE (dest) == SIGN_EXTRACT)
+ dest = XEXP (dest, 0);
+
+ if (GET_CODE (dest) == MEM
+ || GET_CODE (dest) == UNSPEC
+ || GET_CODE (dest) == UNSPEC_VOLATILE)
+ *inherently_necessary_set_p = 1;
+}
+
+/* Mark X as inherently necessary if appropriate. For example,
+ function calls and storing values into memory are inherently
+ necessary. This function is to be used with for_each_rtx ().
+ Return nonzero iff inherently necessary. */
+
+static int
+find_inherently_necessary (x)
+ rtx x;
+{
+ if (x == NULL_RTX)
+ return 0;
+ else if (inherently_necessary_register (x))
+ return !0;
+ else
+ switch (GET_CODE (x))
+ {
+ case CALL_INSN:
+ case BARRIER:
+ case PREFETCH:
+ return !0;
+ case CODE_LABEL:
+ case NOTE:
+ return 0;
+ case JUMP_INSN:
+ return JUMP_TABLE_DATA_P (x) || computed_jump_p (x) != 0;
+ case INSN:
+ {
+ int inherently_necessary_set = 0;
+ note_stores (PATTERN (x),
+ note_inherently_necessary_set,
+ &inherently_necessary_set);
+
+ /* If we found an inherently necessary set or an asm
+ instruction, then we consider this insn inherently
+ necessary. */
+ return (inherently_necessary_set
+ || GET_CODE (PATTERN (x)) == ASM_INPUT
+ || asm_noperands (PATTERN (x)) >= 0);
+ }
+ default:
+ /* Found an impossible insn type. */
+ abort ();
+ break;
+ }
+}
+
+/* Propagate necessity through REG and SUBREG operands of CURRENT_RTX.
+ This function is called with for_each_rtx () on necessary
+ instructions. The DATA must be a varray of unprocessed
+ instructions. */
+
+static int
+propagate_necessity_through_operand (current_rtx, data)
+ rtx *current_rtx;
+ void *data;
+{
+ rtx x = *current_rtx;
+ varray_type *unprocessed_instructions = (varray_type *) data;
+
+ if (x == NULL_RTX)
+ return 0;
+ switch ( GET_CODE (x))
+ {
+ case REG:
+ if (CONVERT_REGISTER_TO_SSA_P (REGNO (x)))
+ {
+ rtx insn = VARRAY_RTX (ssa_definition, REGNO (x));
+ if (insn != NULL_RTX && UNNECESSARY_P (insn))
+ {
+ RESURRECT_INSN (insn);
+ VARRAY_PUSH_RTX (*unprocessed_instructions, insn);
+ }
+ }
+ return 0;
+
+ default:
+ return 0;
+ }
+}
+
+/* Indicate all insns initially assumed to be unnecessary. */
+
+static void
+mark_all_insn_unnecessary ()
+{
+ rtx insn;
+ for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn))
+ KILL_INSN (insn);
+}
+
+/* Find the label beginning block BB, adding one if necessary. */
+
+static rtx
+find_block_label (bb)
+ basic_block bb;
+{
+ rtx insn = bb->head;
+ if (LABEL_P (insn))
+ return insn;
+ else
+ {
+ rtx new_label = emit_label_before (gen_label_rtx (), insn);
+ if (insn == bb->head)
+ bb->head = new_label;
+ return new_label;
+ }
+}
+
+/* Remove INSN, updating its basic block structure. */
+
+static void
+delete_insn_bb (insn)
+ rtx insn;
+{
+ if (!insn)
+ abort ();
+
+ /* Do not actually delete anything that is not an INSN.
+
+ We can get here because we only consider INSNs as
+ potentially necessary. We leave it to later passes
+ to remove unnecessary notes, unused labels, etc. */
+ if (! INSN_P (insn))
+ return;
+
+ delete_insn (insn);
+}
+
+/* Perform the dead-code elimination. */
+
+void
+ssa_eliminate_dead_code ()
+{
+ int i;
+ rtx insn;
+ /* Necessary instructions with operands to explore. */
+ varray_type unprocessed_instructions;
+ /* Map element (b,e) is nonzero if the block is control dependent on
+ edge. "cdbte" abbreviates control dependent block to edge. */
+ control_dependent_block_to_edge_map cdbte;
+ /* Element I is the immediate postdominator of block I. */
+ int *pdom;
+ struct edge_list *el;
+
+ int max_insn_uid = get_max_uid ();
+
+ /* Initialize the data structures. */
+ mark_all_insn_unnecessary ();
+ VARRAY_RTX_INIT (unprocessed_instructions, 64,
+ "unprocessed instructions");
+ cdbte = control_dependent_block_to_edge_map_create (n_basic_blocks);
+
+ /* Prepare for use of BLOCK_NUM (). */
+ connect_infinite_loops_to_exit ();
+ /* Be careful not to clear the added edges. */
+ compute_bb_for_insn (max_insn_uid);
+
+ /* Compute control dependence. */
+ pdom = (int *) xmalloc (n_basic_blocks * sizeof (int));
+ for (i = 0; i < n_basic_blocks; ++i)
+ pdom[i] = INVALID_BLOCK;
+ calculate_dominance_info (pdom, NULL, CDI_POST_DOMINATORS);
+ /* Assume there is a path from each node to the exit block. */
+ for (i = 0; i < n_basic_blocks; ++i)
+ if (pdom[i] == INVALID_BLOCK)
+ pdom[i] = EXIT_BLOCK;
+ el = create_edge_list ();
+ find_all_control_dependences (el, pdom, cdbte);
+
+ /* Find inherently necessary instructions. */
+ for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn))
+ if (find_inherently_necessary (insn))
+ {
+ RESURRECT_INSN (insn);
+ VARRAY_PUSH_RTX (unprocessed_instructions, insn);
+ }
+
+ /* Propagate necessity using the operands of necessary instructions. */
+ while (VARRAY_ACTIVE_SIZE (unprocessed_instructions) > 0)
+ {
+ rtx current_instruction;
+ int edge_number;
+
+ current_instruction = VARRAY_TOP_RTX (unprocessed_instructions);
+ VARRAY_POP (unprocessed_instructions);
+
+ /* Make corresponding control dependent edges necessary. */
+ /* Assume the only JUMP_INSN is the block's last insn. It appears
+ that the last instruction of the program need not be a
+ JUMP_INSN. */
+
+ if (INSN_P (current_instruction)
+ && !JUMP_TABLE_DATA_P (current_instruction))
+ {
+ /* Notes and labels contain no interesting operands. */
+ EXECUTE_IF_CONTROL_DEPENDENT
+ (cdbte, current_instruction, edge_number,
+ {
+ rtx jump_insn = (INDEX_EDGE_PRED_BB (el, edge_number))->end;
+ if (GET_CODE (jump_insn) == JUMP_INSN
+ && UNNECESSARY_P (jump_insn))
+ {
+ RESURRECT_INSN (jump_insn);
+ VARRAY_PUSH_RTX (unprocessed_instructions, jump_insn);
+ }
+ });
+
+ /* Propagate through the operands. */
+ for_each_rtx (&current_instruction,
+ &propagate_necessity_through_operand,
+ (PTR) &unprocessed_instructions);
+
+ /* PHI nodes are somewhat special in that each PHI alternative
+ has data and control dependencies. The data dependencies
+ are handled via propagate_necessity_through_operand. We
+ handle the control dependency here.
+
+ We consider the control dependent edges leading to the
+ predecessor block associated with each PHI alternative
+ as necessary. */
+ if (PHI_NODE_P (current_instruction))
+ {
+ rtvec phi_vec = XVEC (SET_SRC (PATTERN (current_instruction)), 0);
+ int num_elem = GET_NUM_ELEM (phi_vec);
+ int v;
+
+ for (v = num_elem - 2; v >= 0; v -= 2)
+ {
+ basic_block bb;
+
+ bb = BASIC_BLOCK (INTVAL (RTVEC_ELT (phi_vec, v + 1)));
+ EXECUTE_IF_CONTROL_DEPENDENT
+ (cdbte, bb->end, edge_number,
+ {
+ rtx jump_insn;
+
+ jump_insn = (INDEX_EDGE_PRED_BB (el, edge_number))->end;
+ if (((GET_CODE (jump_insn) == JUMP_INSN))
+ && UNNECESSARY_P (jump_insn))
+ {
+ RESURRECT_INSN (jump_insn);
+ VARRAY_PUSH_RTX (unprocessed_instructions, jump_insn);
+ }
+ });
+
+ }
+ }
+ }
+ }
+
+ /* Remove the unnecessary instructions. */
+ EXECUTE_IF_UNNECESSARY (insn,
+ {
+ if (any_condjump_p (insn))
+ {
+ basic_block bb = BLOCK_FOR_INSN (insn);
+ basic_block pdom_bb = find_pdom (pdom, bb);
+ rtx lbl;
+ edge e;
+
+ /* Egad. The immediate post dominator is the exit block. We
+ would like to optimize this conditional jump to jump directly
+ to the exit block. That can be difficult as we may not have
+ a suitable CODE_LABEL that allows us to fall unmolested into
+ the exit block.
+
+ So, we just delete the conditional branch by turning it into
+ a deleted note. That is safe, but just not as optimal as
+ it could be. */
+ if (pdom_bb == EXIT_BLOCK_PTR)
+ {
+ /* Since we're going to just delete the branch, we need
+ look at all the edges and remove all those which are not
+ a fallthru edge. */
+ e = bb->succ;
+ while (e)
+ {
+ edge temp = e;
+
+ e = e->succ_next;
+ if ((temp->flags & EDGE_FALLTHRU) == 0)
+ {
+ /* We've found a non-fallthru edge, find any PHI nodes
+ at the target and clean them up. */
+ if (temp->dest != EXIT_BLOCK_PTR)
+ {
+ rtx insn
+ = first_insn_after_basic_block_note (temp->dest);
+
+ while (PHI_NODE_P (insn))
+ {
+ remove_phi_alternative (PATTERN (insn), temp->src);
+ insn = NEXT_INSN (insn);
+ }
+ }
+
+ remove_edge (temp);
+ }
+ }
+
+ /* Now "delete" the conditional jump. */
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ continue;
+ }
+
+ /* We've found a conditional branch that is unnecessary.
+
+ First, remove all outgoing edges from this block, updating
+ PHI nodes as appropriate. */
+ e = bb->succ;
+ while (e)
+ {
+ edge temp = e;
+
+ e = e->succ_next;
+
+ if (temp->flags & EDGE_ABNORMAL)
+ continue;
+
+ /* We found an edge that is not executable. First simplify
+ the PHI nodes in the target block. */
+ if (temp->dest != EXIT_BLOCK_PTR)
+ {
+ rtx insn = first_insn_after_basic_block_note (temp->dest);
+
+ while (PHI_NODE_P (insn))
+ {
+ remove_phi_alternative (PATTERN (insn), temp->src);
+ insn = NEXT_INSN (insn);
+ }
+ }
+
+ remove_edge (temp);
+ }
+
+ /* Create an edge from this block to the post dominator.
+ What about the PHI nodes at the target? */
+ make_edge (bb, pdom_bb, 0);
+
+ /* Third, transform this insn into an unconditional
+ jump to the label for the immediate postdominator. */
+ lbl = find_block_label (pdom_bb);
+ SET_SRC (PATTERN (insn)) = gen_rtx_LABEL_REF (VOIDmode, lbl);
+ INSN_CODE (insn) = -1;
+ JUMP_LABEL (insn) = lbl;
+ LABEL_NUSES (lbl)++;
+
+ /* A barrier must follow any unconditional jump. Barriers
+ are not in basic blocks so this must occur after
+ deleting the conditional jump. */
+ emit_barrier_after (insn);
+ }
+ else if (!JUMP_P (insn))
+ delete_insn_bb (insn);
+ });
+
+ /* Remove fake edges from the CFG. */
+ remove_fake_edges ();
+
+ /* Find any blocks with no successors and ensure they are followed
+ by a BARRIER. delete_insn has the nasty habit of deleting barriers
+ when deleting insns. */
+ for (i = 0; i < n_basic_blocks; i++)
+ {
+ basic_block bb = BASIC_BLOCK (i);
+
+ if (bb->succ == NULL)
+ {
+ rtx next = NEXT_INSN (bb->end);
+
+ if (!next || GET_CODE (next) != BARRIER)
+ emit_barrier_after (bb->end);
+ }
+ }
+ /* Release allocated memory. */
+ for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn))
+ RESURRECT_INSN (insn);
+ if (VARRAY_ACTIVE_SIZE (unprocessed_instructions) != 0)
+ abort ();
+ VARRAY_FREE (unprocessed_instructions);
+ control_dependent_block_to_edge_map_free (cdbte);
+ free ((PTR) pdom);
+ free_edge_list (el);
+}
OpenPOWER on IntegriCloud