GCC Middle and Back End API Reference
auto-inc-dec.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 "df.h"
#include "insn-config.h"
#include "memmodel.h"
#include "emit-rtl.h"
#include "recog.h"
#include "cfgrtl.h"
#include "expr.h"
#include "tree-pass.h"
#include "dbgcnt.h"
#include "print-rtl.h"
#include "valtrack.h"
Include dependency graph for auto-inc-dec.cc:

Data Structures

struct  inc_insn
 
struct  mem_insn
 

Enumerations

enum  form {
  FORM_PRE_ADD , FORM_PRE_INC , FORM_POST_ADD , FORM_POST_INC ,
  FORM_last
}
 
enum  inc_state {
  INC_ZERO , INC_NEG_SIZE , INC_POS_SIZE , INC_NEG_ANY ,
  INC_POS_ANY , INC_REG , INC_last
}
 
enum  gen_form {
  NOTHING , SIMPLE_PRE_INC , SIMPLE_POST_INC , SIMPLE_PRE_DEC ,
  SIMPLE_POST_DEC , DISP_PRE , DISP_POST , REG_PRE ,
  REG_POST
}
 

Functions

static enum inc_state set_inc_state (HOST_WIDE_INT val, poly_int64 size)
 
static void init_decision_table (void)
 
static void dump_inc_insn (FILE *file)
 
static void dump_mem_insn (FILE *file)
 
static void move_dead_notes (rtx_insn *to_insn, rtx_insn *from_insn, rtx pattern)
 
static bool attempt_change (rtx new_addr, rtx inc_reg)
 
static bool try_merge (void)
 
static rtx_insnget_next_ref (int regno, basic_block bb, rtx_insn **next_array)
 
static bool parse_add_or_inc (rtx_insn *insn, bool before_mem)
 
static int find_address (rtx *address_of_x, rtx findreg)
 
static bool find_inc (bool first_try)
 
static bool find_mem (rtx *address_of_x)
 
static void merge_in_block (int max_reg, basic_block bb)
 
rtl_opt_passmake_pass_inc_dec (gcc::context *ctxt)
 

Variables

static rtx mem_tmp
 
static bool initialized = false
 
static enum gen_form decision_table [INC_last][INC_last][FORM_last]
 
static struct inc_insn inc_insn
 
static struct mem_insn mem_insn
 
static rtx_insn ** reg_next_debug_use = NULL
 
static rtx_insn ** reg_next_use = NULL
 
static rtx_insn ** reg_next_inc_use = NULL
 
static rtx_insn ** reg_next_def = NULL
 

Enumeration Type Documentation

◆ form

Discovery of auto-inc and auto-dec instructions.
   Copyright (C) 2006-2024 Free Software Foundation, Inc.
   Contributed by Kenneth Zadeck <zadeck@naturalbridge.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/>.   
This pass was originally removed from flow.c. However there is
 almost nothing that remains of that code.

 There are (4) basic forms that are matched:

    (1) FORM_PRE_ADD
         a <- b + c
         ...
         *a

      becomes

         a <- b
         ...
         *(a += c) pre

      or, alternately,

         a <- b + c
         ...
         *b

      becomes

         a <- b
         ...
         *(a += c) post

      This uses a post-add, but it's handled as FORM_PRE_ADD because
      the "increment" insn appears before the memory access.


    (2) FORM_PRE_INC
         a += c
         ...
         *a

      becomes

         ...
         *(a += c) pre


    (3) FORM_POST_ADD
         *a
         ...
         b <- a + c

         (For this case to be true, b must not be assigned or used between
         the *a and the assignment to b.  B must also be a Pmode reg.)

      becomes

         b <- a
         *(b += c) post
         ...


    (4) FORM_POST_INC
         *a
         ...
         a <- a + c

      becomes

         *(a += c) post
         ...


There are three types of values of c.

  1) c is a constant equal to the width of the value being accessed by
     the pointer.  This is useful for machines that have
     HAVE_PRE_INCREMENT, HAVE_POST_INCREMENT, HAVE_PRE_DECREMENT or
     HAVE_POST_DECREMENT defined.

  2) c is a constant not equal to the width of the value being accessed
     by the pointer.  This is useful for machines that have
     HAVE_PRE_MODIFY_DISP, HAVE_POST_MODIFY_DISP defined.

  3) c is a register.  This is useful for machines that have
     HAVE_PRE_MODIFY_REG,  HAVE_POST_MODIFY_REG

The is one special case: if a already had an offset equal to it +-
its width and that offset is equal to -c when the increment was
before the ref or +c if the increment was after the ref, then if we
can do the combination but switch the pre/post bit.   
Enumerator
FORM_PRE_ADD 
FORM_PRE_INC 
FORM_POST_ADD 
FORM_POST_INC 
FORM_last 

◆ gen_form

The eight forms that pre/post inc/dec can take.   
Enumerator
NOTHING 
SIMPLE_PRE_INC 
SIMPLE_POST_INC 
SIMPLE_PRE_DEC 
SIMPLE_POST_DEC 
DISP_PRE 
DISP_POST 
REG_PRE 
REG_POST 

◆ inc_state

The states of the second operands of mem refs and inc insns.  If no
second operand of the mem_ref was found, it is assumed to just be
ZERO.  SIZE is the size of the mode accessed in the memref.  The
ANY is used for constants that are not +-size or 0.  REG is used if
the forms are reg1 + reg2.   
Enumerator
INC_ZERO 
INC_NEG_SIZE 
INC_POS_SIZE 
INC_NEG_ANY 
INC_POS_ANY 
INC_REG 
INC_last 

Function Documentation

◆ attempt_change()

◆ dump_inc_insn()

◆ dump_mem_insn()

static void dump_mem_insn ( FILE * file)
static

◆ find_address()

static int find_address ( rtx * address_of_x,
rtx findreg )
static
A recursive function that checks all of the mem uses in
ADDRESS_OF_X to see if any single one of them is compatible with
what has been found in inc_insn.  To avoid accidental matches, we
will only find MEMs with FINDREG, be it inc_insn.reg_res, be it
inc_insn.reg0.

-1 is returned for success.  0 is returned if nothing was found and
1 is returned for failure.  

References b, CONST_INT_P, find_address(), GEN_INT, GET_CODE, GET_RTX_FORMAT, GET_RTX_LENGTH, ggc_alloc(), i, INTVAL, mem_insn::mem_loc, inc_insn::reg0, mem_insn::reg0, inc_insn::reg1, mem_insn::reg1, inc_insn::reg1_is_const, mem_insn::reg1_is_const, inc_insn::reg1_val, mem_insn::reg1_val, inc_insn::reg_res, rtx_equal_p(), XEXP, XVECEXP, and XVECLEN.

Referenced by find_address(), and merge_in_block().

◆ find_inc()

static bool find_inc ( bool first_try)
static
Once a suitable mem reference has been found and the MEM_INSN
structure has been filled in, FIND_INC is called to see if there is
a suitable add or inc insn that follows the mem reference and
determine if it is suitable to merge.

In the case where the MEM_INSN has two registers in the reference,
this function may be called recursively.  The first time looking
for an add of the first register, and if that fails, looking for an
add of the second register.  The FIRST_TRY parameter is used to
only allow the parameters to be reversed once.   

References BLOCK_FOR_INSN(), count_occurrences(), DF_INSN_LUID, DF_REF_REGNO, dump_file, dump_inc_insn(), dump_mem_insn(), find_inc(), FOR_EACH_INSN_DEF, inc_insn::form, FORM_POST_ADD, FORM_POST_INC, GET_MODE, get_next_ref(), ggc_alloc(), inc_insn::insn, mem_insn::insn, MEM_ADDR_SPACE, mem_insn::mem_loc, parse_add_or_inc(), PATTERN(), inc_insn::reg0, mem_insn::reg0, inc_insn::reg1, mem_insn::reg1, inc_insn::reg1_is_const, mem_insn::reg1_is_const, inc_insn::reg1_val, mem_insn::reg1_val, reg_next_def, reg_next_inc_use, reg_next_use, reg_overlap_mentioned_p(), inc_insn::reg_res, REGNO, rtx_equal_p(), targetm, and try_merge().

Referenced by find_inc(), and find_mem().

◆ find_mem()

static bool find_mem ( rtx * address_of_x)
static
A recursive function that walks ADDRESS_OF_X to find all of the mem
uses in pat that could be used as an auto inc or dec.  It then
calls FIND_INC for each one.   

References CONST_INT_P, find_inc(), find_mem(), GEN_INT, GET_CODE, GET_RTX_FORMAT, GET_RTX_LENGTH, ggc_alloc(), i, INTVAL, mem_insn::mem_loc, mem_insn::reg0, mem_insn::reg1, mem_insn::reg1_is_const, mem_insn::reg1_val, REG_P, XEXP, XVECEXP, and XVECLEN.

Referenced by find_mem(), and merge_in_block().

◆ get_next_ref()

static rtx_insn * get_next_ref ( int regno,
basic_block bb,
rtx_insn ** next_array )
static
Return the next insn that uses (if reg_next_use is passed in
NEXT_ARRAY) or defines (if reg_next_def is passed in NEXT_ARRAY)
REGNO in BB.   

References BLOCK_FOR_INSN(), ggc_alloc(), and NULL.

Referenced by find_inc(), and merge_in_block().

◆ init_decision_table()

◆ make_pass_inc_dec()

rtl_opt_pass * make_pass_inc_dec ( gcc::context * ctxt)

References ggc_alloc().

◆ merge_in_block()

◆ move_dead_notes()

static void move_dead_notes ( rtx_insn * to_insn,
rtx_insn * from_insn,
rtx pattern )
static
Move dead note that match PATTERN to TO_INSN from FROM_INSN.  We do
not really care about moving any other notes from the inc or add
insn.  Moving the REG_EQUAL and REG_EQUIV is clearly wrong and it
does not appear that there are any other kinds of relevant notes.   

References ggc_alloc(), NULL, REG_NOTE_KIND, REG_NOTES, and XEXP.

Referenced by attempt_change().

◆ parse_add_or_inc()

static bool parse_add_or_inc ( rtx_insn * insn,
bool before_mem )
static
Return true if INSN is of a form "a = b op c" where a and b are
regs.  op is + if c is a reg and +|- if c is a const.  Fill in
INC_INSN with what is found.

This function is called in two contexts, if BEFORE_MEM is true,
this is called for each insn in the basic block.  If BEFORE_MEM is
false, it is called for the instruction in the block that uses the
index register for some memory reference that is currently being
processed.   

References CONST_INT_P, inc_insn::form, FORM_POST_ADD, FORM_POST_INC, FORM_PRE_ADD, FORM_PRE_INC, frame_pointer_rtx, GEN_INT, GET_CODE, ggc_alloc(), HAVE_POST_MODIFY_REG, HAVE_PRE_MODIFY_REG, inc_insn::insn, INTVAL, inc_insn::pat, inc_insn::reg0, inc_insn::reg1, inc_insn::reg1_is_const, inc_insn::reg1_val, REG_P, inc_insn::reg_res, rtx_equal_p(), SET_DEST, SET_SRC, single_set(), and XEXP.

Referenced by find_inc(), and merge_in_block().

◆ set_inc_state()

static enum inc_state set_inc_state ( HOST_WIDE_INT val,
poly_int64 size )
static

◆ try_merge()

static bool try_merge ( void )
static
Try to combine the instruction in INC_INSN with the instruction in
MEM_INSN.  First the form is determined using the DECISION_TABLE
and the results of parsing the INC_INSN and the MEM_INSN.
Assuming the form is ok, a prototype new address is built which is
passed to ATTEMPT_CHANGE for final processing.   

References attempt_change(), dbg_cnt(), decision_table, DISP_POST, DISP_PRE, dump_file, find_regno_note(), inc_insn::form, FORM_last, FORM_POST_ADD, FORM_POST_INC, FORM_PRE_ADD, FORM_PRE_INC, gcc_unreachable, GET_MODE, GET_MODE_SIZE(), ggc_alloc(), INC_REG, inc_insn::insn, mem_insn::insn, mem_insn::mem_loc, NOTHING, NULL, mem_insn::reg0, inc_insn::reg1, inc_insn::reg1_is_const, mem_insn::reg1_is_const, inc_insn::reg1_state, mem_insn::reg1_state, inc_insn::reg1_val, mem_insn::reg1_val, reg_mode, REG_POST, REG_PRE, inc_insn::reg_res, REGNO, set_inc_state(), SIMPLE_POST_DEC, SIMPLE_POST_INC, SIMPLE_PRE_DEC, SIMPLE_PRE_INC, and stack_pointer_rtx.

Referenced by find_inc(), and merge_in_block().

Variable Documentation

◆ decision_table

enum gen_form decision_table[INC_last][INC_last][FORM_last]
static

Referenced by init_decision_table(), and try_merge().

◆ inc_insn

struct inc_insn inc_insn
static

◆ initialized

bool initialized = false
static
The DECISION_TABLE that describes what form, if any, the increment
or decrement will take. It is a three dimensional table.  The first
index is the type of constant or register found as the second
operand of the inc insn.  The second index is the type of constant
or register found as the second operand of the memory reference (if
no second operand exists, 0 is used).  The third index is the form
and location (relative to the mem reference) of inc insn.   

Referenced by alloc_aux_for_blocks(), alloc_aux_for_edges(), based_loc_descr(), concat_loc_descriptor(), concatn_loc_descriptor(), df_set_blocks(), dw_loc_list(), dw_loc_list_1(), dw_sra_loc_expr(), emit_note_insn_var_location(), init_decision_table(), loc_descriptor(), mem_loc_descriptor(), multiple_reg_loc_descriptor(), one_reg_loc_descriptor(), one_time_initialization(), reg_loc_descriptor(), set_slot_part(), set_variable_part(), unshare_variable(), var_mem_decl_set(), var_mem_delete_and_set(), var_mem_set(), var_reg_decl_set(), var_reg_delete_and_set(), and var_reg_set().

◆ mem_insn

struct mem_insn mem_insn
static

◆ mem_tmp

rtx mem_tmp
static
Tmp mem rtx for use in cost modeling.   

Referenced by attempt_change().

◆ reg_next_debug_use

rtx_insn** reg_next_debug_use = NULL
static
The following three arrays contain pointers to instructions. They
  are indexed by REGNO.  At any point in the basic block where we are
  looking these three arrays contain, respectively, the next insn
  that uses REGNO, the next inc or add insn that uses REGNO and the
  next insn that sets REGNO.

  The arrays are not cleared when we move from block to block so
  whenever an insn is retrieved from these arrays, it's block number
  must be compared with the current block.

Referenced by attempt_change(), and merge_in_block().

◆ reg_next_def

rtx_insn** reg_next_def = NULL
static

◆ reg_next_inc_use

rtx_insn** reg_next_inc_use = NULL
static

◆ reg_next_use

rtx_insn** reg_next_use = NULL
static