+/* Given INSN replace the uses of the accumulator recorded in VE
+ with a new register. */
+
+static void
+expand_var_during_unrolling (struct var_to_expand *ve, rtx insn)
+{
+ rtx new_reg, set;
+ bool really_new_expansion = false;
+
+ set = single_set (insn);
+ if (!set)
+ abort ();
+
+ /* Generate a new register only if the expansion limit has not been
+ reached. Else reuse an already existing expansion. */
+ if (PARAM_VALUE (PARAM_MAX_VARIABLE_EXPANSIONS) > ve->expansion_count)
+ {
+ really_new_expansion = true;
+ new_reg = gen_reg_rtx (GET_MODE (ve->reg));
+ }
+ else
+ new_reg = get_expansion (ve);
+
+ validate_change (insn, &SET_DEST (set), new_reg, 1);
+ validate_change (insn, &XEXP (SET_SRC (set), 0), new_reg, 1);
+
+ if (apply_change_group ())
+ if (really_new_expansion)
+ {
+ VARRAY_PUSH_RTX (ve->var_expansions, new_reg);
+ ve->expansion_count++;
+ }
+}
+
+/* Initialize the variable expansions in loop preheader.
+ Callbacks for htab_traverse. PLACE_P is the loop-preheader
+ basic block where the initialization of the expansions
+ should take place. */
+
+static int
+insert_var_expansion_initialization (void **slot, void *place_p)
+{
+ struct var_to_expand *ve = *slot;
+ basic_block place = (basic_block)place_p;
+ rtx seq, var, zero_init, insn;
+ unsigned i;
+
+ if (VARRAY_ACTIVE_SIZE (ve->var_expansions) == 0)
+ return 1;
+
+ start_sequence ();
+ if (ve->op == PLUS || ve->op == MINUS)
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+ {
+ var = VARRAY_RTX (ve->var_expansions, i);
+ zero_init = CONST0_RTX (GET_MODE (var));
+ emit_move_insn (var, zero_init);
+ }
+ else if (ve->op == MULT)
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+ {
+ var = VARRAY_RTX (ve->var_expansions, i);
+ zero_init = CONST1_RTX (GET_MODE (var));
+ emit_move_insn (var, zero_init);
+ }
+
+ seq = get_insns ();
+ end_sequence ();
+
+ insn = BB_HEAD (place);
+ while (!NOTE_INSN_BASIC_BLOCK_P (insn))
+ insn = NEXT_INSN (insn);
+
+ emit_insn_after (seq, insn);
+ /* Continue traversing the hash table. */
+ return 1;
+}
+
+/* Combine the variable expansions at the loop exit.
+ Callbacks for htab_traverse. PLACE_P is the loop exit
+ basic block where the summation of the expansions should
+ take place. */
+
+static int
+combine_var_copies_in_loop_exit (void **slot, void *place_p)
+{
+ struct var_to_expand *ve = *slot;
+ basic_block place = (basic_block)place_p;
+ rtx sum = ve->reg;
+ rtx expr, seq, var, insn;
+ unsigned i;
+
+ if (VARRAY_ACTIVE_SIZE (ve->var_expansions) == 0)
+ return 1;
+
+ start_sequence ();
+ if (ve->op == PLUS || ve->op == MINUS)
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+ {
+ var = VARRAY_RTX (ve->var_expansions, i);
+ sum = simplify_gen_binary (PLUS, GET_MODE (ve->reg),
+ var, sum);
+ }
+ else if (ve->op == MULT)
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+ {
+ var = VARRAY_RTX (ve->var_expansions, i);
+ sum = simplify_gen_binary (MULT, GET_MODE (ve->reg),
+ var, sum);
+ }
+
+ expr = force_operand (sum, ve->reg);
+ if (expr != ve->reg)
+ emit_move_insn (ve->reg, expr);
+ seq = get_insns ();
+ end_sequence ();
+
+ insn = BB_HEAD (place);
+ while (!NOTE_INSN_BASIC_BLOCK_P (insn))
+ insn = NEXT_INSN (insn);
+
+ emit_insn_after (seq, insn);
+
+ /* Continue traversing the hash table. */
+ return 1;
+}
+
+/* Apply loop optimizations in loop copies using the
+ data which gathered during the unrolling. Structure
+ OPT_INFO record that data.
+