GCC Middle and Back End API Reference
lower-subreg.cc File Reference
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "rtl.h"
#include "tree.h"
#include "cfghooks.h"
#include "df.h"
#include "memmodel.h"
#include "tm_p.h"
#include "expmed.h"
#include "insn-config.h"
#include "emit-rtl.h"
#include "recog.h"
#include "cfgrtl.h"
#include "cfgbuild.h"
#include "dce.h"
#include "expr.h"
#include "explow.h"
#include "tree-pass.h"
#include "lower-subreg.h"
#include "rtl-iter.h"
#include "target.h"
Include dependency graph for lower-subreg.cc:

Data Structures

struct  cost_rtxes


#define LOG_COSTS   0
#define FORCE_LOWERING   0
#define twice_word_mode    this_target_lower_subreg->x_twice_word_mode
#define choices    this_target_lower_subreg->x_choices




static bool interesting_mode_p (machine_mode mode, unsigned int *bytes, unsigned int *words)
static int shift_cost (bool speed_p, struct cost_rtxes *rtxes, enum rtx_code code, machine_mode mode, int op1)
static void compute_splitting_shift (bool speed_p, struct cost_rtxes *rtxes, bool *splitting, enum rtx_code code, int word_move_zero_cost, int word_move_cost)
static void compute_costs (bool speed_p, struct cost_rtxes *rtxes)
void init_lower_subreg (void)
static bool simple_move_operand (rtx x)
static rtx operand_for_swap_move_operator (rtx x)
static rtx simple_move (rtx_insn *insn, bool speed_p)
static bool find_pseudo_copy (rtx set)
static void propagate_pseudo_copies (void)
static void find_decomposable_subregs (rtx *loc, enum classify_move_insn *pcmi)
static void decompose_register (unsigned int regno)
static rtx simplify_subreg_concatn (machine_mode outermode, rtx op, poly_uint64 orig_byte)
static rtx simplify_gen_subreg_concatn (machine_mode outermode, rtx op, machine_mode innermode, unsigned int byte)
static bool resolve_reg_p (rtx x)
static bool resolve_subreg_p (rtx x)
static bool resolve_subreg_use (rtx *loc, rtx insn)
static void resolve_reg_notes (rtx_insn *insn)
static bool can_decompose_p (rtx x)
static rtx resolve_operand_for_swap_move_operator (rtx opnd)
static rtx_insnresolve_simple_move (rtx set, rtx_insn *insn)
static bool resolve_clobber (rtx pat, rtx_insn *insn)
static bool resolve_use (rtx pat, rtx_insn *insn)
static void resolve_debug (rtx_insn *insn)
static bool find_decomposable_shift_zext (rtx_insn *insn, bool speed_p)
static rtx_insnresolve_shift_zext (rtx_insn *insn, bool speed_p)
static void dump_shift_choices (enum rtx_code code, bool *splitting)
static void dump_choices (bool speed_p, const char *description)
static void decompose_multiword_subregs (bool decompose_copies)
rtl_opt_passmake_pass_lower_subreg (gcc::context *ctxt)
rtl_opt_passmake_pass_lower_subreg2 (gcc::context *ctxt)
rtl_opt_passmake_pass_lower_subreg3 (gcc::context *ctxt)


static bitmap decomposable_context
static bitmap non_decomposable_context
static bitmap subreg_context
static vec< bitmapreg_copy_graph
struct target_lower_subreg default_target_lower_subreg

Macro Definition Documentation

◆ choices


#define FORCE_LOWERING   0


#define LOG_COSTS   0
Decompose multiword subregs.
   Copyright (C) 2007-2024 Free Software Foundation, Inc.
   Contributed by Richard Henderson <rth@redhat.com>
                  Ian Lance Taylor <iant@google.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

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
Decompose multi-word pseudo-registers into individual
pseudo-registers when possible and profitable.  This is possible
when all the uses of a multi-word register are via SUBREG, or are
copies of the register to another location.  Breaking apart the
register permits more CSE and permits better register allocation.
This is profitable if the machine does not have move instructions
to do this.

This pass only splits moves with modes that are wider than
word_mode and ASHIFTs, LSHIFTRTs, ASHIFTRTs and ZERO_EXTENDs with
integer modes that are twice the width of word_mode.  The latter
could be generalized if there was a need to do this, but the trend in
architectures is to not need this.

There are two useful preprocessor defines for use by maintainers:

#define LOG_COSTS 1

if you wish to see the actual cost estimates that are being used
for each mode wider than word mode and the cost estimates for zero
extension and the shifts.   This can be useful when port maintainers
are tuning insn rtx costs.


if you wish to test the pass with all the transformation forced on.
This can be useful for finding bugs in the transformations.   

Referenced by compute_costs(), compute_splitting_shift(), and init_lower_subreg().

◆ twice_word_mode

Enumeration Type Documentation

◆ classify_move_insn

A pointer to one of these values is passed to

Function Documentation

◆ can_decompose_p()

static bool can_decompose_p ( rtx x)
Return whether X can be decomposed into subwords.   

References bitmap_bit_p, GET_MODE, HARD_REGISTER_NUM_P, interesting_mode_p(), REG_P, REGNO, simplify_subreg_regno(), subreg_context, and word_mode.

Referenced by resolve_simple_move().

◆ compute_costs()

static void compute_costs ( bool speed_p,
struct cost_rtxes * rtxes )
Compute what we should do when optimizing for speed or size; SPEED_P
selects which.  Use RTXES for computing costs.   

References choices, compute_splitting_shift(), CONST0_RTX, FORCE_LOWERING, GET_MODE_NAME, GET_RTX_NAME, i, interesting_mode_p(), LOG_COSTS, PUT_MODE(), cost_rtxes::set, set_rtx_cost(), SET_SRC, set_src_cost(), cost_rtxes::source, cost_rtxes::target, twice_word_mode, word_mode, and cost_rtxes::zext.

Referenced by init_lower_subreg().

◆ compute_splitting_shift()

static void compute_splitting_shift ( bool speed_p,
struct cost_rtxes * rtxes,
bool * splitting,
enum rtx_code code,
int word_move_zero_cost,
int word_move_cost )
For each X in the range [0, BITS_PER_WORD), set SPLITTING[X]
to true if it is profitable to split a double-word CODE shift
of X + BITS_PER_WORD bits.  SPEED_P says whether we are testing
for speed or size profitability.

Use the rtxes in RTXES to calculate costs.  WORD_MOVE_ZERO_COST is
the cost of moving zero into a word-mode register.  WORD_MOVE_COST
is the cost of moving between word registers.   

References BITS_PER_WORD, FORCE_LOWERING, GET_MODE_NAME, GET_RTX_NAME, i, LOG_COSTS, shift_cost(), twice_word_mode, and word_mode.

Referenced by compute_costs().

◆ decompose_multiword_subregs()

static void decompose_multiword_subregs ( bool decompose_copies)

◆ decompose_register()

static void decompose_register ( unsigned int regno)
Decompose REGNO into word-sized components.  We smash the REG node
in place.  This ensures that (1) something goes wrong quickly if we
fail to make some replacement, and (2) the debug information inside
the symbol table is automatically kept up to date.   

References dump_file, fputc(), gcc_unreachable, gen_reg_rtx_offset(), GET_MODE, i, interesting_mode_p(), NULL_RTX, PUT_CODE, REGNO, regno_reg_rtx, rtvec_alloc(), RTVEC_ELT, word_mode, XVEC, and XVECEXP.

Referenced by decompose_multiword_subregs().

◆ dump_choices()

static void dump_choices ( bool speed_p,
const char * description )
Print to dump_file a description of what we're doing when optimizing
for speed or size; SPEED_P says which.  DESCRIPTION is a description
of the SPEED_P choice.   

References choices, dump_file, dump_shift_choices(), GET_MODE_NAME, i, interesting_mode_p(), and twice_word_mode.

Referenced by decompose_multiword_subregs().

◆ dump_shift_choices()

static void dump_shift_choices ( enum rtx_code code,
bool * splitting )
Print to dump_file a description of what we're doing with shift code CODE.
SPLITTING[X] is true if we are splitting shifts by X + BITS_PER_WORD.   

References BITS_PER_WORD, dump_file, GET_MODE_NAME, GET_RTX_NAME, i, and twice_word_mode.

Referenced by dump_choices().

◆ find_decomposable_shift_zext()

static bool find_decomposable_shift_zext ( rtx_insn * insn,
bool speed_p )
Check if INSN is a decomposable multiword-shift or zero-extend and
set the decomposable_context bitmap accordingly.  SPEED_P is true
if we are optimizing INSN for speed rather than size.  Return true
if INSN is decomposable.   

References bitmap_set_bit, BITS_PER_WORD, choices, CONST_INT_P, decomposable_context, GET_CODE, GET_MODE, HARD_REGISTER_NUM_P, IN_RANGE, INTVAL, REG_P, REGNO, SET_DEST, SET_SRC, single_set(), twice_word_mode, word_mode, and XEXP.

Referenced by decompose_multiword_subregs().

◆ find_decomposable_subregs()

static void find_decomposable_subregs ( rtx * loc,
enum classify_move_insn * pcmi )
If we find a SUBREG in *LOC which we could use to decompose a
pseudo-register, set a bit in DECOMPOSABLE_CONTEXT.  If we find an
unadorned register which is not a simple pseudo-register copy,
DATA will point at the type of move, and we set a bit in

References bitmap_set_bit, decomposable_context, DECOMPOSABLE_SIMPLE_MOVE, find_decomposable_subregs(), FLOAT_MODE_P, FOR_EACH_SUBRTX_VAR, gcc_unreachable, GET_CODE, GET_MODE, HARD_REGISTER_NUM_P, interesting_mode_p(), MEM_P, non_decomposable_context, NOT_SIMPLE_MOVE, REG_P, REGNO, SIMPLE_MOVE, subreg_context, SUBREG_REG, targetm, word_mode, and XEXP.

Referenced by decompose_multiword_subregs(), and find_decomposable_subregs().

◆ find_pseudo_copy()

static bool find_pseudo_copy ( rtx set)
If SET is a copy from one multi-word pseudo-register to another,
record that in reg_copy_graph.  Return whether it is such a

References b, BITMAP_ALLOC, bitmap_set_bit, HARD_REGISTER_NUM_P, NULL, NULL_RTX, operand_for_swap_move_operator(), reg_copy_graph, REG_P, REGNO, SET_DEST, and SET_SRC.

Referenced by decompose_multiword_subregs().

◆ init_lower_subreg()

void init_lower_subreg ( void )
Do one-per-target initialisation.  This involves determining
which operations on the machine are profitable.  If none are found,
then the pass just returns when called.   

References compute_costs(), const0_rtx, gen_rtx_REG(), GET_MODE_2XWIDER_MODE(), LAST_VIRTUAL_REGISTER, LOG_COSTS, cost_rtxes::set, cost_rtxes::shift, cost_rtxes::source, cost_rtxes::target, this_target_lower_subreg, twice_word_mode, word_mode, and cost_rtxes::zext.

Referenced by backend_init_target().

◆ interesting_mode_p()

static bool interesting_mode_p ( machine_mode mode,
unsigned int * bytes,
unsigned int * words )
Return true if MODE is a mode we know how to lower.  When returning true,
store its byte size in *BYTES and its word size in *WORDS.   

References CEIL, and GET_MODE_SIZE().

Referenced by can_decompose_p(), compute_costs(), decompose_register(), dump_choices(), find_decomposable_subregs(), resolve_clobber(), resolve_simple_move(), and simplify_subreg_concatn().

◆ make_pass_lower_subreg()

rtl_opt_pass * make_pass_lower_subreg ( gcc::context * ctxt)

◆ make_pass_lower_subreg2()

rtl_opt_pass * make_pass_lower_subreg2 ( gcc::context * ctxt)

◆ make_pass_lower_subreg3()

rtl_opt_pass * make_pass_lower_subreg3 ( gcc::context * ctxt)

◆ operand_for_swap_move_operator()

static rtx operand_for_swap_move_operator ( rtx x)
If X is an operator that can be treated as a simple move that we
can split, then return the operand that is operated on.   

References BITS_PER_WORD, CONST_INT_P, GET_CODE, GET_MODE, INTVAL, NULL_RTX, simple_move_operand(), twice_word_mode, and XEXP.

Referenced by find_pseudo_copy(), resolve_simple_move(), and simple_move().

◆ propagate_pseudo_copies()

static void propagate_pseudo_copies ( void )
Look through the registers in DECOMPOSABLE_CONTEXT.  For each case
where they are copied to another register, add the register to
which they are copied to DECOMPOSABLE_CONTEXT.  Use
NON_DECOMPOSABLE_CONTEXT to limit this--we don't bother to track
copies of registers which are in NON_DECOMPOSABLE_CONTEXT.   

References b, bitmap_and_compl(), bitmap_clear(), bitmap_copy(), bitmap_empty_p(), bitmap_ior_and_compl_into(), bitmap_ior_into(), decomposable_context, EXECUTE_IF_SET_IN_BITMAP, i, non_decomposable_context, propagate(), queue, and reg_copy_graph.

Referenced by decompose_multiword_subregs().

◆ resolve_clobber()

static bool resolve_clobber ( rtx pat,
rtx_insn * insn )
Change a CLOBBER of a decomposed register into a CLOBBER of the
component registers.  Return whether we changed something.   

References df_insn_rescan(), emit_insn_after(), gcc_assert, gcc_unreachable, GET_MODE, i, interesting_mode_p(), NULL_RTX, paradoxical_subreg_p(), resolve_reg_notes(), resolve_reg_p(), resolve_subreg_p(), simplify_gen_subreg_concatn(), SUBREG_REG, validate_change(), word_mode, and XEXP.

Referenced by decompose_multiword_subregs().

◆ resolve_debug()

static void resolve_debug ( rtx_insn * insn)

◆ resolve_operand_for_swap_move_operator()

static rtx resolve_operand_for_swap_move_operator ( rtx opnd)
OPND is a concatn operand this is used with a simple move operator.
Return a new rtx with the concatn's operands swapped.   

References copy_rtx(), gcc_assert, GET_CODE, and XVECEXP.

Referenced by resolve_simple_move().

◆ resolve_reg_notes()

static void resolve_reg_notes ( rtx_insn * insn)

◆ resolve_reg_p()

static bool resolve_reg_p ( rtx x)
Return whether we should resolve X into the registers into which it
was decomposed.   

References GET_CODE.

Referenced by resolve_clobber(), resolve_debug(), resolve_reg_notes(), resolve_shift_zext(), resolve_simple_move(), resolve_subreg_p(), resolve_subreg_use(), and resolve_use().

◆ resolve_shift_zext()

static rtx_insn * resolve_shift_zext ( rtx_insn * insn,
bool speed_p )
Decompose a more than word wide shift (in INSN) of a multiword
pseudo or a multiword zero-extend of a wordmode pseudo into a move
and 'set to zero' insn.  SPEED_P says whether we are optimizing
for speed or size, when checking if a ZERO_EXTEND is preferable.
Return a pointer to the new insn when a replacement was done.   

References BITS_PER_WORD, choices, CONST0_RTX, copy_rtx(), delete_insn(), dump_file, emit_insn_before(), emit_move_insn(), end_sequence(), expand_shift(), force_reg(), GET_CODE, get_insns(), GET_MODE, GET_MODE_SIZE(), INSN_UID(), insns, INTVAL, is_a(), NEXT_INSN(), NULL, NULL_RTX, REG_P, resolve_reg_p(), SET_DEST, SET_SRC, simplify_gen_subreg_concatn(), simplify_gen_unary(), single_set(), start_sequence(), twice_word_mode, word_mode, and XEXP.

Referenced by decompose_multiword_subregs().

◆ resolve_simple_move()

◆ resolve_subreg_p()

static bool resolve_subreg_p ( rtx x)
Return whether X is a SUBREG of a register which we need to

References GET_CODE, resolve_reg_p(), and SUBREG_REG.

Referenced by resolve_clobber(), resolve_debug(), resolve_simple_move(), resolve_subreg_use(), and resolve_use().

◆ resolve_subreg_use()

static bool resolve_subreg_use ( rtx * loc,
rtx insn )

◆ resolve_use()

static bool resolve_use ( rtx pat,
rtx_insn * insn )
A USE of a decomposed register is no longer meaningful.  Return
whether we changed something.   

References delete_insn(), resolve_reg_notes(), resolve_reg_p(), resolve_subreg_p(), and XEXP.

Referenced by decompose_multiword_subregs().

◆ shift_cost()

static int shift_cost ( bool speed_p,
struct cost_rtxes * rtxes,
enum rtx_code code,
machine_mode mode,
int op1 )
Return the cost of a CODE shift in mode MODE by OP1 bits, using the
rtxes in RTXES.  SPEED_P selects between the speed and size cost.   

References gen_int_shift_amount(), PUT_CODE, PUT_MODE(), set_src_cost(), cost_rtxes::shift, cost_rtxes::source, and XEXP.

Referenced by compute_splitting_shift().

◆ simple_move()

static rtx simple_move ( rtx_insn * insn,
bool speed_p )
If INSN is a single set between two objects that we want to split,
return the single set.  SPEED_P says whether we are optimizing
INSN for speed or size.

INSN should have been passed to recog and extract_insn before this
is called.   

References choices, GET_CODE, GET_MODE, GET_MODE_BITSIZE(), GET_MODE_CLASS, int_mode_for_size(), recog_data_d::n_operands, NULL_RTX, recog_data_d::operand, operand_for_swap_move_operator(), recog_data, SCALAR_INT_MODE_P, cost_rtxes::set, SET_DEST, SET_SRC, simple_move_operand(), single_set(), and targetm.

Referenced by decompose_multiword_subregs().

◆ simple_move_operand()

static bool simple_move_operand ( rtx x)

◆ simplify_gen_subreg_concatn()

static rtx simplify_gen_subreg_concatn ( machine_mode outermode,
rtx op,
machine_mode innermode,
unsigned int byte )

◆ simplify_subreg_concatn()

Variable Documentation

◆ decomposable_context

bitmap decomposable_context
Bit N in this bitmap is set if regno N is used in a context in
which we can decompose it.   

Referenced by decompose_multiword_subregs(), find_decomposable_shift_zext(), find_decomposable_subregs(), and propagate_pseudo_copies().

◆ default_target_lower_subreg

struct target_lower_subreg default_target_lower_subreg

◆ non_decomposable_context

bitmap non_decomposable_context
Bit N in this bitmap is set if regno N is used in a context in
which it cannot be decomposed.   

Referenced by decompose_multiword_subregs(), find_decomposable_subregs(), and propagate_pseudo_copies().

◆ reg_copy_graph

vec<bitmap> reg_copy_graph
Bit N in the bitmap in element M of this array is set if there is a
copy from reg M to reg N.   

Referenced by decompose_multiword_subregs(), find_pseudo_copy(), and propagate_pseudo_copies().

◆ subreg_context

bitmap subreg_context
Bit N in this bitmap is set if regno N is used in a subreg
which changes the mode but not the size.  This typically happens
when the register accessed as a floating-point value; we want to
avoid generating accesses to its subwords in integer modes.   

Referenced by can_decompose_p(), decompose_multiword_subregs(), and find_decomposable_subregs().