LCOV - code coverage report
Current view: top level - gcc - combine-stack-adj.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 96.5 % 340 328
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 18 18
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Combine stack adjustments.
       2              :    Copyright (C) 1987-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 under
       7              : the terms of the GNU General Public License as published by the Free
       8              : Software Foundation; either version 3, or (at your option) any later
       9              : version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12              : 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              : /* Track stack adjustments and stack memory references.  Attempt to
      21              :    reduce the number of stack adjustments by back-propagating across
      22              :    the memory references.
      23              : 
      24              :    This is intended primarily for use with targets that do not define
      25              :    ACCUMULATE_OUTGOING_ARGS.  It is of significantly more value to
      26              :    targets that define PREFERRED_STACK_BOUNDARY more aligned than
      27              :    STACK_BOUNDARY (e.g. x86), or if not all registers can be pushed
      28              :    (e.g. x86 fp regs) which would ordinarily have to be implemented
      29              :    as a sub/mov pair due to restrictions in calls.cc.
      30              : 
      31              :    Propagation stops when any of the insns that need adjusting are
      32              :    (a) no longer valid because we've exceeded their range, (b) a
      33              :    non-trivial push instruction, or (c) a call instruction.
      34              : 
      35              :    Restriction B is based on the assumption that push instructions
      36              :    are smaller or faster.  If a port really wants to remove all
      37              :    pushes, it should have defined ACCUMULATE_OUTGOING_ARGS.  The
      38              :    one exception that is made is for an add immediately followed
      39              :    by a push.  */
      40              : 
      41              : #include "config.h"
      42              : #include "system.h"
      43              : #include "coretypes.h"
      44              : #include "backend.h"
      45              : #include "rtl.h"
      46              : #include "df.h"
      47              : #include "insn-config.h"
      48              : #include "memmodel.h"
      49              : #include "emit-rtl.h"
      50              : #include "recog.h"
      51              : #include "cfgrtl.h"
      52              : #include "tree-pass.h"
      53              : #include "rtl-iter.h"
      54              : 
      55              : 
      56              : /* This structure records two kinds of stack references between stack
      57              :    adjusting instructions: stack references in memory addresses for
      58              :    regular insns and all stack references for debug insns.  */
      59              : 
      60              : struct csa_reflist
      61              : {
      62              :   HOST_WIDE_INT sp_offset;
      63              :   rtx_insn *insn;
      64              :   rtx *ref;
      65              :   struct csa_reflist *next;
      66              : };
      67              : 
      68              : static bool stack_memref_p (rtx);
      69              : static rtx single_set_for_csa (rtx_insn *);
      70              : static void free_csa_reflist (struct csa_reflist *);
      71              : static struct csa_reflist *record_one_stack_ref (rtx_insn *, rtx *,
      72              :                                                  struct csa_reflist *);
      73              : static bool try_apply_stack_adjustment (rtx_insn *, struct csa_reflist *,
      74              :                                         HOST_WIDE_INT, HOST_WIDE_INT,
      75              :                                         bitmap, rtx_insn *);
      76              : static void combine_stack_adjustments_for_block (basic_block, bitmap);
      77              : 
      78              : 
      79              : /* Main entry point for stack adjustment combination.  */
      80              : 
      81              : static void
      82      1043685 : combine_stack_adjustments (void)
      83              : {
      84      1043685 :   basic_block bb;
      85      1043685 :   bitmap live = BITMAP_ALLOC (&reg_obstack);
      86              : 
      87     12626657 :   FOR_EACH_BB_FN (bb, cfun)
      88     11582972 :     combine_stack_adjustments_for_block (bb, live);
      89              : 
      90      1043685 :   BITMAP_FREE (live);
      91      1043685 : }
      92              : 
      93              : /* Recognize a MEM of the form (sp) or (plus sp const).  */
      94              : 
      95              : static bool
      96      2438594 : stack_memref_p (rtx x)
      97              : {
      98      2438594 :   if (!MEM_P (x))
      99              :     return false;
     100      2438594 :   x = XEXP (x, 0);
     101              : 
     102      2438594 :   if (x == stack_pointer_rtx)
     103              :     return true;
     104      2151953 :   if (GET_CODE (x) == PLUS
     105      1365720 :       && XEXP (x, 0) == stack_pointer_rtx
     106      1365345 :       && CONST_INT_P (XEXP (x, 1)))
     107      1365333 :     return true;
     108              : 
     109              :   return false;
     110              : }
     111              : 
     112              : /* Recognize either normal single_set or the hack in i386.md for
     113              :    tying fp and sp adjustments.  */
     114              : 
     115              : static rtx
     116    114172675 : single_set_for_csa (rtx_insn *insn)
     117              : {
     118    114172675 :   int i;
     119    114172675 :   rtx tmp = single_set (insn);
     120    114172675 :   if (tmp)
     121              :     return tmp;
     122              : 
     123     54441451 :   if (!NONJUMP_INSN_P (insn)
     124     54441451 :       || GET_CODE (PATTERN (insn)) != PARALLEL)
     125              :     return NULL_RTX;
     126              : 
     127       352065 :   tmp = PATTERN (insn);
     128       352065 :   if (GET_CODE (XVECEXP (tmp, 0, 0)) != SET)
     129              :     return NULL_RTX;
     130              : 
     131       279819 :   for (i = 1; i < XVECLEN (tmp, 0); ++i)
     132              :     {
     133       279819 :       rtx this_rtx = XVECEXP (tmp, 0, i);
     134              : 
     135              :       /* The special case is allowing a no-op set.  */
     136       279819 :       if (GET_CODE (this_rtx) == SET
     137       273872 :           && SET_SRC (this_rtx) == SET_DEST (this_rtx))
     138              :         ;
     139       279819 :       else if (GET_CODE (this_rtx) != CLOBBER
     140       279819 :                && GET_CODE (this_rtx) != USE)
     141              :         return NULL_RTX;
     142              :     }
     143              : 
     144              :   return XVECEXP (tmp, 0, 0);
     145              : }
     146              : 
     147              : /* Free the list of csa_reflist nodes.  */
     148              : 
     149              : static void
     150      1542287 : free_csa_reflist (struct csa_reflist *reflist)
     151              : {
     152      1542287 :   struct csa_reflist *next;
     153      3418317 :   for (; reflist ; reflist = next)
     154              :     {
     155      1714697 :       next = reflist->next;
     156      1714697 :       free (reflist);
     157              :     }
     158            0 : }
     159              : 
     160              : /* Create a new csa_reflist node from the given stack reference.
     161              :    It is already known that the reference is either a MEM satisfying the
     162              :    predicate stack_memref_p or a REG representing the stack pointer.  */
     163              : 
     164              : static struct csa_reflist *
     165      1714697 : record_one_stack_ref (rtx_insn *insn, rtx *ref, struct csa_reflist *next_reflist)
     166              : {
     167      1714697 :   struct csa_reflist *ml;
     168              : 
     169      1714697 :   ml = XNEW (struct csa_reflist);
     170              : 
     171      1714697 :   if (REG_P (*ref) || XEXP (*ref, 0) == stack_pointer_rtx)
     172       349364 :     ml->sp_offset = 0;
     173              :   else
     174      1365333 :     ml->sp_offset = INTVAL (XEXP (XEXP (*ref, 0), 1));
     175              : 
     176      1714697 :   ml->insn = insn;
     177      1714697 :   ml->ref = ref;
     178      1714697 :   ml->next = next_reflist;
     179              : 
     180      1714697 :   return ml;
     181              : }
     182              : 
     183              : /* We only know how to adjust the CFA; no other frame-related changes
     184              :    may appear in any insn to be deleted.  */
     185              : 
     186              : static bool
     187       420701 : no_unhandled_cfa (rtx_insn *insn)
     188              : {
     189       420701 :   if (!RTX_FRAME_RELATED_P (insn))
     190              :     return true;
     191              : 
     192              :   /* No CFA notes at all is a legacy interpretation like
     193              :      FRAME_RELATED_EXPR, and is context sensitive within
     194              :      the prologue state machine.  We can't handle that here.  */
     195            1 :   bool has_cfa_adjust = false;
     196              : 
     197            3 :   for (rtx link = REG_NOTES (insn); link; link = XEXP (link, 1))
     198            2 :     switch (REG_NOTE_KIND (link))
     199              :       {
     200              :       default:
     201              :         break;
     202            1 :       case REG_CFA_ADJUST_CFA:
     203            1 :         has_cfa_adjust = true;
     204            1 :         break;
     205              : 
     206              :       case REG_FRAME_RELATED_EXPR:
     207              :       case REG_CFA_DEF_CFA:
     208              :       case REG_CFA_OFFSET:
     209              :       case REG_CFA_REGISTER:
     210              :       case REG_CFA_EXPRESSION:
     211              :       case REG_CFA_RESTORE:
     212              :       case REG_CFA_SET_VDRAP:
     213              :       case REG_CFA_WINDOW_SAVE:
     214              :       case REG_CFA_FLUSH_QUEUE:
     215              :       case REG_CFA_NEGATE_RA_STATE:
     216              :         return false;
     217              :       }
     218              : 
     219              :   return has_cfa_adjust;
     220              : }
     221              : 
     222              : /* Attempt to apply ADJUST to the stack adjusting insn INSN, as well
     223              :    as each of the memories and stack references in REFLIST.  Return true
     224              :    on success.  */
     225              : 
     226              : static bool
     227       477455 : try_apply_stack_adjustment (rtx_insn *insn, struct csa_reflist *reflist,
     228              :                             HOST_WIDE_INT new_adjust, HOST_WIDE_INT delta,
     229              :                             bitmap live, rtx_insn *other_insn)
     230              : {
     231       477455 :   struct csa_reflist *ml;
     232       477455 :   rtx set;
     233       477455 :   bool remove_equal = false;
     234              : 
     235       477455 :   set = single_set_for_csa (insn);
     236       477455 :   if (MEM_P (SET_DEST (set)))
     237        56759 :     validate_change (insn, &SET_DEST (set),
     238              :                      replace_equiv_address (SET_DEST (set), stack_pointer_rtx),
     239              :                      1);
     240       420696 :   else if (REG_P (SET_SRC (set)))
     241              :     {
     242          382 :       if (other_insn == NULL_RTX || live == NULL)
     243              :         return false;
     244          382 :       rtx other_set = single_set_for_csa (other_insn);
     245          382 :       if (SET_DEST (other_set) != stack_pointer_rtx
     246          382 :           || GET_CODE (SET_SRC (other_set)) != PLUS
     247          382 :           || XEXP (SET_SRC (other_set), 0) != stack_pointer_rtx
     248          382 :           || !CONST_INT_P (XEXP (SET_SRC (other_set), 1)))
     249              :         return false;
     250          382 :       if (PATTERN (other_insn) != other_set)
     251              :         {
     252          382 :           if (GET_CODE (PATTERN (other_insn)) != PARALLEL)
     253              :             return false;
     254              :           int i;
     255              :           rtx p = PATTERN (other_insn);
     256         1146 :           for (i = 0; i < XVECLEN (p, 0); ++i)
     257              :             {
     258          764 :               rtx this_rtx = XVECEXP (p, 0, i);
     259          764 :               if (this_rtx == other_set)
     260          382 :                 continue;
     261          382 :               if (GET_CODE (this_rtx) != CLOBBER)
     262              :                 return false;
     263          382 :               if (!REG_P (XEXP (this_rtx, 0))
     264          382 :                   || !HARD_REGISTER_P (XEXP (this_rtx, 0)))
     265              :                 return false;
     266          382 :               unsigned int end_regno = END_REGNO (XEXP (this_rtx, 0));
     267          764 :               for (unsigned int regno = REGNO (XEXP (this_rtx, 0));
     268          764 :                    regno < end_regno; ++regno)
     269          382 :                 if (bitmap_bit_p (live, regno))
     270              :                   return false;
     271              :             }
     272              :         }
     273          382 :       validate_change (insn, &PATTERN (insn), copy_rtx (PATTERN (other_insn)),
     274              :                        1);
     275          382 :       set = single_set_for_csa (insn);
     276          382 :       validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust),
     277              :                        1);
     278          382 :       remove_equal = true;
     279              :     }
     280              :   else
     281       420314 :     validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);
     282              : 
     283       921588 :   for (ml = reflist; ml ; ml = ml->next)
     284              :     {
     285       444133 :       rtx new_addr = plus_constant (Pmode, stack_pointer_rtx,
     286       444133 :                                     ml->sp_offset - delta);
     287       444133 :       rtx new_val;
     288              : 
     289       444133 :       if (MEM_P (*ml->ref))
     290       442220 :         new_val = replace_equiv_address_nv (*ml->ref, new_addr);
     291         1913 :       else if (GET_MODE (*ml->ref) == GET_MODE (stack_pointer_rtx))
     292              :         new_val = new_addr;
     293              :       else
     294            0 :         new_val = lowpart_subreg (GET_MODE (*ml->ref), new_addr,
     295            0 :                                   GET_MODE (new_addr));
     296       444133 :       validate_change (ml->insn, ml->ref, new_val, 1);
     297              :     }
     298              : 
     299       477455 :   if (apply_change_group ())
     300              :     {
     301              :       /* Succeeded.  Update our knowledge of the stack references.  */
     302       917879 :       for (ml = reflist; ml ; ml = ml->next)
     303       443599 :         ml->sp_offset -= delta;
     304              : 
     305       474280 :       if (remove_equal)
     306          382 :         remove_reg_equal_equiv_notes (insn);
     307       474280 :       return true;
     308              :     }
     309              :   else
     310              :     return false;
     311              : }
     312              : 
     313              : /* For non-debug insns, record all stack memory references in INSN
     314              :    and return true if there were no other (unrecorded) references to the
     315              :    stack pointer.  For debug insns, record all stack references regardless
     316              :    of context and unconditionally return true.  */
     317              : 
     318              : static bool
     319      8455348 : record_stack_refs (rtx_insn *insn, struct csa_reflist **reflist)
     320              : {
     321      8455348 :   subrtx_ptr_iterator::array_type array;
     322     34700979 :   FOR_EACH_SUBRTX_PTR (iter, array, &PATTERN (insn), NONCONST)
     323              :     {
     324     27220152 :       rtx *loc = *iter;
     325     27220152 :       rtx x = *loc;
     326     27220152 :       switch (GET_CODE (x))
     327              :         {
     328      3491255 :         case MEM:
     329      3491255 :           if (!reg_mentioned_p (stack_pointer_rtx, x))
     330      1052661 :             iter.skip_subrtxes ();
     331              :           /* We are not able to handle correctly all possible memrefs
     332              :              containing stack pointer, so this check is necessary.  */
     333      2438594 :           else if (stack_memref_p (x))
     334              :             {
     335      1651974 :               *reflist = record_one_stack_ref (insn, loc, *reflist);
     336      1651974 :               iter.skip_subrtxes ();
     337              :             }
     338              :           /* Try harder for DEBUG_INSNs, handle e.g.
     339              :              (mem (mem (sp + 16) + 4).  */
     340       786620 :           else if (!DEBUG_INSN_P (insn))
     341       974521 :             return false;
     342              :           break;
     343              : 
     344      7470305 :         case REG:
     345              :           /* ??? We want be able to handle non-memory stack pointer
     346              :              references later.  For now just discard all insns referring to
     347              :              stack pointer outside mem expressions.  We would probably
     348              :              want to teach validate_replace to simplify expressions first.
     349              : 
     350              :              We can't just compare with STACK_POINTER_RTX because the
     351              :              reference to the stack pointer might be in some other mode.
     352              :              In particular, an explicit clobber in an asm statement will
     353              :              result in a QImode clobber.
     354              : 
     355              :              In DEBUG_INSNs, we want to replace all occurrences, otherwise
     356              :              they will cause -fcompare-debug failures.  */
     357      7470305 :           if (REGNO (x) == STACK_POINTER_REGNUM)
     358              :             {
     359       251672 :               if (!DEBUG_INSN_P (insn))
     360              :                 return false;
     361        62723 :               *reflist = record_one_stack_ref (insn, loc, *reflist);
     362              :             }
     363              :           break;
     364              : 
     365              :         default:
     366              :           break;
     367              :         }
     368              :     }
     369      7480827 :   return true;
     370      8455348 : }
     371              : 
     372              : /* If INSN has a REG_ARGS_SIZE note, move it to LAST.
     373              :    AFTER is true iff LAST follows INSN in the instruction stream.  */
     374              : 
     375              : static void
     376       474280 : maybe_move_args_size_note (rtx_insn *last, rtx_insn *insn, bool after)
     377              : {
     378       474280 :   rtx note, last_note;
     379              : 
     380       474280 :   note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
     381       474280 :   if (note == NULL)
     382              :     return;
     383              : 
     384       472717 :   last_note = find_reg_note (last, REG_ARGS_SIZE, NULL_RTX);
     385       472717 :   if (last_note)
     386              :     {
     387              :       /* The ARGS_SIZE notes are *not* cumulative.  They represent an
     388              :          absolute value, and the "most recent" note wins.  */
     389       352171 :       if (!after)
     390       298182 :         XEXP (last_note, 0) = XEXP (note, 0);
     391              :     }
     392              :   else
     393       120546 :     add_reg_note (last, REG_ARGS_SIZE, XEXP (note, 0));
     394              : }
     395              : 
     396              : /* Merge any REG_CFA_ADJUST_CFA note from SRC into DST.
     397              :    AFTER is true iff DST follows SRC in the instruction stream.  */
     398              : 
     399              : static void
     400       420696 : maybe_merge_cfa_adjust (rtx_insn *dst, rtx_insn *src, bool after)
     401              : {
     402       420696 :   rtx snote = NULL, dnote = NULL;
     403       420696 :   rtx sexp, dexp;
     404       420696 :   rtx exp1, exp2;
     405              : 
     406       420696 :   if (RTX_FRAME_RELATED_P (src))
     407            1 :     snote = find_reg_note (src, REG_CFA_ADJUST_CFA, NULL_RTX);
     408            1 :   if (snote == NULL)
     409       420695 :     return;
     410            1 :   sexp = XEXP (snote, 0);
     411              : 
     412            1 :   if (RTX_FRAME_RELATED_P (dst))
     413            1 :     dnote = find_reg_note (dst, REG_CFA_ADJUST_CFA, NULL_RTX);
     414            1 :   if (dnote == NULL)
     415              :     {
     416            0 :       add_reg_note (dst, REG_CFA_ADJUST_CFA, sexp);
     417            0 :       return;
     418              :     }
     419            1 :   dexp = XEXP (dnote, 0);
     420              : 
     421            1 :   gcc_assert (GET_CODE (sexp) == SET);
     422            1 :   gcc_assert (GET_CODE (dexp) == SET);
     423              : 
     424            1 :   if (after)
     425              :     exp1 = dexp, exp2 = sexp;
     426              :   else
     427            0 :     exp1 = sexp, exp2 = dexp;
     428              : 
     429            1 :   SET_SRC (exp1) = simplify_replace_rtx (SET_SRC (exp1), SET_DEST (exp2),
     430              :                                          SET_SRC (exp2));
     431            1 :   XEXP (dnote, 0) = exp1;
     432              : }
     433              : 
     434              : /* Return the next (or previous) active insn within BB.  */
     435              : 
     436              : static rtx_insn *
     437        18022 : prev_active_insn_bb (basic_block bb, rtx_insn *insn)
     438              : {
     439        23944 :   for (insn = PREV_INSN (insn);
     440        23944 :        insn != PREV_INSN (BB_HEAD (bb));
     441         5922 :        insn = PREV_INSN (insn))
     442        23696 :     if (active_insn_p (insn))
     443              :       return insn;
     444              :   return NULL;
     445              : }
     446              : 
     447              : static rtx_insn *
     448        94773 : next_active_insn_bb (basic_block bb, rtx_insn *insn)
     449              : {
     450       114421 :   for (insn = NEXT_INSN (insn);
     451       114421 :        insn != NEXT_INSN (BB_END (bb));
     452        19648 :        insn = NEXT_INSN (insn))
     453       114419 :     if (active_insn_p (insn))
     454              :       return insn;
     455              :   return NULL;
     456              : }
     457              : 
     458              : /* If INSN has a REG_ARGS_SIZE note, if possible move it to PREV.  Otherwise
     459              :    search for a nearby candidate within BB where we can stick the note.  */
     460              : 
     461              : static void
     462        19774 : force_move_args_size_note (basic_block bb, rtx_insn *prev, rtx_insn *insn)
     463              : {
     464        19774 :   rtx note;
     465        19774 :   rtx_insn *test, *next_candidate, *prev_candidate;
     466              : 
     467              :   /* If PREV exists, tail-call to the logic in the other function.  */
     468        19774 :   if (prev)
     469              :     {
     470            0 :       maybe_move_args_size_note (prev, insn, false);
     471            0 :       return;
     472              :     }
     473              : 
     474              :   /* First, make sure there's anything that needs doing.  */
     475        19774 :   note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
     476        19774 :   if (note == NULL)
     477              :     return;
     478              : 
     479              :   /* We need to find a spot between the previous and next exception points
     480              :      where we can place the note and "properly" deallocate the arguments.  */
     481        94773 :   next_candidate = prev_candidate = NULL;
     482              : 
     483              :   /* It is often the case that we have insns in the order:
     484              :         call
     485              :         add sp (previous deallocation)
     486              :         sub sp (align for next arglist)
     487              :         push arg
     488              :      and the add/sub cancel.  Therefore we begin by searching forward.  */
     489              : 
     490              :   test = insn;
     491        94773 :   while ((test = next_active_insn_bb (bb, test)) != NULL)
     492              :     {
     493              :       /* Found an existing note: nothing to do.  */
     494        94771 :       if (find_reg_note (test, REG_ARGS_SIZE, NULL_RTX))
     495              :         return;
     496              :       /* Found something that affects unwinding.  Stop searching.  */
     497        79800 :       if (CALL_P (test) || !insn_nothrow_p (test))
     498              :         break;
     499        74999 :       if (next_candidate == NULL)
     500        13667 :         next_candidate = test;
     501              :     }
     502              : 
     503         4803 :   test = insn;
     504        18022 :   while ((test = prev_active_insn_bb (bb, test)) != NULL)
     505              :     {
     506        17774 :       rtx tnote;
     507              :       /* Found a place that seems logical to adjust the stack.  */
     508        17774 :       tnote = find_reg_note (test, REG_ARGS_SIZE, NULL_RTX);
     509        17774 :       if (tnote)
     510              :         {
     511           38 :           XEXP (tnote, 0) = XEXP (note, 0);
     512           38 :           return;
     513              :         }
     514        17736 :       if (prev_candidate == NULL)
     515         4591 :         prev_candidate = test;
     516              :       /* Found something that affects unwinding.  Stop searching.  */
     517        22253 :       if (CALL_P (test) || !insn_nothrow_p (test))
     518              :         break;
     519              :     }
     520              : 
     521         4765 :   if (prev_candidate)
     522              :     test = prev_candidate;
     523          199 :   else if (next_candidate)
     524              :     test = next_candidate;
     525              :   else
     526              :     {
     527              :       /* ??? We *must* have a place, lest we ICE on the lost adjustment.
     528              :          Options are: dummy clobber insn, nop, or prevent the removal of
     529              :          the sp += 0 insn.  */
     530              :       /* TODO: Find another way to indicate to the dwarf2 code that we
     531              :          have not in fact lost an adjustment.  */
     532            5 :       test = emit_insn_before (gen_rtx_CLOBBER (VOIDmode, const0_rtx), insn);
     533              :     }
     534         4765 :   add_reg_note (test, REG_ARGS_SIZE, XEXP (note, 0));
     535              : }
     536              : 
     537              : /* Subroutine of combine_stack_adjustments, called for each basic block.  */
     538              : 
     539              : static void
     540     11582972 : combine_stack_adjustments_for_block (basic_block bb, bitmap live)
     541              : {
     542     11582972 :   HOST_WIDE_INT last_sp_adjust = 0;
     543     11582972 :   rtx_insn *last_sp_set = NULL;
     544     11582972 :   rtx_insn *last2_sp_set = NULL;
     545     11582972 :   bitmap last_sp_live = NULL;
     546     11582972 :   struct csa_reflist *reflist = NULL;
     547     11582972 :   bitmap copy = NULL;
     548     11582972 :   rtx_insn *insn, *next;
     549     11582972 :   rtx set;
     550     11582972 :   bool end_of_block = false;
     551              : 
     552     23165944 :   bitmap_copy (live, DF_LR_IN (bb));
     553     11582972 :   df_simulate_initialize_forwards (bb, live);
     554              : 
     555    151141698 :   for (insn = BB_HEAD (bb); !end_of_block ; insn = next)
     556              :     {
     557    139558726 :       end_of_block = insn == BB_END (bb);
     558    139558726 :       next = NEXT_INSN (insn);
     559              : 
     560    139558726 :       if (! INSN_P (insn))
     561     25864270 :         continue;
     562              : 
     563    113694456 :       set = single_set_for_csa (insn);
     564    113694456 :       if (set && find_reg_note (insn, REG_STACK_CHECK, NULL_RTX))
     565              :         set = NULL_RTX;
     566    113694429 :       if (set)
     567              :         {
     568     59252978 :           rtx dest = SET_DEST (set);
     569     59252978 :           rtx src = SET_SRC (set);
     570     59252978 :           HOST_WIDE_INT this_adjust = 0;
     571              : 
     572              :           /* Find constant additions to the stack pointer.  */
     573     59252978 :           if (dest == stack_pointer_rtx
     574      2884164 :               && GET_CODE (src) == PLUS
     575      2853428 :               && XEXP (src, 0) == stack_pointer_rtx
     576      2827754 :               && CONST_INT_P (XEXP (src, 1)))
     577      2827595 :             this_adjust = INTVAL (XEXP (src, 1));
     578              :           /* Or such additions turned by postreload into a store of
     579              :              equivalent register.  */
     580     56425383 :           else if (dest == stack_pointer_rtx
     581        56569 :                    && REG_P (src)
     582     56428626 :                    && REGNO (src) != STACK_POINTER_REGNUM)
     583         3243 :             if (rtx equal = find_reg_note (insn, REG_EQUAL, NULL_RTX))
     584         2695 :               if (GET_CODE (XEXP (equal, 0)) == PLUS
     585         2695 :                   && XEXP (XEXP (equal, 0), 0) == stack_pointer_rtx
     586         2695 :                   && CONST_INT_P (XEXP (XEXP (equal, 0), 1)))
     587         2695 :                 this_adjust = INTVAL (XEXP (XEXP (equal, 0), 1));
     588              : 
     589      2830290 :           if (this_adjust)
     590              :             {
     591              :               /* If we've not seen an adjustment previously, record
     592              :                  it now and continue.  */
     593      2830290 :               if (! last_sp_set)
     594              :                 {
     595      2409134 :                   last_sp_set = insn;
     596      2409134 :                   last_sp_adjust = this_adjust;
     597      2409134 :                   if (REG_P (src))
     598              :                     {
     599         2687 :                       if (copy == NULL)
     600         2065 :                         copy = BITMAP_ALLOC (&reg_obstack);
     601         2687 :                       last_sp_live = copy;
     602         2687 :                       bitmap_copy (last_sp_live, live);
     603              :                     }
     604              :                   else
     605              :                     last_sp_live = NULL;
     606      2409134 :                   df_simulate_one_insn_forwards (bb, insn, live);
     607      2409134 :                   continue;
     608              :                 }
     609              : 
     610              :               /* If not all recorded refs can be adjusted, or the
     611              :                  adjustment is now too large for a constant addition,
     612              :                  we cannot merge the two stack adjustments.
     613              : 
     614              :                  Also we need to be careful to not move stack pointer
     615              :                  such that we create stack accesses outside the allocated
     616              :                  area.  We can combine an allocation into the first insn,
     617              :                  or a deallocation into the second insn.  We cannot
     618              :                  combine an allocation followed by a deallocation.
     619              : 
     620              :                  The only somewhat frequent occurrence of the later is when
     621              :                  a function allocates a stack frame but does not use it.
     622              :                  For this case, we would need to analyze rtl stream to be
     623              :                  sure that allocated area is really unused.  This means not
     624              :                  only checking the memory references, but also all registers
     625              :                  or global memory references possibly containing a stack
     626              :                  frame address.
     627              : 
     628              :                  Perhaps the best way to address this problem is to teach
     629              :                  gcc not to allocate stack for objects never used.  */
     630              : 
     631              :               /* Combine an allocation into the first instruction.  */
     632       421156 :               if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
     633              :                 {
     634       357933 :                   if (no_unhandled_cfa (insn)
     635       357933 :                       && try_apply_stack_adjustment (last_sp_set, reflist,
     636              :                                                      last_sp_adjust
     637              :                                                      + this_adjust,
     638              :                                                      this_adjust,
     639              :                                                      last_sp_live,
     640              :                                                      insn))
     641              :                     {
     642              :                       /* It worked!  */
     643       357933 :                       maybe_move_args_size_note (last_sp_set, insn, false);
     644       357933 :                       maybe_merge_cfa_adjust (last_sp_set, insn, false);
     645       357933 :                       delete_insn (insn);
     646       357933 :                       last_sp_adjust += this_adjust;
     647       357933 :                       last_sp_live = NULL;
     648       357933 :                       continue;
     649              :                     }
     650              :                 }
     651              : 
     652              :               /* Otherwise we have a deallocation.  Do not combine with
     653              :                  a previous allocation.  Combine into the second insn.  */
     654        63223 :               else if (STACK_GROWS_DOWNWARD
     655              :                        ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
     656              :                 {
     657        62768 :                   if (no_unhandled_cfa (last_sp_set)
     658        62768 :                       && !REG_P (src)
     659       125531 :                       && try_apply_stack_adjustment (insn, reflist,
     660              :                                                      last_sp_adjust
     661              :                                                      + this_adjust,
     662              :                                                      -last_sp_adjust,
     663              :                                                      NULL, NULL))
     664              :                     {
     665              :                       /* It worked!  */
     666        62763 :                       maybe_move_args_size_note (insn, last_sp_set, true);
     667        62763 :                       maybe_merge_cfa_adjust (insn, last_sp_set, true);
     668        62763 :                       delete_insn (last_sp_set);
     669        62763 :                       last_sp_set = insn;
     670        62763 :                       last_sp_adjust += this_adjust;
     671        62763 :                       last_sp_live = NULL;
     672        62763 :                       free_csa_reflist (reflist);
     673        62763 :                       reflist = NULL;
     674        62763 :                       df_simulate_one_insn_forwards (bb, insn, live);
     675        62763 :                       continue;
     676              :                     }
     677              :                 }
     678              : 
     679              :               /* Combination failed.  Restart processing from here.  If
     680              :                  deallocation+allocation conspired to cancel, we can
     681              :                  delete the old deallocation insn.  */
     682          460 :               if (last_sp_set)
     683              :                 {
     684          460 :                   if (last_sp_adjust == 0 && no_unhandled_cfa (last_sp_set))
     685              :                     {
     686            0 :                       maybe_move_args_size_note (insn, last_sp_set, true);
     687            0 :                       maybe_merge_cfa_adjust (insn, last_sp_set, true);
     688            0 :                       delete_insn (last_sp_set);
     689              :                     }
     690              :                   else
     691              :                     last2_sp_set = last_sp_set;
     692              :                 }
     693          460 :               free_csa_reflist (reflist);
     694          460 :               reflist = NULL;
     695          460 :               last_sp_set = insn;
     696          460 :               last_sp_adjust = this_adjust;
     697          460 :               if (REG_P (src))
     698              :                 {
     699            5 :                   if (copy == NULL)
     700            5 :                     copy = BITMAP_ALLOC (&reg_obstack);
     701            5 :                   last_sp_live = copy;
     702            5 :                   bitmap_copy (last_sp_live, live);
     703              :                 }
     704              :               else
     705              :                 last_sp_live = NULL;
     706          460 :               df_simulate_one_insn_forwards (bb, insn, live);
     707          460 :               continue;
     708              :             }
     709              : 
     710              :           /* Find a store with pre-(dec|inc)rement or pre-modify of exactly
     711              :              the previous adjustment and turn it into a simple store.  This
     712              :              is equivalent to anticipating the stack adjustment so this must
     713              :              be an allocation.  */
     714     56476272 :           if (MEM_P (dest)
     715     12135942 :               && ((STACK_GROWS_DOWNWARD
     716     14945611 :                    ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC
     717      5619338 :                       && known_eq (last_sp_adjust,
     718              :                                    GET_MODE_SIZE (GET_MODE (dest))))
     719              :                    : (GET_CODE (XEXP (dest, 0)) == PRE_INC
     720              :                       && known_eq (-last_sp_adjust,
     721              :                                    GET_MODE_SIZE (GET_MODE (dest)))))
     722     12080044 :                   || ((STACK_GROWS_DOWNWARD
     723              :                        ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
     724     10460942 :                       && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
     725        52748 :                       && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
     726        52748 :                       && XEXP (XEXP (XEXP (dest, 0), 1), 0)
     727        52748 :                          == stack_pointer_rtx
     728        52748 :                       && GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
     729              :                          == CONST_INT
     730        52748 :                       && INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
     731        52748 :                          == -last_sp_adjust))
     732        59646 :               && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
     733        59646 :               && !reg_mentioned_p (stack_pointer_rtx, src)
     734     56425863 :               && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
     735     56479447 :               && try_apply_stack_adjustment (insn, reflist, 0,
     736              :                                              -last_sp_adjust,
     737              :                                              NULL, NULL))
     738              :             {
     739        53584 :               if (last2_sp_set)
     740            0 :                 maybe_move_args_size_note (last2_sp_set, last_sp_set, false);
     741              :               else
     742        53584 :                 maybe_move_args_size_note (insn, last_sp_set, true);
     743        53584 :               delete_insn (last_sp_set);
     744        53584 :               free_csa_reflist (reflist);
     745        53584 :               reflist = NULL;
     746        53584 :               last_sp_set = NULL;
     747        53584 :               last_sp_adjust = 0;
     748        53584 :               last_sp_live = NULL;
     749        53584 :               df_simulate_one_insn_forwards (bb, insn, live);
     750        53584 :               continue;
     751              :             }
     752              :         }
     753              : 
     754    110810582 :       if (!CALL_P (insn) && last_sp_set && record_stack_refs (insn, &reflist))
     755              :         {
     756      7480827 :           df_simulate_one_insn_forwards (bb, insn, live);
     757      7480827 :           continue;
     758              :         }
     759              : 
     760              :       /* Otherwise, we were not able to process the instruction.
     761              :          Do not continue collecting data across such a one.  */
     762    103329755 :       if (last_sp_set
     763    103329755 :           && (CALL_P (insn)
     764       974521 :               || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
     765              :         {
     766      1425480 :           if (last_sp_set && last_sp_adjust == 0)
     767              :             {
     768        19759 :               force_move_args_size_note (bb, last2_sp_set, last_sp_set);
     769        19759 :               delete_insn (last_sp_set);
     770              :             }
     771      1425480 :           free_csa_reflist (reflist);
     772      1425480 :           reflist = NULL;
     773      1425480 :           last2_sp_set = NULL;
     774      1425480 :           last_sp_set = NULL;
     775      1425480 :           last_sp_adjust = 0;
     776      1425480 :           last_sp_live = NULL;
     777              :         }
     778              : 
     779    103329755 :       df_simulate_one_insn_forwards (bb, insn, live);
     780              :     }
     781              : 
     782     11582972 :   if (last_sp_set && last_sp_adjust == 0)
     783              :     {
     784           15 :       force_move_args_size_note (bb, last2_sp_set, last_sp_set);
     785           15 :       delete_insn (last_sp_set);
     786              :     }
     787              : 
     788     11582972 :   if (reflist)
     789     11582972 :     free_csa_reflist (reflist);
     790     11582972 :   if (copy)
     791         2070 :     BITMAP_FREE (copy);
     792     11582972 : }
     793              : 
     794              : static void
     795      1043685 : rest_of_handle_stack_adjustments (void)
     796              : {
     797      1043685 :   df_note_add_problem ();
     798      1043685 :   df_analyze ();
     799      1043685 :   combine_stack_adjustments ();
     800      1043685 : }
     801              : 
     802              : namespace {
     803              : 
     804              : const pass_data pass_data_stack_adjustments =
     805              : {
     806              :   RTL_PASS, /* type */
     807              :   "csa", /* name */
     808              :   OPTGROUP_NONE, /* optinfo_flags */
     809              :   TV_COMBINE_STACK_ADJUST, /* tv_id */
     810              :   0, /* properties_required */
     811              :   0, /* properties_provided */
     812              :   0, /* properties_destroyed */
     813              :   0, /* todo_flags_start */
     814              :   TODO_df_finish, /* todo_flags_finish */
     815              : };
     816              : 
     817              : class pass_stack_adjustments : public rtl_opt_pass
     818              : {
     819              : public:
     820       285722 :   pass_stack_adjustments (gcc::context *ctxt)
     821       571444 :     : rtl_opt_pass (pass_data_stack_adjustments, ctxt)
     822              :   {}
     823              : 
     824              :   /* opt_pass methods: */
     825              :   bool gate (function *) final override;
     826      1043685 :   unsigned int execute (function *) final override
     827              :     {
     828      1043685 :       rest_of_handle_stack_adjustments ();
     829      1043685 :       return 0;
     830              :     }
     831              : 
     832              : }; // class pass_stack_adjustments
     833              : 
     834              : bool
     835      1471370 : pass_stack_adjustments::gate (function *)
     836              : {
     837              :   /* This is kind of a heuristic.  We need to run combine_stack_adjustments
     838              :      even for machines with possibly nonzero TARGET_RETURN_POPS_ARGS
     839              :      and ACCUMULATE_OUTGOING_ARGS.  We expect that only ports having
     840              :      push instructions will have popping returns.  */
     841              : #ifndef PUSH_ROUNDING
     842              :   if (ACCUMULATE_OUTGOING_ARGS)
     843              :     return false;
     844              : #endif
     845      1471370 :   return flag_combine_stack_adjustments;
     846              : }
     847              : 
     848              : } // anon namespace
     849              : 
     850              : rtl_opt_pass *
     851       285722 : make_pass_stack_adjustments (gcc::context *ctxt)
     852              : {
     853       285722 :   return new pass_stack_adjustments (ctxt);
     854              : }
        

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.