GCC Middle and Back End API Reference
loop-unroll.c File Reference

Data Structures

struct  iv_to_split
struct  var_to_expand
struct  iv_split_hasher
struct  var_expand_hasher
struct  opt_info

Functions

static void decide_unrolling_and_peeling (int)
static void peel_loops_completely (int)
static void decide_peel_simple (struct loop *, int)
static void decide_peel_once_rolling (struct loop *, int)
static void decide_peel_completely (struct loop *, int)
static void decide_unroll_stupid (struct loop *, int)
static void decide_unroll_constant_iterations (struct loop *, int)
static void decide_unroll_runtime_iterations (struct loop *, int)
static void peel_loop_simple (struct loop *)
static void peel_loop_completely (struct loop *)
static void unroll_loop_stupid (struct loop *)
static void unroll_loop_constant_iterations (struct loop *)
static void unroll_loop_runtime_iterations (struct loop *)
static struct opt_infoanalyze_insns_in_loop (struct loop *)
static void opt_info_start_duplication (struct opt_info *)
static void apply_opt_in_copies (struct opt_info *, unsigned, bool, bool)
static void free_opt_info (struct opt_info *)
static struct var_to_expandanalyze_insn_to_expand_var (struct loop *, rtx)
static bool referenced_in_one_insn_in_loop_p (struct loop *, rtx, int *)
static struct iv_to_splitanalyze_iv_to_split_insn (rtx)
static void expand_var_during_unrolling (struct var_to_expand *, rtx)
static void insert_var_expansion_initialization (struct var_to_expand *, basic_block)
static void combine_var_copies_in_loop_exit (struct var_to_expand *, basic_block)
static rtx get_expansion (struct var_to_expand *)
static void report_unroll_peel ()
void unroll_and_peel_loops ()
static bool loop_exit_at_end_p ()
static void peel_loops_completely ()
static void decide_unrolling_and_peeling ()
static void decide_peel_once_rolling ()
static void decide_peel_completely ()
static void peel_loop_completely ()
static void decide_unroll_constant_iterations ()
static void unroll_loop_constant_iterations ()
static void decide_unroll_runtime_iterations ()
basic_block split_edge_and_insert ()
static void unroll_loop_runtime_iterations ()
static void decide_peel_simple ()
static void peel_loop_simple ()
static void decide_unroll_stupid ()
static void unroll_loop_stupid ()
static void reset_debug_uses_in_loop ()
static struct var_to_expandanalyze_insn_to_expand_var ()
static struct iv_to_splitanalyze_iv_to_split_insn ()
static struct opt_infoanalyze_insns_in_loop ()
static void opt_info_start_duplication ()
static unsigned determine_split_iv_delta ()
static rtxget_ivts_expr ()
static void allocate_basic_variable ()
static void insert_base_initialization ()
static void split_iv ()
static rtx get_expansion ()
static void expand_var_during_unrolling ()
static void combine_var_copies_in_loop_exit ()
static void maybe_strip_eq_note_for_split_iv ()
static void free_opt_info ()

Function Documentation

static void allocate_basic_variable ( )
static
Allocate basic variable for the induction variable chain.   

References iv_to_split::base_var, gen_reg_rtx(), get_ivts_expr(), and iv_to_split::insn.

Referenced by apply_opt_in_copies().

static struct var_to_expand* analyze_insn_to_expand_var ( struct loop ,
rtx   
)
staticread

Referenced by analyze_insns_in_loop().

static struct var_to_expand* analyze_insn_to_expand_var ( )
staticread
Determine whether INSN contains an accumulator
   which can be expanded into separate copies,
   one for each copy of the LOOP body.

   for (i = 0 ; i < n; i++)
     sum += a[i];

   ==>

   sum += a[i]
   ....
   i = i+1;
   sum1 += a[i]
   ....
   i = i+1
   sum2 += a[i];
   ....

   Return NULL if INSN contains no opportunity for expansion of accumulator.
   Otherwise, allocate a VAR_TO_EXPAND structure, fill it with the relevant
   information and return a pointer to it.

References copy_rtx(), dump_file, var_to_expand::expansion_count, have_insn_for(), var_to_expand::insn, var_to_expand::next, var_to_expand::op, print_rtl(), referenced_in_one_insn_in_loop_p(), var_to_expand::reg, reset_debug_uses_in_loop(), var_to_expand::reuse_expansion, rtx_equal_p(), rtx_referenced_p(), and var_to_expand::var_expansions.

static struct opt_info* analyze_insns_in_loop ( struct loop )
staticread
static struct iv_to_split* analyze_iv_to_split_insn ( rtx  )
staticread

Referenced by analyze_insns_in_loop().

static struct iv_to_split* analyze_iv_to_split_insn ( )
staticread
Determine whether there is an induction variable in INSN that
   we would like to split during unrolling.

   I.e. replace

   i = i + 1;
   ...
   i = i + 1;
   ...
   i = i + 1;
   ...

   type chains by

   i0 = i + 1
   ...
   i = i0 + 1
   ...
   i = i0 + 2
   ...

   Return NULL if INSN contains no interesting IVs.  Otherwise, allocate
   an IV_TO_SPLIT structure, fill it with the relevant information and return a
   pointer to it.   

References iv_to_split::base_var, biv_p(), rtx_iv::extend_mode, iv_to_split::insn, iv_analyze_result(), iv_to_split::loc, rtx_iv::mode, iv_to_split::n_loc, iv_to_split::next, iv_to_split::orig_var, iv_to_split::step, and rtx_iv::step.

static void apply_opt_in_copies ( struct opt_info opt_info,
unsigned  n_copies,
bool  unrolling,
bool  rewrite_original_loop 
)
static
static void combine_var_copies_in_loop_exit ( struct var_to_expand ,
basic_block   
)
static

Referenced by apply_opt_in_copies().

static void combine_var_copies_in_loop_exit ( )
static
Combine the variable expansions at the loop exit.  PLACE is the
   loop exit basic block where the summation of the expansions should
   take place.   

References emit_insn_after(), emit_move_insn(), end_sequence(), force_operand(), get_insns(), var_to_expand::insn, var_to_expand::op, var_to_expand::reg, simplify_gen_binary(), start_sequence(), and var_to_expand::var_expansions.

static void decide_peel_completely ( struct loop ,
int   
)
static

Referenced by peel_loops_completely().

static void decide_peel_once_rolling ( struct loop ,
int   
)
static

Referenced by peel_loops_completely().

static void decide_peel_once_rolling ( )
static
static void decide_peel_simple ( struct loop ,
int   
)
static
static void decide_unroll_constant_iterations ( struct loop ,
int   
)
static
static void decide_unroll_runtime_iterations ( struct loop ,
int   
)
static
static void decide_unroll_stupid ( struct loop ,
int   
)
static
static void decide_unrolling_and_peeling ( int  )
static

Referenced by unroll_and_peel_loops().

static unsigned determine_split_iv_delta ( )
static
Determine the number of iterations between initialization of the base
   variable and the current copy (N_COPY).  N_COPIES is the total number
   of newly created copies.  UNROLLING is true if we are unrolling
   (not peeling) the loop.   

Referenced by apply_opt_in_copies().

static void expand_var_during_unrolling ( struct var_to_expand ,
rtx   
)
static

Referenced by apply_opt_in_copies().

static void expand_var_during_unrolling ( )
static
Given INSN replace the uses of the accumulator recorded in VE
   with a new register.   

References apply_change_group(), var_to_expand::expansion_count, gen_reg_rtx(), get_expansion(), var_to_expand::reg, validate_replace_rtx_group(), and var_to_expand::var_expansions.

static rtx get_expansion ( struct var_to_expand )
static
static rtx get_expansion ( )
static
Return one expansion of the accumulator recorded in struct VE.   

References var_to_expand::reg, var_to_expand::reuse_expansion, and var_to_expand::var_expansions.

static rtx* get_ivts_expr ( )
static
Locate in EXPR the expression corresponding to the location recorded
   in IVTS, and return a pointer to the RTX for this location.   

References iv_to_split::loc, and iv_to_split::n_loc.

Referenced by allocate_basic_variable(), insert_base_initialization(), and split_iv().

static void insert_base_initialization ( )
static
Insert initialization of basic variable of IVTS before INSN, taking
   the initial value from INSN.   

References iv_to_split::base_var, copy_rtx(), emit_insn_before(), emit_move_insn(), end_sequence(), force_operand(), get_insns(), get_ivts_expr(), and start_sequence().

Referenced by apply_opt_in_copies().

static void insert_var_expansion_initialization ( struct var_to_expand ve,
basic_block  place 
)
static
Initialize the variable expansions in loop preheader.  PLACE is the
   loop-preheader basic block where the initialization of the
   expansions should take place.  The expansions are initialized with
   (-0) when the operation is plus or minus to honor sign zero.  This
   way we can prevent cases where the sign of the final result is
   effected by the sign of the expansion.  Here is an example to
   demonstrate this:

   for (i = 0 ; i < n; i++)
     sum += something;

   ==>

   sum += something
   ....
   i = i+1;
   sum1 += something
   ....
   i = i+1
   sum2 += something;
   ....

   When SUM is initialized with -zero and SOMETHING is also -zero; the
   final result of sum should be -zero thus the expansions sum1 and sum2
   should be initialized with -zero as well (otherwise we will get +zero
   as the final result).   

References emit_insn_after(), emit_move_insn(), end_sequence(), get_insns(), var_to_expand::op, var_to_expand::reg, simplify_gen_unary(), start_sequence(), and var_to_expand::var_expansions.

Referenced by apply_opt_in_copies().

static bool loop_exit_at_end_p ( )
static
static void maybe_strip_eq_note_for_split_iv ( )
static
Strip away REG_EQUAL notes for IVs we're splitting.

   Updating REG_EQUAL notes for IVs we split is tricky: We
   cannot tell until after unrolling, DF-rescanning, and liveness
   updating, whether an EQ_USE is reached by the split IV while
   the IV reg is still live.  See PR55006.

   ??? We cannot use remove_reg_equal_equiv_notes_for_regno,
   because RTL loop-iv requires us to defer rescanning insns and
   any notes attached to them.  So resort to old techniques...   

References find_reg_equal_equiv_note(), opt_info::iv_to_split_head, iv_to_split::next, iv_to_split::orig_var, reg_mentioned_p(), and remove_note().

Referenced by apply_opt_in_copies().

static void opt_info_start_duplication ( struct opt_info )
static
static void opt_info_start_duplication ( )
static
Called just before loop duplication.  Records start of duplicated area
   to OPT_INFO.   

References opt_info::first_new_block.

static void peel_loop_completely ( struct loop )
static

Referenced by peel_loops_completely().

static void peel_loop_completely ( )
static
Peel all iterations of LOOP, remove exit edges and cancel the loop
   completely.  The transformation done:

   for (i = 0; i < 4; i++)
     body;

   ==>

   i = 0;
   body; i++;
   body; i++;
   body; i++;
   body; i++;

References analyze_insns_in_loop(), apply_opt_in_copies(), bitmap_clear_bit(), bitmap_ones(), dump_file, duplicate_loop_to_header_edge(), free(), free_opt_info(), free_simple_loop_desc(), get_simple_loop_desc(), HOST_WIDE_INT, niter_desc::in_edge, loop_preheader_edge(), niter_desc::niter, niter_desc::noloop_assumptions, opt_info_start_duplication(), niter_desc::out_edge, remove_path(), and sbitmap_alloc().

static void peel_loop_simple ( struct loop )
static

Referenced by unroll_and_peel_loops().

static void peel_loop_simple ( )
static
Peel a LOOP LOOP->LPT_DECISION.TIMES times.  The transformation does this:

   while (cond)
     body;

   ==>  (LOOP->LPT_DECISION.TIMES == 3)

   if (!cond) goto end;
   body;
   if (!cond) goto end;
   body;
   if (!cond) goto end;
   body;
   while (cond)
     body;
   end: ;

References analyze_insns_in_loop(), apply_opt_in_copies(), bitmap_clear(), niter_desc::const_iter, dump_file, duplicate_loop_to_header_edge(), free(), free_opt_info(), free_simple_loop_desc(), get_simple_loop_desc(), loop_preheader_edge(), loop::lpt_decision, niter_desc::niter, niter_desc::niter_expr, niter_desc::noloop_assumptions, opt_info_start_duplication(), sbitmap_alloc(), niter_desc::simple_p, and lpt_decision::times.

static void peel_loops_completely ( int  )
static

Referenced by unroll_and_peel_loops().

bool referenced_in_one_insn_in_loop_p ( struct loop loop,
rtx  reg,
int *  debug_uses 
)
static
Returns true if REG is referenced in one nondebug insn in LOOP.
   Set *DEBUG_USES to the number of debug insns that reference the
   variable.   

References free(), get_loop_body(), loop::num_nodes, and rtx_referenced_p().

Referenced by analyze_insn_to_expand_var().

static void report_unroll_peel ( )
static
Emit a message summarizing the unroll or peel that will be
   performed for LOOP, along with the loop's location LOCUS, if
   appropriate given the dump or -fopt-info settings.   

References niter_desc::const_iter, basic_block_def::count, lpt_decision::decision, dump_enabled_p(), dump_printf(), dump_printf_loc(), expected_loop_iterations(), get_simple_loop_desc(), loop::header, loop::lpt_decision, LPT_NONE, LPT_PEEL_COMPLETELY, LPT_PEEL_SIMPLE, niter_desc::niter, profile_info, and lpt_decision::times.

Referenced by decide_unrolling_and_peeling(), and peel_loops_completely().

static void reset_debug_uses_in_loop ( )
static
Reset the DEBUG_USES debug insns in LOOP that reference REG.   

References free(), get_loop_body(), loop::num_nodes, rtx_referenced_p(), and validate_change().

Referenced by analyze_insn_to_expand_var().

basic_block split_edge_and_insert ( )
Splits edge E and inserts the sequence of instructions INSNS on it, and
   returns the newly created block.  If INSNS is NULL_RTX, nothing is changed
   and NULL is returned instead.   

References emit_insn_after(), and split_edge().

static void split_iv ( )
static
static void unroll_loop_constant_iterations ( struct loop )
static

Referenced by unroll_and_peel_loops().

static void unroll_loop_runtime_iterations ( struct loop )
static

Referenced by unroll_and_peel_loops().

static void unroll_loop_runtime_iterations ( )
static
Unroll LOOP for which we are able to count number of iterations in runtime
   LOOP->LPT_DECISION.TIMES times.  The transformation does this (with some
   extra care for case n < 0):

   for (i = 0; i < n; i++)
     body;

   ==>  (LOOP->LPT_DECISION.TIMES == 3)

   i = 0;
   mod = n % 4;

   switch (mod)
     {
       case 3:
         body; i++;
       case 2:
         body; i++;
       case 1:
         body; i++;
       case 0: ;
     }

   while (i < n)
     {
       body; i++;
       body; i++;
       body; i++;
       body; i++;
     }

References analyze_insns_in_loop(), loop::any_estimate, apply_opt_in_copies(), bitmap_clear(), bitmap_clear_bit(), bitmap_ones(), bitmap_set_bit(), block_label(), CDI_DOMINATORS, compare_and_jump_seq(), niter_desc::const_iter, copy_rtx(), edge_def::count, basic_block_def::count, edge_def::dest, dump_file, duplicate_loop_to_header_edge(), emit_move_insn(), end_sequence(), expand_simple_binop(), flow_bb_inside_loop_p(), force_operand(), free(), free_opt_info(), double_int::from_uhwi(), gen_reg_rtx(), get_bb_copy(), get_dominated_by(), get_insns(), get_loop_body(), get_simple_loop_desc(), niter_desc::in_edge, iterate_fix_dominators(), loop_exit_at_end_p(), loop_latch_edge(), loop_preheader_edge(), loop::lpt_decision, make_edge(), niter_desc::mode, loop::nb_iterations_estimate, loop::nb_iterations_upper_bound, niter_desc::niter, niter_desc::niter_expr, niter_desc::noloop_assumptions, num_loop_insns(), loop::num_nodes, opt_info_start_duplication(), OPTAB_LIB_WIDEN, niter_desc::out_edge, edge_def::probability, remove_path(), sbitmap_alloc(), set_immediate_dominator(), simplify_gen_binary(), single_pred_edge(), single_succ_edge(), split_edge(), split_edge_and_insert(), edge_def::src, start_sequence(), lpt_decision::times, double_int::udiv(), and unshare_all_rtl_in_chain().

static void unroll_loop_stupid ( struct loop )
static

Referenced by unroll_and_peel_loops().

static void unroll_loop_stupid ( )
static
Unroll a LOOP LOOP->LPT_DECISION.TIMES times.  The transformation does this:

   while (cond)
     body;

   ==>  (LOOP->LPT_DECISION.TIMES == 3)

   while (cond)
     {
       body;
       if (!cond) break;
       body;
       if (!cond) break;
       body;
       if (!cond) break;
       body;
     }

References analyze_insns_in_loop(), apply_opt_in_copies(), bitmap_clear(), dump_file, duplicate_loop_to_header_edge(), free(), free_opt_info(), get_simple_loop_desc(), loop_latch_edge(), loop::lpt_decision, num_loop_insns(), opt_info_start_duplication(), sbitmap_alloc(), niter_desc::simple_p, and lpt_decision::times.