This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] Removal of finite empty loops
- From: Zdenek Dvorak <rakdver at atrey dot karlin dot mff dot cuni dot cz>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 17 Jul 2004 00:11:46 +0200
- Subject: [patch] Removal of finite empty loops
Hello,
this patch makes it possible for cddce to remove empty loops provided
that we are able to prove that they are finite. This result is achieved
by marking back edges of those loops for that we are not sure they are
finite. The marking is done in the loop optimizer, by emitting a
special builtin call (BUILT_IN_MAYBE_INFINITE_LOOP) to them.
The reason for splitting of critical edges before cddce is that the
handling of phi nodes sometimes prevented dead loops from being removed
otherwise (if the argument of a live phi node was inside the loop, the loop
was not removed even if the value of the argument was constant or
defined outside of the loop).
Bootstrapped & regtested on i686.
Zdenek
* Makefile.in (tree-ssa-loop.o): Add function.h and SCEV_H dependency.
(tree-ssa-dce.o): Add function.h dependency.
* builtins.c (expand_builtin): Handle BUILT_IN_MAYBE_INFINITE_LOOP.
* builtins.def (BUILT_IN_MAYBE_INFINITE_LOOP): New builtin.
* function.h (struct function): Add marked_maybe_inf_loops field.
* timevar.def (TV_MARK_MILOOPS): New timevar.
* tree-flow.h (mark_maybe_infinite_loops): Declare.
* tree-optimize.c (init_tree_optimization_passes): Add
pass_mark_maybe_inf_loops and pass_record_bounds. Split critical
edges before dce.
* tree-pass.h (pass_mark_maybe_inf_loops, pass_record_bounds): Declare.
* tree-ssa-dce.c: Include function.h.
(find_obviously_necessary_stmts): Mark back edges only if they were
not marked already.
(perform_tree_ssa_dce): Do not call mark_dfs_back_edges here.
* tree-ssa-loop-niter.c (unmark_surely_finite_loop,
mark_maybe_infinite_loops): New functions.
(number_of_iterations_cond): Record assumptions for NE_EXPR
conditions.
* tree-ssa-loop.c: Include function.h and tree-scalar-evolution.h.
(tree_ssa_loop_init): Call scev_initialize.
(tree_mark_maybe_inf_loops, gate_tree_mark_maybe_inf_loops,
pass_mark_maybe_inf_loops, tree_ssa_loop_bounds, pass_record_bounds):
New passes.
(tree_ssa_loop_done): Free the scev info.
* tree-ssa-operands.c (function_ignores_memory_p): New function.
(get_call_expr_operands): Use it.
* fortran/f95-lang.c (gfc_init_builtin_functions): Initialize
BUILT_IN_MAYBE_INFINITE_LOOP builtin.
* java/builtins.c (initialize_builtins): Initialize
BUILT_IN_MAYBE_INFINITE_LOOP builtin.
* testsuite/gcc.dg/tree-ssa/ssa-dce-4.c: New testcase.
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1328
diff -c -3 -p -r1.1328 Makefile.in
*** Makefile.in 16 Jul 2004 17:55:46 -0000 1.1328
--- Makefile.in 16 Jul 2004 21:56:45 -0000
*************** tree-eh.o : tree-eh.c $(TREE_FLOW_H) $(C
*** 1678,1684 ****
tree-ssa-loop.o : tree-ssa-loop.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) \
output.h diagnostic.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
! tree-pass.h $(FLAGS_H) tree-inline.h
tree-ssa-loop-niter.o : tree-ssa-loop-niter.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) cfgloop.h $(PARAMS_H) tree-inline.h \
output.h diagnostic.h $(TM_H) coretypes.h $(TREE_DUMP_H) flags.h \
--- 1678,1684 ----
tree-ssa-loop.o : tree-ssa-loop.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) \
output.h diagnostic.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
! tree-pass.h $(FLAGS_H) tree-inline.h function.h $(SCEV_H)
tree-ssa-loop-niter.o : tree-ssa-loop-niter.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) cfgloop.h $(PARAMS_H) tree-inline.h \
output.h diagnostic.h $(TM_H) coretypes.h $(TREE_DUMP_H) flags.h \
*************** lcm.o : lcm.c $(CONFIG_H) $(SYSTEM_H) co
*** 1907,1913 ****
$(BASIC_BLOCK_H) $(TM_P_H) $(DF_H) function.h
tree-ssa-dce.o : tree-ssa-dce.c $(CONFIG_H) system.h errors.h $(TREE_H) \
$(RTL_H) $(TM_P_H) $(TREE_FLOW_H) diagnostic.h $(TIMEVAR_H) $(TM_H) \
! coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H)
tree-ssa-ccp.o : tree-ssa-ccp.c $(CONFIG_H) system.h errors.h $(TREE_H) \
$(RTL_H) $(TM_P_H) $(TREE_FLOW_H) diagnostic.h tree-inline.h \
$(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_GIMPLE_H) \
--- 1907,1913 ----
$(BASIC_BLOCK_H) $(TM_P_H) $(DF_H) function.h
tree-ssa-dce.o : tree-ssa-dce.c $(CONFIG_H) system.h errors.h $(TREE_H) \
$(RTL_H) $(TM_P_H) $(TREE_FLOW_H) diagnostic.h $(TIMEVAR_H) $(TM_H) \
! coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) function.h
tree-ssa-ccp.o : tree-ssa-ccp.c $(CONFIG_H) system.h errors.h $(TREE_H) \
$(RTL_H) $(TM_P_H) $(TREE_FLOW_H) diagnostic.h tree-inline.h \
$(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_GIMPLE_H) \
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.366
diff -c -3 -p -r1.366 builtins.c
*** builtins.c 16 Jul 2004 17:19:20 -0000 1.366
--- builtins.c 16 Jul 2004 21:56:46 -0000
*************** expand_builtin (tree exp, rtx target, rt
*** 6293,6298 ****
--- 6293,6302 ----
return target;
break;
+ case BUILT_IN_MAYBE_INFINITE_LOOP:
+ /* This is just a fake statement that expands to nothing. */
+ return const0_rtx;
+
default: /* just do library call, if unknown builtin */
break;
}
Index: builtins.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.def,v
retrieving revision 1.88
diff -c -3 -p -r1.88 builtins.def
*** builtins.def 9 Jul 2004 23:04:32 -0000 1.88
--- builtins.def 16 Jul 2004 21:56:46 -0000
*************** DEF_GCC_BUILTIN (BUILT_IN_FRAME_A
*** 573,578 ****
--- 573,579 ----
DEF_GCC_BUILTIN (BUILT_IN_FROB_RETURN_ADDR, "frob_return_addr", BT_FN_PTR_PTR, ATTR_NULL)
DEF_EXT_LIB_BUILTIN (BUILT_IN_GETTEXT, "gettext", BT_FN_STRING_CONST_STRING, ATTR_FORMAT_ARG_1)
DEF_C99_BUILTIN (BUILT_IN_IMAXABS, "imaxabs", BT_FN_INTMAX_INTMAX, ATTR_CONST_NOTHROW_LIST)
+ DEF_GCC_BUILTIN (BUILT_IN_MAYBE_INFINITE_LOOP, "maybe_infinite_loop", BT_FN_VOID, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_INIT_DWARF_REG_SIZES, "init_dwarf_reg_size_table", BT_FN_VOID_PTR, ATTR_NULL)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FINITE, "finite", BT_FN_INT_DOUBLE, ATTR_CONST_NOTHROW_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FINITEF, "finitef", BT_FN_INT_FLOAT, ATTR_CONST_NOTHROW_LIST)
Index: function.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/function.h,v
retrieving revision 1.129
diff -c -3 -p -r1.129 function.h
*** function.h 14 Jul 2004 07:30:15 -0000 1.129
--- function.h 16 Jul 2004 21:56:46 -0000
*************** struct function GTY(())
*** 437,442 ****
--- 437,445 ----
/* Nonzero if code to initialize arg_pointer_save_area has been emitted. */
unsigned int arg_pointer_save_area_init : 1;
+
+ /* Nonzero if the loops that are possibly infinite are marked. */
+ unsigned int marked_maybe_inf_loops : 1;
};
/* The function currently being compiled. */
Index: timevar.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/timevar.def,v
retrieving revision 1.30
diff -c -3 -p -r1.30 timevar.def
*** timevar.def 10 Jul 2004 04:57:54 -0000 1.30
--- timevar.def 16 Jul 2004 21:56:46 -0000
*************** DEFTIMEVAR (TV_TREE_DCE , "tree co
*** 82,87 ****
--- 82,88 ----
DEFTIMEVAR (TV_TREE_CD_DCE , "tree aggressive DCE")
DEFTIMEVAR (TV_TREE_DSE , "tree DSE")
DEFTIMEVAR (TV_TREE_LOOP , "tree loop optimization")
+ DEFTIMEVAR (TV_MARK_MILOOPS , "mark maybe infinite loops")
DEFTIMEVAR (TV_LIM , "loop invariant motion")
DEFTIMEVAR (TV_TREE_CH , "tree copy headers")
DEFTIMEVAR (TV_TREE_SSA_TO_NORMAL , "tree SSA to normal")
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow.h,v
retrieving revision 2.24
diff -c -3 -p -r2.24 tree-flow.h
*** tree-flow.h 16 Jul 2004 20:40:24 -0000 2.24
--- tree-flow.h 16 Jul 2004 21:56:46 -0000
*************** struct tree_niter_desc
*** 628,633 ****
--- 628,634 ----
/* In tree-ssa-loop*.c */
void tree_ssa_lim (struct loops *);
+ void mark_maybe_infinite_loops (struct loops *);
void number_of_iterations_cond (tree, tree, tree, enum tree_code, tree, tree,
struct tree_niter_desc *);
Index: tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 2.30
diff -c -3 -p -r2.30 tree-optimize.c
*** tree-optimize.c 13 Jul 2004 20:39:09 -0000 2.30
--- tree-optimize.c 16 Jul 2004 21:56:46 -0000
*************** init_tree_optimization_passes (void)
*** 314,319 ****
--- 314,320 ----
NEXT_PASS (pass_loop);
NEXT_PASS (DUP_PASS (pass_dominator));
NEXT_PASS (DUP_PASS (pass_redundant_phi));
+ NEXT_PASS (DUP_PASS (pass_split_crit_edges));
NEXT_PASS (pass_cd_dce);
NEXT_PASS (DUP_PASS (pass_dse));
NEXT_PASS (DUP_PASS (pass_forwprop));
*************** init_tree_optimization_passes (void)
*** 329,334 ****
--- 330,337 ----
p = &pass_loop.sub;
NEXT_PASS (pass_loop_init);
NEXT_PASS (pass_lim);
+ NEXT_PASS (pass_record_bounds);
+ NEXT_PASS (pass_mark_maybe_inf_loops);
NEXT_PASS (pass_loop_done);
*p = NULL;
Index: tree-pass.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pass.h,v
retrieving revision 2.5
diff -c -3 -p -r2.5 tree-pass.h
*** tree-pass.h 10 Jul 2004 04:57:54 -0000 2.5
--- tree-pass.h 16 Jul 2004 21:56:46 -0000
*************** extern struct tree_opt_pass pass_tail_ca
*** 108,113 ****
--- 108,115 ----
extern struct tree_opt_pass pass_loop;
extern struct tree_opt_pass pass_loop_init;
extern struct tree_opt_pass pass_lim;
+ extern struct tree_opt_pass pass_record_bounds;
+ extern struct tree_opt_pass pass_mark_maybe_inf_loops;
extern struct tree_opt_pass pass_loop_done;
extern struct tree_opt_pass pass_ch;
extern struct tree_opt_pass pass_ccp;
Index: tree-ssa-dce.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-dce.c,v
retrieving revision 2.9
diff -c -3 -p -r2.9 tree-ssa-dce.c
*** tree-ssa-dce.c 8 Jul 2004 16:16:41 -0000 2.9
--- tree-ssa-dce.c 16 Jul 2004 21:56:46 -0000
*************** Software Foundation, 59 Temple Place - S
*** 64,69 ****
--- 64,70 ----
#include "tree-pass.h"
#include "timevar.h"
#include "flags.h"
+ #include "function.h"
static struct stmt_stats
{
*************** find_obviously_necessary_stmts (struct e
*** 462,471 ****
bb->flags &= ~BB_VISITED;
}
! if (el)
{
! /* Prevent the loops from being removed. We must keep the infinite loops,
! and we currently do not have a means to recognize the finite ones. */
FOR_EACH_BB (bb)
{
for (e = bb->succ; e; e = e->succ_next)
--- 463,476 ----
bb->flags &= ~BB_VISITED;
}
! /* Prevent the possibly infinite loops from being removed. Provided
! that mark_maybe_infinite_loops was run, this happens automatically,
! since fake builtin call statements were inserted on back edges
! of loops for that it is not able to prove that they stop. */
! if (el && !cfun->marked_maybe_inf_loops)
{
! mark_dfs_back_edges ();
!
FOR_EACH_BB (bb)
{
for (e = bb->succ; e; e = e->succ_next)
*************** perform_tree_ssa_dce (bool aggressive)
*** 852,859 ****
el = create_edge_list ();
find_all_control_dependences (el);
timevar_pop (TV_CONTROL_DEPENDENCES);
-
- mark_dfs_back_edges ();
}
find_obviously_necessary_stmts (el);
--- 857,862 ----
Index: tree-ssa-loop-niter.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-loop-niter.c,v
retrieving revision 2.1
diff -c -3 -p -r2.1 tree-ssa-loop-niter.c
*** tree-ssa-loop-niter.c 9 Jul 2004 03:19:14 -0000 2.1
--- tree-ssa-loop-niter.c 16 Jul 2004 21:56:46 -0000
*************** number_of_iterations_cond (tree type, tr
*** 367,372 ****
--- 367,379 ----
convert (niter_type, integer_one_node));
}
+ assumption = fold (build (FLOOR_MOD_EXPR, niter_type, base1, d));
+ assumption = fold (build (EQ_EXPR, boolean_type_node,
+ assumption, convert (niter_type,
+ integer_zero_node)));
+ assumptions = fold (build (TRUTH_AND_EXPR, boolean_type_node,
+ assumptions, assumption));
+
tmp = fold (build (EXACT_DIV_EXPR, niter_type, base1, d));
tmp = fold (build (MULT_EXPR, niter_type, tmp, inverse (s, bound)));
niter->niter = fold (build (BIT_AND_EXPR, niter_type, tmp, bound));
*************** free_numbers_of_iterations_estimates (st
*** 1303,1305 ****
--- 1310,1392 ----
free_numbers_of_iterations_estimates_loop (loop);
}
}
+
+
+ /*
+
+ Removal of loops in DCE.
+
+ */
+
+ /* If we are able to prove that the LOOP always exits, turn off the
+ EDGE_DFS_BACK flag from its latch edge. */
+
+ static void
+ unmark_surely_finite_loop (struct loop *loop)
+ {
+ edge *exits;
+ unsigned i, n_exits;
+ struct tree_niter_desc niter_desc;
+
+ exits = get_loop_exit_edges (loop, &n_exits);
+ for (i = 0; i < n_exits; i++)
+ if (number_of_iterations_exit (loop, exits[i], &niter_desc))
+ {
+ loop_latch_edge (loop)->flags &= ~EDGE_DFS_BACK;
+ return;
+ }
+ }
+
+ /* Emit special statements preventing removal of possibly infinite loops in
+ CD_DCE to the latches of LOOPS for that we are not able to prove that they
+ iterate just finite number of times. */
+
+ void
+ mark_maybe_infinite_loops (struct loops *loops)
+ {
+ unsigned i;
+ struct loop *loop;
+ basic_block bb;
+ edge e;
+ tree stmt;
+ bool inserted = false;
+ block_stmt_iterator bsi;
+
+ mark_dfs_back_edges ();
+
+ for (i = 1; i < loops->num; i++)
+ {
+ loop = loops->parray[i];
+ if (loop)
+ unmark_surely_finite_loop (loop);
+ }
+
+ FOR_EACH_BB (bb)
+ {
+ for (e = bb->succ; e; e = e->succ_next)
+ if (e->flags & EDGE_DFS_BACK)
+ {
+ stmt = build_function_call_expr (built_in_decls[BUILT_IN_MAYBE_INFINITE_LOOP],
+ NULL);
+
+ if (!(e->flags & EDGE_ABNORMAL))
+ {
+ bsi_insert_on_edge (e, stmt);
+ inserted = true;
+ continue;
+ }
+
+ /* We cannot insert on abnormal edge, so insert to the basic block
+ at its start. */
+ bsi = bsi_last (e->src);
+ if (!bsi_end_p (bsi)
+ && stmt_ends_bb_p (bsi_stmt (bsi)))
+ bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
+ else
+ bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
+ }
+ }
+
+ if (inserted)
+ loop_commit_inserts ();
+ }
Index: tree-ssa-loop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-loop.c,v
retrieving revision 2.8
diff -c -3 -p -r2.8 tree-ssa-loop.c
*** tree-ssa-loop.c 10 Jul 2004 04:57:54 -0000 2.8
--- tree-ssa-loop.c 16 Jul 2004 21:56:46 -0000
*************** Software Foundation, 59 Temple Place - S
*** 37,42 ****
--- 37,44 ----
#include "cfgloop.h"
#include "flags.h"
#include "tree-inline.h"
+ #include "function.h"
+ #include "tree-scalar-evolution.h"
/* The loop tree currently optimized. */
*************** static void
*** 93,98 ****
--- 95,103 ----
tree_ssa_loop_init (void)
{
current_loops = tree_loop_optimizer_init (dump_file);
+ if (!current_loops)
+ return;
+ scev_initialize (current_loops);
}
struct tree_opt_pass pass_loop_init =
*************** struct tree_opt_pass pass_loop_init =
*** 111,116 ****
--- 116,149 ----
0 /* todo_flags_finish */
};
+ /* Record bounds on numbers of iterations of loops. */
+
+ static void
+ tree_ssa_loop_bounds (void)
+ {
+ if (!current_loops)
+ return;
+
+ estimate_numbers_of_iterations (current_loops);
+ scev_reset ();
+ }
+
+ struct tree_opt_pass pass_record_bounds =
+ {
+ "bounds", /* name */
+ NULL, /* gate */
+ tree_ssa_loop_bounds, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ PROP_cfg | PROP_ssa, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0 /* todo_flags_finish */
+ };
+
/* Loop invariant motion pass. */
static void
*************** struct tree_opt_pass pass_lim =
*** 144,149 ****
--- 177,217 ----
TODO_dump_func /* todo_flags_finish */
};
+ /* Marks loops that cannot be removed in DCE, since they are possibly
+ infinite. */
+
+ static void
+ tree_mark_maybe_inf_loops (void)
+ {
+ if (!current_loops)
+ return;
+
+ cfun->marked_maybe_inf_loops = 1;
+ mark_maybe_infinite_loops (current_loops);
+ }
+
+ static bool
+ gate_tree_mark_maybe_inf_loops (void)
+ {
+ return (flag_tree_dce != 0 && optimize >= 2);
+ }
+
+ struct tree_opt_pass pass_mark_maybe_inf_loops =
+ {
+ "miloops", /* name */
+ gate_tree_mark_maybe_inf_loops, /* gate */
+ tree_mark_maybe_inf_loops, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_MARK_MILOOPS, /* tv_id */
+ PROP_cfg | PROP_ssa, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func /* todo_flags_finish */
+ };
+
/* Loop optimizer finalization. */
static void
*************** tree_ssa_loop_done (void)
*** 152,157 ****
--- 220,227 ----
if (!current_loops)
return;
+ free_numbers_of_iterations_estimates (current_loops);
+ scev_finalize ();
loop_optimizer_finalize (current_loops,
(dump_flags & TDF_DETAILS ? dump_file : NULL));
current_loops = NULL;
Index: tree-ssa-operands.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-operands.c,v
retrieving revision 2.19
diff -c -3 -p -r2.19 tree-ssa-operands.c
*** tree-ssa-operands.c 16 Jul 2004 21:13:03 -0000 2.19
--- tree-ssa-operands.c 16 Jul 2004 21:56:46 -0000
*************** get_stmt_operands (tree stmt)
*** 830,835 ****
--- 830,858 ----
timevar_pop (TV_TREE_OPS);
}
+ /* Returns true if the function call EXPR does not access memory. */
+
+ static bool
+ function_ignores_memory_p (tree expr)
+ {
+ tree fndecl = get_callee_fndecl (expr);
+ enum built_in_function fcode;
+
+ if (!fndecl || !DECL_BUILT_IN (fndecl))
+ return false;
+
+ fcode = DECL_FUNCTION_CODE (fndecl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_PREFETCH:
+ case BUILT_IN_MAYBE_INFINITE_LOOP:
+ return true;
+
+ default:
+ return false;
+ }
+ }
/* Recursively scan the expression pointed by EXPR_P in statement STMT.
FLAGS is one of the OPF_* constants modifying how to interpret the
*************** get_call_expr_operands (tree stmt, tree
*** 1259,1266 ****
/* A 'pure' or a 'const' functions never call clobber anything.
A 'noreturn' function might, but since we don't return anyway
there is no point in recording that. */
! if (!(call_flags
! & (ECF_PURE | ECF_CONST | ECF_NORETURN)))
add_call_clobber_ops (stmt, prev_vops);
else if (!(call_flags & (ECF_CONST | ECF_NORETURN)))
add_call_read_ops (stmt, prev_vops);
--- 1282,1291 ----
/* A 'pure' or a 'const' functions never call clobber anything.
A 'noreturn' function might, but since we don't return anyway
there is no point in recording that. */
! if (function_ignores_memory_p (expr))
! ;
! else if (!(call_flags
! & (ECF_PURE | ECF_CONST | ECF_NORETURN)))
add_call_clobber_ops (stmt, prev_vops);
else if (!(call_flags & (ECF_CONST | ECF_NORETURN)))
add_call_read_ops (stmt, prev_vops);
Index: fortran/f95-lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/f95-lang.c,v
retrieving revision 1.8
diff -c -3 -p -r1.8 f95-lang.c
*** fortran/f95-lang.c 11 Jul 2004 09:53:05 -0000 1.8
--- fortran/f95-lang.c 16 Jul 2004 21:56:46 -0000
*************** gfc_init_builtin_functions (void)
*** 809,814 ****
--- 809,819 ----
ftype = build_function_type (void_type_node, tmp);
gfc_define_builtin ("__builtin_stack_restore", ftype, BUILT_IN_STACK_RESTORE,
"stack_restore", false);
+
+ ftype = build_function_type (void_type_node, void_list_node);
+ gfc_define_builtin ("__builtin_maybe_infinite_loop", ftype,
+ BUILT_IN_MAYBE_INFINITE_LOOP, "maybe_infinite_loop",
+ false);
}
#undef DEFINE_MATH_BUILTIN
Index: java/builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/builtins.c,v
retrieving revision 1.24
diff -c -3 -p -r1.24 builtins.c
*** java/builtins.c 13 May 2004 06:40:34 -0000 1.24
--- java/builtins.c 16 Jul 2004 21:56:46 -0000
*************** initialize_builtins (void)
*** 161,166 ****
--- 161,167 ----
{
tree double_ftype_double, double_ftype_double_double;
tree float_ftype_float, float_ftype_float_float;
+ tree void_ftype;
tree t;
int i;
*************** initialize_builtins (void)
*** 185,190 ****
--- 186,193 ----
t = tree_cons (NULL_TREE, double_type_node, t);
double_ftype_double_double = build_function_type (double_type_node, t);
+ void_ftype = build_function_type (void_type_node, NULL_TREE);
+
define_builtin (BUILT_IN_FMOD, "__builtin_fmod",
double_ftype_double_double, "fmod");
define_builtin (BUILT_IN_FMODF, "__builtin_fmodf",
*************** initialize_builtins (void)
*** 216,221 ****
--- 219,226 ----
double_ftype_double, "_ZN4java4lang4Math4sqrtEd");
define_builtin (BUILT_IN_TAN, "__builtin_tan",
double_ftype_double, "_ZN4java4lang4Math3tanEd");
+ define_builtin (BUILT_IN_MAYBE_INFINITE_LOOP, "__builtin_maybe_infinite_loop",
+ void_ftype, "__builtin_maybe_infinite_loop");
}
/* If the call matches a builtin, return the
Index: testsuite/gcc.dg/tree-ssa/ssa-dce-4.c
===================================================================
RCS file: testsuite/gcc.dg/tree-ssa/ssa-dce-4.c
diff -N testsuite/gcc.dg/tree-ssa/ssa-dce-4.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.dg/tree-ssa/ssa-dce-4.c 16 Jul 2004 21:56:46 -0000
***************
*** 0 ****
--- 1,31 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -fdump-tree-miloops-details -fdump-tree-optimized" } */
+
+ unsigned foo (void);
+
+ void xxx(void)
+ {
+ unsigned i, n = foo ();
+
+ for (i = 0; i < 100; i++)
+ {
+ /* This loop should be removed. */
+ }
+
+ for (i = 0; i <= n; i++)
+ {
+ /* This loop might be infinite and therefore cannot be removed. */
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ /* This loop should be removed. */
+ }
+ }
+
+ /* Only the middle loop should be marked as necessary. */
+ /* { dg-final { scan-tree-dump-times "__builtin_maybe_infinite_loop" 1 "miloops" } */
+
+ /* And exactly one loop should remain in the final dump. */
+ /* { dg-final { scan-tree-dump-times "if " 1 "optimized" } */
+