00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "config.h"
00037 #include "system.h"
00038 #include "coretypes.h"
00039 #include "tm.h"
00040 #include "tree.h"
00041 #include "rtl.h"
00042 #include "tm_p.h"
00043 #include "hard-reg-set.h"
00044 #include "basic-block.h"
00045 #include "output.h"
00046 #include "diagnostic.h"
00047 #include "tree-flow.h"
00048 #include "tree-dump.h"
00049 #include "cfgloop.h"
00050 #include "tree-pass.h"
00051 #include "ggc.h"
00052 #include "tree-chrec.h"
00053 #include "tree-scalar-evolution.h"
00054 #include "params.h"
00055 #include "flags.h"
00056 #include "tree-inline.h"
00057
00058
00059
00060
00061 static void
00062 create_canonical_iv (struct loop *loop, edge exit, tree niter)
00063 {
00064 edge in;
00065 tree cond, type, var;
00066 block_stmt_iterator incr_at;
00067 enum tree_code cmp;
00068
00069 if (dump_file && (dump_flags & TDF_DETAILS))
00070 {
00071 fprintf (dump_file, "Added canonical iv to loop %d, ", loop->num);
00072 print_generic_expr (dump_file, niter, TDF_SLIM);
00073 fprintf (dump_file, " iterations.\n");
00074 }
00075
00076 cond = last_stmt (exit->src);
00077 in = EDGE_SUCC (exit->src, 0);
00078 if (in == exit)
00079 in = EDGE_SUCC (exit->src, 1);
00080
00081
00082
00083
00084
00085
00086 type = TREE_TYPE (niter);
00087 niter = fold (build2 (PLUS_EXPR, type,
00088 niter,
00089 build_int_cst (type, 1)));
00090 incr_at = bsi_last (in->src);
00091 create_iv (niter,
00092 fold_convert (type, integer_minus_one_node),
00093 NULL_TREE, loop,
00094 &incr_at, false, NULL, &var);
00095
00096 cmp = (exit->flags & EDGE_TRUE_VALUE) ? EQ_EXPR : NE_EXPR;
00097 COND_EXPR_COND (cond) = build2 (cmp, boolean_type_node,
00098 var,
00099 build_int_cst (type, 0));
00100 modify_stmt (cond);
00101 }
00102
00103
00104
00105 unsigned
00106 tree_num_loop_insns (struct loop *loop)
00107 {
00108 basic_block *body = get_loop_body (loop);
00109 block_stmt_iterator bsi;
00110 unsigned size = 1, i;
00111
00112 for (i = 0; i < loop->num_nodes; i++)
00113 for (bsi = bsi_start (body[i]); !bsi_end_p (bsi); bsi_next (&bsi))
00114 size += estimate_num_insns (bsi_stmt (bsi));
00115 free (body);
00116
00117 return size;
00118 }
00119
00120
00121
00122
00123
00124
00125 static bool
00126 try_unroll_loop_completely (struct loops *loops ATTRIBUTE_UNUSED,
00127 struct loop *loop,
00128 edge exit, tree niter,
00129 bool completely_unroll)
00130 {
00131 unsigned HOST_WIDE_INT n_unroll, ninsns, max_unroll;
00132 tree old_cond, cond, dont_exit, do_exit;
00133
00134 if (loop->inner)
00135 return false;
00136
00137 if (!host_integerp (niter, 1))
00138 return false;
00139 n_unroll = tree_low_cst (niter, 1);
00140
00141 max_unroll = PARAM_VALUE (PARAM_MAX_COMPLETELY_PEEL_TIMES);
00142 if (n_unroll > max_unroll)
00143 return false;
00144
00145 if (n_unroll)
00146 {
00147 if (!completely_unroll)
00148 return false;
00149
00150 ninsns = tree_num_loop_insns (loop);
00151
00152 if (n_unroll * ninsns
00153 > (unsigned) PARAM_VALUE (PARAM_MAX_COMPLETELY_PEELED_INSNS))
00154 return false;
00155 }
00156
00157 if (exit->flags & EDGE_TRUE_VALUE)
00158 {
00159 dont_exit = boolean_false_node;
00160 do_exit = boolean_true_node;
00161 }
00162 else
00163 {
00164 dont_exit = boolean_true_node;
00165 do_exit = boolean_false_node;
00166 }
00167 cond = last_stmt (exit->src);
00168
00169 if (n_unroll)
00170 {
00171 old_cond = COND_EXPR_COND (cond);
00172 COND_EXPR_COND (cond) = dont_exit;
00173 modify_stmt (cond);
00174
00175 if (!tree_duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
00176 loops, n_unroll, NULL,
00177 NULL, NULL, NULL, 0))
00178 {
00179 COND_EXPR_COND (cond) = old_cond;
00180 return false;
00181 }
00182 }
00183
00184 COND_EXPR_COND (cond) = do_exit;
00185 modify_stmt (cond);
00186
00187 if (dump_file && (dump_flags & TDF_DETAILS))
00188 fprintf (dump_file, "Unrolled loop %d completely.\n", loop->num);
00189
00190 return true;
00191 }
00192
00193
00194
00195
00196
00197
00198
00199 static bool
00200 canonicalize_loop_induction_variables (struct loops *loops, struct loop *loop,
00201 bool create_iv, bool completely_unroll,
00202 bool try_eval)
00203 {
00204 edge exit = NULL;
00205 tree niter;
00206
00207 niter = number_of_iterations_in_loop (loop);
00208 if (TREE_CODE (niter) == INTEGER_CST)
00209 {
00210 exit = loop->single_exit;
00211 if (!just_once_each_iteration_p (loop, exit->src))
00212 return false;
00213
00214
00215
00216
00217 niter = fold (build2 (MINUS_EXPR, TREE_TYPE (niter), niter,
00218 build_int_cst (TREE_TYPE (niter), 1)));
00219 }
00220 else
00221 {
00222
00223
00224 if (!loop->single_exit)
00225 niter = find_loop_niter (loop, &exit);
00226
00227
00228 if (try_eval
00229 && (chrec_contains_undetermined (niter)
00230 || TREE_CODE (niter) != INTEGER_CST))
00231 niter = find_loop_niter_by_eval (loop, &exit);
00232
00233 if (chrec_contains_undetermined (niter)
00234 || TREE_CODE (niter) != INTEGER_CST)
00235 return false;
00236 }
00237
00238 if (dump_file && (dump_flags & TDF_DETAILS))
00239 {
00240 fprintf (dump_file, "Loop %d iterates ", loop->num);
00241 print_generic_expr (dump_file, niter, TDF_SLIM);
00242 fprintf (dump_file, " times.\n");
00243 }
00244
00245 if (try_unroll_loop_completely (loops, loop, exit, niter, completely_unroll))
00246 return true;
00247
00248 if (create_iv)
00249 create_canonical_iv (loop, exit, niter);
00250
00251 return false;
00252 }
00253
00254
00255
00256
00257 void
00258 canonicalize_induction_variables (struct loops *loops)
00259 {
00260 unsigned i;
00261 struct loop *loop;
00262
00263 for (i = 1; i < loops->num; i++)
00264 {
00265 loop = loops->parray[i];
00266
00267 if (loop)
00268 canonicalize_loop_induction_variables (loops, loop, true, false, true);
00269 }
00270
00271
00272
00273 scev_reset ();
00274
00275 #if 0
00276
00277 if (changed)
00278 cleanup_tree_cfg_loop ();
00279 #endif
00280 }
00281
00282
00283
00284 void
00285 tree_unroll_loops_completely (struct loops *loops)
00286 {
00287 unsigned i;
00288 struct loop *loop;
00289 bool changed = false;
00290
00291 for (i = 1; i < loops->num; i++)
00292 {
00293 loop = loops->parray[i];
00294
00295 if (!loop)
00296 continue;
00297
00298 changed |= canonicalize_loop_induction_variables (loops, loop,
00299 false, true,
00300 !flag_tree_loop_ivcanon);
00301 }
00302
00303
00304
00305 scev_reset ();
00306
00307 #if 0
00308
00309 if (changed)
00310 cleanup_tree_cfg_loop ();
00311 #endif
00312 }