From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15518 invoked by alias); 13 Apr 2009 20:50:05 -0000 Received: (qmail 15435 invoked by uid 22791); 13 Apr 2009 20:49:57 -0000 X-SWARE-Spam-Status: No, hits=-4.4 required=5.0 tests=AWL,BAYES_50,J_CHICKENPOX_33,J_CHICKENPOX_34,J_CHICKENPOX_48,J_CHICKENPOX_73,RCVD_IN_DNSWL_HI X-Spam-Check-By: sourceware.org Received: from cantor.suse.de (HELO mx1.suse.de) (195.135.220.2) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 13 Apr 2009 20:49:45 +0000 Received: from Relay2.suse.de (relay-ext.suse.de [195.135.221.8]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.suse.de (Postfix) with ESMTP id 6C30C5362F for ; Mon, 13 Apr 2009 22:49:41 +0200 (CEST) Date: Mon, 13 Apr 2009 20:50:00 -0000 From: Michael Matz To: gcc-patches@gcc.gnu.org Subject: RFC: expand from SSA form (1/2) Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2009-04/txt/msg00931.txt.bz2 Hi, This patch implements expanding directly from SSA form, i.e. without first going out and producing GENERIC. It doesn't yet get rid of explicitely building trees instead of expanding GIMPLE directly, that's for somewhen later. But it does make passing information from tree-ssa land into RTL land somewhat easier already (the obvious candidates are debug information because we don't generate new decls and alias info). This first patch actually implements the whole thing, the second patch cleans up all the cruft ("if (0)", dead functions and the like). I've separated them to not clutter the important parts with the deletions. Anyway, here is how it works: (1) in SSA form: create and coalesce partitions, as before, but don't rewrite anything. Pass this info to cfgexpand.c. (2) cfgexpand.c: allocate some space (in pseudos or stack) for each partition not containing a default def (these are the ones corresponding to VAR_DECLs). Set interesting attributes for that RTX according to the underlying SSA_NAME_VAR. I.e. we don't have to create artificial abc.24 variables for secondary partition. (3) cfgexpand.c: setup argument RTXs (4) all partitions not yet having some RTL will now get the one from the underlying SSA_NAME_VAR (these are the ones containing a default def, corresponding to PARM_DECLs) Now all partitions have some allocated space, which we're going to use later in expr.c when we expand SSA_NAMEs (each SSA name belongs to a partition, if it's used anywhere in program text). (5) RTL cfg hooks are activated. Note that basic blocks still are in gimple SSA form, and we still have PHI nodes. (6) tree-outof-ssa.c: expand all phi nodes. This is similar to before, just that we aren't emitting gimple instructions, but already real RTL insns, on the edges. Yep, on the edges we have RTL insns, while in the basic blocks we still have gimple. Which also means we can't yet commit the insns on edges. (7) all basic blocks are expanded like before (i.e. constructing trees of gimple, expanding those one by one, when we see an SSA_NAME we use the RTX expressions from above) Now we have only RTL insns in BBs and edges. Some basic block are expanded to contain multiple jumps, so they really are super blocks. (8) commit all insns from edges. This possibly means splitting edges, which needs redirecting edges, which is a problem when the source block is really a super block. Redirecting edges in RTL land rewrites the jump insn label. As we might have multiple jumps in one super block we need to look into all of them. I explicitely don't want to split all critical edges before expanding. We're basically done now. (9) cleanup data structures (which formerly were passes in their own right), ensure some invariantes in RTL land (no EDGE_EXECUTABLE for instance) and the like. For the necessary interaction between outof-ssa, cfgexpand and expand itself I've created a new header containing the necessary info (the coalesced partitions, plus space for their RTL expressions and some accessors to those). TER is still supported and implemented by deferring expanding an assignment that is TERed to the place where it's actually used. That's a change from before: we don't insert the tree of the RHS directly into the tree that is going to be expanded. The attempt to optimize placement of instructions on edges (process_single_block_loop_latch, analyze_edges_for_bb) isn't reimplemented for now. Currently it's implemented by scanning the gimple instructions looking for common sequences, which is more difficult in RTL land as one move can possibly be emitted as multiple insns. This commonizing should IMO be implemented somewhere else, namely as preconditioning pass before un-SSA. The process_single_block_loop_latch hack needs to be moved somewhere else too, which I'd also like to do later. I've also changed out-of-ssa to mostly work only with partition numbers instead of partition variables (those are removed in the cleanup pass). We also don't need to must-coalesce default defs with base variables or in fact change the variables per partition in any way at all (i.e. a partition always corresponds to exactly one SSA name, whose version is the partition number). As out-of-ssa and expand are now basically one pass there can't be any passes working on non-SSA trees anymore. Currently that's only two passes: tree-nrv, which is easily fixed, and mudflap, which I deactivated for now. This patch (and this one plus the cleanup patch) bootstrap fine one x86_64-linux. Regtesting shows only expected problems (in particular no execute.exp fails), namely fallout from deactivating mudflap and fallout because there's no .optimized treedump anymore. I haven't yet checked the performance impact on SPEC or the like. Neither did I check in detail memory use (i.e. if the cleanups indeed did cleanup all unnecessary memory). But I'm interested in any comments you might have. In particular I'm not exceptionally fond of the four insert_*_on_edge() routines, though we indeed need four signatures: partition to partition, tree to partition, rtx to partition and partition to rtx. No ChangeLog yet. Ciao, Michael. -- Index: builtins.c =================================================================== *** builtins.c.orig --- builtins.c *************** expand_builtin (tree exp, rtx target, rt *** 6237,6242 **** --- 6237,6244 ---- enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp)); + if (mode == VOIDmode) + mode = target_mode; if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) return targetm.expand_builtin (exp, target, subtarget, mode, ignore); Index: tree-nrv.c =================================================================== *** tree-nrv.c.orig --- tree-nrv.c *************** struct nrv_data *** 56,61 **** --- 56,62 ---- /* This is the function's RESULT_DECL. We will replace all occurrences of VAR with RESULT_DECL when we apply this optimization. */ tree result; + int modified; }; static tree finalize_nrv_r (tree *, int *, void *); *************** finalize_nrv_r (tree *tp, int *walk_subt *** 83,89 **** /* Otherwise replace all occurrences of VAR with RESULT. */ else if (*tp == dp->var) ! *tp = dp->result; /* Keep iterating. */ return NULL_TREE; --- 84,90 ---- /* Otherwise replace all occurrences of VAR with RESULT. */ else if (*tp == dp->var) ! *tp = dp->result, dp->modified = 1; /* Keep iterating. */ return NULL_TREE; *************** tree_nrv (void) *** 110,115 **** --- 111,117 ---- basic_block bb; gimple_stmt_iterator gsi; struct nrv_data data; + int any_modified = 0; /* If this function does not return an aggregate type in memory, then there is nothing to do. */ *************** tree_nrv (void) *** 235,241 **** --- 237,246 ---- struct walk_stmt_info wi; memset (&wi, 0, sizeof (wi)); wi.info = &data; + data.modified = 0; walk_gimple_op (stmt, finalize_nrv_r, &wi); + if (data.modified) + update_stmt (stmt), any_modified = 1; gsi_next (&gsi); } } *************** tree_nrv (void) *** 243,248 **** --- 248,258 ---- /* FOUND is no longer used. Ensure it gets removed. */ var_ann (found)->used = 0; + if (any_modified) + { + mark_sym_for_renaming (gimple_vop (cfun)); + return TODO_update_ssa; + } return 0; } *************** struct gimple_opt_pass pass_nrv = *** 263,269 **** NULL, /* next */ 0, /* static_pass_number */ TV_TREE_NRV, /* tv_id */ ! PROP_cfg, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ --- 273,279 ---- NULL, /* next */ 0, /* static_pass_number */ TV_TREE_NRV, /* tv_id */ ! PROP_ssa | PROP_cfg, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ Index: expr.c =================================================================== *** expr.c.orig --- expr.c *************** along with GCC; see the file COPYING3. *** 54,59 **** --- 54,60 ---- #include "timevar.h" #include "df.h" #include "diagnostic.h" + #include "ssaexpand.h" /* Decide whether a function's arguments should be processed from first to last or from last to first. *************** expand_expr_real_1 (tree exp, rtx target *** 7244,7251 **** } case SSA_NAME: ! return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier, ! NULL); case PARM_DECL: case VAR_DECL: --- 7245,7265 ---- } case SSA_NAME: ! /* ??? ivopts calls expander, without any preparation from ! out-of-ssa. So fake instructions as if this was an access to the ! base variable. This unnecessarily allocates a pseudo, see how we can ! reuse it, if partition base vars have it set already. */ ! if (!currently_expanding_to_rtl) ! return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier, NULL); ! { ! gimple g = get_gimple_for_ssa_name (exp); ! if (g) ! return expand_expr_real_1 (gimple_assign_rhs_to_tree (g), target, ! tmode, modifier, NULL); ! } ! decl_rtl = get_rtx_for_ssa_name (exp); ! exp = SSA_NAME_VAR (exp); ! goto expand_decl_rtl; case PARM_DECL: case VAR_DECL: *************** expand_expr_real_1 (tree exp, rtx target *** 7271,7276 **** --- 7285,7291 ---- case FUNCTION_DECL: case RESULT_DECL: decl_rtl = DECL_RTL (exp); + expand_decl_rtl: gcc_assert (decl_rtl); decl_rtl = copy_rtx (decl_rtl); Index: emit-rtl.c =================================================================== *** emit-rtl.c.orig --- emit-rtl.c *************** set_reg_attrs_for_parm (rtx parm_rtx, rt *** 1028,1034 **** /* Set the REG_ATTRS for registers in value X, given that X represents decl T. */ ! static void set_reg_attrs_for_decl_rtl (tree t, rtx x) { if (GET_CODE (x) == SUBREG) --- 1028,1034 ---- /* Set the REG_ATTRS for registers in value X, given that X represents decl T. */ ! void set_reg_attrs_for_decl_rtl (tree t, rtx x) { if (GET_CODE (x) == SUBREG) Index: cfgexpand.c =================================================================== *** cfgexpand.c.orig --- cfgexpand.c *************** along with GCC; see the file COPYING3. *** 42,49 **** --- 42,54 ---- #include "tree-inline.h" #include "value-prof.h" #include "target.h" + #include "ssaexpand.h" + /* This variable holds information helping the rewriting of SSA trees + into RTL. */ + struct ssaexpand SA; + /* Return an expression tree corresponding to the RHS of GIMPLE statement STMT. */ *************** failed: *** 423,428 **** --- 428,447 ---- #define STACK_ALIGNMENT_NEEDED 1 #endif + #define SSAVAR(x) (TREE_CODE (x) == SSA_NAME ? SSA_NAME_VAR (x) : x) + + static inline void + set_rtl (tree t, rtx x) + { + if (TREE_CODE (t) == SSA_NAME) + { + SA.partition_to_pseudo[var_to_partition (SA.map, t)] = x; + if (x && !MEM_P (x)) + set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (t), x); + } + else + SET_DECL_RTL (t, x); + } /* This structure holds data relevant to one variable that will be placed in a stack slot. */ *************** add_stack_var (tree decl) *** 561,575 **** } stack_vars[stack_vars_num].decl = decl; stack_vars[stack_vars_num].offset = 0; ! stack_vars[stack_vars_num].size = tree_low_cst (DECL_SIZE_UNIT (decl), 1); ! stack_vars[stack_vars_num].alignb = get_decl_align_unit (decl); /* All variables are initially in their own partition. */ stack_vars[stack_vars_num].representative = stack_vars_num; stack_vars[stack_vars_num].next = EOC; /* Ensure that this decl doesn't get put onto the list twice. */ ! SET_DECL_RTL (decl, pc_rtx); stack_vars_num++; } --- 580,594 ---- } stack_vars[stack_vars_num].decl = decl; stack_vars[stack_vars_num].offset = 0; ! stack_vars[stack_vars_num].size = tree_low_cst (DECL_SIZE_UNIT (SSAVAR (decl)), 1); ! stack_vars[stack_vars_num].alignb = get_decl_align_unit (SSAVAR (decl)); /* All variables are initially in their own partition. */ stack_vars[stack_vars_num].representative = stack_vars_num; stack_vars[stack_vars_num].next = EOC; /* Ensure that this decl doesn't get put onto the list twice. */ ! set_rtl (decl, pc_rtx); stack_vars_num++; } *************** add_alias_set_conflicts (void) *** 688,709 **** } /* A subroutine of partition_stack_vars. A comparison function for qsort, ! sorting an array of indices by the size of the object. */ static int stack_var_size_cmp (const void *a, const void *b) { HOST_WIDE_INT sa = stack_vars[*(const size_t *)a].size; HOST_WIDE_INT sb = stack_vars[*(const size_t *)b].size; ! unsigned int uida = DECL_UID (stack_vars[*(const size_t *)a].decl); ! unsigned int uidb = DECL_UID (stack_vars[*(const size_t *)b].decl); if (sa < sb) return -1; if (sa > sb) return 1; ! /* For stack variables of the same size use the uid of the decl ! to make the sort stable. */ if (uida < uidb) return -1; if (uida > uidb) --- 707,743 ---- } /* A subroutine of partition_stack_vars. A comparison function for qsort, ! sorting an array of indices by the size and type of the object. */ static int stack_var_size_cmp (const void *a, const void *b) { HOST_WIDE_INT sa = stack_vars[*(const size_t *)a].size; HOST_WIDE_INT sb = stack_vars[*(const size_t *)b].size; ! tree decla, declb; ! unsigned int uida, uidb; if (sa < sb) return -1; if (sa > sb) return 1; ! decla = stack_vars[*(const size_t *)a].decl; ! declb = stack_vars[*(const size_t *)b].decl; ! /* For stack variables of the same size use and id of the decls ! to make the sort stable. Two SSA names are compared by their ! version, SSA names come before non-SSA names, and two normal ! decls are compared by their DECL_UID. */ ! if (TREE_CODE (decla) == SSA_NAME) ! { ! if (TREE_CODE (declb) == SSA_NAME) ! uida = SSA_NAME_VERSION (decla), uidb = SSA_NAME_VERSION (declb); ! else ! return -1; ! } ! else if (TREE_CODE (declb) == SSA_NAME) ! return 1; ! else ! uida = DECL_UID (decla), uidb = DECL_UID (declb); if (uida < uidb) return -1; if (uida > uidb) *************** expand_one_stack_var_at (tree decl, HOST *** 874,894 **** gcc_assert (offset == trunc_int_for_mode (offset, Pmode)); x = plus_constant (virtual_stack_vars_rtx, offset); ! x = gen_rtx_MEM (DECL_MODE (decl), x); ! /* Set alignment we actually gave this decl. */ ! offset -= frame_phase; ! align = offset & -offset; ! align *= BITS_PER_UNIT; ! if (align == 0) ! align = STACK_BOUNDARY; ! else if (align > MAX_SUPPORTED_STACK_ALIGNMENT) ! align = MAX_SUPPORTED_STACK_ALIGNMENT; ! DECL_ALIGN (decl) = align; ! DECL_USER_ALIGN (decl) = 0; ! set_mem_attributes (x, decl, true); ! SET_DECL_RTL (decl, x); } /* A subroutine of expand_used_vars. Give each partition representative --- 908,934 ---- gcc_assert (offset == trunc_int_for_mode (offset, Pmode)); x = plus_constant (virtual_stack_vars_rtx, offset); ! x = gen_rtx_MEM (DECL_MODE (SSAVAR (decl)), x); ! if (TREE_CODE (decl) != SSA_NAME) ! { ! /* Set alignment we actually gave this decl if it isn't an SSA name. ! If it is we generate stack slots only accidentally so it isn't as ! important, we'll simply use the alignment that is already set. */ ! offset -= frame_phase; ! align = offset & -offset; ! align *= BITS_PER_UNIT; ! if (align == 0) ! align = STACK_BOUNDARY; ! else if (align > MAX_SUPPORTED_STACK_ALIGNMENT) ! align = MAX_SUPPORTED_STACK_ALIGNMENT; ! ! DECL_ALIGN (decl) = align; ! DECL_USER_ALIGN (decl) = 0; ! } ! set_mem_attributes (x, SSAVAR (decl), true); ! set_rtl (decl, x); } /* A subroutine of expand_used_vars. Give each partition representative *************** expand_stack_vars (bool (*pred) (tree)) *** 912,918 **** /* Skip variables that have already had rtl assigned. See also add_stack_var where we perpetrate this pc_rtx hack. */ ! if (DECL_RTL (stack_vars[i].decl) != pc_rtx) continue; /* Check the predicate to see whether this variable should be --- 952,960 ---- /* Skip variables that have already had rtl assigned. See also add_stack_var where we perpetrate this pc_rtx hack. */ ! if ((TREE_CODE (stack_vars[i].decl) == SSA_NAME ! ? SA.partition_to_pseudo[var_to_partition (SA.map, stack_vars[i].decl)] ! : DECL_RTL (stack_vars[i].decl)) != pc_rtx) continue; /* Check the predicate to see whether this variable should be *************** account_stack_vars (void) *** 951,957 **** size += stack_vars[i].size; for (j = i; j != EOC; j = stack_vars[j].next) ! SET_DECL_RTL (stack_vars[j].decl, NULL); } return size; } --- 993,999 ---- size += stack_vars[i].size; for (j = i; j != EOC; j = stack_vars[j].next) ! set_rtl (stack_vars[j].decl, NULL); } return size; } *************** expand_one_stack_var (tree var) *** 964,971 **** { HOST_WIDE_INT size, offset, align; ! size = tree_low_cst (DECL_SIZE_UNIT (var), 1); ! align = get_decl_align_unit (var); offset = alloc_stack_frame_space (size, align); expand_one_stack_var_at (var, offset); --- 1006,1013 ---- { HOST_WIDE_INT size, offset, align; ! size = tree_low_cst (DECL_SIZE_UNIT (SSAVAR (var)), 1); ! align = get_decl_align_unit (SSAVAR (var)); offset = alloc_stack_frame_space (size, align); expand_one_stack_var_at (var, offset); *************** expand_one_hard_reg_var (tree var) *** 986,1005 **** static void expand_one_register_var (tree var) { ! tree type = TREE_TYPE (var); int unsignedp = TYPE_UNSIGNED (type); enum machine_mode reg_mode ! = promote_mode (type, DECL_MODE (var), &unsignedp, 0); rtx x = gen_reg_rtx (reg_mode); ! SET_DECL_RTL (var, x); /* Note if the object is a user variable. */ ! if (!DECL_ARTIFICIAL (var)) ! mark_user_reg (x); if (POINTER_TYPE_P (type)) ! mark_reg_pointer (x, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (var)))); } /* A subroutine of expand_one_var. Called to assign rtl to a VAR_DECL that --- 1028,1048 ---- static void expand_one_register_var (tree var) { ! tree decl = SSAVAR (var); ! tree type = TREE_TYPE (decl); int unsignedp = TYPE_UNSIGNED (type); enum machine_mode reg_mode ! = promote_mode (type, DECL_MODE (decl), &unsignedp, 0); rtx x = gen_reg_rtx (reg_mode); ! set_rtl (var, x); /* Note if the object is a user variable. */ ! if (!DECL_ARTIFICIAL (decl)) ! mark_user_reg (x); if (POINTER_TYPE_P (type)) ! mark_reg_pointer (x, TYPE_ALIGN (TREE_TYPE (type))); } /* A subroutine of expand_one_var. Called to assign rtl to a VAR_DECL that *************** defer_stack_allocation (tree var, bool t *** 1067,1072 **** --- 1110,1119 ---- static HOST_WIDE_INT expand_one_var (tree var, bool toplevel, bool really_expand) { + tree origvar = var; + if (TREE_CODE (var) == SSA_NAME) + var = SSA_NAME_VAR (var); + if (SUPPORTS_STACK_ALIGNMENT && TREE_TYPE (var) != error_mark_node && TREE_CODE (var) == VAR_DECL) *************** expand_one_var (tree var, bool toplevel, *** 1092,1098 **** } } ! if (TREE_CODE (var) != VAR_DECL) ; else if (DECL_EXTERNAL (var)) ; --- 1139,1156 ---- } } ! if (TREE_CODE (origvar) == SSA_NAME) ! { ! gcc_assert (TREE_CODE (var) != VAR_DECL ! || (!DECL_EXTERNAL (var) ! && !DECL_HAS_VALUE_EXPR_P (var) ! && !TREE_STATIC (var) ! && !DECL_RTL_SET_P (var) ! && TREE_TYPE (var) != error_mark_node ! && !DECL_HARD_REGISTER (var) ! && really_expand)); ! } ! if (TREE_CODE (var) != VAR_DECL && TREE_CODE (origvar) != SSA_NAME) ; else if (DECL_EXTERNAL (var)) ; *************** expand_one_var (tree var, bool toplevel, *** 1107,1113 **** if (really_expand) expand_one_error_var (var); } ! else if (DECL_HARD_REGISTER (var)) { if (really_expand) expand_one_hard_reg_var (var); --- 1165,1171 ---- if (really_expand) expand_one_error_var (var); } ! else if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var)) { if (really_expand) expand_one_hard_reg_var (var); *************** expand_one_var (tree var, bool toplevel, *** 1115,1128 **** else if (use_register_for_decl (var)) { if (really_expand) ! expand_one_register_var (var); } else if (defer_stack_allocation (var, toplevel)) ! add_stack_var (var); else { if (really_expand) ! expand_one_stack_var (var); return tree_low_cst (DECL_SIZE_UNIT (var), 1); } return 0; --- 1173,1186 ---- else if (use_register_for_decl (var)) { if (really_expand) ! expand_one_register_var (origvar); } else if (defer_stack_allocation (var, toplevel)) ! add_stack_var (origvar); else { if (really_expand) ! expand_one_stack_var (origvar); return tree_low_cst (DECL_SIZE_UNIT (var), 1); } return 0; *************** static void *** 1441,1446 **** --- 1499,1505 ---- expand_used_vars (void) { tree t, next, outer_block = DECL_INITIAL (current_function_decl); + unsigned i; /* Compute the phase of the stack frame for this function. */ { *************** expand_used_vars (void) *** 1451,1456 **** --- 1510,1557 ---- init_vars_expansion (); + for (i = 0; i < SA.map->num_partitions; i++) + { + tree var = partition_to_var (SA.map, i); + + if (TREE_CODE (var) == SSA_NAME) + var = SSA_NAME_VAR (var); + gcc_assert (is_gimple_reg (var)); + if (TREE_CODE (var) == VAR_DECL) + expand_one_var (partition_to_var (SA.map, i), true, true); + else + { + /* This is a PARM_DECL or RESULT_DECL. For those partitions that + contain the default def (representing the parm or result itself) + we don't do anything here. But those which don't contain the + default def (representing a temporary based on the parm/result) + we need to allocate space just like for normal VAR_DECLs. */ + int j = i; + struct partition_elem *start, *elem; + int has_default = 0; + if (SA.map->view_to_partition) + j = SA.map->view_to_partition[j]; + j = partition_find (SA.map->var_partition, j); + start = elem = SA.map->var_partition->elements + j; + do + { + j = elem - SA.map->var_partition->elements; + elem = elem->next; + if (SSA_NAME_IS_DEFAULT_DEF (ssa_name (j))) + { + has_default = 1; + break; + } + } + while (elem != start); + if (!has_default) + { + expand_one_var (partition_to_var (SA.map, i), true, true); + gcc_assert (SA.partition_to_pseudo[i]); + } + } + } + /* At this point all variables on the local_decls with TREE_USED set are not associated with any block scope. Lay them out. */ t = cfun->local_decls; *************** expand_used_vars (void) *** 1462,1473 **** next = TREE_CHAIN (t); /* We didn't set a block for static or extern because it's hard to tell the difference between a global variable (re)declared in a local scope, and one that's really declared there to begin with. And it doesn't really matter much, since we're not giving them stack space. Expand them now. */ ! if (TREE_STATIC (var) || DECL_EXTERNAL (var)) expand_now = true; /* Any variable that could have been hoisted into an SSA_NAME --- 1563,1577 ---- next = TREE_CHAIN (t); + /* Expanded above already. */ + if (is_gimple_reg (var)) + ; /* We didn't set a block for static or extern because it's hard to tell the difference between a global variable (re)declared in a local scope, and one that's really declared there to begin with. And it doesn't really matter much, since we're not giving them stack space. Expand them now. */ ! else if (TREE_STATIC (var) || DECL_EXTERNAL (var)) expand_now = true; /* Any variable that could have been hoisted into an SSA_NAME *************** expand_gimple_cond (basic_block bb, gimp *** 1722,1727 **** --- 1826,1832 ---- if (BARRIER_P (BB_END (new_bb))) BB_END (new_bb) = PREV_INSN (BB_END (new_bb)); update_bb_for_insn (new_bb); + gcc_assert ((dest->flags & BB_RTL) || gimple_seq_empty_p (phi_nodes (dest))); maybe_dump_rtl_for_gimple_stmt (stmt, last2); *************** expand_gimple_basic_block (basic_block b *** 1854,1859 **** --- 1959,1965 ---- { gimple_stmt_iterator gsi; gimple_seq stmts; + gimple_seq phis; gimple stmt = NULL; rtx note, last; edge e; *************** expand_gimple_basic_block (basic_block b *** 1869,1874 **** --- 1975,1981 ---- block to be in GIMPLE, instead of RTL. Therefore, we need to access the BB sequence directly. */ stmts = bb_seq (bb); + phis = phi_nodes (bb); bb->il.gimple = NULL; rtl_profile_for_bb (bb); init_rtl_bb_info (bb); *************** expand_gimple_basic_block (basic_block b *** 1932,1951 **** NOTE_BASIC_BLOCK (note) = bb; - for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) - { - /* Clear EDGE_EXECUTABLE. This flag is never used in the backend. */ - e->flags &= ~EDGE_EXECUTABLE; - - /* At the moment not all abnormal edges match the RTL representation. - It is safe to remove them here as find_many_sub_basic_blocks will - rediscover them. In the future we should get this fixed properly. */ - if (e->flags & EDGE_ABNORMAL) - remove_edge (e); - else - ei_next (&ei); - } - for (; !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); --- 2039,2044 ---- *************** expand_gimple_basic_block (basic_block b *** 1975,1981 **** } else if (gimple_code (stmt) != GIMPLE_CHANGE_DYNAMIC_TYPE) { ! tree stmt_tree = gimple_to_tree (stmt); last = get_last_insn (); expand_expr_stmt (stmt_tree); maybe_dump_rtl_for_gimple_stmt (stmt, last); --- 2068,2086 ---- } else if (gimple_code (stmt) != GIMPLE_CHANGE_DYNAMIC_TYPE) { ! def_operand_p def_p; ! tree stmt_tree; ! def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF); ! ! if (def_p != NULL) ! { ! /* Mark this stmt for removal if it is the list of replaceable ! expressions. */ ! if (SA.values ! && SA.values[SSA_NAME_VERSION (DEF_FROM_PTR (def_p))]) ! continue; ! } ! stmt_tree = gimple_to_tree (stmt); last = get_last_insn (); expand_expr_stmt (stmt_tree); maybe_dump_rtl_for_gimple_stmt (stmt, last); *************** construct_init_block (void) *** 2058,2063 **** --- 2163,2170 ---- first_block = e->dest; redirect_edge_succ (e, init_block); e = make_edge (init_block, first_block, flags); + gcc_assert ((first_block->flags & BB_RTL) + || gimple_seq_empty_p (phi_nodes (first_block))); } else e = make_edge (init_block, EXIT_BLOCK_PTR, EDGE_FALLTHRU); *************** gimple_expand_cfg (void) *** 2286,2291 **** --- 2393,2406 ---- sbitmap blocks; edge_iterator ei; edge e; + unsigned i; + + rewrite_out_of_ssa (&SA); + SA.partition_to_pseudo = (rtx *)xcalloc (SA.map->num_partitions, + sizeof (rtx)); + /* XXX remove_unused_locals also removes var annotation which we rely on during + phi node elimination for now. */ + /*remove_unused_locals ();*/ /* Some backends want to know that we are expanding to RTL. */ currently_expanding_to_rtl = 1; *************** gimple_expand_cfg (void) *** 2339,2344 **** --- 2454,2484 ---- /* Set up parameters and prepare for return, for the function. */ expand_function_start (current_function_decl); + /* Now that we also have the parameter RTXs, copy them over to our + partitions. */ + for (i = 0; i < SA.map->num_partitions; i++) + { + tree var = partition_to_var (SA.map, i); + + if (TREE_CODE (var) == SSA_NAME) + var = SSA_NAME_VAR (var); + if (TREE_CODE (var) != VAR_DECL + && !SA.partition_to_pseudo[i]) + SA.partition_to_pseudo[i] = DECL_RTL_IF_SET (var); + gcc_assert (SA.partition_to_pseudo[i]); + /* Some RTL parts really want to look at DECL_RTL(x) when x + was a decl marked in REG_ATTR or MEM_ATTR. We could use + SET_DECL_RTL here making this available, but that would mean + to select one of the potentially many RTLs for one DECL. Instead + of doing that we simply reset the MEM_EXPR of the RTL in question, + then nobody can get at it and hence nobody can call DECL_RTL on it. */ + if (!DECL_RTL_SET_P (var)) + { + if (MEM_P (SA.partition_to_pseudo[i])) + set_mem_expr (SA.partition_to_pseudo[i], NULL); + } + } + /* If this function is `main', emit a call to `__main' to run global initializers, etc. */ if (DECL_NAME (current_function_decl) *************** gimple_expand_cfg (void) *** 2371,2380 **** /* Register rtl specific functions for cfg. */ rtl_register_cfg_hooks (); init_block = construct_init_block (); /* Clear EDGE_EXECUTABLE on the entry edge(s). It is cleaned from the ! remaining edges in expand_gimple_basic_block. */ FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) e->flags &= ~EDGE_EXECUTABLE; --- 2511,2522 ---- /* Register rtl specific functions for cfg. */ rtl_register_cfg_hooks (); + expand_phi_nodes (&SA); + init_block = construct_init_block (); /* Clear EDGE_EXECUTABLE on the entry edge(s). It is cleaned from the ! remaining edges later. */ FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) e->flags &= ~EDGE_EXECUTABLE; *************** gimple_expand_cfg (void) *** 2382,2387 **** --- 2524,2532 ---- FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR, next_bb) bb = expand_gimple_basic_block (bb); + execute_free_datastructures (); + finish_out_of_ssa (&SA); + /* Expansion is used by optimization passes too, set maybe_hot_insn_p conservatively to true until they are all profile aware. */ pointer_map_destroy (lab_rtx_for_bb); *************** gimple_expand_cfg (void) *** 2401,2411 **** rebuild_jump_labels (get_insns ()); find_exception_handler_labels (); blocks = sbitmap_alloc (last_basic_block); sbitmap_ones (blocks); find_many_sub_basic_blocks (blocks); - purge_all_dead_edges (); sbitmap_free (blocks); compact_blocks (); --- 2546,2597 ---- rebuild_jump_labels (get_insns ()); find_exception_handler_labels (); + currently_expanding_to_rtl = 1; + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR, next_bb) + { + edge e; + edge_iterator ei; + /* ??? commit_one_edge_insertion might reorder the edges of the + current block (when it needs to split an edge), so that we + might miss some edges with instructions on them. Pff. + (see execute/ashldi-1.c). */ + VEC(edge,gc) *edges = VEC_copy (edge,gc,bb->preds); + + for (ei = ei_start (edges); (e = ei_safe_edge (ei)); ) + { + ei_next (&ei); + if (e->insns.r) + commit_one_edge_insertion (e); + } + VEC_free (edge, gc, edges); + } + currently_expanding_to_rtl = 0; + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR, next_bb) + { + edge e; + edge_iterator ei; + for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) + { + /* Clear EDGE_EXECUTABLE. This flag is never used in the backend. */ + e->flags &= ~EDGE_EXECUTABLE; + + /* At the moment not all abnormal edges match the RTL + representation. It is safe to remove them here as + find_many_sub_basic_blocks will rediscover them. + In the future we should get this fixed properly. */ + if ((e->flags & EDGE_ABNORMAL) + && !(e->flags & EDGE_SIBCALL)) + remove_edge (e); + else + ei_next (&ei); + } + } + blocks = sbitmap_alloc (last_basic_block); sbitmap_ones (blocks); find_many_sub_basic_blocks (blocks); sbitmap_free (blocks); + purge_all_dead_edges (); compact_blocks (); *************** struct rtl_opt_pass pass_expand = *** 2471,2480 **** 0, /* static_pass_number */ TV_EXPAND, /* tv_id */ /* ??? If TER is enabled, we actually receive GENERIC. */ ! PROP_gimple_leh | PROP_cfg, /* properties_required */ PROP_rtl, /* properties_provided */ ! PROP_trees, /* properties_destroyed */ ! 0, /* todo_flags_start */ ! TODO_dump_func, /* todo_flags_finish */ } }; --- 2657,2668 ---- 0, /* static_pass_number */ TV_EXPAND, /* tv_id */ /* ??? If TER is enabled, we actually receive GENERIC. */ ! PROP_ssa | PROP_gimple_leh | PROP_cfg, /* properties_required */ PROP_rtl, /* properties_provided */ ! PROP_ssa | PROP_trees, /* properties_destroyed */ ! TODO_verify_ssa | TODO_verify_flow ! | TODO_verify_stmts, /* todo_flags_start */ ! TODO_dump_func ! | TODO_ggc_collect /* todo_flags_finish */ } }; Index: tree-ssa-live.c =================================================================== *** tree-ssa-live.c.orig --- tree-ssa-live.c *************** change_partition_var (var_map map, tree *** 388,393 **** --- 388,394 ---- { var_ann_t ann; + return; gcc_assert (TREE_CODE (var) != SSA_NAME); ann = var_ann (var); Index: tree-ssa.c =================================================================== *** tree-ssa.c.orig --- tree-ssa.c *************** delete_tree_ssa (void) *** 845,851 **** gimple_set_modified (stmt, true); } ! set_phi_nodes (bb, NULL); } /* Remove annotations from every referenced local variable. */ --- 845,852 ---- gimple_set_modified (stmt, true); } ! if (!(bb->flags & BB_RTL)) ! set_phi_nodes (bb, NULL); } /* Remove annotations from every referenced local variable. */ Index: tree-optimize.c =================================================================== *** tree-optimize.c.orig --- tree-optimize.c *************** struct gimple_opt_pass pass_cleanup_cfg_ *** 219,225 **** /* Pass: do the actions required to finish with tree-ssa optimization passes. */ ! static unsigned int execute_free_datastructures (void) { free_dominance_info (CDI_DOMINATORS); --- 219,225 ---- /* Pass: do the actions required to finish with tree-ssa optimization passes. */ ! unsigned int execute_free_datastructures (void) { free_dominance_info (CDI_DOMINATORS); *************** execute_free_datastructures (void) *** 228,233 **** --- 228,237 ---- /* Remove the ssa structures. */ if (cfun->gimple_df) delete_tree_ssa (); + + /* And get rid of annotations we no longer need. */ + delete_tree_cfg_annotations (); + return 0; } *************** struct gimple_opt_pass pass_free_datastr *** 254,262 **** static unsigned int execute_free_cfg_annotations (void) { - /* And get rid of annotations we no longer need. */ - delete_tree_cfg_annotations (); - return 0; } --- 258,263 ---- Index: tree-outof-ssa.c =================================================================== *** tree-outof-ssa.c.orig --- tree-outof-ssa.c *************** along with GCC; see the file COPYING3. *** 30,38 **** #include "tree-flow.h" #include "timevar.h" #include "tree-dump.h" - #include "tree-ssa-live.h" #include "tree-pass.h" #include "toplev.h" /* Used to hold all the components required to do SSA PHI elimination. --- 30,40 ---- #include "tree-flow.h" #include "timevar.h" #include "tree-dump.h" #include "tree-pass.h" #include "toplev.h" + #include "rtl.h" + #include "expr.h" + #include "ssaexpand.h" /* Used to hold all the components required to do SSA PHI elimination. *************** typedef struct _elim_graph { *** 61,67 **** int size; /* List of nodes in the elimination graph. */ ! VEC(tree,heap) *nodes; /* The predecessor and successor edge list. */ VEC(int,heap) *edge_list; --- 63,69 ---- int size; /* List of nodes in the elimination graph. */ ! VEC(int,heap) *nodes; /* The predecessor and successor edge list. */ VEC(int,heap) *edge_list; *************** typedef struct _elim_graph { *** 79,84 **** --- 81,87 ---- edge e; /* List of constant copies to emit. These are pushed on in pairs. */ + VEC(int,heap) *const_dests; VEC(tree,heap) *const_copies; } *elim_graph; *************** create_temp (tree t) *** 131,163 **** } ! /* This helper function fill insert a copy from a constant or variable SRC to ! variable DEST on edge E. */ static void ! insert_copy_on_edge (edge e, tree dest, tree src) { ! gimple copy; ! copy = gimple_build_assign (dest, src); ! set_is_used (dest); ! if (TREE_CODE (src) == ADDR_EXPR) ! src = TREE_OPERAND (src, 0); ! if (TREE_CODE (src) == VAR_DECL || TREE_CODE (src) == PARM_DECL) ! set_is_used (src); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, ! "Inserting a copy on edge BB%d->BB%d :", e->src->index, ! e->dest->index); ! print_gimple_stmt (dump_file, copy, 0, dump_flags); fprintf (dump_file, "\n"); } ! gsi_insert_on_edge (e, copy); } --- 134,253 ---- } ! /* Insert a copy instruction from partition SRC to DEST onto edge E. */ static void ! insert_partition_copy_on_edge (edge e, int dest, int src) { ! rtx seq; ! if (dump_file && (dump_flags & TDF_DETAILS)) ! { ! fprintf (dump_file, ! "Inserting a partition copy on edge BB%d->BB%d :" ! "PART.%d = PART.%d", ! e->src->index, ! e->dest->index, dest, src); ! fprintf (dump_file, "\n"); ! } ! ! gcc_assert (SA.partition_to_pseudo[dest]); ! gcc_assert (SA.partition_to_pseudo[src]); ! ! /* Partition copy between same base variables only, so it's the same mode, ! hence we can use emit_move_insn. */ ! start_sequence (); ! emit_move_insn (SA.partition_to_pseudo[dest], SA.partition_to_pseudo[src]); ! seq = get_insns (); ! end_sequence (); ! insert_insn_on_edge (seq, e); ! } ! /* Insert a copy instruction from expression SRC to partition DEST ! onto edge E. */ + static void + insert_value_copy_on_edge (edge e, int dest, tree src) + { + rtx seq, x; + enum machine_mode mode; if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, ! "Inserting a value copy on edge BB%d->BB%d : PART.%d = ", e->src->index, ! e->dest->index, dest); ! print_generic_expr (dump_file, src, TDF_SLIM); fprintf (dump_file, "\n"); } ! gcc_assert (SA.partition_to_pseudo[dest]); ! ! start_sequence (); ! mode = GET_MODE (SA.partition_to_pseudo[dest]); ! x = expand_expr (src, SA.partition_to_pseudo[dest], mode, EXPAND_NORMAL); ! if (GET_MODE (x) != mode) ! x = convert_to_mode (mode, x, TYPE_UNSIGNED (TREE_TYPE (src))); ! if (x != SA.partition_to_pseudo[dest]) ! emit_move_insn (SA.partition_to_pseudo[dest], x); ! seq = get_insns (); ! end_sequence (); ! ! insert_insn_on_edge (seq, e); ! } ! ! /* Insert a copy instruction from RTL expression SRC to partition DEST ! onto edge E. */ ! ! static void ! insert_rtx_to_part_on_edge (edge e, int dest, rtx src) ! { ! rtx seq; ! if (dump_file && (dump_flags & TDF_DETAILS)) ! { ! fprintf (dump_file, ! "Inserting a temp copy on edge BB%d->BB%d : PART.%d = ", ! e->src->index, ! e->dest->index, dest); ! print_simple_rtl (dump_file, src); ! fprintf (dump_file, "\n"); ! } ! ! gcc_assert (SA.partition_to_pseudo[dest]); ! start_sequence (); ! gcc_assert (GET_MODE (src) == GET_MODE (SA.partition_to_pseudo[dest])); ! emit_move_insn (SA.partition_to_pseudo[dest], src); ! seq = get_insns (); ! end_sequence (); ! ! insert_insn_on_edge (seq, e); ! } ! ! /* Insert a copy instruction from partition SRC to RTL lvalue DEST ! onto edge E. */ ! ! static void ! insert_part_to_rtx_on_edge (edge e, rtx dest, int src) ! { ! rtx seq; ! if (dump_file && (dump_flags & TDF_DETAILS)) ! { ! fprintf (dump_file, ! "Inserting a temp copy on edge BB%d->BB%d : ", ! e->src->index, ! e->dest->index); ! print_simple_rtl (dump_file, dest); ! fprintf (dump_file, "= PART.%d\n", src); ! } ! ! gcc_assert (SA.partition_to_pseudo[src]); ! start_sequence (); ! gcc_assert (GET_MODE (dest) == GET_MODE (SA.partition_to_pseudo[src])); ! emit_move_insn (dest, SA.partition_to_pseudo[src]); ! seq = get_insns (); ! end_sequence (); ! ! insert_insn_on_edge (seq, e); } *************** new_elim_graph (int size) *** 169,175 **** { elim_graph g = (elim_graph) xmalloc (sizeof (struct _elim_graph)); ! g->nodes = VEC_alloc (tree, heap, 30); g->const_copies = VEC_alloc (tree, heap, 20); g->edge_list = VEC_alloc (int, heap, 20); g->stack = VEC_alloc (int, heap, 30); --- 259,266 ---- { elim_graph g = (elim_graph) xmalloc (sizeof (struct _elim_graph)); ! g->nodes = VEC_alloc (int, heap, 30); ! g->const_dests = VEC_alloc (int, heap, 20); g->const_copies = VEC_alloc (tree, heap, 20); g->edge_list = VEC_alloc (int, heap, 20); g->stack = VEC_alloc (int, heap, 30); *************** new_elim_graph (int size) *** 185,191 **** static inline void clear_elim_graph (elim_graph g) { ! VEC_truncate (tree, g->nodes, 0); VEC_truncate (int, g->edge_list, 0); } --- 276,282 ---- static inline void clear_elim_graph (elim_graph g) { ! VEC_truncate (int, g->nodes, 0); VEC_truncate (int, g->edge_list, 0); } *************** delete_elim_graph (elim_graph g) *** 199,205 **** VEC_free (int, heap, g->stack); VEC_free (int, heap, g->edge_list); VEC_free (tree, heap, g->const_copies); ! VEC_free (tree, heap, g->nodes); free (g); } --- 290,297 ---- VEC_free (int, heap, g->stack); VEC_free (int, heap, g->edge_list); VEC_free (tree, heap, g->const_copies); ! VEC_free (int, heap, g->const_dests); ! VEC_free (int, heap, g->nodes); free (g); } *************** delete_elim_graph (elim_graph g) *** 209,230 **** static inline int elim_graph_size (elim_graph g) { ! return VEC_length (tree, g->nodes); } /* Add NODE to graph G, if it doesn't exist already. */ static inline void ! elim_graph_add_node (elim_graph g, tree node) { int x; ! tree t; ! for (x = 0; VEC_iterate (tree, g->nodes, x, t); x++) if (t == node) return; ! VEC_safe_push (tree, heap, g->nodes, node); } --- 301,322 ---- static inline int elim_graph_size (elim_graph g) { ! return VEC_length (int, g->nodes); } /* Add NODE to graph G, if it doesn't exist already. */ static inline void ! elim_graph_add_node (elim_graph g, int node) { int x; ! int t; ! for (x = 0; VEC_iterate (int, g->nodes, x, t); x++) if (t == node) return; ! VEC_safe_push (int, heap, g->nodes, node); } *************** do { \ *** 299,305 **** /* Add T to elimination graph G. */ static inline void ! eliminate_name (elim_graph g, tree T) { elim_graph_add_node (g, T); } --- 391,397 ---- /* Add T to elimination graph G. */ static inline void ! eliminate_name (elim_graph g, int T) { elim_graph_add_node (g, T); } *************** eliminate_name (elim_graph g, tree T) *** 309,315 **** G->e. */ static void ! eliminate_build (elim_graph g, basic_block B) { tree T0, Ti; int p0, pi; --- 401,407 ---- G->e. */ static void ! eliminate_build (elim_graph g) { tree T0, Ti; int p0, pi; *************** eliminate_build (elim_graph g, basic_blo *** 317,332 **** clear_elim_graph (g); ! for (gsi = gsi_start_phis (B); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple phi = gsi_stmt (gsi); ! T0 = var_to_partition_to_var (g->map, gimple_phi_result (phi)); ! /* Ignore results which are not in partitions. */ ! if (T0 == NULL_TREE) continue; Ti = PHI_ARG_DEF (phi, g->e->dest_idx); /* If this argument is a constant, or a SSA_NAME which is being --- 409,424 ---- clear_elim_graph (g); ! for (gsi = gsi_start_phis (g->e->dest); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple phi = gsi_stmt (gsi); ! p0 = var_to_partition (g->map, gimple_phi_result (phi)); /* Ignore results which are not in partitions. */ ! if (p0 == NO_PARTITION) continue; + T0 = partition_to_var (g->map, p0); Ti = PHI_ARG_DEF (phi, g->e->dest_idx); /* If this argument is a constant, or a SSA_NAME which is being *************** eliminate_build (elim_graph g, basic_blo *** 338,355 **** { /* Save constant copies until all other copies have been emitted on this edge. */ ! VEC_safe_push (tree, heap, g->const_copies, T0); VEC_safe_push (tree, heap, g->const_copies, Ti); } else { ! Ti = var_to_partition_to_var (g->map, Ti); ! if (T0 != Ti) { ! eliminate_name (g, T0); ! eliminate_name (g, Ti); ! p0 = var_to_partition (g->map, T0); ! pi = var_to_partition (g->map, Ti); elim_graph_add_edge (g, p0, pi); } } --- 430,448 ---- { /* Save constant copies until all other copies have been emitted on this edge. */ ! VEC_safe_push (int, heap, g->const_dests, p0); VEC_safe_push (tree, heap, g->const_copies, Ti); } else { ! pi = var_to_partition (g->map, Ti); ! if (p0 != pi) { ! /*Ti = var_to_partition_to_var (g->map, Ti);*/ ! eliminate_name (g, p0); ! eliminate_name (g, pi); ! /*p0 = var_to_partition (g->map, T0); ! pi = var_to_partition (g->map, Ti);*/ elim_graph_add_edge (g, p0, pi); } } *************** elim_backward (elim_graph g, int T) *** 399,430 **** if (!TEST_BIT (g->visited, P)) { elim_backward (g, P); ! insert_copy_on_edge (g->e, ! partition_to_var (g->map, P), ! partition_to_var (g->map, T)); } }); } /* Insert required copies for T in graph G. Check for a strongly connected region, and create a temporary to break the cycle if one is found. */ static void elim_create (elim_graph g, int T) { - tree U; int P, S; if (elim_unvisited_predecessor (g, T)) { ! U = create_temp (partition_to_var (g->map, T)); ! insert_copy_on_edge (g->e, U, partition_to_var (g->map, T)); FOR_EACH_ELIM_GRAPH_PRED (g, T, P, { if (!TEST_BIT (g->visited, P)) { elim_backward (g, P); ! insert_copy_on_edge (g->e, partition_to_var (g->map, P), U); } }); } --- 492,534 ---- if (!TEST_BIT (g->visited, P)) { elim_backward (g, P); ! insert_partition_copy_on_edge (g->e, P, T); } }); } + static rtx + get_temp_reg (tree name) + { + tree var = TREE_CODE (name) == SSA_NAME ? SSA_NAME_VAR (name) : name; + tree type = TREE_TYPE (var); + int unsignedp = TYPE_UNSIGNED (type); + enum machine_mode reg_mode + = promote_mode (type, DECL_MODE (var), &unsignedp, 0); + rtx x = gen_reg_rtx (reg_mode); + if (POINTER_TYPE_P (type)) + mark_reg_pointer (x, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (var)))); + return x; + } + /* Insert required copies for T in graph G. Check for a strongly connected region, and create a temporary to break the cycle if one is found. */ static void elim_create (elim_graph g, int T) { int P, S; if (elim_unvisited_predecessor (g, T)) { ! rtx U = get_temp_reg (partition_to_var (g->map, T)); ! insert_part_to_rtx_on_edge (g->e, U, T); FOR_EACH_ELIM_GRAPH_PRED (g, T, P, { if (!TEST_BIT (g->visited, P)) { elim_backward (g, P); ! insert_rtx_to_part_on_edge (g->e, P, U); } }); } *************** elim_create (elim_graph g, int T) *** 434,445 **** if (S != -1) { SET_BIT (g->visited, T); ! insert_copy_on_edge (g->e, ! partition_to_var (g->map, T), ! partition_to_var (g->map, S)); } } - } --- 538,546 ---- if (S != -1) { SET_BIT (g->visited, T); ! insert_partition_copy_on_edge (g->e, T, S); } } } *************** static void *** 449,455 **** eliminate_phi (edge e, elim_graph g) { int x; - basic_block B = e->dest; gcc_assert (VEC_length (tree, g->const_copies) == 0); --- 550,555 ---- *************** eliminate_phi (edge e, elim_graph g) *** 459,478 **** g->e = e; ! eliminate_build (g, B); if (elim_graph_size (g) != 0) { ! tree var; sbitmap_zero (g->visited); VEC_truncate (int, g->stack, 0); ! for (x = 0; VEC_iterate (tree, g->nodes, x, var); x++) { ! int p = var_to_partition (g->map, var); ! if (!TEST_BIT (g->visited, p)) ! elim_forward (g, p); } sbitmap_zero (g->visited); --- 559,577 ---- g->e = e; ! eliminate_build (g); if (elim_graph_size (g) != 0) { ! int part; sbitmap_zero (g->visited); VEC_truncate (int, g->stack, 0); ! for (x = 0; VEC_iterate (int, g->nodes, x, part); x++) { ! if (!TEST_BIT (g->visited, part)) ! elim_forward (g, part); } sbitmap_zero (g->visited); *************** eliminate_phi (edge e, elim_graph g) *** 487,496 **** /* If there are any pending constant copies, issue them now. */ while (VEC_length (tree, g->const_copies) > 0) { ! tree src, dest; src = VEC_pop (tree, g->const_copies); ! dest = VEC_pop (tree, g->const_copies); ! insert_copy_on_edge (e, dest, src); } } --- 586,596 ---- /* If there are any pending constant copies, issue them now. */ while (VEC_length (tree, g->const_copies) > 0) { ! int dest; ! tree src; src = VEC_pop (tree, g->const_copies); ! dest = VEC_pop (int, g->const_dests); ! insert_value_copy_on_edge (e, dest, src); } } *************** rewrite_trees (var_map map, gimple *valu *** 750,755 **** --- 850,856 ---- g->map = map; FOR_EACH_BB (bb) { + if (0) for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ) { gimple stmt = gsi_stmt (gsi); *************** rewrite_trees (var_map map, gimple *valu *** 816,822 **** } phi = phi_nodes (bb); ! if (phi) { edge_iterator ei; FOR_EACH_EDGE (e, ei, bb->preds) --- 917,923 ---- } phi = phi_nodes (bb); ! if (0 && phi) { edge_iterator ei; FOR_EACH_EDGE (e, ei, bb->preds) *************** rewrite_trees (var_map map, gimple *valu *** 827,832 **** --- 928,949 ---- delete_elim_graph (g); } + void + expand_phi_nodes (struct ssaexpand *sa) + { + basic_block bb; + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR, next_bb) + if (!gimple_seq_empty_p (phi_nodes (bb))) + { + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, bb->preds) + eliminate_phi (e, (elim_graph)sa->elim_graph); + set_phi_nodes (bb, NULL); + } + } + + /* These are the local work structures used to determine the best place to insert the copies that were placed on edges by the SSA->normal pass.. */ static VEC(edge,heap) *edge_leader; *************** perform_edge_inserts (void) *** 1339,1350 **** should also be used. */ static void ! remove_ssa_form (bool perform_ter) { basic_block bb; gimple *values = NULL; var_map map; gimple_stmt_iterator gsi; map = coalesce_ssa_name (); --- 1456,1468 ---- should also be used. */ static void ! remove_ssa_form (bool perform_ter, struct ssaexpand *sa) { basic_block bb; gimple *values = NULL; var_map map; gimple_stmt_iterator gsi; + elim_graph g; map = coalesce_ssa_name (); *************** remove_ssa_form (bool perform_ter) *** 1366,1371 **** --- 1484,1490 ---- } /* Assign real variables to the partitions now. */ + if (0) assign_vars (map); if (dump_file && (dump_flags & TDF_DETAILS)) *************** remove_ssa_form (bool perform_ter) *** 1376,1393 **** rewrite_trees (map, values); ! if (values) free (values); /* Remove PHI nodes which have been translated back to real variables. */ FOR_EACH_BB (bb) for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);) remove_phi_node (&gsi, true); /* If any copies were inserted on edges, analyze and insert them now. */ perform_edge_inserts (); delete_var_map (map); } --- 1495,1522 ---- rewrite_trees (map, values); ! if (0 && values) free (values); /* Remove PHI nodes which have been translated back to real variables. */ + if (0) FOR_EACH_BB (bb) for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);) remove_phi_node (&gsi, true); /* If any copies were inserted on edges, analyze and insert them now. */ + if (0) perform_edge_inserts (); + if (0) delete_var_map (map); + + sa->map = map; + sa->values = values; + + g = new_elim_graph (map->num_partitions); + sa->elim_graph = g; + g->map = map; } *************** insert_backedge_copies (void) *** 1477,1488 **** } } /* Take the current function out of SSA form, translating PHIs as described in R. Morgan, ``Building an Optimizing Compiler'', Butterworth-Heinemann, Boston, MA, 1998. pp 176-186. */ ! static unsigned int ! rewrite_out_of_ssa (void) { /* If elimination of a PHI requires inserting a copy on a backedge, then we will have to split the backedge which has numerous --- 1606,1626 ---- } } + void + finish_out_of_ssa (struct ssaexpand *sa) + { + delete_elim_graph ((elim_graph)sa->elim_graph); + if (sa->values) + free (sa->values); + memset (sa, 0, sizeof *sa); + } + /* Take the current function out of SSA form, translating PHIs as described in R. Morgan, ``Building an Optimizing Compiler'', Butterworth-Heinemann, Boston, MA, 1998. pp 176-186. */ ! unsigned int ! rewrite_out_of_ssa (struct ssaexpand *sa) { /* If elimination of a PHI requires inserting a copy on a backedge, then we will have to split the backedge which has numerous *************** rewrite_out_of_ssa (void) *** 1499,1509 **** if (dump_file && (dump_flags & TDF_DETAILS)) gimple_dump_cfg (dump_file, dump_flags & ~TDF_DETAILS); ! remove_ssa_form (flag_tree_ter && !flag_mudflap); if (dump_file && (dump_flags & TDF_DETAILS)) gimple_dump_cfg (dump_file, dump_flags & ~TDF_DETAILS); cfun->gimple_df->in_ssa_p = false; return 0; } --- 1637,1648 ---- if (dump_file && (dump_flags & TDF_DETAILS)) gimple_dump_cfg (dump_file, dump_flags & ~TDF_DETAILS); ! remove_ssa_form (flag_tree_ter && !flag_mudflap, sa); if (dump_file && (dump_flags & TDF_DETAILS)) gimple_dump_cfg (dump_file, dump_flags & ~TDF_DETAILS); + if (0) cfun->gimple_df->in_ssa_p = false; return 0; } *************** rewrite_out_of_ssa (void) *** 1511,1516 **** --- 1650,1656 ---- /* Define the parameters of the out of SSA pass. */ + #if 0 struct gimple_opt_pass pass_del_ssa = { { *************** struct gimple_opt_pass pass_del_ssa = *** 1533,1535 **** --- 1673,1676 ---- | TODO_remove_unused_locals /* todo_flags_finish */ } }; + #endif Index: ssaexpand.h =================================================================== *** /dev/null --- ssaexpand.h *************** *** 0 **** --- 1,59 ---- + /* Routines for expanding from SSA form to RTL. + Copyright (C) 2009 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 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 + . */ + + + #ifndef _SSAEXPAND_H + #define _SSAEXPAND_H 1 + + #include "tree-ssa-live.h" + + struct ssaexpand + { + var_map map; + gimple *values; + rtx *partition_to_pseudo; + void *elim_graph; + }; + + extern struct ssaexpand SA; + + static inline rtx + get_rtx_for_ssa_name (tree exp) + { + int p = partition_find (SA.map->var_partition, SSA_NAME_VERSION (exp)); + if (SA.map->partition_to_view) + p = SA.map->partition_to_view[p]; + return SA.partition_to_pseudo[p]; + } + + static inline gimple + get_gimple_for_ssa_name (tree exp) + { + int v = SSA_NAME_VERSION (exp); + if (SA.values) + return SA.values[v]; + return NULL; + } + + /* In tree-outof-ssa.c. */ + void finish_out_of_ssa (struct ssaexpand *sa); + unsigned int rewrite_out_of_ssa (struct ssaexpand *sa); + void expand_phi_nodes (struct ssaexpand *sa); + + #endif Index: passes.c =================================================================== *** passes.c.orig --- passes.c *************** init_optimization_passes (void) *** 707,723 **** NEXT_PASS (pass_local_pure_const); } NEXT_PASS (pass_cleanup_eh); - NEXT_PASS (pass_del_ssa); NEXT_PASS (pass_nrv); NEXT_PASS (pass_mark_used_blocks); NEXT_PASS (pass_cleanup_cfg_post_optimizing); - NEXT_PASS (pass_warn_function_noreturn); ! NEXT_PASS (pass_free_datastructures); ! NEXT_PASS (pass_mudflap_2); ! NEXT_PASS (pass_free_cfg_annotations); NEXT_PASS (pass_expand); NEXT_PASS (pass_rest_of_compilation); { struct opt_pass **p = &pass_rest_of_compilation.pass.sub; --- 707,723 ---- NEXT_PASS (pass_local_pure_const); } NEXT_PASS (pass_cleanup_eh); NEXT_PASS (pass_nrv); NEXT_PASS (pass_mark_used_blocks); NEXT_PASS (pass_cleanup_cfg_post_optimizing); NEXT_PASS (pass_warn_function_noreturn); ! /* NEXT_PASS (pass_mudflap_2); */ ! /* NEXT_PASS (pass_del_ssa); ! NEXT_PASS (pass_free_datastructures); ! NEXT_PASS (pass_free_cfg_annotations);*/ NEXT_PASS (pass_expand); + NEXT_PASS (pass_rest_of_compilation); { struct opt_pass **p = &pass_rest_of_compilation.pass.sub; Index: cfgrtl.c =================================================================== *** cfgrtl.c.orig --- cfgrtl.c *************** along with GCC; see the file COPYING3. *** 64,70 **** static int can_delete_note_p (const_rtx); static int can_delete_label_p (const_rtx); - static void commit_one_edge_insertion (edge); static basic_block rtl_split_edge (edge); static bool rtl_move_block_after (basic_block, basic_block); static int rtl_verify_flow_info (void); --- 64,69 ---- *************** try_redirect_by_replacing_jump (edge e, *** 872,902 **** return e; } ! /* Redirect edge representing branch of (un)conditional jump or tablejump, ! NULL on failure */ ! static edge ! redirect_branch_edge (edge e, basic_block target) { rtx tmp; - rtx old_label = BB_HEAD (e->dest); - basic_block src = e->src; - rtx insn = BB_END (src); - - /* We can only redirect non-fallthru edges of jump insn. */ - if (e->flags & EDGE_FALLTHRU) - return NULL; - else if (!JUMP_P (insn)) - return NULL; - /* Recognize a tablejump and adjust all matching cases. */ if (tablejump_p (insn, NULL, &tmp)) { rtvec vec; int j; ! rtx new_label = block_label (target); ! if (target == EXIT_BLOCK_PTR) ! return NULL; if (GET_CODE (PATTERN (tmp)) == ADDR_VEC) vec = XVEC (PATTERN (tmp), 0); else --- 871,895 ---- return e; } ! /* Subroutine of redirect_branch_edge that tries to patch the jump ! instruction INSN so that it reaches block NEW. Do this ! only when it originally reached block OLD. Return true if this ! worked or the original target wasn't OLD, return false if redirection ! doesn't work. */ ! ! static bool ! patch_jump_insn (rtx insn, rtx old_label, basic_block new_bb) { rtx tmp; /* Recognize a tablejump and adjust all matching cases. */ if (tablejump_p (insn, NULL, &tmp)) { rtvec vec; int j; ! rtx new_label = block_label (new_bb); ! if (new_bb == EXIT_BLOCK_PTR) ! return false; if (GET_CODE (PATTERN (tmp)) == ADDR_VEC) vec = XVEC (PATTERN (tmp), 0); else *************** redirect_branch_edge (edge e, basic_bloc *** 931,950 **** if (computed_jump_p (insn) /* A return instruction can't be redirected. */ || returnjump_p (insn)) ! return NULL; ! ! /* If the insn doesn't go where we think, we're confused. */ ! gcc_assert (JUMP_LABEL (insn) == old_label); ! /* If the substitution doesn't succeed, die. This can happen ! if the back end emitted unrecognizable instructions or if ! target is exit block on some arches. */ ! if (!redirect_jump (insn, block_label (target), 0)) { ! gcc_assert (target == EXIT_BLOCK_PTR); ! return NULL; } } if (dump_file) fprintf (dump_file, "Edge %i->%i redirected to %i\n", --- 924,978 ---- if (computed_jump_p (insn) /* A return instruction can't be redirected. */ || returnjump_p (insn)) ! return false; ! if (!currently_expanding_to_rtl || JUMP_LABEL (insn) == old_label) { ! /* If the insn doesn't go where we think, we're confused. */ ! gcc_assert (JUMP_LABEL (insn) == old_label); ! ! /* If the substitution doesn't succeed, die. This can happen ! if the back end emitted unrecognizable instructions or if ! target is exit block on some arches. */ ! if (!redirect_jump (insn, block_label (new_bb), 0)) ! { ! gcc_assert (new_bb == EXIT_BLOCK_PTR); ! return false; ! } } } + return true; + } + + + /* Redirect edge representing branch of (un)conditional jump or tablejump, + NULL on failure */ + static edge + redirect_branch_edge (edge e, basic_block target) + { + rtx old_label = BB_HEAD (e->dest); + basic_block src = e->src; + rtx insn = BB_END (src); + + /* We can only redirect non-fallthru edges of jump insn. */ + if (e->flags & EDGE_FALLTHRU) + return NULL; + else if (!JUMP_P (insn) && !currently_expanding_to_rtl) + return NULL; + + if (!currently_expanding_to_rtl) + { + if (!patch_jump_insn (insn, old_label, target)) + return NULL; + } + else + /* When expanding this BB might actually contain multiple + jumps (i.e. not yet split by find_many_sub_basic_blocks). + Redirect all of those that match our label. */ + for (insn = BB_HEAD (src); insn != NEXT_INSN (BB_END (src)); + insn = NEXT_INSN (insn)) + if (JUMP_P (insn) && !patch_jump_insn (insn, old_label, target)) + return NULL; if (dump_file) fprintf (dump_file, "Edge %i->%i redirected to %i\n", *************** insert_insn_on_edge (rtx pattern, edge e *** 1329,1335 **** /* Update the CFG for the instructions queued on edge E. */ ! static void commit_one_edge_insertion (edge e) { rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last; --- 1357,1363 ---- /* Update the CFG for the instructions queued on edge E. */ ! void commit_one_edge_insertion (edge e) { rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last; Index: tree-ssa-coalesce.c =================================================================== *** tree-ssa-coalesce.c.orig --- tree-ssa-coalesce.c *************** compare_pairs (const void *p1, const voi *** 314,320 **** const_coalesce_pair_p const *const pp2 = (const_coalesce_pair_p const *) p2; int result; ! result = (* pp2)->cost - (* pp1)->cost; /* Since qsort does not guarantee stability we use the elements as a secondary key. This provides us with independence from the host's implementation of the sorting algorithm. */ --- 314,320 ---- const_coalesce_pair_p const *const pp2 = (const_coalesce_pair_p const *) p2; int result; ! result = (* pp1)->cost - (* pp2)->cost; /* Since qsort does not guarantee stability we use the elements as a secondary key. This provides us with independence from the host's implementation of the sorting algorithm. */ Index: Makefile.in =================================================================== *** Makefile.in.orig --- Makefile.in *************** TREE_FLOW_H = tree-flow.h tree-flow-inli *** 857,862 **** --- 857,863 ---- $(HASHTAB_H) $(CGRAPH_H) $(IPA_REFERENCE_H) \ tree-ssa-alias.h TREE_SSA_LIVE_H = tree-ssa-live.h $(PARTITION_H) vecprim.h + SSAEXPAND_H = ssaexpand.h $(TREE_SSA_LIVE_H) PRETTY_PRINT_H = pretty-print.h $(INPUT_H) $(OBSTACK_H) DIAGNOSTIC_H = diagnostic.h diagnostic.def $(PRETTY_PRINT_H) options.h C_PRETTY_PRINT_H = c-pretty-print.h $(PRETTY_PRINT_H) $(C_COMMON_H) $(TREE_H) *************** tree-ssa-coalesce.o : tree-ssa-coalesce. *** 2095,2101 **** $(TREE_SSA_LIVE_H) $(BITMAP_H) $(FLAGS_H) $(HASHTAB_H) $(TOPLEV_H) tree-outof-ssa.o : tree-outof-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ $(TREE_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ ! tree-pass.h $(TREE_SSA_LIVE_H) $(BASIC_BLOCK_H) $(BITMAP_H) $(GGC_H) $(TOPLEV_H) tree-ssa-dse.o : tree-ssa-dse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(GGC_H) $(TREE_H) $(RTL_H) $(TM_P_H) $(BASIC_BLOCK_H) \ $(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) domwalk.h $(FLAGS_H) \ --- 2096,2102 ---- $(TREE_SSA_LIVE_H) $(BITMAP_H) $(FLAGS_H) $(HASHTAB_H) $(TOPLEV_H) tree-outof-ssa.o : tree-outof-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ $(TREE_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ ! tree-pass.h $(SSAEXPAND_H) $(BASIC_BLOCK_H) $(BITMAP_H) $(GGC_H) $(TOPLEV_H) tree-ssa-dse.o : tree-ssa-dse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(GGC_H) $(TREE_H) $(RTL_H) $(TM_P_H) $(BASIC_BLOCK_H) \ $(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) domwalk.h $(FLAGS_H) \ *************** expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) *** 2509,2515 **** typeclass.h hard-reg-set.h $(TOPLEV_H) hard-reg-set.h $(EXCEPT_H) reload.h \ $(GGC_H) langhooks.h intl.h $(TM_P_H) $(REAL_H) $(TARGET_H) \ tree-iterator.h gt-expr.h $(MACHMODE_H) $(TIMEVAR_H) $(TREE_FLOW_H) \ ! tree-pass.h $(DF_H) $(DIAGNOSTIC_H) vecprim.h dojump.o : dojump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) $(OPTABS_H) $(INSN_ATTR_H) insn-config.h \ langhooks.h $(GGC_H) gt-dojump.h vecprim.h $(BASIC_BLOCK_H) --- 2510,2516 ---- typeclass.h hard-reg-set.h $(TOPLEV_H) hard-reg-set.h $(EXCEPT_H) reload.h \ $(GGC_H) langhooks.h intl.h $(TM_P_H) $(REAL_H) $(TARGET_H) \ tree-iterator.h gt-expr.h $(MACHMODE_H) $(TIMEVAR_H) $(TREE_FLOW_H) \ ! tree-pass.h $(DF_H) $(DIAGNOSTIC_H) vecprim.h $(SSAEXPAND_H) dojump.o : dojump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) $(OPTABS_H) $(INSN_ATTR_H) insn-config.h \ langhooks.h $(GGC_H) gt-dojump.h vecprim.h $(BASIC_BLOCK_H) *************** cfgexpand.o : cfgexpand.c $(TREE_FLOW_H) *** 2780,2786 **** $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) \ coretypes.h $(TREE_DUMP_H) $(EXCEPT_H) langhooks.h tree-pass.h $(RTL_H) \ $(DIAGNOSTIC_H) $(TOPLEV_H) $(BASIC_BLOCK_H) $(FLAGS_H) debug.h $(PARAMS_H) \ ! value-prof.h $(TREE_INLINE_H) $(TARGET_H) cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h \ output.h $(TOPLEV_H) $(FUNCTION_H) $(EXCEPT_H) $(TM_P_H) insn-config.h $(EXPR_H) \ --- 2781,2787 ---- $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) \ coretypes.h $(TREE_DUMP_H) $(EXCEPT_H) langhooks.h tree-pass.h $(RTL_H) \ $(DIAGNOSTIC_H) $(TOPLEV_H) $(BASIC_BLOCK_H) $(FLAGS_H) debug.h $(PARAMS_H) \ ! value-prof.h $(TREE_INLINE_H) $(TARGET_H) $(SSAEXPAND_H) cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h \ output.h $(TOPLEV_H) $(FUNCTION_H) $(EXCEPT_H) $(TM_P_H) insn-config.h $(EXPR_H) \ Index: basic-block.h =================================================================== *** basic-block.h.orig --- basic-block.h *************** extern void update_bb_for_insn (basic_bl *** 512,517 **** --- 512,518 ---- extern void insert_insn_on_edge (rtx, edge); basic_block split_edge_and_insert (edge, rtx); + extern void commit_one_edge_insertion (edge e); extern void commit_edge_insertions (void); extern void remove_fake_edges (void); Index: rtl.h =================================================================== *** rtl.h.orig --- rtl.h *************** extern rtx emit_copy_of_insn_after (rtx, *** 1495,1500 **** --- 1495,1501 ---- extern void set_reg_attrs_from_value (rtx, rtx); extern void set_mem_attrs_from_reg (rtx, rtx); extern void set_reg_attrs_for_parm (rtx, rtx); + extern void set_reg_attrs_for_decl_rtl (tree t, rtx x); extern void adjust_reg_mode (rtx, enum machine_mode); extern int mem_expr_equal_p (const_tree, const_tree); Index: tree-flow.h =================================================================== *** tree-flow.h.orig --- tree-flow.h *************** rtx addr_for_mem_ref (struct mem_address *** 975,980 **** --- 975,981 ---- void get_address_description (tree, struct mem_address *); tree maybe_fold_tmr (tree); + unsigned int execute_free_datastructures (void); unsigned int execute_fixup_cfg (void); #include "tree-flow-inline.h"