GCC Middle and Back End API Reference
reorg.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 "predict.h"
#include "memmodel.h"
#include "tm_p.h"
#include "expmed.h"
#include "insn-config.h"
#include "emit-rtl.h"
#include "recog.h"
#include "insn-attr.h"
#include "resource.h"
#include "tree-pass.h"
Include dependency graph for reorg.cc:

Macros

#define unfilled_slots_base    ((rtx_insn **) obstack_base (&unfilled_slots_obstack))
 
#define unfilled_slots_next    ((rtx_insn **) obstack_next_free (&unfilled_slots_obstack))
 
#define NUM_REORG_FUNCTIONS   2
 
#define MAX_DELAY_HISTOGRAM   3
 
#define MAX_REORG_PASSES   2
 

Functions

static rtx skip_consecutive_labels (rtx label_or_return)
 
static bool stop_search_p (rtx_insn *, bool)
 
static bool resource_conflicts_p (struct resources *, struct resources *)
 
static bool insn_references_resource_p (rtx, struct resources *, bool)
 
static bool insn_sets_resource_p (rtx, struct resources *, bool)
 
static rtx_code_labelfind_end_label (rtx)
 
static rtx_insnemit_delay_sequence (rtx_insn *, const vec< rtx_insn * > &, int)
 
static void add_to_delay_list (rtx_insn *, vec< rtx_insn * > *)
 
static rtx_insndelete_from_delay_slot (rtx_insn *)
 
static void delete_scheduled_jump (rtx_insn *)
 
static void note_delay_statistics (int, int)
 
static int get_jump_flags (const rtx_insn *, rtx)
 
static int mostly_true_jump (rtx)
 
static rtx get_branch_condition (const rtx_insn *, rtx)
 
static bool condition_dominates_p (rtx, const rtx_insn *)
 
static bool redirect_with_delay_slots_safe_p (rtx_insn *, rtx, rtx)
 
static bool redirect_with_delay_list_safe_p (rtx_insn *, rtx, const vec< rtx_insn * > &)
 
static bool check_annul_list_true_false (bool, const vec< rtx_insn * > &)
 
static void steal_delay_list_from_target (rtx_insn *, rtx, rtx_sequence *, vec< rtx_insn * > *, struct resources *, struct resources *, struct resources *, int, int *, bool *, rtx *)
 
static void steal_delay_list_from_fallthrough (rtx_insn *, rtx, rtx_sequence *, vec< rtx_insn * > *, struct resources *, struct resources *, struct resources *, int, int *, bool *)
 
static void try_merge_delay_insns (rtx_insn *, rtx_insn *)
 
static rtx_insnredundant_insn (rtx, rtx_insn *, const vec< rtx_insn * > &)
 
static bool own_thread_p (rtx, rtx, bool)
 
static void update_block (rtx_insn *, rtx_insn *)
 
static bool reorg_redirect_jump (rtx_jump_insn *, rtx)
 
static void update_reg_dead_notes (rtx_insn *, rtx_insn *)
 
static void fix_reg_dead_note (rtx_insn *, rtx)
 
static void update_reg_unused_notes (rtx_insn *, rtx)
 
static void fill_simple_delay_slots (bool)
 
static void fill_slots_from_thread (rtx_jump_insn *, rtx, rtx, rtx, bool, bool, bool, int, int *, vec< rtx_insn * > *)
 
static void fill_eager_delay_slots (void)
 
static void relax_delay_slots (rtx_insn *)
 
static void make_return_insns (rtx_insn *)
 
static rtx first_active_target_insn (rtx insn)
 
static bool simplejump_or_return_p (rtx insn)
 
static void optimize_skip (rtx_jump_insn *insn, vec< rtx_insn * > *delay_list)
 
static rtx_insnget_label_before (rtx_insn *insn, rtx sibling)
 
static rtx follow_jumps (rtx label, rtx_insn *jump, bool *crossing)
 
static void delete_computation (rtx_insn *insn)
 
static void delete_prior_computation (rtx note, rtx_insn *insn)
 
static void delete_jump (rtx_insn *insn)
 
static rtx_insnlabel_before_next_insn (rtx_insn *x, rtx scan_limit)
 
static bool switch_text_sections_between_p (const rtx_insn *beg, const rtx_insn *end)
 
static void dbr_schedule (rtx_insn *first)
 
static void rest_of_handle_delay_slots (void)
 
rtl_opt_passmake_pass_delay_slots (gcc::context *ctxt)
 
rtl_opt_passmake_pass_machine_reorg (gcc::context *ctxt)
 

Variables

static struct obstack unfilled_slots_obstack
 
static rtxunfilled_firstobj
 
static rtx_code_labelfunction_return_label
 
static rtx_code_labelfunction_simple_return_label
 
static int * uid_to_ruid
 
static int max_uid
 
static int num_insns_needing_delays [NUM_REORG_FUNCTIONS][MAX_REORG_PASSES]
 
static int num_filled_delays [NUM_REORG_FUNCTIONS][MAX_DELAY_HISTOGRAM+1][MAX_REORG_PASSES]
 
static int reorg_pass_number
 
static vec< rtxsibling_labels
 

Macro Definition Documentation

◆ MAX_DELAY_HISTOGRAM

#define MAX_DELAY_HISTOGRAM   3

◆ MAX_REORG_PASSES

#define MAX_REORG_PASSES   2

Referenced by dbr_schedule().

◆ NUM_REORG_FUNCTIONS

#define NUM_REORG_FUNCTIONS   2
Counters for delay-slot filling.   

Referenced by dbr_schedule().

◆ unfilled_slots_base

#define unfilled_slots_base    ((rtx_insn **) obstack_base (&unfilled_slots_obstack))
Define macros to refer to the first and last slot containing unfilled
insns.  These are used because the list may move and its address
should be recomputed at each use.   

Referenced by fill_eager_delay_slots(), and fill_simple_delay_slots().

◆ unfilled_slots_next

#define unfilled_slots_next    ((rtx_insn **) obstack_next_free (&unfilled_slots_obstack))

Function Documentation

◆ add_to_delay_list()

static void add_to_delay_list ( rtx_insn * insn,
vec< rtx_insn * > * delay_list )
static
Add INSN to DELAY_LIST and return the head of the new list.  The list must
be in the order in which the insns are to be executed.   

References clear_hashed_info_for_insn(), and ggc_alloc().

Referenced by delete_from_delay_slot(), fill_simple_delay_slots(), fill_slots_from_thread(), optimize_skip(), steal_delay_list_from_fallthrough(), and steal_delay_list_from_target().

◆ check_annul_list_true_false()

static bool check_annul_list_true_false ( bool annul_true_p,
const vec< rtx_insn * > & delay_list )
static
DELAY_LIST is a list of insns that have already been placed into delay
slots.  See if all of them have the same annulling status as ANNUL_TRUE_P.
If not, return false; otherwise return true.   

References FOR_EACH_VEC_ELT, ggc_alloc(), i, and INSN_FROM_TARGET_P.

Referenced by fill_slots_from_thread(), steal_delay_list_from_fallthrough(), and steal_delay_list_from_target().

◆ condition_dominates_p()

static bool condition_dominates_p ( rtx condition,
const rtx_insn * insn )
static
Return true if CONDITION is more strict than the condition of
INSN, i.e., if INSN will always branch if CONDITION is true.   

References comparison_dominates_p(), const_true_rtx, get_branch_condition(), GET_CODE, GET_RTX_LENGTH, ggc_alloc(), JUMP_LABEL, rtx_equal_p(), and XEXP.

Referenced by steal_delay_list_from_target().

◆ dbr_schedule()

◆ delete_computation()

static void delete_computation ( rtx_insn * insn)
static
Delete INSN and recursively delete insns that compute values used only
by INSN.  This uses the REG_DEAD notes computed during flow analysis.

Look at all our REG_DEAD notes.  If a previous insn does nothing other
than set a register that dies in this insn, we can delete that insn
as well.   

References delete_prior_computation(), delete_related_insns(), ggc_alloc(), REG_NOTE_KIND, REG_NOTES, REG_P, and XEXP.

Referenced by delete_jump(), and delete_prior_computation().

◆ delete_from_delay_slot()

static rtx_insn * delete_from_delay_slot ( rtx_insn * insn)
static

◆ delete_jump()

static void delete_jump ( rtx_insn * insn)
static
If all INSN does is set the pc, delete it,
and delete the insn that set the condition codes for it
if that's what the previous thing was.   

References delete_computation(), GET_CODE, ggc_alloc(), SET_DEST, and single_set().

Referenced by relax_delay_slots().

◆ delete_prior_computation()

static void delete_prior_computation ( rtx note,
rtx_insn * insn )
static
Recursively delete prior insns that compute the value (used only by INSN
which the caller is deleting) stored in the register mentioned by NOTE
which is a REG_DEAD note associated with INSN.   

References add_reg_note(), CALL_P, delete_computation(), END_REGNO(), find_regno_note(), GET_CODE, ggc_alloc(), i, NONJUMP_INSN_P, PATTERN(), prev_nonnote_insn(), REG_NOTES, reg_overlap_mentioned_p(), REG_P, reg_set_p(), REGNO, RTL_CONST_CALL_P, SET, SET_DEST, SET_SRC, side_effects_p(), XEXP, XVECEXP, and XVECLEN.

Referenced by delete_computation().

◆ delete_scheduled_jump()

static void delete_scheduled_jump ( rtx_insn * insn)
static
Delete INSN, a JUMP_INSN.   

References delete_related_insns().

Referenced by relax_delay_slots().

◆ emit_delay_sequence()

static rtx_insn * emit_delay_sequence ( rtx_insn * insn,
const vec< rtx_insn * > & list,
int length )
static
Put INSN and LIST together in a SEQUENCE rtx of LENGTH, and replace
the pattern of INSN with the SEQUENCE.

Returns the insn containing the SEQUENCE that replaces INSN.   

References add_insn_after(), emit_insn(), end_sequence(), gcc_assert, ggc_alloc(), i, INSN_LOCATION(), LABEL_NUSES, LABEL_P, make_insn_raw(), NULL, PREV_INSN(), REG_NOTE_KIND, REG_NOTES, remove_insn(), remove_note(), rtvec_alloc(), SET_NEXT_INSN(), SET_PREV_INSN(), start_sequence(), XEXP, and XVECEXP.

Referenced by delete_from_delay_slot(), fill_eager_delay_slots(), and fill_simple_delay_slots().

◆ fill_eager_delay_slots()

static void fill_eager_delay_slots ( void )
static
Make another attempt to find insns to place in delay slots.

We previously looked for insns located in front of the delay insn
and, for non-jump delay insns, located behind the delay insn.

Here only try to schedule jump insns and try to move insns from either
the target or the following insns into the delay slot.  If annulling is
supported, we will be likely to do this.  Otherwise, we can do this only
if safe.   

References condjump_in_parallel_p(), condjump_p(), const_true_rtx, rtx_insn::deleted(), emit_delay_sequence(), fill_slots_from_thread(), first_active_target_insn(), get_branch_condition(), ggc_alloc(), i, JUMP_LABEL, mostly_true_jump(), next_active_insn(), NEXT_INSN(), note_delay_statistics(), NULL_RTX, own_thread_p(), unfilled_slots_base, and unfilled_slots_next.

Referenced by dbr_schedule().

◆ fill_simple_delay_slots()

static void fill_simple_delay_slots ( bool non_jumps_p)
static
Scan a function looking for insns that need a delay slot and find insns to
put into the delay slot.

NON_JUMPS_P is true if we are to only try to fill non-jump insns (such
as calls).  We do these first since we don't want jump insns (that are
easier to fill) to get the only insns that could be used for non-jump insns.
When it is zero, only try to fill JUMP_INSNs.

When slots are filled in this manner, the insns (including the
delay_insn) are put together in a SEQUENCE rtx.  In this fashion,
it is possible to tell whether a delay slot has really been filled
or not.  `final' knows how to deal with this, by communicating
through FINAL_SEQUENCE.   

References add_to_delay_list(), ANY_RETURN_P, CALL_P, can_throw_internal(), CLEAR_HARD_REG_BIT, CLEAR_RESOURCE, condjump_in_parallel_p(), condjump_p(), const_true_rtx, copy_delay_slot_insn(), delete_related_insns(), rtx_insn::deleted(), emit_delay_sequence(), fill_slots_from_thread(), find_end_label(), find_regno_note(), GET_CODE, get_jump_flags(), get_label_before(), ggc_alloc(), i, insn_references_resource_p(), insn_sets_resource_p(), INVALID_REGNUM, JUMP_LABEL, JUMP_LABEL_AS_INSN(), JUMP_P, jump_to_label_p(), mark_referenced_resources(), mark_set_resources(), MARK_SRC_DEST, MARK_SRC_DEST_CALL, may_trap_or_fault_p(), next_active_insn(), NEXT_INSN(), next_nonnote_insn(), next_real_nondebug_insn(), no_labels_between_p(), NONJUMP_INSN_P, note_delay_statistics(), NULL, NULL_RTX, optimize_skip(), own_thread_p(), PATTERN(), PREV_INSN(), prev_nonnote_insn(), reorg_redirect_jump(), SET_NEXT_INSN(), SET_PREV_INSN(), simple_return_rtx, simplejump_p(), stop_search_p(), targetm, TEST_HARD_REG_BIT, try_split(), unfilled_slots_base, unfilled_slots_next, update_block(), update_reg_dead_notes(), and XVECEXP.

Referenced by dbr_schedule(), and make_return_insns().

◆ fill_slots_from_thread()

static void fill_slots_from_thread ( rtx_jump_insn * insn,
rtx condition,
rtx thread_or_return,
rtx opposite_thread,
bool likely,
bool thread_if_true,
bool own_thread,
int slots_to_fill,
int * pslots_filled,
vec< rtx_insn * > * delay_list )
static
Try to find insns to place in delay slots.

INSN is the jump needing SLOTS_TO_FILL delay slots.  It tests CONDITION
or is an unconditional branch if CONDITION is const_true_rtx.
*PSLOTS_FILLED is updated with the number of slots that we have filled.

THREAD is a flow-of-control, either the insns to be executed if the
branch is true or if the branch is false, THREAD_IF_TRUE says which.

OPPOSITE_THREAD is the thread in the opposite direction.  It is used
to see if any potential delay slot insns set things needed there.

LIKELY is true if it is extremely likely that the branch will be
taken and THREAD_IF_TRUE is set.  This is used for the branch at the
end of a loop back up to the top.

OWN_THREAD is true if we are the only user of the thread, i.e. it is
the target of the jump when we are the only jump going there.

If OWN_THREAD is false, it must be the "true" thread of a jump.  In that
case, we can only take insns from the head of the thread for our delay
slot.  We then adjust the jump to point after the insns we have taken.   

References add_to_delay_list(), ANY_RETURN_P, asm_noperands(), can_throw_internal(), check_annul_list_true_false(), CLEAR_HARD_REG_BIT, CLEAR_RESOURCE, CONST_INT_P, const_true_rtx, constrain_operands(), copy_delay_slot_insn(), CROSSING_JUMP_P, delete_related_insns(), emit_insn_after(), extract_insn(), find_end_label(), find_regno_note(), fix_reg_dead_note(), FLOAT_MODE_P, follow_jumps(), gcc_assert, GET_CODE, get_insns(), get_jump_flags(), get_label_before(), GET_MODE, get_preferred_alternatives(), ggc_alloc(), INSN_ANNULLED_BRANCH_P, INSN_FROM_TARGET_P, insn_references_resource_p(), insn_sets_resource_p(), INVALID_REGNUM, JUMP_LABEL, JUMP_P, jump_to_label_p(), LABEL_NUSES, LABEL_P, mark_referenced_resources(), mark_set_resources(), MARK_SRC_DEST_CALL, mark_target_live_regs(), may_trap_or_fault_p(), modified_in_p(), negate_rtx(), next_active_insn(), next_nonnote_insn(), NONJUMP_INSN_P, NULL_RTX, own_thread_p(), PATTERN(), recog_memoized(), redirect_with_delay_list_safe_p(), redundant_insn(), REG_NOTE_KIND, REG_NOTES, reg_overlap_mentioned_p(), REG_P, reg_referenced_p(), reg_set_p(), reorg_redirect_jump(), rtx_equal_p(), RTX_FRAME_RELATED_P, SET, SET_DEST, SET_HARD_REG_BIT, SET_SRC, side_effects_p(), simple_return_rtx, simplejump_or_return_p(), steal_delay_list_from_fallthrough(), steal_delay_list_from_target(), stop_search_p(), targetm, TEST_HARD_REG_BIT, try_split(), update_block(), update_reg_unused_notes(), validate_replace_rtx(), XEXP, and XVECEXP.

Referenced by fill_eager_delay_slots(), and fill_simple_delay_slots().

◆ find_end_label()

static rtx_code_label * find_end_label ( rtx kind)
static
Find a label at the end of the function or before a RETURN.  If there
is none, try to make one.  If that fails, returns 0.

The property of such a label is that it is placed just before the
epilogue or a bare RETURN insn, so that another bare RETURN can be
turned into a jump to the label unconditionally.  In particular, the
label cannot be placed before a RETURN insn with a filled delay slot.

??? There may be a problem with the current implementation.  Suppose
we start with a bare RETURN insn and call find_end_label.  It may set
function_return_label just before the RETURN.  Suppose the machinery
is able to fill the delay slot of the RETURN insn afterwards.  Then
function_return_label is no longer valid according to the property
described above and find_end_label will still return it unmodified.
Note that this is probably mitigated by the following observation:
once function_return_label is made, it is very likely the target of
a jump, so filling the delay slot of the RETURN will be much more
difficult.
KIND is either simple_return_rtx or ret_rtx, indicating which type of
return we're looking for.   

References BARRIER_P, emit_barrier(), emit_jump_insn(), emit_label(), emit_label_after(), function_return_label, function_simple_return_label, gcc_assert, gen_label_rtx(), GET_CODE, get_last_insn(), ggc_alloc(), JUMP_P, LABEL_NUSES, LABEL_P, NONJUMP_INSN_P, NOTE_P, NULL, PATTERN(), PREV_INSN(), ret_rtx, set_return_jump_label(), simple_return_rtx, targetm, and unfilled_slots_obstack.

Referenced by fill_simple_delay_slots(), fill_slots_from_thread(), optimize_skip(), and relax_delay_slots().

◆ first_active_target_insn()

static rtx first_active_target_insn ( rtx insn)
static
A wrapper around next_active_insn which takes care to return ret_rtx
unchanged.   

References ANY_RETURN_P, ggc_alloc(), and next_active_insn().

Referenced by fill_eager_delay_slots(), and steal_delay_list_from_target().

◆ fix_reg_dead_note()

static void fix_reg_dead_note ( rtx_insn * start_insn,
rtx stop_insn )
static
Called when an insn redundant with start_insn is deleted.  If there
is a REG_DEAD note for the target of start_insn between start_insn
and stop_insn, then the REG_DEAD note needs to be deleted since the
value no longer dies there.

If the REG_DEAD note isn't deleted, then mark_target_live_regs may be
confused into thinking the register is dead.   

References ggc_alloc(), next_nonnote_insn(), PATTERN(), REG_NOTE_KIND, REG_NOTES, REG_P, reg_set_p(), remove_note(), and XEXP.

Referenced by fill_slots_from_thread(), relax_delay_slots(), steal_delay_list_from_fallthrough(), and steal_delay_list_from_target().

◆ follow_jumps()

static rtx follow_jumps ( rtx label,
rtx_insn * jump,
bool * crossing )
static
Follow any unconditional jump at LABEL, for the purpose of redirecting JUMP;
return the ultimate label reached by any such chain of jumps.
Return a suitable return rtx if the chain ultimately leads to a
return instruction.
If LABEL is not followed by a jump, return LABEL.
If the chain loops or we can't find end, return LABEL,
since that tells caller to avoid changing the insn.
If the returned label is obtained by following a crossing jump,
set *CROSSING to true, otherwise set it to false.   

References ANY_RETURN_P, any_uncondjump_p(), BARRIER_P, CROSSING_JUMP_P, ggc_alloc(), JUMP_LABEL, JUMP_P, JUMP_TABLE_DATA_P, next_active_insn(), NEXT_INSN(), NULL_RTX, onlyjump_p(), PATTERN(), and targetm.

Referenced by cse_find_path(), fill_slots_from_thread(), and relax_delay_slots().

◆ get_branch_condition()

static rtx get_branch_condition ( const rtx_insn * insn,
rtx target )
static
Return the condition under which INSN will branch to TARGET.  If TARGET
is zero, return the condition under which INSN will return.  If INSN is
an unconditional branch, return const_true_rtx.  If INSN isn't a simple
type of jump, or it doesn't go to TARGET, return 0.   

References ANY_RETURN_P, condjump_in_parallel_p(), const_true_rtx, GET_CODE, GET_MODE, ggc_alloc(), label_ref_label(), PATTERN(), pc_rtx, reversed_comparison_code(), SET, SET_DEST, SET_SRC, XEXP, and XVECEXP.

Referenced by condition_dominates_p(), and fill_eager_delay_slots().

◆ get_jump_flags()

static int get_jump_flags ( const rtx_insn * insn,
rtx label )
static
Encode and return branch direction and prediction information for
INSN assuming it will jump to LABEL.

Non conditional branches return no direction information and
are predicted as very likely taken.   

References ANY_RETURN_P, condjump_in_parallel_p(), condjump_p(), ggc_alloc(), INSN_UID(), JUMP_P, max_uid, and uid_to_ruid.

Referenced by fill_simple_delay_slots(), fill_slots_from_thread(), make_return_insns(), optimize_skip(), redirect_with_delay_list_safe_p(), redirect_with_delay_slots_safe_p(), steal_delay_list_from_fallthrough(), steal_delay_list_from_target(), and try_merge_delay_insns().

◆ get_label_before()

static rtx_insn * get_label_before ( rtx_insn * insn,
rtx sibling )
static
Return the label before INSN, or put a new label there.  If SIBLING is
non-zero, it is another label associated with the new label (if any),
typically the former target of the jump that will be redirected to
the new label.   

References emit_label_after(), gen_label_rtx(), LABEL_NUSES, LABEL_P, PREV_INSN(), prev_nonnote_insn(), and sibling_labels.

Referenced by fill_simple_delay_slots(), fill_slots_from_thread(), make_return_insns(), and relax_delay_slots().

◆ insn_references_resource_p()

static bool insn_references_resource_p ( rtx insn,
struct resources * res,
bool include_delayed_effects )
static
Return TRUE if any resource marked in RES, a `struct resources', is
referenced by INSN.  If INCLUDE_DELAYED_EFFECTS is set, return if the called
routine is using those resources.

We compute this by computing all the resources referenced by INSN and
seeing if this conflicts with RES.  It might be faster to directly check
ourselves, and this is the way it used to work, but it means duplicating
a large block of complex code.   

References CLEAR_RESOURCE, ggc_alloc(), mark_referenced_resources(), and resource_conflicts_p().

Referenced by fill_simple_delay_slots(), fill_slots_from_thread(), steal_delay_list_from_fallthrough(), steal_delay_list_from_target(), and try_merge_delay_insns().

◆ insn_sets_resource_p()

static bool insn_sets_resource_p ( rtx insn,
struct resources * res,
bool include_delayed_effects )
static
Return TRUE if INSN modifies resources that are marked in RES.
INCLUDE_DELAYED_EFFECTS is set if the actions of that routine should be
included.    

References CLEAR_RESOURCE, ggc_alloc(), mark_set_resources(), MARK_SRC_DEST, MARK_SRC_DEST_CALL, and resource_conflicts_p().

Referenced by fill_simple_delay_slots(), fill_slots_from_thread(), redundant_insn(), steal_delay_list_from_fallthrough(), steal_delay_list_from_target(), and try_merge_delay_insns().

◆ label_before_next_insn()

static rtx_insn * label_before_next_insn ( rtx_insn * x,
rtx scan_limit )
static

◆ make_pass_delay_slots()

rtl_opt_pass * make_pass_delay_slots ( gcc::context * ctxt)

References ggc_alloc().

◆ make_pass_machine_reorg()

rtl_opt_pass * make_pass_machine_reorg ( gcc::context * ctxt)

References ggc_alloc().

◆ make_return_insns()

◆ mostly_true_jump()

static int mostly_true_jump ( rtx jump_insn)
static
Return truth value of the statement that this branch
is mostly taken.  If we think that the branch is extremely likely
to be taken, we return 2.  If the branch is slightly more likely to be
taken, return 1.  If the branch is slightly less likely to be taken,
return 0 and if the branch is highly unlikely to be taken, return -1.   

References find_reg_note(), profile_probability::from_reg_br_prob_note(), ggc_alloc(), REG_BR_PROB_BASE, profile_probability::to_reg_br_prob_base(), and XINT.

Referenced by fill_eager_delay_slots(), and relax_delay_slots().

◆ note_delay_statistics()

static void note_delay_statistics ( int slots_filled,
int index )
static

◆ optimize_skip()

static void optimize_skip ( rtx_jump_insn * insn,
vec< rtx_insn * > * delay_list )
static
Optimize the following cases:

1.  When a conditional branch skips over only one instruction,
    use an annulling branch and put that insn in the delay slot.
    Use either a branch that annuls when the condition if true or
    invert the test with a branch that annuls when the condition is
    false.  This saves insns, since otherwise we must copy an insn
    from the L1 target.

     (orig)              (skip)         (otherwise)
     Bcc.n L1   Bcc',a L1       Bcc,a L1'
     insn               insn            insn2
   L1:        L1:             L1:
     insn2              insn2           insn2
     insn3              insn3         L1':
                                insn3

2.  When a conditional branch skips over only one instruction,
    and after that, it unconditionally branches somewhere else,
    perform the similar optimization. This saves executing the
    second branch in the case where the inverted condition is true.

     Bcc.n L1   Bcc',a L2
     insn               insn
   L1:        L1:
     Bra L2             Bra L2

INSN is a JUMP_INSN.

This should be expanded to skip over N insns, where N is the number
of delay slots required.   

References add_to_delay_list(), ANY_RETURN_P, can_throw_internal(), delete_related_insns(), find_end_label(), GET_CODE, get_jump_flags(), ggc_alloc(), INSN_ANNULLED_BRANCH_P, INSN_FROM_TARGET_P, invert_jump(), JUMP_LABEL, JUMP_LABEL_AS_INSN(), next_active_insn(), next_nonnote_insn(), NONJUMP_INSN_P, PATTERN(), recog_memoized(), reorg_redirect_jump(), RTX_FRAME_RELATED_P, simplejump_or_return_p(), and update_block().

Referenced by fill_simple_delay_slots().

◆ own_thread_p()

static bool own_thread_p ( rtx thread,
rtx label,
bool allow_fallthrough )
static
Return true if THREAD can only be executed in one way.  If LABEL is nonzero,
it is the target of the branch insn being scanned.  If ALLOW_FALLTHROUGH
is true, we are allowed to fall into this thread; otherwise, we are not.

If LABEL is used more than one or we pass a label other than LABEL before
finding an active insn, we do not own this thread.   

References ANY_RETURN_P, BARRIER_P, GET_CODE, ggc_alloc(), LABEL_NUSES, LABEL_P, next_active_insn(), NEXT_INSN(), NONJUMP_INSN_P, PATTERN(), PREV_INSN(), and prev_nonnote_insn().

Referenced by fill_eager_delay_slots(), fill_simple_delay_slots(), fill_slots_from_thread(), and relax_delay_slots().

◆ redirect_with_delay_list_safe_p()

static bool redirect_with_delay_list_safe_p ( rtx_insn * jump,
rtx newlabel,
const vec< rtx_insn * > & delay_list )
static
Return true if redirecting JUMP to NEWLABEL does not invalidate
any insns we wish to place in the delay slot of JUMP.   

References get_jump_flags(), ggc_alloc(), i, INSN_ANNULLED_BRANCH_P, and INSN_FROM_TARGET_P.

Referenced by fill_slots_from_thread().

◆ redirect_with_delay_slots_safe_p()

static bool redirect_with_delay_slots_safe_p ( rtx_insn * jump,
rtx newlabel,
rtx seq )
static
Return true if redirecting JUMP to NEWLABEL does not invalidate
any insns already in the delay slot of JUMP.   

References get_jump_flags(), ggc_alloc(), i, rtx_sequence::insn(), INSN_ANNULLED_BRANCH_P, INSN_FROM_TARGET_P, rtx_sequence::len(), PATTERN(), and XVECEXP.

Referenced by make_return_insns(), and relax_delay_slots().

◆ redundant_insn()

static rtx_insn * redundant_insn ( rtx insn,
rtx_insn * target,
const vec< rtx_insn * > & delay_list )
static
See if INSN is redundant with an insn in front of TARGET.  Often this
is called when INSN is a candidate for a delay slot of TARGET.
DELAY_LIST are insns that will be placed in delay slots of TARGET in front
of INSN.  Often INSN will be redundant with an insn in a delay slot of
some previous insn.  This happens when we have a series of branches to the
same label; in that case the first insn at the target might want to go
into each of the delay slots.

If we are not careful, this routine can take up a significant fraction
of the total compilation time (4%), but only wins rarely.  Hence we
speed this routine up by making two passes.  The first pass goes back
until it hits a label and sees if it finds an insn with an identical
pattern.  Only in this (relatively rare) event does it check for
data conflicts.

We do not split insns we encounter.  This could cause us not to find a
redundant insn, but the cost of splitting seems greater than the possible
gain in rare cases.   

References BARRIER_P, CALL_P, candidate(), CLEAR_RESOURCE, find_reg_note(), FOR_EACH_VEC_ELT, GET_CODE, ggc_alloc(), i, INSN_ANNULLED_BRANCH_P, INSN_FROM_TARGET_P, INSN_P, INSN_REFERENCES_ARE_DELAYED, INSN_SETS_ARE_DELAYED, insn_sets_resource_p(), JUMP_P, LABEL_P, mark_referenced_resources(), mark_set_resources(), MARK_SRC_DEST_CALL, NONJUMP_INSN_P, NULL_RTX, PATTERN(), PREV_INSN(), resource_conflicts_p(), rtx_equal_p(), XVECEXP, and XVECLEN.

Referenced by fill_slots_from_thread(), relax_delay_slots(), steal_delay_list_from_fallthrough(), and steal_delay_list_from_target().

◆ relax_delay_slots()

◆ reorg_redirect_jump()

static bool reorg_redirect_jump ( rtx_jump_insn * jump,
rtx nlabel )
static
Similar to REDIRECT_JUMP except that we update the BB_TICKS entry for
the basic block containing the jump.   

References ggc_alloc(), incr_ticks_for_insn(), and redirect_jump().

Referenced by fill_simple_delay_slots(), fill_slots_from_thread(), make_return_insns(), optimize_skip(), and relax_delay_slots().

◆ resource_conflicts_p()

static bool resource_conflicts_p ( struct resources * res1,
struct resources * res2 )
static
Return TRUE if any resources are marked in both RES1 and RES2 or if either
resource set contains a volatile memory reference.  Otherwise, return FALSE.   

References ggc_alloc(), and hard_reg_set_intersect_p().

Referenced by insn_references_resource_p(), insn_sets_resource_p(), and redundant_insn().

◆ rest_of_handle_delay_slots()

static void rest_of_handle_delay_slots ( void )
static
Run delay slot optimization.   

References dbr_schedule(), get_insns(), and ggc_alloc().

◆ simplejump_or_return_p()

static bool simplejump_or_return_p ( rtx insn)
static
Return true iff INSN is a simplejump, or any kind of return insn.   

References ANY_RETURN_P, ggc_alloc(), JUMP_P, PATTERN(), and simplejump_p().

Referenced by fill_slots_from_thread(), optimize_skip(), relax_delay_slots(), and steal_delay_list_from_fallthrough().

◆ skip_consecutive_labels()

static rtx skip_consecutive_labels ( rtx label_or_return)
static
Perform instruction reorganizations for delay slot filling.
   Copyright (C) 1992-2024 Free Software Foundation, Inc.
   Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
   Hacked by Michael Tiemann (tiemann@cygnus.com).

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/>.   
Instruction reorganization pass.

This pass runs after register allocation and final jump
optimization.  It should be the last pass to run before peephole.
It serves primarily to fill delay slots of insns, typically branch
and call insns.  Other insns typically involve more complicated
interactions of data dependencies and resource constraints, and
are better handled by scheduling before register allocation (by the
function `schedule_insns').

The Branch Penalty is the number of extra cycles that are needed to
execute a branch insn.  On an ideal machine, branches take a single
cycle, and the Branch Penalty is 0.  Several RISC machines approach
branch delays differently:

The MIPS has a single branch delay slot.  Most insns
(except other branches) can be used to fill this slot.  When the
slot is filled, two insns execute in two cycles, reducing the
branch penalty to zero.

The SPARC always has a branch delay slot, but its effects can be
annulled when the branch is not taken.  This means that failing to
find other sources of insns, we can hoist an insn from the branch
target that would only be safe to execute knowing that the branch
is taken.

The HP-PA always has a branch delay slot.  For unconditional branches
its effects can be annulled when the branch is taken.  The effects
of the delay slot in a conditional branch can be nullified for forward
taken branches, or for untaken backward branches.  This means
we can hoist insns from the fall-through path for forward branches or
steal insns from the target of backward branches.

The TMS320C3x and C4x have three branch delay slots.  When the three
slots are filled, the branch penalty is zero.  Most insns can fill the
delay slots except jump insns.

Three techniques for filling delay slots have been implemented so far:

(1) `fill_simple_delay_slots' is the simplest, most efficient way
to fill delay slots.  This pass first looks for insns which come
from before the branch and which are safe to execute after the
branch.  Then it searches after the insn requiring delay slots or,
in the case of a branch, for insns that are after the point at
which the branch merges into the fallthrough code, if such a point
exists.  When such insns are found, the branch penalty decreases
and no code expansion takes place.

(2) `fill_eager_delay_slots' is more complicated: it is used for
scheduling conditional jumps, or for scheduling jumps which cannot
be filled using (1).  A machine need not have annulled jumps to use
this strategy, but it helps (by keeping more options open).
`fill_eager_delay_slots' tries to guess the direction the branch
will go; if it guesses right 100% of the time, it can reduce the
branch penalty as much as `fill_simple_delay_slots' does.  If it
guesses wrong 100% of the time, it might as well schedule nops.  When
`fill_eager_delay_slots' takes insns from the fall-through path of
the jump, usually there is no code expansion; when it takes insns
from the branch target, there is code expansion if it is not the
only way to reach that target.

(3) `relax_delay_slots' uses a set of rules to simplify code that
has been reorganized by (1) and (2).  It finds cases where
conditional test can be eliminated, jumps can be threaded, extra
insns can be eliminated, etc.  It is the job of (1) and (2) to do a
good job of scheduling locally; `relax_delay_slots' takes care of
making the various individual schedules work well together.  It is
especially tuned to handle the control flow interactions of branch
insns.  It does nothing for insns with delay slots that do not
branch.   
First, some functions that were used before GCC got a control flow graph.
These functions are now only used here in reorg.cc, and have therefore
been moved here to avoid inadvertent misuse elsewhere in the compiler.   
Return the last label to mark the same position as LABEL.  Return LABEL
itself if it is null or any return rtx.   

References ANY_RETURN_P, BARRIER_P, ggc_alloc(), INSN_P, LABEL_P, and NEXT_INSN().

Referenced by dbr_schedule(), and relax_delay_slots().

◆ steal_delay_list_from_fallthrough()

static void steal_delay_list_from_fallthrough ( rtx_insn * insn,
rtx condition,
rtx_sequence * seq,
vec< rtx_insn * > * delay_list,
struct resources * sets,
struct resources * needed,
struct resources * other_needed,
int slots_to_fill,
int * pslots_filled,
bool * pannul_p )
static
Similar to steal_delay_list_from_target except that SEQ is on the
fallthrough path of INSN.  Here we only do something if the delay insn
of SEQ is an unconditional branch.  In that case we steal its delay slot
for INSN since unconditional branches are much easier to fill.   

References add_to_delay_list(), check_annul_list_true_false(), const_true_rtx, delete_from_delay_slot(), fix_reg_dead_note(), get_jump_flags(), ggc_alloc(), i, rtx_sequence::insn(), insn_references_resource_p(), insn_sets_resource_p(), JUMP_LABEL, rtx_sequence::len(), may_trap_or_fault_p(), PATTERN(), redundant_insn(), simplejump_or_return_p(), and update_block().

Referenced by fill_slots_from_thread().

◆ steal_delay_list_from_target()

static void steal_delay_list_from_target ( rtx_insn * insn,
rtx condition,
rtx_sequence * seq,
vec< rtx_insn * > * delay_list,
struct resources * sets,
struct resources * needed,
struct resources * other_needed,
int slots_to_fill,
int * pslots_filled,
bool * pannul_p,
rtx * pnew_thread )
static
INSN branches to an insn whose pattern SEQ is a SEQUENCE.  Given that
the condition tested by INSN is CONDITION and the resources shown in
OTHER_NEEDED are needed after INSN, see whether INSN can take all the insns
from SEQ's delay list, in addition to whatever insns it may execute
(in DELAY_LIST).   SETS and NEEDED are denote resources already set and
needed while searching for delay slot insns.  Return the concatenated
delay list if possible, otherwise, return 0.

SLOTS_TO_FILL is the total number of slots required by INSN, and
PSLOTS_FILLED points to the number filled so far (also the number of
insns in DELAY_LIST).  It is updated with the number that have been
filled from the SEQUENCE, if any.

PANNUL_P points to a nonzero value if we already know that we need
to annul INSN.  If this routine determines that annulling is needed,
it may set that value to true.

PNEW_THREAD points to a location that is to receive the place at which
execution should continue.   

References add_to_delay_list(), check_annul_list_true_false(), CLEAR_RESOURCE, condition_dominates_p(), const_true_rtx, copy_delay_slot_insn(), first_active_target_insn(), fix_reg_dead_note(), FOR_EACH_VEC_ELT, get_jump_flags(), ggc_alloc(), i, rtx_sequence::insn(), INSN_ANNULLED_BRANCH_P, INSN_FROM_TARGET_P, insn_references_resource_p(), insn_sets_resource_p(), JUMP_LABEL, rtx_sequence::len(), mark_set_resources(), MARK_SRC_DEST_CALL, may_trap_or_fault_p(), PATTERN(), redundant_insn(), RTX_FRAME_RELATED_P, single_set(), targetm, update_block(), and XVECLEN.

Referenced by fill_slots_from_thread().

◆ stop_search_p()

static bool stop_search_p ( rtx_insn * insn,
bool labels_p )
static
Return TRUE if this insn should stop the search for insn to fill delay
slots.  LABELS_P indicates that labels should terminate the search.
In all cases, jumps terminate the search.   

References asm_noperands(), can_throw_internal(), gcc_unreachable, GET_CODE, ggc_alloc(), and PATTERN().

Referenced by fill_simple_delay_slots(), fill_slots_from_thread(), and try_merge_delay_insns().

◆ switch_text_sections_between_p()

static bool switch_text_sections_between_p ( const rtx_insn * beg,
const rtx_insn * end )
static
Return TRUE if there is a NOTE_INSN_SWITCH_TEXT_SECTIONS note in between
BEG and END.   

References end(), ggc_alloc(), NEXT_INSN(), NOTE_KIND, and NOTE_P.

Referenced by relax_delay_slots().

◆ try_merge_delay_insns()

static void try_merge_delay_insns ( rtx_insn * insn,
rtx_insn * thread )
static
Try merging insns starting at THREAD which match exactly the insns in
INSN's delay list.

If all insns were matched and the insn was previously annulling, the
annul bit will be cleared.

For each insn that is merged, if the branch is or will be non-annulling,
we delete the merged insn.   

References CLEAR_RESOURCE, delete_from_delay_slot(), delete_related_insns(), GET_CODE, get_jump_flags(), ggc_alloc(), i, rtx_sequence::insn(), INSN_ANNULLED_BRANCH_P, INSN_FROM_TARGET_P, insn_references_resource_p(), insn_sets_resource_p(), JUMP_LABEL, JUMP_P, rtx_sequence::len(), mark_referenced_resources(), mark_set_resources(), MARK_SRC_DEST_CALL, next_active_insn(), next_nonnote_insn(), NONJUMP_INSN_P, PATTERN(), rtx_equal_p(), stop_search_p(), try_split(), update_block(), XVECEXP, and XVECLEN.

Referenced by relax_delay_slots().

◆ update_block()

static void update_block ( rtx_insn * insn,
rtx_insn * where )
static
Called when INSN is being moved from a location near the target of a jump.
We leave a marker of the form (use (INSN)) immediately in front of WHERE
for mark_target_live_regs.  These markers will be deleted at the end.

We used to try to update the live status of registers if WHERE is at
the start of a basic block, but that can't work since we may remove a
BARRIER in relax_delay_slots.   

References emit_insn_before(), ggc_alloc(), and incr_ticks_for_insn().

Referenced by fill_simple_delay_slots(), fill_slots_from_thread(), optimize_skip(), relax_delay_slots(), steal_delay_list_from_fallthrough(), steal_delay_list_from_target(), and try_merge_delay_insns().

◆ update_reg_dead_notes()

static void update_reg_dead_notes ( rtx_insn * insn,
rtx_insn * delayed_insn )
static
Called when INSN is being moved forward into a delay slot of DELAYED_INSN.
We check every instruction between INSN and DELAYED_INSN for REG_DEAD notes
that reference values used in INSN.  If we find one, then we move the
REG_DEAD note to INSN.

This is needed to handle the case where a later insn (after INSN) has a
REG_DEAD note for a register used by INSN, and this later insn subsequently
gets moved before a CODE_LABEL because it is a redundant insn.  In this
case, mark_target_live_regs may be confused into thinking the register
is dead because it sees a REG_DEAD note immediately before a CODE_LABEL.   

References ggc_alloc(), next_nonnote_insn(), PATTERN(), REG_NOTE_KIND, REG_NOTES, REG_P, reg_referenced_p(), remove_note(), and XEXP.

Referenced by fill_simple_delay_slots().

◆ update_reg_unused_notes()

static void update_reg_unused_notes ( rtx_insn * insn,
rtx other_insn )
static
Delete any REG_UNUSED notes that exist on INSN but not on OTHER_INSN.

This handles the case of udivmodXi4 instructions which optimize their
output depending on whether any REG_UNUSED notes are present.  We must
make sure that INSN calculates as many results as OTHER_INSN does.   

References find_regno_note(), ggc_alloc(), REG_NOTE_KIND, REG_NOTES, REG_P, REGNO, remove_note(), and XEXP.

Referenced by fill_slots_from_thread().

Variable Documentation

◆ function_return_label

rtx_code_label* function_return_label
static
Points to the label before the end of the function, or before a
return insn.   

Referenced by dbr_schedule(), find_end_label(), and make_return_insns().

◆ function_simple_return_label

rtx_code_label* function_simple_return_label
static
Likewise for a simple_return.   

Referenced by dbr_schedule(), find_end_label(), and make_return_insns().

◆ max_uid

◆ num_filled_delays

◆ num_insns_needing_delays

int num_insns_needing_delays[NUM_REORG_FUNCTIONS][MAX_REORG_PASSES]
static

◆ reorg_pass_number

int reorg_pass_number
static

◆ sibling_labels

vec<rtx> sibling_labels
static

Referenced by dbr_schedule(), and get_label_before().

◆ uid_to_ruid

int* uid_to_ruid
static
Mapping between INSN_UID's and position in the code since INSN_UID's do
not always monotonically increase.   

Referenced by dbr_schedule(), and get_jump_flags().

◆ unfilled_firstobj

rtx* unfilled_firstobj
static

Referenced by dbr_schedule(), and make_return_insns().

◆ unfilled_slots_obstack

struct obstack unfilled_slots_obstack
static
Insns which have delay slots that have not yet been filled.   

Referenced by dbr_schedule(), delete_from_delay_slot(), find_end_label(), and make_return_insns().