From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29375 invoked by alias); 20 May 2003 17:17:44 -0000 Mailing-List: contact gcc-prs-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-prs-owner@gcc.gnu.org Received: (qmail 24967 invoked by uid 71); 20 May 2003 17:16:03 -0000 Date: Tue, 20 May 2003 17:17:00 -0000 Message-ID: <20030520171603.24962.qmail@sources.redhat.com> To: law@gcc.gnu.org Cc: gcc-prs@gcc.gnu.org, From: Andrew MacLeod Subject: Re: optimization/10863: [tree-ssa] ICE in assign_var Reply-To: Andrew MacLeod X-SW-Source: 2003-05/txt/msg02191.txt.bz2 List-Id: The following reply was made to PR optimization/10863; it has been noted by GNATS. From: Andrew MacLeod To: bangerth@dealii.org Cc: gcc-gnats@gcc.gnu.org Subject: Re: optimization/10863: [tree-ssa] ICE in assign_var Date: 20 May 2003 13:10:59 -0400 On Mon, 2003-05-19 at 10:43, bangerth@dealii.org wrote: > > >Number: 10863 > >Category: optimization > >Synopsis: [tree-ssa] ICE in assign_var There is a workaround available for this bug which can be used by anyone who wants/needs it until Diego's changes are ready. I posted it to gcc-patches last week (Friday 16th maybe?), I will attach it here again. Its the hack Ive been using to test overlapping live ranges. Andrew Index: tree-ssa-copyprop.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-copyprop.c,v retrieving revision 1.1.2.2 diff -c -p -r1.1.2.2 tree-ssa-copyprop.c *** tree-ssa-copyprop.c 13 May 2003 17:27:23 -0000 1.1.2.2 --- tree-ssa-copyprop.c 16 May 2003 18:09:46 -0000 *************** get_original (var, vuse_p) *** 217,240 **** { tree orig = TREE_OPERAND (def_stmt, 1); ! /* If the original variable is an INDIRECT_REF, then DEF_STMT will ! contain a virtual use of the variable's base pointer. We also ! need to copy that. */ ! if (TREE_CODE (SSA_NAME_VAR (orig)) == INDIRECT_REF) ! { ! size_t i; ! varray_type vuses = vuse_ops (def_stmt); ! tree base_ptr = TREE_OPERAND (SSA_NAME_VAR (orig), 0); ! ! for (i = 0; i < VARRAY_ACTIVE_SIZE (vuses); i++) ! if (base_ptr == SSA_NAME_VAR (VARRAY_TREE (vuses, i))) ! { ! *vuse_p = VARRAY_TREE (vuses, i); ! break; ! } ! } ! ! return orig; } return NULL_TREE; --- 217,226 ---- { tree orig = TREE_OPERAND (def_stmt, 1); ! /* If the original variable is an INDIRECT_REF, then this isn't a copy ! (it is a load from memory), so don't propagate it. */ ! if (TREE_CODE (SSA_NAME_VAR (orig)) != INDIRECT_REF) ! return orig; } return NULL_TREE; Index: tree-ssa-live.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-live.c,v retrieving revision 1.1.2.4 diff -c -p -r1.1.2.4 tree-ssa-live.c *** tree-ssa-live.c 8 May 2003 20:29:30 -0000 1.1.2.4 --- tree-ssa-live.c 16 May 2003 18:09:46 -0000 *************** register_ssa_partition (map, ssa_var) *** 106,111 **** --- 106,115 ---- { if (TREE_CODE (ssa_var) != SSA_NAME) abort (); + + if (TREE_CODE (SSA_NAME_VAR (ssa_var)) == INDIRECT_REF) + return; + map->partition_to_var[SSA_NAME_VERSION (ssa_var)] = ssa_var; } Index: tree-ssa.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v retrieving revision 1.1.4.80 diff -c -p -r1.1.4.80 tree-ssa.c *** tree-ssa.c 16 May 2003 18:09:19 -0000 1.1.4.80 --- tree-ssa.c 16 May 2003 18:09:47 -0000 *************** struct ssa_stats_d *** 149,159 **** long num_const_prop; long num_copy_prop; long num_re; - /* FIXME. [UNSSA] Not needed after SSA->normal pass is working. */ - #if 1 - long blocked_optimizations; - long blocked_by_life_crossing; - #endif }; static struct ssa_stats_d ssa_stats; --- 149,154 ---- *************** static void set_livein_block PARAMS ((t *** 169,175 **** static void insert_phi_nodes PARAMS ((bitmap *, sbitmap)); static void insert_phis_for_deferred_variables PARAMS ((varray_type)); static void rewrite_block PARAMS ((basic_block, tree)); ! static void rewrite_stmt PARAMS ((block_stmt_iterator, varray_type *, varray_type *)); static inline void rewrite_operand PARAMS ((tree *)); --- 164,170 ---- static void insert_phi_nodes PARAMS ((bitmap *, sbitmap)); static void insert_phis_for_deferred_variables PARAMS ((varray_type)); static void rewrite_block PARAMS ((basic_block, tree)); ! static int rewrite_stmt PARAMS ((block_stmt_iterator, varray_type *, varray_type *)); static inline void rewrite_operand PARAMS ((tree *)); *************** static void coalesce_ssa_name PARAMS (( *** 210,220 **** static void assign_vars PARAMS ((var_map)); static inline void set_if_valid PARAMS ((var_map, sbitmap, tree)); static inline void add_conflicts_if_valid PARAMS ((root_var_p, conflict_graph, var_map, sbitmap, tree)); ! ! /* FIXME: [UNSSA] Remove once the real unSSA pass is implemented. */ ! #if 1 ! static bool var_is_live PARAMS ((tree, basic_block)); ! #endif /* Return nonzero if RHS may be copy propagated into subsequent uses of LHS. */ --- 205,212 ---- static void assign_vars PARAMS ((var_map)); static inline void set_if_valid PARAMS ((var_map, sbitmap, tree)); static inline void add_conflicts_if_valid PARAMS ((root_var_p, conflict_graph, var_map, sbitmap, tree)); ! static void replace_variable PARAMS ((var_map, tree *)); ! static void eliminate_extraneous_phis PARAMS ((void)); /* Return nonzero if RHS may be copy propagated into subsequent uses of LHS. */ *************** rewrite_block (bb, eq_expr_value) *** 783,790 **** /* Step 2. Rewrite every variable used in each statement the block with its immediate reaching definitions. Update the current definition of a variable when a new real or virtual definition is found. */ ! for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) ! rewrite_stmt (si, &block_defs, &block_avail_exprs); /* Step 3. Visit all the successor blocks of BB looking for PHI nodes. For every PHI node found, add a new argument containing the current --- 775,785 ---- /* Step 2. Rewrite every variable used in each statement the block with its immediate reaching definitions. Update the current definition of a variable when a new real or virtual definition is found. */ ! for (si = bsi_start (bb); !bsi_end_p (si); ) ! if (!rewrite_stmt (si, &block_defs, &block_avail_exprs)) ! bsi_next (&si); ! else ! bsi_remove (&si); /* Step 3. Visit all the successor blocks of BB looking for PHI nodes. For every PHI node found, add a new argument containing the current *************** assign_vars (map) *** 1551,1561 **** print_generic_expr (tree_ssa_dump_file, var, TDF_SLIM); } - /* FIXME. Since we still don't have passes that create overlapping - live ranges, the code above should've coalesced all the versions of - the variable together. */ - abort (); - var = create_temp (t); change_partition_var (map, var, i); ann = var_ann (var); --- 1546,1551 ---- *************** assign_vars (map) *** 1572,1587 **** delete_root_var (rv); } ! /* Take function FNDECL out of SSA form. ! FIXME: Need to support overlapping live ranges for different versions of ! the same variable. At the moment, we will silently generate ! wrong code if an optimizer pass moves code so that two versions ! of the same variable have overlapping live ranges. ! NOTE: Look for the string '[UNSSA]' to re-enable code that ! depends on a properly working unSSA pass. */ void rewrite_out_of_ssa (fndecl) --- 1562,1718 ---- delete_root_var (rv); } + /* HACK. */ + #if 1 + + static tree replace_embedded_vars PARAMS ((tree *, int *, void *)); + + static tree hack_stmt; + static var_map hack_map; + static root_var_p hack_rv; + + + /* Look for *s and (*s)_x in the stmt's. Match them up with the VUSES of + versions of s, and replace s with the corerct root variable. */ + + static tree + replace_embedded_vars (tp, walk_subtrees, data) + tree *tp; + int *walk_subtrees ATTRIBUTE_UNUSED; + void *data ATTRIBUTE_UNUSED; + { + tree t = *tp; + size_t i, num_ops; + varray_type ops; + + if (TREE_CODE (t) == INDIRECT_REF) + { + tree var = TREE_OPERAND (t, 0); + tree new_var = NULL_TREE; + int tmp, tmp2; + if (TREE_CODE (var) != SSA_NAME) + { + /* Scan the VUSES, looking for a version of var. */ + ops = vuse_ops (hack_stmt); + num_ops = ((ops) ? VARRAY_ACTIVE_SIZE (ops) : 0); + for (i = 0; i < num_ops; i++) + { + tmp = var_to_partition (hack_map, VARRAY_TREE (ops, i)); + if (tmp == NO_PARTITION) + continue; + tmp2 = find_root_var (hack_rv, tmp); + if (tmp2 != ROOT_VAR_NONE && root_var (hack_rv, tmp2) != var) + { + if (var == SSA_NAME_VAR (VARRAY_TREE (ops, i))) + { + new_var = partition_to_var (hack_map, tmp); + break; + } + } + } + if (new_var != NULL_TREE) + { + tree new_tree = copy_node (t); + TREE_OPERAND (new_tree, 0) = new_var; + *tp = new_tree; ! if (tree_ssa_dump_file) ! { ! print_generic_stmt (tree_ssa_dump_file, hack_stmt, 128); ! fprintf(tree_ssa_dump_file, "\nHACK. Replaced *"); ! print_generic_expr (tree_ssa_dump_file, var, TDF_SLIM); ! fprintf(tree_ssa_dump_file, " with *"); ! print_generic_expr (tree_ssa_dump_file, new_var, TDF_SLIM); ! fprintf(tree_ssa_dump_file, "\n"); ! } ! } ! } ! ! } ! return NULL_TREE; ! } ! #endif ! ! /* Replace *p with whatever variable it has been rewritten to. */ ! ! static void ! replace_variable (map, p) ! var_map map; ! tree *p; ! { ! tree new_var; ! tree var = *p; ! tree copy; ! ! new_var = var_to_partition_to_var (map, var); ! if (new_var) ! *p = new_var; ! else ! { ! /* Replace (*var)_version with just (*var). */ ! if (TREE_CODE (SSA_NAME_VAR (var)) == INDIRECT_REF) ! { ! tree var2 = TREE_OPERAND (SSA_NAME_VAR (var), 0); ! new_var = var_to_partition_to_var (map, var2); ! copy = copy_node (SSA_NAME_VAR (var)); ! if (new_var) ! TREE_OPERAND (copy, 0) = new_var; ! else ! TREE_OPERAND (copy, 0) = var2; ! *p = copy; ! } ! } ! } ! ! ! /* Eliminate any PHI nodes are not used to generate real code. This reduces ! the number of variables in the partition, meaning we will have less ! computations to perform. */ ! ! static void ! eliminate_extraneous_phis () ! { ! tree phi, result, var, last, temp; ! basic_block bb; ! ! /* Look for PHI nodes which result in: ! - A version of the GLOBAL VAR. This is for alising only. ! - A version of an indirect ref. These are load/store alising placeholders. ! All code which is generated will use the variable located *under* the ! INDIRECT_REF. */ ! ! FOR_EACH_BB (bb) ! { ! phi = phi_nodes (bb); ! for (last = NULL; phi; ) ! { ! result = PHI_RESULT (phi); ! var = SSA_NAME_VAR (result); ! if (TREE_CODE (var) == INDIRECT_REF || var == global_var) ! { ! if (tree_ssa_dump_file && (tree_ssa_dump_flags & TDF_DETAILS)) ! { ! fprintf (tree_ssa_dump_file, ! "BB %d. Removing extraneous PHI:", ! bb->index); ! print_generic_stmt (tree_ssa_dump_file, phi, TDF_SLIM); ! fprintf (tree_ssa_dump_file, "\n"); ! } ! temp = phi; ! phi = TREE_CHAIN (phi); ! remove_phi_node (temp, last, bb); ! } ! else ! { ! last = phi; ! phi = TREE_CHAIN (phi); ! } ! } ! } ! } ! /* Take function FNDECL out of SSA form. */ void rewrite_out_of_ssa (fndecl) *************** rewrite_out_of_ssa (fndecl) *** 1594,1604 **** --- 1725,1745 ---- tree phi, next; elim_graph g; int repeat; + #if 1 + /* HACK. */ + root_var_p rv; + #endif + timevar_push (TV_TREE_SSA_TO_NORMAL); tree_ssa_dump_file = dump_begin (TDI_optimized, &tree_ssa_dump_flags); + if (tree_ssa_dump_file && (tree_ssa_dump_flags & TDF_DETAILS)) + dump_tree_cfg (tree_ssa_dump_file, (tree_ssa_dump_flags & ~TDF_DETAILS)); + + eliminate_extraneous_phis (); + map = create_ssa_var_map (); /* Shrink the map to include only referenced variables. Exclude variables *************** rewrite_out_of_ssa (fndecl) *** 1622,1627 **** --- 1763,1775 ---- compact_var_map (map, VARMAP_NORMAL); assign_vars (map); + #if 1 + /* HACK for pointer rename workaround. */ + rv = init_root_var (map); + if (tree_ssa_dump_file) + dump_root_var (tree_ssa_dump_file, rv); + #endif + if (tree_ssa_dump_file && (tree_ssa_dump_flags & TDF_DETAILS)) { fprintf(tree_ssa_dump_file, "After Root variable replacement:\n"); *************** rewrite_out_of_ssa (fndecl) *** 1652,1668 **** for (i = 0; i < num_ops; i++) { use_p = VARRAY_GENERIC_PTR (ops, i); ! *use_p = var_to_partition_to_var (map, *use_p); } if (def_op (stmt)) { tree *def_p = def_op (stmt); ! *def_p = var_to_partition_to_var (map, *def_p); ! if (is_copy && num_ops == 1 && use_p && (*def_p == *use_p)) remove = 1; } /* Remove copies of the form 'var = var'. */ if (remove) --- 1800,1825 ---- for (i = 0; i < num_ops; i++) { use_p = VARRAY_GENERIC_PTR (ops, i); ! replace_variable (map, use_p); } if (def_op (stmt)) { tree *def_p = def_op (stmt); ! replace_variable (map, def_p); ! if (is_copy && num_ops == 1 && use_p && def_p && (*def_p == *use_p)) remove = 1; } + #if 1 + /* HACK. Look for *p = .. and see if the 'p' needs to be renamed. */ + + + hack_stmt = stmt; + hack_map = map; + hack_rv = rv; + walk_tree (&stmt, replace_embedded_vars, NULL, NULL); + #endif /* Remove copies of the form 'var = var'. */ if (remove) *************** rewrite_out_of_ssa (fndecl) *** 1687,1695 **** --- 1844,1861 ---- delete_elim_graph (g); + #if 1 + /* HACK for pointer renaming workaround. */ + if (rv) + delete_root_var (rv); + #endif + /* If any copies were inserted on edges, actually insert them now. */ bsi_commit_edge_inserts (0, NULL); + if (tree_ssa_dump_file && (tree_ssa_dump_flags & TDF_DETAILS)) + dump_tree_cfg (tree_ssa_dump_file, (tree_ssa_dump_flags & ~TDF_DETAILS)); + /* Do some cleanups which reduce the amount of data the tree->rtl expanders deal with. */ do *************** void *** 1765,1771 **** dump_tree_ssa_stats (file) FILE *file; { ! long tmp, n_exprs; fprintf (file, "Total number of statements: %6ld\n\n", ssa_stats.num_stmts); --- 1931,1937 ---- dump_tree_ssa_stats (file) FILE *file; { ! long n_exprs; fprintf (file, "Total number of statements: %6ld\n\n", ssa_stats.num_stmts); *************** dump_tree_ssa_stats (file) *** 1786,1802 **** ssa_stats.num_re, PERCENT (ssa_stats.num_re, n_exprs)); - /* FIXME. [UNSSA] Not needed after SSA->normal pass is working. */ - #if 1 - fprintf (file, " Optimizations blocked by lack of unSSA: %6ld (%.0f%%)\n", - ssa_stats.blocked_optimizations, - PERCENT (ssa_stats.blocked_optimizations, n_exprs)); - - tmp = ssa_stats.blocked_optimizations - ssa_stats.blocked_by_life_crossing; - fprintf (file, " Optimizations blocked due to pruned SSA: %6ld (%.0f%%)\n", - tmp, PERCENT (tmp, n_exprs)); - #endif - fprintf (file, "\nHash table statistics:\n"); fprintf (file, " def_blocks: "); --- 1952,1957 ---- *************** insert_phi_nodes_for (var, dfs, def_maps *** 1983,1989 **** } ! /* Rewrite the statement pointed by iterator SI into SSA form. BLOCK_DEFS_P points to a stack with all the definitions found in the block. This is used by rewrite_block to restore the current reaching --- 2138,2145 ---- } ! /* Rewrite the statement pointed by iterator SI into SSA form. Return ! 1 if the stmt is to be deleted. BLOCK_DEFS_P points to a stack with all the definitions found in the block. This is used by rewrite_block to restore the current reaching *************** insert_phi_nodes_for (var, dfs, def_maps *** 2029,2035 **** replace the constant and copy propagation passes. It only does very simplistic propagation while renaming. */ ! static void rewrite_stmt (si, block_defs_p, block_avail_exprs_p) block_stmt_iterator si; varray_type *block_defs_p; --- 2185,2191 ---- replace the constant and copy propagation passes. It only does very simplistic propagation while renaming. */ ! static int rewrite_stmt (si, block_defs_p, block_avail_exprs_p) block_stmt_iterator si; varray_type *block_defs_p; *************** rewrite_stmt (si, block_defs_p, block_av *** 2043,2049 **** stmt = bsi_stmt (si); if (IS_EMPTY_STMT (stmt)) ! return; ann = stmt_ann (stmt); ssa_stats.num_stmts++; --- 2199,2205 ---- stmt = bsi_stmt (si); if (IS_EMPTY_STMT (stmt)) ! return 0; ann = stmt_ann (stmt); ssa_stats.num_stmts++; *************** rewrite_stmt (si, block_defs_p, block_av *** 2090,2107 **** val = get_value_for (*op_p, const_and_copies); if (val) { - #if 1 - /* FIXME: [UNSSA] Remove the following check after implementing - SSA->normal. For the time being, avoid doing copy propagation - if that would make two versions of VAL to be live at the same - time. */ - if (TREE_CODE (val) == SSA_NAME && !var_is_live (val, ann->bb)) - { - ssa_stats.blocked_optimizations++; - continue; - } - #endif - /* If the replacement is a constant, mark the statement modified because it just lost an operand. */ if (TREE_CONSTANT (val)) --- 2246,2251 ---- *************** rewrite_stmt (si, block_defs_p, block_av *** 2180,2216 **** fprintf (tree_ssa_dump_file, "'\n"); } - /* FIXME: [UNSSA] Re-enable this once the SSA->normal pass is - implemented. Otherwise, this leads to cases where a PHI node - contains arguments from different variables, which is - something we can't handle with the current unSSA pass. It may - also lead to cases where we re-use the LHS of a computation at - a point where more than one version of the LHS is live at the - same time. */ - #if 0 - ssa_stats.num_re++; - TREE_OPERAND (stmt, 1) = cached_lhs; - ann->modified = 1; - #else if (cached_lhs && get_value_for (*def_p, currdefs) == cached_lhs) { /* A redundant assignment to the same lhs, perhaps a new evaluation of an expression temporary that is still live. Just discard it. */ ssa_stats.num_re++; ! bsi_remove (&si); ! return; } ! if (var_is_live (cached_lhs, ann->bb)) ! { ! register_new_def (*def_p, cached_lhs, block_defs_p); ! TREE_OPERAND (stmt, 1) = cached_lhs; ! ann->modified = 1; ! ssa_stats.num_re++; ! } ! else ! ssa_stats.blocked_optimizations++; ! #endif } } --- 2324,2341 ---- fprintf (tree_ssa_dump_file, "'\n"); } if (cached_lhs && get_value_for (*def_p, currdefs) == cached_lhs) { /* A redundant assignment to the same lhs, perhaps a new evaluation of an expression temporary that is still live. Just discard it. */ ssa_stats.num_re++; ! return 1; } ! ! ssa_stats.num_re++; ! TREE_OPERAND (stmt, 1) = cached_lhs; ! ann->modified = 1; } } *************** rewrite_stmt (si, block_defs_p, block_av *** 2243,2248 **** --- 2368,2375 ---- register_new_def (SSA_NAME_VAR (VDEF_RESULT (vdef)), VDEF_RESULT (vdef), block_defs_p); } + + return 0; } *************** get_def_blocks_for (var) *** 2803,2850 **** dm.var = var; return (struct def_blocks_d *) htab_find (def_blocks, (void *) &dm); } - - #if 1 - /* Return true if the variable VAR is live at this point of the - dominator tree walk. This means that the current reaching definition - for VAR is itself and that VAR is livein at basic block BB. - - FIXME: [UNSSA] This will not be necessary when the unSSA pass is - implemented. */ - - static bool - var_is_live (var, bb) - tree var; - basic_block bb; - { - basic_block def_bb; - struct def_blocks_d *def_map; - tree real_var = SSA_NAME_VAR (var); - - if (get_value_for (real_var, currdefs) != var) - { - ssa_stats.blocked_by_life_crossing++; - return false; - } - - /* This is gross, but since it's temporary, close your eyes. It's needed - to avoid miscompiling java/jcf-write.c:generate_classfile, where the - fully pruned SSA form is not inserting PHI nodes in the main loop of - the function for variable 'ptr'. This makes two versions of 'ptr' - live at the same time. - - If there are any blocks between VAR's definition block and BB where - VAR is defined again, then two versions of VAR are live at the same - time. */ - def_map = get_def_blocks_for (real_var); - def_bb = bb_for_stmt (SSA_NAME_DEF_STMT (var)); - if (def_bb && bitmap_first_set_bit (def_map->def_blocks) >= 0) - { - int i; - EXECUTE_IF_SET_IN_BITMAP (def_map->def_blocks, def_bb->index + 1, i, - return ((i < bb->index) ? false : true)); - } - - return true; - } - #endif --- 2930,2932 ----