GCC Middle and Back End API Reference
ira-emit.cc File Reference
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "rtl.h"
#include "tree.h"
#include "predict.h"
#include "df.h"
#include "insn-config.h"
#include "regs.h"
#include "memmodel.h"
#include "ira.h"
#include "ira-int.h"
#include "cfgrtl.h"
#include "cfgbuild.h"
#include "expr.h"
#include "reload.h"
#include "cfgloop.h"
Include dependency graph for ira-emit.cc:

Data Structures

struct  move
 

Typedefs

typedef void * void_p
 
typedef struct movemove_t
 

Functions

void ira_initiate_emit_data (void)
 
void ira_finish_emit_data (void)
 
static ira_allocno_t create_new_allocno (int regno, ira_loop_tree_node_t loop_tree_node)
 
static move_t create_move (ira_allocno_t to, ira_allocno_t from)
 
static void free_move (move_t move)
 
static void free_move_list (move_t head)
 
static bool eq_move_lists_p (move_t list1, move_t list2)
 
static void print_move_list (FILE *f, move_t list)
 
void ira_debug_move_list (move_t list)
 
static bool change_regs (rtx *loc)
 
static bool change_regs_in_insn (rtx_insn **insn_ptr)
 
static void add_to_edge_list (edge e, move_t move, bool head_p)
 
rtx ira_create_new_reg (rtx original_reg)
 
static bool subloop_tree_node_p (ira_loop_tree_node_t subnode, ira_loop_tree_node_t node)
 
static void set_allocno_reg (ira_allocno_t allocno, rtx reg)
 
static bool entered_from_non_parent_p (ira_loop_tree_node_t loop_node)
 
static void setup_entered_from_non_parent_p (void)
 
static bool store_can_be_removed_p (ira_allocno_t src_allocno, ira_allocno_t dest_allocno)
 
static void generate_edge_moves (edge e)
 
static void change_loop (ira_loop_tree_node_t node)
 
static void set_allocno_somewhere_renamed_p (void)
 
static bool eq_edge_move_lists_p (vec< edge, va_gc > *vec)
 
static void unify_moves (basic_block bb, bool start_p)
 
static void traverse_moves (move_t move)
 
static move_t modify_move_list (move_t list)
 
static rtx_insnemit_move_list (move_t list, int freq)
 
static void emit_moves (void)
 
static void update_costs (ira_allocno_t a, bool read_p, int freq)
 
static void add_range_and_copies_from_move_list (move_t list, ira_loop_tree_node_t node, bitmap live_through, int freq)
 
static void add_ranges_and_copies (void)
 
void ira_emit (bool loops_p)
 

Variables

ira_emit_data_t ira_allocno_emit_data
 
static vec< void_pnew_allocno_emit_data_vec
 
static move_tat_bb_start
 
static move_tat_bb_end
 
static int max_regno_before_changing
 
static bitmap local_allocno_bitmap
 
static bitmap used_regno_bitmap
 
static bitmap renamed_regno_bitmap
 
static move_t hard_regno_last_set [FIRST_PSEUDO_REGISTER]
 
static int hard_regno_last_set_check [FIRST_PSEUDO_REGISTER]
 
static move_tallocno_last_set
 
static int * allocno_last_set_check
 
static vec< move_tmove_vec
 
static int curr_tick
 

Typedef Documentation

◆ move_t

typedef struct move* move_t
See comments below.   

◆ void_p

typedef void* void_p
Definitions for vectors of pointers.   

Function Documentation

◆ add_range_and_copies_from_move_list()

static void add_range_and_copies_from_move_list ( move_t list,
ira_loop_tree_node_t node,
bitmap live_through,
int freq )
static

◆ add_ranges_and_copies()

static void add_ranges_and_copies ( void )
static

◆ add_to_edge_list()

static void add_to_edge_list ( edge e,
move_t move,
bool head_p )
static
Attach MOVE to the edge E.  The move is attached to the head of the
list if HEAD_P is TRUE.   

References last, filedep::next, move::next, and NULL.

Referenced by generate_edge_moves().

◆ change_loop()

◆ change_regs()

static bool change_regs ( rtx * loc)
static
This recursive function changes pseudo-registers in *LOC if it is
necessary.  The function returns TRUE if a change was done.   

References allocno_emit_reg(), change_regs(), GET_CODE, GET_RTX_FORMAT, GET_RTX_LENGTH, i, ira_curr_regno_allocno_map, max_regno_before_changing, NULL, NULL_RTX, REGNO, XEXP, XVECEXP, and XVECLEN.

Referenced by change_regs(), and change_regs_in_insn().

◆ change_regs_in_insn()

static bool change_regs_in_insn ( rtx_insn ** insn_ptr)
static

References as_a(), and change_regs().

Referenced by change_loop().

◆ create_move()

static move_t create_move ( ira_allocno_t to,
ira_allocno_t from )
static
Return new move of allocnos TO and FROM.   

References move::deps, move::deps_num, move::from, move::insn, ira_allocate(), move::next, NULL, move::to, and move::visited_p.

Referenced by generate_edge_moves(), and modify_move_list().

◆ create_new_allocno()

static ira_allocno_t create_new_allocno ( int regno,
ira_loop_tree_node_t loop_tree_node )
static
Create and return a new allocno with given REGNO and
LOOP_TREE_NODE.  Allocate emit data for it.   

References a, ALLOCNO_ADD_DATA, ira_allocate(), ira_create_allocno(), and new_allocno_emit_data_vec.

Referenced by modify_move_list().

◆ emit_move_list()

◆ emit_moves()

◆ entered_from_non_parent_p()

static bool entered_from_non_parent_p ( ira_loop_tree_node_t loop_node)
static
Return true if there is an entry to given loop not from its parent
(or grandparent) block.  For example, it is possible for two
adjacent loops inside another loop.   

References ira_loop_tree_node::bb, cfun, ira_loop_tree_node::children, ENTRY_BLOCK_PTR_FOR_FN, FOR_EACH_EDGE, IRA_BB_NODE, ira_loop_tree_node::next, NULL, ira_loop_tree_node::parent, and basic_block_def::preds.

Referenced by setup_entered_from_non_parent_p().

◆ eq_edge_move_lists_p()

static bool eq_edge_move_lists_p ( vec< edge, va_gc > * vec)
static
Return TRUE if move lists on all edges given in vector VEC are
equal.   

References EDGE_COUNT, EDGE_I, eq_move_lists_p(), and i.

Referenced by unify_moves().

◆ eq_move_lists_p()

static bool eq_move_lists_p ( move_t list1,
move_t list2 )
static
Return TRUE if the move list LIST1 and LIST2 are equal (two
moves are equal if they involve the same allocnos).   

References move::from, move::next, NULL, and move::to.

Referenced by eq_edge_move_lists_p().

◆ free_move()

static void free_move ( move_t move)
static
Free memory for MOVE and its dependencies.   

References move::deps, ira_free(), and NULL.

Referenced by free_move_list().

◆ free_move_list()

static void free_move_list ( move_t head)
static
Free memory for list of the moves given by its HEAD.   

References free_move(), and NULL.

Referenced by ira_emit(), and unify_moves().

◆ generate_edge_moves()

static void generate_edge_moves ( edge e)
static
Generate and attach moves to the edge E.  This looks at the final
regnos of allocnos living on the edge with the same original regno
to figure out when moves should be generated.   

References add_to_edge_list(), ALLOCNO_EMIT_DATA, allocno_emit_reg(), ALLOCNO_HARD_REGNO, ALLOCNO_NUM, bitmap_bit_p, create_move(), df_get_live_in(), df_get_live_out(), EXECUTE_IF_SET_IN_REG_SET, internal_flag_ira_verbose, IRA_BB_NODE, ira_dump_file, NULL, ira_loop_tree_node::parent, REGNO, ira_loop_tree_node::regno_allocno_map, and store_can_be_removed_p().

Referenced by ira_emit().

◆ ira_create_new_reg()

rtx ira_create_new_reg ( rtx original_reg)

◆ ira_debug_move_list()

void ira_debug_move_list ( move_t list)
extern
Print move list LIST into stderr.   

References print_move_list().

◆ ira_emit()

◆ ira_finish_emit_data()

void ira_finish_emit_data ( void )
Free the emit data.   

References a, ALLOCNO_ADD_DATA, FOR_EACH_ALLOCNO, ira_allocno_emit_data, ira_free(), new_allocno_emit_data_vec, and NULL.

Referenced by ira().

◆ ira_initiate_emit_data()

void ira_initiate_emit_data ( void )
Allocate and initiate the emit data.   

References a, ALLOCNO_ADD_DATA, ALLOCNO_NUM, FOR_EACH_ALLOCNO, ira_allocate(), ira_allocno_emit_data, ira_allocnos_num, and new_allocno_emit_data_vec.

Referenced by ira().

◆ modify_move_list()

◆ print_move_list()

static void print_move_list ( FILE * f,
move_t list )
static
Print move list LIST into file F.   

References ALLOCNO_NUM, ALLOCNO_REGNO, move::from, move::next, NULL, and move::to.

Referenced by ira_debug_move_list().

◆ set_allocno_reg()

static void set_allocno_reg ( ira_allocno_t allocno,
rtx reg )
static
Set up member `reg' to REG for allocnos which has the same regno as
ALLOCNO and which are inside the loop corresponding to ALLOCNO.  

References a, ALLOCNO_CAP, ALLOCNO_EMIT_DATA, ALLOCNO_LOOP_TREE_NODE, ALLOCNO_NEXT_REGNO_ALLOCNO, ALLOCNO_REGNO, ira_regno_allocno_map, NULL, ira_loop_tree_node::parent, ira_loop_tree_node::regno_allocno_map, and subloop_tree_node_p().

Referenced by change_loop().

◆ set_allocno_somewhere_renamed_p()

static void set_allocno_somewhere_renamed_p ( void )
static
Process to set up flag somewhere_renamed_p.   

References ALLOCNO_EMIT_DATA, allocno_emit_reg(), ALLOCNO_REGNO, bitmap_bit_p, FOR_EACH_ALLOCNO, REGNO, and renamed_regno_bitmap.

Referenced by ira_emit().

◆ setup_entered_from_non_parent_p()

static void setup_entered_from_non_parent_p ( void )
static
Set up ENTERED_FROM_NON_PARENT_P for each loop region.   

References cfun, current_loops, entered_from_non_parent_p(), ira_loop_tree_node::entered_from_non_parent_p, FOR_EACH_VEC_SAFE_ELT, get_loops(), i, ira_assert, ira_loop_nodes, and NULL.

Referenced by ira_emit().

◆ store_can_be_removed_p()

static bool store_can_be_removed_p ( ira_allocno_t src_allocno,
ira_allocno_t dest_allocno )
static
Return TRUE if move of SRC_ALLOCNO (assigned to hard register) to
DEST_ALLOCNO (assigned to memory) can be removed because it does
not change value of the destination.  One possible reason for this
is the situation when SRC_ALLOCNO is not modified in the
corresponding loop.   

References a, ALLOCNO_CAP_MEMBER, allocno_emit_reg(), ALLOCNO_LOOP_TREE_NODE, ALLOCNO_REGNO, bitmap_bit_p, ira_loop_tree_node::entered_from_non_parent_p, ira_assert, ira_loop_tree_node::modified_regnos, NULL, ira_loop_tree_node::parent, REGNO, and ira_loop_tree_node::regno_allocno_map.

Referenced by generate_edge_moves().

◆ subloop_tree_node_p()

static bool subloop_tree_node_p ( ira_loop_tree_node_t subnode,
ira_loop_tree_node_t node )
static
Return TRUE if loop given by SUBNODE inside the loop given by
NODE.   

References NULL, and ira_loop_tree_node::parent.

Referenced by set_allocno_reg().

◆ traverse_moves()

static void traverse_moves ( move_t move)
static
This recursive function traverses dependencies of MOVE and produces
topological sorting (in depth-first order).   

References move::deps, move::deps_num, i, move_vec, traverse_moves(), and move::visited_p.

Referenced by modify_move_list(), and traverse_moves().

◆ unify_moves()

static void unify_moves ( basic_block bb,
bool start_p )
static
Look at all entry edges (if START_P) or exit edges of basic block
BB and put move lists at the BB start or end if it is possible.  In
other words, this decreases code duplication of allocno moves.   

References at_bb_end, at_bb_start, BB_END, control_flow_insn_p(), EDGE_COUNT, EDGE_I, eq_edge_move_lists_p(), free_move_list(), i, basic_block_def::index, NULL, basic_block_def::preds, and basic_block_def::succs.

Referenced by ira_emit().

◆ update_costs()

static void update_costs ( ira_allocno_t a,
bool read_p,
int freq )
static
Update costs of A and corresponding allocnos on upper levels on the
loop tree from reading (if READ_P) or writing A on an execution
path with FREQ.   

References a, ALLOCNO_CAP, ALLOCNO_CLASS, ALLOCNO_FREQ, ALLOCNO_LOOP_TREE_NODE, ALLOCNO_MEMORY_COST, ALLOCNO_MODE, ALLOCNO_NREFS, ALLOCNO_REGNO, ira_memory_move_cost, NULL, and ira_loop_tree_node::regno_allocno_map.

Referenced by add_range_and_copies_from_move_list().

Variable Documentation

◆ allocno_last_set

move_t* allocno_last_set
static
Last move (in move sequence being processed) setting up the
corresponding allocno.   

Referenced by ira_emit().

◆ allocno_last_set_check

int* allocno_last_set_check
static
If the element value is equal to CURR_TICK then the corresponding
element in . `allocno_last_set' is defined and correct.   

Referenced by ira_emit().

◆ at_bb_end

move_t * at_bb_end
static

◆ at_bb_start

move_t* at_bb_start
static
Array of moves (indexed by BB index) which should be put at the
start/end of the corresponding basic blocks.   

Referenced by add_ranges_and_copies(), emit_moves(), ira_emit(), and unify_moves().

◆ curr_tick

int curr_tick
static
The variable value is used to check correctness of values of
elements of arrays `hard_regno_last_set' and
`allocno_last_set_check'.   

Referenced by ira_emit(), and modify_move_list().

◆ hard_regno_last_set

move_t hard_regno_last_set[FIRST_PSEUDO_REGISTER]
static
Last move (in move sequence being processed) setting up the
corresponding hard register.   

Referenced by modify_move_list().

◆ hard_regno_last_set_check

int hard_regno_last_set_check[FIRST_PSEUDO_REGISTER]
static
If the element value is equal to CURR_TICK then the corresponding
element in `hard_regno_last_set' is defined and correct.   

Referenced by ira_emit(), and modify_move_list().

◆ ira_allocno_emit_data

ira_emit_data_t ira_allocno_emit_data
Integrated Register Allocator.  Changing code and generating moves.
   Copyright (C) 2006-2024 Free Software Foundation, Inc.
   Contributed by Vladimir Makarov <vmakarov@redhat.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/>.   
When we have more one region, we need to change the original RTL
code after coloring.  Let us consider two allocnos representing the
same pseudo-register outside and inside a region respectively.
They can get different hard-registers.  The reload pass works on
pseudo registers basis and there is no way to say the reload that
pseudo could be in different registers and it is even more
difficult to say in what places of the code the pseudo should have
particular hard-registers.  So in this case IRA has to create and
use a new pseudo-register inside the region and adds code to move
allocno values on the region's borders.  This is done by the code
in this file.

The code makes top-down traversal of the regions and generate new
pseudos and the move code on the region borders.  In some
complicated cases IRA can create a new pseudo used temporarily to
move allocno values when a swap of values stored in two
hard-registers is needed (e.g. two allocnos representing different
pseudos outside region got respectively hard registers 1 and 2 and
the corresponding allocnos inside the region got respectively hard
registers 2 and 1).  At this stage, the new pseudo is marked as
spilled.

IRA still creates the pseudo-register and the moves on the region
borders even when the both corresponding allocnos were assigned to
the same hard-register.  It is done because, if the reload pass for
some reason spills a pseudo-register representing the original
pseudo outside or inside the region, the effect will be smaller
because another pseudo will still be in the hard-register.  In most
cases, this is better then spilling the original pseudo in its
whole live-range.  If reload does not change the allocation for the
two pseudo-registers, the trivial move will be removed by
post-reload optimizations.

IRA does not generate a new pseudo and moves for the allocno values
if the both allocnos representing an original pseudo inside and
outside region assigned to the same hard register when the register
pressure in the region for the corresponding pressure class is less
than number of available hard registers for given pressure class.

IRA also does some optimizations to remove redundant moves which is
transformed into stores by the reload pass on CFG edges
representing exits from the region.

IRA tries to reduce duplication of code generated on CFG edges
which are enters and exits to/from regions by moving some code to
the edge sources or destinations when it is possible.   
Data used to emit live range split insns and to flattening IR.   

Referenced by ira_finish_emit_data(), and ira_initiate_emit_data().

◆ local_allocno_bitmap

bitmap local_allocno_bitmap
static
Bitmap of allocnos local for the current loop.   

Referenced by change_loop(), and ira_emit().

◆ max_regno_before_changing

int max_regno_before_changing
static
Max regno before renaming some pseudo-registers.  For example, the
same pseudo-register can be renamed in a loop if its allocation is
different outside the loop.   

Referenced by change_regs(), and ira_emit().

◆ move_vec

vec<move_t> move_vec
static
Definition of vector of moves.   
This vec contains moves sorted topologically (depth-first) on their
dependency graph.   

Referenced by ira_emit(), modify_move_list(), and traverse_moves().

◆ new_allocno_emit_data_vec

vec<void_p> new_allocno_emit_data_vec
static
Pointers to data allocated for allocnos being created during
emitting.  Usually there are quite few such allocnos because they
are created only for resolving loop in register shuffling.   

Referenced by create_new_allocno(), ira_finish_emit_data(), and ira_initiate_emit_data().

◆ renamed_regno_bitmap

bitmap renamed_regno_bitmap
static
This bitmap contains regnos of allocnos which were renamed locally
because the allocnos correspond to disjoint live ranges in loops
with a common parent.   

Referenced by change_loop(), ira_emit(), and set_allocno_somewhere_renamed_p().

◆ used_regno_bitmap

bitmap used_regno_bitmap
static
This bitmap is used to find that we need to generate and to use a
new pseudo-register when processing allocnos with the same original
regno.   

Referenced by change_loop(), and ira_emit().