GCC Middle and Back End API Reference
cfgcleanup.cc File Reference
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "target.h"
#include "rtl.h"
#include "tree.h"
#include "cfghooks.h"
#include "df.h"
#include "memmodel.h"
#include "tm_p.h"
#include "insn-config.h"
#include "emit-rtl.h"
#include "cselib.h"
#include "tree-pass.h"
#include "cfgloop.h"
#include "cfgrtl.h"
#include "cfganal.h"
#include "cfgbuild.h"
#include "cfgcleanup.h"
#include "dce.h"
#include "dbgcnt.h"
#include "rtl-iter.h"
#include "regs.h"
#include "function-abi.h"
#include "reg-notes.def"
Include dependency graph for cfgcleanup.cc:

Macros

#define FORWARDER_BLOCK_P(BB)   ((BB)->flags & BB_FORWARDER_BLOCK)
 
#define DEF_REG_NOTE(NAME)   false,
 
#define REG_CFA_NOTE(NAME)   true,
 

Functions

static bool try_crossjump_to_edge (int, edge, edge, enum replace_direction)
 
static bool try_crossjump_bb (int, basic_block)
 
static bool outgoing_edges_match (int, basic_block, basic_block)
 
static enum replace_direction old_insns_match_p (int, rtx_insn *, rtx_insn *)
 
static void merge_blocks_move_predecessor_nojumps (basic_block, basic_block)
 
static void merge_blocks_move_successor_nojumps (basic_block, basic_block)
 
static bool try_optimize_cfg (int)
 
static bool try_simplify_condjump (basic_block)
 
static bool try_forward_edges (int, basic_block)
 
static edge thread_jump (edge, basic_block)
 
static bool mark_effect (rtx, bitmap)
 
static void notice_new_block (basic_block)
 
static void update_forwarder_flag (basic_block)
 
static void merge_memattrs (rtx, rtx)
 
static bool mentions_nonequal_regs (const_rtx x, regset nonequal)
 
static basic_block merge_blocks_move (edge e, basic_block b, basic_block c, int mode)
 
static bool equal_different_set_p (rtx p1, rtx s1, rtx p2, rtx s2)
 
static int values_equal_p (rtx note1, rtx note2, rtx src1, rtx src2)
 
static enum replace_direction can_replace_by (rtx_insn *i1, rtx_insn *i2)
 
static enum replace_direction merge_dir (enum replace_direction a, enum replace_direction b)
 
static bool insns_have_identical_cfa_notes (rtx_insn *i1, rtx_insn *i2)
 
static void merge_notes (rtx_insn *i1, rtx_insn *i2)
 
static void walk_to_nondebug_insn (rtx_insn **i1, basic_block *bb1, bool follow_fallthru, bool *did_fallthru)
 
int flow_find_cross_jump (basic_block bb1, basic_block bb2, rtx_insn **f1, rtx_insn **f2, enum replace_direction *dir_p)
 
int flow_find_head_matching_sequence (basic_block bb1, basic_block bb2, rtx_insn **f1, rtx_insn **f2, int stop_after)
 
static bool block_has_preserve_label (basic_block bb)
 
static bool try_head_merge_bb (basic_block bb)
 
static bool trivially_empty_bb_p (basic_block bb)
 
bool bb_is_just_return (basic_block bb, rtx_insn **ret, rtx_insn **use)
 
bool delete_unreachable_blocks (void)
 
void delete_dead_jumptables (void)
 
bool cleanup_cfg (int mode)
 
rtl_opt_passmake_pass_jump (gcc::context *ctxt)
 
rtl_opt_passmake_pass_jump_after_combine (gcc::context *ctxt)
 
rtl_opt_passmake_pass_jump2 (gcc::context *ctxt)
 

Variables

static bool first_pass
 
static bool crossjumps_occurred
 
static bool block_was_dirty
 
static const bool reg_note_cfa_p []
 

Macro Definition Documentation

◆ DEF_REG_NOTE

#define DEF_REG_NOTE ( NAME)    false,

◆ FORWARDER_BLOCK_P

#define FORWARDER_BLOCK_P ( BB)    ((BB)->flags & BB_FORWARDER_BLOCK)
Control flow optimization code for GNU compiler.
   Copyright (C) 1987-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
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
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
<http://www.gnu.org/licenses/>.   
This file contains optimizer of the control flow.  The main entry point is
cleanup_cfg.  Following optimizations are performed:

- Unreachable blocks removal
- Edge forwarding (edge to the forwarder block is forwarded to its
  successor.  Simplification of the branch instruction is performed by
  underlying infrastructure so branch can be converted to simplejump or
  eliminated).
- Cross jumping (tail merging)
- Conditional jump-around-simplejump simplification
- Basic block merging.   

Referenced by merge_blocks_move(), outgoing_edges_match(), try_crossjump_to_edge(), try_forward_edges(), try_optimize_cfg(), and try_simplify_condjump().

◆ REG_CFA_NOTE

#define REG_CFA_NOTE ( NAME)    true,

Function Documentation

◆ bb_is_just_return()

bool bb_is_just_return ( basic_block bb,
rtx_insn ** ret,
rtx_insn ** use )
Return true if BB contains just a return and possibly a USE of the
return value.  Fill in *RET and *USE with the return and use insns
if any found, otherwise NULL.  All CLOBBERs are ignored.   

References ANY_RETURN_P, cfun, EXIT_BLOCK_PTR_FOR_FN, FOR_BB_INSNS_REVERSE, GET_CODE, ggc_alloc(), NONDEBUG_INSN_P, NULL, PATTERN(), REG_FUNCTION_VALUE_P, REG_P, and XEXP.

Referenced by fixup_reorder_chain(), and try_optimize_cfg().

◆ block_has_preserve_label()

static bool block_has_preserve_label ( basic_block bb)
static
Returns true if BB basic block has a preserve label.   

References block_label(), and LABEL_PRESERVE_P.

Referenced by try_crossjump_to_edge().

◆ can_replace_by()

static enum replace_direction can_replace_by ( rtx_insn * i1,
rtx_insn * i2 )
static
Examine register notes on I1 and I2 and return:
- dir_forward if I1 can be replaced by I2, or
- dir_backward if I2 can be replaced by I1, or
- dir_both if both are the case.   

References CONST_INT_P, d1, d2, dir_backward, dir_both, dir_forward, dir_none, equal_different_set_p(), find_reg_equal_equiv_note(), ggc_alloc(), i1, i2, NULL_RTX, PATTERN(), reload_completed, rtx_equal_p(), rtx_renumbered_equal_p(), SET_DEST, SET_SRC, single_set(), and values_equal_p().

Referenced by old_insns_match_p().

◆ cleanup_cfg()

◆ delete_dead_jumptables()

void delete_dead_jumptables ( void )
Delete any jump tables never referenced.  We can't delete them at the
time of removing tablejump insn as they are referenced by the preceding
insns computing the destination, so we delay deleting and garbagecollect
them once life information is computed.   

References BB_END, cfun, delete_insn(), dump_file, FOR_EACH_BB_FN, ggc_alloc(), INSN_UID(), JUMP_TABLE_DATA_P, LABEL_NUSES, LABEL_P, LABEL_PRESERVE_P, NEXT_INSN(), and NOTE_INSN_BASIC_BLOCK_P.

Referenced by cfg_layout_finalize(), and cleanup_cfg().

◆ delete_unreachable_blocks()

◆ equal_different_set_p()

static bool equal_different_set_p ( rtx p1,
rtx s1,
rtx p2,
rtx s2 )
static

◆ flow_find_cross_jump()

int flow_find_cross_jump ( basic_block bb1,
basic_block bb2,
rtx_insn ** f1,
rtx_insn ** f2,
enum replace_direction * dir_p )
Look through the insns at the end of BB1 and BB2 and find the longest
sequence that are either equivalent, or allow forward or backward
replacement.  Store the first insns for that sequence in *F1 and *F2 and
return the sequence length.

DIR_P indicates the allowed replacement direction on function entry, and
the actual replacement direction on function exit.  If NULL, only equivalent
sequences are allowed.

To simplify callers of this function, if the blocks match exactly,
store the head of the blocks in *F1 and *F2.   

References active_insn_p(), BB_END, BB_HEAD, BB_PARTITION, BLOCK_FOR_INSN(), dir_backward, dir_both, dir_forward, dir_none, f1, f2, ggc_alloc(), i1, i2, INSN_P, LABEL_P, merge_dir(), merge_memattrs(), merge_notes(), NONDEBUG_INSN_P, NULL, old_insns_match_p(), onlyjump_p(), PATTERN(), PREV_INSN(), reload_completed, returnjump_p(), side_effects_p(), simplejump_p(), and walk_to_nondebug_insn().

Referenced by cond_exec_process_if_block(), and try_crossjump_to_edge().

◆ flow_find_head_matching_sequence()

int flow_find_head_matching_sequence ( basic_block bb1,
basic_block bb2,
rtx_insn ** f1,
rtx_insn ** f2,
int stop_after )
Like flow_find_cross_jump, except start looking for a matching sequence from
the head of the two blocks.  Do not include jumps at the end.
If STOP_AFTER is nonzero, stop after finding that many matching
instructions.  If STOP_AFTER is zero, count all INSN_P insns, if it is
non-zero, only count active insns.   

References active_insn_p(), BB_END, BB_HEAD, dir_both, f1, f2, FOR_EACH_EDGE, ggc_alloc(), i1, i2, INSN_P, JUMP_P, merge_memattrs(), merge_notes(), NEXT_INSN(), NONDEBUG_INSN_P, NOTE_KIND, NOTE_P, NULL, and old_insns_match_p().

Referenced by cond_exec_process_if_block(), and try_head_merge_bb().

◆ insns_have_identical_cfa_notes()

static bool insns_have_identical_cfa_notes ( rtx_insn * i1,
rtx_insn * i2 )
static
Return true if I1 and I2 have identical CFA notes (the same order
and equivalent content).   

References i1, i2, NULL_RTX, reg_note_cfa_p, REG_NOTE_KIND, REG_NOTES, reload_completed, rtx_equal_p(), rtx_renumbered_equal_p(), and XEXP.

Referenced by old_insns_match_p().

◆ make_pass_jump()

rtl_opt_pass * make_pass_jump ( gcc::context * ctxt)

References ggc_alloc().

◆ make_pass_jump2()

rtl_opt_pass * make_pass_jump2 ( gcc::context * ctxt)

References ggc_alloc().

◆ make_pass_jump_after_combine()

rtl_opt_pass * make_pass_jump_after_combine ( gcc::context * ctxt)

References ggc_alloc().

◆ mark_effect()

static bool mark_effect ( rtx exp,
regset nonequal )
static
Attempt to prove that operation is NOOP using CSElib or mark the effect
on register.  Used by jump threading.   

References bitmap_clear_range(), bitmap_set_range(), cselib_redundant_set_p(), exp(), GET_CODE, ggc_alloc(), pc_rtx, REG_NREGS, REG_P, REGNO, SET, SET_DEST, and XEXP.

Referenced by thread_jump().

◆ mentions_nonequal_regs()

static bool mentions_nonequal_regs ( const_rtx x,
regset nonequal )
static
Return true if X contains a register in NONEQUAL.   

References END_REGNO(), FOR_EACH_SUBRTX, ggc_alloc(), REG_P, REGNO, and REGNO_REG_SET_P.

Referenced by thread_jump().

◆ merge_blocks_move()

static basic_block merge_blocks_move ( edge e,
basic_block b,
basic_block c,
int mode )
static
Attempt to merge basic blocks that are potentially non-adjacent.
Return NULL iff the attempt failed, otherwise return basic block
where cleanup_cfg should continue.  Because the merging commonly
moves basic block away or introduces another optimization
possibility, return basic block just before B so cleanup_cfg don't
need to iterate.

It may be good idea to return basic block before C in the case
C has been moved after B and originally appeared earlier in the
insn sequence, but we have no information available about the
relative ordering of these two.  Hopefully it is not too common.   

References b, BB_PARTITION, cfun, CLEANUP_EXPENSIVE, current_loops, dump_file, ENTRY_BLOCK_PTR_FOR_FN, find_fallthru_edge(), force_nonfallthru(), FORWARDER_BLOCK_P, ggc_alloc(), basic_block_def::index, loop::latch, basic_block_def::loop_father, merge_blocks(), merge_blocks_move_predecessor_nojumps(), merge_blocks_move_successor_nojumps(), basic_block_def::next_bb, notice_new_block(), NULL, basic_block_def::prev_bb, basic_block_def::succs, and update_forwarder_flag().

Referenced by try_optimize_cfg().

◆ merge_blocks_move_predecessor_nojumps()

static void merge_blocks_move_predecessor_nojumps ( basic_block a,
basic_block b )
static
Blocks A and B are to be merged into a single block.  A has no incoming
fallthru edge, so it can be moved before B without adding or modifying
any jumps (aside from the jump from A to B).   

References a, b, BARRIER_P, BB_END, BB_HEAD, BB_PARTITION, delete_insn(), df_set_bb_dirty(), dump_file, gcc_assert, ggc_alloc(), link_block(), merge_blocks(), next_nonnote_insn(), PREV_INSN(), reorder_insns_nobb(), and unlink_block().

Referenced by merge_blocks_move().

◆ merge_blocks_move_successor_nojumps()

static void merge_blocks_move_successor_nojumps ( basic_block a,
basic_block b )
static
Blocks A and B are to be merged into a single block.  B has no outgoing
fallthru edge, so it can be moved after A without adding or modifying
any jumps (aside from the jump from A to B).   

References a, b, BARRIER_P, BB_END, BB_HEAD, BB_PARTITION, delete_insn(), dump_file, ggc_alloc(), merge_blocks(), NEXT_INSN(), prev_active_insn(), reorder_insns_nobb(), table, and tablejump_p().

Referenced by merge_blocks_move().

◆ merge_dir()

Merges directions A and B.   

References a, b, dir_both, and dir_none.

Referenced by flow_find_cross_jump().

◆ merge_memattrs()

◆ merge_notes()

static void merge_notes ( rtx_insn * i1,
rtx_insn * i2 )
static
When comparing insns I1 and I2 in flow_find_cross_jump or
flow_find_head_matching_sequence, ensure the notes match.   

References find_reg_equal_equiv_note(), ggc_alloc(), i1, i2, remove_note(), rtx_equal_p(), and XEXP.

Referenced by flow_find_cross_jump(), and flow_find_head_matching_sequence().

◆ notice_new_block()

static void notice_new_block ( basic_block bb)
static
Set flags for newly created block.   

References basic_block_def::flags, forwarder_block_p(), and ggc_alloc().

Referenced by merge_blocks_move(), try_forward_edges(), and try_optimize_cfg().

◆ old_insns_match_p()

◆ outgoing_edges_match()

static bool outgoing_edges_match ( int mode,
basic_block bb1,
basic_block bb2 )
static

◆ thread_jump()

◆ trivially_empty_bb_p()

static bool trivially_empty_bb_p ( basic_block bb)
static
Return true if BB contains just bb note, or bb note followed
by only DEBUG_INSNs.   

References BB_END, BB_HEAD, DEBUG_INSN_P, and PREV_INSN().

Referenced by try_optimize_cfg().

◆ try_crossjump_bb()

static bool try_crossjump_bb ( int mode,
basic_block bb )
static
Search the predecessors of BB for common insn sequences.  When found,
share code between them by redirecting control flow.  Return true if
any changes made.   

References BB_END, BB_PARTITION, cfun, changed, computed_jump_p(), crossjumps_occurred, dir_both, dir_forward, EDGE_COUNT, EDGE_PRED, EDGE_SUCC, EXIT_BLOCK_PTR_FOR_FN, find_fallthru_edge(), first_pass, ggc_alloc(), NULL, optimize_bb_for_size_p(), basic_block_def::preds, and try_crossjump_to_edge().

Referenced by try_optimize_cfg().

◆ try_crossjump_to_edge()

static bool try_crossjump_to_edge ( int mode,
edge e1,
edge e2,
enum replace_direction dir )
static
E1 and E2 are edges with the same destination block.  Search their
predecessors for common code.  If found, redirect control flow from
(maybe the middle of) E1->SRC to (maybe the middle of) E2->SRC (dir_forward),
or the other way around (dir_backward).  DIR specifies the allowed
replacement direction.   

References BB_END, BB_HEAD, BB_PARTITION, BLOCK_FOR_INSN(), block_has_preserve_label(), cfun, d2, DEBUG_INSN_P, delete_basic_block(), df_set_bb_dirty(), dir_backward, dump_file, EDGE_COUNT, EDGE_PRED, ENTRY_BLOCK_PTR_FOR_FN, find_fallthru_edge(), flow_find_cross_jump(), FOR_EACH_EDGE, FORWARDER_BLOCK_P, get_insns(), ggc_alloc(), LABEL_P, NEXT_INSN(), NOTE_INSN_BASIC_BLOCK_P, NOTE_KIND, NOTE_P, NULL, NULL_RTX, outgoing_edges_match(), PREV_INSN(), redirect_edge_and_branch_force(), reload_completed, replace_label_in_insn(), single_pred_edge(), single_pred_p(), single_succ(), single_succ_edge(), split_block(), tablejump_p(), update_br_prob_note(), and update_forwarder_flag().

Referenced by try_crossjump_bb().

◆ try_forward_edges()

◆ try_head_merge_bb()

◆ try_optimize_cfg()

static bool try_optimize_cfg ( int mode)
static
Do simple CFG optimizations - basic block merging, simplifying of jump
instructions etc.  Return nonzero if changes were made.   

References any_condjump_p(), b, BARRIER_P, BB_END, BB_FOOTER, BB_HEAD, bb_is_just_return(), block_label(), block_was_dirty, BRANCH_EDGE, can_merge_blocks_p(), cfun, changed, checking_verify_flow_info(), CLEANUP_CFGLAYOUT, CLEANUP_CROSSJUMP, CLEANUP_EXPENSIVE, CLEANUP_NO_INSN_DEL, CLEANUP_NO_PARTITIONING, CLEANUP_THREADING, clear_bb_flags(), copy_insn(), CROSSING_JUMP_P, crossjumps_occurred, current_ir_type(), delete_basic_block(), delete_insn(), df_analyze(), dump_file, EDGE_COMPLEX, EDGE_COUNT, emit_barrier_after(), emit_barrier_after_bb(), emit_insn_before(), ENTRY_BLOCK_PTR_FOR_FN, EXIT_BLOCK_PTR_FOR_FN, FALLTHRU_EDGE, first_pass, fixup_partitions(), FOR_ALL_BB_FN, FOR_EACH_BB_FN, FOR_EACH_EDGE, force_nonfallthru(), FORWARDER_BLOCK_P, gcc_assert, gcc_unreachable, get_last_bb_insn(), ggc_alloc(), invert_jump(), IR_RTL_CFGLAYOUT, JUMP_LABEL, JUMP_P, label_is_jump_target_p(), LABEL_P, LABEL_PRESERVE_P, last, merge_blocks(), merge_blocks_move(), n_basic_blocks_for_fn, basic_block_def::next_bb, NEXT_INSN(), notice_new_block(), NULL, NUM_FIXED_BLOCKS, onlyjump_p(), PATTERN(), basic_block_def::prev_bb, redirect_edge_succ(), redirect_edge_succ_nodup(), redirect_jump(), reload_completed, simplejump_p(), single_pred(), single_pred_edge(), single_pred_p(), single_succ(), single_succ_edge(), single_succ_p(), tablejump_p(), targetm, trivially_empty_bb_p(), try_crossjump_bb(), try_forward_edges(), try_head_merge_bb(), try_redirect_by_replacing_jump(), try_simplify_condjump(), update_br_prob_note(), and update_forwarder_flag().

Referenced by cleanup_cfg().

◆ try_simplify_condjump()

◆ update_forwarder_flag()

static void update_forwarder_flag ( basic_block bb)
static
Recompute forwarder flag after block has been modified.   

References basic_block_def::flags, forwarder_block_p(), and ggc_alloc().

Referenced by merge_blocks_move(), try_crossjump_to_edge(), try_optimize_cfg(), and try_simplify_condjump().

◆ values_equal_p()

static int values_equal_p ( rtx note1,
rtx note2,
rtx src1,
rtx src2 )
static
NOTE1 is the REG_EQUAL note, if any, attached to an insn
that is a single_set with a SET_SRC of SRC1.  Similarly
for NOTE2/SRC2.

So effectively NOTE1/NOTE2 are an alternate form of 
SRC1/SRC2 respectively.

Return nonzero if SRC1 or NOTE1 has the same constant
integer value as SRC2 or NOTE2.   Else return zero.   

References CONST_INT_P, ggc_alloc(), rtx_equal_p(), and XEXP.

Referenced by can_replace_by().

◆ walk_to_nondebug_insn()

static void walk_to_nondebug_insn ( rtx_insn ** i1,
basic_block * bb1,
bool follow_fallthru,
bool * did_fallthru )
static

Variable Documentation

◆ block_was_dirty

bool block_was_dirty
static
Set to true if we couldn't run an optimization due to stale liveness
information; we should run df_analyze to enable more opportunities.   

Referenced by try_head_merge_bb(), and try_optimize_cfg().

◆ crossjumps_occurred

bool crossjumps_occurred
static
Set to true if crossjumps occurred in the latest run of try_optimize_cfg.   

Referenced by cleanup_cfg(), try_crossjump_bb(), try_head_merge_bb(), and try_optimize_cfg().

◆ first_pass

bool first_pass
static
Set to true when we are running first pass of try_optimize_cfg loop.   

Referenced by try_crossjump_bb(), try_forward_edges(), and try_optimize_cfg().

◆ reg_note_cfa_p

const bool reg_note_cfa_p[]
static
Initial value:
= {
#define DEF_REG_NOTE(NAME)
#define REG_CFA_NOTE(NAME)
false
}
Array of flags indexed by reg note kind, true if the given
reg note is CFA related.   

Referenced by insns_have_identical_cfa_notes().