diff options
author | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-07-28 14:33:56 +0000 |
---|---|---|
committer | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-07-28 14:33:56 +0000 |
commit | 75a70cf95f65fe9204b15ad9aba31c571381d224 (patch) | |
tree | 2926705dd533a8904679724ab1cec40dfee45094 /gcc/gimple-iterator.c | |
parent | d0a9db40355cf570989e2aca92ab2060df234926 (diff) | |
download | gcc-75a70cf95f65fe9204b15ad9aba31c571381d224.tar.gz |
2008-07-28 Richard Guenther <rguenther@suse.de>
Merge from gimple-tuples-branch.
* ChangeLog.tuples: ChangeLog from gimple-tuples-branch.
* gimple.def: New file.
* gsstruct.def: Likewise.
* gimple-iterator.c: Likewise.
* gimple-pretty-print.c: Likewise.
* tree-gimple.c: Removed. Merged into ...
* gimple.c: ... here. New file.
* tree-gimple.h: Removed. Merged into ...
* gimple.h: ... here. New file.
* Makefile.in: Add dependencies on GIMPLE_H and tree-iterator.h.
* configure.ac: Added support for ENABLE_GIMPLE_CHECKING and the
--enable-checking=gimple flag.
* config.in: Likewise.
* configure: Regenerated.
* tree-ssa-operands.h: Tuplified.
* tree-vrp.c: Likewise.
* tree-loop-linear.c: Likewise.
* tree-into-ssa.c: Likewise.
* tree-ssa-loop-im.c: Likewise.
* tree-dump.c: Likewise.
* tree-complex.c: Likewise.
* cgraphbuild.c: Likewise.
* tree-ssa-threadupdate.c: Likewise.
* tree-ssa-loop-niter.c: Likewise.
* tree-pretty-print.c: Likewise.
* tracer.c: Likewise.
* gengtype.c: Likewise.
* tree-loop-distribution.c: Likewise.
* tree-ssa-loop-unswitch.c: Likewise.
* cgraph.c: Likewise.
* cgraph.h: Likewise.
* tree-ssa-loop-manip.c: Likewise.
* value-prof.c: Likewise.
* tree-ssa-loop-ch.c: Likewise.
* tree-tailcall.c: Likewise.
* value-prof.h: Likewise.
* tree.c: Likewise.
* tree.h: Likewise.
* tree-pass.h: Likewise.
* ipa-cp.c: Likewise.
* tree-scalar-evolution.c: Likewise.
* tree-scalar-evolution.h: Likewise.
* target.h: Likewise.
* lambda-mat.c: Likewise.
* tree-phinodes.c: Likewise.
* diagnostic.h: Likewise.
* builtins.c: Likewise.
* tree-ssa-alias-warnings.c: Likewise.
* cfghooks.c: Likewise.
* fold-const.c: Likewise.
* cfghooks.h: Likewise.
* omp-low.c: Likewise.
* tree-ssa-dse.c: Likewise.
* ipa-reference.c: Likewise.
* tree-ssa-uncprop.c: Likewise.
* toplev.c: Likewise.
* tree-gimple.c: Likewise.
* tree-gimple.h: Likewise.
* tree-chrec.c: Likewise.
* tree-chrec.h: Likewise.
* tree-ssa-sccvn.c: Likewise.
* tree-ssa-sccvn.h: Likewise.
* cgraphunit.c: Likewise.
* tree-ssa-copyrename.c: Likewise.
* tree-ssa-ccp.c: Likewise.
* tree-ssa-loop-ivopts.c: Likewise.
* tree-nomudflap.c: Likewise.
* tree-call-cdce.c: Likewise.
* ipa-pure-const.c: Likewise.
* c-format.c: Likewise.
* tree-stdarg.c: Likewise.
* tree-ssa-math-opts.c: Likewise.
* tree-ssa-dom.c: Likewise.
* tree-nrv.c: Likewise.
* tree-ssa-propagate.c: Likewise.
* ipa-utils.c: Likewise.
* tree-ssa-propagate.h: Likewise.
* tree-ssa-alias.c: Likewise.
* gimple-low.c: Likewise.
* tree-ssa-sink.c: Likewise.
* ipa-inline.c: Likewise.
* c-semantics.c: Likewise.
* dwarf2out.c: Likewise.
* expr.c: Likewise.
* tree-ssa-loop-ivcanon.c: Likewise.
* predict.c: Likewise.
* tree-ssa-loop.c: Likewise.
* tree-parloops.c: Likewise.
* tree-ssa-address.c: Likewise.
* tree-ssa-ifcombine.c: Likewise.
* matrix-reorg.c: Likewise.
* c-decl.c: Likewise.
* tree-eh.c: Likewise.
* c-pretty-print.c: Likewise.
* lambda-trans.c: Likewise.
* function.c: Likewise.
* langhooks.c: Likewise.
* ebitmap.h: Likewise.
* tree-vectorizer.c: Likewise.
* function.h: Likewise.
* langhooks.h: Likewise.
* tree-vectorizer.h: Likewise.
* ipa-type-escape.c: Likewise.
* ipa-type-escape.h: Likewise.
* domwalk.c: Likewise.
* tree-if-conv.c: Likewise.
* profile.c: Likewise.
* domwalk.h: Likewise.
* tree-data-ref.c: Likewise.
* tree-data-ref.h: Likewise.
* tree-flow-inline.h: Likewise.
* tree-affine.c: Likewise.
* tree-vect-analyze.c: Likewise.
* c-typeck.c: Likewise.
* gimplify.c: Likewise.
* coretypes.h: Likewise.
* tree-ssa-phiopt.c: Likewise.
* calls.c: Likewise.
* tree-ssa-coalesce.c: Likewise.
* tree.def: Likewise.
* tree-dfa.c: Likewise.
* except.c: Likewise.
* except.h: Likewise.
* cfgexpand.c: Likewise.
* tree-cfgcleanup.c: Likewise.
* tree-ssa-pre.c: Likewise.
* tree-ssa-live.c: Likewise.
* tree-sra.c: Likewise.
* tree-ssa-live.h: Likewise.
* tree-predcom.c: Likewise.
* lambda.h: Likewise.
* tree-mudflap.c: Likewise.
* ipa-prop.c: Likewise.
* print-tree.c: Likewise.
* tree-ssa-copy.c: Likewise.
* ipa-prop.h: Likewise.
* tree-ssa-forwprop.c: Likewise.
* ggc-page.c: Likewise.
* c-omp.c: Likewise.
* tree-ssa-dce.c: Likewise.
* tree-vect-patterns.c: Likewise.
* tree-ssa-ter.c: Likewise.
* tree-nested.c: Likewise.
* tree-ssa.c: Likewise.
* lambda-code.c: Likewise.
* tree-ssa-loop-prefetch.c: Likewise.
* tree-inline.c: Likewise.
* tree-inline.h: Likewise.
* tree-iterator.c: Likewise.
* tree-optimize.c: Likewise.
* tree-ssa-phiprop.c: Likewise.
* tree-vect-transform.c: Likewise.
* tree-object-size.c: Likewise.
* tree-outof-ssa.c: Likewise.
* cfgloop.c: Likewise.
* system.h: Likewise.
* tree-profile.c: Likewise.
* cfgloop.h: Likewise.
* c-gimplify.c: Likewise.
* c-common.c: Likewise.
* tree-vect-generic.c: Likewise.
* tree-flow.h: Likewise.
* c-common.h: Likewise.
* basic-block.h: Likewise.
* tree-ssa-structalias.c: Likewise.
* tree-switch-conversion.c: Likewise.
* tree-ssa-structalias.h: Likewise.
* tree-cfg.c: Likewise.
* passes.c: Likewise.
* ipa-struct-reorg.c: Likewise.
* ipa-struct-reorg.h: Likewise.
* tree-ssa-reassoc.c: Likewise.
* cfgrtl.c: Likewise.
* varpool.c: Likewise.
* stmt.c: Likewise.
* tree-ssanames.c: Likewise.
* tree-ssa-threadedge.c: Likewise.
* langhooks-def.h: Likewise.
* tree-ssa-operands.c: Likewise.
* config/alpha/alpha.c: Likewise.
* config/frv/frv.c: Likewise.
* config/s390/s390.c: Likewise.
* config/m32c/m32c.c: Likewise.
* config/m32c/m32c-protos.h: Likewise.
* config/spu/spu.c: Likewise.
* config/sparc/sparc.c: Likewise.
* config/i386/i386.c: Likewise.
* config/sh/sh.c: Likewise.
* config/xtensa/xtensa.c: Likewise.
* config/stormy16/stormy16.c: Likewise.
* config/ia64/ia64.c: Likewise.
* config/rs6000/rs6000.c: Likewise.
* config/pa/pa.c: Likewise.
* config/mips/mips.c: Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@138207 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/gimple-iterator.c')
-rw-r--r-- | gcc/gimple-iterator.c | 771 |
1 files changed, 771 insertions, 0 deletions
diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c new file mode 100644 index 00000000000..a52c83072b4 --- /dev/null +++ b/gcc/gimple-iterator.c @@ -0,0 +1,771 @@ +/* Iterator routines for GIMPLE statements. + Copyright (C) 2007, 2008 Free Software Foundation, Inc. + Contributed by Aldy Hernandez <aldy@quesejoda.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 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "gimple.h" +#include "tree-flow.h" +#include "value-prof.h" + + +/* Mark the statement STMT as modified, and update it. */ + +static inline void +update_modified_stmt (gimple stmt) +{ + if (!ssa_operands_active ()) + return; + update_stmt_if_modified (stmt); +} + + +/* Mark the statements in SEQ as modified, and update them. */ + +static void +update_modified_stmts (gimple_seq seq) +{ + gimple_stmt_iterator gsi; + + if (!ssa_operands_active ()) + return; + for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi)) + update_stmt_if_modified (gsi_stmt (gsi)); +} + + +/* Set BB to be the basic block for all the statements in the list + starting at FIRST and LAST. */ + +static void +update_bb_for_stmts (gimple_seq_node first, basic_block bb) +{ + gimple_seq_node n; + + for (n = first; n; n = n->next) + gimple_set_bb (n->stmt, bb); +} + + +/* Insert the sequence delimited by nodes FIRST and LAST before + iterator I. M specifies how to update iterator I after insertion + (see enum gsi_iterator_update). + + This routine assumes that there is a forward and backward path + between FIRST and LAST (i.e., they are linked in a doubly-linked + list). Additionally, if FIRST == LAST, this routine will properly + insert a single node. */ + +static void +gsi_insert_seq_nodes_before (gimple_stmt_iterator *i, + gimple_seq_node first, + gimple_seq_node last, + enum gsi_iterator_update mode) +{ + basic_block bb; + gimple_seq_node cur = i->ptr; + + if ((bb = gsi_bb (*i)) != NULL) + update_bb_for_stmts (first, bb); + + /* Link SEQ before CUR in the sequence. */ + if (cur) + { + first->prev = cur->prev; + if (first->prev) + first->prev->next = first; + else + gimple_seq_set_first (i->seq, first); + last->next = cur; + cur->prev = last; + } + else + { + gimple_seq_node itlast = gimple_seq_last (i->seq); + + /* If CUR is NULL, we link at the end of the sequence (this case happens + when gsi_after_labels is called for a basic block that contains only + labels, so it returns an iterator after the end of the block, and + we need to insert before it; it might be cleaner to add a flag to the + iterator saying whether we are at the start or end of the list). */ + first->prev = itlast; + if (itlast) + itlast->next = first; + else + gimple_seq_set_first (i->seq, first); + gimple_seq_set_last (i->seq, last); + } + + /* Update the iterator, if requested. */ + switch (mode) + { + case GSI_NEW_STMT: + case GSI_CONTINUE_LINKING: + i->ptr = first; + break; + case GSI_SAME_STMT: + break; + default: + gcc_unreachable (); + } +} + + +/* Inserts the sequence of statements SEQ before the statement pointed + by iterator I. MODE indicates what to do with the iterator after + insertion (see enum gsi_iterator_update). + + This function does not scan for new operands. It is provided for + the use of the gimplifier, which manipulates statements for which + def/use information has not yet been constructed. Most callers + should use gsi_insert_seq_before. */ + +void +gsi_insert_seq_before_without_update (gimple_stmt_iterator *i, gimple_seq seq, + enum gsi_iterator_update mode) +{ + gimple_seq_node first, last; + + if (seq == NULL) + return; + + /* Don't allow inserting a sequence into itself. */ + gcc_assert (seq != i->seq); + + first = gimple_seq_first (seq); + last = gimple_seq_last (seq); + + gimple_seq_set_first (seq, NULL); + gimple_seq_set_last (seq, NULL); + gimple_seq_free (seq); + + /* Empty sequences need no work. */ + if (!first || !last) + { + gcc_assert (first == last); + return; + } + + gsi_insert_seq_nodes_before (i, first, last, mode); +} + + +/* Inserts the sequence of statements SEQ before the statement pointed + by iterator I. MODE indicates what to do with the iterator after + insertion (see enum gsi_iterator_update). Scan the statements in SEQ + for new operands. */ + +void +gsi_insert_seq_before (gimple_stmt_iterator *i, gimple_seq seq, + enum gsi_iterator_update mode) +{ + update_modified_stmts (seq); + gsi_insert_seq_before_without_update (i, seq, mode); +} + + +/* Insert the sequence delimited by nodes FIRST and LAST after + iterator I. M specifies how to update iterator I after insertion + (see enum gsi_iterator_update). + + This routine assumes that there is a forward and backward path + between FIRST and LAST (i.e., they are linked in a doubly-linked + list). Additionally, if FIRST == LAST, this routine will properly + insert a single node. */ + +static void +gsi_insert_seq_nodes_after (gimple_stmt_iterator *i, + gimple_seq_node first, + gimple_seq_node last, + enum gsi_iterator_update m) +{ + basic_block bb; + gimple_seq_node cur = i->ptr; + + /* If the iterator is inside a basic block, we need to update the + basic block information for all the nodes between FIRST and LAST. */ + if ((bb = gsi_bb (*i)) != NULL) + update_bb_for_stmts (first, bb); + + /* Link SEQ after CUR. */ + if (cur) + { + last->next = cur->next; + if (last->next) + last->next->prev = last; + else + gimple_seq_set_last (i->seq, last); + first->prev = cur; + cur->next = first; + } + else + { + gcc_assert (!gimple_seq_last (i->seq)); + gimple_seq_set_first (i->seq, first); + gimple_seq_set_last (i->seq, last); + } + + /* Update the iterator, if requested. */ + switch (m) + { + case GSI_NEW_STMT: + i->ptr = first; + break; + case GSI_CONTINUE_LINKING: + i->ptr = last; + break; + case GSI_SAME_STMT: + gcc_assert (cur); + break; + default: + gcc_unreachable (); + } +} + + +/* Links sequence SEQ after the statement pointed-to by iterator I. + MODE is as in gsi_insert_after. + + This function does not scan for new operands. It is provided for + the use of the gimplifier, which manipulates statements for which + def/use information has not yet been constructed. Most callers + should use gsi_insert_seq_after. */ + +void +gsi_insert_seq_after_without_update (gimple_stmt_iterator *i, gimple_seq seq, + enum gsi_iterator_update mode) +{ + gimple_seq_node first, last; + + if (seq == NULL) + return; + + /* Don't allow inserting a sequence into itself. */ + gcc_assert (seq != i->seq); + + first = gimple_seq_first (seq); + last = gimple_seq_last (seq); + + gimple_seq_set_first (seq, NULL); + gimple_seq_set_last (seq, NULL); + gimple_seq_free (seq); + + /* Empty sequences need no work. */ + if (!first || !last) + { + gcc_assert (first == last); + return; + } + + gsi_insert_seq_nodes_after (i, first, last, mode); +} + + +/* Links sequence SEQ after the statement pointed-to by iterator I. + MODE is as in gsi_insert_after. Scan the statements in SEQ + for new operands. */ + +void +gsi_insert_seq_after (gimple_stmt_iterator *i, gimple_seq seq, + enum gsi_iterator_update mode) +{ + update_modified_stmts (seq); + gsi_insert_seq_after_without_update (i, seq, mode); +} + + +/* Move all statements in the sequence after I to a new sequence. + Return this new sequence. */ + +gimple_seq +gsi_split_seq_after (gimple_stmt_iterator i) +{ + gimple_seq_node cur, next; + gimple_seq old_seq, new_seq; + + cur = i.ptr; + + /* How can we possibly split after the end, or before the beginning? */ + gcc_assert (cur && cur->next); + next = cur->next; + + old_seq = i.seq; + new_seq = gimple_seq_alloc (); + + gimple_seq_set_first (new_seq, next); + gimple_seq_set_last (new_seq, gimple_seq_last (old_seq)); + gimple_seq_set_last (old_seq, cur); + cur->next = NULL; + next->prev = NULL; + + return new_seq; +} + + +/* Move all statements in the sequence before I to a new sequence. + Return this new sequence. I is set to the head of the new list. */ + +gimple_seq +gsi_split_seq_before (gimple_stmt_iterator *i) +{ + gimple_seq_node cur, prev; + gimple_seq old_seq, new_seq; + + cur = i->ptr; + + /* How can we possibly split after the end? */ + gcc_assert (cur); + prev = cur->prev; + + old_seq = i->seq; + new_seq = gimple_seq_alloc (); + i->seq = new_seq; + + /* Set the limits on NEW_SEQ. */ + gimple_seq_set_first (new_seq, cur); + gimple_seq_set_last (new_seq, gimple_seq_last (old_seq)); + + /* Cut OLD_SEQ before I. */ + gimple_seq_set_last (old_seq, prev); + cur->prev = NULL; + if (prev) + prev->next = NULL; + else + gimple_seq_set_first (old_seq, NULL); + + return new_seq; +} + + +/* Replace the statement pointed-to by GSI to STMT. If UPDATE_EH_INFO + is true, the exception handling information of the original + statement is moved to the new statement. */ + +void +gsi_replace (gimple_stmt_iterator *gsi, gimple stmt, bool update_eh_info) +{ + int eh_region; + gimple orig_stmt = gsi_stmt (*gsi); + + if (stmt == orig_stmt) + return; + + gimple_set_location (stmt, gimple_location (orig_stmt)); + gimple_set_bb (stmt, gsi_bb (*gsi)); + + /* Preserve EH region information from the original statement, if + requested by the caller. */ + if (update_eh_info) + { + eh_region = lookup_stmt_eh_region (orig_stmt); + if (eh_region >= 0) + { + remove_stmt_from_eh_region (orig_stmt); + add_stmt_to_eh_region (stmt, eh_region); + } + } + + gimple_duplicate_stmt_histograms (cfun, stmt, cfun, orig_stmt); + gimple_remove_stmt_histograms (cfun, orig_stmt); + delink_stmt_imm_use (orig_stmt); + *gsi_stmt_ptr (gsi) = stmt; + gimple_set_modified (stmt, true); + update_modified_stmt (stmt); +} + + +/* Insert statement STMT before the statement pointed-to by iterator I. + M specifies how to update iterator I after insertion (see enum + gsi_iterator_update). + + This function does not scan for new operands. It is provided for + the use of the gimplifier, which manipulates statements for which + def/use information has not yet been constructed. Most callers + should use gsi_insert_before. */ + +void +gsi_insert_before_without_update (gimple_stmt_iterator *i, gimple stmt, + enum gsi_iterator_update m) +{ + gimple_seq_node n; + + n = GGC_NEW (struct gimple_seq_node_d); + n->prev = n->next = NULL; + n->stmt = stmt; + gsi_insert_seq_nodes_before (i, n, n, m); +} + +/* Insert statement STMT before the statement pointed-to by iterator I. + Update STMT's basic block and scan it for new operands. M + specifies how to update iterator I after insertion (see enum + gsi_iterator_update). */ + +void +gsi_insert_before (gimple_stmt_iterator *i, gimple stmt, + enum gsi_iterator_update m) +{ + update_modified_stmt (stmt); + gsi_insert_before_without_update (i, stmt, m); +} + + +/* Insert statement STMT after the statement pointed-to by iterator I. + M specifies how to update iterator I after insertion (see enum + gsi_iterator_update). + + This function does not scan for new operands. It is provided for + the use of the gimplifier, which manipulates statements for which + def/use information has not yet been constructed. Most callers + should use gsi_insert_after. */ + +void +gsi_insert_after_without_update (gimple_stmt_iterator *i, gimple stmt, + enum gsi_iterator_update m) +{ + gimple_seq_node n; + + n = GGC_NEW (struct gimple_seq_node_d); + n->prev = n->next = NULL; + n->stmt = stmt; + gsi_insert_seq_nodes_after (i, n, n, m); +} + + +/* Insert statement STMT after the statement pointed-to by iterator I. + Update STMT's basic block and scan it for new operands. M + specifies how to update iterator I after insertion (see enum + gsi_iterator_update). */ + +void +gsi_insert_after (gimple_stmt_iterator *i, gimple stmt, + enum gsi_iterator_update m) +{ + update_modified_stmt (stmt); + gsi_insert_after_without_update (i, stmt, m); +} + + +/* Remove the current stmt from the sequence. The iterator is updated + to point to the next statement. + + REMOVE_PERMANENTLY is true when the statement is going to be removed + from the IL and not reinserted elsewhere. In that case we remove the + statement pointed to by iterator I from the EH tables, and free its + operand caches. Otherwise we do not modify this information. */ + +void +gsi_remove (gimple_stmt_iterator *i, bool remove_permanently) +{ + gimple_seq_node cur, next, prev; + gimple stmt = gsi_stmt (*i); + + /* Free all the data flow information for STMT. */ + gimple_set_bb (stmt, NULL); + delink_stmt_imm_use (stmt); + gimple_set_modified (stmt, true); + + if (remove_permanently) + { + remove_stmt_from_eh_region (stmt); + gimple_remove_stmt_histograms (cfun, stmt); + } + + /* Update the iterator and re-wire the links in I->SEQ. */ + cur = i->ptr; + next = cur->next; + prev = cur->prev; + + if (prev) + prev->next = next; + else + gimple_seq_set_first (i->seq, next); + + if (next) + next->prev = prev; + else + gimple_seq_set_last (i->seq, prev); + + i->ptr = next; +} + + +/* Finds iterator for STMT. */ + +gimple_stmt_iterator +gsi_for_stmt (gimple stmt) +{ + gimple_stmt_iterator i; + basic_block bb = gimple_bb (stmt); + + if (gimple_code (stmt) == GIMPLE_PHI) + i = gsi_start_phis (bb); + else + i = gsi_start_bb (bb); + + for (; !gsi_end_p (i); gsi_next (&i)) + if (gsi_stmt (i) == stmt) + return i; + + gcc_unreachable (); +} + + +/* Move the statement at FROM so it comes right after the statement at TO. */ + +void +gsi_move_after (gimple_stmt_iterator *from, gimple_stmt_iterator *to) +{ + gimple stmt = gsi_stmt (*from); + gsi_remove (from, false); + + /* We must have GSI_NEW_STMT here, as gsi_move_after is sometimes used to + move statements to an empty block. */ + gsi_insert_after (to, stmt, GSI_NEW_STMT); +} + + +/* Move the statement at FROM so it comes right before the statement + at TO. */ + +void +gsi_move_before (gimple_stmt_iterator *from, gimple_stmt_iterator *to) +{ + gimple stmt = gsi_stmt (*from); + gsi_remove (from, false); + + /* For consistency with gsi_move_after, it might be better to have + GSI_NEW_STMT here; however, that breaks several places that expect + that TO does not change. */ + gsi_insert_before (to, stmt, GSI_SAME_STMT); +} + + +/* Move the statement at FROM to the end of basic block BB. */ + +void +gsi_move_to_bb_end (gimple_stmt_iterator *from, basic_block bb) +{ + gimple_stmt_iterator last = gsi_last_bb (bb); +#ifdef ENABLE_CHECKING + gcc_assert (gsi_bb (last) == bb); +#endif + + /* Have to check gsi_end_p because it could be an empty block. */ + if (!gsi_end_p (last) && is_ctrl_stmt (gsi_stmt (last))) + gsi_move_before (from, &last); + else + gsi_move_after (from, &last); +} + + +/* Add STMT to the pending list of edge E. No actual insertion is + made until a call to gsi_commit_edge_inserts () is made. */ + +void +gsi_insert_on_edge (edge e, gimple stmt) +{ + gimple_seq_add_stmt (&PENDING_STMT (e), stmt); +} + +/* Add the sequence of statements SEQ to the pending list of edge E. + No actual insertion is made until a call to gsi_commit_edge_inserts + is made. */ + +void +gsi_insert_seq_on_edge (edge e, gimple_seq seq) +{ + gimple_seq_add_seq (&PENDING_STMT (e), seq); +} + + +/* Insert the statement pointed-to by GSI into edge E. Every attempt + is made to place the statement in an existing basic block, but + sometimes that isn't possible. When it isn't possible, the edge is + split and the statement is added to the new block. + + In all cases, the returned *GSI points to the correct location. The + return value is true if insertion should be done after the location, + or false if it should be done before the location. If new basic block + has to be created, it is stored in *NEW_BB. */ + +static bool +gimple_find_edge_insert_loc (edge e, gimple_stmt_iterator *gsi, + basic_block *new_bb) +{ + basic_block dest, src; + gimple tmp; + + dest = e->dest; + + /* If the destination has one predecessor which has no PHI nodes, + insert there. Except for the exit block. + + The requirement for no PHI nodes could be relaxed. Basically we + would have to examine the PHIs to prove that none of them used + the value set by the statement we want to insert on E. That + hardly seems worth the effort. */ +restart: + if (single_pred_p (dest) + && ! phi_nodes (dest) + && dest != EXIT_BLOCK_PTR) + { + *gsi = gsi_start_bb (dest); + if (gsi_end_p (*gsi)) + return true; + + /* Make sure we insert after any leading labels. */ + tmp = gsi_stmt (*gsi); + while (gimple_code (tmp) == GIMPLE_LABEL) + { + gsi_next (gsi); + if (gsi_end_p (*gsi)) + break; + tmp = gsi_stmt (*gsi); + } + + if (gsi_end_p (*gsi)) + { + *gsi = gsi_last_bb (dest); + return true; + } + else + return false; + } + + /* If the source has one successor, the edge is not abnormal and + the last statement does not end a basic block, insert there. + Except for the entry block. */ + src = e->src; + if ((e->flags & EDGE_ABNORMAL) == 0 + && single_succ_p (src) + && src != ENTRY_BLOCK_PTR) + { + *gsi = gsi_last_bb (src); + if (gsi_end_p (*gsi)) + return true; + + tmp = gsi_stmt (*gsi); + if (!stmt_ends_bb_p (tmp)) + return true; + + if (gimple_code (tmp) == GIMPLE_RETURN) + { + gsi_prev (gsi); + return true; + } + } + + /* Otherwise, create a new basic block, and split this edge. */ + dest = split_edge (e); + if (new_bb) + *new_bb = dest; + e = single_pred_edge (dest); + goto restart; +} + + +/* Similar to gsi_insert_on_edge+gsi_commit_edge_inserts. If a new + block has to be created, it is returned. */ + +basic_block +gsi_insert_on_edge_immediate (edge e, gimple stmt) +{ + gimple_stmt_iterator gsi; + basic_block new_bb = NULL; + + gcc_assert (!PENDING_STMT (e)); + + if (gimple_find_edge_insert_loc (e, &gsi, &new_bb)) + gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); + else + gsi_insert_before (&gsi, stmt, GSI_NEW_STMT); + + return new_bb; +} + +/* Insert STMTS on edge E. If a new block has to be created, it + is returned. */ + +basic_block +gsi_insert_seq_on_edge_immediate (edge e, gimple_seq stmts) +{ + gimple_stmt_iterator gsi; + basic_block new_bb = NULL; + + gcc_assert (!PENDING_STMT (e)); + + if (gimple_find_edge_insert_loc (e, &gsi, &new_bb)) + gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT); + else + gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT); + + return new_bb; +} + +/* This routine will commit all pending edge insertions, creating any new + basic blocks which are necessary. */ + +void +gsi_commit_edge_inserts (void) +{ + basic_block bb; + edge e; + edge_iterator ei; + + gsi_commit_one_edge_insert (single_succ_edge (ENTRY_BLOCK_PTR), NULL); + + FOR_EACH_BB (bb) + FOR_EACH_EDGE (e, ei, bb->succs) + gsi_commit_one_edge_insert (e, NULL); +} + + +/* Commit insertions pending at edge E. If a new block is created, set NEW_BB + to this block, otherwise set it to NULL. */ + +void +gsi_commit_one_edge_insert (edge e, basic_block *new_bb) +{ + if (new_bb) + *new_bb = NULL; + + if (PENDING_STMT (e)) + { + gimple_stmt_iterator gsi; + gimple_seq seq = PENDING_STMT (e); + + PENDING_STMT (e) = NULL; + + if (gimple_find_edge_insert_loc (e, &gsi, new_bb)) + gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT); + else + gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT); + } +} + +/* Returns iterator at the start of the list of phi nodes of BB. */ + +gimple_stmt_iterator +gsi_start_phis (basic_block bb) +{ + return gsi_start (phi_nodes (bb)); +} |