aboutsummaryrefslogtreecommitdiffstats
path: root/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99312.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99312.patch')
-rw-r--r--meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99312.patch714
1 files changed, 714 insertions, 0 deletions
diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99312.patch b/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99312.patch
new file mode 100644
index 0000000000..9f0c98e9c9
--- /dev/null
+++ b/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99312.patch
@@ -0,0 +1,714 @@
+2010-07-15 Sandra Loosemore <sandra@codesourcery.com>
+
+ Backport from mainline:
+
+ 2010-06-09 Sandra Loosemore <sandra@codesourcery.com>
+
+ gcc/
+ * tree-ssa-loop-ivopts.c (adjust_setup_cost): New function.
+ (get_computation_cost_at): Use it.
+ (determine_use_iv_cost_condition): Likewise.
+ (determine_iv_cost): Likewise.
+
+ 2010-07-05 Sandra Loosemore <sandra@codesourcery.com>
+
+ PR middle-end/42505
+
+ gcc/
+ * tree-ssa-loop-ivopts.c (determine_set_costs): Delete obsolete
+ comments about cost model.
+ (try_add_cand_for): Add second strategy for choosing initial set
+ based on original IVs, controlled by ORIGINALP argument.
+ (get_initial_solution): Add ORIGINALP argument.
+ (find_optimal_iv_set_1): New function, split from find_optimal_iv_set.
+ (find_optimal_iv_set): Try two different strategies for choosing
+ the IV set, and return the one with lower cost.
+
+ gcc/testsuite/
+ * gcc.target/arm/pr42505.c: New test case.
+
+ 2010-07-10 Sandra Loosemore <sandra@codesourcery.com>
+
+ PR middle-end/42505
+
+ gcc/
+ * tree-inline.c (estimate_num_insns): Refactor builtin complexity
+ lookup code into....
+ * builtins.c (is_simple_builtin, is_inexpensive_builtin): ...these
+ new functions.
+ * tree.h (is_simple_builtin, is_inexpensive_builtin): Declare.
+ * cfgloopanal.c (target_clobbered_regs): Define.
+ (init_set_costs): Initialize target_clobbered_regs.
+ (estimate_reg_pressure_cost): Add call_p argument. When true,
+ adjust the number of available registers to exclude the
+ call-clobbered registers.
+ * cfgloop.h (target_clobbered_regs): Declare.
+ (estimate_reg_pressure_cost): Adjust declaration.
+ * tree-ssa-loop-ivopts.c (struct ivopts_data): Add body_includes_call.
+ (ivopts_global_cost_for_size): Pass it to estimate_reg_pressure_cost.
+ (determine_set_costs): Dump target_clobbered_regs.
+ (loop_body_includes_call): New function.
+ (tree_ssa_iv_optimize_loop): Use it to initialize new field.
+ * loop-invariant.c (gain_for_invariant): Adjust arguments to pass
+ call_p flag through.
+ (best_gain_for_invariant): Likewise.
+ (find_invariants_to_move): Likewise.
+ (move_single_loop_invariants): Likewise, using already-computed
+ has_call field.
+
+ 2010-07-15 Jie Zhang <jie@codesourcery.com>
+
+ Issue #8497, #8893
+
+=== modified file 'gcc/builtins.c'
+--- old/gcc/builtins.c 2010-04-13 12:47:11 +0000
++++ new/gcc/builtins.c 2010-08-02 13:51:23 +0000
+@@ -13624,3 +13624,123 @@
+ break;
+ }
+ }
++
++/* Return true if DECL is a builtin that expands to a constant or similarly
++ simple code. */
++bool
++is_simple_builtin (tree decl)
++{
++ if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
++ switch (DECL_FUNCTION_CODE (decl))
++ {
++ /* Builtins that expand to constants. */
++ case BUILT_IN_CONSTANT_P:
++ case BUILT_IN_EXPECT:
++ case BUILT_IN_OBJECT_SIZE:
++ case BUILT_IN_UNREACHABLE:
++ /* Simple register moves or loads from stack. */
++ case BUILT_IN_RETURN_ADDRESS:
++ case BUILT_IN_EXTRACT_RETURN_ADDR:
++ case BUILT_IN_FROB_RETURN_ADDR:
++ case BUILT_IN_RETURN:
++ case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
++ case BUILT_IN_FRAME_ADDRESS:
++ case BUILT_IN_VA_END:
++ case BUILT_IN_STACK_SAVE:
++ case BUILT_IN_STACK_RESTORE:
++ /* Exception state returns or moves registers around. */
++ case BUILT_IN_EH_FILTER:
++ case BUILT_IN_EH_POINTER:
++ case BUILT_IN_EH_COPY_VALUES:
++ return true;
++
++ default:
++ return false;
++ }
++
++ return false;
++}
++
++/* Return true if DECL is a builtin that is not expensive, i.e., they are
++ most probably expanded inline into reasonably simple code. This is a
++ superset of is_simple_builtin. */
++bool
++is_inexpensive_builtin (tree decl)
++{
++ if (!decl)
++ return false;
++ else if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_MD)
++ return true;
++ else if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
++ switch (DECL_FUNCTION_CODE (decl))
++ {
++ case BUILT_IN_ABS:
++ case BUILT_IN_ALLOCA:
++ case BUILT_IN_BSWAP32:
++ case BUILT_IN_BSWAP64:
++ case BUILT_IN_CLZ:
++ case BUILT_IN_CLZIMAX:
++ case BUILT_IN_CLZL:
++ case BUILT_IN_CLZLL:
++ case BUILT_IN_CTZ:
++ case BUILT_IN_CTZIMAX:
++ case BUILT_IN_CTZL:
++ case BUILT_IN_CTZLL:
++ case BUILT_IN_FFS:
++ case BUILT_IN_FFSIMAX:
++ case BUILT_IN_FFSL:
++ case BUILT_IN_FFSLL:
++ case BUILT_IN_IMAXABS:
++ case BUILT_IN_FINITE:
++ case BUILT_IN_FINITEF:
++ case BUILT_IN_FINITEL:
++ case BUILT_IN_FINITED32:
++ case BUILT_IN_FINITED64:
++ case BUILT_IN_FINITED128:
++ case BUILT_IN_FPCLASSIFY:
++ case BUILT_IN_ISFINITE:
++ case BUILT_IN_ISINF_SIGN:
++ case BUILT_IN_ISINF:
++ case BUILT_IN_ISINFF:
++ case BUILT_IN_ISINFL:
++ case BUILT_IN_ISINFD32:
++ case BUILT_IN_ISINFD64:
++ case BUILT_IN_ISINFD128:
++ case BUILT_IN_ISNAN:
++ case BUILT_IN_ISNANF:
++ case BUILT_IN_ISNANL:
++ case BUILT_IN_ISNAND32:
++ case BUILT_IN_ISNAND64:
++ case BUILT_IN_ISNAND128:
++ case BUILT_IN_ISNORMAL:
++ case BUILT_IN_ISGREATER:
++ case BUILT_IN_ISGREATEREQUAL:
++ case BUILT_IN_ISLESS:
++ case BUILT_IN_ISLESSEQUAL:
++ case BUILT_IN_ISLESSGREATER:
++ case BUILT_IN_ISUNORDERED:
++ case BUILT_IN_VA_ARG_PACK:
++ case BUILT_IN_VA_ARG_PACK_LEN:
++ case BUILT_IN_VA_COPY:
++ case BUILT_IN_TRAP:
++ case BUILT_IN_SAVEREGS:
++ case BUILT_IN_POPCOUNTL:
++ case BUILT_IN_POPCOUNTLL:
++ case BUILT_IN_POPCOUNTIMAX:
++ case BUILT_IN_POPCOUNT:
++ case BUILT_IN_PARITYL:
++ case BUILT_IN_PARITYLL:
++ case BUILT_IN_PARITYIMAX:
++ case BUILT_IN_PARITY:
++ case BUILT_IN_LABS:
++ case BUILT_IN_LLABS:
++ case BUILT_IN_PREFETCH:
++ return true;
++
++ default:
++ return is_simple_builtin (decl);
++ }
++
++ return false;
++}
++
+
+=== modified file 'gcc/cfgloop.h'
+--- old/gcc/cfgloop.h 2009-11-25 10:55:54 +0000
++++ new/gcc/cfgloop.h 2010-08-02 13:51:23 +0000
+@@ -622,13 +622,14 @@
+ /* The properties of the target. */
+
+ extern unsigned target_avail_regs;
++extern unsigned target_clobbered_regs;
+ extern unsigned target_res_regs;
+ extern unsigned target_reg_cost [2];
+ extern unsigned target_spill_cost [2];
+
+ /* Register pressure estimation for induction variable optimizations & loop
+ invariant motion. */
+-extern unsigned estimate_reg_pressure_cost (unsigned, unsigned, bool);
++extern unsigned estimate_reg_pressure_cost (unsigned, unsigned, bool, bool);
+ extern void init_set_costs (void);
+
+ /* Loop optimizer initialization. */
+
+=== modified file 'gcc/cfgloopanal.c'
+--- old/gcc/cfgloopanal.c 2009-09-30 08:57:56 +0000
++++ new/gcc/cfgloopanal.c 2010-08-02 13:51:23 +0000
+@@ -320,6 +320,8 @@
+ /* The properties of the target. */
+
+ unsigned target_avail_regs; /* Number of available registers. */
++unsigned target_clobbered_regs; /* Number of available registers that are
++ call-clobbered. */
+ unsigned target_res_regs; /* Number of registers reserved for temporary
+ expressions. */
+ unsigned target_reg_cost[2]; /* The cost for register when there still
+@@ -342,10 +344,15 @@
+ unsigned i;
+
+ target_avail_regs = 0;
++ target_clobbered_regs = 0;
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i)
+ && !fixed_regs[i])
+- target_avail_regs++;
++ {
++ target_avail_regs++;
++ if (call_used_regs[i])
++ target_clobbered_regs++;
++ }
+
+ target_res_regs = 3;
+
+@@ -379,20 +386,29 @@
+
+ /* Estimates cost of increased register pressure caused by making N_NEW new
+ registers live around the loop. N_OLD is the number of registers live
+- around the loop. */
++ around the loop. If CALL_P is true, also take into account that
++ call-used registers may be clobbered in the loop body, reducing the
++ number of available registers before we spill. */
+
+ unsigned
+-estimate_reg_pressure_cost (unsigned n_new, unsigned n_old, bool speed)
++estimate_reg_pressure_cost (unsigned n_new, unsigned n_old, bool speed,
++ bool call_p)
+ {
+ unsigned cost;
+ unsigned regs_needed = n_new + n_old;
++ unsigned available_regs = target_avail_regs;
++
++ /* If there is a call in the loop body, the call-clobbered registers
++ are not available for loop invariants. */
++ if (call_p)
++ available_regs = available_regs - target_clobbered_regs;
+
+ /* If we have enough registers, we should use them and not restrict
+ the transformations unnecessarily. */
+- if (regs_needed + target_res_regs <= target_avail_regs)
++ if (regs_needed + target_res_regs <= available_regs)
+ return 0;
+
+- if (regs_needed <= target_avail_regs)
++ if (regs_needed <= available_regs)
+ /* If we are close to running out of registers, try to preserve
+ them. */
+ cost = target_reg_cost [speed] * n_new;
+
+=== modified file 'gcc/loop-invariant.c'
+--- old/gcc/loop-invariant.c 2010-04-02 18:54:46 +0000
++++ new/gcc/loop-invariant.c 2010-08-02 13:51:23 +0000
+@@ -1173,11 +1173,13 @@
+ /* Calculates gain for eliminating invariant INV. REGS_USED is the number
+ of registers used in the loop, NEW_REGS is the number of new variables
+ already added due to the invariant motion. The number of registers needed
+- for it is stored in *REGS_NEEDED. */
++ for it is stored in *REGS_NEEDED. SPEED and CALL_P are flags passed
++ through to estimate_reg_pressure_cost. */
+
+ static int
+ gain_for_invariant (struct invariant *inv, unsigned *regs_needed,
+- unsigned *new_regs, unsigned regs_used, bool speed)
++ unsigned *new_regs, unsigned regs_used,
++ bool speed, bool call_p)
+ {
+ int comp_cost, size_cost;
+
+@@ -1188,9 +1190,9 @@
+ if (! flag_ira_loop_pressure)
+ {
+ size_cost = (estimate_reg_pressure_cost (new_regs[0] + regs_needed[0],
+- regs_used, speed)
++ regs_used, speed, call_p)
+ - estimate_reg_pressure_cost (new_regs[0],
+- regs_used, speed));
++ regs_used, speed, call_p));
+ }
+ else
+ {
+@@ -1245,7 +1247,8 @@
+
+ static int
+ best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
+- unsigned *new_regs, unsigned regs_used, bool speed)
++ unsigned *new_regs, unsigned regs_used,
++ bool speed, bool call_p)
+ {
+ struct invariant *inv;
+ int i, gain = 0, again;
+@@ -1261,7 +1264,7 @@
+ continue;
+
+ again = gain_for_invariant (inv, aregs_needed, new_regs, regs_used,
+- speed);
++ speed, call_p);
+ if (again > gain)
+ {
+ gain = again;
+@@ -1314,7 +1317,7 @@
+ /* Determines which invariants to move. */
+
+ static void
+-find_invariants_to_move (bool speed)
++find_invariants_to_move (bool speed, bool call_p)
+ {
+ int gain;
+ unsigned i, regs_used, regs_needed[N_REG_CLASSES], new_regs[N_REG_CLASSES];
+@@ -1353,7 +1356,8 @@
+ new_regs[ira_reg_class_cover[i]] = 0;
+ }
+ while ((gain = best_gain_for_invariant (&inv, regs_needed,
+- new_regs, regs_used, speed)) > 0)
++ new_regs, regs_used,
++ speed, call_p)) > 0)
+ {
+ set_move_mark (inv->invno, gain);
+ if (! flag_ira_loop_pressure)
+@@ -1554,7 +1558,8 @@
+ init_inv_motion_data ();
+
+ find_invariants (loop);
+- find_invariants_to_move (optimize_loop_for_speed_p (loop));
++ find_invariants_to_move (optimize_loop_for_speed_p (loop),
++ LOOP_DATA (loop)->has_call);
+ move_invariants (loop);
+
+ free_inv_motion_data ();
+
+=== added file 'gcc/testsuite/gcc.target/arm/pr42505.c'
+--- old/gcc/testsuite/gcc.target/arm/pr42505.c 1970-01-01 00:00:00 +0000
++++ new/gcc/testsuite/gcc.target/arm/pr42505.c 2010-08-02 13:51:23 +0000
+@@ -0,0 +1,23 @@
++/* { dg-options "-mthumb -Os -march=armv5te" } */
++/* { dg-require-effective-target arm_thumb1_ok } */
++/* { dg-final { scan-assembler-not "str\[\\t \]*r.,\[\\t \]*.sp," } } */
++
++struct A {
++ int f1;
++ int f2;
++};
++
++int func(int c);
++
++/* This function should not need to spill anything to the stack. */
++int test(struct A* src, struct A* dst, int count)
++{
++ while (count--) {
++ if (!func(src->f2)) {
++ return 0;
++ }
++ *dst++ = *src++;
++ }
++
++ return 1;
++}
+
+=== modified file 'gcc/tree-inline.c'
+--- old/gcc/tree-inline.c 2010-03-18 20:07:13 +0000
++++ new/gcc/tree-inline.c 2010-08-02 13:51:23 +0000
+@@ -3246,34 +3246,13 @@
+ if (POINTER_TYPE_P (funtype))
+ funtype = TREE_TYPE (funtype);
+
+- if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_MD)
++ if (is_simple_builtin (decl))
++ return 0;
++ else if (is_inexpensive_builtin (decl))
+ cost = weights->target_builtin_call_cost;
+ else
+ cost = weights->call_cost;
+
+- if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+- switch (DECL_FUNCTION_CODE (decl))
+- {
+- case BUILT_IN_CONSTANT_P:
+- return 0;
+- case BUILT_IN_EXPECT:
+- return 0;
+-
+- /* Prefetch instruction is not expensive. */
+- case BUILT_IN_PREFETCH:
+- cost = weights->target_builtin_call_cost;
+- break;
+-
+- /* Exception state returns or moves registers around. */
+- case BUILT_IN_EH_FILTER:
+- case BUILT_IN_EH_POINTER:
+- case BUILT_IN_EH_COPY_VALUES:
+- return 0;
+-
+- default:
+- break;
+- }
+-
+ if (decl)
+ funtype = TREE_TYPE (decl);
+
+
+=== modified file 'gcc/tree-ssa-loop-ivopts.c'
+--- old/gcc/tree-ssa-loop-ivopts.c 2010-04-01 15:18:07 +0000
++++ new/gcc/tree-ssa-loop-ivopts.c 2010-08-02 13:51:23 +0000
+@@ -257,6 +257,9 @@
+
+ /* Are we optimizing for speed? */
+ bool speed;
++
++ /* Whether the loop body includes any function calls. */
++ bool body_includes_call;
+ };
+
+ /* An assignment of iv candidates to uses. */
+@@ -2926,6 +2929,20 @@
+ return get_computation_at (loop, use, cand, use->stmt);
+ }
+
++/* Adjust the cost COST for being in loop setup rather than loop body.
++ If we're optimizing for space, the loop setup overhead is constant;
++ if we're optimizing for speed, amortize it over the per-iteration cost. */
++static unsigned
++adjust_setup_cost (struct ivopts_data *data, unsigned cost)
++{
++ if (cost == INFTY)
++ return cost;
++ else if (optimize_loop_for_speed_p (data->current_loop))
++ return cost / AVG_LOOP_NITER (data->current_loop);
++ else
++ return cost;
++}
++
+ /* Returns cost of addition in MODE. */
+
+ static unsigned
+@@ -3838,8 +3855,8 @@
+ /* Symbol + offset should be compile-time computable so consider that they
+ are added once to the variable, if present. */
+ if (var_present && (symbol_present || offset))
+- cost.cost += add_cost (TYPE_MODE (ctype), speed)
+- / AVG_LOOP_NITER (data->current_loop);
++ cost.cost += adjust_setup_cost (data,
++ add_cost (TYPE_MODE (ctype), speed));
+
+ /* Having offset does not affect runtime cost in case it is added to
+ symbol, but it increases complexity. */
+@@ -4104,7 +4121,7 @@
+ elim_cost = force_var_cost (data, bound, &depends_on_elim);
+ /* The bound is a loop invariant, so it will be only computed
+ once. */
+- elim_cost.cost /= AVG_LOOP_NITER (data->current_loop);
++ elim_cost.cost = adjust_setup_cost (data, elim_cost.cost);
+ }
+ else
+ elim_cost = infinite_cost;
+@@ -4351,7 +4368,7 @@
+ cost_base = force_var_cost (data, base, NULL);
+ cost_step = add_cost (TYPE_MODE (TREE_TYPE (base)), data->speed);
+
+- cost = cost_step + cost_base.cost / AVG_LOOP_NITER (current_loop);
++ cost = cost_step + adjust_setup_cost (data, cost_base.cost);
+
+ /* Prefer the original ivs unless we may gain something by replacing it.
+ The reason is to make debugging simpler; so this is not relevant for
+@@ -4404,7 +4421,8 @@
+ {
+ /* We add size to the cost, so that we prefer eliminating ivs
+ if possible. */
+- return size + estimate_reg_pressure_cost (size, data->regs_used, data->speed);
++ return size + estimate_reg_pressure_cost (size, data->regs_used, data->speed,
++ data->body_includes_call);
+ }
+
+ /* For each size of the induction variable set determine the penalty. */
+@@ -4419,30 +4437,11 @@
+ struct loop *loop = data->current_loop;
+ bitmap_iterator bi;
+
+- /* We use the following model (definitely improvable, especially the
+- cost function -- TODO):
+-
+- We estimate the number of registers available (using MD data), name it A.
+-
+- We estimate the number of registers used by the loop, name it U. This
+- number is obtained as the number of loop phi nodes (not counting virtual
+- registers and bivs) + the number of variables from outside of the loop.
+-
+- We set a reserve R (free regs that are used for temporary computations,
+- etc.). For now the reserve is a constant 3.
+-
+- Let I be the number of induction variables.
+-
+- -- if U + I + R <= A, the cost is I * SMALL_COST (just not to encourage
+- make a lot of ivs without a reason).
+- -- if A - R < U + I <= A, the cost is I * PRES_COST
+- -- if U + I > A, the cost is I * PRES_COST and
+- number of uses * SPILL_COST * (U + I - A) / (U + I) is added. */
+-
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Global costs:\n");
+ fprintf (dump_file, " target_avail_regs %d\n", target_avail_regs);
++ fprintf (dump_file, " target_clobbered_regs %d\n", target_clobbered_regs);
+ fprintf (dump_file, " target_reg_cost %d\n", target_reg_cost[data->speed]);
+ fprintf (dump_file, " target_spill_cost %d\n", target_spill_cost[data->speed]);
+ }
+@@ -5062,11 +5061,13 @@
+ }
+
+ /* Tries to extend the sets IVS in the best possible way in order
+- to express the USE. */
++ to express the USE. If ORIGINALP is true, prefer candidates from
++ the original set of IVs, otherwise favor important candidates not
++ based on any memory object. */
+
+ static bool
+ try_add_cand_for (struct ivopts_data *data, struct iv_ca *ivs,
+- struct iv_use *use)
++ struct iv_use *use, bool originalp)
+ {
+ comp_cost best_cost, act_cost;
+ unsigned i;
+@@ -5085,7 +5086,8 @@
+ iv_ca_set_no_cp (data, ivs, use);
+ }
+
+- /* First try important candidates not based on any memory object. Only if
++ /* If ORIGINALP is true, try to find the original IV for the use. Otherwise
++ first try important candidates not based on any memory object. Only if
+ this fails, try the specific ones. Rationale -- in loops with many
+ variables the best choice often is to use just one generic biv. If we
+ added here many ivs specific to the uses, the optimization algorithm later
+@@ -5097,7 +5099,10 @@
+ {
+ cand = iv_cand (data, i);
+
+- if (cand->iv->base_object != NULL_TREE)
++ if (originalp && cand->pos !=IP_ORIGINAL)
++ continue;
++
++ if (!originalp && cand->iv->base_object != NULL_TREE)
+ continue;
+
+ if (iv_ca_cand_used_p (ivs, cand))
+@@ -5133,8 +5138,13 @@
+ continue;
+
+ /* Already tried this. */
+- if (cand->important && cand->iv->base_object == NULL_TREE)
+- continue;
++ if (cand->important)
++ {
++ if (originalp && cand->pos == IP_ORIGINAL)
++ continue;
++ if (!originalp && cand->iv->base_object == NULL_TREE)
++ continue;
++ }
+
+ if (iv_ca_cand_used_p (ivs, cand))
+ continue;
+@@ -5168,13 +5178,13 @@
+ /* Finds an initial assignment of candidates to uses. */
+
+ static struct iv_ca *
+-get_initial_solution (struct ivopts_data *data)
++get_initial_solution (struct ivopts_data *data, bool originalp)
+ {
+ struct iv_ca *ivs = iv_ca_new (data);
+ unsigned i;
+
+ for (i = 0; i < n_iv_uses (data); i++)
+- if (!try_add_cand_for (data, ivs, iv_use (data, i)))
++ if (!try_add_cand_for (data, ivs, iv_use (data, i), originalp))
+ {
+ iv_ca_free (&ivs);
+ return NULL;
+@@ -5246,14 +5256,12 @@
+ solution and remove the unused ivs while this improves the cost. */
+
+ static struct iv_ca *
+-find_optimal_iv_set (struct ivopts_data *data)
++find_optimal_iv_set_1 (struct ivopts_data *data, bool originalp)
+ {
+- unsigned i;
+ struct iv_ca *set;
+- struct iv_use *use;
+
+ /* Get the initial solution. */
+- set = get_initial_solution (data);
++ set = get_initial_solution (data, originalp);
+ if (!set)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+@@ -5276,11 +5284,46 @@
+ }
+ }
+
++ return set;
++}
++
++static struct iv_ca *
++find_optimal_iv_set (struct ivopts_data *data)
++{
++ unsigned i;
++ struct iv_ca *set, *origset;
++ struct iv_use *use;
++ comp_cost cost, origcost;
++
++ /* Determine the cost based on a strategy that starts with original IVs,
++ and try again using a strategy that prefers candidates not based
++ on any IVs. */
++ origset = find_optimal_iv_set_1 (data, true);
++ set = find_optimal_iv_set_1 (data, false);
++
++ if (!origset && !set)
++ return NULL;
++
++ origcost = origset ? iv_ca_cost (origset) : infinite_cost;
++ cost = set ? iv_ca_cost (set) : infinite_cost;
++
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+- comp_cost cost = iv_ca_cost (set);
+- fprintf (dump_file, "Final cost %d (complexity %d)\n\n", cost.cost, cost.complexity);
+- }
++ fprintf (dump_file, "Original cost %d (complexity %d)\n\n",
++ origcost.cost, origcost.complexity);
++ fprintf (dump_file, "Final cost %d (complexity %d)\n\n",
++ cost.cost, cost.complexity);
++ }
++
++ /* Choose the one with the best cost. */
++ if (compare_costs (origcost, cost) <= 0)
++ {
++ if (set)
++ iv_ca_free (&set);
++ set = origset;
++ }
++ else if (origset)
++ iv_ca_free (&origset);
+
+ for (i = 0; i < n_iv_uses (data); i++)
+ {
+@@ -5768,6 +5811,25 @@
+ VEC_free (iv_cand_p, heap, data->iv_candidates);
+ }
+
++/* Returns true if the loop body BODY includes any function calls. */
++
++static bool
++loop_body_includes_call (basic_block *body, unsigned num_nodes)
++{
++ gimple_stmt_iterator gsi;
++ unsigned i;
++
++ for (i = 0; i < num_nodes; i++)
++ for (gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi); gsi_next (&gsi))
++ {
++ gimple stmt = gsi_stmt (gsi);
++ if (is_gimple_call (stmt)
++ && !is_inexpensive_builtin (gimple_call_fndecl (stmt)))
++ return true;
++ }
++ return false;
++}
++
+ /* Optimizes the LOOP. Returns true if anything changed. */
+
+ static bool
+@@ -5799,6 +5861,7 @@
+ }
+
+ body = get_loop_body (loop);
++ data->body_includes_call = loop_body_includes_call (body, loop->num_nodes);
+ renumber_gimple_stmt_uids_in_blocks (body, loop->num_nodes);
+ free (body);
+
+
+=== modified file 'gcc/tree.h'
+--- old/gcc/tree.h 2010-04-02 18:54:46 +0000
++++ new/gcc/tree.h 2010-08-02 13:51:23 +0000
+@@ -4962,6 +4962,8 @@
+ extern bool merge_ranges (int *, tree *, tree *, int, tree, tree, int,
+ tree, tree);
+ extern void set_builtin_user_assembler_name (tree decl, const char *asmspec);
++extern bool is_simple_builtin (tree);
++extern bool is_inexpensive_builtin (tree);
+
+ /* In convert.c */
+ extern tree strip_float_extensions (tree);
+