LCOV - code coverage report
Current view: top level - gcc - tree-ssa-address.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 83.1 % 509 423
Test Date: 2026-07-11 15:47:05 Functions: 91.7 % 24 22
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Memory address lowering and addressing mode selection.
       2              :    Copyright (C) 2004-2026 Free Software Foundation, Inc.
       3              : 
       4              : This file is part of GCC.
       5              : 
       6              : GCC is free software; you can redistribute it and/or modify it
       7              : under the terms of the GNU General Public License as published by the
       8              : Free Software Foundation; either version 3, or (at your option) any
       9              : later version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful, but WITHOUT
      12              : ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14              : for more details.
      15              : 
      16              : You should have received a copy of the GNU General Public License
      17              : along with GCC; see the file COPYING3.  If not see
      18              : <http://www.gnu.org/licenses/>.  */
      19              : 
      20              : /* Utility functions for manipulation with TARGET_MEM_REFs -- tree expressions
      21              :    that directly map to addressing modes of the target.  */
      22              : 
      23              : #include "config.h"
      24              : #include "system.h"
      25              : #include "coretypes.h"
      26              : #include "backend.h"
      27              : #include "target.h"
      28              : #include "rtl.h"
      29              : #include "tree.h"
      30              : #include "gimple.h"
      31              : #include "memmodel.h"
      32              : #include "stringpool.h"
      33              : #include "tree-vrp.h"
      34              : #include "tree-ssanames.h"
      35              : #include "expmed.h"
      36              : #include "insn-config.h"
      37              : #include "emit-rtl.h"
      38              : #include "recog.h"
      39              : #include "tree-pretty-print.h"
      40              : #include "fold-const.h"
      41              : #include "stor-layout.h"
      42              : #include "gimple-iterator.h"
      43              : #include "gimplify-me.h"
      44              : #include "tree-ssa-loop-ivopts.h"
      45              : #include "expr.h"
      46              : #include "tree-dfa.h"
      47              : #include "dumpfile.h"
      48              : #include "tree-affine.h"
      49              : #include "gimplify.h"
      50              : #include "builtins.h"
      51              : 
      52              : /* FIXME: We compute address costs using RTL.  */
      53              : #include "tree-ssa-address.h"
      54              : 
      55              : /* TODO -- handling of symbols (according to Richard Hendersons
      56              :    comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html):
      57              : 
      58              :    There are at least 5 different kinds of symbols that we can run up against:
      59              : 
      60              :      (1) binds_local_p, small data area.
      61              :      (2) binds_local_p, eg local statics
      62              :      (3) !binds_local_p, eg global variables
      63              :      (4) thread local, local_exec
      64              :      (5) thread local, !local_exec
      65              : 
      66              :    Now, (1) won't appear often in an array context, but it certainly can.
      67              :    All you have to do is set -GN high enough, or explicitly mark any
      68              :    random object __attribute__((section (".sdata"))).
      69              : 
      70              :    All of these affect whether or not a symbol is in fact a valid address.
      71              :    The only one tested here is (3).  And that result may very well
      72              :    be incorrect for (4) or (5).
      73              : 
      74              :    An incorrect result here does not cause incorrect results out the
      75              :    back end, because the expander in expr.cc validizes the address.  However
      76              :    it would be nice to improve the handling here in order to produce more
      77              :    precise results.  */
      78              : 
      79              : /* A "template" for memory address, used to determine whether the address is
      80              :    valid for mode.  */
      81              : 
      82              : struct GTY (()) mem_addr_template {
      83              :   rtx ref;                      /* The template.  */
      84              :   rtx * GTY ((skip)) step_p;    /* The point in template where the step should be
      85              :                                    filled in.  */
      86              :   rtx * GTY ((skip)) off_p;     /* The point in template where the offset should
      87              :                                    be filled in.  */
      88              : };
      89              : 
      90              : 
      91              : /* The templates.  Each of the low five bits of the index corresponds to one
      92              :    component of TARGET_MEM_REF being present, while the high bits identify
      93              :    the address space.  See TEMPL_IDX.  */
      94              : 
      95              : static GTY(()) vec<mem_addr_template, va_gc> *mem_addr_template_list;
      96              : 
      97              : #define TEMPL_IDX(AS, SYMBOL, BASE, INDEX, STEP, OFFSET) \
      98              :   (((int) (AS) << 5) \
      99              :    | ((SYMBOL != 0) << 4) \
     100              :    | ((BASE != 0) << 3) \
     101              :    | ((INDEX != 0) << 2) \
     102              :    | ((STEP != 0) << 1) \
     103              :    | (OFFSET != 0))
     104              : 
     105              : /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX,
     106              :    STEP and OFFSET to *ADDR using address mode ADDRESS_MODE.  Stores pointers
     107              :    to where step is placed to *STEP_P and offset to *OFFSET_P.  */
     108              : 
     109              : static void
     110      1047021 : gen_addr_rtx (machine_mode address_mode,
     111              :               rtx symbol, rtx base, rtx index, rtx step, rtx offset,
     112              :               rtx *addr, rtx **step_p, rtx **offset_p)
     113              : {
     114      1047021 :   rtx act_elem;
     115              : 
     116      1047021 :   *addr = NULL_RTX;
     117      1047021 :   if (step_p)
     118       190284 :     *step_p = NULL;
     119      1047021 :   if (offset_p)
     120       190284 :     *offset_p = NULL;
     121              : 
     122      1047021 :   if (index && index != const0_rtx)
     123              :     {
     124       556191 :       act_elem = index;
     125       556191 :       if (step)
     126              :         {
     127       272856 :           act_elem = gen_rtx_MULT (address_mode, act_elem, step);
     128              : 
     129       272856 :           if (step_p)
     130        68100 :             *step_p = &XEXP (act_elem, 1);
     131              :         }
     132              : 
     133       556191 :       *addr = act_elem;
     134              :     }
     135              : 
     136      1047021 :   if (base && base != const0_rtx)
     137              :     {
     138       841901 :       if (*addr)
     139       351296 :         *addr = simplify_gen_binary (PLUS, address_mode, base, *addr);
     140              :       else
     141       490605 :         *addr = base;
     142              :     }
     143              : 
     144      1047021 :   if (symbol)
     145              :     {
     146       220431 :       act_elem = symbol;
     147       220431 :       if (offset)
     148              :         {
     149        54467 :           act_elem = gen_rtx_PLUS (address_mode, act_elem, offset);
     150              : 
     151        54467 :           if (offset_p)
     152        13448 :             *offset_p = &XEXP (act_elem, 1);
     153              : 
     154        54467 :           if (GET_CODE (symbol) == SYMBOL_REF
     155        54467 :               || GET_CODE (symbol) == LABEL_REF
     156        17766 :               || GET_CODE (symbol) == CONST)
     157        36701 :             act_elem = gen_rtx_CONST (address_mode, act_elem);
     158              :         }
     159              : 
     160       220431 :       if (*addr)
     161       220206 :         *addr = gen_rtx_PLUS (address_mode, *addr, act_elem);
     162              :       else
     163          225 :         *addr = act_elem;
     164              :     }
     165       826590 :   else if (offset)
     166              :     {
     167       361831 :       if (*addr)
     168              :         {
     169       361831 :           *addr = gen_rtx_PLUS (address_mode, *addr, offset);
     170       361831 :           if (offset_p)
     171        67993 :             *offset_p = &XEXP (*addr, 1);
     172              :         }
     173              :       else
     174              :         {
     175            0 :           *addr = offset;
     176            0 :           if (offset_p)
     177            0 :             *offset_p = addr;
     178              :         }
     179              :     }
     180              : 
     181      1047021 :   if (!*addr)
     182            0 :     *addr = const0_rtx;
     183      1047021 : }
     184              : 
     185              : /* Returns address for TARGET_MEM_REF with parameters given by ADDR
     186              :    in address space AS.
     187              :    If REALLY_EXPAND is false, just make fake registers instead
     188              :    of really expanding the operands, and perform the expansion in-place
     189              :    by using one of the "templates".  */
     190              : 
     191              : rtx
     192     18862733 : addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
     193              :                   bool really_expand)
     194              : {
     195     18862733 :   scalar_int_mode address_mode = targetm.addr_space.address_mode (as);
     196     18862733 :   scalar_int_mode pointer_mode = targetm.addr_space.pointer_mode (as);
     197     18862733 :   rtx address, sym, bse, idx, st, off;
     198     18862733 :   struct mem_addr_template *templ;
     199              : 
     200     18862733 :   if (addr->step && !integer_onep (addr->step))
     201      5646578 :     st = immed_wide_int_const (wi::to_wide (addr->step), pointer_mode);
     202              :   else
     203              :     st = NULL_RTX;
     204              : 
     205     18862733 :   if (addr->offset && !integer_zerop (addr->offset))
     206              :     {
     207      7990811 :       poly_offset_int dc
     208      7990811 :         = poly_offset_int::from (wi::to_poly_wide (addr->offset), SIGNED);
     209      7990811 :       off = immed_wide_int_const (dc, pointer_mode);
     210              :     }
     211              :   else
     212              :     off = NULL_RTX;
     213              : 
     214     18862733 :   if (!really_expand)
     215              :     {
     216     36011992 :       unsigned int templ_index
     217     39325069 :         = TEMPL_IDX (as, addr->symbol, addr->base, addr->index, st, off);
     218              : 
     219     18005996 :       if (templ_index >= vec_safe_length (mem_addr_template_list))
     220       105020 :         vec_safe_grow_cleared (mem_addr_template_list, templ_index + 1, true);
     221              : 
     222              :       /* Reuse the templates for addresses, so that we do not waste memory.  */
     223     18005996 :       templ = &(*mem_addr_template_list)[templ_index];
     224     18005996 :       if (!templ->ref)
     225              :         {
     226       190284 :           sym = (addr->symbol ?
     227        30129 :                  gen_rtx_SYMBOL_REF (pointer_mode, ggc_strdup ("test_symbol"))
     228              :                  : NULL_RTX);
     229       190284 :           bse = (addr->base ?
     230       165019 :                  gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 1)
     231              :                  : NULL_RTX);
     232       190284 :           idx = (addr->index ?
     233       138732 :                  gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 2)
     234              :                  : NULL_RTX);
     235              : 
     236       190284 :           gen_addr_rtx (pointer_mode, sym, bse, idx,
     237              :                         st? const0_rtx : NULL_RTX,
     238              :                         off? const0_rtx : NULL_RTX,
     239              :                         &templ->ref,
     240              :                         &templ->step_p,
     241              :                         &templ->off_p);
     242              :         }
     243              : 
     244     18005996 :       if (st)
     245      5441822 :         *templ->step_p = st;
     246     18005996 :       if (off)
     247      7655954 :         *templ->off_p = off;
     248              : 
     249     18005996 :       return templ->ref;
     250              :     }
     251              : 
     252              :   /* Otherwise really expand the expressions.  */
     253       856737 :   sym = (addr->symbol
     254       856737 :          ? expand_expr (addr->symbol, NULL_RTX, pointer_mode, EXPAND_NORMAL)
     255              :          : NULL_RTX);
     256       856737 :   bse = (addr->base
     257       856737 :          ? expand_expr (addr->base, NULL_RTX, pointer_mode, EXPAND_NORMAL)
     258              :          : NULL_RTX);
     259       856737 :   idx = (addr->index
     260       856737 :          ? expand_expr (addr->index, NULL_RTX, pointer_mode, EXPAND_NORMAL)
     261              :          : NULL_RTX);
     262              : 
     263              :   /* addr->base could be an SSA_NAME that was set to a constant value.  The
     264              :      call to expand_expr may expose that constant.  If so, fold the value
     265              :      into OFF and clear BSE.  Otherwise we may later try to pull a mode from
     266              :      BSE to generate a REG, which won't work with constants because they
     267              :      are modeless.  */
     268       856737 :   if (bse && GET_CODE (bse) == CONST_INT)
     269              :     {
     270            0 :       if (off)
     271            0 :         off = simplify_gen_binary (PLUS, pointer_mode, bse, off);
     272              :       else
     273              :         off = bse;
     274            0 :       gcc_assert (GET_CODE (off) == CONST_INT);
     275              :       bse = NULL_RTX;
     276              :     }
     277       856737 :   gen_addr_rtx (pointer_mode, sym, bse, idx, st, off, &address, NULL, NULL);
     278       856737 :   if (pointer_mode != address_mode)
     279            7 :     address = convert_memory_address (address_mode, address);
     280       856737 :   return address;
     281              : }
     282              : 
     283              : /* implement addr_for_mem_ref() directly from a tree, which avoids exporting
     284              :    the mem_address structure.  */
     285              : 
     286              : rtx
     287       856737 : addr_for_mem_ref (tree exp, addr_space_t as, bool really_expand)
     288              : {
     289       856737 :   struct mem_address addr;
     290       856737 :   get_address_description (exp, &addr);
     291       856737 :   return addr_for_mem_ref (&addr, as, really_expand);
     292              : }
     293              : 
     294              : /* Returns address of MEM_REF in TYPE.  */
     295              : 
     296              : tree
     297        67103 : tree_mem_ref_addr (tree type, tree mem_ref)
     298              : {
     299        67103 :   tree addr;
     300        67103 :   tree act_elem;
     301        67103 :   tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
     302        67103 :   tree addr_base = NULL_TREE, addr_off = NULL_TREE;
     303              : 
     304        67103 :   addr_base = fold_convert (type, TMR_BASE (mem_ref));
     305              : 
     306        67103 :   act_elem = TMR_INDEX (mem_ref);
     307        67103 :   if (act_elem)
     308              :     {
     309         3043 :       if (step)
     310         2346 :         act_elem = fold_build2 (MULT_EXPR, TREE_TYPE (act_elem),
     311              :                                 act_elem, step);
     312              :       addr_off = act_elem;
     313              :     }
     314              : 
     315        67103 :   act_elem = TMR_INDEX2 (mem_ref);
     316        67103 :   if (act_elem)
     317              :     {
     318            0 :       if (addr_off)
     319            0 :         addr_off = fold_build2 (PLUS_EXPR, TREE_TYPE (addr_off),
     320              :                                 addr_off, act_elem);
     321              :       else
     322              :         addr_off = act_elem;
     323              :     }
     324              : 
     325        67103 :   if (offset && !integer_zerop (offset))
     326              :     {
     327        50160 :       if (addr_off)
     328          629 :         addr_off = fold_build2 (PLUS_EXPR, TREE_TYPE (addr_off), addr_off,
     329              :                                 fold_convert (TREE_TYPE (addr_off), offset));
     330              :       else
     331              :         addr_off = offset;
     332              :     }
     333              : 
     334        67103 :   if (addr_off)
     335        52574 :     addr = fold_build_pointer_plus (addr_base, addr_off);
     336              :   else
     337              :     addr = addr_base;
     338              : 
     339        67103 :   return addr;
     340              : }
     341              : 
     342              : /* Returns true if a memory reference in MODE and with parameters given by
     343              :    ADDR is valid on the current target.  */
     344              : 
     345              : bool
     346     11378599 : valid_mem_ref_p (machine_mode mode, addr_space_t as,
     347              :                  struct mem_address *addr, code_helper ch)
     348              : {
     349     11378599 :   rtx address;
     350              : 
     351     11378599 :   address = addr_for_mem_ref (addr, as, false);
     352     11378599 :   if (!address)
     353              :     return false;
     354              : 
     355     11378599 :   return memory_address_addr_space_p (mode, address, as, ch);
     356              : }
     357              : 
     358              : /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR
     359              :    is valid on the current target and if so, creates and returns the
     360              :    TARGET_MEM_REF.  If VERIFY is false omit the verification step.  */
     361              : 
     362              : static tree
     363       904068 : create_mem_ref_raw (tree type, tree alias_ptr_type, struct mem_address *addr,
     364              :                     bool verify)
     365              : {
     366       904068 :   tree base, index2;
     367              : 
     368       904068 :   if (verify
     369       904068 :       && !valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), addr))
     370        38010 :     return NULL_TREE;
     371              : 
     372       866058 :   if (addr->offset)
     373       350906 :     addr->offset = fold_convert (alias_ptr_type, addr->offset);
     374              :   else
     375       515152 :     addr->offset = build_int_cst (alias_ptr_type, 0);
     376              : 
     377       866058 :   if (addr->symbol)
     378              :     {
     379       110270 :       base = addr->symbol;
     380       110270 :       index2 = addr->base;
     381              :     }
     382       755788 :   else if (addr->base
     383       755788 :            && POINTER_TYPE_P (TREE_TYPE (addr->base)))
     384              :     {
     385              :       base = addr->base;
     386              :       index2 = NULL_TREE;
     387              :     }
     388              :   else
     389              :     {
     390           14 :       base = build_int_cst (build_pointer_type (type), 0);
     391           14 :       index2 = addr->base;
     392              :     }
     393              : 
     394              :   /* If possible use a plain MEM_REF instead of a TARGET_MEM_REF.
     395              :      ???  As IVOPTs does not follow restrictions to where the base
     396              :      pointer may point to create a MEM_REF only if we know that
     397              :      base is valid.  */
     398       674248 :   if ((TREE_CODE (base) == ADDR_EXPR || TREE_CODE (base) == INTEGER_CST)
     399       191824 :       && (!index2 || integer_zerop (index2))
     400      1047336 :       && (!addr->index || integer_zerop (addr->index)))
     401          900 :     return fold_build2 (MEM_REF, type, base, addr->offset);
     402              : 
     403       865158 :   return build5 (TARGET_MEM_REF, type,
     404       865158 :                  base, addr->offset, addr->index, addr->step, index2);
     405              : }
     406              : 
     407              : /* Returns true if OBJ is an object whose address is a link time constant.  */
     408              : 
     409              : static bool
     410      1640644 : fixed_address_object_p (tree obj)
     411              : {
     412      1640644 :   return (VAR_P (obj)
     413      1603050 :           && (TREE_STATIC (obj) || DECL_EXTERNAL (obj))
     414      2264961 :           && ! DECL_DLLIMPORT_P (obj));
     415              : }
     416              : 
     417              : /* If ADDR contains an address of object that is a link time constant,
     418              :    move it to PARTS->symbol.  */
     419              : 
     420              : void
     421      4534574 : move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
     422              : {
     423      4534574 :   unsigned i;
     424      4534574 :   tree val = NULL_TREE;
     425              : 
     426      9674677 :   for (i = 0; i < addr->n; i++)
     427              :     {
     428      5764420 :       if (addr->elts[i].coef != 1)
     429      1213178 :         continue;
     430              : 
     431      4551242 :       val = addr->elts[i].val;
     432      4551242 :       if (TREE_CODE (val) == ADDR_EXPR
     433      4551242 :           && fixed_address_object_p (TREE_OPERAND (val, 0)))
     434              :         break;
     435              :     }
     436              : 
     437      4534574 :   if (i == addr->n)
     438              :     return;
     439              : 
     440       624317 :   parts->symbol = val;
     441       624317 :   aff_combination_remove_elt (addr, i);
     442              : }
     443              : 
     444              : /* Return true if ADDR contains an instance of BASE_HINT and it's moved to
     445              :    PARTS->base.  */
     446              : 
     447              : static bool
     448       464733 : move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
     449              :                    aff_tree *addr)
     450              : {
     451       464733 :   unsigned i;
     452       464733 :   tree val = NULL_TREE;
     453       464733 :   int qual;
     454              : 
     455       487810 :   for (i = 0; i < addr->n; i++)
     456              :     {
     457       487796 :       if (addr->elts[i].coef != 1)
     458        22512 :         continue;
     459              : 
     460       465284 :       val = addr->elts[i].val;
     461       465284 :       if (operand_equal_p (val, base_hint, 0))
     462              :         break;
     463              :     }
     464              : 
     465       464733 :   if (i == addr->n)
     466              :     return false;
     467              : 
     468              :   /* Cast value to appropriate pointer type.  We cannot use a pointer
     469              :      to TYPE directly, as the back-end will assume registers of pointer
     470              :      type are aligned, and just the base itself may not actually be.
     471              :      We use void pointer to the type's address space instead.  */
     472       464719 :   qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
     473       464719 :   type = build_qualified_type (void_type_node, qual);
     474       464719 :   parts->base = fold_convert (build_pointer_type (type), val);
     475       464719 :   aff_combination_remove_elt (addr, i);
     476       464719 :   return true;
     477              : }
     478              : 
     479              : /* If ADDR contains an address of a dereferenced pointer, move it to
     480              :    PARTS->base.  */
     481              : 
     482              : static void
     483       289508 : move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
     484              : {
     485       289508 :   unsigned i;
     486       289508 :   tree val = NULL_TREE;
     487              : 
     488       316822 :   for (i = 0; i < addr->n; i++)
     489              :     {
     490       316808 :       if (addr->elts[i].coef != 1)
     491        25878 :         continue;
     492              : 
     493       290930 :       val = addr->elts[i].val;
     494       290930 :       if (POINTER_TYPE_P (TREE_TYPE (val)))
     495              :         break;
     496              :     }
     497              : 
     498       289508 :   if (i == addr->n)
     499              :     return;
     500              : 
     501       289494 :   parts->base = val;
     502       289494 :   aff_combination_remove_elt (addr, i);
     503              : }
     504              : 
     505              : /* Moves the loop variant part V in linear address ADDR to be the index
     506              :    of PARTS.  */
     507              : 
     508              : static void
     509       399720 : move_variant_to_index (struct mem_address *parts, aff_tree *addr, tree v)
     510              : {
     511       399720 :   unsigned i;
     512       399720 :   tree val = NULL_TREE;
     513              : 
     514       399720 :   gcc_assert (!parts->index);
     515       737657 :   for (i = 0; i < addr->n; i++)
     516              :     {
     517       737334 :       val = addr->elts[i].val;
     518       737334 :       if (operand_equal_p (val, v, 0))
     519              :         break;
     520              :     }
     521              : 
     522       399720 :   if (i == addr->n)
     523              :     return;
     524              : 
     525       399397 :   parts->index = fold_convert (sizetype, val);
     526       399397 :   parts->step = wide_int_to_tree (sizetype, addr->elts[i].coef);
     527       399397 :   aff_combination_remove_elt (addr, i);
     528              : }
     529              : 
     530              : /* Adds ELT to PARTS.  */
     531              : 
     532              : static void
     533        60689 : add_to_parts (struct mem_address *parts, tree elt)
     534              : {
     535        60689 :   tree type;
     536              : 
     537        60689 :   if (!parts->index)
     538              :     {
     539         7360 :       parts->index = fold_convert (sizetype, elt);
     540         7360 :       return;
     541              :     }
     542              : 
     543        53329 :   if (!parts->base)
     544              :     {
     545        10581 :       parts->base = elt;
     546        10581 :       return;
     547              :     }
     548              : 
     549              :   /* Add ELT to base.  As we have arbitrarily associated address parts
     550              :      make sure to use unsigned arithmetic.  */
     551        42748 :   type = TREE_TYPE (parts->base);
     552        42748 :   if (POINTER_TYPE_P (type))
     553        37514 :     parts->base
     554        37514 :       = fold_convert (TREE_TYPE (parts->base),
     555              :                       fold_build2 (PLUS_EXPR, sizetype,
     556              :                                    fold_convert (sizetype, parts->base),
     557              :                                    fold_convert (sizetype, elt)));
     558              :   else
     559         5234 :     parts->base = fold_build2 (PLUS_EXPR, type, parts->base, elt);
     560              : }
     561              : 
     562              : /* Returns true if multiplying by RATIO is allowed in an address.  Test the
     563              :    validity for a memory reference accessing memory of mode MODE in address
     564              :    space AS.  */
     565              : 
     566              : static bool
     567        22965 : multiplier_allowed_in_address_p (HOST_WIDE_INT ratio, machine_mode mode,
     568              :                                  addr_space_t as)
     569              : {
     570              : #define MAX_RATIO 128
     571        22965 :   unsigned int data_index = (int) as * MAX_MACHINE_MODE + (int) mode;
     572        22965 :   static vec<sbitmap> valid_mult_list;
     573        22965 :   sbitmap valid_mult;
     574              : 
     575        22965 :   if (data_index >= valid_mult_list.length ())
     576         1075 :     valid_mult_list.safe_grow_cleared (data_index + 1, true);
     577              : 
     578        22965 :   valid_mult = valid_mult_list[data_index];
     579        22965 :   if (!valid_mult)
     580              :     {
     581         1190 :       machine_mode address_mode = targetm.addr_space.address_mode (as);
     582         1190 :       rtx reg1 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1);
     583         1190 :       rtx reg2 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 2);
     584         1190 :       rtx addr, scaled;
     585         1190 :       HOST_WIDE_INT i;
     586              : 
     587         1190 :       valid_mult = sbitmap_alloc (2 * MAX_RATIO + 1);
     588         1190 :       bitmap_clear (valid_mult);
     589         1190 :       scaled = gen_rtx_fmt_ee (MULT, address_mode, reg1, NULL_RTX);
     590         1190 :       addr = gen_rtx_fmt_ee (PLUS, address_mode, scaled, reg2);
     591       307020 :       for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
     592              :         {
     593       305830 :           XEXP (scaled, 1) = gen_int_mode (i, address_mode);
     594       305830 :           if (memory_address_addr_space_p (mode, addr, as)
     595       305830 :               || memory_address_addr_space_p (mode, scaled, as))
     596         4760 :             bitmap_set_bit (valid_mult, i + MAX_RATIO);
     597              :         }
     598              : 
     599         1190 :       if (dump_file && (dump_flags & TDF_DETAILS))
     600              :         {
     601            0 :           fprintf (dump_file, "  allowed multipliers:");
     602            0 :           for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
     603            0 :             if (bitmap_bit_p (valid_mult, i + MAX_RATIO))
     604            0 :               fprintf (dump_file, " %d", (int) i);
     605            0 :           fprintf (dump_file, "\n");
     606            0 :           fprintf (dump_file, "\n");
     607              :         }
     608              : 
     609         1190 :       valid_mult_list[data_index] = valid_mult;
     610              :     }
     611              : 
     612        22965 :   if (ratio > MAX_RATIO || ratio < -MAX_RATIO)
     613              :     return false;
     614              : 
     615        22235 :   return bitmap_bit_p (valid_mult, ratio + MAX_RATIO);
     616              : }
     617              : 
     618              : /* Finds the most expensive multiplication in ADDR that can be
     619              :    expressed in an addressing mode and move the corresponding
     620              :    element(s) to PARTS.  */
     621              : 
     622              : static void
     623       465056 : most_expensive_mult_to_index (tree type, struct mem_address *parts,
     624              :                               aff_tree *addr, bool speed)
     625              : {
     626       465056 :   addr_space_t as = TYPE_ADDR_SPACE (type);
     627       465056 :   machine_mode address_mode = targetm.addr_space.address_mode (as);
     628       465056 :   HOST_WIDE_INT coef;
     629       465056 :   unsigned best_mult_cost = 0, acost;
     630       465056 :   tree mult_elt = NULL_TREE, elt;
     631       465056 :   unsigned i, j;
     632       465056 :   enum tree_code op_code;
     633              : 
     634       465056 :   offset_int best_mult = 0;
     635       488888 :   for (i = 0; i < addr->n; i++)
     636              :     {
     637        23832 :       if (!wi::fits_shwi_p (addr->elts[i].coef))
     638            0 :         continue;
     639              : 
     640        23832 :       coef = addr->elts[i].coef.to_shwi ();
     641        38964 :       if (coef == 1
     642        23832 :           || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
     643        15132 :         continue;
     644              : 
     645         8700 :       acost = mult_by_coeff_cost (coef, address_mode, speed);
     646              : 
     647         8700 :       if (acost > best_mult_cost)
     648              :         {
     649         8542 :           best_mult_cost = acost;
     650         8542 :           best_mult = offset_int::from (addr->elts[i].coef, SIGNED);
     651              :         }
     652              :     }
     653              : 
     654       465056 :   if (!best_mult_cost)
     655       456514 :     return;
     656              : 
     657              :   /* Collect elements multiplied by best_mult.  */
     658        20988 :   for (i = j = 0; i < addr->n; i++)
     659              :     {
     660        12446 :       offset_int amult = offset_int::from (addr->elts[i].coef, SIGNED);
     661        12446 :       offset_int amult_neg = -wi::sext (amult, TYPE_PRECISION (addr->type));
     662              : 
     663        12446 :       if (amult == best_mult)
     664              :         op_code = PLUS_EXPR;
     665         3778 :       else if (amult_neg == best_mult)
     666              :         op_code = MINUS_EXPR;
     667              :       else
     668              :         {
     669          293 :           addr->elts[j] = addr->elts[i];
     670          293 :           j++;
     671          293 :           continue;
     672              :         }
     673              : 
     674        12153 :       elt = fold_convert (sizetype, addr->elts[i].val);
     675        12153 :       if (mult_elt)
     676         3611 :         mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
     677         8542 :       else if (op_code == PLUS_EXPR)
     678              :         mult_elt = elt;
     679              :       else
     680          790 :         mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
     681              :     }
     682         8542 :   addr->n = j;
     683              : 
     684         8542 :   parts->index = mult_elt;
     685         8542 :   parts->step = wide_int_to_tree (sizetype, best_mult);
     686              : }
     687              : 
     688              : /* Splits address ADDR for a memory access of type TYPE into PARTS.
     689              :    If BASE_HINT is non-NULL, it specifies an SSA name to be used
     690              :    preferentially as base of the reference, and IV_CAND is the selected
     691              :    iv candidate used in ADDR.  Store true to VAR_IN_BASE if variant
     692              :    part of address is split to PARTS.base.
     693              : 
     694              :    TODO -- be more clever about the distribution of the elements of ADDR
     695              :    to PARTS.  Some architectures do not support anything but single
     696              :    register in address, possibly with a small integer offset; while
     697              :    create_mem_ref will simplify the address to an acceptable shape
     698              :    later, it would be more efficient to know that asking for complicated
     699              :    addressing modes is useless.  */
     700              : 
     701              : static void
     702       864453 : addr_to_parts (tree type, aff_tree *addr, tree iv_cand, tree base_hint,
     703              :                struct mem_address *parts, bool *var_in_base, bool speed)
     704              : {
     705       864453 :   tree part;
     706       864453 :   unsigned i;
     707              : 
     708       864453 :   parts->symbol = NULL_TREE;
     709       864453 :   parts->base = NULL_TREE;
     710       864453 :   parts->index = NULL_TREE;
     711       864453 :   parts->step = NULL_TREE;
     712              : 
     713       864453 :   if (maybe_ne (addr->offset, 0))
     714       349312 :     parts->offset = wide_int_to_tree (sizetype, addr->offset);
     715              :   else
     716       515141 :     parts->offset = NULL_TREE;
     717              : 
     718              :   /* Try to find a symbol.  */
     719       864453 :   move_fixed_address_to_symbol (parts, addr);
     720              : 
     721              :   /* Since at the moment there is no reliable way to know how to
     722              :      distinguish between pointer and its offset, we decide if var
     723              :      part is the pointer based on guess.  */
     724       864453 :   *var_in_base = (base_hint != NULL && parts->symbol == NULL);
     725       864453 :   if (*var_in_base)
     726       464733 :     *var_in_base = move_hint_to_base (type, parts, base_hint, addr);
     727              :   else
     728       399720 :     move_variant_to_index (parts, addr, iv_cand);
     729              : 
     730              :   /* First move the most expensive feasible multiplication to index.  */
     731       864453 :   if (!parts->index)
     732       465056 :     most_expensive_mult_to_index (type, parts, addr, speed);
     733              : 
     734              :   /* Move pointer into base.  */
     735       864453 :   if (!parts->symbol && !parts->base)
     736       289508 :     move_pointer_to_base (parts, addr);
     737              : 
     738              :   /* Then try to process the remaining elements.  */
     739       925142 :   for (i = 0; i < addr->n; i++)
     740              :     {
     741        60689 :       part = fold_convert (sizetype, addr->elts[i].val);
     742        60689 :       if (addr->elts[i].coef != 1)
     743        57843 :         part = fold_build2 (MULT_EXPR, sizetype, part,
     744              :                             wide_int_to_tree (sizetype, addr->elts[i].coef));
     745        60689 :       add_to_parts (parts, part);
     746              :     }
     747       864453 :   if (addr->rest)
     748            0 :     add_to_parts (parts, fold_convert (sizetype, addr->rest));
     749       864453 : }
     750              : 
     751              : /* Force the PARTS to register.  */
     752              : 
     753              : static void
     754       864453 : gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
     755              : {
     756       864453 :   if (parts->base)
     757       764794 :     parts->base = force_gimple_operand_gsi_1 (gsi, parts->base,
     758              :                                             is_gimple_mem_ref_addr, NULL_TREE,
     759              :                                             true, GSI_SAME_STMT);
     760       864453 :   if (parts->index)
     761       415299 :     parts->index = force_gimple_operand_gsi (gsi, parts->index,
     762              :                                              true, NULL_TREE,
     763              :                                              true, GSI_SAME_STMT);
     764       864453 : }
     765              : 
     766              : /* Return true if the OFFSET in PARTS is the only thing that is making
     767              :    it an invalid address for type TYPE.  */
     768              : 
     769              : static bool
     770        24012 : mem_ref_valid_without_offset_p (tree type, mem_address parts)
     771              : {
     772        24012 :   if (!parts.base)
     773            0 :     parts.base = parts.offset;
     774        24012 :   parts.offset = NULL_TREE;
     775        24012 :   return valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), &parts);
     776              : }
     777              : 
     778              : /* Fold PARTS->offset into PARTS->base, so that there is no longer
     779              :    a separate offset.  Emit any new instructions before GSI.  */
     780              : 
     781              : static void
     782            0 : add_offset_to_base (gimple_stmt_iterator *gsi, mem_address *parts)
     783              : {
     784            0 :   tree tmp = parts->offset;
     785            0 :   if (parts->base)
     786              :     {
     787            0 :       tmp = fold_build_pointer_plus (parts->base, tmp);
     788            0 :       tmp = force_gimple_operand_gsi_1 (gsi, tmp, is_gimple_mem_ref_addr,
     789              :                                         NULL_TREE, true, GSI_SAME_STMT);
     790              :     }
     791            0 :   parts->base = tmp;
     792            0 :   parts->offset = NULL_TREE;
     793            0 : }
     794              : 
     795              : /* Creates and returns a TARGET_MEM_REF for address ADDR.  If necessary
     796              :    computations are emitted in front of GSI.  TYPE is the mode
     797              :    of created memory reference. IV_CAND is the selected iv candidate in ADDR,
     798              :    and BASE_HINT is non NULL if IV_CAND comes from a base address
     799              :    object.  */
     800              : 
     801              : tree
     802       864453 : create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
     803              :                 tree alias_ptr_type, tree iv_cand, tree base_hint, bool speed)
     804              : {
     805       864453 :   bool var_in_base;
     806       864453 :   tree mem_ref, tmp;
     807       864453 :   struct mem_address parts;
     808              : 
     809       864453 :   addr_to_parts (type, addr, iv_cand, base_hint, &parts, &var_in_base, speed);
     810       864453 :   gimplify_mem_ref_parts (gsi, &parts);
     811       864453 :   mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
     812       864453 :   if (mem_ref)
     813              :     return mem_ref;
     814              : 
     815              :   /* The expression is too complicated.  Try making it simpler.  */
     816              : 
     817              :   /* Merge symbol into other parts.  */
     818        37420 :   if (parts.symbol)
     819              :     {
     820          909 :       tmp = parts.symbol;
     821          909 :       parts.symbol = NULL_TREE;
     822          909 :       gcc_assert (is_gimple_val (tmp));
     823              : 
     824          909 :       if (parts.base)
     825              :         {
     826           35 :           gcc_assert (useless_type_conversion_p (sizetype,
     827              :                                                  TREE_TYPE (parts.base)));
     828              : 
     829           35 :           if (parts.index)
     830              :             {
     831              :               /* Add the symbol to base, eventually forcing it to register.  */
     832           35 :               tmp = fold_build_pointer_plus (tmp, parts.base);
     833           35 :               tmp = force_gimple_operand_gsi_1 (gsi, tmp,
     834              :                                                 is_gimple_mem_ref_addr,
     835              :                                                 NULL_TREE, true,
     836              :                                                 GSI_SAME_STMT);
     837              :             }
     838              :           else
     839              :             {
     840              :               /* Move base to index, then move the symbol to base.  */
     841            0 :               parts.index = parts.base;
     842              :             }
     843           35 :           parts.base = tmp;
     844              :         }
     845              :       else
     846          874 :         parts.base = tmp;
     847              : 
     848          909 :       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
     849          909 :       if (mem_ref)
     850              :         return mem_ref;
     851              :     }
     852              : 
     853              :   /* Move multiplication to index by transforming address expression:
     854              :        [... + index << step + ...]
     855              :      into:
     856              :        index' = index << step;
     857              :        [... + index' + ,,,].  */
     858        37101 :   if (parts.step && !integer_onep (parts.step))
     859              :     {
     860        37090 :       gcc_assert (parts.index);
     861        37090 :       if (parts.offset && mem_ref_valid_without_offset_p (type, parts))
     862              :         {
     863            0 :           add_offset_to_base (gsi, &parts);
     864            0 :           mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
     865            0 :           gcc_assert (mem_ref);
     866              :           return mem_ref;
     867              :         }
     868              : 
     869        37090 :       parts.index = force_gimple_operand_gsi (gsi,
     870              :                                 fold_build2 (MULT_EXPR, sizetype,
     871              :                                              parts.index, parts.step),
     872              :                                 true, NULL_TREE, true, GSI_SAME_STMT);
     873        37090 :       parts.step = NULL_TREE;
     874              : 
     875        37090 :       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
     876        37090 :       if (mem_ref)
     877              :         return mem_ref;
     878              :     }
     879              : 
     880              :   /* Add offset to invariant part by transforming address expression:
     881              :        [base + index + offset]
     882              :      into:
     883              :        base' = base + offset;
     884              :        [base' + index]
     885              :      or:
     886              :        index' = index + offset;
     887              :        [base + index']
     888              :      depending on which one is invariant.  */
     889           11 :   if (parts.offset && !integer_zerop (parts.offset))
     890              :     {
     891           11 :       tree old_base = unshare_expr (parts.base);
     892           11 :       tree old_index = unshare_expr (parts.index);
     893           11 :       tree old_offset = unshare_expr (parts.offset);
     894              : 
     895           11 :       tmp = parts.offset;
     896           11 :       parts.offset = NULL_TREE;
     897              :       /* Add offset to invariant part.  */
     898           11 :       if (!var_in_base)
     899              :         {
     900            5 :           if (parts.base)
     901              :             {
     902            5 :               tmp = fold_build_pointer_plus (parts.base, tmp);
     903            5 :               tmp = force_gimple_operand_gsi_1 (gsi, tmp,
     904              :                                                 is_gimple_mem_ref_addr,
     905              :                                                 NULL_TREE, true,
     906              :                                                 GSI_SAME_STMT);
     907              :             }
     908            5 :           parts.base = tmp;
     909              :         }
     910              :       else
     911              :         {
     912            6 :           if (parts.index)
     913              :             {
     914            0 :               tmp = fold_build_pointer_plus (parts.index, tmp);
     915            0 :               tmp = force_gimple_operand_gsi_1 (gsi, tmp,
     916              :                                                 is_gimple_mem_ref_addr,
     917              :                                                 NULL_TREE, true,
     918              :                                                 GSI_SAME_STMT);
     919              :             }
     920            6 :           parts.index = tmp;
     921              :         }
     922              : 
     923           11 :       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
     924           11 :       if (mem_ref)
     925              :         return mem_ref;
     926              : 
     927              :       /* Restore parts.base, index and offset so that we can check if
     928              :          [base + offset] addressing mode is supported in next step.
     929              :          This is necessary for targets only support [base + offset],
     930              :          but not [base + index] addressing mode.  */
     931            0 :       parts.base = old_base;
     932            0 :       parts.index = old_index;
     933            0 :       parts.offset = old_offset;
     934              :     }
     935              : 
     936              :   /* Transform [base + index + ...] into:
     937              :        base' = base + index;
     938              :        [base' + ...].  */
     939            0 :   if (parts.index)
     940              :     {
     941            0 :       tmp = parts.index;
     942            0 :       parts.index = NULL_TREE;
     943              :       /* Add index to base.  */
     944            0 :       if (parts.base)
     945              :         {
     946            0 :           tmp = fold_build_pointer_plus (parts.base, tmp);
     947            0 :           tmp = force_gimple_operand_gsi_1 (gsi, tmp,
     948              :                                             is_gimple_mem_ref_addr,
     949              :                                             NULL_TREE, true, GSI_SAME_STMT);
     950              :         }
     951            0 :       parts.base = tmp;
     952              : 
     953            0 :       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
     954            0 :       if (mem_ref)
     955              :         return mem_ref;
     956              :     }
     957              : 
     958              :   /* Transform [base + offset] into:
     959              :        base' = base + offset;
     960              :        [base'].  */
     961            0 :   if (parts.offset && !integer_zerop (parts.offset))
     962              :     {
     963            0 :       add_offset_to_base (gsi, &parts);
     964            0 :       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
     965            0 :       if (mem_ref)
     966              :         return mem_ref;
     967              :     }
     968              : 
     969              :   /* Verify that the address is in the simplest possible shape
     970              :      (only a register).  If we cannot create such a memory reference,
     971              :      something is really wrong.  */
     972            0 :   gcc_assert (parts.symbol == NULL_TREE);
     973            0 :   gcc_assert (parts.index == NULL_TREE);
     974            0 :   gcc_assert (!parts.step || integer_onep (parts.step));
     975            0 :   gcc_assert (!parts.offset || integer_zerop (parts.offset));
     976            0 :   gcc_unreachable ();
     977              : }
     978              : 
     979              : /* Copies components of the address from OP to ADDR.  */
     980              : 
     981              : void
     982      2834737 : get_address_description (tree op, struct mem_address *addr)
     983              : {
     984      2834737 :   if (TREE_CODE (TMR_BASE (op)) == ADDR_EXPR)
     985              :     {
     986       601801 :       addr->symbol = TMR_BASE (op);
     987       601801 :       addr->base = TMR_INDEX2 (op);
     988              :     }
     989              :   else
     990              :     {
     991      2232936 :       addr->symbol = NULL_TREE;
     992      2232936 :       if (TMR_INDEX2 (op))
     993              :         {
     994           58 :           gcc_assert (integer_zerop (TMR_BASE (op)));
     995           58 :           addr->base = TMR_INDEX2 (op);
     996              :         }
     997              :       else
     998      2232878 :         addr->base = TMR_BASE (op);
     999              :     }
    1000      2834737 :   addr->index = TMR_INDEX (op);
    1001      2834737 :   addr->step = TMR_STEP (op);
    1002      2834737 :   addr->offset = TMR_OFFSET (op);
    1003      2834737 : }
    1004              : 
    1005              : /* Copies the reference information from OLD_REF to NEW_REF, where
    1006              :    NEW_REF should be either a MEM_REF or a TARGET_MEM_REF.  */
    1007              : 
    1008              : void
    1009       909232 : copy_ref_info (tree new_ref, tree old_ref)
    1010              : {
    1011       909232 :   tree new_ptr_base = NULL_TREE;
    1012              : 
    1013       909232 :   gcc_assert (TREE_CODE (new_ref) == MEM_REF
    1014              :               || TREE_CODE (new_ref) == TARGET_MEM_REF);
    1015              : 
    1016       909232 :   TREE_SIDE_EFFECTS (new_ref) = TREE_SIDE_EFFECTS (old_ref);
    1017       909232 :   TREE_THIS_VOLATILE (new_ref) = TREE_THIS_VOLATILE (old_ref);
    1018              : 
    1019       909232 :   new_ptr_base = TREE_OPERAND (new_ref, 0);
    1020              : 
    1021       909232 :   tree base = get_base_address (old_ref);
    1022       909232 :   if (!base)
    1023              :     return;
    1024              : 
    1025              :   /* We can transfer points-to information from an old pointer
    1026              :      or decl base to the new one.  */
    1027       909232 :   if (new_ptr_base
    1028       909232 :       && TREE_CODE (new_ptr_base) == SSA_NAME
    1029      1609654 :       && !SSA_NAME_PTR_INFO (new_ptr_base))
    1030              :     {
    1031       396679 :       if ((TREE_CODE (base) == MEM_REF
    1032       396679 :            || TREE_CODE (base) == TARGET_MEM_REF)
    1033       324303 :           && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
    1034       720982 :           && SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)))
    1035              :         {
    1036       304732 :           duplicate_ssa_name_ptr_info
    1037       304732 :             (new_ptr_base, SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)));
    1038       304732 :           reset_flow_sensitive_info (new_ptr_base);
    1039              :         }
    1040        91947 :       else if (VAR_P (base)
    1041              :                || TREE_CODE (base) == PARM_DECL
    1042              :                || TREE_CODE (base) == RESULT_DECL)
    1043              :         {
    1044        72376 :           struct ptr_info_def *pi = get_ptr_info (new_ptr_base);
    1045        72376 :           pt_solution_set_var (&pi->pt, base);
    1046              :         }
    1047              :     }
    1048              : 
    1049              :   /* We can transfer dependence info.  */
    1050       909232 :   if (!MR_DEPENDENCE_CLIQUE (new_ref)
    1051       909232 :       && (TREE_CODE (base) == MEM_REF
    1052       909232 :           || TREE_CODE (base) == TARGET_MEM_REF)
    1053      1624348 :       && MR_DEPENDENCE_CLIQUE (base))
    1054              :     {
    1055       182015 :       MR_DEPENDENCE_CLIQUE (new_ref) = MR_DEPENDENCE_CLIQUE (base);
    1056       182015 :       MR_DEPENDENCE_BASE (new_ref) = MR_DEPENDENCE_BASE (base);
    1057              :     }
    1058              : 
    1059              :   /* And alignment info.  Note we cannot transfer misalignment info
    1060              :      since that sits on the SSA name but this is flow-sensitive info
    1061              :      which we cannot transfer in this generic routine.  */
    1062       909232 :   unsigned old_align = get_object_alignment (old_ref);
    1063       909232 :   unsigned new_align = get_object_alignment (new_ref);
    1064       909232 :   if (new_align < old_align)
    1065          719 :     TREE_TYPE (new_ref) = build_aligned_type (TREE_TYPE (new_ref), old_align);
    1066              : }
    1067              : 
    1068              : /* Move constants in target_mem_ref REF to offset.  Returns the new target
    1069              :    mem ref if anything changes, NULL_TREE otherwise.  */
    1070              : 
    1071              : tree
    1072      1978000 : maybe_fold_tmr (tree ref)
    1073              : {
    1074      1978000 :   struct mem_address addr;
    1075      1978000 :   bool changed = false;
    1076      1978000 :   tree new_ref, off;
    1077              : 
    1078      1978000 :   get_address_description (ref, &addr);
    1079              : 
    1080      1978000 :   if (addr.base
    1081      1597636 :       && TREE_CODE (addr.base) == INTEGER_CST
    1082      1978053 :       && !integer_zerop (addr.base))
    1083              :     {
    1084           53 :       addr.offset = fold_binary_to_constant (PLUS_EXPR,
    1085           53 :                                              TREE_TYPE (addr.offset),
    1086              :                                              addr.offset, addr.base);
    1087           53 :       addr.base = NULL_TREE;
    1088           53 :       changed = true;
    1089              :     }
    1090              : 
    1091      1978000 :   if (addr.symbol
    1092      1978000 :       && TREE_CODE (TREE_OPERAND (addr.symbol, 0)) == MEM_REF)
    1093              :     {
    1094            0 :       addr.offset = fold_binary_to_constant
    1095            0 :                         (PLUS_EXPR, TREE_TYPE (addr.offset),
    1096              :                          addr.offset,
    1097            0 :                          TREE_OPERAND (TREE_OPERAND (addr.symbol, 0), 1));
    1098            0 :       addr.symbol = TREE_OPERAND (TREE_OPERAND (addr.symbol, 0), 0);
    1099            0 :       changed = true;
    1100              :     }
    1101      1978000 :   else if (addr.symbol
    1102      1978000 :            && handled_component_p (TREE_OPERAND (addr.symbol, 0)))
    1103              :     {
    1104            0 :       poly_int64 offset;
    1105            0 :       addr.symbol = build_fold_addr_expr
    1106              :                       (get_addr_base_and_unit_offset
    1107              :                          (TREE_OPERAND (addr.symbol, 0), &offset));
    1108            0 :       addr.offset = int_const_binop (PLUS_EXPR,
    1109            0 :                                      addr.offset, size_int (offset));
    1110            0 :       changed = true;
    1111              :     }
    1112              : 
    1113      1978000 :   if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
    1114              :     {
    1115         1552 :       off = addr.index;
    1116         1552 :       if (addr.step)
    1117              :         {
    1118         1480 :           off = fold_binary_to_constant (MULT_EXPR, sizetype,
    1119              :                                          off, addr.step);
    1120         1480 :           addr.step = NULL_TREE;
    1121              :         }
    1122              : 
    1123         1552 :       addr.offset = fold_binary_to_constant (PLUS_EXPR,
    1124         1552 :                                              TREE_TYPE (addr.offset),
    1125              :                                              addr.offset, off);
    1126         1552 :       addr.index = NULL_TREE;
    1127         1552 :       changed = true;
    1128              :     }
    1129              : 
    1130      1978000 :   if (!changed)
    1131              :     return NULL_TREE;
    1132              : 
    1133              :   /* If we have propagated something into this TARGET_MEM_REF and thus
    1134              :      ended up folding it, always create a new TARGET_MEM_REF regardless
    1135              :      if it is valid in this for on the target - the propagation result
    1136              :      wouldn't be anyway.  */
    1137         1605 :   new_ref = create_mem_ref_raw (TREE_TYPE (ref),
    1138         1605 :                                 TREE_TYPE (addr.offset), &addr, false);
    1139         1605 :   TREE_SIDE_EFFECTS (new_ref) = TREE_SIDE_EFFECTS (ref);
    1140         1605 :   TREE_THIS_VOLATILE (new_ref) = TREE_THIS_VOLATILE (ref);
    1141         1605 :   return new_ref;
    1142              : }
    1143              : 
    1144              : /* Return the preferred index scale factor for accessing memory of mode
    1145              :    MEM_MODE in the address space of pointer BASE.  Assume that we're
    1146              :    optimizing for speed if SPEED is true and for size otherwise.  */
    1147              : unsigned int
    1148       532010 : preferred_mem_scale_factor (tree base, machine_mode mem_mode,
    1149              :                             bool speed)
    1150              : {
    1151              :   /* For BLKmode, we can't do anything so return 1.  */
    1152       532010 :   if (mem_mode == BLKmode)
    1153              :     return 1;
    1154              : 
    1155       523919 :   struct mem_address parts = {};
    1156       523919 :   addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (base));
    1157       523919 :   unsigned int fact = GET_MODE_UNIT_SIZE (mem_mode);
    1158              : 
    1159              :   /* Addressing mode "base + index".  */
    1160       523919 :   parts.index = integer_one_node;
    1161       523919 :   parts.base = integer_one_node;
    1162       523919 :   rtx addr = addr_for_mem_ref (&parts, as, false);
    1163       523919 :   unsigned cost = address_cost (addr, mem_mode, as, speed);
    1164              : 
    1165              :   /* Addressing mode "base + index << scale".  */
    1166       523919 :   parts.step = wide_int_to_tree (sizetype, fact);
    1167       523919 :   addr = addr_for_mem_ref (&parts, as, false);
    1168       523919 :   unsigned new_cost = address_cost (addr, mem_mode, as, speed);
    1169              : 
    1170              :   /* Compare the cost of an address with an unscaled index with
    1171              :      a scaled index and return factor if useful. */
    1172       523919 :   if (new_cost < cost)
    1173            0 :     return GET_MODE_UNIT_SIZE (mem_mode);
    1174              :   return 1;
    1175              : }
    1176              : 
    1177              : /* Dump PARTS to FILE.  */
    1178              : 
    1179              : extern void dump_mem_address (FILE *, struct mem_address *);
    1180              : void
    1181            0 : dump_mem_address (FILE *file, struct mem_address *parts)
    1182              : {
    1183            0 :   if (parts->symbol)
    1184              :     {
    1185            0 :       fprintf (file, "symbol: ");
    1186            0 :       print_generic_expr (file, TREE_OPERAND (parts->symbol, 0), TDF_SLIM);
    1187            0 :       fprintf (file, "\n");
    1188              :     }
    1189            0 :   if (parts->base)
    1190              :     {
    1191            0 :       fprintf (file, "base: ");
    1192            0 :       print_generic_expr (file, parts->base, TDF_SLIM);
    1193            0 :       fprintf (file, "\n");
    1194              :     }
    1195            0 :   if (parts->index)
    1196              :     {
    1197            0 :       fprintf (file, "index: ");
    1198            0 :       print_generic_expr (file, parts->index, TDF_SLIM);
    1199            0 :       fprintf (file, "\n");
    1200              :     }
    1201            0 :   if (parts->step)
    1202              :     {
    1203            0 :       fprintf (file, "step: ");
    1204            0 :       print_generic_expr (file, parts->step, TDF_SLIM);
    1205            0 :       fprintf (file, "\n");
    1206              :     }
    1207            0 :   if (parts->offset)
    1208              :     {
    1209            0 :       fprintf (file, "offset: ");
    1210            0 :       print_generic_expr (file, parts->offset, TDF_SLIM);
    1211            0 :       fprintf (file, "\n");
    1212              :     }
    1213            0 : }
    1214              : 
    1215              : #include "gt-tree-ssa-address.h"
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.