GCC Middle and Back End API Reference
tree-ssa-loop-ivcanon.cc File Reference
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "tree.h"
#include "gimple.h"
#include "cfghooks.h"
#include "tree-pass.h"
#include "ssa.h"
#include "cgraph.h"
#include "gimple-pretty-print.h"
#include "fold-const.h"
#include "profile.h"
#include "gimple-iterator.h"
#include "gimple-fold.h"
#include "tree-eh.h"
#include "tree-cfg.h"
#include "tree-ssa-loop-manip.h"
#include "tree-ssa-loop-niter.h"
#include "tree-ssa-loop.h"
#include "tree-into-ssa.h"
#include "cfgloop.h"
#include "tree-chrec.h"
#include "tree-scalar-evolution.h"
#include "tree-inline.h"
#include "tree-cfgcleanup.h"
#include "builtins.h"
#include "tree-ssa-sccvn.h"
#include "tree-vectorizer.h"
#include "dbgcnt.h"
Include dependency graph for tree-ssa-loop-ivcanon.cc:

Data Structures

struct  loop_size


enum  unroll_level { UL_SINGLE_ITER , UL_NO_GROWTH , UL_ALL }


void create_canonical_iv (class loop *loop, edge exit, tree niter, tree *var_before=NULL, tree *var_after=NULL)
static bool constant_after_peeling (tree op, gimple *stmt, class loop *loop)
static bool tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel, struct loop_size *size, int upper_bound)
static unsigned HOST_WIDE_INT estimated_unrolled_size (struct loop_size *size, unsigned HOST_WIDE_INT nunroll)
static edge loop_edge_to_cancel (class loop *loop)
static bool remove_exits_and_undefined_stmts (class loop *loop, unsigned int npeeled)
static bool remove_redundant_iv_tests (class loop *loop)
void unloop_loops (vec< class loop * > &loops_to_unloop, vec< int > &loops_to_unloop_nunroll, vec< edge > &edges_to_remove, bitmap loop_closed_ssa_invalidated, bool *irred_invalidated)
static bool try_unroll_loop_completely (class loop *loop, edge exit, tree niter, bool may_be_zero, enum unroll_level ul, HOST_WIDE_INT maxiter, dump_user_location_t locus, bool allow_peel)
static unsigned HOST_WIDE_INT estimated_peeled_sequence_size (struct loop_size *size, unsigned HOST_WIDE_INT npeel)
void adjust_loop_info_after_peeling (class loop *loop, int npeel, bool precise)
static bool try_peel_loop (class loop *loop, edge exit, tree niter, bool may_be_zero, HOST_WIDE_INT maxiter)
static bool canonicalize_loop_induction_variables (class loop *loop, bool create_iv, enum unroll_level ul, bool try_eval, bool allow_peel)
unsigned int canonicalize_induction_variables (void)
static bool tree_unroll_loops_completely_1 (bool may_increase_size, bool unroll_outer, bitmap father_bbs, class loop *loop)
static unsigned int tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
gimple_opt_passmake_pass_iv_canon (gcc::context *ctxt)
gimple_opt_passmake_pass_complete_unroll (gcc::context *ctxt)
gimple_opt_passmake_pass_complete_unrolli (gcc::context *ctxt)


static vec< loop_ploops_to_unloop
static vec< int > loops_to_unloop_nunroll
static vec< edgeedges_to_remove
static bitmap peeled_loops

Enumeration Type Documentation

◆ unroll_level

Induction variable canonicalization and loop peeling.
   Copyright (C) 2004-2024 Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.

GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
This pass detects the loops that iterate a constant number of times,
adds a canonical induction variable (step -1, tested against 0)
and replaces the exit test.  This enables the less powerful rtl
level analysis to use this information.

This might spoil the code in some cases (by increasing register pressure).
Note that in the case the new variable is not needed, ivopts will get rid
of it, so it might only be a problem when there are no other linear induction
variables.  In that case the created optimization possibilities are likely
to pay up.

We also perform
  - complete unrolling (or peeling) when the loops is rolling few enough
  - simple peeling (i.e. copying few initial iterations prior the loop)
    when number of iteration estimate is known (typically by the profile
Specifies types of loops that may be unrolled.   

Function Documentation

◆ adjust_loop_info_after_peeling()

void adjust_loop_info_after_peeling ( class loop * loop,
int npeel,
bool precise )
Update loop estimates after peeling LOOP by NPEEL.
If PRECISE is false only likely exists were duplicated and thus
do not update any estimates that are supposed to be always reliable.   

References loop::any_estimate, loop::any_likely_upper_bound, loop::any_upper_bound, gcc_unreachable, ggc_alloc(), wi::leu_p(), loop::nb_iterations_estimate, loop::nb_iterations_likely_upper_bound, and loop::nb_iterations_upper_bound.

Referenced by try_peel_loop().

◆ canonicalize_induction_variables()

◆ canonicalize_loop_induction_variables()

static bool canonicalize_loop_induction_variables ( class loop * loop,
bool create_iv,
enum unroll_level ul,
bool try_eval,
bool allow_peel )

◆ constant_after_peeling()

◆ create_canonical_iv()

void create_canonical_iv ( class loop * loop,
edge exit,
tree niter,
tree * var_before = NULL,
tree * var_after = NULL )
Adds a canonical induction variable to LOOP iterating NITER times.  EXIT
is the exit edge whose condition is replaced.  The ssa versions of the new
IV before and after increment will be stored in VAR_BEFORE and VAR_AFTER
if they are not NULL.   

References build_int_cst(), create_iv(), dump_file, dump_flags, EDGE_SUCC, fold_build2, ggc_alloc(), gimple_cond_set_code(), gimple_cond_set_lhs(), gimple_cond_set_rhs(), gsi_last_bb(), NULL_TREE, loop::num, print_generic_expr(), TDF_DETAILS, TDF_SLIM, TREE_TYPE, type(), and update_stmt().

Referenced by canonicalize_loop_induction_variables(), and tree_loop_interchange::interchange_loops().

◆ estimated_peeled_sequence_size()

static unsigned HOST_WIDE_INT estimated_peeled_sequence_size ( struct loop_size * size,
unsigned HOST_WIDE_INT npeel )
Return number of instructions after peeling.   

References loop_size::eliminated_by_peeling, ggc_alloc(), MAX, and loop_size::overall.

Referenced by try_peel_loop().

◆ estimated_unrolled_size()

static unsigned HOST_WIDE_INT estimated_unrolled_size ( struct loop_size * size,
unsigned HOST_WIDE_INT nunroll )
Estimate number of insns of completely unrolled loop.
It is (NUNROLL + 1) * size of loop body with taking into account
the fact that in last copy everything after exit conditional
is dead and that some instructions will be eliminated after

Loop body is likely going to simplify further, this is difficult
to guess, we just decrease the result by 1/3.   

References loop_size::eliminated_by_peeling, ggc_alloc(), loop_size::last_iteration, loop_size::last_iteration_eliminated_by_peeling, and loop_size::overall.

Referenced by try_unroll_loop_completely().

◆ loop_edge_to_cancel()

static edge loop_edge_to_cancel ( class loop * loop)
Loop LOOP is known to not loop.  See if there is an edge in the loop
body that can be remove to make the loop to always exit and at
the same time it does not make any code potentially executed 
during the last iteration dead.  

After complete unrolling we still may get rid of the conditional
on the exit in the last copy even if we have no idea what it does.
This is quite common case for loops of form

  int a[5];
  for (i=0;i<b;i++)

Here we prove the loop to iterate 5 times but we do not know
it from induction variable.

For now we handle only simple case where there is exit condition
just before the latch block and the latch block contains no statements
with side effect that may otherwise terminate the execution of loop
(such as by EH or by terminating the program or longjmp).

In the general case we may want to cancel the paths leading to statements
loop-niter identified as having undefined effect in the last iteration.
The other cases are hopefully rare and will be cleaned up later.   

References EDGE_COUNT, EDGE_SUCC, FOR_EACH_VEC_ELT, gcc_assert, get_loop_exit_edges(), ggc_alloc(), gimple_has_side_effects(), gsi_end_p(), gsi_next(), gsi_start_bb(), gsi_stmt(), loop::header, i, loop::latch, NULL, and basic_block_def::preds.

Referenced by try_unroll_loop_completely().

◆ make_pass_complete_unroll()

gimple_opt_pass * make_pass_complete_unroll ( gcc::context * ctxt)

References ggc_alloc().

◆ make_pass_complete_unrolli()

gimple_opt_pass * make_pass_complete_unrolli ( gcc::context * ctxt)

References ggc_alloc().

◆ make_pass_iv_canon()

gimple_opt_pass * make_pass_iv_canon ( gcc::context * ctxt)

References ggc_alloc().

◆ remove_exits_and_undefined_stmts()

◆ remove_redundant_iv_tests()

◆ tree_estimate_loop_size()

static bool tree_estimate_loop_size ( class loop * loop,
edge exit,
edge edge_to_cancel,
struct loop_size * size,
int upper_bound )

◆ tree_unroll_loops_completely()

◆ tree_unroll_loops_completely_1()

◆ try_peel_loop()

◆ try_unroll_loop_completely()

static bool try_unroll_loop_completely ( class loop * loop,
edge exit,
tree niter,
bool may_be_zero,
enum unroll_level ul,
HOST_WIDE_INT maxiter,
dump_user_location_t locus,
bool allow_peel )
Tries to unroll LOOP completely, i.e. NITER times.
UL determines which loops we are allowed to unroll.
EXIT is the exit of the loop that should be eliminated.
MAXITER specfy bound on number of iterations, -1 if it is
not known or too large for HOST_WIDE_INT.  The location
LOCUS corresponding to the loop is used when emitting
a summary of the unroll to the dump file.   

References profile_probability::always(), bitmap_clear(), bitmap_clear_bit(), bitmap_ones(), loop_size::constant_iv, basic_block_def::count, dbg_cnt(), DLTHE_FLAG_COMPLETTE_PEEL, DLTHE_FLAG_UPDATE_FREQ, dump_enabled_p(), dump_file, dump_flags, dump_printf(), dump_printf_loc(), EDGE_SUCC, edges_to_remove, wi::eq_p(), estimated_unrolled_size(), force_edge_cold(), free_original_copy_tables(), ggc_alloc(), gimple_cond_make_false(), gimple_cond_make_true(), gimple_duplicate_loop_body_to_header_edge(), gsi_last_bb(), loop::header, initialize_original_copy_tables(), profile_count::initialized_p(), loop::inner, wi::leu_p(), loop_edge_to_cancel(), loop_preheader_edge(), loops_to_unloop, loops_to_unloop_nunroll, MSG_OPTIMIZED_LOCATIONS, loop_size::non_call_stmts_on_hot_path, NULL, loop::num, loop_size::num_branches_on_hot_path, loop_size::num_non_pure_calls_on_hot_path, loop_size::num_pure_calls_on_hot_path, loop_size::overall, scale_loop_profile(), TDF_DETAILS, profile_count::to_gcov_type(), wi::to_widest(), TREE_CODE, tree_estimate_loop_size(), tree_fits_uhwi_p(), tree_to_uhwi(), ul, UL_NO_GROWTH, UL_SINGLE_ITER, loop::unroll, and update_stmt().

Referenced by canonicalize_loop_induction_variables().

◆ unloop_loops()

void unloop_loops ( vec< class loop * > & loops_to_unloop,
vec< int > & loops_to_unloop_nunroll,
vec< edge > & edges_to_remove,
bitmap loop_closed_ssa_invalidated,
bool * irred_invalidated )
Cancel all fully unrolled loops by putting __builtin_unreachable
on the latch edge.  
We do it after all unrolling since unlooping moves basic blocks
across loop boundaries trashing loop closed SSA form as well
as SCEV info needed to be intact during unrolling. 

IRRED_INVALIDATED is used to bookkeep if information about
irreducible regions may become invalid as a result
of the transformation.  
LOOP_CLOSED_SSA_INVALIDATED is used to bookkepp the case
when we need to go into loop closed SSA form.   

References add_bb_to_loop(), BASIC_BLOCK_FOR_FN, CDI_DOMINATORS, cfun, create_basic_block(), current_loops, edges_to_remove, FOR_EACH_VEC_ELT, gcc_assert, ggc_alloc(), gimple_build_builtin_unreachable(), gsi_insert_after(), GSI_NEW_STMT, gsi_start_bb(), i, loop::latch, loop_latch_edge(), loops_to_unloop, loops_to_unloop_nunroll, make_edge(), profile_probability::never(), NULL, remove_exits_and_undefined_stmts(), remove_path(), set_immediate_dominator(), unloop(), and profile_count::zero().

Referenced by canonicalize_induction_variables(), and tree_unroll_loops_completely().

Variable Documentation

◆ edges_to_remove

◆ loops_to_unloop

vec<loop_p> loops_to_unloop
Stores loops that will be unlooped and edges that will be removed
after we process whole loop tree.  

Referenced by canonicalize_induction_variables(), tree_unroll_loops_completely(), try_unroll_loop_completely(), and unloop_loops().

◆ loops_to_unloop_nunroll

◆ peeled_loops

bitmap peeled_loops
Stores loops that has been peeled.   

Referenced by try_peel_loop().